summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndre Eisenbach <andre@broadcom.com>2012-02-22 13:18:21 -0800
committerMatthew Xie <mattx@google.com>2012-07-14 11:19:11 -0700
commite448862a47c08eb23185aaed574b39264f5005fc (patch)
tree2bc6246e3091315e77224fd798ea2fe8074ef972
parenta2ca4b83ab8bbbfd8d5f6693e927ed4b82094624 (diff)
downloadexternal_bluetooth_bluedroid-e448862a47c08eb23185aaed574b39264f5005fc.zip
external_bluetooth_bluedroid-e448862a47c08eb23185aaed574b39264f5005fc.tar.gz
external_bluetooth_bluedroid-e448862a47c08eb23185aaed574b39264f5005fc.tar.bz2
Initial Bluedroid stack commit
-rw-r--r--Android.mk3
-rw-r--r--CleanSpec.mk49
-rw-r--r--bta/Android.mk140
-rw-r--r--bta/ag/bta_ag_act.c848
-rw-r--r--bta/ag/bta_ag_api.c310
-rw-r--r--bta/ag/bta_ag_at.c230
-rw-r--r--bta/ag/bta_ag_at.h108
-rw-r--r--bta/ag/bta_ag_cfg.c51
-rw-r--r--bta/ag/bta_ag_ci.c86
-rw-r--r--bta/ag/bta_ag_cmd.c1789
-rw-r--r--bta/ag/bta_ag_int.h407
-rw-r--r--bta/ag/bta_ag_main.c1000
-rw-r--r--bta/ag/bta_ag_rfc.c428
-rw-r--r--bta/ag/bta_ag_sco.c1650
-rw-r--r--bta/ag/bta_ag_sdp.c491
-rw-r--r--bta/av/bta_av_aact.c2688
-rw-r--r--bta/av/bta_av_act.c2000
-rw-r--r--bta/av/bta_av_api.c568
-rw-r--r--bta/av/bta_av_cfg.c276
-rw-r--r--bta/av/bta_av_ci.c85
-rw-r--r--bta/av/bta_av_int.h706
-rw-r--r--bta/av/bta_av_main.c1318
-rw-r--r--bta/av/bta_av_ssm.c587
-rw-r--r--bta/dg/bta_dg_act.c900
-rw-r--r--bta/dg/bta_dg_api.c218
-rw-r--r--bta/dg/bta_dg_cfg.c54
-rw-r--r--bta/dg/bta_dg_ci.c159
-rw-r--r--bta/dg/bta_dg_int.h220
-rw-r--r--bta/dg/bta_dg_main.c597
-rw-r--r--bta/dm/bta_dm_act.c4678
-rw-r--r--bta/dm/bta_dm_api.c1602
-rw-r--r--bta/dm/bta_dm_cfg.c424
-rw-r--r--bta/dm/bta_dm_ci.c106
-rw-r--r--bta/dm/bta_dm_int.h956
-rw-r--r--bta/dm/bta_dm_main.c331
-rw-r--r--bta/dm/bta_dm_pm.c980
-rw-r--r--bta/dm/bta_dm_sco.c684
-rw-r--r--bta/fs/bta_fs_cfg.c38
-rw-r--r--bta/fs/bta_fs_ci.c268
-rw-r--r--bta/ft/bta_ft_cfg.c86
-rw-r--r--bta/ft/bta_ftc_act.c2062
-rw-r--r--bta/ft/bta_ftc_api.c796
-rw-r--r--bta/ft/bta_ftc_int.h504
-rw-r--r--bta/ft/bta_ftc_main.c689
-rw-r--r--bta/ft/bta_ftc_utils.c608
-rw-r--r--bta/ft/bta_fts_act.c1523
-rw-r--r--bta/ft/bta_fts_api.c230
-rw-r--r--bta/ft/bta_fts_int.h287
-rw-r--r--bta/ft/bta_fts_main.c603
-rw-r--r--bta/ft/bta_fts_sdp.c66
-rw-r--r--bta/ft/bta_fts_utils.c972
-rw-r--r--bta/gatt/bta_gattc_act.c1789
-rw-r--r--bta/gatt/bta_gattc_api.c922
-rw-r--r--bta/gatt/bta_gattc_cache.c1584
-rw-r--r--bta/gatt/bta_gattc_ci.c125
-rw-r--r--bta/gatt/bta_gattc_int.h452
-rw-r--r--bta/gatt/bta_gattc_main.c474
-rw-r--r--bta/gatt/bta_gattc_utils.c652
-rw-r--r--bta/gatt/bta_gatts_act.c785
-rw-r--r--bta/gatt/bta_gatts_api.c500
-rw-r--r--bta/gatt/bta_gatts_int.h233
-rw-r--r--bta/gatt/bta_gatts_main.c122
-rw-r--r--bta/gatt/bta_gatts_utils.c223
-rw-r--r--bta/hd/bta_hd_act.c646
-rw-r--r--bta/hd/bta_hd_api.c236
-rw-r--r--bta/hd/bta_hd_cfg.c151
-rw-r--r--bta/hd/bta_hd_int.h166
-rw-r--r--bta/hd/bta_hd_main.c242
-rw-r--r--bta/hh/bta_hh_act.c1160
-rw-r--r--bta/hh/bta_hh_api.c412
-rw-r--r--bta/hh/bta_hh_cfg.c52
-rw-r--r--bta/hh/bta_hh_int.h235
-rw-r--r--bta/hh/bta_hh_main.c429
-rw-r--r--bta/hh/bta_hh_utils.c409
-rw-r--r--bta/hl/bta_hl_act.c2794
-rw-r--r--bta/hl/bta_hl_api.c472
-rw-r--r--bta/hl/bta_hl_ci.c158
-rw-r--r--bta/hl/bta_hl_int.h845
-rw-r--r--bta/hl/bta_hl_main.c1907
-rw-r--r--bta/hl/bta_hl_sdp.c429
-rw-r--r--bta/hl/bta_hl_utils.c3324
-rw-r--r--bta/include/bd.h89
-rw-r--r--bta/include/bta_ag_api.h496
-rw-r--r--bta/include/bta_ag_ci.h70
-rw-r--r--bta/include/bta_ag_co.h100
-rw-r--r--bta/include/bta_api.h1712
-rw-r--r--bta/include/bta_av_api.h753
-rw-r--r--bta/include/bta_av_ci.h62
-rw-r--r--bta/include/bta_av_co.h400
-rw-r--r--bta/include/bta_dg_api.h198
-rw-r--r--bta/include/bta_dg_ci.h107
-rw-r--r--bta/include/bta_dg_co.h198
-rw-r--r--bta/include/bta_dm_ci.h69
-rw-r--r--bta/include/bta_dm_co.h262
-rw-r--r--bta/include/bta_fs_api.h32
-rw-r--r--bta/include/bta_fs_ci.h244
-rw-r--r--bta/include/bta_fs_co.h690
-rw-r--r--bta/include/bta_ft_api.h724
-rw-r--r--bta/include/bta_gatt_api.h1206
-rw-r--r--bta/include/bta_gattc_ci.h108
-rw-r--r--bta/include/bta_gattc_co.h89
-rw-r--r--bta/include/bta_gatts_co.h70
-rw-r--r--bta/include/bta_hd_api.h289
-rw-r--r--bta/include/bta_hh_api.h444
-rw-r--r--bta/include/bta_hh_co.h60
-rw-r--r--bta/include/bta_hl_api.h895
-rw-r--r--bta/include/bta_hl_ci.h112
-rw-r--r--bta/include/bta_hl_co.h219
-rw-r--r--bta/include/bta_ma_api.h691
-rw-r--r--bta/include/bta_ma_co.h91
-rw-r--r--bta/include/bta_ma_def.h479
-rw-r--r--bta/include/bta_mse_api.h470
-rw-r--r--bta/include/bta_mse_ci.h146
-rw-r--r--bta/include/bta_mse_co.h330
-rw-r--r--bta/include/bta_op_api.h621
-rw-r--r--bta/include/bta_pan_api.h187
-rw-r--r--bta/include/bta_pan_ci.h139
-rw-r--r--bta/include/bta_pan_co.h189
-rw-r--r--bta/include/bta_pbs_api.h298
-rw-r--r--bta/include/bta_pbs_ci.h93
-rw-r--r--bta/include/bta_pbs_co.h160
-rw-r--r--bta/include/bta_prm_api.h57
-rw-r--r--bta/include/bta_sc_api.h193
-rw-r--r--bta/include/bta_sc_ci.h111
-rw-r--r--bta/include/bta_sc_co.h153
-rw-r--r--bta/include/bta_sys_ci.h57
-rw-r--r--bta/include/bta_sys_co.h47
-rw-r--r--bta/include/ptim.h86
-rw-r--r--bta/include/utl.h156
-rw-r--r--bta/ma/bta_ma_api.c1203
-rw-r--r--bta/ma/bta_ma_util.c1750
-rw-r--r--bta/ma/bta_ma_util.h93
-rw-r--r--bta/ma/bta_mse_act.c2763
-rw-r--r--bta/ma/bta_mse_api.c437
-rw-r--r--bta/ma/bta_mse_cfg.c31
-rw-r--r--bta/ma/bta_mse_ci.c251
-rw-r--r--bta/ma/bta_mse_int.h835
-rw-r--r--bta/ma/bta_mse_main.c1367
-rw-r--r--bta/ma/bta_mse_sdp.c63
-rw-r--r--bta/ma/bta_mse_utils.c3867
-rw-r--r--bta/op/bta_op_fmt.c804
-rw-r--r--bta/op/bta_op_fmt.h92
-rw-r--r--bta/op/bta_op_vcal.c158
-rw-r--r--bta/op/bta_op_vcard.c310
-rw-r--r--bta/op/bta_op_vnote.c99
-rw-r--r--bta/op/bta_opc_act.c1017
-rw-r--r--bta/op/bta_opc_api.c214
-rw-r--r--bta/op/bta_opc_int.h257
-rw-r--r--bta/op/bta_opc_main.c425
-rw-r--r--bta/op/bta_opc_utils.c322
-rw-r--r--bta/op/bta_ops_act.c793
-rw-r--r--bta/op/bta_ops_api.c153
-rw-r--r--bta/op/bta_ops_int.h198
-rw-r--r--bta/op/bta_ops_main.c412
-rw-r--r--bta/op/bta_ops_utils.c487
-rw-r--r--bta/pan/bta_pan_act.c718
-rw-r--r--bta/pan/bta_pan_api.c202
-rw-r--r--bta/pan/bta_pan_ci.c248
-rw-r--r--bta/pan/bta_pan_int.h200
-rw-r--r--bta/pan/bta_pan_main.c409
-rw-r--r--bta/pb/bta_pbs_act.c1134
-rw-r--r--bta/pb/bta_pbs_api.c222
-rw-r--r--bta/pb/bta_pbs_cfg.c38
-rw-r--r--bta/pb/bta_pbs_ci.c119
-rw-r--r--bta/pb/bta_pbs_int.h305
-rw-r--r--bta/pb/bta_pbs_main.c515
-rw-r--r--bta/pb/bta_pbs_sdp.c113
-rw-r--r--bta/pb/bta_pbs_utils.c734
-rw-r--r--bta/sys/bd.c99
-rw-r--r--bta/sys/bta_sys.h296
-rw-r--r--bta/sys/bta_sys_cfg.c42
-rw-r--r--bta/sys/bta_sys_ci.c65
-rw-r--r--bta/sys/bta_sys_conn.c565
-rw-r--r--bta/sys/bta_sys_int.h107
-rw-r--r--bta/sys/bta_sys_main.c728
-rw-r--r--bta/sys/ptim.c149
-rw-r--r--bta/sys/utl.c283
-rw-r--r--btif/co/bta_ag_co.c161
-rw-r--r--btif/co/bta_dm_co.c424
-rw-r--r--btif/co/bta_fs_co.c1212
-rw-r--r--btif/co/bta_sys_co.c86
-rw-r--r--btif/include/btif_api.h368
-rw-r--r--btif/include/btif_common.h177
-rw-r--r--btif/include/btif_dm.h70
-rw-r--r--btif/include/btif_storage.h189
-rw-r--r--btif/include/btif_util.h107
-rw-r--r--btif/src/bluetooth.c381
-rw-r--r--btif/src/btif_core.c1038
-rw-r--r--btif/src/btif_dm.c1159
-rw-r--r--btif/src/btif_hf.c1010
-rw-r--r--btif/src/btif_storage.c1027
-rw-r--r--btif/src/btif_util.c359
-rw-r--r--gki/Android.mk33
-rw-r--r--gki/common/gki.h490
-rw-r--r--gki/common/gki_buffer.c1474
-rw-r--r--gki/common/gki_common.h384
-rw-r--r--gki/common/gki_debug.c348
-rw-r--r--gki/common/gki_inet.h42
-rw-r--r--gki/common/gki_time.c1016
-rw-r--r--gki/ulinux/data_types.h71
-rw-r--r--gki/ulinux/gki_int.h111
-rw-r--r--gki/ulinux/gki_ulinux.c1355
-rw-r--r--include/bt_target.h3441
-rw-r--r--include/bt_trace.h4763
-rw-r--r--include/bte.h106
-rw-r--r--include/bte_appl.h179
-rw-r--r--include/buildcfg.h6
-rw-r--r--include/buildcfg_crespo.h236
-rw-r--r--include/buildcfg_maguro.h235
-rw-r--r--include/gki_target.h486
-rw-r--r--main/Android.mk85
-rw-r--r--main/bte_init.c523
-rw-r--r--main/bte_logmsg.c589
-rw-r--r--main/bte_main.c550
-rw-r--r--main/bte_version.c14
-rw-r--r--stack/Android.mk188
-rw-r--r--stack/a2dp/a2d_api.c382
-rw-r--r--stack/a2dp/a2d_int.h70
-rw-r--r--stack/a2dp/a2d_m12.c141
-rw-r--r--stack/a2dp/a2d_m24.c149
-rw-r--r--stack/a2dp/a2d_sbc.c386
-rw-r--r--stack/avct/avct_api.c453
-rw-r--r--stack/avct/avct_bcb_act.c749
-rw-r--r--stack/avct/avct_ccb.c137
-rw-r--r--stack/avct/avct_defs.h51
-rw-r--r--stack/avct/avct_int.h227
-rw-r--r--stack/avct/avct_l2c.c421
-rw-r--r--stack/avct/avct_l2c_br.c397
-rw-r--r--stack/avct/avct_lcb.c459
-rw-r--r--stack/avct/avct_lcb_act.c690
-rw-r--r--stack/avdt/avdt_ad.c615
-rw-r--r--stack/avdt/avdt_api.c1370
-rw-r--r--stack/avdt/avdt_ccb.c452
-rw-r--r--stack/avdt/avdt_ccb_act.c1095
-rw-r--r--stack/avdt/avdt_defs.h192
-rw-r--r--stack/avdt/avdt_int.h733
-rw-r--r--stack/avdt/avdt_l2c.c508
-rw-r--r--stack/avdt/avdt_msg.c1879
-rw-r--r--stack/avdt/avdt_scb.c787
-rw-r--r--stack/avdt/avdt_scb_act.c2111
-rw-r--r--stack/avrc/avrc_api.c1132
-rw-r--r--stack/avrc/avrc_bld_ct.c1102
-rw-r--r--stack/avrc/avrc_bld_tg.c1547
-rw-r--r--stack/avrc/avrc_int.h146
-rw-r--r--stack/avrc/avrc_opt.c222
-rw-r--r--stack/avrc/avrc_pars_ct.c663
-rw-r--r--stack/avrc/avrc_pars_tg.c452
-rw-r--r--stack/avrc/avrc_sdp.c318
-rw-r--r--stack/avrc/avrc_utils.c254
-rw-r--r--stack/bnep/bnep_api.c768
-rw-r--r--stack/bnep/bnep_int.h238
-rw-r--r--stack/bnep/bnep_main.c825
-rw-r--r--stack/bnep/bnep_utils.c1449
-rw-r--r--stack/btm/btm_acl.c3126
-rw-r--r--stack/btm/btm_ble.c1888
-rw-r--r--stack/btm/btm_ble_addr.c371
-rw-r--r--stack/btm/btm_ble_bgconn.c604
-rw-r--r--stack/btm/btm_ble_gap.c2072
-rw-r--r--stack/btm/btm_ble_int.h285
-rw-r--r--stack/btm/btm_dev.c451
-rw-r--r--stack/btm/btm_devctl.c1935
-rw-r--r--stack/btm/btm_inq.c3233
-rw-r--r--stack/btm/btm_int.h1099
-rw-r--r--stack/btm/btm_main.c59
-rw-r--r--stack/btm/btm_pm.c985
-rw-r--r--stack/btm/btm_sco.c1741
-rw-r--r--stack/btm/btm_sec.c5612
-rw-r--r--stack/btu/btu_hcif.c2257
-rw-r--r--stack/btu/btu_init.c143
-rw-r--r--stack/btu/btu_task.c819
-rw-r--r--stack/dun/dun_api.c592
-rw-r--r--stack/dun/dun_int.h63
-rw-r--r--stack/gatt/att_protocol.c617
-rw-r--r--stack/gatt/gatt_api.c1542
-rw-r--r--stack/gatt/gatt_attr.c264
-rw-r--r--stack/gatt/gatt_auth.c435
-rw-r--r--stack/gatt/gatt_cl.c1206
-rw-r--r--stack/gatt/gatt_db.c1117
-rw-r--r--stack/gatt/gatt_int.h664
-rw-r--r--stack/gatt/gatt_main.c1101
-rw-r--r--stack/gatt/gatt_sr.c1472
-rw-r--r--stack/gatt/gatt_utils.c2587
-rw-r--r--stack/goep/goep_fs.c149
-rw-r--r--stack/goep/goep_int.h55
-rw-r--r--stack/goep/goep_trace.c35
-rw-r--r--stack/goep/goep_util.c504
-rw-r--r--stack/hcic/hciblecmds.c739
-rw-r--r--stack/hcic/hcicmds.c3349
-rw-r--r--stack/hid/hid_conn.h56
-rw-r--r--stack/hid/hidd_api.c536
-rw-r--r--stack/hid/hidd_conn.c970
-rw-r--r--stack/hid/hidd_int.h136
-rw-r--r--stack/hid/hidd_mgmt.c287
-rw-r--r--stack/hid/hidd_pm.c288
-rw-r--r--stack/hid/hidh_api.c534
-rw-r--r--stack/hid/hidh_conn.c1021
-rw-r--r--stack/hid/hidh_int.h81
-rw-r--r--stack/include/a2d_api.h244
-rw-r--r--stack/include/a2d_m12.h145
-rw-r--r--stack/include/a2d_m24.h122
-rw-r--r--stack/include/a2d_sbc.h199
-rw-r--r--stack/include/avct_api.h266
-rw-r--r--stack/include/avdt_api.h889
-rw-r--r--stack/include/avdtc_api.h219
-rw-r--r--stack/include/avrc_api.h621
-rw-r--r--stack/include/avrc_defs.h1411
-rw-r--r--stack/include/bnep_api.h463
-rw-r--r--stack/include/bt_types.h684
-rw-r--r--stack/include/btm_api.h4540
-rw-r--r--stack/include/btm_ble_api.h716
-rw-r--r--stack/include/btu.h297
-rw-r--r--stack/include/dun_api.h201
-rw-r--r--stack/include/dyn_mem.h182
-rw-r--r--stack/include/gatt_api.h1121
-rw-r--r--stack/include/gattdefs.h96
-rw-r--r--stack/include/goep_fs.h386
-rw-r--r--stack/include/goep_util.h265
-rw-r--r--stack/include/hcidefs.h2220
-rw-r--r--stack/include/hcimsgs.h1325
-rw-r--r--stack/include/hidd_api.h241
-rw-r--r--stack/include/hiddefs.h146
-rw-r--r--stack/include/hidh_api.h215
-rw-r--r--stack/include/l2c_api.h1173
-rw-r--r--stack/include/l2cdefs.h304
-rw-r--r--stack/include/mca_api.h482
-rw-r--r--stack/include/mca_defs.h75
-rw-r--r--stack/include/obx_api.h1697
-rw-r--r--stack/include/pan_api.h446
-rw-r--r--stack/include/port_api.h605
-rw-r--r--stack/include/port_ext.h19
-rw-r--r--stack/include/rfcdefs.h236
-rw-r--r--stack/include/sdp_api.h702
-rw-r--r--stack/include/sdpdefs.h305
-rw-r--r--stack/include/smp_api.h292
-rw-r--r--stack/include/uipc_msg.h869
-rw-r--r--stack/include/utfc.h48
-rw-r--r--stack/include/wbt_api.h58
-rw-r--r--stack/include/wcassert.h66
-rw-r--r--stack/include/xml_bld_api.h113
-rw-r--r--stack/include/xml_erp_api.h145
-rw-r--r--stack/include/xml_flp_api.h162
-rw-r--r--stack/include/xml_mlp_api.h169
-rw-r--r--stack/include/xml_pars_api.h358
-rw-r--r--stack/include/xml_vlist_api.h136
-rw-r--r--stack/l2cap/l2c_api.c1800
-rw-r--r--stack/l2cap/l2c_ble.c585
-rw-r--r--stack/l2cap/l2c_csm.c1321
-rw-r--r--stack/l2cap/l2c_fcr.c2697
-rw-r--r--stack/l2cap/l2c_int.h757
-rw-r--r--stack/l2cap/l2c_link.c1703
-rw-r--r--stack/l2cap/l2c_main.c979
-rw-r--r--stack/l2cap/l2c_ucd.c1158
-rw-r--r--stack/l2cap/l2c_utils.c3397
-rw-r--r--stack/mcap/mca_api.c912
-rw-r--r--stack/mcap/mca_cact.c567
-rw-r--r--stack/mcap/mca_csm.c372
-rw-r--r--stack/mcap/mca_dact.c149
-rw-r--r--stack/mcap/mca_dsm.c334
-rw-r--r--stack/mcap/mca_int.h343
-rw-r--r--stack/mcap/mca_l2c.c577
-rw-r--r--stack/mcap/mca_main.c630
-rw-r--r--stack/obx/hdrs/obx_dauth.c149
-rw-r--r--stack/obx/hdrs/obx_dbtp.c189
-rw-r--r--stack/obx/hdrs/obx_dopt.c52
-rw-r--r--stack/obx/hdrs/obx_dunic.c64
-rw-r--r--stack/obx/hdrs/obx_dutf.c91
-rw-r--r--stack/obx/hdrs/obx_dwchar.c91
-rw-r--r--stack/obx/hdrs/obx_ebtp.c177
-rw-r--r--stack/obx/hdrs/obx_eopt.c51
-rw-r--r--stack/obx/hdrs/obx_eunic.c64
-rw-r--r--stack/obx/hdrs/obx_eutf.c111
-rw-r--r--stack/obx/hdrs/obx_ewchar.c100
-rw-r--r--stack/obx/hdrs/obx_gen.c896
-rw-r--r--stack/obx/hdrs/obx_wchar.c84
-rw-r--r--stack/obx/hdrs/utfc.c245
-rw-r--r--stack/obx/obx_cact.c1103
-rw-r--r--stack/obx/obx_capi.c855
-rw-r--r--stack/obx/obx_csm.c365
-rw-r--r--stack/obx/obx_int.h602
-rw-r--r--stack/obx/obx_l2c.c1031
-rw-r--r--stack/obx/obx_main.c946
-rw-r--r--stack/obx/obx_md5.c1050
-rw-r--r--stack/obx/obx_rfc.c613
-rw-r--r--stack/obx/obx_sact.c1519
-rw-r--r--stack/obx/obx_sapi.c591
-rw-r--r--stack/obx/obx_ssm.c365
-rw-r--r--stack/obx/obx_utils.c979
-rw-r--r--stack/pan/pan_api.c840
-rw-r--r--stack/pan/pan_int.h145
-rw-r--r--stack/pan/pan_main.c717
-rw-r--r--stack/pan/pan_utils.c338
-rw-r--r--stack/rfcomm/port_api.c1525
-rw-r--r--stack/rfcomm/port_int.h237
-rw-r--r--stack/rfcomm/port_rfc.c1088
-rw-r--r--stack/rfcomm/port_utils.c562
-rw-r--r--stack/rfcomm/rfc_int.h373
-rw-r--r--stack/rfcomm/rfc_l2cap_if.c430
-rw-r--r--stack/rfcomm/rfc_mx_fsm.c650
-rw-r--r--stack/rfcomm/rfc_port_fsm.c902
-rw-r--r--stack/rfcomm/rfc_port_if.c325
-rw-r--r--stack/rfcomm/rfc_ts_frames.c895
-rw-r--r--stack/rfcomm/rfc_utils.c453
-rw-r--r--stack/sdp/sdp_api.c1264
-rw-r--r--stack/sdp/sdp_db.c948
-rw-r--r--stack/sdp/sdp_discovery.c1113
-rw-r--r--stack/sdp/sdp_main.c694
-rw-r--r--stack/sdp/sdp_server.c821
-rw-r--r--stack/sdp/sdp_utils.c1004
-rw-r--r--stack/sdp/sdpint.h313
-rw-r--r--stack/smp/aes.c926
-rw-r--r--stack/smp/aes.h162
-rw-r--r--stack/smp/smp_act.c943
-rw-r--r--stack/smp/smp_api.c324
-rw-r--r--stack/smp/smp_cmac.c376
-rw-r--r--stack/smp/smp_int.h301
-rw-r--r--stack/smp/smp_keys.c896
-rw-r--r--stack/smp/smp_l2c.c148
-rw-r--r--stack/smp/smp_main.c511
-rw-r--r--stack/smp/smp_utils.c665
-rw-r--r--stack/xml/xml_bld.c192
-rw-r--r--stack/xml/xml_erp.c907
-rw-r--r--stack/xml/xml_flp.c971
-rw-r--r--stack/xml/xml_mlp.c1060
-rw-r--r--stack/xml/xml_parse.c1502
-rw-r--r--stack/xml/xml_vlist.c873
-rw-r--r--udrv/include/unv.h205
-rw-r--r--udrv/ulinux/uipc_linux.h36
-rw-r--r--udrv/ulinux/unv_linux.c818
-rw-r--r--vendor/Android.mk3
-rw-r--r--vendor/firmware/Android.mk2
-rw-r--r--vendor/firmware/LICENSE.TXT216
-rw-r--r--vendor/firmware/bcm4329/Android.mk19
-rw-r--r--vendor/firmware/bcm4329/BCM4329B1_002.002.023.0944.0956.hcdbin0 -> 18310 bytes
-rw-r--r--vendor/firmware/bcm4330/Android.mk19
-rw-r--r--vendor/firmware/bcm4330/BCM4330B1.hcdbin0 -> 53775 bytes
-rw-r--r--vendor/libvendor/Android.mk23
-rw-r--r--vendor/libvendor/include/bt_vendor_brcm.h414
-rw-r--r--vendor/libvendor/include/bt_vendor_lib.h222
-rw-r--r--vendor/libvendor/include/upio.h136
-rw-r--r--vendor/libvendor/include/userial.h245
-rw-r--r--vendor/libvendor/include/utils.h200
-rw-r--r--vendor/libvendor/include/vnd_buildcfg.h14
-rw-r--r--vendor/libvendor/src/bt_vendor_brcm.c455
-rw-r--r--vendor/libvendor/src/btsnoop.c721
-rw-r--r--vendor/libvendor/src/hardware.c1012
-rw-r--r--vendor/libvendor/src/hci_h4.c1047
-rw-r--r--vendor/libvendor/src/upio.c322
-rw-r--r--vendor/libvendor/src/userial.c745
-rw-r--r--vendor/libvendor/src/utils.c312
449 files changed, 283592 insertions, 0 deletions
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 0000000..3c3cb61
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,3 @@
+ifneq ($(TARGET_SIMULATOR),true)
+ include $(call all-subdir-makefiles)
+endif
diff --git a/CleanSpec.mk b/CleanSpec.mk
new file mode 100644
index 0000000..b84e1b6
--- /dev/null
+++ b/CleanSpec.mk
@@ -0,0 +1,49 @@
+# Copyright (C) 2007 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list. These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+# $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list. E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
diff --git a/bta/Android.mk b/bta/Android.mk
new file mode 100644
index 0000000..bbada7e
--- /dev/null
+++ b/bta/Android.mk
@@ -0,0 +1,140 @@
+ifneq ($(TARGET_SIMULATOR),true)
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+ifeq ($(BOARD_HAVE_BLUETOOTH_BCM),true)
+LOCAL_CFLAGS += \
+ -DBOARD_HAVE_BLUETOOTH_BCM
+endif
+LOCAL_CFLAGS += -DBUILDCFG
+
+LOCAL_PRELINK_MODULE:=false
+LOCAL_SRC_FILES:= \
+ ./dm/bta_dm_ci.c \
+ ./dm/bta_dm_act.c \
+ ./dm/bta_dm_pm.c \
+ ./dm/bta_dm_main.c \
+ ./dm/bta_dm_cfg.c \
+ ./dm/bta_dm_api.c \
+ ./dm/bta_dm_sco.c \
+ ./op/bta_op_vcal.c \
+ ./op/bta_opc_utils.c \
+ ./op/bta_opc_main.c \
+ ./op/bta_opc_api.c \
+ ./op/bta_opc_act.c \
+ ./op/bta_ops_utils.c \
+ ./op/bta_op_vcard.c \
+ ./op/bta_ops_main.c \
+ ./op/bta_op_vnote.c \
+ ./op/bta_op_fmt.c \
+ ./op/bta_ops_act.c \
+ ./op/bta_ops_api.c \
+ ./ma/bta_mse_ci.c \
+ ./ma/bta_mse_api.c \
+ ./ma/bta_mse_act.c \
+ ./ma/bta_mse_sdp.c \
+ ./ma/bta_ma_util.c \
+ ./ma/bta_ma_api.c \
+ ./ma/bta_mse_utils.c \
+ ./ma/bta_mse_main.c \
+ ./ma/bta_mse_cfg.c \
+ ./gatt/bta_gattc_api.c \
+ ./gatt/bta_gatts_act.c \
+ ./gatt/bta_gatts_main.c \
+ ./gatt/bta_gattc_utils.c \
+ ./gatt/bta_gattc_ci.c \
+ ./gatt/bta_gatts_api.c \
+ ./gatt/bta_gattc_main.c \
+ ./gatt/bta_gattc_act.c \
+ ./gatt/bta_gattc_cache.c \
+ ./gatt/bta_gatts_utils.c \
+ ./hd/bta_hd_cfg.c \
+ ./hd/bta_hd_api.c \
+ ./hd/bta_hd_main.c \
+ ./hd/bta_hd_act.c \
+ ./ag/bta_ag_sdp.c \
+ ./ag/bta_ag_sco.c \
+ ./ag/bta_ag_cfg.c \
+ ./ag/bta_ag_main.c \
+ ./ag/bta_ag_api.c \
+ ./ag/bta_ag_rfc.c \
+ ./ag/bta_ag_act.c \
+ ./ag/bta_ag_cmd.c \
+ ./ag/bta_ag_ci.c \
+ ./ag/bta_ag_at.c \
+ ./hh/bta_hh_cfg.c \
+ ./hh/bta_hh_act.c \
+ ./hh/bta_hh_api.c \
+ ./hh/bta_hh_utils.c \
+ ./hh/bta_hh_main.c \
+ ./dg/bta_dg_act.c \
+ ./dg/bta_dg_main.c \
+ ./dg/bta_dg_api.c \
+ ./dg/bta_dg_cfg.c \
+ ./dg/bta_dg_ci.c \
+ ./ft/bta_ft_cfg.c \
+ ./ft/bta_ftc_main.c \
+ ./ft/bta_fts_utils.c \
+ ./ft/bta_fts_sdp.c \
+ ./ft/bta_ftc_api.c \
+ ./ft/bta_ftc_act.c \
+ ./ft/bta_fts_act.c \
+ ./ft/bta_fts_api.c \
+ ./ft/bta_fts_main.c \
+ ./ft/bta_ftc_utils.c \
+ ./pb/bta_pbs_act.c \
+ ./pb/bta_pbs_api.c \
+ ./pb/bta_pbs_sdp.c \
+ ./pb/bta_pbs_utils.c \
+ ./pb/bta_pbs_ci.c \
+ ./pb/bta_pbs_main.c \
+ ./pb/bta_pbs_cfg.c \
+ ./fs/bta_fs_ci.c \
+ ./fs/bta_fs_cfg.c \
+ ./pan/bta_pan_main.c \
+ ./pan/bta_pan_ci.c \
+ ./pan/bta_pan_act.c \
+ ./pan/bta_pan_api.c \
+ ./av/bta_av_act.c \
+ ./av/bta_av_ci.c \
+ ./av/bta_av_api.c \
+ ./av/bta_av_aact.c \
+ ./av/bta_av_main.c \
+ ./av/bta_av_cfg.c \
+ ./av/bta_av_ssm.c \
+ ./hl/bta_hl_act.c \
+ ./hl/bta_hl_api.c \
+ ./hl/bta_hl_main.c \
+ ./hl/bta_hl_utils.c \
+ ./hl/bta_hl_sdp.c \
+ ./hl/bta_hl_ci.c \
+ ./sys/bta_sys_main.c \
+ ./sys/bta_sys_ci.c \
+ ./sys/bta_sys_conn.c \
+ ./sys/bta_sys_cfg.c \
+ ./sys/ptim.c \
+ ./sys/bd.c \
+ ./sys/utl.c
+
+LOCAL_MODULE := libbt-brcm_bta
+LOCAL_MODULE_TAGS := eng
+LOCAL_SHARED_LIBRARIES := libcutils libc
+
+LOCAL_C_INCLUDES+= . \
+ $(LOCAL_PATH)/include \
+ $(LOCAL_PATH)/sys \
+ $(LOCAL_PATH)/dm \
+ $(LOCAL_PATH)/../gki/common \
+ $(LOCAL_PATH)/../gki/ulinux \
+ $(LOCAL_PATH)/../include \
+ $(LOCAL_PATH)/../stack/include \
+ $(LOCAL_PATH)/../stack/btm \
+ $(LOCAL_PATH)/../hcis \
+ $(LOCAL_PATH)/../hcis/patchram \
+ $(LOCAL_PATH)/../udrv/include \
+
+include $(BUILD_STATIC_LIBRARY)
+
+endif # TARGET_SIMULATOR != true
diff --git a/bta/ag/bta_ag_act.c b/bta/ag/bta_ag_act.c
new file mode 100644
index 0000000..af7c371
--- /dev/null
+++ b/bta/ag/bta_ag_act.c
@@ -0,0 +1,848 @@
+/*****************************************************************************
+**
+** Name: bta_ag_act.c
+**
+** Description: This file contains action functions for the audio gateway.
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bta_api.h"
+#include "bd.h"
+#include "bta_sys.h"
+#include "bta_ag_api.h"
+#include "bta_ag_co.h"
+#include "bta_ag_int.h"
+#include "port_api.h"
+#include "utl.h"
+#include <string.h>
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+/* maximum length of data to read from RFCOMM */
+#define BTA_AG_RFC_READ_MAX 512
+
+/* maximum AT command length */
+#define BTA_AG_CMD_MAX 512
+
+const UINT16 bta_ag_uuid[BTA_AG_NUM_IDX] =
+{
+ UUID_SERVCLASS_HEADSET_AUDIO_GATEWAY,
+ UUID_SERVCLASS_AG_HANDSFREE
+};
+
+const UINT8 bta_ag_sec_id[BTA_AG_NUM_IDX] =
+{
+ BTM_SEC_SERVICE_HEADSET_AG,
+ BTM_SEC_SERVICE_AG_HANDSFREE
+};
+
+const tBTA_SERVICE_ID bta_ag_svc_id[BTA_AG_NUM_IDX] =
+{
+ BTA_HSP_SERVICE_ID,
+ BTA_HFP_SERVICE_ID
+};
+
+const tBTA_SERVICE_MASK bta_ag_svc_mask[BTA_AG_NUM_IDX] =
+{
+ BTA_HSP_SERVICE_MASK,
+ BTA_HFP_SERVICE_MASK
+};
+
+typedef void (*tBTA_AG_ATCMD_CBACK)(tBTA_AG_SCB *p_scb, UINT16 cmd, UINT8 arg_type,
+ char *p_arg, INT16 int_arg);
+
+const tBTA_AG_ATCMD_CBACK bta_ag_at_cback_tbl[BTA_AG_NUM_IDX] =
+{
+ bta_ag_at_hsp_cback,
+ bta_ag_at_hfp_cback
+};
+
+/*******************************************************************************
+**
+** Function bta_ag_cback_open
+**
+** Description Send open callback event to application.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ag_cback_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data, tBTA_AG_STATUS status)
+{
+ tBTA_AG_OPEN open;
+
+ /* call app callback with open event */
+ open.hdr.handle = bta_ag_scb_to_idx(p_scb);
+ open.hdr.app_id = p_scb->app_id;
+ open.status = status;
+ open.service_id = bta_ag_svc_id[p_scb->conn_service];
+ if(p_data)
+ {
+ /* if p_data is provided then we need to pick the bd address from the open api structure */
+ bdcpy(open.bd_addr, p_data->api_open.bd_addr);
+ }
+ else
+ {
+ bdcpy(open.bd_addr, p_scb->peer_addr);
+ }
+
+ (*bta_ag_cb.p_cback)(BTA_AG_OPEN_EVT, (tBTA_AG *) &open);
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_register
+**
+** Description This function initializes values of the AG cb and sets up
+** the SDP record for the services.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_register(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ tBTA_AG_REGISTER reg;
+
+ /* initialize control block */
+ p_scb->reg_services = p_data->api_register.services;
+ p_scb->serv_sec_mask = p_data->api_register.sec_mask;
+ p_scb->features = p_data->api_register.features;
+ p_scb->app_id = p_data->api_register.app_id;
+
+ /* create SDP records */
+ bta_ag_create_records(p_scb, p_data);
+
+ /* start RFCOMM servers */
+ bta_ag_start_servers(p_scb, p_scb->reg_services);
+
+ /* call app callback with register event */
+ reg.hdr.handle = bta_ag_scb_to_idx(p_scb);
+ reg.hdr.app_id = p_scb->app_id;
+ reg.status = BTA_AG_SUCCESS;
+ (*bta_ag_cb.p_cback)(BTA_AG_REGISTER_EVT, (tBTA_AG *) &reg);
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_deregister
+**
+** Description This function removes the sdp records, closes the RFCOMM
+** servers, and deallocates the service control block.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_deregister(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ /* set dealloc */
+ p_scb->dealloc = TRUE;
+
+ /* remove sdp records */
+ bta_ag_del_records(p_scb, p_data);
+
+ /* remove rfcomm servers */
+ bta_ag_close_servers(p_scb, p_scb->reg_services);
+
+ /* dealloc */
+ bta_ag_scb_dealloc(p_scb);
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_start_dereg
+**
+** Description Start a deregister event.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_start_dereg(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ /* set dealloc */
+ p_scb->dealloc = TRUE;
+
+ /* remove sdp records */
+ bta_ag_del_records(p_scb, p_data);
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_start_open
+**
+** Description This starts an AG open.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_start_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ BD_ADDR pending_bd_addr;
+
+ /* store parameters */
+ if (p_data)
+ {
+ bdcpy(p_scb->peer_addr, p_data->api_open.bd_addr);
+ p_scb->open_services = p_data->api_open.services;
+ p_scb->cli_sec_mask = p_data->api_open.sec_mask;
+ }
+
+ /* Check if RFCOMM has any incoming connection to avoid collision. */
+ if (PORT_IsOpening (pending_bd_addr))
+ {
+ /* Let the incoming connection goes through. */
+ /* Issue collision for this scb for now. */
+ /* We will decide what to do when we find incoming connetion later. */
+ bta_ag_collision_cback (0, BTA_ID_AG, 0, p_scb->peer_addr);
+ return;
+ }
+
+ /* close servers */
+ bta_ag_close_servers(p_scb, p_scb->reg_services);
+
+ /* set role */
+ p_scb->role = BTA_AG_INT;
+
+ /* do service search */
+ bta_ag_do_disc(p_scb, p_scb->open_services);
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_disc_int_res
+**
+** Description This function handles a discovery result when initiator.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_disc_int_res(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ UINT16 event = BTA_AG_DISC_FAIL_EVT;
+
+ APPL_TRACE_DEBUG1 ("bta_ag_disc_int_res: Status: %d", p_data->disc_result.status);
+
+ /* if found service */
+ if (p_data->disc_result.status == SDP_SUCCESS ||
+ p_data->disc_result.status == SDP_DB_FULL)
+ {
+ /* get attributes */
+ if (bta_ag_sdp_find_attr(p_scb, p_scb->open_services))
+ {
+ /* set connected service */
+ p_scb->conn_service = bta_ag_service_to_idx(p_scb->open_services);
+
+ /* send ourselves sdp ok event */
+ event = BTA_AG_DISC_OK_EVT;
+ }
+ }
+
+ /* free discovery db */
+ bta_ag_free_db(p_scb, p_data);
+
+ /* if service not found check if we should search for other service */
+ if ((event == BTA_AG_DISC_FAIL_EVT) &&
+ (p_data->disc_result.status == SDP_SUCCESS ||
+ p_data->disc_result.status == SDP_DB_FULL ||
+ p_data->disc_result.status == SDP_NO_RECS_MATCH))
+ {
+ if ((p_scb->open_services & BTA_HFP_SERVICE_MASK) &&
+ (p_scb->open_services & BTA_HSP_SERVICE_MASK))
+ {
+ /* search for HSP */
+ p_scb->open_services &= ~BTA_HFP_SERVICE_MASK;
+ bta_ag_do_disc(p_scb, p_scb->open_services);
+ }
+ else if ((p_scb->open_services & BTA_HSP_SERVICE_MASK) &&
+ (p_scb->hsp_version == HSP_VERSION_1_2))
+ {
+ /* search for UUID_SERVCLASS_HEADSET for HSP 1.0 device */
+ p_scb->hsp_version = HSP_VERSION_1_0;
+ bta_ag_do_disc(p_scb, p_scb->open_services);
+ }
+ else
+ {
+ /* send ourselves sdp ok/fail event */
+ bta_ag_sm_execute(p_scb, event, p_data);
+ }
+ }
+ else
+ {
+ /* send ourselves sdp ok/fail event */
+ bta_ag_sm_execute(p_scb, event, p_data);
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_disc_acp_res
+**
+** Description This function handles a discovery result when acceptor.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_disc_acp_res(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ /* if found service */
+ if (p_data->disc_result.status == SDP_SUCCESS ||
+ p_data->disc_result.status == SDP_DB_FULL)
+ {
+ /* get attributes */
+ bta_ag_sdp_find_attr(p_scb, bta_ag_svc_mask[p_scb->conn_service]);
+ }
+
+ /* free discovery db */
+ bta_ag_free_db(p_scb, p_data);
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_disc_fail
+**
+** Description This function handles a discovery failure.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_disc_fail(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ /* reopen registered servers */
+ bta_ag_start_servers(p_scb, p_scb->reg_services);
+
+ /* reinitialize stuff */
+
+ /* call open cback w. failure */
+ bta_ag_cback_open(p_scb, NULL, BTA_AG_FAIL_SDP);
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_open_fail
+**
+** Description open connection failed.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_open_fail(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ /* call open cback w. failure */
+ bta_ag_cback_open(p_scb, p_data, BTA_AG_FAIL_RESOURCES);
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_rfc_fail
+**
+** Description RFCOMM connection failed.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_rfc_fail(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ /* reinitialize stuff */
+ p_scb->conn_handle = 0;
+ p_scb->conn_service = 0;
+ p_scb->peer_features = 0;
+#if (BTM_WBS_INCLUDED == TRUE )
+ p_scb->peer_codecs = BTA_AG_CODEC_NONE;
+ p_scb->sco_codec = BTA_AG_CODEC_NONE;
+#endif
+ p_scb->role = 0;
+ p_scb->svc_conn = FALSE;
+ p_scb->hsp_version = HSP_VERSION_1_2;
+
+ /* reopen registered servers */
+ bta_ag_start_servers(p_scb, p_scb->reg_services);
+
+ /* call open cback w. failure */
+ bta_ag_cback_open(p_scb, NULL, BTA_AG_FAIL_RFCOMM);
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_rfc_close
+**
+** Description RFCOMM connection closed.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_rfc_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ tBTA_AG_HDR close;
+ tBTA_SERVICE_MASK services;
+ int i, num_active_conn = 0;
+
+#ifdef _WIN32_WCE
+ /* The BTE RFCOMM automatically removes the connection when closed, but BTW does not */
+ if (p_scb->conn_handle != 0)
+ RFCOMM_RemoveConnection (p_scb->conn_handle);
+#endif
+
+ /* reinitialize stuff */
+ p_scb->conn_service = 0;
+ p_scb->peer_features = 0;
+#if (BTM_WBS_INCLUDED == TRUE )
+ p_scb->peer_codecs = BTA_AG_CODEC_NONE;
+ p_scb->sco_codec = BTA_AG_CODEC_NONE;
+#endif
+ p_scb->role = 0;
+ p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+ p_scb->svc_conn = FALSE;
+ p_scb->hsp_version = HSP_VERSION_1_2;
+ bta_ag_at_reinit(&p_scb->at_cb);
+
+ /* stop timers */
+ bta_sys_stop_timer(&p_scb->act_timer);
+#if (BTM_WBS_INCLUDED == TRUE)
+ bta_sys_stop_timer(&p_scb->cn_timer);
+#endif
+
+ close.handle = bta_ag_scb_to_idx(p_scb);
+ close.app_id = p_scb->app_id;
+
+ bta_sys_conn_close(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+
+ /* call close call-out */
+ bta_ag_co_data_close(close.handle);
+
+ /* call close cback */
+ (*bta_ag_cb.p_cback)(BTA_AG_CLOSE_EVT, (tBTA_AG *) &close);
+
+ /* if not deregistering (deallocating) reopen registered servers */
+ if (p_scb->dealloc == FALSE)
+ {
+ /* Clear peer bd_addr so instance can be reused */
+ bdcpy(p_scb->peer_addr, bd_addr_null);
+
+ /* start only unopened server */
+ services = p_scb->reg_services;
+ for (i = 0; i < BTA_AG_NUM_IDX && services != 0; i++)
+ {
+ if(p_scb->serv_handle[i])
+ services &= ~((tBTA_SERVICE_MASK)1 << (BTA_HSP_SERVICE_ID + i));
+ }
+ bta_ag_start_servers(p_scb, services);
+
+ p_scb->conn_handle = 0;
+
+ /* Make sure SCO state is BTA_AG_SCO_SHUTDOWN_ST */
+ bta_ag_sco_shutdown(p_scb, NULL);
+
+ /* Check if all the SLCs are down */
+ for (i = 0; i < BTA_AG_NUM_SCB; i++)
+ {
+ if (bta_ag_cb.scb[i].in_use && bta_ag_cb.scb[i].svc_conn)
+ num_active_conn++;
+ }
+
+ if(!num_active_conn)
+ {
+ bta_sys_sco_unuse(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+ }
+
+ }
+ /* else close port and deallocate scb */
+ else
+ {
+ RFCOMM_RemoveServer(p_scb->conn_handle);
+ bta_ag_scb_dealloc(p_scb);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_rfc_open
+**
+** Description Handle RFCOMM channel open.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_rfc_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ /* initialize AT feature variables */
+ p_scb->clip_enabled = FALSE;
+ p_scb->ccwa_enabled = FALSE;
+ p_scb->cmer_enabled = FALSE;
+ p_scb->cmee_enabled = FALSE;
+ p_scb->inband_enabled = ((p_scb->features & BTA_AG_FEAT_INBAND) == BTA_AG_FEAT_INBAND);
+
+ /* set up AT command interpreter */
+ p_scb->at_cb.p_at_tbl = (tBTA_AG_AT_CMD *) bta_ag_at_tbl[p_scb->conn_service];
+ p_scb->at_cb.p_cmd_cback = (tBTA_AG_AT_CMD_CBACK *) bta_ag_at_cback_tbl[p_scb->conn_service];
+ p_scb->at_cb.p_err_cback = (tBTA_AG_AT_ERR_CBACK *) bta_ag_at_err_cback;
+ p_scb->at_cb.p_user = p_scb;
+ p_scb->at_cb.cmd_max_len = BTA_AG_CMD_MAX;
+ bta_ag_at_init(&p_scb->at_cb);
+
+ /* call app open call-out */
+ bta_ag_co_data_open(bta_ag_scb_to_idx(p_scb), bta_ag_svc_id[p_scb->conn_service]);
+
+ bta_sys_conn_open(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+
+ bta_ag_cback_open(p_scb, NULL, BTA_AG_SUCCESS);
+
+ if (p_scb->conn_service == BTA_AG_HFP)
+ {
+ /* if hfp start timer for service level conn */
+ bta_sys_start_timer(&p_scb->act_timer, BTA_AG_SVC_TOUT_EVT, p_bta_ag_cfg->conn_tout);
+ }
+ else
+ {
+ /* else service level conn is open */
+ bta_ag_svc_conn_open(p_scb, p_data);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_rfc_acp_open
+**
+** Description Handle RFCOMM channel open when accepting connection.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_rfc_acp_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ UINT16 lcid;
+ int i;
+ tBTA_AG_SCB *ag_scb, *other_scb;
+ BD_ADDR dev_addr;
+ int status;
+
+ /* set role */
+ p_scb->role = BTA_AG_ACP;
+
+ APPL_TRACE_DEBUG2 ("bta_ag_rfc_acp_open: serv_handle0 = %d serv_handle1 = %d",
+ p_scb->serv_handle[0], p_scb->serv_handle[1]);
+
+ /* get bd addr of peer */
+ if (PORT_SUCCESS != (status=PORT_CheckConnection(p_data->rfc.port_handle, dev_addr, &lcid)))
+ {
+ APPL_TRACE_DEBUG1 ("bta_ag_rfc_acp_open error PORT_CheckConnection returned status %d", status);
+ }
+
+ /* Collision Handling */
+ for (i = 0, ag_scb = &bta_ag_cb.scb[0]; i < BTA_AG_NUM_SCB; i++, ag_scb++)
+ {
+ if ((ag_scb->in_use) && (ag_scb->colli_tmr_on))
+ {
+ /* stop collision timer */
+ ag_scb->colli_tmr_on = FALSE;
+ bta_sys_stop_timer (&ag_scb->colli_timer);
+
+ if (bdcmp (dev_addr, ag_scb->peer_addr) == 0)
+ {
+ /* If incoming and outgoing device are same, nothing more to do. */
+ /* Outgoing conn will be aborted because we have successful incoming conn. */
+ }
+ else
+ {
+ /* Resume outgoing connection. */
+ other_scb = bta_ag_get_other_idle_scb (p_scb);
+ if (other_scb)
+ {
+ bdcpy(other_scb->peer_addr, ag_scb->peer_addr);
+ other_scb->open_services = ag_scb->open_services;
+ other_scb->cli_sec_mask = ag_scb->cli_sec_mask;
+
+ bta_ag_resume_open (other_scb);
+ }
+ }
+
+ break;
+ }
+ }
+
+ bdcpy (p_scb->peer_addr, dev_addr);
+
+ /* determine connected service from port handle */
+ for (i = 0; i < BTA_AG_NUM_IDX; i++)
+ {
+ APPL_TRACE_DEBUG3 ("bta_ag_rfc_acp_open: i = %d serv_handle = %d port_handle = %d",
+ i, p_scb->serv_handle[i], p_data->rfc.port_handle);
+
+ if (p_scb->serv_handle[i] == p_data->rfc.port_handle)
+ {
+ p_scb->conn_service = i;
+ p_scb->conn_handle = p_data->rfc.port_handle;
+ break;
+ }
+ }
+
+ APPL_TRACE_DEBUG2 ("bta_ag_rfc_acp_open: conn_service = %d conn_handle = %d",
+ p_scb->conn_service, p_scb->conn_handle);
+
+ /* close any unopened server */
+ bta_ag_close_servers(p_scb, (p_scb->reg_services & ~bta_ag_svc_mask[p_scb->conn_service]));
+
+ /* do service discovery to get features */
+ bta_ag_do_disc(p_scb, bta_ag_svc_mask[p_scb->conn_service]);
+
+ /* continue with common open processing */
+ bta_ag_rfc_open(p_scb, p_data);
+
+
+
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_rfc_data
+**
+** Description Read and process data from RFCOMM.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_rfc_data(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ UINT16 len;
+ char buf[BTA_AG_RFC_READ_MAX];
+
+ memset(buf, 0, BTA_AG_RFC_READ_MAX);
+
+ /* do the following */
+ for(;;)
+ {
+ /* read data from rfcomm; if bad status, we're done */
+ if (PORT_ReadData(p_scb->conn_handle, buf, BTA_AG_RFC_READ_MAX, &len) != PORT_SUCCESS)
+ {
+ break;
+ }
+
+ /* if no data, we're done */
+ if (len == 0)
+ {
+ break;
+ }
+
+ /* run AT command interpreter on data */
+ bta_ag_at_parse(&p_scb->at_cb, buf, len);
+
+ /* no more data to read, we're done */
+ if (len < BTA_AG_RFC_READ_MAX)
+ {
+ break;
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_start_close
+**
+** Description Start the process of closing SCO and RFCOMM connection.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_start_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ /* if SCO is open close SCO and wait on RFCOMM close */
+ if (bta_ag_sco_is_open(p_scb))
+ {
+ p_scb->post_sco = BTA_AG_POST_SCO_CLOSE_RFC;
+ }
+ else
+ {
+ p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+ bta_ag_rfc_do_close(p_scb, p_data);
+ }
+
+ /* always do SCO shutdown to handle all SCO corner cases */
+ bta_ag_sco_shutdown(p_scb, p_data);
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_post_sco_open
+**
+** Description Perform post-SCO open action, if any
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_post_sco_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ switch (p_scb->post_sco)
+ {
+ case BTA_AG_POST_SCO_RING:
+ bta_ag_send_ring(p_scb, p_data);
+ p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+ break;
+
+ case BTA_AG_POST_SCO_CALL_CONN:
+ bta_ag_send_call_inds(p_scb, BTA_AG_IN_CALL_CONN_RES);
+ p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+ break;
+
+ default:
+ break;
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_post_sco_close
+**
+** Description Perform post-SCO close action, if any
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_post_sco_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ switch (p_scb->post_sco)
+ {
+ case BTA_AG_POST_SCO_CLOSE_RFC:
+ bta_ag_rfc_do_close(p_scb, p_data);
+ p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+ break;
+
+ case BTA_AG_POST_SCO_CALL_CONN:
+ bta_ag_send_call_inds(p_scb, BTA_AG_IN_CALL_CONN_RES);
+ p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+ break;
+
+ case BTA_AG_POST_SCO_CALL_ORIG:
+ bta_ag_send_call_inds(p_scb, BTA_AG_OUT_CALL_ORIG_RES);
+ p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+ break;
+
+ case BTA_AG_POST_SCO_CALL_END:
+ bta_ag_send_call_inds(p_scb, BTA_AG_END_CALL_RES);
+ p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+ break;
+
+ case BTA_AG_POST_SCO_CALL_END_INCALL:
+ bta_ag_send_call_inds(p_scb, BTA_AG_END_CALL_RES);
+
+ /* Sending callsetup IND and Ring were defered to after SCO close. */
+ bta_ag_send_call_inds(p_scb, BTA_AG_IN_CALL_RES);
+
+ if (bta_ag_inband_enabled(p_scb) && !(p_scb->features & BTA_AG_FEAT_NOSCO))
+ {
+ p_scb->post_sco = BTA_AG_POST_SCO_RING;
+ bta_ag_sco_open(p_scb, p_data);
+ }
+ else
+ {
+ p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+ bta_ag_send_ring(p_scb, p_data);
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_svc_conn_open
+**
+** Description Service level connection opened
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_svc_conn_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ tBTA_AG_CONN evt;
+
+ if (!p_scb->svc_conn)
+ {
+ /* set state variable */
+ p_scb->svc_conn = TRUE;
+
+ /* Clear AT+BIA mask from previous SLC if any. */
+ p_scb->bia_masked_out = 0;
+
+ /* stop timer */
+ bta_sys_stop_timer(&p_scb->act_timer);
+
+ /* call callback */
+ evt.hdr.handle = bta_ag_scb_to_idx(p_scb);
+ evt.hdr.app_id = p_scb->app_id;
+ evt.peer_feat = p_scb->peer_features;
+#if (BTM_WBS_INCLUDED == TRUE )
+ evt.peer_codec = p_scb->peer_codecs;
+#endif
+
+ if ((p_scb->call_ind != BTA_AG_CALL_INACTIVE) ||
+ (p_scb->callsetup_ind != BTA_AG_CALLSETUP_NONE))
+ {
+ bta_sys_sco_use(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+ }
+
+ (*bta_ag_cb.p_cback)(BTA_AG_CONN_EVT, (tBTA_AG *) &evt);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_ci_rx_data
+**
+** Description Send result code
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_ci_rx_data(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ UINT16 len;
+ tBTA_AG_CI_RX_WRITE *p_rx_write_msg = (tBTA_AG_CI_RX_WRITE *)p_data;
+ char *p_data_area = (char *)(p_rx_write_msg+1); /* Point to data area after header */
+
+ /* send to RFCOMM */
+ PORT_WriteData(p_scb->conn_handle, p_data_area, strlen(p_data_area), &len);
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_rcvd_slc_ready
+**
+** Description Handles SLC ready call-in in case of pass-through mode.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_rcvd_slc_ready(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ APPL_TRACE_DEBUG1("bta_ag_rcvd_slc_ready: handle = %d", bta_ag_scb_to_idx(p_scb));
+
+ if (bta_ag_cb.parse_mode == BTA_AG_PASS_THROUGH)
+ {
+ /* In pass-through mode, BTA knows that SLC is ready only through call-in. */
+ bta_ag_svc_conn_open(p_scb, NULL);
+ }
+}
+
diff --git a/bta/ag/bta_ag_api.c b/bta/ag/bta_ag_api.c
new file mode 100644
index 0000000..d2e38e2
--- /dev/null
+++ b/bta/ag/bta_ag_api.c
@@ -0,0 +1,310 @@
+/*****************************************************************************
+**
+** Name: bta_ag_api.c
+**
+** Description: This is the implementation of the API for the audio gateway
+** (AG) subsystem of BTA, Widcomm's Bluetooth application
+** layer for mobile phones.
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bta_api.h"
+#include "bd.h"
+#include "bta_sys.h"
+#include "bta_ag_api.h"
+#include "bta_ag_int.h"
+#include "gki.h"
+#include <string.h>
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+static const tBTA_SYS_REG bta_ag_reg =
+{
+ bta_ag_hdl_event,
+ BTA_AgDisable
+};
+
+/*******************************************************************************
+**
+** Function BTA_AgEnable
+**
+** Description Enable the audio gateway service. When the enable
+** operation is complete the callback function will be
+** called with a BTA_AG_ENABLE_EVT. This function must
+** be called before other function in the AG API are
+** called.
+**
+** Returns BTA_SUCCESS if OK, BTA_FAILURE otherwise.
+**
+*******************************************************************************/
+tBTA_STATUS BTA_AgEnable(tBTA_AG_PARSE_MODE parse_mode, tBTA_AG_CBACK *p_cback)
+{
+ tBTA_AG_API_ENABLE *p_buf;
+ UINT8 idx;
+
+ /* Error if AG is already enabled, or AG is in the middle of disabling. */
+ for (idx = 0; idx < BTA_AG_NUM_SCB; idx++)
+ {
+ if (bta_ag_cb.scb[idx].in_use)
+ {
+ APPL_TRACE_ERROR0 ("BTA_AgEnable: FAILED, AG already enabled.");
+ return BTA_FAILURE;
+ }
+ }
+
+ /* register with BTA system manager */
+ GKI_sched_lock();
+ bta_sys_register(BTA_ID_AG, &bta_ag_reg);
+ GKI_sched_unlock();
+
+ if ((p_buf = (tBTA_AG_API_ENABLE *) GKI_getbuf(sizeof(tBTA_AG_API_ENABLE))) != NULL)
+ {
+ p_buf->hdr.event = BTA_AG_API_ENABLE_EVT;
+ p_buf->parse_mode = parse_mode;
+ p_buf->p_cback = p_cback;
+ bta_sys_sendmsg(p_buf);
+ }
+
+ return BTA_SUCCESS;
+
+}
+
+/*******************************************************************************
+**
+** Function BTA_AgDisable
+**
+** Description Disable the audio gateway service
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AgDisable(void)
+{
+ BT_HDR *p_buf;
+
+ if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->event = BTA_AG_API_DISABLE_EVT;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_AgRegister
+**
+** Description Register an Audio Gateway service.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AgRegister(tBTA_SERVICE_MASK services, tBTA_SEC sec_mask,tBTA_AG_FEAT features,
+ char * p_service_names[], UINT8 app_id)
+{
+ tBTA_AG_API_REGISTER *p_buf;
+ int i;
+
+ if ((p_buf = (tBTA_AG_API_REGISTER *) GKI_getbuf(sizeof(tBTA_AG_API_REGISTER))) != NULL)
+ {
+ p_buf->hdr.event = BTA_AG_API_REGISTER_EVT;
+ p_buf->features = features;
+ p_buf->sec_mask = sec_mask;
+ p_buf->services = services;
+ p_buf->app_id = app_id;
+ for (i = 0; i < BTA_AG_NUM_IDX; i++)
+ {
+ if(p_service_names[i])
+ {
+ BCM_STRNCPY_S(p_buf->p_name[i], BTA_SERVICE_NAME_LEN+1, p_service_names[i], BTA_SERVICE_NAME_LEN);
+ p_buf->p_name[i][BTA_SERVICE_NAME_LEN] = 0;
+ }
+ else
+ {
+ p_buf->p_name[i][0] = 0;
+ }
+ }
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_AgDeregister
+**
+** Description Deregister an audio gateway service.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AgDeregister(UINT16 handle)
+{
+ BT_HDR *p_buf;
+
+ if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->event = BTA_AG_API_DEREGISTER_EVT;
+ p_buf->layer_specific = handle;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_AgOpen
+**
+** Description Opens a connection to a headset or hands-free device.
+** When connection is open callback function is called
+** with a BTA_AG_OPEN_EVT. Only the data connection is
+** opened. The audio connection is not opened.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AgOpen(UINT16 handle, BD_ADDR bd_addr, tBTA_SEC sec_mask, tBTA_SERVICE_MASK services)
+{
+ tBTA_AG_API_OPEN *p_buf;
+
+ if ((p_buf = (tBTA_AG_API_OPEN *) GKI_getbuf(sizeof(tBTA_AG_API_OPEN))) != NULL)
+ {
+ p_buf->hdr.event = BTA_AG_API_OPEN_EVT;
+ p_buf->hdr.layer_specific = handle;
+ bdcpy(p_buf->bd_addr, bd_addr);
+ p_buf->services = services;
+ p_buf->sec_mask = sec_mask;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_AgClose
+**
+** Description Close the current connection to a headset or a handsfree
+** Any current audio connection will also be closed.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AgClose(UINT16 handle)
+{
+ BT_HDR *p_buf;
+
+ if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->event = BTA_AG_API_CLOSE_EVT;
+ p_buf->layer_specific = handle;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_AgAudioOpen
+**
+** Description Opens an audio connection to the currently connected
+** headset or hnadsfree.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AgAudioOpen(UINT16 handle)
+{
+ BT_HDR *p_buf;
+
+ if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->event = BTA_AG_API_AUDIO_OPEN_EVT;
+ p_buf->layer_specific = handle;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_AgAudioClose
+**
+** Description Close the currently active audio connection to a headset
+** or hnadsfree. The data connection remains open
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AgAudioClose(UINT16 handle)
+{
+ BT_HDR *p_buf;
+
+ if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->event = BTA_AG_API_AUDIO_CLOSE_EVT;
+ p_buf->layer_specific = handle;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function BTA_AgResult
+**
+** Description Send an AT result code to a headset or hands-free device.
+** This function is only used when the AG parse mode is set
+** to BTA_AG_PARSE.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AgResult(UINT16 handle, tBTA_AG_RES result, tBTA_AG_RES_DATA *p_data)
+{
+ tBTA_AG_API_RESULT *p_buf;
+
+ if ((p_buf = (tBTA_AG_API_RESULT *) GKI_getbuf(sizeof(tBTA_AG_API_RESULT))) != NULL)
+ {
+ p_buf->hdr.event = BTA_AG_API_RESULT_EVT;
+ p_buf->hdr.layer_specific = handle;
+ p_buf->result = result;
+ if(p_data)
+ {
+ memcpy(&p_buf->data, p_data, sizeof(p_buf->data));
+ }
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_AgSetCodec
+**
+** Description Specify the codec type to be used for the subsequent
+** audio connection.
+**
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AgSetCodec(UINT16 handle, tBTA_AG_PEER_CODEC codec)
+{
+ tBTA_AG_API_SETCODEC *p_buf;
+
+ if ((p_buf = (tBTA_AG_API_SETCODEC *) GKI_getbuf(sizeof(tBTA_AG_API_SETCODEC))) != NULL)
+ {
+ p_buf->hdr.event = BTA_AG_API_SETCODEC_EVT;
+ p_buf->hdr.layer_specific = handle;
+ p_buf->codec = codec;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
diff --git a/bta/ag/bta_ag_at.c b/bta/ag/bta_ag_at.c
new file mode 100644
index 0000000..4d3bcac
--- /dev/null
+++ b/bta/ag/bta_ag_at.c
@@ -0,0 +1,230 @@
+/*****************************************************************************
+**
+** Name: bta_ag_at.c
+**
+** Description: BTA AG AT command interpreter.
+**
+** Copyright (c) 2004-2005, Widcomm Inc., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include <string.h>
+#include "gki.h"
+#include "bta_ag_at.h"
+#include "utl.h"
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+/******************************************************************************
+**
+** Function bta_ag_at_init
+**
+** Description Initialize the AT command parser control block.
+**
+**
+** Returns void
+**
+******************************************************************************/
+void bta_ag_at_init(tBTA_AG_AT_CB *p_cb)
+{
+ p_cb->p_cmd_buf = NULL;
+ p_cb->cmd_pos = 0;
+}
+
+/******************************************************************************
+**
+** Function bta_ag_at_reinit
+**
+** Description Re-initialize the AT command parser control block. This
+** function resets the AT command parser state and frees
+** any GKI buffer.
+**
+**
+** Returns void
+**
+******************************************************************************/
+void bta_ag_at_reinit(tBTA_AG_AT_CB *p_cb)
+{
+ if (p_cb->p_cmd_buf != NULL)
+ {
+ GKI_freebuf(p_cb->p_cmd_buf);
+ p_cb->p_cmd_buf = NULL;
+ }
+ p_cb->cmd_pos = 0;
+}
+/******************************************************************************
+**
+** Function bta_ag_process_at
+**
+** Description Parse AT commands. This function will take the input
+** character string and parse it for AT commands according to
+** the AT command table passed in the control block.
+**
+**
+** Returns void
+**
+******************************************************************************/
+void bta_ag_process_at(tBTA_AG_AT_CB *p_cb)
+{
+ UINT16 idx;
+ UINT8 arg_type;
+ char *p_arg;
+ INT16 int_arg = 0;
+ /* loop through at command table looking for match */
+ for (idx = 0; p_cb->p_at_tbl[idx].p_cmd[0] != 0; idx++)
+ {
+ if (!utl_strucmp(p_cb->p_at_tbl[idx].p_cmd, p_cb->p_cmd_buf))
+ {
+ break;
+ }
+ }
+
+ /* if there is a match; verify argument type */
+ if (p_cb->p_at_tbl[idx].p_cmd[0] != 0)
+ {
+ /* start of argument is p + strlen matching command */
+ p_arg = p_cb->p_cmd_buf + strlen(p_cb->p_at_tbl[idx].p_cmd);
+
+ /* if no argument */
+ if (p_arg[0] == 0)
+ {
+ arg_type = BTA_AG_AT_NONE;
+ }
+ /* else if arg is '?' and it is last character */
+ else if (p_arg[0] == '?' && p_arg[1] == 0)
+ {
+ /* we have a read */
+ arg_type = BTA_AG_AT_READ;
+ }
+ /* else if arg is '=' */
+ else if (p_arg[0] == '=' && p_arg[1] != 0)
+ {
+ if (p_arg[1] == '?' && p_arg[2] == 0)
+ {
+ /* we have a test */
+ arg_type = BTA_AG_AT_TEST;
+ }
+ else
+ {
+ /* we have a set */
+ arg_type = BTA_AG_AT_SET;
+
+ /* skip past '=' */
+ p_arg++;
+ }
+ }
+ else
+ /* else it is freeform argument */
+ {
+ arg_type = BTA_AG_AT_FREE;
+ }
+
+ /* if arguments match command capabilities */
+ if ((arg_type & p_cb->p_at_tbl[idx].arg_type) != 0)
+ {
+ /* if it's a set integer check max, min range */
+ if (arg_type == BTA_AG_AT_SET &&
+ p_cb->p_at_tbl[idx].fmt == BTA_AG_AT_INT)
+ {
+ int_arg = utl_str2int(p_arg);
+ if (int_arg < (INT16) p_cb->p_at_tbl[idx].min ||
+ int_arg > (INT16) p_cb->p_at_tbl[idx].max)
+ {
+ /* arg out of range; error */
+ (*p_cb->p_err_cback)(p_cb->p_user, FALSE, NULL);
+ }
+ else
+ {
+
+ (*p_cb->p_cmd_cback)(p_cb->p_user, idx, arg_type, p_arg, int_arg);
+ }
+ }
+ else
+ {
+ (*p_cb->p_cmd_cback)(p_cb->p_user, idx, arg_type, p_arg, int_arg);
+ }
+ }
+ /* else error */
+ else
+ {
+ (*p_cb->p_err_cback)(p_cb->p_user, FALSE, NULL);
+ }
+ }
+ /* else no match call error callback */
+ else
+ {
+ (*p_cb->p_err_cback)(p_cb->p_user, TRUE, p_cb->p_cmd_buf);
+ }
+}
+
+/******************************************************************************
+**
+** Function bta_ag_at_parse
+**
+** Description Parse AT commands. This function will take the input
+** character string and parse it for AT commands according to
+** the AT command table passed in the control block.
+**
+**
+** Returns void
+**
+******************************************************************************/
+void bta_ag_at_parse(tBTA_AG_AT_CB *p_cb, char *p_buf, UINT16 len)
+{
+ int i = 0;
+ char* p_save;
+
+ if (p_cb->p_cmd_buf == NULL)
+ {
+ p_cb->p_cmd_buf = (char *) GKI_getbuf(p_cb->cmd_max_len);
+ p_cb->cmd_pos = 0;
+ }
+
+ for (i = 0; i < len;)
+ {
+ while (p_cb->cmd_pos < p_cb->cmd_max_len-1 && i < len)
+ {
+ /* Skip null characters between AT commands. */
+ if ((p_cb->cmd_pos == 0) && (p_buf[i] == 0))
+ {
+ i++;
+ continue;
+ }
+
+ p_cb->p_cmd_buf[p_cb->cmd_pos] = p_buf[i++];
+ if ( p_cb->p_cmd_buf[p_cb->cmd_pos] == '\r' || p_cb->p_cmd_buf[p_cb->cmd_pos] == '\n')
+ {
+ p_cb->p_cmd_buf[p_cb->cmd_pos] = 0;
+ if ((p_cb->cmd_pos > 2) &&
+ (p_cb->p_cmd_buf[0] == 'A' || p_cb->p_cmd_buf[0] == 'a') &&
+ (p_cb->p_cmd_buf[1] == 'T' || p_cb->p_cmd_buf[1] == 't'))
+ {
+ p_save = p_cb->p_cmd_buf;
+ p_cb->p_cmd_buf += 2;
+ bta_ag_process_at(p_cb);
+ p_cb->p_cmd_buf = p_save;
+ }
+
+ p_cb->cmd_pos = 0;
+
+ }
+ else if( p_cb->p_cmd_buf[p_cb->cmd_pos] == 0x1A || p_cb->p_cmd_buf[p_cb->cmd_pos] == 0x1B )
+ {
+ p_cb->p_cmd_buf[++p_cb->cmd_pos] = 0;
+ (*p_cb->p_err_cback)(p_cb->p_user, TRUE, p_cb->p_cmd_buf);
+ p_cb->cmd_pos = 0;
+ }
+ else
+ {
+ ++p_cb->cmd_pos;
+ }
+ }
+
+ if (i < len)
+ p_cb->cmd_pos = 0;
+ }
+}
+
diff --git a/bta/ag/bta_ag_at.h b/bta/ag/bta_ag_at.h
new file mode 100644
index 0000000..2bdd6ae
--- /dev/null
+++ b/bta/ag/bta_ag_at.h
@@ -0,0 +1,108 @@
+/*****************************************************************************
+**
+** Name: bta_ag_at.h
+**
+** Description: Interface file for BTA AG AT command interpreter.
+**
+** Copyright (c) 2004-2005, Widcomm Inc., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_AG_AT_H
+#define BTA_AG_AT_H
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+/* AT command argument capabilities */
+#define BTA_AG_AT_NONE 0x01 /* no argument */
+#define BTA_AG_AT_SET 0x02 /* set value */
+#define BTA_AG_AT_READ 0x04 /* read value */
+#define BTA_AG_AT_TEST 0x08 /* test value range */
+#define BTA_AG_AT_FREE 0x10 /* freeform argument */
+
+/* AT command argument format */
+#define BTA_AG_AT_STR 0 /* string */
+#define BTA_AG_AT_INT 1 /* integer */
+
+/*****************************************************************************
+** Data types
+*****************************************************************************/
+
+/* AT command table element */
+typedef struct
+{
+ const char *p_cmd; /* AT command string */
+ UINT8 arg_type; /* allowable argument type syntax */
+ UINT8 fmt; /* whether arg is int or string */
+ UINT8 min; /* minimum value for int arg */
+ INT16 max; /* maximum value for int arg */
+} tBTA_AG_AT_CMD;
+
+/* callback function executed when command is parsed */
+typedef void (tBTA_AG_AT_CMD_CBACK)(void *p_user, UINT16 cmd, UINT8 arg_type,
+ char *p_arg, INT16 int_arg);
+
+/* callback function executed to send "ERROR" result code */
+typedef void (tBTA_AG_AT_ERR_CBACK)(void *p_user, BOOLEAN unknown, char *p_arg);
+
+/* AT command parsing control block */
+typedef struct
+{
+ tBTA_AG_AT_CMD *p_at_tbl; /* AT command table */
+ tBTA_AG_AT_CMD_CBACK *p_cmd_cback; /* command callback */
+ tBTA_AG_AT_ERR_CBACK *p_err_cback; /* error callback */
+ void *p_user; /* user-defined data */
+ char *p_cmd_buf; /* temp parsing buffer */
+ UINT16 cmd_pos; /* position in temp buffer */
+ UINT16 cmd_max_len; /* length of temp buffer to allocate */
+ UINT8 state; /* parsing state */
+} tBTA_AG_AT_CB;
+
+/*****************************************************************************
+** Function prototypes
+*****************************************************************************/
+
+/*****************************************************************************
+**
+** Function bta_ag_at_init
+**
+** Description Initialize the AT command parser control block.
+**
+**
+** Returns void
+**
+*****************************************************************************/
+extern void bta_ag_at_init(tBTA_AG_AT_CB *p_cb);
+
+/*****************************************************************************
+**
+** Function bta_ag_at_reinit
+**
+** Description Re-initialize the AT command parser control block. This
+** function resets the AT command parser state and frees
+** any GKI buffer.
+**
+**
+** Returns void
+**
+*****************************************************************************/
+extern void bta_ag_at_reinit(tBTA_AG_AT_CB *p_cb);
+
+/*****************************************************************************
+**
+** Function bta_ag_at_parse
+**
+** Description Parse AT commands. This function will take the input
+** character string and parse it for AT commands according to
+** the AT command table passed in the control block.
+**
+**
+** Returns void
+**
+*****************************************************************************/
+extern void bta_ag_at_parse(tBTA_AG_AT_CB *p_cb, char *p_buf, UINT16 len);
+
+#endif /* BTA_AG_AT_H */
+
diff --git a/bta/ag/bta_ag_cfg.c b/bta/ag/bta_ag_cfg.c
new file mode 100644
index 0000000..4f878a4
--- /dev/null
+++ b/bta/ag/bta_ag_cfg.c
@@ -0,0 +1,51 @@
+/*****************************************************************************
+**
+** Name: bta_ag_cfg.c
+**
+** Description: This file contains compile-time configurable constants
+** for the audio gateway.
+**
+** Copyright (c) 2003-2006, Broadcom Corp., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "gki.h"
+#include "bta_api.h"
+#include "bta_ag_api.h"
+
+#ifndef BTA_AG_CIND_INFO
+#define BTA_AG_CIND_INFO "(\"call\",(0,1)),(\"callsetup\",(0-3)),(\"service\",(0-3)),(\"signal\",(0-6)),(\"roam\",(0,1)),(\"battchg\",(0-5)),(\"callheld\",(0-2)),(\"bearer\",(0-7))"
+#endif
+
+#ifndef BTA_AG_CHLD_VAL_ECC
+#define BTA_AG_CHLD_VAL_ECC "(0,1,1x,2,2x,3,4)"
+#endif
+
+#ifndef BTA_AG_CHLD_VAL
+#define BTA_AG_CHLD_VAL "(0,1,2,3,4)"
+#endif
+
+#ifndef BTA_AG_CONN_TIMEOUT
+#define BTA_AG_CONN_TIMEOUT 5000
+#endif
+
+#ifndef BTA_AG_SCO_PKT_TYPES
+/* S1 packet type setting from HFP 1.5 spec */
+#define BTA_AG_SCO_PKT_TYPES /* BTM_SCO_LINK_ALL_PKT_MASK */ (BTM_SCO_LINK_ONLY_MASK | \
+ BTM_SCO_PKT_TYPES_MASK_EV3 | \
+ BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 | \
+ BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 | \
+ BTM_SCO_PKT_TYPES_MASK_NO_3_EV5)
+#endif
+
+const tBTA_AG_CFG bta_ag_cfg =
+{
+ BTA_AG_CIND_INFO,
+ BTA_AG_CONN_TIMEOUT,
+ BTA_AG_SCO_PKT_TYPES,
+ BTA_AG_CHLD_VAL_ECC,
+ BTA_AG_CHLD_VAL
+};
+
+tBTA_AG_CFG *p_bta_ag_cfg = (tBTA_AG_CFG *) &bta_ag_cfg;
diff --git a/bta/ag/bta_ag_ci.c b/bta/ag/bta_ag_ci.c
new file mode 100644
index 0000000..bbd1a55
--- /dev/null
+++ b/bta/ag/bta_ag_ci.c
@@ -0,0 +1,86 @@
+/*****************************************************************************
+**
+** Name: bta_ag_ci.c
+**
+** Description: This is the implementation file for audio gateway call-in
+** functions.
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include <string.h>
+#include "bta_api.h"
+#include "bta_ag_api.h"
+#include "bta_ag_int.h"
+#include "bta_ag_ci.h"
+#include "gki.h"
+
+/******************************************************************************
+**
+** Function bta_ag_ci_rx_write
+**
+** Description This function is called to send data to the AG when the AG
+** is configured for AT command pass-through. The function
+** copies data to an event buffer and sends it.
+**
+** Returns void
+**
+******************************************************************************/
+void bta_ag_ci_rx_write(UINT16 handle, char *p_data, UINT16 len)
+{
+ tBTA_AG_CI_RX_WRITE *p_buf;
+ UINT16 len_remaining = len;
+ char *p_data_area;
+
+ if (len > (RFCOMM_DATA_POOL_BUF_SIZE - sizeof(tBTA_AG_CI_RX_WRITE) - 1))
+ len = RFCOMM_DATA_POOL_BUF_SIZE - sizeof(tBTA_AG_CI_RX_WRITE) - 1;
+
+ while (len_remaining)
+ {
+ if (len_remaining < len)
+ len = len_remaining;
+
+ if ((p_buf = (tBTA_AG_CI_RX_WRITE *) GKI_getbuf((UINT16)(sizeof(tBTA_AG_CI_RX_WRITE) + len + 1))) != NULL)
+ {
+ p_buf->hdr.event = BTA_AG_CI_RX_WRITE_EVT;
+ p_buf->hdr.layer_specific = handle;
+
+ p_data_area = (char *)(p_buf+1); /* Point to data area after header */
+ strncpy(p_data_area, p_data, len);
+ p_data_area[len] = 0;
+
+ bta_sys_sendmsg(p_buf);
+ } else {
+ APPL_TRACE_ERROR1("ERROR: Unable to allocate buffer to hold AT response code. len=%i", len);
+ break;
+ }
+
+ len_remaining-=len;
+ p_data+=len;
+ }
+}
+
+/******************************************************************************
+**
+** Function bta_ag_ci_slc_ready
+**
+** Description This function is called to notify AG that SLC is up at
+** the application. This funcion is only used when the app
+** is running in pass-through mode.
+**
+** Returns void
+**
+******************************************************************************/
+void bta_ag_ci_slc_ready(UINT16 handle)
+{
+ tBTA_AG_DATA *p_buf;
+
+ if ((p_buf = (tBTA_AG_DATA *)GKI_getbuf(sizeof(tBTA_AG_DATA))) != NULL)
+ {
+ p_buf->hdr.event = BTA_AG_CI_SLC_READY_EVT;
+ p_buf->hdr.layer_specific = handle;
+ bta_sys_sendmsg(p_buf);
+ }
+}
diff --git a/bta/ag/bta_ag_cmd.c b/bta/ag/bta_ag_cmd.c
new file mode 100644
index 0000000..af86e26
--- /dev/null
+++ b/bta/ag/bta_ag_cmd.c
@@ -0,0 +1,1789 @@
+/*****************************************************************************
+**
+** Name: bta_ag_cmd.c
+**
+** Description: This file contains functions for processing AT commands
+** and results.
+**
+** Copyright (c) 2004-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bta_api.h"
+#include "bta_sys.h"
+#include "bta_ag_api.h"
+#include "bta_ag_int.h"
+#include "bta_ag_at.h"
+#include "port_api.h"
+#include "utl.h"
+#include <stdio.h>
+#include <string.h>
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+/* ring timeout */
+#define BTA_AG_RING_TOUT 4000
+
+#define BTA_AG_CMD_MAX_VAL 32767 /* Maximum value is signed 16-bit value */
+
+
+
+/* clip type constants */
+#define BTA_AG_CLIP_TYPE_MIN 128
+#define BTA_AG_CLIP_TYPE_MAX 175
+#define BTA_AG_CLIP_TYPE_DEFAULT 129
+#define BTA_AG_CLIP_TYPE_VOIP 255
+
+#if defined(BTA_AG_MULTI_RESULT_INCLUDED) && (BTA_AG_MULTI_RESULT_INCLUDED == TRUE)
+#define BTA_AG_AT_MULTI_LEN 2
+#define AT_SET_RES_CB(res_cb, c, p, i) {res_cb.code = c; res_cb.p_arg = p; res_cb.int_arg = i;}
+
+/* type for AT result code block */
+typedef struct
+{
+ UINT8 code;
+ char *p_arg;
+ INT16 int_arg;
+} tBTA_AG_RESULT_CB;
+
+/* type for multiple AT result codes block */
+typedef struct
+{
+ UINT8 num_result;
+ tBTA_AG_RESULT_CB res_cb[BTA_AG_AT_MULTI_LEN];
+} tBTA_AG_MULTI_RESULT_CB;
+#endif
+
+/* enumeration of HSP AT commands matches HSP command interpreter table */
+enum
+{
+ BTA_AG_HS_CMD_CKPD,
+ BTA_AG_HS_CMD_VGS,
+ BTA_AG_HS_CMD_VGM
+};
+
+/* enumeration of HFP AT commands matches HFP command interpreter table */
+enum
+{
+ BTA_AG_HF_CMD_A,
+ BTA_AG_HF_CMD_D,
+ BTA_AG_HF_CMD_VGS,
+ BTA_AG_HF_CMD_VGM,
+ BTA_AG_HF_CMD_CCWA,
+ BTA_AG_HF_CMD_CHLD,
+ BTA_AG_HF_CMD_CHUP,
+ BTA_AG_HF_CMD_CIND,
+ BTA_AG_HF_CMD_CLIP,
+ BTA_AG_HF_CMD_CMER,
+ BTA_AG_HF_CMD_VTS,
+ BTA_AG_HF_CMD_BINP,
+ BTA_AG_HF_CMD_BLDN,
+ BTA_AG_HF_CMD_BVRA,
+ BTA_AG_HF_CMD_BRSF,
+ BTA_AG_HF_CMD_NREC,
+ BTA_AG_HF_CMD_CNUM,
+ BTA_AG_HF_CMD_BTRH,
+ BTA_AG_HF_CMD_CLCC,
+ BTA_AG_HF_CMD_COPS,
+ BTA_AG_HF_CMD_CMEE,
+ BTA_AG_HF_CMD_BIA,
+ BTA_AG_HF_CMD_CBC,
+ BTA_AG_HF_CMD_BCC,
+ BTA_AG_HF_CMD_BCS,
+ BTA_AG_HF_CMD_BAC
+};
+
+/* AT command interpreter table for HSP */
+const tBTA_AG_AT_CMD bta_ag_hsp_cmd[] =
+{
+ {"+CKPD", BTA_AG_AT_SET, BTA_AG_AT_INT, 200, 200},
+ {"+VGS", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 15},
+ {"+VGM", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 15},
+ {"", BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0}
+};
+
+/* AT command interpreter table for HFP */
+const tBTA_AG_AT_CMD bta_ag_hfp_cmd[] =
+{
+ {"A", BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0},
+ {"D", (BTA_AG_AT_NONE | BTA_AG_AT_FREE), BTA_AG_AT_STR, 0, 0},
+ {"+VGS", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 15},
+ {"+VGM", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 15},
+ {"+CCWA", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 1},
+ /* Consider CHLD as str to take care of indexes for ECC */
+ {"+CHLD", (BTA_AG_AT_SET | BTA_AG_AT_TEST), BTA_AG_AT_STR, 0, 4},
+ {"+CHUP", BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0},
+ {"+CIND", (BTA_AG_AT_READ | BTA_AG_AT_TEST), BTA_AG_AT_STR, 0, 0},
+ {"+CLIP", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 1},
+ {"+CMER", BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 0},
+ {"+VTS", BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 0},
+ {"+BINP", BTA_AG_AT_SET, BTA_AG_AT_INT, 1, 1},
+ {"+BLDN", BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0},
+ {"+BVRA", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 1},
+ {"+BRSF", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, BTA_AG_CMD_MAX_VAL},
+ {"+NREC", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 0},
+ {"+CNUM", BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0},
+ {"+BTRH", (BTA_AG_AT_READ | BTA_AG_AT_SET), BTA_AG_AT_INT, 0, 2},
+ {"+CLCC", BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0},
+ {"+COPS", (BTA_AG_AT_READ | BTA_AG_AT_SET), BTA_AG_AT_STR, 0, 0},
+ {"+CMEE", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 1},
+ {"+BIA", BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 20},
+ {"+CBC", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 100},
+ {"+BCC", BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0},
+ {"+BCS", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, BTA_AG_CMD_MAX_VAL},
+ {"+BAC", BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 0},
+ {"", BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0}
+};
+
+/* AT result code table element */
+typedef struct
+{
+ const char *p_res; /* AT result string */
+ UINT8 fmt; /* whether argument is int or string */
+} tBTA_AG_RESULT;
+
+/* AT result code argument types */
+enum
+{
+ BTA_AG_RES_FMT_NONE, /* no argument */
+ BTA_AG_RES_FMT_INT, /* integer argument */
+ BTA_AG_RES_FMT_STR /* string argument */
+};
+
+/* enumeration of AT result codes, matches constant table */
+enum
+{
+ BTA_AG_RES_OK,
+ BTA_AG_RES_ERROR,
+ BTA_AG_RES_RING,
+ BTA_AG_RES_VGS,
+ BTA_AG_RES_VGM,
+ BTA_AG_RES_CCWA,
+ BTA_AG_RES_CHLD,
+ BTA_AG_RES_CIND,
+ BTA_AG_RES_CLIP,
+ BTA_AG_RES_CIEV,
+ BTA_AG_RES_BINP,
+ BTA_AG_RES_BVRA,
+ BTA_AG_RES_BRSF,
+ BTA_AG_RES_BSIR,
+ BTA_AG_RES_CNUM,
+ BTA_AG_RES_BTRH,
+ BTA_AG_RES_CLCC,
+ BTA_AG_RES_COPS,
+ BTA_AG_RES_CMEE,
+ BTA_AG_RES_BCS,
+ BTA_AG_RES_UNAT
+};
+
+#if defined(BTA_HSP_RESULT_REPLACE_COLON) && (BTA_HSP_RESULT_REPLACE_COLON == TRUE)
+#define COLON_IDX_4_VGSVGM 4
+#endif
+/* AT result code constant table (Indexed by result code) */
+const tBTA_AG_RESULT bta_ag_result_tbl[] =
+{
+ {"OK", BTA_AG_RES_FMT_NONE},
+ {"ERROR", BTA_AG_RES_FMT_NONE},
+ {"RING", BTA_AG_RES_FMT_NONE},
+ {"+VGS: ", BTA_AG_RES_FMT_INT},
+ {"+VGM: ", BTA_AG_RES_FMT_INT},
+ {"+CCWA: ", BTA_AG_RES_FMT_STR},
+ {"+CHLD: ", BTA_AG_RES_FMT_STR},
+ {"+CIND: ", BTA_AG_RES_FMT_STR},
+ {"+CLIP: ", BTA_AG_RES_FMT_STR},
+ {"+CIEV: ", BTA_AG_RES_FMT_STR},
+ {"+BINP: ", BTA_AG_RES_FMT_STR},
+ {"+BVRA: ", BTA_AG_RES_FMT_INT},
+ {"+BRSF: ", BTA_AG_RES_FMT_INT},
+ {"+BSIR: ", BTA_AG_RES_FMT_INT},
+ {"+CNUM: ", BTA_AG_RES_FMT_STR},
+ {"+BTRH: ", BTA_AG_RES_FMT_INT},
+ {"+CLCC: ", BTA_AG_RES_FMT_STR},
+ {"+COPS: ", BTA_AG_RES_FMT_STR},
+ {"+CME ERROR: ", BTA_AG_RES_FMT_INT},
+ {"+BCS: ", BTA_AG_RES_FMT_INT},
+ {"", BTA_AG_RES_FMT_STR}
+};
+
+const tBTA_AG_AT_CMD *bta_ag_at_tbl[BTA_AG_NUM_IDX] =
+{
+ bta_ag_hsp_cmd,
+ bta_ag_hfp_cmd
+};
+
+/* callback event lookup table for HSP */
+const tBTA_AG_EVT bta_ag_hsp_cb_evt[] =
+{
+ BTA_AG_AT_CKPD_EVT, /* BTA_AG_HS_CMD_CKPD */
+ BTA_AG_SPK_EVT, /* BTA_AG_HS_CMD_VGS */
+ BTA_AG_MIC_EVT /* BTA_AG_HS_CMD_VGM */
+};
+
+/* callback event lookup table for HFP (Indexed by command) */
+const tBTA_AG_EVT bta_ag_hfp_cb_evt[] =
+{
+ BTA_AG_AT_A_EVT, /* BTA_AG_HF_CMD_A */
+ BTA_AG_AT_D_EVT, /* BTA_AG_HF_CMD_D */
+ BTA_AG_SPK_EVT, /* BTA_AG_HF_CMD_VGS */
+ BTA_AG_MIC_EVT, /* BTA_AG_HF_CMD_VGM */
+ 0, /* BTA_AG_HF_CMD_CCWA */
+ BTA_AG_AT_CHLD_EVT, /* BTA_AG_HF_CMD_CHLD */
+ BTA_AG_AT_CHUP_EVT, /* BTA_AG_HF_CMD_CHUP */
+ BTA_AG_AT_CIND_EVT, /* BTA_AG_HF_CMD_CIND */
+ 0, /* BTA_AG_HF_CMD_CLIP */
+ 0, /* BTA_AG_HF_CMD_CMER */
+ BTA_AG_AT_VTS_EVT, /* BTA_AG_HF_CMD_VTS */
+ BTA_AG_AT_BINP_EVT, /* BTA_AG_HF_CMD_BINP */
+ BTA_AG_AT_BLDN_EVT, /* BTA_AG_HF_CMD_BLDN */
+ BTA_AG_AT_BVRA_EVT, /* BTA_AG_HF_CMD_BVRA */
+ 0, /* BTA_AG_HF_CMD_BRSF */
+ BTA_AG_AT_NREC_EVT, /* BTA_AG_HF_CMD_NREC */
+ BTA_AG_AT_CNUM_EVT, /* BTA_AG_HF_CMD_CNUM */
+ BTA_AG_AT_BTRH_EVT, /* BTA_AG_HF_CMD_BTRH */
+ BTA_AG_AT_CLCC_EVT, /* BTA_AG_HF_CMD_CLCC */
+ BTA_AG_AT_COPS_EVT, /* BTA_AG_HF_CMD_COPS */
+ 0, /* BTA_AG_HF_CMD_CMEE */
+ 0, /* BTA_AG_HF_CMD_BIA */
+ BTA_AG_AT_CBC_EVT, /* BTA_AG_HF_CMD_CBC */
+ 0, /* BTA_AG_HF_CMD_BCC */
+ BTA_AG_AT_BCS_EVT, /* BTA_AG_HF_CMD_BCS */
+ BTA_AG_AT_BAC_EVT /* BTA_AG_HF_CMD_BAC */
+};
+
+/* translation of API result code values to internal values */
+const UINT8 bta_ag_trans_result[] =
+{
+ BTA_AG_RES_VGS, /* BTA_AG_SPK_RES */
+ BTA_AG_RES_VGM, /* BTA_AG_MIC_RES */
+ BTA_AG_RES_BSIR, /* BTA_AG_INBAND_RING_RES */
+ BTA_AG_RES_CIND, /* BTA_AG_CIND_RES */
+ BTA_AG_RES_BINP, /* BTA_AG_BINP_RES */
+ BTA_AG_RES_CIEV, /* BTA_AG_IND_RES */
+ BTA_AG_RES_BVRA, /* BTA_AG_BVRA_RES */
+ BTA_AG_RES_CNUM, /* BTA_AG_CNUM_RES */
+ BTA_AG_RES_BTRH, /* BTA_AG_BTRH_RES */
+ BTA_AG_RES_CLCC, /* BTA_AG_CLCC_RES */
+ BTA_AG_RES_COPS, /* BTA_AG_COPS_RES */
+ 0, /* BTA_AG_IN_CALL_RES */
+ 0, /* BTA_AG_IN_CALL_CONN_RES */
+ BTA_AG_RES_CCWA, /* BTA_AG_CALL_WAIT_RES */
+ 0, /* BTA_AG_OUT_CALL_ORIG_RES */
+ 0, /* BTA_AG_OUT_CALL_ALERT_RES */
+ 0, /* BTA_AG_OUT_CALL_CONN_RES */
+ 0, /* BTA_AG_CALL_CANCEL_RES */
+ 0, /* BTA_AG_END_CALL_RES */
+ 0, /* BTA_AG_IN_CALL_HELD_RES */
+ BTA_AG_RES_UNAT /* BTA_AG_UNAT_RES */
+};
+
+/* callsetup indicator value lookup table */
+const UINT8 bta_ag_callsetup_ind_tbl[] =
+{
+ 0, /* BTA_AG_SPK_RES */
+ 0, /* BTA_AG_MIC_RES */
+ 0, /* BTA_AG_INBAND_RING_RES */
+ 0, /* BTA_AG_CIND_RES */
+ 0, /* BTA_AG_BINP_RES */
+ 0, /* BTA_AG_IND_RES */
+ 0, /* BTA_AG_BVRA_RES */
+ 0, /* BTA_AG_CNUM_RES */
+ 0, /* BTA_AG_BTRH_RES */
+ 0, /* BTA_AG_CLCC_RES */
+ 0, /* BTA_AG_COPS_RES */
+ BTA_AG_CALLSETUP_INCOMING, /* BTA_AG_IN_CALL_RES */
+ BTA_AG_CALLSETUP_NONE, /* BTA_AG_IN_CALL_CONN_RES */
+ BTA_AG_CALLSETUP_INCOMING, /* BTA_AG_CALL_WAIT_RES */
+ BTA_AG_CALLSETUP_OUTGOING, /* BTA_AG_OUT_CALL_ORIG_RES */
+ BTA_AG_CALLSETUP_ALERTING, /* BTA_AG_OUT_CALL_ALERT_RES */
+ BTA_AG_CALLSETUP_NONE, /* BTA_AG_OUT_CALL_CONN_RES */
+ BTA_AG_CALLSETUP_NONE, /* BTA_AG_CALL_CANCEL_RES */
+ BTA_AG_CALLSETUP_NONE, /* BTA_AG_END_CALL_RES */
+ BTA_AG_CALLSETUP_NONE /* BTA_AG_IN_CALL_HELD_RES */
+};
+
+/*******************************************************************************
+**
+** Function bta_ag_send_result
+**
+** Description Send an AT result code.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ag_send_result(tBTA_AG_SCB *p_scb, UINT8 code, char *p_arg,
+ INT16 int_arg)
+{
+ char buf[BTA_AG_AT_MAX_LEN + 16];
+ char *p = buf;
+ UINT16 len;
+
+#if defined(BTA_AG_RESULT_DEBUG) && (BTA_AG_RESULT_DEBUG == TRUE)
+ memset(buf, NULL, sizeof(buf));
+#endif
+ /* init with \r\n */
+ *p++ = '\r';
+ *p++ = '\n';
+
+ /* copy result code string */
+ BCM_STRCPY_S(p, sizeof(buf), bta_ag_result_tbl[code].p_res);
+#if defined(BTA_HSP_RESULT_REPLACE_COLON) && (BTA_HSP_RESULT_REPLACE_COLON == TRUE)
+ if(p_scb->conn_service == BTA_AG_HSP)
+ {
+ /* If HSP then ":"symbol should be changed as "=" for HSP compatibility */
+ switch(code)
+ {
+ case BTA_AG_RES_VGS:
+ case BTA_AG_RES_VGM:
+ if(*(p+COLON_IDX_4_VGSVGM) == ':')
+ {
+ #if defined(BTA_AG_RESULT_DEBUG) && (BTA_AG_RESULT_DEBUG == TRUE)
+ APPL_TRACE_DEBUG0("[HSP] ':'symbol is changed as '=' for HSP compatibility");
+ #endif
+ *(p+COLON_IDX_4_VGSVGM) = '=';
+ }
+ break;
+ }
+ }
+#endif
+ p += strlen(bta_ag_result_tbl[code].p_res);
+
+ /* copy argument if any */
+ if (bta_ag_result_tbl[code].fmt == BTA_AG_RES_FMT_INT)
+ {
+ p += utl_itoa((UINT16) int_arg, p);
+ }
+ else if (bta_ag_result_tbl[code].fmt == BTA_AG_RES_FMT_STR)
+ {
+ BCM_STRCPY_S(p, sizeof(buf), p_arg);
+ p += strlen(p_arg);
+ }
+
+ /* finish with \r\n */
+ *p++ = '\r';
+ *p++ = '\n';
+
+#if defined(BTA_AG_RESULT_DEBUG) && (BTA_AG_RESULT_DEBUG == TRUE)
+ APPL_TRACE_DEBUG1("bta_ag_send_result: %s", buf);
+#endif
+
+ /* send to RFCOMM */
+ PORT_WriteData(p_scb->conn_handle, buf, (UINT16) (p - buf), &len);
+}
+
+#if defined(BTA_AG_MULTI_RESULT_INCLUDED) && (BTA_AG_MULTI_RESULT_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function bta_ag_send_multi_result
+**
+** Description Send multiple AT result codes.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ag_send_multi_result(tBTA_AG_SCB *p_scb, tBTA_AG_MULTI_RESULT_CB *m_res_cb)
+{
+ char buf[BTA_AG_AT_MAX_LEN * BTA_AG_AT_MULTI_LEN + 16];
+ char *p = buf;
+ UINT16 len;
+ UINT8 res_idx = 0;
+
+ if((!m_res_cb) || (m_res_cb->num_result == 0) || (m_res_cb->num_result > BTA_AG_AT_MULTI_LEN))
+ {
+ APPL_TRACE_DEBUG0("m_res_cb is NULL or num_result is out of range.");
+ return;
+ }
+
+#if defined(BTA_AG_RESULT_DEBUG) && (BTA_AG_RESULT_DEBUG == TRUE)
+ memset(buf, NULL, sizeof(buf));
+#endif
+
+ while(res_idx < m_res_cb->num_result)
+ {
+ /* init with \r\n */
+ *p++ = '\r';
+ *p++ = '\n';
+
+ /* copy result code string */
+ BCM_STRCPY_S(p, sizeof(buf), bta_ag_result_tbl[m_res_cb->res_cb[res_idx].code].p_res);
+ p += strlen(bta_ag_result_tbl[m_res_cb->res_cb[res_idx].code].p_res);
+
+ /* copy argument if any */
+ if (bta_ag_result_tbl[m_res_cb->res_cb[res_idx].code].fmt == BTA_AG_RES_FMT_INT)
+ {
+ p += utl_itoa((UINT16) m_res_cb->res_cb[res_idx].int_arg, p);
+ }
+ else if (bta_ag_result_tbl[m_res_cb->res_cb[res_idx].code].fmt == BTA_AG_RES_FMT_STR)
+ {
+ BCM_STRCPY_S(p, sizeof(buf), m_res_cb->res_cb[res_idx].p_arg);
+ p += strlen(m_res_cb->res_cb[res_idx].p_arg);
+ }
+
+ /* finish with \r\n */
+ *p++ = '\r';
+ *p++ = '\n';
+
+ res_idx++;
+ }
+
+#if defined(BTA_AG_RESULT_DEBUG) && (BTA_AG_RESULT_DEBUG == TRUE)
+ APPL_TRACE_DEBUG1("send_result: %s", buf);
+#endif
+
+ /* send to RFCOMM */
+ PORT_WriteData(p_scb->conn_handle, buf, (UINT16) (p - buf), &len);
+}
+#endif
+
+/*******************************************************************************
+**
+** Function bta_ag_send_ok
+**
+** Description Send an OK result code.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ag_send_ok(tBTA_AG_SCB *p_scb)
+{
+ bta_ag_send_result(p_scb, BTA_AG_RES_OK, NULL, 0);
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_send_error
+**
+** Description Send an ERROR result code.
+** errcode - used to send verbose errocode
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ag_send_error(tBTA_AG_SCB *p_scb, INT16 errcode)
+{
+ /* If HFP and extended audio gateway error codes are enabled */
+ if (p_scb->conn_service == BTA_AG_HFP && p_scb->cmee_enabled)
+ bta_ag_send_result(p_scb, BTA_AG_RES_CMEE, NULL, errcode);
+ else
+ bta_ag_send_result(p_scb, BTA_AG_RES_ERROR, NULL, 0);
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_send_ind
+**
+** Description Send an indicator CIEV result code.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ag_send_ind(tBTA_AG_SCB *p_scb, UINT16 id, UINT16 value, BOOLEAN on_demand)
+{
+ char str[12];
+ char *p = str;
+
+ /* If the indicator is masked out, just return */
+ /* Mandatory indicators can not be masked out. */
+ if ((p_scb->bia_masked_out & ((UINT32)1 << id)) &&
+ ((id != BTA_AG_IND_CALL) && (id != BTA_AG_IND_CALLSETUP) && (id != BTA_AG_IND_CALLHELD)))
+ return;
+
+ /* Ensure we do not send duplicate indicators if not requested by app */
+ /* If it was requested by app, transmit CIEV even if it is duplicate. */
+ if (id == BTA_AG_IND_CALL)
+ {
+ if ((value == p_scb->call_ind) && (on_demand == FALSE))
+ return;
+
+ p_scb->call_ind = (UINT8)value;
+ }
+
+ if ((id == BTA_AG_IND_CALLSETUP) && (on_demand == FALSE))
+ {
+ if (value == p_scb->callsetup_ind)
+ return;
+
+ p_scb->callsetup_ind = (UINT8)value;
+ }
+
+ if ((id == BTA_AG_IND_CALLHELD) && (on_demand == FALSE))
+ {
+ if (value == p_scb->callheld_ind)
+ return;
+
+ p_scb->callheld_ind = (UINT8)value;
+ }
+
+ if (p_scb->cmer_enabled)
+ {
+ p += utl_itoa(id, p);
+ *p++ = ',';
+ utl_itoa(value, p);
+ bta_ag_send_result(p_scb, BTA_AG_RES_CIEV, str, 0);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_parse_cmer
+**
+** Description Parse AT+CMER parameter string.
+**
+**
+** Returns TRUE if parsed ok, FALSE otherwise.
+**
+*******************************************************************************/
+static BOOLEAN bta_ag_parse_cmer(char *p_s, BOOLEAN *p_enabled)
+{
+ INT16 n[4] = {-1, -1, -1, -1};
+ int i;
+ char *p;
+
+ for (i = 0; i < 4; i++)
+ {
+ /* skip to comma delimiter */
+ for (p = p_s; *p != ',' && *p != 0; p++);
+
+ /* get integer value */
+ *p = 0;
+ n[i] = utl_str2int(p_s);
+ p_s = p + 1;
+ if (p_s == 0)
+ {
+ break;
+ }
+ }
+
+ /* process values */
+ if (n[0] < 0 || n[3] < 0)
+ {
+ return FALSE;
+ }
+
+ if ((n[0] == 3) && ((n[3] == 1) || (n[3] == 0)))
+ {
+ *p_enabled = (BOOLEAN) n[3];
+ }
+
+ return TRUE;
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_parse_chld
+**
+** Description Parse AT+CHLD parameter string.
+**
+**
+** Returns Returns idx (1-7), or 0 if ECC not enabled or idx doesn't exist
+**
+*******************************************************************************/
+static UINT8 bta_ag_parse_chld(tBTA_AG_SCB *p_scb, char *p_s)
+{
+ UINT8 retval = 0;
+ INT16 idx = -1;
+
+ if (p_s[1] != 0)
+ {
+ /* p_idxstr++; point to beginning of call number */
+ idx = utl_str2int(&p_s[1]);
+ if (idx != -1 && idx < 255)
+ retval = (UINT8)idx;
+ }
+
+ return (retval);
+}
+
+#if (BTM_WBS_INCLUDED == TRUE )
+/*******************************************************************************
+**
+** Function bta_ag_parse_bac
+**
+** Description Parse AT+BAC parameter string.
+**
+** Returns Returns bitmap of supported codecs.
+**
+*******************************************************************************/
+static tBTA_AG_PEER_CODEC bta_ag_parse_bac(tBTA_AG_SCB *p_scb, char *p_s)
+{
+ tBTA_AG_PEER_CODEC retval = BTA_AG_CODEC_NONE;
+ UINT16 uuid_codec;
+ BOOLEAN cont = FALSE; /* Continue processing */
+ char *p;
+
+ while(p_s)
+ {
+ /* skip to comma delimiter */
+ for(p = p_s; *p != ',' && *p != 0; p++);
+
+ /* get integre value */
+ if (*p != 0)
+ {
+ *p = 0;
+ cont = TRUE;
+ }
+ else
+ cont = FALSE;
+
+ uuid_codec = utl_str2int(p_s);
+ switch(uuid_codec)
+ {
+ case UUID_CODEC_CVSD: retval |= BTA_AG_CODEC_CVSD; break;
+ case UUID_CODEC_MSBC: retval |= BTA_AG_CODEC_MSBC; break;
+ default:
+ APPL_TRACE_ERROR1("Unknown Codec UUID(%d) received", uuid_codec);
+ return BTA_AG_CODEC_NONE;
+ }
+
+ if (cont)
+ p_s = p + 1;
+ else
+ break;
+ }
+
+ return (retval);
+}
+#endif
+
+/*******************************************************************************
+**
+** Function bta_ag_process_unat_res
+**
+** Description Process the unat response data and remove extra carriage return
+** and line feed
+**
+**
+** Returns void
+**
+*******************************************************************************/
+
+static void bta_ag_process_unat_res(char *unat_result)
+{
+ UINT8 str_leng;
+ UINT8 i = 0;
+ UINT8 j = 0;
+ UINT8 pairs_of_nl_cr;
+ char trim_data[BTA_AG_AT_MAX_LEN];
+
+
+
+ str_leng = strlen(unat_result);
+
+ /* If no extra CR and LF, just return */
+ if(str_leng < 4)
+ return;
+
+ /* Remove the carriage return and left feed */
+ while(unat_result[0] =='\r' && unat_result[1] =='\n'
+ && unat_result[str_leng-2] =='\r' && unat_result[str_leng-1] =='\n')
+ {
+ pairs_of_nl_cr = 1;
+ for (i=0;i<(str_leng-4*pairs_of_nl_cr);i++)
+ {
+ trim_data[j++] = unat_result[i+pairs_of_nl_cr*2];
+ }
+ /* Add EOF */
+ trim_data[j] = '\0';
+ str_leng = str_leng - 4;
+ BCM_STRNCPY_S(unat_result, BTA_AG_AT_MAX_LEN+1, trim_data,str_leng+1);
+ i=0;
+ j=0;
+
+ if(str_leng <4)
+ return;
+
+
+ }
+ return;
+}
+
+
+/*******************************************************************************
+**
+** Function bta_ag_inband_enabled
+**
+** Description Determine whether in-band ring can be used.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BOOLEAN bta_ag_inband_enabled(tBTA_AG_SCB *p_scb)
+{
+ /* if feature is enabled and no other scbs connected */
+ if (p_scb->inband_enabled && !bta_ag_other_scb_open(p_scb))
+ {
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_send_call_inds
+**
+** Description Send call and callsetup indicators.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_send_call_inds(tBTA_AG_SCB *p_scb, tBTA_AG_RES result)
+{
+ UINT8 call = p_scb->call_ind;
+ UINT8 callsetup;
+
+ /* set new call and callsetup values based on BTA_AgResult */
+ callsetup = bta_ag_callsetup_ind_tbl[result];
+
+ if (result == BTA_AG_END_CALL_RES)
+ {
+ call = BTA_AG_CALL_INACTIVE;
+ }
+ else if (result == BTA_AG_IN_CALL_CONN_RES || result == BTA_AG_OUT_CALL_CONN_RES
+ || result == BTA_AG_IN_CALL_HELD_RES)
+ {
+ call = BTA_AG_CALL_ACTIVE;
+ }
+ else
+ {
+ call = p_scb->call_ind;
+ }
+
+ /* Send indicator function tracks if the values have actually changed */
+ bta_ag_send_ind(p_scb, BTA_AG_IND_CALL, call, FALSE);
+ bta_ag_send_ind(p_scb, BTA_AG_IND_CALLSETUP, callsetup, FALSE);
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_at_hsp_cback
+**
+** Description AT command processing callback for HSP.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_at_hsp_cback(tBTA_AG_SCB *p_scb, UINT16 cmd, UINT8 arg_type,
+ char *p_arg, INT16 int_arg)
+{
+ tBTA_AG_VAL val;
+
+ APPL_TRACE_DEBUG4("AT cmd:%d arg_type:%d arg:%d arg:%s", cmd, arg_type,
+ int_arg, p_arg);
+
+ /* send OK */
+ bta_ag_send_ok(p_scb);
+
+ val.hdr.handle = bta_ag_scb_to_idx(p_scb);
+ val.hdr.app_id = p_scb->app_id;
+ val.num = (UINT16) int_arg;
+ BCM_STRNCPY_S(val.str, sizeof(val.str), p_arg, BTA_AG_AT_MAX_LEN);
+ val.str[BTA_AG_AT_MAX_LEN] = 0;
+
+ /* call callback with event */
+ (*bta_ag_cb.p_cback)(bta_ag_hsp_cb_evt[cmd], (tBTA_AG *) &val);
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_at_hfp_cback
+**
+** Description AT command processing callback for HFP.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_at_hfp_cback(tBTA_AG_SCB *p_scb, UINT16 cmd, UINT8 arg_type,
+ char *p_arg, INT16 int_arg)
+{
+ tBTA_AG_VAL val;
+ tBTA_AG_EVT event;
+ tBTA_AG_SCB *ag_scb;
+ UINT32 i, ind_id;
+ UINT32 bia_masked_out;
+#if (BTM_WBS_INCLUDED == TRUE )
+ tBTA_AG_PEER_CODEC codec_type, codec_sent;
+#endif
+
+ APPL_TRACE_DEBUG4("HFP AT cmd:%d arg_type:%d arg:%d arg:%s", cmd, arg_type,
+ int_arg, p_arg);
+
+ val.hdr.handle = bta_ag_scb_to_idx(p_scb);
+ val.hdr.app_id = p_scb->app_id;
+ val.num = int_arg;
+ BCM_STRNCPY_S(val.str, sizeof(val.str), p_arg, BTA_AG_AT_MAX_LEN);
+ val.str[BTA_AG_AT_MAX_LEN] = 0;
+
+ event = bta_ag_hfp_cb_evt[cmd];
+
+ switch (cmd)
+ {
+ case BTA_AG_HF_CMD_A:
+ case BTA_AG_HF_CMD_VGS:
+ case BTA_AG_HF_CMD_VGM:
+ case BTA_AG_HF_CMD_CHUP:
+ case BTA_AG_HF_CMD_CBC:
+ /* send OK */
+ bta_ag_send_ok(p_scb);
+ break;
+
+ case BTA_AG_HF_CMD_BLDN:
+ /* Do not send OK, App will send error or OK depending on
+ ** last dial number enabled or not */
+ break;
+
+ case BTA_AG_HF_CMD_D:
+ /* Do not send OK for Dial cmds
+ ** Let application decide whether to send OK or ERROR*/
+
+ /* if mem dial cmd, make sure string contains only digits */
+ if(p_arg[0] == '>')
+ {
+ if(!utl_isintstr(p_arg+1))
+ {
+ event = 0;
+ bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_DSTR);
+ }
+ }
+ else if (p_arg[0] == 'V') /* ATDV : Dial VoIP Call */
+ {
+ /* We do not check string. Code will be added later if needed. */
+ if(!((p_scb->peer_features & BTA_AG_PEER_FEAT_VOIP) && (p_scb->features & BTA_AG_FEAT_VOIP)))
+ {
+ event = 0;
+ bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+ }
+ }
+ /* If dial cmd, make sure string contains only dial digits
+ ** Dial digits are 0-9, A-C, *, #, + */
+ else
+ {
+ if(!utl_isdialstr(p_arg))
+ {
+ event = 0;
+ bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_DSTR);
+ }
+ }
+ break;
+
+ case BTA_AG_HF_CMD_CCWA:
+ /* store setting */
+ p_scb->ccwa_enabled = (BOOLEAN) int_arg;
+
+ /* send OK */
+ bta_ag_send_ok(p_scb);
+ break;
+
+ case BTA_AG_HF_CMD_CHLD:
+ if (arg_type == BTA_AG_AT_TEST)
+ {
+ /* don't call callback */
+ event = 0;
+
+ /* send CHLD string */
+ /* Form string based on supported 1.5 feature */
+ if ((p_scb->peer_version >= HFP_VERSION_1_5) &&
+ (p_scb->features & BTA_AG_FEAT_ECC) &&
+ (p_scb->peer_features & BTA_AG_PEER_FEAT_ECC))
+ bta_ag_send_result(p_scb, BTA_AG_RES_CHLD, p_bta_ag_cfg->chld_val_ecc, 0);
+ else
+ bta_ag_send_result(p_scb, BTA_AG_RES_CHLD, p_bta_ag_cfg->chld_val, 0);
+
+ /* send OK */
+ bta_ag_send_ok(p_scb);
+
+ /* if service level conn. not already open, now it's open */
+ bta_ag_svc_conn_open(p_scb, NULL);
+
+ }
+ else
+ {
+ val.idx = bta_ag_parse_chld(p_scb, val.str);
+
+ if(val.idx && !((p_scb->features & BTA_AG_FEAT_ECC) && (p_scb->peer_features & BTA_AG_PEER_FEAT_ECC)))
+ {
+ /* we do not support ECC, but HF is sending us a CHLD with call index*/
+ event = 0;
+ bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+
+ }
+ else
+ {
+
+ /* If it is swap between calls, set call held indicator to 3(out of valid 0-2)
+ ** Application will set it back to 1
+ ** callheld indicator will be sent across to the peer. */
+ if(val.str[0] == '2')
+ {
+ for (i = 0, ag_scb = &bta_ag_cb.scb[0]; i < BTA_AG_NUM_SCB; i++, ag_scb++)
+ {
+ if (ag_scb->in_use)
+ {
+ if((ag_scb->call_ind == BTA_AG_CALL_ACTIVE)
+ && (ag_scb->callsetup_ind == BTA_AG_CALLSETUP_NONE))
+ ag_scb->callheld_ind = BTA_AG_CALLHELD_NOACTIVE + 1;
+ }
+ }
+ }
+ }
+
+ /* Do not send OK. Let app decide after parsing the val str */
+ /* bta_ag_send_ok(p_scb); */
+ }
+ break;
+
+ case BTA_AG_HF_CMD_CIND:
+ if (arg_type == BTA_AG_AT_TEST)
+ {
+ /* don't call callback */
+ event = 0;
+
+ /* send CIND string, send OK */
+ bta_ag_send_result(p_scb, BTA_AG_RES_CIND, p_bta_ag_cfg->cind_info, 0);
+ bta_ag_send_ok(p_scb);
+ }
+ break;
+
+ case BTA_AG_HF_CMD_CLIP:
+ /* store setting, send OK */
+ p_scb->clip_enabled = (BOOLEAN) int_arg;
+ bta_ag_send_ok(p_scb);
+ break;
+
+ case BTA_AG_HF_CMD_CMER:
+ /* if parsed ok store setting, send OK */
+ if (bta_ag_parse_cmer(p_arg, &p_scb->cmer_enabled))
+ {
+ bta_ag_send_ok(p_scb);
+
+ /* if service level conn. not already open and our features and
+ ** peer features do not have 3-way, service level conn. now open
+ */
+ if (!p_scb->svc_conn &&
+ !((p_scb->features & BTA_AG_FEAT_3WAY) && (p_scb->peer_features & BTA_AG_PEER_FEAT_3WAY)))
+ {
+ bta_ag_svc_conn_open(p_scb, NULL);
+ }
+ }
+ else
+ {
+ bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_TSTR);
+ }
+ break;
+
+ case BTA_AG_HF_CMD_VTS:
+ /* check argument */
+ if (strlen(p_arg) == 1)
+ {
+ bta_ag_send_ok(p_scb);
+ }
+ else
+ {
+ event = 0;
+ bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_TSTR);
+ }
+ break;
+
+ case BTA_AG_HF_CMD_BINP:
+ /* if feature not set don't call callback, send ERROR */
+ if (!(p_scb->features & BTA_AG_FEAT_VTAG))
+ {
+ event = 0;
+ bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+ }
+ break;
+
+ case BTA_AG_HF_CMD_BVRA:
+ /* if feature send OK, else don't call callback, send ERROR */
+ if (p_scb->features & BTA_AG_FEAT_VREC)
+ {
+ bta_ag_send_ok(p_scb);
+ }
+ else
+ {
+ event = 0;
+ bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+ }
+ break;
+
+ case BTA_AG_HF_CMD_BRSF:
+ /* store peer features */
+ p_scb->peer_features = (UINT16) int_arg;
+
+ /* send BRSF, send OK */
+ bta_ag_send_result(p_scb, BTA_AG_RES_BRSF, NULL,
+ (INT16) (p_scb->features & BTA_AG_BSRF_FEAT_SPEC));
+ bta_ag_send_ok(p_scb);
+ break;
+
+ case BTA_AG_HF_CMD_NREC:
+ /* if feature send OK, else don't call callback, send ERROR */
+ if (p_scb->features & BTA_AG_FEAT_ECNR)
+ {
+ bta_ag_send_ok(p_scb);
+ }
+ else
+ {
+ event = 0;
+ bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+ }
+ break;
+
+ case BTA_AG_HF_CMD_BTRH:
+ /* if feature send BTRH, send OK:, else don't call callback, send ERROR */
+ if (p_scb->features & BTA_AG_FEAT_BTRH)
+ {
+ /* If set command; send response and notify app */
+ if (arg_type == BTA_AG_AT_SET)
+ {
+ for (i = 0, ag_scb = &bta_ag_cb.scb[0]; i < BTA_AG_NUM_SCB; i++, ag_scb++)
+ {
+ if (ag_scb->in_use)
+ {
+ bta_ag_send_result(ag_scb, BTA_AG_RES_BTRH, NULL, int_arg);
+ }
+ }
+ bta_ag_send_ok(p_scb);
+ }
+ else /* Read Command */
+ {
+ val.num = BTA_AG_BTRH_READ;
+ }
+ }
+ else
+ {
+ event = 0;
+ bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+ }
+ break;
+
+ case BTA_AG_HF_CMD_COPS:
+ if (arg_type == BTA_AG_AT_SET)
+ {
+ /* don't call callback */
+ event = 0;
+
+ /* send OK */
+ bta_ag_send_ok(p_scb);
+ }
+ break;
+
+ case BTA_AG_HF_CMD_CMEE:
+ if (p_scb->features & BTA_AG_FEAT_EXTERR)
+ {
+ /* store setting */
+ p_scb->cmee_enabled = (BOOLEAN) int_arg;
+
+ /* send OK */
+ bta_ag_send_ok(p_scb);
+ }
+ else
+ {
+ bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+ }
+ /* don't call callback */
+ event = 0;
+ break;
+
+ case BTA_AG_HF_CMD_BIA:
+ /* don't call callback */
+ event = 0;
+
+ bia_masked_out = p_scb->bia_masked_out;
+
+ /* Parse the indicator mask */
+ for (i = 0, ind_id = 1; (val.str[i] != 0) && (ind_id <= 20); i++, ind_id++)
+ {
+ if (val.str[i] == ',')
+ continue;
+
+ if (val.str[i] == '0')
+ bia_masked_out |= ((UINT32)1 << ind_id);
+ else if (val.str[i] == '1')
+ bia_masked_out &= ~((UINT32)1 << ind_id);
+ else
+ break;
+
+ i++;
+ if ( (val.str[i] != 0) && (val.str[i] != ',') )
+ break;
+ }
+ if (val.str[i] == 0)
+ {
+ p_scb->bia_masked_out = bia_masked_out;
+ bta_ag_send_ok (p_scb);
+ }
+ else
+ bta_ag_send_error (p_scb, BTA_AG_ERR_INVALID_INDEX);
+ break;
+
+ case BTA_AG_HF_CMD_CNUM:
+ break;
+ case BTA_AG_HF_CMD_CLCC:
+ if(!(p_scb->features & BTA_AG_FEAT_ECS))
+ {
+ event = 0;
+ bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+ }
+ break;
+
+#if (BTM_WBS_INCLUDED == TRUE )
+ case BTA_AG_HF_CMD_BAC:
+ bta_ag_send_ok(p_scb);
+
+ /* store available codecs from the peer */
+ if((p_scb->peer_features & BTA_AG_PEER_FEAT_CODEC) && (p_scb->features & BTA_AG_FEAT_CODEC))
+ {
+ p_scb->peer_codecs = bta_ag_parse_bac(p_scb, p_arg);
+ p_scb->codec_updated = TRUE;
+
+ if (p_scb->peer_codecs & BTA_AG_CODEC_MSBC)
+ {
+ p_scb->sco_codec = UUID_CODEC_MSBC;
+ APPL_TRACE_DEBUG0("Received AT+BAC, updating sco codec to MSBC");
+ }
+ else
+ {
+ p_scb->sco_codec = UUID_CODEC_CVSD;
+ APPL_TRACE_DEBUG0("Received AT+BAC, updating sco codec to CVSD");
+ }
+
+ /* Received BAC while in codec negotiation. */
+ if ((bta_ag_cb.sco.state == BTA_AG_SCO_CODEC_ST) && (bta_ag_cb.sco.p_curr_scb == p_scb))
+ {
+ bta_ag_codec_negotiate (p_scb);
+ }
+ }
+ else
+ {
+ p_scb->peer_codecs = BTA_AG_CODEC_NONE;
+ APPL_TRACE_ERROR0("Unexpected CMD:AT+BAC, Codec Negotiation is not supported");
+ }
+ break;
+
+ case BTA_AG_HF_CMD_BCS:
+ /* stop cn timer */
+ bta_sys_stop_timer(&p_scb->cn_timer);
+
+ switch(int_arg)
+ {
+ case UUID_CODEC_CVSD: codec_type = BTA_AG_CODEC_CVSD; break;
+ case UUID_CODEC_MSBC: codec_type = BTA_AG_CODEC_MSBC; break;
+ default:
+ APPL_TRACE_ERROR1("Unknown codec_uuid %d", int_arg);
+ codec_type = 0xFFFF;
+ break;
+ }
+
+ if (p_scb->codec_fallback)
+ codec_sent = BTA_AG_CODEC_CVSD;
+ else
+ codec_sent = p_scb->sco_codec;
+
+ if(codec_type == codec_sent)
+ bta_ag_sco_codec_nego(p_scb, TRUE);
+ else
+ bta_ag_sco_codec_nego(p_scb, FALSE);
+
+ bta_ag_send_ok(p_scb);
+ break;
+
+ case BTA_AG_HF_CMD_BCC:
+ bta_ag_send_ok(p_scb);
+ bta_ag_sco_open(p_scb, NULL);
+ break;
+#endif
+
+ default:
+ break;
+ }
+
+ /* call callback */
+ if (event != 0)
+ {
+ (*bta_ag_cb.p_cback)(event, (tBTA_AG *) &val);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_at_err_cback
+**
+** Description AT command parser error callback.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_at_err_cback(tBTA_AG_SCB *p_scb, BOOLEAN unknown, char *p_arg)
+{
+ tBTA_AG_VAL val;
+
+ if(unknown && (!strlen(p_arg)))
+ {
+ APPL_TRACE_DEBUG0("Empty AT cmd string received");
+ bta_ag_send_ok(p_scb);
+ return;
+ }
+
+ /* if unknown AT command and configured to pass these to app */
+ if (unknown && (p_scb->features & BTA_AG_FEAT_UNAT))
+ {
+ val.hdr.handle = bta_ag_scb_to_idx(p_scb);
+ val.hdr.app_id = p_scb->app_id;
+ val.num = 0;
+ BCM_STRNCPY_S(val.str, sizeof(val.str), p_arg, BTA_AG_AT_MAX_LEN);
+ val.str[BTA_AG_AT_MAX_LEN] = 0;
+ (*bta_ag_cb.p_cback)(BTA_AG_AT_UNAT_EVT, (tBTA_AG *) &val);
+ }
+ else
+ {
+ bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_hsp_result
+**
+** Description Handle API result for HSP connections.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_hsp_result(tBTA_AG_SCB *p_scb, tBTA_AG_API_RESULT *p_result)
+{
+ UINT8 code = bta_ag_trans_result[p_result->result];
+
+ APPL_TRACE_DEBUG1("bta_ag_hsp_result : res = %d", p_result->result);
+
+ switch(p_result->result)
+ {
+ case BTA_AG_SPK_RES:
+ case BTA_AG_MIC_RES:
+ bta_ag_send_result(p_scb, code, NULL, p_result->data.num);
+ break;
+
+ case BTA_AG_IN_CALL_RES:
+ /* tell sys to stop av if any */
+ bta_sys_sco_use(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+
+ /* if sco already opened or no inband ring send ring now */
+ if (bta_ag_sco_is_open(p_scb) || !bta_ag_inband_enabled(p_scb) ||
+ (p_scb->features & BTA_AG_FEAT_NOSCO))
+ {
+ bta_ag_send_ring(p_scb, (tBTA_AG_DATA *) p_result);
+ }
+ /* else open sco, send ring after sco opened */
+ else
+ {
+ /* HSPv1.2: AG shall not send RING if using in-band ring tone. */
+ if (p_scb->hsp_version >= HSP_VERSION_1_2)
+ p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+ else
+ p_scb->post_sco = BTA_AG_POST_SCO_RING;
+
+ bta_ag_sco_open(p_scb, (tBTA_AG_DATA *) p_result);
+ }
+ break;
+
+ case BTA_AG_IN_CALL_CONN_RES:
+ case BTA_AG_OUT_CALL_ORIG_RES:
+ /* if incoming call connected stop ring timer */
+ if (p_result->result == BTA_AG_IN_CALL_CONN_RES)
+ {
+ bta_sys_stop_timer(&p_scb->act_timer);
+ }
+
+ if (!(p_scb->features & BTA_AG_FEAT_NOSCO))
+ {
+ /* if audio connected to this scb open sco */
+ if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb))
+ {
+ bta_ag_sco_open(p_scb, (tBTA_AG_DATA *) p_result);
+ }
+ /* else if no audio at call close sco */
+ else if (p_result->data.audio_handle == BTA_AG_HANDLE_NONE)
+ {
+ bta_ag_sco_close(p_scb, (tBTA_AG_DATA *) p_result);
+ }
+ }
+ break;
+
+ case BTA_AG_END_CALL_RES:
+ /* stop ring timer */
+ bta_sys_stop_timer(&p_scb->act_timer);
+
+ /* close sco */
+ if ((bta_ag_sco_is_open(p_scb) || bta_ag_sco_is_opening(p_scb)) && !(p_scb->features & BTA_AG_FEAT_NOSCO))
+ {
+ bta_ag_sco_close(p_scb, (tBTA_AG_DATA *) p_result);
+ }
+ else
+ {
+ /* if av got suspended by this call, let it resume. */
+ bta_sys_sco_unuse(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+ }
+ break;
+
+ case BTA_AG_INBAND_RING_RES:
+ p_scb->inband_enabled = p_result->data.state;
+ APPL_TRACE_DEBUG1("inband_enabled set to %d", p_scb->inband_enabled);
+ break;
+
+ case BTA_AG_UNAT_RES:
+ if (p_result->data.ok_flag != BTA_AG_OK_ERROR)
+ {
+ if (p_result->data.str[0] != 0)
+ {
+ bta_ag_send_result(p_scb, code, p_result->data.str, 0);
+ }
+
+ if (p_result->data.ok_flag == BTA_AG_OK_DONE)
+ bta_ag_send_ok(p_scb);
+ }
+ else
+ {
+ bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_TSTR);
+ }
+ break;
+
+ default:
+ /* ignore all others */
+ break;
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_hfp_result
+**
+** Description Handle API result for HFP connections.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_hfp_result(tBTA_AG_SCB *p_scb, tBTA_AG_API_RESULT *p_result)
+{
+ UINT8 code = bta_ag_trans_result[p_result->result];
+
+ APPL_TRACE_DEBUG1("bta_ag_hfp_result : res = %d", p_result->result);
+
+ switch(p_result->result)
+ {
+ case BTA_AG_SPK_RES:
+ case BTA_AG_MIC_RES:
+ bta_ag_send_result(p_scb, code, NULL, p_result->data.num);
+ break;
+
+ case BTA_AG_IN_CALL_RES:
+ /* tell sys to stop av if any */
+ bta_sys_sco_use(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+
+ /* store caller id string.
+ * append type info at the end.
+ * make sure a valid type info is passed.
+ * otherwise add 129 as default type */
+ if ((p_result->data.num < BTA_AG_CLIP_TYPE_MIN) || (p_result->data.num > BTA_AG_CLIP_TYPE_MAX))
+ {
+ if (p_result->data.num != BTA_AG_CLIP_TYPE_VOIP)
+ p_result->data.num = BTA_AG_CLIP_TYPE_DEFAULT;
+ }
+
+ APPL_TRACE_DEBUG1("CLIP type :%d", p_result->data.num);
+ p_scb->clip[0] = 0;
+ if (p_result->data.str[0] != 0)
+ sprintf(p_scb->clip,"%s,%d", p_result->data.str, p_result->data.num);
+
+ /* send callsetup indicator */
+ if (p_scb->post_sco == BTA_AG_POST_SCO_CALL_END)
+ {
+ /* Need to sent 2 callsetup IND's(Call End and Incoming call) after SCO close. */
+ p_scb->post_sco = BTA_AG_POST_SCO_CALL_END_INCALL;
+ }
+ else
+ {
+ bta_ag_send_call_inds(p_scb, p_result->result);
+
+ /* if sco already opened or no inband ring send ring now */
+ if (bta_ag_sco_is_open(p_scb) || !bta_ag_inband_enabled(p_scb) ||
+ (p_scb->features & BTA_AG_FEAT_NOSCO))
+ {
+ bta_ag_send_ring(p_scb, (tBTA_AG_DATA *) p_result);
+ }
+ /* else open sco, send ring after sco opened */
+ else
+ {
+ p_scb->post_sco = BTA_AG_POST_SCO_RING;
+ bta_ag_sco_open(p_scb, (tBTA_AG_DATA *) p_result);
+ }
+ }
+ break;
+
+ case BTA_AG_IN_CALL_CONN_RES:
+ /* stop ring timer */
+ bta_sys_stop_timer(&p_scb->act_timer);
+
+ /* if sco not opened and we need to open it, open sco first
+ ** then send indicators
+ */
+ if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb) &&
+ !bta_ag_sco_is_open(p_scb) && !(p_scb->features & BTA_AG_FEAT_NOSCO))
+ {
+ p_scb->post_sco = BTA_AG_POST_SCO_CALL_CONN;
+ bta_ag_sco_open(p_scb, (tBTA_AG_DATA *) p_result);
+ }
+ /* else if sco open and we need to close it, close sco first
+ ** then send indicators
+ */
+ else if (p_result->data.audio_handle == BTA_AG_HANDLE_NONE &&
+ bta_ag_sco_is_open(p_scb) && !(p_scb->features & BTA_AG_FEAT_NOSCO))
+ {
+ p_scb->post_sco = BTA_AG_POST_SCO_CALL_CONN;
+ bta_ag_sco_close(p_scb, (tBTA_AG_DATA *) p_result);
+ }
+ /* else send indicators now */
+ else
+ {
+ bta_ag_send_call_inds(p_scb, p_result->result);
+ }
+ break;
+
+ case BTA_AG_IN_CALL_HELD_RES:
+ /* stop ring timer */
+ bta_sys_stop_timer(&p_scb->act_timer);
+
+ bta_ag_send_call_inds(p_scb, p_result->result);
+
+ break;
+
+ case BTA_AG_OUT_CALL_ORIG_RES:
+ /* if sco open and we need to close it, close sco first
+ ** then send indicators; else send indicators now
+ */
+ if (p_result->data.audio_handle == BTA_AG_HANDLE_NONE &&
+ bta_ag_sco_is_open(p_scb) && !(p_scb->features & BTA_AG_FEAT_NOSCO))
+ {
+ p_scb->post_sco = BTA_AG_POST_SCO_CALL_ORIG;
+ bta_ag_sco_close(p_scb, (tBTA_AG_DATA *) p_result);
+ }
+ else
+ {
+ bta_ag_send_call_inds(p_scb, p_result->result);
+ if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb) &&
+ !(p_scb->features & BTA_AG_FEAT_NOSCO))
+ {
+ bta_ag_sco_open(p_scb, (tBTA_AG_DATA *) p_result);
+ }
+ }
+ break;
+
+ case BTA_AG_OUT_CALL_ALERT_RES:
+ /* send indicators */
+ bta_ag_send_call_inds(p_scb, p_result->result);
+ break;
+
+ case BTA_AG_OUT_CALL_CONN_RES:
+ /* send indicators */
+ bta_ag_send_call_inds(p_scb, p_result->result);
+
+ /* open or close sco */
+ if (!(p_scb->features & BTA_AG_FEAT_NOSCO))
+ {
+ if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb))
+ {
+ bta_ag_sco_open(p_scb, (tBTA_AG_DATA *) p_result);
+ }
+ else if (p_result->data.audio_handle == BTA_AG_HANDLE_NONE)
+ {
+ bta_ag_sco_close(p_scb, (tBTA_AG_DATA *) p_result);
+ }
+ }
+ break;
+
+ case BTA_AG_CALL_CANCEL_RES:
+ /* send indicators */
+ bta_ag_send_call_inds(p_scb, p_result->result);
+ break;
+
+ case BTA_AG_END_CALL_RES:
+ /* stop ring timer */
+ bta_sys_stop_timer(&p_scb->act_timer);
+
+ /* if sco open, close sco then send indicator values */
+ if ((bta_ag_sco_is_open(p_scb) || bta_ag_sco_is_opening(p_scb)) && !(p_scb->features & BTA_AG_FEAT_NOSCO))
+ {
+ p_scb->post_sco = BTA_AG_POST_SCO_CALL_END;
+ bta_ag_sco_close(p_scb, (tBTA_AG_DATA *) p_result);
+ }
+ else if (p_scb->post_sco == BTA_AG_POST_SCO_CALL_END_INCALL)
+ {
+ /* sco closing for outgoing call because of incoming call */
+ /* Send only callsetup end indicator after sco close */
+ p_scb->post_sco = BTA_AG_POST_SCO_CALL_END;
+ }
+ else
+ {
+ bta_ag_send_call_inds(p_scb, p_result->result);
+
+ /* if av got suspended by this call, let it resume. */
+ bta_sys_sco_unuse(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+ }
+ break;
+
+ case BTA_AG_INBAND_RING_RES:
+ p_scb->inband_enabled = p_result->data.state;
+ APPL_TRACE_DEBUG1("inband_enabled set to %d", p_scb->inband_enabled);
+ bta_ag_send_result(p_scb, code, NULL, p_result->data.state);
+ break;
+
+ case BTA_AG_CIND_RES:
+ /* store local values */
+ p_scb->call_ind = p_result->data.str[0] - '0';
+ p_scb->callsetup_ind = p_result->data.str[2] - '0';
+ APPL_TRACE_DEBUG2("cind call:%d callsetup:%d", p_scb->call_ind, p_scb->callsetup_ind);
+
+ bta_ag_send_result(p_scb, code, p_result->data.str, 0);
+ bta_ag_send_ok(p_scb);
+ break;
+
+ case BTA_AG_BINP_RES:
+ case BTA_AG_CNUM_RES:
+ case BTA_AG_CLCC_RES:
+ case BTA_AG_COPS_RES:
+ if (p_result->data.ok_flag != BTA_AG_OK_ERROR)
+ {
+ if (p_result->data.str[0] != 0)
+ {
+ bta_ag_send_result(p_scb, code, p_result->data.str, 0);
+ }
+
+ if (p_result->data.ok_flag == BTA_AG_OK_DONE)
+ bta_ag_send_ok(p_scb);
+ }
+ else
+ {
+ bta_ag_send_error(p_scb, p_result->data.errcode);
+ }
+ break;
+
+
+ case BTA_AG_UNAT_RES:
+ if (p_result->data.ok_flag != BTA_AG_OK_ERROR)
+ {
+ if (p_result->data.str[0] != 0)
+ {
+ bta_ag_process_unat_res(p_result->data.str);
+ APPL_TRACE_DEBUG1("BTA_AG_RES :%s",p_result->data.str);
+ bta_ag_send_result(p_scb, code, p_result->data.str, 0);
+ }
+
+ if (p_result->data.ok_flag == BTA_AG_OK_DONE)
+ bta_ag_send_ok(p_scb);
+ }
+ else
+ {
+ bta_ag_send_error(p_scb, p_result->data.errcode);
+ }
+ break;
+
+ case BTA_AG_CALL_WAIT_RES:
+ if (p_scb->ccwa_enabled)
+ {
+ bta_ag_send_result(p_scb, code, p_result->data.str, 0);
+ }
+ bta_ag_send_call_inds(p_scb, p_result->result);
+ break;
+
+ case BTA_AG_IND_RES:
+ bta_ag_send_ind(p_scb, p_result->data.ind.id, p_result->data.ind.value, TRUE);
+ break;
+
+ case BTA_AG_BVRA_RES:
+ bta_ag_send_result(p_scb, code, NULL, p_result->data.state);
+ break;
+
+ case BTA_AG_BTRH_RES:
+ if (p_result->data.ok_flag != BTA_AG_OK_ERROR)
+ {
+ /* Don't respond to read if not in response & hold state */
+ if (p_result->data.num != BTA_AG_BTRH_NO_RESP)
+ {
+ bta_ag_send_result(p_scb, code, NULL, p_result->data.num);
+ }
+
+ /* In case of a response to a read request we need to send OK */
+ if (p_result->data.ok_flag == BTA_AG_OK_DONE)
+ bta_ag_send_ok(p_scb);
+ }
+ else
+ {
+ bta_ag_send_error(p_scb, p_result->data.errcode);
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function bta_ag_result
+**
+** Description Handle API result.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_result(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ if (p_scb->conn_service == BTA_AG_HSP)
+ {
+ bta_ag_hsp_result(p_scb, &p_data->api_result);
+ }
+ else
+ {
+ bta_ag_hfp_result(p_scb, &p_data->api_result);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_setcodec
+**
+** Description Handle API SetCodec
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_setcodec(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+#if (BTM_WBS_INCLUDED == TRUE )
+ tBTA_AG_PEER_CODEC codec_type = p_data->api_setcodec.codec;
+
+ /* Check if the requested codec type is valid */
+ if((codec_type != BTA_AG_CODEC_NONE) &&
+ (codec_type != BTA_AG_CODEC_CVSD) &&
+ (codec_type != BTA_AG_CODEC_MSBC))
+ {
+ APPL_TRACE_ERROR1("bta_ag_setcodec error: unsupported codec type %d", codec_type);
+ return;
+ }
+
+ if((p_scb->peer_codecs & codec_type) || (codec_type == BTA_AG_CODEC_NONE) || (codec_type == BTA_AG_CODEC_CVSD))
+ {
+ p_scb->sco_codec = codec_type;
+ p_scb->codec_updated = TRUE;
+ APPL_TRACE_DEBUG1("bta_ag_setcodec: Updated codec type %d", codec_type);
+ }
+ else
+ {
+ APPL_TRACE_ERROR1("bta_ag_setcodec error: unsupported codec type %d", codec_type);
+ }
+#endif
+}
+
+
+#if (BTM_WBS_INCLUDED == TRUE )
+/*******************************************************************************
+**
+** Function bta_ag_send_bcs
+**
+** Description Send +BCS AT command to peer.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_send_bcs(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ UINT16 codec_uuid;
+
+ if (p_scb->codec_fallback)
+ {
+ codec_uuid = UUID_CODEC_CVSD;
+ }
+ else
+ {
+ switch(p_scb->sco_codec)
+ {
+ case BTA_AG_CODEC_NONE: codec_uuid = UUID_CODEC_CVSD; break;
+ case BTA_AG_CODEC_CVSD: codec_uuid = UUID_CODEC_CVSD; break;
+ case BTA_AG_CODEC_MSBC: codec_uuid = UUID_CODEC_MSBC; break;
+ default:
+ APPL_TRACE_ERROR1("bta_ag_send_bcs: unknown codec %d, use CVSD", p_scb->sco_codec);
+ codec_uuid = UUID_CODEC_CVSD;
+ break;
+ }
+ }
+
+ /* send +BCS */
+ bta_ag_send_result(p_scb, BTA_AG_RES_BCS, NULL, codec_uuid);
+
+}
+#endif
+
+/*******************************************************************************
+**
+** Function bta_ag_send_ring
+**
+** Description Send RING result code to peer.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_send_ring(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+#if defined(BTA_AG_MULTI_RESULT_INCLUDED) && (BTA_AG_MULTI_RESULT_INCLUDED == TRUE)
+ tBTA_AG_MULTI_RESULT_CB m_res_cb;
+
+ if (p_scb->conn_service == BTA_AG_HFP && p_scb->clip_enabled && p_scb->clip[0] != 0)
+ {
+ memset(&m_res_cb, NULL, sizeof(tBTA_AG_MULTI_RESULT_CB));
+
+ m_res_cb.num_result = 2;
+ AT_SET_RES_CB(m_res_cb.res_cb[0], BTA_AG_RES_RING, NULL, 0)
+ AT_SET_RES_CB(m_res_cb.res_cb[1], BTA_AG_RES_CLIP, p_scb->clip, 0)
+
+ bta_ag_send_multi_result(p_scb, &m_res_cb);
+ }
+ else
+ {
+ /* send RING ONLY */
+ bta_ag_send_result(p_scb, BTA_AG_RES_RING, NULL, 0);
+ }
+#else
+ /* send RING */
+ bta_ag_send_result(p_scb, BTA_AG_RES_RING, NULL, 0);
+
+ /* if HFP and clip enabled and clip data send CLIP */
+ if (p_scb->conn_service == BTA_AG_HFP && p_scb->clip_enabled && p_scb->clip[0] != 0)
+ {
+ bta_ag_send_result(p_scb, BTA_AG_RES_CLIP, p_scb->clip, 0);
+ }
+#endif
+
+ /* restart ring timer */
+ bta_sys_start_timer(&p_scb->act_timer, BTA_AG_RING_TOUT_EVT, BTA_AG_RING_TOUT);
+}
+
+
diff --git a/bta/ag/bta_ag_int.h b/bta/ag/bta_ag_int.h
new file mode 100644
index 0000000..d8f681c
--- /dev/null
+++ b/bta/ag/bta_ag_int.h
@@ -0,0 +1,407 @@
+/*****************************************************************************
+**
+** Name: bta_ag_int.h
+**
+** Description: This is the private interface file for the BTA audio
+** gateway.
+**
+** Copyright (c) 2003-2005, Widcomm Inc., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_AG_INT_H
+#define BTA_AG_INT_H
+
+#include "bta_sys.h"
+#include "bta_api.h"
+#include "bta_ag_api.h"
+#include "bta_ag_at.h"
+
+/* Send RING & CLIP in one AT cmd */
+#ifndef BTA_AG_MULTI_RESULT_INCLUDED
+#define BTA_AG_MULTI_RESULT_INCLUDED FALSE
+#endif
+
+/* Replace : in VGS and VGM for HSP */
+#ifndef BTA_HSP_RESULT_REPLACE_COLON
+#define BTA_HSP_RESULT_REPLACE_COLON TRUE
+#endif
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+#define HFP_VERSION_1_1 0x0101
+#define HFP_VERSION_1_5 0x0105
+#define HFP_VERSION_1_6 0x0106
+
+#define HSP_VERSION_1_0 0x0100
+#define HSP_VERSION_1_2 0x0102
+
+/* Number of SCBs (AG service instances that can be registered) */
+#ifndef BTA_AG_NUM_SCB
+#define BTA_AG_NUM_SCB 2
+#endif
+
+/* Timer to wait for retry in case of collision */
+#ifndef BTA_AG_COLLISION_TIMER
+#define BTA_AG_COLLISION_TIMER 2000
+#endif
+
+/* RFCOMM MTU SIZE */
+#define BTA_AG_MTU 256
+
+/* Internal profile indexes */
+#define BTA_AG_HSP 0 /* index for HSP */
+#define BTA_AG_HFP 1 /* index for HFP */
+#define BTA_AG_NUM_IDX 2 /* number of profile indexes */
+
+/* profile role for connection */
+#define BTA_AG_ACP 0 /* accepted connection */
+#define BTA_AG_INT 1 /* initiating connection */
+
+/* feature mask that matches spec */
+#define BTA_AG_BSRF_FEAT_SPEC (BTA_AG_FEAT_3WAY | BTA_AG_FEAT_ECNR | \
+ BTA_AG_FEAT_VREC | BTA_AG_FEAT_INBAND | \
+ BTA_AG_FEAT_VTAG | BTA_AG_FEAT_REJECT | \
+ BTA_AG_FEAT_ECS | BTA_AG_FEAT_ECC | \
+ BTA_AG_FEAT_EXTERR | BTA_AG_FEAT_CODEC | \
+ BTA_AG_FEAT_VOIP)
+
+#define BTA_AG_SDP_FEAT_SPEC (BTA_AG_FEAT_3WAY | BTA_AG_FEAT_ECNR | \
+ BTA_AG_FEAT_VREC | BTA_AG_FEAT_INBAND | \
+ BTA_AG_FEAT_VTAG)
+
+enum
+{
+ /* these events are handled by the state machine */
+ BTA_AG_API_REGISTER_EVT = BTA_SYS_EVT_START(BTA_ID_AG),
+ BTA_AG_API_DEREGISTER_EVT,
+ BTA_AG_API_OPEN_EVT,
+ BTA_AG_API_CLOSE_EVT,
+ BTA_AG_API_AUDIO_OPEN_EVT,
+ BTA_AG_API_AUDIO_CLOSE_EVT,
+ BTA_AG_API_RESULT_EVT,
+ BTA_AG_API_SETCODEC_EVT,
+ BTA_AG_RFC_OPEN_EVT,
+ BTA_AG_RFC_CLOSE_EVT,
+ BTA_AG_RFC_SRV_CLOSE_EVT,
+ BTA_AG_RFC_DATA_EVT,
+ BTA_AG_SCO_OPEN_EVT,
+ BTA_AG_SCO_CLOSE_EVT,
+ BTA_AG_DISC_ACP_RES_EVT,
+ BTA_AG_DISC_INT_RES_EVT,
+ BTA_AG_DISC_OK_EVT,
+ BTA_AG_DISC_FAIL_EVT,
+ BTA_AG_CI_RX_WRITE_EVT,
+ BTA_AG_RING_TOUT_EVT,
+ BTA_AG_SVC_TOUT_EVT,
+ BTA_AG_CI_SCO_DATA_EVT,
+ BTA_AG_CI_SLC_READY_EVT,
+ BTA_AG_MAX_EVT,
+
+ /* these events are handled outside of the state machine */
+ BTA_AG_API_ENABLE_EVT,
+ BTA_AG_API_DISABLE_EVT
+};
+
+/* Actions to perform after a SCO event */
+enum
+{
+ BTA_AG_POST_SCO_NONE, /* no action */
+ BTA_AG_POST_SCO_CLOSE_RFC, /* close RFCOMM channel after SCO closes */
+ BTA_AG_POST_SCO_RING, /* send RING result code after SCO opens */
+ BTA_AG_POST_SCO_CALL_CONN, /* send call indicators after SCO opens/closes */
+ BTA_AG_POST_SCO_CALL_ORIG, /* send call indicators after SCO closes */
+ BTA_AG_POST_SCO_CALL_END, /* send call indicators after SCO closes */
+ BTA_AG_POST_SCO_CALL_END_INCALL /* send call indicators for end call & incoming call after SCO closes */
+};
+
+/* sco states */
+enum
+{
+ BTA_AG_SCO_SHUTDOWN_ST, /* no sco listening, all sco connections closed */
+ BTA_AG_SCO_LISTEN_ST, /* sco listening */
+#if (BTM_WBS_INCLUDED == TRUE )
+ BTA_AG_SCO_CODEC_ST, /* sco codec negotiation */
+#endif
+ BTA_AG_SCO_OPENING_ST, /* sco connection opening */
+ BTA_AG_SCO_OPEN_CL_ST, /* opening sco connection being closed */
+ BTA_AG_SCO_OPEN_XFER_ST, /* opening sco connection being transferred */
+ BTA_AG_SCO_OPEN_ST, /* sco open */
+ BTA_AG_SCO_CLOSING_ST, /* sco closing */
+ BTA_AG_SCO_CLOSE_OP_ST, /* closing sco being opened */
+ BTA_AG_SCO_CLOSE_XFER_ST, /* closing sco being transferred */
+ BTA_AG_SCO_SHUTTING_ST /* sco shutting down */
+};
+
+/*****************************************************************************
+** Data types
+*****************************************************************************/
+
+/* data type for BTA_AG_API_ENABLE_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_AG_PARSE_MODE parse_mode;
+ tBTA_AG_CBACK *p_cback;
+} tBTA_AG_API_ENABLE;
+
+/* data type for BTA_AG_API_REGISTER_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ char p_name[2][BTA_SERVICE_NAME_LEN+1];
+ tBTA_SERVICE_MASK services;
+ tBTA_SEC sec_mask;
+ tBTA_AG_FEAT features;
+ UINT8 app_id;
+} tBTA_AG_API_REGISTER;
+
+/* data type for BTA_AG_API_OPEN_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+ tBTA_SERVICE_MASK services;
+ tBTA_SEC sec_mask;
+} tBTA_AG_API_OPEN;
+
+/* data type for BTA_AG_API_RESULT_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_AG_RES result;
+ tBTA_AG_RES_DATA data;
+} tBTA_AG_API_RESULT;
+
+/* data type for BTA_AG_API_SETCODEC_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_AG_PEER_CODEC codec;
+} tBTA_AG_API_SETCODEC;
+
+/* data type for BTA_AG_DISC_RESULT_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ UINT16 status;
+} tBTA_AG_DISC_RESULT;
+
+/* data type for RFCOMM events */
+typedef struct
+{
+ BT_HDR hdr;
+ UINT16 port_handle;
+} tBTA_AG_RFC;
+
+/* data type for BTA_AG_CI_RX_WRITE_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+// char p_data[BTA_AG_MTU+1];
+} tBTA_AG_CI_RX_WRITE;
+
+/* union of all event datatypes */
+typedef union
+{
+ BT_HDR hdr;
+ tBTA_AG_API_ENABLE api_enable;
+ tBTA_AG_API_REGISTER api_register;
+ tBTA_AG_API_OPEN api_open;
+ tBTA_AG_API_RESULT api_result;
+#if (BTM_WBS_INCLUDED == TRUE )
+ tBTA_AG_API_SETCODEC api_setcodec;
+#endif
+ tBTA_AG_DISC_RESULT disc_result;
+ tBTA_AG_RFC rfc;
+ tBTA_AG_CI_RX_WRITE ci_rx_write;
+} tBTA_AG_DATA;
+
+/* type for each profile */
+typedef struct
+{
+ UINT32 sdp_handle;
+ UINT8 scn;
+} tBTA_AG_PROFILE;
+
+/* type for each service control block */
+typedef struct
+{
+ char clip[BTA_AG_AT_MAX_LEN+1]; /* number string used for CLIP */
+ UINT16 serv_handle[BTA_AG_NUM_IDX]; /* RFCOMM server handles */
+ tBTA_AG_AT_CB at_cb; /* AT command interpreter */
+ TIMER_LIST_ENT act_timer; /* ring timer */
+ BD_ADDR peer_addr; /* peer bd address */
+ tSDP_DISCOVERY_DB *p_disc_db; /* pointer to discovery database */
+ tBTA_SERVICE_MASK reg_services; /* services specified in register API */
+ tBTA_SERVICE_MASK open_services; /* services specified in open API */
+ UINT16 conn_handle; /* RFCOMM handle of connected service */
+ tBTA_SEC serv_sec_mask; /* server security mask */
+ tBTA_SEC cli_sec_mask; /* client security mask */
+ tBTA_AG_FEAT features; /* features registered by application */
+ tBTA_AG_PEER_FEAT peer_features; /* peer device features */
+ UINT16 peer_version; /* profile version of peer device */
+ UINT16 hsp_version; /* HSP profile version */
+#if (BTM_WBS_INCLUDED == TRUE )
+ tBTA_AG_PEER_CODEC peer_codecs; /* codecs for eSCO supported by the peer */
+ tBTA_AG_PEER_CODEC sco_codec; /* codec to be used for eSCO connection */
+ tBTA_AG_PEER_CODEC inuse_codec; /* codec being used for the current SCO connection */
+ BOOLEAN codec_updated; /* set to TRUE whenever the app updates codec type */
+ BOOLEAN codec_fallback; /* If sco nego fails for mSBC, fallback to CVSD */
+ TIMER_LIST_ENT cn_timer; /* codec negotiation timer */
+#endif
+ UINT16 sco_idx; /* SCO handle */
+ BOOLEAN in_use; /* scb in use */
+ BOOLEAN dealloc; /* TRUE if service shutting down */
+ BOOLEAN clip_enabled; /* set to TRUE if HF enables CLIP reporting */
+ BOOLEAN ccwa_enabled; /* set to TRUE if HF enables CCWA reporting */
+ BOOLEAN cmer_enabled; /* set to TRUE if HF enables CMER reporting */
+ BOOLEAN cmee_enabled; /* set to TRUE if HF enables CME ERROR reporting */
+ BOOLEAN inband_enabled; /* set to TRUE if inband ring enabled */
+ BOOLEAN svc_conn; /* set to TRUE when service level connection up */
+ TIMER_LIST_ENT colli_timer; /* Collision timer */
+ BOOLEAN colli_tmr_on; /* TRUE if collision timer is active */
+ UINT8 state; /* state machine state */
+ UINT8 conn_service; /* connected service */
+ UINT8 peer_scn; /* peer scn */
+ UINT8 app_id; /* application id */
+ UINT8 role; /* initiator/acceptor role */
+ UINT8 post_sco; /* action to perform after sco event */
+ UINT8 call_ind; /* CIEV call indicator value */
+ UINT8 callsetup_ind; /* CIEV callsetup indicator value */
+ UINT8 callheld_ind; /* CIEV call held indicator value */
+ BOOLEAN retry_with_sco_only; /* indicator to try with SCO only when eSCO fails */
+ UINT32 bia_masked_out; /* indicators HF does not want us to send */
+} tBTA_AG_SCB;
+
+/* type for sco data */
+typedef struct
+{
+ tBTM_ESCO_CONN_REQ_EVT_DATA conn_data; /* SCO data for pending conn request */
+ tBTA_AG_SCB *p_curr_scb; /* SCB associated with SCO connection */
+ tBTA_AG_SCB *p_xfer_scb; /* SCB associated with SCO transfer */
+ UINT16 cur_idx; /* SCO handle */
+ UINT8 state; /* SCO state variable */
+ BOOLEAN param_updated; /* if params were updated to non-default */
+ tBTM_ESCO_PARAMS params; /* ESCO parameters */
+} tBTA_AG_SCO_CB;
+
+
+/* type for AG control block */
+typedef struct
+{
+ tBTA_AG_SCB scb[BTA_AG_NUM_SCB]; /* service control blocks */
+ tBTA_AG_PROFILE profile[BTA_AG_NUM_IDX]; /* profile-specific data */
+ tBTA_AG_SCO_CB sco; /* SCO data */
+ tBTA_AG_CBACK *p_cback; /* application callback */
+ tBTA_AG_PARSE_MODE parse_mode; /* parse/pass-through mode */
+} tBTA_AG_CB;
+
+/*****************************************************************************
+** Global data
+*****************************************************************************/
+
+/* constant lookup tables */
+extern const UINT16 bta_ag_uuid[BTA_AG_NUM_IDX];
+extern const UINT8 bta_ag_sec_id[BTA_AG_NUM_IDX];
+extern const tBTA_AG_AT_CMD *bta_ag_at_tbl[BTA_AG_NUM_IDX];
+
+/* control block declaration */
+#if BTA_DYNAMIC_MEMORY == FALSE
+extern tBTA_AG_CB bta_ag_cb;
+#else
+extern tBTA_AG_CB *bta_ag_cb_ptr;
+#define bta_ag_cb (*bta_ag_cb_ptr)
+#endif
+
+/* config struct */
+extern tBTA_AG_CFG *p_bta_ag_cfg;
+
+/*****************************************************************************
+** Function prototypes
+*****************************************************************************/
+
+/* main functions */
+extern void bta_ag_scb_dealloc(tBTA_AG_SCB *p_scb);
+extern UINT16 bta_ag_scb_to_idx(tBTA_AG_SCB *p_scb);
+extern tBTA_AG_SCB *bta_ag_scb_by_idx(UINT16 idx);
+extern UINT8 bta_ag_service_to_idx(tBTA_SERVICE_MASK services);
+extern UINT16 bta_ag_idx_by_bdaddr(BD_ADDR peer_addr);
+extern BOOLEAN bta_ag_other_scb_open(tBTA_AG_SCB *p_curr_scb);
+extern tBTA_AG_SCB *bta_ag_get_other_idle_scb (tBTA_AG_SCB *p_curr_scb);
+extern void bta_ag_sm_execute(tBTA_AG_SCB *p_scb, UINT16 event, tBTA_AG_DATA *p_data);
+extern BOOLEAN bta_ag_hdl_event(BT_HDR *p_msg);
+extern void bta_ag_collision_cback (tBTA_SYS_CONN_STATUS status, UINT8 id,
+ UINT8 app_id, BD_ADDR peer_addr);
+extern void bta_ag_resume_open (tBTA_AG_SCB *p_scb);
+
+/* SDP functions */
+extern BOOLEAN bta_ag_add_record(UINT16 service_uuid, char *p_service_name, UINT8 scn,
+ tBTA_AG_FEAT features, UINT32 sdp_handle);
+extern void bta_ag_create_records(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_del_records(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern BOOLEAN bta_ag_sdp_find_attr(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK service);
+extern void bta_ag_do_disc(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK service);
+extern void bta_ag_free_db(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+
+/* RFCOMM functions */
+extern void bta_ag_start_servers(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK services);
+extern void bta_ag_close_servers(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK services);
+extern BOOLEAN bta_ag_is_server_closed (tBTA_AG_SCB *p_scb);
+extern void bta_ag_rfc_do_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_rfc_do_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+
+/* SCO functions */
+extern BOOLEAN bta_ag_sco_is_open(tBTA_AG_SCB *p_scb);
+extern BOOLEAN bta_ag_sco_is_opening(tBTA_AG_SCB *p_scb);
+extern void bta_ag_sco_conn_rsp(tBTA_AG_SCB *p_scb, tBTM_ESCO_CONN_REQ_EVT_DATA *p_data);
+
+/* AT command functions */
+extern void bta_ag_at_hsp_cback(tBTA_AG_SCB *p_scb, UINT16 cmd, UINT8 arg_type,
+ char *p_arg, INT16 int_arg);
+extern void bta_ag_at_hfp_cback(tBTA_AG_SCB *p_scb, UINT16 cmd, UINT8 arg_type,
+ char *p_arg, INT16 int_arg);
+extern void bta_ag_at_err_cback(tBTA_AG_SCB *p_scb, BOOLEAN unknown, char *p_arg);
+extern BOOLEAN bta_ag_inband_enabled(tBTA_AG_SCB *p_scb);
+extern void bta_ag_send_call_inds(tBTA_AG_SCB *p_scb, tBTA_AG_RES result);
+
+/* Action functions */
+extern void bta_ag_register(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_deregister(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_start_dereg(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_start_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_start_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_disc_int_res(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_disc_acp_res(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_disc_fail(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_open_fail(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_rfc_fail(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_rfc_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_rfc_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_rfc_acp_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_rfc_data(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_sco_listen(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_sco_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_sco_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+#if (BTM_WBS_INCLUDED == TRUE )
+extern void bta_ag_sco_codec_nego(tBTA_AG_SCB *p_scb, BOOLEAN result);
+extern void bta_ag_codec_negotiate (tBTA_AG_SCB *p_scb);
+#endif
+extern void bta_ag_sco_shutdown(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_sco_conn_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_sco_conn_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_post_sco_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_post_sco_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_svc_conn_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_result(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_setcodec(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+#if (BTM_WBS_INCLUDED == TRUE )
+extern void bta_ag_send_bcs(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+#endif
+extern void bta_ag_send_ring(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_ci_sco_data(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_set_esco_param(BOOLEAN set_reset, tBTM_ESCO_PARAMS *param);
+extern void bta_ag_ci_rx_data(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_rcvd_slc_ready(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+#endif /* BTA_AG_INT_H */
diff --git a/bta/ag/bta_ag_main.c b/bta/ag/bta_ag_main.c
new file mode 100644
index 0000000..df576cc
--- /dev/null
+++ b/bta/ag/bta_ag_main.c
@@ -0,0 +1,1000 @@
+/*****************************************************************************
+**
+** Name: bta_ag_main.c
+**
+** Description: This is the main implementation file for the BTA
+** audio gateway.
+**
+** Copyright (c) 2003-2005, Widcomm Inc., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include <string.h>
+#include "bta_api.h"
+#include "bta_sys.h"
+#include "bta_ag_co.h"
+#include "bta_ag_int.h"
+#include "bd.h"
+
+/*****************************************************************************
+** Constants and types
+*****************************************************************************/
+#ifndef BTA_AG_DEBUG
+#define BTA_AG_DEBUG FALSE
+#endif
+
+#if BTA_AG_DEBUG == TRUE
+static char *bta_ag_evt_str(UINT16 event, tBTA_AG_RES result);
+static char *bta_ag_state_str(UINT8 state);
+#endif
+
+/* state machine states */
+enum
+{
+ BTA_AG_INIT_ST,
+ BTA_AG_OPENING_ST,
+ BTA_AG_OPEN_ST,
+ BTA_AG_CLOSING_ST
+};
+
+/* state machine action enumeration list */
+enum
+{
+ BTA_AG_REGISTER,
+ BTA_AG_DEREGISTER,
+ BTA_AG_START_OPEN,
+ BTA_AG_RFC_DO_OPEN,
+ BTA_AG_RFC_DO_CLOSE,
+ BTA_AG_START_DEREG,
+ BTA_AG_START_CLOSE,
+ BTA_AG_RFC_OPEN,
+ BTA_AG_OPEN_FAIL,
+ BTA_AG_RFC_ACP_OPEN,
+ BTA_AG_RFC_CLOSE,
+ BTA_AG_RFC_FAIL,
+ BTA_AG_RFC_DATA,
+ BTA_AG_DISC_INT_RES,
+ BTA_AG_DISC_FAIL,
+ BTA_AG_DISC_ACP_RES,
+ BTA_AG_FREE_DB,
+ BTA_AG_SCO_CONN_OPEN,
+ BTA_AG_SCO_CONN_CLOSE,
+ BTA_AG_SCO_LISTEN,
+ BTA_AG_SCO_OPEN,
+ BTA_AG_SCO_CLOSE,
+ BTA_AG_SCO_SHUTDOWN,
+ BTA_AG_POST_SCO_OPEN,
+ BTA_AG_POST_SCO_CLOSE,
+ BTA_AG_SVC_CONN_OPEN,
+ BTA_AG_RESULT,
+ BTA_AG_SETCODEC,
+ BTA_AG_SEND_RING,
+ BTA_AG_CI_SCO_DATA,
+ BTA_AG_CI_RX_DATA,
+ BTA_AG_RCVD_SLC_READY,
+ BTA_AG_NUM_ACTIONS
+};
+
+#define BTA_AG_IGNORE BTA_AG_NUM_ACTIONS
+
+/* type for action functions */
+typedef void (*tBTA_AG_ACTION)(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+
+/* action functions */
+const tBTA_AG_ACTION bta_ag_action[] =
+{
+ bta_ag_register,
+ bta_ag_deregister,
+ bta_ag_start_open,
+ bta_ag_rfc_do_open,
+ bta_ag_rfc_do_close,
+ bta_ag_start_dereg,
+ bta_ag_start_close,
+ bta_ag_rfc_open,
+ bta_ag_open_fail,
+ bta_ag_rfc_acp_open,
+ bta_ag_rfc_close,
+ bta_ag_rfc_fail,
+ bta_ag_rfc_data,
+ bta_ag_disc_int_res,
+ bta_ag_disc_fail,
+ bta_ag_disc_acp_res,
+ bta_ag_free_db,
+ bta_ag_sco_conn_open,
+ bta_ag_sco_conn_close,
+ bta_ag_sco_listen,
+ bta_ag_sco_open,
+ bta_ag_sco_close,
+ bta_ag_sco_shutdown,
+ bta_ag_post_sco_open,
+ bta_ag_post_sco_close,
+ bta_ag_svc_conn_open,
+ bta_ag_result,
+ bta_ag_setcodec,
+ bta_ag_send_ring,
+ bta_ag_ci_sco_data,
+ bta_ag_ci_rx_data,
+ bta_ag_rcvd_slc_ready
+};
+
+/* state table information */
+#define BTA_AG_ACTIONS 2 /* number of actions */
+#define BTA_AG_NEXT_STATE 2 /* position of next state */
+#define BTA_AG_NUM_COLS 3 /* number of columns in state tables */
+
+/* state table for init state */
+const UINT8 bta_ag_st_init[][BTA_AG_NUM_COLS] =
+{
+/* Event Action 1 Action 2 Next state */
+/* API_REGISTER_EVT */ {BTA_AG_REGISTER, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+/* API_DEREGISTER_EVT */ {BTA_AG_DEREGISTER, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+/* API_OPEN_EVT */ {BTA_AG_START_OPEN, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+/* API_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+/* API_AUDIO_OPEN_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+/* API_AUDIO_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+/* API_RESULT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+/* API_SETCODEC_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+/* RFC_OPEN_EVT */ {BTA_AG_RFC_ACP_OPEN, BTA_AG_SCO_LISTEN, BTA_AG_OPEN_ST},
+/* RFC_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+/* RFC_SRV_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+/* RFC_DATA_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+/* SCO_OPEN_EVT */ {BTA_AG_SCO_CONN_OPEN, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+/* SCO_CLOSE_EVT */ {BTA_AG_SCO_CONN_CLOSE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+/* DISC_ACP_RES_EVT */ {BTA_AG_FREE_DB, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+/* DISC_INT_RES_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+/* DISC_OK_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+/* DISC_FAIL_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+/* CI_RX_WRITE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+/* RING_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+/* SVC_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+/* CI_SCO_DATA_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+/* CI_SLC_READY_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST}
+};
+
+/* state table for opening state */
+const UINT8 bta_ag_st_opening[][BTA_AG_NUM_COLS] =
+{
+/* Event Action 1 Action 2 Next state */
+/* API_REGISTER_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+/* API_DEREGISTER_EVT */ {BTA_AG_RFC_DO_CLOSE, BTA_AG_START_DEREG, BTA_AG_CLOSING_ST},
+/* API_OPEN_EVT */ {BTA_AG_OPEN_FAIL, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+/* API_CLOSE_EVT */ {BTA_AG_RFC_DO_CLOSE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+/* API_AUDIO_OPEN_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+/* API_AUDIO_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+/* API_RESULT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+/* API_SETCODEC_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+/* RFC_OPEN_EVT */ {BTA_AG_RFC_OPEN, BTA_AG_SCO_LISTEN, BTA_AG_OPEN_ST},
+/* RFC_CLOSE_EVT */ {BTA_AG_RFC_FAIL, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+/* RFC_SRV_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+/* RFC_DATA_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+/* SCO_OPEN_EVT */ {BTA_AG_SCO_CONN_OPEN, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+/* SCO_CLOSE_EVT */ {BTA_AG_SCO_CONN_CLOSE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+/* DISC_ACP_RES_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+/* DISC_INT_RES_EVT */ {BTA_AG_DISC_INT_RES, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+/* DISC_OK_EVT */ {BTA_AG_RFC_DO_OPEN, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+/* DISC_FAIL_EVT */ {BTA_AG_DISC_FAIL, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+/* CI_RX_WRITE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+/* RING_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+/* SVC_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+/* CI_SCO_DATA_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+/* CI_SLC_READY_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST}
+};
+
+/* state table for open state */
+const UINT8 bta_ag_st_open[][BTA_AG_NUM_COLS] =
+{
+/* Event Action 1 Action 2 Next state */
+/* API_REGISTER_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+/* API_DEREGISTER_EVT */ {BTA_AG_START_CLOSE, BTA_AG_START_DEREG, BTA_AG_CLOSING_ST},
+/* API_OPEN_EVT */ {BTA_AG_OPEN_FAIL, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+/* API_CLOSE_EVT */ {BTA_AG_START_CLOSE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+/* API_AUDIO_OPEN_EVT */ {BTA_AG_SCO_OPEN, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+/* API_AUDIO_CLOSE_EVT */ {BTA_AG_SCO_CLOSE, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+/* API_RESULT_EVT */ {BTA_AG_RESULT, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+/* API_SETCODEC_EVT */ {BTA_AG_SETCODEC, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+/* RFC_OPEN_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+/* RFC_CLOSE_EVT */ {BTA_AG_RFC_CLOSE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+/* RFC_SRV_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+/* RFC_DATA_EVT */ {BTA_AG_RFC_DATA, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+/* SCO_OPEN_EVT */ {BTA_AG_SCO_CONN_OPEN, BTA_AG_POST_SCO_OPEN, BTA_AG_OPEN_ST},
+/* SCO_CLOSE_EVT */ {BTA_AG_SCO_CONN_CLOSE, BTA_AG_POST_SCO_CLOSE, BTA_AG_OPEN_ST},
+/* DISC_ACP_RES_EVT */ {BTA_AG_DISC_ACP_RES, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+/* DISC_INT_RES_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+/* DISC_OK_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+/* DISC_FAIL_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+/* CI_RX_WRITE_EVT */ {BTA_AG_CI_RX_DATA, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+/* RING_TOUT_EVT */ {BTA_AG_SEND_RING, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+/* SVC_TOUT_EVT */ {BTA_AG_SVC_CONN_OPEN, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+/* CI_SCO_DATA_EVT */ {BTA_AG_CI_SCO_DATA, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+/* CI_SLC_READY_EVT */ {BTA_AG_RCVD_SLC_READY, BTA_AG_IGNORE, BTA_AG_OPEN_ST}
+};
+
+/* state table for closing state */
+const UINT8 bta_ag_st_closing[][BTA_AG_NUM_COLS] =
+{
+/* Event Action 1 Action 2 Next state */
+/* API_REGISTER_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+/* API_DEREGISTER_EVT */ {BTA_AG_START_DEREG, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+/* API_OPEN_EVT */ {BTA_AG_OPEN_FAIL, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+/* API_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+/* API_AUDIO_OPEN_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+/* API_AUDIO_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+/* API_RESULT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+/* API_SETCODEC_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+/* RFC_OPEN_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+/* RFC_CLOSE_EVT */ {BTA_AG_RFC_CLOSE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+/* RFC_SRV_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+/* RFC_DATA_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+/* SCO_OPEN_EVT */ {BTA_AG_SCO_CONN_OPEN, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+/* SCO_CLOSE_EVT */ {BTA_AG_SCO_CONN_CLOSE, BTA_AG_POST_SCO_CLOSE, BTA_AG_CLOSING_ST},
+/* DISC_ACP_RES_EVT */ {BTA_AG_FREE_DB, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+/* DISC_INT_RES_EVT */ {BTA_AG_FREE_DB, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+/* DISC_OK_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+/* DISC_FAIL_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+/* CI_RX_WRITE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+/* RING_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+/* SVC_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+/* CI_SCO_DATA_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+/* CI_SLC_READY_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST}
+};
+
+/* type for state table */
+typedef const UINT8 (*tBTA_AG_ST_TBL)[BTA_AG_NUM_COLS];
+
+/* state table */
+const tBTA_AG_ST_TBL bta_ag_st_tbl[] =
+{
+ bta_ag_st_init,
+ bta_ag_st_opening,
+ bta_ag_st_open,
+ bta_ag_st_closing
+};
+
+/*****************************************************************************
+** Global data
+*****************************************************************************/
+
+/* AG control block */
+#if BTA_DYNAMIC_MEMORY == FALSE
+tBTA_AG_CB bta_ag_cb;
+#endif
+
+/*******************************************************************************
+**
+** Function bta_ag_timer_cback
+**
+** Description AG timer callback.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ag_timer_cback(void *p)
+{
+ BT_HDR *p_buf;
+ TIMER_LIST_ENT *p_tle = (TIMER_LIST_ENT *) p;
+
+ if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->event = p_tle->event;
+ p_buf->layer_specific = bta_ag_scb_to_idx((tBTA_AG_SCB *) p_tle->param);
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_scb_alloc
+**
+** Description Allocate an AG service control block.
+**
+**
+** Returns pointer to the scb, or NULL if none could be allocated.
+**
+*******************************************************************************/
+static tBTA_AG_SCB *bta_ag_scb_alloc(void)
+{
+ tBTA_AG_SCB *p_scb = &bta_ag_cb.scb[0];
+ int i;
+
+ for (i = 0; i < BTA_AG_NUM_SCB; i++, p_scb++)
+ {
+ if (!p_scb->in_use)
+ {
+ /* initialize variables */
+ p_scb->in_use = TRUE;
+ p_scb->sco_idx = BTM_INVALID_SCO_INDEX;
+
+ /* set up timers */
+ p_scb->act_timer.param = (UINT32) p_scb;
+ p_scb->act_timer.p_cback = bta_ag_timer_cback;
+
+ APPL_TRACE_DEBUG1("bta_ag_scb_alloc %d", bta_ag_scb_to_idx(p_scb));
+ break;
+ }
+ }
+
+ if (i == BTA_AG_NUM_SCB)
+ {
+ /* out of scbs */
+ p_scb = NULL;
+ APPL_TRACE_WARNING0("Out of ag scbs");
+ }
+ return p_scb;
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_scb_dealloc
+**
+** Description Deallocate a service control block.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_scb_dealloc(tBTA_AG_SCB *p_scb)
+{
+ UINT8 idx;
+ BOOLEAN allocated = FALSE;
+
+ APPL_TRACE_DEBUG1("bta_ag_scb_dealloc %d", bta_ag_scb_to_idx(p_scb));
+
+ /* stop timers */
+ bta_sys_stop_timer(&p_scb->act_timer);
+#if (BTM_WBS_INCLUDED == TRUE)
+ bta_sys_stop_timer(&p_scb->cn_timer);
+#endif
+
+ /* initialize control block */
+ memset(p_scb, 0, sizeof(tBTA_AG_SCB));
+ p_scb->sco_idx = BTM_INVALID_SCO_INDEX;
+
+ /* If all scbs are deallocated, callback with disable event */
+ if (!bta_sys_is_register (BTA_ID_AG))
+ {
+ for (idx = 0; idx < BTA_AG_NUM_SCB; idx++)
+ {
+ if (bta_ag_cb.scb[idx].in_use)
+ {
+ allocated = TRUE;
+ break;
+ }
+ }
+
+ if (!allocated)
+ {
+ (*bta_ag_cb.p_cback)(BTA_AG_DISABLE_EVT, NULL);
+ }
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_scb_to_idx
+**
+** Description Given a pointer to an scb, return its index.
+**
+**
+** Returns Index of scb.
+**
+*******************************************************************************/
+UINT16 bta_ag_scb_to_idx(tBTA_AG_SCB *p_scb)
+{
+ /* use array arithmetic to determine index */
+ return ((UINT16) (p_scb - bta_ag_cb.scb)) + 1;
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_scb_by_idx
+**
+** Description Given an scb index return pointer to scb.
+**
+**
+** Returns Pointer to scb or NULL if not allocated.
+**
+*******************************************************************************/
+tBTA_AG_SCB *bta_ag_scb_by_idx(UINT16 idx)
+{
+ tBTA_AG_SCB *p_scb;
+
+ /* verify index */
+ if (idx > 0 && idx <= BTA_AG_NUM_SCB)
+ {
+ p_scb = &bta_ag_cb.scb[idx - 1];
+ if (!p_scb->in_use)
+ {
+ p_scb = NULL;
+ APPL_TRACE_WARNING1("ag scb idx %d not allocated", idx);
+ }
+ }
+ else
+ {
+ p_scb = NULL;
+ APPL_TRACE_DEBUG1("ag scb idx %d out of range", idx);
+ }
+ return p_scb;
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_service_to_idx
+**
+** Description Given a BTA service mask convert to profile index.
+**
+**
+** Returns Profile ndex of scb.
+**
+*******************************************************************************/
+UINT8 bta_ag_service_to_idx(tBTA_SERVICE_MASK services)
+{
+ if (services & BTA_HFP_SERVICE_MASK)
+ {
+ return BTA_AG_HFP;
+ }
+ else
+ {
+ return BTA_AG_HSP;
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_idx_by_bdaddr
+**
+** Description Find SCB associated with peer BD address.
+**
+**
+** Returns Index of SCB or zero if none found.
+**
+*******************************************************************************/
+UINT16 bta_ag_idx_by_bdaddr(BD_ADDR peer_addr)
+{
+ tBTA_AG_SCB *p_scb = &bta_ag_cb.scb[0];
+ UINT16 i;
+
+ if (peer_addr != NULL)
+ {
+ for (i = 0; i < BTA_AG_NUM_SCB; i++, p_scb++)
+ {
+ if (p_scb->in_use && !bdcmp(peer_addr, p_scb->peer_addr))
+ {
+ return (i + 1);
+ }
+ }
+ }
+
+ /* no scb found */
+ APPL_TRACE_WARNING0("No ag scb for peer addr");
+ return 0;
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_other_scb_open
+**
+** Description Check whether any other scb is in open state.
+**
+**
+** Returns TRUE if another scb is in open state, FALSE otherwise.
+**
+*******************************************************************************/
+BOOLEAN bta_ag_other_scb_open(tBTA_AG_SCB *p_curr_scb)
+{
+ tBTA_AG_SCB *p_scb = &bta_ag_cb.scb[0];
+ int i;
+
+ for (i = 0; i < BTA_AG_NUM_SCB; i++, p_scb++)
+ {
+ if (p_scb->in_use && p_scb != p_curr_scb && p_scb->state == BTA_AG_OPEN_ST)
+ {
+ return TRUE;
+ }
+ }
+
+ /* no other scb found */
+ APPL_TRACE_DEBUG0("No other ag scb open");
+ return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_get_other_idle_scb
+**
+** Description Return other scb if it is in INIT st.
+**
+**
+** Returns Pointer to other scb if INIT st, NULL otherwise.
+**
+*******************************************************************************/
+tBTA_AG_SCB *bta_ag_get_other_idle_scb (tBTA_AG_SCB *p_curr_scb)
+{
+ tBTA_AG_SCB *p_scb = &bta_ag_cb.scb[0];
+ UINT8 xx;
+
+ for (xx = 0; xx < BTA_AG_NUM_SCB; xx++, p_scb++)
+ {
+ if (p_scb->in_use && (p_scb != p_curr_scb) && (p_scb->state == BTA_AG_INIT_ST))
+ {
+ return p_scb;
+ }
+ }
+
+ /* no other scb found */
+ APPL_TRACE_DEBUG0("bta_ag_get_other_idle_scb: No idle AG scb");
+ return NULL;
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_colli_timer_cback
+**
+** Description AG connection collision timer callback
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ag_colli_timer_cback (TIMER_LIST_ENT *p_tle)
+{
+ tBTA_AG_SCB *p_scb;
+
+ APPL_TRACE_DEBUG0 ("bta_ag_colli_timer_cback");
+
+ if (p_tle)
+ {
+ p_scb = (tBTA_AG_SCB *)p_tle->param;
+
+ if (p_scb)
+ {
+ p_scb->colli_tmr_on = FALSE;
+
+ /* If the peer haven't opened AG connection */
+ /* we will restart opening process. */
+ bta_ag_resume_open (p_scb);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_collision_cback
+**
+** Description Get notified about collision.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_collision_cback (tBTA_SYS_CONN_STATUS status, UINT8 id,
+ UINT8 app_id, BD_ADDR peer_addr)
+{
+ UINT16 handle;
+ tBTA_AG_SCB *p_scb;
+
+ /* Check if we have opening scb for the peer device. */
+ handle = bta_ag_idx_by_bdaddr (peer_addr);
+ p_scb = bta_ag_scb_by_idx (handle);
+
+ if (p_scb && (p_scb->state == BTA_AG_OPENING_ST))
+ {
+ if (id == BTA_ID_SYS) /* ACL collision */
+ {
+ APPL_TRACE_WARNING0 ("AG found collision (ACL) ...");
+ }
+ else if (id == BTA_ID_AG) /* RFCOMM collision */
+ {
+ APPL_TRACE_WARNING0 ("AG found collision (RFCOMM) ...");
+ }
+ else
+ {
+ APPL_TRACE_WARNING0 ("AG found collision (\?\?\?) ...");
+ }
+
+ p_scb->state = BTA_AG_INIT_ST;
+
+ /* Cancel SDP if it had been started. */
+ if(p_scb->p_disc_db)
+ {
+ (void)SDP_CancelServiceSearch (p_scb->p_disc_db);
+ bta_ag_free_db(p_scb, NULL);
+ }
+
+ /* reopen registered servers */
+ /* Collision may be detected before or after we close servers. */
+ if (bta_ag_is_server_closed (p_scb))
+ bta_ag_start_servers(p_scb, p_scb->reg_services);
+
+ /* Start timer to han */
+ p_scb->colli_timer.p_cback = (TIMER_CBACK*)&bta_ag_colli_timer_cback;
+ p_scb->colli_timer.param = (INT32)p_scb;
+ bta_sys_start_timer(&p_scb->colli_timer, 0, BTA_AG_COLLISION_TIMER);
+ p_scb->colli_tmr_on = TRUE;
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_resume_open
+**
+** Description Resume opening process.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_resume_open (tBTA_AG_SCB *p_scb)
+{
+ if (p_scb)
+ {
+ APPL_TRACE_DEBUG1 ("bta_ag_resume_open, Handle(%d)", bta_ag_scb_to_idx(p_scb));
+
+ /* resume opening process. */
+ if (p_scb->state == BTA_AG_INIT_ST)
+ {
+ p_scb->state = BTA_AG_OPENING_ST;
+ bta_ag_start_open (p_scb, NULL);
+ }
+ }
+ else
+ {
+ APPL_TRACE_ERROR0 ("bta_ag_resume_open, Null p_scb");
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_api_enable
+**
+** Description Handle an API enable event.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ag_api_enable(tBTA_AG_DATA *p_data)
+{
+ /* initialize control block */
+ memset(&bta_ag_cb, 0, sizeof(tBTA_AG_CB));
+
+ /* store callback function */
+ bta_ag_cb.p_cback = p_data->api_enable.p_cback;
+ bta_ag_cb.parse_mode = p_data->api_enable.parse_mode;
+
+ /* call init call-out */
+ bta_ag_co_init();
+
+ bta_sys_collision_register (BTA_ID_AG, bta_ag_collision_cback);
+
+ /* call callback with enable event */
+ (*bta_ag_cb.p_cback)(BTA_AG_ENABLE_EVT, NULL);
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_api_disable
+**
+** Description Handle an API disable event.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ag_api_disable(tBTA_AG_DATA *p_data)
+{
+ /* deregister all scbs in use */
+ tBTA_AG_SCB *p_scb = &bta_ag_cb.scb[0];
+ BOOLEAN do_dereg = FALSE;
+ int i;
+
+ if (!bta_sys_is_register (BTA_ID_AG))
+ {
+ APPL_TRACE_ERROR0("BTA AG is already disabled, ignoring ...");
+ return;
+ }
+
+ /* De-register with BTA system manager */
+ GKI_sched_lock();
+ bta_sys_deregister(BTA_ID_AG);
+ GKI_sched_unlock();
+
+ for (i = 0; i < BTA_AG_NUM_SCB; i++, p_scb++)
+ {
+ if (p_scb->in_use)
+ {
+ bta_ag_sm_execute(p_scb, BTA_AG_API_DEREGISTER_EVT, p_data);
+ do_dereg = TRUE;
+ }
+ }
+
+ if (!do_dereg)
+ {
+ /* Done, send callback evt to app */
+ (*bta_ag_cb.p_cback)(BTA_AG_DISABLE_EVT, NULL);
+ }
+
+ bta_sys_collision_register (BTA_ID_AG, NULL);
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_api_register
+**
+** Description Handle an API event registers a new service.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ag_api_register(tBTA_AG_DATA *p_data)
+{
+ tBTA_AG_SCB *p_scb;
+ tBTA_AG_REGISTER reg;
+
+ /* allocate an scb */
+ if ((p_scb = bta_ag_scb_alloc()) != NULL)
+ {
+ bta_ag_sm_execute(p_scb, p_data->hdr.event, p_data);
+ }
+ else
+ {
+ reg.status = BTA_AG_FAIL_RESOURCES;
+ (*bta_ag_cb.p_cback)(BTA_AG_REGISTER_EVT, (tBTA_AG *) &reg);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_api_result
+**
+** Description Handle an API result event.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ag_api_result(tBTA_AG_DATA *p_data)
+{
+ tBTA_AG_SCB *p_scb;
+ int i;
+
+ if (p_data->hdr.layer_specific != BTA_AG_HANDLE_ALL)
+ {
+ if ((p_scb = bta_ag_scb_by_idx(p_data->hdr.layer_specific)) != NULL)
+ {
+ bta_ag_sm_execute(p_scb, BTA_AG_API_RESULT_EVT, p_data);
+ }
+ }
+ else
+ {
+ for (i = 0, p_scb = &bta_ag_cb.scb[0]; i < BTA_AG_NUM_SCB; i++, p_scb++)
+ {
+ if (p_scb->in_use)
+ {
+ bta_ag_sm_execute(p_scb, BTA_AG_API_RESULT_EVT, p_data);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_sm_execute
+**
+** Description State machine event handling function for AG
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_sm_execute(tBTA_AG_SCB *p_scb, UINT16 event, tBTA_AG_DATA *p_data)
+{
+ tBTA_AG_ST_TBL state_table;
+ UINT8 action;
+ int i;
+
+#if BTA_AG_DEBUG == TRUE
+ UINT16 in_event = event;
+ UINT8 in_state = p_scb->state;
+
+ /* Ignore displaying of AT results when not connected (Ignored in state machine) */
+ if (in_event != BTA_AG_API_RESULT_EVT || p_scb->state == BTA_AG_OPEN_ST)
+ {
+ APPL_TRACE_EVENT5("AG evt (hdl 0x%04x): State %d (%s), Event 0x%04x (%s)",
+ bta_ag_scb_to_idx(p_scb),
+ p_scb->state, bta_ag_state_str(p_scb->state),
+ event, bta_ag_evt_str(event, p_data->api_result.result));
+ }
+#else
+ APPL_TRACE_EVENT3("AG evt (hdl 0x%04x): State %d, Event 0x%04x",
+ bta_ag_scb_to_idx(p_scb), p_scb->state, event);
+#endif
+
+ event &= 0x00FF;
+ if (event >= (BTA_AG_MAX_EVT & 0x00FF))
+ {
+ APPL_TRACE_ERROR0("AG evt out of range, ignoring...");
+ return;
+ }
+
+ /* look up the state table for the current state */
+ state_table = bta_ag_st_tbl[p_scb->state];
+
+ /* set next state */
+ p_scb->state = state_table[event][BTA_AG_NEXT_STATE];
+
+ /* execute action functions */
+ for (i = 0; i < BTA_AG_ACTIONS; i++)
+ {
+ if ((action = state_table[event][i]) != BTA_AG_IGNORE)
+ {
+ (*bta_ag_action[action])(p_scb, p_data);
+ }
+ else
+ {
+ break;
+ }
+ }
+#if BTA_AG_DEBUG == TRUE
+ if (p_scb->state != in_state)
+ {
+ APPL_TRACE_EVENT3("BTA AG State Change: [%s] -> [%s] after Event [%s]",
+ bta_ag_state_str(in_state),
+ bta_ag_state_str(p_scb->state),
+ bta_ag_evt_str(in_event, p_data->api_result.result));
+ }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_hdl_event
+**
+** Description Data gateway main event handling function.
+**
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+BOOLEAN bta_ag_hdl_event(BT_HDR *p_msg)
+{
+ tBTA_AG_SCB *p_scb;
+
+ switch (p_msg->event)
+ {
+ /* handle enable event */
+ case BTA_AG_API_ENABLE_EVT:
+ bta_ag_api_enable((tBTA_AG_DATA *) p_msg);
+ break;
+
+ /* handle disable event */
+ case BTA_AG_API_DISABLE_EVT:
+ bta_ag_api_disable((tBTA_AG_DATA *) p_msg);
+ break;
+
+ /* handle register event */
+ case BTA_AG_API_REGISTER_EVT:
+ bta_ag_api_register((tBTA_AG_DATA *) p_msg);
+ break;
+
+ /* handle result event */
+ case BTA_AG_API_RESULT_EVT:
+ bta_ag_api_result((tBTA_AG_DATA *) p_msg);
+ break;
+
+ /* all others reference scb by handle */
+ default:
+ if ((p_scb = bta_ag_scb_by_idx(p_msg->layer_specific)) != NULL)
+ {
+ bta_ag_sm_execute(p_scb, p_msg->event, (tBTA_AG_DATA *) p_msg);
+ }
+ break;
+ }
+ return TRUE;
+}
+
+#if BTA_AG_DEBUG == TRUE
+static char *bta_ag_evt_str(UINT16 event, tBTA_AG_RES result)
+{
+ switch (event)
+ {
+ case BTA_AG_API_REGISTER_EVT:
+ return "Register Request";
+ case BTA_AG_API_DEREGISTER_EVT:
+ return "Deregister Request";
+ case BTA_AG_API_OPEN_EVT:
+ return "Open SLC Request";
+ case BTA_AG_API_CLOSE_EVT:
+ return "Close SLC Request";
+ case BTA_AG_API_AUDIO_OPEN_EVT:
+ return "Open Audio Request";
+ case BTA_AG_API_AUDIO_CLOSE_EVT:
+ return "Close Audio Request";
+ case BTA_AG_API_RESULT_EVT:
+ switch (result)
+ {
+ case BTA_AG_SPK_RES: return ("AT Result BTA_AG_SPK_RES");
+ case BTA_AG_MIC_RES: return ("AT Result BTA_AG_MIC_RES");
+ case BTA_AG_INBAND_RING_RES: return ("AT Result BTA_AG_INBAND_RING_RES");
+ case BTA_AG_CIND_RES: return ("AT Result BTA_AG_CIND_RES");
+ case BTA_AG_BINP_RES: return ("AT Result BTA_AG_BINP_RES");
+ case BTA_AG_IND_RES: return ("AT Result BTA_AG_IND_RES");
+ case BTA_AG_BVRA_RES: return ("AT Result BTA_AG_BVRA_RES");
+ case BTA_AG_CNUM_RES: return ("AT Result BTA_AG_CNUM_RES");
+ case BTA_AG_BTRH_RES: return ("AT Result BTA_AG_BTRH_RES");
+ case BTA_AG_CLCC_RES: return ("AT Result BTA_AG_CLCC_RES");
+ case BTA_AG_COPS_RES: return ("AT Result BTA_AG_COPS_RES");
+ case BTA_AG_IN_CALL_RES: return ("AT Result BTA_AG_IN_CALL_RES");
+ case BTA_AG_IN_CALL_CONN_RES: return ("AT Result BTA_AG_IN_CALL_CONN_RES");
+ case BTA_AG_CALL_WAIT_RES: return ("AT Result BTA_AG_CALL_WAIT_RES");
+ case BTA_AG_OUT_CALL_ORIG_RES: return ("AT Result BTA_AG_OUT_CALL_ORIG_RES");
+ case BTA_AG_OUT_CALL_ALERT_RES: return ("AT Result BTA_AG_OUT_CALL_ALERT_RES");
+ case BTA_AG_OUT_CALL_CONN_RES: return ("AT Result BTA_AG_OUT_CALL_CONN_RES");
+ case BTA_AG_CALL_CANCEL_RES: return ("AT Result BTA_AG_CALL_CANCEL_RES");
+ case BTA_AG_END_CALL_RES: return ("AT Result BTA_AG_END_CALL_RES");
+ case BTA_AG_UNAT_RES: return ("AT Result BTA_AG_UNAT_RES");
+ default: return ("Unknown AG Result");
+ }
+ case BTA_AG_API_SETCODEC_EVT:
+ return "Set Codec Request";
+ case BTA_AG_RFC_OPEN_EVT:
+ return "RFC Opened";
+ case BTA_AG_RFC_CLOSE_EVT:
+ return "RFC Closed";
+ case BTA_AG_RFC_SRV_CLOSE_EVT:
+ return "RFC SRV Closed";
+ case BTA_AG_RFC_DATA_EVT:
+ return "RFC Data";
+ case BTA_AG_SCO_OPEN_EVT:
+ return "Audio Opened";
+ case BTA_AG_SCO_CLOSE_EVT:
+ return "Audio Closed";
+ case BTA_AG_DISC_ACP_RES_EVT:
+ return "Discovery ACP Result";
+ case BTA_AG_DISC_INT_RES_EVT:
+ return "Discovery INT Result";
+ case BTA_AG_DISC_OK_EVT:
+ return "Discovery OK";
+ case BTA_AG_DISC_FAIL_EVT:
+ return "Discovery Failed";
+ case BTA_AG_CI_RX_WRITE_EVT:
+ return "CI RX Write";
+ case BTA_AG_RING_TOUT_EVT:
+ return "Ring Timeout";
+ case BTA_AG_SVC_TOUT_EVT:
+ return "Service Timeout";
+ case BTA_AG_API_ENABLE_EVT:
+ return "Enable AG";
+ case BTA_AG_API_DISABLE_EVT:
+ return "Disable AG";
+ case BTA_AG_CI_SCO_DATA_EVT:
+ return "SCO data Callin";
+ case BTA_AG_CI_SLC_READY_EVT:
+ return "SLC Ready Callin";
+ default:
+ return "Unknown AG Event";
+ }
+}
+
+static char *bta_ag_state_str(UINT8 state)
+{
+ switch (state)
+ {
+ case BTA_AG_INIT_ST:
+ return "Initial";
+ case BTA_AG_OPENING_ST:
+ return "Opening";
+ case BTA_AG_OPEN_ST:
+ return "Open";
+ case BTA_AG_CLOSING_ST:
+ return "Closing";
+ default:
+ return "Unknown AG State";
+ }
+}
+
+#endif
diff --git a/bta/ag/bta_ag_rfc.c b/bta/ag/bta_ag_rfc.c
new file mode 100644
index 0000000..bccb2cf
--- /dev/null
+++ b/bta/ag/bta_ag_rfc.c
@@ -0,0 +1,428 @@
+/*****************************************************************************
+**
+** Name: bta_ag_rfc.c
+**
+** Description: This file contains the audio gateway functions
+** controlling the RFCOMM connections.
+**
+** Copyright (c) 2004-2008, Broadcom Corp., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include <string.h>
+#include "bta_api.h"
+#include "bta_sys.h"
+#include "bta_ag_api.h"
+#include "bta_ag_int.h"
+#include "bta_ag_co.h"
+#include "btm_api.h"
+#include "port_api.h"
+#include "rfcdefs.h"
+#include "gki.h"
+#include "bd.h"
+
+/* Event mask for RfCOMM port callback */
+#define BTA_AG_PORT_EV_MASK PORT_EV_RXCHAR
+
+/* each scb has its own rfcomm callbacks */
+void bta_ag_port_cback_1(UINT32 code, UINT16 port_handle);
+void bta_ag_port_cback_2(UINT32 code, UINT16 port_handle);
+void bta_ag_port_cback_3(UINT32 code, UINT16 port_handle);
+
+void bta_ag_mgmt_cback_1(UINT32 code, UINT16 port_handle);
+void bta_ag_mgmt_cback_2(UINT32 code, UINT16 port_handle);
+void bta_ag_mgmt_cback_3(UINT32 code, UINT16 port_handle);
+
+int bta_ag_data_cback_1(UINT16 port_handle, void *p_data, UINT16 len);
+int bta_ag_data_cback_2(UINT16 port_handle, void *p_data, UINT16 len);
+int bta_ag_data_cback_3(UINT16 port_handle, void *p_data, UINT16 len);
+
+/* rfcomm callback function tables */
+typedef tPORT_CALLBACK *tBTA_AG_PORT_CBACK;
+const tBTA_AG_PORT_CBACK bta_ag_port_cback_tbl[] =
+{
+ bta_ag_port_cback_1,
+ bta_ag_port_cback_2,
+ bta_ag_port_cback_3
+};
+
+const tBTA_AG_PORT_CBACK bta_ag_mgmt_cback_tbl[] =
+{
+ bta_ag_mgmt_cback_1,
+ bta_ag_mgmt_cback_2,
+ bta_ag_mgmt_cback_3
+};
+
+typedef tPORT_DATA_CALLBACK *tBTA_AG_DATA_CBACK;
+const tBTA_AG_DATA_CBACK bta_ag_data_cback_tbl[] =
+{
+ bta_ag_data_cback_1,
+ bta_ag_data_cback_2,
+ bta_ag_data_cback_3
+};
+
+/*******************************************************************************
+**
+** Function bta_ag_port_cback
+**
+** Description RFCOMM Port callback
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ag_port_cback(UINT32 code, UINT16 port_handle, UINT16 handle)
+{
+ BT_HDR *p_buf;
+ tBTA_AG_SCB *p_scb;
+
+ if ((p_scb = bta_ag_scb_by_idx(handle)) != NULL)
+ {
+ /* ignore port events for port handles other than connected handle */
+ if (port_handle != p_scb->conn_handle)
+ {
+ APPL_TRACE_DEBUG3("ag_port_cback ignoring handle:%d conn_handle = %d other handle = %d",
+ port_handle, p_scb->conn_handle, handle);
+ return;
+ }
+
+ if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->event = BTA_AG_RFC_DATA_EVT;
+ p_buf->layer_specific = handle;
+ bta_sys_sendmsg(p_buf);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_mgmt_cback
+**
+** Description RFCOMM management callback
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ag_mgmt_cback(UINT32 code, UINT16 port_handle, UINT16 handle)
+{
+ tBTA_AG_RFC *p_buf;
+ tBTA_AG_SCB *p_scb;
+ UINT16 event;
+ UINT8 i;
+ BOOLEAN found_handle = FALSE;
+
+ APPL_TRACE_DEBUG3("ag_mgmt_cback : code = %d, port_handle = %d, handle = %d",
+ code, port_handle, handle);
+
+ if ((p_scb = bta_ag_scb_by_idx(handle)) != NULL)
+ {
+ /* ignore close event for port handles other than connected handle */
+ if ((code != PORT_SUCCESS) && (port_handle != p_scb->conn_handle))
+ {
+ APPL_TRACE_DEBUG1("ag_mgmt_cback ignoring handle:%d", port_handle);
+ return;
+ }
+
+ if (code == PORT_SUCCESS)
+ {
+ if (p_scb->conn_handle) /* Outgoing connection */
+ {
+ if (port_handle == p_scb->conn_handle)
+ found_handle = TRUE;
+ }
+ else /* Incoming connection */
+ {
+ for (i = 0; i < BTA_AG_NUM_IDX; i++)
+ {
+ if (port_handle == p_scb->serv_handle[i])
+ found_handle = TRUE;
+ }
+ }
+
+ if (!found_handle)
+ {
+ APPL_TRACE_ERROR1 ("bta_ag_mgmt_cback: PORT_SUCCESS, ignoring handle = %d", port_handle);
+ return;
+ }
+
+ event = BTA_AG_RFC_OPEN_EVT;
+ }
+ /* distinguish server close events */
+ else if (port_handle == p_scb->conn_handle)
+ {
+ event = BTA_AG_RFC_CLOSE_EVT;
+ }
+ else
+ {
+ event = BTA_AG_RFC_SRV_CLOSE_EVT;
+ }
+
+ if ((p_buf = (tBTA_AG_RFC *) GKI_getbuf(sizeof(tBTA_AG_RFC))) != NULL)
+ {
+ p_buf->hdr.event = event;
+ p_buf->hdr.layer_specific = handle;
+ p_buf->port_handle = port_handle;
+ bta_sys_sendmsg(p_buf);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_data_cback
+**
+** Description RFCOMM data callback
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static int bta_ag_data_cback(UINT16 port_handle, void *p_data, UINT16 len, UINT16 handle)
+{
+ /* call data call-out directly */
+ bta_ag_co_tx_write(handle, (UINT8 *) p_data, len);
+ return 0;
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_port_cback_1 to 3
+** bta_ag_mgmt_cback_1 to 3
+**
+** Description RFCOMM callback functions. This is an easy way to
+** distinguish scb from the callback.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_mgmt_cback_1(UINT32 code, UINT16 handle) {bta_ag_mgmt_cback(code, handle, 1);}
+void bta_ag_mgmt_cback_2(UINT32 code, UINT16 handle) {bta_ag_mgmt_cback(code, handle, 2);}
+void bta_ag_mgmt_cback_3(UINT32 code, UINT16 handle) {bta_ag_mgmt_cback(code, handle, 3);}
+void bta_ag_port_cback_1(UINT32 code, UINT16 handle) {bta_ag_port_cback(code, handle, 1);}
+void bta_ag_port_cback_2(UINT32 code, UINT16 handle) {bta_ag_port_cback(code, handle, 2);}
+void bta_ag_port_cback_3(UINT32 code, UINT16 handle) {bta_ag_port_cback(code, handle, 3);}
+
+/*******************************************************************************
+**
+** Function bta_ag_data_cback_1 to 3
+**
+** Description RFCOMM data callback functions. This is an easy way to
+** distinguish scb from the callback.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+int bta_ag_data_cback_1(UINT16 port_handle, void *p_data, UINT16 len)
+{
+ return bta_ag_data_cback(port_handle, p_data, len, 1);
+}
+int bta_ag_data_cback_2(UINT16 port_handle, void *p_data, UINT16 len)
+{
+ return bta_ag_data_cback(port_handle, p_data, len, 2);
+}
+int bta_ag_data_cback_3(UINT16 port_handle, void *p_data, UINT16 len)
+{
+ return bta_ag_data_cback(port_handle, p_data, len, 3);
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_setup_port
+**
+** Description Setup RFCOMM port for use by AG.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_setup_port(tBTA_AG_SCB *p_scb, UINT16 handle)
+{
+ UINT16 i = bta_ag_scb_to_idx(p_scb) - 1;
+
+ /* set up data callback if using pass through mode */
+ if (bta_ag_cb.parse_mode == BTA_AG_PASS_THROUGH)
+ {
+ PORT_SetDataCallback(handle, bta_ag_data_cback_tbl[i]);
+ }
+
+ PORT_SetEventMask(handle, BTA_AG_PORT_EV_MASK);
+ PORT_SetEventCallback(handle, bta_ag_port_cback_tbl[i]);
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_start_servers
+**
+** Description Setup RFCOMM servers for use by AG.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_start_servers(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK services)
+{
+ int i;
+ int bta_ag_port_status;
+
+ services >>= BTA_HSP_SERVICE_ID;
+ for (i = 0; i < BTA_AG_NUM_IDX && services != 0; i++, services >>= 1)
+ {
+ /* if service is set in mask */
+ if (services & 1)
+ {
+ BTM_SetSecurityLevel(FALSE, "", bta_ag_sec_id[i], p_scb->serv_sec_mask,
+ BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM, bta_ag_cb.profile[i].scn);
+
+ bta_ag_port_status = RFCOMM_CreateConnection(bta_ag_uuid[i], bta_ag_cb.profile[i].scn,
+ TRUE, BTA_AG_MTU, (UINT8 *) bd_addr_any, &(p_scb->serv_handle[i]),
+ bta_ag_mgmt_cback_tbl[bta_ag_scb_to_idx(p_scb) - 1]);
+
+ if( bta_ag_port_status == PORT_SUCCESS )
+ {
+ bta_ag_setup_port(p_scb, p_scb->serv_handle[i]);
+ }
+ else
+ {
+ /* TODO: CR#137125 to handle to error properly */
+ APPL_TRACE_DEBUG1("bta_ag_start_servers: RFCOMM_CreateConnection returned error:%d", bta_ag_port_status);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_close_servers
+**
+** Description Close RFCOMM servers port for use by AG.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_close_servers(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK services)
+{
+ int i;
+
+ services >>= BTA_HSP_SERVICE_ID;
+ for (i = 0; i < BTA_AG_NUM_IDX && services != 0; i++, services >>= 1)
+ {
+ /* if service is set in mask */
+ if (services & 1)
+ {
+ RFCOMM_RemoveServer(p_scb->serv_handle[i]);
+ p_scb->serv_handle[i] = 0;
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_is_server_closed
+**
+** Description Returns TRUE if all servers are closed.
+**
+**
+** Returns TRUE if all servers are closed, FALSE otherwise
+**
+*******************************************************************************/
+BOOLEAN bta_ag_is_server_closed (tBTA_AG_SCB *p_scb)
+{
+ UINT8 xx;
+ BOOLEAN is_closed = TRUE;
+
+ for (xx = 0; xx < BTA_AG_NUM_IDX; xx++)
+ {
+ if (p_scb->serv_handle[xx] != 0)
+ is_closed = FALSE;
+ }
+
+ return is_closed;
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_rfc_do_open
+**
+** Description Open an RFCOMM connection to the peer device.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_rfc_do_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ BTM_SetSecurityLevel(TRUE, "", bta_ag_sec_id[p_scb->conn_service],
+ p_scb->cli_sec_mask, BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM, p_scb->peer_scn);
+
+ if (RFCOMM_CreateConnection(bta_ag_uuid[p_scb->conn_service], p_scb->peer_scn,
+ FALSE, BTA_AG_MTU, p_scb->peer_addr, &(p_scb->conn_handle),
+ bta_ag_mgmt_cback_tbl[bta_ag_scb_to_idx(p_scb) - 1]) == PORT_SUCCESS)
+ {
+ bta_ag_setup_port(p_scb, p_scb->conn_handle);
+ APPL_TRACE_DEBUG1("bta_ag_rfc_do_open : conn_handle = %d", p_scb->conn_handle);
+ }
+ /* RFCOMM create connection failed; send ourselves RFCOMM close event */
+ else
+ {
+ bta_ag_sm_execute(p_scb, BTA_AG_RFC_CLOSE_EVT, p_data);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_rfc_do_close
+**
+** Description Close RFCOMM connection.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_rfc_do_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ tBTA_AG_RFC *p_buf;
+
+ if (p_scb->conn_handle)
+ {
+ RFCOMM_RemoveConnection(p_scb->conn_handle);
+ }
+ else
+ {
+ /* Close API was called while AG is in Opening state. */
+ /* Need to trigger the state machine to send callback to the app */
+ /* and move back to INIT state. */
+ if ((p_buf = (tBTA_AG_RFC *) GKI_getbuf(sizeof(tBTA_AG_RFC))) != NULL)
+ {
+ p_buf->hdr.event = BTA_AG_RFC_CLOSE_EVT;
+ p_buf->hdr.layer_specific = bta_ag_scb_to_idx(p_scb);
+ bta_sys_sendmsg(p_buf);
+ }
+
+ /* Cancel SDP if it had been started. */
+ /*
+ if(p_scb->p_disc_db)
+ {
+ (void)SDP_CancelServiceSearch (p_scb->p_disc_db);
+ }
+ */
+ }
+
+#ifdef _WIN32_WCE
+ {
+ /* Windows versions of RFCOMM does NOT generate a closed callback when we close */
+ tPORT_CALLBACK *rfc_mgmt_cback = bta_ag_mgmt_cback_tbl[bta_ag_scb_to_idx(p_scb) - 1];
+
+ if (rfc_mgmt_cback)
+ {
+ (rfc_mgmt_cback)(PORT_CLOSED, p_scb->conn_handle);
+ }
+ }
+#endif
+}
+
diff --git a/bta/ag/bta_ag_sco.c b/bta/ag/bta_ag_sco.c
new file mode 100644
index 0000000..021b96c
--- /dev/null
+++ b/bta/ag/bta_ag_sco.c
@@ -0,0 +1,1650 @@
+/*****************************************************************************
+**
+** Name: bta_ag_sco.c
+**
+** Description: This file contains functions for managing the
+** SCO connection used in AG.
+**
+** Copyright (c) 2004-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bta_api.h"
+#include "bta_ag_api.h"
+#include "bta_ag_co.h"
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+#include "bta_dm_co.h"
+#endif
+#include "bta_ag_int.h"
+#include "btm_api.h"
+#include "gki.h"
+
+#ifndef BTA_AG_SCO_DEBUG
+#define BTA_AG_SCO_DEBUG FALSE
+#endif
+
+#ifndef BTA_AG_CODEC_NEGO_TIMEOUT
+#define BTA_AG_CODEC_NEGO_TIMEOUT 3000
+#endif
+
+#if BTA_AG_SCO_DEBUG == TRUE
+static char *bta_ag_sco_evt_str(UINT8 event);
+static char *bta_ag_sco_state_str(UINT8 state);
+#endif
+
+#define BTA_AG_NO_EDR_ESCO (BTM_SCO_PKT_TYPES_MASK_NO_2_EV3 | \
+ BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 | \
+ BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 | \
+ BTM_SCO_PKT_TYPES_MASK_NO_3_EV5)
+
+/* sco events */
+enum
+{
+ BTA_AG_SCO_LISTEN_E, /* listen request */
+ BTA_AG_SCO_OPEN_E, /* open request */
+ BTA_AG_SCO_XFER_E, /* transfer request */
+#if (BTM_WBS_INCLUDED == TRUE )
+ BTA_AG_SCO_CN_DONE_E, /* codec negotiation done */
+ BTA_AG_SCO_REOPEN_E, /* Retry with other codec when failed */
+#endif
+ BTA_AG_SCO_CLOSE_E, /* close request */
+ BTA_AG_SCO_SHUTDOWN_E, /* shutdown request */
+ BTA_AG_SCO_CONN_OPEN_E, /* sco open */
+ BTA_AG_SCO_CONN_CLOSE_E, /* sco closed */
+ BTA_AG_SCO_CI_DATA_E /* SCO data ready */
+};
+
+#if (BTM_WBS_INCLUDED == TRUE )
+#define BTA_AG_NUM_CODECS 2
+static const tBTM_ESCO_PARAMS bta_ag_esco_params[BTA_AG_NUM_CODECS] =
+{
+ /* CVSD */
+ {
+ BTM_64KBITS_RATE, /* TX Bandwidth (64 kbits/sec) */
+ BTM_64KBITS_RATE, /* RX Bandwidth (64 kbits/sec) */
+ 0x000a, /* 10 ms (HS/HF can use EV3, 2-EV3, 3-EV3) */
+ BTM_VOICE_SETTING_CVSD, /* Inp Linear, Air CVSD, 2s Comp, 16bit */
+ (BTM_SCO_PKT_TYPES_MASK_HV1 + /* Packet Types */
+ BTM_SCO_PKT_TYPES_MASK_HV2 +
+ BTM_SCO_PKT_TYPES_MASK_HV3 +
+ BTM_SCO_PKT_TYPES_MASK_EV3 +
+ BTM_SCO_PKT_TYPES_MASK_EV4 +
+ BTM_SCO_PKT_TYPES_MASK_EV5 +
+ BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 +
+ BTM_SCO_PKT_TYPES_MASK_NO_3_EV5),
+ BTM_ESCO_RETRANS_POWER /* Retransmission effort */
+ },
+ /* mSBC */
+ {
+ BTM_64KBITS_RATE, /* TX Bandwidth (64 kbits/sec), 8000 */
+ BTM_64KBITS_RATE, /* RX Bandwidth (64 kbits/sec), 8000 */
+ 13, /* 13 ms */
+ BTM_VOICE_SETTING_TRANS, /* Inp Linear, Transparent, 2s Comp, 16bit */
+ (BTM_SCO_PKT_TYPES_MASK_EV3 | /* Packet Types : EV3 + 2-EV3 */
+ BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 |
+ BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 |
+ BTM_SCO_PKT_TYPES_MASK_NO_3_EV5),
+ BTM_ESCO_RETRANS_QUALITY /* Retransmission effort */
+ }
+};
+#else
+static const tBTM_ESCO_PARAMS bta_ag_esco_params =
+{
+ BTM_64KBITS_RATE, /* TX Bandwidth (64 kbits/sec) */
+ BTM_64KBITS_RATE, /* RX Bandwidth (64 kbits/sec) */
+ 0x000a, /* 10 ms (HS/HF can use EV3, 2-EV3, 3-EV3) */
+ 0x0060, /* Inp Linear, Air CVSD, 2s Comp, 16bit */
+ (BTM_SCO_PKT_TYPES_MASK_HV1 + /* Packet Types */
+ BTM_SCO_PKT_TYPES_MASK_HV2 +
+ BTM_SCO_PKT_TYPES_MASK_HV3 +
+ BTM_SCO_PKT_TYPES_MASK_EV3 +
+ BTM_SCO_PKT_TYPES_MASK_EV4 +
+ BTM_SCO_PKT_TYPES_MASK_EV5 +
+ BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 +
+ BTM_SCO_PKT_TYPES_MASK_NO_3_EV5),
+ BTM_ESCO_RETRANS_POWER /* Retransmission effort */
+};
+#endif
+
+/*******************************************************************************
+**
+** Function bta_ag_sco_conn_cback
+**
+** Description BTM SCO connection callback.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ag_sco_conn_cback(UINT16 sco_idx)
+{
+ UINT16 handle;
+ BT_HDR *p_buf;
+ tBTA_AG_SCB *p_scb;
+
+ /* match callback to scb; first check current sco scb */
+ if (bta_ag_cb.sco.p_curr_scb != NULL && bta_ag_cb.sco.p_curr_scb->in_use)
+ {
+ handle = bta_ag_scb_to_idx(bta_ag_cb.sco.p_curr_scb);
+ }
+ /* then check for scb connected to this peer */
+ else
+ {
+ /* Check if SLC is up */
+ handle = bta_ag_idx_by_bdaddr(BTM_ReadScoBdAddr(sco_idx));
+ p_scb = bta_ag_scb_by_idx(handle);
+ if(p_scb && !p_scb->svc_conn)
+ handle = 0;
+ }
+
+ if (handle != 0)
+ {
+ if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->event = BTA_AG_SCO_OPEN_EVT;
+ p_buf->layer_specific = handle;
+ bta_sys_sendmsg(p_buf);
+ }
+ }
+ /* no match found; disconnect sco, init sco variables */
+ else
+ {
+ bta_ag_cb.sco.p_curr_scb = NULL;
+ bta_ag_cb.sco.state = BTA_AG_SCO_SHUTDOWN_ST;
+ BTM_RemoveSco(sco_idx);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_sco_disc_cback
+**
+** Description BTM SCO disconnection callback.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ag_sco_disc_cback(UINT16 sco_idx)
+{
+ BT_HDR *p_buf;
+ UINT16 handle = 0;
+
+ APPL_TRACE_DEBUG3 ("bta_ag_sco_disc_cback(): sco_idx: 0x%x p_cur_scb: 0x%08x sco.state: %d", sco_idx, bta_ag_cb.sco.p_curr_scb, bta_ag_cb.sco.state);
+
+ APPL_TRACE_DEBUG4 ("bta_ag_sco_disc_cback(): scb[0] addr: 0x%08x in_use: %u sco_idx: 0x%x sco state: %u",
+ &bta_ag_cb.scb[0], bta_ag_cb.scb[0].in_use, bta_ag_cb.scb[0].sco_idx, bta_ag_cb.scb[0].state);
+ APPL_TRACE_DEBUG4 ("bta_ag_sco_disc_cback(): scb[1] addr: 0x%08x in_use: %u sco_idx: 0x%x sco state: %u",
+ &bta_ag_cb.scb[1], bta_ag_cb.scb[1].in_use, bta_ag_cb.scb[1].sco_idx, bta_ag_cb.scb[1].state);
+
+ /* match callback to scb */
+ if (bta_ag_cb.sco.p_curr_scb != NULL && bta_ag_cb.sco.p_curr_scb->in_use)
+ {
+ /* We only care about callbacks for the active SCO */
+ if (bta_ag_cb.sco.p_curr_scb->sco_idx != sco_idx)
+ {
+ if (bta_ag_cb.sco.p_curr_scb->sco_idx != 0xFFFF)
+ return;
+ }
+ handle = bta_ag_scb_to_idx(bta_ag_cb.sco.p_curr_scb);
+ }
+
+ if (handle != 0)
+ {
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+ tBTM_STATUS status = BTM_ConfigScoPath(BTM_SCO_ROUTE_PCM, NULL, NULL, TRUE);
+ APPL_TRACE_DEBUG1("bta_ag_sco_disc_cback sco close config status = %d", status);
+ /* SCO clean up here */
+ bta_dm_sco_co_close();
+#endif
+
+#if (BTM_WBS_INCLUDED == TRUE )
+ /* Restore settings */
+ if(bta_ag_cb.sco.p_curr_scb->inuse_codec == BTA_AG_CODEC_MSBC)
+ {
+ BTM_SetWBSCodec (BTM_SCO_CODEC_NONE);
+ BTM_WriteVoiceSettings (BTM_VOICE_SETTING_CVSD);
+
+ /* If SCO open was initiated by AG and failed for mSBC, try CVSD again. */
+ if (bta_ag_sco_is_opening (bta_ag_cb.sco.p_curr_scb))
+ {
+ bta_ag_cb.sco.p_curr_scb->codec_fallback = TRUE;
+ APPL_TRACE_DEBUG0("Fallback to CVSD");
+ }
+ }
+
+ bta_ag_cb.sco.p_curr_scb->inuse_codec = BTA_AG_CODEC_NONE;
+#endif
+
+ if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->event = BTA_AG_SCO_CLOSE_EVT;
+ p_buf->layer_specific = handle;
+ bta_sys_sendmsg(p_buf);
+ }
+ }
+ /* no match found */
+ else
+ {
+ APPL_TRACE_DEBUG0("no scb for ag_sco_disc_cback");
+
+ /* sco could be closed after scb dealloc'ed */
+ if (bta_ag_cb.sco.p_curr_scb != NULL)
+ {
+ bta_ag_cb.sco.p_curr_scb->sco_idx = BTM_INVALID_SCO_INDEX;
+ bta_ag_cb.sco.p_curr_scb = NULL;
+ bta_ag_cb.sco.state = BTA_AG_SCO_SHUTDOWN_ST;
+ }
+ }
+}
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+/*******************************************************************************
+**
+** Function bta_ag_sco_read_cback
+**
+** Description Callback function is the callback function for incoming
+** SCO data over HCI.
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ag_sco_read_cback (UINT16 sco_inx, BT_HDR *p_data, tBTM_SCO_DATA_FLAG status)
+{
+ if (status != BTM_SCO_DATA_CORRECT)
+ {
+ APPL_TRACE_DEBUG1("bta_ag_sco_read_cback: status(%d)", status);
+ }
+
+ /* Callout function must free the data. */
+ bta_dm_sco_co_in_data (p_data, status);
+}
+#endif
+/*******************************************************************************
+**
+** Function bta_ag_remove_sco
+**
+** Description Removes the specified SCO from the system.
+** If only_active is TRUE, then SCO is only removed if connected
+**
+** Returns BOOLEAN - TRUE if Sco removal was started
+**
+*******************************************************************************/
+static BOOLEAN bta_ag_remove_sco(tBTA_AG_SCB *p_scb, BOOLEAN only_active)
+{
+ BOOLEAN removed_started = FALSE;
+ tBTM_STATUS status;
+
+ if (p_scb->sco_idx != BTM_INVALID_SCO_INDEX)
+ {
+ if (!only_active || p_scb->sco_idx == bta_ag_cb.sco.cur_idx)
+ {
+ status = BTM_RemoveSco(p_scb->sco_idx);
+
+ APPL_TRACE_DEBUG2("ag remove sco: inx 0x%04x, status:0x%x", p_scb->sco_idx, status);
+
+ if (status == BTM_CMD_STARTED)
+ {
+ /* Sco is connected; set current control block */
+ bta_ag_cb.sco.p_curr_scb = p_scb;
+
+ removed_started = TRUE;
+ }
+ /* If no connection reset the sco handle */
+ else if ( (status == BTM_SUCCESS) || (status == BTM_UNKNOWN_ADDR) )
+ {
+ p_scb->sco_idx = BTM_INVALID_SCO_INDEX;
+ }
+ }
+ }
+ return removed_started;
+}
+
+
+/*******************************************************************************
+**
+** Function bta_ag_esco_connreq_cback
+**
+** Description BTM eSCO connection requests and eSCO change requests
+** Only the connection requests are processed by BTA.
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ag_esco_connreq_cback(tBTM_ESCO_EVT event, tBTM_ESCO_EVT_DATA *p_data)
+{
+ tBTA_AG_SCB *p_scb;
+ UINT16 handle;
+ UINT16 sco_inx = p_data->conn_evt.sco_inx;
+
+ /* Only process connection requests */
+ if (event == BTM_ESCO_CONN_REQ_EVT)
+ {
+ if ((handle = bta_ag_idx_by_bdaddr(BTM_ReadScoBdAddr(sco_inx))) != 0 &&
+ ((p_scb = bta_ag_scb_by_idx(handle)) != NULL) && p_scb->svc_conn)
+ {
+ p_scb->sco_idx = sco_inx;
+
+ /* If no other SCO active, allow this one */
+ if (!bta_ag_cb.sco.p_curr_scb)
+ {
+ APPL_TRACE_EVENT1("bta_ag_esco_connreq_cback: Accept Conn Request (sco_inx 0x%04x)", sco_inx);
+ bta_ag_sco_conn_rsp(p_scb, &p_data->conn_evt);
+
+ bta_ag_cb.sco.state = BTA_AG_SCO_OPENING_ST;
+ bta_ag_cb.sco.p_curr_scb = p_scb;
+ bta_ag_cb.sco.cur_idx = p_scb->sco_idx;
+ }
+ else /* Begin a transfer: Close current SCO before responding */
+ {
+ APPL_TRACE_DEBUG0("bta_ag_esco_connreq_cback: Begin XFER");
+ bta_ag_cb.sco.p_xfer_scb = p_scb;
+ bta_ag_cb.sco.conn_data = p_data->conn_evt;
+ bta_ag_cb.sco.state = BTA_AG_SCO_OPEN_XFER_ST;
+
+ if (!bta_ag_remove_sco(bta_ag_cb.sco.p_curr_scb, TRUE))
+ {
+ APPL_TRACE_ERROR1("bta_ag_esco_connreq_cback: Nothing to remove so accept Conn Request (sco_inx 0x%04x)", sco_inx);
+ bta_ag_cb.sco.p_xfer_scb = NULL;
+ bta_ag_cb.sco.state = BTA_AG_SCO_LISTEN_ST;
+
+ bta_ag_sco_conn_rsp(p_scb, &p_data->conn_evt);
+ }
+ }
+ }
+ /* If error occurred send reject response immediately */
+ else
+ {
+ APPL_TRACE_WARNING0("no scb for bta_ag_esco_connreq_cback or no resources");
+ BTM_EScoConnRsp(p_data->conn_evt.sco_inx, HCI_ERR_HOST_REJECT_RESOURCES, NULL);
+ }
+ }
+ /* Received a change in the esco link */
+ else if (event == BTM_ESCO_CHG_EVT)
+ {
+ APPL_TRACE_EVENT5("eSCO change event (inx %d): rtrans %d, rxlen %d, txlen %d, txint %d",
+ p_data->chg_evt.sco_inx,
+ p_data->chg_evt.retrans_window, p_data->chg_evt.rx_pkt_len,
+ p_data->chg_evt.tx_pkt_len, p_data->chg_evt.tx_interval);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_cback_sco
+**
+** Description Call application callback function with SCO event.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ag_cback_sco(tBTA_AG_SCB *p_scb, UINT8 event)
+{
+ tBTA_AG_HDR sco;
+
+ sco.handle = bta_ag_scb_to_idx(p_scb);
+ sco.app_id = p_scb->app_id;
+
+ /* call close cback */
+ (*bta_ag_cb.p_cback)(event, (tBTA_AG *) &sco);
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_create_sco
+**
+** Description
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ag_create_sco(tBTA_AG_SCB *p_scb, BOOLEAN is_orig)
+{
+ tBTM_STATUS status;
+ UINT8 *p_bd_addr = NULL;
+ tBTM_ESCO_PARAMS params;
+#if (BTM_WBS_INCLUDED == TRUE )
+ tBTA_AG_PEER_CODEC esco_codec = BTM_SCO_CODEC_CVSD;
+ int codec_index = 0;
+#endif
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+ tBTM_SCO_ROUTE_TYPE sco_route;
+ tBTA_CODEC_INFO codec_info = {BTA_SCO_CODEC_PCM};
+ UINT32 pcm_sample_rate;
+#endif
+
+ /* Make sure this sco handle is not already in use */
+ if (p_scb->sco_idx != BTM_INVALID_SCO_INDEX)
+ {
+ APPL_TRACE_WARNING1("bta_ag_create_sco: Index 0x%04x Already In Use!",
+ p_scb->sco_idx);
+ return;
+ }
+
+#if (BTM_WBS_INCLUDED == TRUE )
+ if ((p_scb->sco_codec == BTM_SCO_CODEC_MSBC) &&
+ !p_scb->codec_fallback &&
+ !p_scb->retry_with_sco_only)
+ esco_codec = BTM_SCO_CODEC_MSBC;
+
+ if (p_scb->codec_fallback)
+ {
+ p_scb->codec_fallback = FALSE;
+
+ /* Force AG to send +BCS for the next audio connection. */
+ p_scb->codec_updated = TRUE;
+ }
+
+ if (esco_codec == BTM_SCO_CODEC_MSBC)
+ codec_index = esco_codec - 1;
+
+ params = bta_ag_esco_params[codec_index];
+#else
+ params = bta_ag_esco_params;
+#endif
+
+ if(bta_ag_cb.sco.param_updated) /* If we do not use the default parameters */
+ params = bta_ag_cb.sco.params;
+
+ if(!bta_ag_cb.sco.param_updated)
+ {
+#if (BTM_WBS_INCLUDED == TRUE)
+ if (!codec_index) /* For non-WBS */
+#endif
+ {
+ /* Use the application packet types (5 slot EV packets not allowed) */
+ params.packet_types = p_bta_ag_cfg->sco_pkt_types |
+ BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 |
+ BTM_SCO_PKT_TYPES_MASK_NO_3_EV5;
+ }
+ }
+
+ /* if initiating set current scb and peer bd addr */
+ if (is_orig)
+ {
+ /* Attempt to use eSCO if remote host supports HFP >= 1.5 */
+ /* Need to find out from SIG if HSP can use eSCO; for now use SCO */
+ if (p_scb->conn_service == BTA_AG_HFP && p_scb->peer_version >= HFP_VERSION_1_5 && !p_scb->retry_with_sco_only)
+ {
+
+ BTM_SetEScoMode(BTM_LINK_TYPE_ESCO, &params);
+ /* If ESCO or EDR ESCO, retry with SCO only in case of failure */
+ if((params.packet_types & BTM_ESCO_LINK_ONLY_MASK)
+ ||!((params.packet_types & ~(BTM_ESCO_LINK_ONLY_MASK | BTM_SCO_LINK_ONLY_MASK)) ^ BTA_AG_NO_EDR_ESCO))
+ {
+#if (BTM_WBS_INCLUDED == TRUE )
+ if (esco_codec != BTA_AG_CODEC_MSBC)
+ {
+ p_scb->retry_with_sco_only = TRUE;
+ APPL_TRACE_API0("Setting retry_with_sco_only to TRUE");
+ }
+ else /* Do not use SCO when using mSBC */
+ {
+ p_scb->retry_with_sco_only = FALSE;
+ APPL_TRACE_API0("Setting retry_with_sco_only to FALSE");
+ }
+#else
+ p_scb->retry_with_sco_only = TRUE;
+ APPL_TRACE_API0("Setting retry_with_sco_only to TRUE");
+#endif
+ }
+ }
+ else
+ {
+ if(p_scb->retry_with_sco_only)
+ APPL_TRACE_API0("retrying with SCO only");
+ p_scb->retry_with_sco_only = FALSE;
+
+ BTM_SetEScoMode(BTM_LINK_TYPE_SCO, &params);
+ }
+
+ bta_ag_cb.sco.p_curr_scb = p_scb;
+
+ /* tell sys to stop av if any */
+ bta_sys_sco_use(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+
+ /* Allow any platform specific pre-SCO set up to take place */
+ bta_ag_co_audio_state(bta_ag_scb_to_idx(p_scb), p_scb->app_id, BTA_AG_CO_AUD_STATE_SETUP);
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+#if (BTM_WBS_INCLUDED == TRUE)
+ if (esco_codec == BTA_AG_CODEC_MSBC)
+ pcm_sample_rate = BTA_DM_SCO_SAMP_RATE_16K;
+ else
+#endif
+ pcm_sample_rate = BTA_DM_SCO_SAMP_RATE_8K;
+
+ sco_route = bta_dm_sco_co_init(pcm_sample_rate, pcm_sample_rate, &codec_info, p_scb->app_id);
+#endif
+
+#if (BTM_WBS_INCLUDED == TRUE )
+ if (esco_codec == BTA_AG_CODEC_MSBC)
+ {
+ /* Enable mSBC codec in fw */
+ BTM_SetWBSCodec (esco_codec);
+ }
+
+ /* Specify PCM input for SBC codec in fw */
+ BTM_ConfigI2SPCM (esco_codec, (UINT8)HCI_BRCM_I2SPCM_IS_DEFAULT_ROLE, (UINT8)HCI_BRCM_I2SPCM_SAMPLE_DEFAULT, (UINT8)HCI_BRCM_I2SPCM_CLOCK_DEFAULT);
+
+ /* This setting may not be necessary */
+ /* To be verified with stable 2049 boards */
+ if (esco_codec == BTA_AG_CODEC_MSBC)
+ BTM_WriteVoiceSettings (BTM_VOICE_SETTING_TRANS);
+ else
+ BTM_WriteVoiceSettings (BTM_VOICE_SETTING_CVSD);
+
+ /* save the current codec because sco_codec can be updated while SCO is open. */
+ p_scb->inuse_codec = esco_codec;
+#endif
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+ /* initialize SCO setup, no voice setting for AG, data rate <==> sample rate */
+ BTM_ConfigScoPath(sco_route, bta_ag_sco_read_cback, NULL, TRUE);
+#endif
+ bta_ag_cb.sco.cur_idx = p_scb->sco_idx;
+ }
+ else
+ p_scb->retry_with_sco_only = FALSE;
+
+ p_bd_addr = p_scb->peer_addr;
+
+ status = BTM_CreateSco(p_bd_addr, is_orig, params.packet_types,
+ &p_scb->sco_idx, bta_ag_sco_conn_cback,
+ bta_ag_sco_disc_cback);
+ if (status == BTM_CMD_STARTED)
+ {
+ if (!is_orig)
+ {
+ BTM_RegForEScoEvts(p_scb->sco_idx, bta_ag_esco_connreq_cback);
+ }
+ else /* Initiating the connection, set the current sco handle */
+ {
+ bta_ag_cb.sco.cur_idx = p_scb->sco_idx;
+ }
+ }
+
+ APPL_TRACE_API4("ag create sco: orig %d, inx 0x%04x, status 0x%x, pkt types 0x%04x",
+ is_orig, p_scb->sco_idx, status, params.packet_types);
+}
+
+#if (BTM_WBS_INCLUDED == TRUE )
+/*******************************************************************************
+**
+** Function bta_ag_cn_timer_cback
+**
+** Description
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ag_cn_timer_cback (TIMER_LIST_ENT *p_tle)
+{
+ tBTA_AG_SCB *p_scb;
+
+ if (p_tle)
+ {
+ p_scb = (tBTA_AG_SCB *)p_tle->param;
+
+ if (p_scb)
+ {
+ /* Announce that codec negotiation failed. */
+ bta_ag_sco_codec_nego(p_scb, FALSE);
+
+ /* call app callback */
+ bta_ag_cback_sco(p_scb, BTA_AG_AUDIO_CLOSE_EVT);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_codec_negotiate
+**
+** Description Initiate codec negotiation by sending AT command.
+** If not necessary, skip negotiation.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_codec_negotiate(tBTA_AG_SCB *p_scb)
+{
+ bta_ag_cb.sco.p_curr_scb = p_scb;
+
+ if (p_scb->codec_updated || p_scb->codec_fallback)
+ {
+ /* Change the power mode to Active until sco open is completed. */
+ bta_sys_busy(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+
+ /* Send +BCS to the peer */
+ bta_ag_send_bcs(p_scb, NULL);
+
+ /* Start timer to handle timeout */
+ p_scb->cn_timer.p_cback = (TIMER_CBACK*)&bta_ag_cn_timer_cback;
+ p_scb->cn_timer.param = (INT32)p_scb;
+ bta_sys_start_timer(&p_scb->cn_timer, 0, BTA_AG_CODEC_NEGO_TIMEOUT);
+ }
+ else
+ {
+ /* use same codec type as previous SCO connection, skip codec negotiation */
+ bta_ag_sco_codec_nego(p_scb, TRUE);
+ }
+}
+#endif
+
+/*******************************************************************************
+**
+** Function bta_ag_sco_event
+**
+** Description
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ag_sco_event(tBTA_AG_SCB *p_scb, UINT8 event)
+{
+ tBTA_AG_SCO_CB *p_sco = &bta_ag_cb.sco;
+#if (BTM_WBS_INCLUDED == TRUE )
+ tBTA_AG_SCB *p_cn_scb = NULL; /* For codec negotiation */
+#endif
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+ BT_HDR *p_buf;
+#endif
+#if BTA_AG_SCO_DEBUG == TRUE
+ UINT8 in_state = p_sco->state;
+
+ APPL_TRACE_EVENT5("BTA ag sco evt (hdl 0x%04x): State %d (%s), Event %d (%s)",
+ p_scb->sco_idx,
+ p_sco->state, bta_ag_sco_state_str(p_sco->state),
+ event, bta_ag_sco_evt_str(event));
+#else
+ APPL_TRACE_EVENT3("BTA ag sco evt (hdl 0x%04x): State %d, Event %d",
+ p_scb->sco_idx, p_sco->state, event);
+#endif
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+ if (event == BTA_AG_SCO_CI_DATA_E)
+ {
+ while (TRUE)
+ {
+ bta_dm_sco_co_out_data(&p_buf);
+ if (p_buf)
+ {
+ if (p_sco->state == BTA_AG_SCO_OPEN_ST)
+ BTM_WriteScoData(p_sco->p_curr_scb->sco_idx, p_buf);
+ else
+ GKI_freebuf(p_buf);
+ }
+ else
+ break;
+ }
+
+ return;
+ }
+#endif
+
+ switch (p_sco->state)
+ {
+ case BTA_AG_SCO_SHUTDOWN_ST:
+ switch (event)
+ {
+ case BTA_AG_SCO_LISTEN_E:
+ /* create sco listen connection */
+ bta_ag_create_sco(p_scb, FALSE);
+ p_sco->state = BTA_AG_SCO_LISTEN_ST;
+ break;
+
+ default:
+ APPL_TRACE_WARNING1("BTA_AG_SCO_SHUTDOWN_ST: Ignoring event %d", event);
+ break;
+ }
+ break;
+
+ case BTA_AG_SCO_LISTEN_ST:
+ switch (event)
+ {
+ case BTA_AG_SCO_LISTEN_E:
+ /* create sco listen connection (Additional channel) */
+ bta_ag_create_sco(p_scb, FALSE);
+ break;
+
+ case BTA_AG_SCO_OPEN_E:
+ /* remove listening connection */
+ bta_ag_remove_sco(p_scb, FALSE);
+
+#if (BTM_WBS_INCLUDED == TRUE )
+ /* start codec negotiation */
+ p_sco->state = BTA_AG_SCO_CODEC_ST;
+ p_cn_scb = p_scb;
+#else
+ /* create sco connection to peer */
+ bta_ag_create_sco(p_scb, TRUE);
+ p_sco->state = BTA_AG_SCO_OPENING_ST;
+#endif
+ break;
+
+ case BTA_AG_SCO_SHUTDOWN_E:
+ /* remove listening connection */
+ bta_ag_remove_sco(p_scb, FALSE);
+
+ if (p_scb == p_sco->p_curr_scb)
+ p_sco->p_curr_scb = NULL;
+
+ /* If last SCO instance then finish shutting down */
+ if (!bta_ag_other_scb_open(p_scb))
+ {
+ p_sco->state = BTA_AG_SCO_SHUTDOWN_ST;
+ }
+ break;
+
+ case BTA_AG_SCO_CLOSE_E:
+ /* remove listening connection */
+ /* Ignore the event. We need to keep listening SCO for the active SLC */
+ APPL_TRACE_WARNING1("BTA_AG_SCO_LISTEN_ST: Ignoring event %d", event);
+ break;
+
+ case BTA_AG_SCO_CONN_CLOSE_E:
+ /* sco failed; create sco listen connection */
+ bta_ag_create_sco(p_scb, FALSE);
+ p_sco->state = BTA_AG_SCO_LISTEN_ST;
+ break;
+
+ default:
+ APPL_TRACE_WARNING1("BTA_AG_SCO_LISTEN_ST: Ignoring event %d", event);
+ break;
+ }
+ break;
+
+#if (BTM_WBS_INCLUDED == TRUE )
+ case BTA_AG_SCO_CODEC_ST:
+ switch (event)
+ {
+ case BTA_AG_SCO_LISTEN_E:
+ /* create sco listen connection (Additional channel) */
+ bta_ag_create_sco(p_scb, FALSE);
+ break;
+
+ case BTA_AG_SCO_CN_DONE_E:
+ /* create sco connection to peer */
+ bta_ag_create_sco(p_scb, TRUE);
+ p_sco->state = BTA_AG_SCO_OPENING_ST;
+ break;
+
+ case BTA_AG_SCO_XFER_E:
+ /* save xfer scb */
+ p_sco->p_xfer_scb = p_scb;
+ p_sco->state = BTA_AG_SCO_CLOSE_XFER_ST;
+ break;
+
+ case BTA_AG_SCO_SHUTDOWN_E:
+ /* remove listening connection */
+ bta_ag_remove_sco(p_scb, FALSE);
+
+ if (p_scb == p_sco->p_curr_scb)
+ p_sco->p_curr_scb = NULL;
+
+ /* If last SCO instance then finish shutting down */
+ if (!bta_ag_other_scb_open(p_scb))
+ {
+ p_sco->state = BTA_AG_SCO_SHUTDOWN_ST;
+ }
+ break;
+
+ case BTA_AG_SCO_CLOSE_E:
+ /* sco open is not started yet. just go back to listening */
+ p_sco->state = BTA_AG_SCO_LISTEN_ST;
+ break;
+
+ case BTA_AG_SCO_CONN_CLOSE_E:
+ /* sco failed; create sco listen connection */
+ bta_ag_create_sco(p_scb, FALSE);
+ p_sco->state = BTA_AG_SCO_LISTEN_ST;
+ break;
+
+ default:
+ APPL_TRACE_WARNING1("BTA_AG_SCO_CODEC_ST: Ignoring event %d", event);
+ break;
+ }
+ break;
+#endif
+
+ case BTA_AG_SCO_OPENING_ST:
+ switch (event)
+ {
+ case BTA_AG_SCO_LISTEN_E:
+ /* second headset has now joined */
+ /* create sco listen connection (Additional channel) */
+ if (p_scb != p_sco->p_curr_scb)
+ {
+ bta_ag_create_sco(p_scb, FALSE);
+ }
+ break;
+
+#if (BTM_WBS_INCLUDED == TRUE)
+ case BTA_AG_SCO_REOPEN_E:
+ /* start codec negotiation */
+ p_sco->state = BTA_AG_SCO_CODEC_ST;
+ p_cn_scb = p_scb;
+ break;
+#endif
+
+ case BTA_AG_SCO_XFER_E:
+ /* save xfer scb */
+ p_sco->p_xfer_scb = p_scb;
+ p_sco->state = BTA_AG_SCO_CLOSE_XFER_ST;
+ break;
+
+ case BTA_AG_SCO_CLOSE_E:
+ p_sco->state = BTA_AG_SCO_OPEN_CL_ST;
+ break;
+
+ case BTA_AG_SCO_SHUTDOWN_E:
+ /* If not opening scb, just close it */
+ if (p_scb != p_sco->p_curr_scb)
+ {
+ /* remove listening connection */
+ bta_ag_remove_sco(p_scb, FALSE);
+ }
+ else
+ p_sco->state = BTA_AG_SCO_SHUTTING_ST;
+
+ break;
+
+ case BTA_AG_SCO_CONN_OPEN_E:
+ p_sco->state = BTA_AG_SCO_OPEN_ST;
+ break;
+
+ case BTA_AG_SCO_CONN_CLOSE_E:
+ /* sco failed; create sco listen connection */
+ bta_ag_create_sco(p_scb, FALSE);
+ p_sco->state = BTA_AG_SCO_LISTEN_ST;
+ break;
+
+ default:
+ APPL_TRACE_WARNING1("BTA_AG_SCO_OPENING_ST: Ignoring event %d", event);
+ break;
+ }
+ break;
+
+ case BTA_AG_SCO_OPEN_CL_ST:
+ switch (event)
+ {
+ case BTA_AG_SCO_XFER_E:
+ /* save xfer scb */
+ p_sco->p_xfer_scb = p_scb;
+
+ p_sco->state = BTA_AG_SCO_CLOSE_XFER_ST;
+ break;
+
+ case BTA_AG_SCO_OPEN_E:
+ p_sco->state = BTA_AG_SCO_OPENING_ST;
+ break;
+
+ case BTA_AG_SCO_SHUTDOWN_E:
+ /* If not opening scb, just close it */
+ if (p_scb != p_sco->p_curr_scb)
+ {
+ /* remove listening connection */
+ bta_ag_remove_sco(p_scb, FALSE);
+ }
+ else
+ p_sco->state = BTA_AG_SCO_SHUTTING_ST;
+
+ break;
+
+ case BTA_AG_SCO_CONN_OPEN_E:
+ /* close sco connection */
+ bta_ag_remove_sco(p_scb, TRUE);
+
+ p_sco->state = BTA_AG_SCO_CLOSING_ST;
+ break;
+
+ case BTA_AG_SCO_CONN_CLOSE_E:
+ /* sco failed; create sco listen connection */
+
+ p_sco->state = BTA_AG_SCO_LISTEN_ST;
+ break;
+
+ default:
+ APPL_TRACE_WARNING1("BTA_AG_SCO_OPEN_CL_ST: Ignoring event %d", event);
+ break;
+ }
+ break;
+
+ case BTA_AG_SCO_OPEN_XFER_ST:
+ switch (event)
+ {
+ case BTA_AG_SCO_CLOSE_E:
+ /* close sco connection */
+ bta_ag_remove_sco(p_scb, TRUE);
+
+ p_sco->state = BTA_AG_SCO_CLOSING_ST;
+ break;
+
+ case BTA_AG_SCO_SHUTDOWN_E:
+ /* remove all connection */
+ bta_ag_remove_sco(p_scb, FALSE);
+ p_sco->state = BTA_AG_SCO_SHUTTING_ST;
+
+ break;
+
+ case BTA_AG_SCO_CONN_CLOSE_E:
+ /* closed sco; place in listen mode and
+ accept the transferred connection */
+ bta_ag_create_sco(p_scb, FALSE); /* Back into listen mode */
+
+ /* Accept sco connection with xfer scb */
+ bta_ag_sco_conn_rsp(p_sco->p_xfer_scb, &p_sco->conn_data);
+ p_sco->state = BTA_AG_SCO_OPENING_ST;
+ p_sco->p_curr_scb = p_sco->p_xfer_scb;
+ p_sco->cur_idx = p_sco->p_xfer_scb->sco_idx;
+ p_sco->p_xfer_scb = NULL;
+ break;
+
+ default:
+ APPL_TRACE_WARNING1("BTA_AG_SCO_OPEN_XFER_ST: Ignoring event %d", event);
+ break;
+ }
+ break;
+
+ case BTA_AG_SCO_OPEN_ST:
+ switch (event)
+ {
+ case BTA_AG_SCO_LISTEN_E:
+ /* second headset has now joined */
+ /* create sco listen connection (Additional channel) */
+ if (p_scb != p_sco->p_curr_scb)
+ {
+ bta_ag_create_sco(p_scb, FALSE);
+ }
+ break;
+
+ case BTA_AG_SCO_XFER_E:
+ /* close current sco connection */
+ bta_ag_remove_sco(p_sco->p_curr_scb, TRUE);
+
+ /* save xfer scb */
+ p_sco->p_xfer_scb = p_scb;
+
+ p_sco->state = BTA_AG_SCO_CLOSE_XFER_ST;
+ break;
+
+ case BTA_AG_SCO_CLOSE_E:
+ /* close sco connection if active */
+ if (bta_ag_remove_sco(p_scb, TRUE))
+ {
+ p_sco->state = BTA_AG_SCO_CLOSING_ST;
+ }
+ break;
+
+ case BTA_AG_SCO_SHUTDOWN_E:
+ /* remove all listening connections */
+ bta_ag_remove_sco(p_scb, FALSE);
+
+ /* If SCO was active on this scb, close it */
+ if (p_scb == p_sco->p_curr_scb)
+ {
+ p_sco->state = BTA_AG_SCO_SHUTTING_ST;
+ }
+ break;
+
+ case BTA_AG_SCO_CONN_CLOSE_E:
+ /* peer closed sco; create sco listen connection */
+ bta_ag_create_sco(p_scb, FALSE);
+ p_sco->state = BTA_AG_SCO_LISTEN_ST;
+ break;
+
+ default:
+ APPL_TRACE_WARNING1("BTA_AG_SCO_OPEN_ST: Ignoring event %d", event);
+ break;
+ }
+ break;
+
+ case BTA_AG_SCO_CLOSING_ST:
+ switch (event)
+ {
+ case BTA_AG_SCO_LISTEN_E:
+ /* create sco listen connection (Additional channel) */
+ if (p_scb != p_sco->p_curr_scb)
+ {
+ bta_ag_create_sco(p_scb, FALSE);
+ }
+ break;
+
+ case BTA_AG_SCO_OPEN_E:
+ p_sco->state = BTA_AG_SCO_CLOSE_OP_ST;
+ break;
+
+ case BTA_AG_SCO_XFER_E:
+ /* save xfer scb */
+ p_sco->p_xfer_scb = p_scb;
+
+ p_sco->state = BTA_AG_SCO_CLOSE_XFER_ST;
+ break;
+
+ case BTA_AG_SCO_SHUTDOWN_E:
+ /* If not closing scb, just close it */
+ if (p_scb != p_sco->p_curr_scb)
+ {
+ /* remove listening connection */
+ bta_ag_remove_sco(p_scb, FALSE);
+ }
+ else
+ p_sco->state = BTA_AG_SCO_SHUTTING_ST;
+
+ break;
+
+ case BTA_AG_SCO_CONN_CLOSE_E:
+ /* peer closed sco; create sco listen connection */
+ bta_ag_create_sco(p_scb, FALSE);
+
+ p_sco->state = BTA_AG_SCO_LISTEN_ST;
+ break;
+
+ default:
+ APPL_TRACE_WARNING1("BTA_AG_SCO_CLOSING_ST: Ignoring event %d", event);
+ break;
+ }
+ break;
+
+ case BTA_AG_SCO_CLOSE_OP_ST:
+ switch (event)
+ {
+ case BTA_AG_SCO_CLOSE_E:
+ p_sco->state = BTA_AG_SCO_CLOSING_ST;
+ break;
+
+ case BTA_AG_SCO_SHUTDOWN_E:
+ p_sco->state = BTA_AG_SCO_SHUTTING_ST;
+ break;
+
+ case BTA_AG_SCO_CONN_CLOSE_E:
+#if (BTM_WBS_INCLUDED == TRUE )
+ /* start codec negotiation */
+ p_sco->state = BTA_AG_SCO_CODEC_ST;
+ p_cn_scb = p_scb;
+#else
+ /* open sco connection */
+ bta_ag_create_sco(p_scb, TRUE);
+ p_sco->state = BTA_AG_SCO_OPENING_ST;
+#endif
+ break;
+
+ case BTA_AG_SCO_LISTEN_E:
+ /* create sco listen connection (Additional channel) */
+ if (p_scb != p_sco->p_curr_scb)
+ {
+ bta_ag_create_sco(p_scb, FALSE);
+ }
+ break;
+
+ default:
+ APPL_TRACE_WARNING1("BTA_AG_SCO_CLOSE_OP_ST: Ignoring event %d", event);
+ break;
+ }
+ break;
+
+ case BTA_AG_SCO_CLOSE_XFER_ST:
+ switch (event)
+ {
+ case BTA_AG_SCO_CONN_OPEN_E:
+ /* close sco connection so headset can be transferred
+ Probably entered this state from "opening state" */
+ bta_ag_remove_sco(p_scb, TRUE);
+ break;
+
+ case BTA_AG_SCO_CLOSE_E:
+ /* clear xfer scb */
+ p_sco->p_xfer_scb = NULL;
+
+ p_sco->state = BTA_AG_SCO_CLOSING_ST;
+ break;
+
+ case BTA_AG_SCO_SHUTDOWN_E:
+ /* clear xfer scb */
+ p_sco->p_xfer_scb = NULL;
+
+ p_sco->state = BTA_AG_SCO_SHUTTING_ST;
+ break;
+
+ case BTA_AG_SCO_CONN_CLOSE_E:
+ /* closed sco; place old sco in listen mode,
+ take current sco out of listen, and
+ create originating sco for current */
+ bta_ag_create_sco(p_scb, FALSE);
+ bta_ag_remove_sco(p_sco->p_xfer_scb, FALSE);
+
+#if (BTM_WBS_INCLUDED == TRUE )
+ /* start codec negotiation */
+ p_sco->state = BTA_AG_SCO_CODEC_ST;
+ p_cn_scb = p_sco->p_xfer_scb;
+ p_sco->p_xfer_scb = NULL;
+#else
+ /* create sco connection to peer */
+ bta_ag_create_sco(p_sco->p_xfer_scb, TRUE);
+ p_sco->p_xfer_scb = NULL;
+ p_sco->state = BTA_AG_SCO_OPENING_ST;
+#endif
+ break;
+
+ default:
+ APPL_TRACE_WARNING1("BTA_AG_SCO_CLOSE_XFER_ST: Ignoring event %d", event);
+ break;
+ }
+ break;
+
+ case BTA_AG_SCO_SHUTTING_ST:
+ switch (event)
+ {
+ case BTA_AG_SCO_CONN_OPEN_E:
+ /* close sco connection; wait for conn close event */
+ bta_ag_remove_sco(p_scb, TRUE);
+ break;
+
+ case BTA_AG_SCO_CONN_CLOSE_E:
+ /* If last SCO instance then finish shutting down */
+ if (!bta_ag_other_scb_open(p_scb))
+ {
+ p_sco->state = BTA_AG_SCO_SHUTDOWN_ST;
+ }
+ else /* Other instance is still listening */
+ {
+ p_sco->state = BTA_AG_SCO_LISTEN_ST;
+ }
+
+ if (p_scb == p_sco->p_curr_scb)
+ {
+ p_sco->p_curr_scb->sco_idx = BTM_INVALID_SCO_INDEX;
+ p_sco->p_curr_scb = NULL;
+ }
+ break;
+
+ case BTA_AG_SCO_LISTEN_E:
+ /* create sco listen connection (Additional channel) */
+ if (p_scb != p_sco->p_curr_scb)
+ {
+ bta_ag_create_sco(p_scb, FALSE);
+ }
+ break;
+
+ case BTA_AG_SCO_SHUTDOWN_E:
+ if (!bta_ag_other_scb_open(p_scb))
+ {
+ p_sco->state = BTA_AG_SCO_SHUTDOWN_ST;
+ }
+ else /* Other instance is still listening */
+ {
+ p_sco->state = BTA_AG_SCO_LISTEN_ST;
+ }
+
+ if (p_scb == p_sco->p_curr_scb)
+ {
+ p_sco->p_curr_scb->sco_idx = BTM_INVALID_SCO_INDEX;
+ p_sco->p_curr_scb = NULL;
+ }
+ break;
+
+ default:
+ APPL_TRACE_WARNING1("BTA_AG_SCO_SHUTTING_ST: Ignoring event %d", event);
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+#if BTA_AG_SCO_DEBUG == TRUE
+ if (p_sco->state != in_state)
+ {
+ APPL_TRACE_EVENT3("BTA AG SCO State Change: [%s] -> [%s] after Event [%s]",
+ bta_ag_sco_state_str(in_state),
+ bta_ag_sco_state_str(p_sco->state),
+ bta_ag_sco_evt_str(event));
+ }
+#endif
+
+#if (BTM_WBS_INCLUDED == TRUE )
+ if (p_cn_scb)
+ {
+ bta_ag_codec_negotiate(p_cn_scb);
+ }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_sco_is_open
+**
+** Description Check if sco is open for this scb.
+**
+**
+** Returns TRUE if sco open for this scb, FALSE otherwise.
+**
+*******************************************************************************/
+BOOLEAN bta_ag_sco_is_open(tBTA_AG_SCB *p_scb)
+{
+ return ((bta_ag_cb.sco.state == BTA_AG_SCO_OPEN_ST) &&
+ (bta_ag_cb.sco.p_curr_scb == p_scb));
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_sco_is_opening
+**
+** Description Check if sco is in Opening state.
+**
+**
+** Returns TRUE if sco is in Opening state for this scb, FALSE otherwise.
+**
+*******************************************************************************/
+BOOLEAN bta_ag_sco_is_opening(tBTA_AG_SCB *p_scb)
+{
+#if (BTM_WBS_INCLUDED == TRUE )
+ return (((bta_ag_cb.sco.state == BTA_AG_SCO_OPENING_ST) ||
+ (bta_ag_cb.sco.state == BTA_AG_SCO_OPENING_ST)) &&
+ (bta_ag_cb.sco.p_curr_scb == p_scb));
+#else
+ return ((bta_ag_cb.sco.state == BTA_AG_SCO_OPENING_ST) &&
+ (bta_ag_cb.sco.p_curr_scb == p_scb));
+#endif
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_sco_listen
+**
+** Description
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_sco_listen(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ bta_ag_sco_event(p_scb, BTA_AG_SCO_LISTEN_E);
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_sco_open
+**
+** Description
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_sco_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ UINT8 event;
+
+ /* if another scb using sco, this is a transfer */
+ if (bta_ag_cb.sco.p_curr_scb != NULL && bta_ag_cb.sco.p_curr_scb != p_scb)
+ {
+ event = BTA_AG_SCO_XFER_E;
+ }
+ /* else it is an open */
+ else
+ {
+ event = BTA_AG_SCO_OPEN_E;
+ }
+
+ bta_ag_sco_event(p_scb, event);
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_sco_close
+**
+** Description
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_sco_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ /* if scb is in use */
+#if (BTM_WBS_INCLUDED == TRUE )
+ /* sco_idx is not allocated in SCO_CODEC_ST, we still need to move to listening state. */
+ if ((p_scb->sco_idx != BTM_INVALID_SCO_INDEX) || (bta_ag_cb.sco.state == BTA_AG_SCO_CODEC_ST))
+#else
+ if (p_scb->sco_idx != BTM_INVALID_SCO_INDEX)
+#endif
+ {
+ APPL_TRACE_DEBUG1("bta_ag_sco_close: sco_inx = %d", p_scb->sco_idx);
+ bta_ag_sco_event(p_scb, BTA_AG_SCO_CLOSE_E);
+ }
+}
+
+#if (BTM_WBS_INCLUDED == TRUE )
+
+/*******************************************************************************
+**
+** Function bta_ag_sco_codec_nego
+**
+** Description
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_sco_codec_nego(tBTA_AG_SCB *p_scb, BOOLEAN result)
+{
+ if(result == TRUE)
+ {
+ /* Subsequent sco connection will skip codec negotiation */
+ p_scb->codec_updated = FALSE;
+
+ bta_ag_sco_event(p_scb, BTA_AG_SCO_CN_DONE_E);
+ }
+ else /* codec negotiation failed */
+ bta_ag_sco_event(p_scb, BTA_AG_SCO_CLOSE_E);
+}
+#endif
+
+/*******************************************************************************
+**
+** Function bta_ag_sco_shutdown
+**
+** Description
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_sco_shutdown(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ bta_ag_sco_event(p_scb, BTA_AG_SCO_SHUTDOWN_E);
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_sco_conn_open
+**
+** Description
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_sco_conn_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ bta_ag_sco_event(p_scb, BTA_AG_SCO_CONN_OPEN_E);
+
+ bta_sys_sco_open(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+
+ bta_ag_co_audio_state(bta_ag_scb_to_idx(p_scb), p_scb->app_id, BTA_AG_CO_AUD_STATE_ON);
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+ /* open SCO codec if SCO is routed through transport */
+ bta_dm_sco_co_open(bta_ag_scb_to_idx(p_scb), BTA_SCO_OUT_PKT_SIZE, BTA_AG_CI_SCO_DATA_EVT);
+#endif
+
+ /* call app callback */
+ bta_ag_cback_sco(p_scb, BTA_AG_AUDIO_OPEN_EVT);
+
+ p_scb->retry_with_sco_only = FALSE;
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_sco_conn_close
+**
+** Description
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_sco_conn_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ UINT16 handle = bta_ag_scb_to_idx(p_scb);
+
+ /* clear current scb */
+ bta_ag_cb.sco.p_curr_scb = NULL;
+ p_scb->sco_idx = BTM_INVALID_SCO_INDEX;
+
+#if (BTM_WBS_INCLUDED == TRUE)
+ /* codec_fallback is set when AG is initiator and connection failed for mSBC. */
+ if (p_scb->codec_fallback && p_scb->svc_conn)
+ {
+ bta_ag_sco_event(p_scb, BTA_AG_SCO_REOPEN_E);
+ }
+ else if (p_scb->retry_with_sco_only && p_scb->svc_conn)
+ {
+ /* retry_with_sco_only is set when AG is initiator and connection failed for eSCO */
+ bta_ag_create_sco(p_scb, TRUE);
+ }
+#else
+ /* retry_with_sco_only, will be set only when AG is initiator
+ ** and AG is first trying to establish an eSCO connection */
+ if (p_scb->retry_with_sco_only && p_scb->svc_conn)
+ {
+ bta_ag_create_sco(p_scb, TRUE);
+ }
+#endif
+ else
+ {
+ /* Indicate if the closing of audio is because of transfer */
+ if (bta_ag_cb.sco.p_xfer_scb)
+ bta_ag_co_audio_state(handle, p_scb->app_id, BTA_AG_CO_AUD_STATE_OFF_XFER);
+ else
+ bta_ag_co_audio_state(handle, p_scb->app_id, BTA_AG_CO_AUD_STATE_OFF);
+
+ bta_ag_sco_event(p_scb, BTA_AG_SCO_CONN_CLOSE_E);
+
+ bta_sys_sco_close(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+
+ /* if av got suspended by this call, let it resume. */
+ /* In case call stays alive regardless of sco, av should not be affected. */
+ if(((p_scb->call_ind == BTA_AG_CALL_INACTIVE) && (p_scb->callsetup_ind == BTA_AG_CALLSETUP_NONE))
+ || (p_scb->post_sco == BTA_AG_POST_SCO_CALL_END))
+ {
+ bta_sys_sco_unuse(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+ }
+
+ /* call app callback */
+ bta_ag_cback_sco(p_scb, BTA_AG_AUDIO_CLOSE_EVT);
+ }
+ p_scb->retry_with_sco_only = FALSE;
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_sco_conn_rsp
+**
+** Description Process the SCO connection request
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_sco_conn_rsp(tBTA_AG_SCB *p_scb, tBTM_ESCO_CONN_REQ_EVT_DATA *p_data)
+{
+ tBTM_ESCO_PARAMS resp;
+ UINT8 hci_status = HCI_SUCCESS;
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+ tBTA_CODEC_INFO codec_info = {BTA_SCO_CODEC_PCM};
+ UINT32 pcm_sample_rate;
+#endif
+
+ if (bta_ag_cb.sco.state == BTA_AG_SCO_LISTEN_ST ||
+ bta_ag_cb.sco.state == BTA_AG_SCO_CLOSE_XFER_ST ||
+ bta_ag_cb.sco.state == BTA_AG_SCO_OPEN_XFER_ST)
+ {
+ /* If script overrided sco parameter by BTA_CMD_SET_ESCO_PARAM */
+ if (bta_ag_cb.sco.param_updated)
+ {
+ resp = bta_ag_cb.sco.params;
+ }
+ else
+ {
+ resp.rx_bw = BTM_64KBITS_RATE;
+ resp.tx_bw = BTM_64KBITS_RATE;
+ resp.max_latency = 10;
+ resp.voice_contfmt = 0x60;
+ resp.retrans_effort = BTM_ESCO_RETRANS_POWER;
+
+ if (p_data->link_type == BTM_LINK_TYPE_SCO)
+ {
+ resp.packet_types = (BTM_SCO_LINK_ONLY_MASK |
+ BTM_SCO_PKT_TYPES_MASK_NO_2_EV3 |
+ BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 |
+ BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 |
+ BTM_SCO_PKT_TYPES_MASK_NO_3_EV5);
+ }
+ else /* Allow controller to use all types available except 5-slot EDR */
+ {
+ resp.packet_types = (BTM_SCO_LINK_ALL_PKT_MASK |
+ BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 |
+ BTM_SCO_PKT_TYPES_MASK_NO_3_EV5);
+ }
+ }
+
+ /* tell sys to stop av if any */
+ bta_sys_sco_use(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+
+ /* Allow any platform specific pre-SCO set up to take place */
+ bta_ag_co_audio_state(bta_ag_scb_to_idx(p_scb), p_scb->app_id, BTA_AG_CO_AUD_STATE_SETUP);
+
+#if (BTM_WBS_INCLUDED == TRUE )
+ /* When HS initiated SCO, it cannot be WBS. */
+ BTM_ConfigI2SPCM (BTM_SCO_CODEC_CVSD, (UINT8)HCI_BRCM_I2SPCM_IS_DEFAULT_ROLE, (UINT8)HCI_BRCM_I2SPCM_SAMPLE_DEFAULT, (UINT8)HCI_BRCM_I2SPCM_CLOCK_DEFAULT);
+#endif
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+ pcm_sample_rate = BTA_DM_SCO_SAMP_RATE_8K;
+
+ /* initialize SCO setup, no voice setting for AG, data rate <==> sample rate */
+ BTM_ConfigScoPath(bta_dm_sco_co_init(pcm_sample_rate, pcm_sample_rate, &codec_info, p_scb->app_id),
+ bta_ag_sco_read_cback, NULL, TRUE);
+#endif
+ }
+ else
+ hci_status = HCI_ERR_HOST_REJECT_DEVICE;
+
+#if (BTM_WBS_INCLUDED == TRUE )
+ /* If SCO open was initiated from HS, it must be CVSD */
+ p_scb->inuse_codec = BTA_AG_CODEC_NONE;
+#endif
+
+ BTM_EScoConnRsp(p_data->sco_inx, hci_status, &resp);
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_ci_sco_data
+**
+** Description Process the SCO data ready callin event
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_ci_sco_data(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+ bta_ag_sco_event(p_scb, BTA_AG_SCO_CI_DATA_E);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_set_esco_param
+**
+** Description Update esco parameters from script wrapper.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_set_esco_param(BOOLEAN set_reset, tBTM_ESCO_PARAMS *param)
+{
+ if(set_reset == FALSE) /* reset the parameters to default */
+ {
+ bta_ag_cb.sco.param_updated = FALSE;
+ APPL_TRACE_DEBUG0("bta_ag_set_esco_param : Resetting ESCO parameters to default");
+ }
+ else
+ {
+ bta_ag_cb.sco.param_updated = TRUE;
+ bta_ag_cb.sco.params = *param;
+ APPL_TRACE_DEBUG0("bta_ag_set_esco_param : Setting ESCO parameters");
+ }
+}
+
+/*******************************************************************************
+** Debugging functions
+*******************************************************************************/
+
+#if BTA_AG_SCO_DEBUG == TRUE
+static char *bta_ag_sco_evt_str(UINT8 event)
+{
+ switch (event)
+ {
+ case BTA_AG_SCO_LISTEN_E:
+ return "Listen Request";
+ case BTA_AG_SCO_OPEN_E:
+ return "Open Request";
+ case BTA_AG_SCO_XFER_E:
+ return "Transfer Request";
+#if (BTM_WBS_INCLUDED == TRUE )
+ case BTA_AG_SCO_CN_DONE_E:
+ return "Codec Negotiation Done";
+ case BTA_AG_SCO_REOPEN_E:
+ return "Reopen Request";
+#endif
+ case BTA_AG_SCO_CLOSE_E:
+ return "Close Request";
+ case BTA_AG_SCO_SHUTDOWN_E:
+ return "Shutdown Request";
+ case BTA_AG_SCO_CONN_OPEN_E:
+ return "Opened";
+ case BTA_AG_SCO_CONN_CLOSE_E:
+ return "Closed";
+ case BTA_AG_SCO_CI_DATA_E :
+ return "Sco Data";
+ default:
+ return "Unknown SCO Event";
+ }
+}
+
+static char *bta_ag_sco_state_str(UINT8 state)
+{
+ switch (state)
+ {
+ case BTA_AG_SCO_SHUTDOWN_ST:
+ return "Shutdown";
+ case BTA_AG_SCO_LISTEN_ST:
+ return "Listening";
+#if (BTM_WBS_INCLUDED == TRUE )
+ case BTA_AG_SCO_CODEC_ST:
+ return "Codec Negotiation";
+#endif
+ case BTA_AG_SCO_OPENING_ST:
+ return "Opening";
+ case BTA_AG_SCO_OPEN_CL_ST:
+ return "Open while closing";
+ case BTA_AG_SCO_OPEN_XFER_ST:
+ return "Opening while Transferring";
+ case BTA_AG_SCO_OPEN_ST:
+ return "Open";
+ case BTA_AG_SCO_CLOSING_ST:
+ return "Closing";
+ case BTA_AG_SCO_CLOSE_OP_ST:
+ return "Close while Opening";
+ case BTA_AG_SCO_CLOSE_XFER_ST:
+ return "Close while Transferring";
+ case BTA_AG_SCO_SHUTTING_ST:
+ return "Shutting Down";
+ default:
+ return "Unknown SCO State";
+ }
+}
+
+#endif
diff --git a/bta/ag/bta_ag_sdp.c b/bta/ag/bta_ag_sdp.c
new file mode 100644
index 0000000..a8e06cb
--- /dev/null
+++ b/bta/ag/bta_ag_sdp.c
@@ -0,0 +1,491 @@
+/*****************************************************************************
+**
+** Name: bta_ag_sdp.c
+**
+** Description: This file contains the audio gateway functions
+** performing SDP operations.
+**
+** Copyright (c) 2003-2005, Broadcom Corp., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include <string.h>
+#include "bta_api.h"
+#include "bta_sys.h"
+#include "bta_ag_api.h"
+#include "bta_ag_int.h"
+#include "sdp_api.h"
+#include "btm_api.h"
+#include "gki.h"
+
+/* Number of protocol elements in protocol element list. */
+#define BTA_AG_NUM_PROTO_ELEMS 2
+
+/* Number of elements in service class id list. */
+#define BTA_AG_NUM_SVC_ELEMS 2
+
+/* size of database for service discovery */
+#ifndef BTA_AG_DISC_BUF_SIZE
+#define BTA_AG_DISC_BUF_SIZE GKI_MAX_BUF_SIZE
+#endif
+
+/* declare sdp callback functions */
+void bta_ag_sdp_cback_1(UINT16 status);
+void bta_ag_sdp_cback_2(UINT16 status);
+void bta_ag_sdp_cback_3(UINT16 status);
+
+/* SDP callback function table */
+typedef tSDP_DISC_CMPL_CB *tBTA_AG_SDP_CBACK;
+const tBTA_AG_SDP_CBACK bta_ag_sdp_cback_tbl[] =
+{
+ bta_ag_sdp_cback_1,
+ bta_ag_sdp_cback_2,
+ bta_ag_sdp_cback_3
+};
+
+/*******************************************************************************
+**
+** Function bta_ag_sdp_cback
+**
+** Description SDP callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ag_sdp_cback(UINT16 status, UINT8 idx)
+{
+ tBTA_AG_DISC_RESULT *p_buf;
+ UINT16 event;
+ tBTA_AG_SCB *p_scb;
+
+ APPL_TRACE_DEBUG1("bta_ag_sdp_cback status:0x%x", status);
+
+ if ((p_scb = bta_ag_scb_by_idx(idx)) != NULL)
+ {
+ /* set event according to int/acp */
+ if (p_scb->role == BTA_AG_ACP)
+ {
+ event = BTA_AG_DISC_ACP_RES_EVT;
+ }
+ else
+ {
+ event = BTA_AG_DISC_INT_RES_EVT;
+ }
+
+ if ((p_buf = (tBTA_AG_DISC_RESULT *) GKI_getbuf(sizeof(tBTA_AG_DISC_RESULT))) != NULL)
+ {
+ p_buf->hdr.event = event;
+ p_buf->hdr.layer_specific = idx;
+ p_buf->status = status;
+ bta_sys_sendmsg(p_buf);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_sdp_cback_1 to 3
+**
+** Description SDP callback functions. Since there is no way to
+** distinguish scb from the callback we need separate
+** callbacks for each scb.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_sdp_cback_1(UINT16 status) {bta_ag_sdp_cback(status, 1);}
+void bta_ag_sdp_cback_2(UINT16 status) {bta_ag_sdp_cback(status, 2);}
+void bta_ag_sdp_cback_3(UINT16 status) {bta_ag_sdp_cback(status, 3);}
+
+/******************************************************************************
+**
+** Function bta_ag_add_record
+**
+** Description This function is called by a server application to add
+** HSP or HFP information to an SDP record. Prior to
+** calling this function the application must call
+** SDP_CreateRecord() to create an SDP record.
+**
+** Returns TRUE if function execution succeeded,
+** FALSE if function execution failed.
+**
+******************************************************************************/
+BOOLEAN bta_ag_add_record(UINT16 service_uuid, char *p_service_name, UINT8 scn,
+ tBTA_AG_FEAT features, UINT32 sdp_handle)
+{
+ tSDP_PROTOCOL_ELEM proto_elem_list[BTA_AG_NUM_PROTO_ELEMS];
+ UINT16 svc_class_id_list[BTA_AG_NUM_SVC_ELEMS];
+ UINT16 browse_list[] = {UUID_SERVCLASS_PUBLIC_BROWSE_GROUP};
+ UINT16 version;
+ UINT16 profile_uuid;
+ UINT8 network;
+ BOOLEAN result = TRUE;
+ BOOLEAN codec_supported = FALSE;
+ UINT8 buf[2];
+
+ APPL_TRACE_DEBUG1("bta_ag_add_record uuid: %x", service_uuid);
+
+ memset( proto_elem_list, 0 , BTA_AG_NUM_PROTO_ELEMS*sizeof(tSDP_PROTOCOL_ELEM));
+
+ /* add the protocol element sequence */
+ proto_elem_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+ proto_elem_list[0].num_params = 0;
+ proto_elem_list[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
+ proto_elem_list[1].num_params = 1;
+ proto_elem_list[1].params[0] = scn;
+ result &= SDP_AddProtocolList(sdp_handle, BTA_AG_NUM_PROTO_ELEMS, proto_elem_list);
+
+ /* add service class id list */
+ svc_class_id_list[0] = service_uuid;
+ svc_class_id_list[1] = UUID_SERVCLASS_GENERIC_AUDIO;
+ result &= SDP_AddServiceClassIdList(sdp_handle, BTA_AG_NUM_SVC_ELEMS, svc_class_id_list);
+
+ /* add profile descriptor list */
+ if (service_uuid == UUID_SERVCLASS_AG_HANDSFREE)
+ {
+ profile_uuid = UUID_SERVCLASS_HF_HANDSFREE;
+#if (BTM_WBS_INCLUDED == TRUE )
+ version = HFP_VERSION_1_6;
+#else
+ version = HFP_VERSION_1_5;
+#endif
+ }
+ else
+ {
+ profile_uuid = UUID_SERVCLASS_HEADSET;
+ version = HSP_VERSION_1_2;
+ }
+ result &= SDP_AddProfileDescriptorList(sdp_handle, profile_uuid, version);
+
+ /* add service name */
+ if (p_service_name != NULL && p_service_name[0] != 0)
+ {
+ result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE,
+ (UINT32)(strlen(p_service_name)+1), (UINT8 *) p_service_name);
+ }
+
+ /* add features and network */
+ if (service_uuid == UUID_SERVCLASS_AG_HANDSFREE)
+ {
+ network = (features & BTA_AG_FEAT_REJECT) ? 1 : 0;
+ result &= SDP_AddAttribute(sdp_handle, ATTR_ID_DATA_STORES_OR_NETWORK,
+ UINT_DESC_TYPE, 1, &network);
+
+ if (features & BTA_AG_FEAT_CODEC)
+ codec_supported = TRUE;
+
+ features &= BTA_AG_SDP_FEAT_SPEC;
+
+ /* Codec bit position is different in SDP and in BRSF */
+ if (codec_supported)
+ features |= 0x0020;
+
+ UINT16_TO_BE_FIELD(buf, features);
+ result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SUPPORTED_FEATURES, UINT_DESC_TYPE, 2, buf);
+ }
+
+ /* add browse group list */
+ result &= SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, browse_list);
+
+ return result;
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_create_records
+**
+** Description Create SDP records for registered services.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_create_records(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ int i;
+ tBTA_SERVICE_MASK services;
+
+ services = p_scb->reg_services >> BTA_HSP_SERVICE_ID;
+ for (i = 0; i < BTA_AG_NUM_IDX && services != 0; i++, services >>= 1)
+ {
+ /* if service is set in mask */
+ if (services & 1)
+ {
+ /* add sdp record if not already registered */
+ if (bta_ag_cb.profile[i].sdp_handle == 0)
+ {
+ bta_ag_cb.profile[i].sdp_handle = SDP_CreateRecord();
+ bta_ag_cb.profile[i].scn = BTM_AllocateSCN();
+ bta_ag_add_record(bta_ag_uuid[i], p_data->api_register.p_name[i],
+ bta_ag_cb.profile[i].scn, p_data->api_register.features,
+ bta_ag_cb.profile[i].sdp_handle);
+ bta_sys_add_uuid(bta_ag_uuid[i]);
+ }
+ }
+ }
+
+ p_scb->hsp_version = HSP_VERSION_1_2;
+
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_del_records
+**
+** Description Delete SDP records for any registered services.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_del_records(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ tBTA_AG_SCB *p = &bta_ag_cb.scb[0];
+ tBTA_SERVICE_MASK services;
+ tBTA_SERVICE_MASK others = 0;
+ int i;
+
+ /* get services of all other registered servers */
+ for (i = 0; i < BTA_AG_NUM_IDX; i++, p++)
+ {
+ if (p_scb == p)
+ {
+ continue;
+ }
+
+ if (p->in_use && p->dealloc == FALSE)
+ {
+ others |= p->reg_services;
+ }
+ }
+
+ others >>= BTA_HSP_SERVICE_ID;
+ services = p_scb->reg_services >> BTA_HSP_SERVICE_ID;
+ for (i = 0; i < BTA_AG_NUM_IDX && services != 0; i++, services >>= 1, others >>= 1)
+ {
+ /* if service registered for this scb and not registered for any other scb */
+ if (((services & 1) == 1) && ((others & 1) == 0))
+ {
+ APPL_TRACE_DEBUG1("bta_ag_del_records %d", i);
+ if (bta_ag_cb.profile[i].sdp_handle != 0)
+ {
+ SDP_DeleteRecord(bta_ag_cb.profile[i].sdp_handle);
+ bta_ag_cb.profile[i].sdp_handle = 0;
+ }
+ BTM_FreeSCN(bta_ag_cb.profile[i].scn);
+ BTM_SecClrService(bta_ag_sec_id[i]);
+ bta_sys_remove_uuid(bta_ag_uuid[i]);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_sdp_find_attr
+**
+** Description Process SDP discovery results to find requested attributes
+** for requested service.
+**
+**
+** Returns TRUE if results found, FALSE otherwise.
+**
+*******************************************************************************/
+BOOLEAN bta_ag_sdp_find_attr(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK service)
+{
+ tSDP_DISC_REC *p_rec = NULL;
+ tSDP_DISC_ATTR *p_attr;
+ tSDP_PROTOCOL_ELEM pe;
+ UINT16 uuid;
+ BOOLEAN result = FALSE;
+
+ if (service & BTA_HFP_SERVICE_MASK)
+ {
+ uuid = UUID_SERVCLASS_HF_HANDSFREE;
+ p_scb->peer_version = HFP_VERSION_1_1; /* Default version */
+ }
+ else if (service & BTA_HSP_SERVICE_MASK && p_scb->role == BTA_AG_INT)
+ {
+ uuid = UUID_SERVCLASS_HEADSET_HS;
+ p_scb->peer_version = 0x0100; /* Default version */
+ }
+ else
+ {
+ return result;
+ }
+
+ /* loop through all records we found */
+ while (TRUE)
+ {
+ /* get next record; if none found, we're done */
+ if ((p_rec = SDP_FindServiceInDb(p_scb->p_disc_db, uuid, p_rec)) == NULL)
+ {
+ if (uuid == UUID_SERVCLASS_HEADSET_HS)
+ {
+ /* Search again in case the peer device is HSP v1.0 */
+ uuid = UUID_SERVCLASS_HEADSET;
+ if ((p_rec = SDP_FindServiceInDb(p_scb->p_disc_db, uuid, p_rec)) == NULL)
+ {
+ break;
+ }
+ }
+ else
+ break;
+ }
+
+ /* get scn from proto desc list if initiator */
+ if (p_scb->role == BTA_AG_INT)
+ {
+ if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe))
+ {
+ p_scb->peer_scn = (UINT8) pe.params[0];
+ }
+ else
+ {
+ continue;
+ }
+ }
+
+ /* get profile version (if failure, version parameter is not updated) */
+ SDP_FindProfileVersionInRec(p_rec, uuid, &p_scb->peer_version);
+
+ /* get features if HFP */
+ if (service & BTA_HFP_SERVICE_MASK)
+ {
+ if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SUPPORTED_FEATURES)) != NULL)
+ {
+ /* Found attribute. Get value. */
+ /* There might be race condition between SDP and BRSF. */
+ /* Do not update if we already received BRSF. */
+ if (p_scb->peer_features == 0)
+ p_scb->peer_features = p_attr->attr_value.v.u16;
+ }
+ }
+ else /* HSP */
+ {
+ if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_REMOTE_AUDIO_VOLUME_CONTROL)) != NULL)
+ {
+ /* Remote volume control of HSP */
+ if (p_attr->attr_value.v.u8)
+ p_scb->peer_features |= BTA_AG_PEER_FEAT_VOL;
+ else
+ p_scb->peer_features &= ~BTA_AG_PEER_FEAT_VOL;
+ }
+
+ }
+
+ /* found what we needed */
+ result = TRUE;
+ break;
+ }
+ return result;
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_do_disc
+**
+** Description Do service discovery.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_do_disc(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK service)
+{
+ tSDP_UUID uuid_list[2];
+ UINT16 num_uuid = 1;
+ UINT16 attr_list[4];
+ UINT8 num_attr;
+ BOOLEAN db_inited = FALSE;
+
+ /* HFP initiator; get proto list and features */
+ if (service & BTA_HFP_SERVICE_MASK && p_scb->role == BTA_AG_INT)
+ {
+ attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST;
+ attr_list[1] = ATTR_ID_PROTOCOL_DESC_LIST;
+ attr_list[2] = ATTR_ID_BT_PROFILE_DESC_LIST;
+ attr_list[3] = ATTR_ID_SUPPORTED_FEATURES;
+ num_attr = 4;
+ uuid_list[0].uu.uuid16 = UUID_SERVCLASS_HF_HANDSFREE;
+ }
+ /* HFP acceptor; get features */
+ else if (service & BTA_HFP_SERVICE_MASK && p_scb->role == BTA_AG_ACP)
+ {
+ attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST;
+ attr_list[1] = ATTR_ID_BT_PROFILE_DESC_LIST;
+ attr_list[2] = ATTR_ID_SUPPORTED_FEATURES;
+ num_attr = 3;
+ uuid_list[0].uu.uuid16 = UUID_SERVCLASS_HF_HANDSFREE;
+ }
+ /* HSP initiator; get proto list */
+ else if (service & BTA_HSP_SERVICE_MASK && p_scb->role == BTA_AG_INT)
+ {
+ attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST;
+ attr_list[1] = ATTR_ID_PROTOCOL_DESC_LIST;
+ attr_list[2] = ATTR_ID_BT_PROFILE_DESC_LIST;
+ attr_list[3] = ATTR_ID_REMOTE_AUDIO_VOLUME_CONTROL;
+ num_attr = 4;
+
+ uuid_list[0].uu.uuid16 = UUID_SERVCLASS_HEADSET; /* Legacy from HSP v1.0 */
+ if (p_scb->hsp_version >= HSP_VERSION_1_2)
+ {
+ uuid_list[1].uu.uuid16 = UUID_SERVCLASS_HEADSET_HS;
+ num_uuid = 2;
+ }
+ }
+ /* HSP acceptor; no discovery */
+ else
+ {
+ return;
+ }
+
+ /* allocate buffer for sdp database */
+ p_scb->p_disc_db = (tSDP_DISCOVERY_DB *) GKI_getbuf(BTA_AG_DISC_BUF_SIZE);
+
+ if(p_scb->p_disc_db)
+ {
+ /* set up service discovery database; attr happens to be attr_list len */
+ uuid_list[0].len = LEN_UUID_16;
+ uuid_list[1].len = LEN_UUID_16;
+ db_inited = SDP_InitDiscoveryDb(p_scb->p_disc_db, BTA_AG_DISC_BUF_SIZE, num_uuid,
+ uuid_list, num_attr, attr_list);
+ }
+
+ if(db_inited)
+ {
+ /*Service discovery not initiated */
+ db_inited = SDP_ServiceSearchAttributeRequest(p_scb->peer_addr, p_scb->p_disc_db,
+ bta_ag_sdp_cback_tbl[bta_ag_scb_to_idx(p_scb) - 1]);
+ }
+
+ if(!db_inited)
+ {
+ /*free discover db */
+ bta_ag_free_db(p_scb, NULL);
+ /* sent failed event */
+ bta_ag_sm_execute(p_scb, BTA_AG_DISC_FAIL_EVT, NULL);
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_free_db
+**
+** Description Free discovery database.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_free_db(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ if (p_scb->p_disc_db != NULL)
+ {
+ GKI_freebuf(p_scb->p_disc_db);
+ p_scb->p_disc_db = NULL;
+ }
+}
diff --git a/bta/av/bta_av_aact.c b/bta/av/bta_av_aact.c
new file mode 100644
index 0000000..aa154b3
--- /dev/null
+++ b/bta/av/bta_av_aact.c
@@ -0,0 +1,2688 @@
+/*****************************************************************************
+**
+** Name: bta_av_aact.c
+**
+** Description: This file contains action functions for
+** advanced audio/video stream state machine.
+** these functions are shared by both audio and video streams.
+**
+** Copyright (c) 2004-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+#if defined(AV_INCLUDED) && (AV_INCLUDED == TRUE)
+
+#include <string.h>
+#include "bta_av_int.h"
+#include "avdt_api.h"
+#include "bd.h"
+#include "utl.h"
+#include "l2c_api.h"
+#include "l2cdefs.h"
+#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
+#include "bta_ar_api.h"
+#endif
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+/* the delay time in milliseconds to start service discovery on AVRCP */
+#ifndef BTA_AV_RC_DISC_TIME_VAL
+#define BTA_AV_RC_DISC_TIME_VAL 3500
+#endif
+
+/* the timer in milliseconds to guard against link busy and AVDT_CloseReq failed to be sent */
+#ifndef BTA_AV_CLOSE_REQ_TIME_VAL
+#define BTA_AV_CLOSE_REQ_TIME_VAL 4000
+#endif
+
+/* number to retry on reconfigure failure - some headsets requirs this number to be more than 1 */
+#ifndef BTA_AV_RECONFIG_RETRY
+#define BTA_AV_RECONFIG_RETRY 6
+#endif
+
+/* state machine states */
+enum
+{
+ BTA_AV_INIT_SST,
+ BTA_AV_INCOMING_SST,
+ BTA_AV_OPENING_SST,
+ BTA_AV_OPEN_SST,
+ BTA_AV_RCFG_SST,
+ BTA_AV_CLOSING_SST
+};
+
+
+/* the call out functions for audio stream */
+const tBTA_AV_CO_FUNCTS bta_av_a2d_cos =
+{
+ bta_av_co_audio_init,
+ bta_av_co_audio_disc_res,
+ bta_av_co_audio_getconfig,
+ bta_av_co_audio_setconfig,
+ bta_av_co_audio_open,
+ bta_av_co_audio_close,
+ bta_av_co_audio_start,
+ bta_av_co_audio_stop,
+ bta_av_co_audio_src_data_path,
+ bta_av_co_audio_delay
+};
+
+/* ssm action functions for audio stream */
+const tBTA_AV_SACT bta_av_a2d_action[] =
+{
+ bta_av_do_disc_a2d, /* BTA_AV_DO_DISC */
+ bta_av_cleanup, /* BTA_AV_CLEANUP */
+ bta_av_free_sdb, /* BTA_AV_FREE_SDB */
+ bta_av_config_ind, /* BTA_AV_CONFIG_IND */
+ bta_av_disconnect_req, /* BTA_AV_DISCONNECT_REQ */
+ bta_av_security_req, /* BTA_AV_SECURITY_REQ */
+ bta_av_security_rsp, /* BTA_AV_SECURITY_RSP */
+ bta_av_setconfig_rsp, /* BTA_AV_SETCONFIG_RSP */
+ bta_av_st_rc_timer, /* BTA_AV_ST_RC_TIMER */
+ bta_av_str_opened, /* BTA_AV_STR_OPENED */
+ bta_av_security_ind, /* BTA_AV_SECURITY_IND */
+ bta_av_security_cfm, /* BTA_AV_SECURITY_CFM */
+ bta_av_do_close, /* BTA_AV_DO_CLOSE */
+ bta_av_connect_req, /* BTA_AV_CONNECT_REQ */
+ bta_av_sdp_failed, /* BTA_AV_SDP_FAILED */
+ bta_av_disc_results, /* BTA_AV_DISC_RESULTS */
+ bta_av_disc_res_as_acp, /* BTA_AV_DISC_RES_AS_ACP */
+ bta_av_open_failed, /* BTA_AV_OPEN_FAILED */
+ bta_av_getcap_results, /* BTA_AV_GETCAP_RESULTS */
+ bta_av_setconfig_rej, /* BTA_AV_SETCONFIG_REJ */
+ bta_av_discover_req, /* BTA_AV_DISCOVER_REQ */
+ bta_av_conn_failed, /* BTA_AV_CONN_FAILED */
+ bta_av_do_start, /* BTA_AV_DO_START */
+ bta_av_str_stopped, /* BTA_AV_STR_STOPPED */
+ bta_av_reconfig, /* BTA_AV_RECONFIG */
+ bta_av_data_path, /* BTA_AV_DATA_PATH */
+ bta_av_start_ok, /* BTA_AV_START_OK */
+ bta_av_start_failed, /* BTA_AV_START_FAILED */
+ bta_av_str_closed, /* BTA_AV_STR_CLOSED */
+ bta_av_clr_cong, /* BTA_AV_CLR_CONG */
+ bta_av_suspend_cfm, /* BTA_AV_SUSPEND_CFM */
+ bta_av_rcfg_str_ok, /* BTA_AV_RCFG_STR_OK */
+ bta_av_rcfg_failed, /* BTA_AV_RCFG_FAILED */
+ bta_av_rcfg_connect, /* BTA_AV_RCFG_CONNECT */
+ bta_av_rcfg_discntd, /* BTA_AV_RCFG_DISCNTD */
+ bta_av_suspend_cont, /* BTA_AV_SUSPEND_CONT */
+ bta_av_rcfg_cfm, /* BTA_AV_RCFG_CFM */
+ bta_av_rcfg_open, /* BTA_AV_RCFG_OPEN */
+ bta_av_security_rej, /* BTA_AV_SECURITY_REJ */
+ bta_av_open_rc, /* BTA_AV_OPEN_RC */
+ bta_av_chk_2nd_start, /* BTA_AV_CHK_2ND_START */
+ bta_av_save_caps, /* BTA_AV_SAVE_CAPS */
+ bta_av_set_use_rc, /* BTA_AV_SET_USE_RC */
+ bta_av_cco_close, /* BTA_AV_CCO_CLOSE */
+ bta_av_switch_role, /* BTA_AV_SWITCH_ROLE */
+ bta_av_role_res, /* BTA_AV_ROLE_RES */
+ bta_av_delay_co, /* BTA_AV_DELAY_CO */
+ bta_av_open_at_inc, /* BTA_AV_OPEN_AT_INC */
+ NULL
+};
+
+/* these tables translate AVDT events to SSM events */
+static const UINT16 bta_av_stream_evt_ok[] = {
+ BTA_AV_STR_DISC_OK_EVT, /* AVDT_DISCOVER_CFM_EVT */
+ BTA_AV_STR_GETCAP_OK_EVT, /* AVDT_GETCAP_CFM_EVT */
+ BTA_AV_STR_OPEN_OK_EVT, /* AVDT_OPEN_CFM_EVT */
+ BTA_AV_STR_OPEN_OK_EVT, /* AVDT_OPEN_IND_EVT */
+ BTA_AV_STR_CONFIG_IND_EVT, /* AVDT_CONFIG_IND_EVT */
+ BTA_AV_STR_START_OK_EVT, /* AVDT_START_CFM_EVT */
+ BTA_AV_STR_START_OK_EVT, /* AVDT_START_IND_EVT */
+ BTA_AV_STR_SUSPEND_CFM_EVT, /* AVDT_SUSPEND_CFM_EVT */
+ BTA_AV_STR_SUSPEND_CFM_EVT, /* AVDT_SUSPEND_IND_EVT */
+ BTA_AV_STR_CLOSE_EVT, /* AVDT_CLOSE_CFM_EVT */
+ BTA_AV_STR_CLOSE_EVT, /* AVDT_CLOSE_IND_EVT */
+ BTA_AV_STR_RECONFIG_CFM_EVT, /* AVDT_RECONFIG_CFM_EVT */
+ 0, /* AVDT_RECONFIG_IND_EVT */
+ BTA_AV_STR_SECURITY_CFM_EVT, /* AVDT_SECURITY_CFM_EVT */
+ BTA_AV_STR_SECURITY_IND_EVT, /* AVDT_SECURITY_IND_EVT */
+ BTA_AV_STR_WRITE_CFM_EVT, /* AVDT_WRITE_CFM_EVT */
+ BTA_AV_AVDT_CONNECT_EVT, /* AVDT_CONNECT_IND_EVT */
+ BTA_AV_AVDT_DISCONNECT_EVT, /* AVDT_DISCONNECT_IND_EVT */
+#if (AVDT_REPORTING == TRUE)
+ BTA_AV_AVDT_RPT_CONN_EVT, /* AVDT_REPORT_CONN_EVT */
+ BTA_AV_AVDT_RPT_CONN_EVT, /* AVDT_REPORT_DISCONN_EVT */
+#endif
+ BTA_AV_AVDT_DELAY_RPT_EVT, /* AVDT_DELAY_REPORT_EVT */
+ 0 /* AVDT_DELAY_REPORT_CFM_EVT */
+};
+
+static const UINT16 bta_av_stream_evt_fail[] = {
+ BTA_AV_STR_DISC_FAIL_EVT, /* AVDT_DISCOVER_CFM_EVT */
+ BTA_AV_STR_GETCAP_FAIL_EVT, /* AVDT_GETCAP_CFM_EVT */
+ BTA_AV_STR_OPEN_FAIL_EVT, /* AVDT_OPEN_CFM_EVT */
+ BTA_AV_STR_OPEN_OK_EVT, /* AVDT_OPEN_IND_EVT */
+ BTA_AV_STR_CONFIG_IND_EVT, /* AVDT_CONFIG_IND_EVT */
+ BTA_AV_STR_START_FAIL_EVT, /* AVDT_START_CFM_EVT */
+ BTA_AV_STR_START_OK_EVT, /* AVDT_START_IND_EVT */
+ BTA_AV_STR_SUSPEND_CFM_EVT, /* AVDT_SUSPEND_CFM_EVT */
+ BTA_AV_STR_SUSPEND_CFM_EVT, /* AVDT_SUSPEND_IND_EVT */
+ BTA_AV_STR_CLOSE_EVT, /* AVDT_CLOSE_CFM_EVT */
+ BTA_AV_STR_CLOSE_EVT, /* AVDT_CLOSE_IND_EVT */
+ BTA_AV_STR_RECONFIG_CFM_EVT, /* AVDT_RECONFIG_CFM_EVT */
+ 0, /* AVDT_RECONFIG_IND_EVT */
+ BTA_AV_STR_SECURITY_CFM_EVT, /* AVDT_SECURITY_CFM_EVT */
+ BTA_AV_STR_SECURITY_IND_EVT, /* AVDT_SECURITY_IND_EVT */
+ BTA_AV_STR_WRITE_CFM_EVT, /* AVDT_WRITE_CFM_EVT */
+ BTA_AV_AVDT_CONNECT_EVT, /* AVDT_CONNECT_IND_EVT */
+ BTA_AV_AVDT_DISCONNECT_EVT, /* AVDT_DISCONNECT_IND_EVT */
+#if (AVDT_REPORTING == TRUE)
+ BTA_AV_AVDT_RPT_CONN_EVT, /* AVDT_REPORT_CONN_EVT */
+ BTA_AV_AVDT_RPT_CONN_EVT, /* AVDT_REPORT_DISCONN_EVT */
+#endif
+ BTA_AV_AVDT_DELAY_RPT_EVT, /* AVDT_DELAY_REPORT_EVT */
+ 0 /* AVDT_DELAY_REPORT_CFM_EVT */
+};
+
+static void bta_av_stream0_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data);
+static void bta_av_stream1_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data);
+#if BTA_AV_NUM_STRS > 2
+static void bta_av_stream2_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data);
+#endif
+#if BTA_AV_NUM_STRS > 3
+static void bta_av_stream3_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data);
+#endif
+#if BTA_AV_NUM_STRS > 4
+static void bta_av_stream4_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data);
+#endif
+#if BTA_AV_NUM_STRS > 5
+static void bta_av_stream5_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data);
+#endif
+/* the array of callback functions to receive events from AVDT control channel */
+tAVDT_CTRL_CBACK * const bta_av_dt_cback[] =
+{
+ bta_av_stream0_cback
+ ,bta_av_stream1_cback
+#if BTA_AV_NUM_STRS > 2
+ ,bta_av_stream2_cback
+#endif
+#if BTA_AV_NUM_STRS > 3
+ ,bta_av_stream3_cback
+#endif
+#if BTA_AV_NUM_STRS > 4
+ ,bta_av_stream4_cback
+#endif
+#if BTA_AV_NUM_STRS > 5
+ ,bta_av_stream5_cback
+#endif
+};
+
+/*******************************************************************************
+**
+** Function bta_av_save_addr
+**
+** Description copy the bd_addr and maybe reset the supported flags
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_av_save_addr(tBTA_AV_SCB *p_scb, const BD_ADDR b)
+{
+ APPL_TRACE_DEBUG2("bta_av_save_addr r:%d, s:%d",
+ p_scb->recfg_sup, p_scb->suspend_sup);
+ if(bdcmp(p_scb->peer_addr, b) != 0)
+ {
+ APPL_TRACE_ERROR0("reset flags");
+ /* a new addr, reset the supported flags */
+ p_scb->recfg_sup = TRUE;
+ p_scb->suspend_sup = TRUE;
+ }
+
+ /* do this copy anyway, just in case the first addr matches
+ * the control block one by accident */
+ bdcpy(p_scb->peer_addr, b);
+}
+
+/*******************************************************************************
+**
+** Function bta_av_st_rc_timer
+**
+** Description start the AVRC timer if no RC connection & CT is supported &
+** RC is used or
+** as ACP (we do not really know if we want AVRC)
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_st_rc_timer(tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+
+ APPL_TRACE_DEBUG2("bta_av_st_rc_timer rc_handle:%d, use_rc: %d",
+ p_scb->rc_handle, p_scb->use_rc);
+ /* for outgoing RC connection as INT/CT */
+ if( (p_scb->rc_handle == BTA_AV_RC_HANDLE_NONE) &&
+ /*(bta_av_cb.features & BTA_AV_FEAT_RCCT) &&*/
+ (p_scb->use_rc == TRUE || (p_scb->role & BTA_AV_ROLE_AD_ACP)) )
+ {
+ if ((p_scb->wait & BTA_AV_WAIT_ROLE_SW_BITS) == 0)
+ bta_sys_start_timer(&p_scb->timer, BTA_AV_AVRC_TIMER_EVT, BTA_AV_RC_DISC_TIME_VAL);
+ else
+ p_scb->wait |= BTA_AV_WAIT_CHECK_RC;
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function bta_av_next_getcap
+**
+** Description The function gets the capabilities of the next available
+** stream found in the discovery results.
+**
+** Returns TRUE if we sent request to AVDT, FALSE otherwise.
+**
+*******************************************************************************/
+static BOOLEAN bta_av_next_getcap(tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+ int i;
+ tAVDT_GETCAP_REQ *p_req;
+ BOOLEAN sent_cmd = FALSE;
+
+ for (i = p_scb->sep_info_idx; i < p_scb->num_seps; i++)
+ {
+ /* steam not in use, is a sink, and is the right media type (audio/video) */
+ if ((p_scb->sep_info[i].in_use == FALSE) &&
+ (p_scb->sep_info[i].tsep == AVDT_TSEP_SNK) &&
+ (p_scb->sep_info[i].media_type == p_scb->media_type))
+ {
+ p_scb->sep_info_idx = i;
+
+ /* we got a stream; get its capabilities */
+ if (p_scb->p_cap == NULL)
+ {
+ p_scb->p_cap = (tAVDT_CFG *) GKI_getbuf(sizeof(tAVDT_CFG));
+ }
+ if (p_scb->p_cap == NULL)
+ {
+ i = p_scb->num_seps;
+ break;
+ }
+ if (p_scb->avdt_version >= AVDT_VERSION_SYNC)
+ {
+ p_req = AVDT_GetAllCapReq;
+ }
+ else
+ {
+ p_req = AVDT_GetCapReq;
+ }
+ (*p_req)(p_scb->peer_addr,
+ p_scb->sep_info[i].seid,
+ p_scb->p_cap, bta_av_dt_cback[p_scb->hdi]);
+ sent_cmd = TRUE;
+ break;
+ }
+ }
+
+ /* if no streams available then stream open fails */
+ if (!sent_cmd)
+ {
+ bta_av_ssm_execute(p_scb, BTA_AV_STR_GETCAP_FAIL_EVT, p_data);
+ }
+
+ return sent_cmd;
+
+}
+
+/*******************************************************************************
+**
+** Function bta_av_proc_stream_evt
+**
+** Description Utility function to compose stream events.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_proc_stream_evt(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data, int index)
+{
+ tBTA_AV_STR_MSG *p_msg;
+ UINT16 sec_len = 0;
+ tBTA_AV_SCB *p_scb = bta_av_cb.p_scb[index];
+ int xx;
+
+ if (p_data)
+ {
+ if (event == AVDT_SECURITY_IND_EVT)
+ {
+ sec_len = (p_data->security_ind.len < BTA_AV_SECURITY_MAX_LEN) ?
+ p_data->security_ind.len : BTA_AV_SECURITY_MAX_LEN;
+ }
+ else if (event == AVDT_SECURITY_CFM_EVT && p_data->hdr.err_code == 0)
+ {
+ sec_len = (p_data->security_cfm.len < BTA_AV_SECURITY_MAX_LEN) ?
+ p_data->security_cfm.len : BTA_AV_SECURITY_MAX_LEN;
+ }
+ }
+
+ if (p_scb && (p_msg = (tBTA_AV_STR_MSG *) GKI_getbuf((UINT16) (sizeof(tBTA_AV_STR_MSG) + sec_len))) != NULL)
+ {
+
+ /* copy event data, bd addr, and handle to event message buffer */
+ p_msg->hdr.offset = 0;
+
+ if (bd_addr != NULL)
+ {
+ bdcpy(p_msg->bd_addr, bd_addr);
+ APPL_TRACE_DEBUG6(" bd_addr:%02x-%02x-%02x-%02x-%02x-%02x",
+ bd_addr[0], bd_addr[1],
+ bd_addr[2], bd_addr[3],
+ bd_addr[4], bd_addr[5]);
+ }
+
+ if (p_data != NULL)
+ {
+ memcpy(&p_msg->msg, p_data, sizeof (tAVDT_CTRL));
+ /* copy config params to event message buffer */
+ switch (event)
+ {
+ case AVDT_CONFIG_IND_EVT:
+ /* We might have 2 SEP signallings(A2DP + VDP) with one peer device on one L2CAP.
+ * If we already have a signalling connection with the bd_addr and the streaming
+ * SST is at INIT state, change it to INCOMING state to handle the signalling
+ * from the 2nd SEP. */
+ if ((bta_av_find_lcb(bd_addr, BTA_AV_LCB_FIND) != NULL) && (bta_av_is_scb_init(p_scb)))
+ {
+ bta_av_set_scb_sst_incoming (p_scb);
+
+ /* When ACP_CONNECT_EVT was received, we put first available scb to incoming state.
+ * Later when we receive AVDT_CONFIG_IND_EVT, we use a new p_scb and set its state to
+ * incoming which we do it above.
+ * We also have to set the old p_scb state to init to be used later */
+ for (xx = 0; xx < BTA_AV_NUM_STRS; xx++)
+ {
+ if ((bta_av_cb.p_scb[xx]) && (xx != index))
+ {
+ if (bta_av_cb.p_scb[xx]->state == BTA_AV_INCOMING_SST)
+ {
+ bta_av_cb.p_scb[xx]->state = BTA_AV_INIT_SST;
+ bta_av_cb.p_scb[xx]->coll_mask = 0;
+ break;
+ }
+ }
+ }
+ }
+
+ memcpy(&p_msg->cfg, p_data->config_ind.p_cfg, sizeof(tAVDT_CFG));
+ break;
+
+ case AVDT_SECURITY_IND_EVT:
+ p_msg->msg.security_ind.p_data = (UINT8 *) (p_msg + 1);
+ memcpy(p_msg->msg.security_ind.p_data, p_data->security_ind.p_data, sec_len);
+ break;
+
+ case AVDT_SECURITY_CFM_EVT:
+ p_msg->msg.security_cfm.p_data = (UINT8 *) (p_msg + 1);
+ if (p_data->hdr.err_code == 0)
+ {
+ memcpy(p_msg->msg.security_cfm.p_data, p_data->security_cfm.p_data, sec_len);
+ }
+ break;
+ case AVDT_SUSPEND_IND_EVT:
+ p_msg->msg.hdr.err_code = 0;
+ break;
+
+ default:
+ break;
+ }
+ }
+ else
+ p_msg->msg.hdr.err_code = 0;
+
+ /* look up application event */
+ if ((p_data == NULL) || (p_data->hdr.err_code == 0))
+ {
+ p_msg->hdr.event = bta_av_stream_evt_ok[event];
+ }
+ else
+ {
+ p_msg->hdr.event = bta_av_stream_evt_fail[event];
+ }
+
+ p_msg->initiator = FALSE;
+ if (event == AVDT_SUSPEND_CFM_EVT)
+ p_msg->initiator = TRUE;
+
+ APPL_TRACE_EVENT1("hndl:x%x", p_scb->hndl);
+ p_msg->hdr.layer_specific = p_scb->hndl;
+ p_msg->handle = handle;
+ p_msg->avdt_event = event;
+ bta_sys_sendmsg(p_msg);
+ }
+
+/* coverity[var_deref_model]: Variable "p_data" tracked as NULL was passed to function "bta_av_conn_cback" that dereferences it.
+ * false-positive: bta_av_conn_cback only processes AVDT_CONNECT_IND_EVT and AVDT_DISCONNECT_IND_EVT event
+ * these 2 events always have associated p_data
+ */
+ bta_av_conn_cback(handle, bd_addr, event, p_data);
+}
+
+/*******************************************************************************
+**
+** Function bta_av_stream0_cback
+**
+** Description This is the AVDTP callback function for stream events.
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_av_stream0_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data)
+{
+ APPL_TRACE_EVENT2("bta_av_stream0_cback avdt_handle: %d event=0x%x", handle, event);
+ bta_av_proc_stream_evt(handle, bd_addr, event, p_data, 0);
+}
+
+/*******************************************************************************
+**
+** Function bta_av_stream1_cback
+**
+** Description This is the AVDTP callback function for stream events.
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_av_stream1_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data)
+{
+ APPL_TRACE_EVENT2("bta_av_stream1_cback avdt_handle: %d event=0x%x", handle, event);
+ bta_av_proc_stream_evt(handle, bd_addr, event, p_data, 1);
+}
+
+#if BTA_AV_NUM_STRS > 2
+/*******************************************************************************
+**
+** Function bta_av_stream2_cback
+**
+** Description This is the AVDTP callback function for stream events.
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_av_stream2_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data)
+{
+ APPL_TRACE_EVENT2("bta_av_stream2_cback avdt_handle: %d event=0x%x", handle, event);
+ bta_av_proc_stream_evt(handle, bd_addr, event, p_data, 2);
+}
+#endif
+
+#if BTA_AV_NUM_STRS > 3
+/*******************************************************************************
+**
+** Function bta_av_stream3_cback
+**
+** Description This is the AVDTP callback function for stream events.
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_av_stream3_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data)
+{
+ APPL_TRACE_EVENT2("bta_av_stream3_cback avdt_handle: %d event=0x%x", handle, event);
+ bta_av_proc_stream_evt(handle, bd_addr, event, p_data, 3);
+}
+#endif
+
+/*******************************************************************************
+**
+** Function bta_av_stream4_cback
+**
+** Description This is the AVDTP callback function for stream events.
+**
+** Returns void
+**
+*******************************************************************************/
+#if BTA_AV_NUM_STRS > 4
+static void bta_av_stream4_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data)
+{
+ APPL_TRACE_EVENT2("bta_av_stream4_cback avdt_handle: %d event=0x%x", handle, event);
+ bta_av_proc_stream_evt(handle, bd_addr, event, p_data, 4);
+}
+#endif
+
+/*******************************************************************************
+**
+** Function bta_av_stream5_cback
+**
+** Description This is the AVDTP callback function for stream events.
+**
+** Returns void
+**
+*******************************************************************************/
+#if BTA_AV_NUM_STRS > 5
+static void bta_av_stream5_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data)
+{
+ APPL_TRACE_EVENT2("bta_av_stream5_cback avdt_handle: %d event=0x%x", handle, event);
+ bta_av_proc_stream_evt(handle, bd_addr, event, p_data, 5);
+}
+#endif
+
+/*******************************************************************************
+**
+** Function bta_av_a2d_sdp_cback
+**
+** Description A2DP service discovery callback.
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_av_a2d_sdp_cback(BOOLEAN found, tA2D_Service *p_service)
+{
+ tBTA_AV_SDP_RES *p_msg;
+ tBTA_AV_SCB *p_scb;
+
+ if ((p_msg = (tBTA_AV_SDP_RES *) GKI_getbuf(sizeof(tBTA_AV_SDP_RES))) != NULL)
+ {
+ p_msg->hdr.event = (found) ? BTA_AV_SDP_DISC_OK_EVT : BTA_AV_SDP_DISC_FAIL_EVT;
+
+ p_scb = bta_av_hndl_to_scb(bta_av_cb.handle);
+ if (p_scb)
+ {
+ if (found && (p_service != NULL))
+ p_scb->avdt_version = p_service->avdt_version;
+ else
+ p_scb->avdt_version = 0x00;
+
+ p_msg->hdr.layer_specific = bta_av_cb.handle;
+ bta_sys_sendmsg(p_msg);
+ }
+ else
+ {
+ APPL_TRACE_ERROR1 ("bta_av_a2d_sdp_cback, no scb found for handle(0x%x)", bta_av_cb.handle);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_adjust_seps_idx
+**
+** Description adjust the sep_idx
+**
+** Returns
+**
+*******************************************************************************/
+static void bta_av_adjust_seps_idx(tBTA_AV_SCB *p_scb)
+{
+ int xx;
+
+ APPL_TRACE_DEBUG1("bta_av_adjust_seps_idx codec_type: %d", p_scb->codec_type);
+ for(xx=0; xx<BTA_AV_MAX_SEPS; xx++)
+ {
+ APPL_TRACE_DEBUG2("av_handle: %d codec_type: %d",
+ p_scb->seps[xx].av_handle, p_scb->seps[xx].codec_type);
+ if(p_scb->seps[xx].av_handle && p_scb->codec_type == p_scb->seps[xx].codec_type)
+ {
+ p_scb->sep_idx = xx;
+ p_scb->avdt_handle = p_scb->seps[xx].av_handle;
+ break;
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_switch_role
+**
+** Description Switch role was not started and a timer was started.
+** another attempt to switch role now - still opening.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_switch_role (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+ tBTA_AV_RS_RES switch_res = BTA_AV_RS_NONE;
+ tBTA_AV_API_OPEN *p_buf = &p_scb->q_info.open;
+
+ APPL_TRACE_DEBUG1("bta_av_switch_role wait:x%x", p_scb->wait);
+ if (p_scb->wait & BTA_AV_WAIT_ROLE_SW_RES_START)
+ p_scb->wait |= BTA_AV_WAIT_ROLE_SW_RETRY;
+
+ /* clear the masks set when the timer is started */
+ p_scb->wait &= ~(BTA_AV_WAIT_ROLE_SW_RES_OPEN|BTA_AV_WAIT_ROLE_SW_RES_START);
+
+ if (p_scb->q_tag == BTA_AV_Q_TAG_OPEN)
+ {
+ if (bta_av_switch_if_needed(p_scb) || !bta_av_link_role_ok(p_scb, A2D_SET_MULTL_BIT))
+ {
+ p_scb->wait |= BTA_AV_WAIT_ROLE_SW_RES_OPEN;
+ }
+ else
+ {
+ /* this should not happen in theory. Just in case...
+ * continue to do_disc_a2d */
+ switch_res = BTA_AV_RS_DONE;
+ }
+ }
+ else
+ {
+ /* report failure on OPEN */
+ switch_res = BTA_AV_RS_FAIL;
+ }
+
+ if (switch_res != BTA_AV_RS_NONE)
+ {
+ if (bta_av_cb.rs_idx == (p_scb->hdi + 1))
+ {
+ bta_av_cb.rs_idx = 0;
+ }
+ p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_RETRY;
+ p_scb->q_tag = 0;
+ p_buf->switch_res = switch_res;
+ bta_av_do_disc_a2d(p_scb, (tBTA_AV_DATA *)p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_role_res
+**
+** Description Handle the role changed event
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_role_res (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+ BOOLEAN initiator = FALSE;
+ tBTA_AV_START start;
+ tBTA_AV_OPEN av_open;
+
+ APPL_TRACE_DEBUG3("bta_av_role_res q_tag:%d, wait:x%x, role:x%x", p_scb->q_tag, p_scb->wait, p_scb->role);
+ if (p_scb->role & BTA_AV_ROLE_START_INT)
+ initiator = TRUE;
+
+ if (p_scb->q_tag == BTA_AV_Q_TAG_START)
+ {
+ if (p_scb->wait & BTA_AV_WAIT_ROLE_SW_STARTED)
+ {
+ p_scb->role &= ~BTA_AV_ROLE_START_INT;
+ p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_BITS;
+ if (p_data->role_res.hci_status != HCI_SUCCESS)
+ {
+ bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+ /* start failed because of role switch. */
+ start.chnl = p_scb->chnl;
+ start.status = BTA_AV_FAIL_ROLE;
+ start.hndl = p_scb->hndl;
+ start.initiator = initiator;
+ (*bta_av_cb.p_cback)(BTA_AV_START_EVT, (tBTA_AV *) &start);
+ }
+ else
+ {
+ bta_av_start_ok(p_scb, p_data);
+ }
+ }
+ else if (p_scb->wait & BTA_AV_WAIT_ROLE_SW_RES_START)
+ p_scb->wait |= BTA_AV_WAIT_ROLE_SW_FAILED;
+ }
+ else if (p_scb->q_tag == BTA_AV_Q_TAG_OPEN)
+ {
+ if (p_scb->wait & BTA_AV_WAIT_ROLE_SW_RES_OPEN)
+ {
+ p_scb->role &= ~BTA_AV_ROLE_START_INT;
+ p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_BITS;
+
+ if (p_data->role_res.hci_status != HCI_SUCCESS)
+ {
+ /* Open failed because of role switch. */
+ bdcpy(av_open.bd_addr, p_scb->peer_addr);
+ av_open.chnl = p_scb->chnl;
+ av_open.hndl = p_scb->hndl;
+ start.status = BTA_AV_FAIL_ROLE;
+ (*bta_av_cb.p_cback)(BTA_AV_OPEN_EVT, (tBTA_AV *)&av_open);
+ }
+ else
+ {
+ /* Continue av open process */
+ p_scb->q_info.open.switch_res = BTA_AV_RS_DONE;
+ bta_av_do_disc_a2d (p_scb, (tBTA_AV_DATA *)&(p_scb->q_info.open));
+ }
+ }
+ else
+ {
+ APPL_TRACE_WARNING2 ("Unexpected role switch event: q_tag = %d wait = %d", p_scb->q_tag, p_scb->wait);
+ }
+ }
+
+ APPL_TRACE_DEBUG2("wait:x%x, role:x%x", p_scb->wait, p_scb->role);
+}
+
+/*******************************************************************************
+**
+** Function bta_av_delay_co
+**
+** Description Call the delay call-out function to report the delay report
+** from SNK
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_delay_co (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+ p_scb->p_cos->delay(p_scb->hndl, p_data->str_msg.msg.delay_rpt_cmd.delay);
+}
+
+/*******************************************************************************
+**
+** Function bta_av_do_disc_a2d
+**
+** Description Do service discovery for A2DP.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_do_disc_a2d (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+ BOOLEAN ok_continue = FALSE;
+ tA2D_SDP_DB_PARAMS db_params;
+ UINT16 attr_list[] = {ATTR_ID_SERVICE_CLASS_ID_LIST,
+ ATTR_ID_PROTOCOL_DESC_LIST,
+ ATTR_ID_BT_PROFILE_DESC_LIST};
+
+ APPL_TRACE_DEBUG3("bta_av_do_disc_a2d use_rc: %d rs:%d, oc:%d",
+ p_data->api_open.use_rc, p_data->api_open.switch_res, bta_av_cb.audio_open_cnt);
+
+ memcpy (&(p_scb->open_api), &(p_data->api_open), sizeof(tBTA_AV_API_OPEN));
+
+ switch(p_data->api_open.switch_res)
+ {
+ case BTA_AV_RS_NONE:
+ if (bta_av_switch_if_needed(p_scb) || !bta_av_link_role_ok(p_scb, A2D_SET_MULTL_BIT))
+ {
+ /* waiting for role switch result. save the api to control block */
+ memcpy(&p_scb->q_info.open, &p_data->api_open, sizeof(tBTA_AV_API_OPEN));
+ p_scb->wait |= BTA_AV_WAIT_ROLE_SW_RES_OPEN;
+ p_scb->q_tag = BTA_AV_Q_TAG_OPEN;
+ }
+ else
+ {
+ ok_continue = TRUE;
+ }
+ break;
+
+ case BTA_AV_RS_FAIL:
+ /* report a new failure event */
+ p_scb->open_status = BTA_AV_FAIL_ROLE;
+ bta_av_ssm_execute(p_scb, BTA_AV_SDP_DISC_FAIL_EVT, NULL);
+ break;
+
+ case BTA_AV_RS_OK:
+ p_data = (tBTA_AV_DATA *)&p_scb->q_info.open;
+ /* continue to open if link role is ok */
+ if (bta_av_link_role_ok(p_scb, A2D_SET_MULTL_BIT))
+ {
+ ok_continue = TRUE;
+ }
+ else
+ {
+ p_scb->wait |= BTA_AV_WAIT_ROLE_SW_RES_OPEN;
+ }
+ break;
+
+ case BTA_AV_RS_DONE:
+ ok_continue = TRUE;
+ break;
+ }
+
+ APPL_TRACE_DEBUG3("ok_continue: %d wait:x%x, q_tag: %d", ok_continue, p_scb->wait, p_scb->q_tag);
+ if (!ok_continue)
+ return;
+
+ /* clear the role switch bits */
+ p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_BITS;
+
+ if (p_scb->wait & BTA_AV_WAIT_CHECK_RC)
+ {
+ p_scb->wait &= ~BTA_AV_WAIT_CHECK_RC;
+ bta_sys_start_timer(&p_scb->timer, BTA_AV_AVRC_TIMER_EVT, BTA_AV_RC_DISC_TIME_VAL);
+ }
+
+ if (bta_av_cb.features & BTA_AV_FEAT_MASTER)
+ {
+ L2CA_SetDesireRole(L2CAP_ROLE_DISALLOW_SWITCH);
+
+ if (bta_av_cb.audio_open_cnt == 1)
+ {
+ /* there's already an A2DP connection. do not allow switch */
+ bta_sys_clear_default_policy(BTA_ID_AV, HCI_ENABLE_MASTER_SLAVE_SWITCH);
+ }
+ }
+ /* store peer addr other parameters */
+ bta_av_save_addr(p_scb, p_data->api_open.bd_addr);
+ p_scb->sec_mask = p_data->api_open.sec_mask;
+ p_scb->use_rc = p_data->api_open.use_rc;
+
+ bta_sys_app_open(BTA_ID_AV, p_scb->app_id, p_scb->peer_addr);
+
+ /* allocate discovery database */
+ if (p_scb->p_disc_db == NULL)
+ {
+ p_scb->p_disc_db = (tSDP_DISCOVERY_DB *) GKI_getbuf(BTA_AV_DISC_BUF_SIZE);
+ }
+
+ /* only one A2D find service is active at a time */
+ bta_av_cb.handle = p_scb->hndl;
+
+ if(p_scb->p_disc_db)
+ {
+ /* set up parameters */
+ db_params.db_len = BTA_AV_DISC_BUF_SIZE;
+ db_params.num_attr = 3;
+ db_params.p_db = p_scb->p_disc_db;
+ db_params.p_attrs = attr_list;
+
+ if(A2D_FindService(UUID_SERVCLASS_AUDIO_SINK, p_scb->peer_addr, &db_params,
+ bta_av_a2d_sdp_cback) == A2D_SUCCESS)
+ {
+ return;
+ }
+ }
+
+ /* when the code reaches here, either the DB is NULL
+ * or A2D_FindService is not successful */
+ bta_av_a2d_sdp_cback(FALSE, NULL);
+}
+
+/*******************************************************************************
+**
+** Function bta_av_cleanup
+**
+** Description cleanup AV stream control block.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_cleanup(tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+ tBTA_AV_CONN_CHG msg;
+ int xx;
+ UINT8 role = BTA_AV_ROLE_AD_INT;
+
+ APPL_TRACE_DEBUG0("bta_av_cleanup");
+
+ /* free any buffers */
+ utl_freebuf((void **) &p_scb->p_cap);
+ utl_freebuf((void **) &p_scb->p_disc_db);
+ p_scb->avdt_version = 0;
+
+ /* initialize some control block variables */
+ p_scb->open_status = BTA_AV_SUCCESS;
+
+ /* if de-registering shut everything down */
+ msg.hdr.layer_specific = p_scb->hndl;
+ p_scb->started = FALSE;
+ p_scb->cong = FALSE;
+ p_scb->role = role;
+ p_scb->cur_psc_mask = 0;
+ p_scb->wait = 0;
+ p_scb->num_disc_snks = 0;
+ bta_sys_stop_timer(&p_scb->timer);
+ if (p_scb->deregistring)
+ {
+ /* remove stream */
+ for(xx=0; xx<BTA_AV_MAX_SEPS; xx++)
+ {
+ if(p_scb->seps[xx].av_handle)
+ AVDT_RemoveStream(p_scb->seps[xx].av_handle);
+ p_scb->seps[xx].av_handle = 0;
+ }
+
+ bta_av_dereg_comp((tBTA_AV_DATA *) &msg);
+ }
+ else
+ {
+ /* report stream closed to main SM */
+ msg.is_up = FALSE;
+ bdcpy(msg.peer_addr, p_scb->peer_addr);
+ bta_av_conn_chg((tBTA_AV_DATA *) &msg);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_free_sdb
+**
+** Description Free service discovery db buffer.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_free_sdb(tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+ utl_freebuf((void **) &p_scb->p_disc_db);
+}
+
+/*******************************************************************************
+**
+** Function bta_av_config_ind
+**
+** Description Handle a stream configuration indication from the peer.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_config_ind (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+ tBTA_AV_CI_SETCONFIG setconfig;
+ tAVDT_SEP_INFO *p_info;
+ tAVDT_CFG *p_evt_cfg = &p_data->str_msg.cfg;
+ UINT8 psc_mask = (p_evt_cfg->psc_mask | p_scb->cfg.psc_mask);
+
+ p_scb->avdt_label = p_data->str_msg.msg.hdr.label;
+ memcpy(p_scb->cfg.codec_info, p_evt_cfg->codec_info, AVDT_CODEC_SIZE);
+ p_scb->codec_type = p_evt_cfg->codec_info[BTA_AV_CODEC_TYPE_IDX];
+ bta_av_save_addr(p_scb, p_data->str_msg.bd_addr);
+
+ /* Clear collision mask */
+ p_scb->coll_mask = 0;
+ bta_sys_stop_timer(&bta_av_cb.acp_sig_tmr);
+
+ /* if no codec parameters in configuration, fail */
+ if ((p_evt_cfg->num_codec == 0) ||
+ /* or the peer requests for a service we do not support */
+ ((psc_mask != p_scb->cfg.psc_mask) &&
+ (psc_mask != (p_scb->cfg.psc_mask&~AVDT_PSC_DELAY_RPT))) )
+ {
+ setconfig.hndl = p_scb->hndl; /* we may not need this */
+ setconfig.err_code = AVDT_ERR_UNSUP_CFG;
+ bta_av_ssm_execute(p_scb, BTA_AV_CI_SETCONFIG_FAIL_EVT, (tBTA_AV_DATA *) &setconfig);
+ }
+ else
+ {
+ p_info = &p_scb->sep_info[0];
+ p_info->in_use = 0;
+ p_info->media_type = p_scb->media_type;
+ p_info->seid = p_data->str_msg.msg.config_ind.int_seid;
+ p_info->tsep = AVDT_TSEP_SNK;
+ p_scb->role |= BTA_AV_ROLE_AD_ACP;
+ p_scb->cur_psc_mask = p_evt_cfg->psc_mask;
+ if (bta_av_cb.features & BTA_AV_FEAT_RCTG)
+ p_scb->use_rc = TRUE;
+ else
+ p_scb->use_rc = FALSE;
+
+ p_scb->num_seps = 1;
+ p_scb->sep_info_idx = 0;
+ APPL_TRACE_DEBUG3("bta_av_config_ind: SEID: %d use_rc: %d cur_psc_mask:0x%x", p_info->seid, p_scb->use_rc, p_scb->cur_psc_mask);
+
+ p_scb->p_cos->setcfg(p_scb->hndl, p_scb->codec_type,
+ p_evt_cfg->codec_info,
+ p_info->seid,
+ p_scb->peer_addr,
+ p_evt_cfg->num_protect,
+ p_evt_cfg->protect_info);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_disconnect_req
+**
+** Description Disconnect AVDTP connection.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_disconnect_req (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+ tBTA_AV_RCB *p_rcb;
+ APPL_TRACE_DEBUG1("bta_av_disconnect_req conn_lcb: 0x%x", bta_av_cb.conn_lcb);
+
+ bta_sys_stop_timer(&bta_av_cb.sig_tmr);
+ bta_sys_stop_timer(&p_scb->timer);
+ if(bta_av_cb.conn_lcb)
+ {
+ p_rcb = bta_av_get_rcb_by_shdl((UINT8)(p_scb->hdi + 1));
+ if (p_rcb)
+ bta_av_del_rc(p_rcb);
+ AVDT_DisconnectReq(p_scb->peer_addr, bta_av_dt_cback[p_scb->hdi]);
+ }
+ else
+ {
+ bta_av_ssm_execute(p_scb, BTA_AV_AVDT_DISCONNECT_EVT, NULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_security_req
+**
+** Description Send an AVDTP security request.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_security_req (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+ if (bta_av_cb.features & BTA_AV_FEAT_PROTECT)
+ {
+ AVDT_SecurityReq(p_scb->avdt_handle, p_data->api_protect_req.p_data,
+ p_data->api_protect_req.len);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_security_rsp
+**
+** Description Send an AVDTP security response.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_security_rsp (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+ if (bta_av_cb.features & BTA_AV_FEAT_PROTECT)
+ {
+ AVDT_SecurityRsp(p_scb->avdt_handle, p_scb->avdt_label, p_data->api_protect_rsp.error_code,
+ p_data->api_protect_rsp.p_data, p_data->api_protect_rsp.len);
+ }
+ else
+ {
+ AVDT_SecurityRsp(p_scb->avdt_handle, p_scb->avdt_label, AVDT_ERR_NSC,
+ NULL, 0);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_setconfig_rsp
+**
+** Description setconfig is OK
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_setconfig_rsp (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+ UINT8 num = p_data->ci_setconfig.num_seid + 1;
+
+ /* we like this codec_type. find the sep_idx */
+ bta_av_adjust_seps_idx(p_scb);
+ APPL_TRACE_DEBUG2("bta_av_setconfig_rsp: sep_idx: %d cur_psc_mask:0x%x", p_scb->sep_idx, p_scb->cur_psc_mask);
+ AVDT_ConfigRsp(p_scb->avdt_handle, p_scb->avdt_label, p_data->ci_setconfig.err_code,
+ p_data->ci_setconfig.category);
+
+ bta_sys_stop_timer(&bta_av_cb.sig_tmr);
+
+ if(p_data->ci_setconfig.err_code == AVDT_SUCCESS)
+ {
+ p_scb->wait = BTA_AV_WAIT_ACP_CAPS_ON;
+ if(p_data->ci_setconfig.recfg_needed)
+ p_scb->role |= BTA_AV_ROLE_SUSPEND_OPT;
+ APPL_TRACE_ERROR3("bta_av_setconfig_rsp recfg_needed:%d role:x%x num:%d",
+ p_data->ci_setconfig.recfg_needed, p_scb->role, num);
+ /* callout module tells BTA the number of "good" SEPs and their SEIDs.
+ * getcap on these SEID */
+ p_scb->num_seps = num;
+
+ if (p_scb->cur_psc_mask & AVDT_PSC_DELAY_RPT)
+ p_scb->avdt_version = AVDT_VERSION_SYNC;
+
+ /* We need to know all the SEPs on SNK */
+ /* Getcap for all SEPs will follow after Discover */
+ APPL_TRACE_DEBUG0("bta_av_setconfig_rsp: start DISCOVER");
+ bta_av_discover_req(p_scb, NULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_str_opened
+**
+** Description Stream opened OK (incoming/outgoing).
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_str_opened (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+ tBTA_AV_CONN_CHG msg;
+ tBTA_AV_OPEN open;
+ UINT8 *p;
+ UINT16 mtu;
+
+ msg.hdr.layer_specific = p_scb->hndl;
+ msg.is_up = TRUE;
+ bdcpy(msg.peer_addr, p_scb->peer_addr);
+ p_scb->l2c_cid = AVDT_GetL2CapChannel(p_scb->avdt_handle);
+ bta_av_conn_chg((tBTA_AV_DATA *) &msg);
+ /* set the congestion flag, so AV would not send media packets by accident */
+ p_scb->cong = TRUE;
+
+
+ p_scb->stream_mtu = p_data->str_msg.msg.open_ind.peer_mtu - AVDT_MEDIA_HDR_SIZE;
+ mtu = bta_av_chk_mtu(p_scb, p_scb->stream_mtu);
+ APPL_TRACE_DEBUG3("bta_av_str_opened l2c_cid: 0x%x stream_mtu: %d mtu: %d",
+ p_scb->l2c_cid, p_scb->stream_mtu, mtu);
+ if(mtu == 0 || mtu > p_scb->stream_mtu)
+ mtu = p_scb->stream_mtu;
+
+ /* Set the media channel as medium priority */
+ L2CA_SetTxPriority(p_scb->l2c_cid, L2CAP_CHNL_PRIORITY_MEDIUM);
+ L2CA_SetChnlFlushability (p_scb->l2c_cid, TRUE);
+
+ bta_sys_conn_open(BTA_ID_AV, p_scb->app_id, p_scb->peer_addr);
+ memset(&p_scb->q_info, 0, sizeof(tBTA_AV_Q_INFO));
+
+ p_scb->l2c_bufs = 0;
+ p_scb->p_cos->open(p_scb->hndl,
+ p_scb->codec_type, p_scb->cfg.codec_info, mtu);
+
+ {
+ /* TODO check if other audio channel is open.
+ * If yes, check if reconfig is needed
+ * Rigt now we do not do this kind of checking.
+ * BTA-AV is INT for 2nd audio connection.
+ * The application needs to make sure the current codec_info is proper.
+ * If one audio connection is open and another SNK attempts to connect to AV,
+ * the connection will be rejected.
+ */
+ /* check if other audio channel is started. If yes, start */
+ bdcpy(open.bd_addr, p_scb->peer_addr);
+ open.chnl = p_scb->chnl;
+ open.hndl = p_scb->hndl;
+ open.status = BTA_AV_SUCCESS;
+ open.starting = bta_av_chk_start(p_scb);
+ open.edr = 0;
+ if( NULL != (p = BTM_ReadRemoteFeatures(p_scb->peer_addr)))
+ {
+ if(HCI_EDR_ACL_2MPS_SUPPORTED(p))
+ open.edr |= BTA_AV_EDR_2MBPS;
+ if(HCI_EDR_ACL_3MPS_SUPPORTED(p))
+ open.edr |= BTA_AV_EDR_3MBPS;
+ }
+#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
+ bta_ar_avdt_conn(BTA_ID_AV, open.bd_addr);
+#endif
+ (*bta_av_cb.p_cback)(BTA_AV_OPEN_EVT, (tBTA_AV *) &open);
+ if(open.starting)
+ {
+ bta_av_ssm_execute(p_scb, BTA_AV_AP_START_EVT, NULL);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_security_ind
+**
+** Description Handle an AVDTP security indication.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_security_ind (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+ tBTA_AV_PROTECT_REQ protect_req;
+
+ p_scb->avdt_label = p_data->str_msg.msg.hdr.label;
+
+ if (bta_av_cb.features & BTA_AV_FEAT_PROTECT)
+ {
+ protect_req.chnl = p_scb->chnl;
+ protect_req.hndl = p_scb->hndl;
+ /*
+ APPL_TRACE_EVENT1("sec ind handle: x%x", protect_req.hndl);
+ */
+ protect_req.p_data = p_data->str_msg.msg.security_ind.p_data;
+ protect_req.len = p_data->str_msg.msg.security_ind.len;
+
+ (*bta_av_cb.p_cback)(BTA_AV_PROTECT_REQ_EVT, (tBTA_AV *) &protect_req);
+ }
+ /* app doesn't support security indication; respond with failure */
+ else
+ {
+ AVDT_SecurityRsp(p_scb->avdt_handle, p_scb->avdt_label, AVDT_ERR_NSC, NULL, 0);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_security_cfm
+**
+** Description Handle an AVDTP security confirm.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_security_cfm (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+ tBTA_AV_PROTECT_RSP protect_rsp;
+
+ if (bta_av_cb.features & BTA_AV_FEAT_PROTECT)
+ {
+ protect_rsp.chnl = p_scb->chnl;
+ protect_rsp.hndl = p_scb->hndl;
+ protect_rsp.p_data = p_data->str_msg.msg.security_cfm.p_data;
+ protect_rsp.len = p_data->str_msg.msg.security_cfm.len;
+ protect_rsp.err_code= p_data->str_msg.msg.hdr.err_code;
+
+ (*bta_av_cb.p_cback)(BTA_AV_PROTECT_RSP_EVT, (tBTA_AV *) &protect_rsp);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_do_close
+**
+** Description Close stream.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_do_close (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+ /* stop stream if started */
+ if (p_scb->co_started)
+ {
+ bta_av_str_stopped(p_scb, NULL);
+ }
+ bta_sys_stop_timer(&bta_av_cb.sig_tmr);
+
+ /* close stream */
+ p_scb->started = FALSE;
+
+ /* drop the buffers queued in L2CAP */
+ L2CA_FlushChannel (p_scb->l2c_cid, L2CAP_FLUSH_CHANS_ALL);
+
+ AVDT_CloseReq(p_scb->avdt_handle);
+ /* just in case that the link is congested, link is flow controled by peer or
+ * for whatever reason the the close request can not be sent in time.
+ * when this timer expires, AVDT_DisconnectReq will be called to disconnect the link
+ */
+ bta_sys_start_timer(&p_scb->timer,
+ (UINT16)BTA_AV_API_CLOSE_EVT,
+ BTA_AV_CLOSE_REQ_TIME_VAL);
+
+}
+
+/*******************************************************************************
+**
+** Function bta_av_connect_req
+**
+** Description Connect AVDTP connection.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_connect_req (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+ utl_freebuf((void **) &p_scb->p_disc_db);
+
+ if (p_scb->coll_mask & BTA_AV_COLL_INC_TMR)
+ {
+ /* SNK initiated L2C connection while SRC was doing SDP. */
+ /* Wait until timeout to check if SNK starts signalling. */
+ APPL_TRACE_EVENT1("bta_av_connect_req: coll_mask = 0x%2X", p_scb->coll_mask);
+ return;
+ }
+
+ AVDT_ConnectReq(p_scb->peer_addr, p_scb->sec_mask, bta_av_dt_cback[p_scb->hdi]);
+}
+
+/*******************************************************************************
+**
+** Function bta_av_sdp_failed
+**
+** Description Service discovery failed.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_sdp_failed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+ if (!p_scb->open_status)
+ p_scb->open_status = BTA_AV_FAIL_SDP;
+
+ utl_freebuf((void **) &p_scb->p_disc_db);
+ bta_av_str_closed(p_scb, p_data);
+}
+
+/*******************************************************************************
+**
+** Function bta_av_disc_results
+**
+** Description Handle the AVDTP discover results. Search through the
+** results and find the first available stream, and get
+** its capabilities.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_disc_results (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+ UINT8 num_snks = 0, i;
+
+ /* store number of stream endpoints returned */
+ p_scb->num_seps = p_data->str_msg.msg.discover_cfm.num_seps;
+
+ for (i = 0; i < p_scb->num_seps; i++)
+ {
+ /* steam not in use, is a sink, and is audio */
+ if ((p_scb->sep_info[i].in_use == FALSE) &&
+ (p_scb->sep_info[i].tsep == AVDT_TSEP_SNK) &&
+ (p_scb->sep_info[i].media_type == p_scb->media_type))
+ {
+ num_snks++;
+ }
+ }
+
+ p_scb->p_cos->disc_res(p_scb->hndl, p_scb->num_seps, num_snks, p_scb->peer_addr);
+ p_scb->num_disc_snks = num_snks;
+
+ /* if we got any */
+ if (p_scb->num_seps > 0)
+ {
+ /* initialize index into discovery results */
+ p_scb->sep_info_idx = 0;
+
+ /* get the capabilities of the first available stream */
+ bta_av_next_getcap(p_scb, p_data);
+ }
+ /* else we got discover response but with no streams; we're done */
+ else
+ {
+ bta_av_ssm_execute(p_scb, BTA_AV_STR_DISC_FAIL_EVT, p_data);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_disc_res_as_acp
+**
+** Description Handle the AVDTP discover results. Search through the
+** results and find the first available stream, and get
+** its capabilities.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_disc_res_as_acp (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+ UINT8 num_snks = 0, i;
+
+ /* store number of stream endpoints returned */
+ p_scb->num_seps = p_data->str_msg.msg.discover_cfm.num_seps;
+
+
+
+ for (i = 0; i < p_scb->num_seps; i++)
+ {
+ /* steam is a sink, and is audio */
+ if ((p_scb->sep_info[i].tsep == AVDT_TSEP_SNK) &&
+ (p_scb->sep_info[i].media_type == p_scb->media_type))
+ {
+ p_scb->sep_info[i].in_use = FALSE;
+ num_snks++;
+ }
+ }
+
+ p_scb->p_cos->disc_res(p_scb->hndl, p_scb->num_seps, num_snks, p_scb->peer_addr);
+ p_scb->num_disc_snks = num_snks;
+
+ /* if we got any */
+ if (p_scb->num_seps > 0)
+ {
+ /* initialize index into discovery results */
+ p_scb->sep_info_idx = 0;
+
+ /* get the capabilities of the first available stream */
+ bta_av_next_getcap(p_scb, p_data);
+ }
+ /* else we got discover response but with no streams; we're done */
+ else
+ {
+ bta_av_ssm_execute(p_scb, BTA_AV_STR_DISC_FAIL_EVT, p_data);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_save_caps
+**
+** Description report the SNK SEP capabilities to application
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_save_caps(tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+ tAVDT_CFG cfg;
+ tAVDT_SEP_INFO *p_info = &p_scb->sep_info[p_scb->sep_info_idx];
+ UINT8 old_wait = p_scb->wait;
+ BOOLEAN getcap_done = FALSE;
+
+ APPL_TRACE_DEBUG3("bta_av_save_caps num_seps:%d sep_info_idx:%d wait:x%x",
+ p_scb->num_seps, p_scb->sep_info_idx, p_scb->wait);
+ memcpy(&cfg, p_scb->p_cap, sizeof(tAVDT_CFG));
+ /* let application know the capability of the SNK */
+ p_scb->p_cos->getcfg(p_scb->hndl, cfg.codec_info[BTA_AV_CODEC_TYPE_IDX],
+ cfg.codec_info, &p_scb->sep_info_idx, p_info->seid,
+ &cfg.num_protect, cfg.protect_info);
+
+ p_scb->sep_info_idx++;
+ if(p_scb->num_seps > p_scb->sep_info_idx)
+ {
+ /* Some devices have seps at the end of the discover list, which is not */
+ /* matching media type(video not audio). */
+ /* In this case, we are done with getcap without sending another */
+ /* request to AVDT. */
+ if (!bta_av_next_getcap(p_scb, p_data))
+ getcap_done = TRUE;
+ }
+ else
+ getcap_done = TRUE;
+
+ if (getcap_done)
+ {
+ /* we are done getting capabilities. restore the p_cb->sep_info_idx */
+ p_scb->sep_info_idx = 0;
+ p_scb->wait &= ~(BTA_AV_WAIT_ACP_CAPS_ON|BTA_AV_WAIT_ACP_CAPS_STARTED);
+ if (old_wait & BTA_AV_WAIT_ACP_CAPS_STARTED)
+ {
+ bta_av_start_ok (p_scb, NULL);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_set_use_rc
+**
+** Description set to use AVRC for this stream control block.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_set_use_rc (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+ p_scb->use_rc = TRUE;
+}
+
+/*******************************************************************************
+**
+** Function bta_av_cco_close
+**
+** Description call close call-out function.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_cco_close (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+ UINT16 mtu;
+ mtu = bta_av_chk_mtu(p_scb, BTA_AV_MAX_A2DP_MTU);
+
+ p_scb->p_cos->close(p_scb->hndl, p_scb->codec_type, mtu);
+}
+
+/*******************************************************************************
+**
+** Function bta_av_open_failed
+**
+** Description Failed to open an AVDT stream
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_open_failed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+ p_scb->open_status = BTA_AV_FAIL_STREAM;
+ bta_av_cco_close(p_scb, p_data);
+ AVDT_DisconnectReq(p_scb->peer_addr, bta_av_dt_cback[p_scb->hdi]);
+}
+
+/*******************************************************************************
+**
+** Function bta_av_getcap_results
+**
+** Description Handle the AVDTP get capabilities results. Check the codec
+** type and see if it matches ours. If it does not, get the
+** capabilities of the next stream, if any.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_getcap_results (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+ tAVDT_CFG cfg;
+ UINT8 media_type;
+ tAVDT_SEP_INFO *p_info = &p_scb->sep_info[p_scb->sep_info_idx];
+
+ memcpy(&cfg, &p_scb->cfg, sizeof(tAVDT_CFG));
+ cfg.num_codec = 1;
+ cfg.num_protect = p_scb->p_cap->num_protect;
+ memcpy(cfg.codec_info, p_scb->p_cap->codec_info, AVDT_CODEC_SIZE);
+ memcpy(cfg.protect_info, p_scb->p_cap->protect_info, AVDT_PROTECT_SIZE);
+ media_type = p_scb->p_cap->codec_info[BTA_AV_MEDIA_TYPE_IDX] >> 4;
+
+ APPL_TRACE_DEBUG1("num_codec %d", p_scb->p_cap->num_codec);
+ APPL_TRACE_DEBUG2("media type x%x, x%x", media_type, p_scb->media_type);
+#if AVDT_MULTIPLEXING == TRUE
+ APPL_TRACE_DEBUG2("mux x%x, x%x", cfg.mux_mask, p_scb->p_cap->mux_mask);
+#endif
+
+ /* if codec present and we get a codec configuration */
+ if ((p_scb->p_cap->num_codec != 0) &&
+ (media_type == p_scb->media_type) &&
+ (p_scb->p_cos->getcfg(p_scb->hndl, p_scb->p_cap->codec_info[BTA_AV_CODEC_TYPE_IDX],
+ cfg.codec_info, &p_scb->sep_info_idx, p_info->seid,
+ &cfg.num_protect, cfg.protect_info) == 0))
+ {
+#if AVDT_MULTIPLEXING == TRUE
+ cfg.mux_mask &= p_scb->p_cap->mux_mask;
+ APPL_TRACE_DEBUG1("mux_mask used x%x", cfg.mux_mask);
+#endif
+ /* save copy of codec type and configuration */
+ p_scb->codec_type = cfg.codec_info[BTA_AV_CODEC_TYPE_IDX];
+ memcpy(&p_scb->cfg, &cfg, sizeof(tAVDT_CFG));
+ bta_av_adjust_seps_idx(p_scb);
+ /* use only the services peer supports */
+ cfg.psc_mask &= p_scb->p_cap->psc_mask;
+ p_scb->cur_psc_mask = cfg.psc_mask;
+
+ /* open the stream */
+ AVDT_OpenReq(p_scb->seps[p_scb->sep_idx].av_handle, p_scb->peer_addr,
+ p_scb->sep_info[p_scb->sep_info_idx].seid, &cfg);
+
+ if (!bta_av_is_rcfg_sst(p_scb))
+ {
+ /* free capabilities buffer */
+ utl_freebuf((void **) &p_scb->p_cap);
+ }
+ }
+ else
+ {
+ /* try the next stream, if any */
+ p_scb->sep_info_idx++;
+ bta_av_next_getcap(p_scb, p_data);
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function bta_av_setconfig_rej
+**
+** Description Send AVDTP set config reject.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_setconfig_rej (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+ tBTA_AV_REJECT reject;
+
+ APPL_TRACE_DEBUG0("bta_av_setconfig_rej");
+ AVDT_ConfigRsp(p_data->str_msg.handle, p_data->str_msg.msg.hdr.label, AVDT_ERR_BAD_STATE, 0);
+ bdcpy(reject.bd_addr, p_data->str_msg.bd_addr);
+ reject.hndl = p_scb->hndl;
+ (*bta_av_cb.p_cback)(BTA_AV_REJECT_EVT, (tBTA_AV *) &reject);
+}
+
+/*******************************************************************************
+**
+** Function bta_av_discover_req
+**
+** Description Send an AVDTP discover request to the peer.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_discover_req (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+ /* send avdtp discover request */
+
+ AVDT_DiscoverReq(p_scb->peer_addr, p_scb->sep_info, BTA_AV_NUM_SEPS, bta_av_dt_cback[p_scb->hdi]);
+}
+
+/*******************************************************************************
+**
+** Function bta_av_conn_failed
+**
+** Description AVDTP connection failed.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_conn_failed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+ p_scb->open_status = BTA_AV_FAIL_STREAM;
+ bta_av_str_closed(p_scb, p_data);
+}
+
+/*******************************************************************************
+**
+** Function bta_av_do_start
+**
+** Description Start stream.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_do_start (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+ UINT8 policy = HCI_ENABLE_SNIFF_MODE;
+ UINT8 cur_role;
+
+ APPL_TRACE_DEBUG3("bta_av_do_start sco_occupied:%d, role:x%x, started:%d", bta_av_cb.sco_occupied, p_scb->role, p_scb->started);
+ if (bta_av_cb.sco_occupied)
+ {
+ bta_av_start_failed(p_scb, p_data);
+ return;
+ }
+
+ /* disallow role switch during streaming, only if we are the master role
+ * i.e. allow role switch, if we are slave.
+ * It would not hurt us, if the peer device wants us to be master */
+ if ((BTM_GetRole (p_scb->peer_addr, &cur_role) == BTM_SUCCESS) &&
+ (cur_role == BTM_ROLE_MASTER) )
+ {
+ policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH;
+ }
+
+ bta_sys_clear_policy(BTA_ID_AV, policy, p_scb->peer_addr);
+
+ if ((p_scb->started == FALSE) && ((p_scb->role & BTA_AV_ROLE_START_INT) == 0))
+ {
+ p_scb->role |= BTA_AV_ROLE_START_INT;
+ bta_sys_busy(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+
+ AVDT_StartReq(&p_scb->avdt_handle, 1);
+ }
+ else
+ {
+ bta_av_start_ok(p_scb, NULL);
+ }
+ APPL_TRACE_DEBUG1("role:x%x", p_scb->role);
+}
+
+/*******************************************************************************
+**
+** Function bta_av_str_stopped
+**
+** Description Stream stopped.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_str_stopped (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+ tBTA_AV_SUSPEND suspend_rsp;
+ UINT8 start = p_scb->started;
+ BOOLEAN sus_evt = TRUE;
+ BT_HDR *p_buf;
+ UINT8 policy = HCI_ENABLE_SNIFF_MODE;
+
+ APPL_TRACE_ERROR1("bta_av_str_stopped:audio_open_cnt=%d", bta_av_cb.audio_open_cnt);
+ bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+ if ((bta_av_cb.features & BTA_AV_FEAT_MASTER) == 0 || bta_av_cb.audio_open_cnt == 1)
+ policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH;
+ bta_sys_set_policy(BTA_ID_AV, policy, p_scb->peer_addr);
+
+ if(p_scb->co_started)
+ {
+ bta_av_stream_chg(p_scb, FALSE);
+ p_scb->co_started = FALSE;
+
+ p_scb->p_cos->stop(p_scb->hndl, p_scb->codec_type);
+ L2CA_SetFlushTimeout(p_scb->peer_addr, L2CAP_DEFAULT_FLUSH_TO);
+ }
+
+ /* if q_info.a2d is not empty, drop it now */
+ if(BTA_AV_CHNL_AUDIO == p_scb->chnl)
+ {
+ while((p_buf = (BT_HDR*)GKI_dequeue (&p_scb->q_info.a2d)) != NULL)
+ GKI_freebuf(p_buf);
+
+ /* drop the audio buffers queued in L2CAP */
+ if(p_data && p_data->api_stop.flush)
+ L2CA_FlushChannel (p_scb->l2c_cid, L2CAP_FLUSH_CHANS_ALL);
+ }
+
+ suspend_rsp.chnl = p_scb->chnl;
+ suspend_rsp.hndl = p_scb->hndl;
+ if (p_data && p_data->api_stop.suspend)
+ {
+ APPL_TRACE_DEBUG2("suspending: %d, sup:%d", start, p_scb->suspend_sup);
+ if ((start) && (p_scb->suspend_sup))
+ {
+ sus_evt = FALSE;
+ p_scb->l2c_bufs = 0;
+ AVDT_SuspendReq(&p_scb->avdt_handle, 1);
+ }
+
+ if(sus_evt)
+ {
+ suspend_rsp.status = BTA_AV_SUCCESS;
+ suspend_rsp.initiator = TRUE;
+ (*bta_av_cb.p_cback)(BTA_AV_SUSPEND_EVT, (tBTA_AV *) &suspend_rsp);
+ }
+ }
+ else
+ {
+ (*bta_av_cb.p_cback)(BTA_AV_STOP_EVT, (tBTA_AV *) &suspend_rsp);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_reconfig
+**
+** Description process the reconfigure request.
+** save the parameter in control block and
+** suspend, reconfigure or close the stream
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_reconfig (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+ tAVDT_CFG *p_cfg;
+ tBTA_AV_API_STOP stop;
+ tBTA_AV_RECONFIG evt;
+ tBTA_AV_API_RCFG *p_rcfg = &p_data->api_reconfig;
+
+ APPL_TRACE_DEBUG4("bta_av_reconfig r:%d, s:%d idx: %d (o:%d)",
+ p_scb->recfg_sup, p_scb->suspend_sup,
+ p_scb->rcfg_idx, p_scb->sep_info_idx);
+
+ p_scb->num_recfg = 0;
+ /* store the new configuration in control block */
+ if (p_scb->p_cap == NULL)
+ {
+ p_scb->p_cap = (tAVDT_CFG *) GKI_getbuf(sizeof(tAVDT_CFG));
+ }
+ if((p_cfg = p_scb->p_cap) == NULL)
+ {
+ /* report failure */
+ evt.status = BTA_AV_FAIL_RESOURCES;
+ evt.chnl = p_scb->chnl;
+ evt.hndl = p_scb->hndl;
+ (*bta_av_cb.p_cback)(BTA_AV_RECONFIG_EVT, (tBTA_AV *)&evt);
+
+ /* this event is not possible in this state.
+ * use it to bring the SSM back to open state */
+ bta_av_ssm_execute(p_scb, BTA_AV_SDP_DISC_OK_EVT, NULL);
+ return;
+ }
+
+ /*if(bta_av_cb.features & BTA_AV_FEAT_RCCT)*/
+ bta_sys_stop_timer(&p_scb->timer);
+
+ memcpy(p_cfg, &p_scb->cfg, sizeof(tAVDT_CFG));
+ p_cfg->num_protect = p_rcfg->num_protect;
+ memcpy(p_cfg->codec_info, p_rcfg->codec_info, AVDT_CODEC_SIZE);
+ memcpy(p_cfg->protect_info, p_rcfg->p_protect_info, p_rcfg->num_protect);
+ p_scb->rcfg_idx = p_rcfg->sep_info_idx;
+ p_scb->p_cap->psc_mask = p_scb->cur_psc_mask;
+
+ /* if the requested index differs from the current one, we can only close/open */
+ if ((p_scb->rcfg_idx == p_scb->sep_info_idx) &&
+ (p_rcfg->suspend)&& (p_scb->recfg_sup) && (p_scb->suspend_sup))
+ {
+ if(p_scb->started)
+ {
+ stop.flush = FALSE;
+ stop.suspend = TRUE;
+ bta_av_str_stopped(p_scb, (tBTA_AV_DATA *)&stop);
+ }
+ else
+ {
+ APPL_TRACE_DEBUG0("Reconfig");
+ AVDT_ReconfigReq(p_scb->avdt_handle, p_scb->p_cap);
+ p_scb->p_cap->psc_mask = p_scb->cur_psc_mask;
+ }
+ }
+ else
+ {
+ /* close the stream */
+ APPL_TRACE_DEBUG1("close/open num_protect: %d", p_cfg->num_protect);
+ if(p_scb->started)
+ bta_av_str_stopped(p_scb, NULL);
+ p_scb->started = FALSE;
+
+ /* drop the buffers queued in L2CAP */
+ L2CA_FlushChannel (p_scb->l2c_cid, L2CAP_FLUSH_CHANS_ALL);
+
+ AVDT_CloseReq(p_scb->avdt_handle);
+
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_data_path
+**
+** Description Handle stream data path.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_data_path (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+ BT_HDR *p_buf;
+ UINT32 data_len;
+ UINT32 timestamp;
+ BOOLEAN new_buf = FALSE;
+ UINT8 m_pt = 0x60 | p_scb->codec_type;
+
+ if (!p_scb->cong)
+ {
+ /*
+ APPL_TRACE_ERROR1("q: %d", p_scb->l2c_bufs);
+ */
+ //Always get the current number of bufs que'd up
+ p_scb->l2c_bufs = (UINT8)L2CA_FlushChannel (p_scb->l2c_cid, L2CAP_FLUSH_CHANS_GET);
+
+ p_buf = (BT_HDR *)GKI_dequeue (&p_scb->q_info.a2d);
+ if(p_buf)
+ {
+ /* use q_info.a2d data, read the timestamp */
+ timestamp = *(UINT32 *)(p_buf + 1);
+ }
+ else
+ {
+ new_buf = TRUE;
+ /* q_info.a2d empty, call co_data, dup data to other channels */
+ p_buf = (BT_HDR *)p_scb->p_cos->data(p_scb->codec_type, &data_len,
+ &timestamp);
+
+ if (p_buf)
+ {
+ /* use the offset area for the time stamp */
+ *(UINT32 *)(p_buf + 1) = timestamp;
+
+ /* dup the data to other channels */
+ bta_av_dup_audio_buf(p_scb, p_buf);
+ }
+ }
+
+ if(p_buf)
+ {
+ if(p_scb->l2c_bufs < (BTA_AV_QUEUE_DATA_CHK_NUM))
+ {
+ /* there's a buffer, just queue it to L2CAP */
+ /* There's no need to increment it here, it is always read from L2CAP see above */
+ /* p_scb->l2c_bufs++; */
+ /*
+ APPL_TRACE_ERROR1("qw: %d", p_scb->l2c_bufs);
+ */
+ AVDT_WriteReq(p_scb->avdt_handle, p_buf, timestamp, m_pt);
+ p_scb->cong = TRUE;
+ }
+ else
+ {
+ /* there's a buffer, but L2CAP does not seem to be moving data */
+ if(new_buf)
+ {
+ /* just got this buffer from co_data,
+ * put it in queue */
+ GKI_enqueue(&p_scb->q_info.a2d, p_buf);
+ }
+ else
+ {
+ /* just dequeue it from the q_info.a2d */
+ if(p_scb->q_info.a2d.count < 3)
+ {
+ /* put it back to the queue */
+ GKI_enqueue_head (&p_scb->q_info.a2d, p_buf);
+ }
+ else
+ {
+ /* too many buffers in q_info.a2d, drop it. */
+ bta_av_co_audio_drop(p_scb->hndl);
+ GKI_freebuf(p_buf);
+ }
+ }
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_start_ok
+**
+** Description Stream started.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_start_ok (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+ tBTA_AV_START start;
+ tBTA_AV_API_STOP stop;
+ BOOLEAN initiator = FALSE;
+ BOOLEAN suspend = FALSE;
+ UINT16 flush_to;
+ UINT8 new_role = p_scb->role;
+ BT_HDR hdr;
+
+ APPL_TRACE_DEBUG2("bta_av_start_ok wait:x%x, role:x%x", p_scb->wait, p_scb->role);
+
+ p_scb->started = TRUE;
+ if (p_scb->sco_suspend)
+ {
+ p_scb->sco_suspend = FALSE;
+ }
+
+ if (new_role & BTA_AV_ROLE_START_INT)
+ initiator = TRUE;
+
+ if (p_scb->wait & BTA_AV_WAIT_ROLE_SW_FAILED)
+ {
+ /* role switch has failed */
+ p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_FAILED;
+ p_data = (tBTA_AV_DATA *)&hdr;
+ hdr.offset = BTA_AV_RS_FAIL;
+ }
+ APPL_TRACE_DEBUG1("wait:x%x", p_scb->wait);
+
+ if (p_data && (p_data->hdr.offset != BTA_AV_RS_NONE))
+ {
+ p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_BITS;
+ if (p_data->hdr.offset == BTA_AV_RS_FAIL)
+ {
+ bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+ start.chnl = p_scb->chnl;
+ start.status = BTA_AV_FAIL_ROLE;
+ start.hndl = p_scb->hndl;
+ start.initiator = initiator;
+ (*bta_av_cb.p_cback)(BTA_AV_START_EVT, (tBTA_AV *) &start);
+ return;
+ }
+ }
+
+ if (!bta_av_link_role_ok(p_scb, A2D_SET_ONE_BIT))
+ p_scb->q_tag = BTA_AV_Q_TAG_START;
+ else
+ {
+ /* The wait flag may be set here while we are already master on the link */
+ /* this could happen if a role switch complete event occurred during reconfig */
+ /* if we are now master on the link, there is no need to wait for the role switch, */
+ /* complete anymore so we can clear the wait for role switch flag */
+ p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_BITS;
+ }
+
+ if (p_scb->wait & (BTA_AV_WAIT_ROLE_SW_RES_OPEN|BTA_AV_WAIT_ROLE_SW_RES_START))
+ {
+ p_scb->wait |= BTA_AV_WAIT_ROLE_SW_STARTED;
+ p_scb->q_tag = BTA_AV_Q_TAG_START;
+ }
+
+ if (p_scb->wait & BTA_AV_WAIT_ACP_CAPS_ON)
+ {
+ p_scb->wait |= BTA_AV_WAIT_ACP_CAPS_STARTED;
+ }
+
+ if (p_scb->wait)
+ {
+ APPL_TRACE_DEBUG2("wait:x%x q_tag:%d- not started", p_scb->wait, p_scb->q_tag);
+ return;
+ }
+
+ /* tell role manager to check M/S role */
+ bta_sys_conn_open(BTA_ID_AV, p_scb->app_id, p_scb->peer_addr);
+
+ bta_sys_busy(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+
+ if(p_scb->media_type == AVDT_MEDIA_AUDIO)
+ {
+ /* in normal logic, conns should be bta_av_cb.audio_count - 1,
+ * However, bta_av_stream_chg is not called to increase bta_av_cb.audio_count yet.
+ * If the code were to be re-arranged for some reasons, this number may need to be changed
+ */
+ p_scb->co_started = bta_av_cb.audio_open_cnt;
+ flush_to = p_bta_av_cfg->p_audio_flush_to[p_scb->co_started - 1];
+ }
+ else
+ {
+ flush_to = p_bta_av_cfg->video_flush_to;
+ }
+ L2CA_SetFlushTimeout(p_scb->peer_addr, flush_to );
+
+ /* clear the congestion flag */
+ p_scb->cong = FALSE;
+
+ if (new_role & BTA_AV_ROLE_START_INT)
+ {
+ new_role &= ~BTA_AV_ROLE_START_INT;
+ }
+ else if ((new_role & BTA_AV_ROLE_AD_ACP) && (new_role & BTA_AV_ROLE_SUSPEND_OPT))
+ {
+ suspend = TRUE;
+ }
+
+ if (!suspend)
+ {
+ p_scb->q_tag = BTA_AV_Q_TAG_STREAM;
+ bta_av_stream_chg(p_scb, TRUE);
+ }
+
+ {
+ p_scb->role = new_role;
+ p_scb->role &= ~BTA_AV_ROLE_AD_ACP;
+ p_scb->role &= ~BTA_AV_ROLE_SUSPEND_OPT;
+
+ p_scb->p_cos->start(p_scb->hndl, p_scb->codec_type);
+ p_scb->co_started = TRUE;
+
+ APPL_TRACE_ERROR2("bta_av_start_ok suspending: %d, role:x%x", suspend, p_scb->role);
+ start.suspending = suspend;
+ start.initiator = initiator;
+ start.chnl = p_scb->chnl;
+ start.status = BTA_AV_SUCCESS;
+ start.hndl = p_scb->hndl;
+ (*bta_av_cb.p_cback)(BTA_AV_START_EVT, (tBTA_AV *) &start);
+
+ if(suspend)
+ {
+ p_scb->role |= BTA_AV_ROLE_SUSPEND;
+ p_scb->cong = TRUE; /* do not allow the media data to go through */
+ /* do not duplicate the media packets to this channel */
+ p_scb->p_cos->stop(p_scb->hndl, p_scb->codec_type);
+ p_scb->co_started = FALSE;
+ stop.flush = FALSE;
+ stop.suspend = TRUE;
+ bta_av_ssm_execute(p_scb, BTA_AV_AP_STOP_EVT, (tBTA_AV_DATA *)&stop);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_start_failed
+**
+** Description Stream start failed.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_start_failed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+ tBTA_AV_START start;
+
+ if(p_scb->started == FALSE && p_scb->co_started == FALSE)
+ {
+ /* if start failed, clear role */
+ p_scb->role &= ~BTA_AV_ROLE_START_INT;
+
+ bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+ start.chnl = p_scb->chnl;
+ start.status = BTA_AV_FAIL;
+ start.initiator = TRUE;
+ start.hndl = p_scb->hndl;
+ (*bta_av_cb.p_cback)(BTA_AV_START_EVT, (tBTA_AV *) &start);
+ }
+
+ bta_sys_set_policy(BTA_ID_AV, (HCI_ENABLE_SNIFF_MODE|HCI_ENABLE_MASTER_SLAVE_SWITCH), p_scb->peer_addr);
+ p_scb->sco_suspend = FALSE;
+}
+
+/*******************************************************************************
+**
+** Function bta_av_str_closed
+**
+** Description Stream closed.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_str_closed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+ tBTA_AV data;
+ tBTA_AV_EVT event;
+ UINT16 mtu;
+ UINT8 policy = HCI_ENABLE_SNIFF_MODE;
+
+ if ((bta_av_cb.features & BTA_AV_FEAT_MASTER) == 0 || bta_av_cb.audio_open_cnt == 1)
+ policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH;
+ bta_sys_set_policy(BTA_ID_AV, policy, p_scb->peer_addr);
+ if (bta_av_cb.audio_open_cnt <= 1)
+ {
+ /* last connection - restore the allow switch flag */
+ L2CA_SetDesireRole(L2CAP_ROLE_ALLOW_SWITCH);
+ }
+
+ if (p_scb->open_status)
+ {
+ /* must be failure when opening the stream */
+ bdcpy(data.open.bd_addr, p_scb->peer_addr);
+ data.open.status = p_scb->open_status;
+ data.open.chnl = p_scb->chnl;
+ data.open.hndl = p_scb->hndl;
+ event = BTA_AV_OPEN_EVT;
+ p_scb->open_status = BTA_AV_SUCCESS;
+
+ bta_sys_conn_close(BTA_ID_AV, p_scb->app_id, p_scb->peer_addr);
+ bta_av_cleanup(p_scb, p_data);
+ (*bta_av_cb.p_cback)(event, &data);
+ }
+ else
+ {
+ /* do stop if we were started */
+ if (p_scb->co_started)
+ {
+ bta_av_str_stopped(p_scb, NULL);
+ }
+
+ /* Update common mtu shared by remaining connectons */
+ mtu = bta_av_chk_mtu(p_scb, BTA_AV_MAX_A2DP_MTU);
+
+ {
+ p_scb->p_cos->close(p_scb->hndl, p_scb->codec_type, mtu);
+ data.close.chnl = p_scb->chnl;
+ data.close.hndl = p_scb->hndl;
+ event = BTA_AV_CLOSE_EVT;
+
+ bta_sys_conn_close(BTA_ID_AV, p_scb->app_id, p_scb->peer_addr);
+ bta_av_cleanup(p_scb, p_data);
+ (*bta_av_cb.p_cback)(event, &data);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_clr_cong
+**
+** Description Clear stream congestion flag.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_clr_cong (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+ if(p_scb->co_started)
+ p_scb->cong = FALSE;
+}
+
+/*******************************************************************************
+**
+** Function bta_av_suspend_cfm
+**
+** Description process the suspend response
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_suspend_cfm (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+ tBTA_AV_SUSPEND suspend_rsp;
+ UINT8 err_code = p_data->str_msg.msg.hdr.err_code;
+ UINT8 policy = HCI_ENABLE_SNIFF_MODE;
+
+ APPL_TRACE_DEBUG2 ("bta_av_suspend_cfm:audio_open_cnt = %d, err_code = %d",
+ bta_av_cb.audio_open_cnt, err_code);
+
+ suspend_rsp.status = BTA_AV_SUCCESS;
+ if(err_code)
+ {
+ p_scb->suspend_sup = FALSE;
+ suspend_rsp.status = BTA_AV_FAIL;
+
+ APPL_TRACE_ERROR0 ("bta_av_suspend_cfm: suspend failed, closing connection");
+
+ /* SUSPEND failed. Close connection. */
+ bta_av_ssm_execute(p_scb, BTA_AV_API_CLOSE_EVT, NULL);
+ }
+ else
+ {
+ /* only set started to FALSE when suspend is successful */
+ p_scb->started = FALSE;
+ }
+
+ if(p_scb->role & BTA_AV_ROLE_SUSPEND)
+ {
+ p_scb->role &= ~BTA_AV_ROLE_SUSPEND;
+ p_scb->cong = FALSE;
+ }
+
+ bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+ if ((bta_av_cb.features & BTA_AV_FEAT_MASTER) == 0 || bta_av_cb.audio_open_cnt == 1)
+ policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH;
+ bta_sys_set_policy(BTA_ID_AV, policy, p_scb->peer_addr);
+
+ /* in case that we received suspend_ind, we may need to call co_stop here */
+ if(p_scb->co_started)
+ {
+ bta_av_stream_chg(p_scb, FALSE);
+
+ {
+ p_scb->co_started = FALSE;
+ p_scb->p_cos->stop(p_scb->hndl, p_scb->codec_type);
+ }
+ L2CA_SetFlushTimeout(p_scb->peer_addr, L2CAP_DEFAULT_FLUSH_TO);
+ }
+
+ {
+ suspend_rsp.chnl = p_scb->chnl;
+ suspend_rsp.hndl = p_scb->hndl;
+ suspend_rsp.initiator = p_data->str_msg.initiator;
+ (*bta_av_cb.p_cback)(BTA_AV_SUSPEND_EVT, (tBTA_AV *) &suspend_rsp);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_rcfg_str_ok
+**
+** Description report reconfigure successful
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_rcfg_str_ok (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+ tBTA_AV_RECONFIG evt;
+
+ p_scb->l2c_cid = AVDT_GetL2CapChannel(p_scb->avdt_handle);
+ APPL_TRACE_DEBUG1("bta_av_rcfg_str_ok: l2c_cid: %d", p_scb->l2c_cid);
+
+ /* rc listen */
+ bta_av_st_rc_timer(p_scb, NULL);
+ utl_freebuf((void **)&p_scb->p_cap);
+
+ /* No need to keep the role bits once reconfig is done. */
+ p_scb->role &= ~BTA_AV_ROLE_AD_ACP;
+ p_scb->role &= ~BTA_AV_ROLE_SUSPEND_OPT;
+ p_scb->role &= ~BTA_AV_ROLE_START_INT;
+
+ {
+ /* reconfigure success */
+ evt.status = BTA_AV_SUCCESS;
+ evt.chnl = p_scb->chnl;
+ evt.hndl = p_scb->hndl;
+ (*bta_av_cb.p_cback)(BTA_AV_RECONFIG_EVT, (tBTA_AV *)&evt);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_rcfg_failed
+**
+** Description process reconfigure failed
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_rcfg_failed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+ tBTA_AV_RECONFIG evt;
+
+ APPL_TRACE_DEBUG2("bta_av_rcfg_failed num_recfg: %d, conn_lcb:0x%x",
+ p_scb->num_recfg, bta_av_cb.conn_lcb);
+ if(p_scb->num_recfg > BTA_AV_RECONFIG_RETRY)
+ {
+ bta_av_cco_close(p_scb, p_data);
+ /* report failure */
+ evt.status = BTA_AV_FAIL_STREAM;
+ evt.chnl = p_scb->chnl;
+ evt.hndl = p_scb->hndl;
+ (*bta_av_cb.p_cback)(BTA_AV_RECONFIG_EVT, (tBTA_AV *)&evt);
+ /* go to closing state */
+ bta_av_ssm_execute(p_scb, BTA_AV_API_CLOSE_EVT, NULL);
+ }
+ else
+ {
+ /* open failed. try again */
+ p_scb->num_recfg++;
+ if(bta_av_cb.conn_lcb)
+ {
+ AVDT_DisconnectReq(p_scb->peer_addr, bta_av_dt_cback[p_scb->hdi]);
+ }
+ else
+ {
+ bta_av_connect_req(p_scb, NULL);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_rcfg_connect
+**
+** Description stream closed. reconnect the stream
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_rcfg_connect (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+ p_scb->cong = FALSE;
+ p_scb->num_recfg++;
+ APPL_TRACE_DEBUG1("bta_av_rcfg_connect num_recfg: %d", p_scb->num_recfg);
+ if(p_scb->num_recfg > BTA_AV_RECONFIG_RETRY)
+ {
+ /* let bta_av_rcfg_failed report fail */
+ bta_av_rcfg_failed(p_scb, NULL);
+ }
+ else
+ AVDT_ConnectReq(p_scb->peer_addr, p_scb->sec_mask, bta_av_dt_cback[p_scb->hdi]);
+}
+
+/*******************************************************************************
+**
+** Function bta_av_rcfg_discntd
+**
+** Description AVDT disconnected. reconnect the stream
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_rcfg_discntd (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+ tBTA_AV_RECONFIG evt;
+
+ APPL_TRACE_DEBUG1("bta_av_rcfg_discntd num_recfg: %d", p_scb->num_recfg);
+ p_scb->num_recfg++;
+ if(p_scb->num_recfg > BTA_AV_RECONFIG_RETRY)
+ {
+ /* report failure */
+ evt.status = BTA_AV_FAIL_STREAM;
+ evt.chnl = p_scb->chnl;
+ evt.hndl = p_scb->hndl;
+ (*bta_av_cb.p_cback)(BTA_AV_RECONFIG_EVT, (tBTA_AV *)&evt);
+ /* report close event & go to init state */
+ bta_av_ssm_execute(p_scb, BTA_AV_STR_DISC_FAIL_EVT, NULL);
+ }
+ else
+ AVDT_ConnectReq(p_scb->peer_addr, p_scb->sec_mask, bta_av_dt_cback[p_scb->hdi]);
+}
+
+/*******************************************************************************
+**
+** Function bta_av_suspend_cont
+**
+** Description received the suspend response.
+** continue to reconfigure the stream
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_suspend_cont (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+ UINT8 err_code = p_data->str_msg.msg.hdr.err_code;
+ tBTA_AV_RECONFIG evt;
+
+ p_scb->started = FALSE;
+ p_scb->cong = FALSE;
+ if(err_code)
+ {
+ if(AVDT_ERR_CONNECT == err_code)
+ {
+ /* report failure */
+ evt.status = BTA_AV_FAIL;
+ (*bta_av_cb.p_cback)(BTA_AV_RECONFIG_EVT, (tBTA_AV *)&evt);
+ bta_av_ssm_execute(p_scb, BTA_AV_STR_DISC_FAIL_EVT, NULL);
+ }
+ else
+ {
+ APPL_TRACE_ERROR0("suspend rejected, try close");
+ p_scb->suspend_sup = FALSE;
+
+ /* drop the buffers queued in L2CAP */
+ L2CA_FlushChannel (p_scb->l2c_cid, L2CAP_FLUSH_CHANS_ALL);
+
+ AVDT_CloseReq(p_scb->avdt_handle);
+ }
+ }
+ else
+ {
+ APPL_TRACE_DEBUG0("bta_av_suspend_cont calling AVDT_ReconfigReq");
+ /* reconfig the stream */
+
+ AVDT_ReconfigReq(p_scb->avdt_handle, p_scb->p_cap);
+ p_scb->p_cap->psc_mask = p_scb->cur_psc_mask;
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_rcfg_cfm
+**
+** Description if reconfigure is successful, report the event
+** otherwise, close the stream.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_rcfg_cfm (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+ UINT8 err_code = p_data->str_msg.msg.hdr.err_code;
+
+ /*
+ APPL_TRACE_DEBUG0("bta_av_rcfg_cfm");
+ */
+ if(err_code)
+ {
+ APPL_TRACE_ERROR0("reconfig rejected, try close");
+ p_scb->recfg_sup = FALSE;
+ /* started flag is FALSE when reconfigure command is sent */
+ /* drop the buffers queued in L2CAP */
+ L2CA_FlushChannel (p_scb->l2c_cid, L2CAP_FLUSH_CHANS_ALL);
+ AVDT_CloseReq(p_scb->avdt_handle);
+ }
+ else
+ {
+ /* take the SSM back to OPEN state */
+ bta_av_ssm_execute(p_scb, BTA_AV_STR_OPEN_OK_EVT, NULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_rcfg_open
+**
+** Description AVDT is connected. open the stream with the new configuration
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_rcfg_open (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+ APPL_TRACE_DEBUG1("bta_av_rcfg_open, num_disc_snks = %d", p_scb->num_disc_snks);
+
+ if (p_scb->num_disc_snks == 0)
+ {
+ /* Need to update call-out module so that it will be ready for discover */
+ p_scb->p_cos->stop(p_scb->hndl, p_scb->codec_type);
+
+ /* send avdtp discover request */
+ AVDT_DiscoverReq(p_scb->peer_addr, p_scb->sep_info, BTA_AV_NUM_SEPS, bta_av_dt_cback[p_scb->hdi]);
+ }
+ else
+ {
+ p_scb->codec_type = p_scb->p_cap->codec_info[BTA_AV_CODEC_TYPE_IDX];
+ memcpy(p_scb->cfg.codec_info, p_scb->p_cap->codec_info, AVDT_CODEC_SIZE);
+ /* we may choose to use a different SEP at reconfig.
+ * adjust the sep_idx now */
+ bta_av_adjust_seps_idx(p_scb);
+
+ /* open the stream with the new config */
+ p_scb->sep_info_idx = p_scb->rcfg_idx;
+ AVDT_OpenReq(p_scb->avdt_handle, p_scb->peer_addr,
+ p_scb->sep_info[p_scb->sep_info_idx].seid, p_scb->p_cap);
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function bta_av_security_rej
+**
+** Description Send an AVDTP security reject.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_security_rej (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+ AVDT_SecurityRsp(p_scb->avdt_handle, p_scb->avdt_label, AVDT_ERR_BAD_STATE,
+ NULL, 0);
+}
+
+/*******************************************************************************
+**
+** Function bta_av_chk_2nd_start
+**
+** Description check if this is 2nd stream and if it needs to be started.
+** This function needs to be kept very similar to bta_av_chk_start
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_chk_2nd_start (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+ tBTA_AV_SCB *p_scbi;
+ int i;
+ BOOLEAN new_started = FALSE;
+
+
+ if ((p_scb->chnl == BTA_AV_CHNL_AUDIO) && (bta_av_cb.audio_open_cnt >= 2))
+ {
+ /* more than one audio channel is connected */
+ if (!(p_scb->role & BTA_AV_ROLE_SUSPEND_OPT))
+ {
+ /* this channel does not need to be reconfigured.
+ * if there is other channel streaming, start the stream now */
+ for(i=0; i<BTA_AV_NUM_STRS; i++)
+ {
+ p_scbi = bta_av_cb.p_scb[i];
+ if(p_scbi && p_scbi->chnl == BTA_AV_CHNL_AUDIO && p_scbi->co_started)
+ {
+ if (!new_started)
+ {
+ /* start the new stream */
+ new_started = TRUE;
+ bta_av_ssm_execute(p_scb, BTA_AV_AP_START_EVT, NULL);
+ }
+ /* may need to update the flush timeout of this already started stream */
+ if (p_scbi->co_started != bta_av_cb.audio_open_cnt)
+ {
+ p_scbi->co_started = bta_av_cb.audio_open_cnt;
+ L2CA_SetFlushTimeout(p_scbi->peer_addr, p_bta_av_cfg->p_audio_flush_to[p_scbi->co_started - 1] );
+ }
+ }
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_open_rc
+**
+** Description Send a message to main SM to open RC channel.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_open_rc (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+ tBTA_AV_START start;
+
+ APPL_TRACE_DEBUG3("bta_av_open_rc use_rc: %d, wait: x%x role:x%x", p_scb->use_rc, p_scb->wait, p_scb->role);
+ if ((p_scb->wait & BTA_AV_WAIT_ROLE_SW_BITS) && (p_scb->q_tag == BTA_AV_Q_TAG_START))
+ {
+ /* waiting for role switch for some reason & the timer expires */
+ if (!bta_av_link_role_ok(p_scb, A2D_SET_ONE_BIT))
+ {
+ APPL_TRACE_ERROR0 ("failed to start streaming for role management reasons!!");
+ bta_sys_stop_timer(&p_scb->timer);
+ start.chnl = p_scb->chnl;
+ start.status = BTA_AV_FAIL_ROLE;
+ start.initiator = TRUE;
+ start.hndl = p_scb->hndl;
+ p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_BITS;
+ bta_av_cb.rs_idx = 0;
+ (*bta_av_cb.p_cback)(BTA_AV_START_EVT, (tBTA_AV *) &start);
+ }
+ else
+ {
+ /* role switch is done. continue to start streaming */
+ bta_av_cb.rs_idx = 0;
+ p_data->hdr.offset = BTA_AV_RS_OK;
+ bta_av_start_ok (p_scb, p_data);
+ }
+ return;
+ }
+
+ if(p_scb->use_rc == TRUE || (p_scb->role & BTA_AV_ROLE_AD_ACP) )
+ {
+ if(bta_av_cb.disc)
+ {
+ /* AVRC discover db is in use */
+ if(p_scb->rc_handle == BTA_AV_RC_HANDLE_NONE)
+ {
+ /* AVRC channel is not connected. delay a little bit */
+ if ((p_scb->wait & BTA_AV_WAIT_ROLE_SW_BITS) == 0)
+ bta_sys_start_timer(&p_scb->timer, BTA_AV_AVRC_TIMER_EVT, BTA_AV_RC_DISC_TIME_VAL);
+ else
+ p_scb->wait |= BTA_AV_WAIT_CHECK_RC;
+ }
+ }
+ else
+ {
+ /* use main SM for AVRC SDP activities */
+ bta_av_rc_disc((UINT8)(p_scb->hdi + 1));
+ }
+ }
+ else
+ {
+ if(BTA_AV_RC_HANDLE_NONE != p_scb->rc_handle)
+ {
+ /* the open API said that this handle does not want a RC connection.
+ * disconnect it now */
+ AVRC_Close(p_scb->rc_handle);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_open_at_inc
+**
+** Description This function is called if API open is called by application
+** while state-machine is at incoming state.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_open_at_inc (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+ tBTA_AV_API_OPEN *p_buf;
+
+ memcpy (&(p_scb->open_api), &(p_data->api_open), sizeof(tBTA_AV_API_OPEN));
+
+ if (p_scb->coll_mask & BTA_AV_COLL_INC_TMR)
+ {
+ p_scb->coll_mask |= BTA_AV_COLL_API_CALLED;
+
+ /* API open will be handled at timeout if SNK did not start signalling. */
+ /* API open will be ignored if SNK starts signalling. */
+ }
+ else
+ {
+ /* SNK did not start signalling, API was called N seconds timeout. */
+ /* We need to switch to INIT state and start opening connection. */
+ p_scb->coll_mask = 0;
+ bta_av_set_scb_sst_init (p_scb);
+
+ if ((p_buf = (tBTA_AV_API_OPEN *) GKI_getbuf(sizeof(tBTA_AV_API_OPEN))) != NULL)
+ {
+ memcpy(p_buf, &(p_scb->open_api), sizeof(tBTA_AV_API_OPEN));
+ bta_sys_sendmsg(p_buf);
+ }
+ }
+}
+
+#endif /* AV_INCLUDED */
diff --git a/bta/av/bta_av_act.c b/bta/av/bta_av_act.c
new file mode 100644
index 0000000..472ed21
--- /dev/null
+++ b/bta/av/bta_av_act.c
@@ -0,0 +1,2000 @@
+/*****************************************************************************
+**
+** Name: bta_av_act.c
+**
+** Description: This file contains action functions for
+** advanced audio/video main state machine.
+**
+** Copyright (c) 2004-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+#if defined(AV_INCLUDED) && (AV_INCLUDED == TRUE)
+
+#include <string.h>
+#include "bta_av_api.h"
+#include "bta_av_int.h"
+#include "avdt_api.h"
+#include "bd.h"
+#include "utl.h"
+#include "l2c_api.h"
+#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
+#include "bta_ar_api.h"
+#endif
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+/* the timer in milliseconds to wait for open req after setconfig for incoming connections */
+#ifndef BTA_AV_SIG_TIME_VAL
+#define BTA_AV_SIG_TIME_VAL 8000
+#endif
+
+/* In millisec to wait for signalling from SNK when it is initiated from SNK. */
+/* If not, we will start signalling from SRC. */
+#ifndef BTA_AV_ACP_SIG_TIME_VAL
+#define BTA_AV_ACP_SIG_TIME_VAL 2000
+#endif
+
+static void bta_av_acp_sig_timer_cback (TIMER_LIST_ENT *p_tle);
+
+/*******************************************************************************
+**
+** Function bta_av_get_rcb_by_shdl
+**
+** Description find the RCB associated with the given SCB handle.
+**
+** Returns tBTA_AV_RCB
+**
+*******************************************************************************/
+tBTA_AV_RCB * bta_av_get_rcb_by_shdl(UINT8 shdl)
+{
+ tBTA_AV_RCB *p_rcb = NULL;
+ int i;
+
+ for (i=0; i<BTA_AV_NUM_RCB; i++)
+ {
+ if (bta_av_cb.rcb[i].shdl == shdl && bta_av_cb.rcb[i].handle != BTA_AV_RC_HANDLE_NONE)
+ {
+ p_rcb = &bta_av_cb.rcb[i];
+ break;
+ }
+ }
+ return p_rcb;
+}
+#define BTA_AV_STS_NO_RSP 0xFF /* a number not used by tAVRC_STS */
+
+/*******************************************************************************
+**
+** Function bta_av_del_rc
+**
+** Description delete the given AVRC handle.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_del_rc(tBTA_AV_RCB *p_rcb)
+{
+ tBTA_AV_SCB *p_scb;
+ UINT8 rc_handle; /* connected AVRCP handle */
+
+ if(p_rcb->handle != BTA_AV_RC_HANDLE_NONE)
+ {
+ if(p_rcb->shdl)
+ {
+ p_scb = bta_av_cb.p_scb[p_rcb->shdl - 1];
+ if(p_scb)
+ {
+ APPL_TRACE_DEBUG3("bta_av_del_rc shdl:%d, srch:%d rc_handle:%d", p_rcb->shdl, p_scb->rc_handle, p_rcb->handle);
+ if(p_scb->rc_handle == p_rcb->handle)
+ p_scb->rc_handle = BTA_AV_RC_HANDLE_NONE;
+ /* just in case the RC timer is active
+ if(bta_av_cb.features & BTA_AV_FEAT_RCCT && p_scb->chnl == BTA_AV_CHNL_AUDIO) */
+ bta_sys_stop_timer(&p_scb->timer);
+ }
+ }
+
+ APPL_TRACE_EVENT4("bta_av_del_rc handle: %d status=0x%x, rc_acp_handle:%d, idx:%d",
+ p_rcb->handle, p_rcb->status, bta_av_cb.rc_acp_handle, bta_av_cb.rc_acp_idx);
+ rc_handle = p_rcb->handle;
+ if(!(p_rcb->status & BTA_AV_RC_CONN_MASK) ||
+ ((p_rcb->status & BTA_AV_RC_ROLE_MASK) == BTA_AV_RC_ROLE_INT) )
+ {
+ p_rcb->status = 0;
+ p_rcb->handle = BTA_AV_RC_HANDLE_NONE;
+ p_rcb->shdl = 0;
+ p_rcb->lidx = 0;
+ }
+ /* else ACP && connected. do not clear the handle yet */
+ AVRC_Close(rc_handle);
+ if (rc_handle == bta_av_cb.rc_acp_handle)
+ bta_av_cb.rc_acp_handle = BTA_AV_RC_HANDLE_NONE;
+ APPL_TRACE_EVENT4("end del_rc handle: %d status=0x%x, rc_acp_handle:%d, lidx:%d",
+ p_rcb->handle, p_rcb->status, bta_av_cb.rc_acp_handle, p_rcb->lidx);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function bta_av_close_all_rc
+**
+** Description close the all AVRC handle.
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_av_close_all_rc(tBTA_AV_CB *p_cb)
+{
+ int i;
+
+ for(i=0; i<BTA_AV_NUM_RCB; i++)
+ {
+ if ((p_cb->disabling == TRUE) || (bta_av_cb.rcb[i].shdl != 0))
+ bta_av_del_rc(&bta_av_cb.rcb[i]);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_del_sdp_rec
+**
+** Description delete the given SDP record handle.
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_av_del_sdp_rec(UINT32 *p_sdp_handle)
+{
+ if(*p_sdp_handle != 0)
+ {
+ SDP_DeleteRecord(*p_sdp_handle);
+ *p_sdp_handle = 0;
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_avrc_sdp_cback
+**
+** Description AVRCP service discovery callback.
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_av_avrc_sdp_cback(UINT16 status)
+{
+ BT_HDR *p_msg;
+
+ if ((p_msg = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_msg->event = BTA_AV_SDP_AVRC_DISC_EVT;
+ bta_sys_sendmsg(p_msg);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_rc_ctrl_cback
+**
+** Description AVRCP control callback.
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_av_rc_ctrl_cback(UINT8 handle, UINT8 event, UINT16 result, BD_ADDR peer_addr)
+{
+ tBTA_AV_RC_CONN_CHG *p_msg;
+ UINT16 msg_event = 0;
+
+#if (defined(BTA_AV_MIN_DEBUG_TRACES) && BTA_AV_MIN_DEBUG_TRACES == TRUE)
+ APPL_TRACE_EVENT2("rc_ctrl handle: %d event=0x%x", handle, event);
+#else
+ APPL_TRACE_EVENT2("bta_av_rc_ctrl_cback handle: %d event=0x%x", handle, event);
+#endif
+ if (event == AVRC_OPEN_IND_EVT)
+ {
+ /* save handle of opened connection
+ bta_av_cb.rc_handle = handle;*/
+
+ msg_event = BTA_AV_AVRC_OPEN_EVT;
+ }
+ else if (event == AVRC_CLOSE_IND_EVT)
+ {
+ msg_event = BTA_AV_AVRC_CLOSE_EVT;
+ }
+
+ if (msg_event)
+ {
+ if ((p_msg = (tBTA_AV_RC_CONN_CHG *) GKI_getbuf(sizeof(tBTA_AV_RC_CONN_CHG))) != NULL)
+ {
+ p_msg->hdr.event = msg_event;
+ p_msg->handle = handle;
+ if(peer_addr)
+ bdcpy(p_msg->peer_addr, peer_addr);
+ bta_sys_sendmsg(p_msg);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_rc_msg_cback
+**
+** Description AVRCP message callback.
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_av_rc_msg_cback(UINT8 handle, UINT8 label, UINT8 opcode, tAVRC_MSG *p_msg)
+{
+ tBTA_AV_RC_MSG *p_buf;
+ UINT8 *p_data = NULL;
+ UINT8 **p_p_data = NULL;
+ UINT16 data_len = 0;
+
+#if (defined(BTA_AV_MIN_DEBUG_TRACES) && BTA_AV_MIN_DEBUG_TRACES == TRUE)
+ APPL_TRACE_ERROR2("rc_msg handle: %d opcode=0x%x", handle, opcode);
+#else
+ APPL_TRACE_EVENT2("bta_av_rc_msg_cback handle: %d opcode=0x%x", handle, opcode);
+#endif
+ /* determine size of buffer we need */
+ if (opcode == AVRC_OP_VENDOR && p_msg->vendor.p_vendor_data != NULL)
+ {
+ p_data = p_msg->vendor.p_vendor_data;
+ p_p_data = &p_msg->vendor.p_vendor_data;
+ data_len = (UINT16) p_msg->vendor.vendor_len;
+ }
+ else if (opcode == AVRC_OP_PASS_THRU && p_msg->pass.p_pass_data != NULL)
+ {
+ p_data = p_msg->pass.p_pass_data;
+ p_p_data = &p_msg->pass.p_pass_data;
+ data_len = (UINT16) p_msg->pass.pass_len;
+ }
+
+ if ((p_buf = (tBTA_AV_RC_MSG *) GKI_getbuf((UINT16) (sizeof(tBTA_AV_RC_MSG) + data_len))) != NULL)
+ {
+ p_buf->hdr.event = BTA_AV_AVRC_MSG_EVT;
+ p_buf->handle = handle;
+ p_buf->label = label;
+ p_buf->opcode = opcode;
+ memcpy(&p_buf->msg, p_msg, sizeof(tAVRC_MSG));
+ if (p_data != NULL)
+ {
+ memcpy((UINT8 *)(p_buf + 1), p_data, data_len);
+ *p_p_data = (UINT8 *)(p_buf + 1);
+ }
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+ if (opcode == AVRC_OP_BROWSE)
+ {
+ /* set p_pkt to NULL, so avrc would not free the GKI buffer */
+ p_msg->browse.p_browse_pkt = NULL;
+ }
+#endif
+#endif
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_rc_create
+**
+** Description alloc RCB and call AVRC_Open
+**
+** Returns the created rc handle
+**
+*******************************************************************************/
+UINT8 bta_av_rc_create(tBTA_AV_CB *p_cb, UINT8 role, UINT8 shdl, UINT8 lidx)
+{
+ tAVRC_CONN_CB ccb;
+ BD_ADDR_PTR bda = (BD_ADDR_PTR)bd_addr_any;
+ UINT8 status = BTA_AV_RC_ROLE_ACP;
+ tBTA_AV_SCB *p_scb = p_cb->p_scb[shdl - 1];
+ int i;
+ UINT8 rc_handle;
+ tBTA_AV_RCB *p_rcb;
+
+ if(role == AVCT_INT)
+ {
+ bda = p_scb->peer_addr;
+ status = BTA_AV_RC_ROLE_INT;
+ }
+ else
+ {
+ if ((p_rcb = bta_av_get_rcb_by_shdl(shdl)) != NULL )
+ {
+ APPL_TRACE_ERROR1("bta_av_rc_create ACP handle exist for shdl:%d", shdl);
+ return p_rcb->handle;
+ }
+ }
+
+ ccb.p_ctrl_cback = bta_av_rc_ctrl_cback;
+ ccb.p_msg_cback = bta_av_rc_msg_cback;
+ ccb.company_id = p_bta_av_cfg->company_id;
+ ccb.conn = role;
+ /* note: BTA_AV_FEAT_RCTG = AVRC_CT_TARGET, BTA_AV_FEAT_RCCT = AVRC_CT_CONTROL */
+ ccb.control = p_cb->features & (BTA_AV_FEAT_RCTG | BTA_AV_FEAT_RCCT | AVRC_CT_PASSIVE);
+
+
+ if (AVRC_Open(&rc_handle, &ccb, bda) != AVRC_SUCCESS)
+ return BTA_AV_RC_HANDLE_NONE;
+
+ i = rc_handle;
+ p_rcb = &p_cb->rcb[i];
+
+ if (p_rcb->handle != BTA_AV_RC_HANDLE_NONE)
+ {
+ APPL_TRACE_ERROR1("bta_av_rc_create found duplicated handle:%d", rc_handle);
+ }
+
+ p_rcb->handle = rc_handle;
+ p_rcb->status = status;
+ p_rcb->shdl = shdl;
+ p_rcb->lidx = lidx;
+ p_rcb->peer_features = 0;
+ if(lidx == (BTA_AV_NUM_LINKS + 1))
+ {
+ /* this LIDX is reserved for the AVRCP ACP connection */
+ p_cb->rc_acp_handle = p_rcb->handle;
+ p_cb->rc_acp_idx = (i + 1);
+ APPL_TRACE_DEBUG2("rc_acp_handle:%d idx:%d", p_cb->rc_acp_handle, p_cb->rc_acp_idx);
+ }
+ APPL_TRACE_DEBUG6("create %d, role: %d, shdl:%d, rc_handle:%d, lidx:%d, status:0x%x",
+ i, role, shdl, p_rcb->handle, lidx, p_rcb->status);
+
+ return rc_handle;
+}
+
+/*******************************************************************************
+**
+** Function bta_av_valid_group_navi_msg
+**
+** Description Check if it is Group Navigation Msg for Metadata
+**
+** Returns BTA_AV_RSP_ACCEPT or BTA_AV_RSP_NOT_IMPL.
+**
+*******************************************************************************/
+static tBTA_AV_CODE bta_av_group_navi_supported(UINT8 len, UINT8 *p_data)
+{
+ tBTA_AV_CODE ret=BTA_AV_RSP_NOT_IMPL;
+ UINT8 *p_ptr = p_data;
+ UINT16 u16;
+ UINT32 u32;
+
+ if (p_bta_av_cfg->avrc_group && len == BTA_GROUP_NAVI_MSG_OP_DATA_LEN)
+ {
+ BTA_AV_BE_STREAM_TO_CO_ID(u32, p_ptr);
+ BE_STREAM_TO_UINT16(u16, p_ptr);
+
+ if (u32 == AVRC_CO_METADATA)
+ {
+ if (u16 <= AVRC_PDU_PREV_GROUP)
+ ret = BTA_AV_RSP_ACCEPT;
+ else
+ ret = BTA_AV_RSP_REJ;
+ }
+ }
+
+ return ret;
+}
+
+/*******************************************************************************
+**
+** Function bta_av_op_supported
+**
+** Description Check if remote control operation is supported.
+**
+** Returns BTA_AV_RSP_ACCEPT of supported, BTA_AV_RSP_NOT_IMPL if not.
+**
+*******************************************************************************/
+static tBTA_AV_CODE bta_av_op_supported(tBTA_AV_RC rc_id)
+{
+ tBTA_AV_CODE ret_code = BTA_AV_RSP_NOT_IMPL;
+
+ if (p_bta_av_rc_id)
+ {
+ if (p_bta_av_rc_id[rc_id >> 4] & (1 << (rc_id & 0x0F)))
+ {
+ ret_code = BTA_AV_RSP_ACCEPT;
+ }
+ else if ((p_bta_av_cfg->rc_pass_rsp == BTA_AV_RSP_INTERIM) && p_bta_av_rc_id_ac)
+ {
+ if (p_bta_av_rc_id_ac[rc_id >> 4] & (1 << (rc_id & 0x0F)))
+ {
+ ret_code = BTA_AV_RSP_INTERIM;
+ }
+ }
+ }
+ return ret_code;
+}
+
+/*******************************************************************************
+**
+** Function bta_av_find_lcb
+**
+** Description Given BD_addr, find the associated LCB.
+**
+** Returns NULL, if not found.
+**
+*******************************************************************************/
+tBTA_AV_LCB * bta_av_find_lcb(BD_ADDR addr, UINT8 op)
+{
+ tBTA_AV_CB *p_cb = &bta_av_cb;
+ int xx;
+ UINT8 mask;
+ tBTA_AV_LCB *p_lcb = NULL;
+
+ for(xx=0; xx<BTA_AV_NUM_LINKS; xx++)
+ {
+ mask = 1 << xx; /* the used mask for this lcb */
+ if((mask & p_cb->conn_lcb) && 0 ==( bdcmp(p_cb->lcb[xx].addr, addr)))
+ {
+ p_lcb = &p_cb->lcb[xx];
+ if(op == BTA_AV_LCB_FREE)
+ {
+ p_cb->conn_lcb &= ~mask; /* clear the connect mask */
+ APPL_TRACE_DEBUG1("conn_lcb: 0x%x", p_cb->conn_lcb);
+ }
+ break;
+ }
+ }
+ return p_lcb;
+}
+
+/*******************************************************************************
+**
+** Function bta_av_rc_opened
+**
+** Description Set AVRCP state to opened.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_rc_opened(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
+{
+ tBTA_AV_RC_OPEN rc_open;
+ tBTA_AV_SCB *p_scb;
+ int i;
+ UINT8 shdl = 0;
+ tBTA_AV_LCB *p_lcb;
+ tBTA_AV_RCB *p_rcb;
+ UINT8 tmp;
+ UINT8 disc = 0;
+
+ /* find the SCB & stop the timer */
+ for(i=0; i<BTA_AV_NUM_STRS; i++)
+ {
+ p_scb = p_cb->p_scb[i];
+ if(p_scb && bdcmp(p_scb->peer_addr, p_data->rc_conn_chg.peer_addr) == 0)
+ {
+ p_scb->rc_handle = p_data->rc_conn_chg.handle;
+ APPL_TRACE_DEBUG2("bta_av_rc_opened shdl:%d, srch %d", i + 1, p_scb->rc_handle);
+ shdl = i+1;
+ APPL_TRACE_ERROR1("use_rc:%d", p_scb->use_rc);
+ bta_sys_stop_timer(&p_scb->timer);
+ disc = p_scb->hndl;
+ break;
+ }
+ }
+
+ i = p_data->rc_conn_chg.handle;
+ if (p_cb->rcb[i].handle == BTA_AV_RC_HANDLE_NONE)
+ {
+ APPL_TRACE_ERROR1("not a valid handle:%d any more", i);
+ return;
+ }
+
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE && AVCT_BROWSE_INCLUDED == TRUE)
+ /* listen to browsing channel when the connection is open,
+ - if peer initiated AVRCP connection and local device supports browsing channel */
+ if ((p_cb->features & BTA_AV_FEAT_BROWSE) && (p_cb->rcb[i].peer_features == 0))
+ AVRC_OpenBrowse (p_data->rc_conn_chg.handle, AVCT_ACP);
+#endif
+
+ if (p_cb->rcb[i].lidx == (BTA_AV_NUM_LINKS + 1) && shdl != 0)
+ {
+ /* rc is opened on the RC only ACP channel, but is for a specific SCB -> need to switch RCBs */
+ p_rcb = bta_av_get_rcb_by_shdl(shdl);
+ if (p_rcb)
+ {
+ p_rcb->shdl = p_cb->rcb[i].shdl;
+ tmp = p_rcb->lidx;
+ p_rcb->lidx = p_cb->rcb[i].lidx;
+ p_cb->rcb[i].lidx = tmp;
+ p_cb->rc_acp_handle = p_rcb->handle;
+ p_cb->rc_acp_idx = (p_rcb - p_cb->rcb) + 1;
+ APPL_TRACE_DEBUG2("switching RCB rc_acp_handle:%d idx:%d", p_cb->rc_acp_handle, p_cb->rc_acp_idx);
+ }
+ }
+
+ p_cb->rcb[i].shdl = shdl;
+ rc_open.rc_handle = i;
+ APPL_TRACE_ERROR4("bta_av_rc_opened rcb[%d] shdl:%d lidx:%d/%d",
+ i, shdl, p_cb->rcb[i].lidx, p_cb->lcb[BTA_AV_NUM_LINKS].lidx);
+ p_cb->rcb[i].status |= BTA_AV_RC_CONN_MASK;
+
+ if(!shdl && 0 == p_cb->lcb[BTA_AV_NUM_LINKS].lidx)
+ {
+ /* no associated SCB -> connected to an RC only device
+ * update the index to the extra LCB */
+ p_lcb = &p_cb->lcb[BTA_AV_NUM_LINKS];
+ bdcpy(p_lcb->addr, p_data->rc_conn_chg.peer_addr);
+ APPL_TRACE_DEBUG6("rc_only bd_addr:%02x-%02x-%02x-%02x-%02x-%02x",
+ p_lcb->addr[0], p_lcb->addr[1],
+ p_lcb->addr[2], p_lcb->addr[3],
+ p_lcb->addr[4], p_lcb->addr[5]);
+ p_lcb->lidx = BTA_AV_NUM_LINKS + 1;
+ p_cb->rcb[i].lidx = p_lcb->lidx;
+ p_lcb->conn_msk = 1;
+ APPL_TRACE_ERROR3("rcb[%d].lidx=%d, lcb.conn_msk=x%x",
+ i, p_cb->rcb[i].lidx, p_lcb->conn_msk);
+ disc = p_data->rc_conn_chg.handle|BTA_AV_CHNL_MSK;
+ }
+
+ bdcpy(rc_open.peer_addr, p_data->rc_conn_chg.peer_addr);
+ rc_open.peer_features = p_cb->rcb[i].peer_features;
+ rc_open.status = BTA_AV_SUCCESS;
+ APPL_TRACE_DEBUG2("local features:x%x peer_features:x%x", p_cb->features, rc_open.peer_features);
+ if(rc_open.peer_features == 0)
+ {
+ /* we have not done SDP on peer RC capabilities.
+ * peer must have initiated the RC connection */
+ rc_open.peer_features = BTA_AV_FEAT_RCCT;
+ bta_av_rc_disc(disc);
+ }
+ (*p_cb->p_cback)(BTA_AV_RC_OPEN_EVT, (tBTA_AV *) &rc_open);
+
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE && AVCT_BROWSE_INCLUDED == TRUE)
+ /* if local initiated AVRCP connection and both peer and locals device support browsing channel,
+ * open the browsing channel now */
+ if ((p_cb->features & BTA_AV_FEAT_BROWSE) && (rc_open.peer_features & BTA_AV_FEAT_BROWSE) &&
+ ((p_cb->rcb[i].status & BTA_AV_RC_ROLE_MASK) == BTA_AV_RC_ROLE_INT))
+ {
+ AVRC_OpenBrowse (p_data->rc_conn_chg.handle, AVCT_INT);
+ }
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function bta_av_rc_remote_cmd
+**
+** Description Send an AVRCP remote control command.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_rc_remote_cmd(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
+{
+ tBTA_AV_RCB *p_rcb;
+ if (p_cb->features & BTA_AV_FEAT_RCCT)
+ {
+ if(p_data->hdr.layer_specific < BTA_AV_NUM_RCB)
+ {
+ p_rcb = &p_cb->rcb[p_data->hdr.layer_specific];
+ if(p_rcb->status & BTA_AV_RC_CONN_MASK)
+ {
+ AVRC_PassCmd(p_rcb->handle, p_data->api_remote_cmd.label,
+ &p_data->api_remote_cmd.msg);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_rc_vendor_cmd
+**
+** Description Send an AVRCP vendor specific command.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_rc_vendor_cmd(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
+{
+ tBTA_AV_RCB *p_rcb;
+ if ( (p_cb->features & (BTA_AV_FEAT_RCCT | BTA_AV_FEAT_VENDOR)) ==
+ (BTA_AV_FEAT_RCCT | BTA_AV_FEAT_VENDOR))
+ {
+ if(p_data->hdr.layer_specific < BTA_AV_NUM_RCB)
+ {
+ p_rcb = &p_cb->rcb[p_data->hdr.layer_specific];
+ AVRC_VendorCmd(p_rcb->handle, p_data->api_vendor.label, &p_data->api_vendor.msg);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_rc_vendor_rsp
+**
+** Description Send an AVRCP vendor specific response.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_rc_vendor_rsp(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
+{
+ tBTA_AV_RCB *p_rcb;
+ if ( (p_cb->features & (BTA_AV_FEAT_RCTG | BTA_AV_FEAT_VENDOR)) ==
+ (BTA_AV_FEAT_RCTG | BTA_AV_FEAT_VENDOR))
+ {
+ if(p_data->hdr.layer_specific < BTA_AV_NUM_RCB)
+ {
+ p_rcb = &p_cb->rcb[p_data->hdr.layer_specific];
+ AVRC_VendorRsp(p_rcb->handle, p_data->api_vendor.label, &p_data->api_vendor.msg);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_rc_meta_rsp
+**
+** Description Send an AVRCP metadata/advanced control command/response.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_rc_meta_rsp(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
+{
+ tBTA_AV_RCB *p_rcb;
+ BOOLEAN free = TRUE;
+
+ if ((p_cb->features & BTA_AV_FEAT_METADATA) && (p_data->hdr.layer_specific < BTA_AV_NUM_RCB))
+ {
+ if ((p_data->api_meta_rsp.is_rsp && (p_cb->features & BTA_AV_FEAT_RCTG)) ||
+ (!p_data->api_meta_rsp.is_rsp && (p_cb->features & BTA_AV_FEAT_RCCT)) )
+ {
+ p_rcb = &p_cb->rcb[p_data->hdr.layer_specific];
+ AVRC_MsgReq(p_rcb->handle, p_data->api_meta_rsp.label, p_data->api_meta_rsp.rsp_code, p_data->api_meta_rsp.p_pkt);
+ free = FALSE;
+ }
+ }
+
+ if (free)
+ GKI_freebuf (p_data->api_meta_rsp.p_pkt);
+}
+
+/*******************************************************************************
+**
+** Function bta_av_rc_free_rsp
+**
+** Description free an AVRCP metadata command buffer.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_rc_free_rsp (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
+{
+ GKI_freebuf (p_data->api_meta_rsp.p_pkt);
+}
+
+/*******************************************************************************
+**
+** Function bta_av_rc_meta_req
+**
+** Description Send an AVRCP metadata command.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_rc_free_msg (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
+{
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+ if (p_data->rc_msg.opcode == AVRC_OP_BROWSE)
+ {
+ utl_freebuf ((void **)&p_data->rc_msg.msg.browse.p_browse_pkt);
+ }
+#endif
+#endif
+}
+
+
+
+/*******************************************************************************
+**
+** Function bta_av_chk_notif_evt_id
+**
+** Description make sure the requested player id is valid.
+**
+** Returns BTA_AV_STS_NO_RSP, if no error
+**
+*******************************************************************************/
+static tAVRC_STS bta_av_chk_notif_evt_id(tAVRC_MSG_VENDOR *p_vendor)
+{
+ tAVRC_STS status = BTA_AV_STS_NO_RSP;
+ UINT8 xx;
+ UINT16 u16;
+ UINT8 *p = p_vendor->p_vendor_data + 2;
+
+ BE_STREAM_TO_UINT16 (u16, p);
+ /* double check the fixed length */
+ if ((u16 != 5) || (p_vendor->vendor_len != 9))
+ {
+ status = AVRC_STS_INTERNAL_ERR;
+ }
+ else
+ {
+ /* make sure the player_id is valid */
+ for (xx=0; xx<p_bta_av_cfg->num_evt_ids; xx++)
+ {
+ if (*p == p_bta_av_cfg->p_meta_evt_ids[xx])
+ {
+ break;
+ }
+ }
+ if (xx == p_bta_av_cfg->num_evt_ids)
+ {
+ status = AVRC_STS_BAD_PARAM;
+ }
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function bta_av_proc_meta_cmd
+**
+** Description Process an AVRCP metadata command from the peer.
+**
+** Returns TRUE to respond immediately
+**
+*******************************************************************************/
+tBTA_AV_EVT bta_av_proc_meta_cmd(tAVRC_RESPONSE *p_rc_rsp, tBTA_AV_RC_MSG *p_msg, UINT8 *p_ctype)
+{
+ tBTA_AV_EVT evt = BTA_AV_META_MSG_EVT;
+ UINT8 u8, pdu, *p;
+ UINT16 u16;
+ tAVRC_MSG_VENDOR *p_vendor = &p_msg->msg.vendor;
+
+ pdu = *(p_vendor->p_vendor_data);
+ p_rc_rsp->pdu = pdu;
+ *p_ctype = AVRC_RSP_REJ;
+ /* Metadata messages only use PANEL sub-unit type */
+ if (p_vendor->hdr.subunit_type != AVRC_SUB_PANEL)
+ {
+ APPL_TRACE_DEBUG0("SUBUNIT must be PANEL");
+ /* reject it */
+ evt=0;
+ p_vendor->hdr.ctype = BTA_AV_RSP_NOT_IMPL;
+ AVRC_VendorRsp(p_msg->handle, p_msg->label, &p_msg->msg.vendor);
+ }
+ else if (!AVRC_IsValidAvcType(pdu, p_vendor->hdr.ctype) )
+ {
+ APPL_TRACE_DEBUG2("Invalid pdu/ctype: 0x%x, %d", pdu, p_vendor->hdr.ctype);
+ /* reject invalid message without reporting to app */
+ evt = 0;
+ p_rc_rsp->rsp.status = AVRC_STS_BAD_CMD;
+ }
+ else
+ {
+ switch (pdu)
+ {
+ case AVRC_PDU_GET_CAPABILITIES:
+ /* process GetCapabilities command without reporting the event to app */
+ evt = 0;
+ u8 = *(p_vendor->p_vendor_data + 4);
+ p = p_vendor->p_vendor_data + 2;
+ p_rc_rsp->get_caps.capability_id = u8;
+ BE_STREAM_TO_UINT16 (u16, p);
+ if ((u16 != 1) || (p_vendor->vendor_len != 5))
+ {
+ p_rc_rsp->get_caps.status = AVRC_STS_INTERNAL_ERR;
+ }
+ else
+ {
+ p_rc_rsp->get_caps.status = AVRC_STS_NO_ERROR;
+ if (u8 == AVRC_CAP_COMPANY_ID)
+ {
+ *p_ctype = AVRC_RSP_IMPL_STBL;
+ p_rc_rsp->get_caps.count = p_bta_av_cfg->num_co_ids;
+ memcpy(p_rc_rsp->get_caps.param.company_id, p_bta_av_cfg->p_meta_co_ids, (p_bta_av_cfg->num_co_ids << 2));
+ }
+ else if (u8 == AVRC_CAP_EVENTS_SUPPORTED)
+ {
+ *p_ctype = AVRC_RSP_IMPL_STBL;
+ p_rc_rsp->get_caps.count = p_bta_av_cfg->num_evt_ids;
+ memcpy(p_rc_rsp->get_caps.param.event_id, p_bta_av_cfg->p_meta_evt_ids, p_bta_av_cfg->num_evt_ids);
+ }
+ else
+ {
+ APPL_TRACE_DEBUG1("Invalid capability ID: 0x%x", u8);
+ /* reject - unknown capability ID */
+ p_rc_rsp->get_caps.status = AVRC_STS_BAD_PARAM;
+ }
+ }
+ break;
+
+
+ case AVRC_PDU_REGISTER_NOTIFICATION:
+ /* make sure the event_id is implemented */
+ p_rc_rsp->rsp.status = bta_av_chk_notif_evt_id (p_vendor);
+ if (p_rc_rsp->rsp.status != BTA_AV_STS_NO_RSP)
+ evt = 0;
+ break;
+
+ }
+ }
+
+ return evt;
+}
+
+
+/*******************************************************************************
+**
+** Function bta_av_rc_msg
+**
+** Description Process an AVRCP message from the peer.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_rc_msg(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
+{
+ tBTA_AV_EVT evt = 0;
+ tBTA_AV av;
+ BT_HDR *p_pkt = NULL;
+ tAVRC_MSG_VENDOR *p_vendor = &p_data->rc_msg.msg.vendor;
+#if (AVRC_METADATA_INCLUDED == TRUE)
+ tAVRC_STS res;
+ UINT8 ctype;
+ tAVRC_RESPONSE rc_rsp;
+
+ rc_rsp.rsp.status = BTA_AV_STS_NO_RSP;
+#endif
+
+ if (p_data->rc_msg.opcode == AVRC_OP_PASS_THRU)
+ {
+ /* if this is a pass thru command */
+ if (p_data->rc_msg.msg.hdr.ctype == AVRC_CMD_CTRL)
+ {
+ /* check if operation is supported */
+ if (p_data->rc_msg.msg.pass.op_id == AVRC_ID_VENDOR)
+ {
+ p_data->rc_msg.msg.hdr.ctype = BTA_AV_RSP_NOT_IMPL;
+#if (AVRC_METADATA_INCLUDED == TRUE)
+ if (p_cb->features & BTA_AV_FEAT_METADATA)
+ p_data->rc_msg.msg.hdr.ctype = bta_av_group_navi_supported(p_data->rc_msg.msg.pass.pass_len, p_data->rc_msg.msg.pass.p_pass_data);
+#endif
+ }
+ else
+ {
+ p_data->rc_msg.msg.hdr.ctype = bta_av_op_supported(p_data->rc_msg.msg.pass.op_id);
+ }
+
+ /* send response */
+ if (p_data->rc_msg.msg.hdr.ctype != BTA_AV_RSP_INTERIM)
+ AVRC_PassRsp(p_data->rc_msg.handle, p_data->rc_msg.label, &p_data->rc_msg.msg.pass);
+
+ /* set up for callback if supported */
+ if (p_data->rc_msg.msg.hdr.ctype == BTA_AV_RSP_ACCEPT || p_data->rc_msg.msg.hdr.ctype == BTA_AV_RSP_INTERIM)
+ {
+ evt = BTA_AV_REMOTE_CMD_EVT;
+ av.remote_cmd.rc_id = p_data->rc_msg.msg.pass.op_id;
+ av.remote_cmd.key_state = p_data->rc_msg.msg.pass.state;
+ av.remote_cmd.p_data = p_data->rc_msg.msg.pass.p_pass_data;
+ av.remote_cmd.len = p_data->rc_msg.msg.pass.pass_len;
+ memcpy(&av.remote_cmd.hdr, &p_data->rc_msg.msg.hdr, sizeof (tAVRC_HDR));
+ av.remote_cmd.label = p_data->rc_msg.label;
+ }
+ }
+ /* else if this is a pass thru response */
+ else if (p_data->rc_msg.msg.hdr.ctype >= AVRC_RSP_ACCEPT)
+ {
+ /* set up for callback */
+ evt = BTA_AV_REMOTE_RSP_EVT;
+ av.remote_rsp.rc_id = p_data->rc_msg.msg.pass.op_id;
+ av.remote_rsp.key_state = p_data->rc_msg.msg.pass.state;
+ av.remote_rsp.rsp_code = p_data->rc_msg.msg.hdr.ctype;
+ av.remote_rsp.label = p_data->rc_msg.label;
+ }
+ /* must be a bad ctype -> reject*/
+ else
+ {
+ p_data->rc_msg.msg.hdr.ctype = BTA_AV_RSP_REJ;
+ AVRC_PassRsp(p_data->rc_msg.handle, p_data->rc_msg.label, &p_data->rc_msg.msg.pass);
+ }
+ }
+ /* else if this is a vendor specific command or response */
+ else if (p_data->rc_msg.opcode == AVRC_OP_VENDOR)
+ {
+ /* set up for callback */
+ av.vendor_cmd.code = p_data->rc_msg.msg.hdr.ctype;
+ av.vendor_cmd.company_id = p_vendor->company_id;
+ av.vendor_cmd.label = p_data->rc_msg.label;
+ av.vendor_cmd.p_data = p_vendor->p_vendor_data;
+ av.vendor_cmd.len = p_vendor->vendor_len;
+
+ /* if configured to support vendor specific and it's a command */
+ if ((p_cb->features & BTA_AV_FEAT_VENDOR) &&
+ p_data->rc_msg.msg.hdr.ctype <= AVRC_CMD_GEN_INQ)
+ {
+#if (AVRC_METADATA_INCLUDED == TRUE)
+ if ((p_cb->features & BTA_AV_FEAT_METADATA) &&
+ (p_vendor->company_id == AVRC_CO_METADATA))
+ {
+ av.meta_msg.p_msg = &p_data->rc_msg.msg;
+ evt = bta_av_proc_meta_cmd (&rc_rsp, &p_data->rc_msg, &ctype);
+ }
+ else
+#endif
+ evt = BTA_AV_VENDOR_CMD_EVT;
+ }
+ /* else if configured to support vendor specific and it's a response */
+ else if ((p_cb->features & BTA_AV_FEAT_VENDOR) &&
+ p_data->rc_msg.msg.hdr.ctype >= AVRC_RSP_ACCEPT)
+ {
+#if (AVRC_METADATA_INCLUDED == TRUE)
+ if ((p_cb->features & BTA_AV_FEAT_METADATA) &&
+ (p_vendor->company_id == AVRC_CO_METADATA))
+ {
+ av.meta_msg.p_msg = &p_data->rc_msg.msg;
+ evt = BTA_AV_META_MSG_EVT;
+ }
+ else
+#endif
+ evt = BTA_AV_VENDOR_RSP_EVT;
+
+ }
+ /* else if not configured to support vendor specific and it's a command */
+ else if (!(p_cb->features & BTA_AV_FEAT_VENDOR) &&
+ p_data->rc_msg.msg.hdr.ctype <= AVRC_CMD_GEN_INQ)
+ {
+ /* reject it */
+ p_data->rc_msg.msg.hdr.ctype = BTA_AV_RSP_NOT_IMPL;
+ AVRC_VendorRsp(p_data->rc_msg.handle, p_data->rc_msg.label, &p_data->rc_msg.msg.vendor);
+ }
+ }
+#if (AVRC_METADATA_INCLUDED == TRUE)
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+ else if (p_data->rc_msg.opcode == AVRC_OP_BROWSE)
+ {
+ /* set up for callback */
+ av.meta_msg.code = p_data->rc_msg.msg.hdr.ctype;
+ av.meta_msg.company_id = p_vendor->company_id;
+ av.meta_msg.label = p_data->rc_msg.label;
+ av.meta_msg.p_data = p_data->rc_msg.msg.browse.p_browse_data;
+ av.meta_msg.len = p_data->rc_msg.msg.browse.browse_len;
+ av.meta_msg.p_msg = &p_data->rc_msg.msg;
+ evt = BTA_AV_META_MSG_EVT;
+ }
+#endif
+#endif
+
+ if (evt == 0 && rc_rsp.rsp.status != BTA_AV_STS_NO_RSP)
+ {
+ if (!p_pkt)
+ {
+ rc_rsp.rsp.opcode = p_data->rc_msg.opcode;
+ res = AVRC_BldResponse (0, &rc_rsp, &p_pkt);
+ }
+ if (p_pkt)
+ AVRC_MsgReq (p_data->rc_msg.handle, p_data->rc_msg.label, ctype, p_pkt);
+ }
+#endif
+
+ /* call callback */
+ if (evt != 0)
+ {
+ av.remote_cmd.rc_handle = p_data->rc_msg.handle;
+ (*p_cb->p_cback)(evt, &av);
+#if (AVRC_METADATA_INCLUDED == TRUE)
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+ /* If the application does not free the buffer or claim the ownership, free the buffer now */
+ if (p_data->rc_msg.opcode == AVRC_OP_BROWSE)
+ utl_freebuf((void **)&p_data->rc_msg.msg.browse.p_browse_pkt);
+#endif
+#endif
+#endif
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_rc_close
+**
+** Description close the specified AVRC handle.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_rc_close (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
+{
+ UINT16 handle = p_data->hdr.layer_specific;
+ tBTA_AV_SCB *p_scb;
+ tBTA_AV_RCB *p_rcb;
+
+ if(handle < BTA_AV_NUM_RCB)
+ {
+ p_rcb = &p_cb->rcb[handle];
+
+ APPL_TRACE_DEBUG2("bta_av_rc_close handle: %d, status=0x%x", p_rcb->handle, p_rcb->status);
+ if(p_rcb->handle != BTA_AV_RC_HANDLE_NONE)
+ {
+ if(p_rcb->shdl)
+ {
+ p_scb = bta_av_cb.p_scb[p_rcb->shdl - 1];
+ if(p_scb)
+ {
+ /* just in case the RC timer is active
+ if(bta_av_cb.features & BTA_AV_FEAT_RCCT &&
+ p_scb->chnl == BTA_AV_CHNL_AUDIO) */
+ bta_sys_stop_timer(&p_scb->timer);
+ }
+ }
+
+ AVRC_Close(p_rcb->handle);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_get_shdl
+**
+** Returns The index to p_scb[]
+**
+*******************************************************************************/
+static UINT8 bta_av_get_shdl(tBTA_AV_SCB *p_scb)
+{
+ int i;
+ UINT8 shdl = 0;
+ /* find the SCB & stop the timer */
+ for(i=0; i<BTA_AV_NUM_STRS; i++)
+ {
+ if(p_scb == bta_av_cb.p_scb[i])
+ {
+ shdl = i+1;
+ break;
+ }
+ }
+ return shdl;
+}
+
+/*******************************************************************************
+**
+** Function bta_av_stream_chg
+**
+** Description audio streaming status changed.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_stream_chg(tBTA_AV_SCB *p_scb, BOOLEAN started)
+{
+ UINT8 started_msk;
+ int i;
+ UINT8 *p_streams;
+ BOOLEAN no_streams = FALSE;
+ tBTA_AV_SCB *p_scbi;
+
+ started_msk = BTA_AV_HNDL_TO_MSK(p_scb->hdi);
+ APPL_TRACE_DEBUG3 ("bta_av_stream_chg started:%d started_msk:x%x chnl:x%x", started, started_msk, p_scb->chnl);
+ if (BTA_AV_CHNL_AUDIO == p_scb->chnl)
+ p_streams = &bta_av_cb.audio_streams;
+ else
+ p_streams = &bta_av_cb.video_streams;
+
+ if (started)
+ {
+ /* Let L2CAP know this channel is processed with high priority */
+ L2CA_SetAclPriority(p_scb->peer_addr, L2CAP_PRIORITY_HIGH);
+ (*p_streams) |= started_msk;
+ }
+ else
+ {
+ (*p_streams) &= ~started_msk;
+ }
+
+ if (!started)
+ {
+ i=0;
+ if (BTA_AV_CHNL_AUDIO == p_scb->chnl)
+ {
+ if (bta_av_cb.video_streams == 0)
+ no_streams = TRUE;
+ }
+ else
+ {
+ no_streams = TRUE;
+ if ( bta_av_cb.audio_streams )
+ {
+ for (; i<BTA_AV_NUM_STRS; i++)
+ {
+ p_scbi = bta_av_cb.p_scb[i];
+ if ( p_scbi && (bta_av_cb.audio_streams & BTA_AV_HNDL_TO_MSK(i)) /* scb is used and started */
+ && bdcmp(p_scbi->peer_addr, p_scb->peer_addr) == 0)
+ {
+ no_streams = FALSE;
+ break;
+ }
+ }
+
+ }
+ }
+
+ APPL_TRACE_DEBUG4 ("no_streams:%d i:%d, audio_streams:x%x, video_streams:x%x", no_streams, i, bta_av_cb.audio_streams, bta_av_cb.video_streams);
+ if (no_streams)
+ {
+ /* Let L2CAP know this channel is processed with low priority */
+ L2CA_SetAclPriority(p_scb->peer_addr, L2CAP_PRIORITY_NORMAL);
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function bta_av_conn_chg
+**
+** Description connetion status changed.
+** Open an AVRCP acceptor channel, if new conn.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_conn_chg(tBTA_AV_DATA *p_data)
+{
+ tBTA_AV_CB *p_cb = &bta_av_cb;
+ tBTA_AV_SCB *p_scb;
+ tBTA_AV_SCB *p_scbi;
+ UINT8 mask;
+ UINT8 conn_msk;
+ UINT8 old_msk;
+ int i;
+ int index = (p_data->hdr.layer_specific & BTA_AV_HNDL_MSK) - 1;
+ tBTA_AV_LCB *p_lcb;
+ tBTA_AV_LCB *p_lcb_rc;
+ tBTA_AV_RCB *p_rcb, *p_rcb2;
+ BOOLEAN chk_restore = FALSE;
+
+ p_scb = p_cb->p_scb[index];
+
+ mask = BTA_AV_HNDL_TO_MSK(index);
+ p_lcb = bta_av_find_lcb(p_data->conn_chg.peer_addr, BTA_AV_LCB_FIND);
+ conn_msk = 1 << (index + 1);
+ if(p_data->conn_chg.is_up)
+ {
+ /* set the conned mask for this channel */
+ if(p_scb)
+ {
+ if(p_lcb)
+ {
+ p_lcb->conn_msk |= conn_msk;
+ for (i=0; i<BTA_AV_NUM_RCB; i++)
+ {
+ if (bta_av_cb.rcb[i].lidx == p_lcb->lidx)
+ {
+ bta_av_cb.rcb[i].shdl = index + 1;
+ APPL_TRACE_DEBUG5("conn_chg up[%d]: %d, status=0x%x, shdl:%d, lidx:%d", i, bta_av_cb.rcb[i].handle, bta_av_cb.rcb[i].status, bta_av_cb.rcb[i].shdl, bta_av_cb.rcb[i].lidx);
+ break;
+ }
+ }
+ }
+ if (p_scb->chnl == BTA_AV_CHNL_AUDIO)
+ {
+ old_msk = p_cb->conn_audio;
+ p_cb->conn_audio |= mask;
+ }
+ else
+ {
+ old_msk = p_cb->conn_video;
+ p_cb->conn_video |= mask;
+ }
+
+ if ((old_msk & mask) == 0)
+ {
+ /* increase the audio open count, if not set yet */
+ bta_av_cb.audio_open_cnt++;
+ }
+
+
+ APPL_TRACE_DEBUG2("rc_acp_handle:%d rc_acp_idx:%d", p_cb->rc_acp_handle, p_cb->rc_acp_idx);
+ /* check if the AVRCP ACP channel is already connected */
+ if(p_lcb && p_cb->rc_acp_handle != BTA_AV_RC_HANDLE_NONE && p_cb->rc_acp_idx)
+ {
+ p_lcb_rc = &p_cb->lcb[BTA_AV_NUM_LINKS];
+ APPL_TRACE_DEBUG1("rc_acp is connected && conn_chg on same addr p_lcb_rc->conn_msk:x%x", p_lcb_rc->conn_msk);
+ /* check if the RC is connected to the scb addr */
+ APPL_TRACE_DEBUG6 ("p_lcb_rc->addr: %02x:%02x:%02x:%02x:%02x:%02x",
+ p_lcb_rc->addr[0], p_lcb_rc->addr[1], p_lcb_rc->addr[2], p_lcb_rc->addr[3], p_lcb_rc->addr[4], p_lcb_rc->addr[5]);
+ APPL_TRACE_DEBUG6 ("conn_chg.peer_addr: %02x:%02x:%02x:%02x:%02x:%02x",
+ p_data->conn_chg.peer_addr[0], p_data->conn_chg.peer_addr[1], p_data->conn_chg.peer_addr[2],
+ p_data->conn_chg.peer_addr[3], p_data->conn_chg.peer_addr[4], p_data->conn_chg.peer_addr[5]);
+ if (p_lcb_rc->conn_msk && bdcmp(p_lcb_rc->addr, p_data->conn_chg.peer_addr) == 0)
+ {
+ /* AVRCP is already connected.
+ * need to update the association betwen SCB and RCB */
+ p_lcb_rc->conn_msk = 0; /* indicate RC ONLY is not connected */
+ p_lcb_rc->lidx = 0;
+ p_scb->rc_handle = p_cb->rc_acp_handle;
+ p_rcb = &p_cb->rcb[p_cb->rc_acp_idx - 1];
+ p_rcb->shdl = bta_av_get_shdl(p_scb);
+ APPL_TRACE_DEBUG3("update rc_acp shdl:%d/%d srch:%d", index + 1, p_rcb->shdl, p_scb->rc_handle );
+
+ p_rcb2 = bta_av_get_rcb_by_shdl(p_rcb->shdl);
+ if (p_rcb2)
+ {
+ /* found the RCB that was created to associated with this SCB */
+ p_cb->rc_acp_handle = p_rcb2->handle;
+ p_cb->rc_acp_idx = (p_rcb2 - p_cb->rcb) + 1;
+ APPL_TRACE_DEBUG2("new rc_acp_handle:%d, idx:%d", p_cb->rc_acp_handle, p_cb->rc_acp_idx);
+ p_rcb2->lidx = (BTA_AV_NUM_LINKS + 1);
+ APPL_TRACE_DEBUG3("rc2 handle:%d lidx:%d/%d",p_rcb2->handle, p_rcb2->lidx, p_cb->lcb[p_rcb2->lidx-1].lidx);
+ }
+ p_rcb->lidx = p_lcb->lidx;
+ APPL_TRACE_DEBUG3("rc handle:%d lidx:%d/%d",p_rcb->handle, p_rcb->lidx, p_cb->lcb[p_rcb->lidx-1].lidx);
+ }
+ }
+ }
+ }
+ else
+ {
+ if ((p_cb->conn_audio & mask) && bta_av_cb.audio_open_cnt)
+ {
+ /* this channel is still marked as open. decrease the count */
+ bta_av_cb.audio_open_cnt--;
+ }
+
+ /* clear the conned mask for this channel */
+ p_cb->conn_audio &= ~mask;
+ p_cb->conn_video &= ~mask;
+ if(p_scb)
+ {
+ /* the stream is closed.
+ * clear the peer address, so it would not mess up the AVRCP for the next round of operation */
+ bdcpy(p_scb->peer_addr, bd_addr_null);
+ if(p_scb->chnl == BTA_AV_CHNL_AUDIO)
+ {
+ if(p_lcb)
+ {
+ p_lcb->conn_msk &= ~conn_msk;
+ }
+ /* audio channel is down. make sure the INT channel is down */
+ /* just in case the RC timer is active
+ if(p_cb->features & BTA_AV_FEAT_RCCT) */
+ {
+ bta_sys_stop_timer(&p_scb->timer);
+ }
+ /* one audio channel goes down. check if we need to restore high priority */
+ chk_restore = TRUE;
+ }
+ }
+
+ APPL_TRACE_DEBUG1("bta_av_conn_chg shdl:%d", index + 1);
+ for (i=0; i<BTA_AV_NUM_RCB; i++)
+ {
+ APPL_TRACE_DEBUG5("conn_chg dn[%d]: %d, status=0x%x, shdl:%d, lidx:%d", i, bta_av_cb.rcb[i].handle, bta_av_cb.rcb[i].status, bta_av_cb.rcb[i].shdl, bta_av_cb.rcb[i].lidx);
+ if(bta_av_cb.rcb[i].shdl == index + 1)
+ {
+ bta_av_del_rc(&bta_av_cb.rcb[i]);
+ break;
+ }
+ }
+
+ if(p_cb->conn_audio == 0 && p_cb->conn_video == 0)
+ {
+ /* if both channels are not connected,
+ * close all RC channels */
+ bta_av_close_all_rc(p_cb);
+ }
+
+ /* if the AVRCP is no longer listening, create the listening channel */
+ if (bta_av_cb.rc_acp_handle == BTA_AV_RC_HANDLE_NONE && bta_av_cb.features & BTA_AV_FEAT_RCTG)
+ bta_av_rc_create(&bta_av_cb, AVCT_ACP, 0, BTA_AV_NUM_LINKS + 1);
+ }
+
+ APPL_TRACE_DEBUG6("bta_av_conn_chg audio:%x video:%x up:%d conn_msk:0x%x chk_restore:%d audio_open_cnt:%d",
+ p_cb->conn_audio, p_cb->conn_video, p_data->conn_chg.is_up, conn_msk, chk_restore, p_cb->audio_open_cnt);
+
+ if (chk_restore)
+ {
+ if (p_cb->audio_open_cnt == 1)
+ {
+ /* one audio channel goes down and there's one audio channel remains open.
+ * restore the switch role in default link policy */
+ bta_sys_set_default_policy(BTA_ID_AV, HCI_ENABLE_MASTER_SLAVE_SWITCH);
+ /* allow role switch, if this is the last connection */
+ bta_av_restore_switch();
+ }
+ if (p_cb->audio_open_cnt)
+ {
+ /* adjust flush timeout settings to longer period */
+ for (i=0; i<BTA_AV_NUM_STRS; i++)
+ {
+ p_scbi = bta_av_cb.p_scb[i];
+ if (p_scbi && p_scbi->chnl == BTA_AV_CHNL_AUDIO && p_scbi->co_started)
+ {
+ /* may need to update the flush timeout of this already started stream */
+ if (p_scbi->co_started != bta_av_cb.audio_open_cnt)
+ {
+ p_scbi->co_started = bta_av_cb.audio_open_cnt;
+ L2CA_SetFlushTimeout(p_scbi->peer_addr, p_bta_av_cfg->p_audio_flush_to[p_scbi->co_started - 1] );
+ }
+ }
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_disable
+**
+** Description disable AV.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_disable(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
+{
+ BT_HDR hdr;
+ UINT16 xx;
+
+ p_cb->disabling = TRUE;
+
+ bta_av_close_all_rc(p_cb);
+
+ utl_freebuf((void **) &p_cb->p_disc_db);
+
+ /* disable audio/video - de-register all channels,
+ * expect BTA_AV_DEREG_COMP_EVT when deregister is complete */
+ for(xx=0; xx<BTA_AV_NUM_STRS; xx++)
+ {
+ hdr.layer_specific = xx + 1;
+ bta_av_api_deregister((tBTA_AV_DATA *)&hdr);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_api_disconnect
+**
+** Description .
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_api_disconnect(tBTA_AV_DATA *p_data)
+{
+ AVDT_DisconnectReq(p_data->api_discnt.bd_addr, bta_av_conn_cback);
+ bta_sys_stop_timer(&bta_av_cb.sig_tmr);
+}
+
+/*******************************************************************************
+**
+** Function bta_av_sig_chg
+**
+** Description process AVDT signal channel up/down.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_sig_chg(tBTA_AV_DATA *p_data)
+{
+ UINT16 event = p_data->str_msg.hdr.layer_specific;
+ tBTA_AV_CB *p_cb = &bta_av_cb;
+ int xx;
+ UINT8 mask;
+ tBTA_AV_LCB *p_lcb = NULL;
+
+ APPL_TRACE_DEBUG1("bta_av_sig_chg event: %d", event);
+ if(event == AVDT_CONNECT_IND_EVT)
+ {
+ p_lcb = bta_av_find_lcb(p_data->str_msg.bd_addr, BTA_AV_LCB_FIND);
+ if(!p_lcb)
+ {
+ /* if the address does not have an LCB yet, alloc one */
+ for(xx=0; xx<BTA_AV_NUM_LINKS; xx++)
+ {
+ mask = 1 << xx;
+ APPL_TRACE_DEBUG1("conn_lcb: 0x%x", p_cb->conn_lcb);
+ if(!(mask & p_cb->conn_lcb))
+ {
+ if (!p_cb->p_scb[xx])
+ {
+ /* We do not have scb for this avdt connection. */
+ /* Silently close the connection. */
+ APPL_TRACE_ERROR0("av scb not available for avdt connection");
+ AVDT_DisconnectReq (p_data->str_msg.bd_addr, NULL);
+ return;
+ }
+
+ p_lcb = &p_cb->lcb[xx];
+ p_lcb->lidx = xx + 1;
+ bdcpy(p_lcb->addr, p_data->str_msg.bd_addr);
+ p_lcb->conn_msk = 0; /* clear the connect mask */
+ /* start listening when the signal channel is open */
+ if (p_cb->features & BTA_AV_FEAT_RCTG)
+ {
+ bta_av_rc_create(p_cb, AVCT_ACP, 0, p_lcb->lidx);
+ }
+ /* this entry is not used yet. */
+ p_cb->conn_lcb |= mask; /* mark it as used */
+ APPL_TRACE_DEBUG1("start sig timer %d", p_data->hdr.offset);
+ if (p_data->hdr.offset == AVDT_ACP)
+ {
+ APPL_TRACE_DEBUG1("Incoming L2CAP acquired, set state as incoming", NULL);
+ bdcpy(p_cb->p_scb[xx]->peer_addr, p_data->str_msg.bd_addr);
+ p_cb->p_scb[xx]->use_rc = TRUE; /* allowing RC for incoming connection */
+ bta_av_ssm_execute(p_cb->p_scb[xx], BTA_AV_ACP_CONNECT_EVT, p_data);
+
+ bta_sys_start_timer(&p_cb->sig_tmr, BTA_AV_SIG_TIMER_EVT, BTA_AV_SIG_TIME_VAL);
+
+ /* Possible collision : need to avoid outgoing processing while the timer is running */
+ p_cb->p_scb[xx]->coll_mask = BTA_AV_COLL_INC_TMR;
+
+ p_cb->acp_sig_tmr.param = (UINT32)xx;
+ p_cb->acp_sig_tmr.p_cback = (TIMER_CBACK*)&bta_av_acp_sig_timer_cback;
+ bta_sys_start_timer(&p_cb->acp_sig_tmr, 0, BTA_AV_ACP_SIG_TIME_VAL);
+ }
+ break;
+ }
+ }
+ }
+ }
+#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
+ else if (event == BTA_AR_AVDT_CONN_EVT)
+ {
+ bta_sys_stop_timer(&bta_av_cb.sig_tmr);
+ }
+#endif
+ else
+ {
+ /* disconnected. */
+ p_lcb = bta_av_find_lcb(p_data->str_msg.bd_addr, BTA_AV_LCB_FREE);
+ if(p_lcb && p_lcb->conn_msk)
+ {
+ APPL_TRACE_DEBUG1("conn_msk: 0x%x", p_lcb->conn_msk);
+ /* clean up ssm */
+ for(xx=0; xx < BTA_AV_NUM_STRS; xx++)
+ {
+ mask = 1 << (xx + 1);
+ if ((mask & p_lcb->conn_msk) && (p_cb->p_scb[xx]) &&
+ (bdcmp(p_cb->p_scb[xx]->peer_addr, p_data->str_msg.bd_addr) == 0))
+ {
+ bta_av_ssm_execute(p_cb->p_scb[xx], BTA_AV_AVDT_DISCONNECT_EVT, NULL);
+ }
+ }
+ }
+ }
+ APPL_TRACE_DEBUG1("conn_lcb: 0x%x", p_cb->conn_lcb);
+}
+
+/*******************************************************************************
+**
+** Function bta_av_sig_timer
+**
+** Description process the signal channel timer. This timer is started
+** when the AVDTP signal channel is connected. If no profile
+** is connected, the timer goes off every BTA_AV_SIG_TIME_VAL
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_sig_timer(tBTA_AV_DATA *p_data)
+{
+ tBTA_AV_CB *p_cb = &bta_av_cb;
+ int xx;
+ UINT8 mask;
+ tBTA_AV_LCB *p_lcb = NULL;
+ tBTA_AV_PEND pend;
+
+ APPL_TRACE_DEBUG0("bta_av_sig_timer");
+ for(xx=0; xx<BTA_AV_NUM_LINKS; xx++)
+ {
+ mask = 1 << xx;
+ if(mask & p_cb->conn_lcb)
+ {
+ /* this entry is used. check if it is connected */
+ p_lcb = &p_cb->lcb[xx];
+ if(!p_lcb->conn_msk)
+ {
+ bta_sys_start_timer(&p_cb->sig_tmr, BTA_AV_SIG_TIMER_EVT, BTA_AV_SIG_TIME_VAL);
+ bdcpy(pend.bd_addr, p_lcb->addr);
+ (*p_cb->p_cback)(BTA_AV_PENDING_EVT, (tBTA_AV *) &pend);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_acp_sig_timer_cback
+**
+** Description Process the timeout when SRC is accepting connection
+** and SNK did not start signalling.
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_av_acp_sig_timer_cback (TIMER_LIST_ENT *p_tle)
+{
+ UINT8 inx = (UINT8)p_tle->param;
+ tBTA_AV_CB *p_cb = &bta_av_cb;
+ tBTA_AV_SCB *p_scb = p_cb->p_scb[inx];
+ tBTA_AV_API_OPEN *p_buf;
+
+ if (p_scb)
+ {
+ APPL_TRACE_DEBUG1("bta_av_acp_sig_timer_cback, coll_mask = 0x%02X", p_scb->coll_mask);
+
+ if (p_scb->coll_mask & BTA_AV_COLL_INC_TMR)
+ {
+ p_scb->coll_mask &= ~BTA_AV_COLL_INC_TMR;
+
+ if (bta_av_is_scb_opening(p_scb))
+ {
+ if (p_scb->p_disc_db)
+ {
+ /* We are still doing SDP. Run the timer again. */
+ p_scb->coll_mask |= BTA_AV_COLL_INC_TMR;
+
+ p_cb->acp_sig_tmr.param = (UINT32)inx;
+ p_cb->acp_sig_tmr.p_cback = (TIMER_CBACK *)&bta_av_acp_sig_timer_cback;
+ bta_sys_start_timer(&p_cb->acp_sig_tmr, 0, BTA_AV_ACP_SIG_TIME_VAL);
+ }
+ else
+ {
+ /* SNK did not start signalling, resume signalling process. */
+ bta_av_discover_req (p_scb, NULL);
+ }
+ }
+ else if (bta_av_is_scb_incoming(p_scb))
+ {
+ /* Stay in incoming state if SNK does not start signalling */
+
+ /* API open was called right after SNK opened L2C connection. */
+ if (p_scb->coll_mask & BTA_AV_COLL_API_CALLED)
+ {
+ p_scb->coll_mask &= ~BTA_AV_COLL_API_CALLED;
+
+ /* BTA_AV_API_OPEN_EVT */
+ if ((p_buf = (tBTA_AV_API_OPEN *) GKI_getbuf(sizeof(tBTA_AV_API_OPEN))) != NULL)
+ {
+ memcpy(p_buf, &(p_scb->open_api), sizeof(tBTA_AV_API_OPEN));
+ bta_sys_sendmsg(p_buf);
+ }
+ }
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_check_peer_features
+**
+** Description checks
+**
+** Returns void
+**
+*******************************************************************************/
+tBTA_AV_FEAT bta_av_check_peer_features (UINT16 service_uuid)
+{
+ tBTA_AV_FEAT peer_features = 0;
+ tBTA_AV_CB *p_cb = &bta_av_cb;
+ tSDP_DISC_REC *p_rec = NULL;
+ tSDP_DISC_ATTR *p_attr;
+ UINT16 peer_rc_version=0;
+ UINT16 categories = 0;
+
+ APPL_TRACE_DEBUG1("bta_av_check_peer_features service_uuid:x%x", service_uuid);
+ /* loop through all records we found */
+ while (TRUE)
+ {
+ /* get next record; if none found, we're done */
+ if ((p_rec = SDP_FindServiceInDb(p_cb->p_disc_db, service_uuid, p_rec)) == NULL)
+ {
+ break;
+ }
+
+ if (( SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_CLASS_ID_LIST)) != NULL)
+ {
+ /* find peer features */
+ if (SDP_FindServiceInDb(p_cb->p_disc_db, UUID_SERVCLASS_AV_REMOTE_CONTROL, NULL))
+ {
+ peer_features |= BTA_AV_FEAT_RCCT;
+ }
+ if (SDP_FindServiceInDb(p_cb->p_disc_db, UUID_SERVCLASS_AV_REM_CTRL_TARGET, NULL))
+ {
+ peer_features |= BTA_AV_FEAT_RCTG;
+ }
+ }
+
+ if (( SDP_FindAttributeInRec(p_rec, ATTR_ID_BT_PROFILE_DESC_LIST)) != NULL)
+ {
+ /* get profile version (if failure, version parameter is not updated) */
+ SDP_FindProfileVersionInRec(p_rec, UUID_SERVCLASS_AV_REMOTE_CONTROL, &peer_rc_version);
+ APPL_TRACE_DEBUG1("peer_rc_version 0x%x", peer_rc_version);
+
+ if (peer_rc_version >= AVRC_REV_1_3)
+ peer_features |= (BTA_AV_FEAT_VENDOR | BTA_AV_FEAT_METADATA);
+
+ if (peer_rc_version >= AVRC_REV_1_4)
+ {
+ peer_features |= (BTA_AV_FEAT_ADV_CTRL);
+ /* get supported categories */
+ if ((p_attr = SDP_FindAttributeInRec(p_rec,
+ ATTR_ID_SUPPORTED_FEATURES)) != NULL)
+ {
+ categories = p_attr->attr_value.v.u16;
+ if (categories & AVRC_SUPF_CT_BROWSE)
+ peer_features |= (BTA_AV_FEAT_BROWSE);
+ }
+ }
+ }
+ }
+ APPL_TRACE_DEBUG1("peer_features:x%x", peer_features);
+ return peer_features;
+}
+
+/*******************************************************************************
+**
+** Function bta_av_rc_disc_done
+**
+** Description Handle AVRCP service discovery results. If matching
+** service found, open AVRCP connection.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_rc_disc_done(tBTA_AV_DATA *p_data)
+{
+ tBTA_AV_CB *p_cb = &bta_av_cb;
+ tBTA_AV_SCB *p_scb = NULL;
+ tBTA_AV_LCB *p_lcb;
+ tBTA_AV_RC_OPEN rc_open;
+ tBTA_AV_RC_FEAT rc_feat;
+ UINT8 rc_handle;
+ tBTA_AV_FEAT peer_features; /* peer features mask */
+
+ APPL_TRACE_DEBUG1("bta_av_rc_disc_done disc:x%x", p_cb->disc);
+ if (!p_cb->disc)
+ {
+ return;
+ }
+
+ if ((p_cb->disc & BTA_AV_CHNL_MSK) == BTA_AV_CHNL_MSK)
+ {
+ /* this is the rc handle/index to tBTA_AV_RCB */
+ rc_handle = p_cb->disc & (~BTA_AV_CHNL_MSK);
+ }
+ else
+ {
+ p_scb = p_cb->p_scb[(p_cb->disc & BTA_AV_HNDL_MSK) - 1];
+ if (p_scb)
+ rc_handle = p_scb->rc_handle;
+ else
+ {
+ p_cb->disc = 0;
+ return;
+ }
+ }
+
+ APPL_TRACE_DEBUG1("rc_handle %d", rc_handle);
+ peer_features = bta_av_check_peer_features (UUID_SERVCLASS_AV_REMOTE_CONTROL);
+ if ((p_cb->features & BTA_AV_FEAT_ADV_CTRL) && ((peer_features&BTA_AV_FEAT_ADV_CTRL) == 0))
+ {
+ /* if we support advance control and peer does not, check their support on TG role
+ * some implementation uses 1.3 on CT ans 1.4 on TG */
+ peer_features |= bta_av_check_peer_features (UUID_SERVCLASS_AV_REM_CTRL_TARGET);
+ }
+
+ p_cb->disc = 0;
+ utl_freebuf((void **) &p_cb->p_disc_db);
+
+ APPL_TRACE_DEBUG2("peer_features 0x%x, features 0x%x", peer_features, p_cb->features);
+
+ /* if we have no rc connection */
+ if (rc_handle == BTA_AV_RC_HANDLE_NONE)
+ {
+ if (p_scb)
+ {
+ /* if peer remote control service matches ours and USE_RC is TRUE */
+ if ((((p_cb->features & BTA_AV_FEAT_RCCT) && (peer_features & BTA_AV_FEAT_RCTG)) ||
+ ((p_cb->features & BTA_AV_FEAT_RCTG) && (peer_features & BTA_AV_FEAT_RCCT))) )
+ {
+ p_lcb = bta_av_find_lcb(p_scb->peer_addr, BTA_AV_LCB_FIND);
+ if(p_lcb)
+ {
+ rc_handle = bta_av_rc_create(p_cb, AVCT_INT, (UINT8)(p_scb->hdi + 1), p_lcb->lidx);
+ p_cb->rcb[rc_handle].peer_features = peer_features;
+ }
+#if (BT_USE_TRACES == TRUE || BT_TRACE_APPL == TRUE)
+ else
+ {
+ APPL_TRACE_ERROR0("can not find LCB!!");
+ }
+#endif
+ }
+ else if(p_scb->use_rc)
+ {
+ /* can not find AVRC on peer device. report failure */
+ p_scb->use_rc = FALSE;
+ bdcpy(rc_open.peer_addr, p_scb->peer_addr);
+ rc_open.peer_features = 0;
+ rc_open.status = BTA_AV_FAIL_SDP;
+ (*p_cb->p_cback)(BTA_AV_RC_OPEN_EVT, (tBTA_AV *) &rc_open);
+ }
+ }
+ }
+ else
+ {
+ p_cb->rcb[rc_handle].peer_features = peer_features;
+ rc_feat.rc_handle = rc_handle;
+ rc_feat.peer_features = peer_features;
+ (*p_cb->p_cback)(BTA_AV_RC_FEAT_EVT, (tBTA_AV *) &rc_feat);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_rc_closed
+**
+** Description Set AVRCP state to closed.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_rc_closed(tBTA_AV_DATA *p_data)
+{
+ tBTA_AV_CB *p_cb = &bta_av_cb;
+ tBTA_AV_RC_CLOSE rc_close;
+ tBTA_AV_RC_CONN_CHG *p_msg = (tBTA_AV_RC_CONN_CHG *)p_data;
+ tBTA_AV_RCB *p_rcb;
+ tBTA_AV_SCB *p_scb;
+ int i;
+ BOOLEAN conn = FALSE;
+ tBTA_AV_LCB *p_lcb;
+
+ rc_close.rc_handle = BTA_AV_RC_HANDLE_NONE;
+ APPL_TRACE_DEBUG1("bta_av_rc_closed rc_handle:%d", p_msg->handle);
+ for(i=0; i<BTA_AV_NUM_RCB; i++)
+ {
+ p_rcb = &p_cb->rcb[i];
+ APPL_TRACE_DEBUG3("bta_av_rc_closed rcb[%d] rc_handle:%d, status=0x%x", i, p_rcb->handle, p_rcb->status);
+ if(p_rcb->handle == p_msg->handle)
+ {
+ rc_close.rc_handle = i;
+ p_rcb->status &= ~BTA_AV_RC_CONN_MASK;
+ p_rcb->peer_features = 0;
+ APPL_TRACE_DEBUG2(" shdl:%d, lidx:%d", p_rcb->shdl, p_rcb->lidx);
+ if(p_rcb->shdl)
+ {
+ p_scb = bta_av_cb.p_scb[p_rcb->shdl - 1];
+ if(p_scb)
+ {
+ bdcpy(rc_close.peer_addr, p_scb->peer_addr);
+ if(p_scb->rc_handle == p_rcb->handle)
+ p_scb->rc_handle = BTA_AV_RC_HANDLE_NONE;
+ APPL_TRACE_DEBUG2("shdl:%d, srch:%d", p_rcb->shdl, p_scb->rc_handle);
+ }
+ p_rcb->shdl = 0;
+ }
+ else if(p_rcb->lidx == (BTA_AV_NUM_LINKS + 1) )
+ {
+ /* if the RCB uses the extra LCB, use the addr for event and clean it */
+ p_lcb = &p_cb->lcb[BTA_AV_NUM_LINKS];
+ bdcpy(rc_close.peer_addr, p_msg->peer_addr);
+ APPL_TRACE_DEBUG6("rc_only closed bd_addr:%02x-%02x-%02x-%02x-%02x-%02x",
+ p_msg->peer_addr[0], p_msg->peer_addr[1],
+ p_msg->peer_addr[2], p_msg->peer_addr[3],
+ p_msg->peer_addr[4], p_msg->peer_addr[5]);
+ p_lcb->conn_msk = 0;
+ p_lcb->lidx = 0;
+ }
+ p_rcb->lidx = 0;
+
+ if((p_rcb->status & BTA_AV_RC_ROLE_MASK) == BTA_AV_RC_ROLE_INT)
+ {
+ /* AVCT CCB is deallocated */
+ p_rcb->handle = BTA_AV_RC_HANDLE_NONE;
+ p_rcb->status = 0;
+ }
+ else
+ {
+ /* AVCT CCB is still there. dealloc */
+ bta_av_del_rc(p_rcb);
+
+ /* if the AVRCP is no longer listening, create the listening channel */
+ if (bta_av_cb.rc_acp_handle == BTA_AV_RC_HANDLE_NONE && bta_av_cb.features & BTA_AV_FEAT_RCTG)
+ bta_av_rc_create(&bta_av_cb, AVCT_ACP, 0, BTA_AV_NUM_LINKS + 1);
+ }
+ }
+ else if((p_rcb->handle != BTA_AV_RC_HANDLE_NONE) && (p_rcb->status & BTA_AV_RC_CONN_MASK))
+ {
+ /* at least one channel is still connected */
+ conn = TRUE;
+ }
+ }
+
+ if(!conn)
+ {
+ /* no AVRC channels are connected, go back to INIT state */
+ bta_av_sm_execute(p_cb, BTA_AV_AVRC_NONE_EVT, NULL);
+ }
+
+ if (rc_close.rc_handle == BTA_AV_RC_HANDLE_NONE)
+ {
+ rc_close.rc_handle = p_msg->handle;
+ bdcpy(rc_close.peer_addr, p_msg->peer_addr);
+ }
+ (*p_cb->p_cback)(BTA_AV_RC_CLOSE_EVT, (tBTA_AV *) &rc_close);
+}
+
+/*******************************************************************************
+**
+** Function bta_av_rc_disc
+**
+** Description start AVRC SDP discovery.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_rc_disc(UINT8 disc)
+{
+ tBTA_AV_CB *p_cb = &bta_av_cb;
+ tAVRC_SDP_DB_PARAMS db_params;
+ UINT16 attr_list[] = {ATTR_ID_SERVICE_CLASS_ID_LIST,
+ ATTR_ID_BT_PROFILE_DESC_LIST,
+ ATTR_ID_SUPPORTED_FEATURES};
+ UINT8 hdi;
+ tBTA_AV_SCB *p_scb;
+ UINT8 *p_addr = NULL;
+ UINT8 rc_handle;
+
+ APPL_TRACE_DEBUG2("bta_av_rc_disc 0x%x, %d", disc, bta_av_cb.disc);
+ if ((bta_av_cb.disc != 0) || (disc == 0))
+ return;
+
+ if ((disc & BTA_AV_CHNL_MSK) == BTA_AV_CHNL_MSK)
+ {
+ /* this is the rc handle/index to tBTA_AV_RCB */
+ rc_handle = disc & (~BTA_AV_CHNL_MSK);
+ if (p_cb->rcb[rc_handle].lidx)
+ {
+ p_addr = p_cb->lcb[p_cb->rcb[rc_handle].lidx-1].addr;
+ }
+ }
+ else
+ {
+ hdi = (disc & BTA_AV_HNDL_MSK) - 1;
+ p_scb = p_cb->p_scb[hdi];
+
+ if (p_scb)
+ {
+ APPL_TRACE_DEBUG1("rc_handle %d", p_scb->rc_handle);
+ p_addr = p_scb->peer_addr;
+ }
+ }
+
+ if (p_addr)
+ {
+ /* allocate discovery database */
+ if (p_cb->p_disc_db == NULL)
+ {
+ p_cb->p_disc_db = (tSDP_DISCOVERY_DB *) GKI_getbuf(BTA_AV_DISC_BUF_SIZE);
+ }
+
+ if (p_cb->p_disc_db)
+ {
+ /* set up parameters */
+ db_params.db_len = BTA_AV_DISC_BUF_SIZE;
+ db_params.num_attr = 3;
+ db_params.p_db = p_cb->p_disc_db;
+ db_params.p_attrs = attr_list;
+
+ /* searching for UUID_SERVCLASS_AV_REMOTE_CONTROL gets both TG and CT */
+ if (AVRC_FindService(UUID_SERVCLASS_AV_REMOTE_CONTROL, p_addr, &db_params,
+ bta_av_avrc_sdp_cback) == AVRC_SUCCESS)
+ {
+ p_cb->disc = disc;
+ APPL_TRACE_DEBUG1("disc %d", p_cb->disc);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_dereg_comp
+**
+** Description deregister complete. free the stream control block.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_dereg_comp(tBTA_AV_DATA *p_data)
+{
+ tBTA_AV_CB *p_cb = &bta_av_cb;
+ tBTA_AV_SCB *p_scb;
+ tBTA_UTL_COD cod;
+ UINT8 mask;
+ BT_HDR *p_buf;
+
+ /* find the stream control block */
+ p_scb = bta_av_hndl_to_scb(p_data->hdr.layer_specific);
+
+ if(p_scb)
+ {
+ APPL_TRACE_DEBUG2("deregistered %d(h%d)", p_scb->chnl, p_scb->hndl);
+ mask = BTA_AV_HNDL_TO_MSK(p_scb->hdi);
+ if(p_scb->chnl == BTA_AV_CHNL_AUDIO)
+ {
+ p_cb->reg_audio &= ~mask;
+ if ((p_cb->conn_audio & mask) && bta_av_cb.audio_open_cnt)
+ {
+ /* this channel is still marked as open. decrease the count */
+ bta_av_cb.audio_open_cnt--;
+ }
+ p_cb->conn_audio &= ~mask;
+
+ if (p_scb->q_tag == BTA_AV_Q_TAG_STREAM)
+ {
+ /* make sure no buffers are in q_info.a2d */
+ while((p_buf = (BT_HDR*)GKI_dequeue (&p_scb->q_info.a2d)) != NULL)
+ GKI_freebuf(p_buf);
+ }
+
+ /* remove the A2DP SDP record, if no more audio stream is left */
+ if(!p_cb->reg_audio)
+ {
+#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
+ bta_ar_dereg_avrc (UUID_SERVCLASS_AV_REMOTE_CONTROL, BTA_ID_AV);
+#endif
+ bta_av_del_sdp_rec(&p_cb->sdp_a2d_handle);
+ bta_sys_remove_uuid(UUID_SERVCLASS_AUDIO_SOURCE);
+ }
+ }
+ else
+ {
+ p_cb->reg_video &= ~mask;
+ /* make sure that this channel is not connected */
+ p_cb->conn_video &= ~mask;
+ /* remove the VDP SDP record, (only one video stream at most) */
+ bta_av_del_sdp_rec(&p_cb->sdp_vdp_handle);
+ bta_sys_remove_uuid(UUID_SERVCLASS_VIDEO_SOURCE);
+ }
+
+ /* make sure that the timer is not active */
+ bta_sys_stop_timer(&p_scb->timer);
+ utl_freebuf((void **)&p_cb->p_scb[p_scb->hdi]);
+ }
+
+ APPL_TRACE_DEBUG3("audio 0x%x, video: 0x%x, disable:%d",
+ p_cb->reg_audio, p_cb->reg_video, p_cb->disabling);
+ /* if no stream control block is active */
+ if((p_cb->reg_audio + p_cb->reg_video) == 0)
+ {
+#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
+ /* deregister from AVDT */
+ bta_ar_dereg_avdt(BTA_ID_AV);
+
+ /* deregister from AVCT */
+ bta_ar_dereg_avrc (UUID_SERVCLASS_AV_REM_CTRL_TARGET, BTA_ID_AV);
+ bta_ar_dereg_avct(BTA_ID_AV);
+#endif
+
+ if(p_cb->disabling)
+ {
+ p_cb->disabling = FALSE;
+ bta_av_cb.features = 0;
+ }
+
+ /* Clear the Capturing service class bit */
+ cod.service = BTM_COD_SERVICE_CAPTURING;
+ utl_set_device_class(&cod, BTA_UTL_CLR_COD_SERVICE_CLASS);
+ }
+}
+#endif /* AV_INCLUDED */
diff --git a/bta/av/bta_av_api.c b/bta/av/bta_av_api.c
new file mode 100644
index 0000000..3bb59f7
--- /dev/null
+++ b/bta/av/bta_av_api.c
@@ -0,0 +1,568 @@
+/*****************************************************************************
+**
+** Name: bta_av_api.c
+**
+** Description: This is the implementation of the API for the advanced
+** audio/video (AV) subsystem of BTA, Widcomm's Bluetooth
+** application layer for mobile phones.
+**
+** Copyright (c) 2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+#if defined(AV_INCLUDED) && (AV_INCLUDED == TRUE)
+
+#include "bta_api.h"
+#include "bd.h"
+#include "bta_sys.h"
+#include "bta_av_api.h"
+#include "bta_av_int.h"
+#include "gki.h"
+#include <string.h>
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+static const tBTA_SYS_REG bta_av_reg =
+{
+ bta_av_hdl_event,
+ BTA_AvDisable
+};
+
+/*******************************************************************************
+**
+** Function BTA_AvEnable
+**
+** Description Enable the advanced audio/video service. When the enable
+** operation is complete the callback function will be
+** called with a BTA_AV_ENABLE_EVT. This function must
+** be called before other function in the AV API are
+** called.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AvEnable(tBTA_SEC sec_mask, tBTA_AV_FEAT features, tBTA_AV_CBACK *p_cback)
+{
+ tBTA_AV_API_ENABLE *p_buf;
+
+ /* register with BTA system manager */
+ GKI_sched_lock();
+ bta_sys_register(BTA_ID_AV, &bta_av_reg);
+ GKI_sched_unlock();
+
+ if ((p_buf = (tBTA_AV_API_ENABLE *) GKI_getbuf(sizeof(tBTA_AV_API_ENABLE))) != NULL)
+ {
+ p_buf->hdr.event = BTA_AV_API_ENABLE_EVT;
+ p_buf->p_cback = p_cback;
+ p_buf->features = features;
+ p_buf->sec_mask = sec_mask;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_AvDisable
+**
+** Description Disable the advanced audio/video service.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AvDisable(void)
+{
+ BT_HDR *p_buf;
+
+ bta_sys_deregister(BTA_ID_AV);
+ if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->event = BTA_AV_API_DISABLE_EVT;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_AvRegister
+**
+** Description Register the audio or video service to stack. When the
+** operation is complete the callback function will be
+** called with a BTA_AV_REGISTER_EVT. This function must
+** be called before AVDT stream is open.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AvRegister(tBTA_AV_CHNL chnl, const char *p_service_name, UINT8 app_id)
+{
+ tBTA_AV_API_REG *p_buf;
+
+
+ if ((p_buf = (tBTA_AV_API_REG *) GKI_getbuf(sizeof(tBTA_AV_API_REG))) != NULL)
+ {
+ p_buf->hdr.layer_specific = chnl;
+ p_buf->hdr.event = BTA_AV_API_REGISTER_EVT;
+ if(p_service_name)
+ {
+ BCM_STRNCPY_S(p_buf->p_service_name, sizeof(p_buf->p_service_name), p_service_name, BTA_SERVICE_NAME_LEN);
+ p_buf->p_service_name[BTA_SERVICE_NAME_LEN-1] = 0;
+ }
+ else
+ {
+ p_buf->p_service_name[0] = 0;
+ }
+ p_buf->app_id = app_id;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_AvDeregister
+**
+** Description Deregister the audio or video service
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AvDeregister(tBTA_AV_HNDL hndl)
+{
+ BT_HDR *p_buf;
+
+ if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->layer_specific = hndl;
+ p_buf->event = BTA_AV_API_DEREGISTER_EVT;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_AvOpen
+**
+** Description Opens an advanced audio/video connection to a peer device.
+** When connection is open callback function is called
+** with a BTA_AV_OPEN_EVT.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AvOpen(BD_ADDR bd_addr, tBTA_AV_HNDL handle, BOOLEAN use_rc, tBTA_SEC sec_mask)
+{
+ tBTA_AV_API_OPEN *p_buf;
+
+ if ((p_buf = (tBTA_AV_API_OPEN *) GKI_getbuf(sizeof(tBTA_AV_API_OPEN))) != NULL)
+ {
+ p_buf->hdr.event = BTA_AV_API_OPEN_EVT;
+ p_buf->hdr.layer_specific = handle;
+ bdcpy(p_buf->bd_addr, bd_addr);
+ p_buf->use_rc = use_rc;
+ p_buf->sec_mask = sec_mask;
+ p_buf->switch_res = BTA_AV_RS_NONE;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_AvClose
+**
+** Description Close the current streams.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AvClose(tBTA_AV_HNDL handle)
+{
+ BT_HDR *p_buf;
+
+ if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->event = BTA_AV_API_CLOSE_EVT;
+ p_buf->layer_specific = handle;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_AvDisconnect
+**
+** Description Close the connection to the address.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AvDisconnect(BD_ADDR bd_addr)
+{
+ tBTA_AV_API_DISCNT *p_buf;
+
+ if ((p_buf = (tBTA_AV_API_DISCNT *) GKI_getbuf(sizeof(tBTA_AV_API_DISCNT))) != NULL)
+ {
+ p_buf->hdr.event = BTA_AV_API_DISCONNECT_EVT;
+ bdcpy(p_buf->bd_addr, bd_addr);
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_AvStart
+**
+** Description Start audio/video stream data transfer.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AvStart(void)
+{
+ BT_HDR *p_buf;
+
+ if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->event = BTA_AV_API_START_EVT;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_AvStop
+**
+** Description Stop audio/video stream data transfer.
+** If suspend is TRUE, this function sends AVDT suspend signal
+** to the connected peer(s).
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AvStop(BOOLEAN suspend)
+{
+ tBTA_AV_API_STOP *p_buf;
+
+ if ((p_buf = (tBTA_AV_API_STOP *) GKI_getbuf(sizeof(tBTA_AV_API_STOP))) != NULL)
+ {
+ p_buf->hdr.event = BTA_AV_API_STOP_EVT;
+ p_buf->flush = TRUE;
+ p_buf->suspend = suspend;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_AvReconfig
+**
+** Description Reconfigure the audio/video stream.
+** If suspend is TRUE, this function tries the suspend/reconfigure
+** procedure first.
+** If suspend is FALSE or when suspend/reconfigure fails,
+** this function closes and re-opens the AVDT connection.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AvReconfig(tBTA_AV_HNDL hndl, BOOLEAN suspend, UINT8 sep_info_idx,
+ UINT8 *p_codec_info, UINT8 num_protect, UINT8 *p_protect_info)
+{
+ tBTA_AV_API_RCFG *p_buf;
+
+ if ((p_buf = (tBTA_AV_API_RCFG *) GKI_getbuf((UINT16) (sizeof(tBTA_AV_API_RCFG) + num_protect))) != NULL)
+ {
+ p_buf->hdr.layer_specific = hndl;
+ p_buf->hdr.event = BTA_AV_API_RECONFIG_EVT;
+ p_buf->num_protect = num_protect;
+ p_buf->suspend = suspend;
+ p_buf->sep_info_idx = sep_info_idx;
+ p_buf->p_protect_info = (UINT8 *)(p_buf + 1);
+ memcpy(p_buf->codec_info, p_codec_info, AVDT_CODEC_SIZE);
+ memcpy(p_buf->p_protect_info, p_protect_info, num_protect);
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_AvProtectReq
+**
+** Description Send a content protection request. This function can only
+** be used if AV is enabled with feature BTA_AV_FEAT_PROTECT.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AvProtectReq(tBTA_AV_HNDL hndl, UINT8 *p_data, UINT16 len)
+{
+ tBTA_AV_API_PROTECT_REQ *p_buf;
+
+ if ((p_buf = (tBTA_AV_API_PROTECT_REQ *) GKI_getbuf((UINT16) (sizeof(tBTA_AV_API_PROTECT_REQ) + len))) != NULL)
+ {
+ p_buf->hdr.layer_specific = hndl;
+ p_buf->hdr.event = BTA_AV_API_PROTECT_REQ_EVT;
+ p_buf->len = len;
+ if (p_data == NULL)
+ {
+ p_buf->p_data = NULL;
+ }
+ else
+ {
+ p_buf->p_data = (UINT8 *) (p_buf + 1);
+ memcpy(p_buf->p_data, p_data, len);
+ }
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_AvProtectRsp
+**
+** Description Send a content protection response. This function must
+** be called if a BTA_AV_PROTECT_REQ_EVT is received.
+** This function can only be used if AV is enabled with
+** feature BTA_AV_FEAT_PROTECT.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AvProtectRsp(tBTA_AV_HNDL hndl, UINT8 error_code, UINT8 *p_data, UINT16 len)
+{
+ tBTA_AV_API_PROTECT_RSP *p_buf;
+
+ if ((p_buf = (tBTA_AV_API_PROTECT_RSP *) GKI_getbuf((UINT16) (sizeof(tBTA_AV_API_PROTECT_RSP) + len))) != NULL)
+ {
+ p_buf->hdr.layer_specific = hndl;
+ p_buf->hdr.event = BTA_AV_API_PROTECT_RSP_EVT;
+ p_buf->len = len;
+ p_buf->error_code = error_code;
+ if (p_data == NULL)
+ {
+ p_buf->p_data = NULL;
+ }
+ else
+ {
+ p_buf->p_data = (UINT8 *) (p_buf + 1);
+ memcpy(p_buf->p_data, p_data, len);
+ }
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_AvRemoteCmd
+**
+** Description Send a remote control command. This function can only
+** be used if AV is enabled with feature BTA_AV_FEAT_RCCT.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AvRemoteCmd(UINT8 rc_handle, UINT8 label, tBTA_AV_RC rc_id, tBTA_AV_STATE key_state)
+{
+ tBTA_AV_API_REMOTE_CMD *p_buf;
+
+ if ((p_buf = (tBTA_AV_API_REMOTE_CMD *) GKI_getbuf(sizeof(tBTA_AV_API_REMOTE_CMD))) != NULL)
+ {
+ p_buf->hdr.event = BTA_AV_API_REMOTE_CMD_EVT;
+ p_buf->hdr.layer_specific = rc_handle;
+ p_buf->msg.op_id = rc_id;
+ p_buf->msg.state = key_state;
+ p_buf->msg.p_pass_data = NULL;
+ p_buf->msg.pass_len = 0;
+ p_buf->label = label;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_AvVendorCmd
+**
+** Description Send a vendor dependent remote control command. This
+** function can only be used if AV is enabled with feature
+** BTA_AV_FEAT_VENDOR.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AvVendorCmd(UINT8 rc_handle, UINT8 label, tBTA_AV_CODE cmd_code, UINT8 *p_data, UINT16 len)
+{
+ tBTA_AV_API_VENDOR *p_buf;
+
+ if ((p_buf = (tBTA_AV_API_VENDOR *) GKI_getbuf((UINT16) (sizeof(tBTA_AV_API_VENDOR) + len))) != NULL)
+ {
+ p_buf->hdr.event = BTA_AV_API_VENDOR_CMD_EVT;
+ p_buf->hdr.layer_specific = rc_handle;
+ p_buf->msg.hdr.ctype = cmd_code;
+ p_buf->msg.hdr.subunit_type = AVRC_SUB_PANEL;
+ p_buf->msg.hdr.subunit_id = 0;
+ p_buf->msg.company_id = p_bta_av_cfg->company_id;
+ p_buf->label = label;
+ p_buf->msg.vendor_len = len;
+ if (p_data == NULL)
+ {
+ p_buf->msg.p_vendor_data = NULL;
+ }
+ else
+ {
+ p_buf->msg.p_vendor_data = (UINT8 *) (p_buf + 1);
+ memcpy(p_buf->msg.p_vendor_data, p_data, len);
+ }
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_AvVendorRsp
+**
+** Description Send a vendor dependent remote control response.
+** This function must be called if a BTA_AV_VENDOR_CMD_EVT
+** is received. This function can only be used if AV is
+** enabled with feature BTA_AV_FEAT_VENDOR.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AvVendorRsp(UINT8 rc_handle, UINT8 label, tBTA_AV_CODE rsp_code, UINT8 *p_data, UINT16 len, UINT32 company_id)
+{
+ tBTA_AV_API_VENDOR *p_buf;
+
+ if ((p_buf = (tBTA_AV_API_VENDOR *) GKI_getbuf((UINT16) (sizeof(tBTA_AV_API_VENDOR) + len))) != NULL)
+ {
+ p_buf->hdr.event = BTA_AV_API_VENDOR_RSP_EVT;
+ p_buf->hdr.layer_specific = rc_handle;
+ p_buf->msg.hdr.ctype = rsp_code;
+ p_buf->msg.hdr.subunit_type = AVRC_SUB_PANEL;
+ p_buf->msg.hdr.subunit_id = 0;
+ if(company_id)
+ p_buf->msg.company_id = company_id;
+ else
+ p_buf->msg.company_id = p_bta_av_cfg->company_id;
+ p_buf->label = label;
+ p_buf->msg.vendor_len = len;
+ if (p_data == NULL)
+ {
+ p_buf->msg.p_vendor_data = NULL;
+ }
+ else
+ {
+ p_buf->msg.p_vendor_data = (UINT8 *) (p_buf + 1);
+ memcpy(p_buf->msg.p_vendor_data, p_data, len);
+ }
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_AvOpenRc
+**
+** Description Open an AVRCP connection toward the device with the
+** specified handle
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AvOpenRc(tBTA_AV_HNDL handle)
+{
+ tBTA_AV_API_OPEN_RC *p_buf;
+
+ if ((p_buf = (tBTA_AV_API_OPEN_RC *) GKI_getbuf(sizeof(tBTA_AV_API_OPEN_RC))) != NULL)
+ {
+ p_buf->hdr.event = BTA_AV_API_RC_OPEN_EVT;
+ p_buf->hdr.layer_specific = handle;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_AvCloseRc
+**
+** Description Close an AVRCP connection
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AvCloseRc(UINT8 rc_handle)
+{
+ tBTA_AV_API_CLOSE_RC *p_buf;
+
+ if ((p_buf = (tBTA_AV_API_CLOSE_RC *) GKI_getbuf(sizeof(tBTA_AV_API_CLOSE_RC))) != NULL)
+ {
+ p_buf->hdr.event = BTA_AV_API_RC_CLOSE_EVT;
+ p_buf->hdr.layer_specific = rc_handle;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_AvMetaRsp
+**
+** Description Send a Metadata/Advanced Control response. The message contained
+** in p_pkt can be composed with AVRC utility functions.
+** This function can only be used if AV is enabled with feature
+** BTA_AV_FEAT_METADATA.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AvMetaRsp(UINT8 rc_handle, UINT8 label, tBTA_AV_CODE rsp_code,
+ BT_HDR *p_pkt)
+{
+ tBTA_AV_API_META_RSP *p_buf;
+
+ if ((p_buf = (tBTA_AV_API_META_RSP *) GKI_getbuf((UINT16) (sizeof(tBTA_AV_API_META_RSP)))) != NULL)
+ {
+ p_buf->hdr.event = BTA_AV_API_META_RSP_EVT;
+ p_buf->hdr.layer_specific = rc_handle;
+ p_buf->rsp_code = rsp_code;
+ p_buf->p_pkt = p_pkt;
+ p_buf->is_rsp = TRUE;
+ p_buf->label = label;
+
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_AvMetaCmd
+**
+** Description Send a Metadata/Advanced Control command. The message contained
+** in p_pkt can be composed with AVRC utility functions.
+** This function can only be used if AV is enabled with feature
+** BTA_AV_FEAT_METADATA.
+** This message is sent only when the peer supports the TG role.
+*8 The only command makes sense right now is the absolute volume command.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AvMetaCmd(UINT8 rc_handle, UINT8 label, tBTA_AV_CMD cmd_code, BT_HDR *p_pkt)
+{
+ tBTA_AV_API_META_RSP *p_buf;
+
+ if ((p_buf = (tBTA_AV_API_META_RSP *) GKI_getbuf((UINT16) (sizeof(tBTA_AV_API_META_RSP)))) != NULL)
+ {
+ p_buf->hdr.event = BTA_AV_API_META_RSP_EVT;
+ p_buf->hdr.layer_specific = rc_handle;
+ p_buf->p_pkt = p_pkt;
+ p_buf->rsp_code = cmd_code;
+ p_buf->is_rsp = FALSE;
+ p_buf->label = label;
+
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+#endif /* AV_INCLUDED */
diff --git a/bta/av/bta_av_cfg.c b/bta/av/bta_av_cfg.c
new file mode 100644
index 0000000..bb01366
--- /dev/null
+++ b/bta/av/bta_av_cfg.c
@@ -0,0 +1,276 @@
+/*****************************************************************************
+**
+** Name: bta_av_cfg.c
+**
+** Description: This file contains compile-time configurable constants
+** for advanced audio/video
+**
+** Copyright (c) 2005-2009, Broadcom Corp., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+#include "gki.h"
+#include "bta_api.h"
+#include "bta_av_int.h"
+
+#ifndef BTA_AV_VDP_INCLUDED
+#define BTA_AV_VDP_INCLUDED TRUE
+#endif
+
+#if ((VDP_INCLUDED == FALSE) && (BTA_AV_VDP_INCLUDED == TRUE))
+#undef BTA_AV_VDP_INCLUDED
+#define BTA_AV_VDP_INCLUDED FALSE
+#endif
+
+#ifndef BTA_AV_RC_PASS_RSP_CODE
+#define BTA_AV_RC_PASS_RSP_CODE BTA_AV_RSP_NOT_IMPL
+#endif
+
+#if (BTA_AV_VDP_INCLUDED == TRUE)
+#define BTA_AV_NUM_A2DP_STRS (BTA_AV_NUM_STRS - 1)
+#else
+#define BTA_AV_NUM_A2DP_STRS (BTA_AV_NUM_STRS)
+#endif
+
+const UINT32 bta_av_meta_caps_co_ids[] = {
+ AVRC_CO_METADATA,
+ AVRC_CO_BROADCOM
+};
+
+/* AVRCP cupported categories */
+#define BTA_AV_RC_SUPF_CT (AVRC_SUPF_CT_CAT2)
+
+
+/* Added to modify
+** 1. flush timeout
+** 2. Remove Group navigation support in SupportedFeatures
+** 3. GetCapabilities supported event_ids list
+** 4. GetCapabilities supported event_ids count
+*/
+#ifdef ANDROID_APP_INCLUDED
+/* Flushing partial avdtp packets can cause some headsets to disconnect the link
+ if receiving partial a2dp frames */
+const UINT16 bta_av_audio_flush_to[] = {
+ 0, /* 1 stream */
+ 0, /* 2 streams */
+ 0, /* 3 streams */
+ 0, /* 4 streams */
+ 0 /* 5 streams */
+}; /* AVDTP audio transport channel flush timeout */
+
+/* Note: Android doesnt support AVRC_SUPF_TG_GROUP_NAVI */
+#if AVRC_ADV_CTRL_INCLUDED == TRUE
+#define BTA_AV_RC_SUPF_TG (AVRC_SUPF_TG_CAT1|AVRC_SUPF_TG_APP_SETTINGS|AVRC_SUPF_TG_BROWSE|AVRC_SUPF_TG_MULTI_PLAYER)
+#else
+#if AVRC_METADATA_INCLUDED == TRUE
+#define BTA_AV_RC_SUPF_TG (AVRC_SUPF_TG_CAT1|AVRC_SUPF_TG_APP_SETTINGS)
+#else
+#define BTA_AV_RC_SUPF_TG (AVRC_SUPF_TG_CAT1)
+#endif
+#endif
+
+
+/*
+ * If the number of event IDs is changed in this array, BTA_AV_ NUM_RC_EVT_IDS also needs to be changed.
+ */
+const UINT8 bta_av_meta_caps_evt_ids[] = {
+ AVRC_EVT_PLAY_STATUS_CHANGE,
+ AVRC_EVT_TRACK_CHANGE,
+ AVRC_EVT_PLAY_POS_CHANGED,
+ AVRC_EVT_APP_SETTING_CHANGE,
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
+ AVRC_EVT_NOW_PLAYING_CHANGE,
+ AVRC_EVT_AVAL_PLAYERS_CHANGE,
+ AVRC_EVT_ADDR_PLAYER_CHANGE,
+// AVRC_EVT_UIDS_CHANGE,
+ AVRC_EVT_VOLUME_CHANGE
+#endif
+};
+#ifndef BTA_AV_NUM_RC_EVT_IDS
+#define BTA_AV_NUM_RC_EVT_IDS (sizeof(bta_av_meta_caps_evt_ids) / sizeof(bta_av_meta_caps_evt_ids[0]))
+#endif /* BTA_AV_NUM_RC_EVT_IDS */
+
+
+#else /* !ANDROID_APP_INCLUDED */
+
+/* Note: if AVRC_SUPF_TG_GROUP_NAVI is set, bta_av_cfg.avrc_group should be TRUE */
+#if AVRC_ADV_CTRL_INCLUDED == TRUE
+#define BTA_AV_RC_SUPF_TG (AVRC_SUPF_TG_CAT1|AVRC_SUPF_TG_APP_SETTINGS|AVRC_SUPF_TG_GROUP_NAVI|AVRC_SUPF_TG_BROWSE|AVRC_SUPF_TG_MULTI_PLAYER)
+#else
+#if AVRC_METADATA_INCLUDED == TRUE
+#define BTA_AV_RC_SUPF_TG (AVRC_SUPF_TG_CAT1|AVRC_SUPF_TG_APP_SETTINGS|AVRC_SUPF_TG_GROUP_NAVI)
+#else
+#define BTA_AV_RC_SUPF_TG (AVRC_SUPF_TG_CAT1)
+#endif
+#endif
+
+const UINT16 bta_av_audio_flush_to[] = {
+ 120, /* 1 stream */
+ 100, /* 2 streams */
+ 80, /* 3 streams */
+ 60, /* 4 streams */
+ 40 /* 5 streams */
+}; /* AVDTP audio transport channel flush timeout */
+
+
+/*
+ * If the number of event IDs is changed in this array, BTA_AV_ NUM_RC_EVT_IDS also needs to be changed.
+ */
+const UINT8 bta_av_meta_caps_evt_ids[] = {
+ AVRC_EVT_PLAY_STATUS_CHANGE,
+ AVRC_EVT_TRACK_CHANGE,
+ AVRC_EVT_TRACK_REACHED_END,
+ AVRC_EVT_TRACK_REACHED_START,
+ AVRC_EVT_PLAY_POS_CHANGED,
+ AVRC_EVT_BATTERY_STATUS_CHANGE,
+ AVRC_EVT_SYSTEM_STATUS_CHANGE,
+ AVRC_EVT_APP_SETTING_CHANGE,
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
+ AVRC_EVT_NOW_PLAYING_CHANGE,
+ AVRC_EVT_AVAL_PLAYERS_CHANGE,
+ AVRC_EVT_ADDR_PLAYER_CHANGE,
+ AVRC_EVT_UIDS_CHANGE,
+ AVRC_EVT_VOLUME_CHANGE
+#endif
+};
+
+#ifndef BTA_AV_NUM_RC_EVT_IDS
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
+#define BTA_AV_NUM_RC_EVT_IDS 13
+#else
+#define BTA_AV_NUM_RC_EVT_IDS 8
+#endif
+#endif
+
+#endif /* ANDROID_APP_INCLUDED */
+
+/* the MTU for the AVRCP browsing channel */
+#ifndef BTA_AV_MAX_RC_BR_MTU
+#define BTA_AV_MAX_RC_BR_MTU 1008
+#endif
+
+const tBTA_AV_CFG bta_av_cfg =
+{
+ AVRC_CO_BROADCOM, /* AVRCP Company ID */
+#if AVRC_METADATA_INCLUDED == TRUE
+ 512, /* AVRCP MTU at L2CAP for control channel */
+ BTA_AV_MAX_RC_BR_MTU, /* AVRCP MTU at L2CAP for browsing channel */
+#else
+ 48, /* AVRCP MTU at L2CAP for control channel */
+ BTA_AV_MAX_RC_BR_MTU, /* AVRCP MTU at L2CAP for browsing channel */
+#endif
+ BTA_AV_RC_SUPF_CT, /* AVRCP controller categories */
+ BTA_AV_RC_SUPF_TG, /* AVRCP target categories */
+ 672, /* AVDTP signaling channel MTU at L2CAP */
+ BTA_AV_MAX_A2DP_MTU, /* AVDTP audio transport channel MTU at L2CAP */
+ bta_av_audio_flush_to, /* AVDTP audio transport channel flush timeout */
+ 6, /* AVDTP audio channel max data queue size */
+ BTA_AV_MAX_VDP_MTU, /* AVDTP video transport channel MTU at L2CAP */
+ 600, /* AVDTP video transport channel flush timeout */
+ TRUE, /* TRUE, to accept AVRC 1.3 group nevigation command */
+ 2, /* company id count in p_meta_co_ids */
+ BTA_AV_NUM_RC_EVT_IDS, /* event id count in p_meta_evt_ids */
+ BTA_AV_RC_PASS_RSP_CODE,/* the default response code for pass through commands */
+ bta_av_meta_caps_co_ids,/* the metadata Get Capabilities response for company id */
+ bta_av_meta_caps_evt_ids,/* the the metadata Get Capabilities response for event id */
+#if BTA_AV_VDP_INCLUDED == TRUE
+ (const tBTA_AV_ACT *)bta_av_vdp_action,/* the action table for VDP */
+ bta_av_reg_vdp /* action function to register VDP */
+#else
+ (const tBTA_AV_ACT *)NULL,/* the action table for VDP */
+ NULL /* action function to register VDP */
+#endif
+};
+
+tBTA_AV_CFG *p_bta_av_cfg = (tBTA_AV_CFG *) &bta_av_cfg;
+
+const UINT16 bta_av_rc_id[] =
+{
+ 0x021F, /* bit mask: 0=SELECT, 1=UP, 2=DOWN, 3=LEFT,
+ 4=RIGHT, 5=RIGHT_UP, 6=RIGHT_DOWN, 7=LEFT_UP,
+ 8=LEFT_DOWN, 9=ROOT_MENU, 10=SETUP_MENU, 11=CONT_MENU,
+ 12=FAV_MENU, 13=EXIT */
+
+ 0, /* not used */
+
+ 0x0000, /* bit mask: 0=0, 1=1, 2=2, 3=3,
+ 4=4, 5=5, 6=6, 7=7,
+ 8=8, 9=9, 10=DOT, 11=ENTER,
+ 12=CLEAR */
+
+ 0x0003, /* bit mask: 0=CHAN_UP, 1=CHAN_DOWN, 2=PREV_CHAN, 3=SOUND_SEL,
+ 4=INPUT_SEL, 5=DISP_INFO, 6=HELP, 7=PAGE_UP,
+ 8=PAGE_DOWN */
+
+#if (BTA_AV_RC_PASS_RSP_CODE == BTA_AV_RSP_INTERIM)
+ /* btui_app provides an example of how to leave the decision of rejecting a command or not
+ * based on which media player is currently addressed (this is only applicable for AVRCP 1.4 or later)
+ * If the decision is per player for a particular rc_id, the related bit is clear (not set) */
+ 0x0070, /* bit mask: 0=POWER, 1=VOL_UP, 2=VOL_DOWN, 3=MUTE,
+ 4=PLAY, 5=STOP, 6=PAUSE, 7=RECORD,
+ 8=REWIND, 9=FAST_FOR, 10=EJECT, 11=FORWARD,
+ 12=BACKWARD */
+#else
+#if (defined BTA_AVRCP_FF_RW_SUPPORT) && (BTA_AVRCP_FF_RW_SUPPORT == TRUE)
+ 0x1b70, /* bit mask: 0=POWER, 1=VOL_UP, 2=VOL_DOWN, 3=MUTE,
+ 4=PLAY, 5=STOP, 6=PAUSE, 7=RECORD,
+ 8=REWIND, 9=FAST_FOR, 10=EJECT, 11=FORWARD,
+ 12=BACKWARD */
+#else
+ 0x1870, /* bit mask: 0=POWER, 1=VOL_UP, 2=VOL_DOWN, 3=MUTE,
+ 4=PLAY, 5=STOP, 6=PAUSE, 7=RECORD,
+ 8=REWIND, 9=FAST_FOR, 10=EJECT, 11=FORWARD,
+ 12=BACKWARD */
+#endif
+#endif
+
+ 0x0000, /* bit mask: 0=ANGLE, 1=SUBPICT */
+
+ 0, /* not used */
+
+ 0x0000 /* bit mask: 0=not used, 1=F1, 2=F2, 3=F3,
+ 4=F4, 5=F5 */
+};
+
+#if (BTA_AV_RC_PASS_RSP_CODE == BTA_AV_RSP_INTERIM)
+const UINT16 bta_av_rc_id_ac[] =
+{
+ 0x0000, /* bit mask: 0=SELECT, 1=UP, 2=DOWN, 3=LEFT,
+ 4=RIGHT, 5=RIGHT_UP, 6=RIGHT_DOWN, 7=LEFT_UP,
+ 8=LEFT_DOWN, 9=ROOT_MENU, 10=SETUP_MENU, 11=CONT_MENU,
+ 12=FAV_MENU, 13=EXIT */
+
+ 0, /* not used */
+
+ 0x0000, /* bit mask: 0=0, 1=1, 2=2, 3=3,
+ 4=4, 5=5, 6=6, 7=7,
+ 8=8, 9=9, 10=DOT, 11=ENTER,
+ 12=CLEAR */
+
+ 0x0000, /* bit mask: 0=CHAN_UP, 1=CHAN_DOWN, 2=PREV_CHAN, 3=SOUND_SEL,
+ 4=INPUT_SEL, 5=DISP_INFO, 6=HELP, 7=PAGE_UP,
+ 8=PAGE_DOWN */
+
+ /* btui_app provides an example of how to leave the decision of rejecting a command or not
+ * based on which media player is currently addressed (this is only applicable for AVRCP 1.4 or later)
+ * If the decision is per player for a particular rc_id, the related bit is set */
+ 0x1800, /* bit mask: 0=POWER, 1=VOL_UP, 2=VOL_DOWN, 3=MUTE,
+ 4=PLAY, 5=STOP, 6=PAUSE, 7=RECORD,
+ 8=REWIND, 9=FAST_FOR, 10=EJECT, 11=FORWARD,
+ 12=BACKWARD */
+
+ 0x0000, /* bit mask: 0=ANGLE, 1=SUBPICT */
+
+ 0, /* not used */
+
+ 0x0000 /* bit mask: 0=not used, 1=F1, 2=F2, 3=F3,
+ 4=F4, 5=F5 */
+};
+UINT16 *p_bta_av_rc_id_ac = (UINT16 *) bta_av_rc_id_ac;
+#else
+UINT16 *p_bta_av_rc_id_ac = NULL;
+#endif
+
+UINT16 *p_bta_av_rc_id = (UINT16 *) bta_av_rc_id;
diff --git a/bta/av/bta_av_ci.c b/bta/av/bta_av_ci.c
new file mode 100644
index 0000000..c182948
--- /dev/null
+++ b/bta/av/bta_av_ci.c
@@ -0,0 +1,85 @@
+/*****************************************************************************
+**
+** Name: bta_av_ci.c
+**
+** Description: This is the implementation file for advanced audio/video
+** call-in functions.
+**
+** Copyright (c) 2005, Widcomm Inc., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bta_api.h"
+#include "bta_sys.h"
+#include "bta_av_int.h"
+#include "bta_av_ci.h"
+
+#include <string.h>
+
+/*******************************************************************************
+**
+** Function bta_av_ci_src_data_ready
+**
+** Description This function sends an event to the AV indicating that
+** the phone has audio stream data ready to send and AV
+** should call bta_av_co_audio_src_data_path() or
+** bta_av_co_video_src_data_path().
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_ci_src_data_ready(tBTA_AV_CHNL chnl)
+{
+ BT_HDR *p_buf;
+
+ if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->layer_specific = chnl;
+ p_buf->event = BTA_AV_CI_SRC_DATA_READY_EVT;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_ci_setconfig
+**
+** Description This function must be called in response to function
+** bta_av_co_audio_setconfig() or bta_av_co_video_setconfig.
+** Parameter err_code is set to an AVDTP status value;
+** AVDT_SUCCESS if the codec configuration is ok,
+** otherwise error.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_ci_setconfig(tBTA_AV_HNDL hndl, UINT8 err_code, UINT8 category,
+ UINT8 num_seid, UINT8 *p_seid, BOOLEAN recfg_needed)
+{
+ tBTA_AV_CI_SETCONFIG *p_buf;
+
+ if ((p_buf = (tBTA_AV_CI_SETCONFIG *) GKI_getbuf(sizeof(tBTA_AV_CI_SETCONFIG))) != NULL)
+ {
+ p_buf->hdr.layer_specific = hndl;
+ p_buf->hdr.event = (err_code == AVDT_SUCCESS) ?
+ BTA_AV_CI_SETCONFIG_OK_EVT : BTA_AV_CI_SETCONFIG_FAIL_EVT;
+ p_buf->err_code = err_code;
+ p_buf->category = category;
+ p_buf->recfg_needed = recfg_needed;
+ p_buf->num_seid = num_seid;
+ if(p_seid && num_seid)
+ {
+ p_buf->p_seid = (UINT8 *)(p_buf + 1);
+ memcpy(p_buf->p_seid, p_seid, num_seid);
+ }
+ else
+ {
+ p_buf->p_seid = NULL;
+ p_buf->num_seid = 0;
+ }
+
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
diff --git a/bta/av/bta_av_int.h b/bta/av/bta_av_int.h
new file mode 100644
index 0000000..9e7f510
--- /dev/null
+++ b/bta/av/bta_av_int.h
@@ -0,0 +1,706 @@
+/*****************************************************************************
+**
+** Name: bta_av_int.h
+**
+** Description: This is the private interface file for the BTA advanced
+** audio/video.
+**
+** Copyright (c) 2004-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_AV_INT_H
+#define BTA_AV_INT_H
+
+#include "bta_sys.h"
+#include "bta_api.h"
+#include "bta_av_api.h"
+#include "avdt_api.h"
+#include "bta_av_co.h"
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+enum
+{
+ /* these events are handled by the AV main state machine */
+ BTA_AV_API_DISABLE_EVT = BTA_SYS_EVT_START(BTA_ID_AV),
+ BTA_AV_API_REMOTE_CMD_EVT,
+ BTA_AV_API_VENDOR_CMD_EVT,
+ BTA_AV_API_VENDOR_RSP_EVT,
+ BTA_AV_API_META_RSP_EVT,
+ BTA_AV_API_RC_CLOSE_EVT,
+ BTA_AV_AVRC_OPEN_EVT,
+ BTA_AV_AVRC_MSG_EVT,
+ BTA_AV_AVRC_NONE_EVT,
+
+ /* these events are handled by the AV stream state machine */
+ BTA_AV_API_OPEN_EVT,
+ BTA_AV_API_CLOSE_EVT,
+ BTA_AV_AP_START_EVT, /* the following 2 events must be in the same order as the *API_*EVT */
+ BTA_AV_AP_STOP_EVT,
+ BTA_AV_API_RECONFIG_EVT,
+ BTA_AV_API_PROTECT_REQ_EVT,
+ BTA_AV_API_PROTECT_RSP_EVT,
+ BTA_AV_API_RC_OPEN_EVT,
+ BTA_AV_SRC_DATA_READY_EVT,
+ BTA_AV_CI_SETCONFIG_OK_EVT,
+ BTA_AV_CI_SETCONFIG_FAIL_EVT,
+ BTA_AV_SDP_DISC_OK_EVT,
+ BTA_AV_SDP_DISC_FAIL_EVT,
+ BTA_AV_STR_DISC_OK_EVT,
+ BTA_AV_STR_DISC_FAIL_EVT,
+ BTA_AV_STR_GETCAP_OK_EVT,
+ BTA_AV_STR_GETCAP_FAIL_EVT,
+ BTA_AV_STR_OPEN_OK_EVT,
+ BTA_AV_STR_OPEN_FAIL_EVT,
+ BTA_AV_STR_START_OK_EVT,
+ BTA_AV_STR_START_FAIL_EVT,
+ BTA_AV_STR_CLOSE_EVT,
+ BTA_AV_STR_CONFIG_IND_EVT,
+ BTA_AV_STR_SECURITY_IND_EVT,
+ BTA_AV_STR_SECURITY_CFM_EVT,
+ BTA_AV_STR_WRITE_CFM_EVT,
+ BTA_AV_STR_SUSPEND_CFM_EVT,
+ BTA_AV_STR_RECONFIG_CFM_EVT,
+ BTA_AV_AVRC_TIMER_EVT,
+ BTA_AV_AVDT_CONNECT_EVT,
+ BTA_AV_AVDT_DISCONNECT_EVT,
+ BTA_AV_ROLE_CHANGE_EVT,
+ BTA_AV_AVDT_DELAY_RPT_EVT,
+ BTA_AV_ACP_CONNECT_EVT,
+
+ /* these events are handled outside of the state machine */
+ BTA_AV_API_ENABLE_EVT,
+ BTA_AV_API_REGISTER_EVT,
+ BTA_AV_API_DEREGISTER_EVT,
+ BTA_AV_API_DISCONNECT_EVT,
+ BTA_AV_CI_SRC_DATA_READY_EVT,
+ BTA_AV_SIG_CHG_EVT,
+ BTA_AV_SIG_TIMER_EVT,
+ BTA_AV_SDP_AVRC_DISC_EVT,
+ BTA_AV_AVRC_CLOSE_EVT,
+ BTA_AV_CONN_CHG_EVT,
+ BTA_AV_DEREG_COMP_EVT,
+#if (AVDT_REPORTING == TRUE)
+ BTA_AV_AVDT_RPT_CONN_EVT,
+#endif
+ BTA_AV_API_START_EVT, /* the following 2 events must be in the same order as the *AP_*EVT */
+ BTA_AV_API_STOP_EVT
+};
+
+/* events for AV control block state machine */
+#define BTA_AV_FIRST_SM_EVT BTA_AV_API_DISABLE_EVT
+#define BTA_AV_LAST_SM_EVT BTA_AV_AVRC_NONE_EVT
+
+/* events for AV stream control block state machine */
+#define BTA_AV_FIRST_SSM_EVT BTA_AV_API_OPEN_EVT
+
+/* events that do not go through state machine */
+#define BTA_AV_FIRST_NSM_EVT BTA_AV_API_ENABLE_EVT
+#define BTA_AV_LAST_NSM_EVT BTA_AV_API_STOP_EVT
+
+/* API events passed to both SSMs (by bta_av_api_to_ssm) */
+#define BTA_AV_FIRST_A2S_API_EVT BTA_AV_API_START_EVT
+#define BTA_AV_FIRST_A2S_SSM_EVT BTA_AV_AP_START_EVT
+
+#define BTA_AV_LAST_EVT BTA_AV_API_STOP_EVT
+
+/* maximum number of SEPS in stream discovery results */
+#define BTA_AV_NUM_SEPS 32
+
+/* initialization value for AVRC handle */
+#define BTA_AV_RC_HANDLE_NONE 0xFF
+
+/* size of database for service discovery */
+#define BTA_AV_DISC_BUF_SIZE 1000
+
+/* offset of media type in codec info byte array */
+#define BTA_AV_MEDIA_TYPE_IDX 1
+
+/* maximum length of AVDTP security data */
+#define BTA_AV_SECURITY_MAX_LEN 400
+
+/* check number of buffers queued at L2CAP when this amount of buffers are queued to L2CAP */
+#define BTA_AV_QUEUE_DATA_CHK_NUM 5
+
+/* the number of ACL links with AVDT */
+#define BTA_AV_NUM_LINKS AVDT_NUM_LINKS
+
+#define BTA_AV_CO_ID_TO_BE_STREAM(p, u32) {*(p)++ = (UINT8)((u32) >> 16); *(p)++ = (UINT8)((u32) >> 8); *(p)++ = (UINT8)(u32); }
+#define BTA_AV_BE_STREAM_TO_CO_ID(u32, p) {u32 = (((UINT32)(*((p) + 2))) + (((UINT32)(*((p) + 1))) << 8) + (((UINT32)(*(p))) << 16)); (p) += 3;}
+
+/* these bits are defined for bta_av_cb.multi_av */
+#define BTA_AV_MULTI_AV_SUPPORTED 0x01
+#define BTA_AV_MULTI_AV_IN_USE 0x02
+
+
+/*****************************************************************************
+** Data types
+*****************************************************************************/
+
+/* function types for call-out functions */
+typedef BOOLEAN (*tBTA_AV_CO_INIT) (UINT8 *p_codec_type, UINT8 *p_codec_info,
+ UINT8 *p_num_protect, UINT8 *p_protect_info, UINT8 index);
+
+typedef void (*tBTA_AV_CO_DISC_RES) (tBTA_AV_HNDL hndl, UINT8 num_seps,
+ UINT8 num_snk, BD_ADDR addr);
+
+typedef UINT8 (*tBTA_AV_CO_GETCFG) (tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type,
+ UINT8 *p_codec_info, UINT8 *p_sep_info_idx, UINT8 seid,
+ UINT8 *p_num_protect, UINT8 *p_protect_info);
+typedef void (*tBTA_AV_CO_SETCFG) (tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type,
+ UINT8 *p_codec_info, UINT8 seid, BD_ADDR addr,
+ UINT8 num_protect, UINT8 *p_protect_info);
+typedef void (*tBTA_AV_CO_OPEN) (tBTA_AV_HNDL hndl,
+ tBTA_AV_CODEC codec_type, UINT8 *p_codec_info,
+ UINT16 mtu);
+typedef void (*tBTA_AV_CO_CLOSE) (tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, UINT16 mtu);
+typedef void (*tBTA_AV_CO_START) (tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type);
+typedef void (*tBTA_AV_CO_STOP) (tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type);
+typedef void * (*tBTA_AV_CO_DATAPATH) (tBTA_AV_CODEC codec_type,
+ UINT32 *p_len, UINT32 *p_timestamp);
+typedef void (*tBTA_AV_CO_DELAY) (tBTA_AV_HNDL hndl, UINT16 delay);
+
+/* the call-out functions for one stream */
+typedef struct
+{
+ tBTA_AV_CO_INIT init;
+ tBTA_AV_CO_DISC_RES disc_res;
+ tBTA_AV_CO_GETCFG getcfg;
+ tBTA_AV_CO_SETCFG setcfg;
+ tBTA_AV_CO_OPEN open;
+ tBTA_AV_CO_CLOSE close;
+ tBTA_AV_CO_START start;
+ tBTA_AV_CO_STOP stop;
+ tBTA_AV_CO_DATAPATH data;
+ tBTA_AV_CO_DELAY delay;
+} tBTA_AV_CO_FUNCTS;
+
+/* data type for BTA_AV_API_ENABLE_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_AV_CBACK *p_cback;
+ tBTA_AV_FEAT features;
+ tBTA_SEC sec_mask;
+} tBTA_AV_API_ENABLE;
+
+/* data type for BTA_AV_API_REG_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ char p_service_name[BTA_SERVICE_NAME_LEN+1];
+ UINT8 app_id;
+} tBTA_AV_API_REG;
+
+
+enum
+{
+ BTA_AV_RS_NONE, /* straight API call */
+ BTA_AV_RS_OK, /* the role switch result - successful */
+ BTA_AV_RS_FAIL, /* the role switch result - failed */
+ BTA_AV_RS_DONE /* the role switch is done - continue */
+};
+typedef UINT8 tBTA_AV_RS_RES;
+/* data type for BTA_AV_API_OPEN_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+ BOOLEAN use_rc;
+ tBTA_SEC sec_mask;
+ tBTA_AV_RS_RES switch_res;
+} tBTA_AV_API_OPEN;
+
+/* data type for BTA_AV_API_STOP_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ BOOLEAN suspend;
+ BOOLEAN flush;
+} tBTA_AV_API_STOP;
+
+/* data type for BTA_AV_API_DISCONNECT_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+} tBTA_AV_API_DISCNT;
+
+/* data type for BTA_AV_API_PROTECT_REQ_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ UINT8 *p_data;
+ UINT16 len;
+} tBTA_AV_API_PROTECT_REQ;
+
+/* data type for BTA_AV_API_PROTECT_RSP_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ UINT8 *p_data;
+ UINT16 len;
+ UINT8 error_code;
+} tBTA_AV_API_PROTECT_RSP;
+
+/* data type for BTA_AV_API_REMOTE_CMD_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ tAVRC_MSG_PASS msg;
+ UINT8 label;
+} tBTA_AV_API_REMOTE_CMD;
+
+/* data type for BTA_AV_API_VENDOR_CMD_EVT and RSP */
+typedef struct
+{
+ BT_HDR hdr;
+ tAVRC_MSG_VENDOR msg;
+ UINT8 label;
+} tBTA_AV_API_VENDOR;
+
+/* data type for BTA_AV_API_RC_OPEN_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+} tBTA_AV_API_OPEN_RC;
+
+/* data type for BTA_AV_API_RC_CLOSE_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+} tBTA_AV_API_CLOSE_RC;
+
+/* data type for BTA_AV_API_META_RSP_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ BOOLEAN is_rsp;
+ UINT8 label;
+ tBTA_AV_CODE rsp_code;
+ BT_HDR *p_pkt;
+} tBTA_AV_API_META_RSP;
+
+
+/* data type for BTA_AV_API_RECONFIG_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ UINT8 codec_info[AVDT_CODEC_SIZE]; /* codec configuration */
+ UINT8 *p_protect_info;
+ UINT8 num_protect;
+ BOOLEAN suspend;
+ UINT8 sep_info_idx;
+} tBTA_AV_API_RCFG;
+
+/* data type for BTA_AV_CI_SETCONFIG_OK_EVT and BTA_AV_CI_SETCONFIG_FAIL_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_AV_HNDL hndl;
+ UINT8 err_code;
+ UINT8 category;
+ UINT8 num_seid;
+ UINT8 *p_seid;
+ BOOLEAN recfg_needed;
+} tBTA_AV_CI_SETCONFIG;
+
+/* data type for all stream events from AVDTP */
+typedef struct {
+ BT_HDR hdr;
+ tAVDT_CFG cfg; /* configuration/capabilities parameters */
+ tAVDT_CTRL msg; /* AVDTP callback message parameters */
+ BD_ADDR bd_addr; /* bd address */
+ UINT8 handle;
+ UINT8 avdt_event;
+ BOOLEAN initiator; /* TRUE, if local device initiates the SUSPEND */
+} tBTA_AV_STR_MSG;
+
+/* data type for BTA_AV_AVRC_MSG_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ tAVRC_MSG msg;
+ UINT8 handle;
+ UINT8 label;
+ UINT8 opcode;
+} tBTA_AV_RC_MSG;
+
+/* data type for BTA_AV_AVRC_OPEN_EVT, BTA_AV_AVRC_CLOSE_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ BD_ADDR peer_addr;
+ UINT8 handle;
+} tBTA_AV_RC_CONN_CHG;
+
+/* data type for BTA_AV_CONN_CHG_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ BD_ADDR peer_addr;
+ BOOLEAN is_up;
+} tBTA_AV_CONN_CHG;
+
+/* data type for BTA_AV_ROLE_CHANGE_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ UINT8 new_role;
+ UINT8 hci_status;
+} tBTA_AV_ROLE_RES;
+
+/* data type for BTA_AV_SDP_DISC_OK_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ UINT16 avdt_version; /* AVDTP protocol version */
+} tBTA_AV_SDP_RES;
+
+/* type for SEP control block */
+typedef struct
+{
+ UINT8 av_handle; /* AVDTP handle */
+ tBTA_AV_CODEC codec_type; /* codec type */
+} tBTA_AV_SEP;
+
+
+/* initiator/acceptor role for adaption */
+#define BTA_AV_ROLE_AD_INT 0x00 /* initiator */
+#define BTA_AV_ROLE_AD_ACP 0x01 /* acceptor */
+
+/* initiator/acceptor signaling roles */
+#define BTA_AV_ROLE_START_ACP 0x00
+#define BTA_AV_ROLE_START_INT 0x10 /* do not change this value */
+
+#define BTA_AV_ROLE_SUSPEND 0x20 /* suspending on start */
+#define BTA_AV_ROLE_SUSPEND_OPT 0x40 /* Suspend on Start option is set */
+
+/* union of all event datatypes */
+typedef union
+{
+ BT_HDR hdr;
+ tBTA_AV_API_ENABLE api_enable;
+ tBTA_AV_API_REG api_reg;
+ tBTA_AV_API_OPEN api_open;
+ tBTA_AV_API_STOP api_stop;
+ tBTA_AV_API_DISCNT api_discnt;
+ tBTA_AV_API_PROTECT_REQ api_protect_req;
+ tBTA_AV_API_PROTECT_RSP api_protect_rsp;
+ tBTA_AV_API_REMOTE_CMD api_remote_cmd;
+ tBTA_AV_API_VENDOR api_vendor;
+ tBTA_AV_API_RCFG api_reconfig;
+ tBTA_AV_CI_SETCONFIG ci_setconfig;
+ tBTA_AV_STR_MSG str_msg;
+ tBTA_AV_RC_MSG rc_msg;
+ tBTA_AV_RC_CONN_CHG rc_conn_chg;
+ tBTA_AV_CONN_CHG conn_chg;
+ tBTA_AV_ROLE_RES role_res;
+ tBTA_AV_SDP_RES sdp_res;
+ tBTA_AV_API_META_RSP api_meta_rsp;
+} tBTA_AV_DATA;
+
+typedef void (tBTA_AV_VDP_DATA_ACT)(void *p_scb);
+
+typedef struct
+{
+ tBTA_AV_VDP_DATA_ACT *p_act;
+ UINT8 *p_frame;
+ UINT16 buf_size;
+ UINT32 len;
+ UINT32 offset;
+ UINT32 timestamp;
+} tBTA_AV_VF_INFO;
+
+typedef union
+{
+ BUFFER_Q a2d; /* used for audio channels only */
+ tBTA_AV_VF_INFO vdp; /* used for video channels only */
+ tBTA_AV_API_OPEN open; /* used only before open and role switch
+ is needed on another AV channel */
+} tBTA_AV_Q_INFO;
+
+#define BTA_AV_Q_TAG_OPEN 0x01 /* after API_OPEN, before STR_OPENED */
+#define BTA_AV_Q_TAG_START 0x02 /* before start sending media packets */
+#define BTA_AV_Q_TAG_STREAM 0x03 /* during streaming */
+
+#define BTA_AV_WAIT_ACP_CAPS_ON 0x01 /* retriving the peer capabilities */
+#define BTA_AV_WAIT_ACP_CAPS_STARTED 0x02 /* started while retriving peer capabilities */
+#define BTA_AV_WAIT_ROLE_SW_RES_OPEN 0x04 /* waiting for role switch result after API_OPEN, before STR_OPENED */
+#define BTA_AV_WAIT_ROLE_SW_RES_START 0x08 /* waiting for role switch result before streaming */
+#define BTA_AV_WAIT_ROLE_SW_STARTED 0x10 /* started while waiting for role switch result */
+#define BTA_AV_WAIT_ROLE_SW_RETRY 0x20 /* set when retry on timeout */
+#define BTA_AV_WAIT_CHECK_RC 0x40 /* set when the timer is used by role switch */
+#define BTA_AV_WAIT_ROLE_SW_FAILED 0x80 /* role switch failed */
+
+#define BTA_AV_WAIT_ROLE_SW_BITS (BTA_AV_WAIT_ROLE_SW_RES_OPEN|BTA_AV_WAIT_ROLE_SW_RES_START|BTA_AV_WAIT_ROLE_SW_STARTED|BTA_AV_WAIT_ROLE_SW_RETRY)
+
+/* Bitmap for collision, coll_mask */
+#define BTA_AV_COLL_INC_TMR 0x01 /* Timer is running for incoming L2C connection */
+#define BTA_AV_COLL_API_CALLED 0x02 /* API open was called while incoming timer is running */
+
+/* type for AV stream control block */
+typedef struct
+{
+ const tBTA_AV_ACT *p_act_tbl; /* the action table for stream state machine */
+ const tBTA_AV_CO_FUNCTS *p_cos; /* the associated callout functions */
+ tSDP_DISCOVERY_DB *p_disc_db; /* pointer to discovery database */
+ tBTA_AV_SEP seps[BTA_AV_MAX_SEPS];
+ tAVDT_CFG *p_cap; /* buffer used for get capabilities */
+ tBTA_AV_Q_INFO q_info;
+ tAVDT_SEP_INFO sep_info[BTA_AV_NUM_SEPS]; /* stream discovery results */
+ tAVDT_CFG cfg; /* local SEP configuration */
+ TIMER_LIST_ENT timer; /* delay timer for AVRC CT */
+ BD_ADDR peer_addr; /* peer BD address */
+ UINT16 l2c_cid; /* L2CAP channel ID */
+ UINT16 stream_mtu; /* MTU of stream */
+ UINT16 avdt_version; /* the avdt version of peer device */
+ tBTA_SEC sec_mask; /* security mask */
+ tBTA_AV_CODEC codec_type; /* codec type */
+ UINT8 media_type; /* Media type */
+ BOOLEAN cong; /* TRUE if AVDTP congested */
+ tBTA_AV_STATUS open_status; /* open failure status */
+ tBTA_AV_CHNL chnl; /* the channel: audio/video */
+ tBTA_AV_HNDL hndl; /* the handle: ((hdi + 1)|chnl) */
+ UINT16 cur_psc_mask; /* Protocol service capabilities mask for current connection */
+ UINT8 avdt_handle; /* AVDTP handle */
+ UINT8 hdi; /* the index to SCB[] */
+ UINT8 num_seps; /* number of seps returned by stream discovery */
+ UINT8 num_disc_snks; /* number of discovered snks */
+ UINT8 sep_info_idx; /* current index into sep_info */
+ UINT8 sep_idx; /* current index into local seps[] */
+ UINT8 rcfg_idx; /* reconfig requested index into sep_info */
+ UINT8 state; /* state machine state */
+ UINT8 avdt_label; /* AVDTP label */
+ UINT8 app_id; /* application id */
+ UINT8 num_recfg; /* number of reconfigure sent */
+ UINT8 role;
+ UINT8 l2c_bufs; /* the number of buffers queued to L2CAP */
+ UINT8 rc_handle; /* connected AVRCP handle */
+ BOOLEAN use_rc; /* TRUE if AVRCP is allowed */
+ BOOLEAN started; /* TRUE if stream started */
+ UINT8 co_started; /* non-zero, if stream started from call-out perspective */
+ BOOLEAN recfg_sup; /* TRUE if the first attempt to reconfigure the stream was successfull, else False if command fails */
+ BOOLEAN suspend_sup; /* TRUE if Suspend stream is supported, else FALSE if suspend command fails */
+ BOOLEAN deregistring; /* TRUE if deregistering */
+ BOOLEAN sco_suspend; /* TRUE if SUSPEND is issued automatically for SCO */
+ UINT8 coll_mask; /* Mask to check incoming and outgoing collision */
+ tBTA_AV_API_OPEN open_api; /* Saved OPEN api message */
+ UINT8 wait; /* set 0x1, when getting Caps as ACP, set 0x2, when started */
+ UINT8 q_tag; /* identify the associated q_info union member */
+} tBTA_AV_SCB;
+
+#define BTA_AV_RC_ROLE_MASK 0x10
+#define BTA_AV_RC_ROLE_INT 0x00
+#define BTA_AV_RC_ROLE_ACP 0x10
+
+#define BTA_AV_RC_CONN_MASK 0x20
+
+/* type for AV RCP control block */
+/* index to this control block is the rc handle */
+typedef struct
+{
+ UINT8 status;
+ UINT8 handle;
+ UINT8 shdl; /* stream handle (hdi + 1) */
+ UINT8 lidx; /* (index+1) to LCB */
+ tBTA_AV_FEAT peer_features; /* peer features mask */
+} tBTA_AV_RCB;
+#define BTA_AV_NUM_RCB (BTA_AV_NUM_STRS + 2)
+
+enum
+{
+ BTA_AV_LCB_FREE,
+ BTA_AV_LCB_FIND
+};
+
+/* type for AV ACL Link control block */
+typedef struct
+{
+ BD_ADDR addr; /* peer BD address */
+ UINT8 conn_msk; /* handle mask of connected stream handle */
+ UINT8 lidx; /* index + 1 */
+} tBTA_AV_LCB;
+
+/* type for stream state machine action functions */
+typedef void (*tBTA_AV_SACT)(tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+
+
+/* type for AV control block */
+typedef struct
+{
+ tBTA_AV_SCB *p_scb[BTA_AV_NUM_STRS]; /* stream control block */
+ tSDP_DISCOVERY_DB *p_disc_db; /* pointer to discovery database */
+ tBTA_AV_CBACK *p_cback; /* application callback function */
+ tBTA_AV_RCB rcb[BTA_AV_NUM_RCB]; /* RCB control block */
+ tBTA_AV_LCB lcb[BTA_AV_NUM_LINKS+1]; /* link control block */
+ TIMER_LIST_ENT sig_tmr; /* link timer */
+ TIMER_LIST_ENT acp_sig_tmr; /* timer to monitor signalling when accepting */
+ UINT32 sdp_a2d_handle; /* SDP record handle for audio src */
+ UINT32 sdp_vdp_handle; /* SDP record handle for video src */
+ tBTA_AV_FEAT features; /* features mask */
+ tBTA_SEC sec_mask; /* security mask */
+ tBTA_AV_HNDL handle; /* the handle for SDP activity */
+ BOOLEAN disabling; /* TRUE if api disabled called */
+ UINT8 disc; /* (hdi+1) or (rc_handle|BTA_AV_CHNL_MSK) if p_disc_db is in use */
+ UINT8 state; /* state machine state */
+ UINT8 conn_rc; /* handle mask of connected RCP channels */
+ UINT8 conn_audio; /* handle mask of connected audio channels */
+ UINT8 conn_video; /* handle mask of connected video channels */
+ UINT8 conn_lcb; /* index mask of used LCBs */
+ UINT8 audio_open_cnt; /* number of connected audio channels */
+ UINT8 reg_audio; /* handle mask of registered audio channels */
+ UINT8 reg_video; /* handle mask of registered video channels */
+ UINT8 rc_acp_handle;
+ UINT8 rc_acp_idx; /* (index + 1) to RCB */
+ UINT8 rs_idx; /* (index + 1) to SCB for the one waiting for RS on open */
+ BOOLEAN sco_occupied; /* TRUE if SCO is being used or call is in progress */
+ UINT8 audio_streams; /* handle mask of streaming audio channels */
+ UINT8 video_streams; /* handle mask of streaming video channels */
+} tBTA_AV_CB;
+
+
+
+/*****************************************************************************
+** Global data
+*****************************************************************************/
+
+/* control block declaration */
+#if BTA_DYNAMIC_MEMORY == FALSE
+extern tBTA_AV_CB bta_av_cb;
+#else
+extern tBTA_AV_CB *bta_av_cb_ptr;
+#define bta_av_cb (*bta_av_cb_ptr)
+#endif
+
+/* config struct */
+extern tBTA_AV_CFG *p_bta_av_cfg;
+
+/* rc id config struct */
+extern UINT16 *p_bta_av_rc_id;
+extern UINT16 *p_bta_av_rc_id_ac;
+
+extern const tBTA_AV_SACT bta_av_a2d_action[];
+extern const tBTA_AV_CO_FUNCTS bta_av_a2d_cos;
+extern const tBTA_AV_SACT bta_av_vdp_action[];
+extern tAVDT_CTRL_CBACK * const bta_av_dt_cback[];
+
+/*****************************************************************************
+** Function prototypes
+*****************************************************************************/
+/* utility functions */
+extern tBTA_AV_SCB *bta_av_hndl_to_scb(UINT16 handle);
+extern BOOLEAN bta_av_chk_start(tBTA_AV_SCB *p_scb);
+extern void bta_av_restore_switch (void);
+extern UINT16 bta_av_chk_mtu(tBTA_AV_SCB *p_scb, UINT16 mtu);
+extern void bta_av_conn_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data);
+extern UINT8 bta_av_rc_create(tBTA_AV_CB *p_cb, UINT8 role, UINT8 shdl, UINT8 lidx);
+extern void bta_av_proc_stream_evt(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data, int index);
+extern void bta_av_stream_chg(tBTA_AV_SCB *p_scb, BOOLEAN started);
+extern BOOLEAN bta_av_is_scb_opening (tBTA_AV_SCB *p_scb);
+extern BOOLEAN bta_av_is_scb_incoming (tBTA_AV_SCB *p_scb);
+extern void bta_av_set_scb_sst_init (tBTA_AV_SCB *p_scb);
+extern BOOLEAN bta_av_is_scb_init (tBTA_AV_SCB *p_scb);
+extern void bta_av_set_scb_sst_incoming (tBTA_AV_SCB *p_scb);
+extern tBTA_AV_LCB * bta_av_find_lcb(BD_ADDR addr, UINT8 op);
+
+
+/* main functions */
+extern void bta_av_api_deregister(tBTA_AV_DATA *p_data);
+extern void bta_av_dup_audio_buf(tBTA_AV_SCB *p_scb, BT_HDR *p_buf);
+extern void bta_av_sm_execute(tBTA_AV_CB *p_cb, UINT16 event, tBTA_AV_DATA *p_data);
+extern void bta_av_ssm_execute(tBTA_AV_SCB *p_scb, UINT16 event, tBTA_AV_DATA *p_data);
+extern BOOLEAN bta_av_hdl_event(BT_HDR *p_msg);
+#if (defined(BTA_AV_DEBUG) && BTA_AV_DEBUG == TRUE)
+extern char *bta_av_evt_code(UINT16 evt_code);
+#endif
+extern BOOLEAN bta_av_switch_if_needed(tBTA_AV_SCB *p_scb);
+extern BOOLEAN bta_av_link_role_ok(tBTA_AV_SCB *p_scb, UINT8 bits);
+extern BOOLEAN bta_av_is_rcfg_sst(tBTA_AV_SCB *p_scb);
+
+/* nsm action functions */
+extern void bta_av_api_disconnect(tBTA_AV_DATA *p_data);
+extern void bta_av_sig_chg(tBTA_AV_DATA *p_data);
+extern void bta_av_sig_timer(tBTA_AV_DATA *p_data);
+extern void bta_av_rc_disc_done(tBTA_AV_DATA *p_data);
+extern void bta_av_rc_closed(tBTA_AV_DATA *p_data);
+extern void bta_av_rc_disc(UINT8 disc);
+extern void bta_av_conn_chg(tBTA_AV_DATA *p_data);
+extern void bta_av_dereg_comp(tBTA_AV_DATA *p_data);
+
+/* sm action functions */
+extern void bta_av_disable (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data);
+extern void bta_av_rc_opened (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data);
+extern void bta_av_rc_remote_cmd (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data);
+extern void bta_av_rc_vendor_cmd (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data);
+extern void bta_av_rc_vendor_rsp (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data);
+extern void bta_av_rc_msg (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data);
+extern void bta_av_rc_close (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data);
+extern void bta_av_rc_meta_rsp (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data);
+extern void bta_av_rc_free_rsp (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data);
+extern void bta_av_rc_free_msg (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data);
+
+extern tBTA_AV_RCB * bta_av_get_rcb_by_shdl(UINT8 shdl);
+extern void bta_av_del_rc(tBTA_AV_RCB *p_rcb);
+
+/* ssm action functions */
+extern void bta_av_do_disc_a2d (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_cleanup (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_free_sdb (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_config_ind (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_disconnect_req (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_security_req (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_security_rsp (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_setconfig_rsp (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_st_rc_timer(tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_str_opened (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_security_ind (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_security_cfm (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_do_close (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_connect_req (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_sdp_failed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_disc_results (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_disc_res_as_acp (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_open_failed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_getcap_results (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_setconfig_rej (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_discover_req (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_conn_failed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_do_start (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_str_stopped (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_reconfig (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_data_path (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_start_ok (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_start_failed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_str_closed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_clr_cong (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_suspend_cfm (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_rcfg_str_ok (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_rcfg_failed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_rcfg_connect (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_rcfg_discntd (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_suspend_cont (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_rcfg_cfm (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_rcfg_open (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_security_rej (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_open_rc (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_chk_2nd_start (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_save_caps (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_rej_conn (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_rej_conn (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_set_use_rc (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_cco_close (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_switch_role (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_role_res (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_delay_co (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_open_at_inc (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+
+/* ssm action functions - vdp specific */
+extern void bta_av_do_disc_vdp (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_vdp_str_opened (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_reg_vdp (tAVDT_CS *p_cs, char *p_service_name, void *p_data);
+
+#endif /* BTA_AV_INT_H */
diff --git a/bta/av/bta_av_main.c b/bta/av/bta_av_main.c
new file mode 100644
index 0000000..65c2cfe
--- /dev/null
+++ b/bta/av/bta_av_main.c
@@ -0,0 +1,1318 @@
+/*****************************************************************************
+**
+** Name: bta_av_main.c
+**
+** Description: This is the main implementation file for the BTA
+** advanced audio/video.
+**
+** Copyright (c) 2004-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+#if defined(AV_INCLUDED) && (AV_INCLUDED == TRUE)
+
+#include <string.h>
+#include "bta_av_int.h"
+#include "utl.h"
+#include "bd.h"
+#include "l2c_api.h"
+#include "l2cdefs.h"
+#include "bta_av_co.h"
+#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
+#include "bta_ar_api.h"
+#endif
+
+/*****************************************************************************
+** Constants and types
+*****************************************************************************/
+
+/* AVDTP protocol timeout values */
+#ifndef BTA_AV_RET_TOUT
+#define BTA_AV_RET_TOUT 4
+#endif
+
+#ifndef BTA_AV_SIG_TOUT
+#define BTA_AV_SIG_TOUT 4
+#endif
+
+#ifndef BTA_AV_IDLE_TOUT
+#define BTA_AV_IDLE_TOUT 10
+#endif
+
+/* the delay time in milliseconds to retry role switch */
+#ifndef BTA_AV_RS_TIME_VAL
+#define BTA_AV_RS_TIME_VAL 1000
+#endif
+
+/* state machine states */
+enum
+{
+ BTA_AV_INIT_ST,
+ BTA_AV_OPEN_ST
+};
+
+/* state machine action enumeration list */
+enum
+{
+ BTA_AV_DISABLE,
+ BTA_AV_RC_OPENED,
+ BTA_AV_RC_REMOTE_CMD,
+ BTA_AV_RC_VENDOR_CMD,
+ BTA_AV_RC_VENDOR_RSP,
+ BTA_AV_RC_FREE_RSP,
+ BTA_AV_RC_FREE_MSG,
+ BTA_AV_RC_META_RSP,
+ BTA_AV_RC_MSG,
+ BTA_AV_RC_CLOSE,
+ BTA_AV_NUM_ACTIONS
+};
+
+#define BTA_AV_IGNORE BTA_AV_NUM_ACTIONS
+
+/* type for action functions */
+typedef void (*tBTA_AV_ACTION)(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data);
+
+/* action functions */
+const tBTA_AV_ACTION bta_av_action[] =
+{
+ bta_av_disable,
+ bta_av_rc_opened,
+ bta_av_rc_remote_cmd,
+ bta_av_rc_vendor_cmd,
+ bta_av_rc_vendor_rsp,
+ bta_av_rc_free_rsp,
+ bta_av_rc_free_msg,
+ bta_av_rc_meta_rsp,
+ bta_av_rc_msg,
+ bta_av_rc_close,
+ NULL
+};
+
+/* state table information */
+#define BTA_AV_ACTION_COL 0 /* position of actions */
+#define BTA_AV_NEXT_STATE 1 /* position of next state */
+#define BTA_AV_NUM_COLS 2 /* number of columns in state tables */
+
+/* state table for init state */
+static const UINT8 bta_av_st_init[][BTA_AV_NUM_COLS] =
+{
+/* Event Action 1 Next state */
+/* API_DISABLE_EVT */ {BTA_AV_DISABLE, BTA_AV_INIT_ST },
+/* API_REMOTE_CMD_EVT */ {BTA_AV_IGNORE, BTA_AV_INIT_ST },
+/* API_VENDOR_CMD_EVT */ {BTA_AV_IGNORE, BTA_AV_INIT_ST },
+/* API_VENDOR_RSP_EVT */ {BTA_AV_IGNORE, BTA_AV_INIT_ST },
+/* API_META_RSP_EVT */ {BTA_AV_RC_FREE_RSP, BTA_AV_INIT_ST },
+/* API_RC_CLOSE_EVT */ {BTA_AV_IGNORE, BTA_AV_INIT_ST },
+/* AVRC_OPEN_EVT */ {BTA_AV_RC_OPENED, BTA_AV_OPEN_ST },
+/* AVRC_MSG_EVT */ {BTA_AV_RC_FREE_MSG, BTA_AV_INIT_ST },
+/* AVRC_NONE_EVT */ {BTA_AV_IGNORE, BTA_AV_INIT_ST },
+};
+
+/* state table for open state */
+static const UINT8 bta_av_st_open[][BTA_AV_NUM_COLS] =
+{
+/* Event Action 1 Next state */
+/* API_DISABLE_EVT */ {BTA_AV_DISABLE, BTA_AV_INIT_ST },
+/* API_REMOTE_CMD_EVT */ {BTA_AV_RC_REMOTE_CMD, BTA_AV_OPEN_ST },
+/* API_VENDOR_CMD_EVT */ {BTA_AV_RC_VENDOR_CMD, BTA_AV_OPEN_ST },
+/* API_VENDOR_RSP_EVT */ {BTA_AV_RC_VENDOR_RSP, BTA_AV_OPEN_ST },
+/* API_META_RSP_EVT */ {BTA_AV_RC_META_RSP, BTA_AV_OPEN_ST },
+/* API_RC_CLOSE_EVT */ {BTA_AV_RC_CLOSE, BTA_AV_OPEN_ST },
+/* AVRC_OPEN_EVT */ {BTA_AV_RC_OPENED, BTA_AV_OPEN_ST },
+/* AVRC_MSG_EVT */ {BTA_AV_RC_MSG, BTA_AV_OPEN_ST },
+/* AVRC_NONE_EVT */ {BTA_AV_IGNORE, BTA_AV_INIT_ST },
+};
+
+/* type for state table */
+typedef const UINT8 (*tBTA_AV_ST_TBL)[BTA_AV_NUM_COLS];
+
+/* state table */
+static const tBTA_AV_ST_TBL bta_av_st_tbl[] =
+{
+ bta_av_st_init,
+ bta_av_st_open
+};
+
+typedef void (*tBTA_AV_NSM_ACT)(tBTA_AV_DATA *p_data);
+static void bta_av_api_enable(tBTA_AV_DATA *p_data);
+static void bta_av_api_register(tBTA_AV_DATA *p_data);
+static void bta_av_ci_data(tBTA_AV_DATA *p_data);
+#if (AVDT_REPORTING == TRUE)
+static void bta_av_rpc_conn(tBTA_AV_DATA *p_data);
+#endif
+static void bta_av_api_to_ssm(tBTA_AV_DATA *p_data);
+
+static void bta_av_sco_chg_cback(tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8
+ app_id, BD_ADDR peer_addr);
+static void bta_av_sys_rs_cback (tBTA_SYS_CONN_STATUS status,UINT8 id, UINT8 app_id, BD_ADDR peer_addr);
+
+
+/* action functions */
+const tBTA_AV_NSM_ACT bta_av_nsm_act[] =
+{
+ bta_av_api_enable, /* BTA_AV_API_ENABLE_EVT */
+ bta_av_api_register, /* BTA_AV_API_REGISTER_EVT */
+ bta_av_api_deregister, /* BTA_AV_API_DEREGISTER_EVT */
+ bta_av_api_disconnect, /* BTA_AV_API_DISCONNECT_EVT */
+ bta_av_ci_data, /* BTA_AV_CI_SRC_DATA_READY_EVT */
+ bta_av_sig_chg, /* BTA_AV_SIG_CHG_EVT */
+ bta_av_sig_timer, /* BTA_AV_SIG_TIMER_EVT */
+ bta_av_rc_disc_done, /* BTA_AV_SDP_AVRC_DISC_EVT */
+ bta_av_rc_closed, /* BTA_AV_AVRC_CLOSE_EVT */
+ bta_av_conn_chg, /* BTA_AV_CONN_CHG_EVT */
+ bta_av_dereg_comp, /* BTA_AV_DEREG_COMP_EVT */
+#if (AVDT_REPORTING == TRUE)
+ bta_av_rpc_conn, /* BTA_AV_AVDT_RPT_CONN_EVT */
+#endif
+ bta_av_api_to_ssm, /* BTA_AV_API_START_EVT */
+ bta_av_api_to_ssm, /* BTA_AV_API_STOP_EVT */
+};
+
+/*****************************************************************************
+** Global data
+*****************************************************************************/
+
+/* AV control block */
+#if BTA_DYNAMIC_MEMORY == FALSE
+tBTA_AV_CB bta_av_cb;
+#endif
+
+#if (defined(BTA_AV_DEBUG) && BTA_AV_DEBUG == TRUE)
+static char *bta_av_st_code(UINT8 state);
+#endif
+
+/*******************************************************************************
+**
+** Function bta_av_timer_cback
+**
+** Description forward the event to stream state machine
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_av_timer_cback(void *p_tle)
+{
+ BT_HDR *p_buf;
+ TIMER_LIST_ENT *p = (TIMER_LIST_ENT *)p_tle;
+ int xx;
+ tBTA_AV_SCB *p_scb = NULL;
+
+ /* find the SCB that has the timer */
+ for(xx=0; xx<BTA_AV_NUM_STRS; xx++)
+ {
+ if(bta_av_cb.p_scb[xx] && &(bta_av_cb.p_scb[xx]->timer)== p)
+ {
+ p_scb = bta_av_cb.p_scb[xx];
+ break;
+ }
+ }
+
+ if (p_scb && (p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ /* send the event through the audio state machine.
+ * only when the audio SM is open, the main SM opens the RC connection as INT */
+ p_buf->event = p->event;
+ p_buf->layer_specific = p_scb->hndl;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_api_enable
+**
+** Description Handle an API enable event.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_av_api_enable(tBTA_AV_DATA *p_data)
+{
+ int i;
+ tBTA_AV_ENABLE enable;
+
+ /* initialize control block */
+ memset(&bta_av_cb, 0, sizeof(tBTA_AV_CB));
+
+ for(i=0; i<BTA_AV_NUM_RCB; i++)
+ bta_av_cb.rcb[i].handle = BTA_AV_RC_HANDLE_NONE;
+
+ bta_av_cb.rc_acp_handle = BTA_AV_RC_HANDLE_NONE;
+
+ /* store parameters */
+ bta_av_cb.p_cback = p_data->api_enable.p_cback;
+ bta_av_cb.features = p_data->api_enable.features;
+ bta_av_cb.sec_mask = p_data->api_enable.sec_mask;
+
+ enable.features = bta_av_cb.features;
+
+ /* Register for SCO change event */
+ if (!(bta_av_cb.features & BTA_AV_FEAT_NO_SCO_SSPD))
+ {
+ bta_sys_sco_register(bta_av_sco_chg_cback);
+ }
+
+ /* call callback with enable event */
+ (*bta_av_cb.p_cback)(BTA_AV_ENABLE_EVT, (tBTA_AV *)&enable);
+}
+
+/*******************************************************************************
+**
+** Function bta_av_addr_to_scb
+**
+** Description find the stream control block by the peer addr
+**
+** Returns void
+**
+*******************************************************************************/
+static tBTA_AV_SCB * bta_av_addr_to_scb(BD_ADDR bd_addr)
+{
+ tBTA_AV_SCB * p_scb = NULL;
+ int xx;
+
+ for(xx=0; xx<BTA_AV_NUM_STRS; xx++)
+ {
+ if(bta_av_cb.p_scb[xx])
+ {
+ if(!bdcmp(bd_addr, bta_av_cb.p_scb[xx]->peer_addr))
+ {
+ p_scb = bta_av_cb.p_scb[xx];
+ break;
+ }
+ }
+ }
+ return p_scb;
+}
+
+/*******************************************************************************
+**
+** Function bta_av_hndl_to_scb
+**
+** Description find the stream control block by the handle
+**
+** Returns void
+**
+*******************************************************************************/
+tBTA_AV_SCB * bta_av_hndl_to_scb(UINT16 handle)
+{
+ tBTA_AV_HNDL hndl = (tBTA_AV_HNDL)handle;
+ tBTA_AV_SCB * p_scb = NULL;
+ UINT8 idx = (hndl & BTA_AV_HNDL_MSK);
+
+ if(idx && (idx <= BTA_AV_NUM_STRS) )
+ {
+ p_scb = bta_av_cb.p_scb[idx-1];
+ }
+ return p_scb;
+}
+
+/*******************************************************************************
+**
+** Function bta_av_alloc_scb
+**
+** Description allocate stream control block,
+** register the service to stack
+** create SDP record
+**
+** Returns void
+**
+*******************************************************************************/
+static tBTA_AV_SCB * bta_av_alloc_scb(tBTA_AV_CHNL chnl)
+{
+ tBTA_AV_SCB *p_ret = NULL;
+ int xx;
+ tBTA_AV_STATUS sts = BTA_AV_SUCCESS;
+
+ if(chnl == BTA_AV_CHNL_VIDEO)
+ {
+ if(p_bta_av_cfg->p_act_tbl == NULL || p_bta_av_cfg->p_reg == NULL)
+ {
+ APPL_TRACE_ERROR0("Video streaming not supported");
+ sts = BTA_AV_FAIL;
+ }
+ else
+ {
+ /* allow only one Video channel */
+ if(bta_av_cb.reg_video)
+ {
+ APPL_TRACE_ERROR0("Already registered");
+ sts = BTA_AV_FAIL;
+ }
+ }
+ }
+ else if(chnl != BTA_AV_CHNL_AUDIO)
+ {
+ APPL_TRACE_ERROR1("bad channel: %d", chnl);
+ sts = BTA_AV_FAIL;
+ }
+
+ if(sts == BTA_AV_SUCCESS)
+ {
+ for(xx=0; xx<BTA_AV_NUM_STRS; xx++)
+ {
+ if(bta_av_cb.p_scb[xx] == NULL)
+ {
+ /* found an empty spot */
+ p_ret = (tBTA_AV_SCB *)GKI_getbuf(sizeof(tBTA_AV_SCB));
+ if(p_ret)
+ {
+ memset(p_ret, 0, sizeof(tBTA_AV_SCB));
+ p_ret->rc_handle = BTA_AV_RC_HANDLE_NONE;
+ p_ret->chnl = chnl;
+ p_ret->hndl = (tBTA_AV_HNDL)((xx + 1) | chnl);
+ p_ret->hdi = xx;
+ bta_av_cb.p_scb[xx] = p_ret;
+ }
+ break;
+ }
+ }
+ }
+ return p_ret;
+}
+
+/*******************************************************************************
+*******************************************************************************/
+void bta_av_conn_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data)
+{
+ tBTA_AV_STR_MSG *p_msg;
+ UINT16 evt = 0;
+ tBTA_AV_SCB *p_scb = NULL;
+
+#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
+ if (event == BTA_AR_AVDT_CONN_EVT ||
+ event == AVDT_CONNECT_IND_EVT || event == AVDT_DISCONNECT_IND_EVT)
+#else
+ if (event == AVDT_CONNECT_IND_EVT || event == AVDT_DISCONNECT_IND_EVT)
+#endif
+ {
+ evt = BTA_AV_SIG_CHG_EVT;
+ if(AVDT_DISCONNECT_IND_EVT == event)
+ p_scb = bta_av_addr_to_scb(bd_addr);
+#if (defined(BTA_AV_DEBUG) && BTA_AV_DEBUG == TRUE)
+ else if (AVDT_CONNECT_IND_EVT == event)
+ {
+ APPL_TRACE_DEBUG1("CONN_IND is ACP:%d", p_data->hdr.err_param);
+ }
+#endif
+
+ if (/*((p_scb && (p_scb->role & BTA_AV_ROLE_AD_ACP)) ||
+
+ //(AVDT_CONNECT_IND_EVT == event && AVDT_ACP == p_data->hdr.err_param))
+
+ (AVDT_CONNECT_IND_EVT == event))&& */
+ (p_msg = (tBTA_AV_STR_MSG *) GKI_getbuf((UINT16) (sizeof(tBTA_AV_STR_MSG)))) != NULL)
+ {
+ p_msg->hdr.event = evt;
+ p_msg->hdr.layer_specific = event;
+ p_msg->hdr.offset = p_data->hdr.err_param;
+ bdcpy(p_msg->bd_addr, bd_addr);
+#if (defined(BTA_AV_DEBUG) && BTA_AV_DEBUG == TRUE)
+ if(p_scb)
+ {
+ APPL_TRACE_DEBUG2("scb hndl x%x, role x%x", p_scb->hndl, p_scb->role);
+ }
+#endif
+ APPL_TRACE_DEBUG6("conn_cback bd_addr:%02x-%02x-%02x-%02x-%02x-%02x",
+ bd_addr[0], bd_addr[1],
+ bd_addr[2], bd_addr[3],
+ bd_addr[4], bd_addr[5]);
+ bta_sys_sendmsg(p_msg);
+ }
+ }
+
+}
+
+#if AVDT_REPORTING == TRUE
+/*******************************************************************************
+**
+** Function bta_av_a2dp_report_cback
+**
+** Description A2DP report callback.
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_av_a2dp_report_cback(UINT8 handle, AVDT_REPORT_TYPE type,
+ tAVDT_REPORT_DATA *p_data)
+{
+ /* Do not need to handle report data for now.
+ * This empty function is here for conformance reasons. */
+}
+#endif
+
+/*******************************************************************************
+**
+** Function bta_av_api_register
+**
+** Description allocate stream control block,
+** register the service to stack
+** create SDP record
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_av_api_register(tBTA_AV_DATA *p_data)
+{
+ tBTA_AV_REGISTER registr;
+ tBTA_AV_SCB *p_scb; /* stream control block */
+ tAVDT_REG reg;
+ tAVDT_CS cs;
+ char *p_service_name;
+ tBTA_AV_CODEC codec_type;
+ tBTA_UTL_COD cod;
+ UINT8 index = 0;
+
+ memset(&cs,0,sizeof(tAVDT_CS));
+
+ registr.status = BTA_AV_FAIL_RESOURCES;
+ registr.app_id = p_data->api_reg.app_id;
+ registr.chnl = (tBTA_AV_CHNL)p_data->hdr.layer_specific;
+ do
+ {
+ p_scb = bta_av_alloc_scb(registr.chnl);
+ if(p_scb == NULL)
+ {
+ APPL_TRACE_ERROR0("failed to alloc SCB");
+ break;
+ }
+
+ registr.hndl = p_scb->hndl;
+ p_scb->app_id = registr.app_id;
+
+ /* initialize the stream control block */
+ p_scb->timer.p_cback = (TIMER_CBACK*)&bta_av_timer_cback;
+ registr.status = BTA_AV_SUCCESS;
+
+ if((bta_av_cb.reg_audio + bta_av_cb.reg_video) == 0)
+ {
+ /* the first channel registered. register to AVDTP */
+ reg.ctrl_mtu = p_bta_av_cfg->sig_mtu;
+ reg.ret_tout = BTA_AV_RET_TOUT;
+ reg.sig_tout = BTA_AV_SIG_TOUT;
+ reg.idle_tout = BTA_AV_IDLE_TOUT;
+ reg.sec_mask = bta_av_cb.sec_mask;
+#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
+ bta_ar_reg_avdt(&reg, bta_av_conn_cback, BTA_ID_AV);
+#endif
+ bta_sys_role_chg_register(&bta_av_sys_rs_cback);
+
+ /* create remote control TG service if required */
+ if (bta_av_cb.features & (BTA_AV_FEAT_RCTG))
+ {
+ /* register with no authorization; let AVDTP use authorization instead */
+#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
+#if (BTA_AV_WITH_AVCTP_AUTHORIZATION == TRUE)
+ bta_ar_reg_avct(p_bta_av_cfg->avrc_mtu, p_bta_av_cfg->avrc_br_mtu,
+ bta_av_cb.sec_mask, BTA_ID_AV);
+#else
+ bta_ar_reg_avct(p_bta_av_cfg->avrc_mtu, p_bta_av_cfg->avrc_br_mtu,
+ (UINT8)(bta_av_cb.sec_mask & (~BTA_SEC_AUTHORIZE)), BTA_ID_AV);
+#endif
+
+ bta_ar_reg_avrc(UUID_SERVCLASS_AV_REM_CTRL_TARGET, "AV Remote Control Target", NULL,
+ p_bta_av_cfg->avrc_tg_cat, BTA_ID_AV);
+#endif
+ }
+
+ /* Set the Capturing service class bit */
+ cod.service = BTM_COD_SERVICE_CAPTURING;
+ utl_set_device_class(&cod, BTA_UTL_SET_COD_SERVICE_CLASS);
+ } /* if 1st channel */
+
+ /* get stream configuration and create stream */
+ /* memset(&cs.cfg,0,sizeof(tAVDT_CFG)); */
+ cs.cfg.num_codec = 1;
+ cs.tsep = AVDT_TSEP_SRC;
+
+ /*
+ * memset of cs takes care setting call back pointers to null.
+ cs.p_data_cback = NULL;
+ cs.p_report_cback = NULL;
+ */
+ cs.nsc_mask = AVDT_NSC_RECONFIG |
+ ((bta_av_cb.features & BTA_AV_FEAT_PROTECT) ? 0 : AVDT_NSC_SECURITY);
+ APPL_TRACE_DEBUG1("nsc_mask: 0x%x", cs.nsc_mask);
+
+ if (p_data->api_reg.p_service_name[0] == 0)
+ {
+ p_service_name = NULL;
+ }
+ else
+ {
+ p_service_name = p_data->api_reg.p_service_name;
+ }
+
+ p_scb->suspend_sup = TRUE;
+ p_scb->recfg_sup = TRUE;
+
+ cs.p_ctrl_cback = bta_av_dt_cback[p_scb->hdi];
+ if(registr.chnl == BTA_AV_CHNL_AUDIO)
+ {
+ /* set up the audio stream control block */
+ p_scb->p_act_tbl = (const tBTA_AV_ACT *)bta_av_a2d_action;
+ p_scb->p_cos = &bta_av_a2d_cos;
+ p_scb->media_type= AVDT_MEDIA_AUDIO;
+ cs.cfg.psc_mask = AVDT_PSC_TRANS;
+ cs.media_type = AVDT_MEDIA_AUDIO;
+ cs.mtu = p_bta_av_cfg->audio_mtu;
+ cs.flush_to = L2CAP_DEFAULT_FLUSH_TO;
+#if AVDT_REPORTING == TRUE
+ if(bta_av_cb.features & BTA_AV_FEAT_REPORT)
+ {
+ cs.cfg.psc_mask |= AVDT_PSC_REPORT;
+ cs.p_report_cback = bta_av_a2dp_report_cback;
+#if AVDT_MULTIPLEXING == TRUE
+ cs.cfg.mux_tsid_report = 2;
+#endif
+ }
+#endif
+ if(bta_av_cb.features & BTA_AV_FEAT_DELAY_RPT)
+ cs.cfg.psc_mask |= AVDT_PSC_DELAY_RPT;
+
+ /* keep the configuration in the stream control block */
+ memcpy(&p_scb->cfg, &cs.cfg, sizeof(tAVDT_CFG));
+ while(index < BTA_AV_MAX_SEPS &&
+ (*bta_av_a2d_cos.init)(&codec_type, cs.cfg.codec_info,
+ &cs.cfg.num_protect, cs.cfg.protect_info, index) == TRUE)
+ {
+ if(AVDT_CreateStream(&p_scb->seps[index].av_handle, &cs) == AVDT_SUCCESS)
+ {
+ p_scb->seps[index].codec_type = codec_type;
+ APPL_TRACE_DEBUG3("audio[%d] av_handle: %d codec_type: %d",
+ index, p_scb->seps[index].av_handle, p_scb->seps[index].codec_type);
+ index++;
+ }
+ else
+ break;
+ }
+
+ if(!bta_av_cb.reg_audio)
+ {
+ /* create the SDP records on the 1st audio channel */
+ bta_av_cb.sdp_a2d_handle = SDP_CreateRecord();
+ A2D_AddRecord(UUID_SERVCLASS_AUDIO_SOURCE, p_service_name, NULL,
+ A2D_SUPF_PLAYER, bta_av_cb.sdp_a2d_handle);
+ bta_sys_add_uuid(UUID_SERVCLASS_AUDIO_SOURCE);
+
+ /* start listening when A2DP is registered */
+ if (bta_av_cb.features & BTA_AV_FEAT_RCTG)
+ bta_av_rc_create(&bta_av_cb, AVCT_ACP, 0, BTA_AV_NUM_LINKS + 1);
+
+ /* if the AV and AVK are both supported, it cannot support the CT role */
+#if (BTA_AVK_INCLUDED == FALSE)
+ if (bta_av_cb.features & (BTA_AV_FEAT_RCCT))
+ {
+ /* if TG is not supported, we need to register to AVCT now */
+ if ((bta_av_cb.features & (BTA_AV_FEAT_RCTG)) == 0)
+ {
+#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
+#if (BTA_AV_WITH_AVCTP_AUTHORIZATION == TRUE)
+ bta_ar_reg_avct(p_bta_av_cfg->avrc_mtu, p_bta_av_cfg->avrc_br_mtu,
+ bta_av_cb.sec_mask, BTA_ID_AV);
+#else
+ bta_ar_reg_avct(p_bta_av_cfg->avrc_mtu, p_bta_av_cfg->avrc_br_mtu,
+ (UINT8)(bta_av_cb.sec_mask & (~BTA_SEC_AUTHORIZE)), BTA_ID_AV);
+#endif
+#endif
+ }
+#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
+ /* create an SDP record as AVRC CT. */
+ bta_ar_reg_avrc(UUID_SERVCLASS_AV_REMOTE_CONTROL, NULL, NULL,
+ p_bta_av_cfg->avrc_ct_cat, BTA_ID_AV);
+#endif
+ }
+#endif
+ }
+ bta_av_cb.reg_audio |= BTA_AV_HNDL_TO_MSK(p_scb->hdi);
+ APPL_TRACE_DEBUG1("reg_audio: 0x%x",bta_av_cb.reg_audio);
+ }
+ else
+ {
+ bta_av_cb.reg_video = BTA_AV_HNDL_TO_MSK(p_scb->hdi);
+ bta_av_cb.sdp_vdp_handle = SDP_CreateRecord();
+ /* register the video channel */
+ /* no need to verify the function pointer here. it's verified prior */
+ (*p_bta_av_cfg->p_reg)(&cs, p_service_name, p_scb);
+ }
+ } while (0);
+
+ /* call callback with register event */
+ (*bta_av_cb.p_cback)(BTA_AV_REGISTER_EVT, (tBTA_AV *)&registr);
+}
+
+/*******************************************************************************
+**
+** Function bta_av_api_deregister
+**
+** Description de-register a channel
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_api_deregister(tBTA_AV_DATA *p_data)
+{
+ tBTA_AV_SCB *p_scb = bta_av_hndl_to_scb(p_data->hdr.layer_specific);
+
+ if(p_scb)
+ {
+ p_scb->deregistring = TRUE;
+ bta_av_ssm_execute(p_scb, BTA_AV_API_CLOSE_EVT, p_data);
+ }
+ else
+ {
+ bta_av_dereg_comp(p_data);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_ci_data
+**
+** Description forward the BTA_AV_CI_SRC_DATA_READY_EVT to stream state machine
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_av_ci_data(tBTA_AV_DATA *p_data)
+{
+ tBTA_AV_SCB *p_scb;
+ int i;
+ UINT8 chnl = (UINT8)p_data->hdr.layer_specific;
+
+ for( i=0; i < BTA_AV_NUM_STRS; i++ )
+ {
+ p_scb = bta_av_cb.p_scb[i];
+
+ if(p_scb && p_scb->chnl == chnl)
+ {
+ bta_av_ssm_execute(p_scb, BTA_AV_SRC_DATA_READY_EVT, p_data);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_rpc_conn
+**
+** Description report report channel open
+**
+** Returns void
+**
+*******************************************************************************/
+#if (AVDT_REPORTING == TRUE)
+static void bta_av_rpc_conn(tBTA_AV_DATA *p_data)
+{
+ tBTA_AV_SCB *p_scb = bta_av_hndl_to_scb(p_data->hdr.layer_specific);
+ if(p_scb)
+ {
+ bta_av_co_video_report_conn(p_data->str_msg.msg.report_conn.err_param,
+ p_scb->avdt_handle);
+ }
+}
+#endif
+
+/*******************************************************************************
+**
+** Function bta_av_api_to_ssm
+**
+** Description forward the API request to stream state machine
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_av_api_to_ssm(tBTA_AV_DATA *p_data)
+{
+ int xx;
+ UINT16 event = p_data->hdr.event - BTA_AV_FIRST_A2S_API_EVT + BTA_AV_FIRST_A2S_SSM_EVT;
+
+ for(xx=0; xx<BTA_AV_NUM_STRS; xx++)
+ {
+ bta_av_ssm_execute(bta_av_cb.p_scb[xx], event, p_data);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_chk_start
+**
+** Description if this is audio channel, check if more than one audio
+** channel is connected & already started.
+**
+** Returns TRUE, if need api_start
+**
+*******************************************************************************/
+BOOLEAN bta_av_chk_start(tBTA_AV_SCB *p_scb)
+{
+ BOOLEAN start = FALSE;
+ tBTA_AV_SCB *p_scbi;
+ int i;
+
+ if(p_scb->chnl == BTA_AV_CHNL_AUDIO)
+ {
+ if ((bta_av_cb.audio_open_cnt >= 2) &&
+ ((0 == (p_scb->role & BTA_AV_ROLE_AD_ACP)) || /* Outgoing connection or */
+ (bta_av_cb.features & BTA_AV_FEAT_ACP_START))) /* auto-starting option */
+ {
+ /* more than one audio channel is connected */
+ /* if this is the 2nd stream as ACP, give INT a chance to issue the START command */
+ for(i=0; i<BTA_AV_NUM_STRS; i++)
+ {
+ p_scbi = bta_av_cb.p_scb[i];
+ if(p_scbi && p_scbi->chnl == BTA_AV_CHNL_AUDIO && p_scbi->co_started)
+ {
+ start = TRUE;
+ /* may need to update the flush timeout of this already started stream */
+ if(p_scbi->co_started != bta_av_cb.audio_open_cnt)
+ {
+ p_scbi->co_started = bta_av_cb.audio_open_cnt;
+ L2CA_SetFlushTimeout(p_scbi->peer_addr, p_bta_av_cfg->p_audio_flush_to[p_scbi->co_started - 1] );
+ }
+ }
+ }
+ }
+ }
+ return start;
+}
+
+/*******************************************************************************
+**
+** Function bta_av_restore_switch
+**
+** Description assume that the caller of this function already makes
+** sure that there's only one ACL connection left
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_restore_switch (void)
+{
+ tBTA_AV_CB *p_cb = &bta_av_cb;
+ int i;
+ UINT8 mask;
+
+ APPL_TRACE_DEBUG1("reg_audio: 0x%x",bta_av_cb.reg_audio);
+ for(i=0; i<BTA_AV_NUM_STRS; i++)
+ {
+ mask = BTA_AV_HNDL_TO_MSK(i);
+ if (p_cb->conn_audio == mask)
+ {
+ if (p_cb->p_scb[i])
+ {
+ bta_sys_set_policy(BTA_ID_AV, HCI_ENABLE_MASTER_SLAVE_SWITCH, p_cb->p_scb[i]->peer_addr);
+ }
+ break;
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_sys_rs_cback
+**
+** Description Receives the role change event from dm
+**
+** Returns (BTA_SYS_ROLE_CHANGE, new_role, hci_status, p_bda)
+**
+*******************************************************************************/
+static void bta_av_sys_rs_cback (tBTA_SYS_CONN_STATUS status,UINT8 id, UINT8 app_id, BD_ADDR peer_addr)
+{
+ int i;
+ tBTA_AV_SCB *p_scb;
+ tBTA_AV_ROLE_RES *p_buf;
+ UINT8 cur_role;
+ UINT8 peer_idx = 0;
+
+ APPL_TRACE_DEBUG1("bta_av_sys_rs_cback: %d", bta_av_cb.rs_idx);
+ for(i=0; i<BTA_AV_NUM_STRS; i++)
+ {
+ /* loop through all the SCBs to find matching peer addresses and report the role change event */
+ /* note that more than one SCB (a2dp & vdp) maybe waiting for this event */
+ p_scb = bta_av_cb.p_scb[i];
+ if (p_scb && (bdcmp (peer_addr, p_scb->peer_addr) == 0) &&
+ (p_buf = (tBTA_AV_ROLE_RES *) GKI_getbuf(sizeof(tBTA_AV_ROLE_RES))) != NULL)
+ {
+ APPL_TRACE_DEBUG3("new_role:%d, hci_status:x%x hndl: x%x", id, app_id, p_scb->hndl);
+ /*
+ if ((id != BTM_ROLE_MASTER) && (app_id != HCI_SUCCESS))
+ {
+ bta_sys_set_policy(BTA_ID_AV, (HCI_ENABLE_MASTER_SLAVE_SWITCH|HCI_ENABLE_SNIFF_MODE), p_scb->peer_addr);
+ }
+ */
+ p_buf->hdr.event = BTA_AV_ROLE_CHANGE_EVT;
+ p_buf->hdr.layer_specific = p_scb->hndl;
+ p_buf->new_role = id;
+ p_buf->hci_status = app_id;
+ bta_sys_sendmsg(p_buf);
+
+ peer_idx = p_scb->hdi + 1; /* Handle index for the peer_addr */
+ }
+ }
+
+ /* restore role switch policy, if role switch failed */
+ if ((HCI_SUCCESS != app_id) &&
+ (BTM_GetRole (peer_addr, &cur_role) == BTM_SUCCESS) &&
+ (cur_role == BTM_ROLE_SLAVE) )
+ {
+ bta_sys_set_policy(BTA_ID_AV, HCI_ENABLE_MASTER_SLAVE_SWITCH, peer_addr);
+ }
+
+ /* if BTA_AvOpen() was called for other device, which caused the role switch of the peer_addr, */
+ /* we need to continue opening process for the BTA_AvOpen(). */
+ if ((bta_av_cb.rs_idx != 0) && (bta_av_cb.rs_idx != peer_idx))
+ {
+ p_scb = bta_av_cb.p_scb[bta_av_cb.rs_idx - 1];
+ if (p_scb && p_scb->q_tag == BTA_AV_Q_TAG_OPEN)
+ {
+ APPL_TRACE_DEBUG3 ("bta_av_sys_rs_cback: rs_idx(%d), hndl:x%x q_tag: %d",
+ bta_av_cb.rs_idx, p_scb->hndl, p_scb->q_tag);
+
+ if(HCI_SUCCESS == app_id || HCI_ERR_NO_CONNECTION == app_id)
+ p_scb->q_info.open.switch_res = BTA_AV_RS_OK;
+ else
+ p_scb->q_info.open.switch_res = BTA_AV_RS_FAIL;
+
+ /* Continue av open process */
+ bta_av_do_disc_a2d (p_scb, (tBTA_AV_DATA *)&(p_scb->q_info.open));
+ }
+
+ bta_av_cb.rs_idx = 0;
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_sco_chg_cback
+**
+** Description receive & process the SCO connection up/down event from sys.
+** call setup also triggers this callback, to suspend av before sco
+** activity happens, or to resume av once call ends.
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_av_sco_chg_cback(tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8
+ app_id, BD_ADDR peer_addr)
+{
+ tBTA_AV_SCB *p_scb;
+ int i;
+ tBTA_AV_API_STOP stop;
+
+ APPL_TRACE_DEBUG2("bta_av_sco_chg_cback:%d status:%d", id, status);
+ if(id)
+ {
+ bta_av_cb.sco_occupied = TRUE;
+
+ /* either BTA_SYS_SCO_OPEN or BTA_SYS_SCO_CLOSE with remaining active SCO */
+ for(i=0; i<BTA_AV_NUM_STRS; i++)
+ {
+ p_scb = bta_av_cb.p_scb[i];
+
+ if( p_scb && p_scb->co_started && (p_scb->sco_suspend == FALSE))
+ {
+ APPL_TRACE_DEBUG1("suspending scb:%d", i);
+ /* scb is used and started, not suspended automatically */
+ p_scb->sco_suspend = TRUE;
+ stop.flush = FALSE;
+ stop.suspend = TRUE;
+ bta_av_ssm_execute(p_scb, BTA_AV_AP_STOP_EVT, (tBTA_AV_DATA *)&stop);
+ }
+ }
+ }
+ else
+ {
+ bta_av_cb.sco_occupied = FALSE;
+
+ for(i=0; i<BTA_AV_NUM_STRS; i++)
+ {
+ p_scb = bta_av_cb.p_scb[i];
+
+ if( p_scb && p_scb->sco_suspend ) /* scb is used and suspended for SCO */
+ {
+ APPL_TRACE_DEBUG1("starting scb:%d", i);
+ bta_av_ssm_execute(p_scb, BTA_AV_AP_START_EVT, NULL);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_switch_if_needed
+**
+** Description This function checks if there is another existing AV
+** channel that is local as slave role.
+** If so, role switch and remove it from link policy.
+**
+** Returns TRUE, if role switch is done
+**
+*******************************************************************************/
+BOOLEAN bta_av_switch_if_needed(tBTA_AV_SCB *p_scb)
+{
+ UINT8 role;
+ BOOLEAN needed = FALSE;
+ tBTA_AV_SCB *p_scbi;
+ int i;
+ UINT8 mask;
+
+ for(i=0; i<BTA_AV_NUM_STRS; i++)
+ {
+ mask = BTA_AV_HNDL_TO_MSK(i);
+ p_scbi = bta_av_cb.p_scb[i];
+ if( p_scbi && (p_scb->hdi != i) && /* not the original channel */
+ ((bta_av_cb.conn_audio & mask) ||/* connected audio */
+ (bta_av_cb.conn_video & mask)) ) /* connected video */
+ {
+ BTM_GetRole(p_scbi->peer_addr, &role);
+ /* this channel is open - clear the role switch link policy for this link */
+ if(BTM_ROLE_MASTER != role)
+ {
+ if (bta_av_cb.features & BTA_AV_FEAT_MASTER)
+ bta_sys_clear_policy(BTA_ID_AV, HCI_ENABLE_MASTER_SLAVE_SWITCH, p_scbi->peer_addr);
+ if (BTM_CMD_STARTED != BTM_SwitchRole(p_scbi->peer_addr, BTM_ROLE_MASTER, NULL))
+ {
+ /* can not switch role on SCBI
+ * start the timer on SCB - because this function is ONLY called when SCB gets API_OPEN */
+ bta_sys_start_timer(&p_scb->timer, BTA_AV_AVRC_TIMER_EVT, BTA_AV_RS_TIME_VAL);
+ }
+ needed = TRUE;
+ /* mark the original channel as waiting for RS result */
+ bta_av_cb.rs_idx = p_scb->hdi + 1;
+ break;
+ }
+ }
+ }
+ return needed;
+}
+
+/*******************************************************************************
+**
+** Function bta_av_link_role_ok
+**
+** Description This function checks if the SCB has existing ACL connection
+** If so, check if the link role fits the requirements.
+**
+** Returns TRUE, if role is ok
+**
+*******************************************************************************/
+BOOLEAN bta_av_link_role_ok(tBTA_AV_SCB *p_scb, UINT8 bits)
+{
+ UINT8 role;
+ BOOLEAN is_ok = TRUE;
+ BOOLEAN need_timer = FALSE;
+
+ if (BTM_GetRole(p_scb->peer_addr, &role) == BTM_SUCCESS)
+ {
+ APPL_TRACE_ERROR5("bta_av_link_role_ok hndl:x%x role:%d, conn_audio:x%x, bits:%d, features:x%x", p_scb->hndl, role, bta_av_cb.conn_audio, bits, bta_av_cb.features);
+ if (BTM_ROLE_MASTER != role && (A2D_BitsSet(bta_av_cb.conn_audio) > bits || (bta_av_cb.features & BTA_AV_FEAT_MASTER)))
+ {
+ if (bta_av_cb.features & BTA_AV_FEAT_MASTER)
+ bta_sys_clear_policy(BTA_ID_AV, HCI_ENABLE_MASTER_SLAVE_SWITCH, p_scb->peer_addr);
+
+ if (BTM_CMD_STARTED != BTM_SwitchRole(p_scb->peer_addr, BTM_ROLE_MASTER, NULL))
+ {
+ /* can not switch role on SCB - start the timer on SCB */
+ need_timer = TRUE;
+ }
+ is_ok = FALSE;
+ p_scb->wait |= BTA_AV_WAIT_ROLE_SW_RES_START;
+
+ }
+ }
+
+ return is_ok;
+}
+
+/*******************************************************************************
+**
+** Function bta_av_chk_mtu
+**
+** Description if this is audio channel, check if more than one audio
+** channel is connected.
+**
+** Returns The smallest mtu of the connected audio channels
+**
+*******************************************************************************/
+UINT16 bta_av_chk_mtu(tBTA_AV_SCB *p_scb, UINT16 mtu)
+{
+ UINT16 ret_mtu = BTA_AV_MAX_A2DP_MTU;
+ tBTA_AV_SCB *p_scbi;
+ int i;
+ UINT8 mask;
+
+ /* TODO_MV mess with the mtu according to the number of EDR/non-EDR headsets */
+ if(p_scb->chnl == BTA_AV_CHNL_AUDIO)
+ {
+ if(bta_av_cb.audio_open_cnt >= 2)
+ {
+ /* more than one audio channel is connected */
+ for(i=0; i<BTA_AV_NUM_STRS; i++)
+ {
+ p_scbi = bta_av_cb.p_scb[i];
+ if((p_scb != p_scbi) && p_scbi && (p_scbi->chnl == BTA_AV_CHNL_AUDIO) )
+ {
+ mask = BTA_AV_HNDL_TO_MSK(i);
+ APPL_TRACE_DEBUG3("[%d] mtu: %d, mask:0x%x",
+ i, p_scbi->stream_mtu, mask);
+ if(bta_av_cb.conn_audio & mask)
+ {
+ if(ret_mtu > p_scbi->stream_mtu)
+ ret_mtu = p_scbi->stream_mtu;
+ }
+ }
+ }
+ }
+ APPL_TRACE_DEBUG3("bta_av_chk_mtu audio count:%d, conn_audio:0x%x, ret:%d",
+ bta_av_cb.audio_open_cnt, bta_av_cb.conn_audio, ret_mtu);
+ }
+ return ret_mtu;
+}
+
+/*******************************************************************************
+**
+** Function bta_av_dup_audio_buf
+**
+** Description dup the audio data to the q_info.a2d of other audio channels
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_dup_audio_buf(tBTA_AV_SCB *p_scb, BT_HDR *p_buf)
+{
+ tBTA_AV_SCB *p_scbi;
+ BUFFER_Q *pq;
+ int i;
+ UINT16 size, copy_size;
+ BT_HDR *p_new;
+
+ if(!p_buf)
+ return;
+
+ if(bta_av_cb.audio_open_cnt >= 2)
+ {
+ size = GKI_get_buf_size(p_buf);
+ copy_size = BT_HDR_SIZE + p_buf->len + p_buf->offset;
+ /* more than one audio channel is connected */
+ for(i=0; i<BTA_AV_NUM_STRS; i++)
+ {
+ p_scbi = bta_av_cb.p_scb[i];
+ if( (p_scb->hdi != i) && /* not the original channel */
+ (bta_av_cb.conn_audio & BTA_AV_HNDL_TO_MSK(i)) && /* connected audio */
+ p_scbi && p_scbi->co_started ) /* scb is used and started */
+ {
+ /* enqueue the data only when the stream is started */
+ p_new = (BT_HDR *)GKI_getbuf(size);
+ if(p_new)
+ {
+ memcpy(p_new, p_buf, copy_size);
+ pq = &p_scbi->q_info.a2d;
+ GKI_enqueue(pq, p_new);
+ if(pq->count > p_bta_av_cfg->audio_mqs)
+ {
+ bta_av_co_audio_drop(p_scbi->hndl);
+ GKI_freebuf(GKI_dequeue(pq));
+ }
+ }
+ }
+ }
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function bta_av_sm_execute
+**
+** Description State machine event handling function for AV
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_sm_execute(tBTA_AV_CB *p_cb, UINT16 event, tBTA_AV_DATA *p_data)
+{
+ tBTA_AV_ST_TBL state_table;
+ UINT8 action;
+
+#if (defined(BTA_AV_DEBUG) && BTA_AV_DEBUG == TRUE)
+ APPL_TRACE_EVENT4("AV event=0x%x(%s) state=%d(%s)",
+ event, bta_av_evt_code(event), p_cb->state, bta_av_st_code(p_cb->state));
+#else
+ APPL_TRACE_EVENT2("AV event=0x%x state=%d", event, p_cb->state);
+#endif
+
+ /* look up the state table for the current state */
+ state_table = bta_av_st_tbl[p_cb->state];
+
+ event &= 0x00FF;
+
+ /* set next state */
+ p_cb->state = state_table[event][BTA_AV_NEXT_STATE];
+ APPL_TRACE_EVENT1("next state=%d", p_cb->state);
+
+ /* execute action functions */
+ if ((action = state_table[event][BTA_AV_ACTION_COL]) != BTA_AV_IGNORE)
+ {
+ (*bta_av_action[action])(p_cb, p_data);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function bta_av_hdl_event
+**
+** Description Advanced audio/video main event handling function.
+**
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+BOOLEAN bta_av_hdl_event(BT_HDR *p_msg)
+{
+ UINT16 event = p_msg->event;
+ UINT16 first_event = BTA_AV_FIRST_NSM_EVT;
+
+ if (event > BTA_AV_LAST_EVT)
+ {
+ return TRUE; /* to free p_msg */
+ }
+
+ if(event >= first_event)
+ {
+#if (defined(BTA_AV_DEBUG) && BTA_AV_DEBUG == TRUE)
+ APPL_TRACE_EVENT2("AV nsm event=0x%x(%s)", event, bta_av_evt_code(event));
+#else
+ APPL_TRACE_EVENT1("AV nsm event=0x%x", event);
+#endif
+ /* non state machine events */
+ (*bta_av_nsm_act[event - BTA_AV_FIRST_NSM_EVT]) ((tBTA_AV_DATA *) p_msg);
+ }
+ else if (event >= BTA_AV_FIRST_SM_EVT && event <= BTA_AV_LAST_SM_EVT)
+ {
+#if (defined(BTA_AV_DEBUG) && BTA_AV_DEBUG == TRUE)
+ APPL_TRACE_EVENT2("AV sm event=0x%x(%s)", event, bta_av_evt_code(event));
+#else
+ APPL_TRACE_EVENT1("AV sm event=0x%x", event);
+#endif
+ /* state machine events */
+ bta_av_sm_execute(&bta_av_cb, p_msg->event, (tBTA_AV_DATA *) p_msg);
+ }
+ else
+ {
+ APPL_TRACE_EVENT1("handle=0x%x", p_msg->layer_specific);
+ /* stream state machine events */
+ bta_av_ssm_execute( bta_av_hndl_to_scb(p_msg->layer_specific),
+ p_msg->event, (tBTA_AV_DATA *) p_msg);
+ }
+ return TRUE;
+}
+
+
+/*****************************************************************************
+** Debug Functions
+*****************************************************************************/
+#if (defined(BTA_AV_DEBUG) && BTA_AV_DEBUG == TRUE)
+/*******************************************************************************
+**
+** Function bta_av_st_code
+**
+** Description
+**
+** Returns char *
+**
+*******************************************************************************/
+static char *bta_av_st_code(UINT8 state)
+{
+ switch(state)
+ {
+ case BTA_AV_INIT_ST: return "INIT";
+ case BTA_AV_OPEN_ST: return "OPEN";
+ default: return "unknown";
+ }
+}
+/*******************************************************************************
+**
+** Function bta_av_evt_code
+**
+** Description
+**
+** Returns char *
+**
+*******************************************************************************/
+char *bta_av_evt_code(UINT16 evt_code)
+{
+ switch(evt_code)
+ {
+ case BTA_AV_API_DISABLE_EVT: return "API_DISABLE";
+ case BTA_AV_API_REMOTE_CMD_EVT: return "API_REMOTE_CMD";
+ case BTA_AV_API_VENDOR_CMD_EVT: return "API_VENDOR_CMD";
+ case BTA_AV_API_VENDOR_RSP_EVT: return "API_VENDOR_RSP";
+ case BTA_AV_API_META_RSP_EVT: return "API_META_RSP_EVT";
+ case BTA_AV_API_RC_CLOSE_EVT: return "API_RC_CLOSE";
+ case BTA_AV_AVRC_OPEN_EVT: return "AVRC_OPEN";
+ case BTA_AV_AVRC_MSG_EVT: return "AVRC_MSG";
+ case BTA_AV_AVRC_NONE_EVT: return "AVRC_NONE";
+
+ case BTA_AV_API_OPEN_EVT: return "API_OPEN";
+ case BTA_AV_API_CLOSE_EVT: return "API_CLOSE";
+ case BTA_AV_AP_START_EVT: return "AP_START";
+ case BTA_AV_AP_STOP_EVT: return "AP_STOP";
+ case BTA_AV_API_RECONFIG_EVT: return "API_RECONFIG";
+ case BTA_AV_API_PROTECT_REQ_EVT: return "API_PROTECT_REQ";
+ case BTA_AV_API_PROTECT_RSP_EVT: return "API_PROTECT_RSP";
+ case BTA_AV_API_RC_OPEN_EVT: return "API_RC_OPEN";
+ case BTA_AV_SRC_DATA_READY_EVT: return "SRC_DATA_READY";
+ case BTA_AV_CI_SETCONFIG_OK_EVT: return "CI_SETCONFIG_OK";
+ case BTA_AV_CI_SETCONFIG_FAIL_EVT: return "CI_SETCONFIG_FAIL";
+ case BTA_AV_SDP_DISC_OK_EVT: return "SDP_DISC_OK";
+ case BTA_AV_SDP_DISC_FAIL_EVT: return "SDP_DISC_FAIL";
+ case BTA_AV_STR_DISC_OK_EVT: return "STR_DISC_OK";
+ case BTA_AV_STR_DISC_FAIL_EVT: return "STR_DISC_FAIL";
+ case BTA_AV_STR_GETCAP_OK_EVT: return "STR_GETCAP_OK";
+ case BTA_AV_STR_GETCAP_FAIL_EVT: return "STR_GETCAP_FAIL";
+ case BTA_AV_STR_OPEN_OK_EVT: return "STR_OPEN_OK";
+ case BTA_AV_STR_OPEN_FAIL_EVT: return "STR_OPEN_FAIL";
+ case BTA_AV_STR_START_OK_EVT: return "STR_START_OK";
+ case BTA_AV_STR_START_FAIL_EVT: return "STR_START_FAIL";
+ case BTA_AV_STR_CLOSE_EVT: return "STR_CLOSE";
+ case BTA_AV_STR_CONFIG_IND_EVT: return "STR_CONFIG_IND";
+ case BTA_AV_STR_SECURITY_IND_EVT: return "STR_SECURITY_IND";
+ case BTA_AV_STR_SECURITY_CFM_EVT: return "STR_SECURITY_CFM";
+ case BTA_AV_STR_WRITE_CFM_EVT: return "STR_WRITE_CFM";
+ case BTA_AV_STR_SUSPEND_CFM_EVT: return "STR_SUSPEND_CFM";
+ case BTA_AV_STR_RECONFIG_CFM_EVT: return "STR_RECONFIG_CFM";
+ case BTA_AV_AVRC_TIMER_EVT: return "AVRC_TIMER";
+ case BTA_AV_AVDT_CONNECT_EVT: return "AVDT_CONNECT";
+ case BTA_AV_AVDT_DISCONNECT_EVT: return "AVDT_DISCONNECT";
+ case BTA_AV_ROLE_CHANGE_EVT: return "ROLE_CHANGE";
+ case BTA_AV_AVDT_DELAY_RPT_EVT: return "AVDT_DELAY_RPT";
+ case BTA_AV_ACP_CONNECT_EVT: return "ACP_CONNECT";
+
+ case BTA_AV_API_ENABLE_EVT: return "API_ENABLE";
+ case BTA_AV_API_REGISTER_EVT: return "API_REG";
+ case BTA_AV_API_DEREGISTER_EVT: return "API_DEREG";
+ case BTA_AV_API_DISCONNECT_EVT: return "API_DISCNT";
+ case BTA_AV_CI_SRC_DATA_READY_EVT: return "CI_DATA_READY";
+ case BTA_AV_SIG_CHG_EVT: return "SIG_CHG";
+ case BTA_AV_SIG_TIMER_EVT: return "SIG_TMR";
+ case BTA_AV_SDP_AVRC_DISC_EVT: return "SDP_AVRC_DISC";
+ case BTA_AV_AVRC_CLOSE_EVT: return "AVRC_CLOSE";
+ case BTA_AV_CONN_CHG_EVT: return "CONN_CHG";
+ case BTA_AV_DEREG_COMP_EVT: return "DEREG_COMP";
+#if (AVDT_REPORTING == TRUE)
+ case BTA_AV_AVDT_RPT_CONN_EVT: return "RPT_CONN";
+#endif
+ case BTA_AV_API_START_EVT: return "API_START";
+ case BTA_AV_API_STOP_EVT: return "API_STOP";
+ default: return "unknown";
+ }
+}
+#endif
+
+#endif /* AV_INCLUDED */
diff --git a/bta/av/bta_av_ssm.c b/bta/av/bta_av_ssm.c
new file mode 100644
index 0000000..ec3532a
--- /dev/null
+++ b/bta/av/bta_av_ssm.c
@@ -0,0 +1,587 @@
+/*****************************************************************************
+**
+** Name: bta_av_ssm.c
+**
+** Description: This is the stream state machine for the BTA
+** advanced audio/video.
+**
+** Copyright (c) 2004, Broadcom Inc., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+#if defined(BTA_AV_INCLUDED) && (BTA_AV_INCLUDED == TRUE)
+
+#include <string.h>
+#include "bta_av_co.h"
+#include "bta_av_int.h"
+
+/*****************************************************************************
+** Constants and types
+*****************************************************************************/
+
+/* state machine states */
+enum
+{
+ BTA_AV_INIT_SST,
+ BTA_AV_INCOMING_SST,
+ BTA_AV_OPENING_SST,
+ BTA_AV_OPEN_SST,
+ BTA_AV_RCFG_SST,
+ BTA_AV_CLOSING_SST
+};
+
+
+/* state machine action enumeration list */
+enum
+{
+ BTA_AV_DO_DISC,
+ BTA_AV_CLEANUP,
+ BTA_AV_FREE_SDB,
+ BTA_AV_CONFIG_IND,
+ BTA_AV_DISCONNECT_REQ,
+ BTA_AV_SECURITY_REQ,
+ BTA_AV_SECURITY_RSP,
+ BTA_AV_SETCONFIG_RSP,
+ BTA_AV_ST_RC_TIMER,
+ BTA_AV_STR_OPENED,
+ BTA_AV_SECURITY_IND,
+ BTA_AV_SECURITY_CFM,
+ BTA_AV_DO_CLOSE,
+ BTA_AV_CONNECT_REQ,
+ BTA_AV_SDP_FAILED,
+ BTA_AV_DISC_RESULTS,
+ BTA_AV_DISC_RES_AS_ACP,
+ BTA_AV_OPEN_FAILED,
+ BTA_AV_GETCAP_RESULTS,
+ BTA_AV_SETCONFIG_REJ,
+ BTA_AV_DISCOVER_REQ,
+ BTA_AV_CONN_FAILED,
+ BTA_AV_DO_START,
+ BTA_AV_STR_STOPPED,
+ BTA_AV_RECONFIG,
+ BTA_AV_DATA_PATH,
+ BTA_AV_START_OK,
+ BTA_AV_START_FAILED,
+ BTA_AV_STR_CLOSED,
+ BTA_AV_CLR_CONG,
+ BTA_AV_SUSPEND_CFM,
+ BTA_AV_RCFG_STR_OK,
+ BTA_AV_RCFG_FAILED,
+ BTA_AV_RCFG_CONNECT,
+ BTA_AV_RCFG_DISCNTD,
+ BTA_AV_SUSPEND_CONT,
+ BTA_AV_RCFG_CFM,
+ BTA_AV_RCFG_OPEN,
+ BTA_AV_SECURITY_REJ,
+ BTA_AV_OPEN_RC,
+ BTA_AV_CHK_2ND_START,
+ BTA_AV_SAVE_CAPS,
+ BTA_AV_SET_USE_RC,
+ BTA_AV_CCO_CLOSE,
+ BTA_AV_SWITCH_ROLE,
+ BTA_AV_ROLE_RES,
+ BTA_AV_DELAY_CO,
+ BTA_AV_OPEN_AT_INC,
+ BTA_AV_NUM_SACTIONS
+};
+
+#define BTA_AV_SIGNORE BTA_AV_NUM_SACTIONS
+
+
+/* state table information */
+/* #define BTA_AV_SACTION_COL 0 position of actions */
+#define BTA_AV_SACTIONS 2 /* number of actions */
+#define BTA_AV_SNEXT_STATE 2 /* position of next state */
+#define BTA_AV_NUM_COLS 3 /* number of columns in state tables */
+
+/* state table for init state */
+static const UINT8 bta_av_sst_init[][BTA_AV_NUM_COLS] =
+{
+/* Event Action 1 Action 2 Next state */
+/* AP_OPEN_EVT */ {BTA_AV_DO_DISC, BTA_AV_SIGNORE, BTA_AV_OPENING_SST },
+/* AP_CLOSE_EVT */ {BTA_AV_CLEANUP, BTA_AV_SIGNORE, BTA_AV_INIT_SST },
+/* AP_START_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST },
+/* AP_STOP_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST },
+/* API_RECONFIG_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST },
+/* API_PROTECT_REQ_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST },
+/* API_PROTECT_RSP_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST },
+/* API_RC_OPEN_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST },
+/* SRC_DATA_READY_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST },
+/* CI_SETCONFIG_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST },
+/* CI_SETCONFIG_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST },
+/* SDP_DISC_OK_EVT */ {BTA_AV_FREE_SDB, BTA_AV_SIGNORE, BTA_AV_INIT_SST },
+/* SDP_DISC_FAIL_EVT */ {BTA_AV_FREE_SDB, BTA_AV_SIGNORE, BTA_AV_INIT_SST },
+/* STR_DISC_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST },
+/* STR_DISC_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST },
+/* STR_GETCAP_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST },
+/* STR_GETCAP_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST },
+/* STR_OPEN_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST },
+/* STR_OPEN_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST },
+/* STR_START_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST },
+/* STR_START_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST },
+/* STR_CLOSE_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST },
+/* STR_CONFIG_IND_EVT */ {BTA_AV_SETCONFIG_REJ, BTA_AV_SIGNORE, BTA_AV_INIT_SST },
+/* STR_SECURITY_IND_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST },
+/* STR_SECURITY_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST },
+/* STR_WRITE_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST },
+/* STR_SUSPEND_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST },
+/* STR_RECONFIG_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST },
+/* AVRC_TIMER_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST },
+/* AVDT_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST },
+/* AVDT_DISCONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST },
+/* ROLE_CHANGE_EVT*/ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST },
+/* AVDT_DELAY_RPT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST },
+/* ACP_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }
+};
+
+/* state table for incoming state */
+static const UINT8 bta_av_sst_incoming[][BTA_AV_NUM_COLS] =
+{
+/* Event Action 1 Action 2 Next state */
+/* AP_OPEN_EVT */ {BTA_AV_OPEN_AT_INC, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST },
+/* AP_CLOSE_EVT */ {BTA_AV_CCO_CLOSE, BTA_AV_DISCONNECT_REQ, BTA_AV_CLOSING_SST },
+/* AP_START_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST },
+/* AP_STOP_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST },
+/* API_RECONFIG_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST },
+/* API_PROTECT_REQ_EVT */ {BTA_AV_SECURITY_REQ, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST },
+/* API_PROTECT_RSP_EVT */ {BTA_AV_SECURITY_RSP, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST },
+/* API_RC_OPEN_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST },
+/* SRC_DATA_READY_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST },
+/* CI_SETCONFIG_OK_EVT */ {BTA_AV_SETCONFIG_RSP, BTA_AV_ST_RC_TIMER, BTA_AV_INCOMING_SST },
+/* CI_SETCONFIG_FAIL_EVT */ {BTA_AV_SETCONFIG_RSP, BTA_AV_CLEANUP, BTA_AV_INIT_SST },
+/* SDP_DISC_OK_EVT */ {BTA_AV_FREE_SDB, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST },
+/* SDP_DISC_FAIL_EVT */ {BTA_AV_FREE_SDB, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST },
+/* STR_DISC_OK_EVT */ {BTA_AV_DISC_RES_AS_ACP,BTA_AV_SIGNORE, BTA_AV_INCOMING_SST },
+/* STR_DISC_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST },
+/* STR_GETCAP_OK_EVT */ {BTA_AV_SAVE_CAPS, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST },
+/* STR_GETCAP_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST },
+/* STR_OPEN_OK_EVT */ {BTA_AV_STR_OPENED, BTA_AV_SIGNORE, BTA_AV_OPEN_SST },
+/* STR_OPEN_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST },
+/* STR_START_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST },
+/* STR_START_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST },
+/* STR_CLOSE_EVT */ {BTA_AV_CCO_CLOSE, BTA_AV_CLEANUP, BTA_AV_INIT_SST },
+/* STR_CONFIG_IND_EVT */ {BTA_AV_CONFIG_IND, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST },
+/* STR_SECURITY_IND_EVT */ {BTA_AV_SECURITY_IND, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST },
+/* STR_SECURITY_CFM_EVT */ {BTA_AV_SECURITY_CFM, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST },
+/* STR_WRITE_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST },
+/* STR_SUSPEND_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST },
+/* STR_RECONFIG_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST },
+/* AVRC_TIMER_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST },
+/* AVDT_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST },
+/* AVDT_DISCONNECT_EVT */ {BTA_AV_CCO_CLOSE, BTA_AV_CLEANUP, BTA_AV_INIT_SST },
+/* ROLE_CHANGE_EVT*/ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST },
+/* AVDT_DELAY_RPT_EVT */ {BTA_AV_DELAY_CO, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST },
+/* ACP_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }
+};
+
+/* state table for opening state */
+static const UINT8 bta_av_sst_opening[][BTA_AV_NUM_COLS] =
+{
+/* Event Action 1 Action 2 Next state */
+/* AP_OPEN_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST },
+/* AP_CLOSE_EVT */ {BTA_AV_DO_CLOSE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST },
+/* AP_START_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST },
+/* AP_STOP_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST },
+/* API_RECONFIG_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST },
+/* API_PROTECT_REQ_EVT */ {BTA_AV_SECURITY_REQ, BTA_AV_SIGNORE, BTA_AV_OPENING_SST },
+/* API_PROTECT_RSP_EVT */ {BTA_AV_SECURITY_RSP, BTA_AV_SIGNORE, BTA_AV_OPENING_SST },
+/* API_RC_OPEN_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST },
+/* SRC_DATA_READY_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST },
+/* CI_SETCONFIG_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST },
+/* CI_SETCONFIG_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST },
+/* SDP_DISC_OK_EVT */ {BTA_AV_CONNECT_REQ, BTA_AV_SIGNORE, BTA_AV_OPENING_SST },
+/* SDP_DISC_FAIL_EVT */ {BTA_AV_SDP_FAILED, BTA_AV_SIGNORE, BTA_AV_INIT_SST },
+/* STR_DISC_OK_EVT */ {BTA_AV_DISC_RESULTS, BTA_AV_SIGNORE, BTA_AV_OPENING_SST },
+/* STR_DISC_FAIL_EVT */ {BTA_AV_OPEN_FAILED, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST },
+/* STR_GETCAP_OK_EVT */ {BTA_AV_GETCAP_RESULTS, BTA_AV_SIGNORE, BTA_AV_OPENING_SST },
+/* STR_GETCAP_FAIL_EVT */ {BTA_AV_OPEN_FAILED, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST },
+/* STR_OPEN_OK_EVT */ {BTA_AV_ST_RC_TIMER, BTA_AV_STR_OPENED, BTA_AV_OPEN_SST },
+/* STR_OPEN_FAIL_EVT */ {BTA_AV_OPEN_FAILED, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST },
+/* STR_START_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST },
+/* STR_START_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST },
+/* STR_CLOSE_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST },
+/* STR_CONFIG_IND_EVT */ {BTA_AV_CONFIG_IND, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST },
+/* STR_SECURITY_IND_EVT */ {BTA_AV_SECURITY_IND, BTA_AV_SIGNORE, BTA_AV_OPENING_SST },
+/* STR_SECURITY_CFM_EVT */ {BTA_AV_SECURITY_CFM, BTA_AV_SIGNORE, BTA_AV_OPENING_SST },
+/* STR_WRITE_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST },
+/* STR_SUSPEND_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST },
+/* STR_RECONFIG_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST },
+/* AVRC_TIMER_EVT */ {BTA_AV_SWITCH_ROLE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST },
+/* AVDT_CONNECT_EVT */ {BTA_AV_DISCOVER_REQ, BTA_AV_SIGNORE, BTA_AV_OPENING_SST },
+/* AVDT_DISCONNECT_EVT */ {BTA_AV_CONN_FAILED, BTA_AV_SIGNORE, BTA_AV_INIT_SST },
+/* ROLE_CHANGE_EVT*/ {BTA_AV_ROLE_RES, BTA_AV_SIGNORE, BTA_AV_OPENING_SST },
+/* AVDT_DELAY_RPT_EVT */ {BTA_AV_DELAY_CO, BTA_AV_SIGNORE, BTA_AV_OPENING_SST },
+/* ACP_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }
+};
+
+/* state table for open state */
+static const UINT8 bta_av_sst_open[][BTA_AV_NUM_COLS] =
+{
+/* Event Action 1 Action 2 Next state */
+/* AP_OPEN_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST },
+/* AP_CLOSE_EVT */ {BTA_AV_DO_CLOSE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST },
+/* AP_START_EVT */ {BTA_AV_DO_START, BTA_AV_SIGNORE, BTA_AV_OPEN_SST },
+/* AP_STOP_EVT */ {BTA_AV_STR_STOPPED, BTA_AV_SIGNORE, BTA_AV_OPEN_SST },
+/* API_RECONFIG_EVT */ {BTA_AV_RECONFIG, BTA_AV_SIGNORE, BTA_AV_RCFG_SST },
+/* API_PROTECT_REQ_EVT */ {BTA_AV_SECURITY_REQ, BTA_AV_SIGNORE, BTA_AV_OPEN_SST },
+/* API_PROTECT_RSP_EVT */ {BTA_AV_SECURITY_RSP, BTA_AV_SIGNORE, BTA_AV_OPEN_SST },
+/* API_RC_OPEN_EVT */ {BTA_AV_SET_USE_RC, BTA_AV_OPEN_RC, BTA_AV_OPEN_SST },
+/* SRC_DATA_READY_EVT */ {BTA_AV_DATA_PATH, BTA_AV_SIGNORE, BTA_AV_OPEN_SST },
+/* CI_SETCONFIG_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST },
+/* CI_SETCONFIG_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST },
+/* SDP_DISC_OK_EVT */ {BTA_AV_FREE_SDB, BTA_AV_SIGNORE, BTA_AV_OPEN_SST },
+/* SDP_DISC_FAIL_EVT */ {BTA_AV_FREE_SDB, BTA_AV_SIGNORE, BTA_AV_OPEN_SST },
+/* STR_DISC_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST },
+/* STR_DISC_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST },
+/* STR_GETCAP_OK_EVT */ {BTA_AV_SAVE_CAPS, BTA_AV_SIGNORE, BTA_AV_OPEN_SST },
+/* STR_GETCAP_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST },
+/* STR_OPEN_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST },
+/* STR_OPEN_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST },
+/* STR_START_OK_EVT */ {BTA_AV_START_OK, BTA_AV_SIGNORE, BTA_AV_OPEN_SST },
+/* STR_START_FAIL_EVT */ {BTA_AV_START_FAILED, BTA_AV_SIGNORE, BTA_AV_OPEN_SST },
+/* STR_CLOSE_EVT */ {BTA_AV_STR_CLOSED, BTA_AV_SIGNORE, BTA_AV_INIT_SST },
+/* STR_CONFIG_IND_EVT */ {BTA_AV_SETCONFIG_REJ, BTA_AV_SIGNORE, BTA_AV_OPEN_SST },
+/* STR_SECURITY_IND_EVT */ {BTA_AV_SECURITY_IND, BTA_AV_SIGNORE, BTA_AV_OPEN_SST },
+/* STR_SECURITY_CFM_EVT */ {BTA_AV_SECURITY_CFM, BTA_AV_SIGNORE, BTA_AV_OPEN_SST },
+/* STR_WRITE_CFM_EVT */ {BTA_AV_CLR_CONG, BTA_AV_DATA_PATH, BTA_AV_OPEN_SST },
+/* STR_SUSPEND_CFM_EVT */ {BTA_AV_SUSPEND_CFM, BTA_AV_SIGNORE, BTA_AV_OPEN_SST },
+/* STR_RECONFIG_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST },
+/* AVRC_TIMER_EVT */ {BTA_AV_OPEN_RC, BTA_AV_CHK_2ND_START, BTA_AV_OPEN_SST },
+/* AVDT_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST },
+/* AVDT_DISCONNECT_EVT */ {BTA_AV_STR_CLOSED, BTA_AV_SIGNORE, BTA_AV_INIT_SST },
+/* ROLE_CHANGE_EVT*/ {BTA_AV_ROLE_RES, BTA_AV_SIGNORE, BTA_AV_OPEN_SST },
+/* AVDT_DELAY_RPT_EVT */ {BTA_AV_DELAY_CO, BTA_AV_SIGNORE, BTA_AV_OPEN_SST },
+/* ACP_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }
+};
+
+/* state table for reconfig state */
+static const UINT8 bta_av_sst_rcfg[][BTA_AV_NUM_COLS] =
+{
+/* Event Action 1 Action 2 Next state */
+/* AP_OPEN_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST },
+/* AP_CLOSE_EVT */ {BTA_AV_DISCONNECT_REQ, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST },
+/* AP_START_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST },
+/* AP_STOP_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST },
+/* API_RECONFIG_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST },
+/* API_PROTECT_REQ_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST },
+/* API_PROTECT_RSP_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST },
+/* API_RC_OPEN_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST },
+/* SRC_DATA_READY_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST },
+/* CI_SETCONFIG_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST },
+/* CI_SETCONFIG_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST },
+/* SDP_DISC_OK_EVT */ {BTA_AV_FREE_SDB, BTA_AV_SIGNORE, BTA_AV_RCFG_SST },
+/* SDP_DISC_FAIL_EVT */ {BTA_AV_FREE_SDB, BTA_AV_SIGNORE, BTA_AV_RCFG_SST },
+/* STR_DISC_OK_EVT */ {BTA_AV_DISC_RESULTS, BTA_AV_SIGNORE, BTA_AV_RCFG_SST },
+/* STR_DISC_FAIL_EVT */ {BTA_AV_STR_CLOSED, BTA_AV_SIGNORE, BTA_AV_INIT_SST },
+/* STR_GETCAP_OK_EVT */ {BTA_AV_GETCAP_RESULTS, BTA_AV_SIGNORE, BTA_AV_RCFG_SST },
+/* STR_GETCAP_FAIL_EVT */ {BTA_AV_STR_CLOSED, BTA_AV_SIGNORE, BTA_AV_INIT_SST },
+/* STR_OPEN_OK_EVT */ {BTA_AV_RCFG_STR_OK, BTA_AV_SIGNORE, BTA_AV_OPEN_SST },
+/* STR_OPEN_FAIL_EVT */ {BTA_AV_RCFG_FAILED, BTA_AV_SIGNORE, BTA_AV_RCFG_SST },
+/* STR_START_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST },
+/* STR_START_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST },
+/* STR_CLOSE_EVT */ {BTA_AV_RCFG_CONNECT, BTA_AV_SIGNORE, BTA_AV_RCFG_SST },
+/* STR_CONFIG_IND_EVT */ {BTA_AV_SETCONFIG_REJ, BTA_AV_SIGNORE, BTA_AV_RCFG_SST },
+/* STR_SECURITY_IND_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST },
+/* STR_SECURITY_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST },
+/* STR_WRITE_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST },
+/* STR_SUSPEND_CFM_EVT */ {BTA_AV_SUSPEND_CONT, BTA_AV_SIGNORE, BTA_AV_RCFG_SST },
+/* STR_RECONFIG_CFM_EVT */ {BTA_AV_RCFG_CFM, BTA_AV_SIGNORE, BTA_AV_RCFG_SST },
+/* AVRC_TIMER_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST },
+/* AVDT_CONNECT_EVT */ {BTA_AV_RCFG_OPEN, BTA_AV_SIGNORE, BTA_AV_RCFG_SST },
+/* AVDT_DISCONNECT_EVT */ {BTA_AV_RCFG_DISCNTD, BTA_AV_SIGNORE, BTA_AV_RCFG_SST },
+/* ROLE_CHANGE_EVT*/ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST },
+/* AVDT_DELAY_RPT_EVT */ {BTA_AV_DELAY_CO, BTA_AV_SIGNORE, BTA_AV_RCFG_SST },
+/* ACP_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }
+};
+
+/* state table for closing state */
+static const UINT8 bta_av_sst_closing[][BTA_AV_NUM_COLS] =
+{
+/* Event Action 1 Action 2 Next state */
+/* AP_OPEN_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST },
+/* AP_CLOSE_EVT */ {BTA_AV_DISCONNECT_REQ, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST },
+/* AP_START_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST },
+/* AP_STOP_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST },
+/* API_RECONFIG_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST },
+/* API_PROTECT_REQ_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST },
+/* API_PROTECT_RSP_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST },
+/* API_RC_OPEN_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST },
+/* SRC_DATA_READY_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST },
+/* CI_SETCONFIG_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST },
+/* CI_SETCONFIG_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST },
+/* SDP_DISC_OK_EVT */ {BTA_AV_SDP_FAILED, BTA_AV_SIGNORE, BTA_AV_INIT_SST },
+/* SDP_DISC_FAIL_EVT */ {BTA_AV_SDP_FAILED, BTA_AV_SIGNORE, BTA_AV_INIT_SST },
+/* STR_DISC_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST },
+/* STR_DISC_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST },
+/* STR_GETCAP_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST },
+/* STR_GETCAP_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST },
+/* STR_OPEN_OK_EVT */ {BTA_AV_DO_CLOSE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST },
+/* STR_OPEN_FAIL_EVT */ {BTA_AV_DISCONNECT_REQ, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST },
+/* STR_START_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST },
+/* STR_START_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST },
+/* STR_CLOSE_EVT */ {BTA_AV_DISCONNECT_REQ, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST },
+/* STR_CONFIG_IND_EVT */ {BTA_AV_SETCONFIG_REJ, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST },
+/* STR_SECURITY_IND_EVT */ {BTA_AV_SECURITY_REJ, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST },
+/* STR_SECURITY_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST },
+/* STR_WRITE_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST },
+/* STR_SUSPEND_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST },
+/* STR_RECONFIG_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST },
+/* AVRC_TIMER_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST },
+/* AVDT_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST },
+/* AVDT_DISCONNECT_EVT */ {BTA_AV_STR_CLOSED, BTA_AV_SIGNORE, BTA_AV_INIT_SST },
+/* ROLE_CHANGE_EVT*/ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST },
+/* AVDT_DELAY_RPT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST },
+/* ACP_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }
+};
+
+/* type for state table */
+typedef const UINT8 (*tBTA_AV_SST_TBL)[BTA_AV_NUM_COLS];
+
+/* state table */
+static const tBTA_AV_SST_TBL bta_av_sst_tbl[] =
+{
+ bta_av_sst_init,
+ bta_av_sst_incoming,
+ bta_av_sst_opening,
+ bta_av_sst_open,
+ bta_av_sst_rcfg,
+ bta_av_sst_closing
+};
+
+
+
+#if (defined(BTA_AV_DEBUG) && BTA_AV_DEBUG == TRUE)
+static char *bta_av_sst_code(UINT8 state);
+#endif
+
+/*******************************************************************************
+**
+** Function bta_av_is_rcfg_sst
+**
+** Description Check if stream state machine is in reconfig state.
+**
+**
+** Returns TRUE if stream state machine is in reconfig state.
+**
+*******************************************************************************/
+BOOLEAN bta_av_is_rcfg_sst (tBTA_AV_SCB *p_scb)
+{
+ BOOLEAN is_rcfg_sst = FALSE;
+
+ if (p_scb != NULL)
+ {
+ if (p_scb->state == BTA_AV_RCFG_SST)
+ is_rcfg_sst = TRUE;
+ }
+
+ return is_rcfg_sst;
+}
+
+/*******************************************************************************
+**
+** Function bta_av_ssm_execute
+**
+** Description Stream state machine event handling function for AV
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_ssm_execute(tBTA_AV_SCB *p_scb, UINT16 event, tBTA_AV_DATA *p_data)
+{
+ tBTA_AV_SST_TBL state_table;
+ UINT8 action;
+ int i, xx;
+
+ if(p_scb == NULL)
+ {
+ /* this stream is not registered */
+ APPL_TRACE_EVENT0("AV channel not registered");
+ return;
+ }
+
+ /* In case incoming connection is for VDP, we need to swap scb. */
+ /* When ACP_CONNECT_EVT was received, we put first available scb to */
+ /* to Incoming state. Later, when STR_CONFIG_IND_EVT is coming, we */
+ /* know if it is A2DP or VDP. */
+ if ((p_scb->state == BTA_AV_INIT_SST) && (event == BTA_AV_STR_CONFIG_IND_EVT))
+ {
+ for (xx = 0; xx < BTA_AV_NUM_STRS; xx++)
+ {
+ if (bta_av_cb.p_scb[xx])
+ {
+ if (bta_av_cb.p_scb[xx]->state == BTA_AV_INCOMING_SST)
+ {
+ bta_av_cb.p_scb[xx]->state = BTA_AV_INIT_SST;
+ bta_av_cb.p_scb[xx]->coll_mask = 0;
+ p_scb->state = BTA_AV_INCOMING_SST;
+ break;
+ }
+ }
+ }
+ }
+
+#if (defined(BTA_AV_DEBUG) && BTA_AV_DEBUG == TRUE)
+ APPL_TRACE_EVENT5("AV Sevent(0x%x)=0x%x(%s) state=%d(%s)",
+ p_scb->hndl, event, bta_av_evt_code(event), p_scb->state, bta_av_sst_code(p_scb->state));
+#else
+ APPL_TRACE_EVENT2("AV Sevent=0x%x state=%d", event, p_scb->state);
+#endif
+
+ /* look up the state table for the current state */
+ state_table = bta_av_sst_tbl[p_scb->state];
+
+ event -= BTA_AV_FIRST_SSM_EVT;
+
+ /* set next state */
+ p_scb->state = state_table[event][BTA_AV_SNEXT_STATE];
+
+ /* execute action functions */
+ for(i=0; i< BTA_AV_SACTIONS; i++)
+ {
+ if ((action = state_table[event][i]) != BTA_AV_SIGNORE)
+ {
+ (*p_scb->p_act_tbl[action])(p_scb, p_data);
+ }
+ else
+ break;
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function bta_av_is_scb_opening
+**
+** Description Returns TRUE is scb is in opening state.
+**
+**
+** Returns TRUE if scb is in opening state.
+**
+*******************************************************************************/
+BOOLEAN bta_av_is_scb_opening (tBTA_AV_SCB *p_scb)
+{
+ BOOLEAN is_opening = FALSE;
+
+ if (p_scb)
+ {
+ if (p_scb->state == BTA_AV_OPENING_SST)
+ is_opening = TRUE;
+ }
+
+ return is_opening;
+}
+
+/*******************************************************************************
+**
+** Function bta_av_is_scb_incoming
+**
+** Description Returns TRUE is scb is in incoming state.
+**
+**
+** Returns TRUE if scb is in incoming state.
+**
+*******************************************************************************/
+BOOLEAN bta_av_is_scb_incoming (tBTA_AV_SCB *p_scb)
+{
+ BOOLEAN is_incoming = FALSE;
+
+ if (p_scb)
+ {
+ if (p_scb->state == BTA_AV_INCOMING_SST)
+ is_incoming = TRUE;
+ }
+
+ return is_incoming;
+}
+
+/*******************************************************************************
+**
+** Function bta_av_set_scb_sst_init
+**
+** Description Set SST state to INIT.
+** Use this function to change SST outside of state machine.
+**
+** Returns None
+**
+*******************************************************************************/
+void bta_av_set_scb_sst_init (tBTA_AV_SCB *p_scb)
+{
+ if (p_scb)
+ {
+ p_scb->state = BTA_AV_INIT_SST;
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_is_scb_init
+**
+** Description Returns TRUE is scb is in init state.
+**
+**
+** Returns TRUE if scb is in incoming state.
+**
+*******************************************************************************/
+BOOLEAN bta_av_is_scb_init (tBTA_AV_SCB *p_scb)
+{
+ BOOLEAN is_init = FALSE;
+
+ if (p_scb)
+ {
+ if (p_scb->state == BTA_AV_INIT_SST)
+ is_init = TRUE;
+ }
+
+ return is_init;
+}
+
+/*******************************************************************************
+**
+** Function bta_av_set_scb_sst_incoming
+**
+** Description Set SST state to incoming.
+** Use this function to change SST outside of state machine.
+**
+** Returns None
+**
+*******************************************************************************/
+void bta_av_set_scb_sst_incoming (tBTA_AV_SCB *p_scb)
+{
+ if (p_scb)
+ {
+ p_scb->state = BTA_AV_INCOMING_SST;
+ }
+}
+
+/*****************************************************************************
+** Debug Functions
+*****************************************************************************/
+#if (defined(BTA_AV_DEBUG) && BTA_AV_DEBUG == TRUE)
+/*******************************************************************************
+**
+** Function bta_av_sst_code
+**
+** Description
+**
+** Returns char *
+**
+*******************************************************************************/
+static char *bta_av_sst_code(UINT8 state)
+{
+ switch(state)
+ {
+ case BTA_AV_INIT_SST: return "INIT";
+ case BTA_AV_INCOMING_SST: return "INCOMING";
+ case BTA_AV_OPENING_SST: return "OPENING";
+ case BTA_AV_OPEN_SST: return "OPEN";
+ case BTA_AV_RCFG_SST: return "RCFG";
+ case BTA_AV_CLOSING_SST: return "CLOSING";
+ default: return "unknown";
+ }
+}
+
+#endif
+#endif /* BTA_AV_INCLUDED */
diff --git a/bta/dg/bta_dg_act.c b/bta/dg/bta_dg_act.c
new file mode 100644
index 0000000..f01d606
--- /dev/null
+++ b/bta/dg/bta_dg_act.c
@@ -0,0 +1,900 @@
+/*****************************************************************************
+**
+** Name: bta_dg_act.c
+**
+** Description: This file contains the data gateway action functions
+** for the state machine.
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+
+#if defined(BTA_DG_INCLUDED) && (BTA_DG_INCLUDED == TRUE)
+
+#include <string.h>
+#include "bta_api.h"
+#include "bta_sys.h"
+#include "bta_dg_api.h"
+#include "bta_dg_int.h"
+#include "bta_dg_co.h"
+#include "btm_api.h"
+#include "sdp_api.h"
+#include "dun_api.h"
+#include "gki.h"
+#include "bd.h"
+
+/* Event mask for RfCOMM port callback */
+#define BTA_DG_PORT_EV_MASK (PORT_EV_FC | PORT_EV_FCS | PORT_EV_RXCHAR | \
+ PORT_EV_TXEMPTY | PORT_EV_CTS | PORT_EV_DSR | \
+ PORT_EV_RING | PORT_EV_CTSS | PORT_EV_DSRS)
+
+/* RX and TX data flow mask */
+#define BTA_DG_RX_MASK 0x0F
+#define BTA_DG_TX_MASK 0xF0
+
+/* size of database for service discovery */
+#define BTA_DG_DISC_BUF_SIZE 450
+
+/* size of discovery db taking into account tBTA_DG_SDP_DB */
+#define BTA_DG_SDP_DB_SIZE (BTA_DG_DISC_BUF_SIZE - (UINT32) &((tBTA_DG_SDP_DB *) 0)->db)
+
+/* UUID lookup table */
+const UINT16 bta_dg_uuid[] =
+{
+ UUID_SERVCLASS_SERIAL_PORT, /* BTA_SPP_SERVICE_ID */
+ UUID_SERVCLASS_DIALUP_NETWORKING, /* BTA_DUN_SERVICE_ID */
+ UUID_SERVCLASS_FAX, /* BTA_FAX_SERVICE_ID */
+ UUID_SERVCLASS_LAN_ACCESS_USING_PPP /* BTA_LAP_SERVICE_ID */
+};
+
+/* BTM service ID lookup table */
+const UINT8 bta_dg_sec_id[] =
+{
+ BTM_SEC_SERVICE_SERIAL_PORT, /* BTA_SPP_SERVICE_ID */
+ BTM_SEC_SERVICE_DUN, /* BTA_DUN_SERVICE_ID */
+ BTM_SEC_SERVICE_FAX, /* BTA_FAX_SERVICE_ID */
+ BTM_SEC_SERVICE_SERIAL_PORT /* BTA_LAP_SERVICE_ID */
+};
+
+/* RS-232 signal lookup table */
+const UINT8 bta_dg_sig[2][4] =
+{
+ {PORT_CLR_DTRDSR, PORT_CLR_CTSRTS, PORT_CLR_RI, PORT_CLR_DCD},
+ {PORT_SET_DTRDSR, PORT_SET_CTSRTS, PORT_SET_RI, PORT_SET_DCD}
+};
+
+/* declare sdp callback functions */
+void bta_dg_sdp_cback_1(UINT16 status);
+void bta_dg_sdp_cback_2(UINT16 status);
+void bta_dg_sdp_cback_3(UINT16 status);
+void bta_dg_sdp_cback_4(UINT16 status);
+void bta_dg_sdp_cback_5(UINT16 status);
+void bta_dg_sdp_cback_6(UINT16 status);
+void bta_dg_sdp_cback_7(UINT16 status);
+void bta_dg_sdp_cback_8(UINT16 status);
+
+/* SDP callback function table */
+typedef tSDP_DISC_CMPL_CB *tBTA_DG_SDP_CBACK;
+const tBTA_DG_SDP_CBACK bta_dg_sdp_cback_tbl[] =
+{
+ bta_dg_sdp_cback_1,
+ bta_dg_sdp_cback_2,
+ bta_dg_sdp_cback_3,
+ bta_dg_sdp_cback_4,
+ bta_dg_sdp_cback_5,
+ bta_dg_sdp_cback_6,
+ bta_dg_sdp_cback_7,
+ bta_dg_sdp_cback_8
+};
+
+/*******************************************************************************
+**
+** Function bta_dg_sdp_cback
+**
+** Description SDP callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_dg_sdp_cback(UINT16 status, UINT8 idx)
+{
+ tBTA_DG_DISC_RESULT *p_buf;
+
+ APPL_TRACE_DEBUG1("bta_dg_sdp_cback status:0x%x", status);
+
+ if ((p_buf = (tBTA_DG_DISC_RESULT *) GKI_getbuf(sizeof(tBTA_DG_DISC_RESULT))) != NULL)
+ {
+ p_buf->hdr.event = BTA_DG_DISC_RESULT_EVT;
+ p_buf->hdr.layer_specific = idx;
+ p_buf->status = status;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_dg_sdp_cback_1 to 8
+**
+** Description SDP callback functions. Since there is no way to
+** distinguish scb from the callback we need separate
+** callbacks for each scb.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dg_sdp_cback_1(UINT16 status) {bta_dg_sdp_cback(status, 1);}
+void bta_dg_sdp_cback_2(UINT16 status) {bta_dg_sdp_cback(status, 2);}
+void bta_dg_sdp_cback_3(UINT16 status) {bta_dg_sdp_cback(status, 3);}
+void bta_dg_sdp_cback_4(UINT16 status) {bta_dg_sdp_cback(status, 4);}
+void bta_dg_sdp_cback_5(UINT16 status) {bta_dg_sdp_cback(status, 5);}
+void bta_dg_sdp_cback_6(UINT16 status) {bta_dg_sdp_cback(status, 6);}
+void bta_dg_sdp_cback_7(UINT16 status) {bta_dg_sdp_cback(status, 7);}
+void bta_dg_sdp_cback_8(UINT16 status) {bta_dg_sdp_cback(status, 8);}
+
+/*******************************************************************************
+**
+** Function bta_dg_port_cback
+**
+** Description RFCOMM Port callback
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_dg_port_cback(UINT32 code, UINT16 port_handle)
+{
+ tBTA_DG_RFC_PORT *p_buf;
+ tBTA_DG_SCB *p_scb;
+
+ /* set flow control state directly */
+ if (code & PORT_EV_FC)
+ {
+ if ((p_scb = bta_dg_scb_by_handle(port_handle)) != NULL)
+ {
+ p_scb->rfc_enable = ((code & PORT_EV_FCS) == PORT_EV_FCS);
+
+ if ((p_scb->flow_mask & BTA_DG_RX_MASK) == BTA_DG_RX_PUSH_BUF)
+ {
+ bta_dg_co_rx_flow(port_handle, p_scb->app_id, p_scb->rfc_enable);
+ }
+ }
+ }
+
+ if ((p_buf = (tBTA_DG_RFC_PORT *) GKI_getbuf(sizeof(tBTA_DG_RFC_PORT))) != NULL)
+ {
+ p_buf->hdr.event = BTA_DG_RFC_PORT_EVT;
+ p_buf->hdr.layer_specific = port_handle;
+ p_buf->code = code;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_dg_mgmt_cback
+**
+** Description RFCOMM management callback
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_dg_mgmt_cback(UINT32 code, UINT16 port_handle)
+{
+ BT_HDR *p_buf;
+ tBTA_DG_SCB *p_scb;
+
+ if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->layer_specific = port_handle;
+
+ if (code == PORT_SUCCESS)
+ {
+ p_buf->event = BTA_DG_RFC_OPEN_EVT;
+ bta_sys_sendmsg(p_buf);
+ }
+ else
+ {
+ if ((p_scb = bta_dg_scb_by_handle(port_handle)) != NULL)
+ {
+/* APPL_TRACE_EVENT6("DG Port Close: handle %d, scb %d, app_id %d, in_use %d, scn %d, state %d",
+ port_handle, bta_dg_scb_to_idx(p_scb), p_scb->app_id, p_scb->in_use, p_scb->scn, p_scb->state);
+*/
+ p_buf->event = BTA_DG_RFC_CLOSE_EVT;
+
+ /* Execute close event before exiting RFC callback to avoid a race
+ condition where RFC could reallocate port_handle before DG can
+ process the event queue
+ */
+ bta_dg_sm_execute(p_scb, p_buf->event, (tBTA_DG_DATA *) p_buf);
+ }
+ else
+ {
+ APPL_TRACE_WARNING1("DG received RFC Close for unknown handle (%d)",
+ port_handle);
+ }
+
+ GKI_freebuf(p_buf);
+ }
+ }
+ else
+ {
+ APPL_TRACE_ERROR0("DG RFC callback: No Resources!");
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_dg_data_cback
+**
+** Description RFCOMM data callback. This callback is used when a server
+** TX data path is configured for BTA_DG_TX_PUSH to transfer
+** data directly from RFCOMM to the phone.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static int bta_dg_data_cback(UINT16 port_handle, void *p_data, UINT16 len)
+{
+ tBTA_DG_SCB *p_scb;
+
+ if ((p_scb = bta_dg_scb_by_handle(port_handle)) != NULL)
+ {
+ bta_dg_co_tx_write(port_handle, p_scb->app_id, (UINT8 *) p_data, len);
+ }
+ return 0;
+}
+
+/*******************************************************************************
+**
+** Function bta_dg_setup_port
+**
+** Description Setup RFCOMM port for use by DG.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_dg_setup_port(tBTA_DG_SCB *p_scb)
+{
+ /* store scb in handle lookup table */
+ bta_dg_cb.hdl_to_scb[p_scb->port_handle - 1] = bta_dg_scb_to_idx(p_scb);
+
+ /* call application init call-out */
+ p_scb->flow_mask = bta_dg_co_init(p_scb->port_handle, p_scb->app_id);
+
+ /* set up port and data callbacks */
+ if ((p_scb->flow_mask & BTA_DG_TX_MASK) == BTA_DG_TX_PUSH)
+ {
+ PORT_SetDataCallback(p_scb->port_handle, bta_dg_data_cback);
+ }
+ PORT_SetEventMask(p_scb->port_handle, BTA_DG_PORT_EV_MASK);
+ PORT_SetEventCallback(p_scb->port_handle, bta_dg_port_cback);
+}
+
+/*******************************************************************************
+**
+** Function bta_dg_setup_server
+**
+** Description This function initializes values of the DG scb and sets up
+** the SDP record for the server.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dg_setup_server(tBTA_DG_SCB *p_scb, tBTA_DG_DATA *p_data)
+{
+ tBTA_DG_LISTEN listen;
+ tBTA_DG_SCB *p_match;
+
+ /* initialize control block */
+ p_scb->service_id = p_data->api_listen.service;
+ p_scb->sec_mask = p_data->api_listen.sec_mask;
+ p_scb->app_id = p_data->api_listen.app_id;
+ p_scb->is_server = TRUE;
+ BCM_STRNCPY_S(p_scb->name, BTA_SERVICE_NAME_LEN+1, p_data->api_listen.name, BTA_SERVICE_NAME_LEN);
+ p_scb->name[BTA_SERVICE_NAME_LEN] = '\0';
+
+ /* if existing matching server */
+ if ((p_match = bta_dg_server_match(p_scb)) != NULL)
+ {
+ /* set SCN same as existing matching server */
+ p_scb->scn = p_match->scn;
+
+ /* copy sdp handle in order to unregister it from any server instance (being last) */
+ p_scb->sdp_handle = p_match->sdp_handle;
+ }
+ else
+ {
+ /* allocate SDP record and SCN */
+ p_scb->sdp_handle = SDP_CreateRecord();
+ p_scb->scn = BTM_AllocateSCN();
+ APPL_TRACE_DEBUG2( "bta_dg_setup_server: x%x, scn:%d", p_scb->sdp_handle, p_scb->scn);
+
+ /* set up sdp record */
+ DUN_AddRecord(bta_dg_uuid[p_scb->service_id - BTA_SPP_SERVICE_ID],
+ p_data->api_listen.name, p_scb->scn, 0, p_scb->sdp_handle);
+
+ bta_sys_add_uuid(bta_dg_uuid[p_scb->service_id - BTA_SPP_SERVICE_ID]);
+ }
+
+ /* Listen on RFCOMM port */
+ bta_dg_listen(p_scb, p_data);
+
+ /* call app callback with listen event */
+ listen.handle = bta_dg_scb_to_idx(p_scb);
+ listen.app_id = p_scb->app_id;
+ (*bta_dg_cb.p_cback)(BTA_DG_LISTEN_EVT, (tBTA_DG *) &listen);
+}
+
+/*******************************************************************************
+**
+** Function bta_dg_listen
+**
+** Description Call DUN_Listen to set up a server.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dg_listen(tBTA_DG_SCB *p_scb, tBTA_DG_DATA *p_data)
+{
+ UINT8 lkup_id = p_scb->service_id - BTA_SPP_SERVICE_ID;
+
+ /* Listen on RFCOMM port */
+ if (DUN_Listen(bta_dg_uuid[lkup_id], p_scb->name, p_scb->scn, p_bta_dg_cfg->mtu[lkup_id],
+ p_scb->sec_mask, &p_scb->port_handle, bta_dg_mgmt_cback)
+ == DUN_SUCCESS)
+ {
+ bta_dg_setup_port(p_scb);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_dg_del_record
+**
+** Description Delete SDP record.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dg_del_record(tBTA_DG_SCB *p_scb, tBTA_DG_DATA *p_data)
+{
+ /* if no existing matching server */
+ if (bta_dg_server_match(p_scb) == NULL)
+ {
+ APPL_TRACE_DEBUG1( "bta_dg_del_record: x%x", p_scb->sdp_handle);
+ if(p_scb->sdp_handle)
+ SDP_DeleteRecord(p_scb->sdp_handle);
+ bta_sys_remove_uuid( bta_dg_uuid[p_scb->service_id - BTA_SPP_SERVICE_ID] );
+ BTM_FreeSCN(p_scb->scn);
+ BTM_SecClrService(bta_dg_sec_id[p_scb->service_id - BTA_SPP_SERVICE_ID]);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_dg_shutdown
+**
+** Description Shut down a server.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dg_shutdown(tBTA_DG_SCB *p_scb, tBTA_DG_DATA *p_data)
+{
+ UINT8 status;
+
+ APPL_TRACE_DEBUG1( "bta_dg_shutdown: x%x", p_scb->sdp_handle);
+
+ status = DUN_Shutdown(p_scb->port_handle);
+
+ APPL_TRACE_DEBUG1("DUN shutdown status %d", status);
+
+ bta_dg_del_record(p_scb, p_data);
+
+ /* set shutdown flag */
+ p_scb->dealloc = TRUE;
+}
+
+/*******************************************************************************
+**
+** Function bta_dg_close
+**
+** Description Close RFCOMM connection.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dg_close(tBTA_DG_SCB *p_scb, tBTA_DG_DATA *p_data)
+{
+ if (p_scb->port_handle)
+ {
+ DUN_Close(p_scb->port_handle);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_dg_set_dealloc
+**
+** Description Set the dealloc flag.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dg_set_dealloc(tBTA_DG_SCB *p_scb, tBTA_DG_DATA *p_data)
+{
+ p_scb->dealloc = TRUE;
+}
+
+/*******************************************************************************
+**
+** Function bta_dg_rx_path
+**
+** Description Handle data on the RX path (data sent from the phone to
+** BTA).
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dg_rx_path(tBTA_DG_SCB *p_scb, tBTA_DG_DATA *p_data)
+{
+ /* if data path configured for rx pull */
+ if ((p_scb->flow_mask & BTA_DG_RX_MASK) == BTA_DG_RX_PULL)
+ {
+ /* if RFCOMM can accept data */
+ if (p_scb->rfc_enable == TRUE)
+ {
+ /* call application callout function for rx path */
+ bta_dg_co_rx_path(p_scb->port_handle, p_scb->app_id, p_scb->mtu);
+ }
+ }
+ /* else data path configured for rx push */
+ else
+ {
+
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_dg_tx_path
+**
+** Description Handle the TX data path (data sent from BTA to the phone).
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dg_tx_path(tBTA_DG_SCB *p_scb, tBTA_DG_DATA *p_data)
+{
+ BT_HDR *p_buf;
+ UINT16 port_errors;
+ tPORT_STATUS port_status;
+ int status;
+
+ /* if data path configured for tx pull */
+ if ((p_scb->flow_mask & BTA_DG_TX_MASK) == BTA_DG_TX_PULL)
+ {
+ /* call application callout function for tx path */
+ bta_dg_co_tx_path(p_scb->port_handle, p_scb->app_id);
+ }
+ /* if configured for zero copy push */
+ else if ((p_scb->flow_mask & BTA_DG_TX_MASK) == BTA_DG_TX_PUSH_BUF)
+ {
+ /* if app can accept data */
+ while (p_scb->app_enable == TRUE)
+ {
+ /* read data from RFCOMM */
+ if ((status = PORT_Read(p_scb->port_handle, &p_buf)) == PORT_SUCCESS)
+ {
+ if(p_buf == NULL)
+ {
+ return;
+ }
+ /* send data to application */
+ bta_dg_co_tx_writebuf(p_scb->port_handle, p_scb->app_id, p_buf);
+ }
+ else if (status == PORT_LINE_ERR)
+ {
+ PORT_ClearError(p_scb->port_handle, &port_errors, &port_status);
+ return;
+ }
+ else
+ {
+ return;
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_dg_fc_state
+**
+** Description Set the application flow control state.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dg_fc_state(tBTA_DG_SCB *p_scb, tBTA_DG_DATA *p_data)
+{
+ p_scb->app_enable = p_data->ci_tx_flow.enable;
+ PORT_FlowControl(p_scb->port_handle, p_scb->app_enable);
+}
+
+/*******************************************************************************
+**
+** Function bta_dg_writebuf
+**
+** Description Handle a bta_dg_ci_rx_writebuf() and send data to RFCOMM.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dg_writebuf(tBTA_DG_SCB *p_scb, tBTA_DG_DATA *p_data)
+{
+ if ((p_scb->flow_mask & BTA_DG_RX_MASK) == BTA_DG_RX_PUSH_BUF)
+ {
+ PORT_Write(p_scb->port_handle, (BT_HDR *) p_data);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_dg_control
+**
+** Description Pass RS-232 control signals from phone to RFCOMM.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dg_control(tBTA_DG_SCB *p_scb, tBTA_DG_DATA *p_data)
+{
+ int i;
+
+ for (i = 0; i < 4; i++)
+ {
+ if (p_data->ci_control.signals & 1)
+ {
+ PORT_Control(p_scb->port_handle, bta_dg_sig[(p_data->ci_control.values & 1)][i]);
+ }
+ p_data->ci_control.signals >>= 1;
+ p_data->ci_control.values >>= 1;
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_dg_rfc_control
+**
+** Description Handle a change in RS-232 signals from RFCOMM
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dg_rfc_control(tBTA_DG_SCB *p_scb, tBTA_DG_DATA *p_data)
+{
+ UINT8 signals = 0;
+ UINT8 values = 0;
+ UINT8 port_values = 0;
+
+ PORT_GetModemStatus(p_scb->port_handle, &port_values);
+
+ if (p_data->rfc_port.code & PORT_EV_CTS)
+ {
+ values |= (p_data->rfc_port.code & PORT_EV_CTSS) ? BTA_DG_RTSCTS_ON : BTA_DG_RTSCTS_OFF;
+ signals |= BTA_DG_RTSCTS;
+ }
+ if (p_data->rfc_port.code & PORT_EV_DSR)
+ {
+ values |= (p_data->rfc_port.code & PORT_EV_DSRS) ? BTA_DG_DTRDSR_ON : BTA_DG_DTRDSR_OFF;
+ signals |= BTA_DG_DTRDSR;
+ }
+ if (p_data->rfc_port.code & PORT_EV_RING)
+ {
+ values |= (port_values & PORT_RING_ON);
+ signals |= BTA_DG_RI;
+ }
+
+ bta_dg_co_control(p_scb->port_handle, p_scb->app_id, signals, values);
+}
+
+/*******************************************************************************
+**
+** Function bta_dg_rfc_open
+**
+** Description Handle RFCOMM channel opening.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dg_rfc_open(tBTA_DG_SCB *p_scb, tBTA_DG_DATA *p_data)
+{
+ tPORT_STATUS status;
+ UINT16 lcid;
+ tBTA_DG_OPEN open;
+
+ /* reset flow control state */
+ p_scb->rfc_enable = TRUE;
+ p_scb->app_enable = TRUE;
+
+ /* get mtu of connection */
+ PORT_GetQueueStatus(p_scb->port_handle, &status);
+ p_scb->mtu = status.mtu_size;
+
+ /* call app call-out */
+ bta_dg_co_open(p_scb->port_handle, p_scb->app_id, p_scb->service_id, p_scb->mtu);
+
+ /* get bd addr of peer */
+ PORT_CheckConnection(p_scb->port_handle, open.bd_addr, &lcid);
+
+ /* call app callback with open event */
+ open.handle = bta_dg_scb_to_idx(p_scb);
+ open.service = p_scb->service_id;
+ open.app_id = p_scb->app_id;
+
+ bdcpy(p_scb->peer_addr, open.bd_addr);
+
+ /* inform role manager */
+ bta_sys_conn_open( BTA_ID_DG ,p_scb->app_id, open.bd_addr);
+
+ (*bta_dg_cb.p_cback)(BTA_DG_OPEN_EVT, (tBTA_DG *) &open);
+}
+
+/*******************************************************************************
+**
+** Function bta_dg_rfc_close
+**
+** Description
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dg_rfc_close(tBTA_DG_SCB *p_scb, tBTA_DG_DATA *p_data)
+{
+ tBTA_DG_CLOSE close;
+
+ /* call app call-out */
+ if (p_scb->port_handle != 0)
+ {
+ bta_dg_co_close(p_scb->port_handle, p_scb->app_id);
+ }
+
+ /* call app callback */
+ close.handle = bta_dg_scb_to_idx(p_scb);
+ close.app_id = p_scb->app_id;
+
+ /* inform role manager */
+ bta_sys_conn_close( BTA_ID_DG ,p_scb->app_id, p_scb->peer_addr);
+
+ (*bta_dg_cb.p_cback)(BTA_DG_CLOSE_EVT, (tBTA_DG *) &close);
+
+ /* if not shutting down, initialize the server */
+ if (p_scb->dealloc == FALSE)
+ {
+ bta_dg_setup_port(p_scb);
+ }
+ /* else dealloc control block */
+ else
+ {
+ bta_dg_scb_dealloc(p_scb);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_dg_dealloc
+**
+** Description
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dg_dealloc(tBTA_DG_SCB *p_scb, tBTA_DG_DATA *p_data)
+{
+ APPL_TRACE_DEBUG1( "bta_dg_dealloc: x%x", p_scb->sdp_handle);
+ bta_dg_scb_dealloc(p_scb);
+}
+/*******************************************************************************
+**
+** Function bta_dg_disc_result
+**
+** Description Process a discovery result.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dg_disc_result(tBTA_DG_SCB *p_scb, tBTA_DG_DATA *p_data)
+{
+ tSDP_DISC_REC *p_rec = NULL;
+ tSDP_DISC_ATTR *p_attr;
+ tSDP_PROTOCOL_ELEM pe;
+ UINT16 name_len;
+ char *p_name;
+ UINT16 evt = BTA_DG_DISC_FAIL_EVT;
+
+
+ if (p_data->disc_result.status == SDP_SUCCESS || p_data->disc_result.status == SDP_DB_FULL)
+ {
+ /* loop through all records we found */
+ while (TRUE)
+ {
+ /* get next record; if none found, we're done */
+ if ((p_rec = SDP_FindServiceInDb(&p_scb->p_disc->db,
+ bta_dg_uuid[p_scb->service_id - BTA_SPP_SERVICE_ID], p_rec)) == NULL)
+ {
+ break;
+ }
+
+ /* get scn from proto desc list; if not found, go to next record */
+ if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe))
+ {
+ p_scb->scn = (UINT8) pe.params[0];
+ }
+ else
+ {
+ continue;
+ }
+
+ /* if service name provided for match */
+ if (p_scb->p_disc->name[0] != 0)
+ {
+ /* get service name */
+ if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_NAME)) != NULL)
+ {
+ /* check if name matches */
+ p_name = (char *) p_attr->attr_value.v.array;
+ name_len = SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
+ if (strncmp(p_scb->p_disc->name, p_name, name_len) == 0)
+ {
+ /* name matches; we found it */
+ evt = BTA_DG_DISC_OK_EVT;
+ break;
+ }
+ else
+ {
+ /* name does not match; continue */
+ continue;
+ }
+ }
+ }
+ /* else name match not required; we're done */
+ else
+ {
+ evt = BTA_DG_DISC_OK_EVT;
+ break;
+ }
+ }
+ }
+
+ /* send ourselves event to process disc ok or fail */
+ bta_dg_sm_execute(p_scb, evt, NULL);
+}
+
+/*******************************************************************************
+**
+** Function bta_dg_do_disc
+**
+** Description Do service discovery.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dg_do_disc(tBTA_DG_SCB *p_scb, tBTA_DG_DATA *p_data)
+{
+ tBTA_DG_OPENING opening;
+ tSDP_UUID uuid_list;
+ UINT16 attr_list[] = {ATTR_ID_SERVICE_CLASS_ID_LIST,
+ ATTR_ID_PROTOCOL_DESC_LIST,
+ ATTR_ID_SERVICE_NAME};
+
+ /* allocate buffer for sdp database */
+ if ((p_scb->p_disc = (tBTA_DG_SDP_DB *) GKI_getbuf(BTA_DG_DISC_BUF_SIZE)) != NULL)
+ {
+ /* store parameters */
+ BCM_STRCPY_S(p_scb->p_disc->name, sizeof(p_scb->p_disc->name), p_data->api_open.name);
+ bdcpy(p_scb->peer_addr, p_data->api_open.bd_addr);
+ p_scb->sec_mask = p_data->api_open.sec_mask;
+ p_scb->service_id = p_data->api_open.service;
+ p_scb->app_id = p_data->api_open.app_id;
+
+ /* initialize some scb parameters */
+ p_scb->dealloc = TRUE;
+ p_scb->port_handle = 0;
+
+
+ bta_sys_app_open(BTA_ID_DG, p_scb->app_id, p_scb->peer_addr);
+
+ /* set up service discovery database */
+ uuid_list.len = LEN_UUID_16;
+ uuid_list.uu.uuid16 = bta_dg_uuid[p_scb->service_id - BTA_SPP_SERVICE_ID];
+
+ /* coverity[OVERRUN_STATIC] False-positive: All pointers are ok. len parameter size (in bytes) of the memory must be larger than sizeof(tSDP_DISCOVERY_DB) */
+ SDP_InitDiscoveryDb(&p_scb->p_disc->db, BTA_DG_SDP_DB_SIZE, 1, &uuid_list, 3, attr_list);
+
+ /* initiate service discovery */
+ if (SDP_ServiceSearchAttributeRequest(p_scb->peer_addr, &p_scb->p_disc->db,
+ bta_dg_sdp_cback_tbl[bta_dg_scb_to_idx(p_scb) - 1]))
+ {
+ /* call callback with opening event */
+ opening.handle = bta_dg_scb_to_idx(p_scb);
+ opening.app_id = p_scb->app_id;
+ (*bta_dg_cb.p_cback)(BTA_DG_OPENING_EVT, (tBTA_DG *) &opening);
+ }
+ else
+ {
+ bta_dg_sdp_cback(SDP_NO_RESOURCES, bta_dg_scb_to_idx(p_scb));
+ }
+ }
+ else
+ {
+ APPL_TRACE_ERROR0("DG DISC: No Resources!");
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function bta_dg_open
+**
+** Description Open a client connection.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dg_open(tBTA_DG_SCB *p_scb, tBTA_DG_DATA *p_data)
+{
+ UINT8 lkup_id = p_scb->service_id - BTA_SPP_SERVICE_ID;
+
+ if (DUN_Connect(bta_dg_uuid[lkup_id], p_scb->peer_addr, p_scb->scn, p_bta_dg_cfg->mtu[lkup_id],
+ p_scb->sec_mask, &p_scb->port_handle, bta_dg_mgmt_cback) == DUN_SUCCESS)
+ {
+ bta_dg_setup_port(p_scb);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_dg_free_db
+**
+** Description Free discovery database.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dg_free_db(tBTA_DG_SCB *p_scb, tBTA_DG_DATA *p_data)
+{
+ if (p_scb->p_disc != NULL)
+ {
+ GKI_freebuf(p_scb->p_disc);
+ p_scb->p_disc = NULL;
+ }
+}
+
+#endif /* BTA_DG_INCLUDED */
diff --git a/bta/dg/bta_dg_api.c b/bta/dg/bta_dg_api.c
new file mode 100644
index 0000000..ab4b737
--- /dev/null
+++ b/bta/dg/bta_dg_api.c
@@ -0,0 +1,218 @@
+/*****************************************************************************
+**
+** Name: bta_dg_api.c
+**
+** Description: This is the implementation of the API for the data gateway
+** (DG) subsystem of BTA, Widcomm's Bluetooth application
+** layer for mobile phones.
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+
+#if defined(BTA_DG_INCLUDED) && (BTA_DG_INCLUDED == TRUE)
+
+#include <string.h>
+#include "bta_api.h"
+#include "bta_sys.h"
+#include "bta_dg_api.h"
+#include "bta_dg_int.h"
+#include "gki.h"
+#include "bd.h"
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+static const tBTA_SYS_REG bta_dg_reg =
+{
+ bta_dg_hdl_event,
+ BTA_DgDisable
+};
+
+/*******************************************************************************
+**
+** Function BTA_DgEnable
+**
+** Description Enable the data gateway service. This function must be
+** called before any other functions in the DG API are called.
+** When the enable operation is complete the callback function
+** will be called with a BTA_DG_ENABLE_EVT. After the DG
+** service is enabled a server can be started by calling
+** BTA_DgListen().
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_DgEnable(tBTA_DG_CBACK *p_cback)
+{
+ tBTA_DG_API_ENABLE *p_buf;
+
+ /* register with BTA system manager */
+ GKI_sched_lock();
+ bta_sys_register(BTA_ID_DG, &bta_dg_reg);
+ GKI_sched_unlock();
+
+ APPL_TRACE_API0( "BTA_DgEnable");
+ if ((p_buf = (tBTA_DG_API_ENABLE *) GKI_getbuf(sizeof(tBTA_DG_API_ENABLE))) != NULL)
+ {
+ p_buf->hdr.event = BTA_DG_API_ENABLE_EVT;
+ p_buf->p_cback = p_cback;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_DgDisable
+**
+** Description Disable the data gateway service. Before calling this
+** function all DG servers must be shut down by calling
+** BTA_DgShutdown().
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_DgDisable(void)
+{
+ BT_HDR *p_buf;
+
+ APPL_TRACE_API0( "BTA_DgDisable");
+ bta_sys_deregister(BTA_ID_DG);
+ if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->event = BTA_DG_API_DISABLE_EVT;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_DgListen
+**
+** Description Create a DG server for DUN, FAX or SPP. After creating a
+** server peer devices can open an RFCOMM connection to the
+** server. When the listen operation has started the callback
+** function will be called with a BTA_DG_LISTEN_EVT providing
+** the handle associated with this server. The handle
+** identifies server when calling other DG functions such as
+** BTA_DgClose() or BTA_DgShutdown().
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_DgListen(tBTA_SERVICE_ID service, tBTA_SEC sec_mask,
+ char *p_service_name, UINT8 app_id)
+{
+ tBTA_DG_API_LISTEN *p_buf;
+
+ APPL_TRACE_API1( "BTA_DgListen %d", service);
+ if ((p_buf = (tBTA_DG_API_LISTEN *) GKI_getbuf(sizeof(tBTA_DG_API_LISTEN))) != NULL)
+ {
+ p_buf->hdr.event = BTA_DG_API_LISTEN_EVT;
+ BCM_STRNCPY_S(p_buf->name, sizeof(p_buf->name), p_service_name, BTA_SERVICE_NAME_LEN);
+ p_buf->sec_mask = sec_mask;
+ p_buf->service = service;
+ p_buf->app_id = app_id;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+/*******************************************************************************
+**
+** Function BTA_DgOpen
+**
+** Description Open a DG client connection to a peer device. BTA first
+** searches for the requested service on the peer device. If
+** the service name is specified it will also match the
+** service name. Then BTA initiates an RFCOMM connection to
+** the peer device. The handle associated with the connection
+** is returned with the BTA_DG_OPEN_EVT. If the connection
+** fails or closes at any time the callback function will be
+** called with a BTA_DG_CLOSE_EVT.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_DgOpen(BD_ADDR bd_addr, tBTA_SERVICE_ID service, tBTA_SEC sec_mask,
+ char *p_service_name, UINT8 app_id)
+{
+ tBTA_DG_API_OPEN *p_buf;
+
+ APPL_TRACE_API0( "BTA_DgOpen");
+ if ((p_buf = (tBTA_DG_API_OPEN *) GKI_getbuf(sizeof(tBTA_DG_API_OPEN))) != NULL)
+ {
+ p_buf->hdr.event = BTA_DG_API_OPEN_EVT;
+ bdcpy(p_buf->bd_addr, bd_addr);
+ if (p_service_name != NULL)
+ {
+ BCM_STRNCPY_S(p_buf->name, sizeof(p_buf->name), p_service_name, BTA_SERVICE_NAME_LEN);
+ }
+ else
+ {
+ p_buf->name[0] = '\0';
+ }
+ p_buf->sec_mask = sec_mask;
+ p_buf->service = service;
+ p_buf->app_id = app_id;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_DgClose
+**
+** Description Close a DG server connection to a peer device. BTA will
+** close the RFCOMM connection to the peer device. The server
+** will still be listening for subsequent connections.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_DgClose(UINT16 handle)
+{
+ BT_HDR *p_buf;
+
+ APPL_TRACE_API0( "BTA_DgClose");
+ if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->event = BTA_DG_API_CLOSE_EVT;
+ p_buf->layer_specific = handle;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_DgShutdown
+**
+** Description Shutdown a DG server previously started by calling
+** BTA_DgListen(). The server will no longer be available
+** to peer devices. If there is currently a connection open
+** to the server it will be closed.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_DgShutdown(UINT16 handle)
+{
+ BT_HDR *p_buf;
+
+ APPL_TRACE_API0( "BTA_DgShutdown");
+ if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->event = BTA_DG_API_SHUTDOWN_EVT;
+ p_buf->layer_specific = handle;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+#endif /* BTA_DG_INCLUDED */
diff --git a/bta/dg/bta_dg_cfg.c b/bta/dg/bta_dg_cfg.c
new file mode 100644
index 0000000..6822c8d
--- /dev/null
+++ b/bta/dg/bta_dg_cfg.c
@@ -0,0 +1,54 @@
+/*****************************************************************************
+**
+** Name: bta_dg_cfg.c
+**
+** Description: This file contains compile-time configurable constants
+** for the BTA data gateway.
+**
+** Copyright (c) 2003, Widcomm Inc., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+
+#if defined(BTA_DG_INCLUDED) && (BTA_DG_INCLUDED == TRUE)
+
+// btla-specific ++
+#include "l2c_api.h"
+#include "rfcdefs.h"
+// btla-specific --
+#include "bta_dg_api.h"
+#include "rfcdefs.h"
+#include "l2c_api.h"
+
+/* RFCOMM MTU for SPP */
+#ifndef BTA_SPP_MTU
+#define BTA_SPP_MTU 330
+#endif
+
+/* RFCOMM MTU for DUN */
+#ifndef BTA_DUN_MTU
+// btla-specific ++
+#define BTA_DUN_MTU (330*3)
+// btla-specific --
+#endif
+
+/* RFCOMM MTU for FAX */
+#ifndef BTA_FAX_MTU
+#define BTA_FAX_MTU 112
+#endif
+
+/* RFCOMM MTU for LAP */
+#ifndef BTA_LAP_MTU
+#define BTA_LAP_MTU 330
+#endif
+
+const tBTA_DG_CFG bta_dg_cfg =
+{
+ {BTA_SPP_MTU, BTA_DUN_MTU, BTA_FAX_MTU, BTA_LAP_MTU},
+
+};
+
+tBTA_DG_CFG *p_bta_dg_cfg = (tBTA_DG_CFG *)&bta_dg_cfg;
+#endif /* BTA_DG_INCLUDED */
diff --git a/bta/dg/bta_dg_ci.c b/bta/dg/bta_dg_ci.c
new file mode 100644
index 0000000..258eafe
--- /dev/null
+++ b/bta/dg/bta_dg_ci.c
@@ -0,0 +1,159 @@
+/*****************************************************************************
+**
+** Name: bta_dg_ci.c
+**
+** Description: This is the implementation file for data gateway call-in
+** functions.
+**
+** Copyright (c) 2003, Widcomm Inc., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bta_api.h"
+#include "bta_dg_api.h"
+#include "bta_dg_ci.h"
+#include "bta_dg_int.h"
+#include "gki.h"
+
+/*******************************************************************************
+**
+** Function bta_dg_ci_tx_ready
+**
+** Description This function sends an event to DG indicating the phone is
+** ready for more data and DG should call bta_dg_co_tx_path().
+** This function is used when the TX data path is configured
+** to use a pull interface.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dg_ci_tx_ready(UINT16 handle)
+{
+ BT_HDR *p_buf;
+
+ if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->event = BTA_DG_CI_TX_READY_EVT;
+ p_buf->layer_specific = handle;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_dg_ci_rx_ready
+**
+** Description This function sends an event to DG indicating the phone
+** has data available to send to DG and DG should call
+** bta_dg_co_rx_path(). This function is used when the RX
+** data path is configured to use a pull interface.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dg_ci_rx_ready(UINT16 handle)
+{
+ BT_HDR *p_buf;
+
+ if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->event = BTA_DG_CI_RX_READY_EVT;
+ p_buf->layer_specific = handle;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_dg_ci_tx_flow
+**
+** Description This function is called to enable or disable data flow on
+** the TX path. The phone should call this function to
+** disable data flow when it is congested and cannot handle
+** any more data sent by bta_dg_co_tx_write() or
+** bta_dg_co_tx_writebuf(). This function is used when the
+** TX data path is configured to use a push interface.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dg_ci_tx_flow(UINT16 handle, BOOLEAN enable)
+{
+ tBTA_DG_CI_TX_FLOW *p_buf;
+
+ if ((p_buf = (tBTA_DG_CI_TX_FLOW *) GKI_getbuf(sizeof(tBTA_DG_CI_TX_FLOW))) != NULL)
+ {
+ p_buf->hdr.event = BTA_DG_CI_TX_FLOW_EVT;
+ p_buf->hdr.layer_specific = handle;
+ p_buf->enable = enable;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_dg_ci_rx_write
+**
+** Description This function is called to send data to DG when the RX path
+** is configured to use a push interface. The function copies
+** data to an event buffer and sends it to DG.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dg_ci_rx_write(UINT16 handle, UINT8 *p_data, UINT16 len)
+{
+
+}
+
+/*******************************************************************************
+**
+** Function bta_dg_ci_rx_writebuf
+**
+** Description This function is called to send data to the phone when
+** the RX path is configured to use a push interface with
+** zero copy. The function sends an event to DG containing
+** the data buffer. The buffer must be allocated using
+** functions GKI_getbuf() or GKI_getpoolbuf(). The buffer
+** will be freed by BTA; the phone must not free the buffer.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dg_ci_rx_writebuf(UINT16 handle, BT_HDR *p_buf)
+{
+ p_buf->event = BTA_DG_CI_RX_WRITEBUF_EVT;
+ p_buf->layer_specific = handle;
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+**
+** Function bta_dg_ci_control
+**
+** Description This function is called to send RS-232 signal information
+** to DG to be propagated over RFCOMM.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dg_ci_control(UINT16 handle, UINT8 signals, UINT8 values)
+{
+ tBTA_DG_CI_CONTROL *p_buf;
+
+ if ((p_buf = (tBTA_DG_CI_CONTROL *) GKI_getbuf(sizeof(tBTA_DG_CI_CONTROL))) != NULL)
+ {
+ p_buf->hdr.event = BTA_DG_CI_CONTROL_EVT;
+ p_buf->hdr.layer_specific = handle;
+ p_buf->signals = signals;
+ p_buf->values = values;
+ bta_sys_sendmsg(p_buf);
+ }
+}
diff --git a/bta/dg/bta_dg_int.h b/bta/dg/bta_dg_int.h
new file mode 100644
index 0000000..0f652e4
--- /dev/null
+++ b/bta/dg/bta_dg_int.h
@@ -0,0 +1,220 @@
+/*****************************************************************************
+**
+** Name: bta_dg_int.h
+**
+** Description: This is the private interface file for the BTA data
+** gateway.
+**
+** Copyright (c) 2003-2009, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_DG_INT_H
+#define BTA_DG_INT_H
+
+#include "bta_sys.h"
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+
+/* DG events */
+enum
+{
+ /* these events are handled by the state machine */
+ BTA_DG_API_CLOSE_EVT = BTA_SYS_EVT_START(BTA_ID_DG),
+ BTA_DG_API_SHUTDOWN_EVT,
+ BTA_DG_API_LISTEN_EVT,
+ BTA_DG_API_OPEN_EVT,
+ BTA_DG_CI_TX_READY_EVT,
+ BTA_DG_CI_RX_READY_EVT,
+ BTA_DG_CI_TX_FLOW_EVT,
+ BTA_DG_CI_RX_WRITEBUF_EVT,
+ BTA_DG_CI_CONTROL_EVT,
+ BTA_DG_RFC_OPEN_EVT,
+ BTA_DG_RFC_CLOSE_EVT,
+ BTA_DG_RFC_TX_READY_EVT,
+ BTA_DG_RFC_RX_READY_EVT,
+ BTA_DG_RFC_FC_EVT,
+ BTA_DG_RFC_CONTROL_EVT,
+ BTA_DG_DISC_RESULT_EVT,
+ BTA_DG_DISC_OK_EVT,
+ BTA_DG_DISC_FAIL_EVT,
+
+ /* these events are handled outside of the state machine */
+ BTA_DG_API_DISABLE_EVT,
+ BTA_DG_API_ENABLE_EVT,
+ BTA_DG_RFC_PORT_EVT
+};
+
+/*****************************************************************************
+** Data types
+*****************************************************************************/
+
+/* data type for BTA_DG_API_ENABLE_EVT */
+typedef struct
+{
+ BT_HDR hdr; /* Event header */
+ tBTA_DG_CBACK *p_cback; /* DG callback function */
+} tBTA_DG_API_ENABLE;
+
+/* data type for BTA_DG_API_LISTEN_EVT */
+typedef struct
+{
+ BT_HDR hdr; /* Event header */
+ char name[BTA_SERVICE_NAME_LEN+1]; /* Service name */
+ tBTA_SEC sec_mask; /* Security mask */
+ tBTA_SERVICE_ID service; /* Service ID */
+ UINT8 app_id; /* Application ID */
+} tBTA_DG_API_LISTEN;
+
+/* data type for BTA_DG_API_OPEN_EVT */
+typedef struct
+{
+ BT_HDR hdr; /* Event header */
+ char name[BTA_SERVICE_NAME_LEN+1]; /* Service name */
+ BD_ADDR bd_addr; /* Peer address */
+ tBTA_SEC sec_mask; /* Security mask */
+ tBTA_SERVICE_ID service; /* Service ID */
+ UINT8 app_id; /* Application ID */
+} tBTA_DG_API_OPEN;
+
+/* data type for BTA_DG_CI_TX_FLOW_EVT */
+typedef struct
+{
+ BT_HDR hdr; /* Event header */
+ BOOLEAN enable; /* Flow control setting */
+} tBTA_DG_CI_TX_FLOW;
+
+/* data type for BTA_DG_CI_CONTROL_EVT */
+typedef struct
+{
+ BT_HDR hdr; /* Event header */
+ UINT8 signals; /* RS-232 signals */
+ UINT8 values; /* RS-232 signal values */
+} tBTA_DG_CI_CONTROL;
+
+/* data type for BTA_DG_RFC_FC_EVT */
+typedef struct
+{
+ BT_HDR hdr; /* Event header */
+ BOOLEAN enable; /* TRUE if data flow enabled */
+} tBTA_DG_RFC_FC;
+
+/* data type for BTA_DG_RFC_PORT_EVT */
+typedef struct
+{
+ BT_HDR hdr; /* Event header */
+ UINT32 code; /* RFCOMM port callback event code mask */
+} tBTA_DG_RFC_PORT;
+
+/* data type for BTA_DG_DISC_RESULT_EVT */
+typedef struct
+{
+ BT_HDR hdr; /* Event header */
+ UINT16 status; /* SDP status */
+} tBTA_DG_DISC_RESULT;
+
+/* union of all data types */
+typedef union
+{
+ BT_HDR hdr;
+ tBTA_DG_API_ENABLE api_enable;
+ tBTA_DG_API_LISTEN api_listen;
+ tBTA_DG_API_OPEN api_open;
+ tBTA_DG_CI_TX_FLOW ci_tx_flow;
+ tBTA_DG_CI_CONTROL ci_control;
+ tBTA_DG_RFC_FC rfc_fc;
+ tBTA_DG_RFC_PORT rfc_port;
+ tBTA_DG_DISC_RESULT disc_result;
+} tBTA_DG_DATA;
+
+/* type used to store temporary sdp data */
+typedef struct
+{
+ char name[BTA_SERVICE_NAME_LEN+1]; /* Service name */
+ tSDP_DISCOVERY_DB db; /* Discovery database */
+} tBTA_DG_SDP_DB;
+
+/* state machine control block */
+typedef struct
+{
+ char name[BTA_SERVICE_NAME_LEN+1]; /* Service name */
+ BD_ADDR peer_addr; /* BD address of peer device */
+ tBTA_DG_SDP_DB *p_disc; /* pointer to sdp discovery db */
+ UINT32 sdp_handle; /* SDP record handle */
+ UINT16 port_handle; /* RFCOMM port handle */
+ UINT16 mtu; /* RFCOMM MTU */
+ tBTA_SERVICE_ID service_id; /* Profile service ID */
+ tBTA_SEC sec_mask; /* Security mask */
+ BOOLEAN rfc_enable; /* RFCOMM flow control state */
+ BOOLEAN app_enable; /* Application flow control state */
+ BOOLEAN in_use; /* TRUE if SCB in use */
+ BOOLEAN dealloc; /* TRUE if service shutting down */
+ BOOLEAN is_server; /* TRUE if scb is for server */
+ UINT8 state; /* State machine state */
+ UINT8 app_id; /* Application ID */
+ UINT8 scn; /* Server channel number */
+ UINT8 flow_mask; /* Data flow mask */
+} tBTA_DG_SCB;
+
+/* main control block */
+typedef struct
+{
+ tBTA_DG_SCB scb[BTA_DG_NUM_CONN]; /* state machine control blocks */
+ UINT8 hdl_to_scb[MAX_RFC_PORTS+1];/* port to state machine lookup table */
+ tBTA_DG_CBACK *p_cback; /* DG callback function */
+} tBTA_DG_CB;
+
+/*****************************************************************************
+** Global data
+*****************************************************************************/
+
+/* DG control block */
+#if BTA_DYNAMIC_MEMORY == FALSE
+extern tBTA_DG_CB bta_dg_cb;
+#else
+extern tBTA_DG_CB *bta_dg_cb_ptr;
+#define bta_dg_cb (*bta_dg_cb_ptr)
+#endif
+
+/* DG configuration constants */
+extern tBTA_DG_CFG * p_bta_dg_cfg;
+
+/*****************************************************************************
+** Function prototypes
+*****************************************************************************/
+
+extern void bta_dg_scb_dealloc(tBTA_DG_SCB *p_scb);
+extern UINT8 bta_dg_scb_to_idx(tBTA_DG_SCB *p_scb);
+extern tBTA_DG_SCB *bta_dg_scb_by_idx(UINT16 idx);
+extern tBTA_DG_SCB *bta_dg_scb_by_handle(UINT16 handle);
+extern tBTA_DG_SCB *bta_dg_server_match(tBTA_DG_SCB *p_srv);
+extern BOOLEAN bta_dg_hdl_event(BT_HDR *p_msg);
+extern void bta_dg_sm_execute(tBTA_DG_SCB *p_scb, UINT16 event, tBTA_DG_DATA *p_data);
+
+/* action functions */
+extern void bta_dg_setup(tBTA_DG_SCB *p_scb, tBTA_DG_DATA *p_data);
+extern void bta_dg_listen(tBTA_DG_SCB *p_scb, tBTA_DG_DATA *p_data);
+extern void bta_dg_del_record(tBTA_DG_SCB *p_scb, tBTA_DG_DATA *p_data);
+extern void bta_dg_shutdown(tBTA_DG_SCB *p_scb, tBTA_DG_DATA *p_data);
+extern void bta_dg_close(tBTA_DG_SCB *p_scb, tBTA_DG_DATA *p_data);
+extern void bta_dg_set_dealloc(tBTA_DG_SCB *p_scb, tBTA_DG_DATA *p_data);
+extern void bta_dg_rx_path(tBTA_DG_SCB *p_scb, tBTA_DG_DATA *p_data);
+extern void bta_dg_tx_path(tBTA_DG_SCB *p_scb, tBTA_DG_DATA *p_data);
+extern void bta_dg_fc_state(tBTA_DG_SCB *p_scb, tBTA_DG_DATA *p_data);
+extern void bta_dg_writebuf(tBTA_DG_SCB *p_scb, tBTA_DG_DATA *p_data);
+extern void bta_dg_control(tBTA_DG_SCB *p_scb, tBTA_DG_DATA *p_data);
+extern void bta_dg_rfc_control(tBTA_DG_SCB *p_scb, tBTA_DG_DATA *p_data);
+extern void bta_dg_rfc_open(tBTA_DG_SCB *p_scb, tBTA_DG_DATA *p_data);
+extern void bta_dg_rfc_close(tBTA_DG_SCB *p_scb, tBTA_DG_DATA *p_data);
+extern void bta_dg_dealloc(tBTA_DG_SCB *p_scb, tBTA_DG_DATA *p_data);
+extern void bta_dg_disc_result(tBTA_DG_SCB *p_scb, tBTA_DG_DATA *p_data);
+extern void bta_dg_do_disc(tBTA_DG_SCB *p_scb, tBTA_DG_DATA *p_data);
+extern void bta_dg_open(tBTA_DG_SCB *p_scb, tBTA_DG_DATA *p_data);
+extern void bta_dg_free_db(tBTA_DG_SCB *p_scb, tBTA_DG_DATA *p_data);
+extern void bta_dg_setup_server(tBTA_DG_SCB *p_scb, tBTA_DG_DATA *p_data);
+
+
+#endif /* BTA_DG_INT_H */
diff --git a/bta/dg/bta_dg_main.c b/bta/dg/bta_dg_main.c
new file mode 100644
index 0000000..63e6db5
--- /dev/null
+++ b/bta/dg/bta_dg_main.c
@@ -0,0 +1,597 @@
+/*****************************************************************************
+**
+** Name: bta_dg_main.c
+**
+** Description: This file contains the data gateway main functions and
+** state machine.
+**
+** Copyright (c) 2003-2006, Broadcom Corp., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+
+#if defined(BTA_DG_INCLUDED) && (BTA_DG_INCLUDED == TRUE)
+
+#include <string.h>
+#include "bta_api.h"
+#include "bta_sys.h"
+#include "bta_dg_api.h"
+#include "bta_dg_int.h"
+#include "port_api.h"
+
+/*****************************************************************************
+** Constants and types
+*****************************************************************************/
+
+/* state machine states */
+enum
+{
+ BTA_DG_INIT_ST,
+ BTA_DG_OPENING_ST,
+ BTA_DG_OPEN_ST,
+ BTA_DG_CLOSING_ST
+};
+
+/* state machine action enumeration list */
+enum
+{
+ BTA_DG_DEL_RECORD,
+ BTA_DG_SHUTDOWN,
+ BTA_DG_CLOSE,
+ BTA_DG_SET_DEALLOC,
+ BTA_DG_RX_PATH,
+ BTA_DG_TX_PATH,
+ BTA_DG_FC_STATE,
+ BTA_DG_WRITEBUF,
+ BTA_DG_CONTROL,
+ BTA_DG_RFC_CONTROL,
+ BTA_DG_RFC_OPEN,
+ BTA_DG_RFC_CLOSE,
+ BTA_DG_DEALLOC,
+ BTA_DG_DISC_RESULT,
+ BTA_DG_DO_DISC,
+ BTA_DG_OPEN,
+ BTA_DG_FREE_DB,
+ BTA_DG_SETUP_SERVER,
+ BTA_DG_IGNORE
+};
+
+/* type for action functions */
+typedef void (*tBTA_DG_ACTION)(tBTA_DG_SCB *p_scb, tBTA_DG_DATA *p_data);
+
+/* action function list */
+const tBTA_DG_ACTION bta_dg_action[] =
+{
+ bta_dg_del_record,
+ bta_dg_shutdown,
+ bta_dg_close,
+ bta_dg_set_dealloc,
+ bta_dg_rx_path,
+ bta_dg_tx_path,
+ bta_dg_fc_state,
+ bta_dg_writebuf,
+ bta_dg_control,
+ bta_dg_rfc_control,
+ bta_dg_rfc_open,
+ bta_dg_rfc_close,
+ bta_dg_dealloc,
+ bta_dg_disc_result,
+ bta_dg_do_disc,
+ bta_dg_open,
+ bta_dg_free_db,
+ bta_dg_setup_server
+};
+
+/* state table information */
+#define BTA_DG_ACTIONS 2 /* number of actions */
+#define BTA_DG_NEXT_STATE 2 /* position of next state */
+#define BTA_DG_NUM_COLS 3 /* number of columns in state tables */
+
+/* state table for init state */
+const UINT8 bta_dg_st_init[][BTA_DG_NUM_COLS] =
+{
+/* Event Action 1 Action 2 Next state */
+/* API_CLOSE_EVT */ {BTA_DG_IGNORE, BTA_DG_IGNORE, BTA_DG_INIT_ST},
+/* API_SHUTDOWN_EVT */ {BTA_DG_SHUTDOWN, BTA_DG_DEALLOC, BTA_DG_INIT_ST},
+/* API_LISTEN_EVT */ {BTA_DG_SETUP_SERVER, BTA_DG_IGNORE, BTA_DG_INIT_ST},
+/* API_OPEN_EVT */ {BTA_DG_DO_DISC, BTA_DG_IGNORE, BTA_DG_OPENING_ST},
+/* CI_TX_READY_EVT */ {BTA_DG_IGNORE, BTA_DG_IGNORE, BTA_DG_INIT_ST},
+/* CI_RX_READY_EVT */ {BTA_DG_IGNORE, BTA_DG_IGNORE, BTA_DG_INIT_ST},
+/* CI_TX_FLOW_EVT */ {BTA_DG_IGNORE, BTA_DG_IGNORE, BTA_DG_INIT_ST},
+/* CI_RX_WRITEBUF_EVT */ {BTA_DG_WRITEBUF, BTA_DG_IGNORE, BTA_DG_INIT_ST},
+/* CI_CONTROL_EVT */ {BTA_DG_IGNORE, BTA_DG_IGNORE, BTA_DG_INIT_ST},
+/* RFC_OPEN_EVT */ {BTA_DG_RFC_OPEN, BTA_DG_IGNORE, BTA_DG_OPEN_ST},
+/* RFC_CLOSE_EVT */ {BTA_DG_IGNORE, BTA_DG_IGNORE, BTA_DG_INIT_ST},
+/* RFC_TX_READY_EVT */ {BTA_DG_IGNORE, BTA_DG_IGNORE, BTA_DG_INIT_ST},
+/* RFC_RX_READY_EVT */ {BTA_DG_IGNORE, BTA_DG_IGNORE, BTA_DG_INIT_ST},
+/* RFC_FC_EVT */ {BTA_DG_IGNORE, BTA_DG_IGNORE, BTA_DG_INIT_ST},
+/* RFC_CONTROL_EVT */ {BTA_DG_RFC_CONTROL, BTA_DG_IGNORE, BTA_DG_INIT_ST},
+/* DISC_RESULT_EVT */ {BTA_DG_IGNORE, BTA_DG_IGNORE, BTA_DG_INIT_ST},
+/* DISC_OK_EVT */ {BTA_DG_IGNORE, BTA_DG_IGNORE, BTA_DG_INIT_ST},
+/* DISC_FAIL_EVT */ {BTA_DG_IGNORE, BTA_DG_IGNORE, BTA_DG_INIT_ST}
+};
+
+/* state table for opening state */
+const UINT8 bta_dg_st_opening[][BTA_DG_NUM_COLS] =
+{
+/* Event Action 1 Action 2 Next state */
+/* API_CLOSE_EVT */ {BTA_DG_CLOSE, BTA_DG_IGNORE, BTA_DG_CLOSING_ST},
+/* API_SHUTDOWN_EVT */ {BTA_DG_IGNORE, BTA_DG_IGNORE, BTA_DG_OPENING_ST},
+/* API_LISTEN_EVT */ {BTA_DG_IGNORE, BTA_DG_IGNORE, BTA_DG_OPENING_ST},
+/* API_OPEN_EVT */ {BTA_DG_IGNORE, BTA_DG_IGNORE, BTA_DG_OPENING_ST},
+/* CI_TX_READY_EVT */ {BTA_DG_IGNORE, BTA_DG_IGNORE, BTA_DG_OPENING_ST},
+/* CI_RX_READY_EVT */ {BTA_DG_IGNORE, BTA_DG_IGNORE, BTA_DG_OPENING_ST},
+/* CI_TX_FLOW_EVT */ {BTA_DG_IGNORE, BTA_DG_IGNORE, BTA_DG_OPENING_ST},
+/* CI_RX_WRITEBUF_EVT */ {BTA_DG_WRITEBUF, BTA_DG_IGNORE, BTA_DG_OPENING_ST},
+/* CI_CONTROL_EVT */ {BTA_DG_IGNORE, BTA_DG_IGNORE, BTA_DG_OPENING_ST},
+/* RFC_OPEN_EVT */ {BTA_DG_RFC_OPEN, BTA_DG_IGNORE, BTA_DG_OPEN_ST},
+/* RFC_CLOSE_EVT */ {BTA_DG_RFC_CLOSE, BTA_DG_IGNORE, BTA_DG_INIT_ST},
+/* RFC_TX_READY_EVT */ {BTA_DG_IGNORE, BTA_DG_IGNORE, BTA_DG_OPENING_ST},
+/* RFC_RX_READY_EVT */ {BTA_DG_IGNORE, BTA_DG_IGNORE, BTA_DG_OPENING_ST},
+/* RFC_FC_EVT */ {BTA_DG_IGNORE, BTA_DG_IGNORE, BTA_DG_OPENING_ST},
+/* RFC_CONTROL_EVT */ {BTA_DG_RFC_CONTROL, BTA_DG_IGNORE, BTA_DG_OPENING_ST},
+/* DISC_RESULT_EVT */ {BTA_DG_DISC_RESULT, BTA_DG_IGNORE, BTA_DG_OPENING_ST},
+/* DISC_OK_EVT */ {BTA_DG_FREE_DB, BTA_DG_OPEN, BTA_DG_OPENING_ST},
+/* DISC_FAIL_EVT */ {BTA_DG_FREE_DB, BTA_DG_RFC_CLOSE, BTA_DG_INIT_ST}
+};
+
+/* state table for open state */
+const UINT8 bta_dg_st_open[][BTA_DG_NUM_COLS] =
+{
+/* Event Action 1 Action 2 Next state */
+/* API_CLOSE_EVT */ {BTA_DG_CLOSE, BTA_DG_IGNORE, BTA_DG_CLOSING_ST},
+/* API_SHUTDOWN_EVT */ {BTA_DG_SHUTDOWN, BTA_DG_IGNORE, BTA_DG_CLOSING_ST},
+/* API_LISTEN_EVT */ {BTA_DG_IGNORE, BTA_DG_IGNORE, BTA_DG_OPEN_ST},
+/* API_OPEN_EVT */ {BTA_DG_IGNORE, BTA_DG_IGNORE, BTA_DG_OPEN_ST},
+/* CI_TX_READY_EVT */ {BTA_DG_TX_PATH, BTA_DG_IGNORE, BTA_DG_OPEN_ST},
+/* CI_RX_READY_EVT */ {BTA_DG_RX_PATH, BTA_DG_IGNORE, BTA_DG_OPEN_ST},
+/* CI_TX_FLOW_EVT */ {BTA_DG_FC_STATE, BTA_DG_TX_PATH, BTA_DG_OPEN_ST},
+/* CI_RX_WRITEBUF_EVT */ {BTA_DG_WRITEBUF, BTA_DG_IGNORE, BTA_DG_OPEN_ST},
+/* CI_CONTROL_EVT */ {BTA_DG_CONTROL, BTA_DG_IGNORE, BTA_DG_OPEN_ST},
+/* RFC_OPEN_EVT */ {BTA_DG_IGNORE, BTA_DG_IGNORE, BTA_DG_OPEN_ST},
+/* RFC_CLOSE_EVT */ {BTA_DG_RFC_CLOSE, BTA_DG_IGNORE, BTA_DG_INIT_ST},
+/* RFC_TX_READY_EVT */ {BTA_DG_RX_PATH, BTA_DG_IGNORE, BTA_DG_OPEN_ST},
+/* RFC_RX_READY_EVT */ {BTA_DG_TX_PATH, BTA_DG_IGNORE, BTA_DG_OPEN_ST},
+/* RFC_FC_EVT */ {BTA_DG_RX_PATH, BTA_DG_IGNORE, BTA_DG_OPEN_ST},
+/* RFC_CONTROL_EVT */ {BTA_DG_RFC_CONTROL, BTA_DG_IGNORE, BTA_DG_OPEN_ST},
+/* DISC_RESULT_EVT */ {BTA_DG_IGNORE, BTA_DG_IGNORE, BTA_DG_OPEN_ST},
+/* DISC_OK_EVT */ {BTA_DG_IGNORE, BTA_DG_IGNORE, BTA_DG_OPEN_ST},
+/* DISC_FAIL_EVT */ {BTA_DG_IGNORE, BTA_DG_IGNORE, BTA_DG_OPEN_ST}
+};
+
+/* state table for closing state */
+const UINT8 bta_dg_st_closing[][BTA_DG_NUM_COLS] =
+{
+/* Event Action 1 Action 2 Next state */
+/* API_CLOSE_EVT */ {BTA_DG_IGNORE, BTA_DG_IGNORE, BTA_DG_CLOSING_ST},
+/* API_SHUTDOWN_EVT */ {BTA_DG_DEL_RECORD, BTA_DG_SET_DEALLOC, BTA_DG_CLOSING_ST},
+/* API_LISTEN_EVT */ {BTA_DG_IGNORE, BTA_DG_IGNORE, BTA_DG_CLOSING_ST},
+/* API_OPEN_EVT */ {BTA_DG_IGNORE, BTA_DG_IGNORE, BTA_DG_CLOSING_ST},
+/* CI_TX_READY_EVT */ {BTA_DG_TX_PATH, BTA_DG_IGNORE, BTA_DG_CLOSING_ST},
+/* CI_RX_READY_EVT */ {BTA_DG_IGNORE, BTA_DG_IGNORE, BTA_DG_CLOSING_ST},
+/* CI_TX_FLOW_EVT */ {BTA_DG_FC_STATE, BTA_DG_TX_PATH, BTA_DG_CLOSING_ST},
+/* CI_RX_WRITEBUF_EVT */ {BTA_DG_WRITEBUF, BTA_DG_IGNORE, BTA_DG_CLOSING_ST},
+/* CI_CONTROL_EVT */ {BTA_DG_CONTROL, BTA_DG_IGNORE, BTA_DG_CLOSING_ST},
+/* RFC_OPEN_EVT */ {BTA_DG_CLOSE, BTA_DG_IGNORE, BTA_DG_CLOSING_ST},
+/* RFC_CLOSE_EVT */ {BTA_DG_RFC_CLOSE, BTA_DG_IGNORE, BTA_DG_INIT_ST},
+/* RFC_TX_READY_EVT */ {BTA_DG_RX_PATH, BTA_DG_IGNORE, BTA_DG_CLOSING_ST},
+/* RFC_RX_READY_EVT */ {BTA_DG_TX_PATH, BTA_DG_IGNORE, BTA_DG_CLOSING_ST},
+/* RFC_FC_EVT */ {BTA_DG_RX_PATH, BTA_DG_IGNORE, BTA_DG_CLOSING_ST},
+/* RFC_CONTROL_EVT */ {BTA_DG_RFC_CONTROL, BTA_DG_IGNORE, BTA_DG_CLOSING_ST},
+/* DISC_RESULT_EVT */ {BTA_DG_FREE_DB, BTA_DG_RFC_CLOSE, BTA_DG_INIT_ST},
+/* DISC_OK_EVT */ {BTA_DG_IGNORE, BTA_DG_IGNORE, BTA_DG_CLOSING_ST},
+/* DISC_FAIL_EVT */ {BTA_DG_IGNORE, BTA_DG_IGNORE, BTA_DG_CLOSING_ST}
+};
+
+/* type for state table */
+typedef const UINT8 (*tBTA_DG_ST_TBL)[BTA_DG_NUM_COLS];
+
+/* state table */
+const tBTA_DG_ST_TBL bta_dg_st_tbl[] = {
+ bta_dg_st_init,
+ bta_dg_st_opening,
+ bta_dg_st_open,
+ bta_dg_st_closing
+};
+
+/*****************************************************************************
+** Global data
+*****************************************************************************/
+
+/* DG control block */
+#if BTA_DYNAMIC_MEMORY == FALSE
+tBTA_DG_CB bta_dg_cb;
+#endif
+
+/*******************************************************************************
+**
+** Function bta_dg_scb_alloc
+**
+** Description Allocate a DG server control block.
+**
+**
+** Returns pointer to the scb, or NULL if none could be allocated.
+**
+*******************************************************************************/
+static tBTA_DG_SCB *bta_dg_scb_alloc(void)
+{
+ tBTA_DG_SCB *p_scb = &bta_dg_cb.scb[0];
+ int i;
+
+ for (i = 0; i < BTA_DG_NUM_CONN; i++, p_scb++)
+ {
+ if (!p_scb->in_use)
+ {
+ p_scb->in_use = TRUE;
+ APPL_TRACE_DEBUG1("bta_dg_scb_alloc %d", bta_dg_scb_to_idx(p_scb));
+ break;
+ }
+ }
+
+ if (i == BTA_DG_NUM_CONN)
+ {
+ /* out of lcbs */
+ p_scb = NULL;
+ APPL_TRACE_WARNING0("Out of scbs");
+ }
+ return p_scb;
+}
+
+/*******************************************************************************
+**
+** Function bta_dg_sm_execute
+**
+** Description State machine event handling function for DG
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dg_sm_execute(tBTA_DG_SCB *p_scb, UINT16 event, tBTA_DG_DATA *p_data)
+{
+ tBTA_DG_ST_TBL state_table;
+ UINT8 action;
+ int i;
+
+ switch( event )
+ {
+ case BTA_DG_CI_TX_READY_EVT:
+ case BTA_DG_CI_RX_READY_EVT:
+ case BTA_DG_RFC_TX_READY_EVT:
+ case BTA_DG_RFC_RX_READY_EVT:
+ break;
+ default:
+ APPL_TRACE_EVENT3("DG scb=%d event=0x%x state=%d", bta_dg_scb_to_idx(p_scb), event, p_scb->state);
+ break;
+ }
+
+ /* look up the state table for the current state */
+ state_table = bta_dg_st_tbl[p_scb->state];
+
+ event &= 0x00FF;
+
+ /* set next state */
+ p_scb->state = state_table[event][BTA_DG_NEXT_STATE];
+
+ /* execute action functions */
+ for (i = 0; i < BTA_DG_ACTIONS; i++)
+ {
+ if ((action = state_table[event][i]) != BTA_DG_IGNORE)
+ {
+ (*bta_dg_action[action])(p_scb, p_data);
+ }
+ else
+ {
+ break;
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_dg_api_enable
+**
+** Description Handle an API enable event.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_dg_api_enable(tBTA_DG_DATA *p_data)
+{
+ /* initialize control block */
+ memset(&bta_dg_cb, 0, sizeof(bta_dg_cb));
+
+ /* store callback function */
+ bta_dg_cb.p_cback = p_data->api_enable.p_cback;
+
+ /* call callback with enable event */
+ (*bta_dg_cb.p_cback)(BTA_DG_ENABLE_EVT, NULL);
+}
+
+/*******************************************************************************
+**
+** Function bta_dg_api_disable
+**
+** Description Handle an API disable event.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_dg_api_disable(tBTA_DG_DATA *p_data)
+{
+ /* close/shutdown all scbs in use */
+ tBTA_DG_SCB *p_scb = &bta_dg_cb.scb[0];
+ int i;
+ UINT16 event;
+
+ for (i = 0; i < BTA_DG_NUM_CONN; i++, p_scb++)
+ {
+ if (p_scb->in_use)
+ {
+ event = (p_scb->is_server) ? BTA_DG_API_SHUTDOWN_EVT : BTA_DG_API_CLOSE_EVT;
+ bta_dg_sm_execute(p_scb, event, p_data);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_dg_new_conn
+**
+** Description Handle an API event that creates a new connection.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_dg_new_conn(tBTA_DG_DATA *p_data)
+{
+ tBTA_DG_SCB *p_scb;
+
+ /* allocate an scb */
+ if ((p_scb = bta_dg_scb_alloc()) != NULL)
+ {
+ bta_dg_sm_execute(p_scb, p_data->hdr.event, p_data);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_dg_rfc_port
+**
+** Description Handle a port event from RFCOMM. This function decodes
+** the port event mask into multiple state machine events.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_dg_rfc_port(tBTA_DG_DATA *p_data)
+{
+ tBTA_DG_SCB *p_scb;
+
+ if ((p_scb = bta_dg_scb_by_handle(p_data->hdr.layer_specific)) != NULL)
+ {
+ if (p_data->rfc_port.code & PORT_EV_FC)
+ {
+ bta_dg_sm_execute(p_scb, BTA_DG_RFC_FC_EVT, p_data);
+ }
+
+ if (p_data->rfc_port.code & PORT_EV_TXEMPTY)
+ {
+ bta_dg_sm_execute(p_scb, BTA_DG_RFC_TX_READY_EVT, p_data);
+ }
+
+ if (p_data->rfc_port.code & PORT_EV_RXCHAR)
+ {
+ bta_dg_sm_execute(p_scb, BTA_DG_RFC_RX_READY_EVT, p_data);
+ }
+
+ if (p_data->rfc_port.code & (PORT_EV_CTS | PORT_EV_DSR | PORT_EV_RING))
+ {
+ bta_dg_sm_execute(p_scb, BTA_DG_RFC_CONTROL_EVT, p_data);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_dg_scb_dealloc
+**
+** Description Deallocate a link control block.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dg_scb_dealloc(tBTA_DG_SCB *p_scb)
+{
+ APPL_TRACE_DEBUG1("bta_dg_scb_dealloc %d", bta_dg_scb_to_idx(p_scb));
+ if (p_scb->port_handle != 0)
+ {
+ bta_dg_cb.hdl_to_scb[p_scb->port_handle - 1] = 0;
+ }
+ memset(p_scb, 0, sizeof(tBTA_DG_SCB));
+}
+
+/*******************************************************************************
+**
+** Function bta_dg_scb_to_idx
+**
+** Description Given a pointer to an scb, return its index.
+**
+**
+** Returns Index of scb.
+**
+*******************************************************************************/
+UINT8 bta_dg_scb_to_idx(tBTA_DG_SCB *p_scb)
+{
+ /* use array arithmetic to determine index */
+ return ((UINT8) (p_scb - bta_dg_cb.scb)) + 1;
+}
+
+/*******************************************************************************
+**
+** Function bta_dg_scb_by_idx
+**
+** Description Given an scb index return pointer to scb.
+**
+**
+** Returns Pointer to scb or NULL if not allocated.
+**
+*******************************************************************************/
+tBTA_DG_SCB *bta_dg_scb_by_idx(UINT16 idx)
+{
+ tBTA_DG_SCB *p_scb;
+
+ /* verify index */
+ if (idx > 0 && idx <= BTA_DG_NUM_CONN)
+ {
+ p_scb = &bta_dg_cb.scb[idx - 1];
+ if (!p_scb->in_use)
+ {
+ p_scb = NULL;
+ APPL_TRACE_WARNING1("scb idx %d not allocated", idx);
+ }
+ }
+ else
+ {
+ p_scb = NULL;
+ APPL_TRACE_WARNING1("scb idx %d out of range", idx);
+ }
+ return p_scb;
+}
+
+/*******************************************************************************
+**
+** Function bta_dg_scb_by_handle
+**
+** Description Find scb associated with handle.
+**
+**
+** Returns Pointer to scb or NULL if not found.
+**
+*******************************************************************************/
+tBTA_DG_SCB *bta_dg_scb_by_handle(UINT16 handle)
+{
+ tBTA_DG_SCB *p_scb = NULL;
+
+ if (bta_dg_cb.hdl_to_scb[handle - 1] != 0)
+ {
+ p_scb = &bta_dg_cb.scb[bta_dg_cb.hdl_to_scb[handle - 1] - 1];
+ if (!p_scb->in_use)
+ {
+ p_scb = NULL;
+ }
+ }
+
+ if (p_scb == NULL)
+ {
+ APPL_TRACE_WARNING1("No scb for port handle %d", handle);
+ }
+
+ return p_scb;
+}
+
+/*******************************************************************************
+**
+** Function bta_dg_server_match
+**
+** Description Check if any servers exist with the same service name
+** and service id.
+**
+**
+** Returns Pointer to scb or NULL if not found.
+**
+*******************************************************************************/
+tBTA_DG_SCB *bta_dg_server_match(tBTA_DG_SCB *p_srv)
+{
+ tBTA_DG_SCB *p_scb = &bta_dg_cb.scb[0];
+ int i;
+
+ for (i = 0; i < BTA_DG_NUM_CONN; i++, p_scb++)
+ {
+ if (p_scb == p_srv)
+ {
+ continue;
+ }
+
+ if (p_scb->in_use && p_scb->is_server &&
+ (p_scb->service_id == p_srv->service_id) &&
+ (strcmp(p_srv->name, p_scb->name) == 0))
+ {
+ APPL_TRACE_DEBUG1("dg server match:%d", i);
+ return p_scb;
+ }
+ }
+ return NULL;
+}
+
+/*******************************************************************************
+**
+** Function bta_dg_hdl_event
+**
+** Description Data gateway main event handling function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BOOLEAN bta_dg_hdl_event(BT_HDR *p_msg)
+{
+ tBTA_DG_SCB *p_scb;
+ BOOLEAN freebuf = TRUE;
+
+ switch (p_msg->event)
+ {
+ /* handle enable event */
+ case BTA_DG_API_ENABLE_EVT:
+ bta_dg_api_enable((tBTA_DG_DATA *) p_msg);
+ break;
+
+ /* handle disable event */
+ case BTA_DG_API_DISABLE_EVT:
+ bta_dg_api_disable((tBTA_DG_DATA *) p_msg);
+ break;
+
+ /* handle listen and open events */
+ case BTA_DG_API_LISTEN_EVT:
+ case BTA_DG_API_OPEN_EVT:
+ bta_dg_new_conn((tBTA_DG_DATA *) p_msg);
+ break;
+
+ /* handle RFCOMM port callback event mask */
+ case BTA_DG_RFC_PORT_EVT:
+ bta_dg_rfc_port((tBTA_DG_DATA *) p_msg);
+ break;
+
+ /* events that reference scb by index rather than port handle */
+ case BTA_DG_API_CLOSE_EVT:
+ case BTA_DG_API_SHUTDOWN_EVT:
+ case BTA_DG_DISC_RESULT_EVT:
+ if ((p_scb = bta_dg_scb_by_idx(p_msg->layer_specific)) != NULL)
+ {
+ bta_dg_sm_execute(p_scb, p_msg->event, (tBTA_DG_DATA *) p_msg);
+ }
+ break;
+
+ /* events that require buffer not be released */
+ case BTA_DG_CI_RX_WRITEBUF_EVT:
+ freebuf = FALSE;
+ /* fall through */
+
+ /* all others reference scb by port handle */
+ default:
+ if ((p_scb = bta_dg_scb_by_handle(p_msg->layer_specific)) != NULL)
+ {
+ bta_dg_sm_execute(p_scb, p_msg->event, (tBTA_DG_DATA *) p_msg);
+ }
+ break;
+ }
+ return freebuf;
+}
+#endif /* BTA_DG_INCLUDED */
diff --git a/bta/dm/bta_dm_act.c b/bta/dm/bta_dm_act.c
new file mode 100644
index 0000000..e21dc3e
--- /dev/null
+++ b/bta/dm/bta_dm_act.c
@@ -0,0 +1,4678 @@
+/*****************************************************************************
+**
+** Name: bta_dm_act.c
+**
+** Description: This file contains the action functions for device manager
+** state machine.
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_types.h"
+#include "gki.h"
+#include "bd.h"
+#include "bta_sys.h"
+#include "bta_api.h"
+#include "bta_dm_int.h"
+#include "bta_dm_co.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "sdp_api.h"
+#include "l2c_api.h"
+#include "wbt_api.h"
+#include "utl.h"
+#include <string.h>
+
+static void bta_dm_inq_results_cb (tBTM_INQ_RESULTS *p_inq, UINT8 *p_eir);
+static void bta_dm_inq_cmpl_cb (void * p_result);
+static void bta_dm_service_search_remname_cback (BD_ADDR bd_addr, DEV_CLASS dc, BD_NAME bd_name);
+static void bta_dm_remname_cback (tBTM_REMOTE_DEV_NAME *p_remote_name);
+static void bta_dm_find_services ( BD_ADDR bd_addr);
+static void bta_dm_discover_next_device(void);
+static void bta_dm_sdp_callback (UINT16 sdp_status);
+static UINT8 bta_dm_authorize_cback (BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NAME bd_name, UINT8 *service_name, UINT8 service_id, BOOLEAN is_originator);
+static UINT8 bta_dm_pin_cback (BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NAME bd_name);
+static UINT8 bta_dm_link_key_request_cback (BD_ADDR bd_addr, LINK_KEY key);
+static UINT8 bta_dm_new_link_key_cback(BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NAME bd_name, LINK_KEY key, UINT8 key_type);
+static UINT8 bta_dm_authentication_complete_cback(BD_ADDR bd_addr, DEV_CLASS dev_class,BD_NAME bd_name, int result);
+static void bta_dm_local_name_cback(BD_ADDR bd_addr);
+static BOOLEAN bta_dm_check_av(UINT16 event);
+#if (BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE)
+static void bta_dm_bl_change_cback (tBTM_BL_EVENT_DATA *p_data);
+#else
+static void bta_dm_acl_change_cback (BD_ADDR p_bda, DEV_CLASS p_dc, BD_NAME p_bdn, BD_FEATURES features, BOOLEAN is_new);
+#endif
+static void bta_dm_policy_cback(tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8 app_id, BD_ADDR peer_addr);
+
+/* Extended Inquiry Response */
+static UINT8 bta_dm_sp_cback (tBTM_SP_EVT event, tBTM_SP_EVT_DATA *p_data);
+
+#if (BTM_EIR_SERVER_INCLUDED == TRUE)
+static void bta_dm_set_eir (char *local_name);
+#endif /* BTM_EIR_SERVER_INCLUDED */
+
+#if (BTM_EIR_CLIENT_INCLUDED == TRUE)
+static void bta_dm_eir_search_services( tBTM_INQ_RESULTS *p_result,
+ tBTA_SERVICE_MASK *p_services_to_search,
+ tBTA_SERVICE_MASK *p_services_found);
+#endif /* BTM_EIR_CLIENT_INCLUDED */
+
+static void bta_dm_rssi_cback (tBTM_RSSI_RESULTS *p_result);
+static void bta_dm_signal_strength_timer_cback (TIMER_LIST_ENT *p_tle);
+static void bta_dm_link_quality_cback (tBTM_LINK_QUALITY_RESULTS *p_result);
+static void bta_dm_search_timer_cback (TIMER_LIST_ENT *p_tle);
+static void bta_dm_disable_timer_cback (TIMER_LIST_ENT *p_tle);
+static void bta_dm_disable_conn_down_timer_cback (TIMER_LIST_ENT *p_tle);
+static void bta_dm_rm_cback(tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8 app_id, BD_ADDR peer_addr);
+static void bta_dm_adjust_roles(void);
+static char *bta_dm_get_remname(void);
+static void bta_dm_bond_cancel_complete_cback(tBTM_STATUS result);
+
+static BOOLEAN bta_dm_read_remote_device_name (BD_ADDR bd_addr);
+static void bta_dm_discover_device(BD_ADDR remote_bd_addr);
+
+static void bta_dm_sys_hw_cback( tBTA_SYS_HW_EVT status );
+
+#if ((defined BLE_INCLUDED) && (BLE_INCLUDED == TRUE))
+ #if ((defined SMP_INCLUDED) && (SMP_INCLUDED == TRUE))
+static UINT8 bta_dm_ble_smp_cback (tBTM_LE_EVT event, BD_ADDR bda, tBTM_LE_EVT_DATA *p_data);
+ #endif
+static void bta_dm_ble_id_key_cback (UINT8 key_type, tBTM_BLE_LOCAL_KEYS *p_key);
+ #if ((defined BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE))
+static void btm_dm_start_gatt_discovery ( BD_ADDR bd_addr);
+static void bta_dm_cancel_gatt_discovery(BD_ADDR bd_addr);
+static void bta_dm_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC *p_data);
+ #endif
+#endif
+
+const UINT16 bta_service_id_to_uuid_lkup_tbl [BTA_MAX_SERVICE_ID] =
+{
+ UUID_SERVCLASS_PNP_INFORMATION, /* Reserved */
+ UUID_SERVCLASS_SERIAL_PORT, /* BTA_SPP_SERVICE_ID */
+ UUID_SERVCLASS_DIALUP_NETWORKING, /* BTA_DUN_SERVICE_ID */
+ UUID_SERVCLASS_FAX, /* BTA_FAX_SERVICE_ID */
+ UUID_SERVCLASS_LAN_ACCESS_USING_PPP, /* BTA_LAP_SERVICE_ID */
+ UUID_SERVCLASS_HEADSET, /* BTA_HSP_SERVICE_ID */
+ UUID_SERVCLASS_HF_HANDSFREE, /* BTA_HFP_SERVICE_ID */
+ UUID_SERVCLASS_OBEX_OBJECT_PUSH, /* BTA_OPP_SERVICE_ID */
+ UUID_SERVCLASS_OBEX_FILE_TRANSFER, /* BTA_FTP_SERVICE_ID */
+ UUID_SERVCLASS_CORDLESS_TELEPHONY, /* BTA_CTP_SERVICE_ID */
+ UUID_SERVCLASS_INTERCOM, /* BTA_ICP_SERVICE_ID */
+ UUID_SERVCLASS_IRMC_SYNC, /* BTA_SYNC_SERVICE_ID */
+ UUID_SERVCLASS_DIRECT_PRINTING, /* BTA_BPP_SERVICE_ID */
+ UUID_SERVCLASS_IMAGING_RESPONDER, /* BTA_BIP_SERVICE_ID */
+ UUID_SERVCLASS_PANU, /* BTA_PANU_SERVICE_ID */
+ UUID_SERVCLASS_NAP, /* BTA_NAP_SERVICE_ID */
+ UUID_SERVCLASS_GN, /* BTA_GN_SERVICE_ID */
+ UUID_SERVCLASS_SAP, /* BTA_SAP_SERVICE_ID */
+ UUID_SERVCLASS_AUDIO_SINK, /* BTA_A2DP_SERVICE_ID */
+ UUID_SERVCLASS_AV_REMOTE_CONTROL, /* BTA_AVRCP_SERVICE_ID */
+ UUID_SERVCLASS_HUMAN_INTERFACE, /* BTA_HID_SERVICE_ID */
+ UUID_SERVCLASS_VIDEO_SINK, /* BTA_VDP_SERVICE_ID */
+ UUID_SERVCLASS_PBAP_PSE, /* BTA_PBAP_SERVICE_ID */
+ UUID_SERVCLASS_HEADSET_AUDIO_GATEWAY, /* BTA_HSP_HS_SERVICE_ID */
+ UUID_SERVCLASS_AG_HANDSFREE, /* BTA_HFP_HS_SERVICE_ID */
+ UUID_SERVCLASS_MESSAGE_ACCESS, /* BTA_MAP_SERVICE_ID */
+ UUID_SERVCLASS_MESSAGE_NOTIFICATION, /* BTA_MN_SERVICE_ID */
+ UUID_SERVCLASS_HDP_PROFILE, /* BTA_HDP_SERVICE_ID */
+ UUID_SERVCLASS_PBAP_PCE /* BTA_PCE_SERVICE_ID */
+#if BLE_INCLUDED && BTA_GATT_INCLUDED
+ ,UUID_PROTOCOL_ATT /* BTA_GATT_SERVICE_ID */
+#endif
+};
+
+/*
+ * NOTE : The number of element in bta_service_id_to_btm_srv_id_lkup_tbl should be matching with
+ * the value BTA_MAX_SERVICE_ID in bta_api.h
+ *
+ * i.e., If you add new Service ID for BTA, the correct security ID of the new service
+ * from Security service definitions (btm_api.h) should be added to this lookup table.
+ */
+const UINT32 bta_service_id_to_btm_srv_id_lkup_tbl [BTA_MAX_SERVICE_ID] =
+{
+ 0, /* Reserved */
+ BTM_SEC_SERVICE_SERIAL_PORT, /* BTA_SPP_SERVICE_ID */
+ BTM_SEC_SERVICE_DUN, /* BTA_DUN_SERVICE_ID */
+ BTM_SEC_SERVICE_FAX, /* BTA_FAX_SERVICE_ID */
+ BTM_SEC_SERVICE_LAN_ACCESS, /* BTA_LAP_SERVICE_ID */
+ BTM_SEC_SERVICE_HEADSET_AG, /* BTA_HSP_SERVICE_ID */
+ BTM_SEC_SERVICE_AG_HANDSFREE, /* BTA_HFP_SERVICE_ID */
+ BTM_SEC_SERVICE_OBEX, /* BTA_OPP_SERVICE_ID */
+ BTM_SEC_SERVICE_OBEX_FTP, /* BTA_FTP_SERVICE_ID */
+ BTM_SEC_SERVICE_CORDLESS, /* BTA_CTP_SERVICE_ID */
+ BTM_SEC_SERVICE_INTERCOM, /* BTA_ICP_SERVICE_ID */
+ BTM_SEC_SERVICE_IRMC_SYNC, /* BTA_SYNC_SERVICE_ID */
+ BTM_SEC_SERVICE_BPP_JOB, /* BTA_BPP_SERVICE_ID */
+ BTM_SEC_SERVICE_BIP, /* BTA_BIP_SERVICE_ID */
+ BTM_SEC_SERVICE_BNEP_PANU, /* BTA_PANU_SERVICE_ID */
+ BTM_SEC_SERVICE_BNEP_NAP, /* BTA_NAP_SERVICE_ID */
+ BTM_SEC_SERVICE_BNEP_GN, /* BTA_GN_SERVICE_ID */
+ BTM_SEC_SERVICE_SAP, /* BTA_SAP_SERVICE_ID */
+ BTM_SEC_SERVICE_AVDTP, /* BTA_A2DP_SERVICE_ID */
+ BTM_SEC_SERVICE_AVCTP, /* BTA_AVRCP_SERVICE_ID */
+ BTM_SEC_SERVICE_HID_SEC_CTRL, /* BTA_HID_SERVICE_ID */
+ BTM_SEC_SERVICE_AVDTP, /* BTA_VDP_SERVICE_ID */
+ BTM_SEC_SERVICE_PBAP, /* BTA_PBAP_SERVICE_ID */
+ BTM_SEC_SERVICE_HEADSET, /* BTA_HSP_HS_SERVICE_ID */
+ BTM_SEC_SERVICE_HF_HANDSFREE, /* BTA_HFP_HS_SERVICE_ID */
+ BTM_SEC_SERVICE_MAP, /* BTA_MAP_SERVICE_ID */
+ BTM_SEC_SERVICE_MAP, /* BTA_MN_SERVICE_ID */
+ BTM_SEC_SERVICE_HDP_SNK, /* BTA_HDP_SERVICE_ID */
+ BTM_SEC_SERVICE_PBAP /* BTA_PCE_SERVICE_ID */
+#if BLE_INCLUDED && BTA_GATT_INCLUDED
+ ,BTM_SEC_SERVICE_ATT /* BTA_GATT_SERVICE_ID */
+#endif
+};
+
+/* bta security callback */
+const tBTM_APPL_INFO bta_security =
+{
+ &bta_dm_authorize_cback,
+ &bta_dm_pin_cback,
+ &bta_dm_new_link_key_cback,
+ &bta_dm_link_key_request_cback,
+ &bta_dm_authentication_complete_cback,
+ NULL,
+ &bta_dm_bond_cancel_complete_cback,
+#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
+ &bta_dm_sp_cback
+#else
+ NULL
+#endif
+#if BLE_INCLUDED == TRUE
+#if SMP_INCLUDED == TRUE
+ ,&bta_dm_ble_smp_cback
+#endif
+ ,&bta_dm_ble_id_key_cback
+#endif
+
+};
+
+#define MAX_DISC_RAW_DATA_BUF (4096)
+UINT8 g_disc_raw_data_buf[MAX_DISC_RAW_DATA_BUF];
+
+/*******************************************************************************
+**
+** Function bta_dm_app_ready_timer_cback
+**
+** Description allow sending EIR to controller
+**
+**
+** Returns void
+**
+*******************************************************************************/
+#if ( BTM_EIR_SERVER_INCLUDED == TRUE )&&(BTA_EIR_CANNED_UUID_LIST != TRUE)
+static void bta_dm_app_ready_timer_cback (TIMER_LIST_ENT *p_tle)
+{
+ bta_dm_set_eir (NULL);
+}
+#else
+#define bta_dm_app_ready_timer_cback (x)
+#endif
+
+/*******************************************************************************
+**
+** Function bta_dm_enable
+**
+** Description Initialises the BT device manager
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_enable(tBTA_DM_MSG *p_data)
+{
+ tBTA_SYS_HW_MSG *sys_enable_event;
+ tBTA_DM_ENABLE enable_event;
+
+
+ /* if already in use, return an error */
+ if( bta_dm_cb.is_bta_dm_active == TRUE )
+ {
+ APPL_TRACE_WARNING0("bta_dm_enable - device already started by another application");
+ memset(&enable_event, 0, sizeof ( tBTA_DM_ENABLE ));
+ enable_event.status = BTA_FAILURE;
+ if( p_data->enable.p_sec_cback != NULL )
+ p_data->enable.p_sec_cback (BTA_DM_ENABLE_EVT, (tBTA_DM_SEC *)&enable_event );
+ return;
+ }
+
+
+ /* first, register our callback to SYS HW manager */
+ bta_sys_hw_register( BTA_SYS_HW_BLUETOOTH, bta_dm_sys_hw_cback );
+
+ /* make sure security callback is saved - if no callback, do not erase the previous one,
+ it could be an error recovery mechanism */
+ if( p_data->enable.p_sec_cback != NULL )
+ bta_dm_cb.p_sec_cback = p_data->enable.p_sec_cback;
+ /* notify BTA DM is now active */
+ bta_dm_cb.is_bta_dm_active = TRUE;
+
+ /* send a message to BTA SYS */
+ if ((sys_enable_event = (tBTA_SYS_HW_MSG *) GKI_getbuf(sizeof(tBTA_SYS_HW_MSG))) != NULL)
+ {
+ sys_enable_event->hdr.event = BTA_SYS_API_ENABLE_EVT;
+ sys_enable_event->hw_module = BTA_SYS_HW_BLUETOOTH;
+
+ bta_sys_sendmsg(sys_enable_event);
+
+ }
+
+
+
+}
+
+
+
+/*******************************************************************************
+**
+** Function bta_dm_sys_hw_cback
+**
+** Description callback register to SYS to get HW status updates
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_dm_sys_hw_cback( tBTA_SYS_HW_EVT status )
+{
+ DEV_CLASS dev_class;
+ tBTA_DM_SEC_CBACK *temp_cback;
+#if BLE_INCLUDED == TRUE
+ UINT8 key_mask = 0;
+ BT_OCTET16 er;
+ tBTA_BLE_LOCAL_ID_KEYS id_key;
+ tBT_UUID app_uuid = {LEN_UUID_128,{0}};
+#endif
+ APPL_TRACE_DEBUG1(" bta_dm_sys_hw_cback with event: %i" , status );
+
+ if( status == BTA_SYS_HW_OFF_EVT )
+ {
+ if( bta_dm_cb.p_sec_cback != NULL )
+ bta_dm_cb.p_sec_cback(BTA_DM_DISABLE_EVT, NULL);
+
+ /* reinitialize the control block */
+ memset(&bta_dm_cb, 0, sizeof(bta_dm_cb));
+
+ /* unregister from SYS */
+ bta_sys_hw_unregister( BTA_SYS_HW_BLUETOOTH );
+ /* notify BTA DM is now unactive */
+ bta_dm_cb.is_bta_dm_active = FALSE;
+ }
+ else
+ if( status == BTA_SYS_HW_ON_EVT )
+ {
+ /* make sure we unregister, so that we don't motified again if another module starts */
+ bta_sys_hw_unregister( BTA_SYS_HW_BLUETOOTH);
+
+ /* save security callback */
+ temp_cback = bta_dm_cb.p_sec_cback;
+ /* make sure the control block is properly initialized */
+ memset(&bta_dm_cb, 0, sizeof(bta_dm_cb));
+ /* and retrieve the callback */
+ bta_dm_cb.p_sec_cback=temp_cback;
+ bta_dm_cb.is_bta_dm_active = TRUE;
+
+ /* hw is ready, go on with BTA DM initialization */
+ memset(&bta_dm_search_cb, 0x00, sizeof(bta_dm_search_cb));
+ memset(&bta_dm_conn_srvcs, 0x00, sizeof(bta_dm_conn_srvcs));
+ memset(&bta_dm_di_cb, 0, sizeof(tBTA_DM_DI_CB));
+
+ memcpy(dev_class, bta_dm_cfg.dev_class, sizeof(dev_class));
+ BTM_SetDeviceClass (dev_class);
+
+#if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE)
+ /* load BLE local information: ID keys, ER if available */
+ bta_dm_co_ble_load_local_keys(&key_mask, er, &id_key);
+
+ if (key_mask & BTA_BLE_LOCAL_KEY_TYPE_ER)
+ {
+ BTM_BleLoadLocalKeys(BTA_BLE_LOCAL_KEY_TYPE_ER, (tBTM_BLE_LOCAL_KEYS *)&er);
+ }
+ if (key_mask & BTA_BLE_LOCAL_KEY_TYPE_ID)
+ {
+ BTM_BleLoadLocalKeys(BTA_BLE_LOCAL_KEY_TYPE_ID, (tBTM_BLE_LOCAL_KEYS *)&id_key);
+ }
+#if ((defined BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE))
+ memset (&app_uuid.uu.uuid128, 0x87, LEN_UUID_128);
+ BTA_GATTC_AppRegister(&app_uuid, bta_dm_gattc_callback);
+#endif
+#endif
+
+ BTM_SecRegister((tBTM_APPL_INFO*)&bta_security);
+ BTM_SetDefaultLinkSuperTout(bta_dm_cfg.link_timeout);
+ BTM_WritePageTimeout(bta_dm_cfg.page_timeout);
+ bta_dm_cb.cur_policy = bta_dm_cfg.policy_settings;
+ BTM_SetDefaultLinkPolicy(bta_dm_cb.cur_policy);
+#if (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE)
+ BTM_RegBusyLevelNotif (bta_dm_bl_change_cback, NULL, BTM_BL_UPDATE_MASK|BTM_BL_ROLE_CHG_MASK);
+#else
+ BTM_AclRegisterForChanges(bta_dm_acl_change_cback);
+#endif
+ /* Earlier, we used to invoke BTM_ReadLocalAddr which was just copying the bd_addr
+ from the control block and invoking the callback which was sending the DM_ENABLE_EVT.
+ But then we have a few HCI commands being invoked above which were still in progress
+ when the ENABLE_EVT was sent. So modified this to fetch the local name which forces
+ the DM_ENABLE_EVT to be sent only after all the init steps are complete */
+ BTM_ReadLocalDeviceNameFromController((tBTM_CMPL_CB *)bta_dm_local_name_cback);
+
+ bta_sys_rm_register((tBTA_SYS_CONN_CBACK*)bta_dm_rm_cback);
+
+ /* initialize bluetooth low power manager */
+ bta_dm_init_pm();
+
+ bta_sys_policy_register((tBTA_SYS_CONN_CBACK*)bta_dm_policy_cback);
+
+
+ // BLUEDROID REMOVE ??
+#if 0
+#if 1
+ /* Create broadcom primary DI record */
+ if(WBT_ExtCreateRecord())
+ {
+#if ( BTM_EIR_SERVER_INCLUDED == TRUE )&&( BTA_EIR_CANNED_UUID_LIST != TRUE )
+ /* while app_ready_timer is running, BTA DM doesn't send EIR to controller */
+ bta_dm_cb.app_ready_timer.p_cback = (TIMER_CBACK*)&bta_dm_app_ready_timer_cback;
+ bta_sys_start_timer(&bta_dm_cb.app_ready_timer, 0, 100);
+
+ bta_sys_add_uuid(UUID_SERVCLASS_PNP_INFORMATION);
+#endif
+ bta_dm_di_cb.di_handle[bta_dm_di_cb.di_num] = 0; /* primary DI record */
+ bta_dm_di_cb.di_num ++;
+ }
+#else /* Eventually implement pin code */
+ if (WBT_ExtCreateRecord())
+ WBT_ExtAddPinCode();
+#endif
+#endif
+ }
+ else
+ APPL_TRACE_DEBUG0(" --- ignored event");
+
+}
+
+
+/*******************************************************************************
+**
+** Function bta_dm_disable
+**
+** Description Disables the BT device manager
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_disable (tBTA_DM_MSG *p_data)
+{
+ /* Set l2cap idle timeout to 0 (so BTE immediately disconnects ACL link after last channel is closed) */
+ L2CA_SetIdleTimeoutByBdAddr((UINT8 *)BT_BD_ANY, 0);
+
+ /* disable all active subsystems */
+ bta_sys_disable(BTA_SYS_HW_BLUETOOTH);
+
+ BTM_SetDiscoverability(BTM_NON_DISCOVERABLE, 0, 0);
+ BTM_SetConnectability(BTM_NON_CONNECTABLE, 0, 0);
+
+ bta_dm_disable_pm();
+
+ bta_dm_cb.disabling = TRUE;
+
+ bta_dm_search_cancel(NULL);
+
+ if(BTM_GetNumAclLinks()==0)
+ {
+ bta_dm_cb.disable_timer.p_cback = (TIMER_CBACK*)&bta_dm_disable_conn_down_timer_cback;
+ bta_sys_start_timer(&bta_dm_cb.disable_timer, 0, 1000);
+ }
+ else
+ {
+ bta_dm_cb.disable_timer.p_cback = (TIMER_CBACK*)&bta_dm_disable_timer_cback;
+ bta_sys_start_timer(&bta_dm_cb.disable_timer, 0, 5000);
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_disable_timer_cback
+**
+** Description Called if the disable timer expires
+** Used to close ACL connections which are still active
+**
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_dm_disable_timer_cback (TIMER_LIST_ENT *p_tle)
+{
+
+ UINT8 i;
+
+ APPL_TRACE_EVENT0(" bta_dm_disable_timer_cback ");
+
+ if(BTM_GetNumAclLinks())
+ {
+ for(i=0; i<bta_dm_cb.device_list.count; i++)
+ {
+ btm_remove_acl(bta_dm_cb.device_list.peer_device[i].peer_bdaddr);
+
+ }
+
+ }
+ else
+ {
+ bta_dm_cb.disabling = FALSE;
+
+ bta_sys_remove_uuid(UUID_SERVCLASS_PNP_INFORMATION);
+ bta_dm_cb.p_sec_cback(BTA_DM_DISABLE_EVT, NULL);
+ }
+}
+
+
+
+
+/*******************************************************************************
+**
+** Function bta_dm_set_dev_name
+**
+** Description Sets local device name
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_set_dev_name (tBTA_DM_MSG *p_data)
+{
+
+ BTM_SetLocalDeviceName((char*)p_data->set_name.name);
+#if (BTM_EIR_SERVER_INCLUDED == TRUE)
+ bta_dm_set_eir ((char*)p_data->set_name.name);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_set_visibility
+**
+** Description Sets discoverability, connectability and pairability
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_set_visibility (tBTA_DM_MSG *p_data)
+{
+
+
+ /* set modes for Discoverability and connectability if not ignore */
+ if (p_data->set_visibility.disc_mode != BTA_DM_IGNORE)
+ BTM_SetDiscoverability((UINT8)p_data->set_visibility.disc_mode,
+ bta_dm_cb.inquiry_scan_window,
+ bta_dm_cb.inquiry_scan_interval);
+
+ if (p_data->set_visibility.conn_mode != BTA_DM_IGNORE)
+ BTM_SetConnectability((UINT8)p_data->set_visibility.conn_mode,
+ bta_dm_cb.page_scan_window,
+ bta_dm_cb.page_scan_interval);
+
+ /* Send False or True if not ignore */
+ if (p_data->set_visibility.pair_mode != BTA_DM_IGNORE )
+ {
+
+ if (p_data->set_visibility.pair_mode == BTA_DM_NON_PAIRABLE)
+ bta_dm_cb.disable_pair_mode = TRUE;
+ else
+ bta_dm_cb.disable_pair_mode = FALSE;
+
+ }
+
+ /* Send False or True if not ignore */
+ if (p_data->set_visibility.conn_paired_only != BTA_DM_IGNORE)
+ {
+
+ if (p_data->set_visibility.conn_paired_only == BTA_DM_CONN_ALL)
+ bta_dm_cb.conn_paired_only = FALSE;
+ else
+ bta_dm_cb.conn_paired_only = TRUE;
+
+ }
+
+ /* Change mode if either mode is not ignore */
+ if (p_data->set_visibility.pair_mode != BTA_DM_IGNORE || p_data->set_visibility.conn_paired_only != BTA_DM_IGNORE)
+ BTM_SetPairableMode((BOOLEAN)(!(bta_dm_cb.disable_pair_mode)),bta_dm_cb.conn_paired_only);
+
+}
+
+
+/*******************************************************************************
+**
+** Function bta_dm_set_afhchannels
+**
+** Description This function sets the AFH first and
+** last disable channel, so channels within
+** that range are disabled.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_set_afhchannels (tBTA_DM_MSG *p_data)
+{
+ BTM_SetAfhChannels(p_data->set_afhchannels.first,p_data->set_afhchannels.last);
+
+}
+
+
+/*******************************************************************************
+**
+** Function bta_dm_vendor_spec_command
+**
+** Description Send a vendor specific command to the controller
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_vendor_spec_command (tBTA_DM_MSG *p_data)
+{
+ tBTM_STATUS status;
+
+ status = BTM_VendorSpecificCommand(p_data->vendor_command.opcode,p_data->vendor_command.param_len,p_data->vendor_command.p_param_buf, p_data->vendor_command.p_cback);
+
+}
+
+
+/*******************************************************************************
+**
+** Function bta_dm_tx_inqpower
+**
+** Description write inquiry tx power.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_tx_inqpower(tBTA_DM_MSG *p_data)
+{
+ if (BTM_WriteInquiryTxPower (p_data->tx_inq_pwr.tx_power) == BTM_ILLEGAL_VALUE)
+ {
+ APPL_TRACE_ERROR1("Invalid Inquiry Tx Power: %d", p_data->tx_inq_pwr.tx_power);
+ }
+ return;
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_add_device
+**
+** Description This function adds a Link Key to an security database entry.
+** It is normally called during host startup to restore all required information
+** stored in the NVRAM.
+****
+*******************************************************************************/
+void bta_dm_add_device (tBTA_DM_MSG *p_data)
+{
+ tBTA_DM_API_ADD_DEVICE *p_dev = &p_data->add_dev;
+ UINT8 *p_dc = NULL;
+ UINT8 *p_lc = NULL;
+ UINT32 trusted_services_mask[BTM_SEC_SERVICE_ARRAY_SIZE];
+ UINT8 index = 0;
+ UINT8 btm_mask_index = 0;
+
+ memset (trusted_services_mask, 0, sizeof(trusted_services_mask));
+
+ /* If not all zeros, the device class has been specified */
+ if (p_dev->dc_known)
+ p_dc = (UINT8 *)p_dev->dc;
+
+ if (p_dev->link_key_known)
+ p_lc = (UINT8 *)p_dev->link_key;
+
+ if (p_dev->is_trusted)
+ {
+ /* covert BTA service mask to BTM mask */
+ while (p_dev->tm && (index < BTA_MAX_SERVICE_ID))
+ {
+ if (p_dev->tm & (UINT32)(1<<index))
+ {
+
+ btm_mask_index = bta_service_id_to_btm_srv_id_lkup_tbl[index] / BTM_SEC_ARRAY_BITS;
+ trusted_services_mask[btm_mask_index] |= (UINT32)(1 << (bta_service_id_to_btm_srv_id_lkup_tbl[index] - (UINT32)(btm_mask_index * 32)));
+
+ p_dev->tm &= (UINT32)(~(1<<index));
+
+ }
+ index++;
+ }
+ }
+
+ if (!BTM_SecAddDevice (p_dev->bd_addr, p_dc, p_dev->bd_name, p_dev->features,
+ trusted_services_mask, p_lc, p_dev->key_type, p_dev->io_cap))
+ {
+ APPL_TRACE_ERROR2 ("BTA_DM: Error adding device %08x%04x",
+ (p_dev->bd_addr[0]<<24)+(p_dev->bd_addr[1]<<16)+(p_dev->bd_addr[2]<<8)+p_dev->bd_addr[3],
+ (p_dev->bd_addr[4]<<8)+p_dev->bd_addr[5]);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_bond
+**
+** Description Bonds with peer device
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_bond (tBTA_DM_MSG *p_data)
+{
+ tBTM_STATUS status;
+ tBTA_DM_SEC sec_event;
+ char *p_name;
+
+ status = BTM_SecBond ( p_data->bond.bd_addr, 0, NULL, 0 );
+
+ if (bta_dm_cb.p_sec_cback && (status != BTM_CMD_STARTED))
+ {
+
+ p_name = BTM_SecReadDevName(p_data->bond.bd_addr);
+ if (!p_name)
+ p_name = "";
+
+ memset(&sec_event, 0, sizeof(tBTA_DM_SEC));
+ bdcpy(sec_event.auth_cmpl.bd_addr, p_data->bond.bd_addr);
+ memcpy(sec_event.auth_cmpl.bd_name, p_name, (BD_NAME_LEN-1));
+ sec_event.auth_cmpl.bd_name[BD_NAME_LEN-1] = 0;
+
+/* taken care of by memset [above]
+ sec_event.auth_cmpl.key_present = FALSE;
+ sec_event.auth_cmpl.success = FALSE;
+*/
+ sec_event.auth_cmpl.fail_reason = HCI_ERR_ILLEGAL_COMMAND;
+ if (status == BTM_SUCCESS)
+ sec_event.auth_cmpl.success = TRUE;
+
+ bta_dm_cb.p_sec_cback(BTA_DM_AUTH_CMPL_EVT, &sec_event);
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_bond_cancel
+**
+** Description Cancels bonding with a peer device
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_bond_cancel (tBTA_DM_MSG *p_data)
+{
+ tBTM_STATUS status;
+ tBTA_DM_SEC sec_event;
+
+ APPL_TRACE_EVENT0(" bta_dm_bond_cancel ");
+ status = BTM_SecBondCancel ( p_data->bond_cancel.bd_addr );
+
+ if (bta_dm_cb.p_sec_cback && (status != BTM_CMD_STARTED && status != BTM_SUCCESS))
+ {
+ sec_event.bond_cancel_cmpl.result = BTA_FAILURE;
+
+ bta_dm_cb.p_sec_cback(BTA_DM_BOND_CANCEL_CMPL_EVT, &sec_event);
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_pin_reply
+**
+** Description Send the pin_reply to a request from BTM
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_pin_reply (tBTA_DM_MSG *p_data)
+{
+ UINT32 trusted_mask[BTM_SEC_SERVICE_ARRAY_SIZE];
+ UINT32 * current_trusted_mask;
+
+ current_trusted_mask = BTM_ReadTrustedMask(p_data->pin_reply.bd_addr);
+
+ if(current_trusted_mask)
+ {
+ memcpy(trusted_mask, current_trusted_mask, sizeof(trusted_mask));
+ }
+ else
+ {
+ memset(trusted_mask, 0, sizeof(trusted_mask));
+ }
+
+ if(p_data->pin_reply.accept)
+ {
+
+ BTM_PINCodeReply(p_data->pin_reply.bd_addr, BTM_SUCCESS, p_data->pin_reply.pin_len, p_data->pin_reply.p_pin, trusted_mask );
+ }
+ else
+ {
+ BTM_PINCodeReply(p_data->pin_reply.bd_addr, BTM_NOT_AUTHORIZED, 0, NULL, trusted_mask );
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_link_policy
+**
+** Description remove/set link policy mask.
+** wake the link, is sniff/park is removed
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_link_policy (tBTA_DM_MSG *p_data)
+{
+ tBTA_DM_PEER_DEVICE *p_dev;
+
+ p_dev = bta_dm_find_peer_device(p_data->link_policy.bd_addr);
+ if(!p_dev)
+ return;
+
+ APPL_TRACE_DEBUG2(" bta_dm_link_policy set:%d, policy:0x%x",
+ p_data->link_policy.set, p_data->link_policy.policy_mask);
+ if(p_data->link_policy.set)
+ {
+ /* restore the default link policy */
+ p_dev->link_policy |= p_data->link_policy.policy_mask;
+ BTM_SetLinkPolicy(p_dev->peer_bdaddr, &(p_dev->link_policy));
+ }
+ else
+ {
+ /* clear the policy from the default link policy */
+ p_dev->link_policy &= (~p_data->link_policy.policy_mask);
+ BTM_SetLinkPolicy(p_dev->peer_bdaddr, &(p_dev->link_policy));
+
+ if(p_data->link_policy.policy_mask & (HCI_ENABLE_SNIFF_MODE | HCI_ENABLE_PARK_MODE))
+ {
+ /* if clearing sniff/park, wake the link */
+ bta_dm_pm_active(p_dev->peer_bdaddr);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_policy_cback
+**
+** Description process the link policy changes
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_dm_policy_cback(tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8 app_id, BD_ADDR peer_addr)
+{
+ tBTA_DM_PEER_DEVICE *p_dev = NULL;
+ UINT16 policy = app_id;
+ UINT32 mask = (UINT32)(1 << id);
+
+ if(peer_addr)
+ p_dev = bta_dm_find_peer_device(peer_addr);
+
+ APPL_TRACE_DEBUG2(" bta_dm_policy_cback cmd:%d, policy:0x%x",
+ status, policy);
+ switch(status)
+ {
+ case BTA_SYS_PLCY_SET:
+ if(!p_dev)
+ return;
+ /* restore the default link policy */
+ p_dev->link_policy |= policy;
+ BTM_SetLinkPolicy(p_dev->peer_bdaddr, &(p_dev->link_policy));
+ break;
+
+ case BTA_SYS_PLCY_CLR:
+ if(!p_dev)
+ return;
+ /* clear the policy from the default link policy */
+ p_dev->link_policy &= (~policy);
+ BTM_SetLinkPolicy(p_dev->peer_bdaddr, &(p_dev->link_policy));
+
+ if(policy & (HCI_ENABLE_SNIFF_MODE | HCI_ENABLE_PARK_MODE))
+ {
+ /* if clearing sniff/park, wake the link */
+ bta_dm_pm_active(p_dev->peer_bdaddr);
+ }
+ break;
+
+ case BTA_SYS_PLCY_DEF_SET:
+ /* want to restore/set the role switch policy */
+ bta_dm_cb.role_policy_mask &= ~mask;
+ if(0 == bta_dm_cb.role_policy_mask)
+ {
+ /* if nobody wants to insist on the role */
+ bta_dm_cb.cur_policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH;
+ BTM_SetDefaultLinkPolicy(bta_dm_cb.cur_policy);
+ }
+ break;
+
+ case BTA_SYS_PLCY_DEF_CLR:
+ /* want to remove the role switch policy */
+ bta_dm_cb.role_policy_mask |= mask;
+ bta_dm_cb.cur_policy &= ~HCI_ENABLE_MASTER_SLAVE_SWITCH;
+ BTM_SetDefaultLinkPolicy(bta_dm_cb.cur_policy);
+ break;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function bta_dm_auth_reply
+**
+** Description Send the authorization reply to a request from BTM
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_auth_reply (tBTA_DM_MSG *p_data)
+{
+
+ UINT32 trusted_mask[BTM_SEC_SERVICE_ARRAY_SIZE];
+ UINT8 btm_mask_index = 0;
+ UINT32 * current_trusted_mask;
+
+ current_trusted_mask = BTM_ReadTrustedMask(p_data->auth_reply.bd_addr);
+
+ if(current_trusted_mask)
+ {
+ memcpy(trusted_mask, current_trusted_mask, sizeof(trusted_mask));
+ }
+ else
+ {
+ memset(trusted_mask, 0, sizeof(trusted_mask));
+ }
+
+ if(p_data->auth_reply.response != BTA_DM_NOT_AUTH)
+ {
+ if(p_data->auth_reply.response == BTA_DM_AUTH_PERM)
+ {
+ if(p_data->auth_reply.service < BTA_MAX_SERVICE_ID)
+ {
+ /* convert BTA service id to BTM mask */
+ btm_mask_index = bta_service_id_to_btm_srv_id_lkup_tbl[p_data->auth_reply.service] / 32;
+ trusted_mask[btm_mask_index] |= (UINT32)(1 << (bta_service_id_to_btm_srv_id_lkup_tbl[p_data->auth_reply.service] - (UINT32)(btm_mask_index * 32)));
+
+ }
+ }
+ BTM_DeviceAuthorized (p_data->auth_reply.bd_addr, BTM_SUCCESS,trusted_mask);
+ }
+ else
+ {
+ BTM_DeviceAuthorized (p_data->auth_reply.bd_addr, BTM_NOT_AUTHORIZED,trusted_mask);
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_confirm
+**
+** Description Send the user confirm request reply in response to a
+** request from BTM
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_confirm(tBTA_DM_MSG *p_data)
+{
+ tBTM_STATUS res = BTM_NOT_AUTHORIZED;
+
+ if(p_data->confirm.accept == TRUE)
+ res = BTM_SUCCESS;
+ BTM_ConfirmReqReply(res, p_data->confirm.bd_addr);
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_passkey_cancel
+**
+** Description Send the passkey cancel from SP initiator by sending a negative
+** passkey request replyreply.
+** Returns void
+**
+*******************************************************************************/
+#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
+void bta_dm_passkey_cancel(tBTA_DM_MSG *p_data)
+{
+ BTM_PasskeyReqReply(BTM_NOT_AUTHORIZED, p_data->passkey_cancel.bd_addr, 0);
+}
+#endif
+
+/*******************************************************************************
+**
+** Function bta_dm_loc_oob
+**
+** Description Retrieve the OOB data from the local LM
+**
+** Returns void
+**
+*******************************************************************************/
+#if (BTM_OOB_INCLUDED == TRUE)
+void bta_dm_loc_oob(tBTA_DM_MSG *p_data)
+{
+ BTM_ReadLocalOobData();
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_ci_io_req_act
+**
+** Description respond to the IO capabilities request from BTM
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_ci_io_req_act(tBTA_DM_MSG *p_data)
+{
+ tBTM_AUTH_REQ auth_req = BTM_AUTH_AP_NO;
+ if(p_data->ci_io_req.auth_req)
+ auth_req = BTM_AUTH_AP_YES;
+ BTM_IoCapRsp(p_data->ci_io_req.bd_addr, p_data->ci_io_req.io_cap,
+ p_data->ci_io_req.oob_data, auth_req);
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_ci_rmt_oob_act
+**
+** Description respond to the OOB data request for the remote device from BTM
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_ci_rmt_oob_act(tBTA_DM_MSG *p_data)
+{
+ tBTM_STATUS res = BTM_NOT_AUTHORIZED;
+
+ if(p_data->ci_rmt_oob.accept == TRUE)
+ res = BTM_SUCCESS;
+ BTM_RemoteOobDataReply(res, p_data->ci_rmt_oob.bd_addr,
+ p_data->ci_rmt_oob.c, p_data->ci_rmt_oob.r );
+}
+#endif /* BTM_OOB_INCLUDED */
+
+/*******************************************************************************
+**
+** Function bta_dm_search_start
+**
+** Description Starts an inquiry
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_search_start (tBTA_DM_MSG *p_data)
+{
+ tBTM_INQUIRY_CMPL result;
+
+#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE
+ UINT16 len = (UINT16)(sizeof(tBT_UUID) * p_data->search.num_uuid);
+#endif
+
+ APPL_TRACE_DEBUG1("bta_dm_search_start avoid_scatter=%d", bta_dm_cfg.avoid_scatter);
+ if (bta_dm_cfg.avoid_scatter &&
+ (p_data->search.rs_res == BTA_DM_RS_NONE) && bta_dm_check_av(BTA_DM_API_SEARCH_EVT))
+ {
+ memcpy(&bta_dm_cb.search_msg, &p_data->search, sizeof(tBTA_DM_API_SEARCH));
+ return;
+ }
+
+ BTM_ClearInqDb(NULL);
+ /* save search params */
+ bta_dm_search_cb.p_search_cback = p_data->search.p_cback;
+ bta_dm_search_cb.services = p_data->search.services;
+
+#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE)
+ utl_freebuf((void **)&bta_dm_search_cb.p_srvc_uuid);
+
+ if ((bta_dm_search_cb.num_uuid = p_data->search.num_uuid) != 0 &&
+ p_data->search.p_uuid != NULL)
+ {
+ if ((bta_dm_search_cb.p_srvc_uuid = (tBT_UUID *)GKI_getbuf(len)) == NULL)
+ {
+ APPL_TRACE_ERROR0("bta_dm_search_start no resources");
+
+ result.status = BTA_FAILURE;
+ result.num_resp = 0;
+ bta_dm_inq_cmpl_cb ((void *)&result);
+ return;
+ }
+// bta_dm_search_cb.p_srvc_uuid = (tBT_UUID *)GKI_getbuf(len);
+ memcpy(bta_dm_search_cb.p_srvc_uuid, p_data->search.p_uuid, len);
+ }
+
+ if (p_data->search.inq_params.mode & BTM_LIMITED_INQUIRY)
+ p_data->search.inq_params.mode |= BTM_BLE_LIMITED_INQUIRY;
+ else
+ p_data->search.inq_params.mode |= BTM_BLE_GENERAL_INQUIRY;
+#endif
+ result.status = BTM_StartInquiry( (tBTM_INQ_PARMS*)&p_data->search.inq_params,
+ bta_dm_inq_results_cb,
+ (tBTM_CMPL_CB*) bta_dm_inq_cmpl_cb);
+
+ APPL_TRACE_EVENT1("bta_dm_search_start status=%d", result.status);
+ if (result.status != BTM_CMD_STARTED)
+ {
+ result.num_resp = 0;
+ bta_dm_inq_cmpl_cb ((void *)&result);
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_search_cancel
+**
+** Description Cancels an ongoing search for devices
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_search_cancel (tBTA_DM_MSG *p_data)
+{
+
+ tBTA_DM_MSG * p_msg;
+
+ if(BTM_IsInquiryActive())
+ {
+ BTM_CancelInquiry();
+ bta_dm_search_cancel_notify(NULL);
+
+ if ((p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL)
+ {
+ p_msg->hdr.event = BTA_DM_SEARCH_CMPL_EVT;
+ p_msg->hdr.layer_specific = BTA_DM_API_DISCOVER_EVT;
+ bta_sys_sendmsg(p_msg);
+
+ }
+ }
+ /* If no Service Search going on then issue cancel remote name in case it is active */
+ else if (!bta_dm_search_cb.name_discover_done)
+ {
+ BTM_CancelRemoteDeviceName();
+ }
+#if ((BLE_INCLUDED == TRUE) && (defined BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE))
+ if (bta_dm_search_cb.gatt_disc_active)
+ {
+ bta_dm_cancel_gatt_discovery(bta_dm_search_cb.peer_bdaddr);
+ }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_discover
+**
+** Description Discovers services on a remote device
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_discover (tBTA_DM_MSG *p_data)
+{
+#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE
+ UINT16 len = (UINT16)(sizeof(tBT_UUID) * p_data->discover.num_uuid);
+#endif
+ APPL_TRACE_EVENT2("bta_dm_discover services_to_search=0x%04X, sdp_search=%d",
+ p_data->discover.services, p_data->discover.sdp_search);
+
+ /* save the search condition */
+ bta_dm_search_cb.services = p_data->discover.services;
+
+#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE
+ utl_freebuf((void **)&bta_dm_search_cb.p_srvc_uuid);
+ if ((bta_dm_search_cb.num_uuid = p_data->discover.num_uuid) != 0 &&
+ p_data->discover.p_uuid != NULL)
+ {
+ if ((bta_dm_search_cb.p_srvc_uuid = (tBT_UUID *)GKI_getbuf(len)) == NULL)
+ {
+ p_data->discover.p_cback(BTA_DM_DISC_CMPL_EVT, NULL);
+ return;
+ }
+ memcpy(bta_dm_search_cb.p_srvc_uuid, p_data->discover.p_uuid, len);
+ }
+ bta_dm_search_cb.uuid_to_search = bta_dm_search_cb.num_uuid;
+#endif
+
+ bta_dm_search_cb.p_search_cback = p_data->discover.p_cback;
+ bta_dm_search_cb.sdp_search = p_data->discover.sdp_search;
+ bta_dm_search_cb.services_to_search = bta_dm_search_cb.services;
+ bta_dm_search_cb.service_index = 0;
+ bta_dm_search_cb.services_found = 0;
+ bta_dm_search_cb.peer_name[0] = 0;
+ bta_dm_search_cb.sdp_search = p_data->discover.sdp_search;
+ bta_dm_search_cb.p_btm_inq_info = BTM_InqDbRead (p_data->discover.bd_addr);
+
+ bta_dm_search_cb.name_discover_done = FALSE;
+ memcpy(&bta_dm_search_cb.uuid, &p_data->discover.uuid, sizeof(tSDP_UUID));
+ bta_dm_discover_device(p_data->discover.bd_addr);
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_di_disc_cmpl
+**
+** Description Sends event to application when DI discovery complete
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_di_disc_cmpl(tBTA_DM_MSG *p_data)
+{
+ tBTA_DM_DI_DISC_CMPL di_disc;
+
+ memset(&di_disc, 0, sizeof(tBTA_DM_DI_DISC_CMPL));
+ bdcpy(di_disc.bd_addr, bta_dm_search_cb.peer_bdaddr);
+
+ if((p_data->hdr.offset == SDP_SUCCESS)
+ || (p_data->hdr.offset == SDP_DB_FULL))
+ {
+ di_disc.num_record = SDP_GetNumDiRecords(bta_dm_di_cb.p_di_db);
+ }
+ else
+ di_disc.result = BTA_FAILURE;
+
+ bta_dm_di_cb.p_di_db = NULL;
+ bta_dm_search_cb.p_search_cback(BTA_DM_DI_DISC_CMPL_EVT, (tBTA_DM_SEARCH *) &di_disc);
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_di_disc_callback
+**
+** Description This function queries a remote device for DI information.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_dm_di_disc_callback(UINT16 result)
+{
+ tBTA_DM_MSG * p_msg;
+
+ if ((p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL)
+ {
+ p_msg->hdr.event = BTA_DM_SEARCH_CMPL_EVT;
+ p_msg->hdr.layer_specific = BTA_DM_API_DI_DISCOVER_EVT;
+ p_msg->hdr.offset = result;
+ bta_sys_sendmsg(p_msg);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_di_disc
+**
+** Description This function queries a remote device for DI information.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_di_disc (tBTA_DM_MSG *p_data)
+{
+ UINT16 result = BTA_FAILURE;
+ tBTA_DM_MSG *p_msg;
+
+ bta_dm_search_cb.p_search_cback = p_data->di_disc.p_cback;
+ bdcpy(bta_dm_search_cb.peer_bdaddr, p_data->di_disc.bd_addr);
+ bta_dm_di_cb.p_di_db = p_data->di_disc.p_sdp_db;
+
+ if((bta_dm_search_cb.p_sdp_db = (tSDP_DISCOVERY_DB *)GKI_getbuf(BTA_DM_SDP_DB_SIZE)) != NULL)
+ {
+ if ( SDP_DiDiscover(bta_dm_search_cb.peer_bdaddr, p_data->di_disc.p_sdp_db,
+ p_data->di_disc.len, bta_dm_di_disc_callback) == SDP_SUCCESS)
+ {
+ result = BTA_SUCCESS;
+ }
+ }
+ else
+ {
+ APPL_TRACE_ERROR0("No buffer to start DI discovery");
+ }
+
+ if ( result == BTA_FAILURE &&
+ (p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL)
+ {
+ p_msg->hdr.event = BTA_DM_SEARCH_CMPL_EVT;
+ p_msg->hdr.layer_specific = BTA_DM_API_DI_DISCOVER_EVT;
+ p_data->hdr.offset = result;
+ bta_sys_sendmsg(p_msg);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_read_remote_device_name
+**
+** Description Initiate to get remote device name
+**
+** Returns TRUE if started to get remote name
+**
+*******************************************************************************/
+static BOOLEAN bta_dm_read_remote_device_name (BD_ADDR bd_addr)
+{
+ tBTM_STATUS btm_status;
+
+ APPL_TRACE_DEBUG0("bta_dm_read_remote_device_name");
+
+ bdcpy(bta_dm_search_cb.peer_bdaddr, bd_addr);
+ bta_dm_search_cb.peer_name[0] = 0;
+
+ btm_status = BTM_ReadRemoteDeviceName (bta_dm_search_cb.peer_bdaddr,
+ (tBTM_CMPL_CB *) bta_dm_remname_cback);
+
+ if ( btm_status == BTM_CMD_STARTED )
+ {
+ APPL_TRACE_DEBUG0("bta_dm_read_remote_device_name: BTM_ReadRemoteDeviceName is started");
+
+ return (TRUE);
+ }
+ else if ( btm_status == BTM_BUSY )
+ {
+ APPL_TRACE_DEBUG0("bta_dm_read_remote_device_name: BTM_ReadRemoteDeviceName is busy");
+
+ /* Remote name discovery is on going now so BTM cannot notify through "bta_dm_remname_cback" */
+ /* adding callback to get notified that current reading remore name done */
+ BTM_SecAddRmtNameNotifyCallback(&bta_dm_service_search_remname_cback);
+
+ return (TRUE);
+ }
+ else
+ {
+ APPL_TRACE_WARNING1("bta_dm_read_remote_device_name: BTM_ReadRemoteDeviceName returns 0x%02X", btm_status);
+
+ return (FALSE);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_inq_cmpl
+**
+** Description Process the inquiry complete event from BTM
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_inq_cmpl (tBTA_DM_MSG *p_data)
+{
+ tBTA_DM_MSG * p_msg;
+ tBTA_DM_SEARCH data;
+
+ APPL_TRACE_DEBUG0("bta_dm_inq_cmpl");
+
+ data.inq_cmpl.num_resps = p_data->inq_cmpl.num;
+ bta_dm_search_cb.p_search_cback(BTA_DM_INQ_CMPL_EVT, &data);
+
+ if((bta_dm_search_cb.p_btm_inq_info = BTM_InqDbFirst()) != NULL)
+ {
+ /* start name and service discovery from the first device on inquiry result */
+ bta_dm_search_cb.name_discover_done = FALSE;
+ bta_dm_search_cb.peer_name[0] = 0;
+ bta_dm_discover_device(bta_dm_search_cb.p_btm_inq_info->results.remote_bd_addr);
+ }
+ else
+ {
+ /* no devices, search complete */
+ bta_dm_search_cb.services = 0;
+
+ if ((p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL)
+ {
+ p_msg->hdr.event = BTA_DM_SEARCH_CMPL_EVT;
+ p_msg->hdr.layer_specific = BTA_DM_API_DISCOVER_EVT;
+ bta_sys_sendmsg(p_msg);
+ }
+ }
+ }
+
+/*******************************************************************************
+**
+** Function bta_dm_rmt_name
+**
+** Description Process the remote name result from BTM
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_rmt_name (tBTA_DM_MSG *p_data)
+{
+ APPL_TRACE_DEBUG0("bta_dm_rmt_name");
+
+ if( p_data->rem_name.result.disc_res.bd_name[0] && bta_dm_search_cb.p_btm_inq_info)
+ {
+ bta_dm_search_cb.p_btm_inq_info->appl_knows_rem_name = TRUE;
+ }
+
+ bta_dm_discover_device(bta_dm_search_cb.peer_bdaddr);
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_disc_rmt_name
+**
+** Description Process the remote name result from BTM when application
+** wants to find the name for a bdaddr
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_disc_rmt_name (tBTA_DM_MSG *p_data)
+{
+ tBTM_INQ_INFO *p_btm_inq_info;
+
+ APPL_TRACE_DEBUG0("bta_dm_disc_rmt_name");
+
+ p_btm_inq_info = BTM_InqDbRead (p_data->rem_name.result.disc_res.bd_addr);
+ if( p_btm_inq_info )
+ {
+ if( p_data->rem_name.result.disc_res.bd_name[0] )
+ {
+ p_btm_inq_info->appl_knows_rem_name = TRUE;
+ }
+ }
+
+ bta_dm_discover_device(p_data->rem_name.result.disc_res.bd_addr);
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_sdp_result
+**
+** Description Process the discovery result from sdp
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_sdp_result (tBTA_DM_MSG *p_data)
+{
+
+ tSDP_DISC_REC *p_sdp_rec = NULL;
+ tBTA_DM_MSG *p_msg;
+ BOOLEAN service_found = FALSE;
+ BOOLEAN scn_found = FALSE;
+ UINT16 service = 0xFFFF;
+ tSDP_PROTOCOL_ELEM pe;
+
+#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE
+ tBT_UUID *p_uuid = bta_dm_search_cb.p_srvc_uuid;
+ tBTA_DM_SEARCH result;
+ tBT_UUID service_uuid;
+#endif
+
+ if((p_data->sdp_event.sdp_result == SDP_SUCCESS)
+ || (p_data->sdp_event.sdp_result == SDP_NO_RECS_MATCH)
+ || (p_data->sdp_event.sdp_result == SDP_DB_FULL))
+ {
+ APPL_TRACE_DEBUG1("sdp_result::0x%x", p_data->sdp_event.sdp_result);
+ do
+ {
+
+ service_found = FALSE;
+ p_sdp_rec = NULL;
+ if( bta_dm_search_cb.service_index == (BTA_USER_SERVICE_ID+1) )
+ {
+ p_sdp_rec = SDP_FindServiceUUIDInDb(bta_dm_search_cb.p_sdp_db, &bta_dm_search_cb.uuid, p_sdp_rec);
+
+ if (p_sdp_rec && SDP_FindProtocolListElemInRec(p_sdp_rec, UUID_PROTOCOL_RFCOMM, &pe))
+ {
+ bta_dm_search_cb.peer_scn = (UINT8) pe.params[0];
+ scn_found = TRUE;
+ }
+ }
+ else
+ {
+ service = bta_service_id_to_uuid_lkup_tbl[bta_dm_search_cb.service_index-1];
+ p_sdp_rec = SDP_FindServiceInDb(bta_dm_search_cb.p_sdp_db, service, p_sdp_rec);
+ }
+
+#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE
+ /* finished with BR/EDR services, now we check the result for GATT based service UUID */
+ if (bta_dm_search_cb.service_index == BTA_MAX_SERVICE_ID)
+ {
+ if (bta_dm_search_cb.uuid_to_search != 0 && p_uuid != NULL)
+ {
+ p_uuid += (bta_dm_search_cb.num_uuid - bta_dm_search_cb.uuid_to_search);
+ /* only support 16 bits UUID for now */
+ service = p_uuid->uu.uuid16;
+
+ }
+ /* all GATT based services */
+ do
+ {
+ /* find a service record, report it */
+ p_sdp_rec = SDP_FindServiceInDb(bta_dm_search_cb.p_sdp_db,
+ 0, p_sdp_rec);
+ if (p_sdp_rec)
+ {
+ if (SDP_FindServiceUUIDInRec(p_sdp_rec, &service_uuid))
+ {
+ /* send result back to app now, one by one */
+ bdcpy (result.disc_ble_res.bd_addr, bta_dm_search_cb.peer_bdaddr);
+ BCM_STRNCPY_S((char*)result.disc_ble_res.bd_name, sizeof(BD_NAME), bta_dm_get_remname(), (BD_NAME_LEN-1));
+ result.disc_ble_res.service.len = service_uuid.len;
+ result.disc_ble_res.service.uu.uuid16 = service_uuid.uu.uuid16;
+
+ bta_dm_search_cb.p_search_cback(BTA_DM_DISC_BLE_RES_EVT, &result);
+ }
+ }
+
+ if (bta_dm_search_cb.uuid_to_search > 0)
+ break;
+
+ } while (p_sdp_rec);
+ }
+ else
+#endif
+ {
+ /* SDP_DB_FULL means some records with the
+ required attributes were received */
+ if((p_data->sdp_event.sdp_result == SDP_DB_FULL) ||
+ (p_sdp_rec != NULL))
+ {
+ /* If Plug and Play service record, check to see if Broadcom stack */
+ if (service == UUID_SERVCLASS_PNP_INFORMATION)
+ {
+ if (p_sdp_rec)
+ {
+ if (SDP_FindAttributeInRec (p_sdp_rec, ATTR_ID_EXT_BRCM_VERSION))
+ {
+ service_found = TRUE;
+ }
+ }
+ }
+ else
+ {
+ service_found = TRUE;
+ }
+
+ if (service_found)
+ {
+ bta_dm_search_cb.services_found |=
+ (tBTA_SERVICE_MASK)(BTA_SERVICE_ID_TO_SERVICE_MASK(bta_dm_search_cb.service_index-1));
+ }
+ }
+ }
+
+ if(bta_dm_search_cb.services == BTA_ALL_SERVICE_MASK &&
+ bta_dm_search_cb.services_to_search == 0)
+ {
+#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE
+ if ( bta_dm_search_cb.service_index == BTA_BLE_SERVICE_ID &&
+ bta_dm_search_cb.uuid_to_search > 0)
+ bta_dm_search_cb.uuid_to_search --;
+
+ if (bta_dm_search_cb.uuid_to_search == 0 ||
+ bta_dm_search_cb.service_index != BTA_BLE_SERVICE_ID)
+#endif
+ bta_dm_search_cb.service_index++;
+ }
+ else /* regular one service per search or PNP search */
+ break;
+
+ }
+ while(bta_dm_search_cb.service_index <= BTA_MAX_SERVICE_ID);
+
+// GKI_freebuf(bta_dm_search_cb.p_sdp_db);
+// bta_dm_search_cb.p_sdp_db = NULL;
+ APPL_TRACE_DEBUG1("bta_dm_sdp_result services_found = %04x", bta_dm_search_cb.services_found);
+
+ /* if there are more services to search for */
+ if(bta_dm_search_cb.services_to_search)
+ {
+ /* Free up the p_sdp_db before checking the next one */
+ bta_dm_free_sdp_db(NULL);
+ bta_dm_find_services(bta_dm_search_cb.peer_bdaddr);
+ }
+ else
+ {
+ /* callbacks */
+ /* start next bd_addr if necessary */
+
+ BTM_SecDeleteRmtNameNotifyCallback(&bta_dm_service_search_remname_cback);
+
+
+ if ((p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL)
+ {
+ p_msg->hdr.event = BTA_DM_DISCOVERY_RESULT_EVT;
+ p_msg->disc_result.result.disc_res.result = BTA_SUCCESS;
+ p_msg->disc_result.result.disc_res.p_raw_data = NULL;
+ p_msg->disc_result.result.disc_res.raw_data_size = 0;
+
+ //copy the raw_data to the discovery result structure
+ //
+ APPL_TRACE_DEBUG2("bta_dm_sdp_result (raw_data used = 0x%x raw_data_ptr = 0x%x)\r\n",bta_dm_search_cb.p_sdp_db->raw_used, bta_dm_search_cb.p_sdp_db->raw_data);
+
+ if ( bta_dm_search_cb.p_sdp_db != NULL && bta_dm_search_cb.p_sdp_db->raw_used != 0 &&
+ bta_dm_search_cb.p_sdp_db->raw_data != NULL) {
+
+ p_msg->disc_result.result.disc_res.p_raw_data = GKI_getbuf(bta_dm_search_cb.p_sdp_db->raw_used);
+ if ( NULL != p_msg->disc_result.result.disc_res.p_raw_data ) {
+ memcpy( p_msg->disc_result.result.disc_res.p_raw_data,
+ bta_dm_search_cb.p_sdp_db->raw_data,
+ bta_dm_search_cb.p_sdp_db->raw_used );
+
+ p_msg->disc_result.result.disc_res.raw_data_size =
+ bta_dm_search_cb.p_sdp_db->raw_used;
+
+ } else {
+ APPL_TRACE_DEBUG1("bta_dm_sdp_result GKI Alloc failed to allocate %d bytes !!\r\n",bta_dm_search_cb.p_sdp_db->raw_used);
+ printf("bta_dm_sdp_result GKI Alloc failed to allocate %d bytes !!\r\n",bta_dm_search_cb.p_sdp_db->raw_used);
+ }
+
+ bta_dm_search_cb.p_sdp_db->raw_data = NULL; //no need to free this - it is a global assigned.
+ bta_dm_search_cb.p_sdp_db->raw_used = 0;
+ bta_dm_search_cb.p_sdp_db->raw_size = 0;
+ }
+ else {
+ APPL_TRACE_DEBUG0("bta_dm_sdp_result raw data size is 0 or raw_data is null!!\r\n");
+ }
+ /* Done with p_sdp_db. Free it */
+ bta_dm_free_sdp_db(NULL);
+ p_msg->disc_result.result.disc_res.services = bta_dm_search_cb.services_found;
+
+ //Piggy back the SCN over result field
+ if( scn_found )
+ {
+ p_msg->disc_result.result.disc_res.result = (3 + bta_dm_search_cb.peer_scn);
+ p_msg->disc_result.result.disc_res.services |= BTA_USER_SERVICE_MASK;
+
+ APPL_TRACE_EVENT1(" Piggy back the SCN over result field SCN=%d", bta_dm_search_cb.peer_scn);
+
+ }
+ bdcpy (p_msg->disc_result.result.disc_res.bd_addr, bta_dm_search_cb.peer_bdaddr);
+ BCM_STRNCPY_S((char*)p_msg->disc_result.result.disc_res.bd_name, sizeof(BD_NAME),
+ bta_dm_get_remname(), (BD_NAME_LEN-1));
+
+ /* make sure the string is null terminated */
+ p_msg->disc_result.result.disc_res.bd_name[BD_NAME_LEN-1] = 0;
+
+ bta_sys_sendmsg(p_msg);
+ }
+
+ }
+
+ }
+ else
+ {
+ /* conn failed. No need for timer */
+ if(p_data->sdp_event.sdp_result == SDP_CONN_FAILED || p_data->sdp_event.sdp_result == SDP_CONN_REJECTED
+ || p_data->sdp_event.sdp_result == SDP_SECURITY_ERR)
+ bta_dm_search_cb.wait_disc = FALSE;
+
+ /* not able to connect go to next device */
+ GKI_freebuf(bta_dm_search_cb.p_sdp_db);
+ bta_dm_search_cb.p_sdp_db = NULL;
+
+ BTM_SecDeleteRmtNameNotifyCallback(&bta_dm_service_search_remname_cback);
+
+ if ((p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL)
+ {
+ p_msg->hdr.event = BTA_DM_DISCOVERY_RESULT_EVT;
+ p_msg->disc_result.result.disc_res.result = BTA_FAILURE;
+ p_msg->disc_result.result.disc_res.services = bta_dm_search_cb.services_found;
+ bdcpy (p_msg->disc_result.result.disc_res.bd_addr, bta_dm_search_cb.peer_bdaddr);
+ BCM_STRNCPY_S((char*)p_msg->disc_result.result.disc_res.bd_name, sizeof(BD_NAME),
+ bta_dm_get_remname(), (BD_NAME_LEN-1));
+
+ /* make sure the string is null terminated */
+ p_msg->disc_result.result.disc_res.bd_name[BD_NAME_LEN-1] = 0;
+
+ bta_sys_sendmsg(p_msg);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_search_cmpl
+**
+** Description Sends event to application
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_search_cmpl (tBTA_DM_MSG *p_data)
+{
+ APPL_TRACE_DEBUG0("bta_dm_search_cmpl");
+
+#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE)
+ utl_freebuf((void **)&bta_dm_search_cb.p_srvc_uuid);
+#endif
+
+ if (p_data->hdr.layer_specific == BTA_DM_API_DI_DISCOVER_EVT)
+ bta_dm_di_disc_cmpl(p_data);
+ else
+ bta_dm_search_cb.p_search_cback(BTA_DM_DISC_CMPL_EVT, NULL);
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_disc_result
+**
+** Description Service discovery result when discovering services on a device
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_disc_result (tBTA_DM_MSG *p_data)
+{
+ tBTA_DM_MSG * p_msg;
+
+ APPL_TRACE_DEBUG0("bta_dm_disc_result");
+
+#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE
+ /* if any BR/EDR service discovery has been done, report the event */
+ if ((bta_dm_search_cb.services & ((BTA_ALL_SERVICE_MASK | BTA_USER_SERVICE_MASK ) & ~BTA_BLE_SERVICE_MASK)))
+#endif
+ bta_dm_search_cb.p_search_cback(BTA_DM_DISC_RES_EVT, &p_data->disc_result.result);
+
+ /* send a message to change state */
+ if ((p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL)
+ {
+ p_msg->hdr.event = BTA_DM_SEARCH_CMPL_EVT;
+ p_msg->hdr.layer_specific = BTA_DM_API_DISCOVER_EVT;
+ bta_sys_sendmsg(p_msg);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_search_result
+**
+** Description Service discovery result while searching for devices
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_search_result (tBTA_DM_MSG *p_data)
+{
+ APPL_TRACE_DEBUG2("bta_dm_search_result searching:0x%04x, result:0x%04x",
+ bta_dm_search_cb.services,
+ p_data->disc_result.result.disc_res.services);
+
+ /* call back if application wants name discovery or found services that application is searching */
+ if (( !bta_dm_search_cb.services )
+ ||(( bta_dm_search_cb.services ) && ( p_data->disc_result.result.disc_res.services )))
+ {
+ bta_dm_search_cb.p_search_cback(BTA_DM_DISC_RES_EVT, &p_data->disc_result.result);
+ }
+
+ /* if searching did not initiate to create link */
+ if(!bta_dm_search_cb.wait_disc )
+ {
+#if ( BTM_EIR_CLIENT_INCLUDED == TRUE )
+ /* if service searching is done with EIR, don't search next device */
+ if( bta_dm_search_cb.p_btm_inq_info )
+#endif
+ bta_dm_discover_next_device();
+ }
+ else
+ {
+ /* wait until link is disconnected or timeout */
+ bta_dm_search_cb.sdp_results = TRUE;
+ bta_dm_search_cb.search_timer.p_cback = (TIMER_CBACK*)&bta_dm_search_timer_cback;
+ bta_sys_start_timer(&bta_dm_search_cb.search_timer, 0, 1000*(L2CAP_LINK_INACTIVITY_TOUT+1) );
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_search_timer_cback
+**
+** Description Called when ACL disconnect time is over
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_dm_search_timer_cback (TIMER_LIST_ENT *p_tle)
+{
+
+ APPL_TRACE_EVENT0(" bta_dm_search_timer_cback ");
+ bta_dm_search_cb.wait_disc = FALSE;
+
+ /* proceed with next device */
+ bta_dm_discover_next_device();
+
+}
+
+
+/*******************************************************************************
+**
+** Function bta_dm_free_sdp_db
+**
+** Description Frees SDP data base
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_free_sdp_db (tBTA_DM_MSG *p_data)
+{
+ if(bta_dm_search_cb.p_sdp_db)
+ {
+ GKI_freebuf(bta_dm_search_cb.p_sdp_db);
+ bta_dm_search_cb.p_sdp_db = NULL;
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_queue_search
+**
+** Description Queues search command while search is being cancelled
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_queue_search (tBTA_DM_MSG *p_data)
+{
+
+ bta_dm_search_cb.p_search_queue = (tBTA_DM_MSG *)GKI_getbuf(sizeof(tBTA_DM_API_SEARCH));
+ memcpy(bta_dm_search_cb.p_search_queue, p_data, sizeof(tBTA_DM_API_SEARCH));
+
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_queue_disc
+**
+** Description Queues discovery command while search is being cancelled
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_queue_disc (tBTA_DM_MSG *p_data)
+{
+
+ bta_dm_search_cb.p_search_queue = (tBTA_DM_MSG *)GKI_getbuf(sizeof(tBTA_DM_API_DISCOVER));
+ memcpy(bta_dm_search_cb.p_search_queue, p_data, sizeof(tBTA_DM_API_DISCOVER));
+
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_search_clear_queue
+**
+** Description Clears the queue if API search cancel is called
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_search_clear_queue (tBTA_DM_MSG *p_data)
+{
+
+ if(bta_dm_search_cb.p_search_queue)
+ {
+ GKI_freebuf(bta_dm_search_cb.p_search_queue);
+ bta_dm_search_cb.p_search_queue = NULL;
+ }
+
+
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_search_cancel_cmpl
+**
+** Description Search cancel is complete
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_search_cancel_cmpl (tBTA_DM_MSG *p_data)
+{
+
+ if(bta_dm_search_cb.p_search_queue)
+ {
+ bta_sys_sendmsg(bta_dm_search_cb.p_search_queue);
+ bta_dm_search_cb.p_search_queue = NULL;
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_search_cancel_transac_cmpl
+**
+** Description Current Service Discovery or remote name procedure is
+** completed after search cancellation
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_search_cancel_transac_cmpl(tBTA_DM_MSG *p_data)
+{
+
+ if(bta_dm_search_cb.p_sdp_db)
+ {
+ GKI_freebuf(bta_dm_search_cb.p_sdp_db);
+ bta_dm_search_cb.p_sdp_db = NULL;
+ }
+
+ bta_dm_search_cancel_notify(NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function bta_dm_search_cancel_notify
+**
+** Description Notify application that search has been cancelled
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_search_cancel_notify (tBTA_DM_MSG *p_data)
+{
+ if (bta_dm_search_cb.p_search_cback)
+ {
+ bta_dm_search_cb.p_search_cback(BTA_DM_SEARCH_CANCEL_CMPL_EVT, NULL);
+ }
+ if (!bta_dm_search_cb.name_discover_done)
+ {
+ BTM_CancelRemoteDeviceName();
+ }
+#if ((BLE_INCLUDED == TRUE) && (defined BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE))
+ if (bta_dm_search_cb.gatt_disc_active)
+ {
+ bta_dm_cancel_gatt_discovery(bta_dm_search_cb.peer_bdaddr);
+ }
+#endif
+
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_find_services
+**
+** Description Starts discovery on a device
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_dm_find_services ( BD_ADDR bd_addr)
+{
+
+ tSDP_UUID uuid;
+ UINT16 attr_list[] = {ATTR_ID_SERVICE_CLASS_ID_LIST, ATTR_ID_EXT_BRCM_VERSION};
+ UINT16 num_attrs = 1;
+ tBTA_DM_MSG *p_msg;
+
+ memset (&uuid, 0, sizeof(tSDP_UUID));
+
+ while(bta_dm_search_cb.service_index < BTA_MAX_SERVICE_ID)
+ {
+ if( bta_dm_search_cb.services_to_search
+ & (tBTA_SERVICE_MASK)(BTA_SERVICE_ID_TO_SERVICE_MASK(bta_dm_search_cb.service_index)))
+ {
+ if((bta_dm_search_cb.p_sdp_db = (tSDP_DISCOVERY_DB *)GKI_getbuf(BTA_DM_SDP_DB_SIZE)) != NULL)
+ {
+ APPL_TRACE_DEBUG1("bta_dm_search_cb.services = %04x***********", bta_dm_search_cb.services);
+ /* try to search all services by search based on L2CAP UUID */
+ if(bta_dm_search_cb.services == BTA_ALL_SERVICE_MASK )
+ {
+ APPL_TRACE_ERROR1("services_to_search = %08x",bta_dm_search_cb.services_to_search);
+ if (bta_dm_search_cb.services_to_search & BTA_RES_SERVICE_MASK)
+ {
+ uuid.uu.uuid16 = bta_service_id_to_uuid_lkup_tbl[0];
+ bta_dm_search_cb.services_to_search &= ~BTA_RES_SERVICE_MASK;
+ }
+ else
+ {
+ uuid.uu.uuid16 = UUID_PROTOCOL_L2CAP;
+ bta_dm_search_cb.services_to_search = 0;
+ }
+ }
+ else
+ {
+#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE
+ /* for LE only profile */
+ if (bta_dm_search_cb.service_index == BTA_BLE_SERVICE_ID)
+ {
+ if (bta_dm_search_cb.uuid_to_search > 0 && bta_dm_search_cb.p_srvc_uuid)
+ {
+ memcpy(&uuid,
+ (const void *)(bta_dm_search_cb.p_srvc_uuid + \
+ bta_dm_search_cb.num_uuid - bta_dm_search_cb.uuid_to_search),
+ sizeof(tBT_UUID));
+
+ bta_dm_search_cb.uuid_to_search -- ;
+ }
+ else
+ uuid.uu.uuid16 = bta_service_id_to_uuid_lkup_tbl[bta_dm_search_cb.service_index];
+
+ /* last one? clear the BLE service bit if all discovery has been done */
+ if (bta_dm_search_cb.uuid_to_search == 0)
+ bta_dm_search_cb.services_to_search &=
+ (tBTA_SERVICE_MASK)(~(BTA_SERVICE_ID_TO_SERVICE_MASK(bta_dm_search_cb.service_index)));
+
+ }
+ else
+#endif
+ {
+ /* remove the service from services to be searched */
+ bta_dm_search_cb.services_to_search &=
+ (tBTA_SERVICE_MASK)(~(BTA_SERVICE_ID_TO_SERVICE_MASK(bta_dm_search_cb.service_index)));
+ uuid.uu.uuid16 = bta_service_id_to_uuid_lkup_tbl[bta_dm_search_cb.service_index];
+ }
+ }
+
+ if (uuid.len == 0)
+ uuid.len = LEN_UUID_16;
+
+#if 0
+ if (uuid.uu.uuid16 == UUID_SERVCLASS_PNP_INFORMATION)
+ {
+ num_attrs = 2;
+ }
+#endif
+
+ if (bta_dm_search_cb.service_index == BTA_USER_SERVICE_ID)
+ {
+ memcpy(&uuid, &bta_dm_search_cb.uuid, sizeof(tSDP_UUID));
+ }
+
+
+ APPL_TRACE_ERROR1("****************search UUID = %04x***********", uuid.uu.uuid16);
+ //SDP_InitDiscoveryDb (bta_dm_search_cb.p_sdp_db, BTA_DM_SDP_DB_SIZE, 1, &uuid, num_attrs, attr_list);
+ SDP_InitDiscoveryDb (bta_dm_search_cb.p_sdp_db, BTA_DM_SDP_DB_SIZE, 1, &uuid, 0, NULL);
+
+
+ memset(g_disc_raw_data_buf, 0, sizeof(g_disc_raw_data_buf));
+ bta_dm_search_cb.p_sdp_db->raw_data = g_disc_raw_data_buf;
+
+ bta_dm_search_cb.p_sdp_db->raw_size = MAX_DISC_RAW_DATA_BUF;
+
+ if (!SDP_ServiceSearchAttributeRequest (bd_addr, bta_dm_search_cb.p_sdp_db, &bta_dm_sdp_callback))
+ {
+ /* if discovery not successful with this device
+ proceed to next one */
+ GKI_freebuf(bta_dm_search_cb.p_sdp_db);
+ bta_dm_search_cb.p_sdp_db = NULL;
+ bta_dm_search_cb.service_index = BTA_MAX_SERVICE_ID;
+
+ }
+ else
+ {
+#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE
+ if ((bta_dm_search_cb.service_index == BTA_BLE_SERVICE_ID &&
+ bta_dm_search_cb.uuid_to_search == 0) ||
+ bta_dm_search_cb.service_index != BTA_BLE_SERVICE_ID)
+#endif
+ bta_dm_search_cb.service_index++;
+ return;
+ }
+ }
+ else
+ {
+ APPL_TRACE_ERROR0("#### Failed to allocate SDP DB buffer! ####");
+ }
+ }
+
+ bta_dm_search_cb.service_index++;
+ }
+
+ /* no more services to be discovered */
+ if(bta_dm_search_cb.service_index >= BTA_MAX_SERVICE_ID)
+ {
+ if ((p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL)
+ {
+ p_msg->hdr.event = BTA_DM_DISCOVERY_RESULT_EVT;
+ p_msg->disc_result.result.disc_res.services = bta_dm_search_cb.services_found;
+ bdcpy (p_msg->disc_result.result.disc_res.bd_addr, bta_dm_search_cb.peer_bdaddr);
+ BCM_STRNCPY_S((char*)p_msg->disc_result.result.disc_res.bd_name, sizeof(BD_NAME),
+ bta_dm_get_remname(), (BD_NAME_LEN-1));
+
+ /* make sure the string is terminated */
+ p_msg->disc_result.result.disc_res.bd_name[BD_NAME_LEN-1] = 0;
+
+ bta_sys_sendmsg(p_msg);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_discover_next_device
+**
+** Description Starts discovery on the next device in Inquiry data base
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_dm_discover_next_device(void)
+{
+
+ tBTA_DM_MSG * p_msg;
+
+ APPL_TRACE_DEBUG0("bta_dm_discover_next_device");
+
+ /* searching next device on inquiry result */
+ if((bta_dm_search_cb.p_btm_inq_info = BTM_InqDbNext(bta_dm_search_cb.p_btm_inq_info)) != NULL)
+ {
+ bta_dm_search_cb.name_discover_done = FALSE;
+ bta_dm_search_cb.peer_name[0] = 0;
+ bta_dm_discover_device(bta_dm_search_cb.p_btm_inq_info->results.remote_bd_addr);
+ }
+ else
+ {
+ /* no devices, search complete */
+ bta_dm_search_cb.services = 0;
+
+ if ((p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL)
+ {
+ p_msg->hdr.event = BTA_DM_SEARCH_CMPL_EVT;
+ p_msg->hdr.layer_specific = BTA_DM_API_DISCOVER_EVT;
+ bta_sys_sendmsg(p_msg);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_discover_device
+**
+** Description Starts name and service discovery on the device
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_dm_discover_device(BD_ADDR remote_bd_addr)
+{
+ tBTA_DM_MSG * p_msg;
+
+#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE
+ tBT_DEVICE_TYPE dev_type;
+ tBLE_ADDR_TYPE addr_type;
+#endif
+
+ APPL_TRACE_DEBUG6("bta_dm_discover_device, BDA:0x%02X%02X%02X%02X%02X%02X",
+ remote_bd_addr[0],remote_bd_addr[1],
+ remote_bd_addr[2],remote_bd_addr[3],
+ remote_bd_addr[4],remote_bd_addr[5]);
+
+ bdcpy(bta_dm_search_cb.peer_bdaddr, remote_bd_addr);
+
+ APPL_TRACE_DEBUG2("bta_dm_discover_device name_discover_done = %d p_btm_inq_info 0x%x ",
+ bta_dm_search_cb.name_discover_done,
+ bta_dm_search_cb.p_btm_inq_info
+ );
+ if ( bta_dm_search_cb.p_btm_inq_info ) {
+
+ APPL_TRACE_DEBUG1("bta_dm_discover_device appl_knows_rem_name %d",
+ bta_dm_search_cb.p_btm_inq_info->appl_knows_rem_name
+ );
+ }
+
+ /* if name discovery is not done and application needs remote name */
+ if ((!bta_dm_search_cb.name_discover_done)
+ && (( bta_dm_search_cb.p_btm_inq_info == NULL )
+ ||(bta_dm_search_cb.p_btm_inq_info && (!bta_dm_search_cb.p_btm_inq_info->appl_knows_rem_name))))
+ {
+ if( bta_dm_read_remote_device_name(bta_dm_search_cb.peer_bdaddr) == TRUE )
+ {
+ return;
+ }
+ else
+ {
+ /* starting name discovery failed */
+ bta_dm_search_cb.name_discover_done = TRUE;
+ }
+ }
+
+ /* if application wants to discover service */
+ if ( bta_dm_search_cb.services )
+ {
+ /* initialize variables */
+ bta_dm_search_cb.service_index = 0;
+ bta_dm_search_cb.services_found = 0;
+ bta_dm_search_cb.services_to_search = bta_dm_search_cb.services;
+#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE
+ bta_dm_search_cb.uuid_to_search = bta_dm_search_cb.num_uuid;
+#endif
+#if ( BTM_EIR_CLIENT_INCLUDED == TRUE )
+ if ((bta_dm_search_cb.p_btm_inq_info != NULL) &&
+ bta_dm_search_cb.services != BTA_USER_SERVICE_MASK
+ &&(bta_dm_search_cb.sdp_search == FALSE))
+ {
+ /* check if EIR provides the information of supported services */
+ bta_dm_eir_search_services( &bta_dm_search_cb.p_btm_inq_info->results,
+ &bta_dm_search_cb.services_to_search,
+ &bta_dm_search_cb.services_found );
+ }
+
+ /* if seaching with EIR is not completed */
+ if(bta_dm_search_cb.services_to_search)
+#endif
+ {
+ /* check whether connection already exists to the device
+ if connection exists, we don't have to wait for ACL
+ link to go down to start search on next device */
+ if(BTM_IsAclConnectionUp(bta_dm_search_cb.peer_bdaddr))
+ bta_dm_search_cb.wait_disc = FALSE;
+ else
+ bta_dm_search_cb.wait_disc = TRUE;
+
+#if (BLE_INCLUDED == TRUE && (defined BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE))
+ if ( bta_dm_search_cb.p_btm_inq_info )
+ {
+ APPL_TRACE_DEBUG3("bta_dm_discover_device p_btm_inq_info 0x%x results.device_type 0x%x services_to_search 0x%x",
+ bta_dm_search_cb.p_btm_inq_info,
+ bta_dm_search_cb.p_btm_inq_info->results.device_type,
+ bta_dm_search_cb.services_to_search
+ );
+ }
+ BTM_ReadDevInfo(remote_bd_addr, &dev_type, &addr_type);
+
+ if (dev_type == BT_DEVICE_TYPE_BLE)
+ /*
+ if ( bta_dm_search_cb.p_btm_inq_info != NULL &&
+ bta_dm_search_cb.p_btm_inq_info->results.device_type == BT_DEVICE_TYPE_BLE &&
+ (bta_dm_search_cb.services_to_search & BTA_BLE_SERVICE_MASK))*/
+ {
+ if (bta_dm_search_cb.services_to_search & BTA_BLE_SERVICE_MASK)
+ {
+ //set the raw data buffer here
+ memset(g_disc_raw_data_buf, 0, sizeof(g_disc_raw_data_buf));
+ bta_dm_search_cb.p_ble_rawdata = g_disc_raw_data_buf;
+
+ bta_dm_search_cb.ble_raw_size = MAX_DISC_RAW_DATA_BUF;
+ bta_dm_search_cb.ble_raw_used = 0;
+
+ /* start GATT for service discovery */
+ btm_dm_start_gatt_discovery(bta_dm_search_cb.peer_bdaddr);
+ return;
+ }
+ }
+ else
+#endif
+ {
+ bta_dm_search_cb.sdp_results = FALSE;
+ bta_dm_find_services(bta_dm_search_cb.peer_bdaddr);
+
+ return;
+ }
+ }
+ }
+
+ /* name discovery and service discovery are done for this device */
+ if ((p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL)
+ {
+ p_msg->hdr.event = BTA_DM_DISCOVERY_RESULT_EVT;
+ /* initialize the data structure - includes p_raw_data and raw_data_size */
+ memset(&(p_msg->disc_result.result), 0, sizeof(tBTA_DM_DISC_RES));
+ p_msg->disc_result.result.disc_res.result = BTA_SUCCESS;
+ p_msg->disc_result.result.disc_res.services = bta_dm_search_cb.services_found;
+ bdcpy (p_msg->disc_result.result.disc_res.bd_addr, bta_dm_search_cb.peer_bdaddr);
+ BCM_STRNCPY_S((char*)p_msg->disc_result.result.disc_res.bd_name, sizeof(BD_NAME),
+ (char*)bta_dm_search_cb.peer_name, (BD_NAME_LEN-1));
+
+ /* make sure the string is terminated */
+ p_msg->disc_result.result.disc_res.bd_name[BD_NAME_LEN-1] = 0;
+
+ bta_sys_sendmsg(p_msg);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_sdp_callback
+**
+** Description Callback from sdp with discovery status
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_dm_sdp_callback (UINT16 sdp_status)
+{
+
+ tBTA_DM_SDP_RESULT * p_msg;
+
+ if ((p_msg = (tBTA_DM_SDP_RESULT *) GKI_getbuf(sizeof(tBTA_DM_SDP_RESULT))) != NULL)
+ {
+ p_msg->hdr.event = BTA_DM_SDP_RESULT_EVT;
+ p_msg->sdp_result = sdp_status;
+ bta_sys_sendmsg(p_msg);
+
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_inq_results_cb
+**
+** Description Inquiry results callback from BTM
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_dm_inq_results_cb (tBTM_INQ_RESULTS *p_inq, UINT8 *p_eir)
+{
+
+ tBTA_DM_SEARCH result;
+ tBTM_INQ_INFO *p_inq_info;
+ UINT16 service_class;
+
+ bdcpy(result.inq_res.bd_addr, p_inq->remote_bd_addr);
+ memcpy(result.inq_res.dev_class, p_inq->dev_class, DEV_CLASS_LEN);
+ BTM_COD_SERVICE_CLASS(service_class, p_inq->dev_class);
+ result.inq_res.is_limited = (service_class & BTM_COD_SERVICE_LMTD_DISCOVER)?TRUE:FALSE;
+ result.inq_res.rssi = p_inq->rssi;
+
+#if (BLE_INCLUDED == TRUE)
+ result.inq_res.ble_addr_type = p_inq->ble_addr_type;
+ result.inq_res.inq_result_type = p_inq->inq_result_type;
+ result.inq_res.device_type = p_inq->device_type;
+
+#endif
+
+ /* application will parse EIR to find out remote device name */
+ result.inq_res.p_eir = p_eir;
+
+ if((p_inq_info = BTM_InqDbRead(p_inq->remote_bd_addr)) != NULL)
+ {
+ /* initialize remt_name_not_required to FALSE so that we get the name by default */
+ result.inq_res.remt_name_not_required = FALSE;
+
+ }
+
+ if(bta_dm_search_cb.p_search_cback)
+ bta_dm_search_cb.p_search_cback(BTA_DM_INQ_RES_EVT, &result);
+
+ if(p_inq_info)
+ {
+ /* application indicates if it knows the remote name, inside the callback
+ copy that to the inquiry data base*/
+ if(result.inq_res.remt_name_not_required)
+ p_inq_info->appl_knows_rem_name = TRUE;
+
+ }
+
+
+}
+
+
+/*******************************************************************************
+**
+** Function bta_dm_inq_cmpl_cb
+**
+** Description Inquiry complete callback from BTM
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_dm_inq_cmpl_cb (void * p_result)
+{
+
+ tBTA_DM_MSG * p_msg;
+
+ APPL_TRACE_DEBUG0("bta_dm_inq_cmpl_cb");
+ if ((p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL)
+ {
+ p_msg->inq_cmpl.hdr.event = BTA_DM_INQUIRY_CMPL_EVT;
+ p_msg->inq_cmpl.num = ((tBTM_INQUIRY_CMPL *)p_result)->num_resp;
+ bta_sys_sendmsg(p_msg);
+
+ }
+
+
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_service_search_remname_cback
+**
+** Description Remote name call back from BTM during service discovery
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_dm_service_search_remname_cback (BD_ADDR bd_addr, DEV_CLASS dc, BD_NAME bd_name)
+{
+ tBTM_REMOTE_DEV_NAME rem_name;
+ tBTM_STATUS btm_status;
+
+ APPL_TRACE_DEBUG1("bta_dm_service_search_remname_cback name=<%s>", bd_name);
+
+ /* if this is what we are looking for */
+ if (!bdcmp( bta_dm_search_cb.peer_bdaddr, bd_addr))
+ {
+ rem_name.length = strlen((char*)bd_name);
+ if (rem_name.length > (BD_NAME_LEN-1))
+ {
+ rem_name.length = (BD_NAME_LEN-1);
+ rem_name.remote_bd_name[(BD_NAME_LEN-1)] = 0;
+ }
+ BCM_STRNCPY_S((char*)rem_name.remote_bd_name, sizeof(BD_NAME), (char*)bd_name, (BD_NAME_LEN-1));
+ rem_name.status = BTM_SUCCESS;
+
+ bta_dm_remname_cback(&rem_name);
+ }
+ else
+ {
+ /* get name of device */
+ btm_status = BTM_ReadRemoteDeviceName (bta_dm_search_cb.peer_bdaddr,
+ (tBTM_CMPL_CB *) bta_dm_remname_cback);
+ if ( btm_status == BTM_BUSY )
+ {
+ /* wait for next chance(notification of remote name discovery done) */
+ APPL_TRACE_DEBUG0("bta_dm_service_search_remname_cback: BTM_ReadRemoteDeviceName is busy");
+ }
+ else if ( btm_status != BTM_CMD_STARTED )
+ {
+ /* if failed to start getting remote name then continue */
+ APPL_TRACE_WARNING1("bta_dm_service_search_remname_cback: BTM_ReadRemoteDeviceName returns 0x%02X", btm_status);
+
+ rem_name.length = 0;
+ rem_name.remote_bd_name[0] = 0;
+ rem_name.status = btm_status;
+ bta_dm_remname_cback(&rem_name);
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function bta_dm_remname_cback
+**
+** Description Remote name complete call back from BTM
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_dm_remname_cback (tBTM_REMOTE_DEV_NAME *p_remote_name)
+{
+ tBTA_DM_REM_NAME * p_msg;
+
+ APPL_TRACE_DEBUG1("bta_dm_remname_cback name=<%s>", p_remote_name->remote_bd_name);
+
+ /* remote name discovery is done but it could be failed */
+ bta_dm_search_cb.name_discover_done = TRUE;
+ BCM_STRNCPY_S((char*)bta_dm_search_cb.peer_name, sizeof(BD_NAME), (char*)p_remote_name->remote_bd_name, (BD_NAME_LEN-1));
+ bta_dm_search_cb.peer_name[BD_NAME_LEN-1]=0;
+
+ BTM_SecDeleteRmtNameNotifyCallback(&bta_dm_service_search_remname_cback);
+
+ if ((p_msg = (tBTA_DM_REM_NAME *) GKI_getbuf(sizeof(tBTA_DM_REM_NAME))) != NULL)
+ {
+ bdcpy (p_msg->result.disc_res.bd_addr, bta_dm_search_cb.peer_bdaddr);
+ BCM_STRNCPY_S((char*)p_msg->result.disc_res.bd_name, sizeof(BD_NAME), (char*)p_remote_name->remote_bd_name, (BD_NAME_LEN-1));
+
+ /* make sure the string is null terminated */
+ p_msg->result.disc_res.bd_name[BD_NAME_LEN-1] = 0;
+
+ p_msg->hdr.event = BTA_DM_REMT_NAME_EVT;
+ bta_sys_sendmsg(p_msg);
+
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_authorize_cback
+**
+** Description cback requesting authorization
+**
+** Returns void
+**
+*******************************************************************************/
+static UINT8 bta_dm_authorize_cback (BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NAME bd_name,
+ UINT8 *service_name, UINT8 service_id, BOOLEAN is_originator)
+{
+ tBTA_DM_SEC sec_event;
+ UINT8 index = 1;
+
+ bdcpy(sec_event.authorize.bd_addr, bd_addr);
+ memcpy(sec_event.authorize.dev_class, dev_class, DEV_CLASS_LEN);
+
+ BCM_STRNCPY_S((char*)sec_event.authorize.bd_name, sizeof(BD_NAME), (char*)bd_name, (BD_NAME_LEN-1));
+
+ /* make sure the string is null terminated */
+ sec_event.authorize.bd_name[BD_NAME_LEN-1] = 0;
+
+#if ( defined(BTA_JV_INCLUDED) && BTA_JV_INCLUDED == TRUE )
+ sec_event.authorize.service = service_id;
+#endif
+
+ while(index < BTA_MAX_SERVICE_ID)
+ {
+ /* get the BTA service id corresponding to BTM id */
+ if(bta_service_id_to_btm_srv_id_lkup_tbl[index] == service_id)
+ {
+ sec_event.authorize.service = index;
+ break;
+ }
+ index++;
+ }
+
+
+ /* if supported service callback otherwise not authorized */
+ if(bta_dm_cb.p_sec_cback && (index < BTA_MAX_SERVICE_ID
+#if ( defined(BTA_JV_INCLUDED) && BTA_JV_INCLUDED == TRUE )
+ /* pass through JV service ID */
+ || (service_id >= BTA_FIRST_JV_SERVICE_ID && service_id <= BTA_LAST_JV_SERVICE_ID)
+#endif
+ ))
+ {
+ bta_dm_cb.p_sec_cback(BTA_DM_AUTHORIZE_EVT, &sec_event);
+ return BTM_CMD_STARTED;
+ }
+ else
+ {
+ return BTM_NOT_AUTHORIZED;
+ }
+}
+
+
+
+
+
+/*******************************************************************************
+**
+** Function bta_dm_pinname_cback
+**
+** Description Callback requesting pin_key
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_dm_pinname_cback (void *p_data)
+{
+ tBTM_REMOTE_DEV_NAME *p_result = (tBTM_REMOTE_DEV_NAME *)p_data;
+ tBTA_DM_SEC sec_event;
+ UINT32 bytes_to_copy;
+ tBTA_DM_SEC_EVT event = bta_dm_cb.pin_evt;
+
+ if (BTA_DM_SP_CFM_REQ_EVT == event)
+ {
+ /* Retrieved saved device class and bd_addr */
+ bdcpy(sec_event.cfm_req.bd_addr, bta_dm_cb.pin_bd_addr);
+ BTA_COPY_DEVICE_CLASS(sec_event.cfm_req.dev_class, bta_dm_cb.pin_dev_class);
+
+ if (p_result && p_result->status == BTM_SUCCESS)
+ {
+ bytes_to_copy = (p_result->length < (BD_NAME_LEN-1))
+ ? p_result->length : (BD_NAME_LEN-1);
+ memcpy(sec_event.cfm_req.bd_name, p_result->remote_bd_name, bytes_to_copy);
+ sec_event.pin_req.bd_name[BD_NAME_LEN-1] = 0;
+ }
+ else /* No name found */
+ sec_event.cfm_req.bd_name[0] = 0;
+
+ sec_event.key_notif.passkey = bta_dm_cb.num_val; /* get PIN code numeric number */
+
+ /* 1 additional event data fields for this event */
+ sec_event.cfm_req.just_works = bta_dm_cb.just_works;
+ }
+ else
+ {
+ /* Retrieved saved device class and bd_addr */
+ bdcpy(sec_event.pin_req.bd_addr, bta_dm_cb.pin_bd_addr);
+ BTA_COPY_DEVICE_CLASS(sec_event.pin_req.dev_class, bta_dm_cb.pin_dev_class);
+
+ if (p_result && p_result->status == BTM_SUCCESS)
+ {
+ bytes_to_copy = (p_result->length < (BD_NAME_LEN-1))
+ ? p_result->length : (BD_NAME_LEN-1);
+ memcpy(sec_event.pin_req.bd_name, p_result->remote_bd_name, bytes_to_copy);
+ sec_event.pin_req.bd_name[BD_NAME_LEN-1] = 0;
+ }
+ else /* No name found */
+ sec_event.pin_req.bd_name[0] = 0;
+
+ event = bta_dm_cb.pin_evt;
+ sec_event.key_notif.passkey = bta_dm_cb.num_val; /* get PIN code numeric number */
+ }
+
+ if( bta_dm_cb.p_sec_cback )
+ bta_dm_cb.p_sec_cback(event, &sec_event);
+}
+
+
+
+/*******************************************************************************
+**
+** Function bta_dm_pin_cback
+**
+** Description Callback requesting pin_key
+**
+** Returns void
+**
+*******************************************************************************/
+static UINT8 bta_dm_pin_cback (BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NAME bd_name)
+{
+ tBTA_DM_SEC sec_event;
+
+ if (!bta_dm_cb.p_sec_cback)
+ return BTM_NOT_AUTHORIZED;
+
+ /* If the device name is not known, save bdaddr and devclass and initiate a name request */
+ if (bd_name[0] == 0)
+ {
+ bta_dm_cb.pin_evt = BTA_DM_PIN_REQ_EVT;
+ bdcpy(bta_dm_cb.pin_bd_addr, bd_addr);
+ BTA_COPY_DEVICE_CLASS(bta_dm_cb.pin_dev_class, dev_class);
+ if ((BTM_ReadRemoteDeviceName(bd_addr, bta_dm_pinname_cback)) == BTM_CMD_STARTED)
+ return BTM_CMD_STARTED;
+
+ APPL_TRACE_WARNING0(" bta_dm_pin_cback() -> Failed to start Remote Name Request ");
+ }
+
+ bdcpy(sec_event.pin_req.bd_addr, bd_addr);
+ BTA_COPY_DEVICE_CLASS(sec_event.pin_req.dev_class, dev_class);
+ BCM_STRNCPY_S((char*)sec_event.pin_req.bd_name, sizeof(BD_NAME), (char*)bd_name, (BD_NAME_LEN-1));
+ sec_event.pin_req.bd_name[BD_NAME_LEN-1] = 0;
+
+ bta_dm_cb.p_sec_cback(BTA_DM_PIN_REQ_EVT, &sec_event);
+ return BTM_CMD_STARTED;
+}
+
+
+
+/*******************************************************************************
+**
+** Function bta_dm_link_key_request_cback
+**
+** Description Callback requesting linkkey
+**
+** Returns void
+**
+*******************************************************************************/
+static UINT8 bta_dm_link_key_request_cback (BD_ADDR bd_addr, LINK_KEY key)
+{
+ /* Application passes all link key to
+ BTM during initialization using add_device
+ API. If BTM doesn't have the link key in it's
+ data base, that's because application doesn't
+ it */
+
+ return BTM_NOT_AUTHORIZED;
+}
+
+
+
+
+
+/*******************************************************************************
+**
+** Function bta_dm_new_link_key_cback
+**
+** Description Callback from BTM to notify new link key
+**
+** Returns void
+**
+*******************************************************************************/
+static UINT8 bta_dm_new_link_key_cback(BD_ADDR bd_addr, DEV_CLASS dev_class,
+ BD_NAME bd_name, LINK_KEY key, UINT8 key_type)
+{
+ tBTA_DM_SEC sec_event;
+ tBTA_DM_AUTH_CMPL *p_auth_cmpl;
+ UINT8 event;
+
+ memset (&sec_event, 0, sizeof(tBTA_DM_SEC));
+
+ /* Not AMP Key type */
+ if (key_type != HCI_LKEY_TYPE_AMP_WIFI && key_type != HCI_LKEY_TYPE_AMP_UWB)
+ {
+ event = BTA_DM_AUTH_CMPL_EVT;
+ p_auth_cmpl = &sec_event.auth_cmpl;
+
+ bdcpy(p_auth_cmpl->bd_addr, bd_addr);
+
+ memcpy(p_auth_cmpl->bd_name, bd_name, (BD_NAME_LEN-1));
+ p_auth_cmpl->bd_name[BD_NAME_LEN-1] = 0;
+
+ p_auth_cmpl->key_present = TRUE;
+ p_auth_cmpl->key_type = key_type;
+ p_auth_cmpl->success = TRUE;
+
+ memcpy(p_auth_cmpl->key, key, LINK_KEY_LEN);
+ sec_event.auth_cmpl.fail_reason = HCI_SUCCESS;
+
+ if(bta_dm_cb.p_sec_cback)
+ {
+ bta_dm_cb.p_sec_cback(event, &sec_event);
+ }
+ }
+ else
+ {
+ APPL_TRACE_WARNING0(" bta_dm_new_link_key_cback() Received AMP Key?? ");
+ }
+
+ return BTM_CMD_STARTED;
+}
+
+
+/*******************************************************************************
+**
+** Function bta_dm_authentication_complete_cback
+**
+** Description Authentication complete callback from BTM
+**
+** Returns void
+**
+*******************************************************************************/
+static UINT8 bta_dm_authentication_complete_cback(BD_ADDR bd_addr, DEV_CLASS dev_class,BD_NAME bd_name, int result)
+{
+
+ tBTA_DM_SEC sec_event;
+
+ if(result != BTM_SUCCESS)
+ {
+ memset(&sec_event, 0, sizeof(tBTA_DM_SEC));
+ bdcpy(sec_event.auth_cmpl.bd_addr, bd_addr);
+
+ memcpy(sec_event.auth_cmpl.bd_name, bd_name, (BD_NAME_LEN-1));
+ sec_event.auth_cmpl.bd_name[BD_NAME_LEN-1] = 0;
+
+/* taken care of by memset [above]
+ sec_event.auth_cmpl.key_present = FALSE;
+ sec_event.auth_cmpl.success = FALSE;
+*/
+ sec_event.auth_cmpl.fail_reason = (UINT8)result;
+ if(bta_dm_cb.p_sec_cback)
+ {
+ bta_dm_cb.p_sec_cback(BTA_DM_AUTH_CMPL_EVT, &sec_event);
+ }
+ }
+
+ return BTM_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_sp_cback
+**
+** Description simple pairing callback from BTM
+**
+** Returns void
+**
+*******************************************************************************/
+static UINT8 bta_dm_sp_cback (tBTM_SP_EVT event, tBTM_SP_EVT_DATA *p_data)
+{
+ tBTM_STATUS status = BTM_CMD_STARTED;
+ tBTA_DM_SEC sec_event;
+ tBTA_DM_SEC_EVT pin_evt = BTA_DM_SP_KEY_NOTIF_EVT;
+
+ APPL_TRACE_EVENT1("bta_dm_sp_cback: %d", event);
+ if (!bta_dm_cb.p_sec_cback)
+ return BTM_NOT_AUTHORIZED;
+
+ /* TODO_SP */
+ switch(event)
+ {
+ case BTM_SP_IO_REQ_EVT:
+#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
+ /* translate auth_req */
+ bta_dm_co_io_req(p_data->io_req.bd_addr, &p_data->io_req.io_cap,
+ &p_data->io_req.oob_data, &p_data->io_req.auth_req, p_data->io_req.is_orig);
+#endif
+#if BTM_OOB_INCLUDED == FALSE
+ status = BTM_SUCCESS;
+#endif
+
+ APPL_TRACE_EVENT2("io mitm: %d oob_data:%d", p_data->io_req.auth_req, p_data->io_req.oob_data);
+ break;
+ case BTM_SP_IO_RSP_EVT:
+#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
+ bta_dm_co_io_rsp(p_data->io_rsp.bd_addr, p_data->io_rsp.io_cap,
+ p_data->io_rsp.oob_data, p_data->io_rsp.auth_req );
+#endif
+ break;
+
+ case BTM_SP_CFM_REQ_EVT:
+ pin_evt = BTA_DM_SP_CFM_REQ_EVT;
+ bta_dm_cb.just_works = sec_event.cfm_req.just_works = p_data->cfm_req.just_works;
+ sec_event.cfm_req.loc_auth_req = p_data->cfm_req.loc_auth_req;
+ sec_event.cfm_req.rmt_auth_req = p_data->cfm_req.rmt_auth_req;
+ /* continue to next case */
+#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
+ /* Passkey entry mode, mobile device with output capability is very
+ unlikely to receive key request, so skip this event */
+ /*case BTM_SP_KEY_REQ_EVT: */
+ case BTM_SP_KEY_NOTIF_EVT:
+#endif
+ bta_dm_cb.num_val = sec_event.key_notif.passkey = p_data->key_notif.passkey;
+ /* If the device name is not known, save bdaddr and devclass and initiate a name request */
+ if (p_data->key_notif.bd_name[0] == 0)
+ {
+ bta_dm_cb.pin_evt = pin_evt;
+ bdcpy(bta_dm_cb.pin_bd_addr, p_data->key_notif.bd_addr);
+ BTA_COPY_DEVICE_CLASS(bta_dm_cb.pin_dev_class, p_data->key_notif.dev_class);
+ if ((BTM_ReadRemoteDeviceName(p_data->key_notif.bd_addr, bta_dm_pinname_cback)) == BTM_CMD_STARTED)
+ return BTM_CMD_STARTED;
+
+ APPL_TRACE_WARNING0(" bta_dm_sp_cback() -> Failed to start Remote Name Request ");
+ }
+ bdcpy(sec_event.key_notif.bd_addr, p_data->key_notif.bd_addr);
+ BTA_COPY_DEVICE_CLASS(sec_event.key_notif.dev_class, p_data->key_notif.dev_class);
+ BCM_STRNCPY_S((char*)sec_event.key_notif.bd_name, sizeof(BD_NAME), (char*)p_data->key_notif.bd_name, (BD_NAME_LEN-1));
+ sec_event.key_notif.bd_name[BD_NAME_LEN-1] = 0;
+
+ bta_dm_cb.p_sec_cback(pin_evt, &sec_event);
+
+ break;
+
+#if BTM_OOB_INCLUDED == TRUE
+ case BTM_SP_LOC_OOB_EVT:
+ bta_dm_co_loc_oob((BOOLEAN)(p_data->loc_oob.status == BTM_SUCCESS),
+ p_data->loc_oob.c, p_data->loc_oob.r);
+ break;
+
+ case BTM_SP_RMT_OOB_EVT:
+ /* If the device name is not known, save bdaddr and devclass and initiate a name request */
+ if (p_data->rmt_oob.bd_name[0] == 0)
+ {
+ bta_dm_cb.pin_evt = BTA_DM_SP_RMT_OOB_EVT;
+ bdcpy(bta_dm_cb.pin_bd_addr, p_data->rmt_oob.bd_addr);
+ BTA_COPY_DEVICE_CLASS(bta_dm_cb.pin_dev_class, p_data->rmt_oob.dev_class);
+ if ((BTM_ReadRemoteDeviceName(p_data->rmt_oob.bd_addr, bta_dm_pinname_cback)) == BTM_CMD_STARTED)
+ return BTM_CMD_STARTED;
+
+ APPL_TRACE_WARNING0(" bta_dm_sp_cback() -> Failed to start Remote Name Request ");
+ }
+ bdcpy(sec_event.rmt_oob.bd_addr, p_data->rmt_oob.bd_addr);
+ BTA_COPY_DEVICE_CLASS(sec_event.rmt_oob.dev_class, p_data->rmt_oob.dev_class);
+ BCM_STRNCPY_S((char*)sec_event.rmt_oob.bd_name, sizeof(BD_NAME), (char*)p_data->rmt_oob.bd_name, (BD_NAME_LEN-1));
+ sec_event.rmt_oob.bd_name[BD_NAME_LEN-1] = 0;
+
+ bta_dm_cb.p_sec_cback(BTA_DM_SP_RMT_OOB_EVT, &sec_event);
+
+ bta_dm_co_rmt_oob(p_data->rmt_oob.bd_addr);
+ break;
+#endif
+ case BTM_SP_COMPLT_EVT:
+ /* do not report this event - handled by link_key_callback or auth_complete_callback */
+ break;
+
+ case BTM_SP_KEYPRESS_EVT:
+ memcpy(&sec_event.key_press, &p_data->key_press, sizeof(tBTM_SP_KEYPRESS));
+ bta_dm_cb.p_sec_cback(BTA_DM_SP_KEYPRESS_EVT, &sec_event);
+ break;
+
+ case BTM_SP_UPGRADE_EVT:
+ bta_dm_co_lk_upgrade(p_data->upgrade.bd_addr, &p_data->upgrade.upgrade );
+ break;
+
+ default:
+ status = BTM_NOT_AUTHORIZED;
+ break;
+ }
+ APPL_TRACE_EVENT1("dm status: %d", status);
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_local_name_cback
+**
+** Description Callback from btm after local name is read
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_dm_local_name_cback(UINT8 *p_name)
+{
+ tBTA_DM_ENABLE enable_event;
+
+ BTM_GetLocalDeviceAddr(enable_event.bd_addr);
+ enable_event.status = BTA_SUCCESS;
+
+ if(bta_dm_cb.p_sec_cback)
+ bta_dm_cb.p_sec_cback(BTA_DM_ENABLE_EVT, (tBTA_DM_SEC *)&enable_event);
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_signal_strength
+**
+** Description Callback from btm after local bdaddr is read
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_signal_strength(tBTA_DM_MSG *p_data)
+{
+
+ if(p_data->sig_strength.start)
+ {
+ bta_dm_cb.signal_strength_mask = p_data->sig_strength.mask;
+ bta_dm_cb.signal_strength_period = p_data->sig_strength.period;
+ bta_dm_signal_strength_timer_cback(NULL);
+ }
+ else
+ {
+ bta_sys_stop_timer(&bta_dm_cb.signal_strength_timer);
+ }
+
+}
+/*******************************************************************************
+**
+** Function bta_dm_signal_strength_timer_cback
+**
+** Description Periodic timer callback to read signal strength
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_dm_signal_strength_timer_cback (TIMER_LIST_ENT *p_tle)
+{
+
+ UINT8 i;
+
+ if(bta_dm_cb.signal_strength_mask & BTA_SIG_STRENGTH_RSSI_MASK)
+ {
+ for(i=0; i<bta_dm_cb.device_list.count; i++)
+ {
+ BTM_ReadRSSI (bta_dm_cb.device_list.peer_device[i].peer_bdaddr, (tBTM_CMPL_CB *)bta_dm_rssi_cback);
+
+ }
+ }
+ if(bta_dm_cb.signal_strength_mask & BTA_SIG_STRENGTH_LINK_QUALITY_MASK)
+ {
+
+ for(i=0; i<bta_dm_cb.device_list.count; i++)
+ {
+ BTM_ReadLinkQuality (bta_dm_cb.device_list.peer_device[i].peer_bdaddr, (tBTM_CMPL_CB *)bta_dm_link_quality_cback);
+ }
+
+ }
+
+ if(bta_dm_cb.signal_strength_period)
+ {
+ bta_dm_cb.signal_strength_timer.p_cback = (TIMER_CBACK*)&bta_dm_signal_strength_timer_cback;
+ bta_sys_start_timer(&bta_dm_cb.signal_strength_timer, 0, (UINT32)1000*bta_dm_cb.signal_strength_period);
+ }
+}
+
+
+#if (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function bta_dm_bl_change_cback
+**
+** Description Callback from btm when acl connection goes up or down
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_dm_bl_change_cback (tBTM_BL_EVENT_DATA *p_data)
+{
+
+ tBTA_DM_ACL_CHANGE * p_msg;
+
+ if ((p_msg = (tBTA_DM_ACL_CHANGE *) GKI_getbuf(sizeof(tBTA_DM_ACL_CHANGE))) != NULL)
+ {
+ p_msg->event = p_data->event;
+ p_msg->is_new = FALSE;
+
+ switch(p_msg->event)
+ {
+ case BTM_BL_CONN_EVT:
+ p_msg->is_new = TRUE;
+ bdcpy(p_msg->bd_addr, p_data->conn.p_bda);
+ break;
+ case BTM_BL_DISCN_EVT:
+ bdcpy(p_msg->bd_addr, p_data->discn.p_bda);
+ break;
+ case BTM_BL_UPDATE_EVT:
+ p_msg->busy_level = p_data->update.busy_level;
+ break;
+ case BTM_BL_ROLE_CHG_EVT:
+ p_msg->new_role = p_data->role_chg.new_role;
+ p_msg->hci_status = p_data->role_chg.hci_status;
+ bdcpy(p_msg->bd_addr, p_data->role_chg.p_bda);
+ break;
+ case BTM_BL_COLLISION_EVT:
+ bdcpy(p_msg->bd_addr, p_data->conn.p_bda);
+ break;;
+ }
+
+ p_msg->hdr.event = BTA_DM_ACL_CHANGE_EVT;
+ bta_sys_sendmsg(p_msg);
+
+ }
+
+}
+#else
+
+/*******************************************************************************
+**
+** Function bta_dm_acl_change_cback
+**
+** Description Callback from btm when acl connection goes up or down
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_dm_acl_change_cback (BD_ADDR p_bda, DEV_CLASS p_dc, BD_NAME p_bdn,
+ BD_FEATURES features, BOOLEAN is_new)
+{
+
+ tBTA_DM_ACL_CHANGE * p_msg;
+
+ if ((p_msg = (tBTA_DM_ACL_CHANGE *) GKI_getbuf(sizeof(tBTA_DM_ACL_CHANGE))) != NULL)
+ {
+ bdcpy (p_msg->bd_addr, p_bda);
+ p_msg->is_new = is_new;
+
+ /* This is collision case */
+ if (features != NULL)
+ {
+ if ((features[0] == 0xFF) && !is_new)
+ p_msg->event = BTM_BL_COLLISION_EVT;
+ }
+
+ p_msg->hdr.event = BTA_DM_ACL_CHANGE_EVT;
+ bta_sys_sendmsg(p_msg);
+
+ }
+
+}
+#endif
+/*******************************************************************************
+**
+** Function bta_dm_rs_cback
+**
+** Description Receives the role switch complete event
+**
+** Returns
+**
+*******************************************************************************/
+static void bta_dm_rs_cback (tBTM_ROLE_SWITCH_CMPL *p1)
+{
+ APPL_TRACE_WARNING1("bta_dm_rs_cback:%d", bta_dm_cb.rs_event);
+ if(bta_dm_cb.rs_event == BTA_DM_API_SEARCH_EVT)
+ {
+ bta_dm_cb.search_msg.rs_res = BTA_DM_RS_OK; /* do not care about the result for now */
+ bta_dm_cb.rs_event = 0;
+ bta_dm_search_start((tBTA_DM_MSG *)&bta_dm_cb.search_msg);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_check_av
+**
+** Description This function checks if AV is active
+** if yes, make sure the AV link is master
+**
+** Returns BOOLEAN - TRUE, if switch is in progress
+**
+*******************************************************************************/
+static BOOLEAN bta_dm_check_av(UINT16 event)
+{
+ BOOLEAN switching = FALSE;
+ UINT8 i;
+ tBTA_DM_PEER_DEVICE *p_dev;
+
+ APPL_TRACE_WARNING1("bta_dm_check_av:%d", bta_dm_cb.cur_av_count);
+ if(bta_dm_cb.cur_av_count)
+ {
+ for(i=0; i<bta_dm_cb.device_list.count; i++)
+ {
+ p_dev = &bta_dm_cb.device_list.peer_device[i];
+ APPL_TRACE_WARNING3("[%d]: state:%d, info:x%x", i, p_dev->conn_state, p_dev->info);
+ if((p_dev->conn_state == BTA_DM_CONNECTED) && (p_dev->info & BTA_DM_DI_AV_ACTIVE))
+ {
+ /* make master and take away the role switch policy */
+ if(BTM_CMD_STARTED == BTM_SwitchRole (p_dev->peer_bdaddr, HCI_ROLE_MASTER, (tBTM_CMPL_CB *)bta_dm_rs_cback))
+ {
+ /* the role switch command is actually sent */
+ bta_dm_cb.rs_event = event;
+ switching = TRUE;
+ }
+ /* else either already master or can not switch for some reasons */
+ bta_dm_policy_cback(BTA_SYS_PLCY_CLR, 0, HCI_ENABLE_MASTER_SLAVE_SWITCH, p_dev->peer_bdaddr);
+ break;
+ }
+ }
+ }
+ return switching;
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_acl_change
+**
+** Description Process BTA_DM_ACL_CHANGE_EVT
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_acl_change(tBTA_DM_MSG *p_data)
+{
+
+ UINT8 i;
+ UINT8 *p;
+ tBTA_DM_SEC conn;
+ BOOLEAN is_new = p_data->acl_change.is_new;
+ BD_ADDR_PTR p_bda = p_data->acl_change.bd_addr;
+ BOOLEAN need_policy_change = FALSE;
+
+#if (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE)
+ tBTA_DM_PEER_DEVICE *p_dev;
+
+ switch(p_data->acl_change.event)
+ {
+ case BTM_BL_UPDATE_EVT: /* busy level update */
+ if( bta_dm_cb.p_sec_cback )
+ bta_dm_cb.p_sec_cback(BTA_DM_BUSY_LEVEL_EVT, (tBTA_DM_SEC *)&p_data->acl_change.busy_level);
+ return;
+
+ case BTM_BL_ROLE_CHG_EVT: /* role change event */
+ p_dev = bta_dm_find_peer_device(p_bda);
+ if(p_dev)
+ {
+ APPL_TRACE_DEBUG3("bta_dm_acl_change role chg info:x%x new_role:%d dev count:%d",
+ p_dev->info, p_data->acl_change.new_role, bta_dm_cb.device_list.count);
+ if(p_dev->info & BTA_DM_DI_AV_ACTIVE)
+ {
+ /* there's AV activity on this link */
+ if(p_data->acl_change.new_role == HCI_ROLE_SLAVE && bta_dm_cb.device_list.count > 1
+ && p_data->acl_change.hci_status == HCI_SUCCESS)
+ {
+ /* more than one connections and the AV connection is role switched to slave
+ * switch it back to master and remove the switch policy */
+ BTM_SwitchRole(p_bda, BTM_ROLE_MASTER, NULL);
+ need_policy_change = TRUE;
+ }
+ else if (bta_dm_cfg.avoid_scatter && (p_data->acl_change.new_role == HCI_ROLE_MASTER))
+ {
+ /* if the link updated to be master include AV activities, remove the switch policy */
+ need_policy_change = TRUE;
+ }
+
+ if(need_policy_change)
+ {
+ bta_dm_policy_cback(BTA_SYS_PLCY_CLR, 0, HCI_ENABLE_MASTER_SLAVE_SWITCH, p_dev->peer_bdaddr);
+ }
+ }
+ else
+ {
+ /* there's AV no activity on this link and role switch happened
+ * check if AV is active
+ * if so, make sure the AV link is master */
+ bta_dm_check_av(0);
+ }
+ bta_sys_notify_role_chg(p_data->acl_change.bd_addr, p_data->acl_change.new_role, p_data->acl_change.hci_status);
+ bdcpy(conn.role_chg.bd_addr, p_bda);
+ conn.role_chg.new_role = (UINT8) p_data->acl_change.new_role;
+ if( bta_dm_cb.p_sec_cback )
+ bta_dm_cb.p_sec_cback(BTA_DM_ROLE_CHG_EVT, (tBTA_DM_SEC *)&conn);
+ }
+ return;
+ }
+#endif
+
+ /* Collision report from Stack: Notify profiles */
+ if (p_data->acl_change.event == BTM_BL_COLLISION_EVT)
+ {
+ bta_sys_notify_collision (p_bda);
+ return;
+ }
+
+ if(is_new)
+ {
+ for(i=0; i<bta_dm_cb.device_list.count; i++)
+ {
+ if(!bdcmp( bta_dm_cb.device_list.peer_device[i].peer_bdaddr, p_bda))
+ break;
+
+ }
+
+ if(i == bta_dm_cb.device_list.count)
+ {
+ bdcpy(bta_dm_cb.device_list.peer_device[bta_dm_cb.device_list.count].peer_bdaddr, p_bda);
+ bta_dm_cb.device_list.peer_device[bta_dm_cb.device_list.count].link_policy = bta_dm_cb.cur_policy;
+ bta_dm_cb.device_list.count++;
+ }
+
+ bta_dm_cb.device_list.peer_device[i].conn_state = BTA_DM_CONNECTED;
+ bta_dm_cb.device_list.peer_device[i].pref_role = BTA_ANY_ROLE;
+ bdcpy(conn.link_up.bd_addr, p_bda);
+ bta_dm_cb.device_list.peer_device[i].info = BTA_DM_DI_NONE;
+ if( ((NULL != (p = BTM_ReadLocalFeatures ())) && HCI_SNIFF_SUB_RATE_SUPPORTED(p)) &&
+ ((NULL != (p = BTM_ReadRemoteFeatures (p_bda))) && HCI_SNIFF_SUB_RATE_SUPPORTED(p)) )
+ {
+ /* both local and remote devices support SSR */
+ bta_dm_cb.device_list.peer_device[i].info = BTA_DM_DI_USE_SSR;
+ }
+ APPL_TRACE_WARNING1("info:x%x", bta_dm_cb.device_list.peer_device[i].info);
+ if( bta_dm_cb.p_sec_cback )
+ bta_dm_cb.p_sec_cback(BTA_DM_LINK_UP_EVT, (tBTA_DM_SEC *)&conn);
+
+ }
+ else
+ {
+ for(i=0; i<bta_dm_cb.device_list.count; i++)
+ {
+ if(bdcmp( bta_dm_cb.device_list.peer_device[i].peer_bdaddr, p_bda))
+ continue;
+
+ for(; i<bta_dm_cb.device_list.count ; i++)
+ {
+
+ memcpy(&bta_dm_cb.device_list.peer_device[i], &bta_dm_cb.device_list.peer_device[i+1], sizeof(bta_dm_cb.device_list.peer_device[i]));
+
+ }
+
+ break;
+
+ }
+ if(bta_dm_cb.device_list.count)
+ bta_dm_cb.device_list.count--;
+
+ if(bta_dm_search_cb.wait_disc && !bdcmp(bta_dm_search_cb.peer_bdaddr, p_bda))
+ {
+ bta_dm_search_cb.wait_disc = FALSE;
+
+ if(bta_dm_search_cb.sdp_results)
+ {
+ APPL_TRACE_EVENT0(" timer stopped ");
+ bta_sys_stop_timer(&bta_dm_search_cb.search_timer);
+ bta_dm_discover_next_device();
+ }
+
+ }
+
+ if(bta_dm_cb.disabling)
+ {
+
+ if(!BTM_GetNumAclLinks())
+ {
+ bta_sys_stop_timer(&bta_dm_cb.disable_timer);
+ bta_dm_cb.disable_timer.p_cback = (TIMER_CBACK*)&bta_dm_disable_conn_down_timer_cback;
+ /* start a timer to make sure that the profiles
+ get the disconnect event */
+ bta_sys_start_timer(&bta_dm_cb.disable_timer, 0, 1000);
+ }
+
+ }
+
+ bdcpy(conn.link_down.bd_addr, p_bda);
+ conn.link_down.status = (UINT8) btm_get_acl_disc_reason_code();
+ if( bta_dm_cb.p_sec_cback )
+ bta_dm_cb.p_sec_cback(BTA_DM_LINK_DOWN_EVT, (tBTA_DM_SEC *)&conn);
+ }
+
+ bta_dm_adjust_roles();
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_disable_conn_down_timer_cback
+**
+** Description Sends disable event to application
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_dm_disable_conn_down_timer_cback (TIMER_LIST_ENT *p_tle)
+{
+ tBTA_SYS_HW_MSG *sys_enable_event;
+
+ /* register our callback to SYS HW manager */
+ bta_sys_hw_register( BTA_SYS_HW_BLUETOOTH, bta_dm_sys_hw_cback );
+
+ /* send a message to BTA SYS */
+ if ((sys_enable_event = (tBTA_SYS_HW_MSG *) GKI_getbuf(sizeof(tBTA_SYS_HW_MSG))) != NULL)
+ {
+ sys_enable_event->hdr.event = BTA_SYS_API_DISABLE_EVT;
+ sys_enable_event->hw_module = BTA_SYS_HW_BLUETOOTH;
+ bta_sys_sendmsg(sys_enable_event);
+ }
+
+ bta_dm_cb.disabling = FALSE;
+
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_rssi_cback
+**
+** Description Callback from btm with rssi values
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_dm_rssi_cback (tBTM_RSSI_RESULTS *p_result)
+{
+
+ tBTA_DM_SIG_STRENGTH result;
+
+ if(p_result->status == BTM_SUCCESS)
+ {
+
+ bdcpy(result.bd_addr, p_result->rem_bda);
+ result.mask = BTA_SIG_STRENGTH_RSSI_MASK;
+ result.rssi_value = p_result->rssi;
+ if( bta_dm_cb.p_sec_cback!= NULL )
+ bta_dm_cb.p_sec_cback(BTA_DM_SIG_STRENGTH_EVT, (tBTA_DM_SEC *)&result);
+
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_link_quality_cback
+**
+** Description Callback from btm with link quality value
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_dm_link_quality_cback (tBTM_LINK_QUALITY_RESULTS *p_result)
+{
+
+ tBTA_DM_SIG_STRENGTH result;
+
+ if(p_result->status == BTM_SUCCESS)
+ {
+
+ bdcpy(result.bd_addr, p_result->rem_bda);
+ result.mask = BTA_SIG_STRENGTH_LINK_QUALITY_MASK;
+ result.link_quality_value = p_result->link_quality;
+ if( bta_dm_cb.p_sec_cback!= NULL )
+ bta_dm_cb.p_sec_cback(BTA_DM_SIG_STRENGTH_EVT, (tBTA_DM_SEC *)&result);
+
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_rm_cback
+**
+** Description Role management callback from sys
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_dm_rm_cback(tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8 app_id, BD_ADDR peer_addr)
+{
+
+ UINT8 j;
+ tBTA_PREF_ROLES role;
+ tBTA_DM_PEER_DEVICE *p_dev;
+
+ p_dev = bta_dm_find_peer_device(peer_addr);
+ if( status == BTA_SYS_CONN_OPEN)
+ {
+ if(p_dev)
+ {
+ p_dev->conn_state = BTA_DM_CONNECTED;
+
+ for(j=1; j<= p_bta_dm_rm_cfg[0].app_id; j++)
+ {
+ if(((p_bta_dm_rm_cfg[j].app_id == app_id) || (p_bta_dm_rm_cfg[j].app_id == BTA_ALL_APP_ID))
+ && (p_bta_dm_rm_cfg[j].id == id))
+ {
+ role = p_bta_dm_rm_cfg[j].cfg;
+
+ if(role > p_dev->pref_role )
+ p_dev->pref_role = role;
+ break;
+ }
+ }
+
+ }
+
+ }
+
+ if((BTA_ID_AV == id)||(BTA_ID_AVK ==id))
+ {
+ if( status == BTA_SYS_CONN_BUSY)
+ {
+ if(p_dev)
+ p_dev->info |= BTA_DM_DI_AV_ACTIVE;
+ /* AV calls bta_sys_conn_open with the A2DP stream count as app_id */
+ if(BTA_ID_AV == id)
+ bta_dm_cb.cur_av_count = app_id;
+ }
+ else if( status == BTA_SYS_CONN_IDLE)
+ {
+ if(p_dev)
+ p_dev->info &= ~BTA_DM_DI_AV_ACTIVE;
+ /* AV calls bta_sys_conn_open with the A2DP stream count as app_id */
+ if(BTA_ID_AV == id)
+ bta_dm_cb.cur_av_count = app_id;
+ }
+ APPL_TRACE_WARNING2("bta_dm_rm_cback:%d, status:%d", bta_dm_cb.cur_av_count, status);
+ }
+
+
+ bta_dm_adjust_roles();
+
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_adjust_roles
+**
+** Description Adjust roles
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_dm_adjust_roles(void)
+{
+
+ UINT8 i;
+ BOOLEAN set_master_role = FALSE;
+
+ if(bta_dm_cb.device_list.count)
+ {
+
+ /* the configuration is no scatternet
+ * or AV connection exists and there are more than one ACL link */
+ if( (p_bta_dm_rm_cfg[0].cfg == BTA_DM_NO_SCATTERNET) ||
+ (bta_dm_cb.cur_av_count && bta_dm_cb.device_list.count > 1) )
+ {
+
+ L2CA_SetDesireRole (HCI_ROLE_MASTER);
+ set_master_role = TRUE;
+
+ }
+
+ for(i=0; i<bta_dm_cb.device_list.count; i++)
+ {
+ if(bta_dm_cb.device_list.peer_device[i].conn_state == BTA_DM_CONNECTED)
+ {
+ if(!set_master_role && (bta_dm_cb.device_list.peer_device[i].pref_role != BTA_ANY_ROLE)
+ && (p_bta_dm_rm_cfg[0].cfg == BTA_DM_PARTIAL_SCATTERNET))
+ {
+ L2CA_SetDesireRole (HCI_ROLE_MASTER);
+ set_master_role = TRUE;
+ }
+
+ if((bta_dm_cb.device_list.peer_device[i].pref_role == BTA_MASTER_ROLE_ONLY)
+ || (bta_dm_cb.device_list.count > 1))
+ {
+
+ BTM_SwitchRole (bta_dm_cb.device_list.peer_device[i].peer_bdaddr, HCI_ROLE_MASTER, NULL);
+
+ }
+
+ }
+ }
+
+
+ if(!set_master_role)
+ {
+
+ L2CA_SetDesireRole (L2CAP_DESIRED_LINK_ROLE);
+
+ }
+
+ }
+ else
+ {
+ L2CA_SetDesireRole (L2CAP_DESIRED_LINK_ROLE);
+ }
+
+
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_get_remname
+**
+** Description Returns a pointer to the remote name stored in the DM control
+** block if it exists, or from the BTM memory.
+**
+** Returns char * - Pointer to the remote device name
+*******************************************************************************/
+static char *bta_dm_get_remname(void)
+{
+ char *p_name = bta_dm_search_cb.peer_name;
+ char *p_temp;
+
+ /* If the name isn't already stored, try retrieving from BTM */
+ if (*p_name == '\0')
+ if ((p_temp = BTM_SecReadDevName(bta_dm_search_cb.peer_bdaddr)) != NULL)
+ p_name = p_temp;
+
+ return p_name;
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_bond_cancel_complete_cback
+**
+** Description Authentication complete callback from BTM
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_dm_bond_cancel_complete_cback(tBTM_STATUS result)
+{
+
+ tBTA_DM_SEC sec_event;
+
+ if (result == BTM_SUCCESS)
+ sec_event.bond_cancel_cmpl.result = BTA_SUCCESS;
+ else
+ sec_event.bond_cancel_cmpl.result = BTA_FAILURE;
+
+ if(bta_dm_cb.p_sec_cback)
+ {
+ bta_dm_cb.p_sec_cback(BTA_DM_BOND_CANCEL_CMPL_EVT, &sec_event);
+ }
+}
+
+#if ( BTM_EIR_SERVER_INCLUDED == TRUE )
+ #if ( BTA_EIR_CANNED_UUID_LIST != TRUE )&&(BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0)
+/*******************************************************************************
+**
+** Function bta_dm_update_eir_uuid
+**
+** Description
+**
+**
+*******************************************************************************/
+void bta_dm_update_eir_uuid (tBTA_DM_MSG *p_data)
+{
+ tBTA_DM_API_UPDATE_EIR_UUID *p_msg = (tBTA_DM_API_UPDATE_EIR_UUID *)p_data;
+ UINT8 xx;
+ UINT8 empty_slot = BTA_EIR_SERVER_NUM_CUSTOM_UUID;
+ UINT8 match_slot = BTA_EIR_SERVER_NUM_CUSTOM_UUID;
+
+ for (xx = 0; xx < BTA_EIR_SERVER_NUM_CUSTOM_UUID; xx++)
+ {
+ if (bta_dm_cb.custom_uuid[xx].len == 0)
+ {
+ if (empty_slot == BTA_EIR_SERVER_NUM_CUSTOM_UUID)
+ empty_slot = xx;
+ }
+ else if (match_slot == BTA_EIR_SERVER_NUM_CUSTOM_UUID)
+ {
+ if (!memcmp (bta_dm_cb.custom_uuid[xx].uu.uuid128, p_msg->uuid.uu.uuid128, p_msg->uuid.len))
+ {
+ match_slot = xx;;
+ }
+ }
+ }
+
+ if (p_msg->is_add)
+ {
+ if (match_slot == BTA_EIR_SERVER_NUM_CUSTOM_UUID)
+ {
+ if (empty_slot == BTA_EIR_SERVER_NUM_CUSTOM_UUID)
+ {
+ APPL_TRACE_ERROR0("No space to add UUID for EIR");
+ return;
+ }
+ else
+ {
+ memcpy (&(bta_dm_cb.custom_uuid[empty_slot]), &(p_msg->uuid), sizeof(tBT_UUID));
+ }
+ }
+ else
+ {
+ APPL_TRACE_ERROR0("UUID is already added for EIR");
+ return;
+ }
+ }
+ else
+ {
+ if (match_slot == BTA_EIR_SERVER_NUM_CUSTOM_UUID)
+ {
+ APPL_TRACE_ERROR0("UUID is not found for EIR");
+ return;
+ }
+ else
+ {
+ memset (&(bta_dm_cb.custom_uuid[match_slot]), 0, sizeof(tBT_UUID));
+ }
+ }
+
+ bta_dm_set_eir (NULL);
+}
+ #endif
+
+/*******************************************************************************
+**
+** Function bta_dm_set_eir_config
+**
+** Description
+**
+**
+*******************************************************************************/
+void bta_dm_set_eir_config (tBTA_DM_MSG *p_data)
+{
+ if (p_data->set_eir_cfg.p_eir_cfg)
+ {
+ /* User defined config */
+ p_bta_dm_eir_cfg = p_data->set_eir_cfg.p_eir_cfg;
+ }
+ else
+ {
+ /* Back to default config */
+ p_bta_dm_eir_cfg = (tBTA_DM_EIR_CONF*)&bta_dm_eir_cfg;
+ }
+
+ bta_dm_set_eir (NULL);
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_set_eir
+**
+** Description This function creates EIR tagged data and writes it to controller.
+**
+** Returns None
+**
+*******************************************************************************/
+static void bta_dm_set_eir (char *local_name)
+{
+ BT_HDR *p_buf;
+ UINT8 *p;
+ UINT8 *p_length;
+#if (BTA_EIR_CANNED_UUID_LIST != TRUE)
+ UINT8 *p_type;
+ UINT8 max_num_uuid;
+#if (BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0)
+ UINT8 custom_uuid_idx;
+#endif
+#endif
+#if (BTM_EIR_DEFAULT_FEC_REQUIRED == FALSE)
+ UINT8 free_eir_length = HCI_EXT_INQ_RESPONSE_LEN;
+#else
+ UINT8 free_eir_length = HCI_DM5_PACKET_SIZE;
+#endif
+ UINT8 num_uuid;
+ UINT8 data_type;
+ UINT8 local_name_len;
+
+ /* wait until complete to disable */
+ if (bta_dm_cb.disable_timer.in_use)
+ return;
+
+#if ( BTA_EIR_CANNED_UUID_LIST != TRUE )
+ /* wait until App is ready */
+ if (bta_dm_cb.app_ready_timer.in_use)
+ return;
+
+ /* if local name is not provided, get it from controller */
+ if( local_name == NULL )
+ {
+ if( BTM_ReadLocalDeviceName( &local_name ) != BTM_SUCCESS )
+ {
+ APPL_TRACE_ERROR0("Fail to read local device name for EIR");
+ }
+ }
+#endif
+
+ /* Allocate a buffer to hold HCI command */
+ if ((p_buf = (BT_HDR *)GKI_getpoolbuf(BTM_CMD_POOL_ID)) == NULL)
+ {
+ APPL_TRACE_ERROR0("bta_dm_set_eir couldn't allocate buffer");
+ return;
+ }
+ p = (UINT8 *)p_buf + BTM_HCI_EIR_OFFSET;
+
+ memset(p, 0x00, HCI_EXT_INQ_RESPONSE_LEN );
+
+ APPL_TRACE_DEBUG0("BTA is generating EIR");
+
+ if( local_name )
+ local_name_len = strlen( local_name );
+ else
+ local_name_len = 0;
+
+ data_type = BTM_EIR_COMPLETE_LOCAL_NAME_TYPE;
+ /* if local name is longer than minimum length of shortened name */
+ /* check whether it needs to be shortened or not */
+ if( local_name_len > p_bta_dm_eir_cfg->bta_dm_eir_min_name_len )
+ {
+ /* get number of UUID 16-bit list */
+#if (BTA_EIR_CANNED_UUID_LIST == TRUE)
+ num_uuid = p_bta_dm_eir_cfg->bta_dm_eir_uuid16_len/LEN_UUID_16;
+#else
+ max_num_uuid = (free_eir_length - 2)/LEN_UUID_16;
+ data_type = BTM_GetEirSupportedServices( bta_dm_cb.eir_uuid, &p,
+ max_num_uuid, &num_uuid );
+ p = (UINT8 *)p_buf + BTM_HCI_EIR_OFFSET; /* reset p */
+#endif
+
+ /* if UUID doesn't fit remaing space, shorten local name */
+ if ( local_name_len > (free_eir_length - 4 - num_uuid*LEN_UUID_16))
+ {
+ APPL_TRACE_WARNING0("BTA EIR: local name is shortened");
+ local_name_len = p_bta_dm_eir_cfg->bta_dm_eir_min_name_len;
+ data_type = BTM_EIR_SHORTENED_LOCAL_NAME_TYPE;
+ }
+ else
+ data_type = BTM_EIR_COMPLETE_LOCAL_NAME_TYPE;
+ }
+
+ UINT8_TO_STREAM(p, local_name_len + 1);
+ UINT8_TO_STREAM(p, data_type);
+ memcpy(p, local_name, local_name_len);
+ p += local_name_len;
+ free_eir_length -= local_name_len + 2;
+
+#if (BTA_EIR_CANNED_UUID_LIST == TRUE)
+ /* if UUID list is provided as static data in configuration */
+ if(( p_bta_dm_eir_cfg->bta_dm_eir_uuid16_len > 0 )
+ &&(p_bta_dm_eir_cfg->bta_dm_eir_uuid16))
+ {
+ if( free_eir_length > LEN_UUID_16 + 2)
+ {
+ free_eir_length -= 2;
+
+ if( free_eir_length >= p_bta_dm_eir_cfg->bta_dm_eir_uuid16_len)
+ {
+ num_uuid = p_bta_dm_eir_cfg->bta_dm_eir_uuid16_len / LEN_UUID_16;
+ data_type = BTM_EIR_COMPLETE_16BITS_UUID_TYPE;
+ }
+ else /* not enough room for all UUIDs */
+ {
+ APPL_TRACE_WARNING0("BTA EIR: UUID 16-bit list is truncated");
+ num_uuid = free_eir_length / LEN_UUID_16;
+ data_type = BTM_EIR_MORE_16BITS_UUID_TYPE;
+ }
+ UINT8_TO_STREAM(p, num_uuid * LEN_UUID_16 + 1);
+ UINT8_TO_STREAM(p, data_type);
+ memcpy(p, p_bta_dm_eir_cfg->bta_dm_eir_uuid16, num_uuid * LEN_UUID_16 );
+ p += num_uuid * LEN_UUID_16;
+ free_eir_length -= num_uuid * LEN_UUID_16;
+ }
+ }
+#else /* (BTA_EIR_CANNED_UUID_LIST == TRUE) */
+ /* if UUID list is dynamic */
+ if ( free_eir_length >= 2)
+ {
+ p_length = p++;
+ p_type = p++;
+ num_uuid = 0;
+
+ max_num_uuid = (free_eir_length - 2)/LEN_UUID_16;
+ data_type = BTM_GetEirSupportedServices( bta_dm_cb.eir_uuid, &p, max_num_uuid, &num_uuid );
+
+ if( data_type == BTM_EIR_MORE_16BITS_UUID_TYPE )
+ {
+ APPL_TRACE_WARNING0("BTA EIR: UUID 16-bit list is truncated");
+ }
+#if (BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0)
+ else
+ {
+ for (custom_uuid_idx = 0; custom_uuid_idx < BTA_EIR_SERVER_NUM_CUSTOM_UUID; custom_uuid_idx++)
+ {
+ if (bta_dm_cb.custom_uuid[custom_uuid_idx].len == LEN_UUID_16)
+ {
+ if ( num_uuid < max_num_uuid )
+ {
+ UINT16_TO_STREAM(p, bta_dm_cb.custom_uuid[custom_uuid_idx].uu.uuid16);
+ num_uuid++;
+ }
+ else
+ {
+ data_type = BTM_EIR_MORE_16BITS_UUID_TYPE;
+ APPL_TRACE_WARNING0("BTA EIR: UUID 16-bit list is truncated");
+ break;
+ }
+ }
+ }
+ }
+#endif /* (BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) */
+
+ UINT8_TO_STREAM(p_length, num_uuid * LEN_UUID_16 + 1);
+ UINT8_TO_STREAM(p_type, data_type);
+ free_eir_length -= num_uuid * LEN_UUID_16 + 2;
+ }
+#endif /* (BTA_EIR_CANNED_UUID_LIST == TRUE) */
+
+#if ( BTA_EIR_CANNED_UUID_LIST != TRUE )&&(BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0)
+ /* Adding 32-bit UUID list */
+ if ( free_eir_length >= 2)
+ {
+ p_length = p++;
+ p_type = p++;
+ num_uuid = 0;
+ data_type = BTM_EIR_COMPLETE_32BITS_UUID_TYPE;
+
+ max_num_uuid = (free_eir_length - 2)/LEN_UUID_32;
+
+ for (custom_uuid_idx = 0; custom_uuid_idx < BTA_EIR_SERVER_NUM_CUSTOM_UUID; custom_uuid_idx++)
+ {
+ if (bta_dm_cb.custom_uuid[custom_uuid_idx].len == LEN_UUID_32)
+ {
+ if ( num_uuid < max_num_uuid )
+ {
+ UINT32_TO_STREAM(p, bta_dm_cb.custom_uuid[custom_uuid_idx].uu.uuid32);
+ num_uuid++;
+ }
+ else
+ {
+ data_type = BTM_EIR_MORE_32BITS_UUID_TYPE;
+ APPL_TRACE_WARNING0("BTA EIR: UUID 32-bit list is truncated");
+ break;
+ }
+ }
+ }
+
+ UINT8_TO_STREAM(p_length, num_uuid * LEN_UUID_32 + 1);
+ UINT8_TO_STREAM(p_type, data_type);
+ free_eir_length -= num_uuid * LEN_UUID_32 + 2;
+ }
+
+ /* Adding 128-bit UUID list */
+ if ( free_eir_length >= 2)
+ {
+ p_length = p++;
+ p_type = p++;
+ num_uuid = 0;
+ data_type = BTM_EIR_COMPLETE_128BITS_UUID_TYPE;
+
+ max_num_uuid = (free_eir_length - 2)/LEN_UUID_128;
+
+ for (custom_uuid_idx = 0; custom_uuid_idx < BTA_EIR_SERVER_NUM_CUSTOM_UUID; custom_uuid_idx++)
+ {
+ if (bta_dm_cb.custom_uuid[custom_uuid_idx].len == LEN_UUID_128)
+ {
+ if ( num_uuid < max_num_uuid )
+ {
+ ARRAY16_TO_STREAM(p, bta_dm_cb.custom_uuid[custom_uuid_idx].uu.uuid128);
+ num_uuid++;
+ }
+ else
+ {
+ data_type = BTM_EIR_MORE_128BITS_UUID_TYPE;
+ APPL_TRACE_WARNING0("BTA EIR: UUID 128-bit list is truncated");
+ break;
+ }
+ }
+ }
+
+ UINT8_TO_STREAM(p_length, num_uuid * LEN_UUID_128 + 1);
+ UINT8_TO_STREAM(p_type, data_type);
+ free_eir_length -= num_uuid * LEN_UUID_128 + 2;
+ }
+#endif /* ( BTA_EIR_CANNED_UUID_LIST != TRUE )&&(BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) */
+
+ /* if Flags are provided in configuration */
+ if(( p_bta_dm_eir_cfg->bta_dm_eir_flag_len > 0 )
+ &&( p_bta_dm_eir_cfg->bta_dm_eir_flags )
+ &&( free_eir_length >= p_bta_dm_eir_cfg->bta_dm_eir_flag_len + 2 ))
+ {
+ UINT8_TO_STREAM(p, p_bta_dm_eir_cfg->bta_dm_eir_flag_len + 1);
+ UINT8_TO_STREAM(p, BTM_EIR_FLAGS_TYPE);
+ memcpy(p, p_bta_dm_eir_cfg->bta_dm_eir_flags,
+ p_bta_dm_eir_cfg->bta_dm_eir_flag_len);
+ p += p_bta_dm_eir_cfg->bta_dm_eir_flag_len;
+ free_eir_length -= p_bta_dm_eir_cfg->bta_dm_eir_flag_len + 2;
+ }
+
+ /* if Inquiry Tx Resp Power compiled */
+ if((p_bta_dm_eir_cfg->bta_dm_eir_inq_tx_power) &&
+ (free_eir_length >= 3))
+ {
+ UINT8_TO_STREAM(p, 2); /* Length field */
+ UINT8_TO_STREAM(p, BTM_EIR_TX_POWER_LEVEL_TYPE);
+ UINT8_TO_STREAM(p, *(p_bta_dm_eir_cfg->bta_dm_eir_inq_tx_power));
+ free_eir_length -= 3;
+ }
+
+ /* if Manufacturer Specific are provided in configuration */
+ if(( p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len > 0 )
+ &&( p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec )
+ &&( free_eir_length >= p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len + 2 ))
+ {
+ p_length = p;
+
+ UINT8_TO_STREAM(p, p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len + 1);
+ UINT8_TO_STREAM(p, BTM_EIR_MANUFACTURER_SPECIFIC_TYPE);
+ memcpy(p, p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec,
+ p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len);
+ p += p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len;
+ free_eir_length -= p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len + 2;
+
+ }
+ else
+ {
+ p_length = NULL;
+ }
+
+ if( free_eir_length )
+ UINT8_TO_STREAM(p, 0); /* terminator of significant part */
+
+ BTM_WriteEIR( p_buf );
+
+}
+#endif
+
+#if ( BTM_EIR_CLIENT_INCLUDED == TRUE )
+/*******************************************************************************
+**
+** Function bta_dm_eir_search_services
+**
+** Description This function searches services in received EIR
+**
+** Returns None
+**
+*******************************************************************************/
+static void bta_dm_eir_search_services( tBTM_INQ_RESULTS *p_result,
+ tBTA_SERVICE_MASK *p_services_to_search,
+ tBTA_SERVICE_MASK *p_services_found)
+{
+ tBTA_SERVICE_MASK service_index = 0;
+ tBTM_EIR_SEARCH_RESULT result;
+
+ APPL_TRACE_DEBUG6("BTA searching services in EIR of BDA:0x%02X%02X%02X%02X%02X%02X",
+ p_result->remote_bd_addr[0],p_result->remote_bd_addr[1],
+ p_result->remote_bd_addr[2],p_result->remote_bd_addr[3],
+ p_result->remote_bd_addr[4],p_result->remote_bd_addr[5]);
+
+ APPL_TRACE_DEBUG1(" with services_to_search=0x%08X", *p_services_to_search);
+
+#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE
+ /* always do GATT based service discovery by SDP instead of from EIR */
+ /* if GATT based service is also to be put in EIR, need to modify this */
+ while (service_index < (BTA_MAX_SERVICE_ID - 1))
+#else
+ while(service_index < BTA_MAX_SERVICE_ID)
+#endif
+ {
+ if( *p_services_to_search
+ & (tBTA_SERVICE_MASK)(BTA_SERVICE_ID_TO_SERVICE_MASK(service_index)))
+ {
+ result = BTM_HasInquiryEirService( p_result,
+ bta_service_id_to_uuid_lkup_tbl[service_index] );
+
+ /* Searching for HSP v1.2 only device */
+ if ((result != BTM_EIR_FOUND) &&
+ (bta_service_id_to_uuid_lkup_tbl[service_index] == UUID_SERVCLASS_HEADSET))
+ {
+ result = BTM_HasInquiryEirService (p_result, UUID_SERVCLASS_HEADSET_HS);
+ }
+
+ if( result == BTM_EIR_FOUND )
+ {
+ /* If Plug and Play service record, need to check to see if Broadcom stack */
+ /* However, EIR data doesn't have EXT_BRCM_VERSION so just skip it */
+ if( bta_service_id_to_uuid_lkup_tbl[service_index]
+ != UUID_SERVCLASS_PNP_INFORMATION )
+ {
+
+ *p_services_found |=
+ (tBTA_SERVICE_MASK)(BTA_SERVICE_ID_TO_SERVICE_MASK(service_index));
+ /* remove the service from services to be searched */
+ *p_services_to_search &=
+ (tBTA_SERVICE_MASK)(~(BTA_SERVICE_ID_TO_SERVICE_MASK(service_index)));
+ }
+ }
+ else if( result == BTM_EIR_NOT_FOUND )
+ {
+ /* remove the service from services to be searched */
+ *p_services_to_search &=
+ (tBTA_SERVICE_MASK)(~(BTA_SERVICE_ID_TO_SERVICE_MASK(service_index)));
+ }
+ }
+
+ service_index++;
+ }
+
+ APPL_TRACE_ERROR2("BTA EIR search result, services_to_search=0x%08X, services_found=0x%08X",
+ *p_services_to_search, *p_services_found);
+}
+#endif
+
+#if ( BTM_EIR_SERVER_INCLUDED == TRUE )&&(BTA_EIR_CANNED_UUID_LIST != TRUE)
+/*******************************************************************************
+**
+** Function bta_dm_eir_update_uuid
+**
+** Description This function adds or removes service UUID in EIR database.
+**
+** Returns None
+**
+*******************************************************************************/
+void bta_dm_eir_update_uuid(UINT16 uuid16, BOOLEAN adding)
+{
+ /* if this UUID is not advertised in EIR */
+ if( !BTM_HasEirService( p_bta_dm_eir_cfg->uuid_mask, uuid16 ))
+ return;
+
+ if( adding )
+ {
+ APPL_TRACE_EVENT1("Adding UUID=0x%04X into EIR", uuid16);
+
+ BTM_AddEirService( bta_dm_cb.eir_uuid, uuid16 );
+ }
+ else
+ {
+ APPL_TRACE_EVENT1("Removing UUID=0x%04X from EIR", uuid16);
+
+ BTM_RemoveEirService( bta_dm_cb.eir_uuid, uuid16 );
+ }
+
+ bta_dm_set_eir (NULL);
+
+ APPL_TRACE_EVENT2("bta_dm_eir_update_uuid UUID bit mask=0x%08X %08X",
+ bta_dm_cb.eir_uuid[1], bta_dm_cb.eir_uuid[0] );
+}
+#endif
+
+/*******************************************************************************
+**
+** Function bta_dm_enable_test_mode
+**
+** Description enable test mode
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_enable_test_mode(tBTA_DM_MSG *p_data)
+{
+ BTM_EnableTestMode();
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_disable_test_mode
+**
+** Description disable test mode
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_disable_test_mode(tBTA_DM_MSG *p_data)
+{
+ BTM_DeviceReset(NULL);
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_execute_callback
+**
+** Description Just execute a generic call back in the context of the BTU/BTA tack
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_execute_callback(tBTA_DM_MSG *p_data)
+{
+ /* sanity check */
+ if(p_data->exec_cback.p_exec_cback == NULL)
+ {
+ return;
+ }
+
+ p_data->exec_cback.p_exec_cback(p_data->exec_cback.p_param);
+}
+/*******************************************************************************
+**
+** Function bta_dm_encrypt_cback
+**
+** Description link encryption complete callback.
+**
+** Returns None
+**
+*******************************************************************************/
+void bta_dm_encrypt_cback(BD_ADDR bd_addr, void *p_ref_data, tBTM_STATUS result)
+{
+ tBTA_STATUS bta_status = BTA_SUCCESS;
+ tBTA_DM_ENCRYPT_CBACK *p_callback = bta_dm_cb.p_encrypt_cback;
+
+ bta_dm_cb.p_encrypt_cback = NULL;
+ switch (result)
+ {
+ case BTM_SUCCESS:
+ break;
+ case BTM_WRONG_MODE:
+ bta_status = BTA_WRONG_MODE;
+ break;
+ case BTM_NO_RESOURCES:
+ bta_status = BTA_NO_RESOURCES;
+ break;
+ case BTM_BUSY:
+ bta_status = BTA_BUSY;
+ break;
+ default:
+ bta_status = BTA_FAILURE;
+ break;
+ }
+
+ APPL_TRACE_DEBUG2("bta_dm_encrypt_cback status =%d p_callback=0x%x", bta_status, p_callback);
+
+ if (p_callback)
+ {
+ (*p_callback)(bd_addr, bta_status);
+ }
+}
+/*******************************************************************************
+**
+** Function bta_dm_set_encryption
+**
+** Description This function to encrypt the link
+**
+** Returns None
+**
+*******************************************************************************/
+void bta_dm_set_encryption (tBTA_DM_MSG *p_data)
+{
+
+ APPL_TRACE_DEBUG0("bta_dm_set_encryption"); //todo
+ if (!p_data->set_encryption.p_callback)
+ {
+ APPL_TRACE_ERROR0("bta_dm_set_encryption callback is not provided");
+ return;
+ }
+
+ if (bta_dm_cb.p_encrypt_cback)
+ {
+ (*p_data->set_encryption.p_callback)(p_data->set_encryption.bd_addr, BTA_BUSY);
+ return;
+ }
+
+
+ bta_dm_cb.p_encrypt_cback = p_data->set_encryption.p_callback;
+ bta_dm_cb.sec_act = p_data->set_encryption.sec_act;
+ BTM_SetEncryption(p_data->set_encryption.bd_addr, bta_dm_encrypt_cback, &bta_dm_cb.sec_act);
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_set_afh_channels
+**
+** Description set afh channels
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_set_afh_channels(tBTA_DM_MSG * p_data)
+{
+
+ BTM_SetAfhChannels(p_data->set_afhchannels.first,p_data->set_afhchannels.last);
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_set_afh_channel_assesment
+**
+** Description set afh channel assesment
+**
+**
+** Returns void
+**
+*******************************************************************************/
+
+void bta_dm_set_afh_channel_assesment (tBTA_DM_MSG * p_data)
+{
+ BTM_SetAfhChannelAssessment(p_data->set_afh_channel_assessment.enable_or_disable);
+}
+
+#if (BLE_INCLUDED == TRUE)
+#if (SMP_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function bta_dm_ble_smp_cback
+**
+** Description Callback for BLE SMP
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static UINT8 bta_dm_ble_smp_cback (tBTM_LE_EVT event, BD_ADDR bda, tBTM_LE_EVT_DATA *p_data)
+{
+ tBTM_STATUS status = BTM_SUCCESS;
+ tBTA_DM_SEC sec_event;
+
+ if (!bta_dm_cb.p_sec_cback)
+ return BTM_NOT_AUTHORIZED;
+
+ memset(&sec_event, 0, sizeof(tBTA_DM_SEC));
+ switch (event)
+ {
+ case BTM_LE_IO_REQ_EVT:
+#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
+
+ bta_dm_co_ble_io_req(bda,
+ &p_data->io_req.io_cap,
+ &p_data->io_req.oob_data,
+ &p_data->io_req.auth_req,
+ &p_data->io_req.max_key_size,
+ &p_data->io_req.init_keys,
+ &p_data->io_req.resp_keys);
+#endif
+#if BTM_OOB_INCLUDED == FALSE
+ status = BTM_SUCCESS;
+#endif
+ APPL_TRACE_EVENT2("io mitm: %d oob_data:%d", p_data->io_req.auth_req, p_data->io_req.oob_data);
+
+ break;
+
+ case BTM_LE_SEC_REQUEST_EVT:
+ bdcpy(sec_event.ble_req.bd_addr, bda);
+ BCM_STRNCPY_S((char*)sec_event.ble_req.bd_name, sizeof(BD_NAME), bta_dm_get_remname(), (BD_NAME_LEN-1));
+ bta_dm_cb.p_sec_cback(BTA_DM_BLE_SEC_REQ_EVT, &sec_event);
+ break;
+
+ case BTM_LE_KEY_NOTIF_EVT:
+ bdcpy(sec_event.key_notif.bd_addr, bda);
+ BCM_STRNCPY_S((char*)sec_event.key_notif.bd_name, sizeof(BD_NAME), bta_dm_get_remname(), (BD_NAME_LEN-1));
+ sec_event.key_notif.passkey = p_data->key_notif;
+ bta_dm_cb.p_sec_cback(BTA_DM_BLE_PASSKEY_NOTIF_EVT, &sec_event);
+ break;
+
+ case BTM_LE_KEY_REQ_EVT:
+ bdcpy(sec_event.ble_req.bd_addr, bda);
+ bta_dm_cb.p_sec_cback(BTA_DM_BLE_PASSKEY_REQ_EVT, &sec_event);
+ break;
+
+ case BTM_LE_OOB_REQ_EVT:
+ bdcpy(sec_event.ble_req.bd_addr, bda);
+ bta_dm_cb.p_sec_cback(BTA_DM_BLE_OOB_REQ_EVT, &sec_event);
+ break;
+
+ case BTM_LE_KEY_EVT:
+ bdcpy(sec_event.ble_key.bd_addr, bda);
+ sec_event.ble_key.key_type = p_data->key.key_type;
+ memcpy(&sec_event.ble_key.key_value, p_data->key.p_key_value, sizeof(tBTM_LE_KEY_VALUE));
+ bta_dm_cb.p_sec_cback(BTA_DM_BLE_KEY_EVT, &sec_event);
+ break;
+
+ case BTM_LE_COMPLT_EVT:
+ bdcpy(sec_event.auth_cmpl.bd_addr, bda);
+ if (p_data->complt.reason != 0)
+ sec_event.auth_cmpl.fail_reason = BTA_DM_AUTH_CONVERT_SMP_CODE(((UINT8)p_data->complt.reason));
+ else
+ sec_event.auth_cmpl.success = TRUE;
+
+ if (bta_dm_cb.p_sec_cback)
+ {
+ //bta_dm_cb.p_sec_cback(BTA_DM_AUTH_CMPL_EVT, &sec_event);
+ bta_dm_cb.p_sec_cback(BTA_DM_BLE_AUTH_CMPL_EVT, &sec_event);
+ }
+
+ break;
+
+ default:
+ status = BTM_NOT_AUTHORIZED;
+ break;
+ }
+ return status;
+}
+#endif /* SMP_INCLUDED == TRUE */
+
+/*******************************************************************************
+**
+** Function bta_dm_ble_id_key_cback
+**
+** Description Callback for BLE local ID keys
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_dm_ble_id_key_cback (UINT8 key_type, tBTM_BLE_LOCAL_KEYS *p_key)
+{
+ UINT8 evt;
+ tBTA_DM_SEC dm_key;
+
+ switch (key_type)
+ {
+ case BTM_BLE_KEY_TYPE_ID:
+ case BTM_BLE_KEY_TYPE_ER:
+ if (bta_dm_cb.p_sec_cback)
+ {
+ memcpy(&dm_key.ble_id_keys, p_key, sizeof(tBTM_BLE_LOCAL_KEYS));
+
+ evt = (key_type == BTM_BLE_KEY_TYPE_ID) ? BTA_DM_BLE_LOCAL_IR_EVT :\
+ BTA_DM_BLE_LOCAL_ER_EVT;
+ bta_dm_cb.p_sec_cback(evt, &dm_key);
+ }
+ break;
+
+ default:
+ APPL_TRACE_DEBUG1("Unknown key type %d", key_type);
+ break;
+ }
+ return;
+
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_add_blekey
+**
+** Description This function adds an BLE Key to an security database entry.
+** This function shall only be called AFTER BTA_DmAddBleDevice has been called.
+** It is normally called during host startup to restore all required information
+** stored in the NVRAM.
+**
+** Parameters:
+**
+*******************************************************************************/
+void bta_dm_add_blekey (tBTA_DM_MSG *p_data)
+{
+ if (!BTM_SecAddBleKey (p_data->add_ble_key.bd_addr,
+ (tBTM_LE_KEY_VALUE *)&p_data->add_ble_key.blekey,
+ p_data->add_ble_key.key_type))
+ {
+ APPL_TRACE_ERROR2 ("BTA_DM: Error adding BLE Key for device %08x%04x",
+ (p_data->add_ble_key.bd_addr[0]<<24)+(p_data->add_ble_key.bd_addr[1]<<16)+\
+ (p_data->add_ble_key.bd_addr[2]<<8)+p_data->add_ble_key.bd_addr[3],
+ (p_data->add_ble_key.bd_addr[4]<<8)+p_data->add_ble_key.bd_addr[5]);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_add_ble_device
+**
+** Description This function adds an BLE device to an security database entry.
+** It is normally called during host startup to restore all required information
+** stored in the NVRAM.
+**
+** Parameters:
+**
+*******************************************************************************/
+void bta_dm_add_ble_device (tBTA_DM_MSG *p_data)
+{
+ if (!BTM_SecAddBleDevice (p_data->add_ble_device.bd_addr, NULL,
+ p_data->add_ble_device.dev_type ,
+ p_data->add_ble_device.addr_type))
+ {
+ APPL_TRACE_ERROR2 ("BTA_DM: Error adding BLE Device for device %08x%04x",
+ (p_data->add_ble_device.bd_addr[0]<<24)+(p_data->add_ble_device.bd_addr[1]<<16)+ \
+ (p_data->add_ble_device.bd_addr[2]<<8)+p_data->add_ble_device.bd_addr[3],
+ (p_data->add_ble_device.bd_addr[4]<<8)+p_data->add_ble_device.bd_addr[5]);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_add_ble_device
+**
+** Description This function adds an BLE device to an security database entry.
+** It is normally called during host startup to restore all required information
+** stored in the NVRAM.
+**
+** Parameters:
+**
+*******************************************************************************/
+void bta_dm_ble_passkey_reply (tBTA_DM_MSG *p_data)
+{
+ if (p_data->pin_reply.accept)
+ {
+
+ BTM_BlePasskeyReply(p_data->ble_passkey_reply.bd_addr, BTM_SUCCESS, p_data->ble_passkey_reply.passkey);
+ }
+ else
+ {
+ BTM_BlePasskeyReply(p_data->ble_passkey_reply.bd_addr, BTM_NOT_AUTHORIZED, p_data->ble_passkey_reply.passkey);
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_security_grant
+**
+** Description This function grant SMP security request access.
+**
+** Parameters:
+**
+*******************************************************************************/
+void bta_dm_security_grant (tBTA_DM_MSG *p_data)
+{
+ BTM_SecurityGrant(p_data->ble_sec_grant.bd_addr, p_data->ble_sec_grant.res);
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_ble_set_bg_conn_type
+**
+** Description This function set the BLE background connection type
+**
+** Parameters:
+**
+*******************************************************************************/
+void bta_dm_ble_set_bg_conn_type (tBTA_DM_MSG *p_data)
+{
+ BTM_BleSetBgConnType(p_data->ble_set_bd_conn_type.bg_conn_type,
+ p_data->ble_set_bd_conn_type.p_select_cback);
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_ble_set_conn_params
+**
+** Description This function set the preferred connection parameters.
+**
+** Parameters:
+**
+*******************************************************************************/
+void bta_dm_ble_set_conn_params (tBTA_DM_MSG *p_data)
+{
+ BTM_BleSetPrefConnParams(p_data->ble_set_conn_params.peer_bda,
+ p_data->ble_set_conn_params.conn_int_min,
+ p_data->ble_set_conn_params.conn_int_max,
+ p_data->ble_set_conn_params.slave_latency,
+ p_data->ble_set_conn_params.supervision_tout);
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_ble_set_scan_params
+**
+** Description This function set the preferred connection scan parameters.
+**
+** Parameters:
+**
+*******************************************************************************/
+void bta_dm_ble_set_scan_params (tBTA_DM_MSG *p_data)
+{
+ BTM_BleSetConnScanParams(p_data->ble_set_scan_params.scan_int,
+ p_data->ble_set_scan_params.scan_window);
+}
+
+#if ((defined BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE))
+
+/*******************************************************************************
+**
+** Function btm_dm_start_disc_gatt_services
+**
+** Description This function starts a GATT service search request.
+**
+** Parameters:
+**
+*******************************************************************************/
+static void btm_dm_start_disc_gatt_services (UINT16 conn_id)
+{
+ tBT_UUID *p_uuid = bta_dm_search_cb.p_srvc_uuid +
+ bta_dm_search_cb.num_uuid - bta_dm_search_cb.uuid_to_search;
+
+ p_uuid = bta_dm_search_cb.p_srvc_uuid +
+ bta_dm_search_cb.num_uuid - bta_dm_search_cb.uuid_to_search;
+
+ /* always search for all services */
+ BTA_GATTC_ServiceSearchRequest(conn_id, p_uuid);
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_gatt_disc_result
+**
+** Description This function process the GATT service search result.
+**
+** Parameters:
+**
+*******************************************************************************/
+static void bta_dm_gatt_disc_result(tBTA_GATT_ID service_id)
+{
+ tBTA_DM_SEARCH result;
+
+ /*
+ * This logic will not work for gatt case. We are checking against the bluetooth profiles here
+ * just copy the GATTID in raw data field and send it across.
+ */
+
+
+ if ( bta_dm_search_cb.ble_raw_used + sizeof(tBTA_GATT_ID) < bta_dm_search_cb.ble_raw_size )
+ {
+ APPL_TRACE_DEBUG3("ADDING BLE SERVICE uuid=0x%x, ble_ptr = 0x%x, ble_raw_used = 0x%x", service_id.uuid.uu.uuid16,bta_dm_search_cb.p_ble_rawdata,bta_dm_search_cb.ble_raw_used);
+
+ memcpy((bta_dm_search_cb.p_ble_rawdata + bta_dm_search_cb.ble_raw_used), &service_id,
+ sizeof(service_id) );
+
+ bta_dm_search_cb.ble_raw_used += sizeof(service_id);
+
+ }
+ else
+ {
+ APPL_TRACE_ERROR3("%s out of room to accomodate more service ids ble_raw_size = %d ble_raw_used = %d", __FUNCTION__,bta_dm_search_cb.ble_raw_size, bta_dm_search_cb.ble_raw_used );
+ }
+
+ APPL_TRACE_ERROR1("bta_dm_gatt_disc_result serivce_id len=%d ", service_id.uuid.len);
+ if ( bta_dm_search_cb.state != BTA_DM_SEARCH_IDLE)
+ {
+
+ /* send result back to app now, one by one */
+ bdcpy (result.disc_ble_res.bd_addr, bta_dm_search_cb.peer_bdaddr);
+ BCM_STRNCPY_S((char*)result.disc_ble_res.bd_name, sizeof(BD_NAME), bta_dm_get_remname(), (BD_NAME_LEN-1));
+ memcpy(&result.disc_ble_res.service, &service_id.uuid, sizeof(tBT_UUID));
+
+ bta_dm_search_cb.p_search_cback(BTA_DM_DISC_BLE_RES_EVT, &result);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_gatt_disc_complete
+**
+** Description This function process the GATT service search complete.
+**
+** Parameters:
+**
+*******************************************************************************/
+static void bta_dm_gatt_disc_complete(UINT16 conn_id, tBTA_GATT_STATUS status)
+{
+ tBTA_DM_MSG *p_msg;
+
+ APPL_TRACE_DEBUG1("bta_dm_gatt_disc_complete conn_id = %d",conn_id);
+
+ if (bta_dm_search_cb.uuid_to_search > 0) bta_dm_search_cb.uuid_to_search --;
+
+ if (status == BTA_GATT_OK && bta_dm_search_cb.uuid_to_search > 0)
+ {
+ btm_dm_start_disc_gatt_services(conn_id);
+ }
+ else
+ {
+ bta_dm_search_cb.uuid_to_search = 0;
+
+ /* no more services to be discovered */
+ if ((p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL)
+ {
+ p_msg->hdr.event = BTA_DM_DISCOVERY_RESULT_EVT;
+ p_msg->disc_result.result.disc_res.result = (status == BTA_GATT_OK) ? BTA_SUCCESS :BTA_FAILURE;
+ p_msg->disc_result.result.disc_res.services = bta_dm_search_cb.services_found;
+ bdcpy (p_msg->disc_result.result.disc_res.bd_addr, bta_dm_search_cb.peer_bdaddr);
+ BCM_STRNCPY_S((char*)p_msg->disc_result.result.disc_res.bd_name, sizeof(BD_NAME),
+ bta_dm_get_remname(), (BD_NAME_LEN-1));
+
+ /* make sure the string is terminated */
+ p_msg->disc_result.result.disc_res.bd_name[BD_NAME_LEN-1] = 0;
+
+ p_msg->disc_result.result.disc_res.device_type = BT_DEVICE_TYPE_BLE;
+ if ( bta_dm_search_cb.ble_raw_used > 0 )
+ {
+ p_msg->disc_result.result.disc_res.p_raw_data = GKI_getbuf(bta_dm_search_cb.ble_raw_used);
+
+ memcpy( p_msg->disc_result.result.disc_res.p_raw_data,
+ bta_dm_search_cb.p_ble_rawdata,
+ bta_dm_search_cb.ble_raw_used );
+
+ p_msg->disc_result.result.disc_res.raw_data_size = bta_dm_search_cb.ble_raw_used;
+ }
+ else
+ {
+ p_msg->disc_result.result.disc_res.p_raw_data = NULL;
+ bta_dm_search_cb.p_ble_rawdata = 0;
+ }
+
+ bta_sys_sendmsg(p_msg);
+ }
+ if (conn_id != BTA_GATT_INVALID_CONN_ID)
+ {
+ BTA_GATTC_Close(conn_id);
+ }
+ bta_dm_search_cb.conn_id = BTA_GATT_INVALID_CONN_ID;
+ bta_dm_search_cb.gatt_disc_active = FALSE;
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_dm_start_gatt_discovery
+**
+** Description This is GATT initiate the service search by open a GATT connection
+** first.
+**
+** Parameters:
+**
+*******************************************************************************/
+void btm_dm_start_gatt_discovery (BD_ADDR bd_addr)
+{
+ bta_dm_search_cb.gatt_disc_active = TRUE;
+ BTA_GATTC_Open(bta_dm_search_cb.client_if, bd_addr, TRUE);
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_cancel_gatt_discovery
+**
+** Description This is GATT cancel the GATT service search.
+**
+** Parameters:
+**
+*******************************************************************************/
+static void bta_dm_cancel_gatt_discovery(BD_ADDR bd_addr)
+{
+ if (bta_dm_search_cb.conn_id == BTA_GATT_INVALID_CONN_ID)
+ {
+ BTA_GATTC_CancelOpen(bta_dm_search_cb.client_if, bd_addr, TRUE);
+ }
+
+ bta_dm_gatt_disc_complete(bta_dm_search_cb.conn_id, (tBTA_GATT_STATUS) BTA_GATT_ERROR);
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_proc_open_evt
+**
+** Description process BTA_GATTC_OPEN_EVT in DM.
+**
+** Parameters:
+**
+*******************************************************************************/
+void bta_dm_proc_open_evt(tBTA_GATTC_OPEN *p_data)
+{
+ UINT8 *p1;
+ UINT8 *p2;
+
+ p1 = bta_dm_search_cb.peer_bdaddr;
+ p2 = p_data->remote_bda;
+
+ APPL_TRACE_DEBUG5("DM Search state= %d search_cb.peer_dbaddr: [%08x%04x] connected_bda= [%08x%04x] ",
+ bta_dm_search_cb.state,
+ ((p1[0])<<24)+((p1[1])<<16)+((p1[2])<<8)+(p1[3]),
+ ((p1[4])<<8)+ p1[5],
+ ((p2[0])<<24)+((p2[1])<<16)+((p2[2])<<8)+(p2[3]),
+ ((p2[4])<<8)+ p2[5]);
+
+ APPL_TRACE_DEBUG3("BTA_GATTC_OPEN_EVT conn_id = %d client_if=%d status = %d" ,
+ p_data->conn_id,
+ p_data->client_if,
+ p_data->status);
+
+ bta_dm_search_cb.conn_id = p_data->conn_id;
+
+ if (p_data->status == BTA_GATT_OK)
+ {
+ btm_dm_start_disc_gatt_services(p_data->conn_id);
+ }
+ else
+ {
+ bta_dm_gatt_disc_complete(BTA_GATT_INVALID_CONN_ID, p_data->status);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_gattc_callback
+**
+** Description This is GATT client callback function used in DM.
+**
+** Parameters:
+**
+*******************************************************************************/
+static void bta_dm_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC *p_data)
+{
+ APPL_TRACE_DEBUG1("bta_dm_gattc_callback event = %d", event);
+
+ switch (event)
+ {
+ case BTA_GATTC_REG_EVT:
+ APPL_TRACE_DEBUG1("BTA_GATTC_REG_EVT client_if = %d", p_data->reg_oper.client_if);
+ if (p_data->reg_oper.status == BTA_GATT_OK)
+ bta_dm_search_cb.client_if = p_data->reg_oper.client_if;
+ else
+ bta_dm_search_cb.client_if = BTA_GATTS_INVALID_IF;
+ break;
+
+ case BTA_GATTC_OPEN_EVT:
+ bta_dm_proc_open_evt(&p_data->open);
+ break;
+
+ case BTA_GATTC_SEARCH_RES_EVT:
+ bta_dm_gatt_disc_result(p_data->srvc_res.service_uuid.id);
+ break;
+
+ case BTA_GATTC_SEARCH_CMPL_EVT:
+ if ( bta_dm_search_cb.state != BTA_DM_SEARCH_IDLE)
+ bta_dm_gatt_disc_complete(p_data->search_cmpl.conn_id, p_data->search_cmpl.status);
+ break;
+
+ case BTA_GATTC_CLOSE_EVT:
+ APPL_TRACE_DEBUG1("BTA_GATTC_CLOSE_EVT reason = %d", p_data->close.reason);
+ /* in case of disconnect before search is completed */
+ if ( (bta_dm_search_cb.state != BTA_DM_SEARCH_IDLE) &&
+ !memcmp(p_data->close.remote_bda, bta_dm_search_cb.peer_bdaddr, BD_ADDR_LEN))
+ {
+ bta_dm_gatt_disc_complete((UINT16)BTA_GATT_INVALID_CONN_ID, (tBTA_GATT_STATUS) BTA_GATT_ERROR);
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+#endif /* BTA_GATT_INCLUDED */
+
+#endif /* BLE_INCLUDED */
diff --git a/bta/dm/bta_dm_api.c b/bta/dm/bta_dm_api.c
new file mode 100644
index 0000000..97e4777
--- /dev/null
+++ b/bta/dm/bta_dm_api.c
@@ -0,0 +1,1602 @@
+/*****************************************************************************
+**
+** Name: bta_dm_api.c
+**
+** Description: This is the API implementation file for the BTA
+** device manager.
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "gki.h"
+#include "bd.h"
+#include "bta_sys.h"
+#include "bta_api.h"
+#include "bta_dm_int.h"
+#include "bta_sys_int.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include <string.h>
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+static const tBTA_SYS_REG bta_dm_reg =
+{
+ bta_dm_sm_execute,
+ bta_dm_sm_disable
+};
+
+static const tBTA_SYS_REG bta_dm_search_reg =
+{
+ bta_dm_search_sm_execute,
+ bta_dm_search_sm_disable
+};
+
+/*******************************************************************************
+**
+** Function BTA_EnableBluetooth
+**
+** Description Enables bluetooth service. This function must be
+** called before any other functions in the BTA API are called.
+**
+**
+** Returns tBTA_STATUS
+**
+*******************************************************************************/
+tBTA_STATUS BTA_EnableBluetooth(tBTA_DM_SEC_CBACK *p_cback)
+{
+
+ tBTA_DM_API_ENABLE *p_msg;
+
+ /* Bluetooth disabling is in progress */
+ if (bta_dm_cb.disabling)
+ return BTA_FAILURE;
+
+ memset(&bta_dm_cb, 0, sizeof(bta_dm_cb));
+
+ GKI_sched_lock();
+ bta_sys_register (BTA_ID_DM, &bta_dm_reg );
+ bta_sys_register (BTA_ID_DM_SEARCH, &bta_dm_search_reg );
+
+ /* if UUID list is not provided as static data */
+ bta_sys_eir_register(bta_dm_eir_update_uuid);
+
+ GKI_sched_unlock();
+
+ if ((p_msg = (tBTA_DM_API_ENABLE *) GKI_getbuf(sizeof(tBTA_DM_API_ENABLE))) != NULL)
+ {
+ p_msg->hdr.event = BTA_DM_API_ENABLE_EVT;
+ p_msg->p_sec_cback = p_cback;
+ bta_sys_sendmsg(p_msg);
+ return BTA_SUCCESS;
+ }
+ return BTA_FAILURE;
+
+}
+
+/*******************************************************************************
+**
+** Function BTA_DisableBluetooth
+**
+** Description Disables bluetooth service. This function is called when
+** the application no longer needs bluetooth service
+**
+** Returns void
+**
+*******************************************************************************/
+tBTA_STATUS BTA_DisableBluetooth(void)
+{
+
+ BT_HDR *p_msg;
+
+ if ((p_msg = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_msg->event = BTA_DM_API_DISABLE_EVT;
+ bta_sys_sendmsg(p_msg);
+ }
+ else
+ {
+ return BTA_FAILURE;
+ }
+
+ return BTA_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function BTA_EnableTestMode
+**
+** Description Enables bluetooth device under test mode
+**
+**
+** Returns tBTA_STATUS
+**
+*******************************************************************************/
+tBTA_STATUS BTA_EnableTestMode(void)
+{
+ BT_HDR *p_msg;
+
+ APPL_TRACE_API0("BTA_EnableTestMode");
+
+ if ((p_msg = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_msg->event = BTA_DM_API_ENABLE_TEST_MODE_EVT;
+ bta_sys_sendmsg(p_msg);
+ return BTA_SUCCESS;
+ }
+ return BTA_FAILURE;
+}
+
+/*******************************************************************************
+**
+** Function BTA_DisableTestMode
+**
+** Description Disable bluetooth device under test mode
+**
+**
+** Returns None
+**
+*******************************************************************************/
+void BTA_DisableTestMode(void)
+{
+ BT_HDR *p_msg;
+
+ APPL_TRACE_API0("BTA_DisableTestMode");
+
+ if ((p_msg = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_msg->event = BTA_DM_API_DISABLE_TEST_MODE_EVT;
+ bta_sys_sendmsg(p_msg);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_DmIsDeviceUp
+**
+** Description Called during startup to check whether the bluetooth module
+** is up and ready
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+BOOLEAN BTA_DmIsDeviceUp(void)
+{
+
+ BOOLEAN status;
+
+ GKI_sched_lock();
+ status = BTM_IsDeviceUp();
+ GKI_sched_unlock();
+ return status;
+
+}
+
+/*******************************************************************************
+**
+** Function BTA_DmSetDeviceName
+**
+** Description This function sets the Bluetooth name of local device
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_DmSetDeviceName(char *p_name)
+{
+
+ tBTA_DM_API_SET_NAME *p_msg;
+
+ if ((p_msg = (tBTA_DM_API_SET_NAME *) GKI_getbuf(sizeof(tBTA_DM_API_SET_NAME))) != NULL)
+ {
+ p_msg->hdr.event = BTA_DM_API_SET_NAME_EVT;
+ /* truncate the name if needed */
+ BCM_STRNCPY_S(p_msg->name, sizeof(p_msg->name), p_name, BD_NAME_LEN-1);
+ p_msg->name[BD_NAME_LEN-1]=0;
+
+ bta_sys_sendmsg(p_msg);
+ }
+
+
+}
+
+/*******************************************************************************
+**
+** Function BTA_DmSetVisibility
+**
+** Description This function sets the Bluetooth connectable,
+** discoverable, pairable and conn paired only modes of local device
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_DmSetVisibility(tBTA_DM_DISC disc_mode, tBTA_DM_CONN conn_mode, UINT8 pairable_mode, UINT8 conn_filter )
+{
+
+ tBTA_DM_API_SET_VISIBILITY *p_msg;
+
+ if ((p_msg = (tBTA_DM_API_SET_VISIBILITY *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL)
+ {
+ p_msg->hdr.event = BTA_DM_API_SET_VISIBILITY_EVT;
+ p_msg->disc_mode = disc_mode;
+ p_msg->conn_mode = conn_mode;
+ p_msg->pair_mode = pairable_mode;
+ p_msg->conn_paired_only = conn_filter;
+
+
+ bta_sys_sendmsg(p_msg);
+ }
+
+
+}
+
+/*******************************************************************************
+**
+** Function BTA_DmSetScanParam
+**
+** Description This function sets the parameters for page scan and
+** inquiry scan.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_DmSetScanParam (UINT16 page_scan_interval, UINT16 page_scan_window,
+ UINT16 inquiry_scan_interval, UINT16 inquiry_scan_window)
+{
+ APPL_TRACE_API4 ("BTA_DmSetScanParam: %d, %d, %d, %d",
+ page_scan_interval, page_scan_window,
+ inquiry_scan_interval, inquiry_scan_window);
+
+ bta_dm_cb.page_scan_interval = page_scan_interval;
+ bta_dm_cb.page_scan_window = page_scan_window;
+ bta_dm_cb.inquiry_scan_interval = inquiry_scan_interval;
+ bta_dm_cb.inquiry_scan_window = inquiry_scan_window;
+}
+
+/*******************************************************************************
+**
+** Function BTA_DmSetAfhChannels
+**
+** Description This function sets the AFH first and
+** last disable channel, so channels within
+** that range are disabled.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_DmSetAfhChannels(UINT8 first, UINT8 last)
+{
+
+ tBTA_DM_API_SET_AFH_CHANNELS_EVT *p_msg;
+
+ if ((p_msg = (tBTA_DM_API_SET_AFH_CHANNELS_EVT *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL)
+ {
+ p_msg->hdr.event = BTA_DM_API_SET_AFH_CHANNELS_EVT;
+ p_msg->first = first;
+ p_msg->last = last;
+ bta_sys_sendmsg(p_msg);
+ }
+
+
+}
+
+/*******************************************************************************
+**
+** Function BTA_SetAfhChannelAssessment
+**
+** Description This function is called to set the channel assessment mode on or off
+**
+** Returns status
+**
+*******************************************************************************/
+void BTA_DmSetAfhChannelAssessment (BOOLEAN enable_or_disable)
+{
+ tBTA_DM_API_SET_AFH_CHANNEL_ASSESSMENT *p_msg;
+
+ if ((p_msg = (tBTA_DM_API_SET_AFH_CHANNEL_ASSESSMENT *) GKI_getbuf(sizeof(tBTA_DM_API_SET_AFH_CHANNEL_ASSESSMENT))) != NULL)
+ {
+ p_msg->hdr.event = BTA_DM_API_SET_AFH_CHANNEL_ASSESMENT_EVT;
+ p_msg->enable_or_disable = enable_or_disable;
+ bta_sys_sendmsg(p_msg);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_DmVendorSpecificCommand
+**
+** Description This function sends the vendor specific command
+** to the controller
+**
+**
+** Returns tBTA_STATUS
+**
+*******************************************************************************/
+tBTA_STATUS BTA_DmVendorSpecificCommand (UINT16 opcode, UINT8 param_len,
+ UINT8 *p_param_buf,
+ tBTA_VENDOR_CMPL_CBACK *p_cback)
+{
+
+ tBTA_DM_API_VENDOR_SPECIFIC_COMMAND *p_msg;
+ UINT16 size;
+
+ /* If p_cback is NULL, Notify application */
+ if (p_cback == NULL)
+ {
+ return (BTA_FAILURE);
+ }
+ else
+ {
+ size = sizeof (tBTA_DM_API_VENDOR_SPECIFIC_COMMAND) + param_len;
+ if ((p_msg = (tBTA_DM_API_VENDOR_SPECIFIC_COMMAND *) GKI_getbuf(size)) != NULL)
+ {
+ p_msg->hdr.event = BTA_DM_API_VENDOR_SPECIFIC_COMMAND_EVT;
+ p_msg->opcode = opcode;
+ p_msg->param_len = param_len;
+ p_msg->p_param_buf = (UINT8 *)(p_msg + 1);
+ p_msg->p_cback = p_cback;
+
+ memcpy (p_msg->p_param_buf, p_param_buf, param_len);
+
+ bta_sys_sendmsg(p_msg);
+ }
+ return (BTA_SUCCESS);
+ }
+}
+/*******************************************************************************
+**
+** Function BTA_DmSearch
+**
+** Description This function searches for peer Bluetooth devices. It performs
+** an inquiry and gets the remote name for devices. Service
+** discovery is done if services is non zero
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_DmSearch(tBTA_DM_INQ *p_dm_inq, tBTA_SERVICE_MASK services, tBTA_DM_SEARCH_CBACK *p_cback)
+{
+
+ tBTA_DM_API_SEARCH *p_msg;
+
+ if ((p_msg = (tBTA_DM_API_SEARCH *) GKI_getbuf(sizeof(tBTA_DM_API_SEARCH))) != NULL)
+ {
+ memset(p_msg, 0, sizeof(tBTA_DM_API_SEARCH));
+
+ p_msg->hdr.event = BTA_DM_API_SEARCH_EVT;
+ memcpy(&p_msg->inq_params, p_dm_inq, sizeof(tBTA_DM_INQ));
+ p_msg->services = services;
+ p_msg->p_cback = p_cback;
+ p_msg->rs_res = BTA_DM_RS_NONE;
+ bta_sys_sendmsg(p_msg);
+ }
+
+}
+
+
+/*******************************************************************************
+**
+** Function BTA_DmSearchCancel
+**
+** Description This function cancels a search initiated by BTA_DmSearch
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_DmSearchCancel(void)
+{
+ BT_HDR *p_msg;
+
+ if ((p_msg = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_msg->event = BTA_DM_API_SEARCH_CANCEL_EVT;
+ bta_sys_sendmsg(p_msg);
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function BTA_DmDiscover
+**
+** Description This function does service discovery for services of a
+** peer device
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_DmDiscover(BD_ADDR bd_addr, tBTA_SERVICE_MASK services,
+ tBTA_DM_SEARCH_CBACK *p_cback, BOOLEAN sdp_search)
+{
+ tBTA_DM_API_DISCOVER *p_msg;
+
+ if ((p_msg = (tBTA_DM_API_DISCOVER *) GKI_getbuf(sizeof(tBTA_DM_API_DISCOVER))) != NULL)
+ {
+ memset(p_msg, 0, sizeof(tBTA_DM_API_DISCOVER));
+
+ p_msg->hdr.event = BTA_DM_API_DISCOVER_EVT;
+ bdcpy(p_msg->bd_addr, bd_addr);
+ p_msg->services = services;
+ p_msg->p_cback = p_cback;
+ p_msg->sdp_search = sdp_search;
+ bta_sys_sendmsg(p_msg);
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function BTA_DmDiscoverUUID
+**
+** Description This function does service discovery for services of a
+** peer device
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_DmDiscoverUUID(BD_ADDR bd_addr, tSDP_UUID *uuid,
+ tBTA_DM_SEARCH_CBACK *p_cback, BOOLEAN sdp_search)
+{
+ tBTA_DM_API_DISCOVER *p_msg;
+
+ if ((p_msg = (tBTA_DM_API_DISCOVER *) GKI_getbuf(sizeof(tBTA_DM_API_DISCOVER))) != NULL)
+ {
+ p_msg->hdr.event = BTA_DM_API_DISCOVER_EVT;
+ bdcpy(p_msg->bd_addr, bd_addr);
+ p_msg->services = BTA_USER_SERVICE_MASK; //Not exposed at API level
+ p_msg->p_cback = p_cback;
+ p_msg->sdp_search = sdp_search;
+
+#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE
+ p_msg->num_uuid = 0;
+ p_msg->p_uuid = NULL;
+#endif
+ memcpy( &p_msg->uuid, uuid, sizeof(tSDP_UUID) );
+ bta_sys_sendmsg(p_msg);
+ }
+
+}
+/*******************************************************************************
+**
+** Function BTA_DmIsMaster
+**
+** Description This function checks if the local device is the master of
+** the link to the given device
+**
+** Returns TRUE if master.
+** FALSE if not.
+**
+*******************************************************************************/
+BOOLEAN BTA_DmIsMaster(BD_ADDR bd_addr)
+{
+ BOOLEAN is_master = FALSE;
+ UINT8 link_role;
+
+ BTM_GetRole(bd_addr, &link_role);
+ APPL_TRACE_API1("BTA_DmIsMaster role:x%x", link_role);
+ if(link_role == BTM_ROLE_MASTER)
+ {
+ is_master = TRUE;
+ }
+ return is_master;
+}
+
+/*******************************************************************************
+**
+** Function BTA_DmBond
+**
+** Description This function initiates a bonding procedure with a peer
+** device
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_DmBond(BD_ADDR bd_addr)
+{
+ tBTA_DM_API_BOND *p_msg;
+
+ if ((p_msg = (tBTA_DM_API_BOND *) GKI_getbuf(sizeof(tBTA_DM_API_BOND))) != NULL)
+ {
+ p_msg->hdr.event = BTA_DM_API_BOND_EVT;
+ bdcpy(p_msg->bd_addr, bd_addr);
+ bta_sys_sendmsg(p_msg);
+ }
+
+
+}
+
+/*******************************************************************************
+**
+** Function BTA_DmBondCancel
+**
+** Description This function cancels the bonding procedure with a peer
+** device
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_DmBondCancel(BD_ADDR bd_addr)
+{
+ tBTA_DM_API_BOND_CANCEL *p_msg;
+
+ if ((p_msg = (tBTA_DM_API_BOND_CANCEL *) GKI_getbuf(sizeof(tBTA_DM_API_BOND_CANCEL))) != NULL)
+ {
+ p_msg->hdr.event = BTA_DM_API_BOND_CANCEL_EVT;
+ bdcpy(p_msg->bd_addr, bd_addr);
+ bta_sys_sendmsg(p_msg);
+ }
+
+
+}
+
+/*******************************************************************************
+**
+** Function BTA_DmPinReply
+**
+** Description This function provides a pincode for a remote device when
+** one is requested by DM through BTA_DM_PIN_REQ_EVT
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_DmPinReply(BD_ADDR bd_addr, BOOLEAN accept, UINT8 pin_len, UINT8 *p_pin)
+
+{
+ tBTA_DM_API_PIN_REPLY *p_msg;
+
+ if ((p_msg = (tBTA_DM_API_PIN_REPLY *) GKI_getbuf(sizeof(tBTA_DM_API_PIN_REPLY))) != NULL)
+ {
+ p_msg->hdr.event = BTA_DM_API_PIN_REPLY_EVT;
+ bdcpy(p_msg->bd_addr, bd_addr);
+ p_msg->accept = accept;
+ if(accept)
+ {
+ p_msg->pin_len = pin_len;
+ memcpy(p_msg->p_pin, p_pin, pin_len);
+ }
+ bta_sys_sendmsg(p_msg);
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function BTA_DmLinkPolicy
+**
+** Description This function sets/clears the link policy mask to the given
+** bd_addr.
+** If clearing the sniff or park mode mask, the link is put
+** in active mode.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_DmLinkPolicy(BD_ADDR bd_addr, tBTA_DM_LP_MASK policy_mask,
+ BOOLEAN set)
+{
+ tBTA_DM_API_LINK_POLICY *p_msg;
+
+ if ((p_msg = (tBTA_DM_API_LINK_POLICY *) GKI_getbuf(sizeof(tBTA_DM_API_LINK_POLICY))) != NULL)
+ {
+ p_msg->hdr.event = BTA_DM_API_LINK_POLICY_EVT;
+ bdcpy(p_msg->bd_addr, bd_addr);
+ p_msg->policy_mask = policy_mask;
+ p_msg->set = set;
+ bta_sys_sendmsg(p_msg);
+ }
+}
+
+
+#if (BTM_OOB_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function BTA_DmLocalOob
+**
+** Description This function retrieves the OOB data from local controller.
+** The result is reported by bta_dm_co_loc_oob().
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_DmLocalOob(void)
+{
+ tBTA_DM_API_LOC_OOB *p_msg;
+
+ if ((p_msg = (tBTA_DM_API_LOC_OOB *) GKI_getbuf(sizeof(tBTA_DM_API_LOC_OOB))) != NULL)
+ {
+ p_msg->hdr.event = BTA_DM_API_LOC_OOB_EVT;
+ bta_sys_sendmsg(p_msg);
+ }
+}
+#endif /* BTM_OOB_INCLUDED */
+/*******************************************************************************
+**
+** Function BTA_DmConfirm
+**
+** Description This function accepts or rejects the numerical value of the
+** Simple Pairing process on BTA_DM_SP_CFM_REQ_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_DmConfirm(BD_ADDR bd_addr, BOOLEAN accept)
+{
+ tBTA_DM_API_CONFIRM *p_msg;
+
+ if ((p_msg = (tBTA_DM_API_CONFIRM *) GKI_getbuf(sizeof(tBTA_DM_API_CONFIRM))) != NULL)
+ {
+ p_msg->hdr.event = BTA_DM_API_CONFIRM_EVT;
+ bdcpy(p_msg->bd_addr, bd_addr);
+ p_msg->accept = accept;
+ bta_sys_sendmsg(p_msg);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_DmPasskeyCancel
+**
+** Description This function is called to cancel the simple pairing process
+** reported by BTA_DM_SP_KEY_NOTIF_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
+void BTA_DmPasskeyCancel(BD_ADDR bd_addr)
+{
+ tBTA_DM_API_PASKY_CANCEL *p_msg;
+
+ if ((p_msg = (tBTA_DM_API_PASKY_CANCEL *) \
+ GKI_getbuf(sizeof(tBTA_DM_API_PASKY_CANCEL))) != NULL)
+ {
+ p_msg->hdr.event = BTA_DM_API_PASKY_CANCEL_EVT;
+ bdcpy(p_msg->bd_addr, bd_addr);
+ bta_sys_sendmsg(p_msg);
+ }
+}
+#endif
+
+
+/*******************************************************************************
+**
+** Function BTA_DmAddDevice
+**
+** Description This function adds a device to the security database list of
+** peer device
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_DmAddDevice(BD_ADDR bd_addr, DEV_CLASS dev_class, LINK_KEY link_key,
+ tBTA_SERVICE_MASK trusted_mask, BOOLEAN is_trusted,
+ UINT8 key_type, tBTA_IO_CAP io_cap)
+{
+
+ tBTA_DM_API_ADD_DEVICE *p_msg;
+
+ if ((p_msg = (tBTA_DM_API_ADD_DEVICE *) GKI_getbuf(sizeof(tBTA_DM_API_ADD_DEVICE))) != NULL)
+ {
+ memset (p_msg, 0, sizeof(tBTA_DM_API_ADD_DEVICE));
+
+ p_msg->hdr.event = BTA_DM_API_ADD_DEVICE_EVT;
+ bdcpy(p_msg->bd_addr, bd_addr);
+ p_msg->tm = trusted_mask;
+ p_msg->is_trusted = is_trusted;
+ p_msg->io_cap = io_cap;
+
+ if (link_key)
+ {
+ p_msg->link_key_known = TRUE;
+ p_msg->key_type = key_type;
+ memcpy(p_msg->link_key, link_key, LINK_KEY_LEN);
+ }
+
+ /* Load device class if specified */
+ if (dev_class)
+ {
+ p_msg->dc_known = TRUE;
+ memcpy (p_msg->dc, dev_class, DEV_CLASS_LEN);
+ }
+
+ memset (p_msg->bd_name, 0, BD_NAME_LEN);
+ memset (p_msg->features, 0, BD_FEATURES_LEN);
+
+ bta_sys_sendmsg(p_msg);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function BTA_DmRemoveDevice
+**
+** Description This function removes a device fromthe security database list of
+** peer device
+**
+**
+** Returns void
+**
+*******************************************************************************/
+tBTA_STATUS BTA_DmRemoveDevice(BD_ADDR bd_addr)
+{
+
+ BOOLEAN device_ok_to_remove = TRUE;
+
+ GKI_sched_lock();
+
+ if (BTM_IsAclConnectionUp(bd_addr))
+ {
+ /* Don't allow deletion while connection is active */
+ device_ok_to_remove = FALSE;
+ }
+ else /* Ok to remove the device in application layer */
+ {
+ BTM_SecDeleteDevice(bd_addr);
+ }
+ GKI_sched_unlock();
+
+ if(device_ok_to_remove)
+ return BTA_SUCCESS;
+ else
+ return BTA_FAILURE;
+}
+
+/*******************************************************************************
+**
+** Function BTA_DmAddDevWithName
+**
+** Description This function is newer version of BTA_DmAddDevice()
+** which added bd_name and features as input parameters.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_DmAddDevWithName (BD_ADDR bd_addr, DEV_CLASS dev_class,
+ BD_NAME bd_name, BD_FEATURES features,
+ LINK_KEY link_key, tBTA_SERVICE_MASK trusted_mask,
+ BOOLEAN is_trusted, UINT8 key_type, tBTA_IO_CAP io_cap)
+{
+ tBTA_DM_API_ADD_DEVICE *p_msg;
+
+ if ((p_msg = (tBTA_DM_API_ADD_DEVICE *) GKI_getbuf(sizeof(tBTA_DM_API_ADD_DEVICE))) != NULL)
+ {
+ memset (p_msg, 0, sizeof(tBTA_DM_API_ADD_DEVICE));
+
+ p_msg->hdr.event = BTA_DM_API_ADD_DEVICE_EVT;
+ bdcpy(p_msg->bd_addr, bd_addr);
+ p_msg->tm = trusted_mask;
+ p_msg->is_trusted = is_trusted;
+ p_msg->io_cap = io_cap;
+
+ if (link_key)
+ {
+ p_msg->link_key_known = TRUE;
+ p_msg->key_type = key_type;
+ memcpy(p_msg->link_key, link_key, LINK_KEY_LEN);
+ }
+
+ /* Load device class if specified */
+ if (dev_class)
+ {
+ p_msg->dc_known = TRUE;
+ memcpy (p_msg->dc, dev_class, DEV_CLASS_LEN);
+ }
+
+ if (bd_name)
+ memcpy(p_msg->bd_name, bd_name, BD_NAME_LEN);
+
+ if (features)
+ memcpy(p_msg->features, features, BD_FEATURES_LEN);
+
+ bta_sys_sendmsg(p_msg);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_DmAuthorizeReply
+**
+** Description This function provides an authorization reply when authorization
+** is requested by BTA through BTA_DM_AUTHORIZE_EVT
+**
+**
+** Returns tBTA_STATUS
+**
+*******************************************************************************/
+void BTA_DmAuthorizeReply(BD_ADDR bd_addr, tBTA_SERVICE_ID service, tBTA_AUTH_RESP response)
+{
+
+ tBTA_DM_API_AUTH_REPLY *p_msg;
+
+ if ((p_msg = (tBTA_DM_API_AUTH_REPLY *) GKI_getbuf(sizeof(tBTA_DM_API_AUTH_REPLY))) != NULL)
+ {
+ p_msg->hdr.event = BTA_DM_API_AUTH_REPLY_EVT;
+ bdcpy(p_msg->bd_addr, bd_addr);
+ p_msg->service = service;
+ p_msg->response = response;
+
+ bta_sys_sendmsg(p_msg);
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function BTA_DmSignalStrength
+**
+** Description This function initiates RSSI and channnel quality
+** measurments. BTA_DM_SIG_STRENGTH_EVT is sent to
+** application with the values of RSSI and channel
+** quality
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_DmSignalStrength(tBTA_SIG_STRENGTH_MASK mask, UINT16 period, BOOLEAN start)
+{
+
+ tBTA_API_DM_SIG_STRENGTH *p_msg;
+
+ if ((p_msg = (tBTA_API_DM_SIG_STRENGTH *) GKI_getbuf(sizeof(tBTA_API_DM_SIG_STRENGTH))) != NULL)
+ {
+ p_msg->hdr.event = BTA_API_DM_SIG_STRENGTH_EVT;
+ p_msg->mask = mask;
+ p_msg->period = period;
+ p_msg->start = start;
+
+ bta_sys_sendmsg(p_msg);
+ }
+
+
+}
+
+/*******************************************************************************
+**
+** Function BTA_DmWriteInqTxPower
+**
+** Description This command is used to write the inquiry transmit power level
+** used to transmit the inquiry (ID) data packets.
+**
+** Parameters tx_power - tx inquiry power to use, valid value is -70 ~ 20
+
+** Returns void
+**
+*******************************************************************************/
+void BTA_DmWriteInqTxPower(INT8 tx_power)
+{
+
+ tBTA_API_DM_TX_INQPWR *p_msg;
+
+ if ((p_msg = (tBTA_API_DM_TX_INQPWR *) GKI_getbuf(sizeof(tBTA_API_DM_TX_INQPWR))) != NULL)
+ {
+ p_msg->hdr.event = BTA_DM_API_TX_INQPWR_EVT;
+ p_msg->tx_power = tx_power;
+
+ bta_sys_sendmsg(p_msg);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function BTA_DmEirAddUUID
+**
+** Description This function is called to add UUID into EIR.
+**
+** Parameters tBT_UUID - UUID
+**
+** Returns None
+**
+*******************************************************************************/
+void BTA_DmEirAddUUID (tBT_UUID *p_uuid)
+{
+#if ( BTM_EIR_SERVER_INCLUDED == TRUE )&&( BTA_EIR_CANNED_UUID_LIST != TRUE )&&(BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0)
+ tBTA_DM_API_UPDATE_EIR_UUID *p_msg;
+
+ if ((p_msg = (tBTA_DM_API_UPDATE_EIR_UUID *) GKI_getbuf(sizeof(tBTA_DM_API_UPDATE_EIR_UUID))) != NULL)
+ {
+ p_msg->hdr.event = BTA_DM_API_UPDATE_EIR_UUID_EVT;
+ p_msg->is_add = TRUE;
+ memcpy (&(p_msg->uuid), p_uuid, sizeof(tBT_UUID));
+
+ bta_sys_sendmsg(p_msg);
+ }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function BTA_DmEirRemoveUUID
+**
+** Description This function is called to remove UUID from EIR.
+**
+** Parameters tBT_UUID - UUID
+**
+** Returns None
+**
+*******************************************************************************/
+void BTA_DmEirRemoveUUID (tBT_UUID *p_uuid)
+{
+#if ( BTM_EIR_SERVER_INCLUDED == TRUE )&&( BTA_EIR_CANNED_UUID_LIST != TRUE )&&(BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0)
+ tBTA_DM_API_UPDATE_EIR_UUID *p_msg;
+
+ if ((p_msg = (tBTA_DM_API_UPDATE_EIR_UUID *) GKI_getbuf(sizeof(tBTA_DM_API_UPDATE_EIR_UUID))) != NULL)
+ {
+ p_msg->hdr.event = BTA_DM_API_UPDATE_EIR_UUID_EVT;
+ p_msg->is_add = FALSE;
+ memcpy (&(p_msg->uuid), p_uuid, sizeof(tBT_UUID));
+
+ bta_sys_sendmsg(p_msg);
+ }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function BTA_DmSetEIRConfig
+**
+** Description This function is called to override the BTA default EIR parameters.
+** This funciton is only valid in a system where BTU & App task
+** are in the same memory space.
+**
+** Parameters Pointer to User defined EIR config
+**
+** Returns None
+**
+*******************************************************************************/
+void BTA_DmSetEIRConfig (tBTA_DM_EIR_CONF *p_eir_cfg)
+{
+#if (BTM_EIR_SERVER_INCLUDED == TRUE)
+ tBTA_DM_API_SET_EIR_CONFIG *p_msg;
+
+ if ((p_msg = (tBTA_DM_API_SET_EIR_CONFIG *) GKI_getbuf(sizeof(tBTA_DM_API_SET_EIR_CONFIG))) != NULL)
+ {
+ p_msg->hdr.event = BTA_DM_API_SET_EIR_CONFIG_EVT;
+ p_msg->p_eir_cfg = p_eir_cfg;
+
+ bta_sys_sendmsg(p_msg);
+ }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function BTA_CheckEirData
+**
+** Description This function is called to get EIR data from significant part.
+**
+** Parameters p_eir - pointer of EIR significant part
+** type - finding EIR data type
+** p_length - return the length of EIR data
+**
+** Returns pointer of EIR data
+**
+*******************************************************************************/
+UINT8 *BTA_CheckEirData( UINT8 *p_eir, UINT8 type, UINT8 *p_length )
+{
+#if ( BTM_EIR_CLIENT_INCLUDED == TRUE )
+ return BTM_CheckEirData( p_eir, type, p_length );
+#else
+ return NULL;
+#endif
+}
+
+/*******************************************************************************
+**
+** Function BTA_GetEirService
+**
+** Description This function is called to get BTA service mask from EIR.
+**
+** Parameters p_eir - pointer of EIR significant part
+** p_services - return the BTA service mask
+**
+** Returns None
+**
+*******************************************************************************/
+extern const UINT16 bta_service_id_to_uuid_lkup_tbl [];
+void BTA_GetEirService( UINT8 *p_eir, tBTA_SERVICE_MASK *p_services )
+{
+#if ( BTM_EIR_CLIENT_INCLUDED == TRUE )
+ UINT8 xx, yy;
+ UINT8 num_uuid, max_num_uuid = 32;
+ UINT8 uuid_list[32*LEN_UUID_16];
+ UINT16 *p_uuid16 = (UINT16 *)uuid_list;
+ tBTA_SERVICE_MASK mask;
+
+ BTM_GetEirUuidList( p_eir, LEN_UUID_16, &num_uuid, uuid_list, max_num_uuid);
+ for( xx = 0; xx < num_uuid; xx++ )
+ {
+ mask = 1;
+ for( yy = 0; yy < BTA_MAX_SERVICE_ID; yy++ )
+ {
+ if( *(p_uuid16 + xx) == bta_service_id_to_uuid_lkup_tbl[yy] )
+ {
+ *p_services |= mask;
+ break;
+ }
+ mask <<= 1;
+ }
+
+ /* for HSP v1.2 only device */
+ if (*(p_uuid16 + xx) == UUID_SERVCLASS_HEADSET_HS)
+ *p_services |= BTA_HSP_SERVICE_MASK;
+ }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function BTA_DmUseSsr
+**
+** Description This function is called to check if the connected peer device
+** supports SSR or not.
+**
+** Returns TRUE, if SSR is supported
+**
+*******************************************************************************/
+BOOLEAN BTA_DmUseSsr( BD_ADDR bd_addr )
+{
+ BOOLEAN use_ssr = FALSE;
+ tBTA_DM_PEER_DEVICE * p_dev = bta_dm_find_peer_device(bd_addr);
+ if(p_dev && (p_dev->info & BTA_DM_DI_USE_SSR) )
+ use_ssr = TRUE;
+ return use_ssr;
+}
+
+/*******************************************************************************
+** Device Identification (DI) Server Functions
+*******************************************************************************/
+/*******************************************************************************
+**
+** Function BTA_DmSetLocalDiRecord
+**
+** Description This function adds a DI record to the local SDP database.
+**
+** Returns BTA_SUCCESS if record set sucessfully, otherwise error code.
+**
+*******************************************************************************/
+tBTA_STATUS BTA_DmSetLocalDiRecord( tBTA_DI_RECORD *p_device_info,
+ UINT32 *p_handle )
+{
+ tBTA_STATUS status = BTA_FAILURE;
+
+ if(bta_dm_di_cb.di_num < BTA_DI_NUM_MAX)
+ {
+ if(SDP_SetLocalDiRecord((tSDP_DI_RECORD *)p_device_info, p_handle) == SDP_SUCCESS)
+ {
+ if(!p_device_info->primary_record)
+ {
+ bta_dm_di_cb.di_handle[bta_dm_di_cb.di_num] = *p_handle;
+ bta_dm_di_cb.di_num ++;
+ }
+
+ bta_sys_add_uuid(UUID_SERVCLASS_PNP_INFORMATION);
+ status = BTA_SUCCESS;
+ }
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function BTA_DmGetLocalDiRecord
+**
+** Description Get a specified DI record to the local SDP database. If no
+** record handle is provided, the primary DI record will be
+** returned.
+**
+** Fills in the device information of the record
+** p_handle - if p_handle == 0, the primary record is returned
+**
+** Returns BTA_SUCCESS if record set sucessfully, otherwise error code.
+**
+*******************************************************************************/
+tBTA_STATUS BTA_DmGetLocalDiRecord( tBTA_DI_GET_RECORD *p_device_info,
+ UINT32 *p_handle )
+{
+ UINT16 status;
+
+ status = SDP_GetLocalDiRecord(p_device_info, p_handle);
+
+ if (status == SDP_SUCCESS)
+ return BTA_SUCCESS;
+ else
+ return BTA_FAILURE;
+
+}
+
+/*******************************************************************************
+** Device Identification (DI) Client Functions
+*******************************************************************************/
+/*******************************************************************************
+**
+** Function BTA_DmDiDiscover
+**
+** Description This function queries a remote device for DI information.
+**
+**
+** Returns None.
+**
+*******************************************************************************/
+void BTA_DmDiDiscover( BD_ADDR remote_device, tBTA_DISCOVERY_DB *p_db,
+ UINT32 len, tBTA_DM_SEARCH_CBACK *p_cback )
+{
+ tBTA_DM_API_DI_DISC *p_msg;
+
+ if ((p_msg = (tBTA_DM_API_DI_DISC *) GKI_getbuf(sizeof(tBTA_DM_API_DI_DISC))) != NULL)
+ {
+ bdcpy(p_msg->bd_addr, remote_device);
+ p_msg->hdr.event = BTA_DM_API_DI_DISCOVER_EVT;
+ p_msg->p_sdp_db = p_db;
+ p_msg->len = len;
+ p_msg->p_cback = p_cback;
+
+ bta_sys_sendmsg(p_msg);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_DmGetDiRecord
+**
+** Description This function retrieves a remote device's DI record from
+** the specified database.
+**
+** Returns BTA_SUCCESS if Get DI record is succeed.
+** BTA_FAILURE if Get DI record failed.
+**
+*******************************************************************************/
+tBTA_STATUS BTA_DmGetDiRecord( UINT8 get_record_index, tBTA_DI_GET_RECORD *p_device_info,
+ tBTA_DISCOVERY_DB *p_db )
+{
+ if (SDP_GetDiRecord(get_record_index, p_device_info, p_db) != SDP_SUCCESS)
+ return BTA_FAILURE;
+ else
+ return BTA_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function BTA_SysFeatures
+**
+** Description This function is called to set system features.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_SysFeatures (UINT16 sys_features)
+{
+ bta_sys_cb.sys_features = sys_features;
+
+ APPL_TRACE_API1("BTA_SysFeatures: sys_features = %d", sys_features);
+}
+
+/*******************************************************************************
+**
+** Function bta_dmexecutecallback
+**
+** Description This function will request BTA to execute a call back in the context of BTU task
+** This API was named in lower case because it is only intended
+** for the internal customers(like BSA).
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dmexecutecallback (tBTA_DM_EXEC_CBACK* p_callback, void * p_param)
+{
+ tBTA_DM_API_EXECUTE_CBACK *p_msg;
+
+ if ((p_msg = (tBTA_DM_API_EXECUTE_CBACK *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL)
+ {
+ p_msg->hdr.event = BTA_DM_API_EXECUTE_CBACK_EVT;
+ p_msg->p_param= p_param;
+ p_msg->p_exec_cback= p_callback;
+ bta_sys_sendmsg(p_msg);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_DmAddBleKey
+**
+** Description Add/modify LE device information. This function will be
+** normally called during host startup to restore all required
+** information stored in the NVRAM.
+**
+** Parameters: bd_addr - BD address of the peer
+** p_le_key - LE key values.
+** key_type - LE SMP key type.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_DmAddBleKey (BD_ADDR bd_addr, tBTA_LE_KEY_VALUE *p_le_key, tBTA_LE_KEY_TYPE key_type)
+{
+#if BLE_INCLUDED == TRUE
+
+ tBTA_DM_API_ADD_BLEKEY *p_msg;
+
+ if ((p_msg = (tBTA_DM_API_ADD_BLEKEY *) GKI_getbuf(sizeof(tBTA_DM_API_ADD_BLEKEY))) != NULL)
+ {
+ memset (p_msg, 0, sizeof(tBTA_DM_API_ADD_BLEKEY));
+
+ p_msg->hdr.event = BTA_DM_API_ADD_BLEKEY_EVT;
+ p_msg->key_type = key_type;
+ bdcpy(p_msg->bd_addr, bd_addr);
+ memcpy(&p_msg->blekey, p_le_key, sizeof(tBTA_LE_KEY_VALUE));
+
+ bta_sys_sendmsg(p_msg);
+ }
+
+#endif
+}
+
+/*******************************************************************************
+**
+** Function BTA_DmAddBleDevice
+**
+** Description Add a BLE device. This function will be normally called
+** during host startup to restore all required information
+** for a LE device stored in the NVRAM.
+**
+** Parameters: bd_addr - BD address of the peer
+** dev_type - Remote device's device type.
+** addr_type - LE device address type.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_DmAddBleDevice(BD_ADDR bd_addr, tBLE_ADDR_TYPE addr_type, tBT_DEVICE_TYPE dev_type)
+{
+#if BLE_INCLUDED == TRUE
+ tBTA_DM_API_ADD_BLE_DEVICE *p_msg;
+
+ if ((p_msg = (tBTA_DM_API_ADD_BLE_DEVICE *) GKI_getbuf(sizeof(tBTA_DM_API_ADD_BLE_DEVICE))) != NULL)
+ {
+ memset (p_msg, 0, sizeof(tBTA_DM_API_ADD_BLE_DEVICE));
+
+ p_msg->hdr.event = BTA_DM_API_ADD_BLEDEVICE_EVT;
+ bdcpy(p_msg->bd_addr, bd_addr);
+ p_msg->addr_type = addr_type;
+ p_msg->dev_type = dev_type;
+
+ bta_sys_sendmsg(p_msg);
+ }
+#endif
+}
+/*******************************************************************************
+**
+** Function BTA_DmBlePasskeyReply
+**
+** Description Send BLE SMP passkey reply.
+**
+** Parameters: bd_addr - BD address of the peer
+** accept - passkey entry sucessful or declined.
+** passkey - passkey value, must be a 6 digit number,
+** can be lead by 0.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_DmBlePasskeyReply(BD_ADDR bd_addr, BOOLEAN accept, UINT32 passkey)
+{
+#if BLE_INCLUDED == TRUE
+ tBTA_DM_API_PASSKEY_REPLY *p_msg;
+
+ if ((p_msg = (tBTA_DM_API_PASSKEY_REPLY *) GKI_getbuf(sizeof(tBTA_DM_API_PASSKEY_REPLY))) != NULL)
+ {
+ memset(p_msg, 0, sizeof(tBTA_DM_API_PASSKEY_REPLY));
+
+ p_msg->hdr.event = BTA_DM_API_BLE_PASSKEY_REPLY_EVT;
+ bdcpy(p_msg->bd_addr, bd_addr);
+ p_msg->accept = accept;
+
+ if(accept)
+ {
+ p_msg->passkey = passkey;
+ }
+ bta_sys_sendmsg(p_msg);
+ }
+#endif
+}
+/*******************************************************************************
+**
+** Function BTA_DmBleSecurityGrant
+**
+** Description Grant security request access.
+**
+** Parameters: bd_addr - BD address of the peer
+** res - security grant status.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_DmBleSecurityGrant(BD_ADDR bd_addr, tBTA_DM_BLE_SEC_GRANT res)
+{
+#if BLE_INCLUDED == TRUE
+ tBTA_DM_API_BLE_SEC_GRANT *p_msg;
+
+ if ((p_msg = (tBTA_DM_API_BLE_SEC_GRANT *) GKI_getbuf(sizeof(tBTA_DM_API_BLE_SEC_GRANT))) != NULL)
+ {
+ memset(p_msg, 0, sizeof(tBTA_DM_API_BLE_SEC_GRANT));
+
+ p_msg->hdr.event = BTA_DM_API_BLE_SEC_GRANT_EVT;
+ bdcpy(p_msg->bd_addr, bd_addr);
+ p_msg->res = res;
+
+ bta_sys_sendmsg(p_msg);
+ }
+#endif
+}
+/*******************************************************************************
+**
+** Function BTA_DmSetBlePrefConnParams
+**
+** Description This function is called to set the preferred connection
+** parameters when default connection parameter is not desired.
+**
+** Parameters: bd_addr - BD address of the peripheral
+** scan_interval - scan interval
+** scan_window - scan window
+** min_conn_int - minimum preferred connection interval
+** max_conn_int - maximum preferred connection interval
+** slave_latency - preferred slave latency
+** supervision_tout - preferred supervision timeout
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_DmSetBlePrefConnParams(BD_ADDR bd_addr,
+ UINT16 min_conn_int, UINT16 max_conn_int,
+ UINT16 slave_latency, UINT16 supervision_tout )
+{
+#if BLE_INCLUDED == TRUE
+ tBTA_DM_API_BLE_CONN_PARAMS *p_msg;
+
+ if ((p_msg = (tBTA_DM_API_BLE_CONN_PARAMS *) GKI_getbuf(sizeof(tBTA_DM_API_BLE_CONN_PARAMS))) != NULL)
+ {
+ memset(p_msg, 0, sizeof(tBTA_DM_API_BLE_CONN_PARAMS));
+
+ p_msg->hdr.event = BTA_DM_API_BLE_CONN_PARAM_EVT;
+
+ memcpy(p_msg->peer_bda, bd_addr, BD_ADDR_LEN);
+
+ p_msg->conn_int_max = max_conn_int;
+ p_msg->conn_int_min = min_conn_int;
+ p_msg->slave_latency = slave_latency;
+ p_msg->supervision_tout = supervision_tout;
+
+ bta_sys_sendmsg(p_msg);
+ }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function BTA_DmSetBleConnScanParams
+**
+** Description This function is called to set scan parameters used in
+** BLE connection request
+**
+** Parameters: scan_interval - scan interval
+** scan_window - scan window
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_DmSetBleConnScanParams(UINT16 scan_interval, UINT16 scan_window )
+{
+#if BLE_INCLUDED == TRUE
+ tBTA_DM_API_BLE_SCAN_PARAMS *p_msg;
+
+ if ((p_msg = (tBTA_DM_API_BLE_SCAN_PARAMS *) GKI_getbuf(sizeof(tBTA_DM_API_BLE_SCAN_PARAMS))) != NULL)
+ {
+ memset(p_msg, 0, sizeof(tBTA_DM_API_BLE_SCAN_PARAMS));
+
+ p_msg->hdr.event = BTA_DM_API_BLE_SCAN_PARAM_EVT;
+
+ p_msg->scan_int = scan_interval;
+ p_msg->scan_window = scan_window;
+
+ bta_sys_sendmsg(p_msg);
+ }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function BTA_DmBleSetBgConnType
+**
+** Description This function is called to set BLE connectable mode for a
+** peripheral device.
+**
+** Parameters bg_conn_type: it can be auto connection, or selective connection.
+** p_select_cback: callback function when selective connection procedure
+** is being used.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_DmBleSetBgConnType(tBTA_DM_BLE_CONN_TYPE bg_conn_type, tBTA_DM_BLE_SEL_CBACK *p_select_cback)
+{
+#if BLE_INCLUDED == TRUE
+ tBTA_DM_API_BLE_SET_BG_CONN_TYPE *p_msg;
+
+ if ((p_msg = (tBTA_DM_API_BLE_SET_BG_CONN_TYPE *) GKI_getbuf(sizeof(tBTA_DM_API_BLE_SET_BG_CONN_TYPE))) != NULL)
+ {
+ memset(p_msg, 0, sizeof(tBTA_DM_API_BLE_SET_BG_CONN_TYPE));
+
+ p_msg->hdr.event = BTA_DM_API_BLE_SET_BG_CONN_TYPE;
+ p_msg->bg_conn_type = bg_conn_type;
+ p_msg->p_select_cback = p_select_cback;
+
+ bta_sys_sendmsg(p_msg);
+ }
+#endif
+}
+/*******************************************************************************
+**
+** Function BTA_DmDiscoverExt
+**
+** Description This function does service discovery for services of a
+** peer device. When services.num_uuid is 0, it indicates all
+** GATT based services are to be searched; other wise a list of
+** UUID of interested services should be provided through
+** p_services->p_uuid.
+**
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_DmDiscoverExt(BD_ADDR bd_addr, tBTA_SERVICE_MASK_EXT *p_services,
+ tBTA_DM_SEARCH_CBACK *p_cback, BOOLEAN sdp_search)
+{
+#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE
+ tBTA_DM_API_DISCOVER *p_msg;
+ UINT16 len = p_services ? (sizeof(tBTA_DM_API_DISCOVER) + sizeof(tBT_UUID) * p_services->num_uuid) :
+ sizeof(tBTA_DM_API_DISCOVER);
+
+ if ((p_msg = (tBTA_DM_API_DISCOVER *) GKI_getbuf(len)) != NULL)
+ {
+ memset(p_msg, 0, len);
+
+ p_msg->hdr.event = BTA_DM_API_DISCOVER_EVT;
+ bdcpy(p_msg->bd_addr, bd_addr);
+ p_msg->p_cback = p_cback;
+ p_msg->sdp_search = sdp_search;
+
+ if (p_services != NULL)
+ {
+ p_msg->services = p_services->srvc_mask;
+ p_msg->num_uuid = p_services->num_uuid;
+
+ if (p_services->num_uuid != 0)
+ {
+ p_msg->p_uuid = (tBT_UUID *)(p_msg + 1);
+ memcpy(p_msg->p_uuid, p_services->p_uuid, sizeof(tBT_UUID) * p_services->num_uuid);
+ }
+ }
+
+ bta_sys_sendmsg(p_msg);
+ }
+#endif
+
+}
+
+/*******************************************************************************
+**
+** Function BTA_DmSearchExt
+**
+** Description This function searches for peer Bluetooth devices. It performs
+** an inquiry and gets the remote name for devices. Service
+** discovery is done if services is non zero
+**
+** Parameters p_dm_inq: inquiry conditions
+** p_services: if service is not empty, service discovery will be done.
+** for all GATT based service condition, put num_uuid, and
+** p_uuid is the pointer to the list of UUID values.
+** p_cback: callback functino when search is completed.
+**
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_DmSearchExt(tBTA_DM_INQ *p_dm_inq, tBTA_SERVICE_MASK_EXT *p_services, tBTA_DM_SEARCH_CBACK *p_cback)
+{
+#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE
+ tBTA_DM_API_SEARCH *p_msg;
+ UINT16 len = p_services ? (sizeof(tBTA_DM_API_SEARCH) + sizeof(tBT_UUID) * p_services->num_uuid) :
+ sizeof(tBTA_DM_API_SEARCH);
+
+ if ((p_msg = (tBTA_DM_API_SEARCH *) GKI_getbuf(len)) != NULL)
+ {
+ memset(p_msg, 0, len);
+
+ p_msg->hdr.event = BTA_DM_API_SEARCH_EVT;
+ memcpy(&p_msg->inq_params, p_dm_inq, sizeof(tBTA_DM_INQ));
+ p_msg->p_cback = p_cback;
+ p_msg->rs_res = BTA_DM_RS_NONE;
+
+
+ if (p_services != NULL)
+ {
+ p_msg->services = p_services->srvc_mask;
+ p_msg->num_uuid = p_services->num_uuid;
+
+ if (p_services->num_uuid != 0)
+ {
+ p_msg->p_uuid = (tBT_UUID *)(p_msg + 1);
+ memcpy(p_msg->p_uuid, p_services->p_uuid, sizeof(tBT_UUID) * p_services->num_uuid);
+ }
+ else
+ p_msg->p_uuid = NULL;
+ }
+
+ bta_sys_sendmsg(p_msg);
+ }
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function BTA_DmSetEncryption
+**
+** Description This function is called to ensure that connection is
+** encrypted. Should be called only on an open connection.
+** Typically only needed for connections that first want to
+** bring up unencrypted links, then later encrypt them.
+**
+** Parameters: bd_addr - Address of the peer device
+** p_callback - Pointer to callback function to indicat the
+** link encryption status
+** sec_act - This is the security action to indicate
+** what knid of BLE security level is required for
+** the BLE link if the BLE is supported
+** Note: This parameter is ignored for the BR/EDR link
+** or the BLE is not supported
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_DmSetEncryption(BD_ADDR bd_addr, tBTA_DM_ENCRYPT_CBACK *p_callback,
+ tBTA_DM_BLE_SEC_ACT sec_act)
+{
+ tBTA_DM_API_SET_ENCRYPTION *p_msg;
+
+ APPL_TRACE_API0("BTA_DmSetEncryption"); //todo
+ if ((p_msg = (tBTA_DM_API_SET_ENCRYPTION *) GKI_getbuf(sizeof(tBTA_DM_API_SET_ENCRYPTION))) != NULL)
+ {
+ memset(p_msg, 0, sizeof(tBTA_DM_API_SET_ENCRYPTION));
+
+ p_msg->hdr.event = BTA_DM_API_SET_ENCRYPTION_EVT;
+
+ memcpy(p_msg->bd_addr, bd_addr, BD_ADDR_LEN);
+ p_msg->p_callback = p_callback;
+ p_msg->sec_act = sec_act;
+
+ bta_sys_sendmsg(p_msg);
+ }
+}
+
diff --git a/bta/dm/bta_dm_cfg.c b/bta/dm/bta_dm_cfg.c
new file mode 100644
index 0000000..e6a76af
--- /dev/null
+++ b/bta/dm/bta_dm_cfg.c
@@ -0,0 +1,424 @@
+/*****************************************************************************
+**
+** Name: bta_dm_cfg.c
+**
+** Description: This file contains compile-time configurable constants
+** for the device manager.
+**
+** Copyright (c) 2003-2011, Broadcom Corp, All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+#include "bta_sys.h"
+#include "bta_api.h"
+#include "bta_dm_int.h"
+
+#ifndef BTA_DM_COD
+
+/*
+ * major : COD_MAJOR_PHONE
+ * minor : COD_MINOR_SMART_PHONE
+ * svc : None, will be set as each profile registers
+ *
+ */
+
+#define BTA_DM_COD {0x40, BTM_COD_MAJOR_PHONE, BTM_COD_MINOR_SMART_PHONE}
+#endif
+
+
+#ifndef BTA_DM_LINK_POLICY_SETTINGS
+#define BTA_DM_LINK_POLICY_SETTINGS (HCI_ENABLE_MASTER_SLAVE_SWITCH | HCI_ENABLE_HOLD_MODE | HCI_ENABLE_SNIFF_MODE | HCI_ENABLE_PARK_MODE)
+#endif
+
+/* page timeout in 625uS */
+#ifndef BTA_DM_PAGE_TIMEOUT
+#define BTA_DM_PAGE_TIMEOUT 8192
+#endif
+
+/* link supervision timeout in 625uS (5 secs) */
+#ifndef BTA_DM_LINK_TIMEOUT
+#define BTA_DM_LINK_TIMEOUT 8000
+#endif
+
+/* For Insight, PM cfg lookup tables are runtime configurable (to allow tweaking of params for power consumption measurements) */
+#ifndef BTE_SIM_APP
+#define tBTA_DM_PM_TYPE_QUALIFIER const
+#else
+#define tBTA_DM_PM_TYPE_QUALIFIER
+#endif
+
+
+const tBTA_DM_CFG bta_dm_cfg =
+{
+ /* mobile phone COD */
+ BTA_DM_COD,
+ /* link policy settings */
+ BTA_DM_LINK_POLICY_SETTINGS,
+ /* page timeout in 625uS */
+ BTA_DM_PAGE_TIMEOUT,
+ /* link supervision timeout in 625uS*/
+ BTA_DM_LINK_TIMEOUT,
+ /* TRUE to avoid scatternet when av is streaming (be the master) */
+ TRUE
+};
+
+#ifndef BTA_DM_SCATTERNET
+/* By default, allow partial scatternet */
+#define BTA_DM_SCATTERNET BTA_DM_PARTIAL_SCATTERNET
+#endif
+
+#ifndef BTA_HH_ROLE
+/* By default, do not specify HH role (backward compatibility) */
+#define BTA_HH_ROLE BTA_ANY_ROLE
+#endif
+
+#ifndef BTA_AV_ROLE
+/* By default, AV role (backward BTA_MASTER_ROLE_PREF) */
+#define BTA_AV_ROLE BTA_MASTER_ROLE_PREF
+#endif
+
+#define BTA_DM_NUM_RM_ENTRY 4
+
+/* appids for PAN used by insight sample application
+ these have to be same as defined in btui_int.h */
+#define BTUI_PAN_ID_PANU 0
+#define BTUI_PAN_ID_NAP 1
+#define BTUI_PAN_ID_GN 2
+
+/* First element is always for SYS:
+ app_id = # of entries table, cfg is
+ device scatternet support */
+const tBTA_DM_RM bta_dm_rm_cfg[] =
+{
+ {BTA_ID_SYS, BTA_DM_NUM_RM_ENTRY, BTA_DM_SCATTERNET},
+ {BTA_ID_PAN, BTUI_PAN_ID_NAP, BTA_MASTER_ROLE_ONLY},
+ {BTA_ID_PAN, BTUI_PAN_ID_GN, BTA_MASTER_ROLE_ONLY},
+ {BTA_ID_HH, BTA_ALL_APP_ID, BTA_HH_ROLE},
+ {BTA_ID_AV, BTA_ALL_APP_ID, BTA_AV_ROLE}
+};
+
+
+tBTA_DM_CFG *p_bta_dm_cfg = (tBTA_DM_CFG *)&bta_dm_cfg;
+
+tBTA_DM_RM *p_bta_dm_rm_cfg = (tBTA_DM_RM *)&bta_dm_rm_cfg;
+
+
+#define BTA_DM_NUM_PM_ENTRY (15+BTA_DM_NUM_JV_ID) /* number of entries in bta_dm_pm_cfg except the first */
+
+tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_CFG bta_dm_pm_cfg[] =
+{
+ {BTA_ID_SYS, BTA_DM_NUM_PM_ENTRY, 0},
+ {BTA_ID_AG, BTA_ALL_APP_ID, 0}, /* ag uses first spec table for app id 0 */
+ {BTA_ID_CT, 1, 1}, /* ct (BTA_ID_CT,APP ID=1) spec table */
+ {BTA_ID_CG, BTA_ALL_APP_ID, 1}, /* cg resue ct spec table */
+ {BTA_ID_DG, BTA_ALL_APP_ID, 2}, /* dg spec table */
+ {BTA_ID_AV, BTA_ALL_APP_ID, 4}, /* av spec table */
+ {BTA_ID_FTC, BTA_ALL_APP_ID, 6}, /* ftc spec table */
+ {BTA_ID_FTS, BTA_ALL_APP_ID, 7}, /* fts spec table */
+ {BTA_ID_HD, BTA_ALL_APP_ID, 3}, /* hd spec table */
+ {BTA_ID_HH, BTA_ALL_APP_ID, 5}, /* hh spec table */
+ {BTA_ID_PBC, BTA_ALL_APP_ID, 2}, /* reuse dg spec table */
+ {BTA_ID_PBS, BTA_ALL_APP_ID, 7}, /* reuse fts spec table */
+ {BTA_ID_OPC, BTA_ALL_APP_ID, 6}, /* reuse ftc spec table */
+ {BTA_ID_OPS, BTA_ALL_APP_ID, 7}, /* reuse fts spec table */
+ {BTA_ID_MSE, BTA_ALL_APP_ID, 7}, /* reuse fts spec table */
+ {BTA_ID_JV1, BTA_ALL_APP_ID, 7}, /* reuse fts spec table */
+ {BTA_ID_JV2, BTA_ALL_APP_ID, 7}, /* reuse fts spec table */
+ {BTA_ID_HL, BTA_ALL_APP_ID, 8} /* reuse fts spec table */
+};
+
+
+#ifdef BTE_SIM_APP /* For Insight builds only, see the detail below */
+#define BTA_DM_NUM_PM_SPEC (9 + 2) /* additional two */
+#else
+#define BTA_DM_NUM_PM_SPEC 9 /* additional JV*/
+#endif
+
+tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_SPEC bta_dm_pm_spec[BTA_DM_NUM_PM_SPEC] =
+{
+ /* AG */
+ {
+ (BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */
+#if (BTM_SSR_INCLUDED == TRUE)
+ (BTA_DM_PM_SSR2), /* the SSR entry */
+#endif
+ {
+ {{BTA_DM_PM_SNIFF, 5000}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff */
+ {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */
+ {{BTA_DM_PM_SNIFF3, 5000}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open, active */
+ {{BTA_DM_PM_SNIFF, 5000}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close sniff */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */
+ {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */
+ {{BTA_DM_PM_RETRY, 5000}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
+ }
+ },
+
+ /* CT */
+ {
+ (BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */
+#if (BTM_SSR_INCLUDED == TRUE)
+ (BTA_DM_PM_SSR2), /* the SSR entry */
+#endif
+ {
+ {{BTA_DM_PM_PARK, 5000}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open park */
+ {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */
+ {{BTA_DM_PM_SNIFF, 5000}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open sniff */
+ {{BTA_DM_PM_PARK, 5000}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close park */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */
+ {{BTA_DM_PM_RETRY, 5000}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
+ }
+ },
+
+ /* DG */
+ {
+ (BTA_DM_PM_ACTIVE), /* no power saving mode allowed */
+#if (BTM_SSR_INCLUDED == TRUE)
+ (BTA_DM_PM_SSR2), /* the SSR entry */
+#endif
+ {
+ {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open active */
+ {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */
+ {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
+ }
+ },
+
+ /* HD */
+ {
+ (BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */
+#if (BTM_SSR_INCLUDED == TRUE)
+ (BTA_DM_PM_SSR3), /* the SSR entry */
+#endif
+ {
+ {{BTA_DM_PM_SNIFF4, 5000}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff */
+ {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */
+ {{BTA_DM_PM_SNIFF2, 5000}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */
+ {{BTA_DM_PM_SNIFF4, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
+ }
+ },
+
+ /* AV */
+ {
+ (BTA_DM_PM_SNIFF), /* allow sniff */
+#if (BTM_SSR_INCLUDED == TRUE)
+ (BTA_DM_PM_SSR2), /* the SSR entry */
+#endif
+ {
+ {{BTA_DM_PM_SNIFF, 5000}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff */
+ {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */
+ {{BTA_DM_PM_SNIFF, 5000}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */
+ {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
+ }
+ },
+
+ /* HH */
+ {
+ (BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */
+#if (BTM_SSR_INCLUDED == TRUE)
+ (BTA_DM_PM_SSR1), /* the SSR entry */
+#endif
+ {
+ {{BTA_DM_PM_SNIFF2, 7000}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff */
+ {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close, used for HH suspend */
+ {{BTA_DM_PM_SNIFF2, 7000}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */
+ {{BTA_DM_PM_SNIFF2, 7000}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
+ }
+ },
+
+ /* FTC, OPC */
+ {
+ (BTA_DM_PM_SNIFF), /* allow sniff */
+#if (BTM_SSR_INCLUDED == TRUE)
+ (BTA_DM_PM_SSR2), /* the SSR entry */
+#endif
+ {
+ {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open active */
+ {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */
+ {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */
+ {{BTA_DM_PM_SNIFF, 5000}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */
+ {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
+ }
+ },
+
+ /* FTS, OPS */
+ {
+ (BTA_DM_PM_SNIFF), /* allow sniff */
+#if (BTM_SSR_INCLUDED == TRUE)
+ (BTA_DM_PM_SSR2), /* the SSR entry */
+#endif
+ {
+ {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open active */
+ {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */
+ {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */
+ {{BTA_DM_PM_SNIFF, 7000}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */
+ {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
+ }
+ },
+
+ /* HL */
+ {
+ (BTA_DM_PM_SNIFF), /* allow sniff */
+#if (BTM_SSR_INCLUDED == TRUE)
+ (BTA_DM_PM_SSR2), /* the SSR entry */
+#endif
+ {
+ {{BTA_DM_PM_SNIFF, 5000}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff */
+ {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open, active */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close sniff */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */
+ {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
+ }
+ }
+
+#ifdef BTE_SIM_APP /* For Insight builds only */
+ /* Entries at the end of the pm_spec table are user-defined (runtime configurable),
+ for power consumption experiments.
+ Insight finds the first user-defined entry by looking for the first BTA_DM_PM_NO_PREF.
+ The number of user_defined specs is defined by BTA_SWRAP_UD_PM_SPEC_COUNT */
+ ,
+ {BTA_DM_PM_NO_PREF}, /* pm_spec USER_DEFINED_0 */
+ {BTA_DM_PM_NO_PREF} /* pm_spec USER_DEFINED_1 */
+#endif /* BTE_SIM_APP */
+};
+
+tBTA_DM_PM_TYPE_QUALIFIER tBTM_PM_PWR_MD bta_dm_pm_md[] =
+{
+/* more sniff parameter entries can be added for BTA_DM_PM_SNIFF3 - BTA_DM_PM_SNIFF7, if needed
+When entries are added or removed, BTA_DM_PM_PARK_IDX needs to be updated to reflect the actual index
+BTA_DM_PM_PARK_IDX is defined in bta_api.h and can be override by the buildcfg.h settings.
+The SNIFF table entries must be in the order from highest latency (biggest interval) to lowest latency.
+If there's a conflict among the connected services, the setting with lowest latency wins.
+*/
+/* sniff modes: max interval, min interval, attempt, timeout */
+ {800, 400, 4, 1, BTM_PM_MD_SNIFF}, /*for BTA_DM_PM_SNIFF - A2DP */
+ {400, 200, 4, 1, BTM_PM_MD_SNIFF}, /*for BTA_DM_PM_SNIFF1 */
+ {180, 150, 4, 1, BTM_PM_MD_SNIFF}, /*for BTA_DM_PM_SNIFF2- HD idle */
+ {150, 50, 4, 1, BTM_PM_MD_SNIFF}, /*for BTA_DM_PM_SNIFF3- SCO open */
+ { 54, 30, 4, 1, BTM_PM_MD_SNIFF}, /*for BTA_DM_PM_SNIFF4- HD active*/
+ {800, 400, 0, 0, BTM_PM_MD_PARK}
+
+#ifdef BTE_SIM_APP /* For Insight builds only */
+ /* Entries at the end of the bta_dm_pm_md table are user-defined (runtime configurable),
+ for power consumption experiments.
+ Insight finds the first user-defined entry by looking for the first 'max=0'.
+ The number of user_defined specs is defined by BTA_SWRAP_UD_PM_DM_COUNT */
+ ,
+ {0}, /* CONN_OPEN/SCO_CLOSE power mode settings for pm_spec USER_DEFINED_0 */
+ {0}, /* SCO_OPEN power mode settings for pm_spec USER_DEFINED_0 */
+
+ {0}, /* CONN_OPEN/SCO_CLOSE power mode settings for pm_spec USER_DEFINED_1 */
+ {0} /* SCO_OPEN power mode settings for pm_spec USER_DEFINED_1 */
+#endif /* BTE_SIM_APP */
+};
+
+/* 0=max_lat -> no SSR */
+/* the smaller of the SSR max latency wins.
+ * the entries in this table must be from highest latency (biggest interval) to lowest latency */
+#if (BTM_SSR_INCLUDED == TRUE)
+tBTA_DM_SSR_SPEC bta_dm_ssr_spec[] =
+{
+ /*max_lat, min_rmt_to, min_loc_to*/
+ {0, 0, 0}, /* BTA_DM_PM_SSR0 - do not use SSR */
+ {1600, 2, 2}, /* BTA_DM_PM_SSR1 - HH */
+ {1200, 2, 2}, /* BTA_DM_PM_SSR2 - others (as long as sniff is allowed)*/
+ {360, 160, 2} /* BTA_DM_PM_SSR3 - HD */
+};
+
+tBTA_DM_SSR_SPEC *p_bta_dm_ssr_spec = (tBTA_DM_SSR_SPEC *)&bta_dm_ssr_spec;
+#endif
+
+tBTA_DM_PM_CFG *p_bta_dm_pm_cfg = (tBTA_DM_PM_CFG *)&bta_dm_pm_cfg;
+tBTA_DM_PM_SPEC *p_bta_dm_pm_spec = (tBTA_DM_PM_SPEC *)&bta_dm_pm_spec;
+tBTM_PM_PWR_MD *p_bta_dm_pm_md = (tBTM_PM_PWR_MD *)&bta_dm_pm_md;
+
+/* The performance impact of EIR packet size
+**
+** When BTM_EIR_DEFAULT_FEC_REQUIRED is TRUE,
+** 1 to 17 bytes, DM1 is used and most robust.
+** 18 to 121 bytes, DM3 is used but impacts inquiry scan time with large number
+** of devices.(almost double with 150 users)
+** 122 to 224 bytes, DM5 is used but cause quite big performance loss even with
+** small number of users. so it is not recommended.
+** 225 to 240 bytes, DH5 is used without FEC but it not recommended.
+** (same reason of DM5)
+**
+** When BTM_EIR_DEFAULT_FEC_REQUIRED is FALSE,
+** 1 to 27 bytes, DH1 is used but only robust at short range.
+** 28 to 183 bytes, DH3 is used but only robust at short range and impacts inquiry
+** scan time with large number of devices.
+** 184 to 240 bytes, DH5 is used but it not recommended.
+*/
+
+#if ( BTM_EIR_SERVER_INCLUDED == TRUE )
+#if (BTA_EIR_CANNED_UUID_LIST == TRUE)
+ /* for example */
+const UINT8 bta_dm_eir_uuid16_list[] = { 0x08, 0x11, /* Headset */
+ 0x1E, 0x11, /* Handsfree */
+ 0x0E, 0x11, /* AV Remote Control */
+ 0x0B, 0x11, /* Audio Sink */
+};
+#endif
+
+/* Extended Inquiry Response */
+const tBTA_DM_EIR_CONF bta_dm_eir_cfg =
+{
+ 50, /* minimum length of local name when it is shortened */
+ /* if length of local name is longer than this and EIR has not enough */
+ /* room for all UUID list then local name is shortened to this length */
+#if (BTA_EIR_CANNED_UUID_LIST == TRUE)
+ 8,
+ (UINT8 *)bta_dm_eir_uuid16_list,
+#else
+ { /* mask of UUID list in EIR */
+ 0xFFFFFFFF, /* LSB is the first UUID of the first 32 UUIDs in BTM_EIR_UUID_LKUP_TBL */
+ 0xFFFFFFFF /* LSB is the first UUID of the next 32 UUIDs in BTM_EIR_UUID_LKUP_TBL */
+ /* BTM_EIR_UUID_LKUP_TBL can be overrided */
+ },
+#endif
+ NULL, /* Inquiry TX power */
+ 0, /* length of flags in bytes */
+ NULL, /* flags for EIR */
+ 0, /* length of manufacturer specific in bytes */
+ NULL, /* manufacturer specific */
+};
+tBTA_DM_EIR_CONF *p_bta_dm_eir_cfg = (tBTA_DM_EIR_CONF*)&bta_dm_eir_cfg;
+#endif
diff --git a/bta/dm/bta_dm_ci.c b/bta/dm/bta_dm_ci.c
new file mode 100644
index 0000000..b003cbe
--- /dev/null
+++ b/bta/dm/bta_dm_ci.c
@@ -0,0 +1,106 @@
+/*****************************************************************************
+**
+** Name: bta_dm_ci.c
+**
+** Description: This is the API implementation file for the BTA
+** device manager.
+**
+** Copyright (c) 2003-2009, Broadcom Corp., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "gki.h"
+#include "bd.h"
+#include "bta_sys.h"
+#include "bta_api.h"
+#include "bta_dm_int.h"
+#include <string.h>
+#include "bta_dm_ci.h"
+
+
+#if (BTM_OOB_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function bta_dm_ci_io_req
+**
+** Description This function must be called in response to function
+** bta_dm_co_io_req(), if *p_oob_data to BTA_OOB_UNKNOWN
+** by bta_dm_co_io_req().
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_ci_io_req(BD_ADDR bd_addr, tBTA_IO_CAP io_cap, tBTA_OOB_DATA oob_data,
+ tBTA_AUTH_REQ auth_req)
+
+{
+ tBTA_DM_CI_IO_REQ *p_msg;
+
+ if ((p_msg = (tBTA_DM_CI_IO_REQ *) GKI_getbuf(sizeof(tBTA_DM_CI_IO_REQ))) != NULL)
+ {
+ p_msg->hdr.event = BTA_DM_CI_IO_REQ_EVT;
+ bdcpy(p_msg->bd_addr, bd_addr);
+ p_msg->io_cap = io_cap;
+ p_msg->oob_data = oob_data;
+ p_msg->auth_req = auth_req;
+ bta_sys_sendmsg(p_msg);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_ci_rmt_oob
+**
+** Description This function must be called in response to function
+** bta_dm_co_rmt_oob() to provide the OOB data associated
+** with the remote device.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_ci_rmt_oob(BOOLEAN accept, BD_ADDR bd_addr, BT_OCTET16 c, BT_OCTET16 r)
+{
+ tBTA_DM_CI_RMT_OOB *p_msg;
+
+ if ((p_msg = (tBTA_DM_CI_RMT_OOB *) GKI_getbuf(sizeof(tBTA_DM_CI_RMT_OOB))) != NULL)
+ {
+ p_msg->hdr.event = BTA_DM_CI_RMT_OOB_EVT;
+ bdcpy(p_msg->bd_addr, bd_addr);
+ p_msg->accept = accept;
+ memcpy(p_msg->c, c, BT_OCTET16_LEN);
+ memcpy(p_msg->r, r, BT_OCTET16_LEN);
+ bta_sys_sendmsg(p_msg);
+ }
+}
+#endif /* BTM_OOB_INCLUDED */
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function bta_dm_sco_ci_data_ready
+**
+** Description This function sends an event to indicating that the phone
+** has SCO data ready.
+**
+** Parameters event: is obtained from bta_dm_sco_co_open() function, which
+** is the BTA event we want to send back to BTA module
+** when there is encoded data ready.
+** sco_handle: is the BTA sco handle which indicate a specific
+** SCO connection.
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_sco_ci_data_ready(UINT16 event, UINT16 sco_handle)
+{
+ BT_HDR *p_buf;
+
+ if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->event = event;
+ p_buf->layer_specific = sco_handle;
+
+ bta_sys_sendmsg(p_buf);
+ }
+}
+#endif
diff --git a/bta/dm/bta_dm_int.h b/bta/dm/bta_dm_int.h
new file mode 100644
index 0000000..5f1da2a
--- /dev/null
+++ b/bta/dm/bta_dm_int.h
@@ -0,0 +1,956 @@
+/*****************************************************************************
+**
+** Name: bta_dm_int.h
+**
+** Description: This is the private interface file for the BTA device
+** manager.
+**
+** Copyright (c) 2003-2012, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_DM_INT_H
+#define BTA_DM_INT_H
+
+#include "bt_target.h"
+
+#if (BLE_INCLUDED == TRUE && (defined BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE))
+ #include "bta_gatt_api.h"
+#endif
+
+
+
+/*****************************************************************************
+** Constants and data types
+*****************************************************************************/
+
+
+#define BTA_COPY_DEVICE_CLASS(coddst, codsrc) {((UINT8 *)(coddst))[0] = ((UINT8 *)(codsrc))[0]; \
+ ((UINT8 *)(coddst))[1] = ((UINT8 *)(codsrc))[1]; \
+ ((UINT8 *)(coddst))[2] = ((UINT8 *)(codsrc))[2];}
+
+
+#define BTA_DM_MSG_LEN 50
+
+#define BTA_SERVICE_ID_TO_SERVICE_MASK(id) (1 << (id))
+
+/* DM events */
+enum
+{
+ /* device manager local device API events */
+ BTA_DM_API_ENABLE_EVT = BTA_SYS_EVT_START(BTA_ID_DM),
+ BTA_DM_API_DISABLE_EVT,
+ BTA_DM_API_SET_NAME_EVT,
+ BTA_DM_API_SET_VISIBILITY_EVT,
+ BTA_DM_API_SET_AFH_CHANNELS_EVT,
+ BTA_API_DM_SIG_STRENGTH_EVT,
+ BTA_DM_API_VENDOR_SPECIFIC_COMMAND_EVT,
+ BTA_DM_API_TX_INQPWR_EVT,
+ BTA_DM_ACL_CHANGE_EVT,
+ BTA_DM_API_ADD_DEVICE_EVT,
+
+ /* security API events */
+ BTA_DM_API_BOND_EVT,
+ BTA_DM_API_BOND_CANCEL_EVT,
+ BTA_DM_API_PIN_REPLY_EVT,
+ BTA_DM_API_LINK_POLICY_EVT,
+ BTA_DM_API_AUTH_REPLY_EVT,
+
+ /* power manger events */
+ BTA_DM_PM_BTM_STATUS_EVT,
+ BTA_DM_PM_TIMER_EVT,
+
+ /* simple pairing events */
+ BTA_DM_API_CONFIRM_EVT,
+
+ BTA_DM_API_SET_ENCRYPTION_EVT,
+
+#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
+ BTA_DM_API_PASKY_CANCEL_EVT,
+#endif
+#if (BTM_OOB_INCLUDED == TRUE)
+ BTA_DM_API_LOC_OOB_EVT,
+ BTA_DM_CI_IO_REQ_EVT,
+ BTA_DM_CI_RMT_OOB_EVT,
+#endif /* BTM_OOB_INCLUDED */
+
+#if BLE_INCLUDED == TRUE
+ BTA_DM_API_ADD_BLEKEY_EVT,
+ BTA_DM_API_ADD_BLEDEVICE_EVT,
+ BTA_DM_API_BLE_PASSKEY_REPLY_EVT,
+ BTA_DM_API_BLE_SEC_GRANT_EVT,
+ BTA_DM_API_BLE_SET_BG_CONN_TYPE,
+ BTA_DM_API_BLE_CONN_PARAM_EVT,
+ BTA_DM_API_BLE_SCAN_PARAM_EVT,
+#endif
+
+#if ( BTM_EIR_SERVER_INCLUDED == TRUE )&&( BTA_EIR_CANNED_UUID_LIST != TRUE )&&(BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0)
+ BTA_DM_API_UPDATE_EIR_UUID_EVT,
+#endif
+#if (BTM_EIR_SERVER_INCLUDED == TRUE)
+ BTA_DM_API_SET_EIR_CONFIG_EVT,
+#endif
+
+ BTA_DM_API_ENABLE_TEST_MODE_EVT,
+ BTA_DM_API_DISABLE_TEST_MODE_EVT,
+ BTA_DM_API_EXECUTE_CBACK_EVT,
+ BTA_DM_API_SET_AFH_CHANNEL_ASSESMENT_EVT,
+ BTA_DM_MAX_EVT
+};
+
+
+/* DM search events */
+enum
+{
+ /* DM search API events */
+ BTA_DM_API_SEARCH_EVT = BTA_SYS_EVT_START(BTA_ID_DM_SEARCH),
+ BTA_DM_API_SEARCH_CANCEL_EVT,
+ BTA_DM_API_DISCOVER_EVT,
+ BTA_DM_INQUIRY_CMPL_EVT,
+ BTA_DM_REMT_NAME_EVT,
+ BTA_DM_SDP_RESULT_EVT,
+ BTA_DM_SEARCH_CMPL_EVT,
+ BTA_DM_DISCOVERY_RESULT_EVT,
+ BTA_DM_API_DI_DISCOVER_EVT
+
+};
+
+/* data type for BTA_DM_API_ENABLE_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_DM_SEC_CBACK *p_sec_cback;
+} tBTA_DM_API_ENABLE;
+
+/* data type for BTA_DM_API_SET_NAME_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ char name[BD_NAME_LEN];
+} tBTA_DM_API_SET_NAME;
+
+/* data type for BTA_DM_API_SET_VISIBILITY_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_DM_DISC disc_mode;
+ tBTA_DM_CONN conn_mode;
+ UINT8 pair_mode;
+ UINT8 conn_paired_only;
+} tBTA_DM_API_SET_VISIBILITY;
+
+/* data type for BTA_DM_API_SET_AFH_CHANNELS_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ UINT8 first;
+ UINT8 last;
+} tBTA_DM_API_SET_AFH_CHANNELS_EVT;
+
+/* data type for BTA_DM_API_VENDOR_SPECIFIC_COMMAND_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ UINT16 opcode;
+ UINT8 param_len;
+ UINT8 *p_param_buf;
+ tBTA_VENDOR_CMPL_CBACK *p_cback;
+
+} tBTA_DM_API_VENDOR_SPECIFIC_COMMAND;
+
+enum
+{
+ BTA_DM_RS_NONE, /* straight API call */
+ BTA_DM_RS_OK, /* the role switch result - successful */
+ BTA_DM_RS_FAIL /* the role switch result - failed */
+};
+typedef UINT8 tBTA_DM_RS_RES;
+
+/* data type for BTA_DM_API_SEARCH_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_DM_INQ inq_params;
+ tBTA_SERVICE_MASK services;
+ tBTA_DM_SEARCH_CBACK * p_cback;
+ tBTA_DM_RS_RES rs_res;
+#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE
+ UINT8 num_uuid;
+ tBT_UUID *p_uuid;
+#endif
+} tBTA_DM_API_SEARCH;
+
+/* data type for BTA_DM_API_DISCOVER_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+ tBTA_SERVICE_MASK services;
+ tBTA_DM_SEARCH_CBACK * p_cback;
+ BOOLEAN sdp_search;
+#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE
+ UINT8 num_uuid;
+ tBT_UUID *p_uuid;
+#endif
+ tSDP_UUID uuid;
+} tBTA_DM_API_DISCOVER;
+
+/* data type for BTA_DM_API_DI_DISC_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+ tBTA_DISCOVERY_DB *p_sdp_db;
+ UINT32 len;
+ tBTA_DM_SEARCH_CBACK * p_cback;
+}tBTA_DM_API_DI_DISC;
+
+/* data type for BTA_DM_API_BOND_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+} tBTA_DM_API_BOND;
+
+/* data type for BTA_DM_API_BOND_CANCEL_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+} tBTA_DM_API_BOND_CANCEL;
+
+/* data type for BTA_DM_API_PIN_REPLY_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+ BOOLEAN accept;
+ UINT8 pin_len;
+ UINT8 p_pin[PIN_CODE_LEN];
+} tBTA_DM_API_PIN_REPLY;
+
+/* data type for BTA_DM_API_LINK_POLICY_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+ UINT16 policy_mask;
+ BOOLEAN set;
+} tBTA_DM_API_LINK_POLICY;
+
+/* data type for BTA_DM_API_AUTH_REPLY_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+ tBTA_SERVICE_ID service;
+ tBTA_AUTH_RESP response;
+} tBTA_DM_API_AUTH_REPLY;
+
+/* data type for BTA_DM_API_LOC_OOB_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+} tBTA_DM_API_LOC_OOB;
+
+/* data type for BTA_DM_API_CONFIRM_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+ BOOLEAN accept;
+} tBTA_DM_API_CONFIRM;
+
+/* data type for BTA_DM_API_PASKY_CANCEL_EVT*/
+typedef struct
+{
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+} tBTA_DM_API_PASKY_CANCEL;
+
+/* data type for BTA_DM_CI_IO_REQ_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+ tBTA_IO_CAP io_cap;
+ tBTA_OOB_DATA oob_data;
+ tBTA_AUTH_REQ auth_req;
+} tBTA_DM_CI_IO_REQ;
+
+/* data type for BTA_DM_CI_RMT_OOB_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+ BT_OCTET16 c;
+ BT_OCTET16 r;
+ BOOLEAN accept;
+} tBTA_DM_CI_RMT_OOB;
+
+/* data type for BTA_DM_REMT_NAME_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_DM_SEARCH result;
+} tBTA_DM_REM_NAME;
+
+/* data type for tBTA_DM_DISC_RESULT */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_DM_SEARCH result;
+} tBTA_DM_DISC_RESULT;
+
+
+/* data type for BTA_DM_INQUIRY_CMPL_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ UINT8 num;
+} tBTA_DM_INQUIRY_CMPL;
+
+/* data type for BTA_DM_SDP_RESULT_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ UINT16 sdp_result;
+} tBTA_DM_SDP_RESULT;
+
+/* data type for BTA_API_DM_SIG_STRENGTH_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_SIG_STRENGTH_MASK mask;
+ UINT16 period;
+ BOOLEAN start;
+} tBTA_API_DM_SIG_STRENGTH;
+
+/* data type for tBTA_API_DM_TX_INQPWR */
+typedef struct
+{
+ BT_HDR hdr;
+ INT8 tx_power;
+}tBTA_API_DM_TX_INQPWR;
+
+/* data type for BTA_DM_ACL_CHANGE_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTM_BL_EVENT event;
+ UINT8 busy_level;
+ BOOLEAN is_new;
+ UINT8 new_role;
+ BD_ADDR bd_addr;
+ UINT8 hci_status;
+} tBTA_DM_ACL_CHANGE;
+
+/* data type for BTA_DM_PM_BTM_STATUS_EVT */
+typedef struct
+{
+
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+ tBTM_PM_STATUS status;
+ UINT16 value;
+ UINT8 hci_status;
+
+} tBTA_DM_PM_BTM_STATUS;
+
+/* data type for BTA_DM_PM_TIMER_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+
+} tBTA_DM_PM_TIMER;
+
+
+/* data type for BTA_DM_API_ADD_DEVICE_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+ DEV_CLASS dc;
+ LINK_KEY link_key;
+ tBTA_SERVICE_MASK tm;
+ BOOLEAN is_trusted;
+ UINT8 key_type;
+ tBTA_IO_CAP io_cap;
+ BOOLEAN link_key_known;
+ BOOLEAN dc_known;
+ BD_NAME bd_name;
+ BD_FEATURES features;
+} tBTA_DM_API_ADD_DEVICE;
+
+/* data type for BTA_DM_API_EXECUTE_CBACK_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ void * p_param;
+ tBTA_DM_EXEC_CBACK *p_exec_cback;
+} tBTA_DM_API_EXECUTE_CBACK;
+
+/* data type for tBTA_DM_API_SET_ENCRYPTION */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_DM_ENCRYPT_CBACK *p_callback;
+ tBTA_DM_BLE_SEC_ACT sec_act;
+ BD_ADDR bd_addr;
+} tBTA_DM_API_SET_ENCRYPTION;
+
+#if BLE_INCLUDED == TRUE
+typedef struct
+{
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+ tBTA_LE_KEY_VALUE blekey;
+ tBTA_LE_KEY_TYPE key_type;
+
+}tBTA_DM_API_ADD_BLEKEY;
+
+typedef struct
+{
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+ tBT_DEVICE_TYPE dev_type ;
+ tBLE_ADDR_TYPE addr_type;
+
+}tBTA_DM_API_ADD_BLE_DEVICE;
+
+typedef struct
+{
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+ BOOLEAN accept;
+ UINT32 passkey;
+}tBTA_DM_API_PASSKEY_REPLY;
+
+typedef struct
+{
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+ tBTA_DM_BLE_SEC_GRANT res;
+}tBTA_DM_API_BLE_SEC_GRANT;
+
+
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_DM_BLE_CONN_TYPE bg_conn_type;
+ tBTA_DM_BLE_SEL_CBACK *p_select_cback;
+}tBTA_DM_API_BLE_SET_BG_CONN_TYPE;
+
+/* set prefered BLE connection parameters for a device */
+typedef struct
+{
+ BT_HDR hdr;
+ BD_ADDR peer_bda;
+ UINT16 conn_int_min;
+ UINT16 conn_int_max;
+ UINT16 supervision_tout;
+ UINT16 slave_latency;
+
+}tBTA_DM_API_BLE_CONN_PARAMS;
+
+/* set scan parameter for BLE connections */
+typedef struct
+{
+ BT_HDR hdr;
+ UINT16 scan_int;
+ UINT16 scan_window;
+}tBTA_DM_API_BLE_SCAN_PARAMS;
+
+#endif
+
+typedef struct
+{
+ BT_HDR hdr;
+ BOOLEAN enable_or_disable;
+}tBTA_DM_API_SET_AFH_CHANNEL_ASSESSMENT;
+
+#if ( BTM_EIR_SERVER_INCLUDED == TRUE )&&( BTA_EIR_CANNED_UUID_LIST != TRUE )&&(BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0)
+/* data type for BTA_DM_API_UPDATE_EIR_UUID_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ BOOLEAN is_add;
+ tBT_UUID uuid;
+}tBTA_DM_API_UPDATE_EIR_UUID;
+#endif
+
+#if (BTM_EIR_SERVER_INCLUDED == TRUE)
+/* data type for BTA_DM_API_SET_EIR_CONFIG_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_DM_EIR_CONF *p_eir_cfg;
+}tBTA_DM_API_SET_EIR_CONFIG;
+#endif
+
+/* union of all data types */
+typedef union
+{
+ /* GKI event buffer header */
+ BT_HDR hdr;
+ tBTA_DM_API_ENABLE enable;
+
+ tBTA_DM_API_SET_NAME set_name;
+
+ tBTA_DM_API_SET_VISIBILITY set_visibility;
+
+ tBTA_DM_API_SET_AFH_CHANNELS_EVT set_afhchannels;
+
+ tBTA_DM_API_VENDOR_SPECIFIC_COMMAND vendor_command;
+
+ tBTA_DM_API_ADD_DEVICE add_dev;
+
+ tBTA_DM_API_SEARCH search;
+
+ tBTA_DM_API_DISCOVER discover;
+
+ tBTA_DM_API_BOND bond;
+
+ tBTA_DM_API_BOND_CANCEL bond_cancel;
+
+ tBTA_DM_API_PIN_REPLY pin_reply;
+ tBTA_DM_API_LINK_POLICY link_policy;
+
+ tBTA_DM_API_LOC_OOB loc_oob;
+ tBTA_DM_API_CONFIRM confirm;
+ tBTA_DM_API_PASKY_CANCEL passkey_cancel;
+ tBTA_DM_CI_IO_REQ ci_io_req;
+ tBTA_DM_CI_RMT_OOB ci_rmt_oob;
+
+ tBTA_DM_API_AUTH_REPLY auth_reply;
+
+ tBTA_DM_REM_NAME rem_name;
+
+ tBTA_DM_DISC_RESULT disc_result;
+
+ tBTA_DM_INQUIRY_CMPL inq_cmpl;
+
+ tBTA_DM_SDP_RESULT sdp_event;
+
+ tBTA_API_DM_SIG_STRENGTH sig_strength;
+
+ tBTA_API_DM_TX_INQPWR tx_inq_pwr;
+
+ tBTA_DM_ACL_CHANGE acl_change;
+
+ tBTA_DM_PM_BTM_STATUS pm_status;
+
+ tBTA_DM_PM_TIMER pm_timer;
+
+ tBTA_DM_API_DI_DISC di_disc;
+
+ tBTA_DM_API_EXECUTE_CBACK exec_cback;
+
+ tBTA_DM_API_SET_ENCRYPTION set_encryption;
+
+#if BLE_INCLUDED == TRUE
+ tBTA_DM_API_ADD_BLEKEY add_ble_key;
+ tBTA_DM_API_ADD_BLE_DEVICE add_ble_device;
+ tBTA_DM_API_PASSKEY_REPLY ble_passkey_reply;
+ tBTA_DM_API_BLE_SEC_GRANT ble_sec_grant;
+ tBTA_DM_API_BLE_SET_BG_CONN_TYPE ble_set_bd_conn_type;
+ tBTA_DM_API_BLE_CONN_PARAMS ble_set_conn_params;
+ tBTA_DM_API_BLE_SCAN_PARAMS ble_set_scan_params;
+#endif
+
+ tBTA_DM_API_SET_AFH_CHANNEL_ASSESSMENT set_afh_channel_assessment;
+
+#if ( BTM_EIR_SERVER_INCLUDED == TRUE )&&( BTA_EIR_CANNED_UUID_LIST != TRUE )&&(BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0)
+ tBTA_DM_API_UPDATE_EIR_UUID update_eir_uuid;
+#endif
+#if (BTM_EIR_SERVER_INCLUDED == TRUE)
+ tBTA_DM_API_SET_EIR_CONFIG set_eir_cfg;
+#endif
+
+} tBTA_DM_MSG;
+
+
+#define BTA_DM_NUM_PEER_DEVICE 7
+
+#define BTA_DM_NOT_CONNECTED 0
+#define BTA_DM_CONNECTED 1
+
+typedef UINT8 tBTA_DM_CONN_STATE;
+
+
+#define BTA_DM_DI_NONE 0x00 /* nothing special */
+#define BTA_DM_DI_USE_SSR 0x10 /* set this bit if ssr is supported for this link */
+#define BTA_DM_DI_AV_ACTIVE 0x20 /* set this bit if AV is active for this link */
+#define BTA_DM_DI_SET_SNIFF 0x01 /* set this bit if call BTM_SetPowerMode(sniff) */
+#define BTA_DM_DI_INT_SNIFF 0x02 /* set this bit if call BTM_SetPowerMode(sniff) & enter sniff mode */
+#define BTA_DM_DI_ACP_SNIFF 0x04 /* set this bit if peer init sniff */
+typedef UINT8 tBTA_DM_DEV_INFO;
+
+typedef struct
+{
+ BD_ADDR peer_bdaddr;
+ UINT16 link_policy;
+ tBTA_DM_CONN_STATE conn_state;
+ tBTA_PREF_ROLES pref_role;
+ BOOLEAN in_use;
+ tBTA_DM_DEV_INFO info;
+#if (BTM_SSR_INCLUDED == TRUE)
+ tBTM_PM_STATUS prev_low; /* previous low power mode used */
+#endif
+ tBTA_DM_PM_ACTTION pm_mode_attempted;
+ tBTA_DM_PM_ACTTION pm_mode_failed;
+
+} tBTA_DM_PEER_DEVICE;
+
+
+
+/* structure to store list of
+ active connections */
+typedef struct
+{
+ tBTA_DM_PEER_DEVICE peer_device[BTA_DM_NUM_PEER_DEVICE];
+ UINT8 count;
+
+} tBTA_DM_ACTIVE_LINK;
+
+
+typedef struct
+{
+ BD_ADDR peer_bdaddr;
+ tBTA_SYS_ID id;
+ UINT8 app_id;
+ tBTA_SYS_CONN_STATUS state;
+
+
+} tBTA_DM_SRVCS;
+
+#define BTA_DM_NUM_CONN_SRVS 5
+
+typedef struct
+{
+
+ UINT8 count;
+ tBTA_DM_SRVCS conn_srvc[BTA_DM_NUM_CONN_SRVS];
+
+} tBTA_DM_CONNECTED_SRVCS;
+
+typedef struct
+{
+ TIMER_LIST_ENT timer;
+ BD_ADDR peer_bdaddr;
+ BOOLEAN in_use;
+
+} tBTA_PM_TIMER;
+
+extern tBTA_DM_CONNECTED_SRVCS bta_dm_conn_srvcs;
+
+#define BTA_DM_NUM_PM_TIMER 3
+
+/* DM control block */
+typedef struct
+{
+ BOOLEAN is_bta_dm_active;
+ tBTA_DM_ACTIVE_LINK device_list;
+ tBTA_DM_SEC_CBACK *p_sec_cback;
+ TIMER_LIST_ENT signal_strength_timer;
+ tBTA_SIG_STRENGTH_MASK signal_strength_mask;
+ UINT16 state;
+ UINT16 signal_strength_period;
+ BOOLEAN disabling;
+ TIMER_LIST_ENT disable_timer;
+ UINT32 wbt_sdp_handle; /* WIDCOMM Extensions SDP record handle */
+ UINT8 wbt_scn; /* WIDCOMM Extensions SCN */
+ UINT8 num_master_only;
+ UINT8 pm_id;
+ tBTA_PM_TIMER pm_timer[BTA_DM_NUM_PM_TIMER];
+ UINT32 role_policy_mask; /* the bits set indicates the modules that wants to remove role switch from the default link policy */
+ UINT16 cur_policy; /* current default link policy */
+ UINT16 rs_event; /* the event waiting for role switch */
+ UINT8 cur_av_count; /* current AV connecions */
+ BOOLEAN disable_pair_mode; /* disable pair mode or not */
+ BOOLEAN conn_paired_only; /* allow connectable to paired device only or not */
+ tBTA_DM_API_SEARCH search_msg;
+ UINT16 page_scan_interval;
+ UINT16 page_scan_window;
+ UINT16 inquiry_scan_interval;
+ UINT16 inquiry_scan_window;
+
+ /* Storage for pin code request parameters */
+ BD_ADDR pin_bd_addr;
+ DEV_CLASS pin_dev_class;
+ tBTA_DM_SEC_EVT pin_evt;
+ UINT32 num_val; /* the numeric value for comparison. If just_works, do not show this number to UI */
+ BOOLEAN just_works; /* TRUE, if "Just Works" association model */
+#if ( BTM_EIR_SERVER_INCLUDED == TRUE )&&( BTA_EIR_CANNED_UUID_LIST != TRUE )
+ /* store UUID list for EIR */
+ TIMER_LIST_ENT app_ready_timer;
+ UINT32 eir_uuid[BTM_EIR_SERVICE_ARRAY_SIZE];
+#if (BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0)
+ tBT_UUID custom_uuid[BTA_EIR_SERVER_NUM_CUSTOM_UUID];
+#endif
+
+#endif
+
+ tBTA_DM_ENCRYPT_CBACK *p_encrypt_cback;
+ tBTA_DM_BLE_SEC_ACT sec_act;
+
+} tBTA_DM_CB;
+
+#ifndef BTA_DM_SDP_DB_SIZE
+#define BTA_DM_SDP_DB_SIZE 250
+#endif
+
+/* DM search control block */
+typedef struct
+{
+
+ tBTA_DM_SEARCH_CBACK * p_search_cback;
+ tBTM_INQ_INFO * p_btm_inq_info;
+ tBTA_SERVICE_MASK services;
+ tBTA_SERVICE_MASK services_to_search;
+ tBTA_SERVICE_MASK services_found;
+ tSDP_DISCOVERY_DB * p_sdp_db;
+ UINT16 state;
+ BD_ADDR peer_bdaddr;
+ BOOLEAN name_discover_done;
+ char peer_name[BD_NAME_LEN];
+ TIMER_LIST_ENT search_timer;
+ UINT8 service_index;
+ tBTA_DM_MSG * p_search_queue; /* search or discover commands during search cancel stored here */
+ BOOLEAN wait_disc;
+ BOOLEAN sdp_results;
+ tSDP_UUID uuid;
+ UINT8 peer_scn;
+ BOOLEAN sdp_search;
+
+#if ((defined BLE_INCLUDED) && (BLE_INCLUDED == TRUE))
+#if ((defined BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE))
+ tBTA_GATTC_IF client_if;
+ UINT8 num_uuid;
+ tBT_UUID *p_srvc_uuid;
+ UINT8 uuid_to_search;
+ BOOLEAN gatt_disc_active;
+ UINT16 conn_id;
+ UINT8 * p_ble_rawdata;
+ UINT32 ble_raw_size;
+ UINT32 ble_raw_used;
+#endif
+#endif
+
+
+} tBTA_DM_SEARCH_CB;
+
+/* DI control block */
+typedef struct
+{
+ tSDP_DISCOVERY_DB * p_di_db; /* pointer to the DI discovery database */
+ UINT8 di_num; /* total local DI record number */
+ UINT32 di_handle[BTA_DI_NUM_MAX]; /* local DI record handle, the first one is primary record */
+}tBTA_DM_DI_CB;
+
+/* DM search state */
+enum
+{
+
+ BTA_DM_SEARCH_IDLE,
+ BTA_DM_SEARCH_ACTIVE,
+ BTA_DM_SEARCH_CANCELLING,
+ BTA_DM_DISCOVER_ACTIVE
+
+};
+
+
+
+typedef struct
+{
+ DEV_CLASS dev_class; /* local device class */
+ UINT16 policy_settings; /* link policy setting hold, sniff, park, MS switch */
+ UINT16 page_timeout; /* timeout for page in slots */
+ UINT16 link_timeout; /* link supervision timeout in slots */
+ BOOLEAN avoid_scatter; /* TRUE to avoid scatternet when av is streaming (be the master) */
+
+} tBTA_DM_CFG;
+
+extern const UINT32 bta_service_id_to_btm_srv_id_lkup_tbl[];
+
+extern const tBTA_DM_CFG bta_dm_cfg;
+
+
+
+#define BTA_ALL_APP_ID 0xff
+
+typedef struct
+{
+ UINT8 id;
+ UINT8 app_id;
+ UINT8 cfg;
+
+} tBTA_DM_RM ;
+
+extern tBTA_DM_CFG *p_bta_dm_cfg;
+extern tBTA_DM_RM *p_bta_dm_rm_cfg;
+
+typedef struct
+{
+
+ UINT8 id;
+ UINT8 app_id;
+ UINT8 spec_idx; /* index of spec table to use */
+
+} tBTA_DM_PM_CFG;
+
+
+typedef struct
+{
+
+ tBTA_DM_PM_ACTTION power_mode;
+ UINT16 timeout;
+
+} tBTA_DM_PM_ACTN;
+
+typedef struct
+{
+
+ UINT8 allow_mask; /* mask of sniff/hold/park modes to allow */
+#if (BTM_SSR_INCLUDED == TRUE)
+ UINT8 ssr; /* set SSR on conn open/unpark */
+#endif
+ tBTA_DM_PM_ACTN actn_tbl [BTA_DM_PM_NUM_EVTS][2];
+
+} tBTA_DM_PM_SPEC;
+
+typedef struct
+{
+ UINT16 max_lat;
+ UINT16 min_rmt_to;
+ UINT16 min_loc_to;
+} tBTA_DM_SSR_SPEC;
+
+extern tBTA_DM_PM_CFG *p_bta_dm_pm_cfg;
+extern tBTA_DM_PM_SPEC *p_bta_dm_pm_spec;
+extern tBTM_PM_PWR_MD *p_bta_dm_pm_md;
+#if (BTM_SSR_INCLUDED == TRUE)
+extern tBTA_DM_SSR_SPEC *p_bta_dm_ssr_spec;
+#endif
+
+#if ( BTM_EIR_SERVER_INCLUDED == TRUE )
+/* update dynamic BRCM Aware EIR data */
+extern const tBTA_DM_EIR_CONF bta_dm_eir_cfg;
+extern tBTA_DM_EIR_CONF *p_bta_dm_eir_cfg;
+#endif
+
+/* DM control block */
+#if BTA_DYNAMIC_MEMORY == FALSE
+extern tBTA_DM_CB bta_dm_cb;
+#else
+extern tBTA_DM_CB *bta_dm_cb_ptr;
+#define bta_dm_cb (*bta_dm_cb_ptr)
+#endif
+
+/* DM search control block */
+#if BTA_DYNAMIC_MEMORY == FALSE
+extern tBTA_DM_SEARCH_CB bta_dm_search_cb;
+#else
+extern tBTA_DM_SEARCH_CB *bta_dm_search_cb_ptr;
+#define bta_dm_search_cb (*bta_dm_search_cb_ptr)
+#endif
+
+/* DI control block */
+#if BTA_DYNAMIC_MEMORY == FALSE
+extern tBTA_DM_DI_CB bta_dm_di_cb;
+#else
+extern tBTA_DM_DI_CB *bta_dm_di_cb_ptr;
+#define bta_dm_di_cb (*bta_dm_di_cb_ptr)
+#endif
+
+extern BOOLEAN bta_dm_sm_execute(BT_HDR *p_msg);
+extern void bta_dm_sm_disable( void );
+extern BOOLEAN bta_dm_search_sm_execute(BT_HDR *p_msg);
+extern void bta_dm_search_sm_disable( void );
+
+
+extern void bta_dm_enable (tBTA_DM_MSG *p_data);
+extern void bta_dm_disable (tBTA_DM_MSG *p_data);
+extern void bta_dm_set_dev_name (tBTA_DM_MSG *p_data);
+extern void bta_dm_set_visibility (tBTA_DM_MSG *p_data);
+extern void bta_dm_set_afhchannels (tBTA_DM_MSG *p_data);
+extern void bta_dm_vendor_spec_command(tBTA_DM_MSG *p_data);
+extern void bta_dm_bond (tBTA_DM_MSG *p_data);
+extern void bta_dm_bond_cancel (tBTA_DM_MSG *p_data);
+extern void bta_dm_pin_reply (tBTA_DM_MSG *p_data);
+extern void bta_dm_link_policy (tBTA_DM_MSG *p_data);
+extern void bta_dm_auth_reply (tBTA_DM_MSG *p_data);
+extern void bta_dm_signal_strength(tBTA_DM_MSG *p_data);
+extern void bta_dm_tx_inqpower(tBTA_DM_MSG *p_data);
+extern void bta_dm_acl_change(tBTA_DM_MSG *p_data);
+extern void bta_dm_add_device (tBTA_DM_MSG *p_data);
+
+extern void bta_dm_pm_btm_status(tBTA_DM_MSG *p_data);
+extern void bta_dm_pm_timer(tBTA_DM_MSG *p_data);
+extern void bta_dm_add_ampkey (tBTA_DM_MSG *p_data);
+
+#if BLE_INCLUDED == TRUE
+extern void bta_dm_add_blekey (tBTA_DM_MSG *p_data);
+extern void bta_dm_add_ble_device (tBTA_DM_MSG *p_data);
+extern void bta_dm_ble_passkey_reply (tBTA_DM_MSG *p_data);
+extern void bta_dm_security_grant (tBTA_DM_MSG *p_data);
+extern void bta_dm_ble_set_bg_conn_type (tBTA_DM_MSG *p_data);
+extern void bta_dm_ble_set_conn_params (tBTA_DM_MSG *p_data);
+extern void bta_dm_ble_set_scan_params (tBTA_DM_MSG *p_data);
+#endif
+extern void bta_dm_set_encryption(tBTA_DM_MSG *p_data);
+extern void bta_dm_confirm(tBTA_DM_MSG *p_data);
+extern void bta_dm_passkey_cancel(tBTA_DM_MSG *p_data);
+#if (BTM_OOB_INCLUDED == TRUE)
+extern void bta_dm_loc_oob(tBTA_DM_MSG *p_data);
+extern void bta_dm_ci_io_req_act(tBTA_DM_MSG *p_data);
+extern void bta_dm_ci_rmt_oob_act(tBTA_DM_MSG *p_data);
+#endif /* BTM_OOB_INCLUDED */
+
+extern void bta_dm_init_pm(void);
+extern void bta_dm_disable_pm(void);
+
+extern void bta_dm_search_start (tBTA_DM_MSG *p_data);
+extern void bta_dm_search_cancel (tBTA_DM_MSG *p_data);
+extern void bta_dm_discover (tBTA_DM_MSG *p_data);
+extern void bta_dm_di_disc (tBTA_DM_MSG *p_data);
+extern void bta_dm_inq_cmpl (tBTA_DM_MSG *p_data);
+extern void bta_dm_rmt_name (tBTA_DM_MSG *p_data);
+extern void bta_dm_sdp_result (tBTA_DM_MSG *p_data);
+extern void bta_dm_search_cmpl (tBTA_DM_MSG *p_data);
+extern void bta_dm_free_sdp_db (tBTA_DM_MSG *p_data);
+extern void bta_dm_disc_result (tBTA_DM_MSG *p_data);
+extern void bta_dm_search_result (tBTA_DM_MSG *p_data);
+extern void bta_dm_discovery_cmpl (tBTA_DM_MSG *p_data);
+extern void bta_dm_queue_search (tBTA_DM_MSG *p_data);
+extern void bta_dm_queue_disc (tBTA_DM_MSG *p_data);
+extern void bta_dm_search_clear_queue (tBTA_DM_MSG *p_data);
+extern void bta_dm_search_cancel_cmpl (tBTA_DM_MSG *p_data);
+extern void bta_dm_search_cancel_notify (tBTA_DM_MSG *p_data);
+extern void bta_dm_search_cancel_transac_cmpl(tBTA_DM_MSG *p_data);
+extern void bta_dm_disc_rmt_name (tBTA_DM_MSG *p_data);
+extern tBTA_DM_PEER_DEVICE * bta_dm_find_peer_device(BD_ADDR peer_addr);
+
+extern void bta_dm_pm_active(BD_ADDR peer_addr);
+
+#if ( BTM_EIR_SERVER_INCLUDED == TRUE )
+void bta_dm_eir_update_uuid(UINT16 uuid16, BOOLEAN adding);
+#else
+#define bta_dm_eir_update_uuid(x, y)
+#endif
+
+#if ( BTM_EIR_SERVER_INCLUDED == TRUE )&&( BTA_EIR_CANNED_UUID_LIST != TRUE )&&(BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0)
+extern void bta_dm_update_eir_uuid (tBTA_DM_MSG *p_data);
+#endif
+#if (BTM_EIR_SERVER_INCLUDED == TRUE)
+extern void bta_dm_set_eir_config (tBTA_DM_MSG *p_data);
+#endif
+extern void bta_dm_enable_test_mode(tBTA_DM_MSG *p_data);
+extern void bta_dm_disable_test_mode(tBTA_DM_MSG *p_data);
+extern void bta_dm_execute_callback(tBTA_DM_MSG *p_data);
+
+extern void bta_dm_set_afh_channel_assesment(tBTA_DM_MSG *p_data);
+
+#endif /* BTA_DM_INT_H */
+
diff --git a/bta/dm/bta_dm_main.c b/bta/dm/bta_dm_main.c
new file mode 100644
index 0000000..a3dd167
--- /dev/null
+++ b/bta/dm/bta_dm_main.c
@@ -0,0 +1,331 @@
+/*****************************************************************************
+**
+** Name: bta_dm_main.c
+**
+** Description: This is the main implementation file for the BTA
+** device manager.
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bta_api.h"
+#include "bta_sys.h"
+#include "bta_dm_int.h"
+
+
+/*****************************************************************************
+** Constants and types
+*****************************************************************************/
+
+#if BTA_DYNAMIC_MEMORY == FALSE
+tBTA_DM_CB bta_dm_cb;
+tBTA_DM_SEARCH_CB bta_dm_search_cb;
+tBTA_DM_DI_CB bta_dm_di_cb;
+#endif
+
+
+#define BTA_DM_NUM_ACTIONS (BTA_DM_MAX_EVT & 0x00ff)
+
+/* type for action functions */
+typedef void (*tBTA_DM_ACTION)(tBTA_DM_MSG *p_data);
+
+/* action function list */
+const tBTA_DM_ACTION bta_dm_action[] =
+{
+
+ /* device manager local device API events */
+ bta_dm_enable, /* 0 BTA_DM_API_ENABLE_EVT */
+ bta_dm_disable, /* 1 BTA_DM_API_DISABLE_EVT */
+ bta_dm_set_dev_name, /* 2 BTA_DM_API_SET_NAME_EVT */
+ bta_dm_set_visibility, /* 3 BTA_DM_API_SET_VISIBILITY_EVT */
+ bta_dm_set_afhchannels, /* 4 BTA_DM_API_SET_AFH_CHANNELS_EVT */
+ bta_dm_signal_strength, /* 5 BTA_API_DM_SIG_STRENGTH_EVT */
+ bta_dm_vendor_spec_command,/* 6 BTA_DM_API_VENDOR_SPECIFIC_COMMAND_EVT */
+ bta_dm_tx_inqpower, /* 7 BTA_DM_API_SIG_STRENGTH_EVT */
+ bta_dm_acl_change, /* 8 BTA_DM_ACL_CHANGE_EVT */
+ bta_dm_add_device, /* 9 BTA_DM_API_ADD_DEVICE_EVT */
+
+ /* security API events */
+ bta_dm_bond, /* 10 BTA_DM_API_BOND_EVT */
+ bta_dm_bond_cancel, /* 11 BTA_DM_API_BOND_CANCEL_EVT */
+ bta_dm_pin_reply, /* 12 BTA_DM_API_PIN_REPLY_EVT */
+ bta_dm_link_policy, /* 13 BTA_DM_API_LINK_POLICY_EVT */
+ bta_dm_auth_reply, /* 14 BTA_DM_API_AUTH_REPLY_EVT */
+
+ /* power manger events */
+ bta_dm_pm_btm_status, /* 15 BTA_DM_PM_BTM_STATUS_EVT */
+ bta_dm_pm_timer, /* 16 BTA_DM_PM_TIMER_EVT*/
+
+ /* simple pairing events */
+ bta_dm_confirm, /* 17 BTA_DM_API_CONFIRM_EVT */
+
+ bta_dm_set_encryption, /* BTA_DM_API_SET_ENCRYPTION_EVT */
+
+#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
+ bta_dm_passkey_cancel, /* 19 BTA_DM_API_PASKY_CANCEL_EVT */
+#endif
+#if (BTM_OOB_INCLUDED == TRUE)
+ bta_dm_loc_oob, /* 20 BTA_DM_API_LOC_OOB_EVT */
+ bta_dm_ci_io_req_act, /* 21 BTA_DM_CI_IO_REQ_EVT */
+ bta_dm_ci_rmt_oob_act, /* 22 BTA_DM_CI_RMT_OOB_EVT */
+#endif /* BTM_OOB_INCLUDED */
+
+#if BLE_INCLUDED == TRUE
+ bta_dm_add_blekey, /* BTA_DM_API_ADD_BLEKEY_EVT */
+ bta_dm_add_ble_device, /* BTA_DM_API_ADD_BLEDEVICE_EVT */
+ bta_dm_ble_passkey_reply, /* BTA_DM_API_BLE_PASSKEY_REPLY_EVT */
+ bta_dm_security_grant,
+ bta_dm_ble_set_bg_conn_type,
+ bta_dm_ble_set_conn_params, /* BTA_DM_API_BLE_CONN_PARAM_EVT */
+ bta_dm_ble_set_scan_params, /* BTA_DM_API_BLE_SCAN_PARAM_EVT */
+#endif
+
+#if ( BTM_EIR_SERVER_INCLUDED == TRUE )&&( BTA_EIR_CANNED_UUID_LIST != TRUE )&&(BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0)
+ bta_dm_update_eir_uuid, /* BTA_DM_API_UPDATE_EIR_UUID_EVT */
+#endif
+#if (BTM_EIR_SERVER_INCLUDED == TRUE)
+ bta_dm_set_eir_config, /* BTA_DM_API_SET_EIR_CONFIG_EVT */
+#endif
+
+ bta_dm_enable_test_mode, /* BTA_DM_API_ENABLE_TEST_MODE_EVT */
+ bta_dm_disable_test_mode, /* BTA_DM_API_DISABLE_TEST_MODE_EVT */
+ bta_dm_execute_callback, /* BTA_DM_API_EXECUTE_CBACK_EVT */
+ bta_dm_set_afh_channel_assesment /* BTA_DM_API_SET_AFH_CHANNEL_ASSESMENT_EVT */
+};
+
+
+
+/* state machine action enumeration list */
+enum
+{
+ BTA_DM_API_SEARCH, /* 0 bta_dm_search_start */
+ BTA_DM_API_SEARCH_CANCEL, /* 1 bta_dm_search_cancel */
+ BTA_DM_API_DISCOVER, /* 2 bta_dm_discover */
+ BTA_DM_INQUIRY_CMPL, /* 3 bta_dm_inq_cmpl */
+ BTA_DM_REMT_NAME, /* 4 bta_dm_rmt_name */
+ BTA_DM_SDP_RESULT, /* 5 bta_dm_sdp_result */
+ BTA_DM_SEARCH_CMPL, /* 6 bta_dm_search_cmpl*/
+ BTA_DM_FREE_SDP_DB, /* 7 bta_dm_free_sdp_db */
+ BTA_DM_DISC_RESULT, /* 8 bta_dm_disc_result */
+ BTA_DM_SEARCH_RESULT, /* 9 bta_dm_search_result */
+ BTA_DM_QUEUE_SEARCH, /* 10 bta_dm_queue_search */
+ BTA_DM_QUEUE_DISC, /* 11 bta_dm_queue_disc */
+ BTA_DM_SEARCH_CLEAR_QUEUE, /* 12 bta_dm_search_clear_queue */
+ BTA_DM_SEARCH_CANCEL_CMPL, /* 13 bta_dm_search_cancel_cmpl */
+ BTA_DM_SEARCH_CANCEL_NOTIFY, /* 14 bta_dm_search_cancel_notify */
+ BTA_DM_SEARCH_CANCEL_TRANSAC_CMPL, /* 15 bta_dm_search_cancel_transac_cmpl */
+ BTA_DM_DISC_RMT_NAME, /* 16 bta_dm_disc_rmt_name */
+ BTA_DM_API_DI_DISCOVER, /* 17 bta_dm_di_disc */
+ BTA_DM_SEARCH_NUM_ACTIONS /* 18 */
+};
+
+
+/* action function list */
+const tBTA_DM_ACTION bta_dm_search_action[] =
+{
+
+ bta_dm_search_start, /* 0 BTA_DM_API_SEARCH */
+ bta_dm_search_cancel, /* 1 BTA_DM_API_SEARCH_CANCEL */
+ bta_dm_discover, /* 2 BTA_DM_API_DISCOVER */
+ bta_dm_inq_cmpl, /* 3 BTA_DM_INQUIRY_CMPL */
+ bta_dm_rmt_name, /* 4 BTA_DM_REMT_NAME */
+ bta_dm_sdp_result, /* 5 BTA_DM_SDP_RESULT */
+ bta_dm_search_cmpl, /* 6 BTA_DM_SEARCH_CMPL */
+ bta_dm_free_sdp_db, /* 7 BTA_DM_FREE_SDP_DB */
+ bta_dm_disc_result, /* 8 BTA_DM_DISC_RESULT */
+ bta_dm_search_result, /* 9 BTA_DM_SEARCH_RESULT */
+ bta_dm_queue_search, /* 10 BTA_DM_QUEUE_SEARCH */
+ bta_dm_queue_disc, /* 11 BTA_DM_QUEUE_DISC */
+ bta_dm_search_clear_queue, /* 12 BTA_DM_SEARCH_CLEAR_QUEUE */
+ bta_dm_search_cancel_cmpl, /* 13 BTA_DM_SEARCH_CANCEL_CMPL */
+ bta_dm_search_cancel_notify, /* 14 BTA_DM_SEARCH_CANCEL_NOTIFY */
+ bta_dm_search_cancel_transac_cmpl, /* 15 BTA_DM_SEARCH_CANCEL_TRANSAC_CMPL */
+ bta_dm_disc_rmt_name, /* 16 BTA_DM_DISC_RMT_NAME */
+ bta_dm_di_disc /* 17 BTA_DM_API_DI_DISCOVER */
+};
+
+#define BTA_DM_SEARCH_IGNORE BTA_DM_SEARCH_NUM_ACTIONS
+/* state table information */
+#define BTA_DM_SEARCH_ACTIONS 2 /* number of actions */
+#define BTA_DM_SEARCH_NEXT_STATE 2 /* position of next state */
+#define BTA_DM_SEARCH_NUM_COLS 3 /* number of columns in state tables */
+
+
+
+/* state table for listen state */
+const UINT8 bta_dm_search_idle_st_table[][BTA_DM_SEARCH_NUM_COLS] =
+{
+
+/* Event Action 1 Action 2 Next State */
+/* API_SEARCH */ {BTA_DM_API_SEARCH, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_ACTIVE},
+/* API_SEARCH_CANCEL */ {BTA_DM_SEARCH_CANCEL_NOTIFY, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IDLE},
+/* API_SEARCH_DISC */ {BTA_DM_API_DISCOVER, BTA_DM_SEARCH_IGNORE, BTA_DM_DISCOVER_ACTIVE},
+/* INQUIRY_CMPL */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IDLE},
+/* REMT_NAME_EVT */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IDLE},
+/* SDP_RESULT_EVT */ {BTA_DM_FREE_SDP_DB, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IDLE},
+/* SEARCH_CMPL_EVT */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IDLE},
+/* DISCV_RES_EVT */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IDLE},
+/* API_DI_DISCOVER_EVT */ {BTA_DM_API_DI_DISCOVER, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_ACTIVE}
+
+};
+const UINT8 bta_dm_search_search_active_st_table[][BTA_DM_SEARCH_NUM_COLS] =
+{
+
+/* Event Action 1 Action 2 Next State */
+/* API_SEARCH */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_ACTIVE},
+/* API_SEARCH_CANCEL */ {BTA_DM_API_SEARCH_CANCEL, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_CANCELLING},
+/* API_SEARCH_DISC */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_ACTIVE},
+/* INQUIRY_CMPL */ {BTA_DM_INQUIRY_CMPL, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_ACTIVE},
+/* REMT_NAME_EVT */ {BTA_DM_REMT_NAME, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_ACTIVE},
+/* SDP_RESULT_EVT */ {BTA_DM_SDP_RESULT, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_ACTIVE},
+/* SEARCH_CMPL_EVT */ {BTA_DM_SEARCH_CMPL, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IDLE},
+/* DISCV_RES_EVT */ {BTA_DM_SEARCH_RESULT, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_ACTIVE},
+/* API_DI_DISCOVER_EVT */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_ACTIVE}
+
+
+};
+
+const UINT8 bta_dm_search_search_cancelling_st_table[][BTA_DM_SEARCH_NUM_COLS] =
+{
+
+/* Event Action 1 Action 2 Next State */
+/* API_SEARCH */ {BTA_DM_QUEUE_SEARCH, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_CANCELLING},
+/* API_SEARCH_CANCEL */ {BTA_DM_SEARCH_CLEAR_QUEUE, BTA_DM_SEARCH_CANCEL_NOTIFY, BTA_DM_SEARCH_CANCELLING},
+/* API_SEARCH_DISC */ {BTA_DM_QUEUE_DISC, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_CANCELLING},
+/* INQUIRY_CMPL */ {BTA_DM_SEARCH_CANCEL_CMPL, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IDLE},
+/* REMT_NAME_EVT */ {BTA_DM_SEARCH_CANCEL_TRANSAC_CMPL, BTA_DM_SEARCH_CANCEL_CMPL, BTA_DM_SEARCH_IDLE},
+/* SDP_RESULT_EVT */ {BTA_DM_SEARCH_CANCEL_TRANSAC_CMPL, BTA_DM_SEARCH_CANCEL_CMPL, BTA_DM_SEARCH_IDLE},
+/* SEARCH_CMPL_EVT */ {BTA_DM_SEARCH_CANCEL_CMPL, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IDLE},
+/* DISCV_RES_EVT */ {BTA_DM_SEARCH_CANCEL_CMPL, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IDLE},
+/* API_DI_DISCOVER_EVT */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_CANCELLING}
+
+
+};
+
+const UINT8 bta_dm_search_disc_active_st_table[][BTA_DM_SEARCH_NUM_COLS] =
+{
+
+/* Event Action 1 Action 2 Next State */
+/* API_SEARCH */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE, BTA_DM_DISCOVER_ACTIVE},
+/* API_SEARCH_CANCEL */ {BTA_DM_SEARCH_CANCEL_NOTIFY, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_CANCELLING},
+/* API_SEARCH_DISC */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE, BTA_DM_DISCOVER_ACTIVE},
+/* INQUIRY_CMPL */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE, BTA_DM_DISCOVER_ACTIVE},
+/* REMT_NAME_EVT */ {BTA_DM_DISC_RMT_NAME, BTA_DM_SEARCH_IGNORE, BTA_DM_DISCOVER_ACTIVE},
+/* SDP_RESULT_EVT */ {BTA_DM_SDP_RESULT, BTA_DM_SEARCH_IGNORE, BTA_DM_DISCOVER_ACTIVE},
+/* SEARCH_CMPL_EVT */ {BTA_DM_SEARCH_CMPL, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IDLE},
+/* DISCV_RES_EVT */ {BTA_DM_DISC_RESULT, BTA_DM_SEARCH_IGNORE, BTA_DM_DISCOVER_ACTIVE},
+/* API_DI_DISCOVER_EVT */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE, BTA_DM_DISCOVER_ACTIVE}
+
+};
+
+typedef const UINT8 (*tBTA_DM_ST_TBL)[BTA_DM_SEARCH_NUM_COLS];
+
+/* state table */
+const tBTA_DM_ST_TBL bta_dm_search_st_tbl[] = {
+ bta_dm_search_idle_st_table,
+ bta_dm_search_search_active_st_table,
+ bta_dm_search_search_cancelling_st_table,
+ bta_dm_search_disc_active_st_table
+};
+
+
+/*******************************************************************************
+**
+** Function bta_dm_sm_disable
+**
+** Description unregister BTA DM
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_sm_disable( )
+{
+ bta_sys_deregister( BTA_ID_DM );
+}
+
+
+/*******************************************************************************
+**
+** Function bta_dm_sm_execute
+**
+** Description State machine event handling function for DM
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BOOLEAN bta_dm_sm_execute(BT_HDR *p_msg)
+{
+ UINT16 event = p_msg->event & 0x00ff;
+
+ APPL_TRACE_EVENT1("bta_dm_sm_execute event:0x%x", event);
+
+ /* execute action functions */
+ if(event < BTA_DM_NUM_ACTIONS)
+ {
+ (*bta_dm_action[event])( (tBTA_DM_MSG*) p_msg);
+ }
+
+ return TRUE;
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_sm_search_disable
+**
+** Description unregister BTA SEARCH DM
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_search_sm_disable( )
+{
+ bta_sys_deregister( BTA_ID_DM_SEARCH );
+
+}
+
+
+/*******************************************************************************
+**
+** Function bta_dm_search_sm_execute
+**
+** Description State machine event handling function for DM
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BOOLEAN bta_dm_search_sm_execute(BT_HDR *p_msg)
+{
+ tBTA_DM_ST_TBL state_table;
+ UINT8 action;
+ int i;
+
+ APPL_TRACE_EVENT2("bta_dm_search_sm_execute state:%d, event:0x%x",
+ bta_dm_search_cb.state, p_msg->event);
+
+ /* look up the state table for the current state */
+ state_table = bta_dm_search_st_tbl[bta_dm_search_cb.state];
+
+ bta_dm_search_cb.state = state_table[p_msg->event & 0x00ff][BTA_DM_SEARCH_NEXT_STATE];
+
+
+ /* execute action functions */
+ for (i = 0; i < BTA_DM_SEARCH_ACTIONS; i++)
+ {
+ if ((action = state_table[p_msg->event & 0x00ff][i]) != BTA_DM_SEARCH_IGNORE)
+ {
+ (*bta_dm_search_action[action])( (tBTA_DM_MSG*) p_msg);
+ }
+ else
+ {
+ break;
+ }
+ }
+ return TRUE;
+}
+
diff --git a/bta/dm/bta_dm_pm.c b/bta/dm/bta_dm_pm.c
new file mode 100644
index 0000000..eb0dfe4
--- /dev/null
+++ b/bta/dm/bta_dm_pm.c
@@ -0,0 +1,980 @@
+/*****************************************************************************
+**
+** Name: bta_dm_act.c
+**
+** Description: This file contains the action functions for device manager
+** state machine.
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "gki.h"
+#include "bd.h"
+#include "bta_sys.h"
+#include "bta_api.h"
+#include "bta_dm_int.h"
+#include "btm_api.h"
+
+#include <string.h>
+
+
+static void bta_dm_pm_cback(tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8 app_id, BD_ADDR peer_addr);
+static void bta_dm_pm_set_mode(BD_ADDR peer_addr, BOOLEAN timed_out );
+static void bta_dm_pm_timer_cback(void *p_tle);
+static void bta_dm_pm_btm_cback(BD_ADDR bd_addr, tBTM_PM_STATUS status, UINT16 value, UINT8 hci_status);
+static BOOLEAN bta_dm_pm_park(BD_ADDR peer_addr);
+static BOOLEAN bta_dm_pm_sniff(tBTA_DM_PEER_DEVICE *p_peer_dev, UINT8 index);
+static BOOLEAN bta_dm_pm_is_sco_active ();
+static void bta_dm_pm_hid_check(BOOLEAN bScoActive);
+static void bta_dm_pm_set_sniff_policy(tBTA_DM_PEER_DEVICE *p_dev, BOOLEAN bDisable);
+#if (BTM_SSR_INCLUDED == TRUE)
+static void bta_dm_pm_ssr(BD_ADDR peer_addr);
+static void bta_dm_ssr_cfg_cback(UINT8 id, UINT8 app_id, UINT16 max_lat, UINT16 min_rmt_to);
+#endif
+
+tBTA_DM_CONNECTED_SRVCS bta_dm_conn_srvcs;
+
+
+/*******************************************************************************
+**
+** Function bta_dm_init_pm
+**
+** Description Initialises the BT low power manager
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_init_pm(void)
+{
+
+ memset(&bta_dm_conn_srvcs, 0x00, sizeof(bta_dm_conn_srvcs));
+
+ /* if there are no power manger entries, so not register */
+ if(p_bta_dm_pm_cfg[0].app_id != 0)
+ {
+ bta_sys_pm_register((tBTA_SYS_CONN_CBACK*)bta_dm_pm_cback);
+
+#if (BTM_SSR_INCLUDED == TRUE)
+ bta_sys_ssr_cfg_register((tBTA_SYS_SSR_CFG_CBACK*)bta_dm_ssr_cfg_cback);
+#endif
+ BTM_PmRegister((BTM_PM_REG_SET | BTM_PM_REG_NOTIF), &bta_dm_cb.pm_id,
+ bta_dm_pm_btm_cback);
+ }
+
+
+}
+
+
+/*******************************************************************************
+**
+** Function bta_dm_disable_pm
+**
+** Description Disable PM
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_disable_pm(void)
+{
+ UINT8 i;
+
+ BTM_PmRegister( BTM_PM_DEREG, &bta_dm_cb.pm_id, NULL);
+
+ /* Need to stop all active timers. */
+ for(i=0; i<BTA_DM_NUM_PM_TIMER; i++)
+ {
+ if(bta_dm_cb.pm_timer[i].in_use)
+ {
+ APPL_TRACE_WARNING1("stop dm_pm_timer:%d", i);
+ bta_sys_stop_timer(&bta_dm_cb.pm_timer[i].timer);
+ bta_dm_cb.pm_timer[i].in_use = FALSE;
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_pm_stop_timer
+**
+** Description stop a PM timer
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_dm_pm_stop_timer(BD_ADDR peer_addr)
+{
+ UINT8 i;
+
+ for(i=0; i<BTA_DM_NUM_PM_TIMER; i++)
+ {
+
+ if(bta_dm_cb.pm_timer[i].in_use && !bdcmp(bta_dm_cb.pm_timer[i].peer_bdaddr, peer_addr))
+ {
+ APPL_TRACE_WARNING1("stop dm_pm_timer:%d", i);
+ bta_sys_stop_timer(&bta_dm_cb.pm_timer[i].timer);
+ bta_dm_cb.pm_timer[i].in_use = FALSE;
+ break;
+ }
+
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_pm_cback
+**
+** Description Conn change callback from sys for low power management
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_dm_pm_cback(tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8 app_id, BD_ADDR peer_addr)
+{
+
+ UINT8 i,j;
+ UINT16 policy_setting;
+ tBTM_STATUS btm_status;
+ tBTM_VERSION_INFO vers;
+#if (BTM_SSR_INCLUDED == TRUE)
+ int index = BTA_DM_PM_SSR0;
+#endif
+ tBTA_DM_PEER_DEVICE *p_dev;
+
+ APPL_TRACE_DEBUG3("bta_dm_pm_cback: st(%d), id(%d), app(%d)", status, id, app_id);
+
+ btm_status = BTM_ReadLocalVersion (&vers);
+ p_dev = bta_dm_find_peer_device(peer_addr);
+
+ /* Disable/Enable sniff policy on the SCO link if sco Up/Down. Will be removed in 2.2*/
+ if ((btm_status == BTM_SUCCESS) &&
+ (vers.manufacturer == LMP_COMPID_BROADCOM) &&
+ (vers.hci_version < HCI_PROTO_VERSION_2_0) &&
+ ((status == BTA_SYS_SCO_OPEN) || (status == BTA_SYS_SCO_CLOSE)) )
+ {
+ bta_dm_pm_set_sniff_policy(p_dev, (status == BTA_SYS_SCO_OPEN));
+ }
+
+ /* find if there is an power mode entry for the service */
+ for(i=1; i<=p_bta_dm_pm_cfg[0].app_id; i++)
+ {
+
+ if((p_bta_dm_pm_cfg[i].id == id)
+ && ((p_bta_dm_pm_cfg[i].app_id == BTA_ALL_APP_ID ) || (p_bta_dm_pm_cfg[i].app_id == app_id )))
+ break;
+
+ }
+
+ /* if no entries are there for the app_id and subystem in p_bta_dm_pm_spec*/
+ if(i> p_bta_dm_pm_cfg[0].app_id)
+ return;
+
+ bta_dm_pm_stop_timer(peer_addr);
+ /*p_dev = bta_dm_find_peer_device(peer_addr);*/
+
+#if (BTM_SSR_INCLUDED == TRUE)
+ /* set SSR parameters on SYS CONN OPEN */
+ if((BTA_SYS_CONN_OPEN == status) && p_dev && (p_dev->info & BTA_DM_DI_USE_SSR))
+ {
+ index = p_bta_dm_pm_spec[p_bta_dm_pm_cfg[i].spec_idx].ssr;
+ }
+#endif
+
+ /* if no action for the event */
+ if(p_bta_dm_pm_spec[p_bta_dm_pm_cfg[i].spec_idx].actn_tbl[status][0].power_mode == BTA_DM_PM_NO_ACTION)
+ {
+#if (BTM_SSR_INCLUDED == TRUE)
+ if(BTA_DM_PM_SSR0 == index) /* and do not need to set SSR, return. */
+#endif
+ return;
+ }
+
+ for(j=0; j<bta_dm_conn_srvcs.count ; j++)
+ {
+ /* check if an entry already present */
+ if((bta_dm_conn_srvcs.conn_srvc[j].id == id)
+ && (bta_dm_conn_srvcs.conn_srvc[j].app_id == app_id )
+ && !bdcmp(bta_dm_conn_srvcs.conn_srvc[j].peer_bdaddr, peer_addr))
+ break;
+
+ }
+
+ /* if subsystem has no more preference on the power mode remove
+ the cb */
+ if(p_bta_dm_pm_spec[p_bta_dm_pm_cfg[i].spec_idx].actn_tbl[status][0].power_mode == BTA_DM_PM_NO_PREF)
+ {
+
+ if(j != bta_dm_conn_srvcs.count)
+ {
+ bta_dm_conn_srvcs.count--;
+
+ for(; j<bta_dm_conn_srvcs.count ; j++)
+ {
+
+ memcpy(&bta_dm_conn_srvcs.conn_srvc[j], &bta_dm_conn_srvcs.conn_srvc[j+1], sizeof(bta_dm_conn_srvcs.conn_srvc[j]));
+
+ }
+ }
+ else
+ {
+ APPL_TRACE_WARNING0("bta_dm_act no entry for connected service cbs");
+ return;
+ }
+ }
+ else if(j == bta_dm_conn_srvcs.count )
+ {
+ /* check if we have more connected service that cbs */
+ if(bta_dm_conn_srvcs.count == BTA_DM_NUM_CONN_SRVS)
+ {
+ APPL_TRACE_WARNING0("bta_dm_act no more connected service cbs");
+ return;
+ }
+
+ /* fill in a new cb */
+ bta_dm_conn_srvcs.conn_srvc[j].id = id;
+ bta_dm_conn_srvcs.conn_srvc[j].app_id = app_id;
+ bdcpy(bta_dm_conn_srvcs.conn_srvc[j].peer_bdaddr, peer_addr);
+
+ APPL_TRACE_WARNING2("new conn_srvc id:%d, app_id:%d", id, app_id);
+
+ bta_dm_conn_srvcs.count++;
+ bta_dm_conn_srvcs.conn_srvc[j].state = status;
+ }
+ else
+ {
+ /* no service is added or removed. only updating status. */
+ bta_dm_conn_srvcs.conn_srvc[j].state = status;
+ }
+
+ if(p_dev)
+ {
+ p_dev->pm_mode_attempted = 0;
+ p_dev->pm_mode_failed = 0;
+ }
+
+#if (BTM_SSR_INCLUDED == TRUE)
+ if(p_bta_dm_ssr_spec[index].max_lat)
+ {
+ bta_dm_pm_ssr(peer_addr);
+ }
+#endif
+
+ bta_dm_pm_set_mode(peer_addr, FALSE);
+
+ /* perform the HID link workaround if needed
+ ** 1. If SCO up/down event is received OR
+ ** 2. If HID connection open is received and SCO is already active.
+ ** This will handle the case where HID connects when SCO already active
+ */
+ if ( (btm_status == BTM_SUCCESS) &&
+ ( ((status == BTA_SYS_SCO_OPEN) || (status == BTA_SYS_SCO_CLOSE)) ||
+ ((status == BTA_SYS_CONN_OPEN) && (id == BTA_ID_HH) && bta_dm_pm_is_sco_active()) ) )
+ {
+ BOOLEAN bScoActive;
+ if (status == BTA_SYS_CONN_OPEN)
+ bScoActive = TRUE;
+ else
+ bScoActive = (status == BTA_SYS_SCO_OPEN);
+
+ bta_dm_pm_hid_check(bScoActive);
+ }
+
+}
+
+
+/*******************************************************************************
+**
+** Function bta_dm_pm_set_mode
+**
+** Description Set the power mode for the device
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_dm_pm_set_mode(BD_ADDR peer_addr, BOOLEAN timed_out )
+{
+
+ tBTA_DM_PM_ACTTION pm_action = BTA_DM_PM_NO_ACTION;
+ UINT16 timeout = 0;
+ UINT8 i,j;
+ tBTA_DM_PM_ACTTION failed_pm = 0;
+ tBTA_DM_PEER_DEVICE *p_peer_device = NULL;
+ tBTA_DM_PM_ACTTION allowed_modes = 0;
+ tBTA_DM_PM_ACTTION pref_modes = 0;
+ tBTA_DM_PM_CFG *p_pm_cfg;
+ tBTA_DM_PM_SPEC *p_pm_spec;
+ tBTA_DM_PM_ACTN *p_act0, *p_act1;
+ tBTA_DM_SRVCS *p_srvcs;
+
+
+ if(!bta_dm_cb.device_list.count)
+ return;
+
+ /* see if any attempt to put device in low power mode failed */
+ p_peer_device = bta_dm_find_peer_device(peer_addr);
+ /* if no peer device found return */
+ if (p_peer_device == NULL)
+ return;
+
+ failed_pm = p_peer_device->pm_mode_failed;
+
+ for(i=0; i<bta_dm_conn_srvcs.count ; i++)
+ {
+
+ p_srvcs = &bta_dm_conn_srvcs.conn_srvc[i];
+ if(!bdcmp(p_srvcs->peer_bdaddr, peer_addr))
+ {
+
+ /* p_bta_dm_pm_cfg[0].app_id is the number of entries */
+ for(j=1; j<=p_bta_dm_pm_cfg[0].app_id; j++)
+ {
+ if((p_bta_dm_pm_cfg[j].id == p_srvcs->id)
+ && ((p_bta_dm_pm_cfg[j].app_id == BTA_ALL_APP_ID ) ||
+ (p_bta_dm_pm_cfg[j].app_id == p_srvcs->app_id)))
+ break;
+ }
+
+ p_pm_cfg = &p_bta_dm_pm_cfg[j];
+ p_pm_spec = &p_bta_dm_pm_spec[p_pm_cfg->spec_idx];
+ p_act0 = &p_pm_spec->actn_tbl[p_srvcs->state][0];
+ p_act1 = &p_pm_spec->actn_tbl[p_srvcs->state][1];
+
+ APPL_TRACE_DEBUG3("bta_dm_pm_set_mode: srvcsid: %d, state: %d, j: %d", p_srvcs->id, p_srvcs->state, j);
+ allowed_modes |= p_pm_spec->allow_mask;
+
+ /* PM actions are in the order of strictness */
+
+ /* first check if the first preference is ok */
+ if(!(failed_pm & p_act0->power_mode))
+ {
+ pref_modes |= p_act0->power_mode;
+
+ if(p_act0->power_mode > pm_action)
+ {
+ pm_action = p_act0->power_mode;
+ timeout = p_act0->timeout;
+
+ }
+ }
+ /* if first preference has already failed, try second preference */
+ else if(!(failed_pm & p_act1->power_mode))
+ {
+ pref_modes |= p_act1->power_mode;
+
+ if(p_act1->power_mode > pm_action)
+ {
+ pm_action = p_act1->power_mode;
+ timeout = p_act1->timeout;
+
+ }
+ }
+ }
+ }
+
+ if(pm_action & (BTA_DM_PM_PARK | BTA_DM_PM_SNIFF))
+ {
+
+ /* some service don't like the mode */
+ if(!(allowed_modes & pm_action))
+ {
+
+ /* select the other mode if its allowed and preferred, otherwise 0 which is BTA_DM_PM_NO_ACTION */
+ pm_action = (allowed_modes & (BTA_DM_PM_PARK | BTA_DM_PM_SNIFF) & pref_modes);
+
+ /* no timeout needed if no action is required */
+ if(pm_action == BTA_DM_PM_NO_ACTION)
+ {
+ timeout = 0;
+ }
+
+ }
+
+
+ }
+
+ if(!timed_out && timeout)
+ {
+
+ for(i=0; i<BTA_DM_NUM_PM_TIMER; i++)
+ {
+
+ if(!bta_dm_cb.pm_timer[i].in_use)
+ {
+ bta_dm_cb.pm_timer[i].in_use = TRUE;
+ bdcpy(bta_dm_cb.pm_timer[i].peer_bdaddr, peer_addr);
+ bta_dm_cb.pm_timer[i].timer.p_cback = bta_dm_pm_timer_cback;
+ bta_sys_start_timer(&bta_dm_cb.pm_timer[i].timer, 0, timeout);
+ APPL_TRACE_WARNING2("start dm_pm_timer:%d, %d", i, timeout);
+ return;
+
+ }
+
+ }
+
+ /* no more timers */
+ if(i==BTA_DM_NUM_PM_TIMER)
+ {
+ APPL_TRACE_WARNING0("bta_dm_act dm_pm_timer no more");
+ return;
+ }
+ }
+
+ if(pm_action == BTA_DM_PM_NO_ACTION)
+ {
+
+
+ }
+ else if(pm_action == BTA_DM_PM_PARK)
+ {
+ p_peer_device->pm_mode_attempted = BTA_DM_PM_PARK;
+ bta_dm_pm_park(peer_addr);
+
+ }
+ else if(pm_action & BTA_DM_PM_SNIFF)
+ {
+ /* dont initiate SNIFF, if link_policy has it disabled */
+ if (p_peer_device->link_policy & HCI_ENABLE_SNIFF_MODE)
+ {
+ p_peer_device->pm_mode_attempted = BTA_DM_PM_SNIFF;
+ bta_dm_pm_sniff(p_peer_device, (UINT8)(pm_action & 0x0F) );
+ }
+ else
+ {
+ APPL_TRACE_DEBUG0("bta_dm_pm_set_mode: Link policy disallows SNIFF, ignore request");
+ }
+ }
+ else if(pm_action == BTA_DM_PM_ACTIVE)
+ {
+
+ bta_dm_pm_active(peer_addr);
+
+ }
+
+
+}
+
+
+/*******************************************************************************
+**
+** Function bta_ag_pm_park
+**
+** Description Switch to park mode.
+**
+**
+** Returns TRUE if park attempted, FALSE otherwise.
+**
+*******************************************************************************/
+static BOOLEAN bta_dm_pm_park(BD_ADDR peer_addr)
+{
+
+ tBTM_PM_MODE mode = BTM_PM_STS_ACTIVE;
+
+ /* if not in park mode, switch to park */
+ BTM_ReadPowerMode(peer_addr, &mode);
+
+ if(mode != BTM_PM_MD_PARK)
+ {
+ BTM_SetPowerMode (bta_dm_cb.pm_id, peer_addr, &p_bta_dm_pm_md[BTA_DM_PM_PARK_IDX]);
+ }
+ return TRUE;
+
+}
+
+
+/*******************************************************************************
+**
+** Function bta_ag_pm_sniff
+**
+** Description Switch to sniff mode.
+**
+**
+** Returns TRUE if sniff attempted, FALSE otherwise.
+**
+*******************************************************************************/
+static BOOLEAN bta_dm_pm_sniff(tBTA_DM_PEER_DEVICE *p_peer_dev, UINT8 index)
+{
+ tBTM_PM_MODE mode = BTM_PM_STS_ACTIVE;
+ tBTM_PM_PWR_MD pwr_md;
+ tBTM_STATUS status;
+
+ BTM_ReadPowerMode(p_peer_dev->peer_bdaddr, &mode);
+
+#if (BTM_SSR_INCLUDED == TRUE)
+ APPL_TRACE_DEBUG3("bta_dm_pm_sniff cur:%d, idx:%d, info:x%x", mode, index, p_peer_dev->info);
+ if (mode != BTM_PM_MD_SNIFF ||
+ (HCI_SNIFF_SUB_RATE_SUPPORTED(BTM_ReadLocalFeatures ()) &&
+ HCI_SNIFF_SUB_RATE_SUPPORTED(BTM_ReadRemoteFeatures (p_peer_dev->peer_bdaddr)) &&
+ !(p_peer_dev->info & BTA_DM_DI_USE_SSR)))
+#else
+ APPL_TRACE_DEBUG2("bta_dm_pm_sniff cur:%d, idx:%d", mode, index);
+ if(mode != BTM_PM_MD_SNIFF)
+#endif
+ {
+ /* if the current mode is not sniff, issue the sniff command.
+ * If sniff, but SSR is not used in this link, still issue the command */
+ memcpy(&pwr_md, &p_bta_dm_pm_md[index], sizeof (tBTM_PM_PWR_MD));
+ if (p_peer_dev->info & BTA_DM_DI_INT_SNIFF)
+ {
+ pwr_md.mode |= BTM_PM_MD_FORCE;
+ }
+ status = BTM_SetPowerMode (bta_dm_cb.pm_id, p_peer_dev->peer_bdaddr, &pwr_md);
+ if (status == BTM_CMD_STORED|| status == BTM_CMD_STARTED)
+ {
+ p_peer_dev->info &= ~(BTA_DM_DI_INT_SNIFF|BTA_DM_DI_ACP_SNIFF);
+ p_peer_dev->info |= BTA_DM_DI_SET_SNIFF;
+ }
+ else if (status == BTM_SUCCESS)
+ {
+ APPL_TRACE_DEBUG0("bta_dm_pm_sniff BTM_SetPowerMode() returns BTM_SUCCESS");
+ p_peer_dev->info &= ~(BTA_DM_DI_INT_SNIFF|BTA_DM_DI_ACP_SNIFF|BTA_DM_DI_SET_SNIFF);
+ }
+ else /* error */
+ {
+ APPL_TRACE_ERROR1("bta_dm_pm_sniff BTM_SetPowerMode() returns ERROR status=%d", status);
+ p_peer_dev->info &= ~(BTA_DM_DI_INT_SNIFF|BTA_DM_DI_ACP_SNIFF|BTA_DM_DI_SET_SNIFF);
+ }
+ }
+ /* else already in sniff and is using SSR, do nothing */
+
+ return TRUE;
+
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_pm_ssr
+**
+** Description checks and sends SSR parameters
+**
+** Returns void
+**
+*******************************************************************************/
+#if (BTM_SSR_INCLUDED == TRUE)
+static void bta_dm_pm_ssr(BD_ADDR peer_addr)
+{
+ tBTA_DM_SSR_SPEC *p_spec, *p_spec_cur;
+ UINT8 i,j;
+ int ssr = BTA_DM_PM_SSR0;
+
+ /* go through the connected services */
+ for(i=0; i<bta_dm_conn_srvcs.count ; i++)
+ {
+ if(!bdcmp(bta_dm_conn_srvcs.conn_srvc[i].peer_bdaddr, peer_addr))
+ {
+ /* p_bta_dm_pm_cfg[0].app_id is the number of entries */
+ for(j=1; j<=p_bta_dm_pm_cfg[0].app_id; j++)
+ {
+ /* find the associated p_bta_dm_pm_cfg */
+ if((p_bta_dm_pm_cfg[j].id == bta_dm_conn_srvcs.conn_srvc[i].id)
+ && ((p_bta_dm_pm_cfg[j].app_id == BTA_ALL_APP_ID )
+ || (p_bta_dm_pm_cfg[j].app_id == bta_dm_conn_srvcs.conn_srvc[i].app_id)))
+ {
+ APPL_TRACE_WARNING2("bta_dm_pm_ssr conn_srvc id:%d, app_id:%d",
+ bta_dm_conn_srvcs.conn_srvc[i].id, bta_dm_conn_srvcs.conn_srvc[i].app_id);
+ break;
+ }
+ }
+
+ /* find the ssr index with the smallest max latency. */
+ p_spec_cur = &p_bta_dm_ssr_spec[p_bta_dm_pm_spec[p_bta_dm_pm_cfg[j].spec_idx].ssr];
+ p_spec = &p_bta_dm_ssr_spec[ssr];
+
+ if (p_spec_cur->max_lat < p_spec->max_lat ||
+ (ssr == BTA_DM_PM_SSR0 && p_bta_dm_pm_spec[p_bta_dm_pm_cfg[j].spec_idx].ssr != BTA_DM_PM_SSR0))
+ {
+ ssr = p_bta_dm_pm_spec[p_bta_dm_pm_cfg[j].spec_idx].ssr;
+ }
+
+ }
+ }
+
+ p_spec = &p_bta_dm_ssr_spec[ssr];
+ APPL_TRACE_WARNING2("bta_dm_pm_ssr:%d, lat:%d", ssr, p_spec->max_lat);
+ if(p_spec->max_lat)
+ {
+ /* set the SSR parameters. */
+ BTM_SetSsrParams (peer_addr, p_spec->max_lat,
+ p_spec->min_rmt_to, p_spec->min_loc_to);
+ }
+}
+/*******************************************************************************
+**
+** Function bta_dm_ssr_cfg_cback
+**
+** Description Conn change callback from sys for low power management
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_dm_ssr_cfg_cback(UINT8 id, UINT8 app_id,
+ UINT16 max_lat, UINT16 min_rmt_to)
+{
+ tBTA_DM_SSR_SPEC *p_spec;
+ UINT8 i, index;
+ /* find if there is an power mode entry for the service */
+ for(i=1; i<=p_bta_dm_pm_cfg[0].app_id; i++)
+ {
+
+ if((p_bta_dm_pm_cfg[i].id == id)
+ && ((p_bta_dm_pm_cfg[i].app_id == BTA_ALL_APP_ID ) || (p_bta_dm_pm_cfg[i].app_id == app_id )))
+ break;
+
+ }
+ /* if no entries are there for the app_id and subystem in p_bta_dm_pm_spec*/
+ if(i> p_bta_dm_pm_cfg[0].app_id)
+ return;
+
+ index = p_bta_dm_pm_spec[p_bta_dm_pm_cfg[i].spec_idx].ssr;
+
+ APPL_TRACE_DEBUG2("SSR parameter changed to: max_latency: %d min_tout: %d", max_lat, min_rmt_to);
+
+ p_spec = &p_bta_dm_ssr_spec[index];
+ p_spec->max_lat = max_lat;
+ p_spec->min_rmt_to = min_rmt_to;
+}
+
+
+#endif
+/*******************************************************************************
+**
+** Function bta_dm_pm_active
+**
+** Description Brings connection to active mode
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_pm_active(BD_ADDR peer_addr)
+{
+ tBTM_PM_PWR_MD pm;
+
+ memset( (void*)&pm, 0, sizeof(pm));
+
+ /* switch to active mode */
+ pm.mode = BTM_PM_MD_ACTIVE;
+ BTM_SetPowerMode (bta_dm_cb.pm_id, peer_addr, &pm);
+
+
+}
+
+
+/*******************************************************************************
+**
+** Function bta_dm_pm_btm_cback
+**
+** Description BTM power manager callback.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_dm_pm_btm_cback(BD_ADDR bd_addr, tBTM_PM_STATUS status, UINT16 value, UINT8 hci_status)
+{
+ tBTA_DM_PM_BTM_STATUS *p_buf;
+
+ if ((p_buf = (tBTA_DM_PM_BTM_STATUS *) GKI_getbuf(sizeof(tBTA_DM_PM_BTM_STATUS))) != NULL)
+ {
+ p_buf->hdr.event = BTA_DM_PM_BTM_STATUS_EVT;
+ p_buf->status = status;
+ p_buf->value = value;
+ p_buf->hci_status = hci_status;
+ bdcpy(p_buf->bd_addr, bd_addr);
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_pm_timer_cback
+**
+** Description Power management timer callback.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_dm_pm_timer_cback(void *p_tle)
+{
+ tBTA_DM_PM_TIMER *p_buf;
+ UINT8 i;
+
+ APPL_TRACE_WARNING0("dm_pm_timer expires");
+
+ for(i=0; i<BTA_DM_NUM_PM_TIMER; i++)
+ {
+
+ if(bta_dm_cb.pm_timer[i].in_use)
+ {
+
+ if(&bta_dm_cb.pm_timer[i].timer == (TIMER_LIST_ENT*) p_tle)
+ {
+ APPL_TRACE_WARNING1("dm_pm_timer expires %d", i);
+ bta_dm_cb.pm_timer[i].in_use = FALSE;
+ break;
+ }
+
+ }
+
+ }
+
+
+ /* no more timers */
+ if(i==BTA_DM_NUM_PM_TIMER)
+ {
+ return;
+ }
+
+ if ((p_buf = (tBTA_DM_PM_TIMER *) GKI_getbuf(sizeof(tBTA_DM_PM_TIMER))) != NULL)
+ {
+ p_buf->hdr.event = BTA_DM_PM_TIMER_EVT;
+ bdcpy(p_buf->bd_addr, bta_dm_cb.pm_timer[i].peer_bdaddr);
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_pm_btm_status
+**
+** Description Process pm status event from btm
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_pm_btm_status(tBTA_DM_MSG *p_data)
+{
+
+ tBTA_DM_PEER_DEVICE *p_dev;
+ tBTA_DM_DEV_INFO info;
+
+ APPL_TRACE_DEBUG1("bta_dm_pm_btm_status:%d", p_data->pm_status.status);
+ p_dev = bta_dm_find_peer_device(p_data->pm_status.bd_addr);
+ if(NULL == p_dev)
+ return;
+
+ info = p_dev->info;
+ /* check new mode */
+ switch (p_data->pm_status.status)
+ {
+ case BTM_PM_STS_ACTIVE:
+ /* if our sniff or park attempt failed
+ we should not try it again*/
+ if (p_data->pm_status.hci_status != 0)
+ {
+ APPL_TRACE_ERROR1("bta_dm_pm_btm_status hci_status=%d", p_data->pm_status.hci_status);
+ p_dev->info &= ~(BTA_DM_DI_INT_SNIFF|BTA_DM_DI_ACP_SNIFF|BTA_DM_DI_SET_SNIFF);
+
+ if(p_dev->pm_mode_attempted &(BTA_DM_PM_PARK | BTA_DM_PM_SNIFF))
+ {
+ p_dev->pm_mode_failed
+ |= ((BTA_DM_PM_PARK | BTA_DM_PM_SNIFF) & p_dev->pm_mode_attempted);
+ bta_dm_pm_stop_timer(p_data->pm_status.bd_addr);
+ bta_dm_pm_set_mode(p_data->pm_status.bd_addr, FALSE);
+ }
+ }
+ else
+ {
+#if (BTM_SSR_INCLUDED == TRUE)
+ if(p_dev->prev_low)
+ {
+ /* need to send the SSR paramaters to controller again */
+ bta_dm_pm_ssr(p_dev->peer_bdaddr);
+ }
+ p_dev->prev_low = BTM_PM_STS_ACTIVE;
+#endif
+ bta_dm_pm_stop_timer(p_data->pm_status.bd_addr);
+ bta_dm_pm_set_mode(p_data->pm_status.bd_addr, FALSE);
+ }
+ break;
+
+#if (BTM_SSR_INCLUDED == TRUE)
+ case BTM_PM_STS_PARK:
+ case BTM_PM_STS_HOLD:
+ /* save the previous low power mode - for SSR.
+ * SSR parameters are sent to controller on "conn open".
+ * the numbers stay good until park/hold/detach */
+ if(p_dev->info & BTA_DM_DI_USE_SSR)
+ p_dev->prev_low = p_data->pm_status.status;
+ break;
+
+ case BTM_PM_STS_SSR:
+ if(p_data->pm_status.value)
+ p_dev->info |= BTA_DM_DI_USE_SSR;
+ else
+ p_dev->info &= ~BTA_DM_DI_USE_SSR;
+ break;
+#endif
+ case BTM_PM_STS_SNIFF:
+ p_dev->info &= ~(BTA_DM_DI_SET_SNIFF|BTA_DM_DI_INT_SNIFF|BTA_DM_DI_ACP_SNIFF);
+ if (info & BTA_DM_DI_SET_SNIFF)
+ p_dev->info |= BTA_DM_DI_INT_SNIFF;
+ else
+ p_dev->info |= BTA_DM_DI_ACP_SNIFF;
+ break;
+
+ case BTM_PM_STS_ERROR:
+ p_dev->info &= ~BTA_DM_DI_SET_SNIFF;
+ break;
+
+ default:
+ break;
+ }
+
+
+
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_pm_timer
+**
+** Description Process pm timer event from btm
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_pm_timer(tBTA_DM_MSG *p_data)
+{
+
+ APPL_TRACE_WARNING0("proc dm_pm_timer expires");
+ bta_dm_pm_set_mode(p_data->pm_status.bd_addr, TRUE);
+
+
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_find_peer_device
+**
+** Description Given an address, find the associated control block.
+**
+** Returns tBTA_DM_PEER_DEVICE
+**
+*******************************************************************************/
+tBTA_DM_PEER_DEVICE * bta_dm_find_peer_device(BD_ADDR peer_addr)
+{
+ tBTA_DM_PEER_DEVICE *p_dev = NULL;
+ int i;
+
+ for(i=0; i<bta_dm_cb.device_list.count; i++)
+ {
+ if(!bdcmp( bta_dm_cb.device_list.peer_device[i].peer_bdaddr, peer_addr))
+ {
+ p_dev = &bta_dm_cb.device_list.peer_device[i];
+ break;
+ }
+
+ }
+ return p_dev;
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_is_sco_active
+**
+** Description Loop through connected services for HFP+State=SCO
+**
+** Returns BOOLEAN. TRUE if SCO active, else FALSE
+**
+*******************************************************************************/
+static BOOLEAN bta_dm_pm_is_sco_active ()
+{
+ int j;
+ BOOLEAN bScoActive = FALSE;
+
+ for(j=0; j<bta_dm_conn_srvcs.count ; j++)
+ {
+ /* check if an entry already present */
+ if ( (bta_dm_conn_srvcs.conn_srvc[j].id == BTA_ID_AG ) && (bta_dm_conn_srvcs.conn_srvc[j].state == BTA_SYS_SCO_OPEN) )
+ {
+ bScoActive = TRUE;
+ break;
+ }
+ }
+
+ APPL_TRACE_DEBUG1("bta_dm_is_sco_active: SCO active: %d", bScoActive);
+ return bScoActive;
+}
+
+
+/*******************************************************************************
+**
+** Function bta_dm_pm_hid_check
+**
+** Description Disables/Enables sniff in link policy based on SCO Up/Down
+**
+** Returns None
+**
+*******************************************************************************/
+
+static void bta_dm_pm_hid_check(BOOLEAN bScoActive)
+{
+ int j;
+
+ /* if HID is active, disable the link policy */
+ for(j=0; j<bta_dm_conn_srvcs.count ; j++)
+ {
+ /* check if an entry already present */
+ if(bta_dm_conn_srvcs.conn_srvc[j].id == BTA_ID_HH )
+ {
+ APPL_TRACE_DEBUG2 ("SCO status change(Active: %d), modify HID link policy. state: %d",
+ bScoActive, bta_dm_conn_srvcs.conn_srvc[j].state);
+ bta_dm_pm_set_sniff_policy( bta_dm_find_peer_device(bta_dm_conn_srvcs.conn_srvc[j].peer_bdaddr), bScoActive);
+
+ /* if we had disabled link policy, seems like the hid device stop retrying SNIFF after a few tries. force sniff if needed */
+ if (!bScoActive)
+ bta_dm_pm_set_mode(bta_dm_conn_srvcs.conn_srvc[j].peer_bdaddr, FALSE);
+ }
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_pm_set_sniff_policy
+**
+** Description Disables/Enables sniff in link policy for the give device
+**
+** Returns None
+**
+*******************************************************************************/
+static void bta_dm_pm_set_sniff_policy(tBTA_DM_PEER_DEVICE *p_dev, BOOLEAN bDisable)
+{
+ UINT16 policy_setting;
+
+ if (!p_dev)
+ return;
+
+ if (bDisable)
+ {
+ policy_setting = bta_dm_cb.cur_policy &
+ (HCI_ENABLE_MASTER_SLAVE_SWITCH |
+ HCI_ENABLE_HOLD_MODE |
+ HCI_ENABLE_PARK_MODE);
+
+ }
+ else
+ {
+ /* allow sniff after sco is closed */
+ policy_setting= bta_dm_cb.cur_policy;
+ }
+
+ /* if disabling SNIFF, make sure link is Active */
+ if (bDisable)
+ bta_dm_pm_active(p_dev->peer_bdaddr);
+
+ /* update device record and set link policy */
+ p_dev->link_policy = policy_setting;
+ BTM_SetLinkPolicy(p_dev->peer_bdaddr, &policy_setting);
+
+}
diff --git a/bta/dm/bta_dm_sco.c b/bta/dm/bta_dm_sco.c
new file mode 100644
index 0000000..7ad840a
--- /dev/null
+++ b/bta/dm/bta_dm_sco.c
@@ -0,0 +1,684 @@
+/*****************************************************************************
+**
+** Name: bta_dm_sco.c
+**
+** Description: This file contains the down sampling utility to convert PCM
+** samples in 16k/32k/48k/44.1k/22050/11025 sampling rate into
+** 8K/16bits samples required for SCO channel format. One API
+** function isprovided and only possible to be used when
+** transmitting SCO data is sent via HCI interface.
+**
+** Original code took from BTW/CE.
+**
+** Copyright (c) 2003-2007, Broadcom Corp., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include <string.h>
+#include "bta_api.h"
+#include "bta_sys.h"
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+
+#ifndef BTA_DM_SCO_DEBUG
+#define BTA_DM_SCO_DEBUG FALSE
+#endif
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+#define BTA_DM_PCM_OVERLAP_SIZE 48
+
+#define BTA_DM_PCM_SMPL_RATE_44100 44100
+#define BTA_DM_PCM_SMPL_RATE_22050 22050
+#define BTA_DM_PCM_SMPL_RATE_11025 11025
+
+/*****************************************************************************
+** Data types for PCM Resampling utility
+*****************************************************************************/
+
+typedef INT32 (*PCONVERT_TO_BT_FILTERED) (UINT8 *pSrc, void *pDst, UINT32 dwSrcSamples,
+ UINT32 dwSrcSps,INT32 *pLastCurPos, UINT8 *pOverlapArea);
+typedef INT32 (*PCONVERT_TO_BT_NOFILTER) (void *pSrc, void *pDst, UINT32 dwSrcSamples,
+ UINT32 dwSrcSps);
+typedef struct
+{
+ UINT8 overlap_area[BTA_DM_PCM_OVERLAP_SIZE * 4];
+ UINT32 cur_pos; /* current position */
+ UINT32 src_sps; /* samples per second (source audio data) */
+ PCONVERT_TO_BT_FILTERED filter; /* the action function to do the
+ conversion 44100, 22050, 11025*/
+ PCONVERT_TO_BT_NOFILTER nofilter; /* the action function to do
+ the conversion 48000, 32000, 16000*/
+ UINT32 bits; /* number of bits per pcm sample */
+ UINT32 n_channels; /* number of channels (i.e. mono(1), stereo(2)...) */
+ UINT32 sample_size;
+ UINT32 can_be_filtered;
+ UINT32 divisor;
+} tBTA_DM_PCM_RESAMPLE_CB;
+
+tBTA_DM_PCM_RESAMPLE_CB bta_dm_pcm_cb;
+
+/*****************************************************************************
+** Macro Definition
+*****************************************************************************/
+
+
+#define CHECK_SATURATION16(x) \
+ if (x > 32767) \
+ x = 32767; \
+ else if (x < -32768) \
+ x = -32768;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+#define CONVERT_44100_TO_BLUETOOTH(pStart, pEnd) \
+ { \
+ INT32 out1, out2, out3, out4, out5; \
+ SRC_TYPE *pS = (SRC_TYPE *)pStart; \
+ SRC_TYPE *pSEnd = (SRC_TYPE *)pEnd; \
+ \
+ while (pS < pSEnd) \
+ { \
+ CurrentPos -= 8000; \
+ \
+ if (CurrentPos >= 0) \
+ { \
+ pS += SRC_CHANNELS; \
+ continue; \
+ } \
+ CurrentPos += dwSrcSps; \
+ \
+ out1 = (SRC_SAMPLE(0) * 1587) \
+ + ((SRC_SAMPLE(1) + SRC_SAMPLE(-1)) * 1522) \
+ + ((SRC_SAMPLE(2) + SRC_SAMPLE(-2)) * 1337) \
+ + ((SRC_SAMPLE(3) + SRC_SAMPLE(-3)) * 1058); \
+ \
+ out1 = out1 / 30000; \
+ \
+ out2 = ((SRC_SAMPLE(4) + SRC_SAMPLE(-4)) * 725) \
+ + ((SRC_SAMPLE(5) + SRC_SAMPLE(-5)) * 384) \
+ + ((SRC_SAMPLE(6) + SRC_SAMPLE(-6)) * 79); \
+ \
+ out2 = out2 / 30000; \
+ \
+ out3 = ((SRC_SAMPLE(7) + SRC_SAMPLE(-7)) * 156) \
+ + ((SRC_SAMPLE(8) + SRC_SAMPLE(-8)) * 298) \
+ + ((SRC_SAMPLE(9) + SRC_SAMPLE(-9)) * 345); \
+ \
+ out3 = out3 / 30000; \
+ \
+ out4 = ((SRC_SAMPLE(10) + SRC_SAMPLE(-10)) * 306) \
+ + ((SRC_SAMPLE(11) + SRC_SAMPLE(-11)) * 207) \
+ + ((SRC_SAMPLE(12) + SRC_SAMPLE(-12)) * 78); \
+ \
+ out4 = out4 / 30000; \
+ \
+ out5 = out1 + out2 - out3 - out4; \
+ \
+ CHECK_SATURATION16(out5); \
+ *psBtOut++ = (INT16)out5; \
+ \
+ pS += SRC_CHANNELS; \
+ } \
+ }
+
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+#define CONVERT_22050_TO_BLUETOOTH(pStart, pEnd) \
+ { \
+ INT32 out1, out2, out3, out4, out5; \
+ SRC_TYPE *pS = (SRC_TYPE *)pStart; \
+ SRC_TYPE *pSEnd = (SRC_TYPE *)pEnd; \
+ \
+ while (pS < pSEnd) \
+ { \
+ CurrentPos -= 8000; \
+ \
+ if (CurrentPos >= 0) \
+ { \
+ pS += SRC_CHANNELS; \
+ continue; \
+ } \
+ CurrentPos += dwSrcSps; \
+ \
+ out1 = (SRC_SAMPLE(0) * 2993) \
+ + ((SRC_SAMPLE(1) + SRC_SAMPLE(-1)) * 2568) \
+ + ((SRC_SAMPLE(2) + SRC_SAMPLE(-2)) * 1509) \
+ + ((SRC_SAMPLE(3) + SRC_SAMPLE(-3)) * 331); \
+ \
+ out1 = out1 / 30000; \
+ \
+ out2 = ((SRC_SAMPLE(4) + SRC_SAMPLE(-4)) * 454) \
+ + ((SRC_SAMPLE(5) + SRC_SAMPLE(-5)) * 620) \
+ + ((SRC_SAMPLE(6) + SRC_SAMPLE(-6)) * 305); \
+ \
+ out2 = out2 / 30000; \
+ \
+ out3 = ((SRC_SAMPLE(7) + SRC_SAMPLE(-7)) * 127) \
+ + ((SRC_SAMPLE(8) + SRC_SAMPLE(-8)) * 350) \
+ + ((SRC_SAMPLE(9) + SRC_SAMPLE(-9)) * 265) \
+ + ((SRC_SAMPLE(10) + SRC_SAMPLE(-10)) * 6); \
+ \
+ out3 = out3 / 30000; \
+ \
+ out4 = ((SRC_SAMPLE(11) + SRC_SAMPLE(-11)) * 201); \
+ \
+ out4 = out4 / 30000; \
+ \
+ out5 = out1 - out2 + out3 - out4; \
+ \
+ CHECK_SATURATION16(out5); \
+ *psBtOut++ = (INT16)out5; \
+ \
+ pS += SRC_CHANNELS; \
+ } \
+ }
+
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+#define CONVERT_11025_TO_BLUETOOTH(pStart, pEnd) \
+ { \
+ INT32 out1; \
+ SRC_TYPE *pS = (SRC_TYPE *)pStart; \
+ SRC_TYPE *pSEnd = (SRC_TYPE *)pEnd; \
+ \
+ while (pS < pSEnd) \
+ { \
+ CurrentPos -= 8000; \
+ \
+ if (CurrentPos >= 0) \
+ { \
+ pS += SRC_CHANNELS; \
+ continue; \
+ } \
+ CurrentPos += dwSrcSps; \
+ \
+ out1 = (SRC_SAMPLE(0) * 6349) \
+ + ((SRC_SAMPLE(1) + SRC_SAMPLE(-1)) * 2874) \
+ - ((SRC_SAMPLE(2) + SRC_SAMPLE(-2)) * 1148) \
+ - ((SRC_SAMPLE(3) + SRC_SAMPLE(-3)) * 287) \
+ + ((SRC_SAMPLE(4) + SRC_SAMPLE(-4)) * 675) \
+ - ((SRC_SAMPLE(5) + SRC_SAMPLE(-5)) * 258) \
+ - ((SRC_SAMPLE(6) + SRC_SAMPLE(-6)) * 206) \
+ + ((SRC_SAMPLE(7) + SRC_SAMPLE(-7)) * 266); \
+ \
+ out1 = out1 / 30000; \
+ \
+ CHECK_SATURATION16(out1); \
+ *psBtOut++ = (INT16)out1; \
+ \
+ pS += SRC_CHANNELS; \
+ } \
+ }
+
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+#undef SRC_CHANNELS
+#undef SRC_SAMPLE
+#undef SRC_TYPE
+
+#define SRC_TYPE UINT8
+#define SRC_CHANNELS 1
+#define SRC_SAMPLE(x) ((pS[x] - 0x80) << 8)
+
+/*****************************************************************************
+** Local Function
+*****************************************************************************/
+INT32 Convert_8M_ToBT_Filtered (UINT8 *pSrc, void *pDst, UINT32 dwSrcSamples,
+ UINT32 dwSrcSps, INT32 *pLastCurPos, UINT8 *pOverlapArea)
+{
+ INT32 CurrentPos = *pLastCurPos;
+ SRC_TYPE *pIn, *pInEnd;
+ SRC_TYPE *pOv, *pOvEnd;
+ INT16 *psBtOut = (INT16 *)pDst;
+#if BTA_DM_SCO_DEBUG
+ APPL_TRACE_DEBUG1("Convert_8M_ToBT_Filtered, CurrentPos %d\n", CurrentPos);
+#endif
+ memcpy (pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 2), pSrc, BTA_DM_PCM_OVERLAP_SIZE * 2);
+
+ pOv = (SRC_TYPE *)(pOverlapArea + BTA_DM_PCM_OVERLAP_SIZE);
+ pOvEnd = (SRC_TYPE *)(pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 3));
+
+ pIn = (SRC_TYPE *)(pSrc + BTA_DM_PCM_OVERLAP_SIZE);
+ pInEnd = (SRC_TYPE *)(pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof (SRC_TYPE)) - \
+ BTA_DM_PCM_OVERLAP_SIZE);
+
+ if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_44100)
+ {
+ CONVERT_44100_TO_BLUETOOTH(pOv, pOvEnd);
+ CONVERT_44100_TO_BLUETOOTH(pIn, pInEnd);
+ }
+ else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_22050)
+ {
+ CONVERT_22050_TO_BLUETOOTH(pOv, pOvEnd);
+ CONVERT_22050_TO_BLUETOOTH(pIn, pInEnd);
+ }
+ else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_11025)
+ {
+ CONVERT_11025_TO_BLUETOOTH(pOv, pOvEnd);
+ CONVERT_11025_TO_BLUETOOTH(pIn, pInEnd);
+ }
+
+ memcpy (pOverlapArea, pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof (SRC_TYPE)) - \
+ (BTA_DM_PCM_OVERLAP_SIZE * 2), BTA_DM_PCM_OVERLAP_SIZE * 2);
+
+ *pLastCurPos = CurrentPos;
+
+ return (psBtOut - (INT16 *)pDst);
+}
+
+INT32 Convert_8M_ToBT_NoFilter (void *pSrc, void *pDst, UINT32 dwSrcSamples, UINT32 dwSrcSps)
+{
+ INT32 CurrentPos;
+ UINT8 *pbSrc = (UINT8 *)pSrc;
+ INT16 *psDst = (INT16 *)pDst;
+ INT16 sWorker;
+
+ // start at dwSpsSrc / 2, decrement by 8000
+ //
+ CurrentPos = (dwSrcSps >> 1);
+
+ while (dwSrcSamples--)
+ {
+ CurrentPos -= 8000;
+
+ if (CurrentPos >= 0)
+ pbSrc++;
+ else
+ {
+ sWorker = *pbSrc++;
+ sWorker -= 0x80;
+ sWorker <<= 8;
+
+ *psDst++ = sWorker;
+
+ CurrentPos += dwSrcSps;
+ }
+ }
+
+ return (psDst - (INT16 *)pDst);
+}
+
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+#undef SRC_CHANNELS
+#undef SRC_SAMPLE
+#undef SRC_TYPE
+
+#define SRC_TYPE INT16
+#define SRC_CHANNELS 1
+#define SRC_SAMPLE(x) pS[x]
+
+INT32 Convert_16M_ToBT_Filtered (UINT8 *pSrc, void *pDst, UINT32 dwSrcSamples,
+ UINT32 dwSrcSps, INT32 *pLastCurPos, UINT8 *pOverlapArea)
+{
+ INT32 CurrentPos = *pLastCurPos;
+ SRC_TYPE *pIn, *pInEnd;
+ SRC_TYPE *pOv, *pOvEnd;
+ INT16 *psBtOut = (INT16 *)pDst;
+
+ memcpy (pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 2), pSrc, BTA_DM_PCM_OVERLAP_SIZE * 2);
+
+ pOv = (SRC_TYPE *)(pOverlapArea + BTA_DM_PCM_OVERLAP_SIZE);
+ pOvEnd = (SRC_TYPE *)(pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 3));
+
+ pIn = (SRC_TYPE *)(pSrc + BTA_DM_PCM_OVERLAP_SIZE);
+ pInEnd = (SRC_TYPE *)(pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof (SRC_TYPE)) - BTA_DM_PCM_OVERLAP_SIZE);
+
+ if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_44100)
+ {
+ CONVERT_44100_TO_BLUETOOTH(pOv, pOvEnd);
+ CONVERT_44100_TO_BLUETOOTH(pIn, pInEnd);
+ }
+ else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_22050)
+ {
+ CONVERT_22050_TO_BLUETOOTH(pOv, pOvEnd);
+ CONVERT_22050_TO_BLUETOOTH(pIn, pInEnd);
+ }
+ else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_11025)
+ {
+ CONVERT_11025_TO_BLUETOOTH(pOv, pOvEnd);
+ CONVERT_11025_TO_BLUETOOTH(pIn, pInEnd);
+ }
+
+ memcpy (pOverlapArea, pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof (SRC_TYPE)) - \
+ (BTA_DM_PCM_OVERLAP_SIZE * 2), BTA_DM_PCM_OVERLAP_SIZE * 2);
+
+ *pLastCurPos = CurrentPos;
+
+ return (psBtOut - (INT16 *)pDst);
+}
+
+INT32 Convert_16M_ToBT_NoFilter (void *pSrc, void *pDst, UINT32 dwSrcSamples, UINT32 dwSrcSps)
+{
+ INT32 CurrentPos;
+ INT16 *psSrc = (INT16 *)pSrc;
+ INT16 *psDst = (INT16 *)pDst;
+
+ // start at dwSpsSrc / 2, decrement by 8000
+ //
+ CurrentPos = (dwSrcSps >> 1);
+
+ while (dwSrcSamples--)
+ {
+ CurrentPos -= 8000;
+
+ if (CurrentPos >= 0)
+ psSrc++;
+ else
+ {
+ *psDst++ = *psSrc++;
+
+ CurrentPos += dwSrcSps;
+ }
+ }
+
+ return (psDst - (INT16 *)pDst);
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+#undef SRC_CHANNELS
+#undef SRC_SAMPLE
+#undef SRC_TYPE
+
+#define SRC_TYPE UINT8
+#define SRC_CHANNELS 2
+#define SRC_SAMPLE(x) ((((pS[x * 2] - 0x80) << 8) + ((pS[(x * 2) + 1] - 0x80) << 8)) >> 1)
+
+INT32 Convert_8S_ToBT_Filtered (UINT8 *pSrc, void *pDst, UINT32 dwSrcSamples,
+ UINT32 dwSrcSps, INT32 *pLastCurPos, UINT8 *pOverlapArea)
+{
+ INT32 CurrentPos = *pLastCurPos;
+ SRC_TYPE *pIn, *pInEnd;
+ SRC_TYPE *pOv, *pOvEnd;
+ INT16 *psBtOut = (INT16 *)pDst;
+
+#if BTA_DM_SCO_DEBUG
+ APPL_TRACE_DEBUG5("Convert_8S_ToBT_Filtered CurrentPos %d, SRC_TYPE %d, SRC_CHANNELS %d, \
+ dwSrcSamples %d, dwSrcSps %d", CurrentPos, sizeof (SRC_TYPE), SRC_CHANNELS, \
+ dwSrcSamples, dwSrcSps);
+#endif
+ memcpy (pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 2), pSrc, BTA_DM_PCM_OVERLAP_SIZE * 2);
+
+ pOv = (SRC_TYPE *)(pOverlapArea + BTA_DM_PCM_OVERLAP_SIZE);
+ pOvEnd = (SRC_TYPE *)(pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 3));
+
+ pIn = (SRC_TYPE *)(pSrc + BTA_DM_PCM_OVERLAP_SIZE);
+ pInEnd = (SRC_TYPE *)(pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof (SRC_TYPE)) - BTA_DM_PCM_OVERLAP_SIZE);
+
+ if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_44100)
+ {
+ CONVERT_44100_TO_BLUETOOTH(pOv, pOvEnd);
+ CONVERT_44100_TO_BLUETOOTH(pIn, pInEnd);
+ }
+ else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_22050)
+ {
+ CONVERT_22050_TO_BLUETOOTH(pOv, pOvEnd);
+ CONVERT_22050_TO_BLUETOOTH(pIn, pInEnd);
+ }
+ else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_11025)
+ {
+ CONVERT_11025_TO_BLUETOOTH(pOv, pOvEnd);
+ CONVERT_11025_TO_BLUETOOTH(pIn, pInEnd);
+ }
+
+ memcpy (pOverlapArea, pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof (SRC_TYPE)) - \
+ (BTA_DM_PCM_OVERLAP_SIZE * 2), BTA_DM_PCM_OVERLAP_SIZE * 2);
+
+ *pLastCurPos = CurrentPos;
+
+ return (psBtOut - (INT16 *)pDst);
+}
+
+INT32 Convert_8S_ToBT_NoFilter (void *pSrc, void *pDst, UINT32 dwSrcSamples, UINT32 dwSrcSps)
+{
+ INT32 CurrentPos;
+ UINT8 *pbSrc = (UINT8 *)pSrc;
+ INT16 *psDst = (INT16 *)pDst;
+ INT16 sWorker, sWorker2;
+
+ // start at dwSpsSrc / 2, decrement by 8000
+ //
+ CurrentPos = (dwSrcSps >> 1);
+
+ while (dwSrcSamples--)
+ {
+ CurrentPos -= 8000;
+
+ if (CurrentPos >= 0)
+ pbSrc += 2;
+ else
+ {
+ sWorker = *(unsigned char *)pbSrc;
+ sWorker -= 0x80;
+ sWorker <<= 8;
+ pbSrc++;
+
+ sWorker2 = *(unsigned char *)pbSrc;
+ sWorker2 -= 0x80;
+ sWorker2 <<= 8;
+ pbSrc++;
+
+ sWorker += sWorker2;
+ sWorker >>= 1;
+
+ *psDst++ = sWorker;
+
+ CurrentPos += dwSrcSps;
+ }
+ }
+
+ return (psDst - (INT16 *)pDst);
+}
+
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+#undef SRC_CHANNELS
+#undef SRC_SAMPLE
+#undef SRC_TYPE
+
+#define SRC_TYPE INT16
+#define SRC_CHANNELS 2
+#define SRC_SAMPLE(x) ((pS[x * 2] + pS[(x * 2) + 1]) >> 1)
+
+INT32 Convert_16S_ToBT_Filtered (UINT8 *pSrc, void *pDst, UINT32 dwSrcSamples,
+ UINT32 dwSrcSps, INT32 *pLastCurPos, UINT8 *pOverlapArea)
+{
+ INT32 CurrentPos = *pLastCurPos;
+ SRC_TYPE *pIn, *pInEnd;
+ SRC_TYPE *pOv, *pOvEnd;
+ INT16 *psBtOut = (INT16 *)pDst;
+
+ memcpy (pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 2), pSrc, BTA_DM_PCM_OVERLAP_SIZE * 2);
+
+ pOv = (SRC_TYPE *)(pOverlapArea + BTA_DM_PCM_OVERLAP_SIZE);
+ pOvEnd = (SRC_TYPE *)(pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 3));
+
+ pIn = (SRC_TYPE *)(pSrc + BTA_DM_PCM_OVERLAP_SIZE);
+ pInEnd = (SRC_TYPE *)(pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof (SRC_TYPE)) - BTA_DM_PCM_OVERLAP_SIZE);
+
+ if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_44100)
+ {
+ CONVERT_44100_TO_BLUETOOTH(pOv, pOvEnd);
+ CONVERT_44100_TO_BLUETOOTH(pIn, pInEnd);
+ }
+ else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_22050)
+ {
+ CONVERT_22050_TO_BLUETOOTH(pOv, pOvEnd);
+ CONVERT_22050_TO_BLUETOOTH(pIn, pInEnd);
+ }
+ else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_11025)
+ {
+ CONVERT_11025_TO_BLUETOOTH(pOv, pOvEnd);
+ CONVERT_11025_TO_BLUETOOTH(pIn, pInEnd);
+ }
+
+ memcpy (pOverlapArea, pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof (SRC_TYPE)) - \
+ (BTA_DM_PCM_OVERLAP_SIZE * 2), BTA_DM_PCM_OVERLAP_SIZE * 2);
+
+ *pLastCurPos = CurrentPos;
+
+ return (psBtOut - (INT16 *)pDst);
+}
+
+INT32 Convert_16S_ToBT_NoFilter (void *pSrc, void *pDst, UINT32 dwSrcSamples, UINT32 dwSrcSps)
+{
+ INT32 CurrentPos;
+ INT16 *psSrc = (INT16 *)pSrc;
+ INT16 *psDst = (INT16 *)pDst;
+ INT16 sWorker;
+
+ // start at dwSpsSrc / 2, decrement by 8000
+ //
+ CurrentPos = (dwSrcSps >> 1);
+
+ while (dwSrcSamples--)
+ {
+ CurrentPos -= 8000;
+
+ if (CurrentPos >= 0)
+ psSrc += 2;
+ else
+ {
+ /* CR 82894, to avoid overflow, divide before add */
+ sWorker = ((*psSrc) >> 1 );
+ psSrc++;
+ sWorker += ((*psSrc) >> 1 );
+ psSrc++;
+
+ *psDst++ = sWorker;
+
+ CurrentPos += dwSrcSps;
+ }
+ }
+
+ return (psDst - (INT16 *)pDst);
+}
+
+/*******************************************************************************
+**
+** Function BTA_DmPcmInitSamples
+**
+** Description initialize the down sample converter.
+**
+** src_sps: original samples per second (source audio data)
+** (ex. 44100, 48000)
+** bits: number of bits per pcm sample (16)
+** n_channels: number of channels (i.e. mono(1), stereo(2)...)
+**
+** Returns none
+**
+*******************************************************************************/
+void BTA_DmPcmInitSamples (UINT32 src_sps, UINT32 bits, UINT32 n_channels)
+{
+ tBTA_DM_PCM_RESAMPLE_CB *p_cb = &bta_dm_pcm_cb;
+
+ p_cb->cur_pos = src_sps / 2;
+ p_cb->src_sps = src_sps;
+ p_cb->bits = bits;
+ p_cb->n_channels = n_channels;
+ p_cb->sample_size = 2;
+ p_cb->divisor = 2;
+
+ memset(p_cb->overlap_area, 0, sizeof(p_cb->overlap_area) );
+
+ if ((src_sps == BTA_DM_PCM_SMPL_RATE_44100) ||
+ (src_sps == BTA_DM_PCM_SMPL_RATE_22050) ||
+ (src_sps == BTA_DM_PCM_SMPL_RATE_11025))
+ p_cb->can_be_filtered = 1;
+ else
+ p_cb->can_be_filtered = 0;
+
+#if BTA_DM_SCO_DEBUG
+ APPL_TRACE_DEBUG2("bta_dm_pcm_init_samples: n_channels = %d bits = %d", n_channels, bits);
+#endif
+ if(n_channels == 1)
+ {
+ /* mono */
+ if(bits == 8)
+ {
+ p_cb->filter = (PCONVERT_TO_BT_FILTERED) Convert_8M_ToBT_Filtered;
+ p_cb->nofilter = (PCONVERT_TO_BT_NOFILTER) Convert_8M_ToBT_NoFilter;
+ p_cb->divisor = 1;
+ }
+ else
+ {
+ p_cb->filter = (PCONVERT_TO_BT_FILTERED) Convert_16M_ToBT_Filtered;
+ p_cb->nofilter = (PCONVERT_TO_BT_NOFILTER) Convert_16M_ToBT_NoFilter;
+ }
+ }
+ else
+ {
+ /* stereo */
+ if(bits == 8)
+ {
+ p_cb->filter = (PCONVERT_TO_BT_FILTERED) Convert_8S_ToBT_Filtered;
+ p_cb->nofilter = (PCONVERT_TO_BT_NOFILTER) Convert_8S_ToBT_NoFilter;
+ }
+ else
+ {
+ p_cb->filter = (PCONVERT_TO_BT_FILTERED) Convert_16S_ToBT_Filtered;
+ p_cb->nofilter = (PCONVERT_TO_BT_NOFILTER) Convert_16S_ToBT_NoFilter;
+ p_cb->divisor = 4;
+ }
+ }
+
+#if BTA_DM_SCO_DEBUG
+ APPL_TRACE_DEBUG2("bta_pcm_init_dwn_sample: cur_pos %d, src_sps %d", \
+ p_cb->cur_pos, p_cb->src_sps);
+ APPL_TRACE_DEBUG3("bta_pcm_init_dwn_sample: bits %d, n_channels %d, sample_size %d, ", \
+ p_cb->bits, p_cb->n_channels, p_cb->sample_size);
+ APPL_TRACE_DEBUG3("bta_pcm_init_dwn_sample: can_be_filtered %d, n_channels: %d, \
+ divisor %d", p_cb->can_be_filtered, p_cb->n_channels, p_cb->divisor);
+#endif
+
+}
+
+/**************************************************************************************
+** Function BTA_DmPcmResample
+**
+** Description Down sampling utility to convert higher sampling rate into 8K/16bits
+** PCM samples.
+**
+** Parameters p_src: pointer to the buffer where the original sampling PCM
+** are stored.
+** in_bytes: Length of the input PCM sample buffer in byte.
+** p_dst: pointer to the buffer which is to be used to store
+** the converted PCM samples.
+**
+**
+** Returns INT32: number of samples converted.
+**
+**************************************************************************************/
+INT32 BTA_DmPcmResample (void *p_src, UINT32 in_bytes, void *p_dst)
+{
+ UINT32 out_sample;
+
+#if BTA_DM_SCO_DEBUG
+ APPL_TRACE_DEBUG1("bta_pcm_resample : insamples %d", (in_bytes / bta_dm_pcm_cb.divisor));
+#endif
+ if(bta_dm_pcm_cb.can_be_filtered)
+ {
+ out_sample = (*bta_dm_pcm_cb.filter) (p_src, p_dst, (in_bytes / bta_dm_pcm_cb.divisor),
+ bta_dm_pcm_cb.src_sps, (INT32 *) &bta_dm_pcm_cb.cur_pos, bta_dm_pcm_cb.overlap_area);
+ }
+ else
+ {
+ out_sample = (*bta_dm_pcm_cb.nofilter) (p_src, p_dst,
+ (in_bytes / bta_dm_pcm_cb.divisor), bta_dm_pcm_cb.src_sps);
+ }
+
+#if BTA_DM_SCO_DEBUG
+ APPL_TRACE_DEBUG1("bta_pcm_resample : outsamples %d", out_sample);
+#endif
+
+ return (out_sample * bta_dm_pcm_cb.sample_size);
+}
+#endif
diff --git a/bta/fs/bta_fs_cfg.c b/bta/fs/bta_fs_cfg.c
new file mode 100644
index 0000000..fc18863
--- /dev/null
+++ b/bta/fs/bta_fs_cfg.c
@@ -0,0 +1,38 @@
+/*****************************************************************************
+**
+** Name: bta_fs_cfg.c
+**
+** Description: This file contains compile-time configurable constants
+** for the BTA File System.
+**
+** Copyright (c) 2003-2008, Broadcom Corp., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+#include "bta_fs_api.h"
+
+/* Character used as path separator */
+#ifndef BTA_FS_PATH_SEPARATOR
+#define BTA_FS_PATH_SEPARATOR ((char) 0x2f) /* 0x2f ('/'), or 0x5c ('\') */
+#endif
+
+/* Maximum path length supported by MMI */
+#ifndef BTA_FS_PATH_LEN
+#define BTA_FS_PATH_LEN 294
+#endif
+
+#ifndef BTA_FS_FILE_LEN
+#define BTA_FS_FILE_LEN 256
+#endif
+
+const tBTA_FS_CFG bta_fs_cfg =
+{
+ BTA_FS_FILE_LEN,
+ BTA_FS_PATH_LEN,
+ BTA_FS_PATH_SEPARATOR
+};
+
+tBTA_FS_CFG *p_bta_fs_cfg = (tBTA_FS_CFG *)&bta_fs_cfg;
+
diff --git a/bta/fs/bta_fs_ci.c b/bta/fs/bta_fs_ci.c
new file mode 100644
index 0000000..d6e52b4
--- /dev/null
+++ b/bta/fs/bta_fs_ci.c
@@ -0,0 +1,268 @@
+/*****************************************************************************
+**
+** Name: bta_fs_ci.c
+**
+** Description: This is the implementation file for the file system
+** call-in functions.
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include <string.h>
+
+#include "bta_api.h"
+#include "bta_sys.h"
+#include "bta_fs_ci.h"
+#include "gki.h"
+#include "bd.h"
+
+/*******************************************************************************
+**
+** Function bta_fs_ci_write
+**
+** Description This function sends an event to IO indicating the phone
+** has written the number of bytes specified in the call-out
+** function, bta_fs_co_write(), and is ready for more data.
+** This function is used to control the TX data flow.
+** Note: The data buffer is released by the stack after
+** calling this function.
+**
+** Parameters fd - file descriptor passed to the stack in the
+** bta_fs_ci_open call-in function.
+** status - BTA_FS_CO_OK or BTA_FS_CO_FAIL
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fs_ci_write(int fd, tBTA_FS_CO_STATUS status, UINT16 evt)
+{
+ tBTA_FS_CI_WRITE_EVT *p_evt;
+
+ if ((p_evt = (tBTA_FS_CI_WRITE_EVT *) GKI_getbuf(sizeof(tBTA_FS_CI_WRITE_EVT))) != NULL)
+ {
+ p_evt->hdr.event = evt;
+ p_evt->fd = fd;
+ p_evt->status = status;
+
+ bta_sys_sendmsg(p_evt);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_fs_ci_read
+**
+** Description This function sends an event to BTA indicating the phone has
+** read in the requested amount of data specified in the
+** bta_fs_co_read() call-out function. It should only be called
+** when the requested number of bytes has been read in, or after
+** the end of the file has been detected.
+**
+** Parameters fd - file descriptor passed to the stack in the
+** bta_fs_ci_open call-in function.
+** num_bytes_read - number of bytes read into the buffer
+** specified in the read callout-function.
+** status - BTA_FS_CO_OK if full buffer of data,
+** BTA_FS_CO_EOF if the end of file has been reached,
+** BTA_FS_CO_FAIL if an error has occurred.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fs_ci_read(int fd, UINT16 num_bytes_read, tBTA_FS_CO_STATUS status, UINT16 evt)
+{
+ tBTA_FS_CI_READ_EVT *p_evt;
+
+ if ((p_evt = (tBTA_FS_CI_READ_EVT *) GKI_getbuf(sizeof(tBTA_FS_CI_READ_EVT))) != NULL)
+ {
+ p_evt->hdr.event = evt;
+ p_evt->fd = fd;
+ p_evt->status = status;
+ p_evt->num_read = num_bytes_read;
+
+ bta_sys_sendmsg(p_evt);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_fs_ci_open
+**
+** Description This function sends an event to BTA indicating the phone has
+** finished opening a file for reading or writing.
+**
+** Parameters fd - file descriptor passed to the stack in the
+** bta_fs_ci_open call-in function.
+** status - BTA_FS_CO_OK if file was opened in mode specified
+** in the call-out function.
+** BTA_FS_CO_EACCES if the file exists, but contains
+** the wrong access permissions.
+** BTA_FS_CO_FAIL if any other error has occurred.
+** file_size - The total size of the file
+** evt - Used Internally by BTA -> MUST be same value passed
+** in call-out function.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fs_ci_open(int fd, tBTA_FS_CO_STATUS status, UINT32 file_size, UINT16 evt)
+{
+ tBTA_FS_CI_OPEN_EVT *p_evt;
+
+ if ((p_evt = (tBTA_FS_CI_OPEN_EVT *) GKI_getbuf(sizeof(tBTA_FS_CI_OPEN_EVT))) != NULL)
+ {
+ p_evt->hdr.event = evt;
+ p_evt->fd = fd;
+ p_evt->status = status;
+ p_evt->file_size = file_size;
+ p_evt->p_file = NULL;
+
+ bta_sys_sendmsg(p_evt);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_fs_ci_direntry
+**
+** Description This function is called in response to the
+** bta_fs_co_getdirentry call-out function.
+**
+** Parameters status - BTA_FS_CO_OK if p_entry points to a valid entry.
+** BTA_FS_CO_EODIR if no more entries (p_entry is ignored).
+** BTA_FS_CO_FAIL if any errors have occurred.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fs_ci_direntry(tBTA_FS_CO_STATUS status, UINT16 evt)
+{
+ tBTA_FS_CI_GETDIR_EVT *p_evt;
+
+ if ((p_evt = (tBTA_FS_CI_GETDIR_EVT *)GKI_getbuf(sizeof(tBTA_FS_CI_GETDIR_EVT))) != NULL)
+ {
+ p_evt->hdr.event = evt;
+ p_evt->status = status;
+ bta_sys_sendmsg(p_evt);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_fs_ci_resume
+**
+** Description This function is called in response to the
+** bta_fs_co_resume call-out function.
+**
+** Parameters p_sess_info - the stored session ID and related information.
+** timeout - the timeout for this suspended session.
+** ssn - the stored session sequence number.
+** info - the stored BTA specific information (like last active operation).
+** status - BTA_FS_CO_OK if p_entry points to a valid entry.
+** BTA_FS_CO_FAIL if any errors have occurred.
+** evt - Used Internally by BTA -> MUST be same value passed
+** in call-out function.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fs_ci_resume (BD_ADDR_PTR p_addr, UINT8 *p_sess_info,
+ UINT32 timeout, UINT32 offset, UINT8 ssn, UINT8 info,
+ tBTA_FS_CO_STATUS status, UINT16 evt)
+{
+ tBTA_FS_CI_RESUME_EVT *p_evt;
+ UINT16 size = sizeof(tBTA_FS_CI_RESUME_EVT) + sizeof(BD_ADDR);
+
+ if ((p_evt = (tBTA_FS_CI_RESUME_EVT *)GKI_getbuf(size)) != NULL)
+ {
+ p_evt->p_addr = NULL;
+ if (p_addr != NULL)
+ {
+ p_evt->p_addr = (BD_ADDR_PTR)(p_evt + 1);
+ bdcpy(p_evt->p_addr, p_addr);
+ }
+ p_evt->hdr.event = evt;
+ p_evt->p_sess_info = p_sess_info;
+ p_evt->timeout = timeout;
+ p_evt->offset = offset;
+ p_evt->ssn = ssn;
+ p_evt->info = info;
+ p_evt->status = status;
+ bta_sys_sendmsg(p_evt);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_fs_ci_action
+**
+** Description This function is called in response to one of the action
+** call-out functions: bta_fs_co_copy, bta_fs_co_rename or
+** bta_fs_co_set_perms.
+**
+** Parameters status - BTA_FS_CO_OK if the action is succession.
+** BTA_FS_CO_FAIL if any errors have occurred.
+** evt - Used Internally by BTA -> MUST be same value passed
+** in call-out function.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fs_ci_action(tBTA_FS_CO_STATUS status, UINT16 evt)
+{
+ tBTA_FS_CI_ACTION_EVT *p_evt;
+
+ if ((p_evt = (tBTA_FS_CI_ACTION_EVT *) GKI_getbuf(sizeof(tBTA_FS_CI_ACTION_EVT))) != NULL)
+ {
+ p_evt->hdr.event = evt;
+ p_evt->status = status;
+
+ bta_sys_sendmsg(p_evt);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_fs_ci_resume_op
+**
+** Description This function sends an event to BTA indicating the phone has
+** finished opening a file for reading or writing on resume.
+**
+** Parameters fd - file descriptor passed to the stack in the
+** bta_fs_ci_open call-in function.
+** status - BTA_FS_CO_OK if file was opened in mode specified
+** in the call-out function.
+** BTA_FS_CO_EACCES if the file exists, but contains
+** the wrong access permissions.
+** BTA_FS_CO_FAIL if any other error has occurred.
+** p_file - The file name associated with fd
+** file_size - The total size of the file
+** evt - Used Internally by BTA -> MUST be same value passed
+** in call-out function.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fs_ci_resume_op(int fd, tBTA_FS_CO_STATUS status, const char *p_file,
+ UINT32 file_size, UINT16 evt)
+{
+ tBTA_FS_CI_OPEN_EVT *p_evt;
+ UINT16 file_len = strlen(p_file) + 1;
+ UINT16 size = sizeof(tBTA_FS_CI_OPEN_EVT) + file_len;
+ char *p;
+
+ if ((p_evt = (tBTA_FS_CI_OPEN_EVT *) GKI_getbuf(size)) != NULL)
+ {
+ p_evt->hdr.event = evt;
+ p_evt->fd = fd;
+ p_evt->status = status;
+ p_evt->file_size = file_size;
+ p = (char *)(p_evt + 1);
+ BCM_STRNCPY_S (p, file_len, p_file, file_len-1);
+ p[file_len] = '\0';
+ p_evt->p_file = (const char *)p;
+
+ bta_sys_sendmsg(p_evt);
+ }
+}
diff --git a/bta/ft/bta_ft_cfg.c b/bta/ft/bta_ft_cfg.c
new file mode 100644
index 0000000..89171e0
--- /dev/null
+++ b/bta/ft/bta_ft_cfg.c
@@ -0,0 +1,86 @@
+/*****************************************************************************
+**
+** Name: bta_ft_cfg.c
+**
+** Description: This file contains compile-time configurable constants
+** for the BTA File Transfer Client and Server.
+**
+** Copyright (c) 2003-2010, Broadcom Inc., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+#include "bta_ftc_int.h"
+
+/* Realm Character Set */
+#ifndef BTA_FTS_REALM_CHARSET
+#define BTA_FTS_REALM_CHARSET 0 /* ASCII */
+#endif
+
+/* Specifies whether or not client's user id is required during obex authentication */
+#ifndef BTA_FTS_USERID_REQ
+#define BTA_FTS_USERID_REQ FALSE
+#endif
+
+#ifndef BTA_FTC_AUTO_FILE_LIST
+#define BTA_FTC_AUTO_FILE_LIST TRUE
+#endif
+
+#ifndef BTA_FTC_ABORT_TIMEOUT
+#define BTA_FTC_ABORT_TIMEOUT 7000 /* 7 Secs for the low baud rates and SRM mode */
+#endif
+
+#ifndef BTA_FTC_STOP_TIMEOUT
+#define BTA_FTC_STOP_TIMEOUT 2000
+#endif
+
+#ifndef BTA_FTC_SUSPEND_TIMEOUT
+#define BTA_FTC_SUSPEND_TIMEOUT 10000
+#endif
+
+#ifndef BTA_FTC_PCE_SUPPORTED_FEAT /* mask: 1/download, 2/browsing */
+#define BTA_FTC_PCE_SUPPORTED_FEAT 0 /* 3/both, 0/PBAP PCE not supported */
+#endif
+
+#ifndef BTA_FTC_PCE_SERVICE_NAME
+#define BTA_FTC_PCE_SERVICE_NAME "PBAP PCE"
+#endif
+
+#ifndef BTA_FTC_2X_SUPPORTED
+#define BTA_FTC_2X_SUPPORTED TRUE
+#endif
+
+const tBTA_FT_CFG bta_ft_cfg =
+{
+#if (defined BIP_INCLUDED && BIP_INCLUDED == TRUE && defined BTA_BI_INCLUDED && BTA_BI_INCLUDED == TRUE)
+ bta_ftc_bi_action, /* Client only */
+#else
+ NULL, /* Client only */
+#endif
+
+ BTA_FTS_REALM_CHARSET, /* Server only */
+ BTA_FTS_USERID_REQ, /* Server only */
+ BTA_FTC_AUTO_FILE_LIST, /* Client only */
+ BTA_FTC_PCE_SUPPORTED_FEAT, /* Client only */
+ BTA_FTC_PCE_SERVICE_NAME, /* Client only */
+ BTA_FTC_ABORT_TIMEOUT, /* Client only */
+ BTA_FTC_STOP_TIMEOUT , /* Client only */
+ BTA_FTC_SUSPEND_TIMEOUT /* Client only - used for 2X only */
+#if BTA_FTC_2X_SUPPORTED == TRUE
+// btla-specific ++
+ , 0 // [no reliable sess] /* non-0 to allow reliable session (Server Only) */
+ , 0 // [no reliable sess] /* the maximum number of suspended session (Server Only) */
+// btla-specific --
+ , TRUE /* TRUE to use Obex Over L2CAP (Server Only) */
+ , TRUE /* TRUE to engage Single Response Mode (Server Only) */
+#else
+ , 0 /* non-0 to allow reliable session (Server Only) */
+ , 0 /* the maximum number of suspended session (Server Only) */
+ , FALSE /* TRUE to use Obex Over L2CAP (Server Only) */
+ , FALSE /* TRUE to engage Single Response Mode (Server Only) */
+#endif
+};
+
+tBTA_FT_CFG *p_bta_ft_cfg = (tBTA_FT_CFG *)&bta_ft_cfg;
+
diff --git a/bta/ft/bta_ftc_act.c b/bta/ft/bta_ftc_act.c
new file mode 100644
index 0000000..bdec2d3
--- /dev/null
+++ b/bta/ft/bta_ftc_act.c
@@ -0,0 +1,2062 @@
+/*****************************************************************************
+**
+** Name: bta_ftc_act.c
+**
+** Description: This file contains the file transfer action
+** functions for the state machine.
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+
+#if defined(BTA_FT_INCLUDED) && (BTA_FT_INCLUDED == TRUE)
+
+#include <string.h>
+#include "gki.h"
+#include "bta_sys.h"
+#include "bd.h"
+#include "port_api.h"
+#include "obx_api.h"
+#include "goep_util.h"
+#include "sdp_api.h"
+#include "bta_fs_api.h"
+#include "bta_ft_api.h"
+#include "bta_ftc_int.h"
+#include "bta_fs_co.h"
+#include "bta_fs_ci.h"
+#include "btm_api.h"
+#include "rfcdefs.h"
+#include "utl.h"
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+/* sdp discovery database size */
+#define BTA_FTC_DISC_SIZE 400
+
+
+/*****************************************************************************
+** Local Function prototypes
+*****************************************************************************/
+#if BTA_FTC_DEBUG == TRUE
+static char *ftc_obx_evt_code(tOBX_EVENT evt_code);
+#endif
+
+static void ftc_reset_cb (tBTA_FTC_CB *p_cb);
+static void bta_ftc_sdp_cback(UINT16 status);
+
+/*****************************************************************************
+** Action Functions
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function bta_ftc_init_open
+**
+** Description Initiate a connection with a peer device's service.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ftc_init_open(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data)
+{
+ p_cb->obx_oper = FTC_OP_NONE;
+ p_cb->sec_mask = p_data->api_open.sec_mask;
+ p_cb->services = p_data->api_open.services;
+ p_cb->srm = p_data->api_open.srm;
+ p_cb->nonce = p_data->api_open.nonce;
+ bdcpy(p_cb->bd_addr, p_data->api_open.bd_addr);
+}
+
+/*******************************************************************************
+**
+** Function bta_ftc_abort
+**
+** Description Abort an active Get or Put operation
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ftc_abort(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data)
+{
+ /* Abort an active request */
+ if (p_cb->obx_oper != FTC_OP_NONE)
+ {
+ p_cb->aborting = FTC_ABORT_REQ_NOT_SENT;
+
+ /* Issue the abort request only if no request pending.
+ * some devices do not like out of sequence aborts even though
+ * the spec allows it */
+ if ( !p_cb->req_pending || p_cb->first_req_pkt ) /* allow request for the first packet */
+ {
+
+ p_cb->aborting = FTC_ABORT_REQ_SENT; /* protection agains sending AbortReq twice in
+ certain conditions */
+ OBX_AbortReq(p_cb->obx_handle, (BT_HDR *)NULL);
+ /* Start abort response timer */
+ p_cb->timer_oper = FTC_TIMER_OP_ABORT;
+ bta_sys_start_timer(&p_cb->rsp_timer, BTA_FTC_RSP_TOUT_EVT,
+ p_bta_ft_cfg->abort_tout);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ftc_api_action
+**
+** Description Send an Action command to the connected server
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ftc_api_action(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data)
+{
+ tBTA_FTC_OBX_PKT *p_obx = &p_cb->obx;
+ tBTA_FTC_STATUS status = BTA_FTC_FAIL;
+ tBTA_FTC_EVT event = BTA_FTC_COPY_EVT + p_data->api_action.action;
+
+ if (p_cb->obx_oper == FTC_OP_NONE)
+ {
+ /* TODO: we need to check the connected profile here */
+ p_obx->p_pkt = OBX_HdrInit(p_cb->obx_handle, OBX_CMD_POOL_SIZE);
+ OBX_AddUtf8NameHdr(p_obx->p_pkt, (UINT8 *)p_data->api_action.p_src);
+ if (p_data->api_action.action == BTA_FT_ACT_PERMISSION)
+ {
+ OBX_AddPermissionHdr(p_obx->p_pkt, p_data->api_action.permission[0],
+ p_data->api_action.permission[1], p_data->api_action.permission[2]);
+ }
+ else
+ {
+ OBX_AddUtf8DestNameHdr(p_obx->p_pkt, (UINT8 *)p_data->api_action.p_dest);
+ }
+
+ if (OBX_ActionReq(p_cb->obx_handle, p_data->api_action.action, p_obx->p_pkt) == OBX_SUCCESS)
+ {
+ status = BTA_FTC_OK;
+ p_cb->req_pending = TRUE;
+ p_cb->obx_oper = FTC_OP_COPY + p_data->api_action.action;
+ p_obx->p_pkt = NULL; /* OBX will free the packet */
+ }
+ }
+
+ if (status != BTA_FTC_OK) /* Send an error response to the application */
+ {
+ utl_freebuf((void**)&p_obx->p_pkt);
+ p_cb->p_cback(event, (tBTA_FTC *)&status);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ftc_obx_action_rsp
+**
+** Description Process the response to an action command
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ftc_obx_action_rsp(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data)
+{
+ tBTA_FTC_OBX_EVT *p_evt = &p_data->obx_evt;
+ tBTA_FTC_STATUS status = BTA_FTC_FAIL;
+ tBTA_FTC_EVT event = BTA_FTC_COPY_EVT + p_cb->obx_oper - FTC_OP_COPY;
+
+ p_cb->req_pending = FALSE;
+
+ if (p_evt->rsp_code == OBX_RSP_OK)
+ status = BTA_FTC_OK;
+
+ APPL_TRACE_DEBUG2("bta_ftc_obx_action_rsp rsp_code:0x%x, status:%d", p_evt->rsp_code, status);
+ p_cb->obx_oper = FTC_OP_NONE;
+
+ utl_freebuf((void**)&p_evt->p_pkt); /* Done with Obex packet */
+ p_cb->p_cback(event, (tBTA_FTC *)&status);
+
+ /* If successful, initiate a directory listing */
+ if (event != BTA_FTC_PERMISSION_EVT &&
+ p_evt->rsp_code == OBX_RSP_OK && p_bta_ft_cfg->auto_file_list &&
+ (p_cb->sdp_service == UUID_SERVCLASS_OBEX_FILE_TRANSFER) )
+ {
+ bta_ftc_get_listing(p_cb, ".", NULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ftc_obx_get_srm_rsp
+**
+** Description Process the response to an get command after suspend is sent
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ftc_obx_get_srm_rsp(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data)
+{
+ tBTA_FTC_ACTION p_act;
+ /* TODO remove
+ if (FTC_SUSPEND_REQ_NOT_SENT == p_cb->aborting)
+ {
+ p_cb->aborting = 0;
+ OBX_SessionReq (p_cb->obx_handle, OBX_SESS_OP_SUSPEND, 0);
+ p_cb->timer_oper = FTC_TIMER_OP_SUSPEND;
+ bta_sys_start_timer(&p_cb->rsp_timer, BTA_FTC_RSP_TOUT_EVT, p_bta_ft_cfg->suspend_tout );
+ }
+ */
+
+ if (p_cb->timer_oper == FTC_TIMER_OP_SUSPEND)
+ {
+ p_act = bta_ftc_obx_get_rsp;
+ }
+ else
+ p_act = bta_ftc_ignore_obx;
+ (p_act)(p_cb, p_data);
+}
+
+/*******************************************************************************
+**
+** Function bta_ftc_ci_write_srm
+**
+** Description Continue with the current write operation after suspend is sent
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ftc_ci_write_srm(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data)
+{
+ if (p_cb->timer_oper == FTC_TIMER_OP_SUSPEND)
+ {
+ bta_ftc_ci_write(p_cb, p_data);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function bta_ftc_init_putfile
+**
+** Description Push a file to the OPP or FTP server.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ftc_init_putfile(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data)
+{
+ tBTA_FS_CO_STATUS status;
+ tBTA_FTC data;
+ BOOLEAN is_dir;
+ UINT8 rsp_code = OBX_RSP_FAILED;
+
+ data.status = BTA_FTC_FAIL;
+ if (p_cb->obx_oper == FTC_OP_NONE)
+ {
+ if (p_cb->sdp_service != UUID_SERVCLASS_PBAP_PSE)
+ {
+ p_cb->obx_oper = FTC_OP_PUT_FILE;
+
+ status = bta_fs_co_access(p_data->api_put.p_name, BTA_FS_ACC_READ,
+ &is_dir, p_cb->app_id);
+ /* Verify that the file exists, and get (optional) file length */
+ if (is_dir || status != BTA_FS_CO_OK)
+ {
+ /* Local file is not accessible or does not exist */
+ if (is_dir || status == BTA_FS_CO_EACCES)
+ rsp_code = OBX_RSP_UNAUTHORIZED;
+ else
+ rsp_code = OBX_RSP_NOT_FOUND;
+ }
+ else
+ {
+ if ((p_cb->p_name = (char *)GKI_getbuf((UINT16)(p_bta_fs_cfg->max_path_len + 1))) != NULL)
+ {
+ BCM_STRNCPY_S(p_cb->p_name, p_bta_fs_cfg->max_path_len+1, p_data->api_put.p_name, p_bta_fs_cfg->max_path_len);
+ p_cb->cout_active = TRUE;
+ bta_fs_co_open(p_cb->p_name, BTA_FS_O_RDONLY, 0, BTA_FTC_CI_OPEN_EVT,
+ p_cb->app_id);
+ rsp_code = OBX_RSP_OK;
+ }
+ }
+ if (rsp_code != OBX_RSP_OK)
+ {
+ p_data->obx_evt.rsp_code = rsp_code;
+ bta_ftc_sm_execute(p_cb, BTA_FTC_OBX_CMPL_EVT, p_data);
+ }
+ return;
+ }
+ else
+ {
+ /* PBAP does not allow PUT */
+ data.status = BTA_FTC_NO_PERMISSION;
+ }
+ }
+
+ p_cb->p_cback(BTA_FTC_PUTFILE_EVT, &data);
+}
+
+/*******************************************************************************
+**
+** Function bta_ftc_init_getfile
+**
+** Description Pull a file off the server.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ftc_init_getfile(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data)
+{
+ tBTA_FTC_API_GET *p_get = &p_data->api_get;
+ tBTA_FTC_GET_PARAM *p_param = p_get->p_param;
+ tBTA_FTC_OBX_PKT *p_obx = &p_cb->obx;
+ tBTA_FTC_STATUS status = BTA_FTC_FAIL;
+ tBTA_FTC data;
+ UINT16 buflen;
+ UINT16 rem_name_len;
+ BOOLEAN is_ok;
+ UINT8 *p = (UINT8 *)BTA_FTC_PULL_VCARD_ENTRY_TYPE;
+ UINT8 *p_start;
+ UINT16 len = 0;
+
+ /* Available for FTP only */
+ if (p_cb->obx_oper == FTC_OP_NONE &&
+ (p_cb->sdp_service == UUID_SERVCLASS_OBEX_FILE_TRANSFER ||
+ p_cb->sdp_service == UUID_SERVCLASS_PBAP_PSE) )
+ {
+ p_cb->first_req_pkt = TRUE;
+ p_obx->offset = 0;
+ if ((p_obx->p_pkt = OBX_HdrInit(p_cb->obx_handle, OBX_CMD_POOL_SIZE/*p_cb->peer_mtu*/)) != NULL)
+ {
+ /* Add the Name Header to the request */
+ is_ok = OBX_AddUtf8NameHdr(p_obx->p_pkt, (UINT8 *)p_get->p_rem_name);
+
+ if (p_cb->sdp_service == UUID_SERVCLASS_PBAP_PSE && is_ok)
+ {
+ /* add type header */
+ if (p_get->obj_type == BTA_FTC_GET_PB)
+ p = (UINT8 *)BTA_FTC_PULL_PB_TYPE;
+ is_ok = OBX_AddTypeHdr(p_obx->p_pkt, (char *)p);
+
+ /* add app params for PCE */
+ p_start = OBX_AddByteStrStart(p_obx->p_pkt, &len);
+ p = p_start;
+ if (p_get->obj_type != BTA_FTC_GET_PB || p_param->max_list_count != 0)
+ {
+ if (p_param->filter)
+ {
+ *p++ = BTA_FTC_APH_FILTER;
+ *p++ = 8;
+ /* set proprietary filter to 0 */
+ UINT32_TO_BE_STREAM(p, 0);
+ UINT32_TO_BE_STREAM(p, p_param->filter);
+ }
+ if (p_param->format < BTA_FTC_FORMAT_MAX)
+ {
+ *p++ = BTA_FTC_APH_FORMAT;
+ *p++ = 1;
+ *p++ = p_param->format;
+ }
+ }
+
+ if (p_get->obj_type == BTA_FTC_GET_PB)
+ {
+ /* this is mandatory */
+ *p++ = BTA_FTC_APH_MAX_LIST_COUNT;
+ *p++ = 2;
+ UINT16_TO_BE_STREAM(p, p_param->max_list_count);
+
+ if (p_param->list_start_offset)
+ {
+ *p++ = BTA_FTC_APH_LIST_STOFF;
+ *p++ = 2;
+ UINT16_TO_BE_STREAM(p, p_param->list_start_offset);
+ }
+ }
+
+ /* If any of the app param header is added */
+ if (p != p_start)
+ {
+ OBX_AddByteStrHdr(p_obx->p_pkt, OBX_HI_APP_PARMS, NULL, (UINT16)(p - p_start));
+ }
+ }
+ }
+
+ rem_name_len = (UINT16)(strlen(p_get->p_rem_name) + 1);
+ /* Need a buffer that can hold the local path and UTF-8 filename */
+ buflen = p_bta_fs_cfg->max_path_len + 2 + rem_name_len;
+
+ /* Save the UNICODE name of the remote file, and local filename and path */
+ if ((p_cb->p_name = (char *)GKI_getbuf(buflen)) != NULL)
+ {
+ memset(p_cb->p_name, 0, buflen);
+ BCM_STRNCPY_S(p_cb->p_name, p_bta_fs_cfg->max_path_len, p_get->p_name, p_bta_fs_cfg->max_path_len-1);
+
+ p_cb->obj_type = p_get->obj_type;
+ p_cb->obx_oper = FTC_OP_GET_FILE;
+ if (p_cb->obj_type == BTA_FTC_GET_PB && p_param->max_list_count == 0)
+ {
+ /* getting the phone book size only. do not need to open a file */
+ bta_ftc_send_get_req(p_cb);
+ }
+ else
+ {
+ p_cb->cout_active = TRUE;
+ bta_fs_co_open(p_cb->p_name,
+ (BTA_FS_O_RDWR | BTA_FS_O_CREAT | BTA_FS_O_TRUNC),
+ 0, BTA_FTC_CI_OPEN_EVT, p_cb->app_id);
+ }
+ status = BTA_FTC_OK;
+ }
+ }
+
+ if (status != BTA_FTC_OK)
+ {
+ data.status = status;
+ p_cb->p_cback(BTA_FTC_GETFILE_EVT, &data);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ftc_chdir
+**
+** Description Change Directory and get a listing of it.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ftc_chdir(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data)
+{
+ tBTA_FTC_API_CHDIR *p_chdir = &p_data->api_chdir;
+ tBTA_FTC_OBX_PKT *p_obx = &p_cb->obx;
+ tOBX_SETPATH_FLAG obx_flags = OBX_SPF_NO_CREATE;
+ tBTA_FTC_STATUS status = BTA_FTC_FAIL;
+ UINT16 len = OBX_CMD_POOL_SIZE; /* Don't need special OBX buffer pool */
+
+ /* Only process if no other OBX operation is active and connected to FTP */
+ if (p_cb->obx_oper == FTC_OP_NONE)
+ {
+ if (p_cb->sdp_service == UUID_SERVCLASS_OBEX_FILE_TRANSFER ||
+ p_cb->sdp_service == UUID_SERVCLASS_PBAP_PSE )
+ {
+ /* Allocate an OBX packet */
+ if ((p_obx->p_pkt = (BT_HDR *)OBX_HdrInit(p_cb->obx_handle, len)) != NULL)
+ {
+ status = BTA_FTC_OK;
+
+ /* Add the name header if not backing up */
+ if (p_chdir->flag != BTA_FTC_FLAG_BACKUP)
+ {
+ if (!OBX_AddUtf8NameHdr(p_obx->p_pkt, (UINT8 *)p_chdir->p_dir))
+ status = BTA_FTC_FAIL;
+ }
+ else
+ obx_flags |= OBX_SPF_BACKUP;
+ }
+ }
+ }
+
+ if (status == BTA_FTC_OK)
+ {
+ if (OBX_SetPathReq(p_cb->obx_handle, obx_flags, p_obx->p_pkt))
+ {
+ status = BTA_FTC_FAIL;
+ }
+ else
+ {
+ p_cb->req_pending = TRUE;
+ p_cb->obx_oper = FTC_OP_CHDIR;
+ p_obx->p_pkt = NULL; /* OBX will free the packet */
+ }
+
+ }
+
+ if (status != BTA_FTC_OK) /* Send an error response to the application */
+ {
+ utl_freebuf((void**)&p_obx->p_pkt);
+ p_cb->p_cback(BTA_FTC_CHDIR_EVT, (tBTA_FTC *)&status);
+ }
+}
+
+/*******************************************************************************
+**
+** Function ftp_clnt_listdir
+**
+** Description List the specified directory contents.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ftc_listdir(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data)
+{
+ /* Only process if no other OBX operation is active and connected to FTP */
+ if (p_cb->obx_oper == FTC_OP_NONE)
+ bta_ftc_get_listing(p_cb, p_data->api_list.p_dir, p_data->api_list.p_param);
+ else
+ bta_ftc_listing_err(&p_cb->obx.p_pkt, BTA_FTC_FAIL);
+}
+
+/*******************************************************************************
+**
+** Function bta_ftc_remove
+** Description Remove the specified directory or a file.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ftc_remove(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data)
+{
+ tBTA_FTC_OBX_PKT *p_obx = &p_cb->obx;
+ tBTA_FTC_STATUS status = BTA_FTC_OK;
+
+ APPL_TRACE_DEBUG1("bta_ftc_remove status:%d", p_cb->obx_oper);
+
+ if (p_data->api_mkdir.p_dir[0] != '\0')
+ {
+
+ /* Only process if no other OBX operation is active and connected to FTP */
+ if (p_cb->obx_oper == FTC_OP_NONE)
+ {
+ if ((p_obx->p_pkt = OBX_HdrInit(p_cb->obx_handle, OBX_CMD_POOL_SIZE)) != NULL)
+ {
+ /* Add the Name Header to the request */
+ status = BTA_FTC_OK;
+ OBX_AddUtf8NameHdr(p_obx->p_pkt, (UINT8 *)p_data->api_remove.p_name);
+ }
+ else
+ status = BTA_FTC_FAIL;
+ }
+ else
+ status = BTA_FTC_BUSY;
+ }
+ else
+ status = BTA_FTC_NOT_FOUND;
+
+ if (status == BTA_FTC_OK)
+ {
+ if ((OBX_PutReq(p_cb->obx_handle, TRUE, p_obx->p_pkt)) == OBX_SUCCESS)
+ {
+ p_cb->req_pending = TRUE;
+ p_cb->obx_oper = FTC_OP_DELETE;
+ p_obx->p_pkt = NULL; /* OBX will free the packet */
+ }
+ else
+ status = BTA_FTC_FAIL;
+ }
+
+ if (status != BTA_FTC_OK) /* Send an error response to the application */
+ {
+ utl_freebuf((void**)&p_obx->p_pkt);
+ p_cb->p_cback(BTA_FTC_REMOVE_EVT, (tBTA_FTC *)&status);
+ }
+}
+/*******************************************************************************
+**
+** Function bta_ftc_mkdir
+**
+** Description Create the specified directory.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ftc_mkdir(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data)
+{
+ tBTA_FTC_OBX_PKT *p_obx = &p_cb->obx;
+ tBTA_FTC_STATUS status = BTA_FTC_OK;
+
+ if (p_data->api_mkdir.p_dir[0] != '\0')
+ {
+ /* Only process if no other OBX operation is active and connected to FTP */
+ if (p_cb->obx_oper == FTC_OP_NONE)
+ {
+ if ((p_obx->p_pkt = OBX_HdrInit(p_cb->obx_handle, OBX_CMD_POOL_SIZE)) != NULL)
+ {
+ /* Add the Name Header to the request */
+ status = BTA_FTC_OK;
+ OBX_AddUtf8NameHdr(p_obx->p_pkt, (UINT8 *)p_data->api_mkdir.p_dir);
+ }
+ }
+ else
+ status = BTA_FTC_BUSY;
+ }
+ else
+ status = BTA_FTC_NOT_FOUND;
+
+ if (status == BTA_FTC_OK )
+ {
+ if ((OBX_SetPathReq(p_cb->obx_handle, 0, p_obx->p_pkt)) == OBX_SUCCESS)
+ {
+ p_cb->req_pending = TRUE;
+ p_cb->obx_oper = FTC_OP_MKDIR;
+ p_obx->p_pkt = NULL; /* OBX will free the packet */
+ }
+ else
+ status = BTA_FTC_FAIL;
+ }
+
+ if (status != BTA_FTC_OK) /* Send an error response to the application */
+ {
+ utl_freebuf((void**)&p_obx->p_pkt);
+ p_cb->p_cback(BTA_FTC_MKDIR_EVT, (tBTA_FTC *)&status);
+ }
+}
+
+
+
+/*******************************************************************************
+**
+** Function bta_ftc_send_authrsp
+**
+** Description Pass the response to an authentication request back to the
+** client.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ftc_send_authrsp(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data)
+{
+ UINT8 *p_pwd = NULL;
+ UINT8 *p_userid = NULL;
+
+ if (p_bta_ft_cfg->p_bi_action != NULL &&
+ p_bta_ft_cfg->p_bi_action[BTA_FTC_BI_AUTHRSP_IDX] &&
+ p_cb->sdp_service == UUID_SERVCLASS_IMAGING_RESPONDER)
+ {
+ (p_bta_ft_cfg->p_bi_action[BTA_FTC_BI_AUTHRSP_IDX])(p_cb, p_data);
+ return;
+ }
+ else
+ {
+ if (p_data->auth_rsp.key_len > 0)
+ p_pwd = (UINT8 *)p_data->auth_rsp.key;
+ if (p_data->auth_rsp.userid_len > 0)
+ p_userid = (UINT8 *)p_data->auth_rsp.userid;
+
+ OBX_AuthResponse(p_cb->obx_handle, p_pwd, p_data->auth_rsp.key_len,
+ p_userid, p_data->auth_rsp.userid_len, FALSE);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ftc_trans_cmpl
+**
+** Description push/pull complete
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ftc_trans_cmpl(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data)
+{
+ tBTA_FTC param;
+
+ /* Close the opened file */
+ if (p_cb->fd >= 0)
+ {
+ bta_fs_co_close(p_cb->fd, p_cb->app_id);
+ p_cb->fd = BTA_FS_INVALID_FD;
+ }
+
+ param.status = bta_ftc_convert_obx_to_ftc_status(p_data->obx_evt.rsp_code);
+
+ if (p_cb->obx_oper == FTC_OP_PUT_FILE)
+ p_cb->p_cback(BTA_FTC_PUTFILE_EVT, &param);
+ else if (p_cb->obx_oper == FTC_OP_GET_FILE)
+ {
+ if (param.status != BTA_FTC_OK)
+ {
+ bta_fs_co_unlink(p_cb->p_name, p_cb->app_id);
+ APPL_TRACE_WARNING2("FTC: Get File Operation Aborted or Error [%s], status 0x%02x",
+ p_cb->p_name, param.status);
+ }
+
+ p_cb->p_cback(BTA_FTC_GETFILE_EVT, &param);
+ }
+
+ /* Clean up control block */
+ ftc_reset_cb(p_cb);
+}
+
+/*******************************************************************************
+**
+** Function bta_ftc_ci_write
+**
+** Description Continue with the current write operation
+** (Get File processing)
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ftc_ci_write(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data)
+{
+ tBTA_FTC_OBX_PKT *p_obx = &p_cb->obx;
+ tBTA_FTC param;
+ UINT8 rsp_code = OBX_RSP_FAILED;
+
+ p_cb->cout_active = FALSE;
+
+ /* Process write call-in event if operation is still active */
+ if (p_cb->obx_oper != FTC_OP_GET_FILE)
+ return;
+
+ /* Free current packet */
+ utl_freebuf((void**)&p_obx->p_pkt);
+
+ /* Process any pending abort */
+ if (p_cb->aborting)
+ {
+ p_cb->aborting |= FTC_ABORT_COUT_DONE;
+
+ /* If already have response to abort then notify appl and cleanup */
+ if (FTC_ABORT_COMPLETED == p_cb->aborting)
+ {
+ /* APPL_TRACE_DEBUG0("Received WRITE CALL-IN function; continuing abort..."); */
+
+ /* OBX_RSP_GONE indicates aborted; used internally when called from API */
+ p_data->obx_evt.rsp_code = (!p_cb->int_abort) ? OBX_RSP_GONE : OBX_RSP_INTRNL_SRVR_ERR;
+ bta_ftc_sm_execute(p_cb, BTA_FTC_OBX_CMPL_EVT, p_data);
+ return;
+ }
+ }
+
+ if (p_data->write_evt.status == BTA_FS_CO_OK)
+ {
+ param.prog.bytes = p_obx->offset;
+ param.prog.file_size = p_cb->file_size;
+ p_cb->p_cback(BTA_FTC_PROGRESS_EVT, &param);
+
+ /* Send another Get request if not finished */
+ if (!p_obx->final_pkt)
+ {
+ /* send a new request */
+ bta_ftc_send_get_req(p_cb);
+ rsp_code = OBX_RSP_CONTINUE;
+ }
+ else
+ rsp_code = OBX_RSP_OK;
+ }
+
+ if (rsp_code != OBX_RSP_CONTINUE)
+ {
+ p_data->obx_evt.rsp_code = rsp_code;
+ bta_ftc_sm_execute(p_cb, BTA_FTC_OBX_CMPL_EVT, p_data);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ftc_ci_read
+**
+** Description Handles the response to a read call-out request.
+** This is called within the OBX get file request. The
+** operation has completed, send the OBX packet out.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ftc_ci_read(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data)
+{
+ tBTA_FTC_OBX_PKT *p_obx = &p_cb->obx;
+ tBTA_FS_CI_READ_EVT *p_revt = &p_data->read_evt;
+ tBTA_FTC param;
+ BOOLEAN is_final;
+
+ p_cb->cout_active = FALSE;
+
+ /* Process read call-in event if operation is still active */
+ if (p_cb->obx_oper == FTC_OP_PUT_FILE)
+ {
+ if (!p_cb->aborting)
+ {
+ if (p_revt->status != BTA_FS_CO_OK && p_revt->status != BTA_FS_CO_EOF)
+ {
+ p_cb->int_abort = TRUE;
+ bta_ftc_sm_execute(p_cb, BTA_FTC_API_ABORT_EVT, p_data);
+ }
+ else
+ {
+ is_final = (p_revt->status == BTA_FS_CO_EOF) ? TRUE: FALSE;
+
+ /* Add the body header to the packet */
+ OBX_AddBodyEnd(p_obx->p_pkt, p_obx->p_start, p_revt->num_read, is_final);
+
+ p_cb->obx.bytes_left -= p_revt->num_read;
+ p_cb->obx.offset += p_revt->num_read;
+
+ /* Send out the data */
+ OBX_PutReq(p_cb->obx_handle, is_final, p_obx->p_pkt);
+ p_obx->p_pkt = NULL;
+ p_cb->req_pending = TRUE;
+
+ /* Give application the status */
+ param.prog.bytes = p_revt->num_read;
+ param.prog.file_size = p_cb->file_size;
+ p_cb->p_cback(BTA_FTC_PROGRESS_EVT, &param);
+ }
+ }
+ else
+ {
+ /* Process any pending abort */
+ p_cb->aborting |= FTC_ABORT_COUT_DONE;
+
+ /* If already have response to abort then notify appl and cleanup */
+ if (FTC_ABORT_COMPLETED == p_cb->aborting)
+ {
+ /* APPL_TRACE_DEBUG0("Received READ CALL-IN function; continuing abort..."); */
+
+ /* OBX_RSP_GONE indicates aborted; used internally when called from API */
+ p_data->obx_evt.rsp_code = (!p_cb->int_abort) ? OBX_RSP_GONE : OBX_RSP_INTRNL_SRVR_ERR;
+ bta_ftc_sm_execute(p_cb, BTA_FTC_OBX_CMPL_EVT, p_data);
+ return;
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ftc_ci_open
+**
+** Description Continue with the current file open operation
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ftc_ci_open(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data)
+{
+ tBTA_FS_CI_OPEN_EVT *p_open = &p_data->open_evt;
+ UINT8 rsp_code = OBX_RSP_FAILED;
+
+ p_cb->cout_active = FALSE;
+ APPL_TRACE_DEBUG2("bta_ftc_ci_open status:%d, aborting:%d", p_open->status, p_cb->aborting);
+
+ /* Process any pending abort */
+ if (p_cb->aborting)
+ {
+ p_cb->aborting |= FTC_ABORT_COUT_DONE;
+
+ /* If already have response to abort then notify appl and cleanup */
+ if (FTC_ABORT_COMPLETED == p_cb->aborting)
+ {
+ /* APPL_TRACE_DEBUG0("Received OPEN CALL-IN function; continuing abort..."); */
+
+ /* OBX_RSP_GONE indicates aborted; used internally when called from API */
+ p_data->obx_evt.rsp_code = (!p_cb->int_abort) ? OBX_RSP_GONE : OBX_RSP_INTRNL_SRVR_ERR;
+ bta_ftc_sm_execute(p_cb, BTA_FTC_OBX_CMPL_EVT, p_data);
+ return;
+ }
+ }
+
+ /* if file is accessible read/write the first buffer of data */
+ if (p_open->status == BTA_FS_CO_OK)
+ {
+ p_cb->fd = p_open->fd;
+
+ /* If using OBEX 1.5 */
+ if (p_open->p_file)
+ {
+ if ((p_cb->p_name != NULL) ||
+ (p_cb->p_name = (char *)GKI_getbuf((UINT16)(p_bta_fs_cfg->max_path_len + 1))) != NULL)
+ {
+ /* save the image file name */
+ BCM_STRNCPY_S(p_cb->p_name, p_bta_fs_cfg->max_path_len+1, p_open->p_file, p_bta_fs_cfg->max_path_len);
+ p_cb->p_name[p_bta_fs_cfg->max_path_len] = '\0';
+ p_cb->first_req_pkt = FALSE;
+ }
+ }
+ else
+ p_cb->first_req_pkt = TRUE;
+
+ APPL_TRACE_DEBUG2("first_req_pkt:%d obx_oper:%d", p_cb->first_req_pkt, p_cb->obx_oper);
+
+ if (p_cb->obx_oper == FTC_OP_PUT_FILE)
+ {
+ p_cb->file_size = p_open->file_size;
+ rsp_code = bta_ftc_cont_put_file(p_cb, p_cb->first_req_pkt);
+ }
+ else if (p_cb->obx_oper == FTC_OP_GET_FILE)
+ {
+ /* Initiate the first OBX GET request */
+ rsp_code = bta_ftc_send_get_req(p_cb);
+ }
+ }
+ else
+ {
+ /* If using OBEX 1.5 */
+ if (p_open->status == BTA_FS_CO_NONE)
+ {
+ rsp_code = OBX_RSP_OK;
+ if (p_cb->obx_oper == FTC_OP_GET_LIST)
+ {
+ bta_ftc_abort(p_cb, NULL);
+ }
+ }
+ else
+ {
+ if (p_open->status == BTA_FS_CO_EACCES)
+ rsp_code = OBX_RSP_UNAUTHORIZED;
+ else /* File could not be found */
+ rsp_code = OBX_RSP_NOT_FOUND;
+ }
+ }
+
+ if (rsp_code != OBX_RSP_OK)
+ {
+ p_data->obx_evt.rsp_code = rsp_code;
+ bta_ftc_sm_execute(p_cb, BTA_FTC_OBX_CMPL_EVT, p_data);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ftc_ci_resume
+**
+** Description Continue with the resume session
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ftc_ci_resume(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data)
+{
+ tBTA_FS_CI_RESUME_EVT *p_resume = &p_data->resume_evt;
+
+ APPL_TRACE_DEBUG3("bta_ftc_ci_resume status:%d, ssn:%d, info:%d",
+ p_resume->status, p_resume->ssn, p_resume->info);
+
+ if (p_resume->status == BTA_FS_CO_OK &&
+ OBX_AllocSession (p_resume->p_sess_info, 0, &p_cb->psm,
+ bta_ftc_obx_cback, &p_cb->obx_handle) == OBX_SUCCESS)
+ {
+ BTM_SetSecurityLevel (TRUE, "BTA_FTC", BTM_SEC_SERVICE_OBEX_FTP,
+ p_cb->sec_mask, p_cb->psm,
+ 0, 0);
+ OBX_ResumeSession (p_cb->bd_addr, p_resume->ssn, p_resume->offset, p_cb->obx_handle);
+ }
+ else
+ {
+ p_cb->status = BTA_FTC_OBX_ERR;
+ p_data->obx_evt.rsp_code = OBX_RSP_FAILED;
+ bta_ftc_sm_execute(p_cb, BTA_FTC_OBX_CLOSE_EVT, p_data);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ftc_obx_conn_rsp
+**
+** Description Process the OBX connect event.
+** If FTP service, get directory listing.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ftc_obx_conn_rsp(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data)
+{
+ tBTA_FTC_OBX_EVT *p_evt = &p_data->obx_evt;
+ tBTA_FTC param;
+ tOBX_SESS_EVT *p_sess;
+ UINT8 obx_oper, *p_obx_oper = &p_cb->obx_oper;
+
+ APPL_TRACE_DEBUG1("bta_ftc_obx_conn_rsp obx_event=%d", p_evt->obx_event);
+
+ /* If using OBEX 1.5 */
+ if (p_evt->obx_event == OBX_SESSION_RSP_EVT)
+ {
+ p_sess = &p_evt->param.sess;
+ APPL_TRACE_DEBUG2("bta_ftc_obx_conn_rsp sess_id:0x%x/0x%x", p_cb->p_sess_info, p_sess->p_sess_info);
+ p_cb->p_sess_info = p_sess->p_sess_info;
+ APPL_TRACE_DEBUG2("client cb p_sess_info:0x%x obj_offset:x%x", p_cb->p_sess_info, p_sess->obj_offset);
+ if (p_cb->nonce != BTA_FTC_RESUME_NONCE)
+ {
+ p_obx_oper = &obx_oper;
+ p_cb->obx_oper = FTC_OP_NONE;
+ }
+ bta_fs_co_session_info(p_cb->bd_addr, p_cb->p_sess_info, p_sess->ssn, BTA_FS_CO_SESS_ST_ACTIVE, NULL, p_obx_oper, p_cb->app_id);
+ if ((p_sess->sess_op == OBX_SESS_OP_CREATE) || (p_sess->sess_op == OBX_SESS_OP_RESUME))
+ {
+ p_cb->state = BTA_FTC_W4_CONN_ST;
+ }
+ if (p_cb->obx_oper)
+ bta_fs_co_resume_op(p_sess->obj_offset, BTA_FTC_CI_OPEN_EVT, p_cb->app_id);
+ return;
+ }
+
+ p_cb->peer_mtu = p_data->obx_evt.param.conn.mtu;
+
+ APPL_TRACE_DEBUG2("bta_ftc_obx_conn_rsp peer_mtu=%d obx_oper:0x%x", p_cb->peer_mtu, p_cb->obx_oper);
+
+ /* OPP is connected and ready */
+ if (p_cb->sdp_service == UUID_SERVCLASS_OBEX_OBJECT_PUSH)
+ {
+ param.open.service = BTA_OPP_SERVICE_ID;
+ APPL_TRACE_EVENT0("[BTA FTC]OPP Service Id ");
+ }
+ /* PBAP is connected and ready */
+ else if (p_cb->sdp_service == UUID_SERVCLASS_PBAP_PSE)
+ {
+ param.open.service = BTA_PBAP_SERVICE_ID;
+ APPL_TRACE_EVENT0("[BTA FTC]PBAP Service Id ");
+ }
+ else /* Initiate directory listing if FTP service */
+ {
+ APPL_TRACE_EVENT0("[BTA FTC]FTP Service Id ");
+ param.open.service = BTA_FTP_SERVICE_ID;
+ if (p_bta_ft_cfg->auto_file_list && !p_cb->obx_oper)
+ {
+ bta_ftc_get_listing(p_cb, ".", NULL);
+ }
+ }
+
+ if (p_cb->p_sess_info == NULL)
+ {
+ bta_fs_co_session_info(p_cb->bd_addr, p_cb->p_sess_info, 0, BTA_FS_CO_SESS_ST_NONE, NULL, NULL, p_cb->app_id);
+ }
+ p_cb->suspending = FALSE;
+
+ /* inform role manager */
+ bta_sys_conn_open( BTA_ID_FTC ,p_cb->app_id, p_cb->bd_addr);
+
+ param.open.version = p_cb->version;
+ p_cb->p_cback(BTA_FTC_OPEN_EVT, &param);
+
+ /* Done with Obex packet */
+ utl_freebuf((void**)&p_evt->p_pkt);
+}
+
+/*******************************************************************************
+**
+** Function bta_ftc_obx_sess_rsp
+**
+** Description Process the OBX session event.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ftc_obx_sess_rsp(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data)
+{
+ tBTA_FTC_OBX_EVT *p_evt = &p_data->obx_evt;
+ tOBX_SESS_EVT *p_sess = &p_data->obx_evt.param.sess;
+
+ APPL_TRACE_DEBUG3("bta_ftc_obx_sess_rsp obx_event=%d sess_op:%d, ssn:%d",
+ p_evt->obx_event, p_sess->sess_op, p_sess->ssn);
+ if (p_evt->obx_event == OBX_SESSION_RSP_EVT && p_sess->sess_op == OBX_SESS_OP_SUSPEND)
+ {
+ p_cb->p_sess_info = p_sess->p_sess_info;
+ APPL_TRACE_DEBUG1("client cb p_sess_info:0x%x", p_cb->p_sess_info);
+ bta_fs_co_suspend(p_cb->bd_addr, p_cb->p_sess_info, p_sess->ssn, &p_sess->timeout, NULL, p_cb->obx_oper, p_cb->app_id);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ftc_suspended
+**
+** Description Process transport down suspend.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ftc_suspended(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data)
+{
+ tBTA_FTC_OBX_EVT *p_evt = &p_data->obx_evt;
+ tOBX_SESS_EVT *p_sess = &p_data->obx_evt.param.sess;
+ UINT32 offset = 0;
+
+ APPL_TRACE_DEBUG4("bta_ftc_suspended obx_event=%d sess_op:%d, ssn:%d, obx_oper:%d",
+ p_evt->obx_event, p_sess->sess_op, p_sess->ssn, p_cb->obx_oper);
+ if (p_evt->obx_event == OBX_SESSION_INFO_EVT)
+ {
+ if ((p_cb->obx_oper != FTC_OP_GET_FILE) && (p_cb->obx_oper != FTC_OP_PUT_FILE) && (p_cb->obx_oper != FTC_OP_GET_LIST))
+ {
+ /* the other obx ops are single transaction.
+ * If the link is dropped before the transaction ends, re-transmit the request when the session resumes */
+ p_sess->ssn--;
+ p_cb->obx_oper = FTC_OP_NONE;
+ }
+ p_cb->suspending = TRUE;
+ bta_fs_co_suspend(p_cb->bd_addr, p_sess->p_sess_info, p_sess->ssn,
+ &p_sess->timeout, &offset, p_cb->obx_oper, p_cb->app_id);
+ /* do not need to worry about active call-out here.
+ * this is a result of OBX_SESSION_INFO_EVT
+ * OBX would report OBX_CLOSE_IND_EVT, which will eventually call bta_ftc_close_complete */
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ftc_obx_abort_rsp
+**
+** Description Process the OBX abort event
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ftc_obx_abort_rsp(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data)
+{
+ bta_sys_stop_timer(&p_cb->rsp_timer);
+
+ /* Done with Obex packet */
+ utl_freebuf((void**)&p_data->obx_evt.p_pkt);
+
+ if (p_cb->obx_oper != FTC_OP_NONE)
+ {
+ if (!p_cb->cout_active)
+ {
+ /* OBX_RSP_GONE indicates aborted; used internally when called from API */
+ p_data->obx_evt.rsp_code = (!p_cb->int_abort) ? OBX_RSP_GONE : OBX_RSP_INTRNL_SRVR_ERR;
+ bta_ftc_sm_execute(p_cb, BTA_FTC_OBX_CMPL_EVT, p_data);
+ }
+ else /* must wait for cout function to complete before finishing the abort */
+ {
+ /* Mark the fact we have already received the response from the peer */
+ p_cb->aborting |= FTC_ABORT_RSP_RCVD;
+ /* APPL_TRACE_DEBUG1("ftc_obx_abort_rsp()->Rcvd abort_rsp; waiting for callin...",
+ p_cb->aborting); */
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ftc_obx_password
+**
+** Description Process the OBX password request
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ftc_obx_password(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data)
+{
+ tBTA_FTC_OBX_EVT *p_evt = &p_data->obx_evt;
+ tBTA_FTC_AUTH parms;
+ tOBX_AUTH_OPT options;
+
+ memset(&parms, 0, sizeof(tBTA_FTC_AUTH));
+
+ /* Extract user id from packet (if available) */
+ if (OBX_ReadChallenge(p_evt->p_pkt, &parms.realm_charset,
+ &parms.p_realm,
+ &parms.realm_len, &options))
+ {
+ if (options & OBX_AO_USR_ID)
+ parms.userid_required = TRUE;
+ }
+
+ /* Don't need OBX packet any longer */
+ utl_freebuf((void**)&p_evt->p_pkt);
+
+ /* Notify application */
+ p_cb->p_cback(BTA_FTC_AUTH_EVT, (tBTA_FTC *)&parms);
+}
+
+/*******************************************************************************
+**
+** Function bta_ftc_obx_timeout
+**
+** Description Process the OBX timeout event
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ftc_obx_timeout(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data)
+{
+ utl_freebuf((void**)&p_data->obx_evt.p_pkt);
+
+ /* If currently processing OBX request, peer is unresponsive so we're done */
+ if (p_cb->aborting || p_cb->obx_oper != FTC_OP_NONE)
+ {
+#if( defined BTA_BI_INCLUDED ) && (BTA_BI_INCLUDED == TRUE)
+ if (p_cb->bic_handle != BTA_BIC_INVALID_HANDLE)
+ {
+ BTA_BicDeRegister(p_cb->bic_handle);
+ p_cb->bic_handle = BTA_BIC_INVALID_HANDLE;
+ }
+ else
+#endif
+ {
+ p_data->obx_evt.rsp_code = OBX_RSP_GONE;
+ p_cb->status = BTA_FTC_OBX_TOUT;
+
+ /* Start stop response timer */
+ p_cb->timer_oper = FTC_TIMER_OP_STOP;
+ bta_sys_start_timer(&p_cb->rsp_timer, BTA_FTC_RSP_TOUT_EVT,
+ p_bta_ft_cfg->stop_tout);
+
+ OBX_DisconnectReq(p_cb->obx_handle, NULL);
+ bta_ftc_sm_execute(p_cb, BTA_FTC_OBX_CLOSE_EVT, p_data);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ftc_obx_put_rsp
+**
+** Description Process the OBX file put and delete file/folder events
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ftc_obx_put_rsp(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data)
+{
+ tBTA_FTC_OBX_EVT *p_evt = &p_data->obx_evt;
+ tBTA_FTC_STATUS status;
+
+ p_cb->req_pending = FALSE;
+ p_cb->first_req_pkt = FALSE;
+
+ /* Done with Obex packet */
+ utl_freebuf((void**)&p_evt->p_pkt);
+
+ if (p_cb->obx_oper == FTC_OP_PUT_FILE)
+ {
+ /* If not finished with Put, start another read */
+ if (p_evt->rsp_code == OBX_RSP_CONTINUE)
+ bta_ftc_cont_put_file(p_cb, FALSE);
+ else
+ {
+ p_data->obx_evt.rsp_code = p_evt->rsp_code;
+ bta_ftc_sm_execute(p_cb, BTA_FTC_OBX_CMPL_EVT, p_data);
+ }
+ }
+
+ else if (p_cb->obx_oper == FTC_OP_DELETE)
+ {
+ status = bta_ftc_convert_obx_to_ftc_status(p_data->obx_evt.rsp_code);
+ p_cb->obx_oper = FTC_OP_NONE;
+ p_cb->p_cback(BTA_FTC_REMOVE_EVT, (tBTA_FTC *)&status);
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function bta_ftc_obx_get_rsp
+**
+** Description Process the OBX file get and folder listing events
+** If the type header is not folder listing, then pulling a file.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ftc_obx_get_rsp(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data)
+{
+ tBTA_FTC_OBX_EVT *p_evt = &p_data->obx_evt;
+
+ APPL_TRACE_DEBUG2("bta_ftc_obx_get_rsp req_pending=%d obx_oper:%d", p_cb->req_pending, p_cb->obx_oper);
+ p_cb->req_pending = FALSE;
+
+ if (p_cb->obx_oper == FTC_OP_GET_FILE)
+ bta_ftc_proc_get_rsp(p_cb, p_data);
+ else if (p_cb->obx_oper == FTC_OP_GET_LIST)
+ bta_ftc_proc_list_data(p_cb, p_evt);
+ else /* Release the unexpected OBX response packet */
+ utl_freebuf((void**)&p_evt->p_pkt);
+}
+
+/*******************************************************************************
+**
+** Function bta_ftc_obx_setpath_rsp
+**
+** Description Process the response to a change or make directory requests
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ftc_obx_setpath_rsp(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data)
+{
+ tBTA_FTC_OBX_EVT *p_evt = &p_data->obx_evt;
+ tBTA_FTC_STATUS status = BTA_FTC_FAIL;
+ tBTA_FTC_EVT event = BTA_FTC_CHDIR_EVT;
+
+ p_cb->req_pending = FALSE;
+
+ if (p_cb->obx_oper == FTC_OP_MKDIR)
+ event = BTA_FTC_MKDIR_EVT;
+
+ if (p_evt->rsp_code == OBX_RSP_OK)
+ status = BTA_FTC_OK;
+
+ p_cb->obx_oper = FTC_OP_NONE;
+
+ utl_freebuf((void**)&p_evt->p_pkt); /* Done with Obex packet */
+ p_cb->p_cback(event, (tBTA_FTC *)&status);
+
+ /* If successful, initiate a directory listing */
+ if (p_evt->rsp_code == OBX_RSP_OK && p_bta_ft_cfg->auto_file_list &&
+ (p_cb->sdp_service == UUID_SERVCLASS_OBEX_FILE_TRANSFER))
+ {
+ bta_ftc_get_listing(p_cb, ".", NULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ftc_rsp_timeout
+**
+** Description Process the OBX response timeout event
+** stop and abort
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ftc_rsp_timeout(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data)
+{
+ p_cb->timer_oper = FTC_TIMER_OP_STOP;
+ if (p_cb->timer_oper == FTC_TIMER_OP_ABORT)
+ {
+ /* Start stop response timer */
+ p_cb->status = BTA_FTC_ABORTED;
+ bta_sys_start_timer(&p_cb->rsp_timer, BTA_FTC_RSP_TOUT_EVT,
+ p_bta_ft_cfg->stop_tout);
+
+ OBX_DisconnectReq(p_cb->obx_handle, NULL);
+ }
+ else /* Timeout waiting for disconnect response */
+ {
+ p_cb->cout_active = FALSE;
+ bta_ftc_initialize(p_cb, p_data);
+#if( defined BTA_BI_INCLUDED ) && (BTA_BI_INCLUDED == TRUE)
+ BTA_BicFreeXmlData(BTA_BIC_CAPABILITIES_EVT, (tBTA_BI_XML **)&p_cb->p_caps);
+#endif
+ /* force OBX to close port */
+ OBX_DisconnectReq(p_cb->obx_handle, NULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ftc_initialize
+**
+** Description Initialize the control block.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ftc_initialize(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data)
+{
+ tBTA_FS_CO_STATUS status;
+
+ bta_sys_stop_timer(&p_cb->rsp_timer);
+
+ /* Close any open files */
+ if (p_cb->fd >= 0)
+ {
+ bta_fs_co_close(p_cb->fd, p_cb->app_id);
+ p_cb->fd = BTA_FS_INVALID_FD;
+
+ /* Delete an aborted unfinished get file operation */
+ if (p_cb->obx_oper == FTC_OP_GET_FILE && p_cb->suspending == FALSE)
+ {
+ status = bta_fs_co_unlink(p_cb->p_name, p_cb->app_id);
+ APPL_TRACE_WARNING2("FTC: Remove ABORTED Get File Operation [%s], status 0x%02x",
+ p_cb->p_name, status);
+ }
+ }
+
+ /* Clean up control block */
+ ftc_reset_cb(p_cb);
+ p_cb->sdp_service = 0;
+ p_cb->sdp_pending = FALSE;
+ p_cb->suspending = FALSE;
+ p_cb->p_sess_info = NULL;
+
+ if (p_cb->disabling)
+ {
+ if (p_cb->sdp_handle)
+ {
+ SDP_DeleteRecord(p_cb->sdp_handle);
+ p_cb->sdp_handle = 0;
+ bta_sys_remove_uuid( UUID_SERVCLASS_PBAP_PCE );
+ }
+ p_cb->is_enabled = FALSE;
+ p_cb->disabling = FALSE;
+ bta_ftc_sm_execute(p_cb, BTA_FTC_DISABLE_CMPL_EVT, NULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ftc_stop_client
+**
+** Description Stop OBX client.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ftc_stop_client(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data)
+{
+ INT32 timeout;
+
+ APPL_TRACE_DEBUG1("bta_ftc_stop_client suspend:%d", p_data->api_close.suspend);
+#if( defined BTA_BI_INCLUDED ) && (BTA_BI_INCLUDED == TRUE)
+ if (p_bta_ft_cfg->p_bi_action &&
+ p_bta_ft_cfg->p_bi_action[BTA_FTC_BI_DEREGISTER_IDX] &&
+ p_cb->bic_handle != BTA_BIC_INVALID_HANDLE)
+ {
+ (p_bta_ft_cfg->p_bi_action[BTA_FTC_BI_DEREGISTER_IDX])(p_cb, p_data);
+ }
+ else if (!p_cb->sdp_pending)
+#else
+ if (!p_cb->sdp_pending)
+#endif
+ {
+ if (p_data->api_close.suspend)
+ {
+ timeout = p_bta_ft_cfg->suspend_tout;
+ p_cb->timer_oper = FTC_TIMER_OP_SUSPEND;
+ p_cb->suspending = TRUE;
+ OBX_SessionReq (p_cb->obx_handle, OBX_SESS_OP_SUSPEND, 0);
+ p_cb->state = BTA_FTC_SUSPENDING_ST;
+
+ }
+ else
+ {
+ bta_fs_co_session_info(p_cb->bd_addr, p_cb->p_sess_info, 0, BTA_FS_CO_SESS_ST_NONE, NULL, NULL, p_cb->app_id);
+
+ timeout = p_bta_ft_cfg->stop_tout;
+ p_cb->timer_oper = FTC_TIMER_OP_STOP;
+ OBX_DisconnectReq(p_cb->obx_handle, NULL);
+ }
+ /* Start stop response timer */
+ bta_sys_start_timer(&p_cb->rsp_timer, BTA_FTC_RSP_TOUT_EVT, timeout );
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ftc_close
+**
+** Description If not waiting for a call-in function, complete the closing
+** of the channel.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ftc_close(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data)
+{
+ /* finished if not waiting on a call-in function */
+ if (!p_cb->sdp_pending && !p_cb->cout_active)
+ bta_ftc_sm_execute(p_cb, BTA_FTC_CLOSE_CMPL_EVT, p_data);
+}
+
+/*******************************************************************************
+**
+** Function bta_ftc_close
+**
+** Description If not waiting for a call-in function, complete the closing
+** of the channel.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ftc_open_fail(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data)
+{
+ bta_ftc_close(p_cb, p_data);
+}
+
+/*******************************************************************************
+**
+** Function bta_ftc_start_client
+**
+** Description Start an FTP or OPP client.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ftc_start_client(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data)
+{
+ tOBX_STATUS status;
+ UINT16 mtu = OBX_MAX_MTU;
+ BOOLEAN srm = p_cb->srm;
+ UINT32 nonce = p_cb->nonce;
+ tBTA_FTC_OBX_PKT *p_obx = &p_cb->obx;
+
+ p_cb->status = BTA_FTC_OK;
+ p_cb->p_sess_info = NULL;
+
+ if ( p_bta_ft_cfg->p_bi_action &&
+ p_bta_ft_cfg->p_bi_action[BTA_FTC_BI_REGISTER_IDX] &&
+ p_cb->sdp_service == UUID_SERVCLASS_IMAGING_RESPONDER)
+ {
+ (p_bta_ft_cfg->p_bi_action[BTA_FTC_BI_REGISTER_IDX])(p_cb, p_data);
+ return;
+ }
+
+ /* If using OBEX 1.5 */
+ if (p_cb->nonce == BTA_FTC_RESUME_NONCE)
+ {
+ APPL_TRACE_DEBUG1("bta_ftc_start_client psm:0x%x", p_data->sdp_ok.psm);
+ p_cb->psm = p_data->sdp_ok.psm;
+ bta_fs_co_resume (BTA_FTC_CI_SESSION_EVT, p_cb->app_id);
+ }
+ /* Allocate an OBX packet */
+ else
+ {
+ if ((p_obx->p_pkt = (BT_HDR *)OBX_HdrInit(OBX_HANDLE_NULL, OBX_CMD_POOL_SIZE)) != NULL)
+ {
+ p_cb->version = p_data->sdp_ok.version;
+
+ /* Add the target header if connecting to FTP service */
+ if (p_cb->sdp_service == UUID_SERVCLASS_OBEX_FILE_TRANSFER)
+ {
+ OBX_AddTargetHdr(p_obx->p_pkt, (UINT8 *)BTA_FTC_FOLDER_BROWSING_TARGET_UUID,
+ BTA_FTC_UUID_LENGTH);
+ }
+ /* Add the target header if connecting to PBAP service */
+ else if (p_cb->sdp_service == UUID_SERVCLASS_PBAP_PSE)
+ {
+ OBX_AddTargetHdr(p_obx->p_pkt, (UINT8 *)BTA_FTC_PB_ACCESS_TARGET_UUID,
+ BTA_FTC_UUID_LENGTH);
+ }
+
+ status = OBX_AllocSession (NULL, p_data->sdp_ok.scn, &p_data->sdp_ok.psm,
+ bta_ftc_obx_cback, &p_cb->obx_handle);
+
+ /* set security level */
+ if (p_data->sdp_ok.scn)
+ {
+ BTM_SetSecurityLevel (TRUE, "BTA_FTC", BTM_SEC_SERVICE_OBEX_FTP,
+ p_cb->sec_mask, BT_PSM_RFCOMM,
+ BTM_SEC_PROTO_RFCOMM, p_data->sdp_ok.scn);
+ srm = 0;
+ nonce = 0;
+ }
+ else
+ {
+ BTM_SetSecurityLevel (TRUE, "BTA_FTC", BTM_SEC_SERVICE_OBEX_FTP,
+ p_cb->sec_mask, p_data->sdp_ok.psm, 0, 0);
+ }
+
+ if (status == OBX_SUCCESS)
+ {
+ OBX_CreateSession (p_cb->bd_addr, mtu, srm, nonce,
+ p_cb->obx_handle, p_obx->p_pkt);
+ p_obx->p_pkt = NULL; /* OBX will free the memory */
+ return;
+ }
+ /* else stay in this function to report failure */
+ return;
+ }
+ else
+ {
+ p_cb->status = BTA_FTC_OBX_ERR;
+ p_data->obx_evt.rsp_code = OBX_RSP_FAILED;
+ bta_ftc_sm_execute(p_cb, BTA_FTC_OBX_CLOSE_EVT, p_data);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ftc_free_db
+**
+** Description Free buffer used for service discovery database.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ftc_free_db(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data)
+{
+ utl_freebuf((void**)&p_cb->p_db);
+ p_cb->sdp_pending = FALSE;
+}
+
+/*******************************************************************************
+**
+** Function bta_ftc_ignore_obx
+**
+** Description Free OBX packet for ignored OBX events.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ftc_ignore_obx(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data)
+{
+ utl_freebuf((void**)&p_data->obx_evt.p_pkt);
+}
+
+/*******************************************************************************
+**
+** Function bta_ftc_find_service
+**
+** Description Perform service discovery to find OPP and/or FTP services on
+** peer device. If the service ID is both FTP and OPP then FTP
+** is tried first.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ftc_find_service(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data)
+{
+ tSDP_UUID uuid_list;
+ UINT16 attr_list[5];
+ UINT16 num_attrs = 4;
+ tBTA_SERVICE_MASK ftc_services = (BTA_FTP_SERVICE_MASK | BTA_OPP_SERVICE_MASK
+ | BTA_BIP_SERVICE_MASK | BTA_PBAP_SERVICE_MASK);
+
+ APPL_TRACE_DEBUG1("bta_ftc_find_service event:0x%x", BTA_FTC_API_OPEN_EVT);
+
+ /* Make sure at least one service was specified */
+ if (p_cb->services & ftc_services)
+ {
+ if ((p_cb->p_db = (tSDP_DISCOVERY_DB *) GKI_getbuf(BTA_FTC_DISC_SIZE)) != NULL)
+ {
+ p_cb->status = BTA_FTC_OK;
+
+ attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST;
+ attr_list[1] = ATTR_ID_PROTOCOL_DESC_LIST;
+ attr_list[2] = ATTR_ID_BT_PROFILE_DESC_LIST;
+ attr_list[3] = ATTR_ID_OBX_OVR_L2CAP_PSM;
+
+ uuid_list.len = LEN_UUID_16;
+
+ /* Try FTP if its service is desired */
+ if (p_cb->services & BTA_FTP_SERVICE_MASK)
+ {
+ p_cb->services &= ~BTA_FTP_SERVICE_MASK;
+ p_cb->sdp_service = UUID_SERVCLASS_OBEX_FILE_TRANSFER;
+ uuid_list.uu.uuid16 = UUID_SERVCLASS_OBEX_FILE_TRANSFER;
+ }
+ else if (p_cb->services & BTA_PBAP_SERVICE_MASK)
+ {
+ p_cb->services &= ~BTA_PBAP_SERVICE_MASK;
+ p_cb->sdp_service = UUID_SERVCLASS_PBAP_PSE;
+ uuid_list.uu.uuid16 = UUID_SERVCLASS_PBAP_PSE;
+ }
+ else if (p_cb->services & BTA_OPP_SERVICE_MASK)
+ {
+ p_cb->services &= ~BTA_OPP_SERVICE_MASK;
+ p_cb->sdp_service = UUID_SERVCLASS_OBEX_OBJECT_PUSH;
+ uuid_list.uu.uuid16 = UUID_SERVCLASS_OBEX_OBJECT_PUSH;
+ }
+ else if (p_bta_ft_cfg->p_bi_action)
+ {
+ /* Try the basic imaging service */
+ p_cb->services &= ~BTA_BIP_SERVICE_MASK;
+ p_cb->sdp_service = UUID_SERVCLASS_IMAGING_RESPONDER;
+ uuid_list.uu.uuid16 = UUID_SERVCLASS_IMAGING_RESPONDER;
+ attr_list[num_attrs++] = ATTR_ID_SUPPORTED_FEATURES;
+ }
+
+ SDP_InitDiscoveryDb(p_cb->p_db, BTA_FTC_DISC_SIZE, 1, &uuid_list, num_attrs, attr_list);
+ if (!SDP_ServiceSearchAttributeRequest(p_cb->bd_addr, p_cb->p_db, bta_ftc_sdp_cback))
+ {
+ p_cb->status = BTA_FTC_SDP_ERR;
+ bta_ftc_sm_execute(p_cb, BTA_FTC_SDP_FAIL_EVT, p_data);
+
+ }
+
+ p_cb->sdp_pending = TRUE;
+ }
+ }
+ else /* No services available */
+ {
+ p_cb->status = BTA_FTC_SERVICE_UNAVL;
+ bta_ftc_sm_execute(p_cb, BTA_FTC_SDP_FAIL_EVT, p_data);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ftc_close_complete
+**
+** Description Finishes the memory cleanup after a channel is closed.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ftc_close_complete(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data)
+{
+ tBTA_FTC param;
+
+ param.status = p_cb->status;
+ p_cb->cout_active = FALSE;
+ bta_ftc_initialize(p_cb, p_data);
+
+ if (p_bta_ft_cfg->p_bi_action && p_bta_ft_cfg->p_bi_action[BTA_FTC_BI_FREEXML_IDX])
+ (p_bta_ft_cfg->p_bi_action[BTA_FTC_BI_FREEXML_IDX])(p_cb, p_data);
+
+ /* inform role manager */
+ bta_sys_conn_close( BTA_ID_FTC ,p_cb->app_id, p_cb->bd_addr);
+ bta_fs_co_session_info(p_cb->bd_addr, p_cb->p_sess_info, 0, BTA_FS_CO_SESS_ST_NONE, NULL, NULL, p_cb->app_id);
+
+ p_cb->p_cback(BTA_FTC_CLOSE_EVT, &param);
+}
+
+/*******************************************************************************
+**
+** Function bta_ftc_set_disable
+**
+** Description Finishes the memory cleanup after a channel is closed.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ftc_set_disable(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data)
+{
+ p_cb->disabling = TRUE;
+}
+
+/*******************************************************************************
+**
+** Function bta_ftc_bic_put
+**
+** Description Initiate a connection with a peer device's service.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ftc_bic_put(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data)
+{
+ if (p_bta_ft_cfg->p_bi_action &&
+ p_bta_ft_cfg->p_bi_action[BTA_FTC_BI_PUT_IDX])
+ {
+ p_bta_ft_cfg->p_bi_action[BTA_FTC_BI_PUT_IDX](p_cb, p_data);
+ }
+ return;
+}
+
+/*******************************************************************************
+**
+** Function bta_ftc_bic_abort
+**
+** Description Initiate a connection with a peer device's service.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ftc_bic_abort(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data)
+{
+ if (p_bta_ft_cfg->p_bi_action &&
+ p_bta_ft_cfg->p_bi_action[BTA_FTC_BI_ABORT_IDX])
+ {
+ p_bta_ft_cfg->p_bi_action[BTA_FTC_BI_ABORT_IDX](p_cb, p_data);
+ }
+ return;
+}
+
+/*****************************************************************************
+** Callback Functions
+*****************************************************************************/
+/*******************************************************************************
+**
+** Function bta_ftc_obx_cback
+**
+** Description OBX callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ftc_obx_cback (tOBX_HANDLE handle, tOBX_EVENT obx_event, UINT8 rsp_code,
+ tOBX_EVT_PARAM param, BT_HDR *p_pkt)
+{
+ tBTA_FTC_OBX_EVT *p_obx_msg;
+ UINT16 event = 0;
+ UINT16 size = sizeof(tBTA_FTC_OBX_EVT);
+
+#if BTA_FTC_DEBUG == TRUE
+ APPL_TRACE_DEBUG2("OBX Event Callback: obx_event [%s] 0x%x", ftc_obx_evt_code(obx_event), p_pkt);
+#endif
+
+ switch (obx_event)
+ {
+ case OBX_SESSION_INFO_EVT:
+ size += OBX_SESSION_INFO_SIZE;
+ /* Falls through */
+
+ case OBX_SESSION_RSP_EVT:
+ case OBX_CONNECT_RSP_EVT:
+ if (rsp_code == OBX_RSP_OK)
+ {
+ event = BTA_FTC_OBX_CONN_RSP_EVT;
+ }
+ else /* Obex will disconnect underneath BTA */
+ {
+ APPL_TRACE_WARNING1("FTC_CBACK: Bad connect response 0x%02x", rsp_code);
+ if (p_pkt)
+ GKI_freebuf(p_pkt);
+ return;
+ }
+ break;
+
+ case OBX_ACTION_RSP_EVT:
+ event = BTA_FTC_OBX_ACTION_RSP_EVT;
+ break;
+
+ case OBX_PUT_RSP_EVT:
+ event = BTA_FTC_OBX_PUT_RSP_EVT;
+ break;
+ case OBX_GET_RSP_EVT:
+ event = BTA_FTC_OBX_GET_RSP_EVT;
+ break;
+ case OBX_SETPATH_RSP_EVT:
+ event = BTA_FTC_OBX_SETPATH_RSP_EVT;
+ break;
+ case OBX_ABORT_RSP_EVT:
+ event = BTA_FTC_OBX_ABORT_RSP_EVT;
+ break;
+ case OBX_CLOSE_IND_EVT:
+ event = BTA_FTC_OBX_CLOSE_EVT;
+ break;
+ case OBX_TIMEOUT_EVT:
+ event = BTA_FTC_OBX_TOUT_EVT;
+ break;
+ case OBX_PASSWORD_EVT:
+ event = BTA_FTC_OBX_PASSWORD_EVT;
+ break;
+
+ default:
+ /* case OBX_DISCONNECT_RSP_EVT: Handled when OBX_CLOSE_IND_EVT arrives */
+ if (p_pkt)
+ GKI_freebuf(p_pkt);
+ return;
+
+ }
+
+ /* send event to BTA, if any */
+ if ((p_obx_msg = (tBTA_FTC_OBX_EVT *) GKI_getbuf(size)) != NULL)
+ {
+ APPL_TRACE_DEBUG2("obx_event [%d] event:0x%x", obx_event, event);
+ p_obx_msg->hdr.event = event;
+ p_obx_msg->obx_event = obx_event;
+ p_obx_msg->handle = handle;
+ p_obx_msg->rsp_code = rsp_code;
+ p_obx_msg->param = param;
+ p_obx_msg->p_pkt = p_pkt;
+
+ if (obx_event == OBX_SESSION_INFO_EVT)
+ {
+ p_obx_msg->param.sess.p_sess_info = (UINT8 *)(p_obx_msg + 1);
+ memcpy (p_obx_msg->param.sess.p_sess_info, param.sess.p_sess_info, OBX_SESSION_INFO_SIZE);
+ }
+
+ bta_sys_sendmsg(p_obx_msg);
+ }
+}
+
+
+/******************************************************************************
+**
+** Function bta_ftc_sdp_cback
+**
+** Description This is the SDP callback function used by FTC.
+** This function will be executed by SDP when the service
+** search is completed. If the search is successful, it
+** finds the first record in the database that matches the
+** UUID of the search. Then retrieves the scn from the
+** record.
+**
+** Returns Nothing.
+**
+******************************************************************************/
+static void bta_ftc_sdp_cback(UINT16 status)
+{
+ tBTA_FTC_CB *p_cb = &bta_ftc_cb;
+ tBTA_FTC_SDP_OK_EVT *p_buf;
+ tSDP_DISC_REC *p_rec = NULL;
+ tSDP_PROTOCOL_ELEM pe;
+ UINT8 scn = 0;
+ UINT16 psm = 0;
+ UINT16 version = GOEP_LEGACY_VERSION;
+ BOOLEAN found = FALSE;
+ tSDP_DISC_ATTR *p_attr;
+#if( defined BTA_BI_INCLUDED ) && (BTA_BI_INCLUDED == TRUE)
+ tBIP_FEATURE_FLAGS features = 0;
+#endif
+
+ APPL_TRACE_DEBUG1("bta_ftc_sdp_cback status:%d", status);
+
+ if ( (status == SDP_SUCCESS) || (status == SDP_DB_FULL) )
+ {
+ status = SDP_SUCCESS;
+ /* loop through all records we found */
+ do
+ {
+ /* get next record; if none found, we're done */
+ if ((p_rec = SDP_FindServiceInDb(p_cb->p_db, p_cb->sdp_service,
+ p_rec)) == NULL)
+ break;
+
+ /* this is an optional attribute */
+ SDP_FindProfileVersionInRec (p_rec, p_cb->sdp_service, &version);
+
+ /* get psm from proto desc list alternative; if not found, go to next record */
+ if ((p_attr = SDP_FindAttributeInRec(p_rec,
+ ATTR_ID_OBX_OVR_L2CAP_PSM)) != NULL)
+ {
+ psm = p_attr->attr_value.v.u16;
+ APPL_TRACE_DEBUG1("attr_len_type: x%x", p_attr->attr_len_type);
+ if ((SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == 2) && L2C_IS_VALID_PSM(psm))
+ {
+ found = TRUE;
+ if (version == GOEP_LEGACY_VERSION)
+ {
+ APPL_TRACE_ERROR0("Lacking mandatory attribute/version");
+ version = BTA_FT_ENHANCED_VERSION;
+ }
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ /* get scn from proto desc list; if not found, go to next record */
+ if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe))
+ {
+ if ( p_bta_ft_cfg->p_bi_action && p_cb->sdp_service == UUID_SERVCLASS_IMAGING_RESPONDER)
+ {
+ /* Check if the Push feature is supported */
+#if( defined BTA_BI_INCLUDED ) && (BTA_BI_INCLUDED == TRUE)
+ if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SUPPORTED_FEATURES)) != NULL)
+ {
+ features = p_attr->attr_value.v.u16;
+ APPL_TRACE_DEBUG1("supported BIP features: x%x", features);
+ if (features & BIP_FT_IMG_PUSH_FLAGS)
+ {
+ found = TRUE;
+ }
+ }
+#endif
+ }
+ else
+ {
+ found = TRUE;
+ }
+ scn = (UINT8) pe.params[0];
+
+ /* we've got everything, we're done */
+ break;
+ }
+ else
+ {
+ continue;
+ }
+ }
+ } while (TRUE);
+ }
+
+ APPL_TRACE_DEBUG4("found: %d scn:%d, psm:0x%x version:0x%x",found , scn, psm, version);
+
+ /* send result in event back to BTA */
+ if ((p_buf = (tBTA_FTC_SDP_OK_EVT *) GKI_getbuf(sizeof(tBTA_FTC_SDP_OK_EVT))) != NULL)
+ {
+ p_buf->hdr.event = BTA_FTC_SDP_FAIL_EVT;
+ p_cb->status = BTA_FTC_SERVICE_UNAVL;
+
+ if (status == SDP_SUCCESS)
+ {
+ if (found == TRUE)
+ {
+ p_buf->hdr.event = BTA_FTC_SDP_OK_EVT;
+ p_buf->scn = scn;
+ p_buf->psm = psm;
+ p_buf->version = version;
+ }
+ /* See if OPP service needs to be searched for */
+ else if (p_cb->services & (BTA_OPP_SERVICE_MASK|BTA_BIP_SERVICE_MASK))
+ {
+ p_buf->hdr.event = BTA_FTC_SDP_NEXT_EVT;
+ }
+ }
+
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*****************************************************************************
+** Local FTP Event Processing Functions
+*****************************************************************************/
+static void ftc_reset_cb (tBTA_FTC_CB *p_cb)
+{
+ /* Clean up control block */
+ utl_freebuf((void**)&p_cb->obx.p_pkt);
+ utl_freebuf((void**)(BT_HDR **)&p_cb->p_name);
+ p_cb->obx_oper = FTC_OP_NONE;
+ p_cb->aborting = 0;
+ p_cb->int_abort = FALSE;
+ p_cb->req_pending = FALSE;
+}
+
+
+/*****************************************************************************
+** Debug Functions
+*****************************************************************************/
+#if BTA_FTC_DEBUG == TRUE
+
+/*******************************************************************************
+**
+** Function ftc_obx_evt_code
+**
+** Description
+**
+** Returns void
+**
+*******************************************************************************/
+static char *ftc_obx_evt_code(tOBX_EVENT evt_code)
+{
+ switch (evt_code)
+ {
+ case OBX_CONNECT_RSP_EVT:
+ return "OBX_CONNECT_RSP_EVT";
+ case OBX_DISCONNECT_RSP_EVT:
+ return "OBX_DISCONNECT_RSP_EVT";
+ case OBX_PUT_RSP_EVT:
+ return "OBX_PUT_RSP_EVT";
+ case OBX_GET_RSP_EVT:
+ return "OBX_GET_RSP_EVT";
+ case OBX_SETPATH_RSP_EVT:
+ return "OBX_SETPATH_RSP_EVT";
+ case OBX_ABORT_RSP_EVT:
+ return "OBX_ABORT_RSP_EVT";
+ case OBX_CLOSE_IND_EVT:
+ return "OBX_CLOSE_IND_EVT";
+ case OBX_TIMEOUT_EVT:
+ return "OBX_TIMEOUT_EVT";
+ case OBX_PASSWORD_EVT:
+ return "OBX_PASSWORD_EVT";
+ case OBX_SESSION_RSP_EVT:
+ return "OBX_SESSION_RSP_EVT";
+ case OBX_ACTION_RSP_EVT:
+ return "OBX_ACTION_RSP_EVT";
+ case OBX_SESSION_INFO_EVT:
+ return "OBX_SESSION_INFO_EVT";
+ default:
+ return "unknown OBX event code";
+ }
+}
+#endif /* Debug Functions */
+#endif /* BTA_FT_INCLUDED */
diff --git a/bta/ft/bta_ftc_api.c b/bta/ft/bta_ftc_api.c
new file mode 100644
index 0000000..31722cf
--- /dev/null
+++ b/bta/ft/bta_ftc_api.c
@@ -0,0 +1,796 @@
+/*****************************************************************************
+**
+** Name: bta_ftc_api.c
+**
+** Description: This is the implementation of the API for the file
+** transfer server subsystem of BTA, Widcomm's Bluetooth
+** application layer for mobile phones.
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include "bt_target.h"
+
+#if defined(BTA_FT_INCLUDED) && (BTA_FT_INCLUDED == TRUE)
+
+#include <string.h>
+#include "gki.h"
+#include "bta_fs_api.h"
+#include "bta_ftc_int.h"
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+static const tBTA_SYS_REG bta_ftc_reg =
+{
+ bta_ftc_hdl_event,
+ BTA_FtcDisable
+};
+
+/*******************************************************************************
+**
+** Function BTA_FtcEnable
+**
+** Description Enable the file transfer client. This function must be
+** called before any other functions in the FTC API are called.
+** When the enable operation is complete the callback function
+** will be called with an BTA_FTC_ENABLE_EVT event.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_FtcEnable(tBTA_FTC_CBACK *p_cback, UINT8 app_id)
+{
+ tBTA_FTC_API_ENABLE *p_buf;
+
+ /* register with BTA system manager */
+ GKI_sched_lock();
+ bta_sys_register(BTA_ID_FTC, &bta_ftc_reg);
+ GKI_sched_unlock();
+
+ if ((p_buf = (tBTA_FTC_API_ENABLE *)GKI_getbuf(sizeof(tBTA_FTC_API_ENABLE))) != NULL)
+ {
+ memset(p_buf, 0, sizeof(tBTA_FTC_API_ENABLE));
+
+ p_buf->hdr.event = BTA_FTC_API_ENABLE_EVT;
+ p_buf->p_cback = p_cback;
+ p_buf->app_id = app_id;
+
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_FtcDisable
+**
+** Description Disable the file transfer client. If the client is currently
+** connected to a peer device the connection will be closed.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_FtcDisable(void)
+{
+ BT_HDR *p_buf;
+
+ bta_sys_deregister(BTA_ID_FTC);
+ if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->event = BTA_FTC_API_DISABLE_EVT;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_FtcOpen
+**
+** Description Open a connection to an FTP, PBAP, OPP or BIP server.
+** If parameter services is set to use both all services,
+** the client will attempt to connect to the device using
+** FTP first and then PBAP, OPP, BIP.
+** When the connection is open the callback function
+** will be called with a BTA_FTC_OPEN_EVT. If the connection
+** fails or otherwise is closed the callback function will be
+** called with a BTA_FTC_CLOSE_EVT.
+**
+** If the connection is opened with FTP profile and
+** bta_ft_cfg.auto_file_list is TRUE , the callback
+** function will be called with one or more BTA_FTC_LIST_EVT
+** containing directory list information formatted in XML as
+** described in the IrOBEX Spec, Version 1.2, section 9.1.2.3.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_FtcOpen(BD_ADDR bd_addr, tBTA_SEC sec_mask, tBTA_SERVICE_MASK services,
+ BOOLEAN srm, UINT32 nonce)
+{
+ tBTA_FTC_API_OPEN *p_buf;
+
+ if ((p_buf = (tBTA_FTC_API_OPEN *)GKI_getbuf(sizeof(tBTA_FTC_API_OPEN))) != NULL)
+ {
+ memset(p_buf, 0, sizeof(tBTA_FTC_API_OPEN));
+
+ p_buf->hdr.event = BTA_FTC_API_OPEN_EVT;
+ p_buf->services = services;
+ p_buf->sec_mask = sec_mask;
+ p_buf->srm = srm;
+ p_buf->nonce = nonce;
+ memcpy(p_buf->bd_addr, bd_addr, BD_ADDR_LEN);
+
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_FtcSuspend
+**
+** Description Suspend the current connection to the server.
+** This is allowed only for the sessions created by
+** BTA_FtcConnect with nonce!=0
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_FtcSuspend(void)
+{
+ tBTA_FTC_API_CLOSE *p_buf;
+
+ APPL_TRACE_DEBUG0("BTA_FtcSuspend");
+ if ((p_buf = (tBTA_FTC_API_CLOSE *)GKI_getbuf(sizeof(tBTA_FTC_API_CLOSE))) != NULL)
+ {
+ p_buf->hdr.event = BTA_FTC_API_CLOSE_EVT;
+ p_buf->suspend = TRUE;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_FtcClose
+**
+** Description Close the current connection to the server.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_FtcClose(void)
+{
+ tBTA_FTC_API_CLOSE *p_buf;
+
+ if ((p_buf = (tBTA_FTC_API_CLOSE *)GKI_getbuf(sizeof(tBTA_FTC_API_CLOSE))) != NULL)
+ {
+ p_buf->hdr.event = BTA_FTC_API_CLOSE_EVT;
+ p_buf->suspend = FALSE;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_FtcCopyFile
+**
+** Description Invoke a Copy action on the server.
+** Create a copy of p_src and name it as p_dest
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_FtcCopyFile(const char *p_src, const char *p_dest)
+{
+ tBTA_FTC_API_ACTION *p_buf;
+ UINT16 src_len = (p_src) ? strlen(p_src) : 0;
+ UINT16 dest_len = (p_dest) ? strlen(p_dest) : 0;
+ UINT16 total_len = sizeof(tBTA_FTC_API_ACTION) + src_len + dest_len + 2;
+
+ APPL_TRACE_DEBUG2("BTA_FtcCopyFile src:%s, dest:%s", p_src, p_dest);
+
+ if ((p_buf = (tBTA_FTC_API_ACTION *)GKI_getbuf( total_len)) != NULL)
+ {
+ p_buf->hdr.event = BTA_FTC_API_ACTION_EVT;
+ p_buf->action = BTA_FT_ACT_COPY;
+ p_buf->p_src = (char *)(p_buf + 1);
+ p_buf->p_dest = (char *)(p_buf->p_src + src_len + 1);
+ /* copy the src name */
+ if (p_src)
+ {
+ BCM_STRNCPY_S(p_buf->p_src, src_len+1, p_src, src_len);
+ p_buf->p_src[src_len] = '\0';
+ }
+ else
+ p_buf->p_src[0] = '\0';
+
+ /* copy the dest name */
+ if (p_dest)
+ {
+ BCM_STRNCPY_S(p_buf->p_dest, dest_len+1, p_dest, dest_len);
+ p_buf->p_dest[dest_len] = '\0';
+ }
+ else
+ p_buf->p_dest[0] = '\0';
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_FtcMoveFile
+**
+** Description Invoke a Move action on the server.
+** Move/rename p_src to p_dest
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_FtcMoveFile(const char *p_src, const char *p_dest)
+{
+ tBTA_FTC_API_ACTION *p_buf;
+ UINT16 src_len = (p_src) ? strlen(p_src) : 0;
+ UINT16 dest_len = (p_dest) ? strlen(p_dest) : 0;
+ UINT16 total_len = sizeof(tBTA_FTC_API_ACTION) + src_len + dest_len + 2;
+
+ APPL_TRACE_DEBUG2("BTA_FtcMoveFile src:%s, dest:%s", p_src, p_dest);
+
+ if ((p_buf = (tBTA_FTC_API_ACTION *)GKI_getbuf(total_len)) != NULL)
+ {
+ p_buf->hdr.event = BTA_FTC_API_ACTION_EVT;
+ p_buf->action = BTA_FT_ACT_MOVE;
+ p_buf->p_src = (char *)(p_buf + 1);
+ p_buf->p_dest = (char *)(p_buf->p_src + src_len + 1);
+
+ /* copy the src name */
+ if (p_src)
+ {
+ BCM_STRNCPY_S(p_buf->p_src, src_len+1, p_src, src_len);
+ p_buf->p_src[src_len] = '\0';
+ }
+ else
+ p_buf->p_src[0] = '\0';
+
+ /* copy the dest name */
+ if (p_dest)
+ {
+ BCM_STRNCPY_S(p_buf->p_dest, dest_len+1, p_dest, dest_len);
+ p_buf->p_dest[dest_len] = '\0';
+ }
+ else
+ p_buf->p_dest[0] = '\0';
+
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_FtcSetPermission
+**
+** Description Invoke a SetPermission action on the server.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_FtcSetPermission(const char *p_src, UINT8 user, UINT8 group, UINT8 other)
+{
+ tBTA_FTC_API_ACTION *p_buf;
+ UINT16 src_len = (p_src) ? strlen(p_src) : 0;
+ UINT16 total_len = sizeof(tBTA_FTC_API_ACTION) + src_len + 1;
+
+ APPL_TRACE_DEBUG4("BTA_FtcSetPermission src:%s, user:0x%x, group:0x%x, other:0x%x",
+ p_src, user, group, other);
+
+ if ((p_buf = (tBTA_FTC_API_ACTION *)GKI_getbuf(total_len)) != NULL)
+ {
+ p_buf->hdr.event = BTA_FTC_API_ACTION_EVT;
+ p_buf->action = BTA_FT_ACT_PERMISSION;
+ p_buf->p_src = (char *)(p_buf + 1);
+
+ /* copy the src name */
+ if (p_src)
+ {
+ BCM_STRNCPY_S(p_buf->p_src, src_len+1, p_src, src_len);
+ p_buf->p_src[src_len] = '\0';
+ }
+ else
+ p_buf->p_src[0] = '\0';
+
+ p_buf->permission[0] = user;
+ p_buf->permission[1] = group;
+ p_buf->permission[2] = other;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_FtcPutFile
+**
+** Description Send a file to the connected server.
+** This function can only be used when the client is connected
+** in FTP, OPP and BIP mode.
+**
+** Note: File name is specified with a fully qualified path.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_FtcPutFile(const char *p_name, tBTA_FTC_PARAM *p_param)
+{
+ tBTA_FTC_DATA *p_msg;
+ INT32 name_len = (INT32)((p_bta_fs_cfg->max_path_len + 1 + 3)/4)*4;
+
+ if ((p_msg = (tBTA_FTC_DATA *)GKI_getbuf((UINT16)(sizeof(tBTA_FTC_DATA) +
+ sizeof(tBTA_FTC_PARAM) + name_len))) != NULL)
+ {
+ p_msg->api_put.p_name = (char *)(p_msg + 1);
+
+ if (p_name != NULL)
+ BCM_STRNCPY_S(p_msg->api_put.p_name, name_len, p_name, p_bta_fs_cfg->max_path_len);
+ else
+ p_msg->api_put.p_name[0] = 0;
+
+ if(p_param)
+ {
+ p_msg->api_put.p_param = (tBTA_FTC_PARAM *)(p_msg->api_put.p_name + name_len);
+ memcpy(p_msg->api_put.p_param, p_param, sizeof(tBTA_FTC_PARAM));
+ }
+ else
+ p_msg->api_put.p_param = NULL;
+
+ p_msg->api_put.hdr.event = BTA_FTC_API_PUTFILE_EVT;
+ bta_sys_sendmsg(p_msg);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_FtcGetPhoneBook
+**
+** Description Retrieve a PhoneBook from the peer device and copy it to the
+** local file system.
+**
+** This function can only be used when the client is connected
+** in PBAP mode.
+**
+** Note: local file name is specified with a fully qualified path.
+** Remote file name is absolute path in UTF-8 format.
+** (telecom/pb.vcf or SIM1/telecom/pb.vcf).
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_FtcGetPhoneBook(char *p_local_name, char *p_remote_name,
+ tBTA_FTC_FILTER_MASK filter, tBTA_FTC_FORMAT format,
+ UINT16 max_list_count, UINT16 list_start_offset)
+{
+ tBTA_FTC_DATA *p_msg;
+ tBTA_FTC_API_GET *p_get;
+ tBTA_FTC_GET_PARAM *p_getp;
+ UINT16 remote_name_length = (p_remote_name) ? strlen(p_remote_name) : 0;
+
+ if ((p_msg = (tBTA_FTC_DATA *)GKI_getbuf((UINT16)(sizeof(tBTA_FTC_DATA) +
+ (p_bta_fs_cfg->max_path_len + 1) + remote_name_length + 1))) != NULL)
+ {
+ p_get = &p_msg->api_get;
+ p_get->p_param = (tBTA_FTC_GET_PARAM *)(p_msg + 1);
+ p_getp = p_get->p_param;
+ p_get->p_rem_name = (char *)(p_getp + 1);
+ p_get->p_name = (char *)(p_get->p_rem_name + remote_name_length + 1);
+ p_get->obj_type = BTA_FTC_GET_PB;
+
+ /* copy the local name */
+ if (p_local_name)
+ BCM_STRNCPY_S(p_get->p_name, p_bta_fs_cfg->max_path_len + 1, p_local_name, p_bta_fs_cfg->max_path_len);
+ else
+ p_get->p_name[0] = '\0';
+
+ /* copy remote name */
+ if( p_remote_name)
+ BCM_STRNCPY_S(p_get->p_rem_name, remote_name_length + 1, p_remote_name, remote_name_length);
+ p_get->p_rem_name[remote_name_length] = '\0';
+
+ p_getp->filter = filter;
+ p_getp->format = format;
+ p_getp->list_start_offset = list_start_offset;
+ p_getp->max_list_count = max_list_count;
+
+ p_get->hdr.event = BTA_FTC_API_GETFILE_EVT;
+ bta_sys_sendmsg(p_msg);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_FtcGetCard
+**
+** Description Retrieve a vCard from the peer device and copy it to the
+** local file system.
+**
+** This function can only be used when the client is connected
+** in PBAP mode.
+**
+** Note: local file name is specified with a fully qualified path.
+** Remote file name is relative path in UTF-8 format.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_FtcGetCard(char *p_local_name, char *p_remote_name,
+ tBTA_FTC_FILTER_MASK filter, tBTA_FTC_FORMAT format)
+{
+ tBTA_FTC_DATA *p_msg;
+ tBTA_FTC_API_GET *p_get;
+ tBTA_FTC_GET_PARAM *p_getp;
+ UINT16 remote_name_length = (p_remote_name) ? strlen(p_remote_name) : 0;
+
+ if ((p_msg = (tBTA_FTC_DATA *)GKI_getbuf((UINT16)(sizeof(tBTA_FTC_DATA) +
+ (p_bta_fs_cfg->max_path_len + 1) + remote_name_length + 1))) != NULL)
+ {
+ p_get = &p_msg->api_get;
+ p_get->p_param = (tBTA_FTC_GET_PARAM *)(p_msg + 1);
+ p_getp = p_get->p_param;
+ p_get->p_rem_name = (char *)(p_getp + 1);
+ p_get->p_name = (char *)(p_get->p_rem_name + remote_name_length + 1);
+ p_get->obj_type = BTA_FTC_GET_CARD;
+
+ /* copy the local name */
+ if (p_local_name)
+ {
+ BCM_STRNCPY_S(p_get->p_name, p_bta_fs_cfg->max_path_len + 1, p_local_name, p_bta_fs_cfg->max_path_len);
+ p_get->p_name[p_bta_fs_cfg->max_path_len] = '\0';
+ }
+ else
+ p_get->p_name[0] = '\0';
+
+ /* copy remote name */
+ if( p_remote_name)
+ BCM_STRNCPY_S(p_get->p_rem_name, remote_name_length+1, p_remote_name, remote_name_length);
+ p_get->p_rem_name[remote_name_length] = '\0';
+
+ p_getp->filter = filter;
+ p_getp->format = format;
+
+ p_get->hdr.event = BTA_FTC_API_GETFILE_EVT;
+ bta_sys_sendmsg(p_msg);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_FtcGetFile
+**
+** Description Retrieve a file from the peer device and copy it to the
+** local file system.
+**
+** This function can only be used when the client is connected
+** in FTP mode.
+**
+** Note: local file name is specified with a fully qualified path.
+** Remote file name is specified in UTF-8 format.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_FtcGetFile(char *p_local_name, char *p_remote_name)
+{
+ tBTA_FTC_DATA *p_msg;
+ tBTA_FTC_API_GET *p_get;
+ UINT16 remote_name_length = (p_remote_name) ? strlen(p_remote_name) : 0;
+
+ if ((p_msg = (tBTA_FTC_DATA *)GKI_getbuf((UINT16)(sizeof(tBTA_FTC_DATA) +
+ (p_bta_fs_cfg->max_path_len + 1) + remote_name_length + 1))) != NULL)
+ {
+ p_get = &p_msg->api_get;
+ p_get->obj_type = BTA_FTC_GET_FILE;
+ p_get->p_param = NULL;
+ p_get->p_rem_name = (char *)(p_msg + 1);
+ p_get->p_name = (char *)(p_msg->api_get.p_rem_name + remote_name_length + 1);
+
+ /* copy the local name */
+ if (p_local_name)
+ {
+ BCM_STRNCPY_S(p_get->p_name, p_bta_fs_cfg->max_path_len + 1, p_local_name, p_bta_fs_cfg->max_path_len);
+ p_get->p_name[p_bta_fs_cfg->max_path_len] = '\0';
+ }
+ else
+ p_get->p_name[0] = '\0';
+
+ /* copy remote name */
+ if( p_remote_name)
+ BCM_STRNCPY_S(p_get->p_rem_name, remote_name_length+1, p_remote_name, remote_name_length);
+ p_get->p_rem_name[remote_name_length] = '\0';
+
+
+ p_get->hdr.event = BTA_FTC_API_GETFILE_EVT;
+ bta_sys_sendmsg(p_msg);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_FtcChDir
+**
+** Description Change directory on the peer device.
+**
+** This function can only be used when the client is connected
+** in FTP and PBAP mode.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_FtcChDir(char *p_dir, tBTA_FTC_FLAG flag)
+{
+ tBTA_FTC_DATA *p_msg;
+ tBTA_FTC_API_CHDIR *p_chdir;
+ UINT16 dir_len;
+
+ /* If directory is specified set the length */
+ dir_len = (p_dir && *p_dir != '\0') ? (UINT16)(strlen(p_dir) + 1): 0;
+
+ if ((p_msg = (tBTA_FTC_DATA *)GKI_getbuf((UINT16)(sizeof(tBTA_FTC_DATA) +
+ dir_len))) != NULL)
+ {
+ p_chdir = &p_msg->api_chdir;
+ p_chdir->flag = flag;
+ if (dir_len)
+ {
+ p_chdir->p_dir = (char *)(p_msg + 1);
+ BCM_STRNCPY_S(p_chdir->p_dir, dir_len, p_dir, dir_len);
+ }
+ else /* Setting to root directory OR backing up a directory */
+ p_chdir->p_dir = NULL;
+
+ p_chdir->hdr.event = BTA_FTC_API_CHDIR_EVT;
+ bta_sys_sendmsg(p_msg);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_FtcAuthRsp
+**
+** Description Sends a response to an OBEX authentication challenge to the
+** connected OBEX server. Called in response to an BTA_FTC_AUTH_EVT
+** event.
+**
+** Note: If the "userid_required" is TRUE in the BTA_FTC_AUTH_EVT event,
+** then p_userid is required, otherwise it is optional.
+**
+** p_password must be less than BTA_FTC_MAX_AUTH_KEY_SIZE (16 bytes)
+** p_userid must be less than OBX_MAX_REALM_LEN (defined in target.h)
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_FtcAuthRsp (char *p_password, char *p_userid)
+{
+ tBTA_FTC_API_AUTHRSP *p_auth_rsp;
+
+ if ((p_auth_rsp = (tBTA_FTC_API_AUTHRSP *)GKI_getbuf(sizeof(tBTA_FTC_API_AUTHRSP))) != NULL)
+ {
+ memset(p_auth_rsp, 0, sizeof(tBTA_FTC_API_AUTHRSP));
+
+ p_auth_rsp->hdr.event = BTA_FTC_API_AUTHRSP_EVT;
+
+ if (p_password)
+ {
+ p_auth_rsp->key_len = strlen(p_password);
+ if (p_auth_rsp->key_len > BTA_FTC_MAX_AUTH_KEY_SIZE)
+ p_auth_rsp->key_len = BTA_FTC_MAX_AUTH_KEY_SIZE;
+ memcpy(p_auth_rsp->key, p_password, p_auth_rsp->key_len);
+ }
+
+ if (p_userid)
+ {
+ p_auth_rsp->userid_len = strlen(p_userid);
+ if (p_auth_rsp->userid_len > OBX_MAX_REALM_LEN)
+ p_auth_rsp->userid_len = OBX_MAX_REALM_LEN;
+ memcpy(p_auth_rsp->userid, p_userid, p_auth_rsp->userid_len);
+ }
+
+ bta_sys_sendmsg(p_auth_rsp);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_FtcListCards
+**
+** Description Retrieve a directory listing from the peer device.
+** When the operation is complete the callback function will
+** be called with one or more BTA_FTC_LIST_EVT events
+** containing directory list information formatted as described
+** in the PBAP Spec, Version 0.9, section 3.1.6.
+** This function can only be used when the client is connected
+** to a peer device.
+**
+** This function can only be used when the client is connected
+** in PBAP mode.
+**
+** Parameters p_dir - Name of directory to retrieve listing of.
+**
+** Returns void
+**
+*******************************************************************************/
+
+void BTA_FtcListCards(char *p_dir, tBTA_FTC_ORDER order, char *p_value,
+ tBTA_FTC_ATTR attribute, UINT16 max_list_count,
+ UINT16 list_start_offset)
+{
+ tBTA_FTC_DATA *p_msg;
+ tBTA_FTC_API_LIST *p_list;
+ tBTA_FTC_LST_PARAM *p_param;
+ UINT16 dir_len = (p_dir == NULL) ? 0 : strlen(p_dir) ;
+ UINT16 value_len = (p_value == NULL) ? 0 : strlen(p_value) ;
+
+ if ((p_msg = (tBTA_FTC_DATA *)GKI_getbuf((UINT16)(sizeof(tBTA_FTC_DATA) +
+ sizeof(tBTA_FTC_LST_PARAM) +
+ dir_len + value_len + 2))) != NULL)
+ {
+ p_list = &p_msg->api_list;
+ p_list->p_param = (tBTA_FTC_LST_PARAM *)(p_msg + 1);
+ p_param = p_list->p_param;
+ p_list->p_dir = (char *)(p_param + 1);
+ p_param->order = order;
+ p_param->attribute = attribute;
+ p_param->max_list_count = max_list_count;
+ p_param->list_start_offset = list_start_offset;
+
+ if (dir_len)
+ BCM_STRNCPY_S(p_list->p_dir, dir_len+1, p_dir, dir_len);
+ p_list->p_dir[dir_len] = 0;
+
+ if (value_len)
+ {
+ p_param->p_value = (char *)(p_list->p_dir + dir_len + 1);
+ BCM_STRNCPY_S(p_param->p_value, value_len+1, p_value, value_len);
+ p_param->p_value[value_len] = 0;
+ }
+ else
+ p_param->p_value = NULL;
+
+ p_list->hdr.event = BTA_FTC_API_LISTDIR_EVT;
+ bta_sys_sendmsg(p_msg);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_FtcListDir
+**
+** Description Retrieve a directory listing from the peer device.
+** When the operation is complete the callback function will
+** be called with one or more BTA_FTC_LIST_EVT events
+** containing directory list information formatted as described
+** in the IrOBEX Spec, Version 1.2, section 9.1.2.3.
+**
+** This function can only be used when the client is connected
+** in FTP mode.
+**
+** Parameters p_dir - Name of directory to retrieve listing of. If NULL,
+** the current working directory is retrieved.
+**
+** Returns void
+**
+*******************************************************************************/
+
+void BTA_FtcListDir(char *p_dir)
+{
+ tBTA_FTC_DATA *p_msg;
+ tBTA_FTC_API_LIST *p_list;
+ UINT16 dir_len = (p_dir == NULL) ? 0 : strlen(p_dir) ;
+
+ if ((p_msg = (tBTA_FTC_DATA *)GKI_getbuf((UINT16)(sizeof(tBTA_FTC_DATA) +
+ dir_len + 1))) != NULL)
+ {
+ p_list = &p_msg->api_list;
+ p_list->p_dir = (char *)(p_msg + 1);
+ p_list->p_param = NULL;
+
+ if (dir_len)
+ BCM_STRNCPY_S(p_list->p_dir, dir_len+1, p_dir, dir_len);
+
+ p_list->p_dir[dir_len] = 0;
+
+ p_list->hdr.event = BTA_FTC_API_LISTDIR_EVT;
+ bta_sys_sendmsg(p_msg);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_FtcMkDir
+**
+** Description Create a directory on the peer device. When the operation is
+** complete the status is returned with the BTA_FTC_MKDIR_EVT
+** event.
+**
+** This function can only be used when the client is connected
+** in FTP mode.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_FtcMkDir(char *p_dir)
+{
+ tBTA_FTC_API_MKDIR *p_mkdir;
+ UINT16 len = (p_dir == NULL) ? 0: strlen(p_dir);
+
+ if ((p_mkdir = (tBTA_FTC_API_MKDIR *)GKI_getbuf((UINT16)(sizeof(tBTA_FTC_API_MKDIR) +
+ len + 1))) != NULL)
+ {
+ p_mkdir->p_dir = (char *)(p_mkdir + 1);
+
+ if (len > 0)
+ BCM_STRNCPY_S(p_mkdir->p_dir, len+1, p_dir, len);
+
+ p_mkdir->p_dir[len] = 0;
+
+ p_mkdir->hdr.event = BTA_FTC_API_MKDIR_EVT;
+ bta_sys_sendmsg(p_mkdir);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_FtcRemove
+**
+** Description Remove a file or directory on the peer device. When the
+** operation is complete the status is returned with the
+** BTA_FTC_REMOVE_EVT event.
+**
+** This function can only be used when the client is connected
+** in FTP mode.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_FtcRemove(char *p_name)
+
+{
+ tBTA_FTC_DATA *p_msg;
+ tBTA_FTC_API_REMOVE *p_remove;
+ UINT16 len = (p_name == NULL) ? 0 :strlen(p_name);
+
+ if ((p_msg = (tBTA_FTC_DATA *)GKI_getbuf((UINT16)(sizeof(tBTA_FTC_DATA) +
+ len + 1))) != NULL)
+ {
+ p_remove = &p_msg->api_remove;
+ p_remove->p_name = (char *)(p_msg +1);
+ if(len)
+ BCM_STRNCPY_S(p_remove->p_name, len+1, p_name, len);
+
+ p_remove->p_name[len] = 0;
+
+ p_remove->hdr.event = BTA_FTC_API_REMOVE_EVT;
+ bta_sys_sendmsg(p_msg);
+ }
+}
+
+
+
+
+/*******************************************************************************
+**
+** Function BTA_FtcAbort
+**
+** Description Aborts any active Put or Get file operation.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_FtcAbort(void)
+{
+ BT_HDR *p_buf;
+
+ if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->event = BTA_FTC_API_ABORT_EVT;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+#endif /* BTA_FT_INCLUDED */
diff --git a/bta/ft/bta_ftc_int.h b/bta/ft/bta_ftc_int.h
new file mode 100644
index 0000000..4279aa6
--- /dev/null
+++ b/bta/ft/bta_ftc_int.h
@@ -0,0 +1,504 @@
+/*****************************************************************************
+**
+** Name: bta_ftc_int.h
+**
+** Description: This is the private file for the file transfer
+** client (FTC).
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_FTC_INT_H
+#define BTA_FTC_INT_H
+
+#include "bt_target.h"
+#include "bta_sys.h"
+#include "obx_api.h"
+#include "bta_ft_api.h"
+#include "bta_fs_co.h"
+#include "bta_fs_ci.h"
+#if( defined BTA_BI_INCLUDED ) && (BTA_BI_INCLUDED == TRUE)
+#include "bta_bi_api.h"
+#endif
+
+/*****************************************************************************
+** Constants and data types
+*****************************************************************************/
+
+#define BTA_FTC_PB_ACCESS_TARGET_UUID "\x79\x61\x35\xF0\xF0\xC5\x11\xD8\x09\x66\x08\x00\x20\x0C\x9A\x66"
+#define BTA_FTC_FOLDER_BROWSING_TARGET_UUID "\xF9\xEC\x7B\xC4\x95\x3C\x11\xD2\x98\x4E\x52\x54\x00\xDC\x9E\x09"
+#define BTA_FTC_UUID_LENGTH 16
+#define BTA_FTC_MAX_AUTH_KEY_SIZE 16 /* Must not be greater than OBX_MAX_AUTH_KEY_SIZE */
+#define BTA_FTC_DEFAULT_VERSION 0x0100 /* for PBAP PCE */
+
+#define BTA_FTC_FOLDER_LISTING_TYPE "x-obex/folder-listing"
+
+#define BTA_FTC_PULL_PB_TYPE "x-bt/phonebook"
+#define BTA_FTC_PULL_VCARD_LISTING_TYPE "x-bt/vcard-listing"
+#define BTA_FTC_PULL_VCARD_ENTRY_TYPE "x-bt/vcard"
+
+/* FTC Active ftp obex operation (Valid in connected state) */
+#define FTC_OP_NONE 0
+#define FTC_OP_GET_FILE 1
+#define FTC_OP_PUT_FILE 2
+#define FTC_OP_DELETE 3 /* Folder or File */
+#define FTC_OP_GET_LIST 4
+#define FTC_OP_MKDIR 5
+#define FTC_OP_CHDIR 6
+/* note: the following 3 OPs need to be continuous and the order can not change */
+#define FTC_OP_COPY 7 /* Copy object */
+#define FTC_OP_MOVE 8 /* Move/rename object */
+#define FTC_OP_PERMISSION 9 /* Set object permission */
+#define FTC_OP_RESUME 0x80 /* to mark the operation to resume */
+
+enum
+{
+ BTA_FTC_GET_FILE, /* get file */
+ BTA_FTC_GET_CARD, /* PBAP PullvCardEntry */
+ BTA_FTC_GET_PB /* PBAP PullPhoneBook */
+};
+typedef UINT8 tBTA_FTC_TYPE;
+
+/* Response Timer Operations */
+#define FTC_TIMER_OP_STOP 0
+#define FTC_TIMER_OP_ABORT 1
+#define FTC_TIMER_OP_SUSPEND 2
+
+/* File abort mask states */
+/* Abort must receive cout and response before abort completed */
+#define FTC_ABORT_REQ_NOT_SENT 0x1
+#define FTC_ABORT_REQ_SENT 0x2
+#define FTC_ABORT_RSP_RCVD 0x4
+#define FTC_ABORT_COUT_DONE 0x8
+
+#define FTC_ABORT_COMPLETED (FTC_ABORT_REQ_SENT | FTC_ABORT_RSP_RCVD | FTC_ABORT_COUT_DONE)
+
+/* TODO remove: Reliable session suspend mask states */
+/* suspend must receive cout and response before suspend completed
+#define FTC_SUSPEND_REQ_NOT_SENT 0x10 */
+
+/* state machine events */
+enum
+{
+ /* these events are handled by the state machine */
+ BTA_FTC_API_DISABLE_EVT = BTA_SYS_EVT_START(BTA_ID_FTC),
+
+ BTA_FTC_API_OPEN_EVT, /* Open a connection request */
+ BTA_FTC_API_CLOSE_EVT, /* Close an open connection request */
+ BTA_FTC_API_PUTFILE_EVT, /* Put File request */
+ BTA_FTC_API_GETFILE_EVT, /* Get File request */
+ BTA_FTC_API_LISTDIR_EVT, /* List Directory request */
+ BTA_FTC_API_CHDIR_EVT, /* Change Directory request */
+ BTA_FTC_API_MKDIR_EVT, /* make Directory request */
+ BTA_FTC_API_REMOVE_EVT, /* Remove Directory request */
+ BTA_FTC_API_AUTHRSP_EVT, /* Response to password request */
+ BTA_FTC_API_ABORT_EVT, /* Abort request */
+ BTA_FTC_API_ACTION_EVT, /* Action request */
+ BTA_FTC_OBX_ACTION_RSP_EVT, /* Copy/Move File or Set Permission */
+ BTA_FTC_CI_SESSION_EVT, /* Call-in response to session requests */
+ BTA_FTC_SDP_OK_EVT, /* Service search was successful */
+ BTA_FTC_SDP_FAIL_EVT, /* Service search failed */
+ BTA_FTC_SDP_NEXT_EVT, /* Try another service search (OPP) */
+ BTA_FTC_CI_WRITE_EVT, /* Call-in response to Write request */
+ BTA_FTC_CI_READ_EVT, /* Call-in response to Read request */
+ BTA_FTC_CI_OPEN_EVT, /* Call-in response to File Open request */
+ BTA_FTC_OBX_CONN_RSP_EVT, /* OBX Channel Connect Request */
+ BTA_FTC_OBX_ABORT_RSP_EVT, /* OBX_operation aborted */
+ BTA_FTC_OBX_TOUT_EVT, /* OBX Operation Timeout */
+ BTA_FTC_OBX_PASSWORD_EVT, /* OBX password requested */
+ BTA_FTC_OBX_CLOSE_EVT, /* OBX Channel Disconnected (Link Lost) */
+ BTA_FTC_OBX_PUT_RSP_EVT, /* Write file data or delete */
+ BTA_FTC_OBX_GET_RSP_EVT, /* Read file data or folder listing */
+ BTA_FTC_OBX_SETPATH_RSP_EVT, /* Make or Change Directory */
+ BTA_FTC_OBX_CMPL_EVT, /* operation has completed */
+ BTA_FTC_CLOSE_CMPL_EVT, /* Finish the closing of the channel */
+ BTA_FTC_DISABLE_CMPL_EVT, /* Finished disabling system */
+ BTA_FTC_RSP_TOUT_EVT, /* Timeout waiting for response from server */
+
+ /* these events are handled outside the state machine */
+ BTA_FTC_API_ENABLE_EVT
+};
+
+
+/* state machine states */
+enum
+{
+ BTA_FTC_IDLE_ST = 0, /* Idle */
+ BTA_FTC_W4_CONN_ST, /* Waiting for an Obex connect response */
+ BTA_FTC_CONN_ST, /* Connected - FTP Session is active */
+ BTA_FTC_SUSPENDING_ST, /* suspend is in progress */
+ BTA_FTC_CLOSING_ST /* Closing is in progress */
+};
+typedef UINT16 tBTA_FTC_INT_EVT;
+
+typedef UINT8 tBTA_FTC_STATE;
+
+/* Application Parameters Header
+Tag IDs used in the Application Parameters header:
+*/
+ /* Tag ID Length Possible Values */
+#define BTA_FTC_APH_ORDER 0x01 /* Order 1 bytes 0x0 to 0x2 */
+#define BTA_FTC_APH_SEARCH_VALUE 0x02 /* SearchValue variable text */
+#define BTA_FTC_APH_SEARCH_ATTR 0x03 /* SearchAttribute 1 byte 0x0 to 0x2 */
+#define BTA_FTC_APH_MAX_LIST_COUNT 0x04 /* MaxListCount 2 bytes 0x0000 to 0xFFFF */
+#define BTA_FTC_APH_LIST_STOFF 0x05 /* ListStartOffset 2 bytes 0x0000 to 0xFFFF */
+#define BTA_FTC_APH_FILTER 0x06 /* Filter 4 bytes 0x00000000 to 0xFFFFFFFF */
+#define BTA_FTC_APH_FORMAT 0x07 /* Format 1 byte 0x00(2.1), 0x01(3.0) */
+#define BTA_FTC_APH_PB_SIZE 0x08 /* PhoneBookSize 2 byte 0x0000 to 0xFFFF */
+#define BTA_FTC_APH_NEW_MISSED_CALL 0x09 /* NewMissedCall 1 bytes 0x00 to 0xFF */
+#define BTA_FTC_APH_MAX_TAG BTA_FTC_APH_NEW_MISSED_CALL
+
+/* data type for BTA_FTC_API_ENABLE_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_FTC_CBACK *p_cback;
+ UINT8 app_id;
+} tBTA_FTC_API_ENABLE;
+
+/* data type for BTA_FTC_API_OPEN_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_SERVICE_MASK services; /* FTP and/or OPP */
+ BD_ADDR bd_addr;
+ UINT8 sec_mask;
+ BOOLEAN srm;
+ UINT32 nonce;
+} tBTA_FTC_API_OPEN;
+
+/* data type for BTA_FTC_API_CLOSE_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ BOOLEAN suspend;
+} tBTA_FTC_API_CLOSE;
+
+/* data type for BTA_FTC_API_ACTION_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_FTC_ACT action;
+ char *p_src; /* UTF-8 name from listing */
+ char *p_dest; /* UTF-8 name */
+ UINT8 permission[3];
+} tBTA_FTC_API_ACTION;
+
+/* data type for BTA_FTC_API_PUTFILE_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ char *p_name;
+ tBTA_FTC_PARAM *p_param;
+} tBTA_FTC_API_PUT;
+
+typedef struct
+{
+ tBTA_FTC_FILTER_MASK filter;
+ UINT16 max_list_count;
+ UINT16 list_start_offset;
+ tBTA_FTC_FORMAT format;
+} tBTA_FTC_GET_PARAM;
+
+/* data type for BTA_FTC_API_GETFILE_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ char *p_rem_name; /* UTF-8 name from listing */
+ char *p_name;
+ tBTA_FTC_GET_PARAM *p_param;
+ UINT8 obj_type;
+} tBTA_FTC_API_GET;
+
+/* data type for BTA_FTC_API_CHDIR_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ char *p_dir; /* UTF-8 name from listing */
+ tBTA_FTC_FLAG flag;
+} tBTA_FTC_API_CHDIR;
+
+typedef struct
+{
+ char *p_value;
+ UINT16 max_list_count;
+ UINT16 list_start_offset;
+ tBTA_FTC_ORDER order;
+ tBTA_FTC_ATTR attribute;
+} tBTA_FTC_LST_PARAM;
+
+/* data type for BTA_FTC_API_LISTDIR_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ char *p_dir; /* UTF-8 name from listing */
+ tBTA_FTC_LST_PARAM *p_param;
+} tBTA_FTC_API_LIST;
+
+/* data type for BTA_FTC_API_MKDIR_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ char *p_dir; /* UTF-8 name directory */
+} tBTA_FTC_API_MKDIR;
+
+/* data type for BTA_FTC_API_REMOVE_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ char *p_name; /* UTF-8 name of file or directory */
+} tBTA_FTC_API_REMOVE;
+
+
+/* data type for BTA_FTC_API_AUTHRSP_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ UINT8 key [BTA_FTC_MAX_AUTH_KEY_SIZE]; /* The authentication key.*/
+ UINT8 key_len;
+ UINT8 userid [OBX_MAX_REALM_LEN]; /* The authentication user id.*/
+ UINT8 userid_len;
+} tBTA_FTC_API_AUTHRSP;
+
+/* data type for BTA_FTC_SDP_OK_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ UINT8 scn;
+ UINT16 psm;
+ UINT16 version;
+} tBTA_FTC_SDP_OK_EVT;
+
+/* data type for all obex events
+ hdr.event contains the FTC event
+*/
+typedef struct
+{
+ BT_HDR hdr;
+ tOBX_HANDLE handle;
+ tOBX_EVT_PARAM param;
+ BT_HDR *p_pkt;
+ tOBX_EVENT obx_event;
+ UINT8 rsp_code;
+} tBTA_FTC_OBX_EVT;
+
+/* union of all event data types */
+typedef union
+{
+ BT_HDR hdr;
+ tBTA_FTC_API_ENABLE api_enable;
+ tBTA_FTC_API_OPEN api_open;
+ tBTA_FTC_API_CLOSE api_close;
+ tBTA_FTC_API_PUT api_put;
+ tBTA_FTC_API_GET api_get;
+ tBTA_FTC_API_CHDIR api_chdir;
+ tBTA_FTC_API_MKDIR api_mkdir;
+ tBTA_FTC_API_REMOVE api_remove;
+ tBTA_FTC_API_AUTHRSP auth_rsp;
+ tBTA_FTC_API_LIST api_list;
+ tBTA_FTC_API_ACTION api_action;
+ tBTA_FTC_SDP_OK_EVT sdp_ok;
+ tBTA_FTC_OBX_EVT obx_evt;
+ tBTA_FS_CI_OPEN_EVT open_evt;
+ tBTA_FS_CI_RESUME_EVT resume_evt;
+ tBTA_FS_CI_READ_EVT read_evt;
+ tBTA_FS_CI_WRITE_EVT write_evt;
+} tBTA_FTC_DATA;
+
+
+/* OBX Response Packet Structure - Holds current command/response packet info */
+typedef struct
+{
+ BT_HDR *p_pkt; /* (Get/Put) Holds the current OBX header for Put or Get */
+ UINT8 *p_start; /* (Get/Put) Start of the Body of the packet */
+ UINT16 offset; /* (Get/Put) Contains the current offset into the Body (p_start) */
+ UINT16 bytes_left; /* (Get/Put) Holds bytes available left in Obx packet */
+ BOOLEAN final_pkt; /* (Get) Holds the final bit of the Put packet */
+} tBTA_FTC_OBX_PKT;
+
+/* Power management state for FTC */
+#define BTA_FTC_PM_BUSY 0
+#define BTA_FTC_PM_IDLE 1
+
+
+/* FTC control block */
+typedef struct
+{
+ tBTA_FTC_CBACK *p_cback; /* pointer to application callback function */
+ char *p_name; /* Holds the local file name */
+ tSDP_DISCOVERY_DB *p_db; /* pointer to discovery database */
+ UINT32 sdp_handle; /* SDP record handle for PCE */
+ tBTA_FTC_OBX_PKT obx; /* Holds the current OBX packet information */
+ TIMER_LIST_ENT rsp_timer; /* response timer */
+ tBTA_SERVICE_MASK services; /* FTP and/or OPP and/or BIP */
+ int fd; /* File Descriptor of opened file */
+ UINT32 file_size; /* (Put/Get) length of file */
+#if( defined BTA_BI_INCLUDED ) && (BTA_BI_INCLUDED == TRUE)
+ tBIP_IMAGING_CAPS *p_caps; /* BIP imaging capabilities */
+ tBIP_IMG_HDL_STR img_hdl; /* The image’s handle for when responder requests thumbnail */
+#endif
+ UINT8 *p_sess_info;
+ UINT16 peer_mtu;
+ UINT16 sdp_service;
+ BD_ADDR bd_addr;
+ tOBX_HANDLE obx_handle;
+ UINT8 sec_mask;
+ tBTA_FTC_STATE state; /* state machine state */
+ UINT8 obx_oper; /* current active OBX operation PUT FILE or GET FILE */
+ UINT8 timer_oper; /* current active response timer action (abort or close) */
+ UINT8 app_id;
+ tBTA_FTC_TYPE obj_type; /* type of get op */
+ BOOLEAN first_req_pkt; /* TRUE if retrieving the first packet of GET/PUT file */
+ BOOLEAN cout_active; /* TRUE if call-out is currently active */
+ BOOLEAN disabling; /* TRUE if client is in process of disabling */
+ UINT8 aborting; /* Non-zero if client is in process of aborting */
+ BOOLEAN int_abort; /* TRUE if internal abort issued (Not API inititated) */
+ BOOLEAN is_enabled; /* TRUE if client is enabled */
+ BOOLEAN req_pending; /* TRUE when waiting for an obex response */
+ BOOLEAN sdp_pending; /* TRUE when waiting for SDP to complete */
+#if( defined BTA_BI_INCLUDED ) && (BTA_BI_INCLUDED == TRUE)
+ UINT8 bic_handle;
+#endif
+ UINT8 scn;
+ UINT16 version;
+
+ /* OBEX 1.5 */
+ UINT16 psm;
+ UINT32 nonce;
+ BOOLEAN srm;
+ BOOLEAN suspending; /* TRUE when suspending session */
+
+ tBTA_FTC_STATUS status;
+ UINT8 pm_state;
+} tBTA_FTC_CB;
+
+/* type for action functions */
+typedef void (*tBTA_FTC_ACTION)(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data);
+
+/******************************************************************************
+** Configuration Definitions
+*******************************************************************************/
+typedef const tBTA_FTC_ACTION (*tBTA_FTC_BI_TBL);
+
+/* Configuration structure */
+typedef struct
+{
+ tBTA_FTC_BI_TBL p_bi_action; /* BI related action func used in FTC */
+ UINT8 realm_charset; /* Server only */
+ BOOLEAN userid_req; /* TRUE if user id is required during obex authentication (Server only) */
+ BOOLEAN auto_file_list; /* TRUE if automatic get the file listing from sever on OBEX connect response */
+ UINT8 pce_features; /* PBAP PCE supported features. If 0, PCE is not supported */
+ char *pce_name; /* service name for PBAP PCE SDP record */
+ INT32 abort_tout; /* Timeout in milliseconds to wait for abort OBEX response (client only) */
+ INT32 stop_tout; /* Timeout in milliseconds to wait for close OBEX response (client only) */
+ INT32 suspend_tout; /* Timeout in milliseconds to wait for suspend OBEX response (client only) */
+ UINT32 nonce; /* non-0 to allow reliable session (Server Only) */
+ UINT8 max_suspend; /* the maximum number of suspended session (Server Only) */
+ BOOLEAN over_l2cap; /* TRUE to use Obex Over L2CAP (Server Only) */
+ BOOLEAN srm; /* TRUE to engage Single Response Mode (Server Only) */
+
+} tBTA_FT_CFG;
+
+enum
+{
+ BTA_FTC_BI_REGISTER_IDX = 0,
+ BTA_FTC_BI_DEREGISTER_IDX,
+ BTA_FTC_BI_AUTHRSP_IDX,
+ BTA_FTC_BI_FREEXML_IDX,
+ BTA_FTC_BI_PUT_IDX,
+ BTA_FTC_BI_ABORT_IDX
+};
+
+extern const tBTA_FTC_ACTION bta_ftc_bi_action[];
+
+/*****************************************************************************
+** Global data
+*****************************************************************************/
+
+/* FTC control block */
+#if BTA_DYNAMIC_MEMORY == FALSE
+extern tBTA_FTC_CB bta_ftc_cb;
+#else
+extern tBTA_FTC_CB *bta_ftc_cb_ptr;
+#define bta_ftc_cb (*bta_ftc_cb_ptr)
+#endif
+
+/* FT configuration constants */
+extern tBTA_FT_CFG *p_bta_ft_cfg;
+
+/*****************************************************************************
+** Function prototypes
+*****************************************************************************/
+
+extern BOOLEAN bta_ftc_hdl_event(BT_HDR *p_msg);
+extern void bta_ftc_sm_execute(tBTA_FTC_CB *p_cb, UINT16 event,
+ tBTA_FTC_DATA *p_data);
+extern void bta_ftc_obx_cback (tOBX_HANDLE handle, tOBX_EVENT event,
+ UINT8 rsp_code, tOBX_EVT_PARAM param,
+ BT_HDR *p_pkt);
+
+extern void bta_ftc_init_open(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data);
+extern void bta_ftc_init_close(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data);
+extern void bta_ftc_init_putfile(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data);
+extern void bta_ftc_init_getfile(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data);
+extern void bta_ftc_chdir(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data);
+extern void bta_ftc_send_authrsp(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data);
+extern void bta_ftc_abort(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data);
+extern void bta_ftc_api_action(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data);
+extern void bta_ftc_obx_action_rsp(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data);
+extern void bta_ftc_obx_get_srm_rsp(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data);
+extern void bta_ftc_ci_write_srm(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data);
+extern void bta_ftc_ci_write(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data);
+extern void bta_ftc_ci_read(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data);
+extern void bta_ftc_ci_open(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data);
+extern void bta_ftc_ci_resume(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data);
+extern void bta_ftc_obx_conn_rsp(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data);
+extern void bta_ftc_obx_sess_rsp(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data);
+extern void bta_ftc_suspended(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data);
+extern void bta_ftc_obx_abort_rsp(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data);
+extern void bta_ftc_obx_password(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data);
+extern void bta_ftc_obx_timeout(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data);
+extern void bta_ftc_obx_put_rsp(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data);
+extern void bta_ftc_obx_get_rsp(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data);
+extern void bta_ftc_obx_setpath_rsp(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data);
+extern void bta_ftc_initialize(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data);
+extern void bta_ftc_trans_cmpl(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data);
+extern void bta_ftc_stop_client(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data);
+extern void bta_ftc_start_client(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data);
+extern void bta_ftc_free_db(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data);
+extern void bta_ftc_ignore_obx(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data);
+extern void bta_ftc_find_service(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data);
+extern void bta_ftc_close(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data);
+extern void bta_ftc_open_fail(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data);
+extern void bta_ftc_close_complete(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data);
+extern void bta_ftc_set_disable(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data);
+extern void bta_ftc_rsp_timeout(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data);
+extern void bta_ftc_bic_put(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data);
+extern void bta_ftc_bic_abort(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data);
+
+/* BI related action function used in FTC */
+extern void bta_ftc_bic_register(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data);
+extern void bta_ftc_bic_deregister(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data);
+extern void bta_ftc_bic_authrsp(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data);
+extern void bta_ftc_bic_freexml(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data);
+extern void bta_ftc_bic_putact(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data);
+extern void bta_ftc_bic_abortact(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data);
+
+
+extern void bta_ftc_listdir(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data);
+extern void bta_ftc_remove(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data);
+extern void bta_ftc_mkdir(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data);
+
+/* miscellaneous functions */
+extern UINT8 bta_ftc_send_get_req(tBTA_FTC_CB *p_cb);
+extern void bta_ftc_proc_get_rsp(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data);
+extern UINT8 bta_ftc_cont_put_file(tBTA_FTC_CB *p_cb, BOOLEAN first_pkt);
+extern void bta_ftc_proc_list_data(tBTA_FTC_CB *p_cb, tBTA_FTC_OBX_EVT *p_evt);
+extern void bta_ftc_get_listing(tBTA_FTC_CB *p_cb, char *p_name, tBTA_FTC_LST_PARAM *p_param);
+extern void bta_ftc_listing_err(BT_HDR **p_pkt, tBTA_FTC_STATUS status);
+
+
+extern tBTA_FTC_STATUS bta_ftc_convert_obx_to_ftc_status(tOBX_STATUS obx_status);
+
+#endif /* BTA_FTC_INT_H */
diff --git a/bta/ft/bta_ftc_main.c b/bta/ft/bta_ftc_main.c
new file mode 100644
index 0000000..8148703
--- /dev/null
+++ b/bta/ft/bta_ftc_main.c
@@ -0,0 +1,689 @@
+/*****************************************************************************
+**
+** Name: bta_ftc_main.c
+**
+** Description: This file contains the file transfer client main functions
+** and state machine.
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include <string.h>
+
+#include "bt_target.h"
+
+#if defined(BTA_FT_INCLUDED) && (BTA_FT_INCLUDED == TRUE)
+
+#include "bta_ftc_int.h"
+#include "gki.h"
+#include "obx_api.h"
+
+
+/*****************************************************************************
+** Constants and types
+*****************************************************************************/
+
+
+/* state machine action enumeration list */
+enum
+{
+ BTA_FTC_INIT_OPEN,
+ BTA_FTC_START_CLIENT,
+ BTA_FTC_STOP_CLIENT,
+ BTA_FTC_INIT_GETFILE,
+ BTA_FTC_INIT_PUTFILE,
+ BTA_FTC_LISTDIR,
+ BTA_FTC_CHDIR,
+ BTA_FTC_MKDIR,
+ BTA_FTC_REMOVE,
+ BTA_FTC_SEND_AUTHRSP,
+ BTA_FTC_CI_WRITE,
+ BTA_FTC_CI_READ,
+ BTA_FTC_CI_OPEN,
+ BTA_FTC_CI_RESUME,
+ BTA_FTC_OBX_SESS_RSP,
+ BTA_FTC_OBX_GET_SRM_RSP,
+ BTA_FTC_CI_WRITE_SRM,
+ BTA_FTC_SUSPENDED,
+ BTA_FTC_OBX_CONN_RSP,
+ BTA_FTC_CLOSE,
+ BTA_FTC_OPEN_FAIL,
+ BTA_FTC_OBX_ABORT_RSP,
+ BTA_FTC_OBX_PASSWORD,
+ BTA_FTC_OBX_TIMEOUT,
+ BTA_FTC_OBX_PUT_RSP,
+ BTA_FTC_OBX_GET_RSP,
+ BTA_FTC_OBX_SETPATH_RSP,
+ BTA_FTC_TRANS_CMPL,
+ BTA_FTC_FREE_DB,
+ BTA_FTC_IGNORE_OBX,
+ BTA_FTC_FIND_SERVICE,
+ BTA_FTC_INITIALIZE,
+ BTA_FTC_CLOSE_COMPLETE,
+ BTA_FTC_BIC_PUT,
+ BTA_FTC_BIC_ABORT,
+ BTA_FTC_SET_DISABLE,
+ BTA_FTC_ABORT,
+ BTA_FTC_API_ACTION,
+ BTA_FTC_OBX_ACTION_RSP,
+ BTA_FTC_RSP_TIMEOUT,
+ BTA_FTC_IGNORE
+};
+
+/* action function list */
+const tBTA_FTC_ACTION bta_ftc_action[] =
+{
+ bta_ftc_init_open,
+ bta_ftc_start_client,
+ bta_ftc_stop_client,
+ bta_ftc_init_getfile,
+ bta_ftc_init_putfile,
+ bta_ftc_listdir,
+ bta_ftc_chdir,
+ bta_ftc_mkdir,
+ bta_ftc_remove,
+ bta_ftc_send_authrsp,
+ bta_ftc_ci_write,
+ bta_ftc_ci_read,
+ bta_ftc_ci_open,
+ bta_ftc_ci_resume,
+ bta_ftc_obx_sess_rsp,
+ bta_ftc_obx_get_srm_rsp,
+ bta_ftc_ci_write_srm,
+ bta_ftc_suspended,
+ bta_ftc_obx_conn_rsp,
+ bta_ftc_close,
+ bta_ftc_open_fail,
+ bta_ftc_obx_abort_rsp,
+ bta_ftc_obx_password,
+ bta_ftc_obx_timeout,
+ bta_ftc_obx_put_rsp,
+ bta_ftc_obx_get_rsp,
+ bta_ftc_obx_setpath_rsp,
+ bta_ftc_trans_cmpl,
+ bta_ftc_free_db,
+ bta_ftc_ignore_obx,
+ bta_ftc_find_service,
+ bta_ftc_initialize,
+ bta_ftc_close_complete,
+ bta_ftc_bic_put,
+ bta_ftc_bic_abort,
+ bta_ftc_set_disable,
+ bta_ftc_abort,
+ bta_ftc_api_action,
+ bta_ftc_obx_action_rsp,
+ bta_ftc_rsp_timeout
+};
+
+
+/* state table information */
+#define BTA_FTC_ACTIONS 2 /* number of actions */
+#define BTA_FTC_NEXT_STATE 2 /* position of next state */
+#define BTA_FTC_NUM_COLS 3 /* number of columns in state tables */
+
+/* state table for idle state */
+static const UINT8 bta_ftc_st_idle[][BTA_FTC_NUM_COLS] =
+{
+/* Event Action 1 Action 2 Next state */
+/* BTA_FTC_API_DISABLE_EVT */ {BTA_FTC_SET_DISABLE, BTA_FTC_INITIALIZE, BTA_FTC_IDLE_ST},
+/* BTA_FTC_API_OPEN_EVT */ {BTA_FTC_INIT_OPEN, BTA_FTC_FIND_SERVICE, BTA_FTC_W4_CONN_ST},
+/* BTA_FTC_API_CLOSE_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST},
+/* BTA_FTC_API_PUTFILE_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST},
+/* BTA_FTC_API_GETFILE_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST},
+/* BTA_FTC_API_LISTDIR_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST},
+/* BTA_FTC_API_CHDIR_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST},
+/* BTA_FTC_API_MKDIR_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST},
+/* BTA_FTC_API_REMOVE_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST},
+/* BTA_FTC_API_AUTHRSP_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST},
+/* BTA_FTC_API_ABORT_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST},
+/* BTA_FTC_API_ACTION_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST},
+/* BTA_FTC_OBX_ACTION_RSP_EVT */ {BTA_FTC_IGNORE_OBX, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST},
+/* BTA_FTC_CI_SESSION_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST},
+/* BTA_FTC_SDP_OK_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST},
+/* BTA_FTC_SDP_FAIL_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST},
+/* BTA_FTC_SDP_NEXT_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST},
+/* BTA_FTC_CI_WRITE_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST},
+/* BTA_FTC_CI_READ_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST},
+/* BTA_FTC_CI_OPEN_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST},
+/* BTA_FTC_OBX_CONN_RSP_EVT */ {BTA_FTC_IGNORE_OBX, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST},
+/* BTA_FTC_OBX_ABORT_RSP_EVT */ {BTA_FTC_IGNORE_OBX, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST},
+/* BTA_FTC_OBX_TOUT_EVT */ {BTA_FTC_IGNORE_OBX, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST},
+/* BTA_FTC_OBX_PASSWORD_EVT */ {BTA_FTC_IGNORE_OBX, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST},
+/* BTA_FTC_OBX_CLOSE_EVT */ {BTA_FTC_IGNORE_OBX, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST},
+/* BTA_FTC_OBX_PUT_RSP_EVT */ {BTA_FTC_IGNORE_OBX, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST},
+/* BTA_FTC_OBX_GET_RSP_EVT */ {BTA_FTC_IGNORE_OBX, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST},
+/* BTA_FTC_OBX_SETPATH_RSP_EVT */ {BTA_FTC_IGNORE_OBX, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST},
+/* BTA_FTC_OBX_CMPL_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST},
+/* BTA_FTC_CLOSE_CMPL_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST},
+/* BTA_FTC_DISABLE_CMPL_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST},
+/* BTA_FTC_RSP_TOUT_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST}
+};
+
+/* state table for wait for authentication response state */
+static const UINT8 bta_ftc_st_w4_conn[][BTA_FTC_NUM_COLS] =
+{
+/* Event Action 1 Action 2 Next state */
+/* BTA_FTC_API_DISABLE_EVT */ {BTA_FTC_SET_DISABLE, BTA_FTC_STOP_CLIENT, BTA_FTC_CLOSING_ST},
+/* BTA_FTC_API_OPEN_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_W4_CONN_ST},
+/* BTA_FTC_API_CLOSE_EVT */ {BTA_FTC_STOP_CLIENT, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST},
+/* BTA_FTC_API_PUTFILE_EVT */ {BTA_FTC_BIC_PUT, BTA_FTC_IGNORE, BTA_FTC_W4_CONN_ST},
+/* BTA_FTC_API_GETFILE_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_W4_CONN_ST},
+/* BTA_FTC_API_LISTDIR_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_W4_CONN_ST},
+/* BTA_FTC_API_CHDIR_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_W4_CONN_ST},
+/* BTA_FTC_API_MKDIR_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_W4_CONN_ST},
+/* BTA_FTC_API_REMOVE_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_W4_CONN_ST},
+/* BTA_FTC_API_AUTHRSP_EVT */ {BTA_FTC_SEND_AUTHRSP, BTA_FTC_IGNORE, BTA_FTC_W4_CONN_ST},
+/* BTA_FTC_API_ABORT_EVT */ {BTA_FTC_BIC_ABORT, BTA_FTC_IGNORE, BTA_FTC_W4_CONN_ST},
+/* BTA_FTC_API_ACTION_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_W4_CONN_ST},
+/* BTA_FTC_OBX_ACTION_RSP_EVT */ {BTA_FTC_IGNORE_OBX, BTA_FTC_IGNORE, BTA_FTC_W4_CONN_ST},
+/* BTA_FTC_CI_SESSION_EVT */ {BTA_FTC_CI_RESUME, BTA_FTC_IGNORE, BTA_FTC_W4_CONN_ST},
+/* BTA_FTC_SDP_OK_EVT */ {BTA_FTC_FREE_DB, BTA_FTC_START_CLIENT, BTA_FTC_W4_CONN_ST},
+/* BTA_FTC_SDP_FAIL_EVT */ {BTA_FTC_FREE_DB, BTA_FTC_CLOSE, BTA_FTC_CLOSING_ST},
+/* BTA_FTC_SDP_NEXT_EVT */ {BTA_FTC_FREE_DB, BTA_FTC_FIND_SERVICE, BTA_FTC_W4_CONN_ST},
+/* BTA_FTC_CI_WRITE_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_W4_CONN_ST},
+/* BTA_FTC_CI_READ_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_W4_CONN_ST},
+/* BTA_FTC_CI_OPEN_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_W4_CONN_ST},
+/* BTA_FTC_OBX_CONN_RSP_EVT */ {BTA_FTC_OBX_CONN_RSP, BTA_FTC_IGNORE, BTA_FTC_CONN_ST},
+/* BTA_FTC_OBX_ABORT_RSP_EVT */ {BTA_FTC_IGNORE_OBX, BTA_FTC_IGNORE, BTA_FTC_W4_CONN_ST},
+/* BTA_FTC_OBX_TOUT_EVT */ {BTA_FTC_OBX_TIMEOUT, BTA_FTC_IGNORE, BTA_FTC_W4_CONN_ST},
+/* BTA_FTC_OBX_PASSWORD_EVT */ {BTA_FTC_OBX_PASSWORD, BTA_FTC_IGNORE, BTA_FTC_W4_CONN_ST},
+/* BTA_FTC_OBX_CLOSE_EVT */ {BTA_FTC_OPEN_FAIL, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST},
+/* BTA_FTC_OBX_PUT_RSP_EVT */ {BTA_FTC_IGNORE_OBX, BTA_FTC_IGNORE, BTA_FTC_W4_CONN_ST},
+/* BTA_FTC_OBX_GET_RSP_EVT */ {BTA_FTC_IGNORE_OBX, BTA_FTC_IGNORE, BTA_FTC_W4_CONN_ST},
+/* BTA_FTC_OBX_SETPATH_RSP_EVT */ {BTA_FTC_IGNORE_OBX, BTA_FTC_IGNORE, BTA_FTC_W4_CONN_ST},
+/* BTA_FTC_OBX_CMPL_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_W4_CONN_ST},
+/* BTA_FTC_CLOSE_CMPL_EVT */ {BTA_FTC_CLOSE_COMPLETE,BTA_FTC_IGNORE, BTA_FTC_IDLE_ST},
+/* BTA_FTC_DISABLE_CMPL_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST},
+/* BTA_FTC_RSP_TOUT_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST}
+
+};
+
+/* state table for connected state */
+static const UINT8 bta_ftc_st_connected[][BTA_FTC_NUM_COLS] =
+{
+/* Event Action 1 Action 2 Next state */
+/* BTA_FTC_API_DISABLE_EVT */ {BTA_FTC_SET_DISABLE, BTA_FTC_STOP_CLIENT, BTA_FTC_CLOSING_ST},
+/* BTA_FTC_API_OPEN_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_CONN_ST},
+/* BTA_FTC_API_CLOSE_EVT */ {BTA_FTC_STOP_CLIENT, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST},
+/* BTA_FTC_API_PUTFILE_EVT */ {BTA_FTC_INIT_PUTFILE, BTA_FTC_IGNORE, BTA_FTC_CONN_ST},
+/* BTA_FTC_API_GETFILE_EVT */ {BTA_FTC_INIT_GETFILE, BTA_FTC_IGNORE, BTA_FTC_CONN_ST},
+/* BTA_FTC_API_LISTDIR_EVT */ {BTA_FTC_LISTDIR , BTA_FTC_IGNORE, BTA_FTC_CONN_ST},
+/* BTA_FTC_API_CHDIR_EVT */ {BTA_FTC_CHDIR, BTA_FTC_IGNORE, BTA_FTC_CONN_ST},
+/* BTA_FTC_API_MKDIR_EVT */ {BTA_FTC_MKDIR, BTA_FTC_IGNORE, BTA_FTC_CONN_ST},
+/* BTA_FTC_API_REMOVE_EVT */ {BTA_FTC_REMOVE, BTA_FTC_IGNORE, BTA_FTC_CONN_ST},
+/* BTA_FTC_API_AUTHRSP_EVT */ {BTA_FTC_SEND_AUTHRSP, BTA_FTC_IGNORE, BTA_FTC_CONN_ST},
+/* BTA_FTC_API_ABORT_EVT */ {BTA_FTC_ABORT, BTA_FTC_IGNORE, BTA_FTC_CONN_ST},
+/* BTA_FTC_API_ACTION_EVT */ {BTA_FTC_API_ACTION, BTA_FTC_IGNORE, BTA_FTC_CONN_ST},
+/* BTA_FTC_OBX_ACTION_RSP_EVT */ {BTA_FTC_OBX_ACTION_RSP, BTA_FTC_IGNORE, BTA_FTC_CONN_ST},
+/* BTA_FTC_CI_SESSION_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_CONN_ST},
+/* BTA_FTC_SDP_OK_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_CONN_ST},
+/* BTA_FTC_SDP_FAIL_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_CONN_ST},
+/* BTA_FTC_SDP_NEXT_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_CONN_ST},
+/* BTA_FTC_CI_WRITE_EVT */ {BTA_FTC_CI_WRITE, BTA_FTC_IGNORE, BTA_FTC_CONN_ST},
+/* BTA_FTC_CI_READ_EVT */ {BTA_FTC_CI_READ, BTA_FTC_IGNORE, BTA_FTC_CONN_ST},
+/* BTA_FTC_CI_OPEN_EVT */ {BTA_FTC_CI_OPEN, BTA_FTC_IGNORE, BTA_FTC_CONN_ST},
+/* BTA_FTC_OBX_CONN_RSP_EVT */ {BTA_FTC_SUSPENDED, BTA_FTC_IGNORE, BTA_FTC_CONN_ST},
+/* BTA_FTC_OBX_ABORT_RSP_EVT */ {BTA_FTC_OBX_ABORT_RSP, BTA_FTC_IGNORE, BTA_FTC_CONN_ST},
+/* BTA_FTC_OBX_TOUT_EVT */ {BTA_FTC_OBX_TIMEOUT, BTA_FTC_IGNORE, BTA_FTC_CONN_ST},
+/* BTA_FTC_OBX_PASSWORD_EVT */ {BTA_FTC_OBX_PASSWORD, BTA_FTC_IGNORE, BTA_FTC_CONN_ST},
+/* BTA_FTC_OBX_CLOSE_EVT */ {BTA_FTC_CLOSE, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST},
+/* BTA_FTC_OBX_PUT_RSP_EVT */ {BTA_FTC_OBX_PUT_RSP, BTA_FTC_IGNORE, BTA_FTC_CONN_ST},
+/* BTA_FTC_OBX_GET_RSP_EVT */ {BTA_FTC_OBX_GET_RSP, BTA_FTC_IGNORE, BTA_FTC_CONN_ST},
+/* BTA_FTC_OBX_SETPATH_RSP_EVT */ {BTA_FTC_OBX_SETPATH_RSP, BTA_FTC_IGNORE, BTA_FTC_CONN_ST},
+/* BTA_FTC_OBX_CMPL_EVT */ {BTA_FTC_TRANS_CMPL, BTA_FTC_IGNORE, BTA_FTC_CONN_ST},
+/* BTA_FTC_CLOSE_CMPL_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_CONN_ST},
+/* BTA_FTC_DISABLE_CMPL_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST},
+/* BTA_FTC_RSP_TOUT_EVT */ {BTA_FTC_RSP_TIMEOUT, BTA_FTC_IGNORE, BTA_FTC_CONN_ST}
+};
+
+/* state table for suspending state */
+static const UINT8 bta_ftc_st_suspending[][BTA_FTC_NUM_COLS] =
+{
+/* Event Action 1 Action 2 Next state */
+/* BTA_FTC_API_DISABLE_EVT */ {BTA_FTC_SET_DISABLE, BTA_FTC_STOP_CLIENT, BTA_FTC_CLOSING_ST},
+/* BTA_FTC_API_OPEN_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST},
+/* BTA_FTC_API_CLOSE_EVT */ {BTA_FTC_STOP_CLIENT, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST},
+/* BTA_FTC_API_PUTFILE_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST},
+/* BTA_FTC_API_GETFILE_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST},
+/* BTA_FTC_API_LISTDIR_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST},
+/* BTA_FTC_API_CHDIR_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST},
+/* BTA_FTC_API_MKDIR_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST},
+/* BTA_FTC_API_REMOVE_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST},
+/* BTA_FTC_API_AUTHRSP_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST},
+/* BTA_FTC_API_ABORT_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST},
+/* BTA_FTC_API_ACTION_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST},
+/* BTA_FTC_OBX_ACTION_RSP_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST},
+/* BTA_FTC_CI_SESSION_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST},
+/* BTA_FTC_SDP_OK_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST},
+/* BTA_FTC_SDP_FAIL_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST},
+/* BTA_FTC_SDP_NEXT_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST},
+/* BTA_FTC_CI_WRITE_EVT */ {BTA_FTC_CI_WRITE_SRM, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST},
+/* BTA_FTC_CI_READ_EVT */ {BTA_FTC_CI_READ, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST},
+/* BTA_FTC_CI_OPEN_EVT */ {BTA_FTC_CI_OPEN, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST},
+/* BTA_FTC_OBX_CONN_RSP_EVT */ {BTA_FTC_OBX_SESS_RSP, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST},
+/* BTA_FTC_OBX_ABORT_RSP_EVT */ {BTA_FTC_OBX_ABORT_RSP, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST},
+/* BTA_FTC_OBX_TOUT_EVT */ {BTA_FTC_OBX_TIMEOUT, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST},
+/* BTA_FTC_OBX_PASSWORD_EVT */ {BTA_FTC_IGNORE_OBX, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST},
+/* BTA_FTC_OBX_CLOSE_EVT */ {BTA_FTC_CLOSE, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST},
+/* BTA_FTC_OBX_PUT_RSP_EVT */ {BTA_FTC_OBX_PUT_RSP, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST},
+/* BTA_FTC_OBX_GET_RSP_EVT */ {BTA_FTC_OBX_GET_SRM_RSP, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST},
+/* BTA_FTC_OBX_SETPATH_RSP_EVT */ {BTA_FTC_IGNORE_OBX, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST},
+/* BTA_FTC_OBX_CMPL_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST},
+/* BTA_FTC_CLOSE_CMPL_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST},
+/* BTA_FTC_DISABLE_CMPL_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST},
+/* BTA_FTC_RSP_TOUT_EVT */ {BTA_FTC_RSP_TIMEOUT, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST}
+};
+
+/* state table for closing state */
+static const UINT8 bta_ftc_st_closing[][BTA_FTC_NUM_COLS] =
+{
+/* Event Action 1 Action 2 Next state */
+/* BTA_FTC_API_DISABLE_EVT */ {BTA_FTC_SET_DISABLE, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST},
+/* BTA_FTC_API_OPEN_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST},
+/* BTA_FTC_API_CLOSE_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST},
+/* BTA_FTC_API_PUTFILE_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST},
+/* BTA_FTC_API_GETFILE_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST},
+/* BTA_FTC_API_LISTDIR_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST},
+/* BTA_FTC_API_CHDIR_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST},
+/* BTA_FTC_API_MKDIR_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST},
+/* BTA_FTC_API_REMOVE_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST},
+/* BTA_FTC_API_AUTHRSP_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST},
+/* BTA_FTC_API_ABORT_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST},
+/* BTA_FTC_API_ACTION_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST},
+/* BTA_FTC_OBX_ACTION_RSP_EVT */ {BTA_FTC_IGNORE_OBX, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST},
+/* BTA_FTC_CI_SESSION_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST},
+/* BTA_FTC_SDP_OK_EVT */ {BTA_FTC_FREE_DB, BTA_FTC_CLOSE, BTA_FTC_CLOSING_ST},
+/* BTA_FTC_SDP_FAIL_EVT */ {BTA_FTC_FREE_DB, BTA_FTC_CLOSE, BTA_FTC_CLOSING_ST},
+/* BTA_FTC_SDP_NEXT_EVT */ {BTA_FTC_FREE_DB, BTA_FTC_CLOSE, BTA_FTC_CLOSING_ST},
+/* BTA_FTC_CI_WRITE_EVT */ {BTA_FTC_CLOSE_COMPLETE,BTA_FTC_IGNORE, BTA_FTC_IDLE_ST},
+/* BTA_FTC_CI_READ_EVT */ {BTA_FTC_CLOSE_COMPLETE,BTA_FTC_IGNORE, BTA_FTC_IDLE_ST},
+/* BTA_FTC_CI_OPEN_EVT */ {BTA_FTC_CLOSE_COMPLETE,BTA_FTC_IGNORE, BTA_FTC_IDLE_ST},
+/* BTA_FTC_OBX_CONN_RSP_EVT */ {BTA_FTC_IGNORE_OBX, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST},
+/* BTA_FTC_OBX_ABORT_RSP_EVT */ {BTA_FTC_OBX_ABORT_RSP, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST},
+/* BTA_FTC_OBX_TOUT_EVT */ {BTA_FTC_OBX_TIMEOUT, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST},
+/* BTA_FTC_OBX_PASSWORD_EVT */ {BTA_FTC_IGNORE_OBX, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST},
+/* BTA_FTC_OBX_CLOSE_EVT */ {BTA_FTC_CLOSE, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST},
+/* BTA_FTC_OBX_PUT_RSP_EVT */ {BTA_FTC_IGNORE_OBX, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST},
+/* BTA_FTC_OBX_GET_RSP_EVT */ {BTA_FTC_IGNORE_OBX, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST},
+/* BTA_FTC_OBX_SETPATH_RSP_EVT */ {BTA_FTC_IGNORE_OBX, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST},
+/* BTA_FTC_OBX_CMPL_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST},
+/* BTA_FTC_CLOSE_CMPL_EVT */ {BTA_FTC_CLOSE_COMPLETE,BTA_FTC_IGNORE, BTA_FTC_IDLE_ST},
+/* BTA_FTC_DISABLE_CMPL_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST},
+/* BTA_FTC_RSP_TOUT_EVT */ {BTA_FTC_RSP_TIMEOUT, BTA_FTC_CLOSE_COMPLETE, BTA_FTC_IDLE_ST}
+};
+
+/* type for state table */
+typedef const UINT8 (*tBTA_FTC_ST_TBL)[BTA_FTC_NUM_COLS];
+
+/* state table */
+const tBTA_FTC_ST_TBL bta_ftc_st_tbl[] =
+{
+ bta_ftc_st_idle,
+ bta_ftc_st_w4_conn,
+ bta_ftc_st_connected,
+ bta_ftc_st_suspending,
+ bta_ftc_st_closing
+};
+
+/*****************************************************************************
+** Global data
+*****************************************************************************/
+
+/* FTC control block */
+#if BTA_DYNAMIC_MEMORY == FALSE
+tBTA_FTC_CB bta_ftc_cb;
+#endif
+
+#if BTA_FTC_DEBUG == TRUE
+static char *ftc_evt_code(tBTA_FTC_INT_EVT evt_code);
+static char *ftc_state_code(tBTA_FTC_STATE state_code);
+#endif
+
+/*******************************************************************************
+**
+** Function bta_ftc_sm_execute
+**
+** Description State machine event handling function for FTC
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ftc_sm_execute(tBTA_FTC_CB *p_cb, UINT16 event, tBTA_FTC_DATA *p_data)
+{
+ tBTA_FTC_ST_TBL state_table;
+ UINT8 action;
+ int i;
+#if BTA_FTC_DEBUG == TRUE
+ tBTA_FTC_STATE in_state = p_cb->state;
+ UINT16 in_event = event;
+ APPL_TRACE_DEBUG4("bta_ftc_sm_execute: State 0x%02x [%s], Event 0x%x[%s]", in_state,
+ ftc_state_code(in_state),
+ in_event,
+ ftc_evt_code(in_event));
+#endif
+
+ /* look up the state table for the current state */
+ state_table = bta_ftc_st_tbl[p_cb->state];
+
+ event &= 0x00FF;
+
+ /* set next state */
+ p_cb->state = state_table[event][BTA_FTC_NEXT_STATE];
+
+ /* execute action functions */
+ for (i = 0; i < BTA_FTC_ACTIONS; i++)
+ {
+ if ((action = state_table[event][i]) != BTA_FTC_IGNORE)
+ {
+ (*bta_ftc_action[action])(p_cb, p_data);
+ }
+ else
+ {
+ break;
+ }
+ }
+
+#if BTA_FTC_DEBUG == TRUE
+ if (in_state != p_cb->state)
+ {
+ APPL_TRACE_DEBUG3("FTC State Change: [%s] -> [%s] after Event [%s]",
+ ftc_state_code(in_state),
+ ftc_state_code(p_cb->state),
+ ftc_evt_code(in_event));
+ }
+#endif
+}
+
+/*****************************************************************************
+**
+** Function: bta_ftc_sdp_register()
+**
+** Purpose: Registers the File Transfer service with SDP
+**
+** Parameters:
+**
+**
+** Returns: void
+**
+*****************************************************************************/
+static void bta_ftc_sdp_register (tBTA_FTC_CB *p_cb)
+{
+ UINT16 pbap_service = UUID_SERVCLASS_PBAP_PCE;
+ UINT16 browse = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
+ BOOLEAN status = FALSE;
+
+ if ((p_cb->sdp_handle = SDP_CreateRecord()) == 0)
+ {
+ APPL_TRACE_WARNING0("FTC SDP: Unable to register PBAP PCE Service");
+ return;
+ }
+
+ /* add service class */
+ if (SDP_AddServiceClassIdList(p_cb->sdp_handle, 1, &pbap_service))
+ {
+ status = TRUE; /* All mandatory fields were successful */
+
+ /* optional: if name is not "", add a name entry */
+ if (p_bta_ft_cfg->pce_name && p_bta_ft_cfg->pce_name[0] != '\0')
+ SDP_AddAttribute(p_cb->sdp_handle,
+ (UINT16)ATTR_ID_SERVICE_NAME,
+ (UINT8)TEXT_STR_DESC_TYPE,
+ (UINT32)(strlen(p_bta_ft_cfg->pce_name) + 1),
+ (UINT8 *)p_bta_ft_cfg->pce_name);
+
+ /* Add in the Bluetooth Profile Descriptor List */
+ SDP_AddProfileDescriptorList(p_cb->sdp_handle,
+ UUID_SERVCLASS_PBAP_PCE,
+ BTA_FTC_DEFAULT_VERSION);
+ } /* end of setting mandatory service class */
+
+ /* Make the service browseable */
+ SDP_AddUuidSequence (p_cb->sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &browse);
+
+ if (!status)
+ {
+ SDP_DeleteRecord(p_cb->sdp_handle);
+ APPL_TRACE_ERROR0("bta_ftc_sdp_register FAILED");
+ p_cb->sdp_handle = 0;
+ }
+ else
+ {
+ bta_sys_add_uuid( pbap_service ); /* UUID_SERVCLASS_PBAP_PCE */
+ APPL_TRACE_DEBUG1("FTC: SDP Registered (handle 0x%08x)", p_cb->sdp_handle);
+ }
+
+ return;
+}
+
+/*******************************************************************************
+**
+** Function bta_ftc_api_enable
+**
+** Description Handle an api enable event. This function enables the FT
+** Client by opening an Obex/Rfcomm channel with a peer device.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ftc_api_enable(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data)
+{
+ if (!p_cb->is_enabled)
+ {
+ /* initialize control block */
+ memset(p_cb, 0, sizeof(tBTA_FTC_CB));
+
+ /* store parameters */
+ p_cb->p_cback = p_data->api_enable.p_cback;
+ p_cb->app_id = p_data->api_enable.app_id;
+#if( defined BTA_BI_INCLUDED ) && (BTA_BI_INCLUDED == TRUE)
+ p_cb->bic_handle = BTA_BIC_INVALID_HANDLE;
+#endif
+ p_cb->fd = BTA_FS_INVALID_FD;
+ p_cb->is_enabled = TRUE;
+
+ /* create SDP record for PCE */
+ if(p_bta_ft_cfg->pce_features)
+ bta_ftc_sdp_register(p_cb);
+ }
+
+ /* callback with enable event */
+ (*p_cb->p_cback)(BTA_FTC_ENABLE_EVT, 0);
+}
+
+/*******************************************************************************
+**
+** Function bta_ftc_hdl_event
+**
+** Description File transfer server main event handling function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BOOLEAN bta_ftc_hdl_event(BT_HDR *p_msg)
+{
+ tBTA_FTC_CB *p_cb = &bta_ftc_cb;
+#if BTA_FTC_DEBUG == TRUE
+ tBTA_FTC_STATE in_state = p_cb->state;
+#endif
+
+ switch (p_msg->event)
+ {
+ case BTA_FTC_API_ENABLE_EVT:
+#if BTA_FTC_DEBUG == TRUE
+ APPL_TRACE_DEBUG3("FTC Event Handler: State 0x%02x [%s], Event [%s]", in_state,
+ ftc_state_code(in_state),
+ ftc_evt_code(p_msg->event));
+#endif
+ bta_ftc_api_enable(p_cb, (tBTA_FTC_DATA *) p_msg);
+#if BTA_FTC_DEBUG == TRUE
+ if (in_state != p_cb->state)
+ {
+ APPL_TRACE_DEBUG3("FTC State Change: [%s] -> [%s] after Event [%s]",
+ ftc_state_code(in_state),
+ ftc_state_code(p_cb->state),
+ ftc_evt_code(p_msg->event));
+ }
+#endif
+ break;
+
+ default:
+ if (p_cb->is_enabled)
+ {
+ bta_ftc_sm_execute(p_cb, p_msg->event, (tBTA_FTC_DATA *) p_msg);
+
+ if ( p_cb->state == BTA_FTC_CONN_ST )
+ {
+ if (( p_cb->pm_state == BTA_FTC_PM_IDLE )
+ &&( p_cb->obx_oper != FTC_OP_NONE ))
+ {
+ /* inform power manager */
+ APPL_TRACE_DEBUG0("BTA FTC informs DM/PM busy state");
+ bta_sys_busy( BTA_ID_FTC, p_cb->app_id, p_cb->bd_addr );
+ p_cb->pm_state = BTA_FTC_PM_BUSY;
+ }
+ else if (( p_cb->pm_state == BTA_FTC_PM_BUSY )
+ &&( p_cb->obx_oper == FTC_OP_NONE ))
+ {
+ /* inform power manager */
+ APPL_TRACE_DEBUG0("BTA FTC informs DM/PM idle state");
+ bta_sys_idle( BTA_ID_FTC ,p_cb->app_id, p_cb->bd_addr);
+ p_cb->pm_state = BTA_FTC_PM_IDLE;
+ }
+ }
+ else if ( p_cb->state == BTA_FTC_IDLE_ST )
+ {
+ /* initialize power management state */
+ p_cb->pm_state = BTA_FTC_PM_BUSY;
+ }
+ }
+ break;
+ }
+
+
+ return (TRUE);
+}
+
+
+/*****************************************************************************
+** Debug Functions
+*****************************************************************************/
+#if BTA_FTC_DEBUG == TRUE
+
+/*******************************************************************************
+**
+** Function ftc_evt_code
+**
+** Description
+**
+** Returns void
+**
+*******************************************************************************/
+static char *ftc_evt_code(tBTA_FTC_INT_EVT evt_code)
+{
+ switch(evt_code)
+ {
+ case BTA_FTC_API_DISABLE_EVT:
+ return "BTA_FTC_API_DISABLE_EVT";
+ case BTA_FTC_API_OPEN_EVT:
+ return "BTA_FTC_API_OPEN_EVT";
+ case BTA_FTC_API_CLOSE_EVT:
+ return "BTA_FTC_API_CLOSE_EVT";
+ case BTA_FTC_API_PUTFILE_EVT:
+ return "BTA_FTC_API_PUTFILE_EVT";
+ case BTA_FTC_API_GETFILE_EVT:
+ return "BTA_FTC_API_GETFILE_EVT";
+ case BTA_FTC_API_LISTDIR_EVT:
+ return "BTA_FTC_API_LISTDIR_EVT";
+ case BTA_FTC_API_CHDIR_EVT:
+ return "BTA_FTC_API_CHDIR_EVT";
+ case BTA_FTC_API_MKDIR_EVT:
+ return "BTA_FTC_API_MKDIR_EVT";
+ case BTA_FTC_API_REMOVE_EVT:
+ return "BTA_FTC_API_REMOVE_EVT";
+ case BTA_FTC_API_AUTHRSP_EVT:
+ return "BTA_FTC_API_AUTHRSP_EVT";
+ case BTA_FTC_API_ABORT_EVT:
+ return "BTA_FTC_API_ABORT_EVT";
+ case BTA_FTC_API_ACTION_EVT:
+ return "BTA_FTC_API_ACTION_EVT";
+ case BTA_FTC_OBX_ACTION_RSP_EVT:
+ return "BTA_FTC_OBX_ACTION_RSP_EVT";
+ case BTA_FTC_CI_SESSION_EVT:
+ return "BTA_FTC_CI_SESSION_EVT";
+ case BTA_FTC_SDP_OK_EVT:
+ return "BTA_FTC_SDP_OK_EVT";
+ case BTA_FTC_SDP_FAIL_EVT:
+ return "BTA_FTC_SDP_FAIL_EVT";
+ case BTA_FTC_SDP_NEXT_EVT:
+ return "BTA_FTC_SDP_NEXT_EVT";
+ case BTA_FTC_CI_WRITE_EVT:
+ return "BTA_FTC_CI_WRITE_EVT";
+ case BTA_FTC_CI_READ_EVT:
+ return "BTA_FTC_CI_READ_EVT";
+ case BTA_FTC_CI_OPEN_EVT:
+ return "BTA_FTC_CI_OPEN_EVT";
+ case BTA_FTC_OBX_CONN_RSP_EVT:
+ return "BTA_FTC_OBX_CONN_RSP_EVT";
+ case BTA_FTC_OBX_ABORT_RSP_EVT:
+ return "BTA_FTC_OBX_ABORT_RSP_EVT";
+ case BTA_FTC_OBX_TOUT_EVT:
+ return "BTA_FTC_OBX_TOUT_EVT";
+ case BTA_FTC_OBX_PASSWORD_EVT:
+ return "BTA_FTC_OBX_PASSWORD_EVT";
+ case BTA_FTC_OBX_CLOSE_EVT:
+ return "BTA_FTC_OBX_CLOSE_EVT";
+ case BTA_FTC_OBX_PUT_RSP_EVT:
+ return "BTA_FTC_OBX_PUT_RSP_EVT";
+ case BTA_FTC_CLOSE_CMPL_EVT:
+ return "BTA_FTC_CLOSE_CMPL_EVT";
+ case BTA_FTC_OBX_GET_RSP_EVT:
+ return "BTA_FTC_OBX_GET_RSP_EVT";
+ case BTA_FTC_OBX_SETPATH_RSP_EVT:
+ return "BTA_FTC_OBX_SETPATH_RSP_EVT";
+ case BTA_FTC_OBX_CMPL_EVT:
+ return "BTA_FTC_OBX_CMPL_EVT";
+ case BTA_FTC_DISABLE_CMPL_EVT:
+ return "BTA_FTC_DISABLE_CMPL_EVT";
+ case BTA_FTC_RSP_TOUT_EVT:
+ return "BTA_FTC_RSP_TOUT_EVT";
+ case BTA_FTC_API_ENABLE_EVT:
+ return "BTA_FTC_API_ENABLE_EVT";
+ default:
+ return "unknown FTC event code";
+ }
+}
+
+/*******************************************************************************
+**
+** Function ftc_state_code
+**
+** Description
+**
+** Returns void
+**
+*******************************************************************************/
+static char *ftc_state_code(tBTA_FTC_STATE state_code)
+{
+ switch(state_code)
+ {
+ case BTA_FTC_IDLE_ST:
+ return "BTA_FTC_IDLE_ST";
+ case BTA_FTC_W4_CONN_ST:
+ return "BTA_FTC_W4_CONN_ST";
+ case BTA_FTC_CONN_ST:
+ return "BTA_FTC_CONN_ST";
+ case BTA_FTC_SUSPENDING_ST:
+ return "BTA_FTC_SUSPENDING_ST";
+ case BTA_FTC_CLOSING_ST:
+ return "BTA_FTC_CLOSING_ST";
+ default:
+ return "unknown FTC state code";
+ }
+}
+
+#endif /* Debug Functions */
+#endif /* BTA_FT_INCLUDED */
diff --git a/bta/ft/bta_ftc_utils.c b/bta/ft/bta_ftc_utils.c
new file mode 100644
index 0000000..8468d5f
--- /dev/null
+++ b/bta/ft/bta_ftc_utils.c
@@ -0,0 +1,608 @@
+/*****************************************************************************
+**
+** Name: bta_ftc_utils.c
+**
+** Description: This file implements object store functions for the
+** file transfer server.
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+
+
+#if defined(BTA_FT_INCLUDED) && (BTA_FT_INCLUDED == TRUE)
+
+#include <stdio.h>
+#include <string.h>
+#include "bta_ftc_int.h"
+#include "bta_fs_api.h"
+#include "bta_fs_co.h"
+#include "gki.h"
+#include "utl.h"
+
+/*******************************************************************************
+** Constants
+*******************************************************************************/
+
+/*******************************************************************************
+** Local Function Prototypes
+*******************************************************************************/
+
+/*******************************************************************************
+* Macros for FTC
+*******************************************************************************/
+#define BTA_FTC_XML_EOL "\n"
+#define BTA_FTC_FOLDER_LISTING_START ( "<?xml version=\"1.0\"?>\n" \
+ "<!DOCTYPE folder-listing SYSTEM \"obex-folder-listing.dtd\">\n" \
+ "<folder-listing version=\"1.0\">\n" )
+
+#define BTA_FTC_FOLDER_LISTING_END ( "</folder-listing>" )
+
+#define BTA_FTC_FILE_ELEM "file"
+#define BTA_FTC_FOLDER_ELEM "folder"
+#define BTA_FTC_PARENT_FOLDER_ELEM "parent-folder"
+#define BTA_FTC_NAME_ATTR "name"
+#define BTA_FTC_SIZE_ATTR "size"
+#define BTA_FTC_TYPE_ATTR "type"
+#define BTA_FTC_MODIFIED_ATTR "modified"
+#define BTA_FTC_CREATED_ATTR "created"
+#define BTA_FTC_ACCESSED_ATTR "accessed"
+#define BTA_FTC_USER_PERM_ATTR "user-perm"
+#define BTA_FTC_GROUP_PERM_ATTR "group-perm"
+#define BTA_FTC_OTHER_PERM_ATTR "other-perm"
+#define BTA_FTC_GROUP_ATTR "group"
+#define BTA_FTC_OWNER_ATTR "owner"
+#define BTA_FTC_LANG_ATTR "xml:lang"
+
+/*******************************************************************************
+** Local Function
+*******************************************************************************/
+/*******************************************************************************
+**
+** Function bta_ftc_send_abort_req
+**
+** Description Send an abort request.
+**
+** Parameters p_cb - Pointer to the FTC control block
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ftc_send_abort_req(tBTA_FTC_CB *p_cb)
+{
+ if (FTC_ABORT_REQ_NOT_SENT == p_cb->aborting)
+ {
+ p_cb->aborting = FTC_ABORT_REQ_SENT;
+ OBX_AbortReq(p_cb->obx_handle, (BT_HDR *)NULL);
+
+ /* Start abort response timer */
+ p_cb->timer_oper = FTC_TIMER_OP_ABORT;
+ bta_sys_start_timer(&p_cb->rsp_timer, BTA_FTC_RSP_TOUT_EVT,
+ p_bta_ft_cfg->abort_tout);
+ }
+}
+/*******************************************************************************
+**
+** Function bta_ftc_proc_pbap_param
+**
+** Description read PBAP app parameter header.
+**
+** Parameters
+**
+** Returns
+**
+*******************************************************************************/
+tBTA_FTC_PB_PARAM * bta_ftc_proc_pbap_param(tBTA_FTC_PB_PARAM *p_param, BT_HDR *p_pkt)
+{
+ UINT8 *p_data = NULL, aph;
+ UINT16 data_len = 0;
+ int left, len;
+ if(OBX_ReadByteStrHdr(p_pkt, OBX_HI_APP_PARMS, &p_data, &data_len, 0))
+ {
+ memset(p_param, 0, sizeof(tBTA_FTC_PB_PARAM));
+ left = data_len;
+ while(left > 0)
+ {
+ aph = *p_data++;
+ len = *p_data++;
+ left -= len;
+ left -= 2;
+ switch(aph)
+ {
+ case BTA_FTC_APH_PB_SIZE:
+ BE_STREAM_TO_UINT16(p_param->phone_book_size, p_data);
+ p_param->pbs_exist = TRUE;
+ break;
+ case BTA_FTC_APH_NEW_MISSED_CALL:
+ p_param->new_missed_calls = *p_data++;
+ p_param->nmc_exist = TRUE;
+ break;
+ default:
+ p_data += len;
+ }
+ }
+ }
+ else
+ p_param = NULL;
+ return p_param;
+}
+
+/*******************************************************************************
+* Exported Functions
+*******************************************************************************/
+/*******************************************************************************
+**
+** Function bta_ftc_send_get_req
+**
+** Description Processes a Get File Operation.
+**
+** Parameters p_cb - Pointer to the FTC control block
+**
+** Returns (UINT8) OBX response code
+**
+*******************************************************************************/
+UINT8 bta_ftc_send_get_req(tBTA_FTC_CB *p_cb)
+{
+ tBTA_FTC_OBX_PKT *p_obx = &p_cb->obx;
+ UINT8 rsp_code = OBX_RSP_FAILED;
+
+ /* Do not start another request if currently aborting */
+ if (!p_cb->aborting)
+ {
+ /* OBX header are added in bta_ftc_init_getfile */
+ if ((OBX_GetReq(p_cb->obx_handle, TRUE, p_obx->p_pkt)) == OBX_SUCCESS)
+ {
+ p_cb->req_pending = TRUE;
+ rsp_code = OBX_RSP_OK;
+ p_obx->p_pkt = NULL;
+ }
+ }
+ else
+ {
+ bta_ftc_send_abort_req(p_cb);
+ }
+
+ return (rsp_code);
+}
+
+/*******************************************************************************
+**
+** Function bta_ftc_proc_get_rsp
+**
+** Description Processes a Get File response packet.
+** Initiates a file write if no errors.
+**
+** Parameters
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ftc_proc_get_rsp(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data)
+{
+ tBTA_FTC_OBX_EVT *p_evt = &p_data->obx_evt;
+ tBTA_FTC_OBX_PKT *p_obx = &p_cb->obx;
+ UINT16 body_size;
+ BOOLEAN final;
+ BOOLEAN done = TRUE;
+ BOOLEAN send_request = TRUE;
+ UINT8 num_hdrs;
+ tBTA_FTC data;
+
+ do
+ {
+ if (p_evt->rsp_code == OBX_RSP_OK || p_evt->rsp_code == OBX_RSP_CONTINUE)
+ {
+ /* Only continue if not aborting */
+ if (p_cb->aborting)
+ {
+ /* Aborting: done with current packet */
+ utl_freebuf((void**)&p_evt->p_pkt);
+
+ /* If aborting, and this response is not last packet send abort */
+ if(p_evt->rsp_code == OBX_RSP_CONTINUE)
+ {
+ bta_ftc_send_abort_req(p_cb);
+ return;
+ }
+ else /* Last packet - abort and remove file (p_evt->rsp_code == OBX_RSP_OK) */
+ {
+ p_evt->rsp_code = (!p_cb->int_abort) ? OBX_RSP_GONE : OBX_RSP_INTRNL_SRVR_ERR;
+ bta_ftc_sm_execute(p_cb, BTA_FTC_OBX_CMPL_EVT, p_data);
+ return;
+ }
+ }
+
+ p_obx->final_pkt = (p_evt->rsp_code == OBX_RSP_OK) ? TRUE : FALSE;
+
+ /* If length header exists, save the file length */
+ if (p_cb->first_req_pkt == TRUE)
+ {
+ p_cb->first_req_pkt = FALSE;
+
+ /* if the obj_type is */
+ if(p_cb->obj_type == BTA_FTC_GET_PB)
+ {
+ bta_ftc_proc_pbap_param(&data.pb, p_obx->p_pkt);
+ bta_ftc_cb.p_cback(BTA_FTC_PHONEBOOK_EVT, &data);
+ if (p_cb->fd == BTA_FS_INVALID_FD)
+ {
+ /* if the obj_type is get pb && the file id not open,
+ * must be getting the phonebook size only
+ * - end of transaction */
+ break;
+ }
+ }
+ if (!OBX_ReadLengthHdr(p_evt->p_pkt, &p_cb->file_size))
+ p_cb->file_size = BTA_FS_LEN_UNKNOWN;
+ }
+
+ /* Read the body header from the obx packet */
+ num_hdrs = OBX_ReadBodyHdr(p_evt->p_pkt, &p_obx->p_start, &body_size,
+ &final);
+ /* process body header */
+ if (num_hdrs == 1)
+ {
+ if (body_size)
+ {
+ /* Data to be written */
+ p_obx->p_pkt = p_evt->p_pkt;
+ p_obx->offset = body_size; /* Save write size for comparison */
+ p_cb->cout_active = TRUE;
+ bta_fs_co_write(p_cb->fd, p_obx->p_start, body_size,
+ BTA_FTC_CI_WRITE_EVT, 0, p_cb->app_id);
+ done = FALSE;
+ send_request = FALSE;
+ }
+ /* If body header is zero in length but not final, request next packet */
+ else if (!final)
+ {
+ done = FALSE;
+ }
+ }
+ else if (num_hdrs > 1) /* Cannot handle more than a single body header */
+ {
+ p_evt->rsp_code = OBX_RSP_BAD_REQUEST;
+ }
+ /* Empty Body; send next request or finished */
+ else if (!p_obx->final_pkt)
+ done = FALSE;
+ }
+ } while (0);
+
+ if (done)
+ {
+ bta_ftc_sm_execute(p_cb, BTA_FTC_OBX_CMPL_EVT, p_data);
+ utl_freebuf((void**)&p_evt->p_pkt);
+ }
+ else if (send_request)
+ {
+ /* Free current packet and send a new request */
+ utl_freebuf((void**)&p_evt->p_pkt);
+ bta_ftc_send_get_req(p_cb);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ftc_cont_put_file
+**
+** Description Continues a Put File Operation.
+** Builds a new OBX packet, and initiates a read operation.
+**
+** Parameters p_cb - pointer to the client's control block.
+** first_pkt - TRUE if initial PUT request to server.
+**
+**
+** Returns UINT8 OBX response code
+**
+*******************************************************************************/
+UINT8 bta_ftc_cont_put_file(tBTA_FTC_CB *p_cb, BOOLEAN first_pkt)
+{
+ tBTA_FTC_OBX_PKT *p_obx = &p_cb->obx;
+ UINT8 rsp_code;
+ char *p_ch;
+
+ /* Do not start another request if currently aborting */
+ if (p_cb->aborting)
+ {
+ bta_ftc_send_abort_req(p_cb);
+ return (OBX_RSP_OK);
+ }
+
+ rsp_code = OBX_RSP_FAILED;
+
+ if ((p_obx->p_pkt = OBX_HdrInit(p_cb->obx_handle, p_cb->peer_mtu)) != NULL)
+ {
+ p_obx->offset = 0;
+
+ /* Add length header if it exists; No body in first packet */
+ if (first_pkt)
+ {
+ /* Add the Name Header to the request */
+ /* Find the beginning of the name (excluding the path) */
+ p_ch = strrchr(p_cb->p_name, (int) p_bta_fs_cfg->path_separator);
+ if (p_ch && p_ch[1] != '\0')
+ {
+ OBX_AddUtf8NameHdr(p_obx->p_pkt, (UINT8 *)&p_ch[1]);
+
+ /* Add the length header if known */
+ if (p_cb->file_size != BTA_FS_LEN_UNKNOWN)
+ {
+ OBX_AddLengthHdr(p_obx->p_pkt, p_cb->file_size);
+
+ }
+
+ OBX_PutReq(p_cb->obx_handle, FALSE, p_obx->p_pkt);
+ p_cb->req_pending = TRUE;
+ p_obx->p_pkt = NULL;
+ rsp_code = OBX_RSP_OK;
+ }
+ }
+ else /* A continuation packet so read file data */
+ {
+ /* Add the start of the Body Header */
+ p_obx->bytes_left = 0;
+ p_obx->p_start = OBX_AddBodyStart(p_obx->p_pkt, &p_obx->bytes_left);
+
+ /* Read in the first packet's worth of data */
+ p_cb->cout_active = TRUE;
+ bta_fs_co_read(p_cb->fd, &p_obx->p_start[p_obx->offset],
+ p_obx->bytes_left, BTA_FTC_CI_READ_EVT, 0, p_cb->app_id);
+ rsp_code = OBX_RSP_OK;
+ }
+ }
+
+ return (rsp_code);
+}
+
+/*******************************************************************************
+**
+** Function bta_ftc_proc_list_data
+**
+** Description Processes responses to directory listing requests
+** Loops through returned data generating application
+** listing data events. If needed, issues a new request
+** to the server.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ftc_proc_list_data(tBTA_FTC_CB *p_cb, tBTA_FTC_OBX_EVT *p_evt)
+{
+ tBTA_FTC app_evt;
+ tBTA_FTC_PB_PARAM param;
+ BOOLEAN is_ok = FALSE;
+ BOOLEAN first_req_pkt = p_cb->first_req_pkt;
+
+ app_evt.list.status = bta_ftc_convert_obx_to_ftc_status(p_evt->rsp_code);
+
+ if (p_evt->rsp_code == OBX_RSP_OK || p_evt->rsp_code == OBX_RSP_CONTINUE)
+ {
+ app_evt.list.p_param = NULL;
+ if (p_cb->first_req_pkt == TRUE)
+ {
+ p_cb->first_req_pkt = FALSE;
+ if(p_cb->sdp_service == UUID_SERVCLASS_PBAP_PSE)
+ app_evt.list.p_param = bta_ftc_proc_pbap_param(&param, p_evt->p_pkt);
+ }
+ APPL_TRACE_EVENT1("first_req_pkt: %d ", first_req_pkt);
+
+ if (OBX_ReadBodyHdr(p_evt->p_pkt, &app_evt.list.data, &app_evt.list.len,
+ &app_evt.list.final))
+ {
+ /* len > 0 or is final packet */
+ if(app_evt.list.len || app_evt.list.final)
+
+ {
+ bta_ftc_cb.p_cback(BTA_FTC_LIST_EVT, &app_evt);
+ }
+ is_ok = TRUE;
+ }
+ else if(first_req_pkt && p_evt->rsp_code == OBX_RSP_CONTINUE)
+ {
+ /* no body header is OK, if this is the first packet and is continue response */
+ is_ok = TRUE;
+ }
+
+ if(is_ok)
+ {
+ utl_freebuf((void**)&p_evt->p_pkt);
+ /* Initiate another request if not finished */
+ if (p_evt->rsp_code == OBX_RSP_CONTINUE)
+ {
+ if (p_cb->aborting)
+ bta_ftc_send_abort_req(p_cb);
+ else
+ bta_ftc_get_listing(p_cb, NULL, NULL);
+ }
+ else
+ p_cb->obx_oper = FTC_OP_NONE; /* Finished with directory listing */
+ }
+ else
+ {
+ /* Missing body header & not the first packet */
+ bta_ftc_listing_err(&p_evt->p_pkt, OBX_RSP_NO_CONTENT);
+ }
+ }
+ else /* Issue an error list entry */
+ bta_ftc_listing_err(&p_evt->p_pkt, app_evt.list.status);
+}
+
+/*******************************************************************************
+**
+** Function bta_ftc_get_listing
+**
+** Description Initiates or Continues a GET Listing operation
+** on the server's current directory.
+**
+** Parameters p_cb - pointer to the client's control block.
+** first_pkt - TRUE if initial GET request to server.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ftc_get_listing(tBTA_FTC_CB *p_cb, char *p_name, tBTA_FTC_LST_PARAM *p_param)
+{
+ tBTA_FTC_OBX_PKT *p_obx = &p_cb->obx;
+ tBTA_FTC_STATUS status = BTA_FTC_FAIL;
+ BOOLEAN is_ok = TRUE;
+ UINT8 *p, *p2, *p_start;
+ UINT16 len = 0;
+
+ if ((p_obx->p_pkt = OBX_HdrInit(p_cb->obx_handle, OBX_CMD_POOL_SIZE)) != NULL)
+ {
+ if (p_name)
+ {
+ /* first packet */
+ p_cb->first_req_pkt = TRUE;
+ /* Add the Type Header */
+ p = (UINT8 *) BTA_FTC_FOLDER_LISTING_TYPE;
+ if(p_cb->sdp_service == UUID_SERVCLASS_PBAP_PSE)
+ p = (UINT8 *) BTA_FTC_PULL_VCARD_LISTING_TYPE;
+
+ is_ok = OBX_AddTypeHdr(p_obx->p_pkt, (char *)p);
+
+ if(strcmp(p_name, ".") == 0 || p_name[0] == 0)
+ {
+ p_name = NULL;
+ }
+
+ if (p_name)
+ {
+ is_ok = OBX_AddUtf8NameHdr(p_obx->p_pkt, (unsigned char *) p_name);
+ }
+
+ if(p_param && p_cb->sdp_service == UUID_SERVCLASS_PBAP_PSE)
+ {
+ /* add app params for PCE */
+ p_start = OBX_AddByteStrStart(p_obx->p_pkt, &len);
+ p = p_start;
+ if(p_param->order < BTA_FTC_ORDER_MAX)
+ {
+ *p++ = BTA_FTC_APH_ORDER;
+ *p++ = 1;
+ *p++ = p_param->order;
+ }
+ if(p_param->p_value)
+ {
+ *p++ = BTA_FTC_APH_SEARCH_VALUE;
+ *p = strlen(p_param->p_value);
+ BCM_STRNCPY_S((char *) (p+1), strlen(p_param->p_value), p_param->p_value, *p);
+ p2 = p + 1 + *p;
+ p = p2;
+ }
+ if(p_param->attribute < BTA_FTC_ATTR_MAX)
+ {
+ *p++ = BTA_FTC_APH_SEARCH_ATTR;
+ *p++ = 1;
+ *p++ = p_param->attribute;
+ }
+ if(p_param->max_list_count != 0xFFFF)
+ {
+ *p++ = BTA_FTC_APH_MAX_LIST_COUNT;
+ *p++ = 2;
+ UINT16_TO_BE_STREAM(p, p_param->max_list_count);
+ }
+ if(p_param->list_start_offset)
+ {
+ *p++ = BTA_FTC_APH_LIST_STOFF;
+ *p++ = 2;
+ UINT16_TO_BE_STREAM(p, p_param->list_start_offset);
+ }
+
+ /* If any of the app param header is added */
+ if(p != p_start)
+ {
+ OBX_AddByteStrHdr(p_obx->p_pkt, OBX_HI_APP_PARMS, NULL, (UINT16)(p - p_start));
+ }
+ } /* if p_param: PBAP PCE need to keep AppParam in the first Get response */
+ }
+
+ if (is_ok)
+ {
+ if ((OBX_GetReq(p_cb->obx_handle, TRUE, p_obx->p_pkt)) == OBX_SUCCESS)
+ {
+ p_cb->req_pending = TRUE;
+ p_obx->p_pkt = NULL; /* OBX will free the memory */
+ p_cb->obx_oper = FTC_OP_GET_LIST;
+ status = BTA_FTC_OK;
+ }
+ }
+ }
+
+ if (status != BTA_FTC_OK) /* Send an error response to the application */
+ bta_ftc_listing_err(&p_obx->p_pkt, status);
+}
+
+/*******************************************************************************
+**
+** Function bta_ftc_listing_err
+**
+** Description Send a directory listing error event to the application
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ftc_listing_err(BT_HDR **p_pkt, tBTA_FTC_STATUS status)
+{
+ tBTA_FTC err_rsp;
+
+ if (bta_ftc_cb.obx_oper == FTC_OP_GET_LIST)
+ bta_ftc_cb.obx_oper = FTC_OP_NONE;
+ utl_freebuf((void**)p_pkt);
+
+ err_rsp.list.len = 0;
+ err_rsp.list.status = status;
+ err_rsp.list.final = TRUE;
+ err_rsp.list.data = NULL;
+ bta_ftc_cb.p_cback(BTA_FTC_LIST_EVT, &err_rsp);
+}
+
+/*******************************************************************************
+**
+** Function bta_ftc_convert_obx_to_ftc_status
+**
+** Description Convert OBX response code into BTA FTC status code.
+**
+** Returns void
+**
+*******************************************************************************/
+tBTA_FTC_STATUS bta_ftc_convert_obx_to_ftc_status(tOBX_STATUS obx_status)
+{
+ tBTA_FTC_STATUS status;
+
+ switch (obx_status)
+ {
+ case OBX_RSP_OK:
+ case OBX_RSP_CONTINUE:
+ status = BTA_FTC_OK;
+ break;
+ case OBX_RSP_UNAUTHORIZED:
+ status = BTA_FTC_NO_PERMISSION;
+ break;
+ case OBX_RSP_NOT_FOUND:
+ status = BTA_FTC_NOT_FOUND;
+ break;
+ case OBX_RSP_REQ_ENT_2_LARGE:
+ case OBX_RSP_DATABASE_FULL:
+ status = BTA_FTC_FULL;
+ break;
+ case OBX_RSP_GONE:
+ status = BTA_FTC_ABORTED;
+ break;
+ case OBX_RSP_SERVICE_UNAVL:
+ status = BTA_FTC_SERVICE_UNAVL;
+ break;
+ default:
+ status = BTA_FTC_FAIL;
+ }
+
+ return (status);
+}
+#endif /* BTA_FT_INCLUDED */
diff --git a/bta/ft/bta_fts_act.c b/bta/ft/bta_fts_act.c
new file mode 100644
index 0000000..52ba9e4
--- /dev/null
+++ b/bta/ft/bta_fts_act.c
@@ -0,0 +1,1523 @@
+/*****************************************************************************
+**
+** Name: bta_fts_act.c
+**
+** Description: This file contains the file transfer action
+** functions for the state machine.
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+
+#if defined(BTA_FT_INCLUDED) && (BTA_FT_INCLUDED == TRUE)
+
+#include <stdio.h>
+#include <string.h>
+#include "gki.h"
+#include "bta_sys.h"
+#include "obx_api.h"
+#include "bta_ft_api.h"
+#include "bta_fts_int.h"
+#include "bta_fs_api.h"
+#include "bta_fs_co.h"
+#include "bta_fs_ci.h"
+#include "btm_api.h"
+#include "utl.h"
+#include "bd.h"
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+#define FLAGS_ARE_MASK (OBX_SPF_BACKUP | OBX_SPF_NO_CREATE)
+#define FLAGS_ARE_ILLEGAL 0x1 /* 'Backup and Create flag combo is BAD */
+
+/*****************************************************************************
+** Local Function prototypes
+*****************************************************************************/
+#if BTA_FTS_DEBUG == TRUE
+static char *fts_obx_evt_code(tOBX_EVENT evt_code);
+#endif
+
+/*****************************************************************************
+** Action Functions
+*****************************************************************************/
+/*******************************************************************************
+**
+** Function bta_fts_api_disable
+**
+** Description Stop FTP server.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fts_api_disable(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data)
+{
+
+ /* If callout is active, wait till finished before shutting down */
+ if (p_cb->cout_active)
+ p_cb->disabling = TRUE;
+ else
+ bta_fts_sm_execute(p_cb, BTA_FTS_DISABLE_CMPL_EVT, p_data);
+
+ bta_sys_remove_uuid(UUID_SERVCLASS_OBEX_FILE_TRANSFER);
+ BTM_SecClrService(BTM_SEC_SERVICE_OBEX_FTP);
+}
+
+/*******************************************************************************
+**
+** Function bta_fts_api_authrsp
+**
+** Description Pass the response to an authentication request back to the
+** client.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fts_api_authrsp(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data)
+{
+ UINT8 *p_pwd = NULL;
+ UINT8 *p_userid = NULL;
+
+ if (p_data->auth_rsp.key_len > 0)
+ p_pwd = (UINT8 *)p_data->auth_rsp.key;
+ if (p_data->auth_rsp.userid_len > 0)
+ p_userid = (UINT8 *)p_data->auth_rsp.userid;
+
+ OBX_Password(p_cb->obx_handle, p_pwd, p_data->auth_rsp.key_len,
+ p_userid, p_data->auth_rsp.userid_len);
+}
+
+/*******************************************************************************
+**
+** Function bta_fts_api_accessrsp
+**
+** Description Process the access API event.
+** If permission had been granted, continue the PUT operation,
+** otherwise stop the operation.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fts_api_accessrsp(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data)
+{
+ UINT8 rsp_code = OBX_RSP_OK;
+ tBTA_FS_CO_STATUS status = BTA_FS_CO_EACCES;
+ tBTA_FT_ACCESS access = p_data->access_rsp.flag;
+ tBTA_FT_OPER old_acc_active = p_cb->acc_active;
+ tBTA_FTS_OBX_RSP *p_rsp = NULL;
+ tBTA_FTS_OBJECT objevt;
+
+ APPL_TRACE_DEBUG3("bta_fts_api_accessrsp op:%d/%d access:%d", old_acc_active, p_data->access_rsp.oper, access);
+ if(p_cb->acc_active != p_data->access_rsp.oper )
+ {
+ APPL_TRACE_WARNING2("FTS ACCRSP: not match active:%d, rsp:%d",
+ p_cb->acc_active, p_data->access_rsp.oper);
+ return;
+ }
+
+ p_cb->acc_active = 0;
+ /* Process the currently active access response */
+ switch (old_acc_active)
+ {
+ case BTA_FT_OPER_PUT:
+ if (access == BTA_FT_ACCESS_ALLOW)
+ {
+ /* Save the file name with path prepended */
+ BCM_STRNCPY_S(p_cb->p_path, p_bta_fs_cfg->max_file_len+1, p_data->access_rsp.p_name, p_bta_fs_cfg->max_file_len);
+ p_cb->p_path[p_bta_fs_cfg->max_file_len] = '\0';
+
+ p_cb->cout_active = TRUE;
+ bta_fs_co_open (p_cb->p_path,
+ (BTA_FS_O_CREAT | BTA_FS_O_TRUNC | BTA_FS_O_RDWR),
+ p_cb->file_length, BTA_FTS_CI_OPEN_EVT,
+ p_cb->app_id);
+ }
+ else /* Access denied */
+ {
+ bta_fts_clean_getput(p_cb, TRUE);
+ OBX_PutRsp(p_cb->obx_handle, OBX_RSP_UNAUTHORIZED, (BT_HDR *)NULL);
+ }
+ break;
+
+ case BTA_FT_OPER_GET:
+ if (access == BTA_FT_ACCESS_ALLOW)
+ {
+ p_cb->cout_active = TRUE;
+ bta_fs_co_open (p_cb->p_path, BTA_FS_O_RDONLY, 0,
+ BTA_FTS_CI_OPEN_EVT, p_cb->app_id);
+ }
+ else /* Denied */
+ bta_fts_get_file_rsp(OBX_RSP_UNAUTHORIZED, 0);
+ break;
+
+ case BTA_FT_OPER_DEL_FILE: /* Request is a DELETE file */
+ p_rsp = OBX_PutRsp;
+ if (access == BTA_FT_ACCESS_ALLOW)
+ {
+ objevt.p_name = p_cb->p_path;
+ objevt.status = BTA_FTS_OK;
+ if ((status = bta_fs_co_unlink(p_cb->p_path, p_cb->app_id)) != BTA_FS_CO_OK)
+ {
+ objevt.status = BTA_FTS_FAIL;
+ }
+
+ /* Notify application of delete attempt */
+ p_cb->p_cback(BTA_FTS_DEL_CMPL_EVT, (tBTA_FTS *)&objevt);
+ }
+ break;
+
+ case BTA_FT_OPER_DEL_DIR: /* Request is a DELETE folder */
+ p_rsp = OBX_PutRsp;
+ if (access == BTA_FT_ACCESS_ALLOW)
+ {
+ objevt.p_name = p_cb->p_path;
+ objevt.status = BTA_FTS_OK;
+ if ((status = bta_fs_co_rmdir(p_cb->p_path, p_cb->app_id)) != BTA_FS_CO_OK)
+ {
+ objevt.status = BTA_FTS_FAIL;
+ }
+
+ /* Notify application of delete attempt */
+ p_cb->p_cback(BTA_FTS_DEL_CMPL_EVT, (tBTA_FTS *)&objevt);
+ }
+ break;
+
+ case BTA_FT_OPER_CHG_DIR: /* Request is a Change Folder */
+ p_rsp = OBX_SetPathRsp;
+ if (access == BTA_FT_ACCESS_ALLOW)
+ {
+ status = BTA_FS_CO_OK;
+ BCM_STRNCPY_S(p_cb->p_workdir, p_bta_fs_cfg->max_path_len+1, p_cb->p_path, p_bta_fs_cfg->max_path_len);
+ p_cb->p_workdir[p_bta_fs_cfg->max_path_len] = '\0';
+ APPL_TRACE_DEBUG1("FTS: SET NEW PATH [%s]", p_cb->p_workdir);
+ bta_fs_co_setdir(p_cb->p_workdir, p_cb->app_id);
+ }
+ break;
+
+ case BTA_FT_OPER_MK_DIR: /* Request is a Make Folder */
+ p_rsp = OBX_SetPathRsp;
+ if (access == BTA_FT_ACCESS_ALLOW)
+ {
+ if ((status = bta_fs_co_mkdir(p_cb->p_path, p_cb->app_id)) == BTA_FS_CO_OK)
+ {
+ BCM_STRNCPY_S(p_cb->p_workdir, p_bta_fs_cfg->max_path_len+1, p_cb->p_path, p_bta_fs_cfg->max_path_len);
+ p_cb->p_workdir[p_bta_fs_cfg->max_path_len] = '\0';
+ APPL_TRACE_DEBUG1("FTS: SET NEW PATH [%s]", p_cb->p_workdir);
+ bta_fs_co_setdir(p_cb->p_workdir, p_cb->app_id);
+ }
+ }
+ break;
+
+ case BTA_FT_OPER_COPY_ACT:
+ if (access == BTA_FT_ACCESS_ALLOW)
+ {
+ p_cb->cout_active = TRUE;
+ bta_fs_co_copy(p_cb->p_path, p_cb->p_dest, p_cb->perms, BTA_FTS_CI_OPEN_EVT, p_cb->app_id);
+ }
+ else
+ p_rsp = OBX_ActionRsp;
+ break;
+
+ case BTA_FT_OPER_MOVE_ACT:
+ if (access == BTA_FT_ACCESS_ALLOW)
+ {
+ p_cb->cout_active = TRUE;
+ bta_fs_co_rename(p_cb->p_path, p_cb->p_dest, p_cb->perms, BTA_FTS_CI_OPEN_EVT, p_cb->app_id);
+ }
+ else
+ p_rsp = OBX_ActionRsp;
+ break;
+
+ case BTA_FT_OPER_SET_PERM:
+ if (access == BTA_FT_ACCESS_ALLOW)
+ {
+ p_cb->cout_active = TRUE;
+ bta_fs_co_set_perms(p_cb->p_path, p_cb->perms, BTA_FTS_CI_OPEN_EVT, p_cb->app_id);
+ }
+ else
+ p_rsp = OBX_ActionRsp;
+ break;
+
+ default:
+ p_cb->acc_active = old_acc_active;
+ APPL_TRACE_WARNING1("FTS ACCRSP: Unknown tBTA_FT_OPER value (%d)",
+ p_cb->acc_active);
+ }
+ if(p_rsp)
+ {
+ switch (status)
+ {
+ case BTA_FS_CO_OK:
+ rsp_code = OBX_RSP_OK;
+ break;
+ case BTA_FS_CO_ENOTEMPTY:
+ rsp_code = OBX_RSP_PRECONDTN_FAILED;
+ break;
+ case BTA_FS_CO_EACCES:
+ rsp_code = OBX_RSP_UNAUTHORIZED;
+ break;
+ default:
+ rsp_code = OBX_RSP_INTRNL_SRVR_ERR;
+ }
+ utl_freebuf((void**)&p_cb->p_name);
+ utl_freebuf((void**)&p_cb->p_path);
+ utl_freebuf((void**)&p_cb->p_dest);
+
+ p_cb->obx_oper = FTS_OP_NONE;
+ (*p_rsp)(p_cb->obx_handle, rsp_code, (BT_HDR *)NULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_fts_api_close
+**
+** Description Handle an api close event.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fts_api_close(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data)
+{
+ BD_ADDR bd_addr;
+ if (OBX_GetPeerAddr(p_cb->obx_handle, bd_addr) != 0)
+ {
+ /* resources will be freed at BTA_PBS_OBX_CLOSE_EVT */
+ OBX_DisconnectRsp(p_cb->obx_handle, OBX_RSP_SERVICE_UNAVL, NULL);
+ }
+ else
+ {
+ p_cb->p_cback(BTA_FTS_CLOSE_EVT, 0);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_fts_ci_write
+**
+** Description Continue with the current write operation
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fts_ci_write(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data)
+{
+ UINT8 rsp_code = OBX_RSP_INTRNL_SRVR_ERR;
+
+ p_cb->cout_active = FALSE;
+
+ if (p_cb->disabling)
+ {
+ bta_fts_sm_execute(p_cb,BTA_FTS_DISABLE_CMPL_EVT, p_data);
+ }
+
+ /* Process write call-in event if operation is still active */
+ if (p_cb->obx_oper == FTS_OP_PUT_FILE)
+ {
+ if (p_data->write_evt.status == BTA_FS_CO_OK)
+ rsp_code = OBX_RSP_OK;
+ else
+ {
+ if (p_data->write_evt.status == BTA_FS_CO_ENOSPACE)
+ rsp_code = OBX_RSP_DATABASE_FULL;
+ bta_fts_clean_getput(p_cb, TRUE);
+ }
+
+ /* Process response to OBX client */
+ bta_fts_put_file_rsp(rsp_code);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_fts_ci_read
+**
+** Description Handles the response to a read call-out request.
+** This is called within the OBX get file request. If the
+** operation has completed, the OBX response is sent out;
+** otherwise a read for additional data is made.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fts_ci_read(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data)
+{
+ tBTA_FS_CI_READ_EVT *p_revt = &p_data->read_evt;
+ UINT8 rsp_code = OBX_RSP_INTRNL_SRVR_ERR;
+
+ p_cb->cout_active = FALSE;
+
+ if (p_cb->disabling)
+ {
+ bta_fts_sm_execute(p_cb,BTA_FTS_DISABLE_CMPL_EVT, p_data);
+ }
+
+ /* Process read call-in event if operation is still active */
+ if (p_cb->obx_oper == FTS_OP_GET_FILE && p_revt->fd == p_cb->fd)
+ {
+ /* Read was successful, not finished yet */
+ if (p_revt->status == BTA_FS_CO_OK)
+ rsp_code = OBX_RSP_CONTINUE;
+
+ /* Read was successful, end of file has been detected */
+ else if (p_revt->status == BTA_FS_CO_EOF)
+ rsp_code = OBX_RSP_OK;
+
+ /* Process response to OBX client */
+ bta_fts_get_file_rsp(rsp_code, p_revt->num_read);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_fts_ci_resume
+**
+** Description Continue with the current file open operation
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fts_ci_resume(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data)
+{
+ tBTA_UTL_COD cod;
+
+ p_cb->state = BTA_FTS_LISTEN_ST;
+ APPL_TRACE_EVENT1("bta_fts_ci_resume status:%d", p_data->resume_evt.status);
+ /* Set the File Transfer service class bit */
+ cod.service = BTM_COD_SERVICE_OBJ_TRANSFER;
+ utl_set_device_class(&cod, BTA_UTL_SET_COD_SERVICE_CLASS);
+ if (p_data->resume_evt.status == BTA_FS_CO_OK)
+ {
+ OBX_AddSuspendedSession (p_cb->obx_handle, p_data->resume_evt.p_addr,
+ p_data->resume_evt.p_sess_info, p_data->resume_evt.timeout,
+ p_data->resume_evt.ssn, p_data->resume_evt.offset);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_fts_ci_open
+**
+** Description Continue with the current file open operation
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fts_ci_open(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data)
+{
+ tBTA_FS_CI_OPEN_EVT *p_open = &p_data->open_evt;
+ UINT8 rsp_code = OBX_RSP_OK;
+ tBTA_FTS_OBX_PKT *p_obx = &p_cb->obx;
+ UINT8 num_hdrs;
+ BOOLEAN endpkt;
+
+ p_cb->cout_active = FALSE;
+
+ if (p_cb->disabling)
+ {
+ bta_fts_sm_execute(p_cb,BTA_FTS_DISABLE_CMPL_EVT, p_data);
+ }
+
+ /* If using OBEX 1.5 */
+ if ( p_cb->obx_oper & FTS_OP_RESUME)
+ {
+ /* clear the FTS_OP_RESUME when the first request is received.
+ * We may need to adjust ssn/offset */
+ if ((p_open->fd >= 0) && (p_cb->obx_oper == FTS_OP_RESUME))
+ {
+ /* file is open successfully when the resumed obex op is FTS_OP_NONE
+ * close this file */
+ bta_fs_co_close(p_open->fd, p_cb->app_id);
+ p_open->fd = BTA_FS_INVALID_FD;
+ }
+ p_cb->fd = p_open->fd;
+ return;
+ }
+
+ /* Only process file get or put operations */
+ if (p_cb->obx_oper == FTS_OP_GET_FILE)
+ {
+ /* if file is accessible read/write the first buffer of data */
+ if (p_open->status == BTA_FS_CO_OK)
+ {
+ p_cb->file_length = p_open->file_size;
+ p_cb->fd = p_open->fd;
+
+ /* Add the length header if available */
+ if (p_cb->file_length != BTA_FS_LEN_UNKNOWN)
+ {
+ OBX_AddLengthHdr(p_obx->p_pkt, p_cb->file_length);
+ if (p_cb->file_length > 0)
+ rsp_code = OBX_RSP_CONTINUE;
+ else
+ OBX_AddBodyEnd(p_obx->p_pkt, p_obx->p_start, p_obx->offset, TRUE);
+ }
+
+ /* Send continuation response with the length of the file and no body */
+ OBX_GetRsp(p_cb->obx_handle, rsp_code, (BT_HDR *)p_obx->p_pkt);
+ p_obx->p_pkt = NULL; /* Do not deallocate buffer; OBX will */
+
+ if (p_cb->file_length == 0)
+ bta_fts_clean_getput(p_cb, FALSE);
+ }
+ else
+ {
+ if (p_open->status == BTA_FS_CO_EACCES)
+ rsp_code = OBX_RSP_UNAUTHORIZED;
+ else /* File could not be found */
+ rsp_code = OBX_RSP_NOT_FOUND;
+
+ /* Send OBX response if an error occurred */
+ bta_fts_get_file_rsp(rsp_code, 0);
+ }
+ }
+ else if (p_cb->obx_oper == FTS_OP_PUT_FILE)
+ {
+ /* if file is accessible read/write the first buffer of data */
+ if (p_open->status == BTA_FS_CO_OK)
+ {
+ p_cb->fd = p_open->fd;
+
+ /* Read in start of body if there is a body header */
+ num_hdrs = OBX_ReadBodyHdr(p_obx->p_pkt, &p_obx->p_start,
+ &p_obx->bytes_left, &endpkt);
+ if (num_hdrs == 1)
+ {
+ rsp_code = OBX_RSP_PART_CONTENT; /* Do not send OBX response yet */
+ /* Initiate the writing out of the data */
+ p_cb->cout_active = TRUE;
+ bta_fs_co_write(p_cb->fd, &p_obx->p_start[p_obx->offset],
+ p_obx->bytes_left, BTA_FTS_CI_WRITE_EVT, 0,
+ p_cb->app_id);
+ }
+ else if (num_hdrs > 1) /* Cannot handle multiple body headers */
+ {
+ rsp_code = OBX_RSP_BAD_REQUEST;
+ bta_fts_clean_getput(p_cb, TRUE);
+ }
+ else /* No body: respond with an OK so client can start sending the data */
+ p_obx->bytes_left = 0;
+
+ if (rsp_code != OBX_RSP_PART_CONTENT)
+ {
+ bta_fts_put_file_rsp(rsp_code);
+ }
+ }
+ else
+ {
+ if (p_open->status == BTA_FS_CO_EACCES)
+ rsp_code = OBX_RSP_UNAUTHORIZED;
+ else if (p_open->status == BTA_FS_CO_ENOSPACE)
+ rsp_code = OBX_RSP_DATABASE_FULL;
+ else
+ rsp_code = OBX_RSP_INTRNL_SRVR_ERR;
+
+ /* Send OBX response now if an error occurred */
+ bta_fts_put_file_rsp(rsp_code);
+ }
+ }
+ /* If using OBEX 1.5 */
+ else
+ {
+ /* must be action commands BTA_FT_OPER_COPY_ACT - BTA_FT_OPER_SET_PERM*/
+ switch (p_open->status)
+ {
+ case BTA_FS_CO_OK:
+ rsp_code = OBX_RSP_OK;
+ break;
+ case BTA_FS_CO_EACCES:
+ rsp_code = OBX_RSP_UNAUTHORIZED;
+ break;
+ case BTA_FS_CO_EIS_DIR:
+ rsp_code = OBX_RSP_FORBIDDEN;
+ default:
+ rsp_code = OBX_RSP_INTRNL_SRVR_ERR;
+ }
+ utl_freebuf((void**)&p_cb->p_name);
+ utl_freebuf((void**)&p_cb->p_path);
+ utl_freebuf((void**)&p_cb->p_dest);
+ p_cb->obx_oper = FTS_OP_NONE;
+ OBX_ActionRsp(p_cb->obx_handle, rsp_code, (BT_HDR *)NULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_fts_ci_direntry
+**
+** Description Continue getting the current directory entry operation
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fts_ci_direntry(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data)
+{
+ UINT8 rsp_code;
+ BOOLEAN free_pkt = TRUE;
+
+ p_cb->cout_active = FALSE;
+
+ if (p_cb->disabling)
+ {
+ bta_fts_sm_execute(p_cb,BTA_FTS_DISABLE_CMPL_EVT, p_data);
+ }
+
+ /* Process dirent listing call-in event if operation is still active */
+ if (p_cb->obx_oper == FTS_OP_LISTING)
+ {
+ switch (p_data->getdir_evt.status)
+ {
+ case BTA_FS_CO_OK: /* Valid new entry */
+ free_pkt = FALSE;
+ if ((rsp_code = bta_fts_add_list_entry()) != OBX_RSP_PART_CONTENT)
+ bta_fts_end_of_list(rsp_code);
+ break;
+
+ case BTA_FS_CO_EODIR: /* End of list (entry not valid) */
+ free_pkt = FALSE;
+ bta_fts_end_of_list(OBX_RSP_OK);
+ break;
+
+ case BTA_FS_CO_FAIL: /* Error occurred */
+ bta_fts_end_of_list(OBX_RSP_NOT_FOUND);
+ break;
+ }
+ }
+
+ if (free_pkt)
+ utl_freebuf((void **)&p_cb->obx.p_pkt);
+}
+
+/*******************************************************************************
+**
+** Function bta_fts_obx_connect
+**
+** Description Process the OBX connect event
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fts_obx_connect(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data)
+{
+ tBTA_FTS_OBX_EVENT *p_evt = &p_data->obx_evt;
+ tOBX_SESS_EVT *p_sess = &p_data->obx_evt.param.sess;
+
+ APPL_TRACE_DEBUG1("bta_fts_obx_connect obx_event=%d", p_evt->obx_event);
+ if (p_evt->obx_event == OBX_SESSION_REQ_EVT)
+ {
+ APPL_TRACE_EVENT3("sess_op:%d obj_offset:x%x ssn:%d", p_sess->sess_op, p_sess->obj_offset, p_sess->ssn);
+
+ BCM_STRNCPY_S(p_cb->p_workdir, p_bta_fs_cfg->max_path_len+1, p_cb->p_rootpath, p_bta_fs_cfg->max_path_len);
+ p_cb->p_workdir[p_bta_fs_cfg->max_path_len] = '\0';
+
+ bta_fs_co_session_info(p_cb->bd_addr, p_sess->p_sess_info, p_sess->ssn,
+ BTA_FS_CO_SESS_ST_ACTIVE, p_cb->p_workdir, &p_cb->obx_oper, p_cb->app_id);
+ APPL_TRACE_DEBUG1("obx_oper:%d", p_cb->obx_oper);
+ if (p_sess->sess_op == OBX_SESS_OP_CREATE)
+ {
+ p_cb->state = BTA_FTS_LISTEN_ST;
+ p_cb->obx_oper = FTS_OP_NONE;
+ }
+ else if (p_sess->sess_op == OBX_SESS_OP_RESUME)
+ {
+ p_cb->state = BTA_FTS_LISTEN_ST;
+ p_cb->resume_ssn = p_sess->ssn;
+ APPL_TRACE_EVENT1("resume ssn:%d", p_sess->ssn);
+ if (p_cb->obx_oper)
+ {
+ bta_fs_co_resume_op(p_sess->obj_offset, BTA_FTS_CI_OPEN_EVT, p_cb->app_id);
+ p_cb->obx_oper |= FTS_OP_RESUME;
+ }
+ }
+ return;
+ }
+
+ p_cb->peer_mtu = p_evt->param.conn.mtu;
+ memcpy(p_cb->bd_addr, p_evt->param.conn.peer_addr, BD_ADDR_LEN);
+ APPL_TRACE_EVENT2("FTS Connect: peer mtu 0x%04x handle:0x%x", p_cb->peer_mtu, p_evt->handle);
+
+ if (!p_evt->param.conn.no_rsp)
+ {
+ OBX_ConnectRsp(p_evt->handle, OBX_RSP_OK, (BT_HDR *)NULL);
+
+ /* Reset to the root directory */
+ BCM_STRNCPY_S(p_cb->p_workdir, p_bta_fs_cfg->max_path_len+1, p_cb->p_rootpath, p_bta_fs_cfg->max_path_len);
+ p_cb->p_workdir[p_bta_fs_cfg->max_path_len] = '\0';
+
+ bta_fs_co_setdir(p_cb->p_workdir, p_cb->app_id);
+ }
+
+ /* inform role manager */
+ bta_sys_conn_open( BTA_ID_FTS, p_cb->app_id, p_cb->bd_addr);
+
+ /* Notify the MMI that a connection has been opened */
+ p_cb->p_cback(BTA_FTS_OPEN_EVT, (tBTA_FTS*)p_cb->bd_addr);
+
+ /* Done with Obex packet */
+ utl_freebuf((void**)&p_evt->p_pkt);
+}
+
+/*******************************************************************************
+**
+** Function bta_fts_obx_disc
+**
+** Description Process the OBX disconnect event
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fts_obx_disc(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data)
+{
+ tBTA_FTS_OBX_EVENT *p_evt = &p_data->obx_evt;
+ UINT8 rsp_code;
+
+ rsp_code = (p_evt->obx_event == OBX_DISCONNECT_REQ_EVT) ? OBX_RSP_OK
+ : OBX_RSP_BAD_REQUEST;
+ OBX_DisconnectRsp(p_evt->handle, rsp_code, (BT_HDR *)NULL);
+
+ /* Done with Obex packet */
+ utl_freebuf((void**)&p_evt->p_pkt);
+}
+
+/*******************************************************************************
+**
+** Function bta_fts_obx_close
+**
+** Description Process the OBX link lost event
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fts_obx_close(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data)
+{
+ /* finished if not waiting on a call-in function */
+ if (!p_cb->cout_active)
+ bta_fts_sm_execute(p_cb, BTA_FTS_CLOSE_CMPL_EVT, p_data);
+}
+
+/*******************************************************************************
+**
+** Function bta_fts_obx_abort
+**
+** Description Process the OBX abort event
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fts_obx_abort(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data)
+{
+ tBTA_FTS_OBX_EVENT *p_evt = &p_data->obx_evt;
+ UINT8 rsp_code = OBX_RSP_OK;
+
+ utl_freebuf((void**)&p_evt->p_pkt);
+
+ switch (p_cb->obx_oper)
+ {
+ case FTS_OP_LISTING:
+ utl_freebuf((void**)&p_cb->obx.p_pkt);
+ bta_fts_clean_list(p_cb);
+ break;
+
+ case FTS_OP_GET_FILE:
+ case FTS_OP_PUT_FILE:
+ bta_fts_clean_getput(p_cb, TRUE);
+ break;
+
+ default: /* Reply OK to the client */
+ rsp_code = OBX_RSP_BAD_REQUEST;
+ }
+
+ OBX_AbortRsp(p_cb->obx_handle, rsp_code, (BT_HDR *)NULL);
+}
+
+/*******************************************************************************
+**
+** Function bta_fts_obx_password
+**
+** Description Process the OBX password request
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fts_obx_password(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data)
+{
+ tBTA_FTS_OBX_EVENT *p_evt = &p_data->obx_evt;
+ tBTA_FTS_AUTH *p_auth;
+ BOOLEAN is_challenged;
+ tOBX_AUTH_OPT options;
+
+ if ((p_auth = (tBTA_FTS_AUTH *)GKI_getbuf(sizeof(tBTA_FTS_AUTH))) != NULL)
+ {
+ memset(p_auth, 0, sizeof(tBTA_FTS_AUTH));
+
+ /* Extract user id from packet (if available) */
+ if (OBX_ReadAuthParams(p_data->obx_evt.p_pkt, &p_auth->p_userid,
+ &p_auth->userid_len,
+ &is_challenged, &options))
+ {
+ if (options & OBX_AO_USR_ID)
+ p_auth->userid_required = TRUE;
+ }
+
+ /* Don't need OBX packet any longer */
+ utl_freebuf((void**)&p_evt->p_pkt);
+
+ /* Notify application */
+ p_cb->p_cback(BTA_FTS_AUTH_EVT, (tBTA_FTS *)p_auth);
+
+ GKI_freebuf(p_auth);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_fts_obx_put
+**
+** Description Process the OBX file put and delete file/folder events
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fts_obx_put(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data)
+{
+ tBTA_FTS_OBX_EVENT *p_evt = &p_data->obx_evt;
+ UINT8 rsp_code = OBX_RSP_OK;
+ BOOLEAN rsp_now = TRUE;
+ BOOLEAN free_in_pkt = TRUE;
+ UINT8 obx_oper = bta_fts_cb.obx_oper;
+ tBTA_FTS_OBX_PKT *p_obx = &p_cb->obx;
+ UINT8 num_hdrs;
+ BOOLEAN endpkt;
+
+ APPL_TRACE_EVENT1("bta_fts_obx_put oper=x%x", p_cb->obx_oper);
+
+ /* If using OBEX 1.5 */
+ if ( p_cb->obx_oper & FTS_OP_RESUME)
+ {
+ APPL_TRACE_EVENT2("bta_fts_obx_put ssn:%d resume ssn:%d", p_evt->param.get.ssn, p_cb->resume_ssn);
+ p_cb->obx_oper &= ~FTS_OP_RESUME;
+ num_hdrs = OBX_ReadBodyHdr(p_obx->p_pkt, &p_obx->p_start,
+ &p_obx->bytes_left, &endpkt);
+ if ((p_evt->param.get.ssn != p_cb->resume_ssn) && (p_cb->fd >= 0))
+ {
+ if ((p_cb->obx_oper == FTS_OP_PUT_FILE) && (num_hdrs == 0) && ((p_evt->param.get.ssn + 1) == p_cb->resume_ssn))
+ {
+ APPL_TRACE_EVENT0("client did not get the last PUT response. Just want another response pkt");
+ }
+ else
+ bta_fs_co_sess_ssn(p_cb->fd, p_evt->param.put.ssn, p_cb->app_id);
+ }
+ }
+
+ /* If currently processing a PUT, use the current name */
+ if (bta_fts_cb.obx_oper == FTS_OP_PUT_FILE)
+ {
+ free_in_pkt = FALSE; /* Hang on to Obx packet until done */
+ bta_fts_proc_put_file(p_evt->p_pkt, p_cb->p_name, p_evt->param.put.final, obx_oper);
+ rsp_now = FALSE; /* Response sent after processing the request */
+ }
+ else /* This is a new request */
+ {
+ /* Pull out the name header if it exists */
+ if ((p_cb->p_name = (char *)GKI_getbuf((UINT16)(p_bta_fs_cfg->max_file_len + 1))) != NULL)
+ {
+ if (OBX_ReadUtf8NameHdr(p_evt->p_pkt, (UINT8 *) p_cb->p_name, p_bta_fs_cfg->max_file_len))
+ {
+ /* Is Put operation Delete, Create, or Put */
+ if (p_evt->param.put.type == OBX_PT_DELETE)
+ {
+ APPL_TRACE_EVENT1("FTS File/Folder Delete: Name [%s]", p_cb->p_name);
+ bta_fts_delete(p_evt, p_cb->p_name);
+ utl_freebuf((void**)&p_cb->p_name);
+ }
+ else /* File Put or File Create */
+ {
+ free_in_pkt = FALSE; /* Hang on to Obx packet until done */
+ APPL_TRACE_EVENT1("FTS File Put: Name [%s]", p_cb->p_name);
+ bta_fts_proc_put_file(p_evt->p_pkt, p_cb->p_name, p_evt->param.put.final, obx_oper);
+ }
+
+ rsp_now = FALSE; /* Response sent after processing the request */
+ }
+ else /* Must have a name header */
+ {
+ utl_freebuf((void**)&p_cb->p_name);
+ rsp_code = OBX_RSP_BAD_REQUEST;
+ }
+ }
+ else
+ rsp_code = OBX_RSP_INTRNL_SRVR_ERR;
+ }
+
+ /* Respond right away if an error has been detected processing request */
+ if (rsp_now)
+ OBX_PutRsp(p_evt->handle, rsp_code, (BT_HDR *)NULL);
+
+ /* Done with Obex packet */
+ if (free_in_pkt)
+ utl_freebuf((void**)&p_evt->p_pkt);
+
+}
+
+/*******************************************************************************
+**
+** Function bta_fts_obx_get
+**
+** Description Process the OBX file get and folder listing events
+** If the type header is not folder listing, then pulling a file.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fts_obx_get(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data)
+{
+ tBTA_FTS_OBX_EVENT *p_evt = &p_data->obx_evt;
+ UINT16 len;
+ BOOLEAN is_file_get = TRUE; /* Set to false if folder listing */
+ UINT8 *p_type;
+
+ APPL_TRACE_EVENT1("bta_fts_obx_get:%d", bta_fts_cb.obx_oper);
+
+ /* If using OBEX 1.5 */
+ if ( p_cb->obx_oper & FTS_OP_RESUME)
+ {
+ p_cb->obx_oper &= ~FTS_OP_RESUME;
+ APPL_TRACE_DEBUG3("ssn:%d resume ssn:%d, op:%d", p_evt->param.get.ssn, p_cb->resume_ssn, bta_fts_cb.obx_oper );
+ if (bta_fts_cb.obx_oper == FTS_OP_LISTING)
+ {
+ /* abort the listing */
+ bta_fts_end_of_list(OBX_RSP_INTRNL_SRVR_ERR);
+ return;
+ }
+ else if ((p_evt->param.get.ssn != p_cb->resume_ssn) && (p_cb->fd >= 0))
+ {
+ APPL_TRACE_EVENT2("ssn:%d resume ssn:%d", p_evt->param.get.ssn, p_cb->resume_ssn);
+ bta_fs_co_sess_ssn(p_cb->fd, p_evt->param.get.ssn, p_cb->app_id);
+ }
+ }
+
+ /* If currently processing a GET, use the current name */
+ if (bta_fts_cb.obx_oper == FTS_OP_LISTING)
+ bta_fts_getdirlist(p_cb->p_name);
+ else if (bta_fts_cb.obx_oper == FTS_OP_GET_FILE)
+ bta_fts_proc_get_file(p_cb->p_name);
+
+ else /* This is a new request */
+ {
+ /* Pull out the name header if it exists */
+ if ((p_cb->p_name = (char *)GKI_getbuf((UINT16)(p_bta_fs_cfg->max_file_len + 1))) != NULL)
+ {
+ if (!OBX_ReadUtf8NameHdr(p_evt->p_pkt, (UINT8 *)p_cb->p_name, p_bta_fs_cfg->max_file_len))
+ {
+ GKI_freebuf(p_cb->p_name);
+ p_cb->p_name = NULL;
+ }
+ }
+
+ /* See if getting a folder listing */
+ if (OBX_ReadTypeHdr(p_evt->p_pkt, &p_type, &len))
+ {
+ if (!memcmp(p_type, BTA_FTS_FOLDER_LISTING_TYPE, len))
+ {
+ is_file_get = FALSE;
+ bta_fts_getdirlist(p_cb->p_name);
+ }
+ }
+
+ /* Initiate the Get File request if not folder listing */
+ if (is_file_get)
+ {
+ if (p_cb->p_name)
+ {
+ APPL_TRACE_EVENT1("FTS File Get: Name [%s]", p_cb->p_name);
+ }
+ bta_fts_proc_get_file(p_cb->p_name);
+ }
+ }
+
+ /* Done with Obex packet */
+ utl_freebuf((void**)&p_evt->p_pkt);
+}
+
+/*******************************************************************************
+**
+** Function bta_fts_obx_setpath
+**
+** Description Process the FTP change or make directory requests
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fts_obx_setpath(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data)
+{
+ tBTA_FTS_OBX_EVENT *p_evt = &p_data->obx_evt;
+ UINT8 rsp_code = OBX_RSP_BAD_REQUEST;
+ tOBX_SETPATH_FLAG *p_flag = &p_evt->param.sp.flag;
+ tBTA_FT_OPER ft_op = 0;
+
+ /* Verify flags and handle before accepting */
+ if (p_evt->handle == p_cb->obx_handle &&
+ (((*p_flag) & FLAGS_ARE_MASK) != FLAGS_ARE_ILLEGAL))
+ {
+ p_cb->p_name = (char *)GKI_getbuf((UINT16)(p_bta_fs_cfg->max_file_len + 1));
+ p_cb->p_path = (char *)GKI_getbuf((UINT16)(p_bta_fs_cfg->max_path_len +
+ p_bta_fs_cfg->max_file_len + 2));
+ if (p_cb->p_name != NULL && p_cb->p_path != NULL)
+ {
+ if (!OBX_ReadUtf8NameHdr(p_evt->p_pkt, (UINT8 *)p_cb->p_name, p_bta_fs_cfg->max_file_len))
+ {
+ utl_freebuf((void **)&p_cb->p_name); /* no name header */
+ }
+ else if (!p_cb->p_name)
+ {
+ /* empty name header set to null terminated string */
+ p_cb->p_name[0] = '\0';
+ }
+
+
+ /* Determine if operation is mkdir */
+ if (!((*p_flag) & OBX_SPF_NO_CREATE))
+ {
+ rsp_code = bta_fts_mkdir(p_evt->p_pkt, &ft_op);
+
+ /* If the directory already exists, silently perform change directory */
+ if(rsp_code == OBX_RSP_CONTINUE)
+ {
+ /* Note BACKUP flag must be FALSE for mkdir operation */
+ rsp_code = bta_fts_chdir(p_evt->p_pkt, FALSE, &ft_op);
+ }
+ }
+ else /* Operation is chdir */
+ rsp_code = bta_fts_chdir(p_evt->p_pkt, (BOOLEAN)((*p_flag) & OBX_SPF_BACKUP), &ft_op);
+ }
+ else
+ rsp_code = OBX_RSP_INTRNL_SRVR_ERR;
+ }
+
+ if (ft_op)
+ {
+ bta_fts_req_app_access(ft_op, p_cb);
+ }
+ else
+ {
+ OBX_SetPathRsp(p_evt->handle, rsp_code, (BT_HDR *)NULL);
+ utl_freebuf((void**)&p_cb->p_name);
+ utl_freebuf((void**)&p_cb->p_path);
+ }
+
+ /* Done with Obex packet */
+ utl_freebuf((void**)&p_evt->p_pkt);
+}
+
+/* Using OBEX 1.5 */
+/*******************************************************************************
+**
+** Function bta_fts_obx_action
+**
+** Description Process the FTP action requests
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fts_obx_action(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data)
+{
+ tBTA_FTS_OBX_EVENT *p_evt = &p_data->obx_evt;
+ UINT8 rsp_code = OBX_RSP_BAD_REQUEST;
+ tBTA_FT_OPER ft_op = 0;
+ UINT8 action;
+ BOOLEAN is_dir;
+ BOOLEAN has_perms = FALSE;
+ char *p_dest_name = NULL;
+ char *p_newpath = NULL;
+
+ /* Verify flags and handle before accepting */
+ if (p_evt->handle == p_cb->obx_handle )
+ {
+ if (OBX_ReadActionIdHdr(p_evt->p_pkt, &action))
+ {
+ p_cb->p_name = (char *)GKI_getbuf((UINT16)(p_bta_fs_cfg->max_file_len + 1));
+ p_cb->p_path = (char *)GKI_getbuf((UINT16)(p_bta_fs_cfg->max_path_len +
+ p_bta_fs_cfg->max_file_len + 2));
+ p_newpath = p_cb->p_path;
+ if ((p_cb->p_name != NULL) && (p_cb->p_path != NULL) &&
+ ((strlen(p_cb->p_name) + strlen(p_cb->p_workdir) + 1) <= p_bta_fs_cfg->max_path_len))
+
+ {
+ if (OBX_ReadUtf8NameHdr(p_evt->p_pkt, (UINT8 *)p_cb->p_name, p_bta_fs_cfg->max_file_len) &&
+ p_cb->p_name[0])
+ {
+ /* the packet has non-empty name header */
+ sprintf(p_newpath, "%s%c%s", p_cb->p_workdir,
+ p_bta_fs_cfg->path_separator, p_cb->p_name);
+ if (((bta_fs_co_access(p_newpath, BTA_FS_ACC_EXIST,
+ &is_dir, p_cb->app_id)) == BTA_FS_CO_OK))
+ {
+ /* the src object exists */
+ ft_op = BTA_FT_OPER_COPY_ACT + action;
+ }
+ else
+ rsp_code = OBX_RSP_NOT_FOUND;
+ }
+
+ if (ft_op)
+ {
+ memset (p_cb->perms, 0, BTA_FS_PERM_SIZE);
+ /* it's SetPermission -> need Permission Header */
+ if (OBX_ReadPermissionHdr(p_evt->p_pkt, &p_cb->perms[BTA_FS_PERM_USER],
+ &p_cb->perms[BTA_FS_PERM_GROUP], &p_cb->perms[BTA_FS_PERM_OTHER]))
+ {
+ has_perms = TRUE;
+ }
+ if (action != BTA_FT_ACT_PERMISSION)
+ {
+ /* it's Move or Copy -> need DestName Header */
+ p_dest_name = (char *)GKI_getbuf((UINT16)(p_bta_fs_cfg->max_file_len + 1));
+ p_cb->p_dest = (char *)GKI_getbuf((UINT16)(p_bta_fs_cfg->max_path_len +
+ p_bta_fs_cfg->max_file_len + 2));
+ p_newpath = p_cb->p_dest;
+ if (p_dest_name && p_cb->p_dest)
+ {
+ if (OBX_ReadUtf8DestNameHdr(p_evt->p_pkt, (UINT8 *)p_dest_name, p_bta_fs_cfg->max_file_len) &&
+ p_dest_name[0])
+ {
+ if (p_dest_name[0] == '/' || p_dest_name[0] == '\\')
+ {
+ /* the packet has non-empty DestName header */
+ sprintf(p_newpath, "%s%c%s", p_cb->p_rootpath,
+ p_bta_fs_cfg->path_separator, p_dest_name);
+ }
+ else
+ {
+ /* the packet has non-empty DestName header */
+ sprintf(p_newpath, "%s%c%s", p_cb->p_workdir,
+ p_bta_fs_cfg->path_separator, p_dest_name);
+ }
+ if (((bta_fs_co_access(p_newpath, BTA_FS_ACC_EXIST,
+ &is_dir, p_cb->app_id)) == BTA_FS_CO_FAIL))
+ {
+ /* the dest object does not exist */
+ rsp_code = OBX_RSP_OK;
+ }
+ }
+ }
+ else
+ rsp_code = OBX_RSP_INTRNL_SRVR_ERR;
+ }
+ else if (has_perms)
+ {
+ /* the SetPermission action must have the permission header */
+ rsp_code = OBX_RSP_OK;
+ }
+ }
+
+ }
+ else
+ rsp_code = OBX_RSP_INTRNL_SRVR_ERR;
+ }
+ }
+
+ if(rsp_code == OBX_RSP_OK)
+ {
+ bta_fts_req_app_access(ft_op, p_cb);
+ }
+ else
+ {
+ OBX_ActionRsp(p_evt->handle, rsp_code, (BT_HDR *)NULL);
+ utl_freebuf((void**)&p_cb->p_name);
+ utl_freebuf((void**)&p_cb->p_path);
+ utl_freebuf((void**)&p_dest_name);
+ utl_freebuf((void**)&p_cb->p_dest);
+ }
+
+ /* Done with Obex packet */
+ utl_freebuf((void**)&p_evt->p_pkt);
+}
+/* end of using OBEX 1.5 */
+
+/*******************************************************************************
+**
+** Function bta_fts_appl_tout
+**
+** Description Process the FTS application timeout event
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fts_appl_tout(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data)
+{
+}
+
+/*******************************************************************************
+**
+** Function bta_fts_conn_err_rsp
+**
+** Description Process the OBX error response
+** Connect request received in wrong state, or bad request
+** from client
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fts_conn_err_rsp(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data)
+{
+ OBX_ConnectRsp(p_data->obx_evt.handle, OBX_RSP_BAD_REQUEST, (BT_HDR *)NULL);
+}
+
+/* Using OBEX 1.5 */
+/*******************************************************************************
+**
+** Function bta_fts_session_req
+**
+** Description Process the OBX session req in connected state
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fts_session_req(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data)
+{
+ tBTA_FTS_OBX_EVENT *p_evt = &p_data->obx_evt;
+ tOBX_SESS_EVT *p_sess = &p_data->obx_evt.param.sess;
+ UINT8 rsp_code = OBX_RSP_OK;
+ UINT32 offset = 0;
+
+ if (p_evt->obx_event == OBX_SESSION_REQ_EVT)
+ {
+ APPL_TRACE_EVENT2("sess_op:%d ssn:%d", p_sess->sess_op, p_sess->ssn);
+ switch (p_sess->sess_op)
+ {
+ case OBX_SESS_OP_SUSPEND:
+ bta_fs_co_suspend(p_cb->bd_addr, p_sess->p_sess_info, p_sess->ssn, &p_sess->timeout, &offset, p_cb->obx_oper, p_cb->app_id);
+ p_cb->state = BTA_FTS_CLOSING_ST;
+ p_cb->suspending = TRUE;
+ break;
+
+ case OBX_SESS_OP_CLOSE:
+ bta_fs_co_session_info(p_cb->bd_addr, p_sess->p_sess_info, 0, BTA_FS_CO_SESS_ST_NONE, NULL, NULL, p_cb->app_id);
+ p_cb->state = BTA_FTS_CLOSING_ST;
+ break;
+
+ case OBX_SESS_OP_CREATE:
+ case OBX_SESS_OP_RESUME:
+ p_cb->state = BTA_FTS_CONN_ST;
+ rsp_code = OBX_RSP_FORBIDDEN;
+ break;
+ }
+ OBX_SessionRsp (p_evt->handle, rsp_code, p_sess->ssn, offset, NULL);
+ return;
+ }
+ else if (p_evt->obx_event == OBX_SESSION_INFO_EVT)
+ {
+ if ((p_cb->obx_oper != FTS_OP_GET_FILE) && (p_cb->obx_oper != FTS_OP_PUT_FILE) && (p_cb->obx_oper != FTS_OP_LISTING))
+ {
+ /* the other obx ops are single transaction.
+ * If the link is dropped before the transaction ends, let the client re-transmit the request */
+ p_sess->ssn--;
+ p_cb->obx_oper = FTS_OP_NONE;
+ }
+ bta_fs_co_suspend(p_cb->bd_addr, p_sess->p_sess_info, p_sess->ssn,
+ &p_sess->timeout, &offset, p_cb->obx_oper, p_cb->app_id);
+ OBX_AddSuspendedSession (p_cb->obx_handle, p_cb->bd_addr,
+ p_sess->p_sess_info, p_sess->timeout,
+ p_sess->ssn, offset);
+ p_cb->suspending = TRUE;
+ }
+ else
+ {
+ p_cb->state = BTA_FTS_CONN_ST;
+ bta_fts_conn_err_rsp (p_cb, p_data);
+ }
+}
+/* End of using OBEX 1.5 */
+
+/*******************************************************************************
+**
+** Function bta_fts_disc_err_rsp
+**
+** Description Process the OBX error response
+** Disconnect request received in wrong state, or bad request
+** from client
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fts_disc_err_rsp(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data)
+{
+ OBX_DisconnectRsp(p_data->obx_evt.handle, OBX_RSP_BAD_REQUEST, (BT_HDR *)NULL);
+}
+
+/*******************************************************************************
+**
+** Function bta_fts_gasp_err_rsp
+**
+** Description Process the OBX error response for Get, Abort, Setpath, and Put.
+**
+** The rsp_code field of tBTA_FTS_DATA (obx_evt) contains the
+** response code to be sent to OBEX, and the obx_event field
+** contains the current OBEX event.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fts_gasp_err_rsp(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data)
+{
+ tBTA_FTS_OBX_EVENT *p_evt = &p_data->obx_evt;
+ tBTA_FTS_OBX_RSP *p_rsp = NULL;
+
+ switch (p_evt->obx_event)
+ {
+ case OBX_PUT_REQ_EVT:
+ p_rsp = OBX_PutRsp;
+ break;
+ case OBX_GET_REQ_EVT:
+ p_rsp = OBX_GetRsp;
+ break;
+ case OBX_SETPATH_REQ_EVT:
+ p_rsp = OBX_SetPathRsp;
+ break;
+ case OBX_ABORT_REQ_EVT:
+ p_rsp = OBX_AbortRsp;
+ break;
+ case OBX_ACTION_REQ_EVT:
+ p_rsp = OBX_ActionRsp;
+ break;
+ }
+ if(p_rsp)
+ (*p_rsp)(p_evt->handle, p_evt->rsp_code, (BT_HDR *)NULL);
+}
+
+/*******************************************************************************
+**
+** Function bta_fts_close_complete
+**
+** Description Finishes the memory cleanup after a channel is closed.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fts_close_complete(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data)
+{
+ p_cb->cout_active = FALSE;
+ bta_fts_clean_getput(p_cb, TRUE);
+ bta_fts_clean_list(p_cb);
+
+ /* inform role manager */
+ bta_sys_conn_close( BTA_ID_FTS ,p_cb->app_id, p_cb->bd_addr);
+
+
+
+
+ /* Notify the MMI that a connection has been closed */
+ p_cb->p_cback(BTA_FTS_CLOSE_EVT, (tBTA_FTS*)p_cb->bd_addr);
+ memset(p_cb->bd_addr, 0, BD_ADDR_LEN);
+
+ if (p_data->obx_evt.p_pkt)
+ APPL_TRACE_WARNING0("FTS: OBX CLOSE CALLED WITH non-NULL Packet!!!");
+}
+
+/*******************************************************************************
+**
+** Function bta_fts_disable_cmpl
+**
+** Description Finishes the memory cleanup before shutting down server.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fts_disable_cmpl(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data)
+{
+ bta_fts_disable_cleanup(p_cb);
+}
+
+/*****************************************************************************
+** Callback Functions
+*****************************************************************************/
+/*******************************************************************************
+**
+** Function bta_fts_obx_cback
+**
+** Description OBX callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fts_obx_cback (tOBX_HANDLE handle, tOBX_EVENT obx_event,
+ tOBX_EVT_PARAM param, BT_HDR *p_pkt)
+{
+ tBTA_FTS_OBX_EVENT *p_obx_msg;
+ UINT16 event = 0;
+ UINT16 size = sizeof(tBTA_FTS_OBX_EVENT);
+
+#if BTA_FTS_DEBUG == TRUE
+ APPL_TRACE_DEBUG2("OBX Event Callback: obx_event [%s] %d", fts_obx_evt_code(obx_event), obx_event);
+#endif
+
+ switch(obx_event)
+ {
+ case OBX_SESSION_INFO_EVT: /* the session information event to resume the session. */
+ size += OBX_SESSION_INFO_SIZE;
+ /* Falls through */
+
+ case OBX_SESSION_REQ_EVT:
+ case OBX_CONNECT_REQ_EVT:
+ event = BTA_FTS_OBX_CONN_EVT;
+ break;
+ case OBX_ACTION_REQ_EVT:
+ event = BTA_FTS_OBX_ACTION_EVT;
+ break;
+ case OBX_DISCONNECT_REQ_EVT:
+ event = BTA_FTS_OBX_DISC_EVT;
+ break;
+ case OBX_PUT_REQ_EVT:
+ event = BTA_FTS_OBX_PUT_EVT;
+ break;
+ case OBX_GET_REQ_EVT:
+ event = BTA_FTS_OBX_GET_EVT;
+ break;
+ case OBX_SETPATH_REQ_EVT:
+ event = BTA_FTS_OBX_SETPATH_EVT;
+ break;
+ case OBX_ABORT_REQ_EVT:
+ event = BTA_FTS_OBX_ABORT_EVT;
+ break;
+ case OBX_CLOSE_IND_EVT:
+ event = BTA_FTS_OBX_CLOSE_EVT;
+ break;
+ case OBX_TIMEOUT_EVT:
+ break;
+ case OBX_PASSWORD_EVT:
+ event = BTA_FTS_OBX_PASSWORD_EVT;
+ break;
+ default:
+ /* Unrecognized packet; disconnect the session */
+ if (p_pkt)
+ event = BTA_FTS_OBX_DISC_EVT;
+ }
+
+ /* send event to BTA, if any */
+ if (event && (p_obx_msg =
+ (tBTA_FTS_OBX_EVENT *) GKI_getbuf(size)) != NULL)
+ {
+ p_obx_msg->hdr.event = event;
+ p_obx_msg->obx_event = obx_event;
+ p_obx_msg->handle = handle;
+ p_obx_msg->param = param;
+ p_obx_msg->p_pkt = p_pkt;
+
+ if (obx_event == OBX_SESSION_INFO_EVT)
+ {
+ p_obx_msg->param.sess.p_sess_info = (UINT8 *)(p_obx_msg + 1);
+ memcpy (p_obx_msg->param.sess.p_sess_info, param.sess.p_sess_info, OBX_SESSION_INFO_SIZE);
+ }
+
+ bta_sys_sendmsg(p_obx_msg);
+ }
+}
+
+/*****************************************************************************
+** Local FTP Event Processing Functions
+*****************************************************************************/
+/*******************************************************************************
+**
+** Function bta_fts_req_app_access
+**
+** Description Sends an access request event to the application.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fts_req_app_access (tBTA_FT_OPER oper, tBTA_FTS_CB *p_cb)
+{
+ tBTA_FTS_ACCESS *p_acc_evt;
+ char *p_devname;
+
+ /* Notify the application that a put or get file has been requested */
+ if ((p_acc_evt = (tBTA_FTS_ACCESS *)GKI_getbuf(sizeof(tBTA_FTS_ACCESS))) != NULL)
+ {
+ memset(p_acc_evt, 0, sizeof(tBTA_FTS_ACCESS));
+
+ APPL_TRACE_API1("ACCESS REQ: [%s]", p_cb->p_path);
+
+ p_acc_evt->p_name = p_cb->p_path;
+ p_acc_evt->p_dest_name = p_cb->p_dest;
+ memcpy(p_acc_evt->perms, p_cb->perms, BTA_FS_PERM_SIZE);
+
+ p_acc_evt->size = p_cb->file_length;
+ p_acc_evt->oper = p_cb->acc_active = oper;
+ bdcpy(p_acc_evt->bd_addr, p_cb->bd_addr);
+ if ((p_devname = BTM_SecReadDevName(p_cb->bd_addr)) != NULL)
+ BCM_STRNCPY_S((char *)p_acc_evt->dev_name, sizeof(p_acc_evt->dev_name), p_devname, BTM_MAX_REM_BD_NAME_LEN);
+
+ p_cb->p_cback(BTA_FTS_ACCESS_EVT, (tBTA_FTS *)p_acc_evt);
+ GKI_freebuf(p_acc_evt);
+ }
+}
+
+/*****************************************************************************
+** Debug Functions
+*****************************************************************************/
+#if BTA_FTS_DEBUG == TRUE
+
+/*******************************************************************************
+**
+** Function fts_obx_evt_code
+**
+** Description
+**
+** Returns void
+**
+*******************************************************************************/
+static char *fts_obx_evt_code(tOBX_EVENT evt_code)
+{
+ switch(evt_code)
+ {
+ case OBX_CONNECT_REQ_EVT:
+ return "OBX_CONNECT_REQ_EVT";
+ case OBX_DISCONNECT_REQ_EVT:
+ return "OBX_DISCONNECT_REQ_EVT";
+ case OBX_PUT_REQ_EVT:
+ return "OBX_PUT_REQ_EVT";
+ case OBX_GET_REQ_EVT:
+ return "OBX_GET_REQ_EVT";
+ case OBX_SETPATH_REQ_EVT:
+ return "OBX_SETPATH_REQ_EVT";
+ case OBX_ABORT_REQ_EVT:
+ return "OBX_ABORT_REQ_EVT";
+ case OBX_CLOSE_IND_EVT:
+ return "OBX_CLOSE_IND_EVT";
+ case OBX_TIMEOUT_EVT:
+ return "OBX_TIMEOUT_EVT";
+ case OBX_PASSWORD_EVT:
+ return "OBX_PASSWORD_EVT";
+ case OBX_SESSION_REQ_EVT:
+ return "OBX_SESSION_REQ_EVT";
+ case OBX_ACTION_REQ_EVT:
+ return "OBX_ACTION_REQ_EVT";
+ case OBX_SESSION_INFO_EVT:
+ return "OBX_SESSION_INFO_EVT";
+
+ default:
+ return "unknown OBX event code";
+ }
+}
+#endif /* Debug Functions */
+#endif /* BTA_FT_INCLUDED */
diff --git a/bta/ft/bta_fts_api.c b/bta/ft/bta_fts_api.c
new file mode 100644
index 0000000..be359e0
--- /dev/null
+++ b/bta/ft/bta_fts_api.c
@@ -0,0 +1,230 @@
+/*****************************************************************************
+**
+** Name: bta_fts_api.c
+**
+** Description: This is the implementation of the API for the file
+** transfer server subsystem of BTA, Widcomm's Bluetooth
+** application layer for mobile phones.
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+
+#if defined(BTA_FT_INCLUDED) && (BTA_FT_INCLUDED == TRUE)
+
+#include <string.h>
+#include "gki.h"
+#include "bta_fs_api.h"
+#include "bta_fts_int.h"
+
+// btla-specific ++
+//todo sdh
+
+/* Maximum path length supported by MMI */
+#ifndef BTA_FS_PATH_LEN
+#define BTA_FS_PATH_LEN 294
+#endif
+// btla-specific --
+
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+static const tBTA_SYS_REG bta_fts_reg =
+{
+ bta_fts_hdl_event,
+ BTA_FtsDisable
+};
+
+/*******************************************************************************
+**
+** Function BTA_FtsEnable
+**
+** Description Enable the file transfer server. This function must be
+** called before any other functions in the FTS API are called.
+** When the enable operation is complete the callback function
+** will be called with an BTA_FTS_ENABLE_EVT event.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_FtsEnable(tBTA_SEC sec_mask, const char *p_service_name,
+ const char *p_root_path, BOOLEAN enable_authen,
+ UINT8 realm_len, UINT8 *p_realm,
+ tBTA_FTS_CBACK *p_cback, UINT8 app_id)
+{
+ tBTA_FTS_API_ENABLE *p_buf;
+
+ /* register with BTA system manager */
+ GKI_sched_lock();
+ bta_sys_register(BTA_ID_FTS, &bta_fts_reg);
+ GKI_sched_unlock();
+
+ if ((p_buf = (tBTA_FTS_API_ENABLE *)GKI_getbuf((UINT16)(sizeof(tBTA_FTS_API_ENABLE) +
+ p_bta_fs_cfg->max_path_len + 1))) != NULL)
+ {
+ memset(p_buf, 0, sizeof(tBTA_FTS_API_ENABLE));
+
+ p_buf->p_root_path = (char *)(p_buf + 1);
+ p_buf->p_root_path[p_bta_fs_cfg->max_path_len] = '\0';
+
+ p_buf->hdr.event = BTA_FTS_API_ENABLE_EVT;
+ p_buf->p_cback = p_cback;
+ p_buf->sec_mask = sec_mask;
+ p_buf->app_id = app_id;
+ p_buf->auth_enabled = enable_authen;
+
+ p_buf->realm_len = (realm_len < OBX_MAX_REALM_LEN) ? realm_len :
+ OBX_MAX_REALM_LEN;
+ if (p_realm)
+ memcpy(p_buf->realm, p_realm, p_buf->realm_len);
+
+ if (p_service_name)
+ BCM_STRNCPY_S(p_buf->servicename, sizeof(p_buf->servicename), p_service_name, BTA_SERVICE_NAME_LEN);
+
+ if (p_root_path)
+ {
+ BCM_STRNCPY_S(p_buf->p_root_path, p_bta_fs_cfg->max_path_len+1, p_root_path,
+ p_bta_fs_cfg->max_path_len);
+ p_buf->p_root_path[p_bta_fs_cfg->max_path_len] = '\0';
+ }
+
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_FtsDisable
+**
+** Description Disable the file transfer server. If the server is currently
+** connected to a peer device the connection will be closed.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_FtsDisable(void)
+{
+ BT_HDR *p_buf;
+
+ bta_sys_deregister(BTA_ID_FTS);
+ if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->event = BTA_FTS_API_DISABLE_EVT;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_FtsClose
+**
+** Description Close the current connection. This function is called if
+** the phone wishes to close the connection before the FT
+** client disconnects.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_FtsClose(void)
+{
+ BT_HDR *p_buf;
+
+ if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->event = BTA_FTS_API_CLOSE_EVT;
+
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_FtsUnauthRsp
+**
+** Description Sends an OBEX authentication challenge to the connected
+** OBEX client. Called in response to an BTA_FTS_AUTH_EVT event.
+** Used when "enable_authen" is set to TRUE in BTA_FtsEnable().
+**
+** Note: If the "userid_required" is TRUE in the BTA_FTS_AUTH_EVT
+** event, then p_userid is required, otherwise it is optional.
+**
+** p_password must be less than BTA_FTS_MAX_AUTH_KEY_SIZE
+** p_userid must be less than OBX_MAX_REALM_LEN
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_FtsAuthRsp (char *p_password, char *p_userid)
+{
+ tBTA_FTS_API_AUTHRSP *p_auth_rsp;
+
+ if ((p_auth_rsp = (tBTA_FTS_API_AUTHRSP *)GKI_getbuf(sizeof(tBTA_FTS_API_AUTHRSP))) != NULL)
+ {
+ memset(p_auth_rsp, 0, sizeof(tBTA_FTS_API_AUTHRSP));
+
+ p_auth_rsp->hdr.event = BTA_FTS_API_AUTHRSP_EVT;
+
+ if (p_password)
+ {
+ p_auth_rsp->key_len = strlen(p_password);
+ if (p_auth_rsp->key_len > BTA_FTS_MAX_AUTH_KEY_SIZE)
+ p_auth_rsp->key_len = BTA_FTS_MAX_AUTH_KEY_SIZE;
+ memcpy(p_auth_rsp->key, p_password, p_auth_rsp->key_len);
+ }
+
+ if (p_userid)
+ {
+ p_auth_rsp->userid_len = strlen(p_userid);
+ if (p_auth_rsp->userid_len > OBX_MAX_REALM_LEN)
+ p_auth_rsp->userid_len = OBX_MAX_REALM_LEN;
+ memcpy(p_auth_rsp->userid, p_userid, p_auth_rsp->userid_len);
+ }
+
+ bta_sys_sendmsg(p_auth_rsp);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_FtsAccessRsp
+**
+** Description Sends a reply to an access request event (BTA_FTS_ACCESS_EVT).
+** This call MUST be made whenever the event occurs.
+**
+** Parameters oper - operation being accessed.
+** access - BTA_FT_ACCESS_ALLOW or BTA_FT_ACCESS_FORBID
+** p_name - Full path of file to pulled or pushed.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_FtsAccessRsp(tBTA_FT_OPER oper, tBTA_FT_ACCESS access, char *p_name)
+{
+ tBTA_FTS_API_ACCESSRSP *p_acc_rsp;
+
+ if ((p_acc_rsp = (tBTA_FTS_API_ACCESSRSP *)GKI_getbuf((UINT16)(sizeof(tBTA_FTS_API_ACCESSRSP)
+ + p_bta_fs_cfg->max_path_len + 1))) != NULL)
+ {
+ p_acc_rsp->flag = access;
+ p_acc_rsp->oper = oper;
+ p_acc_rsp->p_name = (char *)(p_acc_rsp + 1);
+ if (p_name)
+ {
+ BCM_STRNCPY_S(p_acc_rsp->p_name, BTA_FS_PATH_LEN, p_name, p_bta_fs_cfg->max_path_len-1);
+ p_acc_rsp->p_name[p_bta_fs_cfg->max_path_len-1] = '\0';
+ }
+ else
+ *p_acc_rsp->p_name = '\0';
+
+ p_acc_rsp->hdr.event = BTA_FTS_API_ACCESSRSP_EVT;
+ bta_sys_sendmsg(p_acc_rsp);
+ }
+}
+#endif /* BTA_FT_INCLUDED */
diff --git a/bta/ft/bta_fts_int.h b/bta/ft/bta_fts_int.h
new file mode 100644
index 0000000..b77c96f
--- /dev/null
+++ b/bta/ft/bta_fts_int.h
@@ -0,0 +1,287 @@
+/*****************************************************************************
+**
+** Name: bta_fts_int.h
+**
+** Description: This is the private file for the file transfer
+** server (FTS).
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_FTS_INT_H
+#define BTA_FTS_INT_H
+
+#include "bt_target.h"
+#include "bta_sys.h"
+#include "obx_api.h"
+#include "bta_ft_api.h"
+#include "bta_fs_co.h"
+#include "bta_fs_ci.h"
+#include "bta_ftc_int.h"
+
+/*****************************************************************************
+** Constants and data types
+*****************************************************************************/
+
+
+
+#define BTA_FTS_FOLDER_BROWSING_TARGET_UUID "\xF9\xEC\x7B\xC4\x95\x3C\x11\xD2\x98\x4E\x52\x54\x00\xDC\x9E\x09"
+#define BTA_FTS_UUID_LENGTH 16
+#define BTA_FTS_MAX_AUTH_KEY_SIZE 16 /* Must not be greater than OBX_MAX_AUTH_KEY_SIZE */
+
+#define BTA_FTS_DEFAULT_VERSION 0x0100
+#define BTA_FTS_FOLDER_LISTING_TYPE "x-obex/folder-listing"
+
+typedef tOBX_STATUS (tBTA_FTS_OBX_RSP) (tOBX_HANDLE handle, UINT8 rsp_code, BT_HDR *p_pkt);
+
+/* FTS Active ftp obex operation (Valid in connected state) */
+#define FTS_OP_NONE 0
+#define FTS_OP_LISTING 1
+#define FTS_OP_GET_FILE 2
+#define FTS_OP_PUT_FILE 3
+#define FTS_OP_DELETE 4 /* Folder or File */
+#define FTS_OP_CHDIR 5
+#define FTS_OP_MKDIR 6
+#define FTS_OP_RESUME 0x10
+
+/* state machine states */
+enum
+{
+ BTA_FTS_IDLE_ST = 0, /* Idle */
+ BTA_FTS_LISTEN_ST, /* Listen - waiting for OBX/RFC connection */
+ BTA_FTS_W4_AUTH_ST, /* Wait for Authentication - (optional) */
+ BTA_FTS_CONN_ST, /* Connected - FTP Session is active */
+ BTA_FTS_CLOSING_ST /* Closing is in progress */
+};
+
+/* state machine events */
+enum
+{
+ /* these events are handled by the state machine */
+ BTA_FTS_API_DISABLE_EVT = BTA_SYS_EVT_START(BTA_ID_FTS),
+
+ BTA_FTS_API_AUTHRSP_EVT, /* Response to password request */
+ BTA_FTS_API_ACCESSRSP_EVT, /* Response to an access request */
+ BTA_FTS_API_CLOSE_EVT, /* Disconnect the OBEX channel */
+ BTA_FTS_CI_WRITE_EVT, /* Response to Write request */
+ BTA_FTS_CI_READ_EVT, /* Response to Read request */
+ BTA_FTS_CI_OPEN_EVT, /* Response to File Open request */
+ BTA_FTS_CI_DIRENTRY_EVT, /* Response to a directory entry request */
+ BTA_FTS_OBX_CONN_EVT, /* OBX Channel Connect Request */
+ BTA_FTS_OBX_DISC_EVT, /* OBX Channel Disconnect */
+ BTA_FTS_OBX_ABORT_EVT, /* OBX_operation aborted */
+ BTA_FTS_OBX_PASSWORD_EVT, /* OBX password requested */
+ BTA_FTS_OBX_CLOSE_EVT, /* OBX Channel Disconnected (Link Lost) */
+ BTA_FTS_OBX_PUT_EVT, /* Write file data or delete */
+ BTA_FTS_OBX_GET_EVT, /* Read file data or folder listing */
+ BTA_FTS_OBX_SETPATH_EVT, /* Make or Change Directory */
+ BTA_FTS_CI_SESSION_EVT, /* Call-in response to session requests */
+ BTA_FTS_OBX_ACTION_EVT, /* Action command */
+ BTA_FTS_APPL_TOUT_EVT, /* Timeout waiting for application */
+ BTA_FTS_DISC_ERR_EVT, /* Sends OBX_DisconnectRsp with error code */
+ BTA_FTS_GASP_ERR_EVT, /* Sends Err Resp to Get, Abort, Setpath, and Put */
+ BTA_FTS_CLOSE_CMPL_EVT, /* Finished closing channel */
+ BTA_FTS_DISABLE_CMPL_EVT, /* Finished disabling server */
+
+ /* these events are handled outside the state machine */
+ BTA_FTS_API_ENABLE_EVT
+};
+
+typedef UINT16 tBTA_FTS_INT_EVT;
+
+typedef UINT8 tBTA_FTS_STATE;
+
+/* data type for BTA_FTS_API_ENABLE_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_FTS_CBACK *p_cback;
+ char servicename[BTA_SERVICE_NAME_LEN + 1];
+ char *p_root_path;
+ UINT8 realm [OBX_MAX_REALM_LEN]; /* The realm is intended to be
+ displayed to users so they know
+ which userid and password to use.
+ The first byte of the string is
+ the character set of the string.
+ */
+ UINT8 realm_len;
+ UINT8 sec_mask;
+ UINT8 app_id;
+ BOOLEAN auth_enabled;
+} tBTA_FTS_API_ENABLE;
+
+/* data type for BTA_FTS_API_AUTHRSP_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ UINT8 key [BTA_FTS_MAX_AUTH_KEY_SIZE]; /* The authentication key.*/
+ UINT8 key_len;
+ UINT8 userid [OBX_MAX_REALM_LEN]; /* The authentication user id.*/
+ UINT8 userid_len;
+} tBTA_FTS_API_AUTHRSP;
+
+/* data type for BTA_FTS_API_ACCESSRSP_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ char *p_name;
+ tBTA_FT_OPER oper;
+ tBTA_FT_ACCESS flag;
+} tBTA_FTS_API_ACCESSRSP;
+
+/* data type for all obex events
+ hdr.event contains the FTS event
+*/
+typedef struct
+{
+ BT_HDR hdr;
+ tOBX_HANDLE handle;
+ tOBX_EVT_PARAM param;
+ BT_HDR *p_pkt;
+ tOBX_EVENT obx_event;
+ UINT8 rsp_code;
+} tBTA_FTS_OBX_EVENT;
+
+/* union of all event data types */
+typedef union
+{
+ BT_HDR hdr;
+ tBTA_FTS_API_ENABLE api_enable;
+ tBTA_FTS_API_AUTHRSP auth_rsp;
+ tBTA_FTS_API_ACCESSRSP access_rsp;
+ tBTA_FTS_OBX_EVENT obx_evt;
+ tBTA_FS_CI_GETDIR_EVT getdir_evt;
+ tBTA_FS_CI_OPEN_EVT open_evt;
+ tBTA_FS_CI_RESUME_EVT resume_evt;
+ tBTA_FS_CI_READ_EVT read_evt;
+ tBTA_FS_CI_WRITE_EVT write_evt;
+} tBTA_FTS_DATA;
+
+
+/* OBX Response Packet Structure - Holds current response packet info */
+typedef struct
+{
+ BT_HDR *p_pkt; /* (Get/Put) Holds the current OBX header for Put or Get */
+ UINT8 *p_start; /* (Get/Put) Start of the Body of the packet */
+ UINT16 offset; /* (Get/Put) Contains the current offset into the Body (p_start) */
+ UINT16 bytes_left; /* (Get/Put) Holds bytes available left in Obx packet */
+ BOOLEAN final_pkt; /* (Put) Holds the final bit of the Put packet */
+} tBTA_FTS_OBX_PKT;
+
+/* Directory Listing Information */
+typedef struct
+{
+ tBTA_FS_DIRENTRY *p_entry; /* Holds current directory entry */
+ BOOLEAN is_root; /* TRUE if path is root directory */
+} tBTA_FTS_DIRLIST;
+
+/* Power management state for FTS */
+#define BTA_FTS_PM_BUSY 0
+#define BTA_FTS_PM_IDLE 1
+
+/* FTS control block */
+typedef struct
+{
+ tBTA_FTS_CBACK *p_cback; /* pointer to application callback function */
+ char *p_name; /* Holds name of current operation */
+ char *p_dest; /* Holds p_dest_name of current operation */
+ char *p_path; /* Holds path of current operation */
+ char *p_rootpath;
+ char *p_workdir; /* Current working directory */
+ tBTA_FTS_OBX_PKT obx; /* Holds the current OBX packet information */
+ tBTA_FTS_DIRLIST dir; /* Holds current directory list information */
+ UINT32 sdp_handle; /* SDP record handle */
+ UINT32 file_length; /* length of file being PUT/GET */
+ UINT8 sess_id[OBX_SESSION_ID_SIZE]; /* session id */
+ int fd; /* File Descriptor of opened file */
+ BD_ADDR bd_addr; /* Device currently connected to */
+ tOBX_HANDLE obx_handle;
+ UINT16 peer_mtu;
+ UINT16 psm; /* PSM for Obex Over L2CAP */
+ UINT8 perms[BTA_FS_PERM_SIZE]; /* the permission */
+ UINT8 scn; /* SCN of the FTP server */
+ tBTA_FTS_STATE state; /* state machine state */
+ UINT8 obx_oper; /* current active OBX operation PUT FILE, GET FILE, LISTING, etc */
+ UINT8 app_id;
+ BOOLEAN auth_enabled; /* Is OBEX authentication enabled */
+ BOOLEAN cout_active; /* TRUE when waiting for a call-in function */
+ tBTA_FT_OPER acc_active; /* op code when waiting for an access rsp (API) (0 not active) */
+ BOOLEAN suspending; /* TRUE when suspending session */
+ UINT8 resume_ssn; /* the ssn for resume session */
+ BOOLEAN disabling; /* TRUE when disabling server */
+ UINT8 pm_state; /* power management state */
+} tBTA_FTS_CB;
+
+/*****************************************************************************
+** Global data
+*****************************************************************************/
+
+/* FTS control block */
+#if BTA_DYNAMIC_MEMORY == FALSE
+extern tBTA_FTS_CB bta_fts_cb;
+#else
+extern tBTA_FTS_CB *bta_fts_cb_ptr;
+#define bta_fts_cb (*bta_fts_cb_ptr)
+#endif
+
+/* FT configuration constants */
+extern tBTA_FT_CFG * p_bta_ft_cfg;
+
+/*****************************************************************************
+** Function prototypes
+*****************************************************************************/
+
+extern BOOLEAN bta_fts_hdl_event(BT_HDR *p_msg);
+extern void bta_fts_sm_execute(tBTA_FTS_CB *p_cb, UINT16 event, tBTA_FTS_DATA *p_data);
+extern void bta_fts_sdp_register (tBTA_FTS_CB *p_cb, char *p_service_name);
+extern void bta_fts_obx_cback (tOBX_HANDLE handle, tOBX_EVENT event,
+ tOBX_EVT_PARAM param, BT_HDR *p_pkt);
+
+/* action functions */
+extern void bta_fts_api_disable(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data);
+extern void bta_fts_api_authrsp(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data);
+extern void bta_fts_api_accessrsp(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data);
+extern void bta_fts_api_close(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data);
+extern void bta_fts_ci_write(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data);
+extern void bta_fts_ci_read(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data);
+extern void bta_fts_ci_open(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data);
+extern void bta_fts_ci_resume(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data);
+extern void bta_fts_ci_direntry(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data);
+extern void bta_fts_obx_connect(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data);
+extern void bta_fts_obx_disc(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data);
+extern void bta_fts_obx_close(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data);
+extern void bta_fts_obx_abort(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data);
+extern void bta_fts_obx_password(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data);
+extern void bta_fts_obx_put(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data);
+extern void bta_fts_obx_get(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data);
+extern void bta_fts_obx_setpath(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data);
+extern void bta_fts_obx_action(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data);
+extern void bta_fts_appl_tout(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data);
+extern void bta_fts_conn_err_rsp(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data);
+extern void bta_fts_disc_err_rsp(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data);
+extern void bta_fts_gasp_err_rsp(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data);
+extern void bta_fts_close_complete(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data);
+extern void bta_fts_disable_cmpl(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data);
+extern void bta_fts_session_req(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data);
+
+/* object store */
+extern UINT8 bta_fts_mkdir(BT_HDR *p_pkt, tBTA_FT_OPER *p_op);
+extern UINT8 bta_fts_chdir(BT_HDR *p_pkt, BOOLEAN backup_flag, tBTA_FT_OPER *p_op);
+extern void bta_fts_getdirlist(char *p_name);
+extern void bta_fts_proc_get_file(char *p_name);
+extern void bta_fts_proc_put_file(BT_HDR *p_pkt, char *p_name, BOOLEAN final_pkt, UINT8 oper);
+extern void bta_fts_delete(tBTA_FTS_OBX_EVENT *p_evt, const char *p);
+extern void bta_fts_req_app_access (tBTA_FT_OPER oper, tBTA_FTS_CB *p_cb);
+
+/* miscellaneous functions */
+extern void bta_fts_get_file_rsp(UINT8 rsp_code, UINT16 num_read);
+extern void bta_fts_put_file_rsp(UINT8 rsp_code);
+extern void bta_fts_end_of_list(UINT8 rsp_code);
+extern UINT8 bta_fts_add_list_entry(void);
+extern void bta_fts_clean_list(tBTA_FTS_CB *p_cb);
+extern void bta_fts_clean_getput(tBTA_FTS_CB *p_cb, BOOLEAN is_aborted);
+extern void bta_fts_disable_cleanup(tBTA_FTS_CB *p_cb);
+extern void bta_fts_discard_data(UINT16 event, tBTA_FTS_DATA *p_data);
+
+#endif /* BTA_FTS_INT_H */
diff --git a/bta/ft/bta_fts_main.c b/bta/ft/bta_fts_main.c
new file mode 100644
index 0000000..67be954
--- /dev/null
+++ b/bta/ft/bta_fts_main.c
@@ -0,0 +1,603 @@
+/*****************************************************************************
+**
+** Name: bta_fts_main.c
+**
+** Description: This file contains the file transfer server main functions
+** and state machine.
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include <string.h>
+
+#include "bt_target.h"
+#if defined(BTA_FT_INCLUDED) && (BTA_FT_INCLUDED == TRUE)
+
+#include "bta_fs_api.h"
+#include "bta_fts_int.h"
+#include "gki.h"
+#include "utl.h"
+#include "obx_api.h"
+#include "rfcdefs.h" /* BT_PSM_RFCOMM */
+
+/*****************************************************************************
+** Constants and types
+*****************************************************************************/
+
+
+/* state machine action enumeration list */
+enum
+{
+ BTA_FTS_API_DISABLE,
+ BTA_FTS_API_AUTHRSP,
+ BTA_FTS_API_ACCESSRSP,
+ BTA_FTS_API_CLOSE,
+ BTA_FTS_CI_WRITE,
+ BTA_FTS_CI_READ,
+ BTA_FTS_CI_OPEN,
+ BTA_FTS_CI_DIRENTRY,
+ BTA_FTS_OBX_CONNECT,
+ BTA_FTS_OBX_DISC,
+ BTA_FTS_OBX_CLOSE,
+ BTA_FTS_OBX_ABORT,
+ BTA_FTS_OBX_PASSWORD,
+ BTA_FTS_OBX_PUT,
+ BTA_FTS_OBX_GET,
+ BTA_FTS_OBX_SETPATH,
+ BTA_FTS_CI_RESUME,
+ BTA_FTS_OBX_ACTION,
+ BTA_FTS_SESSION_REQ,
+ BTA_FTS_APPL_TOUT,
+ BTA_FTS_CONN_ERR_RSP,
+ BTA_FTS_DISC_ERR_RSP,
+ BTA_FTS_GASP_ERR_RSP,
+ BTA_FTS_CLOSE_COMPLETE,
+ BTA_FTS_DISABLE_CMPL,
+ BTA_FTS_IGNORE
+};
+
+/* type for action functions */
+typedef void (*tBTA_FTS_ACTION)(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data);
+
+/* action function list */
+const tBTA_FTS_ACTION bta_fts_action[] =
+{
+ bta_fts_api_disable,
+ bta_fts_api_authrsp,
+ bta_fts_api_accessrsp,
+ bta_fts_api_close,
+ bta_fts_ci_write,
+ bta_fts_ci_read,
+ bta_fts_ci_open,
+ bta_fts_ci_direntry,
+ bta_fts_obx_connect,
+ bta_fts_obx_disc,
+ bta_fts_obx_close,
+ bta_fts_obx_abort,
+ bta_fts_obx_password,
+ bta_fts_obx_put,
+ bta_fts_obx_get,
+ bta_fts_obx_setpath,
+ bta_fts_ci_resume,
+ bta_fts_obx_action,
+ bta_fts_session_req,
+ bta_fts_appl_tout,
+ bta_fts_conn_err_rsp,
+ bta_fts_disc_err_rsp,
+ bta_fts_gasp_err_rsp,
+ bta_fts_close_complete,
+ bta_fts_disable_cmpl
+};
+
+
+/* state table information */
+#define BTA_FTS_ACTIONS 1 /* number of actions */
+#define BTA_FTS_NEXT_STATE 1 /* position of next state */
+#define BTA_FTS_NUM_COLS 2 /* number of columns in state tables */
+
+/* state table for idle state */
+static const UINT8 bta_fts_st_idle[][BTA_FTS_NUM_COLS] =
+{
+/* Event Action 1 Next state */
+/* BTA_FTS_API_ENABLE_EVT */ {BTA_FTS_IGNORE, BTA_FTS_IDLE_ST},
+/* BTA_FTS_API_AUTHRSP_EVT */ {BTA_FTS_IGNORE, BTA_FTS_IDLE_ST},
+/* BTA_FTS_API_ACCESSRSP_EVT */ {BTA_FTS_IGNORE, BTA_FTS_IDLE_ST},
+/* BTA_FTS_API_CLOSE_EVT */ {BTA_FTS_IGNORE, BTA_FTS_IDLE_ST},
+/* BTA_FTS_CI_WRITE_EVT */ {BTA_FTS_IGNORE, BTA_FTS_IDLE_ST},
+/* BTA_FTS_CI_READ_EVT */ {BTA_FTS_IGNORE, BTA_FTS_IDLE_ST},
+/* BTA_FTS_CI_OPEN_EVT */ {BTA_FTS_IGNORE, BTA_FTS_IDLE_ST},
+/* BTA_FTS_CI_DIRENTRY_EVT */ {BTA_FTS_IGNORE, BTA_FTS_IDLE_ST},
+/* BTA_FTS_OBX_CONN_EVT */ {BTA_FTS_IGNORE, BTA_FTS_IDLE_ST},
+/* BTA_FTS_OBX_DISC_EVT */ {BTA_FTS_IGNORE, BTA_FTS_IDLE_ST},
+/* BTA_FTS_OBX_ABORT_EVT */ {BTA_FTS_IGNORE, BTA_FTS_IDLE_ST},
+/* BTA_FTS_OBX_PASSWORD_EVT */ {BTA_FTS_IGNORE, BTA_FTS_IDLE_ST},
+/* BTA_FTS_OBX_CLOSE_EVT */ {BTA_FTS_IGNORE, BTA_FTS_IDLE_ST},
+/* BTA_FTS_OBX_PUT_EVT */ {BTA_FTS_IGNORE, BTA_FTS_IDLE_ST},
+/* BTA_FTS_OBX_GET_EVT */ {BTA_FTS_IGNORE, BTA_FTS_IDLE_ST},
+/* BTA_FTS_OBX_SETPATH_EVT */ {BTA_FTS_IGNORE, BTA_FTS_IDLE_ST},
+/* BTA_FTS_CI_SESSION_EVT */ {BTA_FTS_CI_RESUME, BTA_FTS_LISTEN_ST},
+/* BTA_FTS_OBX_ACTION_EVT */ {BTA_FTS_IGNORE, BTA_FTS_IDLE_ST},
+/* BTA_FTS_APPL_TOUT_EVT */ {BTA_FTS_IGNORE, BTA_FTS_IDLE_ST},
+/* BTA_FTS_DISC_ERR_EVT */ {BTA_FTS_IGNORE, BTA_FTS_IDLE_ST},
+/* BTA_FTS_GASP_ERR_EVT */ {BTA_FTS_IGNORE, BTA_FTS_IDLE_ST},
+/* BTA_FTS_CLOSE_CMPL_EVT */ {BTA_FTS_IGNORE, BTA_FTS_IDLE_ST},
+/* BTA_FTS_DISABLE_CMPL_EVT */ {BTA_FTS_IGNORE, BTA_FTS_IDLE_ST}
+};
+
+/* state table for obex/rfcomm connection state */
+static const UINT8 bta_fts_st_listen[][BTA_FTS_NUM_COLS] =
+{
+/* Event Action 1 Next state */
+/* BTA_FTS_API_DISABLE_EVT */ {BTA_FTS_API_DISABLE, BTA_FTS_LISTEN_ST},
+/* BTA_FTS_API_AUTHRSP_EVT */ {BTA_FTS_IGNORE, BTA_FTS_LISTEN_ST},
+/* BTA_FTS_API_ACCESSRSP_EVT */ {BTA_FTS_IGNORE, BTA_FTS_LISTEN_ST},
+/* BTA_FTS_API_CLOSE_EVT */ {BTA_FTS_API_CLOSE, BTA_FTS_LISTEN_ST},
+/* BTA_FTS_CI_WRITE_EVT */ {BTA_FTS_IGNORE, BTA_FTS_LISTEN_ST},
+/* BTA_FTS_CI_READ_EVT */ {BTA_FTS_IGNORE, BTA_FTS_LISTEN_ST},
+/* BTA_FTS_CI_OPEN_EVT */ {BTA_FTS_IGNORE, BTA_FTS_LISTEN_ST},
+/* BTA_FTS_CI_DIRENTRY_EVT */ {BTA_FTS_IGNORE, BTA_FTS_LISTEN_ST},
+/* BTA_FTS_OBX_CONN_EVT */ {BTA_FTS_OBX_CONNECT, BTA_FTS_CONN_ST},
+/* BTA_FTS_OBX_DISC_EVT */ {BTA_FTS_IGNORE, BTA_FTS_LISTEN_ST},
+/* BTA_FTS_OBX_ABORT_EVT */ {BTA_FTS_IGNORE, BTA_FTS_LISTEN_ST},
+/* BTA_FTS_OBX_PASSWORD_EVT */ {BTA_FTS_OBX_PASSWORD, BTA_FTS_W4_AUTH_ST},
+/* BTA_FTS_OBX_CLOSE_EVT */ {BTA_FTS_IGNORE, BTA_FTS_LISTEN_ST},
+/* BTA_FTS_OBX_PUT_EVT */ {BTA_FTS_IGNORE, BTA_FTS_LISTEN_ST},
+/* BTA_FTS_OBX_GET_EVT */ {BTA_FTS_IGNORE, BTA_FTS_LISTEN_ST},
+/* BTA_FTS_OBX_SETPATH_EVT */ {BTA_FTS_IGNORE, BTA_FTS_LISTEN_ST},
+/* BTA_FTS_CI_SESSION_EVT */ {BTA_FTS_IGNORE, BTA_FTS_LISTEN_ST},
+/* BTA_FTS_OBX_ACTION_EVT */ {BTA_FTS_IGNORE, BTA_FTS_LISTEN_ST},
+/* BTA_FTS_APPL_TOUT_EVT */ {BTA_FTS_IGNORE, BTA_FTS_LISTEN_ST},
+/* BTA_FTS_DISC_ERR_EVT */ {BTA_FTS_IGNORE, BTA_FTS_LISTEN_ST},
+/* BTA_FTS_GASP_ERR_EVT */ {BTA_FTS_IGNORE, BTA_FTS_LISTEN_ST},
+/* BTA_FTS_CLOSE_CMPL_EVT */ {BTA_FTS_IGNORE, BTA_FTS_LISTEN_ST},
+/* BTA_FTS_DISABLE_CMPL_EVT */ {BTA_FTS_DISABLE_CMPL, BTA_FTS_IDLE_ST}
+};
+
+/* state table for wait for authentication response state */
+static const UINT8 bta_fts_st_w4_auth[][BTA_FTS_NUM_COLS] =
+{
+/* Event Action 1 Next state */
+/* BTA_FTS_API_DISABLE_EVT */ {BTA_FTS_API_DISABLE, BTA_FTS_W4_AUTH_ST},
+/* BTA_FTS_API_AUTHRSP_EVT */ {BTA_FTS_API_AUTHRSP, BTA_FTS_LISTEN_ST},
+/* BTA_FTS_API_ACCESSRSP_EVT */ {BTA_FTS_IGNORE, BTA_FTS_W4_AUTH_ST},
+/* BTA_FTS_API_CLOSE_EVT */ {BTA_FTS_API_CLOSE, BTA_FTS_CLOSING_ST},
+/* BTA_FTS_CI_WRITE_EVT */ {BTA_FTS_IGNORE, BTA_FTS_W4_AUTH_ST},
+/* BTA_FTS_CI_READ_EVT */ {BTA_FTS_IGNORE, BTA_FTS_W4_AUTH_ST},
+/* BTA_FTS_CI_OPEN_EVT */ {BTA_FTS_IGNORE, BTA_FTS_W4_AUTH_ST},
+/* BTA_FTS_CI_DIRENTRY_EVT */ {BTA_FTS_IGNORE, BTA_FTS_W4_AUTH_ST},
+/* BTA_FTS_OBX_CONN_EVT */ {BTA_FTS_CONN_ERR_RSP, BTA_FTS_W4_AUTH_ST},
+/* BTA_FTS_OBX_DISC_EVT */ {BTA_FTS_OBX_DISC, BTA_FTS_W4_AUTH_ST},
+/* BTA_FTS_OBX_ABORT_EVT */ {BTA_FTS_IGNORE, BTA_FTS_W4_AUTH_ST},
+/* BTA_FTS_OBX_PASSWORD_EVT */ {BTA_FTS_IGNORE, BTA_FTS_W4_AUTH_ST},
+/* BTA_FTS_OBX_CLOSE_EVT */ {BTA_FTS_OBX_CLOSE, BTA_FTS_CLOSING_ST},
+/* BTA_FTS_OBX_PUT_EVT */ {BTA_FTS_IGNORE, BTA_FTS_W4_AUTH_ST},
+/* BTA_FTS_OBX_GET_EVT */ {BTA_FTS_IGNORE, BTA_FTS_W4_AUTH_ST},
+/* BTA_FTS_OBX_SETPATH_EVT */ {BTA_FTS_IGNORE, BTA_FTS_W4_AUTH_ST},
+/* BTA_FTS_CI_SESSION_EVT */ {BTA_FTS_IGNORE, BTA_FTS_W4_AUTH_ST},
+/* BTA_FTS_OBX_ACTION_EVT */ {BTA_FTS_IGNORE, BTA_FTS_W4_AUTH_ST},
+/* BTA_FTS_APPL_TOUT_EVT */ {BTA_FTS_APPL_TOUT, BTA_FTS_W4_AUTH_ST},
+/* BTA_FTS_DISC_ERR_EVT */ {BTA_FTS_IGNORE, BTA_FTS_W4_AUTH_ST},
+/* BTA_FTS_GASP_ERR_EVT */ {BTA_FTS_IGNORE, BTA_FTS_W4_AUTH_ST},
+/* BTA_FTS_CLOSE_CMPL_EVT */ {BTA_FTS_IGNORE, BTA_FTS_W4_AUTH_ST},
+/* BTA_FTS_DISABLE_CMPL_EVT */ {BTA_FTS_DISABLE_CMPL, BTA_FTS_IDLE_ST}
+};
+
+/* state table for open state */
+static const UINT8 bta_fts_st_connected[][BTA_FTS_NUM_COLS] =
+{
+/* Event Action 1 Next state */
+/* BTA_FTS_API_DISABLE_EVT */ {BTA_FTS_API_DISABLE, BTA_FTS_CONN_ST},
+/* BTA_FTS_API_AUTHRSP_EVT */ {BTA_FTS_IGNORE, BTA_FTS_CONN_ST},
+/* BTA_FTS_API_ACCESSRSP_EVT */ {BTA_FTS_API_ACCESSRSP, BTA_FTS_CONN_ST},
+/* BTA_FTS_API_CLOSE_EVT */ {BTA_FTS_API_CLOSE, BTA_FTS_CLOSING_ST},
+/* BTA_FTS_CI_WRITE_EVT */ {BTA_FTS_CI_WRITE, BTA_FTS_CONN_ST},
+/* BTA_FTS_CI_READ_EVT */ {BTA_FTS_CI_READ, BTA_FTS_CONN_ST},
+/* BTA_FTS_CI_OPEN_EVT */ {BTA_FTS_CI_OPEN, BTA_FTS_CONN_ST},
+/* BTA_FTS_CI_DIRENTRY_EVT */ {BTA_FTS_CI_DIRENTRY, BTA_FTS_CONN_ST},
+/* BTA_FTS_OBX_CONN_EVT */ {BTA_FTS_SESSION_REQ, BTA_FTS_CONN_ST},
+/* BTA_FTS_OBX_DISC_EVT */ {BTA_FTS_OBX_DISC, BTA_FTS_CLOSING_ST},
+/* BTA_FTS_OBX_ABORT_EVT */ {BTA_FTS_OBX_ABORT, BTA_FTS_CONN_ST},
+/* BTA_FTS_OBX_PASSWORD_EVT */ {BTA_FTS_IGNORE, BTA_FTS_W4_AUTH_ST},
+/* BTA_FTS_OBX_CLOSE_EVT */ {BTA_FTS_OBX_CLOSE, BTA_FTS_CLOSING_ST},
+/* BTA_FTS_OBX_PUT_EVT */ {BTA_FTS_OBX_PUT, BTA_FTS_CONN_ST},
+/* BTA_FTS_OBX_GET_EVT */ {BTA_FTS_OBX_GET, BTA_FTS_CONN_ST},
+/* BTA_FTS_OBX_SETPATH_EVT */ {BTA_FTS_OBX_SETPATH, BTA_FTS_CONN_ST},
+/* BTA_FTS_CI_SESSION_EVT */ {BTA_FTS_IGNORE, BTA_FTS_CONN_ST},
+/* BTA_FTS_OBX_ACTION_EVT */ {BTA_FTS_OBX_ACTION, BTA_FTS_CONN_ST},
+/* BTA_FTS_APPL_TOUT_EVT */ {BTA_FTS_APPL_TOUT, BTA_FTS_LISTEN_ST},
+/* BTA_FTS_DISC_ERR_EVT */ {BTA_FTS_IGNORE, BTA_FTS_CONN_ST},
+/* BTA_FTS_GASP_ERR_EVT */ {BTA_FTS_GASP_ERR_RSP, BTA_FTS_CONN_ST},
+/* BTA_FTS_CLOSE_CMPL_EVT */ {BTA_FTS_IGNORE, BTA_FTS_CONN_ST},
+/* BTA_FTS_DISABLE_CMPL_EVT */ {BTA_FTS_DISABLE_CMPL, BTA_FTS_IDLE_ST}
+};
+
+/* state table for closing state */
+static const UINT8 bta_fts_st_closing[][BTA_FTS_NUM_COLS] =
+{
+/* Event Action 1 Next state */
+/* BTA_FTS_API_DISABLE_EVT */ {BTA_FTS_API_DISABLE, BTA_FTS_CLOSING_ST},
+/* BTA_FTS_API_AUTHRSP_EVT */ {BTA_FTS_IGNORE, BTA_FTS_CLOSING_ST},
+/* BTA_FTS_API_ACCESSRSP_EVT */ {BTA_FTS_IGNORE, BTA_FTS_CLOSING_ST},
+/* BTA_FTS_API_CLOSE_EVT */ {BTA_FTS_IGNORE, BTA_FTS_CLOSING_ST},
+/* BTA_FTS_CI_WRITE_EVT */ {BTA_FTS_CLOSE_COMPLETE, BTA_FTS_LISTEN_ST},
+/* BTA_FTS_CI_READ_EVT */ {BTA_FTS_CLOSE_COMPLETE, BTA_FTS_LISTEN_ST},
+/* BTA_FTS_CI_OPEN_EVT */ {BTA_FTS_CLOSE_COMPLETE, BTA_FTS_LISTEN_ST},
+/* BTA_FTS_CI_DIRENTRY_EVT */ {BTA_FTS_CLOSE_COMPLETE, BTA_FTS_LISTEN_ST},
+/* BTA_FTS_OBX_CONN_EVT */ {BTA_FTS_SESSION_REQ, BTA_FTS_CLOSING_ST},
+/* BTA_FTS_OBX_DISC_EVT */ {BTA_FTS_IGNORE, BTA_FTS_CLOSING_ST},
+/* BTA_FTS_OBX_ABORT_EVT */ {BTA_FTS_OBX_ABORT, BTA_FTS_CLOSING_ST},
+/* BTA_FTS_OBX_PASSWORD_EVT */ {BTA_FTS_IGNORE, BTA_FTS_CLOSING_ST},
+/* BTA_FTS_OBX_CLOSE_EVT */ {BTA_FTS_OBX_CLOSE, BTA_FTS_CLOSING_ST},
+/* BTA_FTS_OBX_PUT_EVT */ {BTA_FTS_IGNORE, BTA_FTS_CLOSING_ST},
+/* BTA_FTS_OBX_GET_EVT */ {BTA_FTS_IGNORE, BTA_FTS_CLOSING_ST},
+/* BTA_FTS_OBX_SETPATH_EVT */ {BTA_FTS_IGNORE, BTA_FTS_CLOSING_ST},
+/* BTA_FTS_CI_SESSION_EVT */ {BTA_FTS_IGNORE, BTA_FTS_CLOSING_ST},
+/* BTA_FTS_OBX_ACTION_EVT */ {BTA_FTS_IGNORE, BTA_FTS_CLOSING_ST},
+/* BTA_FTS_APPL_TOUT_EVT */ {BTA_FTS_IGNORE, BTA_FTS_CLOSING_ST},
+/* BTA_FTS_DISC_ERR_EVT */ {BTA_FTS_DISC_ERR_RSP, BTA_FTS_CONN_ST},
+/* BTA_FTS_GASP_ERR_EVT */ {BTA_FTS_GASP_ERR_RSP, BTA_FTS_CLOSING_ST},
+/* BTA_FTS_CLOSE_CMPL_EVT */ {BTA_FTS_CLOSE_COMPLETE, BTA_FTS_LISTEN_ST},
+/* BTA_FTS_DISABLE_CMPL_EVT */ {BTA_FTS_DISABLE_CMPL, BTA_FTS_IDLE_ST}
+};
+
+/* type for state table */
+typedef const UINT8 (*tBTA_FTS_ST_TBL)[BTA_FTS_NUM_COLS];
+
+/* state table */
+const tBTA_FTS_ST_TBL bta_fts_st_tbl[] =
+{
+ bta_fts_st_idle,
+ bta_fts_st_listen,
+ bta_fts_st_w4_auth,
+ bta_fts_st_connected,
+ bta_fts_st_closing
+};
+
+/*****************************************************************************
+** Global data
+*****************************************************************************/
+
+/* FTS control block */
+#if BTA_DYNAMIC_MEMORY == FALSE
+tBTA_FTS_CB bta_fts_cb;
+#endif
+
+#if BTA_FTS_DEBUG == TRUE
+static char *fts_evt_code(tBTA_FTS_INT_EVT evt_code);
+static char *fts_state_code(tBTA_FTS_STATE state_code);
+#endif
+
+/*******************************************************************************
+**
+** Function bta_fts_sm_execute
+**
+** Description State machine event handling function for FTS
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fts_sm_execute(tBTA_FTS_CB *p_cb, UINT16 event, tBTA_FTS_DATA *p_data)
+{
+ tBTA_FTS_ST_TBL state_table;
+ UINT8 action;
+ int i;
+#if BTA_FTS_DEBUG == TRUE
+ tBTA_FTS_STATE in_state = bta_fts_cb.state;
+ UINT16 in_event = event;
+ APPL_TRACE_EVENT3("FTS Event : State 0x%02x [%s], Event [%s]", in_state,
+ fts_state_code(in_state),
+ fts_evt_code(event));
+#endif
+
+ /* look up the state table for the current state */
+ state_table = bta_fts_st_tbl[p_cb->state];
+
+ event &= 0x00FF;
+
+ /* set next state */
+ p_cb->state = state_table[event][BTA_FTS_NEXT_STATE];
+
+ /* execute action functions */
+ for (i = 0; i < BTA_FTS_ACTIONS; i++)
+ {
+ if ((action = state_table[event][i]) != BTA_FTS_IGNORE)
+ {
+ (*bta_fts_action[action])(p_cb, p_data);
+ }
+ else
+ {
+ /* discard fts data */
+ bta_fts_discard_data(p_data->hdr.event, p_data);
+ break;
+ }
+ }
+
+#if BTA_FTS_DEBUG == TRUE
+ if (in_state != bta_fts_cb.state)
+ {
+ APPL_TRACE_DEBUG3("FTS State Change: [%s] -> [%s] after Event [%s]",
+ fts_state_code(in_state),
+ fts_state_code(bta_fts_cb.state),
+ fts_evt_code(in_event));
+ }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function bta_fts_api_enable
+**
+** Description Handle an api enable event. This function enables the FT
+** Server by opening an Obex/Rfcomm channel and placing it into
+** listen mode.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_fts_api_enable(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data)
+{
+ tOBX_StartParams start_msg;
+ tBTA_FTS_API_ENABLE *p_api = &p_data->api_enable;
+ tOBX_TARGET target;
+ UINT16 len;
+ tOBX_STATUS status;
+ UINT16 mtu = OBX_MAX_MTU;
+
+ /* initialize control block */
+ memset(p_cb, 0, sizeof(tBTA_FTS_CB));
+
+ /* Allocate an aligned memory buffer to hold the root path and working directory */
+ /* Add 1 byte for '\0' */
+ len = p_bta_fs_cfg->max_path_len + 1;
+ if ((p_cb->p_rootpath = (char *)GKI_getbuf((UINT16)(len * 2))) != NULL)
+ {
+ p_cb->p_workdir = p_cb->p_rootpath + len;
+ memcpy(target.target, BTA_FTS_FOLDER_BROWSING_TARGET_UUID, BTA_FTS_UUID_LENGTH);
+ target.len = BTA_FTS_UUID_LENGTH;
+
+ /* store parameters */
+ p_cb->app_id = p_api->app_id;
+ p_cb->p_cback = p_api->p_cback;
+ p_cb->scn = BTM_AllocateSCN();
+
+ if (p_bta_ft_cfg->over_l2cap)
+ {
+ p_cb->psm = L2CA_AllocatePSM();
+ BTM_SetSecurityLevel (FALSE, p_api->servicename, BTM_SEC_SERVICE_OBEX_FTP,
+ p_api->sec_mask, p_cb->psm,
+ 0, 0);
+ }
+
+ p_cb->auth_enabled = p_api->auth_enabled;
+
+ p_cb->fd = BTA_FS_INVALID_FD;
+ /* Initialize the current working directory to be the root directory */
+ BCM_STRNCPY_S(p_cb->p_rootpath, len, p_api->p_root_path, len-1);
+ BCM_STRNCPY_S(p_cb->p_workdir, len, p_api->p_root_path, len-1);
+
+ /* Register FTP security requirements with BTM */
+ BTM_SetSecurityLevel(FALSE, p_api->servicename, BTM_SEC_SERVICE_OBEX_FTP,
+ p_api->sec_mask, BT_PSM_RFCOMM,
+ BTM_SEC_PROTO_RFCOMM, (UINT32)p_cb->scn);
+
+ /* Start up the FTP service */
+ memset (&start_msg, 0, sizeof(tOBX_StartParams));
+ start_msg.p_target = &target;
+
+ /* Make the MTU fit into one RFC frame */
+ start_msg.mtu = mtu;
+ start_msg.scn = p_cb->scn;
+ start_msg.psm = p_cb->psm;
+ start_msg.srm = p_bta_ft_cfg->srm;
+ start_msg.nonce = p_bta_ft_cfg->nonce;
+ start_msg.max_suspend = p_bta_ft_cfg->max_suspend;
+ start_msg.authenticate = p_cb->auth_enabled;
+
+ start_msg.auth_option = (p_bta_ft_cfg->userid_req) ? OBX_AO_USR_ID : OBX_AO_NONE;
+ start_msg.p_cback = bta_fts_obx_cback;
+
+ start_msg.realm_len = p_api->realm_len;
+ start_msg.p_realm = p_api->realm;
+ start_msg.realm_charset = (tOBX_CHARSET) p_bta_ft_cfg->realm_charset;
+
+ if ((status = OBX_StartServer (&start_msg, &p_cb->obx_handle)) == OBX_SUCCESS)
+ {
+ /* Set up the SDP record for file transfer service */
+ bta_fts_sdp_register(p_cb, p_api->servicename);
+
+ if (start_msg.nonce)
+ {
+ bta_fs_co_resume (BTA_FTS_CI_SESSION_EVT, p_cb->app_id);
+ }
+ else
+ {
+ p_data->resume_evt.status = BTA_FS_CO_FAIL;
+ bta_fts_ci_resume(p_cb, p_data);
+ }
+ }
+ else
+ APPL_TRACE_ERROR1("OBX_StartServer returns error (%d)", status);
+ }
+ else /* Cannot allocate resources to run Server */
+ APPL_TRACE_ERROR0("Not enough Resources to run FTP Server");
+
+ p_cb->p_cback(BTA_FTS_ENABLE_EVT, 0);
+}
+
+/*******************************************************************************
+**
+** Function bta_fts_hdl_event
+**
+** Description File transfer server main event handling function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BOOLEAN bta_fts_hdl_event(BT_HDR *p_msg)
+{
+#if BTA_FTS_DEBUG == TRUE
+ tBTA_FTS_STATE in_state = bta_fts_cb.state;
+#endif
+
+ switch (p_msg->event)
+ {
+ case BTA_FTS_API_ENABLE_EVT:
+#if BTA_FTS_DEBUG == TRUE
+ APPL_TRACE_EVENT3("FTS Event Handler: State 0x%02x [%s], Event [%s]", in_state,
+ fts_state_code(in_state),
+ fts_evt_code(p_msg->event));
+#endif
+ bta_fts_api_enable(&bta_fts_cb, (tBTA_FTS_DATA *) p_msg);
+
+#if BTA_FTS_DEBUG == TRUE
+ if (in_state != bta_fts_cb.state)
+ {
+ APPL_TRACE_DEBUG3("FTS State Change: [%s] -> [%s] after Event [%s]",
+ fts_state_code(in_state),
+ fts_state_code(bta_fts_cb.state),
+ fts_evt_code(p_msg->event));
+ }
+#endif
+ break;
+
+ default:
+
+ bta_fts_sm_execute(&bta_fts_cb, p_msg->event, (tBTA_FTS_DATA *) p_msg);
+
+ if ( bta_fts_cb.state == BTA_FTS_CONN_ST )
+ {
+ if (( bta_fts_cb.pm_state == BTA_FTS_PM_IDLE )
+ &&( bta_fts_cb.obx_oper != FTS_OP_NONE ))
+ {
+ /* inform power manager */
+ APPL_TRACE_DEBUG0("BTA FTS informs DM/PM busy state");
+ bta_sys_busy( BTA_ID_FTS ,bta_fts_cb.app_id, bta_fts_cb.bd_addr);
+ bta_fts_cb.pm_state = BTA_FTS_PM_BUSY;
+ }
+ else if (( bta_fts_cb.pm_state == BTA_FTS_PM_BUSY )
+ &&( bta_fts_cb.obx_oper == FTS_OP_NONE ))
+ {
+ /* inform power manager */
+ APPL_TRACE_DEBUG0("BTA FTS informs DM/PM idle state");
+ bta_sys_idle( BTA_ID_FTS ,bta_fts_cb.app_id, bta_fts_cb.bd_addr);
+ bta_fts_cb.pm_state = BTA_FTS_PM_IDLE;
+ }
+ }
+ else if ( bta_fts_cb.state == BTA_FTS_LISTEN_ST )
+ {
+ /* initialize power management state */
+ bta_fts_cb.pm_state = BTA_FTS_PM_BUSY;
+ }
+
+ break;
+ }
+
+ return (TRUE);
+}
+
+
+/*****************************************************************************
+** Debug Functions
+*****************************************************************************/
+#if BTA_FTS_DEBUG == TRUE
+
+/*******************************************************************************
+**
+** Function fts_evt_code
+**
+** Description
+**
+** Returns void
+**
+*******************************************************************************/
+static char *fts_evt_code(tBTA_FTS_INT_EVT evt_code)
+{
+ switch(evt_code)
+ {
+ case BTA_FTS_API_DISABLE_EVT:
+ return "BTA_FTS_API_DISABLE_EVT";
+ case BTA_FTS_API_AUTHRSP_EVT:
+ return "BTA_FTS_API_AUTHRSP_EVT";
+ case BTA_FTS_API_ACCESSRSP_EVT:
+ return "BTA_FTS_API_ACCESSRSP_EVT";
+ case BTA_FTS_API_CLOSE_EVT:
+ return "BTA_FTS_API_CLOSE_EVT";
+ case BTA_FTS_CI_WRITE_EVT:
+ return "BTA_FTS_CI_WRITE_EVT";
+ case BTA_FTS_CI_READ_EVT:
+ return "BTA_FTS_CI_READ_EVT";
+ case BTA_FTS_CI_OPEN_EVT:
+ return "BTA_FTS_CI_OPEN_EVT";
+ case BTA_FTS_CI_DIRENTRY_EVT:
+ return "BTA_FTS_CI_DIRENTRY_EVT";
+ case BTA_FTS_OBX_CONN_EVT:
+ return "BTA_FTS_OBX_CONN_EVT";
+ case BTA_FTS_OBX_DISC_EVT:
+ return "BTA_FTS_OBX_DISC_EVT";
+ case BTA_FTS_OBX_ABORT_EVT:
+ return "BTA_FTS_OBX_ABORT_EVT";
+ case BTA_FTS_OBX_PASSWORD_EVT:
+ return "BTA_FTS_OBX_PASSWORD_EVT";
+ case BTA_FTS_OBX_CLOSE_EVT:
+ return "BTA_FTS_OBX_CLOSE_EVT";
+ case BTA_FTS_OBX_PUT_EVT:
+ return "BTA_FTS_OBX_PUT_EVT";
+ case BTA_FTS_OBX_GET_EVT:
+ return "BTA_FTS_OBX_GET_EVT";
+ case BTA_FTS_OBX_SETPATH_EVT:
+ return "BTA_FTS_OBX_SETPATH_EVT";
+ case BTA_FTS_OBX_ACTION_EVT:
+ return "BTA_FTS_OBX_ACTION_EVT";
+ case BTA_FTS_CI_SESSION_EVT:
+ return "BTA_FTS_CI_SESSION_EVT";
+ case BTA_FTS_APPL_TOUT_EVT:
+ return "BTA_FTS_APPL_TOUT_EVT";
+ case BTA_FTS_DISC_ERR_EVT:
+ return "BTA_FTS_DISC_ERR_EVT";
+ case BTA_FTS_GASP_ERR_EVT:
+ return "BTA_FTS_GASP_ERR_EVT";
+ case BTA_FTS_API_ENABLE_EVT:
+ return "BTA_FTS_API_ENABLE_EVT";
+ case BTA_FTS_CLOSE_CMPL_EVT:
+ return "BTA_FTS_CLOSE_CMPL_EVT";
+ case BTA_FTS_DISABLE_CMPL_EVT:
+ return "BTA_FTS_DISABLE_CMPL_EVT";
+ default:
+ return "unknown FTS event code";
+ }
+}
+
+/*******************************************************************************
+**
+** Function fts_evt_code
+**
+** Description
+**
+** Returns void
+**
+*******************************************************************************/
+static char *fts_state_code(tBTA_FTS_STATE state_code)
+{
+ switch(state_code)
+ {
+ case BTA_FTS_IDLE_ST:
+ return "BTA_FTS_IDLE_ST";
+ case BTA_FTS_LISTEN_ST:
+ return "BTA_FTS_LISTEN_ST";
+ case BTA_FTS_W4_AUTH_ST:
+ return "BTA_FTS_W4_AUTH_ST";
+ case BTA_FTS_CONN_ST:
+ return "BTA_FTS_CONN_ST";
+ case BTA_FTS_CLOSING_ST:
+ return "BTA_FTS_CLOSING_ST";
+ default:
+ return "unknown FTS state code";
+ }
+}
+
+#endif /* Debug Functions */
+#endif /* BTA_FT_INCLUDED */
diff --git a/bta/ft/bta_fts_sdp.c b/bta/ft/bta_fts_sdp.c
new file mode 100644
index 0000000..2613942
--- /dev/null
+++ b/bta/ft/bta_fts_sdp.c
@@ -0,0 +1,66 @@
+/*****************************************************************************
+**
+** Name: bta_fts_sdp.c
+**
+** File: Implements the SDP functions used by File Transfer Server
+**
+** Copyright (c) 2003, Widcomm Inc., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include <string.h>
+
+#include "sdp_api.h"
+#include "bta_fts_int.h"
+#include "goep_util.h"
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+
+/*****************************************************************************
+**
+** Function: bta_fts_sdp_register()
+**
+** Purpose: Registers the File Transfer service with SDP
+**
+** Parameters:
+**
+**
+** Returns: void
+**
+*****************************************************************************/
+void bta_fts_sdp_register (tBTA_FTS_CB *p_cb, char *p_service_name)
+{
+ UINT16 ftp_service = UUID_SERVCLASS_OBEX_FILE_TRANSFER;
+ tGOEP_ERRORS status = GOEP_ERROR;
+ UINT16 version = BTA_FTS_DEFAULT_VERSION;
+ UINT8 temp[4], *p;
+
+ if (p_bta_ft_cfg->over_l2cap)
+ {
+ version = BTA_FT_ENHANCED_VERSION;
+ }
+ status = GOEP_Register (p_service_name, &p_cb->sdp_handle, p_cb->scn, 1, &ftp_service,
+ ftp_service, version);
+
+ if (status == GOEP_SUCCESS)
+ {
+ if (p_bta_ft_cfg->over_l2cap)
+ {
+ /* add the psm */
+ p = temp;
+ UINT16_TO_BE_STREAM(p, p_cb->psm);
+ SDP_AddAttribute(p_cb->sdp_handle, ATTR_ID_OBX_OVR_L2CAP_PSM, UINT_DESC_TYPE,
+ (UINT32)2, (UINT8*)temp);
+ }
+
+
+ bta_sys_add_uuid(ftp_service); /* UUID_SERVCLASS_OBEX_FILE_TRANSFER */
+ APPL_TRACE_DEBUG1("FTS: SDP Registered (handle 0x%08x)", p_cb->sdp_handle);
+ }
+
+ return;
+}
diff --git a/bta/ft/bta_fts_utils.c b/bta/ft/bta_fts_utils.c
new file mode 100644
index 0000000..f689752
--- /dev/null
+++ b/bta/ft/bta_fts_utils.c
@@ -0,0 +1,972 @@
+/*****************************************************************************
+**
+** Name: bta_fts_utils.c
+**
+** Description: This file implements object store functions for the
+** file transfer server.
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+
+#if defined(BTA_FT_INCLUDED) && (BTA_FT_INCLUDED == TRUE)
+
+#include <stdio.h>
+#include <string.h>
+#include "bta_fs_api.h"
+#include "bta_fts_int.h"
+#include "bta_fs_co.h"
+#include "gki.h"
+#include "utl.h"
+
+/*******************************************************************************
+** Constants
+*******************************************************************************/
+
+/*******************************************************************************
+** Local Function Prototypes
+*******************************************************************************/
+
+/*******************************************************************************
+* Macros for FTS
+*******************************************************************************/
+#define BTA_FTS_XML_EOL "\n"
+#define BTA_FTS_FOLDER_LISTING_START ( "<?xml version=\"1.0\"?>\n" \
+ "<!DOCTYPE folder-listing SYSTEM \"obex-folder-listing.dtd\">\n" \
+ "<folder-listing version=\"1.0\">\n" )
+
+#define BTA_FTS_FOLDER_LISTING_END ( "</folder-listing>" )
+#define BTA_FTS_PARENT_FOLDER (" <parent-folder/>\n")
+
+#define BTA_FTS_FILE_ELEM "file"
+#define BTA_FTS_FOLDER_ELEM "folder"
+#define BTA_FTS_NAME_ATTR "name"
+#define BTA_FTS_SIZE_ATTR "size"
+#define BTA_FTS_TYPE_ATTR "type"
+#define BTA_FTS_MODIFIED_ATTR "modified"
+#define BTA_FTS_CREATED_ATTR "created"
+#define BTA_FTS_ACCESSED_ATTR "accessed"
+#define BTA_FTS_USER_PERM_ATTR "user-perm"
+
+/*******************************************************************************
+* Exported Functions
+*******************************************************************************/
+/*******************************************************************************
+**
+** Function bta_fts_getdirlist
+**
+** Description Processes the retrieval of a directory listing.
+**
+** Parameters p_pkt - Pointer to the OBX Get request
+** name directory to list.
+**
+**
+** Returns UINT8 - OBX response code. OBX_RSP_OK if initiated.
+**
+*******************************************************************************/
+void bta_fts_getdirlist(char *p_name)
+{
+ tBTA_FTS_CB *p_cb = &bta_fts_cb;
+ tBTA_FTS_OBX_PKT *p_obx = &p_cb->obx;
+ tBTA_FTS_DIRLIST *p_dir = &p_cb->dir;
+ UINT16 temp_len;
+ BOOLEAN is_dir;
+ UINT8 rsp_code = OBX_RSP_OK;
+
+ if (!p_cb->p_path)
+ p_cb->p_path = (char *)GKI_getbuf((UINT16)(p_bta_fs_cfg->max_path_len + 1));
+ if (p_cb->p_path)
+ {
+ /* If not specified, use the current work directory */
+ if (!p_name || p_name[0] == '\0')
+ {
+ p_cb->p_path[p_bta_fs_cfg->max_path_len] = 0;
+ BCM_STRNCPY_S(p_cb->p_path, (p_bta_fs_cfg->max_path_len + 1), p_cb->p_workdir, p_bta_fs_cfg->max_path_len);
+ }
+ else
+ {
+ if ((strlen(p_cb->p_workdir) + strlen(p_name) + 2) <= p_bta_fs_cfg->max_path_len)
+ {
+ sprintf(p_cb->p_path, "%s%c%s", p_cb->p_workdir,
+ p_bta_fs_cfg->path_separator, p_name);
+
+ /* Make sure the Name is a directory and accessible */
+ if (((bta_fs_co_access(p_cb->p_path, BTA_FS_ACC_EXIST,
+ &is_dir, p_cb->app_id))!= BTA_FS_CO_OK)
+ || !is_dir)
+ rsp_code = OBX_RSP_NOT_FOUND;
+ }
+ else
+ rsp_code = OBX_RSP_BAD_REQUEST;
+ }
+
+ /* Build the listing */
+ if (rsp_code == OBX_RSP_OK)
+ {
+ if (!(strcmp(p_cb->p_path, p_cb->p_rootpath)))
+ p_dir->is_root = TRUE;
+ else
+ p_dir->is_root = FALSE;
+
+ p_obx->p_pkt = (BT_HDR *)OBX_HdrInit(p_cb->obx_handle, p_cb->peer_mtu);
+
+ if (!p_dir->p_entry)
+ {
+ /* Allocate enough space for the structure and the file name */
+ if ((p_dir->p_entry = (tBTA_FS_DIRENTRY *)
+ GKI_getbuf((UINT16)(sizeof(tBTA_FS_DIRENTRY) +
+ p_bta_fs_cfg->max_file_len + 1))) != NULL)
+ p_dir->p_entry->p_name = (char *)(p_dir->p_entry + 1);
+ }
+
+ if (p_dir->p_entry && p_obx->p_pkt)
+ {
+ /* Add the start of the Body Header */
+ p_obx->offset = 0;
+ p_obx->bytes_left = 0;
+ p_obx->p_start = OBX_AddBodyStart(p_obx->p_pkt, &p_obx->bytes_left);
+
+ /* Is this a new request or continuation? */
+ if ((p_cb->obx_oper == FTS_OP_NONE))
+ {
+ p_cb->obx_oper = FTS_OP_LISTING;
+ APPL_TRACE_EVENT1("FTS List Directory: Name [%s]", p_cb->p_path);
+
+ temp_len = strlen(BTA_FTS_FOLDER_LISTING_START);
+
+ /* Add the beginning label of http */
+ memcpy(p_obx->p_start, BTA_FTS_FOLDER_LISTING_START, temp_len);
+ p_obx->bytes_left -= (UINT16)(temp_len + strlen(BTA_FTS_FOLDER_LISTING_END));
+ p_obx->offset += temp_len;
+
+ /* Add the parent directory if not the root */
+ if (strcmp(p_cb->p_path, p_cb->p_rootpath))
+ {
+ temp_len = strlen(BTA_FTS_PARENT_FOLDER);
+ memcpy(p_obx->p_start + p_obx->offset,
+ BTA_FTS_PARENT_FOLDER, temp_len);
+ p_obx->bytes_left -= temp_len;
+ p_obx->offset += temp_len;
+ }
+
+ p_cb->cout_active = TRUE;
+ bta_fs_co_getdirentry (p_cb->p_path, TRUE, p_dir->p_entry,
+ BTA_FTS_CI_DIRENTRY_EVT, p_cb->app_id);
+
+ /* List is not complete, so don't send the response yet */
+ rsp_code = OBX_RSP_PART_CONTENT;
+ }
+ else /* Add the entry previously retrieved */
+ rsp_code = bta_fts_add_list_entry();
+ }
+ else
+ rsp_code = OBX_RSP_INTRNL_SRVR_ERR;
+ }
+ }
+ else /* Error occurred */
+ rsp_code = OBX_RSP_INTRNL_SRVR_ERR;
+
+ /* Response goes out if complete or error occurred */
+ if (rsp_code != OBX_RSP_PART_CONTENT)
+ bta_fts_end_of_list(rsp_code);
+}
+
+/*******************************************************************************
+**
+** Function bta_fts_proc_get_file
+**
+** Description Processes a Get File Operation.
+** If first OBX request, the file is opened, otherwise if it is
+** a continuation the next read is initiated.
+**
+** Parameters p_pkt - Pointer to the OBX Get request
+** name of file to read.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fts_proc_get_file(char *p_name)
+{
+ tBTA_FTS_CB *p_cb = &bta_fts_cb;
+ tBTA_FTS_OBX_PKT *p_obx = &p_cb->obx;
+ UINT8 rsp_code = OBX_RSP_INTRNL_SRVR_ERR;
+
+ p_obx->offset = 0;
+
+ /* Allocate an OBX packet */
+ if ((p_obx->p_pkt = (BT_HDR *)OBX_HdrInit(p_cb->obx_handle,
+ p_cb->peer_mtu)) != NULL)
+ {
+ /* Is this a new request or continuation? */
+ if ((p_cb->obx_oper == FTS_OP_NONE))
+ {
+ /* Validate the name */
+ if (p_name)
+ {
+ if ((p_cb->p_path =
+ (char *)GKI_getbuf((UINT16)(p_bta_fs_cfg->max_path_len + 1))) != NULL)
+ {
+ /* Build a fully qualified path */
+ if ((strlen(p_cb->p_workdir) + strlen(p_name) + 2)
+ <= p_bta_fs_cfg->max_path_len)
+ {
+ rsp_code = OBX_RSP_OK;
+ sprintf(p_cb->p_path, "%s%c%s", p_cb->p_workdir,
+ p_bta_fs_cfg->path_separator, p_name);
+
+ APPL_TRACE_EVENT1("FTS GET FILE: Name [%s]", p_cb->p_path);
+
+ p_cb->obx_oper = FTS_OP_GET_FILE;
+
+ /* Notify the application that a get file has been requested */
+ bta_fts_req_app_access (BTA_FT_OPER_GET, p_cb);
+ }
+ }
+ }
+ }
+ else /* Continue reading from the file */
+ {
+ /* Add the start of the Body Header */
+ p_obx->bytes_left = 0;
+ p_obx->p_start = OBX_AddBodyStart(p_obx->p_pkt, &p_obx->bytes_left);
+
+ rsp_code = OBX_RSP_OK;
+ p_cb->cout_active = TRUE;
+ bta_fs_co_read(p_cb->fd, &p_obx->p_start[p_obx->offset],
+ p_obx->bytes_left, BTA_FTS_CI_READ_EVT, 0, p_cb->app_id);
+ }
+ }
+ if (rsp_code != OBX_RSP_OK)
+ bta_fts_get_file_rsp(rsp_code, 0);
+}
+
+/*******************************************************************************
+**
+** Function bta_fts_proc_put_file
+**
+** Description Processes a Put File Operation.
+** Initiates the opening of a file for writing, or continues
+** with a new Obx packet of data (continuation).
+**
+** Parameters p_pkt - Pointer to the OBX Put request
+** name of file to write out.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fts_proc_put_file(BT_HDR *p_pkt, char *p_name, BOOLEAN final_pkt, UINT8 oper)
+{
+ tBTA_FTS_CB *p_cb = &bta_fts_cb;
+ tBTA_FTS_OBX_PKT *p_obx = &p_cb->obx;
+ tBTA_FS_CO_STATUS status;
+ UINT8 rsp_code = OBX_RSP_INTRNL_SRVR_ERR;
+ UINT8 num_hdrs;
+ BOOLEAN is_dir;
+ BOOLEAN endpkt;
+
+ p_obx->final_pkt = final_pkt;
+ p_obx->p_pkt = p_pkt;
+ p_obx->offset = 0; /* Initial offset into OBX data */
+ APPL_TRACE_DEBUG2("bta_fts_proc_put_file len:%d p_pkt->offset:%d", p_pkt->len, p_pkt->offset);
+
+ /* Is this a new request or continuation? */
+ if ((p_cb->obx_oper == FTS_OP_NONE))
+ {
+ /* See if the folder permissions are writable in the current folder */
+ if (((status = bta_fs_co_access(p_cb->p_workdir, BTA_FS_ACC_RDWR,
+ &is_dir, p_cb->app_id)) == BTA_FS_CO_OK) && is_dir)
+ {
+ /* Initialize the start of data and length */
+ if ((p_cb->p_path =
+ (char *)GKI_getbuf((UINT16)(p_bta_fs_cfg->max_path_len + 1))) != NULL)
+ {
+ /* Build a fully qualified path */
+ if ((strlen(p_cb->p_workdir) + strlen(p_name) + 2)
+ <= p_bta_fs_cfg->max_path_len)
+ {
+ /* Read the file length if header exists */
+ if (!OBX_ReadLengthHdr(p_pkt, &p_cb->file_length))
+ p_cb->file_length = BTA_FS_LEN_UNKNOWN;
+
+ rsp_code = OBX_RSP_PART_CONTENT; /* Do not send OBX response yet */
+ sprintf(p_cb->p_path, "%s%c%s", p_cb->p_workdir,
+ p_bta_fs_cfg->path_separator, p_name);
+
+ APPL_TRACE_DEBUG2("FTS PUT FILE: Name [%s], Length = 0x%0x (0 = n/a)",
+ p_cb->p_path, p_cb->file_length);
+
+ p_cb->obx_oper = FTS_OP_PUT_FILE;
+
+ /* Get permission before proceeding */
+ bta_fts_req_app_access(BTA_FT_OPER_PUT, p_cb);
+ }
+ }
+ }
+ else
+ rsp_code = OBX_RSP_UNAUTHORIZED;
+ }
+ else /* Continue writing to the open file */
+ {
+ /* Read in start of body if there is a body header */
+ num_hdrs = OBX_ReadBodyHdr(p_obx->p_pkt, &p_obx->p_start,
+ &p_obx->bytes_left, &endpkt);
+ if (num_hdrs == 1)
+ {
+ if (p_obx->bytes_left)
+ {
+ rsp_code = OBX_RSP_PART_CONTENT; /* Do not send OBX response yet */
+ p_cb->cout_active = TRUE;
+ bta_fs_co_write(p_cb->fd, &p_obx->p_start[p_obx->offset],
+ p_obx->bytes_left, BTA_FTS_CI_WRITE_EVT, 0, p_cb->app_id);
+ }
+ else
+ {
+ rsp_code = OBX_RSP_OK;
+ }
+
+ }
+ else if (oper & FTS_OP_RESUME)
+ {
+ rsp_code = OBX_RSP_OK;
+ }
+ else
+ {
+ bta_fts_clean_getput(p_cb, TRUE);
+ rsp_code = OBX_RSP_BAD_REQUEST;
+ }
+ }
+
+ if (rsp_code != OBX_RSP_PART_CONTENT)
+ bta_fts_put_file_rsp(rsp_code);
+}
+
+/*******************************************************************************
+**
+** Function bta_fts_mkdir
+**
+** Description make a new directory and sets the new path to this directory
+** if successful.
+**
+** Parameters p_pkt - Pointer to the OBX packet
+**
+** Returns UINT8 - OBX response code
+**
+*******************************************************************************/
+UINT8 bta_fts_mkdir(BT_HDR *p_pkt, tBTA_FT_OPER *p_op)
+{
+ tBTA_FTS_CB *p_cb = &bta_fts_cb;
+ tBTA_FS_CO_STATUS status = BTA_FS_CO_FAIL;
+ UINT8 rsp_code = OBX_RSP_INTRNL_SRVR_ERR;
+ char *p_newpath;
+ char *p_name;
+ BOOLEAN is_dir;
+
+ p_newpath = p_cb->p_path;
+ p_name = p_cb->p_name;
+
+ /* the name of the directory being created */
+ if (p_cb->p_name && p_cb->p_name[0])
+ {
+ /* Make sure the new path is not too big */
+ if ((strlen(p_name) + strlen(p_cb->p_workdir) + 1) <= p_bta_fs_cfg->max_path_len)
+ {
+ /* create a temporary path for creation attempt */
+ sprintf(p_newpath, "%s%c%s", p_cb->p_workdir,
+ p_bta_fs_cfg->path_separator, p_name);
+
+ /* If the directory already exists, we're done */
+ if (((status = bta_fs_co_access(p_newpath, BTA_FS_ACC_EXIST,
+ &is_dir, p_cb->app_id)) == BTA_FS_CO_OK) && is_dir)
+ {
+ /* If directory exists, skip mkdir and just issue chdir- Note OBX_RSP_CONTINUE used internally by callee */
+ rsp_code = OBX_RSP_CONTINUE;
+ }
+
+ /* See if the folder permissions are writable in the current folder */
+ else if (((status = bta_fs_co_access(p_cb->p_workdir, BTA_FS_ACC_RDWR,
+ &is_dir, p_cb->app_id)) == BTA_FS_CO_OK))
+ {
+ *p_op = BTA_FT_OPER_MK_DIR;
+ }
+ else if (status == BTA_FS_CO_EACCES)
+ rsp_code = OBX_RSP_UNAUTHORIZED; /* Read only folder, cannot create a new one */
+ }
+ else
+ APPL_TRACE_WARNING0 ("bta_fts_mkdir: path too long!!!");
+ }
+ else
+ rsp_code = OBX_RSP_BAD_REQUEST;
+
+
+ APPL_TRACE_DEBUG2("bta_fts_mkdir: co_status [%d], obx_rsp_code [0x%02x]",
+ status, rsp_code);
+
+ return (rsp_code);
+}
+
+/*******************************************************************************
+**
+** Function bta_fts_chdir
+**
+** Description Changes the current path to the specified directory.
+**
+** Parameters p_pkt - Pointer to the OBX packet
+** backup_flag - if TRUE, path adjusted up one level.
+**
+** Returns UINT8 - OBX response code
+**
+*******************************************************************************/
+UINT8 bta_fts_chdir(BT_HDR *p_pkt, BOOLEAN backup_flag, tBTA_FT_OPER *p_op)
+{
+ tBTA_FTS_CB *p_cb = &bta_fts_cb;
+ char *p_path = p_cb->p_path;
+ char *p_name = p_cb->p_name;
+ char *p_workdir = p_cb->p_workdir;
+ UINT8 rsp_code = OBX_RSP_INTRNL_SRVR_ERR;
+ BOOLEAN is_dir;
+
+ if (!backup_flag)
+ {
+
+ /* If No Name header, or empty name header, set to root path */
+ if (p_name == NULL || (p_name && p_name[0] == '\0'))
+ {
+ BCM_STRNCPY_S(p_workdir, p_bta_fs_cfg->max_path_len+1, p_cb->p_rootpath, p_bta_fs_cfg->max_path_len);
+ p_workdir[p_bta_fs_cfg->max_path_len] = '\0';
+
+ rsp_code = OBX_RSP_OK;
+ APPL_TRACE_DEBUG0("FTS: Setting current path to ROOT");
+ }
+// btla-specific ++
+ #if defined (FTS_REJECT_INVALID_OBEX_SET_PATH_REQ) && (FTS_REJECT_INVALID_OBEX_SET_PATH_REQ == TRUE)
+ /* Reject invalid OBEX set path reqeust - DOS or unix/linux like change directory*/
+ else if(strncmp("/", p_name, 1) == 0 || strncmp("..", p_name, 2) == 0)
+ {
+ APPL_TRACE_ERROR0("FTS: Rejecting invalid chdir request start with / or ..");
+ rsp_code = OBX_RSP_NOT_FOUND;
+ }
+ #endif
+// btla-specific --
+ /* Make sure the new path is not too big */
+ else if ((strlen(p_name) + strlen(p_workdir) + 2)
+ <= p_bta_fs_cfg->max_path_len)
+ {
+ /* create a temporary path for creation attempt */
+ sprintf(p_path, "%s%c%s", p_workdir,
+ p_bta_fs_cfg->path_separator, p_name);
+
+ if (((bta_fs_co_access(p_path, BTA_FS_ACC_EXIST,
+ &is_dir, p_cb->app_id)) == BTA_FS_CO_OK) && is_dir)
+ {
+ *p_op = BTA_FT_OPER_CHG_DIR;
+ }
+ else
+ rsp_code = OBX_RSP_NOT_FOUND;
+ }
+ }
+ else /* Backing up a directory */
+ {
+ /* Backup unless already at root */
+ if (strcmp(p_workdir, p_cb->p_rootpath))
+ {
+ /* if an empty name header exist(although illegal), goes to root */
+ if (p_name && p_name[0] == '\0')
+ {
+ BCM_STRNCPY_S(p_workdir, p_bta_fs_cfg->max_path_len+1, p_cb->p_rootpath, p_bta_fs_cfg->max_path_len);
+ p_workdir[p_bta_fs_cfg->max_path_len] = '\0';
+
+ APPL_TRACE_DEBUG0("FTS: Setting current path to ROOT");
+ }
+ /* otherwise back up one level */
+ /* Find the last occurrence of separator and replace with '\0' */
+ else if((p_path = strrchr(p_workdir, (int)p_bta_fs_cfg->path_separator)) != NULL)
+ *p_path = '\0';
+ APPL_TRACE_DEBUG1("FTS: SET NEW PATH [%s]", p_cb->p_workdir);
+
+ rsp_code = OBX_RSP_OK;
+ }
+ else
+ rsp_code = OBX_RSP_NOT_FOUND;
+ }
+
+ if (rsp_code == OBX_RSP_OK)
+ bta_fs_co_setdir(p_workdir, p_cb->app_id);
+
+ return (rsp_code);
+}
+
+/*******************************************************************************
+**
+** Function bta_fts_delete
+**
+** Description remove a file or directory
+**
+** Parameters
+** p - Pointer to the name of the object store. It is
+** converted into a fully qualified path before call-out
+** function is called (if not a RAM object).
+**
+** Returns void
+**
+** Obex packet is responded to with:
+** OBX_RSP_OK if successful,
+** OBX_RSP_PRECONDTN_FAILED if a directory and not empty,
+** OBX_RSP_UNAUTHORIZED if read only (access problem),
+** OBX_RSP_INTRNL_SRVR_ERR otherwise.
+**
+*******************************************************************************/
+void bta_fts_delete(tBTA_FTS_OBX_EVENT *p_evt, const char *p_name)
+{
+ tBTA_FTS_CB *p_cb = &bta_fts_cb;
+ char *p_path;
+ tBTA_FS_CO_STATUS status;
+ UINT8 rsp_code = OBX_RSP_INTRNL_SRVR_ERR;
+ BOOLEAN is_dir;
+ tBTA_FT_OPER ft_op = BTA_FT_OPER_DEL_FILE;
+ BOOLEAN rsp_now = TRUE;
+
+ if ((p_cb->p_path = (char *)GKI_getbuf((UINT16)(p_bta_fs_cfg->max_path_len + 2))) != NULL)
+ {
+ p_path = p_cb->p_path;
+ sprintf(p_path, "%s%c%s", p_cb->p_workdir, p_bta_fs_cfg->path_separator,
+ p_name);
+
+ /* Access the object to see if it exists */
+ status = bta_fs_co_access(p_path, BTA_FS_ACC_RDWR, &is_dir, p_cb->app_id);
+ if (status == BTA_FS_CO_OK)
+ {
+ if (is_dir)
+ ft_op = BTA_FT_OPER_DEL_DIR;
+ rsp_now = FALSE;
+ bta_fts_req_app_access(ft_op, p_cb);
+ }
+ else if (status == BTA_FS_CO_EACCES)
+ rsp_code = OBX_RSP_UNAUTHORIZED;
+ else
+ rsp_code = OBX_RSP_NOT_FOUND;
+
+ }
+ if(rsp_now)
+ {
+ utl_freebuf((void**)&p_cb->p_path);
+ OBX_PutRsp(p_evt->handle, rsp_code, (BT_HDR *)NULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_fts_end_of_list
+**
+** Description Finishes up the end body of the listing, and sends out the
+** OBX response
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fts_end_of_list(UINT8 rsp_code)
+{
+ tBTA_FTS_CB *p_cb = &bta_fts_cb;
+ tBTA_FTS_OBX_PKT *p_obx = &p_cb->obx;
+ UINT16 temp_len;
+
+ /* Add the end of folder listing string if successful operation */
+ if (rsp_code == OBX_RSP_OK || rsp_code == OBX_RSP_CONTINUE)
+ {
+ /* If listing has completed, add on end string (http) */
+ if (rsp_code == OBX_RSP_OK)
+ {
+ temp_len = strlen(BTA_FTS_FOLDER_LISTING_END);
+ memcpy(&p_obx->p_start[p_obx->offset], BTA_FTS_FOLDER_LISTING_END, temp_len);
+ p_obx->offset += temp_len;
+
+ OBX_AddBodyEnd(p_obx->p_pkt, p_obx->p_start, p_obx->offset, TRUE);
+
+ /* Clean up control block */
+ bta_fts_clean_list(p_cb);
+ }
+ else /* More listing data to be sent */
+ OBX_AddBodyEnd(p_obx->p_pkt, p_obx->p_start, p_obx->offset, FALSE);
+
+ OBX_GetRsp(p_cb->obx_handle, rsp_code, (BT_HDR *)p_obx->p_pkt);
+ p_obx->p_pkt = NULL; /* Do not deallocate buffer; OBX will */
+ }
+ else /* An error occurred */
+ {
+ OBX_GetRsp(p_cb->obx_handle, rsp_code, (BT_HDR *)NULL);
+ bta_fts_clean_list(p_cb);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_fts_get_file_rsp
+**
+** Description Finishes up the end body of the file get, and sends out the
+** OBX response
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fts_get_file_rsp(UINT8 rsp_code, UINT16 num_read)
+{
+ tBTA_FTS_CB *p_cb = &bta_fts_cb;
+ tBTA_FTS_OBX_PKT *p_obx = &p_cb->obx;
+ tBTA_FTS param;
+ BOOLEAN done = TRUE;
+
+ /* Send the response packet if successful operation */
+ if (rsp_code == OBX_RSP_OK || rsp_code == OBX_RSP_CONTINUE)
+ {
+ p_obx->offset += num_read;
+
+ /* More to be sent */
+ if (rsp_code == OBX_RSP_CONTINUE)
+ {
+ if (p_obx->bytes_left != num_read)
+ APPL_TRACE_WARNING2("FTS Read: Requested (0x%04x), Read In (0x%04x)",
+ p_obx->bytes_left, num_read);
+ done = FALSE;
+ }
+
+ OBX_AddBodyEnd(p_obx->p_pkt, p_obx->p_start, p_obx->offset, done);
+
+ /* Notify application with progress */
+ if (num_read)
+ {
+ param.prog.bytes = num_read;
+ param.prog.file_size = p_cb->file_length;
+ p_cb->p_cback(BTA_FTS_PROGRESS_EVT, &param);
+ }
+ }
+ else
+ p_cb->obx_oper = FTS_OP_NONE;
+
+ OBX_GetRsp(p_cb->obx_handle, rsp_code, (BT_HDR *)p_obx->p_pkt);
+ p_obx->p_pkt = NULL; /* Do not deallocate buffer; OBX will */
+
+ /* Final response packet sent out */
+ if (done)
+ bta_fts_clean_getput(p_cb, FALSE);
+}
+
+/*******************************************************************************
+**
+** Function bta_fts_put_file_rsp
+**
+** Description Responds to a put request, and closes the file if finished
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fts_put_file_rsp(UINT8 rsp_code)
+{
+ tBTA_FTS_CB *p_cb = &bta_fts_cb;
+ tBTA_FTS_OBX_PKT *p_obx = &p_cb->obx;
+ tBTA_FTS param;
+
+ /* Finished with input packet */
+ utl_freebuf((void**)&p_obx->p_pkt);
+
+ if (rsp_code == OBX_RSP_OK)
+ {
+ /* Update application if file data was transferred */
+ if (p_obx->bytes_left)
+ {
+ param.prog.bytes = p_obx->bytes_left;
+ param.prog.file_size = p_cb->file_length;
+ p_cb->p_cback(BTA_FTS_PROGRESS_EVT, &param);
+ }
+
+ /* If not end of file put, set the continue response */
+ if (!p_obx->final_pkt)
+ rsp_code = OBX_RSP_CONTINUE;
+ else /* Done - free the allocated memory */
+ bta_fts_clean_getput(p_cb, FALSE);
+ }
+ else
+ p_cb->obx_oper = FTS_OP_NONE;
+
+ OBX_PutRsp(p_cb->obx_handle, rsp_code, (BT_HDR *)NULL);
+}
+
+/*******************************************************************************
+**
+** Function bta_fts_add_list_entry
+**
+** Description used by bta_fts_getdirlist to write a list entry to an
+** obex packet (byte array).
+**
+** Returns UINT8 - OBX response code
+** OBX_RSP_PART_CONTENT if not finished yet.
+** OBX_RSP_CONTINUE [packet done]
+** Others send error response out
+**
+*******************************************************************************/
+UINT8 bta_fts_add_list_entry(void)
+{
+ tBTA_FTS_CB *p_cb = &bta_fts_cb;
+ tBTA_FTS_OBX_PKT *p_obx = &p_cb->obx;
+ tBTA_FTS_DIRLIST *p_dir = &p_cb->dir;
+ tBTA_FS_DIRENTRY *p_file = p_dir->p_entry;
+ char *p_buf;
+ UINT16 size;
+ UINT8 rsp_code = OBX_RSP_PART_CONTENT;
+
+ if ((p_buf = (char *)GKI_getbuf(GKI_MAX_BUF_SIZE)) != NULL)
+ {
+ p_buf[0] = '\0';
+
+ APPL_TRACE_DEBUG2("bta_fts_add_list_entry: attr:0x%02x, name:%s",
+ p_file->mode, p_file->p_name);
+
+ if(p_file->mode & BTA_FS_A_DIR) /* Subdirectory */
+ {
+ /* ignore "." and ".." */
+ if (strcmp(p_file->p_name, ".") && strcmp(p_file->p_name, ".."))
+ {
+ sprintf(p_buf, " <" BTA_FTS_FOLDER_ELEM " "
+ BTA_FTS_NAME_ATTR "=\"%s\"/>" BTA_FTS_XML_EOL,
+ p_file->p_name);
+ }
+ }
+ else /* treat anything else as file */
+ {
+ /* Add the creation time if valid */
+ if (p_file->crtime[0] != '\0')
+ {
+ sprintf(p_buf, " <" BTA_FTS_FILE_ELEM " "
+ BTA_FTS_NAME_ATTR "=\"%s\" "
+ BTA_FTS_SIZE_ATTR "=\"%lu\" "
+ BTA_FTS_USER_PERM_ATTR "=\"R%s\" "
+ BTA_FTS_CREATED_ATTR "=\"%s\"/>" BTA_FTS_XML_EOL,
+ p_file->p_name,
+ p_file->filesize,
+ p_file->mode & BTA_FS_A_RDONLY ? "" : "WD",
+ p_file->crtime);
+ }
+ else
+ {
+ sprintf(p_buf, " <" BTA_FTS_FILE_ELEM " "
+ BTA_FTS_NAME_ATTR "=\"%s\" "
+ BTA_FTS_SIZE_ATTR "=\"%lu\" "
+ BTA_FTS_USER_PERM_ATTR "=\"R%s\"/>" BTA_FTS_XML_EOL,
+ p_file->p_name,
+ p_file->filesize,
+ p_file->mode & BTA_FS_A_RDONLY ? "" : "WD");
+ }
+ }
+
+ /* Make sure the entry fits into the current obx packet */
+ size = strlen(p_buf);
+ if (size <= p_obx->bytes_left)
+ {
+ if (size > 0)
+ {
+ memcpy (&p_obx->p_start[p_obx->offset], p_buf, size);
+ p_obx->offset += size;
+ p_obx->bytes_left -= size;
+ }
+ /* Get the next directory entry */
+ p_cb->cout_active = TRUE;
+ bta_fs_co_getdirentry (p_cb->p_path, FALSE, p_dir->p_entry,
+ BTA_FTS_CI_DIRENTRY_EVT, p_cb->app_id);
+ }
+ else /* entry did not fit in current obx packet; try to add entry in next obx req */
+ rsp_code = OBX_RSP_CONTINUE;
+
+ /* Done with temporary buffer */
+ GKI_freebuf(p_buf);
+ }
+ else
+ rsp_code = OBX_RSP_INTRNL_SRVR_ERR;
+ return (rsp_code);
+}
+
+
+/*******************************************************************************
+* Static Functions
+*******************************************************************************/
+
+/*******************************************************************************
+**
+** Function bta_fts_clean_list
+**
+** Description Cleans up the get directory list memory and control block
+**
+** Returns void
+**
+*******************************************
+************************************/
+void bta_fts_clean_list(tBTA_FTS_CB *p_cb)
+{
+ tBTA_FTS_DIRLIST *p_dir = &p_cb->dir;
+ /* Clean up control block */
+ p_cb->obx_oper = FTS_OP_NONE;
+ utl_freebuf((void**)&p_cb->p_name);
+ utl_freebuf((void**)&p_dir->p_entry);
+ utl_freebuf((void**)&p_cb->p_path);
+}
+
+/*******************************************************************************
+**
+** Function bta_fts_clean_getput
+**
+** Description Cleans up the get/put resources and control block
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fts_clean_getput(tBTA_FTS_CB *p_cb, BOOLEAN is_aborted)
+{
+ tBTA_FS_CO_STATUS status;
+ tBTA_FTS_OBJECT objdata;
+ tBTA_FTS_EVT evt = 0;
+
+ /* Clean up control block */
+ utl_freebuf((void**)&p_cb->obx.p_pkt);
+
+ /* Close any open files */
+ if (p_cb->fd >= 0)
+ {
+ bta_fs_co_close(p_cb->fd, p_cb->app_id);
+ p_cb->fd = BTA_FS_INVALID_FD;
+
+ /* Notify the application */
+ objdata.p_name = p_cb->p_path;
+
+ if (is_aborted)
+ objdata.status = BTA_FTS_FAIL;
+ else
+ objdata.status = BTA_FTS_OK;
+
+ if (p_cb->obx_oper == FTS_OP_PUT_FILE)
+ {
+ /* Delete an aborted unfinished push file operation */
+ if (is_aborted && p_cb->suspending == FALSE)
+ {
+ status = bta_fs_co_unlink(p_cb->p_path, p_cb->app_id);
+ APPL_TRACE_WARNING2("FTS: Remove ABORTED Push File Operation [%s], status 0x%02x",
+ p_cb->p_path, status);
+ }
+
+ evt = BTA_FTS_PUT_CMPL_EVT;
+ }
+ else if (p_cb->obx_oper == FTS_OP_GET_FILE)
+ {
+ evt = BTA_FTS_GET_CMPL_EVT;
+ }
+
+ if (evt)
+ {
+ /* Notify application of operation complete */
+ p_cb->p_cback(evt, (tBTA_FTS *)&objdata);
+ }
+ }
+
+ p_cb->suspending = FALSE;
+
+ utl_freebuf((void**)&p_cb->p_name);
+ utl_freebuf((void**)&p_cb->p_path);
+
+ p_cb->obx_oper = FTS_OP_NONE;
+ p_cb->obx.bytes_left = 0;
+ p_cb->file_length = BTA_FS_LEN_UNKNOWN;
+ p_cb->acc_active = 0;
+}
+
+/*******************************************************************************
+**
+** Function bta_fts_disable_cleanup
+**
+** Description Cleans up the resources and control block
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fts_disable_cleanup(tBTA_FTS_CB *p_cb)
+{
+ tBTA_FS_CO_STATUS status;
+
+ /* Stop the OBEX server */
+ OBX_StopServer(p_cb->obx_handle);
+
+ /* Clean up control block */
+ utl_freebuf((void **)&p_cb->obx.p_pkt);
+
+ /* Close any open files */
+ if (p_cb->fd >= 0)
+ {
+ bta_fs_co_close(p_cb->fd, p_cb->app_id);
+ p_cb->fd = BTA_FS_INVALID_FD;
+
+ /* Delete an aborted unfinished push file operation */
+ if (p_cb->obx_oper == FTS_OP_PUT_FILE)
+ {
+ status = bta_fs_co_unlink(p_cb->p_path, p_cb->app_id);
+ APPL_TRACE_WARNING2("FTS: bta_fts_disable_cleanup() ->Remove ABORTED Push File Operation [%s], status 0x%02x",
+ p_cb->p_path, status);
+ }
+ }
+
+ /* Free any used memory buffers */
+ utl_freebuf((void **)&p_cb->dir.p_entry);
+ utl_freebuf((void **)&p_cb->p_name);
+ utl_freebuf((void **)&p_cb->p_path);
+
+ /* Remove the FTP service from the SDP database */
+ SDP_DeleteRecord(p_cb->sdp_handle);
+
+ /* Free the allocated server channel number */
+ BTM_FreeSCN(p_cb->scn);
+
+ GKI_freebuf(p_cb->p_rootpath); /* Free buffer containing root and working paths */
+
+ p_cb->obx_oper = FTS_OP_NONE;
+ p_cb->obx.bytes_left = 0;
+ p_cb->file_length = BTA_FS_LEN_UNKNOWN;
+ p_cb->acc_active = 0;
+
+ if (p_cb->p_cback)
+ {
+ /* Notify the application */
+ p_cb->p_cback(BTA_FTS_DISABLE_EVT, 0);
+ p_cb->p_cback = NULL;
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_fts_discard_data
+**
+** Description frees the data
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fts_discard_data(UINT16 event, tBTA_FTS_DATA *p_data)
+{
+ switch(event)
+ {
+ case BTA_FTS_OBX_CONN_EVT:
+ case BTA_FTS_OBX_DISC_EVT:
+ case BTA_FTS_OBX_ABORT_EVT:
+ case BTA_FTS_OBX_PASSWORD_EVT:
+ case BTA_FTS_OBX_CLOSE_EVT:
+ case BTA_FTS_OBX_PUT_EVT:
+ case BTA_FTS_OBX_GET_EVT:
+ case BTA_FTS_OBX_SETPATH_EVT:
+ utl_freebuf((void**)&p_data->obx_evt.p_pkt);
+ break;
+
+ default:
+ /*Nothing to free*/
+ break;
+ }
+}
+
+#endif /* BTA_FT_INCLUDED */
diff --git a/bta/gatt/bta_gattc_act.c b/bta/gatt/bta_gattc_act.c
new file mode 100644
index 0000000..ce0c209
--- /dev/null
+++ b/bta/gatt/bta_gattc_act.c
@@ -0,0 +1,1789 @@
+/*****************************************************************************
+**
+** Name: bta_gattc_act.c
+**
+** Description: This file contains the GATT client action
+** functions for the state machine.
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+
+#if defined(BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE)
+
+
+#include "utl.h"
+#include "gki.h"
+#include "bd.h"
+#include "bta_sys.h"
+
+#include "bta_gattc_int.h"
+#include "l2c_api.h"
+
+
+#include <string.h>
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+static void bta_gattc_conn_cback(tGATT_IF gattc_if, BD_ADDR bda, UINT16 conn_id,
+ BOOLEAN connected, tGATT_DISCONN_REASON reason);
+
+static void bta_gattc_cmpl_cback(UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS status,
+ tGATT_CL_COMPLETE *p_data);
+
+static tGATT_CBACK bta_gattc_cl_cback =
+{
+ bta_gattc_conn_cback,
+ bta_gattc_cmpl_cback,
+ bta_gattc_disc_res_cback,
+ bta_gattc_disc_cmpl_cback,
+ NULL
+};
+
+/* opcode(tGATTC_OPTYPE) order has to be comply with internal event order */
+static UINT16 bta_gattc_opcode_to_int_evt[] =
+{
+ BTA_GATTC_API_READ_EVT,
+ BTA_GATTC_API_WRITE_EVT,
+ BTA_GATTC_API_EXEC_EVT
+};
+
+#if (BT_TRACE_VERBOSE == TRUE)
+static const char *bta_gattc_op_code_name[] =
+{
+ "Unknown",
+ "Discovery",
+ "Read",
+ "Write",
+ "Exec",
+ "Config",
+ "Notification",
+ "Indication"
+};
+#endif
+/*****************************************************************************
+** Action Functions
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function bta_gattc_register
+**
+** Description Register a GATT client application with BTA.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_gattc_register(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_data)
+{
+ tBTA_GATTC cb_data;
+ UINT8 i;
+ tBT_UUID *p_app_uuid = &p_data->api_reg.app_uuid;
+ tBTA_GATTC_INT_START_IF *p_buf;
+
+
+ /* todo need to check duplicate uuid */
+ for (i = 0; i < BTA_GATTC_CL_MAX; i ++)
+ {
+ if (!p_cb->cl_rcb[i].in_use)
+ {
+ if ((p_app_uuid == NULL) || (p_cb->cl_rcb[i].client_if = GATT_Register(p_app_uuid, &bta_gattc_cl_cback)) == 0)
+ {
+ APPL_TRACE_ERROR0("Register with GATT stack failed.");
+ cb_data.reg_oper.status = BTA_GATT_ERROR;
+ }
+ else
+
+ {
+ p_cb->cl_rcb[i].in_use = TRUE;
+ p_cb->cl_rcb[i].p_cback = p_data->api_reg.p_cback;
+ memcpy(&p_cb->cl_rcb[i].app_uuid, p_app_uuid, sizeof(tBT_UUID));
+
+ /* BTA use the same client interface as BTE GATT statck */
+ cb_data.reg_oper.client_if = p_cb->cl_rcb[i].client_if;
+// btla-specific ++
+ memcpy(&(cb_data.reg_oper.app_uuid),p_app_uuid,sizeof(tBT_UUID));
+// btla-specific --
+
+ cb_data.reg_oper.status = BTA_GATT_OK;
+
+ if ((p_buf = (tBTA_GATTC_INT_START_IF *) GKI_getbuf(sizeof(tBTA_GATTC_INT_START_IF))) != NULL)
+ {
+ p_buf->hdr.event = BTA_GATTC_INT_START_IF_EVT;
+ p_buf->client_if = p_cb->cl_rcb[i].client_if;
+
+ bta_sys_sendmsg(p_buf);
+ }
+ else
+ {
+ cb_data.reg_oper.status = BTA_GATT_NO_RESOURCES;
+ memset( &p_cb->cl_rcb[i], 0 , sizeof(tBTA_GATTC_RCB));
+ }
+ break;
+ }
+ }
+ }
+ /* callback with register event */
+ if (p_data->api_reg.p_cback)
+ {
+ (*p_data->api_reg.p_cback)(BTA_GATTC_REG_EVT, (tBTA_GATTC *)&cb_data);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_gattc_start_if
+**
+** Description start an application interface.
+**
+** Returns none.
+**
+*******************************************************************************/
+void bta_gattc_start_if(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_msg)
+{
+ if (bta_gattc_cl_get_regcb(p_msg->int_start_if.client_if) !=NULL )
+ {
+ GATT_StartIf(p_msg->int_start_if.client_if);
+ }
+ else
+ {
+ APPL_TRACE_ERROR1("Unable to start app.: Unknown interface =%d",p_msg->int_start_if.client_if );
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function bta_gattc_deregister_cmpl
+**
+** Description De-Register a GATT client application with BTA completed.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_gattc_int_deregister_cmpl(tBTA_GATTC_RCB *p_clreg, tBTA_GATTC_IF client_if)
+{
+ tBTA_GATTC_CBACK *p_cback = p_clreg->p_cback;
+ tBTA_GATTC cb_data;
+
+
+ APPL_TRACE_DEBUG1("bta_gattc_int_deregister_cmpl client_if=%d", client_if );
+
+ GATT_Deregister(p_clreg->client_if);
+ memset(p_clreg, 0, sizeof(tBTA_GATTC_RCB));
+
+ cb_data.reg_oper.client_if = client_if;
+ cb_data.reg_oper.status = BTA_GATT_OK;
+
+ if (p_cback)
+ /* callback with de-register event */
+ (*p_cback)(BTA_GATTC_DEREG_EVT, (tBTA_GATTC *)&cb_data);
+}
+
+
+/*******************************************************************************
+**
+** Function bta_gattc_deregister_cmpl
+**
+** Description De-Register a GATT client application with BTA completed.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_gattc_deregister_cmpl(tBTA_GATTC_RCB *p_clreg, tBTA_GATTC_IF client_if)
+{
+ tBTA_GATTC_INT_DEREG *p_buf;
+
+ APPL_TRACE_DEBUG1("bta_gattc_deregister_cmpl client_if=%d", client_if );
+
+ if ((p_buf = (tBTA_GATTC_INT_DEREG *) GKI_getbuf(sizeof(tBTA_GATTC_INT_DEREG))) != NULL)
+ {
+ p_buf->hdr.event = BTA_GATTC_INT_DEREG_EVT;
+ p_buf->client_if = client_if;
+ bta_sys_sendmsg(p_buf);
+ }
+ else
+ {
+ APPL_TRACE_ERROR1("bta_gattc_deregister_cmpl unable to allocate buffer to complete dereg=%d", client_if);
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function bta_gattc_deregister
+**
+** Description De-Register a GATT client application with BTA.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_gattc_int_deregister(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_data)
+{
+
+ tBTA_GATTC_IF client_if = p_data->int_dereg.client_if;
+ tBTA_GATTC_CBACK *p_cback;
+ tBTA_GATTC cb_data;
+ tBTA_GATTC_RCB *p_clreg;
+
+
+ APPL_TRACE_DEBUG1("bta_gattc_int_deregister_cmpl client_if=%d", client_if );
+
+ if ((p_clreg = bta_gattc_cl_get_regcb(client_if)) != NULL)
+ {
+ p_cback = p_clreg->p_cback;
+ GATT_Deregister(client_if);
+ memset(p_clreg, 0, sizeof(tBTA_GATTC_RCB));
+ cb_data.reg_oper.client_if = client_if;
+ cb_data.reg_oper.status = BTA_GATT_OK;
+
+ if (p_cback)
+ /* callback with de-register event */
+ (*p_cback)(BTA_GATTC_DEREG_EVT, (tBTA_GATTC *)&cb_data);
+ }
+ else
+ {
+ APPL_TRACE_ERROR1("bta_gattc_int_deregister Deregister Failed, unknown client_if: %d", p_data->int_dereg.client_if);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function bta_gattc_deregister
+**
+** Description De-Register a GATT client application with BTA.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_gattc_deregister(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_data)
+{
+ tBTA_GATTC_RCB *p_clreg;
+ UINT8 i;
+ BT_HDR buf;
+
+ if ((p_clreg = bta_gattc_cl_get_regcb(p_data->api_dereg.client_if)) != NULL)
+ {
+ if (p_clreg->num_clcb > 0)
+ {
+ /* close all CLCB related to this app */
+ for (i= 0; i < BTA_GATTC_CLCB_MAX; i ++)
+ {
+ if (p_cb->clcb[i].in_use && (p_cb->clcb[i].p_rcb == p_clreg))
+ {
+ p_clreg->dereg_pending = TRUE;
+
+ buf.event = BTA_GATTC_API_CLOSE_EVT;
+ buf.layer_specific = p_cb->clcb[i].bta_conn_id;
+ bta_gattc_close(&p_cb->clcb[i], (tBTA_GATTC_DATA *)&buf) ;
+ }
+ }
+ }
+ else
+ bta_gattc_deregister_cmpl(p_clreg, p_clreg->client_if);
+ }
+ else
+ {
+ APPL_TRACE_ERROR1("bta_gattc_deregister Deregister Failed, unknown client_if: %d", p_data->api_dereg.client_if);
+ }
+}
+/*******************************************************************************
+**
+** Function bta_gattc_process_api_open
+**
+** Description process connect API request.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_gattc_process_api_open (tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA * p_msg)
+{
+ UINT16 event = ((BT_HDR *)p_msg)->event;
+ tBTA_GATTC_CLCB *p_clcb = NULL;
+ tBTA_GATTC_RCB *p_clreg = bta_gattc_cl_get_regcb(p_msg->api_conn.client_if);
+
+ if (p_clreg != NULL)
+ {
+ if (p_msg->api_conn.is_direct)
+ {
+ if ((p_clcb = bta_gattc_find_alloc_clcb(p_msg->api_conn.client_if,
+ p_msg->api_conn.remote_bda)) != NULL)
+ {
+ bta_gattc_sm_execute(p_clcb, event, p_msg);
+ }
+ else
+ {
+ APPL_TRACE_ERROR0("No resources to open a new connection.");
+
+ bta_gattc_send_open_cback(p_clreg,
+ BTA_GATT_NO_RESOURCES,
+ p_msg->api_conn.remote_bda,
+ BTA_GATT_INVALID_CONN_ID);
+ }
+ }
+ else
+ {
+ bta_gattc_init_bk_conn(&p_msg->api_conn, p_clreg);
+ }
+ }
+ else
+ {
+ APPL_TRACE_ERROR1("bta_gattc_process_api_open Failed, unknown client_if: %d",
+ p_msg->api_conn.client_if);
+ }
+}
+/*******************************************************************************
+**
+** Function bta_gattc_process_api_open_cancel
+**
+** Description process connect API request.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_gattc_process_api_open_cancel (tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA * p_msg)
+{
+ UINT16 event = ((BT_HDR *)p_msg)->event;
+ tBTA_GATTC_CLCB *p_clcb = NULL;
+ tBTA_GATTC_RCB *p_clreg;
+ tBTA_GATT_STATUS status = BTA_GATT_ERROR;
+
+ if (p_msg->api_cancel_conn.is_direct)
+ {
+ if ((p_clcb = bta_gattc_find_clcb_by_cif(p_msg->api_cancel_conn.client_if,
+ p_msg->api_cancel_conn.remote_bda)) != NULL)
+ {
+ bta_gattc_sm_execute(p_clcb, event, p_msg);
+ }
+ else
+ {
+ APPL_TRACE_ERROR0("No such connection need to be cancelled");
+
+ p_clreg = bta_gattc_cl_get_regcb(p_msg->api_cancel_conn.client_if);
+
+ if (p_clreg && p_clreg->p_cback)
+ {
+ (*p_clreg->p_cback)(BTA_GATTC_CANCEL_OPEN_EVT, (tBTA_GATTC *)&status);
+ }
+ }
+ }
+ else
+ {
+ bta_gattc_cancel_bk_conn(&p_msg->api_cancel_conn);
+
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_gattc_cancel_open_error
+**
+** Description
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_gattc_cancel_open_error(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
+{
+ tBTA_GATT_STATUS status=BTA_GATT_ERROR;
+
+ if ( p_clcb->p_rcb->p_cback )
+ (*p_clcb->p_rcb->p_cback)(BTA_GATTC_CANCEL_OPEN_EVT, (tBTA_GATTC *)&status);
+}
+
+/*******************************************************************************
+**
+** Function bta_gattc_open_error
+**
+** Description
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_gattc_open_error(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
+{
+ APPL_TRACE_ERROR0("Connection already opened. wrong state");
+
+ bta_gattc_send_open_cback(p_clcb->p_rcb,
+ BTA_GATT_ALREADY_OPEN,
+ p_clcb->bda,
+ p_clcb->bta_conn_id);
+}
+/*******************************************************************************
+**
+** Function bta_gattc_open_fail
+**
+** Description
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_gattc_open_fail(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
+{
+ bta_gattc_open_error(p_clcb, p_data);
+ /* open failure, remove clcb */
+ bta_gattc_clcb_dealloc(p_clcb);
+}
+
+/*******************************************************************************
+**
+** Function bta_gattc_open
+**
+** Description Process API connection function.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_gattc_open(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
+{
+ tBTA_GATTC_DATA gattc_data;
+
+ /* open/hold a connection */
+ if (!GATT_Connect(p_clcb->p_rcb->client_if, p_data->api_conn.remote_bda, TRUE))
+ {
+ APPL_TRACE_ERROR0("Connection open failure");
+
+ bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_OPEN_FAIL_EVT, p_data);
+ }
+ else
+ {
+ /* a connected remote device */
+ if (GATT_GetConnIdIfConnected(p_clcb->p_rcb->client_if,
+ p_data->api_conn.remote_bda,
+ &p_clcb->bta_conn_id))
+ {
+ gattc_data.hdr.layer_specific = p_clcb->bta_conn_id;
+
+ bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_CONN_EVT, &gattc_data);
+ }
+ /* else wait for the callback event */
+ }
+}
+/*******************************************************************************
+**
+** Function bta_gattc_init_bk_conn
+**
+** Description Process API Open for a background connection
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_gattc_init_bk_conn(tBTA_GATTC_API_OPEN *p_data, tBTA_GATTC_RCB *p_clreg)
+{
+ tBTA_GATT_STATUS status = BTA_GATT_NO_RESOURCES;
+ UINT16 conn_id;
+ tBTA_GATTC_CLCB *p_clcb;
+ tBTA_GATTC_DATA gattc_data;
+
+ if (bta_gattc_mark_bg_conn(p_data->client_if, p_data->remote_bda, TRUE))
+ {
+ /* alwaya call open to hold a connection */
+ if (!GATT_Connect(p_data->client_if, p_data->remote_bda, FALSE))
+ {
+ status = BTA_GATT_ERROR;
+ APPL_TRACE_ERROR0("bta_gattc_init_bk_conn failed");
+ }
+ else
+ {
+ status = BTA_GATT_OK;
+
+ /* if is a connected remote device */
+ if (GATT_GetConnIdIfConnected(p_data->client_if,
+ p_data->remote_bda,
+ &conn_id))
+ {
+ if ((p_clcb = bta_gattc_clcb_alloc(p_data->client_if, p_data->remote_bda)) != NULL)
+ {
+ gattc_data.hdr.layer_specific = p_clcb->bta_conn_id = conn_id;
+
+ /* open connection */
+ bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_CONN_EVT, &gattc_data);
+ status = BTA_GATT_OK;
+ }
+ }
+ }
+ }
+
+ /* open failure, report OPEN_EVT */
+ if (status != BTA_GATT_OK)
+ {
+ bta_gattc_send_open_cback(p_clreg, status, p_data->remote_bda, BTA_GATT_INVALID_CONN_ID);
+ }
+}
+/*******************************************************************************
+**
+** Function bta_gattc_cancel_bk_conn
+**
+** Description Process API Cancel Open for a background connection
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_gattc_cancel_bk_conn(tBTA_GATTC_API_CANCEL_OPEN *p_data)
+{
+ tBTA_GATTC_RCB *p_clreg;
+ tBTA_GATT_STATUS status = BTA_GATT_ERROR;
+
+ /* remove the device from the bg connection mask */
+ if (bta_gattc_mark_bg_conn(p_data->client_if, p_data->remote_bda, FALSE))
+ {
+ if (GATT_CancelConnect(p_data->client_if, p_data->remote_bda, FALSE))
+ {
+ status = BTA_GATT_OK;
+ }
+ else
+ {
+ APPL_TRACE_ERROR0("bta_gattc_cancel_bk_conn failed");
+ }
+ }
+ p_clreg = bta_gattc_cl_get_regcb(p_data->client_if);
+
+ if (p_clreg && p_clreg->p_cback)
+ {
+ (*p_clreg->p_cback)(BTA_GATTC_CANCEL_OPEN_EVT, (tBTA_GATTC *)&status);
+ }
+
+}
+/*******************************************************************************
+**
+** Function bta_gattc_int_cancel_open_ok
+**
+** Description
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_gattc_cancel_open_ok(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
+{
+ tBTA_GATT_STATUS status = BTA_GATT_OK;
+
+ if ( p_clcb->p_rcb->p_cback )
+ {
+ (*p_clcb->p_rcb->p_cback)(BTA_GATTC_CANCEL_OPEN_EVT, (tBTA_GATTC *)&status);
+ }
+
+ bta_gattc_clcb_dealloc(p_clcb);
+}
+
+/*******************************************************************************
+**
+** Function bta_gattc_cancel_open
+**
+** Description
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_gattc_cancel_open(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
+{
+ tBTA_GATT_STATUS status=BTA_GATT_ERROR;
+
+ if (GATT_CancelConnect(p_clcb->p_rcb->client_if, p_data->api_cancel_conn.remote_bda, TRUE))
+ {
+ bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_CANCEL_OPEN_OK_EVT, p_data);
+ }
+ else
+ {
+ if ( p_clcb->p_rcb->p_cback )
+ {
+ (*p_clcb->p_rcb->p_cback)(BTA_GATTC_CANCEL_OPEN_EVT, (tBTA_GATTC *)&status);
+ }
+ }
+}
+/*******************************************************************************
+**
+** Function bta_gattc_conn
+**
+** Description receive connection callback from stack
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_gattc_conn(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
+{
+ tBTA_GATTC_IF gatt_if;
+ APPL_TRACE_DEBUG1("bta_gattc_conn server cache state=%d",p_clcb->p_srcb->state);
+
+ if (p_data != NULL)
+ {
+ APPL_TRACE_DEBUG1("bta_gattc_conn conn_id=%d",p_data->hdr.layer_specific);
+
+ p_clcb->p_srcb->connected = TRUE;
+ p_clcb->bta_conn_id = p_data->hdr.layer_specific;
+ GATT_GetConnectionInfor(p_data->hdr.layer_specific, &gatt_if, p_clcb->bda);
+
+ /* start database cache if needed */
+ if (p_clcb->p_srcb->p_srvc_cache == NULL)
+ {
+ if (p_clcb->p_srcb->state == BTA_GATTC_SERV_IDLE)
+ {
+ p_clcb->p_srcb->state = BTA_GATTC_SERV_LOAD;
+ bta_gattc_sm_execute(p_clcb, BTA_GATTC_START_CACHE_EVT, p_data);
+ }
+ else /* cache is building */
+ p_clcb->state = BTA_GATTC_DISCOVER_ST;
+ }
+
+ else
+ {
+ /* a pending service handle change indication */
+ if (p_clcb->p_srcb->srvc_hdl_chg)
+ {
+ p_clcb->p_srcb->srvc_hdl_chg = FALSE;
+ /* start discovery */
+ bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_DISCOVER_EVT, NULL);
+ }
+ }
+
+ if (p_clcb->p_rcb)
+ {
+ bta_gattc_send_open_cback(p_clcb->p_rcb,
+ BTA_GATT_OK,
+ p_clcb->bda,
+ p_clcb->bta_conn_id);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_gattc_close_fail
+**
+** Description close a connection.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_gattc_close_fail(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
+{
+ tBTA_GATTC cb_data;
+
+ if ( p_clcb->p_rcb->p_cback )
+ {
+ memset(&cb_data, 0, sizeof(tBTA_GATTC));
+ cb_data.close.client_if = p_clcb->p_rcb->client_if;
+ cb_data.close.conn_id = p_data->hdr.layer_specific;
+ bdcpy(cb_data.close.remote_bda, p_clcb->bda);
+ cb_data.close.status = BTA_GATT_ERROR;
+ cb_data.close.reason = BTA_GATT_CONN_NONE;
+
+
+ (*p_clcb->p_rcb->p_cback)(BTA_GATTC_CLOSE_EVT, &cb_data);
+ }
+}
+/*******************************************************************************
+**
+** Function bta_gattc_api_close
+**
+** Description close a GATTC connection.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_gattc_close(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
+{
+ tBTA_GATTC_CBACK *p_cback = p_clcb->p_rcb->p_cback;
+ tBTA_GATTC_RCB *p_clreg = p_clcb->p_rcb;
+ tBTA_GATTC cb_data;
+
+ APPL_TRACE_DEBUG1("bta_gattc_close conn_id=%d",p_clcb->bta_conn_id);
+
+ if (p_data->hdr.event == BTA_GATTC_API_CLOSE_EVT)
+ p_clcb->status = GATT_Disconnect(p_clcb->bta_conn_id);
+
+ cb_data.close.client_if = p_clcb->p_rcb->client_if;
+ cb_data.close.conn_id = p_clcb->bta_conn_id;
+ cb_data.close.status = p_clcb->status;
+ cb_data.close.reason = p_clcb->reason;
+ bdcpy(cb_data.close.remote_bda, p_clcb->bda);
+
+ if (p_clcb->status == BTA_GATT_OK)
+ {
+ /* if the srcb is no longer needed, reset the state */
+ if ( -- p_clcb->p_srcb->num_clcb == 0)
+ {
+ APPL_TRACE_DEBUG0("Update srcb connection status");
+ p_clcb->p_srcb->connected = FALSE;
+ p_clcb->p_srcb->state = BTA_GATTC_SERV_IDLE;
+ }
+
+ bta_gattc_clcb_dealloc(p_clcb);
+ }
+
+ ( * p_cback)(BTA_GATTC_CLOSE_EVT, (tBTA_GATTC *)&cb_data);
+
+ if (-- p_clreg->num_clcb == 0 && p_clreg->dereg_pending)
+ {
+ bta_gattc_deregister_cmpl(p_clreg, p_clreg->client_if);
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function bta_gattc_reset_discover_st
+**
+** Description when a SRCB finished discovery, tell all related clcb.
+**
+** Returns None.
+**
+*******************************************************************************/
+void bta_gattc_reset_discover_st(tBTA_GATTC_SERV *p_srcb)
+{
+ tBTA_GATTC_CB *p_cb = &bta_gattc_cb;
+ UINT8 i;
+
+ for (i = 0; i < BTA_GATTC_CLCB_MAX; i ++)
+ {
+ if (p_cb->clcb[i].p_srcb == p_srcb)
+ {
+ bta_gattc_sm_execute(&p_cb->clcb[i], BTA_GATTC_DISCOVER_CMPL_EVT, NULL);
+ }
+ }
+}
+/*******************************************************************************
+**
+** Function bta_gattc_set_discover_st
+**
+** Description when a SRCB start discovery, tell all related clcb and set
+** the state.
+**
+** Returns None.
+**
+*******************************************************************************/
+void bta_gattc_set_discover_st(tBTA_GATTC_SERV *p_srcb)
+{
+ tBTA_GATTC_CB *p_cb = &bta_gattc_cb;
+ UINT8 i;
+
+#if BLE_INCLUDED == TRUE
+ L2CA_EnableUpdateBleConnParams(p_srcb->server_bda, FALSE);
+#endif
+ for (i = 0; i < BTA_GATTC_CLCB_MAX; i ++)
+ {
+ if (p_cb->clcb[i].p_srcb == p_srcb)
+ {
+ p_cb->clcb[i].state = BTA_GATTC_DISCOVER_ST;
+ }
+ }
+}
+/*******************************************************************************
+**
+** Function bta_gattc_start_discover
+**
+** Description Start a discovery on server.
+**
+** Returns None.
+**
+*******************************************************************************/
+void bta_gattc_start_discover(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
+{
+ /* pending operation, wait until it finishes */
+
+ APPL_TRACE_DEBUG1("bta_gattc_start_discover conn_id=%d",p_clcb->bta_conn_id);
+ if (p_clcb->p_q_cmd != NULL && p_clcb->auto_update == BTA_GATTC_NO_SCHEDULE &&
+ p_clcb->p_srcb->state == BTA_GATTC_SERV_IDLE)
+ {
+ p_clcb->auto_update = BTA_GATTC_DISC_WAITING;
+ p_clcb->state = BTA_GATTC_CONN_ST; /* set clcb state */
+ }
+ else /* no pending operation, start discovery right away */
+ {
+ p_clcb->auto_update = BTA_GATTC_NO_SCHEDULE;
+
+ if (p_clcb->p_srcb != NULL)
+ {
+ /* clear the service change mask */
+ p_clcb->p_srcb->srvc_hdl_chg = FALSE;
+ p_clcb->p_srcb->update_count = 0;
+
+ /* set all srcb related clcb into discovery ST */
+ bta_gattc_set_discover_st(p_clcb->p_srcb);
+
+ if ( bta_gattc_init_cache(p_clcb->p_srcb) ||
+ bta_gattc_discover_pri_service(p_clcb->bta_conn_id, p_clcb->p_srcb, GATT_DISC_SRVC_ALL) != BTA_GATT_OK)
+ {
+ APPL_TRACE_ERROR0("discovery on server failed");
+ bta_gattc_reset_discover_st(p_clcb->p_srcb);
+ }
+ }
+ else
+ {
+ APPL_TRACE_ERROR0("unknown device, can not start discovery");
+ }
+ }
+}
+/*******************************************************************************
+**
+** Function bta_gattc_disc_cmpl
+**
+** Description discovery on server is finished
+**
+** Returns None.
+**
+*******************************************************************************/
+void bta_gattc_disc_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
+{
+ tBTA_GATTC_DATA *p_q_cmd = p_clcb->p_q_cmd;
+ APPL_TRACE_DEBUG1("bta_gattc_disc_cmpl conn_id=%d",p_clcb->bta_conn_id);
+
+#if BLE_INCLUDED == TRUE
+ L2CA_EnableUpdateBleConnParams(p_clcb->p_srcb->server_bda, TRUE);
+#endif
+ p_clcb->p_srcb->state = BTA_GATTC_SERV_IDLE;
+
+ /* release pending attribute list buffer */
+ utl_freebuf((void **)&p_clcb->p_srcb->p_srvc_list);
+
+ /* get any queued command to proceed */
+ if (p_q_cmd != NULL)
+ {
+ p_clcb->p_q_cmd = NULL;
+
+ bta_gattc_sm_execute(p_clcb, p_q_cmd->hdr.event, p_q_cmd);
+
+ utl_freebuf((void **)&p_q_cmd);
+
+ }
+}
+/*******************************************************************************
+**
+** Function bta_gattc_read
+**
+** Description Read an attribute
+**
+** Returns None.
+**
+*******************************************************************************/
+void bta_gattc_read(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
+{
+ UINT16 handle = 0;
+ tGATT_READ_PARAM read_param;
+ tBTA_GATTC_OP_CMPL op_cmpl;
+
+ memset (&read_param, 0 ,sizeof(tGATT_READ_PARAM));
+ memset (&op_cmpl, 0 ,sizeof(tBTA_GATTC_OP_CMPL));
+
+ if (bta_gattc_enqueue(p_clcb, p_data))
+ {
+ if ((handle = bta_gattc_id2handle(p_clcb->p_srcb,
+ &p_data->api_read.srvc_id,
+ &p_data->api_read.char_id,
+ p_data->api_read.descr_type)) == 0)
+ {
+ op_cmpl.status = BTA_GATT_ERROR;
+ }
+ else
+ {
+ read_param.by_handle.handle = handle;
+ read_param.by_handle.auth_req = p_data->api_read.auth_req;
+
+ op_cmpl.status = GATTC_Read(p_clcb->bta_conn_id, GATT_READ_BY_HANDLE, &read_param);
+ }
+
+ /* read fail */
+ if (op_cmpl.status != BTA_GATT_OK)
+ {
+ op_cmpl.op_code = GATTC_OPTYPE_READ;
+ op_cmpl.p_cmpl = NULL;
+
+ bta_gattc_sm_execute(p_clcb, BTA_GATTC_OP_CMPL_EVT, (tBTA_GATTC_DATA *)&op_cmpl);
+ }
+ }
+}
+/*******************************************************************************
+**
+** Function bta_gattc_read_multi
+**
+** Description read multiple
+**
+** Returns None.
+*********************************************************************************/
+void bta_gattc_read_multi(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
+{
+ UINT16 i, handle;
+ tBTA_GATT_STATUS status = BTA_GATT_OK;
+ tGATT_READ_PARAM read_param;
+ tBTA_GATTC_OP_CMPL op_cmpl;
+ tBTA_GATTC_ATTR_ID *p_id;
+ tBT_UUID dummy_uuid;
+
+ if (bta_gattc_enqueue(p_clcb, p_data))
+ {
+ memset(&dummy_uuid, 0, sizeof(tBT_UUID));
+ memset(&read_param, 0, sizeof(tGATT_READ_PARAM));
+
+ p_id = p_data->api_read_multi.p_id_list;
+
+ for (i = 0; i < p_data->api_read_multi.num_attr && p_id; i ++, p_id ++)
+ {
+ handle = 0;
+
+ if (p_id->id_type == BTA_GATT_TYPE_CHAR)
+ {
+ handle = bta_gattc_id2handle(p_clcb->p_srcb,
+ &p_id->id_value.char_id.srvc_id,
+ &p_id->id_value.char_id.char_id,
+ dummy_uuid);
+ }
+ else if (p_id->id_type == BTA_GATT_TYPE_CHAR_DESCR)
+ {
+ handle = bta_gattc_id2handle(p_clcb->p_srcb,
+ &p_id->id_value.char_descr_id.char_id.srvc_id,
+ &p_id->id_value.char_descr_id.char_id.char_id,
+ p_id->id_value.char_descr_id.descr_type);
+ }
+ else
+ {
+ APPL_TRACE_ERROR1("invalud ID type: %d", p_id->id_type);
+ }
+
+ if (handle == 0)
+ {
+ status = BTA_GATT_ERROR;
+ break;
+ }
+ }
+ if (status == BTA_GATT_OK)
+ {
+ read_param.read_multiple.num_handles = p_data->api_read_multi.num_attr;
+ read_param.read_multiple.auth_req = p_data->api_read_multi.auth_req;
+
+ status = GATTC_Read(p_clcb->bta_conn_id, GATT_READ_MULTIPLE, &read_param);
+ }
+
+ /* read fail */
+ if (status != BTA_GATT_OK)
+ {
+ memset(&op_cmpl, 0, sizeof(tBTA_GATTC_OP_CMPL));
+
+ op_cmpl.status = status;
+ op_cmpl.op_code = GATTC_OPTYPE_READ;
+ op_cmpl.p_cmpl = NULL;
+
+ bta_gattc_sm_execute(p_clcb, BTA_GATTC_OP_CMPL_EVT, (tBTA_GATTC_DATA *)&op_cmpl);
+ }
+ }
+}
+/*******************************************************************************
+**
+** Function bta_gattc_write
+**
+** Description Write an attribute
+**
+** Returns None.
+**
+*******************************************************************************/
+void bta_gattc_write(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
+{
+ UINT16 handle = 0;
+ tGATT_VALUE attr = {0};
+ tBTA_GATTC_OP_CMPL op_cmpl;
+ tBTA_GATT_STATUS status = BTA_GATT_OK;
+
+ if (bta_gattc_enqueue(p_clcb, p_data))
+ {
+ if ((handle = bta_gattc_id2handle(p_clcb->p_srcb,
+ &p_data->api_write.srvc_id,
+ &p_data->api_write.char_id,
+ p_data->api_write.descr_type)) == 0)
+ {
+ status = BTA_GATT_ERROR;
+ }
+ else
+ {
+ attr.handle= handle;
+ attr.offset = p_data->api_write.offset;
+ attr.len = p_data->api_write.len;
+ attr.auth_req = p_data->api_write.auth_req;
+
+ if (p_data->api_write.p_value)
+ memcpy(attr.value, p_data->api_write.p_value, p_data->api_write.len);
+
+ status = GATTC_Write(p_clcb->bta_conn_id, p_data->api_write.write_type, &attr);
+ }
+
+ /* write fail */
+ if (status != BTA_GATT_OK)
+ {
+ memset(&op_cmpl, 0, sizeof(tBTA_GATTC_OP_CMPL));
+
+ op_cmpl.status = status;
+ op_cmpl.op_code = GATTC_OPTYPE_WRITE;
+ op_cmpl.p_cmpl = NULL;
+
+ bta_gattc_sm_execute(p_clcb, BTA_GATTC_OP_CMPL_EVT, (tBTA_GATTC_DATA *)&op_cmpl);
+ }
+ }
+}
+/*******************************************************************************
+**
+** Function bta_gattc_execute
+**
+** Description send execute write
+**
+** Returns None.
+*********************************************************************************/
+void bta_gattc_execute(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
+{
+ tBTA_GATTC_OP_CMPL op_cmpl;
+ tBTA_GATT_STATUS status;
+
+ if (bta_gattc_enqueue(p_clcb, p_data))
+ {
+ status = GATTC_ExecuteWrite(p_clcb->bta_conn_id, p_data->api_exec.is_execute);
+
+ if (status != BTA_GATT_OK)
+ {
+ memset(&op_cmpl, 0, sizeof(tBTA_GATTC_OP_CMPL));
+
+ op_cmpl.status = status;
+ op_cmpl.op_code = GATTC_OPTYPE_EXE_WRITE;
+ op_cmpl.p_cmpl = NULL;
+
+ bta_gattc_sm_execute(p_clcb, BTA_GATTC_OP_CMPL_EVT, (tBTA_GATTC_DATA *)&op_cmpl);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_gattc_confirm
+**
+** Description send handle value confirmation
+**
+** Returns None.
+**
+*******************************************************************************/
+void bta_gattc_confirm(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
+{
+ UINT16 handle;
+ tBT_UUID null_uuid = {0};
+
+ if ((handle = bta_gattc_id2handle(p_clcb->p_srcb,
+ &p_data->api_confirm.srvc_id,
+ &p_data->api_confirm.char_id,
+ null_uuid)) == 0)
+ {
+ APPL_TRACE_ERROR0("Can not map service/char ID into valid handle");
+ }
+ else
+ {
+ if (GATTC_SendHandleValueConfirm(p_data->api_confirm.hdr.layer_specific, handle)
+ != GATT_SUCCESS)
+ {
+ APPL_TRACE_ERROR1("bta_gattc_confirm to handle [0x%04x] failed", handle);
+ }
+ }
+}
+/*******************************************************************************
+**
+** Function bta_gattc_read_cmpl
+**
+** Description read complete
+**
+** Returns None.
+**
+*******************************************************************************/
+void bta_gattc_read_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_OP_CMPL *p_data)
+{
+ UINT8 event;
+ tBTA_GATTC cb_data;
+ tBTA_GATT_READ_VAL read_value;
+
+ memset(&cb_data, 0, sizeof(tBTA_GATTC));
+ memset(&read_value, 0, sizeof(tBTA_GATT_READ_VAL));
+
+ cb_data.read.status = p_data->status;
+
+ if (p_data->p_cmpl != NULL && p_data->status == BTA_GATT_OK)
+ {
+ if (bta_gattc_handle2id(p_clcb->p_srcb,
+ p_data->p_cmpl->att_value.handle,
+ &cb_data.read.srvc_id,
+ &cb_data.read.char_id,
+ &cb_data.read.descr_type) == FALSE)
+ {
+ cb_data.read.status = BTA_GATT_INTERNAL_ERROR;
+ APPL_TRACE_ERROR1("can not map to GATT ID. handle = 0x%04x", p_data->p_cmpl->att_value.handle);
+ }
+ else
+ {
+ cb_data.read.status = bta_gattc_pack_read_cb_data(p_clcb->p_srcb,
+ cb_data.read.descr_type,
+ &p_data->p_cmpl->att_value,
+ &read_value);
+ cb_data.read.p_value = &read_value;
+ }
+ }
+ else
+ {
+ cb_data.read.srvc_id = p_clcb->p_q_cmd->api_read.srvc_id;
+ cb_data.read.char_id = p_clcb->p_q_cmd->api_read.char_id;
+ cb_data.read.descr_type = p_clcb->p_q_cmd->api_read.descr_type;
+ }
+
+ event = (p_clcb->p_q_cmd->api_read.descr_type.len == 0) ? BTA_GATTC_READ_CHAR_EVT: BTA_GATTC_READ_DESCR_EVT;
+ cb_data.read.conn_id = p_clcb->bta_conn_id;
+
+ utl_freebuf((void **)&p_clcb->p_q_cmd);
+ /* read complete, callback */
+ ( *p_clcb->p_rcb->p_cback)(event, (tBTA_GATTC *)&cb_data);
+
+}
+/*******************************************************************************
+**
+** Function bta_gattc_write_cmpl
+**
+** Description read complete
+**
+** Returns None.
+**
+*******************************************************************************/
+void bta_gattc_write_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_OP_CMPL *p_data)
+{
+ tBTA_GATTC cb_data = {0};
+ UINT8 event;
+
+ cb_data.write.status = p_data->status;
+
+ if (p_data->p_cmpl != NULL)
+ {
+ bta_gattc_handle2id(p_clcb->p_srcb, p_data->p_cmpl->handle,
+ &cb_data.write.srvc_id, &cb_data.write.char_id,
+ &cb_data.write.descr_type);
+ }
+ else
+ {
+ cb_data.write.srvc_id = p_clcb->p_q_cmd->api_write.srvc_id;
+ cb_data.write.char_id = p_clcb->p_q_cmd->api_write.char_id;
+ cb_data.write.descr_type = p_clcb->p_q_cmd->api_write.descr_type;
+ }
+
+ if (p_clcb->p_q_cmd->api_write.hdr.event == BTA_GATTC_API_WRITE_EVT &&
+ p_clcb->p_q_cmd->api_write.write_type == BTA_GATTC_WRITE_PREPARE)
+
+ event = BTA_GATTC_PREP_WRITE_EVT;
+
+ else if (p_clcb->p_q_cmd->api_write.descr_type.len == 0)
+
+ event = BTA_GATTC_WRITE_CHAR_EVT;
+
+ else
+ event = BTA_GATTC_WRITE_DESCR_EVT;
+
+ utl_freebuf((void **)&p_clcb->p_q_cmd);
+ cb_data.write.conn_id = p_clcb->bta_conn_id;
+ /* write complete, callback */
+ ( *p_clcb->p_rcb->p_cback)(event, (tBTA_GATTC *)&cb_data);
+
+}
+/*******************************************************************************
+**
+** Function bta_gattc_exec_cmpl
+**
+** Description execute write complete
+**
+** Returns None.
+**
+*******************************************************************************/
+void bta_gattc_exec_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_OP_CMPL *p_data)
+{
+ tBTA_GATTC cb_data;
+
+ utl_freebuf((void **)&p_clcb->p_q_cmd);
+
+ p_clcb->status = BTA_GATT_OK;
+
+ /* execute complete, callback */
+ cb_data.exec_cmpl.conn_id = p_clcb->bta_conn_id;
+ cb_data.exec_cmpl.status = p_data->status;
+
+ ( *p_clcb->p_rcb->p_cback)(BTA_GATTC_EXEC_EVT, &cb_data);
+
+}
+
+
+/*******************************************************************************
+**
+** Function bta_gattc_op_cmpl
+**
+** Description operation completed.
+**
+** Returns None.
+**
+*******************************************************************************/
+void bta_gattc_op_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
+{
+ UINT8 op = (UINT8)p_data->op_cmpl.op_code;
+ UINT8 mapped_op = 0;
+
+ APPL_TRACE_DEBUG1("bta_gattc_op_cmpl op = %d", op);
+
+ if (op == GATTC_OPTYPE_INDICATION || op == GATTC_OPTYPE_NOTIFICATION)
+ {
+ APPL_TRACE_ERROR0("unexpected operation, ignored");
+ }
+ else if (op >= GATTC_OPTYPE_READ)
+ {
+ if (p_clcb->p_q_cmd == NULL)
+ {
+ APPL_TRACE_ERROR0("No pending command");
+ return;
+ }
+ if (p_clcb->p_q_cmd->hdr.event != bta_gattc_opcode_to_int_evt[op - GATTC_OPTYPE_READ])
+ {
+ mapped_op = p_clcb->p_q_cmd->hdr.event - BTA_GATTC_API_READ_EVT + GATTC_OPTYPE_READ;
+ if ( mapped_op > GATTC_OPTYPE_INDICATION) mapped_op = 0;
+
+#if (BT_TRACE_VERBOSE == TRUE)
+ APPL_TRACE_ERROR3("expect op:(%s :0x%04x), receive unexpected operation (%s).",
+ bta_gattc_op_code_name[mapped_op] , p_clcb->p_q_cmd->hdr.event,
+ bta_gattc_op_code_name[op]);
+#else
+ APPL_TRACE_ERROR3("expect op:(%u :0x%04x), receive unexpected operation (%u).",
+ mapped_op , p_clcb->p_q_cmd->hdr.event, op);
+#endif
+ return;
+ }
+
+ /* service handle change void the response, discard it */
+ if (p_clcb->auto_update == BTA_GATTC_DISC_WAITING)
+ {
+ p_clcb->auto_update = BTA_GATTC_REQ_WAITING;
+ bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_DISCOVER_EVT, NULL);
+ }
+ else if (op == GATTC_OPTYPE_READ)
+ bta_gattc_read_cmpl(p_clcb, &p_data->op_cmpl);
+
+ else if (op == GATTC_OPTYPE_WRITE)
+ bta_gattc_write_cmpl(p_clcb, &p_data->op_cmpl);
+
+ else if (op == GATTC_OPTYPE_EXE_WRITE)
+ bta_gattc_exec_cmpl(p_clcb, &p_data->op_cmpl);
+ /*
+ else if (op == GATTC_OPTYPE_CONFIG) // API to be added
+ {
+ }
+ */
+ }
+}
+/*******************************************************************************
+**
+** Function bta_gattc_op_cmpl
+**
+** Description operation completed.
+**
+** Returns None.
+**
+*******************************************************************************/
+void bta_gattc_ignore_op_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
+{
+ /* receive op complete when discovery is started, ignore the response,
+ and wait for discovery finish and resent */
+ APPL_TRACE_DEBUG1("bta_gattc_ignore_op_cmpl op = %d", p_data->hdr.layer_specific);
+
+}
+/*******************************************************************************
+**
+** Function bta_gattc_search
+**
+** Description start a search in the local server cache
+**
+** Returns None.
+**
+*******************************************************************************/
+void bta_gattc_search(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
+{
+ tBTA_GATT_STATUS status = GATT_INTERNAL_ERROR;
+ tBTA_GATTC cb_data;
+ APPL_TRACE_DEBUG1("bta_gattc_search conn_id=%d",p_clcb->bta_conn_id);
+ if (p_clcb->p_srcb && p_clcb->p_srcb->p_srvc_cache)
+ {
+ status = BTA_GATT_OK;
+ /* search the local cache of a server device */
+ bta_gattc_search_service(p_clcb, p_data->api_search.srvc_uuid);
+ }
+ cb_data.search_cmpl.status = status;
+ cb_data.search_cmpl.conn_id = p_clcb->bta_conn_id;
+
+ /* end of search or no server cache available */
+ ( *p_clcb->p_rcb->p_cback)(BTA_GATTC_SEARCH_CMPL_EVT, &cb_data);
+}
+/*******************************************************************************
+**
+** Function bta_gattc_q_cmd
+**
+** Description enqueue a command into control block, usually because discovery
+** operation is busy.
+**
+** Returns None.
+**
+*******************************************************************************/
+void bta_gattc_q_cmd(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
+{
+ bta_gattc_enqueue(p_clcb, p_data);
+}
+/*******************************************************************************
+**
+** Function bta_gattc_cache_open
+**
+** Description open a NV cache for loading
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_gattc_cache_open(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
+{
+ bta_gattc_set_discover_st(p_clcb->p_srcb);
+
+ APPL_TRACE_DEBUG1("bta_gattc_cache_open conn_id=%d",p_clcb->bta_conn_id);
+ bta_gattc_co_cache_open(p_clcb->p_srcb->server_bda, BTA_GATTC_CI_CACHE_OPEN_EVT,
+ p_clcb->bta_conn_id, FALSE);
+}
+/*******************************************************************************
+**
+** Function bta_gattc_start_load
+**
+** Description start cache loading by sending callout open cache
+**
+** Returns None.
+**
+*******************************************************************************/
+void bta_gattc_ci_open(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
+{
+ APPL_TRACE_DEBUG2("bta_gattc_ci_open conn_id=%d server state=%d" ,
+ p_clcb->bta_conn_id, p_clcb->p_srcb->state);
+ if (p_clcb->p_srcb->state == BTA_GATTC_SERV_LOAD)
+ {
+ if (p_data->ci_open.status == BTA_GATT_OK)
+ {
+ p_clcb->p_srcb->attr_index = 0;
+ bta_gattc_co_cache_load(p_clcb->p_srcb->server_bda,
+ BTA_GATTC_CI_CACHE_LOAD_EVT,
+ p_clcb->p_srcb->attr_index,
+ p_clcb->bta_conn_id);
+ }
+ else
+ {
+ /* cache open failure, start discovery */
+ bta_gattc_start_discover(p_clcb, NULL);
+ }
+ }
+ if (p_clcb->p_srcb->state == BTA_GATTC_SERV_SAVE)
+ {
+ if (p_data->ci_open.status == BTA_GATT_OK)
+ {
+ if (!bta_gattc_cache_save(p_clcb->p_srcb, p_clcb->bta_conn_id))
+ {
+ p_data->ci_open.status = BTA_GATT_ERROR;
+ }
+ }
+ if (p_data->ci_open.status != BTA_GATT_OK)
+ {
+ p_clcb->p_srcb->attr_index = 0;
+ bta_gattc_co_cache_close(p_clcb->p_srcb->server_bda, p_clcb->bta_conn_id);
+ bta_gattc_reset_discover_st(p_clcb->p_srcb);
+
+ }
+ }
+}
+/*******************************************************************************
+**
+** Function bta_gattc_ci_load
+**
+** Description cache loading received.
+**
+** Returns None.
+**
+*******************************************************************************/
+void bta_gattc_ci_load(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
+{
+
+ APPL_TRACE_DEBUG2("bta_gattc_ci_load conn_id=%d load status=%d" ,
+ p_clcb->bta_conn_id, p_data->ci_load.status );
+ bta_gattc_co_cache_close(p_clcb->p_srcb->server_bda, 0);
+
+ if ((p_data->ci_load.status == BTA_GATT_OK ||
+ p_data->ci_load.status == BTA_GATT_MORE) &&
+ p_data->ci_load.num_attr > 0)
+ {
+ bta_gattc_rebuild_cache(p_clcb->p_srcb, p_data->ci_load.num_attr, p_data->ci_load.attr, p_clcb->p_srcb->attr_index);
+
+ if (p_data->ci_load.status == BTA_GATT_OK)
+ {
+ p_clcb->p_srcb->attr_index = 0;
+ bta_gattc_reset_discover_st(p_clcb->p_srcb);
+
+ }
+ else /* load more */
+ {
+ p_clcb->p_srcb->attr_index += p_data->ci_load.num_attr;
+
+ bta_gattc_co_cache_load(p_clcb->p_srcb->server_bda,
+ BTA_GATTC_CI_CACHE_LOAD_EVT,
+ p_clcb->p_srcb->attr_index,
+ p_clcb->bta_conn_id);
+ }
+ }
+ else
+ {
+ p_clcb->p_srcb->attr_index = 0;
+ /* cache open failure, start discovery */
+ bta_gattc_start_discover(p_clcb, NULL);
+ }
+}
+/*******************************************************************************
+**
+** Function bta_gattc_ci_load
+**
+** Description cache loading received.
+**
+** Returns None.
+**
+*******************************************************************************/
+void bta_gattc_ci_save(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
+{
+ APPL_TRACE_DEBUG1("bta_gattc_ci_save conn_id=%d " ,
+ p_clcb->bta_conn_id );
+
+ if (!bta_gattc_cache_save(p_clcb->p_srcb, p_clcb->bta_conn_id))
+ {
+ p_clcb->p_srcb->attr_index = 0;
+ bta_gattc_co_cache_close(p_clcb->p_srcb->server_bda, 0);
+ bta_gattc_reset_discover_st(p_clcb->p_srcb);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_gattc_fail
+**
+** Description report API call failure back to apps
+**
+** Returns None.
+**
+*******************************************************************************/
+void bta_gattc_fail(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
+{
+ if (p_clcb->status == BTA_GATT_OK)
+ {
+ APPL_TRACE_ERROR1("operation not supported at current state [%d]", p_clcb->state);
+ }
+}
+/*******************************************************************************
+**
+** Function bta_gattc_conn_cback
+** bta_gattc_cmpl_cback
+**
+** Description callback functions to GATT client stack.
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_gattc_conn_cback(tGATT_IF gattc_if, BD_ADDR bda, UINT16 conn_id,
+ BOOLEAN connected, tGATT_DISCONN_REASON reason)
+{
+ BT_HDR *p_buf;
+ tBTA_GATTC_CLCB *p_clcb = NULL;
+
+ APPL_TRACE_DEBUG4("bta_gattc_conn_cback: cif = %d connected = %d conn_id = %d reaosn = 0x%04x",
+ gattc_if, connected, conn_id, reason);
+
+ if (connected)
+ {
+ /* outgoing connection : locate a logic channel */
+ if ((p_clcb = bta_gattc_find_clcb_by_cif(gattc_if, bda)) == NULL)
+ {
+
+#if BLE_INCLUDED == TRUE
+ /* for a background connection */
+ if (L2CA_GetBleConnRole(bda)== HCI_ROLE_MASTER &&
+ bta_gattc_check_bg_conn(gattc_if, bda))
+ {
+ /* allocate a new channel */
+ p_clcb = bta_gattc_clcb_alloc(gattc_if, bda);
+ }
+#endif
+ }
+ if (p_clcb != NULL)
+ {
+ p_clcb->bta_conn_id = conn_id;
+
+ if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->event = BTA_GATTC_INT_CONN_EVT;
+ p_buf->layer_specific = conn_id;
+
+ bta_sys_sendmsg(p_buf);
+ }
+ }
+ }
+ else
+ {
+ /* connection attempt timeout, send connection callback event */
+ if (reason == GATT_CONN_CANCEL )
+ {
+ p_clcb = bta_gattc_clcb_alloc(gattc_if, bda);
+ p_clcb->bta_conn_id = conn_id;
+ }
+ if ((p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id)) != NULL)
+ {
+ if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->event = BTA_GATTC_INT_DISCONN_EVT;
+ p_buf->layer_specific = conn_id;
+ p_clcb->reason = reason;
+
+ bta_sys_sendmsg(p_buf);
+ }
+ }
+ else
+ {
+ APPL_TRACE_DEBUG1(" connection ID: [%d] not used by BTA", conn_id);
+ }
+ }
+}
+/*******************************************************************************
+**
+** Function bta_gattc_process_srvc_chg_ind
+**
+** Description process service change indication.
+**
+** Returns None.
+**
+*******************************************************************************/
+BOOLEAN bta_gattc_process_srvc_chg_ind(UINT16 conn_id,
+ tBTA_GATTC_RCB *p_clrcb,
+ tBTA_GATTC_SERV *p_srcb,
+ tBTA_GATTC_CLCB *p_clcb,
+ tBTA_GATTC_NOTIFY *p_notify,
+ UINT16 handle)
+{
+ tBT_UUID gattp_uuid, srvc_chg_uuid;
+ BOOLEAN processed = FALSE;
+ UINT8 i;
+
+ gattp_uuid.len = 2;
+ gattp_uuid.uu.uuid16 = UUID_SERVCLASS_GATT_SERVER;
+
+ srvc_chg_uuid.len = 2;
+ srvc_chg_uuid.uu.uuid16 = GATT_UUID_GATT_SRV_CHGD;
+
+ if (bta_gattc_uuid_compare(p_notify->char_id.srvc_id.id.uuid, gattp_uuid, TRUE) &&
+ bta_gattc_uuid_compare(p_notify->char_id.char_id.uuid, srvc_chg_uuid, TRUE))
+ {
+ processed = TRUE;
+ /* mark service handle change pending */
+ p_srcb->srvc_hdl_chg = TRUE;
+ /* clear up all notification/indication registration */
+ bta_gattc_clear_notif_registration(conn_id);
+ /* service change indication all received, do discovery update */
+ if ( ++ p_srcb->update_count == bta_gattc_num_reg_app())
+ {
+ /* not an opened connection; or connection busy */
+ /* search for first available clcb and start discovery */
+ if (p_clcb == NULL || (p_clcb && p_clcb->p_q_cmd != NULL))
+ {
+ for (i = 0 ; i < BTA_GATTC_CLCB_MAX; i ++)
+ {
+ if (bta_gattc_cb.clcb[i].in_use &&
+ bta_gattc_cb.clcb[i].p_srcb == p_srcb &&
+ bta_gattc_cb.clcb[i].p_q_cmd == NULL)
+ {
+ p_clcb = &bta_gattc_cb.clcb[i];
+ break;
+ }
+ }
+ }
+ /* send confirmation here if this is an indication, it should always be */
+ GATTC_SendHandleValueConfirm(conn_id, handle);
+
+ /* if connection available, refresh cache by doing discovery now */
+ if (p_clcb != NULL)
+ bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_DISCOVER_EVT, NULL);
+ }
+ /* notify applicationf or service change */
+ if (p_clrcb->p_cback != NULL)
+ {
+ APPL_TRACE_ERROR0("bta_gattc_process_srvc_chg_ind 2");
+ (* p_clrcb->p_cback)(BTA_GATTC_SRVC_CHG_EVT, (tBTA_GATTC *)p_srcb->server_bda);
+ }
+
+ }
+
+ return processed;
+
+}
+/*******************************************************************************
+**
+** Function bta_gattc_proc_other_indication
+**
+** Description process all non-service change indication/notification.
+**
+** Returns None.
+**
+*******************************************************************************/
+void bta_gattc_proc_other_indication(tBTA_GATTC_CLCB *p_clcb, UINT8 op,
+ tGATT_CL_COMPLETE *p_data,
+ tBTA_GATTC_NOTIFY *p_notify)
+{
+ APPL_TRACE_DEBUG2("bta_gattc_proc_other_indication check \
+ p_data->att_value.handle=%d p_data->handle=%d",
+ p_data->att_value.handle, p_data->handle);
+ APPL_TRACE_DEBUG1("is_notify", p_notify->is_notify);
+
+ p_notify->is_notify = (op == GATTC_OPTYPE_INDICATION) ? FALSE : TRUE;
+ p_notify->len = p_data->att_value.len;
+ bdcpy(p_notify->bda, p_clcb->bda);
+ memcpy(p_notify->value, p_data->att_value.value, p_data->att_value.len);
+ p_notify->conn_id = p_clcb->bta_conn_id;
+
+ if (p_clcb->p_rcb->p_cback)
+ (*p_clcb->p_rcb->p_cback)(BTA_GATTC_NOTIF_EVT, (tBTA_GATTC *)p_notify);
+
+}
+/*******************************************************************************
+**
+** Function bta_gattc_process_indicate
+**
+** Description process indication/notification.
+**
+** Returns None.
+**
+*******************************************************************************/
+void bta_gattc_process_indicate(UINT16 conn_id, tGATTC_OPTYPE op, tGATT_CL_COMPLETE *p_data)
+{
+ UINT16 handle = p_data->att_value.handle;
+ tBTA_GATTC_CLCB *p_clcb ;
+ tBTA_GATTC_RCB *p_clrcb = NULL;
+ tBTA_GATTC_SERV *p_srcb = NULL;
+ tBTA_GATTC_NOTIFY notify;
+ BD_ADDR remote_bda;
+ tBTA_GATTC_IF gatt_if;
+
+ if (!GATT_GetConnectionInfor(conn_id, &gatt_if, remote_bda))
+ {
+ APPL_TRACE_ERROR0("indication/notif for unknown app");
+ return;
+ }
+
+ if ((p_clrcb = bta_gattc_cl_get_regcb(gatt_if)) == NULL)
+ {
+ APPL_TRACE_ERROR0("indication/notif for unregistered app");
+ return;
+ }
+
+ if ((p_srcb = bta_gattc_find_srcb(remote_bda)) == NULL)
+ {
+ APPL_TRACE_ERROR0("indication/notif for unknown device, ignore");
+ return;
+ }
+
+ p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
+
+ if (bta_gattc_handle2id(p_srcb, handle,
+ &notify.char_id.srvc_id,
+ &notify.char_id.char_id,
+ &notify.descr_type))
+ {
+ /* if non-service change indication/notification, forward to application */
+ if (!bta_gattc_process_srvc_chg_ind(conn_id, p_clrcb, p_srcb, p_clcb, &notify, handle))
+ {
+ /* if app registered for the notification */
+ if (bta_gattc_check_notif_registry(p_clrcb, p_srcb, &notify))
+ {
+ /* connection not open yet */
+ if (p_clcb == NULL)
+ {
+ if ((p_clcb = bta_gattc_clcb_alloc(gatt_if, remote_bda)) != NULL)
+ {
+ p_clcb->bta_conn_id = conn_id;
+
+ /* send connection event */
+ bta_gattc_send_open_cback(p_clrcb,
+ BTA_GATT_OK,
+ remote_bda,
+ conn_id);
+ }
+ else
+ {
+ APPL_TRACE_ERROR0("No resources");
+ }
+ }
+
+ if (p_clcb != NULL)
+ bta_gattc_proc_other_indication(p_clcb, op, p_data, &notify);
+ }
+ /* no one intersted and need ack? */
+ else if (op == GATTC_OPTYPE_INDICATION)
+ {
+ APPL_TRACE_DEBUG0("no one interested, ack now");
+ GATTC_SendHandleValueConfirm(conn_id, handle);
+ }
+ }
+ }
+ else
+ {
+ APPL_TRACE_ERROR1("Indi/Notif for Unknown handle[0x%04x], can not find in local cache.", handle);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_gattc_cmpl_cback
+**
+** Description client operation complete callback register with BTE GATT.
+**
+** Returns None.
+**
+*******************************************************************************/
+static void bta_gattc_cmpl_cback(UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS status,
+ tGATT_CL_COMPLETE *p_data)
+{
+ tBTA_GATTC_CLCB *p_clcb ;
+ tBTA_GATTC_OP_CMPL *p_buf;
+ UINT16 len = sizeof(tBTA_GATTC_OP_CMPL) + sizeof(tGATT_CL_COMPLETE);
+
+ APPL_TRACE_DEBUG3("bta_gattc_cmpl_cback: conn_id = %d op = %d status = %d",
+ conn_id, op, status);
+
+ /* notification and indication processed right away */
+ if (op == GATTC_OPTYPE_NOTIFICATION || op == GATTC_OPTYPE_INDICATION)
+ {
+ bta_gattc_process_indicate(conn_id, op, p_data);
+ return;
+ }
+ /* for all other operation, not expected if w/o connection */
+ else if ((p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id)) == NULL)
+ {
+ APPL_TRACE_ERROR1("bta_gattc_cmpl_cback unknown conn_id = %d, ignore data", conn_id);
+ return;
+ }
+
+
+ if ((p_buf = (tBTA_GATTC_OP_CMPL *) GKI_getbuf(len)) != NULL)
+ {
+ memset(p_buf, 0, len);
+ p_buf->hdr.event = BTA_GATTC_OP_CMPL_EVT;
+ p_buf->hdr.layer_specific = conn_id;
+ p_buf->status = status;
+ p_buf->op_code = op;
+
+ if (p_data != NULL)
+ {
+ p_buf->p_cmpl = (tGATT_CL_COMPLETE *)(p_buf + 1);
+ memcpy(p_buf->p_cmpl, p_data, sizeof(tGATT_CL_COMPLETE));
+ }
+
+ bta_sys_sendmsg(p_buf);
+ }
+
+ return;
+}
+#endif /* BTA_GATT_INCLUDED */
diff --git a/bta/gatt/bta_gattc_api.c b/bta/gatt/bta_gattc_api.c
new file mode 100644
index 0000000..4a87ddf
--- /dev/null
+++ b/bta/gatt/bta_gattc_api.c
@@ -0,0 +1,922 @@
+/*****************************************************************************
+**
+** Name: bta_gattc_api.c
+**
+** Description: This is the implementation of the API for GATT module
+** of BTA.
+**
+** Copyright (c) 2010-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+
+#if defined(BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE)
+
+#include <string.h>
+#include "gki.h"
+#include "bta_sys.h"
+#include "bta_gatt_api.h"
+#include "bta_gattc_int.h"
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+static const tBTA_SYS_REG bta_gatt_reg =
+{
+ bta_gattc_hdl_event,
+ NULL /* need a disable functino to be called when BT is disabled */
+};
+
+/*******************************************************************************
+**
+** Function BTA_GATTC_AppRegister
+**
+** Description This function is called to register application callbacks
+** with BTA GATTC module.
+**
+** Parameters p_app_uuid - applicaiton UUID
+** p_client_cb - pointer to the application callback function.
+**
+** Returns None
+**
+*******************************************************************************/
+void BTA_GATTC_AppRegister(tBT_UUID *p_app_uuid, tBTA_GATTC_CBACK *p_client_cb)
+{
+ tBTA_GATTC_API_REG *p_buf;
+
+ /* register with BTA system manager */
+ GKI_sched_lock();
+ bta_sys_register(BTA_ID_GATTC, &bta_gatt_reg);
+ GKI_sched_unlock();
+
+ if ((p_buf = (tBTA_GATTC_API_REG *) GKI_getbuf(sizeof(tBTA_GATTC_API_REG))) != NULL)
+ {
+ p_buf->hdr.event = BTA_GATTC_API_REG_EVT;
+ if (p_app_uuid != NULL)
+ memcpy(&p_buf->app_uuid, p_app_uuid, sizeof(tBT_UUID));
+ p_buf->p_cback = p_client_cb;
+
+ bta_sys_sendmsg(p_buf);
+ }
+ return;
+}
+
+/*******************************************************************************
+**
+** Function BTA_GATTC_AppDeregister
+**
+** Description This function is called to deregister an application
+** from BTA GATTC module.
+**
+** Parameters client_if - client interface identifier.
+**
+** Returns None
+**
+*******************************************************************************/
+void BTA_GATTC_AppDeregister(tBTA_GATTC_IF client_if)
+{
+ tBTA_GATTC_API_DEREG *p_buf;
+
+ if ((p_buf = (tBTA_GATTC_API_DEREG *) GKI_getbuf(sizeof(tBTA_GATTC_API_DEREG))) != NULL)
+ {
+ p_buf->hdr.event = BTA_GATTC_API_DEREG_EVT;
+ p_buf->client_if = client_if;
+ bta_sys_sendmsg(p_buf);
+ }
+ return;
+}
+
+/*******************************************************************************
+**
+** Function BTA_GATTC_Open
+**
+** Description Open a direct connection or add a background auto connection
+** bd address
+**
+** Parameters client_if: server interface.
+** remote_bda: remote device BD address.
+** is_direct: direct connection or background auto connection
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_GATTC_Open(tBTA_GATTC_IF client_if, BD_ADDR remote_bda, BOOLEAN is_direct)
+{
+ tBTA_GATTC_API_OPEN *p_buf;
+
+ if ((p_buf = (tBTA_GATTC_API_OPEN *) GKI_getbuf(sizeof(tBTA_GATTC_API_OPEN))) != NULL)
+ {
+ p_buf->hdr.event = BTA_GATTC_API_OPEN_EVT;
+
+ p_buf->client_if = client_if;
+ p_buf->is_direct = is_direct;
+ memcpy(p_buf->remote_bda, remote_bda, BD_ADDR_LEN);
+
+
+ bta_sys_sendmsg(p_buf);
+ }
+ return;
+}
+
+/*******************************************************************************
+**
+** Function BTA_GATTC_CancelOpen
+**
+** Description Cancel a direct open connection or remove a background auto connection
+** bd address
+**
+** Parameters client_if: server interface.
+** remote_bda: remote device BD address.
+** is_direct: direct connection or background auto connection
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_GATTC_CancelOpen(tBTA_GATTC_IF client_if, BD_ADDR remote_bda, BOOLEAN is_direct)
+{
+ tBTA_GATTC_API_CANCEL_OPEN *p_buf;
+
+ if ((p_buf = (tBTA_GATTC_API_CANCEL_OPEN *) GKI_getbuf(sizeof(tBTA_GATTC_API_CANCEL_OPEN))) != NULL)
+ {
+ p_buf->hdr.event = BTA_GATTC_API_CANCEL_OPEN_EVT;
+
+ p_buf->client_if = client_if;
+ p_buf->is_direct = is_direct;
+ memcpy(p_buf->remote_bda, remote_bda, BD_ADDR_LEN);
+
+ bta_sys_sendmsg(p_buf);
+ }
+ return;
+}
+
+/*******************************************************************************
+**
+** Function BTA_GATTC_Close
+**
+** Description Close a connection to a GATT server.
+**
+** Parameters conn_id: connectino ID to be closed.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_GATTC_Close(UINT16 conn_id)
+{
+ BT_HDR *p_buf;
+
+ if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->event = BTA_GATTC_API_CLOSE_EVT;
+
+ p_buf->layer_specific = conn_id;
+
+ bta_sys_sendmsg(p_buf);
+ }
+ return;
+
+}
+/*******************************************************************************
+**
+** Function BTA_GATTC_ServiceSearchRequest
+**
+** Description This function is called to request a GATT service discovery
+** on a GATT server. This function report service search result
+** by a callback event, and followed by a service search complete
+** event.
+**
+** Parameters conn_id: connection ID.
+** p_srvc_uuid: a UUID of the service application is interested in.
+** If Null, discover for all services.
+**
+** Returns None
+**
+*******************************************************************************/
+void BTA_GATTC_ServiceSearchRequest (UINT16 conn_id, tBT_UUID *p_srvc_uuid)
+{
+ tBTA_GATTC_API_SEARCH *p_buf;
+ UINT16 len = sizeof(tBTA_GATTC_API_SEARCH) + sizeof(tBT_UUID);
+
+ if ((p_buf = (tBTA_GATTC_API_SEARCH *) GKI_getbuf(len)) != NULL)
+ {
+ memset(p_buf, 0, len);
+
+ p_buf->hdr.event = BTA_GATTC_API_SEARCH_EVT;
+ p_buf->hdr.layer_specific = conn_id;
+
+ if (p_srvc_uuid)
+ {
+ memcpy(&p_buf->srvc_uuid, p_srvc_uuid, sizeof(tBT_UUID));
+ }
+ bta_sys_sendmsg(p_buf);
+ }
+ return;
+}
+
+
+/*******************************************************************************
+**
+** Function BTA_GATTC_GetFirstChar
+**
+** Description This function is called to find the first charatceristic of the
+** service on the given server.
+**
+** Parameters conn_id: connection ID which identify the server.
+** p_srvc_id: the service ID of which the characteristic is belonged to.
+** p_char_uuid_cond: Characteristic UUID, if NULL find the first available
+** characteristic.
+** p_char_result: output parameter which will store the GATT
+** characteristic ID.
+** p_property: output parameter to carry the characteristic property.
+**
+** Returns returns status.
+**
+*******************************************************************************/
+tBTA_GATT_STATUS BTA_GATTC_GetFirstChar (UINT16 conn_id, tBTA_GATT_SRVC_ID *p_srvc_id,
+ tBT_UUID *p_char_uuid_cond,
+ tBTA_GATTC_CHAR_ID *p_char_result,
+ tBTA_GATT_CHAR_PROP *p_property)
+{
+ tBTA_GATT_STATUS status;
+
+ if (!p_srvc_id || !p_char_result)
+ return BTA_GATT_ILLEGAL_PARAMETER;
+
+ if ((status = bta_gattc_query_cache(conn_id, BTA_GATTC_ATTR_TYPE_CHAR, p_srvc_id, NULL,
+ p_char_uuid_cond, &p_char_result->char_id, p_property))
+ == BTA_GATT_OK)
+ {
+ memcpy(&p_char_result->srvc_id, p_srvc_id, sizeof(tBTA_GATT_SRVC_ID));
+ }
+
+ return status;
+
+}
+/*******************************************************************************
+**
+** Function BTA_GATTC_GetNextChar
+**
+** Description This function is called to find the next charatceristic of the
+** service on the given server.
+**
+** Parameters conn_id: connection ID which identify the server.
+** p_start_char_id: start the characteristic search from the next record
+** after the one identified by char_id.
+** p_char_uuid_cond: Characteristic UUID, if NULL find the first available
+** characteristic.
+** p_char_result: output parameter which will store the GATT
+** characteristic ID.
+** p_property: output parameter to carry the characteristic property.
+**
+** Returns returns status.
+**
+*******************************************************************************/
+tBTA_GATT_STATUS BTA_GATTC_GetNextChar (UINT16 conn_id,
+ tBTA_GATTC_CHAR_ID *p_start_char_id,
+ tBT_UUID *p_char_uuid_cond,
+ tBTA_GATTC_CHAR_ID *p_char_result,
+ tBTA_GATT_CHAR_PROP *p_property)
+{
+ tBTA_GATT_STATUS status;
+
+ if (!p_start_char_id || !p_char_result)
+ return BTA_GATT_ILLEGAL_PARAMETER;
+
+ if ((status = bta_gattc_query_cache(conn_id, BTA_GATTC_ATTR_TYPE_CHAR,
+ &p_start_char_id->srvc_id,
+ &p_start_char_id->char_id,
+ p_char_uuid_cond,
+ &p_char_result->char_id,
+ p_property))
+ == BTA_GATT_OK)
+ {
+ memcpy(&p_char_result->srvc_id, &p_start_char_id->srvc_id, sizeof(tBTA_GATT_SRVC_ID));
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function BTA_GATTC_GetFirstCharDescr
+**
+** Description This function is called to find the first charatceristic descriptor of the
+** charatceristic on the given server.
+**
+** Parameters conn_id: connection ID which identify the server.
+** p_char_id: the characteristic ID of which the descriptor is belonged to.
+** p_descr_uuid_cond: Characteristic Descr UUID, if NULL find the first available
+** characteristic.
+** p_descr_result: output parameter which will store the GATT
+** characteristic descriptor ID.
+**
+** Returns returns status.
+**
+*******************************************************************************/
+tBTA_GATT_STATUS BTA_GATTC_GetFirstCharDescr (UINT16 conn_id, tBTA_GATTC_CHAR_ID *p_char_id,
+ tBT_UUID *p_descr_uuid_cond,
+ tBTA_GATTC_CHAR_DESCR_ID *p_descr_result)
+{
+ tBTA_GATT_STATUS status;
+
+ if (!p_char_id || !p_descr_result)
+ return BTA_GATT_ILLEGAL_PARAMETER;
+
+ memset(p_descr_result, 0, sizeof(tBTA_GATTC_CHAR_DESCR_ID));
+
+ if ((status = bta_gattc_query_cache(conn_id,
+ BTA_GATTC_ATTR_TYPE_CHAR_DESCR,
+ &p_char_id->srvc_id,
+ &p_char_id->char_id,
+ p_descr_uuid_cond,
+ &p_descr_result->char_id.char_id,
+ NULL))
+ == BTA_GATT_OK)
+ {
+ memcpy(&p_descr_result->descr_type, &p_descr_result->char_id.char_id.uuid, sizeof(tBT_UUID));
+ memcpy(&p_descr_result->char_id, p_char_id, sizeof(tBTA_GATTC_CHAR_ID));
+ }
+
+ return status;
+
+}
+/*******************************************************************************
+**
+** Function BTA_GATTC_GetNextCharDescr
+**
+** Description This function is called to find the next charatceristic of the
+** service on the given server.
+**
+** Parameters conn_id: connection ID which identify the server.
+** p_start_descr_id: start the characteristic search from the next record
+** after the one identified by p_start_descr_id.
+** p_descr_uuid_cond: Characteristic descriptor UUID, if NULL find
+** the first available characteristic descriptor.
+** p_descr_result: output parameter which will store the GATT
+** characteristic descriptor ID.
+**
+** Returns returns status.
+**
+*******************************************************************************/
+tBTA_GATT_STATUS BTA_GATTC_GetNextCharDescr (UINT16 conn_id,
+ tBTA_GATTC_CHAR_DESCR_ID *p_start_descr_id,
+ tBT_UUID *p_descr_uuid_cond,
+ tBTA_GATTC_CHAR_DESCR_ID *p_descr_result)
+{
+ tBTA_GATT_STATUS status;
+
+ if (!p_start_descr_id || !p_descr_result)
+ return BTA_GATT_ILLEGAL_PARAMETER;
+
+ memset(p_descr_result, 0, sizeof(tBTA_GATTC_CHAR_DESCR_ID));
+
+ if ((status = bta_gattc_query_cache(conn_id, BTA_GATTC_ATTR_TYPE_CHAR_DESCR,
+ &p_start_descr_id->char_id.srvc_id,
+ &p_start_descr_id->char_id.char_id,
+ p_descr_uuid_cond,
+ &p_descr_result->char_id.char_id,
+ (void *)&p_start_descr_id->descr_type))
+ == BTA_GATT_OK)
+ {
+ memcpy(&p_descr_result->descr_type, &p_descr_result->char_id.char_id.uuid, sizeof(tBT_UUID));
+ memcpy(&p_descr_result->char_id, p_start_descr_id, sizeof(tBTA_GATTC_CHAR_ID));
+ }
+
+ return status;
+}
+
+
+/*******************************************************************************
+**
+** Function BTA_GATTC_GetFirstIncludedService
+**
+** Description This function is called to find the first included service of the
+** service on the given server.
+**
+** Parameters conn_id: connection ID which identify the server.
+** p_srvc_id: the service ID of which the characteristic is belonged to.
+** p_uuid_cond: Characteristic UUID, if NULL find the first available
+** characteristic.
+** p_result: output parameter which will store the GATT ID
+** of the included service found.
+**
+** Returns returns status.
+**
+*******************************************************************************/
+tBTA_GATT_STATUS BTA_GATTC_GetFirstIncludedService(UINT16 conn_id, tBTA_GATT_SRVC_ID *p_srvc_id,
+ tBT_UUID *p_uuid_cond, tBTA_GATTC_INCL_SVC_ID *p_result)
+{
+ tBTA_GATT_STATUS status;
+
+ if (!p_srvc_id || !p_result)
+ return BTA_GATT_ILLEGAL_PARAMETER;
+
+ if ((status = bta_gattc_query_cache(conn_id,
+ BTA_GATTC_ATTR_TYPE_INCL_SRVC,
+ p_srvc_id,
+ NULL,
+ p_uuid_cond,
+ &p_result->incl_svc_id.id,
+ (tBTA_GATT_CHAR_PROP *)&p_result->incl_svc_id.is_primary))
+ == BTA_GATT_OK)
+ {
+ memcpy(&p_result->srvc_id, p_srvc_id, sizeof(tBTA_GATT_SRVC_ID));
+ }
+
+ return status;
+}
+/*******************************************************************************
+**
+** Function BTA_GATTC_GetNextIncludedService
+**
+** Description This function is called to find the next included service of the
+** service on the given server.
+**
+** Parameters conn_id: connection ID which identify the server.
+** p_start_id: start the search from the next record
+** after the one identified by p_start_id.
+** p_uuid_cond: Included service UUID, if NULL find the first available
+** included service.
+** p_result: output parameter which will store the GATT ID
+** of the included service found.
+**
+** Returns returns status.
+**
+*******************************************************************************/
+tBTA_GATT_STATUS BTA_GATTC_GetNextIncludedService(UINT16 conn_id,
+ tBTA_GATTC_INCL_SVC_ID *p_start_id,
+ tBT_UUID *p_uuid_cond,
+ tBTA_GATTC_INCL_SVC_ID *p_result)
+{
+ tBTA_GATT_STATUS status;
+
+ if (!p_start_id || !p_result)
+ return BTA_GATT_ILLEGAL_PARAMETER;
+
+ if ((status = bta_gattc_query_cache(conn_id,
+ BTA_GATTC_ATTR_TYPE_INCL_SRVC,
+ &p_start_id->srvc_id,
+ &p_start_id->incl_svc_id.id,
+ p_uuid_cond,
+ &p_result->incl_svc_id.id,
+ (tBTA_GATT_CHAR_PROP *)&p_result->incl_svc_id.is_primary))
+ == BTA_GATT_OK)
+ {
+ memcpy(&p_result->srvc_id, &p_start_id->srvc_id, sizeof(tBTA_GATT_SRVC_ID));
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function BTA_GATTC_ReadCharacteristic
+**
+** Description This function is called to read a service's characteristics of
+** the given characteritisc ID.
+**
+** Parameters conn_id - connectino ID.
+** p_char_id - characteritic ID to read.
+**
+** Returns None
+**
+*******************************************************************************/
+void BTA_GATTC_ReadCharacteristic(UINT16 conn_id, tBTA_GATTC_CHAR_ID *p_char_id,
+ tBTA_GATT_AUTH_REQ auth_req)
+{
+ tBTA_GATTC_API_READ *p_buf;
+
+ if ((p_buf = (tBTA_GATTC_API_READ *) GKI_getbuf(sizeof(tBTA_GATTC_API_READ))) != NULL)
+ {
+ memset(p_buf, 0, sizeof(tBTA_GATTC_API_READ));
+
+ p_buf->hdr.event = BTA_GATTC_API_READ_EVT;
+ p_buf->hdr.layer_specific = conn_id;
+ p_buf->auth_req = auth_req;
+
+ memcpy(&p_buf->srvc_id, &p_char_id->srvc_id, sizeof(tBTA_GATT_SRVC_ID));
+ memcpy(&p_buf->char_id, &p_char_id->char_id, sizeof(tBTA_GATT_ID));
+
+ bta_sys_sendmsg(p_buf);
+ }
+ return;
+}
+
+/*******************************************************************************
+**
+** Function BTA_GATTC_ReadCharDescr
+**
+** Description This function is called to read a characteristics descriptor.
+**
+** Parameters conn_id - connection ID.
+** p_char_descr_id - characteritic descriptor ID to read.
+**
+** Returns None
+**
+*******************************************************************************/
+void BTA_GATTC_ReadCharDescr (UINT16 conn_id,
+ tBTA_GATTC_CHAR_DESCR_ID *p_descr_id,
+ tBTA_GATT_AUTH_REQ auth_req)
+{
+ tBTA_GATTC_API_READ *p_buf;
+
+ if ((p_buf = (tBTA_GATTC_API_READ *) GKI_getbuf(sizeof(tBTA_GATTC_API_READ))) != NULL)
+ {
+ memset(p_buf, 0, sizeof(tBTA_GATTC_API_READ));
+
+ p_buf->hdr.event = BTA_GATTC_API_READ_EVT;
+ p_buf->hdr.layer_specific = conn_id;
+ p_buf->auth_req = auth_req;
+
+ memcpy(&p_buf->srvc_id, &p_descr_id->char_id.srvc_id, sizeof(tBTA_GATT_SRVC_ID));
+ memcpy(&p_buf->char_id, &p_descr_id->char_id.char_id, sizeof(tBTA_GATT_ID));
+ memcpy(&p_buf->descr_type, &p_descr_id->descr_type, sizeof(tBT_UUID));
+
+ bta_sys_sendmsg(p_buf);
+ }
+ return;
+
+}
+/*******************************************************************************
+**
+** Function BTA_GATTC_ReadMultiple
+**
+** Description This function is called to read multiple characteristic or
+** characteristic descriptors.
+**
+** Parameters conn_id - connectino ID.
+** p_read_multi - pointer to the read multiple parameter.
+**
+** Returns None
+**
+*******************************************************************************/
+void BTA_GATTC_ReadMultiple(UINT16 conn_id, tBTA_GATTC_MULTI *p_read_multi,
+ tBTA_GATT_AUTH_REQ auth_req)
+{
+ tBTA_GATTC_API_READ_MULTI *p_buf;
+ tBTA_GATTC_ATTR_ID *p_value;
+ UINT16 len = (UINT16)(sizeof(tBTA_GATTC_API_READ_MULTI) +
+ p_read_multi->num_attr * sizeof(tBTA_GATTC_ATTR_ID));
+ UINT8 i;
+
+ if ((p_buf = (tBTA_GATTC_API_READ_MULTI *) GKI_getbuf(len)) != NULL)
+ {
+ memset(p_buf, 0, len);
+
+ p_buf->hdr.event = BTA_GATTC_API_READ_MULTI_EVT;
+ p_buf->hdr.layer_specific = conn_id;
+ p_buf->auth_req = auth_req;
+
+ p_buf->num_attr = p_read_multi->num_attr;
+
+ if (p_buf->num_attr > 0)
+ {
+ p_buf->p_id_list = p_value = (tBTA_GATTC_ATTR_ID *)(p_buf + 1);
+
+ for (i = 0; i < p_buf->num_attr; i ++, p_value ++)
+ {
+ memcpy(p_value, &p_read_multi->id_list[i], sizeof(tBTA_GATTC_ATTR_ID));
+ }
+ }
+ bta_sys_sendmsg(p_buf);
+ }
+ return;
+}
+
+
+/*******************************************************************************
+**
+** Function BTA_GATTC_WriteCharValue
+**
+** Description This function is called to write characteristic value.
+**
+** Parameters conn_id - connection ID.
+** p_char_id - characteristic ID to write.
+** write_type - type of write.
+** len: length of the data to be written.
+** p_value - the value to be written.
+**
+** Returns None
+**
+*******************************************************************************/
+void BTA_GATTC_WriteCharValue ( UINT16 conn_id,
+ tBTA_GATTC_CHAR_ID *p_char_id,
+ tBTA_GATTC_WRITE_TYPE write_type,
+ UINT16 len,
+ UINT8 *p_value,
+ tBTA_GATT_AUTH_REQ auth_req)
+{
+ tBTA_GATTC_API_WRITE *p_buf;
+
+ if ((p_buf = (tBTA_GATTC_API_WRITE *) GKI_getbuf((UINT16)(sizeof(tBTA_GATTC_API_WRITE) + len))) != NULL)
+ {
+ memset(p_buf, 0, sizeof(tBTA_GATTC_API_WRITE) + len);
+
+ p_buf->hdr.event = BTA_GATTC_API_WRITE_EVT;
+ p_buf->hdr.layer_specific = conn_id;
+ p_buf->auth_req = auth_req;
+
+ memcpy(&p_buf->srvc_id, &p_char_id->srvc_id, sizeof(tBTA_GATT_SRVC_ID));
+ memcpy(&p_buf->char_id, &p_char_id->char_id, sizeof(tBTA_GATT_ID));
+
+ p_buf->write_type = write_type;
+ p_buf->len = len;
+
+ if (p_value && len > 0)
+ {
+ p_buf->p_value = (UINT8 *)(p_buf + 1);
+ memcpy(p_buf->p_value, p_value, len);
+ }
+
+ bta_sys_sendmsg(p_buf);
+ }
+ return;
+}
+/*******************************************************************************
+**
+** Function BTA_GATTC_WriteCharDescr
+**
+** Description This function is called to write characteristic descriptor value.
+**
+** Parameters conn_id - connection ID
+** p_char_descr_id - characteristic descriptor ID to write.
+** write_type - write type.
+** p_value - the value to be written.
+**
+** Returns None
+**
+*******************************************************************************/
+void BTA_GATTC_WriteCharDescr (UINT16 conn_id,
+ tBTA_GATTC_CHAR_DESCR_ID *p_char_descr_id,
+ tBTA_GATTC_WRITE_TYPE write_type,
+ tBTA_GATT_UNFMT *p_data,
+ tBTA_GATT_AUTH_REQ auth_req)
+{
+ tBTA_GATTC_API_WRITE *p_buf;
+ UINT16 len = sizeof(tBTA_GATTC_API_WRITE) + p_data->len;
+
+ if ((p_buf = (tBTA_GATTC_API_WRITE *) GKI_getbuf(len)) != NULL)
+ {
+ memset(p_buf, 0, len);
+
+ p_buf->hdr.event = BTA_GATTC_API_WRITE_EVT;
+ p_buf->hdr.layer_specific = conn_id;
+ p_buf->auth_req = auth_req;
+
+ memcpy(&p_buf->srvc_id, &p_char_descr_id->char_id.srvc_id, sizeof(tBTA_GATT_SRVC_ID));
+ memcpy(&p_buf->char_id, &p_char_descr_id->char_id.char_id, sizeof(tBTA_GATT_ID));
+ memcpy(&p_buf->descr_type, &p_char_descr_id->descr_type, sizeof(tBT_UUID));
+ p_buf->write_type = write_type;
+
+ if (p_data && p_data->len != 0)
+ {
+ p_buf->p_value = (UINT8 *)(p_buf + 1);
+ p_buf->len = p_data->len;
+ /* pack the descr data */
+ memcpy(p_buf->p_value, p_data->p_value, p_data->len);
+ }
+
+ bta_sys_sendmsg(p_buf);
+ }
+ return;
+
+}
+/*******************************************************************************
+**
+** Function BTA_GATTC_PrepareWrite
+**
+** Description This function is called to prepare write a characteristic value.
+**
+** Parameters conn_id - connection ID.
+** p_char_id - GATT characteritic ID of the service.
+** offset - offset of the write value.
+** len: length of the data to be written.
+** p_value - the value to be written.
+**
+** Returns None
+**
+*******************************************************************************/
+void BTA_GATTC_PrepareWrite (UINT16 conn_id, tBTA_GATTC_CHAR_ID *p_char_id,
+ UINT16 offset, UINT16 len, UINT8 *p_value,
+ tBTA_GATT_AUTH_REQ auth_req)
+{
+ tBTA_GATTC_API_WRITE *p_buf;
+
+ if ((p_buf = (tBTA_GATTC_API_WRITE *) GKI_getbuf((UINT16)(sizeof(tBTA_GATTC_API_WRITE) + len))) != NULL)
+ {
+ memset(p_buf, 0, sizeof(tBTA_GATTC_API_WRITE) + len);
+
+ p_buf->hdr.event = BTA_GATTC_API_WRITE_EVT;
+ p_buf->hdr.layer_specific = conn_id;
+ p_buf->auth_req = auth_req;
+
+ memcpy(&p_buf->srvc_id, &p_char_id->srvc_id, sizeof(tBTA_GATT_SRVC_ID));
+ memcpy(&p_buf->char_id, &p_char_id->char_id, sizeof(tBTA_GATT_ID));
+
+ p_buf->write_type = BTA_GATTC_WRITE_PREPARE;
+ p_buf->offset = offset;
+ p_buf->len = len;
+
+ if (p_value && len > 0)
+ {
+ p_buf->p_value = (UINT8 *)(p_buf + 1);
+ memcpy(p_buf->p_value, p_value, len);
+ }
+
+ bta_sys_sendmsg(p_buf);
+ }
+ return;
+
+}
+/*******************************************************************************
+**
+** Function BTA_GATTC_ExecuteWrite
+**
+** Description This function is called to execute write a prepare write sequence.
+**
+** Parameters conn_id - connection ID.
+** is_execute - execute or cancel.
+**
+** Returns None
+**
+*******************************************************************************/
+void BTA_GATTC_ExecuteWrite (UINT16 conn_id, BOOLEAN is_execute)
+{
+ tBTA_GATTC_API_EXEC *p_buf;
+
+ if ((p_buf = (tBTA_GATTC_API_EXEC *) GKI_getbuf((UINT16)sizeof(tBTA_GATTC_API_EXEC))) != NULL)
+ {
+ memset(p_buf, 0, sizeof(tBTA_GATTC_API_EXEC));
+
+ p_buf->hdr.event = BTA_GATTC_API_EXEC_EVT;
+ p_buf->hdr.layer_specific = conn_id;
+
+ p_buf->is_execute = is_execute;
+
+ bta_sys_sendmsg(p_buf);
+ }
+ return;
+
+}
+/*******************************************************************************
+**
+** Function BTA_GATTC_SendIndConfirm
+**
+** Description This function is called to send handle value confirmation.
+**
+** Parameters conn_id - connection ID.
+** p_char_id - characteristic ID to confirm.
+**
+** Returns None
+**
+*******************************************************************************/
+void BTA_GATTC_SendIndConfirm (UINT16 conn_id, tBTA_GATTC_CHAR_ID *p_char_id)
+{
+ tBTA_GATTC_API_CONFIRM *p_buf;
+
+ APPL_TRACE_API3("BTA_GATTC_SendIndConfirm conn_id=%d service uuid1=0x%x char uuid=0x%x",
+ conn_id, p_char_id->srvc_id.id.uuid.uu.uuid16, p_char_id->char_id.uuid.uu.uuid16); //toto
+
+ if ((p_buf = (tBTA_GATTC_API_CONFIRM *) GKI_getbuf(sizeof(tBTA_GATTC_API_CONFIRM))) != NULL)
+ {
+ memset(p_buf, 0, sizeof(tBTA_GATTC_API_CONFIRM));
+
+ p_buf->hdr.event = BTA_GATTC_API_CONFIRM_EVT;
+ p_buf->hdr.layer_specific = conn_id;
+
+ memcpy(&p_buf->srvc_id, &p_char_id->srvc_id, sizeof(tBTA_GATT_SRVC_ID));
+ memcpy(&p_buf->char_id, &p_char_id->char_id, sizeof(tBTA_GATT_ID));
+
+ bta_sys_sendmsg(p_buf);
+ }
+ return;
+
+}
+
+/*******************************************************************************
+**
+** Function BTA_GATTC_RegisterForNotifications
+**
+** Description This function is called to register for notification of a service.
+**
+** Parameters client_if - client interface.
+** bda - target GATT server.
+** p_char_id - pointer to GATT characteristic ID.
+**
+** Returns OK if registration succeed, otherwise failed.
+**
+*******************************************************************************/
+tBTA_GATT_STATUS BTA_GATTC_RegisterForNotifications (tBTA_GATTC_IF client_if,
+ BD_ADDR bda,
+ tBTA_GATTC_CHAR_ID *p_char_id)
+{
+ tBTA_GATTC_RCB *p_clreg;
+ tBTA_GATT_STATUS status = BTA_GATT_ILLEGAL_PARAMETER;
+ UINT8 i;
+
+ if (!p_char_id)
+ {
+ APPL_TRACE_ERROR0("deregistration failed, unknow char id");
+ return status;
+ }
+
+ /* lock other GKI task */
+ GKI_sched_lock();
+
+ if ((p_clreg = bta_gattc_cl_get_regcb(client_if)) != NULL)
+ {
+ for (i = 0; i < BTA_GATTC_NOTIF_REG_MAX; i ++)
+ {
+ if (!p_clreg->notif_reg[i].in_use)
+ {
+ memset(&p_clreg->notif_reg, 0, sizeof(tBTA_GATTC_NOTIF_REG));
+
+ p_clreg->notif_reg[i].in_use = TRUE;
+ memcpy(p_clreg->notif_reg[i].remote_bda, bda, BD_ADDR_LEN);
+ memcpy(&p_clreg->notif_reg[i].char_id, p_char_id, sizeof(tBTA_GATTC_CHAR_ID));
+
+ status = BTA_GATT_OK;
+ break;
+ }
+ }
+ if (i == BTA_GATTC_NOTIF_REG_MAX)
+ {
+ status = BTA_GATT_NO_RESOURCES;
+ APPL_TRACE_ERROR0("Max Notification Reached, registration failed.");
+ }
+ }
+ else
+ {
+ APPL_TRACE_ERROR1("Client_if: %d Not Registered", client_if);
+ }
+
+ GKI_sched_unlock();
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function BTA_GATTC_DeregisterForNotifications
+**
+** Description This function is called to de-register for notification of a service.
+**
+** Parameters client_if - client interface.
+** bda - target GATT server.
+** p_char_id - pointer to GATT characteristic ID.
+**
+** Returns OK if deregistration succeed, otherwise failed.
+**
+*******************************************************************************/
+tBTA_GATT_STATUS BTA_GATTC_DeregisterForNotifications (tBTA_GATTC_IF client_if,
+ BD_ADDR bda,
+ tBTA_GATTC_CHAR_ID *p_char_id)
+{
+ tBTA_GATTC_RCB *p_clreg;
+ tBTA_GATT_STATUS status = BTA_GATT_ILLEGAL_PARAMETER;
+ UINT8 i;
+
+ if (!p_char_id)
+ {
+ APPL_TRACE_ERROR0("deregistration failed, unknow char id");
+ return status;
+ }
+
+ /* lock other GKI task */
+ GKI_sched_lock();
+
+ if ((p_clreg = bta_gattc_cl_get_regcb(client_if)) != NULL)
+ {
+ for (i = 0; i < BTA_GATTC_NOTIF_REG_MAX; i ++)
+ {
+ if (p_clreg->notif_reg[i].in_use &&
+ !memcmp(p_clreg->notif_reg[i].remote_bda, bda, BD_ADDR_LEN) &&
+ !memcmp(&p_clreg->notif_reg[i].char_id, p_char_id, sizeof(tBTA_GATTC_CHAR_ID)))
+ {
+ APPL_TRACE_DEBUG0("Deregistered.");
+
+ memset(&p_clreg->notif_reg[i], 0, sizeof(tBTA_GATTC_NOTIF_REG));
+ status = BTA_GATT_OK;
+ break;
+ }
+ }
+ if (i == BTA_GATTC_NOTIF_REG_MAX)
+ {
+ status = BTA_GATT_ERROR;
+
+ APPL_TRACE_ERROR0("registration not found");
+ }
+ }
+ else
+ {
+ APPL_TRACE_ERROR1("Client_if: %d Not Registered", client_if);
+ }
+
+ GKI_sched_unlock();
+
+ return status;
+}
+
+#endif /* BTA_GATT_INCLUDED */
diff --git a/bta/gatt/bta_gattc_cache.c b/bta/gatt/bta_gattc_cache.c
new file mode 100644
index 0000000..7234598
--- /dev/null
+++ b/bta/gatt/bta_gattc_cache.c
@@ -0,0 +1,1584 @@
+/*****************************************************************************
+**
+** Name: bta_gattc_cache.c
+**
+** Description: This file contains the GATT client discovery
+** procedures and cache related functions.
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+
+#if defined(BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE)
+
+#include <string.h>
+#include "utl.h"
+#include "gki.h"
+#include "bta_sys.h"
+#include "sdp_api.h"
+#include "sdpdefs.h"
+#include "bta_gattc_int.h"
+#include "btm_api.h"
+
+static void bta_gattc_char_dscpt_disc_cmpl(UINT16 conn_id, tBTA_GATTC_SERV *p_srvc_cb);
+static tBTA_GATT_STATUS bta_gattc_sdp_service_disc(UINT16 conn_id, tBTA_GATTC_SERV *p_server_cb);
+
+#define BTA_GATT_SDP_DB_SIZE 750
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE)
+static char *bta_gattc_attr_type[] =
+{
+ "I", /* Included Service */
+ "C", /* Characteristic */
+ "D" /* Characteristic Descriptor */
+};
+/* utility functions */
+
+/*******************************************************************************
+**
+** Function bta_gattc_display_cache_server
+**
+** Description debug function to display the server cache.
+**
+** Returns none.
+**
+*******************************************************************************/
+static void bta_gattc_display_cache_server(tBTA_GATTC_CACHE *p_cache)
+{
+ UINT8 i = 0, j;
+ tBTA_GATTC_CACHE *p_cur_srvc = p_cache;
+ tBTA_GATTC_CACHE_ATTR *p_attr;
+
+ APPL_TRACE_ERROR0("<================Start Server Cache =============>");
+
+ while (p_cur_srvc)
+ {
+ APPL_TRACE_ERROR6("Service[%d]: handle[%d ~ %d] %s[0x%04x] inst[%d]",
+ i, p_cur_srvc->s_handle, p_cur_srvc->e_handle,
+ ((p_cur_srvc->service_uuid.id.uuid.len == 2) ? "uuid16" : "uuid128"),
+ p_cur_srvc->service_uuid.id.uuid.uu.uuid16,
+ p_cur_srvc->service_uuid.id.inst_id);
+ i ++;
+
+ p_attr = p_cur_srvc->p_attr;
+
+ for (j = 0; p_attr; j ++ )
+ {
+ APPL_TRACE_ERROR6("\t Attr[0x%04x] handle[%d] uuid[0x%04x] inst[%d] type[%s] prop[0x%1x]",
+ j + 1, p_attr->attr_handle, p_attr->p_uuid->uuid16, p_attr->inst_id,
+ bta_gattc_attr_type[p_attr->attr_type], p_attr->property);
+
+ p_attr = p_attr->p_next;
+ }
+ p_cur_srvc = p_cur_srvc->p_next;
+ }
+
+ APPL_TRACE_ERROR0("<================End Server Cache =============>");
+ APPL_TRACE_ERROR0(" ");
+}
+
+/*******************************************************************************
+**
+** Function bta_gattc_display_explore_record
+**
+** Description debug function to display the exploration list
+**
+** Returns none.
+**
+*******************************************************************************/
+static void bta_gattc_display_explore_record(tBTA_GATTC_ATTR_REC *p_rec, UINT8 num_rec)
+{
+ UINT8 i;
+ tBTA_GATTC_ATTR_REC *pp = p_rec;
+
+ APPL_TRACE_ERROR0("<================Start Explore Queue =============>");
+ for (i = 0; i < num_rec; i ++, pp ++)
+ {
+ APPL_TRACE_ERROR5("\t rec[%d] uuid[0x%04x] s_handle[%d] e_handle[%d] is_primary[%d]",
+ i + 1, pp->uuid.uu.uuid16, pp->s_handle, pp->e_handle, pp->is_primary);
+ }
+ APPL_TRACE_ERROR0("<================ End Explore Queue =============>");
+ APPL_TRACE_ERROR0(" ");
+
+}
+#endif /* BTA_GATT_DEBUG == TRUE */
+
+
+/*******************************************************************************
+**
+** Function bta_gattc_alloc_cache_buf
+**
+** Description Allocate a GKI buffer for database cache.
+**
+** Returns status
+**
+*******************************************************************************/
+BT_HDR *bta_gattc_alloc_cache_buf(tBTA_GATTC_SERV *p_srvc_cb)
+{
+ BT_HDR *p_buf;
+
+ if ((p_buf = (BT_HDR *)GKI_getpoolbuf(GATT_DB_POOL_ID)) == NULL)
+ {
+ APPL_TRACE_DEBUG0("No resources: GKI buffer allocation failed.");
+ utl_freebuf((void **)&p_srvc_cb->p_srvc_list);
+ p_srvc_cb->free_byte = 0;
+ }
+ else
+ {
+ memset(p_buf, 0, GKI_get_buf_size(p_buf));
+ p_srvc_cb->p_free = (UINT8 *) p_buf;
+ p_srvc_cb->free_byte = GKI_get_buf_size(p_buf);
+
+ /* link into buffer queue */
+ GKI_enqueue(&p_srvc_cb->cache_buffer, p_buf);
+ }
+#if BTA_GATT_DEBUG== TRUE
+ APPL_TRACE_DEBUG1("allocating new buffer: free byte = %d", p_srvc_cb->free_byte);
+#endif
+ return p_buf;
+}
+/*******************************************************************************
+**
+** Function bta_gattc_init_cache
+**
+** Description Initialize the database cache and discovery related resources.
+**
+** Returns status
+**
+*******************************************************************************/
+tBTA_GATT_STATUS bta_gattc_init_cache(tBTA_GATTC_SERV *p_srvc_cb)
+{
+ tBTA_GATT_STATUS status = BTA_GATT_OK;
+
+ while (p_srvc_cb->cache_buffer.p_first)
+ GKI_freebuf (GKI_dequeue (&p_srvc_cb->cache_buffer));
+
+ utl_freebuf((void **)&p_srvc_cb->p_srvc_list);
+
+ if ((p_srvc_cb->p_srvc_list = (tBTA_GATTC_ATTR_REC*)GKI_getbuf(BTA_GATTC_ATTR_LIST_SIZE)) == NULL)
+ {
+ APPL_TRACE_DEBUG0("No resources: GKI buffer allocation failed.");
+ status = GATT_NO_RESOURCES;
+ }
+ else
+ {
+ p_srvc_cb->total_srvc = 0;
+ p_srvc_cb->cur_srvc_idx =
+ p_srvc_cb->cur_char_idx =
+ p_srvc_cb->next_avail_idx = 0;
+
+ if (bta_gattc_alloc_cache_buf(p_srvc_cb) == NULL)
+ {
+ status = GATT_NO_RESOURCES;
+ }
+ else
+ {
+ p_srvc_cb->p_cur_srvc = p_srvc_cb->p_srvc_cache = NULL;
+ }
+ }
+
+ return status;
+}
+/*******************************************************************************
+**
+** Function bta_gattc_get_srvc_inst_id
+**
+** Description get service instance number
+**
+** Returns instance ID of the service.
+**
+*******************************************************************************/
+static UINT8 bta_gattc_get_srvc_inst_id(tBTA_GATTC_SERV *p_srvc_cb, tBT_UUID uuid)
+{
+ UINT8 i = 0, inst = 0;
+ tBTA_GATTC_ATTR_REC *p_srvc_rec;
+
+ for (i = 0; i < p_srvc_cb->total_srvc; i ++)
+ /*
+ for (; i < p_srvc_cb->cur_srvc_idx; i ++)*/
+ {
+ p_srvc_rec = p_srvc_cb->p_srvc_list + i;
+
+ if (bta_gattc_uuid_compare(p_srvc_rec->uuid, uuid, TRUE))
+ inst ++;
+ }
+ return inst ;
+}
+/*******************************************************************************
+**
+** Function bta_gattc_get_char_inst_id
+**
+** Description get characteristic instance number
+**
+** Returns characteristic instance ID.
+**
+*******************************************************************************/
+static UINT8 bta_gattc_get_char_inst_id(tBTA_GATTC_CACHE *p_service_cache, tBT_UUID uuid)
+{
+ UINT8 inst = 0;
+ tBTA_GATTC_CACHE_ATTR *p_attr;
+ tBT_UUID attr_uuid;
+
+ p_attr = p_service_cache->p_attr;
+
+ while (p_attr)
+ {
+ bta_gattc_pack_attr_uuid(p_attr, &attr_uuid);
+
+ if (bta_gattc_uuid_compare(attr_uuid, uuid, TRUE))
+ inst ++;
+
+ p_attr = p_attr->p_next;
+ }
+ return inst ;
+}
+
+/*******************************************************************************
+**
+** Function bta_gattc_add_srvc_to_cache
+**
+** Description Add a service into database cache.
+**
+** Returns status
+**
+*******************************************************************************/
+static tBTA_GATT_STATUS bta_gattc_add_srvc_to_cache(tBTA_GATTC_SERV *p_srvc_cb,
+ UINT16 s_handle, UINT16 e_handle,
+ tBT_UUID *p_uuid,
+ BOOLEAN is_primary, UINT8 srvc_inst)
+{
+ tBTA_GATTC_CACHE *p_new_srvc = NULL;
+ tBTA_GATT_STATUS status = BTA_GATT_OK;
+
+#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE)
+ APPL_TRACE_DEBUG0("Add a service into Service");
+ APPL_TRACE_DEBUG2("free byte = %d, req %d bytes.", p_srvc_cb->free_byte, sizeof(tBTA_GATTC_CACHE))
+#endif
+
+ if (p_srvc_cb->free_byte < sizeof(tBTA_GATTC_CACHE))
+ {
+ if (bta_gattc_alloc_cache_buf(p_srvc_cb) == NULL)
+ return GATT_NO_RESOURCES;
+ }
+
+ p_new_srvc = (tBTA_GATTC_CACHE *)p_srvc_cb->p_free;
+ /* update service information */
+ p_new_srvc->s_handle = s_handle;
+ p_new_srvc->e_handle = e_handle;
+ p_new_srvc->service_uuid.is_primary = is_primary;
+ memcpy(&p_new_srvc->service_uuid.id.uuid, p_uuid, sizeof(tBT_UUID));
+ p_new_srvc->service_uuid.id.inst_id = srvc_inst;
+ p_new_srvc->p_next = NULL;
+
+ if (p_srvc_cb->p_cur_srvc != NULL)
+ p_srvc_cb->p_cur_srvc->p_next = p_new_srvc;
+ p_srvc_cb->p_cur_srvc = p_new_srvc;
+
+ /* first service */
+ if (p_srvc_cb->p_srvc_cache == NULL)
+ p_srvc_cb->p_srvc_cache = p_new_srvc;
+
+ /* update buffer managament info */
+ p_srvc_cb->p_free += sizeof(tBTA_GATTC_CACHE);
+ p_srvc_cb->free_byte -= sizeof(tBTA_GATTC_CACHE);
+
+
+#if 0
+//#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE)
+ bta_gattc_display_cache_server(p_srvc_cb->p_srvc_cache);
+#endif
+ return status;
+}
+/*******************************************************************************
+**
+** Function bta_gattc_add_attr_to_cache
+**
+** Description Add an attribute into database cache buffer.
+**
+** Returns status
+**
+*******************************************************************************/
+static tBTA_GATT_STATUS bta_gattc_add_attr_to_cache(tBTA_GATTC_SERV *p_srvc_cb,
+ UINT16 handle,
+ tBT_UUID *p_uuid,
+ UINT8 property,
+ tBTA_GATTC_ATTR_TYPE type)
+{
+ tBTA_GATTC_CACHE_ATTR *p_attr;
+ tBTA_GATT_STATUS status = BTA_GATT_OK;
+ UINT16 len = sizeof(tBTA_GATTC_CACHE_ATTR) + p_uuid->len;
+ UINT8 *pp;
+
+#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE)
+ APPL_TRACE_DEBUG1("bta_gattc_add_attr_to_cache: Add a [%s] into Service", bta_gattc_attr_type[type]);
+ APPL_TRACE_DEBUG4("handle=%d uuid16=0x%x property=0x%x type=%d", handle, p_uuid->uu.uuid16, property, type);
+ APPL_TRACE_DEBUG2("free byte = %d, req %d bytes.", p_srvc_cb->free_byte, len);
+#endif
+
+ if (p_srvc_cb->free_byte < len)
+ {
+ if (bta_gattc_alloc_cache_buf(p_srvc_cb) == NULL)
+ return GATT_NO_RESOURCES;
+ }
+
+ p_attr = (tBTA_GATTC_CACHE_ATTR *)p_srvc_cb->p_free;
+
+ p_attr->attr_handle = handle;
+ p_attr->attr_type = type;
+ p_attr->property = property;
+ p_attr->uuid_len = p_uuid->len;
+ p_attr->p_uuid = (tBTA_GATTC_UUID *)(p_attr + 1);
+ p_attr->p_next = NULL;
+
+ pp = (UINT8 *)p_attr->p_uuid;
+
+ if (p_uuid->len == LEN_UUID_16)
+ {
+ UINT16_TO_STREAM(pp, p_uuid->uu.uuid16);
+ }
+ else if (p_uuid->len == LEN_UUID_128)
+ {
+ memcpy(pp, p_uuid->uu.uuid128, LEN_UUID_128);
+ }
+
+ if (type == BTA_GATTC_ATTR_TYPE_CHAR)
+ p_attr->inst_id = bta_gattc_get_char_inst_id(p_srvc_cb->p_cur_srvc, *p_uuid);
+ /* else: char descriptor, no instance ID needed */
+ else /* TODO: --->> temp treat included service same as char descriptor */
+ p_attr->inst_id = 0;
+
+ /* update service information */
+ p_srvc_cb->p_free += len;
+ p_srvc_cb->free_byte -= len;
+
+ /* first attribute within the service, update the attribute pointer */
+ if (p_srvc_cb->p_cur_srvc->p_attr == NULL)
+ {
+ p_srvc_cb->p_cur_srvc->p_attr = p_attr;
+ }
+ if (p_srvc_cb->p_cur_srvc->p_last_attr != NULL)
+ p_srvc_cb->p_cur_srvc->p_last_attr->p_next = p_attr;
+
+ p_srvc_cb->p_cur_srvc->p_last_attr = p_attr;
+
+#if 0
+//#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE)
+ bta_gattc_display_cache_server(p_srvc_cb->p_srvc_cache);
+#endif
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function bta_gattc_get_disc_range
+**
+** Description get discovery stating and ending handle range.
+**
+** Returns None.
+**
+*******************************************************************************/
+void bta_gattc_get_disc_range(tBTA_GATTC_SERV *p_srvc_cb, UINT16 *p_s_hdl, UINT16 *p_e_hdl, BOOLEAN is_srvc)
+{
+ tBTA_GATTC_ATTR_REC *p_rec = NULL;
+
+ if (is_srvc)
+ {
+ p_rec = p_srvc_cb->p_srvc_list + p_srvc_cb->cur_srvc_idx;
+ *p_s_hdl = p_rec->s_handle;
+ }
+ else
+ {
+ p_rec = p_srvc_cb->p_srvc_list + p_srvc_cb->cur_char_idx;
+ *p_s_hdl = p_rec->s_handle + 1;
+ }
+
+ *p_e_hdl = p_rec->e_handle;
+#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE)
+ APPL_TRACE_DEBUG2("discover range [%d ~ %d]",p_rec->s_handle, p_rec->e_handle);
+#endif
+ return;
+}
+/*******************************************************************************
+**
+** Function bta_gattc_discover_pri_service
+**
+** Description Start primary service discovery
+**
+** Returns status of the operation.
+**
+*******************************************************************************/
+tBTA_GATT_STATUS bta_gattc_discover_pri_service(UINT16 conn_id, tBTA_GATTC_SERV *p_server_cb, UINT8 disc_type)
+{
+#if (BLE_INCLUDED == TRUE && (defined BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE))
+ tBT_DEVICE_TYPE dev_type;
+ tBLE_ADDR_TYPE addr_type;
+
+ BTM_ReadDevInfo(p_server_cb->server_bda, &dev_type, &addr_type);
+ if (dev_type == BT_DEVICE_TYPE_BLE)
+ return bta_gattc_discover_procedure(conn_id, p_server_cb, disc_type);
+ else
+ return bta_gattc_sdp_service_disc(conn_id, p_server_cb);
+#endif
+ return BTA_GATT_ERROR;
+
+}
+/*******************************************************************************
+**
+** Function bta_gattc_discover_procedure
+**
+** Description Start a particular type of discovery procedure on server.
+**
+** Returns status of the operation.
+**
+*******************************************************************************/
+tBTA_GATT_STATUS bta_gattc_discover_procedure(UINT16 conn_id, tBTA_GATTC_SERV *p_server_cb, UINT8 disc_type)
+{
+ tGATT_DISC_PARAM param;
+ BOOLEAN is_service = TRUE;
+
+ memset(&param, 0, sizeof(tGATT_DISC_PARAM));
+
+ if (disc_type == GATT_DISC_SRVC_ALL || disc_type == GATT_DISC_SRVC_BY_UUID)
+ {
+ param.s_handle = 1;
+ param.e_handle = 0xFFFF;
+ }
+ else
+ {
+ if (disc_type == GATT_DISC_CHAR_DSCPT)
+ is_service = FALSE;
+
+ bta_gattc_get_disc_range(p_server_cb, &param.s_handle, &param.e_handle, is_service);
+
+ if (param.s_handle > param.e_handle)
+ {
+ APPL_TRACE_ERROR2("discover range invalid: [0x%04x ~ 0x%04x]", param.s_handle, param.e_handle);
+
+ return GATT_ERROR;
+ }
+ }
+ return GATTC_Discover (conn_id, disc_type, &param);
+
+}
+/*******************************************************************************
+**
+** Function bta_gattc_start_disc_include_srvc
+**
+** Description Start discovery for included service
+**
+** Returns status of the operation.
+**
+*******************************************************************************/
+tBTA_GATT_STATUS bta_gattc_start_disc_include_srvc(UINT16 conn_id, tBTA_GATTC_SERV *p_srvc_cb)
+{
+ APPL_TRACE_DEBUG0("starting discovery included service");
+
+ return bta_gattc_discover_procedure(conn_id, p_srvc_cb, GATT_DISC_INC_SRVC);
+}
+/*******************************************************************************
+**
+** Function bta_gattc_start_disc_char
+**
+** Description Start discovery for characteristic
+**
+** Returns status of the operation.
+**
+*******************************************************************************/
+tBTA_GATT_STATUS bta_gattc_start_disc_char(UINT16 conn_id, tBTA_GATTC_SERV *p_srvc_cb)
+{
+ p_srvc_cb->total_char = 0;
+
+ APPL_TRACE_DEBUG0("starting discover characteristics");
+
+ return bta_gattc_discover_procedure(conn_id, p_srvc_cb, GATT_DISC_CHAR);
+}
+/*******************************************************************************
+**
+** Function bta_gattc_start_disc_char_dscp
+**
+** Description Start discovery for characteristic descriptor
+**
+** Returns none.
+**
+*******************************************************************************/
+void bta_gattc_start_disc_char_dscp(UINT16 conn_id, tBTA_GATTC_SERV *p_srvc_cb)
+{
+ APPL_TRACE_DEBUG0("starting discover characteristics descriptor");
+
+ if (bta_gattc_discover_procedure(conn_id, p_srvc_cb, GATT_DISC_CHAR_DSCPT) != 0)
+ bta_gattc_char_dscpt_disc_cmpl(conn_id, p_srvc_cb);
+
+}
+/*******************************************************************************
+**
+** Function bta_gattc_explore_srvc
+**
+** Description process the service discovery complete event
+**
+** Returns status
+**
+*******************************************************************************/
+static void bta_gattc_explore_srvc(UINT16 conn_id, tBTA_GATTC_SERV *p_srvc_cb)
+{
+ tBTA_GATTC_ATTR_REC *p_rec = p_srvc_cb->p_srvc_list + p_srvc_cb->cur_srvc_idx;
+ tBTA_GATTC_CLCB *p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
+
+ APPL_TRACE_DEBUG1("Start service discovery: srvc_idx = %d", p_srvc_cb->cur_srvc_idx);
+
+ p_srvc_cb->cur_char_idx = p_srvc_cb->next_avail_idx = p_srvc_cb->total_srvc;
+
+ if (p_clcb == NULL)
+ {
+ APPL_TRACE_ERROR0("unknown connection ID");
+ return;
+ }
+ /* start expore a service if there is service not been explored */
+ if (p_srvc_cb->cur_srvc_idx < p_srvc_cb->total_srvc)
+ {
+ /* add the first service into cache */
+ if (bta_gattc_add_srvc_to_cache (p_srvc_cb,
+ p_rec->s_handle,
+ p_rec->e_handle,
+ &p_rec->uuid,
+ p_rec->is_primary,
+ p_rec->srvc_inst_id) == 0)
+ {
+ /* start discovering included services */
+ bta_gattc_start_disc_include_srvc(conn_id, p_srvc_cb);
+ return;
+ }
+ }
+ /* no service found at all, the end of server discovery*/
+ APPL_TRACE_ERROR0("No More Service found");
+
+#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE)
+ bta_gattc_display_cache_server(p_srvc_cb->p_srvc_cache);
+#endif
+ /* save cache to NV */
+ p_clcb->p_srcb->state = BTA_GATTC_SERV_SAVE;
+ bta_gattc_co_cache_open(p_srvc_cb->server_bda, BTA_GATTC_CI_CACHE_OPEN_EVT,
+ conn_id, TRUE);
+ //bta_gattc_sm_execute(p_clcb, BTA_GATTC_DISCOVER_CMPL_EVT, NULL);
+}
+/*******************************************************************************
+**
+** Function bta_gattc_incl_srvc_disc_cmpl
+**
+** Description process the relationship discovery complete event
+**
+** Returns status
+**
+*******************************************************************************/
+static void bta_gattc_incl_srvc_disc_cmpl(UINT16 conn_id, tBTA_GATTC_SERV *p_srvc_cb)
+{
+ p_srvc_cb->cur_char_idx = p_srvc_cb->total_srvc;
+
+ /* start discoverying characteristic */
+ bta_gattc_start_disc_char(conn_id, p_srvc_cb);
+}
+/*******************************************************************************
+**
+** Function bta_gattc_char_disc_cmpl
+**
+** Description process the characteristic discovery complete event
+**
+** Returns status
+**
+*******************************************************************************/
+static void bta_gattc_char_disc_cmpl(UINT16 conn_id, tBTA_GATTC_SERV *p_srvc_cb)
+{
+ tBTA_GATTC_ATTR_REC *p_rec = p_srvc_cb->p_srvc_list + p_srvc_cb->cur_char_idx;
+
+ APPL_TRACE_DEBUG1("Total %d Char found ", p_srvc_cb->total_char);
+
+ /* if there are characteristic needs to be explored */
+ if (p_srvc_cb->total_char > 0)
+ {
+ /* add the first characteristic into cache */
+ bta_gattc_add_attr_to_cache (p_srvc_cb,
+ p_rec->s_handle,
+ &p_rec->uuid,
+ p_rec->property,
+ BTA_GATTC_ATTR_TYPE_CHAR);
+
+ /* start discoverying characteristic descriptor , if failed, disc for next char*/
+ bta_gattc_start_disc_char_dscp(conn_id, p_srvc_cb);
+ }
+ else /* otherwise start with next service */
+ {
+ p_srvc_cb->cur_srvc_idx ++;
+
+ bta_gattc_explore_srvc (conn_id, p_srvc_cb);
+ }
+}
+/*******************************************************************************
+**
+** Function bta_gattc_char_dscpt_disc_cmpl
+**
+** Description process the char descriptor discovery complete event
+**
+** Returns status
+**
+*******************************************************************************/
+static void bta_gattc_char_dscpt_disc_cmpl(UINT16 conn_id, tBTA_GATTC_SERV *p_srvc_cb)
+{
+ tBTA_GATTC_ATTR_REC *p_rec = NULL;
+
+ if (-- p_srvc_cb->total_char > 0)
+ {
+ p_rec = p_srvc_cb->p_srvc_list + (++ p_srvc_cb->cur_char_idx);
+ /* add the next characteristic into cache */
+ bta_gattc_add_attr_to_cache (p_srvc_cb,
+ p_rec->s_handle,
+ &p_rec->uuid,
+ p_rec->property,
+ BTA_GATTC_ATTR_TYPE_CHAR);
+
+ /* start discoverying next characteristic for char descriptor */
+ bta_gattc_start_disc_char_dscp(conn_id, p_srvc_cb);
+ }
+ else
+ /* all characteristic has been explored, start with next service if any */
+ {
+#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE)
+ APPL_TRACE_ERROR0("all char has been explored");
+#endif
+ p_srvc_cb->cur_srvc_idx ++;
+ bta_gattc_explore_srvc (conn_id, p_srvc_cb);
+ }
+
+}
+static BOOLEAN bta_gattc_srvc_in_list(tBTA_GATTC_SERV *p_srvc_cb, UINT16 s_handle,
+ UINT16 e_handle, tBT_UUID uuid)
+{
+ tBTA_GATTC_ATTR_REC *p_rec = NULL;
+ UINT8 i;
+ BOOLEAN exist_srvc = FALSE;
+
+ if (!GATT_HANDLE_IS_VALID(s_handle) || !GATT_HANDLE_IS_VALID(e_handle))
+ {
+ APPL_TRACE_ERROR2("invalid included service handle: [0x%04x ~ 0x%04x]", s_handle, e_handle);
+ exist_srvc = TRUE;
+ }
+ else
+ {
+ for (i = 0; i < p_srvc_cb->next_avail_idx; i ++)
+ {
+ p_rec = p_srvc_cb->p_srvc_list + i;
+
+ /* a new service should not have any overlap with other service handle range */
+ if (p_rec->s_handle == s_handle || p_rec->e_handle == e_handle)
+ {
+ exist_srvc = TRUE;
+ break;
+ }
+ }
+ }
+ return exist_srvc;
+}
+/*******************************************************************************
+**
+** Function bta_gattc_add_srvc_to_list
+**
+** Description Add a service into explore pending list
+**
+** Returns status
+**
+*******************************************************************************/
+static tBTA_GATT_STATUS bta_gattc_add_srvc_to_list(tBTA_GATTC_SERV *p_srvc_cb,
+ UINT16 s_handle, UINT16 e_handle,
+ tBT_UUID uuid, BOOLEAN is_primary)
+{
+ tBTA_GATTC_ATTR_REC *p_rec = NULL;
+ tBTA_GATT_STATUS status = BTA_GATT_OK;
+
+ if (p_srvc_cb->next_avail_idx < BTA_GATTC_MAX_CACHE_CHAR)
+ {
+ p_rec = p_srvc_cb->p_srvc_list + p_srvc_cb->next_avail_idx;
+
+ p_srvc_cb->total_srvc ++;
+
+ APPL_TRACE_DEBUG2("bta_gattc_add_srvc_to_list handle = %d, service type = 0x%04x",
+ s_handle, uuid.uu.uuid16);
+
+ p_rec->s_handle = s_handle;
+ p_rec->e_handle = e_handle;
+ p_rec->is_primary = is_primary;
+ p_rec->srvc_inst_id = bta_gattc_get_srvc_inst_id(p_srvc_cb, uuid);
+ memcpy(&p_rec->uuid, &uuid, sizeof(tBT_UUID));
+
+ p_srvc_cb->next_avail_idx ++;
+
+ }
+ else
+ { /* allocate bigger buffer ?? */
+ status = GATT_DB_FULL;
+
+ APPL_TRACE_ERROR0("char not added, no resources");
+ }
+ return status;
+}
+/*******************************************************************************
+**
+** Function bta_gattc_add_char_to_list
+**
+** Description Add a characteristic into explore pending list
+**
+** Returns status
+**
+*******************************************************************************/
+static tBTA_GATT_STATUS bta_gattc_add_char_to_list(tBTA_GATTC_SERV *p_srvc_cb,
+ UINT16 decl_handle, UINT16 value_handle,
+ tBT_UUID uuid, UINT8 property)
+{
+ tBTA_GATTC_ATTR_REC *p_rec = NULL;
+ tBTA_GATT_STATUS status = BTA_GATT_OK;
+
+ if (p_srvc_cb->p_srvc_list == NULL)
+ {
+ APPL_TRACE_ERROR0("No service available, unexpected char discovery result");
+ status = BTA_GATT_INTERNAL_ERROR;
+ }
+ else if (p_srvc_cb->next_avail_idx < BTA_GATTC_MAX_CACHE_CHAR)
+ {
+
+ p_rec = p_srvc_cb->p_srvc_list + p_srvc_cb->next_avail_idx;
+
+ p_srvc_cb->total_char ++;
+
+ p_rec->s_handle = value_handle;
+ p_rec->property = property;
+ p_rec->e_handle = (p_srvc_cb->p_srvc_list + p_srvc_cb->cur_srvc_idx)->e_handle;
+ memcpy(&p_rec->uuid, &uuid, sizeof(tBT_UUID));
+
+ /* update the endind handle of pervious characteristic if available */
+ if (p_srvc_cb->total_char > 1)
+ {
+ p_rec -= 1;
+ p_rec->e_handle = decl_handle - 1;
+ }
+ p_srvc_cb->next_avail_idx ++;
+ }
+ else
+ {
+ APPL_TRACE_ERROR0("char not added, no resources");
+ /* allocate bigger buffer ?? */
+ status = BTA_GATT_DB_FULL;
+ }
+ return status;
+
+}
+/*******************************************************************************
+**
+** Function bta_gattc_sdp_callback
+**
+** Description Process the discovery result from sdp
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_gattc_sdp_callback (UINT16 sdp_status)
+{
+ tSDP_DISC_REC *p_sdp_rec = NULL;
+ tBT_UUID service_uuid;
+ tSDP_PROTOCOL_ELEM pe;
+ UINT16 start_handle = 0, end_handle = 0;
+ tBTA_GATTC_SERV *p_srvc_cb = bta_gattc_find_scb_by_cid(bta_gattc_cb.sdp_conn_id);
+
+ if(((sdp_status == SDP_SUCCESS) || (sdp_status == SDP_DB_FULL)) && p_srvc_cb != NULL)
+ {
+ do
+ {
+ /* find a service record, report it */
+ p_sdp_rec = SDP_FindServiceInDb(bta_gattc_cb.p_sdp_db,
+ 0, p_sdp_rec);
+ if (p_sdp_rec)
+ {
+ if (SDP_FindServiceUUIDInRec(p_sdp_rec, &service_uuid))
+ {
+
+ if (SDP_FindProtocolListElemInRec(p_sdp_rec, UUID_PROTOCOL_ATT, &pe))
+ {
+ start_handle = (UINT16) pe.params[0];
+ end_handle = (UINT16) pe.params[1];
+
+#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE)
+ APPL_TRACE_EVENT3("Found ATT service [0x%04x] handle[0x%04x ~ 0x%04x]",
+ service_uuid.uu.uuid16, start_handle, end_handle);
+#endif
+
+ if (GATT_HANDLE_IS_VALID(start_handle) && GATT_HANDLE_IS_VALID(end_handle) &&
+ p_srvc_cb != NULL)
+ {
+ /* discover services result, add services into a service list */
+ bta_gattc_add_srvc_to_list(p_srvc_cb,
+ start_handle,
+ end_handle,
+ service_uuid,
+ TRUE);
+ }
+ else
+ {
+ APPL_TRACE_ERROR2("invalid start_handle = %d end_handle = %d", start_handle, end_handle);
+ }
+ }
+
+
+ }
+ }
+ } while (p_sdp_rec);
+ }
+
+ if ( p_srvc_cb != NULL)
+ /* start discover primary service */
+ bta_gattc_explore_srvc(bta_gattc_cb.sdp_conn_id, p_srvc_cb);
+ else
+ {
+ APPL_TRACE_ERROR0("GATT service discovery is done on unknown connection");
+ }
+
+ GKI_freebuf(bta_gattc_cb.p_sdp_db);
+ bta_gattc_cb.p_sdp_db = NULL;
+ bta_gattc_cb.sdp_conn_id = 0;
+}
+/*******************************************************************************
+**
+** Function bta_gattc_sdp_service_disc
+**
+** Description Start DSP Service Discovert
+**
+** Returns void
+**
+*******************************************************************************/
+static tBTA_GATT_STATUS bta_gattc_sdp_service_disc(UINT16 conn_id, tBTA_GATTC_SERV *p_server_cb)
+{
+ tSDP_UUID uuid;
+ UINT16 num_attrs = 2;
+ UINT16 attr_list[2];
+ tBTA_GATT_STATUS status = BTA_GATT_ERROR;
+
+ memset (&uuid, 0, sizeof(tSDP_UUID));
+
+ uuid.len = LEN_UUID_16;
+ uuid.uu.uuid16 = UUID_PROTOCOL_ATT;
+
+ if((bta_gattc_cb.p_sdp_db = (tSDP_DISCOVERY_DB *)GKI_getbuf(BTA_GATT_SDP_DB_SIZE)) != NULL)
+ {
+ attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST;
+ attr_list[1] = ATTR_ID_PROTOCOL_DESC_LIST;
+
+ SDP_InitDiscoveryDb (bta_gattc_cb.p_sdp_db, BTA_GATT_SDP_DB_SIZE, 1, &uuid, num_attrs, attr_list);
+
+ if(!SDP_ServiceSearchAttributeRequest (p_server_cb->server_bda, bta_gattc_cb.p_sdp_db, &bta_gattc_sdp_callback))
+ {
+ GKI_freebuf(bta_gattc_cb.p_sdp_db);
+ bta_gattc_cb.p_sdp_db = NULL;
+ }
+ else
+ {
+ bta_gattc_cb.sdp_conn_id = conn_id;
+ status = BTA_GATT_OK;
+ }
+ }
+ return status;
+}
+/*******************************************************************************
+**
+** Function bta_gattc_disc_res_cback
+** bta_gattc_disc_cmpl_cback
+**
+** Description callback functions to GATT client stack.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_gattc_disc_res_cback (UINT16 conn_id, tGATT_DISC_TYPE disc_type, tGATT_DISC_RES *p_data)
+{
+ tBTA_GATTC_SERV * p_srvc_cb = NULL;
+ BOOLEAN pri_srvc;
+
+ p_srvc_cb = bta_gattc_find_scb_by_cid(conn_id);
+
+ if (p_srvc_cb != NULL)
+ {
+ switch (disc_type)
+ {
+ case GATT_DISC_SRVC_ALL:
+ /* discover services result, add services into a service list */
+ bta_gattc_add_srvc_to_list(p_srvc_cb,
+ p_data->handle,
+ p_data->value.group_value.e_handle,
+ p_data->value.group_value.service_type,
+ TRUE);
+
+ break;
+ case GATT_DISC_SRVC_BY_UUID:
+ bta_gattc_add_srvc_to_list(p_srvc_cb,
+ p_data->handle,
+ p_data->value.handle,
+ p_data->type,
+ TRUE);
+ break;
+
+ case GATT_DISC_INC_SRVC:
+ /* add included service into service list if it's secondary or it never showed up
+ in the primary service search */
+ pri_srvc = bta_gattc_srvc_in_list(p_srvc_cb,
+ p_data->value.incl_service.s_handle,
+ p_data->value.incl_service.e_handle,
+ p_data->value.incl_service.service_type);
+
+ if (!pri_srvc)
+ bta_gattc_add_srvc_to_list(p_srvc_cb,
+ p_data->value.incl_service.s_handle,
+ p_data->value.incl_service.e_handle,
+ p_data->value.incl_service.service_type,
+ FALSE);
+ /* add into database */
+ bta_gattc_add_attr_to_cache(p_srvc_cb,
+ p_data->handle,
+ &p_data->value.incl_service.service_type,
+ pri_srvc,
+ BTA_GATTC_ATTR_TYPE_INCL_SRVC);
+ break;
+
+ case GATT_DISC_CHAR:
+ /* add char value into database */
+ bta_gattc_add_char_to_list(p_srvc_cb,
+ p_data->handle,
+ p_data->value.dclr_value.val_handle,
+ p_data->value.dclr_value.char_uuid,
+ p_data->value.dclr_value.char_prop);
+ break;
+
+ case GATT_DISC_CHAR_DSCPT:
+ bta_gattc_add_attr_to_cache(p_srvc_cb, p_data->handle, &p_data->type, 0, BTA_GATTC_ATTR_TYPE_CHAR_DESCR);
+ break;
+ }
+ }
+}
+void bta_gattc_disc_cmpl_cback (UINT16 conn_id, tGATT_DISC_TYPE disc_type, tGATT_STATUS status)
+{
+ tBTA_GATTC_SERV * p_srvc_cb;
+
+ p_srvc_cb = bta_gattc_find_scb_by_cid(conn_id);
+
+ if (p_srvc_cb != NULL)
+ {
+ switch (disc_type)
+ {
+ case GATT_DISC_SRVC_ALL:
+#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE)
+ bta_gattc_display_explore_record(p_srvc_cb->p_srvc_list, p_srvc_cb->next_avail_idx);
+#endif
+ bta_gattc_explore_srvc(conn_id, p_srvc_cb);
+ break;
+
+ case GATT_DISC_INC_SRVC:
+ bta_gattc_incl_srvc_disc_cmpl(conn_id, p_srvc_cb);
+
+ break;
+
+ case GATT_DISC_CHAR:
+#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE)
+ bta_gattc_display_explore_record(p_srvc_cb->p_srvc_list, p_srvc_cb->next_avail_idx);
+#endif
+ bta_gattc_char_disc_cmpl(conn_id, p_srvc_cb);
+ break;
+
+ case GATT_DISC_CHAR_DSCPT:
+ bta_gattc_char_dscpt_disc_cmpl(conn_id, p_srvc_cb);
+ break;
+ }
+ }
+}
+/*******************************************************************************
+**
+** Function bta_gattc_id2handle
+**
+** Description map GATT ID to handle in a given cache.
+**
+** Returns the handle mapped. 0 if not found.
+**
+*******************************************************************************/
+UINT16 bta_gattc_id2handle(tBTA_GATTC_SERV *p_srcb, tBTA_GATT_SRVC_ID *p_service_id,
+ tBTA_GATT_ID *p_char_id, tBT_UUID descr_uuid)
+{
+ tBTA_GATTC_CACHE *p_cache = p_srcb->p_srvc_cache;
+ tBTA_GATTC_CACHE_ATTR *p_attr;
+ UINT8 j;
+ UINT16 handle = 0;
+ tBT_UUID attr_uuid;
+ BOOLEAN char_map = FALSE, done = FALSE;
+
+ while (p_cache && !done)
+ {
+#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE)
+ APPL_TRACE_DEBUG3("Service: handle[%d] uuid[0x%04x] inst[%d]",
+ p_cache->s_handle, p_cache->service_uuid.id.uuid.uu.uuid16,
+ p_cache->service_uuid.id.inst_id);
+#endif
+ p_attr = p_cache->p_attr;
+
+ if (bta_gattc_uuid_compare(p_service_id->id.uuid, p_cache->service_uuid.id.uuid, TRUE) &&
+ p_service_id->id.inst_id == p_cache->service_uuid.id.inst_id &&
+ p_cache->service_uuid.is_primary == p_service_id->is_primary)
+ {
+ for (j = 0; p_attr; j ++)
+ {
+#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE)
+ APPL_TRACE_DEBUG5("\t Attr[0x%04x] handle[0x%04x] uuid[0x%04x] inst[%d] type[%d]",
+ j + 1, p_attr->attr_handle, p_attr->p_uuid->uuid16, p_attr->inst_id, p_attr->attr_type);
+#endif
+ bta_gattc_pack_attr_uuid(p_attr, &attr_uuid);
+
+ if (bta_gattc_uuid_compare(p_char_id->uuid, attr_uuid, TRUE) &&
+ p_char_id->inst_id == p_attr->inst_id)
+ {
+ if (descr_uuid.len == 0)
+ {
+ handle = p_attr->attr_handle;
+ done = TRUE;
+ break;
+ }
+ else
+ {
+#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE)
+ APPL_TRACE_DEBUG0("found matching characteristic for the descriptor");
+#endif
+ char_map = TRUE;
+ }
+ }
+ else if (char_map == TRUE)
+ {
+ if (p_attr->attr_type == BTA_GATTC_ATTR_TYPE_CHAR_DESCR)
+ {
+
+ if (bta_gattc_uuid_compare(descr_uuid, attr_uuid, TRUE))
+ {
+#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE)
+ APPL_TRACE_DEBUG0("found descripotor!!");
+#endif
+ handle = p_attr->attr_handle;
+ done = TRUE;
+ break;
+ }
+ else
+ {
+#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE)
+ APPL_TRACE_DEBUG0("descriptor UUID not matching");
+#endif
+ }
+ }
+ else /* another char */
+ {
+#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE)
+ APPL_TRACE_DEBUG0("no matching descriptor found!! start of next characteristic");
+#endif
+ char_map = FALSE;
+ done = TRUE;
+ break;
+ }
+ }
+ p_attr = p_attr->p_next;
+ }
+ }
+ p_cache = p_cache->p_next;
+ }
+
+ return handle;
+}
+/*******************************************************************************
+**
+** Function bta_gattc_handle2id
+**
+** Description map a handle to GATT ID in a given cache.
+**
+** Returns FALSE if map can not be found.
+**
+*******************************************************************************/
+
+BOOLEAN bta_gattc_handle2id(tBTA_GATTC_SERV *p_srcb, UINT16 handle, tBTA_GATT_SRVC_ID *p_service_id,
+ tBTA_GATT_ID *p_char_id, tBT_UUID *p_descr_type)
+{
+ tBTA_GATTC_CACHE *p_cache = p_srcb->p_srvc_cache;
+ tBTA_GATTC_CACHE_ATTR *p_attr, *p_char = NULL;
+ UINT8 j;
+
+ memset(p_service_id, 0, sizeof(tBTA_GATT_SRVC_ID));
+ memset(p_char_id, 0, sizeof(tBTA_GATT_ID));
+ memset(p_descr_type, 0, sizeof(tBT_UUID));
+
+ while (p_cache)
+ {
+#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE)
+ APPL_TRACE_DEBUG3("Service: handle[%d] uuid[0x%04x] inst[%d]",
+ p_cache->s_handle, p_cache->service_uuid.id.uuid.uu.uuid16,
+ p_cache->service_uuid.id.inst_id);
+#endif
+ /* a service found */
+ if (p_cache->s_handle == handle)
+ {
+ memcpy(p_service_id, &p_cache->service_uuid, sizeof(tBTA_GATT_SRVC_ID));
+
+ return TRUE;
+ }
+ else /* start looking for attributes within the service */
+ {
+ p_attr = p_cache->p_attr;
+
+ for (j = 0; p_attr; j ++)
+ {
+#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE)
+ APPL_TRACE_DEBUG5("\t Attr[0x%04x] handle[0x%04x] uuid[0x%04x] inst[%d] type[%d]",
+ j + 1, p_attr->attr_handle, p_attr->p_uuid->uuid16, p_attr->inst_id, p_attr->attr_type);
+#endif
+ if (p_attr->attr_type == BTA_GATTC_ATTR_TYPE_CHAR)
+ p_char = p_attr;
+
+ if (handle == p_attr->attr_handle)
+ {
+ memcpy(p_service_id, &p_cache->service_uuid, sizeof(tBTA_GATT_SRVC_ID));
+
+ if (p_attr->attr_type == BTA_GATTC_ATTR_TYPE_CHAR_DESCR)
+ {
+ bta_gattc_pack_attr_uuid(p_attr, p_descr_type);
+
+ if (p_char != NULL)
+ {
+ bta_gattc_pack_attr_uuid(p_char, &p_char_id->uuid);
+ p_char_id->inst_id = p_char->inst_id;
+ }
+ else
+ {
+ APPL_TRACE_ERROR0("descriptor does not belong to any chracteristic, error");
+ }
+ }
+ else
+ /* is a characterisitc value or included service */
+ {
+ bta_gattc_pack_attr_uuid(p_attr, &p_char_id->uuid);
+ p_char_id->inst_id =p_attr->inst_id;
+ }
+ return TRUE;
+ }
+ p_attr = p_attr->p_next;
+ }
+ }
+ p_cache = p_cache->p_next;
+ }
+
+ return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function bta_gattc_search_service
+**
+** Description search local cache for matching service record.
+**
+** Returns FALSE if map can not be found.
+**
+*******************************************************************************/
+void bta_gattc_search_service(tBTA_GATTC_CLCB *p_clcb, tBT_UUID uuid)
+{
+ tBTA_GATTC_SERV *p_srcb = p_clcb->p_srcb;
+ tBTA_GATTC_CACHE *p_cache = p_srcb->p_srvc_cache;
+ tBTA_GATTC cb_data;
+
+ while (p_cache)
+ {
+ if (bta_gattc_uuid_compare(uuid, p_cache->service_uuid.id.uuid, FALSE))
+ {
+//#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE)
+ APPL_TRACE_DEBUG3("found service [0x%04x], inst[%d] handle [%d]",
+ p_cache->service_uuid.id.uuid.uu.uuid16,
+ p_cache->service_uuid.id.inst_id,
+ p_cache->s_handle);
+//#endif
+ if (p_clcb->p_rcb->p_cback)
+ {
+ memset(&cb_data, 0, sizeof(tBTA_GATTC));
+
+ cb_data.srvc_res.conn_id = p_clcb->bta_conn_id;
+ memcpy(&cb_data.srvc_res.service_uuid, &p_cache->service_uuid ,sizeof(tBTA_GATT_SRVC_ID));
+
+ (* p_clcb->p_rcb->p_cback)(BTA_GATTC_SEARCH_RES_EVT, &cb_data);
+ //todo (tBTA_GATTC *)&p_cache->service_uuid);
+ }
+ }
+ p_cache = p_cache->p_next;
+ }
+}
+/*******************************************************************************
+**
+** Function bta_gattc_find_record
+**
+** Description search local cache for matching attribute record.
+**
+** Parameter p_result: output parameter to store the characteristic/
+** included service GATT ID.
+**
+** Returns GATT_ERROR is no recording found. BTA_GATT_OK if record found.
+**
+*******************************************************************************/
+static tBTA_GATT_STATUS bta_gattc_find_record(tBTA_GATTC_SERV *p_srcb,
+ tBTA_GATTC_ATTR_TYPE attr_type,
+ tBTA_GATT_SRVC_ID *p_service_id,
+ tBTA_GATT_ID *p_start_rec,
+ tBT_UUID * p_uuid_cond,
+ tBTA_GATT_ID *p_result,
+ void *p_param)
+{
+ tBTA_GATTC_CACHE *p_cache = p_srcb->p_srvc_cache;
+ tBTA_GATT_STATUS status = BTA_GATT_ERROR;
+ tBT_UUID uuid_cond = {0}, start_descr = {0};
+ UINT8 i, j;
+ tBTA_GATTC_CACHE_ATTR *p_attr;
+ BOOLEAN char_found = FALSE, descr_found = FALSE;
+
+ if (p_uuid_cond)
+ memcpy(&uuid_cond, p_uuid_cond, sizeof(tBT_UUID));
+
+ for (i = 0; p_cache <= p_srcb->p_cur_srvc && p_cache && status != BTA_GATT_OK; i ++)
+ {
+ if (bta_gattc_uuid_compare(p_service_id->id.uuid, p_cache->service_uuid.id.uuid, FALSE) &&
+ p_service_id->id.inst_id == p_cache->service_uuid.id.inst_id &&
+ p_service_id->is_primary == p_cache->service_uuid.is_primary)
+ {
+#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE)
+ APPL_TRACE_DEBUG2("found matching service [0x%04x], inst[%d]",
+ p_cache->service_uuid.id.uuid.uu.uuid16,
+ p_cache->service_uuid.id.inst_id);
+#endif
+ p_attr = p_cache->p_attr;
+
+ for (j = 0; p_attr; j ++)
+ {
+#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE)
+ APPL_TRACE_DEBUG5("\t Attr[%d] handle[0x%04x] uuid[0x%04x] inst[%d] type[%d]",
+ j + 1, p_attr->attr_handle,
+ p_attr->p_uuid->uuid16,
+ p_attr->inst_id,
+ p_attr->attr_type);
+#endif
+ bta_gattc_pack_attr_uuid(p_attr, &p_result->uuid);
+
+ if (p_start_rec != NULL && char_found == FALSE)
+ {
+ /* find the starting record first */
+ if (bta_gattc_uuid_compare(p_start_rec->uuid, p_result->uuid, FALSE) &&
+ p_start_rec->inst_id == p_attr->inst_id &&
+ (attr_type == p_attr->attr_type ||
+ /* find descriptor would look for characteristic first */
+ (attr_type == BTA_GATTC_ATTR_TYPE_CHAR_DESCR && p_attr->attr_type == BTA_GATTC_ATTR_TYPE_CHAR)))
+ {
+ char_found = TRUE;
+ }
+ }
+ else
+ {
+ /* if looking for descriptor, here is the where the descrptor to be found */
+ if (attr_type == BTA_GATTC_ATTR_TYPE_CHAR_DESCR)
+ {
+ /* starting descriptor UUID */
+ if (p_param != NULL)
+ memcpy(&start_descr, p_param, sizeof(tBT_UUID));
+ /* next characeteristic already, return error */
+ if (p_attr->attr_type != BTA_GATTC_ATTR_TYPE_CHAR_DESCR)
+ {
+ break;
+ }
+ else
+ {
+ if (start_descr.len != 0 && !descr_found)
+ {
+ if (bta_gattc_uuid_compare(start_descr, p_result->uuid, FALSE))
+ {
+ descr_found = TRUE;
+ }
+ }
+ else
+ {
+ /* with matching descriptor */
+ if (bta_gattc_uuid_compare(uuid_cond, p_result->uuid, FALSE))
+ {
+ status = BTA_GATT_OK;
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (bta_gattc_uuid_compare(uuid_cond, p_result->uuid, FALSE) &&
+ attr_type == p_attr->attr_type)
+ {
+
+ APPL_TRACE_DEBUG0("found char handle mapping characteristic");
+ p_result->inst_id = p_attr->inst_id;
+
+ if (p_param != NULL)
+ {
+ if (attr_type == BTA_GATTC_ATTR_TYPE_CHAR ||
+ attr_type == BTA_GATTC_ATTR_TYPE_INCL_SRVC)
+ {
+ *(tBTA_GATT_CHAR_PROP *)p_param = p_attr->property;
+ }
+ }
+
+ status = BTA_GATT_OK;
+ break;
+ }
+ }
+ }
+ p_attr = p_attr->p_next;
+ }
+ if (status)
+ {
+ APPL_TRACE_ERROR0("In the given service, can not find matching record");
+ }
+ break;
+ }
+
+ p_cache = p_cache->p_next;
+ }
+ return status;
+
+}
+
+/*******************************************************************************
+**
+** Function bta_gattc_query_cache
+**
+** Description search local cache for matching attribute record.
+**
+** Parameters conn_id: connection ID which identify the server.
+** p_srvc_id: the service ID of which the characteristic is belonged to.
+** *p_start_rec: start the search from the next record
+** after the one identified by *p_start_rec.
+** p_uuid_cond: UUID, if NULL find the first available
+** characteristic/included service.
+** p_output: output parameter which will store the GATT ID
+** of the characteristic /included service found.
+**
+** Returns BTA_GATT_ERROR is no recording found. BTA_GATT_OK if record found.
+**
+*******************************************************************************/
+tBTA_GATT_STATUS bta_gattc_query_cache(UINT16 conn_id,
+ tBTA_GATTC_ATTR_TYPE query_type,
+ tBTA_GATT_SRVC_ID *p_srvc_id,
+ tBTA_GATT_ID *p_start_rec,
+ tBT_UUID *p_uuid_cond,
+ tBTA_GATT_ID *p_output,
+ void *p_param)
+{
+ tBTA_GATTC_CLCB *p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
+ tBTA_GATT_STATUS status = BTA_GATT_ILLEGAL_PARAMETER;
+
+ /* lock other GKI task */
+ GKI_sched_lock();
+
+ APPL_TRACE_DEBUG0("bta_gattc_query_cache");
+
+ if (p_clcb != NULL )
+ {
+ if (p_clcb->state == BTA_GATTC_CONN_ST)
+ {
+ if (p_clcb->p_srcb &&
+ !p_clcb->p_srcb->p_srvc_list && /* no active discovery */
+ p_clcb->p_srcb->p_srvc_cache)
+ {
+ status = bta_gattc_find_record(p_clcb->p_srcb,
+ query_type,
+ p_srvc_id,
+ p_start_rec,
+ p_uuid_cond,
+ p_output,
+ p_param);
+ }
+ else
+ {
+ status = BTA_GATT_ERROR;
+ APPL_TRACE_ERROR0("No server cache available");
+ }
+ }
+ else
+ {
+ APPL_TRACE_ERROR1("server cache not available, CLCB state = %d", p_clcb->state);
+
+ status = (p_clcb->state == BTA_GATTC_DISCOVER_ST) ? BTA_GATT_BUSY : BTA_GATT_ERROR;
+ }
+ }
+ else
+ {
+ APPL_TRACE_ERROR1("Unknown conn ID: %d", conn_id);
+ }
+ GKI_sched_unlock();
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function bta_gattc_rebuild_cache
+**
+** Description rebuild server cache from NV cache.
+**
+** Parameters
+**
+** Returns None.
+**
+*******************************************************************************/
+void bta_gattc_rebuild_cache(tBTA_GATTC_SERV *p_srvc_cb, UINT16 num_attr,
+ tBTA_GATTC_NV_ATTR *p_attr, UINT16 attr_index)
+{
+ /* first attribute loading, initialize buffer */
+ APPL_TRACE_ERROR0("bta_gattc_rebuild_cache");
+ if (attr_index == 0)
+ {
+ while (p_srvc_cb->cache_buffer.p_first)
+ GKI_freebuf (GKI_dequeue (&p_srvc_cb->cache_buffer));
+
+ if (bta_gattc_alloc_cache_buf(p_srvc_cb) == NULL)
+ {
+ APPL_TRACE_ERROR0("allocate cache buffer failed, no resources");
+ }
+ else
+ {
+ p_srvc_cb->p_cur_srvc = p_srvc_cb->p_srvc_cache = NULL;
+ }
+ }
+
+ while (num_attr > 0 && p_attr != NULL)
+ {
+ switch (p_attr->attr_type)
+ {
+ case BTA_GATTC_ATTR_TYPE_SRVC:
+ bta_gattc_add_srvc_to_cache(p_srvc_cb,
+ p_attr->s_handle,
+ p_attr->e_handle,
+ &p_attr->uuid,
+ p_attr->is_primary,
+ p_attr->id);
+ break;
+
+ case BTA_GATTC_ATTR_TYPE_CHAR:
+ case BTA_GATTC_ATTR_TYPE_CHAR_DESCR:
+ case BTA_GATTC_ATTR_TYPE_INCL_SRVC:
+ bta_gattc_add_attr_to_cache(p_srvc_cb,
+ p_attr->s_handle,
+ &p_attr->uuid,
+ p_attr->prop,
+ p_attr->attr_type);
+ break;
+ }
+ p_attr ++;
+ num_attr --;
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_gattc_fill_nv_attr
+**
+** Description fill a NV attribute entry value
+**
+** Returns None.
+**
+*******************************************************************************/
+void bta_gattc_fill_nv_attr(tBTA_GATTC_NV_ATTR *p_attr, UINT8 type, UINT16 s_handle,
+ UINT16 e_handle, UINT8 id, tBT_UUID uuid, UINT8 prop, BOOLEAN is_primary)
+{
+ p_attr->s_handle = s_handle;
+ p_attr->e_handle = e_handle;
+ p_attr->attr_type = type;
+ p_attr->is_primary = is_primary;
+ p_attr->id = id;
+ p_attr->prop = prop;
+
+ memcpy(&p_attr->uuid, &uuid, sizeof(tBT_UUID));
+}
+/*******************************************************************************
+**
+** Function bta_gattc_cache_save
+**
+** Description save the server cache into NV
+**
+** Returns None.
+**
+*******************************************************************************/
+BOOLEAN bta_gattc_cache_save(tBTA_GATTC_SERV *p_srvc_cb, UINT16 conn_id)
+{
+ tBTA_GATTC_CACHE *p_cur_srvc = p_srvc_cb->p_srvc_cache;
+ UINT8 i = 0;
+ UINT16 offset = 0;
+ tBTA_GATTC_NV_ATTR nv_attr[BTA_GATTC_NV_LOAD_MAX];
+ tBTA_GATTC_CACHE_ATTR *p_attr;
+ tBT_UUID uuid;
+
+ while (p_cur_srvc && i < BTA_GATTC_NV_LOAD_MAX)
+ {
+ if (offset ++ >= p_srvc_cb->attr_index)
+ {
+ bta_gattc_fill_nv_attr(&nv_attr[i++],
+ BTA_GATTC_ATTR_TYPE_SRVC,
+ p_cur_srvc->s_handle,
+ p_cur_srvc->e_handle,
+ p_cur_srvc->service_uuid.id.inst_id,
+ p_cur_srvc->service_uuid.id.uuid,
+ 0,
+ p_cur_srvc->service_uuid.is_primary);
+ }
+
+ p_attr = p_cur_srvc->p_attr;
+
+ for (; p_attr && i < BTA_GATTC_NV_LOAD_MAX ; offset ++, p_attr = p_attr->p_next)
+ {
+ if (offset >= p_srvc_cb->attr_index)
+ {
+ if ((uuid.len = p_attr->uuid_len) == LEN_UUID_16)
+ {
+ uuid.uu.uuid16 = p_attr->p_uuid->uuid16;
+ }
+ else
+ {
+ memcpy(uuid.uu.uuid128, p_attr->p_uuid->uuid128, LEN_UUID_128);
+ }
+
+ bta_gattc_fill_nv_attr(&nv_attr[i++],
+ p_attr->attr_type,
+ p_attr->attr_handle,
+ 0,
+ p_attr->inst_id,
+ uuid,
+ p_attr->property,
+ FALSE);
+ }
+ }
+ p_cur_srvc = p_cur_srvc->p_next;
+ }
+
+ if (i > 0)
+ {
+ bta_gattc_co_cache_save(p_srvc_cb->server_bda, BTA_GATTC_CI_CACHE_SAVE_EVT, i,
+ nv_attr, p_srvc_cb->attr_index, conn_id);
+
+ p_srvc_cb->attr_index += i;
+
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+#endif /* BTA_GATT_INCLUDED */
+
diff --git a/bta/gatt/bta_gattc_ci.c b/bta/gatt/bta_gattc_ci.c
new file mode 100644
index 0000000..f5b4f41
--- /dev/null
+++ b/bta/gatt/bta_gattc_ci.c
@@ -0,0 +1,125 @@
+/*****************************************************************************
+**
+** Name: bta_gattc_ci.c
+**
+** Description: This is the implementation file for the GATT
+** call-in functions.
+**
+** Copyright (c) 2010, Broadcom Corp., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+
+#if defined(BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE)
+
+#include <string.h>
+
+#include "bta_api.h"
+#include "bta_sys.h"
+#include "bta_gattc_ci.h"
+#include "gki.h"
+#include "bd.h"
+
+/*******************************************************************************
+**
+** Function bta_gattc_ci_cache_open
+**
+** Description This function sends an event to indicate server cache open
+** completed.
+**
+** Parameters server_bda - server BDA of this cache.
+** status - BTA_GATT_OK if full buffer of data,
+** BTA_GATT_FAIL if an error has occurred.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_gattc_ci_cache_open(BD_ADDR server_bda, UINT16 evt, tBTA_GATT_STATUS status,
+ UINT16 conn_id)
+{
+ tBTA_GATTC_CI_EVT *p_evt;
+
+ if ((p_evt = (tBTA_GATTC_CI_EVT *) GKI_getbuf(sizeof(tBTA_GATTC_CI_EVT))) != NULL)
+ {
+ p_evt->hdr.event = evt;
+ p_evt->hdr.layer_specific = conn_id;
+
+ p_evt->status = status;
+ bta_sys_sendmsg(p_evt);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_gattc_ci_cache_load
+**
+** Description This function sends an event to BTA indicating the phone has
+** load the servere cache and ready to send it to the stack.
+**
+** Parameters server_bda - server BDA of this cache.
+** num_bytes_read - number of bytes read into the buffer
+** specified in the read callout-function.
+** status - BTA_GATT_OK if full buffer of data,
+** BTA_GATT_FAIL if an error has occurred.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_gattc_ci_cache_load(BD_ADDR server_bda, UINT16 evt, UINT16 num_attr,
+ tBTA_GATTC_NV_ATTR *p_attr, tBTA_GATT_STATUS status,
+ UINT16 conn_id)
+{
+ tBTA_GATTC_CI_LOAD *p_evt;
+
+ if ((p_evt = (tBTA_GATTC_CI_LOAD *) GKI_getbuf(sizeof(tBTA_GATTC_CI_LOAD))) != NULL)
+ {
+ memset(p_evt, 0, sizeof(tBTA_GATTC_CI_LOAD));
+
+ p_evt->hdr.event = evt;
+ p_evt->hdr.layer_specific = conn_id;
+
+ p_evt->status = status;
+ p_evt->num_attr = (num_attr > BTA_GATTC_NV_LOAD_MAX) ? BTA_GATTC_NV_LOAD_MAX : num_attr;
+
+ if (p_evt->num_attr > 0 && p_attr != NULL)
+ {
+ memcpy(p_evt->attr, p_attr, p_evt->num_attr * sizeof(tBTA_GATTC_NV_ATTR));
+ }
+
+ bta_sys_sendmsg(p_evt);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_gattc_ci_cache_save
+**
+** Description This function sends an event to BTA indicating the phone has
+** save the servere cache.
+**
+** Parameters server_bda - server BDA of this cache.
+** evt - callin event code.
+** status - BTA_GATT_OK if full buffer of data,
+** BTA_GATT_ERROR if an error has occurred.
+*8 conn_id - for this NV operation for.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_gattc_ci_cache_save(BD_ADDR server_bda, UINT16 evt, tBTA_GATT_STATUS status,
+ UINT16 conn_id)
+{
+ tBTA_GATTC_CI_EVT *p_evt;
+
+ if ((p_evt = (tBTA_GATTC_CI_EVT *) GKI_getbuf(sizeof(tBTA_GATTC_CI_EVT))) != NULL)
+ {
+ p_evt->hdr.event = evt;
+ p_evt->hdr.layer_specific = conn_id;
+
+ p_evt->status = status;
+ bta_sys_sendmsg(p_evt);
+ }
+}
+#endif /* BTA_GATT_INCLUDED */
diff --git a/bta/gatt/bta_gattc_int.h b/bta/gatt/bta_gattc_int.h
new file mode 100644
index 0000000..4ae7697
--- /dev/null
+++ b/bta/gatt/bta_gattc_int.h
@@ -0,0 +1,452 @@
+/*****************************************************************************
+**
+** Name: bta_gattc_int.h
+**
+** Description: This is the private file for the file transfer
+** client (FTC).
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_GATTC_INT_H
+#define BTA_GATTC_INT_H
+
+#include "bt_target.h"
+#include "bta_sys.h"
+#include "bta_gatt_api.h"
+#include "bta_gattc_ci.h"
+#include "bta_gattc_co.h"
+
+#include "gki.h"
+
+/*****************************************************************************
+** Constants and data types
+*****************************************************************************/
+enum
+{
+ BTA_GATTC_API_OPEN_EVT = BTA_SYS_EVT_START(BTA_ID_GATTC),
+ BTA_GATTC_INT_OPEN_FAIL_EVT,
+ BTA_GATTC_API_CANCEL_OPEN_EVT,
+ BTA_GATTC_INT_CANCEL_OPEN_OK_EVT,
+
+ BTA_GATTC_API_READ_EVT,
+ BTA_GATTC_API_WRITE_EVT,
+ BTA_GATTC_API_EXEC_EVT,
+
+ BTA_GATTC_API_CLOSE_EVT,
+
+ BTA_GATTC_API_SEARCH_EVT,
+ BTA_GATTC_API_CONFIRM_EVT,
+ BTA_GATTC_API_READ_MULTI_EVT,
+
+ BTA_GATTC_INT_CONN_EVT,
+ BTA_GATTC_INT_DISCOVER_EVT,
+ BTA_GATTC_DISCOVER_CMPL_EVT,
+ BTA_GATTC_OP_CMPL_EVT,
+ BTA_GATTC_INT_DISCONN_EVT,
+
+ /* for cache loading/saving */
+ BTA_GATTC_START_CACHE_EVT,
+ BTA_GATTC_CI_CACHE_OPEN_EVT,
+ BTA_GATTC_CI_CACHE_LOAD_EVT,
+ BTA_GATTC_CI_CACHE_SAVE_EVT,
+
+ BTA_GATTC_INT_START_IF_EVT,
+ BTA_GATTC_API_REG_EVT,
+ BTA_GATTC_API_DEREG_EVT,
+ BTA_GATTC_INT_DEREG_EVT
+
+};
+typedef UINT16 tBTA_GATTC_INT_EVT;
+
+/* max client application GATTC can support */
+#ifndef BTA_GATTC_CL_MAX
+#define BTA_GATTC_CL_MAX 4
+#endif
+
+/* max known devices GATTC can support */
+#ifndef BTA_GATTC_KNOWN_SR_MAX
+#define BTA_GATTC_KNOWN_SR_MAX 4
+#endif
+
+#ifndef BTA_GATTC_CLCB_MAX
+ #define BTA_GATTC_CLCB_MAX GATT_CL_MAX_LCB
+#endif
+
+#define BTA_GATTC_WRITE_PREPARE GATT_WRITE_PREPARE
+
+/* internal strucutre for GATTC register API */
+typedef struct
+{
+ BT_HDR hdr;
+ tBT_UUID app_uuid;
+ tBTA_GATTC_CBACK *p_cback;
+}tBTA_GATTC_API_REG;
+
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_GATTC_IF client_if;
+}tBTA_GATTC_INT_START_IF;
+
+typedef tBTA_GATTC_INT_START_IF tBTA_GATTC_API_DEREG;
+typedef tBTA_GATTC_INT_START_IF tBTA_GATTC_INT_DEREG;
+
+typedef struct
+{
+ BT_HDR hdr;
+ BD_ADDR remote_bda;
+ tBTA_GATTC_IF client_if;
+ BOOLEAN is_direct;
+} tBTA_GATTC_API_OPEN;
+
+typedef tBTA_GATTC_API_OPEN tBTA_GATTC_API_CANCEL_OPEN;
+
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_GATT_AUTH_REQ auth_req;
+ tBTA_GATT_SRVC_ID srvc_id;
+ tBTA_GATT_ID char_id;
+ tBT_UUID descr_type;
+} tBTA_GATTC_API_READ;
+
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_GATT_AUTH_REQ auth_req;
+ tBTA_GATT_SRVC_ID srvc_id;
+ tBTA_GATT_ID char_id;
+ tBT_UUID descr_type;
+ tBTA_GATTC_WRITE_TYPE write_type;
+ UINT16 offset;
+ UINT16 len;
+ UINT8 *p_value;
+}tBTA_GATTC_API_WRITE;
+
+typedef struct
+{
+ BT_HDR hdr;
+ BOOLEAN is_execute;
+}tBTA_GATTC_API_EXEC;
+
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_GATT_SRVC_ID srvc_id;
+ tBTA_GATT_ID char_id;
+} tBTA_GATTC_API_CONFIRM;
+
+typedef tGATT_CL_COMPLETE tBTA_GATTC_CMPL;
+
+typedef struct
+{
+ BT_HDR hdr;
+ UINT8 op_code;
+ tGATT_STATUS status;
+ tBTA_GATTC_CMPL *p_cmpl;
+}tBTA_GATTC_OP_CMPL;
+
+typedef struct
+{
+ BT_HDR hdr;
+ tBT_UUID srvc_uuid;
+}tBTA_GATTC_API_SEARCH;
+
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_GATT_AUTH_REQ auth_req;
+ UINT8 num_attr;
+ tBTA_GATTC_ATTR_ID *p_id_list;
+}tBTA_GATTC_API_READ_MULTI;
+
+typedef union
+{
+ BT_HDR hdr;
+ tBTA_GATTC_API_REG api_reg;
+ tBTA_GATTC_API_DEREG api_dereg;
+ tBTA_GATTC_API_OPEN api_conn;
+ tBTA_GATTC_API_CANCEL_OPEN api_cancel_conn;
+ tBTA_GATTC_API_READ api_read;
+ tBTA_GATTC_API_SEARCH api_search;
+ tBTA_GATTC_API_WRITE api_write;
+ tBTA_GATTC_API_CONFIRM api_confirm;
+ tBTA_GATTC_API_EXEC api_exec;
+ tBTA_GATTC_API_READ_MULTI api_read_multi;
+ tBTA_GATTC_OP_CMPL op_cmpl;
+ tBTA_GATTC_CI_EVT ci_open;
+ tBTA_GATTC_CI_EVT ci_save;
+ tBTA_GATTC_CI_LOAD ci_load;
+
+ tBTA_GATTC_INT_START_IF int_start_if;
+ tBTA_GATTC_INT_DEREG int_dereg;
+
+} tBTA_GATTC_DATA;
+
+
+/* GATT server cache on the client */
+typedef union
+{
+ UINT8 uuid128[LEN_UUID_128];
+ UINT16 uuid16;
+}tBTA_GATTC_UUID;
+
+typedef struct gattc_attr_cache
+{
+ tBTA_GATTC_UUID *p_uuid;
+ struct gattc_attr_cache *p_next;
+ UINT16 uuid_len;
+ UINT16 attr_handle;
+ UINT8 inst_id;
+ tBTA_GATT_CHAR_PROP property; /* if characteristic, it is char property;
+ if included service, flag primary,
+ if descriptor, not used */
+ tBTA_GATTC_ATTR_TYPE attr_type;
+// btla-specific ++
+} __attribute__((packed)) tBTA_GATTC_CACHE_ATTR;
+// btla-specific --
+
+typedef struct gattc_svc_cache
+{
+ tBTA_GATT_SRVC_ID service_uuid;
+ tBTA_GATTC_CACHE_ATTR *p_attr;
+ tBTA_GATTC_CACHE_ATTR *p_last_attr;
+ UINT16 s_handle;
+ UINT16 e_handle;
+ struct gattc_svc_cache *p_next;
+// btla-specific ++
+} __attribute__((packed)) tBTA_GATTC_CACHE;
+// btla-specific --
+
+typedef struct
+{
+ tBT_UUID uuid;
+ UINT16 s_handle;
+ UINT16 e_handle;
+ BOOLEAN is_primary;
+ UINT8 srvc_inst_id;
+ tBTA_GATT_CHAR_PROP property;
+}tBTA_GATTC_ATTR_REC;
+
+
+#define BTA_GATTC_MAX_CACHE_CHAR 40
+#define BTA_GATTC_ATTR_LIST_SIZE (BTA_GATTC_MAX_CACHE_CHAR * sizeof(tBTA_GATTC_ATTR_REC))
+
+#ifndef BTA_GATTC_CACHE_SRVR_SIZE
+ #define BTA_GATTC_CACHE_SRVR_SIZE 600
+#endif
+
+enum
+{
+ BTA_GATTC_IDLE_ST = 0, /* Idle */
+ BTA_GATTC_W4_CONN_ST, /* Wait for connection - (optional) */
+ BTA_GATTC_CONN_ST, /* connected state */
+ BTA_GATTC_DISCOVER_ST /* discover is in progress */
+};
+typedef UINT8 tBTA_GATTC_STATE;
+
+typedef struct
+{
+ BOOLEAN in_use;
+ BD_ADDR server_bda;
+ BOOLEAN connected;
+
+#define BTA_GATTC_SERV_IDLE 0
+#define BTA_GATTC_SERV_LOAD 1
+#define BTA_GATTC_SERV_SAVE 2
+
+ UINT8 state;
+
+ tBTA_GATTC_CACHE *p_srvc_cache;
+ tBTA_GATTC_CACHE *p_cur_srvc;
+ BUFFER_Q cache_buffer; /* buffer queue used for storing the cache data */
+ UINT8 *p_free; /* starting point to next available byte */
+ UINT16 free_byte; /* number of available bytes in server cache buffer */
+ UINT8 update_count; /* indication received */
+ UINT8 num_clcb; /* number of associated CLCB */
+
+
+ tBTA_GATTC_ATTR_REC *p_srvc_list;
+ UINT8 cur_srvc_idx;
+ UINT8 cur_char_idx;
+ UINT8 next_avail_idx;
+ UINT8 total_srvc;
+ UINT8 total_char;
+
+ UINT8 srvc_hdl_chg; /* service handle change indication pending */
+ UINT16 attr_index; /* cahce NV saving/loading attribute index */
+
+} tBTA_GATTC_SERV;
+
+#ifndef BTA_GATTC_NOTIF_REG_MAX
+#define BTA_GATTC_NOTIF_REG_MAX 4
+#endif
+
+typedef struct
+{
+ BOOLEAN in_use;
+ BD_ADDR remote_bda;
+ tBTA_GATTC_CHAR_ID char_id;
+}tBTA_GATTC_NOTIF_REG;
+
+typedef struct
+{
+ tBTA_GATTC_CBACK *p_cback;
+ BOOLEAN in_use;
+ tBTA_GATTC_IF client_if; /* client interface with BTE stack for this application */
+ UINT8 num_clcb; /* number of associated CLCB */
+ BOOLEAN dereg_pending;
+ tBT_UUID app_uuid;
+ tBTA_GATTC_NOTIF_REG notif_reg[BTA_GATTC_NOTIF_REG_MAX];
+}tBTA_GATTC_RCB;
+
+/* client channel is a mapping between a BTA client(cl_id) and a remote BD address */
+typedef struct
+{
+ UINT16 bta_conn_id; /* client channel ID, unique for clcb */
+ BD_ADDR bda;
+ tBTA_GATTC_RCB *p_rcb; /* pointer to the registration CB */
+ tBTA_GATTC_SERV *p_srcb; /* server cache CB */
+ tBTA_GATTC_DATA *p_q_cmd; /* command in queue waiting for execution */
+
+#define BTA_GATTC_NO_SCHEDULE 0
+#define BTA_GATTC_DISC_WAITING 0x01
+#define BTA_GATTC_REQ_WAITING 0x10
+
+ UINT8 auto_update; /* auto update is waiting */
+ BOOLEAN in_use;
+ tBTA_GATTC_STATE state;
+ tBTA_GATT_STATUS status;
+ UINT16 reason;
+} tBTA_GATTC_CLCB;
+
+/* back ground connection tracking information */
+#if GATT_MAX_APPS <= 8
+typedef UINT8 tBTA_GATTC_CIF_MASK ;
+#elif GATT_MAX_APPS <= 16
+typedef UINT16 tBTA_GATTC_CIF_MASK;
+#elif GATT_MAX_APPS <= 32
+typedef UINT32 tBTA_GATTC_CIF_MASK;
+#endif
+
+typedef struct
+{
+ BOOLEAN in_use;
+ BD_ADDR remote_bda;
+ tBTA_GATTC_CIF_MASK cif_mask;
+
+}tBTA_GATTC_BG_TCK;
+
+typedef struct
+{
+ tBTA_GATTC_BG_TCK bg_track[BTA_GATTC_KNOWN_SR_MAX];
+ tBTA_GATTC_RCB cl_rcb[BTA_GATTC_CL_MAX];
+
+ tBTA_GATTC_CLCB clcb[BTA_GATTC_CLCB_MAX];
+ tBTA_GATTC_SERV known_server[BTA_GATTC_KNOWN_SR_MAX];
+
+ tSDP_DISCOVERY_DB *p_sdp_db;
+ UINT16 sdp_conn_id;
+}tBTA_GATTC_CB;
+
+/*****************************************************************************
+** Global data
+*****************************************************************************/
+
+/* GATTC control block */
+#if BTA_DYNAMIC_MEMORY == FALSE
+extern tBTA_GATTC_CB bta_gattc_cb;
+#else
+extern tBTA_GATTC_CB *bta_gattc_cb_ptr;
+#define bta_gattc_cb (*bta_gattc_cb_ptr)
+#endif
+
+/*****************************************************************************
+** Function prototypes
+*****************************************************************************/
+extern BOOLEAN bta_gattc_hdl_event(BT_HDR *p_msg);
+extern void bta_gattc_sm_execute(tBTA_GATTC_CLCB *p_clcb, UINT16 event, tBTA_GATTC_DATA *p_data);
+
+/* function processed outside SM */
+extern void bta_gattc_register(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_data);
+extern void bta_gattc_start_if(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_data);
+extern void bta_gattc_process_api_open (tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA * p_msg);
+extern void bta_gattc_process_api_open_cancel (tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA * p_msg);
+extern void bta_gattc_deregister(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_data);
+extern void bta_gattc_int_deregister(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_data);
+
+/* function within state machine */
+extern void bta_gattc_open(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data);
+extern void bta_gattc_open_fail(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data);
+extern void bta_gattc_open_error(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data);
+
+extern void bta_gattc_cancel_open(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data);
+extern void bta_gattc_cancel_open_ok(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data);
+extern void bta_gattc_cancel_open_error(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data);
+
+extern void bta_gattc_conn(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data);
+
+extern void bta_gattc_close(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data);
+extern void bta_gattc_close_fail(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data);
+
+extern void bta_gattc_start_discover(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data);
+extern void bta_gattc_disc_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data);
+extern void bta_gattc_read(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data);
+extern void bta_gattc_write(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data);
+extern void bta_gattc_op_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data);
+extern void bta_gattc_q_cmd(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data);
+extern void bta_gattc_search(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data);
+extern void bta_gattc_fail(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data);
+extern void bta_gattc_confirm(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data);
+extern void bta_gattc_execute(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data);
+extern void bta_gattc_read_multi(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data);
+extern void bta_gattc_ci_open(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data);
+extern void bta_gattc_ci_load(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data);
+extern void bta_gattc_ci_close(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data);
+extern void bta_gattc_ci_save(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data);
+extern void bta_gattc_cache_open(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data);
+extern void bta_gattc_ignore_op_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data);
+extern void bta_gattc_init_bk_conn(tBTA_GATTC_API_OPEN *p_data, tBTA_GATTC_RCB *p_clreg);
+extern void bta_gattc_cancel_bk_conn(tBTA_GATTC_API_CANCEL_OPEN *p_data);
+extern void bta_gattc_send_open_cback( tBTA_GATTC_RCB *p_clreg, tBTA_GATT_STATUS status,
+ BD_ADDR remote_bda, UINT16 conn_id);
+
+/* utility functions */
+extern tBTA_GATTC_CLCB * bta_gattc_find_clcb_by_cif (UINT8 client_if, BD_ADDR remote_bda); //todo
+extern tBTA_GATTC_CLCB * bta_gattc_find_clcb_by_conn_id (UINT16 conn_id);
+extern tBTA_GATTC_CLCB * bta_gattc_clcb_alloc(tBTA_GATTC_IF client_if, BD_ADDR remote_bda);
+extern void bta_gattc_clcb_dealloc(tBTA_GATTC_CLCB *p_clcb);
+extern tBTA_GATTC_CLCB * bta_gattc_find_alloc_clcb(tBTA_GATTC_IF client_if, BD_ADDR remote_bda);
+extern tBTA_GATTC_RCB * bta_gattc_cl_get_regcb(UINT8 client_if);
+extern tBTA_GATTC_SERV * bta_gattc_find_srcb(BD_ADDR bda);
+extern tBTA_GATTC_SERV * bta_gattc_srcb_alloc(BD_ADDR bda);
+extern tBTA_GATTC_SERV * bta_gattc_find_scb_by_cid (UINT16 conn_id);
+extern BOOLEAN bta_gattc_enqueue(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data);
+
+extern UINT16 bta_gattc_id2handle(tBTA_GATTC_SERV *p_srcb, tBTA_GATT_SRVC_ID *p_service_id, tBTA_GATT_ID *p_char_id, tBT_UUID descr_uuid);
+extern BOOLEAN bta_gattc_handle2id(tBTA_GATTC_SERV *p_srcb, UINT16 handle, tBTA_GATT_SRVC_ID *service_id, tBTA_GATT_ID *char_id, tBT_UUID *p_type);
+extern BOOLEAN bta_gattc_uuid_compare (tBT_UUID src, tBT_UUID tar, BOOLEAN is_precise);
+extern void bta_gattc_pack_attr_uuid(tBTA_GATTC_CACHE_ATTR *p_attr, tBT_UUID *p_uuid);
+extern BOOLEAN bta_gattc_check_notif_registry(tBTA_GATTC_RCB *p_clreg, tBTA_GATTC_SERV *p_srcb, tBTA_GATTC_NOTIFY *p_notify);
+extern tBTA_GATT_STATUS bta_gattc_pack_read_cb_data(tBTA_GATTC_SERV *p_srcb, tBT_UUID descr_uuid, tGATT_VALUE *p_attr, tBTA_GATT_READ_VAL *p_value);
+extern BOOLEAN bta_gattc_mark_bg_conn (tBTA_GATTC_IF client_if, BD_ADDR remote_bda, BOOLEAN add);
+extern BOOLEAN bta_gattc_check_bg_conn (tBTA_GATTC_IF client_if, BD_ADDR remote_bda);
+extern UINT8 bta_gattc_num_reg_app(void);
+extern void bta_gattc_clear_notif_registration(UINT16 conn_id);
+
+/* discovery functions */
+extern void bta_gattc_disc_res_cback (UINT16 conn_id, tGATT_DISC_TYPE disc_type, tGATT_DISC_RES *p_data);
+extern void bta_gattc_disc_cmpl_cback (UINT16 conn_id, tGATT_DISC_TYPE disc_type, tGATT_STATUS status);
+extern tBTA_GATT_STATUS bta_gattc_discover_procedure(UINT16 conn_id, tBTA_GATTC_SERV *p_server_cb, UINT8 disc_type);
+extern tBTA_GATT_STATUS bta_gattc_discover_pri_service(UINT16 conn_id, tBTA_GATTC_SERV *p_server_cb, UINT8 disc_type);
+extern void bta_gattc_search_service(tBTA_GATTC_CLCB *p_clcb, tBT_UUID uuid);
+extern tBTA_GATT_STATUS bta_gattc_query_cache(UINT16 conn_id, UINT8 query_type, tBTA_GATT_SRVC_ID *p_srvc_id,
+ tBTA_GATT_ID *p_start_rec,tBT_UUID *p_uuid_cond,
+ tBTA_GATT_ID *p_output, void *p_property);
+extern tBTA_GATT_STATUS bta_gattc_init_cache(tBTA_GATTC_SERV *p_srvc_cb);
+extern void bta_gattc_rebuild_cache(tBTA_GATTC_SERV *p_srcv, UINT16 num_attr, tBTA_GATTC_NV_ATTR *p_attr, UINT16 attr_index);
+extern BOOLEAN bta_gattc_cache_save(tBTA_GATTC_SERV *p_srvc_cb, UINT16 conn_id);
+
+#endif /* BTA_GATTC_INT_H */
diff --git a/bta/gatt/bta_gattc_main.c b/bta/gatt/bta_gattc_main.c
new file mode 100644
index 0000000..5016c46
--- /dev/null
+++ b/bta/gatt/bta_gattc_main.c
@@ -0,0 +1,474 @@
+/*****************************************************************************
+**
+** Name: bta_gattc_main.c
+**
+** Description: This file contains the GATT client main functions
+** and state machine.
+**
+** Copyright (c) 2003-2009, Broadcom Corp., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+
+#if defined(BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE)
+
+#include <string.h>
+
+#include "bta_gattc_int.h"
+#include "gki.h"
+
+
+/*****************************************************************************
+** Constants and types
+*****************************************************************************/
+
+
+/* state machine action enumeration list */
+enum
+{
+ BTA_GATTC_OPEN,
+ BTA_GATTC_OPEN_FAIL,
+ //BTA_GATTC_OPEN_FAIL_IN_CONN, //<--- need to remove this?
+ BTA_GATTC_OPEN_ERROR,
+ BTA_GATTC_CANCEL_OPEN,
+ BTA_GATTC_CANCEL_OPEN_OK,
+ BTA_GATTC_CANCEL_OPEN_ERROR,
+ BTA_GATTC_CONN,
+ BTA_GATTC_START_DISCOVER,
+ BTA_GATTC_DISC_CMPL,
+
+ BTA_GATTC_Q_CMD,
+ BTA_GATTC_CLOSE,
+ BTA_GATTC_CLOSE_FAIL,
+ BTA_GATTC_READ,
+ BTA_GATTC_WRITE,
+
+ BTA_GATTC_OP_CMPL,
+ BTA_GATTC_SEARCH,
+ BTA_GATTC_FAIL,
+ BTA_GATTC_CONFIRM,
+ BTA_GATTC_EXEC,
+ BTA_GATTC_READ_MULTI,
+ BTA_GATTC_CI_OPEN,
+ BTA_GATTC_CI_LOAD,
+ BTA_GATTC_CI_SAVE,
+ BTA_GATTC_CACHE_OPEN,
+ BTA_GATTC_IGNORE_OP_CMPL,
+
+ BTA_GATTC_IGNORE
+};
+/* type for action functions */
+typedef void (*tBTA_GATTC_ACTION)(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data);
+
+/* action function list */
+const tBTA_GATTC_ACTION bta_gattc_action[] =
+{
+ bta_gattc_open,
+ bta_gattc_open_fail,
+ //bta_gattc_open_fail_in_conn, //<--- need to remove this?
+ bta_gattc_open_error,
+ bta_gattc_cancel_open,
+ bta_gattc_cancel_open_ok,
+ bta_gattc_cancel_open_error,
+ bta_gattc_conn,
+ bta_gattc_start_discover,
+ bta_gattc_disc_cmpl,
+
+ bta_gattc_q_cmd,
+ bta_gattc_close,
+ bta_gattc_close_fail,
+ bta_gattc_read,
+ bta_gattc_write,
+
+ bta_gattc_op_cmpl,
+ bta_gattc_search,
+ bta_gattc_fail,
+ bta_gattc_confirm,
+ bta_gattc_execute,
+ bta_gattc_read_multi,
+ bta_gattc_ci_open,
+ bta_gattc_ci_load,
+ bta_gattc_ci_save,
+ bta_gattc_cache_open,
+ bta_gattc_ignore_op_cmpl
+};
+
+
+/* state table information */
+#define BTA_GATTC_ACTIONS 1 /* number of actions */
+#define BTA_GATTC_NEXT_STATE 1 /* position of next state */
+#define BTA_GATTC_NUM_COLS 2 /* number of columns in state tables */
+
+/* state table for idle state */
+static const UINT8 bta_gattc_st_idle[][BTA_GATTC_NUM_COLS] =
+{
+/* Event Action 1 Next state */
+/* BTA_GATTC_API_OPEN_EVT */ {BTA_GATTC_OPEN, BTA_GATTC_W4_CONN_ST},
+/* BTA_GATTC_INT_OPEN_FAIL_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_IDLE_ST},
+/* BTA_GATTC_API_CANCEL_OPEN_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_IDLE_ST},
+/* BTA_GATTC_INT_CANCEL_OPEN_OK_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_IDLE_ST},
+
+/* BTA_GATTC_API_READ_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_IDLE_ST},
+/* BTA_GATTC_API_WRITE_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_IDLE_ST},
+/* BTA_GATTC_API_EXEC_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_IDLE_ST},
+
+/* BTA_GATTC_API_CLOSE_EVT */ {BTA_GATTC_CLOSE_FAIL, BTA_GATTC_IDLE_ST},
+
+/* BTA_GATTC_API_SEARCH_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_IDLE_ST},
+/* BTA_GATTC_API_CONFIRM_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_IDLE_ST},
+/* BTA_GATTC_API_READ_MULTI_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_IDLE_ST},
+/* BTA_GATTC_INT_CONN_EVT */ {BTA_GATTC_CONN, BTA_GATTC_CONN_ST},
+/* BTA_GATTC_INT_DISCOVER_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_IDLE_ST},
+/* BTA_GATTC_DISCOVER_CMPL_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_IDLE_ST},
+/* BTA_GATTC_OP_CMPL_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_IDLE_ST},
+/* BTA_GATTC_INT_DISCONN_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_IDLE_ST},
+
+
+/* ===> for cache loading, saving */
+/* BTA_GATTC_START_CACHE_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_IDLE_ST},
+/* BTA_GATTC_CI_CACHE_OPEN_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_IDLE_ST},
+/* BTA_GATTC_CI_CACHE_LOAD_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_IDLE_ST},
+/* BTA_GATTC_CI_CACHE_SAVE_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_IDLE_ST}
+};
+
+/* state table for wait for open state */
+static const UINT8 bta_gattc_st_w4_conn[][BTA_GATTC_NUM_COLS] =
+{
+/* Event Action 1 Next state */
+/* BTA_GATTC_API_OPEN_EVT */ {BTA_GATTC_OPEN, BTA_GATTC_W4_CONN_ST},
+/* BTA_GATTC_INT_OPEN_FAIL_EVT */ {BTA_GATTC_OPEN_FAIL, BTA_GATTC_IDLE_ST},
+/* BTA_GATTC_API_CANCEL_OPEN_EVT */ {BTA_GATTC_CANCEL_OPEN, BTA_GATTC_W4_CONN_ST},
+/* BTA_GATTC_INT_CANCEL_OPEN_OK_EVT */ {BTA_GATTC_CANCEL_OPEN_OK, BTA_GATTC_IDLE_ST},
+
+/* BTA_GATTC_API_READ_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_W4_CONN_ST},
+/* BTA_GATTC_API_WRITE_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_W4_CONN_ST},
+/* BTA_GATTC_API_EXEC_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_W4_CONN_ST},
+
+/* BTA_GATTC_API_CLOSE_EVT */ {BTA_GATTC_CLOSE_FAIL, BTA_GATTC_W4_CONN_ST},
+
+/* BTA_GATTC_API_SEARCH_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_W4_CONN_ST},
+/* BTA_GATTC_API_CONFIRM_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_W4_CONN_ST},
+/* BTA_GATTC_API_READ_MULTI_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_W4_CONN_ST},
+
+/* BTA_GATTC_INT_CONN_EVT */ {BTA_GATTC_CONN, BTA_GATTC_CONN_ST},
+/* BTA_GATTC_INT_DISCOVER_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_W4_CONN_ST},
+/* BTA_GATTC_DISCOVER_CMPL_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_W4_CONN_ST},
+/* BTA_GATTC_OP_CMPL_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_W4_CONN_ST},
+/* BTA_GATTC_INT_DISCONN_EVT */ {BTA_GATTC_CLOSE, BTA_GATTC_IDLE_ST},
+
+/* ===> for cache loading, saving */
+/* BTA_GATTC_START_CACHE_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_W4_CONN_ST},
+/* BTA_GATTC_CI_CACHE_OPEN_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_W4_CONN_ST},
+/* BTA_GATTC_CI_CACHE_LOAD_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_W4_CONN_ST},
+/* BTA_GATTC_CI_CACHE_SAVE_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_W4_CONN_ST}
+};
+
+/* state table for open state */
+static const UINT8 bta_gattc_st_connected[][BTA_GATTC_NUM_COLS] =
+{
+/* Event Action 1 Next state */
+/* BTA_GATTC_API_OPEN_EVT */ {BTA_GATTC_OPEN_ERROR, BTA_GATTC_CONN_ST},
+/* BTA_GATTC_INT_OPEN_FAIL_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_CONN_ST},
+/* BTA_GATTC_API_CANCEL_OPEN_EVT */ {BTA_GATTC_CANCEL_OPEN_ERROR, BTA_GATTC_CONN_ST},
+/* BTA_GATTC_INT_CANCEL_OPEN_OK_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_CONN_ST},
+
+/* BTA_GATTC_API_READ_EVT */ {BTA_GATTC_READ, BTA_GATTC_CONN_ST},
+/* BTA_GATTC_API_WRITE_EVT */ {BTA_GATTC_WRITE, BTA_GATTC_CONN_ST},
+/* BTA_GATTC_API_EXEC_EVT */ {BTA_GATTC_EXEC, BTA_GATTC_CONN_ST},
+
+/* BTA_GATTC_API_CLOSE_EVT */ {BTA_GATTC_CLOSE, BTA_GATTC_IDLE_ST}, //BTA_GATTC_CLOSING_ST
+
+/* BTA_GATTC_API_SEARCH_EVT */ {BTA_GATTC_SEARCH, BTA_GATTC_CONN_ST},
+/* BTA_GATTC_API_CONFIRM_EVT */ {BTA_GATTC_CONFIRM, BTA_GATTC_CONN_ST},
+/* BTA_GATTC_API_READ_MULTI_EVT */ {BTA_GATTC_READ_MULTI, BTA_GATTC_CONN_ST},
+/* BTA_GATTC_INT_CONN_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_CONN_ST},
+/* BTA_GATTC_INT_DISCOVER_EVT */ {BTA_GATTC_START_DISCOVER, BTA_GATTC_DISCOVER_ST},
+/* BTA_GATTC_DISCOVER_CMPL_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_CONN_ST},
+/* BTA_GATTC_OP_CMPL_EVT */ {BTA_GATTC_OP_CMPL, BTA_GATTC_CONN_ST},
+
+/* BTA_GATTC_INT_DISCONN_EVT */ {BTA_GATTC_CLOSE, BTA_GATTC_IDLE_ST},
+
+/* ===> for cache loading, saving */
+/* BTA_GATTC_START_CACHE_EVT */ {BTA_GATTC_CACHE_OPEN, BTA_GATTC_DISCOVER_ST},
+/* BTA_GATTC_CI_CACHE_OPEN_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_CONN_ST},
+/* BTA_GATTC_CI_CACHE_LOAD_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_CONN_ST},
+/* BTA_GATTC_CI_CACHE_SAVE_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_CONN_ST}
+};
+
+/* state table for discover state */
+static const UINT8 bta_gattc_st_discover[][BTA_GATTC_NUM_COLS] =
+{
+/* Event Action 1 Next state */
+/* BTA_GATTC_API_OPEN_EVT */ {BTA_GATTC_OPEN_ERROR, BTA_GATTC_DISCOVER_ST},
+/* BTA_GATTC_INT_OPEN_FAIL_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_DISCOVER_ST},
+/* BTA_GATTC_API_CANCEL_OPEN_EVT */ {BTA_GATTC_CANCEL_OPEN_ERROR, BTA_GATTC_DISCOVER_ST},
+/* BTA_GATTC_INT_CANCEL_OPEN_OK_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_DISCOVER_ST},
+
+/* BTA_GATTC_API_READ_EVT */ {BTA_GATTC_Q_CMD, BTA_GATTC_DISCOVER_ST},
+/* BTA_GATTC_API_WRITE_EVT */ {BTA_GATTC_Q_CMD, BTA_GATTC_DISCOVER_ST},
+/* BTA_GATTC_API_EXEC_EVT */ {BTA_GATTC_Q_CMD, BTA_GATTC_DISCOVER_ST},
+
+/* BTA_GATTC_API_CLOSE_EVT */ {BTA_GATTC_CLOSE, BTA_GATTC_IDLE_ST }, //BTA_GATTC_CLOSING_ST
+
+/* BTA_GATTC_API_SEARCH_EVT */ {BTA_GATTC_Q_CMD, BTA_GATTC_DISCOVER_ST},
+/* BTA_GATTC_API_CONFIRM_EVT */ {BTA_GATTC_CONFIRM, BTA_GATTC_DISCOVER_ST},
+/* BTA_GATTC_API_READ_MULTI_EVT */ {BTA_GATTC_Q_CMD, BTA_GATTC_DISCOVER_ST},
+/* BTA_GATTC_INT_CONN_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_DISCOVER_ST},
+/* BTA_GATTC_INT_DISCOVER_EVT */ {BTA_GATTC_START_DISCOVER, BTA_GATTC_DISCOVER_ST},
+/* BTA_GATTC_DISCOVER_CMPL_EVT */ {BTA_GATTC_DISC_CMPL, BTA_GATTC_CONN_ST},
+/* BTA_GATTC_OP_CMPL_EVT */ {BTA_GATTC_IGNORE_OP_CMPL, BTA_GATTC_DISCOVER_ST},
+/* BTA_GATTC_INT_DISCONN_EVT */ {BTA_GATTC_CLOSE, BTA_GATTC_IDLE_ST},
+
+/* ===> for cache loading, saving */
+/* BTA_GATTC_START_CACHE_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_DISCOVER_ST},
+/* BTA_GATTC_CI_CACHE_OPEN_EVT */ {BTA_GATTC_CI_OPEN, BTA_GATTC_DISCOVER_ST},
+/* BTA_GATTC_CI_CACHE_LOAD_EVT */ {BTA_GATTC_CI_LOAD, BTA_GATTC_DISCOVER_ST},
+/* BTA_GATTC_CI_CACHE_SAVE_EVT */ {BTA_GATTC_CI_SAVE, BTA_GATTC_DISCOVER_ST}
+};
+
+/* type for state table */
+typedef const UINT8 (*tBTA_GATTC_ST_TBL)[BTA_GATTC_NUM_COLS];
+
+/* state table */
+const tBTA_GATTC_ST_TBL bta_gattc_st_tbl[] =
+{
+ bta_gattc_st_idle,
+ bta_gattc_st_w4_conn,
+ bta_gattc_st_connected,
+ bta_gattc_st_discover
+};
+
+/*****************************************************************************
+** Global data
+*****************************************************************************/
+
+/* GATTC control block */
+#if BTA_DYNAMIC_MEMORY == FALSE
+tBTA_GATTC_CB bta_gattc_cb;
+#endif
+
+#if BTA_GATT_DEBUG == TRUE
+static char *gattc_evt_code(tBTA_GATTC_INT_EVT evt_code);
+static char *gattc_state_code(tBTA_GATTC_STATE state_code);
+#endif
+
+/*******************************************************************************
+**
+** Function bta_gattc_sm_execute
+**
+** Description State machine event handling function for GATTC
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_gattc_sm_execute(tBTA_GATTC_CLCB *p_clcb, UINT16 event, tBTA_GATTC_DATA *p_data)
+{
+ tBTA_GATTC_ST_TBL state_table;
+ UINT8 action;
+ int i;
+#if BTA_GATT_DEBUG == TRUE
+ tBTA_GATTC_STATE in_state = p_clcb->state;
+ UINT16 in_event = event;
+ APPL_TRACE_DEBUG4("bta_gattc_sm_execute: State 0x%02x [%s], Event 0x%x[%s]", in_state,
+ gattc_state_code(in_state),
+ in_event,
+ gattc_evt_code(in_event));
+#endif
+
+
+ /* look up the state table for the current state */
+ state_table = bta_gattc_st_tbl[p_clcb->state];
+
+ event &= 0x00FF;
+
+ /* set next state */
+ p_clcb->state = state_table[event][BTA_GATTC_NEXT_STATE];
+
+ /* execute action functions */
+ for (i = 0; i < BTA_GATTC_ACTIONS; i++)
+ {
+ if ((action = state_table[event][i]) != BTA_GATTC_IGNORE)
+ {
+ (*bta_gattc_action[action])(p_clcb, p_data);
+ }
+ else
+ {
+ break;
+ }
+ }
+
+#if BTA_GATT_DEBUG == TRUE
+ if (in_state != p_clcb->state)
+ {
+ APPL_TRACE_DEBUG3("GATTC State Change: [%s] -> [%s] after Event [%s]",
+ gattc_state_code(in_state),
+ gattc_state_code(p_clcb->state),
+ gattc_evt_code(in_event));
+ }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function bta_gattc_hdl_event
+**
+** Description GATT client main event handling function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BOOLEAN bta_gattc_hdl_event(BT_HDR *p_msg)
+{
+ tBTA_GATTC_CB *p_cb = &bta_gattc_cb;
+ tBTA_GATTC_CLCB *p_clcb = NULL;
+
+#if BTA_GATT_DEBUG == TRUE
+ APPL_TRACE_DEBUG1("bta_gattc_hdl_event: Event [%s]", gattc_evt_code(p_msg->event));
+#endif
+ switch (p_msg->event)
+ {
+ case BTA_GATTC_API_REG_EVT:
+ bta_gattc_register(p_cb, (tBTA_GATTC_DATA *) p_msg);
+ break;
+
+ case BTA_GATTC_INT_START_IF_EVT:
+ bta_gattc_start_if(p_cb, (tBTA_GATTC_DATA *) p_msg);
+ break;
+
+ case BTA_GATTC_API_DEREG_EVT:
+ bta_gattc_deregister(p_cb, (tBTA_GATTC_DATA *) p_msg);
+ break;
+
+ case BTA_GATTC_INT_DEREG_EVT:
+ bta_gattc_int_deregister(p_cb, (tBTA_GATTC_DATA *) p_msg);
+ break;
+
+ case BTA_GATTC_API_OPEN_EVT:
+ bta_gattc_process_api_open(p_cb, (tBTA_GATTC_DATA *) p_msg);
+ break;
+
+ case BTA_GATTC_API_CANCEL_OPEN_EVT:
+ bta_gattc_process_api_open_cancel(p_cb, (tBTA_GATTC_DATA *) p_msg);
+ break;
+
+ default:
+ if ((p_clcb = bta_gattc_find_clcb_by_conn_id(p_msg->layer_specific))
+ != NULL)
+ {
+ bta_gattc_sm_execute(p_clcb, p_msg->event, (tBTA_GATTC_DATA *) p_msg);
+ }
+ else
+ {
+ APPL_TRACE_ERROR1("Unknown conn ID: %d", p_msg->layer_specific);
+ }
+
+ break;
+ }
+
+
+ return(TRUE);
+}
+
+
+/*****************************************************************************
+** Debug Functions
+*****************************************************************************/
+#if BTA_GATT_DEBUG == TRUE
+
+/*******************************************************************************
+**
+** Function gattc_evt_code
+**
+** Description
+**
+** Returns void
+**
+*******************************************************************************/
+static char *gattc_evt_code(tBTA_GATTC_INT_EVT evt_code)
+{
+ switch (evt_code)
+ {
+ case BTA_GATTC_API_OPEN_EVT:
+ return "BTA_GATTC_API_OPEN_EVT";
+ case BTA_GATTC_INT_OPEN_FAIL_EVT:
+ return "BTA_GATTC_INT_OPEN_FAIL_EVT";
+ case BTA_GATTC_API_CANCEL_OPEN_EVT:
+ return "BTA_GATTC_API_CANCEL_OPEN_EVT";
+ case BTA_GATTC_INT_CANCEL_OPEN_OK_EVT:
+ return "BTA_GATTC_INT_CANCEL_OPEN_OK_EVT";
+ case BTA_GATTC_API_READ_EVT:
+ return "BTA_GATTC_API_READ_EVT";
+ case BTA_GATTC_API_WRITE_EVT:
+ return "BTA_GATTC_API_WRITE_EVT";
+ case BTA_GATTC_API_EXEC_EVT:
+ return "BTA_GATTC_API_EXEC_EVT";
+ case BTA_GATTC_API_CLOSE_EVT:
+ return "BTA_GATTC_API_CLOSE_EVT";
+ case BTA_GATTC_API_SEARCH_EVT:
+ return "BTA_GATTC_API_SEARCH_EVT";
+ case BTA_GATTC_API_CONFIRM_EVT:
+ return "BTA_GATTC_API_CONFIRM_EVT";
+ case BTA_GATTC_API_READ_MULTI_EVT:
+ return "BTA_GATTC_API_READ_MULTI_EVT";
+ case BTA_GATTC_INT_CONN_EVT:
+ return "BTA_GATTC_INT_CONN_EVT";
+ case BTA_GATTC_INT_DISCOVER_EVT:
+ return "BTA_GATTC_INT_DISCOVER_EVT";
+ case BTA_GATTC_DISCOVER_CMPL_EVT:
+ return "BTA_GATTC_DISCOVER_CMPL_EVT";
+ case BTA_GATTC_OP_CMPL_EVT:
+ return "BTA_GATTC_OP_CMPL_EVT";
+ case BTA_GATTC_INT_DISCONN_EVT:
+ return "BTA_GATTC_INT_DISCONN_EVT";
+ case BTA_GATTC_START_CACHE_EVT:
+ return "BTA_GATTC_START_CACHE_EVT";
+ case BTA_GATTC_CI_CACHE_OPEN_EVT:
+ return "BTA_GATTC_CI_CACHE_OPEN_EVT";
+ case BTA_GATTC_CI_CACHE_LOAD_EVT:
+ return "BTA_GATTC_CI_CACHE_LOAD_EVT";
+ case BTA_GATTC_CI_CACHE_SAVE_EVT:
+ return "BTA_GATTC_CI_CACHE_SAVE_EVT";
+ case BTA_GATTC_INT_START_IF_EVT:
+ return "BTA_GATTC_INT_START_IF_EVT";
+ case BTA_GATTC_API_REG_EVT:
+ return "BTA_GATTC_API_REG_EVT";
+ case BTA_GATTC_API_DEREG_EVT:
+ return "BTA_GATTC_API_DEREG_EVT";
+
+ default:
+ return "unknown GATTC event code";
+ }
+}
+
+/*******************************************************************************
+**
+** Function gattc_state_code
+**
+** Description
+**
+** Returns void
+**
+*******************************************************************************/
+static char *gattc_state_code(tBTA_GATTC_STATE state_code)
+{
+ switch (state_code)
+ {
+ case BTA_GATTC_IDLE_ST:
+ return "GATTC_IDLE_ST";
+ case BTA_GATTC_W4_CONN_ST:
+ return "GATTC_W4_CONN_ST";
+ case BTA_GATTC_CONN_ST:
+ return "GATTC_CONN_ST";
+ case BTA_GATTC_DISCOVER_ST:
+ return "GATTC_DISCOVER_ST";
+ default:
+ return "unknown GATTC state code";
+ }
+}
+
+#endif /* Debug Functions */
+#endif /* BTA_GATT_INCLUDED */
diff --git a/bta/gatt/bta_gattc_utils.c b/bta/gatt/bta_gattc_utils.c
new file mode 100644
index 0000000..227129c
--- /dev/null
+++ b/bta/gatt/bta_gattc_utils.c
@@ -0,0 +1,652 @@
+/*****************************************************************************
+**
+** Name: bta_gattc_utils.c
+**
+** Description: This file contains the GATT client utility
+** function.
+**
+** Copyright (c) 2003-2010, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+
+#if defined(BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE)
+
+#include <string.h>
+#include "utl.h"
+#include "gki.h"
+#include "bta_sys.h"
+#include "bta_gattc_int.h"
+#include "bd.h"
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+
+static const UINT8 base_uuid[LEN_UUID_128] = {0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+/*******************************************************************************
+**
+** Function bta_gatt_convert_uuid16_to_uuid128
+**
+** Description Convert a 16 bits UUID to be an standard 128 bits one.
+**
+** Returns TRUE if two uuid match; FALSE otherwise.
+**
+*******************************************************************************/
+void bta_gatt_convert_uuid16_to_uuid128(UINT8 uuid_128[LEN_UUID_128], UINT16 uuid_16)
+{
+ UINT8 *p = &uuid_128[LEN_UUID_128 - 4];
+
+ memcpy (uuid_128, base_uuid, LEN_UUID_128);
+
+ UINT16_TO_STREAM(p, uuid_16);
+}
+/*******************************************************************************
+**
+** Function bta_gattc_uuid_compare
+**
+** Description Compare two UUID to see if they are the same.
+**
+** Returns TRUE if two uuid match; FALSE otherwise.
+**
+*******************************************************************************/
+BOOLEAN bta_gattc_uuid_compare (tBT_UUID src, tBT_UUID tar, BOOLEAN is_precise)
+{
+ UINT8 su[LEN_UUID_128], tu[LEN_UUID_128];
+ UINT8 *ps, *pt;
+
+ /* any of the UUID is unspecified */
+ if (src.len == 0 || tar.len == 0)
+ {
+ if (is_precise)
+ return FALSE;
+ else
+ return TRUE;
+ }
+
+ /* If both are 16-bit, we can do a simple compare */
+ if (src.len == 2 && tar.len == 2)
+ {
+ return src.uu.uuid16 == tar.uu.uuid16;
+ }
+
+ /* One or both of the UUIDs is 128-bit */
+ if (src.len == LEN_UUID_16)
+ {
+ /* convert a 16 bits UUID to 128 bits value */
+ bta_gatt_convert_uuid16_to_uuid128(su, src.uu.uuid16);
+ ps = su;
+ }
+ else
+ ps = src.uu.uuid128;
+
+ if (tar.len == LEN_UUID_16)
+ {
+ /* convert a 16 bits UUID to 128 bits value */
+ bta_gatt_convert_uuid16_to_uuid128(tu, tar.uu.uuid16);
+ pt = tu;
+ }
+ else
+ pt = tar.uu.uuid128;
+
+ return(memcmp(ps, pt, LEN_UUID_128) == 0);
+}
+
+/*******************************************************************************
+**
+** Function bta_gattc_cl_get_regcb
+**
+** Description get registration control block by client interface.
+**
+** Returns pointer to the regcb
+**
+*******************************************************************************/
+tBTA_GATTC_RCB * bta_gattc_cl_get_regcb(UINT8 client_if)
+{
+ UINT8 i = 0;
+ tBTA_GATTC_RCB *p_clrcb = &bta_gattc_cb.cl_rcb[0];
+
+ for (i = 0; i < BTA_GATTC_CL_MAX; i ++, p_clrcb ++)
+ {
+ if (p_clrcb->in_use &&
+ p_clrcb->client_if == client_if)
+ return p_clrcb;
+ }
+ return NULL;
+}
+/*******************************************************************************
+**
+** Function bta_gattc_num_reg_app
+**
+** Description find the number of registered application.
+**
+** Returns pointer to the regcb
+**
+*******************************************************************************/
+UINT8 bta_gattc_num_reg_app(void)
+{
+ UINT8 i = 0, j = 0;
+
+ for (i = 0; i < BTA_GATTC_CL_MAX; i ++)
+ {
+ if (bta_gattc_cb.cl_rcb[i].in_use)
+ j ++;
+ }
+ return j;
+}
+/*******************************************************************************
+**
+** Function bta_gattc_find_clcb_by_cif
+**
+** Description get clcb by client interface and remote bd adddress
+**
+** Returns pointer to the clcb
+**
+*******************************************************************************/
+tBTA_GATTC_CLCB * bta_gattc_find_clcb_by_cif (UINT8 client_if, BD_ADDR remote_bda)
+{
+ tBTA_GATTC_CLCB *p_clcb = &bta_gattc_cb.clcb[0];
+ UINT8 i;
+
+ for (i = 0; i < BTA_GATTC_CLCB_MAX; i ++, p_clcb ++)
+ {
+ if (p_clcb->in_use &&
+ p_clcb->p_rcb->client_if == client_if &&
+ p_clcb->p_srcb &&
+ bdcmp(p_clcb->p_srcb->server_bda, remote_bda) == 0)
+ return p_clcb;
+ }
+ return NULL;
+}
+/*******************************************************************************
+**
+** Function bta_gattc_find_clcb_by_conn_id
+**
+** Description get clcb by connection ID
+**
+** Returns pointer to the clcb
+**
+*******************************************************************************/
+tBTA_GATTC_CLCB * bta_gattc_find_clcb_by_conn_id (UINT16 conn_id)
+{
+ tBTA_GATTC_CLCB *p_clcb = &bta_gattc_cb.clcb[0];
+ UINT8 i;
+
+ for (i = 0; i < BTA_GATTC_CLCB_MAX; i ++, p_clcb ++)
+ {
+ if (p_clcb->in_use &&
+ p_clcb->bta_conn_id == conn_id)
+ return p_clcb;
+ }
+ return NULL;
+}
+
+/*******************************************************************************
+**
+** Function bta_gattc_clcb_alloc
+**
+** Description allocate CLCB
+**
+** Returns pointer to the clcb
+**
+*******************************************************************************/
+tBTA_GATTC_CLCB * bta_gattc_clcb_alloc(tBTA_GATTC_IF client_if, BD_ADDR remote_bda)
+{
+ UINT8 i_clcb = 0;
+ tBTA_GATTC_CLCB *p_clcb = NULL;
+
+ for (i_clcb = 0; i_clcb < BTA_GATTC_CLCB_MAX; i_clcb++)
+ {
+ if (!bta_gattc_cb.clcb[i_clcb].in_use)
+ {
+#if BTA_GATT_DEBUG == TRUE
+ APPL_TRACE_DEBUG1("bta_gattc_clcb_alloc: found clcb[%d] available",i_clcb);
+#endif
+ p_clcb = &bta_gattc_cb.clcb[i_clcb];
+ p_clcb->in_use = TRUE;
+ bdcpy(p_clcb->bda, remote_bda);
+
+ p_clcb->p_rcb = bta_gattc_cl_get_regcb(client_if);
+
+ if ((p_clcb->p_srcb = bta_gattc_find_srcb(remote_bda)) == NULL)
+ p_clcb->p_srcb = bta_gattc_srcb_alloc(remote_bda);
+
+ if (p_clcb->p_rcb != NULL && p_clcb->p_srcb != NULL)
+ {
+ p_clcb->p_srcb->num_clcb ++;
+ p_clcb->p_rcb->num_clcb ++;
+ }
+ else
+ {
+ /* release this clcb if clcb or srcb allocation failed */
+ p_clcb->in_use = FALSE;
+ p_clcb = NULL;
+ }
+ break;
+ }
+ }
+ return p_clcb;
+}
+/*******************************************************************************
+**
+** Function bta_gattc_find_alloc_clcb
+**
+** Description find or allocate CLCB if not found.
+**
+** Returns pointer to the clcb
+**
+*******************************************************************************/
+tBTA_GATTC_CLCB *bta_gattc_find_alloc_clcb(tBTA_GATTC_IF client_if, BD_ADDR remote_bda)
+{
+ tBTA_GATTC_CLCB *p_clcb ;
+
+ if ((p_clcb = bta_gattc_find_clcb_by_cif(client_if, remote_bda)) == NULL)
+ {
+ p_clcb = bta_gattc_clcb_alloc(client_if, remote_bda);
+ }
+ return p_clcb;
+}
+
+/*******************************************************************************
+**
+** Function bta_gattc_clcb_dealloc
+**
+** Description Deallocte a clcb
+**
+** Returns pointer to the clcb
+**
+*******************************************************************************/
+void bta_gattc_clcb_dealloc(tBTA_GATTC_CLCB *p_clcb)
+{
+
+ if (p_clcb)
+ {
+ if (p_clcb->p_srcb->num_clcb)
+ p_clcb->p_srcb->num_clcb --;
+
+ if (p_clcb->p_rcb->num_clcb)
+ p_clcb->p_rcb->num_clcb --;
+
+ utl_freebuf((void **)&p_clcb->p_q_cmd);
+
+ APPL_TRACE_ERROR2("bta_gattc_clcb_dealloc in_use=%d conn_id=%d",p_clcb->in_use, p_clcb->bta_conn_id);
+ memset(p_clcb, 0, sizeof(tBTA_GATTC_CLCB));
+ }
+ else
+ {
+ APPL_TRACE_ERROR0("bta_gattc_clcb_dealloc p_clcb=NULL");
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_gattc_find_srcb
+**
+** Description find server cache by remote bd address
+**
+** Returns pointer to the server cache.
+**
+*******************************************************************************/
+tBTA_GATTC_SERV * bta_gattc_find_srcb(BD_ADDR bda)
+{
+ tBTA_GATTC_SERV *p_srcb = &bta_gattc_cb.known_server[0];
+ UINT8 i;
+
+ for (i = 0; i < BTA_GATTC_KNOWN_SR_MAX; i ++, p_srcb ++)
+ {
+ if (p_srcb->in_use && bdcmp(p_srcb->server_bda, bda) == 0)
+ return p_srcb;
+ }
+ return NULL;
+}
+/*******************************************************************************
+**
+** Function bta_gattc_find_scb_by_cid
+**
+** Description find server control block by connection ID
+**
+** Returns pointer to the server cache.
+**
+*******************************************************************************/
+tBTA_GATTC_SERV * bta_gattc_find_scb_by_cid (UINT16 conn_id)
+{
+ tBTA_GATTC_CLCB *p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
+
+ if (p_clcb)
+ return p_clcb->p_srcb;
+ else
+ return NULL;
+}
+/*******************************************************************************
+**
+** Function bta_gattc_srcb_alloc
+**
+** Description allocate server cache control block
+**
+** Returns pointer to the server cache.
+**
+*******************************************************************************/
+tBTA_GATTC_SERV * bta_gattc_srcb_alloc(BD_ADDR bda)
+{
+ tBTA_GATTC_SERV *p_tcb = &bta_gattc_cb.known_server[0],
+ *p_recycle = NULL;
+ BOOLEAN found = FALSE;
+ UINT8 i;
+
+ for (i = 0; i < BTA_GATTC_KNOWN_SR_MAX; i ++, p_tcb ++)
+ {
+ if (!p_tcb->in_use)
+ {
+ found = TRUE;
+ break;
+ }
+ else if (!p_tcb->connected)
+ {
+ p_recycle = p_tcb;
+ }
+ }
+
+ /* if not found, try to recycle one known device */
+ if (!found && !p_recycle)
+ p_tcb = NULL;
+ else if (p_recycle)
+ p_tcb = p_recycle;
+
+ if (p_tcb != NULL)
+ {
+ while (p_tcb->cache_buffer.p_first)
+ GKI_freebuf (GKI_dequeue (&p_tcb->cache_buffer));
+
+ utl_freebuf((void **)&p_tcb->p_srvc_list);
+ memset(p_tcb, 0 , sizeof(tBTA_GATTC_SERV));
+
+ p_tcb->in_use = TRUE;
+ bdcpy(p_tcb->server_bda, bda);
+ }
+ return p_tcb;
+}
+/*******************************************************************************
+**
+** Function bta_gattc_enqueue
+**
+** Description enqueue a client request in clcb.
+**
+** Returns success or failure.
+**
+*******************************************************************************/
+BOOLEAN bta_gattc_enqueue(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
+{
+ BOOLEAN in_q = FALSE;
+
+ if (p_clcb->p_q_cmd == NULL)
+ {
+ p_clcb->p_q_cmd = (tBTA_GATTC_DATA *)GKI_getbuf(sizeof(tBTA_GATTC_DATA));
+
+ if (p_data)
+ memcpy(p_clcb->p_q_cmd, p_data, sizeof(tBTA_GATTC_DATA));
+
+ in_q = TRUE;
+ }
+ else
+ {
+ APPL_TRACE_ERROR0("already has a pending command!!");
+ /* skip the callback now. ----- need to send callback ? */
+ }
+ return in_q;
+}
+/*******************************************************************************
+**
+** Function bta_gattc_pack_attr_uuid
+**
+** Description pack UUID into a stream.
+**
+** Returns
+**
+*******************************************************************************/
+void bta_gattc_pack_attr_uuid(tBTA_GATTC_CACHE_ATTR *p_attr, tBT_UUID *p_uuid)
+{
+ UINT8 *pp = (UINT8 *)p_attr->p_uuid;
+
+ memset(p_uuid, 0, sizeof(tBT_UUID));
+
+ p_uuid->len = p_attr->uuid_len;
+
+ if (p_attr->uuid_len == LEN_UUID_16)
+ {
+ STREAM_TO_UINT16(p_uuid->uu.uuid16, pp);
+ }
+ else
+ {
+ memcpy(p_uuid->uu.uuid128, pp, LEN_UUID_128);
+ }
+
+ return;
+}
+/*******************************************************************************
+**
+** Function bta_gattc_check_notif_registry
+**
+** Description check if the service notificaition has been registered.
+**
+** Returns
+**
+*******************************************************************************/
+BOOLEAN bta_gattc_check_notif_registry(tBTA_GATTC_RCB *p_clreg, tBTA_GATTC_SERV *p_srcb,
+ tBTA_GATTC_NOTIFY *p_notify)
+{
+ UINT8 i;
+
+ for (i = 0 ; i < BTA_GATTC_NOTIF_REG_MAX; i ++)
+ {
+ if (p_clreg->notif_reg[i].in_use &&
+ bdcmp(p_clreg->notif_reg[i].remote_bda, p_srcb->server_bda) == 0 &&
+ (bta_gattc_uuid_compare(p_clreg->notif_reg[i].char_id.srvc_id.id.uuid, p_notify->char_id.srvc_id.id.uuid, FALSE) &&
+ p_clreg->notif_reg[i].char_id.srvc_id.id.inst_id == p_notify->char_id.srvc_id.id.inst_id &&
+ p_clreg->notif_reg[i].char_id.srvc_id.is_primary == p_notify->char_id.srvc_id.is_primary &&
+ bta_gattc_uuid_compare(p_clreg->notif_reg[i].char_id.char_id.uuid, p_notify->char_id.char_id.uuid, FALSE) &&
+ p_clreg->notif_reg[i].char_id.char_id.inst_id == p_notify->char_id.char_id.inst_id)
+ )
+ {
+ APPL_TRACE_DEBUG0("Notification registered!");
+ return TRUE;
+ }
+ }
+ return FALSE;
+
+}
+/*******************************************************************************
+**
+** Function bta_gattc_clear_notif_registration
+**
+** Description clear up the notification registration information by BD_ADDR.
+**
+** Returns None.
+**
+*******************************************************************************/
+void bta_gattc_clear_notif_registration(UINT16 conn_id)
+{
+ BD_ADDR remote_bda;
+ tBTA_GATTC_IF gatt_if;
+ tBTA_GATTC_RCB *p_clrcb ;
+ UINT8 i;
+
+ if (GATT_GetConnectionInfor(conn_id, &gatt_if, remote_bda))
+ {
+ if ((p_clrcb = bta_gattc_cl_get_regcb(gatt_if)) != NULL)
+ {
+ for (i = 0 ; i < BTA_GATTC_NOTIF_REG_MAX; i ++)
+ {
+ if (p_clrcb->notif_reg[i].in_use && !bdcmp(p_clrcb->notif_reg[i].remote_bda, remote_bda))
+ memset(&p_clrcb->notif_reg[i], 0, sizeof(tBTA_GATTC_NOTIF_REG));
+ }
+ }
+ }
+ else
+ {
+ APPL_TRACE_ERROR0("can not clear indication/notif registration for unknown app");
+ }
+ return;
+}
+
+/*******************************************************************************
+**
+** Function bta_gattc_pack_cb_data
+**
+** Description pack the data from read response into callback data structure.
+**
+** Returns
+**
+*******************************************************************************/
+tBTA_GATT_STATUS bta_gattc_pack_read_cb_data(tBTA_GATTC_SERV *p_srcb, tBT_UUID descr_uuid,
+ tGATT_VALUE *p_attr, tBTA_GATT_READ_VAL *p_value)
+{
+ UINT8 i = 0, *pp = p_attr->value;
+ tBT_UUID uuid = {LEN_UUID_16, {GATT_UUID_CHAR_AGG_FORMAT}};
+ UINT16 handle;
+ tBTA_GATT_STATUS status = BTA_GATT_OK;
+
+ /* GATT_UUID_CHAR_AGG_FORMAT */
+ if (bta_gattc_uuid_compare (uuid, descr_uuid, TRUE))
+ {
+ while (p_attr->len >= 2 && i < BTA_GATTC_MULTI_MAX)
+ {
+ STREAM_TO_UINT16(handle, pp);
+
+ if (bta_gattc_handle2id(p_srcb,
+ handle,
+ &p_value->aggre_value.pre_format[i].char_id.srvc_id,
+ &p_value->aggre_value.pre_format[i].char_id.char_id,
+ &p_value->aggre_value.pre_format[i].descr_type) == FALSE)
+ {
+ status = BTA_GATT_INTERNAL_ERROR;
+ APPL_TRACE_ERROR1("can not map to GATT ID. handle = 0x%04x", handle);
+ break;
+ }
+ i ++;
+ p_attr->len -= 2;
+ }
+ p_value->aggre_value.num_pres_fmt = i;
+ }
+ else
+ {
+ /* all others, take as raw format */
+ p_value->unformat.len = p_attr->len;
+ p_value->unformat.p_value = p_attr->value;
+ }
+ return status;
+}
+/*******************************************************************************
+**
+** Function bta_gattc_mark_bg_conn
+**
+** Description mark background connection status when a bg connection is initiated
+** or terminated.
+**
+** Returns TRUE if success; FALSE otherwise.
+**
+*******************************************************************************/
+BOOLEAN bta_gattc_mark_bg_conn (tBTA_GATTC_IF client_if, BD_ADDR remote_bda, BOOLEAN add)
+{
+ tBTA_GATTC_BG_TCK *p_bg_tck = &bta_gattc_cb.bg_track[0];
+ UINT8 i = 0;
+
+ for (i = 0; i < BTA_GATTC_KNOWN_SR_MAX; i ++, p_bg_tck ++)
+ {
+ if (p_bg_tck->in_use &&
+ bdcmp(p_bg_tck->remote_bda, remote_bda) == 0)
+ {
+ if (add)
+ /* mask on the cif bit */
+ p_bg_tck->cif_mask |= (1 <<(client_if - 1));
+ else
+ p_bg_tck->cif_mask &= (~(1 <<(client_if - 1)));
+
+ return TRUE;
+ }
+ }
+ if (!add)
+ {
+ APPL_TRACE_ERROR0("Do not find the bg connection mask for the remote device");
+ return FALSE;
+ }
+ else /* adding a new device mask */
+ {
+ for (i = 0, p_bg_tck = &bta_gattc_cb.bg_track[0];
+ i < BTA_GATTC_KNOWN_SR_MAX; i ++, p_bg_tck ++)
+ {
+ if (!p_bg_tck->in_use)
+ {
+ p_bg_tck->in_use = TRUE;
+ bdcpy(p_bg_tck->remote_bda, remote_bda);
+ p_bg_tck->cif_mask = (1 <<(client_if - 1));
+ return TRUE;
+ }
+ }
+ APPL_TRACE_ERROR0("no available space to mark the bg connection status");
+ return FALSE;
+ }
+}
+/*******************************************************************************
+**
+** Function bta_gattc_check_bg_conn
+**
+** Description check if this is a background connection background connection.
+**
+** Returns TRUE if success; FALSE otherwise.
+**
+*******************************************************************************/
+BOOLEAN bta_gattc_check_bg_conn (tBTA_GATTC_IF client_if, BD_ADDR remote_bda)
+{
+ tBTA_GATTC_BG_TCK *p_bg_tck = &bta_gattc_cb.bg_track[0];
+ UINT8 i = 0;
+ BOOLEAN is_bg_conn = FALSE;
+
+ for (i = 0; i < BTA_GATTC_KNOWN_SR_MAX; i ++, p_bg_tck ++)
+ {
+ if (p_bg_tck->in_use &&
+ bdcmp(p_bg_tck->remote_bda, remote_bda) == 0)
+ {
+ if ((p_bg_tck->cif_mask &(1 <<(client_if - 1))) != 0)
+ is_bg_conn = TRUE;
+ break;
+ }
+ }
+ return is_bg_conn;
+}
+/*******************************************************************************
+**
+** Function bta_gattc_send_open_cback
+**
+** Description send open callback
+**
+** Returns
+**
+*******************************************************************************/
+void bta_gattc_send_open_cback( tBTA_GATTC_RCB *p_clreg, tBTA_GATT_STATUS status,
+ BD_ADDR remote_bda, UINT16 conn_id)
+{
+ tBTA_GATTC cb_data;
+
+ if (p_clreg->p_cback)
+ {
+ memset(&cb_data, 0, sizeof(tBTA_GATTC));
+
+ cb_data.open.status = status;
+ cb_data.open.client_if = p_clreg->client_if;
+ cb_data.open.conn_id = conn_id;
+ bdcpy(cb_data.open.remote_bda, remote_bda);
+
+ (*p_clreg->p_cback)(BTA_GATTC_OPEN_EVT, &cb_data);
+ }
+}
+
+
+
+
+
+#endif /* BTA_GATT_INCLUDED */
diff --git a/bta/gatt/bta_gatts_act.c b/bta/gatt/bta_gatts_act.c
new file mode 100644
index 0000000..cb56a32
--- /dev/null
+++ b/bta/gatt/bta_gatts_act.c
@@ -0,0 +1,785 @@
+/*****************************************************************************
+**
+** Name: bta_gatts_act.c
+**
+** Description: This file contains the GATT Server action
+** functions for the state machine.
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+
+#include "bt_target.h"
+
+#if defined(BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE)
+
+#include "utl.h"
+#include "gki.h"
+#include "bta_sys.h"
+#include "bta_gatts_int.h"
+#include "bta_gatts_co.h"
+
+#include <string.h>
+
+static void bta_gatts_nv_save_cback(BOOLEAN is_saved, tGATTS_HNDL_RANGE *p_hndl_range);
+static BOOLEAN bta_gatts_nv_srv_chg_cback(tGATTS_SRV_CHG_CMD cmd, tGATTS_SRV_CHG_REQ *p_req, tGATTS_SRV_CHG_RSP *p_rsp);
+
+static void bta_gatts_conn_cback (tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id, BOOLEAN connected, tGATT_DISCONN_REASON reason);
+static void bta_gatts_send_request_cback (UINT16 conn_id,
+ UINT32 trans_id,
+ tGATTS_REQ_TYPE req_type, tGATTS_DATA *p_data);
+static tGATT_CBACK bta_gatts_cback =
+{
+ bta_gatts_conn_cback,
+ NULL,
+ NULL,
+ NULL,
+ bta_gatts_send_request_cback
+};
+
+tGATT_APPL_INFO bta_gatts_nv_cback =
+{
+ bta_gatts_nv_save_cback,
+ bta_gatts_nv_srv_chg_cback
+};
+
+/*******************************************************************************
+**
+** Function bta_gatts_nv_save_cback
+**
+** Description NV save callback function.
+**
+** Parameter is_add: true is to add a handle range; otherwise is to delete.
+** Returns none.
+**
+*******************************************************************************/
+static void bta_gatts_nv_save_cback(BOOLEAN is_add, tGATTS_HNDL_RANGE *p_hndl_range)
+{
+ bta_gatts_co_update_handle_range(is_add, (tBTA_GATTS_HNDL_RANGE *)p_hndl_range);
+}
+
+
+/*******************************************************************************
+**
+** Function bta_gatts_nv_srv_chg_cback
+**
+** Description NV save callback function.
+**
+** Parameter is_add: true is to add a handle range; otherwise is to delete.
+** Returns none.
+**
+*******************************************************************************/
+static BOOLEAN bta_gatts_nv_srv_chg_cback(tGATTS_SRV_CHG_CMD cmd, tGATTS_SRV_CHG_REQ *p_req, tGATTS_SRV_CHG_RSP *p_rsp)
+{
+ return bta_gatts_co_srv_chg((tBTA_GATTS_SRV_CHG_CMD) cmd,
+ (tBTA_GATTS_SRV_CHG_REQ *) p_req,
+ (tBTA_GATTS_SRV_CHG_RSP *) p_rsp);
+}
+
+
+/*******************************************************************************
+**
+** Function bta_gatts_enable
+**
+** Description enable BTA GATTS module.
+**
+** Returns none.
+**
+*******************************************************************************/
+void bta_gatts_enable(tBTA_GATTS_CB *p_cb)
+{
+ UINT8 index=0;
+ tBTA_GATTS_HNDL_RANGE handle_range;
+
+ p_cb->enabled = TRUE;
+
+ APPL_TRACE_DEBUG0("bta_gatts_enable");
+ while ( bta_gatts_co_load_handle_range(index, &handle_range))
+ {
+ GATTS_AddHandleRange((tGATTS_HNDL_RANGE *)&handle_range);
+ memset(&handle_range, 0, sizeof(tGATTS_HNDL_RANGE));
+ index++;
+ }
+
+ APPL_TRACE_DEBUG1("bta_gatts_enable: num of handle range added=%d", index);
+
+ if (!GATTS_NVRegister(&bta_gatts_nv_cback))
+ {
+ APPL_TRACE_ERROR0("BTA GATTS NV register failed.");
+ }
+}
+/*******************************************************************************
+**
+** Function bta_gatts_register
+**
+** Description register an application.
+**
+** Returns none.
+**
+*******************************************************************************/
+void bta_gatts_register(tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA *p_msg)
+{
+ tBTA_GATTS_INT_START_IF *p_buf;
+ tBTA_GATTS cb_data;
+ tBTA_GATT_STATUS status = BTA_GATT_OK;
+ UINT8 i, first_unuse = 0xff;
+
+ if (!p_cb->enabled)
+ bta_gatts_enable(p_cb);
+
+
+ for (i = 0; i < BTA_GATTS_MAX_APP_NUM; i ++)
+ {
+ if (p_cb->rcb[i].in_use)
+ {
+ if (bta_gatts_uuid_compare(p_cb->rcb[i].app_uuid, p_msg->api_reg.app_uuid))
+ {
+ APPL_TRACE_ERROR0("application already registered.");
+ status = BTA_GATT_DUP_REG;
+ break;
+ }
+ }
+ }
+
+ if (status == BTA_GATT_OK)
+ {
+ for (i = 0; i < BTA_GATTS_MAX_APP_NUM; i ++)
+ {
+ if (first_unuse == 0xff && !p_cb->rcb[i].in_use)
+ {
+ first_unuse = i;
+ break;
+ }
+ }
+
+ cb_data.reg_oper.server_if = BTA_GATTS_INVALID_IF;
+// btla-specific ++
+ memcpy(&cb_data.reg_oper.uuid, &p_msg->api_reg.app_uuid, sizeof(tBT_UUID));
+// btla-specific --
+ if (first_unuse != 0xff)
+ {
+ APPL_TRACE_ERROR1("register application first_unuse rcb_idx = %d", first_unuse);
+
+ p_cb->rcb[first_unuse].in_use = TRUE;
+ p_cb->rcb[first_unuse].p_cback = p_msg->api_reg.p_cback;
+ memcpy(&p_cb->rcb[first_unuse].app_uuid, &p_msg->api_reg.app_uuid, sizeof(tBT_UUID));
+ cb_data.reg_oper.server_if =
+ p_cb->rcb[first_unuse].gatt_if = GATT_Register(&p_msg->api_reg.app_uuid, &bta_gatts_cback);
+ if ( !p_cb->rcb[first_unuse].gatt_if)
+ {
+ status = BTA_GATT_NO_RESOURCES;
+ }
+ else
+ {
+ if ((p_buf = (tBTA_GATTS_INT_START_IF *) GKI_getbuf(sizeof(tBTA_GATTS_INT_START_IF))) != NULL)
+ {
+ p_buf->hdr.event = BTA_GATTS_INT_START_IF_EVT;
+ p_buf->server_if = p_cb->rcb[first_unuse].gatt_if;
+
+ bta_sys_sendmsg(p_buf);
+ }
+ else
+ {
+ status = BTA_GATT_NO_RESOURCES;
+ memset( &p_cb->rcb[first_unuse], 0 , sizeof(tBTA_GATTS_RCB));
+ }
+ }
+ }
+ else
+ {
+ status = BTA_GATT_NO_RESOURCES;
+ }
+
+ }
+ cb_data.reg_oper.status = status;
+ if (p_msg->api_reg.p_cback)
+ (*p_msg->api_reg.p_cback)(BTA_GATTS_REG_EVT, &cb_data);
+}
+
+
+/*******************************************************************************
+**
+** Function bta_gatts_start_if
+**
+** Description start an application interface.
+**
+** Returns none.
+**
+*******************************************************************************/
+void bta_gatts_start_if(tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA *p_msg)
+{
+ if (bta_gatts_find_app_rcb_by_app_if(p_msg->int_start_if.server_if))
+ {
+ GATT_StartIf(p_msg->int_start_if.server_if);
+ }
+ else
+ {
+ APPL_TRACE_ERROR1("Unable to start app.: Unknown interface =%d",p_msg->int_start_if.server_if );
+ }
+}
+/*******************************************************************************
+**
+** Function bta_gatts_deregister
+**
+** Description deregister an application.
+**
+** Returns none.
+**
+*******************************************************************************/
+void bta_gatts_deregister(tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA *p_msg)
+{
+ tBTA_GATT_STATUS status = BTA_GATT_ERROR;
+ tBTA_GATTS_CBACK *p_cback = NULL;
+ UINT8 i;
+ tBTA_GATTS cb_data;
+
+ cb_data.reg_oper.server_if = p_msg->api_dereg.server_if;
+ cb_data.reg_oper.status = status;
+
+ for (i = 0; i < BTA_GATTS_MAX_APP_NUM; i ++)
+ {
+ if (p_cb->rcb[i].in_use && p_cb->rcb[i].gatt_if == p_msg->api_dereg.server_if)
+ {
+ p_cback = p_cb->rcb[i].p_cback;
+ status = BTA_GATT_OK;
+
+ /* deregister the app */
+ GATT_Deregister(p_cb->rcb[i].gatt_if);
+
+ /* reset cb */
+ memset(&p_cb->rcb[i], 0, sizeof(tBTA_GATTS_RCB));
+ cb_data.reg_oper.status = status;
+ break;
+ }
+ }
+
+ if (p_cback)
+ {
+ (*p_cback)(BTA_GATTS_DEREG_EVT, &cb_data);
+ }
+ else
+ {
+ APPL_TRACE_ERROR0("application not registered.");
+ }
+}
+/*******************************************************************************
+**
+** Function bta_gatts_create_srvc
+**
+** Description action function to create a service.
+**
+** Returns none.
+**
+*******************************************************************************/
+void bta_gatts_create_srvc(tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg)
+{
+ UINT8 rcb_idx;
+ tBTA_GATTS cb_data;
+ UINT8 srvc_idx;
+ UINT16 service_id = 0;
+ //tBTA_GATTS_HNDL_RANGE handle_range;
+
+ cb_data.create.status = BTA_GATT_ERROR;
+
+ rcb_idx = bta_gatts_find_app_rcb_idx_by_app_if(p_cb, p_msg->api_create_svc.server_if);
+
+ APPL_TRACE_ERROR1("create service rcb_idx = %d", rcb_idx);
+
+ if (rcb_idx != BTA_GATTS_INVALID_APP)
+ {
+ if ((srvc_idx = bta_gatts_alloc_srvc_cb(p_cb, rcb_idx)) != BTA_GATTS_INVALID_APP)
+ {
+ /* create the service now */
+ service_id = GATTS_CreateService (p_cb->rcb[rcb_idx].gatt_if,
+ &p_msg->api_create_svc.service_uuid,
+ p_msg->api_create_svc.inst,
+ p_msg->api_create_svc.num_handle,
+ p_msg->api_create_svc.is_pri);
+
+ if (service_id != 0)
+ {
+ memcpy(&p_cb->srvc_cb[srvc_idx].service_uuid, &p_msg->api_create_svc.service_uuid, sizeof(tBT_UUID));
+ p_cb->srvc_cb[srvc_idx].service_id = service_id;
+ p_cb->srvc_cb[srvc_idx].inst_num = p_msg->api_create_svc.inst;
+ p_cb->srvc_cb[srvc_idx].idx = srvc_idx;
+
+ cb_data.create.status = BTA_GATT_OK;
+ cb_data.create.service_id = service_id;
+// btla-specific ++
+ cb_data.create.is_primary = p_msg->api_create_svc.is_pri;
+// btla-specific --
+ cb_data.create.server_if = p_cb->rcb[rcb_idx].gatt_if;
+ }
+ else
+ {
+ cb_data.status = BTA_GATT_ERROR;
+ memset(&p_cb->srvc_cb[srvc_idx], 0, sizeof(tBTA_GATTS_SRVC_CB));
+ APPL_TRACE_ERROR0("service creation failed.");
+ }
+// btla-specific ++
+ memcpy(&cb_data.create.uuid, &p_msg->api_create_svc.service_uuid, sizeof(tBT_UUID));
+ cb_data.create.svc_instance= p_msg->api_create_svc.inst;
+// btla-specific --
+ }
+ if (p_cb->rcb[rcb_idx].p_cback)
+ (* p_cb->rcb[rcb_idx].p_cback)(BTA_GATTS_CREATE_EVT, &cb_data);
+ }
+ else /* application not registered */
+ {
+ APPL_TRACE_ERROR0("Application not registered");
+ }
+}
+/*******************************************************************************
+**
+** Function bta_gatts_add_include_srvc
+**
+** Description action function to add an included service.
+**
+** Returns none.
+**
+*******************************************************************************/
+void bta_gatts_add_include_srvc(tBTA_GATTS_SRVC_CB *p_srvc_cb,tBTA_GATTS_DATA * p_msg)
+{
+ tBTA_GATTS_RCB *p_rcb = &bta_gatts_cb.rcb[p_srvc_cb->rcb_idx];
+ UINT16 attr_id = 0;
+ tBTA_GATTS cb_data;
+
+ attr_id = GATTS_AddIncludeService(p_msg->api_add_incl_srvc.hdr.layer_specific,
+ p_msg->api_add_incl_srvc.included_service_id);
+
+ cb_data.add_result.server_if = p_rcb->gatt_if;
+ cb_data.add_result.service_id = p_msg->api_add_incl_srvc.hdr.layer_specific;
+ cb_data.add_result.attr_id = attr_id;
+
+ if (attr_id)
+ {
+ cb_data.add_result.status = BTA_GATT_OK;
+ }
+ else
+ {
+ cb_data.add_result.status = BTA_GATT_ERROR;
+ }
+
+ if (p_rcb->p_cback)
+ (*p_rcb->p_cback)(BTA_GATTS_ADD_INCL_SRVC_EVT, &cb_data);
+}
+/*******************************************************************************
+**
+** Function bta_gatts_add_char
+**
+** Description action function to add characteristic.
+**
+** Returns none.
+**
+*******************************************************************************/
+void bta_gatts_add_char(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA * p_msg)
+{
+ tBTA_GATTS_RCB *p_rcb = &bta_gatts_cb.rcb[p_srvc_cb->rcb_idx];
+ UINT16 attr_id = 0;
+ tBTA_GATTS cb_data;
+
+ attr_id = GATTS_AddCharacteristic(p_msg->api_add_char.hdr.layer_specific,
+ &p_msg->api_add_char.char_uuid,
+ p_msg->api_add_char.perm,
+ p_msg->api_add_char.property);
+ cb_data.add_result.server_if = p_rcb->gatt_if;
+ cb_data.add_result.service_id = p_msg->api_add_incl_srvc.hdr.layer_specific;
+ cb_data.add_result.attr_id = attr_id;
+// btla-specific ++
+ memcpy(&cb_data.add_result.char_uuid, &p_msg->api_add_char.char_uuid, sizeof(tBT_UUID));
+// btla-specific --
+
+ if (attr_id)
+ {
+ cb_data.add_result.status = BTA_GATT_OK;
+ }
+ else
+ {
+ cb_data.add_result.status = BTA_GATT_ERROR;
+ }
+
+ if (p_rcb->p_cback)
+ (*p_rcb->p_cback)(BTA_GATTS_ADD_CHAR_EVT, &cb_data);
+}
+/*******************************************************************************
+**
+** Function bta_gatts_add_char_descr
+**
+** Description action function to add characteristic descriptor.
+**
+** Returns none.
+**
+*******************************************************************************/
+void bta_gatts_add_char_descr(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA * p_msg)
+{
+ tBTA_GATTS_RCB *p_rcb = &bta_gatts_cb.rcb[p_srvc_cb->rcb_idx];
+ UINT16 attr_id = 0;
+ tBTA_GATTS cb_data;
+
+ attr_id = GATTS_AddCharDescriptor(p_msg->api_add_char_descr.hdr.layer_specific,
+ p_msg->api_add_char_descr.perm,
+ &p_msg->api_add_char_descr.descr_uuid);
+
+ cb_data.add_result.server_if = p_rcb->gatt_if;
+ cb_data.add_result.service_id = p_msg->api_add_incl_srvc.hdr.layer_specific;
+ cb_data.add_result.attr_id = attr_id;
+// btla-specific ++
+ memcpy(&cb_data.add_result.char_uuid, &p_msg->api_add_char_descr.descr_uuid, sizeof(tBT_UUID));
+// btla-specific --
+
+ if (attr_id)
+ {
+ cb_data.add_result.status = BTA_GATT_OK;
+ }
+ else
+ {
+ cb_data.add_result.status = BTA_GATT_ERROR;
+ }
+
+ if (p_rcb->p_cback)
+ (*p_rcb->p_cback)(BTA_GATTS_ADD_CHAR_DESCR_EVT, &cb_data);
+
+}
+/*******************************************************************************
+**
+** Function bta_gatts_delete_service
+**
+** Description action function to delete a service.
+**
+** Returns none.
+**
+*******************************************************************************/
+void bta_gatts_delete_service(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA * p_msg)
+{
+ tBTA_GATTS_RCB *p_rcb = &bta_gatts_cb.rcb[p_srvc_cb->rcb_idx];
+ tBTA_GATTS cb_data;
+
+ cb_data.srvc_oper.server_if = p_rcb->gatt_if;
+ cb_data.srvc_oper.service_id = p_msg->api_add_incl_srvc.hdr.layer_specific;
+
+ if (GATTS_DeleteService(p_rcb->gatt_if,
+ &p_srvc_cb->service_uuid,
+ p_srvc_cb->inst_num))
+ {
+ cb_data.srvc_oper.status = BTA_GATT_OK;
+ memset(p_srvc_cb, 0, sizeof(tBTA_GATTS_SRVC_CB));
+ }
+ else
+ {
+ cb_data.srvc_oper.status = BTA_GATT_ERROR;
+ }
+
+ if (p_rcb->p_cback)
+ (*p_rcb->p_cback)(BTA_GATTS_DELELTE_EVT, &cb_data);
+
+}
+/*******************************************************************************
+**
+** Function bta_gatts_start_service
+**
+** Description action function to start a service.
+**
+** Returns none.
+**
+*******************************************************************************/
+void bta_gatts_start_service(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA * p_msg)
+{
+ tBTA_GATTS_RCB *p_rcb = &bta_gatts_cb.rcb[p_srvc_cb->rcb_idx];
+ tBTA_GATTS cb_data;
+
+ cb_data.srvc_oper.server_if = p_rcb->gatt_if;
+ cb_data.srvc_oper.service_id = p_msg->api_add_incl_srvc.hdr.layer_specific;
+
+ if (GATTS_StartService(p_rcb->gatt_if,
+ p_srvc_cb->service_id,
+ p_msg->api_start.transport) == GATT_SUCCESS)
+ {
+ APPL_TRACE_DEBUG1("bta_gatts_start_service service_id= %d", p_srvc_cb->service_id);
+ cb_data.srvc_oper.status = BTA_GATT_OK;
+ }
+ else
+ {
+ cb_data.srvc_oper.status = BTA_GATT_ERROR;
+ }
+
+ if (p_rcb->p_cback)
+ (*p_rcb->p_cback)(BTA_GATTS_START_EVT, &cb_data);
+
+}
+/*******************************************************************************
+**
+** Function bta_gatts_stop_service
+**
+** Description action function to stop a service.
+**
+** Returns none.
+**
+*******************************************************************************/
+void bta_gatts_stop_service(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA * p_msg)
+{
+ tBTA_GATTS_RCB *p_rcb = &bta_gatts_cb.rcb[p_srvc_cb->rcb_idx];
+ tBTA_GATTS cb_data;
+
+ GATTS_StopService(p_srvc_cb->service_id);
+ cb_data.srvc_oper.server_if = p_rcb->gatt_if;
+ cb_data.srvc_oper.service_id = p_srvc_cb->service_id;
+ cb_data.srvc_oper.status = BTA_GATT_OK;
+ APPL_TRACE_ERROR1("bta_gatts_stop_service service_id= %d", p_srvc_cb->service_id);
+
+ if (p_rcb->p_cback)
+ (*p_rcb->p_cback)(BTA_GATTS_STOP_EVT, &cb_data);
+
+}
+/*******************************************************************************
+**
+** Function bta_gatts_send_rsp
+**
+** Description GATTS send response.
+**
+** Returns none.
+**
+*******************************************************************************/
+void bta_gatts_send_rsp (tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg)
+{
+
+ if (GATTS_SendRsp (p_msg->api_rsp.hdr.layer_specific,
+ p_msg->api_rsp.trans_id,
+ p_msg->api_rsp.status,
+ (tGATTS_RSP *)p_msg->api_rsp.p_rsp) != GATT_SUCCESS)
+ {
+ APPL_TRACE_ERROR0("Sending response failed");
+ }
+
+}
+/*******************************************************************************
+**
+** Function bta_gatts_send_rsp
+**
+** Description GATTS send response.
+**
+** Returns none.
+**
+*******************************************************************************/
+void bta_gatts_indicate_handle (tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg)
+{
+ tBTA_GATTS_SRVC_CB *p_srvc_cb;
+ tBTA_GATT_STATUS status;
+
+
+ p_srvc_cb = bta_gatts_find_srvc_cb_by_attr_id (p_cb, p_msg->api_indicate.attr_id);
+
+ if (p_srvc_cb )
+ {
+ if (p_msg->api_indicate.need_confirm)
+
+ status = GATTS_HandleValueIndication (p_msg->api_indicate.hdr.layer_specific,
+ p_msg->api_indicate.attr_id,
+ p_msg->api_indicate.len,
+ p_msg->api_indicate.value);
+ else
+ status = GATTS_HandleValueNotification (p_msg->api_indicate.hdr.layer_specific,
+ p_msg->api_indicate.attr_id,
+ p_msg->api_indicate.len,
+ p_msg->api_indicate.value);
+
+ if (status != GATT_SUCCESS &&
+ p_msg->api_indicate.need_confirm &&
+ p_cb->rcb[p_srvc_cb->rcb_idx].p_cback)
+ {
+ (*p_cb->rcb[p_srvc_cb->rcb_idx].p_cback)(BTA_GATTS_CONF_EVT, (tBTA_GATTS *)&status);
+ }
+ }
+ else
+ {
+ APPL_TRACE_ERROR1("Not an registered servce attribute ID: 0x%04x", p_msg->api_indicate.attr_id);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function bta_gatts_open
+**
+** Description
+**
+** Returns none.
+**
+*******************************************************************************/
+void bta_gatts_open (tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg)
+{
+ tBTA_GATTS_RCB *p_rcb=NULL;
+ tBTA_GATT_STATUS status= BTA_GATT_ERROR;
+
+
+ if ((p_rcb = bta_gatts_find_app_rcb_by_app_if(p_msg->api_open.server_if)) != NULL)
+ {
+ if (GATT_Connect(p_rcb->gatt_if, p_msg->api_open.remote_bda, p_msg->api_open.is_direct))
+ {
+ status = BTA_GATT_OK;
+ }
+ }
+ else
+ {
+ APPL_TRACE_ERROR1("Inavlide server_if=%d", p_msg->api_open.server_if);
+ }
+
+ if (p_rcb && p_rcb->p_cback)
+ (*p_rcb->p_cback)(BTA_GATTS_OPEN_EVT, (tBTA_GATTS *)&status);
+
+}
+/*******************************************************************************
+**
+** Function bta_gatts_cancel_open
+**
+** Description
+**
+** Returns none.
+**
+*******************************************************************************/
+void bta_gatts_cancel_open (tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg)
+{
+ tBTA_GATTS_RCB *p_rcb;
+ tBTA_GATT_STATUS status= BTA_GATT_ERROR;
+
+ if ((p_rcb = bta_gatts_find_app_rcb_by_app_if(p_msg->api_cancel_open.server_if)) != NULL)
+ {
+ if (!GATT_CancelConnect(p_rcb->gatt_if, p_msg->api_cancel_open.remote_bda, p_msg->api_cancel_open.is_direct))
+ {
+ APPL_TRACE_ERROR0("bta_gatts_cancel_open failed for open request");
+ }
+ else
+ {
+ status= BTA_GATT_OK;
+ }
+ }
+ else
+ {
+ APPL_TRACE_ERROR1("Inavlide server_if=%d", p_msg->api_cancel_open.server_if);
+ }
+
+ if (p_rcb && p_rcb->p_cback)
+ (*p_rcb->p_cback)(BTA_GATTS_CANCEL_OPEN_EVT, (tBTA_GATTS *)&status);
+}
+/*******************************************************************************
+**
+** Function bta_gatts_close
+**
+** Description
+**
+** Returns none.
+**
+*******************************************************************************/
+void bta_gatts_close (tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg)
+{
+ tBTA_GATTS_RCB *p_rcb;
+ tBTA_GATT_STATUS status= BTA_GATT_ERROR;
+ tGATT_IF gatt_if;
+ BD_ADDR remote_bda;
+
+ if (GATT_GetConnectionInfor(p_msg->hdr.layer_specific, &gatt_if, remote_bda))
+ {
+ if (GATT_Disconnect(p_msg->hdr.layer_specific) != GATT_SUCCESS)
+ {
+ APPL_TRACE_ERROR1("bta_gatts_close fail conn_id=%d", p_msg->hdr.layer_specific);
+ }
+ else
+ {
+ status= BTA_GATT_OK;
+ }
+
+ p_rcb = bta_gatts_find_app_rcb_by_app_if(gatt_if);
+
+ if (p_rcb && p_rcb->p_cback)
+ (*p_rcb->p_cback)(BTA_GATTS_CLOSE_EVT, (tBTA_GATTS *)&status);
+ }
+ else
+ {
+ APPL_TRACE_ERROR1("Unknown connection ID: %d", p_msg->hdr.layer_specific);
+ }
+
+}
+
+
+/*******************************************************************************
+**
+** Function bta_gatts_request_cback
+**
+** Description GATTS attribute request callback.
+**
+** Returns none.
+**
+*******************************************************************************/
+static void bta_gatts_send_request_cback (UINT16 conn_id,
+ UINT32 trans_id,
+ tGATTS_REQ_TYPE req_type, tGATTS_DATA *p_data)
+{
+ tBTA_GATTS cb_data;
+ tBTA_GATTS_RCB *p_rcb;
+ tGATT_IF gatt_if;
+
+ memset(&cb_data, 0 , sizeof(tBTA_GATTS));
+
+ if (GATT_GetConnectionInfor(conn_id, &gatt_if, cb_data.req_data.remote_bda))
+ {
+ p_rcb = bta_gatts_find_app_rcb_by_app_if(gatt_if);
+
+ APPL_TRACE_DEBUG3 ("bta_gatts_send_request_cback conn_id=%d trans_id=%d req_type=%d", conn_id, trans_id, req_type);
+
+ if (p_rcb && p_rcb->p_cback)
+ {
+ cb_data.req_data.conn_id = conn_id;
+ cb_data.req_data.trans_id = trans_id;
+ cb_data.req_data.p_data = (tBTA_GATTS_REQ_DATA *)p_data;
+
+ (*p_rcb->p_cback)(req_type, &cb_data);
+ }
+ else
+ {
+ APPL_TRACE_ERROR1("connection request on gatt_if[%d] is not interested", gatt_if);
+ }
+ }
+ else
+ {
+ APPL_TRACE_ERROR1("request received on unknown connectino ID: %d", conn_id);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_gatts_conn_cback
+**
+** Description connection callback.
+**
+** Returns none.
+**
+*******************************************************************************/
+static void bta_gatts_conn_cback (tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id,
+ BOOLEAN connected, tGATT_DISCONN_REASON reason)
+{
+ tBTA_GATTS cb_data;
+ UINT8 evt = connected ? BTA_GATTS_CONNECT_EVT: BTA_GATTS_DISCONNECT_EVT;
+ tBTA_GATTS_RCB *p_reg;
+
+ APPL_TRACE_DEBUG4 ("bta_gatts_conn_cback gatt_if=%d conn_id=%d connected=%d reason = 0x%04d",
+ gatt_if, conn_id, connected, reason);
+ APPL_TRACE_DEBUG6("bta_gatts_conn_cback bda :%02x-%02x-%02x-%02x-%02x-%02x ",
+ bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
+
+ p_reg = bta_gatts_find_app_rcb_by_app_if(gatt_if);
+
+ if (p_reg && p_reg->p_cback)
+ {
+ cb_data.conn.conn_id = conn_id;
+ cb_data.conn.server_if = gatt_if;
+ cb_data.conn.reason = reason;
+ memcpy(cb_data.conn.remote_bda, bda, BD_ADDR_LEN);
+ (*p_reg->p_cback)(evt, &cb_data);
+ }
+ else
+ {
+ APPL_TRACE_ERROR1("bta_gatts_conn_cback server_if=%d not found",gatt_if);
+ }
+}
+#endif /* BTA_GATT_INCLUDED */
diff --git a/bta/gatt/bta_gatts_api.c b/bta/gatt/bta_gatts_api.c
new file mode 100644
index 0000000..77a8f6e
--- /dev/null
+++ b/bta/gatt/bta_gatts_api.c
@@ -0,0 +1,500 @@
+/*****************************************************************************
+**
+** Name: bta_gatts_api.c
+**
+** Description: This is the implementation of the API for GATT server
+** of BTA.
+**
+** Copyright (c) 2010-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+
+#if defined(BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE)
+
+#include <string.h>
+#include "gki.h"
+#include "bta_sys.h"
+#include "bta_gatt_api.h"
+#include "bta_gatts_int.h"
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+static const tBTA_SYS_REG bta_gatts_reg =
+{
+ bta_gatts_hdl_event,
+ NULL /* need a disable functino to be called when BT is disabled */
+};
+
+/*******************************************************************************
+**
+** Function BTA_GATTS_AppRegister
+**
+** Description This function is called to register application callbacks
+** with BTA GATTS module.
+**
+** Parameters p_app_uuid - applicaiton UUID
+** p_cback - pointer to the application callback function.
+**
+** Returns None
+**
+*******************************************************************************/
+void BTA_GATTS_AppRegister(tBT_UUID *p_app_uuid, tBTA_GATTS_CBACK *p_cback)
+{
+ tBTA_GATTS_API_REG *p_buf;
+
+ /* register with BTA system manager */
+ GKI_sched_lock();
+ if (!bta_gatts_cb.enabled)
+ {
+ bta_sys_register(BTA_ID_GATTS, &bta_gatts_reg);
+ }
+ GKI_sched_unlock();
+
+ if ((p_buf = (tBTA_GATTS_API_REG *) GKI_getbuf(sizeof(tBTA_GATTS_API_REG))) != NULL)
+ {
+ p_buf->hdr.event = BTA_GATTS_API_REG_EVT;
+
+ if (p_app_uuid != NULL)
+ memcpy(&p_buf->app_uuid, p_app_uuid, sizeof(tBT_UUID));
+ p_buf->p_cback = p_cback;
+
+ bta_sys_sendmsg(p_buf);
+ }
+ return;
+}
+
+
+
+/*******************************************************************************
+**
+** Function BTA_GATTS_AppDeregister
+**
+** Description De-register with GATT Server.
+**
+** Parameters app_id: applicatino ID.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_GATTS_AppDeregister(tBTA_GATTS_IF server_if)
+{
+ tBTA_GATTS_API_DEREG *p_buf;
+
+ if ((p_buf = (tBTA_GATTS_API_DEREG *) GKI_getbuf(sizeof(tBTA_GATTS_API_DEREG))) != NULL)
+ {
+ p_buf->hdr.event = BTA_GATTS_API_DEREG_EVT;
+ p_buf->server_if = server_if;
+
+ bta_sys_sendmsg(p_buf);
+ }
+ return;
+}
+
+/*******************************************************************************
+**
+** Function BTA_GATTS_CreateService
+**
+** Description Create a service. When service creation is done, a callback
+** event BTA_GATTS_CREATE_SRVC_EVT is called to report status
+** and service ID to the profile. The service ID obtained in
+** the callback function needs to be used when adding included
+** service and characteristics/descriptors into the service.
+**
+** Parameters app_id: Profile ID this service is belonged to.
+** p_service_uuid: service UUID.
+** inst: instance ID number of this service.
+** num_handle: numble of handle requessted for this service.
+** is_primary: is this service a primary one or not.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_GATTS_CreateService(tBTA_GATTS_IF server_if, tBT_UUID *p_service_uuid, UINT8 inst,
+ UINT16 num_handle, BOOLEAN is_primary)
+{
+ tBTA_GATTS_API_CREATE_SRVC *p_buf;
+
+ if ((p_buf = (tBTA_GATTS_API_CREATE_SRVC *) GKI_getbuf(sizeof(tBTA_GATTS_API_CREATE_SRVC))) != NULL)
+ {
+ p_buf->hdr.event = BTA_GATTS_API_CREATE_SRVC_EVT;
+
+ p_buf->server_if = server_if;
+ p_buf->inst = inst;
+ memcpy(&p_buf->service_uuid, p_service_uuid, sizeof(tBT_UUID));
+ p_buf->num_handle = num_handle;
+ p_buf->is_pri = is_primary;
+
+ bta_sys_sendmsg(p_buf);
+ }
+ return;
+}
+/*******************************************************************************
+**
+** Function BTA_GATTS_AddIncludeService
+**
+** Description This function is called to add an included service. After included
+** service is included, a callback event BTA_GATTS_ADD_INCL_SRVC_EVT
+** is reported the included service ID.
+**
+** Parameters service_id: service ID to which this included service is to
+** be added.
+** included_service_id: the service ID to be included.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_GATTS_AddIncludeService(UINT16 service_id, UINT16 included_service_id)
+{
+ tBTA_GATTS_API_ADD_INCL_SRVC *p_buf;
+
+ if ((p_buf =
+ (tBTA_GATTS_API_ADD_INCL_SRVC *) GKI_getbuf(sizeof(tBTA_GATTS_API_ADD_INCL_SRVC)))
+ != NULL)
+ {
+ p_buf->hdr.event = BTA_GATTS_API_ADD_INCL_SRVC_EVT;
+
+ p_buf->hdr.layer_specific = service_id;
+ p_buf->included_service_id = included_service_id;
+
+ bta_sys_sendmsg(p_buf);
+ }
+ return;
+
+}
+/*******************************************************************************
+**
+** Function BTA_GATTS_AddCharacteristic
+**
+** Description This function is called to add a characteristic into a service.
+**
+** Parameters service_id: service ID to which this included service is to
+** be added.
+** p_char_uuid : Characteristic UUID.
+** perm : Characteristic value declaration attribute permission.
+** property : Characteristic Properties
+**
+** Returns None
+**
+*******************************************************************************/
+void BTA_GATTS_AddCharacteristic (UINT16 service_id, tBT_UUID *p_char_uuid,
+ tBTA_GATT_PERM perm, tBTA_GATT_CHAR_PROP property)
+{
+ tBTA_GATTS_API_ADD_CHAR *p_buf;
+
+ if ((p_buf = (tBTA_GATTS_API_ADD_CHAR *) GKI_getbuf(sizeof(tBTA_GATTS_API_ADD_CHAR))) != NULL)
+ {
+ memset(p_buf, 0, sizeof(tBTA_GATTS_API_ADD_CHAR));
+
+ p_buf->hdr.event = BTA_GATTS_API_ADD_CHAR_EVT;
+ p_buf->hdr.layer_specific = service_id;
+ p_buf->perm = perm;
+ p_buf->property = property;
+
+ if (p_char_uuid)
+ {
+ memcpy(&p_buf->char_uuid, p_char_uuid, sizeof(tBT_UUID));
+ }
+ bta_sys_sendmsg(p_buf);
+ }
+ return;
+}
+
+/*******************************************************************************
+**
+** Function BTA_GATTS_AddCharDescriptor
+**
+** Description This function is called to add characteristic descriptor. When
+** it's done, a callback event BTA_GATTS_ADD_DESCR_EVT is called
+** to report the status and an ID number for this descriptor.
+**
+** Parameters service_id: service ID to which this charatceristic descriptor is to
+** be added.
+** perm: descriptor access permission.
+** p_descr_uuid: descriptor UUID.
+**
+** Returns returns status.
+**
+*******************************************************************************/
+void BTA_GATTS_AddCharDescriptor (UINT16 service_id,
+ tBTA_GATT_PERM perm,
+ tBT_UUID * p_descr_uuid)
+{
+ tBTA_GATTS_API_ADD_DESCR *p_buf;
+ UINT16 len = sizeof(tBTA_GATTS_API_ADD_DESCR);
+
+
+ if ((p_buf = (tBTA_GATTS_API_ADD_DESCR *) GKI_getbuf(len)) != NULL)
+ {
+ memset(p_buf, 0, len);
+
+ p_buf->hdr.event = BTA_GATTS_API_ADD_DESCR_EVT;
+ p_buf->hdr.layer_specific = service_id;
+ p_buf->perm = perm;
+
+ if (p_descr_uuid)
+ {
+ memcpy(&p_buf->descr_uuid, p_descr_uuid, sizeof(tBT_UUID));
+ }
+ bta_sys_sendmsg(p_buf);
+ }
+ return;
+
+}
+
+/*******************************************************************************
+**
+** Function BTA_GATTS_DeleteService
+**
+** Description This function is called to delete a service. When this is done,
+** a callback event BTA_GATTS_DELETE_EVT is report with the status.
+**
+** Parameters service_id: service_id to be deleted.
+**
+** Returns returns none.
+**
+*******************************************************************************/
+void BTA_GATTS_DeleteService(UINT16 service_id)
+{
+ BT_HDR *p_buf;
+
+ if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->event = BTA_GATTS_API_DEL_SRVC_EVT;
+
+ p_buf->layer_specific = service_id;
+
+ bta_sys_sendmsg(p_buf);
+ }
+ return;
+
+}
+
+/*******************************************************************************
+**
+** Function BTA_GATTS_StartService
+**
+** Description This function is called to start a service.
+**
+** Parameters service_id: the service ID to be started.
+** sup_transport: supported trasnport.
+**
+** Returns None.
+**
+*******************************************************************************/
+void BTA_GATTS_StartService(UINT16 service_id, tBTA_GATT_TRANSPORT sup_transport)
+{
+ tBTA_GATTS_API_START *p_buf;
+
+ if ((p_buf = (tBTA_GATTS_API_START *) GKI_getbuf(sizeof(tBTA_GATTS_API_START))) != NULL)
+ {
+ p_buf->hdr.event = BTA_GATTS_API_START_SRVC_EVT;
+
+ p_buf->hdr.layer_specific = service_id;
+ p_buf->transport = sup_transport;
+
+ bta_sys_sendmsg(p_buf);
+ }
+ return;
+}
+
+/*******************************************************************************
+**
+** Function BTA_GATTS_StopService
+**
+** Description This function is called to stop a service.
+**
+** Parameters service_id - service to be topped.
+**
+** Returns None
+**
+*******************************************************************************/
+void BTA_GATTS_StopService(UINT16 service_id)
+{
+ BT_HDR *p_buf;
+
+ if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->event = BTA_GATTS_API_STOP_SRVC_EVT;
+
+ p_buf->layer_specific = service_id;
+
+ bta_sys_sendmsg(p_buf);
+ }
+ return;
+}
+
+/*******************************************************************************
+**
+** Function BTA_GATTS_HandleValueIndication
+**
+** Description This function is called to read a characteristics descriptor.
+**
+** Parameters bda - remote device bd address to indicate.
+** attr_id - attribute ID to indicate.
+** data_len - indicate data length.
+** p_data: data to indicate.
+** need_confirm - if this indication expects a confirmation or not.
+**
+** Returns None
+**
+*******************************************************************************/
+void BTA_GATTS_HandleValueIndication (UINT16 conn_id, UINT16 attr_id, UINT16 data_len,
+ UINT8 *p_data, BOOLEAN need_confirm)
+{
+ tBTA_GATTS_API_INDICATION *p_buf;
+ UINT16 len = sizeof(tBTA_GATTS_API_INDICATION);
+
+ if ((p_buf = (tBTA_GATTS_API_INDICATION *) GKI_getbuf(len)) != NULL)
+ {
+ memset(p_buf, 0, len);
+
+ p_buf->hdr.event = BTA_GATTS_API_INDICATION_EVT;
+ p_buf->hdr.layer_specific = conn_id;
+ p_buf->attr_id = attr_id;
+ p_buf->need_confirm = need_confirm;
+
+ if (data_len > 0 && p_data != NULL)
+ {
+ p_buf->len = data_len;
+ memcpy(p_buf->value, p_data, data_len);
+
+ }
+ bta_sys_sendmsg(p_buf);
+ }
+ return;
+
+}
+/*******************************************************************************
+**
+** Function BTA_GATTS_SendRsp
+**
+** Description This function is called to send a response to a request.
+**
+** Parameters conn_id - connection identifier.
+** trans_id - transaction ID.
+** status - response status
+** p_msg - response data.
+**
+** Returns None
+**
+*******************************************************************************/
+void BTA_GATTS_SendRsp (UINT16 conn_id, UINT32 trans_id,
+ tBTA_GATT_STATUS status, tBTA_GATTS_RSP *p_msg)
+{
+ tBTA_GATTS_API_RSP *p_buf;
+ UINT16 len = sizeof(tBTA_GATTS_API_RSP) + sizeof(tBTA_GATTS_RSP);
+
+ if ((p_buf = (tBTA_GATTS_API_RSP *) GKI_getbuf(len)) != NULL)
+ {
+ memset(p_buf, 0, len);
+
+ p_buf->hdr.event = BTA_GATTS_API_RSP_EVT;
+ p_buf->hdr.layer_specific = conn_id;
+ p_buf->trans_id = trans_id;
+ p_buf->status = status;
+
+ if (p_msg != NULL)
+ {
+ p_buf->p_rsp = (tBTA_GATTS_RSP *)(p_buf + 1);
+ memcpy(p_buf->p_rsp, p_msg, sizeof(tBTA_GATTS_RSP));
+ }
+
+ bta_sys_sendmsg(p_buf);
+ }
+ return;
+
+}
+
+
+
+/*******************************************************************************
+**
+** Function BTA_GATTS_Open
+**
+** Description Open a direct open connection or add a background auto connection
+** bd address
+**
+** Parameters server_if: server interface.
+** remote_bda: remote device BD address.
+** is_direct: direct connection or background auto connection
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_GATTS_Open(tBTA_GATTS_IF server_if, BD_ADDR remote_bda, BOOLEAN is_direct)
+{
+ tBTA_GATTS_API_OPEN *p_buf;
+
+ if ((p_buf = (tBTA_GATTS_API_OPEN *) GKI_getbuf(sizeof(tBTA_GATTS_API_OPEN))) != NULL)
+ {
+ p_buf->hdr.event = BTA_GATTS_API_OPEN_EVT;
+ p_buf->server_if = server_if;
+ p_buf->is_direct = is_direct;
+ memcpy(p_buf->remote_bda, remote_bda, BD_ADDR_LEN);
+
+ bta_sys_sendmsg(p_buf);
+ }
+ return;
+}
+
+
+/*******************************************************************************
+**
+** Function BTA_GATTS_CancelOpen
+**
+** Description Cancel a direct open connection or remove a background auto connection
+** bd address
+**
+** Parameters server_if: server interface.
+** remote_bda: remote device BD address.
+** is_direct: direct connection or background auto connection
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_GATTS_CancelOpen(tBTA_GATTS_IF server_if, BD_ADDR remote_bda, BOOLEAN is_direct)
+{
+ tBTA_GATTS_API_CANCEL_OPEN *p_buf;
+
+ if ((p_buf = (tBTA_GATTS_API_CANCEL_OPEN *) GKI_getbuf(sizeof(tBTA_GATTS_API_CANCEL_OPEN))) != NULL)
+ {
+ p_buf->hdr.event = BTA_GATTS_API_CANCEL_OPEN_EVT;
+ p_buf->server_if = server_if;
+ p_buf->is_direct = is_direct;
+ memcpy(p_buf->remote_bda, remote_bda, BD_ADDR_LEN);
+ bta_sys_sendmsg(p_buf);
+ }
+ return;
+}
+
+/*******************************************************************************
+**
+** Function BTA_GATTS_Close
+**
+** Description Close a connection a remote device.
+**
+** Parameters conn_id: connectino ID to be closed.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_GATTS_Close(UINT16 conn_id)
+{
+ BT_HDR *p_buf;
+
+ if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->event = BTA_GATTS_API_CLOSE_EVT;
+ p_buf->layer_specific = conn_id;
+ bta_sys_sendmsg(p_buf);
+ }
+ return;
+
+}
+
+#endif /* BTA_GATT_INCLUDED */
diff --git a/bta/gatt/bta_gatts_int.h b/bta/gatt/bta_gatts_int.h
new file mode 100644
index 0000000..77945f0
--- /dev/null
+++ b/bta/gatt/bta_gatts_int.h
@@ -0,0 +1,233 @@
+/*****************************************************************************
+**
+** Name: bta_gatts_int.h
+**
+** Description: This is the private file for the BTA GATT server.
+**
+** Copyright (c) 2003-2010, Broadcom Corp., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_GATTS_INT_H
+#define BTA_GATTS_INT_H
+
+#include "bt_target.h"
+#include "bta_sys.h"
+#include "bta_gatt_api.h"
+#include "gatt_api.h"
+//#include "bta_gatts_co.h"
+
+#include "gki.h"
+
+/*****************************************************************************
+** Constants and data types
+*****************************************************************************/
+enum
+{
+ BTA_GATTS_API_REG_EVT = BTA_SYS_EVT_START(BTA_ID_GATTS),
+ BTA_GATTS_INT_START_IF_EVT,
+ BTA_GATTS_API_DEREG_EVT,
+ BTA_GATTS_API_CREATE_SRVC_EVT,
+ BTA_GATTS_API_INDICATION_EVT,
+
+ BTA_GATTS_API_ADD_INCL_SRVC_EVT,
+ BTA_GATTS_API_ADD_CHAR_EVT,
+ BTA_GATTS_API_ADD_DESCR_EVT,
+ BTA_GATTS_API_DEL_SRVC_EVT,
+ BTA_GATTS_API_START_SRVC_EVT,
+ BTA_GATTS_API_STOP_SRVC_EVT,
+ BTA_GATTS_API_RSP_EVT,
+ BTA_GATTS_API_OPEN_EVT,
+ BTA_GATTS_API_CANCEL_OPEN_EVT,
+ BTA_GATTS_API_CLOSE_EVT
+
+};
+typedef UINT16 tBTA_GATTS_INT_EVT;
+
+/* max number of application allowed on device */
+#define BTA_GATTS_MAX_APP_NUM GATT_MAX_SR_PROFILES
+
+/* max number of services allowed in the device */
+#define BTA_GATTS_MAX_SRVC_NUM GATT_MAX_SR_PROFILES
+
+/* internal strucutre for GATTC register API */
+typedef struct
+{
+ BT_HDR hdr;
+ tBT_UUID app_uuid;
+ tBTA_GATTS_CBACK *p_cback;
+}tBTA_GATTS_API_REG;
+
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_GATTS_IF server_if;
+}tBTA_GATTS_INT_START_IF;
+
+typedef tBTA_GATTS_INT_START_IF tBTA_GATTS_API_DEREG;
+
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_GATTS_IF server_if;
+ tBT_UUID service_uuid;
+ UINT16 num_handle;
+ UINT8 inst;
+ BOOLEAN is_pri;
+
+} tBTA_GATTS_API_CREATE_SRVC;
+
+typedef struct
+{
+ BT_HDR hdr;
+ tBT_UUID char_uuid;
+ tBTA_GATT_PERM perm;
+ tBTA_GATT_CHAR_PROP property;
+
+}tBTA_GATTS_API_ADD_CHAR;
+
+typedef struct
+{
+ BT_HDR hdr;
+ UINT16 included_service_id;
+
+}tBTA_GATTS_API_ADD_INCL_SRVC;
+
+typedef struct
+{
+ BT_HDR hdr;
+ tBT_UUID descr_uuid;
+ tBTA_GATT_PERM perm;
+}tBTA_GATTS_API_ADD_DESCR;
+
+typedef struct
+{
+ BT_HDR hdr;
+ //todo BD_ADDR bd_addr;
+ UINT16 attr_id;
+ UINT16 len;
+ BOOLEAN need_confirm;
+ UINT8 value[BTA_GATT_MAX_ATTR_LEN];
+}tBTA_GATTS_API_INDICATION;
+
+typedef struct
+{
+ BT_HDR hdr;
+ UINT32 trans_id;
+ tBTA_GATT_STATUS status;
+ tBTA_GATTS_RSP *p_rsp;
+}tBTA_GATTS_API_RSP;
+
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_GATT_TRANSPORT transport;
+}tBTA_GATTS_API_START;
+
+
+typedef struct
+{
+ BT_HDR hdr;
+ BD_ADDR remote_bda;
+ tBTA_GATTS_IF server_if;
+ BOOLEAN is_direct;
+}tBTA_GATTS_API_OPEN;
+
+typedef tBTA_GATTS_API_OPEN tBTA_GATTS_API_CANCEL_OPEN;
+
+typedef union
+{
+ BT_HDR hdr;
+ tBTA_GATTS_API_REG api_reg;
+ tBTA_GATTS_API_DEREG api_dereg;
+ tBTA_GATTS_API_CREATE_SRVC api_create_svc;
+ tBTA_GATTS_API_ADD_INCL_SRVC api_add_incl_srvc;
+ tBTA_GATTS_API_ADD_CHAR api_add_char;
+ tBTA_GATTS_API_ADD_DESCR api_add_char_descr;
+ tBTA_GATTS_API_START api_start;
+ tBTA_GATTS_API_INDICATION api_indicate;
+ tBTA_GATTS_API_RSP api_rsp;
+ tBTA_GATTS_API_OPEN api_open;
+ tBTA_GATTS_API_CANCEL_OPEN api_cancel_open;
+
+ tBTA_GATTS_INT_START_IF int_start_if;
+} tBTA_GATTS_DATA;
+
+/* application registration control block */
+typedef struct
+{
+ BOOLEAN in_use;
+ tBT_UUID app_uuid;
+ tBTA_GATTS_CBACK *p_cback;
+ tBTA_GATTS_IF gatt_if; //todo cahneg to server_if
+}tBTA_GATTS_RCB;
+
+/* service registration control block */
+typedef struct
+{
+ tBT_UUID service_uuid; /* service UUID */
+ UINT16 service_id; /* service handle */
+ UINT8 inst_num; /* instance ID */
+ UINT8 rcb_idx;
+ UINT8 idx; /* self index of serviec CB */
+ BOOLEAN in_use;
+
+}tBTA_GATTS_SRVC_CB;
+
+
+/* GATT server control block */
+typedef struct
+{
+ BOOLEAN enabled;
+ tBTA_GATTS_RCB rcb[BTA_GATTS_MAX_APP_NUM];
+ tBTA_GATTS_SRVC_CB srvc_cb[BTA_GATTS_MAX_SRVC_NUM];
+}tBTA_GATTS_CB;
+
+
+
+/*****************************************************************************
+** Global data
+*****************************************************************************/
+
+/* GATTC control block */
+#if BTA_DYNAMIC_MEMORY == FALSE
+extern tBTA_GATTS_CB bta_gatts_cb;
+#else
+extern tBTA_GATTS_CB *bta_gatts_cb_ptr;
+ #define bta_gatts_cb (*bta_gatts_cb_ptr)
+#endif
+
+/*****************************************************************************
+** Function prototypes
+*****************************************************************************/
+extern BOOLEAN bta_gatts_hdl_event(BT_HDR *p_msg);
+
+extern void bta_gatts_register(tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA *p_msg);
+extern void bta_gatts_start_if(tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA *p_msg);
+extern void bta_gatts_deregister(tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA *p_msg);
+extern void bta_gatts_create_srvc(tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg);
+extern void bta_gatts_add_include_srvc(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA * p_msg);
+extern void bta_gatts_add_char(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA * p_msg);
+extern void bta_gatts_add_char_descr(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA * p_msg);
+extern void bta_gatts_delete_service(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA * p_msg);
+extern void bta_gatts_start_service(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA * p_msg);
+extern void bta_gatts_stop_service(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA * p_msg);
+
+extern void bta_gatts_send_rsp(tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg);
+extern void bta_gatts_indicate_handle (tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg);
+
+
+extern void bta_gatts_open (tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg);
+extern void bta_gatts_cancel_open (tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg);
+extern void bta_gatts_close (tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg);
+
+extern BOOLEAN bta_gatts_uuid_compare(tBT_UUID tar, tBT_UUID src);
+extern tBTA_GATTS_RCB *bta_gatts_find_app_rcb_by_app_if(tBTA_GATTS_IF server_if);
+extern UINT8 bta_gatts_find_app_rcb_idx_by_app_if(tBTA_GATTS_CB *p_cb, tBTA_GATTS_IF server_if);
+extern UINT8 bta_gatts_alloc_srvc_cb(tBTA_GATTS_CB *p_cb, UINT8 rcb_idx);
+extern tBTA_GATTS_SRVC_CB * bta_gatts_find_srvc_cb_by_srvc_id(tBTA_GATTS_CB *p_cb, UINT16 service_id);
+extern tBTA_GATTS_SRVC_CB * bta_gatts_find_srvc_cb_by_attr_id(tBTA_GATTS_CB *p_cb, UINT16 attr_id);
+
+
+#endif /* BTA_GATTS_INT_H */
+
diff --git a/bta/gatt/bta_gatts_main.c b/bta/gatt/bta_gatts_main.c
new file mode 100644
index 0000000..6870016
--- /dev/null
+++ b/bta/gatt/bta_gatts_main.c
@@ -0,0 +1,122 @@
+/*****************************************************************************
+**
+** Name: bta_gatts_main.c
+**
+** Description: This file contains the GATT server main functions
+** and state machine.
+**
+** Copyright (c) 2003-2010, Broadcom Corp., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+
+#if defined(BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE)
+
+#include <string.h>
+
+#include "bta_gatts_int.h"
+#include "gki.h"
+
+/* type for service building action functions */
+typedef void (*tBTA_GATTS_SRVC_ACT)(tBTA_GATTS_SRVC_CB *p_rcb, tBTA_GATTS_DATA *p_data);
+
+/* service building action function list */
+const tBTA_GATTS_SRVC_ACT bta_gatts_srvc_build_act[] =
+{
+ bta_gatts_add_include_srvc,
+ bta_gatts_add_char,
+ bta_gatts_add_char_descr,
+ bta_gatts_delete_service,
+ bta_gatts_start_service,
+ bta_gatts_stop_service,
+};
+
+/* GATTS control block */
+#if BTA_DYNAMIC_MEMORY == FALSE
+tBTA_GATTS_CB bta_gatts_cb;
+#endif
+
+/*******************************************************************************
+**
+** Function bta_gatts_hdl_event
+**
+** Description BTA GATT server main event handling function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BOOLEAN bta_gatts_hdl_event(BT_HDR *p_msg)
+{
+ tBTA_GATTS_CB *p_cb = &bta_gatts_cb;
+ tBTA_GATTS_SRVC_CB *p_srvc_cb = NULL;
+
+ switch (p_msg->event)
+ {
+ case BTA_GATTS_API_REG_EVT:
+ bta_gatts_register(p_cb, (tBTA_GATTS_DATA *) p_msg);
+ break;
+
+ case BTA_GATTS_INT_START_IF_EVT:
+ bta_gatts_start_if(p_cb, (tBTA_GATTS_DATA *) p_msg);
+ break;
+
+ case BTA_GATTS_API_DEREG_EVT:
+ bta_gatts_deregister(p_cb, (tBTA_GATTS_DATA *) p_msg);
+ break;
+
+ case BTA_GATTS_API_CREATE_SRVC_EVT:
+ bta_gatts_create_srvc(p_cb, (tBTA_GATTS_DATA *) p_msg);
+ break;
+
+ case BTA_GATTS_API_INDICATION_EVT:
+ bta_gatts_indicate_handle(p_cb,(tBTA_GATTS_DATA *) p_msg);
+ break;
+
+ case BTA_GATTS_API_OPEN_EVT:
+ bta_gatts_open(p_cb,(tBTA_GATTS_DATA *) p_msg);
+ break;
+
+ case BTA_GATTS_API_CANCEL_OPEN_EVT:
+ bta_gatts_cancel_open(p_cb,(tBTA_GATTS_DATA *) p_msg);
+ break;
+
+ case BTA_GATTS_API_CLOSE_EVT:
+ bta_gatts_close(p_cb,(tBTA_GATTS_DATA *) p_msg);
+ break;
+
+ case BTA_GATTS_API_RSP_EVT:
+ bta_gatts_send_rsp(p_cb,(tBTA_GATTS_DATA *) p_msg);
+ break;
+
+ case BTA_GATTS_API_ADD_INCL_SRVC_EVT:
+ case BTA_GATTS_API_ADD_CHAR_EVT:
+ case BTA_GATTS_API_ADD_DESCR_EVT:
+ case BTA_GATTS_API_DEL_SRVC_EVT:
+ case BTA_GATTS_API_START_SRVC_EVT:
+ case BTA_GATTS_API_STOP_SRVC_EVT:
+
+ p_srvc_cb = bta_gatts_find_srvc_cb_by_srvc_id(p_cb,
+ ((tBTA_GATTS_DATA *)p_msg)->api_add_incl_srvc.hdr.layer_specific);
+
+ if (p_srvc_cb != NULL)
+ {
+ bta_gatts_srvc_build_act[p_msg->event - BTA_GATTS_API_ADD_INCL_SRVC_EVT](p_srvc_cb, (tBTA_GATTS_DATA *) p_msg);
+ }
+ else
+ {
+ APPL_TRACE_ERROR0("service not created");
+ }
+ break;
+
+ default:
+ break;
+ }
+
+
+ return (TRUE);
+}
+
+#endif /* BTA_GATT_INCLUDED */
diff --git a/bta/gatt/bta_gatts_utils.c b/bta/gatt/bta_gatts_utils.c
new file mode 100644
index 0000000..8f00793
--- /dev/null
+++ b/bta/gatt/bta_gatts_utils.c
@@ -0,0 +1,223 @@
+/*****************************************************************************
+**
+** Name: bta_gattc_utils.c
+**
+** Description: This file contains the GATT client utility
+** function.
+**
+** Copyright (c) 2003-2010, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+
+#if defined(BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE)
+
+#include <string.h>
+#include "utl.h"
+#include "gki.h"
+#include "bta_sys.h"
+#include "bta_gatts_int.h"
+#include "bd.h"
+
+static const UINT8 base_uuid[LEN_UUID_128] = {0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+/*******************************************************************************
+**
+** Function bta_gatt_convert_uuid16_to_uuid128
+**
+** Description Convert a 16 bits UUID to be an standard 128 bits one.
+**
+** Returns TRUE if two uuid match; FALSE otherwise.
+**
+*******************************************************************************/
+static void bta_gatt_convert_uuid16_to_uuid128(UINT8 uuid_128[LEN_UUID_128], UINT16 uuid_16)
+{
+ UINT8 *p = &uuid_128[LEN_UUID_128 - 4];
+
+ memcpy (uuid_128, base_uuid, LEN_UUID_128);
+
+ UINT16_TO_STREAM(p, uuid_16);
+}
+/*******************************************************************************
+**
+** Function bta_gatts_alloc_srvc_cb
+**
+** Description allocate a service control block.
+**
+** Returns pointer to the control block, or otherwise NULL when failed.
+**
+*******************************************************************************/
+UINT8 bta_gatts_alloc_srvc_cb(tBTA_GATTS_CB *p_cb, UINT8 rcb_idx)
+{
+ UINT8 i;
+
+ for (i = 0; i < BTA_GATTS_MAX_SRVC_NUM; i ++)
+ {
+ if (!p_cb->srvc_cb[i].in_use)
+ {
+ p_cb->srvc_cb[i].in_use = TRUE;
+ p_cb->srvc_cb[i].rcb_idx = rcb_idx;
+ return i;
+ }
+ }
+ return BTA_GATTS_INVALID_APP;
+}
+
+/*******************************************************************************
+**
+** Function bta_gatts_find_app_rcb_by_app_if
+**
+** Description find the index of the application control block by app ID.
+**
+** Returns pointer to the control block if success, otherwise NULL
+**
+*******************************************************************************/
+tBTA_GATTS_RCB *bta_gatts_find_app_rcb_by_app_if(tBTA_GATTS_IF server_if)
+{
+ UINT8 i;
+ tBTA_GATTS_RCB *p_reg;
+
+ for (i = 0, p_reg = bta_gatts_cb.rcb; i < BTA_GATTS_MAX_APP_NUM; i ++, p_reg++)
+ {
+ if (p_reg->in_use && p_reg->gatt_if == server_if)
+ return p_reg;
+ }
+ return NULL;
+}
+
+/*******************************************************************************
+**
+** Function bta_gatts_find_app_rcb_idx_by_app_if
+**
+** Description find the index of the application control block by app ID.
+**
+** Returns index of the control block, or BTA_GATTS_INVALID_APP if failed.
+**
+*******************************************************************************/
+
+UINT8 bta_gatts_find_app_rcb_idx_by_app_if(tBTA_GATTS_CB *p_cb, tBTA_GATTS_IF server_if)
+{
+ UINT8 i;
+
+ for (i = 0; i < BTA_GATTS_MAX_APP_NUM; i ++)
+ {
+ if (p_cb->rcb[i].in_use && p_cb->rcb[i].gatt_if == server_if)
+ return i;
+ }
+ return BTA_GATTS_INVALID_APP;
+}
+/*******************************************************************************
+**
+** Function bta_gatts_find_srvc_cb_by_srvc_id
+**
+** Description find the service control block by service ID.
+**
+** Returns pointer to the rcb.
+**
+*******************************************************************************/
+tBTA_GATTS_SRVC_CB * bta_gatts_find_srvc_cb_by_srvc_id(tBTA_GATTS_CB *p_cb, UINT16 service_id)
+{
+ UINT8 i;
+ APPL_TRACE_DEBUG1("bta_gatts_find_srvc_cb_by_srvc_id service_id=%d", service_id);
+ for (i = 0; i < BTA_GATTS_MAX_SRVC_NUM; i ++)
+ {
+ if (p_cb->srvc_cb[i].in_use &&
+ p_cb->srvc_cb[i].service_id == service_id)
+ {
+ APPL_TRACE_DEBUG1("bta_gatts_find_srvc_cb_by_srvc_id found service cb index =%d", i);
+ return &p_cb->srvc_cb[i];
+ }
+ }
+ return NULL;
+}
+/*******************************************************************************
+**
+** Function bta_gatts_find_srvc_cb_by_attr_id
+**
+** Description find the service control block by attribute ID.
+**
+** Returns pointer to the rcb.
+**
+*******************************************************************************/
+tBTA_GATTS_SRVC_CB * bta_gatts_find_srvc_cb_by_attr_id(tBTA_GATTS_CB *p_cb, UINT16 attr_id)
+{
+ UINT8 i;
+
+ for (i = 0; i < (BTA_GATTS_MAX_SRVC_NUM); i ++)
+ {
+ if (/* middle service */
+ (i < (BTA_GATTS_MAX_SRVC_NUM - 1) &&
+ p_cb->srvc_cb[i].in_use &&
+ p_cb->srvc_cb[i + 1].in_use &&
+ attr_id >= p_cb->srvc_cb[i].service_id &&
+ attr_id < p_cb->srvc_cb[i + 1].service_id) ||
+ /* last active service */
+ (i < (BTA_GATTS_MAX_SRVC_NUM - 1) &&
+ p_cb->srvc_cb[i].in_use &&
+ !p_cb->srvc_cb[i + 1].in_use &&
+ attr_id >= p_cb->srvc_cb[i].service_id) ||
+ /* last service incb */
+ (i == (BTA_GATTS_MAX_SRVC_NUM - 1) &&
+ attr_id >= p_cb->srvc_cb[i].service_id)
+ )
+ {
+ return &p_cb->srvc_cb[i];
+ }
+ }
+ return NULL;
+}
+/*******************************************************************************
+**
+** Function bta_gatts_uuid_compare
+**
+** Description Compare two UUID to see if they are the same.
+**
+** Returns TRUE if two uuid match; FALSE otherwise.
+**
+*******************************************************************************/
+BOOLEAN bta_gatts_uuid_compare(tBT_UUID tar, tBT_UUID src)
+{
+ UINT8 su[LEN_UUID_128], tu[LEN_UUID_128];
+ UINT8 *ps, *pt;
+
+ /* any of the UUID is unspecified */
+ if (src.len == 0 || tar.len == 0)
+ {
+ return TRUE;
+ }
+
+ /* If both are 16-bit, we can do a simple compare */
+ if (src.len == 2 && tar.len == 2)
+ {
+ return src.uu.uuid16 == tar.uu.uuid16;
+ }
+
+ /* One or both of the UUIDs is 128-bit */
+ if (src.len == LEN_UUID_16)
+ {
+ /* convert a 16 bits UUID to 128 bits value */
+ bta_gatt_convert_uuid16_to_uuid128(su, src.uu.uuid16);
+ ps = su;
+ }
+ else
+ ps = src.uu.uuid128;
+
+ if (tar.len == LEN_UUID_16)
+ {
+ /* convert a 16 bits UUID to 128 bits value */
+ bta_gatt_convert_uuid16_to_uuid128(tu, tar.uu.uuid16);
+ pt = tu;
+ }
+ else
+ pt = tar.uu.uuid128;
+
+ return(memcmp(ps, pt, LEN_UUID_128) == 0);
+}
+
+
+
+
+#endif
diff --git a/bta/hd/bta_hd_act.c b/bta/hd/bta_hd_act.c
new file mode 100644
index 0000000..0e6393b
--- /dev/null
+++ b/bta/hd/bta_hd_act.c
@@ -0,0 +1,646 @@
+/******************************************************************************
+**
+** File Name: bta_hd_act.c
+**
+** Description: This module contains state machine action functions for
+** the HID Device service.
+**
+** Copyright (c) 2002-2009, Broadcom Corp., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+******************************************************************************/
+
+#include <string.h>
+#include "data_types.h"
+#include "bt_types.h"
+#include "bt_target.h"
+#include "hidd_api.h"
+#include "bta_hd_int.h"
+#include "bta_hd_api.h"
+#include "l2c_api.h"
+#include "btm_api.h"
+#include "bd.h"
+
+
+
+const UINT8 bta_hd_buf_len[] =
+{
+ BTA_HD_KBD_REPT_SIZE, /* BTA_HD_REPT_ID_SPEC 0: other */
+ BTA_HD_KBD_REPT_SIZE, /* BTA_HD_REPT_ID_KBD 1: regular keyboard */
+ BTA_HD_MOUSE_REPT_SIZE /* BTA_HD_REPT_ID_MOUSE 2: mouse */
+};
+
+typedef struct
+{
+ UINT8 modifier;
+ UINT8 reserved;
+ UINT8 keycode_1;
+ UINT8 keycode_2;
+ UINT8 keycode_3;
+ UINT8 keycode_4;
+ UINT8 keycode_5;
+ UINT8 keycode_6;
+} tBTA_HD_KEY_REPORT;
+
+
+#if (BT_USE_TRACES == TRUE)
+const char * bta_hd_ctrl_str [] =
+{
+ "NOP",
+ "HARD_RESET",
+ "SOFT_RESET",
+ "SUSPEND",
+ "EXIT_SUSPEND",
+ "VCAB_UNPLUG"
+};
+
+const char * bta_hd_rept_id_str [] =
+{
+ "MASK",
+ "OTHER",
+ "INPUT",
+ "OUTPUT",
+ "FEATURE"
+};
+
+const char * bta_hd_evt_str [] =
+{
+ "OPEN",
+ "CLOSE",
+ "RETRYING",
+ "MODE_CHG",
+ "PM_FAILED",
+ "CONTROL",
+ "GET_REPORT",
+ "SET_REPORT",
+ "GET_PROTO",
+ "SET_PROTO",
+ "GET_IDLE",
+ "SET_IDLE",
+ "DATA",
+ "DATC",
+ "L2C_CONG",
+};
+#endif
+
+/*******************************************************************************
+**
+** Function bta_hd_kick_timer
+**
+** Description kick the timer in DM for power management
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_hd_kick_timer(tBTA_HD_CB *p_cb)
+{
+ APPL_TRACE_DEBUG0("bta_hd_kick_timer");
+#if (BTM_SSR_INCLUDED == TRUE)
+ if(!p_cb->use_ssr)
+#endif
+ {
+ bta_sys_busy(BTA_ID_HD, p_cb->app_id, p_cb->peer_addr);
+ bta_sys_idle(BTA_ID_HD, p_cb->app_id, p_cb->peer_addr);
+ }
+}
+/*******************************************************************************
+**
+** Function bta_hd_ssr_timer_cback
+**
+** Description Sends disable event to application
+**
+**
+** Returns void
+**
+*******************************************************************************/
+#if (BTM_SSR_INCLUDED == TRUE)
+static void bta_hd_ssr_timer_cback (TIMER_LIST_ENT *p_tle)
+{
+ tBTA_HD_CB *p_cb = (tBTA_HD_CB *)p_tle->param;
+ p_cb->use_ssr = BTA_DmUseSsr(p_cb->peer_addr);
+ APPL_TRACE_DEBUG1("bta_hd_ssr_timer_cback use_ssr:%d", p_cb->use_ssr);
+ bta_sys_idle(BTA_ID_HD, p_cb->app_id, p_cb->peer_addr);
+}
+#endif
+
+/*******************************************************************************
+**
+** Function bta_hd_send_data
+**
+** Description Send data to the connected host
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_hd_send_data(tBTA_HD_CB *p_cb, UINT8 rep_type, UINT16 len, UINT8 *p_data)
+{
+ BT_HDR *p_buf;
+ UINT8 *p;
+
+ p_buf = (BT_HDR *) GKI_getbuf( (UINT16)(L2CAP_MIN_OFFSET+len + 1) );
+ if(p_buf)
+ {
+ p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET+1;
+ memcpy( p, p_data, len);
+ p_buf->len = len;
+ p_buf->offset = L2CAP_MIN_OFFSET+1;
+ HID_DevSendData ( TRUE, rep_type, p_buf );
+ if(p_cb)
+ {
+ bta_hd_kick_timer(p_cb);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_hd_flush_data
+**
+** Description Send the queued data to the connected host
+**
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+static BOOLEAN bta_hd_flush_data(tBTA_HD_CB *p_cb)
+{
+ BT_HDR *p_buf;
+ BOOLEAN set_busy = FALSE;
+
+ while((p_buf = (BT_HDR*)GKI_dequeue (&p_cb->out_q)) != NULL)
+ {
+ if(HID_DevSendData ( FALSE, HID_PAR_REP_TYPE_INPUT, p_buf ) == HID_ERR_CONGESTED)
+ {
+ /* can not send it now. put it back to the queue */
+ GKI_enqueue_head(&p_cb->out_q, p_buf);
+ break;
+ }
+
+ /* sent one packet */
+ set_busy = TRUE;
+ }
+
+ if(set_busy)
+ {
+ bta_hd_kick_timer(p_cb);
+ }
+ return GKI_queue_is_empty(&p_cb->out_q);
+}
+
+/*******************************************************************************
+**
+** Function bta_hd_init_con_act
+**
+** Description Initialize the connection to the known host.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hd_init_con_act(tBTA_HD_CB *p_cb, tBTA_HD_DATA *p_data)
+{
+ APPL_TRACE_DEBUG0("bta_hd_init_con_act");
+ if( HID_DevConnect() != HID_SUCCESS )
+ {
+ bta_hd_sm_execute(p_cb, BTA_HD_DISCONNECTED_EVT, NULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_hd_close_act
+**
+** Description process close API function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hd_close_act(tBTA_HD_CB *p_cb, tBTA_HD_DATA *p_data)
+{
+ APPL_TRACE_DEBUG0("bta_hd_close_act");
+ HID_DevDisconnect();
+}
+
+/*******************************************************************************
+**
+** Function bta_hd_disable_act
+**
+** Description process disable API function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hd_disable_act(tBTA_HD_CB *p_cb, tBTA_HD_DATA *p_data)
+{
+ APPL_TRACE_DEBUG0("bta_hd_disable_act");
+ BTM_SecClrService(BTM_SEC_SERVICE_HID_SEC_CTRL);
+ BTM_SecClrService(BTM_SEC_SERVICE_HID_INTR);
+ if(bta_hd_cb.sdp_handle)
+ {
+ SDP_DeleteRecord(bta_hd_cb.sdp_handle);
+ bta_hd_cb.sdp_handle = 0;
+#if ( BTM_EIR_SERVER_INCLUDED == TRUE )&&(BTA_EIR_CANNED_UUID_LIST != TRUE)
+ bta_sys_remove_uuid(UUID_SERVCLASS_HUMAN_INTERFACE);
+#endif
+ }
+ HID_DevDeregister();
+}
+
+/*******************************************************************************
+**
+** Function bta_hd_open_act
+**
+** Description received connected event from HIDD. report to user
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hd_open_act(tBTA_HD_CB *p_cb, tBTA_HD_DATA *p_data)
+{
+ BD_ADDR_PTR p_addr = p_data->cback_data.pdata->host_bdaddr;
+#if (BTM_SSR_INCLUDED == TRUE)
+ UINT8 *p;
+#endif
+
+ p_cb->proto = HID_PAR_PROTOCOL_REPORT; /* the default is report mode */
+ bdcpy(p_cb->peer_addr, p_addr);
+ /* inform role manager */
+ bta_sys_conn_open( BTA_ID_HD ,p_cb->app_id, p_addr);
+#if (BTM_SSR_INCLUDED == TRUE)
+ p_cb->timer.param = (UINT32)p_cb;
+ p_cb->timer.p_cback = (TIMER_CBACK*)&bta_hd_ssr_timer_cback;
+ bta_sys_start_timer(&p_cb->timer, 0, 6000);
+ p_cb->use_ssr = FALSE;
+ if( ((NULL != (p = BTM_ReadLocalFeatures ())) && HCI_SNIFF_SUB_RATE_SUPPORTED(p)) &&
+ ((NULL != (p = BTM_ReadRemoteFeatures (p_addr))) && HCI_SNIFF_SUB_RATE_SUPPORTED(p)) )
+ {
+ /* both local and remote devices support SSR */
+ p_cb->use_ssr = TRUE;
+ }
+#endif
+ p_cb->p_cback(BTA_HD_OPEN_EVT, (tBTA_HD *)p_addr);
+}
+
+/*******************************************************************************
+**
+** Function bta_hd_opn_cb_act
+**
+** Description process events from HIDD in open state.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hd_opn_cb_act(tBTA_HD_CB *p_cb, tBTA_HD_DATA *p_data)
+{
+ UINT8 res_code;
+ BOOLEAN *p_cong;
+ tHID_DEV_DSCP_INFO *p_info;
+ tBTA_HD_CBACK_DATA *p_evt = (tBTA_HD_CBACK_DATA *)p_data;
+ BOOLEAN set_busy = TRUE;
+ tBTA_HD_REPORT rpt;
+ UINT8 evt;
+ BT_HDR *p_buf;
+
+ switch(p_evt->event)
+ {
+ case HID_DEV_EVT_CONTROL: /* Host sent HID_CONTROL Data=Control Operation */
+ if(p_evt->data == HID_PAR_CONTROL_VIRTUAL_CABLE_UNPLUG)
+ {
+ p_cb->p_cback(BTA_HD_UNPLUG_EVT, NULL);
+ set_busy = FALSE;
+ }
+ else if(p_evt->data == HID_PAR_CONTROL_SUSPEND)
+ {
+ bta_sys_idle(BTA_ID_HD, p_cb->app_id, p_cb->peer_addr);
+ set_busy = FALSE;
+ }
+ break;
+
+ case HID_DEV_EVT_GET_REPORT:/*Host sent GET_REPORT Data=Length pdata=structure
+ having details of get-report.*/
+ /* bta_hd_hidd_cback sends SM event only when
+ ((tHID_DEV_GET_REP_DATA *)p_data))->rep_type == HID_PAR_REP_TYPE_FEATURE */
+ p_info = &p_bta_hd_cfg->sdp_info.dscp_info;
+ bta_hd_send_data(p_cb, HID_PAR_REP_TYPE_FEATURE, p_info->dl_len, p_info->dsc_list);
+ break;
+
+ case HID_DEV_EVT_GET_PROTO:/*Host sent GET_PROTOCOL Data=NA*/
+ res_code = p_cb->proto; /* the protocol (Report or Boot) mode from control block */
+ bta_hd_send_data(p_cb, HID_PAR_REP_TYPE_OTHER, 1, &res_code);
+ break;
+
+ case HID_DEV_EVT_SET_PROTO:/*Host sent SET_PROTOCOL Data=1 for Report, 0 for Boot*/
+ if((p_evt->data == HID_PAR_PROTOCOL_REPORT) || (p_evt->data == HID_PAR_PROTOCOL_BOOT_MODE))
+ {
+ p_cb->proto = p_evt->data;
+ res_code = HID_PAR_HANDSHAKE_RSP_SUCCESS;
+ }
+ else
+ res_code = HID_PAR_HANDSHAKE_RSP_ERR_UNSUPPORTED_REQ;
+ HID_DevHandShake(res_code);
+ break;
+
+ case HID_DEV_EVT_L2CAP_CONGEST:
+ p_cong = (BOOLEAN *)p_evt->pdata;
+ if(*p_cong == FALSE)
+ {
+ /* L2CAP is uncongested, send out the queued buffers */
+ bta_hd_flush_data(p_cb);
+ set_busy = FALSE;
+ }
+ break;
+
+ case HID_DEV_EVT_DATA:
+ case HID_DEV_EVT_DATC:
+ evt = (p_evt->event == HID_DEV_EVT_DATA) ? BTA_HD_DATA_EVT: BTA_HD_DATC_EVT;
+ if(p_evt->pdata)
+ {
+ if(p_evt->data == HID_PAR_REP_TYPE_OUTPUT)
+ {
+ p_buf = p_evt->pdata->buffer;
+
+ rpt.p_data = (UINT8 *)(p_buf + 1) + p_buf->offset + 1;
+ rpt.len = p_buf->len - 1;
+
+ p_cb->p_cback(evt, (tBTA_HD *)&rpt);
+ }
+
+ GKI_freebuf (p_evt->pdata->buffer);
+ }
+ break;
+ }
+
+ if(set_busy)
+ {
+ bta_hd_kick_timer(p_cb);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_hd_input_act
+**
+** Description received input event from user. send to peer
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hd_input_act(tBTA_HD_CB *p_cb, tBTA_HD_DATA *p_data)
+{
+ tBTA_HD_API_INPUT_SPEC *p_spec = (tBTA_HD_API_INPUT_SPEC *)p_data;
+ tBTA_HD_API_INPUT *p_input = (tBTA_HD_API_INPUT *)p_data;
+ tBTA_HD_KEY_REPORT key_buf = {0};
+ UINT16 len = bta_hd_buf_len[p_input->rid];
+ UINT16 size;
+ BT_HDR *p_buf;
+ UINT8 *p;
+ int temp;
+ BOOLEAN release = FALSE;
+
+ if(p_input->rid == BTA_HD_REPT_ID_SPEC)
+ len = BTA_HD_KBD_REPT_SIZE;
+ size = L2CAP_MIN_OFFSET + sizeof(BT_HDR) + len;
+
+ if ( (p_buf = (BT_HDR *)GKI_getbuf(size)) == NULL )
+ return;
+
+ p_buf->offset = L2CAP_MIN_OFFSET+1;
+ p = (UINT8 *) ((UINT8 *) (p_buf+1))+L2CAP_MIN_OFFSET+1;
+ *p++ = p_input->rid;
+ switch(p_input->rid)
+ {
+ case BTA_HD_REPT_ID_SPEC:
+ p--;
+ memcpy(p, p_spec->seq, p_spec->len);
+ /* use the proper report ID type for the key release */
+ p_input->rid = *p;
+ temp = BTA_HD_KBD_REPT_SIZE - p_spec->len;
+ if(temp > 0)
+ memset(p + p_spec->len, 0, temp);
+ release = p_spec->release;
+ break;
+
+ case BTA_HD_REPT_ID_KBD: /* 1: regular keyboard */
+ key_buf.keycode_1 = p_input->keyCode;
+ key_buf.modifier = p_input->buttons;
+ memcpy(p, (void *)&key_buf, len-1);
+ release = p_input->release;
+ break;
+
+ case BTA_HD_REPT_ID_MOUSE: /* 2: mouse */
+ *p++ = p_input->buttons;
+ *p++ = p_input->keyCode; /* x */
+ *p++ = p_input->keyCode2; /* y */
+ *p++ = p_input->wheel;
+ break;
+
+ default:
+ GKI_freebuf(p_buf);
+ return;
+ }
+ p_buf->len = len;
+
+ GKI_enqueue(&p_cb->out_q, p_buf);
+
+ if(release)
+ {
+ /* key release event */
+ if ( (p_buf = (BT_HDR *)GKI_getbuf(size)) == NULL )
+ return;
+
+ p_buf->offset = L2CAP_MIN_OFFSET+1;
+ p_buf->len = len;
+ p = (UINT8 *) ((UINT8 *) (p_buf+1))+L2CAP_MIN_OFFSET+1;
+ *p++ = p_input->rid;
+ memset(p, 0, p_buf->len-1);
+ GKI_enqueue(&p_cb->out_q, p_buf);
+ }
+ bta_hd_flush_data(p_cb);
+}
+
+/*******************************************************************************
+**
+** Function bta_hd_discntd_act
+**
+** Description received disconnected event from HIDD. report to user
+** The connection was not open yet at this action
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hd_discntd_act(tBTA_HD_CB *p_cb, tBTA_HD_DATA *p_data)
+{
+#if (BTM_SSR_INCLUDED == TRUE)
+ bta_sys_stop_timer(&p_cb->timer);
+#endif
+
+ /* inform role manager */
+ bta_sys_conn_close( BTA_ID_HD ,p_cb->app_id, p_cb->peer_addr);
+ p_cb->p_cback(BTA_HD_CLOSE_EVT, (tBTA_HD *)p_cb->peer_addr);
+}
+
+/*******************************************************************************
+**
+** Function bta_hd_discnt_act
+**
+** Description received disconnected event from HIDD. report to user
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hd_discnt_act(tBTA_HD_CB *p_cb, tBTA_HD_DATA *p_data)
+{
+ BT_HDR *p_buf;
+
+#if (BTM_SSR_INCLUDED == TRUE)
+ bta_sys_stop_timer(&p_cb->timer);
+#endif
+
+ /* clean out queue */
+ while((p_buf = (BT_HDR*)GKI_dequeue (&p_cb->out_q)) != NULL)
+ GKI_freebuf(p_buf);
+
+ /* inform role manager */
+ bta_sys_conn_close( BTA_ID_HD ,p_cb->app_id, p_cb->peer_addr);
+ p_cb->p_cback(BTA_HD_CLOSE_EVT, (tBTA_HD *)p_cb->peer_addr);
+}
+
+/*******************************************************************************
+**
+** Function bta_hd_hidd_cback
+**
+** Description This is the HIDD callback function to process events from HIDD.
+** just post a message to BTA_HD
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hd_hidd_cback(UINT8 event, UINT32 data, tHID_DEV_CBACK_DATA *pdata)
+{
+ tBTA_HD_CBACK_DATA *p_buf;
+ tHID_DEV_GET_REP_DATA *pget_rep;
+ UINT16 sm_evt = BTA_HD_INVALID_EVT;
+ UINT8 res_code;
+
+#if (BT_USE_TRACES == TRUE)
+ APPL_TRACE_EVENT3("HID event=0x%x(%s), data: %d", event, bta_hd_evt_str[event], data);
+#endif
+
+ switch( event )
+ {
+ case HID_DEV_EVT_OPEN: /*Connected to host Data = 1 if Virtual Cable
+ with Interrupt and Control
+ Channels in OPEN state. pdata = Host BD-Addr.*/
+ sm_evt = BTA_HD_CONNECTED_EVT;
+ break;
+
+ case HID_DEV_EVT_CLOSE: /*Connection with host is closed. Data=Reason Code. */
+ sm_evt = BTA_HD_DISCONNECTED_EVT;
+ break;
+
+ /*case HID_DEV_EVT_RETRYING: Data=Retrial number
+ Lost connection is being re-connected.
+ MSKB_TRACE_0("HID_DEV_EVT_RETRYING");
+ break; */
+
+ /*case HID_DEV_EVT_MODE_CHG: Device changed power mode. Data=new power mode
+ APPL_TRACE_DEBUG1("Mode change - %d", data);
+ break; */
+
+ /*case HID_DEV_EVT_PM_FAILED: Host sent SET_IDLE Data=Idle Rate
+ MSKB_TRACE_0("PM - Failed");
+ break; */
+
+ case HID_DEV_EVT_CONTROL: /* Host sent HID_CONTROL Data=Control Operation */
+#if (BT_USE_TRACES == TRUE)
+ APPL_TRACE_DEBUG2("EVT_CONTROL:%d(%s)",data, bta_hd_ctrl_str[data]);
+#endif
+ switch(data)
+ {
+ case HID_PAR_CONTROL_VIRTUAL_CABLE_UNPLUG:
+ case HID_PAR_CONTROL_SUSPEND:
+ case HID_PAR_CONTROL_EXIT_SUSPEND:
+ sm_evt = BTA_HD_CBACK_EVT ;
+ HID_DevHandShake(HID_PAR_HANDSHAKE_RSP_SUCCESS);
+ break;
+ default:
+ HID_DevHandShake(HID_PAR_HANDSHAKE_RSP_ERR_UNSUPPORTED_REQ);
+ }
+ break;
+
+ case HID_DEV_EVT_GET_REPORT:/*Host sent GET_REPORT Data=Length pdata=structure
+ having details of get-report.*/
+ pget_rep = (tHID_DEV_GET_REP_DATA *) pdata;
+ APPL_TRACE_DEBUG3("RepType:%d(%s), id:%d",pget_rep->rep_type,
+ bta_hd_rept_id_str[pget_rep->rep_type], pget_rep->rep_id);
+
+ if(pget_rep->rep_type == HID_PAR_REP_TYPE_FEATURE)
+ {
+ sm_evt = BTA_HD_CBACK_EVT ;
+ }
+ else
+ {
+ HID_DevHandShake(HID_PAR_HANDSHAKE_RSP_ERR_UNSUPPORTED_REQ);
+ }
+ break;
+ case HID_DEV_EVT_SET_REPORT:/*Host sent SET_REPORT Data=Length pdata=details.*/
+ HID_DevHandShake(HID_PAR_HANDSHAKE_RSP_ERR_UNSUPPORTED_REQ);
+ APPL_TRACE_EVENT0("HID_DEV_EVT_SET_REPORT");
+ GKI_freebuf (pdata->buffer);
+ break;
+ case HID_DEV_EVT_GET_PROTO:/*Host sent GET_PROTOCOL Data=NA*/
+ sm_evt = BTA_HD_CBACK_EVT ;
+ break;
+ case HID_DEV_EVT_SET_PROTO:/*Host sent SET_PROTOCOL Data=1 for Report, 0 for Boot*/
+ sm_evt = BTA_HD_CBACK_EVT ;
+ break;
+ case HID_DEV_EVT_GET_IDLE:/* Host sent GET_IDLE Data=NA */
+ /* only support infinite idle rate (= 0) */
+ res_code = 0;
+ bta_hd_send_data(NULL, HID_PAR_REP_TYPE_OTHER, 1, &res_code);
+ break;
+ case HID_DEV_EVT_SET_IDLE: /* Host sent SET_IDLE Data=Idle Rate */
+ res_code = HID_PAR_HANDSHAKE_RSP_ERR_INVALID_PARAM;
+ if( data == 0 ) /* only support infinite idle rate (= 0) */
+ res_code = HID_PAR_HANDSHAKE_RSP_SUCCESS;
+ HID_DevHandShake(res_code);
+ break;
+ case HID_DEV_EVT_L2CAP_CONGEST:
+ sm_evt = BTA_HD_CBACK_EVT ;
+ break;
+ case HID_DEV_EVT_DATA:
+ case HID_DEV_EVT_DATC:
+ APPL_TRACE_EVENT1("HID_DEV_EVT_DATC/DATC event = %s", bta_hd_evt_str[event]);
+ sm_evt = BTA_HD_CBACK_EVT ;
+ break;
+ }
+
+ if ((sm_evt != BTA_HD_INVALID_EVT) &&
+ (p_buf = (tBTA_HD_CBACK_DATA *) GKI_getbuf(
+ (UINT16)(sizeof(tBTA_HD_CBACK_DATA)+sizeof(tHID_DEV_CBACK_DATA)))) != NULL)
+ {
+ p_buf->hdr.event = sm_evt;
+ p_buf->event = event;
+ p_buf->data = data;
+ if(pdata)
+ {
+ p_buf->pdata = (tHID_DEV_CBACK_DATA *)(p_buf + 1);
+ memcpy(p_buf->pdata, pdata, sizeof(tHID_DEV_CBACK_DATA));
+ }
+ else
+ {
+ p_buf->pdata = NULL;
+ }
+ bta_sys_sendmsg(p_buf);
+ }
+
+
+}
+
diff --git a/bta/hd/bta_hd_api.c b/bta/hd/bta_hd_api.c
new file mode 100644
index 0000000..6709c1d
--- /dev/null
+++ b/bta/hd/bta_hd_api.c
@@ -0,0 +1,236 @@
+/******************************************************************************
+**
+** File Name: bta_hd_api.c
+**
+** Description: This is the API functions for the HID Device
+** service.
+**
+** Copyright (c) 2002-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+******************************************************************************/
+
+#include "bta_api.h"
+#include "bd.h"
+#include "bta_sys.h"
+#include "bta_hd_api.h"
+#include "bta_hd_int.h"
+#include "gki.h"
+#include <string.h>
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+static const tBTA_SYS_REG bta_hd_reg =
+{
+ bta_hd_hdl_event,
+ BTA_HdDisable
+};
+
+/*******************************************************************************
+**
+** Function BTA_HdEnable
+**
+** Description Enable the HID Device service. When the enable
+** operation is complete the callback function will be
+** called with a BTA_HD_ENABLE_EVT. This function must
+** be called before other function in the HD API are
+** called.
+**
+** If all bytes of the specified bd_addr are 0xff, the
+** peer address is considered as unknown. The HID device listens
+** for incoming connection request.
+** Otherwise, The HID device initiates a connection toward the
+** specified bd_addr when BTA_HdOpen() is called.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_HdEnable(BD_ADDR bd_addr, tBTA_SEC sec_mask, const char *p_service_name,
+ tBTA_HD_CBACK *p_cback, UINT8 app_id)
+{
+ tBTA_HD_API_ENABLE *p_buf;
+
+
+ /* register with BTA system manager */
+ GKI_sched_lock();
+ bta_sys_register(BTA_ID_HD, &bta_hd_reg);
+ GKI_sched_unlock();
+
+ if ((p_buf = (tBTA_HD_API_ENABLE *) GKI_getbuf(sizeof(tBTA_HD_API_ENABLE))) != NULL)
+ {
+ p_buf->hdr.event = BTA_HD_API_ENABLE_EVT;
+ p_buf->app_id = app_id;
+ if(p_service_name)
+ {
+ BCM_STRNCPY_S(p_buf->service_name, sizeof(p_buf->service_name), p_service_name, BTA_SERVICE_NAME_LEN);
+ p_buf->service_name[BTA_SERVICE_NAME_LEN] = 0;
+ }
+ else
+ {
+ p_buf->service_name[0] = 0;
+ }
+ p_buf->p_cback = p_cback;
+ bdcpy(p_buf->bd_addr, bd_addr);
+ p_buf->sec_mask = sec_mask;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_HdDisable
+**
+** Description Disable the HID Device service.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_HdDisable(void)
+{
+ BT_HDR *p_buf;
+
+ bta_sys_deregister(BTA_ID_HD);
+ if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->event = BTA_HD_API_DISABLE_EVT;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_HdOpen
+**
+** Description Opens an HID Device connection to a peer device.
+** When connection is open, callback function is called
+** with a BTA_HD_OPEN_EVT.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_HdOpen(tBTA_SEC sec_mask)
+{
+ tBTA_HD_API_OPEN *p_buf;
+
+ if ((p_buf = (tBTA_HD_API_OPEN *) GKI_getbuf(sizeof(tBTA_HD_API_OPEN))) != NULL)
+ {
+ p_buf->hdr.event = BTA_HD_API_OPEN_EVT;
+ p_buf->sec_mask = sec_mask;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_HdClose
+**
+** Description Close the current connection a peer device.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_HdClose(void)
+{
+ BT_HDR *p_buf;
+
+ if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->event = BTA_HD_API_CLOSE_EVT;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function BTA_HdSendRegularKey
+**
+** Description Send a key report to the connected host.
+** If auto_release is TRUE, assume the keyboard report must be
+** a key press. An associated key release report is also sent.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_HdSendRegularKey (UINT8 modifier, UINT8 key_code, BOOLEAN auto_release)
+{
+ tBTA_HD_API_INPUT *p_buf;
+
+ if ((p_buf = (tBTA_HD_API_INPUT *) GKI_getbuf(sizeof(tBTA_HD_API_INPUT))) != NULL)
+ {
+ p_buf->hdr.event = BTA_HD_API_INPUT_EVT;
+ p_buf->rid = BTA_HD_REPT_ID_KBD;
+ p_buf->keyCode = key_code;
+ p_buf->buttons = modifier;
+ p_buf->release = auto_release;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_HdSendSpecialKey
+**
+** Description Send a special key report to the connected host.
+** The report is sent as a keyboard report.
+** If auto_release is TRUE, assume the keyboard report must be
+** a key press. An associated key release report is also sent.
+** If key_len is less than BTA_HD_KBD_REPT_SIZE, the key_seq
+** is padded with 0 until BTA_HD_KBD_REPT_SIZE.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_HdSendSpecialKey (UINT8 key_len, UINT8 * key_seq, BOOLEAN auto_release)
+{
+ tBTA_HD_API_INPUT_SPEC *p_buf;
+
+ if ((p_buf = (tBTA_HD_API_INPUT_SPEC *) GKI_getbuf(
+ (UINT16)(sizeof(tBTA_HD_API_INPUT_SPEC)+key_len))) != NULL)
+ {
+ p_buf->hdr.event = BTA_HD_API_INPUT_EVT;
+ p_buf->rid = BTA_HD_REPT_ID_SPEC;
+ p_buf->len = key_len;
+ p_buf->seq = (UINT8 *)(p_buf+1);
+ p_buf->release = auto_release;
+ memcpy(p_buf->seq, key_seq, key_len);
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_HdSendMouseReport
+**
+** Description Send a mouse report to the connected host
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_HdSendMouseReport (UINT8 is_left, UINT8 is_right, UINT8 is_middle,
+ INT8 delta_x, INT8 delta_y, INT8 delta_wheel)
+{
+ tBTA_HD_API_INPUT *p_buf;
+
+ if ((p_buf = (tBTA_HD_API_INPUT *) GKI_getbuf(sizeof(tBTA_HD_API_INPUT))) != NULL)
+ {
+ p_buf->hdr.event = BTA_HD_API_INPUT_EVT;
+ p_buf->rid = BTA_HD_REPT_ID_MOUSE;
+ p_buf->keyCode = (UINT8)delta_x;
+ p_buf->keyCode2 = (UINT8)delta_y;
+ p_buf->buttons = (is_left ? 0x01 : 0x00) |
+ (is_right ? 0x02 : 0x00) |
+ (is_middle ? 0x04 : 0x00);
+ p_buf->wheel = (UINT8)delta_wheel;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+
+
diff --git a/bta/hd/bta_hd_cfg.c b/bta/hd/bta_hd_cfg.c
new file mode 100644
index 0000000..4256ba2
--- /dev/null
+++ b/bta/hd/bta_hd_cfg.c
@@ -0,0 +1,151 @@
+/*****************************************************************************
+**
+** Name: bta_hd_cfg.c
+**
+** Description: This file contains compile-time configurable constants
+** for HID Device
+**
+** Copyright (c) 2004, Widcomm Inc., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "gki.h"
+#include "bta_api.h"
+#include "bd.h"
+#include "bta_hd_api.h"
+
+const UINT8 bta_hd_cfg_report[] =
+{
+ 0x05, 0x01, /* Usage page Desktop 01 */
+ 0x09, 0x06, /* Usage Keyboard 06 */
+ 0xa1, 0x01, /* Collection appliction */
+ 0x05, 0x07, /* Usage page Keyboard */
+ 0x85, BTA_HD_REPT_ID_KBD, /* Report ID 1 */
+ 0x19, 0xe0, /* Usage minimum e0 (leftControl) */
+ 0x29, 0xe7, /* Usage maximum e7 (right gui) */
+ 0x15, 0x00, /* Logical mimumum 0 */
+ 0x25, 0x01, /* Logical Maximum 1 */
+ 0x75, 0x01, /* Report size 1 */
+ 0x95, 0x08, /* Report count 8 */
+ 0x81, 0x02, /* Input Variable Abs */
+ 0x95, 0x01, /* Report count 1 */
+ 0x75, 0x08, /* Report size 8 */
+ 0x81, 0x01, /* Iput constant variable */
+ 0x95, 0x05, /* report count 5 */
+ 0x75, 0x01, /* Report size 1 */
+ 0x05, 0x08, /* LED page */
+ 0x19, 0x01, /* Usage minimum 1 Num lock */
+ 0x29, 0x05, /* Usage maximum 5 Kana */
+ 0x91, 0x02, /* Output Data, Variable, Absolute */
+ 0x95, 0x01, /* Report Count 1 */
+ 0x75, 0x03, /* Report Size 3 */
+ 0x91, 0x01, /* Output constant, Absolute */
+ 0x95, 0x06, /* Report Count 6 */
+ 0x75, 0x08, /* Report size 8 */
+ 0x15, 0x00, /* Logical mimumum 0 */
+ 0x26, 0xa4, 0x00, /* Logical Maximum 00a4 */
+ 0x05, 0x07, /* Usage page Keyboard */
+ 0x19, 0x00, /* Usage minimum 0 */
+ 0x29, 0xa4, /* Usage maximum a4 */
+ 0x81, 0x00, /* Input data array absolute */
+ 0xc0,
+
+ 0x05, 0x01, /* Usage page Desktop 01 */
+ 0x09, 0x02, /* Usage 2 Mouse */
+ 0xa1, 0x01, /* Collection appliction */
+ 0x09, 0x01, /* Usage 1 pointer */
+ 0xa1, 0x00, /* Collection physical */
+ 0x85, BTA_HD_REPT_ID_MOUSE, /* report id 2 */
+ 0x05, 0x09, /* Usage page button */
+ 0x19, 0x01, /* Usage minimum 1 */
+ 0x29, 0x03, /* Usage maximum 3 */
+ 0x15, 0x00, /* Logical mimumum 0 */
+ 0x25, 0x01, /* Logical Maximum 1 */
+ 0x95, 0x03, /* Report Count 3 */
+ 0x75, 0x01, /* Report size 1 */
+ 0x81, 0x02, /* Input Variable Abs */
+ 0x95, 0x01, /* Report Count 1 */
+ 0x75, 0x05, /* Report size 5 */
+ 0x81, 0x03, /* Input const var Abs */
+
+ 0x05, 0x01, /* Usage page Desktop 01 */
+ 0x09, 0x30, /* Usage X */
+ 0x09, 0x31, /* Usage Y */
+ 0x09, 0x38, /* Usage Wheel */
+ 0x15, 0x81, /* Logical mimumum -127 */
+ 0x25, 0x7f, /* Logical Maximum 127 */
+ 0x75, 0x08, /* Report size 8 */
+ 0x95, 0x03, /* Report Count 3 */
+ 0x81, 0x06, /* Input Variable relative */
+ 0xc0,
+ 0xc0,
+
+ 0x05, 0x0c, /* Usage page (consumer page) */
+ 0x09, 0x01, /* Usage Consumer control */
+ 0xa1, 0x01, /* Collection appliction */
+ 0x85, BTA_HD_REPT_ID_CONSUMER, /* Report ID 3 */
+ 0x75, 0x10, /* report size 16 */
+ 0x95, 0x02, /* report count 2 */
+ 0x15, 0x01, /* Logical mimumum 1 */
+ 0x26, 0x8c, 0x02, /* Logical Maximum 028c */
+ 0x19, 0x01, /* Usage minimum 1 */
+ 0x2a, 0x8c, 0x02, /* Usage maximum 028c */
+ 0x81, 0x60, /* Input Data array absolute No preferred, Null state */
+ 0xc0,
+};
+
+
+const tBTA_HD_CFG bta_hd_cfg =
+{
+ {
+ {
+ 0, /* qos_flags */
+ 1, /* service type */
+ 800, /* token rate (bytes/second) */
+ 8, /* token_bucket_size (bytes) */
+ 0, /* peak_bandwidth (bytes/second) */
+ 0xffffffff, /* latency(microseconds) */
+ 0xffffffff /* delay_variation(microseconds) */
+ }, /* ctrl_ch */
+ {
+ 0, /* qos_flags */
+ 1, /* service type */
+ 300, /* token rate (bytes/second) */
+ 4, /* token_bucket_size (bytes) */
+ 300, /* peak_bandwidth (bytes/second) */
+ 10000, /* latency(microseconds) */
+ 10000 /* delay_variation(microseconds) */
+ }, /* int_ch */
+ {
+ 0, /* qos_flags */
+ 2, /* service type */
+ 400, /* token rate (bytes/second) */
+ 8, /* token_bucket_size (bytes) */
+ 800, /* peak_bandwidth (bytes/second) */
+ 10000, /* latency(microseconds) */
+ 10000 /* delay_variation(microseconds) */
+ } /* hci */
+ }, /* qos */
+ {
+ "BTA HID Device", /* Service name */
+ "Remote Control", /* Service Description */
+ "Broadcom Corp", /* Provider Name.*/
+ 0x0100, /* HID device release number */
+ 0x0111, /* HID Parser Version.*/
+ HID_SSR_PARAM_INVALID, /* SSR max latency */
+ HID_SSR_PARAM_INVALID, /* SSR min timeout */
+ BTM_COD_MINOR_COMBO,/*Device Subclass.*/
+ 0, /* Country Code. (0 for not localized) */
+ 0, /* Supervisory Timeout */
+ {
+ sizeof(bta_hd_cfg_report), /* size of report descriptor */
+ (UINT8 *)bta_hd_cfg_report,/* config report descriptor */
+ }, /* dscp_info */
+ 0 /* p_sdp_layer_rec */
+ }, /* sdp info */
+ 1 /* use QoS */
+};
+
+tBTA_HD_CFG *p_bta_hd_cfg = (tBTA_HD_CFG *) &bta_hd_cfg;
+
diff --git a/bta/hd/bta_hd_int.h b/bta/hd/bta_hd_int.h
new file mode 100644
index 0000000..4ea5365
--- /dev/null
+++ b/bta/hd/bta_hd_int.h
@@ -0,0 +1,166 @@
+/******************************************************************************
+**
+** File Name: bta_hd_int.h
+**
+** Description: This is the internal header file for the HID Device service.
+**
+** Copyright (c) 2002-2009, Broadcom Corp., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+******************************************************************************/
+
+#ifndef BTA_HD_INT_H
+#define BTA_HD_INT_H
+
+#include "bt_types.h"
+#include "gki.h"
+#include "bta_sys.h"
+#include "bta_hd_api.h"
+
+
+/*****************************************************************************/
+/* C O N S T A N T S */
+/*****************************************************************************/
+
+#define BTA_HD_KEYBOARD_REPORT_SIZE 0x3F
+#define BTA_HD_MOUSE_REPORT_SIZE 0x32
+
+/* BTA_HD State machine events */
+enum
+{
+ /* these events are handled by the state machine */
+ BTA_HD_API_OPEN_EVT = BTA_SYS_EVT_START(BTA_ID_HD),
+ BTA_HD_API_CLOSE_EVT,
+ BTA_HD_API_DISABLE_EVT,
+ BTA_HD_API_INPUT_EVT,
+ BTA_HD_CBACK_EVT,
+ BTA_HD_CONNECTED_EVT,
+ BTA_HD_DISCONNECTED_EVT,
+
+ /* these events are handled outside of the state machine */
+ BTA_HD_API_ENABLE_EVT
+};
+#define BTA_HD_INVALID_EVT (BTA_HD_API_ENABLE_EVT + 1)
+
+/*****************************************************************************
+** Data types
+*****************************************************************************/
+
+/* data type for BTA_HD_API_ENABLE_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ char service_name[BTA_SERVICE_NAME_LEN+1];
+ tBTA_HD_CBACK *p_cback;
+ BD_ADDR bd_addr;
+ tBTA_SEC sec_mask;
+ UINT8 app_id;
+} tBTA_HD_API_ENABLE;
+
+/* data type for BTA_HD_API_OPEN_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_SEC sec_mask;
+} tBTA_HD_API_OPEN;
+
+
+/* data type for BTA_HD_API_INPUT_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_HD_REPT_ID rid;
+ UINT8 keyCode; /* if BTA_HD_REPT_ID_MOUSE, X */
+ UINT8 keyCode2; /* if BTA_HD_REPT_ID_MOUSE, Y */
+ UINT8 wheel; /* BTA_HD_REPT_ID_MOUSE only */
+ UINT8 buttons; /* BTA_HD_REPT_ID_MOUSE & BTA_HD_REPT_ID_KBD (modifier) only */
+ BOOLEAN release; /* If TRUE, HD sends release key. not used by mouse report */
+} tBTA_HD_API_INPUT;
+
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_HD_REPT_ID rid;
+ UINT8 len;
+ UINT8 *seq;
+ BOOLEAN release; /* If TRUE, HD sends release key. */
+} tBTA_HD_API_INPUT_SPEC;
+
+/* data type for BTA_HD_CBACK_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ UINT8 event;
+ UINT32 data;
+ tHID_DEV_CBACK_DATA *pdata;
+} tBTA_HD_CBACK_DATA;
+
+/* union of all event datatypes */
+typedef union
+{
+ tBTA_HD_API_ENABLE api_enable;
+ tBTA_HD_API_OPEN api_open;
+ tBTA_HD_API_INPUT api_input;
+ tBTA_HD_API_INPUT_SPEC api_spec;
+ tBTA_HD_CBACK_DATA cback_data;
+} tBTA_HD_DATA;
+
+
+/* type for HD control block */
+typedef struct
+{
+ BD_ADDR peer_addr; /* peer BD address */
+ UINT32 sdp_handle; /* SDP record handle */
+ tBTA_HD_CBACK *p_cback; /* application callback function */
+ BUFFER_Q out_q; /* Queue for reports */
+ tBTA_SEC sec_mask; /* security mask */
+ UINT8 state; /* state machine state */
+ UINT8 proto; /* protocol (boot or report) */
+ UINT8 app_id;
+#if (BTM_SSR_INCLUDED == TRUE)
+ BOOLEAN use_ssr; /* TRUE, if SSR is supported on this link */
+ TIMER_LIST_ENT timer; /* delay timer to check for SSR */
+#endif
+} tBTA_HD_CB;
+
+/*****************************************************************************/
+/* P U B L I C D A T A */
+/*****************************************************************************/
+
+/*****************************************************************************
+** Global data
+*****************************************************************************/
+
+/* control block declaration */
+#if BTA_DYNAMIC_MEMORY == FALSE
+extern tBTA_HD_CB bta_hd_cb;
+#else
+extern tBTA_HD_CB *bta_hd_cb_ptr;
+#define bta_hd_cb (*bta_hd_cb_ptr)
+#endif
+
+/* config struct */
+extern tBTA_HD_CFG *p_bta_hd_cfg;
+
+/* rc id config struct */
+extern UINT16 *p_bta_hd_rc_id;
+
+/*****************************************************************************/
+/* F U N C T I O N P R O T O T Y P E S */
+/*****************************************************************************/
+
+/* from bta_hd_main.c */
+extern BOOLEAN bta_hd_hdl_event(BT_HDR *p_msg);
+extern void bta_hd_sm_execute(tBTA_HD_CB *p_cb, UINT16 event, tBTA_HD_DATA *p_data);
+/* from bta_hd_act.c */
+extern void bta_hd_init_con_act(tBTA_HD_CB *p_cb, tBTA_HD_DATA *p_data);
+extern void bta_hd_close_act(tBTA_HD_CB *p_cb, tBTA_HD_DATA *p_data);
+extern void bta_hd_disable_act(tBTA_HD_CB *p_cb, tBTA_HD_DATA *p_data);
+extern void bta_hd_open_act(tBTA_HD_CB *p_cb, tBTA_HD_DATA *p_data);
+extern void bta_hd_opn_cb_act(tBTA_HD_CB *p_cb, tBTA_HD_DATA *p_data);
+extern void bta_hd_input_act(tBTA_HD_CB *p_cb, tBTA_HD_DATA *p_data);
+extern void bta_hd_discntd_act(tBTA_HD_CB *p_cb, tBTA_HD_DATA *p_data);
+extern void bta_hd_discnt_act(tBTA_HD_CB *p_cb, tBTA_HD_DATA *p_data);
+extern void bta_hd_hidd_cback(UINT8 event, UINT32 data, tHID_DEV_CBACK_DATA *pdata);
+#endif /* BTA_HD_INT_H */
+
diff --git a/bta/hd/bta_hd_main.c b/bta/hd/bta_hd_main.c
new file mode 100644
index 0000000..ee3efae
--- /dev/null
+++ b/bta/hd/bta_hd_main.c
@@ -0,0 +1,242 @@
+/******************************************************************************
+**
+** File Name: bta_hd_main.c
+**
+** Description: This is the state machine definition for the HID Device
+** service.
+**
+** Copyright (c) 2002-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+******************************************************************************/
+
+#include <string.h>
+#include "bt_target.h"
+#include "data_types.h"
+#include "bt_types.h"
+#include "hidd_api.h"
+#include "bta_hd_api.h"
+#include "bta_hd_int.h"
+#include "bd.h"
+
+/*****************************************************************************
+** Constants and types
+*****************************************************************************/
+
+
+/* state machine states */
+enum
+{
+ BTA_HD_IDLE_ST,
+ BTA_HD_LISTEN_ST,
+ BTA_HD_OPEN_ST
+};
+
+/* state machine action enumeration list */
+enum
+{
+ BTA_HD_INIT_CON_ACT,
+ BTA_HD_CLOSE_ACT,
+ BTA_HD_DISABLE_ACT,
+ BTA_HD_OPEN_ACT,
+ BTA_HD_OPN_CB_ACT,
+ BTA_HD_INPUT_ACT,
+ BTA_HD_DISCNTD_ACT,
+ BTA_HD_DISCNT_ACT,
+ BTA_HD_NUM_ACTIONS
+};
+
+#define BTA_HD_IGNORE BTA_HD_NUM_ACTIONS
+
+/* type for action functions */
+typedef void (*tBTA_HD_ACTION)(tBTA_HD_CB *p_cb, tBTA_HD_DATA *p_data);
+
+/* action functions */
+const tBTA_HD_ACTION bta_hd_action[] =
+{
+ bta_hd_init_con_act,
+ bta_hd_close_act,
+ bta_hd_disable_act,
+ bta_hd_open_act,
+ bta_hd_opn_cb_act,
+ bta_hd_input_act,
+ bta_hd_discntd_act,
+ bta_hd_discnt_act
+};
+
+/* state table information */
+#define BTA_HD_NUM_ACTS 1 /* number of actions */
+#define BTA_HD_ACTION 0 /* position of action */
+#define BTA_HD_NEXT_STATE 1 /* position of next state */
+#define BTA_HD_NUM_COLS 2 /* number of columns in state tables */
+
+/* state table for listen state */
+const UINT8 bta_hd_st_listen[][BTA_HD_NUM_COLS] =
+{
+/* API_OPEN */ {BTA_HD_INIT_CON_ACT, BTA_HD_LISTEN_ST},
+/* API_CLOSE */ {BTA_HD_CLOSE_ACT, BTA_HD_LISTEN_ST},
+/* API_DISABLE */ {BTA_HD_DISABLE_ACT, BTA_HD_IDLE_ST},
+/* API_INPUT */ {BTA_HD_IGNORE, BTA_HD_LISTEN_ST},
+/* CBACK */ {BTA_HD_IGNORE, BTA_HD_LISTEN_ST},
+/* CONNECTED */ {BTA_HD_OPEN_ACT, BTA_HD_OPEN_ST},
+/* DISCONNECT */ {BTA_HD_DISCNTD_ACT, BTA_HD_LISTEN_ST}
+};
+
+/* state table for open state */
+const UINT8 bta_hd_st_open[][BTA_HD_NUM_COLS] =
+{
+/* API_OPEN */ {BTA_HD_IGNORE, BTA_HD_OPEN_ST},
+/* API_CLOSE */ {BTA_HD_CLOSE_ACT, BTA_HD_OPEN_ST},
+/* API_DISABLE */ {BTA_HD_DISABLE_ACT, BTA_HD_IDLE_ST},
+/* API_INPUT */ {BTA_HD_INPUT_ACT, BTA_HD_OPEN_ST},
+/* CBACK */ {BTA_HD_OPN_CB_ACT, BTA_HD_OPEN_ST},
+/* CONNECTED */ {BTA_HD_IGNORE, BTA_HD_OPEN_ST},
+/* DISCONNECT */ {BTA_HD_DISCNT_ACT, BTA_HD_LISTEN_ST}
+};
+
+/* type for state table */
+typedef const UINT8 (*tBTA_HD_ST_TBL)[BTA_HD_NUM_COLS];
+
+/* state table */
+const tBTA_HD_ST_TBL bta_hd_st_tbl[] =
+{
+ bta_hd_st_listen,
+ bta_hd_st_open
+};
+
+/*****************************************************************************
+** Global data
+*****************************************************************************/
+
+/* HD control block */
+#if BTA_DYNAMIC_MEMORY == FALSE
+tBTA_HD_CB bta_hd_cb;
+#endif
+
+
+/*******************************************************************************
+**
+** Function bta_hd_api_enable
+**
+** Description Handle an API enable event.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_hd_api_enable(tBTA_HD_DATA *p_data)
+{
+ tHID_DEV_SDP_INFO sdp_info;
+ tHID_DEV_REG_INFO reg_info;
+ tBTA_SEC sec_mask = p_data->api_enable.sec_mask;
+ tBTA_HD_STATUS status = BTA_HD_FAIL;
+
+ /* initialize control block */
+ memset(&bta_hd_cb, 0, sizeof(tBTA_HD_CB));
+ GKI_init_q (&bta_hd_cb.out_q);
+
+ /* store parameters */
+ bta_hd_cb.p_cback = p_data->api_enable.p_cback;
+
+ /* register HID Device to HIDD */
+ reg_info.app_cback = bta_hd_hidd_cback;
+ bdcpy(reg_info.host_addr, p_data->api_enable.bd_addr);
+ if(p_bta_hd_cfg->use_qos)
+ reg_info.qos_info = &p_bta_hd_cfg->qos;
+ else
+ reg_info.qos_info = NULL;
+
+
+ if(HID_DevRegister(&reg_info) == HID_SUCCESS)
+ {
+ HID_DevSetSecurityLevel("BT HID Combo Mouse/Keyboard", sec_mask);
+
+ /* register HID Device to SDP */
+ memcpy(&sdp_info, &p_bta_hd_cfg->sdp_info, sizeof(tHID_DEV_SDP_INFO));
+ if(p_data->api_enable.service_name[0])
+ {
+ BCM_STRNCPY_S(sdp_info.svc_name, sizeof(sdp_info.svc_name), p_data->api_enable.service_name,
+// btla-specific ++
+ sizeof(sdp_info.svc_name));
+// btla-specific --
+ }
+ bta_hd_cb.sdp_handle = HID_DevSetSDPRecord(&sdp_info);
+ }
+
+ if(bta_hd_cb.sdp_handle>0)
+ {
+ status = BTA_HD_SUCCESS;
+ bta_hd_cb.state = BTA_HD_LISTEN_ST;
+ bta_sys_add_uuid(UUID_SERVCLASS_HUMAN_INTERFACE);
+ }
+
+ /* call callback with enable event */
+ (*bta_hd_cb.p_cback)(BTA_HD_ENABLE_EVT, (tBTA_HD *)&status);
+}
+
+/*******************************************************************************
+**
+** Function bta_hd_sm_execute
+**
+** Description State machine event handling function for HD
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hd_sm_execute(tBTA_HD_CB *p_cb, UINT16 event, tBTA_HD_DATA *p_data)
+{
+ tBTA_HD_ST_TBL state_table;
+ UINT8 action;
+
+ if(p_cb->state == BTA_HD_IDLE_ST)
+ {
+ APPL_TRACE_EVENT1("HD event=0x%x received in IDLE", event);
+ return;
+ }
+
+ /* look up the state table for the current state */
+ state_table = bta_hd_st_tbl[p_cb->state-1];
+
+ event &= 0x00FF;
+
+ APPL_TRACE_EVENT3("HD event=0x%x state=%d, next: %d",
+ event, p_cb->state, state_table[event][BTA_HD_NEXT_STATE]);
+ /* set next state */
+ p_cb->state = state_table[event][BTA_HD_NEXT_STATE];
+ action = state_table[event][BTA_HD_ACTION];
+
+ /* execute action functions */
+ if (action != BTA_HD_IGNORE)
+ {
+ (*bta_hd_action[action])(p_cb, p_data);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_hd_hdl_event
+**
+** Description HID Device main event handling function.
+**
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+BOOLEAN bta_hd_hdl_event(BT_HDR *p_msg)
+{
+ switch (p_msg->event)
+ {
+ /* handle enable event */
+ case BTA_HD_API_ENABLE_EVT:
+ bta_hd_api_enable((tBTA_HD_DATA *) p_msg);
+ break;
+
+ /* all others run through state machine */
+ default:
+ bta_hd_sm_execute(&bta_hd_cb, p_msg->event, (tBTA_HD_DATA *) p_msg);
+ break;
+ }
+ return TRUE;
+}
+
diff --git a/bta/hh/bta_hh_act.c b/bta/hh/bta_hh_act.c
new file mode 100644
index 0000000..483e79c
--- /dev/null
+++ b/bta/hh/bta_hh_act.c
@@ -0,0 +1,1160 @@
+/*****************************************************************************
+**
+** Name: bta_hh_act.c
+**
+** Description: This file contains the HID host action
+** functions.
+**
+** Copyright (c) 2005-2011, Broadcom Corp, All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+
+#if defined(BTA_HH_INCLUDED) && (BTA_HH_INCLUDED == TRUE)
+
+#include <string.h>
+
+#include "bta_sys.h"
+#include "btm_api.h"
+#include "l2c_api.h"
+#include "bta_hh_int.h"
+#include "bta_hh_co.h"
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+
+/*****************************************************************************
+** Local Function prototypes
+*****************************************************************************/
+static void bta_hh_cback (UINT8 dev_handle, UINT8 event, UINT32 data,
+ BT_HDR *pdata);
+static tBTA_HH_STATUS bta_hh_get_trans_status(UINT32 result);
+
+#if BTA_HH_DEBUG
+static char* bta_hh_get_w4_event(UINT16 event);
+static char * bta_hh_hid_event_name(UINT16 event);
+#endif
+
+/*****************************************************************************
+** Action Functions
+*****************************************************************************/
+/*******************************************************************************
+**
+** Function bta_hh_api_enable
+**
+** Description Perform necessary operations to enable HID host.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hh_api_enable(tBTA_HH_DATA *p_data)
+{
+ tBTA_HH_STATUS status = BTA_HH_ERR;
+ UINT8 xx;
+
+ /* initialize BTE HID */
+ HID_HostInit();
+
+ memset(&bta_hh_cb, 0, sizeof(tBTA_HH_CB));
+
+ HID_HostSetSecurityLevel("", p_data->api_enable.sec_mask);
+
+ /* Register with L2CAP */
+ if ( HID_HostRegister (bta_hh_cback) == HID_SUCCESS)
+ {
+ /* store parameters */
+ bta_hh_cb.p_cback = p_data->api_enable.p_cback;
+
+ status = BTA_HH_OK;
+ /* initialize device CB */
+ for (xx = 0; xx < BTA_HH_MAX_KNOWN; xx ++)
+ {
+ bta_hh_cb.kdev[xx].state = BTA_HH_IDLE_ST;
+ bta_hh_cb.kdev[xx].hid_handle = BTA_HH_INVALID_HANDLE;
+ bta_hh_cb.kdev[xx].index = xx;
+ /* initialize control block map */
+ bta_hh_cb.cb_index[xx] = BTA_HH_MAX_KNOWN;
+ }
+ }
+
+ /* signal BTA call back event */
+ (* bta_hh_cb.p_cback)(BTA_HH_ENABLE_EVT, (tBTA_HH *)&status);
+}
+/*******************************************************************************
+**
+** Function bta_hh_api_disable
+**
+** Description Perform necessary operations to disable HID host.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hh_api_disable(void)
+{
+ UINT8 xx;
+
+ /* service is not enabled */
+ if (bta_hh_cb.p_cback == NULL)
+ return;
+
+ /* no live connection, signal DISC_CMPL_EVT directly */
+ if (!bta_hh_cb.cnt_num)
+ {
+ bta_hh_disc_cmpl();
+ }
+ else /* otherwise, disconnect all live connections */
+ {
+ bta_hh_cb.w4_disable = TRUE;
+
+ for(xx = 0; xx < BTA_HH_MAX_KNOWN; xx ++)
+ {
+ /* send API_CLOSE event to every connected device */
+ if ( bta_hh_cb.kdev[xx].state == BTA_HH_CONN_ST )
+ {
+ /* disconnect all connected devices */
+ bta_hh_sm_execute(&bta_hh_cb.kdev[xx],
+ BTA_HH_API_CLOSE_EVT,
+ NULL);
+ }
+ }
+ }
+
+ return;
+}
+
+/*******************************************************************************
+**
+** Function bta_hh_disc_cmpl
+**
+** Description All connections have been closed, disable service.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hh_disc_cmpl(void)
+{
+ UINT8 xx;
+ tBTA_HH_STATUS status = BTA_HH_OK;
+
+ /* Deregister with lower layer */
+ if (HID_HostDeregister()!= HID_SUCCESS)
+ status = BTA_HH_ERR;
+
+ /* free buffer in CB holding report descriptors */
+ for(xx = 0; xx < BTA_HH_MAX_KNOWN; xx ++)
+ {
+ utl_freebuf((void **)&bta_hh_cb.kdev[xx].dscp_info.descriptor.dsc_list);
+ }
+ utl_freebuf((void **)&bta_hh_cb.p_disc_db);
+
+ (* bta_hh_cb.p_cback)(BTA_HH_DISABLE_EVT, (tBTA_HH *)&status);
+ /* all connections are down, no waiting for diconnect */
+ memset(&bta_hh_cb, 0, sizeof(tBTA_HH_CB));
+}
+/*******************************************************************************
+**
+** Function bta_hh_sdp_cback
+**
+** Description SDP callback function.
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_hh_sdp_cback(UINT16 result, UINT16 attr_mask,
+ tHID_DEV_SDP_INFO *sdp_rec )
+{
+ tBTA_HH_DEV_CB *p_cb = bta_hh_cb.p_cur;
+ UINT8 hdl;
+ tHID_STATUS status = HID_ERR_SDP_BUSY;
+
+
+ if (result == SDP_SUCCESS)
+ {
+ /* security is required for the connection, add attr_mask bit*/
+ if (p_cb->sec_mask)
+ attr_mask |= HID_SEC_REQUIRED;
+
+#if BTA_HH_DEBUG
+ APPL_TRACE_EVENT3("bta_hh_sdp_cback: p_cb: %d result 0x%02x, \
+ attr_mask 0x%02x", \
+ p_cb, result, attr_mask);
+#endif
+
+ /* check to see type of device is supported , and should not been added before */
+ if (bta_hh_tod_spt(p_cb, sdp_rec->sub_class))
+ {
+ /* if not added before */
+ if (p_cb->hid_handle == BTA_HH_INVALID_HANDLE)
+ {
+ /* add device/update attr_mask information */
+ if((status = HID_HostAddDev (p_cb->addr, attr_mask, &hdl)) == HID_SUCCESS)
+ {
+ /* update cb_index[] map */
+ bta_hh_cb.cb_index[hdl] = p_cb->index;
+ }
+ else
+ p_cb->app_id = 0;
+ }
+ /* else : incoming connection after SDP should update the SDP information as well */
+
+ if (p_cb->app_id != 0)
+ {
+ /* update cb information with attr_mask, dscp_info etc. */
+ bta_hh_add_device_to_list(p_cb, hdl, attr_mask,
+ &sdp_rec->dscp_info,
+ sdp_rec->sub_class,
+ sdp_rec->ssr_max_latency,
+ sdp_rec->ssr_min_tout,
+ p_cb->app_id);
+
+ p_cb->dscp_info.ctry_code = sdp_rec->ctry_code;
+
+ status = HID_SUCCESS;
+ }
+
+ }
+ else /* type of device is not supported */
+ status = HID_ERR_INVALID;
+ }
+
+ /* free disc_db when SDP is completed */
+ utl_freebuf((void **)&bta_hh_cb.p_disc_db);
+
+
+ /* send SDP_CMPL_EVT into state machine */
+ bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, (tBTA_HH_DATA *)&status);
+
+ return;
+}
+/*******************************************************************************
+**
+** Function bta_hh_di_sdp_cback
+**
+** Description SDP DI callback function.
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_hh_di_sdp_cback(UINT16 result)
+{
+ tBTA_HH_DEV_CB *p_cb = bta_hh_cb.p_cur;
+ tHID_STATUS status = HID_ERR_SDP_BUSY;
+ tSDP_DI_GET_RECORD di_rec;
+
+ if (result == SDP_SUCCESS)
+ {
+#if BTA_HH_DEBUG
+ APPL_TRACE_EVENT2("bta_hh_di_sdp_cback: p_cb: %d result 0x%02x", \
+ p_cb, result);
+#endif
+ if (SDP_GetNumDiRecords(bta_hh_cb.p_disc_db) != 0)
+ {
+ /* always update information with primary DI record */
+ if (SDP_GetDiRecord(1, &di_rec, bta_hh_cb.p_disc_db) == SDP_SUCCESS)
+ {
+ bta_hh_update_di_info(p_cb, di_rec.rec.vendor, di_rec.rec.product, di_rec.rec.version);
+ }
+ }
+ if ((status = HID_HostGetSDPRecord(p_cb->addr,
+ bta_hh_cb.p_disc_db,
+ p_bta_hh_cfg->sdp_db_size,
+ bta_hh_sdp_cback)) != HID_SUCCESS)
+ {
+#if BTA_HH_DEBUG
+ APPL_TRACE_DEBUG1 ("bta_hh_di_sdp_cback: HID_HostGetSDPRecord failed: \
+ Status 0x%2X",status);
+#endif
+ status = BTA_HH_ERR_SDP;
+ utl_freebuf((void **)&bta_hh_cb.p_disc_db);
+ }
+ }
+
+
+ if (status != HID_SUCCESS)
+ {
+ /* send SDP_CMPL_EVT into state machine */
+ bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, (tBTA_HH_DATA *)&status);
+ }
+ return;
+
+}
+
+
+/*******************************************************************************
+**
+** Function bta_hh_start_sdp
+**
+** Description Start SDP service search, and obtain necessary SDP records.
+** Only one SDP service search request is allowed at the same
+** time. For every BTA_HhOpen API call, do SDP first unless SDP
+** has been done previously.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hh_start_sdp(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
+{
+ tHID_STATUS status = HID_ERR_SDP_BUSY;
+ UINT8 hdl;
+
+ p_cb->sec_mask = p_data->api_conn.sec_mask;
+ p_cb->mode = p_data->api_conn.mode;
+
+ /* if previously virtually cabled device, skip SDP */
+ if (p_cb->app_id)
+ {
+ status = HID_SUCCESS;
+#if BTA_HH_DEBUG
+ APPL_TRACE_DEBUG0("bta_hh_start_sdp:: skip SDP for known devices");
+#endif
+ if (p_cb->hid_handle == BTA_HH_INVALID_HANDLE)
+ {
+ if ((status = HID_HostAddDev (p_cb->addr, p_cb->attr_mask, &hdl)) \
+ == HID_SUCCESS)
+ {
+ /* update device CB with newly register device handle */
+ bta_hh_add_device_to_list(p_cb, hdl, p_cb->attr_mask, NULL,
+ p_cb->sub_class,
+ p_cb->dscp_info.ssr_max_latency,
+ p_cb->dscp_info.ssr_min_tout,
+ p_cb->app_id);
+ /* update cb_index[] map */
+ bta_hh_cb.cb_index[hdl] = p_cb->index;
+ }
+ }
+ bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, (tBTA_HH_DATA *)&status);
+
+ return;
+ }
+ /* GetSDPRecord. at one time only one SDP precedure can be active */
+ else if (!bta_hh_cb.p_disc_db)
+ {
+ bta_hh_cb.p_disc_db = (tSDP_DISCOVERY_DB *) GKI_getbuf(p_bta_hh_cfg->sdp_db_size);
+
+ if (bta_hh_cb.p_disc_db == NULL)
+ {
+ status = BTA_HH_ERR_NO_RES;
+ }
+ else
+ {
+ bta_hh_cb.p_cur = p_cb;
+ /* do DI discovery first */
+ if (SDP_DiDiscover(p_data->api_conn.bd_addr,
+ bta_hh_cb.p_disc_db,
+ p_bta_hh_cfg->sdp_db_size,
+ bta_hh_di_sdp_cback) != SDP_SUCCESS)
+ {
+#if BTA_HH_DEBUG
+ APPL_TRACE_DEBUG1 ("bta_hh_start_sdp: SDP_DiDiscover failed: \
+ Status 0x%2X",status);
+#endif
+ status = BTA_HH_ERR_SDP;
+ utl_freebuf((void **)&bta_hh_cb.p_disc_db);
+ }
+ else
+ status = HID_SUCCESS;
+ }
+ }
+
+ if (status != HID_SUCCESS)
+ bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, (tBTA_HH_DATA *)&status);
+
+ return;
+
+}
+/*******************************************************************************
+**
+** Function bta_hh_sdp_cmpl
+**
+** Description When SDP completed, initiate a connection or report error depend
+** on SDP result.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hh_sdp_cmpl(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
+{
+ tBTA_HH_CONN conn_dat;
+ tHID_STATUS status;
+
+#if BTA_HH_DEBUG
+ APPL_TRACE_DEBUG1 ("bta_hh_sdp_cmpl: status 0x%2X",p_data->status);
+#endif
+
+ /* initialize call back data */
+ memset((void *)&conn_dat, 0, sizeof(tBTA_HH_CONN));
+ conn_dat.handle = p_cb->hid_handle;
+ bdcpy(conn_dat.bda, p_cb->addr);
+
+ /* if SDP compl success */
+ if ( (status = p_data->status) == HID_SUCCESS)
+ {
+ /* not incoming connection doing SDP, initiate a HID connection */
+ if (!p_cb->incoming_conn)
+ {
+ /* set security level */
+ HID_HostSetSecurityLevel("", p_cb->sec_mask);
+
+ /* open HID connection */
+ if ((status = HID_HostOpenDev (p_cb->hid_handle)) != HID_SUCCESS)
+ {
+#if BTA_HH_DEBUG
+ APPL_TRACE_DEBUG1 ("bta_hh_sdp_cmpl: HID_HostOpenDev failed: \
+ Status 0x%2X",status);
+#endif
+ /* open fail, remove device from management device list */
+ HID_HostRemoveDev( p_cb->hid_handle);
+
+ }
+ }
+ else /* incoming connection SDP finish */
+ {
+ bta_hh_sm_execute(p_cb, BTA_HH_OPEN_CMPL_EVT, NULL);
+ }
+ }
+
+ if (status != HID_SUCCESS)
+ {
+ /* receive SDP error */
+ if (p_data->status == HID_ERR_INVALID)
+ conn_dat.status = BTA_HH_ERR_TOD_UNSPT;
+ else
+ conn_dat.status = BTA_HH_ERR_SDP;
+
+ (* bta_hh_cb.p_cback)(BTA_HH_OPEN_EVT, (tBTA_HH *)&conn_dat);
+
+ /* move state machine W4_CONN ->IDLE */
+ bta_hh_sm_execute(p_cb, BTA_HH_API_CLOSE_EVT, NULL);
+
+ /* if this is an outgoing connection to an unknown device, clean up cb */
+ if (p_cb->app_id == 0 && !p_cb->incoming_conn)
+ {
+ /* clean up device control block */
+ bta_hh_clean_up_kdev(p_cb);
+ }
+
+#if BTA_HH_DEBUG
+ bta_hh_trace_dev_db();
+#endif
+ }
+
+ return;
+}
+
+/*******************************************************************************
+**
+** Function bta_hh_api_disc_act
+**
+** Description HID Host initiate a disconnection.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hh_api_disc_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
+{
+ tBTA_HH_CBDATA disc_dat;
+ tHID_STATUS status;
+
+ /* found an active connection */
+ disc_dat.handle = p_data ?(UINT8)p_data->hdr.layer_specific :p_cb->hid_handle;
+ disc_dat.status = BTA_HH_ERR;
+
+ status = HID_HostCloseDev(disc_dat.handle);
+
+ if (status)
+ (* bta_hh_cb.p_cback)(BTA_HH_CLOSE_EVT, (tBTA_HH *)&disc_dat);
+
+ return;
+}
+/*******************************************************************************
+**
+** Function bta_hh_open_cmpl_act
+**
+** Description HID host connection completed
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hh_open_cmpl_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
+{
+ tBTA_HH_CONN conn ;
+ UINT8 dev_handle = p_data ? (UINT8)p_data->hid_cback.hdr.layer_specific : \
+ p_cb->hid_handle;
+
+ memset((void *)&conn, 0, sizeof (tBTA_HH_CONN));
+ conn.handle = dev_handle;
+ bdcpy(conn.bda, p_cb->addr);
+
+ /* increase connection number */
+ bta_hh_cb.cnt_num ++;
+
+ /* initialize device driver */
+ bta_hh_co_open(p_cb->hid_handle, p_cb->sub_class,
+ p_cb->attr_mask, p_cb->app_id);
+
+ /* update SSR settings */
+ bta_sys_chg_ssr_config(BTA_ID_HH ,p_cb->app_id, p_cb->dscp_info.ssr_max_latency, p_cb->dscp_info.ssr_min_tout);
+ /* inform role manager */
+ bta_sys_conn_open( BTA_ID_HH ,p_cb->app_id, p_cb->addr);
+
+ /* set protocol mode when not default report mode */
+ if (p_cb->mode != BTA_HH_PROTO_RPT_MODE)
+ {
+ if ((conn.status = HID_HostWriteDev(dev_handle,
+ HID_TRANS_SET_PROTOCOL, HID_PAR_PROTOCOL_BOOT_MODE,
+ 0,
+ 0, NULL)) != HID_SUCCESS)
+ {
+ /* HID connection is up, while SET_PROTO fail */
+ conn.status = BTA_HH_ERR_PROTO;
+ (* bta_hh_cb.p_cback)(BTA_HH_OPEN_EVT, (tBTA_HH *)&conn);
+ }
+ else
+ p_cb->w4_evt = BTA_HH_OPEN_EVT;
+ }
+ else
+ (* bta_hh_cb.p_cback)(BTA_HH_OPEN_EVT, (tBTA_HH *)&conn);
+
+ p_cb->incoming_conn = FALSE;
+
+}
+/*******************************************************************************
+**
+** Function bta_hh_open_act
+**
+** Description HID host receive HID_OPEN_EVT .
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hh_open_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
+{
+ tBTA_HH_API_CONN conn_data;
+
+#if BTA_HH_DEBUG
+ UINT8 dev_handle = p_data ? (UINT8)p_data->hid_cback.hdr.layer_specific : \
+ p_cb->hid_handle;
+
+ APPL_TRACE_EVENT1 ("bta_hh_open_act: Device[%d] connected", dev_handle);
+#endif
+
+ /* SDP has been done */
+ if (p_cb->app_id != 0)
+ {
+ bta_hh_sm_execute(p_cb, BTA_HH_OPEN_CMPL_EVT, p_data);
+ }
+ else
+ /* app_id == 0 indicates an incoming conenction request arrives without SDP
+ performed, do it first */
+ {
+ p_cb->incoming_conn = TRUE;
+
+ memset(&conn_data, 0, sizeof(tBTA_HH_API_CONN));
+ bdcpy(conn_data.bd_addr, p_cb->addr);
+ bta_hh_start_sdp(p_cb, (tBTA_HH_DATA *)&conn_data);
+ }
+
+ return;
+}
+
+
+/*******************************************************************************
+**
+** Function bta_hh_data_act
+**
+** Description HID Host process a data report
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hh_data_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA * p_data)
+{
+ BT_HDR *pdata = p_data->hid_cback.p_data;
+ UINT8 *p_rpt = (UINT8 *)(pdata + 1) + pdata->offset;
+
+ bta_hh_co_data((UINT8)p_data->hid_cback.hdr.layer_specific, p_rpt, pdata->len,
+ p_cb->mode, p_cb->sub_class, p_cb->dscp_info.ctry_code, p_cb->addr, p_cb->app_id);
+
+ utl_freebuf((void **)&pdata);
+}
+
+
+/*******************************************************************************
+**
+** Function bta_hh_handsk_act
+**
+** Description HID Host process a handshake acknoledgement.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hh_handsk_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA * p_data)
+{
+ tBTA_HH_CBDATA cback_data ;
+ tBTA_HH_HSDATA hs_data;
+ tBTA_HH_CONN conn ;
+
+#if BTA_HH_DEBUG
+ APPL_TRACE_DEBUG2("HANDSHAKE received for: event = %s data= %d",
+ bta_hh_get_w4_event(p_cb->w4_evt), p_data->hid_cback.data);
+#endif
+
+ memset(&hs_data, 0, sizeof(tBTA_HH_HSDATA));
+
+ switch (p_cb->w4_evt)
+ {
+ /* GET_ transsaction, handshake indicate unsupported request */
+ case BTA_HH_GET_PROTO_EVT:
+ hs_data.rsp_data.proto_mode = BTA_HH_PROTO_UNKNOWN;
+ /* fall through */
+ case BTA_HH_GET_RPT_EVT:
+ hs_data.handle = p_cb->hid_handle;
+ /* if handshake gives an OK code for these transaction, fill in UNSUPT */
+ if ((hs_data.status = bta_hh_get_trans_status(p_data->hid_cback.data)) == BTA_HH_OK)
+ hs_data.status = BTA_HH_HS_TRANS_NOT_SPT;
+
+ (* bta_hh_cb.p_cback)(p_cb->w4_evt, (tBTA_HH *)&hs_data);
+ p_cb->w4_evt = 0;
+ break;
+
+ /* acknoledgement from HID device for SET_ transaction */
+ case BTA_HH_SET_RPT_EVT:
+ case BTA_HH_SET_PROTO_EVT:
+ cback_data.handle = p_cb->hid_handle;
+ cback_data.status = bta_hh_get_trans_status(p_data->hid_cback.data);
+ (* bta_hh_cb.p_cback)(p_cb->w4_evt, (tBTA_HH *)&cback_data);
+ p_cb->w4_evt = 0;
+ break;
+
+ /* SET_PROTOCOL when open connection */
+ case BTA_HH_OPEN_EVT:
+ conn.status =p_data->hid_cback.data ? BTA_HH_ERR_PROTO: BTA_HH_OK;
+ conn.handle = p_cb->hid_handle;
+ bdcpy(conn.bda, p_cb->addr);
+ (* bta_hh_cb.p_cback)(p_cb->w4_evt, (tBTA_HH *)&conn);
+#if BTA_HH_DEBUG
+ bta_hh_trace_dev_db();
+#endif
+ p_cb->w4_evt = 0;
+ break;
+
+ default:
+ /* unknow transaction handshake response */
+ APPL_TRACE_DEBUG0("unknown transaction type");
+ break;
+ }
+
+ /* transaction achknoledgement received, inform PM for mode change */
+ bta_sys_idle(BTA_ID_HH, p_cb->app_id, p_cb->addr);
+
+ return;
+}
+/*******************************************************************************
+**
+** Function bta_hh_ctrl_dat_act
+**
+** Description HID Host process a data report from control channel.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hh_ctrl_dat_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA * p_data)
+{
+ BT_HDR *pdata = p_data->hid_cback.p_data;
+ UINT8 *data = (UINT8 *)(pdata + 1) + pdata->offset;
+ tBTA_HH_HSDATA hs_data;
+
+#if BTA_HH_DEBUG
+ APPL_TRACE_DEBUG1("Ctrl DATA received w4: event[%s]",
+ bta_hh_get_w4_event(p_cb->w4_evt));
+#endif
+ hs_data.status = BTA_HH_OK;
+ hs_data.handle = p_cb->hid_handle;
+
+ switch (p_cb->w4_evt)
+ {
+ case BTA_HH_GET_RPT_EVT:
+ hs_data.rsp_data.p_rpt_data = pdata;
+ break;
+ case BTA_HH_GET_PROTO_EVT:
+ /* match up BTE/BTA report/boot mode def*/
+ hs_data.rsp_data.proto_mode = ((*data) == HID_PAR_PROTOCOL_REPORT)? \
+ BTA_HH_PROTO_RPT_MODE : BTA_HH_PROTO_BOOT_MODE;
+#if BTA_HH_DEBUG
+ APPL_TRACE_DEBUG1("GET_PROTOCOL Mode = [%s]",
+ (hs_data.rsp_data.proto_mode == BTA_HH_PROTO_RPT_MODE)? "Report" : "Boot");
+#endif
+ break;
+ /* should not expect control DATA for SET_ transaction */
+ case BTA_HH_SET_PROTO_EVT:
+ /* fall through */
+ case BTA_HH_SET_RPT_EVT:
+ /* fall through */
+ default:
+#if BTA_HH_DEBUG
+ APPL_TRACE_DEBUG1("invalid transaction type for DATA payload: 4_evt[%s]",
+ bta_hh_get_w4_event(p_cb->w4_evt));
+#endif
+ break;
+ }
+
+ /* inform PM for mode change */
+ bta_sys_busy(BTA_ID_HH, p_cb->app_id, p_cb->addr);
+ bta_sys_idle(BTA_ID_HH, p_cb->app_id, p_cb->addr);
+
+ (* bta_hh_cb.p_cback)(p_cb->w4_evt, (tBTA_HH *)&hs_data);
+
+ p_cb->w4_evt = 0;
+ utl_freebuf((void **)&pdata);
+
+}
+
+/*******************************************************************************
+**
+** Function bta_hh_close_act
+**
+** Description HID Host process a close event
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hh_close_act (tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
+{
+ tBTA_HH_CONN conn_dat ;
+ tBTA_HH_CBDATA disc_dat = {BTA_HH_OK, 0};
+ UINT32 reason = p_data->hid_cback.data; /* Reason for closing (32-bit) */
+
+ /* if HID_HDEV_EVT_VC_UNPLUG was received, report BTA_HH_VC_UNPLUG_EVT */
+ UINT16 event = p_cb->vp ? BTA_HH_VC_UNPLUG_EVT : BTA_HH_CLOSE_EVT;
+
+ disc_dat.handle = p_cb->hid_handle;
+ disc_dat.status = p_data->hid_cback.data;
+
+ /* Check reason for closing */
+ if ((reason & (HID_L2CAP_CONN_FAIL|HID_L2CAP_REQ_FAIL)) || /* Failure to initialize connection (page timeout or l2cap error) */
+ (reason == HID_ERR_AUTH_FAILED) || /* Authenication error (while initiating) */
+ (reason == HID_ERR_L2CAP_FAILED)) /* Failure creating l2cap connection */
+ {
+ /* Failure in opening connection */
+ conn_dat.handle = p_cb->hid_handle;
+ conn_dat.status = (reason == HID_ERR_AUTH_FAILED) ? BTA_HH_ERR_AUTH_FAILED : BTA_HH_ERR;
+ bdcpy(conn_dat.bda, p_cb->addr);
+ HID_HostCloseDev(p_cb->hid_handle);
+
+ /* Report OPEN fail event */
+ (*bta_hh_cb.p_cback)(BTA_HH_OPEN_EVT, (tBTA_HH *)&conn_dat);
+
+#if BTA_HH_DEBUG
+ bta_hh_trace_dev_db();
+#endif
+ return;
+ }
+ /* otherwise report CLOSE/VC_UNPLUG event */
+ else
+ {
+ /* finaliza device driver */
+ bta_hh_co_close(p_cb->hid_handle, p_cb->app_id);
+ /* inform role manager */
+ bta_sys_conn_close( BTA_ID_HH ,p_cb->app_id, p_cb->addr);
+ /* update total conn number */
+ bta_hh_cb.cnt_num --;
+
+ if (disc_dat.status)
+ disc_dat.status = BTA_HH_ERR;
+
+ (*bta_hh_cb.p_cback)(event, (tBTA_HH *)&disc_dat);
+
+ /* if virtually unplug, remove device */
+ if (p_cb->vp )
+ {
+ HID_HostRemoveDev( p_cb->hid_handle);
+ bta_hh_clean_up_kdev(p_cb);
+ }
+
+#if BTA_HH_DEBUG
+ bta_hh_trace_dev_db();
+#endif
+ }
+
+ /* clean up control block, but retain SDP info and device handle */
+ p_cb->vp = FALSE;
+ p_cb->w4_evt = 0;
+
+ /* if no connection is active and HH disable is signaled, disable service */
+ if (bta_hh_cb.cnt_num == 0 && bta_hh_cb.w4_disable)
+ {
+ bta_hh_disc_cmpl();
+ }
+
+ return;
+}
+
+/*******************************************************************************
+**
+** Function bta_hh_get_dscp_act
+**
+** Description Get device report descriptor
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hh_get_dscp_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
+{
+ (*bta_hh_cb.p_cback)(BTA_HH_GET_DSCP_EVT, (tBTA_HH *)&p_cb->dscp_info);
+}
+
+/*******************************************************************************
+**
+** Function bta_hh_maint_dev_act
+**
+** Description HID Host maintain device list.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hh_maint_dev_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
+{
+ tBTA_HH_MAINT_DEV *p_dev_info = &p_data->api_maintdev;
+ tBTA_HH_DEV_INFO dev_info ;
+ UINT8 dev_handle;
+
+ dev_info.status = BTA_HH_ERR;
+ dev_info.handle = BTA_HH_INVALID_HANDLE;
+
+ switch (p_dev_info->sub_event)
+ {
+ case BTA_HH_ADD_DEV_EVT: /* add a device */
+ bdcpy(dev_info.bda, p_dev_info->bda);
+ /* initialize callback data */
+ if (p_cb->hid_handle == BTA_HH_INVALID_HANDLE)
+ {
+ if (HID_HostAddDev(p_dev_info->bda, p_dev_info->attr_mask, &dev_handle)\
+ == HID_SUCCESS)
+ {
+ dev_info.handle = dev_handle;
+ dev_info.status = BTA_HH_OK;
+
+ /* update DI information */
+ bta_hh_update_di_info(p_cb,
+ p_dev_info->dscp_info.vendor_id,
+ p_dev_info->dscp_info.product_id,
+ p_dev_info->dscp_info.version);
+
+ /* add to BTA device list */
+ bta_hh_add_device_to_list(p_cb, dev_handle,
+ p_dev_info->attr_mask,
+ &p_dev_info->dscp_info.descriptor,
+ p_dev_info->sub_class,
+ p_dev_info->dscp_info.ssr_max_latency,
+ p_dev_info->dscp_info.ssr_min_tout,
+ p_dev_info->app_id);
+ /* update cb_index[] map */
+ bta_hh_cb.cb_index[dev_handle] = p_cb->index;
+ }
+ }
+ else /* device already been added */
+ {
+ dev_info.handle = p_cb->hid_handle;
+ dev_info.status = BTA_HH_OK;
+ }
+#if BTA_HH_DEBUG
+ bta_hh_trace_dev_db();
+#endif
+ break;
+
+ case BTA_HH_RMV_DEV_EVT: /* remove device */
+ dev_info.handle = (UINT8)p_dev_info->hdr.layer_specific;
+
+ bdcpy(dev_info.bda, p_cb->addr);
+ if (p_cb->state != BTA_HH_CONN_ST )
+ {
+ if(HID_HostRemoveDev( dev_info.handle ) == HID_SUCCESS)
+ {
+ dev_info.status = BTA_HH_OK;
+
+ /* remove from known device list in BTA */
+ bta_hh_clean_up_kdev(p_cb);
+ }
+ }
+ break;
+
+ default:
+ APPL_TRACE_DEBUG0("invalid command");
+ break;
+ }
+
+ (* bta_hh_cb.p_cback)(p_dev_info->sub_event, (tBTA_HH *)&dev_info);
+}
+/*******************************************************************************
+**
+** Function bta_hh_write_dev_act
+**
+** Description Write device action. can be SET/GET/DATA transaction.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hh_write_dev_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
+{
+ tBTA_HH_CBDATA cbdata = {BTA_HH_OK, 0};
+ UINT16 event = (p_data->api_sndcmd.t_type - BTA_HH_FST_BTE_TRANS_EVT) +
+ BTA_HH_FST_TRANS_CB_EVT;
+
+ cbdata.handle = p_cb->hid_handle;
+
+ /* match up BTE/BTA report/boot mode def */
+ if (p_data->api_sndcmd.t_type == HID_TRANS_SET_PROTOCOL)
+ {
+ p_data->api_sndcmd.param = ( p_data->api_sndcmd.param == BTA_HH_PROTO_RPT_MODE) ?\
+ HID_PAR_PROTOCOL_REPORT :HID_PAR_PROTOCOL_BOOT_MODE;
+ }
+
+ if (HID_HostWriteDev (p_cb->hid_handle,
+ p_data->api_sndcmd.t_type,
+ p_data->api_sndcmd.param,
+ p_data->api_sndcmd.data,
+ p_data->api_sndcmd.rpt_id,
+ p_data->api_sndcmd.p_data) != HID_SUCCESS)
+ {
+ APPL_TRACE_ERROR0("HID_HostWriteDev Error ");
+ cbdata.status = BTA_HH_ERR;
+
+ if (p_data->api_sndcmd.t_type != HID_TRANS_CONTROL &&
+ p_data->api_sndcmd.t_type != HID_TRANS_DATA)
+ (* bta_hh_cb.p_cback)(event, (tBTA_HH *)&cbdata);
+ else if (p_data->api_sndcmd.param == BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG)
+ (* bta_hh_cb.p_cback)(BTA_HH_VC_UNPLUG_EVT, (tBTA_HH *)&cbdata);
+ }
+ else
+ {
+
+ switch(p_data->api_sndcmd.t_type)
+ {
+ case HID_TRANS_SET_PROTOCOL:
+ /* fall through */
+ case HID_TRANS_GET_REPORT:
+ /* fall through */
+ case HID_TRANS_SET_REPORT:
+ /* fall through */
+ case HID_TRANS_GET_PROTOCOL:/* set w4_handsk event name for callback function use */
+ p_cb->w4_evt = event;
+ break;
+ case HID_TRANS_DATA: /* output report */
+ /* fall through */
+ case HID_TRANS_CONTROL:
+ /* no handshake event will be generated */
+ /* if VC_UNPLUG is issued, set flag */
+ if (p_data->api_sndcmd.param == BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG)
+ p_cb->vp = TRUE;
+
+ break;
+ /* deprecated for HID 1.1, shall not be sent out */
+ case HID_TRANS_GET_IDLE:
+ /* fall through */
+ case HID_TRANS_SET_IDLE:
+ APPL_TRACE_ERROR0("SET_IDLE, GET_IDLE is deprecated in HID 1.1")
+ break;
+
+ /* currently not expected */
+ case HID_TRANS_DATAC:
+ default:
+ APPL_TRACE_DEBUG1("bta_hh_write_dev_act:: cmd type = %d",
+ p_data->api_sndcmd.t_type);
+ break;
+ }
+
+ /* if not control type transaction, notify PM for energy control */
+ if (p_data->api_sndcmd.t_type != HID_TRANS_CONTROL)
+ {
+ /* inform PM for mode change */
+ bta_sys_busy(BTA_ID_HH, p_cb->app_id, p_cb->addr);
+ bta_sys_idle(BTA_ID_HH, p_cb->app_id, p_cb->addr);
+ }
+ else if (p_data->api_sndcmd.param == BTA_HH_CTRL_SUSPEND)
+ {
+ bta_sys_sco_close(BTA_ID_HH, p_cb->app_id, p_cb->addr);
+ }
+ else if (p_data->api_sndcmd.param == BTA_HH_CTRL_EXIT_SUSPEND)
+ {
+ bta_sys_busy(BTA_ID_HH, p_cb->app_id, p_cb->addr);
+ }
+ }
+
+
+ return;
+}
+
+/*****************************************************************************
+** Static Function
+*****************************************************************************/
+/*******************************************************************************
+**
+** Function bta_hh_cback
+**
+** Description BTA HH callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_hh_cback (UINT8 dev_handle, UINT8 event, UINT32 data,
+ BT_HDR *pdata)
+{
+ tBTA_HH_CBACK_DATA *p_buf = NULL;
+ UINT16 sm_event = BTA_HH_INVALID_EVT;
+ UINT8 xx = 0;
+
+#if BTA_HH_DEBUG
+ APPL_TRACE_DEBUG1("bta_hh_cback::HID_event [%s]", bta_hh_hid_event_name(event));
+#endif
+
+ switch (event)
+ {
+ case HID_HDEV_EVT_OPEN:
+ sm_event = BTA_HH_INT_OPEN_EVT;
+ break;
+ case HID_HDEV_EVT_CLOSE:
+ sm_event = BTA_HH_INT_CLOSE_EVT;
+ break;
+ case HID_HDEV_EVT_INTR_DATA:
+ sm_event = BTA_HH_INT_DATA_EVT;
+ break;
+ case HID_HDEV_EVT_HANDSHAKE:
+ sm_event = BTA_HH_INT_HANDSK_EVT;
+ break;
+ case HID_HDEV_EVT_CTRL_DATA:
+ sm_event = BTA_HH_INT_CTRL_DATA;
+ break;
+ case HID_HDEV_EVT_RETRYING:
+ break;
+ case HID_HDEV_EVT_INTR_DATC:
+ case HID_HDEV_EVT_CTRL_DATC:
+ /* Unhandled events: Free buffer for DATAC */
+ utl_freebuf((void **)&pdata);
+ break;
+ case HID_HDEV_EVT_VC_UNPLUG:
+ for (xx = 0; xx < BTA_HH_MAX_KNOWN; xx++)
+ {
+ if (bta_hh_cb.kdev[xx].hid_handle == dev_handle)
+ {
+ bta_hh_cb.kdev[xx].vp = TRUE;
+ break;
+ }
+ }
+ break;
+ }
+
+ if (sm_event != BTA_HH_INVALID_EVT &&
+ (p_buf = (tBTA_HH_CBACK_DATA *)GKI_getbuf(sizeof(tBTA_HH_CBACK_DATA) +
+ sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->hdr.event = sm_event;
+ p_buf->hdr.layer_specific = (UINT16)dev_handle;
+ p_buf->data = data;
+ p_buf->p_data = pdata;
+
+ bta_sys_sendmsg(p_buf);
+ }
+
+}
+/*******************************************************************************
+**
+** Function bta_hh_get_trans_status
+**
+** Description translate a handshake result code into BTA HH
+** status code
+**
+*******************************************************************************/
+static tBTA_HH_STATUS bta_hh_get_trans_status(UINT32 result)
+{
+ switch(result)
+ {
+ case HID_PAR_HANDSHAKE_RSP_SUCCESS : /* (0) */
+ return BTA_HH_OK;
+ case HID_PAR_HANDSHAKE_RSP_NOT_READY : /* (1) */
+ case HID_PAR_HANDSHAKE_RSP_ERR_INVALID_REP_ID: /* (2) */
+ case HID_PAR_HANDSHAKE_RSP_ERR_UNSUPPORTED_REQ : /* (3) */
+ case HID_PAR_HANDSHAKE_RSP_ERR_INVALID_PARAM : /* (4) */
+ return (tBTA_HH_STATUS)result;
+ case HID_PAR_HANDSHAKE_RSP_ERR_UNKNOWN : /* (14) */
+ case HID_PAR_HANDSHAKE_RSP_ERR_FATAL : /* (15) */
+ default:
+ return BTA_HH_HS_ERROR;
+ break;
+ }
+}
+/*****************************************************************************
+** Debug Functions
+*****************************************************************************/
+
+#if (defined BTA_HH_DEBUG && BTA_HH_DEBUG == TRUE)
+static char* bta_hh_get_w4_event(UINT16 event)
+{
+ switch (event)
+ {
+ case BTA_HH_GET_RPT_EVT:
+ return "BTA_HH_GET_RPT_EVT";
+ case BTA_HH_SET_RPT_EVT:
+ return "BTA_HH_SET_RPT_EVT";
+ case BTA_HH_GET_PROTO_EVT:
+ return "BTA_HH_GET_PROTO_EVT";
+ case BTA_HH_SET_PROTO_EVT:
+ return "BTA_HH_SET_PROTO_EVT";
+ case BTA_HH_GET_IDLE_EVT:
+ return "BTA_HH_GET_IDLE_EVT";
+ case BTA_HH_SET_IDLE_EVT:
+ return "BTA_HH_SET_IDLE_EVT";
+ case BTA_HH_OPEN_EVT:
+ return "BTA_HH_OPEN_EVT";
+ default:
+ return "Unknown event";
+ }
+
+}
+
+static char * bta_hh_hid_event_name(UINT16 event)
+{
+ switch (event)
+ {
+ case HID_HDEV_EVT_OPEN:
+ return "HID_HDEV_EVT_OPEN";
+ case HID_HDEV_EVT_CLOSE:
+ return "HID_HDEV_EVT_CLOSE";
+ case HID_HDEV_EVT_RETRYING:
+ return "HID_HDEV_EVT_RETRYING";
+ case HID_HDEV_EVT_INTR_DATA:
+ return "HID_HDEV_EVT_INTR_DATA";
+ case HID_HDEV_EVT_INTR_DATC:
+ return "HID_HDEV_EVT_INTR_DATC";
+ case HID_HDEV_EVT_CTRL_DATA:
+ return "HID_HDEV_EVT_CTRL_DATA";
+ case HID_HDEV_EVT_CTRL_DATC:
+ return "HID_HDEV_EVT_CTRL_DATC";
+ case HID_HDEV_EVT_HANDSHAKE:
+ return "HID_HDEV_EVT_HANDSHAKE";
+ case HID_HDEV_EVT_VC_UNPLUG:
+ return "HID_HDEV_EVT_VC_UNPLUG";
+ default:
+ return "Unknown HID event";
+ }
+}
+#endif
+#endif /* BTA_HH_INCLUDED */
+
diff --git a/bta/hh/bta_hh_api.c b/bta/hh/bta_hh_api.c
new file mode 100644
index 0000000..73e37a7
--- /dev/null
+++ b/bta/hh/bta_hh_api.c
@@ -0,0 +1,412 @@
+/*****************************************************************************/
+/* */
+/* Name: bta_hh_api.c */
+/* */
+/* Description: this file contains the HID HOST API in the subsystem of */
+/* BTA. */
+/* */
+/* Copyright (c) 2005, Broadcom Corp, All Rights Reserved. */
+/* WIDCOMM Bluetooth Core. Proprietary and confidential. */
+/*****************************************************************************/
+
+#include "bt_target.h"
+
+#if defined(BTA_HH_INCLUDED) && (BTA_HH_INCLUDED == TRUE)
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "bta_hh_api.h"
+#include "bta_hh_int.h"
+#include "l2c_api.h"
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+static const tBTA_SYS_REG bta_hh_reg =
+{
+ bta_hh_hdl_event,
+ BTA_HhDisable
+};
+
+/*******************************************************************************
+**
+** Function BTA_HhEnable
+**
+** Description Enable the HID host. This function must be called before
+** any other functions in the HID host API are called. When the
+** enable operation is complete the callback function will be
+** called with BTA_HH_ENABLE_EVT.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_HhEnable(tBTA_SEC sec_mask, BOOLEAN ucd_enabled, tBTA_HH_CBACK *p_cback)
+{
+ tBTA_HH_API_ENABLE *p_buf;
+
+ /* register with BTA system manager */
+ GKI_sched_lock();
+ bta_sys_register(BTA_ID_HH, &bta_hh_reg);
+ GKI_sched_unlock();
+
+ p_buf = (tBTA_HH_API_ENABLE *)GKI_getbuf((UINT16)sizeof(tBTA_HH_API_ENABLE));
+
+ if (p_buf != NULL)
+ {
+ memset(p_buf, 0, sizeof(tBTA_HH_API_ENABLE));
+
+ p_buf->hdr.event = BTA_HH_API_ENABLE_EVT;
+ p_buf->p_cback = p_cback;
+ p_buf->sec_mask = sec_mask;
+
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_HhDisable
+**
+** Description Disable the HID host. If the server is currently
+** connected, the connection will be closed.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_HhDisable(void)
+{
+ BT_HDR *p_buf;
+
+ bta_sys_deregister(BTA_ID_HH);
+ if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->event = BTA_HH_API_DISABLE_EVT;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_HhClose
+**
+** Description Disconnect a connection.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_HhClose(UINT8 dev_handle)
+{
+ BT_HDR *p_buf;
+
+ if ((p_buf = (BT_HDR *)GKI_getbuf((UINT16)sizeof(BT_HDR))) != NULL)
+ {
+ memset(p_buf, 0, sizeof(BT_HDR));
+ p_buf->event = BTA_HH_API_CLOSE_EVT;
+ p_buf->layer_specific = (UINT16) dev_handle;
+
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_HhOpen
+**
+** Description Connect to a device of specified BD address in specified
+** protocol mode and security level.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_HhOpen(BD_ADDR dev_bda, tBTA_HH_PROTO_MODE mode, tBTA_SEC sec_mask)
+{
+ tBTA_HH_API_CONN *p_buf;
+
+ p_buf = (tBTA_HH_API_CONN *)GKI_getbuf((UINT16)sizeof(tBTA_HH_API_CONN));
+
+ if (p_buf!= NULL)
+ {
+ memset((void *)p_buf, 0, sizeof(tBTA_HH_API_CONN));
+
+ p_buf->hdr.event = BTA_HH_API_OPEN_EVT;
+ p_buf->hdr.layer_specific = BTA_HH_INVALID_HANDLE;
+ p_buf->sec_mask = sec_mask;
+ p_buf->mode = mode;
+ bdcpy(p_buf->bd_addr, dev_bda);
+
+ bta_sys_sendmsg((void *)p_buf);
+ }
+ else
+ {
+ APPL_TRACE_ERROR0("No resource to send HID host Connect request.");
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_hh_snd_write_dev
+**
+*******************************************************************************/
+static void bta_hh_snd_write_dev(UINT8 dev_handle, UINT8 t_type, UINT8 param,
+ UINT16 data, UINT8 rpt_id, BT_HDR *p_data)
+{
+ tBTA_HH_CMD_DATA *p_buf;
+ UINT16 len = (UINT16) (sizeof(tBTA_HH_CMD_DATA) );
+
+ if ((p_buf = (tBTA_HH_CMD_DATA *)GKI_getbuf(len))!= NULL)
+ {
+ memset(p_buf, 0, sizeof(tBTA_HH_CMD_DATA));
+
+ p_buf->hdr.event = BTA_HH_API_WRITE_DEV_EVT;
+ p_buf->hdr.layer_specific = (UINT16) dev_handle;
+ p_buf->t_type = t_type;
+ p_buf->data = data;
+ p_buf->param = param;
+ p_buf->p_data = p_data;
+ p_buf->rpt_id = rpt_id;
+
+ bta_sys_sendmsg(p_buf);
+ }
+}
+/*******************************************************************************
+**
+** Function BTA_HhSetReport
+**
+** Description send SET_REPORT to device.
+**
+** Parameter dev_handle: device handle
+** r_type: report type, could be BTA_HH_RPTT_OUTPUT or
+** BTA_HH_RPTT_FEATURE.
+** Returns void
+**
+*******************************************************************************/
+void BTA_HhSetReport(UINT8 dev_handle, tBTA_HH_RPT_TYPE r_type, BT_HDR *p_data)
+{
+ bta_hh_snd_write_dev(dev_handle, HID_TRANS_SET_REPORT, r_type, 0, 0, p_data);
+}
+/*******************************************************************************
+**
+** Function BTA_HhGetReport
+**
+** Description Send a GET_REPORT to HID device.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_HhGetReport(UINT8 dev_handle, tBTA_HH_RPT_TYPE r_type, UINT8 rpt_id, UINT16 buf_size)
+{
+ UINT8 param = (buf_size) ? (r_type | 0x08) : r_type;
+
+ bta_hh_snd_write_dev(dev_handle, HID_TRANS_GET_REPORT, param,
+ buf_size, rpt_id, NULL);
+}
+/*******************************************************************************
+**
+** Function BTA_HhSetProtoMode
+**
+** Description This function set the protocol mode at specified HID handle
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_HhSetProtoMode(UINT8 dev_handle, tBTA_HH_PROTO_MODE p_type)
+{
+ bta_hh_snd_write_dev(dev_handle, HID_TRANS_SET_PROTOCOL, (UINT8)p_type,
+ 0, 0, NULL);
+}
+/*******************************************************************************
+**
+** Function BTA_HhGetProtoMode
+**
+** Description This function get protocol mode information.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_HhGetProtoMode(UINT8 dev_handle)
+{
+ bta_hh_snd_write_dev(dev_handle, HID_TRANS_GET_PROTOCOL, 0, 0, 0, NULL);
+}
+
+// btla-specific ++
+// ATTENTION:
+// BTA_HH_GET_IDLE_EVT and BTA_HH_SET_IDLE_EVT had been deprecated in the newer stack
+// btla apps will need to be changed accordingly for this
+// btla-specific --
+
+/*******************************************************************************
+**
+** Function BTA_HhSendCtrl
+**
+** Description Send a control command to HID device.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_HhSendCtrl(UINT8 dev_handle, tBTA_HH_TRANS_CTRL_TYPE c_type)
+{
+ bta_hh_snd_write_dev(dev_handle, HID_TRANS_CONTROL, (UINT8)c_type, 0, 0, NULL);
+}
+/*******************************************************************************
+**
+** Function BTA_HhSendData
+**
+** Description This function send DATA transaction to HID device.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_HhSendData(UINT8 dev_handle, BD_ADDR dev_bda, BT_HDR *p_data)
+{
+ bta_hh_snd_write_dev(dev_handle, HID_TRANS_DATA, BTA_HH_RPTT_OUTPUT, 0, 0, p_data);
+}
+
+/*******************************************************************************
+**
+** Function BTA_HhGetDscpInfo
+**
+** Description Get HID device report descriptor
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_HhGetDscpInfo(UINT8 dev_handle)
+{
+ BT_HDR *p_buf;
+
+ if ((p_buf = (BT_HDR *)GKI_getbuf((UINT16)sizeof(BT_HDR))) != NULL)
+ {
+ memset(p_buf, 0, sizeof(BT_HDR));
+ p_buf->event = BTA_HH_API_GET_DSCP_EVT;
+ p_buf->layer_specific = (UINT16) dev_handle;
+
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_HhAddDev
+**
+** Description Add a virtually cabled device into HID-Host device list
+** to manage and assign a device handle for future API call,
+** host applciation call this API at start-up to initialize its
+** virtually cabled devices.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_HhAddDev(BD_ADDR bda, tBTA_HH_ATTR_MASK attr_mask, UINT8 sub_class,
+ UINT8 app_id, tBTA_HH_DEV_DSCP_INFO dscp_info)
+{
+ tBTA_HH_MAINT_DEV *p_buf;
+ UINT16 len = sizeof(tBTA_HH_MAINT_DEV) + dscp_info.descriptor.dl_len;
+
+ p_buf = (tBTA_HH_MAINT_DEV *)GKI_getbuf(len);
+
+ if (p_buf != NULL)
+ {
+ memset(p_buf, 0, sizeof(tBTA_HH_MAINT_DEV));
+
+ p_buf->hdr.event = BTA_HH_API_MAINT_DEV_EVT;
+ p_buf->sub_event = BTA_HH_ADD_DEV_EVT;
+ p_buf->hdr.layer_specific = BTA_HH_INVALID_HANDLE;
+
+ p_buf->attr_mask = (UINT16) attr_mask;
+ p_buf->sub_class = sub_class;
+ p_buf->app_id = app_id;
+ bdcpy(p_buf->bda, bda);
+
+ memcpy(&p_buf->dscp_info, &dscp_info, sizeof(tBTA_HH_DEV_DSCP_INFO));
+ if ( dscp_info.descriptor.dl_len != 0 && dscp_info.descriptor.dsc_list)
+ {
+ p_buf->dscp_info.descriptor.dl_len = dscp_info.descriptor.dl_len;
+ p_buf->dscp_info.descriptor.dsc_list = (UINT8 *)(p_buf + 1);
+ memcpy(p_buf->dscp_info.descriptor.dsc_list, dscp_info.descriptor.dsc_list, dscp_info.descriptor.dl_len);
+ }
+ else
+ {
+ p_buf->dscp_info.descriptor.dsc_list = NULL;
+ p_buf->dscp_info.descriptor.dl_len = 0;
+ }
+
+ bta_sys_sendmsg(p_buf);
+ }
+}
+/*******************************************************************************
+**
+** Function BTA_HhRemoveDev
+**
+** Description Remove a device from the HID host devices list.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_HhRemoveDev(UINT8 dev_handle )
+{
+ tBTA_HH_MAINT_DEV *p_buf;
+
+ p_buf = (tBTA_HH_MAINT_DEV *)GKI_getbuf((UINT16)sizeof(tBTA_HH_MAINT_DEV));
+
+ if (p_buf != NULL)
+ {
+ memset(p_buf, 0, sizeof(tBTA_HH_MAINT_DEV));
+
+ p_buf->hdr.event = BTA_HH_API_MAINT_DEV_EVT;
+ p_buf->sub_event = BTA_HH_RMV_DEV_EVT;
+ p_buf->hdr.layer_specific = (UINT16) dev_handle;
+
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************/
+/* Utility Function */
+/*******************************************************************************/
+
+/*******************************************************************************
+**
+** Function BTA_HhParseBootRpt
+**
+** Description This utility function parse a boot mode report.
+** For keyboard report, report data will carry the keycode max
+** up to 6 key press in one report. Application need to convert
+** the keycode into keypress character according to keyboard
+** language.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_HhParseBootRpt(tBTA_HH_BOOT_RPT *p_data, UINT8 *p_report,
+ UINT16 report_len)
+{
+ p_data->dev_type = BTA_HH_DEVT_UNKNOWN;
+
+ if (p_report)
+ {
+ /* first byte is report ID */
+ switch (p_report[0])
+ {
+ case BTA_HH_KEYBD_RPT_ID: /* key board report ID */
+ p_data->dev_type = p_report[0];
+ bta_hh_parse_keybd_rpt(p_data, p_report + 1, (UINT16)(report_len -1));
+ break;
+
+ case BTA_HH_MOUSE_RPT_ID: /* mouse report ID */
+ p_data->dev_type = p_report[0];
+ bta_hh_parse_mice_rpt(p_data, p_report + 1, (UINT16)(report_len - 1));
+ break;
+
+ default:
+ APPL_TRACE_DEBUG1("Unknown boot report: %d", p_report[0]);;
+ break;
+ }
+ }
+
+ return;
+}
+
+#endif /* BTA_HH_INCLUDED */
diff --git a/bta/hh/bta_hh_cfg.c b/bta/hh/bta_hh_cfg.c
new file mode 100644
index 0000000..126ae4a
--- /dev/null
+++ b/bta/hh/bta_hh_cfg.c
@@ -0,0 +1,52 @@
+/*****************************************************************************
+**
+** Name: bta_hh_cfg.c
+**
+** Description: This file contains compile-time configurable constants
+** for the BTA Hid Host.
+**
+** Copyright (c) 2005, Broadcom Corp, All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+#include "bta_hh_api.h"
+
+/* max number of device types supported by BTA */
+#define BTA_HH_MAX_DEVT_SPT 7
+
+/* size of database for service discovery */
+#ifndef BTA_HH_DISC_BUF_SIZE
+#define BTA_HH_DISC_BUF_SIZE GKI_MAX_BUF_SIZE
+#endif
+
+/* application ID(none-zero) for each type of device */
+#define BTA_HH_APP_ID_MI 1
+#define BTA_HH_APP_ID_KB 2
+#define BTA_HH_APP_ID_RMC 3
+#define BTA_HH_APP_ID_3DSG 4
+
+
+/* The type of devices supported by BTA HH and corresponding application ID */
+tBTA_HH_SPT_TOD p_devt_list[BTA_HH_MAX_DEVT_SPT] =
+{
+ {BTA_HH_DEVT_MIC, BTA_HH_APP_ID_MI},
+ {BTA_HH_DEVT_KBD, BTA_HH_APP_ID_KB},
+ {BTA_HH_DEVT_KBD|BTA_HH_DEVT_MIC, BTA_HH_APP_ID_KB},
+ {BTA_HH_DEVT_RMC, BTA_HH_APP_ID_RMC},
+ {BTA_HH_DEVT_RMC | BTA_HH_DEVT_KBD, BTA_HH_APP_ID_RMC},
+ {BTA_HH_DEVT_MIC | BTA_HH_DEVT_DGT, BTA_HH_APP_ID_MI},
+ {BTA_HH_DEVT_UNKNOWN, BTA_HH_APP_ID_3DSG}
+};
+
+
+const tBTA_HH_CFG bta_hh_cfg =
+{
+ BTA_HH_MAX_DEVT_SPT, /* number of supported type of devices */
+ p_devt_list, /* ToD & AppID list */
+ BTA_HH_DISC_BUF_SIZE /* HH SDP discovery database size */
+};
+
+
+tBTA_HH_CFG *p_bta_hh_cfg = (tBTA_HH_CFG *)&bta_hh_cfg;
diff --git a/bta/hh/bta_hh_int.h b/bta/hh/bta_hh_int.h
new file mode 100644
index 0000000..51dfad1
--- /dev/null
+++ b/bta/hh/bta_hh_int.h
@@ -0,0 +1,235 @@
+/****************************************************************************/
+/* */
+/* Name: bta_hh_int.h */
+/* */
+/* Function: this file contains BTA HID Host internal definitions */
+/* */
+/* Copyright (c) 2005, Broadcom Corp, All Rights Reserved. */
+/* WIDCOMM Bluetooth Core. Proprietary and confidential. */
+/* */
+/****************************************************************************/
+
+#ifndef BTA_HH_INT_H
+#define BTA_HH_INT_H
+
+#include "bta_sys.h"
+#include "bd.h"
+#include "utl.h"
+#include "bta_hh_api.h"
+
+/* can be moved to bta_api.h */
+#define BTA_HH_MAX_RPT_CHARS 8
+
+
+/* state machine events, these events are handled by the state machine */
+enum
+{
+ BTA_HH_API_OPEN_EVT = BTA_SYS_EVT_START(BTA_ID_HH),
+ BTA_HH_API_CLOSE_EVT,
+ BTA_HH_INT_OPEN_EVT,
+ BTA_HH_INT_CLOSE_EVT,
+ BTA_HH_INT_DATA_EVT,
+ BTA_HH_INT_CTRL_DATA,
+ BTA_HH_INT_HANDSK_EVT,
+ BTA_HH_SDP_CMPL_EVT,
+ BTA_HH_API_WRITE_DEV_EVT,
+ BTA_HH_API_GET_DSCP_EVT,
+ BTA_HH_API_MAINT_DEV_EVT,
+ BTA_HH_OPEN_CMPL_EVT,
+
+ /* not handled by execute state machine */
+ BTA_HH_API_ENABLE_EVT,
+ BTA_HH_API_DISABLE_EVT,
+ BTA_HH_DISC_CMPL_EVT
+};
+typedef UINT16 tBTA_HH_INT_EVT; /* HID host internal events */
+
+#define BTA_HH_INVALID_EVT (BTA_HH_DISC_CMPL_EVT + 1)
+
+/* event used to map between BTE event and BTA event */
+#define BTA_HH_FST_TRANS_CB_EVT BTA_HH_GET_RPT_EVT
+#define BTA_HH_FST_BTE_TRANS_EVT HID_TRANS_GET_REPORT
+
+/* sub event code used for device maintainence API call */
+#define BTA_HH_ADD_DEV 0
+#define BTA_HH_REMOVE_DEV 1
+
+/* state machine states */
+enum
+{
+ BTA_HH_NULL_ST,
+ BTA_HH_IDLE_ST,
+ BTA_HH_W4_CONN_ST,
+ BTA_HH_CONN_ST
+};
+typedef UINT8 tBTA_HH_STATE;
+
+/* data structure used to send a command/data to HID device */
+typedef struct
+{
+ BT_HDR hdr;
+ UINT8 t_type;
+ UINT8 param;
+ UINT8 rpt_id;
+ UINT16 data;
+ BT_HDR *p_data;
+}tBTA_HH_CMD_DATA;
+
+/* data type for BTA_HH_API_ENABLE_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ UINT8 sec_mask;
+ UINT8 service_name[BTA_SERVICE_NAME_LEN+1];
+ tBTA_HH_CBACK *p_cback;
+} tBTA_HH_API_ENABLE;
+
+typedef struct
+{
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+ UINT8 sec_mask;
+ tBTA_HH_PROTO_MODE mode;
+}tBTA_HH_API_CONN;
+
+/* internal event data from BTE HID callback */
+typedef struct
+{
+ BT_HDR hdr;
+ UINT32 data;
+ BT_HDR *p_data;
+}tBTA_HH_CBACK_DATA;
+
+typedef struct
+{
+ BT_HDR hdr;
+ BD_ADDR bda;
+ UINT16 attr_mask;
+ UINT16 sub_event;
+ UINT8 sub_class;
+ UINT8 app_id;
+ tBTA_HH_DEV_DSCP_INFO dscp_info;
+}tBTA_HH_MAINT_DEV;
+
+/* union of all event data types */
+typedef union
+{
+ BT_HDR hdr;
+ tBTA_HH_API_ENABLE api_enable;
+ tBTA_HH_API_CONN api_conn;
+ tBTA_HH_CMD_DATA api_sndcmd;
+ tBTA_HH_CBACK_DATA hid_cback;
+ tBTA_HH_STATUS status;
+ tBTA_HH_MAINT_DEV api_maintdev;
+} tBTA_HH_DATA;
+
+/* device control block */
+typedef struct
+{
+ tBTA_HH_DEV_DSCP_INFO dscp_info; /* report descriptor and DI information */
+ BD_ADDR addr; /* BD-Addr of the HID device */
+ UINT16 attr_mask; /* attribute mask */
+ UINT16 w4_evt; /* W4_handshake event name */
+ UINT8 index; /* index number referenced to handle index */
+ UINT8 sub_class; /* Cod sub class */
+ UINT8 sec_mask; /* security mask */
+ UINT8 app_id; /* application ID for this connection */
+ UINT8 hid_handle; /* device handle */
+ BOOLEAN vp; /* virtually unplug flag */
+ BOOLEAN in_use; /* control block currently in use */
+ BOOLEAN incoming_conn; /* is incoming connection? */
+ BOOLEAN opened; /* TRUE if device successfully opened HID connection */
+ tBTA_HH_PROTO_MODE mode; /* protocol mode */
+ tBTA_HH_STATE state; /* CB state */
+} tBTA_HH_DEV_CB;
+
+/* key board parsing control block */
+typedef struct
+{
+ BOOLEAN mod_key[4]; /* ctrl, shift(upper), Alt, GUI */
+ BOOLEAN num_lock;
+ BOOLEAN caps_lock;
+ UINT8 last_report[BTA_HH_MAX_RPT_CHARS];
+} tBTA_HH_KB_CB;
+
+/******************************************************************************
+** Main Control Block
+*******************************************************************************/
+typedef struct
+{
+ tBTA_HH_KB_CB kb_cb; /* key board control block,
+ suppose BTA will connect
+ to only one keyboard at
+ the same time */
+ tBTA_HH_DEV_CB kdev[BTA_HH_MAX_KNOWN]; /* device control block */
+ tBTA_HH_DEV_CB* p_cur; /* current device control
+ block idx, used in sdp */
+ UINT8 cb_index[BTA_HH_MAX_KNOWN]; /* maintain a CB index
+ map to dev handle */
+ tBTA_HH_CBACK *p_cback; /* Application callbacks */
+ tSDP_DISCOVERY_DB* p_disc_db;
+ UINT8 trace_level; /* tracing level */
+ UINT8 cnt_num; /* connected device number */
+ BOOLEAN w4_disable; /* w4 disable flag */
+}
+tBTA_HH_CB;
+
+#if BTA_DYNAMIC_MEMORY == FALSE
+extern tBTA_HH_CB bta_hh_cb;
+#else
+extern tBTA_HH_CB *bta_hh_cb_ptr;
+#define bta_hh_cb (*bta_hh_cb_ptr)
+#endif
+
+/* from bta_hh_cfg.c */
+extern tBTA_HH_CFG *p_bta_hh_cfg;
+
+/*****************************************************************************
+** Function prototypes
+*****************************************************************************/
+extern BOOLEAN bta_hh_hdl_event(BT_HDR *p_msg);
+extern void bta_hh_sm_execute(tBTA_HH_DEV_CB *p_cb, UINT16 event,
+ tBTA_HH_DATA *p_data);
+
+/* action functions */
+extern void bta_hh_api_disc_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data);
+extern void bta_hh_open_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data);
+extern void bta_hh_close_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data);
+extern void bta_hh_data_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA * p_data);
+extern void bta_hh_ctrl_dat_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA * p_data);
+extern void bta_hh_start_sdp(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data);
+extern void bta_hh_sdp_cmpl(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data);
+extern void bta_hh_write_dev_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data);
+extern void bta_hh_get_dscp_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data);
+extern void bta_hh_handsk_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data);
+extern void bta_hh_maint_dev_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data);
+extern void bta_hh_open_cmpl_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data);
+
+/* utility functions */
+extern UINT8 bta_hh_find_cb(BD_ADDR bda);
+extern void bta_hh_parse_keybd_rpt(tBTA_HH_BOOT_RPT *p_kb_data,
+ UINT8 *p_report, UINT16 report_len);
+extern void bta_hh_parse_mice_rpt(tBTA_HH_BOOT_RPT *p_kb_data,
+ UINT8 *p_report, UINT16 report_len);
+extern BOOLEAN bta_hh_tod_spt(tBTA_HH_DEV_CB *p_cb,UINT8 sub_class);
+extern void bta_hh_clean_up_kdev(tBTA_HH_DEV_CB *p_cb);
+
+extern void bta_hh_add_device_to_list(tBTA_HH_DEV_CB *p_cb, UINT8 handle,
+ UINT16 attr_mask,
+ tHID_DEV_DSCP_INFO *p_dscp_info,
+ UINT8 sub_class, UINT16 max_latency, UINT16 min_tout, UINT8 app_id);
+extern void bta_hh_update_di_info(tBTA_HH_DEV_CB *p_cb, UINT16 vendor_id, UINT16 product_id,
+ UINT16 version);
+
+/* action functions used outside state machine */
+extern void bta_hh_api_enable(tBTA_HH_DATA *p_data);
+extern void bta_hh_api_disable(void);
+extern void bta_hh_disc_cmpl(void);
+
+
+#if BTA_HH_DEBUG
+extern void bta_hh_trace_dev_db(void);
+#endif
+
+#endif
+
diff --git a/bta/hh/bta_hh_main.c b/bta/hh/bta_hh_main.c
new file mode 100644
index 0000000..648b10f
--- /dev/null
+++ b/bta/hh/bta_hh_main.c
@@ -0,0 +1,429 @@
+/*****************************************************************************
+**
+** Name: bta_hh_main.c
+**
+** Description: This file contains the HID host main functions and state
+** machine.
+**
+** Copyright (c) 2005, Broadcom Corp, All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+
+#if defined(BTA_HH_INCLUDED) && (BTA_HH_INCLUDED == TRUE)
+
+#include <string.h>
+
+#include "bta_hh_api.h"
+#include "bta_hh_int.h"
+#include "gki.h"
+
+/*****************************************************************************
+** Constants and types
+*****************************************************************************/
+
+/* state machine action enumeration list */
+enum
+{
+ BTA_HH_API_DISC_ACT, /* HID host process API close action */
+ BTA_HH_OPEN_ACT, /* HID host process BTA_HH_EVT_OPEN */
+ BTA_HH_CLOSE_ACT, /* HID host process BTA_HH_EVT_CLOSE */
+ BTA_HH_DATA_ACT, /* HID host receive data report */
+ BTA_HH_CTRL_DAT_ACT,
+ BTA_HH_HANDSK_ACT,
+ BTA_HH_START_SDP, /* HID host inquery */
+ BTA_HH_SDP_CMPL,
+ BTA_HH_WRITE_DEV_ACT,
+ BTA_HH_GET_DSCP_ACT,
+ BTA_HH_MAINT_DEV_ACT,
+ BTA_HH_OPEN_CMPL_ACT,
+ BTA_HH_NUM_ACTIONS
+};
+
+#define BTA_HH_IGNORE BTA_HH_NUM_ACTIONS
+
+/* type for action functions */
+typedef void (*tBTA_HH_ACTION)(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data);
+
+/* action functions */
+const tBTA_HH_ACTION bta_hh_action[] =
+{
+ bta_hh_api_disc_act,
+ bta_hh_open_act,
+ bta_hh_close_act,
+ bta_hh_data_act,
+ bta_hh_ctrl_dat_act,
+ bta_hh_handsk_act,
+ bta_hh_start_sdp,
+ bta_hh_sdp_cmpl,
+ bta_hh_write_dev_act,
+ bta_hh_get_dscp_act,
+ bta_hh_maint_dev_act,
+ bta_hh_open_cmpl_act
+};
+
+/* state table information */
+#define BTA_HH_ACTION 0 /* position of action */
+#define BTA_HH_NEXT_STATE 1 /* position of next state */
+#define BTA_HH_NUM_COLS 2 /* number of columns */
+
+/* state table for idle state */
+const UINT8 bta_hh_st_idle[][BTA_HH_NUM_COLS] =
+{
+/* Event Action Next state */
+/* BTA_HH_API_OPEN_EVT */ {BTA_HH_START_SDP, BTA_HH_W4_CONN_ST },
+/* BTA_HH_API_CLOSE_EVT */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST },
+/* BTA_HH_INT_OPEN_EVT */ {BTA_HH_OPEN_ACT, BTA_HH_W4_CONN_ST },
+/* BTA_HH_INT_CLOSE_EVT */ {BTA_HH_CLOSE_ACT, BTA_HH_IDLE_ST },
+/* BTA_HH_INT_DATA_EVT */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST },
+/* BTA_HH_INT_CTRL_DATA */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST },
+/* BTA_HH_INT_HANDSK_EVT */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST },
+/* BTA_HH_SDP_CMPL_EVT */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST },
+/* BTA_HH_API_WRITE_DEV_EVT */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST },
+/* BTA_HH_API_GET_DSCP_EVT */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST },
+/* BTA_HH_API_MAINT_DEV_EVT */ {BTA_HH_MAINT_DEV_ACT, BTA_HH_IDLE_ST },
+/* BTA_HH_OPEN_CMPL_EVT */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST }
+
+};
+
+
+const UINT8 bta_hh_st_w4_conn[][BTA_HH_NUM_COLS] =
+{
+/* Event Action Next state */
+/* BTA_HH_API_OPEN_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_CONN_ST },
+/* BTA_HH_API_CLOSE_EVT */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST },
+/* BTA_HH_INT_OPEN_EVT */ {BTA_HH_OPEN_ACT, BTA_HH_W4_CONN_ST },
+/* BTA_HH_INT_CLOSE_EVT */ {BTA_HH_CLOSE_ACT, BTA_HH_IDLE_ST },
+/* BTA_HH_INT_DATA_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_CONN_ST },
+/* BTA_HH_INT_CTRL_DATA */ {BTA_HH_IGNORE, BTA_HH_W4_CONN_ST },
+/* BTA_HH_INT_HANDSK_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_CONN_ST },
+/* BTA_HH_SDP_CMPL_EVT */ {BTA_HH_SDP_CMPL, BTA_HH_W4_CONN_ST },
+/* BTA_HH_API_WRITE_DEV_EVT */ {BTA_HH_IGNORE , BTA_HH_W4_CONN_ST },
+/* BTA_HH_API_GET_DSCP_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_CONN_ST },
+/* BTA_HH_API_MAINT_DEV_EVT */ {BTA_HH_MAINT_DEV_ACT, BTA_HH_IDLE_ST },
+/* BTA_HH_OPEN_CMPL_EVT */ {BTA_HH_OPEN_CMPL_ACT, BTA_HH_CONN_ST }
+};
+
+
+const UINT8 bta_hh_st_connected[][BTA_HH_NUM_COLS] =
+{
+/* Event Action Next state */
+/* BTA_HH_API_OPEN_EVT */ {BTA_HH_IGNORE, BTA_HH_CONN_ST },
+/* BTA_HH_API_CLOSE_EVT */ {BTA_HH_API_DISC_ACT, BTA_HH_CONN_ST },
+/* BTA_HH_INT_OPEN_EVT */ {BTA_HH_OPEN_ACT, BTA_HH_CONN_ST },
+/* BTA_HH_INT_CLOSE_EVT */ {BTA_HH_CLOSE_ACT, BTA_HH_IDLE_ST },
+/* BTA_HH_INT_DATA_EVT */ {BTA_HH_DATA_ACT, BTA_HH_CONN_ST },
+/* BTA_HH_INT_CTRL_DATA */ {BTA_HH_CTRL_DAT_ACT, BTA_HH_CONN_ST },
+/* BTA_HH_INT_HANDSK_EVT */ {BTA_HH_HANDSK_ACT, BTA_HH_CONN_ST },
+/* BTA_HH_SDP_CMPL_EVT */ {BTA_HH_IGNORE, BTA_HH_CONN_ST },
+/* BTA_HH_API_WRITE_DEV_EVT */ {BTA_HH_WRITE_DEV_ACT, BTA_HH_CONN_ST },
+/* BTA_HH_API_GET_DSCP_EVT */ {BTA_HH_GET_DSCP_ACT, BTA_HH_CONN_ST },
+/* BTA_HH_API_MAINT_DEV_EVT */ {BTA_HH_MAINT_DEV_ACT, BTA_HH_CONN_ST },
+/* BTA_HH_OPEN_CMPL_EVT */ {BTA_HH_IGNORE, BTA_HH_CONN_ST }
+};
+
+/* type for state table */
+typedef const UINT8 (*tBTA_HH_ST_TBL)[BTA_HH_NUM_COLS];
+
+/* state table */
+const tBTA_HH_ST_TBL bta_hh_st_tbl[] =
+{
+ bta_hh_st_idle,
+ bta_hh_st_w4_conn,
+ bta_hh_st_connected
+};
+
+/*****************************************************************************
+** Global data
+*****************************************************************************/
+#if BTA_DYNAMIC_MEMORY == FALSE
+tBTA_HH_CB bta_hh_cb;
+#endif
+/*****************************************************************************
+** Static functions
+*****************************************************************************/
+#if BTA_HH_DEBUG == TRUE
+static char *bta_hh_evt_code(tBTA_HH_INT_EVT evt_code);
+static char *bta_hh_state_code(tBTA_HH_STATE state_code);
+#endif
+
+/*******************************************************************************
+**
+** Function bta_hh_sm_execute
+**
+** Description State machine event handling function for HID Host
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hh_sm_execute(tBTA_HH_DEV_CB *p_cb, UINT16 event, tBTA_HH_DATA * p_data)
+{
+ tBTA_HH_ST_TBL state_table;
+ UINT8 action;
+ tBTA_HH cback_data;
+ tBTA_HH_EVT cback_event = 0;
+#if BTA_HH_DEBUG == TRUE
+ tBTA_HH_STATE in_state ;
+ UINT16 debug_event = event;
+#endif
+
+ memset(&cback_data, 0, sizeof(tBTA_HH));
+
+ /* handle exception, no valid control block was found */
+ if (!p_cb)
+ {
+ /* BTA HH enabled already? otherwise ignore the event although it's bad*/
+ if (bta_hh_cb.p_cback != NULL)
+ {
+ switch (event)
+ {
+ /* no control block available for new connection */
+ case BTA_HH_API_OPEN_EVT:
+ cback_event = BTA_HH_OPEN_EVT;
+ /* build cback data */
+ bdcpy(cback_data.conn.bda, ((tBTA_HH_API_CONN *)p_data)->bd_addr);
+ cback_data.conn.status = BTA_HH_ERR_DB_FULL;
+ cback_data.conn.handle = BTA_HH_INVALID_HANDLE;
+ break;
+ /* DB full, BTA_HhAddDev */
+ case BTA_HH_API_MAINT_DEV_EVT:
+ cback_event = p_data->api_maintdev.sub_event;
+
+ if (p_data->api_maintdev.sub_event == BTA_HH_ADD_DEV_EVT)
+ {
+ bdcpy(cback_data.dev_info.bda, p_data->api_maintdev.bda);
+ cback_data.dev_info.status = BTA_HH_ERR_DB_FULL;
+ cback_data.dev_info.handle = BTA_HH_INVALID_HANDLE;
+ }
+ else
+ {
+ cback_data.dev_info.status = BTA_HH_ERR_HDL;
+ cback_data.dev_info.handle = (UINT8)p_data->api_maintdev.hdr.layer_specific;
+ }
+ break;
+ case BTA_HH_API_WRITE_DEV_EVT:
+ cback_event = (p_data->api_sndcmd.t_type - BTA_HH_FST_BTE_TRANS_EVT) +
+ BTA_HH_FST_TRANS_CB_EVT;
+ if (p_data->api_sndcmd.t_type == HID_TRANS_SET_PROTOCOL ||
+ p_data->api_sndcmd.t_type == HID_TRANS_SET_REPORT ||
+ p_data->api_sndcmd.t_type == HID_TRANS_SET_IDLE)
+ {
+ cback_data.dev_status.status = BTA_HH_ERR_HDL;
+ cback_data.dev_status.handle = (UINT8)p_data->api_sndcmd.hdr.layer_specific;
+ }
+ else if (p_data->api_sndcmd.t_type != HID_TRANS_DATA &&
+ p_data->api_sndcmd.t_type != HID_TRANS_CONTROL)
+ {
+ cback_data.hs_data.handle = (UINT8)p_data->api_sndcmd.hdr.layer_specific;
+ cback_data.hs_data.status = BTA_HH_ERR_HDL;
+ /* hs_data.rsp_data will be all zero, which is not valid value */
+ }
+ break;
+
+ case BTA_HH_API_CLOSE_EVT:
+ cback_event = BTA_HH_CLOSE_EVT;
+
+ cback_data.dev_status.status = BTA_HH_ERR_HDL;
+ cback_data.dev_status.handle = (UINT8)p_data->api_sndcmd.hdr.layer_specific;
+ break;
+
+ default:
+ /* invalid handle, call bad API event */
+ APPL_TRACE_ERROR1("wrong device handle: [%d]", p_data->hdr.layer_specific);
+ break;
+ }
+ if (cback_event)
+ (* bta_hh_cb.p_cback)(cback_event, &cback_data);
+ }
+ }
+ /* corresponding CB is found, go to state machine */
+ else
+ {
+#if BTA_HH_DEBUG == TRUE
+ in_state = p_cb->state;
+ APPL_TRACE_EVENT3("bta_hh_sm_execute: State 0x%02x [%s], Event [%s]",
+ in_state, bta_hh_state_code(in_state),
+ bta_hh_evt_code(debug_event));
+#endif
+
+ state_table = bta_hh_st_tbl[p_cb->state - 1];
+
+ event &= 0xff;
+
+ p_cb->state = state_table[event][BTA_HH_NEXT_STATE] ;
+
+ if ((action = state_table[event][BTA_HH_ACTION]) != BTA_HH_IGNORE)
+ {
+ (*bta_hh_action[action])(p_cb, p_data);
+ }
+
+#if BTA_HH_DEBUG == TRUE
+ if (in_state != p_cb->state)
+ {
+ APPL_TRACE_DEBUG3("HH State Change: [%s] -> [%s] after Event [%s]",
+ bta_hh_state_code(in_state),
+ bta_hh_state_code(p_cb->state),
+ bta_hh_evt_code(debug_event));
+ }
+#endif
+ }
+
+ return;
+}
+/*******************************************************************************
+**
+** Function bta_hh_hdl_event
+**
+** Description HID host main event handling function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BOOLEAN bta_hh_hdl_event(BT_HDR *p_msg)
+{
+ UINT8 index = BTA_HH_MAX_KNOWN;
+ tBTA_HH_DEV_CB *p_cb = NULL;
+
+ switch (p_msg->event)
+ {
+ case BTA_HH_API_ENABLE_EVT:
+ bta_hh_api_enable((tBTA_HH_DATA *) p_msg);
+ break;
+
+ case BTA_HH_API_DISABLE_EVT:
+ bta_hh_api_disable();
+ break;
+
+ case BTA_HH_DISC_CMPL_EVT: /* disable complete */
+ bta_hh_disc_cmpl();
+ break;
+
+ default:
+ /* all events processed in state machine need to find corresponding
+ CB before proceed */
+ if (p_msg->event == BTA_HH_API_OPEN_EVT)
+ {
+ index = bta_hh_find_cb(((tBTA_HH_API_CONN *)p_msg)->bd_addr);
+ }
+ else if (p_msg->event == BTA_HH_API_MAINT_DEV_EVT)
+ {
+ /* if add device */
+ if (((tBTA_HH_MAINT_DEV *)p_msg)->sub_event == BTA_HH_ADD_DEV_EVT)
+ {
+ index = bta_hh_find_cb(((tBTA_HH_MAINT_DEV *)p_msg)->bda);
+ }
+ else /* else remove device by handle */
+ {
+ index = bta_hh_cb.cb_index[p_msg->layer_specific];
+// btla-specific ++
+ /* If BT disable is done while the HID device is connected and Link_Key uses unauthenticated combination
+ * then we can get into a situation where remove_bonding is called with the index set to 0 (without getting
+ * cleaned up). Only when VIRTUAL_UNPLUG is called do we cleanup the index and make it MAX_KNOWN.
+ * So if REMOVE_DEVICE is called and in_use is FALSE then we should treat this as a NULL p_cb. Hence we
+ * force the index to be MAX_KNOWN
+ */
+ if (bta_hh_cb.kdev[index].in_use == FALSE) {
+ index = BTA_HH_MAX_KNOWN;
+ }
+// btla-specific --
+ }
+ }
+ else if (p_msg->layer_specific < BTA_HH_MAX_KNOWN )
+ index = bta_hh_cb.cb_index[p_msg->layer_specific];
+
+ if (index != BTA_HH_MAX_KNOWN)
+ p_cb = &bta_hh_cb.kdev[index];
+
+#if BTA_HH_DEBUG
+ APPL_TRACE_DEBUG2("bta_hh_hdl_event:: handle = %d dev_cb[%d] ", p_msg->layer_specific, index);
+#endif
+ bta_hh_sm_execute(p_cb, p_msg->event, (tBTA_HH_DATA *) p_msg);
+ }
+ return (TRUE);
+}
+
+/*****************************************************************************
+** Debug Functions
+*****************************************************************************/
+#if BTA_HH_DEBUG
+/*******************************************************************************
+**
+** Function bta_hh_evt_code
+**
+** Description
+**
+** Returns void
+**
+*******************************************************************************/
+static char *bta_hh_evt_code(tBTA_HH_INT_EVT evt_code)
+{
+ switch(evt_code)
+ {
+ case BTA_HH_API_DISABLE_EVT:
+ return "BTA_HH_API_DISABLE_EVT";
+ case BTA_HH_API_ENABLE_EVT:
+ return "BTA_HH_API_ENABLE_EVT";
+ case BTA_HH_API_OPEN_EVT:
+ return "BTA_HH_API_OPEN_EVT";
+ case BTA_HH_API_CLOSE_EVT:
+ return "BTA_HH_API_CLOSE_EVT";
+ case BTA_HH_INT_OPEN_EVT:
+ return "BTA_HH_INT_OPEN_EVT";
+ case BTA_HH_INT_CLOSE_EVT:
+ return "BTA_HH_INT_CLOSE_EVT";
+ case BTA_HH_INT_HANDSK_EVT:
+ return "BTA_HH_INT_HANDSK_EVT";
+ case BTA_HH_INT_DATA_EVT:
+ return "BTA_HH_INT_DATA_EVT";
+ case BTA_HH_INT_CTRL_DATA:
+ return "BTA_HH_INT_CTRL_DATA";
+ case BTA_HH_API_WRITE_DEV_EVT:
+ return "BTA_HH_API_WRITE_DEV_EVT";
+ case BTA_HH_SDP_CMPL_EVT:
+ return "BTA_HH_SDP_CMPL_EVT";
+ case BTA_HH_DISC_CMPL_EVT:
+ return "BTA_HH_DISC_CMPL_EVT";
+ case BTA_HH_API_MAINT_DEV_EVT:
+ return "BTA_HH_API_MAINT_DEV_EVT";
+ case BTA_HH_API_GET_DSCP_EVT:
+ return "BTA_HH_API_GET_DSCP_EVT";
+ case BTA_HH_OPEN_CMPL_EVT:
+ return "BTA_HH_OPEN_CMPL_EVT";
+ default:
+ return "unknown HID Host event code";
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_hh_state_code
+**
+** Description get string representation of HID host state code.
+**
+** Returns void
+**
+*******************************************************************************/
+static char *bta_hh_state_code(tBTA_HH_STATE state_code)
+{
+ switch (state_code)
+ {
+ case BTA_HH_NULL_ST:
+ return"BTA_HH_NULL_ST";
+ case BTA_HH_IDLE_ST:
+ return "BTA_HH_IDLE_ST";
+ case BTA_HH_W4_CONN_ST:
+ return "BTA_HH_W4_CONN_ST";
+ case BTA_HH_CONN_ST:
+ return "BTA_HH_CONN_ST";
+ default:
+ return "unknown HID Host state";
+ }
+}
+
+#endif /* Debug Functions */
+
+#endif /* BTA_HH_INCLUDED */
diff --git a/bta/hh/bta_hh_utils.c b/bta/hh/bta_hh_utils.c
new file mode 100644
index 0000000..18ff0c3
--- /dev/null
+++ b/bta/hh/bta_hh_utils.c
@@ -0,0 +1,409 @@
+/*****************************************************************************
+**
+** Name: bta_hh_utils.c
+**
+** File: Implements the untility functions used by HID Host
+**
+** Copyright (c) 2005, Broadcom Corp, All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include <string.h>
+
+#include "bt_target.h"
+#if defined(HL_INCLUDED) && (HL_INCLUDED == TRUE)
+
+#include "bta_hh_int.h"
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+#define BTA_HH_KB_CTRL_MASK 0x11
+#define BTA_HH_KB_SHIFT_MASK 0x22
+#define BTA_HH_KB_ALT_MASK 0x44
+#define BTA_HH_KB_GUI_MASK 0x88
+
+#define BTA_HH_KB_CAPS_LOCK 0x39 /* caps lock */
+#define BTA_HH_KB_NUM_LOCK 0x53 /* num lock */
+
+
+#define BTA_HH_MAX_RPT_CHARS 8
+
+static const UINT8 bta_hh_mod_key_mask[BTA_HH_MOD_MAX_KEY] =
+{
+ BTA_HH_KB_CTRL_MASK,
+ BTA_HH_KB_SHIFT_MASK,
+ BTA_HH_KB_ALT_MASK,
+ BTA_HH_KB_GUI_MASK
+};
+
+
+/*******************************************************************************
+**
+** Function bta_hh_find_cb
+**
+** Description Find best available control block according to BD address.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+UINT8 bta_hh_find_cb(BD_ADDR bda)
+{
+ UINT8 xx;
+
+ /* See how many active devices there are. */
+ for (xx = 0; xx < BTA_HH_MAX_KNOWN; xx++)
+ {
+ /* check if any active/known devices is a match */
+ if ((!bdcmp (bda, bta_hh_cb.kdev[xx].addr) &&
+ bdcmp(bda, bd_addr_null) != 0) )
+ {
+#if BTA_HH_DEBUG
+ APPL_TRACE_DEBUG2("found kdev_cb[%d] hid_handle = %d ", xx,
+ bta_hh_cb.kdev[xx].hid_handle)
+#endif
+ return xx;
+ }
+#if BTA_HH_DEBUG
+ else
+ APPL_TRACE_DEBUG4("in_use ? [%d] kdev[%d].hid_handle = %d state = [%d]",
+ bta_hh_cb.kdev[xx].in_use, xx,
+ bta_hh_cb.kdev[xx].hid_handle,
+ bta_hh_cb.kdev[xx].state);
+#endif
+ }
+
+ /* if no active device match, find a spot for it */
+ for (xx = 0; xx < BTA_HH_MAX_KNOWN; xx++)
+ {
+ if (!bta_hh_cb.kdev[xx].in_use)
+ {
+ bdcpy(bta_hh_cb.kdev[xx].addr, bda);
+ break;
+ }
+ }
+ /* If device list full, report BTA_HH_MAX_KNOWN */
+#if BTA_HH_DEBUG
+ APPL_TRACE_DEBUG2("bta_hh_find_cb:: index = %d while max = %d",
+ xx, BTA_HH_MAX_KNOWN);
+#endif
+
+ return xx;
+}
+
+/*******************************************************************************
+**
+** Function bta_hh_clean_up_kdev
+**
+** Description Clean up device control block when device is removed from
+** manitainace list, and update control block index map.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hh_clean_up_kdev(tBTA_HH_DEV_CB *p_cb)
+{
+ UINT8 index;
+
+ if (p_cb->hid_handle != BTA_HH_INVALID_HANDLE )
+ bta_hh_cb.cb_index[p_cb->hid_handle] = BTA_HH_MAX_KNOWN;
+
+ /* reset device control block */
+ index = p_cb->index; /* Preserve index for this control block */
+
+ /* Free buffer for report descriptor info */
+ utl_freebuf((void **)&p_cb->dscp_info.descriptor.dsc_list);
+
+ memset(p_cb, 0, sizeof (tBTA_HH_DEV_CB)); /* Reset control block */
+
+ p_cb->index = index; /* Restore index for this control block */
+ p_cb->state = BTA_HH_IDLE_ST;
+ p_cb->hid_handle = BTA_HH_INVALID_HANDLE;
+
+}
+/*******************************************************************************
+**
+** Function bta_hh_update_di_info
+**
+** Description Maintain a known device list for BTA HH.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hh_update_di_info(tBTA_HH_DEV_CB *p_cb, UINT16 vendor_id, UINT16 product_id,
+ UINT16 version)
+{
+#if BTA_HH_DEBUG
+ APPL_TRACE_DEBUG3("vendor_id = 0x%2x product_id = 0x%2x version = 0x%2x",
+ vendor_id, product_id, version);
+#endif
+ p_cb->dscp_info.vendor_id = vendor_id;
+ p_cb->dscp_info.product_id = product_id;
+ p_cb->dscp_info.version = version;
+}
+/*******************************************************************************
+**
+** Function bta_hh_add_device_to_list
+**
+** Description Maintain a known device list for BTA HH.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hh_add_device_to_list(tBTA_HH_DEV_CB *p_cb, UINT8 handle,
+ UINT16 attr_mask,
+ tHID_DEV_DSCP_INFO *p_dscp_info,
+ UINT8 sub_class,
+ UINT16 ssr_max_latency,
+ UINT16 ssr_min_tout,
+ UINT8 app_id)
+{
+#if BTA_HH_DEBUG
+ APPL_TRACE_DEBUG1("subclass = 0x%2x", sub_class);
+#endif
+
+ p_cb->hid_handle = handle;
+ p_cb->in_use = TRUE;
+ p_cb->attr_mask = attr_mask;
+
+ p_cb->sub_class = sub_class;
+ p_cb->app_id = app_id;
+
+ if (ssr_max_latency == HID_SSR_PARAM_INVALID)
+ p_cb->dscp_info.ssr_max_latency = BTA_HH_SSR_MAX_LATENCY_DEF;
+ else
+ p_cb->dscp_info.ssr_max_latency = ssr_max_latency;
+
+ if (ssr_min_tout == HID_SSR_PARAM_INVALID)
+ p_cb->dscp_info.ssr_min_tout = BTA_HH_SSR_MIN_TOUT_DEF;
+ else
+ p_cb->dscp_info.ssr_min_tout = ssr_min_tout;
+
+ /* store report descriptor info */
+ if ( p_dscp_info)
+ {
+ utl_freebuf((void **)&p_cb->dscp_info.descriptor.dsc_list);
+
+ if (p_dscp_info->dl_len &&
+ (p_cb->dscp_info.descriptor.dsc_list =
+ (UINT8 *)GKI_getbuf(p_dscp_info->dl_len)) != NULL)
+ {
+ p_cb->dscp_info.descriptor.dl_len = p_dscp_info->dl_len;
+ memcpy(p_cb->dscp_info.descriptor.dsc_list, p_dscp_info->dsc_list,
+ p_dscp_info->dl_len);
+ }
+ }
+ return;
+}
+
+/*******************************************************************************
+**
+** Function bta_hh_tod_spt
+**
+** Description Check to see if this type of device is supported
+**
+** Returns
+**
+*******************************************************************************/
+BOOLEAN bta_hh_tod_spt(tBTA_HH_DEV_CB *p_cb,UINT8 sub_class)
+{
+ UINT8 xx;
+ UINT8 cod = (sub_class >> 2); /* lower two bits are reserved */
+
+ for (xx = 0 ; xx < p_bta_hh_cfg->max_devt_spt; xx ++)
+ {
+ if (cod == (UINT8) p_bta_hh_cfg->p_devt_list[xx].tod)
+ {
+ p_cb->app_id = p_bta_hh_cfg->p_devt_list[xx].app_id;
+#if BTA_HH_DEBUG
+ APPL_TRACE_EVENT1("bta_hh_tod_spt sub_class:0x%x supported", sub_class);
+#endif
+ return TRUE;
+ }
+ }
+#if BTA_HH_DEBUG
+ APPL_TRACE_EVENT1("bta_hh_tod_spt sub_class:0x%x NOT supported", sub_class);
+#endif
+ return FALSE;
+}
+
+
+/*******************************************************************************
+**
+** Function bta_hh_parse_keybd_rpt
+**
+** Description This utility function parse a boot mode keyboard report.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hh_parse_keybd_rpt(tBTA_HH_BOOT_RPT *p_kb_data, UINT8 *p_report,
+ UINT16 report_len)
+{
+ tBTA_HH_KB_CB *p_kb = &bta_hh_cb.kb_cb;
+ tBTA_HH_KEYBD_RPT *p_data = &p_kb_data->data_rpt.keybd_rpt;
+
+ UINT8 this_char, ctl_shift;
+ UINT16 xx, yy, key_idx = 0;
+ UINT8 this_report[BTA_HH_MAX_RPT_CHARS];
+
+#if BTA_HH_DEBUG
+ APPL_TRACE_DEBUG2("bta_hh_parse_keybd_rpt: (report=%p, report_len=%d) called",
+ p_report, report_len);
+#endif
+
+ if (report_len < 2)
+ return;
+
+ ctl_shift = *p_report++;
+ report_len--;
+
+ if (report_len > BTA_HH_MAX_RPT_CHARS)
+ report_len = BTA_HH_MAX_RPT_CHARS;
+
+ memset (this_report, 0, BTA_HH_MAX_RPT_CHARS);
+ memset (p_data, 0, sizeof(tBTA_HH_KEYBD_RPT));
+ memcpy (this_report, p_report, report_len);
+
+ /* Take care of shift, control, GUI and alt, modifier keys */
+ for (xx = 0; xx < BTA_HH_MOD_MAX_KEY; xx ++ )
+ {
+ if (ctl_shift & bta_hh_mod_key_mask[xx])
+ {
+ APPL_TRACE_DEBUG1("Mod Key[%02x] pressed", bta_hh_mod_key_mask[xx] );
+ p_kb->mod_key[xx] = TRUE;
+ }
+ else if (p_kb->mod_key[xx])
+ {
+ p_kb->mod_key[xx] = FALSE;
+ }
+ /* control key flag is set */
+ p_data->mod_key[xx] = p_kb->mod_key[xx];
+ }
+
+ /***************************************************************************/
+ /* First step is to remove all characters we saw in the last report */
+ /***************************************************************************/
+ for (xx = 0; xx < report_len; xx++)
+ {
+ for (yy = 0; yy < BTA_HH_MAX_RPT_CHARS; yy++)
+ {
+ if (this_report[xx] == p_kb->last_report[yy])
+ {
+ this_report[xx] = 0;
+ }
+ }
+ }
+ /***************************************************************************/
+ /* Now, process all the characters in the report, up to 6 keycodes */
+ /***************************************************************************/
+ for (xx = 0; xx < report_len; xx++)
+ {
+#if BTA_HH_DEBUG
+ APPL_TRACE_DEBUG1("this_char = %02x", this_report[xx]);
+#endif
+ if ((this_char = this_report[xx]) == 0)
+ continue;
+ /* take the key code as the report data */
+ if (this_report[xx] == BTA_HH_KB_CAPS_LOCK)
+ p_kb->caps_lock = p_kb->caps_lock ? FALSE : TRUE;
+ else if (this_report[xx] == BTA_HH_KB_NUM_LOCK)
+ p_kb->num_lock = p_kb->num_lock ? FALSE : TRUE;
+ else
+ p_data->this_char[key_idx ++] = this_char;
+
+#if BTA_HH_DEBUG
+ APPL_TRACE_DEBUG1("found keycode %02x ", this_report[xx]);
+#endif
+ p_data->caps_lock = p_kb->caps_lock;
+ p_kb->num_lock = p_kb->num_lock;
+ }
+
+ memset (p_kb->last_report, 0, BTA_HH_MAX_RPT_CHARS);
+ memcpy (p_kb->last_report, p_report, report_len);
+
+ return;
+}
+
+/*******************************************************************************
+**
+** Function bta_hh_parse_mice_rpt
+**
+** Description This utility function parse a boot mode mouse report.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hh_parse_mice_rpt(tBTA_HH_BOOT_RPT *p_mice_data, UINT8 *p_report,
+ UINT16 report_len)
+{
+ tBTA_HH_MICE_RPT *p_data = &p_mice_data->data_rpt.mice_rpt;
+#if BTA_HH_DEBUG
+ UINT8 xx;
+
+ APPL_TRACE_DEBUG2("bta_hh_parse_mice_rpt: bta_keybd_rpt_rcvd(report=%p, \
+ report_len=%d) called", p_report, report_len);
+#endif
+
+ if (report_len < 3)
+ return;
+
+ if (report_len > BTA_HH_MAX_RPT_CHARS)
+ report_len = BTA_HH_MAX_RPT_CHARS;
+
+#if BTA_HH_DEBUG
+ for (xx = 0; xx < report_len; xx++)
+ {
+ APPL_TRACE_DEBUG1("this_char = %02x", p_report[xx]);
+ }
+#endif
+
+ /* only first bytes lower 3 bits valid */
+ p_data->mouse_button = (p_report[0] & 0x07);
+
+ /* x displacement */
+ p_data->delta_x = p_report[1];
+
+ /* y displacement */
+ p_data->delta_y = p_report[2];
+
+#if BTA_HH_DEBUG
+ APPL_TRACE_DEBUG1("mice button: 0x%2x", p_data->mouse_button);
+ APPL_TRACE_DEBUG2("mice move: x = %d y = %d", p_data->delta_x,
+ p_data->delta_y );
+#endif
+
+ return;
+
+}
+
+#if BTA_HH_DEBUG
+/*******************************************************************************
+**
+** Function bta_hh_trace_dev_db
+**
+** Description Check to see if this type of device is supported
+**
+** Returns
+**
+*******************************************************************************/
+void bta_hh_trace_dev_db(void)
+{
+ UINT8 xx;
+
+ APPL_TRACE_DEBUG0("bta_hh_trace_dev_db:: Device DB list********************");
+
+ for (xx = 0; xx < BTA_HH_MAX_KNOWN; xx++)
+ {
+ APPL_TRACE_DEBUG3("kdev[%d] in_use[%d] handle[%d] ",xx,
+ bta_hh_cb.kdev[xx].in_use, bta_hh_cb.kdev[xx].hid_handle);
+
+ APPL_TRACE_DEBUG4("\t\t\t attr_mask[%04x] state [%d] sub_class[%02x] index = %d",
+ bta_hh_cb.kdev[xx].attr_mask, bta_hh_cb.kdev[xx].state,
+ bta_hh_cb.kdev[xx].sub_class, bta_hh_cb.kdev[xx].index);
+ }
+ APPL_TRACE_DEBUG0("*********************************************************");
+}
+#endif
+#endif /* HL_INCLUDED */
diff --git a/bta/hl/bta_hl_act.c b/bta/hl/bta_hl_act.c
new file mode 100644
index 0000000..cc14721
--- /dev/null
+++ b/bta/hl/bta_hl_act.c
@@ -0,0 +1,2794 @@
+/*****************************************************************************
+**
+** Name: bta_hl_act.c
+**
+** Description: This file contains the HeaLth device profile (HL) action
+** functions for the state machine.
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include <string.h>
+
+#include "bt_target.h"
+#if defined(HL_INCLUDED) && (HL_INCLUDED == TRUE)
+
+#include "gki.h"
+#include "sdp_api.h"
+#include "bta_sys.h"
+#include "port_api.h"
+#include "sdp_api.h"
+#include "bta_hl_api.h"
+#include "bta_hl_int.h"
+#include "utl.h"
+#include "bd.h"
+#include "mca_defs.h"
+#include "mca_api.h"
+
+/*****************************************************************************
+** Local Function prototypes
+*****************************************************************************/
+#if (BTA_HL_DEBUG == TRUE && BT_TRACE_VERBOSE == TRUE)
+static char *bta_hl_mcap_evt_code(UINT8 evt_code);
+static char *bta_hl_dch_oper_code(tBTA_HL_DCH_OPER oper_code);
+static char *bta_hl_cback_evt_code(UINT8 evt_code);
+#endif
+static void bta_hl_sdp_cback(UINT8 sdp_op, UINT8 app_idx, UINT8 mcl_idx,
+ UINT8 mdl_idx, UINT16 status);
+static void bta_hl_sdp_cback0(UINT16 status);
+static void bta_hl_sdp_cback1(UINT16 status);
+static void bta_hl_sdp_cback2(UINT16 status);
+static void bta_hl_sdp_cback3(UINT16 status);
+static void bta_hl_sdp_cback4(UINT16 status);
+static void bta_hl_sdp_cback5(UINT16 status);
+static void bta_hl_sdp_cback6(UINT16 status);
+
+
+static tSDP_DISC_CMPL_CB * const bta_hl_sdp_cback_arr[] = {
+ bta_hl_sdp_cback0,
+ bta_hl_sdp_cback1,
+ bta_hl_sdp_cback2,
+ bta_hl_sdp_cback3,
+ bta_hl_sdp_cback4,
+ bta_hl_sdp_cback5,
+ bta_hl_sdp_cback6
+};
+
+
+
+/*******************************************************************************
+**
+** Function bta_hl_dch_mca_cong_change
+**
+** Description Action routine for processing congestion change notification
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hl_dch_mca_cong_change(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data)
+{
+ tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ tMCA_CONG_CHG *p_cong_chg = &p_data->mca_evt.mca_data.cong_chg;
+ tBTA_HL evt_data;
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG2("bta_hl_dch_mca_cong_change mdl_id=%d cong=%d",
+ p_cong_chg->mdl_id,
+ p_cong_chg->cong);
+#endif
+ evt_data.dch_cong_ind.cong =
+ p_dcb->cong = p_cong_chg->cong;
+ evt_data.dch_cong_ind.mdl_handle = p_dcb->mdl_handle;
+ evt_data.dch_cong_ind.mcl_handle = p_mcb->mcl_handle;
+ evt_data.dch_cong_ind.app_handle = p_acb->app_handle;
+
+ p_acb->p_cback(BTA_HL_CONG_CHG_IND_EVT ,(tBTA_HL *) &evt_data );
+}
+
+
+
+/*******************************************************************************
+**
+** Function bta_hl_dch_echo_test
+**
+** Description Action routine for processing echo test request
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hl_dch_echo_test(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data)
+{
+ tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG0("bta_hl_dch_echo_test");
+#endif
+
+ p_dcb->echo_oper = BTA_HL_ECHO_OP_CI_GET_ECHO_DATA;
+ p_dcb->cout_oper |= BTA_HL_CO_GET_ECHO_DATA_MASK;
+
+ bta_hl_co_get_echo_data(p_acb->app_id, p_mcb->mcl_handle,
+ p_dcb->p_echo_tx_pkt->len,
+ BTA_HL_GET_BUF_PTR(p_dcb->p_echo_tx_pkt),
+ BTA_HL_CI_GET_ECHO_DATA_EVT);
+
+}
+/*******************************************************************************
+**
+** Function bta_hl_dch_sdp_init
+**
+** Description Action routine for processing DCH SDP initiation
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hl_dch_sdp_init(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data)
+{
+ tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG0("bta_hl_dch_sdp_init");
+#endif
+ if ( p_mcb->sdp_oper == BTA_HL_SDP_OP_NONE)
+ {
+ p_mcb->sdp_mdl_idx = mdl_idx;
+ if (p_dcb->dch_oper == BTA_HL_DCH_OP_LOCAL_OPEN )
+ {
+ p_mcb->sdp_oper = BTA_HL_SDP_OP_DCH_OPEN_INIT;
+
+ }
+ else
+ {
+ p_mcb->sdp_oper = BTA_HL_SDP_OP_DCH_RECONNECT_INIT;
+ }
+
+ if (bta_hl_init_sdp(p_mcb->sdp_oper, app_idx, mcl_idx, mdl_idx) != BTA_HL_STATUS_OK)
+ {
+ APPL_TRACE_ERROR0("SDP INIT failed");
+ p_mcb->sdp_oper = BTA_HL_SDP_OP_NONE;
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_SDP_FAIL_EVT, p_data);
+ }
+ }
+ else
+ {
+ APPL_TRACE_ERROR0("SDP in use");
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_SDP_FAIL_EVT, p_data);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function bta_hl_dch_close_echo_test
+**
+** Description Action routine for processing the closing of echo test
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hl_dch_close_echo_test(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data)
+{
+ tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG0("bta_hl_dch_close_echo_test");
+#endif
+
+ switch (p_dcb->echo_oper)
+ {
+ case BTA_HL_ECHO_OP_DCH_CLOSE_CFM:
+ case BTA_HL_ECHO_OP_OPEN_IND:
+ case BTA_HL_ECHO_OP_ECHO_PKT:
+ p_dcb->dch_oper = BTA_HL_DCH_OP_LOCAL_CLOSE_ECHO_TEST;
+ break;
+ case BTA_HL_ECHO_OP_MDL_CREATE_CFM:
+ case BTA_HL_ECHO_OP_DCH_OPEN_CFM:
+ case BTA_HL_ECHO_OP_LOOP_BACK:
+ default:
+ break;
+ }
+
+ if (MCA_CloseReq((tMCA_DL) p_dcb->mdl_handle)!= MCA_SUCCESS)
+ {
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function bta_hl_dch_mca_rcv_data
+**
+** Description Action routine for processing the received data
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hl_dch_mca_rcv_data(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data)
+{
+ tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG0("bta_hl_dch_mca_rcv_data");
+#endif
+
+ if (p_dcb->local_mdep_id == BTA_HL_ECHO_TEST_MDEP_ID)
+ {
+ switch ( p_dcb->echo_oper)
+ {
+ case BTA_HL_ECHO_OP_ECHO_PKT:
+
+ if (MCA_WriteReq((tMCA_DL) p_dcb->mdl_handle, p_data->mca_rcv_data_evt.p_pkt) != MCA_SUCCESS)
+ {
+ utl_freebuf((void **) &p_data->mca_rcv_data_evt.p_pkt);
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_ECHO_TEST_EVT, p_data);
+ }
+ break;
+ case BTA_HL_ECHO_OP_LOOP_BACK:
+
+ p_dcb->p_echo_rx_pkt = p_data->mca_rcv_data_evt.p_pkt;
+ p_dcb->echo_oper = BTA_HL_ECHO_OP_CI_PUT_ECHO_DATA;
+ p_dcb->cout_oper |= BTA_HL_CO_PUT_ECHO_DATA_MASK;
+ p_dcb->ci_put_echo_data_status = BTA_HL_STATUS_FAIL;
+
+ bta_hl_co_put_echo_data(p_acb->app_id, p_mcb->mcl_handle,
+ p_dcb->p_echo_rx_pkt->len,
+ BTA_HL_GET_BUF_PTR(p_dcb->p_echo_rx_pkt),
+ BTA_HL_CI_PUT_ECHO_DATA_EVT);
+ break;
+ default:
+ APPL_TRACE_ERROR1("Unknonw echo_oper=%d",p_dcb->echo_oper);
+ break;
+ }
+
+ }
+ else
+ {
+ p_dcb->cout_oper |= BTA_HL_CO_PUT_RX_DATA_MASK;
+ p_dcb->p_rx_pkt = p_data->mca_rcv_data_evt.p_pkt;
+
+ bta_hl_co_put_rx_data(p_acb->app_id, p_dcb->mdl_handle,
+ p_dcb->p_rx_pkt->len,
+ BTA_HL_GET_BUF_PTR(p_dcb->p_rx_pkt),
+ BTA_HL_CI_PUT_RX_DATA_EVT);
+
+
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function bta_hl_dch_ci_put_echo_data
+**
+** Description Action routine for processing the call-in of the
+** put echo data event
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hl_dch_ci_put_echo_data(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data)
+{
+ tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG0("bta_hl_dch_ci_put_echo_data");
+#endif
+
+ p_dcb->cout_oper &= ~BTA_HL_CO_PUT_ECHO_DATA_MASK;
+ utl_freebuf((void **) &p_dcb->p_echo_rx_pkt);
+ p_dcb->ci_put_echo_data_status = p_data->ci_get_put_echo_data.status;
+
+ p_dcb->echo_oper = BTA_HL_ECHO_OP_DCH_CLOSE_CFM;
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_ECHO_TEST_EVT, p_data);
+}
+
+
+
+/*******************************************************************************
+**
+** Function bta_hl_dch_ci_get_echo_data
+**
+** Description Action routine for processing the call-in of the
+** get echo data event
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hl_dch_ci_get_echo_data(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data)
+{
+ tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ tBTA_HL_STATUS status;
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG0("bta_hl_dch_ci_get_echo_data");
+#endif
+
+ p_dcb->cout_oper &= ~BTA_HL_CO_GET_ECHO_DATA_MASK;
+
+ if (!p_dcb->abort_oper)
+ {
+ status = p_data->ci_get_put_echo_data.status;
+ if (status == BTA_HL_STATUS_OK)
+ {
+ p_dcb->echo_oper = BTA_HL_ECHO_OP_MDL_CREATE_CFM;
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_OPEN_EVT, p_data);
+ }
+ else
+ {
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
+ }
+ }
+ else
+ {
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_dch_ci_put_rx_data
+**
+** Description Action routine for processing the call-in of the
+** put rx data event
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hl_dch_ci_put_rx_data(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data)
+{
+ tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ tBTA_HL evt_data;
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG0("bta_hl_dch_ci_put_rx_data");
+#endif
+
+ p_dcb->cout_oper &= ~BTA_HL_CO_PUT_RX_DATA_MASK;
+ utl_freebuf((void **) &p_dcb->p_rx_pkt);
+ bta_hl_build_rcv_data_ind(&evt_data,
+ p_acb->app_handle,
+ p_mcb->mcl_handle,
+ p_dcb->mdl_handle);
+ p_acb->p_cback(BTA_HL_DCH_RCV_DATA_IND_EVT,(tBTA_HL *) &evt_data );
+ if (p_dcb->close_pending)
+ {
+ if (!p_dcb->cout_oper)
+ {
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_EVT, p_data);
+ }
+
+ }
+}
+
+
+
+/*******************************************************************************
+**
+** Function bta_hl_dch_ci_get_tx_data
+**
+** Description Action routine for processing the call-in of the
+** get tx data event
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hl_dch_ci_get_tx_data(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data)
+{
+ tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ tMCA_RESULT result;
+ tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+ BOOLEAN free_buf = FALSE;
+ BOOLEAN close_dch = FALSE;
+ tBTA_HL evt_data;
+
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG0("bta_hl_dch_ci_get_tx_data");
+#endif
+
+ p_dcb->cout_oper &= ~BTA_HL_CO_GET_TX_DATA_MASK;
+
+ if (p_dcb->close_pending)
+ {
+ status = BTA_HL_STATUS_FAIL;
+ free_buf = TRUE;
+
+ if (!p_dcb->cout_oper)
+ {
+ close_dch = TRUE;
+ }
+ }
+ else
+ {
+ if ((result = MCA_WriteReq((tMCA_DL) p_dcb->mdl_handle, p_dcb->p_tx_pkt)) != MCA_SUCCESS)
+ {
+ if (result == MCA_BUSY)
+ {
+ status = BTA_HL_STATUS_DCH_BUSY;
+ }
+ else
+ {
+ status = BTA_HL_STATUS_FAIL;
+ }
+ free_buf = TRUE;
+ }
+ else
+ {
+ p_dcb->p_tx_pkt = NULL;
+ }
+ }
+
+ if (free_buf)
+ {
+ utl_freebuf((void **) &p_dcb->p_tx_pkt);
+ }
+
+ bta_hl_build_send_data_cfm(&evt_data,
+ p_acb->app_handle,
+ p_mcb->mcl_handle,
+ p_dcb->mdl_handle,
+ status);
+ p_acb->p_cback(BTA_HL_DCH_SEND_DATA_CFM_EVT,(tBTA_HL *) &evt_data );
+
+ if (close_dch)
+ {
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_EVT, p_data);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function bta_hl_dch_send_data
+**
+** Description Action routine for processing api send data request
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hl_dch_send_data(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data)
+{
+ tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ tBTA_HL evt_data;
+ BOOLEAN success = TRUE;
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG0("bta_hl_dch_send_data");
+#endif
+
+ if (!(p_dcb->cout_oper & BTA_HL_CO_GET_TX_DATA_MASK))
+ {
+ if ((p_dcb->p_tx_pkt = bta_hl_get_buf(p_data->api_send_data.pkt_size)) != NULL)
+ {
+ bta_hl_co_get_tx_data( p_acb->app_id,
+ p_dcb->mdl_handle,
+ p_data->api_send_data.pkt_size,
+ BTA_HL_GET_BUF_PTR(p_dcb->p_tx_pkt),
+ BTA_HL_CI_GET_TX_DATA_EVT);
+ p_dcb->cout_oper |= BTA_HL_CO_GET_TX_DATA_MASK;
+ }
+ else
+ {
+ success = FALSE;
+ }
+ }
+ else
+ {
+ success = FALSE;
+ }
+
+ if (!success)
+ {
+ bta_hl_build_send_data_cfm(&evt_data,
+ p_acb->app_handle,
+ p_mcb->mcl_handle,
+ p_dcb->mdl_handle,
+ BTA_HL_STATUS_FAIL);
+ p_acb->p_cback(BTA_HL_DCH_SEND_DATA_CFM_EVT,(tBTA_HL *) &evt_data );
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_dch_close_cmpl
+**
+** Description Action routine for processing the close complete event
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hl_dch_close_cmpl(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data)
+{
+ tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ tBTA_HL evt_data;
+ tBTA_HL_EVT event;
+ BOOLEAN send_evt=TRUE;
+ tBTA_HL_STATUS status;
+
+#if (BTA_HL_DEBUG == TRUE)
+#if (BT_TRACE_VERBOSE == TRUE)
+ APPL_TRACE_DEBUG1("bta_hl_dch_close_cmpl dch oper=%s", bta_hl_dch_oper_code(p_dcb->dch_oper));
+#else
+ APPL_TRACE_DEBUG1("bta_hl_dch_close_cmpl dch oper=%d", p_dcb->dch_oper);
+#endif
+#endif
+
+ switch (p_dcb->dch_oper)
+ {
+ case BTA_HL_DCH_OP_LOCAL_OPEN:
+ case BTA_HL_DCH_OP_LOCAL_RECONNECT:
+
+ if (p_dcb->abort_oper & BTA_HL_ABORT_LOCAL_MASK)
+ {
+ bta_hl_build_abort_cfm(&evt_data,
+ p_acb->app_handle,
+ p_mcb->mcl_handle,
+ BTA_HL_STATUS_OK);
+ event = BTA_HL_DCH_ABORT_CFM_EVT;
+ }
+ else if (p_dcb->abort_oper & BTA_HL_ABORT_REMOTE_MASK )
+ {
+ bta_hl_build_abort_ind(&evt_data,
+ p_acb->app_handle,
+ p_mcb->mcl_handle);
+ event = BTA_HL_DCH_ABORT_IND_EVT;
+ }
+ else
+ {
+ bta_hl_build_dch_open_cfm(&evt_data,
+ p_acb->app_handle,
+ p_mcb->mcl_handle,
+ BTA_HL_INVALID_MDL_HANDLE,
+ 0,0,0,0,0, BTA_HL_STATUS_FAIL);
+ event = BTA_HL_DCH_OPEN_CFM_EVT;
+ if (p_dcb->dch_oper == BTA_HL_DCH_OP_LOCAL_RECONNECT)
+ {
+ event = BTA_HL_DCH_RECONNECT_CFM_EVT;
+ }
+ }
+ break;
+
+ case BTA_HL_DCH_OP_LOCAL_CLOSE:
+ case BTA_HL_DCH_OP_REMOTE_DELETE:
+ case BTA_HL_DCH_OP_LOCAL_CLOSE_RECONNECT:
+ case BTA_HL_DCH_OP_NONE:
+
+ bta_hl_build_dch_close_cfm(&evt_data,
+ p_acb->app_handle,
+ p_mcb->mcl_handle,
+ p_dcb->mdl_handle,
+ BTA_HL_STATUS_OK);
+ event = BTA_HL_DCH_CLOSE_CFM_EVT;
+ break;
+
+ case BTA_HL_DCH_OP_REMOTE_CLOSE:
+ bta_hl_build_dch_close_ind(&evt_data,
+ p_acb->app_handle,
+ p_mcb->mcl_handle,
+ p_dcb->mdl_handle,
+ p_dcb->intentional_close);
+ event = BTA_HL_DCH_CLOSE_IND_EVT;
+ break;
+
+ case BTA_HL_DCH_OP_REMOTE_OPEN:
+
+ if (p_dcb->abort_oper & BTA_HL_ABORT_LOCAL_MASK)
+ {
+ bta_hl_build_abort_cfm(&evt_data,
+ p_acb->app_handle,
+ p_mcb->mcl_handle,
+ BTA_HL_STATUS_OK);
+ event = BTA_HL_DCH_ABORT_CFM_EVT;
+ }
+ else if (p_dcb->abort_oper & BTA_HL_ABORT_REMOTE_MASK )
+ {
+ bta_hl_build_abort_ind(&evt_data,
+ p_acb->app_handle,
+ p_mcb->mcl_handle);
+ event = BTA_HL_DCH_ABORT_IND_EVT;
+ }
+ else
+ {
+ bta_hl_build_dch_close_ind(&evt_data,
+ p_acb->app_handle,
+ p_mcb->mcl_handle,
+ p_dcb->mdl_handle,
+ p_dcb->intentional_close);
+ event = BTA_HL_DCH_CLOSE_IND_EVT;
+ }
+ break;
+
+ case BTA_HL_DCH_OP_LOCAL_CLOSE_ECHO_TEST:
+ /* this is normal echo test close */
+ case BTA_HL_DCH_OP_REMOTE_CREATE:
+ case BTA_HL_DCH_OP_REMOTE_RECONNECT:
+ send_evt=FALSE;
+ break;
+
+ default:
+#if (BTA_HL_DEBUG == TRUE)
+#if (BT_TRACE_VERBOSE == TRUE)
+ APPL_TRACE_ERROR1("DCH operation not found oper=%s", bta_hl_dch_oper_code(p_dcb->dch_oper));
+#else
+ APPL_TRACE_ERROR1("DCH operation not found oper=%d", p_dcb->dch_oper);
+#endif
+#endif
+ send_evt=FALSE;
+ break;
+ }
+
+ if ( p_dcb->local_mdep_id == BTA_HL_ECHO_TEST_MDEP_ID )
+ {
+ p_mcb->echo_test = FALSE;
+ send_evt=FALSE;
+
+ if ( p_dcb->dch_oper != BTA_HL_DCH_OP_LOCAL_CLOSE_ECHO_TEST)
+ {
+ switch (p_dcb->echo_oper)
+ {
+ case BTA_HL_ECHO_OP_CI_GET_ECHO_DATA:
+ case BTA_HL_ECHO_OP_SDP_INIT:
+ case BTA_HL_ECHO_OP_MDL_CREATE_CFM:
+ case BTA_HL_ECHO_OP_DCH_OPEN_CFM:
+ case BTA_HL_ECHO_OP_LOOP_BACK:
+
+ status = BTA_HL_STATUS_FAIL;
+ send_evt = TRUE;
+ break;
+ case BTA_HL_ECHO_OP_OPEN_IND:
+ case BTA_HL_ECHO_OP_ECHO_PKT:
+ break;
+ default:
+ APPL_TRACE_ERROR1("Invalid echo_oper=%d", p_dcb->echo_oper);
+ break;
+ }
+ }
+ else
+ {
+ status = p_dcb->ci_put_echo_data_status;
+ send_evt = TRUE;
+ }
+
+ if (send_evt)
+ {
+ bta_hl_build_echo_test_cfm(&evt_data,
+ p_acb->app_handle,
+ p_mcb->mcl_handle,
+ status);
+ event = BTA_HL_DCH_ECHO_TEST_CFM_EVT;
+ }
+ }
+
+ bta_hl_clean_mdl_cb(app_idx, mcl_idx, mdl_idx);
+
+ if (send_evt)
+ {
+ if (p_acb->p_cback)
+ {
+#if (BTA_HL_DEBUG == TRUE)
+#if (BT_TRACE_VERBOSE == TRUE)
+ APPL_TRACE_DEBUG1("Send Event: %s", bta_hl_cback_evt_code(event));
+#else
+ APPL_TRACE_DEBUG1("Send Event: 0x%02x", event);
+#endif
+#endif
+ p_acb->p_cback(event,(tBTA_HL *) &evt_data );
+ }
+ }
+ /* check cch close is in progress or not */
+ bta_hl_check_cch_close(app_idx, mcl_idx, p_data, FALSE);
+}
+/*******************************************************************************
+**
+** Function bta_hl_dch_mca_close_ind
+**
+** Description Action routine for processing the close indication
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hl_dch_mca_close_ind(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data)
+{
+ tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+#if (BTA_HL_DEBUG == TRUE)
+#if (BT_TRACE_VERBOSE == TRUE)
+ APPL_TRACE_DEBUG1("bta_hl_dch_mca_close_ind dch oper=%s", bta_hl_dch_oper_code(p_dcb->dch_oper));
+#else
+ APPL_TRACE_DEBUG1("bta_hl_dch_mca_close_ind dch oper=%d", p_dcb->dch_oper);
+#endif
+#endif
+
+ p_dcb->intentional_close = FALSE;
+ if (p_data->mca_evt.mca_data.close_ind.reason == L2CAP_DISC_OK)
+ {
+ p_dcb->intentional_close = TRUE;
+ }
+
+ if (!p_dcb->cout_oper)
+ {
+ if ((p_dcb->dch_oper != BTA_HL_DCH_OP_REMOTE_OPEN) &&
+ (p_dcb->dch_oper != BTA_HL_DCH_OP_REMOTE_RECONNECT))
+ {
+ p_dcb->dch_oper = BTA_HL_DCH_OP_REMOTE_CLOSE;
+ }
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
+ }
+ else
+ {
+ p_dcb->close_pending = TRUE;
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_dch_mca_close_cfm
+**
+** Description Action routine for processing the close confirmation
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hl_dch_mca_close_cfm(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data)
+{
+ tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+
+#if (BTA_HL_DEBUG == TRUE)
+#if (BT_TRACE_VERBOSE == TRUE)
+ APPL_TRACE_DEBUG1("bta_hl_dch_mca_close_cfm dch_oper=%s", bta_hl_dch_oper_code(p_dcb->dch_oper) );
+#else
+ APPL_TRACE_DEBUG1("bta_hl_dch_mca_close_cfm dch_oper=%d", p_dcb->dch_oper);
+#endif
+#endif
+
+ switch (p_dcb->dch_oper)
+ {
+ case BTA_HL_DCH_OP_LOCAL_CLOSE:
+ case BTA_HL_DCH_OP_LOCAL_OPEN:
+ case BTA_HL_DCH_OP_LOCAL_RECONNECT:
+ case BTA_HL_DCH_OP_LOCAL_CLOSE_ECHO_TEST:
+ case BTA_HL_DCH_OP_REMOTE_DELETE:
+ case BTA_HL_DCH_OP_LOCAL_CLOSE_RECONNECT:
+ case BTA_HL_DCH_OP_NONE:
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
+ break;
+ default:
+#if (BTA_HL_DEBUG == TRUE)
+#if (BT_TRACE_VERBOSE == TRUE)
+ APPL_TRACE_ERROR1("Invalid dch_oper=%s for close cfm", bta_hl_dch_oper_code(p_dcb->dch_oper) );
+#else
+ APPL_TRACE_ERROR1("Invalid dch_oper=%d for close cfm", p_dcb->dch_oper);
+#endif
+#endif
+ break;
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_dch_mca_close
+**
+** Description Action routine for processing the DCH close request
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hl_dch_mca_close(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data)
+{
+ tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+ tBTA_HL evt_data;
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG0("bta_hl_dch_mca_close");
+#endif
+ if (!p_dcb->cout_oper)
+ {
+ p_dcb->close_pending = FALSE;
+ if (MCA_CloseReq((tMCA_DL)p_dcb->mdl_handle)== MCA_SUCCESS)
+ {
+ p_dcb->dch_oper = BTA_HL_DCH_OP_LOCAL_CLOSE;
+ }
+ else
+ {
+ status = BTA_HL_STATUS_FAIL;
+ }
+
+ if ((status != BTA_HL_STATUS_OK) &&
+ (p_mcb->cch_close_dch_oper != BTA_HL_CCH_CLOSE_OP_DCH_CLOSE))
+ {
+ bta_hl_build_dch_close_cfm(&evt_data,
+ p_acb->app_handle,
+ p_mcb->mcl_handle,
+ p_data->api_dch_close.mdl_handle,
+ status);
+ p_acb->p_cback(BTA_HL_DCH_CLOSE_CFM_EVT,(tBTA_HL *) &evt_data );
+ }
+ }
+ else
+ {
+ p_dcb->close_pending = TRUE;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function bta_hl_dch_mca_open_ind
+**
+** Description Action routine for processing the open indication
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hl_dch_mca_open_ind(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data)
+{
+ tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ tMCA_DL_OPEN *p_open_ind = &p_data->mca_evt.mca_data.open_ind;
+ tBTA_HL evt_data;
+ tBTA_HL_EVT event;
+ UINT8 old_dch_oper;
+ BOOLEAN send_event = FALSE;
+
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG0("bta_hl_dch_mca_open_ind");
+#endif
+ if ((p_dcb->dch_oper == BTA_HL_DCH_OP_REMOTE_OPEN) ||
+ (p_dcb->dch_oper == BTA_HL_DCH_OP_REMOTE_RECONNECT) )
+ {
+ p_dcb->mdl_handle = (tBTA_HL_MDL_HANDLE) p_open_ind->mdl;
+ p_dcb->mtu = p_open_ind->mtu;
+
+ evt_data.dch_open_ind.mdl_handle = p_dcb->mdl_handle;
+ evt_data.dch_open_ind.mcl_handle = p_mcb->mcl_handle;
+ evt_data.dch_open_ind.app_handle = p_acb->app_handle;
+
+ evt_data.dch_open_ind.local_mdep_id = p_dcb->local_mdep_id;
+ evt_data.dch_open_ind.mdl_id = p_dcb->mdl_id;
+ evt_data.dch_open_ind.mtu = p_dcb->mtu;
+
+ if ( p_dcb->chnl_cfg.fcr_opt.mode == L2CAP_FCR_ERTM_MODE )
+ {
+ evt_data.dch_open_ind.dch_mode = BTA_HL_DCH_MODE_RELIABLE;
+ if (!bta_hl_is_the_first_reliable_existed(app_idx, mcl_idx))
+ {
+ p_dcb->is_the_first_reliable = TRUE;
+ }
+ }
+ else
+ {
+ evt_data.dch_open_ind.dch_mode = BTA_HL_DCH_MODE_STREAMING;
+ }
+ evt_data.dch_open_ind.first_reliable = p_dcb->is_the_first_reliable ;
+
+ old_dch_oper = p_dcb->dch_oper;
+ p_dcb->dch_oper = BTA_HL_DCH_OP_NONE;
+
+
+ }
+
+ switch (old_dch_oper)
+ {
+ case BTA_HL_DCH_OP_REMOTE_OPEN:
+
+ p_dcb->dch_mode = evt_data.dch_open_ind.dch_mode;
+ if (p_dcb->local_mdep_id != BTA_HL_ECHO_TEST_MDEP_ID)
+ {
+ bta_hl_save_mdl_cfg(app_idx, mcl_idx,mdl_idx);
+ event= BTA_HL_DCH_OPEN_IND_EVT;
+ send_event= TRUE;
+ }
+ else
+ {
+ p_dcb->echo_oper = BTA_HL_ECHO_OP_ECHO_PKT;
+ }
+
+ break;
+
+ case BTA_HL_DCH_OP_REMOTE_RECONNECT:
+
+ if (bta_hl_validate_chan_cfg(app_idx, mcl_idx, mdl_idx))
+ {
+ bta_hl_save_mdl_cfg(app_idx, mcl_idx,mdl_idx);
+ event= BTA_HL_DCH_RECONNECT_IND_EVT;
+ send_event= TRUE;
+ }
+ else
+ {
+ if (MCA_CloseReq((tMCA_DL) p_dcb->mdl_handle) == MCA_SUCCESS)
+ {
+ p_dcb->dch_oper = BTA_HL_DCH_OP_LOCAL_CLOSE_RECONNECT;
+ }
+ else
+ {
+ APPL_TRACE_ERROR0("Unabel to close DCH for reconnect cfg mismatch");
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (send_event)
+ {
+ p_acb->p_cback(event ,(tBTA_HL *) &evt_data );
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_dch_mca_open_cfm
+**
+** Description Action routine for processing the open confirmation
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hl_dch_mca_open_cfm(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data)
+{
+ tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ tMCA_DL_OPEN *p_open_cfm = &p_data->mca_evt.mca_data.open_cfm;
+ tBTA_HL evt_data;
+ tBTA_HL_EVT event;
+ UINT8 old_dch_oper;
+ tBTA_HL_DCH_MODE dch_mode;
+ BOOLEAN send_event = FALSE;
+
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG0("bta_hl_dch_mca_open_cfm");
+#endif
+ if ((p_dcb->dch_oper == BTA_HL_DCH_OP_LOCAL_OPEN) ||
+ (p_dcb->dch_oper == BTA_HL_DCH_OP_LOCAL_RECONNECT))
+ {
+ p_dcb->mdl_handle = (tBTA_HL_MDL_HANDLE) p_open_cfm->mdl;
+ p_dcb->mtu = p_open_cfm->mtu;
+
+ /*todo verify dch_mode, mtu and fcs for reconnect */
+ if ( p_dcb->chnl_cfg.fcr_opt.mode == L2CAP_FCR_ERTM_MODE )
+ {
+ dch_mode = BTA_HL_DCH_MODE_RELIABLE;
+ }
+ else
+ {
+ dch_mode = BTA_HL_DCH_MODE_STREAMING;
+ }
+
+ if (p_dcb->local_mdep_id != BTA_HL_ECHO_TEST_MDEP_ID)
+ {
+ if (dch_mode == BTA_HL_DCH_MODE_RELIABLE )
+ {
+ if (!bta_hl_is_the_first_reliable_existed(app_idx, mcl_idx))
+ {
+ p_dcb->is_the_first_reliable = TRUE;
+ }
+ }
+ }
+
+ bta_hl_build_dch_open_cfm(&evt_data, p_acb->app_handle,
+ p_mcb->mcl_handle,
+ p_dcb->mdl_handle,
+ p_dcb->local_mdep_id,
+ p_dcb->mdl_id, dch_mode,
+ p_dcb->is_the_first_reliable,
+ p_dcb->mtu,
+ BTA_HL_STATUS_OK);
+
+ old_dch_oper = p_dcb->dch_oper;
+ p_dcb->dch_oper = BTA_HL_DCH_OP_NONE;
+ }
+
+ switch (old_dch_oper)
+ {
+ case BTA_HL_DCH_OP_LOCAL_OPEN:
+
+ p_dcb->dch_mode = dch_mode;
+ if (p_dcb->local_mdep_id != BTA_HL_ECHO_TEST_MDEP_ID)
+ {
+ bta_hl_save_mdl_cfg(app_idx, mcl_idx, mdl_idx);
+ event= BTA_HL_DCH_OPEN_CFM_EVT;
+ send_event= TRUE;
+ }
+ else
+ {
+ p_dcb->echo_oper = BTA_HL_ECHO_OP_LOOP_BACK;
+ if (MCA_WriteReq((tMCA_DL) p_dcb->mdl_handle, p_dcb->p_echo_tx_pkt)!= MCA_SUCCESS)
+ {
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_ECHO_TEST_EVT, p_data);
+ }
+ else
+ {
+ p_dcb->p_echo_tx_pkt = NULL;
+ }
+ }
+ break;
+
+ case BTA_HL_DCH_OP_LOCAL_RECONNECT:
+
+ if (bta_hl_validate_chan_cfg(app_idx, mcl_idx, mdl_idx))
+ {
+ bta_hl_save_mdl_cfg(app_idx, mcl_idx,mdl_idx);
+ event= BTA_HL_DCH_RECONNECT_CFM_EVT;
+ send_event= TRUE;
+ }
+ else
+ {
+ if (MCA_CloseReq((tMCA_DL) p_dcb->mdl_handle) == MCA_SUCCESS)
+ {
+ p_dcb->dch_oper = BTA_HL_DCH_OP_LOCAL_CLOSE_RECONNECT;
+ }
+ else
+ {
+ APPL_TRACE_ERROR0("Unabel to close DCH for reconnect cfg mismatch");
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (send_event)
+ p_acb->p_cback(event ,(tBTA_HL *) &evt_data );
+}
+
+
+/*******************************************************************************
+**
+** Function bta_hl_dch_mca_abort_ind
+**
+** Description Action routine for processing the abort indication
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hl_dch_mca_abort_ind(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data)
+{
+ tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG0("bta_hl_dch_mca_abort_ind");
+#endif
+
+ p_dcb->abort_oper |= BTA_HL_ABORT_REMOTE_MASK;
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_dch_mca_abort_cfm
+**
+** Description Action routine for processing the abort confirmation
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hl_dch_mca_abort_cfm(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data)
+{
+ tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ tBTA_HL evt_data;
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG0("bta_hl_dch_mca_abort_cfm");
+#endif
+
+ if (p_dcb->abort_oper)
+ {
+ if (p_data->mca_evt.mca_data.abort_cfm.rsp_code != MCA_RSP_SUCCESS )
+ {
+ if (p_dcb->abort_oper & BTA_HL_ABORT_LOCAL_MASK)
+ {
+ bta_hl_build_abort_cfm(&evt_data,
+ p_acb->app_handle,
+ p_mcb->mcl_handle,
+ BTA_HL_STATUS_FAIL);
+ p_acb->p_cback(BTA_HL_DCH_ABORT_CFM_EVT ,(tBTA_HL *) &evt_data );
+ }
+ }
+ else
+ {
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
+ }
+ }
+ else
+ {
+ APPL_TRACE_ERROR0("Not expecting Abort CFM ");
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_dch_mca_abort
+**
+** Description Action routine for processing the abort request
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hl_dch_mca_abort(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data)
+{
+ tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ tMCA_RESULT mca_result;
+ tBTA_HL evt_data;
+
+ if (((p_mcb->sdp_oper == BTA_HL_SDP_OP_DCH_OPEN_INIT) ||
+ (p_mcb->sdp_oper == BTA_HL_SDP_OP_DCH_RECONNECT_INIT)) &&
+ (p_mcb->sdp_mdl_idx == mdl_idx) )
+ {
+ p_dcb->abort_oper |= BTA_HL_ABORT_PENDING_MASK;
+ return;
+ }
+ else if (p_dcb->echo_oper == BTA_HL_ECHO_OP_CI_GET_ECHO_DATA)
+ {
+ p_dcb->abort_oper |= BTA_HL_ABORT_PENDING_MASK;
+ return;
+ }
+
+ p_dcb->abort_oper &= ~BTA_HL_ABORT_PENDING_MASK;
+
+ if ((mca_result = MCA_Abort((tMCA_CL) p_mcb->mcl_handle))!= MCA_SUCCESS)
+ {
+ if (mca_result == MCA_NO_RESOURCES)
+ {
+ p_dcb->abort_oper |= BTA_HL_ABORT_PENDING_MASK;
+ }
+ else
+ {
+ if (p_dcb->abort_oper & BTA_HL_ABORT_LOCAL_MASK)
+ {
+ bta_hl_build_abort_cfm(&evt_data,
+ p_acb->app_handle,
+ p_mcb->mcl_handle,
+ BTA_HL_STATUS_FAIL);
+ p_acb->p_cback(BTA_HL_DCH_ABORT_CFM_EVT ,(tBTA_HL *) &evt_data );
+ }
+ bta_hl_check_cch_close(app_idx, mcl_idx, p_data, FALSE);
+ }
+
+
+ }
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG1("bta_hl_dch_mca_abort abort_oper=0x%x", p_dcb->abort_oper);
+#endif
+
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_dch_mca_reconnect_ind
+**
+** Description Action routine for processing the reconnect indication
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hl_dch_mca_reconnect_ind(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data)
+{
+ tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ tBTA_HL_MDL_CFG *p_mdl_cfg;
+ tMCA_EVT_HDR *p_reconnect_ind = &p_data->mca_evt.mca_data.reconnect_ind;
+ UINT8 mdl_cfg_idx, in_use_mdl_idx, mdep_cfg_idx;
+ UINT8 rsp_code = MCA_RSP_SUCCESS;
+
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG1("bta_hl_dch_mca_reconnect_ind mdl_id=%d", p_reconnect_ind->mdl_id);
+#endif
+
+ if (bta_hl_find_mdl_cfg_idx(app_idx, mcl_idx, p_reconnect_ind->mdl_id, &mdl_cfg_idx))
+ {
+ if (!bta_hl_find_mdl_idx(app_idx,mcl_idx,p_reconnect_ind->mdl_id, &in_use_mdl_idx) )
+ {
+ p_mdl_cfg = BTA_HL_GET_MDL_CFG_PTR(app_idx, mdl_cfg_idx);
+
+ if (bta_hl_find_mdep_cfg_idx(app_idx, p_mdl_cfg->local_mdep_id, &mdep_cfg_idx))
+ {
+ p_dcb->in_use = TRUE;
+ p_dcb->dch_oper = BTA_HL_DCH_OP_REMOTE_RECONNECT;
+ p_dcb->sec_mask = (BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
+ p_dcb->peer_mdep_id = 0xFF;
+ p_dcb->local_mdep_id = p_mdl_cfg->local_mdep_id ;
+ p_dcb->local_mdep_cfg_idx = mdep_cfg_idx;
+ p_dcb->local_cfg = BTA_HL_DCH_CFG_UNKNOWN;
+ p_dcb->mdl_id = p_reconnect_ind->mdl_id;
+ p_dcb->mdl_cfg_idx_included = TRUE;
+ p_dcb->mdl_cfg_idx = mdl_cfg_idx;
+ p_dcb->dch_mode = p_mdl_cfg->dch_mode;
+ bta_hl_find_rxtx_apdu_size(app_idx, mdep_cfg_idx,
+ &p_dcb->max_rx_apdu_size,
+ &p_dcb->max_tx_apdu_size);
+ bta_hl_set_dch_chan_cfg(app_idx, mcl_idx, mdl_idx, p_data);
+ }
+ else
+ {
+ rsp_code = MCA_RSP_BAD_MDL;
+ }
+ }
+ else
+ {
+ rsp_code = MCA_RSP_BAD_MDL;
+ }
+ }
+ else
+ {
+ rsp_code = MCA_RSP_BAD_MDL;
+ }
+
+ if (MCA_ReconnectMdlRsp((tMCA_CL) p_mcb->mcl_handle,
+ p_dcb->local_mdep_id,
+ p_dcb->mdl_id,
+ rsp_code,
+ &p_dcb->chnl_cfg)!= MCA_SUCCESS)
+ {
+ MCA_Abort((tMCA_CL) p_mcb->mcl_handle);
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_dch_mca_reconnect_cfm
+**
+** Description Action routine for processing the reconenct confirmation
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hl_dch_mca_reconnect_cfm(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data)
+{
+ tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ tMCA_RSP_EVT *p_reconnect_cfm = &p_data->mca_evt.mca_data.reconnect_cfm;
+
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG0("bta_hl_dch_mca_reconnect_cfm");
+#endif
+ if (p_dcb->abort_oper & BTA_HL_ABORT_PENDING_MASK)
+ {
+ p_dcb->abort_oper &= ~BTA_HL_ABORT_PENDING_MASK;
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_ABORT_EVT, p_data);
+ return;
+ }
+
+
+ if (p_dcb->dch_oper == BTA_HL_DCH_OP_LOCAL_RECONNECT)
+ {
+ if (p_reconnect_cfm->rsp_code == MCA_RSP_SUCCESS)
+ {
+
+ bta_hl_set_dch_chan_cfg(app_idx, mcl_idx, mdl_idx, p_data);
+
+ if (MCA_DataChnlCfg((tMCA_CL) p_mcb->mcl_handle, &p_dcb->chnl_cfg)!= MCA_SUCCESS)
+ {
+ /* should be able to abort so no checking of the return code */
+ MCA_Abort((tMCA_CL) p_mcb->mcl_handle);
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
+ }
+ }
+ else
+ {
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_dch_mca_reconnect
+**
+** Description Action routine for processing the reconnect request
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hl_dch_mca_reconnect(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data)
+{
+ tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ tMCA_CHNL_CFG *p_chnl_cfg=NULL;
+ UINT8 sdp_idx;
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG0("bta_hl_dch_mca_reconnect");
+#endif
+ if (bta_hl_find_sdp_idx_using_ctrl_psm(&p_mcb->sdp, p_mcb->ctrl_psm, &sdp_idx))
+ {
+ p_mcb->data_psm = p_mcb->sdp.sdp_rec[sdp_idx].data_psm;
+ if ( MCA_ReconnectMdl((tMCA_CL) p_mcb->mcl_handle,
+ p_dcb->local_mdep_id,
+ p_mcb->data_psm,
+ p_dcb->mdl_id,
+ p_chnl_cfg ) != MCA_SUCCESS)
+ {
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
+ }
+ }
+ else
+ {
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function bta_hl_dch_create_rsp
+**
+** Description Action routine for processing BTA_HL_API_DCH_CREATE_RSP_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hl_dch_create_rsp(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data)
+{
+ tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ tBTA_HL_API_DCH_CREATE_RSP *p_create_rsp = &p_data->api_dch_create_rsp;
+ UINT8 mca_rsp_code = MCA_RSP_SUCCESS;
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG0("bta_hl_dch_create_rsp");
+#endif
+ if (p_create_rsp->rsp_code == BTA_HL_DCH_CREATE_RSP_SUCCESS)
+ {
+ p_dcb->dch_oper = BTA_HL_DCH_OP_REMOTE_OPEN;
+ p_dcb->local_cfg = p_create_rsp->cfg_rsp;
+
+
+
+ bta_hl_set_dch_chan_cfg(app_idx, mcl_idx, mdl_idx, p_data);
+ }
+ else
+ {
+ mca_rsp_code = MCA_RSP_CFG_REJ;
+ }
+
+ if (MCA_CreateMdlRsp((tMCA_CL) p_mcb->mcl_handle,
+ p_dcb->local_mdep_id,
+ p_dcb->mdl_id,
+ p_dcb->local_cfg,
+ mca_rsp_code,
+ &p_dcb->chnl_cfg)!= MCA_SUCCESS)
+ {
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_dch_mca_create_ind
+**
+** Description Action routine for processing
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hl_dch_mca_create_ind(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data)
+{
+ tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ tMCA_CREATE_IND *p_create_ind = &p_data->mca_evt.mca_data.create_ind;
+ UINT8 mdep_cfg_idx;
+ UINT8 cfg_rsp;
+ UINT8 rsp_code = MCA_RSP_SUCCESS;
+ BOOLEAN send_create_ind_evt = FALSE;
+ tBTA_HL evt_data;
+ tBTA_HL_ECHO_CFG *p_echo_cfg;
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG0("bta_hl_dch_mca_create_ind");
+#endif
+
+ if (bta_hl_find_mdep_cfg_idx(app_idx, p_create_ind->dep_id, &mdep_cfg_idx))
+ {
+ if (p_create_ind->dep_id == BTA_HL_ECHO_TEST_MDEP_ID )
+ {
+ if (bta_hl_find_echo_cfg_rsp(app_idx, mcl_idx, mdep_cfg_idx,p_create_ind->cfg, &cfg_rsp ))
+ {
+ p_dcb->in_use = TRUE;
+ p_dcb->dch_oper = BTA_HL_DCH_OP_REMOTE_OPEN;
+ p_dcb->local_mdep_id = p_create_ind->dep_id ;
+ p_dcb->local_mdep_cfg_idx = mdep_cfg_idx;
+ p_dcb->local_cfg = cfg_rsp;
+ p_dcb->remote_cfg = p_create_ind->cfg ;
+ p_dcb->mdl_id = p_create_ind->mdl_id;
+ p_dcb->mdl_cfg_idx_included = FALSE;
+ p_echo_cfg = BTA_HL_GET_ECHO_CFG_PTR(app_idx);
+ p_dcb->max_rx_apdu_size = p_echo_cfg->max_rx_apdu_size;
+ p_dcb->max_tx_apdu_size = p_echo_cfg->max_tx_apdu_size;
+
+ bta_hl_set_dch_chan_cfg(app_idx, mcl_idx, mdl_idx, p_data);
+ }
+ else
+ {
+ rsp_code = MCA_RSP_CFG_REJ;
+ }
+ }
+ else
+
+ {
+ p_dcb->in_use = TRUE;
+ p_dcb->dch_oper = BTA_HL_DCH_OP_REMOTE_CREATE;
+ p_dcb->local_mdep_id = p_create_ind->dep_id ;
+ p_dcb->local_mdep_cfg_idx = mdep_cfg_idx;
+ p_dcb->local_cfg = BTA_HL_DCH_CFG_UNKNOWN;
+ p_dcb->remote_cfg = p_create_ind->cfg;
+ p_dcb->mdl_id = p_create_ind->mdl_id;
+ p_dcb->mdl_cfg_idx_included = FALSE;
+ bta_hl_find_rxtx_apdu_size(app_idx, mdep_cfg_idx,
+ &p_dcb->max_rx_apdu_size,
+ &p_dcb->max_tx_apdu_size);
+ send_create_ind_evt = TRUE;
+ }
+ }
+ else
+ {
+ rsp_code = MCA_RSP_BAD_MDEP;
+ }
+
+ if (send_create_ind_evt)
+ {
+ evt_data.dch_create_ind.mcl_handle = p_mcb->mcl_handle;
+ evt_data.dch_create_ind.app_handle = p_acb->app_handle;
+ evt_data.dch_create_ind.local_mdep_id = p_dcb->local_mdep_id;
+ evt_data.dch_create_ind.mdl_id = p_dcb->mdl_id;
+ evt_data.dch_create_ind.cfg = p_dcb->remote_cfg;
+ p_acb->p_cback(BTA_HL_DCH_CREATE_IND_EVT,(tBTA_HL *) &evt_data );
+ }
+ else
+ {
+ if (MCA_CreateMdlRsp((tMCA_CL) p_mcb->mcl_handle,
+ p_dcb->local_mdep_id,
+ p_dcb->mdl_id,
+ p_dcb->local_cfg,
+ rsp_code,
+ &p_dcb->chnl_cfg)!= MCA_SUCCESS)
+ {
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
+ }
+ else
+ {
+ if (p_dcb->local_mdep_id == BTA_HL_ECHO_TEST_MDEP_ID)
+ {
+ p_mcb->echo_test = TRUE;
+ p_dcb->echo_oper = BTA_HL_ECHO_OP_OPEN_IND;
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_dch_mca_create_cfm
+**
+** Description Action routine for processing
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hl_dch_mca_create_cfm(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data)
+{
+ tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ tMCA_CREATE_CFM *p_create_cfm = &p_data->mca_evt.mca_data.create_cfm;
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG0("bta_hl_dch_mca_create_cfm");
+#endif
+
+ if (p_dcb->abort_oper & BTA_HL_ABORT_PENDING_MASK)
+ {
+ p_dcb->abort_oper &= ~BTA_HL_ABORT_PENDING_MASK;
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_ABORT_EVT, p_data);
+ return;
+ }
+
+ if (p_dcb->dch_oper == BTA_HL_DCH_OP_LOCAL_OPEN)
+ {
+ if (p_create_cfm->rsp_code == MCA_RSP_SUCCESS)
+ {
+ if (bta_hl_validate_cfg(app_idx, mcl_idx, mdl_idx, p_create_cfm->cfg ))
+ {
+ bta_hl_set_dch_chan_cfg(app_idx, mcl_idx, mdl_idx, p_data);
+
+ if (MCA_DataChnlCfg((tMCA_CL) p_mcb->mcl_handle, &p_dcb->chnl_cfg)!= MCA_SUCCESS)
+ {
+ /* this should not happen */
+ APPL_TRACE_ERROR0("Unable to create data channel");
+ MCA_Abort((tMCA_CL) p_mcb->mcl_handle);
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
+ }
+ else
+ {
+ if (p_dcb->local_mdep_id == BTA_HL_ECHO_TEST_MDEP_ID)
+ {
+ p_dcb->echo_oper = BTA_HL_ECHO_OP_DCH_OPEN_CFM;
+ }
+ }
+ }
+ else
+ {
+ MCA_Abort((tMCA_CL) p_mcb->mcl_handle);
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
+ }
+ }
+ else
+ {
+ APPL_TRACE_ERROR0("MCA Create- failed");
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_dch_mca_create
+**
+** Description Action routine for processing the MDL create request
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hl_dch_mca_create(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data)
+{
+ tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ tMCA_RESULT result;
+ UINT8 sdp_idx;
+
+#if BTA_HL_DEBUG == TRUE
+ APPL_TRACE_DEBUG0("bta_hl_dch_mca_create");
+#endif
+
+ if (bta_hl_find_sdp_idx_using_ctrl_psm(&p_mcb->sdp, p_mcb->ctrl_psm, &sdp_idx) &&
+ bta_hl_validate_peer_cfg(app_idx, mcl_idx, mdl_idx,
+ p_dcb->peer_mdep_id,
+ p_dcb->peer_mdep_role,
+ sdp_idx))
+ {
+
+ p_mcb->data_psm = p_mcb->sdp.sdp_rec[sdp_idx].data_psm;
+ if ( (result = MCA_CreateMdl((tMCA_CL) p_mcb->mcl_handle,
+ p_dcb->local_mdep_id,
+ p_mcb->data_psm,
+ p_dcb->mdl_id,
+ p_dcb->peer_mdep_id,
+ p_dcb->local_cfg,
+ NULL )) != MCA_SUCCESS)
+ {
+ APPL_TRACE_ERROR1("MCA_CreateMdl FAIL mca_result=%d", result);
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
+ }
+ }
+ else
+ {
+ APPL_TRACE_ERROR0("MCA Create- SDP idx or peer MDEP cfg not found");
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_dch_sdp_fail
+**
+** Description Action routine for processing the SDP failed event
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hl_dch_sdp_fail(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data)
+{
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG0("bta_hl_dch_sdp_fail");
+#endif
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
+}
+
+/******************************************************************************
+**
+** Function bta_hl_sdp_cback
+**
+** Description This is the SDP callback function used by HL.
+** This function will be executed by SDP when the service
+** search is completed. If the search is successful, it
+** finds the first record in the database that matches the
+** UUID of the search. Then retrieves the scn from the
+** record.
+**
+** Returns void.
+**
+******************************************************************************/
+static void bta_hl_sdp_cback(UINT8 sdp_oper, UINT8 app_idx, UINT8 mcl_idx,
+ UINT8 mdl_idx, UINT16 status)
+{
+ tBTA_HL_MCL_CB *p_cb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_SDP_REC *p_hdp_rec;
+ tBTA_HL_CCH_SDP *p_cch_buf;
+ tBTA_HL_DCH_SDP *p_dch_buf;
+ tSDP_DISC_REC *p_rec = NULL;
+ tSDP_PROTOCOL_ELEM pe;
+ tSDP_DISC_ATTR *p_attr;
+ UINT8 i, rec_cnt;
+ tBTA_HL_SUP_FEATURE_LIST_ELEM sup_feature;
+ BOOLEAN sdp_parsing_ok =FALSE, result=FALSE;
+ UINT16 event;
+ tBTA_HL_MDL_CB *p_dcb;
+ UINT16 service_uuid;
+ UINT16 name_len;
+
+#if BTA_HL_DEBUG == TRUE
+ APPL_TRACE_DEBUG5("bta_hl_sdp_cback status:%d sdp_oper=%d app_idx=%d, mcl_idx=%d, mdl_idx=%d",
+ status, sdp_oper, app_idx, mcl_idx, mdl_idx);
+#endif
+
+ rec_cnt = 0;
+ service_uuid = bta_hl_get_service_uuids(sdp_oper, app_idx, mcl_idx, mdl_idx);
+
+ if (status == SDP_SUCCESS || status == SDP_DB_FULL)
+ {
+ memset(&p_cb->sdp,0, sizeof(tBTA_HL_SDP));
+ do
+ {
+ if (bta_hl_find_service_in_db(app_idx, mcl_idx, service_uuid, &p_rec))
+ {
+ p_hdp_rec = &p_cb->sdp.sdp_rec[rec_cnt];
+ p_cb->sdp.num_recs = rec_cnt+1;
+ }
+ else
+ {
+ break;
+ }
+
+ if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_L2CAP, &pe))
+ {
+ p_hdp_rec->ctrl_psm = (UINT16) pe.params[0];
+ }
+ else
+ {
+ APPL_TRACE_WARNING0("Control PSM not found");
+ break;
+ }
+ if (SDP_FindAddProtoListsElemInRec(p_rec, UUID_PROTOCOL_L2CAP, &pe))
+ {
+ p_hdp_rec->data_psm = (UINT16) pe.params[0];
+ }
+ else
+ {
+ APPL_TRACE_WARNING0("Data PSM not found");
+ break;
+ }
+
+ p_hdp_rec->srv_name[0]= '\0';
+ if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_NAME)) != NULL)
+ {
+ if (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) < BT_MAX_SERVICE_NAME_LEN)
+ name_len = (UINT16)SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
+ else
+ name_len = BT_MAX_SERVICE_NAME_LEN;
+ memcpy(p_hdp_rec->srv_name, p_attr->attr_value.v.array, name_len);
+ }
+
+ p_hdp_rec->srv_desp[0]= '\0';
+ if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_DESCRIPTION)) != NULL)
+ {
+ if (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) < BT_MAX_SERVICE_NAME_LEN)
+ name_len = (UINT16)SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
+ else
+ name_len = BT_MAX_SERVICE_NAME_LEN;
+ memcpy(p_hdp_rec->srv_desp, p_attr->attr_value.v.array, name_len);
+ }
+
+
+ p_hdp_rec->provider_name[0]= '\0';
+ if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_PROVIDER_NAME)) != NULL)
+ {
+ if (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) < BT_MAX_SERVICE_NAME_LEN)
+ name_len = (UINT16)SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
+ else
+ name_len = BT_MAX_SERVICE_NAME_LEN;
+ memcpy(p_hdp_rec->provider_name, p_attr->attr_value.v.array, name_len);
+ }
+
+ if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_HDP_MCAP_SUP_PROC))!=NULL)
+ {
+ p_hdp_rec->mcap_sup_proc = p_attr->attr_value.v.u8;
+ }
+ else
+ {
+ APPL_TRACE_WARNING0("MCAP SUP PROC not found");
+ break;
+ }
+
+ if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_HDP_SUP_FEAT_LIST ))!=NULL)
+ {
+ if (bta_hl_fill_sup_feature_list (p_attr, &sup_feature))
+ {
+ p_hdp_rec->num_mdeps = (UINT8) sup_feature.num_elems;
+ for (i=0; i<sup_feature.num_elems; i++)
+ {
+ p_hdp_rec->mdep_cfg[i].data_type = sup_feature.list_elem[i].data_type;
+ p_hdp_rec->mdep_cfg[i].mdep_id = sup_feature.list_elem[i].mdep_id;
+ p_hdp_rec->mdep_cfg[i].mdep_role = sup_feature.list_elem[i].mdep_role;
+ /* Check MDEP Description pointer to prevent crash due to null pointer */
+ if (sup_feature.list_elem[i].p_mdep_desp != NULL)
+ {
+ BCM_STRNCPY_S(p_hdp_rec->mdep_cfg[i].mdep_desp,
+ sizeof(p_hdp_rec->mdep_cfg[i].mdep_desp),
+ sup_feature.list_elem[i].p_mdep_desp,
+ BTA_HL_MDEP_DESP_LEN);
+ }
+ else
+ {
+ APPL_TRACE_ERROR1("bta_hl_sdp_cback Incorrect Mdep[%d] Description (Null ptr)", i);
+ }
+ }
+
+ sdp_parsing_ok = TRUE;
+ }
+ else
+ {
+ APPL_TRACE_WARNING0("HDP supported feature list fill failed");
+ break;
+ }
+ }
+ else
+ {
+ APPL_TRACE_WARNING0("HDP supported feature list not found");
+ break;
+ }
+#if BTA_HL_DEBUG == TRUE
+ APPL_TRACE_DEBUG3("record=%d ctrl_psm=%0x data_psm=%x",
+ rec_cnt+1,
+ p_hdp_rec->ctrl_psm,
+ p_hdp_rec->data_psm );
+ APPL_TRACE_DEBUG1("srv_name=[%s]",(p_hdp_rec->srv_name[0] != '\0')? p_hdp_rec->srv_name:"NULL");
+ APPL_TRACE_DEBUG1("srv_desp=[%s]",(p_hdp_rec->srv_desp[0] != '\0')? p_hdp_rec->srv_desp:"NULL");
+ for (i=0; i<sup_feature.num_elems; i++)
+ {
+ APPL_TRACE_DEBUG5("index=0x%02x mdep_id=0x%04x data type=0x%04x mdep role=%s(0x%02x)",
+ (i+1),
+ p_hdp_rec->mdep_cfg[i].mdep_id,
+ p_hdp_rec->mdep_cfg[i].data_type,
+ (p_hdp_rec->mdep_cfg[i].mdep_role == BTA_HL_MDEP_ROLE_SOURCE)?"Src":"Snk",
+ p_hdp_rec->mdep_cfg[i].mdep_role);
+ }
+ APPL_TRACE_DEBUG1("provider_name=[%s]",(p_hdp_rec->provider_name[0] != '\0')? p_hdp_rec->provider_name:"NULL");
+ APPL_TRACE_DEBUG1("found MCAP sup procedure=%d",
+ p_cb->sdp.sdp_rec[rec_cnt].mcap_sup_proc );
+#endif
+ rec_cnt++;
+ if (rec_cnt >= BTA_HL_NUM_SDP_RECS)
+ {
+ APPL_TRACE_WARNING1("No more spaces for SDP recs max_rec_cnt=%d", BTA_HL_NUM_SDP_RECS);
+ break;
+ }
+
+
+ } while (TRUE);
+ }
+
+
+ utl_freebuf((void **)&p_cb->p_db);
+
+ if ( (status == SDP_SUCCESS || status == SDP_DB_FULL) &&
+ p_cb->sdp.num_recs &&
+ sdp_parsing_ok)
+ {
+ result = TRUE;
+ }
+ else
+ {
+ APPL_TRACE_WARNING3("SDP Failed sdp_status=%d num_recs=%d sdp_parsing_ok=%d ",
+ status, p_cb->sdp.num_recs,sdp_parsing_ok );
+ }
+
+
+ p_cb->sdp_oper = BTA_HL_SDP_OP_NONE;
+
+ switch (sdp_oper )
+ {
+ case BTA_HL_SDP_OP_CCH_INIT:
+ case BTA_HL_SDP_OP_SDP_QUERY_NEW:
+ case BTA_HL_SDP_OP_SDP_QUERY_CURRENT:
+
+ /* send result in event back to BTA */
+ if ((p_cch_buf = (tBTA_HL_CCH_SDP *) GKI_getbuf(sizeof(tBTA_HL_CCH_SDP))) != NULL)
+ {
+ if (result)
+ {
+ if (sdp_oper == BTA_HL_SDP_OP_CCH_INIT)
+ {
+ event = BTA_HL_CCH_SDP_OK_EVT;
+ if (p_cb->close_pending)
+ {
+ event = BTA_HL_CCH_SDP_FAIL_EVT;
+ }
+ }
+ else
+ {
+ event = BTA_HL_SDP_QUERY_OK_EVT;
+ }
+ }
+ else
+ {
+ if (sdp_oper == BTA_HL_SDP_OP_CCH_INIT)
+ {
+ event = BTA_HL_CCH_SDP_FAIL_EVT;
+ }
+ else
+ {
+ event = BTA_HL_SDP_QUERY_FAIL_EVT;
+ }
+ }
+ p_cch_buf->hdr.event = event;
+
+ p_cch_buf->app_idx = app_idx;
+ p_cch_buf->mcl_idx = mcl_idx;
+ p_cch_buf->release_mcl_cb = FALSE;
+ if (sdp_oper == BTA_HL_SDP_OP_SDP_QUERY_NEW)
+ {
+ p_cch_buf->release_mcl_cb = TRUE;
+ }
+
+ bta_sys_sendmsg(p_cch_buf);
+ }
+ break;
+ case BTA_HL_SDP_OP_DCH_OPEN_INIT:
+ case BTA_HL_SDP_OP_DCH_RECONNECT_INIT:
+ if ((p_dch_buf = (tBTA_HL_DCH_SDP *) GKI_getbuf(sizeof(tBTA_HL_DCH_SDP))) != NULL)
+ {
+ p_dch_buf->hdr.event = BTA_HL_DCH_SDP_FAIL_EVT;
+ p_dch_buf->app_idx = app_idx;
+ p_dch_buf->mcl_idx = mcl_idx;
+ p_dch_buf->mdl_idx = mdl_idx;
+ p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ if (p_dcb->abort_oper & BTA_HL_ABORT_PENDING_MASK)
+ {
+ p_dcb->abort_oper &= ~BTA_HL_ABORT_PENDING_MASK;
+ result = FALSE;
+ }
+ if (result)
+ {
+ if (sdp_oper == BTA_HL_SDP_OP_DCH_OPEN_INIT)
+ {
+ if (p_dcb->local_mdep_id == BTA_HL_ECHO_TEST_MDEP_ID )
+ {
+ p_dch_buf->hdr.event = BTA_HL_DCH_ECHO_TEST_EVT;
+ }
+ else
+ {
+ p_dch_buf->hdr.event = BTA_HL_DCH_OPEN_EVT;
+ }
+ }
+ else
+ {
+ p_dch_buf->hdr.event = BTA_HL_DCH_RECONNECT_EVT;
+ }
+ }
+ bta_sys_sendmsg(p_dch_buf);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+
+/******************************************************************************
+**
+** Function bta_hl_sdp_cback0
+**
+** Description This is the SDP callback function used by index = 0
+**
+** Returns void.
+**
+******************************************************************************/
+static void bta_hl_sdp_cback0(UINT16 status)
+{
+ bta_hl_sdp_cback(bta_hl_cb.scb[0].sdp_oper,
+ bta_hl_cb.scb[0].app_idx,
+ bta_hl_cb.scb[0].mcl_idx,
+ bta_hl_cb.scb[0].mdl_idx,
+ status);
+ bta_hl_deallocate_spd_cback(0);
+}
+
+/******************************************************************************
+**
+** Function bta_hl_sdp_cback1
+**
+** Description This is the SDP callback function used by index = 1
+**
+** Parameters status - status of the SDP callabck
+**
+** Returns void.
+**
+******************************************************************************/
+static void bta_hl_sdp_cback1(UINT16 status)
+{
+ bta_hl_sdp_cback(bta_hl_cb.scb[1].sdp_oper,
+ bta_hl_cb.scb[1].app_idx,
+ bta_hl_cb.scb[1].mcl_idx,
+ bta_hl_cb.scb[1].mdl_idx,
+ status);
+ bta_hl_deallocate_spd_cback(1);
+}
+
+/******************************************************************************
+**
+** Function bta_hl_sdp_cback2
+**
+** Description This is the SDP callback function used by index = 2
+**
+** Returns void.
+**
+******************************************************************************/
+static void bta_hl_sdp_cback2(UINT16 status)
+{
+ bta_hl_sdp_cback(bta_hl_cb.scb[2].sdp_oper,
+ bta_hl_cb.scb[2].app_idx,
+ bta_hl_cb.scb[2].mcl_idx,
+ bta_hl_cb.scb[2].mdl_idx,
+ status);
+ bta_hl_deallocate_spd_cback(2);
+}
+
+/******************************************************************************
+**
+** Function bta_hl_sdp_cback3
+**
+** Description This is the SDP callback function used by index = 3
+**
+** Returns void.
+**
+******************************************************************************/
+static void bta_hl_sdp_cback3(UINT16 status)
+{
+ bta_hl_sdp_cback(bta_hl_cb.scb[3].sdp_oper,
+ bta_hl_cb.scb[3].app_idx,
+ bta_hl_cb.scb[3].mcl_idx,
+ bta_hl_cb.scb[3].mdl_idx,
+ status);
+ bta_hl_deallocate_spd_cback(3);
+}
+
+/******************************************************************************
+**
+** Function bta_hl_sdp_cback4
+**
+** Description This is the SDP callback function used by index = 4
+**
+** Parameters status - status of the SDP callabck
+**
+** Returns void.
+**
+******************************************************************************/
+static void bta_hl_sdp_cback4(UINT16 status)
+{
+ bta_hl_sdp_cback(bta_hl_cb.scb[4].sdp_oper,
+ bta_hl_cb.scb[4].app_idx,
+ bta_hl_cb.scb[4].mcl_idx,
+ bta_hl_cb.scb[4].mdl_idx,
+ status);
+ bta_hl_deallocate_spd_cback(4);
+}
+
+/******************************************************************************
+**
+** Function bta_hl_sdp_cback5
+**
+** Description This is the SDP callback function used by index = 5
+**
+** Parameters status - status of the SDP callabck
+**
+** Returns void.
+**
+******************************************************************************/
+static void bta_hl_sdp_cback5(UINT16 status)
+{
+ bta_hl_sdp_cback(bta_hl_cb.scb[5].sdp_oper,
+ bta_hl_cb.scb[5].app_idx,
+ bta_hl_cb.scb[5].mcl_idx,
+ bta_hl_cb.scb[5].mdl_idx,
+ status);
+ bta_hl_deallocate_spd_cback(5);
+}
+
+/******************************************************************************
+**
+** Function bta_hl_sdp_cback6
+**
+** Description This is the SDP callback function used by index = 6
+**
+** Returns void.
+**
+******************************************************************************/
+static void bta_hl_sdp_cback6(UINT16 status)
+{
+ bta_hl_sdp_cback(bta_hl_cb.scb[6].sdp_oper,
+ bta_hl_cb.scb[6].app_idx,
+ bta_hl_cb.scb[6].mcl_idx,
+ bta_hl_cb.scb[6].mdl_idx,
+ status);
+ bta_hl_deallocate_spd_cback(6);
+}
+
+
+/*******************************************************************************
+**
+** Function bta_hl_deallocate_spd_cback
+**
+** Description Deallocate a SDP control block
+**
+** Returns BOOLEAN - TRUE found
+** FALSE not found
+**
+*******************************************************************************/
+void bta_hl_deallocate_spd_cback(UINT8 sdp_cback_idx)
+{
+ tBTA_HL_SDP_CB *p_spd_cb = &bta_hl_cb.scb[sdp_cback_idx];
+
+ memset(p_spd_cb, 0, sizeof(tBTA_HL_SDP_CB));
+
+#if BTA_HL_DEBUG == TRUE
+ APPL_TRACE_DEBUG1("bta_hl_deallocate_spd_cback index=%d", sdp_cback_idx);
+#endif
+
+
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_allocate_spd_cback
+**
+** Description Finds a not in used SDP control block index
+**
+**
+** Returns BOOLEAN - TRUE found
+** FALSE not found
+**
+*******************************************************************************/
+tSDP_DISC_CMPL_CB *bta_hl_allocate_spd_cback(tBTA_HL_SDP_OPER sdp_oper, UINT8 app_idx, UINT8 mcl_idx,
+ UINT8 mdl_idx,
+ UINT8 *p_sdp_cback_idx)
+{
+ UINT8 i;
+ tSDP_DISC_CMPL_CB *p_cbcak=NULL;
+
+
+ for (i=0; i < BTA_HL_NUM_SDP_CBACKS ; i ++)
+ {
+ if (!bta_hl_cb.scb[i].in_use)
+ {
+ p_cbcak = bta_hl_sdp_cback_arr[i];
+ bta_hl_cb.scb[i].in_use = TRUE;
+ bta_hl_cb.scb[i].sdp_oper = sdp_oper;
+ bta_hl_cb.scb[i].app_idx = app_idx;
+ bta_hl_cb.scb[i].mcl_idx = mcl_idx;
+ bta_hl_cb.scb[i].mdl_idx = mdl_idx;
+ *p_sdp_cback_idx = i;
+ break;
+ }
+ }
+
+ if (i == BTA_HL_NUM_SDP_CBACKS)
+ {
+ APPL_TRACE_WARNING0("No scb is available to allocate")
+ }
+ else
+ {
+#if BTA_HL_DEBUG == TRUE
+ APPL_TRACE_DEBUG1("bta_hl_allocate_spd_cback cback_idx=%d ",i );
+ APPL_TRACE_DEBUG4("sdp_oper=%d, app_idx=%d, mcl_idx=%d, mdl_idx=%d",
+ bta_hl_cb.scb[i].sdp_oper,
+ bta_hl_cb.scb[i].app_idx,
+ bta_hl_cb.scb[i].mcl_idx,
+ bta_hl_cb.scb[i].mdl_idx );
+#endif
+ }
+ return p_cbcak;
+}
+
+
+/*******************************************************************************
+**
+** Function bta_hl_init_sdp
+**
+** Description Action routine for processing the SDP initiattion request
+**
+** Returns void
+**
+*******************************************************************************/
+tBTA_HL_STATUS bta_hl_init_sdp(tBTA_HL_SDP_OPER sdp_oper, UINT8 app_idx, UINT8 mcl_idx,
+ UINT8 mdl_idx)
+{
+ tBTA_HL_MCL_CB *p_cb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tSDP_UUID uuid_list;
+ UINT16 attr_list[BTA_HL_NUM_SRCH_ATTR];
+ UINT16 num_attrs = BTA_HL_NUM_SRCH_ATTR;
+ tBTA_HL_STATUS status;
+ UINT8 sdp_cback_idx;
+#if BTA_HL_DEBUG == TRUE
+ APPL_TRACE_DEBUG4("bta_hl_init_sdp sdp_oper=%d app_idx=%d mcl_idx=%d, mdl_idx=%d",
+ sdp_oper, app_idx, mcl_idx, mdl_idx);
+#endif
+ if ((p_cb->sdp_cback = bta_hl_allocate_spd_cback(sdp_oper, app_idx, mcl_idx, mdl_idx, &sdp_cback_idx)) != NULL)
+ {
+ if ( p_cb->p_db ||
+ (!p_cb->p_db &&
+ (p_cb->p_db = (tSDP_DISCOVERY_DB *) GKI_getbuf(BTA_HL_DISC_SIZE)) != NULL))
+ {
+ attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST;
+ attr_list[1] = ATTR_ID_PROTOCOL_DESC_LIST;
+ attr_list[2] = ATTR_ID_BT_PROFILE_DESC_LIST;
+ attr_list[3] = ATTR_ID_ADDITION_PROTO_DESC_LISTS;
+ attr_list[4] = ATTR_ID_SERVICE_NAME;
+ attr_list[5] = ATTR_ID_SERVICE_DESCRIPTION;
+ attr_list[6] = ATTR_ID_PROVIDER_NAME;
+ attr_list[7] = ATTR_ID_HDP_SUP_FEAT_LIST;
+ attr_list[8] = ATTR_ID_HDP_DATA_EXCH_SPEC;
+ attr_list[9] = ATTR_ID_HDP_MCAP_SUP_PROC;
+
+
+ uuid_list.len = LEN_UUID_16;
+ uuid_list.uu.uuid16 = UUID_SERVCLASS_HDP_PROFILE;
+
+ SDP_InitDiscoveryDb(p_cb->p_db, BTA_HL_DISC_SIZE, 1, &uuid_list, num_attrs, attr_list);
+
+ if (!SDP_ServiceSearchAttributeRequest(p_cb->bd_addr, p_cb->p_db, p_cb->sdp_cback))
+ {
+ status = BTA_HL_STATUS_FAIL;
+ }
+ else
+ {
+ status = BTA_HL_STATUS_OK;
+ }
+ }
+ else /* No services available */
+ {
+ status = BTA_HL_STATUS_NO_RESOURCE;
+ }
+ }
+ else
+ {
+ status = BTA_HL_STATUS_SDP_NO_RESOURCE;
+ }
+
+ if (status != BTA_HL_STATUS_OK)
+ {
+ utl_freebuf((void **)&p_cb->p_db);
+ if (status != BTA_HL_STATUS_SDP_NO_RESOURCE )
+ {
+ bta_hl_deallocate_spd_cback(sdp_cback_idx);
+ }
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_cch_sdp_init
+**
+** Description Action routine for processing the CCH SDP init event
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hl_cch_sdp_init(UINT8 app_idx, UINT8 mcl_idx, tBTA_HL_DATA *p_data)
+{
+ tBTA_HL_MCL_CB *p_cb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+#if BTA_HL_DEBUG == TRUE
+ APPL_TRACE_DEBUG0("bta_hl_cch_init_sdp");
+#endif
+ if ( p_cb->sdp_oper == BTA_HL_SDP_OP_NONE)
+ {
+ p_cb->sdp_oper = BTA_HL_SDP_OP_CCH_INIT;
+
+ if (bta_hl_init_sdp( p_cb->sdp_oper, app_idx, mcl_idx, 0xFF) != BTA_HL_STATUS_OK)
+ {
+ p_cb->sdp_oper = BTA_HL_SDP_OP_NONE;
+ bta_hl_cch_sm_execute(app_idx, mcl_idx, BTA_HL_CCH_SDP_FAIL_EVT, p_data);
+ }
+ }
+ else
+ {
+ APPL_TRACE_ERROR0("SDP in use");
+ bta_hl_cch_sm_execute(app_idx, mcl_idx, BTA_HL_CCH_SDP_FAIL_EVT, p_data);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_cch_mca_open
+**
+** Description Action routine for processing the CCH open request
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hl_cch_mca_open(UINT8 app_idx, UINT8 mcl_idx, tBTA_HL_DATA *p_data)
+{
+ tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ UINT8 sdp_idx;
+
+#if BTA_HL_DEBUG == TRUE
+ APPL_TRACE_DEBUG0("bta_hl_cch_mca_open");
+#endif
+
+ if (bta_hl_find_sdp_idx_using_ctrl_psm(&p_mcb->sdp, p_mcb->req_ctrl_psm, &sdp_idx))
+ {
+ p_mcb->ctrl_psm = p_mcb->sdp.sdp_rec[sdp_idx].ctrl_psm;
+ p_mcb->data_psm = p_mcb->sdp.sdp_rec[sdp_idx].data_psm;
+ if ( MCA_ConnectReq((tMCA_HANDLE) p_acb->app_handle,
+ p_mcb->bd_addr,
+ p_mcb->ctrl_psm ,
+ p_mcb->sec_mask) != MCA_SUCCESS)
+ {
+
+ bta_hl_cch_sm_execute(app_idx, mcl_idx, BTA_HL_CCH_CLOSE_CMPL_EVT, p_data);
+ }
+ }
+ else
+ {
+ bta_hl_cch_sm_execute(app_idx, mcl_idx, BTA_HL_CCH_CLOSE_CMPL_EVT, p_data);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_cch_mca_close
+**
+** Description Action routine for processing the CCH close request
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hl_cch_mca_close(UINT8 app_idx, UINT8 mcl_idx, tBTA_HL_DATA *p_data)
+{
+ tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+
+#if BTA_HL_DEBUG == TRUE
+ APPL_TRACE_DEBUG0("bta_hl_cch_mca_close");
+#endif
+ if (p_mcb->sdp_oper != BTA_HL_SDP_OP_CCH_INIT)
+ {
+ if ( MCA_DisconnectReq((tMCA_HANDLE) p_acb->app_handle) != MCA_SUCCESS)
+ {
+ bta_hl_cch_sm_execute(app_idx, mcl_idx, BTA_HL_CCH_CLOSE_CMPL_EVT, p_data);
+ }
+ }
+ else
+ {
+ p_mcb->close_pending = TRUE;
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_cch_close_cmpl
+**
+** Description Action routine for processing the CCH close complete event
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hl_cch_close_cmpl(UINT8 app_idx, UINT8 mcl_idx, tBTA_HL_DATA *p_data)
+{
+ tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+
+ tBTA_HL evt_data;
+ tBTA_HL_EVT event;
+ BOOLEAN send_evt=TRUE;
+#if BTA_HL_DEBUG == TRUE
+ APPL_TRACE_DEBUG0("bta_hl_cch_close_cmpl");
+#endif
+ bta_sys_conn_close(BTA_ID_HL, p_acb->app_id, p_mcb->bd_addr);
+
+ switch (p_mcb->cch_oper)
+ {
+ case BTA_HL_CCH_OP_LOCAL_OPEN:
+ bta_hl_build_cch_open_cfm(&evt_data, p_acb->app_handle,
+ p_mcb->mcl_handle,
+ p_mcb->bd_addr,
+ BTA_HL_STATUS_FAIL);
+ event = BTA_HL_CCH_OPEN_CFM_EVT;
+ break;
+ case BTA_HL_CCH_OP_LOCAL_CLOSE:
+ bta_hl_build_cch_close_cfm(&evt_data, p_acb->app_handle,
+ p_mcb->mcl_handle,
+ BTA_HL_STATUS_OK);
+ event = BTA_HL_CCH_CLOSE_CFM_EVT;
+ break;
+ case BTA_HL_CCH_OP_REMOTE_CLOSE:
+ bta_hl_build_cch_close_ind(&evt_data,
+ p_acb->app_handle,
+ p_mcb->mcl_handle,
+ p_mcb->intentional_close);
+ event = BTA_HL_CCH_CLOSE_IND_EVT;
+ break;
+ default:
+ send_evt=FALSE;
+ break;
+ }
+
+
+ memset(p_mcb, 0 ,sizeof(tBTA_HL_MCL_CB));
+
+ if (send_evt)p_acb->p_cback(event,(tBTA_HL *) &evt_data );
+
+ bta_hl_check_deregistration(app_idx, p_data);
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_cch_mca_disconnect
+**
+** Description Action routine for processing the CCH disconnect indication
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hl_cch_mca_disconnect(UINT8 app_idx, UINT8 mcl_idx, tBTA_HL_DATA *p_data)
+{
+
+ tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_MDL_CB *p_dcb;
+ UINT8 i;
+#if BTA_HL_DEBUG == TRUE
+ APPL_TRACE_DEBUG0("bta_hl_cch_mca_disconnect");
+#endif
+
+ p_mcb->intentional_close = FALSE;
+ if (p_data->mca_evt.mca_data.disconnect_ind.reason == L2CAP_DISC_OK)
+ {
+ p_mcb->intentional_close = TRUE;
+ }
+
+ for (i=0; i< BTA_HL_NUM_MDLS_PER_MCL; i++)
+ {
+ p_dcb= BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, i);
+ if (p_dcb->in_use && (p_dcb->dch_state != BTA_HL_DCH_IDLE_ST))
+ {
+ if (p_mcb->cch_oper == BTA_HL_CCH_OP_LOCAL_CLOSE )
+ {
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, i, BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
+ }
+ else
+ {
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, i, BTA_HL_MCA_CLOSE_IND_EVT, p_data);
+ }
+ }
+ }
+ bta_hl_cch_sm_execute(app_idx, mcl_idx, BTA_HL_CCH_CLOSE_CMPL_EVT, p_data);
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_cch_mca_rsp_tout
+**
+** Description Action routine for processing the MCAP response timeout
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hl_cch_mca_rsp_tout(UINT8 app_idx, UINT8 mcl_idx, tBTA_HL_DATA *p_data)
+{
+
+ tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+#if BTA_HL_DEBUG == TRUE
+ APPL_TRACE_DEBUG0("bta_hl_cch_mca_rsp_tout");
+#endif
+
+ p_mcb->rsp_tout = TRUE;
+
+ bta_hl_check_cch_close(app_idx,mcl_idx,p_data,TRUE);
+}
+/*******************************************************************************
+**
+** Function bta_hl_cch_mca_connect
+**
+** Description Action routine for processing the CCH connect indication
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hl_cch_mca_connect(UINT8 app_idx, UINT8 mcl_idx, tBTA_HL_DATA *p_data)
+{
+ tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL evt_data;
+ tBTA_HL_EVT event;
+ BOOLEAN send_event=TRUE;
+
+#if BTA_HL_DEBUG == TRUE
+ APPL_TRACE_DEBUG0("bta_hl_cch_mca_connect");
+#endif
+
+ p_mcb->mcl_handle = p_data->mca_evt.mcl_handle;
+ bdcpy(p_mcb->bd_addr, p_data->mca_evt.mca_data.connect_ind.bd_addr);
+ p_mcb->cch_mtu = p_data->mca_evt.mca_data.connect_ind.mtu;
+
+ bta_sys_conn_open(BTA_ID_HL, p_acb->app_id, p_mcb->bd_addr);
+ switch (p_mcb->cch_oper)
+ {
+ case BTA_HL_CCH_OP_LOCAL_OPEN:
+ bta_hl_build_cch_open_cfm(&evt_data, p_acb->app_handle,
+ p_mcb->mcl_handle,
+ p_mcb->bd_addr,
+ BTA_HL_STATUS_OK);
+ event = BTA_HL_CCH_OPEN_CFM_EVT;
+ break;
+ case BTA_HL_CCH_OP_REMOTE_OPEN:
+ bta_hl_build_cch_open_ind(&evt_data, p_acb->app_handle,
+ p_mcb->mcl_handle,
+ p_mcb->bd_addr);
+ event = BTA_HL_CCH_OPEN_IND_EVT;
+ break;
+ default:
+ send_event = FALSE;
+ break;
+ }
+
+ p_mcb->cch_oper = BTA_HL_CCH_OP_NONE;
+ if (send_event) p_acb->p_cback(event,(tBTA_HL *) &evt_data );
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_mcap_ctrl_cback
+**
+** Description MCAP control callback function for HL.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hl_mcap_ctrl_cback (tMCA_HANDLE handle, tMCA_CL mcl, UINT8 event,
+ tMCA_CTRL *p_data)
+{
+ tBTA_HL_MCA_EVT * p_msg;
+ BOOLEAN send_event=TRUE;
+ UINT16 mca_event;
+
+#if (BTA_HL_DEBUG == TRUE)
+#if (BT_TRACE_VERBOSE == TRUE)
+ APPL_TRACE_EVENT1("bta_hl_mcap_ctrl_cback event[%s]",bta_hl_mcap_evt_code(event));
+#else
+ APPL_TRACE_EVENT1("bta_hl_mcap_ctrl_cback event[0x%02x]", event);
+#endif
+#endif
+
+ switch (event)
+ {
+
+ case MCA_CREATE_IND_EVT:
+ mca_event = (UINT16) BTA_HL_MCA_CREATE_IND_EVT;
+ break;
+ case MCA_CREATE_CFM_EVT:
+ mca_event = (UINT16) BTA_HL_MCA_CREATE_CFM_EVT;
+ break;
+ case MCA_RECONNECT_IND_EVT:
+ mca_event = (UINT16) BTA_HL_MCA_RECONNECT_IND_EVT;
+ break;
+ case MCA_RECONNECT_CFM_EVT:
+ mca_event = (UINT16) BTA_HL_MCA_RECONNECT_CFM_EVT;
+ break;
+ case MCA_ABORT_IND_EVT:
+ mca_event = (UINT16) BTA_HL_MCA_ABORT_IND_EVT;
+ break;
+ case MCA_ABORT_CFM_EVT:
+ mca_event = (UINT16) BTA_HL_MCA_ABORT_CFM_EVT;
+ break;
+ case MCA_DELETE_IND_EVT:
+ mca_event = (UINT16) BTA_HL_MCA_DELETE_IND_EVT;
+ break;
+ case MCA_DELETE_CFM_EVT:
+ mca_event = (UINT16) BTA_HL_MCA_DELETE_CFM_EVT;
+ break;
+ case MCA_CONNECT_IND_EVT:
+ mca_event = (UINT16) BTA_HL_MCA_CONNECT_IND_EVT;
+ break;
+ case MCA_DISCONNECT_IND_EVT:
+ mca_event = (UINT16) BTA_HL_MCA_DISCONNECT_IND_EVT;
+ break;
+ case MCA_OPEN_IND_EVT:
+ mca_event = (UINT16) BTA_HL_MCA_OPEN_IND_EVT;
+ break;
+ case MCA_OPEN_CFM_EVT:
+ mca_event = (UINT16) BTA_HL_MCA_OPEN_CFM_EVT;
+ break;
+ case MCA_CLOSE_IND_EVT:
+ mca_event = (UINT16) BTA_HL_MCA_CLOSE_IND_EVT;
+ break;
+ case MCA_CLOSE_CFM_EVT:
+ mca_event = (UINT16) BTA_HL_MCA_CLOSE_CFM_EVT;
+ break;
+ case MCA_CONG_CHG_EVT:
+ mca_event = (UINT16) BTA_HL_MCA_CONG_CHG_EVT;
+ break;
+ case MCA_RSP_TOUT_IND_EVT:
+ mca_event = (UINT16) BTA_HL_MCA_RSP_TOUT_IND_EVT;
+ break;
+ case MCA_ERROR_RSP_EVT:
+
+ default:
+ send_event=FALSE;
+ break;
+ }
+
+ if ((p_msg = (tBTA_HL_MCA_EVT *)GKI_getbuf(sizeof(tBTA_HL_MCA_EVT))) != NULL)
+ {
+ p_msg->hdr.event = mca_event;
+ p_msg->app_handle = (tBTA_HL_APP_HANDLE) handle;
+ p_msg->mcl_handle = (tBTA_HL_MCL_HANDLE) mcl;
+ memcpy (&p_msg->mca_data, p_data, sizeof(tMCA_CTRL));
+ bta_sys_sendmsg(p_msg);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function bta_hl_mcap_data_cback
+**
+** Description MCAP data callback function for HL.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hl_mcap_data_cback (tMCA_DL mdl, BT_HDR *p_pkt)
+{
+ tBTA_HL_MCA_RCV_DATA_EVT *p_msg;
+
+ UINT8 app_idx, mcl_idx, mdl_idx;
+ if (bta_hl_find_mdl_idx_using_handle ((tBTA_HL_MDL_HANDLE)mdl, &app_idx, &mcl_idx, &mdl_idx))
+ {
+ if ((p_msg = (tBTA_HL_MCA_RCV_DATA_EVT *)GKI_getbuf(sizeof(tBTA_HL_MCA_RCV_DATA_EVT))) != NULL)
+ {
+ p_msg->hdr.event = BTA_HL_MCA_RCV_DATA_EVT;
+ p_msg->app_idx = app_idx;
+ p_msg->mcl_idx = mcl_idx;
+ p_msg->mdl_idx = mdl_idx;
+ p_msg->p_pkt = p_pkt;
+ bta_sys_sendmsg(p_msg);
+ }
+ }
+}
+/*****************************************************************************
+** Debug Functions
+*****************************************************************************/
+#if (BTA_HL_DEBUG == TRUE && BT_TRACE_VERBOSE == TRUE)
+
+/*******************************************************************************
+**
+** Function bta_hl_mcap_evt_code
+**
+** Description get the MCAP event string pointer
+**
+** Returns char * - event string pointer
+**
+*******************************************************************************/
+static char *bta_hl_mcap_evt_code(UINT8 evt_code)
+{
+
+ switch (evt_code)
+ {
+
+ case MCA_ERROR_RSP_EVT:
+ return "MCA_ERROR_RSP_EVT";
+ case MCA_CREATE_IND_EVT:
+ return "MCA_CREATE_IND_EVT";
+ case MCA_CREATE_CFM_EVT:
+ return "MCA_CREATE_CFM_EVT";
+ case MCA_RECONNECT_IND_EVT:
+ return "MCA_RECONNECT_IND_EVT";
+ case MCA_RECONNECT_CFM_EVT:
+ return "MCA_RECONNECT_CFM_EVT";
+ case MCA_ABORT_IND_EVT:
+ return "MCA_ABORT_IND_EVT";
+ case MCA_ABORT_CFM_EVT:
+ return "MCA_ABORT_CFM_EVT";
+ case MCA_DELETE_IND_EVT:
+ return "MCA_DELETE_IND_EVT";
+ case MCA_DELETE_CFM_EVT:
+ return "MCA_DELETE_CFM_EVT";
+
+ case MCA_CONNECT_IND_EVT:
+ return "MCA_CONNECT_IND_EVT";
+ case MCA_DISCONNECT_IND_EVT:
+ return "MCA_DISCONNECT_IND_EVT";
+ case MCA_OPEN_IND_EVT:
+ return "MCA_OPEN_IND_EVT";
+ case MCA_OPEN_CFM_EVT:
+ return "MCA_OPEN_CFM_EVT";
+ case MCA_CLOSE_IND_EVT:
+ return "MCA_CLOSE_IND_EVT";
+ case MCA_CLOSE_CFM_EVT:
+ return "MCA_CLOSE_CFM_EVT";
+ case MCA_CONG_CHG_EVT:
+ return "MCA_CONG_CHG_EVT";
+ case MCA_RSP_TOUT_IND_EVT:
+ return "MCA_RSP_TOUT_IND_EVT";
+ default:
+ return "Unknown MCAP event code";
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function bta_hl_cback_evt_code
+**
+** Description get the HDP event string pointer
+**
+** Returns char * - event string pointer
+**
+*******************************************************************************/
+static char *bta_hl_cback_evt_code(UINT8 evt_code)
+{
+
+ switch (evt_code)
+ {
+
+ case BTA_HL_CCH_OPEN_IND_EVT:
+ return "BTA_HL_CCH_OPEN_IND_EVT";
+ case BTA_HL_CCH_OPEN_CFM_EVT:
+ return "BTA_HL_CCH_OPEN_CFM_EVT";
+ case BTA_HL_CCH_CLOSE_IND_EVT:
+ return "BTA_HL_CCH_CLOSE_IND_EVT";
+ case BTA_HL_CCH_CLOSE_CFM_EVT:
+ return "BTA_HL_CCH_CLOSE_CFM_EVT";
+ case BTA_HL_DCH_OPEN_IND_EVT:
+ return "BTA_HL_DCH_OPEN_IND_EVT";
+ case BTA_HL_DCH_OPEN_CFM_EVT:
+ return "BTA_HL_DCH_OPEN_CFM_EVT";
+ case BTA_HL_DCH_CLOSE_IND_EVT:
+ return "BTA_HL_DCH_CLOSE_IND_EVT";
+ case BTA_HL_DCH_CLOSE_CFM_EVT:
+ return "BTA_HL_DCH_CLOSE_CFM_EVT";
+ case BTA_HL_DCH_RCV_DATA_IND_EVT:
+ return "BTA_HL_DCH_RCV_DATA_IND_EVT";
+ case BTA_HL_REGISTER_CFM_EVT:
+ return "BTA_HL_REGISTER_CFM_EVT";
+ case BTA_HL_DEREGISTER_CFM_EVT:
+ return "BTA_HL_DEREGISTER_CFM_EVT";
+ case BTA_HL_DCH_RECONNECT_CFM_EVT:
+ return "BTA_HL_DCH_RECONNECT_CFM_EVT";
+ case BTA_HL_DCH_RECONNECT_IND_EVT:
+ return "BTA_HL_DCH_RECONNECT_IND_EVT";
+ case BTA_HL_DCH_ECHO_TEST_CFM_EVT:
+ return "BTA_HL_DCH_ECHO_TEST_CFM_EVT";
+ case BTA_HL_SDP_QUERY_CFM_EVT:
+ return "BTA_HL_SDP_QUERY_CFM_EVT";
+ case BTA_HL_CONG_CHG_IND_EVT:
+ return "BTA_HL_CONG_CHG_IND_EVT";
+ case BTA_HL_DCH_CREATE_IND_EVT:
+ return "BTA_HL_DCH_CREATE_IND_EVT";
+ case BTA_HL_DELETE_MDL_IND_EVT:
+ return "BTA_HL_DELETE_MDL_IND_EVT";
+ case BTA_HL_DELETE_MDL_CFM_EVT:
+ return "BTA_HL_DELETE_MDL_CFM_EVT";
+ case BTA_HL_DCH_ABORT_IND_EVT:
+ return "BTA_HL_DCH_ABORT_IND_EVT";
+ case BTA_HL_DCH_ABORT_CFM_EVT:
+ return "BTA_HL_DCH_ABORT_CFM_EVT";
+ default:
+ return "Unknown HDP event code";
+ }
+}
+
+
+
+/*******************************************************************************
+**
+** Function bta_hl_dch_oper_code
+**
+** Description Get the DCH operation string
+**
+** Returns char * - DCH operation string pointer
+**
+*******************************************************************************/
+static char *bta_hl_dch_oper_code(tBTA_HL_DCH_OPER oper_code)
+{
+
+ switch (oper_code)
+ {
+ case BTA_HL_DCH_OP_NONE:
+ return "BTA_HL_DCH_OP_NONE";
+ case BTA_HL_DCH_OP_REMOTE_CREATE:
+ return "BTA_HL_DCH_OP_REMOTE_CREATE";
+ case BTA_HL_DCH_OP_LOCAL_OPEN:
+ return "BTA_HL_DCH_OP_LOCAL_OPEN";
+ case BTA_HL_DCH_OP_REMOTE_OPEN:
+ return "BTA_HL_DCH_OP_REMOTE_OPEN";
+ case BTA_HL_DCH_OP_LOCAL_CLOSE:
+ return "BTA_HL_DCH_OP_LOCAL_CLOSE";
+ case BTA_HL_DCH_OP_REMOTE_CLOSE:
+ return "BTA_HL_DCH_OP_REMOTE_CLOSE";
+ case BTA_HL_DCH_OP_LOCAL_DELETE:
+ return "BTA_HL_DCH_OP_LOCAL_DELETE";
+ case BTA_HL_DCH_OP_REMOTE_DELETE:
+ return "BTA_HL_DCH_OP_REMOTE_DELETE";
+ case BTA_HL_DCH_OP_LOCAL_RECONNECT:
+ return "BTA_HL_DCH_OP_LOCAL_RECONNECT";
+ case BTA_HL_DCH_OP_REMOTE_RECONNECT:
+ return "BTA_HL_DCH_OP_REMOTE_RECONNECT";
+ case BTA_HL_DCH_OP_LOCAL_CLOSE_ECHO_TEST:
+ return "BTA_HL_DCH_OP_LOCAL_CLOSE_ECHO_TEST";
+ case BTA_HL_DCH_OP_LOCAL_CLOSE_RECONNECT:
+ return "BTA_HL_DCH_OP_LOCAL_CLOSE_RECONNECT";
+ default:
+ return "Unknown DCH oper code";
+ }
+}
+
+
+#endif /* Debug Functions */
+#endif /* HL_INCLUDED */
diff --git a/bta/hl/bta_hl_api.c b/bta/hl/bta_hl_api.c
new file mode 100644
index 0000000..65ab7bd
--- /dev/null
+++ b/bta/hl/bta_hl_api.c
@@ -0,0 +1,472 @@
+/*****************************************************************************
+**
+** Name: bta_hl_api.c
+**
+** Description: This is the implementation of the API for the HeaLth
+** device profile (HL) subsystem of BTA, Broadcom Corp's Bluetooth
+** application layer for mobile phones.
+**
+** Copyright (c) 2009-2011 Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include <string.h>
+
+#include "bt_target.h"
+#if defined(HL_INCLUDED) && (HL_INCLUDED == TRUE)
+
+#include "gki.h"
+#include "bd.h"
+#include "bta_hl_api.h"
+#include "bta_hl_int.h"
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+static const tBTA_SYS_REG bta_hl_reg =
+{
+ bta_hl_hdl_event,
+ BTA_HlDisable
+};
+
+/*******************************************************************************
+**
+** Function BTA_HlEnable
+**
+** Description Enable the HL subsystems. This function must be
+** called before any other functions in the HL API are called.
+** When the enable operation is completed the callback function
+** will be called with an BTA_HL_CTRL_ENABLE_CFM_EVT event.
+**
+** Parameters p_cback - HL event call back function
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_HlEnable(tBTA_HL_CTRL_CBACK *p_ctrl_cback)
+{
+ tBTA_HL_API_ENABLE *p_buf;
+
+ /* register with BTA system manager */
+ GKI_sched_lock();
+ bta_sys_register(BTA_ID_HL, &bta_hl_reg);
+ GKI_sched_unlock();
+
+ if ((p_buf = (tBTA_HL_API_ENABLE *)GKI_getbuf(sizeof(tBTA_HL_API_ENABLE))) != NULL)
+ {
+ p_buf->hdr.event = BTA_HL_API_ENABLE_EVT;
+ p_buf->p_cback = p_ctrl_cback;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_HlDisable
+**
+** Description Disable the HL subsystem.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_HlDisable(void)
+{
+ BT_HDR *p_buf;
+
+ bta_sys_deregister(BTA_ID_HL);
+ if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->event = BTA_HL_API_DISABLE_EVT;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_HlRegister
+**
+** Description Register an HDP application
+**
+** Parameters app_id - Application ID
+** p_reg_param - non-platform related parameters for the
+** HDP application
+** p_cback - HL event callback fucntion
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_HlRegister(UINT8 app_id,
+ tBTA_HL_REG_PARAM *p_reg_param,
+ tBTA_HL_CBACK *p_cback)
+{
+ tBTA_HL_API_REGISTER *p_buf;
+
+ if ((p_buf = (tBTA_HL_API_REGISTER *)GKI_getbuf((UINT16)sizeof(tBTA_HL_API_REGISTER))) != NULL)
+ {
+ p_buf->hdr.event = BTA_HL_API_REGISTER_EVT;
+ p_buf->app_id = app_id;
+ p_buf->sec_mask = (p_reg_param->sec_mask | BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
+ p_buf->p_cback = p_cback;
+ if (p_reg_param->p_srv_name)
+ {
+ BCM_STRNCPY_S(p_buf->srv_name, sizeof(p_buf->srv_name),
+ p_reg_param->p_srv_name, BTA_SERVICE_NAME_LEN);
+ p_buf->srv_name[BTA_SERVICE_NAME_LEN] = '\0';
+ }
+ else
+ p_buf->srv_name[0]= '\0';
+
+ if (p_reg_param->p_srv_desp)
+ {
+ BCM_STRNCPY_S(p_buf->srv_desp, sizeof(p_buf->srv_desp),
+ p_reg_param->p_srv_desp, BTA_SERVICE_DESP_LEN);
+ p_buf->srv_desp[BTA_SERVICE_DESP_LEN]= '\0';
+ }
+ else
+ p_buf->srv_desp[0]= '\0';
+
+ if (p_reg_param->p_provider_name)
+ {
+ BCM_STRNCPY_S(p_buf->provider_name, sizeof(p_buf->provider_name),
+ p_reg_param->p_provider_name, BTA_PROVIDER_NAME_LEN);
+ p_buf->provider_name[BTA_PROVIDER_NAME_LEN]= '\0';
+ }
+ else
+ p_buf->provider_name[0]= '\0';
+
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_HlDeregister
+**
+** Description Deregister an HDP application
+**
+** Parameters app_handle - Application handle
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_HlDeregister(tBTA_HL_APP_HANDLE app_handle)
+{
+ tBTA_HL_API_DEREGISTER *p_buf;
+
+ if ((p_buf = (tBTA_HL_API_DEREGISTER *)GKI_getbuf((UINT16)(sizeof(tBTA_HL_API_DEREGISTER)))) != NULL)
+ {
+ p_buf->hdr.event = BTA_HL_API_DEREGISTER_EVT;
+ p_buf->app_handle = app_handle;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+/*******************************************************************************
+**
+** Function BTA_HlCchOpen
+**
+** Description Open a Control channel connection with the specified BD address
+**
+** Parameters app_handle - Application Handle
+** p_open_param - parameters for opening a control channel
+**
+** Returns void
+**
+** Note: The control PSM value is used to select which
+** HDP insatnce should be used in case the peer device support
+** multiple HDP instances. Also, if the control PSM value is zero
+** then the first HDP instance is used for the control channel setup
+*******************************************************************************/
+void BTA_HlCchOpen(tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_CCH_OPEN_PARAM *p_open_param)
+{
+ tBTA_HL_API_CCH_OPEN *p_buf;
+
+ if ((p_buf = (tBTA_HL_API_CCH_OPEN *)GKI_getbuf((UINT16)(sizeof(tBTA_HL_API_CCH_OPEN)))) != NULL)
+ {
+ p_buf->hdr.event = BTA_HL_API_CCH_OPEN_EVT;
+ p_buf->app_handle = app_handle;
+ p_buf->sec_mask = (p_open_param->sec_mask | BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
+ bdcpy(p_buf->bd_addr, p_open_param->bd_addr);
+ p_buf->ctrl_psm = p_open_param->ctrl_psm;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_HlCchClose
+**
+** Description Close a Control channel connection with the specified MCL
+** handle
+**
+** Parameters mcl_handle - MCL handle
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_HlCchClose(tBTA_HL_MCL_HANDLE mcl_handle)
+{
+ tBTA_HL_API_CCH_CLOSE *p_buf;
+
+ if ((p_buf = (tBTA_HL_API_CCH_CLOSE *)GKI_getbuf((UINT16)(sizeof(tBTA_HL_API_CCH_CLOSE)))) != NULL)
+ {
+ p_buf->hdr.event = BTA_HL_API_CCH_CLOSE_EVT;
+ p_buf->mcl_handle = mcl_handle;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_HlDchOpen
+**
+** Description Open a data channel connection with the specified DCH parameters
+**
+** Parameters mcl_handle - MCL handle
+** p_open_param - parameters for opening a data channel
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_HlDchOpen(tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_DCH_OPEN_PARAM *p_open_param)
+{
+ tBTA_HL_API_DCH_OPEN *p_buf;
+
+ if ((p_buf = (tBTA_HL_API_DCH_OPEN *)GKI_getbuf((UINT16)(sizeof(tBTA_HL_API_DCH_OPEN)))) != NULL)
+ {
+ p_buf->hdr.event = BTA_HL_API_DCH_OPEN_EVT;
+ p_buf->mcl_handle = mcl_handle;
+ p_buf->ctrl_psm = p_open_param->ctrl_psm;
+ p_buf->local_mdep_id = p_open_param->local_mdep_id;
+ p_buf->peer_mdep_id = p_open_param->peer_mdep_id;
+ p_buf->local_cfg = p_open_param->local_cfg;
+ p_buf->sec_mask = (p_open_param->sec_mask | BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_HlDchReconnect
+**
+** Description Reconnect a data channel with the specified MDL_ID
+**
+** Parameters mcl_handle - MCL handle
+*8 p_recon_param - parameters for reconnecting a data channel
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_HlDchReconnect(tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_DCH_RECONNECT_PARAM *p_recon_param)
+{
+ tBTA_HL_API_DCH_RECONNECT *p_buf;
+
+ if ((p_buf = (tBTA_HL_API_DCH_RECONNECT *)GKI_getbuf((UINT16)(sizeof(tBTA_HL_API_DCH_RECONNECT)))) != NULL)
+ {
+ p_buf->hdr.event = BTA_HL_API_DCH_RECONNECT_EVT;
+ p_buf->mcl_handle = mcl_handle;
+ p_buf->ctrl_psm = p_recon_param->ctrl_psm;
+ p_buf->mdl_id = p_recon_param->mdl_id;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_HlDchClose
+**
+** Description Close a data channel with the specified MDL handle
+**
+** Parameters mdl_handle - MDL handle
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_HlDchClose(tBTA_HL_MDL_HANDLE mdl_handle)
+{
+ tBTA_HL_API_DCH_CLOSE *p_buf;
+
+ if ((p_buf = (tBTA_HL_API_DCH_CLOSE *)GKI_getbuf((UINT16)(sizeof(tBTA_HL_API_DCH_CLOSE)))) != NULL)
+ {
+ p_buf->hdr.event = BTA_HL_API_DCH_CLOSE_EVT;
+ p_buf->mdl_handle = mdl_handle;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_HlDchAbort
+**
+** Description Abort the current data channel setup with the specified MCL
+** handle
+**
+** Parameters mcl_handle - MCL handle
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_HlDchAbort(tBTA_HL_MCL_HANDLE mcl_handle)
+{
+ tBTA_HL_API_DCH_ABORT *p_buf;
+
+ if ((p_buf = (tBTA_HL_API_DCH_ABORT *)GKI_getbuf((UINT16)(sizeof(tBTA_HL_API_DCH_ABORT)))) != NULL)
+ {
+ p_buf->hdr.event = BTA_HL_API_DCH_ABORT_EVT;
+ p_buf->mcl_handle = mcl_handle;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_HlSendData
+**
+** Description Send an APDU to the peer device
+**
+** Parameters mdl_handle - MDL handle
+** pkt_size - size of the data packet to be sent
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_HlSendData(tBTA_HL_MDL_HANDLE mdl_handle,
+ UINT16 pkt_size)
+{
+ tBTA_HL_API_SEND_DATA *p_buf = NULL;
+
+ if ((p_buf = (tBTA_HL_API_SEND_DATA *)GKI_getbuf((UINT16)(sizeof(tBTA_HL_API_SEND_DATA)))) != NULL)
+ {
+ p_buf->hdr.event = BTA_HL_API_SEND_DATA_EVT;
+ p_buf->mdl_handle = mdl_handle;
+ p_buf->pkt_size = pkt_size;
+ bta_sys_sendmsg(p_buf);
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function BTA_HlDeleteMdl
+**
+** Description Delete the specified MDL_ID within the specified MCL handle
+**
+** Parameters mcl_handle - MCL handle
+** mdl_id - MDL ID
+**
+** Returns void
+**
+** note: If mdl_id = 0xFFFF then this means to delete all MDLs
+** and this value can only be used with DeleteMdl request only
+** not other requests
+**
+*******************************************************************************/
+void BTA_HlDeleteMdl(tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_MDL_ID mdl_id )
+{
+ tBTA_HL_API_DELETE_MDL *p_buf;
+
+ if ((p_buf = (tBTA_HL_API_DELETE_MDL *)GKI_getbuf((UINT16)(sizeof(tBTA_HL_API_DELETE_MDL)))) != NULL)
+ {
+ p_buf->hdr.event = BTA_HL_API_DELETE_MDL_EVT;
+ p_buf->mcl_handle = mcl_handle;
+ p_buf->mdl_id = mdl_id;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_HlDchEchoTest
+**
+** Description Initiate an echo test with the specified MCL handle
+**
+** Parameters mcl_handle - MCL handle
+*8 p_echo_test_param - parameters for echo testing
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_HlDchEchoTest( tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_DCH_ECHO_TEST_PARAM *p_echo_test_param)
+{
+ tBTA_HL_API_DCH_ECHO_TEST *p_buf;
+
+ if ((p_buf = (tBTA_HL_API_DCH_ECHO_TEST *)GKI_getbuf((UINT16)(sizeof(tBTA_HL_API_DCH_ECHO_TEST)))) != NULL)
+ {
+ p_buf->hdr.event = BTA_HL_API_DCH_ECHO_TEST_EVT;
+ p_buf->mcl_handle = mcl_handle;
+ p_buf->ctrl_psm = p_echo_test_param->ctrl_psm;
+ p_buf->local_cfg = p_echo_test_param->local_cfg;
+ p_buf->pkt_size = p_echo_test_param->pkt_size;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function BTA_HlSdpQuery
+**
+** Description SDP query request for the specified BD address
+**
+** Parameters app_handle - application handle
+** bd_addr - BD address
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_HlSdpQuery(tBTA_HL_APP_HANDLE app_handle,
+ BD_ADDR bd_addr)
+{
+ tBTA_HL_API_SDP_QUERY *p_buf;
+
+ if ((p_buf = (tBTA_HL_API_SDP_QUERY *)GKI_getbuf((UINT16)(sizeof(tBTA_HL_API_SDP_QUERY)))) != NULL)
+ {
+ p_buf->hdr.event = BTA_HL_API_SDP_QUERY_EVT;
+ p_buf->app_handle = app_handle;
+ bdcpy(p_buf->bd_addr, bd_addr);
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function BTA_HlDchCreateMdlRsp
+**
+** Description Set the Response and configuration values for the Create MDL
+** request
+**
+** Parameters mcl_handle - MCL handle
+** p_rsp_param - parameters specified whether the request should
+** be accepted or not and if it should be accepted
+** then it also specified the configuration response
+** value
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_HlDchCreateRsp(tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_DCH_CREATE_RSP_PARAM *p_rsp_param)
+{
+ tBTA_HL_API_DCH_CREATE_RSP *p_buf;
+
+ if ((p_buf = (tBTA_HL_API_DCH_CREATE_RSP *)GKI_getbuf((UINT16)(sizeof(tBTA_HL_API_DCH_CREATE_RSP)))) != NULL)
+ {
+ p_buf->hdr.event = BTA_HL_API_DCH_CREATE_RSP_EVT;
+ p_buf->mcl_handle = mcl_handle;
+ p_buf->mdl_id = p_rsp_param->mdl_id;
+ p_buf->local_mdep_id = p_rsp_param->local_mdep_id;
+ p_buf->rsp_code = p_rsp_param->rsp_code;
+ p_buf->cfg_rsp = p_rsp_param->cfg_rsp;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+#endif /* HL_INCLUDED */
diff --git a/bta/hl/bta_hl_ci.c b/bta/hl/bta_hl_ci.c
new file mode 100644
index 0000000..aab858f
--- /dev/null
+++ b/bta/hl/bta_hl_ci.c
@@ -0,0 +1,158 @@
+/*****************************************************************************
+**
+** Name: bta_hl_ci.c
+**
+** Description: This is the implementation file for the HeaLth device profile
+** (HL) subsystem call-in functions.
+**
+** Copyright (c) 2009, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include "bta_api.h"
+#include "btm_api.h"
+#include "bta_sys.h"
+#include "bta_hl_api.h"
+#include "bta_hl_co.h"
+#include "bta_hl_int.h"
+
+/*******************************************************************************
+**
+** Function bta_hl_ci_get_tx_data
+**
+** Description This function is called in response to the
+** bta_hl_co_get_tx_data call-out function.
+**
+** Parameters mdl_handle -MDL handle
+** status - BTA_MA_STATUS_OK if operation is successful
+** BTA_MA_STATUS_FAIL if any errors have occurred.
+** evt - evt from the call-out function
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_hl_ci_get_tx_data( tBTA_HL_MDL_HANDLE mdl_handle,
+ tBTA_HL_STATUS status,
+ UINT16 evt )
+{
+ tBTA_HL_CI_GET_PUT_DATA *p_evt;
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG3("bta_hl_ci_get_tx_data mdl_handle=%d status=%d evt=%d\n",
+ mdl_handle, status, evt);
+#endif
+
+ if ((p_evt = (tBTA_HL_CI_GET_PUT_DATA *)GKI_getbuf(sizeof(tBTA_HL_CI_GET_PUT_DATA))) != NULL)
+ {
+ p_evt->hdr.event = evt;
+ p_evt->mdl_handle = mdl_handle;
+ p_evt->status = status;
+ bta_sys_sendmsg(p_evt);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_ci_put_rx_data
+**
+** Description This function is called in response to the
+** bta_hl_co_put_rx_data call-out function.
+**
+** Parameters mdl_handle -MDL handle
+** status - BTA_MA_STATUS_OK if operation is successful
+** BTA_MA_STATUS_FAIL if any errors have occurred.
+** evt - evt from the call-out function
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_hl_ci_put_rx_data( tBTA_HL_MDL_HANDLE mdl_handle,
+ tBTA_HL_STATUS status,
+ UINT16 evt )
+{
+ tBTA_HL_CI_GET_PUT_DATA *p_evt;
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG3("bta_hl_ci_put_rx_data mdl_handle=%d status=%d evt=%d\n",
+ mdl_handle, status, evt);
+#endif
+
+ if ((p_evt = (tBTA_HL_CI_GET_PUT_DATA *)GKI_getbuf(sizeof(tBTA_HL_CI_GET_PUT_DATA))) != NULL)
+ {
+ p_evt->hdr.event = evt;
+ p_evt->mdl_handle = mdl_handle;
+ p_evt->status = status;
+ bta_sys_sendmsg(p_evt);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function bta_hl_ci_get_echo_data
+**
+** Description This function is called in response to the
+** bta_hl_co_get_echo_data call-out function.
+**
+** Parameters mcl_handle -MCL handle
+** status - BTA_MA_STATUS_OK if operation is successful
+** BTA_MA_STATUS_FAIL if any errors have occurred.
+** evt - evt from the call-out function
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_hl_ci_get_echo_data( tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_STATUS status,
+ UINT16 evt )
+{
+ tBTA_HL_CI_ECHO_DATA *p_evt;
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG3("bta_hl_ci_get_echo_data mcl_handle=%d status=%d evt=%d\n",
+ mcl_handle, status, evt);
+#endif
+
+ if ((p_evt = (tBTA_HL_CI_ECHO_DATA *)GKI_getbuf(sizeof(tBTA_HL_CI_ECHO_DATA))) != NULL)
+ {
+ p_evt->hdr.event = evt;
+ p_evt->mcl_handle = mcl_handle;
+ p_evt->status = status;
+ bta_sys_sendmsg(p_evt);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_ci_put_echo_data
+**
+** Description This function is called in response to the
+** bta_hl_co_put_echo_data call-out function.
+**
+** Parameters mcl_handle -MCL handle
+** status - BTA_MA_STATUS_OK if operation is successful
+** BTA_MA_STATUS_FAIL if any errors have occurred.
+** evt - evt from the call-out function
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_hl_ci_put_echo_data( tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_STATUS status,
+ UINT16 evt )
+{
+ tBTA_HL_CI_ECHO_DATA *p_evt;
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG3("bta_hl_ci_put_echo_data mcl_handle=%d status=%d evt=%d\n",
+ mcl_handle, status, evt);
+#endif
+
+ if ((p_evt = (tBTA_HL_CI_ECHO_DATA *)GKI_getbuf(sizeof(tBTA_HL_CI_ECHO_DATA))) != NULL)
+ {
+ p_evt->hdr.event = evt;
+ p_evt->mcl_handle = mcl_handle;
+ p_evt->status = status;
+ bta_sys_sendmsg(p_evt);
+ }
+}
+
diff --git a/bta/hl/bta_hl_int.h b/bta/hl/bta_hl_int.h
new file mode 100644
index 0000000..03805d4
--- /dev/null
+++ b/bta/hl/bta_hl_int.h
@@ -0,0 +1,845 @@
+/*****************************************************************************
+**
+** Name: bta_hl_int.h
+**
+** Description: This is the private file for the message access
+** equipment (MSE) subsystem.
+**
+** Copyright (c) 1998-2009, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_HL_INT_H
+#define BTA_HL_INT_H
+
+#include "bt_target.h"
+#include "bta_sys.h"
+#include "obx_api.h"
+#include "bta_hl_api.h"
+#include "bta_hl_co.h"
+#include "l2cdefs.h"
+
+
+typedef UINT16 (tBTA_HL_ALLOCATE_PSM) (void);
+
+/*****************************************************************************
+** Constants and data types
+*****************************************************************************/
+
+#ifndef BTA_HL_DISC_SIZE
+#define BTA_HL_DISC_SIZE 1600
+#endif
+#define BTA_HL_NUM_SRCH_ATTR 10
+#define BTA_HL_MIN_SDP_MDEP_LEN 7
+
+/* L2CAP defualt parameters */
+#define BTA_HL_L2C_TX_WIN_SIZE 10
+#define BTA_HL_L2C_MAX_TRANSMIT 32
+#define BTA_HL_L2C_RTRANS_TOUT 2000
+#define BTA_HL_L2C_MON_TOUT 12000
+#define BTA_HL_L2C_MPS 1017
+#define BTA_HL_L2C_USER_RX_POOL_ID L2CAP_DEFAULT_ERM_POOL_ID
+#define BTA_HL_L2C_USER_TX_POOL_ID L2CAP_DEFAULT_ERM_POOL_ID /* todo this should be based on data type */
+#define BTA_HL_L2C_FCR_RX_POOL_ID L2CAP_DEFAULT_ERM_POOL_ID
+#define BTA_HL_L2C_FCR_TX_POOL_ID L2CAP_DEFAULT_ERM_POOL_ID
+
+/* L2CAP FCS setting*/
+#define BTA_HL_MCA_USE_FCS MCA_FCS_USE
+#define BTA_HL_MCA_NO_FCS MCA_FCS_BYPASS
+#define BTA_HL_L2C_USE_FCS 1
+#define BTA_HL_L2C_NO_FCS 0
+#define BTA_HL_DEFAULT_SOURCE_FCS BTA_HL_L2C_USE_FCS
+
+/* SDP Operations */
+#define BTA_HL_SDP_OP_NONE 0
+#define BTA_HL_SDP_OP_CCH_INIT 1
+#define BTA_HL_SDP_OP_DCH_OPEN_INIT 2
+#define BTA_HL_SDP_OP_DCH_RECONNECT_INIT 3
+#define BTA_HL_SDP_OP_SDP_QUERY_NEW 4
+#define BTA_HL_SDP_OP_SDP_QUERY_CURRENT 5
+
+typedef UINT8 tBTA_HL_SDP_OPER;
+
+/* CCH Operations */
+#define BTA_HL_CCH_OP_NONE 0
+#define BTA_HL_CCH_OP_LOCAL_OPEN 1
+#define BTA_HL_CCH_OP_REMOTE_OPEN 2
+#define BTA_HL_CCH_OP_LOCAL_CLOSE 3
+#define BTA_HL_CCH_OP_REMOTE_CLOSE 4
+
+typedef UINT8 tBTA_HL_CCH_OPER;
+
+/* Pending DCH close operations when closing a CCH */
+#define BTA_HL_CCH_CLOSE_OP_DCH_NONE 0
+#define BTA_HL_CCH_CLOSE_OP_DCH_ABORT 1
+#define BTA_HL_CCH_CLOSE_OP_DCH_CLOSE 2
+typedef UINT8 tBTA_HL_CCH_CLOSE_DCH_OPER;
+
+/* DCH Operations */
+#define BTA_HL_DCH_OP_NONE 0
+#define BTA_HL_DCH_OP_REMOTE_CREATE 1
+#define BTA_HL_DCH_OP_LOCAL_OPEN 2
+#define BTA_HL_DCH_OP_REMOTE_OPEN 3
+#define BTA_HL_DCH_OP_LOCAL_CLOSE 4
+#define BTA_HL_DCH_OP_REMOTE_CLOSE 5
+#define BTA_HL_DCH_OP_LOCAL_DELETE 6
+#define BTA_HL_DCH_OP_REMOTE_DELETE 7
+#define BTA_HL_DCH_OP_LOCAL_RECONNECT 8
+#define BTA_HL_DCH_OP_REMOTE_RECONNECT 9
+#define BTA_HL_DCH_OP_LOCAL_CLOSE_ECHO_TEST 10
+#define BTA_HL_DCH_OP_LOCAL_CLOSE_RECONNECT 11
+
+typedef UINT8 tBTA_HL_DCH_OPER;
+
+/* Echo test Operations */
+#define BTA_HL_ECHO_OP_NONE 0
+#define BTA_HL_ECHO_OP_CI_GET_ECHO_DATA 1
+#define BTA_HL_ECHO_OP_SDP_INIT 2
+#define BTA_HL_ECHO_OP_MDL_CREATE_CFM 3
+#define BTA_HL_ECHO_OP_DCH_OPEN_CFM 4
+#define BTA_HL_ECHO_OP_LOOP_BACK 5
+#define BTA_HL_ECHO_OP_CI_PUT_ECHO_DATA 6
+#define BTA_HL_ECHO_OP_DCH_CLOSE_CFM 7
+#define BTA_HL_ECHO_OP_OPEN_IND 8
+#define BTA_HL_ECHO_OP_ECHO_PKT 9
+
+typedef UINT8 tBTA_HL_ECHO_OPER;
+
+/* abort status mask for abort_oper */
+
+#define BTA_HL_ABORT_NONE_MASK 0x00
+#define BTA_HL_ABORT_PENDING_MASK 0x01
+#define BTA_HL_ABORT_LOCAL_MASK 0x10
+#define BTA_HL_ABORT_REMOTE_MASK 0x20
+#define BTA_HL_ABORT_CCH_CLOSE_MASK 0x40
+
+/* call out mask for cout_oper */
+#define BTA_HL_CO_NONE_MASK 0x00
+#define BTA_HL_CO_GET_TX_DATA_MASK 0x01
+#define BTA_HL_CO_PUT_RX_DATA_MASK 0x02
+#define BTA_HL_CO_GET_ECHO_DATA_MASK 0x04
+#define BTA_HL_CO_PUT_ECHO_DATA_MASK 0x08
+
+typedef struct
+{
+ UINT16 mtu;
+ UINT8 fcs; /* '0' No FCS, otherwise '1' */
+} tBTA_HL_L2CAP_CFG_INFO;
+
+
+/* State Machine Events */
+enum
+{
+ /* these events are handled by the state machine */
+ BTA_HL_CCH_OPEN_EVT = BTA_SYS_EVT_START(BTA_ID_HL),
+ BTA_HL_CCH_SDP_OK_EVT,
+ BTA_HL_CCH_SDP_FAIL_EVT,
+ BTA_HL_MCA_CONNECT_IND_EVT,
+ BTA_HL_MCA_DISCONNECT_IND_EVT,
+ BTA_HL_CCH_CLOSE_EVT,
+ BTA_HL_CCH_CLOSE_CMPL_EVT,
+ BTA_HL_MCA_RSP_TOUT_IND_EVT,
+ /* DCH EVENT */
+ BTA_HL_DCH_SDP_INIT_EVT,
+ BTA_HL_DCH_OPEN_EVT,
+ BTA_HL_MCA_CREATE_IND_EVT,
+ BTA_HL_MCA_CREATE_CFM_EVT,
+ BTA_HL_MCA_OPEN_IND_EVT,
+
+ BTA_HL_MCA_OPEN_CFM_EVT,
+ BTA_HL_DCH_CLOSE_EVT,
+ BTA_HL_MCA_CLOSE_IND_EVT,
+ BTA_HL_MCA_CLOSE_CFM_EVT,
+ BTA_HL_API_SEND_DATA_EVT,
+
+ BTA_HL_MCA_RCV_DATA_EVT,
+ BTA_HL_DCH_CLOSE_CMPL_EVT,
+ BTA_HL_DCH_RECONNECT_EVT,
+ BTA_HL_DCH_SDP_FAIL_EVT,
+ BTA_HL_MCA_RECONNECT_IND_EVT,
+
+ BTA_HL_MCA_RECONNECT_CFM_EVT,
+ BTA_HL_DCH_CLOSE_ECHO_TEST_EVT,
+ BTA_HL_API_DCH_CREATE_RSP_EVT,
+ BTA_HL_DCH_ABORT_EVT,
+ BTA_HL_MCA_ABORT_IND_EVT,
+
+ BTA_HL_MCA_ABORT_CFM_EVT,
+ BTA_HL_MCA_CONG_CHG_EVT,
+ BTA_HL_CI_GET_TX_DATA_EVT,
+ BTA_HL_CI_PUT_RX_DATA_EVT,
+ BTA_HL_CI_GET_ECHO_DATA_EVT,
+ BTA_HL_DCH_ECHO_TEST_EVT,
+ BTA_HL_CI_PUT_ECHO_DATA_EVT,
+
+ /* these events are handled outside the state machine */
+ BTA_HL_API_ENABLE_EVT,
+ BTA_HL_API_DISABLE_EVT,
+ BTA_HL_API_REGISTER_EVT,
+ BTA_HL_API_DEREGISTER_EVT,
+ BTA_HL_API_CCH_OPEN_EVT,
+ BTA_HL_API_CCH_CLOSE_EVT,
+ BTA_HL_API_DCH_OPEN_EVT,
+ BTA_HL_API_DCH_RECONNECT_EVT,
+ BTA_HL_API_DCH_CLOSE_EVT,
+ BTA_HL_API_DELETE_MDL_EVT,
+ BTA_HL_API_DCH_ABORT_EVT,
+
+ BTA_HL_API_DCH_ECHO_TEST_EVT,
+ BTA_HL_API_SDP_QUERY_EVT,
+ BTA_HL_SDP_QUERY_OK_EVT,
+ BTA_HL_SDP_QUERY_FAIL_EVT,
+ BTA_HL_MCA_DELETE_IND_EVT,
+ BTA_HL_MCA_DELETE_CFM_EVT
+};
+typedef UINT16 tBTA_HL_INT_EVT;
+
+#define BTA_HL_DCH_EVT_MIN BTA_HL_DCH_SDP_INIT_EVT
+#define BTA_HL_DCH_EVT_MAX 0xFFFF
+
+
+/* state machine states */
+enum
+{
+ BTA_HL_CCH_IDLE_ST = 0, /* Idle */
+ BTA_HL_CCH_OPENING_ST, /* Opening a connection*/
+ BTA_HL_CCH_OPEN_ST, /* Connection is open */
+ BTA_HL_CCH_CLOSING_ST /* Closing is in progress */
+};
+typedef UINT8 tBTA_HL_CCH_STATE;
+
+enum
+{
+ BTA_HL_DCH_IDLE_ST = 0, /* Idle */
+ BTA_HL_DCH_OPENING_ST, /* Opening a connection*/
+ BTA_HL_DCH_OPEN_ST, /* Connection is open */
+ BTA_HL_DCH_CLOSING_ST /* Closing is in progress */
+};
+typedef UINT8 tBTA_HL_DCH_STATE;
+
+
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_HL_CTRL_CBACK *p_cback; /* pointer to control callback function */
+} tBTA_HL_API_ENABLE;
+
+typedef struct
+{
+ BT_HDR hdr;
+ UINT8 app_id;
+ tBTA_HL_CBACK *p_cback; /* pointer to application callback function */
+ tBTA_HL_DEVICE_TYPE dev_type; /* sink, source or dual roles */
+ tBTA_SEC sec_mask; /* security mask for accepting conenction*/
+ char srv_name[BTA_SERVICE_NAME_LEN +1]; /* service name to be used in the SDP; null terminated*/
+ char srv_desp[BTA_SERVICE_DESP_LEN +1]; /* service description to be used in the SDP; null terminated */
+ char provider_name[BTA_PROVIDER_NAME_LEN +1]; /* provide name to be used in the SDP; null terminated */
+} tBTA_HL_API_REGISTER;
+
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_HL_APP_HANDLE app_handle;
+} tBTA_HL_API_DEREGISTER;
+
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_HL_APP_HANDLE app_handle;
+ UINT16 ctrl_psm;
+ BD_ADDR bd_addr; /* Address of peer device */
+ tBTA_SEC sec_mask; /* security mask for initiating connection*/
+} tBTA_HL_API_CCH_OPEN;
+
+
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_HL_MCL_HANDLE mcl_handle;
+} tBTA_HL_API_CCH_CLOSE;
+
+
+
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_HL_MCL_HANDLE mcl_handle;
+ UINT16 ctrl_psm;
+ tBTA_HL_MDEP_ID local_mdep_id; /* local MDEP ID */
+ tBTA_HL_MDEP_ID peer_mdep_id; /* peer mdep id */
+ tBTA_HL_DCH_CFG local_cfg;
+ tBTA_SEC sec_mask; /* security mask for initiating connection*/
+} tBTA_HL_API_DCH_OPEN;
+
+
+typedef struct
+{
+ BT_HDR hdr;
+
+ tBTA_HL_MCL_HANDLE mcl_handle;
+ UINT16 ctrl_psm;
+ tBTA_HL_MDL_ID mdl_id;
+} tBTA_HL_API_DCH_RECONNECT;
+
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_HL_MDL_HANDLE mdl_handle;
+} tBTA_HL_API_DCH_CLOSE;
+
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_HL_MCL_HANDLE mcl_handle;
+ tBTA_HL_MDL_ID mdl_id;
+} tBTA_HL_API_DELETE_MDL;
+
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_HL_MCL_HANDLE mcl_handle;
+} tBTA_HL_API_DCH_ABORT;
+
+
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_HL_MDL_HANDLE mdl_handle;
+ UINT16 pkt_size;
+} tBTA_HL_API_SEND_DATA;
+
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_HL_MCL_HANDLE mcl_handle;
+ UINT16 ctrl_psm;
+ UINT16 pkt_size;
+ tBTA_HL_DCH_CFG local_cfg;
+} tBTA_HL_API_DCH_ECHO_TEST;
+
+typedef struct
+{
+ BT_HDR hdr;
+ UINT8 app_idx;
+ UINT8 mcl_idx;
+ BOOLEAN release_mcl_cb;
+}tBTA_HL_CCH_SDP;
+
+
+/* MCA callback event parameters. */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_HL_APP_HANDLE app_handle;
+ tBTA_HL_MCL_HANDLE mcl_handle;
+ tMCA_CTRL mca_data;
+} tBTA_HL_MCA_EVT;
+
+
+/* MCA callback event parameters. */
+typedef struct
+{
+ BT_HDR hdr;
+ UINT8 app_idx;
+ UINT8 mcl_idx;
+ UINT8 mdl_idx;
+ BT_HDR *p_pkt;
+} tBTA_HL_MCA_RCV_DATA_EVT;
+
+
+typedef struct
+{
+ BT_HDR hdr;
+ UINT8 app_idx;
+ UINT8 mcl_idx;
+ UINT8 mdl_idx;
+}tBTA_HL_DCH_SDP;
+
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_HL_APP_HANDLE app_handle;
+ BD_ADDR bd_addr; /* Address of peer device */
+} tBTA_HL_API_SDP_QUERY;
+
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_HL_MCL_HANDLE mcl_handle;
+ tBTA_HL_MDL_ID mdl_id;
+ tBTA_HL_MDEP_ID local_mdep_id;
+ tBTA_HL_DCH_CREATE_RSP rsp_code;
+ tBTA_HL_DCH_CFG cfg_rsp;
+} tBTA_HL_API_DCH_CREATE_RSP;
+
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_HL_MDL_HANDLE mdl_handle;
+ tBTA_HL_STATUS status;
+} tBTA_HL_CI_GET_PUT_DATA;
+
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_HL_MCL_HANDLE mcl_handle;
+ tBTA_HL_STATUS status;
+} tBTA_HL_CI_ECHO_DATA;
+
+/* union of all state machine event data types */
+typedef union
+{
+ BT_HDR hdr;
+ tBTA_HL_API_ENABLE api_enable; /* data for BTA_MSE_API_ENABLE_EVT */
+ tBTA_HL_API_REGISTER api_reg;
+ tBTA_HL_API_DEREGISTER api_dereg;
+ tBTA_HL_API_CCH_OPEN api_cch_open;
+ tBTA_HL_API_CCH_CLOSE api_cch_close;
+ tBTA_HL_API_DCH_CREATE_RSP api_dch_create_rsp;
+ tBTA_HL_API_DCH_OPEN api_dch_open;
+ tBTA_HL_API_DCH_RECONNECT api_dch_reconnect;
+ tBTA_HL_API_DCH_CLOSE api_dch_close;
+ tBTA_HL_API_DELETE_MDL api_delete_mdl;
+ tBTA_HL_API_DCH_ABORT api_dch_abort;
+ tBTA_HL_API_SEND_DATA api_send_data;
+ tBTA_HL_API_DCH_ECHO_TEST api_dch_echo_test;
+ tBTA_HL_API_SDP_QUERY api_sdp_query;
+
+ tBTA_HL_CCH_SDP cch_sdp;
+ tBTA_HL_MCA_EVT mca_evt;
+ tBTA_HL_MCA_RCV_DATA_EVT mca_rcv_data_evt;
+ tBTA_HL_DCH_SDP dch_sdp; /* for DCH_OPEN_EVT and DCH_RECONNECT_EVT */
+ tBTA_HL_CI_GET_PUT_DATA ci_get_put_data;
+ tBTA_HL_CI_ECHO_DATA ci_get_put_echo_data;
+} tBTA_HL_DATA;
+
+
+typedef struct
+{
+ BOOLEAN in_use;
+ UINT16 mdl_id;
+ tBTA_HL_MDL_HANDLE mdl_handle;
+ tBTA_HL_DCH_OPER dch_oper;
+ BOOLEAN intentional_close;
+ tBTA_HL_DCH_STATE dch_state;
+ UINT8 abort_oper;
+ UINT16 req_data_psm;
+ UINT16 max_rx_apdu_size;
+ UINT16 max_tx_apdu_size;
+ BT_HDR *p_tx_pkt;
+ BT_HDR *p_rx_pkt;
+ tBTA_HL_MDEP_ID local_mdep_id;
+ UINT8 local_mdep_cfg_idx;
+ tBTA_HL_DCH_CFG local_cfg;
+ tBTA_HL_DCH_CFG remote_cfg;
+ tBTA_HL_MDEP_ID peer_mdep_id;
+ UINT16 peer_data_type;
+ tBTA_HL_MDEP_ROLE peer_mdep_role;
+ tBTA_HL_DCH_MODE dch_mode;
+ tBTA_SEC sec_mask;
+ BOOLEAN is_the_first_reliable;
+ BOOLEAN delete_mdl;
+ UINT16 mtu;
+ tMCA_CHNL_CFG chnl_cfg;
+ BOOLEAN mdl_cfg_idx_included;
+ UINT8 mdl_cfg_idx;
+ UINT8 echo_oper;
+ BOOLEAN cong;
+ BOOLEAN close_pending;
+ UINT8 cout_oper;
+ BT_HDR *p_echo_tx_pkt;
+ BT_HDR *p_echo_rx_pkt;
+ tBTA_HL_STATUS ci_put_echo_data_status;
+}tBTA_HL_MDL_CB;
+
+typedef struct
+{
+ tBTA_HL_MDL_CB mdl[BTA_HL_NUM_MDLS_PER_MCL];
+ tBTA_HL_DELETE_MDL delete_mdl;
+ BOOLEAN in_use;
+ tBTA_HL_CCH_STATE cch_state;
+ UINT16 req_ctrl_psm;
+ UINT16 ctrl_psm;
+ UINT16 data_psm;
+ BD_ADDR bd_addr;
+ UINT16 cch_mtu;
+ UINT16 sec_mask;
+ tBTA_HL_MCL_HANDLE mcl_handle;
+ tSDP_DISCOVERY_DB *p_db; /* pointer to discovery database */
+ tSDP_DISC_CMPL_CB *sdp_cback;
+ tBTA_HL_SDP_OPER sdp_oper;
+ BOOLEAN close_pending;
+ UINT8 sdp_mdl_idx;
+ tBTA_HL_SDP sdp;
+ UINT8 cch_oper;
+ BOOLEAN intentional_close;
+ BOOLEAN rsp_tout;
+ UINT8 timer_oper;
+ BOOLEAN echo_test;
+ UINT8 echo_mdl_idx;
+ UINT8 cch_close_dch_oper;
+}tBTA_HL_MCL_CB;
+
+typedef struct
+{
+ tBTA_HL_MCL_CB mcb[BTA_HL_NUM_MCLS]; /* application Control Blocks */
+ tBTA_HL_CBACK *p_cback; /* pointer to control callback function */
+ BOOLEAN in_use; /* this CB is in use*/
+ BOOLEAN deregistering;
+ UINT8 app_id;
+ UINT32 sdp_handle; /* SDP record handle */
+ tBTA_HL_SUP_FEATURE sup_feature;
+ tBTA_HL_MDL_CFG mdl_cfg[BTA_HL_NUM_MDL_CFGS];
+ tBTA_HL_DEVICE_TYPE dev_type;
+ tBTA_HL_APP_HANDLE app_handle;
+ UINT16 ctrl_psm; /* L2CAP PSM for the MCAP control channel */
+ UINT16 data_psm; /* L2CAP PSM for the MCAP data channel */
+ UINT16 sec_mask; /* Security mask for BTM_SetSecurityLevel() */
+
+ char srv_name[BTA_SERVICE_NAME_LEN +1]; /* service name to be used in the SDP; null terminated*/
+ char srv_desp[BTA_SERVICE_DESP_LEN +1]; /* service description to be used in the SDP; null terminated */
+ char provider_name[BTA_PROVIDER_NAME_LEN +1]; /* provide name to be used in the SDP; null terminated */
+
+ tMCA_CTRL_CBACK *p_mcap_cback; /* pointer to MCAP callback function */
+ tMCA_DATA_CBACK *p_data_cback;
+}tBTA_HL_APP_CB;
+
+
+typedef struct
+{
+ BOOLEAN in_use;
+ tBTA_HL_SDP_OPER sdp_oper;
+ UINT8 app_idx;
+ UINT8 mcl_idx;
+ UINT8 mdl_idx;
+}tBTA_HL_SDP_CB;
+
+typedef struct
+{
+ BOOLEAN in_use;
+ UINT8 app_idx;
+ UINT8 mcl_idx;
+}tBTA_HL_TIMER_CB;
+
+typedef struct
+{
+ tBTA_HL_APP_CB acb[BTA_HL_NUM_APPS]; /* HL Control Blocks */
+ tBTA_HL_CTRL_CBACK *p_ctrl_cback; /* pointer to control callback function */
+ BOOLEAN enable;
+ BOOLEAN disabling;
+
+ tBTA_HL_SDP_CB scb[BTA_HL_NUM_SDP_CBACKS];
+ tBTA_HL_TIMER_CB tcb[BTA_HL_NUM_TIMERS];
+ BOOLEAN enable_random_psm;
+ tBTA_HL_ALLOCATE_PSM *p_alloc_psm;
+}tBTA_HL_CB;
+
+/******************************************************************************
+** Configuration Definitions
+*******************************************************************************/
+/* Configuration structure */
+
+/*****************************************************************************
+** Global data
+*****************************************************************************/
+
+/* HL control block */
+#if BTA_DYNAMIC_MEMORY == FALSE
+extern tBTA_HL_CB bta_hl_cb;
+#else
+extern tBTA_HL_CB *bta_hl_cb_ptr;
+ #define bta_hl_cb (*bta_hl_cb_ptr)
+#endif
+
+#define BTA_HL_GET_CB_PTR() &(bta_hl_cb)
+#define BTA_HL_GET_APP_CB_PTR(app_idx) &(bta_hl_cb.acb[(app_idx)])
+#define BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx) &(bta_hl_cb.acb[(app_idx)].mcb[(mcl_idx)])
+#define BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx) &(bta_hl_cb.acb[(app_idx)].mcb[(mcl_idx)].mdl[mdl_idx])
+#define BTA_HL_GET_MDL_CFG_PTR(app_idx, item_idx) &(bta_hl_cb.acb[(app_idx)].mdl_cfg[(item_idx)])
+#define BTA_HL_GET_ECHO_CFG_PTR(app_idx) &(bta_hl_cb.acb[(app_idx)].sup_feature.echo_cfg)
+#define BTA_HL_GET_MDEP_CFG_PTR(app_idx, mdep_cfg_idx) &(bta_hl_cb.acb[(app_idx)].sup_feature.mdep[mdep_cfg_idx].mdep_cfg)
+#define BTA_HL_GET_DATA_CFG_PTR(app_idx, mdep_cfg_idx, data_cfg_idx) \
+ &(bta_hl_cb.acb[(app_idx)].sup_feature.mdep[mdep_cfg_idx].mdep_cfg.data_cfg[data_cfg_idx])
+#define BTA_HL_GET_BUF_PTR(p_pkt) ((UINT8 *)((UINT8 *) (p_pkt+1) + p_pkt->offset))
+
+/*****************************************************************************
+** Function prototypes
+*****************************************************************************/
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+ /* main */
+ extern BOOLEAN bta_hl_hdl_event(BT_HDR *p_msg);
+ /* sdp */
+ extern BOOLEAN bta_hl_fill_sup_feature_list( const tSDP_DISC_ATTR *p_attr,
+ tBTA_HL_SUP_FEATURE_LIST_ELEM *p_list);
+
+ extern tBTA_HL_STATUS bta_hl_sdp_register (UINT8 app_idx);
+ extern tSDP_DISC_REC *bta_hl_find_sink_or_src_srv_class_in_db (const tSDP_DISCOVERY_DB *p_db,
+ const tSDP_DISC_REC *p_start_rec);
+
+ /* action routines */
+ extern void bta_hl_dch_ci_get_tx_data(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data);
+ extern void bta_hl_dch_ci_put_rx_data(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data);
+ extern void bta_hl_dch_ci_get_echo_data(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data);
+
+ extern void bta_hl_dch_echo_test(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data);
+ extern void bta_hl_dch_ci_put_echo_data(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data);
+ extern void bta_hl_dch_send_data(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data);
+ extern void bta_hl_dch_sdp_fail(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data);
+ extern void bta_hl_dch_mca_cong_change(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data);
+ extern void bta_hl_dch_mca_reconnect_ind(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data);
+ extern void bta_hl_dch_mca_reconnect_cfm(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data);
+ extern void bta_hl_dch_mca_reconnect(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data);
+ extern void bta_hl_dch_sdp_init(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data);
+ extern void bta_hl_dch_close_echo_test(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data);
+ extern void bta_hl_dch_create_rsp(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data);
+ extern void bta_hl_dch_mca_rcv_data(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data);
+ extern void bta_hl_dch_close_cmpl(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data);
+ extern void bta_hl_dch_mca_close_cfm(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data);
+ extern void bta_hl_dch_mca_close_ind(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data);
+ extern void bta_hl_dch_mca_close(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data);
+ extern void bta_hl_dch_mca_delete_ind(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data);
+
+ extern void bta_hl_dch_mca_delete_cfm(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data);
+ extern void bta_hl_dch_mca_delete(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data);
+ extern void bta_hl_dch_mca_abort_ind(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data);
+ extern void bta_hl_dch_mca_abort_cfm(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data);
+ extern void bta_hl_dch_mca_abort(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data);
+ extern void bta_hl_dch_mca_open_ind(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data);
+ extern void bta_hl_dch_mca_open_cfm(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data);
+ extern void bta_hl_dch_mca_create_ind(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data);
+ extern void bta_hl_dch_mca_create_cfm(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data);
+ extern void bta_hl_dch_mca_create(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_DATA *p_data);
+ extern void bta_hl_deallocate_spd_cback(UINT8 sdp_cback_idx);
+ extern tSDP_DISC_CMPL_CB *bta_hl_allocate_spd_cback(tBTA_HL_SDP_OPER sdp_oper, UINT8 app_idx, UINT8 mcl_idx,
+ UINT8 mdl_idx,
+ UINT8 *p_sdp_cback_idx);
+ extern tBTA_HL_STATUS bta_hl_init_sdp(tBTA_HL_SDP_OPER sdp_oper, UINT8 app_idx, UINT8 mcl_idx,
+ UINT8 mdl_idx);
+ extern void bta_hl_cch_sdp_init(UINT8 app_idx, UINT8 mcl_idx, tBTA_HL_DATA *p_data);
+ extern void bta_hl_cch_mca_open(UINT8 app_idx, UINT8 mcl_idx, tBTA_HL_DATA *p_data);
+ extern void bta_hl_cch_mca_close(UINT8 app_idx, UINT8 mcl_idx, tBTA_HL_DATA *p_data);
+ extern void bta_hl_cch_close_cmpl(UINT8 app_idx, UINT8 mcl_idx, tBTA_HL_DATA *p_data);
+ extern void bta_hl_cch_mca_disconnect(UINT8 app_idx, UINT8 mcl_idx, tBTA_HL_DATA *p_data);
+ extern void bta_hl_cch_mca_rsp_tout(UINT8 app_idx, UINT8 mcl_idx, tBTA_HL_DATA *p_data);
+ extern void bta_hl_cch_mca_connect(UINT8 app_idx, UINT8 mcl_idx, tBTA_HL_DATA *p_data);
+
+ /* State machine drivers */
+ extern void bta_hl_cch_sm_execute(UINT8 inst_idx, UINT8 mcl_idx,
+ UINT16 event, tBTA_HL_DATA *p_data);
+ extern void bta_hl_dch_sm_execute(UINT8 inst_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ UINT16 event, tBTA_HL_DATA *p_data);
+ /* MCAP callback functions */
+ extern void bta_hl_mcap_ctrl_cback(tMCA_HANDLE handle, tMCA_CL mcl, UINT8 event,
+ tMCA_CTRL *p_data);
+
+ extern void bta_hl_mcap_data_cback(tMCA_DL mdl, BT_HDR *p_pkt);
+
+ /* utility functions */
+ extern BOOLEAN bta_hl_set_ctrl_psm_for_dch(UINT8 app_idx, UINT8 mcl_idx,
+ UINT8 mdl_idx, UINT16 ctrl_psm);
+ extern BOOLEAN bta_hl_find_sdp_idx_using_ctrl_psm(tBTA_HL_SDP *p_sdp,
+ UINT16 ctrl_psm,
+ UINT8 *p_sdp_idx);
+ extern UINT8 bta_hl_set_user_tx_pool_id(UINT16 max_tx_size);
+ extern UINT8 bta_hl_set_user_rx_pool_id(UINT16 mtu);
+ extern UINT8 bta_hl_set_tx_win_size(UINT16 mtu, UINT16 mps);
+ extern UINT16 bta_hl_set_mps(UINT16 mtu);
+ extern void bta_hl_clean_mdl_cb(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx);
+ extern BT_HDR * bta_hl_get_buf(UINT16 data_size);
+ extern BOOLEAN bta_hl_find_service_in_db( UINT8 app_idx, UINT8 mcl_idx,
+ UINT16 service_uuid,
+ tSDP_DISC_REC **pp_rec );
+ extern UINT16 bta_hl_get_service_uuids(UINT8 sdp_oper, UINT8 app_idx, UINT8 mcl_idx,
+ UINT8 mdl_idx );
+ extern BOOLEAN bta_hl_find_echo_cfg_rsp(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdep_idx, UINT8 cfg,
+ UINT8 *p_cfg_rsp);
+ extern BOOLEAN bta_hl_validate_cfg(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ UINT8 cfg);
+ extern BOOLEAN bta_hl_find_cch_cb_indexes(tBTA_HL_DATA *p_msg,
+ UINT8 *p_app_idx,
+ UINT8 *p_mcl_idx);
+ extern BOOLEAN bta_hl_find_dch_cb_indexes(tBTA_HL_DATA *p_msg,
+ UINT8 *p_app_idx,
+ UINT8 *p_mcl_idx,
+ UINT8 *p_mdl_idx);
+ extern UINT16 bta_hl_allocate_mdl_id(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx );
+ extern BOOLEAN bta_hl_find_mdl_idx_using_handle(tBTA_HL_MDL_HANDLE mdl_handle,
+ UINT8 *p_app_idx, UINT8 *p_mcl_idx,
+ UINT8 *p_mdl_idx);
+ extern BOOLEAN bta_hl_find_mdl_idx(UINT8 app_idx, UINT8 mcl_idx, UINT16 mdl_id,
+ UINT8 *p_mdl_idx);
+ extern BOOLEAN bta_hl_find_an_active_mdl_idx(UINT8 app_idx, UINT8 mcl_idx,
+ UINT8 *p_mdl_idx);
+ extern BOOLEAN bta_hl_find_dch_setup_mdl_idx(UINT8 app_idx, UINT8 mcl_idx,
+ UINT8 *p_mdl_idx);
+ extern BOOLEAN bta_hl_find_an_in_use_mcl_idx(UINT8 app_idx,
+ UINT8 *p_mcl_idx);
+ extern BOOLEAN bta_hl_find_an_in_use_app_idx(UINT8 *p_app_idx);
+ extern BOOLEAN bta_hl_find_app_idx(UINT8 app_id, UINT8 *p_app_idx);
+ extern BOOLEAN bta_hl_find_app_idx_using_handle(tBTA_HL_APP_HANDLE app_handle,
+ UINT8 *p_app_idx);
+ extern BOOLEAN bta_hl_find_mcl_idx_using_handle( tBTA_HL_MCL_HANDLE mcl_handle,
+ UINT8 *p_app_idx, UINT8 *p_mcl_idx);
+ extern BOOLEAN bta_hl_find_mcl_idx(UINT8 app_idx, BD_ADDR p_bd_addr, UINT8 *p_mcl_idx);
+ extern BOOLEAN bta_hl_is_the_first_reliable_existed(UINT8 app_idx, UINT8 mcl_idx );
+ extern BOOLEAN bta_hl_find_non_active_mdl_cfg(UINT8 app_idx, UINT8 start_mdl_cfg_idx,
+ UINT8 *p_mdl_cfg_idx);
+ extern BOOLEAN bta_hl_find_avail_mdl_cfg_idx(UINT8 app_idx, UINT8 mcl_idx,
+ UINT8 *p_mdl_cfg_idx);
+ extern BOOLEAN bta_hl_find_mdl_cfg_idx(UINT8 app_idx, UINT8 mcl_idx,
+ tBTA_HL_MDL_ID mdl_id, UINT8 *p_mdl_cfg_idx);
+ extern BOOLEAN bta_hl_get_cur_time(UINT8 app_idx, UINT8 *p_cur_time);
+ extern void bta_hl_sort_cfg_time_idx(UINT8 app_idx, UINT8 *a, UINT8 n);
+ extern void bta_hl_compact_mdl_cfg_time(UINT8 app_idx);
+ extern BOOLEAN bta_hl_is_mdl_exsit_in_mcl(UINT8 app_idx, BD_ADDR bd_addr,
+ tBTA_HL_MDL_ID mdl_id);
+ extern BOOLEAN bta_hl_delete_mdl_cfg(UINT8 app_idx, BD_ADDR bd_addr,
+ tBTA_HL_MDL_ID mdl_id);
+ extern BOOLEAN bta_hl_is_mdl_value_valid(tBTA_HL_MDL_ID mdl_id);
+ extern BOOLEAN bta_hl_find_mdep_cfg_idx(UINT8 app_idx,
+ tBTA_HL_MDEP_ID local_mdep_id, UINT8 *p_mdep_cfg_idx);
+ extern void bta_hl_find_rxtx_apdu_size(UINT8 app_idx, UINT8 mdep_cfg_idx,
+ UINT16 *p_rx_apu_size,
+ UINT16 *p_tx_apu_size);
+ extern BOOLEAN bta_hl_validate_peer_cfg(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_MDEP_ID peer_mdep_id,
+ tBTA_HL_MDEP_ROLE peer_mdep_role,
+ UINT8 sdp_idx);
+ extern tBTA_HL_STATUS bta_hl_chk_local_cfg(UINT8 app_idx, UINT8 mcl_idx,
+ UINT8 mdep_cfg_idx,
+ tBTA_HL_DCH_CFG local_cfg);
+
+ extern BOOLEAN bta_hl_validate_reconnect_params(UINT8 app_idx, UINT8 mcl_idx,
+ tBTA_HL_API_DCH_RECONNECT *p_reconnect,
+ UINT8 *p_mdep_cfg_idx, UINT8 *p_mdl_cfg_idx);
+ extern BOOLEAN bta_hl_find_avail_mcl_idx(UINT8 app_idx, UINT8 *p_mcl_idx);
+ extern BOOLEAN bta_hl_find_avail_mdl_idx(UINT8 app_idx, UINT8 mcl_idx,
+ UINT8 *p_mdl_idx);
+ extern BOOLEAN bta_hl_is_a_duplicate_id(UINT8 app_id);
+ extern BOOLEAN bta_hl_find_avail_app_idx(UINT8 *p_idx);
+ extern tBTA_HL_STATUS bta_hl_app_registration(UINT8 app_idx);
+ extern void bta_hl_discard_data(UINT16 event, tBTA_HL_DATA *p_data);
+ extern void bta_hl_save_mdl_cfg(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx );
+ extern void bta_hl_set_dch_chan_cfg(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, tBTA_HL_DATA *p_data);
+ extern BOOLEAN bta_hl_get_l2cap_cfg(tBTA_HL_MDL_HANDLE mdl_hnd, tBTA_HL_L2CAP_CFG_INFO *p_cfg);
+ extern BOOLEAN bta_hl_validate_chan_cfg(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx);
+ extern BOOLEAN bta_hl_is_cong_on(UINT8 app_id, BD_ADDR bd_addr, tBTA_HL_MDL_ID mdl_id);
+ extern void bta_hl_check_cch_close(UINT8 app_idx, UINT8 mcl_idx,
+ tBTA_HL_DATA *p_data, BOOLEAN check_dch_setup);
+ extern void bta_hl_clean_app(UINT8 app_idx);
+ extern void bta_hl_check_deregistration(UINT8 app_idx, tBTA_HL_DATA *p_data );
+ extern void bta_hl_check_disable(tBTA_HL_DATA *p_data );
+ extern void bta_hl_build_abort_ind(tBTA_HL *p_evt_data,
+ tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle);
+ extern void bta_hl_build_abort_cfm(tBTA_HL *p_evt_data,
+ tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_STATUS status);
+ extern void bta_hl_build_dch_close_cfm(tBTA_HL *p_evt_data,
+ tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_MDL_HANDLE mdl_handle,
+ tBTA_HL_STATUS status);
+ extern void bta_hl_build_dch_close_ind(tBTA_HL *p_evt_data,
+ tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_MDL_HANDLE mdl_handle,
+ BOOLEAN intentional);
+ extern void bta_hl_build_send_data_cfm(tBTA_HL *p_evt_data,
+ tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_MDL_HANDLE mdl_handle,
+ tBTA_HL_STATUS status );
+ extern void bta_hl_build_rcv_data_ind(tBTA_HL *p_evt_data,
+ tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_MDL_HANDLE mdl_handle);
+ extern void bta_hl_build_cch_open_cfm(tBTA_HL *p_evt_data,
+ tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle,
+ BD_ADDR bd_addr,
+ tBTA_HL_STATUS status );
+ extern void bta_hl_build_cch_open_ind(tBTA_HL *p_evt_data,
+ tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle,
+ BD_ADDR bd_addr);
+ extern void bta_hl_build_cch_close_cfm(tBTA_HL *p_evt_data,
+ tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_STATUS status );
+ extern void bta_hl_build_cch_close_ind(tBTA_HL *p_evt_data,
+ tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle,
+ BOOLEAN intentional);
+
+ extern void bta_hl_build_dch_open_cfm(tBTA_HL *p_evt_data,
+ tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_MDL_HANDLE mdl_handle,
+ tBTA_HL_MDEP_ID local_mdep_id,
+ tBTA_HL_MDL_ID mdl_id,
+ tBTA_HL_DCH_MODE dch_mode,
+ BOOLEAN first_reliable,
+ UINT16 mtu,
+ tBTA_HL_STATUS status);
+
+ extern void bta_hl_build_delete_mdl_cfm(tBTA_HL *p_evt_data,
+ tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_MDL_ID mdl_id,
+ tBTA_HL_STATUS status);
+ extern void bta_hl_build_echo_test_cfm(tBTA_HL *p_evt_data,
+ tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_STATUS status );
+ extern void bta_hl_build_sdp_query_cfm(tBTA_HL *p_evt_data,
+ tBTA_HL_APP_HANDLE app_handle,
+ BD_ADDR bd_addr,
+ tBTA_HL_SDP *p_sdp,
+ tBTA_HL_STATUS status);
+
+#if (BTA_HL_DEBUG == TRUE)
+ extern char *bta_hl_status_code(tBTA_HL_STATUS status);
+ extern char *bta_hl_evt_code(tBTA_HL_INT_EVT evt_code);
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif /* BTA_MSE_INT_H */
+
+
diff --git a/bta/hl/bta_hl_main.c b/bta/hl/bta_hl_main.c
new file mode 100644
index 0000000..3bfca86
--- /dev/null
+++ b/bta/hl/bta_hl_main.c
@@ -0,0 +1,1907 @@
+/*****************************************************************************
+**
+** Name: bta_hl_main.c
+**
+** Description: This file contains the HeaLth device profile main functions
+** and state machine.
+**
+** Copyright (c) 1998-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include <string.h>
+
+#include "bt_target.h"
+#if defined(HL_INCLUDED) && (HL_INCLUDED == TRUE)
+
+
+
+#include "bta_hl_api.h"
+#include "bta_hl_int.h"
+#include "gki.h"
+#include "utl.h"
+#include "bd.h"
+#include "l2c_api.h"
+#include "mca_defs.h"
+
+
+#if (BTA_HL_DEBUG == TRUE) && (BT_USE_TRACES == TRUE)
+static char *bta_hl_cch_state_code(tBTA_HL_CCH_STATE state_code);
+static char *bta_hl_dch_state_code(tBTA_HL_DCH_STATE state_code);
+#endif
+
+extern UINT16 L2CA_AllocateRandomPsm(void);
+extern UINT16 L2CA_AllocatePsm(void);
+/*****************************************************************************
+** DCH State Table
+*****************************************************************************/
+/*****************************************************************************
+** Constants and types
+*****************************************************************************/
+/* state machine action enumeration list for DCH */
+/* The order of this enumeration must be the same as bta_hl_dch_act_tbl[] */
+enum
+{
+ BTA_HL_DCH_MCA_CREATE,
+ BTA_HL_DCH_MCA_CREATE_CFM,
+ BTA_HL_DCH_MCA_CREATE_IND,
+ BTA_HL_DCH_MCA_OPEN_CFM,
+ BTA_HL_DCH_MCA_OPEN_IND,
+ BTA_HL_DCH_MCA_CLOSE,
+ BTA_HL_DCH_MCA_CLOSE_CFM,
+ BTA_HL_DCH_MCA_CLOSE_IND,
+ BTA_HL_DCH_CLOSE_CMPL,
+ BTA_HL_DCH_MCA_RCV_DATA,
+
+ BTA_HL_DCH_SDP_INIT,
+ BTA_HL_DCH_MCA_RECONNECT,
+ BTA_HL_DCH_MCA_RECONNECT_IND,
+ BTA_HL_DCH_MCA_RECONNECT_CFM,
+ BTA_HL_DCH_CLOSE_ECHO_TEST,
+ BTA_HL_DCH_CREATE_RSP,
+ BTA_HL_DCH_MCA_ABORT,
+ BTA_HL_DCH_MCA_ABORT_IND,
+ BTA_HL_DCH_MCA_ABORT_CFM,
+ BTA_HL_DCH_MCA_CONG_CHANGE,
+
+ BTA_HL_DCH_SDP_FAIL,
+ BTA_HL_DCH_SEND_DATA,
+ BTA_HL_DCH_CI_GET_TX_DATA,
+ BTA_HL_DCH_CI_PUT_RX_DATA,
+ BTA_HL_DCH_CI_GET_ECHO_DATA,
+ BTA_HL_DCH_ECHO_TEST,
+ BTA_HL_DCH_CI_PUT_ECHO_DATA,
+ BTA_HL_DCH_IGNORE
+};
+
+typedef void (*tBTA_HL_DCH_ACTION)(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, tBTA_HL_DATA *p_data);
+
+static const tBTA_HL_DCH_ACTION bta_hl_dch_action[] =
+{
+ bta_hl_dch_mca_create,
+ bta_hl_dch_mca_create_cfm,
+ bta_hl_dch_mca_create_ind,
+ bta_hl_dch_mca_open_cfm,
+ bta_hl_dch_mca_open_ind,
+ bta_hl_dch_mca_close,
+ bta_hl_dch_mca_close_cfm,
+ bta_hl_dch_mca_close_ind,
+ bta_hl_dch_close_cmpl,
+ bta_hl_dch_mca_rcv_data,
+
+ bta_hl_dch_sdp_init,
+ bta_hl_dch_mca_reconnect,
+ bta_hl_dch_mca_reconnect_ind,
+ bta_hl_dch_mca_reconnect_cfm,
+ bta_hl_dch_close_echo_test,
+ bta_hl_dch_create_rsp,
+ bta_hl_dch_mca_abort,
+ bta_hl_dch_mca_abort_ind,
+ bta_hl_dch_mca_abort_cfm,
+ bta_hl_dch_mca_cong_change,
+
+ bta_hl_dch_sdp_fail,
+ bta_hl_dch_send_data,
+ bta_hl_dch_ci_get_tx_data,
+ bta_hl_dch_ci_put_rx_data,
+ bta_hl_dch_ci_get_echo_data,
+ bta_hl_dch_echo_test,
+ bta_hl_dch_ci_put_echo_data,
+};
+
+
+/* state table information */
+#define BTA_HL_DCH_ACTIONS 1 /* number of actions */
+#define BTA_HL_DCH_ACTION_COL 0 /* position of action */
+#define BTA_HL_DCH_NEXT_STATE 1 /* position of next state */
+#define BTA_HL_DCH_NUM_COLS 2 /* number of columns in state tables */
+
+/* state table for idle state */
+static const UINT8 bta_hl_dch_st_idle[][BTA_HL_DCH_NUM_COLS] =
+{
+/* Event Action 1 Next state */
+/* BTA_HL_DCH_SDP_INIT_EVT */ {BTA_HL_DCH_SDP_INIT, BTA_HL_DCH_OPENING_ST},
+/* BTA_HL_DCH_OPEN_EVT */ {BTA_HL_DCH_MCA_CREATE, BTA_HL_DCH_OPENING_ST},
+/* BTA_HL_MCA_CREATE_IND_EVT */ {BTA_HL_DCH_MCA_CREATE_IND, BTA_HL_DCH_OPENING_ST},
+/* BTA_HL_MCA_CREATE_CFM_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+/* BTA_HL_MCA_OPEN_IND_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+
+/* BTA_HL_MCA_OPEN_CFM_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+/* BTA_HL_DCH_CLOSE_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+/* BTA_HL_MCA_CLOSE_IND_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+/* BTA_HL_MCA_CLOSE_CFM_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+/* BTA_HL_API_SEND_DATA_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+
+/* BTA_HL_MCA_RCV_DATA_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+/* BTA_HL_DCH_CLOSE_CMPL_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+/* BTA_HL_DCH_RECONNECT_EVT */ {BTA_HL_DCH_MCA_RECONNECT, BTA_HL_DCH_OPENING_ST},
+/* BTA_HL_DCH_SDP_FAIL_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+/* BTA_HL_MCA_RECONNECT_IND_EVT*/ {BTA_HL_DCH_MCA_RECONNECT_IND, BTA_HL_DCH_OPENING_ST},
+
+/* BTA_HL_MCA_RECONNECT_CFM_EVT*/ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+/* BTA_HL_DCH_CLOSE_ECHO_TEST_EVT*/ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+/* BTA_HL_API_DCH_CREATE_RSP_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+/* BTA_HL_DCH_ABORT_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+/* BTA_HL_MCA_ABORT_IND_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+
+/* BTA_HL_MCA_ABORT_CFM_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+/* BTA_HL_MCA_CONG_CHG_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+/* BTA_HL_CI_GET_TX_DATA_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+/* BTA_HL_CI_PUT_RX_DATA_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+/* BTA_HL_CI_GET_ECHO_DATA_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+/* BTA_HL_DCH_ECHO_TEST_EVT */ {BTA_HL_DCH_ECHO_TEST, BTA_HL_DCH_OPENING_ST},
+/* BTA_HL_CI_PUT_ECHO_DATA_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST}
+};
+
+/* state table for opening state */
+static const UINT8 bta_hl_dch_st_opening[][BTA_HL_DCH_NUM_COLS] =
+{
+/* Event Action 1 Next state */
+/* BTA_HL_DCH_SDP_INIT_EVT */ {BTA_HL_DCH_SDP_INIT, BTA_HL_DCH_OPENING_ST},
+/* BTA_HL_DCH_OPEN_EVT */ {BTA_HL_DCH_MCA_CREATE, BTA_HL_DCH_OPENING_ST},
+/* BTA_HL_MCA_CREATE_IND_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPENING_ST},
+/* BTA_HL_MCA_CREATE_CFM_EVT */ {BTA_HL_DCH_MCA_CREATE_CFM, BTA_HL_DCH_OPENING_ST},
+/* BTA_HL_MCA_OPEN_IND_EVT */ {BTA_HL_DCH_MCA_OPEN_IND, BTA_HL_DCH_OPEN_ST},
+/* BTA_HL_MCA_OPEN_CFM_EVT */ {BTA_HL_DCH_MCA_OPEN_CFM, BTA_HL_DCH_OPEN_ST},
+/* BTA_HL_DCH_CLOSE_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPENING_ST},
+/* BTA_HL_MCA_CLOSE_IND_EVT */ {BTA_HL_DCH_MCA_CLOSE_IND, BTA_HL_DCH_CLOSING_ST},
+/* BTA_HL_MCA_CLOSE_CFM_EVT */ {BTA_HL_DCH_MCA_CLOSE_CFM, BTA_HL_DCH_CLOSING_ST},
+/* BTA_HL_API_SEND_DATA_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST},
+
+/* BTA_HL_MCA_RCV_DATA_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST},
+/* BTA_HL_DCH_CLOSE_CMPL_EVT */ {BTA_HL_DCH_CLOSE_CMPL, BTA_HL_DCH_IDLE_ST},
+/* BTA_HL_DCH_RECONNECT_EVT */ {BTA_HL_DCH_MCA_RECONNECT, BTA_HL_DCH_OPENING_ST},
+/* BTA_HL_DCH_SDP_FAIL_EVT */ {BTA_HL_DCH_SDP_FAIL, BTA_HL_DCH_CLOSING_ST},
+/* BTA_HL_MCA_RECONNECT_IND_EVT*/ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+/* BTA_HL_MCA_RECONNECT_CFM_EVT*/ {BTA_HL_DCH_MCA_RECONNECT_CFM, BTA_HL_DCH_OPENING_ST},
+/* BTA_HL_DCH_CLOSE_ECHO_TEST_EVT*/ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPENING_ST},
+/* BTA_HL_API_DCH_CREATE_RSP_EVT */ {BTA_HL_DCH_CREATE_RSP, BTA_HL_DCH_OPENING_ST},
+/* BTA_HL_DCH_ABORT_EVT */ {BTA_HL_DCH_MCA_ABORT, BTA_HL_DCH_OPENING_ST},
+/* BTA_HL_MCA_ABORT_IND_EVT */ {BTA_HL_DCH_MCA_ABORT_IND, BTA_HL_DCH_OPENING_ST},
+
+/* BTA_HL_MCA_ABORT_CFM_EVT */ {BTA_HL_DCH_MCA_ABORT_CFM, BTA_HL_DCH_OPENING_ST},
+/* BTA_HL_MCA_CONG_CHG_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPENING_ST},
+/* BTA_HL_CI_GET_TX_DATA_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPENING_ST},
+/* BTA_HL_CI_PUT_RX_DATA_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPENING_ST},
+/* BTA_HL_CI_GET_ECHO_DATA_EVT */ {BTA_HL_DCH_CI_GET_ECHO_DATA, BTA_HL_DCH_OPENING_ST},
+/* BTA_HL_DCH_ECHO_TEST_EVT */ {BTA_HL_DCH_ECHO_TEST, BTA_HL_DCH_OPENING_ST},
+/* BTA_HL_CI_PUT_ECHO_DATA_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPENING_ST}
+};
+
+/* state table for open state */
+static const UINT8 bta_hl_dch_st_open[][BTA_HL_DCH_NUM_COLS] =
+{
+/* Event Action 1 Next state */
+/* BTA_HL_DCH_SDP_INIT_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST},
+/* BTA_HL_DCH_OPEN_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST},
+/* BTA_HL_MCA_CREATE_IND_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST},
+/* BTA_HL_MCA_CREATE_CFM_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST},
+/* BTA_HL_MCA_OPEN_IND_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST},
+/* BTA_HL_MCA_OPEN_CFM_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST},
+/* BTA_HL_DCH_CLOSE_EVT */ {BTA_HL_DCH_MCA_CLOSE, BTA_HL_DCH_CLOSING_ST},
+/* BTA_HL_MCA_CLOSE_IND_EVT */ {BTA_HL_DCH_MCA_CLOSE_IND, BTA_HL_DCH_CLOSING_ST},
+/* BTA_HL_MCA_CLOSE_CFM_EVT */ {BTA_HL_DCH_MCA_CLOSE_CFM, BTA_HL_DCH_CLOSING_ST},
+/* BTA_HL_API_SEND_DATA_EVT */ {BTA_HL_DCH_SEND_DATA, BTA_HL_DCH_OPEN_ST},
+
+/* BTA_HL_MCA_RCV_DATA_EVT */ {BTA_HL_DCH_MCA_RCV_DATA, BTA_HL_DCH_OPEN_ST},
+/* BTA_HL_DCH_CLOSE_CMPL_EVT */ {BTA_HL_DCH_CLOSE_CMPL, BTA_HL_DCH_IDLE_ST},
+/* BTA_HL_DCH_RECONNECT_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST},
+/* BTA_HL_DCH_SDP_FAIL_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST},
+/* BTA_HL_MCA_RECONNECT_IND_EVT*/ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST},
+/* BTA_HL_MCA_RECONNECT_CFM_EVT*/ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST},
+/* BTA_HL_DCH_CLOSE_ECHO_TEST_EVT*/ {BTA_HL_DCH_CLOSE_ECHO_TEST, BTA_HL_DCH_CLOSING_ST},
+/* BTA_HL_API_DCH_CREATE_RSP_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST},
+/* BTA_HL_DCH_ABORT_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST},
+/* BTA_HL_MCA_ABORT_IND_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST},
+
+/* BTA_HL_DCH_ABORT_CFM_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST},
+/* BTA_HL_MCA_CONG_CHG_EVT */ {BTA_HL_DCH_MCA_CONG_CHANGE, BTA_HL_DCH_OPEN_ST},
+/* BTA_HL_CI_GET_TX_DATA_EVT */ {BTA_HL_DCH_CI_GET_TX_DATA, BTA_HL_DCH_OPEN_ST},
+/* BTA_HL_CI_PUT_RX_DATA_EVT */ {BTA_HL_DCH_CI_PUT_RX_DATA, BTA_HL_DCH_OPEN_ST},
+/* BTA_HL_CI_GET_ECHO_DATA_EVT */ {BTA_HL_DCH_CI_GET_ECHO_DATA, BTA_HL_DCH_OPEN_ST},
+/* BTA_HL_DCH_ECHO_TEST_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST},
+/* BTA_HL_CI_PUT_ECHO_DATA_EVT */ {BTA_HL_DCH_CI_PUT_ECHO_DATA, BTA_HL_DCH_OPEN_ST}
+};
+
+
+/* state table for closing state */
+static const UINT8 bta_hl_dch_st_closing[][BTA_HL_DCH_NUM_COLS] =
+{
+/* Event Action 1 Next state */
+/* BTA_HL_DCH_SDP_INIT_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+/* BTA_HL_DCH_OPEN_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+/* BTA_HL_MCA_CREATE_IND_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+/* BTA_HL_MCA_CREATE_CFM_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+/* BTA_HL_MCA_OPEN_IND_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+/* BTA_HL_MCA_OPEN_CFM_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+/* BTA_HL_DCH_CLOSE_EVT */ {BTA_HL_DCH_MCA_CLOSE, BTA_HL_DCH_CLOSING_ST},
+/* BTA_HL_MCA_CLOSE_IND_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+/* BTA_HL_MCA_CLOSE_CFM_EVT */ {BTA_HL_DCH_MCA_CLOSE_CFM, BTA_HL_DCH_CLOSING_ST},
+/* BTA_HL_API_SEND_DATA_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+
+/* BTA_HL_MCA_RCV_DATA_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+/* BTA_HL_DCH_CLOSE_CMPL_EVT */ {BTA_HL_DCH_CLOSE_CMPL, BTA_HL_DCH_IDLE_ST},
+/* BTA_HL_DCH_RECONNECT_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+/* BTA_HL_DCH_SDP_FAIL_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+/* BTA_HL_MCA_RECONNECT_IND_EVT*/ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+/* BTA_HL_MCA_RECONNECT_CFM_EVT*/ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+/* BTA_HL_DCH_CLOSE_ECHO_TEST_EVT*/ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+/* BTA_HL_API_DCH_CREATE_RSP_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+/* BTA_HL_DCH_ABORT_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+/* BTA_HL_MCA_ABORT_IND_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+
+/* BTA_HL_DCH_ABORT_CFM_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+/* BTA_HL_MCA_CONG_CHG_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+/* BTA_HL_CI_GET_TX_DATA_EVT */ {BTA_HL_DCH_CI_GET_TX_DATA, BTA_HL_DCH_CLOSING_ST},
+/* BTA_HL_CI_PUT_RX_DATA_EVT */ {BTA_HL_DCH_CI_PUT_RX_DATA, BTA_HL_DCH_CLOSING_ST},
+/* BTA_HL_CI_GET_ECHO_DATA_EVT */ {BTA_HL_DCH_CI_GET_ECHO_DATA, BTA_HL_DCH_CLOSING_ST},
+/* BTA_HL_DCH_ECHO_TEST_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+/* BTA_HL_CI_PUT_ECHO_DATA_EVT */ {BTA_HL_DCH_CI_PUT_ECHO_DATA, BTA_HL_DCH_CLOSING_ST}
+};
+
+/* type for state table */
+typedef const UINT8 (*tBTA_HL_DCH_ST_TBL)[BTA_HL_DCH_NUM_COLS];
+
+/* state table */
+const tBTA_HL_DCH_ST_TBL bta_hl_dch_st_tbl[] =
+{
+ bta_hl_dch_st_idle,
+ bta_hl_dch_st_opening,
+ bta_hl_dch_st_open,
+ bta_hl_dch_st_closing
+};
+
+/*****************************************************************************
+** CCH State Table
+*****************************************************************************/
+/*****************************************************************************
+** Constants and types
+*****************************************************************************/
+/* state machine action enumeration list for CCH */
+enum
+{
+ BTA_HL_CCH_SDP_INIT,
+ BTA_HL_CCH_MCA_OPEN,
+ BTA_HL_CCH_MCA_CLOSE,
+ BTA_HL_CCH_CLOSE_CMPL,
+ BTA_HL_CCH_MCA_CONNECT,
+ BTA_HL_CCH_MCA_DISCONNECT,
+ BTA_HL_CCH_MCA_RSP_TOUT,
+ BTA_HL_CCH_IGNORE
+};
+
+/* type for action functions */
+typedef void (*tBTA_HL_CCH_ACTION)(UINT8 app_idx, UINT8 mcl_idx, tBTA_HL_DATA *p_data);
+
+/* action function list for MAS */
+const tBTA_HL_CCH_ACTION bta_hl_cch_action[] =
+{
+ bta_hl_cch_sdp_init,
+ bta_hl_cch_mca_open,
+ bta_hl_cch_mca_close,
+ bta_hl_cch_close_cmpl,
+ bta_hl_cch_mca_connect,
+ bta_hl_cch_mca_disconnect,
+ bta_hl_cch_mca_rsp_tout
+};
+
+
+/* state table information */
+#define BTA_HL_CCH_ACTIONS 1 /* number of actions */
+#define BTA_HL_CCH_NEXT_STATE 1 /* position of next state */
+#define BTA_HL_CCH_NUM_COLS 2 /* number of columns in state tables */
+
+
+/* state table for MAS idle state */
+static const UINT8 bta_hl_cch_st_idle[][BTA_HL_CCH_NUM_COLS] =
+{
+/* Event Action 1 Next state */
+/* BTA_HL_CCH_OPEN_EVT */ {BTA_HL_CCH_SDP_INIT, BTA_HL_CCH_OPENING_ST},
+/* BTA_HL_CCH_SDP_OK_EVT */ {BTA_HL_CCH_IGNORE, BTA_HL_CCH_IDLE_ST},
+/* BTA_HL_CCH_SDP_FAIL_EVT */ {BTA_HL_CCH_IGNORE, BTA_HL_CCH_IDLE_ST},
+/* BTA_HL_MCA_CONNECT_IND_EVT */ {BTA_HL_CCH_MCA_CONNECT, BTA_HL_CCH_OPEN_ST},
+/* BTA_HL_MCA_DISCONNECT_IND_EVT */ {BTA_HL_CCH_IGNORE, BTA_HL_CCH_IDLE_ST},
+/* BTA_HL_CCH_CLOSE_EVT */ {BTA_HL_CCH_IGNORE, BTA_HL_CCH_IDLE_ST},
+/* BTA_HL_CCH_CLOSE_CMPL_EVT */ {BTA_HL_CCH_IGNORE, BTA_HL_CCH_IDLE_ST},
+/* BTA_HL_CCH_CLOSE_CMPL_EVT */ {BTA_HL_CCH_IGNORE, BTA_HL_CCH_IDLE_ST}
+};
+
+/* state table for obex/rfcomm connection state */
+static const UINT8 bta_hl_cch_st_opening[][BTA_HL_CCH_NUM_COLS] =
+{
+/* Event Action 1 Next state */
+/* BTA_HL_CCH_OPEN_EVT */ {BTA_HL_CCH_IGNORE, BTA_HL_CCH_OPENING_ST},
+/* BTA_HL_CCH_SDP_OK_EVT */ {BTA_HL_CCH_MCA_OPEN, BTA_HL_CCH_OPENING_ST},
+/* BTA_HL_CCH_SDP_FAIL_EVT */ {BTA_HL_CCH_CLOSE_CMPL, BTA_HL_CCH_IDLE_ST},
+/* BTA_HL_MCA_CONNECT_IND_EVT */ {BTA_HL_CCH_MCA_CONNECT, BTA_HL_CCH_OPEN_ST},
+/* BTA_HL_MCA_DISCONNECT_IND_EVT */ {BTA_HL_CCH_MCA_DISCONNECT, BTA_HL_CCH_CLOSING_ST},
+/* BTA_HL_CCH_CLOSE_EVT */ {BTA_HL_CCH_MCA_CLOSE, BTA_HL_CCH_CLOSING_ST},
+/* BTA_HL_CCH_CLOSE_CMPL_EVT */ {BTA_HL_CCH_CLOSE_CMPL, BTA_HL_CCH_IDLE_ST},
+/* BTA_HL_MCA_RSP_TOUT_IND_EVT */ {BTA_HL_CCH_MCA_RSP_TOUT, BTA_HL_CCH_CLOSING_ST}
+};
+
+/* state table for open state */
+static const UINT8 bta_hl_cch_st_open[][BTA_HL_CCH_NUM_COLS] =
+{
+/* Event Action 1 Next state */
+/* BTA_HL_CCH_OPEN_EVT */ {BTA_HL_CCH_IGNORE, BTA_HL_CCH_OPEN_ST},
+/* BTA_HL_CCH_SDP_OK_EVT */ {BTA_HL_CCH_IGNORE, BTA_HL_CCH_OPEN_ST},
+/* BTA_HL_CCH_SDP_FAIL_EVT */ {BTA_HL_CCH_IGNORE, BTA_HL_CCH_OPEN_ST},
+/* BTA_HL_MCA_CONNECT_IND_EVT */ {BTA_HL_CCH_IGNORE, BTA_HL_CCH_OPEN_ST},
+/* BTA_HL_MCA_DISCONNECT_IND_EVT */ {BTA_HL_CCH_MCA_DISCONNECT, BTA_HL_CCH_CLOSING_ST},
+/* BTA_HL_CCH_CLOSE_EVT */ {BTA_HL_CCH_MCA_CLOSE, BTA_HL_CCH_CLOSING_ST},
+/* BTA_HL_CCH_CLOSE_CMPL_EVT */ {BTA_HL_CCH_IGNORE, BTA_HL_CCH_OPEN_ST},
+/* BTA_HL_MCA_RSP_TOUT_IND_EVT */ {BTA_HL_CCH_MCA_RSP_TOUT, BTA_HL_CCH_CLOSING_ST}
+};
+
+/* state table for closing state */
+static const UINT8 bta_hl_cch_st_closing[][BTA_HL_CCH_NUM_COLS] =
+{
+/* Event Action 1 Next state */
+/* BTA_HL_CCH_OPEN_EVT */ {BTA_HL_CCH_IGNORE, BTA_HL_CCH_CLOSING_ST},
+/* BTA_HL_CCH_SDP_OK_EVT */ {BTA_HL_CCH_CLOSE_CMPL, BTA_HL_CCH_IDLE_ST},
+/* BTA_HL_CCH_SDP_FAIL_EVT */ {BTA_HL_CCH_CLOSE_CMPL, BTA_HL_CCH_IDLE_ST},
+/* BTA_HL_MCA_CONNECT_IND_EVT */ {BTA_HL_CCH_MCA_CONNECT, BTA_HL_CCH_OPEN_ST},
+/* BTA_HL_MCA_DISCONNECT_IND_EVT */ {BTA_HL_CCH_MCA_DISCONNECT, BTA_HL_CCH_CLOSING_ST},
+/* BTA_HL_CCH_CLOSE_EVT */ {BTA_HL_CCH_MCA_CLOSE, BTA_HL_CCH_CLOSING_ST},
+/* BTA_HL_CCH_CLOSE_CMPL_EVT */ {BTA_HL_CCH_CLOSE_CMPL, BTA_HL_CCH_IDLE_ST},
+/* BTA_HL_MCA_RSP_TOUT_IND_EVT */ {BTA_HL_CCH_IGNORE, BTA_HL_CCH_CLOSING_ST}
+};
+
+/* type for state table CCH */
+typedef const UINT8 (*tBTA_HL_CCH_ST_TBL)[BTA_HL_CCH_NUM_COLS];
+
+/* MAS state table */
+const tBTA_HL_CCH_ST_TBL bta_hl_cch_st_tbl[] =
+{
+ bta_hl_cch_st_idle,
+ bta_hl_cch_st_opening,
+ bta_hl_cch_st_open,
+ bta_hl_cch_st_closing
+};
+
+
+/*****************************************************************************
+** Global data
+*****************************************************************************/
+
+/* HL control block */
+#if BTA_DYNAMIC_MEMORY == FALSE
+tBTA_HL_CB bta_hl_cb;
+#endif
+
+
+/*******************************************************************************
+**
+** Function bta_hl_cch_sm_execute
+**
+** Description State machine event handling function for CCH
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hl_cch_sm_execute(UINT8 app_idx, UINT8 mcl_idx,
+ UINT16 event, tBTA_HL_DATA *p_data)
+{
+ tBTA_HL_CCH_ST_TBL state_table;
+ UINT8 action;
+ int i;
+ tBTA_HL_MCL_CB *p_cb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+
+#if (BTA_HL_DEBUG == TRUE) && (BT_USE_TRACES == TRUE)
+ tBTA_HL_CCH_STATE in_state = p_cb->cch_state;
+ UINT16 cur_evt = event;
+ APPL_TRACE_DEBUG3("HDP CCH Event Handler: State 0x%02x [%s], Event [%s]", in_state,
+ bta_hl_cch_state_code(in_state),
+ bta_hl_evt_code(cur_evt));
+#endif
+
+ /* look up the state table for the current state */
+ state_table = bta_hl_cch_st_tbl[p_cb->cch_state];
+
+ event &= 0x00FF;
+
+ /* set next state */
+ p_cb->cch_state = state_table[event][BTA_HL_CCH_NEXT_STATE];
+
+ for (i = 0; i < BTA_HL_CCH_ACTIONS; i++)
+ {
+ if ((action = state_table[event][i]) != BTA_HL_CCH_IGNORE)
+ {
+ (*bta_hl_cch_action[action])(app_idx, mcl_idx, p_data);
+ }
+ else
+ {
+ /* discard HDP data */
+ bta_hl_discard_data(p_data->hdr.event, p_data);
+ break;
+ }
+ }
+#if (BTA_HL_DEBUG == TRUE) && (BT_USE_TRACES == TRUE)
+ if (in_state != p_cb->cch_state)
+ {
+ APPL_TRACE_DEBUG3("HL CCH State Change: [%s] -> [%s] after [%s]",
+ bta_hl_cch_state_code(in_state),
+ bta_hl_cch_state_code(p_cb->cch_state),
+ bta_hl_evt_code(cur_evt));
+ }
+#endif
+
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_dch_sm_execute
+**
+** Description State machine event handling function for DCH
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hl_dch_sm_execute(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ UINT16 event, tBTA_HL_DATA *p_data)
+{
+ tBTA_HL_DCH_ST_TBL state_table;
+ UINT8 action;
+ int i;
+ tBTA_HL_MDL_CB *p_cb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+#if (BTA_HL_DEBUG == TRUE) && (BT_USE_TRACES == TRUE)
+ tBTA_HL_DCH_STATE in_state = p_cb->dch_state;
+ UINT16 cur_evt = event;
+ APPL_TRACE_DEBUG3("HDP DCH Event Handler: State 0x%02x [%s], Event [%s]", in_state,
+ bta_hl_dch_state_code(in_state),
+ bta_hl_evt_code(cur_evt));
+#endif
+
+ /* look up the state table for the current state */
+ state_table = bta_hl_dch_st_tbl[p_cb->dch_state];
+ event -= BTA_HL_DCH_EVT_MIN;
+
+ /* set next state */
+ p_cb->dch_state = state_table[event][BTA_HL_DCH_NEXT_STATE];
+
+ for (i = 0; i < BTA_HL_DCH_ACTIONS; i++)
+ {
+ if ((action = state_table[event][i]) != BTA_HL_DCH_IGNORE)
+ {
+ (*bta_hl_dch_action[action])(app_idx, mcl_idx, mdl_idx, p_data);
+ }
+ else
+ {
+ /* discard mas data */
+ bta_hl_discard_data(p_data->hdr.event, p_data);
+ break;
+ }
+ }
+
+
+#if (BTA_HL_DEBUG == TRUE) && (BT_USE_TRACES == TRUE)
+ if (in_state != p_cb->dch_state)
+ {
+ APPL_TRACE_DEBUG3("HL DCH State Change: [%s] -> [%s] after [%s]",
+ bta_hl_dch_state_code(in_state),
+ bta_hl_dch_state_code(p_cb->dch_state),
+ bta_hl_evt_code(cur_evt));
+ }
+#endif
+}
+/*******************************************************************************
+**
+** Function bta_hl_api_enable
+**
+** Description Process the API enable request to enable the HL subsystem
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_hl_api_enable(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data)
+{
+ tBTA_HL_CTRL evt_data;
+
+ /* If already enabled then reject this request */
+ if (p_cb->enable)
+ {
+ APPL_TRACE_ERROR0("HL is already enabled");
+ evt_data.enable_cfm.status = BTA_HL_STATUS_FAIL;
+ if (p_data->api_enable.p_cback)
+ p_data->api_enable.p_cback(BTA_HL_CTRL_ENABLE_CFM_EVT, (tBTA_HL_CTRL *) &evt_data);
+ return;
+ }
+
+ /* Done with checking. now perform the enable oepration*/
+ /* initialize control block */
+ memset(p_cb, 0, sizeof(tBTA_HL_CB));
+ p_cb->enable = TRUE;
+ p_cb->p_ctrl_cback = p_data->api_enable.p_cback;
+ evt_data.enable_cfm.status = BTA_HL_STATUS_OK;
+ if (p_data->api_enable.p_cback)
+ p_data->api_enable.p_cback(BTA_HL_CTRL_ENABLE_CFM_EVT, (tBTA_HL_CTRL *) &evt_data);
+
+}
+/*******************************************************************************
+**
+** Function bta_hl_api_disable
+**
+** Description Process the API disable request to disable the HL subsystem
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_hl_api_disable(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data)
+{
+ tBTA_HL_CTRL evt_data;
+ tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+
+ if (p_cb->enable)
+ {
+ p_cb->disabling = TRUE;
+ bta_hl_check_disable(p_data);
+ }
+ else
+ {
+ status = BTA_HL_STATUS_FAIL;
+ evt_data.disable_cfm.status = status;
+ if (p_cb->p_ctrl_cback) p_cb->p_ctrl_cback(BTA_HL_CTRL_DISABLE_CFM_EVT, (tBTA_HL_CTRL *) &evt_data);
+ }
+
+
+#if BTA_HL_DEBUG == TRUE
+ if (status != BTA_HL_STATUS_OK)
+ {
+ APPL_TRACE_DEBUG1("bta_hl_api_disable status =%s", bta_hl_status_code(status));
+ }
+#endif
+
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_api_register
+**
+** Description Process the API registration request to register an HDP applciation
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_hl_api_register(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data)
+{
+ tBTA_HL evt_data;
+ UINT8 app_idx;
+ tBTA_HL_APP_CB *p_acb;
+ tBTA_HL_STATUS status = BTA_HL_STATUS_FAIL;
+
+ if (p_cb->enable)
+ {
+ if (!bta_hl_is_a_duplicate_id(p_data->api_reg.app_id))
+ {
+ if (bta_hl_find_avail_app_idx(&app_idx))
+ {
+ p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ p_acb->in_use = TRUE;
+ p_acb->app_id = p_data->api_reg.app_id;
+ p_acb->p_cback = p_data->api_reg.p_cback;
+ p_acb->sec_mask = p_data->api_reg.sec_mask;
+ p_acb->dev_type = p_data->api_reg.dev_type;
+ BCM_STRNCPY_S(p_acb->srv_name, sizeof(p_acb->srv_name), p_data->api_reg.srv_name, BTA_SERVICE_NAME_LEN);
+ BCM_STRNCPY_S(p_acb->srv_desp, sizeof(p_acb->srv_desp), p_data->api_reg.srv_desp, BTA_SERVICE_DESP_LEN);
+ BCM_STRNCPY_S(p_acb->provider_name, sizeof(p_acb->provider_name), p_data->api_reg.provider_name, BTA_PROVIDER_NAME_LEN);
+ bta_hl_cb.p_alloc_psm = L2CA_AllocatePSM;
+ p_acb->ctrl_psm = bta_hl_cb.p_alloc_psm();
+ p_acb->data_psm = bta_hl_cb.p_alloc_psm();
+ p_acb->p_mcap_cback = bta_hl_mcap_ctrl_cback;
+ status = bta_hl_app_registration(app_idx);
+ }
+ else
+ {
+ status = BTA_HL_STATUS_NO_RESOURCE;
+ }
+ }
+ else
+ {
+ status = BTA_HL_STATUS_DUPLICATE_APP_ID;
+ }
+ }
+
+ if (status != BTA_HL_STATUS_OK)
+ {
+ if ((status != BTA_HL_STATUS_DUPLICATE_APP_ID) &&
+ (status != BTA_HL_STATUS_NO_RESOURCE))
+ {
+ memset(p_acb, 0, sizeof(tBTA_HL_APP_CB));
+ }
+ }
+#if BTA_HL_DEBUG == TRUE
+ if (status != BTA_HL_STATUS_OK)
+ {
+ APPL_TRACE_DEBUG1("bta_hl_api_register status =%s", bta_hl_status_code(status));
+ }
+#endif
+
+ evt_data.reg_cfm.status = status;
+ evt_data.reg_cfm.app_id = p_data->api_reg.app_id;
+ evt_data.reg_cfm.app_handle = p_acb->app_handle;
+ if (p_data->api_reg.p_cback)
+ {
+ p_data->api_reg.p_cback(BTA_HL_REGISTER_CFM_EVT, (tBTA_HL *) &evt_data);
+ }
+
+ if (status == BTA_HL_STATUS_OK)
+ {
+ evt_data.sdp_info_ind.app_handle = p_acb->app_handle;
+ evt_data.sdp_info_ind.ctrl_psm = p_acb->ctrl_psm;
+ evt_data.sdp_info_ind.data_psm = p_acb->data_psm;
+ evt_data.sdp_info_ind.data_x_spec = BTA_HL_SDP_IEEE_11073_20601;
+ evt_data.sdp_info_ind.mcap_sup_procs = BTA_HL_MCAP_SUP_PROC_MASK ;
+
+ if (p_data->api_reg.p_cback)
+ {
+ p_data->api_reg.p_cback(BTA_HL_SDP_INFO_IND_EVT, (tBTA_HL *) &evt_data);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_api_deregister
+**
+** Description Process the API de-registration request
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_hl_api_deregister(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data)
+{
+
+ UINT8 app_idx;
+ tBTA_HL_APP_CB *p_acb;
+
+ if (bta_hl_find_app_idx_using_handle(p_data->api_dereg.app_handle, &app_idx))
+ {
+ p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ p_acb->deregistering= TRUE;
+ bta_hl_check_deregistration(app_idx,p_data);
+ }
+ else
+ {
+ APPL_TRACE_ERROR1("Inavlide app_handle=%d", p_data->api_dereg.app_handle);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_api_cch_open
+**
+** Description Process the API CCH open request
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_hl_api_cch_open(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data)
+{
+ tBTA_HL evt_data;
+ tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+ UINT8 app_idx, mcl_idx;
+ tBTA_HL_APP_CB *p_acb;
+ tBTA_HL_MCL_CB *p_mcb;
+
+ if (bta_hl_find_app_idx_using_handle(p_data->api_cch_open.app_handle, &app_idx))
+ {
+
+ if (!bta_hl_find_mcl_idx(app_idx, p_data->api_cch_open.bd_addr, &mcl_idx))
+ {
+ if (bta_hl_find_avail_mcl_idx(app_idx, &mcl_idx))
+ {
+ p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ p_mcb->in_use = TRUE;
+ p_mcb->req_ctrl_psm = p_data->api_cch_open.ctrl_psm;
+ p_mcb->sec_mask = p_data->api_cch_open.sec_mask;
+ bdcpy(p_mcb->bd_addr, p_data->api_cch_open.bd_addr);
+ p_mcb->cch_oper = BTA_HL_CCH_OP_LOCAL_OPEN;
+ }
+ else
+ {
+ status = BTA_HL_STATUS_NO_RESOURCE;
+ }
+ }
+ else
+ {
+ /* Only one MCL per BD_ADDR */
+ status = BTA_HL_STATUS_FAIL;
+ }
+ }
+ else
+ {
+ status = BTA_HL_STATUS_INVALID_APP_HANDLE;
+ }
+#if BTA_HL_DEBUG == TRUE
+ if (status != BTA_HL_STATUS_OK)
+ {
+ APPL_TRACE_DEBUG1("bta_hl_api_cch_open status =%s", bta_hl_status_code(status));
+ }
+#endif
+ switch (status)
+ {
+ case BTA_HL_STATUS_OK:
+ bta_hl_cch_sm_execute(app_idx, mcl_idx, BTA_HL_CCH_OPEN_EVT, p_data);
+ break;
+ case BTA_HL_STATUS_NO_RESOURCE:
+ case BTA_HL_STATUS_FAIL:
+ bta_hl_build_cch_open_cfm(&evt_data, p_data->api_cch_open.app_handle,
+ 0,
+ p_data->api_cch_open.bd_addr,
+ status);
+ p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ p_acb->p_cback(BTA_HL_CCH_OPEN_CFM_EVT,(tBTA_HL *) &evt_data );
+ break;
+ default:
+ APPL_TRACE_ERROR1("status code=%d", status);
+ break;
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_api_cch_close
+**
+** Description Process the API CCH close request
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_hl_api_cch_close(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data)
+{
+ tBTA_HL evt_data;
+ tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+ UINT8 app_idx, mcl_idx;
+ tBTA_HL_APP_CB *p_acb;
+ tBTA_HL_MCL_CB *p_mcb;
+
+ if (bta_hl_find_mcl_idx_using_handle(p_data->api_cch_close.mcl_handle, &app_idx, &mcl_idx))
+ {
+ p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ p_mcb->cch_oper = BTA_HL_CCH_OP_LOCAL_CLOSE;
+ }
+ else
+ {
+ status = BTA_HL_STATUS_INVALID_MCL_HANDLE;
+ }
+#if BTA_HL_DEBUG == TRUE
+ if (status != BTA_HL_STATUS_OK)
+ {
+ APPL_TRACE_DEBUG1("bta_hl_api_cch_close status =%s", bta_hl_status_code(status));
+ }
+#endif
+ switch (status)
+ {
+ case BTA_HL_STATUS_OK:
+ bta_hl_check_cch_close(app_idx, mcl_idx, p_data, TRUE);
+ break;
+
+ case BTA_HL_STATUS_FAIL:
+ p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ bta_hl_build_cch_close_cfm(&evt_data,
+ p_acb->app_handle,
+ p_data->api_cch_close.mcl_handle,
+ status);
+ p_acb->p_cback(BTA_HL_CCH_CLOSE_CFM_EVT,(tBTA_HL *) &evt_data );
+ break;
+
+ default:
+ APPL_TRACE_ERROR1("status code=%d", status);
+ break;
+
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_api_dch_open
+**
+** Description Process the API DCH open request
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_hl_api_dch_open(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data)
+{
+ tBTA_HL evt_data;
+ tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+ UINT8 app_idx, mcl_idx, mdl_idx;
+ tBTA_HL_APP_CB *p_acb;
+ tBTA_HL_MCL_CB *p_mcb;
+ tBTA_HL_MDL_CB *p_dcb;
+ tBTA_HL_MDEP_CFG *p_mdep_cfg;
+ UINT8 mdep_cfg_idx;
+
+ if (bta_hl_find_mcl_idx_using_handle(p_data->api_dch_open.mcl_handle, &app_idx, &mcl_idx))
+ {
+ p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+
+ if (p_mcb->cch_state == BTA_HL_CCH_OPEN_ST)
+ {
+ if (bta_hl_find_avail_mdl_idx(app_idx, mcl_idx, &mdl_idx))
+ {
+ p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+ if (bta_hl_find_mdep_cfg_idx(app_idx, p_data->api_dch_open.local_mdep_id, &mdep_cfg_idx))
+ {
+ if ( mdep_cfg_idx &&
+ (p_acb->sup_feature.mdep[mdep_cfg_idx].mdep_cfg.mdep_role == BTA_HL_MDEP_ROLE_SINK))
+ {
+ p_data->api_dch_open.local_cfg = BTA_HL_DCH_CFG_NO_PREF;
+ }
+
+ if ((status = bta_hl_chk_local_cfg(app_idx,mcl_idx,mdep_cfg_idx,p_data->api_dch_open.local_cfg))
+ == BTA_HL_STATUS_OK)
+ {
+
+ if (p_data->api_dch_open.local_mdep_id != BTA_HL_ECHO_TEST_MDEP_ID)
+ {
+ if (bta_hl_set_ctrl_psm_for_dch(app_idx, mcl_idx, mdl_idx, p_data->api_dch_open.ctrl_psm))
+ {
+ p_mdep_cfg = BTA_HL_GET_MDEP_CFG_PTR(app_idx, mdep_cfg_idx);
+ p_dcb->in_use = TRUE;
+ p_dcb->dch_oper = BTA_HL_DCH_OP_LOCAL_OPEN;
+ p_dcb->sec_mask = p_data->api_dch_open.sec_mask;
+ p_dcb->local_mdep_id = p_data->api_dch_open.local_mdep_id;
+ p_dcb->peer_mdep_id = p_data->api_dch_open.peer_mdep_id;
+
+ if (p_mdep_cfg->mdep_role == BTA_HL_MDEP_ROLE_SINK)
+ {
+ p_dcb->peer_mdep_role = BTA_HL_MDEP_ROLE_SOURCE;
+ }
+ else
+ {
+ p_dcb->peer_mdep_role = BTA_HL_MDEP_ROLE_SINK;
+ }
+
+ p_dcb->local_mdep_cfg_idx = mdep_cfg_idx;
+ p_dcb->local_cfg = p_data->api_dch_open.local_cfg;
+
+ bta_hl_find_rxtx_apdu_size(app_idx, mdep_cfg_idx,
+ &p_dcb->max_rx_apdu_size,
+ &p_dcb->max_tx_apdu_size);
+ p_dcb->mdl_id = bta_hl_allocate_mdl_id(app_idx,mcl_idx,mdl_idx);
+ p_dcb->mdl_cfg_idx_included = FALSE;
+ }
+ else
+ {
+ status = BTA_HL_STATUS_INVALID_CTRL_PSM;
+ }
+
+ }
+ else
+ {
+ status = BTA_HL_STATUS_INVALID_LOCAL_MDEP_ID;
+ }
+ }
+ }
+ else
+ {
+ status = BTA_HL_STATUS_INVALID_LOCAL_MDEP_ID;
+ }
+ }
+ else
+ {
+ status = BTA_HL_STATUS_NO_RESOURCE;
+ }
+ }
+ else
+ {
+ status = BTA_HL_STATUS_NO_CCH;
+ }
+ }
+ else
+ {
+ status = BTA_HL_STATUS_INVALID_MCL_HANDLE;
+ }
+
+#if BTA_HL_DEBUG == TRUE
+ if (status != BTA_HL_STATUS_OK)
+ {
+ APPL_TRACE_DEBUG1("bta_hl_api_dch_open status =%s", bta_hl_status_code(status));
+ }
+#endif
+ switch (status)
+ {
+ case BTA_HL_STATUS_OK:
+ if (p_mcb->sdp.num_recs)
+ {
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_OPEN_EVT, p_data);
+ }
+ else
+ {
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_SDP_INIT_EVT, p_data);
+ }
+ break;
+ case BTA_HL_STATUS_INVALID_DCH_CFG:
+ case BTA_HL_STATUS_NO_FIRST_RELIABLE:
+ case BTA_HL_STATUS_NO_CCH:
+ case BTA_HL_STATUS_NO_RESOURCE:
+ case BTA_HL_STATUS_FAIL:
+ case BTA_HL_STATUS_INVALID_LOCAL_MDEP_ID:
+ case BTA_HL_STATUS_INVALID_CTRL_PSM:
+ p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ bta_hl_build_dch_open_cfm(&evt_data,
+ p_acb->app_handle,
+ p_data->api_dch_open.mcl_handle,
+ BTA_HL_INVALID_MDL_HANDLE,
+ 0,0,0,0,0, status);
+ p_acb->p_cback(BTA_HL_DCH_OPEN_CFM_EVT,(tBTA_HL *) &evt_data );
+ break;
+ default:
+ APPL_TRACE_ERROR1("Status code=%d", status);
+ break;
+
+ }
+
+}
+/*******************************************************************************
+**
+** Function bta_hl_api_dch_close
+**
+** Description Process the API DCH close request
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_hl_api_dch_close(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data)
+{
+ tBTA_HL evt_data;
+ tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+ UINT8 app_idx, mcl_idx, mdl_idx;
+ tBTA_HL_APP_CB *p_acb;
+ tBTA_HL_MCL_CB *p_mcb;
+ tBTA_HL_MDL_CB *p_dcb;
+
+
+ if (bta_hl_find_mdl_idx_using_handle(p_data->api_dch_close.mdl_handle, &app_idx, &mcl_idx, &mdl_idx ))
+ {
+ p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ if (p_dcb->dch_state != BTA_HL_DCH_OPEN_ST)
+ {
+ status = BTA_HL_STATUS_FAIL;
+ }
+ }
+ else
+ {
+ status = BTA_HL_STATUS_INVALID_MDL_HANDLE;
+ }
+
+#if BTA_HL_DEBUG == TRUE
+ if (status != BTA_HL_STATUS_OK)
+ {
+ APPL_TRACE_DEBUG1("bta_hl_api_dch_close status =%s", bta_hl_status_code(status));
+ }
+#endif
+
+ switch (status)
+ {
+ case BTA_HL_STATUS_OK:
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_EVT, p_data);
+ break;
+ case BTA_HL_STATUS_FAIL:
+ p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ bta_hl_build_dch_close_cfm(&evt_data,
+ p_acb->app_handle,
+ p_mcb->mcl_handle,
+ p_data->api_dch_close.mdl_handle,
+ status);
+
+ p_acb->p_cback(BTA_HL_DCH_CLOSE_CFM_EVT,(tBTA_HL *) &evt_data );
+ break;
+ default:
+ APPL_TRACE_ERROR1("Status code=%d", status);
+ break;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function bta_hl_api_dch_reconnect
+**
+** Description Process the API DCH reconnect request
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_hl_api_dch_reconnect(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data)
+{
+ tBTA_HL evt_data;
+ tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+ UINT8 app_idx, mcl_idx, mdl_idx;
+ tBTA_HL_APP_CB *p_acb;
+ tBTA_HL_MCL_CB *p_mcb;
+ tBTA_HL_MDL_CB *p_dcb;
+ UINT8 mdep_cfg_idx;
+ UINT8 mdl_cfg_idx;
+
+ if (bta_hl_find_mcl_idx_using_handle(p_data->api_dch_open.mcl_handle, &app_idx, &mcl_idx))
+ {
+ p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ if (p_mcb->cch_state == BTA_HL_CCH_OPEN_ST)
+ {
+ if (bta_hl_find_avail_mdl_idx(app_idx, mcl_idx, &mdl_idx))
+ {
+ p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ if (bta_hl_validate_reconnect_params(app_idx, mcl_idx, &(p_data->api_dch_reconnect),
+ &mdep_cfg_idx, &mdl_cfg_idx ))
+ {
+ if (!bta_hl_is_the_first_reliable_existed(app_idx, mcl_idx) &&
+ (p_acb->mdl_cfg[mdl_cfg_idx].dch_mode != BTA_HL_DCH_MODE_RELIABLE))
+ {
+ status = BTA_HL_STATUS_NO_FIRST_RELIABLE;
+ }
+ else
+ {
+ if (bta_hl_set_ctrl_psm_for_dch(app_idx, mcl_idx, mdl_idx, p_data->api_dch_open.ctrl_psm))
+ {
+ p_dcb->in_use = TRUE;
+ p_dcb->dch_oper = BTA_HL_DCH_OP_LOCAL_RECONNECT;
+ p_dcb->sec_mask = (BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
+ p_dcb->local_mdep_id = p_acb->mdl_cfg[mdl_cfg_idx].local_mdep_id;
+ p_dcb->local_mdep_cfg_idx = mdep_cfg_idx;
+ p_dcb->local_cfg = BTA_HL_DCH_CFG_UNKNOWN;
+ p_dcb->mdl_id = p_data->api_dch_reconnect.mdl_id;
+ p_dcb->mdl_cfg_idx_included = TRUE;
+ p_dcb->mdl_cfg_idx = mdl_cfg_idx;
+ p_dcb->dch_mode = p_acb->mdl_cfg[mdl_cfg_idx].dch_mode;
+ bta_hl_find_rxtx_apdu_size(app_idx, mdep_cfg_idx,
+ &p_dcb->max_rx_apdu_size,
+ &p_dcb->max_tx_apdu_size);
+ }
+ else
+ {
+ status = BTA_HL_STATUS_INVALID_CTRL_PSM;
+ }
+ }
+ }
+ else
+ {
+ status = BTA_HL_STATUS_INVALID_RECONNECT_CFG;
+ }
+ }
+ else
+ {
+ status = BTA_HL_STATUS_NO_RESOURCE;
+ }
+ }
+ else
+ {
+ status = BTA_HL_STATUS_NO_CCH;
+ }
+ }
+ else
+ {
+ status = BTA_HL_STATUS_INVALID_MCL_HANDLE;
+ }
+
+#if BTA_HL_DEBUG == TRUE
+ if (status != BTA_HL_STATUS_OK)
+ {
+ APPL_TRACE_DEBUG1("bta_hl_api_dch_reconnect status=%s", bta_hl_status_code(status));
+ }
+#endif
+
+ switch (status)
+ {
+ case BTA_HL_STATUS_OK:
+ if (p_mcb->sdp.num_recs)
+ {
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_RECONNECT_EVT, p_data);
+ }
+ else
+ {
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_SDP_INIT_EVT, p_data);
+ }
+ break;
+ case BTA_HL_STATUS_INVALID_RECONNECT_CFG:
+ case BTA_HL_STATUS_NO_FIRST_RELIABLE:
+ case BTA_HL_STATUS_NO_CCH:
+ case BTA_HL_STATUS_NO_RESOURCE:
+ p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ bta_hl_build_dch_open_cfm(&evt_data,
+ p_acb->app_handle,
+ p_data->api_dch_reconnect.mcl_handle,
+ BTA_HL_INVALID_MDL_HANDLE,
+ 0,p_data->api_dch_reconnect.mdl_id,0,0,0, status);
+ p_acb->p_cback(BTA_HL_DCH_RECONNECT_CFM_EVT,(tBTA_HL *) &evt_data );
+ break;
+ default:
+ APPL_TRACE_ERROR1("Status code=%d", status);
+ break;
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_api_dch_echo_test
+**
+** Description Process the API Echo test request
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_hl_api_dch_echo_test(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data)
+{
+ tBTA_HL evt_data;
+ tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+ UINT8 app_idx, mcl_idx, mdl_idx;
+ tBTA_HL_APP_CB *p_acb;
+ tBTA_HL_MCL_CB *p_mcb;
+ tBTA_HL_MDL_CB *p_dcb;
+ tBTA_HL_ECHO_CFG *p_echo_cfg;
+
+
+ if (bta_hl_find_mcl_idx_using_handle(p_data->api_dch_echo_test.mcl_handle, &app_idx, &mcl_idx))
+ {
+ p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ if (p_mcb->cch_state == BTA_HL_CCH_OPEN_ST)
+ {
+ if (!p_mcb->echo_test )
+ {
+ if (bta_hl_find_avail_mdl_idx(app_idx, mcl_idx, &mdl_idx))
+ {
+ p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+ if ((p_data->api_dch_echo_test.local_cfg == BTA_HL_DCH_CFG_RELIABLE) ||
+ (p_data->api_dch_echo_test.local_cfg == BTA_HL_DCH_CFG_STREAMING))
+ {
+ if ((p_dcb->p_echo_tx_pkt = bta_hl_get_buf(p_data->api_dch_echo_test.pkt_size)) != NULL )
+ {
+ if (bta_hl_set_ctrl_psm_for_dch(app_idx, mcl_idx, mdl_idx, p_data->api_dch_open.ctrl_psm))
+ {
+ p_dcb->in_use = TRUE;
+ p_dcb->dch_oper = BTA_HL_DCH_OP_LOCAL_OPEN;
+ p_dcb->sec_mask = (BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
+ p_dcb->local_mdep_cfg_idx = BTA_HL_ECHO_TEST_MDEP_CFG_IDX;
+ p_dcb->local_cfg = p_data->api_dch_echo_test.local_cfg;
+ p_dcb->local_mdep_id = BTA_HL_ECHO_TEST_MDEP_ID;
+ p_dcb->peer_mdep_id = BTA_HL_ECHO_TEST_MDEP_ID;
+ p_dcb->mdl_id = bta_hl_allocate_mdl_id(app_idx,mcl_idx,mdl_idx);
+ p_dcb->mdl_cfg_idx_included = FALSE;
+ p_echo_cfg = BTA_HL_GET_ECHO_CFG_PTR(app_idx);
+ p_dcb->max_rx_apdu_size = p_echo_cfg->max_rx_apdu_size;
+ p_dcb->max_tx_apdu_size = p_echo_cfg->max_tx_apdu_size;
+ p_mcb->echo_test = TRUE;
+ p_mcb->echo_mdl_idx = mdl_idx;
+ }
+ else
+ {
+ status = BTA_HL_STATUS_INVALID_CTRL_PSM;
+ }
+ }
+ else
+ {
+ status = BTA_HL_STATUS_NO_RESOURCE;
+ }
+ }
+ else
+ {
+ status = BTA_HL_STATUS_INVALID_DCH_CFG;
+ }
+ }
+ else
+ {
+ status = BTA_HL_STATUS_NO_RESOURCE;
+ }
+ }
+ else
+ {
+ status = BTA_HL_STATUS_ECHO_TEST_BUSY;
+ }
+ }
+ else
+ {
+ status = BTA_HL_STATUS_NO_CCH;
+ }
+ }
+ else
+ {
+ status = BTA_HL_STATUS_NO_MCL;
+ }
+
+#if BTA_HL_DEBUG == TRUE
+ if (status != BTA_HL_STATUS_OK)
+ {
+ APPL_TRACE_DEBUG1("bta_hl_api_dch_echo_test status=%s", bta_hl_status_code(status));
+ }
+#endif
+
+ switch (status)
+ {
+ case BTA_HL_STATUS_OK:
+ if (p_mcb->sdp.num_recs)
+ {
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_ECHO_TEST_EVT, p_data);
+ }
+ else
+ {
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_SDP_INIT_EVT, p_data);
+ }
+ break;
+ case BTA_HL_STATUS_NO_CCH:
+ case BTA_HL_STATUS_ECHO_TEST_BUSY:
+ case BTA_HL_STATUS_NO_RESOURCE:
+ case BTA_HL_STATUS_INVALID_DCH_CFG:
+ bta_hl_build_echo_test_cfm(&evt_data,
+ p_acb->app_handle,
+ p_mcb->mcl_handle,
+ status);
+ p_acb->p_cback(BTA_HL_DCH_ECHO_TEST_CFM_EVT,(tBTA_HL *) &evt_data );
+ break;
+
+ default:
+ APPL_TRACE_ERROR1("Status code=%s", status);
+ break;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function bta_hl_api_sdp_query
+**
+** Description Process the API SDP query request
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_hl_api_sdp_query(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data)
+{
+ tBTA_HL evt_data;
+ tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+ UINT8 app_idx, mcl_idx;
+ tBTA_HL_APP_CB *p_acb;
+ tBTA_HL_MCL_CB *p_mcb;
+
+
+ if (bta_hl_find_app_idx_using_handle(p_data->api_sdp_query.app_handle, &app_idx))
+ {
+ if (!bta_hl_find_mcl_idx(app_idx, p_data->api_sdp_query.bd_addr, &mcl_idx))
+ {
+ if (bta_hl_find_avail_mcl_idx(app_idx, &mcl_idx))
+ {
+ p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ p_mcb->in_use = TRUE;
+ bdcpy(p_mcb->bd_addr, p_data->api_sdp_query.bd_addr);
+ p_mcb->sdp_oper = BTA_HL_SDP_OP_SDP_QUERY_NEW ;
+ }
+ else
+ {
+ status = BTA_HL_STATUS_NO_RESOURCE;
+ }
+ }
+ else
+ {
+ p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ if (p_mcb->sdp_oper != BTA_HL_SDP_OP_NONE)
+ {
+ status = BTA_HL_STATUS_SDP_NO_RESOURCE;
+ }
+ else
+ {
+ p_mcb->sdp_oper = BTA_HL_SDP_OP_SDP_QUERY_CURRENT;
+ }
+ }
+ }
+ else
+ {
+ status = BTA_HL_STATUS_INVALID_APP_HANDLE;
+ }
+
+ if (status == BTA_HL_STATUS_OK)
+ {
+ status = bta_hl_init_sdp( p_mcb->sdp_oper, app_idx, mcl_idx, 0xFF);
+ if ( (status != BTA_HL_STATUS_OK) &&
+ (p_mcb->sdp_oper == BTA_HL_SDP_OP_SDP_QUERY_NEW) )
+ {
+ memset(p_mcb, 0 ,sizeof(tBTA_HL_MCL_CB));
+ }
+ }
+#if BTA_HL_DEBUG == TRUE
+ if (status != BTA_HL_STATUS_OK)
+ {
+ APPL_TRACE_DEBUG1("bta_hl_api_sdp_query status=%s", bta_hl_status_code(status));
+ }
+#endif
+ switch (status)
+ {
+ case BTA_HL_STATUS_NO_RESOURCE:
+ case BTA_HL_STATUS_FAIL:
+ case BTA_HL_STATUS_SDP_NO_RESOURCE:
+ bta_hl_build_sdp_query_cfm(&evt_data,
+ p_data->api_sdp_query.app_handle,
+ p_data->api_sdp_query.bd_addr,
+ NULL,
+ status);
+ p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ p_acb->p_cback(BTA_HL_SDP_QUERY_CFM_EVT,(tBTA_HL *) &evt_data );
+ break;
+ case BTA_HL_STATUS_OK:
+ break;
+ default:
+ APPL_TRACE_ERROR1("Status code=%d", status);
+ break;
+ }
+}
+
+
+
+
+/*******************************************************************************
+**
+** Function bta_hl_sdp_query_results
+**
+** Description Process the SDP query results
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_hl_sdp_query_results(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data)
+{
+ tBTA_HL evt_data;
+ tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+ UINT8 app_idx = p_data->cch_sdp.app_idx;
+ UINT8 mcl_idx = p_data->cch_sdp.mcl_idx;
+ tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR( app_idx);
+ tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR( app_idx, mcl_idx);
+ tBTA_HL_SDP *p_sdp=NULL;
+ tBTA_HL_SDP_OPER sdp_oper;
+ UINT16 event;
+ BOOLEAN release_sdp_buf=FALSE;
+
+ event = p_data->hdr.event;
+ sdp_oper = p_mcb->sdp_oper;
+
+ if ( event == BTA_HL_SDP_QUERY_OK_EVT)
+ {
+ if ((p_sdp = (tBTA_HL_SDP *)GKI_getbuf((UINT16)(sizeof(tBTA_HL_SDP)))) != NULL)
+ {
+ memcpy(p_sdp, &p_mcb->sdp, sizeof(tBTA_HL_SDP));
+ release_sdp_buf = TRUE;
+ }
+ else
+ {
+ status = BTA_HL_STATUS_SDP_NO_RESOURCE;
+ }
+ }
+ else
+ {
+ status = BTA_HL_STATUS_SDP_FAIL;
+ }
+
+#if BTA_HL_DEBUG == TRUE
+ if (status != BTA_HL_STATUS_OK)
+ {
+ APPL_TRACE_DEBUG1("bta_hl_sdp_query_results status=%s", bta_hl_status_code(status));
+ }
+#endif
+
+ bta_hl_build_sdp_query_cfm(&evt_data,p_acb->app_handle,
+ p_mcb->bd_addr,p_sdp,status);
+ p_acb->p_cback(BTA_HL_SDP_QUERY_CFM_EVT,(tBTA_HL *) &evt_data );
+
+ if (release_sdp_buf)
+ {
+ utl_freebuf((void **) &p_sdp);
+ }
+
+ if (p_data->cch_sdp.release_mcl_cb)
+ {
+ memset(p_mcb, 0 ,sizeof(tBTA_HL_MCL_CB));
+ }
+ else
+ {
+ if (p_mcb->close_pending)
+ {
+ bta_hl_check_cch_close(app_idx,mcl_idx,p_data, TRUE);
+ }
+
+ if (!p_mcb->ctrl_psm)
+ {
+ /* this is a control channel acceptor do not store the sdp records*/
+ memset(&p_mcb->sdp, 0, sizeof(tBTA_HL_SDP));
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function bta_hl_api_delete_mdl
+**
+** Description Process the API DELETE MDL request
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_hl_api_delete_mdl(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data)
+{
+ tBTA_HL evt_data;
+ tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+ UINT8 app_idx, mcl_idx;
+ tBTA_HL_APP_CB *p_acb;
+ tBTA_HL_MCL_CB *p_mcb;
+
+ if (bta_hl_find_mcl_idx_using_handle(p_data->api_delete_mdl.mcl_handle, &app_idx, &mcl_idx ))
+ {
+ if (bta_hl_is_mdl_value_valid(p_data->api_delete_mdl.mdl_id))
+ {
+ p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ if (bta_hl_is_mdl_exsit_in_mcl(app_idx,
+ p_mcb->bd_addr,
+ p_data->api_delete_mdl.mdl_id))
+ {
+
+
+ p_mcb->delete_mdl.mcl_handle = p_data->api_delete_mdl.mcl_handle;
+ p_mcb->delete_mdl.mdl_id = p_data->api_delete_mdl.mdl_id;
+ p_mcb->delete_mdl.delete_req_pending = TRUE;
+
+ if (MCA_Delete((tMCA_CL) p_mcb->mcl_handle,
+ p_data->api_delete_mdl.mdl_id)!= MCA_SUCCESS)
+ {
+ status = BTA_HL_STATUS_FAIL;
+ memset(&p_mcb->delete_mdl, 0, sizeof(tBTA_HL_DELETE_MDL));
+ }
+ }
+ else
+ {
+ status = BTA_HL_STATUS_NO_MDL_ID_FOUND;
+ }
+ }
+ else
+ {
+ status = BTA_HL_STATUS_INVALID_MDL_ID;
+ }
+ }
+ else
+ {
+ status = BTA_HL_STATUS_INVALID_MCL_HANDLE;
+ }
+
+#if BTA_HL_DEBUG == TRUE
+ if (status != BTA_HL_STATUS_OK)
+ {
+ APPL_TRACE_DEBUG1("bta_hl_api_delete_mdl status=%s", bta_hl_status_code(status));
+ }
+#endif
+ switch (status)
+ {
+ case BTA_HL_STATUS_OK:
+ break;
+ case BTA_HL_STATUS_FAIL:
+ case BTA_HL_STATUS_NO_MDL_ID_FOUND:
+ case BTA_HL_STATUS_INVALID_MDL_ID:
+ p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ bta_hl_build_delete_mdl_cfm(&evt_data,
+ p_acb->app_handle,
+ p_data->api_delete_mdl.mcl_handle,
+ p_data->api_delete_mdl.mdl_id,
+ status);
+
+ p_acb->p_cback(BTA_HL_DELETE_MDL_CFM_EVT,(tBTA_HL *) &evt_data );
+ break;
+ case BTA_HL_STATUS_INVALID_APP_HANDLE:
+ default:
+ APPL_TRACE_ERROR1("status code =%d", status);
+ break;
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_mca_delete_mdl_cfm
+**
+** Description Process the DELETE MDL confirmation event
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_hl_mca_delete_mdl_cfm(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data)
+{
+ tBTA_HL evt_data;
+ tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+ UINT8 app_idx, mcl_idx;
+ tMCA_RSP_EVT *p_delete_cfm = &p_data->mca_evt.mca_data.delete_cfm;
+ tBTA_HL_MCL_CB *p_mcb;
+ BOOLEAN send_cfm_evt = TRUE;
+ tBTA_HL_APP_CB *p_acb;
+
+ if (bta_hl_find_mcl_idx_using_handle(p_data->mca_evt.mcl_handle, &app_idx, &mcl_idx))
+ {
+ p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ if ( p_mcb->delete_mdl.delete_req_pending)
+ {
+ if (p_delete_cfm->rsp_code == MCA_RSP_SUCCESS )
+ {
+
+ if (!bta_hl_delete_mdl_cfg(app_idx,
+ p_mcb->bd_addr ,
+ p_delete_cfm->mdl_id))
+ {
+ status = BTA_HL_STATUS_FAIL;
+ }
+ }
+ else
+ {
+ status = BTA_HL_STATUS_FAIL;
+ }
+
+ memset(&p_mcb->delete_mdl, 0, sizeof(tBTA_HL_DELETE_MDL));
+ }
+ else
+ {
+ send_cfm_evt = FALSE;
+ }
+ }
+ else
+ {
+ send_cfm_evt = FALSE;
+ }
+
+#if BTA_HL_DEBUG == TRUE
+ if (status != BTA_HL_STATUS_OK)
+ {
+ APPL_TRACE_DEBUG1("bta_hl_api_delete_mdl status=%s", bta_hl_status_code(status));
+ }
+#endif
+
+ if (send_cfm_evt)
+ {
+ p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ bta_hl_build_delete_mdl_cfm(&evt_data,
+ p_acb->app_handle,
+ p_mcb->mcl_handle,
+ p_delete_cfm->mdl_id,
+ status);
+
+ p_acb->p_cback(BTA_HL_DELETE_MDL_CFM_EVT,(tBTA_HL *) &evt_data );
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_mca_delete_mdl_ind
+**
+** Description Process the DELETE MDL indication event
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_hl_mca_delete_mdl_ind(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data)
+{
+ tBTA_HL evt_data;
+ UINT8 app_idx, mcl_idx, mdl_idx;
+ tMCA_EVT_HDR *p_delete_ind = &p_data->mca_evt.mca_data.delete_ind;
+ tBTA_HL_MCL_CB *p_mcb;
+ tBTA_HL_MDL_CB *p_dcb;
+ BOOLEAN send_ind_evt = TRUE;
+ tBTA_HL_APP_CB *p_acb;
+
+ if (bta_hl_find_mcl_idx_using_handle(p_data->mca_evt.mcl_handle, &app_idx, &mcl_idx) )
+ {
+ p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+
+ if (bta_hl_find_mdl_idx(app_idx, mcl_idx, p_delete_ind->mdl_id, &mdl_idx ))
+ {
+ p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ p_dcb->dch_oper = BTA_HL_DCH_OP_REMOTE_DELETE;
+ }
+ if (bta_hl_delete_mdl_cfg(app_idx,
+ p_mcb->bd_addr ,
+ p_delete_ind->mdl_id))
+ {
+ send_ind_evt = TRUE;
+ }
+ }
+
+#if BTA_HL_DEBUG == TRUE
+ if (!send_ind_evt)
+ {
+ APPL_TRACE_DEBUG1("bta_hl_mca_delete_mdl_ind is_send_ind_evt =%d", send_ind_evt);
+ }
+#endif
+
+ if (send_ind_evt)
+ {
+ p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ evt_data.delete_mdl_ind.mcl_handle = p_mcb->mcl_handle;
+ evt_data.delete_mdl_ind.app_handle = p_acb->app_handle;
+ evt_data.delete_mdl_ind.mdl_id = p_delete_ind->mdl_id;
+ p_acb->p_cback(BTA_HL_DELETE_MDL_IND_EVT,(tBTA_HL *) &evt_data );
+ }
+}
+
+
+
+/*******************************************************************************
+**
+** Function bta_hl_api_dch_abort
+**
+** Description Process the API DCH abort request
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_hl_api_dch_abort(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data)
+{
+
+ tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+ UINT8 app_idx, mcl_idx, mdl_idx;
+ tBTA_HL_APP_CB *p_acb;
+ tBTA_HL_MCL_CB *p_mcb;
+ tBTA_HL_MDL_CB *p_dcb;
+ tBTA_HL evt_data;
+
+
+ if (bta_hl_find_mcl_idx_using_handle(p_data->api_dch_abort.mcl_handle, &app_idx, &mcl_idx ))
+ {
+
+ if (!bta_hl_find_dch_setup_mdl_idx(app_idx, mcl_idx, &mdl_idx ))
+ {
+ status = BTA_HL_STATUS_NO_MDL_ID_FOUND;
+ }
+ else
+ {
+ p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ if (p_dcb->abort_oper)
+ {
+ /* abort already in progress*/
+ status = BTA_HL_STATUS_FAIL;
+ }
+ else
+ {
+ p_dcb->abort_oper = BTA_HL_ABORT_LOCAL_MASK;
+ }
+ }
+ }
+ else
+ {
+ status = BTA_HL_STATUS_INVALID_MCL_HANDLE;
+ }
+
+
+#if BTA_HL_DEBUG == TRUE
+ if (status != BTA_HL_STATUS_OK)
+ {
+ APPL_TRACE_DEBUG1("bta_hl_api_dch_abort status=%s", bta_hl_status_code(status));
+ }
+#endif
+ switch (status)
+ {
+ case BTA_HL_STATUS_OK:
+
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_ABORT_EVT, p_data);
+ break;
+ case BTA_HL_STATUS_NO_MDL_ID_FOUND:
+ case BTA_HL_STATUS_FAIL:
+
+ p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ bta_hl_build_abort_cfm(&evt_data,
+ p_acb->app_handle,
+ p_mcb->mcl_handle,
+ BTA_HL_STATUS_FAIL);
+ p_acb->p_cback(BTA_HL_DCH_ABORT_CFM_EVT,(tBTA_HL *) &evt_data );
+ break;
+ case BTA_HL_STATUS_INVALID_BD_ADDR:
+ case BTA_HL_STATUS_INVALID_APP_HANDLE:
+ default:
+ APPL_TRACE_ERROR1("Status code=%d", status);
+ break;
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_hdl_event
+**
+** Description HL main event handling function.
+**
+** Returns void
+**
+*******************************************************************************/
+BOOLEAN bta_hl_hdl_event(BT_HDR *p_msg)
+{
+ UINT8 app_idx, mcl_idx, mdl_idx;
+ BOOLEAN success = TRUE;
+
+#if BTA_HL_DEBUG == TRUE
+ APPL_TRACE_DEBUG1("BTA HL Event Handler: Event [%s]",
+ bta_hl_evt_code(p_msg->event));
+#endif
+
+ switch (p_msg->event)
+ {
+ case BTA_HL_API_ENABLE_EVT:
+ bta_hl_api_enable(&bta_hl_cb, (tBTA_HL_DATA *) p_msg);
+ break;
+ case BTA_HL_API_DISABLE_EVT:
+ bta_hl_api_disable(&bta_hl_cb, (tBTA_HL_DATA *) p_msg);
+ break;
+ case BTA_HL_API_REGISTER_EVT:
+ bta_hl_api_register(&bta_hl_cb, (tBTA_HL_DATA *) p_msg);
+ break;
+ case BTA_HL_API_DEREGISTER_EVT:
+ bta_hl_api_deregister(&bta_hl_cb, (tBTA_HL_DATA *) p_msg);
+ break;
+ case BTA_HL_API_CCH_OPEN_EVT:
+ bta_hl_api_cch_open(&bta_hl_cb, (tBTA_HL_DATA *) p_msg);
+ break;
+ case BTA_HL_API_CCH_CLOSE_EVT:
+ bta_hl_api_cch_close(&bta_hl_cb, (tBTA_HL_DATA *) p_msg);
+ break;
+ case BTA_HL_API_DCH_OPEN_EVT:
+ bta_hl_api_dch_open(&bta_hl_cb, (tBTA_HL_DATA *) p_msg);
+ break;
+ case BTA_HL_API_DCH_CLOSE_EVT:
+ bta_hl_api_dch_close(&bta_hl_cb, (tBTA_HL_DATA *) p_msg);
+ break;
+ case BTA_HL_API_DELETE_MDL_EVT:
+ bta_hl_api_delete_mdl(&bta_hl_cb, (tBTA_HL_DATA *) p_msg);
+ break;
+ case BTA_HL_API_DCH_RECONNECT_EVT:
+ bta_hl_api_dch_reconnect(&bta_hl_cb, (tBTA_HL_DATA *) p_msg);
+ break;
+
+ case BTA_HL_API_DCH_ECHO_TEST_EVT:
+ bta_hl_api_dch_echo_test(&bta_hl_cb, (tBTA_HL_DATA *) p_msg);
+ break;
+
+ case BTA_HL_API_SDP_QUERY_EVT:
+ bta_hl_api_sdp_query(&bta_hl_cb, (tBTA_HL_DATA *) p_msg);
+ break;
+
+ case BTA_HL_MCA_DELETE_CFM_EVT:
+ bta_hl_mca_delete_mdl_cfm(&bta_hl_cb, (tBTA_HL_DATA *) p_msg);
+ break;
+
+ case BTA_HL_MCA_DELETE_IND_EVT:
+ bta_hl_mca_delete_mdl_ind(&bta_hl_cb, (tBTA_HL_DATA *) p_msg);
+ break;
+
+ case BTA_HL_SDP_QUERY_OK_EVT:
+ case BTA_HL_SDP_QUERY_FAIL_EVT:
+ bta_hl_sdp_query_results(&bta_hl_cb, (tBTA_HL_DATA *) p_msg);
+ break;
+ case BTA_HL_API_DCH_ABORT_EVT:
+ bta_hl_api_dch_abort(&bta_hl_cb, (tBTA_HL_DATA *) p_msg);
+ break;
+
+
+ default:
+ if (p_msg->event < BTA_HL_DCH_EVT_MIN)
+ {
+ if (bta_hl_find_cch_cb_indexes((tBTA_HL_DATA *) p_msg, &app_idx, &mcl_idx))
+ {
+ bta_hl_cch_sm_execute( app_idx,
+ mcl_idx,
+ p_msg->event, (tBTA_HL_DATA *) p_msg);
+ }
+ else
+ {
+#if BTA_HL_DEBUG == TRUE
+ APPL_TRACE_ERROR1("unable to find control block indexes for CCH: [event=%s]",
+ bta_hl_evt_code(p_msg->event));
+#else
+ APPL_TRACE_ERROR1("unable to find control block indexes for CCH: [event=%d]", p_msg->event);
+#endif
+ success = FALSE;
+ }
+ }
+ else
+ {
+ if (bta_hl_find_dch_cb_indexes((tBTA_HL_DATA *) p_msg, &app_idx, &mcl_idx, &mdl_idx))
+ {
+ bta_hl_dch_sm_execute( app_idx,
+ mcl_idx,
+ mdl_idx,
+ p_msg->event, (tBTA_HL_DATA *) p_msg);
+ }
+ else
+ {
+
+#if BTA_HL_DEBUG == TRUE
+ APPL_TRACE_ERROR1("unable to find control block indexes for DCH : [event=%s]",
+ bta_hl_evt_code(p_msg->event));
+#else
+ APPL_TRACE_ERROR1("unable to find control block indexes for DCH: [event=%d]", p_msg->event);
+#endif
+ success = FALSE;
+ }
+ }
+
+ break;
+ }
+
+ return(success);
+}
+
+
+/*****************************************************************************
+** Debug Functions
+*****************************************************************************/
+#if (BTA_HL_DEBUG == TRUE) && (BT_USE_TRACES == TRUE)
+
+/*******************************************************************************
+**
+** Function bta_hl_cch_state_code
+**
+** Description Map CCH state code to the corresponding state string
+**
+** Returns string pointer for the associated state name
+**
+*******************************************************************************/
+static char *bta_hl_cch_state_code(tBTA_HL_CCH_STATE state_code)
+{
+ switch (state_code)
+ {
+ case BTA_HL_CCH_IDLE_ST:
+ return "BTA_HL_CCH_IDLE_ST";
+ case BTA_HL_CCH_OPENING_ST:
+ return "BTA_HL_CCH_OPENING_ST";
+ case BTA_HL_CCH_OPEN_ST:
+ return "BTA_HL_CCH_OPEN_ST";
+ case BTA_HL_CCH_CLOSING_ST:
+ return "BTA_HL_CCH_CLOSING_ST";
+ default:
+ return "Unknown CCH state code";
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_dch_state_code
+**
+** Description Map DCH state code to the corresponding state string
+**
+** Returns string pointer for the associated state name
+**
+*******************************************************************************/
+static char *bta_hl_dch_state_code(tBTA_HL_DCH_STATE state_code)
+{
+ switch (state_code)
+ {
+ case BTA_HL_DCH_IDLE_ST:
+ return "BTA_HL_DCH_IDLE_ST";
+ case BTA_HL_DCH_OPENING_ST:
+ return "BTA_HL_DCH_OPENING_ST";
+ case BTA_HL_DCH_OPEN_ST:
+ return "BTA_HL_DCH_OPEN_ST";
+ case BTA_HL_DCH_CLOSING_ST:
+ return "BTA_HL_DCH_CLOSING_ST";
+ default:
+ return "Unknown DCH state code";
+ }
+}
+#endif /* Debug Functions */
+#endif /* HL_INCLUDED */
diff --git a/bta/hl/bta_hl_sdp.c b/bta/hl/bta_hl_sdp.c
new file mode 100644
index 0000000..765f6c1
--- /dev/null
+++ b/bta/hl/bta_hl_sdp.c
@@ -0,0 +1,429 @@
+/*****************************************************************************
+**
+** Name: bta_hl_sdp.c
+**
+** File: Implements the SDP functions used by HeaLth device profile
+**
+** Copyright (c) 1998-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include <string.h>
+
+#include "bt_target.h"
+#if defined(HL_INCLUDED) && (HL_INCLUDED == TRUE)
+
+#include "sdp_api.h"
+#include "bta_hl_int.h"
+
+
+/*******************************************************************************
+**
+** Function bta_hl_fill_sup_feature_list
+**
+** Description Fill the supported features from teh SDP record
+**
+** Returns TRUE if found, FALSE if not
+** If found, the passed protocol list element is filled in.
+**
+*******************************************************************************/
+BOOLEAN bta_hl_fill_sup_feature_list( const tSDP_DISC_ATTR *p_attr,
+ tBTA_HL_SUP_FEATURE_LIST_ELEM *p_list)
+{
+ tSDP_DISC_ATTR *p_sattr;
+ UINT8 seq_len, item_cnt;
+ UINT8 list_cnt=0;
+ BOOLEAN status=TRUE;
+
+ for (p_attr = p_attr->attr_value.v.p_sub_attr; p_attr; p_attr = p_attr->p_next_attr)
+ {
+ /* mdep sequence */
+ if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) != DATA_ELE_SEQ_DESC_TYPE)
+ {
+ return(FALSE);
+ }
+ seq_len =SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
+ item_cnt=0;
+
+ for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr && (item_cnt < 4) ; p_sattr = p_sattr->p_next_attr)
+ {
+ /* for each mdep list */
+
+ p_list->list_elem[list_cnt].p_mdep_desp = NULL;
+ switch (item_cnt)
+ {
+ case 0:
+ p_list->list_elem[list_cnt].mdep_id = p_sattr->attr_value.v.u8;
+ break;
+ case 1:
+ p_list->list_elem[list_cnt].data_type = p_sattr->attr_value.v.u16;
+ break;
+ case 2:
+ p_list->list_elem[list_cnt].mdep_role = (tBTA_HL_MDEP_ROLE) p_sattr->attr_value.v.u8;
+ break;
+ case 3:
+ p_list->list_elem[list_cnt].p_mdep_desp = (char *) p_sattr->attr_value.v.array;
+ break;
+ }
+
+ item_cnt++;
+ }
+ list_cnt++;
+ }
+ p_list->num_elems = list_cnt;
+ return(status);
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_compose_supported_feature_list
+**
+** Description This function is called to compose a data sequence from
+** the supported feature element list struct pointer
+**
+** Returns the length of the data sequence
+**
+*******************************************************************************/
+int bta_hl_compose_supported_feature_list( UINT8 *p, UINT16 num_elem,
+ const tBTA_HL_SUP_FEATURE_ELEM *p_elem_list)
+{
+ UINT16 xx, str_len, seq_len;
+ UINT8 *p_head = p;
+
+ for (xx = 0; xx < num_elem; xx++, p_elem_list++)
+ {
+ UINT8_TO_BE_STREAM (p, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
+ seq_len=7;
+ str_len=0;
+ if (p_elem_list->p_mdep_desp)
+ {
+ str_len = strlen(p_elem_list->p_mdep_desp)+1;
+ seq_len += str_len+2; /* todo add a # symbol for 2 */
+ }
+
+ *p++ = (UINT8) seq_len;
+
+ UINT8_TO_BE_STREAM (p, (UINT_DESC_TYPE << 3) | SIZE_ONE_BYTE);
+ UINT8_TO_BE_STREAM (p, p_elem_list->mdep_id);
+ UINT8_TO_BE_STREAM (p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
+ UINT16_TO_BE_STREAM (p, p_elem_list->data_type);
+ UINT8_TO_BE_STREAM (p, (UINT_DESC_TYPE << 3) | SIZE_ONE_BYTE);
+ UINT8_TO_BE_STREAM (p, p_elem_list->mdep_role);
+
+ if (str_len)
+ {
+ UINT8_TO_BE_STREAM (p, (TEXT_STR_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
+ UINT8_TO_BE_STREAM (p, str_len);
+ ARRAY_TO_BE_STREAM(p, p_elem_list->p_mdep_desp, str_len);
+ }
+ }
+
+ return(p - p_head);
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_add_sup_feature_list
+**
+** Description This function is called to add a protocol descriptor list to
+** a record. This would be through the SDP database maintenance API.
+** If the protocol list already exists in the record, it is replaced
+** with the new list.
+**
+** Returns TRUE if added OK, else FALSE
+**
+*******************************************************************************/
+BOOLEAN bta_hl_add_sup_feature_list (UINT32 handle, UINT16 num_elem,
+ const tBTA_HL_SUP_FEATURE_ELEM *p_elem_list)
+{
+ UINT8 *p_buf;
+ int offset;
+ BOOLEAN result = FALSE;
+
+ if ((p_buf = (UINT8 *)GKI_getbuf(BTA_HL_SUP_FEATURE_SDP_BUF_SIZE)) != NULL)
+ {
+ offset = bta_hl_compose_supported_feature_list(p_buf, num_elem, p_elem_list);
+ result = SDP_AddAttribute (handle, ATTR_ID_HDP_SUP_FEAT_LIST,
+ DATA_ELE_SEQ_DESC_TYPE, (UINT32) offset, p_buf);
+ GKI_freebuf(p_buf);
+ }
+ return result;
+}
+/*****************************************************************************
+**
+** Function: bta_hl_sdp_register
+**
+** Purpose: Register an HDP application with SDP
+**
+** Parameters: p_cb - Pointer to MA instance control block
+** p_service_name - MA server name
+** inst_id - MAS instance ID
+** msg_type - Supported message type(s)
+**
+**
+** Returns: void
+**
+*****************************************************************************/
+tBTA_HL_STATUS bta_hl_sdp_register (UINT8 app_idx)
+{
+ UINT16 svc_class_id_list[BTA_HL_NUM_SVC_ELEMS];
+ tSDP_PROTOCOL_ELEM proto_elem_list[BTA_HL_NUM_PROTO_ELEMS];
+ tSDP_PROTO_LIST_ELEM add_proto_list;
+ tBTA_HL_SUP_FEATURE_LIST_ELEM sup_feature_list;
+ UINT16 browse_list[] = {UUID_SERVCLASS_PUBLIC_BROWSE_GROUP};
+ UINT8 i,j, cnt,mdep_id, mdep_role;
+ UINT8 data_exchange_spec = BTA_HL_SDP_IEEE_11073_20601;
+ UINT8 mcap_sup_proc = BTA_HL_MCAP_SUP_PROC_MASK;
+ UINT16 profile_uuid = UUID_SERVCLASS_HDP_PROFILE;
+ UINT16 version = BTA_HL_VERSION_01_00;
+ UINT8 num_services=1;
+ tBTA_HL_APP_CB *p_cb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ BOOLEAN result = TRUE;
+ tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+
+#if BTA_HL_DEBUG == TRUE
+ APPL_TRACE_DEBUG1("bta_hl_sdp_register app_idx=%d",app_idx);
+#endif
+
+ if ((p_cb->sup_feature.app_role_mask == BTA_HL_MDEP_ROLE_MASK_SOURCE) &&
+ (!p_cb->sup_feature.advertize_source_sdp))
+ {
+ return BTA_HL_STATUS_OK;
+ }
+
+ if ((p_cb->sdp_handle = SDP_CreateRecord()) == 0)
+ {
+ return BTA_HL_STATUS_SDP_NO_RESOURCE;
+ }
+
+ num_services=1;
+ svc_class_id_list[0]= UUID_SERVCLASS_HDP_SOURCE;
+ if (p_cb->sup_feature.app_role_mask == BTA_HL_MDEP_ROLE_MASK_SINK)
+ {
+ svc_class_id_list[0]= UUID_SERVCLASS_HDP_SINK;
+ }
+ else
+ {
+ if (p_cb->sup_feature.app_role_mask != BTA_HL_MDEP_ROLE_MASK_SOURCE)
+ {
+ /* dual role */
+ num_services=2;
+ svc_class_id_list[1]= UUID_SERVCLASS_HDP_SINK;
+ }
+ }
+ result &= SDP_AddServiceClassIdList(p_cb->sdp_handle, num_services, svc_class_id_list);
+
+ if (result)
+ {
+ /* add the protocol element sequence */
+ proto_elem_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+ proto_elem_list[0].num_params = 1;
+ proto_elem_list[0].params[0] = p_cb->ctrl_psm;
+ proto_elem_list[1].protocol_uuid = UUID_PROTOCOL_MCAP_CTRL;
+ proto_elem_list[1].num_params = 1;
+ proto_elem_list[1].params[0] = version;
+ result &= SDP_AddProtocolList(p_cb->sdp_handle, BTA_HL_NUM_PROTO_ELEMS, proto_elem_list);
+
+ result &= SDP_AddProfileDescriptorList(p_cb->sdp_handle, profile_uuid, version);
+ }
+
+ if (result)
+ {
+ add_proto_list.num_elems = BTA_HL_NUM_ADD_PROTO_ELEMS;
+ add_proto_list.list_elem[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+ add_proto_list.list_elem[0].num_params = 1;
+ add_proto_list.list_elem[0].params[0] = p_cb->data_psm;
+ add_proto_list.list_elem[1].protocol_uuid = UUID_PROTOCOL_MCAP_DATA;
+ add_proto_list.list_elem[1].num_params = 0;
+ result &= SDP_AddAdditionProtoLists(p_cb->sdp_handle, BTA_HL_NUM_ADD_PROTO_LISTS,
+ (tSDP_PROTO_LIST_ELEM *)&add_proto_list);
+ }
+
+ if (result)
+ {
+ if (p_cb->srv_name[0] )
+ {
+ result &= SDP_AddAttribute(p_cb->sdp_handle,
+ (UINT16)ATTR_ID_SERVICE_NAME,
+ (UINT8)TEXT_STR_DESC_TYPE,
+ (UINT32)(strlen(p_cb->srv_name) + 1),
+ (UINT8 *)p_cb->srv_name);
+ } /* end of setting optional service name */
+ }
+
+ if (result)
+ {
+ if (p_cb->srv_desp[0] )
+ {
+ result &= SDP_AddAttribute(p_cb->sdp_handle,
+ (UINT16)ATTR_ID_SERVICE_DESCRIPTION,
+ (UINT8)TEXT_STR_DESC_TYPE,
+ (UINT32)(strlen(p_cb->srv_desp) + 1),
+ (UINT8 *)p_cb->srv_desp);
+
+ } /* end of setting optional service description */
+
+ }
+
+ if (result)
+ {
+ if (p_cb->provider_name[0] )
+ {
+ result &= SDP_AddAttribute(p_cb->sdp_handle,
+ (UINT16)ATTR_ID_PROVIDER_NAME,
+ (UINT8)TEXT_STR_DESC_TYPE,
+ (UINT32)(strlen(p_cb->provider_name) + 1),
+ (UINT8 *)p_cb->provider_name);
+ } /* end of setting optional provider name */
+ }
+
+ /* add supported feture list */
+
+ if (result)
+ {
+ cnt=0;
+ for (i=1; i<= p_cb->sup_feature.num_of_mdeps; i++)
+ {
+ mdep_id = (UINT8)p_cb->sup_feature.mdep[i].mdep_id;
+ mdep_role = (UINT8)p_cb->sup_feature.mdep[i].mdep_cfg.mdep_role;
+
+ for (j=0; j<p_cb->sup_feature.mdep[i].mdep_cfg.num_of_mdep_data_types; j++)
+ {
+ sup_feature_list.list_elem[cnt].mdep_id = mdep_id;
+ sup_feature_list.list_elem[cnt].mdep_role = mdep_role;
+ sup_feature_list.list_elem[cnt].data_type = p_cb->sup_feature.mdep[i].mdep_cfg.data_cfg[j].data_type;
+ if (p_cb->sup_feature.mdep[i].mdep_cfg.data_cfg[j].desp[0] != '\0')
+ {
+ sup_feature_list.list_elem[cnt].p_mdep_desp = p_cb->sup_feature.mdep[i].mdep_cfg.data_cfg[j].desp;
+ }
+ else
+ {
+ sup_feature_list.list_elem[cnt].p_mdep_desp = NULL;
+ }
+
+ cnt++;
+ if (cnt>BTA_HL_NUM_SUP_FEATURE_ELEMS)
+ {
+ result = FALSE;
+ break;
+ }
+ }
+ }
+ sup_feature_list.num_elems = cnt;
+ result &= bta_hl_add_sup_feature_list (p_cb->sdp_handle,
+ sup_feature_list.num_elems,
+ sup_feature_list.list_elem);
+ }
+ if (result)
+ {
+ result &= SDP_AddAttribute(p_cb->sdp_handle, ATTR_ID_HDP_DATA_EXCH_SPEC, UINT_DESC_TYPE,
+ (UINT32)1, (UINT8*)&data_exchange_spec);
+ }
+
+ if (result)
+ {
+
+ result &= SDP_AddAttribute(p_cb->sdp_handle, ATTR_ID_HDP_MCAP_SUP_PROC, UINT_DESC_TYPE,
+ (UINT32)1, (UINT8*)&mcap_sup_proc);
+ }
+
+ if (result)
+ {
+ result &= SDP_AddUuidSequence(p_cb->sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, browse_list);
+ }
+
+ if (result)
+ {
+ for(i=0; i < num_services; i++)
+ {
+ bta_sys_add_uuid(svc_class_id_list[i]);
+ APPL_TRACE_DEBUG2("dbg bta_sys_add_uuid i=%d uuid=0x%x", i, svc_class_id_list[i]); //todo
+ }
+ }
+ else
+ {
+ if (p_cb->sdp_handle)
+ {
+ SDP_DeleteRecord(p_cb->sdp_handle);
+ p_cb->sdp_handle = 0;
+ }
+ status = BTA_HL_STATUS_SDP_FAIL;
+ }
+#if BTA_HL_DEBUG == TRUE
+ APPL_TRACE_DEBUG1("bta_hl_sdp_register status=%s", bta_hl_status_code(status));
+#endif
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_find_sink_or_src_srv_class_in_db
+**
+** Description This function queries an SDP database for either a HDP Sink or
+** Source service class ID.
+** If the p_start_rec pointer is NULL, it looks from the beginning
+** of the database, else it continues from the next record after
+** p_start_rec.
+**
+** Returns Pointer to record containing service class, or NULL
+**
+*******************************************************************************/
+tSDP_DISC_REC *bta_hl_find_sink_or_src_srv_class_in_db (const tSDP_DISCOVERY_DB *p_db,
+ const tSDP_DISC_REC *p_start_rec)
+{
+#if SDP_CLIENT_ENABLED == TRUE
+ tSDP_DISC_REC *p_rec;
+ tSDP_DISC_ATTR *p_attr, *p_sattr;
+
+ /* Must have a valid database */
+ if (p_db == NULL)
+ return(NULL);
+
+
+ if (!p_start_rec)
+ {
+
+ p_rec = p_db->p_first_rec;
+ }
+ else
+ {
+ p_rec = p_start_rec->p_next_rec;
+ }
+
+ while (p_rec)
+ {
+ p_attr = p_rec->p_first_attr;
+ while (p_attr)
+ {
+ if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST)
+ && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE))
+ {
+ for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr)
+ {
+ if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE)
+ && (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2)
+ && ( (p_sattr->attr_value.v.u16 == UUID_SERVCLASS_HDP_SINK) ||
+ (p_sattr->attr_value.v.u16 == UUID_SERVCLASS_HDP_SOURCE)) )
+ {
+ return(p_rec);
+ }
+ }
+ break;
+ }
+
+ p_attr = p_attr->p_next_attr;
+ }
+
+ p_rec = p_rec->p_next_rec;
+ }
+#endif
+ /* If here, no matching UUID found */
+
+#if BTA_HL_DEBUG == TRUE
+ APPL_TRACE_DEBUG0("bta_hl_find_sink_or_src_srv_class_in_db failed");
+#endif
+
+ return(NULL);
+}
+#endif /* HL_INCLUDED */
diff --git a/bta/hl/bta_hl_utils.c b/bta/hl/bta_hl_utils.c
new file mode 100644
index 0000000..169e965
--- /dev/null
+++ b/bta/hl/bta_hl_utils.c
@@ -0,0 +1,3324 @@
+/*********************************************a********************************
+**
+** Name: bta_hl_utils.c
+**
+** Description: This file implements utility functions for the
+** HeaLth device profile (HL).
+**
+** Copyright (c) 2003-2009, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+
+#include "bt_target.h"
+#if defined(HL_INCLUDED) && (HL_INCLUDED == TRUE)
+
+
+#include "gki.h"
+#include "utl.h"
+#include "bd.h"
+#include "bta_fs_api.h"
+#include "bta_hl_int.h"
+#include "bta_hl_co.h"
+#include "mca_defs.h"
+#include "mca_api.h"
+
+
+/*******************************************************************************
+**
+** Function bta_hl_set_ctrl_psm_for_dch
+**
+** Description This function set the control PSM for the DCH setup
+**
+** Returns BOOLEAN - TRUE - control PSM setting is successful
+*******************************************************************************/
+BOOLEAN bta_hl_set_ctrl_psm_for_dch(UINT8 app_idx, UINT8 mcl_idx,
+ UINT8 mdl_idx, UINT16 ctrl_psm)
+{
+ tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ BOOLEAN success = TRUE, update_ctrl_psm = FALSE;
+
+ if (p_mcb->sdp.num_recs)
+ {
+ if (p_mcb->ctrl_psm != ctrl_psm)
+ {
+ /* can not use a different ctrl PSM than the current one*/
+ success = FALSE;
+ }
+ }
+ else
+ {
+ /* No SDP info control i.e. channel was opened by the peer */
+ update_ctrl_psm = TRUE;
+ }
+
+ if (success && update_ctrl_psm)
+ {
+ p_mcb->ctrl_psm = ctrl_psm;
+ }
+
+
+#if BTA_HL_DEBUG == TRUE
+ if (!success)
+ {
+ APPL_TRACE_DEBUG4("bta_hl_set_ctrl_psm_for_dch num_recs=%d success=%d update_ctrl_psm=%d ctrl_psm=0x%x ",
+ p_mcb->sdp.num_recs, success, update_ctrl_psm, ctrl_psm );
+ }
+#endif
+
+ return success;
+}
+
+
+/*******************************************************************************
+**
+** Function bta_hl_find_sdp_idx_using_ctrl_psm
+**
+** Description
+**
+** Returns UINT8 pool_id
+**
+*******************************************************************************/
+BOOLEAN bta_hl_find_sdp_idx_using_ctrl_psm(tBTA_HL_SDP *p_sdp,
+ UINT16 ctrl_psm,
+ UINT8 *p_sdp_idx)
+{
+ BOOLEAN found=FALSE;
+ tBTA_HL_SDP_REC *p_rec;
+ UINT8 i;
+
+ if (ctrl_psm != 0)
+ {
+ for (i=0; i<p_sdp->num_recs; i++)
+ {
+ p_rec = &p_sdp->sdp_rec[i];
+ if (p_rec->ctrl_psm == ctrl_psm)
+ {
+ *p_sdp_idx = i;
+ found = TRUE;
+ break;
+ }
+ }
+ }
+ else
+ {
+ *p_sdp_idx = 0;
+ found = TRUE;
+ }
+
+#if BTA_HL_DEBUG == TRUE
+ if (!found)
+ {
+ APPL_TRACE_DEBUG3("bta_hl_find_sdp_idx_using_ctrl_psm found=%d sdp_idx=%d ctrl_psm=0x%x ",
+ found, *p_sdp_idx, ctrl_psm );
+ }
+#endif
+ return found;
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_set_user_tx_pool_id
+**
+** Description This function sets the user tx pool id
+**
+** Returns UINT8 pool_id
+**
+*******************************************************************************/
+
+UINT8 bta_hl_set_user_tx_pool_id(UINT16 max_tx_size)
+{
+ UINT8 pool_id;
+
+ if (max_tx_size > GKI_get_pool_bufsize (OBX_FCR_TX_POOL_ID))
+ {
+ pool_id = BTA_HL_LRG_DATA_POOL_ID;
+ }
+ else
+ {
+ pool_id = L2CAP_DEFAULT_ERM_POOL_ID;
+ }
+
+#if BTA_HL_DEBUG == TRUE
+ APPL_TRACE_DEBUG3("bta_hl_set_user_rx_pool_id pool_id=%d max_tx_size=%d default_ertm_pool_size=%d",
+ pool_id, max_tx_size, GKI_get_pool_bufsize (OBX_FCR_TX_POOL_ID));
+#endif
+
+ return pool_id;
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_set_user_rx_pool_id
+**
+** Description This function sets the user trx pool id
+**
+** Returns UINT8 pool_id
+**
+*******************************************************************************/
+
+UINT8 bta_hl_set_user_rx_pool_id(UINT16 mtu)
+{
+ UINT8 pool_id;
+
+ if (mtu > GKI_get_pool_bufsize (OBX_FCR_RX_POOL_ID))
+ {
+ pool_id = BTA_HL_LRG_DATA_POOL_ID;
+ }
+ else
+ {
+ pool_id = L2CAP_DEFAULT_ERM_POOL_ID;
+ }
+
+#if BTA_HL_DEBUG == TRUE
+ APPL_TRACE_DEBUG3("bta_hl_set_user_rx_pool_id pool_id=%d mtu=%d default_ertm_pool_size=%d",
+ pool_id, mtu, GKI_get_pool_bufsize (OBX_FCR_RX_POOL_ID));
+#endif
+
+ return pool_id;
+}
+
+
+
+/*******************************************************************************
+**
+** Function bta_hl_set_tx_win_size
+**
+** Description This function sets the tx window size
+**
+** Returns UINT8 tx_win_size
+**
+*******************************************************************************/
+UINT8 bta_hl_set_tx_win_size(UINT16 mtu, UINT16 mps)
+{
+ UINT8 tx_win_size;
+
+ if (mtu <= mps)
+ {
+ tx_win_size =1;
+ }
+ else
+ {
+ if (mps > 0)
+ {
+ tx_win_size = (mtu/mps)+1;
+ }
+ else
+ {
+ APPL_TRACE_ERROR0("The MPS is zero");
+ tx_win_size = 10;
+ }
+ }
+
+#if BTA_HL_DEBUG == TRUE
+ APPL_TRACE_DEBUG3("bta_hl_set_tx_win_size win_size=%d mtu=%d mps=%d",
+ tx_win_size, mtu, mps);
+#endif
+ return tx_win_size;
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_set_mps
+**
+** Description This function sets the MPS
+**
+** Returns UINT16 MPS
+**
+*******************************************************************************/
+UINT16 bta_hl_set_mps(UINT16 mtu)
+{
+ UINT16 mps;
+ if (mtu > BTA_HL_L2C_MPS)
+ {
+ mps = BTA_HL_L2C_MPS;
+ }
+ else
+ {
+ mps = mtu;
+ }
+#if BTA_HL_DEBUG == TRUE
+ APPL_TRACE_DEBUG2("bta_hl_set_mps mps=%d mtu=%d",
+ mps, mtu);
+#endif
+ return mps;
+}
+
+
+/*******************************************************************************
+**
+** Function bta_hl_clean_mdl_cb
+**
+** Description This function clean up the specified MDL control block
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hl_clean_mdl_cb(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx)
+{
+ tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+#if BTA_HL_DEBUG == TRUE
+ APPL_TRACE_DEBUG3("bta_hl_clean_mdl_cb app_idx=%d mcl_idx=%d mdl_idx=%d",
+ app_idx, mcl_idx, mdl_idx);
+#endif
+ utl_freebuf((void **) &p_dcb->p_tx_pkt);
+ utl_freebuf((void **) &p_dcb->p_rx_pkt);
+ utl_freebuf((void **) &p_dcb->p_echo_tx_pkt);
+ utl_freebuf((void **) &p_dcb->p_echo_rx_pkt);
+
+ memset((void *)p_dcb, 0 , sizeof(tBTA_HL_MDL_CB));
+}
+
+
+/*******************************************************************************
+**
+** Function bta_hl_get_buf
+**
+** Description This function allocate a buffer based on the specified data size
+**
+** Returns BT_HDR *.
+**
+*******************************************************************************/
+BT_HDR * bta_hl_get_buf(UINT16 data_size)
+{
+ BT_HDR *p_new;
+ UINT16 size = data_size + L2CAP_MIN_OFFSET + BT_HDR_SIZE;
+
+ if (size < GKI_MAX_BUF_SIZE)
+ {
+ p_new = (BT_HDR *)GKI_getbuf(size);
+ }
+ else
+ {
+ p_new = (BT_HDR *) GKI_getpoolbuf(BTA_HL_LRG_DATA_POOL_ID);
+ }
+
+ if (p_new)
+ {
+ p_new->len = data_size;
+ p_new->offset = L2CAP_MIN_OFFSET;
+ }
+
+ return p_new;
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_find_service_in_db
+**
+** Description This function check the specified service class(es) can be find in
+** the received SDP database
+**
+** Returns BOOLEAN TRUE - found
+** FALSE - not found
+**
+*******************************************************************************/
+BOOLEAN bta_hl_find_service_in_db( UINT8 app_idx, UINT8 mcl_idx,
+ UINT16 service_uuid,
+ tSDP_DISC_REC **pp_rec )
+{
+ tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ BOOLEAN found = TRUE;
+
+ switch (service_uuid)
+ {
+ case UUID_SERVCLASS_HDP_SINK:
+ case UUID_SERVCLASS_HDP_SOURCE:
+ if ((*pp_rec = SDP_FindServiceInDb(p_mcb->p_db, service_uuid,
+ *pp_rec)) == NULL)
+ {
+ found = FALSE;
+ }
+ break;
+ default:
+ if (((*pp_rec = bta_hl_find_sink_or_src_srv_class_in_db(p_mcb->p_db,
+ *pp_rec)) == NULL))
+ {
+ found = FALSE;
+ }
+ break;
+ }
+ return found;
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_get_service_uuids
+**
+**
+** Description This function finds the service class(es) for both CCH and DCH oeprations
+**
+** Returns UINT16 - service_id
+** if service_uuid = 0xFFFF then it means service uuid
+** can be either Sink or Source
+**
+*******************************************************************************/
+UINT16 bta_hl_get_service_uuids(UINT8 sdp_oper, UINT8 app_idx, UINT8 mcl_idx,
+ UINT8 mdl_idx )
+{
+ tBTA_HL_MDL_CB *p_dcb;
+ UINT16 service_uuid = 0xFFFF; /* both Sink and Source */
+
+ switch (sdp_oper)
+ {
+
+ case BTA_HL_SDP_OP_DCH_OPEN_INIT:
+ case BTA_HL_SDP_OP_DCH_RECONNECT_INIT:
+ p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ if (p_dcb->local_mdep_id != BTA_HL_ECHO_TEST_MDEP_ID)
+ {
+ if (p_dcb->peer_mdep_role == BTA_HL_MDEP_ROLE_SINK)
+ {
+ service_uuid = UUID_SERVCLASS_HDP_SINK;
+ }
+ else
+ {
+ service_uuid = UUID_SERVCLASS_HDP_SOURCE;
+ }
+ }
+ break;
+ case BTA_HL_SDP_OP_CCH_INIT:
+ default:
+ /* use default that is both Sink and Source */
+ break;
+ }
+#if BTA_HL_DEBUG == TRUE
+ APPL_TRACE_DEBUG1("bta_hl_get_service_uuids service_uuid=0x%x",service_uuid );
+#endif
+ return service_uuid;
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_find_echo_cfg_rsp
+**
+**
+** Description This function finds the configuration response for the echo test
+**
+** Returns BOOLEAN - TRUE found
+** FALSE not found
+**
+*******************************************************************************/
+BOOLEAN bta_hl_find_echo_cfg_rsp(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdep_idx, UINT8 cfg,
+ UINT8 *p_cfg_rsp)
+{
+ tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_MDEP *p_mdep= &p_acb->sup_feature.mdep[mdep_idx];
+ BOOLEAN status =TRUE;
+
+ if (p_mdep->mdep_id == BTA_HL_ECHO_TEST_MDEP_ID)
+ {
+ if ((cfg == BTA_HL_DCH_CFG_RELIABLE) || (cfg == BTA_HL_DCH_CFG_STREAMING))
+ {
+ *p_cfg_rsp = cfg;
+ }
+ else if (cfg == BTA_HL_DCH_CFG_NO_PREF )
+ {
+ *p_cfg_rsp = BTA_HL_DEFAULT_ECHO_TEST_SRC_DCH_CFG;
+ }
+ else
+ {
+ status = FALSE;
+ APPL_TRACE_ERROR0("Inavlid echo cfg value");
+ }
+ return status;
+ }
+
+#if BTA_HL_DEBUG == TRUE
+ if (!status)
+ {
+ APPL_TRACE_DEBUG4("bta_hl_find_echo_cfg_rsp status=failed app_idx=%d mcl_idx=%d mdep_idx=%d cfg=%d",
+ app_idx, mcl_idx, mdep_idx, cfg);
+ }
+#endif
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_validate_dch_cfg
+**
+** Description This function validate the DCH configuration
+**
+** Returns BOOLEAN - TRUE cfg is valid
+** FALSE not valid
+**
+*******************************************************************************/
+BOOLEAN bta_hl_validate_cfg(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ UINT8 cfg)
+{
+ tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ BOOLEAN is_valid =FALSE;
+
+
+ if (!bta_hl_is_the_first_reliable_existed(app_idx, mcl_idx) &&
+ (cfg != BTA_HL_DCH_CFG_RELIABLE))
+ {
+ APPL_TRACE_ERROR0("the first DCH should be a reliable channel");
+ return is_valid;
+ }
+
+ switch (p_dcb->local_cfg)
+ {
+ case BTA_HL_DCH_CFG_NO_PREF:
+
+ if ((cfg == BTA_HL_DCH_CFG_RELIABLE) || (cfg == BTA_HL_DCH_CFG_STREAMING))
+ {
+ is_valid = TRUE;
+ }
+ break;
+ case BTA_HL_DCH_CFG_RELIABLE:
+ case BTA_HL_DCH_CFG_STREAMING:
+ if (p_dcb->local_cfg == cfg )
+ {
+ is_valid = TRUE;
+ }
+ break;
+ default:
+ break;
+ }
+
+#if BTA_HL_DEBUG == TRUE
+ if (!is_valid)
+ {
+ APPL_TRACE_DEBUG2("bta_hl_validate_dch_open_cfg is_valid=%d, cfg=%d", is_valid, cfg );
+ }
+#endif
+ return is_valid;
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_find_cch_cb_indexes
+**
+** Description This function finds the indexes needed for the CCH state machine
+**
+** Returns BOOLEAN - TRUE found
+** FALSE not found
+**
+*******************************************************************************/
+BOOLEAN bta_hl_find_cch_cb_indexes(tBTA_HL_DATA *p_msg,
+ UINT8 *p_app_idx,
+ UINT8 *p_mcl_idx)
+{
+ BOOLEAN found = FALSE;
+ tBTA_HL_MCL_CB *p_mcb;
+ UINT8 app_idx, mcl_idx;
+
+ switch (p_msg->hdr.event)
+ {
+ case BTA_HL_CCH_SDP_OK_EVT:
+ case BTA_HL_CCH_SDP_FAIL_EVT:
+ app_idx = p_msg->cch_sdp.app_idx;
+ mcl_idx = p_msg->cch_sdp.mcl_idx;
+ found = TRUE;
+ break;
+
+ case BTA_HL_MCA_CONNECT_IND_EVT:
+
+ if (bta_hl_find_app_idx_using_handle(p_msg->mca_evt.app_handle, &app_idx))
+ {
+ if (bta_hl_find_mcl_idx(app_idx, p_msg->mca_evt.mca_data.connect_ind.bd_addr, &mcl_idx))
+ {
+ /* local initiated */
+ found = TRUE;
+ }
+ else if (!bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx, &mcl_idx)&&
+ bta_hl_find_avail_mcl_idx(app_idx, &mcl_idx))
+ {
+ /* remote initiated */
+ p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ p_mcb->in_use = TRUE;
+ p_mcb->cch_oper = BTA_HL_CCH_OP_REMOTE_OPEN;
+ found = TRUE;
+ }
+ }
+ break;
+
+ case BTA_HL_MCA_DISCONNECT_IND_EVT:
+
+ if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx, &mcl_idx))
+ {
+ found = TRUE;
+ }
+ else if (bta_hl_find_app_idx_using_handle(p_msg->mca_evt.app_handle, &app_idx) &&
+ bta_hl_find_mcl_idx(app_idx, p_msg->mca_evt.mca_data.disconnect_ind.bd_addr, &mcl_idx))
+ {
+ found = TRUE;
+ }
+
+ if (found)
+ {
+ p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ if (p_mcb->cch_oper != BTA_HL_CCH_OP_LOCAL_CLOSE)
+ {
+ p_mcb->cch_oper = BTA_HL_CCH_OP_REMOTE_CLOSE;
+ }
+ }
+ break;
+
+ case BTA_HL_MCA_RSP_TOUT_IND_EVT:
+
+ if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx, &mcl_idx))
+ {
+ found = TRUE;
+ }
+
+ if (found)
+ {
+ p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ if (p_mcb->cch_oper != BTA_HL_CCH_OP_REMOTE_CLOSE)
+ {
+ p_mcb->cch_oper = BTA_HL_CCH_OP_LOCAL_CLOSE;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+
+ if (found)
+ {
+ *p_app_idx = app_idx;
+ *p_mcl_idx = mcl_idx;
+ }
+
+#if BTA_HL_DEBUG == TRUE
+ if (!found)
+ {
+ APPL_TRACE_DEBUG4("bta_hl_find_cch_cb_indexes event=%s found=%d app_idx=%d mcl_idx=%d",
+ bta_hl_evt_code(p_msg->hdr.event), found, app_idx, mcl_idx);
+ }
+#endif
+
+ return found;
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_find_dch_cb_indexes
+**
+** Description This function finds the indexes needed for the DCH state machine
+**
+** Returns BOOLEAN - TRUE found
+** FALSE not found
+**
+*******************************************************************************/
+BOOLEAN bta_hl_find_dch_cb_indexes(tBTA_HL_DATA *p_msg,
+ UINT8 *p_app_idx,
+ UINT8 *p_mcl_idx,
+ UINT8 *p_mdl_idx)
+{
+ BOOLEAN found = FALSE;
+ tBTA_HL_MCL_CB *p_mcb;
+ UINT8 app_idx, mcl_idx, mdl_idx;
+
+ switch (p_msg->hdr.event)
+ {
+ case BTA_HL_MCA_CREATE_CFM_EVT:
+ if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx, &mcl_idx) &&
+ bta_hl_find_mdl_idx( app_idx, mcl_idx, p_msg->mca_evt.mca_data.create_cfm.mdl_id, &mdl_idx))
+ {
+ found = TRUE;
+ }
+ break;
+
+ case BTA_HL_MCA_CREATE_IND_EVT:
+ case BTA_HL_MCA_RECONNECT_IND_EVT:
+ if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx, &mcl_idx) &&
+ bta_hl_find_avail_mdl_idx( app_idx, mcl_idx, &mdl_idx))
+ {
+ found = TRUE;
+ }
+ break;
+
+ case BTA_HL_MCA_OPEN_CFM_EVT:
+ if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx, &mcl_idx) &&
+ bta_hl_find_mdl_idx( app_idx, mcl_idx, p_msg->mca_evt.mca_data.open_cfm.mdl_id, &mdl_idx))
+ {
+ found = TRUE;
+ }
+ break;
+
+ case BTA_HL_MCA_OPEN_IND_EVT:
+ if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx, &mcl_idx) &&
+ bta_hl_find_mdl_idx( app_idx, mcl_idx, p_msg->mca_evt.mca_data.open_ind.mdl_id, &mdl_idx))
+ {
+ found = TRUE;
+ }
+ break;
+
+ case BTA_HL_MCA_CLOSE_CFM_EVT:
+
+ if (bta_hl_find_mdl_idx_using_handle((tBTA_HL_MDL_HANDLE)p_msg->mca_evt.mca_data.close_cfm.mdl,
+ &app_idx, &mcl_idx, &mdl_idx))
+ {
+ found = TRUE;
+ }
+ break;
+ case BTA_HL_MCA_CLOSE_IND_EVT:
+
+ if (bta_hl_find_mdl_idx_using_handle((tBTA_HL_MDL_HANDLE)p_msg->mca_evt.mca_data.close_ind.mdl,
+ &app_idx, &mcl_idx, &mdl_idx))
+ {
+ found = TRUE;
+ }
+ break;
+ case BTA_HL_API_SEND_DATA_EVT:
+
+ if (bta_hl_find_mdl_idx_using_handle(p_msg->api_send_data.mdl_handle,
+ &app_idx, &mcl_idx, &mdl_idx ))
+ {
+ found = TRUE;
+ }
+
+ break;
+
+ case BTA_HL_MCA_CONG_CHG_EVT:
+
+ if (bta_hl_find_mdl_idx_using_handle((tBTA_HL_MDL_HANDLE)p_msg->mca_evt.mca_data.cong_chg.mdl,
+ &app_idx, &mcl_idx, &mdl_idx ))
+ {
+ found = TRUE;
+ }
+
+ break;
+
+ case BTA_HL_MCA_RCV_DATA_EVT:
+ app_idx = p_msg->mca_rcv_data_evt.app_idx;
+ mcl_idx = p_msg->mca_rcv_data_evt.mcl_idx;
+ mdl_idx = p_msg->mca_rcv_data_evt.mdl_idx;
+ found = TRUE;
+ break;
+ case BTA_HL_DCH_RECONNECT_EVT:
+ case BTA_HL_DCH_OPEN_EVT:
+ case BTA_HL_DCH_ECHO_TEST_EVT:
+ case BTA_HL_DCH_SDP_FAIL_EVT:
+ app_idx = p_msg->dch_sdp.app_idx;
+ mcl_idx = p_msg->dch_sdp.mcl_idx;
+ mdl_idx = p_msg->dch_sdp.mdl_idx;
+ found = TRUE;
+ break;
+ case BTA_HL_MCA_RECONNECT_CFM_EVT:
+ if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx, &mcl_idx) &&
+ bta_hl_find_mdl_idx( app_idx, mcl_idx, p_msg->mca_evt.mca_data.reconnect_cfm.mdl_id, &mdl_idx))
+ {
+ found = TRUE;
+ }
+ break;
+
+
+ case BTA_HL_API_DCH_CREATE_RSP_EVT:
+ if (bta_hl_find_mcl_idx_using_handle(p_msg->api_dch_create_rsp.mcl_handle, &app_idx, &mcl_idx)&&
+ bta_hl_find_mdl_idx( app_idx, mcl_idx,p_msg->api_dch_create_rsp.mdl_id, &mdl_idx))
+ {
+ found = TRUE;
+ }
+ break;
+ case BTA_HL_MCA_ABORT_IND_EVT:
+ if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx, &mcl_idx) &&
+ bta_hl_find_mdl_idx( app_idx, mcl_idx,p_msg->mca_evt.mca_data.abort_ind.mdl_id, &mdl_idx))
+ {
+ found = TRUE;
+ }
+ break;
+ case BTA_HL_MCA_ABORT_CFM_EVT:
+ if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx, &mcl_idx) &&
+ bta_hl_find_mdl_idx( app_idx, mcl_idx, p_msg->mca_evt.mca_data.abort_cfm.mdl_id, &mdl_idx))
+ {
+ found = TRUE;
+ }
+ break;
+ case BTA_HL_CI_GET_TX_DATA_EVT:
+ case BTA_HL_CI_PUT_RX_DATA_EVT:
+ if (bta_hl_find_mdl_idx_using_handle(p_msg->ci_get_put_data.mdl_handle, &app_idx, &mcl_idx, &mdl_idx))
+ {
+ found = TRUE;
+ }
+ break;
+ case BTA_HL_CI_GET_ECHO_DATA_EVT:
+ case BTA_HL_CI_PUT_ECHO_DATA_EVT:
+ if (bta_hl_find_mcl_idx_using_handle(p_msg->ci_get_put_echo_data.mcl_handle, &app_idx, &mcl_idx))
+ {
+ p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ mdl_idx = p_mcb->echo_mdl_idx;
+ found = TRUE;
+ }
+ break;
+
+ default:
+ break;
+
+ }
+
+ if (found)
+ {
+ *p_app_idx = app_idx;
+ *p_mcl_idx = mcl_idx;
+ *p_mdl_idx = mdl_idx;
+ }
+#if BTA_HL_DEBUG == TRUE
+ if (!found)
+ {
+ APPL_TRACE_DEBUG5("bta_hl_find_dch_cb_indexes event=%s found=%d app_idx=%d mcl_idx=%d mdl_idx=%d",
+ bta_hl_evt_code(p_msg->hdr.event), found, *p_app_idx, *p_mcl_idx, *p_mdl_idx );
+ }
+#endif
+
+ return found;
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_allocate_mdl_id
+**
+** Description This function allocates a MDL ID
+**
+** Returns UINT16 - MDL ID
+**
+*******************************************************************************/
+UINT16 bta_hl_allocate_mdl_id(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx )
+{
+ UINT16 mdl_id=0;
+ tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ BOOLEAN duplicate_id;
+ UINT8 i, mdl_cfg_idx;
+
+ do
+ {
+ duplicate_id = FALSE;
+ mdl_id = ((mdl_id+1) & 0xFEFF);
+ /* check mdl_ids that are used for the current conenctions */
+ for (i=0; i< BTA_HL_NUM_MDLS_PER_MCL; i++)
+ {
+ if (p_mcb->mdl[i].in_use &&
+ (i != mdl_idx) &&
+ (p_mcb->mdl[i].mdl_id == mdl_id) )
+ {
+ duplicate_id = TRUE;
+ break;
+ }
+ }
+
+ if (duplicate_id)
+ {
+ /* start from the beginning to get another MDL value*/
+ continue;
+ }
+ else
+ {
+ /* check mdl_ids that are stored in the persistent memory */
+ if (bta_hl_find_mdl_cfg_idx(app_idx,mcl_idx, mdl_id, &mdl_cfg_idx))
+ {
+ duplicate_id = TRUE;
+ }
+ else
+ {
+ /* found a new MDL value */
+ break;
+ }
+ }
+
+ }while (TRUE);
+
+#if BTA_HL_DEBUG == TRUE
+ APPL_TRACE_DEBUG1("bta_hl_allocate_mdl OK mdl_id=%d", mdl_id);
+#endif
+ return mdl_id;
+}
+/*******************************************************************************
+**
+** Function bta_hl_find_mdl_idx
+**
+** Description This function finds the MDL index based on mdl_id
+**
+** Returns BOOLEAN TRUE-found
+**
+*******************************************************************************/
+BOOLEAN bta_hl_find_mdl_idx(UINT8 app_idx, UINT8 mcl_idx, UINT16 mdl_id,
+ UINT8 *p_mdl_idx)
+{
+ tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ BOOLEAN found=FALSE;
+ UINT8 i;
+
+ for (i=0; i < BTA_HL_NUM_MDLS_PER_MCL ; i ++)
+ {
+ if (p_mcb->mdl[i].in_use &&
+ (mdl_id !=0) &&
+ (p_mcb->mdl[i].mdl_id== mdl_id))
+ {
+ found = TRUE;
+ *p_mdl_idx = i;
+ break;
+ }
+ }
+
+#if BTA_HL_DEBUG == TRUE
+ if (!found)
+ {
+ APPL_TRACE_DEBUG3("bta_hl_find_mdl_idx found=%d mdl_id=%d mdl_idx=%d ",
+ found, mdl_id, i);
+ }
+#endif
+
+ return found;
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_find_an_active_mdl_idx
+**
+** Description This function finds an active MDL
+**
+** Returns BOOLEAN TRUE-found
+**
+*******************************************************************************/
+BOOLEAN bta_hl_find_an_active_mdl_idx(UINT8 app_idx, UINT8 mcl_idx,
+ UINT8 *p_mdl_idx)
+{
+ tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ BOOLEAN found=FALSE;
+ UINT8 i;
+
+ for (i=0; i < BTA_HL_NUM_MDLS_PER_MCL ; i ++)
+ {
+ if (p_mcb->mdl[i].in_use &&
+ (p_mcb->mdl[i].dch_state == BTA_HL_DCH_OPEN_ST))
+ {
+ found = TRUE;
+ *p_mdl_idx = i;
+ break;
+ }
+ }
+
+#if BTA_HL_DEBUG == TRUE
+ if (found)
+ {
+ APPL_TRACE_DEBUG4("bta_hl_find_an_opened_mdl_idx found=%d app_idx=%d mcl_idx=%d mdl_idx=%d",
+ found, app_idx, mcl_idx, i);
+ }
+#endif
+
+ return found;
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_find_dch_setup_mdl_idx
+**
+** Description This function finds a MDL which in the DCH setup state
+**
+** Returns BOOLEAN TRUE-found
+**
+*******************************************************************************/
+BOOLEAN bta_hl_find_dch_setup_mdl_idx(UINT8 app_idx, UINT8 mcl_idx,
+ UINT8 *p_mdl_idx)
+{
+ tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ BOOLEAN found=FALSE;
+ UINT8 i;
+
+ for (i=0; i < BTA_HL_NUM_MDLS_PER_MCL ; i ++)
+ {
+ if (p_mcb->mdl[i].in_use &&
+ (p_mcb->mdl[i].dch_state == BTA_HL_DCH_OPENING_ST))
+ {
+ found = TRUE;
+ *p_mdl_idx = i;
+ break;
+ }
+ }
+
+#if BTA_HL_DEBUG == TRUE
+ if (found)
+ {
+ APPL_TRACE_DEBUG4("bta_hl_find_dch_setup_mdl_idx found=%d app_idx=%d mcl_idx=%d mdl_idx=%d",
+ found, app_idx, mcl_idx, i);
+ }
+#endif
+
+ return found;
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_find_an_in_use_mcl_idx
+**
+** Description This function finds an in-use MCL control block index
+**
+** Returns BOOLEAN TRUE-found
+**
+*******************************************************************************/
+BOOLEAN bta_hl_find_an_in_use_mcl_idx(UINT8 app_idx,
+ UINT8 *p_mcl_idx)
+{
+ tBTA_HL_MCL_CB *p_mcb;
+ BOOLEAN found=FALSE;
+ UINT8 i;
+
+ for (i=0; i < BTA_HL_NUM_MCLS ; i ++)
+ {
+ p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, i);
+ if (p_mcb->in_use &&
+ (p_mcb->cch_state != BTA_HL_CCH_IDLE_ST))
+ {
+ found = TRUE;
+ *p_mcl_idx = i;
+ break;
+ }
+ }
+
+#if BTA_HL_DEBUG == TRUE
+ if (found)
+ {
+ APPL_TRACE_DEBUG3("bta_hl_find_an_in_use_mcl_idx found=%d app_idx=%d mcl_idx=%d ",
+ found, app_idx, i);
+ }
+#endif
+
+ return found;
+}
+
+
+/*******************************************************************************
+**
+** Function bta_hl_find_an_in_use_app_idx
+**
+** Description This function finds an in-use application control block index
+**
+** Returns BOOLEAN TRUE-found
+**
+*******************************************************************************/
+BOOLEAN bta_hl_find_an_in_use_app_idx(UINT8 *p_app_idx)
+{
+ tBTA_HL_APP_CB *p_acb ;
+ BOOLEAN found=FALSE;
+ UINT8 i;
+
+ for (i=0; i < BTA_HL_NUM_APPS ; i ++)
+ {
+ p_acb = BTA_HL_GET_APP_CB_PTR(i);
+ if (p_acb->in_use)
+ {
+ found = TRUE;
+ *p_app_idx = i;
+ break;
+ }
+ }
+
+#if BTA_HL_DEBUG == TRUE
+ if (found)
+ {
+ APPL_TRACE_DEBUG2("bta_hl_find_an_in_use_app_idx found=%d app_idx=%d ",
+ found, i);
+ }
+#endif
+
+ return found;
+}
+/*******************************************************************************
+**
+** Function bta_hl_find_app_idx
+**
+** Description This function finds the application control block index based on
+** the application ID
+**
+** Returns BOOLEAN TRUE-found
+**
+*******************************************************************************/
+BOOLEAN bta_hl_find_app_idx(UINT8 app_id, UINT8 *p_app_idx)
+{
+ BOOLEAN found=FALSE;
+ UINT8 i;
+
+ for (i=0; i < BTA_HL_NUM_APPS ; i ++)
+ {
+ if (bta_hl_cb.acb[i].in_use &&
+ (bta_hl_cb.acb[i].app_id == app_id))
+ {
+ found = TRUE;
+ *p_app_idx = i;
+ break;
+ }
+ }
+
+#if BTA_HL_DEBUG == TRUE
+ APPL_TRACE_DEBUG3("bta_hl_find_app_idx found=%d app_id=%d idx=%d ",
+ found, app_id, i);
+#endif
+
+ return found;
+}
+
+
+/*******************************************************************************
+**
+** Function bta_hl_find_app_idx_using_handle
+**
+** Description This function finds the application control block index based on
+** the application handle
+**
+** Returns BOOLEAN TRUE-found
+**
+*******************************************************************************/
+BOOLEAN bta_hl_find_app_idx_using_handle(tBTA_HL_APP_HANDLE app_handle,
+ UINT8 *p_app_idx)
+{
+ BOOLEAN found=FALSE;
+ UINT8 i;
+
+ for (i=0; i < BTA_HL_NUM_APPS ; i ++)
+ {
+ if (bta_hl_cb.acb[i].in_use &&
+ (bta_hl_cb.acb[i].app_handle == app_handle))
+ {
+ found = TRUE;
+ *p_app_idx = i;
+ break;
+ }
+ }
+
+#if BTA_HL_DEBUG == TRUE
+ if (!found)
+ {
+ APPL_TRACE_DEBUG3("bta_hl_find_app_idx_using_mca_handle status=%d handle=%d app_idx=%d ",
+ found, app_handle , i);
+ }
+#endif
+
+ return found;
+}
+
+
+/*******************************************************************************
+**
+** Function bta_hl_find_mcl_idx_using_handle
+**
+** Description This function finds the MCL control block index based on
+** the MCL handle
+**
+** Returns BOOLEAN TRUE-found
+**
+*******************************************************************************/
+BOOLEAN bta_hl_find_mcl_idx_using_handle( tBTA_HL_MCL_HANDLE mcl_handle,
+ UINT8 *p_app_idx, UINT8 *p_mcl_idx)
+{
+ tBTA_HL_APP_CB *p_acb;
+ BOOLEAN found=FALSE;
+ UINT8 i,j;
+
+ for (i=0; i<BTA_HL_NUM_APPS; i++)
+ {
+ p_acb = BTA_HL_GET_APP_CB_PTR(i);
+ if (p_acb->in_use)
+ {
+ for (j=0; j < BTA_HL_NUM_MCLS ; j++)
+ {
+ if ( p_acb->mcb[j].mcl_handle == mcl_handle )
+ {
+ found = TRUE;
+ *p_app_idx = i;
+ *p_mcl_idx = j;
+ break;
+ }
+ }
+ }
+ }
+
+#if BTA_HL_DEBUG == TRUE
+ if (!found)
+ {
+ APPL_TRACE_DEBUG3("bta_hl_find_mcl_idx_using_handle found=%d app_idx=%d mcl_idx=%d",
+ found, i, j);
+ }
+#endif
+ return found;
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_find_mcl_idx
+**
+** Description This function finds the MCL control block index based on
+** the peer BD address
+**
+** Returns BOOLEAN TRUE-found
+**
+*******************************************************************************/
+BOOLEAN bta_hl_find_mcl_idx(UINT8 app_idx, BD_ADDR p_bd_addr, UINT8 *p_mcl_idx)
+{
+ BOOLEAN found=FALSE;
+ UINT8 i;
+ tBTA_HL_MCL_CB *p_mcb;
+
+ for (i=0; i < BTA_HL_NUM_MCLS ; i ++)
+ {
+ p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, i);
+
+ if (bta_hl_cb.acb[app_idx].mcb[i].in_use &&
+ (!memcmp (bta_hl_cb.acb[app_idx].mcb[i].bd_addr, p_bd_addr, BD_ADDR_LEN)))
+ {
+ found = TRUE;
+ *p_mcl_idx = i;
+ break;
+ }
+ }
+
+#if BTA_HL_DEBUG == TRUE
+ if (!found)
+ {
+ APPL_TRACE_DEBUG2("bta_hl_find_mcl_idx found=%d idx=%d",
+ found, i);
+ }
+#endif
+ return found;
+}
+
+
+
+/*******************************************************************************
+**
+** Function bta_hl_find_mdl_idx_using_handle
+**
+** Description This function finds the MDL control block index based on
+** the MDL handle
+**
+** Returns BOOLEAN TRUE-found
+**
+*******************************************************************************/
+BOOLEAN bta_hl_find_mdl_idx_using_handle(tBTA_HL_MDL_HANDLE mdl_handle,
+ UINT8 *p_app_idx,UINT8 *p_mcl_idx,
+ UINT8 *p_mdl_idx)
+{
+ tBTA_HL_APP_CB *p_acb;
+ tBTA_HL_MCL_CB *p_mcb;
+ tBTA_HL_MDL_CB *p_dcb;
+ BOOLEAN found=FALSE;
+ UINT8 i,j,k;
+
+ for (i=0; i < BTA_HL_NUM_APPS ; i ++)
+ {
+ p_acb = BTA_HL_GET_APP_CB_PTR(i);
+ if (p_acb->in_use)
+ {
+ for (j=0; j< BTA_HL_NUM_MCLS; j++)
+ {
+ p_mcb = BTA_HL_GET_MCL_CB_PTR(i,j);
+ if (p_mcb->in_use)
+ {
+ for (k=0; k< BTA_HL_NUM_MDLS_PER_MCL; k++)
+ {
+ p_dcb = BTA_HL_GET_MDL_CB_PTR(i,j,k);
+ if (p_dcb->in_use)
+ {
+ if (p_dcb->mdl_handle == mdl_handle)
+ {
+ found = TRUE;
+ *p_app_idx = i;
+ *p_mcl_idx =j;
+ *p_mdl_idx = k;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+#if BTA_HL_DEBUG == TRUE
+ if (!found)
+ {
+ APPL_TRACE_DEBUG2("bta_hl_find_mdl_idx_using_handle found=%d mdl_handle=%d ",
+ found, mdl_handle);
+ }
+#endif
+ return found;
+}
+/*******************************************************************************
+**
+** Function bta_hl_is_the_first_reliable_existed
+**
+** Description This function checks whether the first reliable DCH channel
+** has been setup on the MCL or not
+**
+** Returns BOOLEAN - TRUE exist
+** FALSE does not exist
+**
+*******************************************************************************/
+BOOLEAN bta_hl_is_the_first_reliable_existed(UINT8 app_idx, UINT8 mcl_idx )
+{
+ tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ BOOLEAN is_existed =FALSE;
+ UINT8 i ;
+
+ for (i=0; i< BTA_HL_NUM_MDLS_PER_MCL; i++)
+ {
+ if (p_mcb->mdl[i].in_use && p_mcb->mdl[i].is_the_first_reliable)
+ {
+ is_existed = TRUE;
+ break;
+ }
+ }
+
+#if BTA_HL_DEBUG == TRUE
+ APPL_TRACE_DEBUG1("bta_hl_is_the_first_reliable_existed is_existed=%d ",is_existed );
+#endif
+ return is_existed;
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_find_non_active_mdl_cfg
+**
+** Description This function finds a valid MDL configiration index and this
+** MDL ID is not active
+**
+** Returns BOOLEAN - TRUE found
+** FALSE not found
+**
+*******************************************************************************/
+BOOLEAN bta_hl_find_non_active_mdl_cfg(UINT8 app_idx, UINT8 start_mdl_cfg_idx,
+ UINT8 *p_mdl_cfg_idx)
+{
+
+ tBTA_HL_MCL_CB *p_mcb;
+ tBTA_HL_MDL_CB *p_dcb;
+ tBTA_HL_MDL_CFG *p_mdl;
+ BOOLEAN mdl_in_use;
+ BOOLEAN found = FALSE;
+ UINT8 i,j,k;
+
+ for (i = start_mdl_cfg_idx; i< BTA_HL_NUM_MDL_CFGS; i++)
+ {
+ mdl_in_use = FALSE;
+ p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, i);
+ for (j=0; j< BTA_HL_NUM_MCLS; j++)
+ {
+ p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, j);
+ if (p_mcb->in_use &&
+ !memcmp(p_mdl->peer_bd_addr,p_mcb->bd_addr,BD_ADDR_LEN))
+ {
+
+ for (k=0; k<BTA_HL_NUM_MDLS_PER_MCL; k++)
+ {
+ p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, j, k);
+
+ if (p_dcb->in_use && p_mdl->mdl_id == p_dcb->mdl_id)
+ {
+ mdl_in_use = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (mdl_in_use)
+ {
+ break;
+ }
+ }
+
+ if (!mdl_in_use)
+ {
+ *p_mdl_cfg_idx = i;
+ found = TRUE;
+ break;
+ }
+ }
+
+ return found;
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_find_mdl_cfg_idx
+**
+** Description This function finds an available MDL configiration index
+**
+** Returns BOOLEAN - TRUE found
+** FALSE not found
+**
+*******************************************************************************/
+BOOLEAN bta_hl_find_avail_mdl_cfg_idx(UINT8 app_idx, UINT8 mcl_idx,
+ UINT8 *p_mdl_cfg_idx)
+{
+ tBTA_HL_MDL_CFG *p_mdl, *p_mdl1, *p_mdl2;
+ UINT8 i;
+ BOOLEAN found=FALSE;
+ UINT8 first_mdl_cfg_idx, second_mdl_cfg_idx, older_mdl_cfg_idx;
+ BOOLEAN done;
+
+
+ for (i=0; i< BTA_HL_NUM_MDL_CFGS; i++)
+ {
+ p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, i);
+ if (!p_mdl->active )
+ {
+ /* found an unused space to store mdl cfg*/
+ found=TRUE;
+ *p_mdl_cfg_idx =i;
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ /* all available mdl cfg spaces are in use so we need to find the mdl cfg which is
+ not currently in use and has the the oldest time stamp to remove*/
+
+ found = TRUE;
+ if (bta_hl_find_non_active_mdl_cfg(app_idx,0, &first_mdl_cfg_idx))
+ {
+ if (bta_hl_find_non_active_mdl_cfg(app_idx,(UINT8) (first_mdl_cfg_idx+1), &second_mdl_cfg_idx))
+ {
+ done = FALSE;
+ while (!done)
+ {
+ p_mdl1 = BTA_HL_GET_MDL_CFG_PTR(app_idx, first_mdl_cfg_idx);
+ p_mdl2 = BTA_HL_GET_MDL_CFG_PTR(app_idx, second_mdl_cfg_idx);
+
+ if (p_mdl1->time < p_mdl2->time)
+ {
+ older_mdl_cfg_idx = first_mdl_cfg_idx;
+ }
+ else
+ {
+ older_mdl_cfg_idx = second_mdl_cfg_idx;
+ }
+
+ if (bta_hl_find_non_active_mdl_cfg(app_idx,(UINT8) (second_mdl_cfg_idx+1), &second_mdl_cfg_idx))
+ {
+ first_mdl_cfg_idx = older_mdl_cfg_idx;
+ }
+ else
+ {
+ done = TRUE;
+ }
+ }
+
+ *p_mdl_cfg_idx = older_mdl_cfg_idx;
+
+ }
+ else
+ {
+ *p_mdl_cfg_idx = first_mdl_cfg_idx;
+ }
+
+ }
+ else
+ {
+ found = FALSE;
+ }
+ }
+
+#if BTA_HL_DEBUG == TRUE
+ if (!found)
+ {
+ APPL_TRACE_DEBUG2("bta_hl_find_avail_mdl_cfg_idx found=%d mdl_cfg_idx=%d ",found, *p_mdl_cfg_idx );
+ }
+#endif
+
+ return found;
+
+
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_find_mdl_cfg_idx
+**
+** Description This function finds the MDL configuration index based on
+** the MDL ID
+**
+** Returns BOOLEAN - TRUE found
+** FALSE not found
+**
+*******************************************************************************/
+BOOLEAN bta_hl_find_mdl_cfg_idx(UINT8 app_idx, UINT8 mcl_idx,
+ tBTA_HL_MDL_ID mdl_id, UINT8 *p_mdl_cfg_idx)
+{
+ tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_MDL_CFG *p_mdl;
+ UINT8 i ;
+ BOOLEAN found=FALSE;
+ for (i=0; i< BTA_HL_NUM_MDL_CFGS; i++)
+ {
+ p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, i);
+ if (p_mdl->active &&
+ (!memcmp (p_mcb->bd_addr, p_mdl->peer_bd_addr, BD_ADDR_LEN))&&
+ (p_mdl->mdl_id == mdl_id))
+ {
+ found=TRUE;
+ *p_mdl_cfg_idx =i;
+ break;
+ }
+ }
+
+#if BTA_HL_DEBUG == TRUE
+ if (!found)
+ {
+ APPL_TRACE_DEBUG2("bta_hl_find_mdl_cfg_idx found=%d mdl_cfg_idx=%d ",found, i );
+ }
+#endif
+
+ return found;
+
+
+}
+
+
+/*******************************************************************************
+**
+** Function bta_hl_get_cur_time
+**
+** Description This function get the cuurent time value
+**
+** Returns BOOLEAN - TRUE found
+** FALSE not found
+**
+*******************************************************************************/
+BOOLEAN bta_hl_get_cur_time(UINT8 app_idx, UINT8 *p_cur_time)
+{
+ tBTA_HL_MDL_CFG *p_mdl;
+ UINT8 i, j, time_latest, time;
+ BOOLEAN found=FALSE, result=TRUE;
+
+ for (i=0; i< BTA_HL_NUM_MDL_CFGS; i++)
+ {
+ p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, i);
+ if (p_mdl->active)
+ {
+ found=TRUE;
+ time_latest = p_mdl->time;
+ for (j=(i+1); j< BTA_HL_NUM_MDL_CFGS; j++ )
+ {
+ p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, j);
+ if (p_mdl->active)
+ {
+ time = p_mdl->time;
+ if (time > time_latest)
+ {
+ time_latest = time;
+ }
+ }
+ }
+ break;
+ }
+ }
+
+
+ if (found)
+ {
+ if (time_latest < BTA_HL_MAX_TIME)
+ {
+ *p_cur_time = time_latest+1;
+ }
+ else
+ {
+ /* need to wrap around */
+ result = FALSE;
+ }
+ }
+ else
+ {
+ *p_cur_time = BTA_HL_MIN_TIME;
+ }
+
+#if BTA_HL_DEBUG == TRUE
+ if (!result)
+ {
+ APPL_TRACE_DEBUG2("bta_hl_get_cur_time result=%s cur_time=%d",
+ (result?"OK":"FAIL"), *p_cur_time);
+ }
+#endif
+
+ return result;
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_sort_cfg_time_idx
+**
+** Description This function sort the mdl configuration idx stored in array a
+** based on decending time value
+**
+** Returns BOOLEAN - TRUE found
+** FALSE not found
+**
+*******************************************************************************/
+void bta_hl_sort_cfg_time_idx(UINT8 app_idx, UINT8 *a, UINT8 n)
+{
+ tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ UINT8 temp_time, temp_idx;
+ INT16 i, j;
+ for (i = 1; i < n; ++i)
+ {
+ temp_idx = a[i];
+ temp_time = p_acb->mdl_cfg[temp_idx].time;
+ j = i - 1;
+ while ((j >= 0) && (temp_time < p_acb->mdl_cfg[a[j]].time))
+ {
+ a[j + 1] = a[j];
+ --j;
+ }
+ a[j + 1] = temp_idx;
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_compact_mdl_cfg_time
+**
+** Description This function finds the MDL configuration index based on
+** the MDL ID
+**
+** Returns BOOLEAN - TRUE found
+** FALSE not found
+**
+*******************************************************************************/
+void bta_hl_compact_mdl_cfg_time(UINT8 app_idx)
+{
+ tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_MDL_CFG *p_mdl;
+ UINT8 i, time_min, cnt=0;
+ UINT8 s_arr[BTA_HL_NUM_MDL_CFGS];
+
+
+ for (i=0; i< BTA_HL_NUM_MDL_CFGS; i++)
+ {
+ p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, i);
+ if (p_mdl->active )
+ {
+ s_arr[cnt]= i;
+ cnt++;
+ }
+ }
+
+
+
+#if BTA_HL_DEBUG == TRUE
+ APPL_TRACE_DEBUG1("bta_hl_compact_mdl_cfg_time cnt=%d ",cnt );
+#endif
+
+
+ if (cnt)
+ {
+ bta_hl_sort_cfg_time_idx(app_idx, s_arr, cnt);
+ time_min = BTA_HL_MIN_TIME;
+ for (i=0;i<cnt; i++)
+ {
+ p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, s_arr[i]);
+ p_mdl->time = time_min + i;
+ bta_hl_co_save_mdl(p_acb->app_id, s_arr[i], p_mdl);
+ }
+ }
+
+
+}
+
+
+
+/*******************************************************************************
+**
+** Function bta_hl_is_mdl_exsit_in_mcl
+**
+** Description This function checks whether the MDL ID
+** has already existed in teh MCL or not
+**
+** Returns BOOLEAN - TRUE exist
+** FALSE does not exist
+**
+*******************************************************************************/
+BOOLEAN bta_hl_is_mdl_exsit_in_mcl(UINT8 app_idx, BD_ADDR bd_addr,
+ tBTA_HL_MDL_ID mdl_id)
+{
+ tBTA_HL_MDL_CFG *p_mdl;
+ BOOLEAN found = FALSE;
+ UINT8 i;
+
+ for (i = 0; i< BTA_HL_NUM_MDL_CFGS; i++)
+ {
+ p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, i);
+ if (p_mdl->active &&
+ !memcmp(p_mdl->peer_bd_addr, bd_addr,BD_ADDR_LEN))
+ {
+ if (mdl_id != BTA_HL_DELETE_ALL_MDL_IDS)
+ {
+ if (p_mdl->mdl_id == mdl_id)
+ {
+ found = TRUE;
+ break;
+ }
+ }
+ else
+ {
+ found = TRUE;
+ break;
+ }
+ }
+ }
+
+ return found;
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_delete_mdl_cfg
+**
+** Description This function delete the specified MDL ID
+**
+** Returns BOOLEAN - TRUE Success
+** FALSE Failed
+**
+*******************************************************************************/
+BOOLEAN bta_hl_delete_mdl_cfg(UINT8 app_idx, BD_ADDR bd_addr,
+ tBTA_HL_MDL_ID mdl_id)
+{
+ tBTA_HL_MDL_CFG *p_mdl;
+ BOOLEAN success = FALSE;
+ UINT8 i;
+ tBTA_HL_APP_CB *p_acb= BTA_HL_GET_APP_CB_PTR(app_idx);
+ UINT8 app_id = p_acb->app_id;
+
+ for (i = 0; i< BTA_HL_NUM_MDL_CFGS; i++)
+ {
+ p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, i);
+ if (p_mdl->active &&
+ !memcmp(p_mdl->peer_bd_addr, bd_addr,BD_ADDR_LEN))
+ {
+ if (mdl_id != BTA_HL_DELETE_ALL_MDL_IDS)
+ {
+ if (p_mdl->mdl_id == mdl_id)
+ {
+ bta_hl_co_delete_mdl(app_id, i);
+ memset(p_mdl, 0, sizeof(tBTA_HL_MDL_CFG));
+ success = TRUE;
+ break;
+ }
+ }
+ else
+ {
+ bta_hl_co_delete_mdl(app_id, i);
+ memset(p_mdl, 0, sizeof(tBTA_HL_MDL_CFG));
+ success = TRUE;
+ }
+ }
+ }
+
+ return success;
+}
+
+
+/*******************************************************************************
+**
+** Function bta_hl_is_mdl_value_valid
+**
+**
+** Description This function checks the specified MDL ID is in valid range or not
+**
+** Returns BOOLEAN - TRUE Success
+** FALSE Failed
+**
+** note: mdl_id range 0x0000 reserved,
+** 0x0001-oxFEFF dynamic range,
+** 0xFF00-0xFFFE reserved,
+** 0xFFFF indicates all MDLs (for delete operation only)
+**
+*******************************************************************************/
+BOOLEAN bta_hl_is_mdl_value_valid(tBTA_HL_MDL_ID mdl_id)
+{
+ BOOLEAN status = TRUE;
+
+ if (mdl_id != BTA_HL_DELETE_ALL_MDL_IDS)
+ {
+ if (mdl_id != 0)
+ {
+ if (mdl_id > BTA_HL_MAX_MDL_VAL )
+ {
+ status = FALSE;
+ }
+ }
+ else
+ {
+ status = FALSE;
+ }
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_find_mdep_cfg_idx
+**
+** Description This function finds the MDEP configuration index based
+** on the local MDEP ID
+**
+** Returns BOOLEAN - TRUE found
+** FALSE not found
+**
+*******************************************************************************/
+BOOLEAN bta_hl_find_mdep_cfg_idx(UINT8 app_idx, tBTA_HL_MDEP_ID local_mdep_id,
+ UINT8 *p_mdep_cfg_idx)
+{
+ tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_SUP_FEATURE *p_sup_feature= &p_acb->sup_feature;
+ BOOLEAN found =FALSE;
+ UINT8 i;
+
+ for (i=0; i< p_sup_feature->num_of_mdeps; i++)
+ {
+ if ( p_sup_feature->mdep[i].mdep_id == local_mdep_id)
+ {
+ found = TRUE;
+ *p_mdep_cfg_idx = i;
+ break;
+ }
+ }
+
+#if BTA_HL_DEBUG == TRUE
+ if (!found)
+ {
+ APPL_TRACE_DEBUG3("bta_hl_find_mdep_cfg_idx found=%d mdep_idx=%d local_mdep_id=%d ",
+ found,i, local_mdep_id );
+ }
+#endif
+ return found;
+}
+
+
+/*******************************************************************************
+**
+** Function bta_hl_find_rxtx_apdu_size
+**
+** Description This function finds the maximum APDU rx and tx sizes based on
+** the MDEP configuration data
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hl_find_rxtx_apdu_size(UINT8 app_idx, UINT8 mdep_cfg_idx,
+ UINT16 *p_rx_apu_size,
+ UINT16 *p_tx_apu_size)
+{
+ tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_MDEP_CFG *p_mdep_cfg;
+ UINT8 i;
+ UINT16 max_rx_apdu_size=0, max_tx_apdu_size=0;
+
+ p_mdep_cfg = &p_acb->sup_feature.mdep[mdep_cfg_idx].mdep_cfg;
+
+
+ for (i=0; i< p_mdep_cfg->num_of_mdep_data_types ; i++)
+ {
+
+ if (max_rx_apdu_size < p_mdep_cfg->data_cfg[i].max_rx_apdu_size)
+ {
+ max_rx_apdu_size = p_mdep_cfg->data_cfg[i].max_rx_apdu_size;
+ }
+
+ if (max_tx_apdu_size < p_mdep_cfg->data_cfg[i].max_tx_apdu_size)
+ {
+ max_tx_apdu_size = p_mdep_cfg->data_cfg[i].max_tx_apdu_size;
+ }
+ }
+
+
+ *p_rx_apu_size = max_rx_apdu_size;
+ *p_tx_apu_size = max_tx_apdu_size;
+
+#if BTA_HL_DEBUG == TRUE
+ APPL_TRACE_DEBUG2("bta_hl_find_rxtx_apdu_size max_rx_apdu_size=%d max_tx_apdu_size=%d ",
+ max_rx_apdu_size, max_tx_apdu_size );
+#endif
+
+
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_validate_peer_cfg
+**
+** Description This function validates the peer DCH configuration
+**
+** Returns BOOLEAN - TRUE validation is successful
+** FALSE validation failed
+**
+*******************************************************************************/
+BOOLEAN bta_hl_validate_peer_cfg(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
+ tBTA_HL_MDEP_ID peer_mdep_id,
+ tBTA_HL_MDEP_ROLE peer_mdep_role,
+ UINT8 sdp_idx)
+{
+ tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ tBTA_HL_SDP_REC *p_rec;
+ BOOLEAN peer_found =FALSE;
+ UINT8 i;
+
+ APPL_TRACE_DEBUG1("bta_hl_validate_peer_cfg sdp_idx=%d", sdp_idx);
+
+
+ if (p_dcb->local_mdep_id == BTA_HL_ECHO_TEST_MDEP_ID)
+ {
+ return TRUE;
+ }
+
+ p_rec = &p_mcb->sdp.sdp_rec[sdp_idx];
+ for (i=0; i< p_rec->num_mdeps; i++)
+ {
+ if ( (p_rec->mdep_cfg[i].mdep_id == peer_mdep_id) &&
+ (p_rec->mdep_cfg[i].mdep_role == peer_mdep_role))
+ {
+ peer_found = TRUE;
+
+ break;
+ }
+ }
+
+
+#if BTA_HL_DEBUG == TRUE
+ if (!peer_found)
+ {
+ APPL_TRACE_DEBUG1("bta_hl_validate_peer_cfg failed num_mdeps=%d",p_rec->num_mdeps);
+ }
+#endif
+ return peer_found;
+}
+
+
+/*******************************************************************************
+**
+** Function bta_hl_chk_local_cfg
+**
+** Description This function check whether the local DCH configuration is OK or not
+**
+** Returns tBTA_HL_STATUS - OK - local DCH configuration is OK
+** NO_FIRST_RELIABLE - the streaming DCH configuration
+** is not OK and it needs to use
+** reliable DCH configuration
+**
+*******************************************************************************/
+tBTA_HL_STATUS bta_hl_chk_local_cfg(UINT8 app_idx, UINT8 mcl_idx,
+ UINT8 mdep_cfg_idx,
+ tBTA_HL_DCH_CFG local_cfg)
+{
+ tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+
+ if ( mdep_cfg_idx &&
+ (p_acb->sup_feature.mdep[mdep_cfg_idx].mdep_cfg.mdep_role == BTA_HL_MDEP_ROLE_SOURCE) &&
+ (!bta_hl_is_the_first_reliable_existed(app_idx, mcl_idx)) &&
+ (local_cfg != BTA_HL_DCH_CFG_RELIABLE))
+ {
+ status = BTA_HL_STATUS_NO_FIRST_RELIABLE;
+ APPL_TRACE_ERROR0("BTA_HL_STATUS_INVALID_DCH_CFG");
+ }
+
+ return status;
+}
+
+
+/*******************************************************************************
+**
+** Function bta_hl_validate_reconnect_params
+**
+** Description This function validates the reconnect parameters
+**
+** Returns BOOLEAN - TRUE validation is successful
+** FALSE validation failed
+*******************************************************************************/
+BOOLEAN bta_hl_validate_reconnect_params(UINT8 app_idx, UINT8 mcl_idx,
+ tBTA_HL_API_DCH_RECONNECT *p_reconnect,
+ UINT8 *p_mdep_cfg_idx, UINT8 *p_mdl_cfg_idx)
+{
+ tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_SUP_FEATURE *p_sup_feature = &p_acb->sup_feature;
+ UINT8 num_mdeps;
+ UINT8 mdl_cfg_idx;
+ BOOLEAN local_mdep_id_found =FALSE;
+ BOOLEAN mdl_cfg_found =FALSE;
+ BOOLEAN status=FALSE;
+ UINT8 i, in_use_mdl_idx;
+
+#if BTA_HL_DEBUG == TRUE
+ APPL_TRACE_DEBUG1("bta_hl_validate_reconnect_params mdl_id=%d", p_reconnect->mdl_id);
+#endif
+ if (bta_hl_find_mdl_cfg_idx(app_idx, mcl_idx, p_reconnect->mdl_id, &mdl_cfg_idx))
+ {
+ mdl_cfg_found = TRUE;
+ }
+
+#if BTA_HL_DEBUG == TRUE
+ if (!mdl_cfg_found)
+ {
+ APPL_TRACE_DEBUG0("mdl_cfg_found not found");
+ }
+#endif
+
+
+ if (mdl_cfg_found)
+ {
+ num_mdeps = p_sup_feature->num_of_mdeps;
+ for (i=0; i< num_mdeps ; i++)
+ {
+ if ( p_sup_feature->mdep[i].mdep_id == p_acb->mdl_cfg[mdl_cfg_idx].local_mdep_id)
+ {
+ local_mdep_id_found = TRUE;
+ *p_mdep_cfg_idx =i;
+ *p_mdl_cfg_idx = mdl_cfg_idx;
+ break;
+ }
+ }
+ }
+
+#if BTA_HL_DEBUG == TRUE
+ if (!local_mdep_id_found)
+ {
+ APPL_TRACE_DEBUG0("local_mdep_id not found");
+ }
+#endif
+
+
+ if (local_mdep_id_found)
+ {
+ if (!bta_hl_find_mdl_idx(app_idx,mcl_idx, p_reconnect->mdl_id, &in_use_mdl_idx))
+ {
+ status= TRUE;
+ }
+ else
+ {
+ APPL_TRACE_ERROR1("mdl_id=%d is curreltly in use",p_reconnect->mdl_id);
+ }
+ }
+
+#if BTA_HL_DEBUG == TRUE
+ if (!status)
+ {
+ APPL_TRACE_DEBUG3("Reconnect validation failed local_mdep_id found=%d mdl_cfg_idx found=%d in_use_mdl_idx=%d ",
+ local_mdep_id_found, mdl_cfg_found, in_use_mdl_idx);
+ }
+#endif
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_find_avail_mcl_idx
+**
+** Returns BOOLEAN - TRUE found
+** FALSE not found
+**
+*******************************************************************************/
+BOOLEAN bta_hl_find_avail_mcl_idx(UINT8 app_idx, UINT8 *p_mcl_idx)
+{
+ BOOLEAN found=FALSE;
+ UINT8 i;
+
+ for (i=0; i < BTA_HL_NUM_MCLS ; i ++)
+ {
+ if (!bta_hl_cb.acb[app_idx].mcb[i].in_use)
+ {
+ found = TRUE;
+ *p_mcl_idx = i;
+ break;
+ }
+ }
+
+#if BTA_HL_DEBUG == TRUE
+ if (!found)
+ {
+ APPL_TRACE_DEBUG2("bta_hl_find_avail_mcl_idx found=%d idx=%d",
+ found, i);
+ }
+#endif
+ return found;
+}
+
+
+
+/*******************************************************************************
+**
+** Function bta_hl_find_avail_mdl_idx
+**
+** Description This function finds an available MDL control block index
+**
+** Returns BOOLEAN - TRUE found
+** FALSE not found
+**
+*******************************************************************************/
+BOOLEAN bta_hl_find_avail_mdl_idx(UINT8 app_idx, UINT8 mcl_idx,
+ UINT8 *p_mdl_idx)
+{
+ tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ BOOLEAN found=FALSE;
+ UINT8 i;
+
+ for (i=0; i < BTA_HL_NUM_MDLS_PER_MCL ; i ++)
+ {
+ if (!p_mcb->mdl[i].in_use)
+ {
+ memset((void *)&p_mcb->mdl[i],0, sizeof(tBTA_HL_MDL_CB));
+ found = TRUE;
+ *p_mdl_idx = i;
+ break;
+ }
+ }
+
+#if BTA_HL_DEBUG == TRUE
+ if (!found)
+ {
+ APPL_TRACE_DEBUG2("bta_hl_find_avail_mdl_idx found=%d idx=%d",
+ found, i);
+ }
+#endif
+ return found;
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_is_a_duplicate_id
+**
+** Description This function finds the application has been used or not
+**
+** Returns BOOLEAN - TRUE the app_id is a duplicate ID
+** FALSE not a duplicate ID
+*******************************************************************************/
+BOOLEAN bta_hl_is_a_duplicate_id(UINT8 app_id)
+{
+ BOOLEAN is_duplicate=FALSE;
+ UINT8 i;
+
+ for (i=0; i < BTA_HL_NUM_APPS ; i ++)
+ {
+ if (bta_hl_cb.acb[i].in_use &&
+ (bta_hl_cb.acb[i].app_id == app_id))
+ {
+ is_duplicate = TRUE;
+
+ break;
+ }
+ }
+
+#if BTA_HL_DEBUG == TRUE
+ if (is_duplicate)
+ {
+
+ APPL_TRACE_DEBUG2("bta_hl_is_a_duplicate_id app_id=%d is_duplicate=%d",
+ app_id, is_duplicate);
+ }
+#endif
+
+ return is_duplicate;
+}
+
+
+/*******************************************************************************
+**
+** Function bta_hl_find_avail_app_idx
+**
+** Description This function finds an available application control block index
+**
+** Returns BOOLEAN - TRUE found
+** FALSE not found
+**
+*******************************************************************************/
+BOOLEAN bta_hl_find_avail_app_idx(UINT8 *p_idx)
+{
+ BOOLEAN found=FALSE;
+ UINT8 i;
+
+ for (i=0; i < BTA_HL_NUM_APPS ; i ++)
+ {
+ if (!bta_hl_cb.acb[i].in_use)
+ {
+ found = TRUE;
+ *p_idx = i;
+ break;
+ }
+ }
+
+#if BTA_HL_DEBUG == TRUE
+ if (!found)
+ {
+ APPL_TRACE_DEBUG2("bta_hl_find_avail_app_idx found=%d app_idx=%d",
+ found, i);
+ }
+#endif
+ return found;
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_app_registration
+**
+** Description This function registers an HDP application MCAP and DP
+**
+** Returns tBTA_HL_STATUS -registration status
+**
+*******************************************************************************/
+tBTA_HL_STATUS bta_hl_app_registration(UINT8 app_idx)
+{
+ tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+ tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tMCA_REG reg;
+ tMCA_CS mca_cs;
+ UINT8 i, num_of_mdeps;
+
+
+#if BTA_HL_DEBUG == TRUE
+ APPL_TRACE_DEBUG1("bta_hl_app_registration app_idx=%d", app_idx);
+#endif
+
+ reg.ctrl_psm = p_acb->ctrl_psm;
+ reg.data_psm = p_acb->data_psm;
+ reg.sec_mask = p_acb->sec_mask;
+ reg.rsp_tout = BTA_HL_MCAP_RSP_TOUT;
+
+ if ( (p_acb->app_handle = (tBTA_HL_APP_HANDLE) MCA_Register(&reg, bta_hl_mcap_ctrl_cback))!=0)
+ {
+ mca_cs.type = MCA_TDEP_ECHO;
+ mca_cs.max_mdl = BTA_HL_NUM_MDLS_PER_MDEP;
+ mca_cs.p_data_cback = bta_hl_mcap_data_cback;
+
+ if (MCA_CreateDep((tMCA_HANDLE)p_acb->app_handle,
+ &(p_acb->sup_feature.mdep[0].mdep_id),
+ &mca_cs) == MCA_SUCCESS)
+ {
+ if (p_acb->sup_feature.mdep[0].mdep_id != BTA_HL_ECHO_TEST_MDEP_ID)
+ {
+ status = BTA_HL_STATUS_MCAP_REG_FAIL;
+ APPL_TRACE_ERROR1("BAD MDEP ID for echo test mdep_id=%d",
+ p_acb->sup_feature.mdep[0].mdep_id );
+ }
+ }
+ else
+ {
+ status = BTA_HL_STATUS_MCAP_REG_FAIL;
+ APPL_TRACE_ERROR0("MCA_CreateDep for echo test(mdep_id=0) failed");
+ }
+
+
+ if ((status == BTA_HL_STATUS_OK) &&
+ bta_hl_co_get_num_of_mdep(p_acb->app_id, &num_of_mdeps))
+ {
+ p_acb->sup_feature.num_of_mdeps = num_of_mdeps+1;
+
+ for (i=1; i<p_acb->sup_feature.num_of_mdeps; i++)
+ {
+ mca_cs.type = MCA_TDEP_DATA;
+ mca_cs.max_mdl = BTA_HL_NUM_MDLS_PER_MDEP;
+ mca_cs.p_data_cback = bta_hl_mcap_data_cback;
+
+ if (MCA_CreateDep((tMCA_HANDLE)p_acb->app_handle,
+ &(p_acb->sup_feature.mdep[i].mdep_id), &mca_cs) == MCA_SUCCESS)
+ {
+ if (bta_hl_co_get_mdep_config(p_acb->app_id,
+ i,
+ p_acb->sup_feature.mdep[i].mdep_id,
+ &p_acb->sup_feature.mdep[i].mdep_cfg))
+ {
+ if (p_acb->sup_feature.mdep[i].mdep_cfg.mdep_role == BTA_HL_MDEP_ROLE_SOURCE)
+ {
+ p_acb->sup_feature.app_role_mask |= BTA_HL_MDEP_ROLE_MASK_SOURCE;
+ }
+ else if (p_acb->sup_feature.mdep[i].mdep_cfg.mdep_role == BTA_HL_MDEP_ROLE_SINK)
+ {
+ p_acb->sup_feature.app_role_mask |= BTA_HL_MDEP_ROLE_MASK_SINK;
+ }
+ else
+ {
+ status = BTA_HL_STATUS_MDEP_CO_FAIL;
+ break;
+ }
+ }
+ else
+ {
+ status = BTA_HL_STATUS_MDEP_CO_FAIL;
+ break;
+ }
+ }
+ else
+ {
+ status = BTA_HL_STATUS_MCAP_REG_FAIL;
+ break;
+ }
+ }
+
+
+
+ if ((status == BTA_HL_STATUS_OK) &&
+ (p_acb->sup_feature.app_role_mask == BTA_HL_MDEP_ROLE_MASK_SOURCE))
+ {
+ /* this is a source only applciation */
+ p_acb->sup_feature.advertize_source_sdp =
+ bta_hl_co_advrtise_source_sdp(p_acb->app_id);
+ }
+
+ if ((status == BTA_HL_STATUS_OK)&&
+ (!bta_hl_co_get_echo_config(p_acb->app_id, &p_acb->sup_feature.echo_cfg)))
+ {
+ status = BTA_HL_STATUS_ECHO_CO_FAIL;
+ }
+
+ if ((status == BTA_HL_STATUS_OK)&&
+ (!bta_hl_co_load_mdl_config(p_acb->app_id, BTA_HL_NUM_MDL_CFGS, &p_acb->mdl_cfg[0])))
+ {
+ status = BTA_HL_STATUS_MDL_CFG_CO_FAIL;
+ }
+ }
+ else
+ {
+ status = BTA_HL_STATUS_MDEP_CO_FAIL;
+ }
+ }
+ else
+ {
+ status = BTA_HL_STATUS_MCAP_REG_FAIL;
+ }
+
+ if (status == BTA_HL_STATUS_OK)
+ {
+ status = bta_hl_sdp_register(app_idx);
+ }
+
+ return status;
+}
+
+
+/*******************************************************************************
+**
+** Function bta_hl_discard_data
+**
+** Description This function discard an HDP event
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hl_discard_data(UINT16 event, tBTA_HL_DATA *p_data)
+{
+
+#if BTA_HL_DEBUG == TRUE
+ APPL_TRACE_ERROR1("BTA HL Discard event=%s",bta_hl_evt_code(event));
+
+#endif
+
+ switch (event)
+ {
+ case BTA_HL_API_SEND_DATA_EVT:
+ break;
+
+ case BTA_HL_MCA_RCV_DATA_EVT:
+ utl_freebuf((void**)&p_data->mca_rcv_data_evt.p_pkt);
+ break;
+
+ default:
+ /*Nothing to free*/
+ break;
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_save_mdl_cfg
+**
+** Description This function saves the MDL configuration
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hl_save_mdl_cfg(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx )
+{
+ tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ UINT8 mdl_cfg_idx;
+ tBTA_HL_MDL_ID mdl_id;
+ BOOLEAN found=TRUE;
+ tBTA_HL_MDL_CFG mdl_cfg;
+ tBTA_HL_MDEP *p_mdep_cfg;
+ tBTA_HL_L2CAP_CFG_INFO l2cap_cfg;
+ UINT8 time_val;
+ mdl_id = p_dcb->mdl_id;
+ if (!bta_hl_find_mdl_cfg_idx(app_idx, mcl_idx, mdl_id, &mdl_cfg_idx))
+ {
+ if (!bta_hl_find_avail_mdl_cfg_idx(app_idx, mcl_idx, &mdl_cfg_idx))
+ {
+ APPL_TRACE_ERROR0("No space to save the MDL config");
+ found= FALSE; /*no space available*/
+ }
+ }
+
+ if (found)
+ {
+ bta_hl_get_l2cap_cfg(p_dcb->mdl_handle, &l2cap_cfg);
+ if (!bta_hl_get_cur_time(app_idx, &time_val ))
+ {
+ bta_hl_compact_mdl_cfg_time(app_idx);
+ bta_hl_get_cur_time(app_idx, &time_val);
+ }
+ mdl_cfg.active = TRUE;
+ mdl_cfg.time = time_val;
+ mdl_cfg.mdl_id = p_dcb->mdl_id;
+ mdl_cfg.dch_mode = p_dcb->dch_mode;
+ mdl_cfg.mtu = l2cap_cfg.mtu;
+ mdl_cfg.fcs = l2cap_cfg.fcs;
+
+ bdcpy(mdl_cfg.peer_bd_addr, p_mcb->bd_addr);
+ mdl_cfg.local_mdep_id= p_dcb->local_mdep_id;
+ p_mdep_cfg = &p_acb->sup_feature.mdep[p_dcb->local_mdep_cfg_idx];
+ mdl_cfg.local_mdep_role= p_mdep_cfg->mdep_cfg.mdep_role;
+ memcpy(&p_acb->mdl_cfg[mdl_cfg_idx], &mdl_cfg, sizeof(tBTA_HL_MDL_CFG));
+ bta_hl_co_save_mdl(p_acb->app_id, mdl_cfg_idx, &mdl_cfg);
+ }
+
+#if BTA_HL_DEBUG == TRUE
+ if (found)
+ {
+ if (p_dcb->mtu != l2cap_cfg.mtu)
+ {
+ APPL_TRACE_WARNING2("MCAP and L2CAP peer mtu size out of sync from MCAP mtu=%d from l2cap mtu=%d",
+ p_dcb->mtu, l2cap_cfg.mtu);
+ }
+ APPL_TRACE_DEBUG1("bta_hl_save_mdl_cfg saved=%d", found);
+ APPL_TRACE_DEBUG4("Saved. L2cap cfg mdl_id=%d mtu=%d fcs=%d dch_mode=%d",
+ mdl_cfg.mdl_id, mdl_cfg.mtu, mdl_cfg.fcs, mdl_cfg.dch_mode);
+ }
+#endif
+
+
+
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_set_dch_chan_cfg
+**
+** Description This function setups the L2CAP DCH channel configuration
+**
+** Returns void
+*******************************************************************************/
+void bta_hl_set_dch_chan_cfg(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,tBTA_HL_DATA *p_data)
+{
+ tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ UINT8 l2cap_mode = L2CAP_FCR_ERTM_MODE;
+ tBTA_HL_SUP_FEATURE *p_sup_feature= &p_acb->sup_feature;
+ UINT8 local_mdep_cfg_idx = p_dcb->local_mdep_cfg_idx;
+
+ switch (p_dcb->dch_oper)
+ {
+ case BTA_HL_DCH_OP_LOCAL_RECONNECT:
+ case BTA_HL_DCH_OP_REMOTE_RECONNECT:
+ if (p_dcb->dch_mode == BTA_HL_DCH_MODE_STREAMING)
+ l2cap_mode = L2CAP_FCR_STREAM_MODE;
+ break;
+ case BTA_HL_DCH_OP_LOCAL_OPEN:
+ if (p_data->mca_evt.mca_data.create_cfm.cfg == BTA_HL_DCH_CFG_STREAMING)
+ l2cap_mode = L2CAP_FCR_STREAM_MODE;
+ break;
+ case BTA_HL_DCH_OP_REMOTE_OPEN:
+ if (p_dcb->local_cfg == BTA_HL_DCH_CFG_STREAMING )
+ l2cap_mode = L2CAP_FCR_STREAM_MODE;
+ break;
+ default:
+ APPL_TRACE_ERROR1("Invalid dch oper=%d for set dch chan cfg", p_dcb->dch_oper);
+ break;
+ }
+ p_dcb->chnl_cfg.fcr_opt.mode = l2cap_mode;
+ p_dcb->chnl_cfg.fcr_opt.mps = bta_hl_set_mps(p_dcb->max_rx_apdu_size);
+ p_dcb->chnl_cfg.fcr_opt.tx_win_sz = bta_hl_set_tx_win_size(p_dcb->max_rx_apdu_size,
+ p_dcb->chnl_cfg.fcr_opt.mps);
+ p_dcb->chnl_cfg.fcr_opt.max_transmit= BTA_HL_L2C_MAX_TRANSMIT;
+ p_dcb->chnl_cfg.fcr_opt.rtrans_tout = BTA_HL_L2C_RTRANS_TOUT;
+ p_dcb->chnl_cfg.fcr_opt.mon_tout = BTA_HL_L2C_MON_TOUT;
+
+ p_dcb->chnl_cfg.user_rx_pool_id = bta_hl_set_user_rx_pool_id(p_dcb->max_rx_apdu_size);
+ p_dcb->chnl_cfg.user_tx_pool_id = bta_hl_set_user_tx_pool_id(p_dcb->max_tx_apdu_size);
+ p_dcb->chnl_cfg.fcr_rx_pool_id = BTA_HL_L2C_FCR_RX_POOL_ID;
+ p_dcb->chnl_cfg.fcr_tx_pool_id = BTA_HL_L2C_FCR_TX_POOL_ID;
+ p_dcb->chnl_cfg.data_mtu = p_dcb->max_rx_apdu_size;
+
+ p_dcb->chnl_cfg.fcs = BTA_HL_MCA_NO_FCS;
+ if (local_mdep_cfg_idx != BTA_HL_ECHO_TEST_MDEP_CFG_IDX)
+ {
+ if (p_sup_feature->mdep[local_mdep_cfg_idx].mdep_cfg.mdep_role ==
+ BTA_HL_MDEP_ROLE_SOURCE)
+ {
+ p_dcb->chnl_cfg.fcs = BTA_HL_DEFAULT_SOURCE_FCS;
+ }
+ }
+ else
+ {
+ p_dcb->chnl_cfg.fcs = BTA_HL_MCA_USE_FCS;
+ }
+
+#if BTA_HL_DEBUG == TRUE
+ APPL_TRACE_DEBUG1("L2CAP Params l2cap_mode[3-ERTM 4-STREAM]=%d", l2cap_mode);
+ APPL_TRACE_DEBUG2("Use FCS =%s mtu=%d", ((p_dcb->chnl_cfg.fcs & 1)?"YES":"NO"),
+ p_dcb->chnl_cfg.data_mtu);
+ APPL_TRACE_DEBUG5("tx_win_sz=%d, max_transmit=%d, rtrans_tout=%d, mon_tout=%d, mps=%d",
+ p_dcb->chnl_cfg.fcr_opt.tx_win_sz,
+ p_dcb->chnl_cfg.fcr_opt.max_transmit,
+ p_dcb->chnl_cfg.fcr_opt.rtrans_tout,
+ p_dcb->chnl_cfg.fcr_opt.mon_tout,
+ p_dcb->chnl_cfg.fcr_opt.mps);
+
+ APPL_TRACE_DEBUG4("USER rx_pool_id=%d, tx_pool_id=%d, FCR rx_pool_id=%d, tx_pool_id=%d",
+ p_dcb->chnl_cfg.user_rx_pool_id,
+ p_dcb->chnl_cfg.user_tx_pool_id,
+ p_dcb->chnl_cfg.fcr_rx_pool_id,
+ p_dcb->chnl_cfg.fcr_tx_pool_id);
+
+#endif
+
+
+
+
+
+
+
+
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_get_l2cap_cfg
+**
+** Description This function get the current L2CAP channel configuration
+**
+** Returns BOOLEAN - TRUE - operation is successful
+*******************************************************************************/
+BOOLEAN bta_hl_get_l2cap_cfg(tBTA_HL_MDL_HANDLE mdl_hnd, tBTA_HL_L2CAP_CFG_INFO *p_cfg)
+{
+ BOOLEAN success = FALSE;
+ UINT16 lcid;
+ tL2CAP_CFG_INFO *p_our_cfg;
+ tL2CAP_CH_CFG_BITS our_cfg_bits;
+ tL2CAP_CFG_INFO *p_peer_cfg;
+ tL2CAP_CH_CFG_BITS peer_cfg_bits;
+
+ lcid = MCA_GetL2CapChannel((tMCA_DL) mdl_hnd);
+ if ( lcid &&
+ L2CA_GetCurrentConfig(lcid, &p_our_cfg, &our_cfg_bits, &p_peer_cfg,
+ &peer_cfg_bits))
+ {
+ p_cfg->fcs = BTA_HL_MCA_NO_FCS;
+ if (our_cfg_bits & L2CAP_CH_CFG_MASK_FCS)
+ {
+ p_cfg->fcs |= p_our_cfg->fcs;
+ }
+ else
+ {
+ p_cfg->fcs = BTA_HL_MCA_USE_FCS;
+ }
+
+ if (p_cfg->fcs != BTA_HL_MCA_USE_FCS )
+ {
+ if (peer_cfg_bits & L2CAP_CH_CFG_MASK_FCS)
+ {
+ p_cfg->fcs |= p_peer_cfg->fcs;
+ }
+ else
+ {
+ p_cfg->fcs = BTA_HL_MCA_USE_FCS;
+ }
+ }
+
+ p_cfg->mtu =0;
+ if (peer_cfg_bits & L2CAP_CH_CFG_MASK_MTU)
+ {
+ p_cfg->mtu = p_peer_cfg->mtu;
+ }
+ else
+ {
+ p_cfg->mtu = L2CAP_DEFAULT_MTU;
+ }
+ success = TRUE;
+ }
+
+#if BTA_HL_DEBUG == TRUE
+ if (!success)
+ {
+ APPL_TRACE_DEBUG3("bta_hl_get_l2cap_cfg success=%d mdl=%d lcid=%d", success, mdl_hnd, lcid);
+ APPL_TRACE_DEBUG2("l2cap mtu=%d fcs=%d", p_cfg->mtu, p_cfg->fcs);
+ }
+#endif
+
+ return success;
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_validate_chan_cfg
+**
+** Description This function validates the L2CAP channel configuration
+**
+** Returns BOOLEAN - TRUE - validation is successful
+*******************************************************************************/
+BOOLEAN bta_hl_validate_chan_cfg(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx)
+{
+ tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ BOOLEAN success = FALSE;
+ UINT8 mdl_cfg_idx;
+ tBTA_HL_L2CAP_CFG_INFO l2cap_cfg;
+
+
+ if (bta_hl_get_l2cap_cfg(p_dcb->mdl_handle, &l2cap_cfg) &&
+ bta_hl_find_mdl_cfg_idx(app_idx, mcl_idx, p_dcb->mdl_id, &mdl_cfg_idx))
+ {
+ if ((p_acb->mdl_cfg[mdl_cfg_idx].mtu <= l2cap_cfg.mtu) &&
+ (p_acb->mdl_cfg[mdl_cfg_idx].fcs == l2cap_cfg.fcs) &&
+ (p_acb->mdl_cfg[mdl_cfg_idx].dch_mode == p_dcb->dch_mode))
+ {
+ success = TRUE;
+ }
+ }
+
+
+#if BTA_HL_DEBUG == TRUE
+
+ if (p_dcb->mtu != l2cap_cfg.mtu)
+ {
+ APPL_TRACE_WARNING2("MCAP and L2CAP peer mtu size out of sync from MCAP mtu=%d from l2cap mtu=%d",
+ p_dcb->mtu, l2cap_cfg.mtu);
+ }
+
+ if (!success)
+ {
+ APPL_TRACE_DEBUG4("bta_hl_validate_chan_cfg success=%d app_idx=%d mcl_idx=%d mdl_idx=%d",success, app_idx, mcl_idx, mdl_idx);
+ APPL_TRACE_DEBUG3("Cur. L2cap cfg mtu=%d fcs=%d dch_mode=%d", l2cap_cfg.mtu, l2cap_cfg.fcs, p_dcb->dch_mode);
+ APPL_TRACE_DEBUG3("From saved: L2cap cfg mtu=%d fcs=%d dch_mode=%d", p_acb->mdl_cfg[mdl_cfg_idx].mtu,
+ p_acb->mdl_cfg[mdl_cfg_idx].fcs , p_acb->mdl_cfg[mdl_cfg_idx].dch_mode);
+ }
+#endif
+
+ return success;
+}
+
+
+/*******************************************************************************
+**
+** Function bta_hl_is_cong_on
+**
+** Description This function checks whether the congestion condition is on or not
+**
+** Returns BOOLEAN - TRUE DCH is congested
+** FALSE not congested
+**
+*******************************************************************************/
+BOOLEAN bta_hl_is_cong_on(UINT8 app_id, BD_ADDR bd_addr, tBTA_HL_MDL_ID mdl_id)
+
+{
+ tBTA_HL_MDL_CB *p_dcb;
+ UINT8 app_idx, mcl_idx, mdl_idx;
+ BOOLEAN cong_status = TRUE;
+
+ if (bta_hl_find_app_idx(app_id, &app_idx))
+ {
+ if (bta_hl_find_mcl_idx(app_idx, bd_addr, &mcl_idx ))
+ {
+ if (bta_hl_find_mdl_idx(app_idx, mcl_idx, mdl_id, &mdl_idx ))
+ {
+ p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ cong_status = p_dcb->cong;
+ }
+ }
+ }
+
+ return cong_status;
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_check_cch_close
+**
+** Description This function checks whether there is a pending CCH close request
+** or not
+**
+** Returns void
+*******************************************************************************/
+void bta_hl_check_cch_close(UINT8 app_idx, UINT8 mcl_idx, tBTA_HL_DATA *p_data, BOOLEAN check_dch_setup )
+{
+ tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_MDL_CB *p_dcb;
+ UINT8 mdl_idx;
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG1("bta_hl_check_cch_close cch_close_dch_oper=%d",p_mcb->cch_close_dch_oper );
+#endif
+
+ if (p_mcb->cch_oper == BTA_HL_CCH_OP_LOCAL_CLOSE)
+ {
+ if (check_dch_setup && bta_hl_find_dch_setup_mdl_idx(app_idx, mcl_idx, &mdl_idx))
+ {
+ p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ if (!p_mcb->rsp_tout)
+ {
+ p_mcb->cch_close_dch_oper = BTA_HL_CCH_CLOSE_OP_DCH_ABORT;
+
+ if (!p_dcb->abort_oper)
+ {
+ p_dcb->abort_oper |= BTA_HL_ABORT_CCH_CLOSE_MASK;
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_ABORT_EVT, p_data);
+ }
+ }
+ else
+ {
+ p_mcb->cch_close_dch_oper = BTA_HL_CCH_CLOSE_OP_DCH_CLOSE;
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
+ }
+ }
+ else if (bta_hl_find_an_active_mdl_idx(app_idx, mcl_idx,&mdl_idx))
+ {
+ p_mcb->cch_close_dch_oper = BTA_HL_CCH_CLOSE_OP_DCH_CLOSE;
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_EVT, p_data);
+ }
+ else
+ {
+ p_mcb->cch_close_dch_oper = BTA_HL_CCH_CLOSE_OP_DCH_NONE;
+ bta_hl_cch_sm_execute(app_idx, mcl_idx, BTA_HL_CCH_CLOSE_EVT, p_data);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_clean_app
+**
+** Description Cleans up the HDP application resources and control block
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hl_clean_app(UINT8 app_idx)
+{
+ tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ int i, num_act_apps=0;
+
+#if BTA_HL_DEBUG == TRUE
+ APPL_TRACE_DEBUG0("bta_hl_clean_app");
+#endif
+ MCA_Deregister((tMCA_HANDLE)p_acb->app_handle);
+
+ if (p_acb->sdp_handle) SDP_DeleteRecord(p_acb->sdp_handle);
+
+ memset((void *) p_acb, 0, sizeof(tBTA_HL_APP_CB));
+
+ /* check any application is still active */
+ for (i=0; i < BTA_HL_NUM_APPS ; i ++)
+ {
+ p_acb = BTA_HL_GET_APP_CB_PTR(i);
+ if (p_acb->in_use) num_act_apps++;
+ }
+
+ if (!num_act_apps)
+ {
+ bta_sys_remove_uuid(UUID_SERVCLASS_HDP_PROFILE);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_check_deregistration
+**
+** Description This function checks whether there is a pending deregistration
+** request or not
+**
+** Returns void
+*******************************************************************************/
+void bta_hl_check_deregistration(UINT8 app_idx, tBTA_HL_DATA *p_data )
+{
+ tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_MCL_CB *p_mcb;
+ UINT8 mcl_idx;
+ tBTA_HL evt_data;
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG0("bta_hl_check_deregistration");
+#endif
+
+ if (p_acb->deregistering)
+ {
+ if (bta_hl_find_an_in_use_mcl_idx(app_idx, &mcl_idx))
+ {
+ p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ if (p_mcb->cch_oper != BTA_HL_CCH_OP_LOCAL_CLOSE)
+ {
+ p_mcb->cch_oper = BTA_HL_CCH_OP_LOCAL_CLOSE;
+ bta_hl_check_cch_close(app_idx,mcl_idx,p_data, TRUE);
+ }
+ }
+ else
+ {
+ /* all cchs are closed */
+ evt_data.dereg_cfm.app_handle = p_acb->app_handle;
+ evt_data.dereg_cfm.status = BTA_HL_STATUS_OK;
+ p_acb->p_cback(BTA_HL_DEREGISTER_CFM_EVT, (tBTA_HL *) &evt_data );
+ bta_hl_clean_app(app_idx);
+ bta_hl_check_disable(p_data);
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function bta_hl_check_disable
+**
+** Description This function checks whether there is a pending disable
+** request or not
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hl_check_disable(tBTA_HL_DATA *p_data )
+{
+ tBTA_HL_CB *p_cb= &bta_hl_cb;
+ tBTA_HL_APP_CB *p_acb;
+ UINT8 app_idx;
+ tBTA_HL_CTRL evt_data;
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG0("bta_hl_check_disable");
+#endif
+
+ if (bta_hl_cb.disabling)
+ {
+ if (bta_hl_find_an_in_use_app_idx(&app_idx))
+ {
+ p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ if (!p_acb->deregistering)
+ {
+ p_acb->deregistering = TRUE;
+ bta_hl_check_deregistration(app_idx, p_data);
+ }
+ }
+ else
+ {
+ /* all apps are deregistered */
+ bta_sys_deregister(BTA_ID_HL);
+ evt_data.disable_cfm.status = BTA_HL_STATUS_OK;
+ if (p_cb->p_ctrl_cback) p_cb->p_ctrl_cback(BTA_HL_CTRL_DISABLE_CFM_EVT, (tBTA_HL_CTRL *) &evt_data);
+ memset((void *) p_cb, 0, sizeof(tBTA_HL_CB));
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_build_abort_cfm
+**
+** Description This function builds the abort confirmation event data
+**
+** Returns None
+**
+*******************************************************************************/
+void bta_hl_build_abort_cfm(tBTA_HL *p_evt_data,
+ tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_STATUS status)
+{
+ p_evt_data->dch_abort_cfm.status = status;
+ p_evt_data->dch_abort_cfm.mcl_handle = mcl_handle;
+ p_evt_data->dch_abort_cfm.app_handle = app_handle;
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_build_abort_ind
+**
+** Description This function builds the abort indication event data
+**
+** Returns None
+**
+*******************************************************************************/
+void bta_hl_build_abort_ind(tBTA_HL *p_evt_data,
+ tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle)
+{
+ p_evt_data->dch_abort_ind.mcl_handle = mcl_handle;
+ p_evt_data->dch_abort_ind.app_handle = app_handle;
+}
+/*******************************************************************************
+**
+** Function bta_hl_build_close_cfm
+**
+** Description This function builds the close confirmation event data
+**
+** Returns None
+**
+*******************************************************************************/
+void bta_hl_build_dch_close_cfm(tBTA_HL *p_evt_data,
+ tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_MDL_HANDLE mdl_handle,
+ tBTA_HL_STATUS status)
+{
+ p_evt_data->dch_close_cfm.status = status;
+ p_evt_data->dch_close_cfm.mdl_handle = mdl_handle;
+ p_evt_data->dch_close_cfm.mcl_handle = mcl_handle;
+ p_evt_data->dch_close_cfm.app_handle = app_handle;
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_build_dch_close_ind
+**
+** Description This function builds the close indication event data
+**
+** Returns None
+**
+*******************************************************************************/
+void bta_hl_build_dch_close_ind(tBTA_HL *p_evt_data,
+ tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_MDL_HANDLE mdl_handle,
+ BOOLEAN intentional)
+{
+ p_evt_data->dch_close_ind.mdl_handle = mdl_handle;
+ p_evt_data->dch_close_ind.mcl_handle = mcl_handle;
+ p_evt_data->dch_close_ind.app_handle = app_handle;
+ p_evt_data->dch_close_ind.intentional = intentional;
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_build_send_data_cfm
+**
+** Description This function builds the send data confirmation event data
+**
+** Returns None
+**
+*******************************************************************************/
+void bta_hl_build_send_data_cfm(tBTA_HL *p_evt_data,
+ tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_MDL_HANDLE mdl_handle,
+ tBTA_HL_STATUS status )
+{
+
+ p_evt_data->dch_send_data_cfm.mdl_handle = mdl_handle;
+ p_evt_data->dch_send_data_cfm.mcl_handle = mcl_handle;
+ p_evt_data->dch_send_data_cfm.app_handle = app_handle;
+ p_evt_data->dch_send_data_cfm.status = status;
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_build_rcv_data_ind
+**
+** Description This function builds the received data indication event data
+**
+** Returns None
+**
+*******************************************************************************/
+void bta_hl_build_rcv_data_ind(tBTA_HL *p_evt_data,
+ tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_MDL_HANDLE mdl_handle)
+{
+ p_evt_data->dch_rcv_data_ind.mdl_handle = mdl_handle;
+ p_evt_data->dch_rcv_data_ind.mcl_handle = mcl_handle;
+ p_evt_data->dch_rcv_data_ind.app_handle = app_handle;
+}
+
+
+/*******************************************************************************
+**
+** Function bta_hl_build_cch_open_cfm
+**
+** Description This function builds the CCH open confirmation event data
+**
+** Returns None
+**
+*******************************************************************************/
+void bta_hl_build_cch_open_cfm(tBTA_HL *p_evt_data,
+ tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle,
+ BD_ADDR bd_addr,
+ tBTA_HL_STATUS status )
+{
+
+ p_evt_data->cch_open_cfm.app_handle = app_handle;
+ p_evt_data->cch_open_cfm.mcl_handle = mcl_handle;
+ bdcpy(p_evt_data->cch_open_cfm.bd_addr, bd_addr);
+ p_evt_data->cch_open_cfm.status = status;
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_build_cch_open_ind
+**
+** Description This function builds the CCH open indication event data
+**
+** Returns None
+**
+*******************************************************************************/
+void bta_hl_build_cch_open_ind(tBTA_HL *p_evt_data, tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle,
+ BD_ADDR bd_addr )
+{
+
+ p_evt_data->cch_open_ind.app_handle = app_handle;
+ p_evt_data->cch_open_ind.mcl_handle = mcl_handle;
+ bdcpy(p_evt_data->cch_open_ind.bd_addr, bd_addr);
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_build_cch_close_cfm
+**
+** Description This function builds the CCH close confirmation event data
+**
+** Returns None
+**
+*******************************************************************************/
+void bta_hl_build_cch_close_cfm(tBTA_HL *p_evt_data,
+ tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_STATUS status )
+{
+ p_evt_data->cch_close_cfm.mcl_handle = mcl_handle;
+ p_evt_data->cch_close_cfm.app_handle = app_handle;
+ p_evt_data->cch_close_cfm.status = status;
+}
+
+
+/*******************************************************************************
+**
+** Function bta_hl_build_cch_close_ind
+**
+** Description This function builds the CCH colse indication event data
+**
+** Returns None
+**
+*******************************************************************************/
+void bta_hl_build_cch_close_ind(tBTA_HL *p_evt_data,
+ tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle,
+ BOOLEAN intentional)
+{
+ p_evt_data->cch_close_ind.mcl_handle = mcl_handle;
+ p_evt_data->cch_close_ind.app_handle = app_handle;
+ p_evt_data->cch_close_ind.intentional = intentional;
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_build_dch_open_cfm
+**
+** Description This function builds the DCH open confirmation event data
+**
+** Returns None
+**
+*******************************************************************************/
+void bta_hl_build_dch_open_cfm(tBTA_HL *p_evt_data,
+ tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_MDL_HANDLE mdl_handle,
+ tBTA_HL_MDEP_ID local_mdep_id,
+ tBTA_HL_MDL_ID mdl_id,
+ tBTA_HL_DCH_MODE dch_mode,
+ BOOLEAN first_reliable,
+ UINT16 mtu,
+ tBTA_HL_STATUS status)
+
+{
+ p_evt_data->dch_open_cfm.mdl_handle = mdl_handle;
+ p_evt_data->dch_open_cfm.mcl_handle = mcl_handle;
+ p_evt_data->dch_open_cfm.app_handle = app_handle;
+ p_evt_data->dch_open_cfm.local_mdep_id = local_mdep_id;
+ p_evt_data->dch_open_cfm.mdl_id = mdl_id;
+ p_evt_data->dch_open_cfm.dch_mode = dch_mode;
+ p_evt_data->dch_open_cfm.first_reliable = first_reliable;
+ p_evt_data->dch_open_cfm.mtu = mtu;
+ p_evt_data->dch_open_cfm.status = status;
+}
+
+
+/*******************************************************************************
+**
+** Function bta_hl_build_sdp_query_cfm
+**
+** Description This function builds the SDP query indication event data
+**
+** Returns None
+**
+*******************************************************************************/
+void bta_hl_build_sdp_query_cfm(tBTA_HL *p_evt_data,
+ tBTA_HL_APP_HANDLE app_handle,
+ BD_ADDR bd_addr,
+ tBTA_HL_SDP *p_sdp,
+ tBTA_HL_STATUS status)
+
+{
+ p_evt_data->sdp_query_cfm.app_handle = app_handle;
+ bdcpy(p_evt_data->sdp_query_cfm.bd_addr, bd_addr);
+ p_evt_data->sdp_query_cfm.p_sdp = p_sdp;
+ p_evt_data->sdp_query_cfm.status = status;
+}
+
+
+/*******************************************************************************
+**
+** Function bta_hl_build_delete_mdl_cfm
+**
+** Description This function builds the delete MDL confirmation event data
+**
+** Returns None
+**
+*******************************************************************************/
+void bta_hl_build_delete_mdl_cfm(tBTA_HL *p_evt_data,
+ tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_MDL_ID mdl_id,
+ tBTA_HL_STATUS status)
+
+{
+ p_evt_data->delete_mdl_cfm.mcl_handle = mcl_handle;
+ p_evt_data->delete_mdl_cfm.app_handle = app_handle;
+ p_evt_data->delete_mdl_cfm.mdl_id = mdl_id;
+ p_evt_data->delete_mdl_cfm.status = status;
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_build_echo_test_cfm
+**
+** Description This function builds the echo test confirmation event data
+**
+** Returns None
+**
+*******************************************************************************/
+void bta_hl_build_echo_test_cfm(tBTA_HL *p_evt_data,
+ tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_STATUS status )
+{
+ p_evt_data->echo_test_cfm.mcl_handle = mcl_handle;
+ p_evt_data->echo_test_cfm.app_handle = app_handle;
+ p_evt_data->echo_test_cfm.status = status;
+}
+
+
+/*****************************************************************************
+** Debug Functions
+*****************************************************************************/
+#if (BTA_HL_DEBUG == TRUE)
+
+/*******************************************************************************
+**
+** Function bta_hl_status_code
+**
+** Description get the status string pointer
+**
+** Returns char * - status string pointer
+**
+*******************************************************************************/
+char *bta_hl_status_code(tBTA_HL_STATUS status)
+{
+ switch (status)
+ {
+ case BTA_HL_STATUS_OK:
+ return "BTA_HL_STATUS_OK";
+ case BTA_HL_STATUS_FAIL:
+ return "BTA_HL_STATUS_FAIL";
+ case BTA_HL_STATUS_ABORTED:
+ return "BTA_HL_STATUS_ABORTED";
+ case BTA_HL_STATUS_NO_RESOURCE:
+ return "BTA_HL_STATUS_NO_RESOURCE";
+ case BTA_HL_STATUS_LAST_ITEM:
+ return "BTA_HL_STATUS_LAST_ITEM";
+ case BTA_HL_STATUS_DUPLICATE_APP_ID:
+ return "BTA_HL_STATUS_DUPLICATE_APP_ID";
+ case BTA_HL_STATUS_INVALID_APP_HANDLE:
+ return "BTA_HL_STATUS_INVALID_APP_HANDLE";
+ case BTA_HL_STATUS_INVALID_MCL_HANDLE:
+ return "BTA_HL_STATUS_INVALID_MCL_HANDLE";
+ case BTA_HL_STATUS_MCAP_REG_FAIL:
+ return "BTA_HL_STATUS_MCAP_REG_FAIL";
+ case BTA_HL_STATUS_MDEP_CO_FAIL:
+ return "BTA_HL_STATUS_MDEP_CO_FAIL";
+ case BTA_HL_STATUS_ECHO_CO_FAIL:
+ return "BTA_HL_STATUS_ECHO_CO_FAIL";
+ case BTA_HL_STATUS_MDL_CFG_CO_FAIL:
+ return "BTA_HL_STATUS_MDL_CFG_CO_FAIL";
+ case BTA_HL_STATUS_SDP_NO_RESOURCE:
+ return "BTA_HL_STATUS_SDP_NO_RESOURCE";
+ case BTA_HL_STATUS_SDP_FAIL:
+ return "BTA_HL_STATUS_SDP_FAIL";
+ case BTA_HL_STATUS_NO_CCH:
+ return "BTA_HL_STATUS_NO_CCH";
+ case BTA_HL_STATUS_NO_MCL:
+ return "BTA_HL_STATUS_NO_MCL";
+
+ case BTA_HL_STATUS_NO_FIRST_RELIABLE:
+ return "BTA_HL_STATUS_NO_FIRST_RELIABLE";
+ case BTA_HL_STATUS_INVALID_DCH_CFG:
+ return "BTA_HL_STATUS_INVALID_DCH_CFG";
+ case BTA_HL_STATUS_INVALID_BD_ADDR:
+ return "BTA_HL_STATUS_INVALID_BD_ADDR";
+ case BTA_HL_STATUS_INVALID_RECONNECT_CFG:
+ return "BTA_HL_STATUS_INVALID_RECONNECT_CFG";
+ case BTA_HL_STATUS_ECHO_TEST_BUSY:
+ return "BTA_HL_STATUS_ECHO_TEST_BUSY";
+ case BTA_HL_STATUS_INVALID_LOCAL_MDEP_ID:
+ return "BTA_HL_STATUS_INVALID_LOCAL_MDEP_ID";
+ case BTA_HL_STATUS_INVALID_MDL_ID:
+ return "BTA_HL_STATUS_INVALID_MDL_ID";
+ case BTA_HL_STATUS_NO_MDL_ID_FOUND:
+ return "BTA_HL_STATUS_NO_MDL_ID_FOUND";
+ case BTA_HL_STATUS_DCH_BUSY:
+ return "BTA_HL_STATUS_DCH_BUSY";
+ default:
+ return "Unknown status code";
+ }
+}
+/*******************************************************************************
+**
+** Function bta_hl_evt_code
+**
+** Description Maps HL event code to the corresponding event string
+**
+** Returns string pointer for the associated event name
+**
+*******************************************************************************/
+char *bta_hl_evt_code(tBTA_HL_INT_EVT evt_code)
+{
+ switch (evt_code)
+ {
+ case BTA_HL_CCH_OPEN_EVT:
+ return "BTA_HL_CCH_OPEN_EVT";
+ case BTA_HL_CCH_SDP_OK_EVT:
+ return "BTA_HL_CCH_SDP_OK_EVT";
+ case BTA_HL_CCH_SDP_FAIL_EVT:
+ return "BTA_HL_CCH_SDP_FAIL_EVT";
+ case BTA_HL_MCA_CONNECT_IND_EVT:
+ return "BTA_HL_MCA_CONNECT_IND_EVT";
+ case BTA_HL_MCA_DISCONNECT_IND_EVT:
+ return "BTA_HL_MCA_DISCONNECT_IND_EVT";
+
+ case BTA_HL_CCH_CLOSE_EVT:
+ return "BTA_HL_CCH_CLOSE_EVT";
+ case BTA_HL_CCH_CLOSE_CMPL_EVT:
+ return "BTA_HL_CCH_CLOSE_CMPL_EVT";
+ case BTA_HL_DCH_OPEN_EVT:
+ return "BTA_HL_DCH_OPEN_EVT";
+ case BTA_HL_MCA_CREATE_IND_EVT:
+ return "BTA_HL_MCA_CREATE_IND_EVT";
+ case BTA_HL_MCA_CREATE_CFM_EVT:
+ return "BTA_HL_MCA_CREATE_CFM_EVT";
+ case BTA_HL_MCA_OPEN_IND_EVT:
+ return "BTA_HL_MCA_OPEN_IND_EVT";
+ case BTA_HL_MCA_OPEN_CFM_EVT:
+ return "BTA_HL_MCA_OPEN_CFM_EVT";
+ case BTA_HL_DCH_CLOSE_EVT:
+ return "BTA_HL_DCH_CLOSE_EVT";
+ case BTA_HL_MCA_CLOSE_IND_EVT:
+ return "BTA_HL_MCA_CLOSE_IND_EVT";
+ case BTA_HL_MCA_CLOSE_CFM_EVT:
+ return "BTA_HL_MCA_CLOSE_CFM_EVT";
+ case BTA_HL_API_SEND_DATA_EVT:
+ return "BTA_HL_API_SEND_DATA_EVT";
+ case BTA_HL_MCA_RCV_DATA_EVT:
+ return "BTA_HL_MCA_RCV_DATA_EVT";
+ case BTA_HL_DCH_CLOSE_CMPL_EVT:
+ return "BTA_HL_DCH_CLOSE_CMPL_EVT";
+
+ case BTA_HL_API_ENABLE_EVT:
+ return "BTA_HL_API_ENABLE_EVT";
+ case BTA_HL_API_DISABLE_EVT:
+ return "BTA_HL_API_DISABLE_EVT";
+ case BTA_HL_API_REGISTER_EVT:
+ return "BTA_HL_API_REGISTER_EVT";
+ case BTA_HL_API_DEREGISTER_EVT:
+ return "BTA_HL_API_DEREGISTER_EVT";
+
+ case BTA_HL_API_CCH_OPEN_EVT:
+ return "BTA_HL_API_CCH_OPEN_EVT";
+
+ case BTA_HL_API_CCH_CLOSE_EVT:
+ return "BTA_HL_API_CCH_CLOSE_EVT";
+ case BTA_HL_API_DCH_OPEN_EVT:
+ return "BTA_HL_API_DCH_OPEN_EVT";
+
+ case BTA_HL_API_DCH_RECONNECT_EVT:
+ return "BTA_HL_API_DCH_RECONNECT_EVT";
+ case BTA_HL_API_DCH_CLOSE_EVT:
+ return "BTA_HL_API_DCH_CLOSE_EVT";
+ case BTA_HL_API_DELETE_MDL_EVT:
+ return "BTA_HL_API_DELETE_MDL_EVT";
+ case BTA_HL_API_DCH_ABORT_EVT:
+ return "BTA_HL_API_DCH_ABORT_EVT";
+
+ case BTA_HL_DCH_RECONNECT_EVT:
+ return "BTA_HL_DCH_RECONNECT_EVT";
+ case BTA_HL_DCH_SDP_INIT_EVT:
+ return "BTA_HL_DCH_SDP_INIT_EVT";
+ case BTA_HL_DCH_SDP_FAIL_EVT:
+ return "BTA_HL_DCH_SDP_FAIL_EVT";
+ case BTA_HL_API_DCH_ECHO_TEST_EVT:
+ return "BTA_HL_API_DCH_ECHO_TEST_EVT";
+ case BTA_HL_DCH_CLOSE_ECHO_TEST_EVT:
+ return "BTA_HL_DCH_CLOSE_ECHO_TEST_EVT";
+ case BTA_HL_MCA_RECONNECT_IND_EVT:
+ return "BTA_HL_MCA_RECONNECT_IND_EVT";
+ case BTA_HL_MCA_RECONNECT_CFM_EVT:
+ return "BTA_HL_MCA_RECONNECT_CFM_EVT";
+ case BTA_HL_API_DCH_CREATE_RSP_EVT:
+ return "BTA_HL_API_DCH_CREATE_RSP_EVT";
+ case BTA_HL_DCH_ABORT_EVT:
+ return "BTA_HL_DCH_ABORT_EVT";
+ case BTA_HL_MCA_ABORT_IND_EVT:
+ return "BTA_HL_MCA_ABORT_IND_EVT";
+ case BTA_HL_MCA_ABORT_CFM_EVT:
+ return "BTA_HL_MCA_ABORT_CFM_EVT";
+ case BTA_HL_MCA_DELETE_IND_EVT:
+ return "BTA_HL_MCA_DELETE_IND_EVT";
+ case BTA_HL_MCA_DELETE_CFM_EVT:
+ return "BTA_HL_MCA_DELETE_CFM_EVT";
+ case BTA_HL_MCA_CONG_CHG_EVT:
+ return "BTA_HL_MCA_CONG_CHG_EVT";
+ case BTA_HL_CI_GET_TX_DATA_EVT:
+ return "BTA_HL_CI_GET_TX_DATA_EVT";
+ case BTA_HL_CI_PUT_RX_DATA_EVT:
+ return "BTA_HL_CI_PUT_RX_DATA_EVT";
+ case BTA_HL_CI_GET_ECHO_DATA_EVT:
+ return "BTA_HL_CI_GET_ECHO_DATA_EVT";
+ case BTA_HL_DCH_ECHO_TEST_EVT:
+ return "BTA_HL_DCH_ECHO_TEST_EVT";
+ case BTA_HL_CI_PUT_ECHO_DATA_EVT:
+ return "BTA_HL_CI_PUT_ECHO_DATA_EVT";
+ case BTA_HL_API_SDP_QUERY_EVT:
+ return "BTA_HL_API_SDP_QUERY_EVT";
+ case BTA_HL_SDP_QUERY_OK_EVT:
+ return "BTA_HL_SDP_QUERY_OK_EVT";
+ case BTA_HL_SDP_QUERY_FAIL_EVT:
+ return "BTA_HL_SDP_QUERY_FAIL_EVT";
+ case BTA_HL_MCA_RSP_TOUT_IND_EVT:
+ return "BTA_HL_MCA_RSP_TOUT_IND_EVT";
+
+ default:
+ return "Unknown HL event code";
+ }
+}
+
+#endif /* Debug Functions */
+#endif // HL_INCLUDED
+
+
+
+
+
+
+
+
diff --git a/bta/include/bd.h b/bta/include/bd.h
new file mode 100644
index 0000000..0fd0cf8
--- /dev/null
+++ b/bta/include/bd.h
@@ -0,0 +1,89 @@
+/*****************************************************************************
+**
+** Name: bd.h
+**
+** Description: BD address services.
+**
+** Copyright (c) 2003, Widcomm Inc., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BD_H
+#define BD_H
+
+/*****************************************************************************
+** Constants and data types
+*****************************************************************************/
+
+/* bd addr length and type */
+#ifndef BD_ADDR_LEN
+#define BD_ADDR_LEN 6
+typedef UINT8 BD_ADDR[BD_ADDR_LEN];
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* global constant for "any" bd addr */
+extern const BD_ADDR bd_addr_any;
+extern const BD_ADDR bd_addr_null;
+/*****************************************************************************
+** Function Declarations
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function bdcpy
+**
+** Description Copy bd addr b to a.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+extern void bdcpy(BD_ADDR a, const BD_ADDR b);
+
+/*******************************************************************************
+**
+** Function bdcmp
+**
+** Description Compare bd addr b to a.
+**
+**
+** Returns Zero if b==a, nonzero otherwise (like memcmp).
+**
+*******************************************************************************/
+extern int bdcmp(const BD_ADDR a, const BD_ADDR b);
+
+/*******************************************************************************
+**
+** Function bdcmpany
+**
+** Description Compare bd addr to "any" bd addr.
+**
+**
+** Returns Zero if a equals bd_addr_any.
+**
+*******************************************************************************/
+extern int bdcmpany(const BD_ADDR a);
+
+/*******************************************************************************
+**
+** Function bdsetany
+**
+** Description Set bd addr to "any" bd addr.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+extern void bdsetany(BD_ADDR a);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BD_H */
+
diff --git a/bta/include/bta_ag_api.h b/bta/include/bta_ag_api.h
new file mode 100644
index 0000000..32473ed
--- /dev/null
+++ b/bta/include/bta_ag_api.h
@@ -0,0 +1,496 @@
+/*****************************************************************************
+**
+** Name: bta_ag_api.h
+**
+** Description: This is the public interface file for the audio gateway
+** (AG) subsystem of BTA, Widcomm's Bluetooth application
+** layer for mobile phones.
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_AG_API_H
+#define BTA_AG_API_H
+
+#include "bta_api.h"
+
+/*****************************************************************************
+** Constants and data types
+*****************************************************************************/
+
+/* AG feature masks */
+#define BTA_AG_FEAT_3WAY 0x00000001 /* Three-way calling */
+#define BTA_AG_FEAT_ECNR 0x00000002 /* Echo cancellation and/or noise reduction */
+#define BTA_AG_FEAT_VREC 0x00000004 /* Voice recognition */
+#define BTA_AG_FEAT_INBAND 0x00000008 /* In-band ring tone */
+#define BTA_AG_FEAT_VTAG 0x00000010 /* Attach a phone number to a voice tag */
+#define BTA_AG_FEAT_REJECT 0x00000020 /* Ability to reject incoming call */
+#define BTA_AG_FEAT_ECS 0x00000040 /* Enhanced Call Status */
+#define BTA_AG_FEAT_ECC 0x00000080 /* Enhanced Call Control */
+#define BTA_AG_FEAT_EXTERR 0x00000100 /* Extended error codes */
+#define BTA_AG_FEAT_CODEC 0x00000200 /* Codec Negotiation */
+#define BTA_AG_FEAT_VOIP 0x00000400 /* VoIP call */
+/* Proprietary features: using 31 ~ 16 bits */
+#define BTA_AG_FEAT_BTRH 0x00010000 /* CCAP incoming call hold */
+#define BTA_AG_FEAT_UNAT 0x00020000 /* Pass unknown AT commands to application */
+#define BTA_AG_FEAT_NOSCO 0x00040000 /* No SCO control performed by BTA AG */
+#define BTA_AG_FEAT_NO_ESCO 0x00080000 /* Do not allow or use eSCO */
+
+typedef UINT32 tBTA_AG_FEAT;
+
+/* AG parse mode */
+#define BTA_AG_PARSE 0 /* Perform AT command parsing in AG */
+#define BTA_AG_PASS_THROUGH 1 /* Pass data directly to phone’s AT command interpreter */
+
+typedef UINT8 tBTA_AG_PARSE_MODE;
+
+/* AG open status */
+#define BTA_AG_SUCCESS 0 /* Connection successfully opened */
+#define BTA_AG_FAIL_SDP 1 /* Open failed due to SDP */
+#define BTA_AG_FAIL_RFCOMM 2 /* Open failed due to RFCOMM */
+#define BTA_AG_FAIL_RESOURCES 3 /* out of resources failure */
+
+typedef UINT8 tBTA_AG_STATUS;
+
+/* handle values used with BTA_AgResult */
+#define BTA_AG_HANDLE_NONE 0
+#define BTA_AG_HANDLE_ALL 0xFFFF
+
+/* AG result codes used with BTA_AgResult */
+#define BTA_AG_SPK_RES 0 /* Update speaker volume */
+#define BTA_AG_MIC_RES 1 /* Update microphone volume */
+#define BTA_AG_INBAND_RING_RES 2 /* Update inband ring state */
+#define BTA_AG_CIND_RES 3 /* Send indicator response for AT+CIND */
+#define BTA_AG_BINP_RES 4 /* Send phone number for voice tag for AT+BINP */
+#define BTA_AG_IND_RES 5 /* Update an indicator value */
+#define BTA_AG_BVRA_RES 6 /* Update voice recognition state */
+#define BTA_AG_CNUM_RES 7 /* Send subscriber number response for AT+CNUM */
+#define BTA_AG_BTRH_RES 8 /* Send CCAP incoming call hold */
+#define BTA_AG_CLCC_RES 9 /* Query list of calls */
+#define BTA_AG_COPS_RES 10 /* Read network operator */
+#define BTA_AG_IN_CALL_RES 11 /* Indicate incoming phone call */
+#define BTA_AG_IN_CALL_CONN_RES 12 /* Incoming phone call connected */
+#define BTA_AG_CALL_WAIT_RES 13 /* Call waiting notification */
+#define BTA_AG_OUT_CALL_ORIG_RES 14 /* Outgoing phone call origination */
+#define BTA_AG_OUT_CALL_ALERT_RES 15 /* Outgoing phone call alerting remote party */
+#define BTA_AG_OUT_CALL_CONN_RES 16 /* Outgoing phone call connected */
+#define BTA_AG_CALL_CANCEL_RES 17 /* Incoming/outgoing 3-way canceled before connected */
+#define BTA_AG_END_CALL_RES 18 /* End call */
+#define BTA_AG_IN_CALL_HELD_RES 19 /* Incoming call held */
+#define BTA_AG_UNAT_RES 20 /* Response to unknown AT command event */
+
+typedef UINT8 tBTA_AG_RES;
+
+/* HFP peer features */
+#define BTA_AG_PEER_FEAT_ECNR 0x0001 /* Echo cancellation and/or noise reduction */
+#define BTA_AG_PEER_FEAT_3WAY 0x0002 /* Call waiting and three-way calling */
+#define BTA_AG_PEER_FEAT_CLI 0x0004 /* Caller ID presentation capability */
+#define BTA_AG_PEER_FEAT_VREC 0x0008 /* Voice recognition activation */
+#define BTA_AG_PEER_FEAT_VOL 0x0010 /* Remote volume control */
+#define BTA_AG_PEER_FEAT_ECS 0x0020 /* Enhanced Call Status */
+#define BTA_AG_PEER_FEAT_ECC 0x0040 /* Enhanced Call Control */
+#define BTA_AG_PEER_FEAT_CODEC 0x0080 /* Codec Negotiation */
+#define BTA_AG_PEER_FEAT_VOIP 0x0100 /* VoIP call */
+
+typedef UINT16 tBTA_AG_PEER_FEAT;
+
+/* HFP peer supported codec masks */
+#define BTA_AG_CODEC_NONE BTM_SCO_CODEC_NONE
+#define BTA_AG_CODEC_CVSD BTM_SCO_CODEC_CVSD /* CVSD */
+#define BTA_AG_CODEC_MSBC BTM_SCO_CODEC_MSBC /* mSBC */
+typedef UINT16 tBTA_AG_PEER_CODEC;
+
+/* HFP errcode - Set when BTA_AG_OK_ERROR is returned in 'ok_flag' */
+#define BTA_AG_ERR_PHONE_FAILURE 0 /* Phone Failure */
+#define BTA_AG_ERR_NO_CONN_PHONE 1 /* No connection to phone */
+#define BTA_AG_ERR_OP_NOT_ALLOWED 3 /* Operation not allowed */
+#define BTA_AG_ERR_OP_NOT_SUPPORTED 4 /* Operation not supported */
+#define BTA_AG_ERR_PHSIM_PIN_REQ 5 /* PH-SIM PIN required */
+#define BTA_AG_ERR_SIM_NOT_INSERTED 10 /* SIM not inserted */
+#define BTA_AG_ERR_SIM_PIN_REQ 11 /* SIM PIN required */
+#define BTA_AG_ERR_SIM_PUK_REQ 12 /* SIM PUK required */
+#define BTA_AG_ERR_SIM_FAILURE 13 /* SIM failure */
+#define BTA_AG_ERR_SIM_BUSY 14 /* SIM busy */
+#define BTA_AG_ERR_INCORRECT_PWD 16 /* Incorrect password */
+#define BTA_AG_ERR_SIM_PIN2_REQ 17 /* SIM PIN2 required */
+#define BTA_AG_ERR_SIM_PUK2_REQ 18 /* SIM PUK2 required */
+#define BTA_AG_ERR_MEMORY_FULL 20 /* Memory full */
+#define BTA_AG_ERR_INVALID_INDEX 21 /* Invalid index */
+#define BTA_AG_ERR_MEMORY_FAILURE 23 /* Memory failure */
+#define BTA_AG_ERR_TEXT_TOO_LONG 24 /* Text string too long */
+#define BTA_AG_ERR_INV_CHAR_IN_TSTR 25 /* Invalid characters in text string */
+#define BTA_AG_ERR_DSTR_TOO_LONG 26 /* Dial string too long */
+#define BTA_AG_ERR_INV_CHAR_IN_DSTR 27 /* Invalid characters in dial string */
+#define BTA_AG_ERR_NO_NETWORK_SERV 30 /* No network service */
+#define BTA_AG_ERR_NETWORK_TIME_OUT 31 /* Network timeout */
+#define BTA_AG_ERR_NO_NET_EMG_ONLY 32 /* Network not allowed - emergency service only */
+#define BTA_AG_ERR_VOIP_CS_CALLS 33 /* AG cannot create simultaneous VoIP and CS calls */
+#define BTA_AG_ERR_NOT_FOR_VOIP 34 /* Not supported on this call type(VoIP) */
+#define BTA_AG_ERR_SIP_RESP_CODE 35 /* SIP 3 digit response code */
+
+#if 0 /* Not Used in Bluetooth HFP 1.5 Specification */
+#define BTA_AG_ERR_PHADAP_LNK_RES 2 /* Phone-adapter link reserved */
+#define BTA_AG_ERR_PHFSIM_PIN_REQ 6 /* PH-FSIM PIN required */
+#define BTA_AG_ERR_PHFSIM_PUK_REQ 7 /* PH-FSIM PUK required */
+#define BTA_AG_ERR_SIM_WRONG 15 /* SIM wrong */
+#define BTA_AG_ERR_NOT_FOUND 22 /* Not found */
+#define BTA_AG_ERR_NETWORK_TIMEOUT 31 /* Network timeout */
+#define BTA_AG_ERR_NET_PIN_REQ 40 /* Network personalization PIN required */
+#define BTA_AG_ERR_NET_PUK_REQ 41 /* Network personalization PUK required */
+#define BTA_AG_ERR_SUBSET_PIN_REQ 42 /* Network subset personalization PIN required */
+#define BTA_AG_ERR_SUBSET_PUK_REQ 43 /* Network subset personalization PUK required */
+#define BTA_AG_ERR_SERVPRO_PIN_REQ 44 /* Service provider personalization PIN required */
+#define BTA_AG_ERR_SERVPRO_PUK_REQ 45 /* Service provider personalization PUK required */
+#define BTA_AG_ERR_CORP_PIN_REQ 46 /* Corporate personalization PIN required */
+#define BTA_AG_ERR_CORP_PUK_REQ 47 /* Corporate personalization PUK required */
+#define BTA_AG_ERR_UNKNOWN 100 /* Unknown error */
+/* GPRS-related errors */
+#define BTA_AG_ERR_ILL_MS 103 /* Illegal MS (#3) */
+#define BTA_AG_ERR_ILL_ME 106 /* Illegal ME (#6) */
+#define BTA_AG_ERR_GPRS_NOT_ALLOWED 107 /* GPRS services not allowed (#7) */
+#define BTA_AG_ERR_PLMN_NOT_ALLOWED 111 /* PLMN services not allowed (#11) */
+#define BTA_AG_ERR_LOC_NOT_ALLOWED 112 /* Location area not allowed (#12) */
+#define BTA_AG_ERR_ROAM_NOT_ALLOWED 113 /* Roaming not allowed in this location area (#13) */
+/* Errors related to a failure to Activate a Context */
+#define BTA_AG_ERR_OPT_NOT_SUPP 132 /* Service option not supported (#32) */
+#define BTA_AG_ERR_OPT_NOT_SUBSCR 133 /* Requested service option not subscribed (#33) */
+#define BTA_AG_ERR_OPT_OUT_OF_ORDER 134 /* Service option temporarily out of order (#34) */
+#define BTA_AG_ERR_PDP_AUTH_FAILURE 149 /* PDP authentication failure */
+/* Other GPRS errors */
+#define BTA_AG_ERR_INV_MOBILE_CLASS 150 /* Invalid mobile class */
+#define BTA_AG_ERR_UNSPEC_GPRS_ERR 148 /* Unspecified GPRS error */
+#endif /* Unused error codes */
+
+
+/* HFP result data 'ok_flag' */
+#define BTA_AG_OK_CONTINUE 0 /* Send out response (more responses coming) */
+#define BTA_AG_OK_DONE 1 /* Send out response followed by OK (finished) */
+#define BTA_AG_OK_ERROR 2 /* Error response */
+
+/* BTRH values */
+#define BTA_AG_BTRH_SET_HOLD 0 /* Put incoming call on hold */
+#define BTA_AG_BTRH_SET_ACC 1 /* Accept incoming call on hold */
+#define BTA_AG_BTRH_SET_REJ 2 /* Reject incoming call on hold */
+#define BTA_AG_BTRH_READ 3 /* Read the current value */
+#define BTA_AG_BTRH_NO_RESP 4 /* Not in RH States (reply to read) */
+
+/* ASCII character string of arguments to the AT command or result */
+#ifndef BTA_AG_AT_MAX_LEN
+#define BTA_AG_AT_MAX_LEN 256
+#endif
+
+/* data associated with BTA_AG_IND_RES */
+typedef struct
+{
+ UINT16 id;
+ UINT16 value;
+} tBTA_AG_IND;
+
+/* data type for BTA_AgResult() */
+typedef struct
+{
+ char str[BTA_AG_AT_MAX_LEN+1];
+ tBTA_AG_IND ind;
+ UINT16 num;
+ UINT16 audio_handle;
+ UINT16 errcode; /* Valid only if 'ok_flag' is set to BTA_AG_OK_ERROR */
+ UINT8 ok_flag; /* Indicates if response is finished, and if error occurred */
+ BOOLEAN state;
+} tBTA_AG_RES_DATA;
+
+/* AG callback events */
+#define BTA_AG_ENABLE_EVT 0 /* AG enabled */
+#define BTA_AG_REGISTER_EVT 1 /* AG registered */
+#define BTA_AG_OPEN_EVT 2 /* AG connection open */
+#define BTA_AG_CLOSE_EVT 3 /* AG connection closed */
+#define BTA_AG_CONN_EVT 4 /* Service level connection opened */
+#define BTA_AG_AUDIO_OPEN_EVT 5 /* Audio connection open */
+#define BTA_AG_AUDIO_CLOSE_EVT 6 /* Audio connection closed */
+#define BTA_AG_SPK_EVT 7 /* Speaker volume changed */
+#define BTA_AG_MIC_EVT 8 /* Microphone volume changed */
+#define BTA_AG_AT_CKPD_EVT 9 /* CKPD from the HS */
+#define BTA_AG_DISABLE_EVT 30 /* AG disabled */
+
+/* Values below are for HFP only */
+#define BTA_AG_AT_A_EVT 10 /* Answer a call */
+#define BTA_AG_AT_D_EVT 11 /* Place a call using number or memory dial */
+#define BTA_AG_AT_CHLD_EVT 12 /* Call hold */
+#define BTA_AG_AT_CHUP_EVT 13 /* Hang up a call */
+#define BTA_AG_AT_CIND_EVT 14 /* Read indicator settings */
+#define BTA_AG_AT_VTS_EVT 15 /* Transmit DTMF tone */
+#define BTA_AG_AT_BINP_EVT 16 /* Retrieve number from voice tag */
+#define BTA_AG_AT_BLDN_EVT 17 /* Place call to last dialed number */
+#define BTA_AG_AT_BVRA_EVT 18 /* Enable/disable voice recognition */
+#define BTA_AG_AT_NREC_EVT 19 /* Disable echo canceling */
+#define BTA_AG_AT_CNUM_EVT 20 /* Retrieve subscriber number */
+#define BTA_AG_AT_BTRH_EVT 21 /* CCAP-style incoming call hold */
+#define BTA_AG_AT_CLCC_EVT 22 /* Query list of current calls */
+#define BTA_AG_AT_COPS_EVT 23 /* Query list of current calls */
+#define BTA_AG_AT_UNAT_EVT 24 /* Unknown AT command */
+#define BTA_AG_AT_CBC_EVT 25 /* Battery Level report from HF */
+#define BTA_AG_AT_BAC_EVT 26 /* Codec select */
+#define BTA_AG_AT_BCS_EVT 27 /* Codec select */
+
+typedef UINT8 tBTA_AG_EVT;
+
+/* data associated with most non-AT events */
+typedef struct
+{
+ UINT16 handle;
+ UINT8 app_id;
+} tBTA_AG_HDR;
+
+/* data associated with BTA_AG_REGISTER_EVT */
+typedef struct
+{
+ tBTA_AG_HDR hdr;
+ tBTA_AG_STATUS status;
+} tBTA_AG_REGISTER;
+
+/* data associated with BTA_AG_OPEN_EVT */
+typedef struct
+{
+ tBTA_AG_HDR hdr;
+ BD_ADDR bd_addr;
+ tBTA_SERVICE_ID service_id;
+ tBTA_AG_STATUS status;
+} tBTA_AG_OPEN;
+
+/* data associated with BTA_AG_CONN_EVT */
+typedef struct
+{
+ tBTA_AG_HDR hdr;
+ tBTA_AG_PEER_FEAT peer_feat;
+ tBTA_AG_PEER_CODEC peer_codec;
+} tBTA_AG_CONN;
+
+/* data associated with AT command event */
+typedef struct
+{
+ tBTA_AG_HDR hdr;
+ char str[BTA_AG_AT_MAX_LEN+1];
+ UINT16 num;
+ UINT8 idx; /* call number used by CLCC and CHLD */
+} tBTA_AG_VAL;
+
+/* union of data associated with AG callback */
+typedef union
+{
+ tBTA_AG_HDR hdr;
+ tBTA_AG_REGISTER reg;
+ tBTA_AG_OPEN open;
+ tBTA_AG_CONN conn;
+ tBTA_AG_VAL val;
+} tBTA_AG;
+
+/* AG callback */
+typedef void (tBTA_AG_CBACK)(tBTA_AG_EVT event, tBTA_AG *p_data);
+
+/* indicator constants HFP 1.1 and later */
+#define BTA_AG_IND_CALL 1 /* position of call indicator */
+#define BTA_AG_IND_CALLSETUP 2 /* position of callsetup indicator */
+#define BTA_AG_IND_SERVICE 3 /* position of service indicator */
+
+/* indicator constants HFP 1.5 and later */
+#define BTA_AG_IND_SIGNAL 4 /* position of signal strength indicator */
+#define BTA_AG_IND_ROAM 5 /* position of roaming indicator */
+#define BTA_AG_IND_BATTCHG 6 /* position of battery charge indicator */
+#define BTA_AG_IND_CALLHELD 7 /* position of callheld indicator */
+#define BTA_AG_IND_BEARER 8 /* position of bearer indicator */
+
+/* call indicator values */
+#define BTA_AG_CALL_INACTIVE 0 /* Phone call inactive */
+#define BTA_AG_CALL_ACTIVE 1 /* Phone call active */
+
+/* callsetup indicator values */
+#define BTA_AG_CALLSETUP_NONE 0 /* Not currently in call set up */
+#define BTA_AG_CALLSETUP_INCOMING 1 /* Incoming call process ongoing */
+#define BTA_AG_CALLSETUP_OUTGOING 2 /* Outgoing call set up is ongoing */
+#define BTA_AG_CALLSETUP_ALERTING 3 /* Remote party being alerted in an outgoing call */
+
+/* service indicator values */
+#define BTA_AG_SERVICE_NONE 0 /* Neither CS nor VoIP service is available */
+#define BTA_AG_SERVICE_CS 1 /* Only CS service is available */
+#define BTA_AG_SERVICE_VOIP 2 /* Only VoIP service is available */
+#define BTA_AG_SERVICE_CS_VOIP 3 /* Both CS and VoIP services available */
+
+/* callheld indicator values */
+#define BTA_AG_CALLHELD_INACTIVE 0 /* No held calls */
+#define BTA_AG_CALLHELD_ACTIVE 1 /* Call held and call active */
+#define BTA_AG_CALLHELD_NOACTIVE 2 /* Call held and no call active */
+
+/* signal strength indicator values */
+#define BTA_AG_ROAMING_INACTIVE 0 /* Phone call inactive */
+#define BTA_AG_ROAMING_ACTIVE 1 /* Phone call active */
+
+/* bearer indicator values */
+#define BTA_AG_BEARER_WLAN 0 /* WLAN */
+#define BTA_AG_BEARER_BLUETOOTH 1 /* Bluetooth */
+#define BTA_AG_BEARER_WIRED 2 /* Wired */
+#define BTA_AG_BEARER_2G3G 3 /* 2G 3G */
+#define BTA_AG_BEARER_WIMAX 4 /* WIMAX */
+#define BTA_AG_BEARER_RES1 5 /* Reserved */
+#define BTA_AG_BEARER_RES2 6 /* Reserved */
+#define BTA_AG_BEARER_RES3 7 /* Reserved */
+
+/* AG configuration structure */
+typedef struct
+{
+ char *cind_info;
+ INT32 conn_tout;
+ UINT16 sco_pkt_types;
+ char *chld_val_ecc;
+ char *chld_val;
+} tBTA_AG_CFG;
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*****************************************************************************
+** External Function Declarations
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function BTA_AgEnable
+**
+** Description Enable the audio gateway service. When the enable
+** operation is complete the callback function will be
+** called with a BTA_AG_ENABLE_EVT. This function must
+** be called before other function in the AG API are
+** called.
+**
+** Returns BTA_SUCCESS if OK, BTA_FAILURE otherwise.
+**
+*******************************************************************************/
+BTA_API tBTA_STATUS BTA_AgEnable(tBTA_AG_PARSE_MODE parse_mode, tBTA_AG_CBACK *p_cback);
+
+/*******************************************************************************
+**
+** Function BTA_AgDisable
+**
+** Description Disable the audio gateway service
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API void BTA_AgDisable(void);
+
+/*******************************************************************************
+**
+** Function BTA_AgRegister
+**
+** Description Register an Audio Gateway service.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API void BTA_AgRegister(tBTA_SERVICE_MASK services, tBTA_SEC sec_mask,
+ tBTA_AG_FEAT features, char *p_service_names[], UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function BTA_AgDeregister
+**
+** Description Deregister an audio gateway service.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API void BTA_AgDeregister(UINT16 handle);
+
+/*******************************************************************************
+**
+** Function BTA_AgOpen
+**
+** Description Opens a connection to a headset or hands-free device.
+** When connection is open callback function is called
+** with a BTA_AG_OPEN_EVT. Only the data connection is
+** opened. The audio connection is not opened.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API void BTA_AgOpen(UINT16 handle, BD_ADDR bd_addr, tBTA_SEC sec_mask, tBTA_SERVICE_MASK services);
+
+/*******************************************************************************
+**
+** Function BTA_AgClose
+**
+** Description Close the current connection to a headset or a handsfree
+** Any current audio connection will also be closed
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API void BTA_AgClose(UINT16 handle);
+
+/*******************************************************************************
+**
+** Function BTA_AgAudioOpen
+**
+** Description Opens an audio connection to the currently connected
+** headset or hnadsfree
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API void BTA_AgAudioOpen(UINT16 handle);
+
+/*******************************************************************************
+**
+** Function BTA_AgAudioClose
+**
+** Description Close the currently active audio connection to a headset
+** or hnadsfree. The data connection remains open
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API void BTA_AgAudioClose(UINT16 handle);
+
+/*******************************************************************************
+**
+** Function BTA_AgResult
+**
+** Description Send an AT result code to a headset or hands-free device.
+** This function is only used when the AG parse mode is set
+** to BTA_AG_PARSE.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API void BTA_AgResult(UINT16 handle, tBTA_AG_RES result, tBTA_AG_RES_DATA *p_data);
+
+/*******************************************************************************
+**
+** Function BTA_AgSetCodec
+**
+** Description Specify the codec type to be used for the subsequent
+** audio connection.
+**
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API void BTA_AgSetCodec(UINT16 handle, tBTA_AG_PEER_CODEC codec);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_AG_API_H */
+
+
diff --git a/bta/include/bta_ag_ci.h b/bta/include/bta_ag_ci.h
new file mode 100644
index 0000000..5fc5a61
--- /dev/null
+++ b/bta/include/bta_ag_ci.h
@@ -0,0 +1,70 @@
+/*****************************************************************************
+**
+** Name: bta_ag_ci.h
+**
+** Description: This is the interface file for audio gateway call-in
+** functions.
+**
+** Copyright (c) 2003, Widcomm Inc., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_AG_CI_H
+#define BTA_AG_CI_H
+
+#include "bta_ag_api.h"
+
+/*****************************************************************************
+** Function Declarations
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*******************************************************************************
+**
+** Function bta_ag_ci_rx_write
+**
+** Description This function is called to send data to the AG when the AG
+** is configured for AT command pass-through. The function
+** copies data to an event buffer and sends it.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_ag_ci_rx_write(UINT16 handle, char *p_data, UINT16 len);
+
+/******************************************************************************
+**
+** Function bta_ag_ci_slc_ready
+**
+** Description This function is called to notify AG that SLC is up at
+** the application. This funcion is only used when the app
+** is running in pass-through mode.
+**
+** Returns void
+**
+******************************************************************************/
+BTA_API extern void bta_ag_ci_slc_ready(UINT16 handle);
+
+// btla-specific ++
+/******************************************************************************
+**
+** Function bta_ag_ci_wbs_command
+**
+** Description This function is called to notify AG that a WBS command is
+** received
+**
+** Returns void
+**
+******************************************************************************/
+BTA_API extern void bta_ag_ci_wbs_command (UINT16 handle, char *p_data, UINT16 len);
+// btla-specific --
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_AG_CI_H */
+
diff --git a/bta/include/bta_ag_co.h b/bta/include/bta_ag_co.h
new file mode 100644
index 0000000..81927aa
--- /dev/null
+++ b/bta/include/bta_ag_co.h
@@ -0,0 +1,100 @@
+/*****************************************************************************
+**
+** Name: bta_ag_co.h
+**
+** Description: This is the interface file for audio gateway call-out
+** functions.
+**
+** Copyright (c) 2003-2006, Broadcom Corp., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_AG_CO_H
+#define BTA_AG_CO_H
+
+#include "bta_ag_api.h"
+
+/* Definitions for audio state callout function "state" parameter */
+#define BTA_AG_CO_AUD_STATE_OFF 0
+#define BTA_AG_CO_AUD_STATE_OFF_XFER 1 /* Closed pending transfer of audio */
+#define BTA_AG_CO_AUD_STATE_ON 2
+#define BTA_AG_CO_AUD_STATE_SETUP 3
+
+/*******************************************************************************
+**
+** Function bta_ag_co_init
+**
+** Description This callout function is executed by AG when it is
+** started by calling BTA_AgEnable(). This function can be
+** used by the phone to initialize audio paths or for other
+** initialization purposes.
+**
+**
+** Returns Void.
+**
+*******************************************************************************/
+BTA_API extern void bta_ag_co_init(void);
+
+/*******************************************************************************
+**
+** Function bta_ag_co_audio_state
+**
+** Description This function is called by the AG before the audio connection
+** is brought up, after it comes up, and after it goes down.
+**
+** Parameters handle - handle of the AG instance
+** state - Audio state
+** BTA_AG_CO_AUD_STATE_OFF - Audio has been turned off
+** BTA_AG_CO_AUD_STATE_OFF_XFER - Audio is closed pending transfer
+** BTA_AG_CO_AUD_STATE_ON - Audio has been turned on
+** BTA_AG_CO_AUD_STATE_SETUP - Audio is about to be turned on
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_ag_co_audio_state(UINT16 handle, UINT8 app_id, UINT8 state);
+
+/*******************************************************************************
+**
+** Function bta_ag_co_data_open
+**
+** Description This function is executed by AG when a service level connection
+** is opened. The phone can use this function to set
+** up data paths or perform any required initialization or
+** set up particular to the connected service.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_ag_co_data_open(UINT16 handle, tBTA_SERVICE_ID service);
+
+/*******************************************************************************
+**
+** Function bta_ag_co_data_close
+**
+** Description This function is called by AG when a service level
+** connection is closed
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_ag_co_data_close(UINT16 handle);
+
+/*******************************************************************************
+**
+** Function bta_ag_co_tx_write
+**
+** Description This function is called by the AG to send data to the
+** phone when the AG is configured for AT command pass-through.
+** The implementation of this function must copy the data to
+** the phone’s memory.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_ag_co_tx_write(UINT16 handle, UINT8 *p_data, UINT16 len);
+
+#endif /* BTA_AG_CO_H */
+
diff --git a/bta/include/bta_api.h b/bta/include/bta_api.h
new file mode 100644
index 0000000..8d7b71b
--- /dev/null
+++ b/bta/include/bta_api.h
@@ -0,0 +1,1712 @@
+/*****************************************************************************
+**
+** Name: bta_api.h
+**
+** Description: This is the public interface file for BTA, Widcomm's
+** Bluetooth application layer for mobile phones.
+**
+** Copyright (c) 2003-2010, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_API_H
+#define BTA_API_H
+
+#include "data_types.h"
+#include "bt_target.h"
+#include "bt_types.h"
+#include "btm_api.h"
+#include "uipc_msg.h"
+
+#if BLE_INCLUDED == TRUE
+#include "btm_ble_api.h"
+#endif
+
+/*****************************************************************************
+** Constants and data types
+*****************************************************************************/
+
+/* Status Return Value */
+#define BTA_SUCCESS 0 /* Successful operation. */
+#define BTA_FAILURE 1 /* Generic failure. */
+#define BTA_PENDING 2 /* API cannot be completed right now */
+#define BTA_BUSY 3
+#define BTA_NO_RESOURCES 4
+#define BTA_WRONG_MODE 5
+
+typedef UINT8 tBTA_STATUS;
+
+/*
+ * Service ID
+ *
+ * NOTES: When you add a new Service ID for BTA AND require to change the value of BTA_MAX_SERVICE_ID,
+ * make sure that the correct security ID of the new service from Security service definitions (btm_api.h)
+ * should be added to bta_service_id_to_btm_srv_id_lkup_tbl table in bta_dm_act.c.
+ */
+
+#define BTA_RES_SERVICE_ID 0 /* Reserved */
+#define BTA_SPP_SERVICE_ID 1 /* Serial port profile. */
+#define BTA_DUN_SERVICE_ID 2 /* Dial-up networking profile. */
+#define BTA_FAX_SERVICE_ID 3 /* Fax profile. */
+#define BTA_LAP_SERVICE_ID 4 /* LAN access profile. */
+#define BTA_HSP_SERVICE_ID 5 /* Headset profile. */
+#define BTA_HFP_SERVICE_ID 6 /* Hands-free profile. */
+#define BTA_OPP_SERVICE_ID 7 /* Object push */
+#define BTA_FTP_SERVICE_ID 8 /* File transfer */
+#define BTA_CTP_SERVICE_ID 9 /* Cordless Terminal */
+#define BTA_ICP_SERVICE_ID 10 /* Intercom Terminal */
+#define BTA_SYNC_SERVICE_ID 11 /* Synchronization */
+#define BTA_BPP_SERVICE_ID 12 /* Basic printing profile */
+#define BTA_BIP_SERVICE_ID 13 /* Basic Imaging profile */
+#define BTA_PANU_SERVICE_ID 14 /* PAN User */
+#define BTA_NAP_SERVICE_ID 15 /* PAN Network access point */
+#define BTA_GN_SERVICE_ID 16 /* PAN Group Ad-hoc networks */
+#define BTA_SAP_SERVICE_ID 17 /* SIM Access profile */
+#define BTA_A2DP_SERVICE_ID 18 /* Advanced audio distribution */
+#define BTA_AVRCP_SERVICE_ID 19 /* A/V remote control */
+#define BTA_HID_SERVICE_ID 20 /* HID */
+#define BTA_VDP_SERVICE_ID 21 /* Video distribution */
+#define BTA_PBAP_SERVICE_ID 22 /* PhoneBook Access Server*/
+#define BTA_HSP_HS_SERVICE_ID 23 /* HFP HS role */
+#define BTA_HFP_HS_SERVICE_ID 24 /* HSP HS role */
+#define BTA_MAP_SERVICE_ID 25 /* Message Access Profile */
+#define BTA_MN_SERVICE_ID 26 /* Message Notification Service */
+#define BTA_HDP_SERVICE_ID 27 /* Health Device Profile */
+#define BTA_PCE_SERVICE_ID 28 /* PhoneBook Access Client*/
+
+#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE
+/* BLE profile service ID */
+#define BTA_BLE_SERVICE_ID 29 /* GATT profile */
+
+// btla-specific ++
+#define BTA_USER_SERVICE_ID 30 /* User requested UUID */
+
+#define BTA_MAX_SERVICE_ID 31
+// btla-specific --
+#else
+#define BTA_USER_SERVICE_ID 29 /* User requested UUID */
+#define BTA_MAX_SERVICE_ID 30
+#endif
+/* service IDs (BTM_SEC_SERVICE_FIRST_EMPTY + 1) to (BTM_SEC_MAX_SERVICES - 1)
+ * are used by BTA JV */
+#define BTA_FIRST_JV_SERVICE_ID (BTM_SEC_SERVICE_FIRST_EMPTY + 1)
+#define BTA_LAST_JV_SERVICE_ID (BTM_SEC_MAX_SERVICES - 1)
+
+typedef UINT8 tBTA_SERVICE_ID;
+
+/* Service ID Mask */
+#define BTA_RES_SERVICE_MASK 0x00000001 /* Reserved */
+#define BTA_SPP_SERVICE_MASK 0x00000002 /* Serial port profile. */
+#define BTA_DUN_SERVICE_MASK 0x00000004 /* Dial-up networking profile. */
+#define BTA_FAX_SERVICE_MASK 0x00000008 /* Fax profile. */
+#define BTA_LAP_SERVICE_MASK 0x00000010 /* LAN access profile. */
+#define BTA_HSP_SERVICE_MASK 0x00000020 /* HSP AG role. */
+#define BTA_HFP_SERVICE_MASK 0x00000040 /* HFP AG role */
+#define BTA_OPP_SERVICE_MASK 0x00000080 /* Object push */
+#define BTA_FTP_SERVICE_MASK 0x00000100 /* File transfer */
+#define BTA_CTP_SERVICE_MASK 0x00000200 /* Cordless Terminal */
+#define BTA_ICP_SERVICE_MASK 0x00000400 /* Intercom Terminal */
+#define BTA_SYNC_SERVICE_MASK 0x00000800 /* Synchronization */
+#define BTA_BPP_SERVICE_MASK 0x00001000 /* Print server */
+#define BTA_BIP_SERVICE_MASK 0x00002000 /* Basic Imaging */
+#define BTA_PANU_SERVICE_MASK 0x00004000 /* PAN User */
+#define BTA_NAP_SERVICE_MASK 0x00008000 /* PAN Network access point */
+#define BTA_GN_SERVICE_MASK 0x00010000 /* PAN Group Ad-hoc networks */
+#define BTA_SAP_SERVICE_MASK 0x00020000 /* PAN Group Ad-hoc networks */
+#define BTA_A2DP_SERVICE_MASK 0x00040000 /* Advanced audio distribution */
+#define BTA_AVRCP_SERVICE_MASK 0x00080000 /* A/V remote control */
+#define BTA_HID_SERVICE_MASK 0x00100000 /* HID */
+#define BTA_VDP_SERVICE_MASK 0x00200000 /* Video distribution */
+#define BTA_PBAP_SERVICE_MASK 0x00400000 /* Phone Book Server */
+#define BTA_HSP_HS_SERVICE_MASK 0x00800000 /* HFP HS role */
+#define BTA_HFP_HS_SERVICE_MASK 0x01000000 /* HSP HS role */
+#define BTA_MAS_SERVICE_MASK 0x02000000 /* Message Access Profile */
+#define BTA_MN_SERVICE_MASK 0x04000000 /* Message Notification Profile */
+#define BTA_HL_SERVICE_MASK 0x08000000 /* Health Device Profile */
+#define BTA_PCE_SERVICE_MASK 0x10000000 /* Phone Book Client */
+
+#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE
+#define BTA_BLE_SERVICE_MASK 0x20000000 /* GATT based service */
+// btla-specific ++
+#define BTA_USER_SERVICE_MASK 0x40000000 /* Message Notification Profile */
+// btla-specific --
+#else
+// btla-specific ++
+#define BTA_USER_SERVICE_MASK 0x20000000 /* Message Notification Profile */
+// btla-specific --
+#endif
+
+#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE
+#define BTA_ALL_SERVICE_MASK 0x3FFFFFFF /* All services supported by BTA. */
+#else
+#define BTA_ALL_SERVICE_MASK 0x1FFFFFFF /* All services supported by BTA. */
+#endif
+
+typedef UINT32 tBTA_SERVICE_MASK;
+
+/* extended service mask, including mask with one or more GATT UUID */
+typedef struct
+{
+ tBTA_SERVICE_MASK srvc_mask;
+ UINT8 num_uuid;
+ tBT_UUID *p_uuid;
+}tBTA_SERVICE_MASK_EXT;
+
+/* Security Setting Mask */
+#define BTA_SEC_NONE BTM_SEC_NONE /* No security. */
+#define BTA_SEC_AUTHORIZE (BTM_SEC_IN_AUTHORIZE ) /* Authorization required (only needed for out going connection )*/
+#define BTA_SEC_AUTHENTICATE (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_OUT_AUTHENTICATE) /* Authentication required. */
+#define BTA_SEC_ENCRYPT (BTM_SEC_IN_ENCRYPT | BTM_SEC_OUT_ENCRYPT) /* Encryption required. */
+
+typedef UINT8 tBTA_SEC;
+
+/* Ignore for Discoverable, Connectable, Pairable and Connectable Paired only device modes */
+
+#define BTA_DM_IGNORE 0xFF
+
+
+/* Discoverable Modes */
+#define BTA_DM_NON_DISC BTM_NON_DISCOVERABLE /* Device is not discoverable. */
+#define BTA_DM_GENERAL_DISC BTM_GENERAL_DISCOVERABLE /* General discoverable. */
+#define BTA_DM_LIMITED_DISC BTM_LIMITED_DISCOVERABLE /* Limited discoverable. */
+
+// btla-specific ++
+typedef UINT16 tBTA_DM_DISC;
+// btla-specific --
+
+/* Connectable Modes */
+#define BTA_DM_NON_CONN BTM_NON_CONNECTABLE /* Device is not connectable. */
+#define BTA_DM_CONN BTM_CONNECTABLE /* Device is connectable. */
+
+// btla-specific ++
+typedef UINT16 tBTA_DM_CONN;
+// btla-specific --
+
+/* Pairable Modes */
+#define BTA_DM_PAIRABLE 1
+#define BTA_DM_NON_PAIRABLE 0
+
+/* Connectable Paired Only Mode */
+#define BTA_DM_CONN_ALL 0
+#define BTA_DM_CONN_PAIRED 1
+
+/* Inquiry Modes */
+#define BTA_DM_GENERAL_INQUIRY BTM_GENERAL_INQUIRY /* Perform general inquiry. */
+#define BTA_DM_LIMITED_INQUIRY BTM_LIMITED_INQUIRY /* Perform limited inquiry. */
+
+#if ((defined BLE_INCLUDED) && (BLE_INCLUDED == TRUE))
+#define BTA_BLE_INQUIRY_NONE BTM_BLE_INQUIRY_NONE
+#define BTA_BLE_GENERAL_INQUIRY BTM_BLE_GENERAL_INQUIRY /* Perform LE general inquiry. */
+#define BTA_BLE_LIMITED_INQUIRY BTM_BLE_LIMITED_INQUIRY /* Perform LE limited inquiry. */
+#endif
+typedef UINT8 tBTA_DM_INQ_MODE;
+
+/* Inquiry Filter Type */
+#define BTA_DM_INQ_CLR BTM_CLR_INQUIRY_FILTER /* Clear inquiry filter. */
+#define BTA_DM_INQ_DEV_CLASS BTM_FILTER_COND_DEVICE_CLASS /* Filter on device class. */
+#define BTA_DM_INQ_BD_ADDR BTM_FILTER_COND_BD_ADDR /* Filter on a specific BD address. */
+
+typedef UINT8 tBTA_DM_INQ_FILT;
+
+/* Authorize Response */
+#define BTA_DM_AUTH_PERM 0 /* Authorized for future connections to the service */
+#define BTA_DM_AUTH_TEMP 1 /* Authorized for current connection only */
+#define BTA_DM_NOT_AUTH 2 /* Not authorized for the service */
+
+typedef UINT8 tBTA_AUTH_RESP;
+
+/* M/S preferred roles */
+#define BTA_ANY_ROLE 0x00
+#define BTA_MASTER_ROLE_PREF 0x01
+#define BTA_MASTER_ROLE_ONLY 0x02
+
+typedef UINT8 tBTA_PREF_ROLES;
+
+enum
+{
+
+ BTA_DM_NO_SCATTERNET, /* Device doesn't support scatternet, it might
+ support "role switch during connection" for
+ an incoming connection, when it already has
+ another connection in master role */
+ BTA_DM_PARTIAL_SCATTERNET, /* Device supports partial scatternet. It can have
+ simulateous connection in Master and Slave roles
+ for short period of time */
+ BTA_DM_FULL_SCATTERNET /* Device can have simultaneous connection in master
+ and slave roles */
+
+};
+
+
+/* Inquiry filter device class condition */
+typedef struct
+{
+ DEV_CLASS dev_class; /* device class of interest */
+ DEV_CLASS dev_class_mask; /* mask to determine the bits of device class of interest */
+} tBTA_DM_COD_COND;
+
+
+/* Inquiry Filter Condition */
+typedef union
+{
+ BD_ADDR bd_addr; /* BD address of device to filter. */
+ tBTA_DM_COD_COND dev_class_cond; /* Device class filter condition */
+} tBTA_DM_INQ_COND;
+
+/* Inquiry Parameters */
+typedef struct
+{
+ tBTA_DM_INQ_MODE mode; /* Inquiry mode, limited or general. */
+ UINT8 duration; /* Inquiry duration in 1.28 sec units. */
+ UINT8 max_resps; /* Maximum inquiry responses. Set to zero for unlimited responses. */
+ BOOLEAN report_dup; /* report duplicated inquiry response with higher RSSI value */
+ tBTA_DM_INQ_FILT filter_type; /* Filter condition type. */
+ tBTA_DM_INQ_COND filter_cond; /* Filter condition data. */
+} tBTA_DM_INQ;
+
+typedef struct
+{
+ UINT8 bta_dm_eir_min_name_len; /* minimum length of local name when it is shortened */
+#if (BTA_EIR_CANNED_UUID_LIST == TRUE)
+ UINT8 bta_dm_eir_uuid16_len; /* length of 16-bit UUIDs */
+ UINT8 *bta_dm_eir_uuid16; /* 16-bit UUIDs */
+#else
+ UINT32 uuid_mask[BTM_EIR_SERVICE_ARRAY_SIZE]; /* mask of UUID list in EIR */
+#endif
+ INT8 *bta_dm_eir_inq_tx_power; /* Inquiry TX power */
+ UINT8 bta_dm_eir_flag_len; /* length of flags in bytes */
+ UINT8 *bta_dm_eir_flags; /* flags for EIR */
+ UINT8 bta_dm_eir_manufac_spec_len; /* length of manufacturer specific in bytes */
+ UINT8 *bta_dm_eir_manufac_spec; /* manufacturer specific */
+} tBTA_DM_EIR_CONF;
+
+#if BLE_INCLUDED == TRUE
+/* ADV data flag bit definition used for BTM_BLE_AD_TYPE_FLAG */
+#define BTA_BLE_LIMIT_DISC_FLAG BTM_BLE_LIMIT_DISC_FLAG
+#define BTA_BLE_GEN_DISC_FLAG BTM_BLE_GEN_DISC_FLAG
+#define BTA_BLE_BREDR_NOT_SPT BTM_BLE_BREDR_NOT_SPT
+#define BTA_BLE_NON_LIMIT_DISC_FLAG BTM_BLE_NON_LIMIT_DISC_FLAG
+#define BTA_BLE_ADV_FLAG_MASK BTM_BLE_ADV_FLAG_MASK
+#define BTA_BLE_LIMIT_DISC_MASK BTM_BLE_LIMIT_DISC_MASK
+
+#define BTA_BLE_AD_BIT_DEV_NAME BTM_BLE_AD_BIT_DEV_NAME
+#define BTA_BLE_AD_BIT_FLAGS BTM_BLE_AD_BIT_FLAGS
+#define BTA_BLE_AD_BIT_MANU BTM_BLE_AD_BIT_MANU
+#define BTA_BLE_AD_BIT_TX_PWR BTM_BLE_AD_BIT_TX_PWR
+#define BTA_BLE_AD_BIT_ATTR BTM_BLE_AD_BIT_ATTR
+#define BTA_BLE_AD_BIT_INT_RANGE BTM_BLE_AD_BIT_INT_RANGE
+#define BTA_BLE_AD_BIT_SERVICE BTM_BLE_AD_BIT_SERVICE
+#define BTA_BLE_AD_BIT_SERVICE_SOL BTM_BLE_AD_BIT_SERVICE_SOL
+#define BTA_BLE_AD_BIT_SERVICE_DATA BTM_BLE_AD_BIT_SERVICE_DATA
+#define BTA_BLE_AD_BIT_SIGN_DATA BTM_BLE_AD_BIT_SIGN_DATA
+typedef UINT16 tBTA_BLE_AD_MASK;
+
+/* slave preferred connection interval range */
+typedef struct
+{
+ UINT16 low;
+ UINT16 hi;
+
+}tBTA_BLE_INT_RANGE;
+
+/* Service tag supported in the device */
+typedef struct
+{
+ UINT8 num_service;
+ BOOLEAN list_cmpl;
+ UINT16 *p_uuid;
+}tBTA_BLE_SERVICE;
+
+/* attribute data */
+typedef struct
+{
+ UINT16 uuid;
+ UINT16 data_len;
+ UINT8 *p_data;
+}tBTA_BLE_ATTR;
+
+#define BTA_BLE_NUM_AD_ATTR_MAX BTM_BLE_NUM_AD_ATTR_MAX
+
+/* attribute list contained in adv data */
+typedef struct
+{
+ UINT8 num_attr;
+ tBTA_BLE_ATTR attr_list[BTA_BLE_NUM_AD_ATTR_MAX];
+}tBTA_BLE_ATTR_DATA;
+
+typedef struct
+{
+ UINT8 len;
+ UINT8 *p_val;
+}tBTA_BLE_MANU;
+
+typedef struct
+{
+ tBTA_BLE_MANU manu; /* manufactuer data */
+ tBTA_BLE_INT_RANGE int_range; /* slave prefered conn interval range */
+ tBTA_BLE_SERVICE services; /* services */
+ tBTA_BLE_ATTR_DATA attr; /* attribute data */
+ UINT8 flag;
+}tBTA_BLE_ADV_DATA;
+
+/* These are the fields returned in each device adv packet. It
+** is returned in the results callback if registered.
+*/
+typedef struct
+{
+ UINT8 conn_mode;
+ tBTA_BLE_AD_MASK ad_mask; /* mask of the valid adv data field */
+ UINT8 flag;
+ UINT8 tx_power_level;
+ UINT8 remote_name_len;
+ UINT8 *p_remote_name;
+ tBTA_BLE_ATTR_DATA attr_data;
+ tBTA_BLE_SERVICE service;
+} tBTA_BLE_INQ_DATA;
+#endif
+
+typedef INT8 tBTA_DM_RSSI_VALUE;
+typedef UINT8 tBTA_DM_LINK_QUALITY_VALUE;
+
+
+/* signal strength mask */
+#define BTA_SIG_STRENGTH_RSSI_MASK 1
+#define BTA_SIG_STRENGTH_LINK_QUALITY_MASK 2
+
+typedef UINT8 tBTA_SIG_STRENGTH_MASK;
+
+
+/* Security Callback Events */
+#define BTA_DM_ENABLE_EVT 0 /* Enable Event */
+#define BTA_DM_DISABLE_EVT 1 /* Disable Event */
+#define BTA_DM_PIN_REQ_EVT 2 /* PIN request. */
+#define BTA_DM_AUTH_CMPL_EVT 3 /* Authentication complete indication. */
+#define BTA_DM_AUTHORIZE_EVT 4 /* Authorization request. */
+#define BTA_DM_LINK_UP_EVT 5 /* Connection UP event */
+#define BTA_DM_LINK_DOWN_EVT 6 /* Connection DOWN event */
+#define BTA_DM_SIG_STRENGTH_EVT 7 /* Signal strength for bluetooth connection */
+#define BTA_DM_BUSY_LEVEL_EVT 8 /* System busy level */
+#define BTA_DM_BOND_CANCEL_CMPL_EVT 9 /* Bond cancel complete indication */
+#define BTA_DM_SP_CFM_REQ_EVT 10 /* Simple Pairing User Confirmation request. */
+#define BTA_DM_SP_KEY_NOTIF_EVT 11 /* Simple Pairing Passkey Notification */
+#define BTA_DM_SP_RMT_OOB_EVT 12 /* Simple Pairing Remote OOB Data request. */
+#define BTA_DM_SP_KEYPRESS_EVT 13 /* Key press notification event. */
+#define BTA_DM_ROLE_CHG_EVT 14 /* Role Change event. */
+#define BTA_DM_BLE_KEY_EVT 15 /* BLE SMP key event for peer device keys */
+#define BTA_DM_BLE_SEC_REQ_EVT 16 /* BLE SMP security request */
+#define BTA_DM_BLE_PASSKEY_NOTIF_EVT 17 /* SMP passkey notification event */
+#define BTA_DM_BLE_PASSKEY_REQ_EVT 18 /* SMP passkey request event */
+#define BTA_DM_BLE_OOB_REQ_EVT 19 /* SMP OOB request event */
+#define BTA_DM_BLE_LOCAL_IR_EVT 20 /* BLE local IR event */
+#define BTA_DM_BLE_LOCAL_ER_EVT 21 /* BLE local ER event */
+// btla-specific ++
+#define BTA_DM_BLE_AUTH_CMPL_EVT 22 /* BLE Auth complete */
+// btla-specific --
+
+typedef UINT8 tBTA_DM_SEC_EVT;
+
+/* Structure associated with BTA_DM_ENABLE_EVT */
+typedef struct
+{
+ BD_ADDR bd_addr; /* BD address of local device. */
+ tBTA_STATUS status;
+} tBTA_DM_ENABLE;
+
+/* Structure associated with BTA_DM_PIN_REQ_EVT */
+typedef struct
+{
+ BD_ADDR bd_addr; /* BD address peer device. */
+ BD_NAME bd_name; /* Name of peer device. */
+ DEV_CLASS dev_class; /* Class of Device */
+} tBTA_DM_PIN_REQ;
+
+/* BLE related definition */
+
+#define BTA_DM_AUTH_FAIL_BASE (HCI_ERR_MAX_ERR + 10)
+#define BTA_DM_AUTH_CONVERT_SMP_CODE(x) (BTA_DM_AUTH_FAIL_BASE + (x))
+#define BTA_DM_AUTH_SMP_PASSKEY_FAIL BTA_DM_AUTH_CONVERT_SMP_CODE (SMP_PASSKEY_ENTRY_FAIL)
+#define BTA_DM_AUTH_SMP_OOB_FAIL (BTA_DM_AUTH_FAIL_BASE + SMP_OOB_FAIL)
+#define BTA_DM_AUTH_SMP_PAIR_AUTH_FAIL (BTA_DM_AUTH_FAIL_BASE + SMP_PAIR_AUTH_FAIL)
+#define BTA_DM_AUTH_SMP_CONFIRM_VALUE_FAIL (BTA_DM_AUTH_FAIL_BASE + SMP_CONFIRM_VALUE_ERR)
+#define BTA_DM_AUTH_SMP_PAIR_NOT_SUPPORT (BTA_DM_AUTH_FAIL_BASE + SMP_PAIR_NOT_SUPPORT)
+#define BTA_DM_AUTH_SMP_ENC_KEY_SIZE (BTA_DM_AUTH_FAIL_BASE + SMP_ENC_KEY_SIZE)
+#define BTA_DM_AUTH_SMP_INVALID_CMD (BTA_DM_AUTH_FAIL_BASE + SMP_INVALID_CMD)
+#define BTA_DM_AUTH_SMP_UNKNOWN_ERR (BTA_DM_AUTH_FAIL_BASE + SMP_PAIR_FAIL_UNKNOWN)
+#define BTA_DM_AUTH_SMP_REPEATED_ATTEMPT (BTA_DM_AUTH_FAIL_BASE + SMP_REPEATED_ATTEMPTS)
+#define BTA_DM_AUTH_SMP_INTERNAL_ERR (BTA_DM_AUTH_FAIL_BASE + SMP_PAIR_INTERNAL_ERR)
+#define BTA_DM_AUTH_SMP_UNKNOWN_IO (BTA_DM_AUTH_FAIL_BASE + SMP_UNKNOWN_IO_CAP)
+#define BTA_DM_AUTH_SMP_INIT_FAIL (BTA_DM_AUTH_FAIL_BASE + SMP_INIT_FAIL)
+#define BTA_DM_AUTH_SMP_CONFIRM_FAIL (BTA_DM_AUTH_FAIL_BASE + SMP_CONFIRM_FAIL)
+#define BTA_DM_AUTH_SMP_BUSY (BTA_DM_AUTH_FAIL_BASE + SMP_BUSY)
+#define BTA_DM_AUTH_SMP_ENC_FAIL (BTA_DM_AUTH_FAIL_BASE + SMP_ENC_FAIL)
+#define BTA_DM_AUTH_SMP_RSP_TIMEOUT (BTA_DM_AUTH_FAIL_BASE + SMP_RSP_TIMEOUT)
+
+/* connection parameter boundary value and dummy value */
+#define BTA_DM_BLE_SCAN_INT_MIN BTM_BLE_SCAN_INT_MIN
+#define BTA_DM_BLE_SCAN_INT_MAX BTM_BLE_SCAN_INT_MAX
+#define BTA_DM_BLE_SCAN_WIN_MIN BTM_BLE_SCAN_WIN_MIN
+#define BTA_DM_BLE_SCAN_WIN_MAX BTM_BLE_SCAN_WIN_MAX
+#define BTA_DM_BLE_CONN_INT_MIN BTM_BLE_CONN_INT_MIN
+#define BTA_DM_BLE_CONN_INT_MAX BTM_BLE_CONN_INT_MAX
+#define BTA_DM_BLE_CONN_LATENCY_MAX BTM_BLE_CONN_LATENCY_MAX
+#define BTA_DM_BLE_CONN_SUP_TOUT_MIN BTM_BLE_CONN_SUP_TOUT_MIN
+#define BTA_DM_BLE_CONN_SUP_TOUT_MAX BTM_BLE_CONN_SUP_TOUT_MAX
+#define BTA_DM_BLE_CONN_PARAM_UNDEF BTM_BLE_CONN_PARAM_UNDEF /* use this value when a specific value not to be overwritten */
+
+
+#define BTA_LE_KEY_PENC BTM_LE_KEY_PENC /* encryption information of peer device */
+#define BTA_LE_KEY_PID BTM_LE_KEY_PID /* identity key of the peer device */
+#define BTA_LE_KEY_PCSRK BTM_LE_KEY_PCSRK /* peer SRK */
+#define BTA_LE_KEY_LENC BTM_LE_KEY_LENC /* master role security information:div */
+#define BTA_LE_KEY_LID BTM_LE_KEY_LID /* master device ID key */
+#define BTA_LE_KEY_LCSRK BTM_LE_KEY_LCSRK /* local CSRK has been deliver to peer */
+typedef UINT8 tBTA_LE_KEY_TYPE; /* can be used as a bit mask */
+
+
+typedef tBTM_LE_PENC_KEYS tBTA_LE_PENC_KEYS ;
+typedef tBTM_LE_PCSRK_KEYS tBTA_LE_PCSRK_KEYS;
+typedef tBTM_LE_LENC_KEYS tBTA_LE_LENC_KEYS ;
+typedef tBTM_LE_LCSRK_KEYS tBTA_LE_LCSRK_KEYS ;
+
+typedef union
+{
+ tBTA_LE_PENC_KEYS penc_key; /* received peer encryption key */
+ tBTA_LE_PCSRK_KEYS psrk_key; /* received peer device SRK */
+ BT_OCTET16 pid_key; /* peer device ID key */
+ tBTA_LE_LENC_KEYS lenc_key; /* local encryption reproduction keys LTK = = d1(ER,DIV,0)*/
+ tBTA_LE_LCSRK_KEYS lcsrk_key; /* local device CSRK = d1(ER,DIV,1)*/
+}tBTA_LE_KEY_VALUE;
+
+#define BTA_BLE_LOCAL_KEY_TYPE_ID 1
+#define BTA_BLE_LOCAL_KEY_TYPE_ER 2
+typedef UINT8 tBTA_DM_BLE_LOCAL_KEY_MASK;
+
+typedef struct
+{
+ BT_OCTET16 ir;
+ BT_OCTET16 irk;
+ BT_OCTET16 dhk;
+}tBTA_BLE_LOCAL_ID_KEYS;
+
+#define BTA_DM_SEC_GRANTED BTA_SUCCESS
+#define BTA_DM_SEC_PAIR_NOT_SPT BTA_DM_AUTH_SMP_PAIR_NOT_SUPPORT
+#define BTA_DM_SEC_REP_ATTEMPTS BTA_DM_AUTH_SMP_REPEATED_ATTEMPT
+typedef UINT8 tBTA_DM_BLE_SEC_GRANT;
+
+
+#define BTA_DM_BLE_ONN_NONE BTM_BLE_CONN_NONE
+#define BTA_DM_BLE_CONN_AUTO BTM_BLE_CONN_AUTO
+#define BTA_DM_BLE_CONN_SELECTIVE BTM_BLE_CONN_SELECTIVE
+typedef UINT8 tBTA_DM_BLE_CONN_TYPE;
+
+typedef BOOLEAN (tBTA_DM_BLE_SEL_CBACK)(BD_ADDR random_bda, UINT8 *p_remote_name);
+
+/* Structure associated with BTA_DM_BLE_SEC_REQ_EVT */
+typedef struct
+{
+ BD_ADDR bd_addr; /* peer address */
+ BD_NAME bd_name; /* peer device name */
+} tBTA_DM_BLE_SEC_REQ;
+
+typedef struct
+{
+ BD_ADDR bd_addr; /* peer address */
+ tBTM_LE_KEY_TYPE key_type;
+ tBTM_LE_KEY_VALUE key_value;
+}tBTA_DM_BLE_KEY;
+
+/* Structure associated with BTA_DM_AUTH_CMPL_EVT */
+typedef struct
+{
+ BD_ADDR bd_addr; /* BD address peer device. */
+ BD_NAME bd_name; /* Name of peer device. */
+ BOOLEAN key_present; /* Valid link key value in key element */
+ LINK_KEY key; /* Link key associated with peer device. */
+ UINT8 key_type; /* The type of Link Key */
+ BOOLEAN success; /* TRUE of authentication succeeded, FALSE if failed. */
+ UINT8 fail_reason; /* The HCI reason/error code for when success=FALSE */
+
+} tBTA_DM_AUTH_CMPL;
+
+
+/* Structure associated with BTA_DM_AUTHORIZE_EVT */
+typedef struct
+{
+ BD_ADDR bd_addr; /* BD address peer device. */
+ BD_NAME bd_name; /* Name of peer device. */
+ tBTA_SERVICE_ID service; /* Service ID to authorize. */
+// btla-specific ++
+ DEV_CLASS dev_class;
+// btla-specific --
+} tBTA_DM_AUTHORIZE;
+
+/* Structure associated with BTA_DM_LINK_UP_EVT */
+typedef struct
+{
+ BD_ADDR bd_addr; /* BD address peer device. */
+} tBTA_DM_LINK_UP;
+
+/* Structure associated with BTA_DM_LINK_DOWN_EVT */
+typedef struct
+{
+ BD_ADDR bd_addr; /* BD address peer device. */
+ UINT8 status; /* connection open/closed */
+} tBTA_DM_LINK_DOWN;
+
+/* Structure associated with BTA_DM_ROLE_CHG_EVT */
+typedef struct
+{
+ BD_ADDR bd_addr; /* BD address peer device. */
+ UINT8 new_role; /* the new connection role */
+} tBTA_DM_ROLE_CHG;
+
+/* Structure associated with BTA_DM_SIG_STRENGTH_EVT */
+typedef struct
+{
+ BD_ADDR bd_addr; /* BD address peer device. */
+ tBTA_SIG_STRENGTH_MASK mask; /* mask for the values that are valid */
+ tBTA_DM_RSSI_VALUE rssi_value;
+ tBTA_DM_LINK_QUALITY_VALUE link_quality_value;
+
+} tBTA_DM_SIG_STRENGTH;
+
+/* Structure associated with BTA_DM_BUSY_LEVEL_EVT */
+typedef struct
+{
+ UINT8 level; /* when paging or inquiring, level is 10.
+ Otherwise, the number of ACL links */
+} tBTA_DM_BUSY_LEVEL;
+
+#define BTA_IO_CAP_OUT BTM_IO_CAP_OUT /* DisplayOnly */
+#define BTA_IO_CAP_IO BTM_IO_CAP_IO /* DisplayYesNo */
+#define BTA_IO_CAP_IN BTM_IO_CAP_IN /* KeyboardOnly */
+#define BTA_IO_CAP_NONE BTM_IO_CAP_NONE /* NoInputNoOutput */
+typedef tBTM_IO_CAP tBTA_IO_CAP;
+
+#define BTA_AUTH_SP_NO BTM_AUTH_SP_NO /* 0 MITM Protection Not Required - Single Profile/non-bonding
+ Numeric comparison with automatic accept allowed */
+#define BTA_AUTH_SP_YES BTM_AUTH_SP_YES /* 1 MITM Protection Required - Single Profile/non-bonding
+ Use IO Capabilities to determine authentication procedure */
+#define BTA_AUTH_AP_NO BTM_AUTH_AP_NO /* 2 MITM Protection Not Required - All Profiles/dedicated bonding
+ Numeric comparison with automatic accept allowed */
+#define BTA_AUTH_AP_YES BTM_AUTH_AP_YES /* 3 MITM Protection Required - All Profiles/dedicated bonding
+ Use IO Capabilities to determine authentication procedure */
+#define BTA_AUTH_SPGB_NO BTM_AUTH_SPGB_NO /* 4 MITM Protection Not Required - Single Profiles/general bonding
+ Numeric comparison with automatic accept allowed */
+#define BTA_AUTH_SPGB_YES BTM_AUTH_SPGB_YES /* 5 MITM Protection Required - Single Profiles/general bonding
+ Use IO Capabilities to determine authentication procedure */
+typedef tBTM_AUTH_REQ tBTA_AUTH_REQ;
+
+#define BTA_AUTH_DD_BOND BTM_AUTH_DD_BOND /* 2 this bit is set for dedicated bonding */
+#define BTA_AUTH_GEN_BOND BTM_AUTH_SPGB_NO /* 4 this bit is set for general bonding */
+#define BTA_AUTH_BONDS BTM_AUTH_BONDS /* 6 the general/dedicated bonding bits */
+
+#define BTA_LE_AUTH_NO_BOND BTM_LE_AUTH_REQ_NO_BOND /* 0*/
+#define BTA_LE_AUTH_BOND BTM_LE_AUTH_REQ_BOND /* 1 << 0 */
+#define BTA_LE_AUTH_REQ_MITM BTM_LE_AUTH_REQ_MITM /* 1 << 2 */
+typedef tBTM_LE_AUTH_REQ tBTA_LE_AUTH_REQ; /* combination of the above bit pattern */
+
+#define BTA_OOB_NONE BTM_OOB_NONE
+#define BTA_OOB_PRESENT BTM_OOB_PRESENT
+#if BTM_OOB_INCLUDED == TRUE
+#define BTA_OOB_UNKNOWN BTM_OOB_UNKNOWN
+#endif
+typedef tBTM_OOB_DATA tBTA_OOB_DATA;
+
+/* Structure associated with BTA_DM_SP_CFM_REQ_EVT */
+typedef struct
+{
+ BD_ADDR bd_addr; /* peer address */
+ DEV_CLASS dev_class; /* peer CoD */
+ BD_NAME bd_name; /* peer device name */
+ UINT32 num_val; /* the numeric value for comparison. If just_works, do not show this number to UI */
+ BOOLEAN just_works; /* TRUE, if "Just Works" association model */
+ tBTA_AUTH_REQ loc_auth_req; /* Authentication required for local device */
+ tBTA_AUTH_REQ rmt_auth_req; /* Authentication required for peer device */
+} tBTA_DM_SP_CFM_REQ;
+
+enum
+{
+ BTA_SP_KEY_STARTED, /* passkey entry started */
+ BTA_SP_KEY_ENTERED, /* passkey digit entered */
+ BTA_SP_KEY_ERASED, /* passkey digit erased */
+ BTA_SP_KEY_CLEARED, /* passkey cleared */
+ BTA_SP_KEY_COMPLT /* passkey entry completed */
+};
+typedef UINT8 tBTA_SP_KEY_TYPE;
+
+/* Structure associated with BTA_DM_SP_KEYPRESS_EVT */
+typedef struct
+{
+ BD_ADDR bd_addr; /* peer address */
+ tBTA_SP_KEY_TYPE notif_type;
+}tBTA_DM_SP_KEY_PRESS;
+
+/* Structure associated with BTA_DM_SP_KEY_NOTIF_EVT */
+typedef struct
+{
+ BD_ADDR bd_addr; /* peer address */
+ DEV_CLASS dev_class; /* peer CoD */
+ BD_NAME bd_name; /* peer device name */
+ UINT32 passkey; /* the numeric value for comparison. If just_works, do not show this number to UI */
+} tBTA_DM_SP_KEY_NOTIF;
+
+/* Structure associated with BTA_DM_SP_RMT_OOB_EVT */
+typedef struct
+{
+ BD_ADDR bd_addr; /* peer address */
+ DEV_CLASS dev_class; /* peer CoD */
+ BD_NAME bd_name; /* peer device name */
+} tBTA_DM_SP_RMT_OOB;
+
+/* Structure associated with BTA_DM_BOND_CANCEL_CMPL_EVT */
+typedef struct
+{
+ tBTA_STATUS result; /* TRUE of bond cancel succeeded, FALSE if failed. */
+} tBTA_DM_BOND_CANCEL_CMPL;
+
+/* Union of all security callback structures */
+typedef union
+{
+ tBTA_DM_ENABLE enable; /* BTA enabled */
+ tBTA_DM_PIN_REQ pin_req; /* PIN request. */
+ tBTA_DM_AUTH_CMPL auth_cmpl; /* Authentication complete indication. */
+ tBTA_DM_AUTHORIZE authorize; /* Authorization request. */
+ tBTA_DM_LINK_UP link_up; /* ACL connection down event */
+ tBTA_DM_LINK_DOWN link_down; /* ACL connection down event */
+ tBTA_DM_SIG_STRENGTH sig_strength; /* rssi and link quality value */
+ tBTA_DM_BUSY_LEVEL busy_level; /* System busy level */
+ tBTA_DM_SP_CFM_REQ cfm_req; /* user confirm request */
+ tBTA_DM_SP_KEY_NOTIF key_notif; /* passkey notification */
+ tBTA_DM_SP_RMT_OOB rmt_oob; /* remote oob */
+ tBTA_DM_BOND_CANCEL_CMPL bond_cancel_cmpl; /* Bond Cancel Complete indication */
+ tBTA_DM_SP_KEY_PRESS key_press; /* key press notification event */
+ tBTA_DM_ROLE_CHG role_chg; /* role change event */
+ tBTA_DM_BLE_SEC_REQ ble_req; /* BLE SMP related request */
+ tBTA_DM_BLE_KEY ble_key; /* BLE SMP keys used when pairing */
+ tBTA_BLE_LOCAL_ID_KEYS ble_id_keys; /* IR event */
+ BT_OCTET16 ble_er; /* ER event data */
+} tBTA_DM_SEC;
+
+/* Security callback */
+typedef void (tBTA_DM_SEC_CBACK)(tBTA_DM_SEC_EVT event, tBTA_DM_SEC *p_data);
+
+/* Vendor Specific Command Callback */
+typedef tBTM_VSC_CMPL_CB tBTA_VENDOR_CMPL_CBACK;
+
+/* Search callback events */
+#define BTA_DM_INQ_RES_EVT 0 /* Inquiry result for a peer device. */
+#define BTA_DM_INQ_CMPL_EVT 1 /* Inquiry complete. */
+#define BTA_DM_DISC_RES_EVT 2 /* Discovery result for a peer device. */
+#define BTA_DM_DISC_BLE_RES_EVT 3 /* Discovery result for BLE GATT based servoce on a peer device. */
+#define BTA_DM_DISC_CMPL_EVT 4 /* Discovery complete. */
+#define BTA_DM_DI_DISC_CMPL_EVT 5 /* Discovery complete. */
+#define BTA_DM_SEARCH_CANCEL_CMPL_EVT 6 /* Search cancelled */
+
+typedef UINT8 tBTA_DM_SEARCH_EVT;
+
+#define BTA_DM_INQ_RES_IGNORE_RSSI BTM_INQ_RES_IGNORE_RSSI /* 0x7f RSSI value not supplied (ignore it) */
+
+/* Structure associated with BTA_DM_INQ_RES_EVT */
+typedef struct
+{
+ BD_ADDR bd_addr; /* BD address peer device. */
+ DEV_CLASS dev_class; /* Device class of peer device. */
+ BOOLEAN remt_name_not_required; /* Application sets this flag if it already knows the name of the device */
+ /* If the device name is known to application BTA skips the remote name request */
+ BOOLEAN is_limited; /* TRUE, if the limited inquiry bit is set in the CoD */
+ INT8 rssi; /* The rssi value */
+ UINT8 *p_eir; /* received EIR */
+#if (BLE_INCLUDED == TRUE)
+ UINT8 inq_result_type;
+ UINT8 ble_addr_type;
+ tBTM_BLE_EVT_TYPE ble_evt_type;
+ tBT_DEVICE_TYPE device_type;
+#endif
+
+} tBTA_DM_INQ_RES;
+
+/* Structure associated with BTA_DM_INQ_CMPL_EVT */
+typedef struct
+{
+ UINT8 num_resps; /* Number of inquiry responses. */
+} tBTA_DM_INQ_CMPL;
+
+/* Structure associated with BTA_DM_DI_DISC_CMPL_EVT */
+typedef struct
+{
+ BD_ADDR bd_addr; /* BD address peer device. */
+ UINT8 num_record; /* Number of DI record */
+ tBTA_STATUS result;
+} tBTA_DM_DI_DISC_CMPL;
+
+/* Structure associated with BTA_DM_DISC_RES_EVT */
+typedef struct
+{
+ BD_ADDR bd_addr; /* BD address peer device. */
+ BD_NAME bd_name; /* Name of peer device. */
+ tBTA_SERVICE_MASK services; /* Services found on peer device. */
+// btla-specific ++
+ UINT8 * p_raw_data; /* Raw data for discovery DB */
+ UINT32 raw_data_size; /* size of raw data */
+ tBT_DEVICE_TYPE device_type; /* device type in case it is BLE device */
+// btla-specific --
+ tBTA_STATUS result;
+} tBTA_DM_DISC_RES;
+
+/* Structure associated with tBTA_DM_DISC_BLE_RES */
+typedef struct
+{
+ BD_ADDR bd_addr; /* BD address peer device. */
+ BD_NAME bd_name; /* Name of peer device. */
+ tBT_UUID service; /* GATT based Services UUID found on peer device. */
+} tBTA_DM_DISC_BLE_RES;
+
+
+/* Union of all search callback structures */
+typedef union
+{
+ tBTA_DM_INQ_RES inq_res; /* Inquiry result for a peer device. */
+ tBTA_DM_INQ_CMPL inq_cmpl; /* Inquiry complete. */
+ tBTA_DM_DISC_RES disc_res; /* Discovery result for a peer device. */
+ tBTA_DM_DISC_BLE_RES disc_ble_res; /* discovery result for GATT based service */
+ tBTA_DM_DI_DISC_CMPL di_disc; /* DI discovery result for a peer device */
+
+} tBTA_DM_SEARCH;
+
+/* Search callback */
+typedef void (tBTA_DM_SEARCH_CBACK)(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH *p_data);
+
+/* Execute call back */
+typedef void (tBTA_DM_EXEC_CBACK) (void * p_param);
+
+/* Encryption callback*/
+typedef void (tBTA_DM_ENCRYPT_CBACK) (BD_ADDR bd_addr, tBTA_STATUS result);
+
+#if BLE_INCLUDED == TRUE
+#define BTA_DM_BLE_SEC_NONE BTM_BLE_SEC_NONE
+#define BTA_DM_BLE_SEC_ENCRYPT BTM_BLE_SEC_ENCRYPT
+#define BTA_DM_BLE_SEC_NO_MITM BTM_BLE_SEC_ENCRYPT_NO_MITM
+#define BTA_DM_BLE_SEC_MITM BTM_BLE_SEC_ENCRYPT_MITM
+typedef tBTM_BLE_SEC_ACT tBTA_DM_BLE_SEC_ACT;
+#else
+typedef UINT8 tBTA_DM_BLE_SEC_ACT;
+#endif
+
+/* Maximum service name length */
+#define BTA_SERVICE_NAME_LEN 35
+#define BTA_SERVICE_DESP_LEN BTA_SERVICE_NAME_LEN
+#define BTA_PROVIDER_NAME_LEN BTA_SERVICE_NAME_LEN
+
+
+/* link policy masks */
+#define BTA_DM_LP_SWITCH HCI_ENABLE_MASTER_SLAVE_SWITCH
+#define BTA_DM_LP_HOLD HCI_ENABLE_HOLD_MODE
+#define BTA_DM_LP_SNIFF HCI_ENABLE_SNIFF_MODE
+#define BTA_DM_LP_PARK HCI_ENABLE_PARK_MODE
+typedef UINT16 tBTA_DM_LP_MASK;
+
+/* power mode actions */
+#define BTA_DM_PM_NO_ACTION 0x00 /* no change to the current pm setting */
+#define BTA_DM_PM_PARK 0x10 /* prefers park mode */
+#define BTA_DM_PM_SNIFF 0x20 /* prefers sniff mode */
+#define BTA_DM_PM_SNIFF1 0x21 /* prefers sniff1 mode */
+#define BTA_DM_PM_SNIFF2 0x22 /* prefers sniff2 mode */
+#define BTA_DM_PM_SNIFF3 0x23 /* prefers sniff3 mode */
+#define BTA_DM_PM_SNIFF4 0x24 /* prefers sniff4 mode */
+#define BTA_DM_PM_SNIFF5 0x25 /* prefers sniff5 mode */
+#define BTA_DM_PM_SNIFF6 0x26 /* prefers sniff6 mode */
+#define BTA_DM_PM_SNIFF7 0x27 /* prefers sniff7 mode */
+#define BTA_DM_PM_SNIFF_USER0 0x28 /* prefers user-defined sniff0 mode (testtool only) */
+#define BTA_DM_PM_SNIFF_USER1 0x29 /* prefers user-defined sniff1 mode (testtool only) */
+#define BTA_DM_PM_ACTIVE 0x40 /* prefers active mode */
+#define BTA_DM_PM_RETRY 0x80 /* retry power mode based on current settings */
+#define BTA_DM_PM_NO_PREF 0x01 /* service has no prefernce on power mode setting. eg. connection to service got closed */
+
+typedef UINT8 tBTA_DM_PM_ACTTION;
+
+/* index to bta_dm_ssr_spec */
+#define BTA_DM_PM_SSR0 0
+#define BTA_DM_PM_SSR1 1
+#define BTA_DM_PM_SSR2 2
+#define BTA_DM_PM_SSR3 3
+#define BTA_DM_PM_SSR4 4
+#define BTA_DM_PM_SSR5 5
+#define BTA_DM_PM_SSR6 6
+
+#define BTA_DM_PM_NUM_EVTS 9
+
+#ifndef BTA_DM_PM_PARK_IDX
+#define BTA_DM_PM_PARK_IDX 5 /* the actual index to bta_dm_pm_md[] for PARK mode */
+#endif
+
+#define BTA_DM_SW_BB_TO_MM BTM_SW_BB_TO_MM
+#define BTA_DM_SW_MM_TO_BB BTM_SW_MM_TO_BB
+#define BTA_DM_SW_BB_TO_BTC BTM_SW_BB_TO_BTC
+#define BTA_DM_SW_BTC_TO_BB BTM_SW_BTC_TO_BB
+
+typedef tBTM_SW_DIR tBTA_DM_SW_DIR;
+
+/* Switch callback events */
+#define BTA_DM_SWITCH_CMPL_EVT 0 /* Completion of the Switch API */
+
+typedef UINT8 tBTA_DM_SWITCH_EVT;
+typedef void (tBTA_DM_SWITCH_CBACK)(tBTA_DM_SWITCH_EVT event, tBTA_STATUS status);
+
+/* Audio routing out configuration */
+#define BTA_DM_ROUTE_NONE 0x00 /* No Audio output */
+#define BTA_DM_ROUTE_DAC 0x01 /* routing over analog output */
+#define BTA_DM_ROUTE_I2S 0x02 /* routing over digital (I2S) output */
+#define BTA_DM_ROUTE_BT_MONO 0x04 /* routing over SCO */
+#define BTA_DM_ROUTE_BT_STEREO 0x08 /* routing over BT Stereo */
+#define BTA_DM_ROUTE_HOST 0x10 /* routing over Host */
+#define BTA_DM_ROUTE_FMTX 0x20 /* routing over FMTX */
+#define BTA_DM_ROUTE_FMRX 0x40 /* routing over FMRX */
+#define BTA_DM_ROUTE_BTSNK 0x80 /* routing over BT SNK */
+
+typedef UINT8 tBTA_DM_ROUTE_PATH;
+
+
+/* Device Identification (DI) data structure
+*/
+/* Used to set the DI record */
+typedef tSDP_DI_RECORD tBTA_DI_RECORD;
+/* Used to get the DI record */
+typedef tSDP_DI_GET_RECORD tBTA_DI_GET_RECORD;
+/* SDP discovery database */
+typedef tSDP_DISCOVERY_DB tBTA_DISCOVERY_DB;
+
+#ifndef BTA_DI_NUM_MAX
+#define BTA_DI_NUM_MAX 3
+#endif
+
+/*****************************************************************************
+** External Function Declarations
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*******************************************************************************
+**
+** Function BTA_EnableBluetooth
+**
+** Description This function initializes BTA and prepares BTA and the
+** Bluetooth protocol stack for use. This function is
+** typically called at startup or when Bluetooth services
+** are required by the phone. This function must be called
+** before calling any other API function.
+**
+**
+** Returns BTA_SUCCESS if successful.
+** BTA_FAIL if internal failure.
+**
+*******************************************************************************/
+BTA_API extern tBTA_STATUS BTA_EnableBluetooth(tBTA_DM_SEC_CBACK *p_cback);
+
+/*******************************************************************************
+**
+** Function BTA_DisableBluetooth
+**
+** Description This function disables BTA and the Bluetooth protocol
+** stack. It is called when BTA is no longer being used
+** by any application in the system.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern tBTA_STATUS BTA_DisableBluetooth(void);
+
+/*******************************************************************************
+**
+** Function BTA_EnableTestMode
+**
+** Description Enables bluetooth device under test mode
+**
+**
+** Returns tBTA_STATUS
+**
+*******************************************************************************/
+BTA_API extern tBTA_STATUS BTA_EnableTestMode(void);
+
+/*******************************************************************************
+**
+** Function BTA_DisableTestMode
+**
+** Description Disable bluetooth device under test mode
+**
+**
+** Returns None
+**
+*******************************************************************************/
+BTA_API extern void BTA_DisableTestMode(void);
+
+/*******************************************************************************
+**
+** Function BTA_DmIsDeviceUp
+**
+** Description This function tests whether the Bluetooth module is up
+** and ready. This is a direct execution function that
+** may lock task scheduling on some platforms.
+**
+**
+** Returns TRUE if the module is ready.
+** FALSE if the module is not ready.
+**
+*******************************************************************************/
+BTA_API extern BOOLEAN BTA_DmIsDeviceUp(void);
+
+/*******************************************************************************
+**
+** Function BTA_DmSetDeviceName
+**
+** Description This function sets the Bluetooth name of the local device.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_DmSetDeviceName(char *p_name);
+
+/*******************************************************************************
+**
+** Function BTA_DmSetVisibility
+**
+** Description This function sets the Bluetooth connectable,discoverable,
+** pairable and conn paired only modesmodes of the local device.
+** This controls whether other Bluetooth devices can find and connect to
+** the local device.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_DmSetVisibility(tBTA_DM_DISC disc_mode, tBTA_DM_CONN conn_mode, UINT8 pairable_mode, UINT8 conn_filter);
+
+/*******************************************************************************
+**
+** Function BTA_DmSetScanParam
+**
+** Description This function sets the parameters for page scan and
+** inquiry scan.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_DmSetScanParam (UINT16 page_scan_interval, UINT16 page_scan_window,
+ UINT16 inquiry_scan_interval, UINT16 inquiry_scan_window);
+
+/*******************************************************************************
+**
+** Function BTA_DmSetAfhChannels
+**
+** Description This function sets the AFH first and
+** last disable channel, so channels within
+** that range are disabled.
+** In order to use this API, BTM_BYPASS_AMP_AUTO_AFH must be set
+** to be TRUE
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_DmSetAfhChannels(UINT8 first, UINT8 last);
+
+
+/*******************************************************************************
+**
+** Function BTA_DmVendorSpecificCommand
+**
+** Description This function sends the vendor specific command
+** to the controller
+**
+**
+** Returns tBTA_STATUS
+**
+*******************************************************************************/
+BTA_API extern tBTA_STATUS BTA_DmVendorSpecificCommand (UINT16 opcode, UINT8 param_len,UINT8 *p_param_buf, tBTA_VENDOR_CMPL_CBACK *p_cback);
+
+
+/*******************************************************************************
+**
+** Function BTA_DmSearch
+**
+** Description This function searches for peer Bluetooth devices. It
+** first performs an inquiry; for each device found from the
+** inquiry it gets the remote name of the device. If
+** parameter services is nonzero, service discovery will be
+** performed on each device for the services specified.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_DmSearch(tBTA_DM_INQ *p_dm_inq, tBTA_SERVICE_MASK services,
+ tBTA_DM_SEARCH_CBACK *p_cback);
+
+/*******************************************************************************
+**
+** Function BTA_DmSearchCancel
+**
+** Description This function cancels a search that has been initiated
+** by calling BTA_DmSearch().
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_DmSearchCancel(void);
+
+/*******************************************************************************
+**
+** Function BTA_DmDiscover
+**
+** Description This function performs service discovery for the services
+** of a particular peer device.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_DmDiscover(BD_ADDR bd_addr, tBTA_SERVICE_MASK services,
+ tBTA_DM_SEARCH_CBACK *p_cback, BOOLEAN sdp_search);
+
+// btla-specific ++
+/*******************************************************************************
+**
+** Function BTA_DmDiscoverUUID
+**
+** Description This function performs service discovery for the services
+** of a particular peer device.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_DmDiscoverUUID(BD_ADDR bd_addr, tSDP_UUID *uuid,
+ tBTA_DM_SEARCH_CBACK *p_cback, BOOLEAN sdp_search);
+
+/*******************************************************************************
+**
+** Function BTA_DmGetCachedRemoteName
+**
+** Description Retieve cached remote name if available
+**
+** Returns BTA_SUCCESS if cached name was retrieved
+** BTA_FAILURE if cached name is not available
+**
+*******************************************************************************/
+tBTA_STATUS BTA_DmGetCachedRemoteName(BD_ADDR remote_device, UINT8 **pp_cached_name);
+// btla-specific --
+
+/*******************************************************************************
+**
+** Function BTA_DmIsMaster
+**
+** Description This function checks if the local device is the master of
+** the link to the given device
+**
+** Returns TRUE if master.
+** FALSE if not.
+**
+*******************************************************************************/
+BTA_API extern BOOLEAN BTA_DmIsMaster(BD_ADDR bd_addr);
+
+/*******************************************************************************
+**
+** Function BTA_DmBond
+**
+** Description This function initiates a bonding procedure with a peer
+** device. The bonding procedure enables authentication
+** and optionally encryption on the Bluetooth link.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_DmBond(BD_ADDR bd_addr);
+
+/*******************************************************************************
+**
+** Function BTA_DmBondCancel
+**
+** Description This function cancels a bonding procedure with a peer
+** device.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_DmBondCancel(BD_ADDR bd_addr);
+
+/*******************************************************************************
+**
+** Function BTA_DmPinReply
+**
+** Description This function provides a PIN when one is requested by DM
+** during a bonding procedure. The application should call
+** this function after the security callback is called with
+** a BTA_DM_PIN_REQ_EVT.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_DmPinReply(BD_ADDR bd_addr, BOOLEAN accept, UINT8 pin_len,
+ UINT8 *p_pin);
+
+/*******************************************************************************
+**
+** Function BTA_DmLinkPolicy
+**
+** Description This function sets/clears the link policy mask to the given
+** bd_addr.
+** If clearing the sniff or park mode mask, the link is put
+** in active mode.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_DmLinkPolicy(BD_ADDR bd_addr, tBTA_DM_LP_MASK policy_mask,
+ BOOLEAN set);
+
+#if (BTM_OOB_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function BTA_DmLocalOob
+**
+** Description This function retrieves the OOB data from local controller.
+** The result is reported by bta_dm_co_loc_oob().
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_DmLocalOob(void);
+#endif /* BTM_OOB_INCLUDED */
+
+/*******************************************************************************
+**
+** Function BTA_DmConfirm
+**
+** Description This function accepts or rejects the numerical value of the
+** Simple Pairing process on BTA_DM_SP_CFM_REQ_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_DmConfirm(BD_ADDR bd_addr, BOOLEAN accept);
+
+/*******************************************************************************
+**
+** Function BTA_DmPasskeyCancel
+**
+** Description This function is called to cancel the simple pairing process
+** reported by BTA_DM_SP_KEY_NOTIF_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_DmPasskeyCancel(BD_ADDR bd_addr);
+
+/*******************************************************************************
+**
+** Function BTA_DmAddDevice
+**
+** Description This function adds a device to the security database list
+** of peer devices. This function would typically be called
+** at system startup to initialize the security database with
+** known peer devices. This is a direct execution function
+** that may lock task scheduling on some platforms.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_DmAddDevice(BD_ADDR bd_addr, DEV_CLASS dev_class,
+ LINK_KEY link_key, tBTA_SERVICE_MASK trusted_mask,
+ BOOLEAN is_trusted, UINT8 key_type,
+ tBTA_IO_CAP io_cap);
+
+/*******************************************************************************
+**
+** Function BTA_DmAddDevWithName
+**
+** Description This function is newer version of BTA_DmAddDevice()
+** which added bd_name and features as input parameters.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_DmAddDevWithName (BD_ADDR bd_addr, DEV_CLASS dev_class,
+ BD_NAME bd_name, BD_FEATURES features,
+ LINK_KEY link_key, tBTA_SERVICE_MASK trusted_mask,
+ BOOLEAN is_trusted, UINT8 key_type, tBTA_IO_CAP io_cap);
+
+/*******************************************************************************
+**
+** Function BTA_DmRemoveDevice
+**
+** Description This function removes a device from the security database.
+** This is a direct execution function that may lock task
+** scheduling on some platforms.
+**
+**
+** Returns BTA_SUCCESS if successful.
+** BTA_FAIL if operation failed.
+**
+*******************************************************************************/
+BTA_API extern tBTA_STATUS BTA_DmRemoveDevice(BD_ADDR bd_addr);
+
+/*******************************************************************************
+**
+** Function BTA_DmAuthorizeReply
+**
+** Description This function provides an authorization reply when
+** authorization is requested by BTA. The application calls
+** this function after the security callback is called with
+** a BTA_DM_AUTHORIZE_EVT.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_DmAuthorizeReply(BD_ADDR bd_addr, tBTA_SERVICE_ID service,
+ tBTA_AUTH_RESP response);
+
+/*******************************************************************************
+**
+** Function BTA_DmSignalStrength
+**
+** Description This function initiates RSSI and channnel quality
+** measurments. BTA_DM_SIG_STRENGTH_EVT is sent to
+** application with the values of RSSI and channel
+** quality
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_DmSignalStrength(tBTA_SIG_STRENGTH_MASK mask, UINT16 period, BOOLEAN start);
+
+/*******************************************************************************
+**
+** Function BTA_DmWriteInqTxPower
+**
+** Description This command is used to write the inquiry transmit power level
+** used to transmit the inquiry (ID) data packets.
+**
+** Parameters tx_power - tx inquiry power to use, valid value is -70 ~ 20
+
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_DmWriteInqTxPower(INT8 tx_power);
+
+/*******************************************************************************
+**
+** Function BTA_DmEirAddUUID
+**
+** Description This function is called to add UUID into EIR.
+**
+** Parameters tBT_UUID - UUID
+**
+** Returns None
+**
+*******************************************************************************/
+BTA_API extern void BTA_DmEirAddUUID (tBT_UUID *p_uuid);
+
+/*******************************************************************************
+**
+** Function BTA_DmEirRemoveUUID
+**
+** Description This function is called to remove UUID from EIR.
+**
+** Parameters tBT_UUID - UUID
+**
+** Returns None
+**
+*******************************************************************************/
+BTA_API extern void BTA_DmEirRemoveUUID (tBT_UUID *p_uuid);
+
+/*******************************************************************************
+**
+** Function BTA_DmSetEIRConfig
+**
+** Description This function is called to override the BTA default EIR parameters.
+** This funciton is only valid in a system where BTU & App task
+** are in the same memory space.
+**
+** Parameters Pointer to User defined EIR config
+**
+** Returns None
+**
+*******************************************************************************/
+BTA_API extern void BTA_DmSetEIRConfig (tBTA_DM_EIR_CONF *p_eir_cfg);
+
+/*******************************************************************************
+**
+** Function BTA_CheckEirData
+**
+** Description This function is called to get EIR data from significant part.
+**
+** Parameters p_eir - pointer of EIR significant part
+** type - finding EIR data type
+** p_length - return the length of EIR data
+**
+** Returns pointer of EIR data
+**
+*******************************************************************************/
+BTA_API extern UINT8 *BTA_CheckEirData( UINT8 *p_eir, UINT8 tag, UINT8 *p_length );
+
+/*******************************************************************************
+**
+** Function BTA_GetEirService
+**
+** Description This function is called to get BTA service mask from EIR.
+**
+** Parameters p_eir - pointer of EIR significant part
+** p_services - return the BTA service mask
+**
+** Returns None
+**
+*******************************************************************************/
+BTA_API extern void BTA_GetEirService( UINT8 *p_eir, tBTA_SERVICE_MASK *p_services );
+
+/*******************************************************************************
+**
+** Function BTA_DmUseSsr
+**
+** Description This function is called to check if the connected peer device
+** supports SSR or not.
+**
+** Returns TRUE, if SSR is supported
+**
+*******************************************************************************/
+BTA_API extern BOOLEAN BTA_DmUseSsr( BD_ADDR bd_addr );
+
+
+/*******************************************************************************
+**
+** Function BTA_DmSetLocalDiRecord
+**
+** Description This function adds a DI record to the local SDP database.
+**
+** Returns BTA_SUCCESS if record set sucessfully, otherwise error code.
+**
+*******************************************************************************/
+BTA_API extern tBTA_STATUS BTA_DmSetLocalDiRecord( tBTA_DI_RECORD *p_device_info,
+ UINT32 *p_handle );
+
+/*******************************************************************************
+**
+** Function BTA_DmGetLocalDiRecord
+**
+** Description Get a specified DI record to the local SDP database. If no
+** record handle is provided, the primary DI record will be
+** returned.
+**
+** Returns BTA_SUCCESS if record set sucessfully, otherwise error code.
+**
+*******************************************************************************/
+BTA_API extern tBTA_STATUS BTA_DmGetLocalDiRecord( tBTA_DI_GET_RECORD *p_device_info,
+ UINT32 *p_handle );
+
+/*******************************************************************************
+**
+** Function BTA_DmDiDiscover
+**
+** Description This function queries a remote device for DI information.
+**
+** Returns None.
+**
+*******************************************************************************/
+BTA_API extern void BTA_DmDiDiscover( BD_ADDR remote_device, tBTA_DISCOVERY_DB *p_db,
+ UINT32 len, tBTA_DM_SEARCH_CBACK *p_cback );
+
+/*******************************************************************************
+**
+** Function BTA_DmGetDiRecord
+**
+** Description This function retrieves a remote device's DI record from
+** the specified database.
+**
+** Returns None.
+**
+*******************************************************************************/
+BTA_API extern tBTA_STATUS BTA_DmGetDiRecord( UINT8 get_record_index, tBTA_DI_GET_RECORD *p_device_info,
+ tBTA_DISCOVERY_DB *p_db );
+
+/*******************************************************************************
+**
+** Function BTA_SysFeatures
+**
+** Description This function is called to set system features.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_SysFeatures (UINT16 sys_features);
+
+/*******************************************************************************
+**
+** Function bta_dmexecutecallback
+**
+** Description This function will request BTA to execute a call back in the context of BTU task
+** This API was named in lower case because it is only intended
+** for the internal customers(like BSA).
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_dmexecutecallback (tBTA_DM_EXEC_CBACK* p_callback, void * p_param);
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function BTA_DmPcmInitSamples
+**
+** Description initialize the down sample converter.
+**
+** src_sps: original samples per second (source audio data)
+** (ex. 44100, 48000)
+** bits: number of bits per pcm sample (16)
+** n_channels: number of channels (i.e. mono(1), stereo(2)...)
+**
+** Returns none
+**
+*******************************************************************************/
+BTA_API extern void BTA_DmPcmInitSamples (UINT32 src_sps, UINT32 bits, UINT32 n_channels);
+
+/**************************************************************************************
+** Function BTA_DmPcmResample
+**
+** Description Down sampling utility to convert higher sampling rate into 8K/16bits
+** PCM samples.
+**
+** Parameters p_src: pointer to the buffer where the original sampling PCM
+** are stored.
+** in_bytes: Length of the input PCM sample buffer in byte.
+** p_dst: pointer to the buffer which is to be used to store
+** the converted PCM samples.
+**
+**
+** Returns INT32: number of samples converted.
+**
+**************************************************************************************/
+BTA_API extern INT32 BTA_DmPcmResample (void *p_src, UINT32 in_bytes, void *p_dst);
+#endif
+
+#if ((defined BLE_INCLUDED) && (BLE_INCLUDED == TRUE))
+/* BLE related API functions */
+/*******************************************************************************
+**
+** Function BTA_DmBleSecurityGrant
+**
+** Description Grant security request access.
+**
+** Parameters: bd_addr - BD address of the peer
+** res - security grant status.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_DmBleSecurityGrant(BD_ADDR bd_addr, tBTA_DM_BLE_SEC_GRANT res);
+
+
+
+/*******************************************************************************
+**
+** Function BTA_DmBleSetBgConnType
+**
+** Description This function is called to set BLE connectable mode for a
+** peripheral device.
+**
+** Parameters bg_conn_type: it can be auto connection, or selective connection.
+** p_select_cback: callback function when selective connection procedure
+** is being used.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_DmBleSetBgConnType(tBTA_DM_BLE_CONN_TYPE bg_conn_type, tBTA_DM_BLE_SEL_CBACK *p_select_cback);
+
+/*******************************************************************************
+**
+** Function BTA_DmBlePasskeyReply
+**
+** Description Send BLE SMP passkey reply.
+**
+** Parameters: bd_addr - BD address of the peer
+** accept - passkey entry sucessful or declined.
+** passkey - passkey value, must be a 6 digit number,
+** can be lead by 0.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_DmBlePasskeyReply(BD_ADDR bd_addr, BOOLEAN accept, UINT32 passkey);
+
+/*******************************************************************************
+**
+** Function BTA_DmAddBleDevice
+**
+** Description Add a BLE device. This function will be normally called
+** during host startup to restore all required information
+** for a LE device stored in the NVRAM.
+**
+** Parameters: bd_addr - BD address of the peer
+** dev_type - Remote device's device type.
+** addr_type - LE device address type.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_DmAddBleDevice(BD_ADDR bd_addr, tBLE_ADDR_TYPE addr_type,
+ tBT_DEVICE_TYPE dev_type);
+
+
+/*******************************************************************************
+**
+** Function BTA_DmAddBleKey
+**
+** Description Add/modify LE device information. This function will be
+** normally called during host startup to restore all required
+** information stored in the NVRAM.
+**
+** Parameters: bd_addr - BD address of the peer
+** p_le_key - LE key values.
+** key_type - LE SMP key type.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_DmAddBleKey (BD_ADDR bd_addr, tBTA_LE_KEY_VALUE *p_le_key,
+ tBTA_LE_KEY_TYPE key_type);
+
+/*******************************************************************************
+**
+** Function BTA_DmSetBlePrefConnParams
+**
+** Description This function is called to set the preferred connection
+** parameters when default connection parameter is not desired.
+**
+** Parameters: bd_addr - BD address of the peripheral
+** min_conn_int - minimum preferred connection interval
+** max_conn_int - maximum preferred connection interval
+** slave_latency - preferred slave latency
+** supervision_tout - preferred supervision timeout
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_DmSetBlePrefConnParams(BD_ADDR bd_addr,
+ UINT16 min_conn_int, UINT16 max_conn_int,
+ UINT16 slave_latency, UINT16 supervision_tout );
+
+/*******************************************************************************
+**
+** Function BTA_DmSetBleConnScanParams
+**
+** Description This function is called to set scan parameters used in
+** BLE connection request
+**
+** Parameters: bd_addr - BD address of the peripheral
+** scan_interval - scan interval
+** scan_window - scan window
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_DmSetBleConnScanParams(UINT16 scan_interval,
+ UINT16 scan_window );
+
+/*******************************************************************************
+**
+** Function BTA_DmSearchExt
+**
+** Description This function searches for peer Bluetooth devices. It performs
+** an inquiry and gets the remote name for devices. Service
+** discovery is done if services is non zero
+**
+** Parameters p_dm_inq: inquiry conditions
+** services: if service is not empty, service discovery will be done.
+** for all GATT based service condition, put num_uuid, and
+** p_uuid is the pointer to the list of UUID values.
+** p_cback: callback functino when search is completed.
+**
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_DmSearchExt(tBTA_DM_INQ *p_dm_inq, tBTA_SERVICE_MASK_EXT *p_services,
+ tBTA_DM_SEARCH_CBACK *p_cback);
+
+/*******************************************************************************
+**
+** Function BTA_DmDiscoverExt
+**
+** Description This function does service discovery for services of a
+** peer device. When services.num_uuid is 0, it indicates all
+** GATT based services are to be searched; other wise a list of
+** UUID of interested services should be provided through
+** services.p_uuid.
+**
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_DmDiscoverExt(BD_ADDR bd_addr, tBTA_SERVICE_MASK_EXT *p_services,
+ tBTA_DM_SEARCH_CBACK *p_cback, BOOLEAN sdp_search);
+
+
+/*******************************************************************************
+**
+** Function BTA_DmSetEncryption
+**
+** Description This function is called to ensure that connection is
+** encrypted. Should be called only on an open connection.
+** Typically only needed for connections that first want to
+** bring up unencrypted links, then later encrypt them.
+**
+** Parameters: bd_addr - Address of the peer device
+** p_callback - Pointer to callback function to indicat the
+** link encryption status
+** sec_act - This is the security action to indicate
+** what knid of BLE security level is required for
+** the BLE link if the BLE is supported
+** Note: This parameter is ignored for the BR/EDR link
+** or the BLE is not supported
+**
+** Returns void
+**
+**
+*******************************************************************************/
+BTA_API extern void BTA_DmSetEncryption(BD_ADDR bd_addr, tBTA_DM_ENCRYPT_CBACK *p_callback,
+ tBTA_DM_BLE_SEC_ACT sec_act);
+
+#endif
+
+// btla-specific ++
+/*******************************************************************************
+**
+** Function BTA_DmSetAfhChannelAssessment
+**
+** Description This function is called to set the channel assessment mode on or off
+**
+** Returns status
+**
+*******************************************************************************/
+BTA_API extern void BTA_DmSetAfhChannelAssessment (BOOLEAN enable_or_disable);
+// btla-specific --
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_API_H */
+
diff --git a/bta/include/bta_av_api.h b/bta/include/bta_av_api.h
new file mode 100644
index 0000000..f639d22
--- /dev/null
+++ b/bta/include/bta_av_api.h
@@ -0,0 +1,753 @@
+/*****************************************************************************
+**
+** Name: bta_av_api.h
+**
+** Description: This is the public interface file for the advanced
+** audio/video streaming (AV) subsystem of BTA, Widcomm's
+** Bluetooth application layer for mobile phones.
+**
+** Copyright (c) 2004-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_AV_API_H
+#define BTA_AV_API_H
+
+#include "avrc_api.h"
+#include "avdt_api.h"
+#include "a2d_api.h"
+#include "bta_api.h"
+#if( defined VDP_INCLUDED) && (VDP_INCLUDED == TRUE)
+#include "vdp_api.h"
+#endif
+
+/*****************************************************************************
+** Constants and data types
+*****************************************************************************/
+/* Set to TRUE if seperate authorization prompt desired for AVCTP besides A2DP authorization */
+/* Typically FALSE when AVRCP is used in conjunction with A2DP */
+#ifndef BTA_AV_WITH_AVCTP_AUTHORIZATION
+#define BTA_AV_WITH_AVCTP_AUTHORIZATION FALSE
+#endif
+
+/* AV status values */
+#define BTA_AV_SUCCESS 0 /* successful operation */
+#define BTA_AV_FAIL 1 /* generic failure */
+#define BTA_AV_FAIL_SDP 2 /* service not found */
+#define BTA_AV_FAIL_STREAM 3 /* stream connection failed */
+#define BTA_AV_FAIL_RESOURCES 4 /* no resources */
+#define BTA_AV_FAIL_ROLE 5 /* failed due to role management related issues */
+
+typedef UINT8 tBTA_AV_STATUS;
+
+/* AV features masks */
+#define BTA_AV_FEAT_RCTG 0x0001 /* remote control target */
+#define BTA_AV_FEAT_RCCT 0x0002 /* remote control controller */
+#define BTA_AV_FEAT_PROTECT 0x0004 /* streaming media contect protection */
+#define BTA_AV_FEAT_VENDOR 0x0008 /* remote control vendor dependent commands */
+#define BTA_AV_FEAT_REPORT 0x0020 /* use reporting service for VDP */
+#define BTA_AV_FEAT_METADATA 0x0040 /* remote control Metadata Transfer command/response */
+#define BTA_AV_FEAT_MULTI_AV 0x0080 /* use multi-av, if controller supports it */
+#define BTA_AV_FEAT_BROWSE 0x0010 /* use browsing channel */
+#define BTA_AV_FEAT_MASTER 0x0100 /* stream only as master role */
+#define BTA_AV_FEAT_ADV_CTRL 0x0200 /* remote control Advanced Control command/response */
+#define BTA_AV_FEAT_DELAY_RPT 0x0400 /* allow delay reporting */
+#define BTA_AV_FEAT_ACP_START 0x0800 /* start stream when 2nd SNK was accepted */
+
+/* Internal features */
+#define BTA_AV_FEAT_NO_SCO_SSPD 0x8000 /* Do not suspend av streaming as to AG events(SCO or Call) */
+
+typedef UINT16 tBTA_AV_FEAT;
+
+/* AV channel values */
+#define BTA_AV_CHNL_MSK 0xC0
+#define BTA_AV_CHNL_AUDIO 0x40 /* audio channel */
+#define BTA_AV_CHNL_VIDEO 0x80 /* video channel */
+typedef UINT8 tBTA_AV_CHNL;
+
+
+#define BTA_AV_HNDL_MSK 0x3F
+typedef UINT8 tBTA_AV_HNDL;
+/* handle index to mask */
+#define BTA_AV_HNDL_TO_MSK(h) ((UINT8)(1 << (h)))
+
+/* tBTA_AV_HNDL to mask */
+#define BTA_AV_HNDL_TYPE_TO_MSK(h) ((UINT8)(1 << (h&BTA_AV_HNDL_MSK)))
+
+/* offset of codec type in codec info byte array */
+#define BTA_AV_CODEC_TYPE_IDX AVDT_CODEC_TYPE_INDEX /* 2 */
+
+
+
+/* maximum number of streams created: 1 for audio, 1 for video */
+#ifndef BTA_AV_NUM_STRS
+#define BTA_AV_NUM_STRS 2
+#endif
+
+#ifndef BTA_AV_MAX_SEPS
+#define BTA_AV_MAX_SEPS 2
+#endif
+
+#ifndef BTA_AV_MAX_A2DP_MTU
+ /*#define BTA_AV_MAX_A2DP_MTU 668 //224 (DM5) * 3 - 4(L2CAP header) */
+#define BTA_AV_MAX_A2DP_MTU 1008
+#endif
+
+#ifndef BTA_AV_MAX_VDP_MTU
+#define BTA_AV_MAX_VDP_MTU 1008
+#endif
+
+
+/* codec type */
+#define BTA_AV_CODEC_SBC A2D_MEDIA_CT_SBC /* SBC media codec type */
+#define BTA_AV_CODEC_M12 A2D_MEDIA_CT_M12 /* MPEG-1, 2 Audio media codec type */
+#define BTA_AV_CODEC_M24 A2D_MEDIA_CT_M24 /* MPEG-2, 4 AAC media codec type */
+#define BTA_AV_CODEC_ATRAC A2D_MEDIA_CT_ATRAC /* ATRAC family media codec type */
+#define BTA_AV_CODEC_H263_P0 VDP_MEDIA_CT_H263_P0 /* H.263 baseline (profile 0) */
+#define BTA_AV_CODEC_MPEG4 VDP_MEDIA_CT_MPEG4 /* MPEG-4 Visual Simple Profile */
+#define BTA_AV_CODEC_H263_P3 VDP_MEDIA_CT_H263_P3 /* H.263 profile 3 */
+#define BTA_AV_CODEC_H263_P8 VDP_MEDIA_CT_H263_P8 /* H.263 profile 8 */
+#define BTA_AV_CODEC_VEND VDP_MEDIA_CT_VEND /* Non-VDP */
+
+typedef UINT8 tBTA_AV_CODEC;
+
+/* Company ID in BT assigned numbers */
+#define BTA_AV_BT_VENDOR_ID VDP_BT_VENDOR_ID /* Broadcom Corporation */
+
+/* vendor specific codec ID */
+#define BTA_AV_CODEC_ID_H264 VDP_CODEC_ID_H264 /* Non-VDP codec ID - H.264 */
+#define BTA_AV_CODEC_ID_IMG VDP_CODEC_ID_IMG /* Non-VDP codec ID - images/slideshow */
+
+/* operation id list for BTA_AvRemoteCmd */
+#define BTA_AV_RC_SELECT AVRC_ID_SELECT /* select */
+#define BTA_AV_RC_UP AVRC_ID_UP /* up */
+#define BTA_AV_RC_DOWN AVRC_ID_DOWN /* down */
+#define BTA_AV_RC_LEFT AVRC_ID_LEFT /* left */
+#define BTA_AV_RC_RIGHT AVRC_ID_RIGHT /* right */
+#define BTA_AV_RC_RIGHT_UP AVRC_ID_RIGHT_UP /* right-up */
+#define BTA_AV_RC_RIGHT_DOWN AVRC_ID_RIGHT_DOWN /* right-down */
+#define BTA_AV_RC_LEFT_UP AVRC_ID_LEFT_UP /* left-up */
+#define BTA_AV_RC_LEFT_DOWN AVRC_ID_LEFT_DOWN /* left-down */
+#define BTA_AV_RC_ROOT_MENU AVRC_ID_ROOT_MENU /* root menu */
+#define BTA_AV_RC_SETUP_MENU AVRC_ID_SETUP_MENU /* setup menu */
+#define BTA_AV_RC_CONT_MENU AVRC_ID_CONT_MENU /* contents menu */
+#define BTA_AV_RC_FAV_MENU AVRC_ID_FAV_MENU /* favorite menu */
+#define BTA_AV_RC_EXIT AVRC_ID_EXIT /* exit */
+#define BTA_AV_RC_0 AVRC_ID_0 /* 0 */
+#define BTA_AV_RC_1 AVRC_ID_1 /* 1 */
+#define BTA_AV_RC_2 AVRC_ID_2 /* 2 */
+#define BTA_AV_RC_3 AVRC_ID_3 /* 3 */
+#define BTA_AV_RC_4 AVRC_ID_4 /* 4 */
+#define BTA_AV_RC_5 AVRC_ID_5 /* 5 */
+#define BTA_AV_RC_6 AVRC_ID_6 /* 6 */
+#define BTA_AV_RC_7 AVRC_ID_7 /* 7 */
+#define BTA_AV_RC_8 AVRC_ID_8 /* 8 */
+#define BTA_AV_RC_9 AVRC_ID_9 /* 9 */
+#define BTA_AV_RC_DOT AVRC_ID_DOT /* dot */
+#define BTA_AV_RC_ENTER AVRC_ID_ENTER /* enter */
+#define BTA_AV_RC_CLEAR AVRC_ID_CLEAR /* clear */
+#define BTA_AV_RC_CHAN_UP AVRC_ID_CHAN_UP /* channel up */
+#define BTA_AV_RC_CHAN_DOWN AVRC_ID_CHAN_DOWN /* channel down */
+#define BTA_AV_RC_PREV_CHAN AVRC_ID_PREV_CHAN /* previous channel */
+#define BTA_AV_RC_SOUND_SEL AVRC_ID_SOUND_SEL /* sound select */
+#define BTA_AV_RC_INPUT_SEL AVRC_ID_INPUT_SEL /* input select */
+#define BTA_AV_RC_DISP_INFO AVRC_ID_DISP_INFO /* display information */
+#define BTA_AV_RC_HELP AVRC_ID_HELP /* help */
+#define BTA_AV_RC_PAGE_UP AVRC_ID_PAGE_UP /* page up */
+#define BTA_AV_RC_PAGE_DOWN AVRC_ID_PAGE_DOWN /* page down */
+#define BTA_AV_RC_POWER AVRC_ID_POWER /* power */
+#define BTA_AV_RC_VOL_UP AVRC_ID_VOL_UP /* volume up */
+#define BTA_AV_RC_VOL_DOWN AVRC_ID_VOL_DOWN /* volume down */
+#define BTA_AV_RC_MUTE AVRC_ID_MUTE /* mute */
+#define BTA_AV_RC_PLAY AVRC_ID_PLAY /* play */
+#define BTA_AV_RC_STOP AVRC_ID_STOP /* stop */
+#define BTA_AV_RC_PAUSE AVRC_ID_PAUSE /* pause */
+#define BTA_AV_RC_RECORD AVRC_ID_RECORD /* record */
+#define BTA_AV_RC_REWIND AVRC_ID_REWIND /* rewind */
+#define BTA_AV_RC_FAST_FOR AVRC_ID_FAST_FOR /* fast forward */
+#define BTA_AV_RC_EJECT AVRC_ID_EJECT /* eject */
+#define BTA_AV_RC_FORWARD AVRC_ID_FORWARD /* forward */
+#define BTA_AV_RC_BACKWARD AVRC_ID_BACKWARD /* backward */
+#define BTA_AV_RC_ANGLE AVRC_ID_ANGLE /* angle */
+#define BTA_AV_RC_SUBPICT AVRC_ID_SUBPICT /* subpicture */
+#define BTA_AV_RC_F1 AVRC_ID_F1 /* F1 */
+#define BTA_AV_RC_F2 AVRC_ID_F2 /* F2 */
+#define BTA_AV_RC_F3 AVRC_ID_F3 /* F3 */
+#define BTA_AV_RC_F4 AVRC_ID_F4 /* F4 */
+#define BTA_AV_RC_F5 AVRC_ID_F5 /* F5 */
+#define BTA_AV_VENDOR AVRC_ID_VENDOR /* vendor unique */
+
+typedef UINT8 tBTA_AV_RC;
+
+/* state flag for pass through command */
+#define BTA_AV_STATE_PRESS AVRC_STATE_PRESS /* key pressed */
+#define BTA_AV_STATE_RELEASE AVRC_STATE_RELEASE /* key released */
+
+typedef UINT8 tBTA_AV_STATE;
+
+/* command codes for BTA_AvVendorCmd */
+#define BTA_AV_CMD_CTRL AVRC_CMD_CTRL
+#define BTA_AV_CMD_STATUS AVRC_CMD_STATUS
+#define BTA_AV_CMD_SPEC_INQ AVRC_CMD_SPEC_INQ
+#define BTA_AV_CMD_NOTIF AVRC_CMD_NOTIF
+#define BTA_AV_CMD_GEN_INQ AVRC_CMD_GEN_INQ
+
+typedef UINT8 tBTA_AV_CMD;
+
+/* response codes for BTA_AvVendorRsp */
+#define BTA_AV_RSP_NOT_IMPL AVRC_RSP_NOT_IMPL
+#define BTA_AV_RSP_ACCEPT AVRC_RSP_ACCEPT
+#define BTA_AV_RSP_REJ AVRC_RSP_REJ
+#define BTA_AV_RSP_IN_TRANS AVRC_RSP_IN_TRANS
+#define BTA_AV_RSP_IMPL_STBL AVRC_RSP_IMPL_STBL
+#define BTA_AV_RSP_CHANGED AVRC_RSP_CHANGED
+#define BTA_AV_RSP_INTERIM AVRC_RSP_INTERIM
+
+typedef UINT8 tBTA_AV_CODE;
+
+/* error codes for BTA_AvProtectRsp */
+#define BTA_AV_ERR_NONE A2D_SUCCESS /* Success, no error */
+#define BTA_AV_ERR_BAD_STATE AVDT_ERR_BAD_STATE /* Message cannot be processed in this state */
+#define BTA_AV_ERR_RESOURCE AVDT_ERR_RESOURCE /* Insufficient resources */
+#define BTA_AV_ERR_BAD_CP_TYPE A2D_BAD_CP_TYPE /* The requested Content Protection Type is not supported */
+#define BTA_AV_ERR_BAD_CP_FORMAT A2D_BAD_CP_FORMAT /* The format of Content Protection Data is not correct */
+
+typedef UINT8 tBTA_AV_ERR;
+
+
+/* AV callback events */
+#define BTA_AV_ENABLE_EVT 0 /* AV enabled */
+#define BTA_AV_REGISTER_EVT 1 /* registered to AVDT */
+#define BTA_AV_OPEN_EVT 2 /* connection opened */
+#define BTA_AV_CLOSE_EVT 3 /* connection closed */
+#define BTA_AV_START_EVT 4 /* stream data transfer started */
+#define BTA_AV_STOP_EVT 5 /* stream data transfer stopped */
+#define BTA_AV_PROTECT_REQ_EVT 6 /* content protection request */
+#define BTA_AV_PROTECT_RSP_EVT 7 /* content protection response */
+#define BTA_AV_RC_OPEN_EVT 8 /* remote control channel open */
+#define BTA_AV_RC_CLOSE_EVT 9 /* remote control channel closed */
+#define BTA_AV_REMOTE_CMD_EVT 10 /* remote control command */
+#define BTA_AV_REMOTE_RSP_EVT 11 /* remote control response */
+#define BTA_AV_VENDOR_CMD_EVT 12 /* vendor dependent remote control command */
+#define BTA_AV_VENDOR_RSP_EVT 13 /* vendor dependent remote control response */
+#define BTA_AV_RECONFIG_EVT 14 /* reconfigure response */
+#define BTA_AV_SUSPEND_EVT 15 /* suspend response */
+#define BTA_AV_PENDING_EVT 16 /* incoming connection pending:
+ * signal channel is open and stream is not open
+ * after BTA_AV_SIG_TIME_VAL ms */
+#define BTA_AV_META_MSG_EVT 17 /* metadata messages */
+#define BTA_AV_REJECT_EVT 18 /* incoming connection rejected */
+#define BTA_AV_RC_FEAT_EVT 19 /* remote control channel peer supported features update */
+
+typedef UINT8 tBTA_AV_EVT;
+
+/* Event associated with BTA_AV_ENABLE_EVT */
+typedef struct
+{
+ tBTA_AV_FEAT features;
+} tBTA_AV_ENABLE;
+
+/* Event associated with BTA_AV_REGISTER_EVT */
+typedef struct
+{
+ tBTA_AV_CHNL chnl; /* audio/video */
+ tBTA_AV_HNDL hndl; /* Handle associated with the stream. */
+ UINT8 app_id; /* ID associated with call to BTA_AvRegister() */
+ tBTA_AV_STATUS status;
+} tBTA_AV_REGISTER;
+
+/* data associated with BTA_AV_OPEN_EVT */
+#define BTA_AV_EDR_2MBPS 0x01
+#define BTA_AV_EDR_3MBPS 0x02
+typedef UINT8 tBTA_AV_EDR;
+
+typedef struct
+{
+ tBTA_AV_CHNL chnl;
+ tBTA_AV_HNDL hndl;
+ BD_ADDR bd_addr;
+ tBTA_AV_STATUS status;
+ BOOLEAN starting;
+ tBTA_AV_EDR edr; /* 0, if peer device does not support EDR */
+} tBTA_AV_OPEN;
+
+/* data associated with BTA_AV_CLOSE_EVT */
+typedef struct
+{
+ tBTA_AV_CHNL chnl;
+ tBTA_AV_HNDL hndl;
+} tBTA_AV_CLOSE;
+
+/* data associated with BTA_AV_START_EVT */
+typedef struct
+{
+ tBTA_AV_CHNL chnl;
+ tBTA_AV_HNDL hndl;
+ tBTA_AV_STATUS status;
+ BOOLEAN initiator; /* TRUE, if local device initiates the START */
+ BOOLEAN suspending;
+} tBTA_AV_START;
+
+/* data associated with BTA_AV_SUSPEND_EVT */
+typedef struct
+{
+ tBTA_AV_CHNL chnl;
+ tBTA_AV_HNDL hndl;
+ BOOLEAN initiator; /* TRUE, if local device initiates the SUSPEND */
+ tBTA_AV_STATUS status;
+} tBTA_AV_SUSPEND;
+
+/* data associated with BTA_AV_RECONFIG_EVT */
+typedef struct
+{
+ tBTA_AV_CHNL chnl;
+ tBTA_AV_HNDL hndl;
+ tBTA_AV_STATUS status;
+} tBTA_AV_RECONFIG;
+
+/* data associated with BTA_AV_PROTECT_REQ_EVT */
+typedef struct
+{
+ tBTA_AV_CHNL chnl;
+ tBTA_AV_HNDL hndl;
+ UINT8 *p_data;
+ UINT16 len;
+} tBTA_AV_PROTECT_REQ;
+
+/* data associated with BTA_AV_PROTECT_RSP_EVT */
+typedef struct
+{
+ tBTA_AV_CHNL chnl;
+ tBTA_AV_HNDL hndl;
+ UINT8 *p_data;
+ UINT16 len;
+ tBTA_AV_ERR err_code;
+} tBTA_AV_PROTECT_RSP;
+
+/* data associated with BTA_AV_RC_OPEN_EVT */
+typedef struct
+{
+ UINT8 rc_handle;
+ tBTA_AV_FEAT peer_features;
+ BD_ADDR peer_addr;
+ tBTA_AV_STATUS status;
+} tBTA_AV_RC_OPEN;
+
+/* data associated with BTA_AV_RC_CLOSE_EVT */
+typedef struct
+{
+ UINT8 rc_handle;
+ BD_ADDR peer_addr;
+} tBTA_AV_RC_CLOSE;
+
+/* data associated with BTA_AV_RC_FEAT_EVT */
+typedef struct
+{
+ UINT8 rc_handle;
+ tBTA_AV_FEAT peer_features;
+} tBTA_AV_RC_FEAT;
+
+/* data associated with BTA_AV_REMOTE_CMD_EVT */
+typedef struct
+{
+ UINT8 rc_handle;
+ tBTA_AV_RC rc_id;
+ tBTA_AV_STATE key_state;
+ UINT8 len;
+ UINT8 *p_data;
+ tAVRC_HDR hdr; /* Message header. */
+ UINT8 label;
+} tBTA_AV_REMOTE_CMD;
+
+/* data associated with BTA_AV_REMOTE_RSP_EVT */
+typedef struct
+{
+ UINT8 rc_handle;
+ tBTA_AV_RC rc_id;
+ tBTA_AV_STATE key_state;
+ UINT8 len;
+ UINT8 *p_data;
+ tBTA_AV_CODE rsp_code;
+ UINT8 label;
+} tBTA_AV_REMOTE_RSP;
+
+/* data associated with BTA_AV_VENDOR_CMD_EVT, BTA_AV_VENDOR_RSP_EVT */
+typedef struct
+{
+ UINT8 rc_handle;
+ UINT16 len; /* Max vendor dependent message is 512 */
+ UINT8 label;
+ tBTA_AV_CODE code;
+ UINT32 company_id;
+ UINT8 *p_data;
+} tBTA_AV_VENDOR;
+
+/* data associated with BTA_AV_META_MSG_EVT */
+typedef struct
+{
+ UINT8 rc_handle;
+ UINT16 len;
+ UINT8 label;
+ tBTA_AV_CODE code;
+ UINT32 company_id;
+ UINT8 *p_data;
+ tAVRC_MSG *p_msg;
+} tBTA_AV_META_MSG;
+
+/* data associated with BTA_AV_PENDING_EVT */
+typedef struct
+{
+ BD_ADDR bd_addr;
+} tBTA_AV_PEND;
+
+/* data associated with BTA_AV_REJECT_EVT */
+typedef struct
+{
+ BD_ADDR bd_addr;
+ tBTA_AV_HNDL hndl; /* Handle associated with the stream that rejected the connection. */
+} tBTA_AV_REJECT;
+
+
+/* union of data associated with AV callback */
+typedef union
+{
+ tBTA_AV_CHNL chnl;
+ tBTA_AV_ENABLE enable;
+ tBTA_AV_REGISTER registr;
+ tBTA_AV_OPEN open;
+ tBTA_AV_CLOSE close;
+ tBTA_AV_START start;
+ tBTA_AV_PROTECT_REQ protect_req;
+ tBTA_AV_PROTECT_RSP protect_rsp;
+ tBTA_AV_RC_OPEN rc_open;
+ tBTA_AV_RC_CLOSE rc_close;
+ tBTA_AV_REMOTE_CMD remote_cmd;
+ tBTA_AV_REMOTE_RSP remote_rsp;
+ tBTA_AV_VENDOR vendor_cmd;
+ tBTA_AV_VENDOR vendor_rsp;
+ tBTA_AV_RECONFIG reconfig;
+ tBTA_AV_SUSPEND suspend;
+ tBTA_AV_PEND pend;
+ tBTA_AV_META_MSG meta_msg;
+ tBTA_AV_REJECT reject;
+ tBTA_AV_RC_FEAT rc_feat;
+} tBTA_AV;
+
+
+#define BTA_AVC_PACKET_LEN AVRC_PACKET_LEN
+#define BTA_VENDOR_DATA_OFFSET 6
+#define BTA_VENDOR_HEADER_LEN 4
+#define BTA_MAX_VENDOR_DEPENDENT_DATA_LEN (BTA_AVC_PACKET_LEN-BTA_VENDOR_DATA_OFFSET-BTA_VENDOR_HEADER_LEN)
+#define BTA_GROUP_NAVI_MSG_OP_DATA_LEN 5
+
+#define BTA_ERROR_INVALID_CMD AVRC_STS_BAD_CMD
+#define BTA_ERROR_INVALID_PARAM AVRC_STS_BAD_PARAM
+#define BTA_ERROR_BAD_CONTENTS AVRC_STS_NOT_FOUND
+#define BTA_ERROR_INTERNAL AVRC_STS_INTERNAL_ERR
+
+#define BTA_AV_META_SINGLE_PACKET AVRC_PKT_SINGLE
+
+#define BTA_AV_CO_METADATA AVRC_CO_METADATA
+
+/* AV callback */
+typedef void (tBTA_AV_CBACK)(tBTA_AV_EVT event, tBTA_AV *p_data);
+
+/* type for stream state machine action functions */
+typedef void (*tBTA_AV_ACT)(void *p_cb, void *p_data);
+
+/* type for registering VDP */
+typedef void (tBTA_AV_REG) (tAVDT_CS *p_cs, char *p_service_name, void *p_data);
+
+/* AV configuration structure */
+typedef struct
+{
+ UINT32 company_id; /* AVRCP Company ID */
+ UINT16 avrc_mtu; /* AVRCP MTU at L2CAP for control channel */
+ UINT16 avrc_br_mtu; /* AVRCP MTU at L2CAP for browsing channel */
+ UINT16 avrc_ct_cat; /* AVRCP controller categories */
+ UINT16 avrc_tg_cat; /* AVRCP target categories */
+ UINT16 sig_mtu; /* AVDTP signaling channel MTU at L2CAP */
+ UINT16 audio_mtu; /* AVDTP audio transport channel MTU at L2CAP */
+ const UINT16 *p_audio_flush_to;/* AVDTP audio transport channel flush timeout */
+ UINT16 audio_mqs; /* AVDTP audio channel max data queue size */
+ UINT16 video_mtu; /* AVDTP video transport channel MTU at L2CAP */
+ UINT16 video_flush_to; /* AVDTP video transport channel flush timeout */
+ BOOLEAN avrc_group; /* TRUE, to accept AVRC 1.3 group nevigation command */
+ UINT8 num_co_ids; /* company id count in p_meta_co_ids */
+ UINT8 num_evt_ids; /* event id count in p_meta_evt_ids */
+ tBTA_AV_CODE rc_pass_rsp; /* the default response code for pass through commands */
+ const UINT32 *p_meta_co_ids;/* the metadata Get Capabilities response for company id */
+ const UINT8 *p_meta_evt_ids;/* the the metadata Get Capabilities response for event id */
+ const tBTA_AV_ACT *p_act_tbl;/* the action function table for VDP stream */
+ tBTA_AV_REG *p_reg; /* action function to register VDP */
+} tBTA_AV_CFG;
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*****************************************************************************
+** External Function Declarations
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function BTA_AvEnable
+**
+** Description Enable the advanced audio/video service. When the enable
+** operation is complete the callback function will be
+** called with a BTA_AV_ENABLE_EVT. This function must
+** be called before other function in the AV API are
+** called.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API void BTA_AvEnable(tBTA_SEC sec_mask, tBTA_AV_FEAT features,
+ tBTA_AV_CBACK *p_cback);
+
+/*******************************************************************************
+**
+** Function BTA_AvDisable
+**
+** Description Disable the advanced audio/video service.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API void BTA_AvDisable(void);
+
+/*******************************************************************************
+**
+** Function BTA_AvRegister
+**
+** Description Register the audio or video service to stack. When the
+** operation is complete the callback function will be
+** called with a BTA_AV_REGISTER_EVT. This function must
+** be called before AVDT stream is open.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API void BTA_AvRegister(tBTA_AV_CHNL chnl, const char *p_service_name,
+ UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function BTA_AvDeregister
+**
+** Description Deregister the audio or video service
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API void BTA_AvDeregister(tBTA_AV_HNDL hndl);
+
+/*******************************************************************************
+**
+** Function BTA_AvOpen
+**
+** Description Opens an advanced audio/video connection to a peer device.
+** When connection is open callback function is called
+** with a BTA_AV_OPEN_EVT.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API void BTA_AvOpen(BD_ADDR bd_addr, tBTA_AV_HNDL handle,
+ BOOLEAN use_rc, tBTA_SEC sec_mask);
+
+/*******************************************************************************
+**
+** Function BTA_AvClose
+**
+** Description Close the current streams.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API void BTA_AvClose(tBTA_AV_HNDL handle);
+
+/*******************************************************************************
+**
+** Function BTA_AvDisconnect
+**
+** Description Close the connection to the address.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API void BTA_AvDisconnect(BD_ADDR bd_addr);
+
+/*******************************************************************************
+**
+** Function BTA_AvStart
+**
+** Description Start audio/video stream data transfer.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API void BTA_AvStart(void);
+
+/*******************************************************************************
+**
+** Function BTA_AvStop
+**
+** Description Stop audio/video stream data transfer.
+** If suspend is TRUE, this function sends AVDT suspend signal
+** to the connected peer(s).
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API void BTA_AvStop(BOOLEAN suspend);
+
+/*******************************************************************************
+**
+** Function BTA_AvReconfig
+**
+** Description Reconfigure the audio/video stream.
+** If suspend is TRUE, this function tries the suspend/reconfigure
+** procedure first.
+** If suspend is FALSE or when suspend/reconfigure fails,
+** this function closes and re-opens the AVDT connection.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API void BTA_AvReconfig(tBTA_AV_HNDL hndl, BOOLEAN suspend, UINT8 sep_info_idx,
+ UINT8 *p_codec_info, UINT8 num_protect, UINT8 *p_protect_info);
+
+/*******************************************************************************
+**
+** Function BTA_AvProtectReq
+**
+** Description Send a content protection request. This function can only
+** be used if AV is enabled with feature BTA_AV_FEAT_PROTECT.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API void BTA_AvProtectReq(tBTA_AV_HNDL hndl, UINT8 *p_data, UINT16 len);
+
+/*******************************************************************************
+**
+** Function BTA_AvProtectRsp
+**
+** Description Send a content protection response. This function must
+** be called if a BTA_AV_PROTECT_REQ_EVT is received.
+** This function can only be used if AV is enabled with
+** feature BTA_AV_FEAT_PROTECT.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API void BTA_AvProtectRsp(tBTA_AV_HNDL hndl, UINT8 error_code, UINT8 *p_data,
+ UINT16 len);
+
+/*******************************************************************************
+**
+** Function BTA_AvRemoteCmd
+**
+** Description Send a remote control command. This function can only
+** be used if AV is enabled with feature BTA_AV_FEAT_RCCT.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API void BTA_AvRemoteCmd(UINT8 rc_handle, UINT8 label, tBTA_AV_RC rc_id,
+ tBTA_AV_STATE key_state);
+
+/*******************************************************************************
+**
+** Function BTA_AvVendorCmd
+**
+** Description Send a vendor dependent remote control command. This
+** function can only be used if AV is enabled with feature
+** BTA_AV_FEAT_VENDOR.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API void BTA_AvVendorCmd(UINT8 rc_handle, UINT8 label, tBTA_AV_CODE cmd_code,
+ UINT8 *p_data, UINT16 len);
+
+/*******************************************************************************
+**
+** Function BTA_AvVendorRsp
+**
+** Description Send a vendor dependent remote control response.
+** This function must be called if a BTA_AV_VENDOR_CMD_EVT
+** is received. This function can only be used if AV is
+** enabled with feature BTA_AV_FEAT_VENDOR.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API void BTA_AvVendorRsp(UINT8 rc_handle, UINT8 label, tBTA_AV_CODE rsp_code,
+ UINT8 *p_data, UINT16 len, UINT32 company_id);
+
+
+/*******************************************************************************
+**
+** Function BTA_AvOpenRc
+**
+** Description Open an AVRCP connection toward the device with the
+** specified handle
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API void BTA_AvOpenRc(tBTA_AV_HNDL handle);
+
+/*******************************************************************************
+**
+** Function BTA_AvCloseRc
+**
+** Description Close an AVRCP connection
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API void BTA_AvCloseRc(UINT8 rc_handle);
+
+/*******************************************************************************
+**
+** Function BTA_AvMetaRsp
+**
+** Description Send a Metadata command/response. The message contained
+** in p_pkt can be composed with AVRC utility functions.
+** This function can only be used if AV is enabled with feature
+** BTA_AV_FEAT_METADATA.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API void BTA_AvMetaRsp(UINT8 rc_handle, UINT8 label, tBTA_AV_CODE rsp_code,
+ BT_HDR *p_pkt);
+
+/*******************************************************************************
+**
+** Function BTA_AvMetaCmd
+**
+** Description Send a Metadata/Advanced Control command. The message contained
+** in p_pkt can be composed with AVRC utility functions.
+** This function can only be used if AV is enabled with feature
+** BTA_AV_FEAT_METADATA.
+** This message is sent only when the peer supports the TG role.
+*8 The only command makes sense right now is the absolute volume command.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API void BTA_AvMetaCmd(UINT8 rc_handle, UINT8 label, tBTA_AV_CMD cmd_code, BT_HDR *p_pkt);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_AV_API_H */
diff --git a/bta/include/bta_av_ci.h b/bta/include/bta_av_ci.h
new file mode 100644
index 0000000..c09e5e9
--- /dev/null
+++ b/bta/include/bta_av_ci.h
@@ -0,0 +1,62 @@
+/*****************************************************************************
+**
+** Name: bta_av_ci.h
+**
+** Description: This is the interface file for advanced audio/video call-in
+** functions.
+**
+** Copyright (c) 2005, Widcomm Inc., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_AV_CI_H
+#define BTA_AV_CI_H
+
+#include "bta_av_api.h"
+
+/*****************************************************************************
+** Function Declarations
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*******************************************************************************
+**
+** Function bta_av_ci_src_data_ready
+**
+** Description This function sends an event to the AV indicating that
+** the phone has audio stream data ready to send and AV
+** should call bta_av_co_audio_src_data_path() or
+** bta_av_co_video_src_data_path().
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_av_ci_src_data_ready(tBTA_AV_CHNL chnl);
+
+/*******************************************************************************
+**
+** Function bta_av_ci_setconfig
+**
+** Description This function must be called in response to function
+** bta_av_co_audio_setconfig() or bta_av_co_video_setconfig.
+** Parameter err_code is set to an AVDTP status value;
+** AVDT_SUCCESS if the codec configuration is ok,
+** otherwise error.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_av_ci_setconfig(tBTA_AV_HNDL hndl, UINT8 err_code,
+ UINT8 category, UINT8 num_seid, UINT8 *p_seid,
+ BOOLEAN recfg_needed);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_AV_CI_H */
+
diff --git a/bta/include/bta_av_co.h b/bta/include/bta_av_co.h
new file mode 100644
index 0000000..2f41180
--- /dev/null
+++ b/bta/include/bta_av_co.h
@@ -0,0 +1,400 @@
+/*****************************************************************************
+**
+** Name: bta_av_co.h
+**
+** Description: This is the interface file for advanced audio/video call-out
+** functions.
+**
+** Copyright (c) 2003, Widcomm Inc., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_AV_CO_H
+#define BTA_AV_CO_H
+
+#include "l2c_api.h"
+#include "bta_av_api.h"
+
+/*****************************************************************************
+** Constants and data types
+*****************************************************************************/
+
+/* TRUE to use SCMS-T content protection */
+#ifndef BTA_AV_CO_CP_SCMS_T
+#define BTA_AV_CO_CP_SCMS_T FALSE
+#endif
+
+/* the content protection IDs assigned by BT SIG */
+#define BTA_AV_CP_SCMS_T_ID 0x0002
+#define BTA_AV_CP_DTCP_ID 0x0001
+
+#define BTA_AV_CP_LOSC 2
+#define BTA_AV_CP_INFO_LEN 3
+
+#define BTA_AV_CP_SCMS_COPY_MASK 3
+#define BTA_AV_CP_SCMS_COPY_FREE 2
+#define BTA_AV_CP_SCMS_COPY_ONCE 1
+#define BTA_AV_CP_SCMS_COPY_NEVER 0
+
+#define BTA_AV_CO_DEFAULT_AUDIO_OFFSET AVDT_MEDIA_OFFSET
+
+enum
+{
+ BTA_AV_CO_ST_INIT,
+ BTA_AV_CO_ST_IN,
+ BTA_AV_CO_ST_OUT,
+ BTA_AV_CO_ST_OPEN,
+ BTA_AV_CO_ST_STREAM
+};
+
+/* data type for the Video Codec Information Element*/
+typedef struct
+{
+ UINT8 codec_type; /* Codec type */
+ UINT8 levels; /* level mask */
+} tBTA_AV_VIDEO_CFG;
+
+/* data type for the Audio Codec Information*/
+typedef struct
+{
+ UINT16 bit_rate; /* SBC encoder bit rate in kbps */
+ UINT16 bit_rate_busy; /* SBC encoder bit rate in kbps */
+ UINT16 bit_rate_swampd;/* SBC encoder bit rate in kbps */
+ UINT8 busy_level; /* Busy level indicating the bit-rate to be used */
+ UINT8 codec_info[AVDT_CODEC_SIZE];
+ UINT8 codec_type; /* Codec type */
+} tBTA_AV_AUDIO_CODEC_INFO;
+
+/*******************************************************************************
+**
+** Function bta_av_co_audio_init
+**
+** Description This callout function is executed by AV when it is
+** started by calling BTA_AvEnable(). This function can be
+** used by the phone to initialize audio paths or for other
+** initialization purposes.
+**
+**
+** Returns Stream codec and content protection capabilities info.
+**
+*******************************************************************************/
+BTA_API extern BOOLEAN bta_av_co_audio_init(UINT8 *p_codec_type, UINT8 *p_codec_info,
+ UINT8 *p_num_protect, UINT8 *p_protect_info, UINT8 index);
+
+/*******************************************************************************
+**
+** Function bta_av_co_video_init
+**
+** Description This callout function is executed by AV when it is
+** started by calling BTA_AvEnable(). This function can be
+** used by the phone to initialize video paths or for other
+** initialization purposes.
+**
+**
+** Returns Stream codec and content protection capabilities info.
+**
+*******************************************************************************/
+BTA_API extern BOOLEAN bta_av_co_video_init(UINT8 *p_codec_type, UINT8 *p_codec_info,
+ UINT8 *p_num_protect, UINT8 *p_protect_info, UINT8 index);
+
+/*******************************************************************************
+**
+** Function bta_av_co_audio_disc_res
+**
+** Description This callout function is executed by AV to report the
+** number of stream end points (SEP) were found during the
+** AVDT stream discovery process.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+BTA_API extern void bta_av_co_audio_disc_res(tBTA_AV_HNDL hndl, UINT8 num_seps,
+ UINT8 num_snk, BD_ADDR addr);
+
+/*******************************************************************************
+**
+** Function bta_av_co_video_disc_res
+**
+** Description This callout function is executed by AV to report the
+** number of stream end points (SEP) were found during the
+** AVDT stream discovery process.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+BTA_API extern void bta_av_co_video_disc_res(tBTA_AV_HNDL hndl, UINT8 num_seps,
+ UINT8 num_snk, BD_ADDR addr);
+
+/*******************************************************************************
+**
+** Function bta_av_co_audio_getconfig
+**
+** Description This callout function is executed by AV to retrieve the
+** desired codec and content protection configuration for the
+** audio stream.
+**
+**
+** Returns Stream codec and content protection configuration info.
+**
+*******************************************************************************/
+BTA_API extern UINT8 bta_av_co_audio_getconfig(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type,
+ UINT8 *p_codec_info, UINT8 *p_sep_info_idx, UINT8 seid,
+ UINT8 *p_num_protect, UINT8 *p_protect_info);
+
+/*******************************************************************************
+**
+** Function bta_av_co_video_getconfig
+**
+** Description This callout function is executed by AV to retrieve the
+** desired codec and content protection configuration for the
+** video stream.
+**
+**
+** Returns Stream codec and content protection configuration info.
+**
+*******************************************************************************/
+BTA_API extern UINT8 bta_av_co_video_getconfig(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type,
+ UINT8 *p_codec_info, UINT8 *p_sep_info_idx, UINT8 seid,
+ UINT8 *p_num_protect, UINT8 *p_protect_info);
+
+/*******************************************************************************
+**
+** Function bta_av_co_audio_setconfig
+**
+** Description This callout function is executed by AV to set the
+** codec and content protection configuration of the audio stream.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_av_co_audio_setconfig(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type,
+ UINT8 *p_codec_info, UINT8 seid, BD_ADDR addr,
+ UINT8 num_protect, UINT8 *p_protect_info);
+
+/*******************************************************************************
+**
+** Function bta_av_co_video_setconfig
+**
+** Description This callout function is executed by AV to set the
+** codec and content protection configuration of the video stream.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_av_co_video_setconfig(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type,
+ UINT8 *p_codec_info, UINT8 seid, BD_ADDR addr,
+ UINT8 num_protect, UINT8 *p_protect_info);
+
+/*******************************************************************************
+**
+** Function bta_av_co_audio_open
+**
+** Description This function is called by AV when the audio stream connection
+** is opened.
+** BTA-AV maintains the MTU of A2DP streams.
+** If this is the 2nd audio stream, mtu is the smaller of the 2
+** streams.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_av_co_audio_open(tBTA_AV_HNDL hndl,
+ tBTA_AV_CODEC codec_type, UINT8 *p_codec_info,
+ UINT16 mtu);
+
+/*******************************************************************************
+**
+** Function bta_av_co_video_open
+**
+** Description This function is called by AV when the video stream connection
+** is opened.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_av_co_video_open(tBTA_AV_HNDL hndl,
+ tBTA_AV_CODEC codec_type, UINT8 *p_codec_info,
+ UINT16 mtu);
+
+/*******************************************************************************
+**
+** Function bta_av_co_audio_close
+**
+** Description This function is called by AV when the audio stream connection
+** is closed.
+** BTA-AV maintains the MTU of A2DP streams.
+** When one stream is closed and no other audio stream is open,
+** mtu is reported as 0.
+** Otherwise, the MTU remains open is reported.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_av_co_audio_close(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type,
+ UINT16 mtu);
+
+/*******************************************************************************
+**
+** Function bta_av_co_video_close
+**
+** Description This function is called by AV when the video stream connection
+** is closed.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_av_co_video_close(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type,
+ UINT16 mtu);
+
+/*******************************************************************************
+**
+** Function bta_av_co_audio_start
+**
+** Description This function is called by AV when the audio streaming data
+** transfer is started.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_av_co_audio_start(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type);
+
+/*******************************************************************************
+**
+** Function bta_av_co_video_start
+**
+** Description This function is called by AV when the video streaming data
+** transfer is started.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_av_co_video_start(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type);
+
+/*******************************************************************************
+**
+** Function bta_av_co_audio_stop
+**
+** Description This function is called by AV when the audio streaming data
+** transfer is stopped.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_av_co_audio_stop(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type);
+
+/*******************************************************************************
+**
+** Function bta_av_co_video_stop
+**
+** Description This function is called by AV when the video streaming data
+** transfer is stopped.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_av_co_video_stop(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type);
+
+/*******************************************************************************
+**
+** Function bta_av_co_audio_src_data_path
+**
+** Description This function is called to get the next data buffer from
+** the audio codec
+**
+** Returns NULL if data is not ready.
+** Otherwise, a GKI buffer (BT_HDR*) containing the audio data.
+**
+*******************************************************************************/
+BTA_API extern void * bta_av_co_audio_src_data_path(tBTA_AV_CODEC codec_type,
+ UINT32 *p_len, UINT32 *p_timestamp);
+
+/*******************************************************************************
+**
+** Function bta_av_co_video_src_data_path
+**
+** Description This function is called to get the next data buffer from
+** the video codec.
+**
+** Returns NULL if data is not ready.
+** Otherwise, a video data buffer (UINT8*).
+**
+*******************************************************************************/
+BTA_API extern void * bta_av_co_video_src_data_path(tBTA_AV_CODEC codec_type,
+ UINT32 *p_len, UINT32 *p_timestamp);
+
+/*******************************************************************************
+**
+** Function bta_av_co_audio_drop
+**
+** Description An Audio packet is dropped. .
+** It's very likely that the connected headset with this handle
+** is moved far away. The implementation may want to reduce
+** the encoder bit rate setting to reduce the packet size.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_av_co_audio_drop(tBTA_AV_HNDL hndl);
+
+/*******************************************************************************
+**
+** Function bta_av_co_video_report_conn
+**
+** Description This function is called by AV when the reporting channel is
+** opened (open=TRUE) or closed (open=FALSE).
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_av_co_video_report_conn (BOOLEAN open, UINT8 avdt_handle);
+
+/*******************************************************************************
+**
+** Function bta_av_co_video_report_rr
+**
+** Description This function is called by AV when a Receiver Report is
+** received
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_av_co_video_report_rr (UINT32 packet_lost);
+
+/*******************************************************************************
+**
+** Function bta_av_co_audio_delay
+**
+** Description This function is called by AV when the audio stream connection
+** needs to send the initial delay report to the connected SRC.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_av_co_audio_delay(tBTA_AV_HNDL hndl, UINT16 delay);
+
+/*******************************************************************************
+**
+** Function bta_av_co_video_delay
+**
+** Description This function is called by AV when the video stream connection
+** needs to send the initial delay report to the connected SRC.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_av_co_video_delay(tBTA_AV_HNDL hndl, UINT16 delay);
+
+#endif /* BTA_AV_CO_H */
+
diff --git a/bta/include/bta_dg_api.h b/bta/include/bta_dg_api.h
new file mode 100644
index 0000000..3e8b2db
--- /dev/null
+++ b/bta/include/bta_dg_api.h
@@ -0,0 +1,198 @@
+/*****************************************************************************
+**
+** Name: bta_dg_api.h
+**
+** Description: This is the public interface file for the data gateway
+** (DG) subsystem of BTA, Widcomm's Bluetooth application
+** layer for mobile phones.
+**
+** Copyright (c) 2003, Widcomm Inc., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_DG_API_H
+#define BTA_DG_API_H
+
+#include "bta_api.h"
+
+/*****************************************************************************
+** Constants and data types
+*****************************************************************************/
+
+/* DG Callback events */
+#define BTA_DG_ENABLE_EVT 0 /* DG service is enabled. */
+#define BTA_DG_LISTEN_EVT 1 /* Server listen is started. */
+#define BTA_DG_OPENING_EVT 2 /* Client connection opening. */
+#define BTA_DG_OPEN_EVT 3 /* Connection has been opened. */
+#define BTA_DG_CLOSE_EVT 4 /* Connection has been closed. */
+
+typedef UINT8 tBTA_DG_EVT;
+
+/* Event associated with BTA_DG_LISTEN_EVT */
+typedef struct
+{
+ UINT16 handle; /* Handle associated with this server. */
+ UINT8 app_id; /* ID associated with call to BTA_DgListen(). */
+} tBTA_DG_LISTEN;
+
+/* Event associated with BTA_DG_OPENING_EVT */
+typedef struct
+{
+ UINT16 handle; /* Handle associated with this server. */
+ UINT8 app_id; /* ID associated with call to BTA_DgListen(). */
+} tBTA_DG_OPENING;
+
+
+/* Event associated with BTA_DG_OPEN_EVT */
+typedef struct
+{
+ BD_ADDR bd_addr; /* BD address of peer device. */
+ UINT16 handle; /* Handle associated with this server. */
+ tBTA_SERVICE_ID service; /* Service ID of opened service. */
+ UINT8 app_id; /* ID associated with call to BTA_DgListen(). */
+} tBTA_DG_OPEN;
+
+/* Event associated with BTA_DG_CLOSE_EVT */
+typedef struct
+{
+ UINT16 handle; /* Handle associated with this server. */
+ UINT8 app_id; /* ID associated with call to BTA_DgListen(). */
+} tBTA_DG_CLOSE;
+
+/* Union of all DG callback structures */
+typedef union
+{
+ tBTA_DG_LISTEN listen; /* Server listen is started. */
+ tBTA_DG_OPENING opening; /* Client connection opening. */
+ tBTA_DG_OPEN open; /* Connection has been opened. */
+ tBTA_DG_CLOSE close; /* Connection has been closed. */
+} tBTA_DG;
+
+/* DG callback */
+typedef void (tBTA_DG_CBACK)(tBTA_DG_EVT event, tBTA_DG *p_data);
+
+/* configuration structure */
+typedef struct
+{
+ UINT16 mtu[4]; /* MTU for SPP, DUN, FAX, LAP */
+
+} tBTA_DG_CFG;
+
+/* Number of DG servers */
+#ifndef BTA_DG_NUM_CONN
+#define BTA_DG_NUM_CONN 5
+#endif
+
+/*****************************************************************************
+** External Function Declarations
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*******************************************************************************
+**
+** Function BTA_DgEnable
+**
+** Description Enable the data gateway service. This function must be
+** called before any other functions in the DG API are called.
+** When the enable operation is complete the callback function
+** will be called with a BTA_DG_ENABLE_EVT. After the DG
+** service is enabled a server can be started by calling
+** BTA_DgListen().
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_DgEnable(tBTA_DG_CBACK *p_cback);
+
+/*******************************************************************************
+**
+** Function BTA_DgDisable
+**
+** Description Disable the data gateway service. Before calling this
+** function all DG servers must be shut down by calling
+** BTA_DgShutdown().
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_DgDisable(void);
+
+/*******************************************************************************
+**
+** Function BTA_DgListen
+**
+** Description Create a DG server for DUN, FAX or SPP. After creating a
+** server peer devices can open an RFCOMM connection to the
+** server. When the listen operation has started the callback
+** function will be called with a BTA_DG_LISTEN_EVT providing
+** the handle associated with this server. The handle
+** identifies server when calling other DG functions such as
+** BTA_DgClose() or BTA_DgShutdown().
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_DgListen(tBTA_SERVICE_ID service, tBTA_SEC sec_mask,
+ char *p_service_name, UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function BTA_DgOpen
+**
+** Description Open a DG client connection to a peer device. BTA first
+** searches for the requested service on the peer device. If
+** the service name is specified it will also match the
+** service name. Then BTA initiates an RFCOMM connection to
+** the peer device. The handle associated with the connection
+** is returned with the BTA_DG_OPEN_EVT. If the connection
+** fails or closes at any time the callback function will be
+** called with a BTA_DG_CLOSE_EVT.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_DgOpen(BD_ADDR bd_addr, tBTA_SERVICE_ID service,
+ tBTA_SEC sec_mask, char *p_service_name, UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function BTA_DgClose
+**
+** Description Close a DG connection to a peer device. BTA will
+** close the RFCOMM connection to the peer device. Servers
+** will still be listening for subsequent connections.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_DgClose(UINT16 handle);
+
+/*******************************************************************************
+**
+** Function BTA_DgShutdown
+**
+** Description Shutdown a DG server previously started by calling
+** BTA_DgListen(). The server will no longer be available
+** to peer devices. If there is currently a connection open
+** to the server it will be closed.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_DgShutdown(UINT16 handle);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_DG_API_H */
+
diff --git a/bta/include/bta_dg_ci.h b/bta/include/bta_dg_ci.h
new file mode 100644
index 0000000..1f52ab2
--- /dev/null
+++ b/bta/include/bta_dg_ci.h
@@ -0,0 +1,107 @@
+/*****************************************************************************
+**
+** Name: bta_dg_ci.h
+**
+** Description: This is the interface file for data gateway call-in
+** functions.
+**
+** Copyright (c) 2003, Widcomm Inc., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_DG_CI_H
+#define BTA_DG_CI_H
+
+#include "bta_dg_api.h"
+
+/*****************************************************************************
+** Function Declarations
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*******************************************************************************
+**
+** Function bta_dg_ci_tx_ready
+**
+** Description This function sends an event to DG indicating the phone is
+** ready for more data and DG should call bta_dg_co_tx_path().
+** This function is used when the TX data path is configured
+** to use a pull interface.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_dg_ci_tx_ready(UINT16 handle);
+
+/*******************************************************************************
+**
+** Function bta_dg_ci_rx_ready
+**
+** Description This function sends an event to DG indicating the phone
+** has data available to send to DG and DG should call
+** bta_dg_co_rx_path(). This function is used when the RX
+** data path is configured to use a pull interface.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_dg_ci_rx_ready(UINT16 handle);
+
+/*******************************************************************************
+**
+** Function bta_dg_ci_tx_flow
+**
+** Description This function is called to enable or disable data flow on
+** the TX path. The phone should call this function to
+** disable data flow when it is congested and cannot handle
+** any more data sent by bta_dg_co_tx_write() or
+** bta_dg_co_tx_writebuf(). This function is used when the
+** TX data path is configured to use a push interface.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_dg_ci_tx_flow(UINT16 handle, BOOLEAN enable);
+
+/*******************************************************************************
+**
+** Function bta_dg_ci_rx_writebuf
+**
+** Description This function is called to send data to the phone when
+** the RX path is configured to use a push interface with
+** zero copy. The function sends an event to DG containing
+** the data buffer. The buffer must be allocated using
+** functions GKI_getbuf() or GKI_getpoolbuf(). The buffer
+** will be freed by BTA; the phone must not free the buffer.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_dg_ci_rx_writebuf(UINT16 handle, BT_HDR *p_buf);
+
+/*******************************************************************************
+**
+** Function bta_dg_ci_control
+**
+** Description This function is called to send RS-232 signal information
+** to DG to be propagated over RFCOMM.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_dg_ci_control(UINT16 handle, UINT8 signals, UINT8 values);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_DG_CI_H */
+
diff --git a/bta/include/bta_dg_co.h b/bta/include/bta_dg_co.h
new file mode 100644
index 0000000..667a01c
--- /dev/null
+++ b/bta/include/bta_dg_co.h
@@ -0,0 +1,198 @@
+/*****************************************************************************
+**
+** Name: bta_dg_co.h
+**
+** Description: This is the interface file for data gateway call-out
+** functions.
+**
+** Copyright (c) 2003, Widcomm Inc., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_DG_CO_H
+#define BTA_DG_CO_H
+
+#include "bta_dg_api.h"
+#include "l2c_api.h"
+#include "rfcdefs.h"
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+/* RS-232 Signal Mask */
+#define BTA_DG_DTRDSR 0x01 /* DTR/DSR signal. */
+#define BTA_DG_RTSCTS 0x02 /* RTS/CTS signal. */
+#define BTA_DG_RI 0x04 /* Ring indicator signal. */
+#define BTA_DG_CD 0x08 /* Carrier detect signal. */
+
+/* RS-232 Signal Values */
+#define BTA_DG_DTRDSR_ON 0x01 /* DTR/DSR signal on. */
+#define BTA_DG_DTRDSR_OFF 0x00 /* DTR/DSR signal off. */
+#define BTA_DG_RTSCTS_ON 0x02 /* RTS/CTS signal on. */
+#define BTA_DG_RTSCTS_OFF 0x00 /* RTS/CTS signal off. */
+#define BTA_DG_RI_ON 0x04 /* Ring indicator signal on. */
+#define BTA_DG_RI_OFF 0x00 /* Ring indicator signal off. */
+#define BTA_DG_CD_ON 0x08 /* Carrier detect signal on. */
+#define BTA_DG_CD_OFF 0x00 /* Carrier detect signal off. */
+
+/* Data Flow Mask */
+#define BTA_DG_RX_PUSH_BUF 0x01 /* RX push with zero copy. */
+#define BTA_DG_RX_PULL 0x02 /* RX pull. */
+#define BTA_DG_TX_PUSH 0x00 /* TX push. */
+#define BTA_DG_TX_PUSH_BUF 0x10 /* TX push with zero copy. */
+#define BTA_DG_TX_PULL 0x20 /* TX pull. */
+
+/* BT_HDR buffer offset */
+#define BTA_DG_MIN_OFFSET (L2CAP_MIN_OFFSET + RFCOMM_MIN_OFFSET)
+
+/*****************************************************************************
+** Function Declarations
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function bta_dg_co_init
+**
+** Description This callout function is executed by DG when a server is
+** started by calling BTA_DgListen(). This function can be
+** used by the phone to initialize data paths or for other
+** initialization purposes. The function must return the
+** data flow mask as described below.
+**
+**
+** Returns Data flow mask.
+**
+*******************************************************************************/
+BTA_API extern UINT8 bta_dg_co_init(UINT16 handle, UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function bta_dg_co_open
+**
+** Description This function is executed by DG when a connection to a
+** server is opened. The phone can use this function to set
+** up data paths or perform any required initialization or
+** set up particular to the connected service.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_dg_co_open(UINT16 handle, UINT8 app_id, tBTA_SERVICE_ID service, UINT16 mtu);
+
+/*******************************************************************************
+**
+** Function bta_dg_co_close
+**
+** Description This function is called by DG when a connection to a
+** server is closed.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_dg_co_close(UINT16 handle, UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function bta_dg_co_tx_path
+**
+** Description This function is called by DG to transfer data on the
+** TX path; that is, data being sent from BTA to the phone.
+** This function is used when the TX data path is configured
+** to use the pull interface. The implementation of this
+** function will typically call Bluetooth stack functions
+** PORT_Read() or PORT_ReadData() to read data from RFCOMM
+** and then a platform-specific function to send data that
+** data to the phone.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_dg_co_tx_path(UINT16 handle, UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function bta_dg_co_rx_path
+**
+** Description This function is called by DG to transfer data on the
+** RX path; that is, data being sent from the phone to BTA.
+** This function is used when the RX data path is configured
+** to use the pull interface. The implementation of this
+** function will typically call a platform-specific function
+** to read data from the phone and then call Bluetooth stack
+** functions PORT_Write() or PORT_WriteData() to send data
+** to RFCOMM.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_dg_co_rx_path(UINT16 handle, UINT8 app_id, UINT16 mtu);
+
+/*******************************************************************************
+**
+** Function bta_dg_co_tx_write
+**
+** Description This function is called by DG to send data to the phone
+** when the TX path is configured to use a push interface.
+** The implementation of this function must copy the data to
+** the phone's memory.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_dg_co_tx_write(UINT16 handle, UINT8 app_id, UINT8 *p_data, UINT16 len);
+
+/*******************************************************************************
+**
+** Function bta_dg_co_tx_writebuf
+**
+** Description This function is called by DG to send data to the phone
+** when the TX path is configured to use a push interface with
+** zero copy. The phone must free the buffer using function
+** GKI_freebuf() when it is through processing the buffer.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_dg_co_tx_writebuf(UINT16 handle, UINT8 app_id, BT_HDR *p_buf);
+
+/*******************************************************************************
+**
+** Function bta_dg_co_rx_flow
+**
+** Description This function is called by DG to enable or disable
+** data flow on the RX path when it is configured to use
+** a push interface. If data flow is disabled the phone must
+** not call bta_dg_ci_rx_write() or bta_dg_ci_rx_writebuf()
+** until data flow is enabled again.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_dg_co_rx_flow(UINT16 handle, UINT8 app_id, BOOLEAN enable);
+
+/*******************************************************************************
+**
+** Function bta_dg_co_control
+**
+** Description This function is called by DG to send RS-232 signal
+** information to the phone. This function allows these
+** signals to be propagated from the RFCOMM channel to the
+** phone. If the phone does not use these signals the
+** implementation of this function can do nothing.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_dg_co_control(UINT16 handle, UINT8 app_id, UINT8 signals, UINT8 values);
+
+#endif /* BTA_DG_CO_H */
+
diff --git a/bta/include/bta_dm_ci.h b/bta/include/bta_dm_ci.h
new file mode 100644
index 0000000..f662f17
--- /dev/null
+++ b/bta/include/bta_dm_ci.h
@@ -0,0 +1,69 @@
+/*****************************************************************************
+**
+** Name: bta_dm_ci.h
+**
+** Description: This is the interface file for device mananger call-in
+** functions.
+**
+** Copyright (c) 2006, Widcomm Inc., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_DM_CI_H
+#define BTA_DM_CI_H
+
+#include "bta_api.h"
+
+/*****************************************************************************
+** Function Declarations
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*******************************************************************************
+**
+** Function bta_dm_ci_io_req
+**
+** Description This function must be called in response to function
+** bta_dm_co_io_req(), if *p_oob_data is set to BTA_OOB_UNKNOWN
+** by bta_dm_co_io_req().
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_dm_ci_io_req(BD_ADDR bd_addr, tBTA_IO_CAP io_cap,
+ tBTA_OOB_DATA oob_data, tBTA_AUTH_REQ auth_req);
+
+/*******************************************************************************
+**
+** Function bta_dm_ci_rmt_oob
+**
+** Description This function must be called in response to function
+** bta_dm_co_rmt_oob() to provide the OOB data associated
+** with the remote device.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_dm_ci_rmt_oob(BOOLEAN accept, BD_ADDR bd_addr,
+ BT_OCTET16 c, BT_OCTET16 r);
+/*******************************************************************************
+**
+** Function bta_dm_sco_ci_data_ready
+**
+** Description This function sends an event to indicating that the phone
+** has SCO data ready..
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_dm_sco_ci_data_ready(UINT16 event, UINT16 sco_handle);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/bta/include/bta_dm_co.h b/bta/include/bta_dm_co.h
new file mode 100644
index 0000000..cadf6bf
--- /dev/null
+++ b/bta/include/bta_dm_co.h
@@ -0,0 +1,262 @@
+/*****************************************************************************
+**
+** Name: bta_dm_co.h
+**
+** Description: This is the interface file for device mananger callout
+** functions.
+**
+** Copyright (c) 2006-2009, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_DM_CO_H
+#define BTA_DM_CO_H
+
+#include "bta_sys.h"
+
+
+#ifndef BTA_SCO_OUT_PKT_SIZE
+ #define BTA_SCO_OUT_PKT_SIZE BTM_SCO_DATA_SIZE_MAX
+#endif
+
+#define BTA_SCO_CODEC_PCM 0 /* used for regular SCO */
+#define BTA_SCO_CODEC_SBC 1 /* used for WBS */
+typedef UINT8 tBTA_SCO_CODEC_TYPE;
+
+#define BTA_DM_SCO_SAMP_RATE_8K 8000
+#define BTA_DM_SCO_SAMP_RATE_16K 16000
+
+/* SCO codec information */
+typedef struct
+{
+ tBTA_SCO_CODEC_TYPE codec_type;
+}tBTA_CODEC_INFO;
+
+#define BTA_DM_SCO_ROUTE_PCM BTM_SCO_ROUTE_PCM
+#define BTA_DM_SCO_ROUTE_HCI BTM_SCO_ROUTE_HCI
+
+typedef tBTM_SCO_ROUTE_TYPE tBTA_DM_SCO_ROUTE_TYPE;
+
+
+/*****************************************************************************
+** Function Declarations
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function bta_dm_co_io_req
+**
+** Description This callout function is executed by DM to get IO capabilities
+** of the local device for the Simple Pairing process
+**
+** Parameters bd_addr - The peer device
+** *p_io_cap - The local Input/Output capabilities
+** *p_oob_data - TRUE, if OOB data is available for the peer device.
+** *p_auth_req - TRUE, if MITM protection is required.
+**
+** Returns void.
+**
+*******************************************************************************/
+BTA_API extern void bta_dm_co_io_req(BD_ADDR bd_addr, tBTA_IO_CAP *p_io_cap,
+ tBTA_OOB_DATA *p_oob_data, tBTA_AUTH_REQ *p_auth_req,
+ BOOLEAN is_orig);
+
+/*******************************************************************************
+**
+** Function bta_dm_co_io_rsp
+**
+** Description This callout function is executed by DM to report IO capabilities
+** of the peer device for the Simple Pairing process
+**
+** Parameters bd_addr - The peer device
+** io_cap - The remote Input/Output capabilities
+** oob_data - TRUE, if OOB data is available for the peer device.
+** auth_req - TRUE, if MITM protection is required.
+**
+** Returns void.
+**
+*******************************************************************************/
+BTA_API extern void bta_dm_co_io_rsp(BD_ADDR bd_addr, tBTA_IO_CAP io_cap,
+ tBTA_OOB_DATA oob_data, tBTA_AUTH_REQ auth_req);
+
+/*******************************************************************************
+**
+** Function bta_dm_co_lk_upgrade
+**
+** Description This callout function is executed by DM to check if the
+** platform wants allow link key upgrade
+**
+** Parameters bd_addr - The peer device
+** *p_upgrade - TRUE, if link key upgrade is desired.
+**
+** Returns void.
+**
+*******************************************************************************/
+BTA_API extern void bta_dm_co_lk_upgrade(BD_ADDR bd_addr, BOOLEAN *p_upgrade );
+
+/*******************************************************************************
+**
+** Function bta_dm_co_loc_oob
+**
+** Description This callout function is executed by DM to report the OOB
+** data of the local device for the Simple Pairing process
+**
+** Parameters valid - TRUE, if the local OOB data is retrieved from LM
+** c - Simple Pairing Hash C
+** r - Simple Pairing Randomnizer R
+**
+** Returns void.
+**
+*******************************************************************************/
+BTA_API extern void bta_dm_co_loc_oob(BOOLEAN valid, BT_OCTET16 c, BT_OCTET16 r);
+
+/*******************************************************************************
+**
+** Function bta_dm_co_rmt_oob
+**
+** Description This callout function is executed by DM to request the OOB
+** data for the remote device for the Simple Pairing process
+**
+** Parameters bd_addr - The peer device
+**
+** Returns void.
+**
+*******************************************************************************/
+BTA_API extern void bta_dm_co_rmt_oob(BD_ADDR bd_addr);
+
+/*****************************************************************************
+** SCO over HCI Function Declarations
+*****************************************************************************/
+/*******************************************************************************
+**
+** Function bta_dm_sco_co_init
+**
+** Description This function can be used by the phone to initialize audio
+** codec or for other initialization purposes before SCO connection
+** is opened.
+**
+**
+** Returns Void.
+**
+*******************************************************************************/
+BTA_API extern tBTA_DM_SCO_ROUTE_TYPE bta_dm_sco_co_init(UINT32 rx_bw, UINT32 tx_bw,
+ tBTA_CODEC_INFO *p_codec_info, UINT8 app_id);
+
+
+/*******************************************************************************
+**
+** Function bta_dm_sco_co_open
+**
+** Description This function is executed when a SCO connection is open.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_dm_sco_co_open(UINT16 handle, UINT8 pkt_size, UINT16 event);
+
+/*******************************************************************************
+**
+** Function bta_dm_sco_co_close
+**
+** Description This function is called when a SCO connection is closed
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_dm_sco_co_close(void);
+
+/*******************************************************************************
+**
+** Function bta_dm_sco_co_out_data
+**
+** Description This function is called to send SCO data over HCI.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_dm_sco_co_out_data(BT_HDR **p_buf);
+
+/*******************************************************************************
+**
+** Function bta_dm_sco_co_in_data
+**
+** Description This function is called to send incoming SCO data to application.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_dm_sco_co_in_data(BT_HDR *p_buf, tBTM_SCO_DATA_FLAG status);
+
+
+
+/*******************************************************************************
+**
+** Function bta_dm_co_ble_io_req
+**
+** Description This callout function is executed by DM to get BLE IO capabilities
+** before SMP pairing gets going.
+**
+** Parameters bd_addr - The peer device
+** *p_io_cap - The local Input/Output capabilities
+** *p_oob_data - TRUE, if OOB data is available for the peer device.
+** *p_auth_req - Auth request setting (Bonding and MITM required or not)
+** *p_max_key_size - max key size local device supported.
+** *p_init_key - initiator keys.
+** *p_resp_key - responder keys.
+**
+** Returns void.
+**
+*******************************************************************************/
+BTA_API extern void bta_dm_co_ble_io_req(BD_ADDR bd_addr, tBTA_IO_CAP *p_io_cap,
+ tBTA_OOB_DATA *p_oob_data,
+ tBTA_LE_AUTH_REQ *p_auth_req,
+ UINT8 *p_max_key_size,
+ tBTA_LE_KEY_TYPE *p_init_key,
+ tBTA_LE_KEY_TYPE *p_resp_key );
+
+
+/*******************************************************************************
+**
+** Function bta_dm_co_ble_local_key_reload
+**
+** Description This callout function is to load the local BLE keys if available
+** on the device.
+**
+** Parameters none
+**
+** Returns void.
+**
+*******************************************************************************/
+BTA_API extern void bta_dm_co_ble_load_local_keys (tBTA_DM_BLE_LOCAL_KEY_MASK *p_key_mask, BT_OCTET16 er,
+ tBTA_BLE_LOCAL_ID_KEYS *p_id_keys);
+
+// btla-specific ++
+/*******************************************************************************
+**
+** Function bta_dm_co_ble_io_req
+**
+** Description This callout function is executed by DM to get BLE IO capabilities
+** before SMP pairing gets going.
+**
+** Parameters bd_addr - The peer device
+** *p_io_cap - The local Input/Output capabilities
+** *p_oob_data - TRUE, if OOB data is available for the peer device.
+** *p_auth_req - Auth request setting (Bonding and MITM required or not)
+** *p_max_key_size - max key size local device supported.
+** *p_init_key - initiator keys.
+** *p_resp_key - responder keys.
+**
+** Returns void.
+**
+*******************************************************************************/
+BTA_API extern void bta_dm_co_ble_io_req(BD_ADDR bd_addr, tBTA_IO_CAP *p_io_cap,
+ tBTA_OOB_DATA *p_oob_data,
+ tBTA_LE_AUTH_REQ *p_auth_req,
+ UINT8 *p_max_key_size,
+ tBTA_LE_KEY_TYPE *p_init_key,
+ tBTA_LE_KEY_TYPE *p_resp_key );
+// btla-specific --
+
+#endif
diff --git a/bta/include/bta_fs_api.h b/bta/include/bta_fs_api.h
new file mode 100644
index 0000000..c0cb4f5
--- /dev/null
+++ b/bta/include/bta_fs_api.h
@@ -0,0 +1,32 @@
+/*****************************************************************************
+**
+** Name: bta_fs_api.h
+**
+** Description: This is the public interface file for the
+** file system of BTA, Widcomm's
+** Bluetooth application layer for mobile phones.
+**
+** Copyright (c) 2003 - 2009, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_FS_API_H
+#define BTA_FS_API_H
+
+#include "bta_api.h"
+
+/*****************************************************************************
+** Constants and data types
+*****************************************************************************/
+
+/* Configuration structure */
+typedef struct
+{
+ UINT16 max_file_len; /* Maximum size file name */
+ UINT16 max_path_len; /* Maximum path length (includes appended file name) */
+ char path_separator; /* 0x2f ('/'), or 0x5c ('\') */
+} tBTA_FS_CFG;
+
+extern tBTA_FS_CFG * p_bta_fs_cfg;
+
+#endif /* BTA_FS_API_H */
diff --git a/bta/include/bta_fs_ci.h b/bta/include/bta_fs_ci.h
new file mode 100644
index 0000000..c60b3ba
--- /dev/null
+++ b/bta/include/bta_fs_ci.h
@@ -0,0 +1,244 @@
+/*****************************************************************************
+**
+** Name: bta_fs_ci.h
+**
+** Description: This is the interface file for file system
+** call-in functions.
+**
+** Copyright (c) 2003-2009, Broadcom Corp., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_FS_CI_H
+#define BTA_FS_CI_H
+
+#include "bta_fs_co.h"
+
+/*****************************************************************************
+** Constants and data types
+*****************************************************************************/
+
+/* Open Complete Event */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_FS_CO_STATUS status;
+ UINT32 file_size;
+ int fd;
+ const char *p_file;
+} tBTA_FS_CI_OPEN_EVT;
+
+/* Read Ready Event */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_FS_CO_STATUS status;
+ int fd;
+ UINT16 num_read;
+} tBTA_FS_CI_READ_EVT;
+
+/* Write Ready Event */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_FS_CO_STATUS status;
+ int fd;
+} tBTA_FS_CI_WRITE_EVT;
+
+/* Get Directory Entry Event */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_FS_CO_STATUS status;
+} tBTA_FS_CI_GETDIR_EVT;
+
+/* Resume Information Event */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_FS_CO_STATUS status;
+ BD_ADDR_PTR p_addr;
+ UINT8 *p_sess_info;
+ UINT32 timeout;
+ UINT32 offset;
+ UINT8 ssn;
+ UINT8 info;
+} tBTA_FS_CI_RESUME_EVT;
+
+/* Action Complete Event */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_FS_CO_STATUS status;
+} tBTA_FS_CI_ACTION_EVT;
+
+
+/*****************************************************************************
+** Function Declarations
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*******************************************************************************
+**
+** Function bta_fs_ci_write
+**
+** Description This function sends an event to BTA indicating the phone
+** has written the number of bytes specified in the call-out
+** function, bta_fs_co_write(), and is ready for more data.
+** This function is used to control the TX data flow.
+** Note: The data buffer is released by the stack aioer
+** calling this function.
+**
+** Parameters fd - file descriptor passed to the stack in the
+** bta_fs_ci_open call-in function.
+** status - BTA_FS_CO_OK, BTA_FS_CO_NOSPACE, or BTA_FS_CO_FAIL
+** evt - Used Internally by BTA -> MUST be same value passed
+** in call-out function.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_fs_ci_write(int fd, tBTA_FS_CO_STATUS status, UINT16 evt);
+
+/*******************************************************************************
+**
+** Function bta_fs_ci_read
+**
+** Description This function sends an event to BTA indicating the phone has
+** read in the requested amount of data specified in the
+** bta_fs_co_read() call-out function. It should only be called
+** when the requested number of bytes has been read in, or aioer
+** the end of the file has been detected.
+**
+** Parameters fd - file descriptor passed to the stack in the
+** bta_fs_ci_open call-in function.
+** num_bytes_read - number of bytes read into the buffer
+** specified in the read callout-function.
+** status - BTA_FS_CO_OK if full buffer of data,
+** BTA_FS_CO_EOF if the end of file has been reached,
+** BTA_FS_CO_FAIL if an error has occurred.
+** evt - Used Internally by BTA -> MUST be same value passed
+** in call-out function.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_fs_ci_read(int fd, UINT16 num_bytes_read,
+ tBTA_FS_CO_STATUS status, UINT16 evt);
+
+/*******************************************************************************
+**
+** Function bta_fs_ci_open
+**
+** Description This function sends an event to BTA indicating the phone has
+** finished opening a file for reading or writing.
+**
+** Parameters fd - file descriptor passed to the stack in the
+** bta_fs_ci_open call-in function.
+** status - BTA_FS_CO_OK if file was opened in mode specified
+** in the call-out function.
+** BTA_FS_CO_EACCES if the file exists, but contains
+** the wrong access permissions.
+** BTA_FS_CO_FAIL if any other error has occurred.
+** file_size - The total size of the file
+** evt - Used Internally by BTA -> MUST be same value passed
+** in call-out function.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_fs_ci_open(int fd, tBTA_FS_CO_STATUS status,
+ UINT32 file_size, UINT16 evt);
+
+/*******************************************************************************
+**
+** Function bta_fs_ci_direntry
+**
+** Description This function is called in response to the
+** bta_fs_co_getdirentry call-out function.
+**
+** Parameters status - BTA_FS_CO_OK if p_entry points to a valid entry.
+** BTA_FS_CO_EODIR if no more entries (p_entry is ignored).
+** BTA_FS_CO_FAIL if any errors have occurred.
+** evt - Used Internally by BTA -> MUST be same value passed
+** in call-out function.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_fs_ci_direntry(tBTA_FS_CO_STATUS status, UINT16 evt);
+
+/*******************************************************************************
+**
+** Function bta_fs_ci_resume
+**
+** Description This function is called in response to the
+** bta_fs_co_resume call-out function.
+**
+** Parameters p_sess_info - the stored session ID and related information.
+** ssn - the stored session sequence number.
+** info - the stored BTA specific information (like last active operation).
+** status - BTA_FS_CO_OK if p_entry points to a valid entry.
+** BTA_FS_CO_FAIL if any errors have occurred.
+** evt - Used Internally by BTA -> MUST be same value passed
+** in call-out function.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_fs_ci_resume (BD_ADDR_PTR p_addr, UINT8 *p_sess_info,
+ UINT32 timeout, UINT32 offset, UINT8 ssn, UINT8 info,
+ tBTA_FS_CO_STATUS status, UINT16 evt);
+
+/*******************************************************************************
+**
+** Function bta_fs_ci_action
+**
+** Description This function is called in response to one of the action
+** call-out functions: bta_fs_co_copy, bta_fs_co_rename or
+** bta_fs_co_set_perms.
+**
+** Parameters status - BTA_FS_CO_OK if the action is succession.
+** BTA_FS_CO_FAIL if any errors have occurred.
+** evt - Used Internally by BTA -> MUST be same value passed
+** in call-out function.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_fs_ci_action(tBTA_FS_CO_STATUS status, UINT16 evt);
+
+/*******************************************************************************
+**
+** Function bta_fs_ci_resume_op
+**
+** Description This function sends an event to BTA indicating the phone has
+** finished opening a file for reading or writing on resume.
+**
+** Parameters fd - file descriptor passed to the stack in the
+** bta_fs_ci_open call-in function.
+** status - BTA_FS_CO_OK if file was opened in mode specified
+** in the call-out function.
+** BTA_FS_CO_EACCES if the file exists, but contains
+** the wrong access permissions.
+** BTA_FS_CO_FAIL if any other error has occurred.
+** p_file - The file name associated with fd
+** file_size - The total size of the file
+** evt - Used Internally by BTA -> MUST be same value passed
+** in call-out function.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_fs_ci_resume_op(int fd, tBTA_FS_CO_STATUS status, const char *p_file,
+ UINT32 file_size, UINT16 evt);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_FS_CI_H */
+
diff --git a/bta/include/bta_fs_co.h b/bta/include/bta_fs_co.h
new file mode 100644
index 0000000..6b068df
--- /dev/null
+++ b/bta/include/bta_fs_co.h
@@ -0,0 +1,690 @@
+/*****************************************************************************
+**
+** Name: bta_fs_co.h
+**
+** Description: This is the interface file for the synchronization
+** server call-out functions.
+**
+** Copyright (c) 2003-2009, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_FS_CO_H
+#define BTA_FS_CO_H
+
+#include <time.h>
+
+#include "bta_api.h"
+#include "goep_fs.h"
+#include "obx_api.h"
+
+/*****************************************************************************
+** Constants and Data Types
+*****************************************************************************/
+
+#ifndef BTA_FS_CO_MAX_SSN_ENTRIES
+#define BTA_FS_CO_MAX_SSN_ENTRIES 10
+#endif
+
+/* Maximum path length supported by FS_CO */
+#ifndef BTA_FS_CO_PATH_LEN
+#define BTA_FS_CO_PATH_LEN 294
+#endif
+
+#ifndef BTA_FS_CO_TEST_ROOT
+#define BTA_FS_CO_TEST_ROOT "test_files"
+#endif
+
+#define BTA_FS_CO_TEST_TYPE_NONE 0
+#define BTA_FS_CO_TEST_TYPE_REJECT 1
+#define BTA_FS_CO_TEST_TYPE_SUSPEND 2
+
+#ifndef BTA_FS_CO_TEST_AB_END
+#define BTA_FS_CO_TEST_AB_END BTA_FS_CO_TEST_TYPE_NONE
+#endif
+
+/**************************
+** Common Definitions
+***************************/
+
+/* Status codes returned by call-out functions, or in call-in functions as status */
+#define BTA_FS_CO_OK GOEP_OK
+#define BTA_FS_CO_FAIL GOEP_FAIL /* Used to pass all other errors */
+#define BTA_FS_CO_EACCES GOEP_EACCES
+#define BTA_FS_CO_ENOTEMPTY GOEP_ENOTEMPTY
+#define BTA_FS_CO_EOF GOEP_EOF
+#define BTA_FS_CO_EODIR GOEP_EODIR
+#define BTA_FS_CO_ENOSPACE GOEP_ENOSPACE/* Returned in bta_fs_ci_open if no room */
+#define BTA_FS_CO_EIS_DIR GOEP_EIS_DIR
+#define BTA_FS_CO_RESUME GOEP_RESUME /* used in ci_open, on resume */
+#define BTA_FS_CO_NONE GOEP_NONE /* used in ci_open, on resume (no file to resume) */
+
+typedef UINT16 tBTA_FS_CO_STATUS;
+
+/* the index to the permission flags */
+#define BTA_FS_PERM_USER 0
+#define BTA_FS_PERM_GROUP 1
+#define BTA_FS_PERM_OTHER 2
+/* max number of the permission flags */
+#define BTA_FS_PERM_SIZE 3
+
+/* Flags passed to the open function (bta_fs_co_open)
+** Values are OR'd together. (First 3 are
+** mutually exclusive.
+*/
+#define BTA_FS_O_RDONLY GOEP_O_RDONLY
+#define BTA_FS_O_WRONLY GOEP_O_WRONLY
+#define BTA_FS_O_RDWR GOEP_O_RDWR
+
+#define BTA_FS_O_CREAT GOEP_O_CREAT
+#define BTA_FS_O_EXCL GOEP_O_EXCL
+#define BTA_FS_O_TRUNC GOEP_O_TRUNC
+
+#define BTA_FS_O_MODE_MASK(x) (((UINT16)(x)) & 0x0003)
+
+/* Origin for the bta_fs_co_seek function */
+#define BTA_FS_SEEK_SET GOEP_SEEK_SET
+#define BTA_FS_SEEK_CUR GOEP_SEEK_CUR
+#define BTA_FS_SEEK_END GOEP_SEEK_END
+
+/* mode field in bta_fs_co_access callout */
+#define BTA_FS_ACC_EXIST GOEP_ACC_EXIST
+#define BTA_FS_ACC_READ GOEP_ACC_READ
+#define BTA_FS_ACC_RDWR GOEP_ACC_RDWR
+
+#define BTA_FS_LEN_UNKNOWN GOEP_LEN_UNKNOWN
+#define BTA_FS_INVALID_FD GOEP_INVALID_FD
+#define BTA_FS_INVALID_APP_ID (0xFF) /* this app_id is reserved */
+
+/* mode field in tBTA_FS_DIRENTRY (OR'd together) */
+#define BTA_FS_A_RDONLY GOEP_A_RDONLY
+#define BTA_FS_A_DIR GOEP_A_DIR /* Entry is a sub directory */
+
+#define BTA_FS_CTIME_LEN GOEP_CTIME_LEN /* Creation time "yyyymmddTHHMMSSZ" */
+
+/* Return structure type for a directory entry */
+typedef struct
+{
+ UINT32 refdata; /* holder for OS specific data used to get next entry */
+ UINT32 filesize;
+ char crtime[BTA_FS_CTIME_LEN]; /* "yyyymmddTHHMMSSZ", or "" if none */
+ char *p_name; /* Contains the addr of memory to copy name into */
+ UINT8 mode; /* BTA_FS_A_RDONLY and/or BTA_FS_A_DIR */
+} tBTA_FS_DIRENTRY;
+
+/* session state */
+enum
+{
+ BTA_FS_CO_SESS_ST_NONE,
+ BTA_FS_CO_SESS_ST_ACTIVE,
+ BTA_FS_CO_SESS_ST_SUSPEND,
+ BTA_FS_CO_SESS_ST_RESUMING
+};
+typedef UINT8 tBTA_FS_CO_SESS_ST;
+
+
+
+/* a data type to keep an array of ssn/file offset - the info can be saved to NV */
+typedef struct
+{
+ char path[BTA_FS_CO_PATH_LEN + 1]; /* the "current path". path[0]==0-> root */
+ char file[BTA_FS_CO_PATH_LEN + 1]; /* file[0] !=0 on resume -> the previous suspended session had opened files */
+ int oflags; /* the flag to open the file */
+ BD_ADDR bd_addr;
+ UINT8 sess_info[OBX_SESSION_INFO_SIZE];
+ UINT32 offset; /* last file offset */
+ UINT32 timeout; /* the timeout value on suspend */
+ time_t suspend_time; /* the time of suspend */
+ UINT16 nbytes; /* number of bytes for last read/write */
+ UINT8 ssn;
+ UINT8 info; /* info for BTA on the client side */
+ UINT8 app_id;
+ tBTA_FS_CO_SESS_ST sess_st;
+} tBTA_FS_CO_SESSION;
+
+/*****************************************************************************
+** Function Declarations
+*****************************************************************************/
+/**************************
+** Common Functions
+***************************/
+/*******************************************************************************
+**
+** Function bta_fs_co_init
+**
+** Description This function is executed as a part of the start up sequence
+** to make sure the control block is initialized.
+**
+** Parameters void.
+**
+** Returns void
+**
+**
+*******************************************************************************/
+BTA_API extern void bta_fs_co_init(void);
+
+/*******************************************************************************
+**
+** Function bta_fs_co_open
+**
+** Description This function is executed by BTA when a file is opened.
+** The phone uses this function to open
+** a file for reading or writing.
+**
+** Parameters p_path - Fully qualified path and file name.
+** oflags - permissions and mode (see constants above)
+** size - size of file to put (0 if unavailable or not applicable)
+** evt - event that must be passed into the call-in function.
+** app_id - application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns void
+**
+** Note: Upon completion of the request, a file descriptor (int),
+** if successful, and an error code (tBTA_FS_CO_STATUS)
+** are returned in the call-in function, bta_fs_ci_open().
+**
+*******************************************************************************/
+BTA_API extern void bta_fs_co_open(const char *p_path, int oflags, UINT32 size,
+ UINT16 evt, UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function bta_fs_co_session_info
+**
+** Description This function is executed by BTA when a reliable session is
+** established (p_sess_info != NULL) or ended (p_sess_info == NULL).
+**
+** Parameters bd_addr - the peer address
+** p_sess_info - the session ID and related information.
+** app_id - application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_fs_co_session_info(BD_ADDR bd_addr, UINT8 *p_sess_info, UINT8 ssn,
+ tBTA_FS_CO_SESS_ST new_st, char *p_path, UINT8 *p_info, UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function bta_fs_co_resume_op
+**
+** Description This function is executed by BTA when a reliable session is
+** resumed and there was an interrupted operation.
+**
+** Parameters offset - the session ID and related information.
+** evt - event that must be passed into the call-in function.
+** app_id - application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_fs_co_resume_op(UINT32 offset, UINT16 evt, UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function bta_fs_co_suspend
+**
+** Description This function is executed by BTA when a reliable session is
+** suspended.
+**
+** Parameters bd_addr - the peer address
+** ssn - the session sequence number.
+** info - the BTA specific information (like last active operation).
+** p_offset- the location to receive object offset of the suspended session
+** app_id - application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_fs_co_suspend(BD_ADDR bd_addr, UINT8 *p_sess_info, UINT8 ssn,
+ UINT32 *p_timeout, UINT32 *p_offset, UINT8 info, UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function bta_fs_co_resume
+**
+** Description This function is executed by BTA when resuming a session.
+** This is used to retrieve the session ID and related information
+**
+** Parameters evt - event that must be passed into the call-in function.
+** app_id - application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns void
+**
+** Note: Upon completion of the request, the related session information,
+** if successful, and an error code (tBTA_FS_CO_STATUS)
+** are returned in the call-in function, bta_fs_ci_resume().
+**
+*******************************************************************************/
+BTA_API extern void bta_fs_co_resume(UINT16 evt, UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function bta_fs_co_sess_ssn
+**
+** Description This function is executed by BTA when resuming a session.
+** This is used to inform call-out module if the ssn/file offset
+** needs to be adjusted.
+**
+** Parameters ssn - the session sequence number of the first request
+** after resume.
+** app_id - application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_fs_co_sess_ssn(int fd, UINT8 ssn, UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function bta_fs_co_setdir
+**
+** Description This function is executed by BTA when the server changes the
+** local path
+**
+** Parameters p_path - the new path.
+** app_id - application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_fs_co_setdir(const char *p_path, UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function bta_fs_co_close
+**
+** Description This function is called by BTA when a connection to a
+** client is closed.
+**
+** Parameters fd - file descriptor of file to close.
+** app_id - application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns (tBTA_FS_CO_STATUS) status of the call.
+** [BTA_FS_CO_OK if successful],
+** [BTA_FS_CO_FAIL if failed ]
+**
+*******************************************************************************/
+BTA_API extern tBTA_FS_CO_STATUS bta_fs_co_close(int fd, UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function bta_fs_co_read
+**
+** Description This function is called by BTA to read in data from the
+** previously opened file on the phone.
+**
+** Parameters fd - file descriptor of file to read from.
+** p_buf - buffer to read the data into.
+** nbytes - number of bytes to read into the buffer.
+** evt - event that must be passed into the call-in function.
+** ssn - session sequence number. Ignored, if bta_fs_co_open
+** was not called with BTA_FS_CO_RELIABLE.
+** app_id - application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns void
+**
+** Note: Upon completion of the request, bta_fs_ci_read() is
+** called with the buffer of data, along with the number
+** of bytes read into the buffer, and a status. The
+** call-in function should only be called when ALL requested
+** bytes have been read, the end of file has been detected,
+** or an error has occurred.
+**
+*******************************************************************************/
+BTA_API extern void bta_fs_co_read(int fd, UINT8 *p_buf, UINT16 nbytes, UINT16 evt,
+ UINT8 ssn, UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function bta_fs_co_write
+**
+** Description This function is called by io to send file data to the
+** phone.
+**
+** Parameters fd - file descriptor of file to write to.
+** p_buf - buffer to read the data from.
+** nbytes - number of bytes to write out to the file.
+** evt - event that must be passed into the call-in function.
+** ssn - session sequence number. Ignored, if bta_fs_co_open
+** was not called with BTA_FS_CO_RELIABLE.
+** app_id - application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns void
+**
+** Note: Upon completion of the request, bta_fs_ci_write() is
+** called with the file descriptor and the status. The
+** call-in function should only be called when ALL requested
+** bytes have been written, or an error has been detected,
+**
+*******************************************************************************/
+BTA_API extern void bta_fs_co_write(int fd, const UINT8 *p_buf, UINT16 nbytes, UINT16 evt,
+ UINT8 ssn, UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function bta_fs_co_seek
+**
+** Description This function is called by io to move the file pointer
+** of a previously opened file to the specified location for
+** the next read or write operation.
+**
+** Parameters fd - file descriptor of file.
+** offset - Number of bytes from origin.
+** origin - Initial position: BTA_FS_SEEK_SET, BTA_FS_SEEK_CUR,
+** or BTA_FS_SEEK_END.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_fs_co_seek (int fd, INT32 offset, INT16 origin, UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function bta_fs_co_access
+**
+** Description This function is called to check the existence of a file or
+** directory.
+**
+** Parameters p_path - (input) file or directory to access (fully qualified path).
+** mode - (input) [BTA_FS_ACC_EXIST, BTA_FS_ACC_READ, or BTA_FS_ACC_RDWR]
+** p_is_dir - (output) returns TRUE if p_path specifies a directory.
+** app_id - (input) application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns (tBTA_FS_CO_STATUS) status of the call.
+** [BTA_FS_CO_OK if it exists]
+** [BTA_FS_CO_EACCES if permissions are wrong]
+** [BTA_FS_CO_FAIL if it does not exist]
+**
+*******************************************************************************/
+BTA_API extern tBTA_FS_CO_STATUS bta_fs_co_access(const char *p_path, int mode,
+ BOOLEAN *p_is_dir, UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function bta_fs_co_mkdir
+**
+** Description This function is called to create a directory with
+** the pathname given by path. The pathname is a null terminated
+** string. All components of the path must already exist.
+**
+** Parameters p_path - (input) name of directory to create (fully qualified path).
+** app_id - (input) application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns (tBTA_FS_CO_STATUS) status of the call.
+** [BTA_FS_CO_OK if successful]
+** [BTA_FS_CO_FAIL if unsuccessful]
+**
+*******************************************************************************/
+BTA_API extern tBTA_FS_CO_STATUS bta_fs_co_mkdir(const char *p_path, UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function bta_fs_co_rmdir
+**
+** Description This function is called to remove a directory whose
+** name is given by path. The directory must be empty.
+**
+** Parameters p_path - (input) name of directory to remove (fully qualified path).
+** app_id - (input) application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns (tBTA_FS_CO_STATUS) status of the call.
+** [BTA_FS_CO_OK if successful]
+** [BTA_FS_CO_EACCES if read-only]
+** [BTA_FS_CO_ENOTEMPTY if directory is not empty]
+** [BTA_FS_CO_FAIL otherwise]
+**
+*******************************************************************************/
+BTA_API extern tBTA_FS_CO_STATUS bta_fs_co_rmdir(const char *p_path, UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function bta_fs_co_unlink
+**
+** Description This function is called by to remove a file whose name
+** is given by p_path.
+**
+** Parameters p_path - (input) name of file to remove (fully qualified path).
+** app_id - (input) application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns (tBTA_FS_CO_STATUS) status of the call.
+** [BTA_FS_CO_OK if successful]
+** [BTA_FS_CO_EACCES if read-only]
+** [BTA_FS_CO_FAIL otherwise]
+**
+*******************************************************************************/
+BTA_API extern tBTA_FS_CO_STATUS bta_fs_co_unlink(const char *p_path, UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function bta_fs_co_getdirentry
+**
+** Description This function is called to retrieve a directory entry for the
+** specified path. The first/next directory should be filled
+** into the location specified by p_entry.
+**
+** Parameters p_path - directory to search (Fully qualified path)
+** first_item - TRUE if first search, FALSE if next search
+** (p_cur contains previous)
+** p_entry (input/output) - Points to last entry data (valid when
+** first_item is FALSE)
+** evt - event that must be passed into the call-in function.
+** app_id - application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns void
+**
+** Note: Upon completion of the request, the status is passed
+** in the bta_fs_ci_direntry() call-in function.
+** BTA_FS_CO_OK is returned when p_entry is valid,
+** BTA_FS_CO_EODIR is returned when no more entries [finished]
+** BTA_FS_CO_FAIL is returned if an error occurred
+**
+*******************************************************************************/
+BTA_API extern void bta_fs_co_getdirentry(const char *p_path, BOOLEAN first_item,
+ tBTA_FS_DIRENTRY *p_entry, UINT16 evt,
+ UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function bta_fs_co_copy
+**
+** Description This function is called to copy a file/directory whose
+** name is given by p_src_path to p_dest_path.
+**
+** Parameters p_src_path - (input) name of file/directory to be copied (fully qualified path).
+** p_dest_path - (input) new name of file/directory(fully qualified path).
+** p_perms - the permission of the new object.
+** evt - event that must be passed into the call-in function.
+** app_id - (input) application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns (tBTA_FS_CO_STATUS) status of the call.
+** [BTA_FS_CO_OK if successful]
+** [BTA_FS_CO_EIS_DIR if p_src_path is a folder]
+** [BTA_FS_CO_EACCES if p_dest_path already exists or could not be created (invalid path);
+** or p_src_path is a directory and p_dest_path specifies a different path. ]
+** [BTA_FS_CO_FAIL otherwise]
+**
+*******************************************************************************/
+BTA_API extern void bta_fs_co_copy(const char *p_src_path, const char *p_dest_path, UINT8 *p_perms, UINT16 evt, UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function bta_fs_co_rename
+**
+** Description This function is called to move a file/directory whose
+** name is given by p_src_path to p_dest_path.
+**
+** Parameters p_src_path - (input) name of file/directory to be moved (fully qualified path).
+** p_dest_path - (input) new name of file/directory(fully qualified path).
+** p_perms - the permission of the new object.
+** app_id - (input) application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns (tBTA_FS_CO_STATUS) status of the call.
+** [BTA_FS_CO_OK if successful]
+** [BTA_FS_CO_EACCES if p_dest_path already exists or could not be created (invalid path);
+** or p_src_path is a directory and p_dest_path specifies a different path. ]
+** [BTA_FS_CO_FAIL otherwise]
+**
+*******************************************************************************/
+BTA_API extern void bta_fs_co_rename(const char *p_src_path, const char *p_dest_path, UINT8 *p_perms, UINT16 evt, UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function bta_fs_co_set_perms
+**
+** Description This function is called to set the permission a file/directory
+** with name as p_src_path.
+**
+** Parameters p_src_path - (input) name of file/directory to set permission (fully qualified path).
+** p_perms - the permission .
+** app_id - (input) application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns (tBTA_FS_CO_STATUS) status of the call.
+** [BTA_FS_CO_OK if successful]
+** [BTA_FS_CO_EACCES if p_dest_path already exists or could not be created (invalid path);
+** or p_src_path is a directory and p_dest_path specifies a different path. ]
+** [BTA_FS_CO_FAIL otherwise]
+**
+*******************************************************************************/
+BTA_API extern void bta_fs_co_set_perms(const char *p_src_path, UINT8 *p_perms, UINT16 evt, UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function bta_fs_co_sess_fopen
+**
+** Description This function is called by bta_fs_co_open to keep track of
+** the opened file (for reliable session suspend/resume.)
+**
+** Parameters p_path - Fully qualified path and file name.
+** oflags - permissions and mode (see constants above)
+** app_id - application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_fs_co_sess_fopen(const char *p_path, int oflags, UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function bta_fs_co_sess_fclose
+**
+** Description This function is called by bta_fs_co_close
+**
+** Parameters app_id - application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_fs_co_sess_fclose(UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function bta_fs_co_sess_offset
+**
+** Description This function is called by bta_fs_co_write to keep track of
+** the last file offset (Only the receiving side needs to keep
+** track of the file offset)
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_fs_co_sess_offset(UINT8 ssn, INT32 pos, UINT16 nbytes, UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function bta_fs_co_suspended_addr
+**
+** Description find the peer address of the suspended session control block
+** for the given an app_id.
+**
+** Returns the control block found.
+**
+*******************************************************************************/
+BTA_API extern UINT8 *bta_fs_co_suspended_addr(UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function bta_fs_co_num_suspended_session
+**
+** Description find the number of suspended session control blocks for the
+** given an app_id.
+**
+** Returns the number of control blocks found.
+**
+*******************************************************************************/
+BTA_API extern UINT8 bta_fs_co_num_suspended_session(UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function bta_fs_co_get_active_session
+**
+** Description find the active session control block for the given an app_id.
+**
+** Returns the control block found.
+**
+*******************************************************************************/
+BTA_API extern tBTA_FS_CO_SESSION *bta_fs_co_get_active_session(UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function bta_fs_co_init_db
+**
+** Description Initialize the session control blocks for platform.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_fs_co_init_db (tBTA_FS_CO_SESSION *p_first);
+
+/*******************************************************************************
+**
+** Function bta_fs_convert_oflags
+**
+** Description This function converts the open flags from BTA into MFS.
+**
+** Returns BTA FS status value.
+**
+*******************************************************************************/
+BTA_API extern int bta_fs_convert_bta_oflags(int bta_oflags);
+
+#endif /* BTA_FS_CO_H */
diff --git a/bta/include/bta_ft_api.h b/bta/include/bta_ft_api.h
new file mode 100644
index 0000000..96ed66f
--- /dev/null
+++ b/bta/include/bta_ft_api.h
@@ -0,0 +1,724 @@
+/*****************************************************************************
+**
+** Name: bta_ft_api.h
+**
+** Description: This is the public interface file for the file transfer
+** (FT) server subsystem of BTA, Widcomm's
+** Bluetooth application layer for mobile phones.
+**
+** Copyright (c) 2003-2009, Broadcom Corp., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_FT_API_H
+#define BTA_FT_API_H
+
+#include "bta_api.h"
+#include "btm_api.h"
+#if( defined BIP_INCLUDED) && (BIP_INCLUDED == TRUE)
+#include "bip_api.h"
+#endif
+#include "bta_sys.h"
+#include "bta_fs_co.h"
+
+/*****************************************************************************
+** Constants and data types
+*****************************************************************************/
+#define BTA_FT_ENHANCED_VERSION 0x0102
+
+/**************************
+** Common Definitions
+***************************/
+/* Access response types */
+#define BTA_FT_ACCESS_ALLOW 0 /* Allow the requested operation */
+#define BTA_FT_ACCESS_FORBID 1 /* Disallow the requested operation */
+
+typedef UINT8 tBTA_FT_ACCESS;
+
+/* Access event operation types */
+#define BTA_FT_OPER_DEFAULT 0 /* Default mode */
+#define BTA_FT_OPER_PUT 1 /* Request is a PUT file */
+#define BTA_FT_OPER_GET 2 /* Request is a GET file */
+#define BTA_FT_OPER_DEL_FILE 3 /* Request is a DELETE file */
+#define BTA_FT_OPER_DEL_DIR 4 /* Request is a DELETE folder */
+#define BTA_FT_OPER_CHG_DIR 5 /* Request is a Change Folder */
+#define BTA_FT_OPER_MK_DIR 6 /* Request is a Make Folder */
+#define BTA_FT_OPER_COPY_ACT 7 /* Request is a Copy Action command */
+#define BTA_FT_OPER_MOVE_ACT 8 /* Request is a Move Action command */
+#define BTA_FT_OPER_SET_PERM 9 /* Request is a SetPermission Action command */
+
+typedef UINT8 tBTA_FT_OPER;
+
+#define BTA_FT_ACT_COPY OBX_ACT_COPY /* 0x00 Copy object */
+#define BTA_FT_ACT_MOVE OBX_ACT_MOVE /* 0x01 Move/rename object */
+#define BTA_FT_ACT_PERMISSION OBX_ACT_PERMISSION /* 0x02 Set object permission */
+typedef tOBX_ACTION tBTA_FTC_ACT;
+
+#define BTA_FTC_RESUME_NONCE 0xFFFFFFFF
+
+/* permission flags */
+#define BTA_FT_PERMISSION_READ OBX_PERMISSION_READ /* 0x01 */
+#define BTA_FT_PERMISSION_WRITE OBX_PERMISSION_WRITE /* 0x02 */
+#define BTA_FT_PERMISSION_DELETE OBX_PERMISSION_DELETE /* 0x04 */
+#define BTA_FT_PERMISSION_MODIFY OBX_PERMISSION_MODIFY /* 0x80 */
+
+/**************************
+** Server Definitions
+***************************/
+/* Extra Debug Code */
+#ifndef BTA_FTS_DEBUG
+#define BTA_FTS_DEBUG FALSE
+#endif
+
+#define BTA_FTS_OK 0
+#define BTA_FTS_FAIL 1
+typedef UINT8 tBTA_FTS_STATUS;
+
+/* Server callback function events */
+#define BTA_FTS_ENABLE_EVT 0 /* File transfer server is enabled. */
+#define BTA_FTS_OPEN_EVT 1 /* Connection to peer is open. */
+#define BTA_FTS_CLOSE_EVT 2 /* Connection to peer closed. */
+#define BTA_FTS_AUTH_EVT 3 /* Request for Authentication key and realm */
+#define BTA_FTS_ACCESS_EVT 4 /* Request for access to put a file */
+#define BTA_FTS_PROGRESS_EVT 5 /* Number of bytes read or written so far */
+#define BTA_FTS_PUT_CMPL_EVT 6 /* File Put complete */
+#define BTA_FTS_GET_CMPL_EVT 7 /* File Get complete */
+#define BTA_FTS_DEL_CMPL_EVT 8 /* Remove File or Folder complete */
+#define BTA_FTS_DISABLE_EVT 9 /* Reply to a disable api request */
+
+typedef UINT8 tBTA_FTS_EVT;
+
+/* Structure associated with BTA_FTS_xxx_CMPL_EVT */
+typedef struct
+{
+ char *p_name; /* file or folder name. */
+ tBTA_FTS_STATUS status;
+} tBTA_FTS_OBJECT;
+
+typedef struct
+{
+ UINT32 file_size; /* Total size of file (BTA_FS_LEN_UNKNOWN if unknown) */
+ UINT16 bytes; /* Number of bytes read or written since last progress event */
+} tBTA_FTS_PROGRESS;
+
+typedef struct
+{
+
+ UINT8 *p_userid;
+ UINT8 userid_len;
+ BOOLEAN userid_required; /* TRUE if user ID is required in response (rechallanged) */
+} tBTA_FTS_AUTH;
+
+typedef struct
+{
+ char *p_name; /* file name with fully qualified path */
+ UINT32 size; /* file size */
+ tBTM_BD_NAME dev_name; /* Name of device, "" if unknown */
+ tBTA_FT_OPER oper; /* operation (put) */
+ BD_ADDR bd_addr; /* Address of device */
+ char *p_dest_name; /* destination file name with fully qualified path (BTA_FT_OPER_COPY_ACT & BTA_FT_OPER_MOVE_ACT) */
+ UINT8 perms[BTA_FS_PERM_SIZE]; /* user/group/other permission (BTA_FT_OPER_SET_PERM) */
+} tBTA_FTS_ACCESS;
+
+typedef union
+{
+ tBTA_FTS_STATUS status;
+ tBTA_FTS_PROGRESS prog;
+ tBTA_FTS_AUTH auth;
+ tBTA_FTS_ACCESS access;
+ tBTA_FTS_OBJECT obj;
+ BD_ADDR bd_addr;
+} tBTA_FTS;
+
+/* Server callback function */
+typedef void tBTA_FTS_CBACK(tBTA_FTS_EVT event, tBTA_FTS *p_data);
+
+
+/**************************
+** Client Definitions
+***************************/
+/* Extra Debug Code */
+#ifndef BTA_FTC_DEBUG
+#define BTA_FTC_DEBUG FALSE
+#endif
+
+/* Additional paramters for BTA_FtcPutFile using BIP service */
+typedef union
+{
+#if( defined BTA_BI_INCLUDED ) && (BTA_BI_INCLUDED == TRUE)
+ tBIP_IMAGE_DESC desc; /* when connectied with BIP service */
+#else
+ void* desc;
+#endif
+} tBTA_FTC_PARAM;
+
+/* Client callback function events */
+#define BTA_FTC_ENABLE_EVT 0 /* File transfer client is enabled. */
+#define BTA_FTC_OPEN_EVT 1 /* Connection to peer is open. */
+#define BTA_FTC_CLOSE_EVT 2 /* Connection to peer closed. */
+#define BTA_FTC_AUTH_EVT 3 /* Request for Authentication key and user id */
+#define BTA_FTC_LIST_EVT 4 /* Event contains a directory entry (tBTA_FTC_LIST) */
+#define BTA_FTC_PROGRESS_EVT 5 /* Number of bytes read or written so far */
+#define BTA_FTC_PUTFILE_EVT 6 /* File Put complete */
+#define BTA_FTC_GETFILE_EVT 7 /* File Get complete */
+#define BTA_FTC_BI_CAPS_EVT 8 /* BIP imaging capabilities */
+#define BTA_FTC_THUMBNAIL_EVT 9 /* BIP responder requests for the thumbnail version */
+#define BTA_FTC_CHDIR_EVT 10 /* Change Directory complete */
+#define BTA_FTC_MKDIR_EVT 11 /* Make Directory complete */
+#define BTA_FTC_REMOVE_EVT 12 /* Remove File/Directory complete */
+#define BTA_FTC_PHONEBOOK_EVT 13 /* Report the Application Parameters for BTA_FtcGetPhoneBook response */
+#define BTA_FTC_COPY_EVT 14 /* Copy File complete */
+#define BTA_FTC_MOVE_EVT 15 /* Move File complete */
+#define BTA_FTC_PERMISSION_EVT 16 /* Set File permission complete */
+
+
+typedef UINT8 tBTA_FTC_EVT;
+
+
+#define BTA_FTC_OK 0
+#define BTA_FTC_FAIL 1
+#define BTA_FTC_NO_PERMISSION 2
+#define BTA_FTC_NOT_FOUND 3
+#define BTA_FTC_FULL 4
+#define BTA_FTC_BUSY 5
+#define BTA_FTC_ABORTED 6
+#define BTA_FTC_SERVICE_UNAVL 7
+#define BTA_FTC_SDP_ERR 8
+#define BTA_FTC_OBX_ERR 9
+#define BTA_FTC_OBX_TOUT 10
+
+typedef UINT8 tBTA_FTC_STATUS;
+
+#define BTA_FTC_FLAG_NONE 0
+#define BTA_FTC_FLAG_BACKUP 1
+
+typedef UINT8 tBTA_FTC_FLAG;
+
+typedef struct
+{
+ tBTA_SERVICE_ID service; /* Connection is open with OPP, BIP, PBAP or FTP service */
+ UINT16 version;
+} tBTA_FTC_OPEN;
+
+#define BTA_FTC_FILTER_VERSION (1<<0) /* Version */
+#define BTA_FTC_FILTER_FN (1<<1) /* Formatted Name */
+#define BTA_FTC_FILTER_N (1<<2) /* Structured Presentation of Name */
+#define BTA_FTC_FILTER_PHOTO (1<<3) /* Associated Image or Photo */
+#define BTA_FTC_FILTER_BDAY (1<<4) /* Birthday */
+#define BTA_FTC_FILTER_ADR (1<<5) /* Delivery Address */
+#define BTA_FTC_FILTER_LABEL (1<<6) /* Delivery */
+#define BTA_FTC_FILTER_TEL (1<<7) /* Telephone Number */
+#define BTA_FTC_FILTER_EMAIL (1<<8) /* Electronic Mail Address */
+#define BTA_FTC_FILTER_MAILER (1<<9) /* Electronic Mail */
+#define BTA_FTC_FILTER_TZ (1<<10) /* Time Zone */
+#define BTA_FTC_FILTER_GEO (1<<11) /* Geographic Position */
+#define BTA_FTC_FILTER_TITLE (1<<12) /* Job */
+#define BTA_FTC_FILTER_ROLE (1<<13) /* Role within the Organization */
+#define BTA_FTC_FILTER_LOGO (1<<14) /* Organization Logo */
+#define BTA_FTC_FILTER_AGENT (1<<15) /* vCard of Person Representing */
+#define BTA_FTC_FILTER_ORG (1<<16) /* Name of Organization */
+#define BTA_FTC_FILTER_NOTE (1<<17) /* Comments */
+#define BTA_FTC_FILTER_REV (1<<18) /* Revision */
+#define BTA_FTC_FILTER_SOUND (1<<19) /* Pronunciation of Name */
+#define BTA_FTC_FILTER_URL (1<<20) /* Uniform Resource Locator */
+#define BTA_FTC_FILTER_UID (1<<21) /* Unique ID */
+#define BTA_FTC_FILTER_KEY (1<<22) /* Public Encryption Key */
+#define BTA_FTC_FILTER_ALL (0)
+typedef UINT32 tBTA_FTC_FILTER_MASK;
+
+enum
+{
+ BTA_FTC_FORMAT_CARD_21, /* vCard format 2.1 */
+ BTA_FTC_FORMAT_CARD_30, /* vCard format 3.0 */
+ BTA_FTC_FORMAT_MAX
+};
+typedef UINT8 tBTA_FTC_FORMAT;
+
+typedef struct
+{
+ UINT16 phone_book_size;
+ BOOLEAN pbs_exist; /* phone_book_size is present in the response */
+ UINT8 new_missed_calls;
+ BOOLEAN nmc_exist; /* new_missed_calls is present in the response */
+} tBTA_FTC_PB_PARAM;
+
+typedef struct
+{
+ tBTA_FTC_PB_PARAM *p_param;
+ UINT8 *data;
+ UINT16 len;
+ BOOLEAN final; /* If TRUE, entry is last of the series */
+ tBTA_FTC_STATUS status; /* Fields are valid when status is BTA_FTC_OK */
+} tBTA_FTC_LIST;
+
+enum
+{
+ BTA_FTC_ORDER_INDEXED = 0, /* indexed */
+ BTA_FTC_ORDER_ALPHANUM, /* alphanumeric */
+ BTA_FTC_ORDER_PHONETIC, /* phonetic */
+ BTA_FTC_ORDER_MAX
+};
+typedef UINT8 tBTA_FTC_ORDER;
+enum
+{
+ BTA_FTC_ATTR_NAME = 0, /* name */
+ BTA_FTC_ATTR_NUMBER, /* number */
+ BTA_FTC_ATTR_SOUND, /* sound */
+ BTA_FTC_ATTR_MAX
+};
+typedef UINT8 tBTA_FTC_ATTR;
+
+typedef struct
+{
+ UINT32 file_size; /* Total size of file (BTA_FS_LEN_UNKNOWN if unknown) */
+ UINT16 bytes; /* Number of bytes read or written since last progress event */
+} tBTA_FTC_PROGRESS;
+
+typedef struct
+{
+ UINT8 *p_realm;
+ UINT8 realm_len;
+ UINT8 realm_charset;
+ BOOLEAN userid_required; /* If TRUE, a user ID must be sent */
+} tBTA_FTC_AUTH;
+
+#if( defined BTA_BI_INCLUDED ) && (BTA_BI_INCLUDED == TRUE)
+typedef struct
+{
+ tBIP_IMAGING_CAPS *p_bi_caps; /* BIP imaging capabilities */
+} tBTA_FTC_CAPS;
+
+typedef struct
+{
+ UINT8 *p_name; /* the image file name */
+ tBIP_IMG_HDL_STR handle; /* The image’s handle assigned by BIP responder. */
+} tBTA_FTC_THUMB;
+#endif
+
+typedef union
+{
+ tBTA_FTC_STATUS status;
+ tBTA_FTC_OPEN open;
+ tBTA_FTC_LIST list;
+ tBTA_FTC_PROGRESS prog;
+ tBTA_FTC_AUTH auth;
+#if( defined BTA_BI_INCLUDED ) && (BTA_BI_INCLUDED == TRUE)
+ tBTA_FTC_CAPS bi_caps;
+ tBTA_FTC_THUMB thumb;
+#endif
+ tBTA_FTC_PB_PARAM pb;
+} tBTA_FTC;
+
+/* Client callback function */
+typedef void tBTA_FTC_CBACK(tBTA_FTC_EVT event, tBTA_FTC *p_data);
+
+/*****************************************************************************
+** External Function Declarations
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**************************
+** Server Functions
+***************************/
+
+/*******************************************************************************
+**
+** Function BTA_FtsEnable
+**
+** Description Enable the file transfer server. This function must be
+** called before any other functions in the FTS API are called.
+** When the enable operation is complete the callback function
+** will be called with an BTA_FTS_ENABLE_EVT event.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_FtsEnable(tBTA_SEC sec_mask, const char *p_service_name,
+ const char *p_root_path, BOOLEAN enable_authen,
+ UINT8 realm_len, UINT8 *p_realm,
+ tBTA_FTS_CBACK *p_cback, UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function BTA_FtsDisable
+**
+** Description Disable the file transfer server. If the server is currently
+** connected to a peer device the connection will be closed.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_FtsDisable(void);
+
+/*******************************************************************************
+**
+** Function BTA_FtsClose
+**
+** Description Close the current connection. This function is called if
+** the phone wishes to close the connection before the FT
+** client disconnects.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_FtsClose(void);
+
+/*******************************************************************************
+**
+** Function BTA_FtsUnauthRsp
+**
+** Description Sends an OBEX authentication challenge to the connected
+** OBEX client. Called in response to an BTA_FTS_AUTH_EVT event.
+** Used when "enable_authen" is set to TRUE in BTA_FtsEnable().
+**
+** Note: If the "userid_required" is TRUE in the BTA_FTS_AUTH_EVT
+** event, then p_userid is required, otherwise it is optional.
+**
+** p_password must be less than BTA_FTS_MAX_AUTH_KEY_SIZE (16 bytes)
+** p_userid must be less than OBX_MAX_REALM_LEN (defined in target.h)
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_FtsAuthRsp (char *p_password, char *p_userid);
+
+/*******************************************************************************
+**
+** Function BTA_FtsAccessRsp
+**
+** Description Sends a reply to an access request event (BTA_FTS_ACCESS_EVT).
+** This call MUST be made whenever the event occurs.
+**
+** Parameters oper - operation being accessed.
+** access - BTA_FT_ACCESS_ALLOW or BTA_FT_ACCESS_FORBID
+** p_name - Full path of file to pulled or pushed.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_FtsAccessRsp(tBTA_FT_OPER oper, tBTA_FT_ACCESS access,
+ char *p_name);
+
+
+/**************************
+** Client Functions
+***************************/
+
+/*******************************************************************************
+**
+** Function BTA_FtcEnable
+**
+** Description Enable the file transfer client. This function must be
+** called before any other functions in the FTC API are called.
+** When the enable operation is complete the callback function
+** will be called with an BTA_FTC_ENABLE_EVT event.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_FtcEnable(tBTA_FTC_CBACK *p_cback, UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function BTA_FtcDisable
+**
+** Description Disable the file transfer client. If the client is currently
+** connected to a peer device the connection will be closed.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_FtcDisable(void);
+
+/*******************************************************************************
+**
+** Function BTA_FtcOpen
+**
+** Description Open a connection to an FTP, PBAP, OPP or BIP server.
+** If parameter services is set to use both all services,
+** the client will attempt to connect to the device using
+** FTP first and then PBAP, OPP, BIP.
+** When the connection is open the callback function
+** will be called with a BTA_FTC_OPEN_EVT. If the connection
+** fails or otherwise is closed the callback function will be
+** called with a BTA_FTC_CLOSE_EVT.
+**
+** If the connection is opened with FTP profile and
+** bta_ft_cfg.auto_file_list is TRUE , the callback
+** function will be called with one or more BTA_FTC_LIST_EVT
+** containing directory list information formatted in XML as
+** described in the IrOBEX Spec, Version 1.2, section 9.1.2.3.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_FtcOpen(BD_ADDR bd_addr, tBTA_SEC sec_mask,
+ tBTA_SERVICE_MASK services, BOOLEAN srm, UINT32 nonce);
+
+/*******************************************************************************
+**
+** Function BTA_FtcSuspend
+**
+** Description Suspend the current connection to the server.
+** This is allowed only for the sessions created by
+** BTA_FtcConnect with nonce!=0
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_FtcSuspend(void);
+
+/*******************************************************************************
+**
+** Function BTA_FtcClose
+**
+** Description Close the current connection to the server. Aborts any
+** active file transfer.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_FtcClose(void);
+
+/*******************************************************************************
+**
+** Function BTA_FtcCopyFile
+**
+** Description Invoke a Copy action on the server.
+** Create a copy of p_src and name it as p_dest
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_FtcCopyFile(const char *p_src, const char *p_dest);
+
+/*******************************************************************************
+**
+** Function BTA_FtcMoveFile
+**
+** Description Invoke a Move action on the server.
+** Move/rename p_src to p_dest
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_FtcMoveFile(const char *p_src, const char *p_dest);
+
+/*******************************************************************************
+**
+** Function BTA_FtcSetPermission
+**
+** Description Invoke a SetPermission action on the server.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_FtcSetPermission(const char *p_src, UINT8 user, UINT8 group, UINT8 other);
+
+/*******************************************************************************
+**
+** Function BTA_FtcPutFile
+**
+** Description Send a file to the connected server.
+**
+** This function can only be used when the client is connected
+** in FTP, OPP and BIP mode.
+**
+** Note: File name is specified with a fully qualified path.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_FtcPutFile(const char *p_name, tBTA_FTC_PARAM *p_param);
+
+/*******************************************************************************
+**
+** Function BTA_FtcGetPhoneBook
+**
+** Description Retrieve a PhoneBook from the peer device and copy it to the
+** local file system.
+**
+** This function can only be used when the client is connected
+** in PBAP mode.
+**
+** Note: local file name is specified with a fully qualified path.
+** Remote file name is absolute path in UTF-8 format
+** (telecom/pb.vcf or SIM1/telecom/pb.vcf).
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_FtcGetPhoneBook(char *p_local_name, char *p_remote_name,
+ tBTA_FTC_FILTER_MASK filter, tBTA_FTC_FORMAT format,
+ UINT16 max_list_count, UINT16 list_start_offset);
+
+/*******************************************************************************
+**
+** Function BTA_FtcGetCard
+**
+** Description Retrieve a vCard from the peer device and copy it to the
+** local file system.
+**
+** This function can only be used when the client is connected
+** in PBAP mode.
+**
+** Note: local file name is specified with a fully qualified path.
+** Remote file name is relative path in UTF-8 format.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_FtcGetCard(char *p_local_name, char *p_remote_name,
+ tBTA_FTC_FILTER_MASK filter, tBTA_FTC_FORMAT format);
+
+/*******************************************************************************
+**
+** Function BTA_FtcGetFile
+**
+** Description Retrieve a file from the peer device and copy it to the
+** local file system.
+**
+** This function can only be used when the client is connected
+** in FTP mode.
+**
+** Note: local file name is specified with a fully qualified path.
+** Remote file name is specified in UTF-8 format.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_FtcGetFile(char *p_local_name, char *p_remote_name);
+
+/*******************************************************************************
+**
+** Function BTA_FtcChDir
+**
+** Description Change directory on the peer device.
+**
+** This function can only be used when the client is connected
+** in FTP and PBAP mode.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_FtcChDir(char *p_dir, tBTA_FTC_FLAG flag);
+
+/*******************************************************************************
+**
+** Function BTA_FtcAuthRsp
+**
+** Description Sends a response to an OBEX authentication challenge to the
+** connected OBEX server. Called in response to an BTA_FTC_AUTH_EVT
+** event.
+**
+** Note: If the "userid_required" is TRUE in the BTA_FTC_AUTH_EVT event,
+** then p_userid is required, otherwise it is optional.
+**
+** p_password must be less than BTA_FTC_MAX_AUTH_KEY_SIZE (16 bytes)
+** p_userid must be less than OBX_MAX_REALM_LEN (defined in target.h)
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_FtcAuthRsp (char *p_password, char *p_userid);
+
+/*******************************************************************************
+**
+** Function BTA_FtcListCards
+**
+** Description Retrieve a directory listing from the peer device.
+** When the operation is complete the callback function will
+** be called with one or more BTA_FTC_LIST_EVT events
+** containing directory list information formatted as described
+** in the PBAP Spec, Version 0.9, section 3.1.6.
+** This function can only be used when the client is connected
+** to a peer device.
+**
+** This function can only be used when the client is connected
+** in PBAP mode.
+**
+** Parameters p_dir - Name of directory to retrieve listing of.
+**
+** Returns void
+**
+*******************************************************************************/
+
+BTA_API extern void BTA_FtcListCards(char *p_dir, tBTA_FTC_ORDER order, char *p_value,
+ tBTA_FTC_ATTR attribute, UINT16 max_list_count,
+ UINT16 list_start_offset);
+
+/*******************************************************************************
+**
+** Function BTA_FtcListDir
+**
+** Description Retrieve a directory listing from the peer device.
+** When the operation is complete the callback function will
+** be called with one or more BTA_FTC_LIST_EVT events
+** containing directory list information formatted as described
+** in the IrOBEX Spec, Version 1.2, section 9.1.2.3.
+**
+** This function can only be used when the client is connected
+** in FTP mode.
+**
+** Parameters p_dir - Name of directory to retrieve listing of. If NULL,
+** the current working directory is retrieved.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_FtcListDir(char *p_dir);
+
+/*******************************************************************************
+**
+** Function BTA_FtcAbort
+**
+** Description Aborts any active Put or Get file operation.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_FtcAbort(void);
+
+/*******************************************************************************
+**
+** Function BTA_FtcRemove
+**
+** Description Remove a file or directory on the peer device. When the
+** operation is complete the status is returned with the
+** BTA_FTC_REMOVE_EVT event.
+**
+** This function can only be used when the client is connected
+** in FTP mode.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_FtcRemove(char *p_name);
+
+/*******************************************************************************
+**
+** Function BTA_FtcMkDir
+**
+** Description Create a directory on the peer device. When the operation is
+** complete the status is returned with the BTA_FTC_MKDIR_EVT
+** event.
+**
+** This function can only be used when the client is connected
+** in FTP mode.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_FtcMkDir(char *p_dir);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_FT_API_H */
diff --git a/bta/include/bta_gatt_api.h b/bta/include/bta_gatt_api.h
new file mode 100644
index 0000000..02284a5
--- /dev/null
+++ b/bta/include/bta_gatt_api.h
@@ -0,0 +1,1206 @@
+/*****************************************************************************
+**
+** Name: bta_gatt_api.h
+**
+** Description: This is the public interface file for BTA GATT.
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_GATT_API_H
+#define BTA_GATT_API_H
+
+#include "bta_api.h"
+#include "gatt_api.h"
+
+#ifndef BTA_GATT_INCLUDED
+#define BTA_GATT_INCLUDED FALSE
+#endif
+
+
+#if ((BLE_INCLUDED == FALSE) && (BTA_GATT_INCLUDED == TRUE))
+#undef BTA_GATT_INCLUDED
+#define BTA_GATT_INCLUDED FALSE
+#endif
+
+
+#ifndef BTA_GATT_DEBUG
+#define BTA_GATT_DEBUG FALSE
+#endif
+
+/*****************************************************************************
+** Constants and data types
+*****************************************************************************/
+/**************************
+** Common Definitions
+***************************/
+/* GATT ID */
+typedef struct
+{
+ tBT_UUID uuid; /* uuid of the attribute */
+ UINT8 inst_id; /* instance ID */
+} tBTA_GATT_ID;
+
+/* Success code and error codes */
+#define BTA_GATT_OK GATT_SUCCESS
+#define BTA_GATT_INVALID_HANDLE GATT_INVALID_HANDLE /* 0x0001 */
+#define BTA_GATT_READ_NOT_PERMIT GATT_READ_NOT_PERMIT /* 0x0002 */
+#define BTA_GATT_WRITE_NOT_PERMIT GATT_WRITE_NOT_PERMIT /* 0x0003 */
+#define BTA_GATT_INVALID_PDU GATT_INVALID_PDU /* 0x0004 */
+#define BTA_GATT_INSUF_AUTHENTICATION GATT_INSUF_AUTHENTICATION /* 0x0005 */
+#define BTA_GATT_REQ_NOT_SUPPORTED GATT_REQ_NOT_SUPPORTED /* 0x0006 */
+#define BTA_GATT_INVALID_OFFSET GATT_INVALID_OFFSET /* 0x0007 */
+#define BTA_GATT_INSUF_AUTHORIZATION GATT_INSUF_AUTHORIZATION /* 0x0008 */
+#define BTA_GATT_PREPARE_Q_FULL GATT_PREPARE_Q_FULL /* 0x0009 */
+#define BTA_GATT_NOT_FOUND GATT_NOT_FOUND /* 0x000a */
+#define BTA_GATT_NOT_LONG GATT_NOT_LONG /* 0x000b */
+#define BTA_GATT_INSUF_KEY_SIZE GATT_INSUF_KEY_SIZE /* 0x000c */
+#define BTA_GATT_INVALID_ATTR_LEN GATT_INVALID_ATTR_LEN /* 0x000d */
+#define BTA_GATT_ERR_UNLIKELY GATT_ERR_UNLIKELY /* 0x000e */
+#define BTA_GATT_INSUF_ENCRYPTION GATT_INSUF_ENCRYPTION /* 0x000f */
+#define BTA_GATT_UNSUPPORT_GRP_TYPE GATT_UNSUPPORT_GRP_TYPE /* 0x0010 */
+#define BTA_GATT_INSUF_RESOURCE GATT_INSUF_RESOURCE /* 0x0011 */
+
+
+#define BTA_GATT_ILLEGAL_PARAMETER GATT_ILLEGAL_PARAMETER /* 0x0087 */
+#define BTA_GATT_NO_RESOURCES GATT_NO_RESOURCES /* 0x0080 */
+#define BTA_GATT_INTERNAL_ERROR GATT_INTERNAL_ERROR /* 0x0081 */
+#define BTA_GATT_WRONG_STATE GATT_WRONG_STATE /* 0x0082 */
+#define BTA_GATT_DB_FULL GATT_DB_FULL /* 0x0083 */
+#define BTA_GATT_BUSY GATT_BUSY /* 0x0084 */
+#define BTA_GATT_ERROR GATT_ERROR /* 0x0085 */
+#define BTA_GATT_CMD_STARTED GATT_CMD_STARTED /* 0x0086 */
+#define BTA_GATT_PENDING GATT_PENDING /* 0x0088 */
+#define BTA_GATT_AUTH_FAIL GATT_AUTH_FAIL /* 0x0089 */
+#define BTA_GATT_MORE GATT_MORE /* 0x008a */
+#define BTA_GATT_INVALID_CFG GATT_INVALID_CFG /* 0x008b */
+#define BTA_GATT_DUP_REG 0x008c
+#define BTA_GATT_ALREADY_OPEN 0x008d /* 0x008d */
+typedef UINT8 tBTA_GATT_STATUS;
+
+#define BTA_GATT_INVALID_CONN_ID GATT_INVALID_CONN_ID
+
+
+/* Client callback function events */
+#define BTA_GATTC_REG_EVT 0 /* GATT client is registered. */
+#define BTA_GATTC_DEREG_EVT 1 /* GATT client deregistered event */
+#define BTA_GATTC_OPEN_EVT 2 /* GATTC open request status event */
+#define BTA_GATTC_READ_CHAR_EVT 3 /* GATT read characteristic event */
+#define BTA_GATTC_WRITE_CHAR_EVT 4 /* GATT write characteristic or char descriptor event */
+#define BTA_GATTC_CLOSE_EVT 5 /* GATTC close request status event */
+#define BTA_GATTC_SEARCH_CMPL_EVT 6 /* GATT discovery complete event */
+#define BTA_GATTC_SEARCH_RES_EVT 7 /* GATT discovery result event */
+#define BTA_GATTC_READ_DESCR_EVT 8 /* GATT read characterisitc descriptor event */
+#define BTA_GATTC_WRITE_DESCR_EVT 9 /* GATT write characteristic descriptor event */
+#define BTA_GATTC_NOTIF_EVT 10 /* GATT attribute notification event */
+#define BTA_GATTC_PREP_WRITE_EVT 11 /* GATT prepare write event */
+#define BTA_GATTC_EXEC_EVT 12 /* execute write complete event */
+#define BTA_GATTC_ACL_EVT 13 /* ACL up event */
+#define BTA_GATTC_CANCEL_OPEN_EVT 14 /* cancel open event */
+#define BTA_GATTC_SRVC_CHG_EVT 15 /* service change event */
+typedef UINT8 tBTA_GATTC_EVT;
+
+typedef tGATT_IF tBTA_GATTC_IF;
+
+typedef struct
+{
+ UINT16 unit; /* as UUIUD defined by SIG */
+ UINT16 descr; /* as UUID as defined by SIG */
+ tGATT_FORMAT format;
+ INT8 exp;
+ UINT8 name_spc; /* The name space of the description */
+}tBTA_GATT_CHAR_PRES;
+
+#define BTA_GATT_CLT_CONFIG_NONE GATT_CLT_CONFIG_NONE /* 0x0000 */
+#define BTA_GATT_CLT_CONFIG_NOTIFICATION GATT_CLT_CONFIG_NOTIFICATION /* 0x0001 */
+#define BTA_GATT_CLT_CONFIG_INDICATION GATT_CLT_CONFIG_INDICATION /* 0x0002 */
+typedef UINT16 tBTA_GATT_CLT_CHAR_CONFIG;
+
+/* characteristic descriptor: server configuration value
+*/
+#define BTA_GATT_SVR_CONFIG_NONE GATT_SVR_CONFIG_NONE /* 0x0000 */
+#define BTA_GATT_SVR_CONFIG_BROADCAST GATT_SVR_CONFIG_BROADCAST /* 0x0001 */
+typedef UINT16 tBTA_GATT_SVR_CHAR_CONFIG;
+
+/* Characteristic Aggregate Format attribute value
+*/
+#define BTA_GATT_AGGR_HANDLE_NUM_MAX 10
+typedef struct
+{
+ UINT8 num_handle;
+ UINT16 handle_list[BTA_GATT_AGGR_HANDLE_NUM_MAX];
+} tBTA_GATT_CHAR_AGGRE;
+typedef tGATT_VALID_RANGE tBTA_GATT_VALID_RANGE;
+
+typedef struct
+{
+ UINT16 len;
+ UINT8 *p_value;
+}tBTA_GATT_UNFMT;
+
+#define BTA_GATT_MAX_ATTR_LEN GATT_MAX_ATTR_LEN
+
+#define BTA_GATTC_TYPE_WRITE GATT_WRITE
+#define BTA_GATTC_TYPE_WRITE_NO_RSP GATT_WRITE_NO_RSP
+typedef UINT8 tBTA_GATTC_WRITE_TYPE;
+
+#define BTA_GATT_CONN_UNKNOWN 0
+#define BTA_GATT_CONN_NO_RESOURCES GATT_CONN_NO_RESOURCES /* connection fail for l2cap resource failure */
+#define BTA_GATT_CONN_TIMEOUT GATT_CONN_TIMEOUT /* 0x08 connection timeout */
+#define BTA_GATT_CONN_TERMINATE_PEER_USER GATT_CONN_TERMINATE_PEER_USER /* 0x13 connection terminate by peer user */
+#define BTA_GATT_CONN_TERMINATE_LOCAL_HOST GATT_CONN_TERMINATE_LOCAL_HOST/* 0x16 connectionterminated by local host */
+#define BTA_GATT_CONN_FAIL_ESTABLISH GATT_CONN_FAIL_ESTABLISH /* 0x03E connection fail to establish */
+#define BTA_GATT_CONN_LMP_TIMEOUT GATT_CONN_LMP_TIMEOUT /* 0x22 connection fail for LMP response tout */
+#define BTA_GATT_CONN_CANCEL GATT_CONN_CANCEL /* 0x0100 L2CAP connection cancelled */
+#define BTA_GATT_CONN_NONE 0x0101 /* 0x0101 no connection to cancel */
+typedef UINT16 tBTA_GATT_REASON;
+
+typedef struct
+{
+ tBTA_GATT_ID id;
+ BOOLEAN is_primary;
+}tBTA_GATT_SRVC_ID;
+
+typedef struct
+{
+ tBTA_GATT_SRVC_ID srvc_id;
+ tBTA_GATT_ID char_id;
+}tBTA_GATTC_CHAR_ID;
+
+typedef struct
+{
+ tBTA_GATTC_CHAR_ID char_id;
+ tBT_UUID descr_type;
+}tBTA_GATTC_CHAR_DESCR_ID;
+
+typedef struct
+{
+ tBTA_GATT_SRVC_ID srvc_id;
+ tBTA_GATT_SRVC_ID incl_svc_id;
+}tBTA_GATTC_INCL_SVC_ID;
+
+#define BTA_GATT_TYPE_CHAR 0
+#define BTA_GATT_TYPE_CHAR_DESCR 1
+typedef UINT8 tBTA_GATT_ID_TYPE;
+
+typedef struct
+{
+ tBTA_GATT_ID_TYPE id_type;
+ union
+ {
+ tBTA_GATTC_CHAR_ID char_id;
+ tBTA_GATTC_CHAR_DESCR_ID char_descr_id;
+
+ } id_value;
+}tBTA_GATTC_ATTR_ID;
+
+#define BTA_GATTC_MULTI_MAX GATT_MAX_READ_MULTI_HANDLES
+
+typedef struct
+{
+ UINT8 num_attr;
+ tBTA_GATTC_ATTR_ID id_list[BTA_GATTC_MULTI_MAX];
+
+}tBTA_GATTC_MULTI;
+
+#define BTA_GATT_AUTH_REQ_NONE GATT_AUTH_REQ_NONE
+#define BTA_GATT_AUTH_REQ_NO_MITM GATT_AUTH_REQ_NO_MITM /* unauthenticated encryption */
+#define BTA_GATT_AUTH_REQ_MITM GATT_AUTH_REQ_MITM /* authenticated encryption */
+#define BTA_GATT_AUTH_REQ_SIGNED_NO_MITM GATT_AUTH_REQ_SIGNED_NO_MITM
+#define BTA_GATT_AUTH_REQ_SIGNED_MITM GATT_AUTH_REQ_SIGNED_MITM
+
+typedef tGATT_AUTH_REQ tBTA_GATT_AUTH_REQ;
+
+enum
+{
+ BTA_GATTC_ATTR_TYPE_INCL_SRVC,
+ BTA_GATTC_ATTR_TYPE_CHAR,
+ BTA_GATTC_ATTR_TYPE_CHAR_DESCR,
+ BTA_GATTC_ATTR_TYPE_SRVC
+};
+typedef UINT8 tBTA_GATTC_ATTR_TYPE;
+
+
+typedef struct
+{
+ tBT_UUID uuid;
+ UINT16 s_handle;
+ UINT16 e_handle; /* used for service only */
+ UINT8 attr_type;
+ UINT8 id;
+ UINT8 prop; /* used when attribute type is characteristic */
+ BOOLEAN is_primary; /* used when attribute type is service */
+}tBTA_GATTC_NV_ATTR;
+
+/* callback data structure */
+typedef struct
+{
+ tBTA_GATT_STATUS status;
+ tBTA_GATTC_IF client_if;
+// btla-specific ++
+ tBT_UUID app_uuid;
+// btla-specific --
+}tBTA_GATTC_REG;
+
+typedef struct
+{
+ UINT8 num_pres_fmt; /* number of presentation format aggregated*/
+ tBTA_GATTC_CHAR_DESCR_ID pre_format[BTA_GATTC_MULTI_MAX];
+}tBTA_GATT_CHAR_AGGRE_VALUE;
+
+typedef union
+{
+ tBTA_GATT_CHAR_AGGRE_VALUE aggre_value;
+ tBTA_GATT_UNFMT unformat;
+
+}tBTA_GATT_READ_VAL;
+
+typedef struct
+{
+ UINT16 conn_id;
+ tBTA_GATT_STATUS status;
+ tBTA_GATT_SRVC_ID srvc_id;
+ tBTA_GATT_ID char_id;
+ tBT_UUID descr_type;
+ tBTA_GATT_READ_VAL *p_value;
+}tBTA_GATTC_READ;
+
+typedef struct
+{
+ UINT16 conn_id;
+ tBTA_GATT_STATUS status;
+ tBTA_GATT_SRVC_ID srvc_id;
+ tBTA_GATT_ID char_id;
+ tBT_UUID descr_type;
+}tBTA_GATTC_WRITE;
+
+typedef struct
+{
+ UINT16 conn_id;
+ tBTA_GATT_STATUS status;
+}tBTA_GATTC_EXEC_CMPL;
+
+typedef struct
+{
+ UINT16 conn_id;
+ tBTA_GATT_STATUS status;
+}tBTA_GATTC_SEARCH_CMPL;
+
+typedef struct
+{
+ UINT16 conn_id;
+ tBTA_GATT_SRVC_ID service_uuid;
+}tBTA_GATTC_SRVC_RES;
+
+
+typedef struct
+{
+ tBTA_GATT_STATUS status;
+ UINT16 conn_id;
+ tBTA_GATTC_IF client_if;
+ BD_ADDR remote_bda;
+}tBTA_GATTC_OPEN;
+
+typedef struct
+{
+ tBTA_GATT_STATUS status;
+ UINT16 conn_id;
+ tBTA_GATTC_IF client_if;
+ BD_ADDR remote_bda;
+ tBTA_GATT_REASON reason; /* disconnect reason code, not useful when connect event is reported */
+}tBTA_GATTC_CLOSE;
+
+typedef struct
+{
+ UINT16 conn_id;
+ BD_ADDR bda;
+ tBTA_GATTC_CHAR_ID char_id;
+ tBT_UUID descr_type;
+ UINT16 len;
+ UINT8 value[BTA_GATT_MAX_ATTR_LEN];
+ BOOLEAN is_notify;
+}tBTA_GATTC_NOTIFY;
+
+// btla-specific ++
+typedef struct
+{
+ tBTA_GATT_STATUS status;
+ tBTA_GATTC_IF client_if;
+ UINT16 conn_id;
+ BD_ADDR remote_bda;
+}tBTA_GATTC_OPEN_CLOSE;
+// btla-specific --
+
+typedef union
+{
+ tBTA_GATT_STATUS status;
+
+ tBTA_GATTC_SEARCH_CMPL search_cmpl; /* discovery complete */
+ tBTA_GATTC_SRVC_RES srvc_res; /* discovery result */
+ tBTA_GATTC_REG reg_oper; /* registration data */
+ tBTA_GATTC_OPEN open;
+ tBTA_GATTC_CLOSE close;
+ tBTA_GATTC_READ read; /* read attribute/descriptor data */
+ tBTA_GATTC_WRITE write; /* write complete data */
+ tBTA_GATTC_EXEC_CMPL exec_cmpl; /* execute complete */
+ tBTA_GATTC_NOTIFY notify; /* notification/indication event data */
+ BD_ADDR remote_bda; /* service change event */
+} tBTA_GATTC;
+
+/* Client callback function */
+typedef void (tBTA_GATTC_CBACK)(tBTA_GATTC_EVT event, tBTA_GATTC *p_data);
+
+
+/* GATT Server Data Structure */
+/* Server callback function events */
+#define BTA_GATTS_REG_EVT 0
+#define BTA_GATTS_READ_EVT GATTS_REQ_TYPE_READ /* 1 */
+#define BTA_GATTS_WRITE_EVT GATTS_REQ_TYPE_WRITE /* 2 */
+#define BTA_GATTS_EXEC_WRITE_EVT GATTS_REQ_TYPE_WRITE_EXEC /* 3 */
+#define BTA_GATTS_MTU_EVT GATTS_REQ_TYPE_MTU /* 4 */
+#define BTA_GATTS_CONF_EVT GATTS_REQ_TYPE_CONF /* 5 */
+#define BTA_GATTS_DEREG_EVT 6
+#define BTA_GATTS_CREATE_EVT 7
+#define BTA_GATTS_ADD_INCL_SRVC_EVT 8
+#define BTA_GATTS_ADD_CHAR_EVT 9
+#define BTA_GATTS_ADD_CHAR_DESCR_EVT 10
+#define BTA_GATTS_DELELTE_EVT 11
+#define BTA_GATTS_START_EVT 12
+#define BTA_GATTS_STOP_EVT 13
+#define BTA_GATTS_CONNECT_EVT 14
+#define BTA_GATTS_DISCONNECT_EVT 15
+#define BTA_GATTS_OPEN_EVT 16
+#define BTA_GATTS_CANCEL_OPEN_EVT 17
+#define BTA_GATTS_CLOSE_EVT 18
+
+typedef UINT8 tBTA_GATTS_EVT;
+typedef tGATT_IF tBTA_GATTS_IF;
+
+/* Attribute permissions
+*/
+#define BTA_GATT_PERM_READ GATT_PERM_READ /* bit 0 - 0x0001 */
+#define BTA_GATT_PERM_READ_ENCRYPTED GATT_PERM_READ_ENCRYPTED /* bit 1 - 0x0002 */
+#define BTA_GATT_PERM_READ_ENC_MITM GATT_PERM_READ_ENC_MITM /* bit 2 - 0x0004 */
+#define BTA_GATT_PERM_WRITE GATT_PERM_WRITE /* bit 4 - 0x0010 */
+#define BTA_GATT_PERM_WRITE_ENCRYPTED GATT_PERM_WRITE_ENCRYPTED /* bit 5 - 0x0020 */
+#define BTA_GATT_PERM_WRITE_ENC_MITM GATT_PERM_WRITE_ENC_MITM /* bit 6 - 0x0040 */
+#define BTA_GATT_PERM_WRITE_SIGNED GATT_PERM_WRITE_SIGNED /* bit 7 - 0x0080 */
+#define BTA_GATT_PERM_WRITE_SIGNED_MITM GATT_PERM_WRITE_SIGNED_MITM /* bit 8 - 0x0100 */
+typedef UINT16 tBTA_GATT_PERM;
+
+#define BTA_GATTS_INVALID_APP 0xff
+
+#define BTA_GATTS_INVALID_IF 0
+
+/* definition of characteristic properties */
+#define BTA_GATT_CHAR_PROP_BIT_BROADCAST GATT_CHAR_PROP_BIT_BROADCAST /* 0x01 */
+#define BTA_GATT_CHAR_PROP_BIT_READ GATT_CHAR_PROP_BIT_READ /* 0x02 */
+#define BTA_GATT_CHAR_PROP_BIT_WRITE_NR GATT_CHAR_PROP_BIT_WRITE_NR /* 0x04 */
+#define BTA_GATT_CHAR_PROP_BIT_WRITE GATT_CHAR_PROP_BIT_WRITE /* 0x08 */
+#define BTA_GATT_CHAR_PROP_BIT_NOTIFY GATT_CHAR_PROP_BIT_NOTIFY /* 0x10 */
+#define BTA_GATT_CHAR_PROP_BIT_INDICATE GATT_CHAR_PROP_BIT_INDICATE /* 0x20 */
+#define BTA_GATT_CHAR_PROP_BIT_AUTH GATT_CHAR_PROP_BIT_AUTH /* 0x40 */
+#define BTA_GATT_CHAR_PROP_BIT_EXT_PROP GATT_CHAR_PROP_BIT_EXT_PROP /* 0x80 */
+typedef UINT8 tBTA_GATT_CHAR_PROP;
+
+#ifndef BTA_GATTC_CHAR_DESCR_MAX
+#define BTA_GATTC_CHAR_DESCR_MAX 7
+#endif
+
+/*********************** NV callback Data Definitions **********************
+*/
+typedef struct
+{
+ tBT_UUID app_uuid128;
+ tBT_UUID svc_uuid;
+ UINT16 svc_inst;
+ UINT16 s_handle;
+ UINT16 e_handle;
+ BOOLEAN is_primary; /* primary service or secondary */
+} tBTA_GATTS_HNDL_RANGE;
+
+#define BTA_GATTS_SRV_CHG_CMD_ADD_CLIENT GATTS_SRV_CHG_CMD_ADD_CLIENT
+#define BTA_GATTS_SRV_CHG_CMD_UPDATE_CLIENT GATTS_SRV_CHG_CMD_UPDATE_CLIENT
+#define BTA_GATTS_SRV_CHG_CMD_REMOVE_CLIENT GATTS_SRV_CHG_CMD_REMOVE_CLIENT
+#define BTA_GATTS_SRV_CHG_CMD_READ_NUM_CLENTS GATTS_SRV_CHG_CMD_READ_NUM_CLENTS
+#define BTA_GATTS_SRV_CHG_CMD_READ_CLENT GATTS_SRV_CHG_CMD_READ_CLENT
+typedef tGATTS_SRV_CHG_CMD tBTA_GATTS_SRV_CHG_CMD;
+
+typedef tGATTS_SRV_CHG tBTA_GATTS_SRV_CHG;
+typedef tGATTS_SRV_CHG_REQ tBTA_GATTS_SRV_CHG_REQ;
+typedef tGATTS_SRV_CHG_RSP tBTA_GATTS_SRV_CHG_RSP;
+
+enum
+{
+ BTA_GATT_TRANSPORT_LE,
+ BTA_GATT_TRANSPORT_BR_EDR,
+ BTA_GATT_TRANSPORT_LE_BR_EDR
+};
+typedef UINT8 tBTA_GATT_TRANSPORT;
+
+/* attribute value */
+typedef tGATT_VALUE tBTA_GATT_VALUE;
+
+/* attribute response data */
+typedef tGATTS_RSP tBTA_GATTS_RSP;
+
+/* attribute request data from the client */
+#define BTA_GATT_PREP_WRITE_CANCEL 0x00
+#define BTA_GATT_PREP_WRITE_EXEC 0x01
+typedef tGATT_EXEC_FLAG tBTA_GATT_EXEC_FLAG;
+
+/* read request always based on UUID */
+typedef tGATT_READ_REQ tTA_GBATT_READ_REQ;
+
+/* write request data */
+typedef tGATT_WRITE_REQ tBTA_GATT_WRITE_REQ;
+
+/* callback data for server access request from client */
+typedef tGATTS_DATA tBTA_GATTS_REQ_DATA;
+
+typedef struct
+{
+ BD_ADDR remote_bda;
+ UINT32 trans_id;
+ UINT16 conn_id;
+ tBTA_GATTS_REQ_DATA *p_data;
+}tBTA_GATTS_REQ;
+
+typedef struct
+{
+ tBTA_GATTS_IF server_if;
+ tBTA_GATT_STATUS status;
+// btla-specific ++
+ tBT_UUID uuid;
+// btla-specific --
+}tBTA_GATTS_REG_OPER;
+
+
+typedef struct
+{
+ tBTA_GATTS_IF server_if;
+ UINT16 service_id;
+// btla-specific ++
+ UINT16 svc_instance;
+ BOOLEAN is_primary;
+ tBTA_GATT_STATUS status;
+ tBT_UUID uuid;
+// btla-specific --
+}tBTA_GATTS_CREATE;
+
+typedef struct
+{
+ tBTA_GATTS_IF server_if;
+ UINT16 service_id;
+ UINT16 attr_id;
+ tBTA_GATT_STATUS status;
+// btla-specific ++
+ tBT_UUID char_uuid;
+// btla-specific --
+}tBTA_GATTS_ADD_RESULT;
+
+typedef struct
+{
+ tBTA_GATTS_IF server_if;
+ UINT16 service_id;
+ tBTA_GATT_STATUS status;
+}tBTA_GATTS_SRVC_OPER;
+
+
+typedef struct
+{
+ tBTA_GATTS_IF server_if;
+ BD_ADDR remote_bda;
+ UINT16 conn_id;
+ tBTA_GATT_REASON reason; /* report disconnect reason */
+}tBTA_GATTS_CONN;
+
+/* GATTS callback data */
+typedef union
+{
+ tBTA_GATTS_REG_OPER reg_oper;
+ tBTA_GATTS_CREATE create;
+ tBTA_GATTS_SRVC_OPER srvc_oper;
+ tBTA_GATT_STATUS status; /* BTA_GATTS_CONF_EVT */
+ tBTA_GATTS_ADD_RESULT add_result; /* add included service: BTA_GATTS_ADD_INCL_SRVC_EVT
+ add char : BTA_GATTS_ADD_CHAR_EVT
+ add char descriptor: BTA_GATTS_ADD_CHAR_DESCR_EVT */
+ tBTA_GATTS_REQ req_data;
+ tBTA_GATTS_CONN conn; /* BTA_GATTS_CONN_EVT */
+
+}tBTA_GATTS;
+
+
+/* Server callback function */
+typedef void (tBTA_GATTS_CBACK)(tBTA_GATTS_EVT event, tBTA_GATTS *p_data);
+/*****************************************************************************
+** External Function Declarations
+*****************************************************************************/
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**************************
+** Client Functions
+***************************/
+
+/*******************************************************************************
+**
+** Function BTA_GATTC_AppRegister
+**
+** Description This function is called to register application callbacks
+** with BTA GATTC module.
+**
+** Parameters p_app_uuid - applicaiton UUID
+** p_client_cb - pointer to the application callback function.
+**
+** Returns None
+**
+*******************************************************************************/
+BTA_API extern void BTA_GATTC_AppRegister(tBT_UUID *p_app_uuid, tBTA_GATTC_CBACK *p_client_cb);
+
+/*******************************************************************************
+**
+** Function BTA_GATTC_AppDeregister
+**
+** Description This function is called to deregister an application
+** from BTA GATTC module.
+**
+** Parameters client_if - client interface identifier.
+**
+** Returns None
+**
+*******************************************************************************/
+BTA_API extern void BTA_GATTC_AppDeregister (tBTA_GATTC_IF client_if);
+
+/*******************************************************************************
+**
+** Function BTA_GATTC_Open
+**
+** Description Open a direct connection or add a background auto connection
+** bd address
+**
+** Parameters client_if: server interface.
+** remote_bda: remote device BD address.
+** is_direct: direct connection or background auto connection
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_GATTC_Open(tBTA_GATTC_IF client_if, BD_ADDR remote_bda, BOOLEAN is_direct);
+
+/*******************************************************************************
+**
+** Function BTA_GATTC_CancelOpen
+**
+** Description Open a direct connection or add a background auto connection
+** bd address
+**
+** Parameters client_if: server interface.
+** remote_bda: remote device BD address.
+** is_direct: direct connection or background auto connection
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_GATTC_CancelOpen(tBTA_GATTC_IF client_if, BD_ADDR remote_bda, BOOLEAN is_direct);
+
+/*******************************************************************************
+**
+** Function BTA_GATTC_Close
+**
+** Description Close a connection to a GATT server.
+**
+** Parameters conn_id: connectino ID to be closed.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_GATTC_Close(UINT16 conn_id);
+
+/*******************************************************************************
+**
+** Function BTA_GATTC_ServiceSearchRequest
+**
+** Description This function is called to request a GATT service discovery
+** on a GATT server. This function report service search result
+** by a callback event, and followed by a service search complete
+** event.
+**
+** Parameters conn_id: connection ID.
+** p_srvc_uuid: a UUID of the service application is interested in.
+** If Null, discover for all services.
+**
+** Returns None
+**
+*******************************************************************************/
+BTA_API extern void BTA_GATTC_ServiceSearchRequest(UINT16 conn_id, tBT_UUID *p_srvc_uuid);
+
+/*******************************************************************************
+**
+** Function BTA_GATTC_GetFirstChar
+**
+** Description This function is called to find the first charatceristic of the
+** service on the given server.
+**
+** Parameters conn_id: connection ID which identify the server.
+** p_srvc_id: the service ID of which the characteristic is belonged to.
+** p_char_uuid_cond: Characteristic UUID, if NULL find the first available
+** characteristic.
+** p_char_result: output parameter which will store the GATT
+** characteristic ID.
+** p_property: output parameter to carry the characteristic property.
+**
+** Returns returns status.
+**
+*******************************************************************************/
+BTA_API extern tBTA_GATT_STATUS BTA_GATTC_GetFirstChar (UINT16 conn_id,
+ tBTA_GATT_SRVC_ID *p_srvc_id,
+ tBT_UUID *p_char_uuid_cond,
+ tBTA_GATTC_CHAR_ID *p_char_result,
+ tBTA_GATT_CHAR_PROP *p_property);
+
+/*******************************************************************************
+**
+** Function BTA_GATTC_GetNextChar
+**
+** Description This function is called to find the next charatceristic of the
+** service on the given server.
+**
+** Parameters conn_id: connection ID which identify the server.
+** p_start_char_id: start the characteristic search from the next record
+** after the one identified by char_id.
+** p_char_uuid_cond: Characteristic UUID, if NULL find the first available
+** characteristic.
+** p_char_result: output parameter which will store the GATT
+** characteristic ID.
+** p_property: output parameter, characteristic property.
+**
+** Returns returns status.
+**
+*******************************************************************************/
+BTA_API extern tBTA_GATT_STATUS BTA_GATTC_GetNextChar (UINT16 conn_id,
+ tBTA_GATTC_CHAR_ID *p_start_char_id,
+ tBT_UUID *p_char_uuid_cond,
+ tBTA_GATTC_CHAR_ID *p_char_result,
+ tBTA_GATT_CHAR_PROP *p_property);
+
+/*******************************************************************************
+**
+** Function BTA_GATTC_GetFirstCharDescr
+**
+** Description This function is called to find the first charatceristic descriptor of the
+** charatceristic on the given server.
+**
+** Parameters conn_id: connection ID which identify the server.
+** p_char_id: the characteristic ID of which the descriptor is belonged to.
+** p_descr_uuid_cond: Characteristic Descr UUID, if NULL find the first available
+** characteristic.
+** p_descr_result: output parameter which will store the GATT
+** characteristic descriptor ID.
+**
+** Returns returns status.
+**
+*******************************************************************************/
+BTA_API extern tBTA_GATT_STATUS BTA_GATTC_GetFirstCharDescr (UINT16 conn_id, tBTA_GATTC_CHAR_ID *p_char_id,
+ tBT_UUID *p_descr_uuid_cond,
+ tBTA_GATTC_CHAR_DESCR_ID *p_descr_result);
+
+/*******************************************************************************
+**
+** Function BTA_GATTC_GetNextCharDescr
+**
+** Description This function is called to find the next charatceristic of the
+** service on the given server.
+**
+** Parameters conn_id: connection ID which identify the server.
+** p_start_descr_id: start the characteristic search from the next record
+** after the one identified by p_start_descr_id.
+** p_descr_uuid_cond: Characteristic descriptor UUID, if NULL find
+** the first available characteristic descriptor.
+** p_descr_result: output parameter which will store the GATT
+** characteristic descriptor ID.
+**
+** Returns returns status.
+**
+*******************************************************************************/
+BTA_API extern tBTA_GATT_STATUS BTA_GATTC_GetNextCharDescr (UINT16 conn_id,
+ tBTA_GATTC_CHAR_DESCR_ID *p_start_descr_id,
+ tBT_UUID *p_descr_uuid_cond,
+ tBTA_GATTC_CHAR_DESCR_ID *p_descr_result);
+
+
+/*******************************************************************************
+**
+** Function BTA_GATTC_GetFirstIncludedService
+**
+** Description This function is called to find the first included service of the
+** service on the given server.
+**
+** Parameters conn_id: connection ID which identify the server.
+** p_srvc_id: the service ID of which the included service is belonged to.
+** p_uuid_cond: include service UUID, if NULL find the first available
+** included service.
+** p_result: output parameter which will store the GATT ID
+** of the included service found.
+**
+** Returns returns status.
+**
+*******************************************************************************/
+BTA_API extern tBTA_GATT_STATUS BTA_GATTC_GetFirstIncludedService(UINT16 conn_id,
+ tBTA_GATT_SRVC_ID *p_srvc_id,
+ tBT_UUID *p_uuid_cond,
+ tBTA_GATTC_INCL_SVC_ID *p_result);
+
+/*******************************************************************************
+**
+** Function BTA_GATTC_GetNextIncludedService
+**
+** Description This function is called to find the next included service of the
+** service on the given server.
+**
+** Parameters conn_id: connection ID which identify the server.
+** p_start_id: start the search from the next record
+** after the one identified by p_start_id.
+** p_uuid_cond: Included service UUID, if NULL find the first available
+** included service.
+** p_result: output parameter which will store the GATT ID
+** of the included service found.
+**
+** Returns returns status.
+**
+*******************************************************************************/
+BTA_API extern tBTA_GATT_STATUS BTA_GATTC_GetNextIncludedService(UINT16 conn_id,
+ tBTA_GATTC_INCL_SVC_ID *p_start_id,
+ tBT_UUID *p_uuid_cond,
+ tBTA_GATTC_INCL_SVC_ID *p_result);
+
+/*******************************************************************************
+**
+** Function BTA_GATTC_ReadCharacteristic
+**
+** Description This function is called to read a service's characteristics of
+** the given characteritisc ID.
+**
+** Parameters conn_id - connectino ID.
+** p_char_id - characteritic ID to read.
+**
+** Returns None
+**
+*******************************************************************************/
+BTA_API extern void BTA_GATTC_ReadCharacteristic (UINT16 conn_id,
+ tBTA_GATTC_CHAR_ID *p_char_id,
+ tBTA_GATT_AUTH_REQ auth_req);
+
+/*******************************************************************************
+**
+** Function BTA_GATTC_ReadCharDescr
+**
+** Description This function is called to read a characteristics descriptor.
+**
+** Parameters conn_id - connection ID.
+** p_char_descr_id - characteritic descriptor ID to read.
+**
+** Returns None
+**
+*******************************************************************************/
+BTA_API extern void BTA_GATTC_ReadCharDescr (UINT16 conn_id,
+ tBTA_GATTC_CHAR_DESCR_ID *p_char_descr_id,
+ tBTA_GATT_AUTH_REQ auth_req);
+
+/*******************************************************************************
+**
+** Function BTA_GATTC_WriteCharValue
+**
+** Description This function is called to write characteristic value.
+**
+** Parameters conn_id - connection ID.
+** p_char_id - characteristic ID to write.
+** write_type - type of write.
+** len: length of the data to be written.
+** p_value - the value to be written.
+**
+** Returns None
+**
+*******************************************************************************/
+BTA_API extern void BTA_GATTC_WriteCharValue (UINT16 conn_id,
+ tBTA_GATTC_CHAR_ID *p_char_id,
+ tBTA_GATTC_WRITE_TYPE write_type,
+ UINT16 len,
+ UINT8 *p_value,
+ tBTA_GATT_AUTH_REQ auth_req);
+
+/*******************************************************************************
+**
+** Function BTA_GATTC_WriteCharDescr
+**
+** Description This function is called to write characteristic descriptor value.
+**
+** Parameters conn_id - connection ID
+** p_char_descr_id - characteristic descriptor ID to write.
+** write_type - type of write.
+** p_value - the value to be written.
+**
+** Returns None
+**
+*******************************************************************************/
+BTA_API extern void BTA_GATTC_WriteCharDescr (UINT16 conn_id,
+ tBTA_GATTC_CHAR_DESCR_ID *p_char_descr_id,
+ tBTA_GATTC_WRITE_TYPE write_type,
+ tBTA_GATT_UNFMT *p_data,
+ tBTA_GATT_AUTH_REQ auth_req);
+
+/*******************************************************************************
+**
+** Function BTA_GATTC_SendIndConfirm
+**
+** Description This function is called to send handle value confirmation.
+**
+** Parameters conn_id - connection ID.
+** p_char_id - characteristic ID to confrim.
+**
+** Returns None
+**
+*******************************************************************************/
+BTA_API extern void BTA_GATTC_SendIndConfirm (UINT16 conn_id, tBTA_GATTC_CHAR_ID *p_char_id);
+
+/*******************************************************************************
+**
+** Function BTA_GATTC_RegisterForNotifications
+**
+** Description This function is called to register for notification of a service.
+**
+** Parameters client_if - client interface.
+** remote_bda - target GATT server.
+** p_char_id - pointer to GATT characteristic ID.
+**
+** Returns OK if registration succeed, otherwise failed.
+**
+*******************************************************************************/
+BTA_API extern tBTA_GATT_STATUS BTA_GATTC_RegisterForNotifications (tBTA_GATTC_IF client_if,
+ BD_ADDR remote_bda,
+ tBTA_GATTC_CHAR_ID *p_char_id);
+
+
+/*******************************************************************************
+**
+** Function BTA_GATTC_DeregisterForNotifications
+**
+** Description This function is called to de-register for notification of a servbice.
+**
+** Parameters client_if - client interface.
+** remote_bda - target GATT server.
+** p_char_id - pointer to a GATT characteristic ID.
+**
+** Returns OK if deregistration succeed, otherwise failed.
+**
+*******************************************************************************/
+BTA_API extern tBTA_GATT_STATUS BTA_GATTC_DeregisterForNotifications (tBTA_GATTC_IF client_if,
+ BD_ADDR remote_bda,
+ tBTA_GATTC_CHAR_ID *p_char_id);
+
+/*******************************************************************************
+**
+** Function BTA_GATTC_PrepareWrite
+**
+** Description This function is called to prepare write a characteristic value.
+**
+** Parameters conn_id - connection ID.
+** p_char_id - GATT characteritic ID of the service.
+** offset - offset of the write value.
+** len: length of the data to be written.
+** p_value - the value to be written.
+**
+** Returns None
+**
+*******************************************************************************/
+BTA_API extern void BTA_GATTC_PrepareWrite (UINT16 conn_id,
+ tBTA_GATTC_CHAR_ID *p_char_id,
+ UINT16 offset,
+ UINT16 len,
+ UINT8 *p_value,
+ tBTA_GATT_AUTH_REQ auth_req);
+
+/*******************************************************************************
+**
+** Function BTA_GATTC_ExecuteWrite
+**
+** Description This function is called to execute write a prepare write sequence.
+**
+** Parameters conn_id - connection ID.
+** is_execute - execute or cancel.
+**
+** Returns None
+**
+*******************************************************************************/
+BTA_API extern void BTA_GATTC_ExecuteWrite (UINT16 conn_id, BOOLEAN is_execute);
+
+/*******************************************************************************
+**
+** Function BTA_GATTC_ReadMultiple
+**
+** Description This function is called to read multiple characteristic or
+** characteristic descriptors.
+**
+** Parameters conn_id - connectino ID.
+** p_read_multi - read multiple parameters.
+**
+** Returns None
+**
+*******************************************************************************/
+BTA_API extern void BTA_GATTC_ReadMultiple(UINT16 conn_id, tBTA_GATTC_MULTI *p_read_multi,
+ tBTA_GATT_AUTH_REQ auth_req);
+
+
+
+
+/*******************************************************************************
+** BTA GATT Server API
+********************************************************************************/
+/*******************************************************************************
+**
+** Function BTA_GATTS_AppRegister
+**
+** Description This function is called to register application callbacks
+** with BTA GATTS module.
+**
+** Parameters p_app_uuid - applicaiton UUID
+** p_cback - pointer to the application callback function.
+**
+** Returns None
+**
+*******************************************************************************/
+ BTA_API extern void BTA_GATTS_AppRegister(tBT_UUID *p_app_uuid, tBTA_GATTS_CBACK *p_cback);
+
+
+/*******************************************************************************
+**
+** Function BTA_GATTS_AppDeregister
+**
+** Description De-register with BTA GATT Server.
+**
+** Parameters server_if: server interface
+**
+** Returns void
+**
+*******************************************************************************/
+ BTA_API extern void BTA_GATTS_AppDeregister(tBTA_GATTS_IF server_if);
+
+/*******************************************************************************
+**
+** Function BTA_GATTS_CreateService
+**
+** Description Create a service. When service creation is done, a callback
+** event BTA_GATTS_CREATE_SRVC_EVT is called to report status
+** and service ID to the profile. The service ID obtained in
+** the callback function needs to be used when adding included
+** service and characteristics/descriptors into the service.
+**
+** Parameters server_if: server interface.
+** p_service_uuid: service UUID.
+** inst: instance ID number of this service.
+** num_handle: numble of handle requessted for this service.
+** is_primary: is this service a primary one or not.
+**
+** Returns void
+**
+*******************************************************************************/
+ BTA_API extern void BTA_GATTS_CreateService(tBTA_GATTS_IF server_if, tBT_UUID *p_service_uuid,
+ UINT8 inst, UINT16 num_handle, BOOLEAN is_primary);
+
+/*******************************************************************************
+**
+** Function BTA_GATTS_AddIncludeService
+**
+** Description This function is called to add an included service. After included
+** service is included, a callback event BTA_GATTS_ADD_INCL_SRVC_EVT
+** is reported the included service ID.
+**
+** Parameters service_id: service ID to which this included service is to
+** be added.
+** included_service_id: the service ID to be included.
+**
+** Returns void
+**
+*******************************************************************************/
+ BTA_API extern void BTA_GATTS_AddIncludeService(UINT16 service_id, UINT16 included_service_id);
+
+/*******************************************************************************
+**
+** Function BTA_GATTS_AddCharacteristic
+**
+** Description This function is called to add a characteristic into a service.
+**
+** Parameters service_id: service ID to which this included service is to
+** be added.
+** p_char_uuid : Characteristic UUID.
+** perm : Characteristic value declaration attribute permission.
+** property : Characteristic Properties
+**
+** Returns None
+**
+*******************************************************************************/
+ BTA_API extern void BTA_GATTS_AddCharacteristic (UINT16 service_id, tBT_UUID *p_char_uuid,
+ tBTA_GATT_PERM perm, tBTA_GATT_CHAR_PROP property);
+
+/*******************************************************************************
+**
+** Function BTA_GATTS_AddCharDescriptor
+**
+** Description This function is called to add characteristic descriptor. When
+** it's done, a callback event BTA_GATTS_ADD_DESCR_EVT is called
+** to report the status and an ID number for this descriptor.
+**
+** Parameters service_id: service ID to which this charatceristic descriptor is to
+** be added.
+** perm: descriptor access permission.
+** p_descr_uuid: descriptor UUID.
+** p_descr_params: descriptor value if it's read only descriptor.
+**
+** Returns returns status.
+**
+*******************************************************************************/
+ BTA_API extern void BTA_GATTS_AddCharDescriptor (UINT16 service_id,
+ tBTA_GATT_PERM perm,
+ tBT_UUID * p_descr_uuid);
+
+/*******************************************************************************
+**
+** Function BTA_GATTS_DeleteService
+**
+** Description This function is called to delete a service. When this is done,
+** a callback event BTA_GATTS_DELETE_EVT is report with the status.
+**
+** Parameters service_id: service_id to be deleted.
+**
+** Returns returns none.
+**
+*******************************************************************************/
+ BTA_API extern void BTA_GATTS_DeleteService(UINT16 service_id);
+
+/*******************************************************************************
+**
+** Function BTA_GATTS_StartService
+**
+** Description This function is called to start a service.
+**
+** Parameters service_id: the service ID to be started.
+** sup_transport: supported trasnport.
+**
+** Returns None.
+**
+*******************************************************************************/
+ BTA_API extern void BTA_GATTS_StartService(UINT16 service_id, tBTA_GATT_TRANSPORT sup_transport);
+
+/*******************************************************************************
+**
+** Function BTA_GATTS_StopService
+**
+** Description This function is called to stop a service.
+**
+** Parameters service_id - service to be topped.
+**
+** Returns None
+**
+*******************************************************************************/
+ BTA_API extern void BTA_GATTS_StopService(UINT16 service_id);
+
+/*******************************************************************************
+**
+** Function BTA_GATTS_HandleValueIndication
+**
+** Description This function is called to read a characteristics descriptor.
+**
+** Parameters conn_id - connection identifier.
+** attr_id - attribute ID to indicate.
+** data_len - indicate data length.
+** p_data: data to indicate.
+** need_confirm - if this indication expects a confirmation or not.
+**
+** Returns None
+**
+*******************************************************************************/
+ BTA_API extern void BTA_GATTS_HandleValueIndication (UINT16 conn_id, UINT16 attr_id,
+ UINT16 data_len,
+ UINT8 *p_data,
+ BOOLEAN need_confirm);
+
+/*******************************************************************************
+**
+** Function BTA_GATTS_SendRsp
+**
+** Description This function is called to send a response to a request.
+**
+** Parameters conn_id - connection identifier.
+** trans_id - transaction ID.
+** status - response status
+** p_msg - response data.
+**
+** Returns None
+**
+*******************************************************************************/
+ BTA_API extern void BTA_GATTS_SendRsp (UINT16 conn_id, UINT32 trans_id,
+ tBTA_GATT_STATUS status, tBTA_GATTS_RSP *p_msg);
+
+
+
+
+/*******************************************************************************
+**
+** Function BTA_GATTS_Open
+**
+** Description Open a direct open connection or add a background auto connection
+** bd address
+**
+** Parameters server_if: server interface.
+** remote_bda: remote device BD address.
+** is_direct: direct connection or background auto connection
+**
+** Returns void
+**
+*******************************************************************************/
+ BTA_API extern void BTA_GATTS_Open(tBTA_GATTS_IF server_if, BD_ADDR remote_bda, BOOLEAN is_direct);
+
+
+/*******************************************************************************
+**
+** Function BTA_GATTS_CancelOpen
+**
+** Description Cancel a direct open connection or remove a background auto connection
+** bd address
+**
+** Parameters server_if: server interface.
+** remote_bda: remote device BD address.
+** is_direct: direct connection or background auto connection
+**
+** Returns void
+**
+*******************************************************************************/
+ BTA_API extern void BTA_GATTS_CancelOpen(tBTA_GATTS_IF server_if, BD_ADDR remote_bda, BOOLEAN is_direct);
+
+
+/*******************************************************************************
+**
+** Function BTA_GATTS_Close
+**
+** Description Close a connection a remote device.
+**
+** Parameters conn_id: connectino ID to be closed.
+**
+** Returns void
+**
+*******************************************************************************/
+ BTA_API extern void BTA_GATTS_Close(UINT16 conn_id);
+
+
+#ifdef __cplusplus
+
+}
+#endif
+
+
+#endif /* BTA_GATT_API_H */
+
diff --git a/bta/include/bta_gattc_ci.h b/bta/include/bta_gattc_ci.h
new file mode 100644
index 0000000..65941fc
--- /dev/null
+++ b/bta/include/bta_gattc_ci.h
@@ -0,0 +1,108 @@
+/*****************************************************************************
+**
+** Name: bta_gattc_ci.h
+**
+** Description: This is the interface file for GATT
+** call-in functions.
+**
+** Copyright (c) 2003-2009, Broadcom Corp., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_GATTC_CI_H
+#define BTA_GATTC_CI_H
+
+#include "bta_gatt_api.h"
+
+/*****************************************************************************
+** Constants and data types
+*****************************************************************************/
+
+/* Open Complete Event */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_GATT_STATUS status;
+} tBTA_GATTC_CI_EVT;
+
+#define BTA_GATTC_NV_LOAD_MAX 10
+
+/* Read Ready Event */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_GATT_STATUS status;
+ UINT16 num_attr;
+ tBTA_GATTC_NV_ATTR attr[BTA_GATTC_NV_LOAD_MAX];
+} tBTA_GATTC_CI_LOAD;
+
+
+/*****************************************************************************
+** Function Declarations
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*******************************************************************************
+**
+** Function bta_gattc_ci_cache_open
+**
+** Description This function sends an event to indicate server cache open
+** completed.
+**
+** Parameters server_bda - server BDA of this cache.
+** status - BTA_GATT_OK if full buffer of data,
+** BTA_GATT_FAIL if an error has occurred.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_gattc_ci_cache_open(BD_ADDR server_bda, UINT16 evt,
+ tBTA_GATT_STATUS status, UINT16 conn_id);
+
+/*******************************************************************************
+**
+** Function bta_gattc_ci_cache_load
+**
+** Description This function sends an event to BTA indicating the phone has
+** load the servere cache and ready to send it to the stack.
+**
+** Parameters server_bda - server BDA of this cache.
+** num_bytes_read - number of bytes read into the buffer
+** specified in the read callout-function.
+** status - BTA_GATT_OK if full buffer of data,
+** BTA_GATT_FAIL if an error has occurred.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_gattc_ci_cache_load(BD_ADDR server_bda, UINT16 evt,
+ UINT16 num_attr, tBTA_GATTC_NV_ATTR *p_atrr,
+ tBTA_GATT_STATUS status, UINT16 conn_id);
+
+/*******************************************************************************
+**
+** Function bta_gattc_ci_save
+**
+** Description This function sends an event to BTA indicating the phone has
+** save the server cache.
+**
+** Parameters server_bda - server BDA of this cache.
+** status - BTA_GATT_OK if full buffer of data,
+** BTA_GATT_FAIL if an error has occurred.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_gattc_ci_cache_save(BD_ADDR server_bda, UINT16 evt,
+ tBTA_GATT_STATUS status, UINT16 conn_id);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_GATTC_CI_H */
+
diff --git a/bta/include/bta_gattc_co.h b/bta/include/bta_gattc_co.h
new file mode 100644
index 0000000..0aedf9f
--- /dev/null
+++ b/bta/include/bta_gattc_co.h
@@ -0,0 +1,89 @@
+/*****************************************************************************
+**
+** Name: bta_gattc_co.h
+**
+** Description: This is the interface file for BTA GATT client call-out
+** functions.
+**
+** Copyright (c) 2010, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_GATTC_CO_H
+#define BTA_GATTC_CO_H
+
+#include "bta_gatt_api.h"
+
+/*******************************************************************************
+**
+** Function bta_gattc_co_cache_open
+**
+** Description This callout function is executed by GATTC when a GATT server
+** cache is ready to be sent.
+**
+** Parameter server_bda: server bd address of this cache belongs to
+** evt: call in event to be passed in when cache open is done.
+** conn_id: connection ID of this cache operation attach to.
+** to_save: open cache to save or to load.
+**
+** Returns void.
+**
+*******************************************************************************/
+BTA_API extern void bta_gattc_co_cache_open(BD_ADDR server_bda, UINT16 evt,
+ UINT16 conn_id, BOOLEAN to_save);
+
+/*******************************************************************************
+**
+** Function bta_gattc_co_cache_close
+**
+** Description This callout function is executed by GATTC when a GATT server
+** cache is written completely.
+**
+** Parameter server_bda: server bd address of this cache belongs to
+** conn_id: connection ID of this cache operation attach to.
+**
+** Returns void.
+**
+*******************************************************************************/
+BTA_API extern void bta_gattc_co_cache_close(BD_ADDR server_bda, UINT16 conn_id);
+
+/*******************************************************************************
+**
+** Function bta_gattc_co_cache_save
+**
+** Description This callout function is executed by GATT when a server cache
+** is available to save.
+**
+** Parameter server_bda: server bd address of this cache belongs to
+** evt: call in event to be passed in when cache save is done.
+** num_attr: number of attribute to be save.
+** p_attr: pointer to the list of attributes to save.
+** attr_index: starting attribute index of the save operation.
+** conn_id: connection ID of this cache operation attach to.
+** Returns
+**
+*******************************************************************************/
+BTA_API extern void bta_gattc_co_cache_save(BD_ADDR server_bda, UINT16 evt,
+ UINT16 num_attr, tBTA_GATTC_NV_ATTR *p_attr,
+ UINT16 attr_index, UINT16 conn_id);
+
+/*******************************************************************************
+**
+** Function bta_gattc_co_cache_load
+**
+** Description This callout function is executed by GATT when server cache
+** is required to load.
+**
+** Parameter server_bda: server bd address of this cache belongs to
+** evt: call in event to be passed in when cache save is done.
+** num_attr: number of attribute to be save.
+** attr_index: starting attribute index of the save operation.
+** conn_id: connection ID of this cache operation attach to.
+** Returns
+**
+*******************************************************************************/
+BTA_API extern void bta_gattc_co_cache_load(BD_ADDR server_bda, UINT16 evt,
+ UINT16 start_index, UINT16 conn_id);
+
+#endif /* BTA_GATT_CO_H */
+
diff --git a/bta/include/bta_gatts_co.h b/bta/include/bta_gatts_co.h
new file mode 100644
index 0000000..cb1ff76
--- /dev/null
+++ b/bta/include/bta_gatts_co.h
@@ -0,0 +1,70 @@
+/*****************************************************************************
+**
+** Name: bta_gatts_co.h
+**
+** Description: This is the interface file for BTA GATT server call-out
+** functions.
+**
+** Copyright (c) 2010, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_GATTS_CO_H
+#define BTA_GATTS_CO_H
+
+#include "bta_gatt_api.h"
+
+/*******************************************************************************
+**
+** Function bta_gatts_co_update_handle_range
+**
+** Description This callout function is executed by GATTS when a GATT server
+** handle range ios to be added or removed.
+**
+** Parameter is_add: true is to add a handle range; otherwise is to delete.
+** p_hndl_range: handle range.
+**
+** Returns void.
+**
+*******************************************************************************/
+BTA_API extern void bta_gatts_co_update_handle_range(BOOLEAN is_add, tBTA_GATTS_HNDL_RANGE *p_hndl_range);
+
+/*******************************************************************************
+**
+** Function bta_gatts_co_srv_chg
+**
+** Description This call-out is to read/write/remove service change related
+** informaiton. The request consists of the cmd and p_req and the
+** response is returned in p_rsp
+**
+** Parameter cmd - request command
+** p_req - request paramters
+** p_rsp - response data for the request
+**
+** Returns TRUE - if the request is processed successfully and
+** the response is returned in p_rsp.
+** FASLE - if the request can not be processed
+**
+*******************************************************************************/
+BTA_API extern BOOLEAN bta_gatts_co_srv_chg(tBTA_GATTS_SRV_CHG_CMD cmd,
+ tBTA_GATTS_SRV_CHG_REQ *p_req,
+ tBTA_GATTS_SRV_CHG_RSP *p_rsp);
+
+/*******************************************************************************
+**
+** Function bta_gatts_co_load_handle_range
+**
+** Description This callout function is executed by GATTS when a GATT server
+** handle range is requested to be loaded from NV.
+**
+** Parameter
+**
+** Returns void.
+**
+*******************************************************************************/
+BTA_API extern BOOLEAN bta_gatts_co_load_handle_range(UINT8 index,
+ tBTA_GATTS_HNDL_RANGE *p_handle);
+
+
+#endif /* BTA_GATTS_CO_H */
+
diff --git a/bta/include/bta_hd_api.h b/bta/include/bta_hd_api.h
new file mode 100644
index 0000000..5fd7443
--- /dev/null
+++ b/bta/include/bta_hd_api.h
@@ -0,0 +1,289 @@
+/******************************************************************************
+**
+** File Name: bta_hd_api.h
+**
+** Description: This is the interface header file for the HID Device service.
+**
+** Copyright (c) 2002-2004, WIDCOMM Inc., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+******************************************************************************/
+
+#ifndef BTA_HD_API_H
+#define BTA_HD_API_H
+
+#include "bt_types.h"
+#include "bta_api.h"
+#include "hidd_api.h"
+
+/*****************************************************************************/
+/* C O N S T A N T S */
+/*****************************************************************************/
+/* status values */
+#define BTA_HD_SUCCESS 0 /* operation successful */
+#define BTA_HD_FAIL 1 /* generic failure */
+#define BTA_HD_FAIL_SDP 2 /* service not found */
+
+typedef UINT8 tBTA_HD_STATUS;
+
+/* HD callback events */
+#define BTA_HD_ENABLE_EVT 0 /* HD enabled */
+#define BTA_HD_OPEN_EVT 1 /* connection opened */
+#define BTA_HD_CLOSE_EVT 2 /* connection closed */
+#define BTA_HD_UNPLUG_EVT 3 /* unplug */
+#define BTA_HD_DATA_EVT 4 /* Data received */
+#define BTA_HD_DATC_EVT 5 /* Data continueation received */
+
+typedef UINT8 tBTA_HD_EVT;
+
+enum
+{
+ BTA_HD_REPT_ID_SPEC, /* 0 */
+ BTA_HD_REPT_ID_KBD, /* 1: regular keyboard */
+ BTA_HD_REPT_ID_MOUSE, /* 2: mouse */
+ BTA_HD_REPT_ID_CONSUMER
+};
+typedef UINT8 tBTA_HD_REPT_ID;
+#define BTA_HD_REPT_ID_MAX BTA_HD_REPT_ID_CONSUMER
+
+
+#define BTA_HD_KBD_REPT_SIZE 9
+#define BTA_HD_MOUSE_REPT_SIZE 5
+
+
+/* Modifier Keys definition */
+#define BTA_HD_MDF_LCTRL 0x01 /* Left CTRL */
+#define BTA_HD_MDF_LSHIFT 0x02 /* Left SHIFT */
+#define BTA_HD_MDF_LALT 0x04 /* Left ALT */
+#define BTA_HD_MDF_LGUI 0x08 /* Left GUI */
+#define BTA_HD_MDF_RCTRL 0x10 /* Right CTRL */
+#define BTA_HD_MDF_RSHIFT 0x20 /* Right SHIFT */
+#define BTA_HD_MDF_RALT 0x40 /* Right ALT */
+#define BTA_HD_MDF_RGUI 0x80 /* Right GUI */
+
+/* keycode definition -
+ * See USB HID Usage Tables section 10: Keyboard/Keypad Page (0x07) */
+#define BTA_HD_KEYCODE_A 0x04 /* a A */
+#define BTA_HD_KEYCODE_B 0x05 /* b B */
+#define BTA_HD_KEYCODE_C 0x06 /* c C */
+#define BTA_HD_KEYCODE_D 0x07 /* d D */
+#define BTA_HD_KEYCODE_E 0x08 /* e E */
+#define BTA_HD_KEYCODE_F 0x09 /* f F */
+#define BTA_HD_KEYCODE_G 0x0A /* g G */
+#define BTA_HD_KEYCODE_H 0x0B /* h H */
+#define BTA_HD_KEYCODE_I 0x0C /* i I */
+#define BTA_HD_KEYCODE_J 0x0D /* j J */
+#define BTA_HD_KEYCODE_K 0x0E /* k K */
+#define BTA_HD_KEYCODE_L 0x0F /* l L */
+#define BTA_HD_KEYCODE_M 0x10 /* m M */
+#define BTA_HD_KEYCODE_N 0x11 /* n N */
+#define BTA_HD_KEYCODE_O 0x12 /* o O */
+#define BTA_HD_KEYCODE_P 0x13 /* p P */
+#define BTA_HD_KEYCODE_Q 0x14 /* q Q */
+#define BTA_HD_KEYCODE_R 0x15 /* r R */
+#define BTA_HD_KEYCODE_S 0x16 /* s S */
+#define BTA_HD_KEYCODE_T 0x17 /* t T */
+#define BTA_HD_KEYCODE_U 0x18 /* u U */
+#define BTA_HD_KEYCODE_V 0x19 /* v V */
+#define BTA_HD_KEYCODE_W 0x1A /* w W */
+#define BTA_HD_KEYCODE_X 0x1B /* x X */
+#define BTA_HD_KEYCODE_Y 0x1C /* y Y */
+#define BTA_HD_KEYCODE_Z 0x1D /* z Z */
+#define BTA_HD_KEYCODE_1 0x1E /* 1 ! */
+#define BTA_HD_KEYCODE_2 0x1F /* 2 @ */
+#define BTA_HD_KEYCODE_3 0x20 /* 3 # */
+#define BTA_HD_KEYCODE_4 0x21 /* 4 $ */
+#define BTA_HD_KEYCODE_5 0x22 /* 5 % */
+#define BTA_HD_KEYCODE_6 0x23 /* 6 ^ */
+#define BTA_HD_KEYCODE_7 0x24 /* 7 & */
+#define BTA_HD_KEYCODE_8 0x25 /* 8 * */
+#define BTA_HD_KEYCODE_9 0x26 /* 9 ( */
+#define BTA_HD_KEYCODE_0 0x27 /* 0 ) */
+#define BTA_HD_KEYCODE_ENTER 0x28 /* ENTER */
+#define BTA_HD_KEYCODE_ESC 0x29 /* ESC */
+#define BTA_HD_KEYCODE_BACKSPACE 0x2A /* BACKSPACE */
+#define BTA_HD_KEYCODE_TAB 0x2B /* TAB */
+#define BTA_HD_KEYCODE_SPACE 0x2C /* SPACE */
+#define BTA_HD_KEYCODE_MINUS 0x2D /* - _ */
+#define BTA_HD_KEYCODE_EQUAL 0x2E /* = + */
+#define BTA_HD_KEYCODE_LBRACKET 0x2F /* [ { */
+#define BTA_HD_KEYCODE_RBRACKET 0x30 /* ] } */
+#define BTA_HD_KEYCODE_BACKSLASH 0x31 /* \ | */
+#define BTA_HD_KEYCODE_SEMICOLUMN 0x33 /* ; : */
+#define BTA_HD_KEYCODE_QUOTE 0x34 /* ' " */
+#define BTA_HD_KEYCODE_TILT 0x35 /* ` ~ */
+#define BTA_HD_KEYCODE_COMMA 0x36 /* , < */
+#define BTA_HD_KEYCODE_DIR 0x37 /* . > */
+#define BTA_HD_KEYCODE_SLASH 0x38 /* / ? */
+#define BTA_HD_KEYCODE_F1 0x3A /* F1 */
+#define BTA_HD_KEYCODE_F2 0x3B /* F2 */
+#define BTA_HD_KEYCODE_F3 0x3C /* F3 */
+#define BTA_HD_KEYCODE_F4 0x3D /* F4 */
+#define BTA_HD_KEYCODE_F5 0x3E /* F5 */
+#define BTA_HD_KEYCODE_F6 0x3F /* F6 */
+#define BTA_HD_KEYCODE_F7 0x40 /* F7 */
+#define BTA_HD_KEYCODE_F8 0x41 /* F8 */
+#define BTA_HD_KEYCODE_F9 0x42 /* F9 */
+#define BTA_HD_KEYCODE_F10 0x43 /* F10 */
+#define BTA_HD_KEYCODE_F11 0x44 /* F11 */
+#define BTA_HD_KEYCODE_F12 0x45 /* F12 */
+#define BTA_HD_KEYCODE_HOME 0x4A /* HOME */
+#define BTA_HD_KEYCODE_PAGEUP 0x4B /* PAGE UP */
+#define BTA_HD_KEYCODE_END 0x4D /* END */
+#define BTA_HD_KEYCODE_PAGEDOWN 0x4E /* PAGE DOWN */
+#define BTA_HD_KEYCODE_RIGHTARROW 0x4F /* RIGHT ARROW */
+#define BTA_HD_KEYCODE_LEFTARROW 0x50 /* LEFT ARROW */
+#define BTA_HD_KEYCODE_DOWNARROW 0x51 /* DOWN ARROW */
+#define BTA_HD_KEYCODE_UPARROW 0x52 /* UP ARROW */
+#define BTA_HD_KEYCODE_POPUP 0x65 /* POPUP Menu */
+
+/* data associated with BTA_HD_OPEN_EVT */
+typedef struct
+{
+ BD_ADDR bd_addr;
+} tBTA_HD_OPEN;
+
+/* data associated with BTA_HD_ENABLE_EVT */
+typedef struct
+{
+ tBTA_HD_STATUS status;
+} tBTA_HD_ENABLE;
+
+/* data associated with BTA_HD_CLOSE_EVT */
+typedef struct
+{
+ BD_ADDR bd_addr;
+} tBTA_HD_CLOSE;
+
+/* data associated with BTA_HD_REPORT_EVT */
+typedef struct
+{
+ UINT8 *p_data;
+ UINT16 len;
+} tBTA_HD_REPORT;
+/*****************************************************************************/
+/* F U N C T I O N P R O T O T Y P E S */
+/*****************************************************************************/
+/* union of data associated with HD callback */
+typedef union
+{
+ tBTA_HD_ENABLE enable;
+ tBTA_HD_OPEN open;
+ tBTA_HD_CLOSE close;
+ tBTA_HD_REPORT data;
+} tBTA_HD;
+
+/* HD callback */
+typedef void (tBTA_HD_CBACK)(tBTA_HD_EVT event, tBTA_HD *p_data);
+
+/* HD configuration structure */
+typedef struct
+{
+ tHID_DEV_QOS_INFO qos;
+ tHID_DEV_SDP_INFO sdp_info;
+ BOOLEAN use_qos; /* use QoS */
+} tBTA_HD_CFG;
+
+/*******************************************************************************
+**
+** Function BTA_HdEnable
+**
+** Description Enable the HID Device service. When the enable
+** operation is complete the callback function will be
+** called with a BTA_HD_ENABLE_EVT. This function must
+** be called before other function in the HD API are
+** called.
+**
+** If all bytes of the specified bd_addr are 0xff, the
+** peer address is considered as unknown. The HID device listens
+** for incoming connection request.
+** Otherwise, The HID device initiates a connection toward the
+** specified bd_addr when BTA_HdOpen() is called.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API void BTA_HdEnable(BD_ADDR bd_addr, tBTA_SEC sec_mask, const char *p_service_name,
+ tBTA_HD_CBACK *p_cback, UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function BTA_HdDisable
+**
+** Description Disable the HID Device service.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API void BTA_HdDisable(void);
+
+/*******************************************************************************
+**
+** Function BTA_HdOpen
+**
+** Description Opens an HID Device connection to a peer device.
+** When connection is open, callback function is called
+** with a BTA_HD_OPEN_EVT.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API void BTA_HdOpen(tBTA_SEC sec_mask);
+
+/*******************************************************************************
+**
+** Function BTA_HdClose
+**
+** Description Close the current connection a peer device.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API void BTA_HdClose(void);
+
+/*******************************************************************************
+**
+** Function BTA_HdSendRegularKey
+**
+** Description Send a key report to the connected host.
+** If auto_release is TRUE, assume the keyboard report must be
+** a key press. An associated key release report is also sent.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API void BTA_HdSendRegularKey (UINT8 modifier, UINT8 key_code, BOOLEAN auto_release);
+
+/*******************************************************************************
+**
+** Function BTA_HdSendSpecialKey
+**
+** Description Send a special key report to the connected host.
+** The report is sent as a keyboard report.
+** If auto_release is TRUE, assume the keyboard report must be
+** a key press. An associated key release report is also sent.
+** If key_len is less than BTA_HD_KBD_REPT_SIZE, the key_seq
+** is padded with 0 until BTA_HD_KBD_REPT_SIZE.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API void BTA_HdSendSpecialKey (UINT8 key_len, UINT8 * key_seq, BOOLEAN auto_release);
+
+/*******************************************************************************
+**
+** Function BTA_HdSendMouseReport
+**
+** Description Send a mouse report to the connected host
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API void BTA_HdSendMouseReport (UINT8 is_left, UINT8 is_right, UINT8 is_middle,
+ INT8 delta_x, INT8 delta_y, INT8 delta_wheel);
+
+
+#endif /* BTA_HD_API_H */
diff --git a/bta/include/bta_hh_api.h b/bta/include/bta_hh_api.h
new file mode 100644
index 0000000..11dc35e
--- /dev/null
+++ b/bta/include/bta_hh_api.h
@@ -0,0 +1,444 @@
+/****************************************************************************
+**
+** Name: bta_hh_api.h
+**
+** Function: this file contains HID HOST side API definitions
+**
+** Copyright (c) 2002-2004, WIDCOMM Inc., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_HH_API_H
+#define BTA_HH_API_H
+
+#include "bta_api.h"
+#include "hidh_api.h"
+
+/*****************************************************************************
+** Constants and Type Definitions
+*****************************************************************************/
+#ifndef BTA_HH_DEBUG
+#define BTA_HH_DEBUG FALSE
+#endif
+
+#ifndef BTA_HH_SSR_MAX_LATENCY_DEF
+#define BTA_HH_SSR_MAX_LATENCY_DEF 1600
+#endif
+
+#ifndef BTA_HH_SSR_MIN_TOUT_DEF
+#define BTA_HH_SSR_MIN_TOUT_DEF 2
+#endif
+
+/* BTA HID Host callback events */
+#define BTA_HH_ENABLE_EVT 0 /* HH enabled */
+#define BTA_HH_DISABLE_EVT 1 /* HH disabled */
+#define BTA_HH_OPEN_EVT 2 /* connection opened */
+#define BTA_HH_CLOSE_EVT 3 /* connection closed */
+#define BTA_HH_GET_RPT_EVT 4 /* BTA_HhGetReport callback */
+#define BTA_HH_SET_RPT_EVT 5 /* BTA_HhSetReport callback */
+#define BTA_HH_GET_PROTO_EVT 6 /* BTA_GetProtoMode callback */
+#define BTA_HH_SET_PROTO_EVT 7 /* BTA_HhSetProtoMode callback */
+/* leave 8, 9 gap due to deprecate of GET_IDLE and SET_IDLE */
+#define BTA_HH_GET_DSCP_EVT 10 /* Get report descripotor */
+#define BTA_HH_ADD_DEV_EVT 11 /* Add Device callback */
+#define BTA_HH_RMV_DEV_EVT 12 /* remove device finished */
+#define BTA_HH_VC_UNPLUG_EVT 13 /* virtually unplugged */
+#define BTA_HH_UPDATE_UCD_EVT 14
+#define BTA_HH_API_ERR_EVT 15 /* API error is caught */
+
+typedef UINT16 tBTA_HH_EVT;
+
+/* defined the minimum offset */
+#define BTA_HH_MIN_OFFSET L2CAP_MIN_OFFSET+1
+
+#define BTA_HH_MAX_KNOWN HID_HOST_MAX_DEVICES
+/* invalid device handle */
+#define BTA_HH_INVALID_HANDLE 0xff
+
+/* type of protocol mode */
+#define BTA_HH_PROTO_RPT_MODE (0x00)
+#define BTA_HH_PROTO_BOOT_MODE (0x01)
+#define BTA_HH_PROTO_UNKNOWN (0xff)
+typedef UINT8 tBTA_HH_PROTO_MODE;
+
+enum
+{
+ BTA_HH_KEYBD_RPT_ID = 1,
+ BTA_HH_MOUSE_RPT_ID
+};
+typedef UINT8 tBTA_HH_BOOT_RPT_ID;
+
+/* type of devices, bit mask */
+#define BTA_HH_DEVT_UNKNOWN 0x00
+#define BTA_HH_DEVT_JOS 0x01 /* joy stick */
+#define BTA_HH_DEVT_GPD 0x02 /* game pad */
+#define BTA_HH_DEVT_RMC 0x03 /* remote control */
+#define BTA_HH_DEVT_SED 0x04 /* sensing device */
+#define BTA_HH_DEVT_DGT 0x05 /* Digitizer tablet */
+#define BTA_HH_DEVT_CDR 0x06 /* card reader */
+#define BTA_HH_DEVT_KBD 0x10 /* keyboard */
+#define BTA_HH_DEVT_MIC 0x20 /* pointing device */
+#define BTA_HH_DEVT_COM 0x30 /* Combo keyboard/pointing */
+#define BTA_HH_DEVT_OTHER 0x80
+typedef UINT8 tBTA_HH_DEVT;
+
+enum
+{
+ BTA_HH_OK,
+ BTA_HH_HS_HID_NOT_READY, /* handshake error : device not ready */
+ BTA_HH_HS_INVALID_RPT_ID, /* handshake error : invalid report ID */
+ BTA_HH_HS_TRANS_NOT_SPT, /* handshake error : transaction not spt */
+ BTA_HH_HS_INVALID_PARAM, /* handshake error : invalid paremter */
+ BTA_HH_HS_ERROR, /* handshake error : unspecified HS error */
+ BTA_HH_ERR, /* general BTA HH error */
+ BTA_HH_ERR_SDP, /* SDP error */
+ BTA_HH_ERR_PROTO, /* SET_Protocol error,
+ only used in BTA_HH_OPEN_EVT callback */
+ BTA_HH_ERR_DB_FULL, /* device database full error, used in
+ BTA_HH_OPEN_EVT/BTA_HH_ADD_DEV_EVT */
+ BTA_HH_ERR_TOD_UNSPT, /* type of device not supported */
+ BTA_HH_ERR_NO_RES, /* out of system resources */
+ BTA_HH_ERR_AUTH_FAILED, /* authentication fail */
+ BTA_HH_ERR_HDL
+};
+typedef UINT8 tBTA_HH_STATUS;
+
+
+#define BTA_HH_VIRTUAL_CABLE HID_VIRTUAL_CABLE
+#define BTA_HH_NORMALLY_CONNECTABLE HID_NORMALLY_CONNECTABLE
+#define BTA_HH_RECONN_INIT HID_RECONN_INIT
+#define BTA_HH_SDP_DISABLE HID_SDP_DISABLE
+#define BTA_HH_BATTERY_POWER HID_BATTERY_POWER
+#define BTA_HH_REMOTE_WAKE HID_REMOTE_WAKE
+#define BTA_HH_SUP_TOUT_AVLBL HID_SUP_TOUT_AVLBL
+#define BTA_HH_SEC_REQUIRED HID_SEC_REQUIRED
+typedef UINT16 tBTA_HH_ATTR_MASK;
+
+
+/* supported type of device and corresponding application ID */
+typedef struct
+{
+ tBTA_HH_DEVT tod; /* type of device */
+ UINT8 app_id; /* corresponding application ID */
+}tBTA_HH_SPT_TOD;
+
+/* configuration struct */
+typedef struct
+{
+ UINT8 max_devt_spt; /* max number of types of devices spt */
+ tBTA_HH_SPT_TOD *p_devt_list; /* supported types of device list */
+ UINT16 sdp_db_size;
+}tBTA_HH_CFG;
+
+enum
+{
+ BTA_HH_RPTT_RESRV, /* reserved */
+ BTA_HH_RPTT_INPUT, /* input report */
+ BTA_HH_RPTT_OUTPUT, /* output report */
+ BTA_HH_RPTT_FEATURE /* feature report */
+};
+typedef UINT8 tBTA_HH_RPT_TYPE;
+
+/* HID_CONTROL operation code used in BTA_HhSendCtrl()
+*/
+enum
+{
+ BTA_HH_CTRL_NOP = 0 + HID_PAR_CONTROL_NOP ,/* mapping from BTE */
+ BTA_HH_CTRL_HARD_RESET, /* hard reset */
+ BTA_HH_CTRL_SOFT_RESET, /* soft reset */
+ BTA_HH_CTRL_SUSPEND, /* enter suspend */
+ BTA_HH_CTRL_EXIT_SUSPEND, /* exit suspend */
+ BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG /* virtual unplug */
+};
+typedef UINT8 tBTA_HH_TRANS_CTRL_TYPE;
+
+typedef tHID_DEV_DSCP_INFO tBTA_HH_DEV_DESCR;
+
+/* report descriptor information */
+typedef struct
+{
+ UINT16 vendor_id; /* vendor ID */
+ UINT16 product_id; /* product ID */
+ UINT16 version; /* version */
+ UINT16 ssr_max_latency; /* SSR max latency */
+ UINT16 ssr_min_tout; /* SSR min timeout */
+ UINT8 ctry_code; /*Country Code.*/
+ tBTA_HH_DEV_DESCR descriptor;
+}tBTA_HH_DEV_DSCP_INFO;
+
+/* callback event data for BTA_HH_OPEN_EVT */
+typedef struct
+{
+ BD_ADDR bda; /* HID device bd address */
+ tBTA_HH_STATUS status; /* operation status */
+ UINT8 handle; /* device handle */
+} tBTA_HH_CONN;
+
+typedef tBTA_HH_CONN tBTA_HH_DEV_INFO;
+
+/* callback event data */
+typedef struct
+{
+ tBTA_HH_STATUS status; /* operation status */
+ UINT8 handle; /* device handle */
+} tBTA_HH_CBDATA;
+
+enum
+{
+ BTA_HH_MOD_CTRL_KEY,
+ BTA_HH_MOD_SHFT_KEY,
+ BTA_HH_MOD_ALT_KEY,
+ BTA_HH_MOD_GUI_KEY,
+ BTA_HH_MOD_MAX_KEY
+};
+
+/* parsed boot mode keyboard report */
+typedef struct
+{
+ UINT8 this_char[6]; /* virtual key code */
+ BOOLEAN mod_key[BTA_HH_MOD_MAX_KEY];
+ /* ctrl, shift, Alt, GUI */
+ /* modifier key: is Shift key pressed */
+ /* modifier key: is Ctrl key pressed */
+ /* modifier key: is Alt key pressed */
+ /* modifier key: GUI up/down */
+ BOOLEAN caps_lock; /* is caps locked */
+ BOOLEAN num_lock; /* is Num key pressed */
+} tBTA_HH_KEYBD_RPT;
+
+/* parsed boot mode mouse report */
+typedef struct
+{
+ UINT8 mouse_button; /* mouse button is clicked */
+ INT8 delta_x; /* displacement x */
+ INT8 delta_y; /* displacement y */
+}tBTA_HH_MICE_RPT;
+
+/* parsed Boot report */
+typedef struct
+{
+ tBTA_HH_BOOT_RPT_ID dev_type; /* type of device report */
+ union
+ {
+ tBTA_HH_KEYBD_RPT keybd_rpt; /* keyboard report */
+ tBTA_HH_MICE_RPT mice_rpt; /* mouse report */
+ } data_rpt;
+} tBTA_HH_BOOT_RPT;
+
+/* handshake data */
+typedef struct
+{
+ tBTA_HH_STATUS status; /* handshake status */
+ UINT8 handle; /* device handle */
+ union
+ {
+ tBTA_HH_PROTO_MODE proto_mode; /* GET_PROTO_EVT :protocol mode */
+ BT_HDR *p_rpt_data; /* GET_RPT_EVT : report data */
+ UINT8 idle_rate; /* GET_IDLE_EVT : idle rate */
+ } rsp_data;
+
+}tBTA_HH_HSDATA;
+
+/* union of data associated with HD callback */
+typedef union
+{
+ tBTA_HH_DEV_INFO dev_info; /* BTA_HH_ADD_DEV_EVT, BTA_HH_RMV_DEV_EVT */
+ tBTA_HH_CONN conn; /* BTA_HH_OPEN_EVT */
+ tBTA_HH_CBDATA dev_status; /* BTA_HH_CLOSE_EVT,
+ BTA_HH_SET_PROTO_EVT
+ BTA_HH_SET_RPT_EVT
+ BTA_HH_SET_IDLE_EVT */
+
+ tBTA_HH_STATUS status; /* BTA_HH_ENABLE_EVT */
+ tBTA_HH_DEV_DSCP_INFO dscp_info; /* BTA_HH_GET_DSCP_EVT */
+ tBTA_HH_HSDATA hs_data; /* GET_ transaction callback
+ BTA_HH_GET_RPT_EVT
+ BTA_HH_GET_PROTO_EVT
+ BTA_HH_GET_IDLE_EVT */
+} tBTA_HH;
+
+/* BTA HH callback function */
+typedef void (tBTA_HH_CBACK) (tBTA_HH_EVT event, tBTA_HH *p_data);
+
+
+/*****************************************************************************
+** External Function Declarations
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*******************************************************************************
+**
+** Function BTA_HhRegister
+**
+** Description This function enable HID host and registers HID-Host with
+** lower layers.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_HhEnable(tBTA_SEC sec_mask, BOOLEAN ucd_enabled, tBTA_HH_CBACK *p_cback);
+
+/*******************************************************************************
+**
+** Function BTA_HhDeregister
+**
+** Description This function is called when the host is about power down.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_HhDisable(void);
+
+/*******************************************************************************
+**
+** Function BTA_HhOpen
+**
+** Description This function is called to start an inquiry and read SDP
+** record of responding devices; connect to a device if only
+** one active HID device is found.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_HhOpen (BD_ADDR dev_bda, tBTA_HH_PROTO_MODE mode,
+ tBTA_SEC sec_mask);
+
+/*******************************************************************************
+**
+** Function BTA_HhClose
+**
+** Description This function disconnects the device.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_HhClose(UINT8 dev_handle);
+
+/*******************************************************************************
+**
+** Function BTA_HhSetProtoMode
+**
+** Description This function set the protocol mode at specified HID handle
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_HhSetProtoMode(UINT8 handle, tBTA_HH_PROTO_MODE t_type);
+
+/*******************************************************************************
+**
+** Function BTA_HhGetProtoMode
+**
+** Description This function get the protocol mode of a specified HID device.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_HhGetProtoMode(UINT8 dev_handle);
+/*******************************************************************************
+**
+** Function BTA_HhSetReport
+**
+** Description send SET_REPORT to device.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_HhSetReport(UINT8 dev_handle, tBTA_HH_RPT_TYPE r_type,
+ BT_HDR *p_data);
+
+/*******************************************************************************
+**
+** Function BTA_HhGetReport
+**
+** Description Send a GET_REPORT to HID device.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_HhGetReport(UINT8 dev_handle, tBTA_HH_RPT_TYPE r_type,
+ UINT8 rpt_id, UINT16 buf_size);
+/*******************************************************************************
+**
+** Function BTA_HhSendCtrl
+**
+** Description Send HID_CONTROL request to a HID device.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_HhSendCtrl(UINT8 dev_handle,
+ tBTA_HH_TRANS_CTRL_TYPE c_type);
+
+/*******************************************************************************
+**
+** Function BTA_HhSendData
+**
+** Description Send DATA transaction to a HID device.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_HhSendData(UINT8 dev_handle, BD_ADDR dev_bda, BT_HDR *p_buf);
+
+/*******************************************************************************
+**
+** Function BTA_HhGetDscpInfo
+**
+** Description Get report descriptor of the device
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_HhGetDscpInfo(UINT8 dev_handle);
+
+/*******************************************************************************
+**
+** Function BTA_HhAddDev
+**
+** Description Add a virtually cabled device into HID-Host device list
+** to manage and assign a device handle for future API call,
+** host applciation call this API at start-up to initialize its
+** virtually cabled devices.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_HhAddDev(BD_ADDR bda, tBTA_HH_ATTR_MASK attr_mask,
+ UINT8 sub_class, UINT8 app_id,
+ tBTA_HH_DEV_DSCP_INFO dscp_info);
+/*******************************************************************************
+**
+** Function BTA_HhRemoveDev
+**
+** Description Remove a device from the HID host devices list.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_HhRemoveDev(UINT8 dev_handle );
+/*******************************************************************************
+**
+** Parsing Utility Functions
+**
+*******************************************************************************/
+/*******************************************************************************
+**
+** Function BTA_HhParseBootRpt
+**
+** Description This utility function parse a boot mode report.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_HhParseBootRpt(tBTA_HH_BOOT_RPT *p_data, UINT8 *p_report,
+ UINT16 report_len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_HH_API_H */
diff --git a/bta/include/bta_hh_co.h b/bta/include/bta_hh_co.h
new file mode 100644
index 0000000..37d27ea
--- /dev/null
+++ b/bta/include/bta_hh_co.h
@@ -0,0 +1,60 @@
+/*****************************************************************************
+**
+** Name: bta_hh_co.h
+**
+** Description: This is the interface file for hid host call-out
+** functions.
+**
+** Copyright (c) 2005, Broadcom Corp., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_HH_CO_H
+#define BTA_HH_CO_H
+
+#include "bta_hh_api.h"
+
+
+/*******************************************************************************
+**
+** Function bta_hh_co_data
+**
+** Description This callout function is executed by HH when data is received
+** in interupt channel.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+BTA_API extern void bta_hh_co_data(UINT8 dev_handle, UINT8 *p_rpt, UINT16 len,
+ tBTA_HH_PROTO_MODE mode, UINT8 sub_class,
+ UINT8 ctry_code, BD_ADDR peer_addr, UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function bta_hh_co_open
+**
+** Description This callout function is executed by HH when connection is
+** opened, and application may do some device specific
+** initialization.
+**
+** Returns void.
+**
+*******************************************************************************/
+BTA_API extern void bta_hh_co_open(UINT8 dev_handle, UINT8 sub_class,
+ UINT16 attr_mask, UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function bta_hh_co_close
+**
+** Description This callout function is executed by HH when connection is
+** closed, and device specific finalizatio nmay be needed.
+**
+** Returns void.
+**
+*******************************************************************************/
+BTA_API extern void bta_hh_co_close(UINT8 dev_handle, UINT8 app_id);
+
+#endif /* BTA_HH_CO_H */
+
diff --git a/bta/include/bta_hl_api.h b/bta/include/bta_hl_api.h
new file mode 100644
index 0000000..a9cd312
--- /dev/null
+++ b/bta/include/bta_hl_api.h
@@ -0,0 +1,895 @@
+/*****************************************************************************
+**
+** Name: bta_hl_api.h
+**
+** Description: This is the public interface file for the HeaLth device profile
+** (HL) subsystem of BTA, Broadcom's
+** Bluetooth application layer for mobile phones.
+**
+** Copyright (c) 2009, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_HL_API_H
+#define BTA_HL_API_H
+
+#include "bta_api.h"
+#include "btm_api.h"
+#include "mca_api.h"
+
+/*****************************************************************************
+** Constants and data types
+*****************************************************************************/
+/* Extra Debug Code */
+#ifndef BTA_HL_DEBUG
+#define BTA_HL_DEBUG TRUE
+#endif
+
+#ifndef BTA_HL_NUM_APPS
+#define BTA_HL_NUM_APPS 3
+#endif
+
+#ifndef BTA_HL_NUM_MDEPS
+#define BTA_HL_NUM_MDEPS 5
+#endif
+
+#ifndef BTA_HL_NUM_MCLS
+#define BTA_HL_NUM_MCLS 7
+#endif
+
+#ifndef BTA_HL_NUM_MDLS_PER_MDEP
+#define BTA_HL_NUM_MDLS_PER_MDEP 4
+#endif
+
+#ifndef BTA_HL_NUM_MDLS_PER_MCL
+#define BTA_HL_NUM_MDLS_PER_MCL 10
+#endif
+
+#ifndef BTA_HL_NUM_DATA_TYPES
+#define BTA_HL_NUM_DATA_TYPES 5 /* maximum number of data types can be supported
+ per MDEP ID */
+#endif
+
+#define BTA_HL_MCAP_RSP_TOUT 2 /* 2 seconds */
+
+#ifndef BTA_HL_CCH_NUM_FILTER_ELEMS
+#define BTA_HL_CCH_NUM_FILTER_ELEMS 3
+#endif
+
+#ifndef BTA_HL_NUM_SDP_CBACKS
+#define BTA_HL_NUM_SDP_CBACKS 7
+#endif
+
+#ifndef BTA_HL_NUM_SDP_RECS
+#define BTA_HL_NUM_SDP_RECS 3
+#endif
+
+#ifndef BTA_HL_NUM_SDP_MDEPS
+#define BTA_HL_NUM_SDP_MDEPS 10
+#endif
+
+#ifndef BTA_HL_NUM_SVC_ELEMS
+#define BTA_HL_NUM_SVC_ELEMS 2
+#endif
+
+#ifndef BTA_HL_NUM_PROTO_ELEMS
+#define BTA_HL_NUM_PROTO_ELEMS 2
+#endif
+
+#define BTA_HL_VERSION_01_00 0x0100
+#define BTA_HL_NUM_ADD_PROTO_LISTS 1
+#define BTA_HL_NUM_ADD_PROTO_ELEMS 2
+#define BTA_HL_MDEP_SEQ_SIZE 20
+#define BTA_HL_VAL_ARRY_SIZE 320
+
+#ifndef BTA_HL_NUM_MDL_CFGS
+#define BTA_HL_NUM_MDL_CFGS 16 /* numer of MDL cfg saved in the persistent memory*/
+#endif
+
+#define BTA_HL_NUM_TIMERS 7
+
+#define BTA_HL_CCH_RSP_TOUT 2000
+#define BTA_HL_LRG_POOL_ID GKI_POOL_ID_7
+#define BTA_HL_MAX_TIME 255
+#define BTA_HL_MIN_TIME 1
+#define BTA_HL_INVALID_APP_HANDLE 0xFF
+#define BTA_HL_INVALID_MCL_HANDLE 0xFF
+#define BTA_HL_INVALID_MDL_HANDLE 0xFFFF
+
+#define BTA_HL_STATUS_OK 0
+#define BTA_HL_STATUS_FAIL 1 /* Used to pass all other errors */
+#define BTA_HL_STATUS_ABORTED 2
+#define BTA_HL_STATUS_NO_RESOURCE 3
+#define BTA_HL_STATUS_LAST_ITEM 4
+#define BTA_HL_STATUS_DUPLICATE_APP_ID 5
+#define BTA_HL_STATUS_INVALID_APP_HANDLE 6
+#define BTA_HL_STATUS_INVALID_MCL_HANDLE 7
+#define BTA_HL_STATUS_MCAP_REG_FAIL 8
+#define BTA_HL_STATUS_MDEP_CO_FAIL 9
+#define BTA_HL_STATUS_ECHO_CO_FAIL 10
+#define BTA_HL_STATUS_MDL_CFG_CO_FAIL 11
+#define BTA_HL_STATUS_SDP_NO_RESOURCE 12
+#define BTA_HL_STATUS_SDP_FAIL 13
+#define BTA_HL_STATUS_NO_CCH 14
+#define BTA_HL_STATUS_NO_MCL 15
+
+#define BTA_HL_STATUS_NO_FIRST_RELIABLE 17
+#define BTA_HL_STATUS_INVALID_DCH_CFG 18
+#define BTA_HL_STATUS_INVALID_MDL_HANDLE 19
+#define BTA_HL_STATUS_INVALID_BD_ADDR 20
+#define BTA_HL_STATUS_INVALID_RECONNECT_CFG 21
+#define BTA_HL_STATUS_ECHO_TEST_BUSY 22
+#define BTA_HL_STATUS_INVALID_LOCAL_MDEP_ID 23
+#define BTA_HL_STATUS_INVALID_MDL_ID 24
+#define BTA_HL_STATUS_NO_MDL_ID_FOUND 25
+#define BTA_HL_STATUS_DCH_BUSY 26 /* DCH is congested*/
+#define BTA_HL_STATUS_INVALID_CTRL_PSM 27
+
+typedef UINT8 tBTA_HL_STATUS;
+typedef tMCA_HANDLE tBTA_HL_APP_HANDLE;
+typedef tMCA_CL tBTA_HL_MCL_HANDLE;
+typedef tMCA_DL tBTA_HL_MDL_HANDLE;
+enum
+{
+ BTA_HL_DEVICE_TYPE_SINK,
+ BTA_HL_DEVICE_TYPE_SOURCE,
+ BTA_HL_DEVICE_TYPE_DUAL
+};
+
+typedef UINT8 tBTA_HL_DEVICE_TYPE;
+
+
+
+#define BTA_HL_SDP_IEEE_11073_20601 0x01
+
+#define BTA_HL_MCAP_SUP_RECONNECT_MASK_INIT 2 /* 0x02 */
+#define BTA_HL_MCAP_SUP_RECONNECT_MASK_ACCEPT 4 /* 0x04 */
+#define BTA_HL_MCAP_SUP_CSP_MASK_SYNC_SLAVE 0 /* 0x08 */
+#define BTA_HL_MCAP_SUP_CSP_MASK_SYNC_MASTER 0 /* 0x10 */
+
+#define BTA_HL_MCAP_SUP_PROC_MASK (BTA_HL_MCAP_SUP_RECONNECT_MASK_INIT | \
+ BTA_HL_MCAP_SUP_RECONNECT_MASK_ACCEPT | \
+ BTA_HL_MCAP_SUP_CSP_MASK_SYNC_SLAVE | \
+ BTA_HL_MCAP_SUP_CSP_MASK_SYNC_MASTER)
+#define BTA_HL_MDEP_ROLE_SOURCE 0x00
+#define BTA_HL_MDEP_ROLE_SINK 0x01
+
+typedef UINT8 tBTA_HL_MDEP_ROLE;
+
+#define BTA_HL_MDEP_ROLE_MASK_SOURCE 0x01 /* bit mask */
+#define BTA_HL_MDEP_ROLE_MASK_SINK 0x02
+typedef UINT8 tBTA_HL_MDEP_ROLE_MASK;
+
+
+#define BTA_HL_ECHO_TEST_MDEP_ID 0
+#define BTA_HL_ECHO_TEST_MDEP_CFG_IDX 0
+
+#define BTA_HL_INVALID_MDEP_ID 0xFF
+typedef tMCA_DEP tBTA_HL_MDEP_ID; /* 0 is for echo test,
+ 0x01-0x7F availave for use,
+ 0x80-0xFF reserved*/
+
+
+#define BTA_HL_DELETE_ALL_MDL_IDS 0xFFFF
+#define BTA_HL_MAX_MDL_VAL 0xFEFF
+typedef UINT16 tBTA_HL_MDL_ID; /* 0x0000 reserved,
+ 0x0001-0xFEFF dynamic range,
+ 0xFF00-0xFFFE reserved,
+ 0xFFFF indicates all MDLs*/
+
+#define BTA_HL_MDEP_DESP_LEN 35
+
+#define BTA_HL_DCH_MODE_RELIABLE 0
+#define BTA_HL_DCH_MODE_STREAMING 1
+
+typedef UINT8 tBTA_HL_DCH_MODE;
+
+#define BTA_HL_DCH_CFG_NO_PREF 0
+#define BTA_HL_DCH_CFG_RELIABLE 1
+#define BTA_HL_DCH_CFG_STREAMING 2
+#define BTA_HL_DCH_CFG_UNKNOWN 0xFF
+
+typedef UINT8 tBTA_HL_DCH_CFG;
+
+/* The Default DCH CFG for the echo test when the device is a Source */
+#define BTA_HL_DEFAULT_ECHO_TEST_SRC_DCH_CFG BTA_HL_DCH_CFG_RELIABLE
+
+#define BTA_HL_DCH_CREATE_RSP_SUCCESS 0
+#define BTA_HL_DCH_CREATE_RSP_CFG_REJ 1
+
+typedef UINT8 tBTA_HL_DCH_CREATE_RSP;
+
+#define BTA_HL_MCAP_SUP_PROC_RECONNECT_INIT 0x02
+#define BTA_HL_MCAP_SUP_PROC_RECONNECT_APT 0x04
+#define BTA_HL_MCAP_SUP_PROC_CSP_SLAVE 0x08
+#define BTA_HL_MCAP_SUP_PROC_CSP_MASTER 0x10
+
+typedef UINT8 tBTA_HL_SUP_PROC_MASK;
+
+typedef struct
+{
+ UINT16 max_rx_apdu_size; /* local rcv MTU */
+ UINT16 max_tx_apdu_size; /* maximum TX APDU size*/
+} tBTA_HL_ECHO_CFG;
+
+
+typedef struct
+{
+ UINT16 data_type;
+ UINT16 max_rx_apdu_size; /* local rcv MTU */
+ UINT16 max_tx_apdu_size; /* maximum TX APDU size*/
+ char desp[BTA_HL_MDEP_DESP_LEN+1];
+} tBTA_HL_MDEP_DATA_TYPE_CFG;
+
+
+typedef struct
+{
+ tBTA_HL_MDEP_ROLE mdep_role;
+ UINT8 num_of_mdep_data_types;
+ tBTA_HL_MDEP_DATA_TYPE_CFG data_cfg[BTA_HL_NUM_DATA_TYPES];
+} tBTA_HL_MDEP_CFG;
+
+typedef struct
+{
+ tBTA_HL_MDEP_ID mdep_id; /* MDEP ID 0x01-0x7F */
+ tBTA_HL_MDEP_CFG mdep_cfg;
+} tBTA_HL_MDEP;
+
+typedef struct
+{
+ tBTA_HL_MDEP mdep[BTA_HL_NUM_MDEPS];
+ tBTA_HL_ECHO_CFG echo_cfg;
+ tBTA_HL_MDEP_ROLE_MASK app_role_mask;
+ BOOLEAN advertize_source_sdp;
+ UINT8 num_of_mdeps;
+} tBTA_HL_SUP_FEATURE;
+
+typedef struct
+{
+ BOOLEAN delete_req_pending;
+ tBTA_HL_MDL_ID mdl_id;
+ tBTA_HL_MCL_HANDLE mcl_handle;
+} tBTA_HL_DELETE_MDL;
+
+typedef struct
+{
+ UINT8 time;
+ UINT16 mtu;
+ tBTA_HL_MDL_ID mdl_id;
+ tBTA_HL_MDEP_ID local_mdep_id;
+ tBTA_HL_MDEP_ROLE local_mdep_role;
+ BOOLEAN active; /* true if this item is in use */
+ tBTA_HL_DCH_MODE dch_mode;
+ UINT8 fcs;
+ BD_ADDR peer_bd_addr;
+} tBTA_HL_MDL_CFG;
+
+
+/* Maximum number of supported feature list items (list_elem in tSDP_SUP_FEATURE_ELEM) */
+#define BTA_HL_NUM_SUP_FEATURE_ELEMS 10
+#define BTA_HL_SUP_FEATURE_SDP_BUF_SIZE 512
+/* This structure is used to add supported feature lists and find supported feature elements */
+typedef struct
+{
+ UINT8 mdep_id;
+ UINT16 data_type;
+ tBTA_HL_MDEP_ROLE mdep_role;
+ char *p_mdep_desp;
+} tBTA_HL_SUP_FEATURE_ELEM;
+
+typedef struct
+{
+ UINT16 num_elems;
+ tBTA_HL_SUP_FEATURE_ELEM list_elem[BTA_HL_NUM_SUP_FEATURE_ELEMS];
+} tBTA_HL_SUP_FEATURE_LIST_ELEM;
+
+
+typedef struct
+{
+ tBTA_HL_DEVICE_TYPE dev_type; /* sink, source or dual roles */
+ tBTA_SEC sec_mask; /* security mask for accepting conenction*/
+ const char *p_srv_name; /* service name to be used in the SDP; null terminated*/
+ const char *p_srv_desp; /* service description to be used in the SDP; null terminated */
+ const char *p_provider_name; /* provide name to be used in the SDP; null terminated */
+} tBTA_HL_REG_PARAM;
+
+typedef struct
+{
+ UINT16 ctrl_psm;
+ BD_ADDR bd_addr; /* Address of peer device */
+ tBTA_SEC sec_mask; /* security mask for initiating connection*/
+} tBTA_HL_CCH_OPEN_PARAM;
+
+
+typedef struct
+{
+ UINT16 ctrl_psm;
+ tBTA_HL_MDEP_ID local_mdep_id; /* local MDEP ID */
+ tBTA_HL_MDEP_ID peer_mdep_id; /* peer mdep id */
+ tBTA_HL_DCH_CFG local_cfg;
+ tBTA_SEC sec_mask; /* security mask for initiating connection*/
+} tBTA_HL_DCH_OPEN_PARAM;
+
+
+typedef struct
+{
+ UINT16 ctrl_psm;
+ tBTA_HL_MDL_ID mdl_id;
+} tBTA_HL_DCH_RECONNECT_PARAM;
+
+
+typedef struct
+{
+ UINT16 ctrl_psm;
+ UINT16 pkt_size;
+ tBTA_HL_DCH_CFG local_cfg;
+} tBTA_HL_DCH_ECHO_TEST_PARAM;
+
+typedef struct
+{
+ UINT16 buf_size;
+ UINT8 p_buf; /* buffer pointer */
+} tBTA_HL_DCH_BUF_INFO;
+
+typedef struct
+{
+ tBTA_HL_MDEP_ID local_mdep_id; /* local MDEP ID */
+ tBTA_HL_MDL_ID mdl_id;
+ tBTA_HL_DCH_CREATE_RSP rsp_code;
+ tBTA_HL_DCH_CFG cfg_rsp;
+} tBTA_HL_DCH_CREATE_RSP_PARAM;
+
+typedef struct
+{
+ UINT16 data_type;
+ UINT8 mdep_id;
+ tBTA_HL_MDEP_ROLE mdep_role;
+ char mdep_desp[BTA_HL_MDEP_DESP_LEN+1];
+}tBTA_HL_SDP_MDEP_CFG;
+
+typedef struct
+{
+ UINT16 ctrl_psm;
+ UINT16 data_psm;
+ UINT8 mcap_sup_proc;
+ UINT8 num_mdeps; /* number of mdep elements from SDP*/
+ char srv_name[BTA_SERVICE_NAME_LEN+1];
+ char srv_desp[BTA_SERVICE_DESP_LEN+1];
+ char provider_name[BTA_PROVIDER_NAME_LEN+1];
+ tBTA_HL_SDP_MDEP_CFG mdep_cfg[BTA_HL_NUM_SDP_MDEPS];
+} tBTA_HL_SDP_REC;
+
+typedef struct
+{
+ UINT8 num_recs;
+ tBTA_HL_SDP_REC sdp_rec[BTA_HL_NUM_SDP_RECS];
+} tBTA_HL_SDP;
+
+/* HL control callback function events */
+enum
+{
+ BTA_HL_CTRL_ENABLE_CFM_EVT = 0,
+ BTA_HL_CTRL_DISABLE_CFM_EVT
+};
+typedef UINT8 tBTA_HL_CTRL_EVT;
+/* Structure associated with BTA_HL_ENABLE_EVT
+ BTA_HL_DISABLE_EVT */
+
+typedef struct
+{
+ tBTA_HL_STATUS status;
+} tBTA_HL_CTRL_ENABLE_DISABLE;
+
+typedef union
+{
+ tBTA_HL_CTRL_ENABLE_DISABLE enable_cfm;
+ tBTA_HL_CTRL_ENABLE_DISABLE disable_cfm;
+} tBTA_HL_CTRL;
+
+/* HL instance callback function events */
+enum
+{
+ BTA_HL_REGISTER_CFM_EVT =0,
+ BTA_HL_DEREGISTER_CFM_EVT,
+ BTA_HL_CCH_OPEN_IND_EVT,
+ BTA_HL_CCH_OPEN_CFM_EVT,
+ BTA_HL_CCH_CLOSE_IND_EVT,
+ BTA_HL_CCH_CLOSE_CFM_EVT,
+ BTA_HL_DCH_CREATE_IND_EVT,
+ BTA_HL_DCH_OPEN_IND_EVT,
+ BTA_HL_DCH_OPEN_CFM_EVT,
+ BTA_HL_DCH_CLOSE_IND_EVT,
+ BTA_HL_DCH_CLOSE_CFM_EVT,
+ BTA_HL_DCH_RECONNECT_IND_EVT,
+ BTA_HL_DCH_RECONNECT_CFM_EVT,
+
+ BTA_HL_DCH_ABORT_IND_EVT,
+ BTA_HL_DCH_ABORT_CFM_EVT,
+ BTA_HL_DELETE_MDL_IND_EVT,
+ BTA_HL_DELETE_MDL_CFM_EVT,
+ BTA_HL_DCH_SEND_DATA_CFM_EVT,
+ BTA_HL_DCH_RCV_DATA_IND_EVT,
+ BTA_HL_CONG_CHG_IND_EVT,
+ BTA_HL_DCH_ECHO_TEST_CFM_EVT,
+ BTA_HL_SDP_QUERY_CFM_EVT,
+ BTA_HL_SDP_INFO_IND_EVT
+};
+typedef UINT8 tBTA_HL_EVT;
+
+
+typedef struct
+{
+ tBTA_HL_STATUS status; /* start status */
+ UINT8 app_id;
+ tBTA_HL_APP_HANDLE app_handle;
+} tBTA_HL_REGISTER_CFM;
+
+
+typedef struct
+{
+ tBTA_HL_STATUS status; /* start status */
+ tBTA_HL_APP_HANDLE app_handle;
+} tBTA_HL_DEREGISTER_CFM;
+
+
+typedef struct
+{
+ BOOLEAN intentional;
+ tBTA_HL_MCL_HANDLE mcl_handle;
+ tBTA_HL_APP_HANDLE app_handle;
+} tBTA_HL_CCH_CLOSE_IND;
+
+
+typedef struct
+{
+ tBTA_HL_MCL_HANDLE mcl_handle;
+ tBTA_HL_APP_HANDLE app_handle;
+} tBTA_HL_MCL_IND;
+
+typedef struct
+{
+ tBTA_HL_STATUS status; /* connection status */
+ tBTA_HL_MCL_HANDLE mcl_handle;
+ tBTA_HL_APP_HANDLE app_handle;
+} tBTA_HL_MCL_CFM;
+
+typedef struct
+{
+ tBTA_HL_MCL_HANDLE mcl_handle;
+ tBTA_HL_APP_HANDLE app_handle;
+ BD_ADDR bd_addr; /* address of peer device */
+} tBTA_HL_CCH_OPEN_IND;
+
+typedef struct
+{
+ tBTA_HL_STATUS status; /* connection status */
+ tBTA_HL_MCL_HANDLE mcl_handle;
+ tBTA_HL_APP_HANDLE app_handle;
+ BD_ADDR bd_addr; /* address of peer device */
+} tBTA_HL_CCH_OPEN_CFM;
+
+typedef struct
+{
+ tBTA_HL_MCL_HANDLE mcl_handle;
+ tBTA_HL_APP_HANDLE app_handle;
+ tBTA_HL_MDEP_ID local_mdep_id;
+ tBTA_HL_MDL_ID mdl_id; /* MCAP data link ID for this
+ data channel conenction */
+ tBTA_HL_DCH_CFG cfg; /* dch cfg requested by the peer device */
+} tBTA_HL_DCH_CREATE_IND;
+
+typedef struct
+{
+ tBTA_HL_MDL_HANDLE mdl_handle;
+ tBTA_HL_MCL_HANDLE mcl_handle;
+ tBTA_HL_APP_HANDLE app_handle;
+ tBTA_HL_MDEP_ID local_mdep_id;
+ tBTA_HL_MDL_ID mdl_id; /* MCAP data link ID for this
+ data channel conenction */
+ tBTA_HL_DCH_MODE dch_mode; /* data channel mode - reliable or streaming*/
+
+ BOOLEAN first_reliable; /* whether this is the first reliable data channel */
+ UINT16 mtu;
+} tBTA_HL_DCH_OPEN_IND;
+
+typedef struct
+{
+ tBTA_HL_STATUS status; /* connection status */
+ tBTA_HL_MDL_HANDLE mdl_handle;
+ tBTA_HL_MCL_HANDLE mcl_handle;
+ tBTA_HL_APP_HANDLE app_handle;
+ tBTA_HL_MDEP_ID local_mdep_id;
+ tBTA_HL_MDL_ID mdl_id; /* MCAP data link ID for this
+ data channel conenction */
+ tBTA_HL_DCH_MODE dch_mode; /* data channel mode - reliable or streaming*/
+ BOOLEAN first_reliable; /* whether this is the first reliable data channel */
+ UINT16 mtu;
+} tBTA_HL_DCH_OPEN_CFM;
+
+
+typedef struct
+{
+ BOOLEAN intentional;
+ tBTA_HL_MDL_HANDLE mdl_handle;
+ tBTA_HL_MCL_HANDLE mcl_handle;
+ tBTA_HL_APP_HANDLE app_handle;
+} tBTA_HL_DCH_CLOSE_IND;
+
+
+typedef struct
+{
+ tBTA_HL_MDL_HANDLE mdl_handle;
+ tBTA_HL_MCL_HANDLE mcl_handle;
+ tBTA_HL_APP_HANDLE app_handle;
+} tBTA_HL_MDL_IND;
+
+typedef struct
+{
+ tBTA_HL_STATUS status;
+ tBTA_HL_MDL_HANDLE mdl_handle;
+ tBTA_HL_MCL_HANDLE mcl_handle;
+ tBTA_HL_APP_HANDLE app_handle;
+} tBTA_HL_MDL_CFM;
+
+typedef struct
+{
+ tBTA_HL_MCL_HANDLE mcl_handle;
+ tBTA_HL_APP_HANDLE app_handle;
+ tBTA_HL_MDL_ID mdl_id;
+} tBTA_HL_DELETE_MDL_IND;
+
+typedef struct
+{
+ tBTA_HL_STATUS status;
+ tBTA_HL_MCL_HANDLE mcl_handle;
+ tBTA_HL_APP_HANDLE app_handle;
+ tBTA_HL_MDL_ID mdl_id;
+} tBTA_HL_DELETE_MDL_CFM;
+
+typedef struct
+{
+ tBTA_HL_MDL_HANDLE mdl_handle;
+ tBTA_HL_MCL_HANDLE mcl_handle;
+ tBTA_HL_APP_HANDLE app_handle;
+ BOOLEAN cong;
+} tBTA_HL_DCH_CONG_IND;
+
+typedef struct
+{
+ tBTA_HL_APP_HANDLE app_handle;
+ UINT16 ctrl_psm;
+ UINT16 data_psm;
+ UINT8 data_x_spec;
+ UINT8 mcap_sup_procs;
+} tBTA_HL_SDP_INFO_IND;
+
+typedef struct
+{
+ tBTA_HL_STATUS status;
+ tBTA_HL_APP_HANDLE app_handle;
+ BD_ADDR bd_addr;
+ tBTA_HL_SDP *p_sdp;
+} tBTA_HL_SDP_QUERY_CFM;
+
+typedef union
+{
+ tBTA_HL_REGISTER_CFM reg_cfm;
+ tBTA_HL_DEREGISTER_CFM dereg_cfm;
+ tBTA_HL_CCH_OPEN_IND cch_open_ind;
+ tBTA_HL_CCH_OPEN_CFM cch_open_cfm;
+ tBTA_HL_CCH_CLOSE_IND cch_close_ind;
+ tBTA_HL_MCL_CFM cch_close_cfm;
+ tBTA_HL_DCH_CREATE_IND dch_create_ind;
+ tBTA_HL_DCH_OPEN_IND dch_open_ind;
+ tBTA_HL_DCH_OPEN_CFM dch_open_cfm;
+ tBTA_HL_DCH_CLOSE_IND dch_close_ind;
+ tBTA_HL_MDL_CFM dch_close_cfm;
+ tBTA_HL_DCH_OPEN_IND dch_reconnect_ind;
+ tBTA_HL_DCH_OPEN_CFM dch_reconnect_cfm;
+ tBTA_HL_MCL_IND dch_abort_ind;
+ tBTA_HL_MCL_CFM dch_abort_cfm;
+ tBTA_HL_DELETE_MDL_IND delete_mdl_ind;
+ tBTA_HL_DELETE_MDL_CFM delete_mdl_cfm;
+ tBTA_HL_MDL_CFM dch_send_data_cfm;
+ tBTA_HL_MDL_IND dch_rcv_data_ind;
+ tBTA_HL_DCH_CONG_IND dch_cong_ind;
+ tBTA_HL_MCL_CFM echo_test_cfm;
+ tBTA_HL_SDP_QUERY_CFM sdp_query_cfm;
+ tBTA_HL_SDP_INFO_IND sdp_info_ind;
+
+} tBTA_HL;
+
+/* HL callback functions */
+typedef void tBTA_HL_CTRL_CBACK(tBTA_HL_CTRL_EVT event, tBTA_HL_CTRL *p_data);
+typedef void tBTA_HL_CBACK(tBTA_HL_EVT event, tBTA_HL *p_data);
+
+
+/*****************************************************************************
+** External Function Declarations
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**************************
+** API Functions
+***************************/
+
+/*******************************************************************************
+**
+** Function BTA_HlEnable
+**
+** Description Enable the HL subsystems. This function must be
+** called before any other functions in the HL API are called.
+** When the enable operation is completed the callback function
+** will be called with an BTA_HL_CTRL_ENABLE_CFM_EVT event.
+**
+** Parameters p_cback - HL event call back function
+**
+** Returns void
+**
+*******************************************************************************/
+ BTA_API extern void BTA_HlEnable(tBTA_HL_CTRL_CBACK *p_ctrl_cback);
+/*******************************************************************************
+**
+** Function BTA_HlDisable
+**
+** Description Disable the HL subsystem.
+**
+** Returns void
+**
+*******************************************************************************/
+ BTA_API extern void BTA_HlDisable(void);
+/*******************************************************************************
+**
+** Function BTA_HlRegister
+**
+** Description Register a HDP application
+**
+**
+** Parameters app_id - hdp application ID
+** p_reg_param - non-platform related parameters for the
+** HDP application
+** p_cback - HL event callback fucntion
+**
+** Returns void
+**
+*******************************************************************************/
+ BTA_API extern void BTA_HlRegister(UINT8 app_id,
+ tBTA_HL_REG_PARAM *p_reg_param,
+ tBTA_HL_CBACK *p_cback);
+
+/*******************************************************************************
+**
+** Function BTA_HlDeregister
+**
+** Description Deregister an HDP application
+**
+** Parameters app_handle - Application handle
+**
+** Returns void
+**
+*******************************************************************************/
+ BTA_API extern void BTA_HlDeregister(tBTA_HL_APP_HANDLE app_handle);
+
+/*******************************************************************************
+**
+** Function BTA_HlCchOpen
+**
+** Description Open a Control channel connection with the specified BD address
+** and the control PSM value is used to select which
+** HDP insatnce should be used in case the peer device support
+** multiple HDP instances.
+**
+**
+** Parameters app_handle - Application Handle
+** p_open_param - parameters for opening a control channel
+**
+** Returns void
+**
+** Note: If the control PSM value is zero then the first HDP
+** instance is used for the control channel setup
+*******************************************************************************/
+ BTA_API extern void BTA_HlCchOpen(tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_CCH_OPEN_PARAM *p_open_param);
+
+/*******************************************************************************
+**
+** Function BTA_HlCchClose
+**
+** Description Close a Control channel connection with the specified MCL
+** handle
+**
+** Parameters mcl_handle - MCL handle
+**
+** Returns void
+**
+*******************************************************************************/
+ BTA_API extern void BTA_HlCchClose(tBTA_HL_MCL_HANDLE mcl_handle);
+
+/*******************************************************************************
+**
+** Function BTA_HlDchOpen
+**
+** Description Open a data channel connection with the specified DCH parameters
+**
+** Parameters mcl_handle - MCL handle
+** p_open_param - parameters for opening a data channel
+**
+** Returns void
+**
+*******************************************************************************/
+ BTA_API extern void BTA_HlDchOpen(tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_DCH_OPEN_PARAM *p_open_param);
+/*******************************************************************************
+**
+** Function BTA_HlDchReconnect
+**
+** Description Reconnect a data channel with the specified MDL_ID
+**
+** Parameters mcl_handle - MCL handle
+*8 p_recon_param - parameters for reconnecting a data channel
+**
+** Returns void
+**
+*******************************************************************************/
+ BTA_API extern void BTA_HlDchReconnect(tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_DCH_RECONNECT_PARAM *p_recon_param);
+/*******************************************************************************
+**
+** Function BTA_HlDchClose
+**
+** Description Close a data channel with the specified MDL handle
+**
+** Parameters mdl_handle - MDL handle
+**
+** Returns void
+**
+*******************************************************************************/
+ BTA_API extern void BTA_HlDchClose(tBTA_HL_MDL_HANDLE mdl_handle);
+
+/*******************************************************************************
+**
+** Function BTA_HlDchAbort
+**
+** Description Abort the current data channel setup with the specified MCL
+** handle
+**
+** Parameters mcl_handle - MCL handle
+**
+**
+** Returns void
+**
+*******************************************************************************/
+ BTA_API extern void BTA_HlDchAbort(tBTA_HL_MCL_HANDLE mcl_handle);
+
+/*******************************************************************************
+**
+** Function BTA_HlSendData
+**
+** Description Send an APDU to the peer device
+**
+** Parameters mdl_handle - MDL handle
+** pkt_size - size of the data packet to be sent
+**
+** Returns void
+**
+*******************************************************************************/
+ BTA_API extern void BTA_HlSendData(tBTA_HL_MDL_HANDLE mdl_handle,
+ UINT16 pkt_size);
+
+/*******************************************************************************
+**
+** Function BTA_HlDeleteMdl
+**
+** Description Delete the specified MDL_ID within the specified MCL handle
+**
+** Parameters mcl_handle - MCL handle
+** mdl_id - MDL ID
+**
+** Returns void
+**
+** note: If mdl_id = 0xFFFF then this means to delete all MDLs
+** and this value can only be used with DeleteMdl request only
+** not other requests
+**
+*******************************************************************************/
+ BTA_API extern void BTA_HlDeleteMdl(tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_MDL_ID mdl_id );
+
+/*******************************************************************************
+**
+** Function BTA_HlDchEchoTest
+**
+** Description Initiate an echo test with the specified MCL handle
+**
+** Parameters mcl_handle - MCL handle
+*8 p_echo_test_param - parameters for echo testing
+**
+** Returns void
+**
+*******************************************************************************/
+ BTA_API extern void BTA_HlDchEchoTest( tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_DCH_ECHO_TEST_PARAM *p_echo_test_param);
+
+/*******************************************************************************
+**
+** Function BTA_HlSdpQuery
+**
+** Description SDP query request for the specified BD address
+**
+** Parameters app_handle - application handle
+** bd_addr - BD address
+**
+** Returns void
+**
+*******************************************************************************/
+ BTA_API extern void BTA_HlSdpQuery(tBTA_HL_APP_HANDLE app_handle,
+ BD_ADDR bd_addr);
+
+/*******************************************************************************
+**
+** Function BTA_HlDchCreateMdlRsp
+**
+** Description Set the Response and configuration values for the Create MDL
+** request
+**
+** Parameters mcl_handle - MCL handle
+** p_rsp_param - parameters specified whether the request should
+** be accepted or not and if it should be accepted
+** then it also specified the configuration response
+** value
+**
+** Returns void
+**
+*******************************************************************************/
+ BTA_API extern void BTA_HlDchCreateRsp(tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_DCH_CREATE_RSP_PARAM *p_rsp_param);
+
+
+
+#ifdef __cplusplus
+
+}
+#endif
+
+#endif /* BTA_HL_API_H */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/bta/include/bta_hl_ci.h b/bta/include/bta_hl_ci.h
new file mode 100644
index 0000000..6cb1451
--- /dev/null
+++ b/bta/include/bta_hl_ci.h
@@ -0,0 +1,112 @@
+/*****************************************************************************
+**
+** Name: bta_hl_ci.h
+**
+** Description: This is the interface file for the HL (HeaLth device profile)
+** subsystem call-in functions.
+**
+** Copyright (c) 2009, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_HL_CI_H
+#define BTA_HL_CI_H
+
+#include "bta_api.h"
+#include "bta_hl_api.h"
+
+
+/*****************************************************************************
+** Constants and Data Types
+*****************************************************************************/
+/**************************
+** Common Definitions
+***************************/
+/* Read Ready Event */
+/*****************************************************************************
+** Function Declarations
+*****************************************************************************/
+/**************************
+** Common Functions
+***************************/
+/*******************************************************************************
+**
+** Function bta_hl_ci_get_tx_data
+**
+** Description This function is called in response to the
+** bta_hl_co_get_tx_data call-out function.
+**
+** Parameters mdl_handle -MDL handle
+** status - BTA_MA_STATUS_OK if operation is successful
+** BTA_MA_STATUS_FAIL if any errors have occurred.
+** evt - evt from the call-out function
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_hl_ci_get_tx_data( tBTA_HL_MDL_HANDLE mdl_handle,
+ tBTA_HL_STATUS status,
+ UINT16 evt );
+
+/*******************************************************************************
+**
+** Function bta_hl_ci_put_rx_data
+**
+** Description This function is called in response to the
+** bta_hl_co_put_rx_data call-out function.
+**
+** Parameters mdl_handle -MDL handle
+** status - BTA_MA_STATUS_OK if operation is successful
+** BTA_MA_STATUS_FAIL if any errors have occurred.
+** evt - evt from the call-out function
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_hl_ci_put_rx_data( tBTA_HL_MDL_HANDLE mdl_handle,
+ tBTA_HL_STATUS status,
+ UINT16 evt );
+
+
+
+/*******************************************************************************
+**
+** Function bta_hl_ci_get_echo_data
+**
+** Description This function is called in response to the
+** bta_hl_co_get_echo_data call-out function.
+**
+** Parameters mcl_handle -MCL handle
+** status - BTA_MA_STATUS_OK if operation is successful
+** BTA_MA_STATUS_FAIL if any errors have occurred.
+** evt - evt from the call-out function
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_hl_ci_get_echo_data( tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_STATUS status,
+ UINT16 evt );
+
+
+/*******************************************************************************
+**
+** Function bta_hl_ci_put_echo_data
+**
+** Description This function is called in response to the
+** bta_hl_co_put_echo_data call-out function.
+**
+** Parameters mcl_handle -MCL handle
+** status - BTA_MA_STATUS_OK if operation is successful
+** BTA_MA_STATUS_FAIL if any errors have occurred.
+** evt - evt from the call-out function
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_hl_ci_put_echo_data( tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_STATUS status,
+ UINT16 evt );
+#endif /* BTA_HL_CI_H */
+
+
diff --git a/bta/include/bta_hl_co.h b/bta/include/bta_hl_co.h
new file mode 100644
index 0000000..464e99a
--- /dev/null
+++ b/bta/include/bta_hl_co.h
@@ -0,0 +1,219 @@
+/*****************************************************************************
+**
+** Name: bta_hl_co.h
+**
+** Description: This is the interface file for the HL (HeaLth device profile)
+** subsystem call-out functions.
+**
+** Copyright (c) 2009, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_HL_CO_H
+#define BTA_HL_CO_H
+
+#include "bta_api.h"
+#include "bta_hl_api.h"
+
+/*****************************************************************************
+** Constants and Data Types
+*****************************************************************************/
+/**************************
+** Common Definitions
+***************************/
+
+
+/*******************************************************************************
+**
+** Function bta_hl_co_get_num_of_mdep
+**
+** Description This function is called to get the number of MDEPs for this
+** application ID
+**
+** Parameters app_id - application ID
+** p_num_of_mdep (output) - number of MDEP configurations supported
+** by the application
+**
+** Returns Bloolean - TRUE success
+**
+*******************************************************************************/
+BTA_API extern BOOLEAN bta_hl_co_get_num_of_mdep(UINT8 app_id, UINT8 *p_num_of_mdep);
+/*******************************************************************************
+**
+** Function bta_hl_co_advrtise_source_sdp
+**
+** Description This function is called to find out whether the SOURCE MDEP
+** configuration information should be advertize in the SDP or nopt
+**
+** Parameters app_id - application ID
+**
+** Returns Bloolean - TRUE advertise the SOURCE MDEP configuration
+** information
+**
+*******************************************************************************/
+BTA_API extern BOOLEAN bta_hl_co_advrtise_source_sdp(UINT8 app_id);
+/*******************************************************************************
+**
+** Function bta_hl_co_get_mdep_config
+**
+** Description This function is called to get the supported feature
+** configuration for the specified mdep index and it also assigns
+** the MDEP ID for the specified mdep index
+**
+** Parameters app_id - HDP application ID
+** mdep_idx - the mdep index
+** mdep_id - the assigned MDEP ID for the specified medp_idx
+** p_mdl_cfg (output) - pointer to the MDEP configuration
+**
+**
+** Returns Bloolean - TRUE success
+*******************************************************************************/
+BTA_API extern BOOLEAN bta_hl_co_get_mdep_config(UINT8 app_id,
+ UINT8 mdep_idx,
+ tBTA_HL_MDEP_ID mdep_id,
+ tBTA_HL_MDEP_CFG *p_mdep_cfg);
+
+
+/*******************************************************************************
+**
+** Function bta_hl_co_get_echo_config
+**
+** Description This function is called to get the echo test
+** maximum APDU size configuration
+**
+** Parameters app_id - HDP application ID
+** p_echo_cfg (output) - pointer to the Echo test maximum APDU size
+** configuration
+**
+** Returns Bloolean - TRUE success
+*******************************************************************************/
+BTA_API extern BOOLEAN bta_hl_co_get_echo_config(UINT8 app_id,
+ tBTA_HL_ECHO_CFG *p_echo_cfg);
+
+
+/*******************************************************************************
+**
+** Function bta_hl_co_save_mdl
+**
+** Description This function is called to save a MDL configuration item in persistent
+** storage
+**
+** Parameters app_id - HDP application ID
+** item_idx - the MDL configuration storage index
+** p_mdl_cfg - pointer to the MDL configuration data
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_hl_co_save_mdl(UINT8 app_id, UINT8 item_idx, tBTA_HL_MDL_CFG *p_mdl_cfg );
+/*******************************************************************************
+**
+** Function bta_hl_co_delete_mdl
+**
+** Description This function is called to delete a MDL configuration item in persistent
+** storage
+**
+** Parameters app_id - HDP application ID
+** item_idx - the MDL configuration storage index
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_hl_co_delete_mdl(UINT8 app_id, UINT8 item_idx);
+/*******************************************************************************
+**
+** Function bta_hl_co_get_mdl_config
+**
+** Description This function is called to get the MDL configuration
+** from teh persistent memory. This function shall only be called
+*8 once after the device is powered up
+**
+** Parameters app_id - HDP application ID
+** buffer_size - the unit of the buffer size is sizeof(tBTA_HL_MDL_CFG)
+** p_mdl_buf - Point to the starting location of the buffer
+**
+** Returns BOOLEAN
+**
+**
+*******************************************************************************/
+BTA_API extern BOOLEAN bta_hl_co_load_mdl_config (UINT8 app_id, UINT8 buffer_size,
+ tBTA_HL_MDL_CFG *p_mdl_buf );
+
+
+/*******************************************************************************
+**
+** Function bta_hl_co_get_tx_data
+**
+** Description Get the data to be sent
+**
+** Parameters app_id - HDP application ID
+** mdl_handle - MDL handle
+** buf_size - the size of the buffer
+** p_buf - the buffer pointer
+** evt - the evt to be passed back to the HL in the
+** bta_hl_ci_get_tx_data call-in function
+**
+** Returns Void
+**
+*******************************************************************************/
+BTA_API extern void bta_hl_co_get_tx_data (UINT8 app_id, tBTA_HL_MDL_HANDLE mdl_handle,
+ UINT16 buf_size, UINT8 *p_buf, UINT16 evt);
+
+
+/*******************************************************************************
+**
+** Function bta_hl_co_put_rx_data
+**
+** Description Put the received data
+**
+** Parameters app_id - HDP application ID
+** mdl_handle - MDL handle
+** data_size - the size of the data
+** p_data - the data pointer
+** evt - the evt to be passed back to the HL in the
+** bta_hl_ci_put_rx_data call-in function
+**
+** Returns Void
+**
+*******************************************************************************/
+BTA_API extern void bta_hl_co_put_rx_data (UINT8 app_id, tBTA_HL_MDL_HANDLE mdl_handle,
+ UINT16 data_size, UINT8 *p_data, UINT16 evt);
+/*******************************************************************************
+**
+** Function bta_hl_co_get_tx_data
+**
+** Description Get the Echo data to be sent
+**
+** Parameters app_id - HDP application ID
+** mcl_handle - MCL handle
+** buf_size - the size of the buffer
+** p_buf - the buffer pointer
+** evt - the evt to be passed back to the HL in the
+** bta_hl_ci_get_tx_data call-in function
+**
+** Returns Void
+**
+*******************************************************************************/
+BTA_API extern void bta_hl_co_get_echo_data (UINT8 app_id, tBTA_HL_MCL_HANDLE mcl_handle,
+ UINT16 buf_size, UINT8 *p_buf, UINT16 evt);
+
+/*******************************************************************************
+**
+** Function bta_hl_co_put_echo_data
+**
+** Description Put the received loopback echo data
+**
+** Parameters app_id - HDP application ID
+** mcl_handle - MCL handle
+** data_size - the size of the data
+** p_data - the data pointer
+** evt - the evt to be passed back to the HL in the
+** bta_hl_ci_put_echo_data call-in function
+**
+** Returns Void
+**
+*******************************************************************************/
+BTA_API extern void bta_hl_co_put_echo_data (UINT8 app_id, tBTA_HL_MCL_HANDLE mcl_handle,
+ UINT16 data_size, UINT8 *p_data, UINT16 evt);
+
+#endif /* BTA_HL_CO_H */
diff --git a/bta/include/bta_ma_api.h b/bta/include/bta_ma_api.h
new file mode 100644
index 0000000..e0b413e
--- /dev/null
+++ b/bta/include/bta_ma_api.h
@@ -0,0 +1,691 @@
+/*****************************************************************************
+**
+** Name: bta_ma_api.h
+**
+** Description: This file contains the common API functions used
+** for the Message Access Profiles (MAP).
+**
+** Copyright (c) 2009, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_MA_API_H
+#define BTA_MA_API_H
+
+#include "bta_mse_api.h" /* For tBTA_MA_MSG_TYPE */
+#include <stdio.h>
+
+typedef struct
+{
+ UINT16 size; /* Size of the buffer */
+ UINT8 * p_buffer; /* Pointer to buffer */
+ UINT8 * p_next; /* Pointer to next byte to use in buffer */
+
+}tBTA_MA_MEM_STREAM;
+
+typedef struct
+{
+ int fd;
+
+}tBTA_MA_FILE_STREAM;
+
+/* Structure used for streaming data */
+typedef struct
+{
+#define STRM_TYPE_MEMORY 0
+#define STRM_TYPE_FILE 1
+
+ UINT8 type;
+
+#define STRM_SUCCESS 0
+#define STRM_ERROR_OVERFLOW 1
+#define STRM_ERROR_FILE 2
+
+ UINT8 status;
+
+ union
+ {
+ tBTA_MA_MEM_STREAM mem;
+ tBTA_MA_FILE_STREAM file;
+ } u;
+
+} tBTA_MA_STREAM;
+
+/*******************************************************************************
+**
+** bMessage functions
+**
+** Description The following API functions are generic in a sense that
+** they do not imply how the data is stored (to memory or
+** to file, etc.).
+**
+** They operate on a generic set of structure types. Though
+** the internal structure of those types are implementation
+** specific.
+**
+*******************************************************************************/
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*******************************************************************************
+**
+** Function BTA_MaBmsgCreate
+**
+** Description Create and initialize an instance of a tBTA_MA_BMSG structure.
+**
+** Parameters None
+**
+** Returns Pointer to a bMessage object, or NULL if this fails.
+**
+*******************************************************************************/
+BTA_API extern tBTA_MA_BMSG * BTA_MaBmsgCreate(void);
+/*******************************************************************************
+**
+** Function BTA_MaBmsgFree
+**
+** Description Destroy (free) the contents of a tBTA_MA_BMSG structure.
+**
+** Parameters p_bmsg - Pointer to a bMessage object
+**
+** Returns None
+**
+*******************************************************************************/
+BTA_API extern void BTA_MaBmsgFree(tBTA_MA_BMSG * p_msg);
+/*******************************************************************************
+**
+** Function BTA_MaBmsgSetReadSts
+**
+** Description Set the bmessage-readstatus-property value for the bMessage
+** object. If the 'read_sts' is TRUE then value will be "READ",
+** otherwise it is "UNREAD".
+**
+** Parameters p_bmsg - Pointer to a bMessage object
+** read_sts - Read status TRUE- read FALSE - unread
+**
+** Returns None
+**
+*******************************************************************************/
+BTA_API extern void BTA_MaBmsgSetReadSts(tBTA_MA_BMSG * p_msg, BOOLEAN read_sts);
+/*******************************************************************************
+**
+** Function BTA_MaBmsgGetReadSts
+**
+** Description Get the bmessage-readstatus-property value for the bMessage
+** object
+**
+** Parameters p_bmsg - Pointer to a bMessage object
+**
+** Returns Read status (TRUE/FALSE) for the specified bMessage.
+**
+*******************************************************************************/
+BTA_API extern BOOLEAN BTA_MaBmsgGetReadSts(tBTA_MA_BMSG * p_msg);
+/*******************************************************************************
+**
+** Function BTA_MaBmsgSetMsgType
+**
+** Description Set the bmessage-type-property value for the bMessage object
+**
+** Parameters p_bmsg - Pointer to a bMessage object
+** msg_type - Message type
+**
+** Returns None
+**
+*******************************************************************************/
+BTA_API extern void BTA_MaBmsgSetMsgType(tBTA_MA_BMSG * p_msg, tBTA_MA_MSG_TYPE msg_type);
+/*******************************************************************************
+**
+** Function BTA_MaBmsgGetMsgType
+**
+** Description Get the bmessage-type-property value for the specified
+** bMessage object
+**
+** Parameters p_bmsg - Pointer to a bMessage object
+**
+** Returns Message type
+**
+*******************************************************************************/
+BTA_API extern tBTA_MA_MSG_TYPE BTA_MaBmsgGetMsgType(tBTA_MA_BMSG * p_msg);
+/*******************************************************************************
+**
+** Function BTA_MaBmsgSetFolder
+**
+** Description Set the bmessage-folder-property value for the bMessage object
+**
+** Parameters p_bmsg - Pointer to a bMessage object
+** p_folder - Pointer to a folder path
+**
+** Returns None
+**
+*******************************************************************************/
+BTA_API extern void BTA_MaBmsgSetFolder(tBTA_MA_BMSG * p_msg, char * p_folder);
+/*******************************************************************************
+**
+** Function BTA_MaBmsgGetFolder
+**
+** Description Get the bmessage-folder-property value for the specified
+** bMessage object
+**
+** Parameters p_bmsg - Pointer to a bMessage object
+**
+** Returns Pointer to folder path string, or NULL if it has not been set.
+**
+*******************************************************************************/
+BTA_API extern char * BTA_MaBmsgGetFolder(tBTA_MA_BMSG * p_msg);
+/*******************************************************************************
+**
+** Function BTA_MaBmsgAddOrigToBmsg
+**
+** Description Add an originator to the bMessage object
+**
+** Parameters p_bmsg - Pointer to a bMessage object
+**
+** Returns Pointer to a new vCard structure, or NULL if this function
+** fails.
+**
+*******************************************************************************/
+BTA_API extern tBTA_MA_BMSG_VCARD * BTA_MaBmsgAddOrigToBmsg(tBTA_MA_BMSG * p_msg);
+/*******************************************************************************
+**
+** Function BTA_MaBmsgGetOrigFromBmsg
+**
+** Description Get the first originator vCard information from the specified
+** bMessage object
+**
+** Parameters p_bmsg - Pointer to a bMessage object
+**
+** Returns Pointer to first 'originator vCard, or NULL not used.
+**
+*******************************************************************************/
+BTA_API extern tBTA_MA_BMSG_VCARD * BTA_MaBmsgGetOrigFromBmsg(tBTA_MA_BMSG * p_msg);
+/*******************************************************************************
+**
+** Function BTA_MaBmsgAddEnvToBmsg
+**
+** Description Add a new envelope to the bMessage object. This is the first
+** (top) level envelope. bMessage allows up to 3 levels of envelopes.
+** application should call BTA_MaBmsgAddEnvToEnv to add the 2nd
+** 3rd level enevelope.
+**
+** Parameters p_bmsg - Pointer to a bMessage object
+**
+** Returns Pointer to a new envelope structure, or NULL if this
+** function fails.
+**
+*******************************************************************************/
+BTA_API extern tBTA_MA_BMSG_ENVELOPE * BTA_MaBmsgAddEnvToBmsg(tBTA_MA_BMSG * p_msg);
+/*******************************************************************************
+**
+** Function BTA_MaBmsgAddEnvToEnv
+**
+** Description Add a child envelope to an existing envelope.
+**
+** Parameters p_envelope - Pointer to a parent envelope
+**
+** Returns Pointer to an envelope structure, or NULL if this
+** function fails.
+**
+*******************************************************************************/
+BTA_API extern tBTA_MA_BMSG_ENVELOPE * BTA_MaBmsgAddEnvToEnv(tBTA_MA_BMSG_ENVELOPE * p_envelope);
+/*******************************************************************************
+**
+** Function BTA_MaBmsgGetEnv
+**
+** Description Get the pointer of the first level envelope.
+**
+** Parameters p_bmsg - Pointer to a bMessage object
+**
+** Returns Pointer to the first level envelope structure, or NULL if it
+** does not exist
+**
+*******************************************************************************/
+BTA_API extern tBTA_MA_BMSG_ENVELOPE * BTA_MaBmsgGetEnv(tBTA_MA_BMSG * p_msg);
+/*******************************************************************************
+**
+** Function BTA_MaBmsgGetNextEnv
+**
+** Description Get the child envelope of the specified parent envelope.
+**
+** Parameters p_env - Pointer to a parent envelope
+**
+** Returns Pointer to a child enevelope. NULL if the
+** envelope does not have a 'child' envelope.
+**
+*******************************************************************************/
+BTA_API extern tBTA_MA_BMSG_ENVELOPE * BTA_MaBmsgGetNextEnv(tBTA_MA_BMSG_ENVELOPE * p_env);
+/*******************************************************************************
+**
+** Function BTA_MaBmsgAddRecipToEnv
+**
+** Description Add recipient to the specified envelope.
+**
+** Parameters p_env - Pointer to a envelope
+**
+** Returns Pointer to a vCard structure. NULL if it
+** fails to allocate a vCard structure.
+**
+*******************************************************************************/
+BTA_API extern tBTA_MA_BMSG_VCARD * BTA_MaBmsgAddRecipToEnv(tBTA_MA_BMSG_ENVELOPE * p_env);
+/*******************************************************************************
+**
+** Function BTA_MaBmsgGetRecipFromEnv
+**
+** Description Get the first recipient's vCard from the specified envelope.
+**
+** Parameters p_env - Pointer to a envelope
+**
+** Returns Pointer to the first recipient's vCard structure. NULL if it
+** has not be set.
+**
+*******************************************************************************/
+BTA_API extern tBTA_MA_BMSG_VCARD * BTA_MaBmsgGetRecipFromEnv(tBTA_MA_BMSG_ENVELOPE * p_env);
+/*******************************************************************************
+**
+** Function BTA_MaBmsgAddBodyToEnv
+**
+** Description Add a message body to the specified envelope.
+**
+** Parameters p_env - Pointer to a envelope
+**
+** Returns Pointer to a message body structure.
+** NULL if it fails to allocate a message body structure.
+**
+*******************************************************************************/
+BTA_API extern tBTA_MA_BMSG_BODY * BTA_MaBmsgAddBodyToEnv(tBTA_MA_BMSG_ENVELOPE * p_env);
+/*******************************************************************************
+**
+** Function BTA_MaBmsgGetBodyFromEnv
+**
+** Description Get the message body pointer from the specified envelope.
+**
+** Parameters p_env - Pointer to a envelope
+**
+** Returns Pointer to a message body structure.
+** NULL if it has not been set.
+**
+*******************************************************************************/
+BTA_API extern tBTA_MA_BMSG_BODY * BTA_MaBmsgGetBodyFromEnv(tBTA_MA_BMSG_ENVELOPE * p_env);
+/*******************************************************************************
+**
+** Function BTA_MaBmsgSetBodyEncoding
+**
+** Description Set the bmessage-body-encoding-property value for the bMessage
+** body.
+**
+** Parameters p_body - Pointer to a bMessage body
+** encoding - encoding scheme
+**
+** Returns None
+**
+*******************************************************************************/
+BTA_API extern void BTA_MaBmsgSetBodyEncoding(tBTA_MA_BMSG_BODY * p_body, tBTA_MA_BMSG_ENCODING encoding);
+/*******************************************************************************
+**
+** Function BTA_MaBmsgGetBodyEncoding
+**
+** Description Get the bmessage-body-encoding-property value for the specified
+** bMessage body.
+**
+** Parameters p_body - Pointer to a bMessage body
+**
+** Returns Message encoding scheme
+**
+*******************************************************************************/
+BTA_API extern tBTA_MA_BMSG_ENCODING BTA_MaBmsgGetBodyEncoding(tBTA_MA_BMSG_BODY * p_body);
+/*******************************************************************************
+**
+** Function BTA_MaBmsgSetBodyPartid
+**
+** Description Set the bmessage-body-part-ID value for the speicified
+** bMessage body.
+**
+** Parameters p_body - Pointer to a bMessage body
+** part_id - Part ID (range: from 0 to 65535)
+**
+** Returns None
+**
+*******************************************************************************/
+BTA_API extern void BTA_MaBmsgSetBodyPartid(tBTA_MA_BMSG_BODY * p_body, UINT16 part_id);
+/*******************************************************************************
+**
+** Function BTA_MaBmsgGetBodyPartid
+**
+** Description Get the bmessage-body-part-ID value for the specified
+** bMessage body.
+**
+** Parameters p_body - Pointer to a bMessage body
+**
+** Returns The value of the Part ID
+**
+*******************************************************************************/
+BTA_API extern UINT16 BTA_MaBmsgGetBodyPartid(tBTA_MA_BMSG_BODY * p_body);
+/*******************************************************************************
+**
+** Function BTA_MaBmsgIsBodyMultiPart
+**
+** Description Is this a multi-part body
+**
+** Parameters p_body - Pointer to a bMessage body
+**
+** Returns TURE - if this is a multi-part body
+**
+*******************************************************************************/
+BTA_API extern BOOLEAN BTA_MaBmsgIsBodyMultiPart(tBTA_MA_BMSG_BODY * p_body);
+/*******************************************************************************
+**
+** Function BTA_MaBmsgGetBodyCharset
+**
+** Description Get the bmessage-body-charset-property value for the speicified
+** bMessage body.
+**
+** Parameters p_body - Pointer to a bMessage body
+**
+** Returns Charset
+**
+*******************************************************************************/
+BTA_API extern void BTA_MaBmsgSetBodyCharset(tBTA_MA_BMSG_BODY * p_body, tBTA_MA_CHARSET charset);
+/*******************************************************************************
+**
+** Function BTA_MaBmsgGetBodyCharset
+**
+** Description Get the bmessage-body-charset-property value for the speicified
+** bMessage body.
+**
+** Parameters p_body - Pointer to a bMessage body
+**
+** Returns Charset
+**
+*******************************************************************************/
+BTA_API extern tBTA_MA_CHARSET BTA_MaBmsgGetBodyCharset(tBTA_MA_BMSG_BODY * p_body);
+/*******************************************************************************
+**
+** Function BTA_MaBmsgSetBodyLanguage
+**
+** Description Set the bmessage-body-language-property value for the speicified
+** bMessage body.
+**
+** Parameters p_body - Pointer to a bMessage body
+** Language - the language of the message
+**
+** Returns None
+**
+*******************************************************************************/
+BTA_API extern void BTA_MaBmsgSetBodyLanguage(tBTA_MA_BMSG_BODY * p_body, tBTA_MA_BMSG_LANGUAGE language);
+/*******************************************************************************
+**
+** Function BTA_MaBmsgGetBodyLanguage
+**
+** Description Get the bmessage-body-language-property value for the speicified
+** bMessage body.
+**
+** Parameters p_body - Pointer to a bMessage body
+**
+** Returns the language of the message
+**
+*******************************************************************************/
+BTA_API extern tBTA_MA_BMSG_LANGUAGE BTA_MaBmsgGetBodyLanguage(tBTA_MA_BMSG_BODY * p_body);
+/*******************************************************************************
+**
+** Function BTA_MaBmsgAddContentToBody
+**
+** Description Add a message content to the speicified bMessage body.
+**
+** Parameters p_body - Pointer to a bMessage body
+**
+** Returns Pointer to a message content.
+** NULL if it fails to allocate a message content buffer
+**
+*******************************************************************************/
+BTA_API extern tBTA_MA_BMSG_CONTENT * BTA_MaBmsgAddContentToBody(tBTA_MA_BMSG_BODY * p_body);
+/*******************************************************************************
+**
+** Function BTA_MaBmsgGetContentFromBody
+**
+** Description Get a message content from the speicified bMessage body.
+**
+** Parameters p_body - Pointer to a bMessage body
+**
+** Returns Pointer to a message content.
+** NULL if it has not been set.
+**
+*******************************************************************************/
+BTA_API extern tBTA_MA_BMSG_CONTENT * BTA_MaBmsgGetContentFromBody(tBTA_MA_BMSG_BODY * p_body);
+/*******************************************************************************
+**
+** Function BTA_MaBmsgGetNextContent
+**
+** Description Get the next message content from the speicified message content.
+**
+** Parameters p_content - Pointer to a message content
+**
+** Returns Pointer to a message content.
+** NULL if it has not been set.
+**
+*******************************************************************************/
+BTA_API extern tBTA_MA_BMSG_CONTENT * BTA_MaBmsgGetNextContent(tBTA_MA_BMSG_CONTENT * p_content);
+/*******************************************************************************
+**
+** Function BTA_MaBmsgAddMsgContent
+**
+** Description Add a text string to the speicified message content.
+**
+** Parameters p_content - Pointer to a message content
+** p_text - Pointer to a text string
+**
+** Returns None
+**
+*******************************************************************************/
+BTA_API extern void BTA_MaBmsgAddMsgContent(tBTA_MA_BMSG_CONTENT * p_content, char * p_text);
+/*******************************************************************************
+**
+** Function BTA_MaBmsgGetMsgContent
+**
+** Description Get the next text string from the speicified message content.
+**
+** Parameters p_content - Pointer to a message content
+**
+** Returns Pointer to the next text string.
+** NULL if it has not been set.
+**
+*******************************************************************************/
+BTA_API extern char * BTA_MaBmsgGetMsgContent(tBTA_MA_BMSG_CONTENT * p_content);
+/*******************************************************************************
+**
+** Function BTA_MaBmsgGetNextVcard
+**
+** Description Get the next vCard from the speicified vCard.
+**
+** Parameters p_vcard - Pointer to a vCard
+**
+** Returns Pointer to the next vCard.
+** NULL if it has not been set.
+**
+*******************************************************************************/
+BTA_API extern char * BTA_MaBmsgGetNextMsgContent(tBTA_MA_BMSG_CONTENT * p_content);
+/*******************************************************************************
+**
+** Function BTA_MaBmsgGetNextVcard
+**
+** Description Get the next vCard from the speicified vCard.
+**
+** Parameters p_vcard - Pointer to a vCard
+**
+** Returns Pointer to the next vCard.
+** NULL if it has not been set.
+**
+*******************************************************************************/
+BTA_API extern tBTA_MA_BMSG_VCARD * BTA_MaBmsgGetNextVcard(tBTA_MA_BMSG_VCARD * p_vcard);
+/*******************************************************************************
+**
+** Function BTA_MaBmsgSetVcardVersion
+**
+** Description Set the vCard version for the speicified vCard.
+**
+** Parameters p_vcard - Pointer to a vCard
+** version - vcard version
+**
+** Returns None
+**
+*******************************************************************************/
+BTA_API extern void BTA_MaBmsgSetVcardVersion(tBTA_MA_BMSG_VCARD * p_vcard, tBTA_MA_VCARD_VERSION version);
+/*******************************************************************************
+**
+** Function BTA_MaBmsgGetVcardVersion
+**
+** Description Get the vCard version from the speicified vCard.
+**
+** Parameters p_vcard - Pointer to a vCard
+**
+** Returns vCard version number
+**
+*******************************************************************************/
+BTA_API extern tBTA_MA_VCARD_VERSION BTA_MaBmsgGetVcardVersion(tBTA_MA_BMSG_VCARD * p_vcard);
+/*******************************************************************************
+**
+** Function BTA_MaBmsgGetVcardProp
+**
+** Description Get the vCard property from the speicified vCard peoperty enum.
+**
+** Parameters p_vcard - Pointer to a vCard
+** prop - Indicate which vCard peoperty
+**
+** Returns Pointer to the vCard peoperty.
+** NULL if the vCard peoperty does not exist
+**
+*******************************************************************************/
+BTA_API extern tBTA_MA_VCARD_PROPERTY * BTA_MaBmsgAddVcardProp(tBTA_MA_BMSG_VCARD * p_vcard, tBTA_MA_VCARD_PROP prop, char * p_value, char * p_param);
+/*******************************************************************************
+**
+** Function BTA_MaBmsgGetVcardProp
+**
+** Description Get the next vCard property from the speicified vCard peoperty.
+**
+** Parameters p_prop - Pointer to a vCard property
+**
+** Returns Pointer to the next vCard peoperty.
+** NULL if the next vCard peoperty does not exist
+**
+*******************************************************************************/
+BTA_API extern tBTA_MA_VCARD_PROPERTY * BTA_MaBmsgGetVcardProp(tBTA_MA_BMSG_VCARD * p_vcard, tBTA_MA_VCARD_PROP prop);
+/*******************************************************************************
+**
+** Function BTA_MaBmsgGetNextVcardProp
+**
+** Description Get the next vCard property from the speicified vCard peoperty.
+**
+** Parameters p_prop - Pointer to a vCard property
+**
+** Returns Pointer to the next vCard peoperty.
+** NULL if the next vCard peoperty does not exist
+**
+*******************************************************************************/
+BTA_API extern tBTA_MA_VCARD_PROPERTY * BTA_MaBmsgGetNextVcardProp(tBTA_MA_VCARD_PROPERTY * p_prop);
+/*******************************************************************************
+**
+** Function BTA_MaBmsgGetVcardPropValue
+**
+** Description Get the vCard property value from the speicified vCard peoperty.
+**
+** Parameters p_prop - Pointer to a vCard property
+**
+** Returns Pointer to the vCard peoperty value.
+** NULL if the vCard peoperty value has not been set.
+**
+*******************************************************************************/
+BTA_API extern char * BTA_MaBmsgGetVcardPropValue(tBTA_MA_VCARD_PROPERTY * p_prop);
+/*******************************************************************************
+**
+** Function BTA_MaBmsgGetVcardPropParam
+**
+** Description Get the vCard property parameter from the speicified vCard peoperty.
+**
+** Parameters p_prop - Pointer to a vCard property
+**
+** Returns Poiter to the vCard peoperty parameter.
+** NULL if the vCard peoperty parameter has not been set.
+**
+*******************************************************************************/
+BTA_API extern char * BTA_MaBmsgGetVcardPropParam(tBTA_MA_VCARD_PROPERTY * p_prop);
+/*******************************************************************************
+**
+** Function BTA_MaBuildMapBmsgObj
+**
+** Description Builds a specification compliant bMessage object given a
+** generic bMessage internal structure.
+**
+** Parameters p_msg - pointer to bMessage object structure (input).
+** p_stream - Output stream.
+**
+** Returns BTA_MA_STATUS_OK if successful. BTA_MA_STATUS_FAIL if not.
+**
+*******************************************************************************/
+BTA_API extern tBTA_MA_STATUS BTA_MaBuildMapBmsgObj(tBTA_MA_BMSG * p_msg, tBTA_MA_STREAM * p_stream);
+/*******************************************************************************
+**
+** Function bta_ma_parse_map_bmsg_obj
+**
+** Description Parses a bMessage object from a stream into a generic
+** bMessage internal structure.
+**
+** Parameters p_msg - pointer to bMessage object structure (output).
+** p_stream - Input stream.
+**
+** Returns BTA_MA_STATUS_OK if successful. BTA_MA_STATUS_FAIL if not.
+**
+*******************************************************************************/
+BTA_API extern tBTA_MA_STATUS BTA_MaParseMapBmsgObj(tBTA_MA_BMSG * p_msg, tBTA_MA_STREAM * p_stream);
+
+/*******************************************************************************
+**
+** Function BTA_MaInitMemStream
+**
+** Description Initializes a memory based stream
+**
+** Parameters p_stream - pointer to stream information.
+** p_buffer - pointer to buffer to be manipulated.
+** size - size of buffer pointed to by 'p_buffer'.
+**
+** Returns TRUE if stream is successfully initialized
+**
+*******************************************************************************/
+BTA_API extern BOOLEAN BTA_MaInitMemStream(tBTA_MA_STREAM * p_stream,
+ UINT8 * p_buffer,
+ UINT16 size);
+/*******************************************************************************
+**
+** Function BTA_MaInitFileStream
+**
+** Description Initializes a file stream
+**
+** Parameters p_stream - pointer to stream information.
+** p_filename - Full pathname to file to use.
+** oflags - permissions and mode (see constants above)
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern BOOLEAN BTA_MaInitFileStream(tBTA_MA_STREAM * p_stream,
+ const char *p_path,
+ int oflags);
+/*******************************************************************************
+**
+** Function BTA_MaCloseStream
+**
+** Description Close a stream (do any necessary clean-up.
+**
+** Parameters p_stream - pointer to stream information.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_MaCloseStream(tBTA_MA_STREAM * p_stream);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_BMSG_API_H */
diff --git a/bta/include/bta_ma_co.h b/bta/include/bta_ma_co.h
new file mode 100644
index 0000000..442d106
--- /dev/null
+++ b/bta/include/bta_ma_co.h
@@ -0,0 +1,91 @@
+/*****************************************************************************
+**
+** Name: bta_ma_co.h
+**
+** Description: This is the interface file for the Message Access Profile
+** common call-out functions.
+**
+** Copyright (c) 2009, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_MA_CO_H
+#define BTA_MA_CO_H
+
+#include <stdio.h>
+
+/*****************************************************************************
+**
+** Utility functions for converting types to strings.
+**
+*****************************************************************************/
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*******************************************************************************
+**
+** Function bta_ma_co_open
+**
+** Description Open a file.
+**
+** Parameters p_path - Full path of file to open.
+** oflags - file open flags.
+**
+** Returns file descriptor. BTA_FS_INVALID_FD if open fails.
+**
+*******************************************************************************/
+ BTA_API extern int bta_ma_co_open(const char *p_path, int oflags);
+
+/*******************************************************************************
+**
+** Function bta_ma_co_write
+**
+** Description Write data to file.
+**
+** Parameters fd - file descriptor.
+** buffer - data to write.
+** size - size of data to write (in bytes).
+**
+** Returns Number of bytes written.
+**
+*******************************************************************************/
+ BTA_API extern int bta_ma_co_write(int fd, const void *buffer, int size);
+
+/*******************************************************************************
+**
+** Function bta_ma_co_read
+**
+** Description Read data from file.
+**
+** Parameters fd - file descriptor.
+** buffer - to receive data.
+** size - amount of data to read (in bytes).
+**
+** Returns Number of bytes read.
+**
+*******************************************************************************/
+ BTA_API extern int bta_ma_co_read(int fd, void *buffer, int size);
+
+/*******************************************************************************
+**
+** Function bta_ma_co_close
+**
+** Description Close the file.
+**
+** Parameters fd - file descriptor.
+**
+** Returns void
+**
+*******************************************************************************/
+ BTA_API extern void bta_ma_co_close(int fd);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_MA_FILE_H */
+
+
diff --git a/bta/include/bta_ma_def.h b/bta/include/bta_ma_def.h
new file mode 100644
index 0000000..7202385
--- /dev/null
+++ b/bta/include/bta_ma_def.h
@@ -0,0 +1,479 @@
+/*****************************************************************************
+**
+** Name: bta_ma_def.h
+**
+** Description: This file contains the common definitions for the Message Access
+** profile (MA) related SW modules
+**
+** Copyright (c) 2009, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_MA_DEF_H
+#define BTA_MA_DEF_H
+
+#include "obx_api.h"
+#include "bta_api.h"
+#include "btm_api.h"
+#include "bta_sys.h"
+#include "bta_fs_co.h"
+
+/*****************************************************************************
+** Constants and data types
+*****************************************************************************/
+
+
+#define BTA_MA_HANDLE_SIZE 8
+
+typedef UINT8 tBTA_MA_MSG_HANDLE[BTA_MA_HANDLE_SIZE];
+
+typedef tOBX_HANDLE tBTA_MA_SESS_HANDLE;
+
+typedef UINT8 tBTA_MA_INST_ID;
+
+#define BTA_MA_STATUS_OK 0
+#define BTA_MA_STATUS_FAIL 1 /* Used to pass all other errors */
+#define BTA_MA_STATUS_ABORTED 2
+#define BTA_MA_STATUS_NO_RESOURCE 3
+#define BTA_MA_STATUS_EACCES 4
+#define BTA_MA_STATUS_ENOTEMPTY 5
+#define BTA_MA_STATUS_EOF 6
+#define BTA_MA_STATUS_EODIR 7
+#define BTA_MA_STATUS_ENOSPACE 8 /* Returned in bta_fs_ci_open if no room */
+#define BTA_MA_STATUS_DUPLICATE_ID 9
+#define BTA_MA_STATUS_ID_NOT_FOUND 10
+#define BTA_MA_STATUS_FULL 11 /* reach the max packet size */
+
+typedef UINT8 tBTA_MA_STATUS;
+
+#define BTA_MA_OPER_NONE 0
+#define BTA_MA_OPER_GET_MSG 1
+#define BTA_MA_OPER_PUSH_MSG 2
+
+typedef UINT8 tBTA_MA_OPER;
+
+/* mode field in tBTA_MSE_CO_FOLDER_ENTRY (OR'd together) */
+#define BTA_MA_A_RDONLY 1
+#define BTA_MA_A_DIR 2 /* Entry is a sub directory */
+
+
+/* message status inficator */
+#define BTA_MA_STS_INDTR_READ 0
+#define BTA_MA_STS_INDTR_DELETE 1
+typedef UINT8 tBTA_MA_STS_INDCTR;
+
+/* message status value */
+#define BTA_MA_STS_VALUE_NO 0
+#define BTA_MA_STS_VALUE_YES 1
+typedef UINT8 tBTA_MA_STS_VALUE;
+
+/* notification status */
+enum
+{
+ BTA_MA_NOTIF_OFF = 0,
+ BTA_MA_NOTIF_ON,
+ BTA_MA_NOTIF_MAX
+
+};
+typedef UINT8 tBTA_MA_NOTIF_STATUS;
+
+
+/* Access response types */
+enum
+{
+ BTA_MA_ACCESS_TYPE_ALLOW = 0, /* Allow the requested operation */
+ BTA_MA_ACCESS_TYPE_FORBID /* Disallow the requested operation */
+};
+
+typedef UINT8 tBTA_MA_ACCESS_TYPE;
+
+/* Structure for in progress related event*/
+typedef struct
+{
+ UINT32 obj_size; /* Total size of object 0 if unknow*/
+ tBTA_MA_SESS_HANDLE mas_session_id;
+ UINT16 bytes; /* Number of bytes read or written since last progress event */
+} tBTA_MA_IN_PROG;
+
+
+/* Message type see SDP supported message type */
+#define BTA_MA_MSG_TYPE_EMAIL (1<<0)
+#define BTA_MA_MSG_TYPE_SMS_GSM (1<<1)
+#define BTA_MA_MSG_TYPE_SMS_CDMA (1<<2)
+#define BTA_MA_MSG_TYPE_MMS (1<<3)
+typedef UINT8 tBTA_MA_MSG_TYPE;
+
+#define BTA_MA_MAX_FILTER_TEXT_SIZE 255
+
+/* Message type mask for FilterMessageType in Application parameter */
+#define BTA_MA_MSG_TYPE_MASK_SMS_GSM (1<<0)
+#define BTA_MA_MSG_TYPE_MASK_SMS_CDMA (1<<1)
+#define BTA_MA_MSG_TYPE_MASK_EMAIL (1<<2)
+#define BTA_MA_MSG_TYPE_MASK_MMS (1<<3)
+
+
+typedef UINT8 tBTA_MA_MSG_TYPE_MASK;
+
+
+
+/* Parameter Mask for Messages-Listing */
+#define BTA_MA_ML_MASK_SUBJECT (1<<0)
+#define BTA_MA_ML_MASK_DATETIME (1<<1)
+#define BTA_MA_ML_MASK_SENDER_NAME (1<<2)
+#define BTA_MA_ML_MASK_SENDER_ADDRESSING (1<<3)
+#define BTA_MA_ML_MASK_RECIPIENT_NAME (1<<4)
+#define BTA_MA_ML_MASK_RECIPIENT_ADDRESSING (1<<5)
+#define BTA_MA_ML_MASK_TYPE (1<<6)
+#define BTA_MA_ML_MASK_SIZE (1<<7)
+#define BTA_MA_ML_MASK_RECEPTION_STATUS (1<<8)
+#define BTA_MA_ML_MASK_TEXT (1<<9)
+#define BTA_MA_ML_MASK_ATTACHMENT_SIZE (1<<10)
+#define BTA_MA_ML_MASK_PRIORITY (1<<11)
+#define BTA_MA_ML_MASK_READ (1<<12)
+#define BTA_MA_ML_MASK_SENT (1<<13)
+#define BTA_MA_ML_MASK_PROTECTED (1<<14)
+#define BTA_MA_ML_MASK_REPLYTO_ADDRESSING (1<<15)
+
+typedef UINT32 tBTA_MA_ML_MASK;
+
+/* Read status used for message list */
+enum
+{
+ BTA_MA_READ_STATUS_NO_FILTERING = 0,
+ BTA_MA_READ_STATUS_UNREAD = 1,
+ BTA_MA_READ_STATUS_READ = 2
+};
+typedef UINT8 tBTA_MA_READ_STATUS;
+
+/* Priority status used for filtering message list */
+enum
+{
+ BTA_MA_PRI_STATUS_NO_FILTERING = 0,
+ BTA_MA_PRI_STATUS_HIGH = 1,
+ BTA_MA_PRI_STATUS_NON_HIGH = 2
+};
+typedef UINT8 tBTA_MA_PRI_STATUS;
+
+#define BTA_MA_LTIME_LEN 15
+typedef struct
+{
+ tBTA_MA_ML_MASK parameter_mask;
+ UINT16 max_list_cnt;
+ UINT16 list_start_offset;
+ UINT8 subject_length; /* valid range 1...255 */
+ tBTA_MA_MSG_TYPE_MASK msg_mask;
+ char period_begin[BTA_MA_LTIME_LEN+1]; /* "yyyymmddTHHMMSS", or "" if none */
+ char period_end[BTA_MA_LTIME_LEN+1]; /* "yyyymmddTHHMMSS", or "" if none */
+ tBTA_MA_READ_STATUS read_status;
+ char recipient[BTA_MA_MAX_FILTER_TEXT_SIZE+1]; /* "" if none */
+ char originator[BTA_MA_MAX_FILTER_TEXT_SIZE+1];/* "" if none */
+ tBTA_MA_PRI_STATUS pri_status;
+} tBTA_MA_MSG_LIST_FILTER_PARAM;
+
+/* enum for charset used in GetMEssage */
+enum
+{
+ BTA_MA_CHARSET_NATIVE = 0,
+ BTA_MA_CHARSET_UTF_8 = 1,
+ BTA_MA_CHARSET_UNKNOWN,
+ BTA_MA_CHARSET_MAX
+};
+typedef UINT8 tBTA_MA_CHARSET;
+
+/* enum for fraction request used in GetMEssage */
+enum
+{
+ BTA_MA_FRAC_REQ_FIRST = 0,
+ BTA_MA_FRAC_REQ_NEXT = 1,
+ BTA_MA_FRAC_REQ_NO, /* this is not a fraction request */
+ BTA_MA_FRAC_REQ_MAX
+};
+typedef UINT8 tBTA_MA_FRAC_REQ;
+
+/* enum for fraction delivery used in GetMEssage */
+enum
+{
+ BTA_MA_FRAC_DELIVER_MORE = 0,
+ BTA_MA_FRAC_DELIVER_LAST = 1,
+ BTA_MA_FRAC_DELIVER_NO, /* this is not a fraction deliver*/
+ BTA_MA_FRAC_DELIVER_MAX
+};
+typedef UINT8 tBTA_MA_FRAC_DELIVER;
+
+
+typedef struct
+{
+ BOOLEAN attachment;
+ tBTA_MA_MSG_HANDLE handle;
+ tBTA_MA_CHARSET charset;
+ tBTA_MA_FRAC_REQ fraction_request;
+} tBTA_MA_GET_MSG_PARAM;
+
+#define BTA_MA_RETRY_OFF 0
+#define BTA_MA_RETRY_ON 1
+#define BTA_MA_RETRY_UNKNOWN 0xff
+typedef UINT8 tBTA_MA_RETRY_TYPE;
+
+
+#define BTA_MA_TRANSP_OFF 0
+#define BTA_MA_TRANSP_ON 1
+#define BTA_MA_TRANSP_UNKNOWN 0xff
+typedef UINT8 tBTA_MA_TRANSP_TYPE;
+
+typedef struct
+{
+ char *p_folder; /* current or child folder
+ for current folder set
+ *p_folder = ""
+ */
+ char *p_msg_name; /* for MCE use only*/
+ tBTA_MA_TRANSP_TYPE transparent;
+ tBTA_MA_RETRY_TYPE retry;
+ tBTA_MA_CHARSET charset;
+
+} tBTA_MA_PUSH_MSG_PARAM;
+
+/* get or push message multi-packet status */
+enum
+{
+ BTA_MA_MPKT_STATUS_MORE = 0,
+ BTA_MA_MPKT_STATUS_LAST,
+ BTA_MA_MPKT_MAX
+};
+
+typedef UINT8 tBTA_MA_MPKT_STATUS;
+
+/* definitions for directory navigation */
+#define BTA_MA_DIR_NAV_ROOT_OR_DOWN_ONE_LVL 2
+#define BTA_MA_DIR_NAV_UP_ONE_LVL 3
+
+typedef UINT8 tBTA_MA_DIR_NAV;
+
+enum
+{
+ BTA_MA_ATTACH_OFF = 0,
+ BTA_MA_ATTACH_ON
+};
+typedef UINT8 tBTA_MA_ATTACH_TYPE;
+
+/* MAS tag ID in application parameters header definition */
+#define BTA_MA_APH_MAX_LIST_COUNT 0x01 /* MaxListCount 2 bytes 0x0000 to 0xFFFF */
+#define BTA_MA_APH_START_STOFF 0x02 /* StartOffset 2 bytes 0x0000 to 0xFFFF */
+#define BTA_MA_APH_FILTER_MSG_TYPE 0x03 /* SearchAttribute 1 byte 1,2,4 */
+#define BTA_MA_APH_FILTER_PRD_BEGIN 0x04 /* Filter Period Begin variable */
+#define BTA_MA_APH_FILTER_PRD_END 0x05 /* Filter Period End variable */
+#define BTA_MA_APH_FILTER_READ_STS 0x06 /* Filter read status 1 byte 0, 1, 2 */
+#define BTA_MA_APH_FILTER_RECEIP 0x07 /* FilterRecipient variable */
+#define BTA_MA_APH_FILTER_ORIGIN 0x08 /* FilterOriginator variable */
+#define BTA_MA_APH_FILTER_PRIORITY 0x09 /* FilterPriority 1 byte */
+#define BTA_MA_APH_ATTACH 0x0a /* Attachment 1 byte */
+#define BTA_MA_APH_TRANSPARENT 0x0b /* transparent 1 byte */
+#define BTA_MA_APH_RETRY 0x0c /* retry 1 byte */
+#define BTA_MA_APH_NEW_MSG 0x0d /* NewMessage 1 byte */
+#define BTA_MA_APH_NOTIF_STATUS 0x0e /* Notification Status 1 byte */
+#define BTA_MA_APH_MAS_INST_ID 0x0f /* MAS instance ID 1 byte 0 ... 255 */
+#define BTA_MA_APH_PARAM_MASK 0x10 /* Parameter mask 2 bytes */
+#define BTA_MA_APH_FOLDER_LST_SIZE 0x11 /* Folder Listing Size 2 bytes */
+#define BTA_MA_APH_MSG_LST_SIZE 0x12 /* Message Listing Size 2 bytes */
+#define BTA_MA_APH_SUBJ_LEN 0x13 /* Subject Length 1 byte */
+#define BTA_MA_APH_CHARSET 0x14 /* Character Set 1 byte :0, 1 */
+#define BTA_MA_APH_FRAC_REQ 0x15 /* Fraction request 1 byte :0, 1 */
+#define BTA_MA_APH_FRAC_DELVR 0x16 /* Fraction delivery 1 byte :0, 1 */
+#define BTA_MA_APH_STS_INDCTR 0x17 /* Status Indicator 1 byte */
+#define BTA_MA_APH_STS_VALUE 0x18 /* Status Value 1 byte: 0, 1 */
+#define BTA_MA_APH_MSE_TIME 0x19 /* MSETime variable */
+
+#define BTA_MA_BODY_FILLER_BYTE 0x30
+
+/* MAS type header */
+#define BTA_MA_HDR_TYPE_NOTIF_REG "x-bt/MAP-NotificationRegistration"
+#define BTA_MA_HDR_TYPE_MSG_UPDATE "x-bt/MAP-messageUpdate"
+#define BTA_MA_HDR_TYPE_EVENT_RPT "x-bt/MAP-event-report"
+#define BTA_MA_HDR_TYPE_MSG_LIST "x-bt/MAP-msg-listing"
+#define BTA_MA_HDR_TYPE_MSG "x-bt/message"
+#define BTA_MA_HDR_TYPE_MSG_STATUS "x-bt/messageStatus"
+#define BTA_MA_HDR_TYPE_FOLDER_LIST "x-obex/folder-listing"
+
+#define BTA_MAS_MESSAGE_ACCESS_TARGET_UUID "\xBB\x58\x2B\x40\x42\x0C\x11\xDB\xB0\xDE\x08\x00\x20\x0C\x9A\x66"
+#define BTA_MAS_MESSAGE_NOTIFICATION_TARGET_UUID "\xBB\x58\x2B\x41\x42\x0C\x11\xDB\xB0\xDE\x08\x00\x20\x0C\x9A\x66"
+#define BTA_MAS_UUID_LENGTH 16
+#define BTA_MAS_DEFAULT_VERSION 0x0100
+
+#define BTA_MA_NOTIF_STS_TAG_ID 0x0E
+#define BTA_MA_NOTIF_STS_LEN 0x01
+#define BTA_MA_NOTIF_STS_ON 0x01
+#define BTA_MA_NOTIF_STS_OFF 0x00
+
+#define BTA_MA_NAS_INST_ID_TAG_ID 0x0F
+#define BTA_MA_NAS_INST_ID_LEN 0x01
+
+#define BTA_MA_DEFAULT_MAX_LIST_CNT 1024
+
+
+#define BTA_MA_64BIT_HEX_STR_SIZE (16+1)
+#define BTA_MA_32BIT_HEX_STR_SIZE (8+1)
+
+
+
+/*******************************************************************************
+**
+** bMessage types
+**
+** Description The following types are designed to hold data in memory.
+** The internal structure of these types are implementation
+** specific.
+**
+*******************************************************************************/
+
+enum
+{
+ BTA_MA_BMSG_ENC_8BIT = 0, /* Used for Email/MMS */
+
+ BTA_MA_BMSG_ENC_G7BIT, /* Used for GSM-SMS */
+ BTA_MA_BMSG_ENC_G7BITEXT,
+ BTA_MA_BMSG_ENC_GUCS2,
+ BTA_MA_BMSG_ENC_G8BIT,
+
+ BTA_MA_BMSG_ENC_C8BIT, /* Used for CDMA-SMS */
+ BTA_MA_BMSG_ENC_CEPM,
+ BTA_MA_BMSG_ENC_C7ASCII,
+ BTA_MA_BMSG_ENC_CIA5,
+ BTA_MA_BMSG_ENC_CUNICODE,
+ BTA_MA_BMSG_ENC_CSJIS,
+ BTA_MA_BMSG_ENC_CKOREAN,
+ BTA_MA_BMSG_ENC_CLATINHEB,
+ BTA_MA_BMSG_ENC_CLATIN,
+
+ BTA_MA_BMSG_ENC_UNKNOWN
+};
+typedef UINT8 tBTA_MA_BMSG_ENCODING;
+
+enum
+{
+ BTA_MA_BMSG_LANG_UNSPECIFIED = 0,
+
+ BTA_MA_BMSG_LANG_UNKNOWN,
+ BTA_MA_BMSG_LANG_SPANISH, /* GSM-SMS or CDMA-SMS */
+
+ BTA_MA_BMSG_LANG_TURKISH, /* GSM-SMS only */
+ BTA_MA_BMSG_LANG_PORTUGUESE,
+
+ BTA_MA_BMSG_LANG_ENGLISH, /* CDMA-SMS only */
+ BTA_MA_BMSG_LANG_FRENCH,
+ BTA_MA_BMSG_LANG_JAPANESE,
+ BTA_MA_BMSG_LANG_KOREAN,
+ BTA_MA_BMSG_LANG_CHINESE,
+ BTA_MA_BMSG_LANG_HEBREW
+};
+typedef UINT8 tBTA_MA_BMSG_LANGUAGE;
+
+
+enum
+{
+ BTA_MA_VCARD_VERSION_21=0,
+ BTA_MA_VCARD_VERSION_30
+};
+typedef UINT8 tBTA_MA_VCARD_VERSION;
+
+enum
+{
+ BTA_MA_VCARD_PROP_N,
+ BTA_MA_VCARD_PROP_FN,
+ BTA_MA_VCARD_PROP_TEL,
+ BTA_MA_VCARD_PROP_EMAIL,
+
+ BTA_MA_VCARD_PROP_MAX
+};
+typedef UINT8 tBTA_MA_VCARD_PROP;
+
+typedef struct
+{
+ char * p_param;
+ char * p_value;
+
+ /* link to the next property (if any) */
+ void * p_next;
+
+} tBTA_MA_VCARD_PROPERTY;
+
+typedef struct
+{
+ tBTA_MA_VCARD_VERSION version;
+
+ tBTA_MA_VCARD_PROPERTY * p_prop[BTA_MA_VCARD_PROP_MAX];
+
+ /* link to the next vCard (if any) */
+ void * p_next;
+
+} tBTA_MA_BMSG_VCARD;
+
+typedef struct BMSG_MESSAGE_struct
+{
+ char * p_text;
+
+ /* link to the next chunk of message text (if any) */
+ void * p_next;
+
+} tBTA_MA_BMSG_MESSAGE;
+
+typedef struct BMSG_CONTENT_struct
+{
+ /* this is the first bit of message text */
+ tBTA_MA_BMSG_MESSAGE * p_message;
+
+ /* this points to the last entered text -or-
+ ** it is the last that we returned back to
+ **
+ */
+ tBTA_MA_BMSG_MESSAGE * p_last;
+
+ /* link to the next chunk of content (if any) */
+ void * p_next;
+
+} tBTA_MA_BMSG_CONTENT;
+
+
+typedef struct
+{
+ /* Part ID */
+ UINT16 part_id;
+ BOOLEAN is_multipart;
+
+ /* Properties */
+ tBTA_MA_BMSG_ENCODING encoding;
+ tBTA_MA_BMSG_LANGUAGE language; /* optional */
+ tBTA_MA_CHARSET charset;
+ /* One or more body content */
+ tBTA_MA_BMSG_CONTENT * p_content;
+
+} tBTA_MA_BMSG_BODY;
+
+typedef struct BMSG_ENVELOPE_struct
+{
+ /* One or more Recipient (vCards) */
+ tBTA_MA_BMSG_VCARD * p_recip;
+
+ /* There will be either another envelope or the body */
+ void * p_next;
+ tBTA_MA_BMSG_BODY * p_body;
+
+} tBTA_MA_BMSG_ENVELOPE;
+
+typedef struct
+{
+ /* Property values */
+ BOOLEAN read_sts;
+ tBTA_MA_MSG_TYPE msg_type;
+ char * p_folder;
+
+ /* One or more Originator (vCards) */
+ tBTA_MA_BMSG_VCARD * p_orig;
+
+ /* Envelope */
+ tBTA_MA_BMSG_ENVELOPE * p_envelope;
+
+} tBTA_MA_BMSG;
+
+
+#endif
+
diff --git a/bta/include/bta_mse_api.h b/bta/include/bta_mse_api.h
new file mode 100644
index 0000000..742ea7a
--- /dev/null
+++ b/bta/include/bta_mse_api.h
@@ -0,0 +1,470 @@
+/*****************************************************************************
+**
+** Name: bta_mse_api.h
+**
+** Description: This is the public interface file for the Message Server Equipment
+** (MSE) subsystem of BTA, Broadcom's
+** Bluetooth application layer for mobile phones.
+**
+** Copyright (c) 2009, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_MSE_API_H
+#define BTA_MSE_API_H
+
+#include "bta_api.h"
+#include "bta_ma_def.h"
+
+/*****************************************************************************
+** Constants and data types
+*****************************************************************************/
+/* Extra Debug Code */
+#ifndef BTA_MSE_DEBUG
+ #define BTA_MSE_DEBUG TRUE
+#endif
+
+/**************************
+** Common Definitions
+***************************/
+
+/* MSE callback function events */
+enum
+{
+ BTA_MSE_ENABLE_EVT = 0, /* MAS server is enabled. */
+ BTA_MSE_DISABLE_EVT,
+ BTA_MSE_ACCESS_EVT,
+ BTA_MSE_OPER_CMPL_EVT, /* MSE operation complete */
+ BTA_MSE_MA_OPEN_EVT,
+ BTA_MSE_MA_CLOSE_EVT,
+ BTA_MSE_SET_NOTIF_REG_EVT,
+ BTA_MSE_NOTIF_REG_EVT,
+ BTA_MSE_UPDATE_INBOX_EVT,
+ BTA_MSE_GET_MSG_IN_PROG_EVT,
+ BTA_MSE_PUSH_MSG_IN_PROG_EVT,
+ BTA_MSE_SEND_NOTIF_EVT,
+ BTA_MSE_MN_OPEN_EVT,
+ BTA_MSE_MN_CLOSE_EVT,
+ BTA_MSE_START_EVT,
+ BTA_MSE_STOP_EVT
+};
+typedef UINT8 tBTA_MSE_EVT;
+
+
+/* Structure associated with BTA_MSE_ENABLE_EVT
+ BTA_MSE_DISABLE_EVT
+*/
+typedef struct
+{
+ tBTA_MA_STATUS status;
+ UINT8 app_id;
+} tBTA_MSE_ENABLE_DISABLE;
+
+
+/*******************************************
+** Message Access Server Definitions
+********************************************/
+/* Access event operation types */
+#define BTA_MSE_OPER_NONE 0
+#define BTA_MSE_OPER_SETPATH 1
+#define BTA_MSE_OPER_GET_FOLDER_LIST 2
+#define BTA_MSE_OPER_GET_MSG_LIST 3
+#define BTA_MSE_OPER_GET_MSG 4
+#define BTA_MSE_OPER_SET_MSG_STATUS 5
+#define BTA_MSE_OPER_DEL_MSG 6
+#define BTA_MSE_OPER_PUSH_MSG 7
+#define BTA_MSE_OPER_NOTIF_REG 8
+#define BTA_MSE_OPER_UPDATE_INBOX 9
+
+typedef UINT8 tBTA_MSE_OPER;
+
+/* Structure associated with BTA_MSE_ACCESS_EVT */
+typedef struct
+{
+ tBTA_MA_SESS_HANDLE mas_session_id; /* MAS Session ID */
+ tBTA_MSE_OPER oper; /* operation */
+ char *p_path; /* full path name */
+ tBTM_BD_NAME dev_name; /* Name of device, "" if unknown */
+ BD_ADDR bd_addr; /* Address of device */
+ tBTA_MA_MSG_HANDLE handle;
+ BOOLEAN delete_sts;
+} tBTA_MSE_ACCESS;
+
+/* Structure associated with BTA_MSE_OPER_CMPL_EVT */
+typedef struct
+{
+ UINT32 obj_size; /* Total size of object 0 if unknow*/
+ tBTA_MA_SESS_HANDLE mas_session_id; /* MAS Session ID */
+ tBTA_MSE_OPER operation;
+ tBTA_MA_STATUS status;
+} tBTA_MSE_OPER_CMPL;
+
+
+/* Structure associated with BTA_MSE_MA_OPEN_EVT */
+typedef struct
+{
+ tBTA_MA_INST_ID mas_instance_id; /* MAS instance ID: one MAS
+ instance can support multiple
+ sessions */
+ tBTA_MA_SESS_HANDLE mas_session_id; /* MAS Session ID, all session based
+ operation will need to use this ID */
+ tBTM_BD_NAME dev_name; /* Name of device, "" if unknown */
+ BD_ADDR bd_addr; /* Address of device */
+
+} tBTA_MSE_MA_OPEN;
+
+/* Structure associated with BTA_MSE_MA_CLOSE_EVT */
+typedef struct
+{
+ tBTA_MA_STATUS status;
+ tBTA_MA_SESS_HANDLE mas_session_id;
+ tBTA_MA_INST_ID mas_instance_id;
+} tBTA_MSE_MA_CLOSE;
+
+/* Structure associated with BTA_MSE_MN_OPEN_EVT or
+ BTA_MSE_MN_CLOSE_EVT
+*/
+typedef struct
+{
+ tBTM_BD_NAME dev_name; /* Name of device, "" if unknown */
+ BD_ADDR bd_addr; /* Address of device */
+ tBTA_MA_INST_ID first_mas_instance_id; /* MN connection can be used for more
+ than one MasInstanceIDs.
+ first_mas_instance_id is the MasInstanceId of a
+ MAS service MCE first registers to receive the
+ message notification */
+} tBTA_MSE_MN_OPEN;
+
+typedef struct
+{
+ tBTM_BD_NAME dev_name; /* Name of device, "" if unknown */
+ BD_ADDR bd_addr; /* Address of device */
+} tBTA_MSE_MN_CLOSE;
+
+/* Update Inbox response types */
+enum
+{
+ BTA_MSE_UPDATE_INBOX_ALLOW = 0, /* Allow the update inbox */
+ BTA_MSE_UPDATE_INBOX_FORBID /* Disallow the update inbox */
+};
+typedef UINT8 tBTA_MSE_UPDATE_INBOX_TYPE;
+
+
+/* Set Notification Registration response types */
+enum
+{
+ BTA_MSE_SET_NOTIF_REG_ALLOW = 0, /* Allow the notification registration request*/
+ BTA_MSE_SET_NOTIF_REG_FORBID /* Disallow the notification registration request */
+};
+typedef UINT8 tBTA_MSE_SET_NOTIF_REG_TYPE;
+
+/* Structure associated with BTA_MSE_SEND_NOTIF_EVT */
+typedef struct
+{
+ tBTA_MA_STATUS status;
+ tBTA_MA_INST_ID mas_instance_id;
+ BD_ADDR bd_addr; /* remote MCE's BD address*/
+} tBTA_MSE_SEND_NOTIF;
+
+
+/* Structure associated with BTA_MSE_START_EVT or
+ BTA_MSE_STOP_EVT */
+typedef struct
+{
+ tBTA_MA_STATUS status;
+ UINT8 mas_instance_id;
+} tBTA_MSE_START_STOP;
+
+typedef struct
+{
+ tBTA_MA_SESS_HANDLE mas_session_id;
+ tBTA_MA_INST_ID mas_instance_id;
+ tBTA_MA_NOTIF_STATUS notif_status;
+ BD_ADDR bd_addr; /* remote MCE's BD address*/
+}tBTA_MSE_SET_NOTIF_REG;
+
+typedef struct
+{
+ tBTA_MA_STATUS status;
+ tBTA_MA_SESS_HANDLE mas_session_id;
+ tBTA_MA_INST_ID mas_instance_id;
+ tBTA_MA_NOTIF_STATUS notif_status;
+ BD_ADDR bd_addr; /* remote MCE's BD address*/
+}tBTA_MSE_NOTIF_REG;
+
+
+/* Data associated with call back events */
+typedef union
+{
+ tBTA_MA_SESS_HANDLE mas_session_id; /* BTA_MSE_UPDATE_INBOX_EVT*/
+ tBTA_MSE_ENABLE_DISABLE enable;
+ tBTA_MSE_ENABLE_DISABLE disable;
+ tBTA_MSE_ACCESS access;
+ tBTA_MSE_SET_NOTIF_REG set_notif_reg;
+ tBTA_MSE_NOTIF_REG notif_reg;
+ tBTA_MSE_MN_OPEN mn_open;
+ tBTA_MSE_MN_CLOSE mn_close;
+ tBTA_MSE_MA_OPEN ma_open;
+ tBTA_MSE_MA_CLOSE ma_close;
+ tBTA_MSE_SEND_NOTIF send_notif;
+ tBTA_MA_IN_PROG get_msg_in_prog;
+ tBTA_MA_IN_PROG push_msg_in_prog;
+ tBTA_MSE_OPER_CMPL oper_cmpl;
+ tBTA_MSE_START_STOP start;
+ tBTA_MSE_START_STOP stop;
+} tBTA_MSE;
+
+/* MSE callback function */
+typedef void tBTA_MSE_CBACK(tBTA_MSE_EVT event, tBTA_MSE *p_data);
+
+
+/********************************************
+** Message Notification Client Definitions
+*********************************************/
+
+/* Send Notification function arguments definition */
+enum
+{
+ BTA_MSE_NOTIF_TYPE_NEW_MSG = 0,
+ BTA_MSE_NOTIF_TYPE_DELIVERY_SUCCESS,
+ BTA_MSE_NOTIF_TYPE_SENDING_SUCCESS,
+ BTA_MSE_NOTIF_TYPE_DELIVERY_FAILURE,
+ BTA_MSE_NOTIF_TYPE_SENDING_FAILURE,
+ BTA_MSE_NOTIF_TYPE_MEMORY_FULL,
+ BTA_MSE_NOTIF_TYPE_MEMORY_AVAILABLE,
+ BTA_MSE_NOTIF_TYPE_MESSAGE_DELETED,
+ BTA_MSE_NOTIF_TYPE_MESSAGE_SHIFT,
+ BTA_MSE_NOTIF_TYPE_MAX
+};
+
+typedef UINT8 tBTA_MSE_NOTIF_TYPE;
+
+/* configuration related constant */
+
+
+
+/* MSE configuration data */
+#define BTA_MSE_NUM_INST 4
+#define BTA_MSE_NUM_SESS 4
+#define BTA_MSE_NUM_MN 7 /* i.e. up to 7 MCEs can be connected to the MSE */
+
+typedef struct
+{
+ INT32 obx_rsp_tout; /* maximum amount of time to wait for obx rsp */
+ UINT16 max_name_len; /* maximum folder name length */
+
+} tBTA_MSE_CFG;
+
+extern tBTA_MSE_CFG * p_bta_mse_cfg;
+/*****************************************************************************
+** External Function Declarations
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**************************
+** API Functions
+***************************/
+
+/*******************************************************************************
+**
+** Function BTA_MseEnable
+**
+** Description Enable the MSE subsystems. This function must be
+** called before any other functions in the MSE API are called.
+** When the enable operation is completed the callback function
+** will be called with an BTA_MSE_ENABLE_EVT event.
+**
+** Parameters p_cback - MSE event call back function
+** app_id - Application ID
+**
+** Returns void
+**
+*******************************************************************************/
+ BTA_API extern void BTA_MseEnable(tBTA_MSE_CBACK *p_cback, UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function BTA_MseDisable
+**
+** Description Disable the MSE subsystem.
+**
+** Parameters
+**
+** Returns void
+**
+*******************************************************************************/
+ BTA_API extern void BTA_MseDisable(void);
+/*******************************************************************************
+**
+** Function BTA_MseStart
+**
+** Description Start a MA server on the MSE
+**
+**
+** Parameters mas_inst_id - MAS instance ID
+** sec_mask - Security Setting Mask
+** MSE always enables
+** (BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT)
+** p_service_name - Pointer to service name
+** p_root_path - Pointer to root path
+** (one level above telecom)
+** sup_msg_type - supported message type(s)
+**
+** Returns void
+**
+*******************************************************************************/
+ BTA_API extern void BTA_MseStart( tBTA_MA_INST_ID mas_inst_id,
+ tBTA_SEC sec_mask, const char *p_service_name,
+ const char *p_root_path,
+ tBTA_MA_MSG_TYPE sup_msg_type);
+/*******************************************************************************
+**
+** Function BTA_MseStop
+**
+** Description Stop a MAS service on the MSE
+**
+** Parameters mas_instance_id - MAS Instance ID
+**
+** Returns void
+**
+*******************************************************************************/
+ BTA_API extern void BTA_MseStop (tBTA_MA_INST_ID mas_instance_id);
+
+/*******************************************************************************
+**
+** Function BTA_MseClose
+**
+** Description Close all MAS sessions on the specified MAS Instance ID
+**
+** Parameters mas_instance_id - MAS Inatance ID
+**
+** Returns void
+**
+*******************************************************************************/
+ BTA_API extern void BTA_MseClose(tBTA_MA_INST_ID mas_instance_id);
+
+/*******************************************************************************
+**
+** Function BTA_MseMaClose
+**
+** Description Close a MAS sessions on the specified BD address
+**
+** Parameters bd_addr - remote BD's address
+** mas_instance_id - MAS Inatance ID
+**
+** Returns void
+**
+*******************************************************************************/
+ BTA_API extern void BTA_MseMaClose(BD_ADDR bd_addr, tBTA_MA_INST_ID mas_instance_id);
+
+/*******************************************************************************
+**
+** Function BTA_MseMnClose
+**
+** Description Close a MN session
+**
+** Parameters bd_addr - remote BT's address
+**
+** Returns void
+**
+*******************************************************************************/
+ BTA_API extern void BTA_MseMnClose(BD_ADDR bd_addr);
+
+/*******************************************************************************
+**
+** Function BTA_MseAccessRsp
+**
+** Description Send a response for the access request
+**
+** Parameters mas_session_id - MAS session ID
+** oper - MAS operation type
+** access - Access is allowed or not
+** p_path - pointer to a path if if the operation
+** involves accessing a folder
+** Returns void
+**
+*******************************************************************************/
+ BTA_API extern void BTA_MseAccessRsp(tBTA_MA_SESS_HANDLE mas_session_id, tBTA_MSE_OPER oper,
+ tBTA_MA_ACCESS_TYPE access, char *p_name);
+
+/*******************************************************************************
+**
+** Function BTA_MseUpdateInboxRsp
+**
+** Description Send a response for the update inbox request
+**
+**
+** Parameters mas_session_id - MAS session ID
+** update_rsp - update inbox is allowed or not
+**
+** Returns void
+**
+*******************************************************************************/
+ BTA_API extern void BTA_MseUpdateInboxRsp(tBTA_MA_SESS_HANDLE mas_session_id,
+ tBTA_MSE_UPDATE_INBOX_TYPE update_rsp);
+
+/*******************************************************************************
+**
+** Function BTA_MseSetNotifRegRsp
+**
+** Description Send a response for the set notification registration
+**
+**
+** Parameters mas_session_id - MAS session ID
+** set_notif_reg_rsp - indicate whether the set notification
+** registration is allowed or not
+**
+** Returns void
+**
+*******************************************************************************/
+ BTA_API extern void BTA_MseSetNotifRegRsp(tBTA_MA_SESS_HANDLE mas_session_id,
+ tBTA_MSE_SET_NOTIF_REG_TYPE set_notif_reg_rsp);
+
+/*******************************************************************************
+**
+** Function BTA_MseSendNotif
+**
+** Description Send a Message notification report to all MCEs registered with
+** the specified MAS instance ID
+**
+** Parameters mas_instance_id - MAS Instance ID
+** notif_type - message notification type
+** handle - message handle
+** p_folder - pointer to current folder
+** p_old_folder - pointer to older folder
+** msg_type - message type (E_MAIL, SMS_GSM, SMS_CDMA, MMS)
+** except_bd_addr - except to the MCE on this BD Address.
+** (Note: notification will be not sent to
+** this BD Addreess)
+**
+** Returns void
+**
+*******************************************************************************/
+ BTA_API extern void BTA_MseSendNotif(tBTA_MA_INST_ID mas_instance_id,
+ tBTA_MSE_NOTIF_TYPE notif_type,
+ tBTA_MA_MSG_HANDLE handle,
+ char * p_folder, char *p_old_folder,
+ tBTA_MA_MSG_TYPE msg_type,
+ BD_ADDR except_bd_addr);
+
+/*******************************************************************************
+**
+** Function BTA_MseMnAbort
+**
+** Description Abort the current OBEX multi-packt operation
+**
+** Parameters mas_instance_id - MAS Instance ID
+**
+** Returns void
+**
+*******************************************************************************/
+ BTA_API extern void BTA_MseMnAbort(tBTA_MA_INST_ID mas_instance_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_MSE_API_H */
diff --git a/bta/include/bta_mse_ci.h b/bta/include/bta_mse_ci.h
new file mode 100644
index 0000000..f366f16
--- /dev/null
+++ b/bta/include/bta_mse_ci.h
@@ -0,0 +1,146 @@
+/*****************************************************************************
+**
+** Name: bta_mse_ci.h
+**
+** Description: This is the interface file for the Message Server Equipment
+** (MSE) subsystem call-out functions.
+**
+** Copyright (c) 2009, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_MSE_CI_H
+#define BTA_MSE_CI_H
+
+#include "bta_api.h"
+#include "bta_ma_def.h"
+#include "bta_mse_api.h"
+#include "bta_mse_co.h"
+
+/*******************************************************************************
+**
+** Function bta_mse_ci_get_folder_entry
+**
+** Description This function is called in response to the
+** bta_mse_co_get_folder_entry call-out function.
+**
+** Parameters mas_session_id - MAS session ID
+** status - BTA_MA_STATUS_OK if p_entry points to a valid entry.
+** BTA_MA_STATUS_EODIR if no more entries (p_entry is ignored).
+** BTA_MA_STATUS_FAIL if any errors have occurred.
+** evt - evt from the call-out function
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_mse_ci_get_folder_entry(tBTA_MA_SESS_HANDLE mas_session_id,
+ tBTA_MA_STATUS status,
+ UINT16 evt);
+/*******************************************************************************
+**
+** Function bta_mse_ci_get_msg_list_info
+**
+** Description This function is called in response to the
+** bta_mse_co_get_msg_list_info call-out function.
+**
+** Parameters mas_session_id - MAS session ID
+** status - BTA_MA_STATUS_OK operation is successful.
+** BTA_MA_STATUS_FAIL if any errors have occurred.
+** evt - evt from the call-out function
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_mse_ci_get_msg_list_info(tBTA_MA_SESS_HANDLE mas_session_id,
+ tBTA_MA_STATUS status,
+ UINT16 evt);
+/*******************************************************************************
+**
+** Function bta_mse_ci_get_msg_list_entry
+**
+** Description This function is called in response to the
+** bta_mse_co_get_msg_list_entry call-out function.
+**
+** Parameters mas_session_id - MAS session ID
+** status - BTA_MA_STATUS_OK if p_entry points to a valid entry.
+** BTA_MA_STATUS_EODIR if no more entries (p_entry is ignored).
+** BTA_MA_STATUS_FAIL if any errors have occurred.
+** evt - evt from the call-out function
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_mse_ci_get_msg_list_entry(tBTA_MA_SESS_HANDLE mas_session_id,
+ tBTA_MA_STATUS status,
+ UINT16 evt);
+/*******************************************************************************
+**
+** Function bta_mse_ci_get_msg
+**
+** Description This function is called in response to the
+** bta_mse_co_get_msg call-out function.
+**
+** Parameters mas_session_id - MAS session ID
+** status - BTA_MA_STATUS_OK if p_msg points to a valid bmessage.
+** BTA_MA_STATUS_FAIL if any errors have occurred.
+** filled_buff_size - size of the filled buffer
+** multi_pkt_status - BTA_MA_MPKT_STATUS_MORE - need to get more packets
+** BTA_MA_MPKT_STATUS_LAST - last packet of the bMessage
+** frac_deliver_status - BTA_MA_FRAC_DELIVER_MORE - other fractions following
+** this bMessage
+** BTA_MA_FRAC_DELIVER_LAST - Last fraction
+** evt - evt from the call-out function
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_mse_ci_get_msg(tBTA_MA_SESS_HANDLE mas_session_id,
+ tBTA_MA_STATUS status,
+ UINT16 filled_buff_size,
+ tBTA_MA_MPKT_STATUS multi_pkt_status,
+ tBTA_MA_FRAC_DELIVER frac_deliver_status,
+ UINT16 evt);
+/*******************************************************************************
+**
+** Function bta_mse_ci_set_msg_delete_status
+**
+** Description This function is called in response to the
+** bta_mse_co_set_msg_delete_status call-out function.
+**
+** Parameters mas_session_id - MAS session ID
+** status - BTA_MA_STATUS_OK if operation is successful.
+** BTA_MA_STATUS_FAIL if any errors have occurred.
+** evt - evt from the call-out function
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_mse_ci_set_msg_delete_status(tBTA_MA_SESS_HANDLE mas_session_id,
+ tBTA_MA_STATUS status,
+ UINT16 evt);
+/*******************************************************************************
+**
+** Function bta_mse_ci_push_msg
+**
+** Description This function is called in response to the
+** bta_mse_co_push_msg call-out function.
+**
+** Parameters mas_session_id - MAS session ID
+** status - BTA_MA_STATUS_OK if the message upload is successful.
+** BTA_MA_STATUS_FAIL if any errors have occurred.
+** last_packet - last packet of a multi-packet message
+** handle - message handle for the uploaded message if
+** status is BTA_MA_OK and last_packet is TRUE
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_mse_ci_push_msg(tBTA_MA_SESS_HANDLE mas_session_id,
+ tBTA_MA_STATUS status,
+ BOOLEAN last_packet,
+ tBTA_MA_MSG_HANDLE handle,
+ UINT16 evt);
+#endif /* BTA_MSE_CI_H */
+
+
+
+
diff --git a/bta/include/bta_mse_co.h b/bta/include/bta_mse_co.h
new file mode 100644
index 0000000..adc551f
--- /dev/null
+++ b/bta/include/bta_mse_co.h
@@ -0,0 +1,330 @@
+/*****************************************************************************
+**
+** Name: bta_mse_co.h
+**
+** Description: This is the interface file for the Message Server Equipment
+** (MSE) subsystem call-out functions.
+**
+** Copyright (c) 2009-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_MSE_CO_H
+#define BTA_MSE_CO_H
+
+#include "bta_api.h"
+#include "bta_ma_def.h"
+#include "bta_mse_api.h"
+
+/*****************************************************************************
+** Constants and Data Types
+*****************************************************************************/
+/**************************
+** Common Definitions
+***************************/
+
+
+/* Return structure type for a folder entry i.e. only folder level
+ information under the specified path and no file name */
+typedef struct
+{
+ UINT32 refdata; /* holder for OS specific data used to get next entry */
+ UINT32 filesize;
+ char *p_name; /* Contains the addr of memory to copy name into */
+ char crtime[BTA_FS_CTIME_LEN]; /* "yyyymmddTHHMMSSZ", or "" if none */
+ UINT8 mode; /* BTA_MSE_A_RDONLY and/or BTA_MSE_A_DIR */
+} tBTA_MSE_CO_FOLDER_ENTRY;
+
+
+#define BTA_MSE_CO_MAX_ADDR_LEN 256 /* See MAP spec 3.1.6 */
+#define BTA_MSE_CO_MAX_DATE_TIME 21 /* "YYYYMMDDTHHMMSS+hhmm" or "YYYYMMDDTHHMMSS" */
+
+enum
+{
+ BTA_MSE_CO_RCV_STATUS_COMPLETE = 0,
+ BTA_MSE_CO_RCV_STATUS_FRACTIONED,
+ BTA_MSE_CO_RCV_STATUS_NOTIFICATION,
+ BTA_MSE_CO_RCV_STATUS_MAX
+};
+
+typedef UINT8 tBTA_MSE_CO_RCV_STATUS;
+
+typedef struct
+{
+ UINT16 msg_list_size;
+ UINT8 mse_time_len;
+ char mse_time[BTA_FS_CTIME_LEN];
+ BOOLEAN new_msg;
+} tBTA_MSE_CO_MSG_LIST_INFO;
+
+typedef struct
+{
+ UINT32 refdata; /* holder for OS specific data used to get next msg entry */
+ tBTA_MA_ML_MASK parameter_mask;
+ UINT32 org_msg_size;
+ UINT32 attachment_size;
+ BOOLEAN text;
+ BOOLEAN high_priority;
+ BOOLEAN read;
+ BOOLEAN sent;
+ BOOLEAN is_protected;
+ tBTA_MA_MSG_HANDLE msg_handle;
+ tBTA_MA_MSG_TYPE type;
+ tBTA_MSE_CO_RCV_STATUS reception_status;
+ char subject[BTA_MSE_CO_MAX_ADDR_LEN];
+ char date_time[BTA_MSE_CO_MAX_DATE_TIME]; /* "YYYYMMDDTHHMMSS+hhmm", "YYYYMMDDTHHMMSS", or "" if none */
+ char sender_name[BTA_MSE_CO_MAX_ADDR_LEN];
+ char sender_addressing[BTA_MSE_CO_MAX_ADDR_LEN];
+ char recipient_name[BTA_MSE_CO_MAX_ADDR_LEN];
+ char recipient_addressing[BTA_MSE_CO_MAX_ADDR_LEN];
+ char replyto_addressing[BTA_MSE_CO_MAX_ADDR_LEN];
+} tBTA_MSE_CO_MSG_LIST_ENTRY;
+
+/*******************************************************************************
+**
+** Function bta_mse_co_update_inbox
+**
+** Description Update the inbox
+**
+** Parameters mas_session_id - MAS session ID
+** app_id - application ID specified in the enable functions.
+** It can be used to identify which application
+** is the caller of the call-out function.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_mse_co_update_inbox(tBTA_MA_SESS_HANDLE mas_session_id, UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function bta_mse_co_set_folder
+**
+** Description Set the current foldeer to the specified path
+**
+** Parameters mas_session_id - MAS session ID
+** p_path - points to the current folder path
+** app_id - application ID specified in the enable functions.
+** It can be used to identify which application
+** is the caller of the call-out function.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_mse_co_set_folder(tBTA_MA_SESS_HANDLE mas_session_id,
+ const char *p_path,
+ UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function bta_mse_co_get_folder_entry
+**
+** Description This function is called to get a folder entry for the
+** specified path. The folder name should be filled
+** into the location specified by p_entry.
+**
+** Parameters mas_session_id - MAS session ID
+** p_path - points to the folder path to get the subfolder entry
+** (fully qualified path)
+** first_item - TRUE if first search, FALSE if next search
+** p_entry (input/output) - Points to the current entry data
+** evt - event that must be passed into the call-in function.
+** app_id - application ID specified in the enable functions.
+** It can be used to identify which application
+** is the caller of the call-out function.
+**
+** Returns void
+**
+** Note: Upon completion of the request, the status is passed
+** in the bta_mse_ci_get_folder_entry() call-in function.
+** BTA_MA_STATUS_OK is returned when p_entry is valid,
+** BTA_MA_STATUS_EODIR is returned when no more entries [finished]
+** BTA_MA_STATUS_FAIL is returned if an error occurred
+**
+*******************************************************************************/
+BTA_API extern void bta_mse_co_get_folder_entry(tBTA_MA_SESS_HANDLE mas_session_id, const char *p_path,
+ BOOLEAN first_item, tBTA_MSE_CO_FOLDER_ENTRY *p_entry,
+ UINT16 evt, UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function bta_mse_co_get_msg_list_info
+**
+** Description This function is called to get a message list information for
+** the specified folder
+**
+** Parameters mas_session_id - MAS session ID
+** p_name - points to the current or child folder for getting the
+** message list information
+** (if *p_name == "" it means current folder)
+** filter_para - filter parameters for getting the message
+** list information
+** p_info(input/output) - Points to the message listing information
+** evt - event that be passed into the call-in function.
+** app_id - application ID specified in the enable functions.
+** It can be used to identify which application
+** is the caller of the call-out function.
+**
+** Returns void
+**
+** Note: Upon completion of the request, the status is passed
+** in the bta_mse_ci_get_msg_list_info() call-in function.
+** BTA_MA_STATUS_OK is returned when p_entry is valid
+** BTA_MA_STATUS_FAIL is returned if an error occurred
+**
+*******************************************************************************/
+BTA_API extern void bta_mse_co_get_msg_list_info(tBTA_MA_SESS_HANDLE mas_session_id, const char *p_name,
+ tBTA_MA_MSG_LIST_FILTER_PARAM * p_filter_param,
+ tBTA_MSE_CO_MSG_LIST_INFO * p_info,
+ UINT16 evt, UINT8 app_id);
+/*******************************************************************************
+**
+** Function bta_mse_co_get_msg_list_entry
+**
+** Description This function is called to retrieve a message list entry for
+** the specified folder. The msg information should be filled by
+** application into the location specified by p_entry.
+**
+** Parameters mas_session_id - MAS session ID
+** p_name - points to the current or child folder for getting the
+** message list entry
+** (if *p_name == "" it means current folder)
+** filter_para - filter parameters for getting message list
+** first_item - TRUE if first get, FALSE if next msg
+** p_entry(input/output) - Points to current entry data
+** evt - event that must be passed into the call-in function.
+** app_id - application ID specified in the enable functions.
+** It can be used to identify which application
+** is the caller of the call-out function.
+**
+** Returns void
+**
+** Note: Upon completion of the request, the status is passed
+** in the bta_mse_ci_get_msg_list_entry() call-in function.
+** BTA_MA_STATUS_OK is returned when p_entry is valid,
+** BTA_MA_STATUS_EODIR is returned when no more entries [finished]
+** BTA_MA_STATUS_FAIL is returned if an error occurred
+*******************************************************************************/
+BTA_API extern void bta_mse_co_get_msg_list_entry(tBTA_MA_SESS_HANDLE mas_session_id, const char *p_name,
+ tBTA_MA_MSG_LIST_FILTER_PARAM *p_filter_param,
+ BOOLEAN first_item, tBTA_MSE_CO_MSG_LIST_ENTRY *p_entry,
+ UINT16 evt, UINT8 app_id);
+/*******************************************************************************
+**
+** Function bta_mse_co_get_msg
+**
+** Description This function is called to retrieve a msessage for the
+** specified message handle. The message will be filled by
+** application in bMessage format into the location
+** specified by p_buffer. The status and size of the filled
+** buffer are returned by bta_mse_ci_get_msg() call-in function
+**
+**
+** Parameters mas_session_id - MAS session ID
+** p_param - points to the parameters for the get message operation
+** first_get - TRUE first get FALSE subsequent get
+** buffer_size - size of the buffer pointed by p_buffer
+** p_buffer - points to the bMessage object storage location
+** evt - event that be passed into the call-in function.
+** app_id - application ID specified in the enable functions.
+** It can be used to identify which application
+** is the caller of the call-out function.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_mse_co_get_msg(tBTA_MA_SESS_HANDLE mas_session_id,
+ tBTA_MA_GET_MSG_PARAM *p_param,
+ BOOLEAN first_get,
+ UINT16 buffer_size,
+ UINT8 *p_buffer,
+ UINT16 evt,
+ UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function bta_mse_co_set_msg_delete_status
+**
+** Description This function is called to set a message delete status
+**
+** Parameters mas_session_id - MAS session ID
+** handle - message handle
+** status value - 1- yes, 0 = No
+** evt_id - event that be passed into the call-in function.
+** app_id - application ID specified in the enable functions.
+** It can be used to identify which application
+** is the caller of the call-out function.
+**
+** Returns void
+**
+** Note: Upon completion of the request, the status is passed
+** in the bta_mse_ci_set_msg_delete_status() call-in function.
+** BTA_MA_STATUS_OK is returned when the delete operation is successful
+** BTA_MA_STATUS_FAIL is returned if an error occurred
+*******************************************************************************/
+BTA_API extern void bta_mse_co_set_msg_delete_status(tBTA_MA_SESS_HANDLE mas_session_id,
+ tBTA_MA_MSG_HANDLE handle,
+ UINT8 status_value,
+ UINT16 evt_id,
+ UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function bta_mse_co_set_msg_read_status
+**
+** Description This function is called to set a message read status
+**
+** Parameters mas_session_id - MAS session ID
+** handle - message handle
+** status value - 1- yes, 0 = No
+** app_id - application ID specified in the enable functions.
+** It can be used to identify which application
+** is the caller of the call-out function.
+**
+** Returns BTA_MA_STATUS_OK - read status change is successful
+** BTA_MA_STATUS_FAIL
+*******************************************************************************/
+BTA_API extern tBTA_MA_STATUS bta_mse_co_set_msg_read_status(tBTA_MA_SESS_HANDLE mas_session_id,
+ tBTA_MA_MSG_HANDLE handle,
+ UINT8 status_value,
+ UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function bta_mse_co_push_msg
+**
+** Description This function is called to upload a message to the
+** specified folder
+**
+** Parameters mas_session_id - MAS session ID
+** p_param - points to parameters for message upload
+** msg_len - length of the message to be uploaded
+** p_msg - points to the message to be uploaded
+** first_pkt - TRUE first push message packet
+** multi_pkt_status -
+** BTA_MA_MPKT_STATUS_MORE - need to get more packets
+** BTA_MA_MPKT_STATUS_LAST - last packet of
+** the bMessage to be uploaded
+** evt - event that be passed into the call-in function.
+** app_id - application ID specified in the enable functions.
+** It can be used to identify which application
+** is the caller of the call-out function.
+**
+** Returns void
+**
+** Note1: Upon completion of the request, the status is passed
+** in the bta_mse_ci_push_msg() call-in function.
+** BTA_MA_STATUS_OK is returned if the request is successful,
+** BTA_MA_STATUS_FAIL is returned if an error occurred
+**
+*******************************************************************************/
+BTA_API extern void bta_mse_co_push_msg(tBTA_MA_SESS_HANDLE mas_session_id,
+ tBTA_MA_PUSH_MSG_PARAM *p_param,
+ UINT16 msg_len,
+ UINT8 *p_msg,
+ BOOLEAN first_pkt,
+ tBTA_MA_MPKT_STATUS mpkt_status,
+ UINT16 evt,
+ UINT8 app_id);
+
+#endif /* BTA_MSE_CO_H */
diff --git a/bta/include/bta_op_api.h b/bta/include/bta_op_api.h
new file mode 100644
index 0000000..b2a624c
--- /dev/null
+++ b/bta/include/bta_op_api.h
@@ -0,0 +1,621 @@
+/*****************************************************************************
+**
+** Name: bta_op_api.h
+**
+** Description: This is the public interface file for the object push
+** (OP) client and server subsystem of BTA, Widcomm's
+** Bluetooth application layer for mobile phones.
+**
+** Copyright (c) 2003-2006, Broadcom Corp., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_OP_API_H
+#define BTA_OP_API_H
+
+#include "bta_api.h"
+
+/*****************************************************************************
+** Constants and data types
+*****************************************************************************/
+/* Extra Debug Code */
+#ifndef BTA_OPS_DEBUG
+#define BTA_OPS_DEBUG FALSE
+#endif
+
+#ifndef BTA_OPC_DEBUG
+#define BTA_OPC_DEBUG FALSE
+#endif
+
+
+/* Object format */
+#define BTA_OP_VCARD21_FMT 1 /* vCard 2.1 */
+#define BTA_OP_VCARD30_FMT 2 /* vCard 3.0 */
+#define BTA_OP_VCAL_FMT 3 /* vCal 1.0 */
+#define BTA_OP_ICAL_FMT 4 /* iCal 2.0 */
+#define BTA_OP_VNOTE_FMT 5 /* vNote */
+#define BTA_OP_VMSG_FMT 6 /* vMessage */
+#define BTA_OP_OTHER_FMT 0xFF /* other format */
+
+typedef UINT8 tBTA_OP_FMT;
+
+/* Object format mask */
+#define BTA_OP_VCARD21_MASK 0x01 /* vCard 2.1 */
+#define BTA_OP_VCARD30_MASK 0x02 /* vCard 3.0 */
+#define BTA_OP_VCAL_MASK 0x04 /* vCal 1.0 */
+#define BTA_OP_ICAL_MASK 0x08 /* iCal 2.0 */
+#define BTA_OP_VNOTE_MASK 0x10 /* vNote */
+#define BTA_OP_VMSG_MASK 0x20 /* vMessage */
+#define BTA_OP_ANY_MASK 0x40 /* Any type of object. */
+
+typedef UINT8 tBTA_OP_FMT_MASK;
+
+/* Status */
+#define BTA_OP_OK 0 /* Operation successful. */
+#define BTA_OP_FAIL 1 /* Operation failed. */
+#define BTA_OP_MEM 2 /* Not enough memory to complete operation. */
+
+typedef UINT8 tBTA_OP_STATUS;
+
+/* vCal Object Type */
+#define BTA_OP_VCAL_EVENT 0 /* Object is an "Event" object. */
+#define BTA_OP_VCAL_TODO 1 /* Object is a "ToDo" object. */
+
+typedef UINT8 tBTA_OP_VCAL;
+
+/* vCard Property Names */
+#define BTA_OP_VCARD_ADR 1 /* Address. */
+#define BTA_OP_VCARD_EMAIL 2 /* Email address. */
+#define BTA_OP_VCARD_FN 3 /* Formatted name. */
+#define BTA_OP_VCARD_NOTE 4 /* Note. */
+#define BTA_OP_VCARD_NICKNAME 5 /* Nickname. */
+#define BTA_OP_VCARD_N 6 /* Name. */
+#define BTA_OP_VCARD_ORG 7 /* Organization. */
+#define BTA_OP_VCARD_TEL 8 /* Telephone number. */
+#define BTA_OP_VCARD_TITLE 9 /* Title. */
+#define BTA_OP_VCARD_URL 10 /* URL. */
+#define BTA_OP_VCARD_LUID 11 /* Locally Unique Identifier. */
+#define BTA_OP_VCARD_BDAY 12 /* Birthday. */
+#define BTA_OP_VCARD_PHOTO 13 /* Photo. */
+#define BTA_OP_VCARD_SOUND 14 /* Sound. */
+#define BTA_OP_VCARD_CALL 15 /* Call date-time */
+
+/* vCal Property Names */
+#define BTA_OP_VCAL_CATEGORIES 1 /* Categories of event. */
+#define BTA_OP_VCAL_COMPLETED 2 /* Time event is completed. */
+#define BTA_OP_VCAL_DESCRIPTION 3 /* Description of event. */
+#define BTA_OP_VCAL_DTEND 4 /* End date and time of event. */
+#define BTA_OP_VCAL_DTSTART 5 /* Start date and time of event. */
+#define BTA_OP_VCAL_DUE 6 /* Due date and time of event. */
+#define BTA_OP_VCAL_LOCATION 7 /* Location of event. */
+#define BTA_OP_VCAL_PRIORITY 8 /* Priority of event. */
+#define BTA_OP_VCAL_STATUS 9 /* Status of event. */
+#define BTA_OP_VCAL_SUMMARY 10 /* Summary of event. */
+#define BTA_OP_VCAL_LUID 11 /* Locally Unique Identifier. */
+
+/* vNote Property Names */
+#define BTA_OP_VNOTE_BODY 1 /* Message body text. */
+#define BTA_OP_VNOTE_LUID 2 /* Locally Unique Identifier. */
+
+/* Structure of the 32-bit parameters mask:
+**
+** + property-specific
+** +reserved | + character set
+** | | | + encoding
+** | | | |
+** 0000000000000000 00000000 00000 000
+*/
+
+/* Encoding Parameter */
+#define BTA_OP_ENC_QUOTED_PRINTABLE (1<<0) /* Quoted-Printable encoding. */
+#define BTA_OP_ENC_8BIT (2<<0) /* 8-bit encoding */
+#define BTA_OP_ENC_BINARY (3<<0) /* Binary encoding */
+// btla-specific ++
+#define BTA_OP_ENC_BASE64 (4<<0) /* base64 encoding */
+// btla-specific --
+
+/* Character Set Parameter */
+#define BTA_OP_CHAR_BIG5 (1<<3) /* Big5 character set. */
+#define BTA_OP_CHAR_EUC_JP (2<<3) /* EUC-JP character set. */
+#define BTA_OP_CHAR_EUC_KR (3<<3) /* EUC-KR character set. */
+#define BTA_OP_CHAR_GB2312 (4<<3) /* GB2312 character set. */
+#define BTA_OP_CHAR_ISO_2022_JP (5<<3) /* ISO-2022-JP character set. */
+#define BTA_OP_CHAR_ISO_8859_1 (6<<3) /* ISO-8859-1 character set. */
+#define BTA_OP_CHAR_ISO_8859_2 (7<<3) /* ISO-8859-2 character set. */
+#define BTA_OP_CHAR_ISO_8859_3 (8<<3) /* ISO-8859-3 character set. */
+#define BTA_OP_CHAR_ISO_8859_4 (9<<3) /* ISO-8859-4 character set. */
+#define BTA_OP_CHAR_ISO_8859_5 (10<<3) /* ISO-8859-5 character set. */
+#define BTA_OP_CHAR_ISO_8859_6 (11<<3) /* ISO-8859-6 character set. */
+#define BTA_OP_CHAR_ISO_8859_7 (12<<3) /* ISO-8859-7 character set. */
+#define BTA_OP_CHAR_ISO_8859_8 (13<<3) /* ISO-8859-8 character set. */
+#define BTA_OP_CHAR_KOI8_R (14<<3) /* KOI8-R character set. */
+#define BTA_OP_CHAR_SHIFT_JIS (15<<3) /* Shift_JIS character set. */
+#define BTA_OP_CHAR_UTF_8 (16<<3) /* UTF-8 character set. */
+
+/* Address Type Parameter */
+#define BTA_OP_ADR_DOM (1<<8) /* Domestic address. */
+#define BTA_OP_ADR_INTL (1<<9) /* International address. */
+#define BTA_OP_ADR_POSTAL (1<<10) /* Postal address. */
+#define BTA_OP_ADR_PARCEL (1<<11) /* Parcel post address. */
+#define BTA_OP_ADR_HOME (1<<12) /* Home address. */
+#define BTA_OP_ADR_WORK (1<<13) /* Work address. */
+
+/* EMAIL Type Parameter */
+#define BTA_OP_EMAIL_PREF (1<<8) /* Preferred email. */
+#define BTA_OP_EMAIL_INTERNET (1<<9) /* Internet email. */
+#define BTA_OP_EMAIL_X400 (1<<10) /* x400 emaill */
+
+/* Telephone Number Type Parameter */
+#define BTA_OP_TEL_PREF (1<<8) /* Preferred number. */
+#define BTA_OP_TEL_WORK (1<<9) /* Work number. */
+#define BTA_OP_TEL_HOME (1<<10) /* Home number. */
+#define BTA_OP_TEL_VOICE (1<<11) /* Voice number. */
+#define BTA_OP_TEL_FAX (1<<12) /* Fax number. */
+#define BTA_OP_TEL_MSG (1<<13) /* Message number. */
+#define BTA_OP_TEL_CELL (1<<14) /* Cell phone number. */
+#define BTA_OP_TEL_PAGER (1<<15) /* Pager number. */
+
+/* Photo Parameter */
+#define BTA_OP_PHOTO_VALUE_URI (1<<8) /* URI value */
+#define BTA_OP_PHOTO_VALUE_URL (1<<9) /* URL value */
+#define BTA_OP_PHOTO_TYPE_JPEG (1<<10) /* JPEG photo */
+#define BTA_OP_PHOTO_TYPE_GIF (1<<11) /* GIF photo */
+
+/* Sound Parameter */
+#define BTA_OP_SOUND_VALUE_URI (1<<8) /* URI value */
+#define BTA_OP_SOUND_VALUE_URL (1<<9) /* URL value */
+#define BTA_OP_SOUND_TYPE_BASIC (1<<10) /* BASIC sound */
+#define BTA_OP_SOUND_TYPE_WAVE (1<<11) /* WAVE sound */
+
+/* vCard filter mask */
+#define BTA_OP_FILTER_VERSION (1<<0) /* vCard Version */
+#define BTA_OP_FILTER_FN (1<<1) /* Formatted Name */
+#define BTA_OP_FILTER_N (1<<2) /* Structured Presentation of Name */
+#define BTA_OP_FILTER_PHOTO (1<<3) /* Associated Image or Photo */
+#define BTA_OP_FILTER_BDAY (1<<4) /* Birthday */
+#define BTA_OP_FILTER_ADR (1<<5) /* Delivery Address */
+#define BTA_OP_FILTER_LABEL (1<<6) /* Delivery */
+#define BTA_OP_FILTER_TEL (1<<7) /* Telephone Number */
+#define BTA_OP_FILTER_EMAIL (1<<8) /* Electronic Mail Address */
+#define BTA_OP_FILTER_MAILER (1<<9) /* Electronic Mail */
+#define BTA_OP_FILTER_TZ (1<<10) /* Time Zone */
+#define BTA_OP_FILTER_GEO (1<<11) /* Geographic Position */
+#define BTA_OP_FILTER_TITLE (1<<12) /* Job */
+#define BTA_OP_FILTER_ROLE (1<<13) /* Role within the Organization */
+#define BTA_OP_FILTER_LOGO (1<<14) /* Organization Logo */
+#define BTA_OP_FILTER_AGENT (1<<15) /* vCard of Person Representing */
+#define BTA_OP_FILTER_ORG (1<<16) /* Name of Organization */
+#define BTA_OP_FILTER_NOTE (1<<17) /* Comments */
+#define BTA_OP_FILTER_REV (1<<18) /* Revision */
+#define BTA_OP_FILTER_SOUND (1<<19) /* Pronunciation of Name */
+#define BTA_OP_FILTER_URL (1<<20) /* Uniform Resource Locator */
+#define BTA_OP_FILTER_UID (1<<21) /* Unique ID */
+#define BTA_OP_FILTER_KEY (1<<22) /* Public Encryption Key */
+#define BTA_OP_FILTER_NICKNAME (1<<23) /* Nickname */
+#define BTA_OP_FILTER_CATEGORIES (1<<24) /* Categories */
+#define BTA_OP_FILTER_PROID (1<<25) /* Product ID */
+#define BTA_OP_FILTER_CLASS (1<<26) /* Class Information */
+#define BTA_OP_FILTER_SORT_STRING (1<<27) /* String used for sorting operations */
+#define BTA_OP_FILTER_TIME_STAMP (1<<28) /* Time Stamp */
+#define BTA_OP_FILTER_ALL (0)
+
+/* This structure describes an object property, or individual item, inside an object. */
+typedef struct
+{
+ UINT8 *p_data; /* Pointer to property data. */
+ UINT32 parameters; /* Property parameters. */
+ UINT16 name; /* Property name. */
+ UINT16 len; /* Length of data. */
+ UINT8 *p_param; /* Pointer to the Parameters */
+ UINT16 param_len; /* Param Len */
+} tBTA_OP_PROP;
+
+
+/* Access response types */
+#define BTA_OP_ACCESS_ALLOW 0 /* Allow the requested operation */
+#define BTA_OP_ACCESS_FORBID 1 /* Disallow the requested operation */
+#define BTA_OP_ACCESS_NONSUP 2 /* Requested operation is not supported */
+
+typedef UINT8 tBTA_OP_ACCESS;
+
+/* Access event operation types */
+#define BTA_OP_OPER_PUSH 1
+#define BTA_OP_OPER_PULL 2
+
+typedef UINT8 tBTA_OP_OPER;
+
+
+/* Client callback function event */
+#define BTA_OPC_ENABLE_EVT 0 /* Object push client is enabled. */
+#define BTA_OPC_OPEN_EVT 1 /* Connection to peer is open. */
+#define BTA_OPC_PROGRESS_EVT 2 /* push/pull in progres */
+#define BTA_OPC_OBJECT_EVT 3 /* Object Pulled */
+#define BTA_OPC_OBJECT_PSHD_EVT 4 /* Object pushed */
+#define BTA_OPC_CLOSE_EVT 5 /* Connection to peer closed. */
+
+typedef UINT8 tBTA_OPC_EVT;
+
+/* Client callback function result */
+#define BTA_OPC_OK 0 /* Object push succeeded. */
+#define BTA_OPC_FAIL 1 /* Object push failed. */
+#define BTA_OPC_NOT_FOUND 2 /* Object not found. */
+#define BTA_OPC_NO_PERMISSION 3 /* Operation not authorized. */
+#define BTA_OPC_SRV_UNAVAIL 4 /* Service unavaliable */
+#define BTA_OPC_ON_BT 5 /* only used for BTA_OPC_MOVE_CH_EVT */
+#define BTA_OPC_RSP_FORBIDDEN 6 /* Operation forbidden */
+#define BTA_OPC_RSP_NOT_ACCEPTABLE 7 /* Operation not acceptable */
+
+typedef UINT8 tBTA_OPC_STATUS;
+
+/* Structure associated with BTA_OPC_OBJECT_EVT */
+typedef struct
+{
+ char *p_name; /* Object name. */
+ tBTA_OPC_STATUS status;
+} tBTA_OPC_OBJECT;
+
+typedef struct
+{
+ UINT32 obj_size; /* Total size of object (BTA_FS_LEN_UNKNOWN if unknown) */
+ UINT16 bytes; /* Number of bytes read or written since last progress event */
+ tBTA_OP_OPER operation; /* Is progress for Push or Pull */
+} tBTA_OPC_PROGRESS;
+
+/* Union of all client callback structures */
+typedef union
+{
+ tBTA_OPC_OBJECT object;
+ tBTA_OPC_PROGRESS prog;
+ tBTA_OPC_STATUS status;
+} tBTA_OPC;
+
+/* Client callback function */
+typedef void (tBTA_OPC_CBACK)(tBTA_OPC_EVT event, tBTA_OPC *p_data);
+
+/* Server callback function event */
+#define BTA_OPS_ENABLE_EVT 0 /* Object push server is enabled. */
+#define BTA_OPS_OPEN_EVT 1 /* Connection to peer is open. */
+#define BTA_OPS_PROGRESS_EVT 2 /* Object being sent or received. */
+#define BTA_OPS_OBJECT_EVT 3 /* Object has been received. */
+#define BTA_OPS_CLOSE_EVT 4 /* Connection to peer closed. */
+#define BTA_OPS_ACCESS_EVT 5 /* Request for access to push or pull object */
+
+typedef UINT8 tBTA_OPS_EVT;
+
+typedef UINT8 tBTA_OPS_STATUS;
+
+/* Structure associated with BTA_OPS_OBJECT_EVT */
+typedef struct
+{
+ char *p_name; /* Object name. */
+ tBTA_OP_FMT format; /* Object format. */
+} tBTA_OPS_OBJECT;
+
+typedef struct
+{
+ UINT32 obj_size; /* Total size of object (BTA_FS_LEN_UNKNOWN if unknown) */
+ UINT16 bytes; /* Number of bytes read or written since last progress event */
+ tBTA_OP_OPER operation; /* Is progress for Push or Pull */
+} tBTA_OPS_PROGRESS;
+
+typedef struct
+{
+ char *p_name; /* Object name */
+ char *p_type; /* Object type (NULL if not specified) */
+ UINT32 size; /* Object size */
+ tBTM_BD_NAME dev_name; /* Name of device, "" if unknown */
+ BD_ADDR bd_addr; /* Address of device */
+ tBTA_OP_OPER oper; /* Operation (push or pull) */
+ tBTA_OP_FMT format; /* Object format */
+} tBTA_OPS_ACCESS;
+
+/* Union of all server callback structures */
+typedef union
+{
+ tBTA_OPS_STATUS status;
+ tBTA_OPS_OBJECT object;
+ tBTA_OPS_PROGRESS prog;
+ tBTA_OPS_ACCESS access;
+ BD_ADDR bd_addr;
+} tBTA_OPS;
+
+/* Server callback function */
+typedef void (tBTA_OPS_CBACK)(tBTA_OPS_EVT event, tBTA_OPS *p_data);
+
+
+/*****************************************************************************
+** External Function Declarations
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*******************************************************************************
+**
+** Function BTA_OpcEnable
+**
+** Description Enable the object push client. This function must be
+** called before any other functions in the OP API are called.
+** When the enable operation is complete the callback function
+** will be called with a BTA_OPC_ENABLE_EVT.
+**
+** If single_op is FALSE, the connection stays open after
+** the operation finishes (until BTA_OpcClose is called).
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_OpcEnable(tBTA_SEC sec_mask, tBTA_OPC_CBACK *p_cback,
+ BOOLEAN single_op, BOOLEAN srm, UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function BTA_OpcDisable
+**
+** Description Disable the object push client. If the client is currently
+** connected to a peer device the connection will be closed.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_OpcDisable(void);
+
+/*******************************************************************************
+**
+** Function BTA_OpcPush
+**
+** Description Push an object to a peer device. p_name must point to
+** a fully qualified path and file name.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_OpcPush(BD_ADDR bd_addr, tBTA_OP_FMT format, char *p_name);
+
+/*******************************************************************************
+**
+** Function BTA_OpcPullCard
+**
+** Description Pull default card from peer. p_path must point to a fully
+** qualified path specifying where to store the pulled card.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_OpcPullCard(BD_ADDR bd_addr, char *p_path);
+
+
+/*******************************************************************************
+**
+** Function BTA_OpcExchCard
+**
+** Description Exchange business cards with a peer device. p_send points to
+** a fully qualified path and file name of vcard to push.
+** p_recv_path points to a fully qualified path specifying
+** where to store the pulled card.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_OpcExchCard(BD_ADDR bd_addr, char *p_send,
+ char *p_recv_path);
+
+
+/*******************************************************************************
+**
+** Function BTA_OpcClose
+**
+** Description Close the current connection. This function is called if
+** the phone wishes to close the connection before the object
+** push is completed. In a typical connection this function
+** does not need to be called; the connection will be closed
+** automatically when the object push is complete.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_OpcClose(void);
+
+/*******************************************************************************
+**
+** Function BTA_OpsEnable
+**
+** Description Enable the object push server. This function must be
+** called before any other functions in the OPS API are called.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_OpsEnable(tBTA_SEC sec_mask, tBTA_OP_FMT_MASK formats,
+ char *p_service_name, tBTA_OPS_CBACK *p_cback,
+ BOOLEAN srm, UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function BTA_OpsDisable
+**
+** Description Disable the object push server. If the server is currently
+** connected to a peer device the connection will be closed.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_OpsDisable(void);
+
+/*******************************************************************************
+**
+** Function BTA_OpsClose
+**
+** Description Close the current connection. This function is called if
+** the phone wishes to close the connection before the object
+** push is completed.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_OpsClose(void);
+
+/*******************************************************************************
+**
+** Function BTA_OpsAccessRsp
+**
+** Description Sends a reply to an access request event (BTA_OPS_ACCESS_EVT).
+** This call MUST be made whenever the event occurs.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_OpsAccessRsp(tBTA_OP_OPER oper, tBTA_OP_ACCESS access,
+ char *p_name);
+
+/*******************************************************************************
+**
+** Function BTA_OpBuildCard
+**
+** Description Build a vCard object. The input to this function is
+** requested format(2.1/3.0), an array of vCard properties
+** and a pointer to memory to store the card.
+** The output is a formatted vCard.
+**
+**
+** Returns BTA_OP_OK if operation successful.
+** BTA_OP_FAIL if invalid property data.
+** BTA_OP_MEM if not enough memory to complete build.
+**
+*******************************************************************************/
+BTA_API extern tBTA_OP_STATUS BTA_OpBuildCard(UINT8 *p_card, UINT16 *p_len,
+ tBTA_OP_FMT fmt,
+ tBTA_OP_PROP *p_prop,
+ UINT8 num_prop);
+
+/*******************************************************************************
+**
+** Function BTA_OpBuildNote
+**
+** Description Build a vNote object. The input to this function is an
+** array of vNote properties and a pointer to memory to store
+** the card. The output is a formatted vNote.
+**
+**
+** Returns BTA_OP_OK if operation successful.
+** BTA_OP_FAIL if invalid property data.
+** BTA_OP_MEM if not enough memory to complete build.
+**
+*******************************************************************************/
+BTA_API extern tBTA_OP_STATUS BTA_OpBuildNote(UINT8 *p_note, UINT16 *p_len,
+ tBTA_OP_PROP *p_prop,
+ UINT8 num_prop);
+
+/*******************************************************************************
+**
+** Function BTA_OpBuildCal
+**
+** Description Build a vCal 1.0 object. The input to this function is an
+** array of vCaalproperties and a pointer to memory to store
+** the card. The output is a formatted vCal.
+**
+**
+** Returns BTA_OP_OK if operation successful.
+** BTA_OP_FAIL if invalid property data.
+** BTA_OP_MEM if not enough memory to complete build.
+**
+*******************************************************************************/
+BTA_API extern tBTA_OP_STATUS BTA_OpBuildCal(UINT8 *p_cal, UINT16 *p_len,
+ tBTA_OP_PROP *p_prop,
+ UINT8 num_prop,
+ tBTA_OP_VCAL vcal_type);
+
+/*******************************************************************************
+**
+** Function BTA_OpParseCard
+**
+** Description Parse a vCard 2.1 object. The input to this function is
+** a pointer to vCard data. The output is an array of parsed
+** vCard properties.
+**
+**
+** Returns BTA_OP_OK if operation successful.
+** BTA_OP_FAIL if invalid property data.
+** BTA_OP_MEM if not enough memory to complete parsing.
+**
+*******************************************************************************/
+BTA_API extern tBTA_OP_STATUS BTA_OpParseCard(tBTA_OP_PROP *p_prop,
+ UINT8 *p_num_prop, UINT8 *p_card,
+ UINT16 len);
+
+/*******************************************************************************
+**
+** Function BTA_OpGetCardProperty
+**
+** Description Get Card property value by name. The input to this function is
+** property name. The output is property value and len
+**
+**
+** Returns BTA_OP_OK if operation successful.
+** BTA_OP_FAIL if invalid property data.
+**
+*******************************************************************************/
+BTA_API extern tBTA_OP_STATUS BTA_OpGetCardProperty(UINT8 *p_value, UINT16 *p_len, tBTA_OP_PROP *p_prop,
+ UINT8 num_prop, UINT8 *p_name);
+
+/*******************************************************************************
+**
+** Function BTA_OpParseNote
+**
+** Description Parse a vNote object. The input to this function is a
+** pointer to vNote data. The output is an array of parsed
+** vNote properties.
+**
+**
+** Returns BTA_OP_OK if operation successful.
+** BTA_OP_FAIL if invalid property data.
+** BTA_OP_MEM if not enough memory to complete parsing.
+**
+*******************************************************************************/
+BTA_API extern tBTA_OP_STATUS BTA_OpParseNote(tBTA_OP_PROP *p_prop,
+ UINT8 *p_num_prop,
+ UINT8 *p_note, UINT16 len);
+
+/*******************************************************************************
+**
+** Function BTA_OpParseCal
+**
+** Description Parse a vCal object. The input to this function is a
+** pointer to vCal data. The output is an array of parsed
+** vCal properties.
+**
+**
+** Returns BTA_OP_OK if operation successful.
+** BTA_OP_FAIL if invalid property data.
+** BTA_OP_MEM if not enough memory to complete parsing.
+**
+*******************************************************************************/
+BTA_API extern tBTA_OP_STATUS BTA_OpParseCal(tBTA_OP_PROP *p_prop,
+ UINT8 *p_num_prop, UINT8 *p_cal,
+ UINT16 len, tBTA_OP_VCAL *p_vcal_type);
+
+/*******************************************************************************
+**
+** Function BTA_OpSetCardPropFilterMask
+**
+** Description Set Property Filter Mask
+**
+**
+** Returns
+**
+*******************************************************************************/
+BTA_API extern void BTA_OpSetCardPropFilterMask(UINT32 mask);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_OP_API_H */
+
diff --git a/bta/include/bta_pan_api.h b/bta/include/bta_pan_api.h
new file mode 100644
index 0000000..83fa40d
--- /dev/null
+++ b/bta/include/bta_pan_api.h
@@ -0,0 +1,187 @@
+/*****************************************************************************
+**
+** Name: bta_pan_api.h
+**
+** Description: This is the public interface file for the Personal
+** Area Networking (PAN) subsystem of BTA, Widcomm's
+** Bluetooth application layer for mobile phones.
+**
+** Copyright (c) 2004, Widcomm Inc., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_PAN_API_H
+#define BTA_PAN_API_H
+
+#include "bta_api.h"
+#include "pan_api.h"
+
+/*****************************************************************************
+** Constants and data types
+*****************************************************************************/
+#define BTA_PAN_SUCCESS 0
+#define BTA_PAN_FAIL 1
+
+typedef UINT8 tBTA_PAN_STATUS;
+
+
+/* PAN Callback events */
+#define BTA_PAN_ENABLE_EVT 0 /* PAN service is enabled. */
+#define BTA_PAN_SET_ROLE_EVT 1 /* PAN roles registered */
+#define BTA_PAN_OPENING_EVT 2 /* Connection is being opened. */
+#define BTA_PAN_OPEN_EVT 3 /* Connection has been opened. */
+#define BTA_PAN_CLOSE_EVT 4 /* Connection has been closed. */
+
+typedef UINT8 tBTA_PAN_EVT;
+
+
+/* pan roles */
+#define BTA_PAN_ROLE_PANU PAN_ROLE_CLIENT
+#define BTA_PAN_ROLE_GN PAN_ROLE_GN_SERVER
+#define BTA_PAN_ROLE_NAP PAN_ROLE_NAP_SERVER
+
+
+typedef UINT8 tBTA_PAN_ROLE;
+
+/* information regarding PAN roles */
+typedef struct
+{
+ char *p_srv_name; /* service name for the PAN role */
+ UINT8 app_id; /* application id */
+ tBTA_SEC sec_mask; /* security setting for the role */
+
+} tBTA_PAN_ROLE_INFO;
+
+
+/* Event associated with BTA_PAN_SET_ROLE_EVT */
+typedef struct
+{
+ tBTA_PAN_ROLE role; /* PAN roles successfully registered */
+} tBTA_PAN_SET_ROLE;
+
+/* Event associated with BTA_PAN_OPENING_EVT */
+typedef struct
+{
+ BD_ADDR bd_addr; /* BD address of peer device. */
+ UINT16 handle; /* Handle associated with this connection. */
+
+} tBTA_PAN_OPENING;
+
+
+/* Event associated with BTA_PAN_OPEN_EVT */
+typedef struct
+{
+ BD_ADDR bd_addr; /* BD address of peer device. */
+ UINT16 handle; /* Handle associated with this connection. */
+ tBTA_PAN_STATUS status; /* status of open event */
+ tBTA_PAN_ROLE local_role; /* Local device PAN role for the connection */
+ tBTA_PAN_ROLE peer_role; /* Peer device PAN role for the connection */
+
+} tBTA_PAN_OPEN;
+
+/* Event associated with BTA_PAN_CLOSE_EVT */
+typedef struct
+{
+ UINT16 handle; /* Handle associated with the connection. */
+} tBTA_PAN_CLOSE;
+
+/* Union of all PAN callback structures */
+typedef union
+{
+ tBTA_PAN_SET_ROLE set_role; /* set_role event */
+ tBTA_PAN_OPEN open; /* Connection has been opened. */
+ tBTA_PAN_OPENING opening; /* Connection being opened */
+ tBTA_PAN_CLOSE close; /* Connection has been closed. */
+} tBTA_PAN;
+
+/* Number of PAN connections */
+#ifndef BTA_PAN_NUM_CONN
+#define BTA_PAN_NUM_CONN 4
+#endif
+
+/* PAN callback */
+typedef void (tBTA_PAN_CBACK)(tBTA_PAN_EVT event, tBTA_PAN *p_data);
+
+/*****************************************************************************
+** External Function Declarations
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*******************************************************************************
+**
+** Function BTA_PanEnable
+**
+** Description Enable PAN service. This function must be
+** called before any other functions in the PAN API are called.
+** When the enable operation is complete the callback function
+** will be called with a BTA_PAN_ENABLE_EVT.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_PanEnable(tBTA_PAN_CBACK p_cback);
+
+/*******************************************************************************
+**
+** Function BTA_PanDisable
+**
+** Description Disable PAN service.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_PanDisable(void);
+
+
+/*******************************************************************************
+**
+** Function BTA_PanSetRole
+**
+** Description Sets PAN roles. When the enable operation is complete
+** the callback function will be called with a BTA_PAN_SET_ROLE_EVT.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API void BTA_PanSetRole(tBTA_PAN_ROLE role, tBTA_PAN_ROLE_INFO *p_user_info, tBTA_PAN_ROLE_INFO *p_gn_info,
+ tBTA_PAN_ROLE_INFO *p_nap_info);
+
+
+/*******************************************************************************
+**
+** Function BTA_PanOpen
+**
+** Description Opens a connection to a peer device.
+** When connection is open callback function is called
+** with a BTA_PAN_OPEN_EVT.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API void BTA_PanOpen(BD_ADDR bd_addr, tBTA_PAN_ROLE local_role, tBTA_PAN_ROLE peer_role);
+
+
+
+/*******************************************************************************
+**
+** Function BTA_PanClose
+**
+** Description Close a PAN connection to a peer device.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_PanClose(UINT16 handle);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_PAN_API_H */
+
diff --git a/bta/include/bta_pan_ci.h b/bta/include/bta_pan_ci.h
new file mode 100644
index 0000000..cd759d9
--- /dev/null
+++ b/bta/include/bta_pan_ci.h
@@ -0,0 +1,139 @@
+/*****************************************************************************
+**
+** Name: bta_pan_ci.h
+**
+** Description: This is the interface file for pan call-in
+** functions.
+**
+** Copyright (c) 2004, Widcomm Inc., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_PAN_CI_H
+#define BTA_PAN_CI_H
+
+#include "bta_pan_api.h"
+
+/*****************************************************************************
+** Function Declarations
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*******************************************************************************
+**
+** Function bta_pan_ci_tx_ready
+**
+** Description This function sends an event to PAN indicating the phone is
+** ready for more data and PAN should call bta_pan_co_tx_path().
+** This function is used when the TX data path is configured
+** to use a pull interface.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_pan_ci_tx_ready(UINT16 handle);
+
+/*******************************************************************************
+**
+** Function bta_pan_ci_rx_ready
+**
+** Description This function sends an event to PAN indicating the phone
+** has data available to send to PAN and PAN should call
+** bta_pan_co_rx_path(). This function is used when the RX
+** data path is configured to use a pull interface.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_pan_ci_rx_ready(UINT16 handle);
+
+/*******************************************************************************
+**
+** Function bta_pan_ci_tx_flow
+**
+** Description This function is called to enable or disable data flow on
+** the TX path. The phone should call this function to
+** disable data flow when it is congested and cannot handle
+** any more data sent by bta_pan_co_tx_write() or
+** bta_pan_co_tx_writebuf(). This function is used when the
+** TX data path is configured to use a push interface.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_pan_ci_tx_flow(UINT16 handle, BOOLEAN enable);
+
+/*******************************************************************************
+**
+** Function bta_pan_ci_rx_writebuf
+**
+** Description This function is called to send data to the phone when
+** the RX path is configured to use a push interface with
+** zero copy. The function sends an event to PAN containing
+** the data buffer. The buffer must be allocated using
+** functions GKI_getbuf() or GKI_getpoolbuf(). The buffer
+** will be freed by BTA; the phone must not free the buffer.
+**
+**
+** Returns TRUE if flow enabled
+**
+*******************************************************************************/
+BTA_API extern void bta_pan_ci_rx_writebuf(UINT16 handle, BD_ADDR src, BD_ADDR dst, UINT16 protocol, BT_HDR *p_buf, BOOLEAN ext);
+
+/*******************************************************************************
+**
+** Function bta_pan_ci_readbuf
+**
+** Description This function is called by the phone to read data from PAN
+** when the TX path is configured to use a pull interface.
+** The phone must free the buffer using function GKI_freebuf() when
+** it is through processing the buffer.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern BT_HDR * bta_pan_ci_readbuf(UINT16 handle, BD_ADDR src, BD_ADDR dst, UINT16 *p_protocol,
+ BOOLEAN* p_ext, BOOLEAN* p_forward);
+
+/*******************************************************************************
+**
+** Function bta_pan_ci_set_pfilters
+**
+** Description This function is called to set protocol filters
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_pan_ci_set_pfilters(UINT16 handle, UINT16 num_filters, UINT16 *p_start_array, UINT16 *p_end_array);
+
+
+/*******************************************************************************
+**
+** Function bta_pan_ci_set_mfilters
+**
+** Description This function is called to set multicast filters
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_pan_ci_set_mfilters(UINT16 handle, UINT16 num_mcast_filters, UINT8 *p_start_array,
+ UINT8 *p_end_array);
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_PAN_CI_H */
+
diff --git a/bta/include/bta_pan_co.h b/bta/include/bta_pan_co.h
new file mode 100644
index 0000000..c8769f4
--- /dev/null
+++ b/bta/include/bta_pan_co.h
@@ -0,0 +1,189 @@
+/*****************************************************************************
+**
+** Name: bta_pan_co.h
+**
+** Description: This is the interface file for data gateway call-out
+** functions.
+**
+** Copyright (c) 2004, Widcomm Inc., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_PAN_CO_H
+#define BTA_PAN_CO_H
+
+#include "bta_pan_api.h"
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+
+
+/* BT_HDR buffer offset */
+#define BTA_PAN_MIN_OFFSET PAN_MINIMUM_OFFSET
+
+
+/* Data Flow Mask */
+#define BTA_PAN_RX_PUSH 0x00 /* RX push. */
+#define BTA_PAN_RX_PUSH_BUF 0x01 /* RX push with zero copy. */
+#define BTA_PAN_RX_PULL 0x02 /* RX pull. */
+#define BTA_PAN_TX_PUSH 0x00 /* TX push. */
+#define BTA_PAN_TX_PUSH_BUF 0x10 /* TX push with zero copy. */
+#define BTA_PAN_TX_PULL 0x20 /* TX pull. */
+
+
+
+/*****************************************************************************
+** Function Declarations
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function bta_pan_co_init
+**
+** Description This callout function is executed by PAN when a server is
+** started by calling BTA_PanEnable(). This function can be
+** used by the phone to initialize data paths or for other
+** initialization purposes. The function must return the
+** data flow mask as described below.
+**
+**
+** Returns Data flow mask.
+**
+*******************************************************************************/
+BTA_API extern UINT8 bta_pan_co_init(UINT8 *q_level);
+
+/*******************************************************************************
+**
+** Function bta_pan_co_open
+**
+** Description This function is executed by PAN when a connection
+** is opened. The phone can use this function to set
+** up data paths or perform any required initialization.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_pan_co_open(UINT16 handle, UINT8 app_id, tBTA_PAN_ROLE local_role, tBTA_PAN_ROLE peer_role, BD_ADDR peer_addr);
+
+/*******************************************************************************
+**
+** Function bta_pan_co_close
+**
+** Description This function is called by PAN when a connection to a
+** server is closed.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_pan_co_close(UINT16 handle, UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function bta_pan_co_tx_path
+**
+** Description This function is called by PAN to transfer data on the
+** TX path; that is, data being sent from BTA to the phone.
+** This function is used when the TX data path is configured
+** to use the pull interface.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_pan_co_tx_path(UINT16 handle, UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function bta_pan_co_rx_path
+**
+** Description This function is called by PAN to transfer data on the
+** RX path; that is, data being sent from the phone to BTA.
+** This function is used when the RX data path is configured
+** to use the pull interface.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_pan_co_rx_path(UINT16 handle, UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function bta_pan_co_tx_write
+**
+** Description This function is called by PAN to send data to the phone
+** when the TX path is configured to use a push interface.
+** The implementation of this function must copy the data to
+** the phone's memory.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_pan_co_tx_write(UINT16 handle, UINT8 app_id, BD_ADDR src, BD_ADDR dst, UINT16 protocol, UINT8 *p_data,
+ UINT16 len, BOOLEAN ext, BOOLEAN forward);
+
+/*******************************************************************************
+**
+** Function bta_pan_co_tx_writebuf
+**
+** Description This function is called by PAN to send data to the phone
+** when the TX path is configured to use a push interface with
+** zero copy. The phone must free the buffer using function
+** GKI_freebuf() when it is through processing the buffer.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_pan_co_tx_writebuf(UINT16 handle, UINT8 app_id, BD_ADDR src, BD_ADDR dst, UINT16 protocol, BT_HDR *p_buf,
+ BOOLEAN ext, BOOLEAN forward);
+
+
+/*******************************************************************************
+**
+** Function bta_pan_co_rx_flow
+**
+** Description This function is called by PAN to enable or disable
+** data flow on the RX path when it is configured to use
+** a push interface. If data flow is disabled the phone must
+** not call bta_pan_ci_rx_write() or bta_pan_ci_rx_writebuf()
+** until data flow is enabled again.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_pan_co_rx_flow(UINT16 handle, UINT8 app_id, BOOLEAN enable);
+
+
+/*******************************************************************************
+**
+** Function bta_pan_co_filt_ind
+**
+** Description protocol filter indication from peer device
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_pan_co_pfilt_ind(UINT16 handle, BOOLEAN indication, tBTA_PAN_STATUS result,
+ UINT16 len, UINT8 *p_filters);
+
+/*******************************************************************************
+**
+** Function bta_pan_co_mfilt_ind
+**
+** Description multicast filter indication from peer device
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_pan_co_mfilt_ind(UINT16 handle, BOOLEAN indication, tBTA_PAN_STATUS result,
+ UINT16 len, UINT8 *p_filters);
+
+#endif /* BTA_PAN_CO_H */
+
diff --git a/bta/include/bta_pbs_api.h b/bta/include/bta_pbs_api.h
new file mode 100644
index 0000000..41198ff
--- /dev/null
+++ b/bta/include/bta_pbs_api.h
@@ -0,0 +1,298 @@
+/*****************************************************************************
+**
+** Name: bta_pbs_api.h
+**
+** Description: This is the public interface file for the phone book access
+** (PB) server subsystem of BTA, Widcomm's
+** Bluetooth application layer for mobile phones.
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_PB_API_H
+#define BTA_PB_API_H
+
+#include "bta_api.h"
+#include "btm_api.h"
+#include "bta_sys.h"
+
+/*****************************************************************************
+** Constants and data types
+*****************************************************************************/
+
+/**************************
+** Common Definitions
+***************************/
+
+/* Profile supported features */
+#define BTA_PBS_SUPF_DOWNLOAD 0x0001
+#define BTA_PBS_SURF_BROWSE 0x0002
+
+/* Profile supported repositories */
+#define BTA_PBS_REPOSIT_LOCAL 0x01 /* Local PhoneBook */
+#define BTA_PBS_REPOSIT_SIM 0x02 /* SIM card PhoneBook */
+
+enum
+{
+ BTA_PBS_VCF_FMT_21 = 0, /* vcard format 2.1 */
+ BTA_PBS_VCF_FMT_30 /* vcard format 3.0 */
+};
+typedef UINT8 tBTA_PBS_VCF_FMT;
+
+enum
+{
+ BTA_PBS_ORDER_INDEX = 0, /* Default. vCard handle */
+ BTA_PBS_ORDER_ALPHA_NUM, /* UTF8 name attribute, LastName then FirstName then MiddleName */
+ BTA_PBS_ORDER_PHONETIC /* UTF8 representation of the sound attribute */
+};
+typedef UINT8 tBTA_PBS_ORDER;
+
+enum
+{
+ BTA_PBS_ATTR_NAME = 0, /* name */
+ BTA_PBS_ATTR_NUMBER, /* number */
+ BTA_PBS_ATTR_SOUND, /* sound */
+ BTA_PBS_ATTR_MAX
+};
+typedef UINT8 tBTA_PBS_ATTR;
+
+#define BTA_PBS_FILTER_VERSION (1<<0) /* vCard Version */
+#define BTA_PBS_FILTER_FN (1<<1) /* Formatted Name */
+#define BTA_PBS_FILTER_N (1<<2) /* Structured Presentation of Name */
+#define BTA_PBS_FILTER_PHOTO (1<<3) /* Associated Image or Photo */
+#define BTA_PBS_FILTER_BDAY (1<<4) /* Birthday */
+#define BTA_PBS_FILTER_ADR (1<<5) /* Delivery Address */
+#define BTA_PBS_FILTER_LABEL (1<<6) /* Delivery */
+#define BTA_PBS_FILTER_TEL (1<<7) /* Telephone Number */
+#define BTA_PBS_FILTER_EMAIL (1<<8) /* Electronic Mail Address */
+#define BTA_PBS_FILTER_MAILER (1<<9) /* Electronic Mail */
+#define BTA_PBS_FILTER_TZ (1<<10) /* Time Zone */
+#define BTA_PBS_FILTER_GEO (1<<11) /* Geographic Position */
+#define BTA_PBS_FILTER_TITLE (1<<12) /* Job */
+#define BTA_PBS_FILTER_ROLE (1<<13) /* Role within the Organization */
+#define BTA_PBS_FILTER_LOGO (1<<14) /* Organization Logo */
+#define BTA_PBS_FILTER_AGENT (1<<15) /* vCard of Person Representing */
+#define BTA_PBS_FILTER_ORG (1<<16) /* Name of Organization */
+#define BTA_PBS_FILTER_NOTE (1<<17) /* Comments */
+#define BTA_PBS_FILTER_REV (1<<18) /* Revision */
+#define BTA_PBS_FILTER_SOUND (1<<19) /* Pronunciation of Name */
+#define BTA_PBS_FILTER_URL (1<<20) /* Uniform Resource Locator */
+#define BTA_PBS_FILTER_UID (1<<21) /* Unique ID */
+#define BTA_PBS_FILTER_KEY (1<<22) /* Public Encryption Key */
+#define BTA_PBS_FILTER_NICKNAME (1<<23) /* Nickname */
+#define BTA_PBS_FILTER_CATEGORIES (1<<24) /* Categories */
+#define BTA_PBS_FILTER_PROID (1<<25) /* Product ID */
+#define BTA_PBS_FILTER_CLASS (1<<26) /* Class Information */
+#define BTA_PBS_FILTER_SORT_STRING (1<<27) /* String used for sorting operations */
+#define BTA_PBS_FILTER_TIME_STAMP (1<<28) /* Time Stamp */
+#define BTA_PBS_FILTER_PROPRIETARY (1<<39) /* Indicates the usage of a proprietary filter */
+#define BTA_PBS_FILTER_ALL (0)
+
+typedef UINT32 tBTA_PBS_FILTER_MASK;
+
+/* Access response types */
+enum
+{
+ BTA_PBS_ACCESS_TYPE_ALLOW = 0, /* Allow the requested operation */
+ BTA_PBS_ACCESS_TYPE_FORBID, /* Disallow the requested operation */
+ BTA_PBS_ACCESS_TYPE_PRECONDITION /* Get vCard Entry operation only (object handle invalid) */
+};
+
+typedef UINT8 tBTA_PBS_ACCESS_TYPE;
+
+#define BTA_PBS_MAX_FILE_LEN 64
+#define BTA_PBS_MAX_CONTACT_NAME_LEN 128
+
+/* Obex application params passed to open callout */
+typedef struct
+{
+ tBTA_PBS_FILTER_MASK filter;
+ tBTA_PBS_VCF_FMT format;
+ UINT16 max_count;
+ UINT16 start_offset;
+} tBTA_PBS_PULLPB_APP_PARAMS;
+
+/* Obex application params passed to getvlist callout */
+typedef struct
+{
+ tBTA_PBS_ORDER order;
+ tBTA_PBS_ATTR attribute;
+ UINT8 p_value[64];
+ UINT16 value_len;
+ UINT16 max_count;
+ UINT16 start_offset;
+} tBTA_PBS_VCARDLIST_APP_PARAMS;
+
+/* VCard Listing structuture Returned by application*/
+typedef struct
+{
+ char handle[BTA_PBS_MAX_FILE_LEN]; /* Contains the vcf name */
+ char name[BTA_PBS_MAX_CONTACT_NAME_LEN]; /* Contains the contacted name of the vlist */
+} tBTA_PBS_VCARDLIST;
+
+/* Access event operation types */
+#define BTA_PBS_OPER_NONE 0
+#define BTA_PBS_OPER_PULL_PB 1
+#define BTA_PBS_OPER_SET_PB 2
+#define BTA_PBS_OPER_PULL_VCARD_LIST 3
+#define BTA_PBS_OPER_PULL_VCARD_ENTRY 4
+
+typedef UINT8 tBTA_PBS_OPER;
+
+/* Object type */
+#define BTA_PBS_NONE_OBJ 0
+#define BTA_PBS_PB_OBJ 1
+#define BTA_PBS_ICH_OBJ 2
+#define BTA_PBS_OCH_OBJ 3
+#define BTA_PBS_MCH_OBJ 4
+#define BTA_PBS_CCH_OBJ 5
+
+typedef UINT8 tBTA_PBS_OBJ_TYPE;
+
+
+/**************************
+** Server Definitions
+***************************/
+/* Extra Debug Code */
+#ifndef BTA_PBS_DEBUG
+#define BTA_PBS_DEBUG FALSE
+#endif
+
+#define BTA_PBS_OK 0
+#define BTA_PBS_FAIL 1
+typedef UINT8 tBTA_PBS_STATUS;
+
+/* Server callback function events */
+#define BTA_PBS_ENABLE_EVT 0 /* PB transfer server is enabled. */
+#define BTA_PBS_OPEN_EVT 1 /* Connection to peer is open. */
+#define BTA_PBS_CLOSE_EVT 2 /* Connection to peer closed. */
+#define BTA_PBS_AUTH_EVT 3 /* Request for Authentication key and realm */
+#define BTA_PBS_ACCESS_EVT 4 /* Request for access to put a file */
+#define BTA_PBS_OPER_CMPL_EVT 5 /* PB operation complete */
+
+typedef UINT8 tBTA_PBS_EVT;
+
+/* Structure associated with BTA_PBS_OPER_CMPL_EVT */
+typedef struct
+{
+ char *p_name; /* file or folder name. */
+ tBTA_PBS_OPER operation;
+ tBTA_PBS_STATUS status;
+} tBTA_PBS_OBJECT;
+
+typedef struct
+{
+ UINT8 *p_userid;
+ UINT8 userid_len;
+ BOOLEAN userid_required; /* TRUE if user ID is required in response (rechallanged) */
+} tBTA_PBS_AUTH;
+
+typedef struct
+{
+ char *p_name; /* file or directory name with fully qualified path */
+ tBTM_BD_NAME dev_name; /* Name of device, "" if unknown */
+ tBTA_PBS_OPER oper; /* operation */
+ BD_ADDR bd_addr; /* Address of device */
+} tBTA_PBS_ACCESS;
+
+typedef struct
+{
+ tBTM_BD_NAME dev_name; /* Name of device, "" if unknown */
+ BD_ADDR bd_addr; /* Address of device */
+} tBTA_PBS_OPEN;
+
+typedef union
+{
+ tBTA_PBS_AUTH auth;
+ tBTA_PBS_ACCESS access;
+ tBTA_PBS_OBJECT obj;
+ tBTA_PBS_OPEN open;
+} tBTA_PBS;
+
+/* Server callback function */
+typedef void tBTA_PBS_CBACK(tBTA_PBS_EVT event, tBTA_PBS *p_data);
+
+/**************************
+** Server Functions
+***************************/
+
+/*******************************************************************************
+**
+** Function BTA_PbsEnable
+**
+** Description Enable the phone book access server. This function must be
+** called before any other functions in the PB Server API are called.
+** When the enable operation is complete the callback function
+** will be called with an BTA_PBS_ENABLE_EVT event.
+** Note: Pbs always enable (BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT)
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_PbsEnable(tBTA_SEC sec_mask, const char *p_service_name,
+ const char *p_root_path, BOOLEAN enable_authen,
+ UINT8 realm_len, UINT8 *p_realm,
+ tBTA_PBS_CBACK *p_cback, UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function BTA_PbsDisable
+**
+** Description Disable the Phone book access server. If the server is currently
+** connected to a peer device the connection will be closed.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_PbsDisable(void);
+
+/*******************************************************************************
+**
+** Function BTA_PbsAuthRsp
+**
+** Description Respond to obex client authenticate repond by sending back password to
+** BTA. Called in response to an BTA_PBS_AUTH_EVT event.
+** Used when "enable_authen" is set to TRUE in BTA_PbapsEnable().
+**
+** Note: If the "userid_required" is TRUE in the BTA_PBS_AUTH_EVT
+** event, then p_userid is required, otherwise it is optional.
+**
+** p_password must be less than BTA_PBS_MAX_AUTH_KEY_SIZE (16 bytes)
+** p_userid must be less than OBX_MAX_REALM_LEN (defined in target.h)
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_PbsAuthRsp (char *p_password, char *p_userid);
+
+/*******************************************************************************
+**
+** Function BTA_PbsAccessRsp
+**
+** Description Sends a reply to an access request event (BTA_PBS_ACCESS_EVT).
+** This call MUST be made whenever the event occurs.
+**
+** Parameters oper - operation being accessed.
+** access - BTA_PBS_ACCESS_ALLOW or BTA_PBS_ACCESS_FORBID
+** p_name - path of file or directory to be accessed.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_PbsAccessRsp(tBTA_PBS_OPER oper, tBTA_PBS_ACCESS_TYPE access,
+ char *p_name);
+
+/*******************************************************************************
+**
+** Function BTA_PbsClose
+**
+** Description Close the current connection.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_PbsClose(void);
+#endif
diff --git a/bta/include/bta_pbs_ci.h b/bta/include/bta_pbs_ci.h
new file mode 100644
index 0000000..e44f960
--- /dev/null
+++ b/bta/include/bta_pbs_ci.h
@@ -0,0 +1,93 @@
+/*****************************************************************************
+**
+** Name: bta_pbs_ci.h
+**
+** Description: This is the interface file for phone book access server
+** call-in functions.
+**
+** Copyright (c) 2003, Widcomm Inc., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_PBS_CI_H
+#define BTA_PBS_CI_H
+
+#include "bta_pbs_co.h"
+
+/*****************************************************************************
+** Constants and data types
+*****************************************************************************/
+
+
+/*****************************************************************************
+** Function Declarations
+*****************************************************************************/
+
+
+/*******************************************************************************
+**
+** Function bta_pbs_ci_read
+**
+** Description This function sends an event to BTA indicating the phone has
+** read in the requested amount of data specified in the
+** bta_pbs_co_read() call-out function.
+**
+** Parameters fd - file descriptor passed to the stack in the
+** bta_pbs_ci_open call-in function.
+** num_bytes_read - number of bytes read into the buffer
+** specified in the read callout-function.
+** status - BTA_PBS_CO_OK if get buffer of data,
+** BTA_PBS_CO_FAIL if an error has occurred.
+** final - indicate whether it is the final data
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_pbs_ci_read(int fd, UINT16 num_bytes_read,
+ tBTA_PBS_CO_STATUS status, BOOLEAN final);
+
+/*******************************************************************************
+**
+** Function bta_pbs_ci_open
+**
+** Description This function sends an event to BTA indicating the phone has
+** finished opening a pb for reading.
+**
+** Parameters fd - file descriptor passed to the stack in the
+** bta_pbs_ci_open call-in function.
+** status - BTA_PBS_CO_OK if file was opened in mode specified
+** in the call-out function.
+** BTA_PBS_CO_EACCES if the file exists, but contains
+** the wrong access permissions.
+** BTA_PBS_CO_FAIL if any other error has occurred.
+** file_size - The total size of the file
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_pbs_ci_open(int fd, tBTA_PBS_CO_STATUS status,
+ UINT32 file_size);
+
+/*******************************************************************************
+**
+** Function bta_pbs_ci_getvlist
+**
+** Description This function sends an event to BTA indicating the phone has
+** finished reading a VCard list entry.
+**
+** Parameters
+** status - BTA_PBS_CO_OK if reading Vcard list entry
+** BTA_PBS_CO_FAIL if any other error has occurred.
+** final - whether it is the last entry
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_pbs_ci_getvlist(tBTA_PBS_CO_STATUS status, BOOLEAN final);
+
+
+#endif
+
diff --git a/bta/include/bta_pbs_co.h b/bta/include/bta_pbs_co.h
new file mode 100644
index 0000000..76ec75a
--- /dev/null
+++ b/bta/include/bta_pbs_co.h
@@ -0,0 +1,160 @@
+/*****************************************************************************
+**
+** Name: bta_pbs_co.h
+**
+** Description: This is the interface file for the phone book access server
+** call-out functions.
+**
+** Copyright (c) 2003-2004, Widcomm Inc., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_PBS_CO_H
+#define BTA_PBS_CO_H
+
+#include "bta_api.h"
+#include "goep_fs.h"
+#include "bta_pbs_api.h"
+
+
+/*****************************************************************************
+** Constants and Data Types
+*****************************************************************************/
+/**************************
+** Common Definitions
+***************************/
+
+/* Status codes returned by call-out functions, or in call-in functions as status */
+#define BTA_PBS_CO_OK GOEP_OK
+#define BTA_PBS_CO_FAIL GOEP_FAIL /* Used to pass all other errors */
+#define BTA_PBS_CO_EACCES GOEP_EACCES
+#define BTA_PBS_CO_EOF GOEP_EOF
+#define BTA_PBS_CO_EODIR GOEP_EODIR
+
+typedef UINT16 tBTA_PBS_CO_STATUS;
+
+#define BTA_PBS_LEN_UNKNOWN GOEP_LEN_UNKNOWN
+#define BTA_PBS_INVALID_FD GOEP_INVALID_FD
+#define BTA_PBS_INVALID_APP_ID (0xFF) /* this app_id is reserved */
+
+
+/*****************************************************************************
+** Function Declarations
+*****************************************************************************/
+/**************************
+** Common Functions
+***************************/
+/*******************************************************************************
+**
+** Function bta_pbs_co_open
+**
+** Description This function is executed by BTA when a pb file is requested to be opened.
+** The phone book access profile server uses this function to open
+** a file for reading on two phone book access operations
+** (pull pb or pull pb entry)
+**
+** Parameters p_path - path and file name.
+** operation - BTA_PB_OPER_PULL_PB or BTA_PB_OPER_PULL_VCARD_ENTRY
+** p_app_params - obex application params
+**
+**
+** Returns void
+**
+** Note: Upon completion of the request
+** if successful, and an error code (tBTA_PBS_CO_STATUS)
+** are returned in the call-in function, bta_pbs_ci_open().
+**
+*******************************************************************************/
+BTA_API extern void bta_pbs_co_open(const char *p_path, tBTA_PBS_OPER operation, tBTA_PBS_PULLPB_APP_PARAMS *p_app_params);
+
+/*******************************************************************************
+**
+** Function bta_pbs_co_close
+**
+** Description This function is called by BTA when a connection to a
+** client is closed.
+**
+** Parameters fd - file descriptor of file to close.
+**
+**
+** Returns (tBTA_PBS_CO_STATUS) status of the call.
+** [BTA_PBS_CO_OK if successful],
+** [BTA_PBS_CO_FAIL if failed ]
+**
+*******************************************************************************/
+BTA_API extern tBTA_PBS_CO_STATUS bta_pbs_co_close(int fd);
+
+/*******************************************************************************
+**
+** Function bta_pbs_co_get_pbinfo
+**
+** Description This function is called by BTA to inquire about pb size and new missed calls.
+**
+** Parameters p_name: which type of phone book object Eg. telecom/pb.vcf, telecom/ich.vcf
+** operation: phone book operation type Eg. BTA_PBS_OPER_PULL_PB
+** obj_type: phone book repository type Eg. BTA_PBS_MCH_OBJ
+**
+** Returns pb_size - phone book size
+** new_missed_call - new missed calls
+* (tBTA_PBS_CO_STATUS) status of the call.
+** [BTA_PBS_CO_OK if successful],
+** [BTA_PBS_CO_FAIL if failed ]
+**
+*******************************************************************************/
+BTA_API extern tBTA_PBS_CO_STATUS bta_pbs_co_getpbinfo(tBTA_PBS_OPER operation, tBTA_PBS_OBJ_TYPE obj_type, UINT16 *pb_size, UINT16 *new_missed_call);
+
+/*******************************************************************************
+**
+** Function bta_pbs_co_read
+**
+** Description This function is called by BTA to read in data from the
+** previously opened pb file on the phone.
+** the application callin should fill in the PB object needed to be
+** send to the client
+**
+** Parameters fd - file descriptor of file to read from.
+** operation - BTA_PBS_OPER_PULL_PB or BTA_PBS_OPER_PULL_VCARD_ENTRY
+** p_buf - buffer to read the data into.
+** nbytes - number of bytes to read into the buffer.
+**
+**
+** Returns void
+**
+** Note: Upon completion of the request, bta_pbs_ci_read() is
+** called with the buffer of data, along with the number
+** of bytes read into the buffer, and a status.
+**
+*******************************************************************************/
+BTA_API extern void bta_pbs_co_read(int fd, tBTA_PBS_OPER operation, UINT8 *p_buf, UINT16 nbytes);
+
+
+/*******************************************************************************
+**
+** Function bta_pbs_co_getvlist
+**
+** Description This function is called to retrieve a vcard list entry for the
+** specified path.
+** The first/next directory should be filled by application
+** into the location specified by p_entry.
+**
+** Parameters p_path - directory to search
+** p_app_params - Obex application params, NULL if first_item is FALSE
+** first_item - TRUE if first get, FALSE if next getvlist
+** (p_entry contains previous)
+** p_entry(input/output) - Points to prev entry data, the callout application need
+** to fill in with the next entry
+**
+**
+** Returns void
+**
+** Note: Upon completion of the request, bta_pbs_ci_getvlist() is
+** called with the a status and final flag.
+**
+**
+**
+*******************************************************************************/
+BTA_API extern void bta_pbs_co_getvlist(const char *p_path, tBTA_PBS_VCARDLIST_APP_PARAMS *p_app_params,
+ BOOLEAN first_item, tBTA_PBS_VCARDLIST *p_entry);
+
+
+#endif /* BTA_PBS_CO_H */
diff --git a/bta/include/bta_prm_api.h b/bta/include/bta_prm_api.h
new file mode 100644
index 0000000..434888f
--- /dev/null
+++ b/bta/include/bta_prm_api.h
@@ -0,0 +1,57 @@
+/*****************************************************************************
+**
+** Name: bta_prm_api.h
+**
+** Description: This is the public interface file for the patch ram
+** subsystem of BTA, Widcomm's
+** Bluetooth application layer for mobile phones.
+**
+** Copyright (c) 2003-2005, Widcomm Inc., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_PRM_API_H
+#define BTA_PRM_API_H
+
+#include "bta_api.h"
+#include "bta_sys.h"
+
+/* callback function */
+typedef void (tBTA_PRM_CBACK) (tBTA_STATUS status);
+
+/*****************************************************************************
+** External Function Declarations
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*******************************************************************************
+**
+** Function BTA_PatchRam
+**
+** Description Patch Ram function
+**
+** Parameters p_cback - callback to indicate status of download operation.
+** p_name - path and file name of the patch file.
+** - if p_name is NULL, try to use patch data built into code.
+** fs_app_id - app_id used by bta file system callout functions
+** - to distinguish between applications which uses FS.
+** address - address of patch ram
+**
+**
+** Returns void
+**
+**
+*******************************************************************************/
+BTA_API extern void BTA_PatchRam(tBTA_PRM_CBACK *p_cback, const char *p_name,
+ UINT8 fs_app_id, UINT32 address);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
diff --git a/bta/include/bta_sc_api.h b/bta/include/bta_sc_api.h
new file mode 100644
index 0000000..90e673f
--- /dev/null
+++ b/bta/include/bta_sc_api.h
@@ -0,0 +1,193 @@
+/*****************************************************************************
+**
+** Name: bta_sc_api.c
+**
+** Description: This is the implementation of the API for the SIM
+** Card (SC) server subsystem of BTA, Widcomm's Bluetooth
+** application layer for mobile phones.
+**
+** Copyright (c) 2004, Widcomm Inc., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_SC_API_H
+#define BTA_SC_API_H
+
+#include "bta_api.h"
+#include "sap_api.h"
+
+/*****************************************************************************
+** Constants and data types
+*****************************************************************************/
+
+/* Status of SIM card (for BTA_ScCardStatus) */
+#define BTA_SC_CARD_UNKNOWN_ERROR SAP_CARD_UNKNOWN_ERROR /* Unknown problem with SIM card. */
+#define BTA_SC_CARD_RESET SAP_CARD_RESET /* SIM inserted and powered on prior to SIM Access Profile connection. */
+#define BTA_SC_CARD_NOT_ACCESSIBLE SAP_CARD_NOT_ACCESSIBLE /* SIM inserted, but not accessible. */
+#define BTA_SC_CARD_REMOVED SAP_CARD_REMOVED /* SIM not inserted, or has been removed. */
+#define BTA_SC_CARD_INSERTED SAP_CARD_INSERTED /* SIM inserted, but not powered on. Client needs to power on the SIM before using it. */
+#define BTA_SC_CARD_RECOVERED SAP_CARD_RECOVERED /* Previously not accessible card has been made accessible again, and is powered on by server. */
+typedef UINT8 tBTA_SC_CARD_STATUS;
+
+/* Flags describing Card Reader options (for reader_flags parameter of BTA_ScEnable) */
+#define BTA_SC_READER_FL_REMOVABLE 0x0001
+typedef UINT16 tBTA_SC_READER_FLAGS;
+
+/* Status of card reader (for BTA_ScReaderStatus) */
+#define BTA_SC_READER_STATUS_ATTACHED 0
+#define BTA_SC_READER_STATUS_REMOVED 1
+typedef UINT8 tBTA_SC_READER_STATUS;
+
+
+/* Disconnection type (for BTA_Disconnect) */
+#define BTA_SC_DISC_GRACEFUL SAP_DISCONNECT_GRACEFUL
+#define BTA_SC_DISC_IMMEDIATE SAP_DISCONNECT_IMMEDIATE
+typedef UINT8 tBTA_SC_DISCONNECT_TYPE;
+
+/* Server callback function events */
+#define BTA_SC_ENABLE_EVT 0 /* SIM Access server is enabled. */
+#define BTA_SC_OPEN_EVT 1 /* Connection to peer is open. */
+#define BTA_SC_CLOSE_EVT 2 /* Connection to peer closed. */
+// btla-specific ++
+#define BTA_SC_DISABLE_EVT 3 /* SIM Access server is disabled. */
+// btla-specific --
+typedef UINT8 tBTA_SC_EVT;
+
+
+/* Results codes for use with call-in functions */
+#define BTA_SC_RESULT_OK SAP_RESULT_OK /* Request processed correctly. */
+#define BTA_SC_RESULT_ERROR SAP_RESULT_ERROR /* Error - no reason specified. */
+#define BTA_SC_RESULT_CARD_NOT_ACCESSIBLE SAP_RESULT_CARD_NOT_ACCESSIBLE /* Error - card inserted but not accessible. */
+#define BTA_SC_RESULT_CARD_POWERED_OFF SAP_RESULT_CARD_POWERED_OFF /* Error - card is powered off. */
+#define BTA_SC_RESULT_CARD_REMOVED SAP_RESULT_CARD_REMOVED /* Error - card is not inserted. */
+#define BTA_SC_RESULT_CARD_ALREADY_ON SAP_RESULT_CARD_ALREADY_ON /* Error - card already turned on. */
+#define BTA_SC_RESULT_DATA_NOT_AVAILABLE SAP_RESULT_DATA_NOT_AVAILABLE /* Error - data not available. */
+/* Request codes for use with call-in functions */
+#define BTA_SC_REQUEST_APDU (BTA_SC_RESULT_OK + 10)
+typedef UINT8 tBTA_SC_RESULT;
+
+
+/* Results codes for sim reset */
+#define BTA_SC_RESET_RESULT_OK 0 /* Reset successful */
+#define BTA_SC_RESET_RESULT_ERROR 1 /* Reset failed */
+#define BTA_SC_RESET_RESULT_OK_ONGOING_CALL 2 /* Ongoing call (will reset after call is released) */
+typedef UINT8 tBTA_SC_RESET_RESULT;
+
+/**************************
+** Structure definitions
+***************************/
+/* Event data for BTA_SC_OPEN_EVT */
+typedef struct
+{
+ BD_ADDR bd_addr; /* Client bd address */
+} tBTA_SC_OPEN;
+
+
+/* Union of data types for BTA_SC callback function */
+typedef union
+{
+ tBTA_SC_OPEN open;
+} tBTA_SC;
+
+/* Server callback function */
+typedef void tBTA_SC_CBACK (tBTA_SC_EVT event, tBTA_SC *p_data);
+
+
+/*****************************************************************************
+** External Function Declarations
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+/*******************************************************************************
+**
+** Function BTA_ScEnable
+**
+** Description Enable the SIM Card server. This function must be
+** called before any other functions in the SC API are called.
+** When the enable operation is complete the callback function
+** will be called with a BTA_SC_ENABLE_EVT.
+**
+** Parameters
+** sec_mask Security options
+** p_service_name Service name for SDP record
+** reader_id SIM Card Reader ID (for TRANSFER_CARD_READER_STATUS requests)
+** reader_flags Flags describing card reader
+** msg_size_min Min message size for SIM APDU commands
+** msg_size_max Max message size for SIM APDU commands
+** p_cback Callback for BTA_SC event notification
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_ScEnable(tBTA_SEC sec_mask, const char *p_service_name,
+ UINT8 reader_id, tBTA_SC_READER_FLAGS reader_flags,
+ UINT16 msg_size_min, UINT16 msg_size_max,
+ tBTA_SC_CBACK *p_cback);
+
+/*******************************************************************************
+**
+** Function BTA_ScDisable
+**
+** Description Disable the SIM Card server.
+**
+** Parameters none
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_ScDisable(void);
+
+/*******************************************************************************
+**
+** Function BTA_ScClose
+**
+** Description Close client connection.
+**
+** Parameters
+** type Type of disconnection desired (BTA_SC_DISC_GRACEFUL or
+** BTA_SC_DISC_IMMEDIATE)
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_ScClose(tBTA_SC_DISCONNECT_TYPE type);
+
+
+/*******************************************************************************
+**
+** Function BTA_ScCardStatus
+**
+** Description Notify client of change in SIM card status
+**
+** Parameters
+** status New status
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_ScCardStatus(tBTA_SC_CARD_STATUS status);
+
+
+/*******************************************************************************
+**
+** Function BTA_ScReaderStatus
+**
+** Description Notify client of change in SIM card reader status
+**
+** Parameters
+** status New status
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_ScReaderStatus(tBTA_SC_READER_STATUS status);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_SC_API_H */
diff --git a/bta/include/bta_sc_ci.h b/bta/include/bta_sc_ci.h
new file mode 100644
index 0000000..10b11e6
--- /dev/null
+++ b/bta/include/bta_sc_ci.h
@@ -0,0 +1,111 @@
+/*****************************************************************************
+**
+** Name: bta_sc_ci.h
+**
+** Description: This is the interface file for SIM Access server
+** call-in functions.
+**
+** Copyright (c) 2003, Widcomm Inc., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_SC_CI_H
+#define BTA_SC_CI_H
+
+#include "bta_sc_api.h"
+
+/*****************************************************************************
+** Function Declarations
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*******************************************************************************
+**
+** Function bta_sc_ci_apdu
+**
+** Description This function sends an event to SC to indicate the APDU request
+** has been completed or requested
+**
+** Parameters
+** result result of operation or request of operation
+** p_apdu response buffer for APDU command (if result=BTA_SC_RESULT_OK)
+** or request buffer for APDU command (if result=BTA_SC_REQUEST_APDU)
+** apdulen length of response or request buffer
+** is_apdu_7816 TRUE if format of apdu data is APDU7816
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_sc_ci_apdu(tBTA_SC_RESULT result, UINT8 *p_apdu, UINT16 apdulen, BOOLEAN is_apdu_7816);
+
+/*******************************************************************************
+**
+** Function bta_sc_ci_atr
+**
+** Description This function sends an event to SC to indicate the ATR request
+** has been completed
+**
+** Parameters
+** result result of operation
+** p_atr response buffer for ATR request (if result=BTA_SC_RESULT_OK)
+** atrlen length of response buffer
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_sc_ci_atr(tBTA_SC_RESULT result, UINT8 *p_atr, UINT16 atrlen);
+
+/*******************************************************************************
+**
+** Function bta_sc_ci_sim_on
+**
+** Description This function sends an event to SC to indicate the SIM_ON request
+** has been completed
+**
+** Parameters
+** result result of operation
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_sc_ci_sim_on(tBTA_SC_RESULT result);
+
+/*******************************************************************************
+**
+** Function bta_sc_ci_sim_off
+**
+** Description This function sends an event to SC to indicate the SIM_OFF request
+** has been completed
+**
+** Parameters
+** result result of operation
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_sc_ci_sim_off(tBTA_SC_RESULT result);
+
+/*******************************************************************************
+**
+** Function bta_sc_ci_sim_reset
+**
+** Description This function sends an event to SC to indicate the SIM_RESET request
+** has been completed
+**
+** Parameters
+** result result of operation
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_sc_ci_sim_reset(tBTA_SC_RESET_RESULT result);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_SC_CI_H */
+
diff --git a/bta/include/bta_sc_co.h b/bta/include/bta_sc_co.h
new file mode 100644
index 0000000..a088823
--- /dev/null
+++ b/bta/include/bta_sc_co.h
@@ -0,0 +1,153 @@
+/*****************************************************************************
+**
+** Name: bta_sc_co.h
+**
+** Description: This is the interface file for the SIM access
+** server call-out functions.
+**
+** Copyright (c) 2003, Widcomm Inc., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_SC_CO_H
+#define BTA_SC_CO_H
+
+#include "bta_sc_api.h"
+
+/*****************************************************************************
+** Constants and Data Types
+*****************************************************************************/
+
+/*****************************************************************************
+** Function Declarations
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*******************************************************************************
+**
+** Function bta_sc_co_sim_opem
+**
+** Description Called when client connection is opened, in case any special
+** handling or intialization of the SIM is required.
+**
+** Parameters
+** None.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_sc_co_sim_open(void);
+
+/*******************************************************************************
+**
+** Function bta_sc_co_sim_close
+**
+** Description Called when client connection is closed.
+**
+** Parameters
+** None.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_sc_co_sim_close(void);
+
+/*******************************************************************************
+**
+** Function bta_sc_co_sim_reset
+**
+** Description This function is called by BTA to reset the SIM card
+**
+** Once SIM has been turned reset, call bta_sc_ci_sim_reset().
+**
+** Parameters
+** None.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_sc_co_sim_reset(void);
+
+/*******************************************************************************
+**
+** Function bta_sc_co_sim_off
+**
+** Description This function is called by BTA to turn the SIM card off
+**
+** Once SIM has been turned on, call bta_sc_ci_sim_on().
+**
+** Parameters
+** None.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_sc_co_sim_off(void);
+
+/*******************************************************************************
+**
+** Function bta_sc_co_sim_on
+**
+** Description This function is called by BTA to turn the SIM card on
+**
+** Once SIM has been turned on, call bta_sc_ci_sim_on().
+**
+** Parameters
+** None.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_sc_co_sim_on(void);
+
+/*******************************************************************************
+**
+** Function bta_sc_co_atr
+**
+** Description This function is called by BTA to retrieve ATR information
+** (operational requirements of the SIM, as described in
+** section 5.8 of GSM 11.11)
+**
+** Once the ATR information is retrieved, call bta_sc_ci_atr().
+**
+** Parameters
+** None.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_sc_co_atr(void);
+
+/*******************************************************************************
+**
+** Function bta_sc_co_apdu
+**
+** Description This function is called by BTA to to transfer APDU command
+** messages to the SIM. Generally used for selecting, storing
+** and retrieving data from the SIM.
+**
+** Once the command has been completed, call bta_sc_ci_apdu()
+** with the result.
+**
+** Parameters
+** p_apdu_req Pointer to the APDU message from the client. Format
+** is described in section 9 of GSM 11.11
+**
+** req_len Length of APDU message.
+**
+** rsp_maxlen Maximum length of response message allowed by client
+** (negotiated during CONNECT_REQ)
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_sc_co_apdu(UINT8 *p_apdu_req, UINT16 req_len, UINT16 rsp_maxlen, BOOLEAN is_apdu_7816);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_SC_CO_H */
diff --git a/bta/include/bta_sys_ci.h b/bta/include/bta_sys_ci.h
new file mode 100644
index 0000000..48cfab1
--- /dev/null
+++ b/bta/include/bta_sys_ci.h
@@ -0,0 +1,57 @@
+/*****************************************************************************
+**
+** Name: bta_sys_ci.h
+**
+** Description: This is the interface file for system call-in
+** functions.
+**
+** Copyright (c) 2010, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_SYS_CI_H
+#define BTA_SYS_CI_H
+
+#include "bta_api.h"
+
+/*****************************************************************************
+** Function Declarations
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*******************************************************************************
+**
+** Function bta_sys_hw_ci_enabled
+**
+** Description This function must be called in response to function
+** bta_sys_hw_co_enable(), when HW is indeed enabled
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API void bta_sys_hw_ci_enabled(tBTA_SYS_HW_MODULE module );
+
+
+/*******************************************************************************
+**
+** Function bta_sys_hw_ci_disabled
+**
+** Description This function must be called in response to function
+** bta_sys_hw_co_disable() when HW is really OFF
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API void bta_sys_hw_ci_disabled( tBTA_SYS_HW_MODULE module );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/bta/include/bta_sys_co.h b/bta/include/bta_sys_co.h
new file mode 100644
index 0000000..2b82153
--- /dev/null
+++ b/bta/include/bta_sys_co.h
@@ -0,0 +1,47 @@
+/*****************************************************************************
+**
+** Name: bta_sys_co.h
+**
+** Description: This is the interface file for system callout
+** functions.
+**
+** Copyright (c) 2010, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_SYS_CO_H
+#define BTA_SYS_CO_H
+
+#include "bta_sys.h"
+
+
+
+/*****************************************************************************
+** Function Declarations
+*****************************************************************************/
+
+
+/*******************************************************************************
+**
+** Function bta_sys_hw_co_enable
+**
+** Description This function is called by the stack to power up the HW
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API void bta_sys_hw_co_enable( tBTA_SYS_HW_MODULE module );
+
+/*******************************************************************************
+**
+** Function bta_sys_hw_co_disable
+**
+** Description This function is called by the stack to power down the HW
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API void bta_sys_hw_co_disable( tBTA_SYS_HW_MODULE module );
+
+
+#endif
diff --git a/bta/include/ptim.h b/bta/include/ptim.h
new file mode 100644
index 0000000..35082a0
--- /dev/null
+++ b/bta/include/ptim.h
@@ -0,0 +1,86 @@
+/*****************************************************************************
+**
+** Name: ptim.h
+**
+** Description: Protocol timer services.
+**
+** Copyright (c) 2003-2006, Broadcom Corp., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef PTIM_H
+#define PTIM_H
+
+#include "gki.h"
+
+/*****************************************************************************
+** Constants and data types
+*****************************************************************************/
+
+typedef struct
+{
+ TIMER_LIST_Q timer_queue; /* GKI timer queue */
+ INT32 period; /* Timer period in milliseconds */
+ UINT32 last_gki_ticks; /* GKI ticks since last time update called */
+ UINT8 timer_id; /* GKI timer id */
+} tPTIM_CB;
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*****************************************************************************
+** Function Declarations
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function ptim_init
+**
+** Description Initialize a protocol timer service control block.
+**
+** Returns void
+**
+*******************************************************************************/
+extern void ptim_init(tPTIM_CB *p_cb, UINT16 period, UINT8 timer_id);
+
+/*******************************************************************************
+**
+** Function ptim_timer_update
+**
+** Description Update the protocol timer list and handle expired timers.
+**
+** Returns void
+**
+*******************************************************************************/
+extern void ptim_timer_update(tPTIM_CB *p_cb);
+
+/*******************************************************************************
+**
+** Function ptim_start_timer
+**
+** Description Start a protocol timer for the specified amount
+** of time in milliseconds.
+**
+** Returns void
+**
+*******************************************************************************/
+extern void ptim_start_timer(tPTIM_CB *p_cb, TIMER_LIST_ENT *p_tle, UINT16 type, INT32 timeout);
+
+/*******************************************************************************
+**
+** Function ptim_stop_timer
+**
+** Description Stop a protocol timer.
+**
+** Returns void
+**
+*******************************************************************************/
+extern void ptim_stop_timer(tPTIM_CB *p_cb, TIMER_LIST_ENT *p_tle);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PTIM_H */
diff --git a/bta/include/utl.h b/bta/include/utl.h
new file mode 100644
index 0000000..392d239
--- /dev/null
+++ b/bta/include/utl.h
@@ -0,0 +1,156 @@
+/*****************************************************************************
+**
+** Name: utl.h
+**
+** Description: Basic utility functions.
+**
+** Copyright (c) 2003-2004, Widcomm Inc., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef UTL_H
+#define UTL_H
+
+#include "data_types.h"
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+/*** class of device settings ***/
+#define BTA_UTL_SET_COD_MAJOR_MINOR 0x01
+#define BTA_UTL_SET_COD_SERVICE_CLASS 0x02 /* only set the bits in the input */
+#define BTA_UTL_CLR_COD_SERVICE_CLASS 0x04
+#define BTA_UTL_SET_COD_ALL 0x08 /* take service class as the input (may clear some set bits!!) */
+#define BTA_UTL_INIT_COD 0x0a
+
+/*****************************************************************************
+** Type Definitions
+*****************************************************************************/
+
+/** for utl_set_device_class() **/
+typedef struct
+{
+ UINT8 minor;
+ UINT8 major;
+ UINT16 service;
+} tBTA_UTL_COD;
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*****************************************************************************
+** External Function Declarations
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function utl_str2int
+**
+** Description This utility function converts a character string to an
+** integer. Acceptable values in string are 0-9. If invalid
+** string or string value too large, -1 is returned.
+**
+**
+** Returns Integer value or -1 on error.
+**
+*******************************************************************************/
+extern INT16 utl_str2int(const char *p_s);
+
+/*******************************************************************************
+**
+** Function utl_strucmp
+**
+** Description This utility function compares two strings in uppercase.
+** String p_s must be uppercase. String p_t is converted to
+** uppercase if lowercase. If p_s ends first, the substring
+** match is counted as a match.
+**
+**
+** Returns 0 if strings match, nonzero otherwise.
+**
+*******************************************************************************/
+extern int utl_strucmp(const char *p_s, const char *p_t);
+
+/*******************************************************************************
+**
+** Function utl_itoa
+**
+** Description This utility function converts a UINT16 to a string. The
+** string is NULL-terminated. The length of the string is
+** returned.
+**
+**
+** Returns Length of string.
+**
+*******************************************************************************/
+extern UINT8 utl_itoa(UINT16 i, char *p_s);
+
+/*******************************************************************************
+**
+** Function utl_freebuf
+**
+** Description This function calls GKI_freebuf to free the buffer passed
+** in, if buffer pointer is not NULL, and also initializes
+** buffer pointer to NULL.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+extern void utl_freebuf(void **p);
+
+/*******************************************************************************
+**
+** Function utl_set_device_class
+**
+** Description This function updates the local Device Class.
+**
+** Parameters:
+** p_cod - Pointer to the device class to set to
+**
+** cmd - the fields of the device class to update.
+** BTA_UTL_SET_COD_MAJOR_MINOR, - overwrite major, minor class
+** BTA_UTL_SET_COD_SERVICE_CLASS - set the bits in the input
+** BTA_UTL_CLR_COD_SERVICE_CLASS - clear the bits in the input
+** BTA_UTL_SET_COD_ALL - overwrite major, minor, set the bits in service class
+** BTA_UTL_INIT_COD - overwrite major, minor, and service class
+**
+** Returns TRUE if successful, Otherwise FALSE
+**
+*******************************************************************************/
+extern BOOLEAN utl_set_device_class(tBTA_UTL_COD *p_cod, UINT8 cmd);
+
+/*******************************************************************************
+**
+** Function utl_isintstr
+**
+** Description This utility function checks if the given string is an
+** integer string or not
+**
+**
+** Returns TRUE if successful, Otherwise FALSE
+**
+*******************************************************************************/
+extern BOOLEAN utl_isintstr(const char *p_s);
+
+/*******************************************************************************
+**
+** Function utl_isdialstr
+**
+** Description This utility function checks if the given string contains
+** only dial digits or not
+**
+**
+** Returns TRUE if successful, Otherwise FALSE
+**
+*******************************************************************************/
+extern BOOLEAN utl_isdialstr(const char *p_s);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* UTL_H */
diff --git a/bta/ma/bta_ma_api.c b/bta/ma/bta_ma_api.c
new file mode 100644
index 0000000..2157447
--- /dev/null
+++ b/bta/ma/bta_ma_api.c
@@ -0,0 +1,1203 @@
+/*****************************************************************************
+**
+** Name: bta_mse_api.c
+**
+** Description: This is the implementation of the common API for the Message
+** Acess Profile of BTA, Broadcom Corp's Bluetooth
+** application layer for mobile phones.
+**
+** Copyright (c) 2009-2011 Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+
+#if defined(BTA_MSE_INCLUDED) && (BTA_MSE_INCLUDED == TRUE)
+
+
+#include <string.h>
+#include "bta_ma_api.h"
+#include "bta_ma_util.h"
+#include "bta_ma_co.h"
+/*******************************************************************************
+**
+** Function BTA_MaBmsgCreate
+**
+** Description Create and initialize an instance of a tBTA_MA_BMSG structure.
+**
+** Parameters None
+**
+** Returns Pointer to a bMessage object, or NULL if this fails.
+**
+*******************************************************************************/
+tBTA_MA_BMSG * BTA_MaBmsgCreate(void)
+{
+ tBTA_MA_BMSG *p_msg = (tBTA_MA_BMSG *) bta_ma_bmsg_alloc(sizeof(tBTA_MA_BMSG));
+
+ if ( p_msg )
+ {
+ memset(p_msg, 0, sizeof(tBTA_MA_BMSG));
+ }
+ else
+ {
+ APPL_TRACE_ERROR0("BTA_MaBmsgCreate failed");
+ }
+
+ return(p_msg);
+}
+
+/*******************************************************************************
+**
+** Function BTA_MaBmsgFree
+**
+** Description Destroy (free) the contents of a tBTA_MA_BMSG structure.
+**
+** Parameters p_bmsg - Pointer to a bMessage object
+**
+** Returns None
+**
+*******************************************************************************/
+void BTA_MaBmsgFree(tBTA_MA_BMSG * p_msg)
+{
+ if ( p_msg )
+ {
+ /* free folder string */
+ bta_ma_bmsg_free(p_msg->p_folder);
+
+ /* free all the vCards */
+ bta_ma_bmsg_free_vcards(p_msg->p_orig);
+
+ /* free the envelopes */
+ bta_ma_bmsg_free_envelope(p_msg->p_envelope);
+
+ /* free b-message structure itself */
+ bta_ma_bmsg_free(p_msg);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_MaBmsgSetReadSts
+**
+** Description Set the bmessage-readstatus-property value for the bMessage
+** object. If the 'read_sts' is TRUE then value will be "READ",
+** otherwise it is "UNREAD".
+**
+** Parameters p_bmsg - Pointer to a bMessage object
+** read_sts - Read status TRUE- read FALSE - unread
+**
+** Returns None
+**
+*******************************************************************************/
+void BTA_MaBmsgSetReadSts(tBTA_MA_BMSG * p_msg, BOOLEAN read_sts)
+{
+ if ( p_msg )
+ p_msg->read_sts = read_sts;
+}
+
+/*******************************************************************************
+**
+** Function BTA_MaBmsgGetReadSts
+**
+** Description Get the bmessage-readstatus-property value for the bMessage
+** object
+**
+** Parameters p_bmsg - Pointer to a bMessage object
+**
+** Returns Read status (TRUE/FALSE) for the specified bMessage.
+**
+*******************************************************************************/
+BOOLEAN BTA_MaBmsgGetReadSts(tBTA_MA_BMSG * p_msg)
+{
+ return( p_msg ? p_msg->read_sts : FALSE);
+}
+
+/*******************************************************************************
+**
+** Function BTA_MaBmsgSetMsgType
+**
+** Description Set the bmessage-type-property value for the bMessage object
+**
+** Parameters p_bmsg - Pointer to a bMessage object
+** msg_type - Message type
+**
+** Returns None
+**
+*******************************************************************************/
+void BTA_MaBmsgSetMsgType(tBTA_MA_BMSG * p_msg, tBTA_MA_MSG_TYPE msg_type)
+{
+ if ( p_msg )
+ p_msg->msg_type = msg_type;
+}
+
+/*******************************************************************************
+**
+** Function BTA_MaBmsgGetMsgType
+**
+** Description Get the bmessage-type-property value for the specified
+** bMessage object
+**
+** Parameters p_bmsg - Pointer to a bMessage object
+**
+** Returns Message type
+**
+*******************************************************************************/
+tBTA_MA_MSG_TYPE BTA_MaBmsgGetMsgType(tBTA_MA_BMSG * p_msg)
+{
+ /* return 0 (for lack of a better value) */
+ return( p_msg ? p_msg->msg_type : 0);
+}
+
+/*******************************************************************************
+**
+** Function BTA_MaBmsgSetFolder
+**
+** Description Set the bmessage-folder-property value for the bMessage object
+**
+** Parameters p_bmsg - Pointer to a bMessage object
+** p_folder - Pointer to a folder path
+**
+** Returns None
+**
+*******************************************************************************/
+void BTA_MaBmsgSetFolder(tBTA_MA_BMSG *p_msg, char *p_folder)
+{
+ if ( p_msg && p_folder )
+ {
+ /* free any existing string */
+ if ( p_msg->p_folder )
+ bta_ma_bmsg_free(p_msg->p_folder);
+
+ /* allocate a new one */
+ p_msg->p_folder = (char *) bta_ma_bmsg_alloc(strlen(p_folder)+1);
+ if ( p_msg->p_folder )
+ BCM_STRNCPY_S(p_msg->p_folder, strlen(p_folder)+1, p_folder, strlen(p_folder)+1);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_MaBmsgGetFolder
+**
+** Description Get the bmessage-folder-property value for the specified
+** bMessage object
+**
+** Parameters p_bmsg - Pointer to a bMessage object
+**
+** Returns Pointer to folder path string, or NULL if it has not been set.
+**
+*******************************************************************************/
+char * BTA_MaBmsgGetFolder(tBTA_MA_BMSG * p_msg)
+{
+ return(p_msg ? (char *) p_msg->p_folder : NULL);
+}
+
+/*******************************************************************************
+**
+** Function BTA_MaBmsgAddOrigToBmsg
+**
+** Description Add an originator to the bMessage object
+**
+** Parameters p_bmsg - Pointer to a bMessage object
+**
+** Returns Pointer to a new vCard structure, or NULL if this function
+** fails.
+**
+*******************************************************************************/
+tBTA_MA_BMSG_VCARD * BTA_MaBmsgAddOrigToBmsg(tBTA_MA_BMSG * p_msg)
+{
+ tBTA_MA_BMSG_VCARD * p_vcard = NULL;
+ tBTA_MA_BMSG_VCARD * p_last_vcard = NULL;
+
+ if ( p_msg )
+ {
+ p_vcard = (tBTA_MA_BMSG_VCARD *)bta_ma_bmsg_alloc(sizeof(tBTA_MA_BMSG_VCARD));
+ if ( p_vcard )
+ {
+ memset(p_vcard, 0, sizeof(tBTA_MA_BMSG_VCARD));
+ p_vcard->version = BTA_MA_VCARD_VERSION_21; /* default to 2.1 */
+
+ if ( p_msg->p_orig )
+ {
+ /* set pointer to the last entry in the list */
+ p_last_vcard = p_msg->p_orig;
+ while ( p_last_vcard->p_next )
+ p_last_vcard = (tBTA_MA_BMSG_VCARD *) p_last_vcard->p_next;
+
+ p_last_vcard->p_next = p_vcard;
+ }
+ else
+ p_msg->p_orig = p_vcard;
+ }
+ }
+
+ return(p_vcard);
+}
+
+/*******************************************************************************
+**
+** Function BTA_MaBmsgGetOrigFromBmsg
+**
+** Description Get the first originator vCard information from the specified
+** bMessage object
+**
+** Parameters p_bmsg - Pointer to a bMessage object
+**
+** Returns Pointer to first 'originator vCard, or NULL not used.
+**
+*******************************************************************************/
+tBTA_MA_BMSG_VCARD * BTA_MaBmsgGetOrigFromBmsg(tBTA_MA_BMSG * p_msg)
+{
+ return(p_msg ? (tBTA_MA_BMSG_VCARD *) p_msg->p_orig : NULL);
+}
+
+/*******************************************************************************
+**
+** Function BTA_MaBmsgAddEnvToBmsg
+**
+** Description Add a new envelope to the bMessage object. This is the first
+** (top) level envelope. bMessage allows up to 3 levels of envelopes.
+** application should call BTA_MaBmsgAddEnvToEnv to add the 2nd
+** 3rd level enevelope.
+**
+** Parameters p_bmsg - Pointer to a bMessage object
+**
+** Returns Pointer to a new envelope structure, or NULL if this
+** function fails.
+**
+*******************************************************************************/
+tBTA_MA_BMSG_ENVELOPE * BTA_MaBmsgAddEnvToBmsg(tBTA_MA_BMSG * p_msg)
+{
+ tBTA_MA_BMSG_ENVELOPE * p_envelope = NULL;
+
+ if ( p_msg )
+ {
+ p_envelope = (tBTA_MA_BMSG_ENVELOPE *)bta_ma_bmsg_alloc(sizeof(tBTA_MA_BMSG_ENVELOPE));
+ if ( p_envelope )
+ {
+ memset(p_envelope, 0, sizeof(tBTA_MA_BMSG_ENVELOPE));
+ p_msg->p_envelope = p_envelope;
+ }
+ }
+
+ return( p_envelope );
+}
+/*******************************************************************************
+**
+** Function BTA_MaBmsgAddEnvToEnv
+**
+** Description Add a child envelope to an existing envelope.
+**
+** Parameters p_envelope - Pointer to a parent envelope
+**
+** Returns Pointer to an envelope structure, or NULL if this
+** function fails.
+**
+*******************************************************************************/
+tBTA_MA_BMSG_ENVELOPE * BTA_MaBmsgAddEnvToEnv(tBTA_MA_BMSG_ENVELOPE * p_envelope)
+{
+ tBTA_MA_BMSG_ENVELOPE * p_new_envelope = NULL;
+
+ if ( p_envelope )
+ {
+ p_new_envelope = (tBTA_MA_BMSG_ENVELOPE *)bta_ma_bmsg_alloc(sizeof(tBTA_MA_BMSG_ENVELOPE));
+ if ( p_new_envelope )
+ {
+ memset(p_new_envelope, 0, sizeof(tBTA_MA_BMSG_ENVELOPE));
+ p_envelope->p_next = p_new_envelope;
+ }
+ }
+
+ return( p_new_envelope );
+}
+
+/*******************************************************************************
+**
+** Function BTA_MaBmsgGetEnv
+**
+** Description Get the pointer of the first level envelope.
+**
+** Parameters p_bmsg - Pointer to a bMessage object
+**
+** Returns Pointer to the first level envelope structure, or NULL if it
+** does not exist
+**
+*******************************************************************************/
+tBTA_MA_BMSG_ENVELOPE * BTA_MaBmsgGetEnv(tBTA_MA_BMSG * p_msg)
+{
+ return(p_msg ? (tBTA_MA_BMSG_ENVELOPE *) p_msg->p_envelope : NULL);
+}
+
+/*******************************************************************************
+**
+** Function BTA_MaBmsgGetNextEnv
+**
+** Description Get the child envelope of the specified parent envelope.
+**
+** Parameters p_env - Pointer to a parent envelope
+**
+** Returns Pointer to a child enevelope. NULL if the
+** envelope does not have a 'child' envelope.
+**
+*******************************************************************************/
+tBTA_MA_BMSG_ENVELOPE * BTA_MaBmsgGetNextEnv(tBTA_MA_BMSG_ENVELOPE * p_env)
+{
+ return(p_env ? (tBTA_MA_BMSG_ENVELOPE *)p_env->p_next : NULL);
+}
+/*******************************************************************************
+**
+** Function BTA_MaBmsgAddRecipToEnv
+**
+** Description Add recipient to the specified envelope.
+**
+** Parameters p_env - Pointer to a envelope
+**
+** Returns Pointer to a vCard structure. NULL if it
+** fails to allocate a vCard structure.
+**
+*******************************************************************************/
+tBTA_MA_BMSG_VCARD * BTA_MaBmsgAddRecipToEnv(tBTA_MA_BMSG_ENVELOPE * p_env)
+{
+ tBTA_MA_BMSG_VCARD * p_vcard = NULL;
+ tBTA_MA_BMSG_VCARD * p_last_vcard = NULL;
+
+ if ( p_env )
+ {
+ p_vcard = (tBTA_MA_BMSG_VCARD *)bta_ma_bmsg_alloc(sizeof(tBTA_MA_BMSG_VCARD));
+ if ( p_vcard )
+ {
+ memset(p_vcard, 0, sizeof(tBTA_MA_BMSG_VCARD));
+ p_vcard->version = BTA_MA_VCARD_VERSION_21; /* default to 2.1 */
+
+ if ( p_env->p_recip )
+ {
+ /* set pointer to the last entry in the list */
+ p_last_vcard = p_env->p_recip;
+ while ( p_last_vcard->p_next )
+ p_last_vcard = (tBTA_MA_BMSG_VCARD *) p_last_vcard->p_next;
+
+ p_last_vcard->p_next = p_vcard;
+ }
+ else
+ p_env->p_recip = p_vcard;
+ }
+ }
+
+ return(p_vcard);
+}
+/*******************************************************************************
+**
+** Function BTA_MaBmsgGetRecipFromEnv
+**
+** Description Get the first recipient's vCard from the specified envelope.
+**
+** Parameters p_env - Pointer to a envelope
+**
+** Returns Pointer to the first recipient's vCard structure. NULL if it
+** has not be set.
+**
+*******************************************************************************/
+tBTA_MA_BMSG_VCARD * BTA_MaBmsgGetRecipFromEnv(tBTA_MA_BMSG_ENVELOPE * p_env)
+{
+ return(p_env ? p_env->p_recip : NULL);
+}
+/*******************************************************************************
+**
+** Function BTA_MaBmsgAddBodyToEnv
+**
+** Description Add a message body to the specified envelope.
+**
+** Parameters p_env - Pointer to a envelope
+**
+** Returns Pointer to a message body structure.
+** NULL if it fails to allocate a message body structure.
+**
+*******************************************************************************/
+tBTA_MA_BMSG_BODY * BTA_MaBmsgAddBodyToEnv(tBTA_MA_BMSG_ENVELOPE * p_env)
+{
+ tBTA_MA_BMSG_BODY * p_body = NULL;
+
+ if ( p_env )
+ {
+ /* free any existing body */
+ if ( p_env->p_body )
+ bta_ma_bmsg_free_body(p_env->p_body);
+
+ /* allocate a new one */
+ p_body = (tBTA_MA_BMSG_BODY *)bta_ma_bmsg_alloc(sizeof(tBTA_MA_BMSG_BODY));
+ if ( p_body )
+ {
+ memset(p_body, 0, sizeof(tBTA_MA_BMSG_BODY));
+ p_body->encoding = BTA_MA_BMSG_ENC_8BIT; /* default */
+ }
+
+ p_env->p_body = p_body;
+ }
+
+ return(p_body);
+}
+/*******************************************************************************
+**
+** Function BTA_MaBmsgGetBodyFromEnv
+**
+** Description Get the message body pointer from the specified envelope.
+**
+** Parameters p_env - Pointer to a envelope
+**
+** Returns Pointer to a message body structure.
+** NULL if it has not been set.
+**
+*******************************************************************************/
+tBTA_MA_BMSG_BODY * BTA_MaBmsgGetBodyFromEnv(tBTA_MA_BMSG_ENVELOPE * p_env)
+{
+ return( p_env ? p_env->p_body : NULL);
+}
+
+/*******************************************************************************
+**
+** Function BTA_MaBmsgSetBodyEncoding
+**
+** Description Set the bmessage-body-encoding-property value for the bMessage
+** body.
+**
+** Parameters p_body - Pointer to a bMessage body
+** encoding - encoding scheme
+**
+** Returns None
+**
+*******************************************************************************/
+void BTA_MaBmsgSetBodyEncoding(tBTA_MA_BMSG_BODY * p_body, tBTA_MA_BMSG_ENCODING encoding)
+{
+ if ( p_body )
+ p_body->encoding = encoding;
+}
+
+/*******************************************************************************
+**
+** Function BTA_MaBmsgGetBodyEncoding
+**
+** Description Get the bmessage-body-encoding-property value for the specified
+** bMessage body.
+**
+** Parameters p_body - Pointer to a bMessage body
+**
+** Returns Message encoding scheme
+**
+*******************************************************************************/
+tBTA_MA_BMSG_ENCODING BTA_MaBmsgGetBodyEncoding(tBTA_MA_BMSG_BODY * p_body)
+{
+ return( p_body ? p_body->encoding : BTA_MA_BMSG_ENC_8BIT );
+}
+/*******************************************************************************
+**
+** Function BTA_MaBmsgSetBodyPartid
+**
+** Description Set the bmessage-body-part-ID value for the speicified
+** bMessage body.
+**
+** Parameters p_body - Pointer to a bMessage body
+** part_id - Part ID (range: from 0 to 65535)
+**
+** Returns None
+**
+*******************************************************************************/
+void BTA_MaBmsgSetBodyPartid(tBTA_MA_BMSG_BODY * p_body, UINT16 part_id)
+{
+ if ( p_body )
+ {
+ p_body->part_id = part_id;
+ p_body->is_multipart = TRUE;
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_MaBmsgGetBodyPartid
+**
+** Description Get the bmessage-body-part-ID value for the specified
+** bMessage body.
+**
+** Parameters p_body - Pointer to a bMessage body
+**
+** Returns The value of the Part ID
+**
+*******************************************************************************/
+UINT16 BTA_MaBmsgGetBodyPartid(tBTA_MA_BMSG_BODY * p_body)
+{
+ return( p_body ? p_body->part_id : 0 );
+}
+/*******************************************************************************
+**
+** Function BTA_MaBmsgIsBodyMultiPart
+**
+** Description Is this a multi-part body
+**
+** Parameters p_body - Pointer to a bMessage body
+**
+** Returns TURE - if this is a multi-part body
+**
+*******************************************************************************/
+BOOLEAN BTA_MaBmsgIsBodyMultiPart(tBTA_MA_BMSG_BODY * p_body)
+{
+ return( p_body ? p_body->is_multipart : FALSE );
+}
+
+/*******************************************************************************
+**
+** Function BTA_MaBmsgSetBodyCharset
+**
+** Description Set the bmessage-body-charset-property value for the speicified
+** bMessage body.
+**
+** Parameters p_body - Pointer to a bMessage body
+** charset - Charset
+**
+** Returns None
+**
+*******************************************************************************/
+void BTA_MaBmsgSetBodyCharset(tBTA_MA_BMSG_BODY * p_body, tBTA_MA_CHARSET charset)
+{
+ if ( p_body )
+ p_body->charset = charset;
+}
+/*******************************************************************************
+**
+** Function BTA_MaBmsgGetBodyCharset
+**
+** Description Get the bmessage-body-charset-property value for the speicified
+** bMessage body.
+**
+** Parameters p_body - Pointer to a bMessage body
+**
+** Returns Charset
+**
+*******************************************************************************/
+tBTA_MA_CHARSET BTA_MaBmsgGetBodyCharset(tBTA_MA_BMSG_BODY * p_body)
+{
+ return( p_body ? p_body->charset : BTA_MA_CHARSET_UNKNOWN );
+}
+/*******************************************************************************
+**
+** Function BTA_MaBmsgSetBodyLanguage
+**
+** Description Set the bmessage-body-language-property value for the speicified
+** bMessage body.
+**
+** Parameters p_body - Pointer to a bMessage body
+** Language - the language of the message
+**
+** Returns None
+**
+*******************************************************************************/
+void BTA_MaBmsgSetBodyLanguage(tBTA_MA_BMSG_BODY * p_body, tBTA_MA_BMSG_LANGUAGE language)
+{
+ if ( p_body )
+ p_body->language = language;
+}
+/*******************************************************************************
+**
+** Function BTA_MaBmsgGetBodyLanguage
+**
+** Description Get the bmessage-body-language-property value for the speicified
+** bMessage body.
+**
+** Parameters p_body - Pointer to a bMessage body
+**
+** Returns the language of the message
+**
+*******************************************************************************/
+tBTA_MA_BMSG_LANGUAGE BTA_MaBmsgGetBodyLanguage(tBTA_MA_BMSG_BODY * p_body)
+{
+ return( p_body ? p_body->language : BTA_MA_BMSG_LANG_UNSPECIFIED );
+}
+/*******************************************************************************
+**
+** Function BTA_MaBmsgAddContentToBody
+**
+** Description Add a message content to the speicified bMessage body.
+**
+** Parameters p_body - Pointer to a bMessage body
+**
+** Returns Pointer to a message content.
+** NULL if it fails to allocate a message content buffer
+**
+*******************************************************************************/
+tBTA_MA_BMSG_CONTENT * BTA_MaBmsgAddContentToBody(tBTA_MA_BMSG_BODY * p_body)
+{
+ tBTA_MA_BMSG_CONTENT * p_content = NULL;
+ tBTA_MA_BMSG_CONTENT * p_last_content = NULL;
+
+ if ( p_body )
+ {
+ p_content = (tBTA_MA_BMSG_CONTENT *)bta_ma_bmsg_alloc(sizeof(tBTA_MA_BMSG_CONTENT));
+ if ( p_content )
+ {
+ memset(p_content, 0, sizeof(tBTA_MA_BMSG_CONTENT));
+
+ if ( p_body->p_content )
+ {
+ /* set pointer to the last entry in the list */
+ p_last_content = p_body->p_content;
+ while ( p_last_content->p_next )
+ p_last_content = (tBTA_MA_BMSG_CONTENT *)p_last_content->p_next;
+
+ p_last_content->p_next = p_content;
+ }
+ else
+ p_body->p_content = p_content;
+ }
+ }
+
+ return(p_content);
+}
+/*******************************************************************************
+**
+** Function BTA_MaBmsgGetContentFromBody
+**
+** Description Get a message content from the speicified bMessage body.
+**
+** Parameters p_body - Pointer to a bMessage body
+**
+** Returns Pointer to a message content.
+** NULL if it has not been set.
+**
+*******************************************************************************/
+tBTA_MA_BMSG_CONTENT * BTA_MaBmsgGetContentFromBody(tBTA_MA_BMSG_BODY * p_body)
+{
+ return(p_body ? p_body->p_content : NULL);
+}
+/*******************************************************************************
+**
+** Function BTA_MaBmsgGetNextContent
+**
+** Description Get the next message content from the speicified message content.
+**
+** Parameters p_content - Pointer to a message content
+**
+** Returns Pointer to a message content.
+** NULL if it has not been set.
+**
+*******************************************************************************/
+tBTA_MA_BMSG_CONTENT * BTA_MaBmsgGetNextContent(tBTA_MA_BMSG_CONTENT * p_content)
+{
+ return(p_content ? (tBTA_MA_BMSG_CONTENT *)p_content->p_next : NULL);
+}
+
+/*******************************************************************************
+**
+** Function BTA_MaBmsgAddMsgContent
+**
+** Description Add a text string to the speicified message content.
+**
+** Parameters p_content - Pointer to a message content
+** p_text - Pointer to a text string
+**
+** Returns None
+**
+*******************************************************************************/
+void BTA_MaBmsgAddMsgContent(tBTA_MA_BMSG_CONTENT * p_content, char * p_text)
+{
+ tBTA_MA_BMSG_MESSAGE * p_message;
+
+ if ( p_content )
+ {
+ p_message = (tBTA_MA_BMSG_MESSAGE *)bta_ma_bmsg_alloc(sizeof(tBTA_MA_BMSG_MESSAGE));
+ if ( p_message )
+ {
+ memset(p_message, 0, sizeof(tBTA_MA_BMSG_MESSAGE));
+
+ p_message->p_text = (char *)bta_ma_bmsg_alloc(strlen(p_text)+1);
+
+ if ( p_message->p_text )
+ {
+ BCM_STRNCPY_S(p_message->p_text, strlen(p_text)+1, p_text, strlen(p_text)+1);
+
+ /* if the content already points to a message,
+ ** then we tack it on the end of the message list.
+ */
+ if ( p_content->p_message && p_content->p_last )
+ p_content->p_last->p_next = p_message;
+ else
+ p_content->p_message = p_message;
+
+ /* keep track of the last message text we added */
+ p_content->p_last = p_message;
+ }
+ else
+ bta_ma_bmsg_free(p_message);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_MaBmsgGetMsgContent
+**
+** Description Get the first text string from the speicified message content.
+**
+** Parameters p_content - Pointer to a message content
+**
+** Returns Pointer to the first text string.
+** NULL if it has not been set.
+**
+*******************************************************************************/
+char * BTA_MaBmsgGetMsgContent(tBTA_MA_BMSG_CONTENT * p_content)
+{
+ char * p_text = NULL;
+ if ( p_content && p_content->p_message )
+ {
+ /* reset 'last' pointer for when 'get_next' is called. */
+ p_content->p_last = p_content->p_message;
+
+ p_text = p_content->p_message->p_text;
+ }
+
+ return( p_text );
+}
+/*******************************************************************************
+**
+** Function BTA_MaBmsgGetMsgContent
+**
+** Description Get the next text string from the speicified message content.
+**
+** Parameters p_content - Pointer to a message content
+**
+** Returns Pointer to the next text string.
+** NULL if it has not been set.
+**
+*******************************************************************************/
+char * BTA_MaBmsgGetNextMsgContent(tBTA_MA_BMSG_CONTENT * p_content)
+{
+ char * p_text = NULL;
+
+ if ( p_content && p_content->p_last )
+ {
+ /* advance pointer */
+ p_content->p_last = ( tBTA_MA_BMSG_MESSAGE *)p_content->p_last->p_next;
+
+ if ( p_content->p_last )
+ p_text = p_content->p_last->p_text;
+ }
+
+ return( p_text );
+}
+
+
+/*******************************************************************************
+**
+** Function BTA_MaBmsgGetNextVcard
+**
+** Description Get the next vCard from the speicified vCard.
+**
+** Parameters p_vcard - Pointer to a vCard
+**
+** Returns Pointer to the next vCard.
+** NULL if it has not been set.
+**
+*******************************************************************************/
+tBTA_MA_BMSG_VCARD * BTA_MaBmsgGetNextVcard(tBTA_MA_BMSG_VCARD * p_vcard)
+{
+ return(p_vcard ? (tBTA_MA_BMSG_VCARD *)p_vcard->p_next : NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function BTA_MaBmsgSetVcardVersion
+**
+** Description Set the vCard version for the speicified vCard.
+**
+** Parameters p_vcard - Pointer to a vCard
+** version - vcard version
+**
+** Returns None
+**
+*******************************************************************************/
+void BTA_MaBmsgSetVcardVersion(tBTA_MA_BMSG_VCARD * p_vcard, tBTA_MA_VCARD_VERSION version)
+{
+ if ( p_vcard )
+ p_vcard->version = version;
+}
+/*******************************************************************************
+**
+** Function BTA_MaBmsgGetVcardVersion
+**
+** Description Get the vCard version from the speicified vCard.
+**
+** Parameters p_vcard - Pointer to a vCard
+**
+** Returns vCard version number
+**
+*******************************************************************************/
+tBTA_MA_VCARD_VERSION BTA_MaBmsgGetVcardVersion(tBTA_MA_BMSG_VCARD * p_vcard)
+{
+ return(p_vcard ? p_vcard->version : 0);
+}
+/*******************************************************************************
+**
+** Function BTA_MaBmsgAddVcardProp
+**
+** Description Add a property to the speicified vCard.
+**
+** Parameters p_vcard - Pointer to a vCard
+** prop - Indicate which vCard peoperty
+** p_value - Pointer to the vCard property value
+** p_param - Pointer to the vCard property parameter
+**
+** Returns Pointer to the vCard peoperty
+**
+*******************************************************************************/
+tBTA_MA_VCARD_PROPERTY * BTA_MaBmsgAddVcardProp(tBTA_MA_BMSG_VCARD *p_vcard, tBTA_MA_VCARD_PROP prop, char *p_value, char *p_param)
+{
+ tBTA_MA_VCARD_PROPERTY * p_prop = NULL;
+ tBTA_MA_VCARD_PROPERTY * p_last_prop = NULL;
+
+ if ( p_vcard && prop < BTA_MA_VCARD_PROP_MAX )
+ {
+ p_prop = (tBTA_MA_VCARD_PROPERTY *) bta_ma_bmsg_alloc(sizeof(tBTA_MA_VCARD_PROPERTY));
+ if ( p_prop )
+ {
+ memset(p_prop, 0, sizeof(tBTA_MA_VCARD_PROPERTY));
+
+ /* Set the value (if given) */
+ if ( p_value )
+ {
+ p_prop->p_value = (char *)bta_ma_bmsg_alloc(strlen(p_value)+1);
+ if ( p_prop->p_value )
+ BCM_STRNCPY_S(p_prop->p_value, strlen(p_value)+1, p_value, strlen(p_value)+1);
+ }
+
+ /* Set the parameter (if given) */
+ if ( p_param )
+ {
+ p_prop->p_param = (char *)bta_ma_bmsg_alloc(strlen(p_param)+1);
+ if ( p_prop->p_param )
+ BCM_STRNCPY_S(p_prop->p_param, strlen(p_param)+1, p_param, strlen(p_param)+1);
+ }
+
+ /* There can be more than one of a property. So add this property to the end of the list. */
+ if ( p_vcard->p_prop[prop] == NULL )
+ p_vcard->p_prop[prop] = p_prop;
+ else
+ {
+ p_last_prop = p_vcard->p_prop[prop];
+ while ( p_last_prop->p_next )
+ p_last_prop = (tBTA_MA_VCARD_PROPERTY *)p_last_prop->p_next;
+
+ p_last_prop->p_next = p_prop;
+ }
+ }
+ }
+
+ return(p_prop);
+}
+/*******************************************************************************
+**
+** Function BTA_MaBmsgGetVcardProp
+**
+** Description Get the vCard property from the speicified vCard peoperty enum.
+**
+** Parameters p_vcard - Pointer to a vCard
+** prop - Indicate which vCard peoperty
+**
+** Returns Pointer to the vCard peoperty.
+** NULL if the vCard peoperty does not exist
+**
+*******************************************************************************/
+tBTA_MA_VCARD_PROPERTY * BTA_MaBmsgGetVcardProp(tBTA_MA_BMSG_VCARD * p_vcard, tBTA_MA_VCARD_PROP prop)
+{
+ return( p_vcard && prop < BTA_MA_VCARD_PROP_MAX ? p_vcard->p_prop[prop] : NULL);
+}
+/*******************************************************************************
+**
+** Function BTA_MaBmsgGetNextVcardProp
+**
+** Description Get the next vCard property from the speicified vCard peoperty.
+**
+** Parameters p_prop - Pointer to a vCard property
+**
+** Returns Pointer to the next vCard peoperty.
+** NULL if the next vCard peoperty does not exist
+**
+*******************************************************************************/
+tBTA_MA_VCARD_PROPERTY * BTA_MaBmsgGetNextVcardProp(tBTA_MA_VCARD_PROPERTY * p_prop)
+{
+ return(p_prop ? (tBTA_MA_VCARD_PROPERTY *)p_prop->p_next : NULL);
+}
+/*******************************************************************************
+**
+** Function BTA_MaBmsgGetVcardPropValue
+**
+** Description Get the vCard property value from the speicified vCard peoperty.
+**
+** Parameters p_prop - Pointer to a vCard property
+**
+** Returns Pointer to the vCard peoperty value.
+** NULL if the vCard peoperty value has not been set.
+**
+*******************************************************************************/
+char * BTA_MaBmsgGetVcardPropValue(tBTA_MA_VCARD_PROPERTY * p_prop)
+{
+ return(p_prop ? p_prop->p_value : NULL);
+}
+/*******************************************************************************
+**
+** Function BTA_MaBmsgGetVcardPropParam
+**
+** Description Get the vCard property parameter from the speicified vCard peoperty.
+**
+** Parameters p_prop - Pointer to a vCard property
+**
+** Returns Poiter to the vCard peoperty parameter.
+** NULL if the vCard peoperty parameter has not been set.
+**
+*******************************************************************************/
+char * BTA_MaBmsgGetVcardPropParam(tBTA_MA_VCARD_PROPERTY * p_prop)
+{
+ return(p_prop ? p_prop->p_param : NULL);
+}
+
+/*******************************************************************************
+**
+** Function BTA_MaBuildMapBmsgObj
+**
+** Description Builds a specification compliant bMessage object given a
+** generic bMessage internal structure.
+**
+** Parameters p_msg - pointer to bMessage object structure (input).
+** p_stream - Output stream.
+**
+** Returns BTA_MA_STATUS_OK if successful. BTA_MA_STATUS_FAIL if not.
+**
+*******************************************************************************/
+tBTA_MA_STATUS BTA_MaBuildMapBmsgObj(tBTA_MA_BMSG * p_msg,
+ tBTA_MA_STREAM * p_stream)
+{
+ tBTA_MA_STATUS status = BTA_MA_STATUS_FAIL;
+
+
+ if ( p_msg && p_stream )
+ {
+ bta_ma_stream_str(p_stream, "BEGIN:BMSG");
+ bta_ma_stream_str(p_stream, "\r\nVERSION:1.0");
+
+ /* Read Status */
+ bta_ma_stream_str(p_stream, "\r\nSTATUS:");
+ bta_ma_stream_str(p_stream, (BTA_MaBmsgGetReadSts(p_msg) ? "READ" : "UNREAD"));
+
+ /* Type */
+ bta_ma_stream_str(p_stream, "\r\nTYPE:");
+ bta_ma_stream_str(p_stream, bta_ma_msg_typ_to_string(BTA_MaBmsgGetMsgType(p_msg)));
+
+ /* Folder */
+ bta_ma_stream_str(p_stream, "\r\nFOLDER:");
+ bta_ma_stream_str(p_stream, BTA_MaBmsgGetFolder(p_msg));
+
+ /* Originator(s) */
+ bta_ma_stream_vcards(p_stream, BTA_MaBmsgGetOrigFromBmsg(p_msg));
+
+ /* Envelopes (nested) */
+ bta_ma_stream_envelopes(p_stream, BTA_MaBmsgGetEnv(p_msg));
+
+ bta_ma_stream_str(p_stream, "\r\nEND:BMSG\r\n");
+
+ /* if buffer overflowed then return failure */
+ status = bta_ma_stream_ok(p_stream)
+ ? BTA_MA_STATUS_OK
+ : BTA_MA_STATUS_FAIL;
+ }
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT1("BTA_MA_STATUS =%d (0-OK) BTA_MaBuildMapBmsgObj", status);
+#endif
+ return( status );
+}
+/*******************************************************************************
+**
+** Function bta_ma_parse_map_bmsg_obj
+**
+** Description Parses a bMessage object from a stream into a generic
+** bMessage internal structure.
+**
+** Parameters p_msg - pointer to bMessage object structure (output).
+** p_stream - Input stream.
+**
+** Returns BTA_MA_STATUS_OK if successful. BTA_MA_STATUS_FAIL if not.
+**
+*******************************************************************************/
+tBTA_MA_STATUS BTA_MaParseMapBmsgObj(tBTA_MA_BMSG * p_msg,
+ tBTA_MA_STREAM * p_stream)
+{
+ char sz[BTA_MA_MAX_SIZE];
+ UINT32 prop_mask = 0;
+ tBTA_MA_STATUS status = BTA_MA_STATUS_FAIL;
+ tBTA_MA_BMSG_VCARD * p_vcard = NULL;
+ tBTA_MA_BMSG_ENVELOPE * p_envelope = NULL;
+ tBTA_MA_MSG_TYPE msg_type = 0;
+
+ APPL_TRACE_EVENT0("BTA_MaParseMapBmsgObj");
+ if ( p_msg && p_stream )
+ {
+ /* Must start with BEGIN:MSG */
+ if ( bta_ma_get_tag(p_stream, sz, BTA_MA_MAX_SIZE)
+ && (strcmp(sz, "BEGIN") == 0)
+ && bta_ma_get_value(p_stream, sz, BTA_MA_MAX_SIZE)
+ && (strcmp(sz, "BMSG") == 0) )
+ {
+ while ( bta_ma_get_tag(p_stream, sz, BTA_MA_MAX_SIZE) )
+ {
+ /* VERSION */
+ if ( strcmp(sz, "VERSION") == 0 )
+ {
+ if ( bta_ma_get_value(p_stream, sz, BTA_MA_MAX_SIZE)
+ && (strcmp(sz, "1.0") == 0) )
+ {
+ prop_mask |= BTA_MA_PROP_VERSION;
+ }
+ else
+ break; /* incorrect VERSION */
+ }
+ else if ( strcmp(sz, "STATUS") == 0 )
+ {
+ bta_ma_get_value(p_stream, sz, BTA_MA_MAX_SIZE);
+ BTA_MaBmsgSetReadSts(p_msg, (BOOLEAN) (strcmp(sz, "READ") == 0));
+ }
+ else if ( strcmp(sz, "TYPE") == 0 )
+ {
+ bta_ma_get_value(p_stream, sz, BTA_MA_MAX_SIZE);
+ if ( bta_ma_str_to_msg_typ(sz, &msg_type) )
+ BTA_MaBmsgSetMsgType(p_msg, msg_type);
+
+ }
+ else if ( strcmp(sz, "FOLDER") == 0 )
+ {
+ bta_ma_get_value(p_stream, sz, BTA_MA_MAX_SIZE);
+ BTA_MaBmsgSetFolder(p_msg, sz);
+ }
+ else if ( strcmp(sz, "BEGIN") == 0 )
+ {
+ bta_ma_get_value(p_stream, sz, BTA_MA_MAX_SIZE);
+
+ if ( strcmp(sz, "VCARD") == 0 )
+ {
+ p_vcard = BTA_MaBmsgAddOrigToBmsg(p_msg);
+ bta_ma_parse_vcard(p_vcard, p_stream);
+ }
+ else if ( strcmp(sz, "BENV") == 0 )
+ {
+ p_envelope = BTA_MaBmsgAddEnvToBmsg(p_msg);
+ bta_ma_parse_envelope(p_envelope, p_stream);
+ }
+ else
+ {
+ APPL_TRACE_ERROR1("bta_ma_parse_map_bmsg_obj - Invalid BEGIN: '%s'", sz);
+ }
+ }
+ else if ( strcmp(sz, "END") == 0 )
+ {
+ bta_ma_get_value(p_stream, sz, BTA_MA_MAX_SIZE);
+ status = BTA_MA_STATUS_OK;
+ break;
+ }
+ else
+ {
+ APPL_TRACE_ERROR1("bta_ma_parse_map_bmsg_obj - Invalid tag: '%s'", sz);
+ }
+ }
+ }
+ }
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT1("BTA_MaParseMapBmsgObj status=%d(0-OK)", status);
+#endif
+ return( status );
+}
+
+/*******************************************************************************
+**
+** Function BTA_MaInitMemStream
+**
+** Description Initializes a memory based stream
+**
+** Parameters p_stream - pointer to stream information.
+** p_buffer - pointer to buffer to be manipulated.
+** size - size of buffer pointed to by 'p_buffer'.
+**
+** Returns TRUE if stream is opened.
+**
+*******************************************************************************/
+BOOLEAN BTA_MaInitMemStream(tBTA_MA_STREAM * p_stream,
+ UINT8 * p_buffer,
+ UINT16 size)
+{
+ if ( !p_stream )
+ return(FALSE);
+
+ memset(p_stream, 0, sizeof(tBTA_MA_STREAM));
+
+ p_stream->type = STRM_TYPE_MEMORY;
+ p_stream->u.mem.p_buffer = p_stream->u.mem.p_next = p_buffer;
+ p_stream->u.mem.size = size;
+
+ return(TRUE);
+}
+
+/*******************************************************************************
+**
+** Function BTA_MaInitFileStream
+**
+** Description Initializes a file stream
+**
+** Parameters p_stream - pointer to stream information.
+** p_path - Full pathname to file to use.
+** oflags - permissions and mode
+**
+** Returns TRUE if file stream is opened.
+**
+*******************************************************************************/
+BOOLEAN BTA_MaInitFileStream(tBTA_MA_STREAM * p_stream,
+ const char *p_path,
+ int oflags)
+{
+ if ( !p_stream )
+ {
+ APPL_TRACE_ERROR0("Invalid stream pointer");
+ return(FALSE);
+ }
+
+ memset(p_stream, 0, sizeof(tBTA_MA_STREAM));
+
+ p_stream->type = STRM_TYPE_FILE;
+
+ p_stream->u.file.fd = bta_ma_co_open(p_path, oflags);
+
+ if ( p_stream->u.file.fd == -1 )
+ {
+ APPL_TRACE_ERROR0("Unable to open file ");
+ p_stream->status = STRM_ERROR_FILE;
+ }
+
+ /* return TRUE if stream is OK */
+ return(p_stream->status == STRM_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function BTA_MaCloseStream
+**
+** Description Close a stream (do any necessary clean-up).
+**
+** Parameters p_stream - pointer to stream information.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_MaCloseStream(tBTA_MA_STREAM * p_stream)
+{
+ if ( p_stream->type == STRM_TYPE_FILE )
+ {
+ bta_ma_co_close(p_stream->u.file.fd);
+ p_stream->u.file.fd = BTA_FS_INVALID_FD;
+ }
+}
+#endif /* BTA_MSE_INCLUDED */
diff --git a/bta/ma/bta_ma_util.c b/bta/ma/bta_ma_util.c
new file mode 100644
index 0000000..6544e6a
--- /dev/null
+++ b/bta/ma/bta_ma_util.c
@@ -0,0 +1,1750 @@
+/*****************************************************************************
+**
+** Name: bta_ma_util.c
+**
+** Description: This is the implementation file for the Message Access
+** Profile (MAP) utility functions.
+**
+** Copyright (c) 2009, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+
+#if defined(BTA_MSE_INCLUDED) && (BTA_MSE_INCLUDED)
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "bta_ma_api.h"
+#include "bta_ma_util.h"
+
+/*
+** Static constant data declarations
+*/
+/* Charset */static const char * bmsg_body_charset[] =
+{
+ "native", /* BMSG_CHARSET_NATIVE (native) */
+ "UTF-8" /* BMSG_CHARSET_UTF-8 (UTF-8) */
+};
+
+static const int num_bmsg_body_charset = sizeof(bmsg_body_charset) / sizeof(char*);
+
+
+/* vCard property names (the order is dicated by the tBTA_MA_BMSG_VCARD_PROP enumeration in bmsg_cnt.h) */
+static const char * vcard_prop_name[] =
+{
+ "N", /* VCARD_PROP_N */
+ "FN", /* VCARD_PROP_FN */
+ "TEL", /* VCARD_PROP_TEL */
+ "EMAIL" /* VCARD_PROP_EMAIL */
+};
+
+/* bMessage encoding names (the order is dictated by the tBTA_MA_BMSG_ENCODING enumeration in bmsg_cnt.h) */
+static const char * bmsg_body_encoding[] =
+{
+ "8BIT", /* BMSG_ENC_8BIT (8-Bit-Clean encoding) */
+ "G-7BIT", /* BMSG_ENC_G7BIT (GSM 7 bit Default Alphabet) */
+ "G-7BITEXT", /* BMSG_ENC_G7BITEXT (GSM 7 bit Alphabet with national language extension) */
+ "G-UCS2" , /* BMSG_ENC_GUCS2 */
+ "G-8BIT", /* BMSG_ENC_G8BIT */
+ "C-8BIT", /* BMSG_ENC_C8BIT (Octet, unspecified) */
+ "C-EPM", /* BMSG_ENC_CEPM (Extended Protocol Message) */
+ "C-7ASCII", /* BMSG_ENC_C7ASCII (7-bit ASCII) */
+ "C-IA5", /* BMSG_ENC_CIA5 (IA5) */
+ "C-UNICODE", /* BMSG_ENC_CUNICODE (UNICODE) */
+ "C-SJIS", /* BMSG_ENC_CSJIS (Shift-JIS) */
+ "C-KOREAN", /* BMSG_ENC_CKOREAN (Korean) */
+ "C-LATINHEB", /* BMSG_ENC_CLATINHEB (Latin/Hebrew) */
+ "C-LATIN" /* BMSG_ENC_CLATIN (Latin) */
+};
+
+static const int num_bmsg_body_encoding = sizeof(bmsg_body_encoding) / sizeof(char*);
+
+static const char * bmsg_body_language[] =
+{
+ "", /* BMSG_LANG_UNSPECIFIED (not provided in bBody */
+ "UNKNOWN", /* BMSG_LANG_UNKNOWN */
+ "SPANISH", /* BMSG_LANG_SPANISH */
+ "TURKISH", /* BMSG_LANG_TURKISH */
+ "PORTUGUESE", /* BMSG_LANG_PORTUGUESE */
+ "ENGLISH", /* BMSG_LANG_ENGLISH */
+ "FRENCH", /* BMSG_LANG_FRENCH */
+ "JAPANESE", /* BMSG_LANG_JAPANESE */
+ "KOREAN", /* BMSG_LANG_KOREAN */
+ "CHINESE", /* BMSG_LANG_CHINESE */
+ "HEBREW" /* BMSG_LANG_HEBREW */
+};
+
+static const int num_bmsg_body_language = sizeof(bmsg_body_language) / sizeof(char*);
+
+#include "bta_ma_co.h"
+
+#define BTA_MSE_NOTIF_TYPE_NEW_MSG_STR "NewMessage"
+#define BTA_MSE_NOTIF_TYPE_DELIVERY_SUCCESS_STR "DeliverySuccess"
+#define BTA_MSE_NOTIF_TYPE_SENDING_SUCCESS_STR "SendingSuccess"
+#define BTA_MSE_NOTIF_TYPE_DELIVERY_FAILURE_STR "DeliveryFailure"
+#define BTA_MSE_NOTIF_TYPE_SENDING_FAILURE_STR "SendingFailure"
+#define BTA_MSE_NOTIF_TYPE_MEMORY_FULL_STR "MemoryFull"
+#define BTA_MSE_NOTIF_TYPE_MEMORY_AVAILABLE_STR "MemoryAvailable"
+#define BTA_MSE_NOTIF_TYPE_MESSAGE_DELETED_STR "MessageDeleted"
+#define BTA_MSE_NOTIF_TYPE_MESSAGE_SHIFT_STR "MessageShift"
+
+#define BTA_MSE_MSG_TYPE_EMAIL "EMAIL"
+#define BTA_MSE_MSG_TYPE_SMS_GSM "SMS_GSM"
+#define BTA_MSE_MSG_TYPE_SMS_CDMA "SMS_CDMA"
+#define BTA_MSE_MSG_TYPE_MMS "MMS"
+
+#define BTA_MSE_RCV_STATUS_COMPLETE "complete"
+#define BTA_MSE_RCV_STATUS_FRACTIONED "fractioned"
+#define BTA_MSE_RCV_STATUS_NOTIFICATION "notification"
+
+#define BTA_MSE_BOOLEAN_YES "yes"
+#define BTA_MSE_BOOLEAN_NO "no"
+
+/*******************************************************************************
+**
+** Function bta_ma_evt_typ_to_string
+**
+** Description Utility function to return a pointer to a string holding
+** the notifiction "type" for the MAP-Event-Report object.
+**
+** Parameters notif_type - Notification type
+**
+** Returns Pointer to static string representing notification type.
+**
+*******************************************************************************/
+
+const char * bta_ma_evt_typ_to_string(tBTA_MSE_NOTIF_TYPE notif_type)
+{
+ switch (notif_type)
+ {
+ case BTA_MSE_NOTIF_TYPE_NEW_MSG:
+ return(BTA_MSE_NOTIF_TYPE_NEW_MSG_STR);
+ case BTA_MSE_NOTIF_TYPE_DELIVERY_SUCCESS:
+ return(BTA_MSE_NOTIF_TYPE_DELIVERY_SUCCESS_STR);
+ case BTA_MSE_NOTIF_TYPE_SENDING_SUCCESS:
+ return(BTA_MSE_NOTIF_TYPE_SENDING_SUCCESS_STR);
+ case BTA_MSE_NOTIF_TYPE_DELIVERY_FAILURE:
+ return(BTA_MSE_NOTIF_TYPE_DELIVERY_FAILURE_STR);
+ case BTA_MSE_NOTIF_TYPE_SENDING_FAILURE:
+ return(BTA_MSE_NOTIF_TYPE_SENDING_FAILURE_STR);
+ case BTA_MSE_NOTIF_TYPE_MEMORY_FULL:
+ return(BTA_MSE_NOTIF_TYPE_MEMORY_FULL_STR);
+ case BTA_MSE_NOTIF_TYPE_MEMORY_AVAILABLE:
+ return(BTA_MSE_NOTIF_TYPE_MEMORY_AVAILABLE_STR);
+ case BTA_MSE_NOTIF_TYPE_MESSAGE_DELETED:
+ return(BTA_MSE_NOTIF_TYPE_MESSAGE_DELETED_STR);
+ case BTA_MSE_NOTIF_TYPE_MESSAGE_SHIFT:
+ return(BTA_MSE_NOTIF_TYPE_MESSAGE_SHIFT_STR);
+ }
+
+ return NULL;
+}
+
+/*******************************************************************************
+**
+** Function bta_ma_msg_typ_to_string
+**
+** Description Utility function to return a pointer to a string holding
+** the "msg_type" for the MAP-Event-Report object or or the
+** the type for the MAP-msg-listing object
+**
+** Parameters msg_typ - Message type
+**
+** Returns Pointer to static string representing message type.
+**
+*******************************************************************************/
+
+const char * bta_ma_msg_typ_to_string(tBTA_MA_MSG_TYPE msg_typ)
+{
+ switch (msg_typ)
+ {
+ case BTA_MA_MSG_TYPE_EMAIL: return(BTA_MSE_MSG_TYPE_EMAIL);
+ case BTA_MA_MSG_TYPE_SMS_GSM: return(BTA_MSE_MSG_TYPE_SMS_GSM);
+ case BTA_MA_MSG_TYPE_SMS_CDMA: return(BTA_MSE_MSG_TYPE_SMS_CDMA);
+ case BTA_MA_MSG_TYPE_MMS: return(BTA_MSE_MSG_TYPE_MMS);
+ }
+
+ return NULL;
+}
+
+/*******************************************************************************
+**
+** Function bta_ma_rcv_status_to_string
+**
+** Description Utility function to return a pointer to a string holding
+** the "reception_status" for the MAP-msg-listing object
+**
+** Parameters rcv_status - Reception status
+**
+** Returns Pointer to static string representing message type.
+**
+*******************************************************************************/
+const char * bta_ma_rcv_status_to_string(tBTA_MSE_CO_RCV_STATUS rcv_status)
+{
+ switch (rcv_status)
+ {
+ case BTA_MSE_CO_RCV_STATUS_COMPLETE:
+ return(BTA_MSE_RCV_STATUS_COMPLETE);
+ case BTA_MSE_CO_RCV_STATUS_FRACTIONED:
+ return(BTA_MSE_RCV_STATUS_FRACTIONED);
+ case BTA_MSE_CO_RCV_STATUS_NOTIFICATION:
+ return(BTA_MSE_RCV_STATUS_NOTIFICATION);
+ }
+
+ return NULL;
+}
+
+/*******************************************************************************
+**
+** Function bta_ma_stream_str
+**
+** Description Input a string into the stream.
+**
+** Parameters p_stream - pointer to stream information.
+** p_str - pointer to string to be put in the buffer. Only the
+** string characters, and not the NULL, are put into the
+** buffer.
+**
+** Returns TRUE if the string was successfully added into the stream.
+**
+*******************************************************************************/
+BOOLEAN bta_ma_stream_str(tBTA_MA_STREAM * p_stream, const char * p_str)
+{
+ UINT16 buf_size;
+ UINT16 str_size;
+ UINT16 size = 0;
+
+ /* ensure stream and string are not NULL */
+ if ( !p_str || !p_stream )
+ return(FALSE);
+
+ /* get length of string */
+ str_size = strlen(p_str);
+
+ switch ( p_stream->type )
+ {
+ case STRM_TYPE_MEMORY:
+ /* ensure buffer is not full */
+ if ( p_stream->status == STRM_SUCCESS )
+ {
+ /* get amount of size left in buffer */
+ buf_size = p_stream->u.mem.size - bta_ma_stream_used_size(p_stream);
+
+ /* calculate the size to copy (the minimum of string and buffer size */
+ if ( str_size > buf_size )
+ {
+ size = buf_size;
+ p_stream->status = STRM_ERROR_OVERFLOW;
+ }
+ else
+ size = str_size;
+
+ /* copy the data and move the pointer */
+ memcpy(p_stream->u.mem.p_next, p_str, size);
+ p_stream->u.mem.p_next += size;
+ }
+ break;
+
+ case STRM_TYPE_FILE:
+ /* write string */
+ bta_ma_co_write(p_stream->u.file.fd, p_str, str_size);
+ break;
+ }
+
+ /* return TRUE if stream is OK */
+ return(p_stream->status == STRM_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function bta_ma_stream_buf
+**
+** Description Stream a buffer into the buffer.
+**
+** Parameters p_stream - pointer to stream information.
+** len - length of buffer
+** p_buf - pointer to buffer to stream.
+**
+** Returns TRUE if the buffer was large enough to hold the data.
+**
+*******************************************************************************/
+extern BOOLEAN bta_ma_stream_buf(tBTA_MA_STREAM * p_stream,
+ UINT16 len,
+ UINT8 * p_buf)
+{
+ UINT16 buf_size;
+ UINT16 size = 0;
+
+ /* ensure stream and buffer pointer are not NULL */
+ if ( !p_buf || !p_stream )
+ return(FALSE);
+
+ switch ( p_stream->type )
+ {
+ case STRM_TYPE_MEMORY:
+ /* ensure buffer is not full */
+ if ( p_stream->status == STRM_SUCCESS )
+ {
+ /* get amount of size left in buffer */
+ buf_size = p_stream->u.mem.size - bta_ma_stream_used_size(p_stream);
+
+ /* calculate the size to copy (the minimum of string and buffer size */
+ if ( len > buf_size )
+ {
+ size = buf_size;
+ p_stream->status = STRM_ERROR_OVERFLOW;
+ }
+ else
+ size = len;
+
+ /* copy the data and move the pointer */
+ memcpy(p_stream->u.mem.p_next, p_buf, len);
+ p_stream->u.mem.p_next += size;
+ }
+ break;
+ case STRM_TYPE_FILE:
+ /* write string */
+ bta_ma_co_write(p_stream->u.file.fd, p_buf, len);
+ break;
+ }
+
+ /* return TRUE if stream is OK */
+ return(p_stream->status == STRM_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function bta_ma_stream_boolean_yes_no
+**
+** Description Stream a yes/no string into the buffer.
+**
+** Parameters p_stream - pointer to stream information.
+** val - a boolean value to indicate yes or no
+**
+** Returns TRUE if the yes/no string was successfully added into
+** the stream.
+**
+*******************************************************************************/
+BOOLEAN bta_ma_stream_boolean_yes_no(tBTA_MA_STREAM * p_stream, BOOLEAN val)
+{
+ return bta_ma_stream_str(p_stream,
+ val == FALSE ? BTA_MSE_BOOLEAN_NO : BTA_MSE_BOOLEAN_YES);
+}
+
+/*******************************************************************************
+**
+** Function bta_ma_stream_value
+**
+** Description Stream an UINT32 value string into the buffer.
+**
+** Parameters p_stream - pointer to stream information.
+** val - a UINT32 value
+**
+** Returns TRUE if the buffer was large enough to hold the data.
+**
+*******************************************************************************/
+BOOLEAN bta_ma_stream_value(tBTA_MA_STREAM * p_stream, UINT32 val)
+{
+ char temp[50];
+
+ sprintf(temp, "%lu", val);
+ return bta_ma_stream_str(p_stream, temp);
+}
+
+/*******************************************************************************
+**
+** Function bta_ma_stream_handle
+**
+** Description Stream a message handle into the buffer.
+**
+** Parameters p_stream - pointer to stream information.
+** handle - handle to be put in the buffer.
+**
+** Returns TRUE if the buffer was large enough to hold the data.
+**
+*******************************************************************************/
+
+BOOLEAN bta_ma_stream_handle(tBTA_MA_STREAM * p_stream, tBTA_MA_MSG_HANDLE handle)
+{
+ char temp[5];
+ int x;
+ BOOLEAN value_yet = FALSE;
+
+ /* ensure buffer is not full */
+ if ( p_stream->status == STRM_SUCCESS )
+ {
+ for ( x=0; x < BTA_MA_HANDLE_SIZE; x++ )
+ {
+ /* Skip any leading 0's */
+ if ( (! value_yet) && (handle[x] == 0) )
+ continue;
+
+ value_yet = TRUE;
+
+ sprintf(temp, "%02x", handle[x]);
+
+ if ( bta_ma_stream_str(p_stream, temp) == FALSE )
+ return(FALSE);
+ }
+ }
+
+ /* return TRUE if stream is OK */
+ return(p_stream->status == STRM_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function bta_ma_stream_used_size
+**
+** Description Returns the used byte count.
+**
+** Parameters p_stream - pointer to stream information.
+**
+** Returns Number of bytes used in the buffer.
+**
+*******************************************************************************/
+
+UINT16 bta_ma_stream_used_size(tBTA_MA_STREAM * p_stream)
+{
+ return(p_stream->u.mem.p_next - p_stream->u.mem.p_buffer);
+}
+
+/*******************************************************************************
+**
+** Function bta_ma_stream_ok
+**
+** Description Determines if the stream is ok.
+**
+** Parameters p_stream - pointer to stream information.
+**
+** Returns TRUE if stream status is OK.
+**
+*******************************************************************************/
+
+BOOLEAN bta_ma_stream_ok(tBTA_MA_STREAM * p_stream)
+{
+ return(p_stream && p_stream->status == STRM_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function bta_ma_convert_hex_str_to_64bit_handle
+**
+** Description Convert a hex string to a 64 bit message handle in Big Endian
+** format
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ma_convert_hex_str_to_64bit_handle(char *p_hex_str, tBTA_MA_MSG_HANDLE handle)
+{
+ UINT32 ul1, ul2;
+ UINT8 *p;
+ char tmp[BTA_MA_32BIT_HEX_STR_SIZE];
+ UINT8 str_len;
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("bta_mse_convert_hex_str_to_64bit_handle");
+#endif
+
+ str_len = strlen(p_hex_str);
+ memset(handle,0,sizeof(tBTA_MA_MSG_HANDLE));
+
+ if (str_len >= 8)
+ {
+ /* most significant 4 bytes */
+ memcpy(tmp,p_hex_str,(str_len-8));
+ tmp[str_len-8]='\0';
+ ul1 = strtoul(tmp,0,16);
+ p=handle;
+ UINT32_TO_BE_STREAM(p, ul1);
+
+ /* least significant 4 bytes */
+ memcpy(tmp,&(p_hex_str[str_len-8]),8);
+ tmp[8]='\0';
+ ul2 = strtoul(tmp,0,16);
+ p=&handle[4];
+ UINT32_TO_BE_STREAM(p, ul2);
+ }
+ else
+ {
+ /* least significant 4 bytes */
+ ul1 = strtoul(p_hex_str,0,16);
+ p=&handle[4];
+ UINT32_TO_BE_STREAM(p, ul1);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ma_get_char
+**
+** Description Gets one character from the stream.
+**
+** Parameters p_stream - pointer to stream information.
+** p_char - pointer to where to receive the character.
+**
+** Returns TRUE if character was read OK.
+**
+*******************************************************************************/
+BOOLEAN bta_ma_get_char(tBTA_MA_STREAM * p_stream, char * p_char)
+{
+ BOOLEAN bStatus = FALSE;
+
+ if ( p_char )
+ {
+ *p_char = 0;
+
+ if ( p_stream )
+ {
+ switch ( p_stream->type )
+ {
+ case STRM_TYPE_MEMORY:
+ if ( (p_stream->u.mem.p_next-p_stream->u.mem.p_buffer) < p_stream->u.mem.size )
+ {
+ *p_char = *p_stream->u.mem.p_next;
+ p_stream->u.mem.p_next++;
+
+ bStatus = TRUE;
+ }
+ break;
+ case STRM_TYPE_FILE:
+ /* read character */
+ bStatus = bta_ma_co_read(p_stream->u.file.fd, (void *) p_char, 1) == 1;
+ break;
+ }
+ }
+ }
+
+ return( bStatus );
+}
+
+
+/*******************************************************************************
+**
+** Function bta_ma_get_tag
+**
+** Description Parses a tag from the stream. Basically this returns any text
+** before a ':' character, ignoring leading whitespace.
+**
+** Parameters p_stream - Input stream.
+** psz - buffer to receive the tag
+** max_size - size of the receiving buffer (including space
+** for the NULL character.
+**
+** Returns Size of tag, or 0 if there was an error.
+**
+*******************************************************************************/
+UINT16 bta_ma_get_tag(tBTA_MA_STREAM * p_stream, char * psz, UINT16 max_size)
+{
+ char c;
+ UINT16 count = 0;
+
+ /* handle bad arguments */
+ if ( p_stream && psz && (max_size > 0) )
+ {
+ /* reserve last byte for NULL terminator */
+ max_size--;
+
+ while ( bta_ma_get_char(p_stream, &c)
+ && (c != ':')
+ && (count < max_size) )
+ {
+ /* ignore leading whitespace */
+ if ( !count && ((c == ' ') || (c == '\t')) )
+ continue;
+
+ /* if we hit a CR, return 0 to indicate an error */
+ if ( c == '\r' )
+ return( 0 );
+
+ psz[count++] = c;
+ }
+
+ /* Either we hit a problem reading from the stream
+ ** or the buffer was not large enough
+ */
+ if ( c != ':' )
+ return( 0 );
+
+ /* terminate string */
+ psz[count] = '\0';
+ }
+
+ return( count );
+}
+
+/*******************************************************************************
+**
+** Function bta_ma_get_value
+**
+** Description Parses a value from the stream. Basically this any text
+** up to (but not including) the CR LF sequence.
+**
+** Parameters p_stream - Input stream.
+** psz - buffer to receive the value
+** max_size - size of the receiving buffer (including space
+** for the NULL character.
+**
+** Returns Size of value, or 0 if there was an error.
+**
+*******************************************************************************/
+UINT16 bta_ma_get_value(tBTA_MA_STREAM * p_stream, char * psz, UINT16 max_size)
+{
+ char c;
+ UINT16 count = 0;
+
+ /* handle bad arguments */
+ if ( p_stream && psz && (max_size > 0) )
+ {
+ /* reserve last byte for NULL terminator */
+ max_size--;
+
+ while ( bta_ma_get_char(p_stream, &c)
+ && (c != '\r')
+ && (count < max_size) )
+ {
+ psz[count++] = c;
+ }
+
+ /* Either we hit a problem reading from the stream
+ ** or the buffer was not large enough
+ */
+ if ( c != '\r' )
+ return( 0 );
+
+ /* burn the next character which must be LF */
+ if ( ! bta_ma_get_char(p_stream, &c) )
+ return( 0 );
+
+ /* terminate string */
+ psz[count] = '\0';
+ }
+
+ return( count );
+}
+
+/*******************************************************************************
+**
+** Function bta_ma_get_param
+**
+** Description Parses the parameter from the source string.
+**
+** Parameters p_src - source paramter string.
+** psz - buffer to receive the value
+**
+** Returns Size of param, or 0 if there was an error.
+**
+*******************************************************************************/
+UINT16 bta_ma_get_param(char *p_src, char *psz )
+{
+ char c;
+ UINT16 count = 0;
+ BOOLEAN first_semicolon_found=FALSE;
+
+ /* handle bad arguments */
+ if ( p_src && psz )
+ {
+ while ( (c = *p_src++) )
+ {
+
+ /* throw away the first ';' */
+ if ( !count && (c==';') )
+ {
+ first_semicolon_found = TRUE;
+ continue;
+ }
+
+ /* first char should be ';' otherwise return 0 */
+ if(!count && !first_semicolon_found && (c!=';'))
+ return (0);
+
+ /* if we hit a CR, return 0 to indicate an error */
+ if ( c == '\r' )
+ return( 0 );
+
+ psz[count++] = c;
+ }
+
+ if ( !count )
+ return( 0 );
+
+ /* terminate string */
+ psz[count] = '\0';
+ }
+
+ return( count );
+}
+
+
+
+
+/*******************************************************************************
+**
+** Function bta_ma_parse_vcard
+**
+** Description Parses a vCard from the stream into a generic tBTA_MA_BMSG_VCARD
+** structure.
+**
+** Parameters p_vcard - pointer to generic vCard structure.
+** p_stream - Input stream.
+**
+** Returns BTA_MA_STATUS_OK if successful. BTA_MA_STATUS_FAIL if not.
+**
+*******************************************************************************/
+tBTA_MA_STATUS bta_ma_parse_vcard(tBTA_MA_BMSG_VCARD * p_vcard,
+ tBTA_MA_STREAM * p_stream)
+{
+ char sz[BTA_MA_MAX_SIZE];
+ tBTA_MA_STATUS status = BTA_MA_STATUS_FAIL;
+ tBTA_MA_VCARD_VERSION version;
+ char * psztoken_tel = "TEL";
+// btla-specific ++
+ char * psztoken_name = "N;";
+// btla-specific --
+ char param[BTA_MA_MAX_SIZE];
+ char *p_src;
+ UINT16 len;
+
+
+ while ( bta_ma_get_tag(p_stream, sz, BTA_MA_MAX_SIZE) )
+ {
+ if ( strcmp(sz, "VERSION") == 0 )
+ {
+ bta_ma_get_value(p_stream, sz, BTA_MA_MAX_SIZE);
+ if ( strcmp(sz, "3.0") == 0 )
+ version = BTA_MA_VCARD_VERSION_30;
+ else if ( strcmp(sz, "2.1") == 0 )
+ version = BTA_MA_VCARD_VERSION_21;
+ else
+ {
+ APPL_TRACE_ERROR1("bta_ma_parse_vcard - Invalid vcard version: '%s'", sz);
+ break;
+ }
+
+ BTA_MaBmsgSetVcardVersion(p_vcard, version);
+ }
+ else if ( strcmp(sz, "N") == 0 )
+ {
+ bta_ma_get_value(p_stream, sz, BTA_MA_MAX_SIZE);
+ BTA_MaBmsgAddVcardProp(p_vcard, BTA_MA_VCARD_PROP_N, sz, NULL);
+// btla-specific ++
+ }
+ else if ( strstr(sz, psztoken_name) == sz )
+ {
+ p_src = sz + strlen(psztoken_name) - 1; // move to (first) semicolon, not past it
+ len = strlen(p_src);
+ if ( (len < BTA_MA_MAX_SIZE) && bta_ma_get_param(p_src, param))
+ {
+ bta_ma_get_value(p_stream, sz, BTA_MA_MAX_SIZE);
+ BTA_MaBmsgAddVcardProp(p_vcard, BTA_MA_VCARD_PROP_N, sz, param);
+ }
+// btla-specific --
+ }
+ else if ( strcmp(sz, "FN") == 0 )
+ {
+ bta_ma_get_value(p_stream, sz, BTA_MA_MAX_SIZE);
+ BTA_MaBmsgAddVcardProp(p_vcard, BTA_MA_VCARD_PROP_FN, sz, NULL);
+ }
+ else if ( strcmp(sz, psztoken_tel ) == 0 )
+ {
+ bta_ma_get_value(p_stream, sz, BTA_MA_MAX_SIZE);
+ BTA_MaBmsgAddVcardProp(p_vcard, BTA_MA_VCARD_PROP_TEL, sz, NULL);
+ }
+ else if ( strstr(sz, psztoken_tel) == sz )
+ {
+ p_src = sz + strlen(psztoken_tel);
+ len = strlen(p_src);
+ if ( (len < BTA_MA_MAX_SIZE) && bta_ma_get_param(p_src, param))
+ {
+ bta_ma_get_value(p_stream, sz, BTA_MA_MAX_SIZE);
+ BTA_MaBmsgAddVcardProp(p_vcard, BTA_MA_VCARD_PROP_TEL, sz, param);
+ }
+ }
+ else if ( strcmp(sz, "EMAIL") == 0 )
+ {
+ bta_ma_get_value(p_stream, sz, BTA_MA_MAX_SIZE);
+ BTA_MaBmsgAddVcardProp(p_vcard, BTA_MA_VCARD_PROP_EMAIL, sz, NULL);
+ }
+ else if ( strcmp(sz, "END") == 0 )
+ {
+ bta_ma_get_value(p_stream, sz, BTA_MA_MAX_SIZE);
+ status = BTA_MA_STATUS_OK;
+ break;
+ }
+ else
+ {
+ APPL_TRACE_ERROR1("bta_ma_parse_vcard - Invalid tag: '%s'", sz);
+ }
+ }
+
+ return( status );
+}
+
+/*******************************************************************************
+**
+** Function bta_ma_parse_content
+**
+** Description Parses a <bmessage-body-content> from the stream into a
+** generic tBTA_MA_BMSG_CONTENT structure. This will parse text until
+** we see "END:MSG" at the start of a line.
+**
+** Parameters p_content - pointer to generic content structure.
+** p_stream - Input stream.
+**
+** Returns BTA_MA_STATUS_OK if successful. BTA_MA_STATUS_FAIL if not.
+**
+*******************************************************************************/
+tBTA_MA_STATUS bta_ma_parse_content(tBTA_MA_BMSG_CONTENT * p_content,
+ tBTA_MA_STREAM * p_stream)
+{
+/* This constant defines the size of the work buffer used for parsing.
+** It MUST be larger than the 'END:MSG<CRLF>" string size. The larger
+** the buffer the more efficient this parser will be.
+*/
+#define BTA_MA_PARSE_BUF_SIZE BTA_MA_MAX_SIZE
+
+/* These constants define the four states the parser can be in.
+*/
+#define STATE_WS (0) /* checking for leading whitespace */
+#define STATE_END (1) /* checking for END:MSG */
+#define STATE_CR (2) /* checking for CRLF */
+#define STATE_TEXT (3) /* copying text */
+
+ static const char * END_MSG = "END:MSG\r\n";
+
+ char sz[BTA_MA_PARSE_BUF_SIZE+1];
+ char c;
+ int state = STATE_WS; /* start in the 'whitespace' state */
+ int idx_commit = 0;
+ int idx_trial = 0;
+ int idx_end = 0;
+ int x;
+
+ /* NOTES - There are 3 primary indices used during parsing:
+ **
+ ** 'idx_commit' these are characters that are commited to being
+ ** in the message text. We need to be able to save characters
+ ** (such as <CR><LF>, "END..", etc.) but not actually 'commit' them.
+ **
+ ** 'idx_trial' these are characters that we are saving on a trial
+ ** basis until we know what to do with them. For example, if
+ ** we get a sequence "<CR>+<LF>+E+N", we don't want to commit
+ ** them until we know it is not "END:MSG<CR><LF>".
+ **
+ ** 'idx_end' is used to index through the "END:MSG<CR><LF> string.
+ */
+
+ /* Handle bad arguments */
+ if ( p_stream && p_content )
+ {
+ /* Get one character from the stream */
+ while ( bta_ma_get_char(p_stream, &c) )
+ {
+ switch (state)
+ {
+ case STATE_WS:
+ /* totally ignore leading whitespace */
+ if ( (c == ' ') || (c == '\t') )
+ continue;
+
+ /* Otherwise intentionaly fall through after resetting the
+ ** 'end' index so we start comparing from the beginning.
+ */
+ idx_end = 0;
+
+ case STATE_END:
+ /* Is the character in the "END:MSG<CR><LF> sequence? */
+ if ( c == END_MSG[idx_end] )
+ {
+ /* Yes. Did we get to the end of "END:MSG<cr><lf>"? */
+ if ( ! END_MSG[++idx_end] )
+ {
+ /* Yes. Commit any characters and get out. */
+ if ( idx_commit )
+ {
+ sz[idx_commit] = '\0';
+ BTA_MaBmsgAddMsgContent(p_content, sz);
+ }
+
+ return( BTA_MA_STATUS_OK );
+ }
+
+ state = STATE_END;
+ break;
+ }
+ /* If we fell through from the whitespace state
+ ** then we should commit all chars at this point.
+ ** It handles the case where we get consecutive CRLF.
+ */
+ if ( state == STATE_WS )
+ idx_commit = idx_trial;
+
+ /* And intentionally fall through */
+
+ case STATE_CR:
+ /* We got <CR>, is this <LF>? */
+ if ( c == '\n' )
+ {
+ /* Now look for any whitespace */
+ state = STATE_WS;
+ break;
+ }
+
+ /* otherwise intentionally fall through */
+
+ case STATE_TEXT:
+ /* is a CR? */
+ if ( c == '\r' )
+ state = STATE_CR; /* Look for <LF> */
+ else
+ state = STATE_TEXT; /* Copy the text */
+ break;
+ }
+
+ /* All (non-whitespace) characters are copied to
+ ** the buffer as 'trial' characters possibly
+ ** committed later.
+ */
+ sz[idx_trial++] = c;
+
+ /* If we are in the text copy state, then
+ ** commit all characters to this point.
+ */
+ if ( state == STATE_TEXT )
+ idx_commit = idx_trial;
+
+ /* The buffer is full. Commit the good characters
+ ** to the message content, and rearrange the rest
+ ** of the text to make room for more.
+ */
+ if ( idx_trial == BTA_MA_PARSE_BUF_SIZE )
+ {
+ /* Do we have characters to commit?
+ ** If we don't we are in trouble.
+ */
+ if ( idx_commit )
+ {
+ /* Save the last character so we can put a NULL there. */
+ c = sz[idx_commit];
+ sz[idx_commit] = '\0';
+ BTA_MaBmsgAddMsgContent(p_content, sz);
+
+ /* Do we need to rearrange uncommited text? */
+ if ( idx_commit != idx_trial )
+ {
+ /* Restore character */
+ sz[idx_commit] = c;
+
+ /* Copy the 'trial' characters to the beginning of buffer */
+ idx_trial -= idx_commit;
+ for ( x=0; x < idx_trial; x++)
+ sz[x] = sz[x+idx_commit];
+ idx_commit = 0;
+ }
+ else
+ {
+ idx_trial = idx_commit = 0;
+ }
+ }
+ else
+ {
+ /* ERROR - no space to shuffle things around */
+ APPL_TRACE_ERROR0("bta_ma_parse_content - work buffer too small");
+ break;
+ }
+ }
+ }
+ }
+
+ return( BTA_MA_STATUS_FAIL );
+}
+
+/*******************************************************************************
+**
+** Function bta_ma_parse_body
+**
+** Description Parses a <bmessage-content> (BBODY) from the stream into a
+** generic tBTA_MA_BMSG_BODY structure. This will parse text until
+** we see "END:BODY" at the start of a line.
+**
+** Parameters p_body - pointer to generic content body structure.
+** p_stream - Input stream.
+**
+** Returns BTA_MA_STATUS_OK if successful. BTA_MA_STATUS_FAIL if not.
+**
+*******************************************************************************/
+tBTA_MA_STATUS bta_ma_parse_body(tBTA_MA_BMSG_BODY * p_body,
+ tBTA_MA_STREAM * p_stream)
+{
+ char sz[BTA_MA_MAX_SIZE];
+ tBTA_MA_STATUS status = BTA_MA_STATUS_FAIL;
+ tBTA_MA_BMSG_CONTENT *p_content = NULL;
+ tBTA_MA_BMSG_ENCODING encoding;
+ tBTA_MA_BMSG_LANGUAGE language;
+ tBTA_MA_CHARSET charset;
+
+ while ( bta_ma_get_tag(p_stream, sz, BTA_MA_MAX_SIZE) )
+ {
+ if ( strcmp(sz, "PARTID") == 0 )
+ {
+ bta_ma_get_value(p_stream, sz, BTA_MA_MAX_SIZE);
+ BTA_MaBmsgSetBodyPartid(p_body, (UINT16) atoi(sz));
+ }
+ else if ( strcmp(sz, "ENCODING") == 0 )
+ {
+ bta_ma_get_value(p_stream, sz, BTA_MA_MAX_SIZE);
+ if ( bta_ma_str_to_encoding(sz, &encoding) )
+ BTA_MaBmsgSetBodyEncoding(p_body, encoding);
+ else
+ APPL_TRACE_ERROR1("bta_ma_parse_body - Invalid ENCODING: '%s'", sz);
+ }
+ else if ( strcmp(sz, "CHARSET") == 0 )
+ {
+ bta_ma_get_value(p_stream, sz, BTA_MA_MAX_SIZE);
+ if ( bta_ma_str_to_charset(sz, &charset))
+ BTA_MaBmsgSetBodyCharset(p_body, charset);
+ else
+ APPL_TRACE_ERROR1("bta_ma_parse_body - invalid CHARSET: '%s'", sz);
+ }
+ else if ( strcmp(sz, "LANGUAGE") == 0 )
+ {
+ bta_ma_get_value(p_stream, sz, BTA_MA_MAX_SIZE);
+ if ( bta_ma_str_to_language(sz, &language) )
+ BTA_MaBmsgSetBodyLanguage(p_body, language);
+ else
+ APPL_TRACE_ERROR1("bta_ma_parse_body - Invalid LANGUAGE: '%s'", sz);
+ }
+ else if ( strcmp(sz, "LENGTH") == 0 )
+ {
+ bta_ma_get_value(p_stream, sz, BTA_MA_MAX_SIZE);
+ /* we don't really care about the length */
+ }
+ else if ( strcmp(sz, "BEGIN") == 0 )
+ {
+ bta_ma_get_value(p_stream, sz, BTA_MA_MAX_SIZE);
+
+ if ( strcmp(sz, "MSG") == 0 )
+ {
+ p_content = BTA_MaBmsgAddContentToBody(p_body);
+ bta_ma_parse_content(p_content, p_stream);
+ }
+ else
+ {
+ APPL_TRACE_ERROR1("bta_ma_parse_body - Invalid BEGIN: '%s'", sz);
+ }
+ }
+ else if ( strcmp(sz, "END") == 0 )
+ {
+ bta_ma_get_value(p_stream, sz, BTA_MA_MAX_SIZE);
+ status = BTA_MA_STATUS_OK;
+ break;
+ }
+ else
+ {
+ APPL_TRACE_ERROR1("bta_ma_parse_body - Invalid tag: '%s'", sz);
+ }
+ }
+
+ return( status );
+}
+
+/*******************************************************************************
+**
+** Function bta_ma_parse_envelope
+**
+** Description Parses a <bmessage-envelope> from the stream into a
+** generic tBTA_MA_BMSG_ENVELOPE structure. This will parse text
+** until we see "END:BENV" at the start of a line.
+**
+** Parameters p_envelope - pointer to generic envelope structure.
+** p_stream - Input stream.
+**
+** Returns BTA_MA_STATUS_OK if successful. BTA_MA_STATUS_FAIL if not.
+**
+*******************************************************************************/
+tBTA_MA_STATUS bta_ma_parse_envelope(tBTA_MA_BMSG_ENVELOPE * p_envelope,
+ tBTA_MA_STREAM * p_stream)
+{
+ char sz[BTA_MA_MAX_SIZE];
+ tBTA_MA_STATUS status = BTA_MA_STATUS_FAIL;
+ tBTA_MA_BMSG_VCARD * p_vcard = NULL;
+ tBTA_MA_BMSG_ENVELOPE * p_new_envelope = NULL;
+ tBTA_MA_BMSG_BODY * p_body = NULL;
+
+ while ( bta_ma_get_tag(p_stream, sz, BTA_MA_MAX_SIZE) )
+ {
+ if ( strcmp(sz, "BEGIN") == 0 )
+ {
+ bta_ma_get_value(p_stream, sz, BTA_MA_MAX_SIZE);
+
+ if ( strcmp(sz, "VCARD") == 0 )
+ {
+ p_vcard = BTA_MaBmsgAddRecipToEnv(p_envelope);
+ bta_ma_parse_vcard(p_vcard, p_stream);
+ }
+ else if ( strcmp(sz, "BENV") == 0 )
+ {
+ p_new_envelope = BTA_MaBmsgAddEnvToEnv(p_envelope);
+ bta_ma_parse_envelope(p_new_envelope, p_stream);
+ }
+ else if ( strcmp(sz, "BBODY") == 0 )
+ {
+ p_body = BTA_MaBmsgAddBodyToEnv(p_envelope);
+ bta_ma_parse_body(p_body, p_stream);
+ }
+ else
+ {
+ APPL_TRACE_ERROR1("bta_ma_parse_envelope - Invalid BEGIN: '%s'", sz);
+ }
+
+ }
+ else if ( strcmp(sz, "END") == 0 )
+ {
+ bta_ma_get_value(p_stream, sz, BTA_MA_MAX_SIZE);
+ status = BTA_MA_STATUS_OK;
+ break;
+ }
+ else
+ {
+ APPL_TRACE_ERROR1("bta_ma_parse_envelope - Invalid tag: '%s'", sz);
+ }
+ }
+
+ return( status );
+}
+
+/*******************************************************************************
+**
+** Function bta_ma_stream_vcards
+**
+** Description Builds vCards into a stream.
+**
+** Parameters p_stream - Output stream.
+** p_vcard - pointer to single vCard that may be linked to
+** additional vCards.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ma_stream_vcards(tBTA_MA_STREAM * p_stream,
+ tBTA_MA_BMSG_VCARD * p_vcard)
+{
+ int x;
+
+ /* vCards are formatted one after another */
+ while ( p_stream && p_vcard )
+ {
+ bta_ma_stream_str(p_stream, "\r\nBEGIN:VCARD");
+
+ /* version */
+ bta_ma_stream_str(p_stream, "\r\nVERSION:");
+ bta_ma_stream_str(p_stream,
+ p_vcard->version == BTA_MA_VCARD_VERSION_21 ? "2.1" : "3.0");
+
+ /* vcard properties */
+ for (x=0; x < BTA_MA_VCARD_PROP_MAX; x++)
+ bta_ma_stream_vcard_prop(p_stream, p_vcard,(tBTA_MA_VCARD_PROP) x);
+
+ bta_ma_stream_str(p_stream, "\r\nEND:VCARD");
+
+ /* Get the next vCard and repeat */
+ p_vcard = BTA_MaBmsgGetNextVcard(p_vcard);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ma_stream_vcard_prop
+**
+** Description Builds a property and values into a stream. This will
+** build all of the property/values for one property (i.e.
+** can be multiple EMAIL propeties set). It will only
+** format the property if it has a value (except the N/name
+** if a 2.1 vCard and FN/fullname property of a 3.0 vCard
+** will always be output).
+**
+** Parameters p_stream - Output stream.
+** p_vcard - pointer to vCard.
+** prop - property.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ma_stream_vcard_prop(tBTA_MA_STREAM * p_stream,
+ tBTA_MA_BMSG_VCARD * p_vcard,
+ tBTA_MA_VCARD_PROP prop)
+{
+ tBTA_MA_VCARD_PROPERTY * p_prop;
+ tBTA_MA_VCARD_VERSION version;
+ char * p_param;
+ char * p_value;
+
+ if ( p_vcard && prop < BTA_MA_VCARD_PROP_MAX )
+ {
+ p_prop = BTA_MaBmsgGetVcardProp(p_vcard, prop);
+
+ do
+ {
+ p_param = BTA_MaBmsgGetVcardPropParam(p_prop);
+ p_value = BTA_MaBmsgGetVcardPropValue(p_prop);
+ version = BTA_MaBmsgGetVcardVersion(p_vcard);
+
+ if ( (p_value && strlen(p_value))
+ || ((version == BTA_MA_VCARD_VERSION_21) && (prop == BTA_MA_VCARD_PROP_N))
+ || ((version == BTA_MA_VCARD_VERSION_30) && (prop <= BTA_MA_VCARD_PROP_FN)) )
+ {
+ /* property name */
+ bta_ma_stream_str(p_stream, "\r\n");
+ bta_ma_stream_str(p_stream, vcard_prop_name[prop]);
+
+
+ /* property parameter */
+ if ( p_param )
+ {
+ bta_ma_stream_str(p_stream, ";");
+ bta_ma_stream_str(p_stream, p_param);
+ }
+
+ /* property value */
+ bta_ma_stream_str(p_stream, ":");
+ bta_ma_stream_str(p_stream, p_value);
+ }
+
+ /* There may be multiple instances of a property (e.g. 2 TEL numbers */
+ p_prop = BTA_MaBmsgGetNextVcardProp(p_prop);
+
+ } while ( p_prop );
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ma_stream_envelopes
+**
+** Description Builds a envelope <bmessage-envelope> (or series of
+** envelopes) into a stream.
+**
+** Parameters p_stream - Output stream.
+** p_envelope - pointer to envelope structure.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ma_stream_envelopes(tBTA_MA_STREAM * p_stream,
+ tBTA_MA_BMSG_ENVELOPE * p_envelope)
+{
+ tBTA_MA_BMSG_BODY * p_body;
+
+ if ( p_stream && p_envelope )
+ {
+ bta_ma_stream_str(p_stream, "\r\nBEGIN:BENV");
+
+ /* Recipients */
+ bta_ma_stream_vcards(p_stream, BTA_MaBmsgGetRecipFromEnv(p_envelope));
+
+ /* It will either be another (nested) envelope or the body */
+ p_body = BTA_MaBmsgGetBodyFromEnv(p_envelope);
+
+ if ( p_body )
+ bta_ma_stream_body(p_stream, p_body);
+ else
+ bta_ma_stream_envelopes(p_stream, BTA_MaBmsgGetNextEnv(p_envelope));
+
+ bta_ma_stream_str(p_stream, "\r\nEND:BENV");
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ma_stream_body
+**
+** Description Builds a bMessage content <bmessage-content> into a stream.
+**
+** Parameters p_stream - Output stream.
+** p_body - pointer to bBody structure.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ma_stream_body(tBTA_MA_STREAM * p_stream, tBTA_MA_BMSG_BODY * p_body)
+{
+ UINT16 part_id = 0;
+ tBTA_MA_BMSG_LANGUAGE language;
+ tBTA_MA_CHARSET charset;
+
+ if ( p_stream && p_body )
+ {
+ bta_ma_stream_str(p_stream, "\r\nBEGIN:BBODY");
+
+ /* Part ID (optional) */
+ part_id = BTA_MaBmsgGetBodyPartid(p_body);
+ if ( part_id != 0 )
+ {
+ bta_ma_stream_str(p_stream, "\r\nPARTID:");
+ bta_ma_stream_value(p_stream, part_id);
+ }
+
+ /* Character set */
+ charset = BTA_MaBmsgGetBodyCharset(p_body);
+ switch ( charset)
+ {
+ case BTA_MA_CHARSET_UTF_8:
+ bta_ma_stream_str(p_stream, "\r\nCHARSET:UTF-8");
+ break;
+ case BTA_MA_CHARSET_NATIVE:
+ bta_ma_stream_str(p_stream, "\r\nCHARSET:NATIVE");
+ /* Encoding */
+ bta_ma_stream_str(p_stream, "\r\nENCODING:");
+ bta_ma_stream_str(p_stream, bmsg_body_encoding[BTA_MaBmsgGetBodyEncoding(p_body)]);
+ break;
+ default:
+ break;
+ }
+
+ /* Language */
+ language = BTA_MaBmsgGetBodyLanguage(p_body);
+ if ( language != BTA_MA_BMSG_LANG_UNSPECIFIED )
+ {
+ bta_ma_stream_str(p_stream, "\r\nLANGUAGE:");
+ bta_ma_stream_str(p_stream, bmsg_body_language[language]);
+ }
+
+ /* Body content length */
+ bta_ma_stream_str(p_stream, "\r\nLENGTH:");
+ bta_ma_stream_value(p_stream, bta_ma_get_body_length(p_body));
+
+ /* Content */
+ bta_ma_stream_body_content(p_stream, BTA_MaBmsgGetContentFromBody(p_body));
+
+ bta_ma_stream_str(p_stream, "\r\nEND:BBODY");
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ma_stream_body_content
+**
+** Description Builds a body content <bmessage-body-content> into a stream.
+**
+** Parameters p_stream - Output stream.
+** p_content - pointer to content structure.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ma_stream_body_content(tBTA_MA_STREAM * p_stream,
+ tBTA_MA_BMSG_CONTENT * p_content)
+{
+ char * p_text;
+
+ APPL_TRACE_EVENT0("bta_ma_stream_body_content");
+ while ( p_stream && p_content )
+ {
+ bta_ma_stream_str(p_stream, "\r\nBEGIN:MSG");
+
+ p_text = BTA_MaBmsgGetMsgContent(p_content);
+ if ( p_text )
+ {
+ bta_ma_stream_str(p_stream, "\r\n");
+
+ while ( p_text )
+ {
+ bta_ma_stream_str(p_stream, p_text);
+ p_text = BTA_MaBmsgGetNextMsgContent(p_content);
+ }
+ }
+
+ bta_ma_stream_str(p_stream, "\r\nEND:MSG");
+
+ p_content = BTA_MaBmsgGetNextContent(p_content);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ma_str_to_charset
+**
+** Description Returns the charset enumeration (tBTA_MA_CHARSET) that
+** corresponds to the provided string.
+**
+** Parameters psz - Input string.
+** p_charset - pointer to the charset value to be received.
+**
+** Returns TRUE if there is a match, otherwise FALSE.
+**
+*******************************************************************************/
+BOOLEAN bta_ma_str_to_charset(char * psz, tBTA_MA_CHARSET * p_charset)
+{
+
+ tBTA_MA_CHARSET e;
+
+ if ( psz && p_charset )
+ {
+ for (e= BTA_MA_CHARSET_NATIVE; e < num_bmsg_body_charset; e++)
+ {
+ if ( strcmp(psz, bmsg_body_charset[e]) == 0 )
+ {
+ *p_charset = e;
+ return( TRUE );
+ }
+ }
+ }
+
+ return( FALSE );
+}
+
+
+/*******************************************************************************
+**
+** Function bta_ma_str_to_encoding
+**
+** Description Returns the encoding enumeration (tBTA_MA_BMSG_ENCODING) that
+** corresponds to the provided string.
+**
+** Parameters psz - Input string.
+** p_encoding - pointer to the encoding value to be received.
+**
+** Returns TRUE if there is a match, otherwise FALSE.
+**
+*******************************************************************************/
+BOOLEAN bta_ma_str_to_encoding(char * psz, tBTA_MA_BMSG_ENCODING * p_encoding)
+{
+ tBTA_MA_BMSG_ENCODING e;
+
+ if ( psz && p_encoding )
+ {
+ for (e= BTA_MA_BMSG_ENC_8BIT; e < num_bmsg_body_encoding; e++)
+ {
+ if ( strcmp(psz, bmsg_body_encoding[e]) == 0 )
+ {
+ *p_encoding = e;
+ return( TRUE );
+ }
+ }
+ }
+
+ return( FALSE );
+}
+
+/*******************************************************************************
+**
+** Function bta_ma_str_to_language
+**
+** Description Returns the language enumeration (tBTA_MA_BMSG_LANGUAGE) that
+** corresponds to the provided string.
+**
+** Parameters psz - Input string.
+** p_language - pointer to the language value to be received.
+**
+** Returns TRUE if there is a match, otherwise FALSE.
+**
+*******************************************************************************/
+BOOLEAN bta_ma_str_to_language(char * psz, tBTA_MA_BMSG_LANGUAGE * p_language)
+{
+ tBTA_MA_BMSG_LANGUAGE l;
+
+ if ( psz && p_language )
+ {
+ for (l=BTA_MA_BMSG_LANG_UNSPECIFIED; l < num_bmsg_body_language; l++)
+ {
+ if ( strcmp(psz, bmsg_body_language[l]) == 0 )
+ {
+ *p_language = l;
+ return( TRUE );
+ }
+ }
+ }
+
+ return( FALSE );
+}
+
+/*******************************************************************************
+**
+** Function bta_ma_str_to_msg_typ
+**
+** Description Returns the message type enumeration (tBTA_MA_MSG_TYPE)
+** that corresponds to the provided string.
+**
+** Parameters psz - Input string.
+** p_msg_type - pointer to the message type value to be
+** received.
+**
+** Returns TRUE if there is a match, otherwise FALSE.
+**
+*******************************************************************************/
+BOOLEAN bta_ma_str_to_msg_typ(char * psz, tBTA_MA_MSG_TYPE * p_msg_type)
+{
+ if ( psz && p_msg_type )
+ {
+ if ( strcmp(psz, "EMAIL") == 0 )
+ *p_msg_type = BTA_MA_MSG_TYPE_EMAIL;
+ else if ( strcmp(psz, "SMS_GSM") == 0 )
+ *p_msg_type = BTA_MA_MSG_TYPE_SMS_GSM;
+ else if ( strcmp(psz, "SMS_CDMA") == 0 )
+ *p_msg_type = BTA_MA_MSG_TYPE_SMS_CDMA;
+ else if ( strcmp(psz, "MMS") == 0 )
+ *p_msg_type = BTA_MA_MSG_TYPE_MMS;
+ else
+ return FALSE;
+ }
+
+ return( TRUE );
+}
+
+/*******************************************************************************
+**
+** Function bta_ma_get_body_length
+**
+** Description Returns the combined length in characters of the message
+** content.
+**
+** Parameters p_body - pointer to bBody structure.
+**
+** Returns Length of the body message text.
+**
+*******************************************************************************/
+UINT32 bta_ma_get_body_length(tBTA_MA_BMSG_BODY * p_body)
+{
+ UINT32 length = 0, len=0;
+ tBTA_MA_BMSG_CONTENT * p_content;
+ char * p_text;
+
+ APPL_TRACE_EVENT0("bta_ma_get_body_length");
+
+ p_content = BTA_MaBmsgGetContentFromBody(p_body);
+
+ while ( p_content )
+ {
+ p_text= BTA_MaBmsgGetMsgContent(p_content);
+
+ while ( p_text )
+ {
+ len = strlen(p_text);
+ length += (len + BTA_MA_BMSG_BODY_TAG_CTL_LENGTH);
+
+ APPL_TRACE_EVENT3("total=%d len=%d text=%s",length, len, p_text);
+
+ p_text = BTA_MaBmsgGetNextMsgContent(p_content);
+ }
+
+ p_content = BTA_MaBmsgGetNextContent(p_content);
+ }
+
+ APPL_TRACE_EVENT1("bta_ma_get_body_length len=%d", length);
+ return( length );
+
+
+}
+
+/*******************************************************************************
+**
+** Function bta_ma_bmsg_free_vcards
+**
+** Description Free buffers used by vVards
+**
+** Parameters p_vcard - Pointer to the first vCard in the linked vCards
+**
+** Returns None
+**
+*******************************************************************************/
+
+void bta_ma_bmsg_free_vcards(tBTA_MA_BMSG_VCARD * p_vcard)
+{
+ int x;
+
+ if ( p_vcard )
+ {
+ /* recursively free any linked vCards */
+ bta_ma_bmsg_free_vcards((tBTA_MA_BMSG_VCARD *)p_vcard->p_next);
+
+ /* Free properties */
+ for (x=0; x < BTA_MA_VCARD_PROP_MAX; x++)
+ bta_ma_bmsg_free_vcard_prop(p_vcard->p_prop[x]);
+
+ /* free vcard structure itself */
+ bta_ma_bmsg_free(p_vcard);
+ }
+}
+/*******************************************************************************
+**
+** Function bta_ma_bmsg_free_envelope
+**
+** Description Free buffers used by envelopes
+**
+** Parameters p_envelope - Pointer to the first envelope in the linked envelopes
+**
+** Returns None
+**
+*******************************************************************************/
+void bta_ma_bmsg_free_envelope(tBTA_MA_BMSG_ENVELOPE * p_envelope)
+{
+ if ( p_envelope )
+ {
+ /* recursively free any linked envelopes */
+ bta_ma_bmsg_free_envelope((tBTA_MA_BMSG_ENVELOPE *)p_envelope->p_next);
+
+ /* free the body */
+ bta_ma_bmsg_free_body(p_envelope->p_body);
+
+ /* free recipients */
+ bta_ma_bmsg_free_vcards(p_envelope->p_recip);
+
+ /* free envelope structure itself */
+ bta_ma_bmsg_free(p_envelope);
+ }
+}
+/*******************************************************************************
+**
+** Function bta_ma_bmsg_free_body
+**
+** Description Free buffers used by a message body
+**
+** Parameters p_body - Pointer to a message body
+**
+** Returns None
+**
+*******************************************************************************/
+void bta_ma_bmsg_free_body(tBTA_MA_BMSG_BODY * p_body)
+{
+ if ( p_body )
+ {
+ bta_ma_bmsg_free_content(p_body->p_content);
+
+ /* free body structure itself */
+ bta_ma_bmsg_free(p_body);
+ }
+}
+/*******************************************************************************
+**
+** Function bta_ma_bmsg_free_content
+**
+** Description Free buffers used by message contents
+**
+** Parameters p_envelope - Pointer to the first message content in the
+** linked message contents
+**
+** Returns None
+**
+*******************************************************************************/
+void bta_ma_bmsg_free_content(tBTA_MA_BMSG_CONTENT * p_content)
+{
+ if ( p_content )
+ {
+ /* recursively free any linked content */
+ bta_ma_bmsg_free_content((tBTA_MA_BMSG_CONTENT *)p_content->p_next);
+
+ /* free all of the message text */
+ bta_ma_bmsg_free_message_text(p_content->p_message);
+
+ /* free content structure itself */
+ bta_ma_bmsg_free(p_content);
+ }
+}
+/*******************************************************************************
+**
+** Function bta_ma_bmsg_free_message_text
+**
+** Description Free text string buffers used by a message
+**
+** Parameters p_envelope - Pointer to a message
+**
+** Returns None
+**
+*******************************************************************************/
+void bta_ma_bmsg_free_message_text(tBTA_MA_BMSG_MESSAGE * p_message)
+{
+ tBTA_MA_BMSG_MESSAGE * p_temp;
+
+ while ( p_message )
+ {
+ p_temp = (tBTA_MA_BMSG_MESSAGE *)p_message->p_next;
+
+ /* free message string */
+ bta_ma_bmsg_free(p_message->p_text);
+
+ /* free message text structure */
+ bta_ma_bmsg_free(p_message);
+
+ /* now point to the next one */
+ p_message = p_temp;
+ }
+}
+/*******************************************************************************
+**
+** Function bta_ma_bmsg_free_vcard_prop
+**
+** Description Free buffers used by a vCard property
+**
+** Parameters p_envelope - Pointer to a vCard property
+**
+** Returns None
+**
+*******************************************************************************/
+void bta_ma_bmsg_free_vcard_prop(tBTA_MA_VCARD_PROPERTY * p_prop)
+{
+ if ( p_prop )
+ {
+ /* free the value and the parameter */
+ if ( p_prop->p_value )
+ bta_ma_bmsg_free(p_prop->p_value);
+
+ if ( p_prop->p_param )
+ bta_ma_bmsg_free(p_prop->p_param);
+
+ /* recursively free any linked content */
+ if ( p_prop->p_next )
+ bta_ma_bmsg_free_vcard_prop((tBTA_MA_VCARD_PROPERTY *)p_prop->p_next);
+
+ /* free property structure itself */
+ bta_ma_bmsg_free(p_prop);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ma_bmsg_alloc
+**
+** Description Allocate buffer for the specified size
+**
+** Parameters cb - request buffer size
+**
+** Returns None
+**
+*******************************************************************************/
+
+void * bta_ma_bmsg_alloc(size_t cb)
+{
+ void * p_buf;
+
+ if ((p_buf = GKI_getbuf((UINT16) cb)) == NULL )
+ {
+ APPL_TRACE_ERROR1("Unable to allocate buffer for size=%", (UINT16) cb);
+ }
+ return(p_buf);
+}
+/*******************************************************************************
+**
+** Function bta_ma_bmsg_free
+**
+** Description Free buffer
+**
+** Parameters p - pointer to a buffer
+**
+** Returns None
+**
+*******************************************************************************/
+void bta_ma_bmsg_free(void * p)
+{
+ if ( p )
+ GKI_freebuf(p);
+}
+
+
+#endif /* BTA_MSE_INCLUDED */
diff --git a/bta/ma/bta_ma_util.h b/bta/ma/bta_ma_util.h
new file mode 100644
index 0000000..9040201
--- /dev/null
+++ b/bta/ma/bta_ma_util.h
@@ -0,0 +1,93 @@
+/*****************************************************************************
+**
+** Name: bta_ma_util.h
+**
+** Description: This is the interface file for the Message Access Profile
+** (MAP) utility functions.
+**
+** Copyright (c) 2009, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_MA_UTIL_H
+#define BTA_MA_UTIL_H
+
+#include "bta_ma_def.h"
+#include "bta_mse_api.h"
+#include "bta_mse_co.h"
+#include "bta_ma_api.h"
+
+
+#define BTA_MA_MAX_SIZE (100)
+
+/* Here are a set of property flags used to keep track
+** of properties that are successfully parsed. We use
+** this information to determine if all the *required*
+** properties have been provided in the parsed object.
+*/
+#define BTA_MA_PROP_VERSION 0x00000001
+#define BTA_MA_BMSG_BODY_TAG_CTL_LENGTH 22 /* see MAP Spec. Errata 3603 */
+ /* BEGIN:MSG<CRTL>+<CRTL>+END:MSG<CRTL> */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+ extern const char * bta_ma_evt_typ_to_string(tBTA_MSE_NOTIF_TYPE notif_type);
+ extern const char * bta_ma_msg_typ_to_string(tBTA_MA_MSG_TYPE msg_typ);
+ extern const char * bta_ma_rcv_status_to_string(tBTA_MSE_CO_RCV_STATUS rcv_status);
+
+ extern BOOLEAN bta_ma_stream_str(tBTA_MA_STREAM * p_stream,
+ const char * p_str);
+
+ extern BOOLEAN bta_ma_stream_buf(tBTA_MA_STREAM * p_stream,
+ UINT16 len,
+ UINT8 * p_buf);
+
+ extern BOOLEAN bta_ma_stream_boolean_yes_no(tBTA_MA_STREAM * p_stream, BOOLEAN val);
+
+ extern BOOLEAN bta_ma_stream_value(tBTA_MA_STREAM * p_stream, UINT32 val);
+
+ extern BOOLEAN bta_ma_stream_handle(tBTA_MA_STREAM * p_stream,
+ tBTA_MA_MSG_HANDLE handle);
+
+ extern UINT16 bta_ma_stream_used_size(tBTA_MA_STREAM * p_stream);
+
+ extern BOOLEAN bta_ma_stream_ok(tBTA_MA_STREAM * p_stream);
+
+ extern void bta_ma_convert_hex_str_to_64bit_handle(char *p_hex_str, tBTA_MA_MSG_HANDLE handle);
+
+ extern BOOLEAN bta_ma_get_char(tBTA_MA_STREAM * p_stream, char * p_char);
+ extern BOOLEAN bta_ma_str_to_charset(char * psz, tBTA_MA_CHARSET * p_charset);
+ extern BOOLEAN bta_ma_str_to_encoding(char * psz, tBTA_MA_BMSG_ENCODING * p_encoding);
+ extern BOOLEAN bta_ma_str_to_language(char * psz, tBTA_MA_BMSG_LANGUAGE * p_language);
+ extern BOOLEAN bta_ma_str_to_msg_typ(char * psz, tBTA_MA_MSG_TYPE * p_msg_type);
+
+ extern void bta_ma_stream_vcards(tBTA_MA_STREAM *, tBTA_MA_BMSG_VCARD *);
+ extern void bta_ma_stream_envelopes(tBTA_MA_STREAM * p_stream, tBTA_MA_BMSG_ENVELOPE * p_envelope);
+ extern void bta_ma_stream_body(tBTA_MA_STREAM * p_stream, tBTA_MA_BMSG_BODY * p_body);
+ extern void bta_ma_stream_body_content(tBTA_MA_STREAM * p_stream, tBTA_MA_BMSG_CONTENT * p_content);
+ extern void bta_ma_stream_vcard_prop(tBTA_MA_STREAM * p_stream, tBTA_MA_BMSG_VCARD * p_vcard, tBTA_MA_VCARD_PROP prop);
+
+ extern UINT32 bta_ma_get_body_length(tBTA_MA_BMSG_BODY * p_body);
+
+ extern UINT16 bta_ma_get_tag(tBTA_MA_STREAM * p_stream, char * psz, UINT16 max_size);
+ extern UINT16 bta_ma_get_value(tBTA_MA_STREAM * p_stream, char * psz, UINT16 max_size);
+
+ extern tBTA_MA_STATUS bta_ma_parse_vcard(tBTA_MA_BMSG_VCARD * p_vcard, tBTA_MA_STREAM * p_stream);
+ extern tBTA_MA_STATUS bta_ma_parse_envelope(tBTA_MA_BMSG_ENVELOPE * p_envelope, tBTA_MA_STREAM * p_stream);
+
+ extern void * bta_ma_bmsg_alloc(size_t cb);
+ extern void bta_ma_bmsg_free(void * p);
+ extern void bta_ma_bmsg_free_vcards(tBTA_MA_BMSG_VCARD * p_vcard);
+ extern void bta_ma_bmsg_free_envelope(tBTA_MA_BMSG_ENVELOPE * p_envelope);
+ extern void bta_ma_bmsg_free_body(tBTA_MA_BMSG_BODY * p_body);
+ extern void bta_ma_bmsg_free_content(tBTA_MA_BMSG_CONTENT * p_content);
+ extern void bta_ma_bmsg_free_message_text(tBTA_MA_BMSG_MESSAGE * p_message);
+ extern void bta_ma_bmsg_free_vcard_prop(tBTA_MA_VCARD_PROPERTY * p_prop);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_MA_UTIL_H */
diff --git a/bta/ma/bta_mse_act.c b/bta/ma/bta_mse_act.c
new file mode 100644
index 0000000..c8ec487
--- /dev/null
+++ b/bta/ma/bta_mse_act.c
@@ -0,0 +1,2763 @@
+/*****************************************************************************
+**
+** Name: bta_mse_act.c
+**
+** Description: This file contains the message access server action
+** functions for the state machine.
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+
+#if defined(BTA_MSE_INCLUDED) && (BTA_MSE_INCLUDED == TRUE)
+
+#include <string.h>
+#include "gki.h"
+#include "sdp_api.h"
+#include "bta_sys.h"
+#include "port_api.h"
+#include "obx_api.h"
+#include "sdp_api.h"
+#include "bta_fs_api.h"
+#include "bta_mse_api.h"
+#include "bta_mse_int.h"
+#include "bta_fs_co.h"
+#include "utl.h"
+#include "bd.h"
+#include "bta_ma_def.h"
+
+
+/*****************************************************************************
+** Local Function prototypes
+*****************************************************************************/
+void bta_mse_req_app_access(UINT8 inst_idx, UINT8 sess_idx, tBTA_MSE_DATA *p_data);
+static void bta_mse_mn_sdp_cback0(UINT16 status);
+static void bta_mse_mn_sdp_cback1(UINT16 status);
+static void bta_mse_mn_sdp_cback2(UINT16 status);
+static void bta_mse_mn_sdp_cback3(UINT16 status);
+static void bta_mse_mn_sdp_cback4(UINT16 status);
+static void bta_mse_mn_sdp_cback5(UINT16 status);
+static void bta_mse_mn_sdp_cback6(UINT16 status);
+
+static tSDP_DISC_CMPL_CB * const bta_mse_mn_sdp_cback_arr[] = {
+ bta_mse_mn_sdp_cback0,
+ bta_mse_mn_sdp_cback1,
+ bta_mse_mn_sdp_cback2,
+ bta_mse_mn_sdp_cback3,
+ bta_mse_mn_sdp_cback4,
+ bta_mse_mn_sdp_cback5,
+ bta_mse_mn_sdp_cback6
+};
+
+#if (BTA_MSE_DEBUG == TRUE) && (BT_USE_TRACES == TRUE)
+static char *bta_mse_obx_evt_code(UINT16 evt_code);
+#endif
+
+
+/*******************************************************************************
+** Message Access Server (MAS) Action functions
+**
+*******************************************************************************/
+
+/*******************************************************************************
+**
+** Function bta_mse_ma_int_close
+**
+** Description Porcesses the Internal MAS session close event
+**
+** Parameters inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+** p_data - Pointer to the event data
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_ma_int_close(UINT8 inst_idx, UINT8 sess_idx, tBTA_MSE_DATA *p_data)
+{
+ tBTA_MSE_MA_SESS_CB *p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, sess_idx);
+ BD_ADDR bd_addr;
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT2("bta_mse_ma_int_close inst idx=%d sess idx=%d",inst_idx, sess_idx);
+#endif
+
+ if (OBX_GetPeerAddr(p_cb->obx_handle, bd_addr) != 0)
+ {
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT1("Send Obx Discon rsp obx session id=%d",
+ p_cb->obx_handle);
+#endif
+ /* resources will be freed at BTA_MSE_MA_OBX_CLOSE_EVT */
+ OBX_DisconnectRsp(p_cb->obx_handle, OBX_RSP_SERVICE_UNAVL, NULL);
+ }
+ else
+ {
+ /* OBX close already */
+ bta_mse_ma_sm_execute(inst_idx, sess_idx, BTA_MSE_MA_OBX_CLOSE_EVT, p_data);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_ma_api_upd_ibx_rsp
+**
+** Description Processes the API update inbox response event.
+** If permission had been granted, continue the operation,
+** otherwise stop the operation.
+**
+** Parameters inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+** p_data - Pointer to the event data
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_ma_api_upd_ibx_rsp(UINT8 inst_idx, UINT8 sess_idx, tBTA_MSE_DATA *p_data)
+{
+ tBTA_MSE_MA_SESS_CB *p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, sess_idx);
+ UINT8 rsp_code = OBX_RSP_UNAUTHORIZED;
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT2("bta_mse_ma_api_upd_ibx_rsp inst idx=%d sess idx=%d",inst_idx, sess_idx);
+#endif
+
+ /* Process the currently active access response */
+ if (p_cb->oper == BTA_MSE_OPER_UPDATE_INBOX)
+ {
+ bta_mse_set_ma_oper(inst_idx, sess_idx, BTA_MSE_OPER_NONE);
+ if (p_data->api_upd_ibx_rsp.rsp == BTA_MSE_UPDATE_INBOX_ALLOW)
+ {
+ bta_mse_co_update_inbox(p_cb->obx_handle, bta_mse_cb.app_id);
+ rsp_code = OBX_RSP_OK;
+ }
+ OBX_PutRsp(p_cb->obx_handle, rsp_code, (BT_HDR *)NULL);
+ }
+ else
+ {
+ APPL_TRACE_WARNING1("MSE UPDIBXRSP: Unknown tBTA_MSE_OPER value (%d)",
+ p_cb->oper);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function bta_mse_ma_api_set_notif_reg_rsp
+**
+** Description Processes the API set notification registration response event.
+** If permission had been granted, continue the operation,
+** otherwise stop the operation.
+**
+** Parameters inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+** p_data - Pointer to the event data
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_ma_api_set_notif_reg_rsp(UINT8 inst_idx, UINT8 sess_idx, tBTA_MSE_DATA *p_data)
+{
+ tBTA_MSE_MA_SESS_CB *p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, sess_idx);
+ UINT8 rsp_code = OBX_RSP_SERVICE_UNAVL;
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT2("bta_mse_ma_api_set_notif_reg_rsp inst idx=%d sess idx=%d",inst_idx, sess_idx);
+#endif
+
+ /* Process the currently active access response */
+ if ( p_cb->oper == BTA_MSE_OPER_NOTIF_REG)
+ {
+ bta_mse_set_ma_oper(inst_idx, sess_idx, BTA_MSE_OPER_NONE);
+ if (p_data->api_set_notif_reg_rsp.rsp == BTA_MSE_SET_NOTIF_REG_ALLOW)
+ {
+ bta_mse_proc_notif_reg_status(p_cb->notif_reg_req.notif_status,
+ inst_idx, sess_idx);
+ }
+ else
+ {
+ OBX_PutRsp(p_cb->obx_handle, rsp_code, (BT_HDR *)NULL);
+ }
+ }
+ else
+ {
+ APPL_TRACE_WARNING1("MSE SETNOTIFREGRSP: Unknown tBTA_MSE_OPER value (%d)",
+ p_cb->oper);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function bta_mse_ma_api_accessrsp
+**
+** Description Processes the API access response event.
+** If permission had been granted, continue the operation,
+** otherwise stop the operation.
+**
+** Parameters inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+** p_data - Pointer to the event data
+**
+** Returns void
+**
+*******************************************************************************/
+
+void bta_mse_ma_api_accessrsp(UINT8 inst_idx, UINT8 sess_idx, tBTA_MSE_DATA *p_data)
+{
+ tBTA_MSE_MA_SESS_CB *p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, sess_idx);
+ UINT8 rsp_code = OBX_RSP_OK;
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT3("bta_mse_ma_api_accessrsp inst idx=%d sess idx=%d access_rsp=%d",
+ inst_idx, sess_idx,
+ p_data->api_access_rsp.rsp);
+#endif
+
+ if (p_cb->oper != p_data->api_access_rsp.oper )
+ {
+ APPL_TRACE_WARNING2("MSE MA ACCRSP: not match active:%d, rsp:%d",
+ p_cb->oper, p_data->api_access_rsp.oper);
+ return;
+ }
+
+ /* Process the currently active access response */
+ switch (p_cb->oper)
+ {
+ case BTA_MSE_OPER_SETPATH:
+
+ if (p_data->api_access_rsp.rsp == BTA_MA_ACCESS_TYPE_ALLOW)
+ {
+ bta_mse_co_set_folder( p_cb->obx_handle, p_cb->sp.p_path, bta_mse_cb.app_id);
+ /* updat the working dir */
+ BCM_STRNCPY_S(p_cb->p_workdir, p_bta_fs_cfg->max_path_len+1, p_cb->sp.p_path, p_bta_fs_cfg->max_path_len);
+ }
+ else
+ {
+ rsp_code = OBX_RSP_UNAUTHORIZED;
+ }
+
+ utl_freebuf((void**)&(p_cb->sp.p_path));
+ utl_freebuf((void**)&(p_cb->sp.p_name));
+ OBX_SetPathRsp(p_cb->obx_handle, rsp_code, (BT_HDR *)NULL);
+ bta_mse_set_ma_oper(inst_idx, sess_idx, BTA_MSE_OPER_NONE);
+ break;
+
+ case BTA_MSE_OPER_GET_MSG_LIST:
+
+ if (p_data->api_access_rsp.rsp == BTA_MA_ACCESS_TYPE_ALLOW)
+ {
+ bta_mse_getmsglist(inst_idx,sess_idx, TRUE);
+ }
+ else
+ {
+ OBX_GetRsp(p_cb->obx_handle, OBX_RSP_UNAUTHORIZED, (BT_HDR *)NULL);
+ bta_mse_clean_msg_list(inst_idx,sess_idx);
+ }
+ break;
+
+ case BTA_MSE_OPER_GET_MSG:
+
+ if (p_data->api_access_rsp.rsp == BTA_MA_ACCESS_TYPE_ALLOW)
+ {
+ bta_mse_getmsg(inst_idx,sess_idx, TRUE);
+ }
+ else
+ {
+ OBX_GetRsp(p_cb->obx_handle, OBX_RSP_UNAUTHORIZED, (BT_HDR *)NULL);
+ bta_mse_clean_msg(inst_idx,sess_idx);
+ }
+ break;
+
+ case BTA_MSE_OPER_PUSH_MSG:
+
+ if (p_data->api_access_rsp.rsp == BTA_MA_ACCESS_TYPE_ALLOW)
+ {
+ bta_mse_pushmsg(inst_idx, sess_idx, TRUE);
+ }
+ else
+ {
+ OBX_PutRsp(p_cb->obx_handle, OBX_RSP_UNAUTHORIZED, (BT_HDR *)NULL);
+ bta_mse_clean_push_msg(inst_idx,sess_idx);
+ }
+ break;
+
+ case BTA_MSE_OPER_DEL_MSG:
+
+ if (p_data->api_access_rsp.rsp == BTA_MA_ACCESS_TYPE_ALLOW)
+ {
+ p_cb->cout_active = TRUE;
+ bta_mse_co_set_msg_delete_status((tBTA_MA_SESS_HANDLE) p_cb->obx_handle,
+ p_cb->set_msg_sts.handle,
+ p_cb->set_msg_sts.sts_val,
+ BTA_MSE_CI_DEL_MSG_EVT,
+ bta_mse_cb.app_id);
+ }
+ else
+ {
+ OBX_PutRsp(p_cb->obx_handle, OBX_RSP_UNAUTHORIZED, (BT_HDR *)NULL);
+ bta_mse_clean_set_msg_sts(inst_idx,sess_idx);
+ }
+ break;
+
+ default:
+ APPL_TRACE_WARNING1("MSE ACCRSP: Unknown tBTA_MSE_OPER value (%d)",
+ p_cb->oper);
+ break;
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_ma_ci_get_folder_entry
+**
+** Description Proceses the get folder entry call-in event
+**
+** Parameters inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+** p_data - Pointer to the event data
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_ma_ci_get_folder_entry(UINT8 inst_idx, UINT8 sess_idx, tBTA_MSE_DATA *p_data)
+{
+ tBTA_MSE_MA_SESS_CB *p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, sess_idx);
+ UINT8 rsp_code = OBX_RSP_PART_CONTENT;
+ BOOLEAN free_pkt = TRUE;
+
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT2("bta_mse_ma_ci_get_folder_entry inst idx=%d sess idx=%d",
+ inst_idx, sess_idx);
+#endif
+
+ p_cb->cout_active = FALSE;
+
+ if (p_cb->aborting)
+ {
+ bta_mse_clean_getput(inst_idx,sess_idx, BTA_MA_STATUS_ABORTED);
+ return;
+ }
+
+ /* Process dirent listing call-in event if operation is still active */
+ if (p_cb->oper == BTA_MSE_OPER_GET_FOLDER_LIST)
+ {
+ switch (p_data->ci_get_fentry.status)
+ {
+ case BTA_MA_STATUS_OK: /* Valid new entry */
+ free_pkt = FALSE;
+ rsp_code = bta_mse_add_list_entry(inst_idx, sess_idx);
+ break;
+
+ case BTA_MA_STATUS_EODIR: /* End of list (entry not valid) */
+ free_pkt = FALSE;
+ rsp_code = OBX_RSP_OK;
+ break;
+
+ case BTA_MA_STATUS_FAIL: /* Error occurred */
+ rsp_code = OBX_RSP_NOT_FOUND;
+ break;
+
+ default:
+ APPL_TRACE_ERROR1("bta_mse_ma_ci_get_folder_entry Unknown status=%d ",
+ p_data->ci_get_fentry.status );
+ rsp_code = OBX_RSP_NOT_FOUND;
+ break;
+ }
+ }
+
+ if (rsp_code != OBX_RSP_PART_CONTENT)
+ bta_mse_end_of_list(inst_idx, sess_idx,rsp_code);
+
+ if (free_pkt)
+ utl_freebuf((void **)&p_cb->obx.p_pkt);
+}
+
+
+/*******************************************************************************
+**
+** Function bta_mse_ma_ci_get_ml_info
+**
+** Description Proceses the get message list info call-in event
+**
+** Parameters inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+** p_data - Pointer to the event data
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_ma_ci_get_ml_info(UINT8 inst_idx, UINT8 sess_idx, tBTA_MSE_DATA *p_data)
+{
+ tBTA_MSE_MA_SESS_CB *p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, sess_idx);
+ UINT8 rsp_code = OBX_RSP_PART_CONTENT;
+ BOOLEAN free_pkt = TRUE;
+
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT2("bta_mse_ma_ci_get_ml_info inst idx=%d sess idx=%d",
+ inst_idx, sess_idx);
+#endif
+
+ p_cb->cout_active = FALSE;
+
+ if (p_cb->aborting)
+ {
+ bta_mse_clean_getput(inst_idx,sess_idx, BTA_MA_STATUS_ABORTED);
+ return;
+ }
+
+ /* Process dirent listing call-in event if operation is still active */
+ if (p_cb->oper == BTA_MSE_OPER_GET_MSG_LIST)
+ {
+ switch (p_data->ci_get_ml_info.status)
+ {
+ case BTA_MA_STATUS_OK: /* Valid new entry */
+ free_pkt = FALSE;
+ rsp_code = bta_mse_add_msg_list_info(inst_idx, sess_idx);
+ break;
+
+ case BTA_MA_STATUS_EODIR: /* End of list (entry not valid) */
+ free_pkt = FALSE;
+ rsp_code = OBX_RSP_OK;
+ break;
+
+ case BTA_MA_STATUS_FAIL: /* Error occurred */
+ rsp_code = OBX_RSP_NOT_FOUND;
+ break;
+
+ default:
+ APPL_TRACE_ERROR1("bta_mse_ma_ci_get_ml_info Unknown status=%d ",
+ p_data->ci_get_ml_info.status );
+ rsp_code = OBX_RSP_NOT_FOUND;
+ break;
+ }
+ }
+
+ if (rsp_code != OBX_RSP_PART_CONTENT)
+ bta_mse_end_of_msg_list(inst_idx, sess_idx,rsp_code);
+
+ if (free_pkt)
+ utl_freebuf((void **)&p_cb->obx.p_pkt);
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_ma_ci_get_msg_entry
+**
+** Description Proceses the get message entry call-in event
+**
+** Parameters inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+** p_data - Pointer to the event data
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_ma_ci_get_ml_entry(UINT8 inst_idx, UINT8 sess_idx, tBTA_MSE_DATA *p_data)
+{
+ tBTA_MSE_MA_SESS_CB *p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, sess_idx);
+ UINT8 rsp_code = OBX_RSP_PART_CONTENT;
+ BOOLEAN free_pkt = TRUE;
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT2("bta_mse_ma_ci_get_msg_entry inst idx=%d sess idx=%d",inst_idx, sess_idx);
+ APPL_TRACE_EVENT1(" status=%d",p_data->ci_get_ml_entry.status);
+#endif
+
+ p_cb->cout_active = FALSE;
+
+ if (p_cb->aborting)
+ {
+ bta_mse_clean_getput(inst_idx,sess_idx, BTA_MA_STATUS_ABORTED);
+ return;
+ }
+
+ /* Process dirent listing call-in event if operation is still active */
+ if (p_cb->oper == BTA_MSE_OPER_GET_MSG_LIST)
+ {
+ switch (p_data->ci_get_ml_entry.status)
+ {
+ case BTA_MA_STATUS_OK: /* Valid new entry */
+ free_pkt = FALSE;
+ rsp_code = bta_mse_add_msg_list_entry(inst_idx, sess_idx);
+ break;
+
+ case BTA_MA_STATUS_EODIR: /* End of list (entry not valid) */
+ free_pkt = FALSE;
+ rsp_code = OBX_RSP_OK;
+ break;
+
+ case BTA_MA_STATUS_FAIL: /* Error occurred */
+ rsp_code = OBX_RSP_NOT_FOUND;
+ break;
+
+ default:
+ APPL_TRACE_ERROR1("bta_mse_ma_ci_get_ml_entry Unknown status=%d ",
+ p_data->ci_get_ml_entry.status);
+ rsp_code = OBX_RSP_NOT_FOUND;
+ break;
+ }
+ }
+
+ if (rsp_code != OBX_RSP_PART_CONTENT)
+ bta_mse_end_of_msg_list(inst_idx, sess_idx,rsp_code);
+
+ if (free_pkt)
+ utl_freebuf((void **)&p_cb->obx.p_pkt);
+}
+
+
+/*******************************************************************************
+**
+** Function bta_mse_ma_ci_get_msg
+**
+** Description Proceses the get message call-in event
+**
+** Parameters inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+** p_data - Pointer to the event data
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_ma_ci_get_msg(UINT8 inst_idx, UINT8 sess_idx, tBTA_MSE_DATA *p_data)
+{
+ tBTA_MSE_MA_SESS_CB *p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, sess_idx);
+ tBTA_MSE_OPER_MSG_PARAM *p_param = &p_cb->msg_param;
+ tBTA_MSE_CI_GET_MSG *p_ci_get_msg = &p_data->ci_get_msg;
+ UINT8 rsp_code = OBX_RSP_NOT_FOUND;
+ BOOLEAN free_pkt = TRUE, end_of_msg= TRUE;
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT2("bta_mse_ma_ci_get_msg inst idx=%d sess idx=%d",
+ inst_idx, sess_idx);
+ APPL_TRACE_EVENT1("status=%d",p_data->ci_get_ml_entry.status);
+#endif
+
+ p_cb->cout_active = FALSE;
+
+ if (p_cb->aborting)
+ {
+ bta_mse_clean_getput(inst_idx,sess_idx, BTA_MA_STATUS_ABORTED);
+ return;
+ }
+
+ /* Process get msg call-in event if operation is still active */
+ if (p_cb->oper == BTA_MSE_OPER_GET_MSG)
+ {
+ switch (p_data->ci_get_msg.status)
+ {
+ case BTA_MA_STATUS_OK: /* Valid new entry */
+ free_pkt = FALSE;
+ p_param->frac_deliver_status = p_ci_get_msg->frac_deliver_status;
+ p_param->filled_buff_size = p_ci_get_msg->filled_buff_size;
+
+ if ( p_ci_get_msg->multi_pkt_status == BTA_MA_MPKT_STATUS_MORE)
+ {
+ p_param->byte_get_cnt += p_param->filled_buff_size;
+ rsp_code = OBX_RSP_CONTINUE;
+ }
+ else
+ rsp_code = OBX_RSP_OK;
+
+ break;
+
+ case BTA_MA_STATUS_FAIL: /* Error occurred */
+ break;
+
+ default:
+ end_of_msg = FALSE;
+ break;
+ }
+ }
+
+ if (end_of_msg)
+ bta_mse_end_of_msg(inst_idx, sess_idx,rsp_code);
+
+ if (free_pkt)
+ utl_freebuf((void **)&p_cb->obx.p_pkt);
+}
+
+
+/*******************************************************************************
+**
+** Function bta_mse_ma_ci_push_msg
+**
+** Description Proceses the push message call-in event
+**
+** Parameters inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+** p_data - Pointer to the event data
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_ma_ci_push_msg(UINT8 inst_idx, UINT8 sess_idx, tBTA_MSE_DATA *p_data)
+{
+ tBTA_MSE_MA_SESS_CB *p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, sess_idx);
+ tBTA_MSE_OBX_PKT *p_obx = &p_cb->obx;
+ UINT8 rsp_code = OBX_RSP_INTRNL_SRVR_ERR;
+ BOOLEAN free_pkt = TRUE;
+ char handle_buf[BTA_MSE_64BIT_HEX_STR_SIZE];
+ tBTA_MA_STREAM strm;
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT2("bta_mse_ma_ci_push_msg inst idx=%d sess idx=%d",
+ inst_idx, sess_idx);
+ APPL_TRACE_EVENT4(" status=%d ci_last_pkt=%d obx_final=%d oper=%d",
+ p_data->ci_push_msg.status,
+ p_data->ci_push_msg.last_packet,
+ p_obx->final_pkt,
+ p_cb->oper);
+#endif
+
+ p_cb->cout_active = FALSE;
+
+ if (p_cb->aborting)
+ {
+ bta_mse_clean_getput(inst_idx,sess_idx, BTA_MA_STATUS_ABORTED);
+ return;
+ }
+
+ /* Process get msg call-in event if operation is still active */
+ if (p_cb->oper == BTA_MSE_OPER_PUSH_MSG)
+ {
+ switch (p_data->ci_push_msg.status)
+ {
+ case BTA_MA_STATUS_OK: /* Valid new entry */
+ if (p_obx->final_pkt)
+ {
+ APPL_TRACE_EVENT2("final pkt: status=%d oper=%d",
+ p_data->ci_push_msg.status, p_cb->oper);
+
+ utl_freebuf((void**)&p_obx->p_pkt);
+
+ rsp_code = OBX_RSP_OK;
+
+ p_obx->p_pkt = (BT_HDR *)OBX_HdrInit(p_cb->obx_handle,
+ /* p_cb->peer_mtu */ HCI_CMD_POOL_BUF_SIZE);
+ if (p_obx->p_pkt)
+ {
+ memset(handle_buf, 0,BTA_MSE_64BIT_HEX_STR_SIZE);
+ BTA_MaInitMemStream(&strm,(UINT8 *) handle_buf, BTA_MSE_64BIT_HEX_STR_SIZE);
+ bta_ma_stream_handle(&strm, p_data->ci_push_msg.handle);
+ if (OBX_AddUtf8NameHdr(p_obx->p_pkt, (UINT8 *)handle_buf))
+ {
+ rsp_code = OBX_RSP_OK;
+ free_pkt = FALSE;
+ }
+ else
+ {
+ rsp_code = OBX_RSP_INTRNL_SRVR_ERR;
+ }
+ }
+ else
+ {
+ rsp_code = OBX_RSP_INTRNL_SRVR_ERR;
+ }
+ }
+ else
+ rsp_code = OBX_RSP_CONTINUE;
+ break;
+
+ case BTA_MA_STATUS_FAIL: /* Error occurred */
+ rsp_code = OBX_RSP_UNAUTHORIZED;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (rsp_code==OBX_RSP_OK)
+ {
+ OBX_PutRsp(p_cb->obx_handle, rsp_code, (BT_HDR *)p_obx->p_pkt);
+ p_obx->p_pkt = NULL; /* Do not deallocate buffer; OBX will */
+ }
+ else
+ {
+ OBX_PutRsp(p_cb->obx_handle, rsp_code, (BT_HDR *)NULL);
+ }
+
+
+ if (rsp_code == OBX_RSP_CONTINUE)
+ {
+ bta_mse_send_push_msg_in_prog_evt(inst_idx,sess_idx);
+ }
+ else
+ {
+ if ((rsp_code != OBX_RSP_OK) ||
+ ((p_obx->final_pkt) &&(rsp_code == OBX_RSP_OK)))
+ {
+ bta_mse_send_oper_cmpl_evt(inst_idx,sess_idx, p_data->ci_push_msg.status);
+ bta_mse_clean_push_msg(inst_idx,sess_idx);
+ }
+ }
+
+ if (free_pkt) utl_freebuf((void**)&p_obx->p_pkt);
+
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_ma_ci_del_msg
+**
+** Description Proceses the delete message call-in event
+**
+** Parameters inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+** p_data - Pointer to the event data
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_ma_ci_del_msg(UINT8 inst_idx, UINT8 sess_idx, tBTA_MSE_DATA *p_data)
+{
+ tBTA_MSE_MA_SESS_CB *p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, sess_idx);
+ UINT8 rsp_code = OBX_RSP_OK;
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT2("bta_mse_ma_ci_del_msg inst idx=%d sess idx=%d",
+ inst_idx, sess_idx);
+ APPL_TRACE_EVENT2(" status=%d oper=%d",p_data->ci_del_msg.status, p_cb->oper);
+#endif
+
+ p_cb->cout_active = FALSE;
+
+ if (p_cb->aborting)
+ {
+ /* too late to abort now*/
+ bta_mse_abort_too_late(inst_idx,sess_idx);
+ }
+
+ /* Process get msg call-in event if operation is still active */
+ if (p_cb->oper == BTA_MSE_OPER_DEL_MSG)
+ {
+ switch (p_data->ci_del_msg.status)
+ {
+ case BTA_MA_STATUS_OK:
+ rsp_code = OBX_RSP_OK;
+ break;
+
+ case BTA_MA_STATUS_FAIL: /* Error occurred */
+ rsp_code = OBX_RSP_FORBIDDEN;
+ break;
+ default:
+ break;
+ }
+ }
+
+ OBX_PutRsp(p_cb->obx_handle, rsp_code, (BT_HDR *)NULL);
+ bta_mse_clean_set_msg_sts(inst_idx,sess_idx);
+
+}
+/*******************************************************************************
+**
+** Function bta_mse_ma_obx_connect
+**
+** Description Proceses the obx connect request to open a MAS session
+**
+** Parameters inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+** p_data - Pointer to the event data
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_ma_obx_connect(UINT8 inst_idx, UINT8 sess_idx, tBTA_MSE_DATA *p_data)
+{
+ tBTA_MSE_MA_CB *p_scb = BTA_MSE_GET_INST_CB_PTR(inst_idx);
+ tBTA_MSE_MA_SESS_CB *p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, sess_idx);
+ tBTA_MSE_OBX_EVT *p_evt = &p_data->obx_evt;
+ tBTA_MSE cback_evt_data;
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT2("bta_mse_ma_obx_connect inst idx=%d sess idx=%d",
+ inst_idx, sess_idx);
+#endif
+
+ p_cb->peer_mtu = p_evt->param.conn.mtu;
+ p_cb->obx_handle = p_evt->handle;
+ memcpy(p_cb->bd_addr, p_evt->param.conn.peer_addr, BD_ADDR_LEN);
+
+ OBX_ConnectRsp(p_evt->handle, OBX_RSP_OK, (BT_HDR *)NULL);
+
+ /* Reset to the root directory */
+ BCM_STRNCPY_S(p_cb->p_workdir, p_bta_fs_cfg->max_path_len+1, p_scb->p_rootpath, p_bta_fs_cfg->max_path_len);
+
+ /* inform role manager */
+ bta_mse_pm_conn_open(p_cb->bd_addr);
+
+ bdcpy(cback_evt_data.ma_open.bd_addr, p_cb->bd_addr);
+ BCM_STRNCPY_S((char *)cback_evt_data.ma_open.dev_name, sizeof(cback_evt_data.ma_open.dev_name),
+ "", BTM_MAX_REM_BD_NAME_LEN);
+ cback_evt_data.ma_open.mas_instance_id = p_scb->mas_inst_id;
+ cback_evt_data.ma_open.mas_session_id = p_cb->obx_handle;
+
+ bta_mse_cb.p_cback(BTA_MSE_MA_OPEN_EVT, (tBTA_MSE *) &cback_evt_data);
+
+ /* Done with Obex packet */
+ utl_freebuf((void**)&p_evt->p_pkt);
+
+}
+/*******************************************************************************
+**
+** Function bta_mse_ma_obx_disc
+**
+** Description Proceses the obx disconnect request to close a MAS session
+**
+** Parameters inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+** p_data - Pointer to the event data
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_ma_obx_disc(UINT8 inst_idx, UINT8 sess_idx, tBTA_MSE_DATA *p_data)
+{
+ tBTA_MSE_OBX_EVT *p_evt = &p_data->obx_evt;
+ UINT8 rsp_code;
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT2("bta_mse_ma_obx_disc inst idx=%d sess idx=%d",
+ inst_idx, sess_idx);
+#endif
+ rsp_code = (p_evt->obx_event == OBX_DISCONNECT_REQ_EVT) ? OBX_RSP_OK
+ : OBX_RSP_BAD_REQUEST;
+ OBX_DisconnectRsp(p_evt->handle, rsp_code, (BT_HDR *)NULL);
+
+ /* Done with Obex packet */
+ utl_freebuf((void**)&p_evt->p_pkt);
+}
+/*******************************************************************************
+**
+** Function bta_mse_ma_obx_close
+**
+** Description Proceses the obx close indication to close a MAS connection
+**
+** Parameters inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+** p_data - Pointer to the event data
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_ma_obx_close(UINT8 inst_idx, UINT8 sess_idx, tBTA_MSE_DATA *p_data)
+{
+ tBTA_MSE_MA_SESS_CB *p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, sess_idx);
+
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT2("bta_mse_ma_obx_close inst idx=%d sess idx=%d",
+ inst_idx, sess_idx);
+#endif
+ /* finished if not waiting on a call-in function */
+ if (!p_cb->cout_active)
+ bta_mse_ma_sm_execute(inst_idx, sess_idx, BTA_MSE_CLOSE_CMPL_EVT, p_data);
+
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_ma_obx_abort
+**
+** Description Proceses the obx abort request
+**
+** Parameters inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+** p_data - Pointer to the event data
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_ma_obx_abort(UINT8 inst_idx, UINT8 sess_idx, tBTA_MSE_DATA *p_data)
+{
+ tBTA_MSE_MA_SESS_CB *p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, sess_idx);
+ tBTA_MSE_OBX_EVT *p_evt = &p_data->obx_evt;
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT3("bta_mse_ma_obx_abort inst idx=%d sess idx=%d oper=%d",
+ inst_idx, sess_idx, p_cb->oper);
+#endif
+
+ utl_freebuf((void**)&p_evt->p_pkt);
+
+ switch (p_cb->oper)
+ {
+ case BTA_MSE_OPER_SETPATH:
+ case BTA_MSE_OPER_NONE:
+ OBX_AbortRsp(p_evt->handle, OBX_RSP_BAD_REQUEST, (BT_HDR *)NULL);
+ return;
+ default:
+ break;
+
+ }
+
+ if (!p_cb->cout_active)
+ {
+ bta_mse_clean_getput(inst_idx,sess_idx, BTA_MA_STATUS_ABORTED);
+ }
+ else /* Delay the response if a call-out function is active */
+ p_cb->aborting = TRUE;
+
+}
+/*******************************************************************************
+**
+** Function bta_mse_ma_obx_put
+**
+** Description Proceses the obx put request
+**
+** Parameters inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+** p_data - Pointer to the event data
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_ma_obx_put(UINT8 inst_idx, UINT8 sess_idx, tBTA_MSE_DATA *p_data)
+{
+ tBTA_MSE_MA_SESS_CB *p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, sess_idx);
+ tBTA_MSE_OBX_EVT *p_evt = &p_data->obx_evt;
+ tBTA_MSE_OBX_PKT *p_obx = &p_cb->obx;
+ tBTA_MSE_OPER_PUSH_MSG *p_push_msg = &p_cb->push_msg;
+ tBTA_MSE_OPER_SET_MSG_STS *p_set_msg_sts = &p_cb->set_msg_sts;
+ tBTA_MA_SESS_HANDLE mas_session_id;
+ UINT16 len;
+ UINT8 *p_type;
+ UINT8 *p_param;
+ UINT8 rsp_code = OBX_RSP_OK;
+ UINT8 num_hdrs;
+ BOOLEAN free_pkt = TRUE;
+ BOOLEAN send_rsp = TRUE;
+ BOOLEAN send_ok_rsp = FALSE;
+
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT2("bta_mse_ma_obx_put inst idx=%d sess idx=%d",
+ inst_idx, sess_idx);
+#endif
+
+ if (OBX_ReadTypeHdr(p_evt->p_pkt, &p_type, &len))
+ {
+ if (!memcmp(p_type, BTA_MA_HDR_TYPE_NOTIF_REG, len))
+ {
+ bta_mse_set_ma_oper(inst_idx, sess_idx, BTA_MSE_OPER_NOTIF_REG);
+ }
+ else if (!memcmp(p_type, BTA_MA_HDR_TYPE_MSG, len))
+ {
+ bta_mse_set_ma_oper(inst_idx, sess_idx, BTA_MSE_OPER_PUSH_MSG);
+ bta_mse_init_push_msg(inst_idx, sess_idx, &rsp_code);
+ if (rsp_code != OBX_RSP_OK)
+ {
+ OBX_PutRsp(p_evt->handle, rsp_code, (BT_HDR *)NULL);
+ bta_mse_clean_push_msg(inst_idx, sess_idx);
+ return;
+ }
+ }
+ else if (!memcmp(p_type, BTA_MA_HDR_TYPE_MSG_UPDATE, len))
+ {
+ bta_mse_set_ma_oper(inst_idx, sess_idx, BTA_MSE_OPER_UPDATE_INBOX);
+ }
+ else if (!memcmp(p_type, BTA_MA_HDR_TYPE_MSG_STATUS, len))
+ {
+ bta_mse_set_ma_oper(inst_idx, sess_idx, BTA_MSE_OPER_SET_MSG_STATUS);
+ bta_mse_init_set_msg_sts(inst_idx, sess_idx, &rsp_code);
+ if (rsp_code != OBX_RSP_OK)
+ {
+ OBX_PutRsp(p_evt->handle, rsp_code, (BT_HDR *)NULL);
+ bta_mse_clean_set_msg_sts(inst_idx, sess_idx);
+ return;
+ }
+ }
+ }
+
+ switch ( p_cb->oper)
+ {
+ case BTA_MSE_OPER_NOTIF_REG:
+
+ p_param = bta_mse_read_app_params(p_evt->p_pkt, BTA_MA_APH_NOTIF_STATUS, &len);
+ if (p_param)
+ {
+ p_cb->notif_reg_req.notif_status_rcv = TRUE;
+ BE_STREAM_TO_UINT8(p_cb->notif_reg_req.notif_status, p_param);
+ }
+
+ if (p_evt->param.put.final)
+ {
+ /* check end of body is included or not */
+
+ if ((num_hdrs = OBX_ReadBodyHdr(p_evt->p_pkt, &p_obx->p_start, &p_obx->offset, &p_obx->final_pkt)) &&
+ p_obx->final_pkt)
+ {
+ if (p_cb->notif_reg_req.notif_status_rcv)
+ {
+ if (!bta_mse_send_set_notif_reg(p_cb->notif_reg_req.notif_status,
+ inst_idx, sess_idx))
+ {
+ OBX_PutRsp(p_evt->handle, OBX_RSP_BAD_REQUEST, (BT_HDR *)NULL);
+ }
+ else
+ {
+ /* wait for the set notif reg response from the application*/
+ break;
+ }
+ }
+ else
+ {
+ OBX_PutRsp(p_evt->handle, OBX_RSP_BAD_REQUEST, (BT_HDR *)NULL);
+ }
+ }
+ else
+ {
+ OBX_PutRsp(p_evt->handle, OBX_RSP_BAD_REQUEST, (BT_HDR *)NULL);
+ }
+ /* if reach here this is a bad request case so clean up*/
+ bta_mse_clean_set_notif_reg(inst_idx,sess_idx);
+ }
+ else
+ {
+ OBX_PutRsp(p_evt->handle, OBX_RSP_CONTINUE, (BT_HDR *)NULL);
+ }
+
+ break;
+ case BTA_MSE_OPER_PUSH_MSG:
+
+ if ((!p_push_msg->rcv_folder_name) &&
+ (OBX_ReadUtf8NameHdr(p_evt->p_pkt, (UINT8 *)p_push_msg->param.p_folder,
+ p_bta_mse_cfg->max_name_len)))
+ {
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT2("Rcv folder len=%d, name=%s ",
+ strlen( p_push_msg->param.p_folder),
+ p_push_msg->param.p_folder);
+#endif
+ p_push_msg->rcv_folder_name = TRUE;
+ }
+
+ if (!p_push_msg->rcv_charset)
+ {
+ p_param = bta_mse_read_app_params(p_evt->p_pkt, BTA_MA_APH_CHARSET, &len);
+ if (p_param)
+ {
+
+ p_push_msg->rcv_charset = TRUE;
+ BE_STREAM_TO_UINT8(p_push_msg->param.charset, p_param);
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT1("Rcv Charset=%d(0-native 1-UTF8)",p_push_msg->param.charset);
+#endif
+ }
+ }
+
+ if (!p_push_msg->rcv_transparent)
+ {
+ p_param = bta_mse_read_app_params(p_evt->p_pkt, BTA_MA_APH_TRANSPARENT, &len);
+ if (p_param)
+ {
+ p_push_msg->rcv_transparent = TRUE;
+ BE_STREAM_TO_UINT8(p_push_msg->param.transparent, p_param);
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT1("Rcv Transparent=%d",p_push_msg->param.transparent);
+#endif
+ }
+ }
+
+ if (!p_push_msg->rcv_retry)
+ {
+ p_param = bta_mse_read_app_params(p_evt->p_pkt, BTA_MA_APH_RETRY, &len);
+ if (p_param)
+ {
+ p_push_msg->rcv_retry = TRUE;
+ BE_STREAM_TO_UINT8(p_push_msg->param.retry, p_param);
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT1("Rcv Retry=%d",p_push_msg->param.retry);
+#endif
+ }
+ }
+
+ /* Read the body header from the obx packet */
+ num_hdrs = OBX_ReadBodyHdr(p_evt->p_pkt, &p_obx->p_start, &p_obx->offset,
+ &p_obx->final_pkt);
+ /* process body or end of body header */
+ if (num_hdrs >= 1 )
+ {
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT3("Rcv Body or EndOfBody body_hdr=%d len=%d final=%d",
+ num_hdrs,
+ p_obx->offset,
+ p_obx->final_pkt);
+#endif
+
+ if (p_push_msg->rcv_charset && p_push_msg->rcv_folder_name)
+ {
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("Rcv all Required params");
+#endif
+
+ free_pkt = FALSE;
+ p_obx->p_pkt = p_evt->p_pkt;
+ if (p_push_msg->first_req_pkt)
+ {
+ p_push_msg->first_req_pkt = FALSE;
+ bta_mse_req_app_access( inst_idx, sess_idx, p_data);
+ }
+ else
+ {
+ bta_mse_pushmsg(inst_idx, sess_idx, FALSE);
+ }
+ send_rsp = FALSE;
+ }
+ else
+ {
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_ERROR0("Not all Mandatory params are rcv before body/EndofBody: bad request");
+#endif
+ rsp_code = OBX_RSP_BAD_REQUEST;
+ }
+ }
+ else
+ {
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("No Body or End of Body in this push msg pkt");
+#endif
+ }
+
+ if (!p_obx->final_pkt)
+ {
+ if (rsp_code != OBX_RSP_BAD_REQUEST)
+ {
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("Not a final pkt and no error set rsp_code=Continue");
+#endif
+ rsp_code = OBX_RSP_CONTINUE;
+ }
+ }
+
+ if (send_rsp) OBX_PutRsp(p_evt->handle, rsp_code, (BT_HDR *)NULL);
+ if (rsp_code == OBX_RSP_BAD_REQUEST )
+ {
+ if (!p_push_msg->first_req_pkt)
+ bta_mse_send_oper_cmpl_evt(inst_idx,sess_idx, BTA_MA_STATUS_FAIL);
+ bta_mse_clean_push_msg(inst_idx,sess_idx);
+ }
+ break;
+ case BTA_MSE_OPER_UPDATE_INBOX:
+
+ if (p_evt->param.put.final)
+ {
+ /* check enod of body is included or not */
+
+ if ((num_hdrs = OBX_ReadBodyHdr(p_evt->p_pkt, &p_obx->p_start, &p_obx->offset, &p_obx->final_pkt)) &&
+ p_obx->final_pkt)
+ {
+
+ mas_session_id = (tBTA_MA_SESS_HANDLE) p_cb->obx_handle;
+ bta_mse_cb.p_cback(BTA_MSE_UPDATE_INBOX_EVT, (tBTA_MSE *)&mas_session_id);
+ }
+ else
+ {
+ OBX_PutRsp(p_evt->handle, OBX_RSP_BAD_REQUEST, (BT_HDR *)NULL);
+ }
+ }
+ else
+ {
+ OBX_PutRsp(p_evt->handle, OBX_RSP_CONTINUE, (BT_HDR *)NULL);
+ }
+
+
+ break;
+ case BTA_MSE_OPER_SET_MSG_STATUS:
+
+
+ if ((!p_set_msg_sts->rcv_msg_handle) &&
+ (OBX_ReadUtf8NameHdr(p_evt->p_pkt, (UINT8 *)p_set_msg_sts->p_msg_handle,
+ BTA_MSE_64BIT_HEX_STR_SIZE)))
+ {
+ bta_ma_convert_hex_str_to_64bit_handle(p_set_msg_sts->p_msg_handle,
+ p_set_msg_sts->handle);
+ p_set_msg_sts->rcv_msg_handle = TRUE;
+ }
+
+ if (!p_set_msg_sts->rcv_sts_ind)
+ {
+ p_param = bta_mse_read_app_params(p_evt->p_pkt, BTA_MA_APH_STS_INDCTR, &len);
+ if (p_param)
+ {
+ p_set_msg_sts->rcv_sts_ind = TRUE;
+ BE_STREAM_TO_UINT8(p_set_msg_sts->sts_ind, p_param);
+ }
+ }
+
+ if (!p_set_msg_sts->rcv_sts_val)
+ {
+ p_param = bta_mse_read_app_params(p_evt->p_pkt, BTA_MA_APH_STS_VALUE, &len);
+ if (p_param)
+ {
+ p_set_msg_sts->rcv_sts_val = TRUE;
+ BE_STREAM_TO_UINT8(p_set_msg_sts->sts_val, p_param);
+ }
+ }
+
+ /* Read the body header from the obx packet */
+ num_hdrs = OBX_ReadBodyHdr(p_evt->p_pkt, &p_obx->p_start, &p_obx->offset,
+ &p_obx->final_pkt);
+ /* process body or end of body header */
+ if ((num_hdrs >= 1 && p_obx->final_pkt ) )
+ {
+ if (p_set_msg_sts->rcv_msg_handle && p_set_msg_sts->rcv_sts_ind &&
+ p_set_msg_sts->rcv_sts_val)
+ {
+ if (p_set_msg_sts->sts_ind == BTA_MA_STS_INDTR_DELETE)
+ {
+ p_cb->oper = BTA_MSE_OPER_DEL_MSG;
+ bta_mse_req_app_access( inst_idx, sess_idx, p_data);
+ }
+ else
+ {
+ if (bta_mse_co_set_msg_read_status((tBTA_MA_SESS_HANDLE) p_cb->obx_handle,
+ p_set_msg_sts->handle,
+ p_set_msg_sts->sts_val,
+ bta_mse_cb.app_id) != BTA_MA_STATUS_OK)
+ {
+ rsp_code = OBX_RSP_FORBIDDEN;
+ }
+ send_ok_rsp = TRUE;
+ }
+ }
+ else
+ {
+ rsp_code = OBX_RSP_BAD_REQUEST;
+ }
+ }
+
+ if (!p_obx->final_pkt)
+ {
+ if (rsp_code != OBX_RSP_BAD_REQUEST)
+ {
+ rsp_code = OBX_RSP_CONTINUE;
+ }
+ }
+
+ if (rsp_code != OBX_RSP_OK)
+ {
+ OBX_PutRsp(p_evt->handle, rsp_code, (BT_HDR *)NULL);
+ if (rsp_code == OBX_RSP_BAD_REQUEST )
+ {
+ bta_mse_clean_set_msg_sts(inst_idx,sess_idx);
+ }
+ }
+ else
+ {
+ if (send_ok_rsp)
+ {
+ OBX_PutRsp(p_evt->handle, rsp_code, (BT_HDR *)NULL);
+ bta_mse_clean_set_msg_sts(inst_idx,sess_idx);
+ }
+ }
+ break;
+ default:
+ OBX_PutRsp(p_evt->handle, OBX_RSP_BAD_REQUEST, (BT_HDR *)NULL);
+ break;
+ }
+
+ /* Done with Obex packet */
+ if (free_pkt) utl_freebuf((void**)&p_evt->p_pkt);
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_ma_obx_get
+**
+** Description Proceses the obx get request
+**
+** Parameters inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+** p_data - Pointer to the event data
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_ma_obx_get(UINT8 inst_idx, UINT8 sess_idx, tBTA_MSE_DATA *p_data)
+{
+ tBTA_MSE_MA_SESS_CB *p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, sess_idx);
+ tBTA_MSE_OBX_EVT *p_evt = &p_data->obx_evt;
+ UINT16 len;
+ UINT8 *p_type;
+ tBTA_MSE_MA_GET_ACT get_act = BTA_MSE_MA_GET_ACT_NONE;
+ tBTA_MSE_MA_GET_TYPE get_type = BTA_MSE_MA_GET_TYPE_NONE;
+ UINT8 rsp_code = OBX_RSP_BAD_REQUEST;
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT2("bta_mse_ma_obx_get inst idx=%d sess idx=%d",inst_idx, sess_idx);
+ APPL_TRACE_EVENT1(" oper=%d",p_cb->oper );
+#endif
+ switch (p_cb->oper)
+ {
+ case BTA_MSE_OPER_GET_FOLDER_LIST:
+ get_type = BTA_MSE_MA_GET_TYPE_CON_FOLDER_LIST;
+ break;
+ case BTA_MSE_OPER_GET_MSG_LIST:
+ get_type = BTA_MSE_MA_GET_TYPE_CON_MSG_LIST;
+ break;
+ case BTA_MSE_OPER_GET_MSG:
+ get_type = BTA_MSE_MA_GET_TYPE_CON_MSG;
+ break;
+ case BTA_MSE_OPER_NONE:
+ if (OBX_ReadTypeHdr(p_evt->p_pkt, &p_type, &len))
+ {
+ if (!memcmp(p_type, BTA_MA_HDR_TYPE_FOLDER_LIST, len))
+ {
+ get_type = BTA_MSE_MA_GET_TYPE_FOLDER_LIST;
+ }
+ else if (!memcmp(p_type, BTA_MA_HDR_TYPE_MSG_LIST, len) )
+ {
+ get_type = BTA_MSE_MA_GET_TYPE_MSG_LIST;
+ }
+ else if (!memcmp(p_type, BTA_MA_HDR_TYPE_MSG, len) )
+ {
+
+ get_type = BTA_MSE_MA_GET_TYPE_MSG;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT1("bta_mse_ma_obx_get get_type=%d",get_type);
+#endif
+ switch (get_type)
+ {
+ case BTA_MSE_MA_GET_TYPE_FOLDER_LIST:
+ bta_mse_ma_fl_read_app_params(inst_idx, sess_idx, p_evt->p_pkt);
+ get_act = BTA_MSE_MA_GET_ACT_NEW_FOLDER_LIST;
+ break;
+
+ case BTA_MSE_MA_GET_TYPE_MSG_LIST:
+ if (!p_cb->ml_param.p_name)
+ {
+ p_cb->ml_param.p_name = (char *)GKI_getbuf((UINT16)(p_bta_mse_cfg->max_name_len + 1));
+ }
+
+ if (!p_cb->ml_param.p_path)
+ {
+ p_cb->ml_param.p_path = (char *)GKI_getbuf((UINT16)(p_bta_fs_cfg->max_path_len + 1));
+ }
+
+ if ((p_cb->ml_param.p_name != NULL) && (p_cb->ml_param.p_path != NULL))
+ {
+ if (!OBX_ReadUtf8NameHdr(p_evt->p_pkt, (UINT8 *)p_cb->ml_param.p_name,
+ p_bta_mse_cfg->max_name_len))
+ {
+ rsp_code = OBX_RSP_BAD_REQUEST;
+ break;
+ }
+ else
+ {
+ if (!bta_mse_get_msglist_path(inst_idx, sess_idx))
+ {
+ rsp_code = OBX_RSP_NOT_FOUND;
+ break;
+ }
+ }
+ }
+ else
+ {
+ rsp_code = OBX_RSP_INTRNL_SRVR_ERR;
+ break;
+ }
+
+ bta_mse_ma_ml_read_app_params(inst_idx, sess_idx,p_evt->p_pkt);
+ get_act = BTA_MSE_MA_GET_ACT_NEW_MSG_LIST;
+ break;
+
+ case BTA_MSE_MA_GET_TYPE_MSG:
+
+ if (!p_cb->msg_param.p_msg_handle)
+ {
+ if ((p_cb->msg_param.p_msg_handle = (char *)GKI_getbuf((UINT16)(BTA_MSE_64BIT_HEX_STR_SIZE))) == NULL )
+ {
+ rsp_code = OBX_RSP_INTRNL_SRVR_ERR;
+ get_act = BTA_MSE_MA_GET_ACT_ERR;
+ break;
+ }
+ }
+
+ if (OBX_ReadUtf8NameHdr(p_evt->p_pkt, (UINT8 *)p_cb->msg_param.p_msg_handle,
+ BTA_MSE_64BIT_HEX_STR_SIZE))
+ {
+ bta_ma_convert_hex_str_to_64bit_handle(p_cb->msg_param.p_msg_handle,
+ p_cb->msg_param.data.handle);
+ }
+ else
+ {
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("Unable to decode or find Name Header for Message Handle");
+#endif
+
+ get_act = BTA_MSE_MA_GET_ACT_ERR;
+ break;
+ }
+
+ if (!bta_mse_ma_msg_read_app_params(inst_idx, sess_idx, p_evt->p_pkt))
+ {
+ get_act = BTA_MSE_MA_GET_ACT_ERR;
+ break;
+ }
+ get_act = BTA_MSE_MA_GET_ACT_NEW_MSG;
+ break;
+
+ case BTA_MSE_MA_GET_TYPE_CON_FOLDER_LIST:
+ get_act = BTA_MSE_MA_GET_ACT_CON_FOLDER_LIST;
+ break;
+
+ case BTA_MSE_MA_GET_TYPE_CON_MSG_LIST:
+ get_act = BTA_MSE_MA_GET_ACT_CON_MSG_LIST;
+ break;
+
+ case BTA_MSE_MA_GET_TYPE_CON_MSG:
+ get_act = BTA_MSE_MA_GET_ACT_CON_MSG;
+ break;
+ default:
+ break;
+ }
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT1(" get_act=%d",get_act);
+#endif
+ switch (get_act)
+ {
+ case BTA_MSE_MA_GET_ACT_NEW_FOLDER_LIST:
+ bta_mse_set_ma_oper(inst_idx, sess_idx, BTA_MSE_OPER_GET_FOLDER_LIST);
+ bta_mse_getfolderlist(inst_idx,sess_idx, TRUE);
+ break;
+ case BTA_MSE_MA_GET_ACT_CON_FOLDER_LIST:
+ bta_mse_getfolderlist(inst_idx,sess_idx, FALSE);
+ break;
+
+ case BTA_MSE_MA_GET_ACT_NEW_MSG_LIST:
+ bta_mse_set_ma_oper(inst_idx, sess_idx, BTA_MSE_OPER_GET_MSG_LIST);
+ bta_mse_req_app_access( inst_idx, sess_idx, p_data);
+ break;
+ case BTA_MSE_MA_GET_ACT_CON_MSG_LIST:
+ bta_mse_getmsglist(inst_idx,sess_idx, FALSE);
+ break;
+
+ case BTA_MSE_MA_GET_ACT_NEW_MSG:
+ bta_mse_set_ma_oper(inst_idx, sess_idx, BTA_MSE_OPER_GET_MSG);
+ if (p_cb->msg_param.data.fraction_request == BTA_MA_FRAC_REQ_FIRST ||
+ p_cb->msg_param.data.fraction_request == BTA_MA_FRAC_REQ_NEXT)
+ {
+ p_cb->msg_param.add_frac_del_hdr = TRUE;
+ }
+ p_cb->msg_param.byte_get_cnt = 0;
+ bta_mse_req_app_access( inst_idx, sess_idx, p_data);
+ break;
+ case BTA_MSE_MA_GET_ACT_CON_MSG:
+ bta_mse_getmsg(inst_idx,sess_idx, FALSE);
+ break;
+
+ case BTA_MSE_MA_GET_ACT_ERR:
+ default:
+ OBX_GetRsp(p_evt->handle, rsp_code, (BT_HDR *)NULL);
+ utl_freebuf((void**)&p_cb->ml_param.p_name);
+ utl_freebuf((void**)&p_cb->ml_param.p_path);
+ break;
+ }
+ /* Done with Obex packet */
+ utl_freebuf((void**)&p_evt->p_pkt);
+}
+/*******************************************************************************
+**
+** Function bta_mse_ma_obx_setpath
+**
+** Description Proceses the obx setpath request
+**
+** Parameters inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+** p_data - Pointer to the event data
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_ma_obx_setpath(UINT8 inst_idx, UINT8 sess_idx, tBTA_MSE_DATA *p_data)
+{
+
+ tBTA_MSE_MA_SESS_CB *p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, sess_idx);
+ tBTA_MSE_OBX_EVT *p_evt = &p_data->obx_evt;
+ tBTA_MA_DIR_NAV flags = (tBTA_MA_DIR_NAV)p_evt->param.sp.flag;
+ UINT8 rsp_code = OBX_RSP_BAD_REQUEST;
+ tBTA_MSE_OPER mse_oper = BTA_MSE_OPER_NONE;
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT2("bta_mse_ma_obx_setpath inst idx=%d sess idx=%d",
+ inst_idx, sess_idx);
+ APPL_TRACE_EVENT1(" flags=%d ", flags);
+#endif
+
+ /* Verify flags and handle before accepting */
+ if ((flags == BTA_MA_DIR_NAV_ROOT_OR_DOWN_ONE_LVL) ||
+ (flags == BTA_MA_DIR_NAV_UP_ONE_LVL))
+ {
+
+ p_cb->sp.p_path = (char *)GKI_getbuf((UINT16)(p_bta_fs_cfg->max_path_len + 1));
+ p_cb->sp.p_name = (char *)GKI_getbuf((UINT16)(p_bta_mse_cfg->max_name_len + 1));
+ if (p_cb->sp.p_name != NULL )
+ {
+ p_cb->sp.flags = flags;
+
+ if (!OBX_ReadUtf8NameHdr(p_evt->p_pkt, (UINT8 *)p_cb->sp.p_name,
+ p_bta_fs_cfg->max_path_len))
+ {
+ p_cb->sp.p_name[0] = '\0';
+ }
+
+ rsp_code = bta_mse_chdir( inst_idx, sess_idx, &mse_oper);
+
+ }
+ else
+ {
+ rsp_code = OBX_RSP_INTRNL_SRVR_ERR;
+ }
+ }
+
+ bta_mse_set_ma_oper(inst_idx, sess_idx, mse_oper);
+ if (mse_oper != BTA_MSE_OPER_NONE)
+ {
+ bta_mse_req_app_access( inst_idx, sess_idx, p_data);
+ }
+ else
+ {
+ OBX_SetPathRsp(p_evt->handle, rsp_code, (BT_HDR *)NULL);
+ utl_freebuf((void**)&p_cb->sp.p_name);
+ }
+
+ /* Done with Obex packet */
+ utl_freebuf((void**)&p_evt->p_pkt);
+}
+/*******************************************************************************
+**
+** Function bta_mse_ma_conn_err_rsp
+**
+** Description Proceses the inavlid obx connection request
+**
+** Parameters inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+** p_data - Pointer to the event data
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_ma_conn_err_rsp(UINT8 inst_idx, UINT8 sess_idx, tBTA_MSE_DATA *p_data)
+{
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT2("bta_mse_ma_conn_err_rsp inst idx=%d sess idx=%d",inst_idx, sess_idx);
+#endif
+
+ OBX_ConnectRsp(p_data->obx_evt.handle, OBX_RSP_BAD_REQUEST, (BT_HDR *)NULL);
+ /* Done with Obex packet */
+ utl_freebuf((void**)&(p_data->obx_evt.p_pkt));
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_ma_close_complete
+**
+** Description Proceses the connection close complete event.
+**
+** Parameters inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+** p_data - Pointer to the event data
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_ma_close_complete(UINT8 inst_idx, UINT8 sess_idx, tBTA_MSE_DATA *p_data)
+{
+ tBTA_MSE_MA_CB *p_scb = BTA_MSE_GET_INST_CB_PTR(inst_idx);
+ tBTA_MSE_MA_SESS_CB *p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, sess_idx);
+ tBTA_MSE cback_evt_data;
+ tBTA_MSE *p_cevt = &cback_evt_data;
+ UINT8 num_act_mas=0, num_act_sess=0, i;
+ tBTA_MA_STATUS clean_getput_status = BTA_MA_STATUS_OK;
+ UINT8 ccb_idx;
+ BD_ADDR bd_addr;
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT2("bta_mse_ma_close_complete inst idx=%d sess idx=%d",inst_idx, sess_idx);
+#endif
+
+
+ p_cb->cout_active = FALSE;
+
+ if (p_cb->aborting) clean_getput_status = BTA_MA_STATUS_ABORTED;
+ bta_mse_clean_getput(inst_idx, sess_idx, clean_getput_status);
+ utl_freebuf((void**)&p_cb->p_workdir);
+
+ /* inform role manager */
+
+ bta_mse_pm_conn_close(p_cb->bd_addr);
+ bdcpy(bd_addr, p_cb->bd_addr);
+ memset(p_cb->bd_addr, 0, BD_ADDR_LEN);
+ p_cb->peer_mtu = 0;
+
+ /* We now done with the close this seesion so issue a BTA_MSE_MA_CLOSE_EVT*/
+ p_cevt->ma_close.mas_session_id = p_cb->obx_handle;
+ p_cevt->ma_close.mas_instance_id = p_scb->mas_inst_id;
+ p_cevt->ma_close.status = BTA_MA_STATUS_OK ;
+ bta_mse_cb.p_cback(BTA_MSE_MA_CLOSE_EVT, (tBTA_MSE *) p_cevt);
+
+
+ /* turn off the registration status for the associated MAs instance
+ and also check whether MN connection needs to be closed or not */
+ if (bta_mse_find_bd_addr_match_mn_cb_index(bd_addr, &ccb_idx) &&
+ bta_mse_mn_is_inst_id_exist(ccb_idx, p_scb->mas_inst_id))
+ {
+ bta_mse_mn_remove_inst_id(ccb_idx, p_scb->mas_inst_id);
+ if (!bta_mse_mn_find_num_of_act_inst_id(ccb_idx))
+ {
+ bta_mse_mn_sm_execute(ccb_idx,BTA_MSE_MN_INT_CLOSE_EVT, NULL);
+ }
+ }
+
+ /* Check Any MAS instance need to be stopped */
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT2("stopping=%d MAS in use=%d", p_scb->stopping,p_scb->in_use);
+#endif
+ if (p_scb->stopping && p_scb->in_use)
+ {
+ num_act_sess = 0;
+ for (i=0; i < BTA_MSE_NUM_SESS; i ++)
+ {
+ p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, i);
+ if (p_cb->state != BTA_MSE_MA_LISTEN_ST)
+ num_act_sess++;
+ }
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT1("num_act_sess=%d ", num_act_sess);
+#endif
+ if (!num_act_sess)
+ {
+ p_cevt->stop.status = BTA_MA_STATUS_OK;
+ p_cevt->stop.mas_instance_id = p_scb->mas_inst_id;
+ bta_mse_cb.p_cback(BTA_MSE_STOP_EVT, (tBTA_MSE *) p_cevt);
+ bta_mse_clean_mas_service(inst_idx);
+ }
+ }
+
+ if (bta_mse_cb.disabling && bta_mse_cb.enable)
+ {
+ num_act_mas=0;
+ for (i=0; i < BTA_MSE_NUM_INST ; i ++)
+ {
+ p_scb = BTA_MSE_GET_INST_CB_PTR(i);
+ if (p_scb->in_use )
+ num_act_mas++;
+ }
+
+ if (!num_act_mas)
+ {
+ bta_mse_cb.enable = FALSE;
+ p_cevt->disable.status = BTA_MA_STATUS_OK;
+ p_cevt->disable.app_id = bta_mse_cb.app_id;
+ bta_mse_cb.p_cback(BTA_MSE_DISABLE_EVT, (tBTA_MSE *) p_cevt);
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("MSE Disabled location-2");
+#endif
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_ignore_obx
+**
+** Description Ignores the obx event
+**
+** Parameters inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+** p_data - Pointer to the event data
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_ignore_obx(UINT8 inst_idx, UINT8 sess_idx, tBTA_MSE_DATA *p_data)
+{
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT2("bta_mse_ignore_obx inst idx=%d sess idx=%d",inst_idx, sess_idx);
+#endif
+
+ utl_freebuf((void**)&p_data->obx_evt.p_pkt);
+}
+/*******************************************************************************
+**
+** Function bta_mse_ma_obx_cback
+**
+** Description OBX callback function for MA.
+**
+** Parameters handle - Handle for Obex session
+** obx_event - Obex event
+** param - event parameters
+** p_pkt - pointer to Obex packet
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_ma_obx_cback (tOBX_HANDLE handle, tOBX_EVENT obx_event,
+ tOBX_EVT_PARAM param, BT_HDR *p_pkt)
+{
+ tBTA_MSE_OBX_EVT *p_obx_msg;
+ UINT16 event = 0;
+
+ switch (obx_event)
+ {
+ case OBX_CONNECT_REQ_EVT:
+ event = BTA_MSE_MA_OBX_CONN_EVT;
+ break;
+ case OBX_DISCONNECT_REQ_EVT:
+ event = BTA_MSE_MA_OBX_DISC_EVT;
+ break;
+ case OBX_PUT_REQ_EVT:
+ event = BTA_MSE_MA_OBX_PUT_EVT;
+ break;
+ case OBX_GET_REQ_EVT:
+ event = BTA_MSE_MA_OBX_GET_EVT;
+ break;
+ case OBX_SETPATH_REQ_EVT:
+ event = BTA_MSE_MA_OBX_SETPATH_EVT;
+ break;
+ case OBX_ABORT_REQ_EVT:
+ event = BTA_MSE_MA_OBX_ABORT_EVT;
+ break;
+ case OBX_CLOSE_IND_EVT:
+ event = BTA_MSE_MA_OBX_CLOSE_EVT;
+ break;
+ case OBX_TIMEOUT_EVT:
+ break;
+ case OBX_PASSWORD_EVT:
+ break;
+ default:
+ /* Unrecognized packet; disconnect the session */
+ if (p_pkt)
+ event = BTA_MSE_MA_OBX_DISC_EVT;
+ }
+
+ /* send event to BTA, if any */
+ if (event && (p_obx_msg =
+ (tBTA_MSE_OBX_EVT *) GKI_getbuf(sizeof(tBTA_MSE_OBX_EVT))) != NULL)
+ {
+#if (BTA_MSE_DEBUG == TRUE) && (BT_USE_TRACES == TRUE)
+ APPL_TRACE_DEBUG1("MA OBX Event Callback: mse_obx_event [%s]", bta_mse_obx_evt_code(event));
+#endif
+ p_obx_msg->hdr.event = event;
+ p_obx_msg->obx_event = obx_event;
+ p_obx_msg->handle = handle;
+ p_obx_msg->param = param;
+ p_obx_msg->p_pkt = p_pkt;
+ p_obx_msg->hdr.layer_specific = 0xFFFF;
+
+ bta_sys_sendmsg(p_obx_msg);
+ }
+}
+/*******************************************************************************
+** Message Notification Client (MNC) Action functions
+**
+*******************************************************************************/
+/******************************************************************************
+**
+** Function bta_mse_mn_sdp_cback
+**
+** Description This is the SDP callback function used by MSE.
+** This function will be executed by SDP when the service
+** search is completed. If the search is successful, it
+** finds the first record in the database that matches the
+** UUID of the search. Then retrieves the scn from the
+** record.
+**
+** Parameters ccb_idx - Index to the MN control block
+** status - status of the SDP callabck
+**
+** Returns void.
+**
+******************************************************************************/
+static void bta_mse_mn_sdp_cback(UINT8 ccb_idx, UINT16 status)
+{
+ tBTA_MSE_MN_CB *p_cb = BTA_MSE_GET_MN_CB_PTR(ccb_idx);
+ tBTA_MSE_MN_SDP_OK *p_buf;
+ tSDP_DISC_REC *p_rec = NULL;
+ tSDP_PROTOCOL_ELEM pe;
+ UINT8 scn = 0;
+ BOOLEAN found = FALSE;
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT1("bta_mse_mn_sdp_cback status:%d", status);
+#endif
+ if (status == SDP_SUCCESS || status == SDP_DB_FULL)
+ {
+ /* loop through all records we found */
+ do
+ {
+ /* get next record; if none found, we're done */
+ if ((p_rec = SDP_FindServiceInDb(p_cb->p_db, p_cb->sdp_service,
+ p_rec)) == NULL)
+ {
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("SDP Not Found");
+#endif
+ break;
+ }
+
+ /* get scn from proto desc list; if not found, go to next record */
+ if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe))
+ {
+ found = TRUE;
+ scn = (UINT8) pe.params[0];
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT1("SDP found scn=%d", scn);
+#endif
+ /* we've got everything, we're done */
+ break;
+ }
+ else
+ continue;
+ } while (TRUE);
+ }
+
+ /* send result in event back to BTA */
+ if ((p_buf = (tBTA_MSE_MN_SDP_OK *) GKI_getbuf(sizeof(tBTA_MSE_MN_SDP_OK))) != NULL)
+ {
+ p_buf->hdr.event = BTA_MSE_MN_SDP_FAIL_EVT;
+ p_buf->ccb_idx = ccb_idx;
+ if (status == SDP_SUCCESS || status == SDP_DB_FULL)
+ {
+ if (found == TRUE)
+ {
+ p_buf->hdr.event = BTA_MSE_MN_SDP_OK_EVT;
+ p_buf->scn = scn;
+ }
+ else
+ {
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("SDP 1 BTA_MSE_MN_SDP_FAIL_EVT");
+#endif
+ }
+ }
+ else
+ {
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("SDP 2 BTA_MSE_MN_SDP_FAIL_EVT");
+#endif
+ }
+
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/******************************************************************************
+**
+** Function bta_mse_mn_sdp_cback0
+**
+** Description This is the SDP callback function used by MN indx = 0
+**
+** Parameters status - status of the SDP callabck
+**
+** Returns void.
+**
+******************************************************************************/
+static void bta_mse_mn_sdp_cback0(UINT16 status)
+{
+ bta_mse_mn_sdp_cback(0, status);
+}
+
+/******************************************************************************
+**
+** Function bta_mse_mn_sdp_cback1
+**
+** Description This is the SDP callback function used by MN indx = 1
+**
+** Parameters status - status of the SDP callabck
+**
+** Returns void.
+**
+******************************************************************************/
+static void bta_mse_mn_sdp_cback1(UINT16 status)
+{
+ bta_mse_mn_sdp_cback(1, status);
+}
+
+/******************************************************************************
+**
+** Function bta_mse_mn_sdp_cback2
+**
+** Description This is the SDP callback function used by MN indx = 2
+**
+** Parameters status - status of the SDP callabck
+**
+** Returns void.
+**
+******************************************************************************/
+static void bta_mse_mn_sdp_cback2(UINT16 status)
+{
+ bta_mse_mn_sdp_cback(2, status);
+}
+
+/******************************************************************************
+**
+** Function bta_mse_mn_sdp_cback3
+**
+** Description This is the SDP callback function used by MN indx = 3
+**
+** Parameters status - status of the SDP callabck
+**
+** Returns void.
+**
+******************************************************************************/
+static void bta_mse_mn_sdp_cback3(UINT16 status)
+{
+ bta_mse_mn_sdp_cback(3, status);
+}
+
+/******************************************************************************
+**
+** Function bta_mse_mn_sdp_cback4
+**
+** Description This is the SDP callback function used by MN indx = 4
+**
+** Parameters status - status of the SDP callabck
+**
+** Returns void.
+**
+******************************************************************************/
+static void bta_mse_mn_sdp_cback4(UINT16 status)
+{
+ bta_mse_mn_sdp_cback(4, status);
+}
+
+/******************************************************************************
+**
+** Function bta_mse_mn_sdp_cback5
+**
+** Description This is the SDP callback function used by MN indx = 5
+**
+** Parameters status - status of the SDP callabck
+**
+** Returns void.
+**
+******************************************************************************/
+static void bta_mse_mn_sdp_cback5(UINT16 status)
+{
+ bta_mse_mn_sdp_cback(5, status);
+}
+
+/******************************************************************************
+**
+** Function bta_mse_mn_sdp_cback6
+**
+** Description This is the SDP callback function used by MN indx = 6
+**
+** Parameters status - status of the SDP callabck
+**
+** Returns void.
+**
+******************************************************************************/
+static void bta_mse_mn_sdp_cback6(UINT16 status)
+{
+ bta_mse_mn_sdp_cback(6, status);
+}
+/*******************************************************************************
+**
+** Function bta_mse_mn_init_sdp
+**
+** Description Initialize SDP on message notification server device.
+**
+** Parameters ccb_idx - Index to the MN control block
+** p_data - Pointer to the MN event data
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_mn_init_sdp(UINT8 ccb_idx, tBTA_MSE_DATA *p_data)
+{
+ tBTA_MSE_MN_CB *p_cb = &(bta_mse_cb.ccb[ccb_idx]);
+ tBTA_MSE_MN_INT_OPEN *p_evt = &p_data->mn_int_open;
+
+ tSDP_UUID uuid_list;
+ UINT16 attr_list[3];
+ UINT16 num_attrs = 2;
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("bta_mse_mn_init_sdp");
+#endif
+
+ p_cb->in_use = TRUE;
+ p_cb->sec_mask = p_evt->sec_mask;
+ bdcpy(p_cb->bd_addr,p_evt->bd_addr);
+ p_cb->sdp_pending = TRUE;
+ p_cb->sdp_cback = bta_mse_mn_sdp_cback_arr[ccb_idx];
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT6("SDP INIT BD_ADDR= %x:%x:%x:%x:%x:%x",
+ p_cb->bd_addr[0],
+ p_cb->bd_addr[1],
+ p_cb->bd_addr[2],
+ p_cb->bd_addr[3],
+ p_cb->bd_addr[4],
+ p_cb->bd_addr[5]);
+#endif
+
+ if ((p_cb->p_db = (tSDP_DISCOVERY_DB *) GKI_getbuf(BTA_MSE_MN_DISC_SIZE)) != NULL)
+ {
+ attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST;
+ attr_list[1] = ATTR_ID_PROTOCOL_DESC_LIST;
+
+ uuid_list.len = LEN_UUID_16;
+
+ p_cb->sdp_service = UUID_SERVCLASS_MESSAGE_NOTIFICATION;
+ uuid_list.uu.uuid16 = UUID_SERVCLASS_MESSAGE_NOTIFICATION;
+
+ SDP_InitDiscoveryDb(p_cb->p_db, BTA_MSE_MN_DISC_SIZE, 1, &uuid_list, num_attrs, attr_list);
+ if (!SDP_ServiceSearchAttributeRequest(p_cb->bd_addr, p_cb->p_db, p_cb->sdp_cback))
+ {
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("SDP Init failed ");
+#endif
+ bta_mse_mn_sm_execute(ccb_idx, BTA_MSE_MN_SDP_FAIL_EVT, p_data);
+ }
+ else
+ {
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("SDP Init Success ");
+#endif
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_mn_start_client
+**
+** Description Starts the OBEX client for Message Notification service.
+**
+** Parameters ccb_idx - Index to the MN control block
+** p_data - Pointer to the MN event data
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_mn_start_client(UINT8 ccb_idx, tBTA_MSE_DATA *p_data)
+{
+
+ tBTA_MSE_MN_CB *p_cb = BTA_MSE_GET_MN_CB_PTR(ccb_idx);
+ tBTA_MSE_OBX_PKT *p_obx = &p_cb->obx;
+ BOOLEAN connect_fail = TRUE;
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT1("bta_mse_mn_start_client ccb idx=%d ",ccb_idx);
+#endif
+
+ /* free discovery data base */
+ utl_freebuf((void**)&p_cb->p_db);
+ p_cb->sdp_pending = FALSE;
+ /* Allocate an OBX packet */
+ if ((p_obx->p_pkt = (BT_HDR *)OBX_HdrInit(OBX_HANDLE_NULL, OBX_CMD_POOL_SIZE)) != NULL)
+ {
+ /* set security level */
+ BTM_SetSecurityLevel (TRUE, "BTA_MNC", BTM_SEC_SERVICE_MAP,
+ p_cb->sec_mask, BT_PSM_RFCOMM,
+ BTM_SEC_PROTO_RFCOMM, p_data->mn_sdp_ok.scn);
+
+ if (p_cb->sdp_service == UUID_SERVCLASS_MESSAGE_NOTIFICATION)
+ {
+ OBX_AddTargetHdr(p_obx->p_pkt, (UINT8 *)BTA_MAS_MESSAGE_NOTIFICATION_TARGET_UUID,
+ BTA_MAS_UUID_LENGTH);
+ }
+ if (OBX_ConnectReq(p_cb->bd_addr, p_data->mn_sdp_ok.scn, OBX_MAX_MTU,
+ bta_mse_mn_obx_cback, &p_cb->obx_handle, p_obx->p_pkt) == OBX_SUCCESS)
+ {
+ p_obx->p_pkt = NULL; /* OBX will free the memory */
+ connect_fail = FALSE;
+ }
+ else
+ {
+ utl_freebuf((void**)&p_obx->p_pkt);
+ }
+ }
+
+ if (connect_fail)
+ {
+ bta_mse_mn_sm_execute(ccb_idx, BTA_MSE_MN_OBX_CLOSE_EVT, p_data);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_mn_rsp_timeout
+**
+** Description Process the OBX response timeout event
+**
+** Parameters ccb_idx - Index to the MN control block
+** p_data - Pointer to the MN event data
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_mn_rsp_timeout(UINT8 ccb_idx, tBTA_MSE_DATA *p_data)
+{
+ tBTA_MSE_MN_CB *p_cb = BTA_MSE_GET_MN_CB_PTR(ccb_idx);
+
+ if (p_cb->timer_oper == BTA_MSE_TIMER_OP_ABORT)
+ {
+ /* Start stop response timer */
+ bta_mse_mn_start_timer(ccb_idx, BTA_MSE_TIMER_OP_STOP);
+
+ OBX_DisconnectReq(p_cb->obx_handle, NULL);
+ }
+ else /* Timeout waiting for disconnect response */
+ {
+ bta_mse_mn_sm_execute(ccb_idx, BTA_MSE_MN_OBX_CLOSE_EVT, p_data);
+
+ }
+}
+/*******************************************************************************
+**
+** Function bta_mse_mn_stop_client
+**
+** Description Stop the OBX client for Message Notification service.
+**
+** Parameters ccb_idx - Index to the MN control block
+** p_data - Pointer to the MN event data
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_mn_stop_client(UINT8 ccb_idx, tBTA_MSE_DATA *p_data)
+{
+ tBTA_MSE_MN_CB *p_cb = BTA_MSE_GET_MN_CB_PTR(ccb_idx);
+
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT1("bta_mse_mn_stop_client ccb idx=%d ",ccb_idx);
+#endif
+
+ if (!p_cb->sdp_pending)
+ {
+ /* Start stop response timer */
+ bta_mse_mn_start_timer(ccb_idx, BTA_MSE_TIMER_OP_STOP);
+ OBX_DisconnectReq(p_cb->obx_handle, NULL);
+ }
+ else
+ {
+ APPL_TRACE_WARNING0("bta_mase_mn_stop_client: Waiting for SDP to complete");
+ }
+}
+/*******************************************************************************
+**
+** Function bta_mse_mn_obx_conn_rsp
+**
+** Description Process OBX connection response.
+**
+** Parameters ccb_idx - Index to the MN control block
+** p_data - Pointer to the MN event data
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_mn_obx_conn_rsp(UINT8 ccb_idx, tBTA_MSE_DATA *p_data)
+{
+ tBTA_MSE_MN_CB *p_cb = BTA_MSE_GET_MN_CB_PTR(ccb_idx);
+ tBTA_MSE_OBX_EVT *p_evt = &p_data->obx_evt;
+ tBTA_MSE param;
+ UINT8 mas_insatnce_id;
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT1("bta_mse_mn_obx_conn_rsp ccb idx=%d ",ccb_idx);
+#endif
+
+ p_cb->peer_mtu = p_data->obx_evt.param.conn.mtu;
+ p_cb->obx_handle = p_evt->handle;
+
+ if (p_cb->sdp_service == UUID_SERVCLASS_MESSAGE_NOTIFICATION)
+ {
+ bdcpy(param.mn_open.bd_addr ,p_cb->bd_addr);
+ BCM_STRNCPY_S((char *)param.mn_open.dev_name, sizeof(param.mn_open.dev_name), "",
+ BTM_MAX_REM_BD_NAME_LEN);
+ if (bta_mse_mn_get_first_inst_id(ccb_idx, &mas_insatnce_id))
+ {
+ param.mn_open.first_mas_instance_id = mas_insatnce_id;
+ }
+ else
+ {
+ APPL_TRACE_ERROR0("Unable to find the first instance ID");
+ }
+ }
+
+ /* inform role manager */
+ bta_mse_pm_conn_open(p_cb->bd_addr);
+
+ bta_mse_cb.p_cback(BTA_MSE_MN_OPEN_EVT, &param);
+
+ /* Done with Obex packet */
+ utl_freebuf((void**)&p_evt->p_pkt);
+}
+/*******************************************************************************
+**
+** Function bta_mse_mn_close
+**
+** Description Process the connection close event.
+**
+** Parameters ccb_idx - Index to the MN control block
+** p_data - Pointer to the MN event data
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_mn_close(UINT8 ccb_idx, tBTA_MSE_DATA *p_data)
+{
+ tBTA_MSE_MN_CB *p_cb = BTA_MSE_GET_MN_CB_PTR(ccb_idx);
+
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT1("bta_mse_mn_close ccb idx=%d ",ccb_idx);
+#endif
+
+ bta_mse_mn_remove_all_inst_ids(ccb_idx);
+
+ /* finished if not waiting on a call-in function */
+ if (!p_cb->sdp_pending && !p_cb->cout_active)
+ bta_mse_mn_sm_execute(ccb_idx, BTA_MSE_MN_CLOSE_CMPL_EVT, p_data);
+}
+/*******************************************************************************
+**
+** Function bta_mse_mn_send_notif
+**
+** Description Process send notification request
+**
+** Parameters ccb_idx - Index to the MN control block
+** p_data - Pointer to the MN event data
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_mn_send_notif(UINT8 ccb_idx, tBTA_MSE_DATA *p_data)
+{
+ tBTA_MSE_MN_CB *p_cb = BTA_MSE_GET_MN_CB_PTR(ccb_idx);
+ tBTA_MSE_MN_API_SEND_NOTIF *p_evt = &p_data->mn_send_notif;
+ UINT8 *p_buffer;
+ UINT16 buffer_len;
+ tBTA_MA_STATUS status = BTA_MA_STATUS_FAIL;
+
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT1("bta_mse_mn_send_notif ccb_idx=%d ",ccb_idx);
+#endif
+
+ if ( (p_cb->req_pending == TRUE) &&
+ (p_cb->obx_oper == BTA_MSE_MN_OP_PUT_EVT_RPT))
+ {
+ /* only one pending request per Obex connection is allowed */
+ bta_mse_mn_send_notif_evt(p_evt->mas_instance_id,
+ BTA_MA_STATUS_NO_RESOURCE,
+ p_cb->bd_addr);
+ return;
+ }
+
+ memset(&(p_cb->msg_notif), 0, sizeof(tBTA_MSE_MN_MSG_NOTIF));
+
+ if ((p_buffer = (UINT8 *)GKI_getbuf(BTA_MSE_MN_MAX_MSG_EVT_OBECT_SIZE)) != NULL)
+ {
+ /* Build the Message Event Object */
+ buffer_len = BTA_MSE_MN_MAX_MSG_EVT_OBECT_SIZE;
+ status = bta_mse_build_map_event_rpt_obj( p_evt->notif_type,
+ p_evt->handle,
+ p_evt->p_folder,
+ p_evt->p_old_folder,
+ p_evt->msg_type,
+ &buffer_len,
+ p_buffer);
+ if (status == BTA_MA_STATUS_OK)
+ {
+ p_cb->msg_notif.p_buffer = p_buffer;
+ p_cb->msg_notif.buffer_len = buffer_len;
+ p_cb->msg_notif.bytes_sent = 0;
+ p_cb->msg_notif.mas_instance_id = p_evt->mas_instance_id;
+ status = bta_mse_mn_cont_send_notif(ccb_idx, TRUE);
+ }
+ }
+
+ if ( status != BTA_MA_STATUS_OK)
+ {
+ bta_mse_mn_send_notif_evt(p_evt->mas_instance_id,
+ BTA_MA_STATUS_NO_RESOURCE,
+ p_cb->bd_addr);
+ bta_mse_mn_clean_send_notif(ccb_idx);
+ }
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT1("status=%d ",status );
+#endif
+}
+/*******************************************************************************
+**
+** Function bta_mse_mn_put_rsp
+**
+** Description Process the obx PUT response.
+**
+** Parameters ccb_idx - Index to the MN control block
+** p_data - Pointer to the MN event data
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_mn_put_rsp(UINT8 ccb_idx, tBTA_MSE_DATA *p_data)
+{
+ tBTA_MSE_MN_CB *p_cb = BTA_MSE_GET_MN_CB_PTR(ccb_idx);
+ tBTA_MSE_OBX_EVT *p_evt = &p_data->obx_evt;
+ tBTA_MSE_MN_MSG_NOTIF *p_msg_notif = &p_cb->msg_notif;
+ tBTA_MA_STATUS status = BTA_MA_STATUS_FAIL;
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT2("bta_mse_mn_put_rsp ccb idx=%d rsp_code=%d",
+ ccb_idx, p_evt->rsp_code);
+#endif
+
+ p_cb->req_pending = FALSE;
+ /* Done with Obex packet */
+ utl_freebuf((void**)&p_evt->p_pkt);
+
+ if (p_cb->obx_oper == BTA_MSE_MN_OP_PUT_EVT_RPT)
+ {
+ /* If not finished with Put, start another read */
+ if (p_evt->rsp_code == OBX_RSP_CONTINUE)
+ bta_mse_mn_cont_send_notif(ccb_idx, FALSE);
+ else
+ {
+ /* done with obex operation */
+ if ( p_evt->rsp_code == OBX_RSP_OK ) status = BTA_MA_STATUS_OK;
+ bta_mse_mn_send_notif_evt(p_msg_notif->mas_instance_id, status,
+ p_cb->bd_addr);
+ bta_mse_mn_clean_send_notif(ccb_idx);
+ }
+ }
+}
+/*******************************************************************************
+**
+** Function bta_mse_mn_close_compl
+**
+** Description Process the close complete event.
+**
+** Parameters ccb_idx - Index to the MN control block
+** p_data - Pointer to the MN event data
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_mn_close_compl(UINT8 ccb_idx, tBTA_MSE_DATA *p_data)
+{
+ tBTA_MSE_MN_CB *p_cb = BTA_MSE_GET_MN_CB_PTR(ccb_idx);
+ tBTA_MSE param;
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT1("bta_mse_mn_close_compl ccb idx=%d ",ccb_idx);
+#endif
+
+ /* free discovery data base */
+ utl_freebuf((void**)&p_cb->p_db);
+ p_cb->sdp_pending = FALSE;
+
+ p_cb->cout_active = FALSE;
+ bta_mse_mn_stop_timer(ccb_idx, BTA_MSE_TIMER_OP_ALL);
+ bta_mse_mn_clean_send_notif(ccb_idx);
+ /* inform role manager */
+ bta_mse_pm_conn_close(p_cb->bd_addr);
+ bdcpy(param.mn_close.bd_addr ,p_cb->bd_addr);
+ bta_mse_cb.p_cback(BTA_MSE_MN_CLOSE_EVT, &param);
+ memset(p_cb, 0 , sizeof(tBTA_MSE_MN_CB));
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_mn_abort
+**
+** Description Process the abort event.
+**
+** Parameters ccb_idx - Index to the MN control block
+** p_data - Pointer to the MN event data
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_mn_abort(UINT8 ccb_idx, tBTA_MSE_DATA *p_data)
+{
+ tBTA_MSE_MN_CB *p_cb = BTA_MSE_GET_MN_CB_PTR(ccb_idx);
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT1("bta_mse_mn_abort ccb idx=%d ",ccb_idx);
+#endif
+ /* Abort an active request */
+ if (p_cb->obx_oper != BTA_MSE_MN_OP_NONE)
+ {
+ p_cb->aborting = BTA_MSE_MN_ABORT_REQ_NOT_SENT;
+
+ /* Issue the abort request only if no request pending.
+ * some devices do not like out of sequence aborts even though
+ * the spec allows it */
+ if (!p_cb->req_pending)
+ {
+ /* Start abort response timer */
+ bta_mse_mn_start_timer(ccb_idx, BTA_MSE_TIMER_OP_ABORT);
+ OBX_AbortReq(p_cb->obx_handle, (BT_HDR *)NULL);
+ p_cb->aborting = BTA_MSE_MN_ABORT_REQ_SENT;
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_mn_abort_rsp
+**
+** Description Process the abort response event.
+**
+** Parameters ccb_idx - Index to the MN control block
+** p_data - Pointer to the MN event data
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_mn_abort_rsp(UINT8 ccb_idx, tBTA_MSE_DATA *p_data)
+{
+ tBTA_MSE_MN_CB *p_cb = BTA_MSE_GET_MN_CB_PTR(ccb_idx);
+ tBTA_MSE_OBX_EVT *p_evt = &p_data->obx_evt;
+ tBTA_MSE_MN_MSG_NOTIF *p_msg_notif = &p_cb->msg_notif;
+ tBTA_MA_STATUS status = BTA_MA_STATUS_FAIL;
+
+
+ bta_mse_mn_stop_timer(ccb_idx,BTA_MSE_TIMER_OP_ABORT);
+
+ /* Done with Obex packet */
+ utl_freebuf((void**)&p_evt->p_pkt);
+
+ if (p_cb->obx_oper != BTA_MSE_MN_OP_NONE)
+ {
+ if (p_cb->obx_oper == BTA_MSE_MN_OP_PUT_EVT_RPT )
+ {
+ bta_mse_mn_send_notif_evt(p_msg_notif->mas_instance_id, status,
+ p_cb->bd_addr);
+ bta_mse_mn_clean_send_notif(ccb_idx);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_mn_sdp_fail
+**
+** Description Process the SDP fail event.
+**
+** Parameters ccb_idx - Index to the MN control block
+** p_data - Pointer to the MN event data
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_mn_sdp_fail(UINT8 ccb_idx, tBTA_MSE_DATA *p_data)
+{
+ tBTA_MSE_MN_CB *p_cb = BTA_MSE_GET_MN_CB_PTR(ccb_idx);
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT1("bta_mse_mn_sdp_fail ccb idx=%d ",ccb_idx);
+#endif
+ /* free discovery data base */
+ utl_freebuf((void**)&p_cb->p_db);
+ p_cb->sdp_pending = FALSE;
+ bta_mse_mn_sm_execute(ccb_idx, BTA_MSE_MN_OBX_CLOSE_EVT, p_data);
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_mn_obx_tout
+**
+** Description Process the obx timeout event.
+**
+** Parameters ccb_idx - Index to the MN control block
+** p_data - Pointer to the MN event data
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_mn_obx_tout(UINT8 ccb_idx, tBTA_MSE_DATA *p_data)
+{
+ tBTA_MSE_MN_CB *p_cb = BTA_MSE_GET_MN_CB_PTR(ccb_idx);
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT1("bta_mse_mn_obx_tout ccb idx=%d ",ccb_idx);
+#endif
+
+ if (p_cb->req_pending)
+ {
+ if (p_cb->obx_oper == BTA_MSE_MN_OP_PUT_EVT_RPT)
+ {
+ bta_mse_mn_send_notif_evt( p_cb->msg_notif.mas_instance_id,
+ BTA_MA_STATUS_FAIL,
+ p_cb->bd_addr);
+ bta_mse_mn_clean_send_notif(ccb_idx);
+ }
+ }
+}
+/*******************************************************************************
+**
+** Function bta_mse_mn_ignore_obx
+**
+** Description Ignore OBX event.
+**
+** Parameters ccb_idx - Index to the MN control block
+** p_data - Pointer to the MN event data
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_mn_ignore_obx(UINT8 ccb_idx, tBTA_MSE_DATA *p_data)
+{
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT1("bta_mse_mn_ignore_obx ccb idx=%d ",ccb_idx);
+#endif
+
+ utl_freebuf((void **) &p_data->obx_evt.p_pkt);
+}
+
+
+
+/*****************************************************************************
+** MNC Callback Functions
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function bta_mse_mn_obx_cback
+**
+** Description OBX callback function.
+**
+** Parameters handle - Handle for Obex session
+** obx_event - Obex event
+** rsp_code - Obex response code
+** param - event parameters
+** p_pkt - pointer to Obex packet
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_mn_obx_cback (tOBX_HANDLE handle, tOBX_EVENT obx_event, UINT8 rsp_code,
+ tOBX_EVT_PARAM param, BT_HDR *p_pkt)
+{
+ tBTA_MSE_OBX_EVT *p_obx_msg;
+ UINT16 event = 0;
+
+
+
+ switch (obx_event)
+ {
+ case OBX_CONNECT_RSP_EVT:
+ if (rsp_code == OBX_RSP_OK)
+ {
+ event = BTA_MSE_MN_OBX_CONN_RSP_EVT;
+ }
+ else /* Obex will disconnect underneath BTA */
+ {
+ APPL_TRACE_WARNING1("MN_OBX_CBACK: Bad connect response 0x%02x", rsp_code);
+ if (p_pkt)
+ GKI_freebuf(p_pkt);
+ return;
+ }
+ break;
+ case OBX_PUT_RSP_EVT:
+ event = BTA_MSE_MN_OBX_PUT_RSP_EVT;
+ break;
+ case OBX_CLOSE_IND_EVT:
+ event = BTA_MSE_MN_OBX_CLOSE_EVT;
+ break;
+ case OBX_TIMEOUT_EVT:
+ event = BTA_MSE_MN_OBX_TOUT_EVT;
+ break;
+ case OBX_ABORT_RSP_EVT:
+ event = BTA_MSE_MN_OBX_ABORT_RSP_EVT;
+ break;
+ case OBX_PASSWORD_EVT:
+ case OBX_GET_RSP_EVT:
+ case OBX_SETPATH_RSP_EVT:
+ default:
+ /* case OBX_DISCONNECT_RSP_EVT: Handled when OBX_CLOSE_IND_EVT arrives */
+ if (p_pkt)
+ GKI_freebuf(p_pkt);
+ return;
+ }
+
+
+
+ if (event && (p_obx_msg =
+ (tBTA_MSE_OBX_EVT *) GKI_getbuf(sizeof(tBTA_MSE_OBX_EVT))) != NULL)
+ {
+#if (BTA_MSE_DEBUG == TRUE) && (BT_USE_TRACES == TRUE)
+ APPL_TRACE_DEBUG1("MN OBX Event Callback: mn_obx_event [%s]",
+ bta_mse_obx_evt_code(event));
+#endif
+ /* send event to BTA, if any */
+ p_obx_msg->hdr.event = event;
+ p_obx_msg->hdr.layer_specific = 0xFFFF; /* not used */
+ p_obx_msg->obx_event = obx_event;
+ p_obx_msg->handle = handle;
+ p_obx_msg->rsp_code = rsp_code;
+ p_obx_msg->param = param;
+ p_obx_msg->p_pkt = p_pkt;
+
+ bta_sys_sendmsg(p_obx_msg);
+ }
+}
+
+
+/*****************************************************************************
+** Local MSE Event Processing Functions
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function bta_mse_req_app_access
+**
+** Description Sends an access request event to the application.
+**
+** Parameters ccb_idx - Index to the MN control block
+** p_data - Pointer to the MN event data
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_req_app_access (UINT8 inst_idx, UINT8 sess_idx, tBTA_MSE_DATA *p_data)
+{
+ tBTA_MSE_MA_SESS_CB *p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, sess_idx);
+ tBTA_MSE_ACCESS *p_acc_evt;
+ char *p_devname;
+
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT2("bta_mse_req_app_access inst idx=%d sess idx=%d",
+ inst_idx, sess_idx);
+#endif
+
+ /* Ask application for the operation's access permission */
+ if ((p_acc_evt = (tBTA_MSE_ACCESS *)GKI_getbuf((UINT16) (sizeof(tBTA_MSE_ACCESS)+
+ (p_bta_fs_cfg->max_path_len + 1)))) != NULL)
+ {
+ memset(p_acc_evt, 0, sizeof(tBTA_MSE_ACCESS));
+ p_acc_evt->p_path = (char *) (p_acc_evt+1);
+ p_acc_evt->p_path[0]='\0';
+
+ APPL_TRACE_API1("MSE ACCESS REQ: Oper=%d", p_cb->oper);
+ switch (p_cb->oper)
+ {
+ case BTA_MSE_OPER_SETPATH:
+ BCM_STRNCPY_S(p_acc_evt->p_path, p_bta_fs_cfg->max_path_len+1,
+ p_cb->sp.p_path, p_bta_fs_cfg->max_path_len);
+ break;
+
+ case BTA_MSE_OPER_GET_MSG_LIST:
+ BCM_STRNCPY_S(p_acc_evt->p_path, p_bta_fs_cfg->max_path_len+1,
+ p_cb->ml_param.p_path, p_bta_fs_cfg->max_path_len);
+ break;
+
+ case BTA_MSE_OPER_GET_MSG:
+ memcpy(p_acc_evt->handle, p_cb->msg_param.data.handle,
+ sizeof(tBTA_MA_MSG_HANDLE));
+ break;
+ case BTA_MSE_OPER_PUSH_MSG:
+ memset(p_acc_evt->handle, 0, sizeof(tBTA_MA_MSG_HANDLE));
+ BCM_STRNCPY_S(p_acc_evt->p_path, p_bta_fs_cfg->max_path_len+1,
+ p_cb->push_msg.param.p_folder, p_bta_fs_cfg->max_path_len);
+ break;
+ case BTA_MSE_OPER_DEL_MSG:
+ memcpy(p_acc_evt->handle, p_cb->set_msg_sts.handle,
+ sizeof(tBTA_MA_MSG_HANDLE));
+ p_acc_evt->delete_sts = p_cb->set_msg_sts.sts_val;
+ break;
+ default:
+ break;
+ }
+
+ p_acc_evt->oper = p_cb->oper;
+ p_acc_evt->mas_session_id = (tBTA_MA_SESS_HANDLE) p_cb->obx_handle;
+ bdcpy(p_acc_evt->bd_addr, p_cb->bd_addr);
+ if ((p_devname = BTM_SecReadDevName(p_cb->bd_addr)) != NULL)
+ BCM_STRNCPY_S((char *)p_acc_evt->dev_name, sizeof(p_acc_evt->dev_name), p_devname, BTM_MAX_REM_BD_NAME_LEN);
+
+ bta_mse_cb.p_cback(BTA_MSE_ACCESS_EVT, (tBTA_MSE *)p_acc_evt);
+ GKI_freebuf(p_acc_evt);
+ }
+}
+
+/*****************************************************************************
+** Debug Functions
+*****************************************************************************/
+#if (BTA_MSE_DEBUG == TRUE) && (BT_USE_TRACES == TRUE)
+
+/*******************************************************************************
+**
+** Function bta_mse_obx_evt_code
+**
+** Description get the obx event string pointer
+**
+** Parameters evt_code - obex event code
+**
+** Returns char * - event string pointer
+**
+*******************************************************************************/
+static char *bta_mse_obx_evt_code(UINT16 evt_code)
+{
+ switch (evt_code)
+ {
+ case BTA_MSE_MA_OBX_CONN_EVT:
+ return "BTA_MSE_MA_OBX_CONN_EVT";
+ case BTA_MSE_MA_OBX_DISC_EVT:
+ return "BTA_MSE_MA_OBX_DISC_EVT";
+ case BTA_MSE_MA_OBX_PUT_EVT:
+ return "BTA_MSE_MA_OBX_PUT_EVT";
+ case BTA_MSE_MA_OBX_GET_EVT:
+ return "BTA_MSE_MA_OBX_GET_EVT";
+ case BTA_MSE_MA_OBX_SETPATH_EVT:
+ return "BTA_MSE_MA_OBX_SETPATH_EVT";
+ case BTA_MSE_MA_OBX_ABORT_EVT:
+ return "BTA_MSE_MA_OBX_ABORT_EVT";
+ case BTA_MSE_MA_OBX_CLOSE_EVT:
+ return "BTA_MSE_MA_OBX_CLOSE_EVT";
+ case BTA_MSE_MN_OBX_TOUT_EVT:
+ return "BTA_MSE_MN_OBX_TOUT_EVT";
+ case BTA_MSE_MN_OBX_CONN_RSP_EVT:
+ return "BTA_MSE_MN_OBX_CONN_RSP_EVT";
+ case BTA_MSE_MN_OBX_PUT_RSP_EVT:
+ return "BTA_MSE_MN_OBX_PUT_RSP_EVT";
+ case BTA_MSE_MN_OBX_CLOSE_EVT:
+ return "BTA_MSE_MN_OBX_CLOSE_EVT";
+ case BTA_MSE_MN_OBX_ABORT_RSP_EVT:
+ return"BTA_MSE_MN_OBX_ABORT_RSP_EVT";
+ default:
+ return "unknown MSE OBX event code";
+ }
+}
+#endif /* Debug Functions */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#endif /* BTA_MSE_INCLUDED */
diff --git a/bta/ma/bta_mse_api.c b/bta/ma/bta_mse_api.c
new file mode 100644
index 0000000..5a2fd29
--- /dev/null
+++ b/bta/ma/bta_mse_api.c
@@ -0,0 +1,437 @@
+/*****************************************************************************
+**
+** Name: bta_mse_api.c
+**
+** Description: This is the implementation of the API for the Message
+** Acess Server subsystem of BTA, Broadcom Corp's Bluetooth
+** application layer for mobile phones.
+**
+** Copyright (c) 2009-2011 Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+
+#if defined(BTA_MSE_INCLUDED) && (BTA_MSE_INCLUDED == TRUE)
+
+#include <string.h>
+#include "gki.h"
+#include "bd.h"
+#include "bta_ma_def.h"
+#include "bta_mse_api.h"
+#include "bta_fs_api.h"
+#include "bta_mse_int.h"
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+static const tBTA_SYS_REG bta_mse_reg =
+{
+ bta_mse_hdl_event,
+ BTA_MseDisable
+};
+
+/*******************************************************************************
+**
+** Function BTA_MseEnable
+**
+** Description Enable the MSE subsystems. This function must be
+** called before any other functions in the MSE API are called.
+** When the enable operation is completed the callback function
+** will be called with an BTA_MSE_ENABLE_EVT event.
+**
+** Parameters p_cback - MSE event call back function
+** app_id - Application ID
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_MseEnable(tBTA_MSE_CBACK *p_cback, UINT8 app_id)
+{
+ tBTA_MSE_API_ENABLE *p_buf;
+
+ /* register with BTA system manager */
+ GKI_sched_lock();
+ bta_sys_register(BTA_ID_MSE, &bta_mse_reg);
+ GKI_sched_unlock();
+
+ if ((p_buf = (tBTA_MSE_API_ENABLE *)GKI_getbuf(sizeof(tBTA_MSE_API_ENABLE))) != NULL)
+ {
+ p_buf->hdr.event = BTA_MSE_API_ENABLE_EVT;
+ p_buf->p_cback = p_cback;
+ p_buf->app_id = app_id;
+
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_MseDisable
+**
+** Description Disable the MSE subsystem.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_MseDisable(void)
+{
+ BT_HDR *p_buf;
+
+ bta_sys_deregister(BTA_ID_MSE);
+ if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->event = BTA_MSE_API_DISABLE_EVT;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_MseStart
+**
+** Description Start a MA server on the MSE
+**
+**
+** Parameters mas_inst_id - MAS instance ID
+** sec_mask - Security Setting Mask
+** MSE always enables
+** (BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT)
+** p_service_name - Pointer to service name
+** p_root_path - Pointer to root path
+** (one level above telecom)
+** sup_msg_type - supported message type(s)
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_MseStart( tBTA_MA_INST_ID mas_inst_id,
+ tBTA_SEC sec_mask, const char *p_service_name,
+ const char *p_root_path,
+ tBTA_MA_MSG_TYPE sup_msg_type)
+{
+ tBTA_MSE_API_START *p_buf;
+
+ if ((p_buf = (tBTA_MSE_API_START *)GKI_getbuf((UINT16)(sizeof(tBTA_MSE_API_START) +
+ p_bta_fs_cfg->max_path_len + 1))) != NULL)
+ {
+ p_buf->p_root_path = (char *)(p_buf + 1);
+ p_buf->hdr.event = BTA_MSE_API_START_EVT;
+ p_buf->mas_inst_id = mas_inst_id;
+ p_buf->sec_mask = (sec_mask | BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
+ p_buf->sup_msg_type = sup_msg_type;
+
+
+ if (p_service_name)
+ {
+ BCM_STRNCPY_S(p_buf->servicename, sizeof(p_buf->servicename), p_service_name, BTA_SERVICE_NAME_LEN);
+ p_buf->servicename[BTA_SERVICE_NAME_LEN] = '\0';
+ }
+ else
+ p_buf->servicename[0]= '\0';
+
+ if (p_root_path)
+ {
+ BCM_STRNCPY_S(p_buf->p_root_path, p_bta_fs_cfg->max_path_len+1, p_root_path, p_bta_fs_cfg->max_path_len);
+ p_buf->p_root_path[p_bta_fs_cfg->max_path_len] = '\0';
+ }
+ else
+ p_buf->p_root_path[0] = '\0';
+
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_MseStop
+**
+** Description Stop a MA server on the MSE
+**
+** Parameters mas_instance_id - MAS Instance ID
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_MseStop (tBTA_MA_INST_ID mas_instance_id)
+{
+ tBTA_MSE_API_STOP *p_buf;
+
+ if ((p_buf = (tBTA_MSE_API_STOP *)GKI_getbuf((UINT16)(sizeof(tBTA_MSE_API_STOP)))) != NULL)
+ {
+ p_buf->hdr.event = BTA_MSE_API_STOP_EVT;
+ p_buf->mas_inst_id = mas_instance_id;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_MseClose
+**
+** Description Close all MAS sessions on the specified MAS Instance ID
+**
+** Parameters mas_instance_id - MAS Inatance ID
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_MseClose(tBTA_MA_INST_ID mas_instance_id)
+{
+
+ tBTA_MSE_API_CLOSE *p_buf;
+
+ if ((p_buf = (tBTA_MSE_API_CLOSE *)GKI_getbuf((UINT16)(sizeof(tBTA_MSE_API_CLOSE)))) != NULL)
+ {
+ p_buf->hdr.event = BTA_MSE_API_CLOSE_EVT;
+ p_buf->mas_instance_id = mas_instance_id;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_MseMaClose
+**
+** Description Close a MAS sessions on the specified BD address
+**
+** Parameters bd_addr - remote BD's address
+** mas_instance_id - MAS Inatance ID
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_MseMaClose(BD_ADDR bd_addr, tBTA_MA_INST_ID mas_instance_id)
+{
+ tBTA_MSE_API_MA_CLOSE *p_buf;
+
+ if ((p_buf = (tBTA_MSE_API_MA_CLOSE *)GKI_getbuf((UINT16)(sizeof(tBTA_MSE_API_MA_CLOSE)))) != NULL)
+ {
+ memset(p_buf, 0, sizeof(tBTA_MSE_API_MA_CLOSE));
+
+ p_buf->hdr.event = BTA_MSE_API_MA_CLOSE_EVT;
+ bdcpy(p_buf->bd_addr, bd_addr);
+ p_buf->mas_instance_id = mas_instance_id;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+/*******************************************************************************
+**
+** Function BTA_MseMnClose
+**
+** Description Close a MN session
+**
+** Parameters bd_addr - remote BD's address
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_MseMnClose(BD_ADDR bd_addr)
+{
+ tBTA_MSE_API_MN_CLOSE *p_buf;
+
+ if ((p_buf = (tBTA_MSE_API_MN_CLOSE *)GKI_getbuf((UINT16)(sizeof(tBTA_MSE_API_MN_CLOSE)))) != NULL)
+ {
+ p_buf->hdr.event = BTA_MSE_API_MN_CLOSE_EVT;
+ bdcpy(p_buf->bd_addr, bd_addr);
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_MseAccessRsp
+**
+** Description Send a response for the access request
+**
+** Parameters mas_session_id - MAS session ID
+** oper - MAS operation type
+** access - Access is allowed or not
+** p_path - pointer to a path if if the operation
+** involves accessing a folder
+** Returns void
+**
+*******************************************************************************/
+void BTA_MseAccessRsp(tBTA_MA_SESS_HANDLE mas_session_id, tBTA_MSE_OPER oper,
+ tBTA_MA_ACCESS_TYPE access, char *p_path)
+{
+ tBTA_MSE_API_ACCESSRSP *p_acc_rsp;
+ UINT16 path_len;
+
+ /* If directory is specified set the length */
+ path_len = (p_path && *p_path != '\0') ? (UINT16)(strlen(p_path) + 1): 1;
+
+ if ((p_acc_rsp = (tBTA_MSE_API_ACCESSRSP *)GKI_getbuf((UINT16)(sizeof(tBTA_MSE_API_ACCESSRSP)
+ + path_len))) != NULL)
+ {
+ p_acc_rsp->mas_session_id = mas_session_id;
+ p_acc_rsp->rsp = access;
+ p_acc_rsp->oper = oper;
+ p_acc_rsp->p_path = (char *)(p_acc_rsp + 1);
+ if (p_path)
+ {
+ BCM_STRNCPY_S(p_acc_rsp->p_path, path_len, p_path, path_len-1);
+ p_acc_rsp->p_path[path_len-1] = '\0';
+ }
+ else
+ p_acc_rsp->p_path[0] = '\0';
+
+ p_acc_rsp->hdr.event = BTA_MSE_API_ACCESSRSP_EVT;
+ bta_sys_sendmsg(p_acc_rsp);
+ }
+}
+/*******************************************************************************
+**
+** Function BTA_MseUpdateInboxRsp
+**
+** Description Send a response for the update inbox request
+**
+**
+** Parameters mas_session_id - MAS session ID
+** update_rsp - update inbox is allowed or not
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_MseUpdateInboxRsp(tBTA_MA_SESS_HANDLE mas_session_id,
+ tBTA_MSE_UPDATE_INBOX_TYPE update_rsp)
+{
+ tBTA_MSE_API_UPDINBRSP *p_buf;
+
+ if ((p_buf = (tBTA_MSE_API_UPDINBRSP *)GKI_getbuf((UINT16)(sizeof(tBTA_MSE_API_UPDINBRSP)))) != NULL)
+ {
+ p_buf->hdr.event = BTA_MSE_API_UPD_IBX_RSP_EVT;
+ p_buf->mas_session_id = mas_session_id;
+ p_buf->rsp = update_rsp;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+/*******************************************************************************
+**
+** Function BTA_MseSetNotifRegRsp
+**
+** Description Send a response for the set notification registration
+**
+**
+** Parameters mas_session_id - MAS session ID
+** set_notif_reg_rsp - indicate whether the set notification
+** registration is allowed or not
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_MseSetNotifRegRsp(tBTA_MA_SESS_HANDLE mas_session_id,
+ tBTA_MSE_SET_NOTIF_REG_TYPE set_notif_reg_rsp)
+{
+ tBTA_MSE_API_SETNOTIFREGRSP *p_buf;
+
+ if ((p_buf = (tBTA_MSE_API_SETNOTIFREGRSP *)GKI_getbuf((UINT16)(sizeof(tBTA_MSE_API_UPDINBRSP)))) != NULL)
+ {
+ p_buf->hdr.event = BTA_MSE_API_SET_NOTIF_REG_RSP_EVT;
+ p_buf->mas_session_id = mas_session_id;
+ p_buf->rsp = set_notif_reg_rsp;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+/*******************************************************************************
+**
+** Function BTA_MseSendNotif
+**
+** Description Send a Message notification report to all MCEs registered with
+** the specified MAS instance ID
+**
+** Parameters mas_instance_id - MAS Instance ID
+** notif_type - message notification type
+** handle - message handle
+** p_folder - pointer to current folder
+** p_old_folder - pointer to older folder
+** msg_type - message type (E_MAIL, SMS_GSM, SMS_CDMA, MMS)
+** except_bd_addr - except to the MCE on this BD Address.
+** (Note: notification will be not sent to
+** this BD Addreess)
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_MseSendNotif(tBTA_MA_INST_ID mas_instance_id,
+ tBTA_MSE_NOTIF_TYPE notif_type,
+ tBTA_MA_MSG_HANDLE handle,
+ char * p_folder, char *p_old_folder,
+ tBTA_MA_MSG_TYPE msg_type,
+ BD_ADDR except_bd_addr)
+{
+ tBTA_MSE_MN_API_SEND_NOTIF *p_buf;
+ UINT16 folder_len, old_folder_len;
+
+ /* If directory is specified set the length */
+ folder_len = (p_folder && *p_folder != '\0') ? (UINT16)(strlen(p_folder) + 1): 0;
+ old_folder_len = (p_old_folder && *p_old_folder != '\0') ? (UINT16)(strlen(p_old_folder) + 1): 0;
+
+ if ((p_buf = (tBTA_MSE_MN_API_SEND_NOTIF *)GKI_getbuf((UINT16) ((UINT16)sizeof(tBTA_MSE_MN_API_SEND_NOTIF) +
+ folder_len +
+ old_folder_len))) != NULL)
+ {
+ p_buf->hdr.event = BTA_MSE_API_SEND_NOTIF_EVT;
+ p_buf->mas_instance_id = mas_instance_id;
+ p_buf->notif_type = notif_type;
+ memcpy(p_buf->handle, handle, sizeof(tBTA_MA_MSG_HANDLE));
+
+ if (folder_len)
+ {
+ p_buf->p_folder = (char *)(p_buf + 1);
+ BCM_STRNCPY_S(p_buf->p_folder, folder_len+1, p_folder, folder_len);
+ }
+ else
+ p_buf->p_folder = NULL;
+
+ if (old_folder_len)
+ {
+ if (folder_len)
+ p_buf->p_old_folder = p_buf->p_folder + folder_len;
+ else
+ p_buf->p_old_folder = (char *)(p_buf + 1);
+
+ BCM_STRNCPY_S(p_buf->p_old_folder, old_folder_len+1, p_old_folder, old_folder_len);
+ }
+ else
+ p_buf->p_old_folder = NULL;
+
+ p_buf->msg_type = msg_type;
+ if (except_bd_addr != NULL)
+ {
+ bdcpy(p_buf->except_bd_addr, except_bd_addr);
+ }
+ else
+ {
+ memset(p_buf->except_bd_addr, 0, sizeof(BD_ADDR));
+ }
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_MseMnAbort
+**
+** Description Abort the current OBEX multi-packt operation in MN
+**
+** Parameters mas_instance_id - MAS Instance ID
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_MseMnAbort(tBTA_MA_INST_ID mas_instance_id)
+{
+ tBTA_MSE_MN_API_ABORT *p_buf;
+
+ if ((p_buf = (tBTA_MSE_MN_API_ABORT *)GKI_getbuf((UINT16)(sizeof(tBTA_MSE_MN_API_ABORT)))) != NULL)
+ {
+ p_buf->hdr.event = BTA_MSE_API_MN_ABORT_EVT;
+ p_buf->mas_instance_id = mas_instance_id;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+
+#endif /* BTA_MSE_INCLUDED */
diff --git a/bta/ma/bta_mse_cfg.c b/bta/ma/bta_mse_cfg.c
new file mode 100644
index 0000000..69953d0
--- /dev/null
+++ b/bta/ma/bta_mse_cfg.c
@@ -0,0 +1,31 @@
+/*****************************************************************************
+**
+** Name: bta_mse_cfg.c
+**
+** Description: This file contains compile-time configurable constants
+** for the MSE subsystem.
+**
+** Copyright (c) 2009, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bta_mse_api.h"
+
+#ifndef BTA_MSE_MAX_NAME_LEN
+ #define BTA_MSE_MAX_NAME_LEN 256
+#endif
+
+#ifndef BTA_MSE_OBX_RSP_TOUT
+ #define BTA_MSE_OBX_RSP_TOUT 2000
+#endif
+
+
+const tBTA_MSE_CFG bta_mse_cfg =
+{
+ BTA_MSE_OBX_RSP_TOUT,
+ BTA_MSE_MAX_NAME_LEN
+};
+
+tBTA_MSE_CFG *p_bta_mse_cfg = (tBTA_MSE_CFG *)&bta_mse_cfg;
+
diff --git a/bta/ma/bta_mse_ci.c b/bta/ma/bta_mse_ci.c
new file mode 100644
index 0000000..dfaeb7e
--- /dev/null
+++ b/bta/ma/bta_mse_ci.c
@@ -0,0 +1,251 @@
+/*****************************************************************************
+**
+** Name: bta_mse_ci.c
+**
+** Description: This is the implementaion for the Message Server Equipment
+** (MSE) subsystem call-in functions.
+**
+** Copyright (c) 2009, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include <stdio.h>
+#include <string.h>
+#include "bta_api.h"
+#include "bta_ma_def.h"
+#include "bta_mse_api.h"
+#include "bta_mse_co.h"
+#include "bta_mse_int.h"
+#include "bta_mse_ci.h"
+
+/*******************************************************************************
+**
+** Function bta_mse_ci_get_folder_entry
+**
+** Description This function is called in response to the
+** bta_mse_co_get_folder_entry call-out function.
+**
+** Parameters mas_session_id - MAS session ID
+** status - BTA_MA_STATUS_OK if p_entry points to a valid entry.
+** BTA_MA_STATUS_EODIR if no more entries (p_entry is ignored).
+** BTA_MA_STATUS_FAIL if any errors have occurred.
+** evt - evt from the call-out function
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_mse_ci_get_folder_entry(tBTA_MA_SESS_HANDLE mas_session_id,
+ tBTA_MA_STATUS status,
+ UINT16 evt)
+{
+ tBTA_MSE_CI_GET_FENTRY *p_evt;
+
+ if ((p_evt = (tBTA_MSE_CI_GET_FENTRY *)GKI_getbuf(sizeof(tBTA_MSE_CI_GET_FENTRY))) != NULL)
+ {
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT2("bta_mse_ci_get_folder_entry sess_id=%d, status=%d \n",
+ mas_session_id, status);
+#endif
+ p_evt->hdr.event = evt;
+ p_evt->mas_session_id = mas_session_id;
+ p_evt->status = status;
+ bta_sys_sendmsg(p_evt);
+ }
+}
+/*******************************************************************************
+**
+** Function bta_mse_ci_get_msg_list_info
+**
+** Description This function is called in response to the
+** bta_mse_co_get_msg_list_info call-out function.
+**
+** Parameters mas_session_id - MAS session ID
+** status - BTA_MA_STATUS_OK operation is successful.
+** BTA_MA_STATUS_FAIL if any errors have occurred.
+** evt - evt from the call-out function
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_mse_ci_get_msg_list_info(tBTA_MA_SESS_HANDLE mas_session_id,
+ tBTA_MA_STATUS status,
+ UINT16 evt)
+{
+ tBTA_MSE_CI_GET_ML_INFO *p_evt;
+
+ if ((p_evt = (tBTA_MSE_CI_GET_ML_INFO *)GKI_getbuf(sizeof(tBTA_MSE_CI_GET_ML_INFO))) != NULL)
+ {
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT2("bta_mse_ci_get_msg_list_info sess_id=%d, status=%d \n",
+ mas_session_id, status);
+#endif
+ p_evt->hdr.event = evt;
+ p_evt->mas_session_id = mas_session_id;
+ p_evt->status = status;
+ bta_sys_sendmsg(p_evt);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_ci_get_msg_list_entry
+**
+** Description This function is called in response to the
+** bta_mse_co_get_msg_list_entry call-out function.
+**
+** Parameters mas_session_id - MAS session ID
+** status - BTA_MA_STATUS_OK if p_entry points to a valid entry.
+** BTA_MA_STATUS_EODIR if no more entries (p_entry is ignored).
+** BTA_MA_STATUS_FAIL if any errors have occurred.
+** evt - evt from the call-out function
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_mse_ci_get_msg_list_entry(tBTA_MA_SESS_HANDLE mas_session_id,
+ tBTA_MA_STATUS status,
+ UINT16 evt)
+{
+ tBTA_MSE_CI_GET_ML_ENTRY *p_evt;
+
+ if ((p_evt = (tBTA_MSE_CI_GET_ML_ENTRY *)GKI_getbuf(sizeof(tBTA_MSE_CI_GET_ML_ENTRY))) != NULL)
+ {
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT2("bta_mse_ci_get_msg_list_entry sess_id=%d, status=%d \n",
+ mas_session_id, status);
+#endif
+ p_evt->hdr.event = evt;
+ p_evt->mas_session_id = mas_session_id;
+ p_evt->status = status;
+ bta_sys_sendmsg(p_evt);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_ci_get_msg
+**
+** Description This function is called in response to the
+** bta_mse_co_get_msg call-out function.
+**
+** Parameters mas_session_id - MAS session ID
+** status - BTA_MA_STATUS_OK if p_msg points to a valid bmessage.
+** BTA_MA_STATUS_FAIL if any errors have occurred.
+** filled_buff_size - size of the filled buffer
+** multi_pkt_status - BTA_MA_MPKT_STATUS_MORE - need to get more packets
+** BTA_MA_MPKT_STATUS_LAST - last packet of the bMessage
+** frac_deliver_status - BTA_MA_FRAC_DELIVER_MORE - other fractions following
+** this bMessage
+** BTA_MA_FRAC_DELIVER_LAST - Last fraction
+** evt - evt from the call-out function
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_mse_ci_get_msg(tBTA_MA_SESS_HANDLE mas_session_id,
+ tBTA_MA_STATUS status,
+ UINT16 filled_buff_size,
+ tBTA_MA_MPKT_STATUS multi_pkt_status,
+ tBTA_MA_FRAC_DELIVER frac_deliver_status,
+ UINT16 evt)
+{
+ tBTA_MSE_CI_GET_MSG *p_evt;
+
+ if ((p_evt = (tBTA_MSE_CI_GET_MSG *)GKI_getbuf(sizeof(tBTA_MSE_CI_GET_MSG))) != NULL)
+ {
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT4("bta_mse_ci_get_msg sess_id=%d, status=%d, multi-pkt status=%d frac=%d\n",
+ mas_session_id,
+ status,
+ multi_pkt_status,
+ frac_deliver_status);
+#endif
+ p_evt->hdr.event = evt;
+ p_evt->mas_session_id = mas_session_id;
+ p_evt->status = status;
+ p_evt->filled_buff_size = filled_buff_size;
+ p_evt->multi_pkt_status = multi_pkt_status;
+ p_evt->frac_deliver_status = frac_deliver_status;
+ bta_sys_sendmsg(p_evt);
+ }
+}
+/*******************************************************************************
+**
+** Function bta_mse_ci_set_msg_delete_status
+**
+** Description This function is called in response to the
+** bta_mse_co_set_msg_delete_status call-out function.
+**
+** Parameters mas_session_id - MAS session ID
+** status - BTA_MA_STATUS_OK if operation is successful.
+** BTA_MA_STATUS_FAIL if any errors have occurred.
+** evt - evt from the call-out function
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_mse_ci_set_msg_delete_status(tBTA_MA_SESS_HANDLE mas_session_id,
+ tBTA_MA_STATUS status,
+ UINT16 evt)
+{
+ tBTA_MSE_CI_DEL_MSG *p_evt;
+
+ if ((p_evt = (tBTA_MSE_CI_DEL_MSG *)GKI_getbuf(sizeof(tBTA_MSE_CI_DEL_MSG))) != NULL)
+ {
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT3("bta_mse_ci_del_msg sess_id=%d, status=%d evt=%d\n",
+ mas_session_id, status, evt);
+#endif
+ p_evt->hdr.event = evt;
+ p_evt->mas_session_id = mas_session_id;
+ p_evt->status = status;
+ bta_sys_sendmsg(p_evt);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_ci_push_msg
+**
+** Description This function is called in response to the
+** bta_mse_co_push_msg call-out function.
+**
+** Parameters mas_session_id - MAS session ID
+** status - BTA_MA_STATUS_OK if the message upload is successful.
+** BTA_MA_STATUS_FAIL if any errors have occurred.
+** last_packet - last packet of a multi-packet message
+** handle - message handle for the uploaded message if
+** status is BTA_MA_OK and last_packet is TRUE
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_mse_ci_push_msg(tBTA_MA_SESS_HANDLE mas_session_id,
+ tBTA_MA_STATUS status,
+ BOOLEAN last_packet,
+ tBTA_MA_MSG_HANDLE handle,
+ UINT16 evt)
+{
+ tBTA_MSE_CI_PUSH_MSG *p_evt;
+
+ if ((p_evt = (tBTA_MSE_CI_PUSH_MSG *)GKI_getbuf(sizeof(tBTA_MSE_CI_PUSH_MSG))) != NULL)
+ {
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT4("bta_mse_ci_push_msg sess_id=%d, status=%d, last_pkt=%d evt=%d\n",
+ mas_session_id,
+ status,
+ last_packet,
+ evt);
+#endif
+
+ p_evt->hdr.event = evt;
+ p_evt->mas_session_id = mas_session_id;
+ p_evt->status = status;
+ memcpy(p_evt->handle,
+ handle,
+ sizeof(tBTA_MA_MSG_HANDLE));
+ p_evt->last_packet = last_packet;
+ bta_sys_sendmsg(p_evt);
+ }
+}
+
+
diff --git a/bta/ma/bta_mse_int.h b/bta/ma/bta_mse_int.h
new file mode 100644
index 0000000..d519b71
--- /dev/null
+++ b/bta/ma/bta_mse_int.h
@@ -0,0 +1,835 @@
+/*****************************************************************************
+**
+** Name: bta_mse_int.h
+**
+** Description: This is the private file for the message access
+** equipment (MSE) subsystem.
+**
+** Copyright (c) 1998-2009, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_MSE_INT_H
+#define BTA_MSE_INT_H
+
+#include "bt_target.h"
+#include "bta_sys.h"
+#include "obx_api.h"
+#include "bta_ma_def.h"
+#include "bta_mse_api.h"
+#include "bta_mse_co.h"
+#include "bta_mse_ci.h"
+#include "bta_ma_util.h"
+
+/*****************************************************************************
+** Constants and data types
+*****************************************************************************/
+typedef tOBX_STATUS (tBTA_MA_OBX_RSP) (tOBX_HANDLE handle, UINT8 rsp_code, BT_HDR *p_pkt);
+
+#ifndef BTA_MSE_MN_DISC_SIZE
+ #define BTA_MSE_MN_DISC_SIZE 500
+#endif
+
+#define BTA_MSE_64BIT_HEX_STR_SIZE (16+1)
+#define BTA_MSE_32BIT_HEX_STR_SIZE (8+1)
+
+#define BTA_MSE_MN_MAX_MSG_EVT_OBECT_SIZE 1536 /* 1.5 k */
+/* mode field in tBTA_MSE_CO_FOLDER_ENTRY (OR'd together) */
+#define BTA_MSE_A_RDONLY GOEP_A_RDONLY
+#define BTA_MSE_A_DIR GOEP_A_DIR /* Entry is a sub directory */
+
+enum
+{
+ BTA_MSE_MA_GET_ACT_NEW_FOLDER_LIST = 0,
+ BTA_MSE_MA_GET_ACT_CON_FOLDER_LIST,
+ BTA_MSE_MA_GET_ACT_ERR_FOLDER_LIST,
+ BTA_MSE_MA_GET_ACT_NEW_MSG_LIST,
+ BTA_MSE_MA_GET_ACT_CON_MSG_LIST,
+ BTA_MSE_MA_GET_ACT_ERR_MSG_LIST,
+ BTA_MSE_MA_GET_ACT_NEW_MSG,
+ BTA_MSE_MA_GET_ACT_CON_MSG,
+ BTA_MSE_MA_GET_ACT_ERR_MSG,
+ BTA_MSE_MA_GET_ACT_ERR,
+ BTA_MSE_MA_GET_ACT_NONE,
+ BTA_MSE_MA_GET_ACT_MAX
+};
+typedef UINT8 tBTA_MSE_MA_GET_ACT;
+
+enum
+{
+ BTA_MSE_MA_GET_TYPE_FOLDER_LIST = 0,
+ BTA_MSE_MA_GET_TYPE_MSG_LIST,
+ BTA_MSE_MA_GET_TYPE_MSG,
+ BTA_MSE_MA_GET_TYPE_CON_FOLDER_LIST,
+ BTA_MSE_MA_GET_TYPE_CON_MSG_LIST,
+ BTA_MSE_MA_GET_TYPE_CON_MSG,
+ BTA_MSE_MA_GET_TYPE_NONE,
+ BTA_MSE_MA_GET_TYPE_MAX
+};
+typedef UINT8 tBTA_MSE_MA_GET_TYPE;
+
+enum
+{
+ BTA_MSE_MA_PUT_TYPE_NOTIF_REG = 0,
+ BTA_MSE_MA_PUT_TYPE_EVT_RPT,
+ BTA_MSE_MA_PUT_TYPE_NONE,
+ BTA_MSE_MA_PUT_TYPE_MAX
+};
+typedef UINT8 tBTA_MSE_MA_PUT_TYPE;
+
+enum
+{
+ BTA_MSE_MN_NOTIF_REG_STS_OFF = 0,
+ BTA_MSE_MN_NOTIF_REG_STS_ON,
+ BTA_MSE_MN_NOTIF_REG_STS_NONE,
+ BTA_MSE_MN_NOTIF_REG_STS_MAX
+};
+typedef UINT8 tBTA_MSE_MN_NOTIF_REG_STS;
+
+enum
+{
+ BTA_MSE_MN_ACT_TYPE_OPEN_CONN = 0,
+ BTA_MSE_MN_ACT_TYPE_OPEN_CONN_NONE,
+ BTA_MSE_MN_ACT_TYPE_OPEN_CONN_ERR,
+ BTA_MSE_MN_ACT_TYPE_CLOSE_CONN,
+ BTA_MSE_MN_ACT_TYPE_CLOSE_CONN_NONE,
+ BTA_MSE_MN_ACT_TYPE_CLOSE_CONN_ERR,
+ BTA_MSE_MN_ACT_TYPE_NONE,
+ BTA_MSE_MN_ACT_TYPE_MAX
+};
+typedef UINT8 tBTA_MSE_MN_ACT_TYPE;
+
+typedef tOBX_STATUS (tBTA_MSE_OBX_RSP) (tOBX_HANDLE handle, UINT8 rsp_code, BT_HDR *p_pkt);
+
+/* MSE Active MA obex operation (Valid in connected state) */
+#define BTA_MSE_MA_OP_NONE 0
+#define BTA_MSE_MA_OP_SETPATH 1
+#define BTA_MSE_MA_OP_GET_FOLDER_LIST 2
+#define BTA_MSE_MA_OP_GET_MSG_LIST 3
+#define BTA_MSE_MA_OP_GET_MSG 4
+#define BTA_MSE_MA_OP_SET_STATUS 5
+#define BTA_MSE_MA_OP_PUSH_MSG 6
+
+/* MAS Active MN obex operation (Valid in connected state) */
+#define BTA_MSE_MN_OP_NONE 0
+#define BTA_MSE_MN_OP_PUT_EVT_RPT 1
+
+
+/* MN Abort state */
+#define BTA_MSE_MN_ABORT_NONE 0x0
+#define BTA_MSE_MN_ABORT_REQ_NOT_SENT 0x1
+#define BTA_MSE_MN_ABORT_REQ_SENT 0x2
+#define BTA_MSE_MN_ABORT_RSP_RCVD 0x4
+
+
+/* Response Timer Operations */
+#define BTA_MSE_TIMER_OP_NONE 0
+#define BTA_MSE_TIMER_OP_STOP 1
+#define BTA_MSE_TIMER_OP_ABORT 2
+#define BTA_MSE_TIMER_OP_ALL 0xFF /* use to stop all timers */
+
+/* State Machine Events */
+enum
+{
+ /* these events are handled by the state machine */
+ BTA_MSE_INT_CLOSE_EVT = BTA_SYS_EVT_START(BTA_ID_MSE),
+ BTA_MSE_API_ACCESSRSP_EVT,
+ BTA_MSE_API_UPD_IBX_RSP_EVT,
+ BTA_MSE_API_SET_NOTIF_REG_RSP_EVT,
+ BTA_MSE_INT_START_EVT,
+ BTA_MSE_CI_GET_FENTRY_EVT,
+ BTA_MSE_CI_GET_ML_INFO_EVT,
+ BTA_MSE_CI_GET_ML_ENTRY_EVT,
+ BTA_MSE_CI_GET_MSG_EVT,
+ BTA_MSE_CI_PUSH_MSG_EVT,
+ BTA_MSE_CI_DEL_MSG_EVT,
+ BTA_MSE_MA_OBX_CONN_EVT, /* OBX Channel Connect Request */
+ BTA_MSE_MA_OBX_DISC_EVT, /* OBX Channel Disconnect */
+ BTA_MSE_MA_OBX_ABORT_EVT, /* OBX_operation aborted */
+ BTA_MSE_MA_OBX_CLOSE_EVT, /* OBX Channel Disconnected (Link Lost) */
+ BTA_MSE_MA_OBX_PUT_EVT, /* Write file data or delete */
+ BTA_MSE_MA_OBX_GET_EVT, /* Read file data or folder listing */
+ BTA_MSE_MA_OBX_SETPATH_EVT, /* Make or Change Directory */
+ BTA_MSE_CLOSE_CMPL_EVT, /* Finished closing channel */
+
+ /* Message Notification Client events */
+ BTA_MSE_MN_INT_OPEN_EVT,
+ BTA_MSE_MN_INT_CLOSE_EVT,
+ BTA_MSE_MN_SDP_OK_EVT,
+ BTA_MSE_MN_SDP_FAIL_EVT,
+ BTA_MSE_MN_OBX_CONN_RSP_EVT,
+ BTA_MSE_MN_OBX_PUT_RSP_EVT,
+ BTA_MSE_MN_OBX_CLOSE_EVT,
+ BTA_MSE_MN_OBX_TOUT_EVT,
+ BTA_MSE_MN_CLOSE_CMPL_EVT,
+ BTA_MSE_API_SEND_NOTIF_EVT,
+ BTA_MSE_API_MN_ABORT_EVT,
+ BTA_MSE_MN_OBX_ABORT_RSP_EVT,
+ BTA_MSE_MN_RSP_TOUT_EVT,
+
+ /* these events are handled outside the state machine */
+ BTA_MSE_MN_RSP0_TOUT_EVT, /* timeout event for MN control block index 0*/
+ BTA_MSE_MN_RSP1_TOUT_EVT,
+ BTA_MSE_MN_RSP2_TOUT_EVT,
+ BTA_MSE_MN_RSP3_TOUT_EVT,
+ BTA_MSE_MN_RSP4_TOUT_EVT,
+ BTA_MSE_MN_RSP5_TOUT_EVT,
+ BTA_MSE_MN_RSP6_TOUT_EVT, /* Bluetooth limit for upto 7 devices*/
+ BTA_MSE_API_ENABLE_EVT,
+ BTA_MSE_API_DISABLE_EVT,
+ BTA_MSE_API_START_EVT,
+ BTA_MSE_API_STOP_EVT,
+ BTA_MSE_API_CLOSE_EVT,
+ BTA_MSE_API_MA_CLOSE_EVT,
+ BTA_MSE_API_MN_CLOSE_EVT
+
+};
+typedef UINT16 tBTA_MSE_INT_EVT;
+
+#define BTA_MSE_MN_EVT_MIN BTA_MSE_MN_INT_OPEN_EVT
+#define BTA_MSE_MN_EVT_MAX BTA_MSE_MN_RSP_TOUT_EVT
+
+
+/* state machine states */
+enum
+{
+ BTA_MSE_MA_IDLE_ST = 0, /* Idle */
+ BTA_MSE_MA_LISTEN_ST, /* Listen - waiting for OBX/RFC connection */
+ BTA_MSE_MA_CONN_ST, /* Connected - MA Session is active */
+ BTA_MSE_MA_CLOSING_ST /* Closing is in progress */
+};
+typedef UINT8 tBTA_MSE_MA_STATE;
+
+/* data type for BTA_MSE_MA_CI_GET_FENTRY_EVT note:sdh */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_MA_SESS_HANDLE mas_session_id;
+ tBTA_MA_STATUS status;
+} tBTA_MSE_CI_GET_FENTRY;
+
+/* data type for BTA_MSE_MA_CI_GET_FENTRY_EVT note:sdh */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_MA_SESS_HANDLE mas_session_id;
+ tBTA_MA_STATUS status;
+} tBTA_MSE_CI_GET_ML_INFO;
+
+
+
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_MA_SESS_HANDLE mas_session_id;
+ tBTA_MA_STATUS status;
+} tBTA_MSE_CI_GET_ML_ENTRY;
+
+
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_MA_SESS_HANDLE mas_session_id;
+ tBTA_MA_STATUS status;
+ BOOLEAN last_packet;
+ tBTA_MA_MSG_HANDLE handle;
+} tBTA_MSE_CI_PUSH_MSG;
+
+
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_MA_SESS_HANDLE mas_session_id;
+ tBTA_MA_STATUS status;
+ UINT16 filled_buff_size;
+ tBTA_MA_MPKT_STATUS multi_pkt_status;
+ tBTA_MA_FRAC_DELIVER frac_deliver_status;
+} tBTA_MSE_CI_GET_MSG;
+
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_MA_SESS_HANDLE mas_session_id;
+ tBTA_MA_STATUS status;
+} tBTA_MSE_CI_DEL_MSG;
+
+
+
+/* data type for BTA_MSE_API_ENABLE_EVT note:sdh */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_MSE_CBACK *p_cback; /* pointer to application callback function */
+ UINT8 app_id;
+} tBTA_MSE_API_ENABLE;
+
+
+/* data type for BTA_MSE_API_DISABLE_EVT note:sdh */
+typedef struct
+{
+ BT_HDR hdr;
+ UINT8 app_id;
+} tBTA_MSE_API_DISABLE;
+
+/* data type for BTA_MSE_API_START_EVT note:sdh */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_MA_INST_ID mas_inst_id;
+ char servicename[BTA_SERVICE_NAME_LEN + 1];
+ char *p_root_path;
+ tBTA_SEC sec_mask;
+ tBTA_MA_MSG_TYPE sup_msg_type;
+} tBTA_MSE_API_START;
+
+/* data type for BTA_MSE_API_STOP_EVT note:sdh */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_MA_INST_ID mas_inst_id;
+
+} tBTA_MSE_API_STOP;
+
+/* data type for BTA_MSE_API_CLOSE_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_MA_INST_ID mas_instance_id;
+
+} tBTA_MSE_API_CLOSE;
+
+/* data type for BTA_MSE_API_MA_CLOSE_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+ tBTA_MA_INST_ID mas_instance_id;
+
+} tBTA_MSE_API_MA_CLOSE;
+
+/* data type for BTA_MSE_INT_CLOSE_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_MA_SESS_HANDLE mas_session_id;
+
+} tBTA_MSE_INT_CLOSE;
+
+
+/* data type for BTA_MSE_API_MN_CLOSE_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+} tBTA_MSE_API_MN_CLOSE;
+
+
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_MA_SESS_HANDLE mas_session_id;
+ tBTA_MSE_OPER oper;
+ tBTA_MA_ACCESS_TYPE rsp;
+ char *p_path;
+} tBTA_MSE_API_ACCESSRSP;
+
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_MA_SESS_HANDLE mas_session_id;
+ tBTA_MSE_UPDATE_INBOX_TYPE rsp;
+ char *p_path;
+} tBTA_MSE_API_UPDINBRSP;
+
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_MA_SESS_HANDLE mas_session_id;
+ tBTA_MSE_SET_NOTIF_REG_TYPE rsp;
+} tBTA_MSE_API_SETNOTIFREGRSP;
+
+/* data type for all obex events
+ hdr.event contains the MAS event
+*/
+typedef struct
+{
+ BT_HDR hdr;
+ tOBX_HANDLE handle;
+ tOBX_EVT_PARAM param;
+ BT_HDR *p_pkt;
+ tOBX_EVENT obx_event;
+ UINT8 rsp_code;
+} tBTA_MSE_OBX_EVT;
+
+/* OBX Response Packet Structure - Holds current response packet info */
+typedef struct
+{
+ BT_HDR *p_pkt; /* (Get/Put) Holds the current OBX header for Put or Get */
+ UINT8 *p_start; /* (Get/Put) Start of the Body of the packet */
+ UINT16 offset; /* (Get/Put) Contains the current offset into the Body (p_start) */
+ UINT16 bytes_left; /* (Get/Put) Holds bytes available left in Obx packet */
+ BOOLEAN final_pkt; /* (Put) Holds the final bit of the Put packet */
+} tBTA_MSE_OBX_PKT;
+
+/* data type for BTA_MSE_MN_INT_OPEN_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ UINT8 ccb_idx;
+ BD_ADDR bd_addr;
+ tBTA_SEC sec_mask;
+}tBTA_MSE_MN_INT_OPEN;
+
+/* data type for BTA_MSE_MN_INT_OPEN_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ UINT8 ccb_idx;
+}tBTA_MSE_MN_INT_CLOSE;
+
+/* data type for BTA_MSE_MN_SDP_OK_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ UINT8 ccb_idx;
+ UINT8 scn;
+}tBTA_MSE_MN_SDP_OK;
+
+
+/* data type for BTA_MSE_MN_SDP_FAIL_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ UINT8 ccb_idx;
+}tBTA_MSE_MN_SDP_FAIL;
+
+
+/* data type for BTA_MSE_MN_API_SEND_NOTIF_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_MA_INST_ID mas_instance_id;
+ tBTA_MSE_NOTIF_TYPE notif_type;
+ tBTA_MA_MSG_HANDLE handle;
+ char *p_folder;
+ char *p_old_folder;
+ tBTA_MA_MSG_TYPE msg_type;
+ BD_ADDR except_bd_addr;
+} tBTA_MSE_MN_API_SEND_NOTIF;
+
+/* data type for BTA_MSE_API_MN_ABORT_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_MA_INST_ID mas_instance_id;
+}tBTA_MSE_MN_API_ABORT;
+
+
+/* union of all state machine event data types */
+typedef union
+{
+ BT_HDR hdr;
+ tBTA_MSE_API_ENABLE api_enable; /* data for BTA_MSE_API_ENABLE_EVT */
+ tBTA_MSE_API_DISABLE api_disable;
+ tBTA_MSE_API_START api_start;
+ tBTA_MSE_API_STOP api_stop;
+ tBTA_MSE_API_CLOSE api_close;
+ tBTA_MSE_INT_CLOSE int_close;
+ tBTA_MSE_API_MA_CLOSE api_ma_close;
+ tBTA_MSE_API_MN_CLOSE api_mn_close;
+ tBTA_MSE_API_ACCESSRSP api_access_rsp;
+ tBTA_MSE_API_UPDINBRSP api_upd_ibx_rsp;
+ tBTA_MSE_API_SETNOTIFREGRSP api_set_notif_reg_rsp;
+ tBTA_MSE_OBX_EVT obx_evt;
+ tBTA_MSE_CI_GET_FENTRY ci_get_fentry;
+ tBTA_MSE_CI_GET_ML_INFO ci_get_ml_info;
+ tBTA_MSE_CI_GET_ML_ENTRY ci_get_ml_entry;
+ tBTA_MSE_CI_GET_MSG ci_get_msg;
+ tBTA_MSE_CI_PUSH_MSG ci_push_msg;
+ tBTA_MSE_CI_DEL_MSG ci_del_msg;
+ tBTA_MSE_MN_INT_OPEN mn_int_open;
+ tBTA_MSE_MN_INT_CLOSE mn_int_close;
+ tBTA_MSE_MN_SDP_OK mn_sdp_ok;
+ tBTA_MSE_MN_SDP_FAIL mn_sdp_fail;
+ tBTA_MSE_MN_API_SEND_NOTIF mn_send_notif;
+ tBTA_MSE_MN_API_ABORT mn_abort;
+
+} tBTA_MSE_DATA;
+
+typedef struct
+{
+ char *p_path;
+ char *p_name;
+ tBTA_MA_DIR_NAV flags;
+} tBTA_MSE_OPER_SETPATH;
+
+/* Directory Listing bufer pointer */
+typedef struct
+{
+ tBTA_MSE_CO_FOLDER_ENTRY *p_entry; /* Holds current directory entry */
+ BOOLEAN is_root; /* TRUE if path is root directory */
+} tBTA_MSE_DIRLIST;
+
+typedef struct
+{
+ UINT16 max_list_cnt;
+ UINT16 start_offset;
+ UINT16 list_cnt;
+} tBTA_MSE_OPER_FLIST_PARAM;
+
+/* Message Listing buffer pointers */
+typedef struct
+{
+ tBTA_MSE_CO_MSG_LIST_ENTRY *p_entry;
+ tBTA_MSE_CO_MSG_LIST_INFO *p_info;
+ BOOLEAN pending_ml_frag;
+ char *p_xml_buf;
+ UINT16 offset;
+ UINT16 remaing_size;
+} tBTA_MSE_MSGLIST;
+
+typedef struct
+{
+ tBTA_MA_MSG_LIST_FILTER_PARAM filter;
+ char *p_name;
+ char *p_path;
+ BOOLEAN w4info;
+} tBTA_MSE_OPER_MLIST_PARAM;
+
+
+typedef struct
+{
+ BOOLEAN notif_status_rcv;
+ tBTA_MA_NOTIF_STATUS notif_status;
+} tBTA_NOTIF_REG;
+
+typedef struct
+{
+ tBTA_MA_GET_MSG_PARAM data;
+ char *p_msg_handle;
+ UINT8 *p_frac_delivery;
+ UINT16 byte_get_cnt;
+ UINT16 filled_buff_size;
+ BOOLEAN add_frac_del_hdr;
+ tBTA_MA_FRAC_DELIVER frac_deliver_status;
+} tBTA_MSE_OPER_MSG_PARAM;
+
+typedef struct
+{
+ tBTA_MA_PUSH_MSG_PARAM param;
+ UINT16 push_byte_cnt;
+ BOOLEAN rcv_folder_name;
+ BOOLEAN rcv_charset;
+ BOOLEAN rcv_transparent;
+ BOOLEAN rcv_retry;
+ BOOLEAN first_req_pkt;
+} tBTA_MSE_OPER_PUSH_MSG;
+
+typedef struct
+{
+ char *p_msg_handle;
+ BOOLEAN rcv_msg_handle;
+ BOOLEAN rcv_sts_ind;
+ BOOLEAN rcv_sts_val;
+ tBTA_MA_MSG_HANDLE handle;
+ tBTA_MA_STS_INDCTR sts_ind;
+ tBTA_MA_STS_VALUE sts_val;
+} tBTA_MSE_OPER_SET_MSG_STS;
+
+
+/* MAS control block */
+typedef struct
+{
+ tBTA_NOTIF_REG notif_reg_req;
+ tBTA_MSE_OPER_PUSH_MSG push_msg;
+ tBTA_MSE_OPER_SET_MSG_STS set_msg_sts;
+ tBTA_MSE_OPER_SETPATH sp;
+ tBTA_MSE_OPER_FLIST_PARAM fl_param;
+ tBTA_MSE_DIRLIST dir;
+ tBTA_MSE_OPER_MLIST_PARAM ml_param;
+ tBTA_MSE_MSGLIST ml; /* point to the Message-Listing object buffer */
+ tBTA_MSE_OPER_MSG_PARAM msg_param;
+ tBTA_MSE_OBX_PKT obx;
+ char *p_workdir; /* Current working folder */
+ tOBX_HANDLE obx_handle; /* OBEX handle,used as MAS session ID as well */
+ UINT16 peer_mtu;
+ BOOLEAN cout_active; /* TRUE when waiting for a call-in function */
+ BOOLEAN aborting;
+ BD_ADDR bd_addr; /* Device currently connected to */
+ tBTA_MSE_OPER oper;
+ tBTA_MSE_MA_STATE state; /* state machine state */
+
+} tBTA_MSE_MA_SESS_CB;
+
+typedef struct
+{
+ tBTA_MSE_MA_SESS_CB sess_cb[BTA_MSE_NUM_SESS];
+ UINT32 sdp_handle; /* SDP record handle */
+ char *p_rootpath;
+ tOBX_HANDLE obx_handle; /* OBEX handle ID */
+ BOOLEAN stopping;
+ BOOLEAN in_use;
+ tBTA_SEC sec_mask;
+ tBTA_MA_MSG_TYPE sup_msg_type;
+ char servicename[BTA_SERVICE_NAME_LEN + 1];
+ UINT8 scn; /* SCN of the MA server */
+ tBTA_MA_INST_ID mas_inst_id; /* MAS instance id */
+}tBTA_MSE_MA_CB;
+
+/* state machine states */
+enum
+{
+ BTA_MSE_MN_IDLE_ST = 0, /* Idle */
+ BTA_MSE_MN_W4_CONN_ST, /* wait for connection state */
+ BTA_MSE_MN_CONN_ST, /* Connected - MAS Session is active */
+ BTA_MSE_MN_CLOSING_ST /* Closing is in progress */
+};
+typedef UINT8 tBTA_MSE_MN_STATE;
+
+/* notification registration status */
+typedef struct
+{
+ BOOLEAN status;
+ tBTA_MA_INST_ID mas_inst_id; /* only valid when status == TRUE*/
+} tBTA_MSE_MN_REG_STATUS;
+
+/* Message notification report */
+typedef struct
+{
+ UINT16 buffer_len;
+ UINT16 bytes_sent;
+ BOOLEAN final_pkt;
+ UINT8 pkt_cnt;
+ tBTA_MA_INST_ID mas_instance_id;
+ UINT8 *p_buffer;
+}tBTA_MSE_MN_MSG_NOTIF;
+
+typedef struct
+{
+ tBTA_MSE_MN_REG_STATUS notif_reg[BTA_MSE_NUM_INST];
+ tBTA_MSE_OBX_PKT obx; /* Holds the current OBX packet information */
+ tBTA_MSE_MN_MSG_NOTIF msg_notif;
+ TIMER_LIST_ENT rsp_timer; /* response timer */
+ tSDP_DISCOVERY_DB *p_db; /* pointer to discovery database */
+ tSDP_DISC_CMPL_CB *sdp_cback;
+ tOBX_HANDLE obx_handle;
+ UINT16 sdp_service;
+ UINT16 peer_mtu;
+ BOOLEAN in_use;
+ BOOLEAN req_pending; /* TRUE when waiting for an obex response */
+ BOOLEAN cout_active; /* TRUE if call-out is currently active */
+ BOOLEAN sdp_pending;
+ BD_ADDR bd_addr; /* Peer device MNS server address */
+ tBTA_MSE_MN_STATE state; /* state machine state */
+ tBTA_SEC sec_mask;
+ UINT8 timer_oper; /* current active response timer action (abort or close) */
+ UINT8 obx_oper; /* current active OBX operation PUT or GET operations */
+ UINT8 aborting;
+}tBTA_MSE_MN_CB;
+
+typedef struct
+{
+ BOOLEAN in_use;
+ BD_ADDR bd_addr;
+ BOOLEAN opened;
+ BOOLEAN busy;
+}tBTA_MSE_PM_CB;
+
+
+typedef struct
+{
+ tBTA_MSE_MA_CB scb[BTA_MSE_NUM_INST]; /* MA Server Control Blocks */
+ tBTA_MSE_MN_CB ccb[BTA_MSE_NUM_MN]; /* MN Client Control Blocks */
+ tBTA_MSE_PM_CB pcb[BTA_MSE_NUM_MN];
+ tBTA_MSE_CBACK *p_cback; /* pointer to application event callback function */
+ BOOLEAN enable;
+ BOOLEAN disabling;
+ UINT8 app_id;
+}tBTA_MSE_CB;
+
+/******************************************************************************
+** Configuration Definitions
+*******************************************************************************/
+/* Configuration structure */
+typedef struct
+{
+ INT32 abort_tout; /* Timeout in milliseconds to wait for abort OBEX response (client only) */
+ INT32 stop_tout; /* Timeout in milliseconds to wait for close OBEX response (client only) */
+
+} tBTA_MSE_MA_CFG;
+
+/*****************************************************************************
+** Global data
+*****************************************************************************/
+
+/* MAS control block */
+#if BTA_DYNAMIC_MEMORY == FALSE
+extern tBTA_MSE_CB bta_mse_cb;
+#else
+extern tBTA_MSE_CB *bta_mse_cb_ptr;
+ #define bta_mse_cb (*bta_mse_cb_ptr)
+#endif
+
+#define BTA_MSE_GET_INST_CB_PTR(inst_idx) &(bta_mse_cb.scb[(inst_idx)])
+#define BTA_MSE_GET_SESS_CB_PTR(inst_idx, sess_idx ) &(bta_mse_cb.scb[(inst_idx)].sess_cb[(sess_idx)])
+#define BTA_MSE_GET_MN_CB_PTR(ccb_idx) &(bta_mse_cb.ccb[(ccb_idx)])
+#define BTA_MSE_GET_PM_CB_PTR(pcb_idx) &(bta_mse_cb.pcb[(pcb_idx)])
+/* MAS configuration constants */
+extern tBTA_MSE_MA_CFG * p_bta_ms_cfg;
+
+/*****************************************************************************
+** Function prototypes
+*****************************************************************************/
+/* MSE event handler for MA and MN */
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+ extern BOOLEAN bta_mse_hdl_event(BT_HDR *p_msg);
+
+/* State machine drivers */
+ extern void bta_mse_ma_sm_execute(UINT8 inst_idx, UINT8 sess_idx, UINT16 event, tBTA_MSE_DATA *p_data);
+ extern void bta_mse_mn_sm_execute(UINT8 ccb_idx, UINT16 event, tBTA_MSE_DATA *p_data);
+
+ extern void bta_mse_ma_sdp_register (tBTA_MSE_MA_CB *p_scb, char *p_service_name, tBTA_MA_INST_ID inst_id, tBTA_MA_MSG_TYPE msg_type);
+
+/* Obx callback functions */
+ extern void bta_mse_ma_obx_cback (tOBX_HANDLE handle, tOBX_EVENT event,
+ tOBX_EVT_PARAM param, BT_HDR *p_pkt);
+
+ extern void bta_mse_mn_obx_cback (tOBX_HANDLE handle, tOBX_EVENT obx_event, UINT8 rsp_code,
+ tOBX_EVT_PARAM param, BT_HDR *p_pkt);
+
+/* action functions for MA */
+ extern void bta_mse_ma_int_close(UINT8 inst_idx, UINT8 sess_idx, tBTA_MSE_DATA *p_data);
+ extern void bta_mse_ma_api_accessrsp(UINT8 inst_idx, UINT8 sess_idx, tBTA_MSE_DATA *p_data);
+ extern void bta_mse_ma_api_upd_ibx_rsp(UINT8 inst_idx, UINT8 sess_idx, tBTA_MSE_DATA *p_data);
+ extern void bta_mse_ma_api_set_notif_reg_rsp(UINT8 inst_idx, UINT8 sess_idx, tBTA_MSE_DATA *p_data);
+
+ extern void bta_mse_ma_ci_get_folder_entry(UINT8 inst_idx, UINT8 sess_idx, tBTA_MSE_DATA *p_data);
+ extern void bta_mse_ma_ci_get_ml_info(UINT8 inst_idx, UINT8 sess_idx, tBTA_MSE_DATA *p_data);
+ extern void bta_mse_ma_ci_get_ml_entry(UINT8 inst_idx, UINT8 sess_idx, tBTA_MSE_DATA *p_data);
+ extern void bta_mse_ma_ci_get_msg(UINT8 inst_idx, UINT8 sess_idx, tBTA_MSE_DATA *p_data);
+ extern void bta_mse_ma_ci_push_msg(UINT8 inst_idx, UINT8 sess_idx, tBTA_MSE_DATA *p_data);
+ extern void bta_mse_ma_ci_del_msg(UINT8 inst_idx, UINT8 sess_idx, tBTA_MSE_DATA *p_data);
+
+ extern void bta_mse_ma_obx_disc(UINT8 inst_idx, UINT8 sess_idx, tBTA_MSE_DATA *p_data);
+ extern void bta_mse_ma_obx_connect(UINT8 inst_idx, UINT8 sess_idx, tBTA_MSE_DATA *p_data);
+ extern void bta_mse_ma_obx_close(UINT8 inst_idx, UINT8 sess_idx, tBTA_MSE_DATA *p_data);
+ extern void bta_mse_ma_obx_abort(UINT8 inst_idx, UINT8 sess_idx, tBTA_MSE_DATA *p_data);
+ extern void bta_mse_ma_obx_put(UINT8 inst_idx, UINT8 sess_idx, tBTA_MSE_DATA *p_data);
+ extern void bta_mse_ma_obx_get(UINT8 inst_idx, UINT8 sess_idx, tBTA_MSE_DATA *p_data);
+ extern void bta_mse_ma_obx_setpath(UINT8 inst_idx, UINT8 sess_idx, tBTA_MSE_DATA *p_data);
+ extern void bta_mse_ma_conn_err_rsp(UINT8 inst_idx, UINT8 sess_idx, tBTA_MSE_DATA *p_data);
+ extern void bta_mse_ma_close_complete(UINT8 inst_idx, UINT8 sess_idx, tBTA_MSE_DATA *p_data);
+
+/* action function for MN */
+ extern void bta_mse_mn_init_sdp(UINT8 ccb_idx, tBTA_MSE_DATA *p_data);
+ extern void bta_mse_mn_start_client(UINT8 ccb_idx, tBTA_MSE_DATA *p_data);
+ extern void bta_mse_mn_stop_client(UINT8 ccb_idx, tBTA_MSE_DATA *p_data);
+ extern void bta_mse_mn_obx_conn_rsp(UINT8 ccb_idx, tBTA_MSE_DATA *p_data);
+ extern void bta_mse_mn_close(UINT8 ccb_idx, tBTA_MSE_DATA *p_data);
+ extern void bta_mse_mn_send_notif(UINT8 ccb_idx, tBTA_MSE_DATA *p_data);
+ extern void bta_mse_mn_rsp_timeout(UINT8 ccb_idx, tBTA_MSE_DATA *p_data);
+ extern void bta_mse_mn_put_rsp(UINT8 ccb_idx, tBTA_MSE_DATA *p_data);
+ extern void bta_mse_mn_obx_tout(UINT8 ccb_idx, tBTA_MSE_DATA *p_data);
+ extern void bta_mse_mn_close_compl(UINT8 ccb_idx, tBTA_MSE_DATA *p_data);
+ extern void bta_mse_mn_ignore_obx(UINT8 ccb_idx, tBTA_MSE_DATA *p_data);
+ extern void bta_mse_mn_sdp_fail(UINT8 ccb_idx, tBTA_MSE_DATA *p_data);
+ extern void bta_mse_mn_abort(UINT8 ccb_idx, tBTA_MSE_DATA *p_data);
+ extern void bta_mse_mn_abort_rsp(UINT8 ccb_idx, tBTA_MSE_DATA *p_data);
+
+
+/* miscellaneous functions */
+ extern void bta_mse_discard_data(UINT16 event, tBTA_MSE_DATA *p_data);
+
+/* utility functions */
+
+ extern void bta_mse_send_push_msg_in_prog_evt(UINT8 inst_idx, UINT8 sess_idx);
+ extern void bta_mse_send_get_msg_in_prog_evt(UINT8 inst_idx, UINT8 sess_idx);
+ extern void bta_mse_send_oper_cmpl_evt(UINT8 inst_idx, UINT8 sess_idx, tBTA_MA_STATUS status);
+ extern void bta_mse_pushmsg(UINT8 inst_idx, UINT8 sess_idx, BOOLEAN first_pkt);
+ extern void bta_mse_clean_set_msg_sts(UINT8 inst_idx, UINT8 sess_idx);
+ extern void bta_mse_clean_set_notif_reg(UINT8 inst_idx, UINT8 sess_idx);
+ extern void bta_mse_clean_push_msg(UINT8 inst_idx, UINT8 sess_idx);
+ extern void bta_mse_init_set_msg_sts(UINT8 inst_idx, UINT8 sess_idx, UINT8 *p_rsp_code);
+ extern void bta_mse_init_push_msg(UINT8 inst_idx, UINT8 sess_idx, UINT8 *p_rsp_code);
+ extern void bta_mse_remove_uuid(void);
+ extern void bta_mse_clean_mas_service(UINT8 inst_idx);
+ extern void bta_mse_abort_too_late(UINT8 inst_idx, UINT8 sess_idx);
+ extern void bta_mse_clean_getput(UINT8 inst_idx, UINT8 sess_idx, tBTA_MA_STATUS status);
+ extern void bta_mse_clean_msg(UINT8 inst_idx, UINT8 sess_idx);
+ extern void bta_mse_end_of_msg(UINT8 inst_idx, UINT8 sess_idx, UINT8 rsp_code);
+ extern void bta_mse_getmsg(UINT8 inst_idx, UINT8 sess_idx, BOOLEAN new_req);
+ extern tBTA_MA_STATUS bta_mse_build_msg_listing_obj(tBTA_MSE_CO_MSG_LIST_ENTRY *p_entry,
+ UINT16 *p_size, char *p_buf );
+ extern void bta_mse_clean_msg_list(UINT8 inst_idx, UINT8 sess_idx);
+ extern void bta_mse_end_of_msg_list(UINT8 inst_idx, UINT8 sess_idx, UINT8 rsp_code);
+ extern UINT8 bta_mse_add_msg_list_info(UINT8 inst_idx, UINT8 sess_idx);
+ extern UINT8 bta_mse_add_msg_list_entry(UINT8 inst_idx, UINT8 sess_idx);
+ extern void bta_mse_getmsglist(UINT8 inst_idx, UINT8 sess_idx,BOOLEAN new_req);
+ extern UINT8 * bta_mse_read_app_params(BT_HDR *p_pkt, UINT8 tag, UINT16 *param_len);
+ extern void bta_mse_clean_list(UINT8 inst_idx, UINT8 sess_idx);
+ extern void bta_mse_end_of_list(UINT8 inst_idx, UINT8 sess_idx, UINT8 rsp_code);
+ extern UINT8 bta_mse_add_list_entry(UINT8 inst_idx, UINT8 sess_idx);
+ extern void bta_mse_getfolderlist(UINT8 inst_idx, UINT8 sess_idx, BOOLEAN new_req);
+ extern UINT8 bta_mse_chdir(UINT8 inst_idx, UINT8 sess_idx, tBTA_MSE_OPER *p_oper);
+ extern BOOLEAN bta_mse_send_set_notif_reg(UINT8 status,
+ UINT8 inst_idx, UINT8 sess_idx);
+ extern void bta_mse_proc_notif_reg_status(UINT8 status,
+ UINT8 inst_idx, UINT8 sess_idx);
+ extern void bta_mse_discard_data(UINT16 event, tBTA_MSE_DATA *p_data);
+ extern BOOLEAN bta_mse_find_bd_addr_match_sess_cb_idx(BD_ADDR bd_addr, UINT8 inst_idx, UINT8 *p_idx);
+ extern BOOLEAN bta_mse_find_mas_inst_id_match_cb_idx(tBTA_MA_INST_ID mas_inst_id, UINT8 *p_idx);
+ extern BOOLEAN bta_mse_find_handle_match_mas_inst_cb_idx(tOBX_HANDLE obx_handle, UINT8 *p_idx);
+ extern BOOLEAN bta_mse_find_mas_sess_cb_idx(tOBX_HANDLE obx_handle, UINT8 *p_mas_inst_idx, UINT8 *p_mas_sess_idx);
+ extern BOOLEAN bta_mse_find_ma_cb_indexes(tBTA_MSE_DATA *p_msg, UINT8 *p_inst_idx, UINT8 *p_sess_idx);
+ extern void bta_mse_ma_cleanup(tBTA_MSE_DATA *p_msg);
+ extern BOOLEAN bta_mse_is_a_duplicate_id(tBTA_MA_INST_ID mas_inst_id);
+ extern BOOLEAN bta_mse_find_avail_mas_inst_cb_idx(UINT8 *p_idx);
+ extern BOOLEAN bta_mse_find_avail_mas_sess_cb_idx(tBTA_MSE_MA_CB *p_scb, UINT8 *p_idx);
+ extern BOOLEAN bta_mse_find_sess_id_match_ma_cb_indexes(tBTA_MA_SESS_HANDLE mas_session_id,
+ UINT8 *p_inst_idx, UINT8 *p_sess_idx);
+ extern BOOLEAN bta_mse_find_avail_mn_cb_idx(UINT8 *p_idx);
+ extern BOOLEAN bta_mse_find_bd_addr_match_mn_cb_index(BD_ADDR p_bd_addr, UINT8 *p_idx);
+ extern BOOLEAN bta_mse_find_sess_id_match_mn_cb_index(tBTA_MA_SESS_HANDLE mas_session_id,
+ UINT8 *p_idx);
+ extern BOOLEAN bta_mse_find_mn_cb_index(tBTA_MSE_DATA *p_msg, UINT8 *p_ccb_idx);
+ extern void bta_mse_mn_cleanup(tBTA_MSE_DATA *p_msg);
+ extern tBTA_MA_STATUS bta_mse_build_map_event_rpt_obj(tBTA_MSE_NOTIF_TYPE notif_type,
+ tBTA_MA_MSG_HANDLE handle,
+ char * p_folder,
+ char * p_old_folder,
+ tBTA_MA_MSG_TYPE msg_typ,
+ UINT16 * p_len,
+ UINT8 * p_buffer);
+ extern void bta_mse_mn_start_timer(UINT8 ccb_idx, UINT8 timer_id);
+ extern void bta_mse_mn_stop_timer(UINT8 ccb_idx, UINT8 timer_id);
+ extern BOOLEAN bta_mse_mn_add_inst_id(UINT8 ccb_idx, tBTA_MA_INST_ID mas_inst_id);
+ extern BOOLEAN bta_mse_mn_remove_inst_id(UINT8 ccb_idx, tBTA_MA_INST_ID mas_inst_id);
+ extern void bta_mse_mn_remove_all_inst_ids(UINT8 ccb_idx);
+ extern UINT8 bta_mse_mn_find_num_of_act_inst_id(UINT8 ccb_idx);
+ extern BOOLEAN bta_mse_mn_is_inst_id_exist(UINT8 ccb_idx, tBTA_MA_INST_ID mas_inst_id );
+ extern BOOLEAN bta_mse_mn_is_ok_to_close_mn(BD_ADDR bd_addr, tBTA_MA_INST_ID mas_inst_id );
+ extern BOOLEAN bta_mse_mn_get_first_inst_id(UINT8 ccb_idx, tBTA_MA_INST_ID *p_mas_inst_id);
+ extern tBTA_MA_STATUS bta_mse_mn_cont_send_notif(UINT8 ccb_idx, BOOLEAN first_pkt);
+ extern void bta_mse_mn_send_notif_evt(tBTA_MA_INST_ID mas_instance_id, tBTA_MA_STATUS status,
+ BD_ADDR bd_addr );
+ extern void bta_mse_mn_clean_send_notif(UINT8 ccb_idx);
+ extern void bta_mse_ma_fl_read_app_params(UINT8 inst_idx, UINT8 sess_idx, BT_HDR *p_pkt);
+ extern void bta_mse_ma_ml_read_app_params(UINT8 inst_idx, UINT8 sess_idx, BT_HDR *p_pkt);
+ extern BOOLEAN bta_mse_ma_msg_read_app_params(UINT8 inst_idx, UINT8 sess_idx, BT_HDR *p_pkt);
+ extern BOOLEAN bta_mse_get_msglist_path(UINT8 inst_idx, UINT8 sess_idx);
+
+ extern BOOLEAN bta_mse_find_pm_cb_index(BD_ADDR p_bd_addr, UINT8 *p_idx);
+ extern BOOLEAN bta_mse_find_avail_pm_cb_idx(UINT8 *p_idx);
+ extern void bta_mse_pm_conn_open(BD_ADDR bd_addr);
+ extern void bta_mse_pm_conn_close(BD_ADDR bd_addr);
+ extern void bta_mse_set_ma_oper(UINT8 inst_idx, UINT8 sess_idx, tBTA_MSE_OPER oper);
+ extern void bta_mse_set_mn_oper(UINT8 ccb_idx, UINT8 oper);
+#ifdef __cplusplus
+}
+#endif
+#endif /* BTA_MSE_INT_H */
diff --git a/bta/ma/bta_mse_main.c b/bta/ma/bta_mse_main.c
new file mode 100644
index 0000000..feddd09
--- /dev/null
+++ b/bta/ma/bta_mse_main.c
@@ -0,0 +1,1367 @@
+/*****************************************************************************
+**
+** Name: bta_mse_main.c
+**
+** Description: This file contains the Message Access Server main functions
+** and state machine.
+**
+** Copyright (c) 1998-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+
+#if defined(BTA_MSE_INCLUDED) && (BTA_MSE_INCLUDED == TRUE)
+
+#include <string.h>
+
+#include "bta_fs_api.h"
+#include "bta_mse_int.h"
+#include "gki.h"
+#include "utl.h"
+#include "obx_api.h"
+
+/*****************************************************************************
+** Message Access Server State Table
+*****************************************************************************/
+/*****************************************************************************
+** Constants and types
+*****************************************************************************/
+/* state machine action enumeration list for MAS */
+enum
+{
+ BTA_MSE_MA_INT_CLOSE,
+ BTA_MSE_MA_API_ACCESSRSP,
+ BTA_MSE_MA_API_UPD_IBX_RSP,
+ BTA_MSE_MA_API_SET_NOTIF_REG_RSP,
+ BTA_MSE_MA_CI_GET_FENTRY,
+ BTA_MSE_MA_CI_GET_ML_INFO,
+ BTA_MSE_MA_CI_GET_ML_ENTRY,
+ BTA_MSE_MA_CI_GET_MSG,
+ BTA_MSE_MA_CI_PUSH_MSG,
+ BTA_MSE_MA_CI_DEL_MSG,
+ BTA_MSE_MA_OBX_CONNECT,
+ BTA_MSE_MA_OBX_DISC,
+ BTA_MSE_MA_OBX_CLOSE,
+ BTA_MSE_MA_OBX_ABORT,
+ BTA_MSE_MA_OBX_PUT,
+ BTA_MSE_MA_OBX_GET,
+ BTA_MSE_MA_OBX_SETPATH,
+ BTA_MSE_MA_CONN_ERR_RSP,
+ BTA_MSE_MA_CLOSE_COMPLETE,
+ BTA_MSE_MA_IGNORE
+};
+
+/* type for action functions */
+typedef void (*tBTA_MSE_MA_ACTION)(UINT8 inst_idx, UINT8 sess_idx, tBTA_MSE_DATA *p_data);
+
+/* action function list for MAS */
+const tBTA_MSE_MA_ACTION bta_mse_ma_action[] =
+{
+ bta_mse_ma_int_close,
+ bta_mse_ma_api_accessrsp,
+ bta_mse_ma_api_upd_ibx_rsp,
+ bta_mse_ma_api_set_notif_reg_rsp,
+ bta_mse_ma_ci_get_folder_entry,
+ bta_mse_ma_ci_get_ml_info,
+ bta_mse_ma_ci_get_ml_entry,
+ bta_mse_ma_ci_get_msg,
+ bta_mse_ma_ci_push_msg,
+ bta_mse_ma_ci_del_msg,
+ bta_mse_ma_obx_connect,
+ bta_mse_ma_obx_disc,
+ bta_mse_ma_obx_close,
+ bta_mse_ma_obx_abort,
+ bta_mse_ma_obx_put,
+ bta_mse_ma_obx_get,
+ bta_mse_ma_obx_setpath,
+ bta_mse_ma_conn_err_rsp,
+ bta_mse_ma_close_complete,
+};
+
+
+/* state table information */
+#define BTA_MSE_MA_ACTIONS 1 /* number of actions */
+#define BTA_MSE_MA_NEXT_STATE 1 /* position of next state */
+#define BTA_MSE_MA_NUM_COLS 2 /* number of columns in state tables */
+
+
+/* state table for MAS idle state */
+static const UINT8 bta_mse_ma_st_idle[][BTA_MSE_MA_NUM_COLS] =
+{
+/* Event Action 1 Next state */
+/* BTA_MSE_INT_CLOSE_EVT */ {BTA_MSE_MA_IGNORE, BTA_MSE_MA_IDLE_ST},
+/* BTA_MSE_API_ACCESSRSP_EVT */ {BTA_MSE_MA_IGNORE, BTA_MSE_MA_IDLE_ST},
+/* BTA_MSE_API_UPD_IBX_RSP_EVT*/ {BTA_MSE_MA_IGNORE, BTA_MSE_MA_IDLE_ST},
+/* BTA_MSE_API_SET_NOTIF_REG_RSP_EVT*/ {BTA_MSE_MA_IGNORE, BTA_MSE_MA_IDLE_ST},
+/* BTA_MSE_INT_START_EVT */ {BTA_MSE_MA_IGNORE, BTA_MSE_MA_IDLE_ST},
+
+/* BTA_MSE_CI_GET_FENTRY_EVT */ {BTA_MSE_MA_IGNORE, BTA_MSE_MA_IDLE_ST},
+/* BTA_MSE_CI_GET_ML_INFO_EVT */ {BTA_MSE_MA_IGNORE, BTA_MSE_MA_IDLE_ST},
+/* BTA_MSE_CI_GET_ML_ENTRY_EVT*/ {BTA_MSE_MA_IGNORE, BTA_MSE_MA_IDLE_ST},
+/* BTA_MSE_CI_GET_MSG_EVT */ {BTA_MSE_MA_IGNORE, BTA_MSE_MA_IDLE_ST},
+/* BTA_MSE_CI_PUSH_MSG_EVT */ {BTA_MSE_MA_IGNORE, BTA_MSE_MA_IDLE_ST},
+/* BTA_MSE_CI_DEL_MSG_EVT */ {BTA_MSE_MA_IGNORE, BTA_MSE_MA_IDLE_ST},
+
+/* BTA_MSE_MA_OBX_CONN_EVT */ {BTA_MSE_MA_IGNORE, BTA_MSE_MA_IDLE_ST},
+/* BTA_MSE_MA_OBX_DISC_EVT */ {BTA_MSE_MA_IGNORE, BTA_MSE_MA_IDLE_ST},
+/* BTA_MSE_MA_OBX_ABORT_EVT */ {BTA_MSE_MA_IGNORE, BTA_MSE_MA_IDLE_ST},
+/* BTA_MSE_MA_OBX_CLOSE_EVT */ {BTA_MSE_MA_IGNORE, BTA_MSE_MA_IDLE_ST},
+/* BTA_MSE_MA_OBX_PUT_EVT */ {BTA_MSE_MA_IGNORE, BTA_MSE_MA_IDLE_ST},
+/* BTA_MSE_MA_OBX_GET_EVT */ {BTA_MSE_MA_IGNORE, BTA_MSE_MA_IDLE_ST},
+/* BTA_MSE_MA_OBX_SETPATH_EVT*/ {BTA_MSE_MA_IGNORE, BTA_MSE_MA_IDLE_ST},
+/* BTA_MSE_CLOSE_CMPL_EVT */ {BTA_MSE_MA_IGNORE, BTA_MSE_MA_IDLE_ST},
+};
+
+/* state table for obex/rfcomm connection state */
+static const UINT8 bta_mse_ma_st_listen[][BTA_MSE_MA_NUM_COLS] =
+{
+/* Event Action 1 Next state */
+/* BTA_MSE_INT_CLOSE_EVT */ {BTA_MSE_MA_IGNORE, BTA_MSE_MA_LISTEN_ST},
+/* BTA_MSE_API_ACCESSRSP_EVT */ {BTA_MSE_MA_IGNORE, BTA_MSE_MA_LISTEN_ST},
+/* BTA_MSE_API_UPD_IBX_RSP_EVT*/ {BTA_MSE_MA_IGNORE, BTA_MSE_MA_LISTEN_ST},
+/* BTA_MSE_API_SET_NOTIF_REG_RSP_EVT*/{BTA_MSE_MA_IGNORE, BTA_MSE_MA_LISTEN_ST},
+/* BTA_MSE_MA_INT_START_EVT */ {BTA_MSE_MA_IGNORE, BTA_MSE_MA_LISTEN_ST},
+/* BTA_MSE_CI_GET_FENTRY_EVT */ {BTA_MSE_MA_IGNORE, BTA_MSE_MA_LISTEN_ST},
+/* BTA_MSE_CI_GET_ML_INFO_EVT */ {BTA_MSE_MA_IGNORE, BTA_MSE_MA_LISTEN_ST},
+/* BTA_MSE_CI_GET_ML_ENTRY_EVT*/ {BTA_MSE_MA_IGNORE, BTA_MSE_MA_LISTEN_ST},
+/* BTA_MSE_CI_GET_MSG_EVT */ {BTA_MSE_MA_IGNORE, BTA_MSE_MA_LISTEN_ST},
+/* BTA_MSE_CI_PUSH_MSG_EVT */ {BTA_MSE_MA_IGNORE, BTA_MSE_MA_LISTEN_ST},
+/* BTA_MSE_CI_DEL_MSG_EVT */ {BTA_MSE_MA_IGNORE, BTA_MSE_MA_LISTEN_ST},
+/* BTA_MSE_MA_OBX_CONN_EVT */ {BTA_MSE_MA_OBX_CONNECT, BTA_MSE_MA_CONN_ST},
+/* BTA_MSE_MA_OBX_DISC_EVT */ {BTA_MSE_MA_IGNORE, BTA_MSE_MA_LISTEN_ST},
+/* BTA_MSE_MA_OBX_ABORT_EVT */ {BTA_MSE_MA_IGNORE, BTA_MSE_MA_LISTEN_ST},
+/* BTA_MSE_MA_OBX_CLOSE_EVT */ {BTA_MSE_MA_IGNORE, BTA_MSE_MA_LISTEN_ST},
+/* BTA_MSE_MA_OBX_PUT_EVT */ {BTA_MSE_MA_IGNORE, BTA_MSE_MA_LISTEN_ST},
+/* BTA_MSE_MA_OBX_GET_EVT */ {BTA_MSE_MA_IGNORE, BTA_MSE_MA_LISTEN_ST},
+/* BTA_MSE_MA_OBX_SETPATH_EVT*/ {BTA_MSE_MA_IGNORE, BTA_MSE_MA_LISTEN_ST},
+/* BTA_MSE_CLOSE_CMPL_EVT */ {BTA_MSE_MA_IGNORE, BTA_MSE_MA_LISTEN_ST},
+};
+
+/* state table for open state */
+static const UINT8 bta_mse_ma_st_connected[][BTA_MSE_MA_NUM_COLS] =
+{
+/* Event Action 1 Next state */
+/* BTA_MSE_INT_CLOSE_EVT */ {BTA_MSE_MA_INT_CLOSE, BTA_MSE_MA_CLOSING_ST},
+/* BTA_MSE_API_ACCESSRSP_EVT */ {BTA_MSE_MA_API_ACCESSRSP, BTA_MSE_MA_CONN_ST},
+/* BTA_MSE_API_UPD_IBX_RSP_EVT*/ {BTA_MSE_MA_API_UPD_IBX_RSP, BTA_MSE_MA_CONN_ST},
+/* BTA_MSE_API_SET_NOTIF_REG_RSP_EVT*/{BTA_MSE_MA_API_SET_NOTIF_REG_RSP,BTA_MSE_MA_CONN_ST},
+/* BTA_MSE_MA_INT_START_EVT */ {BTA_MSE_MA_IGNORE, BTA_MSE_MA_CONN_ST},
+/* BTA_MSE_CI_GET_FENTRY_EVT */ {BTA_MSE_MA_CI_GET_FENTRY, BTA_MSE_MA_CONN_ST},
+/* BTA_MSE_CI_GET_ML_INFO_EVT */ {BTA_MSE_MA_CI_GET_ML_INFO, BTA_MSE_MA_CONN_ST},
+/* BTA_MSE_CI_GET_ML_ENTRY_EVT*/ {BTA_MSE_MA_CI_GET_ML_ENTRY, BTA_MSE_MA_CONN_ST},
+/* BTA_MSE_CI_GET_MSG_EVT */ {BTA_MSE_MA_CI_GET_MSG, BTA_MSE_MA_CONN_ST},
+/* BTA_MSE_CI_PUSH_MSG_EVT */ {BTA_MSE_MA_CI_PUSH_MSG, BTA_MSE_MA_CONN_ST},
+/* BTA_MSE_CI_DEL_MSG_EVT */ {BTA_MSE_MA_CI_DEL_MSG, BTA_MSE_MA_CONN_ST},
+/* BTA_MSE_MA_OBX_CONN_EVT */ {BTA_MSE_MA_CONN_ERR_RSP, BTA_MSE_MA_CONN_ST},
+/* BTA_MSE_MA_OBX_DISC_EVT */ {BTA_MSE_MA_OBX_DISC, BTA_MSE_MA_CLOSING_ST},
+/* BTA_MSE_MA_OBX_ABORT_EVT */ {BTA_MSE_MA_OBX_ABORT, BTA_MSE_MA_CONN_ST},
+/* BTA_MSE_MA_OBX_CLOSE_EVT */ {BTA_MSE_MA_OBX_CLOSE, BTA_MSE_MA_CLOSING_ST},
+/* BTA_MSE_MA_OBX_PUT_EVT */ {BTA_MSE_MA_OBX_PUT, BTA_MSE_MA_CONN_ST},
+/* BTA_MSE_MA_OBX_GET_EVT */ {BTA_MSE_MA_OBX_GET, BTA_MSE_MA_CONN_ST},
+/* BTA_MSE_MA_OBX_SETPATH_EVT*/ {BTA_MSE_MA_OBX_SETPATH, BTA_MSE_MA_CONN_ST},
+/* BTA_MSE_CLOSE_CMPL_EVT */ {BTA_MSE_MA_IGNORE, BTA_MSE_MA_CONN_ST},
+};
+
+/* state table for closing state */
+static const UINT8 bta_mse_ma_st_closing[][BTA_MSE_MA_NUM_COLS] =
+{
+/* Event Action 1 Next state */
+/* BTA_MSE_INT_CLOSE_EVT */ {BTA_MSE_MA_INT_CLOSE, BTA_MSE_MA_CLOSING_ST},
+/* BTA_MSE_API_ACCESSRSP_EVT */ {BTA_MSE_MA_IGNORE, BTA_MSE_MA_CLOSING_ST},
+/* BTA_MSE_API_UPD_IBX_RSP_EVT*/ {BTA_MSE_MA_IGNORE, BTA_MSE_MA_CLOSING_ST},
+/* BTA_MSE_API_SET_NOTIF_REG_RSP_EVT*/{BTA_MSE_MA_IGNORE, BTA_MSE_MA_CLOSING_ST},
+/* BTA_MSE_MA_INT_START_EVT */ {BTA_MSE_MA_IGNORE, BTA_MSE_MA_CLOSING_ST},
+/* BTA_MSE_CI_GET_FENTRY_EVT */ {BTA_MSE_MA_CLOSE_COMPLETE, BTA_MSE_MA_CLOSING_ST},
+/* BTA_MSE_CI_GET_ML_INFO_EVT*/ {BTA_MSE_MA_CLOSE_COMPLETE, BTA_MSE_MA_CLOSING_ST},
+/* BTA_MSE_CI_GET_ML_ENTRY_EVT*/ {BTA_MSE_MA_CLOSE_COMPLETE, BTA_MSE_MA_CLOSING_ST},
+/* BTA_MSE_CI_GET_MSG_EVT */ {BTA_MSE_MA_CLOSE_COMPLETE, BTA_MSE_MA_CLOSING_ST},
+/* BTA_MSE_CI_PUSH_MSG_EVT */ {BTA_MSE_MA_CLOSE_COMPLETE, BTA_MSE_MA_CLOSING_ST},
+/* BTA_MSE_CI_DEL_MSG_EVT */ {BTA_MSE_MA_CLOSE_COMPLETE, BTA_MSE_MA_CLOSING_ST},
+/* BTA_MSE_MA_OBX_CONN_EVT */ {BTA_MSE_MA_CONN_ERR_RSP, BTA_MSE_MA_CLOSING_ST},
+/* BTA_MSE_MA_OBX_DISC_EVT */ {BTA_MSE_MA_IGNORE, BTA_MSE_MA_CLOSING_ST},
+/* BTA_MSE_MA_OBX_ABORT_EVT */ {BTA_MSE_MA_OBX_ABORT, BTA_MSE_MA_CLOSING_ST},
+/* BTA_MSE_MA_OBX_CLOSE_EVT */ {BTA_MSE_MA_OBX_CLOSE, BTA_MSE_MA_CLOSING_ST},
+/* BTA_MSE_MA_OBX_PUT_EVT */ {BTA_MSE_MA_IGNORE, BTA_MSE_MA_CLOSING_ST},
+/* BTA_MSE_MA_OBX_GET_EVT */ {BTA_MSE_MA_IGNORE, BTA_MSE_MA_CLOSING_ST},
+/* BTA_MSE_MA_OBX_SETPATH_EVT*/ {BTA_MSE_MA_IGNORE, BTA_MSE_MA_CLOSING_ST},
+/* BTA_MSE_CLOSE_CMPL_EVT */ {BTA_MSE_MA_CLOSE_COMPLETE, BTA_MSE_MA_LISTEN_ST},
+};
+
+/* type for state table MAS */
+typedef const UINT8 (*tBTA_MSE_MA_ST_TBL)[BTA_MSE_MA_NUM_COLS];
+
+/* MAS state table */
+const tBTA_MSE_MA_ST_TBL bta_mse_ma_st_tbl[] =
+{
+ bta_mse_ma_st_idle,
+ bta_mse_ma_st_listen,
+ bta_mse_ma_st_connected,
+ bta_mse_ma_st_closing
+};
+
+/*****************************************************************************
+** Message Notification Client State Table
+*****************************************************************************/
+/*****************************************************************************
+** Constants and types
+*****************************************************************************/
+/* state machine action enumeration list for MNC */
+/* The order of this enumeration must be the same as bta_mse_mn_act_tbl[] */
+enum
+{
+ BTA_MSE_MN_INIT_SDP,
+ BTA_MSE_MN_START_CLIENT,
+ BTA_MSE_MN_STOP_CLIENT,
+ BTA_MSE_MN_OBX_CONN_RSP,
+ BTA_MSE_MN_CLOSE,
+ BTA_MSE_MN_SEND_NOTIF,
+ BTA_MSE_MN_RSP_TIMEOUT,
+ BTA_MSE_MN_PUT_RSP,
+ BTA_MSE_MN_OBX_TOUT,
+ BTA_MSE_MN_CLOSE_COMPL,
+ BTA_MSE_MN_ABORT,
+ BTA_MSE_MN_ABORT_RSP,
+ BTA_MSE_MN_SDP_FAIL,
+ BTA_MSE_MN_IGNORE_OBX,
+ BTA_MSE_MN_IGNORE
+};
+
+typedef void (*tBTA_MSE_MN_ACTION)(UINT8 ccb_idx, tBTA_MSE_DATA *p_data);
+
+static const tBTA_MSE_MN_ACTION bta_mse_mn_action[] =
+{
+ bta_mse_mn_init_sdp,
+ bta_mse_mn_start_client,
+ bta_mse_mn_stop_client,
+ bta_mse_mn_obx_conn_rsp,
+ bta_mse_mn_close,
+ bta_mse_mn_send_notif,
+ bta_mse_mn_rsp_timeout,
+ bta_mse_mn_put_rsp,
+ bta_mse_mn_obx_tout,
+ bta_mse_mn_close_compl,
+ bta_mse_mn_abort,
+ bta_mse_mn_abort_rsp,
+ bta_mse_mn_sdp_fail,
+ bta_mse_mn_ignore_obx
+};
+
+
+/* state table information */
+#define BTA_MSE_MN_ACTIONS 1 /* number of actions */
+#define BTA_MSE_MN_ACTION_COL 0 /* position of action */
+#define BTA_MSE_MN_NEXT_STATE 1 /* position of next state */
+#define BTA_MSE_MN_NUM_COLS 2 /* number of columns in state tables */
+
+/* state table for idle state */
+static const UINT8 bta_mse_mn_st_idle[][BTA_MSE_MN_NUM_COLS] =
+{
+/* Event Action 1 Next state */
+/* BTA_MSE_MN_INT_OPEN_EVT */ {BTA_MSE_MN_INIT_SDP, BTA_MSE_MN_W4_CONN_ST},
+/* BTA_MSE_MN_INT_CLOSE_EVT */ {BTA_MSE_MN_IGNORE, BTA_MSE_MN_IDLE_ST},
+/* BTA_MSE_MN_SDP_OK_EVT */ {BTA_MSE_MN_IGNORE, BTA_MSE_MN_IDLE_ST},
+/* BTA_MSE_MN_SDP_FAIL_EVT */ {BTA_MSE_MN_IGNORE, BTA_MSE_MN_IDLE_ST},
+/* BTA_MSE_MN_OBX_CONN_RSP_EVT */ {BTA_MSE_MN_IGNORE_OBX, BTA_MSE_MN_IDLE_ST},
+/* BTA_MSE_MN_OBX_PUT_RSP_EVT */ {BTA_MSE_MN_IGNORE_OBX, BTA_MSE_MN_IDLE_ST},
+/* BTA_MSE_MN_OBX_CLOSE_EVT */ {BTA_MSE_MN_IGNORE_OBX, BTA_MSE_MN_IDLE_ST},
+/* BTA_MSE_MN_OBX_TOUT_EVT */ {BTA_MSE_MN_IGNORE_OBX, BTA_MSE_MN_IDLE_ST},
+/* BTA_MSE_MN_CLOSE_CMPL_EVT */ {BTA_MSE_MN_IGNORE, BTA_MSE_MN_IDLE_ST},
+/* BTA_MSE_API_SEND_NOTIF_EVT */ {BTA_MSE_MN_IGNORE, BTA_MSE_MN_IDLE_ST},
+/* BTA_MSE_API_MN_ABORT_EVT */ {BTA_MSE_MN_IGNORE, BTA_MSE_MN_IDLE_ST},
+/* BTA_MSE_MN_OBX_ABORT_RSP_EVT */ {BTA_MSE_MN_IGNORE, BTA_MSE_MN_IDLE_ST},
+/* BTA_MSE_MN_RSP_TOUT_EVT */ {BTA_MSE_MN_IGNORE, BTA_MSE_MN_IDLE_ST}
+};
+
+
+/* state table for wait for authentication state */
+static const UINT8 bta_mse_mn_st_w4_conn[][BTA_MSE_MN_NUM_COLS] =
+{
+/* Event Action 1 Next state */
+/* BTA_MSE_MN_INT_OPEN_EVT */ {BTA_MSE_MN_IGNORE, BTA_MSE_MN_W4_CONN_ST},
+/* BTA_MSE_MN_INT_CLOSE_EVT */ {BTA_MSE_MN_STOP_CLIENT, BTA_MSE_MN_CLOSING_ST},
+/* BTA_MSE_MN_SDP_OK_EVT */ {BTA_MSE_MN_START_CLIENT, BTA_MSE_MN_W4_CONN_ST},
+/* BTA_MSE_MN_SDP_FAIL_EVT */ {BTA_MSE_MN_SDP_FAIL, BTA_MSE_MN_W4_CONN_ST},
+/* BTA_MSE_MN_OBX_CONN_RSP_EVT */ {BTA_MSE_MN_OBX_CONN_RSP, BTA_MSE_MN_CONN_ST},
+/* BTA_MSE_MN_OBX_PUT_RSP_EVT */ {BTA_MSE_MN_IGNORE, BTA_MSE_MN_W4_CONN_ST},
+/* BTA_MSE_MN_OBX_CLOSE_EVT */ {BTA_MSE_MN_CLOSE, BTA_MSE_MN_CLOSING_ST},
+/* BTA_MSE_MN_OBX_TOUT_EVT */ {BTA_MSE_MN_IGNORE, BTA_MSE_MN_W4_CONN_ST},
+/* BTA_MSE_MN_CLOSE_CMPL_EVT */ {BTA_MSE_MN_IGNORE, BTA_MSE_MN_W4_CONN_ST},
+/* BTA_MSE_API_SEND_NOTIF_EVT */ {BTA_MSE_MN_IGNORE, BTA_MSE_MN_W4_CONN_ST},
+/* BTA_MSE_API_MN_ABORT_EVT */ {BTA_MSE_MN_IGNORE, BTA_MSE_MN_W4_CONN_ST},
+/* BTA_MSE_MN_OBX_ABORT_RSP_EVT */ {BTA_MSE_MN_IGNORE, BTA_MSE_MN_W4_CONN_ST},
+/* BTA_MSE_MN_RSP_TOUT_EVT */ {BTA_MSE_MN_IGNORE, BTA_MSE_MN_W4_CONN_ST}
+};
+
+/* state table for connected state */
+static const UINT8 bta_mse_mn_st_connected[][BTA_MSE_MN_NUM_COLS] =
+{
+/* Event Action 1 Next state */
+/* BTA_MSE_MN_INT_OPEN_EVT */ {BTA_MSE_MN_IGNORE, BTA_MSE_MN_CONN_ST},
+/* BTA_MSE_MN_INT_CLOSE_EVT */ {BTA_MSE_MN_STOP_CLIENT, BTA_MSE_MN_CLOSING_ST},
+/* BTA_MSE_MN_SDP_OK_EVT */ {BTA_MSE_MN_IGNORE, BTA_MSE_MN_CONN_ST},
+/* BTA_MSE_MN_SDP_FAIL_EVT */ {BTA_MSE_MN_IGNORE, BTA_MSE_MN_CONN_ST},
+/* BTA_MSE_MN_OBX_CONN_RSP_EVT */ {BTA_MSE_MN_IGNORE, BTA_MSE_MN_CONN_ST},
+/* BTA_MSE_MN_OBX_PUT_RSP_EVT */ {BTA_MSE_MN_PUT_RSP, BTA_MSE_MN_CONN_ST},
+/* BTA_MSE_MN_OBX_CLOSE_EVT */ {BTA_MSE_MN_CLOSE, BTA_MSE_MN_CLOSING_ST},
+/* BTA_MSE_MN_OBX_TOUT_EVT */ {BTA_MSE_MN_OBX_TOUT, BTA_MSE_MN_CONN_ST},
+/* BTA_MSE_MN_CLOSE_CMPL_EVT */ {BTA_MSE_MN_IGNORE, BTA_MSE_MN_CONN_ST},
+/* BTA_MSE_API_SEND_NOTIF_EVT */ {BTA_MSE_MN_SEND_NOTIF, BTA_MSE_MN_CONN_ST},
+/* BTA_MSE_API_MN_ABORT_EVT */ {BTA_MSE_MN_ABORT, BTA_MSE_MN_CONN_ST},
+/* BTA_MSE_MN_OBX_ABORT_RSP_EVT */ {BTA_MSE_MN_ABORT_RSP, BTA_MSE_MN_CONN_ST},
+/* BTA_MSE_MN_RSP_TOUT_EVT */ {BTA_MSE_MN_RSP_TIMEOUT, BTA_MSE_MN_CLOSING_ST}
+};
+
+/* state table for closing state */
+static const UINT8 bta_mse_mn_st_closing[][BTA_MSE_MN_NUM_COLS] =
+{
+/* Event Action 1 Next state */
+/* BTA_MSE_MN_INT_OPEN_EVT */ {BTA_MSE_MN_IGNORE, BTA_MSE_MN_CLOSING_ST},
+/* BTA_MSE_MN_INT_CLOSE_EVT */ {BTA_MSE_MN_IGNORE, BTA_MSE_MN_CLOSING_ST},
+/* BTA_MSE_MN_SDP_OK_EVT */ {BTA_MSE_MN_CLOSE_COMPL, BTA_MSE_MN_IDLE_ST},
+/* BTA_MSE_MN_SDP_FAIL_EVT */ {BTA_MSE_MN_CLOSE_COMPL, BTA_MSE_MN_IDLE_ST},
+/* BTA_MSE_MN_OBX_CONN_RSP_EVT */ {BTA_MSE_MN_IGNORE, BTA_MSE_MN_CLOSING_ST},
+/* BTA_MSE_MN_OBX_PUT_RSP_EVT */ {BTA_MSE_MN_IGNORE_OBX, BTA_MSE_MN_CLOSING_ST},
+/* BTA_MSE_MN_OBX_CLOSE_EVT */ {BTA_MSE_MN_CLOSE, BTA_MSE_MN_CLOSING_ST},
+/* BTA_MSE_MN_OBX_TOUT_EVT */ {BTA_MSE_MN_IGNORE, BTA_MSE_MN_CLOSING_ST},
+/* BTA_MSE_MN_CLOSE_CMPL_EVT */ {BTA_MSE_MN_CLOSE_COMPL, BTA_MSE_MN_IDLE_ST},
+/* BTA_MSE_API_SEND_NOTIF_EVT */ {BTA_MSE_MN_IGNORE, BTA_MSE_MN_CLOSING_ST},
+/* BTA_MSE_API_MN_ABORT_EVT */ {BTA_MSE_MN_IGNORE, BTA_MSE_MN_CLOSING_ST},
+/* BTA_MSE_MN_OBX_ABORT_RSP_EVT */ {BTA_MSE_MN_IGNORE, BTA_MSE_MN_CLOSING_ST},
+/* BTA_MSE_MN_RSP_TOUT_EVT */ {BTA_MSE_MN_RSP_TIMEOUT, BTA_MSE_MN_CLOSING_ST}
+};
+
+/* type for state table */
+typedef const UINT8 (*tBTA_MSE_MN_ST_TBL)[BTA_MSE_MN_NUM_COLS];
+
+/* state table */
+const tBTA_MSE_MN_ST_TBL bta_mse_mn_st_tbl[] =
+{
+ bta_mse_mn_st_idle,
+ bta_mse_mn_st_w4_conn,
+ bta_mse_mn_st_connected,
+ bta_mse_mn_st_closing
+};
+/*****************************************************************************
+** Global data
+*****************************************************************************/
+
+/* MSE control block */
+#if BTA_DYNAMIC_MEMORY == FALSE
+tBTA_MSE_CB bta_mse_cb;
+#endif
+
+#if (BTA_MSE_DEBUG == TRUE) && (BT_USE_TRACES == TRUE)
+
+static char *bta_mse_evt_code(tBTA_MSE_INT_EVT evt_code);
+static char *bta_mse_ma_state_code(tBTA_MSE_MA_STATE state_code);
+static char *bta_mse_mn_state_code(tBTA_MSE_MN_STATE state_code);
+#endif
+
+/*******************************************************************************
+**
+** Function bta_mse_ma_sm_execute
+**
+** Description State machine event handling function for MA
+**
+** Parameters inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+** event - MA event
+** p_data - Pointer to the event data
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_ma_sm_execute(UINT8 inst_idx, UINT8 sess_idx, UINT16 event, tBTA_MSE_DATA *p_data)
+{
+ tBTA_MSE_MA_ST_TBL state_table;
+ UINT8 action;
+ int i;
+ tBTA_MSE_MA_SESS_CB *p_cb = &(bta_mse_cb.scb[inst_idx].sess_cb[sess_idx]);
+
+#if (BTA_MSE_DEBUG == TRUE) && (BT_USE_TRACES == TRUE)
+ tBTA_MSE_MA_STATE in_state = p_cb->state;
+ UINT16 cur_evt = event;
+ APPL_TRACE_EVENT3("MSE MA Event Handler: State 0x%02x [%s], Event [%s]", in_state,
+ bta_mse_ma_state_code(in_state),
+ bta_mse_evt_code(cur_evt));
+#endif
+
+ /* look up the state table for the current state */
+ state_table = bta_mse_ma_st_tbl[p_cb->state];
+
+ event &= 0x00FF;
+
+ /* set next state */
+ p_cb->state = state_table[event][BTA_MSE_MA_NEXT_STATE];
+
+ /* execute action functions */
+ for (i = 0; i < BTA_MSE_MA_ACTIONS; i++)
+ {
+ if ((action = state_table[event][i]) != BTA_MSE_MA_IGNORE)
+ {
+ (*bta_mse_ma_action[action])(inst_idx, sess_idx, p_data);
+ }
+ else
+ {
+ /* discard mas data */
+ bta_mse_discard_data(p_data->hdr.event, p_data);
+ break;
+ }
+ }
+#if (BTA_MSE_DEBUG == TRUE) && (BT_USE_TRACES == TRUE)
+ if (in_state != p_cb->state)
+ {
+ APPL_TRACE_EVENT3("MSE MA State Change: [%s] -> [%s] after Event [%s]",
+ bta_mse_ma_state_code(in_state),
+ bta_mse_ma_state_code(p_cb->state),
+ bta_mse_evt_code(cur_evt));
+ }
+#endif
+
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_mn_sm_execute
+**
+** Description State machine event handling function for MNC
+**
+** Parameters mn_cb_idx - Index to the MN control block
+** event - MN event
+** p_data - Pointer to the event data
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_mn_sm_execute(UINT8 mn_cb_idx, UINT16 event, tBTA_MSE_DATA *p_data)
+{
+ tBTA_MSE_MN_CB *p_cb = &(bta_mse_cb.ccb[mn_cb_idx]);
+ tBTA_MSE_MN_ST_TBL state_table;
+ UINT8 action;
+ int i;
+
+
+
+#if (BTA_MSE_DEBUG == TRUE) && (BT_USE_TRACES == TRUE)
+ tBTA_MSE_MN_STATE in_state = p_cb->state;
+ UINT16 cur_evt = event;
+ APPL_TRACE_EVENT3("MSE MN Event Handler: State 0x%02x [%s], Event [%s]", in_state,
+ bta_mse_mn_state_code(in_state),
+ bta_mse_evt_code(cur_evt));
+#endif
+
+ /* look up the state table for the current state */
+ state_table = bta_mse_mn_st_tbl[p_cb->state];
+ event -= BTA_MSE_MN_EVT_MIN;
+
+ /* set next state */
+ p_cb->state = state_table[event][BTA_MSE_MN_NEXT_STATE];
+
+ /* execute action functions */
+ for (i = 0; i < BTA_MSE_MN_ACTIONS; i++)
+ {
+ if ((action = state_table[event][i]) != BTA_MSE_MN_IGNORE)
+ {
+ (*bta_mse_mn_action[action])(mn_cb_idx, p_data);
+ }
+ else
+ {
+ /* discard mas data */
+ bta_mse_discard_data(p_data->hdr.event, p_data);
+ break;
+ }
+ }
+
+
+#if (BTA_MSE_DEBUG == TRUE) && (BT_USE_TRACES == TRUE)
+ if (in_state != p_cb->state)
+ {
+ APPL_TRACE_EVENT3("MSE MN State Change: [%s] -> [%s] after Event [%s]",
+ bta_mse_mn_state_code(in_state),
+ bta_mse_mn_state_code(p_cb->state),
+ bta_mse_evt_code(cur_evt));
+ }
+#endif
+}
+/*******************************************************************************
+**
+** Function bta_mse_ma_api_enable
+**
+** Description Process API enable request to enable MCE subsystem
+**
+** Parameters p_cb - Pointer to MSE control block
+** p_data - Pointer to MSE event data
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_mse_ma_api_enable(tBTA_MSE_CB *p_cb, tBTA_MSE_DATA *p_data)
+{
+ tBTA_MSE evt_data;
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("bta_mse_ma_api_enable" );
+#endif
+ /* If already enabled then reject this request */
+ if (p_cb->enable)
+ {
+ APPL_TRACE_ERROR0("MSE is already enabled");
+ evt_data.enable.app_id = p_data->api_enable.app_id;
+ evt_data.enable.status = BTA_MA_STATUS_FAIL;
+ p_data->api_enable.p_cback(BTA_MSE_ENABLE_EVT, (tBTA_MSE *) &evt_data);
+ return;
+ }
+
+ /* Done with checking. now perform the enable oepration*/
+ /* initialize control block */
+ memset(p_cb, 0, sizeof(tBTA_MSE_CB));
+
+ p_cb->p_cback = p_data->api_enable.p_cback;
+ p_cb->app_id = p_data->api_enable.app_id;
+ p_cb->enable = TRUE;
+
+ evt_data.enable.app_id = p_cb->app_id;
+ evt_data.enable.status = BTA_MA_STATUS_OK;
+ p_cb->p_cback(BTA_MSE_ENABLE_EVT, (tBTA_MSE *) &evt_data);
+}
+/*******************************************************************************
+**
+** Function bta_mse_ma_api_disable
+**
+** Description Process API disable request
+**
+** Parameters p_cb - Pointer to MSE control block
+** p_data - Pointer to MSE event data
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_mse_ma_api_disable(tBTA_MSE_CB *p_cb, tBTA_MSE_DATA *p_data)
+{
+ tBTA_MSE evt_data;
+ tBTA_MA_STATUS status = BTA_MA_STATUS_OK;
+ UINT8 app_id = p_data->api_disable.app_id;
+ UINT8 i,j, num_act_mas=0, num_act_sess=0;
+ tBTA_MSE_MA_CB *p_scb;
+ tBTA_MSE_MA_SESS_CB *p_sess_cb;
+ BOOLEAN send_disable_evt =FALSE;
+ tBTA_MSE_MN_CB *p_ccb;
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("bta_mse_ma_api_disable" );
+#endif
+
+ if (p_cb->enable)
+ {
+ /* close all MN connections */
+ for (i=0; i < BTA_MSE_NUM_MN; i ++)
+ {
+ p_ccb = BTA_MSE_GET_MN_CB_PTR(i);
+ if (p_ccb->in_use &&
+ (p_ccb->state != BTA_MSE_MN_IDLE_ST))
+ {
+ bta_mse_mn_remove_all_inst_ids(i);
+ bta_mse_mn_sm_execute(i,BTA_MSE_MN_INT_CLOSE_EVT, NULL);
+ }
+ }
+
+ for (i=0; i < BTA_MSE_NUM_INST ; i ++)
+ {
+ p_scb = BTA_MSE_GET_INST_CB_PTR(i);
+ if (p_scb->in_use )
+ {
+ num_act_mas++;
+ p_cb->disabling = TRUE;
+ p_scb->stopping = TRUE;
+ num_act_sess =0;
+ for (j=0; j<BTA_MSE_NUM_SESS; j++ )
+ {
+ p_sess_cb = BTA_MSE_GET_SESS_CB_PTR(i, j);
+ if (p_sess_cb->state != BTA_MSE_MA_LISTEN_ST)
+ {
+ bta_mse_ma_sm_execute(i, j, BTA_MSE_INT_CLOSE_EVT, p_data);
+ num_act_sess++;
+ }
+ }
+
+ if (!num_act_sess)
+ {
+ evt_data.stop.status = BTA_MA_STATUS_OK;
+ evt_data.stop.mas_instance_id = p_scb->mas_inst_id;
+ p_cb->p_cback(BTA_MSE_STOP_EVT, (tBTA_MSE *) &evt_data);
+ bta_mse_clean_mas_service(i);
+ num_act_mas--;
+ }
+ }
+ }
+
+ if (!num_act_mas)
+ {
+ send_disable_evt = TRUE;
+ p_cb->enable = FALSE;
+ }
+ }
+ else
+ {
+ send_disable_evt = TRUE;
+ status = BTA_MA_STATUS_FAIL;
+ }
+
+
+ if (send_disable_evt)
+ {
+ evt_data.enable.app_id = app_id;
+ evt_data.enable.status = status;
+ p_cb->p_cback(BTA_MSE_DISABLE_EVT, (tBTA_MSE *) &evt_data);
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("MSE Disabled location-1");
+#endif
+ }
+
+}
+/*******************************************************************************
+**
+** Function bta_mse_ma_api_start
+**
+** Description Process API MA server start request
+**
+** Parameters p_cb - Pointer to MSE control block
+** p_data - Pointer to MSE event data
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_mse_ma_api_start(tBTA_MSE_CB *p_cb, tBTA_MSE_DATA *p_data)
+{
+ UINT8 i = 0;
+ tBTA_MSE evt_data; /* event call back */
+ tBTA_MSE_MA_CB *p_scb = NULL; /* MA instance control block*/
+ tOBX_StartParams start_msg;
+ tBTA_MSE_API_START *p_api = &p_data->api_start;
+ tOBX_TARGET target;
+ tOBX_STATUS status;
+ tBTA_UTL_COD cod;
+ UINT8 mas_instance_idx;
+ UINT16 root_folder_len;
+ tBTA_MA_STATUS ma_status = BTA_MA_STATUS_OK;
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("bta_mse_ma_api_start" );
+#endif
+ if (!p_cb->enable || ((p_cb->enable) && bta_mse_is_a_duplicate_id(p_api->mas_inst_id)) )
+ {
+ ma_status = BTA_MA_STATUS_DUPLICATE_ID;
+ }
+
+ if ((ma_status == BTA_MA_STATUS_OK) && bta_mse_find_avail_mas_inst_cb_idx(&mas_instance_idx))
+ {
+ APPL_TRACE_EVENT1("bta_mse_ma_api_start inst_idx=%d",mas_instance_idx );
+
+ /* initialize the MA Instance control block */
+ p_scb = &(p_cb->scb[mas_instance_idx]);
+ memset(p_scb, 0, sizeof(tBTA_MSE_MA_CB));
+
+ p_scb->in_use = TRUE;
+ BCM_STRNCPY_S(p_scb->servicename, sizeof(p_scb->servicename), p_api->servicename, BTA_SERVICE_NAME_LEN);
+ p_scb->mas_inst_id = p_api->mas_inst_id;
+ p_scb->sec_mask = p_api->sec_mask;
+ p_scb->sup_msg_type = p_api->sup_msg_type;
+
+ /* If directory is specified set the length */
+ root_folder_len = p_bta_fs_cfg->max_path_len + 1;
+
+ /* Allocate an aligned memory buffer to hold the root path in the */
+ /* MAS instance cb as well as the session cbs */
+ /* Add 1 byte for '\0' */
+ if ((p_scb->p_rootpath = (char *)GKI_getbuf((UINT16)(root_folder_len+1))) != NULL)
+ {
+ memcpy(target.target, BTA_MAS_MESSAGE_ACCESS_TARGET_UUID, BTA_MAS_UUID_LENGTH);
+ target.len = BTA_MAS_UUID_LENGTH;
+ p_scb->scn = BTM_AllocateSCN();
+ BCM_STRNCPY_S(p_scb->p_rootpath, root_folder_len+1, p_api->p_root_path, root_folder_len);
+ p_scb->p_rootpath[root_folder_len] = '\0';
+
+ /* Register MAP security requirements with BTM */
+ BTM_SetSecurityLevel(FALSE, p_api->servicename, BTM_SEC_SERVICE_MAP,
+ p_api->sec_mask, BT_PSM_RFCOMM,
+ BTM_SEC_PROTO_RFCOMM, (UINT32)p_scb->scn);
+
+ /* Start up the MSE service */
+ memset(&start_msg, 0, sizeof(tOBX_StartParams));
+ start_msg.p_target = &target;
+ /* Make the MTU fit into one RFC frame */
+ start_msg.mtu = OBX_MAX_MTU;
+ start_msg.scn = p_scb->scn;
+ start_msg.authenticate = FALSE; /* OBX authentication is disabled */
+ start_msg.auth_option = (UINT8) NULL;
+ start_msg.p_cback = bta_mse_ma_obx_cback;
+ start_msg.realm_len =(UINT8) NULL;
+ start_msg.p_realm = (UINT8) NULL;
+ start_msg.realm_charset = (tOBX_CHARSET) NULL;
+ start_msg.max_sessions = BTA_MSE_NUM_SESS;
+
+ if ((status = OBX_StartServer (&start_msg, &p_scb->obx_handle)) == OBX_SUCCESS)
+ {
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT1("Obx start for MAS server: obx_hdl=%d", p_scb->obx_handle);
+#endif
+ /* initialze all session states */
+ for (i=0; i<BTA_MSE_NUM_SESS; i++ )
+ {
+ p_scb->sess_cb[i].state = BTA_MSE_MA_LISTEN_ST;
+ }
+
+ if (ma_status == BTA_MA_STATUS_OK)
+ {
+ /* Set the File Transfer service class bit */
+ cod.service = BTM_COD_SERVICE_OBJ_TRANSFER;
+ utl_set_device_class(&cod, BTA_UTL_SET_COD_SERVICE_CLASS);
+
+ /* Set up the SDP record for pbs service */
+ bta_mse_ma_sdp_register(p_scb, p_api->servicename, p_scb->mas_inst_id, p_scb->sup_msg_type );
+ }
+ else
+ {
+ /* release resources */
+ OBX_StopServer(p_scb->obx_handle);
+ for (i=0; i < BTA_MSE_NUM_SESS; i++ )
+ {
+ utl_freebuf((void**)&p_scb->sess_cb[i].p_workdir );
+ }
+ }
+ }
+ else
+ {
+ /* release resources */
+ utl_freebuf((void**)&p_scb->p_rootpath);
+ APPL_TRACE_ERROR1("OBX_StartServer returns error (%d)", status);
+ ma_status = BTA_MA_STATUS_NO_RESOURCE;
+ }
+ }
+ else /* Cannot allocate resources to run Server */
+ {
+ APPL_TRACE_ERROR0("Not enough Resources to run MSE Server");
+ ma_status = BTA_MA_STATUS_NO_RESOURCE;
+ }
+
+ if (ma_status != BTA_MA_STATUS_OK)
+ {
+ /* clearn up the contrl block*/
+ memset(p_scb, 0, sizeof(tBTA_MSE_MA_CB));
+ }
+ }
+
+ evt_data.start.mas_instance_id = p_api->mas_inst_id;
+ evt_data.start.status = ma_status;
+ p_cb->p_cback(BTA_MSE_START_EVT, (tBTA_MSE *) &evt_data);
+
+}
+/*******************************************************************************
+**
+** Function bta_mse_ma_api_stop
+**
+** Description Process API MA server stop request
+**
+** Parameters p_cb - Pointer to MSE control block
+** p_data - Pointer to MSE event data
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_mse_ma_api_stop(tBTA_MSE_CB *p_cb, tBTA_MSE_DATA *p_data)
+{
+ tBTA_MSE_API_STOP *p_stop = &p_data->api_stop;
+ BOOLEAN send_stop_evt = FALSE;
+ tBTA_MA_STATUS status = BTA_MA_STATUS_OK;
+ tBTA_MSE_MA_CB *p_scb;
+ tBTA_MSE_MA_SESS_CB *p_sess_cb;
+ tBTA_MSE_MN_CB *p_ccb;
+ UINT8 i, inst_idx;
+ UINT8 num_act_sess=0;
+ tBTA_MSE evt_data;
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("bta_mse_ma_api_stop" );
+#endif
+
+
+ if (bta_mse_find_mas_inst_id_match_cb_idx(p_stop->mas_inst_id, &inst_idx))
+ {
+ p_scb = BTA_MSE_GET_INST_CB_PTR(inst_idx);
+ p_scb->stopping = TRUE;
+
+ for (i=0; i < BTA_MSE_NUM_MN; i ++)
+ {
+ p_ccb = BTA_MSE_GET_MN_CB_PTR(i);
+ if (p_ccb->in_use &&
+ (p_ccb->state != BTA_MSE_MN_IDLE_ST) &&
+ bta_mse_mn_is_ok_to_close_mn(p_ccb->bd_addr,p_scb->mas_inst_id))
+ {
+ /* close the MN connection if mas_inst_id is the last active inst_id */
+ bta_mse_mn_remove_inst_id(i, p_scb->mas_inst_id);
+ bta_mse_mn_sm_execute(i,BTA_MSE_MN_INT_CLOSE_EVT, NULL);
+ }
+ }
+ /* close all active session */
+ for (i=0; i < BTA_MSE_NUM_SESS; i ++)
+ {
+ p_sess_cb = &(p_scb->sess_cb[i]);
+ if (p_sess_cb->state != BTA_MSE_MA_LISTEN_ST)
+ {
+ APPL_TRACE_EVENT2("Send API CLOSE to SM for STOP sess ind=%d state=%d",i,p_sess_cb->state);
+ bta_mse_ma_sm_execute(inst_idx, i, BTA_MSE_INT_CLOSE_EVT, p_data);
+ num_act_sess++;
+ }
+ }
+
+ if (!num_act_sess)
+ {
+ bta_mse_clean_mas_service(inst_idx);
+ send_stop_evt = TRUE;
+ }
+ }
+ else
+ {
+ send_stop_evt = TRUE;
+ status = BTA_MA_STATUS_FAIL;
+ }
+
+ if (send_stop_evt)
+ {
+ evt_data.stop.status = status;
+ evt_data.stop.mas_instance_id = p_stop->mas_inst_id;
+ p_cb->p_cback(BTA_MSE_STOP_EVT, (tBTA_MSE *) &evt_data);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_ma_api_close
+**
+** Description Process API close request. It will close all MA
+** sesions on the specified MAS instance ID
+**
+** Parameters p_cb - Pointer to MSE control block
+** p_data - Pointer to MSE event data
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_mse_ma_api_close(tBTA_MSE_CB *p_cb, tBTA_MSE_DATA *p_data)
+{
+ tBTA_MSE_API_CLOSE *p_close = &p_data->api_close;
+ BOOLEAN send_close_evt = FALSE;
+ tBTA_MA_STATUS status = BTA_MA_STATUS_OK;
+ tBTA_MSE_MA_CB *p_scb;
+ tBTA_MSE_MA_SESS_CB *p_sess_cb;
+ UINT8 i, inst_idx;
+ UINT8 num_act_sess=0;
+ tBTA_MSE evt_data;
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("bta_mse_ma_api_close" );
+#endif
+ if (bta_mse_find_mas_inst_id_match_cb_idx(p_close->mas_instance_id, &inst_idx))
+ {
+ p_scb = BTA_MSE_GET_INST_CB_PTR(inst_idx);
+ /* close all active sessions for the specified MA Server */
+ for (i=0; i < BTA_MSE_NUM_SESS; i ++)
+ {
+ p_sess_cb = &(p_scb->sess_cb[i]);
+ if (p_sess_cb->state != BTA_MSE_MA_LISTEN_ST)
+ {
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT4("Disconnect inst_id=%d, sess_id=%d, inst_idx=%d, sess_idx=%d",
+ p_close->mas_instance_id,
+ p_sess_cb->obx_handle,
+ inst_idx,
+ i);
+#endif
+
+ bta_mse_ma_sm_execute(inst_idx, i, BTA_MSE_INT_CLOSE_EVT, p_data);
+ num_act_sess++;
+ }
+ }
+
+ if (!num_act_sess)
+ {
+ send_close_evt = TRUE;
+ }
+ }
+ else
+ {
+ send_close_evt = TRUE;
+ status = BTA_MA_STATUS_FAIL;
+ }
+
+ if (send_close_evt)
+ {
+ evt_data.ma_close.status = status;
+ evt_data.ma_close.mas_session_id = 0;
+ evt_data.ma_close.mas_instance_id = p_close->mas_instance_id ;
+ p_cb->p_cback(BTA_MSE_MA_CLOSE_EVT, (tBTA_MSE *) &evt_data);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_ma_api_ma_close
+**
+** Description Process API MA close request. It will close the
+** specified MA session.
+**
+** Parameters p_cb - Pointer to MSE control block
+** p_data - Pointer to MSE event data
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_mse_ma_api_ma_close(tBTA_MSE_CB *p_cb, tBTA_MSE_DATA *p_data)
+{
+ tBTA_MSE_API_MA_CLOSE *p_ma_close = &p_data->api_ma_close;
+ UINT8 inst_idx, sess_idx;
+ tBTA_MSE evt_data;
+
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("bta_mse_ma_api_ma_close" );
+#endif
+
+ if (bta_mse_find_mas_inst_id_match_cb_idx (p_ma_close->mas_instance_id, &inst_idx)&&
+ bta_mse_find_bd_addr_match_sess_cb_idx(p_ma_close->bd_addr,inst_idx,&sess_idx))
+ {
+ bta_mse_ma_sm_execute(inst_idx, sess_idx, BTA_MSE_INT_CLOSE_EVT, p_data);
+ }
+ else
+ {
+ evt_data.ma_close.mas_session_id = 0xFF;
+ evt_data.ma_close.mas_instance_id = p_ma_close->mas_instance_id;
+ evt_data.ma_close.status = BTA_MA_STATUS_FAIL ;
+ p_cb->p_cback(BTA_MSE_MA_CLOSE_EVT, (tBTA_MSE *) &evt_data);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function bta_mse_mn_api_close
+**
+** Description Process API MN close request.
+**
+** Parameters p_cb - Pointer to MSE control block
+** p_data - Pointer to MSE event data
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_mse_mn_api_close(tBTA_MSE_CB *p_cb, tBTA_MSE_DATA *p_data)
+{
+ tBTA_MSE_API_MN_CLOSE *p_mn_close = &p_data->api_mn_close;
+ UINT8 ccb_idx;
+ tBTA_MSE evt_data;
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("bta_mse_mn_api_close" );
+#endif
+
+ if (bta_mse_find_bd_addr_match_mn_cb_index(p_mn_close->bd_addr, &ccb_idx))
+ {
+ bta_mse_mn_sm_execute(ccb_idx, BTA_MSE_MN_INT_CLOSE_EVT, p_data);
+ }
+ else
+ {
+ evt_data.mn_close.bd_addr[0] = '\0';
+ evt_data.mn_close.dev_name[0] = '\0';
+ p_cb->p_cback(BTA_MSE_MN_CLOSE_EVT, (tBTA_MSE *) &evt_data);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_mn_api_send_notif
+**
+** Description Process API send message notification report to all MCEs
+** registered with the specified MAS instance ID
+**
+** Parameters p_cb - Pointer to MSE control block
+** p_data - Pointer to MSE event data
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_mse_mn_api_send_notif(tBTA_MSE_CB *p_cb, tBTA_MSE_DATA *p_data)
+{
+ tBTA_MSE_MN_API_SEND_NOTIF *p_mn_send_notif = &p_data->mn_send_notif;
+ UINT8 i;
+ tBTA_MSE evt_data;
+ tBTA_MSE_MN_CB *p_ccb;
+ UINT8 active_sess_cnt;
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("bta_mse_mn_api_send_notif" );
+#endif
+
+ active_sess_cnt =0 ;
+ for (i=0; i < BTA_MSE_NUM_MN; i ++)
+ {
+ p_ccb = BTA_MSE_GET_MN_CB_PTR(i);
+
+ if (p_ccb->in_use &&
+ (p_ccb->state == BTA_MSE_MN_CONN_ST) &&
+ (memcmp(p_ccb->bd_addr, p_mn_send_notif->except_bd_addr, BD_ADDR_LEN) != 0 ) &&
+ bta_mse_mn_is_inst_id_exist(i,p_mn_send_notif->mas_instance_id))
+ {
+ bta_mse_mn_sm_execute(i, BTA_MSE_API_SEND_NOTIF_EVT, p_data);
+ active_sess_cnt++;
+ }
+ }
+
+ if (!active_sess_cnt)
+ {
+ evt_data.send_notif.mas_instance_id = p_mn_send_notif->mas_instance_id;
+ evt_data.send_notif.status = BTA_MA_STATUS_FAIL;
+ memset(evt_data.send_notif.bd_addr,0, sizeof(evt_data.send_notif.bd_addr));
+ p_cb->p_cback(BTA_MSE_SEND_NOTIF_EVT, (tBTA_MSE *) &evt_data);
+ }
+
+}
+
+
+/*******************************************************************************
+**
+** Function bta_mse_mn_api_abort
+**
+** Description Abort the current OBEX multi-packet oepration
+**
+** Parameters p_cb - Pointer to MSE control block
+** p_data - Pointer to MSE event data
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_mse_mn_api_abort(tBTA_MSE_CB *p_cb, tBTA_MSE_DATA *p_data)
+{
+ tBTA_MSE_MN_API_ABORT *p_mn_abort = &p_data->mn_abort;
+ UINT8 i;
+ tBTA_MSE_MN_CB *p_ccb;
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("bta_mse_mn_api_abort" );
+#endif
+
+ for (i=0; i < BTA_MSE_NUM_MN; i ++)
+ {
+ p_ccb = BTA_MSE_GET_MN_CB_PTR(i);
+ if (p_ccb->in_use &&
+ (p_ccb->state == BTA_MSE_MN_CONN_ST) &&
+ bta_mse_mn_is_inst_id_exist(i,p_mn_abort->mas_instance_id))
+ {
+ bta_mse_mn_sm_execute(i, BTA_MSE_API_MN_ABORT_EVT, p_data);
+ }
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_mn_rsp_tout
+**
+** Description Process MN response timer timeout event
+**
+** Parameters p_cb - Pointer to MSE control block
+** p_data - Pointer to MSE event data
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_mse_mn_rsp_tout(tBTA_MSE_CB *p_cb, tBTA_MSE_DATA *p_data)
+{
+ UINT8 ccb_idx;
+
+ ccb_idx = (UINT8)(p_data->hdr.event - BTA_MSE_MN_RSP0_TOUT_EVT);
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT1("bta_mse_mn_rsp_tout ccd_idx=%d",ccb_idx);
+#endif
+ bta_mse_mn_sm_execute(ccb_idx, BTA_MSE_MN_RSP_TOUT_EVT, p_data);
+}
+/*******************************************************************************
+**
+** Function bta_mse_hdl_event
+**
+** Description MSE main event handling function.
+**
+** Parameters p_msg - Pointer to MSE event data
+**
+** Returns void
+**
+*******************************************************************************/
+BOOLEAN bta_mse_hdl_event(BT_HDR *p_msg){
+ UINT8 inst_idx, sess_idx, ccb_idx;
+ BOOLEAN success = TRUE;
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT1("MSE Event Handler: Event [%s]",
+ bta_mse_evt_code(p_msg->event));
+#endif
+
+ switch (p_msg->event)
+ {
+ case BTA_MSE_API_ENABLE_EVT:
+ bta_mse_ma_api_enable(&bta_mse_cb, (tBTA_MSE_DATA *) p_msg);
+ break;
+
+ case BTA_MSE_API_START_EVT:
+ bta_mse_ma_api_start(&bta_mse_cb, (tBTA_MSE_DATA *) p_msg);
+ break;
+
+ case BTA_MSE_API_STOP_EVT:
+ bta_mse_ma_api_stop(&bta_mse_cb, (tBTA_MSE_DATA *) p_msg);
+ break;
+
+ case BTA_MSE_API_DISABLE_EVT:
+ bta_mse_ma_api_disable(&bta_mse_cb, (tBTA_MSE_DATA *) p_msg);
+ break;
+
+ case BTA_MSE_API_CLOSE_EVT:
+ bta_mse_ma_api_close(&bta_mse_cb, (tBTA_MSE_DATA *) p_msg);
+ break;
+
+ case BTA_MSE_API_MA_CLOSE_EVT:
+ bta_mse_ma_api_ma_close(&bta_mse_cb, (tBTA_MSE_DATA *) p_msg);
+ break;
+
+ case BTA_MSE_API_MN_CLOSE_EVT:
+ bta_mse_mn_api_close(&bta_mse_cb, (tBTA_MSE_DATA *) p_msg);
+ break;
+
+ case BTA_MSE_API_SEND_NOTIF_EVT:
+ bta_mse_mn_api_send_notif(&bta_mse_cb, (tBTA_MSE_DATA *) p_msg);
+ break;
+
+ case BTA_MSE_API_MN_ABORT_EVT:
+ bta_mse_mn_api_abort(&bta_mse_cb, (tBTA_MSE_DATA *) p_msg);
+ break;
+
+ case BTA_MSE_MN_RSP0_TOUT_EVT:
+ case BTA_MSE_MN_RSP1_TOUT_EVT:
+ case BTA_MSE_MN_RSP2_TOUT_EVT:
+ case BTA_MSE_MN_RSP3_TOUT_EVT:
+ case BTA_MSE_MN_RSP4_TOUT_EVT:
+ case BTA_MSE_MN_RSP5_TOUT_EVT:
+ case BTA_MSE_MN_RSP6_TOUT_EVT:
+ bta_mse_mn_rsp_tout(&bta_mse_cb, (tBTA_MSE_DATA *) p_msg);
+ break;
+
+ default:
+
+ if (p_msg->event < BTA_MSE_MN_EVT_MIN)
+ {
+ if (bta_mse_find_ma_cb_indexes((tBTA_MSE_DATA *) p_msg, &inst_idx, &sess_idx))
+ {
+ bta_mse_ma_sm_execute( inst_idx ,
+ sess_idx ,
+ p_msg->event, (tBTA_MSE_DATA *) p_msg);
+ }
+ else
+ {
+ APPL_TRACE_ERROR1("unable to find inst_idx and sess_idx: event=%s",
+ bta_mse_evt_code(p_msg->event));
+ success = FALSE;
+ bta_mse_ma_cleanup ((tBTA_MSE_DATA *) p_msg);
+ }
+ }
+ else
+ {
+ if (bta_mse_find_mn_cb_index((tBTA_MSE_DATA *) p_msg, &ccb_idx))
+ {
+ bta_mse_mn_sm_execute( ccb_idx,
+ p_msg->event ,
+ (tBTA_MSE_DATA *) p_msg);
+ }
+ else
+ {
+ APPL_TRACE_ERROR1("unable to find ccb_idx: event=%s",
+ bta_mse_evt_code(p_msg->event));
+ success = FALSE;
+ bta_mse_mn_cleanup ((tBTA_MSE_DATA *) p_msg);
+ }
+ }
+ break;
+ }
+
+ return(success);
+}
+
+
+/*****************************************************************************
+** Debug Functions
+*****************************************************************************/
+#if (BTA_MSE_DEBUG == TRUE) && (BT_USE_TRACES == TRUE)
+/*******************************************************************************
+**
+** Function bta_mse_ma_evt_code
+**
+** Description Maps MA event code to the corresponding event string
+**
+** Parameters evt_code - MA event code
+**
+** Returns string pointer for the associated event name
+**
+*******************************************************************************/
+static char *bta_mse_evt_code(tBTA_MSE_INT_EVT evt_code){
+ switch (evt_code)
+ {
+ case BTA_MSE_API_CLOSE_EVT:
+ return "BTA_MSE_API_CLOSE_EVT";
+ case BTA_MSE_API_MA_CLOSE_EVT:
+ return "BTA_MSE_API_MA_CLOSE_EVT";
+ case BTA_MSE_API_MN_CLOSE_EVT:
+ return "BTA_MSE_API_MN_CLOSE_EVT";
+ case BTA_MSE_INT_CLOSE_EVT:
+ return "BTA_MSE_INT_CLOSE_EVT";
+ case BTA_MSE_API_ACCESSRSP_EVT:
+ return "BTA_MSE_API_ACCESSRSP_EVT";
+ case BTA_MSE_API_UPD_IBX_RSP_EVT:
+ return "BTA_MSE_API_UPD_IBX_RSP_EVT";
+ case BTA_MSE_API_SET_NOTIF_REG_RSP_EVT:
+ return "BTA_MSE_API_SET_NOTIF_REG_RSP_EVT";
+ case BTA_MSE_INT_START_EVT:
+ return "BTA_MSE_INT_START_EVT";
+ case BTA_MSE_CI_GET_FENTRY_EVT:
+ return "BTA_MSE_CI_GET_FENTRY_EVT";
+ case BTA_MSE_CI_GET_ML_INFO_EVT:
+ return "BTA_MSE_CI_GET_ML_INFO_EVT";
+ case BTA_MSE_CI_GET_ML_ENTRY_EVT:
+ return "BTA_MSE_CI_GET_ML_ENTRY_EVT";
+ case BTA_MSE_CI_GET_MSG_EVT:
+ return "BTA_MSE_CI_GET_MSG_EVT";
+ case BTA_MSE_CI_PUSH_MSG_EVT:
+ return "BTA_MSE_CI_PUSH_MSG_EVT";
+ case BTA_MSE_CI_DEL_MSG_EVT:
+ return "BTA_MSE_CI_DEL_MSG_EVT";
+ case BTA_MSE_MA_OBX_CONN_EVT:
+ return "BTA_MSE_MA_OBX_CONN_EVT";
+ case BTA_MSE_MA_OBX_DISC_EVT:
+ return "BTA_MSE_MA_OBX_DISC_EVT";
+ case BTA_MSE_MA_OBX_ABORT_EVT:
+ return "BTA_MSE_MA_OBX_ABORT_EVT";
+ case BTA_MSE_MA_OBX_CLOSE_EVT:
+ return "BTA_MSE_MA_OBX_CLOSE_EVT";
+ case BTA_MSE_MA_OBX_PUT_EVT:
+ return "BTA_MSE_MA_OBX_PUT_EVT";
+ case BTA_MSE_MA_OBX_GET_EVT:
+ return "BTA_MSE_MA_OBX_GET_EVT";
+ case BTA_MSE_MA_OBX_SETPATH_EVT:
+ return "BTA_MSE_MA_OBX_SETPATH_EVT";
+ case BTA_MSE_CLOSE_CMPL_EVT:
+ return "BTA_MSE_CLOSE_CMPL_EVT";
+ case BTA_MSE_MN_INT_OPEN_EVT:
+ return "BTA_MSE_MN_INT_OPEN_EVT";
+ case BTA_MSE_MN_INT_CLOSE_EVT:
+ return "BTA_MSE_MN_INT_CLOSE_EVT";
+ case BTA_MSE_MN_SDP_OK_EVT:
+ return "BTA_MSE_MN_SDP_OK_EVT";
+ case BTA_MSE_MN_SDP_FAIL_EVT:
+ return "BTA_MSE_MN_SDP_FAIL_EVT";
+ case BTA_MSE_MN_OBX_CONN_RSP_EVT:
+ return "BTA_MSE_MN_OBX_CONN_RSP_EVT";
+ case BTA_MSE_MN_OBX_PUT_RSP_EVT:
+ return "BTA_MSE_MN_OBX_PUT_RSP_EVT";
+ case BTA_MSE_MN_OBX_CLOSE_EVT:
+ return "BTA_MSE_MN_OBX_CLOSE_EVT";
+ case BTA_MSE_MN_OBX_TOUT_EVT:
+ return "BTA_MSE_MN_OBX_TOUT_EVT";
+ case BTA_MSE_MN_CLOSE_CMPL_EVT:
+ return "BTA_MSE_MN_CLOSE_CMPL_EVT";
+ case BTA_MSE_API_SEND_NOTIF_EVT:
+ return "BTA_MSE_API_SEND_NOTIF_EVT";
+ case BTA_MSE_API_MN_ABORT_EVT:
+ return "BTA_MSE_API_MN_ABORT_EVT";
+ case BTA_MSE_MN_OBX_ABORT_RSP_EVT:
+ return "BTA_MSE_MN_OBX_ABORT_RSP_EVT";
+ case BTA_MSE_API_ENABLE_EVT:
+ return "BTA_MSE_API_ENABLE_EVT";
+ case BTA_MSE_API_START_EVT:
+ return "BTA_MSE_API_START_EVT";
+ case BTA_MSE_API_STOP_EVT:
+ return "BTA_MSE_API_STOP_EVT";
+ default:
+ return "Unknown MSE event code";
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_ma_state_code
+**
+** Description Maps MA state code to the corresponding state string
+**
+** Parameters state_code - MA state code
+**
+** Returns string pointer for the associated state name
+**
+*******************************************************************************/
+static char *bta_mse_ma_state_code(tBTA_MSE_MA_STATE state_code){
+ switch (state_code)
+ {
+ case BTA_MSE_MA_IDLE_ST:
+ return "BTA_MSE_MA_IDLE_ST";
+ case BTA_MSE_MA_LISTEN_ST:
+ return "BTA_MSE_MA_LISTEN_ST";
+ case BTA_MSE_MA_CONN_ST:
+ return "BTA_MSE_MA_CONN_ST";
+ case BTA_MSE_MA_CLOSING_ST:
+ return "BTA_MSE_MA_CLOSING_ST";
+ default:
+ return "Unknown MA state code";
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function bta_mse_mn_state_code
+**
+** Description Maps MN state code to the corresponding state string
+**
+** Parameters state_code - MN state code
+**
+** Returns string pointer for the associated state name
+**
+*******************************************************************************/
+static char *bta_mse_mn_state_code(tBTA_MSE_MN_STATE state_code){
+ switch (state_code)
+ {
+ case BTA_MSE_MN_IDLE_ST:
+ return "BTA_MSE_MN_IDLE_ST";
+ case BTA_MSE_MN_W4_CONN_ST:
+ return "BTA_MSE_MN_W4_CONN_ST";
+ case BTA_MSE_MN_CONN_ST:
+ return "BTA_MSE_MN_CONN_ST";
+ case BTA_MSE_MN_CLOSING_ST:
+ return "BTA_MSE_MN_CLOSING_ST";
+ default:
+ return "Unknown MN state code";
+ }
+}
+
+#endif /* Debug Functions */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#endif /* BTA_MSE_INCLUDED */
diff --git a/bta/ma/bta_mse_sdp.c b/bta/ma/bta_mse_sdp.c
new file mode 100644
index 0000000..a56e07f
--- /dev/null
+++ b/bta/ma/bta_mse_sdp.c
@@ -0,0 +1,63 @@
+/*****************************************************************************
+**
+** Name: bta_mse_sdp.c
+**
+** File: Implements the SDP functions used by Message Access Server
+**
+** Copyright (c) 1998-2009, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include <string.h>
+
+#include "sdp_api.h"
+#include "bta_mse_int.h"
+#include "goep_util.h"
+
+/*****************************************************************************
+**
+** Function: bta_mas_sdp_register
+**
+** Purpose: Register the Message Access service with SDP
+**
+** Parameters: p_cb - Pointer to MA instance control block
+** p_service_name - MA server name
+** inst_id - MAS instance ID
+** msg_type - Supported message type(s)
+**
+**
+** Returns: void
+**
+*****************************************************************************/
+void bta_mse_ma_sdp_register (tBTA_MSE_MA_CB *p_cb, char *p_service_name,
+ tBTA_MA_INST_ID inst_id,
+ tBTA_MA_MSG_TYPE msg_type)
+{
+ UINT16 mas_service = UUID_SERVCLASS_MESSAGE_ACCESS;
+ tGOEP_ERRORS goep_status;
+
+ goep_status = GOEP_Register(p_service_name, &p_cb->sdp_handle, p_cb->scn,
+ 1, &mas_service, UUID_SERVCLASS_MAP_PROFILE,
+ BTA_MAS_DEFAULT_VERSION);
+ if (goep_status == GOEP_SUCCESS)
+ {
+ /* add instance ID */
+ SDP_AddAttribute(p_cb->sdp_handle, ATTR_ID_MAS_INSTANCE_ID, UINT_DESC_TYPE,
+ (UINT32)1, (UINT8*)&inst_id);
+
+ /* add supported message type */
+ SDP_AddAttribute(p_cb->sdp_handle, ATTR_ID_SUPPORTED_MSG_TYPE, UINT_DESC_TYPE,
+ (UINT32)1, (UINT8*)&msg_type);
+
+ bta_sys_add_uuid(mas_service); /* UUID_SERVCLASS_MESSAGE_ACCESS */
+ APPL_TRACE_DEBUG1("MAS: SDP Registered (handle 0x%08x)", p_cb->sdp_handle);
+ }
+ else
+ {
+ if (p_cb->sdp_handle) SDP_DeleteRecord(p_cb->sdp_handle);
+ APPL_TRACE_ERROR0("bta_mse_ma_sdp_register FAILED");
+ }
+
+ return;
+}
diff --git a/bta/ma/bta_mse_utils.c b/bta/ma/bta_mse_utils.c
new file mode 100644
index 0000000..2b14b7a
--- /dev/null
+++ b/bta/ma/bta_mse_utils.c
@@ -0,0 +1,3867 @@
+/*********************************************a********************************
+**
+** Name: bta_mse_utils.c
+**
+** Description: This file implements utility functions for the
+** file transfer server.
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+
+#if defined(BTA_MSE_INCLUDED) && (BTA_MSE_INCLUDED == TRUE)
+
+#include <stdio.h>
+#include <string.h>
+#include "gki.h"
+#include "utl.h"
+#include "bd.h"
+#include "bta_fs_api.h"
+#include "bta_mse_int.h"
+#include "bta_fs_co.h"
+#include "bta_mse_co.h"
+
+#include "bta_ma_util.h"
+
+
+/*******************************************************************************
+* Macros for MSE
+*******************************************************************************/
+#define BTA_MSE_XML_EOL "\n"
+#define BTA_MSE_FOLDER_LISTING_START ( "<?xml version=\"1.0\"?>\n" \
+ "<!DOCTYPE folder-listing SYSTEM \"obex-folder-listing.dtd\">\n" \
+ "<folder-listing version=\"1.0\">\n" )
+
+#define BTA_MSE_FOLDER_LISTING_END ( "</folder-listing>" )
+#define BTA_MSE_PARENT_FOLDER (" <parent-folder/>\n")
+
+#define BTA_MSE_FILE_ELEM "file"
+#define BTA_MSE_FOLDER_ELEM "folder"
+#define BTA_MSE_NAME_ATTR "name"
+#define BTA_MSE_SIZE_ATTR "size"
+#define BTA_MSE_TYPE_ATTR "type"
+#define BTA_MSE_MODIFIED_ATTR "modified"
+#define BTA_MSE_CREATED_ATTR "created"
+#define BTA_MSE_ACCESSED_ATTR "accessed"
+#define BTA_MSE_USER_PERM_ATTR "user-perm"
+
+#define BTA_MSE_MSG_LISTING_START ( "<MAP-msg-listing version=\"1.0\">\n" )
+#define BTA_MSE_MSG_LISTING_END ( "</MAP-msg-listing>" )
+
+
+// btla-specific ++
+#define BTA_MSE_ENABLE_FS_CO FALSE
+// btla-specific --
+
+/*******************************************************************************
+**
+** Function bta_mse_send_push_msg_in_prog_evt
+**
+** Description send the push message in progress event
+**
+** Parameters inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+**
+** Returns void
+**
+*******************************************************************************/
+
+void bta_mse_send_push_msg_in_prog_evt(UINT8 inst_idx, UINT8 sess_idx)
+{
+ tBTA_MSE_MA_SESS_CB *p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, sess_idx);
+ tBTA_MSE_OPER_PUSH_MSG *p_push_msg = &p_cb->push_msg;
+ tBTA_MSE cback_evt_data;
+ tBTA_MSE *p_data = &cback_evt_data;
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT2("bta_mse_send_push_msg_in_prog_evt inst_idx=%d sess_idx=%d",
+ inst_idx,sess_idx);
+#endif
+
+ p_data->push_msg_in_prog.mas_session_id = p_cb->obx_handle;
+ p_data->push_msg_in_prog.bytes = p_cb->obx.offset;
+ p_data->push_msg_in_prog.obj_size = p_push_msg->push_byte_cnt;
+ bta_mse_cb.p_cback(BTA_MSE_PUSH_MSG_IN_PROG_EVT, (tBTA_MSE *) p_data);
+}
+/*******************************************************************************
+**
+** Function bta_mse_send_get_msg_in_prog_evt
+**
+** Description Sends the get message in progress event
+**
+** Parameters inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_send_get_msg_in_prog_evt(UINT8 inst_idx, UINT8 sess_idx)
+{
+ tBTA_MSE_MA_SESS_CB *p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, sess_idx);
+ tBTA_MSE_OPER_MSG_PARAM *p_param = &p_cb->msg_param;
+ tBTA_MSE cback_evt_data;
+ tBTA_MSE *p_data = &cback_evt_data;
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT2("bta_mse_send_get_msg_in_prog_evt inst_idx=%d sess_idx=%d",
+ inst_idx,sess_idx);
+#endif
+
+ p_data->get_msg_in_prog.mas_session_id = (tBTA_MA_SESS_HANDLE) p_cb->obx_handle;
+ p_data->get_msg_in_prog.bytes = p_param->filled_buff_size;
+ p_data->get_msg_in_prog.obj_size = p_param->byte_get_cnt;
+ bta_mse_cb.p_cback(BTA_MSE_GET_MSG_IN_PROG_EVT, (tBTA_MSE *) p_data);
+}
+/*******************************************************************************
+**
+** Function bta_mse_send_oper_cmpl_evt
+**
+** Description Sends the operartion complete event based on the specified status
+**
+** Parameters inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+** status - MA status code
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_send_oper_cmpl_evt(UINT8 inst_idx, UINT8 sess_idx, tBTA_MA_STATUS status)
+{
+ tBTA_MSE_MA_SESS_CB *p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, sess_idx);
+ tBTA_MSE_OPER_MSG_PARAM *p_param = &p_cb->msg_param;
+ tBTA_MSE_OPER_PUSH_MSG *p_push_msg = &p_cb->push_msg;
+ tBTA_MSE cback_evt_data;
+ tBTA_MSE *p_data = &cback_evt_data;
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT3("bta_mse_send_oper_cmpl_evt inst_idx=%d sess_idx=%d status=%d",
+ inst_idx, sess_idx, status);
+#endif
+
+ p_data->oper_cmpl.mas_session_id = p_cb->obx_handle;
+ p_data->oper_cmpl.operation = p_cb->oper;
+ p_data->oper_cmpl.status = status;
+ switch (p_cb->oper)
+ {
+ case BTA_MSE_OPER_GET_MSG:
+ p_data->oper_cmpl.obj_size = p_param->byte_get_cnt;
+ break;
+ case BTA_MSE_OPER_PUSH_MSG:
+ p_data->oper_cmpl.obj_size = p_push_msg->push_byte_cnt;
+ break;
+ default:
+ p_data->oper_cmpl.obj_size = 0;
+ break;
+ }
+ bta_mse_cb.p_cback(BTA_MSE_OPER_CMPL_EVT, (tBTA_MSE *) p_data);
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_pushmsg
+**
+** Description Process the push message request
+**
+** Parameters inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+** first_pkt - first packet of the push message request
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_pushmsg(UINT8 inst_idx, UINT8 sess_idx, BOOLEAN first_pkt)
+{
+ tBTA_MSE_MA_SESS_CB *p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, sess_idx);
+ tBTA_MSE_OPER_PUSH_MSG *p_push_msg = &p_cb->push_msg;
+ tBTA_MSE_OBX_PKT *p_obx = &p_cb->obx;
+ tBTA_MA_MPKT_STATUS mpkt_status;
+
+ p_push_msg->push_byte_cnt += p_obx->offset;
+ p_cb->cout_active = TRUE;
+ mpkt_status = BTA_MA_MPKT_STATUS_LAST;
+ if (!p_obx->final_pkt) mpkt_status = BTA_MA_MPKT_STATUS_MORE;
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT5("bta_mse_pushmsg i_idx=%d s_idx=%d first=%d final=%d cnt=%d",
+ inst_idx, sess_idx, first_pkt, p_obx->final_pkt,
+ p_push_msg->push_byte_cnt);
+#endif
+
+
+ bta_mse_co_push_msg((tBTA_MA_SESS_HANDLE) p_cb->obx_handle, &p_push_msg->param,
+ p_obx->offset, p_obx->p_start, first_pkt,
+ mpkt_status, BTA_MSE_CI_PUSH_MSG_EVT, bta_mse_cb.app_id);
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_clean_set_msg_sts
+**
+** Description Cleans up the set message status resources and cotrol block
+**
+** Parameters inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_clean_set_msg_sts(UINT8 inst_idx, UINT8 sess_idx)
+{
+ tBTA_MSE_MA_SESS_CB *p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, sess_idx);
+ tBTA_MSE_OPER_SET_MSG_STS *p_set_msg_sts = &p_cb->set_msg_sts;
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("bta_mse_clean_set_msg_sts");
+#endif
+
+ utl_freebuf((void**)&(p_set_msg_sts->p_msg_handle));
+ bta_mse_set_ma_oper(inst_idx, sess_idx, BTA_MSE_OPER_NONE);
+
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_clean_set_notif_reg
+**
+** Description Cleans up the set notification registration resources and cotrol block
+**
+** Parameters inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_clean_set_notif_reg(UINT8 inst_idx, UINT8 sess_idx)
+{
+ tBTA_MSE_MA_SESS_CB *p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, sess_idx);
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("bta_mse_clean_set_notif_reg");
+#endif
+
+ p_cb->notif_reg_req.notif_status_rcv = FALSE;
+ bta_mse_set_ma_oper(inst_idx, sess_idx, BTA_MSE_OPER_NONE);
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_clean_push_msg
+**
+** Description Cleans up the push message resources and cotrol block
+**
+** Parameters inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_clean_push_msg(UINT8 inst_idx, UINT8 sess_idx)
+{
+ tBTA_MSE_MA_SESS_CB *p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, sess_idx);
+ tBTA_MSE_OPER_PUSH_MSG *p_push_msg = &p_cb->push_msg;
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("bta_mse_clean_push_msg");
+#endif
+
+ utl_freebuf((void**)&(p_push_msg->param.p_folder));
+ bta_mse_set_ma_oper(inst_idx, sess_idx, BTA_MSE_OPER_NONE);
+
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_init_set_msg_sts
+**
+** Description Initializes the set message status resources and cotrol block
+**
+** Parameters inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+** p_rsp_code - (output) pointer to the obex response code
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_init_set_msg_sts(UINT8 inst_idx, UINT8 sess_idx, UINT8 *p_rsp_code)
+{
+ tBTA_MSE_MA_SESS_CB *p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, sess_idx);
+ tBTA_MSE_OPER_SET_MSG_STS *p_set_msg_sts = &p_cb->set_msg_sts;
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("bta_mse_init_set_msg_sts");
+#endif
+ *p_rsp_code = OBX_RSP_OK;
+
+
+
+ p_set_msg_sts->rcv_msg_handle = FALSE;
+ p_set_msg_sts->rcv_sts_ind = FALSE;
+ p_set_msg_sts->rcv_sts_val = FALSE;
+
+ if (!p_set_msg_sts->p_msg_handle)
+ {
+ if ((p_set_msg_sts->p_msg_handle = (char *)GKI_getbuf((UINT16)(BTA_MSE_64BIT_HEX_STR_SIZE))) == NULL )
+ {
+ *p_rsp_code = OBX_RSP_INTRNL_SRVR_ERR;
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_init_push_msg
+**
+** Description initializes the push message resources and control block
+**
+** Parameters inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+** p_rsp_code - (output) pointer to the obex response code
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_init_push_msg(UINT8 inst_idx, UINT8 sess_idx, UINT8 *p_rsp_code)
+{
+ tBTA_MSE_MA_SESS_CB *p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, sess_idx);
+ tBTA_MSE_OPER_PUSH_MSG *p_push_msg = &p_cb->push_msg;
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("bta_mse_init_push_msg");
+#endif
+ *p_rsp_code = OBX_RSP_OK;
+
+
+ p_push_msg->push_byte_cnt = 0;
+ p_push_msg->first_req_pkt = TRUE;
+ p_push_msg->rcv_charset = FALSE;
+ p_push_msg->rcv_folder_name = FALSE;
+ p_push_msg->rcv_retry = FALSE;
+ p_push_msg->rcv_transparent = FALSE;
+ p_push_msg->param.transparent = BTA_MA_TRANSP_OFF;
+ p_push_msg->param.retry = BTA_MA_RETRY_OFF;
+
+ if (!p_push_msg->param.p_folder)
+ {
+ if ((p_push_msg->param.p_folder = (char *)GKI_getbuf((UINT16)(p_bta_mse_cfg->max_name_len + 1))) == NULL )
+ {
+ *p_rsp_code = OBX_RSP_INTRNL_SRVR_ERR;
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function bta_mse_remove_uuid
+**
+** Description Remove UUID and clear service
+**
+** Parameters none
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_remove_uuid(void)
+{
+ bta_sys_remove_uuid(UUID_SERVCLASS_MESSAGE_ACCESS);
+ BTM_SecClrService(BTM_SEC_SERVICE_MAP);
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_clean_mas_service
+**
+** Description Cleans up the MAS service resources and control block
+**
+** Parameters inst_idx - Index to the MA instance control block
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_clean_mas_service(UINT8 inst_idx)
+{
+ tBTA_MSE_MA_CB *p_scb = BTA_MSE_GET_INST_CB_PTR(inst_idx);
+ tBTA_MSE_MA_SESS_CB *p_cb;
+ int i, num_act_mas =0;
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("bta_mse_clean_mas_service");
+#endif
+ OBX_StopServer(p_scb->obx_handle);
+ BTM_FreeSCN(p_scb->scn);
+ if (p_scb->sdp_handle) SDP_DeleteRecord(p_scb->sdp_handle);
+
+ utl_freebuf((void**)&p_scb->p_rootpath);
+ for (i=0; i < BTA_MSE_NUM_SESS; i++ )
+ {
+ p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, i);
+ utl_freebuf((void**)&p_cb->p_workdir);
+ }
+ p_scb->in_use = FALSE;
+
+ /* check all other MAS instances */
+ for (i=0; i < BTA_MSE_NUM_INST ; i ++)
+ {
+ p_scb = BTA_MSE_GET_INST_CB_PTR(i);
+ if (p_scb->in_use) num_act_mas++;
+ }
+
+ if (!num_act_mas) bta_mse_remove_uuid();
+}
+
+
+/*******************************************************************************
+**
+** Function bta_mse_abort_too_late
+**
+** Description It is too late to abort the operation
+**
+** Parameters inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_abort_too_late(UINT8 inst_idx, UINT8 sess_idx)
+{
+ tBTA_MSE_MA_SESS_CB *p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, sess_idx);
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT1("bta_mse_abort_too_late oper=%d ",p_cb->oper );
+#endif
+ OBX_AbortRsp(p_cb->obx_handle, OBX_RSP_FORBIDDEN, (BT_HDR *)NULL);
+ p_cb->aborting = FALSE;
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_clean_getput
+**
+** Description Cleans up get and put resources and control blocks
+**
+** Parameters inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+** status - operation status
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_clean_getput(UINT8 inst_idx, UINT8 sess_idx, tBTA_MA_STATUS status)
+{
+ tBTA_MSE_MA_SESS_CB *p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, sess_idx);
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT2("bta_mse_clean_getput oper=%d status=%d",p_cb->oper, status );
+#endif
+ if (status == BTA_MA_STATUS_ABORTED)
+ {
+ OBX_AbortRsp(p_cb->obx_handle, OBX_RSP_OK, (BT_HDR *)NULL);
+ p_cb->aborting = FALSE;
+ }
+ switch (p_cb->oper)
+ {
+ case BTA_MSE_OPER_UPDATE_INBOX:
+ bta_mse_set_ma_oper(inst_idx,sess_idx, BTA_MSE_OPER_NONE);
+ break;
+ case BTA_MSE_OPER_GET_FOLDER_LIST:
+ bta_mse_clean_list(inst_idx,sess_idx);
+ break;
+ case BTA_MSE_OPER_GET_MSG_LIST:
+ bta_mse_clean_msg_list(inst_idx,sess_idx);
+ break;
+ case BTA_MSE_OPER_GET_MSG:
+ bta_mse_send_oper_cmpl_evt(inst_idx,sess_idx, status);
+ bta_mse_clean_msg(inst_idx,sess_idx);
+ break;
+ case BTA_MSE_OPER_PUSH_MSG:
+ bta_mse_send_oper_cmpl_evt(inst_idx,sess_idx, status);
+ bta_mse_clean_push_msg(inst_idx,sess_idx);
+ break;
+ case BTA_MSE_OPER_DEL_MSG:
+ case BTA_MSE_OPER_SET_MSG_STATUS:
+ bta_mse_clean_set_msg_sts(inst_idx,sess_idx);
+ break;
+
+ default:
+ break;
+ }
+
+ utl_freebuf((void**)&p_cb->obx.p_pkt);
+ p_cb->obx.bytes_left = 0;
+
+}
+
+
+/*******************************************************************************
+**
+** Function bta_mse_clean_msg
+**
+** Description Cleans up the get message resources and control block
+**
+** Parameters inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_clean_msg(UINT8 inst_idx, UINT8 sess_idx)
+{
+ tBTA_MSE_MA_SESS_CB *p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, sess_idx);
+ /* Clean up control block */
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("bta_mse_clean_msg");
+#endif
+ utl_freebuf((void **)&p_cb->msg_param.p_msg_handle);
+ bta_mse_set_ma_oper(inst_idx, sess_idx, BTA_MSE_OPER_NONE);
+
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_end_of_msg
+**
+** Description Complete the end body of the get message response, and
+** sends out the OBX get response
+**
+** Parameters inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+** rsp_code - Obex response code
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_end_of_msg(UINT8 inst_idx, UINT8 sess_idx, UINT8 rsp_code)
+{
+ tBTA_MSE_MA_SESS_CB *p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, sess_idx);
+ tBTA_MSE_OBX_PKT *p_obx = &p_cb->obx;
+ tBTA_MSE_OPER_MSG_PARAM *p_param = &p_cb->msg_param;
+
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("bta_mse_end_of_msg");
+#endif
+ /* Add the end of folder listing string if successful operation */
+ if (rsp_code == OBX_RSP_OK || rsp_code == OBX_RSP_CONTINUE)
+ {
+ /* If get message has completed, update the fraction delivery status */
+
+ if (p_param->add_frac_del_hdr)
+ {
+ *(p_param->p_frac_delivery) = p_param->frac_deliver_status;
+ p_param->add_frac_del_hdr = FALSE;
+ }
+
+ p_obx->offset += p_param->filled_buff_size;
+
+ if (rsp_code == OBX_RSP_OK)
+ {
+ OBX_AddBodyEnd(p_obx->p_pkt, p_obx->p_start, p_obx->offset, TRUE);
+ }
+ else /* More data to be sent */
+ OBX_AddBodyEnd(p_obx->p_pkt, p_obx->p_start, p_obx->offset, FALSE);
+
+ OBX_GetRsp(p_cb->obx_handle, rsp_code, (BT_HDR *)p_obx->p_pkt);
+ p_obx->p_pkt = NULL; /* Do not deallocate buffer; OBX will */
+
+ if (rsp_code == OBX_RSP_CONTINUE)
+ {
+ bta_mse_send_get_msg_in_prog_evt(inst_idx, sess_idx);
+ }
+ else
+ {
+ bta_mse_clean_getput(inst_idx, sess_idx, BTA_MA_STATUS_OK);
+ }
+ }
+ else /* An error occurred */
+ {
+ OBX_GetRsp(p_cb->obx_handle, rsp_code, (BT_HDR *)NULL);
+ bta_mse_clean_getput(inst_idx, sess_idx, BTA_MA_STATUS_FAIL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_getmsg
+**
+** Description Processes the get message request
+**
+** Parameters inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_getmsg(UINT8 inst_idx, UINT8 sess_idx, BOOLEAN new_req)
+{
+ tBTA_MSE_MA_SESS_CB *p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, sess_idx);
+ tBTA_MSE_OBX_PKT *p_obx = &p_cb->obx;
+ tBTA_MSE_OPER_MSG_PARAM *p_param = &p_cb->msg_param;
+ UINT8 rsp_code = OBX_RSP_OK;
+ UINT8 *p, *p_start;
+ UINT16 len = 0;
+ BOOLEAN first_get=FALSE;
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("bta_mse_getmsg");
+#endif
+
+ p_obx->p_pkt = (BT_HDR *)OBX_HdrInit(p_cb->obx_handle,
+ /* p_cb->peer_mtu */ OBX_LRG_DATA_POOL_SIZE);
+ if (p_obx->p_pkt)
+ {
+ /* Is this a new request or continuation? */
+ if (new_req)
+ {
+ first_get = TRUE;
+ if (p_param->add_frac_del_hdr)
+ {
+ /* Add Fraction Deliver Header */
+ p_start = OBX_AddByteStrStart(p_obx->p_pkt, &len);
+ p = p_start;
+ *p++ = BTA_MA_APH_FRAC_DELVR;
+ *p++ = 1;
+ p_param->p_frac_delivery = p;
+ /* use Last as default and it can be changed to More if application indicates more */
+ UINT8_TO_BE_STREAM(p, BTA_MA_FRAC_DELIVER_LAST);
+ OBX_AddByteStrHdr(p_obx->p_pkt, OBX_HI_APP_PARMS, NULL, (UINT16)(p - p_start));
+ }
+ }
+
+ /* Add the start of the Body Header */
+ p_obx->offset = 0;
+ p_obx->bytes_left = 0;
+ p_obx->p_start = OBX_AddBodyStart(p_obx->p_pkt, &p_obx->bytes_left);
+ p_cb->cout_active = TRUE;
+ bta_mse_co_get_msg((tBTA_MA_SESS_HANDLE) p_cb->obx_handle,
+ &p_param->data,
+ first_get,
+ p_obx->bytes_left,
+ p_obx->p_start,
+ BTA_MSE_CI_GET_MSG_EVT,
+ bta_mse_cb.app_id);
+
+ /* List is not complete, so don't send the response yet */
+ rsp_code = OBX_RSP_PART_CONTENT;
+ }
+ else
+ rsp_code = OBX_RSP_INTRNL_SRVR_ERR;
+
+ /* Response goes out if complete or error occurred */
+ if (rsp_code != OBX_RSP_PART_CONTENT)
+ bta_mse_end_of_msg(inst_idx, sess_idx,rsp_code);
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_clean_msg_list
+**
+** Description Cleans up the get message list resources and control block
+**
+** Parameters inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_clean_msg_list(UINT8 inst_idx, UINT8 sess_idx)
+{
+ tBTA_MSE_MA_SESS_CB *p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, sess_idx);
+ tBTA_MSE_MSGLIST *p_ml = &p_cb->ml;
+ /* Clean up control block */
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("bta_mse_clean_msg_list");
+#endif
+ bta_mse_set_ma_oper(inst_idx, sess_idx, BTA_MSE_OPER_NONE);
+ p_ml->remaing_size =0;
+ p_ml->offset =0;
+ p_ml->pending_ml_frag = FALSE;
+
+ utl_freebuf((void**)&p_ml->p_entry);
+ utl_freebuf((void**)&p_ml->p_info);
+ utl_freebuf((void**)&p_ml->p_xml_buf);
+ utl_freebuf((void**)&p_cb->ml_param.p_name);
+ utl_freebuf((void**)&p_cb->ml_param.p_path);
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_end_of_msg_list
+**
+** Description Complete the end body of the get message listing response, and
+** sends out the OBX get response
+**
+** Parameters inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+** rsp_code - Obex response code
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_end_of_msg_list(UINT8 inst_idx, UINT8 sess_idx, UINT8 rsp_code)
+{
+ tBTA_MSE_MA_SESS_CB *p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, sess_idx);
+ tBTA_MSE_OBX_PKT *p_obx = &p_cb->obx;
+ tBTA_MSE_OPER_MLIST_PARAM *p_ml_param = &p_cb->ml_param;
+ UINT16 len;
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("bta_mse_end_of_msg_list");
+#endif
+ /* Add the end of folder listing string if successful operation */
+ if (rsp_code == OBX_RSP_OK || rsp_code == OBX_RSP_CONTINUE)
+ {
+ /* If listing has completed, check the max list count */
+ if (rsp_code == OBX_RSP_OK)
+ {
+ if (p_ml_param->filter.max_list_cnt)
+ {
+ len = strlen(BTA_MSE_MSG_LISTING_END);
+ memcpy(&p_obx->p_start[p_obx->offset], BTA_MSE_MSG_LISTING_END, len);
+ p_obx->offset += len;
+
+ OBX_AddBodyEnd(p_obx->p_pkt, p_obx->p_start, p_obx->offset, TRUE);
+ }
+
+ /* Clean up control block */
+ bta_mse_clean_msg_list(inst_idx, sess_idx);
+ }
+ else /* More listing data to be sent */
+ OBX_AddBodyEnd(p_obx->p_pkt, p_obx->p_start, p_obx->offset, FALSE);
+
+ OBX_GetRsp(p_cb->obx_handle, rsp_code, (BT_HDR *)p_obx->p_pkt);
+ p_obx->p_pkt = NULL; /* Do not deallocate buffer; OBX will */
+ }
+ else /* An error occurred */
+ {
+ OBX_GetRsp(p_cb->obx_handle, rsp_code, (BT_HDR *)NULL);
+ bta_mse_clean_msg_list(inst_idx, sess_idx);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_add_msg_list_info
+**
+** Description Adds applications paramter headers for new message and
+** message list size
+**
+** Parameters inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+**
+** Returns UINT8 - OBX response code
+** OBX_RSP_PART_CONTENT if not finished yet.
+**
+*******************************************************************************/
+UINT8 bta_mse_add_msg_list_info(UINT8 inst_idx, UINT8 sess_idx)
+{
+ tBTA_MSE_MA_SESS_CB *p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, sess_idx);
+ tBTA_MSE_OBX_PKT *p_obx = &p_cb->obx;
+ tBTA_MSE_MSGLIST *p_ml = &p_cb->ml;
+ tBTA_MSE_CO_MSG_LIST_INFO *p_info = p_ml->p_info;
+ tBTA_MSE_CO_MSG_LIST_ENTRY *p_entry = p_ml->p_entry;
+ tBTA_MA_MSG_LIST_FILTER_PARAM *p_filter = &p_cb->ml_param.filter;
+ UINT8 rsp_code = OBX_RSP_PART_CONTENT;
+ UINT8 *p, *p_start;
+ UINT16 len = 0;
+
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT2("bta_mse_add_msg_list_info: new msg=%d, list size=%d",
+ p_info->new_msg, p_info->msg_list_size );
+#endif
+
+ /* add app params for GetMessageListing */
+ p_start = OBX_AddByteStrStart(p_obx->p_pkt, &len);
+ p = p_start;
+
+ *p++ = BTA_MA_APH_NEW_MSG;
+ *p++ = 1;
+ UINT8_TO_BE_STREAM(p, p_info->new_msg);
+
+ *p++ = BTA_MA_APH_MSG_LST_SIZE;
+ *p++ = 2;
+ UINT16_TO_BE_STREAM(p, p_info->msg_list_size);
+
+ *p++ = BTA_MA_APH_MSE_TIME;
+ *p++ = p_info->mse_time_len;
+ memcpy(p, p_info->mse_time, p_info->mse_time_len);
+ p += p_info->mse_time_len;
+
+ if (p != p_start)
+ {
+ OBX_AddByteStrHdr(p_obx->p_pkt, OBX_HI_APP_PARMS, NULL, (UINT16)(p - p_start));
+ }
+
+ if (p_filter->max_list_cnt)
+ {
+ /* Add the start of the Body Header */
+ p_obx->offset = 0;
+ p_obx->bytes_left = 0;
+ p_obx->p_start = OBX_AddBodyStart(p_obx->p_pkt, &p_obx->bytes_left);
+
+ len = strlen(BTA_MSE_MSG_LISTING_START);
+ memcpy(&p_obx->p_start[p_obx->offset], BTA_MSE_MSG_LISTING_START, len);
+ p_obx->bytes_left -= (UINT16)(len + strlen(BTA_MSE_MSG_LISTING_END));
+ p_obx->offset += len;
+ p_cb->cout_active = TRUE;
+ bta_mse_co_get_msg_list_entry((tBTA_MA_SESS_HANDLE) p_cb->obx_handle,
+ p_cb->ml_param.p_name,
+ p_filter, TRUE,
+ p_entry,
+ BTA_MSE_CI_GET_ML_ENTRY_EVT,
+ bta_mse_cb.app_id);
+ }
+ else
+ {
+ /* done with get msg list request */
+ rsp_code = OBX_RSP_OK;
+ }
+ return(rsp_code);
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_add_msg_list_entry
+**
+** Description Adds one entry of the message list to the message list object
+**
+** Parameters inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+**
+** Returns UINT8 - OBX response code
+** OBX_RSP_PART_CONTENT if not finished yet.
+** OBX_RSP_CONTINUE [packet done]
+** Others send error response out
+**
+*******************************************************************************/
+UINT8 bta_mse_add_msg_list_entry(UINT8 inst_idx, UINT8 sess_idx)
+{
+ tBTA_MSE_MA_SESS_CB *p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, sess_idx);
+ tBTA_MSE_OBX_PKT *p_obx = &p_cb->obx;
+ tBTA_MSE_MSGLIST *p_ml = &p_cb->ml;
+ tBTA_MSE_CO_MSG_LIST_ENTRY *p_entry = p_ml->p_entry;
+ tBTA_MA_MSG_LIST_FILTER_PARAM *p_filter = &p_cb->ml_param.filter;
+ char *p_buf;
+ UINT16 size;
+ UINT8 rsp_code = OBX_RSP_PART_CONTENT;
+ tBTA_MA_STATUS status;
+ BOOLEAN release_xml_buf = TRUE;
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("bta_mse_add_msg_list_entry");
+#endif
+
+ if (p_ml->pending_ml_frag)
+ {
+ if (p_ml->remaing_size <= p_obx->bytes_left)
+ {
+ size = p_ml->remaing_size;
+ p_ml->pending_ml_frag = FALSE;
+ }
+ else
+ {
+ rsp_code = OBX_RSP_CONTINUE;
+ size = p_obx->bytes_left;
+ }
+
+ p_buf = p_ml->p_xml_buf + p_ml->offset;
+ memcpy (&p_obx->p_start[p_obx->offset], p_buf, size);
+ p_obx->offset += size;
+ p_obx->bytes_left -= size;
+ p_ml->remaing_size -= size;
+ p_ml->offset += size;
+
+ if ( !p_ml->pending_ml_frag )
+ {
+ utl_freebuf((void **) &p_ml->p_xml_buf);
+ }
+
+
+ if (rsp_code == OBX_RSP_PART_CONTENT)
+ {
+ /* Get the next msg list entry */
+ p_cb->cout_active = TRUE;
+ bta_mse_co_get_msg_list_entry((tBTA_MA_SESS_HANDLE) p_cb->obx_handle,
+ p_cb->ml_param.p_name,
+ p_filter, FALSE,
+ p_entry,
+ BTA_MSE_CI_GET_ML_ENTRY_EVT,
+ bta_mse_cb.app_id);
+ }
+ return rsp_code;
+ }
+
+ if ((p_buf = (char *)GKI_getbuf(GKI_MAX_BUF_SIZE)) != NULL)
+ {
+ p_buf[0] = '\0';
+ size = GKI_MAX_BUF_SIZE;
+ status = bta_mse_build_msg_listing_obj( p_entry, &size, p_buf );
+
+ if (status == BTA_MA_STATUS_OK)
+ {
+ size = strlen(p_buf);
+
+ if (size <= p_obx->bytes_left)
+ {
+ if ( size > 0)
+ {
+ memcpy (&p_obx->p_start[p_obx->offset], p_buf, size);
+ p_obx->offset += size;
+ p_obx->bytes_left -= size;
+ }
+
+ /* Get the next msg list entry */
+ p_cb->cout_active = TRUE;
+ bta_mse_co_get_msg_list_entry((tBTA_MA_SESS_HANDLE) p_cb->obx_handle,
+ p_cb->ml_param.p_name,
+ p_filter, FALSE,
+ p_entry,
+ BTA_MSE_CI_GET_ML_ENTRY_EVT,
+ bta_mse_cb.app_id);
+ }
+ else /* entry did not fit in current obx packet; try to add entry in next obx req */
+ {
+ p_ml->pending_ml_frag = TRUE;
+ p_ml->p_xml_buf= p_buf;
+ p_ml->offset =0;
+ p_ml->remaing_size = size - p_obx->bytes_left;
+ p_ml->offset += p_obx->bytes_left;
+ release_xml_buf = FALSE;
+ memcpy (&p_obx->p_start[p_obx->offset], p_buf, p_obx->bytes_left);
+ p_obx->offset += p_obx->bytes_left;
+ p_obx->bytes_left = 0;
+
+ APPL_TRACE_EVENT2("1st msg list fragment peer_mtu=%d msg_list_size=%d",
+ p_cb->peer_mtu, size);
+ APPL_TRACE_EVENT3("pending_flag=%d offset=%d remaining_size=%d",
+ p_ml->pending_ml_frag, p_ml->offset, p_ml->remaing_size);
+ APPL_TRACE_EVENT2("obx offset=%d byte_left=%d",
+ p_obx->offset, p_obx->bytes_left );
+
+ rsp_code = OBX_RSP_CONTINUE;
+
+ }
+ }
+ else
+ rsp_code = OBX_RSP_INTRNL_SRVR_ERR;
+ /* Done with temporary buffer */
+ if (release_xml_buf) utl_freebuf((void **) &p_buf);
+ }
+ else
+ rsp_code = OBX_RSP_INTRNL_SRVR_ERR;
+
+ return(rsp_code);
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_getmsglist
+**
+** Description Process the retrieval of a msg listing.
+**
+** Parameters inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+**
+** Returns None
+**
+*******************************************************************************/
+void bta_mse_getmsglist(UINT8 inst_idx, UINT8 sess_idx, BOOLEAN new_req)
+{
+ tBTA_MSE_MA_SESS_CB *p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, sess_idx);
+ tBTA_MSE_OBX_PKT *p_obx = &p_cb->obx;
+ tBTA_MSE_MSGLIST *p_ml = &p_cb->ml;
+ UINT8 rsp_code = OBX_RSP_OK;
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("bta_mse_getmsglist ");
+#endif
+
+ p_obx->p_pkt = (BT_HDR *)OBX_HdrInit(p_cb->obx_handle,
+ /* p_cb->peer_mtu */ OBX_LRG_DATA_POOL_SIZE);
+ if (!p_ml->p_entry)
+ {
+ /* Allocate enough space for the structure */
+ p_ml->p_entry = (tBTA_MSE_CO_MSG_LIST_ENTRY *)
+ GKI_getbuf((UINT16)(sizeof(tBTA_MSE_CO_MSG_LIST_ENTRY)));
+ }
+
+ if (p_ml->p_entry && p_obx->p_pkt)
+ {
+ /* Is this a new request or continuation? */
+ if (new_req)
+ {
+ if (!p_ml->p_info)
+ {
+ /* Allocate enough space for the structure */
+ p_ml->p_info = (tBTA_MSE_CO_MSG_LIST_INFO *)
+ GKI_getbuf((UINT16)(sizeof(tBTA_MSE_CO_MSG_LIST_INFO)));
+ }
+
+ if (p_ml->p_info)
+ {
+ p_cb->ml_param.w4info =TRUE;
+
+ p_cb->cout_active = TRUE;
+ bta_mse_co_get_msg_list_info((tBTA_MA_SESS_HANDLE) p_cb->obx_handle,
+ p_cb->ml_param.p_name,
+ &(p_cb->ml_param.filter),
+ p_ml->p_info,
+ BTA_MSE_CI_GET_ML_INFO_EVT,
+ bta_mse_cb.app_id);
+
+ /* List is not complete, so don't send the response yet */
+ rsp_code = OBX_RSP_PART_CONTENT;
+ }
+ else
+ rsp_code = OBX_RSP_INTRNL_SRVR_ERR;
+ }
+ else /* Add the entry previously retrieved */
+ {
+ /* Add the start of the Body Header */
+ p_obx->offset = 0;
+ p_obx->bytes_left = 0;
+ p_obx->p_start = OBX_AddBodyStart(p_obx->p_pkt, &p_obx->bytes_left);
+ rsp_code = bta_mse_add_msg_list_entry(inst_idx, sess_idx);
+ }
+ }
+ else
+ rsp_code = OBX_RSP_INTRNL_SRVR_ERR;
+
+ /* Response goes out if complete or error occurred */
+ if (rsp_code != OBX_RSP_PART_CONTENT)
+ bta_mse_end_of_msg_list(inst_idx, sess_idx,rsp_code);
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_read_app_params
+**
+** Description Read the specified application parameter from the given OBX packet
+**
+** Parameters p_pkt - obex packet pointer
+** tag - application parameter tag
+** param_len - (output) pointer to the length of application paramter
+**
+** Returns pointer to the application parameter found
+** NULL - not found
+**
+*******************************************************************************/
+
+UINT8 * bta_mse_read_app_params(BT_HDR *p_pkt, UINT8 tag, UINT16 *param_len)
+{
+ UINT8 *p_data = NULL, *p = NULL;
+ UINT16 data_len = 0;
+ int left, len;
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("bta_mse_read_app_params");
+#endif
+
+ if (OBX_ReadByteStrHdr(p_pkt, OBX_HI_APP_PARMS, &p_data, &data_len, 0))
+ {
+ left = data_len;
+ while (left > 0)
+ {
+ len = *(p_data + 1);
+ if (*p_data == tag)
+ {
+ p_data += 2;
+ p = p_data;
+ *param_len = (UINT16) len;
+ break;
+ }
+ p_data += (len+2);
+ left -= (len+2);
+ }
+ }
+ return p;
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_clean_list
+**
+** Description Cleans up the get folder list resources and control block
+**
+** Parameters inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_clean_list(UINT8 inst_idx, UINT8 sess_idx)
+{
+
+ tBTA_MSE_MA_SESS_CB *p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, sess_idx);
+ tBTA_MSE_DIRLIST *p_dir = &p_cb->dir;
+ /*tBTA_MSE_CO_FOLDER_ENTRY *p_entry = p_dir->p_entry; */
+ /* Clean up control block */
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("bta_mse_clean_list");
+#endif
+ bta_mse_set_ma_oper(inst_idx,sess_idx, BTA_MSE_OPER_NONE);
+ utl_freebuf((void**)&(p_dir->p_entry));
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_end_of_list
+**
+** Description Finishes up the end body of the get folder listing, and sends out the
+** OBX response
+**
+** Parameters inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+** rsp_code - obex response code
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_end_of_list(UINT8 inst_idx, UINT8 sess_idx, UINT8 rsp_code)
+{
+ tBTA_MSE_MA_SESS_CB *p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, sess_idx);
+ tBTA_MSE_OBX_PKT *p_obx = &p_cb->obx;
+ UINT16 len = 0;
+ UINT8 *p, *p_start;
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("bta_mse_end_of_list");
+#endif
+ /* Add the end of folder listing string if successful operation */
+ if (rsp_code == OBX_RSP_OK || rsp_code == OBX_RSP_CONTINUE)
+ {
+ /* If listing has completed, add on end string (http) */
+ if (rsp_code == OBX_RSP_OK)
+ {
+ if (p_cb->fl_param.max_list_cnt)
+ {
+ len = strlen(BTA_MSE_FOLDER_LISTING_END);
+ memcpy(&p_obx->p_start[p_obx->offset], BTA_MSE_FOLDER_LISTING_END, len);
+ p_obx->offset += len;
+ OBX_AddBodyEnd(p_obx->p_pkt, p_obx->p_start, p_obx->offset, TRUE);
+ }
+ else
+ {
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT1("list_cnt=%d",p_cb->fl_param.list_cnt);
+#endif
+
+ /* send the folder list size header only*/
+ p_start = OBX_AddByteStrStart(p_obx->p_pkt, &len);
+ p = p_start;
+
+ *p++ = BTA_MA_APH_FOLDER_LST_SIZE;
+ *p++ = 2;
+ UINT16_TO_BE_STREAM(p, p_cb->fl_param.list_cnt);
+ if (p != p_start)
+ {
+ OBX_AddByteStrHdr(p_obx->p_pkt, OBX_HI_APP_PARMS, NULL, (UINT16)(p - p_start));
+ }
+ }
+ /* Clean up control block */
+ bta_mse_clean_list(inst_idx, sess_idx);
+ }
+ else /* More listing data to be sent */
+ OBX_AddBodyEnd(p_obx->p_pkt, p_obx->p_start, p_obx->offset, FALSE);
+
+ OBX_GetRsp(p_cb->obx_handle, rsp_code, (BT_HDR *)p_obx->p_pkt);
+ p_obx->p_pkt = NULL; /* Do not deallocate buffer; OBX will */
+ }
+ else /* An error occurred */
+ {
+ OBX_GetRsp(p_cb->obx_handle, rsp_code, (BT_HDR *)NULL);
+ bta_mse_clean_list(inst_idx, sess_idx);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_add_list_entry
+**
+** Description Adds an subfolder entry to the folder list object
+**
+** Parameters inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+**
+** Returns UINT8 - OBX response code
+** OBX_RSP_PART_CONTENT if not finished yet.
+** OBX_RSP_CONTINUE [packet done]
+** Others send error response out
+**
+*******************************************************************************/
+UINT8 bta_mse_add_list_entry(UINT8 inst_idx, UINT8 sess_idx)
+{
+ tBTA_MSE_MA_SESS_CB *p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, sess_idx);
+ tBTA_MSE_OBX_PKT *p_obx = &p_cb->obx;
+ tBTA_MSE_DIRLIST *p_dir = &p_cb->dir;
+ tBTA_MSE_CO_FOLDER_ENTRY *p_entry = p_dir->p_entry;
+ char *p_buf;
+ UINT16 size;
+ UINT8 rsp_code = OBX_RSP_PART_CONTENT;
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("bta_mse_add_list_entry");
+#endif
+ if ((p_buf = (char *)GKI_getbuf(GKI_MAX_BUF_SIZE)) != NULL)
+ {
+ p_buf[0] = '\0';
+
+ APPL_TRACE_DEBUG2("bta_mse_add_list_entry: attr:0x%02x, name:%s",
+ p_entry->mode, p_entry->p_name);
+
+ if (p_entry->mode & BTA_MA_A_DIR) /* only process Subdirectory ignore files */
+ {
+ /* ignore "." and ".." */
+ if (strcmp(p_entry->p_name, ".") && strcmp(p_entry->p_name, ".."))
+ {
+ p_cb->fl_param.list_cnt++;
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT1("list_cnt=%d",p_cb->fl_param.list_cnt);
+#endif
+ if (p_cb->fl_param.max_list_cnt)
+ {
+ if (p_cb->fl_param.list_cnt <= p_cb->fl_param.max_list_cnt)
+ {
+ if (p_cb->fl_param.list_cnt > p_cb->fl_param.start_offset )
+ {
+ sprintf(p_buf, " <" BTA_MSE_FOLDER_ELEM " "
+ BTA_MSE_NAME_ATTR "=\"%s\"/>" BTA_MSE_XML_EOL,
+ p_entry->p_name);
+ }
+ }
+ } /* if max_list_cnt==0 only count the list size - but no body should be included*/
+ }
+ }/* ignore files i.e. non-folder items */
+
+ size = strlen(p_buf);
+ if (size <= p_obx->bytes_left)
+ {
+ if ( size > 0)
+ {
+ memcpy (&p_obx->p_start[p_obx->offset], p_buf, size);
+ p_obx->offset += size;
+ p_obx->bytes_left -= size;
+ }
+
+ if ((p_cb->fl_param.list_cnt < p_cb->fl_param.max_list_cnt) ||
+ (p_cb->fl_param.max_list_cnt == 0) )
+ {
+ /* Get the next directory entry */
+ p_cb->cout_active = TRUE;
+ bta_mse_co_get_folder_entry((tBTA_MA_SESS_HANDLE) p_cb->obx_handle,
+ p_cb->p_workdir, FALSE, p_dir->p_entry,
+ BTA_MSE_CI_GET_FENTRY_EVT,
+ bta_mse_cb.app_id);
+ }
+ else
+ {
+ /* reach the max allowed */
+ rsp_code = OBX_RSP_OK;
+ }
+ }
+ else /* entry did not fit in current obx packet; try to add entry in next obx req */
+ {
+ p_cb->fl_param.list_cnt--;
+ rsp_code = OBX_RSP_CONTINUE;
+ }
+
+ /* Done with temporary buffer */
+ GKI_freebuf(p_buf);
+ }
+ else
+ rsp_code = OBX_RSP_INTRNL_SRVR_ERR;
+ return(rsp_code);
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_getfolderlist
+**
+** Description Processes the retrieval of a folder listing.
+**
+** Parameters inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_getfolderlist(UINT8 inst_idx, UINT8 sess_idx, BOOLEAN new_req)
+{
+ tBTA_MSE_MA_CB *p_scb = BTA_MSE_GET_INST_CB_PTR(inst_idx);
+ tBTA_MSE_MA_SESS_CB *p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, sess_idx);
+ tBTA_MSE_OBX_PKT *p_obx = &p_cb->obx;
+ tBTA_MSE_DIRLIST *p_dir = &p_cb->dir;
+ UINT16 temp_len;
+ UINT8 rsp_code = OBX_RSP_OK;
+
+#if BTA_MSE_ENABLE_FS_CO == TRUE
+ BOOLEAN is_dir;
+#endif
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("bta_mse_getfolderlist");
+#endif
+
+#if BTA_MSE_ENABLE_FS_CO == TRUE
+ /* Make sure the Name is a directory and accessible */
+ if (((bta_fs_co_access(p_cb->p_workdir, BTA_FS_ACC_EXIST,
+ &is_dir, bta_mse_cb.app_id))!= BTA_FS_CO_OK)
+ || !is_dir)
+ rsp_code = OBX_RSP_NOT_FOUND;
+#endif
+ /* Build the listing */
+ if (rsp_code == OBX_RSP_OK)
+ {
+ p_obx->p_pkt = (BT_HDR *)OBX_HdrInit(p_cb->obx_handle,
+ /* p_cb->peer_mtu */ OBX_LRG_DATA_POOL_SIZE);
+ if (!(strcmp(p_cb->p_workdir, p_scb->p_rootpath)))
+ p_dir->is_root = TRUE;
+ else
+ p_dir->is_root = FALSE;
+
+ if (!p_dir->p_entry)
+ {
+ /* Allocate enough space for the structure and the folder name */
+ if ((p_dir->p_entry = (tBTA_MSE_CO_FOLDER_ENTRY *)
+ GKI_getbuf((UINT16)(sizeof(tBTA_MSE_CO_FOLDER_ENTRY) +
+ p_bta_mse_cfg->max_name_len + 1))) != NULL)
+ p_dir->p_entry->p_name = (char *)(p_dir->p_entry + 1);
+ }
+
+ if (p_dir->p_entry && p_obx->p_pkt)
+ {
+ if (p_cb->fl_param.max_list_cnt)
+ {
+ /* Add the start of the Body Header */
+ p_obx->offset = 0;
+ p_obx->bytes_left = 0;
+ p_obx->p_start = OBX_AddBodyStart(p_obx->p_pkt, &p_obx->bytes_left);
+ }
+
+ /* Is this a new request or continuation? */
+ if (new_req)
+ {
+ APPL_TRACE_EVENT1("Folder List Directory: [%s]", p_cb->p_workdir);
+ p_cb->fl_param.list_cnt =0;
+
+ /* add body header if max_list_cnt is not 0
+ if max_list_cnt =0 then only report the actual number
+ accessible folders. Use FolderListingSize header only
+ */
+
+ if (p_cb->fl_param.max_list_cnt)
+ {
+ temp_len = strlen(BTA_MSE_FOLDER_LISTING_START);
+
+ /* Add the beginning label of http */
+ memcpy(p_obx->p_start, BTA_MSE_FOLDER_LISTING_START, temp_len);
+ p_obx->bytes_left -= (UINT16)(temp_len + strlen(BTA_MSE_FOLDER_LISTING_END));
+ p_obx->offset += temp_len;
+
+ /* Add the parent directory if not the root */
+ if (strcmp(p_cb->p_workdir, p_scb->p_rootpath))
+ {
+ APPL_TRACE_EVENT0("Add parent folder");
+
+ temp_len = strlen(BTA_MSE_PARENT_FOLDER);
+ memcpy(p_obx->p_start + p_obx->offset,
+ BTA_MSE_PARENT_FOLDER, temp_len);
+ p_obx->bytes_left -= temp_len;
+ p_obx->offset += temp_len;
+ }
+ }
+ p_cb->cout_active = TRUE;
+ bta_mse_co_get_folder_entry((tBTA_MA_SESS_HANDLE) p_cb->obx_handle,
+ p_cb->p_workdir, TRUE, p_dir->p_entry,
+ BTA_MSE_CI_GET_FENTRY_EVT,
+ bta_mse_cb.app_id);
+
+ /* List is not complete, so don't send the response yet */
+ rsp_code = OBX_RSP_PART_CONTENT;
+ }
+ else /* Add the entry previously retrieved */
+ rsp_code = bta_mse_add_list_entry(inst_idx, sess_idx);
+ }
+ else
+ rsp_code = OBX_RSP_INTRNL_SRVR_ERR;
+ }
+
+ /* Response goes out if complete or error occurred */
+ if (rsp_code != OBX_RSP_PART_CONTENT)
+ bta_mse_end_of_list(inst_idx, sess_idx,rsp_code);
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_chdir
+**
+** Description Changes the current path based on received setpath paramters
+**
+** Parameters inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+** p_oper - (output) pointer to the MSE operation code
+**
+** Returns UINT8 - OBX response code
+** output *p_oper set to BTA_MSE_OPER_SETPATH if the
+** the resulting path is a valid path
+*******************************************************************************/
+UINT8 bta_mse_chdir(UINT8 inst_idx, UINT8 sess_idx, tBTA_MSE_OPER *p_oper)
+{
+ tBTA_MSE_MA_CB *p_scb = BTA_MSE_GET_INST_CB_PTR(inst_idx);
+ tBTA_MSE_MA_SESS_CB *p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, sess_idx);
+ char *p_path = p_cb->sp.p_path;
+ char *p_name = p_cb->sp.p_name;
+ char *p_tmp;
+
+ char *p_workdir = p_cb->p_workdir;
+ UINT8 rsp_code = OBX_RSP_OK;
+
+#if BTA_MSE_ENABLE_FS_CO == TRUE
+ BOOLEAN is_dir;
+#endif
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT2("bta_mse_chdir flag=%d name=%s",p_cb->sp.flags,p_cb->sp.p_name );
+#endif
+ *p_oper = BTA_MSE_OPER_NONE;
+ switch (p_cb->sp.flags)
+ {
+ case BTA_MA_DIR_NAV_ROOT_OR_DOWN_ONE_LVL:
+ p_path = p_cb->sp.p_path;
+ p_name = p_cb->sp.p_name;
+ rsp_code = OBX_RSP_OK;
+ if (*p_name == '\0')
+ {
+ /* backup to root */
+ if (strcmp(p_workdir, p_scb->p_rootpath))
+ {
+ BCM_STRNCPY_S(p_path, p_bta_fs_cfg->max_path_len+1, p_scb->p_rootpath, p_bta_fs_cfg->max_path_len);
+ /* go back up to the root folder*/
+ *p_oper = BTA_MSE_OPER_SETPATH;
+ }
+ }
+ /* Make sure the new path is not too big */
+ /* +1 is for the separator */
+ else if ((strlen(p_workdir)+1+strlen(p_name)) <= p_bta_fs_cfg->max_path_len)
+ {
+ /* create a temporary path for creation attempt */
+ sprintf(p_path, "%s%c%s", p_workdir,
+ p_bta_fs_cfg->path_separator, p_name);
+#if BTA_MSE_ENABLE_FS_CO == TRUE
+ if (((bta_fs_co_access(p_path, BTA_FS_ACC_EXIST,
+ &is_dir, bta_mse_cb.app_id)) == BTA_FS_CO_OK) && is_dir)
+ {
+ /* go back down one level to the name folder*/
+ *p_oper = BTA_MSE_OPER_SETPATH;
+ }
+ else
+ rsp_code = OBX_RSP_NOT_FOUND;
+#else
+ *p_oper = BTA_MSE_OPER_SETPATH;
+#endif
+ }
+ else
+ {
+ rsp_code = OBX_RSP_INTRNL_SRVR_ERR;
+ }
+ break;
+ case BTA_MA_DIR_NAV_UP_ONE_LVL:
+
+ if (strcmp(p_workdir, p_scb->p_rootpath))
+ {
+ /* Find the last occurrence of separator and replace with '\0' */
+ BCM_STRNCPY_S(p_path, p_bta_fs_cfg->max_path_len+1, p_workdir, p_bta_fs_cfg->max_path_len);
+ if ((p_tmp = strrchr(p_path, (int)p_bta_fs_cfg->path_separator)) != NULL)
+ {
+ *p_tmp = '\0';
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT1("path=[%s]",p_path );
+ APPL_TRACE_EVENT1("name=[%s]", p_name );
+#endif
+ /* now check we need to go down one level if name is not empty*/
+ if (*p_name !='\0')
+ {
+ if ((strlen(p_workdir)+1+strlen(p_name)) <= p_bta_fs_cfg->max_path_len)
+ {
+ sprintf(p_path, "%s%c%s", p_path,
+ p_bta_fs_cfg->path_separator, p_name);
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("Up one level and then down one" );
+ APPL_TRACE_EVENT1("path=[%s]",p_path );
+#endif
+#if BTA_MSE_ENABLE_FS_CO == TRUE
+ if (((bta_fs_co_access(p_path, BTA_FS_ACC_EXIST,
+ &is_dir, bta_mse_cb.app_id)) == BTA_FS_CO_OK) && is_dir)
+ {
+ /* go up one level and then go down one level to the name folder */
+ *p_oper = BTA_MSE_OPER_SETPATH;
+ }
+ else
+ {
+ rsp_code = OBX_RSP_NOT_FOUND;
+ }
+#else
+ *p_oper = BTA_MSE_OPER_SETPATH;
+#endif
+ }
+ else
+ {
+ rsp_code = OBX_RSP_INTRNL_SRVR_ERR;
+ }
+ }
+ else
+ {
+ /* just go up one level to the parent directory */
+ *p_oper = BTA_MSE_OPER_SETPATH;
+ }
+ }
+ else
+ {
+ rsp_code = OBX_RSP_INTRNL_SRVR_ERR;
+ }
+ }
+ else
+ {
+ rsp_code = OBX_RSP_NOT_FOUND;
+ }
+ break;
+ default:
+ rsp_code = OBX_RSP_INTRNL_SRVR_ERR;
+ break;
+ }
+
+ return(rsp_code);
+}
+
+
+/*******************************************************************************
+**
+** Function bta_mse_send_set_notif_reg
+**
+** Description Send a set notification registration event to application
+** so application can decide whether the request is allowed or not
+**
+** Parameters status - (output) pointer to the MSE operation code
+** inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+**
+** Returns TRUE - request is sent FALSE - requestr is not sent due to
+** error in the request
+*******************************************************************************/
+BOOLEAN bta_mse_send_set_notif_reg(UINT8 status,
+ UINT8 inst_idx, UINT8 sess_idx)
+{
+ tBTA_MSE_MA_SESS_CB *p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, sess_idx);
+ tBTA_MSE_MA_CB *p_scb = BTA_MSE_GET_INST_CB_PTR(inst_idx);
+ tBTA_MSE cback_evt_data;
+ tBTA_MA_NOTIF_STATUS notif_sts = BTA_MA_NOTIF_OFF;
+ BOOLEAN send_status = TRUE;
+ UINT8 ccb_idx;
+
+ if (status & BTA_MA_NOTIF_STS_ON) notif_sts = BTA_MA_NOTIF_ON;
+
+ if (notif_sts == BTA_MA_NOTIF_OFF)
+ {
+ if (!bta_mse_find_bd_addr_match_mn_cb_index(p_cb->bd_addr, &ccb_idx))
+ {
+ send_status = FALSE;
+ }
+ }
+
+ if (send_status)
+ {
+ cback_evt_data.set_notif_reg.mas_session_id = p_cb->obx_handle;
+ cback_evt_data.set_notif_reg.mas_instance_id = p_scb->mas_inst_id;
+ cback_evt_data.set_notif_reg.notif_status = notif_sts;
+ bdcpy(cback_evt_data.set_notif_reg.bd_addr, p_cb->bd_addr);
+ bta_mse_cb.p_cback(BTA_MSE_SET_NOTIF_REG_EVT, (tBTA_MSE *) &cback_evt_data);
+ }
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT1("bta_mse_send_set_notif_reg send_status=%d",send_status );
+#endif
+
+
+ return send_status;
+
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_proc_notif_reg_status
+**
+** Description Process the notification registration status to determine
+** whether a MN conenction should be opened or closed
+**
+** Parameters status - (output) pointer to the MSE operation code
+** inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+**
+** Returns None
+**
+*******************************************************************************/
+void bta_mse_proc_notif_reg_status(UINT8 status,
+ UINT8 inst_idx, UINT8 sess_idx )
+{
+ tBTA_MSE_MA_SESS_CB *p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, sess_idx);
+ tBTA_MSE_MA_CB *p_scb = BTA_MSE_GET_INST_CB_PTR(inst_idx);
+ tBTA_MA_NOTIF_STATUS notif_sts = BTA_MA_NOTIF_OFF;
+ tBTA_MSE_MN_CB *p_ccb;
+ UINT8 ccb_idx;
+ tBTA_MSE_MN_ACT_TYPE mn_act_type = BTA_MSE_MN_ACT_TYPE_NONE;
+ tOBX_RSP_CODE rsp_code = OBX_RSP_OK;
+
+ tBTA_MSE cback_evt_data;
+ tBTA_MSE_MN_INT_OPEN *p_open_evt;
+ tBTA_MSE_MN_INT_CLOSE *p_close_evt;
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("bta_mse_proc_notif_reg_status");
+#endif
+
+ if (status & BTA_MA_NOTIF_STS_ON) notif_sts = BTA_MA_NOTIF_ON;
+
+ switch (notif_sts)
+ {
+ case BTA_MA_NOTIF_ON:
+
+ if (!bta_mse_find_bd_addr_match_mn_cb_index(p_cb->bd_addr, &ccb_idx))
+ {
+ if (bta_mse_find_avail_mn_cb_idx(&ccb_idx))
+ mn_act_type = BTA_MSE_MN_ACT_TYPE_OPEN_CONN;
+ else
+ mn_act_type = BTA_MSE_MN_ACT_TYPE_OPEN_CONN_ERR;
+ }
+ else
+ {
+ /* it is connected already */
+ mn_act_type = BTA_MSE_MN_ACT_TYPE_OPEN_CONN_NONE;
+ }
+ break;
+
+ case BTA_MA_NOTIF_OFF:
+
+ if (!bta_mse_find_bd_addr_match_mn_cb_index(p_cb->bd_addr, &ccb_idx))
+ {
+ mn_act_type = BTA_MSE_MN_ACT_TYPE_CLOSE_CONN_ERR;
+ break;
+ }
+
+ p_ccb = BTA_MSE_GET_MN_CB_PTR(ccb_idx);
+
+ if ((p_ccb->state !=BTA_MSE_MN_W4_CONN_ST) &&
+ (p_ccb->state !=BTA_MSE_MN_CONN_ST))
+ {
+ /* MN is either idle or to be closed shortly so do nothing*/
+ mn_act_type = BTA_MSE_MN_ACT_TYPE_CLOSE_CONN_NONE;
+ }
+ else
+ {
+ if (bta_mse_mn_is_ok_to_close_mn(p_cb->bd_addr, p_scb->mas_inst_id))
+ {
+ /* This is the last active MN session using this conncection*/
+ mn_act_type = BTA_MSE_MN_ACT_TYPE_CLOSE_CONN;
+ }
+ else
+ {
+ mn_act_type = BTA_MSE_MN_ACT_TYPE_CLOSE_CONN_NONE;
+ }
+ }
+ break;
+ }
+
+ switch (mn_act_type)
+ {
+ case BTA_MSE_MN_ACT_TYPE_OPEN_CONN:
+
+ if ((p_open_evt = (tBTA_MSE_MN_INT_OPEN *) GKI_getbuf(sizeof(tBTA_MSE_MN_INT_OPEN))) != NULL)
+ {
+ bta_mse_mn_add_inst_id(ccb_idx, p_scb->mas_inst_id);
+ p_open_evt->hdr.event = BTA_MSE_MN_INT_OPEN_EVT;
+ p_open_evt->ccb_idx = ccb_idx;
+ p_open_evt->sec_mask = (BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
+ memcpy(p_open_evt->bd_addr, p_cb->bd_addr, sizeof(BD_ADDR));
+ bta_sys_sendmsg(p_open_evt);
+ }
+ else
+ {
+ rsp_code = OBX_RSP_FAILED;
+ }
+
+ break;
+
+ case BTA_MSE_MN_ACT_TYPE_CLOSE_CONN:
+
+ if ((p_close_evt = (tBTA_MSE_MN_INT_CLOSE *) GKI_getbuf(sizeof(tBTA_MSE_MN_INT_CLOSE))) != NULL)
+ {
+ bta_mse_mn_remove_inst_id(ccb_idx, p_scb->mas_inst_id);
+ p_close_evt->hdr.event = BTA_MSE_MN_INT_CLOSE_EVT;
+ p_close_evt->ccb_idx = ccb_idx;
+ bta_sys_sendmsg(p_close_evt);
+ }
+ else
+ {
+ rsp_code = OBX_RSP_FAILED;
+ }
+ break;
+
+ case BTA_MSE_MN_ACT_TYPE_OPEN_CONN_ERR:
+ rsp_code = OBX_RSP_FAILED;
+ break;
+
+ case BTA_MSE_MN_ACT_TYPE_OPEN_CONN_NONE:
+ bta_mse_mn_add_inst_id(ccb_idx, p_scb->mas_inst_id);
+ break;
+ case BTA_MSE_MN_ACT_TYPE_CLOSE_CONN_NONE:
+ bta_mse_mn_remove_inst_id(ccb_idx, p_scb->mas_inst_id);
+ break;
+ default:
+ break;
+ }
+
+ OBX_PutRsp(p_cb->obx_handle , rsp_code, NULL);
+ if (rsp_code == OBX_RSP_OK)
+ cback_evt_data.notif_reg.status = BTA_MA_STATUS_OK;
+ else
+ cback_evt_data.notif_reg.status = BTA_MA_STATUS_FAIL;
+ cback_evt_data.notif_reg.mas_session_id = p_cb->obx_handle;
+ cback_evt_data.notif_reg.mas_instance_id = p_scb->mas_inst_id;
+ cback_evt_data.notif_reg.notif_status = notif_sts;
+ bdcpy(cback_evt_data.notif_reg.bd_addr, p_cb->bd_addr);
+ bta_mse_clean_set_notif_reg(inst_idx,sess_idx);
+
+ bta_mse_cb.p_cback(BTA_MSE_NOTIF_REG_EVT, (tBTA_MSE *) &cback_evt_data);
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_discard_data
+**
+** Description frees the data
+**
+** Parameters event - MSE event
+** p_data - Pointer to the MSE event data
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_discard_data(UINT16 event, tBTA_MSE_DATA *p_data)
+{
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("bta_mse_discard_data");
+#endif
+
+ switch (event)
+ {
+ case BTA_MSE_MA_OBX_CONN_EVT:
+ case BTA_MSE_MA_OBX_DISC_EVT:
+ case BTA_MSE_MA_OBX_ABORT_EVT:
+ case BTA_MSE_MA_OBX_CLOSE_EVT:
+ case BTA_MSE_MA_OBX_PUT_EVT:
+ case BTA_MSE_MA_OBX_GET_EVT:
+ case BTA_MSE_MA_OBX_SETPATH_EVT:
+ utl_freebuf((void**)&p_data->obx_evt.p_pkt);
+ break;
+
+ default:
+ /*Nothing to free*/
+ break;
+ }
+}
+
+
+
+/*******************************************************************************
+**
+** Function bta_mse_find_mas_inst_id_match_cb_idx
+**
+** Description Finds the MAS instance control block index based on the specified
+** MAS instance ID
+**
+** Parameters mas_inst_id - MAS instance ID
+** p_idx - (output) pointer to the MA control block index
+**
+** Returns BOOLEAN - TRUE found
+** FALSE not found
+*******************************************************************************/
+BOOLEAN bta_mse_find_mas_inst_id_match_cb_idx(tBTA_MA_INST_ID mas_inst_id, UINT8 *p_idx)
+{
+ BOOLEAN found=FALSE;
+ UINT8 i;
+
+ for (i=0; i < BTA_MSE_NUM_INST ; i ++)
+ {
+ if (bta_mse_cb.scb[i].in_use)
+ {
+ if (bta_mse_cb.scb[i].mas_inst_id == mas_inst_id)
+ {
+ found = TRUE;
+ *p_idx = i;
+ break;
+ }
+ }
+ }
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT3("bta_mse_find_mas_inst_id_match_cb_idx found=%d, inst_id=%d inst_idx=%d",
+ found, mas_inst_id, i);
+#endif
+ return found;
+}
+
+
+/*******************************************************************************
+**
+** Function bta_mse_find_bd_addr_match_sess_cb_idx
+**
+** Description Finds the Session control block index based on the specified
+** MAS instance control block index and BD address
+**
+** Parameters bd_addr - BD address
+** inst_idx - MA control block index
+** p_idx - (output) pointer to the MA server control block
+** index
+**
+**
+** Returns BOOLEAN - TRUE found
+** FALSE not found
+*******************************************************************************/
+BOOLEAN bta_mse_find_bd_addr_match_sess_cb_idx(BD_ADDR bd_addr, UINT8 inst_idx,
+ UINT8 *p_idx)
+{
+ tBTA_MSE_MA_SESS_CB *p_cb;
+ BOOLEAN found=FALSE;
+ UINT8 i;
+
+ for (i=0; i < BTA_MSE_NUM_SESS ; i ++)
+ {
+ p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, i);
+ if ((p_cb->state == BTA_MSE_MA_CONN_ST) &&
+ !memcmp (p_cb->bd_addr, bd_addr, BD_ADDR_LEN))
+ {
+ found = TRUE;
+ *p_idx = i;
+ break;
+ }
+ }
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT3("bta_mse_find_bd_addr_match_sess_cb_idx found=%d, inst_idx=%d p_idx=%d",
+ found, inst_idx, i);
+#endif
+ return found;
+}
+
+
+/*******************************************************************************
+**
+** Function bta_mse_find_handle_match_mas_inst_cb_idx
+**
+** Description Finds the MAS instance control block index based on the specified Obx handle
+**
+** Parameters obx_handle - Obex session handle
+** p_idx - (output) pointer to the MA server control block index
+**
+**
+** Returns BOOLEAN - TRUE found
+** FALSE not found
+**
+*******************************************************************************/
+BOOLEAN bta_mse_find_handle_match_mas_inst_cb_idx(tOBX_HANDLE obx_handle, UINT8 *p_idx)
+{
+ BOOLEAN found=FALSE;
+ UINT8 i;
+
+ for (i=0; i < BTA_MSE_NUM_INST ; i ++)
+ {
+ if (bta_mse_cb.scb[i].in_use)
+ {
+ if (bta_mse_cb.scb[i].obx_handle == obx_handle)
+ {
+ found = TRUE;
+ *p_idx = i;
+ break;
+ }
+ }
+ }
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT2("bta_mse_find_handle_match_mas_inst_cb_idx found=%d idx=%d",found, i);
+#endif
+ return found;
+}
+/*******************************************************************************
+**
+** Function bta_mse_find_mas_sess_cb_idx
+**
+** Description Finds the MAS instance and session control block indexes
+** based on Obx handle
+**
+** Parameters obx_handle - Obex session handle
+** p_mas_inst_idx - (output) pointer to the MA server control
+** block index
+** p_mas_sess_idx - (output) pointer to the MA session control
+** block index
+**
+** Returns BOOLEAN - TRUE found
+** FALSE not found
+**
+*******************************************************************************/
+BOOLEAN bta_mse_find_mas_sess_cb_idx(tOBX_HANDLE obx_handle,
+ UINT8 *p_mas_inst_idx, UINT8 *p_mas_sess_idx)
+{
+ BOOLEAN found=FALSE;
+ UINT8 i, j;
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("bta_mse_find_mas_sess_cb_idx");
+#endif
+ for (i=0; i< BTA_MSE_NUM_INST; i++)
+ {
+ if (bta_mse_cb.scb[i].in_use)
+ {
+ for (j=0; j < BTA_MSE_NUM_SESS; j++ )
+ {
+ if ( (bta_mse_cb.scb[i].sess_cb[j].state != BTA_MSE_MA_LISTEN_ST) &&
+ (bta_mse_cb.scb[i].sess_cb[j].obx_handle == obx_handle) )
+ {
+ found = TRUE;
+ *p_mas_inst_idx = i;
+ *p_mas_sess_idx = j;
+ return found;
+ }
+ }
+ }
+ }
+
+ return found;
+}
+
+
+/*******************************************************************************
+**
+** Function bta_mse_find_ma_cb_indexes
+**
+** Description Finds the MAS instance and session control block indexes
+** based on the received internal event
+**
+** Parameters p_msg - Pointer to MSE msg data
+** p_mas_inst_idx - (output) pointer to the MA server control
+** block index
+** p_mas_sess_idx - (output) pointer to the MA session control
+** block index
+**
+** Returns BOOLEAN - TRUE found
+** FALSE not found
+**
+*******************************************************************************/
+BOOLEAN bta_mse_find_ma_cb_indexes(tBTA_MSE_DATA *p_msg,
+ UINT8 *p_inst_idx, UINT8 *p_sess_idx)
+{
+ BOOLEAN found = FALSE;
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("bta_mse_find_ma_cb_indexes");
+#endif
+ switch (p_msg->hdr.event)
+ {
+ case BTA_MSE_MA_OBX_CONN_EVT:
+
+ if (bta_mse_find_handle_match_mas_inst_cb_idx( p_msg->obx_evt.param.conn.handle, p_inst_idx))
+ {
+ if (bta_mse_find_avail_mas_sess_cb_idx(&(bta_mse_cb.scb[*p_inst_idx]), p_sess_idx))
+ found = TRUE;
+ }
+ break;
+
+ case BTA_MSE_API_ACCESSRSP_EVT:
+
+ if (bta_mse_find_sess_id_match_ma_cb_indexes(p_msg->api_access_rsp.mas_session_id,
+ p_inst_idx,p_sess_idx))
+ found = TRUE;
+
+ break;
+
+ case BTA_MSE_API_UPD_IBX_RSP_EVT:
+
+ if (bta_mse_find_sess_id_match_ma_cb_indexes(p_msg->api_upd_ibx_rsp.mas_session_id,
+ p_inst_idx,p_sess_idx))
+ found = TRUE;
+
+ break;
+
+ case BTA_MSE_API_SET_NOTIF_REG_RSP_EVT:
+
+ if (bta_mse_find_sess_id_match_ma_cb_indexes(p_msg->api_set_notif_reg_rsp.mas_session_id,
+ p_inst_idx,p_sess_idx))
+ found = TRUE;
+
+ break;
+
+ case BTA_MSE_INT_CLOSE_EVT:
+
+ if (bta_mse_find_sess_id_match_ma_cb_indexes(p_msg->int_close.mas_session_id,
+ p_inst_idx,p_sess_idx))
+ found = TRUE;
+
+ break;
+
+ case BTA_MSE_CI_GET_FENTRY_EVT:
+
+ if (bta_mse_find_sess_id_match_ma_cb_indexes(p_msg->ci_get_fentry.mas_session_id,
+ p_inst_idx,p_sess_idx))
+ found = TRUE;
+
+ break;
+ case BTA_MSE_CI_GET_ML_INFO_EVT:
+
+ if (bta_mse_find_sess_id_match_ma_cb_indexes(p_msg->ci_get_ml_info.mas_session_id,
+ p_inst_idx,p_sess_idx))
+ found = TRUE;
+
+ break;
+ case BTA_MSE_CI_GET_ML_ENTRY_EVT:
+
+ if (bta_mse_find_sess_id_match_ma_cb_indexes(p_msg->ci_get_ml_entry.mas_session_id,
+ p_inst_idx,p_sess_idx))
+ found = TRUE;
+
+ break;
+ case BTA_MSE_CI_GET_MSG_EVT:
+
+ if (bta_mse_find_sess_id_match_ma_cb_indexes(p_msg->ci_get_msg.mas_session_id,
+ p_inst_idx,p_sess_idx))
+ found = TRUE;
+
+ break;
+
+ case BTA_MSE_CI_PUSH_MSG_EVT:
+
+ if (bta_mse_find_sess_id_match_ma_cb_indexes(p_msg->ci_push_msg.mas_session_id,
+ p_inst_idx,p_sess_idx))
+ found = TRUE;
+
+ break;
+
+ case BTA_MSE_CI_DEL_MSG_EVT:
+
+ if (bta_mse_find_sess_id_match_ma_cb_indexes(p_msg->ci_del_msg.mas_session_id,
+ p_inst_idx,p_sess_idx))
+ found = TRUE;
+
+ break;
+
+ case BTA_MSE_MA_OBX_DISC_EVT:
+ case BTA_MSE_MA_OBX_ABORT_EVT:
+ case BTA_MSE_MA_OBX_CLOSE_EVT:
+ case BTA_MSE_MA_OBX_PUT_EVT:
+ case BTA_MSE_MA_OBX_GET_EVT:
+ case BTA_MSE_MA_OBX_SETPATH_EVT:
+
+ if (bta_mse_find_mas_sess_cb_idx( p_msg->obx_evt.handle, p_inst_idx, p_sess_idx))
+ found = TRUE;
+ break;
+ default:
+ break;
+
+ }
+
+ return found;
+}
+
+
+/*******************************************************************************
+**
+** Function bta_mse_ma_cleanup
+**
+** Description Free resources if unable to find MA control block indexes
+**
+** Parameters p_msg - Pointer to MSE msg data
+**
+** Returns none
+**
+*******************************************************************************/
+void bta_mse_ma_cleanup(tBTA_MSE_DATA *p_msg)
+{
+ tBTA_MSE_OBX_EVT *p_evt = &p_msg->obx_evt;
+ tBTA_MA_OBX_RSP *p_rsp = NULL;
+ UINT8 rsp_code = OBX_RSP_BAD_REQUEST;
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("bta_mse_ma_cleanup");
+#endif
+ switch (p_msg->hdr.event)
+ {
+ case BTA_MSE_MA_OBX_CONN_EVT:
+ p_rsp = OBX_ConnectRsp;
+ rsp_code = OBX_RSP_SERVICE_UNAVL;
+ break;
+ case BTA_MSE_MA_OBX_DISC_EVT:
+ p_rsp = OBX_DisconnectRsp;
+ break;
+ case BTA_MSE_MA_OBX_ABORT_EVT:
+ p_rsp = OBX_AbortRsp;
+ break;
+ case BTA_MSE_MA_OBX_PUT_EVT:
+ p_rsp = OBX_PutRsp;
+ break;
+ case BTA_MSE_MA_OBX_GET_EVT:
+ p_rsp = OBX_GetRsp;
+ break;
+ case BTA_MSE_MA_OBX_SETPATH_EVT:
+ p_rsp = OBX_SetPathRsp;
+ break;
+ default:
+ break;
+ }
+
+ if (p_rsp)
+ {
+ (*p_rsp)(p_evt->handle, rsp_code, (BT_HDR *)NULL);
+ /* Done with Obex packet */
+ utl_freebuf((void**)&p_evt->p_pkt);
+ }
+}
+
+
+
+/*******************************************************************************
+**
+** Function bta_mse_is_a_duplicate_id
+**
+** Description Determine the MAS instance ID has been used or not by other MAS instance
+**
+** Parameters mas_inst_id - MAS instance ID
+**
+** Returns BOOLEAN - TRUE the MAS isntance is a duplicate ID
+** FALSE not a duplicate ID
+*******************************************************************************/
+BOOLEAN bta_mse_is_a_duplicate_id(tBTA_MA_INST_ID mas_inst_id)
+{
+ BOOLEAN is_duplicate=FALSE;
+ UINT8 i;
+
+ for (i=0; i < BTA_MSE_NUM_INST ; i ++)
+ {
+ if (bta_mse_cb.scb[i].in_use &&
+ (bta_mse_cb.scb[i].mas_inst_id == mas_inst_id))
+ {
+ is_duplicate = TRUE;
+
+ break;
+ }
+ }
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT2("bta_mse_is_a_duplicate_id inst_id=%d status=%d",
+ mas_inst_id, is_duplicate);
+#endif
+
+ return is_duplicate;
+}
+
+
+/*******************************************************************************
+**
+** Function bta_mse_find_avail_mas_inst_cb_idx
+**
+** Description Finds a not in used MAS instance control block index
+**
+** Parameters p_idx - (output) pointer to the MA server control
+** block index
+**
+** Returns BOOLEAN - TRUE found
+** FALSE not found
+**
+*******************************************************************************/
+BOOLEAN bta_mse_find_avail_mas_inst_cb_idx(UINT8 *p_idx)
+{
+ BOOLEAN found=FALSE;
+ UINT8 i;
+
+
+ for (i=0; i < BTA_MSE_NUM_INST ; i ++)
+ {
+ if (!bta_mse_cb.scb[i].in_use)
+ {
+ found = TRUE;
+ *p_idx = i;
+ break;
+ }
+ }
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT2("bta_mse_find_avail_mas_inst_cb_idx found=%d inst_idx=%d",
+ found, i);
+#endif
+ return found;
+}
+/*******************************************************************************
+**
+** Function bta_mse_find_avail_mas_sess_cb_idx
+**
+** Description Finds a not in used MAS session control block index
+**
+** Parameters p_scb - Pointer to the MA control block
+** p_idx - (output) pointer to the MA session control
+** block index
+**
+** Returns BOOLEAN - TRUE found
+** FALSE not found
+*******************************************************************************/
+BOOLEAN bta_mse_find_avail_mas_sess_cb_idx(tBTA_MSE_MA_CB *p_scb, UINT8 *p_idx)
+{
+ BOOLEAN found=FALSE;
+ UINT8 i;
+
+ for (i=0; i < BTA_MSE_NUM_SESS ; i ++)
+ {
+ if (p_scb->sess_cb[i].state == BTA_MSE_MA_LISTEN_ST)
+ {
+ if ((p_scb->sess_cb[i].p_workdir = (char *)GKI_getbuf((UINT16)(p_bta_fs_cfg->max_path_len + 1))) != NULL)
+ {
+ found = TRUE;
+ *p_idx = i;
+ }
+ break;
+ }
+ }
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT2("bta_mse_find_avail_mas_sess_cb_idx found=%d idx=%d", found, i);
+#endif
+ return found;
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_find_avail_mn_cb_idx
+**
+** Description Finds a not in use MN control block index
+**
+** Parameters p_idx - (output) pointer to the MN control block index
+**
+** Returns BOOLEAN - TRUE found
+** FALSE not found
+**
+*******************************************************************************/
+BOOLEAN bta_mse_find_avail_mn_cb_idx(UINT8 *p_idx)
+{
+ BOOLEAN found=FALSE;
+ UINT8 i;
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("bta_mse_find_avail_mn_cb_idx");
+#endif
+ for (i=0; i < BTA_MSE_NUM_MN ; i ++)
+ {
+ if (!bta_mse_cb.ccb[i].in_use)
+ {
+ found = TRUE;
+ *p_idx = i;
+ break;
+ }
+ }
+ return found;
+}
+
+
+
+/*******************************************************************************
+**
+** Function bta_mse_find_bd_addr_match_mn_cb_index
+**
+** Description Find the MN control block index based on the specified BD address
+**
+** Parameters p_bd_addr - Pointer to the BD address
+** p_idx - (output) pointer to the MN control block index
+**
+** Returns BOOLEAN - TRUE found
+** FALSE not found
+**
+*******************************************************************************/
+
+BOOLEAN bta_mse_find_bd_addr_match_mn_cb_index(BD_ADDR p_bd_addr, UINT8 *p_idx)
+{
+ BOOLEAN found=FALSE;
+ UINT8 i;
+
+ for (i=0; i < BTA_MSE_NUM_MN ; i ++)
+ {
+ if ((bta_mse_cb.ccb[i].in_use) &&
+ (!memcmp (bta_mse_cb.ccb[i].bd_addr, p_bd_addr, BD_ADDR_LEN)))
+ {
+ found = TRUE;
+ *p_idx = i;
+ break;
+ }
+ }
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT2("bta_mse_find_bd_addr_match_mn_cb_index found=%d index=%d", found, i);
+#endif
+ return found;
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_find_bd_addr_match_mn_cb_index
+**
+** Description Find the MN control block index based on the specified obx handle
+**
+** Parameters obx_hdl - Obex session handle
+** p_idx - (output) pointer to the MN control block index
+**
+** Returns BOOLEAN - TRUE found
+** FALSE not found
+**
+*******************************************************************************/
+
+BOOLEAN bta_mse_find_obx_hdl_match_mn_cb_index(tOBX_HANDLE obx_hdl, UINT8 *p_idx)
+{
+ BOOLEAN found=FALSE;
+ UINT8 i;
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("bta_mse_find_obx_hdl_match_mn_cb_index");
+#endif
+ for (i=0; i < BTA_MSE_NUM_INST ; i ++)
+ {
+ if ((bta_mse_cb.ccb[i].in_use) &&
+ (bta_mse_cb.ccb[i].obx_handle == obx_hdl))
+ {
+ found = TRUE;
+ *p_idx = i;
+ break;
+ }
+ }
+
+ return found;
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_find_sess_id_match_ma_cb_indexes
+**
+** Description Finds the MAS instance and session control block indexes
+** based on the specified MAS session ID
+**
+** Parameters mas_session_id - MAS instance ID
+** p_inst_idx - (output) pointer to the MA server control
+** block index
+** p_sess_idx - (output) pointer to the MA session control
+** block index
+**
+** Returns BOOLEAN - TRUE found
+** FALSE not found
+**
+*******************************************************************************/
+BOOLEAN bta_mse_find_sess_id_match_ma_cb_indexes(tBTA_MA_SESS_HANDLE mas_session_id,
+ UINT8 *p_inst_idx, UINT8 *p_sess_idx)
+{
+ BOOLEAN found=FALSE;
+ UINT8 i,j;
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("bta_mse_find_sess_id_match_ma_cb_indexes");
+#endif
+ for (i=0; i < BTA_MSE_NUM_INST ; i ++)
+ {
+ for (j=0; j<BTA_MSE_NUM_SESS; j++ )
+ {
+ if ((bta_mse_cb.scb[i].in_use) &&
+ (bta_mse_cb.scb[i].sess_cb[j].obx_handle == (tOBX_HANDLE) mas_session_id ))
+ {
+ found = TRUE;
+ *p_inst_idx = i;
+ *p_sess_idx = j;
+ return found;
+ }
+ }
+ }
+
+ return found;
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_find_sess_id_match_mn_cb_index
+**
+** Description Finds the MN control block index
+** based on the specified MAS session ID
+**
+** Parameters mas_session_id - MAS instance ID
+** p_idx - (output) pointer to the MN control
+** block index
+**
+** Returns BOOLEAN - TRUE found
+** FALSE not found
+**
+*******************************************************************************/
+BOOLEAN bta_mse_find_sess_id_match_mn_cb_index(tBTA_MA_SESS_HANDLE mas_session_id,
+ UINT8 *p_idx)
+{
+ BOOLEAN found=FALSE;
+
+ UINT8 i,j;
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("bta_mse_find_sess_id_match_mn_cb_index");
+#endif
+ for (i=0; i < BTA_MSE_NUM_INST ; i ++)
+ {
+ for (j=0; j<BTA_MSE_NUM_SESS; j++ )
+ {
+ if ((bta_mse_cb.scb[i].in_use) &&
+ (bta_mse_cb.scb[i].sess_cb[j].obx_handle == (tOBX_HANDLE) mas_session_id ))
+ {
+ found = TRUE;
+ break;
+ }
+ }
+ if (found) break;
+ }
+
+ /* found session index now need to match BD address*/
+ if (found)
+ {
+ found = FALSE;
+ if ( bta_mse_find_bd_addr_match_mn_cb_index(bta_mse_cb.scb[i].sess_cb[j].bd_addr, p_idx))
+ {
+ found = TRUE;
+ }
+ }
+ return found;
+}
+
+
+/*******************************************************************************
+**
+** Function bta_mse_find_mn_cb_index
+**
+** Description Finds the MN control block index
+** based on the specified event
+**
+** Parameters p_msg - Pointer to MSE msg data
+** p_ccb_idx - (output) pointer to the MN control block index
+**
+** Returns BOOLEAN - TRUE found
+** FALSE not found
+**
+*******************************************************************************/
+BOOLEAN bta_mse_find_mn_cb_index(tBTA_MSE_DATA *p_msg, UINT8 *p_ccb_idx)
+{
+ BOOLEAN found = TRUE;
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("bta_mse_find_mn_cb_index");
+#endif
+ switch (p_msg->hdr.event)
+ {
+ case BTA_MSE_MN_INT_OPEN_EVT:
+ *p_ccb_idx= p_msg->mn_int_open.ccb_idx;
+ break;
+
+ case BTA_MSE_MN_INT_CLOSE_EVT:
+ *p_ccb_idx= p_msg->mn_int_close.ccb_idx;
+ break;
+
+ case BTA_MSE_MN_OBX_CONN_RSP_EVT:
+
+ if (!bta_mse_find_bd_addr_match_mn_cb_index(
+ p_msg->obx_evt.param.conn.peer_addr,
+ p_ccb_idx))
+ {
+ found = FALSE;
+ }
+ break;
+
+ case BTA_MSE_MN_OBX_TOUT_EVT:
+ case BTA_MSE_MN_OBX_CLOSE_EVT:
+ case BTA_MSE_MN_OBX_PUT_RSP_EVT:
+ if (!bta_mse_find_obx_hdl_match_mn_cb_index(
+ p_msg->obx_evt.handle,
+ p_ccb_idx))
+ {
+ found = FALSE;
+ }
+
+ break;
+
+ case BTA_MSE_MN_SDP_OK_EVT:
+
+ *p_ccb_idx = p_msg->mn_sdp_ok.ccb_idx;
+ break;
+
+ case BTA_MSE_MN_SDP_FAIL_EVT:
+
+ *p_ccb_idx = p_msg->mn_sdp_fail.ccb_idx;
+ break;
+
+ default:
+ found = FALSE;
+ break;
+ }
+
+ return found;
+}
+
+
+/*******************************************************************************
+**
+** Function bta_mse_mn_cleanup
+**
+** Description Free resources if unable to find MN control block index
+**
+** Parameters p_msg - Pointer to MSE msg data
+**
+** Returns none
+**
+*******************************************************************************/
+void bta_mse_mn_cleanup(tBTA_MSE_DATA *p_msg)
+{
+ tBTA_MSE_OBX_EVT *p_evt = &p_msg->obx_evt;
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("bta_mse_mn_cleanup");
+#endif
+ switch (p_msg->hdr.event)
+ {
+ case BTA_MSE_MN_OBX_CONN_RSP_EVT:
+ case BTA_MSE_MN_OBX_PUT_RSP_EVT:
+ /* Done with Obex packet */
+ utl_freebuf((void**)&p_evt->p_pkt);
+ break;
+
+ default:
+ break;
+ }
+}
+/*******************************************************************************
+**
+** Function bta_mse_build_map_event_rpt_obj
+**
+** Description Create a MAP-Event-Report object in the
+** specified buffer.
+**
+** Parameters notif_type - Notification type
+** handle (input only) - handle of the message that the "type"
+** indication refers to. Ignored when the event "type" is
+** "MemoryFull" or "MemoryAvailable".
+** p_folder - name of the folder in which the corresponding
+** message has been filed by the MSE. NULL when the event
+** "type" is "MemoryFull" or "MemoryAvailable".
+** p_old_folder - Used only in case of a message shift to
+** indicate the folder on the MSE from which the message
+** has been shifted out.
+** msg_typ - Gives the type of the message. Ignored when the
+** event "type" is "MemoryFull" or "MemoryAvailable".
+** p_len - Pointer to value containing the size of
+** the buffer (p_buffer). Receives the output size of
+** filled XML object.
+** p_buffer - Pointer to buffer to receive the XML object.
+**
+** Returns BTA_MA_STATUS_FAIL if buffer was not large enough, otherwise
+** returns BTA_MA_STATUS_OK.
+**
+*******************************************************************************/
+tBTA_MA_STATUS bta_mse_build_map_event_rpt_obj(tBTA_MSE_NOTIF_TYPE notif_type,
+ tBTA_MA_MSG_HANDLE handle,
+ char * p_folder,
+ char * p_old_folder,
+ tBTA_MA_MSG_TYPE msg_typ,
+ UINT16 * p_len,
+ UINT8 * p_buffer)
+{
+ tBTA_MA_STREAM strm;
+
+ memset(p_buffer, 0, *p_len);
+ BTA_MaInitMemStream(&strm, p_buffer, *p_len);
+
+ /* stream event attribute and event type */
+ bta_ma_stream_str(&strm, "<MAP-event-report version=\"1.0\">\n"
+ "<event type = \"");
+ bta_ma_stream_str(&strm, bta_ma_evt_typ_to_string(notif_type));
+
+ /* Some things are not used for "MemoryFull" and "MemoryAvailable" */
+ if ( (BTA_MSE_NOTIF_TYPE_MEMORY_FULL != notif_type)
+ && (BTA_MSE_NOTIF_TYPE_MEMORY_AVAILABLE != notif_type) )
+ {
+ /* stream handle label and value */
+ bta_ma_stream_str(&strm, "\" handle = \"");
+ bta_ma_stream_handle(&strm, handle);
+
+ if (p_folder && (*p_folder !='\0'))
+ {
+ /* stream folder */
+ bta_ma_stream_str(&strm, "\" folder = \"");
+ bta_ma_stream_str(&strm, p_folder);
+ }
+
+ /* stream old_folder if it is a "MessageShift" */
+ if ( (BTA_MSE_NOTIF_TYPE_MESSAGE_SHIFT == notif_type) &&
+ p_old_folder && (*p_old_folder !='\0'))
+ {
+ /* stream folder */
+ bta_ma_stream_str(&strm, "\" old_folder = \"");
+ bta_ma_stream_str(&strm, p_old_folder);
+ }
+
+ /* stream message type */
+ bta_ma_stream_str(&strm, "\" msg_type = \"");
+ bta_ma_stream_str(&strm, bta_ma_msg_typ_to_string(msg_typ));
+ }
+
+ /* we are done with this evnet */
+ bta_ma_stream_str(&strm, "\" />\n</MAP-event-report>");
+
+ /* set the output length (i.e. amount of buffer that got used) */
+ *p_len = bta_ma_stream_used_size(&strm);
+
+ /* return status based on the stream status */
+ return(bta_ma_stream_ok(&strm)
+ ? BTA_MA_STATUS_OK
+ : BTA_MA_STATUS_FAIL);
+}
+
+
+/*******************************************************************************
+**
+** Function bta_mse_build_msg_listing_obj
+**
+** Description Build the message listing object in the specified buffer
+**
+** Parameters p_entry - Pointer to the message listing entry
+** p_size - input: pointer to the available buffer size
+** output: pointer to the filled buffer size
+** p_buf - pointer to the buffer for building the msg listing
+** object
+**
+** Returns status - BTA_MA_STATUS_OK - build the object successfully
+** BTA_MA_STATUS_FAIL - failed to build the object
+**
+*******************************************************************************/
+tBTA_MA_STATUS bta_mse_build_msg_listing_obj(tBTA_MSE_CO_MSG_LIST_ENTRY *p_entry,
+ UINT16 *p_size, char *p_buf )
+{
+ tBTA_MA_STREAM strm;
+
+ memset(p_buf, 0, *p_size);
+ BTA_MaInitMemStream(&strm, (UINT8 *)p_buf, *p_size);
+
+ /* stream msg element */
+ bta_ma_stream_str(&strm, "<msg ");
+ /* stream msg attributes */
+ bta_ma_stream_str(&strm, "handle = \"");
+ bta_ma_stream_handle(&strm, p_entry->msg_handle);
+
+ if (p_entry->parameter_mask &BTA_MA_ML_MASK_SUBJECT)
+ {
+ bta_ma_stream_str(&strm, "\" subject = \"");
+ bta_ma_stream_str(&strm, p_entry->subject);
+ }
+
+ if (p_entry->parameter_mask & BTA_MA_ML_MASK_DATETIME)
+ {
+ bta_ma_stream_str(&strm, "\" datetime = \"");
+ bta_ma_stream_str(&strm, p_entry->date_time);
+ }
+
+ if (p_entry->parameter_mask & BTA_MA_ML_MASK_SENDER_NAME)
+ {
+ bta_ma_stream_str(&strm, "\" sender_name = \"");
+ bta_ma_stream_str(&strm, p_entry->sender_name);
+ }
+
+
+ if (p_entry->parameter_mask & BTA_MA_ML_MASK_SENDER_ADDRESSING)
+ {
+ bta_ma_stream_str(&strm, "\" sender_addressing = \"");
+ bta_ma_stream_str(&strm, p_entry->sender_addressing);
+ }
+
+ if (p_entry->parameter_mask & BTA_MA_ML_MASK_REPLYTO_ADDRESSING)
+ {
+ bta_ma_stream_str(&strm, "\" replyto_addressing = \"");
+ bta_ma_stream_str(&strm, p_entry->replyto_addressing);
+ }
+
+ if (p_entry->parameter_mask & BTA_MA_ML_MASK_RECIPIENT_NAME)
+ {
+ bta_ma_stream_str(&strm, "\" recipient_name = \"");
+ bta_ma_stream_str(&strm, p_entry->recipient_name);
+ }
+
+ if (p_entry->parameter_mask & BTA_MA_ML_MASK_RECIPIENT_ADDRESSING)
+ {
+ bta_ma_stream_str(&strm, "\" recipient_addressing = \"");
+ bta_ma_stream_str(&strm, p_entry->recipient_addressing);
+ }
+
+ if (p_entry->parameter_mask & BTA_MA_ML_MASK_TYPE)
+ {
+ bta_ma_stream_str(&strm, "\" type = \"");
+ if (!bta_ma_stream_str(&strm, bta_ma_msg_typ_to_string(p_entry->type)))
+ {
+ return BTA_MA_STATUS_FAIL;
+ }
+ }
+
+ if (p_entry->parameter_mask & BTA_MA_ML_MASK_SIZE)
+ {
+ bta_ma_stream_str(&strm, "\" size = \"");
+ bta_ma_stream_value(&strm, p_entry->org_msg_size);
+ }
+
+ if (p_entry->parameter_mask & BTA_MA_ML_MASK_TEXT)
+ {
+ bta_ma_stream_str(&strm, "\" text = \"");
+ bta_ma_stream_boolean_yes_no(&strm, p_entry->text);
+ }
+
+ if (p_entry->parameter_mask & BTA_MA_ML_MASK_RECEPTION_STATUS)
+ {
+ bta_ma_stream_str(&strm, "\" reception_status = \"");
+ if (!bta_ma_stream_str(&strm,
+ bta_ma_rcv_status_to_string(p_entry->reception_status)))
+ {
+ return BTA_MA_STATUS_FAIL;
+ }
+ }
+
+ if (p_entry->parameter_mask & BTA_MA_ML_MASK_ATTACHMENT_SIZE)
+ {
+ bta_ma_stream_str(&strm, "\" attachment_size = \"");
+ bta_ma_stream_value(&strm, p_entry->attachment_size);
+ }
+
+ if (p_entry->parameter_mask & BTA_MA_ML_MASK_PRIORITY)
+ {
+ bta_ma_stream_str(&strm, "\" priority = \"");
+ bta_ma_stream_boolean_yes_no(&strm, p_entry->high_priority);
+ }
+ if (p_entry->parameter_mask & BTA_MA_ML_MASK_READ)
+ {
+ bta_ma_stream_str(&strm, "\" read = \"");
+ bta_ma_stream_boolean_yes_no(&strm, p_entry->read);
+ }
+ if (p_entry->parameter_mask & BTA_MA_ML_MASK_SENT)
+ {
+ bta_ma_stream_str(&strm, "\" sent = \"");
+ bta_ma_stream_boolean_yes_no(&strm, p_entry->sent);
+ }
+ if (p_entry->parameter_mask & BTA_MA_ML_MASK_PROTECTED)
+ {
+ bta_ma_stream_str(&strm, "\" protected = \"");
+ bta_ma_stream_boolean_yes_no(&strm, p_entry->is_protected);
+ }
+
+ /* stream msg element end tag*/
+ bta_ma_stream_str(&strm, "\"/> ");
+
+ /* set the output length (i.e. amount of buffer that got used) */
+ *p_size = bta_ma_stream_used_size(&strm);
+
+ /* return status based on the stream status */
+ return(bta_ma_stream_ok(&strm)
+ ? BTA_MA_STATUS_OK
+ : BTA_MA_STATUS_FAIL);
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_mn_start_timer
+**
+** Description Start a wait for obx response timer
+**
+** Parameters ccb_inx - MN control block index
+** timer_id - indicating this timer is for which operation
+**
+** Returns None
+**
+*******************************************************************************/
+void bta_mse_mn_start_timer(UINT8 ccb_idx, UINT8 timer_id)
+{
+ tBTA_MSE_MN_CB *p_cb = BTA_MSE_GET_MN_CB_PTR(ccb_idx);
+ UINT16 event_id;
+ p_cb->rsp_timer.param = (UINT32) (ccb_idx+1);
+ event_id = (UINT16) BTA_MSE_MN_RSP0_TOUT_EVT + ccb_idx;
+ bta_sys_start_timer(&p_cb->rsp_timer, event_id,
+ p_bta_mse_cfg->obx_rsp_tout);
+
+ p_cb->timer_oper = timer_id;
+}
+/*******************************************************************************
+**
+** Function bta_mse_mn_start_stop_timer
+**
+** Description Stop a wait for obx response timer
+**
+** Parameters ccb_inx - MN control block index
+** timer_id - indicating this timer is for which operation
+**
+** Returns None
+**
+*******************************************************************************/
+void bta_mse_mn_stop_timer(UINT8 ccb_idx, UINT8 timer_id)
+{
+ tBTA_MSE_MN_CB *p_cb = BTA_MSE_GET_MN_CB_PTR(ccb_idx);
+
+ if ((p_cb->timer_oper == timer_id) || (timer_id == BTA_MSE_TIMER_OP_ALL))
+ {
+ p_cb->rsp_timer.param = 0;
+ bta_sys_stop_timer(&p_cb->rsp_timer );
+ p_cb->timer_oper = BTA_MSE_TIMER_OP_NONE;
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_mn_add_inst_id
+**
+** Description Add mas_inst_id to the MN notif_reg data base
+**
+** Parameters ccb_inx - MN control block index
+** mas_inst_id - MAS instance ID
+**
+** Returns BOOLEAN - TRUE OK
+** FALSE not OK
+**
+*******************************************************************************/
+BOOLEAN bta_mse_mn_add_inst_id(UINT8 ccb_idx, tBTA_MA_INST_ID mas_inst_id)
+{
+ BOOLEAN found=FALSE;
+ BOOLEAN add_status=FALSE;
+ UINT8 i;
+ tBTA_MSE_MN_CB *p_ccb = BTA_MSE_GET_MN_CB_PTR(ccb_idx);
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT2("bta_mse_mn_add_inst_id ccb_idx=%d mas_inst_id=%d",
+ ccb_idx, mas_inst_id);
+#endif
+ for (i=0; i < BTA_MSE_NUM_INST ; i ++)
+ {
+ if (p_ccb->notif_reg[i].status &&
+ (p_ccb->notif_reg[i].mas_inst_id == mas_inst_id))
+ {
+ found = TRUE;
+ add_status = TRUE;
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ for (i=0; i < BTA_MSE_NUM_INST ; i ++)
+ {
+ if (!p_ccb->notif_reg[i].status)
+ {
+ /* find an available entry to add */
+ p_ccb->notif_reg[i].mas_inst_id = mas_inst_id;
+ p_ccb->notif_reg[i].status = TRUE;
+ add_status = TRUE;
+ break;
+ }
+ }
+ }
+
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT1("add_status=%d", add_status);
+#endif
+
+ return add_status;
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_mn_remove_inst_id
+**
+** Description Remove mas_inst_id from the MN notif_reg data base
+**
+** Parameters ccb_inx - MN control block index
+** mas_inst_id - MAS instance ID
+**
+** Returns BOOLEAN - TRUE OK
+** FALSE not OK
+**
+*******************************************************************************/
+BOOLEAN bta_mse_mn_remove_inst_id(UINT8 ccb_idx, tBTA_MA_INST_ID mas_inst_id)
+{
+ BOOLEAN remove_status=FALSE;
+ UINT8 i;
+ tBTA_MSE_MN_CB *p_ccb = BTA_MSE_GET_MN_CB_PTR(ccb_idx);
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT2("bta_mse_mn_remove_inst_id ccb_idx=%d mas_inst_id=%d",
+ ccb_idx, mas_inst_id);
+#endif
+ for (i=0; i < BTA_MSE_NUM_INST ; i ++)
+ {
+ if (p_ccb->notif_reg[i].status &&
+ (p_ccb->notif_reg[i].mas_inst_id == mas_inst_id))
+ {
+ p_ccb->notif_reg[i].status = FALSE;
+ p_ccb->notif_reg[i].mas_inst_id =(tBTA_MA_INST_ID )0;
+
+ remove_status = TRUE;
+ break;
+ }
+ }
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT1("remove_status=%d", remove_status);
+#endif
+
+ return remove_status;
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_mn_remove_all_inst_ids
+**
+** Description Remove all mas_inst_ids from the MN notif_reg data base
+**
+** Parameters ccb_inx - MN control block index
+**
+** Returns None
+**
+*******************************************************************************/
+void bta_mse_mn_remove_all_inst_ids(UINT8 ccb_idx)
+{
+ UINT8 i;
+ tBTA_MSE_MN_CB *p_ccb = BTA_MSE_GET_MN_CB_PTR(ccb_idx);
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT1("bta_mse_mn_remove_all_inst_ids ccb_idx=%d ",
+ ccb_idx);
+#endif
+ for (i=0; i < BTA_MSE_NUM_INST ; i ++)
+ {
+ if (p_ccb->notif_reg[i].status)
+ {
+ p_ccb->notif_reg[i].status = FALSE;
+ p_ccb->notif_reg[i].mas_inst_id =(tBTA_MA_INST_ID) 0;
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_mn_find_num_of_act_inst_id
+**
+** Description fin the number of Mas Instance IDs with registration status on
+**
+** Parameters ccb_inx - MN control block index
+**
+** Returns UINT8 - Number of active Mas Instance ID
+**
+*******************************************************************************/
+UINT8 bta_mse_mn_find_num_of_act_inst_id(UINT8 ccb_idx)
+{
+ UINT8 i,cnt;
+ tBTA_MSE_MN_CB *p_ccb = BTA_MSE_GET_MN_CB_PTR(ccb_idx);;
+
+ cnt =0;
+ for (i=0; i < BTA_MSE_NUM_INST ; i ++)
+ {
+ if (p_ccb->notif_reg[i].status) cnt++;
+ }
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT2("bta_mse_mn_find_num_of_act_inst_id ccb_idx=%d cnt=%d",
+ ccb_idx, cnt);
+#endif
+
+ return cnt;
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_mn_is_inst_id_exist
+**
+** Description Check whether the specified mas_inst_id is in the
+** MN notif_reg data base
+**
+** Parameters ccb_inx - MN control block index
+** mas_inst_id - MAS instance ID
+**
+** Returns BOOLEAN - TRUE found
+** FALSE not found
+**
+**
+*******************************************************************************/
+BOOLEAN bta_mse_mn_is_inst_id_exist(UINT8 ccb_idx, tBTA_MA_INST_ID mas_inst_id )
+{
+ BOOLEAN found = FALSE;
+ UINT8 i;
+ tBTA_MSE_MN_CB *p_ccb = BTA_MSE_GET_MN_CB_PTR(ccb_idx);;
+
+ for (i=0; i < BTA_MSE_NUM_INST ; i ++)
+ {
+ if (p_ccb->notif_reg[i].status &&
+ (p_ccb->notif_reg[i].mas_inst_id == mas_inst_id))
+ {
+ found = TRUE;
+ break;
+ }
+ }
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT3("bta_mse_mn_is_inst_id_exist ccb_idx=%d mas_inst_id=%d found=%d",
+ ccb_idx, mas_inst_id, found);
+#endif
+
+ return found;
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_mn_is_ok_to_close_mn
+**
+** Description Determine is ok to close MN connection
+**
+** Parameters bd_addr - BD address
+** mas_inst_id - MAS instance ID
+**
+** Returns BOOLEAN - TRUE OK
+** FALSE not OK
+**
+*******************************************************************************/
+BOOLEAN bta_mse_mn_is_ok_to_close_mn(BD_ADDR bd_addr, tBTA_MA_INST_ID mas_inst_id )
+{
+ UINT8 ccb_idx;
+ BOOLEAN ok_status= FALSE;
+
+
+ if (bta_mse_find_bd_addr_match_mn_cb_index(bd_addr, &ccb_idx) &&
+ (bta_mse_mn_find_num_of_act_inst_id(ccb_idx) == 1) &&
+ (bta_mse_mn_is_inst_id_exist(ccb_idx, mas_inst_id)))
+ {
+ ok_status = TRUE;
+ }
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT2("bta_mse_mn_is_ok_to_close_mn mas_inst_id=%d ok_status=%d",
+ mas_inst_id, ok_status);
+#endif
+
+ return ok_status;
+}
+
+
+/*******************************************************************************
+**
+** Function bta_mse_mn_get_first_inst_id
+**
+** Description Get the first active mas_inst_id from the MN notif_reg data base
+**
+** Parameters ccb_inx - MN control block index
+** mas_inst_id - MAS instance ID
+**
+** Returns BOOLEAN - TRUE OK
+** FALSE not OK
+**
+*******************************************************************************/
+BOOLEAN bta_mse_mn_get_first_inst_id(UINT8 ccb_idx, tBTA_MA_INST_ID *p_mas_inst_id)
+{
+ BOOLEAN found=FALSE;
+ UINT8 i;
+ tBTA_MSE_MN_CB *p_ccb = BTA_MSE_GET_MN_CB_PTR(ccb_idx);
+
+
+ for (i=0; i < BTA_MSE_NUM_INST ; i ++)
+ {
+ if (p_ccb->notif_reg[i].status )
+ {
+ *p_mas_inst_id = p_ccb->notif_reg[i].mas_inst_id;
+
+ found = TRUE;
+ break;
+ }
+ }
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT3("bta_mse_mn_get_inst_id ccb_idx=%d found status =%d mas_inst_id=%d",
+ ccb_idx, found, *p_mas_inst_id);
+#endif
+
+ return found;
+}
+
+
+/*******************************************************************************
+**
+** Function bta_mse_mn_send_abort_req
+**
+** Description Send an abort request.
+**
+** Parameters ccb_inx - MN control block index
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_mn_send_abort_req(UINT8 ccb_idx)
+{
+ tBTA_MSE_MN_CB *p_cb = BTA_MSE_GET_MN_CB_PTR(ccb_idx);
+
+ if (BTA_MSE_MN_ABORT_REQ_NOT_SENT == p_cb->aborting)
+ {
+ bta_mse_mn_start_timer(ccb_idx, BTA_MSE_TIMER_OP_ABORT);
+ OBX_AbortReq(p_cb->obx_handle, (BT_HDR *)NULL);
+ p_cb->aborting = BTA_MSE_MN_ABORT_REQ_SENT;
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_mn_cont_send_notif
+**
+** Description Continues the send notification operation. Builds a new OBX packet
+**
+** Parameters ccb_idx - MN control block index
+** first_pkt - first obex packet indicator
+**
+** Returns tBTA_MA_STATUS : BTA_MA_STATUS_OK if msg notification sent is ok
+** otherwise BTA_MA_STATUS_FAIL
+*******************************************************************************/
+tBTA_MA_STATUS bta_mse_mn_cont_send_notif(UINT8 ccb_idx, BOOLEAN first_pkt)
+{
+ tBTA_MSE_MN_CB *p_cb = BTA_MSE_GET_MN_CB_PTR(ccb_idx);
+ tBTA_MSE_OBX_PKT *p_obx = &p_cb->obx;
+ tBTA_MSE_MN_MSG_NOTIF *p_msg_notif = &p_cb->msg_notif;
+ tOBX_TRIPLET app_param[1];
+ UINT16 body_len;
+ BOOLEAN final_pkt = FALSE;
+ tBTA_MA_STATUS status = BTA_MA_STATUS_OK;
+
+ /* Do not start another request if currently aborting */
+ if (p_cb->aborting)
+ {
+ bta_mse_mn_send_abort_req(ccb_idx);
+ return status;
+ }
+
+ if ((p_obx->p_pkt = OBX_HdrInit(p_cb->obx_handle, p_cb->peer_mtu)) != NULL)
+ {
+ if (first_pkt)
+ {
+ OBX_AddTypeHdr(p_obx->p_pkt, BTA_MA_HDR_TYPE_EVENT_RPT);
+
+ app_param[0].tag = BTA_MA_NAS_INST_ID_TAG_ID;
+ app_param[0].len = BTA_MA_NAS_INST_ID_LEN;
+ app_param[0].p_array = &(p_msg_notif->mas_instance_id);
+ OBX_AddAppParamHdr(p_obx->p_pkt, app_param, 1);
+ }
+ else
+ {
+ p_obx->offset =
+ p_obx->bytes_left = 0; /* 0 -length available */
+ p_obx->p_start = OBX_AddBodyStart(p_obx->p_pkt, &p_obx->bytes_left);
+
+ body_len = p_obx->bytes_left;
+ final_pkt = ( (p_msg_notif->buffer_len - p_msg_notif->bytes_sent) < body_len) ?
+ TRUE : FALSE ;
+ if (final_pkt) body_len = (p_msg_notif->buffer_len - p_msg_notif->bytes_sent);
+
+ memcpy(&p_obx->p_start[p_obx->offset],
+ &(p_msg_notif->p_buffer[p_msg_notif->bytes_sent]), body_len);
+ p_msg_notif->bytes_sent += body_len;
+ p_obx->offset += body_len;
+ OBX_AddBodyEnd(p_obx->p_pkt, p_obx->p_start, p_obx->offset, TRUE);
+ }
+
+ OBX_PutReq(p_cb->obx_handle, final_pkt , p_obx->p_pkt);
+ p_obx->p_pkt = NULL;
+ p_cb->req_pending = TRUE;
+ bta_mse_set_mn_oper(ccb_idx, BTA_MSE_MN_OP_PUT_EVT_RPT);
+ p_msg_notif->final_pkt = final_pkt;
+ p_msg_notif->pkt_cnt++;
+ }
+ else
+ {
+ status = BTA_MA_STATUS_FAIL;
+ }
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT4("bta_mse_mn_cont_send_notif ccb_idx=%d first_pkt=%d send_status=%d final=%d",
+ ccb_idx, first_pkt, status, final_pkt);
+#endif
+
+ return status;
+}
+/*******************************************************************************
+**
+** Function bta_mse_mn_send_notif_evt
+**
+** Description Issue a send notification event
+**
+** Parameters mas_instance_id - MAS instance ID
+** status - MS sttaus
+** bd_addr - BD address
+**
+**
+** Returns UINT8 OBX response code
+**
+*******************************************************************************/
+void bta_mse_mn_send_notif_evt(tBTA_MA_INST_ID mas_instance_id, tBTA_MA_STATUS status,
+ BD_ADDR bd_addr )
+{
+ tBTA_MSE param;
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT2("bta_mse_mn_send_notif_evt mas_instance_id=%d status=%d",
+ mas_instance_id,
+ status);
+#endif
+
+ param.send_notif.mas_instance_id = mas_instance_id;
+ param.send_notif.status = status;
+ bdcpy(param.send_notif.bd_addr, bd_addr);
+ bta_mse_cb.p_cback(BTA_MSE_SEND_NOTIF_EVT, &param);
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_mn_clean_send_notif
+**
+** Description Clean up send notif resources and cotrol block
+**
+** Parameters ccb_idx - MN control block index
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_mn_clean_send_notif(UINT8 ccb_idx)
+{
+ tBTA_MSE_MN_CB *p_cb = BTA_MSE_GET_MN_CB_PTR(ccb_idx);
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("bta_mse_mn_clean_send_notif");
+#endif
+
+ utl_freebuf((void**)&(p_cb->msg_notif.p_buffer));
+ bta_mse_set_mn_oper(ccb_idx, BTA_MSE_MN_OP_NONE);
+ p_cb->req_pending = FALSE;
+ p_cb->aborting = BTA_MSE_MN_ABORT_NONE;
+ memset(&(p_cb->msg_notif), 0, sizeof(tBTA_MSE_MN_MSG_NOTIF));
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_ma_fl_read_app_params
+**
+** Description Read application parameters for the get folder list requst
+**
+** Parameters inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+** p_pkt - Pointer to the obex packet
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_mse_ma_fl_read_app_params(UINT8 inst_idx, UINT8 sess_idx, BT_HDR *p_pkt)
+
+{
+ tBTA_MSE_MA_SESS_CB *p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, sess_idx);
+ UINT8 *p_param;
+ UINT16 len;
+
+ p_param = bta_mse_read_app_params(p_pkt, BTA_MA_APH_MAX_LIST_COUNT, &len);
+
+ if (p_param)
+ {
+ BE_STREAM_TO_UINT16(p_cb->fl_param.max_list_cnt, p_param);
+ }
+ else
+ p_cb->fl_param.max_list_cnt = BTA_MA_DEFAULT_MAX_LIST_CNT;
+
+ p_param = bta_mse_read_app_params(p_pkt, BTA_MA_APH_START_STOFF, &len);
+
+ if (p_param)
+ {
+ BE_STREAM_TO_UINT16(p_cb->fl_param.start_offset, p_param);
+ }
+ else
+ p_cb->fl_param.start_offset = 0;
+
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_ma_ml_read_app_params
+**
+** Description Read application parameters for the get message list requst
+**
+** Parameters inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+** p_pkt - Pointer to the obex packet
+**
+** Returns void
+**
+*******************************************************************************/
+
+void bta_mse_ma_ml_read_app_params(UINT8 inst_idx, UINT8 sess_idx, BT_HDR *p_pkt)
+
+{
+ tBTA_MSE_MA_SESS_CB *p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, sess_idx);
+ UINT8 *p_param;
+ UINT16 len;
+
+ memset(&(p_cb->ml_param.filter), 0x00, sizeof(tBTA_MA_MSG_LIST_FILTER_PARAM));
+
+ p_param = bta_mse_read_app_params(p_pkt, BTA_MA_APH_MAX_LIST_COUNT, &len);
+ if (p_param)
+ {
+ BE_STREAM_TO_UINT16(p_cb->ml_param.filter.max_list_cnt, p_param);
+ }
+ else
+ {
+ p_cb->ml_param.filter.max_list_cnt = BTA_MA_DEFAULT_MAX_LIST_CNT;
+ }
+
+ p_param = bta_mse_read_app_params(p_pkt, BTA_MA_APH_START_STOFF, &len);
+ if (p_param)
+ {
+ BE_STREAM_TO_UINT16(p_cb->ml_param.filter.list_start_offset, p_param);
+ }
+ else
+ {
+ p_cb->ml_param.filter.list_start_offset = 0;
+ }
+
+ p_param = bta_mse_read_app_params(p_pkt, BTA_MA_APH_SUBJ_LEN, &len);
+ if (p_param)
+ {
+ BE_STREAM_TO_UINT8(p_cb->ml_param.filter.subject_length, p_param);
+ }
+ else
+ {
+ p_cb->ml_param.filter.subject_length = 0xff;
+ }
+
+ p_param = bta_mse_read_app_params(p_pkt, BTA_MA_APH_PARAM_MASK, &len);
+ if (p_param)
+ {
+ BE_STREAM_TO_UINT32(p_cb->ml_param.filter.parameter_mask, p_param);
+ }
+ else
+ {
+ p_cb->ml_param.filter.parameter_mask = 0;
+ }
+
+ p_param = bta_mse_read_app_params(p_pkt, BTA_MA_APH_FILTER_MSG_TYPE, &len);
+ if (p_param)
+ {
+ BE_STREAM_TO_UINT8(p_cb->ml_param.filter.msg_mask, p_param);
+ }
+ else
+ {
+ p_cb->ml_param.filter.msg_mask = 0;
+ }
+
+ p_param = bta_mse_read_app_params(p_pkt, BTA_MA_APH_FILTER_PRD_BEGIN, &len);
+
+ if (p_param)
+ {
+ p_cb->ml_param.filter.period_begin[BTA_MA_LTIME_LEN]='\0';
+ if (len < BTA_MA_LTIME_LEN)
+ {
+ p_cb->ml_param.filter.period_begin[0] = '\0';
+ }
+ else
+ {
+ BCM_STRNCPY_S((char *)p_cb->ml_param.filter.period_begin, sizeof(p_cb->ml_param.filter.period_begin),
+ (const char *)p_param, BTA_MA_LTIME_LEN);
+ }
+ }
+ else
+ {
+ p_cb->ml_param.filter.period_begin[0] = '\0';
+ }
+
+ p_param = bta_mse_read_app_params(p_pkt, BTA_MA_APH_FILTER_PRD_END, &len);
+ if (p_param)
+ {
+ p_cb->ml_param.filter.period_end[BTA_MA_LTIME_LEN] = '\0';
+ if (len < BTA_MA_LTIME_LEN)
+ {
+ p_cb->ml_param.filter.period_end[0] = '\0';
+ }
+ else
+ {
+ BCM_STRNCPY_S((char *)p_cb->ml_param.filter.period_end, sizeof(p_cb->ml_param.filter.period_end),
+ (const char *)p_param, BTA_MA_LTIME_LEN);
+ }
+ }
+ else
+ {
+ p_cb->ml_param.filter.period_end[0] = '\0';
+ }
+
+ p_param = bta_mse_read_app_params(p_pkt, BTA_MA_APH_FILTER_READ_STS, &len);
+ if (p_param)
+ {
+ BE_STREAM_TO_UINT8(p_cb->ml_param.filter.read_status, p_param);
+ }
+ else
+ {
+ p_cb->ml_param.filter.read_status = 0;
+ }
+
+ p_param = bta_mse_read_app_params(p_pkt, BTA_MA_APH_FILTER_RECEIP, &len);
+ p_cb->ml_param.filter.recipient[0] = '\0';
+ if (p_param && len)
+ {
+ if (len >= BTA_MA_MAX_FILTER_TEXT_SIZE)
+ {
+ p_cb->ml_param.filter.recipient[BTA_MA_MAX_FILTER_TEXT_SIZE] = '\0';
+ len = BTA_MA_MAX_FILTER_TEXT_SIZE;
+ }
+ BCM_STRNCPY_S((char *)p_cb->ml_param.filter.recipient, sizeof(p_cb->ml_param.filter.recipient),
+ (const char *)p_param, len);
+ }
+
+ p_param = bta_mse_read_app_params(p_pkt, BTA_MA_APH_FILTER_ORIGIN, &len);
+ p_cb->ml_param.filter.originator[0] = '\0';
+ if (p_param && len)
+ {
+ if (len >= BTA_MA_MAX_FILTER_TEXT_SIZE)
+ {
+ p_cb->ml_param.filter.originator[BTA_MA_MAX_FILTER_TEXT_SIZE] = '\0';
+ len = BTA_MA_MAX_FILTER_TEXT_SIZE;
+ }
+ BCM_STRNCPY_S((char *)p_cb->ml_param.filter.originator, sizeof(p_cb->ml_param.filter.originator),
+ (const char *)p_param, len);
+ }
+
+ p_param = bta_mse_read_app_params(p_pkt, BTA_MA_APH_FILTER_PRIORITY, &len);
+ if (p_param)
+ {
+ BE_STREAM_TO_UINT8(p_cb->ml_param.filter.pri_status, p_param);
+ }
+ else
+ {
+ p_cb->ml_param.filter.pri_status = 0;
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_ma_msg_read_app_params
+**
+** Description Read application parameters for the get message list requst
+**
+** Parameters inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+** p_pkt - Pointer to the obex packet
+**
+** Returns BOOLEAN TRUE - operation is successful
+**
+*******************************************************************************/
+
+BOOLEAN bta_mse_ma_msg_read_app_params(UINT8 inst_idx, UINT8 sess_idx, BT_HDR *p_pkt)
+
+{
+ tBTA_MSE_MA_SESS_CB *p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, sess_idx);
+ UINT8 *p_param;
+ UINT16 len;
+
+ p_param = bta_mse_read_app_params(p_pkt, BTA_MA_APH_CHARSET, &len);
+ if (p_param)
+ {
+ BE_STREAM_TO_UINT8(p_cb->msg_param.data.charset, p_param);
+ }
+ else
+ {
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT0("Unable to decode or find charset in application parameter ");
+#endif
+ return FALSE;
+ }
+
+ p_param = bta_mse_read_app_params(p_pkt, BTA_MA_APH_ATTACH, &len);
+ if (p_param)
+ {
+ BE_STREAM_TO_UINT8(p_cb->msg_param.data.attachment, p_param);
+ }
+ else
+ {
+ p_cb->msg_param.data.attachment = FALSE;
+ }
+
+ p_param = bta_mse_read_app_params(p_pkt, BTA_MA_APH_FRAC_REQ, &len);
+ if (p_param)
+ {
+ BE_STREAM_TO_UINT8(p_cb->msg_param.data.fraction_request, p_param);
+ }
+ else
+ {
+ p_cb->msg_param.data.fraction_request = BTA_MA_FRAC_REQ_NO;
+ }
+
+
+ return TRUE;
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_get_msglist_path
+**
+** Description Get the path based on received folder name for the get
+** message list
+**
+** Parameters inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+** p_path - (output) pointer to the folder path
+**
+** Returns BOOLEAN TRUE-get path is successful
+*******************************************************************************/
+BOOLEAN bta_mse_get_msglist_path(UINT8 inst_idx, UINT8 sess_idx)
+{
+ tBTA_MSE_MA_SESS_CB *p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, sess_idx);
+ char *p_name = p_cb->ml_param.p_name;
+ char *p_path = p_cb->ml_param.p_path;
+ char *p_workdir = p_cb->p_workdir;
+ BOOLEAN status = TRUE;
+#if BTA_MSE_ENABLE_FS_CO == TRUE
+ BOOLEAN is_dir;
+#endif
+
+
+ if (*p_name == '\0')
+ {
+ BCM_STRNCPY_S(p_path, p_bta_fs_cfg->max_path_len+1, p_workdir, p_bta_fs_cfg->max_path_len);
+ }
+ /* Make sure the new path is not too big */
+ /* +1 is for the separator */
+ else if ((strlen(p_workdir)+1+strlen(p_name)) <= p_bta_fs_cfg->max_path_len)
+ {
+ /* create a temporary path for creation attempt */
+ sprintf(p_path, "%s%c%s", p_workdir,
+ p_bta_fs_cfg->path_separator, p_name);
+#if BTA_MSE_ENABLE_FS_CO == TRUE
+ if (((bta_fs_co_access(p_path, BTA_FS_ACC_EXIST,
+ &is_dir, bta_mse_cb.app_id)) != BTA_FS_CO_OK) || !is_dir)
+ {
+ status = FALSE;
+ }
+#endif
+ }
+ else
+ {
+ status = FALSE;
+ }
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_EVENT2("bta_mse_get_msglist_path status=%d pth=%s",status, p_path );
+#endif
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_find_bd_addr_match_pm_cb_index
+**
+** Description Finds the PM control block index
+** based on the specified BD address
+**
+** Parameters app_id - app_id
+** p_bd_addr - BD address
+** p_idx - (output) pointer to the MN control
+** block index
+**
+** Returns BOOLEAN - TRUE found
+** FALSE not found
+**
+*******************************************************************************/
+BOOLEAN bta_mse_find_pm_cb_index(BD_ADDR p_bd_addr, UINT8 *p_idx)
+{
+ BOOLEAN found=FALSE;
+ UINT8 i;
+
+ for (i=0; i < BTA_MSE_NUM_MN ; i ++)
+ {
+ if ((bta_mse_cb.pcb[i].in_use) &&
+ (!memcmp (bta_mse_cb.pcb[i].bd_addr, p_bd_addr, BD_ADDR_LEN)))
+ {
+ found = TRUE;
+ *p_idx = i;
+ break;
+ }
+ }
+
+#if BTA_MSE_DEBUG == TRUE
+ if (!found) APPL_TRACE_DEBUG2("dbg bta_mse_find_pm_cb_index found=%d index=%d", found, i);
+#endif
+ return found;
+}
+
+
+/*******************************************************************************
+**
+** Function bta_mse_find_avail_pm_cb_idx
+**
+** Description Finds a not in use PM control block index
+**
+** Parameters p_idx - (output) pointer to the PM control block index
+**
+** Returns BOOLEAN - TRUE found
+** FALSE not found
+**
+*******************************************************************************/
+BOOLEAN bta_mse_find_avail_pm_cb_idx(UINT8 *p_idx)
+{
+ BOOLEAN found=FALSE;
+ UINT8 i;
+
+ for (i=0; i < BTA_MSE_NUM_MN ; i ++)
+ {
+ if (!bta_mse_cb.pcb[i].in_use)
+ {
+ found = TRUE;
+ *p_idx = i;
+ break;
+ }
+ }
+
+#if BTA_MSE_DEBUG == TRUE
+ if (!found) APPL_TRACE_DEBUG2("bta_mse_find_avail_pm_cb_idx found=%d i=%d", found, i);
+#endif
+
+ return found;
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_pm_conn_open
+**
+** Description Determine whether or not bta_sys_conn_open should be called
+**
+** Parameters bd_addr - peer BD address
+**
+** Returns None
+**
+*******************************************************************************/
+void bta_mse_pm_conn_open(BD_ADDR bd_addr)
+{
+ tBTA_MSE_PM_CB *p_pcb;
+ UINT8 idx;
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_DEBUG0("bta_mse_pm_conn_open");
+#endif
+ if (!bta_mse_find_pm_cb_index(bd_addr, &idx))
+ {
+ if (bta_mse_find_avail_pm_cb_idx(&idx))
+ {
+ p_pcb = BTA_MSE_GET_PM_CB_PTR(idx);
+
+ p_pcb->in_use = TRUE;
+ p_pcb->opened = TRUE;
+ bdcpy(p_pcb->bd_addr, bd_addr);
+ bta_sys_conn_open(BTA_ID_MSE , bta_mse_cb.app_id, bd_addr);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_pm_conn_close
+**
+** Description Determine whether or not bta_sys_conn_close should be called
+**
+** Parameters bd_addr - peer BD address
+**
+** Returns None
+*******************************************************************************/
+void bta_mse_pm_conn_close(BD_ADDR bd_addr)
+{
+ tBTA_MSE_PM_CB *p_pcb;
+ UINT8 i, pm_idx, sess_idx, mn_idx;
+ BOOLEAN found_bd_addr=FALSE;
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_DEBUG0("bta_mse_pm_conn_close");
+#endif
+ if (bta_mse_find_pm_cb_index(bd_addr, &pm_idx))
+ {
+ p_pcb = BTA_MSE_GET_PM_CB_PTR(pm_idx);
+ if (p_pcb->opened)
+ {
+ for (i=0; i<BTA_MSE_NUM_INST; i++)
+ {
+ if (bta_mse_find_bd_addr_match_sess_cb_idx(bd_addr, i, &sess_idx))
+ {
+ found_bd_addr = TRUE;
+ break;
+ }
+ }
+
+ if (!found_bd_addr)
+ {
+ if ( bta_mse_find_bd_addr_match_mn_cb_index(bd_addr, &mn_idx))
+ {
+ found_bd_addr = TRUE;
+
+ }
+ }
+
+ if (!found_bd_addr)
+ {
+ memset(p_pcb, 0, sizeof(tBTA_MSE_PM_CB));
+ bta_sys_conn_close(BTA_ID_MSE , bta_mse_cb.app_id, bd_addr);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_mse_set_ma_oper
+**
+** Description Set MA operation and power management's busy/idle status based on
+** MA operation
+**
+** Parameters inst_idx - Index to the MA instance control block
+** sess_idx - Index to the MA session control block
+** oper - MA operation
+**
+** Returns None
+*******************************************************************************/
+void bta_mse_set_ma_oper(UINT8 inst_idx, UINT8 sess_idx, tBTA_MSE_OPER oper)
+{
+ tBTA_MSE_MA_SESS_CB *p_cb = BTA_MSE_GET_SESS_CB_PTR(inst_idx, sess_idx);
+ tBTA_MSE_MA_SESS_CB *p_scb;
+ tBTA_MSE_MN_CB *p_mcb;
+ tBTA_MSE_PM_CB *p_pcb;
+ UINT8 i, j, pm_idx, mn_idx;
+ BOOLEAN still_busy = FALSE;
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_DEBUG2("bta_mse_set_ma_oper old=%d new=%d", p_cb->oper, oper);
+#endif
+
+ if (p_cb->oper != oper)
+ {
+ p_cb->oper = oper;
+ if (bta_mse_find_pm_cb_index(p_cb->bd_addr, &pm_idx))
+ {
+ p_pcb = BTA_MSE_GET_PM_CB_PTR(pm_idx);
+
+ if (oper != BTA_MSE_OPER_NONE )
+ {
+ if (!p_pcb->busy)
+ {
+ p_pcb->busy = TRUE;
+ bta_sys_busy(BTA_ID_MSE, bta_mse_cb.app_id, p_cb->bd_addr);
+ }
+ }
+ else
+ {
+ if (p_pcb->busy)
+ {
+ for (i=0; i<BTA_MSE_NUM_INST; i++)
+ {
+ if (bta_mse_find_bd_addr_match_sess_cb_idx( p_cb->bd_addr, i, &j) &&
+ (i != inst_idx) && (j != sess_idx))
+ {
+ p_scb = BTA_MSE_GET_SESS_CB_PTR(i, j);
+ if (p_scb->oper != BTA_MSE_OPER_NONE )
+ {
+ still_busy = TRUE;
+ break;
+ }
+ }
+ }
+
+ if ((!still_busy) &&
+ bta_mse_find_bd_addr_match_mn_cb_index( p_cb->bd_addr, &mn_idx))
+ {
+ p_mcb = BTA_MSE_GET_MN_CB_PTR(mn_idx);
+ if (p_mcb->obx_oper != BTA_MSE_MN_OP_NONE )
+ {
+ still_busy = TRUE;
+ }
+ }
+
+ if (!still_busy)
+ {
+ p_pcb->busy = FALSE;
+ bta_sys_idle(BTA_ID_MSE, bta_mse_cb.app_id, p_cb->bd_addr);
+ }
+ }
+ }
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function bta_mse_set_mn_oper
+**
+** Description Set MN operation and power management's busy/idle status based on
+** MN operation
+**
+** Parameters ccb_idx - MN control block index
+** oper - MN operation
+**
+** Returns None
+*******************************************************************************/
+void bta_mse_set_mn_oper(UINT8 ccb_idx, UINT8 oper)
+{
+ tBTA_MSE_MN_CB *p_cb = BTA_MSE_GET_MN_CB_PTR(ccb_idx);
+ tBTA_MSE_MA_SESS_CB *p_scb;
+ tBTA_MSE_MN_CB *p_mcb;
+ tBTA_MSE_PM_CB *p_pcb;
+ UINT8 i, j, pm_idx, mn_idx;
+ BOOLEAN still_busy = FALSE;
+
+#if BTA_MSE_DEBUG == TRUE
+ APPL_TRACE_DEBUG2("dbg bta_mse_set_mn_oper old=%d new=%d", p_cb->obx_oper, oper);
+#endif
+ if (p_cb->obx_oper != oper)
+ {
+ p_cb->obx_oper = oper;
+ if (bta_mse_find_pm_cb_index(p_cb->bd_addr, &pm_idx))
+ {
+ p_pcb = BTA_MSE_GET_PM_CB_PTR(pm_idx);
+
+ if (oper != BTA_MSE_MN_OP_NONE )
+ {
+ if (!p_pcb->busy)
+ {
+ p_pcb->busy = TRUE;
+ bta_sys_busy(BTA_ID_MSE, bta_mse_cb.app_id, p_cb->bd_addr);
+ }
+ }
+ else
+ {
+ if (p_pcb->busy)
+ {
+ for (i=0; i<BTA_MSE_NUM_INST; i++)
+ {
+ if (bta_mse_find_bd_addr_match_sess_cb_idx( p_cb->bd_addr, i, &j))
+ {
+ p_scb = BTA_MSE_GET_SESS_CB_PTR(i, j);
+ if (p_scb->oper != BTA_MSE_OPER_NONE )
+ {
+ still_busy = TRUE;
+ break;
+ }
+ }
+ }
+
+ if ((!still_busy) &&
+ bta_mse_find_bd_addr_match_mn_cb_index(p_cb->bd_addr, &mn_idx) &&
+ (mn_idx != ccb_idx))
+ {
+ p_mcb = BTA_MSE_GET_MN_CB_PTR(mn_idx);
+ if (p_mcb->obx_oper != BTA_MSE_MN_OP_NONE )
+ {
+ still_busy = TRUE;
+ }
+ }
+
+ if (!still_busy)
+ {
+ p_pcb->busy = FALSE;
+ bta_sys_idle(BTA_ID_MSE, bta_mse_cb.app_id, p_cb->bd_addr);
+ }
+ }
+ }
+ }
+ }
+
+}
+
+#endif /* BTA_MSE_INCLUDED */
diff --git a/bta/op/bta_op_fmt.c b/bta/op/bta_op_fmt.c
new file mode 100644
index 0000000..000370a
--- /dev/null
+++ b/bta/op/bta_op_fmt.c
@@ -0,0 +1,804 @@
+/*****************************************************************************
+**
+** Name: bta_op_fmt.c
+**
+** Description: This file contains common functions and data structures
+** used by the OPP object formatting functions.
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include <string.h>
+#include <ctype.h>
+#include "bta_op_api.h"
+#include "bta_op_fmt.h"
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+#define BTA_OP_ENCODING_LEN 9
+#define BTA_OP_CHARSET_LEN 8
+#define BTA_OP_PARAM_TYPE_HDR_LEN 5
+#define BTA_OP_NUM_NONINLINE_MEDIA 2
+
+const char bta_op_encoding[] = "ENCODING=";
+
+const tBTA_OP_PARAM bta_op_encodings[] =
+{/* the len is (BTA_OP_ENCODING_LEN + 1 + strlen(p_name)) */
+ {NULL, 0},
+ {"QUOTED-PRINTABLE", 26}, /* BTA_OP_ENC_QUOTED_PRINTABLE */
+ {"8BIT", 14}, /* BTA_OP_ENC_8BIT */
+ {"b", 11}, /* BTA_OP_ENC_BINARY */
+// btla-specific ++
+ {"BASE64", 16} /* BTA_OP_ENC_BASE64 */
+// btla-specific --
+};
+
+#define BTA_OP_NUM_ENCODINGS 3
+#define BTA_OP_QP_IDX 1 /* array index for quoted printable in bta_op_encodings */
+
+const char bta_op_charset[] = "CHARSET=";
+
+const char bta_op_param_type_hdr[] = "TYPE=";
+
+const tBTA_OP_PARAM bta_op_charsets[] =
+{/* the len is (BTA_OP_CHARSET_LEN + 1 + strlen(p_name)) */
+ {NULL, 0},
+ {"BIG5", 13}, /* BTA_OP_CHAR_BIG5 */
+ {"EUC-JP", 15}, /* BTA_OP_CHAR_EUC_JP */
+ {"EUC-KR", 15}, /* BTA_OP_CHAR_EUC_KR */
+ {"GB2312", 15}, /* BTA_OP_CHAR_GB2312 */
+ {"ISO-2022-JP", 20}, /* BTA_OP_CHAR_ISO_2022_JP */
+ {"ISO-8859-1", 19}, /* BTA_OP_CHAR_ISO_8859_1 */
+ {"ISO-8859-2", 19}, /* BTA_OP_CHAR_ISO_8859_2 */
+ {"ISO-8859-3", 19}, /* BTA_OP_CHAR_ISO_8859_3 */
+ {"ISO-8859-4", 19}, /* BTA_OP_CHAR_ISO_8859_4 */
+ {"ISO-8859-5", 19}, /* BTA_OP_CHAR_ISO_8859_5 */
+ {"ISO-8859-6", 19}, /* BTA_OP_CHAR_ISO_8859_6 */
+ {"ISO-8859-7", 19}, /* BTA_OP_CHAR_ISO_8859_7 */
+ {"ISO-8859-8", 19}, /* BTA_OP_CHAR_ISO_8859_8 */
+ {"KOI8-R", 15}, /* BTA_OP_CHAR_KOI8_R */
+ {"SHIFT_JIS", 18}, /* BTA_OP_CHAR_SHIFT_JIS */
+ {"UTF-8", 14} /* BTA_OP_CHAR_UTF_8 */
+};
+
+#define BTA_OP_NUM_CHARSETS 16
+
+/* Structure of the 32-bit parameters mask:
+** (same comment is in bta_op_api.h)
+** + property-specific
+** +reserved | + character set
+** | | | + encoding
+** | | | |
+** 0000000000000000 00000000 00000 000
+*/
+#define BTA_OP_GET_PARAM(param, encod, charset, specific) \
+ encod = (UINT8) (param) & 0x00000007; \
+ charset = (UINT8) ((param) >> 3) & 0x0000001F; \
+ specific = (UINT8) ((param) >> 8) & 0x000000FF;
+
+/* mask for properties default 0, filter all */
+static UINT32 bta_op_prop_filter_mask = 0;
+
+const tBTA_OP_PROP_MEDIA bta_op_media[] =
+{
+ {NULL, 2},
+ {"PHOTO", 5},
+ {"SOUND", 5}
+};
+
+/* Place holder constant for safe string functions since there's no way to know how
+** memory is remaining for input parameter to build property.
+** Note: The BCM_STRCPY_S functions should be changed to know how much memory
+** is remaining. When completed this constant can be removed. Also, if safe
+** string functions are not used then this parameter is ignored anyway!
+*/
+#ifndef BTA_OP_REM_MEMORY
+#define BTA_OP_REM_MEMORY 8228
+#endif
+
+/*******************************************************************************
+**
+** Function bta_op_strnicmp
+**
+** Description Case insensitive strncmp.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+INT16 bta_op_strnicmp(const char *pStr1, const char *pStr2, size_t Count)
+{
+ char c1, c2;
+ INT16 v;
+
+ if (Count == 0)
+ return 0;
+
+ do {
+ c1 = *pStr1++;
+ c2 = *pStr2++;
+ /* the casts are necessary when pStr1 is shorter & char is signed */
+ v = (UINT16) tolower(c1) - (UINT16) tolower(c2);
+ } while ((v == 0) && (c1 != '\0') && (--Count > 0));
+
+ return v;
+}
+
+/*******************************************************************************
+**
+** Function bta_op_set_prop_mask
+**
+** Description Set property mask
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_op_set_prop_filter_mask(UINT32 mask)
+{
+ bta_op_prop_filter_mask = mask;
+ return;
+}
+
+/*******************************************************************************
+**
+** Function bta_op_prop_len
+**
+** Description Calculate the length of a property string through lookup
+** tables.
+**
+**
+** Returns Length of string in bytes.
+**
+*******************************************************************************/
+UINT16 bta_op_prop_len(const tBTA_OP_PROP_TBL *p_tbl, tBTA_OP_PROP *p_prop)
+{
+ UINT8 i_e, i_c, i_s;
+ UINT8 len_s = 0;
+ int i;
+
+ /* parse parameters mask */
+ BTA_OP_GET_PARAM(p_prop->parameters, i_e, i_c, i_s);
+
+ /* calculate length of property-specific parameters, if any */
+ if (p_tbl[p_prop->name].p_param_tbl != NULL)
+ {
+ for (i = 1; (i_s != 0) && (i <= p_tbl[p_prop->name].p_param_tbl[0].len); i++)
+ {
+ if (i_s & 1)
+ {
+ len_s += p_tbl[p_prop->name].p_param_tbl[i].len;
+ }
+ i_s >>= 1;
+ }
+ }
+
+ return (p_tbl[p_prop->name].len + len_s + bta_op_charsets[i_c].len +
+ bta_op_encodings[i_e].len + p_prop->len);
+}
+
+/*******************************************************************************
+**
+** Function bta_op_param_conflict
+**
+** Description Check if the parameters of the property for the format
+** conflict/not allowed.
+**
+**
+** Returns TRUE if not allowed, else FALSE
+**
+*******************************************************************************/
+BOOLEAN bta_op_param_conflict(tBTA_OP_SUP_FMT fmt, tBTA_OP_PROP *p_prop)
+{
+ UINT8 i_e, i_c, i_s;
+ BOOLEAN conflict = FALSE;
+
+ if (p_prop->parameters != 0)
+ {
+ BTA_OP_GET_PARAM(p_prop->parameters, i_e, i_c, i_s);
+
+ if (fmt == BTA_OP_FMT_VCARD30)
+ {
+ /* VCard 3.0 does not support CHARSET. If it is present, we
+ should ignore the whole property in the vCard build process */
+ if (bta_op_charsets[i_c].p_name != NULL)
+ conflict = TRUE;
+
+ /* VCard 3.0 only supports 'b' encoding. If any other encoding
+ ex. quoted-printable, is present, then whole property is ignored */
+ if ((bta_op_encodings[i_e].p_name != NULL) && strcmp(bta_op_encodings[i_e].p_name, "b"))
+ conflict = TRUE;
+ }
+ }
+
+ return conflict;
+}
+/*******************************************************************************
+**
+** Function bta_op_add_param
+**
+** Description Add parameter strings to a property string.
+**
+**
+** Returns Pointer to the next byte after the end of the string.
+**
+*******************************************************************************/
+UINT8 *bta_op_add_param(tBTA_OP_SUP_FMT fmt, const tBTA_OP_PROP_TBL *p_tbl, UINT8 *p, tBTA_OP_PROP *p_prop)
+{
+ UINT8 i_e, i_c, i_s;
+ int i;
+ UINT8 bta_op_param_type_delimit = 0;
+
+ if (p_prop->parameters != 0)
+ {
+ BTA_OP_GET_PARAM(p_prop->parameters, i_e, i_c, i_s);
+
+ /* add encoding parameter */
+ if (bta_op_encodings[i_e].p_name != NULL)
+ {
+ *p++ = ';';
+ BCM_STRCPY_S((char *) p, BTA_OP_REM_MEMORY, bta_op_encoding);
+ p += BTA_OP_ENCODING_LEN;
+ BCM_STRCPY_S((char *) p, BTA_OP_REM_MEMORY, bta_op_encodings[i_e].p_name);
+ p += bta_op_encodings[i_e].len - BTA_OP_ENCODING_LEN - 1;
+ }
+
+ /* add character set parameter */
+ if (bta_op_charsets[i_c].p_name != NULL)
+ {
+ *p++ = ';';
+ BCM_STRCPY_S((char *) p, BTA_OP_REM_MEMORY, bta_op_charset);
+ p += BTA_OP_CHARSET_LEN;
+ BCM_STRCPY_S((char *) p, BTA_OP_REM_MEMORY, bta_op_charsets[i_c].p_name);
+ p += bta_op_charsets[i_c].len - BTA_OP_CHARSET_LEN - 1;
+ }
+
+ /* add any property-specific parameters */
+ if (p_tbl[p_prop->name].p_param_tbl != NULL)
+ {
+ for (i = 1; (i_s != 0) && (i <= p_tbl[p_prop->name].p_param_tbl[0].len); i++)
+ {
+ if (i_s & 1)
+ {
+ if (bta_op_param_type_delimit)
+ {
+ *p++ = ',';
+ }
+ else
+ {
+ *p++ = ';';
+
+ if (fmt == BTA_OP_FMT_VCARD30)
+ {
+ BCM_STRNCPY_S((char *) p, BTA_OP_PARAM_TYPE_HDR_LEN+1, bta_op_param_type_hdr, BTA_OP_PARAM_TYPE_HDR_LEN);
+ p += BTA_OP_PARAM_TYPE_HDR_LEN;
+ bta_op_param_type_delimit++;
+ }
+ }
+ BCM_STRCPY_S((char *) p, BTA_OP_REM_MEMORY, p_tbl[p_prop->name].p_param_tbl[i].p_name);
+ p += p_tbl[p_prop->name].p_param_tbl[i].len - 1;
+ }
+ i_s >>= 1;
+ }
+ }
+ }
+ else if (p_prop->p_param)
+ {
+ *p++ = ';';
+ memcpy((char *) p, p_prop->p_param, p_prop->param_len);
+ p += p_prop->param_len;
+ }
+
+ return p;
+}
+
+/*******************************************************************************
+**
+** Function bta_op_add_media_param
+**
+** Description Add parameter strings to a media property string.
+**
+**
+** Returns Pointer to the next byte after the end of the string.
+**
+*******************************************************************************/
+UINT8 *bta_op_add_media_param(const tBTA_OP_PROP_TBL *p_tbl, UINT8 *p, tBTA_OP_PROP *p_prop)
+{
+ UINT8 i_e, i_c, i_s;
+ int i;
+
+ if (p_prop->parameters != 0)
+ {
+ BTA_OP_GET_PARAM(p_prop->parameters, i_e, i_c, i_s);
+
+ /* add encoding parameter */
+ if (bta_op_encodings[i_e].p_name != NULL)
+ {
+ *p++ = ';';
+ BCM_STRCPY_S((char *) p, BTA_OP_REM_MEMORY, bta_op_encoding);
+ p += BTA_OP_ENCODING_LEN;
+ BCM_STRCPY_S((char *) p, BTA_OP_REM_MEMORY, bta_op_encodings[i_e].p_name);
+ p += bta_op_encodings[i_e].len - BTA_OP_ENCODING_LEN - 1;
+ }
+
+ /* add any property-specific parameters */
+ if (p_tbl[p_prop->name].p_param_tbl != NULL)
+ {
+ for (i = 1; (i_s != 0) && (i <= p_tbl[p_prop->name].p_param_tbl[0].len); i++)
+ {
+ if (i_s & 1)
+ {
+ *p++ = ';';
+
+ /* Add "TYPE=" to non-referenced (inline) media */
+ if (i > BTA_OP_NUM_NONINLINE_MEDIA)
+ {
+ BCM_STRNCPY_S((char *) p, BTA_OP_PARAM_TYPE_HDR_LEN+1, bta_op_param_type_hdr, BTA_OP_PARAM_TYPE_HDR_LEN);
+ p += BTA_OP_PARAM_TYPE_HDR_LEN;
+ }
+
+ BCM_STRCPY_S((char *) p, BTA_OP_REM_MEMORY, p_tbl[p_prop->name].p_param_tbl[i].p_name);
+ p += p_tbl[p_prop->name].p_param_tbl[i].len - 1;
+ break;
+ }
+ i_s >>= 1;
+ }
+ }
+ }
+ else if (p_prop->p_param)
+ {
+ *p++ = ';';
+ memcpy((char *) p, p_prop->p_param, p_prop->param_len);
+ p += p_prop->param_len;
+ }
+
+ return p;
+}
+
+/*******************************************************************************
+**
+** Function bta_op_get_property_by_name
+**
+** Description Get the property user data by name.
+**
+**
+** Returns BTA_OP_OK if operation successful.
+** BTA_OP_FAIL if there is no property user data.
+**
+*******************************************************************************/
+tBTA_OP_STATUS bta_op_get_property_by_name(const tBTA_OP_PROP_TBL *p_tbl, UINT8 *p_name,
+ tBTA_OP_PROP *p_prop, UINT8 num_prop, UINT8 *p_data,
+ UINT16 *p_len)
+{
+ int i, j;
+ tBTA_OP_STATUS result = BTA_OP_FAIL;
+
+ /* for each property */
+ for(i = 0; num_prop != 0; num_prop--, i++)
+ {
+ /* verify property is valid */
+ if ((p_prop[i].name == 0) || (p_prop[i].name > p_tbl[0].len))
+ {
+ result = BTA_OP_FAIL;
+ break;
+ }
+
+ j = p_prop[i].name;
+
+ if (bta_op_strnicmp(p_tbl[j].p_name, (char *) p_name,
+ (p_tbl[j].len - BTA_OP_PROP_OVHD)) == 0)
+ {
+ memcpy(p_data, p_prop[i].p_data, p_prop[i].len);
+ *p_len = p_prop[i].len;
+ result = BTA_OP_OK;
+ break;
+ }
+ }
+ return result;
+}
+
+/*******************************************************************************
+**
+** Function bta_op_build_obj
+**
+** Description Build an object from property data supplied by the user.
+**
+**
+** Returns BTA_OP_OK if operation successful.
+** BTA_OP_FAIL if invalid property data.
+** BTA_OP_MEM if not enough memory to complete build.
+**
+*******************************************************************************/
+tBTA_OP_STATUS bta_op_build_obj(const tBTA_OP_OBJ_TBL *p_bld, UINT8 *p_data,
+ UINT16 *p_len, tBTA_OP_PROP *p_prop, UINT8 num_prop)
+{
+ int i,j;
+ tBTA_OP_STATUS result = BTA_OP_OK;
+ UINT8 *p = p_data;
+
+ /* sanity check length */
+ if (*p_len < p_bld->min_len)
+ {
+ result = BTA_OP_MEM;
+ }
+ else
+ {
+ /* adjust p_len to amount of free space minus start and end */
+ *p_len -= p_bld->min_len;
+
+ /* add begin, version */
+ BCM_STRCPY_S((char *) p, BTA_OP_REM_MEMORY, p_bld->p_begin_str);
+ p += p_bld->begin_len;
+
+ /* for each property */
+ for(i = 0; num_prop != 0; num_prop--, i++)
+ {
+ /* verify property is valid */
+ if ((p_prop[i].name == 0) || (p_prop[i].name > p_bld->p_tbl[0].len))
+ {
+ result = BTA_OP_FAIL;
+ break;
+ }
+
+ /* verify property will fit */
+ if (bta_op_prop_len(p_bld->p_tbl, &p_prop[i]) > (p_data + p_bld->begin_len + *p_len - p))
+ {
+ result = BTA_OP_MEM;
+ break;
+ }
+
+ /* check for filter */
+ if (bta_op_prop_filter_mask !=0 && p_bld->p_prop_filter_mask_tbl != NULL &&
+ p_prop[i].name <= p_bld->p_prop_filter_mask_tbl->len)
+ {
+ if (!(bta_op_prop_filter_mask & p_bld->p_prop_filter_mask_tbl->p_prop_filter_mask[p_prop[i].name]))
+ continue;
+ }
+
+ /* Check if the combination of parameters are allowed for
+ the format we are building */
+ if (bta_op_param_conflict(p_bld->fmt, &p_prop[i]))
+ continue;
+
+ /* add property string */
+ BCM_STRCPY_S((char *) p, BTA_OP_REM_MEMORY, p_bld->p_tbl[p_prop[i].name].p_name);
+ p += p_bld->p_tbl[p_prop[i].name].len - BTA_OP_PROP_OVHD;
+
+ for (j= bta_op_media[0].len; j > 0; j--)
+ {
+ if (!bta_op_strnicmp(bta_op_media[j].media_name, p_bld->p_tbl[p_prop[i].name].p_name, bta_op_media[j].len))
+ {
+ p = bta_op_add_media_param(p_bld->p_tbl, p, &p_prop[i]);
+ break;
+ }
+ }
+
+ if (!j)
+ {
+ /* add property parameters */
+ p = bta_op_add_param(p_bld->fmt, p_bld->p_tbl, p, &p_prop[i]);
+ }
+
+ /* add user data */
+// btla-specific ++
+ if(p_prop[i].name != BTA_OP_VCARD_CALL) // If the data is call date-time, use ';' instead of ':'
+ {
+ *p++ = ':';
+ }
+ else
+ {
+ *p++ = ';';
+ }
+// btla-specific --
+
+ memcpy(p, p_prop[i].p_data, p_prop[i].len);
+ p += p_prop[i].len;
+ *p++ = '\r';
+ *p++ = '\n';
+ }
+
+ /* add in end */
+ memcpy(p, p_bld->p_end_str, p_bld->end_len);
+ p += p_bld->end_len;
+ }
+
+ *p_len = (UINT16) (p - p_data);
+ return result;
+}
+
+/*******************************************************************************
+**
+** Function bta_op_nextline
+**
+** Description Scan to beginning of next property text line.
+**
+**
+** Returns Pointer to beginning of property or NULL if end of
+** data reached.
+**
+*******************************************************************************/
+static UINT8 *bta_op_nextline(UINT8 *p, UINT8 *p_end, BOOLEAN qp)
+{
+// btla-specific ++
+ if (*p == '\r')
+ {
+ p--;
+ }
+// btla-specific --
+
+ if ((p_end - p) > 3)
+ {
+ p_end -= 3;
+ while (p < p_end)
+ {
+ if (*(++p) == '\r')
+ {
+ if (*(p + 1) == '\n')
+ {
+ if (qp)
+ {
+ if (*(p - 1) == '=')
+ {
+ /* this is a soft break for quoted-printable*/
+ continue;
+ }
+ }
+
+ if ((*(p + 2) != ' ') && (*(p + 2) != '\t'))
+ {
+ return(p + 2);
+ }
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+/*******************************************************************************
+**
+** Function bta_op_scantok
+**
+** Description Scan a line for one or more tokens.
+**
+**
+** Returns Pointer to token or NULL if end of data reached.
+**
+*******************************************************************************/
+static UINT8 *bta_op_scantok(UINT8 *p, UINT8 *p_end, const char *p_tok)
+{
+ int i;
+ UINT8 num_tok = strlen(p_tok);
+
+ for (; p < p_end; p++)
+ {
+ for (i = 0; i < num_tok; i++)
+ {
+ if (*p == p_tok[i])
+ {
+ return p;
+ }
+ }
+ }
+ return NULL;
+}
+
+/*******************************************************************************
+**
+** Function bta_op_scanstr
+**
+** Description Scan for a matching string.
+**
+**
+** Returns Pointer to end of match or NULL if end of data reached.
+**
+*******************************************************************************/
+UINT8 *bta_op_scanstr(UINT8 *p, UINT8 *p_end, const char *p_str)
+{
+ int len = strlen(p_str);
+
+ for (;;)
+ {
+ /* check for match */
+ if (strncmp((char *) p, p_str, len) == 0)
+ {
+ p += len;
+ break;
+ }
+ /* no match; skip to next line, checking for end */
+ else if ((p = bta_op_nextline(p, p_end, FALSE)) == NULL)
+ {
+ break;
+ }
+ }
+ return p;
+}
+
+/*******************************************************************************
+**
+** Function bta_op_parse_obj
+**
+** Description Parse an object.
+**
+**
+** Returns BTA_OP_OK if operation successful.
+** BTA_OP_FAIL if invalid data.
+** BTA_OP_MEM if not enough memory to complete build.
+**
+*******************************************************************************/
+tBTA_OP_STATUS bta_op_parse_obj(const tBTA_OP_OBJ_TBL *p_prs, tBTA_OP_PROP *p_prop,
+ UINT8 *p_num_prop, UINT8 *p_data, UINT16 len)
+{
+ UINT32 j;
+ UINT8 *p_s, *p_e;
+ tBTA_OP_STATUS result = BTA_OP_OK;
+ UINT8 max_prop = *p_num_prop;
+ UINT8 *p_end = p_data + len;
+ UINT8 prop_name = 0;
+ BOOLEAN qp=FALSE;
+
+ *p_num_prop = 0;
+
+ /* sanity check length */
+ if (len < p_prs->min_len)
+ {
+ return BTA_OP_FAIL;
+ }
+
+ /* find beginning */
+ if ((p_s = bta_op_scanstr(p_data, p_end, p_prs->p_begin_str)) == NULL)
+ {
+ return BTA_OP_FAIL;
+ }
+
+ while (*p_num_prop < max_prop)
+ {
+ /* scan for next delimiter */
+ if ((p_e = bta_op_scantok(p_s, p_end, ".;:")) == NULL)
+ {
+ break;
+ }
+
+ /* deal with grouping delimiter */
+ if (*p_e == '.')
+ {
+ p_s = p_e + 1;
+ if ((p_e = bta_op_scantok(p_s, p_end, ";:")) == NULL)
+ {
+ break;
+ }
+ }
+
+ /* we found a property; see if it matches anything in our list */
+ for (j = 1; j <= p_prs->p_tbl[0].len; j++)
+ {
+ if (bta_op_strnicmp(p_prs->p_tbl[j].p_name, (char *) p_s,
+ (p_prs->p_tbl[j].len - BTA_OP_PROP_OVHD)) == 0)
+ {
+ p_prop[*p_num_prop].name = prop_name = j;
+ p_prop[*p_num_prop].parameters = 0;
+ break;
+ }
+ }
+
+ /* if not in our list we can't parse it; continue */
+ if (j > p_prs->p_tbl[0].len)
+ {
+ if ((p_s = bta_op_nextline(p_e, p_end, FALSE)) == NULL)
+ {
+ break;
+ }
+ continue;
+ }
+
+ /* now parse out all the parameters */
+ if (*p_e == ';')
+ {
+ while ((*p_e == ';') || (*p_e == ','))
+ {
+ p_s = p_e + 1;
+
+ if ((p_e = bta_op_scantok(p_s, p_end, ",;:")) == NULL)
+ {
+ break;
+ }
+
+ /* we found a parameter; see if it matches anything */
+
+ /* check for encoding */
+ qp = FALSE;
+ if (bta_op_strnicmp(bta_op_encoding, (char *) p_s, BTA_OP_ENCODING_LEN) == 0)
+ {
+ p_s += BTA_OP_ENCODING_LEN;
+ for (j = 1; j <= BTA_OP_NUM_ENCODINGS; j++)
+ {
+ if (bta_op_strnicmp(bta_op_encodings[j].p_name, (char *) p_s,
+ (bta_op_encodings[j].len - BTA_OP_ENCODING_LEN - 1)) == 0)
+ {
+ if (j == BTA_OP_QP_IDX)
+ {
+ /* encoding = quoted-printable*/
+ qp= TRUE;
+ }
+ p_prop[*p_num_prop].parameters |= j;
+ break;
+ }
+ }
+ }
+ /* check for charset */
+ else if (bta_op_strnicmp(bta_op_charset, (char *) p_s, BTA_OP_CHARSET_LEN) == 0)
+ {
+ p_s += BTA_OP_CHARSET_LEN;
+ for (j = 1; j <= BTA_OP_NUM_CHARSETS; j++)
+ {
+ if (bta_op_strnicmp(bta_op_charsets[j].p_name, (char *) p_s,
+ (bta_op_charsets[j].len - BTA_OP_CHARSET_LEN - 1)) == 0)
+ {
+ p_prop[*p_num_prop].parameters |= j << 3;
+ break;
+ }
+ }
+ }
+ /* check for property-specific parameters */
+ else if (p_prs->p_tbl[prop_name].p_param_tbl != NULL)
+ {
+
+ /* Check for "TYPE=" */
+ if (!bta_op_strnicmp((char *)p_s, bta_op_param_type_hdr, BTA_OP_PARAM_TYPE_HDR_LEN))
+ {
+ p_s += BTA_OP_PARAM_TYPE_HDR_LEN;
+ }
+
+ for (j = p_prs->p_tbl[prop_name].p_param_tbl[0].len; j > 0; j--)
+ {
+ if (bta_op_strnicmp(p_prs->p_tbl[prop_name].p_param_tbl[j].p_name,
+ (char *) p_s, (p_prs->p_tbl[prop_name].p_param_tbl[j].len - 1)) == 0)
+ {
+ p_prop[*p_num_prop].parameters |= ((UINT32) 1) << (j + 7);
+ break;
+ }
+ }
+ }
+ else
+ {
+ /* if this the start of the param */
+ if (!p_prop[*p_num_prop].p_param)
+ p_prop[*p_num_prop].p_param = p_s;
+ if (*p_e == ':')
+ p_prop[*p_num_prop].param_len += (p_e - p_s);
+ else
+ p_prop[*p_num_prop].param_len += (p_e - p_s + 1);
+ }
+ }
+ }
+
+ if (p_e == NULL)
+ {
+ break;
+ }
+
+ /* go to start of next property */
+ p_s = p_e + 1;
+ if ((p_e = bta_op_nextline(p_s, p_end, qp)) == NULL)
+ {
+ break;
+ }
+
+ /* save property info */
+ p_prop[*p_num_prop].p_data = p_s;
+ p_prop[*p_num_prop].len = (UINT16) (p_e - p_s - 2);
+// btla-specific ++
+ if (p_prop[*p_num_prop].len)
+ {
+ (*p_num_prop)++;
+ }
+// btla-specific --
+ p_s = p_e;
+ }
+ return result;
+}
+
diff --git a/bta/op/bta_op_fmt.h b/bta/op/bta_op_fmt.h
new file mode 100644
index 0000000..29bb40c
--- /dev/null
+++ b/bta/op/bta_op_fmt.h
@@ -0,0 +1,92 @@
+/*****************************************************************************
+**
+** Name: bta_op_fmt.h
+**
+** Description: This is the interface file for common functions and data
+** types used by the OPP object formatting functions.
+**
+** Copyright (c) 2003, Widcomm Inc., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_OP_FMT_H
+#define BTA_OP_FMT_H
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+#define BTA_OP_PROP_OVHD 3
+
+/*****************************************************************************
+** Data types
+*****************************************************************************/
+
+enum {
+ BTA_OP_FMT_NONE=0,
+ BTA_OP_FMT_VCARD21,
+ BTA_OP_FMT_VCARD30,
+ BTA_OP_FMT_VCAL10,
+ BTA_OP_FMT_VNOTE11
+};
+
+/*Supported formats */
+typedef UINT8 tBTA_OP_SUP_FMT;
+
+typedef struct
+{
+ const char *p_name;
+ UINT8 len;
+} tBTA_OP_PARAM;
+
+typedef struct
+{
+ const char *p_name;
+ const tBTA_OP_PARAM *p_param_tbl;
+ UINT8 len;
+} tBTA_OP_PROP_TBL;
+
+
+typedef struct
+{
+ const UINT32 *p_prop_filter_mask;
+ UINT8 len;
+} tBTA_OP_PROP_FILTER_MASK_TBL;
+
+typedef struct
+{
+ const tBTA_OP_PROP_TBL *p_tbl;
+ tBTA_OP_SUP_FMT fmt;
+ const char *p_begin_str;
+ const char *p_end_str;
+ UINT8 begin_len;
+ UINT8 end_len;
+ UINT8 min_len;
+ const tBTA_OP_PROP_FILTER_MASK_TBL *p_prop_filter_mask_tbl;
+} tBTA_OP_OBJ_TBL;
+
+typedef struct
+{
+ const char *media_name;
+ UINT8 len;
+} tBTA_OP_PROP_MEDIA;
+
+/*****************************************************************************
+** Function prototypes
+*****************************************************************************/
+
+extern tBTA_OP_STATUS bta_op_build_obj(const tBTA_OP_OBJ_TBL *p_bld,
+ UINT8 *p_data, UINT16 *p_len,
+ tBTA_OP_PROP *p_prop, UINT8 num_prop);
+
+extern tBTA_OP_STATUS bta_op_parse_obj(const tBTA_OP_OBJ_TBL *p_prs,
+ tBTA_OP_PROP *p_prop, UINT8 *p_num_prop,
+ UINT8 *p_data, UINT16 len);
+extern tBTA_OP_STATUS bta_op_get_property_by_name(const tBTA_OP_PROP_TBL *p_tbl, UINT8 *p_name,
+ tBTA_OP_PROP *p_prop, UINT8 num_prop, UINT8 *p_data,
+ UINT16 *p_len);
+extern UINT8 *bta_op_scanstr(UINT8 *p, UINT8 *p_end, const char *p_str);
+extern void bta_op_set_prop_filter_mask(UINT32 mask);
+
+#endif /* BTA_OP_FMT_H */
+
diff --git a/bta/op/bta_op_vcal.c b/bta/op/bta_op_vcal.c
new file mode 100644
index 0000000..79aef02
--- /dev/null
+++ b/bta/op/bta_op_vcal.c
@@ -0,0 +1,158 @@
+/*****************************************************************************
+**
+** Name: bta_op_vcal.c
+**
+** Description: This file contains functions for parsing and building
+** vCal objects.
+**
+** Copyright (c) 2003, Widcomm Inc., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bta_op_api.h"
+#include "bta_op_fmt.h"
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+#define BTA_OP_TODO_BEGIN_LEN 43
+#define BTA_OP_TODO_END_LEN 26
+
+#define BTA_OP_TODO_MIN_LEN (BTA_OP_TODO_BEGIN_LEN + BTA_OP_TODO_END_LEN)
+
+#define BTA_OP_EVENT_BEGIN_LEN 44
+#define BTA_OP_EVENT_END_LEN 27
+
+#define BTA_OP_EVENT_MIN_LEN (BTA_OP_EVENT_BEGIN_LEN + BTA_OP_EVENT_END_LEN)
+
+#define BTA_OP_VCAL_BEGIN_LEN 17
+#define BTA_OP_VCAL_END_LEN 15
+#define BTA_OP_VCAL_MIN_LEN (BTA_OP_VCAL_BEGIN_LEN + BTA_OP_VCAL_END_LEN)
+#define BTA_OP_BEGIN_OFFSET 30
+
+const char bta_op_vcal_begin[] = "BEGIN:VCALENDAR\r\n";
+
+const char bta_op_todo_begin[] = "BEGIN:VCALENDAR\r\nVERSION:1.0\r\nBEGIN:VTODO\r\n";
+
+const char bta_op_todo_end[] = "END:VTODO\r\nEND:VCALENDAR\r\n";
+
+const char bta_op_event_begin[] = "BEGIN:VCALENDAR\r\nVERSION:1.0\r\nBEGIN:VEVENT\r\n";
+
+const char bta_op_event_end[] = "END:VEVENT\r\nEND:VCALENDAR\r\n";
+
+const tBTA_OP_PROP_TBL bta_op_vcal_tbl[] =
+{
+ {NULL, NULL, 11}, /* Number of elements in array */
+ {"CATEGORIES", NULL, 13}, /* BTA_OP_VCAL_CATEGORIES */
+ {"COMPLETED", NULL, 12}, /* BTA_OP_VCAL_COMPLETED */
+ {"DESCRIPTION", NULL, 14}, /* BTA_OP_VCAL_DESCRIPTION */
+ {"DTEND", NULL, 8}, /* BTA_OP_VCAL_DTEND */
+ {"DTSTART", NULL, 10}, /* BTA_OP_VCAL_DTSTART */
+ {"DUE", NULL, 6}, /* BTA_OP_VCAL_DUE */
+ {"LOCATION", NULL, 11}, /* BTA_OP_VCAL_LOCATION */
+ {"PRIORITY", NULL, 11}, /* BTA_OP_VCAL_PRIORITY */
+ {"STATUS", NULL, 9}, /* BTA_OP_VCAL_STATUS */
+ {"SUMMARY", NULL, 10}, /* BTA_OP_VCAL_SUMMARY */
+ {"X-IRMC-LUID", NULL, 14} /* BTA_OP_VCAL_LUID */
+};
+
+const tBTA_OP_OBJ_TBL bta_op_todo_bld =
+{
+ bta_op_vcal_tbl,
+ BTA_OP_FMT_VCAL10,
+ bta_op_todo_begin,
+ bta_op_todo_end,
+ BTA_OP_TODO_BEGIN_LEN,
+ BTA_OP_TODO_END_LEN,
+ BTA_OP_TODO_MIN_LEN
+};
+
+const tBTA_OP_OBJ_TBL bta_op_event_bld =
+{
+ bta_op_vcal_tbl,
+ BTA_OP_FMT_VCAL10,
+ bta_op_event_begin,
+ bta_op_event_end,
+ BTA_OP_EVENT_BEGIN_LEN,
+ BTA_OP_EVENT_END_LEN,
+ BTA_OP_EVENT_MIN_LEN
+};
+
+const tBTA_OP_OBJ_TBL bta_op_vcal_prs =
+{
+ bta_op_vcal_tbl,
+ BTA_OP_FMT_VCAL10,
+ bta_op_vcal_begin,
+ NULL,
+ BTA_OP_VCAL_BEGIN_LEN,
+ BTA_OP_VCAL_END_LEN,
+ BTA_OP_VCAL_MIN_LEN
+};
+
+/*******************************************************************************
+**
+** Function BTA_OpBuildCal
+**
+** Description Build a vCal 1.0 object. The input to this function is an
+** array of vCaalproperties and a pointer to memory to store
+** the card. The output is a formatted vCal.
+**
+**
+** Returns BTA_OP_OK if operation successful.
+** BTA_OP_FAIL if invalid property data.
+** BTA_OP_MEM if not enough memory to complete build.
+**
+*******************************************************************************/
+tBTA_OP_STATUS BTA_OpBuildCal(UINT8 *p_cal, UINT16 *p_len, tBTA_OP_PROP *p_prop,
+ UINT8 num_prop, tBTA_OP_VCAL vcal_type)
+{
+ tBTA_OP_OBJ_TBL *p_bld;
+
+ if (vcal_type == BTA_OP_VCAL_EVENT)
+ {
+ p_bld = (tBTA_OP_OBJ_TBL *) &bta_op_event_bld;
+ }
+ else
+ {
+ p_bld = ( tBTA_OP_OBJ_TBL *) &bta_op_todo_bld;
+ }
+
+ return bta_op_build_obj(p_bld, p_cal, p_len, p_prop, num_prop);
+}
+
+/*******************************************************************************
+**
+** Function BTA_OpParseCal
+**
+** Description Parse a vCal object. The input to this function is a
+** pointer to vCal data. The output is an array of parsed
+** vCal properties.
+**
+**
+** Returns BTA_OP_OK if operation successful.
+** BTA_OP_FAIL if invalid property data.
+** BTA_OP_MEM if not enough memory to complete parsing.
+**
+*******************************************************************************/
+tBTA_OP_STATUS BTA_OpParseCal(tBTA_OP_PROP *p_prop, UINT8 *p_num_prop, UINT8 *p_cal,
+ UINT16 len, tBTA_OP_VCAL *p_vcal_type)
+{
+ if (bta_op_scanstr(p_cal, (p_cal + len), &bta_op_todo_begin[BTA_OP_BEGIN_OFFSET]) != NULL)
+ {
+ *p_vcal_type = BTA_OP_VCAL_TODO;
+ }
+ else if (bta_op_scanstr(p_cal, (p_cal + len), &bta_op_event_begin[BTA_OP_BEGIN_OFFSET]) != NULL)
+ {
+ *p_vcal_type = BTA_OP_VCAL_EVENT;
+ }
+ else
+ {
+ *p_num_prop = 0;
+ return BTA_OP_FAIL;
+ }
+
+ return bta_op_parse_obj(&bta_op_vcal_prs, p_prop, p_num_prop, p_cal, len);
+}
+
diff --git a/bta/op/bta_op_vcard.c b/bta/op/bta_op_vcard.c
new file mode 100644
index 0000000..6a278ba
--- /dev/null
+++ b/bta/op/bta_op_vcard.c
@@ -0,0 +1,310 @@
+/*****************************************************************************
+**
+** Name: bta_op_vcard.c
+**
+** Description: This file contains functions for parsing and building
+** vCard objects.
+**
+** Copyright (c) 2003, Widcomm Inc., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bta_op_api.h"
+#include "bta_op_fmt.h"
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+#define BTA_OP_VCARD_BEGIN_LEN 26
+#define BTA_OP_VCARD_END_LEN 11
+
+#define BTA_OP_VCARD_MIN_LEN (BTA_OP_VCARD_BEGIN_LEN + BTA_OP_VCARD_END_LEN)
+
+const char bta_op_vcard_prs_begin[] = "BEGIN:VCARD\r\n";
+
+const char bta_op_vcard_21_begin[] = "BEGIN:VCARD\r\nVERSION:2.1\r\n";
+
+const char bta_op_vcard_30_begin[] = "BEGIN:VCARD\r\nVERSION:3.0\r\n";
+
+const char bta_op_vcard_end[] = "END:VCARD\r\n";
+
+const tBTA_OP_PARAM bta_op_vcard_adr[] =
+{
+ {NULL, 6}, /* Number of elements in array */
+ {"DOM", 4}, /* BTA_OP_ADR_DOM */
+ {"INTL", 5}, /* BTA_OP_ADR_INTL */
+ {"POSTAL", 7}, /* BTA_OP_ADR_POSTAL */
+ {"PARCEL", 7}, /* BTA_OP_ADR_PARCEL */
+ {"HOME", 5}, /* BTA_OP_ADR_HOME */
+ {"WORK", 5} /* BTA_OP_ADR_WORK */
+};
+
+const tBTA_OP_PARAM bta_op_vcard_email[] =
+{
+ {NULL, 3}, /* Number of elements in array */
+ {"PREF", 5}, /* BTA_OP_EMAIL_PREF */
+ {"INTERNET", 9}, /* BTA_OP_EMAIL_INTERNET */
+ {"X400", 5} /* BTA_OP_EMAIL_X400 */
+};
+
+const tBTA_OP_PARAM bta_op_vcard_tel[] =
+{
+ {NULL, 8}, /* Number of elements in array */
+ {"PREF", 5}, /* BTA_OP_TEL_PREF */
+ {"WORK", 5}, /* BTA_OP_TEL_WORK */
+ {"HOME", 5}, /* BTA_OP_TEL_HOME */
+ {"VOICE", 6}, /* BTA_OP_TEL_VOICE */
+ {"FAX", 4}, /* BTA_OP_TEL_FAX */
+ {"MSG", 4}, /* BTA_OP_TEL_MSG */
+ {"CELL", 5}, /* BTA_OP_TEL_CELL */
+ {"PAGER", 6} /* BTA_OP_TEL_PAGER */
+};
+
+const tBTA_OP_PARAM bta_op_vcard_photo[] =
+{
+ {NULL, 4}, /* Number of elements in array */
+ {"VALUE=URI", 10}, /* BTA_OP_PHOTO_VALUE_URI */
+ {"VALUE=URL", 10}, /* BTA_OP_PHOTO_VALUE_URL */
+ {"JPEG", 5}, /* BTA_OP_PHOTO_TYPE_JPEG */
+ {"GIF", 4} /* BTA_OP_PHOTO_TYPE_GIF */
+};
+
+const tBTA_OP_PARAM bta_op_vcard_sound[] =
+{
+ {NULL, 4}, /* Number of elements in array */
+ {"VALUE=URI", 10}, /* BTA_OP_SOUND_VALUE_URI */
+ {"VALUE=URL", 10}, /* BTA_OP_SOUND_VALUE_URL */
+ {"BASIC", 6}, /* BTA_OP_SOUND_TYPE_BASIC */
+ {"WAVE", 5} /* BTA_OP_SOUND_TYPE_WAVE */
+};
+
+const tBTA_OP_PROP_TBL bta_op_vcard_tbl[] =
+{
+ {NULL, NULL, 15}, /* Number of elements in array */
+ {"ADR", bta_op_vcard_adr, 6}, /* BTA_OP_VCARD_ADR */
+ {"EMAIL", bta_op_vcard_email, 8}, /* BTA_OP_VCARD_EMAIL */
+ {"FN", NULL, 5}, /* BTA_OP_VCARD_FN */
+ {"NOTE", NULL, 7}, /* BTA_OP_VCARD_NOTE */
+ {"NICKNAME", NULL, 11}, /* BTA_OP_VACRD_NICKNAME */
+ {"N", NULL, 4}, /* BTA_OP_VCARD_N */
+ {"ORG", NULL, 6}, /* BTA_OP_VCARD_ORG */
+ {"TEL", bta_op_vcard_tel, 6}, /* BTA_OP_VCARD_TEL */
+ {"TITLE", NULL, 8}, /* BTA_OP_VCARD_TITLE */
+ {"URL", NULL, 6}, /* BTA_OP_VCARD_URL */
+ {"X-IRMC-LUID", NULL, 14}, /* BTA_OP_VNOTE_LUID */
+ {"BDAY", NULL, 7}, /* BTA_OP_VCARD_BDAY */
+ {"PHOTO", bta_op_vcard_photo, 8}, /* BTA_OP_VCARD_PHOTO */
+ {"SOUND", bta_op_vcard_sound, 8}, /* BTA_OP_VCARD_SOUND */
+ {"X-IRMC-CALL-DATETIME", NULL, 23} /* BTA_OP_VCARD_CALL */
+};
+
+const UINT32 bta_op_vcard_prop_filter_mask[] =
+{
+/* table index should be the same as the prop table above */
+ BTA_OP_FILTER_ALL,
+ BTA_OP_FILTER_ADR,
+ BTA_OP_FILTER_EMAIL,
+ BTA_OP_FILTER_FN,
+ BTA_OP_FILTER_NOTE,
+ BTA_OP_FILTER_NICKNAME,
+ BTA_OP_FILTER_N,
+ BTA_OP_FILTER_ORG,
+ BTA_OP_FILTER_TEL,
+ BTA_OP_FILTER_TITLE,
+ BTA_OP_FILTER_URL,
+ BTA_OP_FILTER_UID,
+ BTA_OP_FILTER_BDAY,
+ BTA_OP_FILTER_PHOTO,
+ BTA_OP_FILTER_SOUND,
+ BTA_OP_FILTER_TIME_STAMP
+};
+
+const tBTA_OP_PROP_FILTER_MASK_TBL bta_op_vcard_prop_filter_mask_tbl =
+{
+ bta_op_vcard_prop_filter_mask,
+ 15
+};
+
+const tBTA_OP_OBJ_TBL bta_op_vcard_21_bld =
+{
+ bta_op_vcard_tbl,
+ BTA_OP_FMT_VCARD21,
+ bta_op_vcard_21_begin,
+ bta_op_vcard_end,
+ BTA_OP_VCARD_BEGIN_LEN,
+ BTA_OP_VCARD_END_LEN,
+ BTA_OP_VCARD_MIN_LEN,
+ &bta_op_vcard_prop_filter_mask_tbl
+};
+
+const tBTA_OP_OBJ_TBL bta_op_vcard_30_bld =
+{
+ bta_op_vcard_tbl,
+ BTA_OP_FMT_VCARD30,
+ bta_op_vcard_30_begin,
+ bta_op_vcard_end,
+ BTA_OP_VCARD_BEGIN_LEN,
+ BTA_OP_VCARD_END_LEN,
+ BTA_OP_VCARD_MIN_LEN,
+ &bta_op_vcard_prop_filter_mask_tbl
+};
+
+const tBTA_OP_OBJ_TBL bta_op_vcard_21_prs =
+{
+ bta_op_vcard_tbl,
+ BTA_OP_FMT_VCARD21,
+ bta_op_vcard_prs_begin,
+ bta_op_vcard_end,
+ BTA_OP_VCARD_BEGIN_LEN,
+ BTA_OP_VCARD_END_LEN,
+ BTA_OP_VCARD_MIN_LEN,
+ NULL
+};
+
+const tBTA_OP_OBJ_TBL bta_op_vcard_30_prs =
+{
+ bta_op_vcard_tbl,
+ BTA_OP_FMT_VCARD30,
+ bta_op_vcard_prs_begin,
+ bta_op_vcard_end,
+ BTA_OP_VCARD_BEGIN_LEN,
+ BTA_OP_VCARD_END_LEN,
+ BTA_OP_VCARD_MIN_LEN,
+ NULL
+};
+
+
+/*******************************************************************************
+**
+** Function bta_op_get_card_fmt
+**
+** Description Finds the vCard format contained in buffer pointed by p_card
+**
+**
+** Returns Vcard Format BTA_OP_VCARD21_FMT/BTA_OP_VCARD30_FMT else
+** BTA_OP_OTHER_FMT
+**
+*******************************************************************************/
+static tBTA_OP_SUP_FMT bta_op_get_card_fmt(UINT8 *p_data, UINT16 len)
+{
+ UINT8 *p_end = p_data + len;
+
+ if (bta_op_scanstr(p_data, p_end, bta_op_vcard_21_begin) != NULL)
+ {
+ return BTA_OP_FMT_VCARD21;
+ }
+ else if (bta_op_scanstr(p_data, p_end, bta_op_vcard_30_begin) != NULL)
+ {
+ return BTA_OP_FMT_VCARD30;
+ }
+ else
+ {
+ return BTA_OP_FMT_NONE;
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_OpBuildCard
+**
+** Description Build a vCard object. The input to this function is
+** requested format(2.1/3.0), an array of vCard properties
+** and a pointer to memory to store the card.
+** The output is a formatted vCard.
+**
+**
+** Returns BTA_OP_OK if operation successful.
+** BTA_OP_FAIL if invalid property data.
+** BTA_OP_MEM if not enough memory to complete build.
+**
+*******************************************************************************/
+tBTA_OP_STATUS BTA_OpBuildCard(UINT8 *p_card, UINT16 *p_len, tBTA_OP_FMT fmt,
+ tBTA_OP_PROP *p_prop, UINT8 num_prop)
+{
+ if(fmt == BTA_OP_VCARD21_FMT)
+ {
+ return bta_op_build_obj(&bta_op_vcard_21_bld, p_card, p_len, p_prop, num_prop);
+ }
+ else if(fmt == BTA_OP_VCARD30_FMT)
+ {
+ return bta_op_build_obj(&bta_op_vcard_30_bld, p_card, p_len, p_prop, num_prop);
+ }
+ else
+ {
+ *p_len = 0;
+ return BTA_OP_FAIL;
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_OpSetCardPropFilterMask
+**
+** Description Set Property Filter Mask
+**
+**
+** Returns
+**
+*******************************************************************************/
+void BTA_OpSetCardPropFilterMask(UINT32 mask)
+{
+ bta_op_set_prop_filter_mask(mask);
+ return;
+}
+
+/*******************************************************************************
+**
+** Function BTA_OpParseCard
+**
+** Description Parse a vCard 2.1 object. The input to this function is
+** a pointer to vCard data. The output is an array of parsed
+** vCard properties.
+**
+**
+** Returns BTA_OP_OK if operation successful.
+** BTA_OP_FAIL if invalid property data.
+** BTA_OP_MEM if not enough memory to complete parsing.
+**
+*******************************************************************************/
+tBTA_OP_STATUS BTA_OpParseCard(tBTA_OP_PROP *p_prop, UINT8 *p_num_prop,
+ UINT8 *p_card, UINT16 len)
+{
+ tBTA_OP_SUP_FMT fmt = bta_op_get_card_fmt(p_card, len);
+
+ if (fmt == BTA_OP_FMT_VCARD21)
+ {
+ return bta_op_parse_obj(&bta_op_vcard_21_prs, p_prop, p_num_prop, p_card, len);
+ }
+ else if(fmt == BTA_OP_FMT_VCARD30)
+ {
+ return bta_op_parse_obj(&bta_op_vcard_30_prs, p_prop, p_num_prop, p_card, len);
+ }
+ else
+ {
+ *p_num_prop = 0;
+ return BTA_OP_FAIL;
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_OpGetCardProperty
+**
+** Description Get Card property value by name. The input to this function is
+** property name. The output is property value and len
+**
+**
+** Returns BTA_OP_OK if operation successful.
+** BTA_OP_FAIL if invalid property data.
+**
+*******************************************************************************/
+tBTA_OP_STATUS BTA_OpGetCardProperty(UINT8 *p_value, UINT16 *p_len, tBTA_OP_PROP *p_prop,
+ UINT8 num_prop, UINT8 *p_name)
+{
+ return bta_op_get_property_by_name(bta_op_vcard_tbl, p_name,
+ p_prop, num_prop, p_value, p_len);
+}
+
+
diff --git a/bta/op/bta_op_vnote.c b/bta/op/bta_op_vnote.c
new file mode 100644
index 0000000..ff1c015
--- /dev/null
+++ b/bta/op/bta_op_vnote.c
@@ -0,0 +1,99 @@
+/*****************************************************************************
+**
+** Name: bta_op_vnote.c
+**
+** Description: This file contains functions for parsing and building
+** vNote objects.
+**
+** Copyright (c) 2003, Widcomm Inc., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bta_op_api.h"
+#include "bta_op_fmt.h"
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+#define BTA_OP_VNOTE_BEGIN_LEN 26
+#define BTA_OP_VNOTE_END_LEN 11
+
+#define BTA_OP_VNOTE_MIN_LEN (BTA_OP_VNOTE_BEGIN_LEN + BTA_OP_VNOTE_END_LEN)
+
+const char bta_op_vnote_prs_begin[] = "BEGIN:VNOTE\r\n";
+
+const char bta_op_vnote_begin[] = "BEGIN:VNOTE\r\nVERSION:1.1\r\n";
+
+const char bta_op_vnote_end[] = "END:VNOTE\r\n";
+
+const tBTA_OP_PROP_TBL bta_op_vnote_tbl[] =
+{
+ {NULL, NULL, 2}, /* Number of elements in array */
+ {"BODY", NULL, 7}, /* BTA_OP_VNOTE_BODY */
+ {"X-IRMC-LUID", NULL, 14} /* BTA_OP_VNOTE_LUID */
+};
+
+const tBTA_OP_OBJ_TBL bta_op_vnote_bld =
+{
+ bta_op_vnote_tbl,
+ BTA_OP_FMT_VNOTE11,
+ bta_op_vnote_begin,
+ bta_op_vnote_end,
+ BTA_OP_VNOTE_BEGIN_LEN,
+ BTA_OP_VNOTE_END_LEN,
+ BTA_OP_VNOTE_MIN_LEN
+};
+
+const tBTA_OP_OBJ_TBL bta_op_vnote_prs =
+{
+ bta_op_vnote_tbl,
+ BTA_OP_FMT_VNOTE11,
+ bta_op_vnote_prs_begin,
+ bta_op_vnote_end,
+ BTA_OP_VNOTE_BEGIN_LEN,
+ BTA_OP_VNOTE_END_LEN,
+ BTA_OP_VNOTE_MIN_LEN
+};
+
+/*******************************************************************************
+**
+** Function BTA_OpBuildNote
+**
+** Description Build a vNote object. The input to this function is an
+** array of vNote properties and a pointer to memory to store
+** the card. The output is a formatted vNote.
+**
+**
+** Returns BTA_OP_OK if operation successful.
+** BTA_OP_FAIL if invalid property data.
+** BTA_OP_MEM if not enough memory to complete build.
+**
+*******************************************************************************/
+tBTA_OP_STATUS BTA_OpBuildNote(UINT8 *p_note, UINT16 *p_len, tBTA_OP_PROP *p_prop,
+ UINT8 num_prop)
+{
+ return bta_op_build_obj(&bta_op_vnote_bld, p_note, p_len, p_prop, num_prop);
+}
+
+/*******************************************************************************
+**
+** Function BTA_OpParseNote
+**
+** Description Parse a vNote object. The input to this function is a
+** pointer to vNote data. The output is an array of parsed
+** vNote properties.
+**
+**
+** Returns BTA_OP_OK if operation successful.
+** BTA_OP_FAIL if invalid property data.
+** BTA_OP_MEM if not enough memory to complete parsing.
+**
+*******************************************************************************/
+tBTA_OP_STATUS BTA_OpParseNote(tBTA_OP_PROP *p_prop, UINT8 *p_num_prop, UINT8 *p_note,
+ UINT16 len)
+{
+ return bta_op_parse_obj(&bta_op_vnote_prs, p_prop, p_num_prop, p_note, len);
+}
+
diff --git a/bta/op/bta_opc_act.c b/bta/op/bta_opc_act.c
new file mode 100644
index 0000000..cf4780d
--- /dev/null
+++ b/bta/op/bta_opc_act.c
@@ -0,0 +1,1017 @@
+/*****************************************************************************
+**
+** Name: bta_opc_act.c
+**
+** Description: This file contains the file transfer action
+** functions for the state machine.
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include <string.h>
+#include "gki.h"
+#include "bta_sys.h"
+#include "bd.h"
+#include "port_api.h"
+#include "obx_api.h"
+#include "goep_util.h"
+#include "sdp_api.h"
+#include "bta_fs_api.h"
+#include "bta_op_api.h"
+#include "bta_opc_int.h"
+#include "bta_fs_co.h"
+#include "bta_fs_ci.h"
+#include "btm_api.h"
+#include "rfcdefs.h"
+#include "utl.h"
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+/* sdp discovery database size */
+#define BTA_OPC_DISC_SIZE 450
+
+
+/*****************************************************************************
+** Local Function prototypes
+*****************************************************************************/
+#if BTA_OPC_DEBUG == TRUE
+static char *opc_obx_evt_code(tOBX_EVENT evt_code);
+#endif
+
+static void bta_opc_sdp_cback(UINT16 status);
+
+
+/*****************************************************************************
+** Action Functions
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function bta_opc_enable
+**
+** Description Handle an api enable event. This function enables the OP
+** Client by opening an Obex/Rfcomm channel with a peer device.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_opc_enable(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data)
+{
+
+ /* store parameters */
+ p_cb->p_cback = p_data->api_enable.p_cback;
+ p_cb->sec_mask = p_data->api_enable.sec_mask;
+ p_cb->app_id = p_data->api_enable.app_id;
+ p_cb->srm = p_data->api_enable.srm;
+ p_cb->single_op = p_data->api_enable.single_op;
+ p_cb->fd = BTA_FS_INVALID_FD;
+
+ /* callback with enable event */
+ (*p_cb->p_cback)(BTA_OPC_ENABLE_EVT, NULL);
+}
+
+/*******************************************************************************
+**
+** Function bta_opc_init_push
+**
+** Description Push an object to the OPP server.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_opc_init_push(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data)
+{
+ p_cb->status = BTA_OPC_FAIL;
+ p_cb->exch_status = BTA_OPC_OK;
+
+ if ((p_cb->p_name = (char *)GKI_getbuf((UINT16)(p_bta_fs_cfg->max_path_len + 1))) != NULL)
+ {
+ p_cb->to_do = BTA_OPC_PUSH_MASK;
+ p_cb->format = p_data->api_push.format;
+ BCM_STRNCPY_S(p_cb->p_name, p_bta_fs_cfg->max_path_len+1, p_data->api_push.p_name, p_bta_fs_cfg->max_path_len);
+ p_cb->p_name[p_bta_fs_cfg->max_path_len] = '\0';
+ }
+ else
+ bta_opc_sm_execute(p_cb, BTA_OPC_OBX_CMPL_EVT, (tBTA_OPC_DATA *)NULL);
+}
+
+/*******************************************************************************
+**
+** Function bta_opc_init_pull
+**
+** Description Pull an object off the server.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_opc_init_pull(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data)
+{
+ p_cb->status = BTA_OPC_FAIL;
+ p_cb->exch_status = BTA_OPC_OK;
+
+ if ((p_cb->p_name = (char *)GKI_getbuf((UINT16)(p_bta_fs_cfg->max_file_len +
+ p_bta_fs_cfg->max_path_len + 2))) != NULL)
+ {
+ p_cb->p_rcv_path = p_cb->p_name + p_bta_fs_cfg->max_file_len + 1;
+ p_cb->to_do = BTA_OPC_PULL_MASK;
+ p_cb->first_get_pkt = TRUE;
+ BCM_STRNCPY_S(p_cb->p_rcv_path, p_bta_fs_cfg->max_path_len+1, p_data->api_pull.p_path, p_bta_fs_cfg->max_path_len);
+ p_cb->p_rcv_path[p_bta_fs_cfg->max_path_len] = '\0';
+ }
+ else
+ bta_opc_sm_execute(p_cb, BTA_OPC_OBX_CMPL_EVT, (tBTA_OPC_DATA *)NULL);
+}
+
+/*******************************************************************************
+**
+** Function bta_opc_init_exch
+**
+** Description Exchange business cards with a server.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_opc_init_exch(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data)
+{
+ p_cb->status = BTA_OPC_FAIL;
+ p_cb->exch_status = BTA_OPC_OK;
+
+ /* Need room to hold the receive path, along with path and file name to push */
+ if ((p_cb->p_name =
+ (char *)GKI_getbuf((UINT16)((p_bta_fs_cfg->max_path_len + 1) * 2))) != NULL)
+ {
+ p_cb->p_rcv_path = p_cb->p_name + p_bta_fs_cfg->max_path_len + 1;
+ p_cb->to_do = BTA_OPC_PULL_MASK | BTA_OPC_PUSH_MASK;
+ p_cb->first_get_pkt = TRUE;
+ BCM_STRNCPY_S(p_cb->p_name, p_bta_fs_cfg->max_path_len+1, p_data->api_exch.p_send, p_bta_fs_cfg->max_path_len);
+ p_cb->p_name[p_bta_fs_cfg->max_path_len] = '\0';
+ BCM_STRNCPY_S(p_cb->p_rcv_path, p_bta_fs_cfg->max_path_len+1, p_data->api_exch.p_rcv_path, p_bta_fs_cfg->max_path_len);
+ p_cb->p_rcv_path[p_bta_fs_cfg->max_path_len] = '\0';
+ }
+ else
+ bta_opc_sm_execute(p_cb, BTA_OPC_OBX_CMPL_EVT, (tBTA_OPC_DATA *)NULL);
+}
+
+/*******************************************************************************
+**
+** Function bta_opc_trans_cmpl
+**
+** Description push/pull complete
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_opc_trans_cmpl(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data)
+{
+ tBTA_OPC_OBJECT param;
+ tBTA_OPC_EVT evt = BTA_OPC_OBJECT_EVT;
+ tBTA_FS_CO_STATUS status;
+
+ if (p_data)
+ {
+ p_cb->status = bta_opc_convert_obx_to_opc_status(p_data->obx_evt.rsp_code);
+ }
+ else
+ {
+ /* some action functions send the event to SM with NULL p_data */
+ p_cb->status = BTA_OPC_FAIL;
+ }
+
+ if (p_cb->obx_oper == OPC_OP_PUSH_OBJ)
+ evt = BTA_OPC_OBJECT_PSHD_EVT;
+
+ /* rearrange the code a little bit to make sure p_cb->status is for the current op
+ * (previously, we might use the ststus from the PUSH op, if this is an exchange card) */
+ param.status = p_cb->status;
+
+ /* If exchange, and push received an error use this error */
+ if (p_cb->exch_status != BTA_OPC_OK)
+ param.status = p_cb->exch_status;
+
+ /* Notify appl the result of the pull or push */
+ param.p_name = p_cb->p_name;
+ p_cb->p_cback(evt, (tBTA_OPC *)&param);
+
+ /* Close any open files */
+ if (p_cb->fd >= 0)
+ {
+ bta_fs_co_close(p_cb->fd, p_cb->app_id);
+ p_cb->fd = BTA_FS_INVALID_FD;
+
+ /* Delete an aborted unfinished get vCard operation */
+ if (p_cb->obx_oper == OPC_OP_PULL_OBJ && p_cb->status != BTA_OPC_OK)
+ {
+ status = bta_fs_co_unlink(p_cb->p_name, p_cb->app_id);
+ APPL_TRACE_WARNING2("OPC: Remove ABORTED Get File Operation [%s], status 0x%02x",
+ p_cb->p_name, status);
+ }
+ }
+
+ utl_freebuf((void**)&p_cb->p_name);
+
+ p_cb->obx_oper = OPC_OP_NONE;
+
+}
+
+/*******************************************************************************
+**
+** Function bta_opc_ci_write
+**
+** Description Continue with the current write operation
+** (Get File processing)
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_opc_ci_write(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data)
+{
+ tBTA_OPC_OBX_PKT *p_obx = &p_cb->obx;
+ tBTA_OPC_PROGRESS param;
+ UINT8 rsp_code = OBX_RSP_FAILED;
+
+ p_cb->cout_active = FALSE;
+
+ /* Process write call-in event if operation is still active */
+ if (p_cb->obx_oper == OPC_OP_PULL_OBJ)
+ {
+ if (p_data->write_evt.status == BTA_FS_CO_OK)
+ {
+ param.bytes = p_obx->offset;
+ param.obj_size = p_cb->obj_size;
+ param.operation = BTA_OP_OPER_PULL;
+ p_cb->p_cback(BTA_OPC_PROGRESS_EVT, (tBTA_OPC *)&param);
+
+ /* Send another Get request if not finished */
+ if (!p_obx->final_pkt)
+ {
+ /* Free current packet and send a new request */
+ bta_opc_send_get_req(p_cb);
+ rsp_code = OBX_RSP_CONTINUE;
+ }
+ else
+ rsp_code = OBX_RSP_OK;
+ }
+
+ if (rsp_code != OBX_RSP_CONTINUE)
+ {
+ p_data->obx_evt.rsp_code = rsp_code;
+ bta_opc_sm_execute(p_cb, BTA_OPC_OBX_CMPL_EVT, p_data);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_opc_ci_read
+**
+** Description Handles the response to a read call-out request.
+** This is called within the OBX get object request. The
+** operation has completed, send the OBX packet out.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_opc_ci_read(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data)
+{
+ tBTA_OPC_OBX_PKT *p_obx = &p_cb->obx;
+ tBTA_FS_CI_READ_EVT *p_revt = &p_data->read_evt;
+ tBTA_OPC_PROGRESS param;
+ BOOLEAN is_final;
+
+ p_cb->cout_active = FALSE;
+
+ /* Process read call-in event if operation is still active */
+ if (p_cb->obx_oper == OPC_OP_PUSH_OBJ)
+ {
+ if (p_revt->status != BTA_FS_CO_OK && p_revt->status != BTA_FS_CO_EOF)
+ {
+ p_data->obx_evt.rsp_code = OBX_RSP_FAILED;
+/* if abort added to OPC use -> bta_opc_sm_execute(p_cb, BTA_OPC_OBX_CMPL_EVT, p_data); */
+ bta_opc_sm_execute(p_cb, BTA_OPC_API_CLOSE_EVT, p_data);
+ }
+ else
+ {
+ is_final = (p_revt->status == BTA_FS_CO_EOF) ? TRUE: FALSE;
+
+ /* Add the body header to the packet */
+ OBX_AddBodyEnd(p_obx->p_pkt, p_obx->p_start, p_revt->num_read, is_final);
+
+ p_cb->obx.bytes_left -= p_revt->num_read;
+ p_cb->obx.offset += p_revt->num_read;
+
+ /* Send out the data */
+ OBX_PutReq(p_cb->obx_handle, is_final, p_obx->p_pkt);
+ p_obx->p_pkt = NULL;
+ p_cb->req_pending = TRUE;
+
+ /* Give application the status */
+ param.bytes = p_revt->num_read;
+ param.obj_size = p_cb->obj_size;
+ param.operation = BTA_OP_OPER_PUSH;
+ p_cb->p_cback(BTA_OPC_PROGRESS_EVT, (tBTA_OPC *)&param);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_opc_ci_open
+**
+** Description Continue with the current file open operation
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_opc_ci_open(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data)
+{
+ tBTA_OPC_OBX_PKT *p_obx = &p_cb->obx;
+ tBTA_FS_CI_OPEN_EVT *p_open = &p_data->open_evt;
+ UINT8 rsp_code = OBX_RSP_FAILED;
+
+ p_cb->cout_active = FALSE;
+
+ /* if file is accessible read/write the first buffer of data */
+ if (p_open->status == BTA_FS_CO_OK)
+ {
+ p_cb->fd = p_open->fd;
+
+ if (p_cb->obx_oper == OPC_OP_PUSH_OBJ)
+ {
+ p_cb->obj_size = p_open->file_size;
+
+ rsp_code = bta_opc_send_put_req(p_cb, TRUE);
+ }
+ else if (p_cb->obx_oper == OPC_OP_PULL_OBJ)
+ {
+ rsp_code = OBX_RSP_OK;
+
+ /* Initiate the first OBX GET request */
+ p_obx->offset = 0;
+
+ /* Continue processing GET rsp */
+ bta_opc_cont_get_rsp(p_cb);
+ }
+ }
+ else
+ {
+ if (p_open->status == BTA_FS_CO_EACCES)
+ rsp_code = OBX_RSP_UNAUTHORIZED;
+ else /* File could not be found */
+ rsp_code = OBX_RSP_NOT_FOUND;
+ }
+
+ if (rsp_code != OBX_RSP_OK)
+ {
+ p_data->obx_evt.rsp_code = rsp_code;
+ bta_opc_sm_execute(p_cb, BTA_OPC_API_CLOSE_EVT, p_data);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_opc_obx_conn_rsp
+**
+** Description Process the OBX connect event.
+** If OPP service, get directory listing.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_opc_obx_conn_rsp(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data)
+{
+ tBTA_OPC_OBX_EVT *p_evt = &p_data->obx_evt;
+
+ /* Done with Obex packet */
+ utl_freebuf((void**)&p_evt->p_pkt);
+
+ p_cb->peer_mtu = p_data->obx_evt.param.conn.mtu;
+
+ /* inform role manager */
+ bta_sys_conn_open( BTA_ID_OPC ,p_cb->app_id, bta_opc_cb.bd_addr);
+
+ p_cb->p_cback(BTA_OPC_OPEN_EVT, NULL);
+
+ /* start the first operation. For card exchange PUSH is done first */
+ if(p_cb->to_do & BTA_OPC_PUSH_MASK)
+ bta_opc_start_push(p_cb);
+ else
+ bta_opc_send_get_req(p_cb);
+}
+
+/*******************************************************************************
+**
+** Function bta_opc_obx_put_rsp
+**
+** Description Process the OBX file put and delete file/folder events
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_opc_obx_put_rsp(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data)
+{
+ tBTA_OPC_OBX_EVT *p_evt = &p_data->obx_evt;
+ tBTA_OPC_OBJECT param;
+
+ p_cb->req_pending = FALSE;
+ APPL_TRACE_DEBUG1("bta_opc_obx_put_rsp to_do 0x%02x",p_cb->to_do);
+
+ /* Done with Obex packet */
+ utl_freebuf((void**)&p_evt->p_pkt);
+
+ if (p_cb->obx_oper == OPC_OP_PUSH_OBJ)
+ {
+ /* If not finished with Put, start another read */
+ if (p_evt->rsp_code == OBX_RSP_CONTINUE)
+ bta_opc_send_put_req(p_cb, FALSE);
+
+ /* Start the Pull if this is card exchange */
+ else if (p_cb->to_do & BTA_OPC_PULL_MASK)
+ {
+ /* Close the current file and initiate a pull vcard */
+ bta_fs_co_close(p_cb->fd, p_cb->app_id);
+ p_cb->fd = BTA_FS_INVALID_FD;
+
+ /* If error occurred during push save it */
+ if (p_evt->rsp_code != OBX_RSP_OK)
+ p_cb->exch_status = BTA_OPC_FAIL;
+
+ /* Notify application with status of push operation */
+ param.status = p_cb->exch_status;
+ param.p_name = p_cb->p_name;
+ p_cb->p_cback(BTA_OPC_OBJECT_PSHD_EVT, (tBTA_OPC *)&param);
+
+ /* Initiate the Pull operation */
+ bta_opc_send_get_req(p_cb);
+ }
+ else /* Finished or an error occurred */
+ {
+ p_data->obx_evt.rsp_code = p_evt->rsp_code;
+ bta_opc_sm_execute(p_cb, BTA_OPC_OBX_CMPL_EVT, p_data);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_opc_obx_get_rsp
+**
+** Description Process the OBX file get and folder listing events
+** If the type header is not folder listing, then pulling a file.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_opc_obx_get_rsp(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data)
+{
+ tBTA_OPC_OBX_EVT *p_evt = &p_data->obx_evt;
+ tBTA_OPC_OBX_PKT *p_obx = &p_cb->obx;
+ BOOLEAN free_pkt = FALSE;
+
+ p_obx->final_pkt = (p_evt->rsp_code == OBX_RSP_OK) ? TRUE : FALSE;
+ p_obx->p_pkt = p_evt->p_pkt;
+ p_obx->rsp_code = p_evt->rsp_code;
+ p_cb->req_pending = FALSE;
+
+ if (p_cb->obx_oper == OPC_OP_PULL_OBJ)
+ {
+ /* Open file for writing */
+ if (p_cb->first_get_pkt == TRUE)
+ {
+ p_cb->first_get_pkt = FALSE;
+ free_pkt = bta_opc_proc_get_rsp(p_cb, p_data);
+ }
+ else /* Continuation of the object transfer */
+ bta_opc_cont_get_rsp(p_cb);
+ }
+ else
+ free_pkt = TRUE;
+
+ if (free_pkt) /* Release the OBX response packet */
+ utl_freebuf((void**)&p_obx->p_pkt);
+}
+
+/*******************************************************************************
+**
+** Function bta_opc_initialize
+**
+** Description Initialize the control block.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_opc_initialize(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data)
+{
+ tBTA_FS_CO_STATUS status;
+
+ utl_freebuf((void**)&p_cb->obx.p_pkt);
+
+ /* Close any open files */
+ if (p_cb->fd >= 0)
+ {
+ bta_fs_co_close(p_cb->fd, p_cb->app_id);
+ p_cb->fd = BTA_FS_INVALID_FD;
+
+ /* Delete an aborted unfinished get vCard operation */
+ if (p_cb->obx_oper == OPC_OP_PULL_OBJ && p_cb->status != BTA_OPC_OK)
+ {
+ status = bta_fs_co_unlink(p_cb->p_name, p_cb->app_id);
+ APPL_TRACE_WARNING2("OPC: Remove ABORTED Get File Operation [%s], status 0x%02x",
+ p_cb->p_name, status);
+ }
+ }
+
+ utl_freebuf((void**)&p_cb->p_name);
+
+ /* Clean up control block */
+ p_cb->obx_oper = OPC_OP_NONE;
+ p_cb->req_pending = FALSE;
+ p_cb->sdp_pending = FALSE;
+ p_cb->to_do = 0;
+ p_cb->p_rcv_path = NULL;
+ p_cb->first_get_pkt = FALSE;
+
+ if (p_cb->disabling)
+ {
+ p_cb->disabling = FALSE;
+ bta_opc_sm_execute(p_cb, BTA_OPC_DISABLE_CMPL_EVT, NULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_opc_stop_client
+**
+** Description Stop OBX client.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_opc_stop_client(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data)
+{
+ if (!p_cb->sdp_pending)
+ {
+// btla-specific ++
+#if defined (BTA_OPC_SENDING_ABORT) && (BTA_OPC_SENDING_ABORT == TRUE)
+ APPL_TRACE_WARNING3("bta_opc_stop_client p_cb->req_pending = %d, p_cb->sdp_pending = %d,handle = %d",
+ p_cb->req_pending, p_cb->sdp_pending,p_cb->obx_handle);
+ /* Abort an active request */
+ if (p_cb->req_pending)
+ OBX_AbortReq(p_cb->obx_handle, (BT_HDR *)NULL);
+#endif
+// btla-specific --
+ /* do not free p_cb->obx.p_pkt here, just in case cout_active.
+ * bta_opc_close_complete would handle it */
+ OBX_DisconnectReq(p_cb->obx_handle, NULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_opc_close
+**
+** Description If not waiting for a call-in function, complete the closing
+** of the channel.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_opc_close(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data)
+{
+ /* finished if not waiting on a call-in function */
+ if (!p_cb->cout_active)
+ bta_opc_sm_execute(p_cb, BTA_OPC_CLOSE_CMPL_EVT, p_data);
+}
+
+/*******************************************************************************
+**
+** Function bta_opc_start_client
+**
+** Description Start an OPP operation.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_opc_start_client(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data)
+{
+ tBTA_OPC_OBX_PKT *p_obx = &p_cb->obx;
+ tOBX_STATUS status;
+ BOOLEAN srm = p_cb->srm;
+
+ /* Allocate an OBX packet */
+ if ((p_obx->p_pkt = (BT_HDR *)OBX_HdrInit(OBX_HANDLE_NULL, OBX_MAX_MTU)) != NULL)
+ {
+ status = OBX_AllocSession (NULL, p_data->sdp_ok.scn, &p_data->sdp_ok.psm,
+ bta_opc_obx_cback, &p_cb->obx_handle);
+
+ /* set security level */
+ if (p_data->sdp_ok.scn)
+ {
+ BTM_SetSecurityLevel (TRUE, "BTA_OPC", BTM_SEC_SERVICE_OBEX,
+ p_cb->sec_mask, BT_PSM_RFCOMM,
+ BTM_SEC_PROTO_RFCOMM, p_data->sdp_ok.scn);
+ srm = 0;
+ }
+ else
+ {
+ BTM_SetSecurityLevel (TRUE, "BTA_OPC", BTM_SEC_SERVICE_OBEX,
+ p_cb->sec_mask, p_data->sdp_ok.psm, 0, 0);
+ }
+
+ if (status == OBX_SUCCESS)
+ {
+ OBX_CreateSession (p_cb->bd_addr, OBX_MAX_MTU, srm, 0,
+ p_cb->obx_handle, p_obx->p_pkt);
+ p_obx->p_pkt = NULL; /* OBX will free the memory */
+ return;
+ }
+ }
+ else
+ {
+ p_data->obx_evt.rsp_code = OBX_RSP_FAILED;
+ bta_opc_sm_execute(p_cb, BTA_OPC_CLOSE_CMPL_EVT, p_data);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_opc_free_db
+**
+** Description Free buffer used for service discovery database.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_opc_free_db(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data)
+{
+ utl_freebuf((void**)&p_cb->p_db);
+ p_cb->sdp_pending = FALSE;
+}
+
+/*******************************************************************************
+**
+** Function bta_opc_ignore_obx
+**
+** Description Free OBX packet for ignored OBX events.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_opc_ignore_obx(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data)
+{
+ utl_freebuf((void**)&p_data->obx_evt.p_pkt);
+}
+
+/*******************************************************************************
+**
+** Function bta_opc_find_service
+**
+** Description Perform service discovery to find the OPP service on the
+** peer device.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_opc_find_service(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data)
+{
+ tSDP_UUID uuid_list;
+ UINT16 attr_list[3];
+
+ if (!p_cb->to_do)
+ return;
+
+ bdcpy(p_cb->bd_addr, p_data->api_push.bd_addr);
+ if ((p_cb->p_db = (tSDP_DISCOVERY_DB *) GKI_getbuf(BTA_OPC_DISC_SIZE)) != NULL)
+ {
+ attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST;
+ attr_list[1] = ATTR_ID_PROTOCOL_DESC_LIST;
+ attr_list[2] = ATTR_ID_OBX_OVR_L2CAP_PSM;
+
+ uuid_list.len = LEN_UUID_16;
+ uuid_list.uu.uuid16 = UUID_SERVCLASS_OBEX_OBJECT_PUSH;
+ p_cb->sdp_pending = TRUE;
+ SDP_InitDiscoveryDb(p_cb->p_db, BTA_OPC_DISC_SIZE, 1, &uuid_list, 3, attr_list);
+ if(!SDP_ServiceSearchAttributeRequest(p_cb->bd_addr, p_cb->p_db, bta_opc_sdp_cback))
+ {
+ bta_opc_sm_execute(p_cb, BTA_OPC_SDP_FAIL_EVT, (tBTA_OPC_DATA *)NULL);
+ }
+ }
+ else
+ bta_opc_sm_execute(p_cb, BTA_OPC_OBX_CMPL_EVT, (tBTA_OPC_DATA *)NULL);
+}
+
+/*******************************************************************************
+**
+** Function bta_opc_close_complete
+**
+** Description Finishes the memory cleanup after a channel is closed.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_opc_close_complete(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data)
+{
+ p_cb->cout_active = FALSE;
+ bta_opc_initialize(p_cb, p_data);
+
+ /* inform role manager */
+ bta_sys_conn_close( BTA_ID_OPC ,p_cb->app_id, bta_opc_cb.bd_addr);
+
+ p_cb->p_cback(BTA_OPC_CLOSE_EVT, (tBTA_OPC *)&p_cb->status);
+}
+
+/*******************************************************************************
+**
+** Function bta_opc_set_disable
+**
+** Description Sets flag to disable.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_opc_set_disable(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data)
+{
+ p_cb->disabling = TRUE;
+}
+
+/*******************************************************************************
+**
+** Function bta_opc_chk_close
+**
+** Description Check if we need to stop the client now.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_opc_chk_close(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data)
+{
+ if (p_cb->single_op)
+ {
+ bta_opc_sm_execute(p_cb, BTA_OPC_API_CLOSE_EVT, (tBTA_OPC_DATA *)NULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_opc_do_pull
+**
+** Description
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_opc_do_pull(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data)
+{
+ APPL_TRACE_DEBUG1("bta_opc_do_pull to_do 0x%02x",p_cb->to_do);
+ bta_opc_send_get_req(p_cb);
+}
+
+/*******************************************************************************
+**
+** Function bta_opc_do_push
+**
+** Description
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_opc_do_push(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data)
+{
+ APPL_TRACE_DEBUG1("bta_opc_do_push to_do 0x%02x",p_cb->to_do);
+ bta_opc_start_push(p_cb);
+}
+
+/*****************************************************************************
+** Callback Functions
+*****************************************************************************/
+/*******************************************************************************
+**
+** Function bta_opc_obx_cback
+**
+** Description OBX callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_opc_obx_cback (tOBX_HANDLE handle, tOBX_EVENT obx_event, UINT8 rsp_code,
+ tOBX_EVT_PARAM param, BT_HDR *p_pkt)
+{
+ tBTA_OPC_OBX_EVT *p_obx_msg;
+ UINT16 event = 0;
+
+#if BTA_OPC_DEBUG == TRUE
+ APPL_TRACE_DEBUG1("OBX Event Callback: obx_event [%s]", opc_obx_evt_code(obx_event));
+#endif
+
+ switch(obx_event)
+ {
+ case OBX_CONNECT_RSP_EVT:
+ if (rsp_code == OBX_RSP_OK)
+ {
+ event = BTA_OPC_OBX_CONN_RSP_EVT;
+ }
+ else /* Obex will disconnect underneath BTA */
+ {
+ APPL_TRACE_WARNING1("OPC_CBACK: Bad connect response 0x%02x", rsp_code);
+ if (p_pkt)
+ GKI_freebuf(p_pkt);
+ return;
+ }
+ break;
+ case OBX_PUT_RSP_EVT:
+ event = BTA_OPC_OBX_PUT_RSP_EVT;
+ break;
+ case OBX_GET_RSP_EVT:
+ event = BTA_OPC_OBX_GET_RSP_EVT;
+ break;
+ case OBX_CLOSE_IND_EVT:
+ event = BTA_OPC_OBX_CLOSE_EVT;
+ break;
+ case OBX_PASSWORD_EVT:
+ event = BTA_OPC_OBX_PASSWORD_EVT;
+ break;
+
+ default:
+/* case OBX_ABORT_RSP_EVT: */
+/* case OBX_DISCONNECT_RSP_EVT: Handled when OBX_CLOSE_IND_EVT arrives */
+ if (p_pkt)
+ GKI_freebuf(p_pkt);
+ return;
+ }
+
+ /* send event to BTA, if any */
+ if ((p_obx_msg = (tBTA_OPC_OBX_EVT *) GKI_getbuf(sizeof(tBTA_OPC_OBX_EVT))) != NULL)
+ {
+ p_obx_msg->hdr.event = event;
+ p_obx_msg->obx_event = obx_event;
+ p_obx_msg->handle = handle;
+ p_obx_msg->rsp_code = rsp_code;
+ p_obx_msg->param = param;
+ p_obx_msg->p_pkt = p_pkt;
+
+ bta_sys_sendmsg(p_obx_msg);
+ }
+}
+
+/******************************************************************************
+**
+** Function bta_opc_sdp_cback
+**
+** Description This is the SDP callback function used by OPC.
+** This function will be executed by SDP when the service
+** search is completed. If the search is successful, it
+** finds the first record in the database that matches the
+** UUID of the search. Then retrieves the scn from the
+** record.
+**
+** Returns Nothing.
+**
+******************************************************************************/
+static void bta_opc_sdp_cback(UINT16 status)
+{
+ tBTA_OPC_SDP_OK_EVT *p_buf;
+ tSDP_DISC_REC *p_rec = NULL;
+ tSDP_PROTOCOL_ELEM pe;
+ UINT8 scn = 0;
+ BOOLEAN found = FALSE;
+ UINT16 version = GOEP_LEGACY_VERSION;
+ UINT16 psm = 0;
+ tSDP_DISC_ATTR *p_attr;
+
+ APPL_TRACE_DEBUG1("bta_opc_sdp_cback status:%d", status);
+
+ if ( (status == SDP_SUCCESS) || (status == SDP_DB_FULL) )
+ {
+ status = SDP_SUCCESS;
+ /* loop through all records we found */
+ do
+ {
+ /* get next record; if none found, we're done */
+ if ((p_rec = SDP_FindServiceInDb(bta_opc_cb.p_db,
+ UUID_SERVCLASS_OBEX_OBJECT_PUSH, p_rec)) == NULL)
+ break;
+
+ /* this is an optional attribute */
+ SDP_FindProfileVersionInRec (p_rec, UUID_SERVCLASS_OBEX_OBJECT_PUSH, &version);
+
+ /* get psm from proto desc list alternative; if not found, go to next record */
+ if ((p_attr = SDP_FindAttributeInRec(p_rec,
+ ATTR_ID_OBX_OVR_L2CAP_PSM)) != NULL)
+ {
+ psm = p_attr->attr_value.v.u16;
+ if ((SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == 2) && L2C_IS_VALID_PSM(psm))
+ {
+ found = TRUE;
+ if (version == GOEP_LEGACY_VERSION)
+ {
+ APPL_TRACE_ERROR0("Lacking mandatory attribute/version");
+ version = GOEP_ENHANCED_VERSION;
+ }
+ break;
+ }
+ }
+
+ /* If no OBEX over L2CAP look for RFCOMM SCN */
+ if (!found)
+ {
+ /* get scn from proto desc list; if not found, go to next record */
+ if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe))
+ {
+ scn = (UINT8) pe.params[0];
+
+ /* we've got everything, we're done */
+ found = TRUE;
+ break;
+ }
+ else
+ {
+ continue;
+ }
+ }
+ } while (TRUE);
+ }
+
+ /* send result in event back to BTA */
+ if ((p_buf = (tBTA_OPC_SDP_OK_EVT *) GKI_getbuf(sizeof(tBTA_OPC_SDP_OK_EVT))) != NULL)
+ {
+ if ((status == SDP_SUCCESS) && (found == TRUE))
+ {
+ p_buf->hdr.event = BTA_OPC_SDP_OK_EVT;
+ p_buf->scn = scn;
+ p_buf->psm = psm;
+ p_buf->version = version;
+ }
+ else
+ p_buf->hdr.event = BTA_OPC_SDP_FAIL_EVT;
+
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*****************************************************************************
+** Local OPP Event Processing Functions
+*****************************************************************************/
+
+/*****************************************************************************
+** Debug Functions
+*****************************************************************************/
+#if BTA_OPC_DEBUG == TRUE
+
+/*******************************************************************************
+**
+** Function opc_obx_evt_code
+**
+** Description
+**
+** Returns void
+**
+*******************************************************************************/
+static char *opc_obx_evt_code(tOBX_EVENT evt_code)
+{
+ switch(evt_code)
+ {
+ case OBX_CONNECT_RSP_EVT:
+ return "OBX_CONNECT_RSP_EVT";
+ case OBX_DISCONNECT_RSP_EVT:
+ return "OBX_DISCONNECT_RSP_EVT";
+ case OBX_PUT_RSP_EVT:
+ return "OBX_PUT_RSP_EVT";
+ case OBX_GET_RSP_EVT:
+ return "OBX_GET_RSP_EVT";
+ case OBX_SETPATH_RSP_EVT:
+ return "OBX_SETPATH_RSP_EVT";
+ case OBX_ABORT_RSP_EVT:
+ return "OBX_ABORT_RSP_EVT";
+ case OBX_CLOSE_IND_EVT:
+ return "OBX_CLOSE_IND_EVT";
+ case OBX_TIMEOUT_EVT:
+ return "OBX_TIMEOUT_EVT";
+ case OBX_PASSWORD_EVT:
+ return "OBX_PASSWORD_EVT";
+ default:
+ return "unknown OBX event code";
+ }
+}
+#endif /* Debug Functions */
diff --git a/bta/op/bta_opc_api.c b/bta/op/bta_opc_api.c
new file mode 100644
index 0000000..4440b1c
--- /dev/null
+++ b/bta/op/bta_opc_api.c
@@ -0,0 +1,214 @@
+/*****************************************************************************
+**
+** Name: bta_opc_api.c
+**
+** Description: This is the implementation of the API for the object
+** push client subsystem of BTA, Widcomm's Bluetooth
+** application layer for mobile phones.
+**
+** Copyright (c) 2003 - 2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include <string.h>
+#include "gki.h"
+#include "bta_sys.h"
+#include "bta_fs_api.h"
+#include "bta_op_api.h"
+#include "bta_opc_int.h"
+#include "bd.h"
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+static const tBTA_SYS_REG bta_opc_reg =
+{
+ bta_opc_hdl_event,
+ BTA_OpcDisable
+};
+
+/*******************************************************************************
+**
+** Function BTA_OpcEnable
+**
+** Description Enable the object push client. This function must be
+** called before any other functions in the DG API are called.
+** When the enable operation is complete the callback function
+** will be called with a BTA_OPC_ENABLE_EVT.
+**
+** If single_op is FALSE, the connection stays open after
+** the operation finishes (until BTA_OpcClose is called).
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_OpcEnable(tBTA_SEC sec_mask, tBTA_OPC_CBACK *p_cback,
+ BOOLEAN single_op, BOOLEAN srm, UINT8 app_id)
+{
+ tBTA_OPC_API_ENABLE *p_buf;
+
+ /* register with BTA system manager */
+ GKI_sched_lock();
+ bta_sys_register(BTA_ID_OPC, &bta_opc_reg);
+ GKI_sched_unlock();
+
+ /* initialize control block */
+ memset(&bta_opc_cb, 0, sizeof(tBTA_OPC_CB));
+
+ if ((p_buf = (tBTA_OPC_API_ENABLE *) GKI_getbuf(sizeof(tBTA_OPC_API_ENABLE))) != NULL)
+ {
+ p_buf->hdr.event = BTA_OPC_API_ENABLE_EVT;
+ p_buf->p_cback = p_cback;
+ p_buf->sec_mask = sec_mask;
+ p_buf->single_op = single_op;
+ p_buf->srm = srm;
+ p_buf->app_id = app_id;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_OpcDisable
+**
+** Description Disable the object push client. If the client is currently
+** connected to a peer device the connection will be closed.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_OpcDisable(void)
+{
+ BT_HDR *p_buf;
+
+ bta_sys_deregister(BTA_ID_OPC);
+ if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->event = BTA_OPC_API_DISABLE_EVT;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_OpcPush
+**
+** Description Push an object to a peer device. p_name must point to
+** a fully qualified path and file name.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_OpcPush(BD_ADDR bd_addr, tBTA_OP_FMT format, char *p_name)
+{
+ tBTA_OPC_DATA *p_msg;
+
+ if ((p_msg = (tBTA_OPC_DATA *)GKI_getbuf((UINT16)(sizeof(tBTA_OPC_DATA) +
+ p_bta_fs_cfg->max_path_len + 1))) != NULL)
+ {
+ p_msg->api_push.p_name = (char *)(p_msg + 1);
+ BCM_STRNCPY_S(p_msg->api_push.p_name, p_bta_fs_cfg->max_path_len+1, p_name, p_bta_fs_cfg->max_path_len);
+ p_msg->api_push.p_name[p_bta_fs_cfg->max_path_len] = '\0';
+ p_msg->hdr.event = BTA_OPC_API_PUSH_EVT;
+ bdcpy(p_msg->api_push.bd_addr, bd_addr);
+ p_msg->api_push.format = format;
+ bta_sys_sendmsg(p_msg);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_OpcPullCard
+**
+** Description Pull default card from peer. p_path must point to a fully
+** qualified path specifying where to store the pulled card.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_OpcPullCard(BD_ADDR bd_addr, char *p_path)
+{
+ tBTA_OPC_DATA *p_msg;
+ tBTA_OPC_API_PULL *p_pull;
+
+ if ((p_msg = (tBTA_OPC_DATA *)GKI_getbuf((UINT16)(sizeof(tBTA_OPC_DATA) +
+ (p_bta_fs_cfg->max_path_len + 1)))) != NULL)
+ {
+ p_pull = &p_msg->api_pull;
+ p_pull->p_path = (char *)(p_msg + 1);
+ BCM_STRNCPY_S(p_pull->p_path, p_bta_fs_cfg->max_path_len+1, p_path, p_bta_fs_cfg->max_path_len);
+ p_pull->p_path[p_bta_fs_cfg->max_path_len] = '\0';
+ bdcpy(p_pull->bd_addr, bd_addr);
+ p_pull->hdr.event = BTA_OPC_API_PULL_EVT;
+ bta_sys_sendmsg(p_msg);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_OpcExchCard
+**
+** Description Exchange business cards with a peer device. p_send points to
+** a fully qualified path and file name of vcard to push.
+** p_recv_path points to a fully qualified path specifying
+** where to store the pulled card.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_OpcExchCard(BD_ADDR bd_addr, char *p_send, char *p_recv_path)
+{
+ tBTA_OPC_DATA *p_msg;
+ tBTA_OPC_API_EXCH *p_exch;
+
+ if(!p_send || !p_recv_path)
+ return;
+
+ if ((p_msg = (tBTA_OPC_DATA *)GKI_getbuf((UINT16)(sizeof(tBTA_OPC_DATA) +
+ (p_bta_fs_cfg->max_path_len + 1) * 2))) != NULL)
+ {
+ p_exch = &p_msg->api_exch;
+ p_exch->p_send = (char *)(p_msg + 1);
+ p_exch->p_rcv_path = (char *)(p_exch->p_send + p_bta_fs_cfg->max_path_len + 1);
+ BCM_STRNCPY_S(p_exch->p_send, p_bta_fs_cfg->max_path_len+1, p_send, p_bta_fs_cfg->max_path_len);
+ p_exch->p_send[p_bta_fs_cfg->max_path_len] = '\0';
+ BCM_STRNCPY_S(p_exch->p_rcv_path, p_bta_fs_cfg->max_path_len+1, p_recv_path, p_bta_fs_cfg->max_path_len);
+ p_exch->p_rcv_path[p_bta_fs_cfg->max_path_len] = '\0';
+ bdcpy(p_exch->bd_addr, bd_addr);
+ p_exch->hdr.event = BTA_OPC_API_EXCH_EVT;
+ bta_sys_sendmsg(p_msg);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_OpcClose
+**
+** Description Close the current connection. This function is called if
+** the phone wishes to close the connection before the object
+** push is completed. In a typical connection this function
+** does not need to be called; the connection will be closed
+** automatically when the object push is complete.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_OpcClose(void)
+{
+ BT_HDR *p_buf;
+
+ if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->event = BTA_OPC_API_CLOSE_EVT;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+
diff --git a/bta/op/bta_opc_int.h b/bta/op/bta_opc_int.h
new file mode 100644
index 0000000..e26d2b5
--- /dev/null
+++ b/bta/op/bta_opc_int.h
@@ -0,0 +1,257 @@
+/*****************************************************************************
+**
+** Name: bta_opc_int.h
+**
+** Description: This is the private header file for the Object Push
+** Client (OPC).
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_OPC_INT_H
+#define BTA_OPC_INT_H
+
+#include "bt_target.h"
+#include "bta_sys.h"
+#include "obx_api.h"
+#include "bta_op_api.h"
+#include "bta_fs_co.h"
+#include "bta_fs_ci.h"
+
+/*****************************************************************************
+** Constants and data types
+*****************************************************************************/
+
+
+#define OPC_DEF_NAME "default_opc.vcf"
+
+/* if the pulled vCard does not have a Name Header associated with it,
+ * this is the default name used to received the file.
+ * Please make sure that this is of different file name than the local
+ * default vCard file name */
+#ifndef OPC_DEF_RCV_NAME
+#define OPC_DEF_RCV_NAME "opc_def_rcv.vcf"
+#endif
+
+/* OPC Active opp obex operation (Valid in connected state) */
+#define OPC_OP_NONE 0
+#define OPC_OP_PULL_OBJ 1
+#define OPC_OP_PUSH_OBJ 2
+
+/* Constants used for "to_do" list */
+#define BTA_OPC_PUSH_MASK 0x01
+#define BTA_OPC_PULL_MASK 0x02
+
+/* state machine events */
+enum
+{
+ /* these events are handled by the state machine */
+ BTA_OPC_API_ENABLE_EVT = BTA_SYS_EVT_START(BTA_ID_OPC),
+ BTA_OPC_API_DISABLE_EVT,
+ BTA_OPC_API_CLOSE_EVT, /* Close connection event */
+ BTA_OPC_API_PUSH_EVT, /* Push Object request */
+ BTA_OPC_API_PULL_EVT, /* Pull Object request */
+ BTA_OPC_API_EXCH_EVT, /* Exchange business Cards */
+ BTA_OPC_SDP_OK_EVT, /* Service search was successful */
+ BTA_OPC_SDP_FAIL_EVT, /* Service search failed */
+ BTA_OPC_CI_WRITE_EVT, /* Call-in response to Write request */
+ BTA_OPC_CI_READ_EVT, /* Call-in response to Read request */
+ BTA_OPC_CI_OPEN_EVT, /* Call-in response to File Open request */
+ BTA_OPC_OBX_CONN_RSP_EVT, /* OBX Channel Connect Request */
+ BTA_OPC_OBX_PASSWORD_EVT, /* OBX password requested */
+ BTA_OPC_OBX_CLOSE_EVT, /* OBX Channel Disconnected (Link Lost) */
+ BTA_OPC_OBX_PUT_RSP_EVT, /* Write file data or delete */
+ BTA_OPC_OBX_GET_RSP_EVT, /* Read file data or folder listing */
+ BTA_OPC_OBX_CMPL_EVT, /* operation has completed */
+ BTA_OPC_CLOSE_CMPL_EVT, /* Finish the closing of the channel */
+ BTA_OPC_DISABLE_CMPL_EVT /* Transition to disabled state */
+};
+
+typedef UINT16 tBTA_OPC_INT_EVT;
+
+typedef UINT8 tBTA_OPC_STATE;
+
+/* data type for BTA_OPC_API_ENABLE_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_OPC_CBACK *p_cback;
+ UINT8 sec_mask;
+ BOOLEAN single_op;
+ BOOLEAN srm;
+ UINT8 app_id;
+} tBTA_OPC_API_ENABLE;
+
+/* data type for BTA_OPC_API_PUSH_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+ char *p_name;
+ tBTA_OP_FMT format;
+} tBTA_OPC_API_PUSH;
+
+/* data type for BTA_OPC_API_PULL_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+ char *p_path;
+} tBTA_OPC_API_PULL;
+
+/* data type for BTA_OPC_API_EXCH_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+ char *p_send;
+ char *p_rcv_path;
+} tBTA_OPC_API_EXCH;
+
+/* data type for BTA_OPC_SDP_OK_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ UINT8 scn;
+ UINT16 psm;
+ UINT16 version;
+} tBTA_OPC_SDP_OK_EVT;
+
+/* data type for all obex events
+ hdr.event contains the OPC event
+*/
+typedef struct
+{
+ BT_HDR hdr;
+ tOBX_HANDLE handle;
+ tOBX_EVT_PARAM param;
+ BT_HDR *p_pkt;
+ tOBX_EVENT obx_event;
+ UINT8 rsp_code;
+} tBTA_OPC_OBX_EVT;
+
+/* union of all event data types */
+typedef union
+{
+ BT_HDR hdr;
+ tBTA_OPC_API_ENABLE api_enable;
+ tBTA_OPC_API_PUSH api_push;
+ tBTA_OPC_API_PULL api_pull;
+ tBTA_OPC_API_EXCH api_exch;
+ tBTA_OPC_SDP_OK_EVT sdp_ok;
+ tBTA_OPC_OBX_EVT obx_evt;
+ tBTA_FS_CI_OPEN_EVT open_evt;
+ tBTA_FS_CI_READ_EVT read_evt;
+ tBTA_FS_CI_WRITE_EVT write_evt;
+} tBTA_OPC_DATA;
+
+
+/* OBX Response Packet Structure - Holds current command/response packet info */
+typedef struct
+{
+ BT_HDR *p_pkt; /* (Get/Put) Holds the current OBX header for Put or Get */
+ UINT8 *p_start; /* (Get/Put) Start of the Body of the packet */
+ UINT16 offset; /* (Get/Put) Contains the current offset into the Body (p_start) */
+ UINT16 bytes_left; /* (Get/Put) Holds bytes available leop in Obx packet */
+ BOOLEAN final_pkt; /* (Get) Holds the final bit of the Put packet */
+ UINT8 rsp_code;
+} tBTA_OPC_OBX_PKT;
+
+/* Power management state for OPC */
+#define BTA_OPC_PM_BUSY 0
+#define BTA_OPC_PM_IDLE 1
+
+/* OPC control block */
+typedef struct
+{
+ tBTA_OPC_CBACK *p_cback; /* pointer to application callback function */
+ char *p_name; /* Holds the local path and file name of pushed item */
+ char *p_rcv_path; /* Holds the local path and file name of received item (card exch only) */
+ tSDP_DISCOVERY_DB *p_db; /* pointer to discovery database */
+ tBTA_OPC_OBX_PKT obx; /* Holds the current OBX packet information */
+ int fd; /* File Descriptor of opened file */
+ UINT32 obj_size; /* (Push/Pull) file length */
+ tOBX_HANDLE obx_handle;
+ UINT16 peer_mtu;
+ BD_ADDR bd_addr;
+ BOOLEAN single_op; /* if TRUE, close OBX connection when OP finishes */
+ UINT8 sec_mask;
+ tBTA_OPC_STATE state; /* state machine state */
+ tBTA_OP_FMT format;
+ UINT8 obx_oper; /* current active OBX operation PUT FILE or GET FILE */
+ UINT8 to_do; /* actions to be done (push,pull) */
+ UINT8 app_id;
+ tBTA_OPC_STATUS status;
+ tBTA_OPC_STATUS exch_status;
+ BOOLEAN first_get_pkt; /* TRUE if retrieving the first packet of GET object */
+ BOOLEAN cout_active; /* TRUE if call-out is currently active */
+ BOOLEAN req_pending; /* TRUE if an obx request to peer is in progress */
+ BOOLEAN disabling; /* TRUE if an disabling client */
+ BOOLEAN sdp_pending; /* TRUE when waiting for SDP to complete */
+ BOOLEAN srm; /* TRUE, to use SIngle Response Mode */
+ UINT8 pm_state;
+} tBTA_OPC_CB;
+
+/*****************************************************************************
+** Global data
+*****************************************************************************/
+
+/* OPC control block */
+#if BTA_DYNAMIC_MEMORY == FALSE
+extern tBTA_OPC_CB bta_opc_cb;
+#else
+extern tBTA_OPC_CB *bta_opc_cb_ptr;
+#define bta_opc_cb (*bta_opc_cb_ptr)
+#endif
+
+
+/*****************************************************************************
+** Function prototypes
+*****************************************************************************/
+
+extern BOOLEAN bta_opc_hdl_event(BT_HDR *p_msg);
+extern void bta_opc_sm_execute(tBTA_OPC_CB *p_cb, UINT16 event,
+ tBTA_OPC_DATA *p_data);
+extern void bta_opc_obx_cback (tOBX_HANDLE handle, tOBX_EVENT event,
+ UINT8 rsp_code, tOBX_EVT_PARAM param,
+ BT_HDR *p_pkt);
+
+/* action functions */
+extern void bta_opc_init_close(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data);
+extern void bta_opc_init_push(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data);
+extern void bta_opc_init_pull(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data);
+extern void bta_opc_init_exch(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data);
+extern void bta_opc_send_authrsp(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data);
+extern void bta_opc_ci_write(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data);
+extern void bta_opc_ci_read(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data);
+extern void bta_opc_ci_open(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data);
+extern void bta_opc_obx_conn_rsp(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data);
+extern void bta_opc_obx_put_rsp(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data);
+extern void bta_opc_obx_get_rsp(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data);
+extern void bta_opc_initialize(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data);
+extern void bta_opc_trans_cmpl(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data);
+extern void bta_opc_stop_client(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data);
+extern void bta_opc_start_client(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data);
+extern void bta_opc_free_db(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data);
+extern void bta_opc_ignore_obx(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data);
+extern void bta_opc_find_service(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data);
+extern void bta_opc_close(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data);
+extern void bta_opc_close_complete(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data);
+extern void bta_opc_set_disable(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data);
+extern void bta_opc_chk_close(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data);
+extern void bta_opc_do_pull(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data);
+extern void bta_opc_do_push(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data);
+extern void bta_opc_enable(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data);
+
+/* miscellaneous functions */
+extern UINT8 bta_opc_send_get_req(tBTA_OPC_CB *p_cb);
+extern BOOLEAN bta_opc_proc_get_rsp(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data);
+extern void bta_opc_cont_get_rsp(tBTA_OPC_CB *p_cb);
+extern UINT8 bta_opc_send_put_req(tBTA_OPC_CB *p_cb, BOOLEAN first_pkt);
+extern void bta_opc_start_push(tBTA_OPC_CB *p_cb);
+extern void bta_opc_listing_err(BT_HDR **p_pkt, tBTA_OPC_STATUS status);
+
+extern tBTA_OPC_STATUS bta_opc_convert_obx_to_opc_status(tOBX_STATUS obx_status);
+
+#endif /* BTA_OPC_INT_H */
diff --git a/bta/op/bta_opc_main.c b/bta/op/bta_opc_main.c
new file mode 100644
index 0000000..cf76143
--- /dev/null
+++ b/bta/op/bta_opc_main.c
@@ -0,0 +1,425 @@
+/*****************************************************************************
+**
+** Name: bta_opc_main.c
+**
+** Description: This file contains the file transfer client main functions
+** and state machine.
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include <string.h>
+
+#include "bta_opc_int.h"
+
+/*****************************************************************************
+** Constants and types
+*****************************************************************************/
+
+/* state machine states */
+enum
+{
+ BTA_OPC_DISABLED_ST = 0, /* Disabled */
+ BTA_OPC_IDLE_ST, /* Idle */
+ BTA_OPC_W4_CONN_ST, /* Waiting for an Obex connect response */
+ BTA_OPC_CONN_ST, /* Connected - OPP Session is active */
+ BTA_OPC_CLOSING_ST /* Closing is in progress */
+};
+
+/* state machine action enumeration list */
+enum
+{
+ BTA_OPC_START_CLIENT,
+ BTA_OPC_STOP_CLIENT,
+ BTA_OPC_INIT_PULL,
+ BTA_OPC_INIT_PUSH,
+ BTA_OPC_INIT_EXCH,
+ BTA_OPC_CI_WRITE,
+ BTA_OPC_CI_READ,
+ BTA_OPC_CI_OPEN,
+ BTA_OPC_OBX_CONN_RSP,
+ BTA_OPC_CLOSE,
+ BTA_OPC_OBX_PUT_RSP,
+ BTA_OPC_OBX_GET_RSP,
+ BTA_OPC_TRANS_CMPL,
+ BTA_OPC_FREE_DB,
+ BTA_OPC_IGNORE_OBX,
+ BTA_OPC_FIND_SERVICE,
+ BTA_OPC_INITIALIZE,
+ BTA_OPC_CLOSE_COMPLETE,
+ BTA_OPC_SET_DISABLE,
+ BTA_OPC_CHK_CLOSE,
+ BTA_OPC_DO_PUSH,
+ BTA_OPC_DO_PULL,
+ BTA_OPC_ENABLE,
+ BTA_OPC_IGNORE
+};
+
+/* type for action functions */
+typedef void (*tBTA_OPC_ACTION)(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data);
+
+/* action function list */
+const tBTA_OPC_ACTION bta_opc_action[] =
+{
+ bta_opc_start_client,
+ bta_opc_stop_client,
+ bta_opc_init_pull,
+ bta_opc_init_push,
+ bta_opc_init_exch,
+ bta_opc_ci_write,
+ bta_opc_ci_read,
+ bta_opc_ci_open,
+ bta_opc_obx_conn_rsp,
+ bta_opc_close,
+ bta_opc_obx_put_rsp,
+ bta_opc_obx_get_rsp,
+ bta_opc_trans_cmpl,
+ bta_opc_free_db,
+ bta_opc_ignore_obx,
+ bta_opc_find_service,
+ bta_opc_initialize,
+ bta_opc_close_complete,
+ bta_opc_set_disable,
+ bta_opc_chk_close,
+ bta_opc_do_push,
+ bta_opc_do_pull,
+ bta_opc_enable
+};
+
+
+/* state table information */
+#define BTA_OPC_ACTIONS 2 /* number of actions */
+#define BTA_OPC_NEXT_STATE 2 /* position of next state */
+#define BTA_OPC_NUM_COLS 3 /* number of columns in state tables */
+
+/* state table for disabled state (enable is handled*/
+static const UINT8 bta_opc_st_disabled[][BTA_OPC_NUM_COLS] =
+{
+/* Event Action 1 Action 2 Next state */
+/* BTA_OPC_API_ENABLE_EVT */ {BTA_OPC_ENABLE, BTA_OPC_IGNORE, BTA_OPC_IDLE_ST},
+/* BTA_OPC_API_DISABLE_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_DISABLED_ST},
+/* BTA_OPC_API_DISABLE_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_DISABLED_ST},
+/* BTA_OPC_API_CLOSE_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_DISABLED_ST},
+/* BTA_OPC_API_PUSH_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_DISABLED_ST},
+/* BTA_OPC_API_PULL_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_DISABLED_ST},
+/* BTA_OPC_API_EXCH_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_DISABLED_ST}
+};
+
+/* state table for idle state */
+static const UINT8 bta_opc_st_idle[][BTA_OPC_NUM_COLS] =
+{
+/* Event Action 1 Action 2 Next state */
+/* BTA_OPC_API_ENABLE_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_IDLE_ST},
+/* BTA_OPC_API_DISABLE_EVT */ {BTA_OPC_INITIALIZE, BTA_OPC_IGNORE, BTA_OPC_DISABLED_ST},
+/* BTA_OPC_API_CLOSE_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_IDLE_ST},
+/* BTA_OPC_API_PUSH_EVT */ {BTA_OPC_INIT_PUSH, BTA_OPC_FIND_SERVICE, BTA_OPC_W4_CONN_ST},
+/* BTA_OPC_API_PULL_EVT */ {BTA_OPC_INIT_PULL, BTA_OPC_FIND_SERVICE, BTA_OPC_W4_CONN_ST},
+/* BTA_OPC_API_EXCH_EVT */ {BTA_OPC_INIT_EXCH, BTA_OPC_FIND_SERVICE, BTA_OPC_W4_CONN_ST},
+/* BTA_OPC_SDP_OK_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_IDLE_ST},
+/* BTA_OPC_SDP_FAIL_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_IDLE_ST},
+/* BTA_OPC_CI_WRITE_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_IDLE_ST},
+/* BTA_OPC_CI_READ_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_IDLE_ST},
+/* BTA_OPC_CI_OPEN_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_IDLE_ST},
+/* BTA_OPC_OBX_CONN_RSP_EVT */ {BTA_OPC_IGNORE_OBX, BTA_OPC_IGNORE, BTA_OPC_IDLE_ST},
+/* BTA_OPC_OBX_PASSWORD_EVT */ {BTA_OPC_IGNORE_OBX, BTA_OPC_IGNORE, BTA_OPC_IDLE_ST},
+/* BTA_OPC_OBX_CLOSE_EVT */ {BTA_OPC_IGNORE_OBX, BTA_OPC_IGNORE, BTA_OPC_IDLE_ST},
+/* BTA_OPC_OBX_PUT_RSP_EVT */ {BTA_OPC_IGNORE_OBX, BTA_OPC_IGNORE, BTA_OPC_IDLE_ST},
+/* BTA_OPC_OBX_GET_RSP_EVT */ {BTA_OPC_IGNORE_OBX, BTA_OPC_IGNORE, BTA_OPC_IDLE_ST},
+/* BTA_OPC_OBX_CMPL_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_IDLE_ST},
+/* BTA_OPC_CLOSE_CMPL_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_IDLE_ST},
+/* BTA_OPC_DISABLE_CMPL_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_DISABLED_ST}
+};
+
+/* state table for wait for authentication response state */
+static const UINT8 bta_opc_st_w4_conn[][BTA_OPC_NUM_COLS] =
+{
+/* Event Action 1 Action 2 Next state */
+/* BTA_OPC_API_ENABLE_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_W4_CONN_ST},
+/* BTA_OPC_API_DISABLE_EVT */ {BTA_OPC_SET_DISABLE, BTA_OPC_STOP_CLIENT, BTA_OPC_CLOSING_ST},
+/* BTA_OPC_API_CLOSE_EVT */ {BTA_OPC_STOP_CLIENT, BTA_OPC_IGNORE, BTA_OPC_CLOSING_ST},
+/* BTA_OPC_API_PUSH_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_W4_CONN_ST},
+/* BTA_OPC_API_PULL_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_W4_CONN_ST},
+/* BTA_OPC_API_EXCH_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_W4_CONN_ST},
+/* BTA_OPC_SDP_OK_EVT */ {BTA_OPC_FREE_DB, BTA_OPC_START_CLIENT, BTA_OPC_W4_CONN_ST},
+/* BTA_OPC_SDP_FAIL_EVT */ {BTA_OPC_FREE_DB, BTA_OPC_CLOSE_COMPLETE, BTA_OPC_IDLE_ST},
+/* BTA_OPC_CI_WRITE_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_W4_CONN_ST},
+/* BTA_OPC_CI_READ_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_W4_CONN_ST},
+/* BTA_OPC_CI_OPEN_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_W4_CONN_ST},
+/* BTA_OPC_OBX_CONN_RSP_EVT */ {BTA_OPC_OBX_CONN_RSP, BTA_OPC_IGNORE, BTA_OPC_CONN_ST},
+/* BTA_OPC_OBX_PASSWORD_EVT */ {BTA_OPC_IGNORE_OBX, BTA_OPC_STOP_CLIENT, BTA_OPC_W4_CONN_ST},
+/* BTA_OPC_OBX_CLOSE_EVT */ {BTA_OPC_IGNORE_OBX, BTA_OPC_CLOSE, BTA_OPC_CLOSING_ST},
+/* BTA_OPC_OBX_PUT_RSP_EVT */ {BTA_OPC_IGNORE_OBX, BTA_OPC_IGNORE, BTA_OPC_W4_CONN_ST},
+/* BTA_OPC_OBX_GET_RSP_EVT */ {BTA_OPC_IGNORE_OBX, BTA_OPC_IGNORE, BTA_OPC_W4_CONN_ST},
+/* BTA_OPC_OBX_CMPL_EVT */ {BTA_OPC_TRANS_CMPL, BTA_OPC_STOP_CLIENT, BTA_OPC_CLOSING_ST},
+/* BTA_OPC_CLOSE_CMPL_EVT */ {BTA_OPC_CLOSE_COMPLETE,BTA_OPC_IGNORE, BTA_OPC_IDLE_ST},
+/* BTA_OPC_DISABLE_CMPL_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_DISABLED_ST}
+};
+
+/* state table for open state */
+static const UINT8 bta_opc_st_connected[][BTA_OPC_NUM_COLS] =
+{
+/* Event Action 1 Action 2 Next state */
+/* BTA_OPC_API_ENABLE_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_CONN_ST},
+/* BTA_OPC_API_DISABLE_EVT */ {BTA_OPC_SET_DISABLE, BTA_OPC_STOP_CLIENT, BTA_OPC_CLOSING_ST},
+/* BTA_OPC_API_CLOSE_EVT */ {BTA_OPC_STOP_CLIENT, BTA_OPC_IGNORE, BTA_OPC_CLOSING_ST},
+/* BTA_OPC_API_PUSH_EVT */ {BTA_OPC_INIT_PUSH, BTA_OPC_DO_PUSH, BTA_OPC_CONN_ST},
+/* BTA_OPC_API_PULL_EVT */ {BTA_OPC_INIT_PULL, BTA_OPC_DO_PULL, BTA_OPC_CONN_ST},
+/* BTA_OPC_API_EXCH_EVT */ {BTA_OPC_INIT_EXCH, BTA_OPC_DO_PUSH, BTA_OPC_CONN_ST},
+/* BTA_OPC_SDP_OK_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_CONN_ST},
+/* BTA_OPC_SDP_FAIL_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_CONN_ST},
+/* BTA_OPC_CI_WRITE_EVT */ {BTA_OPC_CI_WRITE, BTA_OPC_IGNORE, BTA_OPC_CONN_ST},
+/* BTA_OPC_CI_READ_EVT */ {BTA_OPC_CI_READ, BTA_OPC_IGNORE, BTA_OPC_CONN_ST},
+/* BTA_OPC_CI_OPEN_EVT */ {BTA_OPC_CI_OPEN, BTA_OPC_IGNORE, BTA_OPC_CONN_ST},
+/* BTA_OPC_OBX_CONN_RSP_EVT */ {BTA_OPC_IGNORE_OBX, BTA_OPC_IGNORE, BTA_OPC_CONN_ST},
+/* BTA_OPC_OBX_PASSWORD_EVT */ {BTA_OPC_IGNORE_OBX, BTA_OPC_STOP_CLIENT, BTA_OPC_CLOSING_ST},
+/* BTA_OPC_OBX_CLOSE_EVT */ {BTA_OPC_IGNORE_OBX, BTA_OPC_CLOSE, BTA_OPC_CLOSING_ST},
+/* BTA_OPC_OBX_PUT_RSP_EVT */ {BTA_OPC_OBX_PUT_RSP, BTA_OPC_IGNORE, BTA_OPC_CONN_ST},
+/* BTA_OPC_OBX_GET_RSP_EVT */ {BTA_OPC_OBX_GET_RSP, BTA_OPC_IGNORE, BTA_OPC_CONN_ST},
+/* BTA_OPC_OBX_CMPL_EVT */ {BTA_OPC_TRANS_CMPL, BTA_OPC_CHK_CLOSE, BTA_OPC_CONN_ST},
+/* BTA_OPC_CLOSE_CMPL_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_CONN_ST},
+/* BTA_OPC_DISABLE_CMPL_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_DISABLED_ST}
+};
+
+/* state table for closing state */
+static const UINT8 bta_opc_st_closing[][BTA_OPC_NUM_COLS] =
+{
+/* Event Action 1 Action 2 Next state */
+/* BTA_OPC_API_ENABLE_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_CLOSING_ST},
+/* BTA_OPC_API_DISABLE_EVT */ {BTA_OPC_SET_DISABLE, BTA_OPC_IGNORE, BTA_OPC_CLOSING_ST},
+/* BTA_OPC_API_CLOSE_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_CLOSING_ST},
+/* BTA_OPC_API_PUSH_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_CLOSING_ST},
+/* BTA_OPC_API_PULL_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_CLOSING_ST},
+/* BTA_OPC_API_EXCH_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_CLOSING_ST},
+/* BTA_OPC_SDP_OK_EVT */ {BTA_OPC_FREE_DB, BTA_OPC_CLOSE, BTA_OPC_CLOSING_ST},
+/* BTA_OPC_SDP_FAIL_EVT */ {BTA_OPC_FREE_DB, BTA_OPC_CLOSE, BTA_OPC_CLOSING_ST},
+/* BTA_OPC_CI_WRITE_EVT */ {BTA_OPC_CLOSE_COMPLETE,BTA_OPC_IGNORE, BTA_OPC_IDLE_ST},
+/* BTA_OPC_CI_READ_EVT */ {BTA_OPC_CLOSE_COMPLETE,BTA_OPC_IGNORE, BTA_OPC_IDLE_ST},
+/* BTA_OPC_CI_OPEN_EVT */ {BTA_OPC_CLOSE_COMPLETE,BTA_OPC_IGNORE, BTA_OPC_IDLE_ST},
+/* BTA_OPC_OBX_CONN_RSP_EVT */ {BTA_OPC_IGNORE_OBX, BTA_OPC_STOP_CLIENT, BTA_OPC_CLOSING_ST},
+/* BTA_OPC_OBX_PASSWORD_EVT */ {BTA_OPC_IGNORE_OBX, BTA_OPC_IGNORE, BTA_OPC_CLOSING_ST},
+/* BTA_OPC_OBX_CLOSE_EVT */ {BTA_OPC_IGNORE_OBX, BTA_OPC_CLOSE, BTA_OPC_CLOSING_ST},
+/* BTA_OPC_OBX_PUT_RSP_EVT */ {BTA_OPC_IGNORE_OBX, BTA_OPC_IGNORE, BTA_OPC_CLOSING_ST},
+/* BTA_OPC_OBX_GET_RSP_EVT */ {BTA_OPC_IGNORE_OBX, BTA_OPC_IGNORE, BTA_OPC_CLOSING_ST},
+/* BTA_OPC_OBX_CMPL_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_CLOSING_ST},
+/* BTA_OPC_CLOSE_CMPL_EVT */ {BTA_OPC_CLOSE_COMPLETE,BTA_OPC_IGNORE, BTA_OPC_IDLE_ST},
+/* BTA_OPC_DISABLE_CMPL_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_DISABLED_ST}
+};
+
+/* type for state table */
+typedef const UINT8 (*tBTA_OPC_ST_TBL)[BTA_OPC_NUM_COLS];
+
+/* state table */
+const tBTA_OPC_ST_TBL bta_opc_st_tbl[] =
+{
+ bta_opc_st_disabled,
+ bta_opc_st_idle,
+ bta_opc_st_w4_conn,
+ bta_opc_st_connected,
+ bta_opc_st_closing
+};
+
+/*****************************************************************************
+** Global data
+*****************************************************************************/
+
+/* OPC control block */
+#if BTA_DYNAMIC_MEMORY == FALSE
+tBTA_OPC_CB bta_opc_cb;
+#endif
+
+#if BTA_OPC_DEBUG == TRUE
+static char *opc_evt_code(tBTA_OPC_INT_EVT evt_code);
+static char *opc_state_code(tBTA_OPC_STATE state_code);
+#endif
+
+/*******************************************************************************
+**
+** Function bta_opc_sm_execute
+**
+** Description State machine event handling function for OPC
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_opc_sm_execute(tBTA_OPC_CB *p_cb, UINT16 event, tBTA_OPC_DATA *p_data)
+{
+ tBTA_OPC_ST_TBL state_table;
+ UINT8 action;
+ int i;
+
+ /* look up the state table for the current state */
+ state_table = bta_opc_st_tbl[p_cb->state];
+
+ event &= 0x00FF;
+
+ /* set next state */
+ p_cb->state = state_table[event][BTA_OPC_NEXT_STATE];
+
+ /* execute action functions */
+ for (i = 0; i < BTA_OPC_ACTIONS; i++)
+ {
+ if ((action = state_table[event][i]) != BTA_OPC_IGNORE)
+ {
+ (*bta_opc_action[action])(p_cb, p_data);
+ }
+ else
+ {
+ break;
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_opc_hdl_event
+**
+** Description File transfer server main event handling function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BOOLEAN bta_opc_hdl_event(BT_HDR *p_msg)
+{
+ tBTA_OPC_CB *p_cb = &bta_opc_cb;
+
+#if BTA_OPC_DEBUG == TRUE
+ tBTA_OPC_STATE in_state = p_cb->state;
+ APPL_TRACE_DEBUG3("OPC Event Handler: State 0x%02x [%s], Event [%s]", in_state,
+ opc_state_code(in_state),
+ opc_evt_code(p_msg->event));
+#endif
+
+ bta_opc_sm_execute(p_cb, p_msg->event, (tBTA_OPC_DATA *) p_msg);
+
+ if ( p_cb->state == BTA_OPC_CONN_ST )
+ {
+ if (( p_cb->pm_state == BTA_OPC_PM_IDLE )
+ &&( p_cb->obx_oper != OPC_OP_NONE ))
+ {
+ /* inform power manager */
+ APPL_TRACE_DEBUG0("BTA OPC informs DM/PM busy state");
+ bta_sys_busy( BTA_ID_OPC, p_cb->app_id, p_cb->bd_addr );
+ p_cb->pm_state = BTA_OPC_PM_BUSY;
+ }
+ else if (( p_cb->pm_state == BTA_OPC_PM_BUSY )
+ &&( p_cb->obx_oper == OPC_OP_NONE ))
+ {
+ /* inform power manager */
+ APPL_TRACE_DEBUG0("BTA OPC informs DM/PM idle state");
+ bta_sys_idle( BTA_ID_OPC ,p_cb->app_id, p_cb->bd_addr);
+ p_cb->pm_state = BTA_OPC_PM_IDLE;
+ }
+ }
+ else if ( p_cb->state == BTA_OPC_IDLE_ST )
+ {
+ /* initialize power management state */
+ p_cb->pm_state = BTA_OPC_PM_BUSY;
+ }
+
+#if BTA_OPC_DEBUG == TRUE
+ if (in_state != p_cb->state)
+ {
+ APPL_TRACE_DEBUG3("OPC State Change: [%s] -> [%s] after Event [%s]",
+ opc_state_code(in_state),
+ opc_state_code(p_cb->state),
+ opc_evt_code(p_msg->event));
+ }
+#endif
+
+ return (TRUE);
+}
+
+
+/*****************************************************************************
+** Debug Functions
+*****************************************************************************/
+#if BTA_OPC_DEBUG == TRUE
+
+/*******************************************************************************
+**
+** Function opc_evt_code
+**
+** Description
+**
+** Returns void
+**
+*******************************************************************************/
+static char *opc_evt_code(tBTA_OPC_INT_EVT evt_code)
+{
+ switch(evt_code)
+ {
+ case BTA_OPC_API_ENABLE_EVT:
+ return "BTA_OPC_API_ENABLE_EVT";
+ case BTA_OPC_API_DISABLE_EVT:
+ return "BTA_OPC_API_DISABLE_EVT";
+ case BTA_OPC_API_CLOSE_EVT:
+ return "BTA_OPC_API_CLOSE_EVT";
+ case BTA_OPC_API_PUSH_EVT:
+ return "BTA_OPC_API_PUSH_EVT";
+ case BTA_OPC_API_PULL_EVT:
+ return "BTA_OPC_API_PULL_EVT";
+ case BTA_OPC_API_EXCH_EVT:
+ return "BTA_OPC_API_EXCH_EVT";
+ case BTA_OPC_SDP_OK_EVT:
+ return "BTA_OPC_SDP_OK_EVT";
+ case BTA_OPC_SDP_FAIL_EVT:
+ return "BTA_OPC_SDP_FAIL_EVT";
+ case BTA_OPC_CI_WRITE_EVT:
+ return "BTA_OPC_CI_WRITE_EVT";
+ case BTA_OPC_CI_READ_EVT:
+ return "BTA_OPC_CI_READ_EVT";
+ case BTA_OPC_CI_OPEN_EVT:
+ return "BTA_OPC_CI_OPEN_EVT";
+ case BTA_OPC_OBX_CONN_RSP_EVT:
+ return "BTA_OPC_OBX_CONN_RSP_EVT";
+ case BTA_OPC_OBX_PASSWORD_EVT:
+ return "BTA_OPC_OBX_PASSWORD_EVT";
+ case BTA_OPC_OBX_CLOSE_EVT:
+ return "BTA_OPC_OBX_CLOSE_EVT";
+ case BTA_OPC_OBX_PUT_RSP_EVT:
+ return "BTA_OPC_OBX_PUT_RSP_EVT";
+ case BTA_OPC_OBX_GET_RSP_EVT:
+ return "BTA_OPC_OBX_GET_RSP_EVT";
+ case BTA_OPC_OBX_CMPL_EVT:
+ return "BTA_OPC_OBX_CMPL_EVT";
+ case BTA_OPC_CLOSE_CMPL_EVT:
+ return "BTA_OPC_CLOSE_CMPL_EVT";
+ case BTA_OPC_DISABLE_CMPL_EVT:
+ return "BTA_OPC_DISABLE_CMPL_EVT";
+ default:
+ return "unknown OPC event code";
+ }
+}
+
+/*******************************************************************************
+**
+** Function opc_evt_code
+**
+** Description
+**
+** Returns void
+**
+*******************************************************************************/
+static char *opc_state_code(tBTA_OPC_STATE state_code)
+{
+ switch(state_code)
+ {
+ case BTA_OPC_DISABLED_ST:
+ return "BTA_OPC_DISABLED_ST";
+ case BTA_OPC_IDLE_ST:
+ return "BTA_OPC_IDLE_ST";
+ case BTA_OPC_W4_CONN_ST:
+ return "BTA_OPC_W4_CONN_ST";
+ case BTA_OPC_CONN_ST:
+ return "BTA_OPC_CONN_ST";
+ case BTA_OPC_CLOSING_ST:
+ return "BTA_OPC_CLOSING_ST";
+ default:
+ return "unknown OPC state code";
+ }
+}
+
+#endif /* Debug Functions */
diff --git a/bta/op/bta_opc_utils.c b/bta/op/bta_opc_utils.c
new file mode 100644
index 0000000..82e626c
--- /dev/null
+++ b/bta/op/bta_opc_utils.c
@@ -0,0 +1,322 @@
+/*****************************************************************************
+**
+** Name: bta_opc_utils.c
+**
+** Description: This file implements object store functions for the
+** file transfer server.
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include "bta_opc_int.h"
+#include "bta_fs_api.h"
+#include "bta_fs_co.h"
+#include "gki.h"
+#include "utl.h"
+
+/*******************************************************************************
+** Constants
+*******************************************************************************/
+
+/*******************************************************************************
+** Local Function Prototypes
+*******************************************************************************/
+
+/*******************************************************************************
+* Macros for OPC
+*******************************************************************************/
+
+/*******************************************************************************
+* Exported Functions
+*******************************************************************************/
+/*******************************************************************************
+**
+** Function bta_opc_send_get_req
+**
+** Description Processes a Get File Operation.
+**
+** Parameters p_cb - Pointer to the OPC control block
+**
+** Returns (UINT8) OBX response code
+**
+*******************************************************************************/
+UINT8 bta_opc_send_get_req(tBTA_OPC_CB *p_cb)
+{
+ tBTA_OPC_OBX_PKT *p_obx = &p_cb->obx;
+ UINT8 rsp_code = OBX_RSP_FAILED;
+
+ utl_freebuf((void**)&p_obx->p_pkt);
+ if ((p_obx->p_pkt = OBX_HdrInit(p_cb->obx_handle, p_cb->peer_mtu)) != NULL)
+ {
+ /* If first request add the Type Header to the request */
+ if (p_cb->first_get_pkt == TRUE)
+ {
+ p_cb->obx_oper = OPC_OP_PULL_OBJ;
+ p_cb->to_do &= ~BTA_OPC_PULL_MASK;
+ OBX_AddTypeHdr(p_obx->p_pkt, "text/x-vcard");
+ }
+
+ if ((OBX_GetReq(p_cb->obx_handle, TRUE, p_obx->p_pkt)) == OBX_SUCCESS)
+ {
+ rsp_code = OBX_RSP_OK;
+ p_obx->p_pkt = NULL;
+ p_cb->req_pending = TRUE;
+ }
+ }
+
+ return (rsp_code);
+}
+
+/*******************************************************************************
+**
+** Function bta_opc_cont_get_rsp
+**
+** Description Continues an obex get response packet.
+** This function is called upon completion of a file open or
+** a file write event.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_opc_cont_get_rsp(tBTA_OPC_CB *p_cb)
+{
+ tBTA_OPC_OBX_EVT obx_evt;
+ tBTA_OPC_OBX_PKT *p_obx = &p_cb->obx;
+ UINT16 body_size;
+ BOOLEAN end;
+
+ /* Read the body header from the obx packet if it exists */
+ if (OBX_ReadBodyHdr(p_obx->p_pkt, &p_obx->p_start, &body_size, &end))
+ {
+ p_obx->final_pkt = end;
+ if (body_size)
+ {
+ /* Data to be written */
+ p_obx->offset = body_size; /* Save write size for comparison */
+ p_cb->cout_active = TRUE;
+ bta_fs_co_write(p_cb->fd, p_obx->p_start, body_size,
+ BTA_OPC_CI_WRITE_EVT, 0, p_cb->app_id);
+ return;
+ }
+ }
+
+ /* Empty Body; send next request or finished */
+ if (!p_obx->final_pkt)
+ {
+ bta_opc_send_get_req(p_cb);
+ }
+ else /* Done getting object */
+ {
+ memset(&obx_evt, 0, sizeof(tBTA_OPC_OBX_EVT));
+ obx_evt.rsp_code = OBX_RSP_OK;
+ bta_opc_sm_execute(p_cb, BTA_OPC_OBX_CMPL_EVT, (tBTA_OPC_DATA *) &obx_evt);
+ utl_freebuf((void**)&p_obx->p_pkt);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_opc_proc_get_rsp
+**
+** Description Processes an obex get response packet.
+** Initiates a file open if no errors.
+**
+**
+** Returns BOOLEAN - TRUE if obex packet is to be freed
+**
+*******************************************************************************/
+BOOLEAN bta_opc_proc_get_rsp(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data)
+{
+ tBTA_OPC_OBX_EVT *p_evt = &p_data->obx_evt;
+ tBTA_OPC_OBX_PKT *p_obx = &p_cb->obx;
+ char *p_filename;
+
+ if (p_evt->rsp_code == OBX_RSP_OK || p_evt->rsp_code == OBX_RSP_CONTINUE)
+ {
+ /* The get the file name */
+ if (!OBX_ReadUtf8NameHdr(p_obx->p_pkt, (UINT8 *) p_cb->p_name,
+ p_bta_fs_cfg->max_file_len))
+ BCM_STRNCPY_S(p_cb->p_name, p_bta_fs_cfg->max_path_len+1, OPC_DEF_RCV_NAME, sizeof(OPC_DEF_RCV_NAME)+1);
+
+ /* If length header exists, save the file length */
+ if (!OBX_ReadLengthHdr(p_obx->p_pkt, &p_cb->obj_size))
+ p_cb->obj_size = BTA_FS_LEN_UNKNOWN;
+
+ /* Build the file name with a fully qualified path */
+ if ((p_filename = (char *)GKI_getbuf((UINT16)(p_bta_fs_cfg->max_path_len + 1))) != NULL)
+ {
+ sprintf(p_filename, "%s%c%s", p_cb->p_rcv_path,
+ p_bta_fs_cfg->path_separator,
+ p_cb->p_name);
+
+ p_cb->cout_active = TRUE;
+ bta_fs_co_open(p_filename,
+ (BTA_FS_O_RDWR | BTA_FS_O_CREAT | BTA_FS_O_TRUNC),
+ p_cb->obj_size, BTA_OPC_CI_OPEN_EVT, p_cb->app_id);
+
+ GKI_freebuf(p_filename);
+ return FALSE; /* Do not free the obex packet until data is written */
+ }
+ else
+ p_evt->rsp_code = OBX_RSP_INTRNL_SRVR_ERR;
+ }
+
+ /* Server returned an error or out of memory to process request */
+ bta_opc_sm_execute(p_cb, BTA_OPC_OBX_CMPL_EVT, p_data);
+
+ return TRUE;
+}
+
+/*******************************************************************************
+**
+** Function bta_opc_send_put_req
+**
+** Description Initiates/Continues a Put Object Operation.
+** Builds a new OBX packet, and initiates a read operation.
+**
+** Parameters p_cb - pointer to the client's control block.
+** first_pkt - TRUE if initial PUT request to server.
+**
+**
+** Returns UINT8 OBX response code
+**
+*******************************************************************************/
+UINT8 bta_opc_send_put_req(tBTA_OPC_CB *p_cb, BOOLEAN first_pkt)
+{
+ tBTA_OPC_OBX_PKT *p_obx = &p_cb->obx;
+ UINT8 rsp_code = OBX_RSP_FAILED;
+ char *p_ch;
+
+ utl_freebuf((void**)&p_obx->p_pkt);
+ if ((p_obx->p_pkt = OBX_HdrInit(p_cb->obx_handle, OBX_LRG_DATA_POOL_SIZE)) != NULL)
+ {
+ /* Add length header if it exists; No body in first packet */
+ if (first_pkt)
+ {
+ /* Add the Name Header to the request */
+ /* Find the beginning of the name (excluding the path) */
+ p_ch = strrchr(p_cb->p_name, (int) p_bta_fs_cfg->path_separator);
+ if (p_ch == NULL)
+ p_ch = p_cb->p_name;
+
+ if (p_ch && p_ch[1] != '\0')
+ {
+ OBX_AddUtf8NameHdr(p_obx->p_pkt, (UINT8 *) (&p_ch[1]));
+
+ /* Add the length header if known */
+ if (p_cb->obj_size != BTA_FS_LEN_UNKNOWN)
+ {
+ OBX_AddLengthHdr(p_obx->p_pkt, p_cb->obj_size);
+ }
+
+ /* Add the type header if known */
+ switch (p_cb->format)
+ {
+ case BTA_OP_VCARD30_FMT:
+ case BTA_OP_VCARD21_FMT:
+ OBX_AddTypeHdr(p_obx->p_pkt, "text/x-vcard");
+ break;
+ case BTA_OP_VCAL_FMT:
+ case BTA_OP_ICAL_FMT:
+ OBX_AddTypeHdr(p_obx->p_pkt, "text/x-vcalendar");
+ break;
+ case BTA_OP_VNOTE_FMT:
+ OBX_AddTypeHdr(p_obx->p_pkt, "text/x-vnote");
+ break;
+ case BTA_OP_VMSG_FMT:
+ OBX_AddTypeHdr(p_obx->p_pkt, "text/x-vmessage");
+ break;
+ }
+
+ OBX_PutReq(p_cb->obx_handle, FALSE, p_obx->p_pkt);
+ p_obx->p_pkt = NULL;
+ p_cb->req_pending = TRUE;
+ rsp_code = OBX_RSP_OK;
+ }
+ else
+ APPL_TRACE_ERROR1("Invalid file name [%s] feed, PutReq NOT sent.", p_cb->p_name);
+
+ }
+ else /* A continuation packet so read object data */
+ {
+ /* Add the start of the Body Header */
+ p_obx->offset = 0;
+ p_obx->bytes_left = 0;
+ p_obx->p_start = OBX_AddBodyStart(p_obx->p_pkt, &p_obx->bytes_left);
+
+ /* Read in the first packet's worth of data */
+ p_cb->cout_active = TRUE;
+ bta_fs_co_read(p_cb->fd, &p_obx->p_start[p_obx->offset],
+ p_obx->bytes_left, BTA_OPC_CI_READ_EVT, 0, p_cb->app_id);
+ rsp_code = OBX_RSP_OK;
+ }
+ }
+
+ return (rsp_code);
+}
+
+/*******************************************************************************
+**
+** Function bta_opc_start_push
+**
+** Description Push an object to connected server.
+** Opens the object to be transferred to the server.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_opc_start_push(tBTA_OPC_CB *p_cb)
+{
+ p_cb->to_do &= ~BTA_OPC_PUSH_MASK;
+ p_cb->obx_oper = OPC_OP_PUSH_OBJ;
+ p_cb->cout_active = TRUE;
+
+ bta_fs_co_open(p_cb->p_name, BTA_FS_O_RDONLY, 0, BTA_OPC_CI_OPEN_EVT,
+ p_cb->app_id);
+}
+
+/*******************************************************************************
+**
+** Function bta_opc_convert_obx_to_opc_status
+**
+** Description Convert OBX response code into BTA OPC status code.
+**
+** Returns void
+**
+*******************************************************************************/
+tBTA_OPC_STATUS bta_opc_convert_obx_to_opc_status(tOBX_STATUS obx_status)
+{
+ tBTA_OPC_STATUS status;
+
+ switch (obx_status)
+ {
+ case OBX_RSP_OK:
+ case OBX_RSP_CONTINUE:
+ status = BTA_OPC_OK;
+ break;
+ case OBX_RSP_UNAUTHORIZED:
+ status = BTA_OPC_NO_PERMISSION;
+ break;
+ case OBX_RSP_NOT_FOUND:
+ status = BTA_OPC_NOT_FOUND;
+ break;
+ case OBX_RSP_SERVICE_UNAVL:
+ status = BTA_OPC_SRV_UNAVAIL;
+ break;
+ case OBX_RSP_FORBIDDEN:
+ status = BTA_OPC_RSP_FORBIDDEN;
+ break;
+ case OBX_RSP_NOT_ACCEPTABLE:
+ status = BTA_OPC_RSP_NOT_ACCEPTABLE;
+ break;
+ default:
+ status = BTA_OPC_FAIL;
+ }
+
+ return (status);
+}
diff --git a/bta/op/bta_ops_act.c b/bta/op/bta_ops_act.c
new file mode 100644
index 0000000..5409cf1
--- /dev/null
+++ b/bta/op/bta_ops_act.c
@@ -0,0 +1,793 @@
+/*****************************************************************************
+**
+** Name: bta_ops_act.c
+**
+** Description: This file contains the object transfer action
+** functions for the state machine.
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+
+#if defined(BTA_OP_INCLUDED) && (BTA_OP_INCLUDED)
+
+#include <string.h>
+#include "gki.h"
+#include "bta_sys.h"
+#include "obx_api.h"
+#include "bta_op_api.h"
+#include "bta_ops_int.h"
+#include "bta_fs_api.h"
+#include "bta_fs_co.h"
+#include "bta_fs_ci.h"
+#include "rfcdefs.h" /* BT_PSM_RFCOMM */
+#include "btm_api.h"
+#include "utl.h"
+#include "goep_util.h"
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+#define BTA_OPS_NUM_FMTS 7
+#define BTA_OPS_PROTOCOL_COUNT 3
+
+/* object format lookup table */
+const tBTA_OP_FMT bta_ops_obj_fmt[] =
+{
+ BTA_OP_VCARD21_FMT,
+ BTA_OP_VCARD30_FMT,
+ BTA_OP_VCAL_FMT,
+ BTA_OP_ICAL_FMT,
+ BTA_OP_VNOTE_FMT,
+ BTA_OP_VMSG_FMT,
+ BTA_OP_OTHER_FMT
+};
+
+/*****************************************************************************
+** Local Function prototypes
+*****************************************************************************/
+#if BTA_OPS_DEBUG == TRUE
+static char *ops_obx_evt_code(tOBX_EVENT evt_code);
+#endif
+
+/*****************************************************************************
+** Action Functions
+*****************************************************************************/
+/*******************************************************************************
+**
+** Function bta_ops_enable
+**
+** Description Perform necessary operations to enable object push.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ops_enable(tBTA_OPS_CB *p_cb, tBTA_OPS_API_ENABLE *p_data)
+{
+ tOBX_StartParams start_params;
+ UINT16 servclass = UUID_SERVCLASS_OBEX_OBJECT_PUSH;
+ int i, j;
+ tBTA_UTL_COD cod;
+ tOBX_STATUS status;
+ UINT8 desc_type[BTA_OPS_NUM_FMTS];
+ UINT8 type_len[BTA_OPS_NUM_FMTS];
+ UINT8 *type_value[BTA_OPS_NUM_FMTS];
+ UINT16 mtu = OBX_MAX_MTU;
+ UINT8 temp[4], *p;
+ UINT16 version = GOEP_ENHANCED_VERSION;
+
+ /* allocate scn for opp */
+ p_cb->scn = BTM_AllocateSCN();
+ p_cb->app_id = p_data->app_id;
+
+ /* set security level */
+ BTM_SetSecurityLevel (FALSE, (char *) "", BTM_SEC_SERVICE_OBEX,
+ p_data->sec_mask, BT_PSM_RFCOMM,
+ BTM_SEC_PROTO_RFCOMM, p_cb->scn);
+
+ p_cb->psm = L2CA_AllocatePSM();
+ BTM_SetSecurityLevel (FALSE, (char *) "", BTM_SEC_SERVICE_OBEX,
+ p_data->sec_mask, p_cb->psm, 0, 0);
+
+ memset (&start_params, 0, sizeof(tOBX_StartParams));
+ start_params.p_target = NULL;
+ start_params.p_cback = &bta_ops_obx_cback;
+ start_params.mtu = mtu;
+ start_params.scn = p_cb->scn;
+ start_params.psm = p_cb->psm;
+ start_params.srm = p_cb->srm;
+ start_params.nonce = 0;
+ start_params.authenticate = FALSE;
+ start_params.auth_option = OBX_AO_NONE;
+ start_params.realm_charset = OBX_RCS_ASCII;
+ start_params.p_realm = NULL;
+ start_params.realm_len = 0;
+
+ if ((status = OBX_StartServer (&start_params, &p_cb->obx_handle)) == OBX_SUCCESS)
+ {
+ status = GOEP_Register (p_data->name, &p_cb->sdp_handle, p_cb->scn, 1, &servclass,
+ servclass, version);
+
+ /* add the psm */
+ p = temp;
+ UINT16_TO_BE_STREAM(p, p_cb->psm);
+ SDP_AddAttribute(p_cb->sdp_handle, ATTR_ID_OBX_OVR_L2CAP_PSM, UINT_DESC_TYPE,
+ (UINT32)2, (UINT8*)temp);
+
+ /* add sequence for supported types */
+ for (i = 0, j = 0; i < BTA_OPS_NUM_FMTS; i++)
+ {
+ if ((p_data->formats >> i) & 1)
+ {
+ type_value[j] = (UINT8 *) &bta_ops_obj_fmt[i];
+ desc_type[j] = UINT_DESC_TYPE;
+ type_len[j++] = 1;
+ }
+ }
+
+ SDP_AddSequence(p_cb->sdp_handle, (UINT16) ATTR_ID_SUPPORTED_FORMATS_LIST,
+ (UINT8) j, desc_type, type_len, type_value);
+
+ /* set class of device */
+ cod.service = BTM_COD_SERVICE_OBJ_TRANSFER;
+ utl_set_device_class(&cod, BTA_UTL_SET_COD_SERVICE_CLASS);
+
+ /* store formats value */
+ p_cb->formats = p_data->formats;
+ }
+ bta_sys_add_uuid(servclass); /* UUID_SERVCLASS_OBEX_OBJECT_PUSH */
+
+ p_cb->p_cback(BTA_OPS_ENABLE_EVT, NULL);
+}
+
+/*******************************************************************************
+**
+** Function bta_ops_api_disable
+**
+** Description Perform necessary operations to disable object push.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ops_api_disable(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data)
+{
+ /* Free any outstanding headers and control block memory */
+ bta_ops_clean_getput(p_cb, TRUE);
+
+ /* Stop the OBEX server */
+ OBX_StopServer(p_cb->obx_handle);
+
+ /* Remove the OPP service from the SDP database */
+ SDP_DeleteRecord(p_cb->sdp_handle);
+ bta_sys_remove_uuid(UUID_SERVCLASS_OBEX_OBJECT_PUSH);
+
+ /* Free the allocated server channel number */
+ BTM_FreeSCN(p_cb->scn);
+ BTM_SecClrService(BTM_SEC_SERVICE_OBEX);
+}
+
+/*******************************************************************************
+**
+** Function bta_ops_api_accessrsp
+**
+** Description Process the access API event.
+** If permission had been granted, continue the push or pull
+** operation.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ops_api_accessrsp(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data)
+{
+ UINT8 rsp_code;
+
+ /* Process the currently active access response */
+ switch (p_cb->acc_active)
+ {
+ case BTA_OP_OPER_PUSH:
+ if (p_data->api_access.oper == BTA_OP_OPER_PUSH)
+ {
+ if (p_data->api_access.flag == BTA_OP_ACCESS_ALLOW)
+ {
+ /* Save the file name with path prepended */
+ BCM_STRCPY_S(p_cb->p_path, p_bta_fs_cfg->max_path_len+1, p_data->api_access.p_name);
+
+ APPL_TRACE_DEBUG2("OPS PUSH OBJ: Name [%s], Length = 0x%0x (0 = n/a)",
+ p_cb->p_path, p_cb->file_length);
+
+ p_cb->cout_active = TRUE;
+ bta_fs_co_open (p_cb->p_path,
+ (BTA_FS_O_CREAT | BTA_FS_O_TRUNC | BTA_FS_O_RDWR),
+ p_cb->file_length, BTA_OPS_CI_OPEN_EVT,
+ p_cb->app_id);
+ }
+ else /* Access denied or Unsupported */
+ {
+ rsp_code = (p_data->api_access.flag == BTA_OP_ACCESS_NONSUP)
+ ? OBX_RSP_UNSUPTD_TYPE : OBX_RSP_UNAUTHORIZED;
+ bta_ops_clean_getput(p_cb, TRUE);
+ OBX_PutRsp(p_cb->obx_handle, rsp_code, (BT_HDR *)NULL);
+ }
+ p_cb->acc_active = 0;
+ }
+
+ break;
+
+ case BTA_OP_OPER_PULL:
+ if (p_data->api_access.oper == BTA_OP_OPER_PULL)
+ {
+ if (p_data->api_access.flag == BTA_OP_ACCESS_ALLOW)
+ {
+ /* Save the file name with path prepended */
+ BCM_STRCPY_S(p_cb->p_path, p_bta_fs_cfg->max_path_len+1, p_data->api_access.p_name);
+
+ APPL_TRACE_DEBUG1("OPS PULL VCARD: Name [%s]", p_cb->p_path);
+
+ p_cb->cout_active = TRUE;
+ bta_fs_co_open (p_cb->p_path, BTA_FS_O_RDONLY, 0,
+ BTA_OPS_CI_OPEN_EVT, p_cb->app_id);
+ }
+ else /* Denied */
+ bta_ops_get_obj_rsp(OBX_RSP_UNAUTHORIZED, 0);
+
+ p_cb->acc_active = 0;
+ }
+ break;
+
+ default:
+ APPL_TRACE_WARNING1("OPS ACCRSP: Unknown tBTA_OP_OPER value (%d)",
+ p_cb->acc_active);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ops_api_close
+**
+** Description Handle an api close event.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ops_api_close(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data)
+{
+ /* resources will be freed at BTA_OPS_OBX_CLOSE_EVT */
+ OBX_DisconnectRsp(p_cb->obx_handle, OBX_RSP_SERVICE_UNAVL, NULL);
+}
+
+/*******************************************************************************
+**
+** Function bta_ops_ci_write
+**
+** Description Continue with the current write operation
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ops_ci_write(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data)
+{
+ UINT8 rsp_code = OBX_RSP_INTRNL_SRVR_ERR;
+
+ p_cb->cout_active = FALSE;
+
+ if (!p_cb->aborting)
+ {
+ /* Process write call-in event if operation is still active */
+ if (p_cb->obx_oper == OPS_OP_PUSH_OBJ)
+ {
+ if (p_data->write_evt.status == BTA_FS_CO_OK)
+ rsp_code = OBX_RSP_OK;
+ else
+ {
+ if (p_data->write_evt.status == BTA_FS_CO_ENOSPACE)
+ rsp_code = OBX_RSP_DATABASE_FULL;
+ bta_ops_clean_getput(p_cb, TRUE);
+ }
+
+ /* Process response to OBX client */
+ bta_ops_put_obj_rsp(rsp_code);
+ }
+ }
+ else /* Finish aborting */
+ {
+ bta_ops_clean_getput(p_cb, TRUE);
+ OBX_AbortRsp(p_cb->obx_handle, OBX_RSP_OK, (BT_HDR *)NULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ops_ci_read
+**
+** Description Handles the response to a read call-out request.
+** This is called within the OBX get file request. If the
+** operation has completed, the OBX response is sent out;
+** otherwise a read for additional data is made.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ops_ci_read(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data)
+{
+ tBTA_FS_CI_READ_EVT *p_revt = &p_data->read_evt;
+ UINT8 rsp_code = OBX_RSP_INTRNL_SRVR_ERR;
+
+ p_cb->cout_active = FALSE;
+
+ if (!p_cb->aborting)
+ {
+ /* Process read call-in event if operation is still active */
+ if (p_cb->obx_oper == OPS_OP_PULL_OBJ && p_revt->fd == p_cb->fd)
+ {
+ /* Read was successful, not finished yet */
+ if (p_revt->status == BTA_FS_CO_OK)
+ rsp_code = OBX_RSP_CONTINUE;
+
+ /* Read was successful, end of file has been detected */
+ else if (p_revt->status == BTA_FS_CO_EOF)
+ rsp_code = OBX_RSP_OK;
+
+ /* Process response to OBX client */
+ bta_ops_get_obj_rsp(rsp_code, p_revt->num_read);
+ }
+ }
+ else /* Finish aborting */
+ {
+ bta_ops_clean_getput(p_cb, TRUE);
+ OBX_AbortRsp(p_cb->obx_handle, OBX_RSP_OK, (BT_HDR *)NULL);
+ APPL_TRACE_ERROR0("OPS PUSH OBJ: Finished ABORTING!!!");
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ops_ci_open
+**
+** Description Continue with the current file open operation
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ops_ci_open(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data)
+{
+ tBTA_OPS_OBX_PKT *p_obx = &p_cb->obx;
+ tBTA_FS_CI_OPEN_EVT *p_open = &p_data->open_evt;
+ UINT8 rsp_code = OBX_RSP_OK;
+ UINT8 num_hdrs;
+ BOOLEAN endpkt;
+ char *p_name;
+
+ p_cb->cout_active = FALSE;
+
+ if (p_cb->aborting)
+ {
+ bta_ops_clean_getput(p_cb, TRUE);
+ OBX_AbortRsp(p_cb->obx_handle, OBX_RSP_OK, (BT_HDR *)NULL);
+ return;
+ }
+
+ /* Only process file get or put operations */
+ if (p_cb->obx_oper == OPS_OP_PULL_OBJ)
+ {
+ /* if file is accessible read/write the first buffer of data */
+ if (p_open->status == BTA_FS_CO_OK)
+ {
+ p_cb->fd = p_open->fd;
+ p_cb->file_length = p_open->file_size;
+
+ /* Add the name and length headers */
+ p_name = strrchr(p_cb->p_path, (int)p_bta_fs_cfg->path_separator);
+ if (p_name == NULL)
+ p_name = p_cb->p_path;
+ else
+ p_name++; /* increment past the file separator */
+
+ OBX_AddUtf8NameHdr(p_obx->p_pkt, (UINT8 *)p_name);
+
+ if (p_cb->file_length != BTA_FS_LEN_UNKNOWN)
+ {
+ OBX_AddLengthHdr(p_obx->p_pkt, p_cb->file_length);
+ if (p_cb->file_length > 0)
+ {
+ rsp_code = OBX_RSP_CONTINUE;
+ }
+ }
+
+ /* Send continuation response with the length of the file and no body */
+ OBX_GetRsp(p_cb->obx_handle, rsp_code, (BT_HDR *)p_obx->p_pkt);
+ p_obx->p_pkt = NULL; /* Do not deallocate buffer; OBX will */
+ }
+ else
+ {
+ if (p_open->status == BTA_FS_CO_EACCES)
+ rsp_code = OBX_RSP_UNAUTHORIZED;
+ else /* File could not be found */
+ rsp_code = OBX_RSP_NOT_FOUND;
+
+ /* Send OBX response if an error occurred */
+ bta_ops_get_obj_rsp(rsp_code, 0);
+ }
+ }
+ else if (p_cb->obx_oper == OPS_OP_PUSH_OBJ)
+ {
+ /* if file is accessible read/write the first buffer of data */
+ if (p_open->status == BTA_FS_CO_OK)
+ {
+ p_cb->fd = p_open->fd;
+
+ /* Read in start of body if there is a body header */
+ num_hdrs = OBX_ReadBodyHdr(p_obx->p_pkt, &p_obx->p_start,
+ &p_obx->bytes_left, &endpkt);
+ if (num_hdrs == 1)
+ {
+ rsp_code = OBX_RSP_PART_CONTENT; /* Do not send OBX response yet */
+
+ /* Initiate the writing out of the data */
+ p_cb->cout_active = TRUE;
+ bta_fs_co_write(p_cb->fd, &p_obx->p_start[p_obx->offset],
+ p_obx->bytes_left, BTA_OPS_CI_WRITE_EVT,
+ 0, p_cb->app_id);
+ }
+ else if (num_hdrs > 1) /* Too many body headers to handle */
+ {
+ rsp_code = OBX_RSP_BAD_REQUEST;
+ bta_ops_clean_getput(p_cb, TRUE);
+ }
+ else /* No body: respond with an OK so client can start sending the data */
+ p_obx->bytes_left = 0;
+ }
+ else
+ {
+ if (p_open->status == BTA_FS_CO_EACCES)
+ rsp_code = OBX_RSP_UNAUTHORIZED;
+ else if (p_open->status == BTA_FS_CO_ENOSPACE)
+ rsp_code = OBX_RSP_DATABASE_FULL;
+ else
+ rsp_code = OBX_RSP_INTRNL_SRVR_ERR;
+ }
+
+ /* Send OBX response now if an error occurred or no body */
+ if (rsp_code != OBX_RSP_PART_CONTENT)
+ bta_ops_put_obj_rsp(rsp_code);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ops_obx_connect
+**
+** Description Process the OBX connect event
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ops_obx_connect(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data)
+{
+ tBTA_OPS_OBX_EVENT *p_evt = &p_data->obx_evt;
+
+ p_cb->peer_mtu = p_evt->param.conn.mtu;
+ memcpy(p_cb->bd_addr, p_evt->param.conn.peer_addr, BD_ADDR_LEN);
+ APPL_TRACE_EVENT1("OPS Connect: peer mtu 0x%04x", p_cb->peer_mtu);
+
+ /* done with obex packet */
+ utl_freebuf((void**)&p_evt->p_pkt);
+
+ OBX_ConnectRsp(p_evt->handle, OBX_RSP_OK, (BT_HDR *)NULL);
+
+ /* inform role manager */
+ bta_sys_conn_open( BTA_ID_OPS ,p_cb->app_id, bta_ops_cb.bd_addr);
+
+ /* Notify the MMI that a connection has been opened */
+ p_cb->p_cback(BTA_OPS_OPEN_EVT, (tBTA_OPS*)bta_ops_cb.bd_addr);
+}
+
+/*******************************************************************************
+**
+** Function bta_ops_obx_disc
+**
+** Description Process the OBX disconnect event
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ops_obx_disc(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data)
+{
+ tBTA_OPS_OBX_EVENT *p_evt = &p_data->obx_evt;
+ UINT8 rsp_code;
+
+ rsp_code = (p_evt->obx_event == OBX_DISCONNECT_REQ_EVT) ? OBX_RSP_OK
+ : OBX_RSP_BAD_REQUEST;
+
+ /* Action operation is not supported in OPP, send reject rsp and free data */
+ if(p_evt->obx_event == OBX_ACTION_REQ_EVT)
+ {
+ OBX_ActionRsp(p_evt->handle, rsp_code, (BT_HDR *)NULL);
+ }
+
+ OBX_DisconnectRsp(p_evt->handle, rsp_code, (BT_HDR *)NULL);
+
+ /* Done with Obex packet */
+ utl_freebuf((void**)&p_evt->p_pkt);
+}
+
+/*******************************************************************************
+**
+** Function bta_ops_obx_close
+**
+** Description Process the OBX link lost event
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ops_obx_close(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data)
+{
+ /* finished if not waiting on a call-in function */
+ if (!p_cb->cout_active)
+ bta_ops_sm_execute(p_cb, BTA_OPS_CLOSE_CMPL_EVT, p_data);
+}
+
+/*******************************************************************************
+**
+** Function bta_ops_obx_abort
+**
+** Description Process the OBX abort event
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ops_obx_abort(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data)
+{
+ tBTA_OPS_OBX_EVENT *p_evt = &p_data->obx_evt;
+ UINT8 rsp_code = OBX_RSP_OK;
+
+ utl_freebuf((void**)&p_evt->p_pkt);
+
+ if (!p_cb->cout_active)
+ {
+ bta_ops_clean_getput(p_cb, TRUE);
+ OBX_AbortRsp(p_cb->obx_handle, rsp_code, (BT_HDR *)NULL);
+ }
+ else /* Delay the response if a call-out function is active */
+ p_cb->aborting = TRUE;
+}
+
+/*******************************************************************************
+**
+** Function bta_ops_obx_put
+**
+** Description Process the OBX push object put event
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ops_obx_put(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data)
+{
+ tBTA_OPS_OBX_EVENT *p_evt = &p_data->obx_evt;
+ UINT8 rsp_code = OBX_RSP_CONTINUE;
+
+ p_cb->obx.final_pkt = p_evt->param.put.final;
+
+ /* If currently processing a push, use the current name */
+ if (bta_ops_cb.obx_oper == OPS_OP_PUSH_OBJ)
+ {
+ bta_ops_proc_put_obj(p_evt->p_pkt);
+ }
+
+ /* This is a new request; allocate enough memory to hold the path (including file name) */
+ else if ((p_cb->p_path = (char *)GKI_getbuf((UINT16)(p_bta_fs_cfg->max_path_len
+ + p_bta_fs_cfg->max_file_len + 2))) != NULL)
+ {
+ p_cb->p_name = (p_cb->p_path + p_bta_fs_cfg->max_path_len + 1);
+ p_cb->p_name[p_bta_fs_cfg->max_file_len] = '\0';
+ p_cb->p_path[p_bta_fs_cfg->max_path_len] = '\0';
+
+ /* read the name header if it exists */
+ if (OBX_ReadUtf8NameHdr(p_evt->p_pkt, (UINT8 *)p_cb->p_name, p_bta_fs_cfg->max_file_len))
+ {
+ /* get file type from file name; check if supported */
+ if ((p_cb->obj_fmt = bta_ops_fmt_supported(p_cb->p_name,
+ p_cb->formats)) != 0)
+ {
+ if(!(OBX_ReadLengthHdr(p_evt->p_pkt, &p_cb->file_length)))
+ p_cb->file_length = BTA_FS_LEN_UNKNOWN;
+
+ p_cb->obx.p_pkt = p_evt->p_pkt; /* save the packet for later use */
+ p_cb->obx.offset = 0; /* Initial offset into OBX data */
+ p_cb->obx_oper = OPS_OP_PUSH_OBJ;
+
+ /* request access from the app */
+ bta_ops_req_app_access (BTA_OP_OPER_PUSH, p_cb);
+ }
+ else
+ rsp_code = OBX_RSP_UNSUPTD_TYPE;
+ }
+ else
+ rsp_code = OBX_RSP_BAD_REQUEST;
+ }
+ else
+ rsp_code = OBX_RSP_INTRNL_SRVR_ERR;
+
+ /* Error has been detected; respond with error code */
+ if (rsp_code != OBX_RSP_CONTINUE)
+ {
+ utl_freebuf((void**)&p_evt->p_pkt); /* done with obex packet */
+ utl_freebuf((void**)&p_cb->p_path);
+ p_cb->p_name = NULL;
+ OBX_PutRsp(p_evt->handle, rsp_code, (BT_HDR *)NULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ops_obx_get
+**
+** Description Process the OBX pull vCard object.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ops_obx_get(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data)
+{
+ /* this is a new request; validate it */
+ if (bta_ops_cb.obx_oper != OPS_OP_PULL_OBJ)
+ bta_ops_init_get_obj(p_cb, p_data);
+ else /* this is a continuation request */
+ bta_ops_proc_get_obj(p_cb);
+
+ /* done with Obex packet */
+ utl_freebuf((void**)&p_data->obx_evt.p_pkt);
+}
+
+/*******************************************************************************
+**
+** Function bta_ops_close_complete
+**
+** Description Finishes the memory cleanup after a channel is closed.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ops_close_complete(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data)
+{
+
+ /* inform role manager */
+ bta_sys_conn_close( BTA_ID_OPS ,p_cb->app_id, bta_ops_cb.bd_addr);
+
+ p_cb->cout_active = FALSE;
+
+ bta_ops_clean_getput(p_cb, TRUE);
+
+ /* Notify the MMI that a connection has been closed */
+ p_cb->p_cback(BTA_OPS_CLOSE_EVT, (tBTA_OPS*)p_cb->bd_addr);
+ memset(p_cb->bd_addr, 0, BD_ADDR_LEN);
+
+ if (p_data->obx_evt.p_pkt)
+ APPL_TRACE_WARNING0("OPS: OBX CLOSE CALLED WITH non-NULL Packet!!!");
+}
+
+/*****************************************************************************
+** Callback Functions
+*****************************************************************************/
+/*******************************************************************************
+**
+** Function bta_ops_obx_cback
+**
+** Description OBX callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ops_obx_cback (tOBX_HANDLE handle, tOBX_EVENT obx_event,
+ tOBX_EVT_PARAM param, BT_HDR *p_pkt)
+{
+ tBTA_OPS_OBX_EVENT *p_obx_msg;
+ UINT16 event = 0;
+
+#if BTA_OPS_DEBUG == TRUE
+ APPL_TRACE_DEBUG1("OBX Event Callback: ops_obx_event[%s]", ops_obx_evt_code(obx_event));
+#endif
+
+ switch(obx_event)
+ {
+ case OBX_CONNECT_REQ_EVT:
+ event = BTA_OPS_OBX_CONN_EVT;
+ break;
+ case OBX_DISCONNECT_REQ_EVT:
+ event = BTA_OPS_OBX_DISC_EVT;
+ break;
+ case OBX_PUT_REQ_EVT:
+ event = BTA_OPS_OBX_PUT_EVT;
+ break;
+ case OBX_GET_REQ_EVT:
+ event = BTA_OPS_OBX_GET_EVT;
+ break;
+ case OBX_ABORT_REQ_EVT:
+ event = BTA_OPS_OBX_ABORT_EVT;
+ break;
+ case OBX_CLOSE_IND_EVT:
+ event = BTA_OPS_OBX_CLOSE_EVT;
+ break;
+ case OBX_TIMEOUT_EVT:
+ break;
+ default:
+ /* Unrecognized packet; disconnect the session */
+ if (p_pkt)
+ event = BTA_OPS_OBX_DISC_EVT;
+ }
+
+ /* send event to BTA, if any */
+ if (event && (p_obx_msg =
+ (tBTA_OPS_OBX_EVENT *) GKI_getbuf(sizeof(tBTA_OPS_OBX_EVENT))) != NULL)
+ {
+ p_obx_msg->hdr.event = event;
+ p_obx_msg->obx_event = obx_event;
+ p_obx_msg->handle = handle;
+ p_obx_msg->param = param;
+ p_obx_msg->p_pkt = p_pkt;
+
+ bta_sys_sendmsg(p_obx_msg);
+ }
+}
+
+/*****************************************************************************
+** Debug Functions
+*****************************************************************************/
+#if BTA_OPS_DEBUG == TRUE
+
+/*******************************************************************************
+**
+** Function ops_obx_evt_code
+**
+** Description
+**
+** Returns void
+**
+*******************************************************************************/
+static char *ops_obx_evt_code(tOBX_EVENT evt_code)
+{
+ switch(evt_code)
+ {
+ case OBX_CONNECT_REQ_EVT:
+ return "OBX_CONNECT_REQ_EVT";
+ case OBX_DISCONNECT_REQ_EVT:
+ return "OBX_DISCONNECT_REQ_EVT";
+ case OBX_PUT_REQ_EVT:
+ return "OBX_PUT_REQ_EVT";
+ case OBX_GET_REQ_EVT:
+ return "OBX_GET_REQ_EVT";
+ case OBX_SETPATH_REQ_EVT:
+ return "OBX_SETPATH_REQ_EVT";
+ case OBX_ABORT_REQ_EVT:
+ return "OBX_ABORT_REQ_EVT";
+ case OBX_CLOSE_IND_EVT:
+ return "OBX_CLOSE_IND_EVT";
+ case OBX_TIMEOUT_EVT:
+ return "OBX_TIMEOUT_EVT";
+ case OBX_PASSWORD_EVT:
+ return "OBX_PASSWORD_EVT";
+ case OBX_SESSION_REQ_EVT:
+ return "OBX_SESSION_REQ_EVT";
+ case OBX_ACTION_REQ_EVT:
+ return "OBX_ACTION_REQ_EVT";
+ default:
+ return "unknown OBX event code";
+ }
+}
+#endif /* Debug Functions */
+#endif /* BTA_OP_INCLUDED */
diff --git a/bta/op/bta_ops_api.c b/bta/op/bta_ops_api.c
new file mode 100644
index 0000000..1c09094
--- /dev/null
+++ b/bta/op/bta_ops_api.c
@@ -0,0 +1,153 @@
+/*****************************************************************************
+**
+** Name: bta_ops_api.c
+**
+** Description: This is the implementation of the API for the object
+** push server subsystem of BTA, Widcomm's Bluetooth
+** application layer for mobile phones.
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+
+#if defined(BTA_OP_INCLUDED) && (BTA_OP_INCLUDED)
+
+#include <string.h>
+#include "gki.h"
+#include "bta_sys.h"
+#include "bta_fs_api.h"
+#include "bta_op_api.h"
+#include "bta_ops_int.h"
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+static const tBTA_SYS_REG bta_ops_reg =
+{
+ bta_ops_hdl_event,
+ BTA_OpsDisable
+};
+
+/*******************************************************************************
+**
+** Function BTA_OpsEnable
+**
+** Description Enable the object push server. This function must be
+** called before any other functions in the OPS API are called.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_OpsEnable(tBTA_SEC sec_mask, tBTA_OP_FMT_MASK formats,
+ char *p_service_name, tBTA_OPS_CBACK *p_cback, BOOLEAN srm, UINT8 app_id)
+{
+ tBTA_OPS_API_ENABLE *p_buf;
+
+ GKI_sched_lock();
+ /* register with BTA system manager */
+ bta_sys_register(BTA_ID_OPS, &bta_ops_reg);
+ GKI_sched_unlock();
+
+ if ((p_buf = (tBTA_OPS_API_ENABLE *) GKI_getbuf(sizeof(tBTA_OPS_API_ENABLE))) != NULL)
+ {
+ p_buf->hdr.event = BTA_OPS_API_ENABLE_EVT;
+ BCM_STRNCPY_S(p_buf->name, sizeof(p_buf->name), p_service_name, BTA_SERVICE_NAME_LEN);
+ p_buf->name[BTA_SERVICE_NAME_LEN] = '\0';
+ p_buf->p_cback = p_cback;
+ p_buf->app_id = app_id;
+ p_buf->formats = formats;
+ p_buf->sec_mask = sec_mask;
+ p_buf->srm = srm;
+
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_OpsDisable
+**
+** Description Disable the object push server. If the server is currently
+** connected to a peer device the connection will be closed.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_OpsDisable(void)
+{
+ BT_HDR *p_buf;
+
+ bta_sys_deregister(BTA_ID_OPS);
+ if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->event = BTA_OPS_API_DISABLE_EVT;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_OpsClose
+**
+** Description Close the current connection. This function is called if
+** the phone wishes to close the connection before the object
+** push is completed.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_OpsClose(void)
+{
+ BT_HDR *p_buf;
+
+ if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->event = BTA_OPS_API_CLOSE_EVT;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_OpsAccessRsp
+**
+** Description Sends a reply to an access request event (BTA_OPS_ACCESS_EVT).
+** This call MUST be made whenever the event occurs.
+**
+** Parameters oper - operation being accessed.
+** access - BTA_OP_ACCESS_ALLOW, BTA_OP_ACCESS_FORBID, or
+** BTA_OP_ACCESS_NONSUP.
+** p_name - Full path of file to read from (pull) or write to
+** (push).
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_OpsAccessRsp(tBTA_OP_OPER oper, tBTA_OP_ACCESS access, char *p_name)
+{
+ tBTA_OPS_API_ACCESSRSP *p_buf;
+
+ if ((p_buf = (tBTA_OPS_API_ACCESSRSP *)GKI_getbuf((UINT16)(sizeof(tBTA_OPS_API_ACCESSRSP)
+ + p_bta_fs_cfg->max_path_len + 1))) != NULL)
+ {
+ p_buf->flag = access;
+ p_buf->oper = oper;
+ p_buf->p_name = (char *)(p_buf + 1);
+ if (p_name)
+ {
+ BCM_STRNCPY_S(p_buf->p_name, p_bta_fs_cfg->max_path_len+1, p_name, p_bta_fs_cfg->max_path_len);
+ p_buf->p_name[p_bta_fs_cfg->max_path_len] = '\0';
+ }
+ else
+ *p_buf->p_name = '\0';
+
+ p_buf->hdr.event = BTA_OPS_API_ACCESSRSP_EVT;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+#endif /* BTA_OP_INCLUDED */
diff --git a/bta/op/bta_ops_int.h b/bta/op/bta_ops_int.h
new file mode 100644
index 0000000..733b9ae
--- /dev/null
+++ b/bta/op/bta_ops_int.h
@@ -0,0 +1,198 @@
+/*****************************************************************************
+**
+** Name: bta_ops_int.h
+**
+** Description: This is the private file for the object transfer
+** server (OPS).
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_OPS_INT_H
+#define BTA_OPS_INT_H
+
+#include "bt_target.h"
+#include "bta_sys.h"
+#include "obx_api.h"
+#include "bta_op_api.h"
+#include "bta_fs_co.h"
+#include "bta_fs_ci.h"
+
+/*****************************************************************************
+** Constants and data types
+*****************************************************************************/
+
+
+/* OPS active obex operation (Valid in connected state) */
+#define OPS_OP_NONE 0
+#define OPS_OP_PULL_OBJ 1
+#define OPS_OP_PUSH_OBJ 2
+
+/* state machine events */
+enum
+{
+ /* these events are handled by the state machine */
+ BTA_OPS_API_DISABLE_EVT = BTA_SYS_EVT_START(BTA_ID_OPS),
+
+ BTA_OPS_API_ACCESSRSP_EVT, /* Response to an access request */
+ BTA_OPS_API_CLOSE_EVT, /* Close API */
+ BTA_OPS_CI_OPEN_EVT, /* Response to File Open request */
+ BTA_OPS_CI_WRITE_EVT, /* Response to Write request */
+ BTA_OPS_CI_READ_EVT, /* Response to Read request */
+ BTA_OPS_OBX_CONN_EVT, /* OBX Channel Connect Request */
+ BTA_OPS_OBX_DISC_EVT, /* OBX Channel Disconnect */
+ BTA_OPS_OBX_ABORT_EVT, /* OBX_operation aborted */
+ BTA_OPS_OBX_CLOSE_EVT, /* OBX Channel Disconnected (Link Lost) */
+ BTA_OPS_OBX_PUT_EVT, /* Write file data or delete */
+ BTA_OPS_OBX_GET_EVT, /* Read file data or folder listing */
+ BTA_OPS_CLOSE_CMPL_EVT, /* Finished closing channel */
+
+ /* these events are handled outside the state machine */
+ BTA_OPS_API_ENABLE_EVT
+};
+
+typedef UINT16 tBTA_OPS_INT_EVT;
+
+typedef UINT8 tBTA_OPS_STATE;
+
+/* data type for BTA_OPS_API_ENABLE_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ char name[BTA_SERVICE_NAME_LEN + 1];
+ tBTA_OPS_CBACK *p_cback;
+ tBTA_OP_FMT_MASK formats;
+ UINT8 sec_mask;
+ BOOLEAN srm;
+ UINT8 app_id;
+} tBTA_OPS_API_ENABLE;
+
+/* data type for BTA_OPS_API_ACCESSRSP_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ char *p_name;
+ tBTA_OP_OPER oper;
+ tBTA_OP_ACCESS flag;
+} tBTA_OPS_API_ACCESSRSP;
+
+/* data type for all obex events
+ hdr.event contains the OPS event
+*/
+typedef struct
+{
+ BT_HDR hdr;
+ tOBX_HANDLE handle;
+ tOBX_EVT_PARAM param;
+ BT_HDR *p_pkt;
+ tOBX_EVENT obx_event;
+ UINT8 rsp_code;
+} tBTA_OPS_OBX_EVENT;
+
+/* union of all event data types */
+typedef union
+{
+ BT_HDR hdr;
+ tBTA_OPS_API_ENABLE api_enable;
+ tBTA_OPS_API_ACCESSRSP api_access;
+ tBTA_OPS_OBX_EVENT obx_evt;
+ tBTA_FS_CI_OPEN_EVT open_evt;
+ tBTA_FS_CI_READ_EVT read_evt;
+ tBTA_FS_CI_WRITE_EVT write_evt;
+} tBTA_OPS_DATA;
+
+/* OBX Response Packet Structure - Holds current response packet info */
+typedef struct
+{
+ BT_HDR *p_pkt; /* (Pull/Push) Holds the current OBX hdr for Push or Pull */
+ UINT8 *p_start; /* (Pull/Push) Start of the Body of the packet */
+ UINT16 offset; /* (Pull/Push) Contains the current offset into the Body (p_start) */
+ UINT16 bytes_left; /* (Pull/Push) Holds bytes available left in Obx packet */
+ BOOLEAN final_pkt; /* (Push) Holds the final bit of the Push packet */
+} tBTA_OPS_OBX_PKT;
+
+/* Power management state for OPS */
+#define BTA_OPS_PM_BUSY 0
+#define BTA_OPS_PM_IDLE 1
+
+/* OPS control block */
+typedef struct
+{
+ tBTA_OPS_CBACK *p_cback; /* pointer to application callback function */
+ char *p_name; /* Holds name of current operation */
+ char *p_path; /* Holds path of current operation */
+ tBTA_OPS_OBX_PKT obx; /* Holds the current OBX packet information */
+ UINT32 sdp_handle; /* SDP record handle */
+ UINT32 file_length; /* length of file being Push/Pull */
+ int fd; /* File Descriptor of opened file */
+ BD_ADDR bd_addr; /* Device currently connected to */
+ tOBX_HANDLE obx_handle;
+ UINT16 peer_mtu;
+ UINT16 psm; /* PSM for Obex Over L2CAP */
+ BOOLEAN srm; /* TRUE, to use SIngle Response Mode */
+ UINT8 scn; /* SCN of the OPP server */
+ tBTA_OP_FMT_MASK formats; /* supported object formats */
+ tBTA_OPS_STATE state; /* state machine state */
+ tBTA_OP_FMT obj_fmt; /* file format of received object */
+ UINT8 obx_oper; /* current active OBX operation PUSH OBJ, or PULL OBJ */
+ UINT8 app_id;
+ tBTA_OP_OPER acc_active; /* op code when waiting for an access rsp (API) (0 not active) */
+ BOOLEAN cout_active; /* TRUE when waiting for a call-in function */
+ BOOLEAN aborting; /* TRUE when waiting for a call-in function */
+ UINT8 pm_state;
+} tBTA_OPS_CB;
+
+/*****************************************************************************
+** Global data
+*****************************************************************************/
+
+/* OPS control block */
+#if BTA_DYNAMIC_MEMORY == FALSE
+extern tBTA_OPS_CB bta_ops_cb;
+#else
+extern tBTA_OPS_CB *bta_ops_cb_ptr;
+#define bta_ops_cb (*bta_ops_cb_ptr)
+#endif
+
+
+/*****************************************************************************
+** Function prototypes
+*****************************************************************************/
+
+extern BOOLEAN bta_ops_hdl_event(BT_HDR *p_msg);
+extern void bta_ops_sm_execute(tBTA_OPS_CB *p_cb, UINT16 event, tBTA_OPS_DATA *p_data);
+extern void bta_ops_obx_cback (tOBX_HANDLE handle, tOBX_EVENT event,
+ tOBX_EVT_PARAM param, BT_HDR *p_pkt);
+
+/* action functions */
+extern void bta_ops_api_disable(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data);
+extern void bta_ops_api_accessrsp(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data);
+extern void bta_ops_api_close(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data);
+extern void bta_ops_ci_write(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data);
+extern void bta_ops_ci_read(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data);
+extern void bta_ops_ci_open(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data);
+extern void bta_ops_obx_connect(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data);
+extern void bta_ops_obx_disc(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data);
+extern void bta_ops_obx_close(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data);
+extern void bta_ops_obx_abort(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data);
+extern void bta_ops_obx_put(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data);
+extern void bta_ops_obx_get(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data);
+extern void bta_ops_gasp_err_rsp(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data);
+extern void bta_ops_close_complete(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data);
+
+/* object store */
+extern void bta_ops_init_get_obj(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data);
+extern void bta_ops_proc_get_obj(tBTA_OPS_CB *p_cb);
+extern void bta_ops_proc_put_obj(BT_HDR *p_pkt);
+
+/* miscellaneous functions */
+extern void bta_ops_enable(tBTA_OPS_CB *p_cb, tBTA_OPS_API_ENABLE *p_data);
+extern void bta_ops_get_obj_rsp(UINT8 rsp_code, UINT16 num_read);
+extern void bta_ops_put_obj_rsp(UINT8 rsp_code);
+extern void bta_ops_clean_getput(tBTA_OPS_CB *p_cb, BOOLEAN is_aborted);
+extern void bta_ops_discard_data(UINT16 event, tBTA_OPS_DATA *p_data);
+extern void bta_ops_req_app_access (tBTA_OP_OPER oper, tBTA_OPS_CB *p_cb);
+extern tBTA_OP_FMT bta_ops_fmt_supported(char *p, tBTA_OP_FMT_MASK fmt_mask);
+
+#endif /* BTA_OPS_INT_H */
diff --git a/bta/op/bta_ops_main.c b/bta/op/bta_ops_main.c
new file mode 100644
index 0000000..f98b43b
--- /dev/null
+++ b/bta/op/bta_ops_main.c
@@ -0,0 +1,412 @@
+/*****************************************************************************
+**
+** Name: bta_ops_main.c
+**
+** Description: This file contains the file transfer server main functions
+** and state machine.
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+
+#if defined(BTA_OP_INCLUDED) && (BTA_OP_INCLUDED)
+
+#include <string.h>
+
+#include "bta_fs_api.h"
+#include "bta_ops_int.h"
+#include "gki.h"
+#include "obx_api.h"
+
+/*****************************************************************************
+** Constants and types
+*****************************************************************************/
+
+/* state machine states */
+enum
+{
+ BTA_OPS_IDLE_ST = 0, /* Idle */
+ BTA_OPS_LISTEN_ST, /* Listen - waiting for OBX/RFC connection */
+ BTA_OPS_CONN_ST, /* Connected - OPP Session is active */
+ BTA_OPS_CLOSING_ST /* Closing is in progress */
+};
+
+/* state machine action enumeration list */
+enum
+{
+ BTA_OPS_API_DISABLE,
+ BTA_OPS_API_ACCESSRSP,
+ BTA_OPS_API_CLOSE,
+ BTA_OPS_CI_WRITE,
+ BTA_OPS_CI_READ,
+ BTA_OPS_CI_OPEN,
+ BTA_OPS_OBX_CONNECT,
+ BTA_OPS_OBX_DISC,
+ BTA_OPS_OBX_CLOSE,
+ BTA_OPS_OBX_ABORT,
+ BTA_OPS_OBX_PUT,
+ BTA_OPS_OBX_GET,
+ BTA_OPS_CLOSE_COMPLETE,
+ BTA_OPS_IGNORE
+};
+
+/* type for action functions */
+typedef void (*tBTA_OPS_ACTION)(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data);
+
+/* action function list */
+const tBTA_OPS_ACTION bta_ops_action[] =
+{
+ bta_ops_api_disable,
+ bta_ops_api_accessrsp,
+ bta_ops_api_close,
+ bta_ops_ci_write,
+ bta_ops_ci_read,
+ bta_ops_ci_open,
+ bta_ops_obx_connect,
+ bta_ops_obx_disc,
+ bta_ops_obx_close,
+ bta_ops_obx_abort,
+ bta_ops_obx_put,
+ bta_ops_obx_get,
+ bta_ops_close_complete
+};
+
+
+/* state table information */
+#define BTA_OPS_ACTIONS 1 /* number of actions */
+#define BTA_OPS_NEXT_STATE 1 /* position of next state */
+#define BTA_OPS_NUM_COLS 2 /* number of columns in state tables */
+
+/* state table for idle state */
+static const UINT8 bta_ops_st_idle[][BTA_OPS_NUM_COLS] =
+{
+/* Event Action 1 Next state */
+/* BTA_OPS_API_DISABLE_EVT */ {BTA_OPS_IGNORE, BTA_OPS_IDLE_ST},
+/* BTA_OPS_API_ACCESSRSP_EVT */ {BTA_OPS_IGNORE, BTA_OPS_IDLE_ST},
+/* BTA_OPS_API_CLOSE_EVT */ {BTA_OPS_IGNORE, BTA_OPS_IDLE_ST},
+};
+
+/* state table for obex/rfcomm connection state */
+static const UINT8 bta_ops_st_listen[][BTA_OPS_NUM_COLS] =
+{
+/* Event Action 1 Next state */
+/* BTA_OPS_API_DISABLE_EVT */ {BTA_OPS_API_DISABLE, BTA_OPS_IDLE_ST},
+/* BTA_OPS_API_ACCESSRSP_EVT */ {BTA_OPS_IGNORE, BTA_OPS_LISTEN_ST},
+/* BTA_OPS_API_CLOSE_EVT */ {BTA_OPS_IGNORE, BTA_OPS_LISTEN_ST},
+/* BTA_OPS_CI_OPEN_EVT */ {BTA_OPS_IGNORE, BTA_OPS_LISTEN_ST},
+/* BTA_OPS_CI_WRITE_EVT */ {BTA_OPS_IGNORE, BTA_OPS_LISTEN_ST},
+/* BTA_OPS_CI_READ_EVT */ {BTA_OPS_IGNORE, BTA_OPS_LISTEN_ST},
+/* BTA_OPS_OBX_CONN_EVT */ {BTA_OPS_OBX_CONNECT, BTA_OPS_CONN_ST},
+/* BTA_OPS_OBX_DISC_EVT */ {BTA_OPS_IGNORE, BTA_OPS_LISTEN_ST},
+/* BTA_OPS_OBX_ABORT_EVT */ {BTA_OPS_IGNORE, BTA_OPS_LISTEN_ST},
+/* BTA_OPS_OBX_CLOSE_EVT */ {BTA_OPS_IGNORE, BTA_OPS_LISTEN_ST},
+/* BTA_OPS_OBX_PUT_EVT */ {BTA_OPS_IGNORE, BTA_OPS_LISTEN_ST},
+/* BTA_OPS_OBX_GET_EVT */ {BTA_OPS_IGNORE, BTA_OPS_LISTEN_ST},
+/* BTA_OPS_CLOSE_CMPL_EVT */ {BTA_OPS_IGNORE, BTA_OPS_LISTEN_ST}
+};
+
+/* state table for open state */
+static const UINT8 bta_ops_st_connected[][BTA_OPS_NUM_COLS] =
+{
+/* Event Action 1 Next state */
+/* BTA_OPS_API_DISABLE_EVT */ {BTA_OPS_API_DISABLE, BTA_OPS_IDLE_ST},
+/* BTA_OPS_API_ACCESSRSP_EVT */ {BTA_OPS_API_ACCESSRSP, BTA_OPS_CONN_ST},
+/* BTA_OPS_API_CLOSE_EVT */ {BTA_OPS_API_CLOSE, BTA_OPS_CLOSING_ST},
+/* BTA_OPS_CI_OPEN_EVT */ {BTA_OPS_CI_OPEN, BTA_OPS_CONN_ST},
+/* BTA_OPS_CI_WRITE_EVT */ {BTA_OPS_CI_WRITE, BTA_OPS_CONN_ST},
+/* BTA_OPS_CI_READ_EVT */ {BTA_OPS_CI_READ, BTA_OPS_CONN_ST},
+/* BTA_OPS_OBX_CONN_EVT */ {BTA_OPS_IGNORE, BTA_OPS_CONN_ST},
+/* BTA_OPS_OBX_DISC_EVT */ {BTA_OPS_OBX_DISC, BTA_OPS_CLOSING_ST},
+/* BTA_OPS_OBX_ABORT_EVT */ {BTA_OPS_OBX_ABORT, BTA_OPS_CONN_ST},
+/* BTA_OPS_OBX_CLOSE_EVT */ {BTA_OPS_OBX_CLOSE, BTA_OPS_CLOSING_ST},
+/* BTA_OPS_OBX_PUT_EVT */ {BTA_OPS_OBX_PUT, BTA_OPS_CONN_ST},
+/* BTA_OPS_OBX_GET_EVT */ {BTA_OPS_OBX_GET, BTA_OPS_CONN_ST},
+/* BTA_OPS_CLOSE_CMPL_EVT */ {BTA_OPS_IGNORE, BTA_OPS_CONN_ST}
+};
+
+/* state table for closing state */
+static const UINT8 bta_ops_st_closing[][BTA_OPS_NUM_COLS] =
+{
+/* Event Action 1 Next state */
+/* BTA_OPS_API_DISABLE_EVT */ {BTA_OPS_API_DISABLE, BTA_OPS_IDLE_ST},
+/* BTA_OPS_API_ACCESSRSP_EVT */ {BTA_OPS_IGNORE, BTA_OPS_CLOSING_ST},
+/* BTA_OPS_API_CLOSE_EVT */ {BTA_OPS_IGNORE, BTA_OPS_CLOSING_ST},
+/* BTA_OPS_CI_OPEN_EVT */ {BTA_OPS_CLOSE_COMPLETE, BTA_OPS_LISTEN_ST},
+/* BTA_OPS_CI_WRITE_EVT */ {BTA_OPS_CLOSE_COMPLETE, BTA_OPS_LISTEN_ST},
+/* BTA_OPS_CI_READ_EVT */ {BTA_OPS_CLOSE_COMPLETE, BTA_OPS_LISTEN_ST},
+/* BTA_OPS_OBX_CONN_EVT */ {BTA_OPS_IGNORE, BTA_OPS_CLOSING_ST},
+/* BTA_OPS_OBX_DISC_EVT */ {BTA_OPS_IGNORE, BTA_OPS_CLOSING_ST},
+/* BTA_OPS_OBX_ABORT_EVT */ {BTA_OPS_OBX_ABORT, BTA_OPS_CLOSING_ST},
+/* BTA_OPS_OBX_CLOSE_EVT */ {BTA_OPS_OBX_CLOSE, BTA_OPS_CLOSING_ST},
+/* BTA_OPS_OBX_PUT_EVT */ {BTA_OPS_IGNORE, BTA_OPS_CLOSING_ST},
+/* BTA_OPS_OBX_GET_EVT */ {BTA_OPS_IGNORE, BTA_OPS_CLOSING_ST},
+/* BTA_OPS_CLOSE_CMPL_EVT */ {BTA_OPS_CLOSE_COMPLETE, BTA_OPS_LISTEN_ST}
+};
+
+/* type for state table */
+typedef const UINT8 (*tBTA_OPS_ST_TBL)[BTA_OPS_NUM_COLS];
+
+/* state table */
+const tBTA_OPS_ST_TBL bta_ops_st_tbl[] =
+{
+ bta_ops_st_idle,
+ bta_ops_st_listen,
+ bta_ops_st_connected,
+ bta_ops_st_closing
+};
+
+/*****************************************************************************
+** Global data
+*****************************************************************************/
+
+/* OPS control block */
+#if BTA_DYNAMIC_MEMORY == FALSE
+tBTA_OPS_CB bta_ops_cb;
+#endif
+
+#if BTA_OPS_DEBUG == TRUE
+static char *ops_evt_code(tBTA_OPS_INT_EVT evt_code);
+static char *ops_state_code(tBTA_OPS_STATE state_code);
+#endif
+
+/*******************************************************************************
+**
+** Function bta_ops_sm_execute
+**
+** Description State machine event handling function for OPS
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ops_sm_execute(tBTA_OPS_CB *p_cb, UINT16 event, tBTA_OPS_DATA *p_data)
+{
+ tBTA_OPS_ST_TBL state_table;
+ UINT8 action;
+ int i;
+#if BTA_OPS_DEBUG == TRUE
+ tBTA_OPS_STATE in_state = bta_ops_cb.state;
+ UINT16 in_event = event;
+ APPL_TRACE_EVENT3("OPS Event Handler: State 0x%02x [%s], Event [%s]", in_state,
+ ops_state_code(in_state),
+ ops_evt_code(event));
+#endif
+
+ /* look up the state table for the current state */
+ state_table = bta_ops_st_tbl[p_cb->state];
+
+ event &= 0x00FF;
+
+ /* set next state */
+ p_cb->state = state_table[event][BTA_OPS_NEXT_STATE];
+
+ /* execute action functions */
+ for (i = 0; i < BTA_OPS_ACTIONS; i++)
+ {
+ if ((action = state_table[event][i]) != BTA_OPS_IGNORE)
+ {
+ (*bta_ops_action[action])(p_cb, p_data);
+ }
+ else
+ {
+ /* discard ops data */
+ bta_ops_discard_data(p_data->hdr.event, p_data);
+ break;
+ }
+ }
+
+#if BTA_OPS_DEBUG == TRUE
+ if (in_state != bta_ops_cb.state)
+ {
+ APPL_TRACE_DEBUG3("OPS State Change: [%s] -> [%s] after Event [%s]",
+ ops_state_code(in_state),
+ ops_state_code(bta_ops_cb.state),
+ ops_evt_code(in_event));
+ }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function bta_ops_api_enable
+**
+** Description Handle an api enable event. This function enables the OP
+** Server by opening an Obex/Rfcomm channel and placing it into
+** listen mode.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ops_api_enable(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data)
+{
+ tBTA_OPS_API_ENABLE *p_enable = &p_data->api_enable;
+
+ /* initialize control block */
+ memset(p_cb, 0, sizeof(tBTA_OPS_CB));
+ p_cb->p_cback = p_enable->p_cback;
+ p_cb->app_id = p_enable->app_id;
+ p_cb->srm = p_enable->srm;
+ p_cb->fd = BTA_FS_INVALID_FD;
+
+ bta_ops_cb.state = BTA_OPS_LISTEN_ST;
+
+ /* call enable action function */
+ bta_ops_enable(p_cb, p_enable);
+}
+
+/*******************************************************************************
+**
+** Function bta_ops_hdl_event
+**
+** Description File transfer server main event handling function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BOOLEAN bta_ops_hdl_event(BT_HDR *p_msg)
+{
+#if BTA_OPS_DEBUG == TRUE
+ tBTA_OPS_STATE in_state = bta_ops_cb.state;
+#endif
+
+ switch (p_msg->event)
+ {
+ case BTA_OPS_API_ENABLE_EVT:
+#if BTA_OPS_DEBUG == TRUE
+ APPL_TRACE_EVENT3("OPS Event Handler: State 0x%02x [%s], Event [%s]", in_state,
+ ops_state_code(in_state),
+ ops_evt_code(p_msg->event));
+#endif
+ bta_ops_api_enable(&bta_ops_cb, (tBTA_OPS_DATA *) p_msg);
+
+#if BTA_OPS_DEBUG == TRUE
+ if (in_state != bta_ops_cb.state)
+ {
+ APPL_TRACE_DEBUG3("OPS State Change: [%s] -> [%s] after Event [%s]",
+ ops_state_code(in_state),
+ ops_state_code(bta_ops_cb.state),
+ ops_evt_code(p_msg->event));
+ }
+#endif
+ break;
+
+ default:
+
+ bta_ops_sm_execute(&bta_ops_cb, p_msg->event, (tBTA_OPS_DATA *) p_msg);
+
+ if ( bta_ops_cb.state == BTA_OPS_CONN_ST )
+ {
+ if (( bta_ops_cb.pm_state == BTA_OPS_PM_IDLE )
+ &&( bta_ops_cb.obx_oper != OPS_OP_NONE ))
+ {
+ /* inform power manager */
+ APPL_TRACE_DEBUG0("BTA OPS informs DM/PM busy state");
+ bta_sys_busy( BTA_ID_OPS ,bta_ops_cb.app_id, bta_ops_cb.bd_addr);
+ bta_ops_cb.pm_state = BTA_OPS_PM_BUSY;
+ }
+ else if (( bta_ops_cb.pm_state == BTA_OPS_PM_BUSY )
+ &&( bta_ops_cb.obx_oper == OPS_OP_NONE ))
+ {
+ /* inform power manager */
+ APPL_TRACE_DEBUG0("BTA OPS informs DM/PM idle state");
+ bta_sys_idle( BTA_ID_OPS ,bta_ops_cb.app_id, bta_ops_cb.bd_addr);
+ bta_ops_cb.pm_state = BTA_OPS_PM_IDLE;
+ }
+ }
+ else if ( bta_ops_cb.state == BTA_OPS_LISTEN_ST )
+ {
+ /* initialize power management state */
+ bta_ops_cb.pm_state = BTA_OPS_PM_BUSY;
+ }
+
+ break;
+ }
+
+ return (TRUE);
+}
+
+
+/*****************************************************************************
+** Debug Functions
+*****************************************************************************/
+#if BTA_OPS_DEBUG == TRUE
+
+/*******************************************************************************
+**
+** Function ops_evt_code
+**
+** Description
+**
+** Returns void
+**
+*******************************************************************************/
+static char *ops_evt_code(tBTA_OPS_INT_EVT evt_code)
+{
+ switch(evt_code)
+ {
+ case BTA_OPS_API_DISABLE_EVT:
+ return "BTA_OPS_API_DISABLE_EVT";
+ case BTA_OPS_API_ACCESSRSP_EVT:
+ return "BTA_OPS_API_ACCESSRSP_EVT";
+ case BTA_OPS_API_CLOSE_EVT:
+ return "BTA_OPS_API_CLOSE_EVT";
+ case BTA_OPS_CI_OPEN_EVT:
+ return "BTA_OPS_CI_OPEN_EVT";
+ case BTA_OPS_CI_WRITE_EVT:
+ return "BTA_OPS_CI_WRITE_EVT";
+ case BTA_OPS_CI_READ_EVT:
+ return "BTA_OPS_CI_READ_EVT";
+ case BTA_OPS_OBX_CONN_EVT:
+ return "BTA_OPS_OBX_CONN_EVT";
+ case BTA_OPS_OBX_DISC_EVT:
+ return "BTA_OPS_OBX_DISC_EVT";
+ case BTA_OPS_OBX_ABORT_EVT:
+ return "BTA_OPS_OBX_ABORT_EVT";
+ case BTA_OPS_OBX_CLOSE_EVT:
+ return "BTA_OPS_OBX_CLOSE_EVT";
+ case BTA_OPS_OBX_PUT_EVT:
+ return "BTA_OPS_OBX_PUT_EVT";
+ case BTA_OPS_OBX_GET_EVT:
+ return "BTA_OPS_OBX_GET_EVT";
+ case BTA_OPS_CLOSE_CMPL_EVT:
+ return "BTA_OPS_CLOSE_CMPL_EVT";
+ case BTA_OPS_API_ENABLE_EVT:
+ return "BTA_OPS_API_ENABLE_EVT";
+ default:
+ return "unknown OPS event code";
+ }
+}
+
+/*******************************************************************************
+**
+** Function ops_evt_code
+**
+** Description
+**
+** Returns void
+**
+*******************************************************************************/
+static char *ops_state_code(tBTA_OPS_STATE state_code)
+{
+ switch(state_code)
+ {
+ case BTA_OPS_IDLE_ST:
+ return "BTA_OPS_IDLE_ST";
+ case BTA_OPS_LISTEN_ST:
+ return "BTA_OPS_LISTEN_ST";
+ case BTA_OPS_CONN_ST:
+ return "BTA_OPS_CONN_ST";
+ case BTA_OPS_CLOSING_ST:
+ return "BTA_OPS_CLOSING_ST";
+ default:
+ return "unknown OPS state code";
+ }
+}
+
+#endif /* Debug Functions */
+#endif /* BTA_OP_INCLUDED */
diff --git a/bta/op/bta_ops_utils.c b/bta/op/bta_ops_utils.c
new file mode 100644
index 0000000..eccc1e7
--- /dev/null
+++ b/bta/op/bta_ops_utils.c
@@ -0,0 +1,487 @@
+/*****************************************************************************
+**
+** Name: bta_ops_utils.c
+**
+** Description: This file implements object store functions for the
+** object transfer server.
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+
+#if defined(BTA_OP_INCLUDED) && (BTA_OP_INCLUDED)
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include "bta_fs_api.h"
+#include "bta_ops_int.h"
+#include "bta_fs_co.h"
+#include "gki.h"
+#include "utl.h"
+#include "bd.h"
+
+/*******************************************************************************
+** Constants
+*******************************************************************************/
+
+/*******************************************************************************
+** Local Function Prototypes
+*******************************************************************************/
+static int bta_ops_stricmp (const char *p_str1, const char *p_str2);
+
+/*******************************************************************************
+* Exported Functions
+*******************************************************************************/
+/*******************************************************************************
+**
+** Function bta_ops_init_get_obj
+**
+** Description Processes a begin object pull request.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ops_init_get_obj(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data)
+{
+ tBTA_OPS_OBX_EVENT *p_evt = &p_data->obx_evt;
+ UINT8 rsp_code = OBX_RSP_FORBIDDEN;
+ UINT16 len;
+ UINT8 *p_type;
+ UINT16 name_len;
+
+ /* Type Hdr must be present */
+ if (OBX_ReadTypeHdr(p_evt->p_pkt, &p_type, &len))
+ {
+ /* Type Hdr must be correct */
+ if (!bta_ops_stricmp((const char *)p_type, "text/x-vcard"))
+ {
+ /* Erratum 385 - original OPP spec says "Name Header must not be used."
+ * errara says "Name Header must be empty"
+ * Be a forgiving OPP server, allow either way */
+ name_len = OBX_ReadHdrLen(p_evt->p_pkt, OBX_HI_NAME);
+ if((name_len == OBX_INVALID_HDR_LEN) ||/* no name header */
+ (name_len == 3) /* name header is empty */ )
+ {
+ p_cb->obx.p_pkt = (BT_HDR *)OBX_HdrInit(p_cb->obx_handle,
+ /*p_cb->peer_mtu*/OBX_CMD_POOL_SIZE);
+ p_cb->p_path = (char *)GKI_getbuf((UINT16)(p_bta_fs_cfg->max_path_len + 1));
+
+ if (p_cb->p_path && p_cb->obx.p_pkt)
+ {
+ p_cb->p_path[0] = '\0';
+ p_cb->p_name = p_cb->p_path;
+ p_cb->obx_oper = OPS_OP_PULL_OBJ;
+ p_cb->obj_fmt = BTA_OP_VCARD21_FMT;
+ p_cb->file_length = BTA_FS_LEN_UNKNOWN;
+
+ /* Notify the appl that a pull default card has been requested */
+ bta_ops_req_app_access (BTA_OP_OPER_PULL, p_cb);
+ rsp_code = OBX_RSP_CONTINUE;
+ }
+ else
+ rsp_code = OBX_RSP_INTRNL_SRVR_ERR;
+ }
+ }
+ }
+
+ /* Error has been detected; respond with error code */
+ if (rsp_code != OBX_RSP_CONTINUE)
+ {
+ utl_freebuf((void**)&p_cb->obx.p_pkt);
+ utl_freebuf((void**)&p_cb->p_path);
+ p_cb->p_name = NULL;
+ OBX_GetRsp(p_evt->handle, rsp_code, (BT_HDR *)NULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ops_proc_get_obj
+**
+** Description Processes a continuation packet for pulling a vcard.
+** Builds a response packet and initiates a read into it.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ops_proc_get_obj(tBTA_OPS_CB *p_cb)
+{
+ tBTA_OPS_OBX_PKT *p_obx = &p_cb->obx;
+
+ /* Allocate a new OBX packet */
+ if ((p_obx->p_pkt = (BT_HDR *)OBX_HdrInit(p_cb->obx_handle,
+ /*p_cb->peer_mtu*/OBX_LRG_DATA_POOL_SIZE)) != NULL)
+ {
+ /* Add the start of the Body Header */
+ p_obx->offset = 0;
+ p_obx->bytes_left = 0;
+ p_obx->p_start = OBX_AddBodyStart(p_obx->p_pkt, &p_obx->bytes_left);
+
+ p_cb->cout_active = TRUE;
+ bta_fs_co_read(p_cb->fd, &p_obx->p_start[p_obx->offset],
+ p_obx->bytes_left, BTA_OPS_CI_READ_EVT, 0, p_cb->app_id);
+ }
+ else
+ bta_ops_get_obj_rsp(OBX_RSP_INTRNL_SRVR_ERR, 0);
+}
+
+/*******************************************************************************
+**
+** Function bta_ops_proc_put_obj
+**
+** Description Processes a Push Object Operation.
+** Initiates the opening of an object for writing, or continues
+** with a new Obx packet of data (continuation).
+**
+** Parameters p_pkt - Pointer to the OBX Put request
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ops_proc_put_obj(BT_HDR *p_pkt)
+{
+ tBTA_OPS_CB *p_cb = &bta_ops_cb;
+ tBTA_OPS_OBX_PKT *p_obx = &p_cb->obx;
+ UINT8 num_hdrs;
+ BOOLEAN endpkt;
+
+ p_obx->p_pkt = p_pkt;
+
+ p_obx->offset = 0; /* Initial offset into OBX data */
+ /* Read in start of body if there is a body header */
+ num_hdrs = OBX_ReadBodyHdr(p_obx->p_pkt, &p_obx->p_start, &p_obx->bytes_left,
+ &endpkt);
+ if (num_hdrs == 1)
+ {
+ p_cb->cout_active = TRUE;
+ bta_fs_co_write(p_cb->fd, &p_obx->p_start[p_obx->offset],
+ p_obx->bytes_left, BTA_OPS_CI_WRITE_EVT, 0, p_cb->app_id);
+ }
+ else
+ {
+ bta_ops_clean_getput(p_cb, TRUE);
+ bta_ops_put_obj_rsp(OBX_RSP_BAD_REQUEST);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ops_get_obj_rsp
+**
+** Description Finishes up the end body of the object get, and sends out the
+** OBX response
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ops_get_obj_rsp(UINT8 rsp_code, UINT16 num_read)
+{
+ tBTA_OPS_CB *p_cb = &bta_ops_cb;
+ tBTA_OPS_OBX_PKT *p_obx = &p_cb->obx;
+ tBTA_OPS_PROGRESS param;
+ BOOLEAN done = TRUE;
+
+ /* Send the response packet if successful operation */
+ if (rsp_code == OBX_RSP_OK || rsp_code == OBX_RSP_CONTINUE)
+ {
+ p_obx->offset += num_read;
+
+ /* More to be sent */
+ if (rsp_code == OBX_RSP_CONTINUE)
+ {
+ if (p_obx->bytes_left != num_read)
+ APPL_TRACE_WARNING2("OPS Read: Requested (0x%04x), Read In (0x%04x)",
+ p_obx->bytes_left, num_read);
+ done = FALSE;
+ }
+
+ OBX_AddBodyEnd(p_obx->p_pkt, p_obx->p_start, p_obx->offset, done);
+
+ /* Notify application with progress */
+ if (num_read)
+ {
+ param.bytes = num_read;
+ param.obj_size = p_cb->file_length;
+ param.operation = BTA_OP_OPER_PULL;
+ p_cb->p_cback(BTA_OPS_PROGRESS_EVT, (tBTA_OPS *)&param);
+ }
+ }
+ else
+ p_cb->obx_oper = OPS_OP_NONE;
+
+ OBX_GetRsp(p_cb->obx_handle, rsp_code, (BT_HDR *)p_obx->p_pkt);
+ p_obx->p_pkt = NULL; /* Do not deallocate buffer; OBX will */
+
+ /* Final response packet sent out */
+ if (done)
+ bta_ops_clean_getput(p_cb, FALSE);
+}
+
+/*******************************************************************************
+**
+** Function bta_ops_put_obj_rsp
+**
+** Description Responds to a put request, and closes the object if finished
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ops_put_obj_rsp(UINT8 rsp_code)
+{
+ tBTA_OPS_CB *p_cb = &bta_ops_cb;
+ tBTA_OPS_OBX_PKT *p_obx = &p_cb->obx;
+ tBTA_OPS_PROGRESS param;
+ tBTA_OPS_OBJECT object;
+
+ /* Finished with input packet */
+ utl_freebuf((void**)&p_obx->p_pkt);
+
+ if (rsp_code == OBX_RSP_OK)
+ {
+ /* Update application if object data was transferred */
+ if (p_obx->bytes_left)
+ {
+ param.bytes = p_obx->bytes_left;
+ param.obj_size = p_cb->file_length;
+ param.operation = BTA_OP_OPER_PUSH;
+ p_cb->p_cback(BTA_OPS_PROGRESS_EVT, (tBTA_OPS *)&param);
+ }
+
+ /* If not end of object put, set the continue response */
+ if (!p_obx->final_pkt)
+ rsp_code = OBX_RSP_CONTINUE;
+ else /* Done - free the allocated memory */
+ {
+ /* callback to app with object */
+ object.format = p_cb->obj_fmt;
+ object.p_name = p_cb->p_name;
+
+ bta_ops_clean_getput(p_cb, FALSE);
+ p_cb->p_cback(BTA_OPS_OBJECT_EVT, (tBTA_OPS *) &object);
+
+ }
+ }
+ else
+ p_cb->obx_oper = OPS_OP_NONE;
+
+ OBX_PutRsp(p_cb->obx_handle, rsp_code, (BT_HDR *)NULL);
+}
+
+/*******************************************************************************
+**
+** Function bta_ops_req_app_access
+**
+** Description Sends an access request event to the application.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ops_req_app_access (tBTA_OP_OPER oper, tBTA_OPS_CB *p_cb)
+{
+ tBTA_OPS_ACCESS *p_acc_evt;
+ char *p_devname;
+ UINT16 len;
+
+ /* Notify the application that a put or get file has been requested */
+ if ((p_acc_evt = (tBTA_OPS_ACCESS *)GKI_getbuf(sizeof(tBTA_OPS_ACCESS))) != NULL)
+ {
+ memset(p_acc_evt, 0, sizeof(tBTA_OPS_ACCESS));
+ p_acc_evt->p_name = p_cb->p_name;
+ p_acc_evt->size = p_cb->file_length;
+ p_acc_evt->oper = p_cb->acc_active = oper;
+ p_acc_evt->format = p_cb->obj_fmt;
+ bdcpy(p_acc_evt->bd_addr, p_cb->bd_addr);
+
+ if ((p_devname = BTM_SecReadDevName(p_cb->bd_addr)) != NULL)
+ BCM_STRNCPY_S((char *)p_acc_evt->dev_name, sizeof(tBTM_BD_NAME), p_devname, BTM_MAX_REM_BD_NAME_LEN);
+
+ /* Only pass the object type if Push operation */
+ if (oper == BTA_OP_OPER_PUSH)
+ {
+ if (!OBX_ReadTypeHdr(p_cb->obx.p_pkt, (UINT8 **)&p_acc_evt->p_type, &len))
+ p_acc_evt->p_type = NULL;
+ }
+
+ if (p_acc_evt->p_type)
+ {
+ APPL_TRACE_EVENT3("OPS Access Request...Name [%s], Oper [%d], Type [%s]",
+ p_cb->p_name, oper, p_acc_evt->p_type);
+ }
+ else
+ {
+ APPL_TRACE_EVENT2("OPS Access Request...Name [%s], Oper [%d]",
+ p_cb->p_name, oper);
+ }
+
+ p_cb->p_cback(BTA_OPS_ACCESS_EVT, (tBTA_OPS *)p_acc_evt);
+ GKI_freebuf(p_acc_evt);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ops_clean_getput
+**
+** Description Cleans up the get/put resources and control block
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ops_clean_getput(tBTA_OPS_CB *p_cb, BOOLEAN is_aborted)
+{
+ tBTA_FS_CO_STATUS status;
+
+ /* Clean up control block */
+ utl_freebuf((void**)&p_cb->obx.p_pkt);
+
+ /* Close any open files */
+ if (p_cb->fd >= 0)
+ {
+ bta_fs_co_close(p_cb->fd, p_cb->app_id);
+ p_cb->fd = BTA_FS_INVALID_FD;
+
+ /* Delete an aborted unfinished push file operation */
+ if (is_aborted && p_cb->obx_oper == OPS_OP_PUSH_OBJ)
+ {
+ status = bta_fs_co_unlink(p_cb->p_path, p_cb->app_id);
+ APPL_TRACE_WARNING2("OPS: Remove ABORTED Push File Operation [%s], status 0x%02x", p_cb->p_path, status);
+ }
+ }
+
+ utl_freebuf((void**)&p_cb->p_path);
+ p_cb->p_name = NULL;
+
+ p_cb->obx_oper = OPS_OP_NONE;
+ p_cb->obx.bytes_left = 0;
+ p_cb->file_length = BTA_FS_LEN_UNKNOWN;
+ p_cb->acc_active = 0;
+ p_cb->aborting = FALSE;
+}
+
+/*******************************************************************************
+**
+** Function bta_ops_fmt_supported
+**
+** Description This function determines the file type from a file name
+** and checks if the file type is supported.
+**
+**
+** Returns Format type value or zero if format unsupported.
+**
+*******************************************************************************/
+tBTA_OP_FMT bta_ops_fmt_supported(char *p, tBTA_OP_FMT_MASK fmt_mask)
+{
+ char *p_suffix;
+ tBTA_OP_FMT fmt = BTA_OP_OTHER_FMT;
+
+ /* scan to find file suffix */
+ if ((p_suffix = strrchr(p, '.')) != NULL)
+ {
+ p_suffix++;
+ if (bta_ops_stricmp (p_suffix, "vcf") == 0)
+ {
+ fmt = BTA_OP_VCARD21_FMT;
+ }
+ else if (bta_ops_stricmp (p_suffix, "vcd") == 0)
+ {
+ fmt = BTA_OP_VCARD30_FMT;
+ }
+ else if (bta_ops_stricmp (p_suffix, "vcs") == 0)
+ {
+ fmt = BTA_OP_VCAL_FMT;
+ }
+ else if (bta_ops_stricmp (p_suffix, "ics") == 0)
+ {
+ fmt = BTA_OP_ICAL_FMT;
+ }
+ else if (bta_ops_stricmp (p_suffix, "vmg") == 0)
+ {
+ fmt = BTA_OP_VMSG_FMT;
+ }
+ else if (bta_ops_stricmp (p_suffix, "vnt") == 0)
+ {
+ fmt = BTA_OP_VNOTE_FMT;
+ }
+ }
+
+ /* see if supported */
+ if (fmt == BTA_OP_OTHER_FMT)
+ {
+ if (!(fmt_mask & BTA_OP_ANY_MASK))
+ fmt = 0; /* Other types not supported */
+ }
+ else
+ {
+ if (!((1 << (fmt - 1)) & fmt_mask))
+ fmt = 0;
+ }
+
+ return fmt;
+}
+
+/*******************************************************************************
+**
+** Function bta_ops_discard_data
+**
+** Description frees the data
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ops_discard_data(UINT16 event, tBTA_OPS_DATA *p_data)
+{
+ switch(event)
+ {
+ case BTA_OPS_OBX_CONN_EVT:
+ case BTA_OPS_OBX_DISC_EVT:
+ case BTA_OPS_OBX_ABORT_EVT:
+ case BTA_OPS_OBX_CLOSE_EVT:
+ case BTA_OPS_OBX_PUT_EVT:
+ case BTA_OPS_OBX_GET_EVT:
+ utl_freebuf((void**)&p_data->obx_evt.p_pkt);
+ break;
+
+ default:
+ /*Nothing to free*/
+ break;
+ }
+}
+
+/*******************************************************************************
+* Static Functions
+*******************************************************************************/
+/*******************************************************************************
+**
+** Function bta_ops_stricmp
+**
+** Description Used to compare type header
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static int bta_ops_stricmp (const char *p_str1, const char *p_str2)
+{
+ UINT16 i;
+ UINT16 cmplen;
+
+ if (!p_str1 || !p_str2)
+ return (1);
+
+ cmplen = strlen(p_str1);
+ if (cmplen != strlen(p_str2))
+ return (1);
+
+ for (i = 0; i < cmplen; i++)
+ {
+ if (toupper(p_str1[i]) != toupper(p_str2[i]))
+ return (i+1);
+ }
+
+ return 0;
+}
+#endif /* BTA_OP_INCLUDED */
diff --git a/bta/pan/bta_pan_act.c b/bta/pan/bta_pan_act.c
new file mode 100644
index 0000000..d9424ec
--- /dev/null
+++ b/bta/pan/bta_pan_act.c
@@ -0,0 +1,718 @@
+/*****************************************************************************
+**
+** Name: bta_pan_act.c
+**
+** Description: This file contains the pan action functions
+** for the state machine.
+**
+** Copyright (c) 2004-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+
+#if defined(PAN_INCLUDED) && (PAN_INCLUDED == TRUE)
+
+#include "bta_api.h"
+#include "bta_sys.h"
+#include "bd.h"
+#include "gki.h"
+#include "pan_api.h"
+#include "bta_pan_api.h"
+#include "bta_pan_int.h"
+#include "bta_pan_co.h"
+#include <string.h>
+
+
+/* RX and TX data flow mask */
+#define BTA_PAN_RX_MASK 0x0F
+#define BTA_PAN_TX_MASK 0xF0
+
+/*******************************************************************************
+**
+** Function bta_pan_conn_state_cback
+**
+** Description Connection state callback from Pan profile
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_pan_conn_state_cback(UINT16 handle, BD_ADDR bd_addr, tPAN_RESULT state,
+ BOOLEAN is_role_change, UINT8 src_role, UINT8 dst_role)
+{
+
+ tBTA_PAN_CONN * p_buf;
+ tBTA_PAN_SCB *p_scb;
+
+
+ if ((p_buf = (tBTA_PAN_CONN *) GKI_getbuf(sizeof(tBTA_PAN_CONN))) != NULL)
+ {
+ if((state == PAN_SUCCESS) && !is_role_change)
+ {
+ p_buf->hdr.event = BTA_PAN_CONN_OPEN_EVT;
+ if((p_scb = bta_pan_scb_by_handle(handle)) == NULL)
+ {
+ /* allocate an scb */
+ p_scb = bta_pan_scb_alloc();
+
+ }
+ /* we have exceeded maximum number of connections */
+ if(!p_scb)
+ {
+ PAN_Disconnect (handle);
+ return;
+ }
+
+ p_scb->handle = handle;
+ p_scb->local_role = src_role;
+ p_scb->peer_role = dst_role;
+ p_scb->pan_flow_enable = TRUE;
+ bdcpy(p_scb->bd_addr, bd_addr);
+ GKI_init_q(&p_scb->data_queue);
+
+ if(src_role == PAN_ROLE_CLIENT)
+ p_scb->app_id = bta_pan_cb.app_id[0];
+ else if (src_role == PAN_ROLE_GN_SERVER)
+ p_scb->app_id = bta_pan_cb.app_id[1];
+ else if (src_role == PAN_ROLE_NAP_SERVER)
+ p_scb->app_id = bta_pan_cb.app_id[2];
+
+ }
+ else if((state != PAN_SUCCESS) && !is_role_change)
+ {
+ p_buf->hdr.event = BTA_PAN_CONN_CLOSE_EVT;
+
+ }
+ else
+ {
+ return;
+ }
+
+ p_buf->result = state;
+ p_buf->hdr.layer_specific = handle;
+ bta_sys_sendmsg(p_buf);
+
+ }
+
+
+
+}
+
+/*******************************************************************************
+**
+** Function bta_pan_data_flow_cb
+**
+** Description Data flow status callback from PAN
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_pan_data_flow_cb(UINT16 handle, tPAN_RESULT result)
+{
+ BT_HDR *p_buf;
+ tBTA_PAN_SCB *p_scb;
+
+ if((p_scb = bta_pan_scb_by_handle(handle)) == NULL)
+ return;
+
+ if(result == PAN_TX_FLOW_ON)
+ {
+ if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->layer_specific = handle;
+ p_buf->event = BTA_PAN_BNEP_FLOW_ENABLE_EVT;
+ bta_sys_sendmsg(p_buf);
+ }
+ bta_pan_co_rx_flow(handle, p_scb->app_id, TRUE);
+
+ }
+ else if(result == PAN_TX_FLOW_OFF)
+ {
+
+ p_scb->pan_flow_enable = FALSE;
+ bta_pan_co_rx_flow(handle, p_scb->app_id, FALSE);
+
+ }
+
+
+}
+
+
+/*******************************************************************************
+**
+** Function bta_pan_data_buf_ind_cback
+**
+** Description data indication callback from pan profile
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_pan_data_buf_ind_cback(UINT16 handle, BD_ADDR src, BD_ADDR dst, UINT16 protocol, BT_HDR *p_buf,
+ BOOLEAN ext, BOOLEAN forward)
+{
+ tBTA_PAN_SCB *p_scb;
+ BT_HDR * p_event;
+ BT_HDR *p_new_buf;
+
+ if ( sizeof(tBTA_PAN_DATA_PARAMS) > p_buf->offset )
+ {
+ /* offset smaller than data structure in front of actual data */
+ p_new_buf = (BT_HDR *)GKI_getpoolbuf( PAN_POOL_ID );
+ if(!p_new_buf)
+ {
+ APPL_TRACE_WARNING0("Cannot get a PAN GKI buffer");
+ GKI_freebuf( p_buf );
+ return;
+ }
+ else
+ {
+ memcpy( (UINT8 *)(p_new_buf+1)+sizeof(tBTA_PAN_DATA_PARAMS), (UINT8 *)(p_buf+1)+p_buf->offset, p_buf->len );
+ p_new_buf->len = p_buf->len;
+ p_new_buf->offset = sizeof(tBTA_PAN_DATA_PARAMS);
+ GKI_freebuf( p_buf );
+ }
+ }
+ else
+ {
+ p_new_buf = p_buf;
+ }
+ /* copy params into the space before the data */
+ bdcpy(((tBTA_PAN_DATA_PARAMS *)p_new_buf)->src, src);
+ bdcpy(((tBTA_PAN_DATA_PARAMS *)p_new_buf)->dst, dst);
+ ((tBTA_PAN_DATA_PARAMS *)p_new_buf)->protocol = protocol;
+ ((tBTA_PAN_DATA_PARAMS *)p_new_buf)->ext = ext;
+ ((tBTA_PAN_DATA_PARAMS *)p_new_buf)->forward = forward;
+
+
+ if((p_scb = bta_pan_scb_by_handle(handle)) == NULL)
+ {
+
+ GKI_freebuf( p_new_buf );
+ return;
+ }
+
+ GKI_enqueue(&p_scb->data_queue, p_new_buf);
+ if ((p_event = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_event->layer_specific = handle;
+ p_event->event = BTA_PAN_RX_FROM_BNEP_READY_EVT;
+ bta_sys_sendmsg(p_event);
+ }
+
+}
+
+
+/*******************************************************************************
+**
+** Function bta_pan_pfilt_ind_cback
+**
+** Description
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_pan_pfilt_ind_cback(UINT16 handle, BOOLEAN indication,tBNEP_RESULT result,
+ UINT16 num_filters, UINT8 *p_filters)
+{
+
+ bta_pan_co_pfilt_ind(handle, indication, (tBTA_PAN_STATUS)((result == BNEP_SUCCESS) ? BTA_PAN_SUCCESS : BTA_PAN_FAIL),
+ num_filters, p_filters);
+
+
+}
+
+
+/*******************************************************************************
+**
+** Function bta_pan_mfilt_ind_cback
+**
+** Description
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_pan_mfilt_ind_cback(UINT16 handle, BOOLEAN indication,tBNEP_RESULT result,
+ UINT16 num_mfilters, UINT8 *p_mfilters)
+{
+
+ bta_pan_co_mfilt_ind(handle, indication, (tBTA_PAN_STATUS)((result == BNEP_SUCCESS) ? BTA_PAN_SUCCESS : BTA_PAN_FAIL),
+ num_mfilters, p_mfilters);
+}
+
+
+
+/*******************************************************************************
+**
+** Function bta_pan_enable
+**
+** Description
+**
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pan_enable(tBTA_PAN_DATA *p_data)
+{
+ tPAN_REGISTER reg_data;
+ UINT16 initial_discoverability;
+ UINT16 initial_connectability;
+ UINT16 d_window;
+ UINT16 d_interval;
+ UINT16 c_window;
+ UINT16 c_interval;
+
+ bta_pan_cb.p_cback = p_data->api_enable.p_cback;
+
+ reg_data.pan_conn_state_cb = bta_pan_conn_state_cback;
+ reg_data.pan_bridge_req_cb = NULL;
+ reg_data.pan_data_buf_ind_cb = bta_pan_data_buf_ind_cback;
+ reg_data.pan_data_ind_cb = NULL;
+ reg_data.pan_pfilt_ind_cb = bta_pan_pfilt_ind_cback;
+ reg_data.pan_mfilt_ind_cb = bta_pan_mfilt_ind_cback;
+ reg_data.pan_tx_data_flow_cb = bta_pan_data_flow_cb;
+
+ /* read connectability and discoverability settings.
+ Pan profile changes the settings. We have to change it back to
+ be consistent with other bta subsystems */
+ initial_connectability = BTM_ReadConnectability(&c_window, &c_interval);
+ initial_discoverability = BTM_ReadDiscoverability(&d_window, &d_interval);
+
+
+ PAN_Register (&reg_data);
+
+
+ /* set it back to original value */
+ BTM_SetDiscoverability(initial_discoverability, d_window, d_interval);
+ BTM_SetConnectability(initial_connectability, c_window, c_interval);
+
+ bta_pan_cb.flow_mask = bta_pan_co_init(&bta_pan_cb.q_level);
+ bta_pan_cb.p_cback(BTA_PAN_ENABLE_EVT, NULL);
+
+}
+
+/*******************************************************************************
+**
+** Function bta_pan_set_role
+**
+** Description
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pan_set_role(tBTA_PAN_DATA *p_data)
+{
+ tPAN_RESULT status;
+ tBTA_PAN_SET_ROLE set_role;
+ UINT8 sec[3];
+
+
+ bta_pan_cb.app_id[0] = p_data->api_set_role.user_app_id;
+ bta_pan_cb.app_id[1] = p_data->api_set_role.gn_app_id;
+ bta_pan_cb.app_id[2] = p_data->api_set_role.nap_app_id;
+
+ sec[0] = p_data->api_set_role.user_sec_mask;
+ sec[1] = p_data->api_set_role.gn_sec_mask;
+ sec[2] = p_data->api_set_role.nap_sec_mask;
+
+ /* set security correctly in api and here */
+ status = PAN_SetRole(p_data->api_set_role.role, sec,
+ p_data->api_set_role.user_name,
+ p_data->api_set_role.gn_name,
+ p_data->api_set_role.nap_name);
+
+ if(status == PAN_SUCCESS)
+ {
+ if(p_data->api_set_role.role & PAN_ROLE_NAP_SERVER )
+ bta_sys_add_uuid(UUID_SERVCLASS_NAP);
+ else
+ bta_sys_remove_uuid(UUID_SERVCLASS_NAP);
+
+ if(p_data->api_set_role.role & PAN_ROLE_GN_SERVER )
+ bta_sys_add_uuid(UUID_SERVCLASS_GN);
+ else
+ bta_sys_remove_uuid(UUID_SERVCLASS_GN);
+
+ if(p_data->api_set_role.role & PAN_ROLE_CLIENT )
+ bta_sys_add_uuid(UUID_SERVCLASS_PANU);
+ else
+ bta_sys_remove_uuid(UUID_SERVCLASS_PANU);
+
+ set_role.role = p_data->api_set_role.role;
+ bta_pan_cb.p_cback(BTA_PAN_SET_ROLE_EVT, (tBTA_PAN *)&set_role);
+ }
+ /* if status is not success clear everything */
+ else
+ {
+ PAN_SetRole(0, 0, NULL, NULL, NULL);
+
+ bta_sys_remove_uuid(UUID_SERVCLASS_NAP);
+ bta_sys_remove_uuid(UUID_SERVCLASS_GN);
+ bta_sys_remove_uuid(UUID_SERVCLASS_PANU);
+ set_role.role = 0;
+ bta_pan_cb.p_cback(BTA_PAN_SET_ROLE_EVT, (tBTA_PAN *)&set_role);
+ }
+
+}
+
+
+
+/*******************************************************************************
+**
+** Function bta_pan_disable
+**
+** Description
+**
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pan_disable(void)
+{
+
+ BT_HDR *p_buf;
+ tBTA_PAN_SCB *p_scb = &bta_pan_cb.scb[0];
+ UINT8 i;
+
+
+ /* close all connections */
+ PAN_SetRole (0, NULL, NULL, NULL, NULL);
+
+#if ( BTM_EIR_SERVER_INCLUDED == TRUE )&&(BTA_EIR_CANNED_UUID_LIST != TRUE)
+ bta_sys_remove_uuid(UUID_SERVCLASS_NAP);
+ bta_sys_remove_uuid(UUID_SERVCLASS_GN);
+ bta_sys_remove_uuid(UUID_SERVCLASS_PANU);
+#endif
+ /* free all queued up data buffers */
+ for (i = 0; i < BTA_PAN_NUM_CONN; i++, p_scb++)
+ {
+ if (p_scb->in_use)
+ {
+ while((p_buf = (BT_HDR *)GKI_dequeue(&p_scb->data_queue)) != NULL)
+ GKI_freebuf(p_buf);
+
+ bta_pan_co_close(p_scb->handle, p_scb->app_id);
+
+ }
+ }
+
+
+
+ PAN_Deregister();
+
+}
+
+/*******************************************************************************
+**
+** Function bta_pan_open
+**
+** Description
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pan_open(tBTA_PAN_SCB *p_scb, tBTA_PAN_DATA *p_data)
+{
+ tPAN_RESULT status;
+ tBTA_PAN_OPEN data;
+ tBTA_PAN_OPENING opening;
+
+
+ status = PAN_Connect (p_data->api_open.bd_addr, p_data->api_open.local_role, p_data->api_open.peer_role,
+ &p_scb->handle);
+
+
+ if(status == PAN_SUCCESS)
+ {
+
+ bdcpy(p_scb->bd_addr, p_data->api_open.bd_addr);
+ p_scb->local_role = p_data->api_open.local_role;
+ p_scb->peer_role = p_data->api_open.peer_role;
+ bdcpy(opening.bd_addr, p_data->api_open.bd_addr);
+ opening.handle = p_scb->handle;
+ bta_pan_cb.p_cback(BTA_PAN_OPENING_EVT, (tBTA_PAN *)&opening);
+
+
+ }
+ else
+ {
+ bta_pan_scb_dealloc(p_scb);
+ bdcpy(data.bd_addr, p_data->api_open.bd_addr);
+ data.status = BTA_PAN_FAIL;
+ bta_pan_cb.p_cback(BTA_PAN_OPEN_EVT, (tBTA_PAN *)&data);
+ }
+
+}
+
+
+/*******************************************************************************
+**
+** Function bta_pan_close
+**
+** Description
+**
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pan_api_close (tBTA_PAN_SCB *p_scb, tBTA_PAN_DATA *p_data)
+{
+ tBTA_PAN_CONN * p_buf;
+
+ PAN_Disconnect (p_scb->handle);
+
+
+ /* send an event to BTA so that application will get the connection
+ close event */
+ if ((p_buf = (tBTA_PAN_CONN *) GKI_getbuf(sizeof(tBTA_PAN_CONN))) != NULL)
+ {
+ p_buf->hdr.event = BTA_PAN_CONN_CLOSE_EVT;
+
+ p_buf->hdr.layer_specific = p_scb->handle;
+ bta_sys_sendmsg(p_buf);
+
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function bta_pan_conn_open
+**
+** Description process connection open event
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pan_conn_open(tBTA_PAN_SCB *p_scb, tBTA_PAN_DATA *p_data)
+{
+
+ tBTA_PAN_OPEN data;
+
+ bdcpy(data.bd_addr, p_scb->bd_addr);
+ data.handle = p_scb->handle;
+ data.local_role = p_scb->local_role;
+ data.peer_role = p_scb->peer_role;
+
+ if(p_data->conn.result == PAN_SUCCESS)
+ {
+ data.status = BTA_PAN_SUCCESS;
+ bta_pan_co_open(p_scb->handle, p_scb->app_id, p_scb->local_role, p_scb->peer_role, p_scb->bd_addr);
+
+ }
+ else
+ {
+ bta_pan_scb_dealloc(p_scb);
+ data.status = BTA_PAN_FAIL;
+ }
+
+ p_scb->pan_flow_enable = TRUE;
+ p_scb->app_flow_enable = TRUE;
+
+ bta_sys_conn_open( BTA_ID_PAN ,p_scb->app_id, p_scb->bd_addr);
+
+ bta_pan_cb.p_cback(BTA_PAN_OPEN_EVT, (tBTA_PAN *)&data);
+
+
+}
+
+/*******************************************************************************
+**
+** Function bta_pan_conn_close
+**
+** Description process connection close event
+**
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pan_conn_close(tBTA_PAN_SCB *p_scb, tBTA_PAN_DATA *p_data)
+{
+
+ tBTA_PAN_CLOSE data;
+ BT_HDR *p_buf;
+
+ data.handle = p_data->hdr.layer_specific;
+
+
+ bta_sys_conn_close( BTA_ID_PAN ,p_scb->app_id, p_scb->bd_addr);
+
+ /* free all queued up data buffers */
+ while((p_buf = (BT_HDR *)GKI_dequeue(&p_scb->data_queue)) != NULL)
+ GKI_freebuf(p_buf);
+
+ GKI_init_q(&p_scb->data_queue);
+
+ bta_pan_co_close(p_scb->handle, p_scb->app_id);
+
+ bta_pan_scb_dealloc(p_scb);
+
+ bta_pan_cb.p_cback(BTA_PAN_CLOSE_EVT, (tBTA_PAN *)&data);
+
+}
+
+
+
+
+/*******************************************************************************
+**
+** Function bta_pan_rx_path
+**
+** Description Handle data on the RX path (data sent from the phone to
+** BTA).
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pan_rx_path(tBTA_PAN_SCB *p_scb, tBTA_PAN_DATA *p_data)
+{
+ /* if data path configured for rx pull */
+ if ((bta_pan_cb.flow_mask & BTA_PAN_RX_MASK) == BTA_PAN_RX_PULL)
+ {
+ /* if we can accept data */
+ if (p_scb->pan_flow_enable == TRUE)
+ {
+ /* call application callout function for rx path */
+ bta_pan_co_rx_path(p_scb->handle, p_scb->app_id);
+ }
+ }
+ /* else data path configured for rx push */
+ else
+ {
+
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_pan_tx_path
+**
+** Description Handle the TX data path (data sent from BTA to the phone).
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pan_tx_path(tBTA_PAN_SCB *p_scb, tBTA_PAN_DATA *p_data)
+{
+
+ BT_HDR * p_buf;
+ /* if data path configured for tx pull */
+ if ((bta_pan_cb.flow_mask & BTA_PAN_TX_MASK) == BTA_PAN_TX_PULL)
+ {
+ /* call application callout function for tx path */
+ bta_pan_co_tx_path(p_scb->handle, p_scb->app_id);
+
+ /* free data that exceeds queue level */
+ while(p_scb->data_queue.count > bta_pan_cb.q_level)
+ GKI_freebuf(GKI_dequeue(&p_scb->data_queue));
+ }
+ /* if configured for zero copy push */
+ else if ((bta_pan_cb.flow_mask & BTA_PAN_TX_MASK) == BTA_PAN_TX_PUSH_BUF)
+ {
+ /* if app can accept data */
+ if (p_scb->app_flow_enable == TRUE)
+ {
+ /* read data from the queue */
+ if ((p_buf = (BT_HDR *)GKI_dequeue(&p_scb->data_queue)) != NULL)
+ {
+ /* send data to application */
+ bta_pan_co_tx_writebuf(p_scb->handle,
+ p_scb->app_id,
+ ((tBTA_PAN_DATA_PARAMS *)p_buf)->src,
+ ((tBTA_PAN_DATA_PARAMS *)p_buf)->dst,
+ ((tBTA_PAN_DATA_PARAMS *)p_buf)->protocol,
+ p_buf,
+ ((tBTA_PAN_DATA_PARAMS *)p_buf)->ext,
+ ((tBTA_PAN_DATA_PARAMS *)p_buf)->forward);
+
+ }
+ /* free data that exceeds queue level */
+ while(p_scb->data_queue.count > bta_pan_cb.q_level)
+ GKI_freebuf(GKI_dequeue(&p_scb->data_queue));
+
+ /* if there is more data to be passed to
+ upper layer */
+ if(p_scb->data_queue.count)
+ {
+ if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->layer_specific = p_scb->handle;
+ p_buf->event = BTA_PAN_RX_FROM_BNEP_READY_EVT;
+ bta_sys_sendmsg(p_buf);
+ }
+
+ }
+
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_pan_tx_flow
+**
+** Description Set the application flow control state.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pan_tx_flow(tBTA_PAN_SCB *p_scb, tBTA_PAN_DATA *p_data)
+{
+ p_scb->app_flow_enable = p_data->ci_tx_flow.enable;
+}
+
+/*******************************************************************************
+**
+** Function bta_pan_write_buf
+**
+** Description Handle a bta_pan_ci_rx_writebuf() and send data to PAN.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pan_write_buf(tBTA_PAN_SCB *p_scb, tBTA_PAN_DATA *p_data)
+{
+ if ((bta_pan_cb.flow_mask & BTA_PAN_RX_MASK) == BTA_PAN_RX_PUSH_BUF)
+ {
+
+ PAN_WriteBuf (p_scb->handle,
+ ((tBTA_PAN_DATA_PARAMS *)p_data)->dst,
+ ((tBTA_PAN_DATA_PARAMS *)p_data)->src,
+ ((tBTA_PAN_DATA_PARAMS *)p_data)->protocol,
+ (BT_HDR *)p_data,
+ ((tBTA_PAN_DATA_PARAMS *)p_data)->ext);
+
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_pan_free_buf
+**
+** Description Frees the data buffer during closing state
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pan_free_buf(tBTA_PAN_SCB *p_scb, tBTA_PAN_DATA *p_data)
+{
+
+ GKI_freebuf(p_data);
+
+}
+
+#endif /* PAN_INCLUDED */
diff --git a/bta/pan/bta_pan_api.c b/bta/pan/bta_pan_api.c
new file mode 100644
index 0000000..5a84668
--- /dev/null
+++ b/bta/pan/bta_pan_api.c
@@ -0,0 +1,202 @@
+/*****************************************************************************
+**
+** Name: bta_pan_api.c
+**
+** Description: This is the implementation of the API for PAN
+** subsystem of BTA, Widcomm's Bluetooth application
+** layer for mobile phones.
+**
+** Copyright (c) 2004-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+
+#if defined(BTA_PAN_INCLUDED) && (BTA_PAN_INCLUDED == TRUE)
+
+#include "bta_api.h"
+#include "bta_sys.h"
+#include "pan_api.h"
+#include "gki.h"
+#include "bta_pan_api.h"
+#include "bta_pan_int.h"
+#include "bd.h"
+#include <string.h>
+
+static const tBTA_SYS_REG bta_pan_reg =
+{
+ bta_pan_hdl_event,
+ BTA_PanDisable
+};
+
+/*******************************************************************************
+**
+** Function BTA_PanEnable
+**
+** Description Enable PAN service. This function must be
+** called before any other functions in the PAN API are called.
+** When the enable operation is complete the callback function
+** will be called with a BTA_PAN_ENABLE_EVT.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_PanEnable(tBTA_PAN_CBACK p_cback)
+{
+ tBTA_PAN_API_ENABLE *p_buf;
+
+ /* register with BTA system manager */
+ GKI_sched_lock();
+ bta_sys_register(BTA_ID_PAN, &bta_pan_reg);
+ GKI_sched_unlock();
+
+ if ((p_buf = (tBTA_PAN_API_ENABLE *) GKI_getbuf(sizeof(tBTA_PAN_API_ENABLE))) != NULL)
+ {
+ p_buf->hdr.event = BTA_PAN_API_ENABLE_EVT;
+ p_buf->p_cback = p_cback;
+
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+
+
+/*******************************************************************************
+**
+** Function BTA_PanDisable
+**
+** Description Disables PAN service.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_PanDisable(void)
+{
+ BT_HDR *p_buf;
+
+ bta_sys_deregister(BTA_ID_PAN);
+ if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->event = BTA_PAN_API_DISABLE_EVT;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_PanSetRole
+**
+** Description Sets PAN roles. When the enable operation is complete
+** the callback function will be called with a BTA_PAN_SET_ROLE_EVT.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_PanSetRole(tBTA_PAN_ROLE role, tBTA_PAN_ROLE_INFO *p_user_info, tBTA_PAN_ROLE_INFO *p_gn_info,
+ tBTA_PAN_ROLE_INFO *p_nap_info)
+{
+
+ tBTA_PAN_API_SET_ROLE *p_buf;
+
+ if ((p_buf = (tBTA_PAN_API_SET_ROLE *) GKI_getbuf(sizeof(tBTA_PAN_API_SET_ROLE))) != NULL)
+ {
+ p_buf->hdr.event = BTA_PAN_API_SET_ROLE_EVT;
+ p_buf->role = role;
+
+ if(p_user_info && (role & BTA_PAN_ROLE_PANU))
+ {
+ if(p_user_info->p_srv_name)
+ BCM_STRNCPY_S(p_buf->user_name, sizeof(p_buf->user_name), p_user_info->p_srv_name, BTA_SERVICE_NAME_LEN);
+ else
+ p_buf->user_name[0] = 0;
+
+ p_buf->user_name[BTA_SERVICE_NAME_LEN] = 0;
+ p_buf->user_app_id = p_user_info->app_id;
+ p_buf->user_sec_mask = p_user_info->sec_mask;
+ }
+
+ if(p_gn_info && (role & BTA_PAN_ROLE_GN))
+ {
+ if(p_gn_info->p_srv_name)
+ BCM_STRNCPY_S(p_buf->gn_name, sizeof(p_buf->gn_name), p_gn_info->p_srv_name, BTA_SERVICE_NAME_LEN);
+ else
+ p_buf->gn_name[0] = 0;
+
+ p_buf->gn_name[BTA_SERVICE_NAME_LEN] = 0;
+ p_buf->gn_app_id = p_gn_info->app_id;
+ p_buf->gn_sec_mask = p_gn_info->sec_mask;
+
+ }
+
+ if(p_nap_info && (role & BTA_PAN_ROLE_NAP))
+ {
+ if(p_nap_info->p_srv_name)
+ BCM_STRNCPY_S(p_buf->nap_name, sizeof(p_buf->nap_name), p_nap_info->p_srv_name, BTA_SERVICE_NAME_LEN);
+ else
+ p_buf->nap_name[0] = 0;
+
+ p_buf->nap_name[BTA_SERVICE_NAME_LEN] = 0;
+ p_buf->nap_app_id = p_nap_info->app_id;
+ p_buf->nap_sec_mask = p_nap_info->sec_mask;
+
+ }
+
+ bta_sys_sendmsg(p_buf);
+ }
+
+
+
+}
+
+/*******************************************************************************
+**
+** Function BTA_PanOpen
+**
+** Description Opens a connection to a peer device.
+** When connection is open callback function is called
+** with a BTA_PAN_OPEN_EVT.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API void BTA_PanOpen(BD_ADDR bd_addr, tBTA_PAN_ROLE local_role, tBTA_PAN_ROLE peer_role)
+{
+
+ tBTA_PAN_API_OPEN *p_buf;
+
+ if ((p_buf = (tBTA_PAN_API_OPEN *) GKI_getbuf(sizeof(tBTA_PAN_API_OPEN))) != NULL)
+ {
+ p_buf->hdr.event = BTA_PAN_API_OPEN_EVT;
+ p_buf->local_role = local_role;
+ p_buf->peer_role = peer_role;
+ bdcpy(p_buf->bd_addr, bd_addr);
+ bta_sys_sendmsg(p_buf);
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function BTA_PanClose
+**
+** Description Close a PAN connection to a peer device.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API void BTA_PanClose(UINT16 handle)
+{
+ BT_HDR *p_buf;
+
+ if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->event = BTA_PAN_API_CLOSE_EVT;
+ p_buf->layer_specific = handle;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+#endif /* BTA_PAN_INCLUDED */
diff --git a/bta/pan/bta_pan_ci.c b/bta/pan/bta_pan_ci.c
new file mode 100644
index 0000000..843d2b9
--- /dev/null
+++ b/bta/pan/bta_pan_ci.c
@@ -0,0 +1,248 @@
+/*****************************************************************************
+**
+** Name: bta_pan_ci.c
+**
+** Description: This is the implementation file for data gateway call-in
+** functions.
+**
+** Copyright (c) 2004, Widcomm Inc., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+
+#if defined(BTA_PAN_INCLUDED) && (BTA_PAN_INCLUDED == TRUE)
+
+#include <string.h>
+
+#include "gki.h"
+#include "pan_api.h"
+#include "bd.h"
+#include "bta_api.h"
+#include "bta_pan_api.h"
+#include "bta_pan_ci.h"
+#include "bta_pan_int.h"
+
+
+/*******************************************************************************
+**
+** Function bta_pan_ci_tx_ready
+**
+** Description This function sends an event to PAN indicating the phone is
+** ready for more data and PAN should call bta_pan_co_tx_path().
+** This function is used when the TX data path is configured
+** to use a pull interface.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pan_ci_tx_ready(UINT16 handle)
+{
+ BT_HDR *p_buf;
+
+ if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->layer_specific = handle;
+ p_buf->event = BTA_PAN_CI_TX_READY_EVT;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_pan_ci_rx_ready
+**
+** Description This function sends an event to PAN indicating the phone
+** has data available to send to PAN and PAN should call
+** bta_pan_co_rx_path(). This function is used when the RX
+** data path is configured to use a pull interface.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pan_ci_rx_ready(UINT16 handle)
+{
+ BT_HDR *p_buf;
+
+ if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->layer_specific = handle;
+ p_buf->event = BTA_PAN_CI_RX_READY_EVT;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_pan_ci_tx_flow
+**
+** Description This function is called to enable or disable data flow on
+** the TX path. The phone should call this function to
+** disable data flow when it is congested and cannot handle
+** any more data sent by bta_pan_co_tx_write() or
+** bta_pan_co_tx_writebuf(). This function is used when the
+** TX data path is configured to use a push interface.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pan_ci_tx_flow(UINT16 handle, BOOLEAN enable)
+{
+ tBTA_PAN_CI_TX_FLOW *p_buf;
+
+ if ((p_buf = (tBTA_PAN_CI_TX_FLOW *) GKI_getbuf(sizeof(tBTA_PAN_CI_TX_FLOW))) != NULL)
+ {
+ p_buf->hdr.layer_specific = handle;
+ p_buf->hdr.event = BTA_PAN_CI_TX_FLOW_EVT;
+ p_buf->enable = enable;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_pan_ci_rx_write
+**
+** Description This function is called to send data to PAN when the RX path
+** is configured to use a push interface. The function copies
+** data to an event buffer and sends it to PAN.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pan_ci_rx_write(UINT16 handle, BD_ADDR dst, BD_ADDR src, UINT16 protocol,
+ UINT8 *p_data, UINT16 len, BOOLEAN ext)
+{
+ BT_HDR * p_buf;
+
+ if((p_buf = (BT_HDR *) GKI_getpoolbuf(PAN_POOL_ID)) != NULL)
+ {
+
+
+ p_buf->offset = PAN_MINIMUM_OFFSET;
+
+ /* copy all other params before the data */
+ bdcpy(((tBTA_PAN_DATA_PARAMS *)p_buf)->src, src);
+ bdcpy(((tBTA_PAN_DATA_PARAMS *)p_buf)->dst, dst);
+ ((tBTA_PAN_DATA_PARAMS *)p_buf)->protocol = protocol;
+ ((tBTA_PAN_DATA_PARAMS *)p_buf)->ext = ext;
+ p_buf->len=len;
+
+ /* copy data */
+ memcpy((UINT8 *)(p_buf + 1) + p_buf->offset, p_data, len);
+
+ p_buf->layer_specific = handle;
+ p_buf->event = BTA_PAN_CI_RX_WRITEBUF_EVT;
+ bta_sys_sendmsg(p_buf);
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function bta_pan_ci_rx_writebuf
+**
+** Description This function is called to send data to the phone when
+** the RX path is configured to use a push interface with
+** zero copy. The function sends an event to PAN containing
+** the data buffer. The buffer must be allocated using
+** functions GKI_getbuf() or GKI_getpoolbuf(). The buffer
+** will be freed by BTA; the phone must not free the buffer.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pan_ci_rx_writebuf(UINT16 handle, BD_ADDR dst, BD_ADDR src, UINT16 protocol,
+ BT_HDR *p_buf, BOOLEAN ext)
+{
+
+ /* copy all other params before the data */
+ bdcpy(((tBTA_PAN_DATA_PARAMS *)p_buf)->src, src);
+ bdcpy(((tBTA_PAN_DATA_PARAMS *)p_buf)->dst, dst);
+ ((tBTA_PAN_DATA_PARAMS *)p_buf)->protocol = protocol;
+ ((tBTA_PAN_DATA_PARAMS *)p_buf)->ext = ext;
+
+ p_buf->layer_specific = handle;
+ p_buf->event = BTA_PAN_CI_RX_WRITEBUF_EVT;
+ bta_sys_sendmsg(p_buf);
+}
+
+
+
+
+/*******************************************************************************
+**
+** Function bta_pan_ci_readbuf
+**
+** Description
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BT_HDR * bta_pan_ci_readbuf(UINT16 handle, BD_ADDR src, BD_ADDR dst, UINT16* p_protocol,
+ BOOLEAN* p_ext, BOOLEAN* p_forward)
+{
+ tBTA_PAN_SCB * p_scb;
+ BT_HDR * p_buf;
+
+ p_scb = bta_pan_scb_by_handle(handle);
+
+ p_buf = (BT_HDR *)GKI_dequeue(&p_scb->data_queue);
+
+ if(p_buf)
+ {
+ bdcpy(src,((tBTA_PAN_DATA_PARAMS *)p_buf)->src);
+ bdcpy(dst,((tBTA_PAN_DATA_PARAMS *)p_buf)->dst);
+ *p_protocol = ((tBTA_PAN_DATA_PARAMS *)p_buf)->protocol;
+ *p_ext = ((tBTA_PAN_DATA_PARAMS *)p_buf)->ext;
+ *p_forward = ((tBTA_PAN_DATA_PARAMS *)p_buf)->forward;
+ }
+
+ return p_buf;
+}
+
+
+/*******************************************************************************
+**
+** Function bta_pan_ci_set_mfilters
+**
+** Description This function is called to set multicast filters
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pan_ci_set_mfilters(UINT16 handle, UINT16 num_mcast_filters, UINT8 *p_start_array,
+ UINT8 *p_end_array)
+{
+
+ PAN_SetMulticastFilters(handle, num_mcast_filters, p_start_array, p_end_array);
+
+}
+
+
+/*******************************************************************************
+**
+** Function bta_pan_ci_set_mfilters
+**
+** Description This function is called to set protocol filters
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pan_ci_set_pfilters(UINT16 handle, UINT16 num_filters, UINT16 *p_start_array, UINT16 *p_end_array)
+{
+
+ PAN_SetProtocolFilters(handle, num_filters, p_start_array, p_end_array );
+
+}
+
+#endif /* BTA_PAN_API */
diff --git a/bta/pan/bta_pan_int.h b/bta/pan/bta_pan_int.h
new file mode 100644
index 0000000..5715c31
--- /dev/null
+++ b/bta/pan/bta_pan_int.h
@@ -0,0 +1,200 @@
+/*****************************************************************************
+**
+** Name: bta_pan_int.h
+**
+** Description: This is the private interface file for the BTA data
+** gateway.
+**
+** Copyright (c) 2004, Widcomm Inc., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_PAN_INT_H
+#define BTA_PAN_INT_H
+
+#include "bta_sys.h"
+#include "bta_pan_api.h"
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+
+
+
+/* PAN events */
+enum
+{
+ /* these events are handled by the state machine */
+ BTA_PAN_API_CLOSE_EVT = BTA_SYS_EVT_START(BTA_ID_PAN),
+ BTA_PAN_CI_TX_READY_EVT,
+ BTA_PAN_CI_RX_READY_EVT,
+ BTA_PAN_CI_TX_FLOW_EVT,
+ BTA_PAN_CI_RX_WRITE_EVT,
+ BTA_PAN_CI_RX_WRITEBUF_EVT,
+ BTA_PAN_CONN_OPEN_EVT,
+ BTA_PAN_CONN_CLOSE_EVT,
+ BTA_PAN_BNEP_FLOW_ENABLE_EVT,
+ BTA_PAN_RX_FROM_BNEP_READY_EVT,
+
+ /* these events are handled outside of the state machine */
+ BTA_PAN_API_ENABLE_EVT,
+ BTA_PAN_API_DISABLE_EVT,
+ BTA_PAN_API_SET_ROLE_EVT,
+ BTA_PAN_API_OPEN_EVT
+};
+
+
+
+
+/*****************************************************************************
+** Data types
+*****************************************************************************/
+
+/* data type for BTA_PAN_API_ENABLE_EVT */
+typedef struct
+{
+ BT_HDR hdr; /* Event header */
+ tBTA_PAN_CBACK *p_cback; /* PAN callback function */
+} tBTA_PAN_API_ENABLE;
+
+/* data type for BTA_PAN_API_REG_ROLE_EVT */
+typedef struct
+{
+ BT_HDR hdr; /* Event header */
+ char user_name[BTA_SERVICE_NAME_LEN+1]; /* Service name */
+ char gn_name[BTA_SERVICE_NAME_LEN+1]; /* Service name */
+ char nap_name[BTA_SERVICE_NAME_LEN+1]; /* Service name */
+ tBTA_PAN_ROLE role;
+ UINT8 user_app_id;
+ UINT8 gn_app_id;
+ UINT8 nap_app_id;
+ tBTA_SEC user_sec_mask; /* Security mask */
+ tBTA_SEC gn_sec_mask; /* Security mask */
+ tBTA_SEC nap_sec_mask; /* Security mask */
+
+
+} tBTA_PAN_API_SET_ROLE;
+
+/* data type for BTA_PAN_API_OPEN_EVT */
+typedef struct
+{
+ BT_HDR hdr; /* Event header */
+ tBTA_PAN_ROLE local_role; /* local role */
+ tBTA_PAN_ROLE peer_role; /* peer role */
+ BD_ADDR bd_addr; /* peer bdaddr */
+} tBTA_PAN_API_OPEN;
+
+/* data type for BTA_PAN_CI_TX_FLOW_EVT */
+typedef struct
+{
+ BT_HDR hdr; /* Event header */
+ BOOLEAN enable; /* Flow control setting */
+} tBTA_PAN_CI_TX_FLOW;
+
+/* data type for BTA_PAN_CONN_OPEN_EVT */
+typedef struct
+{
+ BT_HDR hdr; /* Event header */
+ tPAN_RESULT result;
+
+} tBTA_PAN_CONN;
+
+
+
+
+/* union of all data types */
+typedef union
+{
+ BT_HDR hdr;
+ tBTA_PAN_API_ENABLE api_enable;
+ tBTA_PAN_API_SET_ROLE api_set_role;
+ tBTA_PAN_API_OPEN api_open;
+ tBTA_PAN_CI_TX_FLOW ci_tx_flow;
+ tBTA_PAN_CONN conn;
+} tBTA_PAN_DATA;
+
+/* state machine control block */
+typedef struct
+{
+ BD_ADDR bd_addr; /* peer bdaddr */
+ BUFFER_Q data_queue; /* Queue of buffers waiting to be passed to application */
+ UINT16 handle; /* BTA PAN/BNEP handle */
+ BOOLEAN in_use; /* scb in use */
+ tBTA_SEC sec_mask; /* Security mask */
+ BOOLEAN pan_flow_enable;/* BNEP flow control state */
+ BOOLEAN app_flow_enable;/* Application flow control state */
+ UINT8 state; /* State machine state */
+ tBTA_PAN_ROLE local_role; /* local role */
+ tBTA_PAN_ROLE peer_role; /* peer role */
+ UINT8 app_id; /* application id for the connection */
+
+} tBTA_PAN_SCB;
+
+
+
+/* main control block */
+typedef struct
+{
+ tBTA_PAN_SCB scb[BTA_PAN_NUM_CONN]; /* state machine control blocks */
+ tBTA_PAN_CBACK *p_cback; /* PAN callback function */
+ UINT8 app_id[3]; /* application id for PAN roles */
+ UINT8 flow_mask; /* Data flow mask */
+ UINT8 q_level; /* queue level set by application for TX data */
+
+} tBTA_PAN_CB;
+
+
+/* pan data param */
+typedef struct
+{
+ BT_HDR hdr;
+ BD_ADDR src;
+ BD_ADDR dst;
+ UINT16 protocol;
+ BOOLEAN ext;
+ BOOLEAN forward;
+
+} tBTA_PAN_DATA_PARAMS;
+
+
+/*****************************************************************************
+** Global data
+*****************************************************************************/
+
+/* PAN control block */
+
+#if BTA_DYNAMIC_MEMORY == FALSE
+extern tBTA_PAN_CB bta_pan_cb;
+#else
+extern tBTA_PAN_CB *bta_pan_cb_ptr;
+#define bta_pan_cb (*bta_pan_cb_ptr)
+#endif
+
+/*****************************************************************************
+** Function prototypes
+*****************************************************************************/
+extern tBTA_PAN_SCB *bta_pan_scb_alloc(void);
+extern void bta_pan_scb_dealloc(tBTA_PAN_SCB *p_scb);
+extern UINT8 bta_pan_scb_to_idx(tBTA_PAN_SCB *p_scb);
+extern tBTA_PAN_SCB *bta_pan_scb_by_handle(UINT16 handle);
+extern BOOLEAN bta_pan_hdl_event(BT_HDR *p_msg);
+
+/* action functions */
+extern void bta_pan_enable(tBTA_PAN_DATA *p_data);
+extern void bta_pan_disable(void);
+extern void bta_pan_set_role(tBTA_PAN_DATA *p_data);
+extern void bta_pan_open(tBTA_PAN_SCB *p_scb, tBTA_PAN_DATA *p_data);
+extern void bta_pan_api_close(tBTA_PAN_SCB *p_scb, tBTA_PAN_DATA *p_data);
+extern void bta_pan_set_shutdown(tBTA_PAN_SCB *p_scb, tBTA_PAN_DATA *p_data);
+extern void bta_pan_rx_path(tBTA_PAN_SCB *p_scb, tBTA_PAN_DATA *p_data);
+extern void bta_pan_tx_path(tBTA_PAN_SCB *p_scb, tBTA_PAN_DATA *p_data);
+extern void bta_pan_tx_flow(tBTA_PAN_SCB *p_scb, tBTA_PAN_DATA *p_data);
+extern void bta_pan_conn_open(tBTA_PAN_SCB *p_scb, tBTA_PAN_DATA *p_data);
+extern void bta_pan_conn_close(tBTA_PAN_SCB *p_scb, tBTA_PAN_DATA *p_data);
+extern void bta_pan_writebuf(tBTA_PAN_SCB *p_scb, tBTA_PAN_DATA *p_data);
+extern void bta_pan_write_buf(tBTA_PAN_SCB *p_scb, tBTA_PAN_DATA *p_data);
+extern void bta_pan_free_buf(tBTA_PAN_SCB *p_scb, tBTA_PAN_DATA *p_data);
+
+
+#endif /* BTA_PAN_INT_H */
diff --git a/bta/pan/bta_pan_main.c b/bta/pan/bta_pan_main.c
new file mode 100644
index 0000000..34caf61
--- /dev/null
+++ b/bta/pan/bta_pan_main.c
@@ -0,0 +1,409 @@
+/*****************************************************************************
+**
+** Name: bta_pan_main.c
+**
+** Description: This file contains the PAN main functions and
+** state machine.
+**
+** Copyright (c) 2004, Widcomm Inc., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+
+#if defined(BTA_PAN_INCLUDED) && (BTA_PAN_INCLUDED == TRUE)
+
+#include <string.h>
+#include "bta_api.h"
+#include "bta_sys.h"
+#include "gki.h"
+#include "pan_api.h"
+#include "bta_pan_api.h"
+#include "bta_pan_int.h"
+#include "bd.h"
+
+/*****************************************************************************
+** Constants and types
+*****************************************************************************/
+
+
+
+/* state machine action enumeration list */
+enum
+{
+ BTA_PAN_API_CLOSE,
+ BTA_PAN_TX_PATH,
+ BTA_PAN_RX_PATH,
+ BTA_PAN_TX_FLOW,
+ BTA_PAN_WRITE_BUF,
+ BTA_PAN_CONN_OPEN,
+ BTA_PAN_CONN_CLOSE,
+ BTA_PAN_FREE_BUF,
+ BTA_PAN_IGNORE
+};
+
+
+
+/* type for action functions */
+typedef void (*tBTA_PAN_ACTION)(tBTA_PAN_SCB *p_scb, tBTA_PAN_DATA *p_data);
+
+
+
+
+/* action function list */
+const tBTA_PAN_ACTION bta_pan_action[] =
+{
+ bta_pan_api_close,
+ bta_pan_tx_path,
+ bta_pan_rx_path,
+ bta_pan_tx_flow,
+ bta_pan_write_buf,
+ bta_pan_conn_open,
+ bta_pan_conn_close,
+ bta_pan_free_buf,
+
+};
+
+/* state table information */
+#define BTA_PAN_ACTIONS 1 /* number of actions */
+#define BTA_PAN_NEXT_STATE 1 /* position of next state */
+#define BTA_PAN_NUM_COLS 2 /* number of columns in state tables */
+
+
+/* state machine states */
+enum
+{
+ BTA_PAN_IDLE_ST,
+ BTA_PAN_OPEN_ST,
+ BTA_PAN_CLOSING_ST
+};
+
+
+/* state table for listen state */
+const UINT8 bta_pan_st_idle[][BTA_PAN_NUM_COLS] =
+{
+ /* API_CLOSE */ {BTA_PAN_API_CLOSE, BTA_PAN_IDLE_ST},
+ /* CI_TX_READY */ {BTA_PAN_IGNORE, BTA_PAN_IDLE_ST},
+ /* CI_RX_READY */ {BTA_PAN_IGNORE, BTA_PAN_IDLE_ST},
+ /* CI_TX_FLOW */ {BTA_PAN_IGNORE, BTA_PAN_IDLE_ST},
+ /* CI_RX_WRITE */ {BTA_PAN_IGNORE, BTA_PAN_IDLE_ST},
+ /* CI_RX_WRITEBUF */ {BTA_PAN_IGNORE, BTA_PAN_IDLE_ST},
+ /* PAN_CONN_OPEN */ {BTA_PAN_CONN_OPEN, BTA_PAN_OPEN_ST},
+ /* PAN_CONN_CLOSE */ {BTA_PAN_CONN_OPEN, BTA_PAN_IDLE_ST},
+ /* FLOW_ENABLE */ {BTA_PAN_IGNORE, BTA_PAN_IDLE_ST},
+ /* BNEP_DATA */ {BTA_PAN_IGNORE, BTA_PAN_IDLE_ST}
+
+};
+
+
+
+/* state table for open state */
+const UINT8 bta_pan_st_open[][BTA_PAN_NUM_COLS] =
+{
+ /* API_CLOSE */ {BTA_PAN_API_CLOSE, BTA_PAN_OPEN_ST},
+ /* CI_TX_READY */ {BTA_PAN_TX_PATH, BTA_PAN_OPEN_ST},
+ /* CI_RX_READY */ {BTA_PAN_RX_PATH, BTA_PAN_OPEN_ST},
+ /* CI_TX_FLOW */ {BTA_PAN_TX_FLOW, BTA_PAN_OPEN_ST},
+ /* CI_RX_WRITE */ {BTA_PAN_IGNORE, BTA_PAN_OPEN_ST},
+ /* CI_RX_WRITEBUF */ {BTA_PAN_WRITE_BUF, BTA_PAN_OPEN_ST},
+ /* PAN_CONN_OPEN */ {BTA_PAN_IGNORE, BTA_PAN_OPEN_ST},
+ /* PAN_CONN_CLOSE */ {BTA_PAN_CONN_CLOSE, BTA_PAN_IDLE_ST},
+ /* FLOW_ENABLE */ {BTA_PAN_RX_PATH, BTA_PAN_OPEN_ST},
+ /* BNEP_DATA */ {BTA_PAN_TX_PATH, BTA_PAN_OPEN_ST}
+};
+
+/* state table for closing state */
+const UINT8 bta_pan_st_closing[][BTA_PAN_NUM_COLS] =
+{
+ /* API_CLOSE */ {BTA_PAN_IGNORE, BTA_PAN_CLOSING_ST},
+ /* CI_TX_READY */ {BTA_PAN_TX_PATH, BTA_PAN_CLOSING_ST},
+ /* CI_RX_READY */ {BTA_PAN_RX_PATH, BTA_PAN_CLOSING_ST},
+ /* CI_TX_FLOW */ {BTA_PAN_TX_FLOW, BTA_PAN_CLOSING_ST},
+ /* CI_RX_WRITE */ {BTA_PAN_IGNORE, BTA_PAN_CLOSING_ST},
+ /* CI_RX_WRITEBUF */ {BTA_PAN_FREE_BUF, BTA_PAN_CLOSING_ST},
+ /* PAN_CONN_OPEN */ {BTA_PAN_IGNORE, BTA_PAN_CLOSING_ST},
+ /* PAN_CONN_CLOSE */ {BTA_PAN_CONN_CLOSE, BTA_PAN_IDLE_ST},
+ /* FLOW_ENABLE */ {BTA_PAN_RX_PATH, BTA_PAN_CLOSING_ST},
+ /* BNEP_DATA */ {BTA_PAN_TX_PATH, BTA_PAN_CLOSING_ST}
+};
+
+/* type for state table */
+typedef const UINT8 (*tBTA_PAN_ST_TBL)[BTA_PAN_NUM_COLS];
+
+/* state table */
+const tBTA_PAN_ST_TBL bta_pan_st_tbl[] = {
+ bta_pan_st_idle,
+ bta_pan_st_open,
+ bta_pan_st_closing
+};
+
+/*****************************************************************************
+** Global data
+*****************************************************************************/
+
+/* PAN control block */
+#if BTA_DYNAMIC_MEMORY == FALSE
+tBTA_PAN_CB bta_pan_cb;
+#endif
+
+/*******************************************************************************
+**
+** Function bta_pan_scb_alloc
+**
+** Description Allocate a PAN server control block.
+**
+**
+** Returns pointer to the scb, or NULL if none could be allocated.
+**
+*******************************************************************************/
+tBTA_PAN_SCB *bta_pan_scb_alloc(void)
+{
+ tBTA_PAN_SCB *p_scb = &bta_pan_cb.scb[0];
+ int i;
+
+ for (i = 0; i < BTA_PAN_NUM_CONN; i++, p_scb++)
+ {
+ if (!p_scb->in_use)
+ {
+ p_scb->in_use = TRUE;
+ APPL_TRACE_DEBUG1("bta_pan_scb_alloc %d", i);
+ break;
+ }
+ }
+
+ if (i == BTA_PAN_NUM_CONN)
+ {
+ /* out of scbs */
+ p_scb = NULL;
+ APPL_TRACE_WARNING0("Out of scbs");
+ }
+ return p_scb;
+}
+
+/*******************************************************************************
+**
+** Function bta_pan_sm_execute
+**
+** Description State machine event handling function for PAN
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_pan_sm_execute(tBTA_PAN_SCB *p_scb, UINT16 event, tBTA_PAN_DATA *p_data)
+{
+ tBTA_PAN_ST_TBL state_table;
+ UINT8 action;
+ int i;
+
+ APPL_TRACE_EVENT3("PAN scb=%d event=0x%x state=%d", bta_pan_scb_to_idx(p_scb), event, p_scb->state);
+
+ /* look up the state table for the current state */
+ state_table = bta_pan_st_tbl[p_scb->state];
+
+ event &= 0x00FF;
+
+ /* set next state */
+ p_scb->state = state_table[event][BTA_PAN_NEXT_STATE];
+
+ /* execute action functions */
+ for (i = 0; i < BTA_PAN_ACTIONS; i++)
+ {
+ if ((action = state_table[event][i]) != BTA_PAN_IGNORE)
+ {
+ (*bta_pan_action[action])(p_scb, p_data);
+ }
+ else
+ {
+ break;
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_pan_api_enable
+**
+** Description Handle an API enable event.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_pan_api_enable(tBTA_PAN_DATA *p_data)
+{
+ /* initialize control block */
+ memset(&bta_pan_cb, 0, sizeof(bta_pan_cb));
+
+ /* store callback function */
+ bta_pan_cb.p_cback = p_data->api_enable.p_cback;
+ bta_pan_enable(p_data);
+}
+
+/*******************************************************************************
+**
+** Function bta_pan_api_disable
+**
+** Description Handle an API disable event.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_pan_api_disable(tBTA_PAN_DATA *p_data)
+{
+ bta_pan_disable();
+}
+
+
+/*******************************************************************************
+**
+** Function bta_pan_api_open
+**
+** Description Handle an API listen event.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_pan_api_open(tBTA_PAN_DATA *p_data)
+{
+ tBTA_PAN_SCB *p_scb;
+ tBTA_PAN_OPEN data;
+
+ /* allocate an scb */
+ if ((p_scb = bta_pan_scb_alloc()) != NULL)
+ {
+ bta_pan_open(p_scb, p_data);
+ }
+ else
+ {
+ bdcpy(data.bd_addr, p_data->api_open.bd_addr);
+ data.status = BTA_PAN_FAIL;
+ bta_pan_cb.p_cback(BTA_PAN_OPEN_EVT, (tBTA_PAN *)&data);
+
+ }
+}
+/*******************************************************************************
+**
+** Function bta_pan_scb_dealloc
+**
+** Description Deallocate a link control block.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pan_scb_dealloc(tBTA_PAN_SCB *p_scb)
+{
+ APPL_TRACE_DEBUG1("bta_pan_scb_dealloc %d", bta_pan_scb_to_idx(p_scb));
+ memset(p_scb, 0, sizeof(tBTA_PAN_SCB));
+}
+
+/*******************************************************************************
+**
+** Function bta_pan_scb_to_idx
+**
+** Description Given a pointer to an scb, return its index.
+**
+**
+** Returns Index of scb.
+**
+*******************************************************************************/
+UINT8 bta_pan_scb_to_idx(tBTA_PAN_SCB *p_scb)
+{
+
+ return ((UINT8) (p_scb - bta_pan_cb.scb)) + 1;
+}
+
+
+
+/*******************************************************************************
+**
+** Function bta_pan_scb_by_handle
+**
+** Description Find scb associated with handle.
+**
+**
+** Returns Pointer to scb or NULL if not found.
+**
+*******************************************************************************/
+tBTA_PAN_SCB *bta_pan_scb_by_handle(UINT16 handle)
+{
+ tBTA_PAN_SCB *p_scb = &bta_pan_cb.scb[0];
+ UINT8 i;
+
+ for (i = 0; i < BTA_PAN_NUM_CONN; i++, p_scb++)
+ {
+ if (p_scb->handle == handle)
+ {
+ return p_scb;;
+ }
+ }
+
+
+ APPL_TRACE_WARNING1("No scb for handle %d", handle);
+
+ return NULL;
+}
+
+/*******************************************************************************
+**
+** Function bta_pan_hdl_event
+**
+** Description Data gateway main event handling function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BOOLEAN bta_pan_hdl_event(BT_HDR *p_msg)
+{
+ tBTA_PAN_SCB *p_scb;
+ BOOLEAN freebuf = TRUE;
+
+ switch (p_msg->event)
+ {
+ /* handle enable event */
+ case BTA_PAN_API_ENABLE_EVT:
+ bta_pan_api_enable((tBTA_PAN_DATA *) p_msg);
+ break;
+
+ /* handle disable event */
+ case BTA_PAN_API_DISABLE_EVT:
+ bta_pan_api_disable((tBTA_PAN_DATA *) p_msg);
+ break;
+
+ /* handle set role event */
+ case BTA_PAN_API_SET_ROLE_EVT:
+ bta_pan_set_role((tBTA_PAN_DATA *) p_msg);
+ break;
+
+ /* handle open event */
+ case BTA_PAN_API_OPEN_EVT:
+ bta_pan_api_open((tBTA_PAN_DATA *) p_msg);
+ break;
+
+
+ /* events that require buffer not be released */
+ case BTA_PAN_CI_RX_WRITEBUF_EVT:
+ freebuf = FALSE;
+ if ((p_scb = bta_pan_scb_by_handle(p_msg->layer_specific)) != NULL)
+ {
+ bta_pan_sm_execute(p_scb, p_msg->event, (tBTA_PAN_DATA *) p_msg);
+ }
+ break;
+
+ /* all other events */
+ default:
+ if ((p_scb = bta_pan_scb_by_handle(p_msg->layer_specific)) != NULL)
+ {
+ bta_pan_sm_execute(p_scb, p_msg->event, (tBTA_PAN_DATA *) p_msg);
+ }
+ break;
+
+ }
+ return freebuf;
+}
+#endif /* BTA_PAN_INCLUDED */
diff --git a/bta/pb/bta_pbs_act.c b/bta/pb/bta_pbs_act.c
new file mode 100644
index 0000000..98f6463
--- /dev/null
+++ b/bta/pb/bta_pbs_act.c
@@ -0,0 +1,1134 @@
+/*****************************************************************************
+**
+** Name: bta_pbs_act.c
+**
+** Description: This file contains the phone book access server
+** functions for the state machine.
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+
+#if defined(BTA_PBS_INCLUDED) && (BTA_PBS_INCLUDED == TRUE)
+
+#include <string.h>
+#include "gki.h"
+#include "bta_sys.h"
+#include "obx_api.h"
+#include "bta_fs_api.h"
+#include "bta_pbs_api.h"
+#include "bta_pbs_int.h"
+#include "btm_api.h"
+#include "utl.h"
+#include "bd.h"
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+#define FLAGS_ARE_MASK (OBX_SPF_BACKUP | OBX_SPF_NO_CREATE)
+#define FLAGS_ARE_ILLEGAL 0x1 /* 'Backup and Create flag combo is BAD */
+/*****************************************************************************
+** Local Function prototypes
+*****************************************************************************/
+#if BTA_PBS_DEBUG == TRUE
+static char *pbs_obx_evt_code(tOBX_EVENT evt_code);
+#endif
+
+/*****************************************************************************
+** Action Functions
+*****************************************************************************/
+/*******************************************************************************
+**
+** Function bta_pbs_api_disable
+**
+** Description Stop PBS server.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pbs_api_disable(tBTA_PBS_CB *p_cb, tBTA_PBS_DATA *p_data)
+{
+ /* Free any outstanding headers and control block memory */
+ bta_pbs_clean_getput(p_cb, TRUE);
+
+ /* Stop the OBEX server */
+ OBX_StopServer(p_cb->obx_handle);
+
+ /* Remove the PBS service from the SDP database */
+ SDP_DeleteRecord(p_cb->sdp_handle);
+ bta_sys_remove_uuid(UUID_SERVCLASS_PBAP_PSE);
+ /* Free the allocated server channel number */
+ BTM_FreeSCN(p_cb->scn);
+ BTM_SecClrService(BTM_SEC_SERVICE_PBAP);
+
+ utl_freebuf((void**)&p_cb->p_rootpath); /* Free buffer containing root and working paths */
+}
+
+/*******************************************************************************
+**
+** Function bta_pbs_api_authrsp
+**
+** Description Pass the response to an authentication request back to the
+** client.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pbs_api_authrsp(tBTA_PBS_CB *p_cb, tBTA_PBS_DATA *p_data)
+{
+ UINT8 *p_pwd = NULL;
+ UINT8 *p_userid = NULL;
+
+ if (p_data->auth_rsp.key_len > 0)
+ p_pwd = (UINT8 *)p_data->auth_rsp.key;
+ if (p_data->auth_rsp.userid_len > 0)
+ p_userid = (UINT8 *)p_data->auth_rsp.userid;
+
+ OBX_Password(p_cb->obx_handle, p_pwd, p_data->auth_rsp.key_len,
+ p_userid, p_data->auth_rsp.userid_len);
+}
+
+/*******************************************************************************
+**
+** Function bta_pbs_api_close
+**
+** Description Handle an api close event.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pbs_api_close(tBTA_PBS_CB *p_cb, tBTA_PBS_DATA *p_data)
+{
+ BD_ADDR bd_addr;
+ if (OBX_GetPeerAddr(p_cb->obx_handle, bd_addr) != 0)
+ {
+ /* resources will be freed at BTA_PBS_OBX_CLOSE_EVT */
+ OBX_DisconnectRsp(p_cb->obx_handle, OBX_RSP_SERVICE_UNAVL, NULL);
+ }
+ else
+ {
+ p_cb->p_cback(BTA_PBS_CLOSE_EVT, 0);
+}
+}
+
+
+/*******************************************************************************
+**
+** Function bta_pbs_api_accessrsp
+**
+** Description Process the access API event.
+** If permission had been granted, continue the operation,
+** otherwise stop the operation.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pbs_api_accessrsp(tBTA_PBS_CB *p_cb, tBTA_PBS_DATA *p_data)
+{
+ UINT8 rsp_code = OBX_RSP_OK;
+ tBTA_PBS_CO_STATUS status = BTA_PBS_CO_EACCES;
+ tBTA_PBS_ACCESS_TYPE access = p_data->access_rsp.flag;
+ tBTA_PBS_OPER old_acc_active = p_cb->acc_active;
+ tBTA_PBS_OBX_RSP *p_rsp = NULL;
+ tBTA_PBS_OBJECT objevt;
+
+ if(p_cb->acc_active != p_data->access_rsp.oper )
+ {
+ APPL_TRACE_WARNING2("PBS ACCRSP: not match active:%d, rsp:%d",
+ p_cb->acc_active, p_data->access_rsp.oper);
+ return;
+ }
+
+ p_cb->acc_active = 0;
+ /* Process the currently active access response */
+ switch (old_acc_active)
+ {
+ case BTA_PBS_OPER_PULL_PB:
+ case BTA_PBS_OPER_PULL_VCARD_ENTRY:
+ if (access == BTA_PBS_ACCESS_TYPE_ALLOW)
+ {
+ p_cb->cout_active = TRUE;
+ bta_pbs_co_open(p_cb->p_path, p_cb->obx_oper, &p_cb->pullpb_app_params);
+ }
+
+ /* Case where application determined requested vCard handle has been modified: Requests a new listing to clear */
+ else if (access == BTA_PBS_ACCESS_TYPE_PRECONDITION && old_acc_active == BTA_PBS_OPER_PULL_VCARD_ENTRY)
+ bta_pbs_get_file_rsp(OBX_RSP_PRECONDTN_FAILED, 0);
+ else /* Denied */
+ bta_pbs_get_file_rsp(OBX_RSP_UNAUTHORIZED, 0);
+ break;
+ case BTA_PBS_OPER_PULL_VCARD_LIST:
+ if (access == BTA_PBS_ACCESS_TYPE_ALLOW)
+ {
+ /* continue with get vlist */
+ bta_pbs_getvlist(p_cb->p_name);
+ }
+ else
+ bta_pbs_get_file_rsp(OBX_RSP_UNAUTHORIZED, 0);
+ break;
+
+ case BTA_PBS_OPER_SET_PB: /* Request is a Change Folder */
+ p_rsp = OBX_SetPathRsp;
+ if (access == BTA_PBS_ACCESS_TYPE_ALLOW)
+ {
+ status = BTA_PBS_CO_OK;
+ /* set obj type based on path */
+ if (!memcmp(p_cb->p_name, BTA_PBS_PBFOLDER_NAME, sizeof(BTA_PBS_PBFOLDER_NAME)))
+ p_cb->obj_type = BTA_PBS_PB_OBJ;
+ if (!memcmp(p_cb->p_name, BTA_PBS_ICHFOLDER_NAME, sizeof(BTA_PBS_ICHFOLDER_NAME)))
+ p_cb->obj_type = BTA_PBS_ICH_OBJ;
+ if (!memcmp(p_cb->p_name, BTA_PBS_OCHFOLDER_NAME, sizeof(BTA_PBS_OCHFOLDER_NAME)))
+ p_cb->obj_type = BTA_PBS_OCH_OBJ;
+ if (!memcmp(p_cb->p_name, BTA_PBS_MCHFOLDER_NAME, sizeof(BTA_PBS_MCHFOLDER_NAME)))
+ p_cb->obj_type = BTA_PBS_MCH_OBJ;
+ if (!memcmp(p_cb->p_name, BTA_PBS_CCHFOLDER_NAME, sizeof(BTA_PBS_CCHFOLDER_NAME)))
+ p_cb->obj_type = BTA_PBS_CCH_OBJ;
+ BCM_STRNCPY_S(p_cb->p_workdir, p_bta_fs_cfg->max_path_len+1, p_cb->p_path, p_bta_fs_cfg->max_path_len);
+ p_cb->p_workdir[p_bta_fs_cfg->max_path_len] = '\0';
+ APPL_TRACE_DEBUG1("PBS: SET NEW PATH [%s]", p_cb->p_workdir);
+ }
+ break;
+
+ default:
+ p_cb->acc_active = old_acc_active;
+ APPL_TRACE_WARNING1("PBS ACCRSP: Unknown tBTA_PBS_OPER value (%d)",
+ p_cb->acc_active);
+ break;
+ }
+
+ /* Set Path Done */
+ if(p_rsp && old_acc_active == BTA_PBS_OPER_SET_PB)
+ {
+ switch (status)
+ {
+ case BTA_PBS_CO_OK:
+ rsp_code = OBX_RSP_OK;
+ break;
+ case BTA_PBS_CO_EACCES:
+ rsp_code = OBX_RSP_UNAUTHORIZED;
+ break;
+ default:
+ rsp_code = OBX_RSP_SERVICE_UNAVL;
+ break;
+ }
+ if (p_cb->p_cback)
+ {
+ objevt.operation = p_cb->obx_oper;
+ objevt.p_name = p_cb->p_path;
+ objevt.status = (status == BTA_PBS_CO_OK ? BTA_PBS_OK: BTA_PBS_FAIL);
+ (p_cb->p_cback) (BTA_PBS_OPER_CMPL_EVT, (tBTA_PBS *) &objevt);
+ }
+ utl_freebuf((void**)&p_cb->p_name);
+ utl_freebuf((void**)&p_cb->p_path);
+ p_cb->obx_oper = BTA_PBS_OPER_NONE;
+ (*p_rsp)(p_cb->obx_handle, rsp_code, (BT_HDR *)NULL);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function bta_pbs_ci_vlist_act
+**
+** Description Continue getting the current vlist entry operation
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pbs_ci_vlist_act(tBTA_PBS_CB *p_cb, tBTA_PBS_DATA *p_data)
+{
+ UINT8 rsp_code;
+ tBTA_PBS_CI_VLIST_EVT *p_revt = &p_data->vlist_evt;
+
+ p_cb->cout_active = FALSE;
+
+ /* Process vcard listing call-in event if operation is still active */
+ if (p_cb->obx_oper == BTA_PBS_OPER_PULL_VCARD_LIST)
+ {
+ switch (p_revt->status)
+ {
+ case BTA_PBS_CO_OK:
+ p_cb->num_vlist_idxs++;
+
+ /* Valid new entry */
+ if (!strcmp(p_cb->vlist.handle, ".") || !strcmp(p_cb->vlist.handle, "..")
+ || p_cb->vlist.handle[0] == '\0') {
+ /* don't count this entry */
+ p_cb->num_vlist_idxs--;
+
+ /* continue get */
+ if (p_revt->final) {
+ /* if it is final */
+ bta_pbs_end_of_list(OBX_RSP_OK);
+ } else {
+ p_cb->cout_active = TRUE;
+ bta_pbs_co_getvlist(p_cb->p_path, &p_cb->getvlist_app_params,
+ FALSE, &p_cb->vlist);
+ }
+ } else if ((rsp_code = bta_pbs_add_list_entry()) == OBX_RSP_OK) {
+ /* if we can add the entry */
+ if (p_revt->final) {
+ /* if it is final */
+ bta_pbs_end_of_list(rsp_code);
+ } else {
+ /* continue get */
+ p_cb->cout_active = TRUE;
+ bta_pbs_co_getvlist(p_cb->p_path, &p_cb->getvlist_app_params,
+ FALSE, &p_cb->vlist);
+ }
+ } else if (rsp_code == OBX_RSP_CONTINUE) {
+ /* do not have enough data buffer, send obex continue to client */
+ if (p_revt->final) {
+ /* if this is the last VCard list entry */
+ p_cb->obx.final_pkt = TRUE;
+ }
+ bta_pbs_end_of_list(rsp_code);
+ } else {
+ bta_pbs_end_of_list(rsp_code);
+ }
+ break;
+
+ case BTA_PBS_CO_FAIL: /* Error occurred */
+ bta_pbs_end_of_list(OBX_RSP_SERVICE_UNAVL);
+ break;
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_pbs_ci_read
+**
+** Description Handles the response to a read call-out request.
+** This is called within the OBX get file request. If the
+** operation has completed, the OBX response is sent out;
+** otherwise a read for additional data is made.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pbs_ci_read_act(tBTA_PBS_CB *p_cb, tBTA_PBS_DATA *p_data)
+{
+ tBTA_PBS_CI_READ_EVT *p_revt = &p_data->read_evt;
+ UINT8 rsp_code = OBX_RSP_SERVICE_UNAVL;
+
+ p_cb->cout_active = FALSE;
+ if (p_cb->aborting)
+ {
+ bta_pbs_clean_getput(p_cb, TRUE);
+ OBX_AbortRsp(p_cb->obx_handle, OBX_RSP_OK, (BT_HDR *)NULL);
+ return;
+ }
+
+ /* Process read call-in event if operation is still active */
+ if ((p_cb->obx_oper == BTA_PBS_OPER_PULL_PB || p_cb->obx_oper == BTA_PBS_OPER_PULL_VCARD_ENTRY)
+ && p_revt->fd == p_cb->fd)
+ {
+ /* Read was successful, not finished yet */
+ if (p_revt->status == BTA_PBS_CO_OK && !p_revt->final)
+ rsp_code = OBX_RSP_CONTINUE;
+ if (p_revt->status == BTA_PBS_CO_OK && p_revt->final)
+ rsp_code = OBX_RSP_OK;
+
+ /* Process response to OBX client */
+ bta_pbs_get_file_rsp(rsp_code, p_revt->num_read);
+ }
+ else
+ {
+ bta_pbs_get_file_rsp(rsp_code, 0);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_pbs_ci_open
+**
+** Description Continue with the current file open operation
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pbs_ci_open_act(tBTA_PBS_CB *p_cb, tBTA_PBS_DATA *p_data)
+{
+ tBTA_PBS_CI_OPEN_EVT *p_open = &p_data->open_evt;
+ UINT8 rsp_code = OBX_RSP_OK;
+ tBTA_PBS_OBX_PKT *p_obx = &p_cb->obx;
+ UINT16 pb_size = 0, new_missed_call = 0, len=0;
+ UINT8 *p, *p_start;
+
+ p_cb->cout_active = FALSE;
+
+ if (p_cb->aborting)
+ {
+ bta_pbs_clean_getput(p_cb, TRUE);
+ OBX_AbortRsp(p_cb->obx_handle, OBX_RSP_OK, (BT_HDR *)NULL);
+ return;
+ }
+
+ /* Only process file get operations */
+ if (p_cb->obx_oper == BTA_PBS_OPER_PULL_PB || p_cb->obx_oper == BTA_PBS_OPER_PULL_VCARD_ENTRY)
+ {
+ if (p_open->status == BTA_PBS_CO_OK)
+ {
+ p_cb->file_length = p_open->file_size;
+ p_cb->fd = p_open->fd;
+
+ /* add other application header */
+ if (p_cb->obx_oper == BTA_PBS_OPER_PULL_PB)
+ {
+ if (p_cb->pullpb_app_params.max_count == 0 ||
+ p_cb->obj_type == BTA_PBS_MCH_OBJ)
+ {
+ p_start = OBX_AddByteStrStart(p_obx->p_pkt, &len);
+ bta_pbs_co_getpbinfo(p_cb->obx_oper, p_cb->obj_type, &pb_size, &new_missed_call);
+ p = p_start;
+ if (p_cb->pullpb_app_params.max_count == 0)
+ {
+ *p++ = BTA_PBS_TAG_PB_SIZE;
+ *p++ = 2;
+ UINT16_TO_BE_STREAM(p, pb_size);
+ /* if max count = 0, client want to know the pb size */
+ p_cb->file_length = 0;
+ }
+ if (p_cb->obj_type == BTA_PBS_MCH_OBJ)
+ {
+ *p++ = BTA_PBS_TAG_NEW_MISSED_CALLS;
+ *p++ = 1;
+ *p++ = (UINT8) new_missed_call;
+ }
+ OBX_AddByteStrHdr(p_obx->p_pkt, OBX_HI_APP_PARMS, NULL, (UINT16)(p - p_start));
+ }
+ }
+
+ if (p_cb->file_length > 0)
+ {
+ /* contiune to get file */
+ bta_pbs_proc_get_file(p_cb->p_name, p_cb->obx_oper);
+ }
+ else
+ {
+ /* If file length is zero, add end body header */
+ if (((p_cb->obx_oper == BTA_PBS_OPER_PULL_PB) && p_cb->pullpb_app_params.max_count) || p_cb->obx_oper == BTA_PBS_OPER_PULL_VCARD_ENTRY)
+ {
+ p_obx->offset = 0;
+ p_obx->bytes_left = 0;
+ p_obx->p_start = OBX_AddBodyStart(p_obx->p_pkt, &p_obx->bytes_left);
+ OBX_AddBodyEnd(p_obx->p_pkt, p_obx->p_start, 0, TRUE);
+ }
+ bta_pbs_get_file_rsp(rsp_code, 0);
+ }
+ }
+ else
+ {
+ if (p_open->status == BTA_PBS_CO_EACCES)
+ rsp_code = OBX_RSP_UNAUTHORIZED;
+ else /* File could not be found */
+ rsp_code = OBX_RSP_NOT_FOUND;
+
+ /* Send OBX response if an error occurred */
+ bta_pbs_get_file_rsp(rsp_code, 0);
+ }
+ }
+
+ return;
+
+}
+
+
+/*******************************************************************************
+**
+** Function bta_pbs_obx_connect
+**
+** Description Process the OBX connect event
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pbs_obx_connect(tBTA_PBS_CB *p_cb, tBTA_PBS_DATA *p_data)
+{
+ tBTA_PBS_OBX_EVENT *p_evt = &p_data->obx_evt;
+ tBTA_PBS_OPEN open_evt;
+ char *p_devname;
+
+ p_cb->peer_mtu = p_evt->param.conn.mtu;
+ memcpy(p_cb->bd_addr, p_evt->param.conn.peer_addr, BD_ADDR_LEN);
+ APPL_TRACE_EVENT1("PBS Connect: peer mtu 0x%04x", p_cb->peer_mtu);
+
+ OBX_ConnectRsp(p_evt->handle, OBX_RSP_OK, (BT_HDR *)NULL);
+
+ /* Reset to the root directory */
+ BCM_STRNCPY_S(p_cb->p_workdir, p_bta_fs_cfg->max_path_len+1, p_cb->p_rootpath, p_bta_fs_cfg->max_path_len);
+ p_cb->p_workdir[p_bta_fs_cfg->max_path_len] = '\0';
+
+ /* inform role manager */
+ bta_sys_conn_open(BTA_ID_PBS ,p_cb->app_id, p_cb->bd_addr);
+
+ /* Notify the MMI that a connection has been opened */
+ memcpy(open_evt.bd_addr, p_evt->param.conn.peer_addr, BD_ADDR_LEN);
+ if ((p_devname = BTM_SecReadDevName(p_cb->bd_addr)) != NULL)
+ BCM_STRNCPY_S((char *)open_evt.dev_name, sizeof(tBTM_BD_NAME), p_devname, BTM_MAX_REM_BD_NAME_LEN);
+
+ p_cb->p_cback(BTA_PBS_OPEN_EVT, (tBTA_PBS *) &open_evt);
+
+ /* Done with Obex packet */
+ utl_freebuf((void**)&p_evt->p_pkt);
+}
+
+/*******************************************************************************
+**
+** Function bta_pbs_obx_disc
+**
+** Description Process the OBX disconnect event
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pbs_obx_disc(tBTA_PBS_CB *p_cb, tBTA_PBS_DATA *p_data)
+{
+ tBTA_PBS_OBX_EVENT *p_evt = &p_data->obx_evt;
+ UINT8 rsp_code;
+
+ rsp_code = (p_evt->obx_event == OBX_DISCONNECT_REQ_EVT) ? OBX_RSP_OK
+ : OBX_RSP_BAD_REQUEST;
+ OBX_DisconnectRsp(p_evt->handle, rsp_code, (BT_HDR *)NULL);
+
+ /* Done with Obex packet */
+ utl_freebuf((void**)&p_evt->p_pkt);
+}
+
+/*******************************************************************************
+**
+** Function bta_pbs_obx_close
+**
+** Description Process the OBX link lost event
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pbs_obx_close(tBTA_PBS_CB *p_cb, tBTA_PBS_DATA *p_data)
+{
+ /* finished if not waiting on a call-in function */
+ if (!p_cb->cout_active)
+ bta_pbs_sm_execute(p_cb, BTA_PBS_CLOSE_CMPL_EVT, p_data);
+}
+
+/*******************************************************************************
+**
+** Function bta_pbs_obx_abort
+**
+** Description Process the OBX abort event
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pbs_obx_abort(tBTA_PBS_CB *p_cb, tBTA_PBS_DATA *p_data)
+{
+ tBTA_PBS_OBX_EVENT *p_evt = &p_data->obx_evt;
+ UINT8 rsp_code = OBX_RSP_OK;
+
+ utl_freebuf((void**)&p_evt->p_pkt);
+
+ if (!p_cb->cout_active)
+ {
+ bta_pbs_clean_getput(p_cb, TRUE);
+ OBX_AbortRsp(p_cb->obx_handle, rsp_code, (BT_HDR *)NULL);
+ }
+ else /* Delay the response if a call-out function is active */
+ p_cb->aborting = TRUE;
+}
+
+/*******************************************************************************
+**
+** Function bta_pbs_obx_password
+**
+** Description Process the OBX password request
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pbs_obx_password(tBTA_PBS_CB *p_cb, tBTA_PBS_DATA *p_data)
+{
+ tBTA_PBS_OBX_EVENT *p_evt = &p_data->obx_evt;
+ tBTA_PBS_AUTH *p_auth;
+ BOOLEAN is_challenged;
+ tOBX_AUTH_OPT options;
+
+ if ((p_auth = (tBTA_PBS_AUTH *)GKI_getbuf(sizeof(tBTA_PBS_AUTH))) != NULL)
+ {
+ memset(p_auth, 0, sizeof(tBTA_PBS_AUTH));
+
+ /* Extract user id from packet (if available) */
+ if (OBX_ReadAuthParams(p_data->obx_evt.p_pkt, &p_auth->p_userid,
+ &p_auth->userid_len,
+ &is_challenged, &options))
+ {
+ if (options & OBX_AO_USR_ID)
+ p_auth->userid_required = TRUE;
+ }
+
+
+ /* Notify application */
+ p_cb->p_cback(BTA_PBS_AUTH_EVT, (tBTA_PBS *)p_auth);
+
+ GKI_freebuf(p_auth);
+ }
+ /* Don't need OBX packet any longer */
+ utl_freebuf((void**)&p_evt->p_pkt);
+}
+
+
+/*******************************************************************************
+**
+** Function bta_pbs_obx_get
+**
+** Description Process the OBX file get and folder listing events
+** If the type header is not folder listing, then pulling a file.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pbs_obx_get(tBTA_PBS_CB *p_cb, tBTA_PBS_DATA *p_data)
+{
+ tBTA_PBS_OBX_EVENT *p_evt = &p_data->obx_evt;
+ UINT16 len;
+ UINT8 *p_type;
+ UINT8 *p_param;
+ UINT16 param_len;
+ tBTA_PBS_OPER operation = 0;
+
+ /* If currently processing a GET, use the current name */
+ if (bta_pbs_cb.obx_oper == BTA_PBS_OPER_PULL_VCARD_LIST)
+ bta_pbs_getvlist(p_cb->p_name);
+ else if (bta_pbs_cb.obx_oper == BTA_PBS_OPER_PULL_PB ||
+ bta_pbs_cb.obx_oper == BTA_PBS_OPER_PULL_VCARD_ENTRY)
+ bta_pbs_proc_get_file(p_cb->p_name, bta_pbs_cb.obx_oper);
+ else /* This is a new request */
+ {
+ /* Pull out the name header if it exists */
+ if ((p_cb->p_name = (char *)GKI_getbuf((UINT16)(p_bta_fs_cfg->max_file_len + 1))) != NULL)
+ {
+ if (!OBX_ReadUtf8NameHdr(p_evt->p_pkt, (UINT8 *)p_cb->p_name, p_bta_fs_cfg->max_file_len))
+ {
+
+ GKI_freebuf(p_cb->p_name);
+ p_cb->p_name = NULL;
+
+#if 0 /* Peer spec violation, but some platforms do this wrong, so relaxing requirement.
+ enable this if strict error checking needed */
+ utl_freebuf((void**)&p_evt->p_pkt);
+ OBX_GetRsp(p_cb->obx_handle, OBX_RSP_BAD_REQUEST, (BT_HDR *)NULL);
+ return;
+#endif
+ }
+ } else {
+ OBX_GetRsp(p_cb->obx_handle, OBX_RSP_SERVICE_UNAVL, (BT_HDR *)NULL);
+ utl_freebuf((void**)&p_evt->p_pkt);
+ return;
+ }
+
+ /* See what type of operations */
+ if (OBX_ReadTypeHdr(p_evt->p_pkt, &p_type, &len))
+ {
+ if (!memcmp(p_type, BTA_PBS_GETVCARD_LISTING_TYPE, len))
+ {
+
+ if ((p_cb->p_name) && strlen(p_cb->p_name))
+ {
+ APPL_TRACE_EVENT1("PBS VList Get: Name [%s]", p_cb->p_name);
+ }
+ else /* This is a peer spec violation, but allowing for better IOP */
+ {
+ APPL_TRACE_WARNING0("PBS OBX GET: Missing Name Header...Assuming current directory");
+
+ /* Errata 1824: It is illegal to issue a PullvCardListing request with an empty
+ name header from the "telecom" folder */
+ if (p_cb->p_workdir && !strcmp(&(p_cb->p_workdir[strlen(p_cb->p_workdir) - 7]), "telecom"))
+ {
+ utl_freebuf((void**)&p_evt->p_pkt);
+ OBX_GetRsp(p_cb->obx_handle, OBX_RSP_NOT_FOUND, (BT_HDR *)NULL);
+ return;
+ }
+ }
+
+ /* read application params */
+ p_param = bta_pbs_read_app_params(p_evt->p_pkt, BTA_PBS_TAG_MAX_LIST_COUNT, &param_len);
+ if (p_param)
+ {
+ BE_STREAM_TO_UINT16(p_cb->getvlist_app_params.max_count, p_param);
+ }
+ else
+ {
+ p_cb->getvlist_app_params.max_count = BTA_PBS_MAX_LIST_COUNT;
+ }
+
+ p_param = bta_pbs_read_app_params(p_evt->p_pkt, BTA_PBS_TAG_LIST_START_OFFSET, &param_len);
+ if (p_param)
+ {
+ BE_STREAM_TO_UINT16(p_cb->getvlist_app_params.start_offset, p_param);
+ }
+ else
+ {
+ p_cb->getvlist_app_params.start_offset = 0;
+ }
+
+ p_param = bta_pbs_read_app_params(p_evt->p_pkt, BTA_PBS_TAG_ORDER, &param_len);
+ if (p_param)
+ {
+ p_cb->getvlist_app_params.order = *p_param;
+ }
+ else
+ {
+ p_cb->getvlist_app_params.order = BTA_PBS_ORDER_INDEX;
+ }
+
+ p_param = bta_pbs_read_app_params(p_evt->p_pkt, BTA_PBS_TAG_SEARCH_ATTRIBUTE, &param_len);
+ if (p_param)
+ {
+ p_cb->getvlist_app_params.attribute = *p_param;
+ }
+ else
+ {
+ p_cb->getvlist_app_params.attribute = 0;
+ }
+
+ p_param = bta_pbs_read_app_params(p_evt->p_pkt, BTA_PBS_TAG_SEARCH_VALUE, &param_len);
+ if (p_param)
+ {
+ memcpy(p_cb->getvlist_app_params.p_value, p_param, param_len);
+ p_cb->getvlist_app_params.value_len = param_len;
+ }
+ else
+ {
+ p_cb->getvlist_app_params.value_len = 0;
+ }
+
+ /* Assume downloading vCard Listing if no name */
+ p_cb->obj_type = BTA_PBS_PB_OBJ;
+
+ if (p_cb->p_name)
+ {
+/* if (!memcmp(p_cb->p_name, BTA_PBS_PBFOLDER_NAME, sizeof(BTA_PBS_PBFOLDER_NAME)))
+ p_cb->obj_type = BTA_PBS_PB_OBJ; <-- default type */
+ if (!memcmp(p_cb->p_name, BTA_PBS_ICHFOLDER_NAME, sizeof(BTA_PBS_ICHFOLDER_NAME)))
+ p_cb->obj_type = BTA_PBS_ICH_OBJ;
+ else if (!memcmp(p_cb->p_name, BTA_PBS_OCHFOLDER_NAME, sizeof(BTA_PBS_OCHFOLDER_NAME)))
+ p_cb->obj_type = BTA_PBS_OCH_OBJ;
+ else if (!memcmp(p_cb->p_name, BTA_PBS_MCHFOLDER_NAME, sizeof(BTA_PBS_MCHFOLDER_NAME)))
+ p_cb->obj_type = BTA_PBS_MCH_OBJ;
+ else if (!memcmp(p_cb->p_name, BTA_PBS_CCHFOLDER_NAME, sizeof(BTA_PBS_CCHFOLDER_NAME)))
+ p_cb->obj_type = BTA_PBS_CCH_OBJ;
+ }
+ bta_pbs_getvlist(p_cb->p_name);
+ }
+ else if (!memcmp(p_type, BTA_PBS_GETFILE_TYPE, len) ||
+ !memcmp(p_type, BTA_PBS_GETVARD_ENTRY_TYPE, len))
+ {
+ if (!memcmp(p_type, BTA_PBS_GETFILE_TYPE, len))
+ operation = BTA_PBS_OPER_PULL_PB;
+ else
+ operation = BTA_PBS_OPER_PULL_VCARD_ENTRY;
+ /* read application params */
+ if (p_cb->p_name)
+ {
+ APPL_TRACE_EVENT2("PBS File Get: Name [%s], operation %d", p_cb->p_name, operation);
+ }
+
+ p_param = bta_pbs_read_app_params(p_evt->p_pkt, BTA_PBS_TAG_FILTER, &param_len);
+ if (p_param)
+ {
+ if (param_len == 8)
+ p_param += 4; /* skip the first 4 bytes, we do not handle proprietary AttributesMask */
+ BE_STREAM_TO_UINT32(p_cb->pullpb_app_params.filter, p_param);
+ }
+ else
+ {
+ p_cb->pullpb_app_params.filter = BTA_PBS_FILTER_ALL;
+ }
+
+ p_param = bta_pbs_read_app_params(p_evt->p_pkt, BTA_PBS_TAG_FORMAT, &param_len);
+ if (p_param)
+ {
+ p_cb->pullpb_app_params.format = *p_param;
+ }
+ else
+ {
+ p_cb->pullpb_app_params.format = BTA_PBS_VCF_FMT_21;
+ }
+
+ /* set the object type for pull pb */
+ if (operation == BTA_PBS_OPER_PULL_PB)
+ {
+ if (p_cb->p_name == NULL)
+ OBX_GetRsp(p_cb->obx_handle, OBX_RSP_BAD_REQUEST, (BT_HDR *)NULL);
+ else
+ {
+ if (!memcmp(p_cb->p_name, BTA_PBS_PULLPB_NAME, sizeof(BTA_PBS_PULLPB_NAME)))
+ p_cb->obj_type = BTA_PBS_PB_OBJ;
+ if (!memcmp(p_cb->p_name, BTA_PBS_PULLICH_NAME, sizeof(BTA_PBS_PULLICH_NAME)))
+ p_cb->obj_type = BTA_PBS_ICH_OBJ;
+ if (!memcmp(p_cb->p_name, BTA_PBS_PULLOCH_NAME, sizeof(BTA_PBS_PULLOCH_NAME)))
+ p_cb->obj_type = BTA_PBS_OCH_OBJ;
+ if (!memcmp(p_cb->p_name, BTA_PBS_PULLMCH_NAME, sizeof(BTA_PBS_PULLMCH_NAME)))
+ p_cb->obj_type = BTA_PBS_MCH_OBJ;
+ if (!memcmp(p_cb->p_name, BTA_PBS_PULLCCH_NAME, sizeof(BTA_PBS_PULLCCH_NAME)))
+ p_cb->obj_type = BTA_PBS_CCH_OBJ;
+ }
+ }
+ /* for pull pb, read app params for max list count and start offset */
+ if (operation == BTA_PBS_OPER_PULL_PB)
+ {
+ p_param = bta_pbs_read_app_params(p_evt->p_pkt, BTA_PBS_TAG_MAX_LIST_COUNT, &param_len);
+ if (p_param)
+ BE_STREAM_TO_UINT16(p_cb->pullpb_app_params.max_count, p_param);
+ p_param = bta_pbs_read_app_params(p_evt->p_pkt, BTA_PBS_TAG_LIST_START_OFFSET, &param_len);
+ if (p_param)
+ {
+ BE_STREAM_TO_UINT16(p_cb->pullpb_app_params.start_offset, p_param);
+ }
+ else
+ {
+ p_cb->pullpb_app_params.start_offset = 0;
+ }
+ }
+ bta_pbs_proc_get_file(p_cb->p_name, operation);
+ }
+ else {
+ OBX_GetRsp(p_cb->obx_handle, OBX_RSP_BAD_REQUEST, (BT_HDR *)NULL);
+ }
+ }
+ }
+
+ /* Done with Obex packet */
+ utl_freebuf((void**)&p_evt->p_pkt);
+}
+
+/*******************************************************************************
+**
+** Function bta_pbs_obx_setpath
+**
+** Description Process the PBS change directory requests
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pbs_obx_setpath(tBTA_PBS_CB *p_cb, tBTA_PBS_DATA *p_data)
+{
+ tBTA_PBS_OBX_EVENT *p_evt = &p_data->obx_evt;
+ UINT8 rsp_code = OBX_RSP_BAD_REQUEST;
+ tOBX_SETPATH_FLAG *p_flag = &p_evt->param.sp.flag;
+ tBTA_PBS_OPER pbs_op = 0;
+ tBTA_PBS_OBJECT objevt;
+
+ /* Verify flags and handle before accepting */
+ if (p_evt->handle == p_cb->obx_handle &&
+ (((*p_flag) & FLAGS_ARE_MASK) != FLAGS_ARE_ILLEGAL))
+ {
+ p_cb->obx_oper = BTA_PBS_OPER_SET_PB;
+ p_cb->p_name = (char *)GKI_getbuf((UINT16)(p_bta_fs_cfg->max_file_len + 1));
+ p_cb->p_path = (char *)GKI_getbuf((UINT16)(p_bta_fs_cfg->max_path_len +
+ p_bta_fs_cfg->max_file_len + 2));
+ if (p_cb->p_name != NULL && p_cb->p_path != NULL)
+ {
+ if (!OBX_ReadUtf8NameHdr(p_evt->p_pkt, (UINT8 *)p_cb->p_name, p_bta_fs_cfg->max_file_len))
+ {
+ p_cb->p_name[0] = 0;
+ }
+
+ rsp_code = bta_pbs_chdir(p_evt->p_pkt, (BOOLEAN)((*p_flag) & OBX_SPF_BACKUP), &pbs_op);
+ }
+ else
+ rsp_code = OBX_RSP_SERVICE_UNAVL;
+ }
+
+ if(pbs_op)
+ {
+ bta_pbs_req_app_access(pbs_op, p_cb);
+ }
+ else
+ {
+ if (p_cb->p_cback)
+ {
+ objevt.operation = BTA_PBS_OPER_SET_PB;
+ objevt.p_name = p_cb->p_path;
+ objevt.status = (rsp_code == OBX_RSP_OK ? BTA_PBS_OK: BTA_PBS_FAIL);
+ (p_cb->p_cback) (BTA_PBS_OPER_CMPL_EVT, (tBTA_PBS *) &objevt);
+ }
+ p_cb->obx_oper = BTA_PBS_OPER_NONE;
+ OBX_SetPathRsp(p_evt->handle, rsp_code, (BT_HDR *)NULL);
+ utl_freebuf((void**)&p_cb->p_name);
+ utl_freebuf((void**)&p_cb->p_path);
+ }
+
+ /* Done with Obex packet */
+ utl_freebuf((void**)&p_evt->p_pkt);
+}
+
+/*******************************************************************************
+**
+** Function bta_pbs_appl_tout
+**
+** Description Process the PBS application timeout event
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pbs_appl_tout(tBTA_PBS_CB *p_cb, tBTA_PBS_DATA *p_data)
+{
+}
+
+/*******************************************************************************
+**
+** Function bta_pbs_conn_err_rsp
+**
+** Description Process the OBX error response
+** Connect request received in wrong state, or bad request
+** from client
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pbs_conn_err_rsp(tBTA_PBS_CB *p_cb, tBTA_PBS_DATA *p_data)
+{
+ OBX_ConnectRsp(p_data->obx_evt.handle, OBX_RSP_BAD_REQUEST, (BT_HDR *)NULL);
+}
+
+/*******************************************************************************
+**
+** Function bta_pbs_disc_err_rsp
+**
+** Description Process the OBX error response
+** Disconnect request received in wrong state, or bad request
+** from client
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pbs_disc_err_rsp(tBTA_PBS_CB *p_cb, tBTA_PBS_DATA *p_data)
+{
+ OBX_DisconnectRsp(p_data->obx_evt.handle, OBX_RSP_BAD_REQUEST, (BT_HDR *)NULL);
+}
+
+/*******************************************************************************
+**
+** Function bta_pbs_gasp_err_rsp
+**
+** Description Process the OBX error response for Get, Abort, Setpath.
+**
+** The rsp_code field of tBTA_PBS_DATA (obx_evt) contains the
+** response code to be sent to OBEX, and the obx_event field
+** contains the current OBEX event.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pbs_gasp_err_rsp(tBTA_PBS_CB *p_cb, tBTA_PBS_DATA *p_data)
+{
+ tBTA_PBS_OBX_EVENT *p_evt = &p_data->obx_evt;
+
+ switch (p_evt->obx_event)
+ {
+ case OBX_GET_REQ_EVT:
+ OBX_GetRsp(p_evt->handle, p_evt->rsp_code, (BT_HDR *)NULL);
+ break;
+ case OBX_SETPATH_REQ_EVT:
+ OBX_SetPathRsp(p_evt->handle, p_evt->rsp_code, (BT_HDR *)NULL);
+ break;
+ case OBX_ABORT_REQ_EVT:
+ OBX_AbortRsp(p_evt->handle, p_evt->rsp_code, (BT_HDR *)NULL);
+ break;
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_pbs_close_complete
+**
+** Description Finishes the memory cleanup after a channel is closed.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pbs_close_complete(tBTA_PBS_CB *p_cb, tBTA_PBS_DATA *p_data)
+{
+ p_cb->cout_active = FALSE;
+ bta_pbs_clean_getput(p_cb, TRUE);
+
+ /* inform role manager */
+ bta_sys_conn_close( BTA_ID_PBS ,p_cb->app_id, p_cb->bd_addr);
+
+ memset(p_cb->bd_addr, 0, BD_ADDR_LEN);
+
+ /* Notify the MMI that a connection has been closed */
+ p_cb->p_cback(BTA_PBS_CLOSE_EVT, 0);
+
+ if (p_data->obx_evt.p_pkt)
+ APPL_TRACE_WARNING0("PBS: OBX CLOSE CALLED WITH non-NULL Packet!!!");
+}
+
+/*****************************************************************************
+** Callback Functions
+*****************************************************************************/
+/*******************************************************************************
+**
+** Function bta_pbs_obx_cback
+**
+** Description OBX callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pbs_obx_cback (tOBX_HANDLE handle, tOBX_EVENT obx_event,
+ tOBX_EVT_PARAM param, BT_HDR *p_pkt)
+{
+ tBTA_PBS_OBX_EVENT *p_obx_msg;
+ UINT16 event = 0;
+
+#if BTA_PBS_DEBUG == TRUE
+ APPL_TRACE_DEBUG1("OBX Event Callback: obx_event [%s]", pbs_obx_evt_code(obx_event));
+#endif
+
+ switch(obx_event)
+ {
+ case OBX_CONNECT_REQ_EVT:
+ event = BTA_PBS_OBX_CONN_EVT;
+ break;
+ case OBX_DISCONNECT_REQ_EVT:
+ event = BTA_PBS_OBX_DISC_EVT;
+ break;
+ case OBX_GET_REQ_EVT:
+ event = BTA_PBS_OBX_GET_EVT;
+ break;
+ case OBX_SETPATH_REQ_EVT:
+ event = BTA_PBS_OBX_SETPATH_EVT;
+ break;
+ case OBX_ABORT_REQ_EVT:
+ event = BTA_PBS_OBX_ABORT_EVT;
+ break;
+ case OBX_CLOSE_IND_EVT:
+ event = BTA_PBS_OBX_CLOSE_EVT;
+ break;
+ case OBX_TIMEOUT_EVT:
+ break;
+ case OBX_PASSWORD_EVT:
+ event = BTA_PBS_OBX_PASSWORD_EVT;
+ break;
+ /* send Bad Request for Obex put request */
+ case OBX_PUT_REQ_EVT:
+ OBX_PutRsp(handle, OBX_RSP_BAD_REQUEST, (BT_HDR *)NULL);
+ if (p_pkt)
+ utl_freebuf((void**)&p_pkt);
+ return;
+ break;
+ default:
+ /* Unrecognized packet; disconnect the session */
+ if (p_pkt)
+ {
+ event = BTA_PBS_OBX_DISC_EVT;
+ utl_freebuf((void**)&p_pkt);
+ }
+ break;
+ }
+
+ /* send event to BTA, if any */
+ if (event && (p_obx_msg =
+ (tBTA_PBS_OBX_EVENT *) GKI_getbuf(sizeof(tBTA_PBS_OBX_EVENT))) != NULL)
+ {
+ p_obx_msg->hdr.event = event;
+ p_obx_msg->obx_event = obx_event;
+ p_obx_msg->handle = handle;
+ p_obx_msg->param = param;
+ p_obx_msg->p_pkt = p_pkt;
+
+ bta_sys_sendmsg(p_obx_msg);
+ }
+}
+
+/*****************************************************************************
+** Local PBS Event Processing Functions
+*****************************************************************************/
+/*******************************************************************************
+**
+** Function bta_pbs_req_app_access
+**
+** Description Sends an access request event to the application.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pbs_req_app_access (tBTA_PBS_OPER oper, tBTA_PBS_CB *p_cb)
+{
+ tBTA_PBS_ACCESS *p_acc_evt;
+ char *p_devname;
+
+ /* Notify the application that a get file has been requested */
+ if ((p_acc_evt = (tBTA_PBS_ACCESS *)GKI_getbuf(sizeof(tBTA_PBS_ACCESS))) != NULL)
+ {
+ memset(p_acc_evt, 0, sizeof(tBTA_PBS_ACCESS));
+
+ APPL_TRACE_API1("ACCESS REQ: [%s]", p_cb->p_path);
+ p_acc_evt->p_name = p_cb->p_path;
+ p_acc_evt->oper = p_cb->acc_active = oper;
+ bdcpy(p_acc_evt->bd_addr, p_cb->bd_addr);
+ if ((p_devname = BTM_SecReadDevName(p_cb->bd_addr)) != NULL)
+ BCM_STRNCPY_S((char *)p_acc_evt->dev_name, sizeof(tBTM_BD_NAME), p_devname, BTM_MAX_REM_BD_NAME_LEN);
+
+ p_cb->p_cback(BTA_PBS_ACCESS_EVT, (tBTA_PBS *)p_acc_evt);
+ GKI_freebuf(p_acc_evt);
+ }
+}
+
+/*****************************************************************************
+** Debug Functions
+*****************************************************************************/
+#if BTA_PBS_DEBUG == TRUE
+
+/*******************************************************************************
+**
+** Function pbs_obx_evt_code
+**
+** Description
+**
+** Returns void
+**
+*******************************************************************************/
+static char *pbs_obx_evt_code(tOBX_EVENT evt_code)
+{
+ switch(evt_code)
+ {
+ case OBX_CONNECT_REQ_EVT:
+ return "OBX_CONNECT_REQ_EVT";
+ case OBX_DISCONNECT_REQ_EVT:
+ return "OBX_DISCONNECT_REQ_EVT";
+ case OBX_GET_REQ_EVT:
+ return "OBX_GET_REQ_EVT";
+ case OBX_SETPATH_REQ_EVT:
+ return "OBX_SETPATH_REQ_EVT";
+ case OBX_ABORT_REQ_EVT:
+ return "OBX_ABORT_REQ_EVT";
+ case OBX_CLOSE_IND_EVT:
+ return "OBX_CLOSE_IND_EVT";
+ case OBX_TIMEOUT_EVT:
+ return "OBX_TIMEOUT_EVT";
+ case OBX_PASSWORD_EVT:
+ return "OBX_PASSWORD_EVT";
+ default:
+ return "unknown OBX event code";
+ }
+}
+#endif /* Debug Functions */
+#endif /* BTA_PBS_INCLUDED */
diff --git a/bta/pb/bta_pbs_api.c b/bta/pb/bta_pbs_api.c
new file mode 100644
index 0000000..c8466f6
--- /dev/null
+++ b/bta/pb/bta_pbs_api.c
@@ -0,0 +1,222 @@
+/*****************************************************************************
+**
+** Name: bta_pbs_api.c
+**
+** Description: This is the implementation of the API for the phone book
+** access server subsystem of BTA, Widcomm's Bluetooth
+** application layer for mobile phones.
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+
+#if defined(BTA_PBS_INCLUDED) && (BTA_PBS_INCLUDED == TRUE)
+
+#include <string.h>
+#include "gki.h"
+#include "bta_fs_api.h"
+#include "bta_pbs_api.h"
+#include "bta_pbs_int.h"
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+static const tBTA_SYS_REG bta_pbs_reg =
+{
+ bta_pbs_hdl_event,
+ BTA_PbsDisable
+};
+
+/*******************************************************************************
+**
+** Function BTA_PbsEnable
+**
+** Description Enable the phone book access server. This function must be
+** called before any other functions in the PB Server API are called.
+** When the enable operation is complete the callback function
+** will be called with an BTA_PBS_ENABLE_EVT event.
+** Note: Pbs always enable (BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT)
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_PbsEnable(tBTA_SEC sec_mask, const char *p_service_name,
+ const char *p_root_path, BOOLEAN enable_authen,
+ UINT8 realm_len, UINT8 *p_realm,
+ tBTA_PBS_CBACK *p_cback, UINT8 app_id)
+{
+ tBTA_PBS_API_ENABLE *p_buf;
+
+ /* register with BTA system manager */
+ GKI_sched_lock();
+ bta_sys_register(BTA_ID_PBS, &bta_pbs_reg);
+ GKI_sched_unlock();
+
+ if ((p_buf = (tBTA_PBS_API_ENABLE *)GKI_getbuf((UINT16)(sizeof(tBTA_PBS_API_ENABLE) +
+ p_bta_fs_cfg->max_path_len + 1))) != NULL)
+ {
+ memset(p_buf, 0, sizeof(tBTA_PBS_API_ENABLE));
+
+ p_buf->p_root_path = (char *)(p_buf + 1);
+ p_buf->p_root_path[0] = '\0';
+
+ p_buf->hdr.event = BTA_PBS_API_ENABLE_EVT;
+ p_buf->p_cback = p_cback;
+ p_buf->sec_mask = (sec_mask | BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
+ p_buf->app_id = app_id;
+ p_buf->auth_enabled = enable_authen;
+
+ p_buf->realm_len = (realm_len < OBX_MAX_REALM_LEN) ? realm_len :
+ OBX_MAX_REALM_LEN;
+ if (p_realm)
+ memcpy(p_buf->realm, p_realm, p_buf->realm_len);
+
+ if (p_service_name)
+ {
+ BCM_STRNCPY_S(p_buf->servicename, sizeof(p_buf->servicename), p_service_name, BTA_SERVICE_NAME_LEN);
+ p_buf->servicename[BTA_SERVICE_NAME_LEN] = '\0';
+ }
+
+ if (p_root_path)
+ {
+ BCM_STRNCPY_S(p_buf->p_root_path, p_bta_fs_cfg->max_path_len+1, p_root_path, p_bta_fs_cfg->max_path_len);
+ p_buf->p_root_path[p_bta_fs_cfg->max_path_len] = '\0';
+ }
+
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_PbsDisable
+**
+** Description Disable the Phone book access server. If the server is currently
+** connected to a peer device the connection will be closed.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_PbsDisable(void)
+{
+ BT_HDR *p_buf;
+
+ bta_sys_deregister(BTA_ID_PBS);
+ if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->event = BTA_PBS_API_DISABLE_EVT;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+/*******************************************************************************
+**
+** Function BTA_PbsAuthRsp
+**
+** Description Respond to obex client authenticate repond by sending back password to
+** BTA. Called in response to an BTA_PBS_AUTH_EVT event.
+** Used when "enable_authen" is set to TRUE in BTA_PbapsEnable().
+**
+** Note: If the "userid_required" is TRUE in the BTA_PBS_AUTH_EVT
+** event, then p_userid is required, otherwise it is optional.
+**
+** p_password must be less than BTA_PBS_MAX_AUTH_KEY_SIZE (16 bytes)
+** p_userid must be less than OBX_MAX_REALM_LEN (defined in target.h)
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_PbsAuthRsp (char *p_password, char *p_userid)
+{
+ tBTA_PBS_API_AUTHRSP *p_auth_rsp;
+
+ if ((p_auth_rsp = (tBTA_PBS_API_AUTHRSP *)GKI_getbuf(sizeof(tBTA_PBS_API_AUTHRSP))) != NULL)
+ {
+ memset(p_auth_rsp, 0, sizeof(tBTA_PBS_API_AUTHRSP));
+
+ p_auth_rsp->hdr.event = BTA_PBS_API_AUTHRSP_EVT;
+
+ if (p_password)
+ {
+ p_auth_rsp->key_len = strlen(p_password);
+ if (p_auth_rsp->key_len > BTA_PBS_MAX_AUTH_KEY_SIZE)
+ p_auth_rsp->key_len = BTA_PBS_MAX_AUTH_KEY_SIZE;
+ memcpy(p_auth_rsp->key, p_password, p_auth_rsp->key_len);
+ }
+
+ if (p_userid)
+ {
+ p_auth_rsp->userid_len = strlen(p_userid);
+ if (p_auth_rsp->userid_len > OBX_MAX_REALM_LEN)
+ p_auth_rsp->userid_len = OBX_MAX_REALM_LEN;
+ memcpy(p_auth_rsp->userid, p_userid, p_auth_rsp->userid_len);
+ }
+
+ bta_sys_sendmsg(p_auth_rsp);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_PbsAccessRsp
+**
+** Description Sends a reply to an access request event (BTA_PBS_ACCESS_EVT).
+** This call MUST be made whenever the event occurs.
+**
+** Parameters oper - operation being accessed.
+** access - BTA_PBS_ACCESS_ALLOW or BTA_PBS_ACCESS_FORBID
+** p_name - path of file or directory to be accessed.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_PbsAccessRsp(tBTA_PBS_OPER oper, tBTA_PBS_ACCESS_TYPE access, char *p_name)
+{
+ tBTA_PBS_API_ACCESSRSP *p_acc_rsp;
+ UINT16 max_full_name = p_bta_fs_cfg->max_path_len + p_bta_fs_cfg->max_file_len + 1;
+
+ if ((p_acc_rsp = (tBTA_PBS_API_ACCESSRSP *)GKI_getbuf((UINT16)(sizeof(tBTA_PBS_API_ACCESSRSP)
+ + max_full_name + 1))) != NULL)
+ {
+ p_acc_rsp->flag = access;
+ p_acc_rsp->oper = oper;
+ p_acc_rsp->p_name = (char *)(p_acc_rsp + 1);
+ if (p_name)
+ {
+ BCM_STRNCPY_S(p_acc_rsp->p_name, max_full_name+1, p_name, max_full_name);
+ p_acc_rsp->p_name[max_full_name] = '\0';
+ }
+ else
+ p_acc_rsp->p_name[0] = '\0';
+
+ p_acc_rsp->hdr.event = BTA_PBS_API_ACCESSRSP_EVT;
+ bta_sys_sendmsg(p_acc_rsp);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_PbsClose
+**
+** Description Close the current connection.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_PbsClose(void)
+{
+ BT_HDR *p_buf;
+
+ if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->event = BTA_PBS_API_CLOSE_EVT;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+#endif /* BTA_PBS_INCLUDED */
diff --git a/bta/pb/bta_pbs_cfg.c b/bta/pb/bta_pbs_cfg.c
new file mode 100644
index 0000000..0dc303c
--- /dev/null
+++ b/bta/pb/bta_pbs_cfg.c
@@ -0,0 +1,38 @@
+/*****************************************************************************
+**
+** Name: bta_pbs_cfg.c
+**
+** Description: This file contains compile-time configurable constants
+** for the BTA Phone Book Access Server.
+**
+** Copyright (c) 2003-2005, Widcomm Inc., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+
+#if defined(BTA_PBS_INCLUDED) && (BTA_PBS_INCLUDED == TRUE)
+
+#include "bta_pbs_int.h"
+
+/* Realm Character Set */
+#ifndef BTA_PBS_REALM_CHARSET
+#define BTA_PBS_REALM_CHARSET 0 /* ASCII */
+#endif
+
+/* Specifies whether or not client's user id is required during obex authentication */
+#ifndef BTA_PBS_USERID_REQ
+#define BTA_PBS_USERID_REQ FALSE
+#endif
+
+const tBTA_PBS_CFG bta_pbs_cfg =
+{
+ BTA_PBS_REALM_CHARSET, /* Server only */
+ BTA_PBS_USERID_REQ, /* Server only */
+ (BTA_PBS_SUPF_DOWNLOAD | BTA_PBS_SURF_BROWSE),
+ BTA_PBS_REPOSIT_LOCAL,
+};
+
+tBTA_PBS_CFG *p_bta_pbs_cfg = (tBTA_PBS_CFG *)&bta_pbs_cfg;
+#endif /* BTA_PBS_INCLUDED */
diff --git a/bta/pb/bta_pbs_ci.c b/bta/pb/bta_pbs_ci.c
new file mode 100644
index 0000000..fa2644b
--- /dev/null
+++ b/bta/pb/bta_pbs_ci.c
@@ -0,0 +1,119 @@
+/*****************************************************************************
+**
+** Name: bta_pbs_ci.c
+**
+** Description: This is the implementation file for the phone book access server
+** call-in functions.
+**
+** Copyright (c) 2003, Widcomm Inc., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bta_api.h"
+#include "bta_sys.h"
+#include "bta_pbs_ci.h"
+#include "bta_pbs_int.h"
+#include "gki.h"
+
+/*******************************************************************************
+**
+** Function bta_pbs_ci_read
+**
+** Description This function sends an event to BTA indicating the phone has
+** read in the requested amount of data specified in the
+** bta_pbs_co_read() call-out function.
+**
+** Parameters fd - file descriptor passed to the stack in the
+** bta_pbs_ci_open call-in function.
+** num_bytes_read - number of bytes read into the buffer
+** specified in the read callout-function.
+** status - BTA_PBS_CO_OK if get buffer of data,
+** BTA_PBS_CO_FAIL if an error has occurred.
+** final - indicate whether it is the final data
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pbs_ci_read(int fd, UINT16 num_bytes_read,
+ tBTA_PBS_CO_STATUS status, BOOLEAN final)
+{
+ tBTA_PBS_CI_READ_EVT *p_evt;
+
+ if ((p_evt = (tBTA_PBS_CI_READ_EVT *) GKI_getbuf(sizeof(tBTA_PBS_CI_READ_EVT))) != NULL)
+ {
+ p_evt->hdr.event = BTA_PBS_CI_READ_EVT;
+ p_evt->fd = fd;
+ p_evt->status = status;
+ p_evt->num_read = num_bytes_read;
+ p_evt->final = final;
+
+ bta_sys_sendmsg(p_evt);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_pbs_ci_open
+**
+** Description This function sends an event to BTA indicating the phone has
+** finished opening a pb for reading.
+**
+** Parameters fd - file descriptor passed to the stack in the
+** bta_pbs_ci_open call-in function.
+** status - BTA_PBS_CO_OK if file was opened in mode specified
+** in the call-out function.
+** BTA_PBS_CO_EACCES if the file exists, but contains
+** the wrong access permissions.
+** BTA_PBS_CO_FAIL if any other error has occurred.
+** file_size - The total size of the file
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pbs_ci_open(int fd, tBTA_PBS_CO_STATUS status, UINT32 file_size)
+{
+ tBTA_PBS_CI_OPEN_EVT *p_evt;
+
+ if ((p_evt = (tBTA_PBS_CI_OPEN_EVT *) GKI_getbuf(sizeof(tBTA_PBS_CI_OPEN_EVT))) != NULL)
+ {
+ p_evt->hdr.event = BTA_PBS_CI_OPEN_EVT;
+ p_evt->fd = fd;
+ p_evt->status = status;
+ p_evt->file_size = file_size;
+
+ bta_sys_sendmsg(p_evt);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_pbs_ci_getvlist
+**
+** Description This function sends an event to BTA indicating the phone has
+** finished reading a VCard list entry.
+**
+** Parameters
+** status - BTA_PBS_CO_OK if reading Vcard list entry
+** BTA_PBS_CO_FAIL if any other error has occurred.
+** final - whether it is the last entry
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void bta_pbs_ci_getvlist(tBTA_PBS_CO_STATUS status, BOOLEAN final)
+{
+ tBTA_PBS_CI_VLIST_EVT *p_evt;
+
+ if ((p_evt = (tBTA_PBS_CI_VLIST_EVT *) GKI_getbuf(sizeof(tBTA_PBS_CI_VLIST_EVT))) != NULL)
+ {
+ p_evt->hdr.event = BTA_PBS_CI_VLIST_EVT;
+ p_evt->status = status;
+ p_evt->final = final;
+
+ bta_sys_sendmsg(p_evt);
+ }
+}
diff --git a/bta/pb/bta_pbs_int.h b/bta/pb/bta_pbs_int.h
new file mode 100644
index 0000000..19045fd
--- /dev/null
+++ b/bta/pb/bta_pbs_int.h
@@ -0,0 +1,305 @@
+/*****************************************************************************
+**
+** Name: bta_pbs_int.h
+**
+** Description: This is the private file for the phone book access
+** server (PBS).
+**
+** Copyright (c) 2003-2010, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_PBS_INT_H
+#define BTA_PBS_INT_H
+
+#include "bt_target.h"
+#include "bta_sys.h"
+#include "obx_api.h"
+#include "bta_pbs_api.h"
+#include "bta_pbs_co.h"
+#include "bta_pbs_ci.h"
+
+/*****************************************************************************
+** Constants and data types
+*****************************************************************************/
+
+#define BTA_PBS_TARGET_UUID "\x79\x61\x35\xf0\xf0\xc5\x11\xd8\x09\x66\x08\x00\x20\x0c\x9a\x66"
+#define BTA_PBS_UUID_LENGTH 16
+#define BTA_PBS_MAX_AUTH_KEY_SIZE 16 /* Must not be greater than OBX_MAX_AUTH_KEY_SIZE */
+
+#define BTA_PBS_DEFAULT_VERSION 0x0101 /* for PBAP PSE version 1.1 */
+
+#define BTA_PBS_GETVCARD_LISTING_TYPE "x-bt/vcard-listing"
+#define BTA_PBS_GETFILE_TYPE "x-bt/phonebook"
+#define BTA_PBS_GETVARD_ENTRY_TYPE "x-bt/vcard"
+#define BTA_PBS_PULLPB_NAME "telecom/pb.vcf"
+#define BTA_PBS_PULLICH_NAME "telecom/ich.vcf"
+#define BTA_PBS_PULLOCH_NAME "telecom/och.vcf"
+#define BTA_PBS_PULLMCH_NAME "telecom/mch.vcf"
+#define BTA_PBS_PULLCCH_NAME "telecom/cch.vcf"
+#define BTA_PBS_PBFOLDER_NAME "pb"
+#define BTA_PBS_ICHFOLDER_NAME "ich"
+#define BTA_PBS_OCHFOLDER_NAME "och"
+#define BTA_PBS_MCHFOLDER_NAME "mch"
+#define BTA_PBS_CCHFOLDER_NAME "cch"
+
+/* Tags for application parameter obex headers */
+/* application parameter len: number of bytes + 2 (tag&len) */
+#define BTA_PBS_TAG_ORDER 1 /* UINT8 */
+#define BTA_PBS_TAG_SEARCH_VALUE 2 /* string */
+#define BTA_PBS_TAG_SEARCH_ATTRIBUTE 3 /* UINT8 */
+#define BTA_PBS_TAG_MAX_LIST_COUNT 4 /* UINT16 */
+#define BTA_PBS_TAG_LIST_START_OFFSET 5 /* UINT16 */
+#define BTA_PBS_TAG_FILTER 6 /* UINT32 */
+#define BTA_PBS_TAG_FORMAT 7 /* UINT8 */
+#define BTA_PBS_TAG_PB_SIZE 8 /* UINT16 */
+#define BTA_PBS_TAG_NEW_MISSED_CALLS 9 /* UINT8 */
+
+#define BTA_PBS_MAX_LIST_COUNT 65535
+
+typedef tOBX_STATUS (tBTA_PBS_OBX_RSP) (tOBX_HANDLE handle, UINT8 rsp_code, BT_HDR *p_pkt);
+
+/* state machine events */
+enum
+{
+ /* these events are handled by the state machine */
+ BTA_PBS_API_DISABLE_EVT = BTA_SYS_EVT_START(BTA_ID_PBS),
+
+ BTA_PBS_API_AUTHRSP_EVT, /* Response to password request */
+ BTA_PBS_API_ACCESSRSP_EVT, /* Response to an access request */
+ BTA_PBS_API_CLOSE_EVT, /* Response to a close request */
+ BTA_PBS_CI_READ_EVT, /* Response to Read request */
+ BTA_PBS_CI_OPEN_EVT, /* Response to File Open request */
+ BTA_PBS_CI_VLIST_EVT, /* Response to Get Vcard Entry request */
+ BTA_PBS_OBX_CONN_EVT, /* OBX Channel Connect Request */
+ BTA_PBS_OBX_DISC_EVT, /* OBX Channel Disconnect */
+ BTA_PBS_OBX_ABORT_EVT, /* OBX_operation aborted */
+ BTA_PBS_OBX_PASSWORD_EVT, /* OBX password requested */
+ BTA_PBS_OBX_CLOSE_EVT, /* OBX Channel Disconnected (Link Lost) */
+ BTA_PBS_OBX_GET_EVT, /* Read file data or folder listing */
+ BTA_PBS_OBX_SETPATH_EVT, /* Make or Change Directory */
+ BTA_PBS_APPL_TOUT_EVT, /* Timeout waiting for application */
+ BTA_PBS_DISC_ERR_EVT, /* Sends OBX_DisconnectRsp with error code */
+ BTA_PBS_GASP_ERR_EVT, /* Sends Err Resp to Get, Abort, Setpath */
+ BTA_PBS_CLOSE_CMPL_EVT, /* Finished closing channel */
+
+ /* these events are handled outside the state machine */
+ BTA_PBS_API_ENABLE_EVT
+};
+
+typedef UINT16 tBTA_PBS_INT_EVT;
+
+typedef UINT8 tBTA_PBS_STATE;
+
+/* data type for BTA_PBS_API_ENABLE_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_PBS_CBACK *p_cback;
+ char servicename[BTA_SERVICE_NAME_LEN + 1];
+ char *p_root_path;
+ UINT8 realm [OBX_MAX_REALM_LEN]; /* The realm is intended to be
+ displayed to users so they know
+ which userid and password to use.
+ The first byte of the string is
+ the character set of the string.
+ */
+ UINT8 realm_len;
+ UINT8 sec_mask;
+ UINT8 app_id;
+ BOOLEAN auth_enabled;
+} tBTA_PBS_API_ENABLE;
+
+/* data type for BTA_PBS_API_AUTHRSP_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ UINT8 key [BTA_PBS_MAX_AUTH_KEY_SIZE]; /* The authentication key.*/
+ UINT8 key_len;
+ UINT8 userid [OBX_MAX_REALM_LEN]; /* The authentication user id.*/
+ UINT8 userid_len;
+} tBTA_PBS_API_AUTHRSP;
+
+/* data type for BTA_PBS_API_ACCESSRSP_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ char *p_name;
+ tBTA_PBS_OPER oper;
+ tBTA_PBS_ACCESS_TYPE flag;
+} tBTA_PBS_API_ACCESSRSP;
+
+typedef struct
+{
+ BT_HDR hdr;
+ UINT32 file_size;
+ int fd;
+ tBTA_PBS_CO_STATUS status;
+} tBTA_PBS_CI_OPEN_EVT;
+
+/* Read Ready Event */
+typedef struct
+{
+ BT_HDR hdr;
+ int fd;
+ UINT16 num_read;
+ tBTA_PBS_CO_STATUS status;
+ BOOLEAN final;
+} tBTA_PBS_CI_READ_EVT;
+
+/* Get Vlist Entry Ready Event */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_PBS_CO_STATUS status;
+ BOOLEAN final;
+} tBTA_PBS_CI_VLIST_EVT;
+
+
+/* data type for all obex events
+ hdr.event contains the PBS event
+*/
+typedef struct
+{
+ BT_HDR hdr;
+ tOBX_HANDLE handle;
+ tOBX_EVT_PARAM param;
+ BT_HDR *p_pkt;
+ tOBX_EVENT obx_event;
+ UINT8 rsp_code;
+} tBTA_PBS_OBX_EVENT;
+
+/* union of all event data types */
+typedef union
+{
+ BT_HDR hdr;
+ tBTA_PBS_API_ENABLE api_enable;
+ tBTA_PBS_API_AUTHRSP auth_rsp;
+ tBTA_PBS_API_ACCESSRSP access_rsp;
+ tBTA_PBS_OBX_EVENT obx_evt;
+ tBTA_PBS_CI_OPEN_EVT open_evt;
+ tBTA_PBS_CI_READ_EVT read_evt;
+ tBTA_PBS_CI_VLIST_EVT vlist_evt;
+} tBTA_PBS_DATA;
+
+
+/* OBX Response Packet Structure - Holds current response packet info */
+typedef struct
+{
+ BT_HDR *p_pkt; /* (Get/Put) Holds the current OBX header for Put or Get */
+ UINT8 *p_start; /* (Get/Put) Start of the Body of the packet */
+ UINT16 offset; /* (Get/Put) Contains the current offset into the Body (p_start) */
+ UINT16 bytes_left; /* (Get/Put) Holds bytes available left in Obx packet */
+ BOOLEAN final_pkt; /* (Put) Holds the final bit of the Put packet */
+} tBTA_PBS_OBX_PKT;
+
+
+/* PBS control block */
+typedef struct
+{
+ tBTA_PBS_CBACK *p_cback; /* pointer to application callback function */
+ char *p_name; /* Holds name of current operation */
+ char *p_path; /* Holds path of current operation */
+ char *p_rootpath;
+ char *p_workdir; /* Current working directory */
+ UINT8 *p_stream_indexes; /* Contains pointer to beginning of phonebook size area in ob hdr */
+ tBTA_PBS_OBX_PKT obx; /* Holds the current OBX packet information */
+ tBTA_PBS_PULLPB_APP_PARAMS pullpb_app_params; /* PULLPB Application params */
+ tBTA_PBS_VCARDLIST_APP_PARAMS getvlist_app_params; /* Get VLIST Application params */
+ tBTA_PBS_VCARDLIST vlist; /* Holds current directory list information */
+ UINT32 sdp_handle; /* SDP record handle */
+ UINT32 file_length; /* length of file being PUT/GET */
+ int fd; /* File Descriptor of opened file */
+ BD_ADDR bd_addr; /* Device currently connected to */
+ tOBX_HANDLE obx_handle;
+ UINT16 peer_mtu;
+ UINT16 num_vlist_idxs; /* keeps track of number of indexes in vCard listing */
+ UINT8 scn; /* SCN of the FTP server */
+ tBTA_PBS_STATE state; /* state machine state */
+ UINT8 obx_oper; /* current active OBX operation GET FILE, LISTING, etc */
+ UINT8 app_id;
+ BOOLEAN auth_enabled; /* Is OBEX authentication enabled */
+ BOOLEAN cout_active; /* TRUE when waiting for a call-in function */
+ BOOLEAN aborting;
+ BOOLEAN get_only_indexes; /* True if PCE only wants num indexes for vListing response */
+ tBTA_PBS_OPER acc_active; /* op code when waiting for an access rsp (API) (0 not active) */
+ tBTA_PBS_OBJ_TYPE obj_type;
+ UINT8 realm [OBX_MAX_REALM_LEN]; /* The realm is intended to be
+ displayed to users so they know
+ which userid and password to use.
+ The first byte of the string is
+ the character set of the string.
+ */
+ UINT8 realm_len;
+} tBTA_PBS_CB;
+
+
+
+/* Configuration structure */
+typedef struct
+{
+ UINT8 realm_charset; /* Server only */
+ BOOLEAN userid_req; /* TRUE if user id is required during obex authentication (Server only) */
+ UINT8 supported_features; /* Server supported features */
+ UINT8 supported_repositories; /* Server supported repositories */
+
+} tBTA_PBS_CFG;
+
+/*****************************************************************************
+** Global data
+*****************************************************************************/
+
+/* PBS control block */
+#if BTA_DYNAMIC_MEMORY == FALSE
+extern tBTA_PBS_CB bta_pbs_cb;
+#else
+extern tBTA_PBS_CB *bta_pbs_cb_ptr;
+#define bta_pbs_cb (*bta_pbs_cb_ptr)
+#endif
+
+/* PBS configuration constants */
+extern tBTA_PBS_CFG * p_bta_pbs_cfg;
+
+/*****************************************************************************
+** Function prototypes
+*****************************************************************************/
+
+extern BOOLEAN bta_pbs_hdl_event(BT_HDR *p_msg);
+extern void bta_pbs_sm_execute(tBTA_PBS_CB *p_cb, UINT16 event, tBTA_PBS_DATA *p_data);
+extern void bta_pbs_sdp_register (tBTA_PBS_CB *p_cb, char *p_service_name);
+extern void bta_pbs_obx_cback (tOBX_HANDLE handle, tOBX_EVENT event,
+ tOBX_EVT_PARAM param, BT_HDR *p_pkt);
+
+/* action functions */
+extern void bta_pbs_api_disable(tBTA_PBS_CB *p_cb, tBTA_PBS_DATA *p_data);
+extern void bta_pbs_api_authrsp(tBTA_PBS_CB *p_cb, tBTA_PBS_DATA *p_data);
+extern void bta_pbs_api_accessrsp(tBTA_PBS_CB *p_cb, tBTA_PBS_DATA *p_data);
+extern void bta_pbs_api_close(tBTA_PBS_CB *p_cb, tBTA_PBS_DATA *p_data);
+extern void bta_pbs_obx_connect(tBTA_PBS_CB *p_cb, tBTA_PBS_DATA *p_data);
+extern void bta_pbs_obx_disc(tBTA_PBS_CB *p_cb, tBTA_PBS_DATA *p_data);
+extern void bta_pbs_obx_close(tBTA_PBS_CB *p_cb, tBTA_PBS_DATA *p_data);
+extern void bta_pbs_obx_abort(tBTA_PBS_CB *p_cb, tBTA_PBS_DATA *p_data);
+extern void bta_pbs_obx_password(tBTA_PBS_CB *p_cb, tBTA_PBS_DATA *p_data);
+extern void bta_pbs_obx_get(tBTA_PBS_CB *p_cb, tBTA_PBS_DATA *p_data);
+extern void bta_pbs_obx_setpath(tBTA_PBS_CB *p_cb, tBTA_PBS_DATA *p_data);
+extern void bta_pbs_appl_tout(tBTA_PBS_CB *p_cb, tBTA_PBS_DATA *p_data);
+extern void bta_pbs_conn_err_rsp(tBTA_PBS_CB *p_cb, tBTA_PBS_DATA *p_data);
+extern void bta_pbs_disc_err_rsp(tBTA_PBS_CB *p_cb, tBTA_PBS_DATA *p_data);
+extern void bta_pbs_gasp_err_rsp(tBTA_PBS_CB *p_cb, tBTA_PBS_DATA *p_data);
+extern void bta_pbs_close_complete(tBTA_PBS_CB *p_cb, tBTA_PBS_DATA *p_data);
+extern void bta_pbs_ci_open_act(tBTA_PBS_CB *p_cb, tBTA_PBS_DATA *p_data);
+extern void bta_pbs_ci_read_act(tBTA_PBS_CB *p_cb, tBTA_PBS_DATA *p_data);
+extern void bta_pbs_ci_vlist_act(tBTA_PBS_CB *p_cb, tBTA_PBS_DATA *p_data);
+/* object store */
+extern void bta_pbs_proc_get_file(char *p_name, tBTA_PBS_OPER operation);
+extern void bta_pbs_req_app_access (tBTA_PBS_OPER oper, tBTA_PBS_CB *p_cb);
+extern void bta_pbs_getvlist(char *p_name);
+/* miscellaneous functions */
+extern void bta_pbs_get_file_rsp(UINT8 rsp_code, UINT16 num_read);
+extern void bta_pbs_clean_getput(tBTA_PBS_CB *p_cb, BOOLEAN is_aborted);
+extern void bta_pbs_end_of_list(UINT8 rsp_code);
+extern UINT8 bta_pbs_add_list_entry(void);
+extern UINT8 bta_pbs_chdir(BT_HDR *p_pkt, BOOLEAN backup_flag, tBTA_PBS_OPER *p_op);
+extern UINT8 * bta_pbs_read_app_params(BT_HDR *p_pkt, UINT8 tag, UINT16 *param_len);
+
+#endif /* BTA_PBS_INT_H */
diff --git a/bta/pb/bta_pbs_main.c b/bta/pb/bta_pbs_main.c
new file mode 100644
index 0000000..1ed892d
--- /dev/null
+++ b/bta/pb/bta_pbs_main.c
@@ -0,0 +1,515 @@
+/*****************************************************************************
+**
+** Name: bta_pbs_main.c
+**
+** Description: This file contains the phone book access server main functions
+** and state machine.
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+
+#if defined(BTA_PBS_INCLUDED) && (BTA_PBS_INCLUDED == TRUE)
+
+#include <string.h>
+#include "bta_fs_api.h"
+#include "bta_pbs_api.h"
+#include "bta_pbs_int.h"
+#include "gki.h"
+#include "utl.h"
+#include "obx_api.h"
+#include "rfcdefs.h" /* BT_PSM_RFCOMM */
+#include "bta_fs_co.h"
+
+/*****************************************************************************
+** Constants and types
+*****************************************************************************/
+
+/* state machine states */
+enum
+{
+ BTA_PBS_IDLE_ST = 0, /* Idle */
+ BTA_PBS_LISTEN_ST, /* Listen - waiting for OBX/RFC connection */
+ BTA_PBS_W4_AUTH_ST, /* Wait for Authentication - (optional) */
+ BTA_PBS_CONN_ST, /* Connected - PBS Session is active */
+ BTA_PBS_CLOSING_ST /* Closing is in progress */
+};
+
+/* state machine action enumeration list */
+enum
+{
+ BTA_PBS_API_DISABLE,
+ BTA_PBS_API_AUTHRSP,
+ BTA_PBS_API_ACCESSRSP,
+ BTA_PBS_API_CLOSE,
+ BTA_PBS_CI_READ,
+ BTA_PBS_CI_OPEN,
+ BTA_PBS_CI_VLIST,
+ BTA_PBS_OBX_CONNECT,
+ BTA_PBS_OBX_DISC,
+ BTA_PBS_OBX_CLOSE,
+ BTA_PBS_OBX_ABORT,
+ BTA_PBS_OBX_PASSWORD,
+ BTA_PBS_OBX_GET,
+ BTA_PBS_OBX_SETPATH,
+ BTA_PBS_APPL_TOUT,
+ BTA_PBS_CONN_ERR_RSP,
+ BTA_PBS_DISC_ERR_RSP,
+ BTA_PBS_GASP_ERR_RSP,
+ BTA_PBS_CLOSE_COMPLETE,
+ BTA_PBS_IGNORE
+};
+
+/* type for action functions */
+typedef void (*tBTA_PBS_ACTION)(tBTA_PBS_CB *p_cb, tBTA_PBS_DATA *p_data);
+
+/* action function list */
+const tBTA_PBS_ACTION bta_pbs_action[] =
+{
+ bta_pbs_api_disable,
+ bta_pbs_api_authrsp,
+ bta_pbs_api_accessrsp,
+ bta_pbs_api_close,
+ bta_pbs_ci_read_act,
+ bta_pbs_ci_open_act,
+ bta_pbs_ci_vlist_act,
+ bta_pbs_obx_connect,
+ bta_pbs_obx_disc,
+ bta_pbs_obx_close,
+ bta_pbs_obx_abort,
+ bta_pbs_obx_password,
+ bta_pbs_obx_get,
+ bta_pbs_obx_setpath,
+ bta_pbs_appl_tout,
+ bta_pbs_conn_err_rsp,
+ bta_pbs_disc_err_rsp,
+ bta_pbs_gasp_err_rsp,
+ bta_pbs_close_complete
+};
+
+
+/* state table information */
+#define BTA_PBS_ACTIONS 1 /* number of actions */
+#define BTA_PBS_NEXT_STATE 1 /* position of next state */
+#define BTA_PBS_NUM_COLS 2 /* number of columns in state tables */
+
+/* state table for idle state */
+static const UINT8 bta_pbs_st_idle[][BTA_PBS_NUM_COLS] =
+{
+/* Event Action 1 Next state */
+/* BTA_PBS_API_ENABLE_EVT */ {BTA_PBS_IGNORE, BTA_PBS_LISTEN_ST}
+};
+
+/* state table for obex/rfcomm connection state */
+static const UINT8 bta_pbs_st_listen[][BTA_PBS_NUM_COLS] =
+{
+/* Event Action 1 Next state */
+/* BTA_PBS_API_DISABLE_EVT */ {BTA_PBS_API_DISABLE, BTA_PBS_IDLE_ST},
+/* BTA_PBS_API_AUTHRSP_EVT */ {BTA_PBS_IGNORE, BTA_PBS_LISTEN_ST},
+/* BTA_PBS_API_ACCESSRSP_EVT */ {BTA_PBS_IGNORE, BTA_PBS_LISTEN_ST},
+/* BTA_PBS_API_CLOSE_EVT */ {BTA_PBS_API_CLOSE, BTA_PBS_LISTEN_ST},
+/* BTA_PBS_CI_READ_EVT */ {BTA_PBS_IGNORE, BTA_PBS_LISTEN_ST},
+/* BTA_PBS_CI_OPEN_EVT */ {BTA_PBS_IGNORE, BTA_PBS_LISTEN_ST},
+/* BTA_PBS_CI_VLIST_EVT */ {BTA_PBS_IGNORE, BTA_PBS_LISTEN_ST},
+/* BTA_PBS_OBX_CONN_EVT */ {BTA_PBS_OBX_CONNECT, BTA_PBS_CONN_ST},
+/* BTA_PBS_OBX_DISC_EVT */ {BTA_PBS_IGNORE, BTA_PBS_LISTEN_ST},
+/* BTA_PBS_OBX_ABORT_EVT */ {BTA_PBS_IGNORE, BTA_PBS_LISTEN_ST},
+/* BTA_PBS_OBX_PASSWORD_EVT */ {BTA_PBS_OBX_PASSWORD, BTA_PBS_W4_AUTH_ST},
+/* BTA_PBS_OBX_CLOSE_EVT */ {BTA_PBS_IGNORE, BTA_PBS_LISTEN_ST},
+/* BTA_PBS_OBX_GET_EVT */ {BTA_PBS_IGNORE, BTA_PBS_LISTEN_ST},
+/* BTA_PBS_OBX_SETPATH_EVT */ {BTA_PBS_IGNORE, BTA_PBS_LISTEN_ST},
+/* BTA_PBS_APPL_TOUT_EVT */ {BTA_PBS_IGNORE, BTA_PBS_LISTEN_ST},
+/* BTA_PBS_DISC_ERR_EVT */ {BTA_PBS_IGNORE, BTA_PBS_LISTEN_ST},
+/* BTA_PBS_GASP_ERR_EVT */ {BTA_PBS_IGNORE, BTA_PBS_LISTEN_ST},
+/* BTA_PBS_CLOSE_CMPL_EVT */ {BTA_PBS_IGNORE, BTA_PBS_LISTEN_ST}
+};
+
+/* state table for wait for authentication response state */
+static const UINT8 bta_pbs_st_w4_auth[][BTA_PBS_NUM_COLS] =
+{
+/* Event Action 1 Next state */
+/* BTA_PBS_API_DISABLE_EVT */ {BTA_PBS_API_DISABLE, BTA_PBS_IDLE_ST},
+/* BTA_PBS_API_AUTHRSP_EVT */ {BTA_PBS_API_AUTHRSP, BTA_PBS_LISTEN_ST},
+/* BTA_PBS_API_ACCESSRSP_EVT */ {BTA_PBS_IGNORE, BTA_PBS_W4_AUTH_ST},
+/* BTA_PBS_API_CLOSE_EVT */ {BTA_PBS_API_CLOSE, BTA_PBS_CLOSING_ST},
+/* BTA_PBS_CI_READ_EVT */ {BTA_PBS_IGNORE, BTA_PBS_W4_AUTH_ST},
+/* BTA_PBS_CI_OPEN_EVT */ {BTA_PBS_IGNORE, BTA_PBS_W4_AUTH_ST},
+/* BTA_PBS_CI_VLIST_EVT */ {BTA_PBS_IGNORE, BTA_PBS_W4_AUTH_ST},
+/* BTA_PBS_OBX_CONN_EVT */ {BTA_PBS_CONN_ERR_RSP, BTA_PBS_W4_AUTH_ST},
+/* BTA_PBS_OBX_DISC_EVT */ {BTA_PBS_OBX_DISC, BTA_PBS_W4_AUTH_ST},
+/* BTA_PBS_OBX_ABORT_EVT */ {BTA_PBS_IGNORE, BTA_PBS_W4_AUTH_ST},
+/* BTA_PBS_OBX_PASSWORD_EVT */ {BTA_PBS_IGNORE, BTA_PBS_W4_AUTH_ST},
+/* BTA_PBS_OBX_CLOSE_EVT */ {BTA_PBS_OBX_CLOSE, BTA_PBS_CLOSING_ST},
+/* BTA_PBS_OBX_GET_EVT */ {BTA_PBS_IGNORE, BTA_PBS_W4_AUTH_ST},
+/* BTA_PBS_OBX_SETPATH_EVT */ {BTA_PBS_IGNORE, BTA_PBS_W4_AUTH_ST},
+/* BTA_PBS_APPL_TOUT_EVT */ {BTA_PBS_APPL_TOUT, BTA_PBS_W4_AUTH_ST},
+/* BTA_PBS_DISC_ERR_EVT */ {BTA_PBS_IGNORE, BTA_PBS_W4_AUTH_ST},
+/* BTA_PBS_GASP_ERR_EVT */ {BTA_PBS_IGNORE, BTA_PBS_W4_AUTH_ST},
+/* BTA_PBS_CLOSE_CMPL_EVT */ {BTA_PBS_IGNORE, BTA_PBS_W4_AUTH_ST}
+};
+
+/* state table for open state */
+static const UINT8 bta_pbs_st_connected[][BTA_PBS_NUM_COLS] =
+{
+/* Event Action 1 Next state */
+/* BTA_PBS_API_DISABLE_EVT */ {BTA_PBS_API_DISABLE, BTA_PBS_IDLE_ST},
+/* BTA_PBS_API_AUTHRSP_EVT */ {BTA_PBS_IGNORE, BTA_PBS_CONN_ST},
+/* BTA_PBS_API_ACCESSRSP_EVT */ {BTA_PBS_API_ACCESSRSP, BTA_PBS_CONN_ST},
+/* BTA_PBS_API_CLOSE_EVT */ {BTA_PBS_API_CLOSE, BTA_PBS_CLOSING_ST},
+/* BTA_PBS_CI_READ_EVT */ {BTA_PBS_CI_READ, BTA_PBS_CONN_ST},
+/* BTA_PBS_CI_OPEN_EVT */ {BTA_PBS_CI_OPEN, BTA_PBS_CONN_ST},
+/* BTA_PBS_CI_VLIST_EVT */ {BTA_PBS_CI_VLIST, BTA_PBS_CONN_ST},
+/* BTA_PBS_OBX_CONN_EVT */ {BTA_PBS_CONN_ERR_RSP, BTA_PBS_CONN_ST},
+/* BTA_PBS_OBX_DISC_EVT */ {BTA_PBS_OBX_DISC, BTA_PBS_CLOSING_ST},
+/* BTA_PBS_OBX_ABORT_EVT */ {BTA_PBS_OBX_ABORT, BTA_PBS_CONN_ST},
+/* BTA_PBS_OBX_PASSWORD_EVT */ {BTA_PBS_IGNORE, BTA_PBS_W4_AUTH_ST},
+/* BTA_PBS_OBX_CLOSE_EVT */ {BTA_PBS_OBX_CLOSE, BTA_PBS_CLOSING_ST},
+/* BTA_PBS_OBX_GET_EVT */ {BTA_PBS_OBX_GET, BTA_PBS_CONN_ST},
+/* BTA_PBS_OBX_SETPATH_EVT */ {BTA_PBS_OBX_SETPATH, BTA_PBS_CONN_ST},
+/* BTA_PBS_APPL_TOUT_EVT */ {BTA_PBS_APPL_TOUT, BTA_PBS_LISTEN_ST},
+/* BTA_PBS_DISC_ERR_EVT */ {BTA_PBS_IGNORE, BTA_PBS_CONN_ST},
+/* BTA_PBS_GASP_ERR_EVT */ {BTA_PBS_GASP_ERR_RSP, BTA_PBS_CONN_ST},
+/* BTA_PBS_CLOSE_CMPL_EVT */ {BTA_PBS_IGNORE, BTA_PBS_CONN_ST}
+};
+
+/* state table for closing state */
+static const UINT8 bta_pbs_st_closing[][BTA_PBS_NUM_COLS] =
+{
+/* Event Action 1 Next state */
+/* BTA_PBS_API_DISABLE_EVT */ {BTA_PBS_API_DISABLE, BTA_PBS_IDLE_ST},
+/* BTA_PBS_API_AUTHRSP_EVT */ {BTA_PBS_IGNORE, BTA_PBS_CLOSING_ST},
+/* BTA_PBS_API_ACCESSRSP_EVT */ {BTA_PBS_IGNORE, BTA_PBS_CLOSING_ST},
+/* BTA_PBS_API_CLOSE_EVT */ {BTA_PBS_IGNORE, BTA_PBS_CLOSING_ST},
+/* BTA_PBS_CI_READ_EVT */ {BTA_PBS_CLOSE_COMPLETE, BTA_PBS_LISTEN_ST},
+/* BTA_PBS_CI_OPEN_EVT */ {BTA_PBS_CLOSE_COMPLETE, BTA_PBS_LISTEN_ST},
+/* BTA_PBS_CI_VLIST_EVT */ {BTA_PBS_CLOSE_COMPLETE, BTA_PBS_LISTEN_ST},
+/* BTA_PBS_OBX_CONN_EVT */ {BTA_PBS_CONN_ERR_RSP, BTA_PBS_CLOSING_ST},
+/* BTA_PBS_OBX_DISC_EVT */ {BTA_PBS_IGNORE, BTA_PBS_CLOSING_ST},
+/* BTA_PBS_OBX_ABORT_EVT */ {BTA_PBS_OBX_ABORT, BTA_PBS_CLOSING_ST},
+/* BTA_PBS_OBX_PASSWORD_EVT */ {BTA_PBS_IGNORE, BTA_PBS_CLOSING_ST},
+/* BTA_PBS_OBX_CLOSE_EVT */ {BTA_PBS_OBX_CLOSE, BTA_PBS_CLOSING_ST},
+/* BTA_PBS_OBX_GET_EVT */ {BTA_PBS_IGNORE, BTA_PBS_CLOSING_ST},
+/* BTA_PBS_OBX_SETPATH_EVT */ {BTA_PBS_IGNORE, BTA_PBS_CLOSING_ST},
+/* BTA_PBS_APPL_TOUT_EVT */ {BTA_PBS_IGNORE, BTA_PBS_CLOSING_ST},
+/* BTA_PBS_DISC_ERR_EVT */ {BTA_PBS_DISC_ERR_RSP, BTA_PBS_CONN_ST},
+/* BTA_PBS_GASP_ERR_EVT */ {BTA_PBS_GASP_ERR_RSP, BTA_PBS_CLOSING_ST},
+/* BTA_PBS_CLOSE_CMPL_EVT */ {BTA_PBS_CLOSE_COMPLETE, BTA_PBS_LISTEN_ST}
+};
+
+/* type for state table */
+typedef const UINT8 (*tBTA_PBS_ST_TBL)[BTA_PBS_NUM_COLS];
+
+/* state table */
+const tBTA_PBS_ST_TBL bta_pbs_st_tbl[] =
+{
+ bta_pbs_st_idle,
+ bta_pbs_st_listen,
+ bta_pbs_st_w4_auth,
+ bta_pbs_st_connected,
+ bta_pbs_st_closing
+};
+
+/*****************************************************************************
+** Global data
+*****************************************************************************/
+
+/* PBS control block */
+#if BTA_DYNAMIC_MEMORY == FALSE
+tBTA_PBS_CB bta_pbs_cb;
+#endif
+
+#if BTA_PBS_DEBUG == TRUE
+static char *pbs_evt_code(tBTA_PBS_INT_EVT evt_code);
+static char *pbs_state_code(tBTA_PBS_STATE state_code);
+#endif
+
+/*******************************************************************************
+**
+** Function bta_pbs_sm_execute
+**
+** Description State machine event handling function for PBS
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pbs_sm_execute(tBTA_PBS_CB *p_cb, UINT16 event, tBTA_PBS_DATA *p_data)
+{
+ tBTA_PBS_ST_TBL state_table;
+ UINT8 action;
+ int i;
+ tBTA_PBS_OBX_EVENT *p_obex_event;
+#if BTA_PBS_DEBUG == TRUE
+ tBTA_PBS_STATE in_state = bta_pbs_cb.state;
+ UINT16 in_event = event;
+ APPL_TRACE_EVENT3("PBS Event : State 0x%02x [%s], Event [%s]", in_state,
+ pbs_state_code(in_state),
+ pbs_evt_code(event));
+#endif
+
+ /* look up the state table for the current state */
+ state_table = bta_pbs_st_tbl[p_cb->state];
+
+ event &= 0x00FF;
+
+ /* set next state */
+ p_cb->state = state_table[event][BTA_PBS_NEXT_STATE];
+
+ /* execute action functions */
+ for (i = 0; i < BTA_PBS_ACTIONS; i++)
+ {
+ if ((action = state_table[event][i]) != BTA_PBS_IGNORE)
+ {
+ (*bta_pbs_action[action])(p_cb, p_data);
+ }
+ else
+ {
+ if (event >= BTA_PBS_OBX_CONN_EVT && event <= BTA_PBS_OBX_SETPATH_EVT) {
+ p_obex_event = (tBTA_PBS_OBX_EVENT *) p_data;
+ utl_freebuf((void**)&(p_obex_event->p_pkt));
+ }
+ break;
+ }
+ }
+
+#if BTA_PBS_DEBUG == TRUE
+ if (in_state != bta_pbs_cb.state)
+ {
+ APPL_TRACE_DEBUG3("PBS State Change: [%s] -> [%s] after Event [%s]",
+ pbs_state_code(in_state),
+ pbs_state_code(bta_pbs_cb.state),
+ pbs_evt_code(in_event));
+ }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function bta_pbs_api_enable
+**
+** Description Handle an api enable event. This function enables the PBS
+** Server by opening an Obex/Rfcomm channel and placing it into
+** listen mode.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_pbs_api_enable(tBTA_PBS_CB *p_cb, tBTA_PBS_DATA *p_data)
+{
+ tOBX_StartParams start_msg;
+ tBTA_PBS_API_ENABLE *p_api = &p_data->api_enable;
+ tOBX_TARGET target;
+ UINT16 len;
+ tOBX_STATUS status;
+ tBTA_UTL_COD cod;
+
+ /* initialize control block */
+ memset(p_cb, 0, sizeof(tBTA_PBS_CB));
+
+ /* Allocate an aligned memory buffer to hold the root path and working directory */
+ /* Add 1 byte for '\0' */
+ len = p_bta_fs_cfg->max_path_len + 1;
+ if ((p_cb->p_rootpath = (char *)GKI_getbuf((UINT16)(len * 2))) != NULL)
+ {
+ p_cb->p_workdir = p_cb->p_rootpath + len;
+ memcpy(target.target, BTA_PBS_TARGET_UUID, BTA_PBS_UUID_LENGTH);
+ target.len = BTA_PBS_UUID_LENGTH;
+
+ /* store parameters */
+ p_cb->app_id = p_api->app_id;
+ p_cb->p_cback = p_api->p_cback;
+ p_cb->scn = BTM_AllocateSCN();
+ p_cb->auth_enabled = p_api->auth_enabled;
+ p_cb->fd = BTA_FS_INVALID_FD;
+ p_cb->realm_len = p_api->realm_len;
+ memcpy(p_cb->realm, p_api->realm, p_api->realm_len);
+
+ /* Initialize the current working directory to be the root directory */
+ BCM_STRNCPY_S(p_cb->p_rootpath, len, p_api->p_root_path, p_bta_fs_cfg->max_path_len);
+ p_cb->p_rootpath[len-1] = '\0';
+ BCM_STRNCPY_S(p_cb->p_workdir, len, p_api->p_root_path, p_bta_fs_cfg->max_path_len);
+ p_cb->p_workdir[len-1] = '\0';
+
+ /* Register PBS security requirements with BTM */
+ BTM_SetSecurityLevel(FALSE, p_api->servicename, BTM_SEC_SERVICE_PBAP,
+ p_api->sec_mask, BT_PSM_RFCOMM,
+ BTM_SEC_PROTO_RFCOMM, (UINT32)p_cb->scn);
+
+ /* Start up the PBS service */
+ memset (&start_msg, 0, sizeof(tOBX_StartParams));
+ start_msg.p_target = &target;
+
+ /* Make the MTU fit into one RFC frame */
+ start_msg.mtu = OBX_MAX_MTU;
+ start_msg.scn = p_cb->scn;
+ start_msg.authenticate = p_cb->auth_enabled;
+
+ start_msg.auth_option = (p_bta_pbs_cfg->userid_req) ? OBX_AO_USR_ID : OBX_AO_NONE;
+ start_msg.p_cback = bta_pbs_obx_cback;
+
+ start_msg.realm_len = p_api->realm_len;
+ start_msg.p_realm = p_api->realm;
+ start_msg.realm_charset = (tOBX_CHARSET) p_bta_pbs_cfg->realm_charset;
+
+ if ((status = OBX_StartServer (&start_msg, &p_cb->obx_handle)) == OBX_SUCCESS)
+ {
+ p_cb->state = BTA_PBS_LISTEN_ST;
+
+ /* Set the File Transfer service class bit */
+ cod.service = BTM_COD_SERVICE_OBJ_TRANSFER;
+ utl_set_device_class(&cod, BTA_UTL_SET_COD_SERVICE_CLASS);
+
+ /* Set up the SDP record for pbs service */
+ bta_pbs_sdp_register(p_cb, p_api->servicename);
+ }
+ else
+ APPL_TRACE_ERROR1("OBX_StartServer returns error (%d)", status);
+ }
+ else /* Cannot allocate resources to run Server */
+ APPL_TRACE_ERROR0("Not enough Resources to run PBS Server");
+
+ p_cb->p_cback(BTA_PBS_ENABLE_EVT, 0);
+}
+
+/*******************************************************************************
+**
+** Function bta_pbs_hdl_event
+**
+** Description File transfer server main event handling function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BOOLEAN bta_pbs_hdl_event(BT_HDR *p_msg)
+{
+#if BTA_PBS_DEBUG == TRUE
+ tBTA_PBS_STATE in_state = bta_pbs_cb.state;
+#endif
+
+ switch (p_msg->event)
+ {
+ case BTA_PBS_API_ENABLE_EVT:
+#if BTA_PBS_DEBUG == TRUE
+ APPL_TRACE_EVENT3("PBS Event Handler: State 0x%02x [%s], Event [%s]", in_state,
+ pbs_state_code(in_state),
+ pbs_evt_code(p_msg->event));
+#endif
+ bta_pbs_api_enable(&bta_pbs_cb, (tBTA_PBS_DATA *) p_msg);
+
+#if BTA_PBS_DEBUG == TRUE
+ if (in_state != bta_pbs_cb.state)
+ {
+ APPL_TRACE_DEBUG3("PBS State Change: [%s] -> [%s] after Event [%s]",
+ pbs_state_code(in_state),
+ pbs_state_code(bta_pbs_cb.state),
+ pbs_evt_code(p_msg->event));
+ }
+#endif
+ break;
+
+ default:
+ bta_pbs_sm_execute(&bta_pbs_cb, p_msg->event, (tBTA_PBS_DATA *) p_msg);
+ break;
+ }
+
+ return (TRUE);
+}
+
+
+/*****************************************************************************
+** Debug Functions
+*****************************************************************************/
+#if BTA_PBS_DEBUG == TRUE
+
+/*******************************************************************************
+**
+** Function pbs_evt_code
+**
+** Description
+**
+** Returns void
+**
+*******************************************************************************/
+static char *pbs_evt_code(tBTA_PBS_INT_EVT evt_code)
+{
+ switch(evt_code)
+ {
+ case BTA_PBS_API_DISABLE_EVT:
+ return "BTA_PBS_API_DISABLE_EVT";
+ case BTA_PBS_API_AUTHRSP_EVT:
+ return "BTA_PBS_API_AUTHRSP_EVT";
+ case BTA_PBS_API_ACCESSRSP_EVT:
+ return "BTA_PBS_API_ACCESSRSP_EVT";
+ case BTA_PBS_API_CLOSE_EVT:
+ return "BTA_PBS_API_CLOSE_EVT";
+ case BTA_PBS_CI_READ_EVT:
+ return "BTA_PBS_CI_READ_EVT";
+ case BTA_PBS_CI_OPEN_EVT:
+ return "BTA_PBS_CI_OPEN_EVT";
+ case BTA_PBS_CI_VLIST_EVT:
+ return "BTA_PBS_CI_VLIST_EVT";
+ case BTA_PBS_OBX_CONN_EVT:
+ return "BTA_PBS_OBX_CONN_EVT";
+ case BTA_PBS_OBX_DISC_EVT:
+ return "BTA_PBS_OBX_DISC_EVT";
+ case BTA_PBS_OBX_ABORT_EVT:
+ return "BTA_PBS_OBX_ABORT_EVT";
+ case BTA_PBS_OBX_PASSWORD_EVT:
+ return "BTA_PBS_OBX_PASSWORD_EVT";
+ case BTA_PBS_OBX_CLOSE_EVT:
+ return "BTA_PBS_OBX_CLOSE_EVT";
+ case BTA_PBS_OBX_GET_EVT:
+ return "BTA_PBS_OBX_GET_EVT";
+ case BTA_PBS_OBX_SETPATH_EVT:
+ return "BTA_PBS_OBX_SETPATH_EVT";
+ case BTA_PBS_APPL_TOUT_EVT:
+ return "BTA_PBS_APPL_TOUT_EVT";
+ case BTA_PBS_DISC_ERR_EVT:
+ return "BTA_PBS_DISC_ERR_EVT";
+ case BTA_PBS_GASP_ERR_EVT:
+ return "BTA_PBS_GASP_ERR_EVT";
+ case BTA_PBS_API_ENABLE_EVT:
+ return "BTA_PBS_API_ENABLE_EVT";
+ case BTA_PBS_CLOSE_CMPL_EVT:
+ return "BTA_PBS_CLOSE_CMPL_EVT";
+ default:
+ APPL_TRACE_EVENT1("unknown PBS Event: %d", evt_code)
+ return "unknown PBS event code";
+ }
+}
+
+/*******************************************************************************
+**
+** Function pbs_evt_code
+**
+** Description
+**
+** Returns void
+**
+*******************************************************************************/
+static char *pbs_state_code(tBTA_PBS_STATE state_code)
+{
+ switch(state_code)
+ {
+ case BTA_PBS_IDLE_ST:
+ return "BTA_PBS_IDLE_ST";
+ case BTA_PBS_LISTEN_ST:
+ return "BTA_PBS_LISTEN_ST";
+ case BTA_PBS_W4_AUTH_ST:
+ return "BTA_PBS_W4_AUTH_ST";
+ case BTA_PBS_CONN_ST:
+ return "BTA_PBS_CONN_ST";
+ case BTA_PBS_CLOSING_ST:
+ return "BTA_PBS_CLOSING_ST";
+ default:
+ return "unknown PBS state code";
+ }
+}
+
+#endif /* Debug Functions */
+#endif /* BTA_PBS_INCLUDED */
diff --git a/bta/pb/bta_pbs_sdp.c b/bta/pb/bta_pbs_sdp.c
new file mode 100644
index 0000000..eeec573
--- /dev/null
+++ b/bta/pb/bta_pbs_sdp.c
@@ -0,0 +1,113 @@
+/*****************************************************************************
+**
+** Name: bta_pbs_sdp.c
+**
+** File: Implements the SDP functions used by Phone Book Access Server
+**
+** Copyright (c) 2003, Widcomm Inc., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+
+#if defined(BTA_PBS_INCLUDED) && (BTA_PBS_INCLUDED == TRUE)
+
+#include <string.h>
+
+#include "sdp_api.h"
+#include "bta_pbs_int.h"
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+
+/*****************************************************************************
+**
+** Function: bta_pbs_sdp_register()
+**
+** Purpose: Registers the PBS service with SDP
+**
+** Parameters:
+**
+**
+** Returns: void
+**
+*****************************************************************************/
+void bta_pbs_sdp_register (tBTA_PBS_CB *p_cb, char *p_service_name)
+{
+ tSDP_PROTOCOL_ELEM protoList [3];
+ UINT16 pbs_service = UUID_SERVCLASS_PBAP_PSE;
+// btla-specific ++
+ UINT16 browse = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
+// btla-specific --
+ BOOLEAN status = FALSE;
+
+ if ((p_cb->sdp_handle = SDP_CreateRecord()) == 0)
+ {
+ APPL_TRACE_WARNING0("PBS SDP: Unable to register PBS Service");
+ return;
+ }
+
+ /* add service class */
+ if (SDP_AddServiceClassIdList(p_cb->sdp_handle, 1, &pbs_service))
+ {
+ memset( protoList, 0 , 3*sizeof(tSDP_PROTOCOL_ELEM) );
+ /* add protocol list, including RFCOMM scn */
+ protoList[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+ protoList[0].num_params = 0;
+ protoList[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
+ protoList[1].num_params = 1;
+ protoList[1].params[0] = p_cb->scn;
+ protoList[2].protocol_uuid = UUID_PROTOCOL_OBEX;
+ protoList[2].num_params = 0;
+
+ if (SDP_AddProtocolList(p_cb->sdp_handle, 3, protoList))
+ {
+ status = TRUE; /* All mandatory fields were successful */
+
+ /* optional: if name is not "", add a name entry */
+ if (*p_service_name != '\0')
+ SDP_AddAttribute(p_cb->sdp_handle,
+ (UINT16)ATTR_ID_SERVICE_NAME,
+ (UINT8)TEXT_STR_DESC_TYPE,
+ (UINT32)(strlen(p_service_name) + 1),
+ (UINT8 *)p_service_name);
+
+ /* Add in the Bluetooth Profile Descriptor List */
+ SDP_AddProfileDescriptorList(p_cb->sdp_handle,
+ UUID_SERVCLASS_PHONE_ACCESS,
+ BTA_PBS_DEFAULT_VERSION);
+
+ } /* end of setting mandatory protocol list */
+ } /* end of setting mandatory service class */
+
+ /* add supported feature and repositories */
+ if (status)
+ {
+// btla-specific ++
+ // SDP_AddAttribute(p_cb->sdp_handle, ATTR_ID_SUPPORTED_FEATURES, UINT_DESC_TYPE,
+ // (UINT32)1, (UINT8*)&p_bta_pbs_cfg->supported_features);
+ SDP_AddAttribute(p_cb->sdp_handle, ATTR_ID_SUPPORTED_REPOSITORIES, UINT_DESC_TYPE,
+ (UINT32)1, (UINT8*)&p_bta_pbs_cfg->supported_repositories);
+
+ /* Make the service browseable */
+ SDP_AddUuidSequence (p_cb->sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &browse);
+// btla-specific --
+ }
+
+ if (!status)
+ {
+ SDP_DeleteRecord(p_cb->sdp_handle);
+ APPL_TRACE_ERROR0("bta_pbs_sdp_register FAILED");
+ }
+ else
+ {
+ bta_sys_add_uuid(pbs_service); /* UUID_SERVCLASS_PBAP_PSE */
+ APPL_TRACE_DEBUG1("PBS: SDP Registered (handle 0x%08x)", p_cb->sdp_handle);
+ }
+
+ return;
+}
+#endif /* BTA_PBS_INCLUDED */
diff --git a/bta/pb/bta_pbs_utils.c b/bta/pb/bta_pbs_utils.c
new file mode 100644
index 0000000..61d7401
--- /dev/null
+++ b/bta/pb/bta_pbs_utils.c
@@ -0,0 +1,734 @@
+/*****************************************************************************
+**
+** Name: bta_pbs_utils.c
+**
+** Description: This file implements utils functions for phone book access
+** server.
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+
+#if defined(BTA_PBS_INCLUDED) && (BTA_PBS_INCLUDED == TRUE)
+
+#include <stdio.h>
+#include <string.h>
+#include "bta_fs_api.h"
+#include "bta_pbs_int.h"
+#include "bta_fs_co.h"
+#include "gki.h"
+#include "utl.h"
+
+/*******************************************************************************
+** Constants
+*******************************************************************************/
+
+/*******************************************************************************
+** Local Function Prototypes
+*******************************************************************************/
+static void bta_pbs_translate_special_character(char *buffer, const char *str);
+/*******************************************************************************
+* Macros for PBS
+*******************************************************************************/
+#define BTA_PBS_XML_EOL "\n"
+#define BTA_PBS_FOLDER_LISTING_START ( "<?xml version=\"1.0\"?>\n" \
+ "<!DOCTYPE vcard-listing SYSTEM \"vcard-listing.dtd\">\n" \
+ "<vCard-listing version=\"1.0\">\n" )
+
+#define BTA_PBS_FOLDER_LISTING_END ( "</vCard-listing>" )
+#define BTA_PBS_PARENT_FOLDER (" <parent-folder/>\n")
+
+#define BTA_PBS_CARD_ELEM "card handle"
+#define BTA_PBS_NAME_ATTR "name"
+
+/*******************************************************************************
+* Exported Functions
+*******************************************************************************/
+/*******************************************************************************
+**
+** Function bta_pbs_getdirlist
+**
+** Description Processes the retrieval of a directory listing.
+**
+** Parameters p_pkt - Pointer to the OBX Get request
+** name directory to list.
+**
+**
+** Returns UINT8 - OBX response code. OBX_RSP_OK if initiated.
+**
+*******************************************************************************/
+void bta_pbs_getvlist(char *p_name)
+{
+ tBTA_PBS_CB *p_cb = &bta_pbs_cb;
+ tBTA_PBS_OBX_PKT *p_obx = &p_cb->obx;
+ UINT16 temp_len;
+ UINT8 rsp_code = OBX_RSP_OK;
+ UINT16 pb_size, new_missed_call, len=0;
+ UINT8 *p, *p_start;
+ char *p_sep = NULL;
+
+
+ /* if this the first time asking for access */
+ if (!p_cb->p_path)
+ {
+ p_cb->p_path = (char *)GKI_getbuf((UINT16)(p_bta_fs_cfg->max_path_len + 1));
+ /* If not specified, use the current work directory */
+ if (!p_name || p_name[0] == '\0')
+ {
+ BCM_STRNCPY_S(p_cb->p_path, p_bta_fs_cfg->max_path_len+1, p_cb->p_workdir, p_bta_fs_cfg->max_path_len);
+ p_sep = strchr((char *)p_cb->p_path, '/');
+ if (p_sep)
+ *p_sep = p_bta_fs_cfg->path_separator;
+ }
+ else
+ {
+ if ((strlen(p_cb->p_workdir) + strlen(p_name) + 2) <= p_bta_fs_cfg->max_path_len)
+ {
+ sprintf(p_cb->p_path, "%s%c%s", p_cb->p_workdir,
+ p_bta_fs_cfg->path_separator, p_name);
+ if (p_bta_fs_cfg->path_separator == 0x5c)
+ {
+ while ((p_sep = strchr((char *)p_cb->p_path, '/')) != NULL)
+ {
+ if (p_sep)
+ *p_sep = p_bta_fs_cfg->path_separator;
+ }
+ }
+ }
+ else
+ rsp_code = OBX_RSP_BAD_REQUEST;
+ }
+ if (rsp_code == OBX_RSP_OK)
+ {
+ p_obx->p_pkt = (BT_HDR *)OBX_HdrInit(p_cb->obx_handle,
+ /* p_cb->peer_mtu */ OBX_LRG_DATA_POOL_SIZE);
+ if (p_obx->p_pkt)
+ {
+ /* Notify the application that a get file has been requested */
+ bta_pbs_req_app_access (BTA_PBS_OPER_PULL_VCARD_LIST, p_cb);
+ return;
+ }
+ else
+ rsp_code = OBX_RSP_BAD_REQUEST;
+ }
+ OBX_GetRsp(p_cb->obx_handle, rsp_code, (BT_HDR *)NULL);
+ bta_pbs_clean_getput(p_cb, TRUE);
+ }
+ else if (p_cb->p_path)
+ {
+ /* Build the listing */
+ if (rsp_code == OBX_RSP_OK)
+ {
+ if (!p_obx->p_pkt)
+ p_obx->p_pkt = (BT_HDR *)OBX_HdrInit(p_cb->obx_handle,
+ /* p_cb->peer_mtu */ OBX_LRG_DATA_POOL_SIZE);
+ if (p_obx->p_pkt)
+ {
+ /* Is this a new request or continuation? */
+ if ((p_cb->obx_oper == BTA_PBS_OPER_NONE))
+ {
+ p_cb->get_only_indexes = FALSE;
+
+ if (p_cb->getvlist_app_params.max_count == 0 ||
+ p_cb->obj_type == BTA_PBS_MCH_OBJ)
+ {
+ p_start = OBX_AddByteStrStart(p_obx->p_pkt, &len);
+ bta_pbs_co_getpbinfo(p_cb->obx_oper, p_cb->obj_type, &pb_size, &new_missed_call);
+ p = p_start;
+ /* Just looking for number of indexes only ? */
+ if (p_cb->getvlist_app_params.max_count == 0)
+ {
+ *p++ = BTA_PBS_TAG_PB_SIZE;
+ *p++ = 2;
+ p_cb->p_stream_indexes = p; /* save location to store entries later */
+ UINT16_TO_BE_STREAM(p, p_cb->getvlist_app_params.max_count);
+
+ /* overwrite appl params max count so entries will be retrieved */
+ p_cb->getvlist_app_params.max_count = BTA_PBS_MAX_LIST_COUNT;
+ /* ignore the list start offset */
+ p_cb->getvlist_app_params.start_offset = 0;
+ p_cb->get_only_indexes = TRUE;
+ p_cb->num_vlist_idxs = 0;
+ APPL_TRACE_EVENT1("PBS Get Vcard List: Name [p_stream = 0x%07x] (Indexes Only)", /*p_cb->p_path*/(UINT32)p_cb->p_stream_indexes);
+ }
+
+ if (p_cb->obj_type == BTA_PBS_MCH_OBJ)
+ {
+ *p++ = BTA_PBS_TAG_NEW_MISSED_CALLS;
+ *p++ = 1;
+ *p++ = (UINT8) new_missed_call;
+ }
+ OBX_AddByteStrHdr(p_obx->p_pkt, OBX_HI_APP_PARMS, NULL, (UINT16)(p - p_start));
+ }
+
+ /* By pass Body Header if only requesting number of entries */
+ if (!p_cb->get_only_indexes)
+ {
+ /* Add the start of the Body Header */
+ p_obx->offset = 0;
+ p_obx->bytes_left = 0;
+ p_obx->p_start = OBX_AddBodyStart(p_obx->p_pkt, &p_obx->bytes_left);
+
+ temp_len = strlen(BTA_PBS_FOLDER_LISTING_START);
+
+ /* Add the beginning label of vard list */
+ memcpy(p_obx->p_start, BTA_PBS_FOLDER_LISTING_START, temp_len);
+ p_obx->bytes_left -= (UINT16)(temp_len + strlen(BTA_PBS_FOLDER_LISTING_END));
+ p_obx->offset += temp_len;
+
+ APPL_TRACE_EVENT1("PBS Get Vcard List: Name [%s]", p_cb->p_path);
+ }
+
+ p_cb->obx_oper = BTA_PBS_OPER_PULL_VCARD_LIST;
+ p_cb->cout_active = TRUE;
+
+ bta_pbs_co_getvlist(p_cb->p_path, &p_cb->getvlist_app_params,
+ TRUE, &p_cb->vlist);
+
+ /* List is not complete, so don't send the response yet */
+ rsp_code = OBX_RSP_PART_CONTENT;
+ }
+ else /* continue case */
+ {
+ /* By pass Body Header if only requesting number of entries */
+ if (!p_cb->get_only_indexes)
+ {
+ /* Add the start of the Body Header */
+ p_obx->offset = 0;
+ p_obx->bytes_left = 0;
+ p_obx->p_start = OBX_AddBodyStart(p_obx->p_pkt, &p_obx->bytes_left);
+ APPL_TRACE_EVENT1("PBS Get Vcard List: Name [%s] continue", p_cb->p_path);
+ }
+
+ /* Add the entry previously retrieved */
+ rsp_code = bta_pbs_add_list_entry();
+
+ if (!p_obx->final_pkt) {
+ p_cb->cout_active = TRUE;
+
+ bta_pbs_co_getvlist(p_cb->p_path, &p_cb->getvlist_app_params,
+ FALSE, &p_cb->vlist);
+ /* List is not complete, so don't send the response yet */
+ rsp_code = OBX_RSP_PART_CONTENT;
+ } else
+ p_obx->final_pkt = FALSE;
+ }
+ }
+ else
+ rsp_code = OBX_RSP_SERVICE_UNAVL;
+ }
+ }
+ else /* Error occurred */
+ rsp_code = OBX_RSP_SERVICE_UNAVL;
+
+ /* Response goes out if complete or error occurred */
+ if (rsp_code != OBX_RSP_PART_CONTENT)
+ bta_pbs_end_of_list(rsp_code);
+}
+
+/*******************************************************************************
+**
+** Function bta_pbs_proc_get_file
+**
+** Description Processes a Get File Operation.
+** If first OBX request, the file is opened, otherwise if it is
+** a continuation the next read is initiated.
+**
+** Parameters p_pkt - Pointer to the OBX Get request
+** name of file to read.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pbs_proc_get_file(char *p_name, tBTA_PBS_OPER operation)
+{
+ tBTA_PBS_CB *p_cb = &bta_pbs_cb;
+ tBTA_PBS_OBX_PKT *p_obx = &p_cb->obx;
+ UINT8 rsp_code = OBX_RSP_SERVICE_UNAVL;
+ char *p_sep;
+
+ if (operation != BTA_PBS_OPER_PULL_PB && operation != BTA_PBS_OPER_PULL_VCARD_ENTRY)
+ return;
+ /* Allocate an OBX packet */
+ if (p_obx->p_pkt != NULL || (p_obx->p_pkt = (BT_HDR *)OBX_HdrInit(p_cb->obx_handle,
+ /*p_cb->peer_mtu*/OBX_LRG_DATA_POOL_SIZE)) != NULL)
+ {
+ /* Is this a new request or continuation? */
+ if ((p_cb->obx_oper == BTA_PBS_OPER_NONE))
+ {
+ /* Validate the name */
+ if (p_name)
+ {
+ if ((p_cb->p_path =
+ (char *)GKI_getbuf((UINT16)(p_bta_fs_cfg->max_path_len + 1))) != NULL)
+ {
+ /* Build a fully qualified path for Pull Vcard entry */
+ if (operation == BTA_PBS_OPER_PULL_VCARD_ENTRY)
+ {
+ if ((strlen(p_cb->p_workdir) + strlen(p_name) + 2)
+ <= p_bta_fs_cfg->max_path_len)
+ {
+ rsp_code = OBX_RSP_OK;
+ sprintf(p_cb->p_path, "%s%c%s", p_cb->p_workdir,
+ p_bta_fs_cfg->path_separator, p_name);
+ if (p_bta_fs_cfg->path_separator == 0x5c) {
+ while ((p_sep = strchr((char *)p_cb->p_path, '/')) != NULL)
+ {
+ if (p_sep)
+ *p_sep = p_bta_fs_cfg->path_separator;
+ }
+ }
+
+ APPL_TRACE_EVENT1("PBS PULL VCARD ENTRY: Name [%s]", p_cb->p_path);
+
+ p_cb->obx_oper = BTA_PBS_OPER_PULL_VCARD_ENTRY;
+
+ /* Notify the application that a get file has been requested */
+ bta_pbs_req_app_access (BTA_PBS_OPER_PULL_VCARD_ENTRY, p_cb);
+ }
+ }
+
+ /* Build a fully qualified path for Pull PBentry */
+ if (operation == BTA_PBS_OPER_PULL_PB)
+ {
+ if ((strlen(p_cb->p_rootpath) + strlen(p_name) + 2)
+ <= p_bta_fs_cfg->max_path_len)
+ {
+ rsp_code = OBX_RSP_OK;
+ sprintf(p_cb->p_path, "%s%c%s", p_cb->p_rootpath,
+ p_bta_fs_cfg->path_separator, p_name);
+ if (p_bta_fs_cfg->path_separator == 0x5c) {
+ while ((p_sep = strchr((char *)p_cb->p_path, '/')) != NULL)
+ {
+ if (p_sep)
+ *p_sep = p_bta_fs_cfg->path_separator;
+ }
+ }
+
+ APPL_TRACE_EVENT1("PBS PULL PB : Name [%s]", p_cb->p_path);
+
+ p_cb->obx_oper = BTA_PBS_OPER_PULL_PB;
+
+ /* Notify the application that a get file has been requested */
+ bta_pbs_req_app_access (BTA_PBS_OPER_PULL_PB, p_cb);
+ }
+ }
+
+ }
+ }
+ }
+ else /* Continue reading from the file */
+ {
+ /* Add the start of the Body Header */
+ p_obx->offset = 0;
+ p_obx->bytes_left = 0;
+ p_obx->p_start = OBX_AddBodyStart(p_obx->p_pkt, &p_obx->bytes_left);
+
+ rsp_code = OBX_RSP_OK;
+ p_cb->cout_active = TRUE;
+ bta_pbs_co_read(p_cb->fd, p_cb->obx_oper, &p_obx->p_start[p_obx->offset],
+ p_obx->bytes_left);
+ }
+ }
+ if (rsp_code != OBX_RSP_OK)
+ bta_pbs_get_file_rsp(rsp_code, 0);
+}
+
+
+
+
+/*******************************************************************************
+**
+** Function bta_pbs_chdir
+**
+** Description Changes the current path to the specified directory.
+**
+** Parameters p_pkt - Pointer to the OBX packet
+** backup_flag - if TRUE, path adjusted up one level.
+**
+** Returns UINT8 - OBX response code
+**
+*******************************************************************************/
+UINT8 bta_pbs_chdir(BT_HDR *p_pkt, BOOLEAN backup_flag, tBTA_PBS_OPER *p_op)
+{
+ tBTA_PBS_CB *p_cb = &bta_pbs_cb;
+ char *p_path;
+ char *p_name;
+ char *p_workdir = p_cb->p_workdir;
+ UINT8 rsp_code = OBX_RSP_SERVICE_UNAVL;
+ BOOLEAN is_dir;
+
+ if (!backup_flag)
+ {
+ p_path = p_cb->p_path;
+ p_name = p_cb->p_name;
+
+ /* If No Name header, or if it is NULL, set to root path */
+ if (*p_name == '\0')
+ {
+ BCM_STRNCPY_S(p_workdir, p_bta_fs_cfg->max_path_len+1, p_cb->p_rootpath, p_bta_fs_cfg->max_path_len);
+ p_workdir[p_bta_fs_cfg->max_path_len] = '\0';
+ p_cb->obj_type = BTA_PBS_NONE_OBJ;
+ rsp_code = OBX_RSP_OK;
+ APPL_TRACE_DEBUG0("PBS: Setting current path to ROOT");
+ }
+ /* Make sure the new path is not too big */
+ else if ((strlen(p_name) + strlen(p_workdir) + 2)
+ <= p_bta_fs_cfg->max_path_len)
+ {
+ if (!strcmp(p_name, "pb") || !strcmp(p_name, "telecom") ||
+ !strcmp(p_name, "ich") || !strcmp(p_name, "och") ||
+ !strcmp(p_name, "mch") || !strcmp(p_name, "cch") ||
+ !strcmp(p_name, "SIM1"))
+ {
+
+ /* create a temporary path for creation attempt */
+ sprintf(p_path, "%s%c%s", p_workdir,
+ p_bta_fs_cfg->path_separator, p_name);
+
+ if (((bta_fs_co_access(p_path, BTA_FS_ACC_EXIST,
+ &is_dir, p_cb->app_id)) == BTA_FS_CO_OK) && is_dir)
+ {
+ *p_op = BTA_PBS_OPER_SET_PB;
+ }
+ else
+ rsp_code = OBX_RSP_NOT_FOUND;
+ }
+ else
+ rsp_code = OBX_RSP_BAD_REQUEST;
+ }
+ }
+ else /* Backing up a directory */
+ {
+ /* Backup a level unless already at root */
+ if (strcmp(p_workdir, p_cb->p_rootpath))
+ {
+ /* Find the last occurrence of separator and replace with '\0' */
+ if ((p_path = strrchr(p_workdir, (int)p_bta_fs_cfg->path_separator)) != NULL)
+ *p_path = '\0';
+ p_cb->obj_type = BTA_PBS_NONE_OBJ;
+ APPL_TRACE_DEBUG1("PBS: SET NEW PATH [%s]", p_cb->p_workdir);
+
+ rsp_code = OBX_RSP_OK;
+ }
+ else
+ rsp_code = OBX_RSP_NOT_FOUND;
+ }
+
+ return (rsp_code);
+}
+
+
+/*******************************************************************************
+**
+** Function bta_pbs_end_of_list
+**
+** Description Finishes up the end body of the listing, and sends out the
+** OBX response
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pbs_end_of_list(UINT8 rsp_code)
+{
+ tBTA_PBS_CB *p_cb = &bta_pbs_cb;
+ tBTA_PBS_OBX_PKT *p_obx = &p_cb->obx;
+ UINT16 temp_len;
+
+ /* Add the end of folder listing string if successful operation */
+ if (rsp_code == OBX_RSP_OK || rsp_code == OBX_RSP_CONTINUE)
+ {
+ /* If only getting entries add the number to the response */
+ if (p_cb->get_only_indexes)
+ {
+ if (rsp_code != OBX_RSP_OK)
+ {
+ rsp_code = OBX_RSP_OK;
+ APPL_TRACE_WARNING0("bta_pbs_end_of_list: index ONLY, but received OBX_RSP_CONTINUE??");
+ }
+ APPL_TRACE_DEBUG2("bta_pbs_end_of_list: indexes = %d, p_stream_indexes = 0x%07x",
+ p_cb->num_vlist_idxs, p_cb->p_stream_indexes);
+ UINT16_TO_BE_STREAM(p_cb->p_stream_indexes, p_cb->num_vlist_idxs);
+ }
+ else
+ {
+ /* If listing has completed, add on end string (http) */
+ if (rsp_code == OBX_RSP_OK)
+ {
+ temp_len = strlen(BTA_PBS_FOLDER_LISTING_END);
+ memcpy(&p_obx->p_start[p_obx->offset], BTA_PBS_FOLDER_LISTING_END, temp_len);
+ p_obx->offset += temp_len;
+
+ OBX_AddBodyEnd(p_obx->p_pkt, p_obx->p_start, p_obx->offset, TRUE);
+ }
+ else /* More listing data to be sent */
+ OBX_AddBodyEnd(p_obx->p_pkt, p_obx->p_start, p_obx->offset, FALSE);
+ }
+
+ OBX_GetRsp(p_cb->obx_handle, rsp_code, (BT_HDR *)p_obx->p_pkt);
+ p_obx->p_pkt = NULL; /* Do not deallocate buffer; OBX will */
+ if (rsp_code == OBX_RSP_OK)
+ bta_pbs_clean_getput(p_cb, FALSE);
+ }
+ else /* An error occurred */
+ {
+ OBX_GetRsp(p_cb->obx_handle, rsp_code, (BT_HDR *)NULL);
+ bta_pbs_clean_getput(p_cb, TRUE);
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function bta_pbs_get_file_rsp
+**
+** Description Finishes up the end body of the file get, and sends out the
+** OBX response
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pbs_get_file_rsp(UINT8 rsp_code, UINT16 num_read)
+{
+ tBTA_PBS_CB *p_cb = &bta_pbs_cb;
+ tBTA_PBS_OBX_PKT *p_obx = &p_cb->obx;
+ BOOLEAN done = TRUE;
+
+ /* Send the response packet if successful operation */
+ if (rsp_code == OBX_RSP_OK || rsp_code == OBX_RSP_CONTINUE)
+ {
+ p_obx->offset += num_read;
+
+ /* More to be sent */
+ if (rsp_code == OBX_RSP_CONTINUE)
+ {
+ if (p_obx->bytes_left != num_read)
+ APPL_TRACE_WARNING2("PBS Read: Requested (0x%04x), Read In (0x%04x)",
+ p_obx->bytes_left, num_read);
+ done = FALSE;
+ }
+
+ if (num_read)
+ OBX_AddBodyEnd(p_obx->p_pkt, p_obx->p_start, p_obx->offset, done);
+ }
+ else
+ p_cb->obx_oper = BTA_PBS_OPER_NONE;
+
+ OBX_GetRsp(p_cb->obx_handle, rsp_code, (BT_HDR *)p_obx->p_pkt);
+ p_obx->p_pkt = NULL; /* Do not deallocate buffer; OBX will */
+
+ /* Final response packet sent out */
+ if (done && rsp_code == OBX_RSP_OK)
+ bta_pbs_clean_getput(p_cb, FALSE);
+ /* If there is error */
+ if (rsp_code != OBX_RSP_OK && rsp_code != OBX_RSP_CONTINUE)
+ bta_pbs_clean_getput(p_cb, TRUE);
+}
+
+
+/*******************************************************************************
+**
+** Function bta_pbs_add_list_entry
+**
+** Description used by bta_pbs_getdirlist to write a list entry to an
+** obex packet (byte array).
+**
+** Returns UINT8 - OBX response code
+** OBX_RSP_OK
+** OBX_RSP_CONTINUE
+** Others send error response out
+**
+*******************************************************************************/
+UINT8 bta_pbs_add_list_entry(void)
+{
+ tBTA_PBS_CB *p_cb = &bta_pbs_cb;
+ tBTA_PBS_OBX_PKT *p_obx = &p_cb->obx;
+ char *p_buf;
+ UINT16 size;
+ UINT8 rsp_code = OBX_RSP_SERVICE_UNAVL;
+
+ /* Skip filling in entry; just counting */
+ if (p_cb->get_only_indexes)
+ {
+ return (OBX_RSP_OK);
+ }
+
+ if ((p_buf = (char *)GKI_getbuf(GKI_MAX_BUF_SIZE)) != NULL)
+ {
+ p_buf[0] = '\0';
+
+ APPL_TRACE_DEBUG2("bta_pbs_add_list_entry: handle:%s, name:%s",
+ p_cb->vlist.handle, p_cb->vlist.name);
+
+ sprintf(p_buf, " <" BTA_PBS_CARD_ELEM " = \"%s\" " BTA_PBS_NAME_ATTR " = \"",p_cb->vlist.handle);
+ /* Need to translate special characters to XML format */
+ bta_pbs_translate_special_character(strlen(p_buf) + p_buf, p_cb->vlist.name);
+ sprintf(strlen(p_buf)+p_buf, "\"/>" BTA_PBS_XML_EOL);
+ /* Make sure the entry fits into the current obx packet */
+ size = strlen(p_buf);
+ if (size <= p_obx->bytes_left)
+ {
+ if (size > 0)
+ {
+ memcpy (&p_obx->p_start[p_obx->offset], p_buf, size);
+ p_obx->offset += size;
+ p_obx->bytes_left -= size;
+ }
+ rsp_code = OBX_RSP_OK;
+ }
+ else /* entry did not fit in current obx packet; try to add entry in next obx req */
+ rsp_code = OBX_RSP_CONTINUE;
+
+ /* Done with temporary buffer */
+ GKI_freebuf(p_buf);
+ }
+ else
+ rsp_code = OBX_RSP_SERVICE_UNAVL;
+
+ return (rsp_code);
+}
+
+
+/*******************************************************************************
+**
+** Function bta_pbs_clean_getput
+**
+** Description Cleans up the get resources and control block
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pbs_clean_getput(tBTA_PBS_CB *p_cb, BOOLEAN is_aborted)
+{
+ tBTA_PBS_OBJECT objdata;
+
+ /* Clean up control block */
+ utl_freebuf((void**)&p_cb->obx.p_pkt);
+
+ /* Close any open files */
+ if (p_cb->fd >= 0)
+ {
+ bta_pbs_co_close(p_cb->fd);
+ p_cb->fd = BTA_FS_INVALID_FD;
+ }
+
+ /* Notify the application */
+ objdata.p_name = p_cb->p_path;
+
+ if (is_aborted)
+ objdata.status = BTA_PBS_FAIL;
+ else
+ objdata.status = BTA_PBS_OK;
+
+ if (p_cb->p_cback && p_cb->obx_oper != 0)
+ {
+ objdata.operation = p_cb->obx_oper;
+ /* Notify application of operation complete */
+ p_cb->p_cback(BTA_PBS_OPER_CMPL_EVT, (tBTA_PBS *)&objdata);
+ }
+
+ utl_freebuf((void**)&p_cb->p_name);
+ utl_freebuf((void**)&p_cb->p_path);
+
+ p_cb->obx_oper = BTA_PBS_OPER_NONE;
+ p_cb->obj_type = BTA_PBS_NONE_OBJ;
+ p_cb->obx.bytes_left = 0;
+ p_cb->file_length = BTA_FS_LEN_UNKNOWN;
+ p_cb->acc_active = 0;
+// btla-specific ++
+ p_cb->aborting = FALSE;
+// btla-specific --
+ memset(&p_cb->getvlist_app_params, 0, sizeof(p_cb->getvlist_app_params));
+ memset(&p_cb->pullpb_app_params, 0, sizeof(p_cb->pullpb_app_params));
+ memset(&p_cb->vlist, 0, sizeof(p_cb->vlist));
+}
+
+/*****************************************************************************
+* Function: bta_pbs_read_app_params
+* Purpose: Read the application parameters from the given OBX packet
+*****************************************************************************/
+UINT8 * bta_pbs_read_app_params(BT_HDR *p_pkt, UINT8 tag, UINT16 *param_len)
+{
+ UINT8 *p_data = NULL, *p = NULL;
+ UINT16 data_len = 0;
+ int left, len;
+
+ if(OBX_ReadByteStrHdr(p_pkt, OBX_HI_APP_PARMS, &p_data, &data_len, 0))
+ {
+ left = data_len;
+ while(left > 0)
+ {
+ len = *(p_data + 1);
+ if(*p_data == tag)
+ {
+ p_data += 2;
+ p = p_data;
+ *param_len = (UINT16) len;
+ break;
+ }
+ p_data += (len+2);
+ left -= (len+2);
+ }
+ }
+ return p;
+}
+
+
+
+/*******************************************************************************
+**
+** Function bta_pbs_handle_special_character
+**
+** Description Translate special characters to XML format
+**
+**
+** Returns Void
+**
+*******************************************************************************/
+static void bta_pbs_translate_special_character(char *buffer, const char *str)
+{
+ char *buf=buffer;
+ int slen = strlen(str);
+ int i;
+ for (i=0; i < slen;i++)
+ {
+
+ char c = str[i];
+ switch (c)
+ {
+ case '<':
+ BCM_STRCPY_S(buf,4,"&lt;");
+ buf+=4;
+ break;
+ case '>':
+ BCM_STRCPY_S(buf,4,"&gt;");
+ buf+=4;
+ break;
+ case '\"':
+ BCM_STRCPY_S(buf,6,"&quot;");
+ buf+=6;
+ break;
+ case '\'':
+ BCM_STRCPY_S(buf,6,"&apos;");
+ buf+=6;
+ break;
+ case '&':
+ BCM_STRCPY_S(buf,5,"&amp;");
+ buf+=5;
+ break;
+ default:
+ buf[0]=c;
+ buf++;
+ }
+ }
+ buf[0]='\0';
+
+}
+
+
+
+#endif /* BTA_PBS_INCLUDED */
diff --git a/bta/sys/bd.c b/bta/sys/bd.c
new file mode 100644
index 0000000..3c639d1
--- /dev/null
+++ b/bta/sys/bd.c
@@ -0,0 +1,99 @@
+/*****************************************************************************
+**
+** Name: bd.c
+**
+** Description: BD address services.
+**
+** Copyright (c) 2003, Widcomm Inc., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "data_types.h"
+#include "bd.h"
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+/* global constant for "any" bd addr */
+const BD_ADDR bd_addr_any = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+const BD_ADDR bd_addr_null= {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+/*****************************************************************************
+** Functions
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function bdcpy
+**
+** Description Copy bd addr b to a.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bdcpy(BD_ADDR a, const BD_ADDR b)
+{
+ int i;
+
+ for (i = BD_ADDR_LEN; i != 0; i--)
+ {
+ *a++ = *b++;
+ }
+}
+
+/*******************************************************************************
+**
+** Function bdcmp
+**
+** Description Compare bd addr b to a.
+**
+**
+** Returns Zero if b==a, nonzero otherwise (like memcmp).
+**
+*******************************************************************************/
+int bdcmp(const BD_ADDR a, const BD_ADDR b)
+{
+ int i;
+
+ for (i = BD_ADDR_LEN; i != 0; i--)
+ {
+ if (*a++ != *b++)
+ {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/*******************************************************************************
+**
+** Function bdcmpany
+**
+** Description Compare bd addr to "any" bd addr.
+**
+**
+** Returns Zero if a equals bd_addr_any.
+**
+*******************************************************************************/
+int bdcmpany(const BD_ADDR a)
+{
+ return bdcmp(a, bd_addr_any);
+}
+
+/*******************************************************************************
+**
+** Function bdsetany
+**
+** Description Set bd addr to "any" bd addr.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bdsetany(BD_ADDR a)
+{
+ bdcpy(a, bd_addr_any);
+}
diff --git a/bta/sys/bta_sys.h b/bta/sys/bta_sys.h
new file mode 100644
index 0000000..32cb69a
--- /dev/null
+++ b/bta/sys/bta_sys.h
@@ -0,0 +1,296 @@
+/*****************************************************************************
+**
+** Name: bta_sys.h
+**
+** Description: This is the public interface file for the BTA system
+** manager.
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_SYS_H
+#define BTA_SYS_H
+
+#include "bt_target.h"
+#include "gki.h"
+
+/*****************************************************************************
+** Constants and data types
+*****************************************************************************/
+
+/* event handler function type */
+typedef BOOLEAN (tBTA_SYS_EVT_HDLR)(BT_HDR *p_msg);
+
+/* disable function type */
+typedef void (tBTA_SYS_DISABLE)(void);
+
+
+/* HW modules */
+enum
+{
+ BTA_SYS_HW_BLUETOOTH,
+ BTA_SYS_HW_FMRX,
+ BTA_SYS_HW_FMTX,
+ BTA_SYS_HW_GPS,
+ BTA_SYS_HW_SENSOR,
+ BTA_SYS_HW_NFC,
+ BTA_SYS_HW_RT,
+
+ BTA_SYS_MAX_HW_MODULES
+};
+
+typedef UINT16 tBTA_SYS_HW_MODULE;
+
+#ifndef BTA_DM_NUM_JV_ID
+#define BTA_DM_NUM_JV_ID 2
+#endif
+
+/* SW sub-systems */
+#define BTA_ID_SYS 0 /* system manager */
+/* BLUETOOTH PART - from 0 to BTA_ID_BLUETOOTH_MAX */
+#define BTA_ID_DM 1 /* device manager */
+#define BTA_ID_DM_SEARCH 2 /* device manager search */
+#define BTA_ID_DM_SEC 3 /* device manager security */
+#define BTA_ID_DG 4 /* data gateway */
+#define BTA_ID_AG 5 /* audio gateway */
+#define BTA_ID_OPC 6 /* object push client */
+#define BTA_ID_OPS 7 /* object push server */
+#define BTA_ID_FTS 8 /* file transfer server */
+#define BTA_ID_CT 9 /* cordless telephony terminal */
+#define BTA_ID_FTC 10 /* file transfer client */
+#define BTA_ID_SS 11 /* synchronization server */
+#define BTA_ID_PR 12 /* Printer client */
+#define BTA_ID_BIC 13 /* Basic Imaging Client */
+#define BTA_ID_PAN 14 /* Personal Area Networking */
+#define BTA_ID_BIS 15 /* Basic Imaging Server */
+#define BTA_ID_ACC 16 /* Advanced Camera Client */
+#define BTA_ID_SC 17 /* SIM Card Access server */
+#define BTA_ID_AV 18 /* Advanced audio/video */
+#define BTA_ID_AVK 19 /* Audio/video sink */
+#define BTA_ID_HD 20 /* HID Device */
+#define BTA_ID_CG 21 /* Cordless Gateway */
+#define BTA_ID_BP 22 /* Basic Printing Client */
+#define BTA_ID_HH 23 /* Human Interface Device Host */
+#define BTA_ID_PBS 24 /* Phone Book Access Server */
+#define BTA_ID_PBC 25 /* Phone Book Access Client */
+#define BTA_ID_JV 26 /* Java */
+#define BTA_ID_HS 27 /* Headset */
+#define BTA_ID_MSE 28 /* Message Server Equipment */
+#define BTA_ID_MCE 29 /* Message Client Equipment */
+#define BTA_ID_HL 30 /* Health Device Profile*/
+#define BTA_ID_GATTC 31 /* GATT Client */
+#define BTA_ID_GATTS 32 /* GATT Client */
+#define BTA_ID_BLUETOOTH_MAX 33 /* last BT profile */
+
+/* FM */
+#define BTA_ID_FM 34 /* FM */
+#define BTA_ID_FMTX 35 /* FM TX */
+
+/* SENSOR */
+#define BTA_ID_SSR 36 /* Sensor */
+
+/* GPS */
+#define BTA_ID_GPS 37 /* GPS */
+
+/* GENERIC */
+#define BTA_ID_PRM 38
+#define BTA_ID_SYSTEM 39 /* platform-specific */
+#define BTA_ID_SWRAP 40 /* Insight script wrapper */
+#define BTA_ID_MIP 41 /* Multicase Individual Polling */
+#define BTA_ID_RT 42 /* Audio Routing module: This module is always on. */
+
+
+/* JV */
+#define BTA_ID_JV1 43 /* JV1 */
+#define BTA_ID_JV2 44 /* JV2 */
+
+#define BTA_ID_MAX (43 + BTA_DM_NUM_JV_ID)
+
+typedef UINT8 tBTA_SYS_ID;
+
+
+#define BTA_SYS_CONN_OPEN 0x00
+#define BTA_SYS_CONN_CLOSE 0x01
+#define BTA_SYS_APP_OPEN 0x02
+#define BTA_SYS_APP_CLOSE 0x03
+#define BTA_SYS_SCO_OPEN 0x04
+#define BTA_SYS_SCO_CLOSE 0x05
+#define BTA_SYS_CONN_IDLE 0x06
+#define BTA_SYS_CONN_BUSY 0x07
+
+/* for link policy */
+#define BTA_SYS_PLCY_SET 0x10 /* set the link policy to the given addr */
+#define BTA_SYS_PLCY_CLR 0x11 /* clear the link policy to the given addr */
+#define BTA_SYS_PLCY_DEF_SET 0x12 /* set the default link policy */
+#define BTA_SYS_PLCY_DEF_CLR 0x13 /* clear the default link policy */
+#define BTA_SYS_ROLE_CHANGE 0x14 /* role change */
+
+typedef UINT8 tBTA_SYS_CONN_STATUS;
+
+/* Bitmask of sys features */
+#define BTA_SYS_FEAT_PCM2 0x0001
+#define BTA_SYS_FEAT_PCM2_MASTER 0x0002
+
+/* tBTA_PREF_ROLES */
+typedef UINT8 tBTA_SYS_PREF_ROLES;
+
+/* conn callback for role / low power manager*/
+typedef void (tBTA_SYS_CONN_CBACK)(tBTA_SYS_CONN_STATUS status,UINT8 id, UINT8 app_id, BD_ADDR peer_addr);
+
+/* conn callback for role / low power manager*/
+typedef void (tBTA_SYS_SSR_CFG_CBACK)(UINT8 id, UINT8 app_id, UINT16 latency, UINT16 tout);
+
+#if ( BTM_EIR_SERVER_INCLUDED == TRUE )&&(BTA_EIR_CANNED_UUID_LIST != TRUE)
+/* eir callback for adding/removeing UUID */
+typedef void (tBTA_SYS_EIR_CBACK)(UINT16 uuid16, BOOLEAN adding);
+#endif
+
+/* registration structure */
+typedef struct
+{
+ tBTA_SYS_EVT_HDLR *evt_hdlr;
+ tBTA_SYS_DISABLE *disable;
+} tBTA_SYS_REG;
+
+/* system manager configuration structure */
+typedef struct
+{
+ UINT16 mbox_evt; /* GKI mailbox event */
+ UINT8 mbox; /* GKI mailbox id */
+ UINT8 timer; /* GKI timer id */
+ UINT8 trace_level; /* initial trace level */
+} tBTA_SYS_CFG;
+
+/* data type to send events to BTA SYS HW manager */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_SYS_HW_MODULE hw_module;
+} tBTA_SYS_HW_MSG;
+
+
+
+/*****************************************************************************
+** Global data
+*****************************************************************************/
+
+/* trace level */
+extern UINT8 appl_trace_level;
+
+/*****************************************************************************
+** Macros
+*****************************************************************************/
+
+/* Calculate start of event enumeration; id is top 8 bits of event */
+#define BTA_SYS_EVT_START(id) ((id) << 8)
+
+/*****************************************************************************
+** events for BTA SYS HW manager
+*****************************************************************************/
+
+/* events sent to SYS HW manager - must be kept synchronized with tables in bta_sys_main.c */
+enum
+{
+ /* device manager local device API events */
+ BTA_SYS_API_ENABLE_EVT = BTA_SYS_EVT_START(BTA_ID_SYS),
+ BTA_SYS_EVT_ENABLED_EVT,
+ BTA_SYS_EVT_STACK_ENABLED_EVT,
+ BTA_SYS_API_DISABLE_EVT,
+ BTA_SYS_EVT_DISABLED_EVT,
+ BTA_SYS_ERROR_EVT,
+
+ BTA_SYS_MAX_EVT
+};
+
+
+
+/* SYS HW status events - returned by SYS HW manager to other modules. */
+enum
+{
+ BTA_SYS_HW_OFF_EVT,
+ BTA_SYS_HW_ON_EVT,
+ BTA_SYS_HW_STARTING_EVT,
+ BTA_SYS_HW_STOPPING_EVT,
+ BTA_SYS_HW_ERROR_EVT
+
+};
+typedef UINT8 tBTA_SYS_HW_EVT;
+
+/* HW enable callback type */
+typedef void (tBTA_SYS_HW_CBACK)(tBTA_SYS_HW_EVT status);
+
+/*****************************************************************************
+** Function declarations
+*****************************************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+BTA_API extern void bta_sys_init(void);
+BTA_API extern void bta_sys_event(BT_HDR *p_msg);
+BTA_API extern void bta_sys_timer_update(void);
+BTA_API extern void bta_sys_disable_timers(void);
+BTA_API extern void bta_sys_set_trace_level(UINT8 level);
+extern void bta_sys_register(UINT8 id, const tBTA_SYS_REG *p_reg);
+extern void bta_sys_deregister(UINT8 id);
+extern BOOLEAN bta_sys_is_register(UINT8 id);
+extern UINT16 bta_sys_get_sys_features(void);
+extern void bta_sys_sendmsg(void *p_msg);
+extern void bta_sys_start_timer(TIMER_LIST_ENT *p_tle, UINT16 type, INT32 timeout);
+extern void bta_sys_stop_timer(TIMER_LIST_ENT *p_tle);
+extern void bta_sys_disable(tBTA_SYS_HW_MODULE module);
+
+extern void bta_sys_hw_register( tBTA_SYS_HW_MODULE module, tBTA_SYS_HW_CBACK *cback);
+extern void bta_sys_hw_unregister( tBTA_SYS_HW_MODULE module );
+
+
+extern void bta_sys_rm_register(tBTA_SYS_CONN_CBACK * p_cback);
+extern void bta_sys_pm_register(tBTA_SYS_CONN_CBACK * p_cback);
+
+extern void bta_sys_policy_register(tBTA_SYS_CONN_CBACK * p_cback);
+extern void bta_sys_sco_register(tBTA_SYS_CONN_CBACK * p_cback);
+
+
+extern void bta_sys_conn_open(UINT8 id, UINT8 app_id, BD_ADDR peer_addr);
+extern void bta_sys_conn_close(UINT8 id, UINT8 app_id, BD_ADDR peer_addr);
+extern void bta_sys_app_open(UINT8 id, UINT8 app_id, BD_ADDR peer_addr);
+extern void bta_sys_app_close(UINT8 id, UINT8 app_id, BD_ADDR peer_addr);
+extern void bta_sys_sco_open(UINT8 id, UINT8 app_id, BD_ADDR peer_addr);
+extern void bta_sys_sco_close(UINT8 id, UINT8 app_id, BD_ADDR peer_addr);
+extern void bta_sys_sco_use(UINT8 id, UINT8 app_id, BD_ADDR peer_addr);
+extern void bta_sys_sco_unuse(UINT8 id, UINT8 app_id, BD_ADDR peer_addr);
+extern void bta_sys_idle(UINT8 id, UINT8 app_id, BD_ADDR peer_addr);
+extern void bta_sys_busy(UINT8 id, UINT8 app_id, BD_ADDR peer_addr);
+
+#if (BTM_SSR_INCLUDED == TRUE)
+extern void bta_sys_ssr_cfg_register(tBTA_SYS_SSR_CFG_CBACK * p_cback);
+extern void bta_sys_chg_ssr_config (UINT8 id, UINT8 app_id, UINT16 max_latency, UINT16 min_tout);
+#endif
+
+extern void bta_sys_role_chg_register(tBTA_SYS_CONN_CBACK * p_cback);
+extern void bta_sys_notify_role_chg(BD_ADDR_PTR p_bda, UINT8 new_role, UINT8 hci_status);
+extern void bta_sys_collision_register(UINT8 bta_id, tBTA_SYS_CONN_CBACK *p_cback);
+extern void bta_sys_notify_collision (BD_ADDR_PTR p_bda);
+
+#if ( BTM_EIR_SERVER_INCLUDED == TRUE )&&(BTA_EIR_CANNED_UUID_LIST != TRUE)
+extern void bta_sys_eir_register(tBTA_SYS_EIR_CBACK * p_cback);
+extern void bta_sys_add_uuid(UINT16 uuid16);
+extern void bta_sys_remove_uuid(UINT16 uuid16);
+#else
+#define bta_sys_eir_register(ut)
+#define bta_sys_add_uuid(ut)
+#define bta_sys_remove_uuid(ut)
+#endif
+
+extern void bta_sys_set_policy (UINT8 id, UINT8 policy, BD_ADDR peer_addr);
+extern void bta_sys_clear_policy (UINT8 id, UINT8 policy, BD_ADDR peer_addr);
+extern void bta_sys_set_default_policy (UINT8 id, UINT8 policy);
+extern void bta_sys_clear_default_policy (UINT8 id, UINT8 policy);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_SYS_H */
diff --git a/bta/sys/bta_sys_cfg.c b/bta/sys/bta_sys_cfg.c
new file mode 100644
index 0000000..4d102ef
--- /dev/null
+++ b/bta/sys/bta_sys_cfg.c
@@ -0,0 +1,42 @@
+/*****************************************************************************
+**
+** Name: bta_sys_cfg.c
+**
+** Description: This file contains compile-time configurable constants
+** for the BTA system manager.
+**
+** Copyright (c) 2003, Widcomm Inc., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+#include "gki.h"
+#include "bta_sys.h"
+
+/* GKI task mailbox event for BTA. */
+#ifndef BTA_MBOX_EVT
+#define BTA_MBOX_EVT TASK_MBOX_2_EVT_MASK
+#endif
+
+/* GKI task mailbox for BTA. */
+#ifndef BTA_MBOX
+#define BTA_MBOX TASK_MBOX_2
+#endif
+
+/* GKI timer id used for protocol timer for BTA. */
+#ifndef BTA_TIMER
+#define BTA_TIMER TIMER_1
+#endif
+
+const tBTA_SYS_CFG bta_sys_cfg =
+{
+ BTA_MBOX_EVT, /* GKI mailbox event */
+ BTA_MBOX, /* GKI mailbox id */
+ BTA_TIMER, /* GKI timer id */
+ BT_TRACE_LEVEL_DEBUG //TODO: Fix this - APPL_INITIAL_TRACE_LEVEL /* initial trace level */
+};
+
+tBTA_SYS_CFG *p_bta_sys_cfg = (tBTA_SYS_CFG *)&bta_sys_cfg;
+
+
diff --git a/bta/sys/bta_sys_ci.c b/bta/sys/bta_sys_ci.c
new file mode 100644
index 0000000..d8ef532
--- /dev/null
+++ b/bta/sys/bta_sys_ci.c
@@ -0,0 +1,65 @@
+/*****************************************************************************
+**
+** Name: bta_sys_ci.c
+**
+** Description: This is the implementation file for BTA system call-in
+** functions.
+**
+** Copyright (c) 2010, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bta_sys.h"
+#include "bta_sys_ci.h"
+
+
+/*******************************************************************************
+**
+** Function bta_sys_hw_ci_enabled
+**
+** Description This function must be called in response to function
+** bta_sys_hw_enable_co(), when HW is indeed enabled
+**
+**
+** Returns void
+**
+*******************************************************************************/
+ void bta_sys_hw_ci_enabled(tBTA_SYS_HW_MODULE module )
+
+{
+ tBTA_SYS_HW_MSG *p_msg;
+
+ if ((p_msg = (tBTA_SYS_HW_MSG *) GKI_getbuf(sizeof(tBTA_SYS_HW_MSG))) != NULL)
+ {
+ p_msg->hdr.event = BTA_SYS_EVT_ENABLED_EVT;
+ p_msg->hw_module = module;
+
+ bta_sys_sendmsg(p_msg);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_sys_hw_ci_disabled
+**
+** Description This function must be called in response to function
+** bta_sys_hw_disable_co() when HW is really OFF
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_sys_hw_ci_disabled( tBTA_SYS_HW_MODULE module )
+{
+ tBTA_SYS_HW_MSG *p_msg;
+
+ if ((p_msg = (tBTA_SYS_HW_MSG *) GKI_getbuf(sizeof(tBTA_SYS_HW_MSG))) != NULL)
+ {
+ p_msg->hdr.event = BTA_SYS_EVT_DISABLED_EVT;
+ p_msg->hw_module = module;
+
+ bta_sys_sendmsg(p_msg);
+ }
+}
+
diff --git a/bta/sys/bta_sys_conn.c b/bta/sys/bta_sys_conn.c
new file mode 100644
index 0000000..63e9fc6
--- /dev/null
+++ b/bta/sys/bta_sys_conn.c
@@ -0,0 +1,565 @@
+/*****************************************************************************
+**
+** Name: bta_sys_conn.c
+**
+** Description: Routes connection status callbacks from various sub systems
+** to DM
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bta_api.h"
+#include "bta_sys.h"
+#include "bta_sys_int.h"
+#include "gki.h"
+
+
+/*******************************************************************************
+**
+** Function bta_sys_rm_register
+**
+** Description Called by BTA DM to register role management callbacks
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_sys_rm_register(tBTA_SYS_CONN_CBACK * p_cback)
+{
+ bta_sys_cb.prm_cb = p_cback;
+}
+
+
+/*******************************************************************************
+**
+** Function bta_sys_policy_register
+**
+** Description Called by BTA DM to register link policy change callbacks
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_sys_policy_register(tBTA_SYS_CONN_CBACK * p_cback)
+{
+ bta_sys_cb.p_policy_cb = p_cback;
+}
+
+/*******************************************************************************
+**
+** Function bta_sys_role_chg_register
+**
+** Description Called by BTA AV to register role change callbacks
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_sys_role_chg_register(tBTA_SYS_CONN_CBACK * p_cback)
+{
+ bta_sys_cb.p_role_cb = p_cback;
+}
+/*******************************************************************************
+**
+** Function bta_sys_ssr_cfg_register
+**
+** Description Called by BTA DM to register SSR configuration callback
+**
+**
+** Returns void
+**
+*******************************************************************************/
+#if (BTM_SSR_INCLUDED == TRUE)
+void bta_sys_ssr_cfg_register(tBTA_SYS_SSR_CFG_CBACK * p_cback)
+{
+ bta_sys_cb.p_ssr_cb = p_cback;
+}
+#endif
+/*******************************************************************************
+**
+** Function bta_sys_role_chg_register
+**
+** Description Called by BTA AV to register role change callbacks
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_sys_notify_role_chg(BD_ADDR_PTR p_bda, UINT8 new_role, UINT8 hci_status)
+{
+ if (bta_sys_cb.p_role_cb)
+ {
+ bta_sys_cb.p_role_cb(BTA_SYS_ROLE_CHANGE, new_role, hci_status, p_bda);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_sys_collision_register
+**
+** Description Called by any BTA module to register for collision event.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_sys_collision_register(UINT8 bta_id, tBTA_SYS_CONN_CBACK *p_cback)
+{
+ UINT8 index;
+
+ for (index = 0; index < MAX_COLLISION_REG; index++)
+ {
+ if ((bta_sys_cb.colli_reg.id[index] == bta_id) ||
+ (bta_sys_cb.colli_reg.id[index] == 0))
+ {
+ bta_sys_cb.colli_reg.id[index] = bta_id;
+ bta_sys_cb.colli_reg.p_coll_cback[index] = p_cback;
+ return;
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_sys_notify_collision
+**
+** Description Called by BTA DM to notify collision event.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_sys_notify_collision (BD_ADDR_PTR p_bda)
+{
+ UINT8 index;
+
+ for (index = 0; index < MAX_COLLISION_REG; index++)
+ {
+ if ((bta_sys_cb.colli_reg.id[index] != 0) &&
+ (bta_sys_cb.colli_reg.p_coll_cback[index] != NULL))
+ {
+ bta_sys_cb.colli_reg.p_coll_cback[index] (0, BTA_ID_SYS, 0, p_bda);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_sys_sco_register
+**
+** Description Called by BTA AV to register sco connection change callbacks
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_sys_sco_register(tBTA_SYS_CONN_CBACK * p_cback)
+{
+ bta_sys_cb.p_sco_cb = p_cback;
+}
+
+/*******************************************************************************
+**
+** Function bta_sys_pm_register
+**
+** Description Called by BTA DM to register power management callbacks
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_sys_pm_register(tBTA_SYS_CONN_CBACK * p_cback)
+{
+ bta_sys_cb.ppm_cb = p_cback;
+}
+
+/*******************************************************************************
+**
+** Function bta_sys_conn_open
+**
+** Description Called by BTA subsystems when a connection is made to
+** the service
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_sys_conn_open(UINT8 id, UINT8 app_id, BD_ADDR peer_addr)
+{
+ if(bta_sys_cb.prm_cb)
+ {
+
+ bta_sys_cb.prm_cb(BTA_SYS_CONN_OPEN, id, app_id, peer_addr);
+
+ }
+
+ if(bta_sys_cb.ppm_cb)
+ {
+
+ bta_sys_cb.ppm_cb(BTA_SYS_CONN_OPEN, id, app_id, peer_addr);
+
+ }
+}
+
+
+
+/*******************************************************************************
+**
+** Function bta_sys_conn_close
+**
+** Description Called by BTA subsystems when a connection to the service
+** is closed
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_sys_conn_close(UINT8 id, UINT8 app_id, BD_ADDR peer_addr)
+{
+ if(bta_sys_cb.prm_cb)
+ {
+
+ bta_sys_cb.prm_cb(BTA_SYS_CONN_CLOSE, id, app_id, peer_addr);
+
+ }
+
+ if(bta_sys_cb.ppm_cb)
+ {
+
+ bta_sys_cb.ppm_cb(BTA_SYS_CONN_CLOSE, id, app_id, peer_addr);
+
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function bta_sys_app_open
+**
+** Description Called by BTA subsystems when application initiates connection
+** to a peer device
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_sys_app_open(UINT8 id, UINT8 app_id, BD_ADDR peer_addr)
+{
+ if(bta_sys_cb.ppm_cb)
+ {
+ bta_sys_cb.ppm_cb(BTA_SYS_APP_OPEN, id, app_id, peer_addr);
+ }
+}
+
+
+
+/*******************************************************************************
+**
+** Function bta_sys_app_close
+**
+** Description Called by BTA subsystems when application initiates close
+** of connection to peer device
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_sys_app_close(UINT8 id, UINT8 app_id, BD_ADDR peer_addr)
+{
+ if(bta_sys_cb.ppm_cb)
+ {
+ bta_sys_cb.ppm_cb(BTA_SYS_APP_CLOSE, id, app_id, peer_addr);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function bta_sys_sco_open
+**
+** Description Called by BTA subsystems when sco connection for that service
+** is open
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_sys_sco_open(UINT8 id, UINT8 app_id, BD_ADDR peer_addr)
+{
+ /* AG triggers p_sco_cb by bta_sys_sco_use. */
+ if((id != BTA_ID_AG) && (bta_sys_cb.p_sco_cb))
+ {
+ /* without querying BTM_GetNumScoLinks() */
+ bta_sys_cb.p_sco_cb(BTA_SYS_SCO_OPEN, 1, app_id, peer_addr);
+ }
+
+ if(bta_sys_cb.ppm_cb)
+ {
+ bta_sys_cb.ppm_cb(BTA_SYS_SCO_OPEN, id, app_id, peer_addr);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_sys_sco_close
+**
+** Description Called by BTA subsystems when sco connection for that service
+** is closed
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_sys_sco_close(UINT8 id, UINT8 app_id, BD_ADDR peer_addr)
+{
+ UINT8 num_sco_links;
+
+ if((id != BTA_ID_AG) && (bta_sys_cb.p_sco_cb))
+ {
+ num_sco_links = BTM_GetNumScoLinks();
+ bta_sys_cb.p_sco_cb(BTA_SYS_SCO_CLOSE, num_sco_links, app_id, peer_addr);
+ }
+
+ if(bta_sys_cb.ppm_cb)
+ {
+ bta_sys_cb.ppm_cb(BTA_SYS_SCO_CLOSE, id, app_id, peer_addr);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_sys_sco_use
+**
+** Description Called by BTA subsystems when that service needs to use sco.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_sys_sco_use(UINT8 id, UINT8 app_id, BD_ADDR peer_addr)
+{
+ /* AV streaming need to be suspended before SCO is connected. */
+ if(bta_sys_cb.p_sco_cb)
+ {
+ /* without querying BTM_GetNumScoLinks() */
+ bta_sys_cb.p_sco_cb(BTA_SYS_SCO_OPEN, 1, app_id, peer_addr);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_sys_sco_unuse
+**
+** Description Called by BTA subsystems when sco connection for that service
+** is no longer needed.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_sys_sco_unuse(UINT8 id, UINT8 app_id, BD_ADDR peer_addr)
+{
+ UINT8 num_sco_links;
+
+ if((bta_sys_cb.p_sco_cb))
+ {
+ num_sco_links = BTM_GetNumScoLinks();
+ bta_sys_cb.p_sco_cb(BTA_SYS_SCO_CLOSE, num_sco_links, app_id, peer_addr);
+ }
+}
+/*******************************************************************************
+**
+** Function bta_sys_chg_ssr_config
+**
+** Description Called by BTA subsystems to indicate that the given app SSR setting
+** need to be changed.
+**
+** Returns void
+**
+*******************************************************************************/
+#if (BTM_SSR_INCLUDED == TRUE)
+void bta_sys_chg_ssr_config (UINT8 id, UINT8 app_id, UINT16 max_latency, UINT16 min_tout)
+{
+ if(bta_sys_cb.p_ssr_cb)
+ {
+ bta_sys_cb.p_ssr_cb(id, app_id, max_latency, min_tout);
+ }
+}
+#endif
+/*******************************************************************************
+**
+** Function bta_sys_set_policy
+**
+** Description Called by BTA subsystems to indicate that the given link
+** policy to peer device should be set
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_sys_set_policy (UINT8 id, UINT8 policy, BD_ADDR peer_addr)
+{
+ if(bta_sys_cb.p_policy_cb)
+ {
+ bta_sys_cb.p_policy_cb(BTA_SYS_PLCY_SET, id, policy, peer_addr);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_sys_clear_policy
+**
+** Description Called by BTA subsystems to indicate that the given link
+** policy to peer device should be clear
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_sys_clear_policy (UINT8 id, UINT8 policy, BD_ADDR peer_addr)
+{
+ if(bta_sys_cb.p_policy_cb)
+ {
+ bta_sys_cb.p_policy_cb(BTA_SYS_PLCY_CLR, id, policy, peer_addr);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_sys_set_default_policy
+**
+** Description Called by BTA subsystems to indicate that the given default
+** link policy should be set
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_sys_set_default_policy (UINT8 id, UINT8 policy)
+{
+ if(bta_sys_cb.p_policy_cb)
+ {
+ bta_sys_cb.p_policy_cb(BTA_SYS_PLCY_DEF_SET, id, policy, NULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_sys_clear_default_policy
+**
+** Description Called by BTA subsystems to indicate that the given default
+** link policy should be clear
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_sys_clear_default_policy (UINT8 id, UINT8 policy)
+{
+ if(bta_sys_cb.p_policy_cb)
+ {
+ bta_sys_cb.p_policy_cb(BTA_SYS_PLCY_DEF_CLR, id, policy, NULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_sys_idle
+**
+** Description Called by BTA subsystems to indicate that the connection to
+** peer device is idle
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_sys_idle(UINT8 id, UINT8 app_id, BD_ADDR peer_addr)
+{
+
+ if(bta_sys_cb.prm_cb)
+ {
+
+ bta_sys_cb.prm_cb(BTA_SYS_CONN_IDLE, id, app_id, peer_addr);
+
+ }
+
+ if(bta_sys_cb.ppm_cb)
+ {
+
+ bta_sys_cb.ppm_cb(BTA_SYS_CONN_IDLE, id, app_id, peer_addr);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_sys_busy
+**
+** Description Called by BTA subsystems to indicate that the connection to
+** peer device is busy
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_sys_busy(UINT8 id, UINT8 app_id, BD_ADDR peer_addr)
+{
+ if(bta_sys_cb.prm_cb)
+ {
+
+ bta_sys_cb.prm_cb(BTA_SYS_CONN_BUSY, id, app_id, peer_addr);
+
+ }
+
+ if(bta_sys_cb.ppm_cb)
+ {
+
+ bta_sys_cb.ppm_cb(BTA_SYS_CONN_BUSY, id, app_id, peer_addr);
+
+ }
+}
+
+#if ( BTM_EIR_SERVER_INCLUDED == TRUE )&&(BTA_EIR_CANNED_UUID_LIST != TRUE)
+/*******************************************************************************
+**
+** Function bta_sys_eir_register
+**
+** Description Called by BTA DM to register EIR utility function that can be
+** used by the other BTA modules to add/remove UUID.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_sys_eir_register(tBTA_SYS_EIR_CBACK * p_cback)
+{
+ bta_sys_cb.eir_cb = p_cback;
+}
+
+/*******************************************************************************
+**
+** Function bta_sys_add_uuid
+**
+** Description Called by BTA subsystems to indicate to DM that new service
+** class UUID is added.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_sys_add_uuid(UINT16 uuid16)
+{
+ if(bta_sys_cb.eir_cb)
+ {
+ bta_sys_cb.eir_cb(uuid16, TRUE );
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_sys_remove_uuid
+**
+** Description Called by BTA subsystems to indicate to DM that the service
+** class UUID is removed.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_sys_remove_uuid(UINT16 uuid16)
+{
+ if(bta_sys_cb.eir_cb)
+ {
+ bta_sys_cb.eir_cb(uuid16, FALSE);
+ }
+}
+#endif
+
diff --git a/bta/sys/bta_sys_int.h b/bta/sys/bta_sys_int.h
new file mode 100644
index 0000000..ac54453
--- /dev/null
+++ b/bta/sys/bta_sys_int.h
@@ -0,0 +1,107 @@
+/*****************************************************************************
+**
+** Name: bta_sys_int.h
+**
+** Description: This is the private interface file for the BTA system
+** manager.
+**
+** Copyright (c) 2003-2010, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef BTA_SYS_INT_H
+#define BTA_SYS_INT_H
+
+#include "ptim.h"
+
+/*****************************************************************************
+** Constants and data types
+*****************************************************************************/
+
+/*****************************************************************************
+** state table
+*****************************************************************************/
+
+/* SYS HW state */
+enum
+{
+ BTA_SYS_HW_OFF,
+ BTA_SYS_HW_STARTING,
+ BTA_SYS_HW_ON,
+ BTA_SYS_HW_STOPPING
+};
+typedef UINT8 tBTA_SYS_HW_STATE;
+
+/* Collision callback */
+#define MAX_COLLISION_REG 5
+
+typedef struct
+{
+ UINT8 id[MAX_COLLISION_REG];
+ tBTA_SYS_CONN_CBACK *p_coll_cback[MAX_COLLISION_REG];
+} tBTA_SYS_COLLISION;
+
+/* system manager control block */
+typedef struct
+{
+ tBTA_SYS_REG *reg[BTA_ID_MAX]; /* registration structures */
+ BOOLEAN is_reg[BTA_ID_MAX]; /* registration structures */
+ tPTIM_CB ptim_cb; /* protocol timer list */
+ BOOLEAN timers_disabled; /* TRUE if sys timers disabled */
+ UINT8 task_id; /* GKI task id */
+ tBTA_SYS_HW_STATE state;
+ tBTA_SYS_HW_CBACK *sys_hw_cback[BTA_SYS_MAX_HW_MODULES]; /* enable callback for each HW modules */
+ UINT32 sys_hw_module_active; /* bitmask of all active modules */
+ UINT16 sys_features; /* Bitmask of sys features */
+
+ tBTA_SYS_CONN_CBACK *prm_cb; /* role management callback registered by DM */
+ tBTA_SYS_CONN_CBACK *ppm_cb; /* low power management callback registered by DM */
+ tBTA_SYS_CONN_CBACK *p_policy_cb; /* link policy change callback registered by DM */
+ tBTA_SYS_CONN_CBACK *p_sco_cb; /* SCO connection change callback registered by AV */
+ tBTA_SYS_CONN_CBACK *p_role_cb; /* role change callback registered by AV */
+ tBTA_SYS_COLLISION colli_reg; /* collision handling module */
+#if ( BTM_EIR_SERVER_INCLUDED == TRUE )&&(BTA_EIR_CANNED_UUID_LIST != TRUE)
+ tBTA_SYS_EIR_CBACK *eir_cb; /* add/remove UUID into EIR */
+#endif
+#if (BTM_SSR_INCLUDED == TRUE)
+ tBTA_SYS_SSR_CFG_CBACK *p_ssr_cb;
+#endif
+} tBTA_SYS_CB;
+
+
+
+
+/*****************************************************************************
+** Global variables
+*****************************************************************************/
+
+/* system manager control block */
+#if BTA_DYNAMIC_MEMORY == FALSE
+extern tBTA_SYS_CB bta_sys_cb;
+#else
+extern tBTA_SYS_CB *bta_sys_cb_ptr;
+#define bta_sys_cb (*bta_sys_cb_ptr)
+#endif
+
+
+/* system manager configuration structure */
+extern tBTA_SYS_CFG *p_bta_sys_cfg;
+
+
+
+/* functions used for BTA SYS HW state machine */
+void bta_sys_hw_btm_cback( tBTM_DEV_STATUS status );
+void bta_sys_hw_error(tBTA_SYS_HW_MSG *p_sys_hw_msg);
+void bta_sys_hw_api_enable( tBTA_SYS_HW_MSG *p_sys_hw_msg );
+void bta_sys_hw_api_disable(tBTA_SYS_HW_MSG *p_sys_hw_msg);
+void bta_sys_hw_evt_enabled(tBTA_SYS_HW_MSG *p_sys_hw_msg);
+void bta_sys_hw_evt_disabled(tBTA_SYS_HW_MSG *p_sys_hw_msg);
+void bta_sys_hw_evt_stack_enabled(tBTA_SYS_HW_MSG *p_sys_hw_msg);
+
+BOOLEAN bta_sys_sm_execute(BT_HDR *p_msg);
+
+
+
+
+
+#endif /* BTA_SYS_INT_H */
diff --git a/bta/sys/bta_sys_main.c b/bta/sys/bta_sys_main.c
new file mode 100644
index 0000000..2b54289
--- /dev/null
+++ b/bta/sys/bta_sys_main.c
@@ -0,0 +1,728 @@
+/*****************************************************************************
+**
+** Name: bta_sys_main.c
+**
+** Description: This is the main implementation file for the BTA
+** system manager.
+**
+** Copyright (c) 2003-2010, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "btm_api.h"
+#include "bta_api.h"
+#include "bta_sys.h"
+#include "bta_sys_int.h"
+#include "bta_sys_ci.h"
+#include "bta_sys_co.h"
+#if BTA_FM_INCLUDED == TRUE
+#include "bta_fm_api.h"
+#endif
+#if BTA_FMTX_INCLUDED == TRUE
+#include "bta_fmtx_api.h"
+#endif
+#if GPS_INCLUDED == TRUE
+#include "bta_gps_api.h"
+#endif
+
+#include "gki.h"
+#include "ptim.h"
+#include <string.h>
+#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
+#include "bta_ar_api.h"
+#endif
+
+/* protocol timer update period, in milliseconds */
+#ifndef BTA_SYS_TIMER_PERIOD
+#define BTA_SYS_TIMER_PERIOD 1000
+#endif
+
+/* system manager control block definition */
+#if BTA_DYNAMIC_MEMORY == FALSE
+tBTA_SYS_CB bta_sys_cb;
+#endif
+
+/* trace level */
+/* TODO Bluedroid - Hard-coded trace levels - Needs to be configurable */
+UINT8 appl_trace_level = BT_TRACE_LEVEL_DEBUG; //APPL_INITIAL_TRACE_LEVEL;
+UINT8 btif_trace_level = BT_TRACE_LEVEL_DEBUG;
+
+static const tBTA_SYS_REG bta_sys_hw_reg =
+{
+ bta_sys_sm_execute,
+ NULL
+};
+
+
+/* type for action functions */
+typedef void (*tBTA_SYS_ACTION)(tBTA_SYS_HW_MSG *p_data);
+
+/* action function list */
+const tBTA_SYS_ACTION bta_sys_action[] =
+{
+ /* device manager local device API events - cf bta_sys.h for events */
+ bta_sys_hw_api_enable, /* 0 BTA_SYS_HW_API_ENABLE_EVT */
+ bta_sys_hw_evt_enabled, /* 1 BTA_SYS_HW_EVT_ENABLED_EVT */
+ bta_sys_hw_evt_stack_enabled, /* 2 BTA_SYS_HW_EVT_STACK_ENABLED_EVT */
+ bta_sys_hw_api_disable, /* 3 BTA_SYS_HW_API_DISABLE_EVT */
+ bta_sys_hw_evt_disabled, /* 4 BTA_SYS_HW_EVT_DISABLED_EVT */
+ bta_sys_hw_error /* 5 BTA_SYS_HW_ERROR_EVT */
+};
+
+/* state machine action enumeration list */
+enum
+{
+ /* device manager local device API events */
+ BTA_SYS_HW_API_ENABLE,
+ BTA_SYS_HW_EVT_ENABLED,
+ BTA_SYS_HW_EVT_STACK_ENABLED,
+ BTA_SYS_HW_API_DISABLE,
+ BTA_SYS_HW_EVT_DISABLED,
+ BTA_SYS_HW_ERROR
+};
+
+#define BTA_SYS_NUM_ACTIONS (BTA_SYS_MAX_EVT & 0x00ff)
+#define BTA_SYS_IGNORE BTA_SYS_NUM_ACTIONS
+
+/* state table information */
+#define BTA_SYS_ACTIONS 2 /* number of actions */
+#define BTA_SYS_NEXT_STATE 2 /* position of next state */
+#define BTA_SYS_NUM_COLS 3 /* number of columns in state tables */
+
+
+/* state table for OFF state */
+const UINT8 bta_sys_hw_off[][BTA_SYS_NUM_COLS] =
+{
+/* Event Action 1 Action 2 Next State */
+/* API_ENABLE */ {BTA_SYS_HW_API_ENABLE, BTA_SYS_IGNORE, BTA_SYS_HW_STARTING},
+/* EVT_ENABLED */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE, BTA_SYS_HW_STARTING},
+/* STACK_ENABLED */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE, BTA_SYS_HW_ON},
+/* API_DISABLE */ {BTA_SYS_HW_EVT_DISABLED, BTA_SYS_IGNORE, BTA_SYS_HW_OFF},
+/* EVT_DISABLED */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE, BTA_SYS_HW_OFF},
+/* EVT_ERROR */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE, BTA_SYS_HW_OFF}
+};
+
+const UINT8 bta_sys_hw_starting[][BTA_SYS_NUM_COLS] =
+{
+/* Event Action 1 Action 2 Next State */
+/* API_ENABLE */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE, BTA_SYS_HW_STARTING}, /* wait for completion event */
+/* EVT_ENABLED */ {BTA_SYS_HW_EVT_ENABLED, BTA_SYS_IGNORE, BTA_SYS_HW_STARTING},
+/* STACK_ENABLED */ {BTA_SYS_HW_EVT_STACK_ENABLED, BTA_SYS_IGNORE, BTA_SYS_HW_ON},
+/* API_DISABLE */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE, BTA_SYS_HW_STOPPING}, /* successive disable/enable: change state wait for completion to disable */
+/* EVT_DISABLED */ {BTA_SYS_HW_EVT_DISABLED, BTA_SYS_HW_API_ENABLE, BTA_SYS_HW_STARTING}, /* successive enable/disable: notify, then restart HW */
+/* EVT_ERROR */ {BTA_SYS_HW_ERROR, BTA_SYS_IGNORE, BTA_SYS_HW_ON}
+};
+
+const UINT8 bta_sys_hw_on[][BTA_SYS_NUM_COLS] =
+{
+/* Event Action 1 Action 2 Next State */
+/* API_ENABLE */ {BTA_SYS_HW_API_ENABLE, BTA_SYS_IGNORE, BTA_SYS_HW_ON},
+/* EVT_ENABLED */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE, BTA_SYS_HW_ON},
+/* STACK_ENABLED */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE, BTA_SYS_HW_ON},
+/* API_DISABLE */ {BTA_SYS_HW_API_DISABLE, BTA_SYS_IGNORE, BTA_SYS_HW_ON}, /* don't change the state here, as some other modules might be active */
+/* EVT_DISABLED */ {BTA_SYS_HW_ERROR, BTA_SYS_IGNORE, BTA_SYS_HW_ON},
+/* EVT_ERROR */ {BTA_SYS_HW_ERROR, BTA_SYS_IGNORE, BTA_SYS_HW_ON}
+};
+
+const UINT8 bta_sys_hw_stopping[][BTA_SYS_NUM_COLS] =
+{
+/* Event Action 1 Action 2 Next State */
+/* API_ENABLE */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE, BTA_SYS_HW_STARTING}, /* change state, and wait for completion event to enable */
+/* EVT_ENABLED */ {BTA_SYS_HW_EVT_ENABLED, BTA_SYS_IGNORE, BTA_SYS_HW_STOPPING}, /* successive enable/disable: finish the enable before disabling */
+/* STACK_ENABLED */ {BTA_SYS_HW_EVT_STACK_ENABLED, BTA_SYS_HW_API_DISABLE, BTA_SYS_HW_STOPPING}, /* successive enable/disable: notify, then stop */
+/* API_DISABLE */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE, BTA_SYS_HW_STOPPING}, /* wait for completion event */
+/* EVT_DISABLED */ {BTA_SYS_HW_EVT_DISABLED, BTA_SYS_IGNORE, BTA_SYS_HW_OFF},
+/* EVT_ERROR */ {BTA_SYS_HW_API_DISABLE, BTA_SYS_IGNORE, BTA_SYS_HW_STOPPING}
+};
+
+typedef const UINT8 (*tBTA_SYS_ST_TBL)[BTA_SYS_NUM_COLS];
+
+/* state table */
+const tBTA_SYS_ST_TBL bta_sys_st_tbl[] = {
+ bta_sys_hw_off,
+ bta_sys_hw_starting,
+ bta_sys_hw_on,
+ bta_sys_hw_stopping
+};
+
+/*******************************************************************************
+**
+** Function bta_sys_init
+**
+** Description BTA initialization; called from task initialization.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API void bta_sys_init(void)
+{
+ memset(&bta_sys_cb, 0, sizeof(tBTA_SYS_CB));
+ ptim_init(&bta_sys_cb.ptim_cb, BTA_SYS_TIMER_PERIOD, p_bta_sys_cfg->timer);
+ bta_sys_cb.task_id = GKI_get_taskid();
+ appl_trace_level = p_bta_sys_cfg->trace_level;
+
+ /* register BTA SYS message handler */
+ bta_sys_register( BTA_ID_SYS, &bta_sys_hw_reg);
+
+ /* register for BTM notifications */
+ BTM_RegisterForDeviceStatusNotif ((tBTM_DEV_STATUS_CB*)&bta_sys_hw_btm_cback );
+
+#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
+ bta_ar_init();
+#endif
+
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_sm_execute
+**
+** Description State machine event handling function for DM
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BOOLEAN bta_sys_sm_execute(BT_HDR *p_msg)
+{
+ BOOLEAN freebuf = TRUE;
+ tBTA_SYS_ST_TBL state_table;
+ UINT8 action;
+ int i;
+
+ APPL_TRACE_EVENT2("bta_sys_sm_execute state:%d, event:0x%x", bta_sys_cb.state, p_msg->event);
+
+ /* look up the state table for the current state */
+ state_table = bta_sys_st_tbl[bta_sys_cb.state];
+ /* update state */
+ bta_sys_cb.state = state_table[p_msg->event & 0x00ff][BTA_SYS_NEXT_STATE];
+
+ /* execute action functions */
+ for (i = 0; i < BTA_SYS_ACTIONS; i++)
+ {
+ if ((action = state_table[p_msg->event & 0x00ff][i]) != BTA_SYS_IGNORE)
+ {
+ (*bta_sys_action[action])( (tBTA_SYS_HW_MSG*) p_msg);
+ }
+ else
+ {
+ break;
+ }
+ }
+ return freebuf;
+
+}
+
+
+void bta_sys_hw_register( tBTA_SYS_HW_MODULE module, tBTA_SYS_HW_CBACK *cback)
+{
+ bta_sys_cb.sys_hw_cback[module]=cback;
+}
+
+
+void bta_sys_hw_unregister( tBTA_SYS_HW_MODULE module )
+{
+ bta_sys_cb.sys_hw_cback[module]=NULL;
+}
+
+/*******************************************************************************
+**
+** Function bta_sys_hw_btm_cback
+**
+** Description This function is registered by BTA SYS to BTM in order to get status notifications
+**
+**
+** Returns
+**
+*******************************************************************************/
+void bta_sys_hw_btm_cback( tBTM_DEV_STATUS status )
+{
+
+ tBTA_SYS_HW_MSG *sys_event;
+
+ APPL_TRACE_DEBUG1(" bta_sys_hw_btm_cback was called with parameter: %i" , status );
+
+ /* send a message to BTA SYS */
+ if ((sys_event = (tBTA_SYS_HW_MSG *) GKI_getbuf(sizeof(tBTA_SYS_HW_MSG))) != NULL)
+ {
+ if (status == BTM_DEV_STATUS_UP)
+ sys_event->hdr.event = BTA_SYS_EVT_STACK_ENABLED_EVT;
+ else if (status == BTM_DEV_STATUS_DOWN)
+ sys_event->hdr.event = BTA_SYS_ERROR_EVT;
+ else
+ {
+ /* BTM_DEV_STATUS_CMD_TOUT is ignored for now. */
+ GKI_freebuf (sys_event);
+ sys_event = NULL;
+ }
+
+ if (sys_event)
+ {
+ bta_sys_sendmsg(sys_event);
+ }
+ }
+ else
+ {
+ APPL_TRACE_DEBUG0("ERROR bta_sys_hw_btm_cback couldn't send msg" );
+ }
+}
+
+
+
+/*******************************************************************************
+**
+** Function bta_sys_hw_error
+**
+** Description In case the HW device stops answering... Try to turn it off, then re-enable all
+** previously active SW modules.
+**
+** Returns success or failure
+**
+*******************************************************************************/
+void bta_sys_hw_error(tBTA_SYS_HW_MSG *p_sys_hw_msg)
+{
+
+ UINT8 module_index;
+
+ for (module_index = 0; module_index < BTA_SYS_MAX_HW_MODULES; module_index++)
+ {
+ if( bta_sys_cb.sys_hw_module_active & ((UINT32)1 << module_index ))
+ switch( module_index)
+ {
+
+ case BTA_SYS_HW_BLUETOOTH:
+ BTA_DisableBluetooth();
+ break;
+ default:
+ /* not yet supported */
+ break;
+ }
+ }
+
+ /* turn everything OFF, then re-start the modules that were ON. Let the state machine handle all this... */
+
+ for (module_index = 0; module_index < BTA_SYS_MAX_HW_MODULES; module_index++)
+ {
+ if( bta_sys_cb.sys_hw_module_active & ((UINT32)1 << module_index ))
+ switch( module_index)
+ {
+
+ case BTA_SYS_HW_BLUETOOTH:
+ BTA_EnableBluetooth(NULL);
+ break;
+ default:
+ /* not yet supported */
+ break;
+ }
+ }
+
+
+
+
+
+}
+
+
+
+/*******************************************************************************
+**
+** Function bta_sys_hw_enable
+**
+** Description this function is called after API enable and HW has been turned on
+**
+**
+** Returns success or failure
+**
+*******************************************************************************/
+
+void bta_sys_hw_api_enable( tBTA_SYS_HW_MSG *p_sys_hw_msg )
+{
+ if ((!bta_sys_cb.sys_hw_module_active) && (bta_sys_cb.state != BTA_SYS_HW_ON))
+ {
+ /* register which HW module was turned on */
+ bta_sys_cb.sys_hw_module_active |= ((UINT32)1 << p_sys_hw_msg->hw_module );
+
+ /* use call-out to power-up HW */
+ bta_sys_hw_co_enable(p_sys_hw_msg->hw_module);
+ }
+ else
+ {
+ /* register which HW module was turned on */
+ bta_sys_cb.sys_hw_module_active |= ((UINT32)1 << p_sys_hw_msg->hw_module );
+
+ /* HW already in use, so directly notify the caller */
+ if (bta_sys_cb.sys_hw_cback[p_sys_hw_msg->hw_module ]!= NULL )
+ bta_sys_cb.sys_hw_cback[p_sys_hw_msg->hw_module ]( BTA_SYS_HW_ON_EVT );
+ }
+
+ APPL_TRACE_EVENT2 ("bta_sys_hw_api_enable for %d, active modules 0x%04X",
+ p_sys_hw_msg->hw_module, bta_sys_cb.sys_hw_module_active);
+
+}
+
+/*******************************************************************************
+**
+** Function bta_sys_hw_disable
+**
+** Description if no other module is using the HW, this function will call ( if defined ) a user-macro to turn off the HW
+**
+**
+** Returns success or failure
+**
+*******************************************************************************/
+void bta_sys_hw_api_disable(tBTA_SYS_HW_MSG *p_sys_hw_msg)
+{
+ APPL_TRACE_DEBUG2("bta_sys_hw_api_disable for %d, active modules: 0x%04X",
+ p_sys_hw_msg->hw_module, bta_sys_cb.sys_hw_module_active );
+
+ /* make sure the related SW blocks were stopped */
+ bta_sys_disable( p_sys_hw_msg->hw_module );
+
+
+ /* register which module we turn off */
+ bta_sys_cb.sys_hw_module_active &= ~((UINT32)1 << p_sys_hw_msg->hw_module );
+
+
+ /* if there are still some SW modules using the HW, just provide an answer to the calling */
+ if( bta_sys_cb.sys_hw_module_active != 0 )
+ {
+ /* if there are still some SW modules using the HW, directly notify the caller */
+ if( bta_sys_cb.sys_hw_cback[p_sys_hw_msg->hw_module ]!= NULL )
+ bta_sys_cb.sys_hw_cback[p_sys_hw_msg->hw_module ]( BTA_SYS_HW_OFF_EVT );
+ }
+ else
+ {
+ /* manually update the state of our system */
+ bta_sys_cb.state = BTA_SYS_HW_STOPPING;
+ /* and use the call-out to disable HW */
+ bta_sys_hw_co_disable(p_sys_hw_msg->hw_module);
+ }
+
+}
+
+
+/*******************************************************************************
+**
+** Function bta_sys_hw_event_enabled
+**
+** Description
+**
+**
+** Returns success or failure
+**
+*******************************************************************************/
+void bta_sys_hw_evt_enabled(tBTA_SYS_HW_MSG *p_sys_hw_msg)
+{
+ APPL_TRACE_EVENT1("bta_sys_hw_evt_enabled for %i", p_sys_hw_msg->hw_module);
+
+#if ( defined BTM_AUTOMATIC_HCI_RESET && BTM_AUTOMATIC_HCI_RESET == TRUE )
+ /* If device is already up, send a fake "BTM DEVICE UP" using BTA SYS state machine */
+ /* If we are in the middle device initialization, BTM_DEVICE_UP will be issued */
+ /* by BTM once initialization is done. */
+ if (BTA_DmIsDeviceUp())
+ {
+ bta_sys_hw_btm_cback (BTM_DEV_STATUS_UP);
+ }
+#else
+
+ /* if HCI reset was not sent during stack start-up */
+ BTM_DeviceReset( NULL );
+
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function bta_sys_hw_event_disabled
+**
+** Description
+**
+**
+** Returns success or failure
+**
+*******************************************************************************/
+void bta_sys_hw_evt_disabled(tBTA_SYS_HW_MSG *p_sys_hw_msg)
+{
+ UINT8 hw_module_index;
+
+ APPL_TRACE_DEBUG1("bta_sys_hw_evt_disabled - module 0x%X", p_sys_hw_msg->hw_module);
+
+ for (hw_module_index = 0; hw_module_index < BTA_SYS_MAX_HW_MODULES; hw_module_index++)
+ {
+ if (bta_sys_cb.sys_hw_cback[hw_module_index] != NULL)
+ bta_sys_cb.sys_hw_cback[hw_module_index] (BTA_SYS_HW_OFF_EVT);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_sys_hw_event_stack_enabled
+**
+** Description we receive this event from once the SW side is ready ( stack, FW download,... ),
+** i.e. we can really start using the device. So notify the app.
+**
+** Returns success or failure
+**
+*******************************************************************************/
+void bta_sys_hw_evt_stack_enabled(tBTA_SYS_HW_MSG *p_sys_hw_msg)
+{
+ UINT8 hw_module_index;
+
+ APPL_TRACE_DEBUG0(" bta_sys_hw_evt_stack_enabled!notify the callers");
+
+ for (hw_module_index = 0; hw_module_index < BTA_SYS_MAX_HW_MODULES; hw_module_index++ )
+ {
+ if (bta_sys_cb.sys_hw_cback[hw_module_index] != NULL)
+ bta_sys_cb.sys_hw_cback[hw_module_index] (BTA_SYS_HW_ON_EVT);
+ }
+}
+
+
+
+
+/*******************************************************************************
+**
+** Function bta_sys_event
+**
+** Description BTA event handler; called from task event handler.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API void bta_sys_event(BT_HDR *p_msg)
+{
+ UINT8 id;
+ BOOLEAN freebuf = TRUE;
+
+ APPL_TRACE_EVENT1("BTA got event 0x%x", p_msg->event);
+
+ /* get subsystem id from event */
+ id = (UINT8) (p_msg->event >> 8);
+
+ /* verify id and call subsystem event handler */
+ if ((id < BTA_ID_MAX) && (bta_sys_cb.reg[id] != NULL))
+ {
+ freebuf = (*bta_sys_cb.reg[id]->evt_hdlr)(p_msg);
+ }
+ else
+ {
+ APPL_TRACE_WARNING1("BTA got unregistered event id %d", id);
+ }
+
+ if (freebuf)
+ {
+ GKI_freebuf(p_msg);
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function bta_sys_timer_update
+**
+** Description Update the BTA timer list and handle expired timers.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API void bta_sys_timer_update(void)
+{
+ if (!bta_sys_cb.timers_disabled)
+ {
+ ptim_timer_update(&bta_sys_cb.ptim_cb);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_sys_register
+**
+** Description Called by other BTA subsystems to register their event
+** handler.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_sys_register(UINT8 id, const tBTA_SYS_REG *p_reg)
+{
+ bta_sys_cb.reg[id] = (tBTA_SYS_REG *) p_reg;
+ bta_sys_cb.is_reg[id] = TRUE;
+}
+
+/*******************************************************************************
+**
+** Function bta_sys_deregister
+**
+** Description Called by other BTA subsystems to de-register
+** handler.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_sys_deregister(UINT8 id)
+{
+ bta_sys_cb.is_reg[id] = FALSE;
+}
+
+/*******************************************************************************
+**
+** Function bta_sys_is_register
+**
+** Description Called by other BTA subsystems to get registeration
+** status.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BOOLEAN bta_sys_is_register(UINT8 id)
+{
+ return bta_sys_cb.is_reg[id];
+}
+
+/*******************************************************************************
+**
+** Function bta_sys_sendmsg
+**
+** Description Send a GKI message to BTA. This function is designed to
+** optimize sending of messages to BTA. It is called by BTA
+** API functions and call-in functions.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_sys_sendmsg(void *p_msg)
+{
+ GKI_send_msg(bta_sys_cb.task_id, p_bta_sys_cfg->mbox, p_msg);
+}
+
+/*******************************************************************************
+**
+** Function bta_sys_start_timer
+**
+** Description Start a protocol timer for the specified amount
+** of time in milliseconds.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_sys_start_timer(TIMER_LIST_ENT *p_tle, UINT16 type, INT32 timeout)
+{
+ ptim_start_timer(&bta_sys_cb.ptim_cb, p_tle, type, timeout);
+}
+
+/*******************************************************************************
+**
+** Function bta_sys_stop_timer
+**
+** Description Stop a BTA timer.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_sys_stop_timer(TIMER_LIST_ENT *p_tle)
+{
+ ptim_stop_timer(&bta_sys_cb.ptim_cb, p_tle);
+}
+
+/*******************************************************************************
+**
+** Function bta_sys_disable
+**
+** Description For each registered subsystem execute its disable function.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_sys_disable(tBTA_SYS_HW_MODULE module)
+{
+ int bta_id = 0;
+ int bta_id_max = 0;
+
+ APPL_TRACE_DEBUG1("bta_sys_disable: module %i", module);
+
+ switch( module )
+ {
+ case BTA_SYS_HW_BLUETOOTH:
+ bta_id = BTA_ID_DM;
+ bta_id_max = BTA_ID_BLUETOOTH_MAX;
+ break;
+ case BTA_SYS_HW_FMRX:
+ bta_id = BTA_ID_FM;
+ bta_id_max = BTA_ID_FM;
+ break;
+ case BTA_SYS_HW_FMTX:
+ bta_id = BTA_ID_FMTX;
+ bta_id_max = BTA_ID_FMTX;
+ break;
+ case BTA_SYS_HW_GPS:
+ bta_id = BTA_ID_GPS;
+ bta_id_max = BTA_ID_GPS;
+ break;
+ default:
+ APPL_TRACE_WARNING0("bta_sys_disable: unkown module");
+ return;
+ }
+
+ for ( ; bta_id <= bta_id_max; bta_id++)
+ {
+ if (bta_sys_cb.reg[bta_id] != NULL)
+ {
+ if (bta_sys_cb.is_reg[bta_id] == TRUE && bta_sys_cb.reg[bta_id]->disable != NULL)
+ {
+ (*bta_sys_cb.reg[bta_id]->disable)();
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_sys_disable_timers
+**
+** Description Disable sys timer event handling
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_sys_disable_timers(void)
+{
+ bta_sys_cb.timers_disabled = TRUE;
+}
+
+/*******************************************************************************
+**
+** Function bta_sys_set_trace_level
+**
+** Description Set trace level for BTA
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_sys_set_trace_level(UINT8 level)
+{
+ appl_trace_level = level;
+}
+
+/*******************************************************************************
+**
+** Function bta_sys_get_sys_features
+**
+** Description Returns sys_features to other BTA modules.
+**
+** Returns sys_features
+**
+*******************************************************************************/
+UINT16 bta_sys_get_sys_features (void)
+{
+ return bta_sys_cb.sys_features;
+}
+
+
diff --git a/bta/sys/ptim.c b/bta/sys/ptim.c
new file mode 100644
index 0000000..24ed246
--- /dev/null
+++ b/bta/sys/ptim.c
@@ -0,0 +1,149 @@
+/*****************************************************************************
+**
+** Name: ptim.c
+**
+** Description: Protocol timer services.
+**
+** Copyright (c) 2003-2006, Broadcom Corp., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+#include "gki.h"
+#include "ptim.h"
+#include "bta_sys.h"
+
+/*******************************************************************************
+**
+** Function ptim_init
+**
+** Description Initialize a protocol timer control block. Parameter
+** period is the GKI timer period in milliseconds. Parameter
+** timer_id is the GKI timer id.
+**
+** Returns void
+**
+*******************************************************************************/
+void ptim_init(tPTIM_CB *p_cb, UINT16 period, UINT8 timer_id)
+{
+ GKI_init_timer_list(&p_cb->timer_queue);
+ p_cb->period = period;
+ p_cb->timer_id = timer_id;
+}
+
+/*******************************************************************************
+**
+** Function ptim_timer_update
+**
+** Description Update the protocol timer list and handle expired timers.
+** This function is called from the task running the protocol
+** timers when the periodic GKI timer expires.
+**
+** Returns void
+**
+*******************************************************************************/
+void ptim_timer_update(tPTIM_CB *p_cb)
+{
+ TIMER_LIST_ENT *p_tle;
+ BT_HDR *p_msg;
+ UINT32 new_ticks_count;
+ INT32 period_in_ticks;
+
+ /* To handle the case when the function is called less frequently than the period
+ we must convert determine the number of ticks since the last update, then
+ convert back to milliseconds before updating timer list */
+ new_ticks_count = GKI_get_tick_count();
+
+ /* Check for wrapped condition */
+ if (new_ticks_count >= p_cb->last_gki_ticks)
+ {
+ period_in_ticks = (INT32)(new_ticks_count - p_cb->last_gki_ticks);
+ }
+ else
+ {
+ period_in_ticks = (INT32)(((UINT32)0xffffffff - p_cb->last_gki_ticks)
+ + new_ticks_count + 1);
+ }
+
+ /* update timer list */
+ GKI_update_timer_list(&p_cb->timer_queue, GKI_TICKS_TO_MS(period_in_ticks));
+
+ p_cb->last_gki_ticks = new_ticks_count;
+
+ /* while there are expired timers */
+ while((p_cb->timer_queue.p_first) && (p_cb->timer_queue.p_first->ticks <= 0))
+ {
+ /* removed expired timer from list */
+ p_tle = p_cb->timer_queue.p_first;
+ GKI_remove_from_timer_list(&p_cb->timer_queue, p_tle);
+
+ /* call timer callback */
+ if(p_tle->p_cback)
+ {
+ (*p_tle->p_cback)(p_tle);
+ }
+ else if(p_tle->event)
+ {
+ if ((p_msg = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_msg->event = p_tle->event;
+ p_msg->layer_specific = 0;
+ bta_sys_sendmsg(p_msg);
+ }
+ }
+ }
+
+ /* if timer list is empty stop periodic GKI timer */
+ if (p_cb->timer_queue.p_first == NULL)
+ {
+ GKI_stop_timer(p_cb->timer_id);
+ }
+}
+
+/*******************************************************************************
+**
+** Function ptim_start_timer
+**
+** Description Start a protocol timer for the specified amount
+** of time in seconds.
+**
+** Returns void
+**
+*******************************************************************************/
+void ptim_start_timer(tPTIM_CB *p_cb, TIMER_LIST_ENT *p_tle, UINT16 type, INT32 timeout)
+{
+ /* if timer list is currently empty, start periodic GKI timer */
+ if (p_cb->timer_queue.p_first == NULL)
+ {
+ p_cb->last_gki_ticks = GKI_get_tick_count();
+ GKI_start_timer(p_cb->timer_id, GKI_MS_TO_TICKS(p_cb->period), TRUE);
+ }
+
+ GKI_remove_from_timer_list(&p_cb->timer_queue, p_tle);
+
+ p_tle->event = type;
+ p_tle->ticks = timeout;
+
+ GKI_add_to_timer_list(&p_cb->timer_queue, p_tle);
+}
+
+/*******************************************************************************
+**
+** Function ptim_stop_timer
+**
+** Description Stop a protocol timer.
+**
+** Returns void
+**
+*******************************************************************************/
+void ptim_stop_timer(tPTIM_CB *p_cb, TIMER_LIST_ENT *p_tle)
+{
+ GKI_remove_from_timer_list (&p_cb->timer_queue, p_tle);
+
+ /* if timer list is empty stop periodic GKI timer */
+ if (p_cb->timer_queue.p_first == NULL)
+ {
+ GKI_stop_timer(p_cb->timer_id);
+ }
+}
diff --git a/bta/sys/utl.c b/bta/sys/utl.c
new file mode 100644
index 0000000..1487f2e
--- /dev/null
+++ b/bta/sys/utl.c
@@ -0,0 +1,283 @@
+/*****************************************************************************
+**
+** Name: utl.c
+**
+** Description: This file contains utility functions.
+**
+** Copyright (c) 2003, Widcomm Inc., All Rights Reserved.
+** Widcomm Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include "utl.h"
+#include "gki.h"
+#include "btm_api.h"
+
+/*******************************************************************************
+**
+** Function utl_str2int
+**
+** Description This utility function converts a character string to an
+** integer. Acceptable values in string are 0-9. If invalid
+** string or string value too large, -1 is returned. Leading
+** spaces are skipped.
+**
+**
+** Returns Integer value or -1 on error.
+**
+*******************************************************************************/
+INT16 utl_str2int(const char *p_s)
+{
+ INT32 val = 0;
+
+ for (;*p_s == ' ' && *p_s != 0; p_s++);
+
+ if (*p_s == 0) return -1;
+
+ for (;;)
+ {
+ if ((*p_s < '0') || (*p_s > '9')) return -1;
+
+ val += (INT32) (*p_s++ - '0');
+
+ if (val > 32767) return -1;
+
+ if (*p_s == 0)
+ {
+ return (INT16) val;
+ }
+ else
+ {
+ val *= 10;
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function utl_strucmp
+**
+** Description This utility function compares two strings in uppercase.
+** String p_s must be uppercase. String p_t is converted to
+** uppercase if lowercase. If p_s ends first, the substring
+** match is counted as a match.
+**
+**
+** Returns 0 if strings match, nonzero otherwise.
+**
+*******************************************************************************/
+int utl_strucmp(const char *p_s, const char *p_t)
+{
+ char c;
+
+ while (*p_s && *p_t)
+ {
+ c = *p_t++;
+ if (c >= 'a' && c <= 'z')
+ {
+ c -= 0x20;
+ }
+ if (*p_s++ != c)
+ {
+ return -1;
+ }
+ }
+ /* if p_t hit null first, no match */
+ if (*p_t == 0 && *p_s != 0)
+ {
+ return 1;
+ }
+ /* else p_s hit null first, count as match */
+ else
+ {
+ return 0;
+ }
+}
+
+/*******************************************************************************
+**
+** Function utl_itoa
+**
+** Description This utility function converts a UINT16 to a string. The
+** string is NULL-terminated. The length of the string is
+** returned;
+**
+**
+** Returns Length of string.
+**
+*******************************************************************************/
+UINT8 utl_itoa(UINT16 i, char *p_s)
+{
+ UINT16 j, k;
+ char *p = p_s;
+ BOOLEAN fill = FALSE;
+
+ if (i == 0)
+ {
+ /* take care of zero case */
+ *p++ = '0';
+ }
+ else
+ {
+ for(j = 10000; j > 0; j /= 10)
+ {
+ k = i / j;
+ i %= j;
+ if (k > 0 || fill)
+ {
+ *p++ = k + '0';
+ fill = TRUE;
+ }
+ }
+ }
+ *p = 0;
+ return (UINT8) (p - p_s);
+}
+
+/*******************************************************************************
+**
+** Function utl_freebuf
+**
+** Description This function calls GKI_freebuf to free the buffer passed
+** in, if buffer pointer is not NULL, and also initializes
+** buffer pointer to NULL.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void utl_freebuf(void **p)
+{
+ if (*p != NULL)
+ {
+ GKI_freebuf(*p);
+ *p = NULL;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function utl_set_device_class
+**
+** Description This function updates the local Device Class.
+**
+** Parameters:
+** p_cod - Pointer to the device class to set to
+**
+** cmd - the fields of the device class to update.
+** BTA_UTL_SET_COD_MAJOR_MINOR, - overwrite major, minor class
+** BTA_UTL_SET_COD_SERVICE_CLASS - set the bits in the input
+** BTA_UTL_CLR_COD_SERVICE_CLASS - clear the bits in the input
+** BTA_UTL_SET_COD_ALL - overwrite major, minor, set the bits in service class
+** BTA_UTL_INIT_COD - overwrite major, minor, and service class
+**
+** Returns TRUE if successful, Otherwise FALSE
+**
+*******************************************************************************/
+BOOLEAN utl_set_device_class(tBTA_UTL_COD *p_cod, UINT8 cmd)
+{
+ UINT8 *dev;
+ UINT16 service;
+ UINT8 minor, major;
+ DEV_CLASS dev_class;
+
+ dev = BTM_ReadDeviceClass();
+ BTM_COD_SERVICE_CLASS( service, dev );
+ BTM_COD_MINOR_CLASS(minor, dev );
+ BTM_COD_MAJOR_CLASS(major, dev );
+
+ switch(cmd)
+ {
+ case BTA_UTL_SET_COD_MAJOR_MINOR:
+ minor = p_cod->minor & BTM_COD_MINOR_CLASS_MASK;
+ major = p_cod->major & BTM_COD_MAJOR_CLASS_MASK;
+ break;
+
+ case BTA_UTL_SET_COD_SERVICE_CLASS:
+ /* clear out the bits that is not SERVICE_CLASS bits */
+ p_cod->service &= BTM_COD_SERVICE_CLASS_MASK;
+ service = service | p_cod->service;
+ break;
+
+ case BTA_UTL_CLR_COD_SERVICE_CLASS:
+ p_cod->service &= BTM_COD_SERVICE_CLASS_MASK;
+ service = service & (~p_cod->service);
+ break;
+
+ case BTA_UTL_SET_COD_ALL:
+ minor = p_cod->minor & BTM_COD_MINOR_CLASS_MASK;
+ major = p_cod->major & BTM_COD_MAJOR_CLASS_MASK;
+ p_cod->service &= BTM_COD_SERVICE_CLASS_MASK;
+ service = service | p_cod->service;
+ break;
+
+ case BTA_UTL_INIT_COD:
+ minor = p_cod->minor & BTM_COD_MINOR_CLASS_MASK;
+ major = p_cod->major & BTM_COD_MAJOR_CLASS_MASK;
+ service = p_cod->service & BTM_COD_SERVICE_CLASS_MASK;
+ break;
+
+ default:
+ return FALSE;
+ }
+
+ /* convert the fields into the device class type */
+ FIELDS_TO_COD(dev_class, minor, major, service);
+
+ if (BTM_SetDeviceClass(dev_class) == BTM_SUCCESS)
+ return TRUE;
+
+ return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function utl_isintstr
+**
+** Description This utility function checks if the given string is an
+** integer string or not
+**
+**
+** Returns TRUE if successful, Otherwise FALSE
+**
+*******************************************************************************/
+BOOLEAN utl_isintstr(const char *p_s)
+{
+ UINT16 i = 0;
+
+ for(i=0; p_s[i] != 0; i++)
+ {
+ if(((p_s[i] < '0') || (p_s[i] > '9')) && (p_s[i] != ';'))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*******************************************************************************
+**
+** Function utl_isdialstr
+**
+** Description This utility function checks if the given string contains
+** only dial digits or not
+**
+**
+** Returns TRUE if successful, Otherwise FALSE
+**
+*******************************************************************************/
+BOOLEAN utl_isdialstr(const char *p_s)
+{
+ UINT16 i = 0;
+
+ for(i=0; p_s[i] != 0; i++)
+ {
+ if(!(((p_s[i] >= '0') && (p_s[i] <= '9'))
+ || (p_s[i] == '*') || (p_s[i] == '+') || (p_s[i] == '#') || (p_s[i] == ';')
+ || ((p_s[i] >= 'A') && (p_s[i] <= 'C'))))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
diff --git a/btif/co/bta_ag_co.c b/btif/co/bta_ag_co.c
new file mode 100644
index 0000000..ec1d5bb
--- /dev/null
+++ b/btif/co/bta_ag_co.c
@@ -0,0 +1,161 @@
+/************************************************************************************
+ *
+ * Copyright (C) 2009-2011 Broadcom Corporation
+ *
+ * This program is the proprietary software of Broadcom Corporation and/or its
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
+ *
+ * Except as expressly set forth in the Authorized License,
+ *
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
+ * Broadcom integrated circuit products.
+ *
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT
+ * OF USE OR PERFORMANCE OF THE SOFTWARE.
+ *
+ * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR
+ * ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+ *
+ ************************************************************************************/
+#include "gki.h"
+#include "bta_api.h"
+#include "bta_sys.h"
+#include "bta_ag_api.h"
+#include "bta_ag_co.h"
+#include "bte_appl.h"
+
+#define LOG_TAG "BTA_AG_CO: "
+
+#ifndef LINUX_NATIVE
+#include <cutils/properties.h>
+#include <cutils/log.h>
+#else
+#include <stdio.h>
+#define LOGI(format, ...) fprintf (stdout, LOG_TAG format"\n", ## __VA_ARGS__)
+#define LOGD(format, ...) fprintf (stdout, LOG_TAG format"\n", ## __VA_ARGS__)
+#define LOGV(format, ...) fprintf (stdout, LOG_TAG format"\n", ## __VA_ARGS__)
+#define LOGE(format, ...) fprintf (stderr, LOG_TAG format"\n", ## __VA_ARGS__)
+#endif
+
+
+/*******************************************************************************
+**
+** Function bta_ag_co_init
+**
+** Description This callout function is executed by AG when it is
+** started by calling BTA_AgEnable(). This function can be
+** used by the phone to initialize audio paths or for other
+** initialization purposes.
+**
+**
+** Returns Void.
+**
+*******************************************************************************/
+void bta_ag_co_init(void)
+{
+ BTM_WriteVoiceSettings(AG_VOICE_SETTINGS);
+}
+
+
+/*******************************************************************************
+**
+** Function bta_ag_co_audio_state
+**
+** Description This function is called by the AG before the audio connection
+** is brought up, after it comes up, and after it goes down.
+**
+** Parameters handle - handle of the AG instance
+** state - Audio state
+** BTA_AG_CO_AUD_STATE_OFF - Audio has been turned off
+** BTA_AG_CO_AUD_STATE_OFF_XFER - Audio has been turned off (xfer)
+** BTA_AG_CO_AUD_STATE_ON - Audio has been turned on
+** BTA_AG_CO_AUD_STATE_SETUP - Audio is about to be turned on
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_co_audio_state(UINT16 handle, UINT8 app_id, UINT8 state)
+{
+ BTIF_TRACE_DEBUG2("bta_ag_co_audio_state: handle %d, state %d", handle, state);
+}
+
+
+/*******************************************************************************
+**
+** Function bta_ag_co_data_open
+**
+** Description This function is executed by AG when a service level connection
+** is opened. The phone can use this function to set
+** up data paths or perform any required initialization or
+** set up particular to the connected service.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_co_data_open(UINT16 handle, tBTA_SERVICE_ID service)
+{
+ BTIF_TRACE_DEBUG2("bta_ag_co_data_open handle:%d service:%d", handle, service);
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_co_data_close
+**
+** Description This function is called by AG when a service level
+** connection is closed
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_co_data_close(UINT16 handle)
+{
+ BTIF_TRACE_DEBUG1("bta_ag_co_data_close handle:%d", handle);
+}
+
+
+/*******************************************************************************
+ **
+ ** Function bta_ag_co_tx_write
+ **
+ ** Description This function is called by the AG to send data to the
+ ** phone when the AG is configured for AT command pass-through.
+ ** The implementation of this function must copy the data to
+ ** the phones memory.
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+void bta_ag_co_tx_write(UINT16 handle, UINT8 * p_data, UINT16 len)
+{
+ BTIF_TRACE_DEBUG2( "bta_ag_co_tx_write: handle: %d, len: %d", handle, len );
+}
+
diff --git a/btif/co/bta_dm_co.c b/btif/co/bta_dm_co.c
new file mode 100644
index 0000000..b4c893c
--- /dev/null
+++ b/btif/co/bta_dm_co.c
@@ -0,0 +1,424 @@
+/************************************************************************************
+ *
+ * Copyright (C) 2009-2011 Broadcom Corporation
+ *
+ * This program is the proprietary software of Broadcom Corporation and/or its
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
+ *
+ * Except as expressly set forth in the Authorized License,
+ *
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
+ * Broadcom integrated circuit products.
+ *
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT
+ * OF USE OR PERFORMANCE OF THE SOFTWARE.
+ *
+ * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR
+ * ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+ *
+ ************************************************************************************/
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "bta_api.h"
+#include "bta_sys.h"
+#include "bta_dm_co.h"
+#include "bta_dm_ci.h"
+
+
+/*******************************************************************************
+**
+** Function bta_dm_co_get_compress_memory
+**
+** Description This callout function is executed by DM to get memory for compression
+
+** Parameters id - BTA SYS ID
+** memory_p - memory return by callout
+** memory_size - memory size
+**
+** Returns TRUE for success, FALSE for fail.
+**
+*******************************************************************************/
+BOOLEAN bta_dm_co_get_compress_memory(tBTA_SYS_ID id, UINT8 **memory_p, UINT32 *memory_size)
+{
+ return TRUE;
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_co_io_req
+**
+** Description This callout function is executed by DM to get IO capabilities
+** of the local device for the Simple Pairing process
+**
+** Parameters bd_addr - The peer device
+** *p_io_cap - The local Input/Output capabilities
+** *p_oob_data - TRUE, if OOB data is available for the peer device.
+** *p_auth_req - TRUE, if MITM protection is required.
+**
+** Returns void.
+**
+*******************************************************************************/
+void bta_dm_co_io_req(BD_ADDR bd_addr, tBTA_IO_CAP *p_io_cap, tBTA_OOB_DATA *p_oob_data,
+ tBTA_AUTH_REQ *p_auth_req, BOOLEAN is_orig)
+{
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_co_io_rsp
+**
+** Description This callout function is executed by DM to report IO capabilities
+** of the peer device for the Simple Pairing process
+**
+** Parameters bd_addr - The peer device
+** io_cap - The remote Input/Output capabilities
+** oob_data - TRUE, if OOB data is available for the peer device.
+** auth_req - TRUE, if MITM protection is required.
+**
+** Returns void.
+**
+*******************************************************************************/
+void bta_dm_co_io_rsp(BD_ADDR bd_addr, tBTA_IO_CAP io_cap,
+ tBTA_OOB_DATA oob_data, tBTA_AUTH_REQ auth_req)
+{
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_co_lk_upgrade
+**
+** Description This callout function is executed by DM to check if the
+** platform wants allow link key upgrade
+**
+** Parameters bd_addr - The peer device
+** *p_upgrade - TRUE, if link key upgrade is desired.
+**
+** Returns void.
+**
+*******************************************************************************/
+void bta_dm_co_lk_upgrade(BD_ADDR bd_addr, BOOLEAN *p_upgrade )
+{
+}
+
+#if (BTM_OOB_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function bta_dm_co_loc_oob
+**
+** Description This callout function is executed by DM to report the OOB
+** data of the local device for the Simple Pairing process
+**
+** Parameters valid - TRUE, if the local OOB data is retrieved from LM
+** c - Simple Pairing Hash C
+** r - Simple Pairing Randomnizer R
+**
+** Returns void.
+**
+*******************************************************************************/
+void bta_dm_co_loc_oob(BOOLEAN valid, BT_OCTET16 c, BT_OCTET16 r)
+{
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_co_rmt_oob
+**
+** Description This callout function is executed by DM to request the OOB
+** data for the remote device for the Simple Pairing process
+** Need to call bta_dm_ci_rmt_oob() in response
+**
+** Parameters bd_addr - The peer device
+**
+** Returns void.
+**
+*******************************************************************************/
+void bta_dm_co_rmt_oob(BD_ADDR bd_addr)
+{
+}
+
+#endif /* BTM_OOB_INCLUDED */
+
+
+// REMOVE FOR BLUEDROID ?
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE ) && (BTM_SCO_INCLUDED == TRUE)
+
+/*******************************************************************************
+**
+** Function btui_sco_codec_callback
+**
+** Description Callback for btui codec.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void btui_sco_codec_callback(UINT16 event, UINT16 sco_handle)
+{
+ bta_dm_sco_ci_data_ready(event, sco_handle);
+}
+/*******************************************************************************
+**
+** Function bta_dm_sco_co_init
+**
+** Description This function can be used by the phone to initialize audio
+** codec or for other initialization purposes before SCO connection
+** is opened.
+**
+**
+** Returns tBTA_DM_SCO_ROUTE_TYPE: SCO routing configuration type.
+**
+*******************************************************************************/
+tBTA_DM_SCO_ROUTE_TYPE bta_dm_sco_co_init(UINT32 rx_bw, UINT32 tx_bw,
+ tBTA_CODEC_INFO * p_codec_type, UINT8 app_id)
+{
+ tBTM_SCO_ROUTE_TYPE route = BTA_DM_SCO_ROUTE_PCM;
+
+ BTIF_TRACE_DEBUG0("bta_dm_sco_co_init");
+
+ /* set up SCO routing configuration if SCO over HCI app ID is used and run time
+ configuration is set to SCO over HCI */
+ /* HS invoke this call-out */
+ if (
+#if (BTA_HS_INCLUDED == TRUE ) && (BTA_HS_INCLUDED == TRUE)
+ (app_id == BTUI_DM_SCO_4_HS_APP_ID && btui_cfg.hs_sco_over_hci) ||
+#endif
+ /* AG invoke this call-out */
+ (app_id != BTUI_DM_SCO_4_HS_APP_ID && btui_cfg.ag_sco_over_hci ))
+ {
+ route = btui_cb.sco_hci = BTA_DM_SCO_ROUTE_HCI;
+ }
+ /* no codec is is used for the SCO data */
+ if (p_codec_type->codec_type == BTA_SCO_CODEC_PCM && route == BTA_DM_SCO_ROUTE_HCI)
+ {
+ /* initialize SCO codec */
+ if (!btui_sco_codec_init(rx_bw, tx_bw))
+ {
+ BTIF_TRACE_ERROR0("codec initialization exception!");
+ }
+ }
+
+ return route;
+}
+
+
+
+/*******************************************************************************
+**
+** Function bta_dm_sco_co_open
+**
+** Description This function is executed when a SCO connection is open.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_sco_co_open(UINT16 handle, UINT8 pkt_size, UINT16 event)
+{
+ tBTUI_SCO_CODEC_CFG cfg;
+
+ if (btui_cb.sco_hci)
+ {
+ BTIF_TRACE_DEBUG2("bta_dm_sco_co_open handle:%d pkt_size:%d", handle, pkt_size);
+ /* use dedicated SCO buffer pool for SCO TX data */
+ cfg.pool_id = HCI_SCO_POOL_ID;
+ cfg.p_cback = btui_sco_codec_callback;
+ cfg.pkt_size = pkt_size;
+ cfg.cb_event = event;
+ /* open and start the codec */
+ btui_sco_codec_open(&cfg);
+ btui_sco_codec_start(handle);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_sco_co_close
+**
+** Description This function is called when a SCO connection is closed
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_sco_co_close(void)
+{
+ if (btui_cb.sco_hci)
+ {
+ BTIF_TRACE_DEBUG0("bta_dm_sco_co_close close codec");
+ /* close sco codec */
+ btui_sco_codec_close();
+
+ btui_cb.sco_hci = FALSE;
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_sco_co_in_data
+**
+** Description This function is called to send incoming SCO data to application.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_sco_co_in_data(BT_HDR *p_buf)
+{
+ if (btui_cfg.sco_use_mic)
+ btui_sco_codec_inqdata (p_buf);
+ else
+ GKI_freebuf(p_buf);
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_sco_co_out_data
+**
+** Description This function is called to send SCO data over HCI.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_sco_co_out_data(BT_HDR **p_buf)
+{
+ btui_sco_codec_readbuf(p_buf);
+}
+
+#endif /* #if (BTM_SCO_HCI_INCLUDED == TRUE ) && (BTM_SCO_INCLUDED == TRUE)*/
+
+
+#if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function bta_dm_co_le_io_key_req
+**
+** Description This callout function is executed by DM to get BLE key information
+** before SMP pairing gets going.
+**
+** Parameters bd_addr - The peer device
+** *p_max_key_size - max key size local device supported.
+** *p_init_key - initiator keys.
+** *p_resp_key - responder keys.
+**
+** Returns void.
+**
+*******************************************************************************/
+void bta_dm_co_le_io_key_req(BD_ADDR bd_addr, UINT8 *p_max_key_size,
+ tBTA_LE_KEY_TYPE *p_init_key,
+ tBTA_LE_KEY_TYPE *p_resp_key )
+{
+ BTIF_TRACE_ERROR0("##################################");
+ BTIF_TRACE_ERROR0("bta_dm_co_le_io_key_req: only setting max size to 16");
+ BTIF_TRACE_ERROR0("##################################");
+ *p_max_key_size = 16;
+ *p_init_key = *p_resp_key =
+ (BTA_LE_KEY_PENC|BTA_LE_KEY_PID|BTA_LE_KEY_PCSRK|BTA_LE_KEY_LENC|BTA_LE_KEY_LID|BTA_LE_KEY_LCSRK);
+}
+
+
+/*******************************************************************************
+**
+** Function bta_dm_co_ble_local_key_reload
+**
+** Description This callout function is to load the local BLE keys if available
+** on the device.
+**
+** Parameters none
+**
+** Returns void.
+**
+*******************************************************************************/
+void bta_dm_co_ble_load_local_keys(tBTA_DM_BLE_LOCAL_KEY_MASK *p_key_mask, BT_OCTET16 er,
+ tBTA_BLE_LOCAL_ID_KEYS *p_id_keys)
+{
+ BTIF_TRACE_ERROR0("##################################");
+ BTIF_TRACE_ERROR0("bta_dm_co_ble_load_local_keys: TBD Load local keys if any are persisted");
+ BTIF_TRACE_ERROR0("##################################");
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_co_ble_io_req
+**
+** Description This callout function is executed by DM to get BLE IO capabilities
+** before SMP pairing gets going.
+**
+** Parameters bd_addr - The peer device
+** *p_io_cap - The local Input/Output capabilities
+** *p_oob_data - TRUE, if OOB data is available for the peer device.
+** *p_auth_req - Auth request setting (Bonding and MITM required or not)
+** *p_max_key_size - max key size local device supported.
+** *p_init_key - initiator keys.
+** *p_resp_key - responder keys.
+**
+** Returns void.
+**
+*******************************************************************************/
+void bta_dm_co_ble_io_req(BD_ADDR bd_addr, tBTA_IO_CAP *p_io_cap,
+ tBTA_OOB_DATA *p_oob_data,
+ tBTA_LE_AUTH_REQ *p_auth_req,
+ UINT8 *p_max_key_size,
+ tBTA_LE_KEY_TYPE *p_init_key,
+ tBTA_LE_KEY_TYPE *p_resp_key )
+{
+ /* if OOB is not supported, this call-out function does not need to do anything
+ * otherwise, look for the OOB data associated with the address and set *p_oob_data accordingly
+ * If the answer can not be obtained right away,
+ * set *p_oob_data to BTA_OOB_UNKNOWN and call bta_dm_ci_io_req() when the answer is available */
+
+ /* *p_auth_req by default is FALSE for devices with NoInputNoOutput; TRUE for other devices. */
+ BTIF_TRACE_ERROR2("bta_dm_co_ble_io_req. p_auth_req=%d ble_authereq=%d", *p_auth_req, bte_appl_cfg.ble_auth_req);
+ BTIF_TRACE_ERROR2("bta_dm_co_ble_io_req. p_io_cap=%d ble_io_cap=%d", *p_io_cap, bte_appl_cfg.ble_io_cap);
+ BTIF_TRACE_ERROR2("bta_dm_co_ble_io_req. p_init_key=%d ble_init_key=%d", *p_init_key, bte_appl_cfg.ble_init_key);
+ BTIF_TRACE_ERROR2("bta_dm_co_ble_io_req. p_resp_key=%d ble_resp_key=%d", *p_resp_key, bte_appl_cfg.ble_resp_key );
+ BTIF_TRACE_ERROR2("bta_dm_co_ble_io_req. p_max_key_size=%d ble_max_key_size=%d", *p_max_key_size, bte_appl_cfg.ble_max_key_size );
+
+ *p_oob_data = FALSE;
+ if (bte_appl_cfg.ble_auth_req)
+ *p_auth_req = bte_appl_cfg.ble_auth_req | (bte_appl_cfg.ble_auth_req & 0x04) | ((*p_auth_req) & 0x04);
+
+ if (bte_appl_cfg.ble_io_cap <=4)
+ *p_io_cap = bte_appl_cfg.ble_io_cap;
+
+ if (bte_appl_cfg.ble_init_key<=7)
+ *p_init_key = bte_appl_cfg.ble_init_key;
+
+ if (bte_appl_cfg.ble_resp_key<=7)
+ *p_resp_key = bte_appl_cfg.ble_resp_key;
+
+ if (bte_appl_cfg.ble_max_key_size<=16)
+ *p_max_key_size = bte_appl_cfg.ble_max_key_size;
+
+}
+
+
+#endif
+
diff --git a/btif/co/bta_fs_co.c b/btif/co/bta_fs_co.c
new file mode 100644
index 0000000..9b0ab0a
--- /dev/null
+++ b/btif/co/bta_fs_co.c
@@ -0,0 +1,1212 @@
+/************************************************************************************
+ *
+ * Copyright (C) 2009-2011 Broadcom Corporation
+ *
+ * This program is the proprietary software of Broadcom Corporation and/or its
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
+ *
+ * Except as expressly set forth in the Authorized License,
+ *
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
+ * Broadcom integrated circuit products.
+ *
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT
+ * OF USE OR PERFORMANCE OF THE SOFTWARE.
+ *
+ * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR
+ * ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+ *
+ ************************************************************************************/
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/statfs.h>
+#include <sys/vfs.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <time.h>
+#include <limits.h>
+#include "gki.h"
+#include "bta_fs_co.h"
+#include "bta_fs_ci.h"
+//#include "btui.h"
+//#include "btui_int.h"
+#include <inttypes.h>
+
+#ifndef AID_SYSTEM
+#define AID_SYSTEM 1000
+#define AID_BLUETOOTH 1002
+#define AID_SDCARD_RW 1015
+#define AID_MISC 9998
+#endif
+
+#define FAT_FS 0x4d44
+const unsigned short BT_UID= AID_BLUETOOTH;
+const unsigned short BT_GID= AID_BLUETOOTH;
+
+/* enable additional debugging traces that should be compiled out by default! */
+#ifndef BTA_FS_DEBUG
+#define BTA_FS_DEBUG TRUE
+#define LOG_TAG "BTA_FS_CO"
+#define LOGI(format, ...) fprintf (stdout, LOG_TAG format"\n", ## __VA_ARGS__)
+#endif
+
+#if (defined BTA_PBS_INCLUDED) && (BTA_PBS_INCLUDED == TRUE)
+extern const tBTA_PBS_CFG bta_pbs_cfg;
+#endif
+
+
+
+static int del_path (const char *path)
+{
+ DIR *dir;
+ struct dirent *de;
+ int ret = 0;
+ char nameBuffer[PATH_MAX] = {0};
+ struct stat statBuffer;
+ BTIF_TRACE_DEBUG1("in del_path for path:%s", path);
+ dir = opendir(path);
+
+ if (dir == NULL) {
+ BTIF_TRACE_DEBUG1("opendir failed on path:%s", path);
+ return -1;
+ }
+
+ char *filenameOffset;
+
+ strncpy(nameBuffer, path, PATH_MAX - 1);
+ strcat(nameBuffer, "/");
+ int nameLen = strlen(nameBuffer);
+ filenameOffset = nameBuffer + nameLen;
+
+ for (;;) {
+ de = readdir(dir);
+
+ if (de == NULL) {
+ BTIF_TRACE_DEBUG1("readdir failed for path:%s", path);
+ //ret = -1;
+ break;
+ }
+
+ if (0 == strcmp(de->d_name, ".") || 0 == strcmp(de->d_name, ".."))
+ continue;
+
+ if((int)strlen(de->d_name) > PATH_MAX - nameLen) {
+ BTIF_TRACE_DEBUG1("d_name len:%d is too big", strlen(de->d_name));
+ ret = -1;
+ break;
+ }
+
+ strcpy(filenameOffset, de->d_name);
+
+ ret = lstat (nameBuffer, &statBuffer);
+
+ if (ret != 0) {
+ BTIF_TRACE_DEBUG1("lstat failed for path:%s", nameBuffer);
+ break;
+ }
+
+ if(S_ISDIR(statBuffer.st_mode)) {
+
+ ret = del_path(nameBuffer);
+ if(ret != 0)
+ break;
+ } else {
+ ret = unlink(nameBuffer);
+ if (ret != 0) {
+ BTIF_TRACE_DEBUG1("unlink failed for path:%s", nameBuffer);
+ break;
+ }
+ }
+ }
+
+ closedir(dir);
+ if(ret == 0) {
+ ret = rmdir(path);
+ BTIF_TRACE_DEBUG2("rmdir return:%d for path:%s", ret, path);
+ }
+
+ return ret;
+
+}
+
+inline int getAccess(int accType, struct stat *buffer, char *p_path)
+{
+
+ struct statfs fsbuffer;
+ int idType;
+
+ if(! buffer)
+ return BTA_FS_CO_FAIL;
+
+ //idType= (buffer->st_uid== BT_UID) ? 1 : (buffer->st_uid== BT_GID) ? 2 : 3;
+ if(buffer->st_uid == BT_UID)
+ idType = 1;
+ else if(buffer->st_gid == BT_GID ||
+ buffer->st_gid == AID_SYSTEM ||
+ buffer->st_gid == AID_MISC ||
+ buffer->st_gid == AID_SDCARD_RW)
+ idType = 2;
+ else idType = 3;
+
+ if(statfs(p_path, &fsbuffer)==0)
+ {
+ if(fsbuffer.f_type == FAT_FS)
+ return BTA_FS_CO_OK;
+ }
+ else {
+ return BTA_FS_CO_FAIL;
+ }
+
+ switch(accType) {
+ case 4:
+ if(idType== 1) { //Id is User Id
+ if(buffer-> st_mode & S_IRUSR)
+ return BTA_FS_CO_OK;
+ }
+ else if(idType==2) { //Id is Group Id
+ if(buffer-> st_mode & S_IRGRP)
+ return BTA_FS_CO_OK;
+ }
+ else { //Id is Others
+ if(buffer-> st_mode & S_IROTH)
+ return BTA_FS_CO_OK;
+ }
+ break;
+
+ case 6:
+ if(idType== 1) { //Id is User Id
+ if((buffer-> st_mode & S_IRUSR) && (buffer-> st_mode & S_IWUSR))
+ return BTA_FS_CO_OK;
+ }
+ else if(idType==2) { //Id is Group Id
+ if((buffer-> st_mode & S_IRGRP) && (buffer-> st_mode & S_IWGRP))
+ return BTA_FS_CO_OK;
+ }
+ else { //Id is Others
+ if((buffer-> st_mode & S_IROTH) && (buffer-> st_mode & S_IWOTH))
+ return BTA_FS_CO_OK;
+ }
+ break;
+
+ default:
+ return BTA_FS_CO_OK;
+ }
+ BTIF_TRACE_DEBUG0("*************FTP- Access Failed **********");
+ return BTA_FS_CO_EACCES;
+}
+
+
+/*****************************************************************************
+** Function Declarations
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function bta_fs_convert_oflags
+**
+** Description This function converts the open flags from BTA into MFS.
+**
+** Returns BTA FS status value.
+**
+*******************************************************************************/
+int bta_fs_convert_bta_oflags(int bta_oflags)
+{
+ int oflags = 0; /* Initially read only */
+
+ /* Only one of these can be set: Read Only, Read/Write, or Write Only */
+ if (bta_oflags & BTA_FS_O_RDWR)
+ oflags |= O_RDWR;
+ else if (bta_oflags & BTA_FS_O_WRONLY)
+ oflags |= O_WRONLY;
+
+ /* OR in any other flags that are set by BTA */
+ if (bta_oflags & BTA_FS_O_CREAT)
+ oflags |= O_CREAT;
+
+ if (bta_oflags & BTA_FS_O_EXCL)
+ oflags |= O_EXCL;
+
+ if (bta_oflags & BTA_FS_O_TRUNC)
+ oflags |= O_TRUNC;
+
+ return (oflags);
+}
+
+
+
+/*******************************************************************************
+ **
+ ** Function btapp_fs_check_space
+ **
+ ** Description determines access and if there is enough space for given files size on given path
+ **
+ ** Parameters p_path - Fully qualified path and file name.
+ ** WARNING: file name is stripped off! so it must be present!
+ ** size - size of file to put (0 if unavailable or not applicable)
+ ** app_id - in case application specific treatement is required (e.g opp versus ftp)
+ ** Returns 0 if enough space, otherwise errno failure codes
+ **
+ *******************************************************************************/
+static int btapp_fs_check_space( const char *p_path, const UINT32 size, const UINT8 app_id )
+{
+
+ unsigned long long max_space;
+ struct statfs fs_buffer;
+ int err = 0;
+ char *p_dir;
+ char *p_end;
+
+ if(size==BTA_FS_LEN_UNKNOWN)
+ return 0;
+ /* fail silently in case of no memory. write will catch if not enough space */
+
+ if (NULL != (p_dir = (char *) GKI_getbuf(strlen(p_path) + 1)))
+ {
+ strcpy(p_dir, p_path);
+ if (NULL != (p_end = strrchr(p_dir, '/')))
+ {
+
+ *p_end = '\0';
+ /* get fs info and calculate available space. if not enough, the fs error EFBIG is returned */
+
+ if (0 == statfs(p_dir, &fs_buffer))
+ {
+
+ max_space = fs_buffer.f_bavail * fs_buffer.f_bsize;
+#if (BTA_FS_DEBUG==TRUE)
+ BTIF_TRACE_DEBUG2("btapp_fs_enough_space(file size: %d): (uint)max_size: %u", size, (UINT32)max_space);
+#endif
+ if (max_space < size)
+ err = EFBIG;
+ }
+ else
+ {
+ err = errno;
+ BTIF_TRACE_WARNING1("btapp_fs_enough_space(): statfs() failed with err: %d", err);
+ }
+ }
+ else
+ {
+ err = ENOENT;
+ }
+ GKI_freebuf(p_dir);
+ }
+ else
+ {
+ err = ENOMEM;
+ }
+ return err;
+
+} /* btapp_fs_check_access_space() */
+
+
+/*******************************************************************************
+**
+** Function bta_fs_co_open
+**
+** Description This function is executed by BTA when a file is opened.
+** The phone uses this function to open
+** a file for reading or writing.
+**
+** Parameters p_path - Fully qualified path and file name.
+** oflags - permissions and mode (see constants above)
+** size - size of file to put (0 if unavailable or not applicable)
+** evt - event that must be passed into the call-in function.
+** app_id - application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns void
+**
+** Note: Upon completion of the request, a file descriptor (int),
+** if successful, and an error code (tBTA_FS_CO_STATUS)
+** are returned in the call-in function, bta_fs_ci_open().
+**
+*******************************************************************************/
+
+void bta_fs_co_open(const char *p_path, int oflags, UINT32 size, UINT16 evt,
+ UINT8 app_id)
+{
+
+ tBTA_FS_CO_STATUS status;
+ UINT32 file_size = 0;
+ struct stat file_stat;
+ int fd = -1;
+ int err = 0;
+
+ /* Convert BTA oflags into os specific flags */
+ oflags = bta_fs_convert_bta_oflags(oflags);
+
+ /* check available space in case of write access. oflags are in OS format! */
+ if (oflags & (O_RDWR|O_WRONLY))
+ {
+ err = btapp_fs_check_space(p_path, size, app_id);
+ }
+
+ if ( 0==err )
+ {
+ if ((fd = open(p_path, oflags | O_NONBLOCK, 0666)) >= 0)
+ {
+ if (fstat(fd, &file_stat) == 0)
+ {
+ file_size = file_stat.st_size;
+ if (oflags & O_CREAT)
+ {
+ fchown(fd, BT_UID, BT_GID);
+ BTIF_TRACE_DEBUG0("\n ******CHANGED OWNERSHIP SUCCESSFULLY**********");
+ }
+ }
+ }
+
+ else
+ {
+ err = errno;
+ }
+ }
+
+ BTIF_TRACE_DEBUG4("[CO] bta_fs_co_open: handle:%d err:%d, flags:%x, app id:%d",
+ fd, err, oflags, app_id);
+ BTIF_TRACE_DEBUG1("file=%s", p_path);
+
+ /* convert fs error into bta_fs err. erro is set by first call to enough space to a valid value
+ * and needs only updating in case of error. This reports correct failure to remote obex! */
+
+ switch (err)
+ {
+
+ case 0:
+ status = BTA_FS_CO_OK;
+ break;
+ case EACCES:
+ status = BTA_FS_CO_EACCES;
+ break;
+ case EFBIG: /* file to big for available fs space */
+ status = BTA_FS_CO_ENOSPACE;
+ break;
+ default:
+ status = BTA_FS_CO_FAIL;
+ break;
+ }
+ bta_fs_ci_open(fd, status, file_size, evt);
+}
+
+/*******************************************************************************
+**
+** Function bta_fs_co_close
+**
+** Description This function is called by BTA when a connection to a
+** client is closed.
+**
+** Parameters fd - file descriptor of file to close.
+** app_id - application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns (tBTA_FS_CO_STATUS) status of the call.
+** [BTA_FS_CO_OK if successful],
+** [BTA_FS_CO_FAIL if failed ]
+**
+*******************************************************************************/
+tBTA_FS_CO_STATUS bta_fs_co_close(int fd, UINT8 app_id)
+{
+ tBTA_FS_CO_STATUS status = BTA_FS_CO_OK;
+ int err;
+
+ BTIF_TRACE_DEBUG2("[CO] bta_fs_co_close: handle:%d, app id:%d",
+ fd, app_id);
+ if (close (fd) < 0)
+ {
+ err = errno;
+ status = BTA_FS_CO_FAIL;
+ BTIF_TRACE_WARNING3("[CO] bta_fs_co_close: handle:%d error=%d app_id:%d", fd, err, app_id);
+ }
+
+ return (status);
+}
+
+/*******************************************************************************
+**
+** Function bta_fs_co_read
+**
+** Description This function is called by BTA to read in data from the
+** previously opened file on the phone.
+**
+** Parameters fd - file descriptor of file to read from.
+** p_buf - buffer to read the data into.
+** nbytes - number of bytes to read into the buffer.
+** evt - event that must be passed into the call-in function.
+** ssn - session sequence number. Ignored, if bta_fs_co_open
+** was not called with BTA_FS_CO_RELIABLE.
+** app_id - application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns void
+**
+** Note: Upon completion of the request, bta_fs_ci_read() is
+** called with the buffer of data, along with the number
+** of bytes read into the buffer, and a status. The
+** call-in function should only be called when ALL requested
+** bytes have been read, the end of file has been detected,
+** or an error has occurred.
+**
+*******************************************************************************/
+void bta_fs_co_read(int fd, UINT8 *p_buf, UINT16 nbytes, UINT16 evt, UINT8 ssn, UINT8 app_id)
+{
+ tBTA_FS_CO_STATUS status = BTA_FS_CO_OK;
+ INT32 num_read;
+ int err;
+
+ if ((num_read = read (fd, p_buf, nbytes)) < 0)
+ {
+ err = errno;
+ status = BTA_FS_CO_FAIL;
+ BTIF_TRACE_WARNING3("[CO] bta_fs_co_read: handle:%d error=%d app_id:%d",
+ fd, err, app_id);
+ }
+ else if (num_read < nbytes)
+ status = BTA_FS_CO_EOF;
+
+ bta_fs_ci_read(fd, (UINT16)num_read, status, evt);
+}
+
+/*******************************************************************************
+**
+** Function bta_fs_co_write
+**
+** Description This function is called by io to send file data to the
+** phone.
+**
+** Parameters fd - file descriptor of file to write to.
+** p_buf - buffer to read the data from.
+** nbytes - number of bytes to write out to the file.
+** evt - event that must be passed into the call-in function.
+** ssn - session sequence number. Ignored, if bta_fs_co_open
+** was not called with BTA_FS_CO_RELIABLE.
+** app_id - application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns void
+**
+** Note: Upon completion of the request, bta_fs_ci_write() is
+** called with the file descriptor and the status. The
+** call-in function should only be called when ALL requested
+** bytes have been written, or an error has been detected,
+**
+*******************************************************************************/
+void bta_fs_co_write(int fd, const UINT8 *p_buf, UINT16 nbytes, UINT16 evt,
+ UINT8 ssn, UINT8 app_id)
+{
+ tBTA_FS_CO_STATUS status = BTA_FS_CO_OK;
+ INT32 num_written;
+ int err=0;
+
+ if ((num_written = write (fd, p_buf, nbytes)) < 0)
+ {
+ err = errno;
+ status = BTA_FS_CO_FAIL;
+ }
+/* BTIF_TRACE_DEBUG3("[CO] bta_fs_co_write: handle:%d error=%d, num_written:%d", fd, err, num_written);*/
+
+ bta_fs_ci_write(fd, status, evt);
+}
+
+/*******************************************************************************
+**
+** Function bta_fs_co_seek
+**
+** Description This function is called by io to move the file pointer
+** of a previously opened file to the specified location for
+** the next read or write operation.
+**
+** Parameters fd - file descriptor of file.
+** offset - Number of bytes from origin.
+** origin - Initial position.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fs_co_seek (int fd, INT32 offset, INT16 origin, UINT8 app_id)
+{
+ lseek(fd, offset, origin);
+}
+
+/*******************************************************************************
+**
+** Function bta_fs_co_access
+**
+** Description This function is called to check the existence of
+** a file or directory, and return whether or not it is a
+** directory or length of the file.
+**
+** Parameters p_path - (input) file or directory to access (fully qualified path).
+** mode - (input) [BTA_FS_ACC_EXIST, BTA_FS_ACC_READ, or BTA_FS_ACC_RDWR]
+** p_is_dir - (output) returns TRUE if p_path specifies a directory.
+** app_id - (input) application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns (tBTA_FS_CO_STATUS) status of the call.
+** [BTA_FS_CO_OK if it exists]
+** [BTA_FS_CO_EACCES if permissions are wrong]
+** [BTA_FS_CO_FAIL if it does not exist]
+**
+*******************************************************************************/
+tBTA_FS_CO_STATUS bta_fs_co_access(const char *p_path, int mode, BOOLEAN *p_is_dir,
+ UINT8 app_id)
+{
+ int err;
+ int os_mode = 0;
+ tBTA_FS_CO_STATUS status = BTA_FS_CO_OK;
+ struct stat buffer;
+
+ #if (TRUE==BTA_FS_DEBUG)
+ LOGI("***********CHECKING ACCESS TO = %s", p_path);
+ #endif
+
+ #if (defined BTA_PBS_INCLUDED) && (BTA_PBS_INCLUDED == TRUE)
+
+ if (app_id == UI_PBS_ID)
+ {
+
+ *p_is_dir = TRUE;
+
+ #if (TRUE==BTA_FS_DEBUG)
+ LOGI("***********SUPPORTED REPO = %d", bta_pbs_cfg.supported_repositories);
+ #endif
+ //Check if SIM contact requested, and if so if it's supported.
+ //If not, return error!
+ if (strstr(p_path,"SIM1") && !(bta_pbs_cfg.supported_repositories & 0x2)) {
+ LOGI("***********RETURNING FAIL!");
+ return BTA_FS_CO_FAIL;
+ }
+
+ #if (TRUE==BTA_FS_DEBUG)
+ LOGI("***********RETURNING success!");
+ #endif
+ return (status);
+ }
+ #endif
+
+
+ *p_is_dir = FALSE;
+
+ if (mode == BTA_FS_ACC_RDWR)
+ os_mode = 6;
+ else if (mode == BTA_FS_ACC_READ)
+ os_mode = 4;
+
+ if (stat(p_path, &buffer) == 0)
+ {
+ /* Determine if the object is a file or directory */
+ if (S_ISDIR(buffer.st_mode))
+ *p_is_dir = TRUE;
+ }
+ else
+ {
+ BTIF_TRACE_DEBUG0("stat() failed! ");
+ return BTA_FS_CO_FAIL;
+ }
+
+ status=getAccess (os_mode, &buffer, (char*)p_path);
+ return (status);
+}
+
+/*******************************************************************************
+**
+** Function bta_fs_co_mkdir
+**
+** Description This function is called to create a directory with
+** the pathname given by path. The pathname is a null terminated
+** string. All components of the path must already exist.
+**
+** Parameters p_path - (input) name of directory to create (fully qualified path).
+** app_id - (input) application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns (tBTA_FS_CO_STATUS) status of the call.
+** [BTA_FS_CO_OK if successful]
+** [BTA_FS_CO_FAIL if unsuccessful]
+**
+*******************************************************************************/
+tBTA_FS_CO_STATUS bta_fs_co_mkdir(const char *p_path, UINT8 app_id)
+{
+ int err;
+ tBTA_FS_CO_STATUS status = BTA_FS_CO_OK;
+
+ if ((mkdir (p_path, 0666)) != 0)
+ {
+ err = errno;
+ status = BTA_FS_CO_FAIL;
+ BTIF_TRACE_WARNING3("[CO] bta_fs_co_mkdir: error=%d, path [%s] app_id:%d",
+ err, p_path, app_id);
+ }
+ return (status);
+}
+
+/*******************************************************************************
+**
+** Function bta_fs_co_rmdir
+**
+** Description This function is called to remove a directory whose
+** name is given by path. The directory must be empty.
+**
+** Parameters p_path - (input) name of directory to remove (fully qualified path).
+** app_id - (input) application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns (tBTA_FS_CO_STATUS) status of the call.
+** [BTA_FS_CO_OK if successful]
+** [BTA_FS_CO_EACCES if read-only]
+** [BTA_FS_CO_ENOTEMPTY if directory is not empty]
+** [BTA_FS_CO_FAIL otherwise]
+**
+*******************************************************************************/
+tBTA_FS_CO_STATUS bta_fs_co_rmdir(const char *p_path, UINT8 app_id)
+{
+ int err, path_len;
+ tBTA_FS_CO_STATUS status = BTA_FS_CO_OK;
+ struct stat buffer;
+ char *dirName, *tmp = NULL;
+
+ path_len = strlen( p_path )+1;
+ BTIF_TRACE_DEBUG2( "bta_fs_co_rmdir( app_id: %d ): path_len: %d", app_id, path_len );
+#if (TRUE==BTA_FS_DEBUG)
+ BTIF_TRACE_DEBUG1( "bta_fs_co_rmdir():path_len: %d, p_path", app_id );
+ BTIF_TRACE_DEBUG0( p_path );
+#endif
+
+ /* allocate a temp buffer for path with 0 char. make sure not to crash if path is too big! */
+ dirName = (char*) calloc(1, path_len+1);
+ if ( NULL != dirName )
+ {
+ strcpy( dirName, p_path );
+ }
+ else
+ {
+ BTIF_TRACE_WARNING2( "bta_fs_co_rmdir( app_id: %d ) for path_len: %d::out of memory",
+ app_id, path_len );
+ return BTA_FS_CO_FAIL;
+ }
+
+ if (NULL!= (tmp = strrchr(dirName, '/')))
+ {
+ *tmp = '\0';
+ }
+ if (stat(dirName, &buffer) == 0)
+ {
+ status = getAccess(6, &buffer, dirName);
+ }
+ else
+ {
+ free(dirName);
+#if (TRUE==BTA_FS_DEBUG)
+ BTIF_TRACE_WARNING0( "bta_fs_co_rmdir()::stat(dirName) failed" );
+#endif
+ return BTA_FS_CO_FAIL;
+ }
+
+ free(dirName);
+ if (status != BTA_FS_CO_OK)
+ {
+#if (TRUE==BTA_FS_DEBUG)
+ BTIF_TRACE_WARNING0( "bta_fs_co_rmdir()::getAccess(dirName) FAILED");
+#endif
+ return status;
+ }
+
+ if (stat(p_path, &buffer) == 0)
+ {
+ status = getAccess(6, &buffer, (char*)p_path);
+ }
+ else
+ {
+#if (TRUE==BTA_FS_DEBUG)
+ BTIF_TRACE_WARNING0( "bta_fs_co_rmdir()::stat(p_path) FAILED");
+#endif
+ return BTA_FS_CO_FAIL;
+ }
+
+ if (status != BTA_FS_CO_OK)
+ {
+#if (TRUE==BTA_FS_DEBUG)
+ BTIF_TRACE_DEBUG0( "bta_fs_co_rmdir()::getAccess(p_path) FAILED");
+#endif
+ return status;
+ }
+ //if ((rmdir (p_path)) != 0)
+ if (del_path(p_path) != 0)
+ {
+ err = errno;
+ BTIF_TRACE_WARNING1( "bta_fs_co_rmdir():rmdir/del_path FAILED with err: %d", err );
+ if (err == EACCES)
+ status = BTA_FS_CO_EACCES;
+ else if (err == ENOTEMPTY)
+ status = BTA_FS_CO_ENOTEMPTY;
+ else
+ status = BTA_FS_CO_FAIL;
+ }
+ return (status);
+}
+
+/*******************************************************************************
+**
+** Function bta_fs_co_unlink
+**
+** Description This function is called to remove a file whose name
+** is given by p_path.
+**
+** Parameters p_path - (input) name of file to remove (fully qualified path).
+** app_id - (input) application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns (tBTA_FS_CO_STATUS) status of the call.
+** [BTA_FS_CO_OK if successful]
+** [BTA_FS_CO_EACCES if read-only]
+** [BTA_FS_CO_FAIL otherwise]
+**
+*******************************************************************************/
+tBTA_FS_CO_STATUS bta_fs_co_unlink(const char *p_path, UINT8 app_id)
+{
+ BTIF_TRACE_DEBUG0("bta_fs_co_unlink");
+ int err;
+ tBTA_FS_CO_STATUS status = BTA_FS_CO_OK;
+ char *dirName, *tmp=NULL;
+ struct stat buffer;
+
+ if(! p_path)
+ return BTA_FS_CO_FAIL;
+
+ /* buffer needs to be NULL terminated - so add one more byte to be zero'd out */
+#if 0
+ dirName= (char*) calloc(1, strlen(p_path)); /* <--- this can cause problems */
+#else
+ dirName= (char*) calloc(1, strlen(p_path) + 1);
+#endif
+
+ strncpy(dirName, p_path, strlen(p_path));
+ if((tmp=strrchr(dirName, '/')))
+ {
+ *tmp='\0';
+ }
+ if (stat(dirName, &buffer) == 0)
+ {
+ status=getAccess (6, &buffer, dirName);
+ free(dirName);
+ }
+ else
+ {
+ BTIF_TRACE_DEBUG0("stat() failed! ");
+ free(dirName);
+ return BTA_FS_CO_FAIL;
+ }
+
+ if(status!= BTA_FS_CO_OK)
+ return status;
+
+ if ((unlink (p_path)) != 0)
+ {
+ err = errno;
+ if (err == EACCES)
+ status = BTA_FS_CO_EACCES;
+ else
+ status = BTA_FS_CO_FAIL;
+ }
+ return (status);
+
+}
+
+/*******************************************************************************
+**
+** Function bta_fs_co_getdirentry
+**
+** Description This function is called to get a directory entry for the
+** specified p_path. The first/next directory should be filled
+** into the location specified by p_entry.
+**
+** Parameters p_path - directory to search (Fully qualified path)
+** first_item - TRUE if first search, FALSE if next search
+** (p_cur contains previous)
+** p_entry (input/output) - Points to last entry data (valid when
+** first_item is FALSE)
+** evt - event that must be passed into the call-in function.
+** app_id - application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns void
+**
+** Note: Upon completion of the request, the status is passed
+** in the bta_fs_ci_direntry() call-in function.
+** BTA_FS_CO_OK is returned when p_entry is valid,
+** BTA_FS_CO_EODIR is returned when no more entries [finished]
+** BTA_FS_CO_FAIL is returned if an error occurred
+**
+*******************************************************************************/
+void bta_fs_co_getdirentry(const char *p_path, BOOLEAN first_item,
+ tBTA_FS_DIRENTRY *p_entry, UINT16 evt, UINT8 app_id)
+{
+ tBTA_FS_CO_STATUS co_status = BTA_FS_CO_FAIL;
+ int status = -1; /* '0' - success, '-1' - fail */
+ struct tm *p_tm;
+ DIR *dir;
+ struct dirent *dirent;
+ struct stat buf;
+ char fullname[500];
+
+ BTIF_TRACE_DEBUG0("Entered bta_fs_co_getdirentry");
+
+ /* First item is to be retrieved */
+ if (first_item)
+ {
+ BTIF_TRACE_DEBUG1("bta_fs_co_getdirentry: path = %s", p_path);
+
+ dir = opendir(p_path);
+ if(dir == NULL)
+ {
+ BTIF_TRACE_DEBUG1("bta_fs_co_getdirentry: dir is NULL so error out with errno=%d", errno);
+ co_status = BTA_FS_CO_EODIR;
+ bta_fs_ci_direntry(co_status, evt);
+ return;
+ }
+
+ BTIF_TRACE_DEBUG1("bta_fs_co_getdirentry: dir = %p", dir);
+ if((dirent = readdir(dir)) != NULL)
+ {
+ p_entry->refdata = (UINT32) dir; /* Save this for future searches */
+ status = 0;
+ BTIF_TRACE_DEBUG1("bta_fs_co_getdirentry: dirent = %p", dirent);
+ }
+ else
+ {
+ BTIF_TRACE_DEBUG1("bta_fs_co_getdirentry: dirent = %p", dirent);
+ /* Close the search if there are no more items */
+ closedir( (DIR*) p_entry->refdata);
+ co_status = BTA_FS_CO_EODIR;
+ }
+ }
+ else /* Get the next entry based on the p_ref data from previous search */
+ {
+ if ((dirent = readdir((DIR*)p_entry->refdata)) == NULL)
+ {
+ /* Close the search if there are no more items */
+ closedir( (DIR*) p_entry->refdata);
+ co_status = BTA_FS_CO_EODIR;
+ BTIF_TRACE_DEBUG1("bta_fs_co_getdirentry: dirent = %p", dirent);
+ }
+ else
+ {
+ BTIF_TRACE_DEBUG1("bta_fs_co_getdirentry: dirent = %p", dirent);
+ status = 0;
+ }
+ }
+
+ if (status == 0)
+ {
+ BTIF_TRACE_DEBUG0("bta_fs_co_getdirentry: status = 0");
+
+ sprintf(fullname, "%s/%s", p_path, dirent->d_name);
+
+ /* Load new values into the return structure (refdata is left untouched) */
+ if (stat(fullname, &buf) == 0) {
+ p_entry->filesize = buf.st_size;
+ p_entry->mode = 0; /* Default is normal read/write file access */
+
+ if (S_ISDIR(buf.st_mode))
+ p_entry->mode |= BTA_FS_A_DIR;
+ else
+ p_entry->mode |= BTA_FS_A_RDONLY;
+
+ strcpy(p_entry->p_name, dirent->d_name);
+#if 0
+ fprintf(stderr, "bta_fs_co_getdirentry(): %s %9d %d\n",
+ dirent->d_name,
+ buf.st_size,
+ p_entry->mode);
+#endif
+ p_tm = localtime((const time_t*)&buf.st_mtime);
+ if (p_tm != NULL)
+ {
+ sprintf(p_entry->crtime, "%04d%02d%02dT%02d%02d%02dZ",
+ p_tm->tm_year + 1900, /* Base Year ISO 6201 */
+ p_tm->tm_mon + 1, /* month starts at 0 */
+ p_tm->tm_mday,
+ p_tm->tm_hour,
+ p_tm->tm_min,
+ p_tm->tm_sec);
+ }
+ else
+ p_entry->crtime[0] = '\0'; /* No valid time */
+#if 0
+ fprintf(stderr, "bta_fs_co_getdirentry(): %s %9d %d %s\n",
+ dirent->d_name,
+ p_entry->filesize,
+ p_entry->mode,
+ p_entry->crtime);
+#endif
+ co_status = BTA_FS_CO_OK;
+ } else {
+ BTIF_TRACE_WARNING0("stat() failed! ");
+ co_status = BTA_FS_CO_EACCES;
+ }
+ }
+ BTIF_TRACE_DEBUG0("bta_fs_co_getdirentry: calling bta_fs_ci_getdirentry");
+
+ bta_fs_ci_direntry(co_status, evt);
+}
+
+
+
+
+/*******************************************************************************
+**
+** Function bta_fs_co_setdir
+**
+** Description This function is executed by BTA when the server changes the
+** local path
+**
+** Parameters p_path - the new path.
+** app_id - application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fs_co_setdir(const char *p_path, UINT8 app_id)
+{
+ BTIF_TRACE_DEBUG2("Entered %s. New path: %s", __FUNCTION__, p_path);
+}
+
+/*******************************************************************************
+** OBEX14 Reliable Session not supported. Stub associated callouts.
+******************************************************************************/
+
+/*******************************************************************************
+**
+** Function bta_fs_co_resume
+**
+** Description This function is executed by BTA when resuming a session.
+** This is used to retrieve the session ID and related information
+**
+** Parameters evt - event that must be passed into the call-in function.
+** app_id - application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns void
+**
+** Note: Upon completion of the request, the related session information,
+** if successful, and an error code (tBTA_FS_CO_STATUS)
+** are returned in the call-in function, bta_fs_ci_resume().
+**
+*******************************************************************************/
+void bta_fs_co_resume(UINT16 evt, UINT8 app_id)
+{
+ BTIF_TRACE_WARNING0("[CO] bta_fs_co_resume - NOT implemented");
+}
+
+/*******************************************************************************
+**
+** Function bta_fs_co_set_perms
+**
+** Description This function is called to set the permission a file/directory
+** with name as p_src_path.
+**
+** Parameters p_src_path - (input) name of file/directory to set permission (fully qualified path).
+** p_perms - the permission .
+** app_id - (input) application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns (tBTA_FS_CO_STATUS) status of the call.
+** [BTA_FS_CO_OK if successful]
+** [BTA_FS_CO_EACCES if p_dest_path already exists or could not be created (invalid path);
+** or p_src_path is a directory and p_dest_path specifies a different path. ]
+** [BTA_FS_CO_FAIL otherwise]
+**
+*******************************************************************************/
+void bta_fs_co_set_perms(const char *p_src_path, UINT8 *p_perms, UINT16 evt, UINT8 app_id)
+{
+ BTIF_TRACE_WARNING0("[CO] bta_fs_co_set_perms - NOT implemented");
+}
+
+/*******************************************************************************
+**
+** Function bta_fs_co_rename
+**
+** Description This function is called to move a file/directory whose
+** name is given by p_src_path to p_dest_path.
+**
+** Parameters p_src_path - (input) name of file/directory to be moved (fully qualified path).
+** p_dest_path - (input) new name of file/directory(fully qualified path).
+** p_perms - the permission of the new object.
+** app_id - (input) application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns (tBTA_FS_CO_STATUS) status of the call.
+** [BTA_FS_CO_OK if successful]
+** [BTA_FS_CO_EACCES if p_dest_path already exists or could not be created (invalid path);
+** or p_src_path is a directory and p_dest_path specifies a different path. ]
+** [BTA_FS_CO_FAIL otherwise]
+**
+*******************************************************************************/
+void bta_fs_co_rename(const char *p_src_path, const char *p_dest_path, UINT8 *p_perms, UINT16 evt, UINT8 app_id)
+{
+ BTIF_TRACE_WARNING0("[CO] bta_fs_co_rename - NOT implemented");
+}
+
+/*******************************************************************************
+**
+** Function bta_fs_co_copy
+**
+** Description This function is called to copy a file/directory whose
+** name is given by p_src_path to p_dest_path.
+**
+** Parameters p_src_path - (input) name of file/directory to be copied (fully qualified path).
+** p_dest_path - (input) new name of file/directory(fully qualified path).
+** p_perms - the permission of the new object.
+** evt - event that must be passed into the call-in function.
+** app_id - (input) application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns (tBTA_FS_CO_STATUS) status of the call.
+** [BTA_FS_CO_OK if successful]
+** [BTA_FS_CO_EIS_DIR if p_src_path is a folder]
+** [BTA_FS_CO_EACCES if p_dest_path already exists or could not be created (invalid path);
+** or p_src_path is a directory and p_dest_path specifies a different path. ]
+** [BTA_FS_CO_FAIL otherwise]
+**
+*******************************************************************************/
+void bta_fs_co_copy(const char *p_src_path, const char *p_dest_path, UINT8 *p_perms, UINT16 evt, UINT8 app_id)
+{
+ BTIF_TRACE_WARNING0("[CO] bta_fs_co_copy - NOT implemented");
+}
+
+/*******************************************************************************
+**
+** Function bta_fs_co_resume_op
+**
+** Description This function is executed by BTA when a reliable session is
+** resumed and there was an interrupted operation.
+**
+** Parameters offset - the session ID and related information.
+** evt - event that must be passed into the call-in function.
+** app_id - application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fs_co_resume_op(UINT32 offset, UINT16 evt, UINT8 app_id)
+{
+ BTIF_TRACE_WARNING0("[CO] bta_fs_co_resume_op - NOT implemented");
+}
+
+
+/*******************************************************************************
+**
+** Function bta_fs_co_session_info
+**
+** Description This function is executed by BTA when a reliable session is
+** established (p_sess_info != NULL) or ended (p_sess_info == NULL).
+**
+** Parameters bd_addr - the peer address
+** p_sess_info - the session ID and related information.
+** app_id - application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fs_co_session_info(BD_ADDR bd_addr, UINT8 *p_sess_info, UINT8 ssn,
+ tBTA_FS_CO_SESS_ST new_st, char *p_path, UINT8 *p_info, UINT8 app_id)
+{
+ BTIF_TRACE_WARNING0("[CO] bta_fs_co_session_info - NOT implemented");
+}
+
+
+/*******************************************************************************
+**
+** Function bta_fs_co_suspend
+**
+** Description This function is executed by BTA when a reliable session is
+** suspended.
+**
+** Parameters bd_addr - the peer address
+** ssn - the session sequence number.
+** info - the BTA specific information (like last active operation).
+** p_offset- the location to receive object offset of the suspended session
+** app_id - application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fs_co_suspend(BD_ADDR bd_addr, UINT8 *p_sess_info, UINT8 ssn,
+ UINT32 *p_timeout, UINT32 *p_offset, UINT8 info, UINT8 app_id)
+{
+ BTIF_TRACE_WARNING0("[CO] bta_fs_co_suspend - NOT implemented");
+}
+
+/*******************************************************************************
+**
+** Function bta_fs_co_sess_ssn
+**
+** Description This function is executed by BTA when resuming a session.
+** This is used to inform call-out module if the ssn/file offset
+** needs to be adjusted.
+**
+** Parameters ssn - the session sequence number of the first request
+** after resume.
+** app_id - application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fs_co_sess_ssn(int fd, UINT8 ssn, UINT8 app_id)
+{
+ BTIF_TRACE_WARNING0("[CO] bta_fs_co_suspend - NOT implemented");
+}
+
diff --git a/btif/co/bta_sys_co.c b/btif/co/bta_sys_co.c
new file mode 100644
index 0000000..66643bf
--- /dev/null
+++ b/btif/co/bta_sys_co.c
@@ -0,0 +1,86 @@
+/************************************************************************************
+ *
+ * Copyright (C) 2009-2011 Broadcom Corporation
+ *
+ * This program is the proprietary software of Broadcom Corporation and/or its
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
+ *
+ * Except as expressly set forth in the Authorized License,
+ *
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
+ * Broadcom integrated circuit products.
+ *
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT
+ * OF USE OR PERFORMANCE OF THE SOFTWARE.
+ *
+ * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR
+ * ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+ *
+ ************************************************************************************/
+#include "bta_sys.h"
+#include "bta_sys_ci.h"
+
+/*******************************************************************************
+**
+** Function bta_sys_hw_co_enable
+**
+** Description This function is called by the stack to power up the HW
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_sys_hw_co_enable( tBTA_SYS_HW_MODULE module )
+{
+ /* platform specific implementation to power-up the HW */
+
+
+ /* if no client/server asynchronous system like linux-based OS, directly call the ci here */
+ bta_sys_hw_ci_enabled( module );
+}
+
+
+/*******************************************************************************
+**
+** Function bta_sys_hw_co_disable
+**
+** Description This function is called by the stack to power down the HW
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_sys_hw_co_disable( tBTA_SYS_HW_MODULE module )
+{
+ /* platform specific implementation to power-down the HW */
+
+
+ /* if no client/server asynchronous system like linux-based OS, directly call the ci here */
+ bta_sys_hw_ci_disabled( module );
+
+}
diff --git a/btif/include/btif_api.h b/btif/include/btif_api.h
new file mode 100644
index 0000000..5ceb197
--- /dev/null
+++ b/btif/include/btif_api.h
@@ -0,0 +1,368 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * This program is the proprietary software of Broadcom Corporation and/or its
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
+ *
+ * Except as expressly set forth in the Authorized License,
+ *
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
+ * Broadcom integrated circuit products.
+ *
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING
+ * OUT OF USE OR PERFORMANCE OF THE SOFTWARE.
+ *
+ * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM
+ * OR ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+ *
+ *****************************************************************************/
+
+/*****************************************************************************
+ *
+ * Filename: btif_api.h
+ *
+ * Description: Main API header file for all BTIF functions accessed
+ * from main bluetooth HAL. All HAL extensions will not
+ * require headerfiles as they would be accessed through
+ * callout/callins.
+ *
+ *****************************************************************************/
+
+#ifndef BTIF_API_H
+#define BTIF_API_H
+
+#include "btif_common.h"
+#include "btif_dm.h"
+
+/*****************************************************************************
+** Constants & Macros
+******************************************************************************/
+
+/*****************************************************************************
+** Type definitions for callback functions
+******************************************************************************/
+
+/*****************************************************************************
+** Type definitions and return values
+******************************************************************************/
+
+/*****************************************************************************
+** Extern variables and functions
+******************************************************************************/
+
+/*****************************************************************************
+** Functions
+******************************************************************************/
+
+
+/*****************************************************************************
+** BTIF CORE API
+******************************************************************************/
+
+
+/*******************************************************************************
+**
+** Function btif_init_bluetooth
+**
+** Description Creates BTIF task and prepares BT scheduler for startup
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+
+bt_status_t btif_init_bluetooth(void);
+
+/*******************************************************************************
+**
+** Function btif_enable_bluetooth
+**
+** Description Performs chip power on and kickstarts OS scheduler
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+
+bt_status_t btif_enable_bluetooth(void);
+
+/*******************************************************************************
+**
+** Function btif_disable_bluetooth
+**
+** Description Inititates shutdown of Bluetooth system.
+** Any active links will be dropped and device entering
+** non connectable/discoverable mode
+**
+** Returns void
+**
+*******************************************************************************/
+
+bt_status_t btif_disable_bluetooth(void);
+
+/*******************************************************************************
+**
+** Function btif_shutdown_bluetooth
+**
+** Description Finalizes BT scheduler shutdown and terminates BTIF
+** task.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+
+bt_status_t btif_shutdown_bluetooth(void);
+
+
+/*******************************************************************************
+**
+** Function btif_get_adapter_properties
+**
+** Description Fetches all local adapter properties
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+
+bt_status_t btif_get_adapter_properties(void);
+
+/*******************************************************************************
+**
+** Function btif_get_adapter_property
+**
+** Description Fetches property value from local cache
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+
+bt_status_t btif_get_adapter_property( bt_property_type_t type);
+
+/*******************************************************************************
+**
+** Function btif_set_adapter_property
+**
+** Description Updates core stack with property value and stores it in
+** local cache
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+
+bt_status_t btif_set_adapter_property( const bt_property_t *property);
+
+/*******************************************************************************
+**
+** Function btif_get_remote_device_property
+**
+** Description Fetches the remote device property from the NVRAM
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+
+bt_status_t btif_get_remote_device_property( bt_bdaddr_t *remote_addr,
+ bt_property_type_t type);
+
+
+/*******************************************************************************
+**
+** Function btif_get_remote_device_properties
+**
+** Description Fetches all the remote device properties from NVRAM
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+
+bt_status_t btif_get_remote_device_properties( bt_bdaddr_t *remote_addr);
+
+
+/*******************************************************************************
+**
+** Function btif_set_remote_device_property
+**
+** Description Writes the remote device property to NVRAM.
+** Currently, BT_PROPERTY_REMOTE_FRIENDLY_NAME is the only
+** remote device property that can be set
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+
+bt_status_t btif_set_remote_device_property( bt_bdaddr_t *remote_addr,
+ const bt_property_t *property);
+
+
+/*******************************************************************************
+**
+** Function btif_get_remote_service_record
+**
+** Description Looks up the service matching uuid on the remote device
+** and fetches the SCN and service_name if the UUID is found
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+
+bt_status_t btif_get_remote_service_record( bt_bdaddr_t *remote_addr,
+ bt_uuid_t *uuid);
+
+/*****************************************************************************
+** BTIF DM API
+******************************************************************************/
+
+/*******************************************************************************
+**
+** Function btif_dm_start_discovery
+**
+** Description Start device discovery/inquiry
+**
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+
+bt_status_t btif_dm_start_discovery(void);
+
+/*******************************************************************************
+**
+** Function btif_dm_cancel_discovery
+**
+** Description Cancels search
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+
+bt_status_t btif_dm_cancel_discovery(void);
+
+/*******************************************************************************
+**
+** Function btif_dm_create_bond
+**
+** Description Initiate bonding with the specified device
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+
+bt_status_t btif_dm_create_bond(const bt_bdaddr_t *bd_addr);
+
+/*******************************************************************************
+**
+** Function btif_dm_cancel_bond
+**
+** Description Initiate bonding with the specified device
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+
+bt_status_t btif_dm_cancel_bond(const bt_bdaddr_t *bd_addr);
+
+/*******************************************************************************
+**
+** Function btif_dm_remove_bond
+**
+** Description Removes bonding with the specified device
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+
+bt_status_t btif_dm_remove_bond(const bt_bdaddr_t *bd_addr);
+
+/*******************************************************************************
+**
+** Function btif_dm_pin_reply
+**
+** Description BT legacy pairing - PIN code reply
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+
+bt_status_t btif_dm_pin_reply( const bt_bdaddr_t *bd_addr, uint8_t accept,
+ uint8_t pin_len, bt_pin_code_t *pin_code);
+
+/*******************************************************************************
+**
+** Function btif_dm_passkey_reply
+**
+** Description BT SSP passkey reply
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+
+bt_status_t btif_dm_passkey_reply( const bt_bdaddr_t *bd_addr,
+ uint8_t accept, uint32_t passkey);
+
+/*******************************************************************************
+**
+** Function btif_dm_ssp_reply
+**
+** Description BT SSP Reply - Just Works & Numeric Comparison
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+
+bt_status_t btif_dm_ssp_reply( const bt_bdaddr_t *bd_addr,
+ uint8_t accept);
+
+/*******************************************************************************
+**
+** Function btif_dm_get_adapter_property
+**
+** Description Queries the BTA for the adapter property
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+
+bt_status_t btif_dm_get_adapter_property(bt_property_t *prop);
+
+/*******************************************************************************
+**
+** Function btif_dm_get_remote_services
+**
+** Description Start SDP to get remote services
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+
+bt_status_t btif_dm_get_remote_service_record(bt_bdaddr_t *remote_addr,
+ bt_uuid_t *uuid);
+
+#endif /* BTIF_API_H */
+
diff --git a/btif/include/btif_common.h b/btif/include/btif_common.h
new file mode 100644
index 0000000..488adb8
--- /dev/null
+++ b/btif/include/btif_common.h
@@ -0,0 +1,177 @@
+/************************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * This program is the proprietary software of Broadcom Corporation and/or its
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
+ *
+ * Except as expressly set forth in the Authorized License,
+ *
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
+ * Broadcom integrated circuit products.
+ *
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT
+ * OF USE OR PERFORMANCE OF THE SOFTWARE.
+ *
+ * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR
+ * ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+ *
+ ************************************************************************************/
+
+/************************************************************************************
+ *
+ * Filename: btif_common.h
+ *
+ * Description:
+ *
+ ***********************************************************************************/
+
+#ifndef BTIF_COMMON_H
+#define BTIF_COMMON_H
+
+#include "data_types.h"
+#include "bt_types.h"
+#include "bta_api.h"
+
+#ifndef LOG_TAG
+#error "LOG_TAG not defined, please add in .c file prior to including bt_common.h"
+#endif
+
+#include <utils/Log.h>
+
+/************************************************************************************
+** Constants & Macros
+************************************************************************************/
+
+#define ASSERTC(cond, msg, val) if (!(cond)) {LOGE("### ASSERT : %s line %d %s (%d) ###", __FILE__, __LINE__, msg, val);}
+
+/* Calculate start of event enumeration; id is top 8 bits of event */
+#define BTIF_SIG_START(id) ((id) << 8)
+
+/* for upstream the MSB bit is always SET */
+#define BTIF_SIG_CB_BIT (0x8000)
+#define BTIF_SIG_CB_START(id) (((id) << 8) | BTIF_SIG_CB_BIT)
+
+/* BTIF sub-systems */
+#define BTIF_CORE 0 /* core */
+#define BTIF_DM 1
+#define BTIF_HFP 2
+#define BTIF_AV 3
+
+extern bt_callbacks_t *bt_hal_cbacks;
+
+#define CHECK_CALL_CBACK(P_CB, P_CBACK, ...)\
+ if (P_CB && P_CB->P_CBACK) { \
+ P_CB->P_CBACK(__VA_ARGS__); \
+ } \
+ else { \
+ ASSERTC(0, "Callback is NULL", 0); \
+ }
+
+/* btif events for requests that require context switch to btif task
+ on downstreams path */
+enum
+{
+ BTIF_CORE_API_START = BTIF_SIG_START(BTIF_CORE),
+ BTIF_CORE_STORAGE_NO_ACTION,
+ BTIF_CORE_STORAGE_ADAPTER_WRITE,
+ BTIF_CORE_STORAGE_ADAPTER_READ,
+ BTIF_CORE_STORAGE_ADAPTER_READ_ALL,
+ BTIF_CORE_STORAGE_REMOTE_WRITE,
+ BTIF_CORE_STORAGE_REMOTE_READ,
+ BTIF_CORE_STORAGE_REMOTE_READ_ALL,
+ BTIF_CORE_STORAGE_READ_ALL,
+ BTIF_CORE_STORAGE_NOTIFY_STATUS,
+ /* add here */
+
+ BTIF_DM_API_START = BTIF_SIG_START(BTIF_DM),
+ /* add here */
+
+ BTIF_HFP_API_START = BTIF_SIG_START(BTIF_HFP),
+ /* add here */
+
+ BTIF_AV_API_START = BTIF_SIG_START(BTIF_AV),
+ /* add here */
+
+};
+
+/* btif events for callbacks that require context switch to btif task
+ on upstream path - Typically these would be non-BTA events
+ that are generated by the BTIF layer */
+enum
+{
+ BTIF_CORE_CB_START = BTIF_SIG_CB_START(BTIF_CORE),
+ /* add here */
+
+ BTIF_DM_CB_START = BTIF_SIG_CB_START(BTIF_DM),
+ BTIF_DM_CB_DISCOVERY_STARTED, /* Discovery has started */
+ BTIF_DM_CB_BONDING_STARTED, /* Bonding process has started */
+ BTIF_DM_CB_REMOVED_BONDING /* Bonded device deleted */
+};
+
+/************************************************************************************
+** Type definitions for callback functions
+************************************************************************************/
+
+typedef void (tBTIF_CBACK) (UINT16 event, char *p_param);
+typedef void (tBTIF_COPY_CBACK) (UINT16 event, char *p_dest, char *p_src);
+
+/************************************************************************************
+** Type definitions and return values
+************************************************************************************/
+
+/* this type handles all btif context switches between BTU and HAL */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTIF_CBACK* p_cb; /* context switch callback */
+
+ /* parameters passed to callback */
+ UINT16 event; /* message event id */
+ char p_param[0]; /* parameter area needs to be last */
+} tBTIF_CONTEXT_SWITCH_CBACK;
+
+
+/************************************************************************************
+** Functions
+************************************************************************************/
+bt_status_t btif_transfer_context (tBTIF_CBACK *p_cback, UINT16 event, char* p_params, int param_len, tBTIF_COPY_CBACK *p_copy_cback);
+
+/*
+ * BTIF_Events
+ */
+
+void btif_enable_bluetooth_evt(tBTA_STATUS status, BD_ADDR local_bd);
+void btif_disable_bluetooth_evt(void);
+void btif_adapter_properties_evt(bt_status_t status, uint32_t num_props, bt_property_t *p_props);
+void btif_remote_properties_evt(bt_status_t status, bt_bdaddr_t *remote_addr,
+ uint32_t num_props, bt_property_t *p_props);
+#endif /* BTIF_COMMON_H */
+
diff --git a/btif/include/btif_dm.h b/btif/include/btif_dm.h
new file mode 100644
index 0000000..766f4ee
--- /dev/null
+++ b/btif/include/btif_dm.h
@@ -0,0 +1,70 @@
+/************************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * This program is the proprietary software of Broadcom Corporation and/or its
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
+ *
+ * Except as expressly set forth in the Authorized License,
+ *
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
+ * Broadcom integrated circuit products.
+ *
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT
+ * OF USE OR PERFORMANCE OF THE SOFTWARE.
+ *
+ * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR
+ * ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+ *
+ ************************************************************************************/
+
+/************************************************************************************
+ *
+ * Filename: btif_dm.h
+ *
+ * Description:
+ *
+ ***********************************************************************************/
+
+#ifndef BTIF_DM_H
+#define BTIF_DM_H
+
+/************************************************************************************
+** Functions
+************************************************************************************/
+
+/*******************************************************************************
+**
+** Description BTIF callback to switch context from bte to btif
+**
+*******************************************************************************/
+void bte_dm_evt(tBTA_DM_SEC_EVT event, tBTA_DM_SEC *p_data);
+
+#endif
diff --git a/btif/include/btif_storage.h b/btif/include/btif_storage.h
new file mode 100644
index 0000000..c1b5bcf
--- /dev/null
+++ b/btif/include/btif_storage.h
@@ -0,0 +1,189 @@
+/************************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * This program is the proprietary software of Broadcom Corporation and/or its
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
+ *
+ * Except as expressly set forth in the Authorized License,
+ *
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
+ * Broadcom integrated circuit products.
+ *
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT
+ * OF USE OR PERFORMANCE OF THE SOFTWARE.
+ *
+ * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR
+ * ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+ *
+ ************************************************************************************/
+
+/************************************************************************************
+ *
+ * Filename: btif_storage.h
+ *
+ * Description:
+ *
+ ***********************************************************************************/
+
+#ifndef BTIF_STORAGE_H
+#define BTIF_STORAGE_H
+
+#include "data_types.h"
+#include "bt_types.h"
+
+#include <utils/Log.h>
+
+/************************************************************************************
+** Constants & Macros
+************************************************************************************/
+#define BTIF_STORAGE_FILL_PROPERTY(p_prop, t, l, p_v) \
+ (p_prop)->type = t;(p_prop)->len = l; (p_prop)->val = (p_v);
+
+/************************************************************************************
+** Type definitions for callback functions
+************************************************************************************/
+
+/************************************************************************************
+** Type definitions and return values
+************************************************************************************/
+
+/************************************************************************************
+** Functions
+************************************************************************************/
+/*******************************************************************************
+**
+** Function btif_storage_get_adapter_property
+**
+** Description BTIF storage API - Fetches the adapter property->type
+** from NVRAM and fills property->val.
+** Caller should provide memory for property->val and
+** set the property->val
+**
+** Returns BT_STATUS_SUCCESS if the fetch was successful,
+** BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_storage_get_adapter_property(bt_property_t *property);
+/*******************************************************************************
+**
+** Function btif_storage_set_adapter_property
+**
+** Description BTIF storage API - Stores the adapter property
+** to NVRAM
+**
+** Returns BT_STATUS_SUCCESS if the store was successful,
+** BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_storage_set_adapter_property(bt_property_t *property);
+/*******************************************************************************
+**
+** Function btif_storage_get_remote_device_property
+**
+** Description BTIF storage API - Fetches the remote device property->type
+** from NVRAM and fills property->val.
+** Caller should provide memory for property->val and
+** set the property->val
+**
+** Returns BT_STATUS_SUCCESS if the fetch was successful,
+** BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_storage_get_remote_device_property(bt_bdaddr_t *remote_bd_addr,
+ bt_property_t *property);
+/*******************************************************************************
+**
+** Function btif_storage_set_remote_device_property
+**
+** Description BTIF storage API - Stores the remote device property
+** to NVRAM
+**
+** Returns BT_STATUS_SUCCESS if the store was successful,
+** BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_storage_set_remote_device_property(bt_bdaddr_t *remote_bd_addr,
+ bt_property_t *property);
+/*******************************************************************************
+**
+** Function btif_storage_add_remote_device
+**
+** Description BTIF storage API - Adds a newly discovered device to NVRAM
+** along with the timestamp. Also, stores the various
+** properties - RSSI, BDADDR, NAME (if found in EIR)
+**
+** Returns BT_STATUS_SUCCESS if the store was successful,
+** BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_storage_add_remote_device(bt_bdaddr_t *remote_bdaddr,
+ uint32_t num_properties,
+ bt_property_t *properties);
+/*******************************************************************************
+**
+** Function btif_storage_add_bonded_device
+**
+** Description BTIF storage API - Adds the newly bonded device to NVRAM
+** along with the link-key, Key type and Pin key length
+**
+** Returns BT_STATUS_SUCCESS if the store was successful,
+** BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_storage_add_bonded_device(bt_bdaddr_t *remote_bd_addr,
+ LINK_KEY link_key,
+ uint8_t key_type,
+ uint8_t pin_length);
+/*******************************************************************************
+**
+** Function btif_storage_remove_bonded_device
+**
+** Description BTIF storage API - Deletes the bonded device from NVRAM
+**
+** Returns BT_STATUS_SUCCESS if the deletion was successful,
+** BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_storage_remove_bonded_device(bt_bdaddr_t *remote_bd_addr);
+/*******************************************************************************
+**
+** Function btif_storage_remove_bonded_device
+**
+** Description BTIF storage API - Deletes the bonded device from NVRAM
+**
+** Returns BT_STATUS_SUCCESS if the deletion was successful,
+** BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_storage_load_bonded_devices(void);
+
+#endif /* BTIF_STORAGE_H */
+
diff --git a/btif/include/btif_util.h b/btif/include/btif_util.h
new file mode 100644
index 0000000..95a1279
--- /dev/null
+++ b/btif/include/btif_util.h
@@ -0,0 +1,107 @@
+/************************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * This program is the proprietary software of Broadcom Corporation and/or its
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
+ *
+ * Except as expressly set forth in the Authorized License,
+ *
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
+ * Broadcom integrated circuit products.
+ *
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT
+ * OF USE OR PERFORMANCE OF THE SOFTWARE.
+ *
+ * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR
+ * ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+ *
+ ************************************************************************************/
+
+/************************************************************************************
+ *
+ * Filename: btif_util.h
+ *
+ * Description:
+ *
+ ***********************************************************************************/
+
+#ifndef BTIF_UTIL_H
+#define BTIF_UTIL_H
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_hf.h>
+#include <utils/Log.h>
+
+#include "data_types.h"
+#include "bt_types.h"
+
+/************************************************************************************
+** Constants & Macros
+************************************************************************************/
+
+#define CASE_RETURN_STR(const) case const: return #const;
+
+/************************************************************************************
+** Type definitions for callback functions
+************************************************************************************/
+
+typedef char bdstr_t[18];
+
+/************************************************************************************
+** Type definitions and return values
+************************************************************************************/
+
+
+/************************************************************************************
+** Functions
+************************************************************************************/
+
+const char* dump_bt_status(bt_status_t status);
+const char* dump_dm_search_event(UINT16 event);
+const char* dump_hf_event(UINT16 event);
+const char* dump_hf_conn_state(UINT16 event);
+const char* dump_hf_call_state(bthf_call_state_t call_state);
+const char* dump_property_type(bt_property_type_t type);
+const char* dump_hf_audio_state(UINT16 event);
+const char* dump_adapter_scan_mode(bt_scan_mode_t mode);
+const char* dump_thread_evt(bt_cb_thread_evt evt);
+
+int str2bd(char *str, bt_bdaddr_t *addr);
+char *bd2str(bt_bdaddr_t *addr, bdstr_t *bdstr);
+
+UINT32 devclass2uint(DEV_CLASS dev_class);
+void uuid16_to_uuid128(uint16_t uuid16, bt_uuid_t* uuid128);
+
+void uuid_to_string(bt_uuid_t *p_uuid, char *str);
+void string_to_uuid(char *str, bt_uuid_t *p_uuid);
+
+#endif /* BTIF_UTIL_H */
+
diff --git a/btif/src/bluetooth.c b/btif/src/bluetooth.c
new file mode 100644
index 0000000..766f685
--- /dev/null
+++ b/btif/src/bluetooth.c
@@ -0,0 +1,381 @@
+/************************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * This program is the proprietary software of Broadcom Corporation and/or its
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
+ *
+ * Except as expressly set forth in the Authorized License,
+ *
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
+ * Broadcom integrated circuit products.
+ *
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT
+ * OF USE OR PERFORMANCE OF THE SOFTWARE.
+ *
+ * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR
+ * ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+ *
+ ************************************************************************************/
+
+/************************************************************************************
+ *
+ * Filename: bluetooth.c
+ *
+ * Description: Bluetooth HAL implementation
+ *
+ ***********************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_hf.h>
+
+#define LOG_NDDEBUG 0
+#define LOG_TAG "bluedroid"
+
+#include "btif_api.h"
+
+/************************************************************************************
+** Constants & Macros
+************************************************************************************/
+
+#define is_profile(profile, str) ((strlen(str) == strlen(profile)) && strncmp((const char *)profile, str, strlen(str)) == 0)
+
+/************************************************************************************
+** Local type definitions
+************************************************************************************/
+
+/************************************************************************************
+** Static variables
+************************************************************************************/
+
+bt_callbacks_t *bt_hal_cbacks = NULL;
+
+/************************************************************************************
+** Static functions
+************************************************************************************/
+
+/************************************************************************************
+** Externs
+************************************************************************************/
+
+/* list all extended interfaces here */
+
+/* handsfree profile */
+extern bthf_interface_t *btif_hf_get_interface();
+
+/************************************************************************************
+** Functions
+************************************************************************************/
+
+static uint8_t interface_ready(void)
+{
+ /* add checks here that would prevent API calls other than init to be executed */
+ if (bt_hal_cbacks == NULL)
+ return FALSE;
+
+ return TRUE;
+}
+
+
+/*****************************************************************************
+**
+** BLUETOOTH HAL INTERFACE FUNCTIONS
+**
+*****************************************************************************/
+
+static int init(bt_callbacks_t* callbacks )
+{
+ LOGI("init");
+
+ /* store reference to user callbacks */
+ bt_hal_cbacks = callbacks;
+
+ /* add checks for individual callbacks ? */
+
+ /* init btif */
+ btif_init_bluetooth();
+
+ return BT_STATUS_SUCCESS;
+}
+
+static int enable( void )
+{
+ LOGI("enable");
+
+ /* sanity check */
+ if (interface_ready() == FALSE)
+ return BT_STATUS_NOT_READY;
+
+ return btif_enable_bluetooth();
+}
+
+static int disable(void)
+{
+ /* sanity check */
+ if (interface_ready() == FALSE)
+ return BT_STATUS_NOT_READY;
+
+ return btif_disable_bluetooth();
+}
+
+static void cleanup( void )
+{
+ /* sanity check */
+ if (interface_ready() == FALSE)
+ return;
+
+ btif_shutdown_bluetooth();
+
+ /* hal callbacks reset upon shutdown complete callback */
+
+ return;
+}
+
+static int get_adapter_properties(void)
+{
+ /* sanity check */
+ if (interface_ready() == FALSE)
+ return BT_STATUS_NOT_READY;
+
+ return btif_get_adapter_properties();
+}
+
+static int get_adapter_property(bt_property_type_t type)
+{
+ /* sanity check */
+ if (interface_ready() == FALSE)
+ return BT_STATUS_NOT_READY;
+
+ return btif_get_adapter_property(type);
+}
+
+static int set_adapter_property(const bt_property_t *property)
+{
+ /* sanity check */
+ if (interface_ready() == FALSE)
+ return BT_STATUS_NOT_READY;
+
+ return btif_set_adapter_property(property);
+}
+
+int get_remote_device_properties(bt_bdaddr_t *remote_addr)
+{
+ /* sanity check */
+ if (interface_ready() == FALSE)
+ return BT_STATUS_NOT_READY;
+
+ return btif_get_remote_device_properties(remote_addr);
+}
+
+int get_remote_device_property(bt_bdaddr_t *remote_addr, bt_property_type_t type)
+{
+ /* sanity check */
+ if (interface_ready() == FALSE)
+ return BT_STATUS_NOT_READY;
+
+ return btif_get_remote_device_property(remote_addr, type);
+}
+
+int set_remote_device_property(bt_bdaddr_t *remote_addr, const bt_property_t *property)
+{
+ /* sanity check */
+ if (interface_ready() == FALSE)
+ return BT_STATUS_NOT_READY;
+
+ return btif_set_remote_device_property(remote_addr, property);
+}
+
+int get_remote_service_record(bt_bdaddr_t *remote_addr, bt_uuid_t *uuid)
+{
+ /* sanity check */
+ if (interface_ready() == FALSE)
+ return BT_STATUS_NOT_READY;
+
+ return btif_get_remote_service_record(remote_addr, uuid);
+}
+
+static int start_discovery(void)
+{
+ /* sanity check */
+ if (interface_ready() == FALSE)
+ return BT_STATUS_NOT_READY;
+
+ return btif_dm_start_discovery();
+}
+
+static int cancel_discovery(void)
+{
+ /* sanity check */
+ if (interface_ready() == FALSE)
+ return BT_STATUS_NOT_READY;
+
+ return btif_dm_cancel_discovery();
+}
+
+static int create_bond(const bt_bdaddr_t *bd_addr)
+{
+ /* sanity check */
+ if (interface_ready() == FALSE)
+ return BT_STATUS_NOT_READY;
+
+ return btif_dm_create_bond(bd_addr);
+}
+
+static int cancel_bond(const bt_bdaddr_t *bd_addr)
+{
+ /* sanity check */
+ if (interface_ready() == FALSE)
+ return BT_STATUS_NOT_READY;
+
+ return btif_dm_cancel_bond(bd_addr);
+}
+
+static int remove_bond(const bt_bdaddr_t *bd_addr)
+{
+ /* sanity check */
+ if (interface_ready() == FALSE)
+ return BT_STATUS_NOT_READY;
+
+ return btif_dm_remove_bond(bd_addr);
+}
+
+static int pin_reply(const bt_bdaddr_t *bd_addr, uint8_t accept,
+ uint8_t pin_len, bt_pin_code_t *pin_code)
+{
+ /* sanity check */
+ if (interface_ready() == FALSE)
+ return BT_STATUS_NOT_READY;
+
+ return btif_dm_pin_reply(bd_addr, accept, pin_len, pin_code);
+}
+
+static int passkey_reply(const bt_bdaddr_t *bd_addr, uint8_t accept,
+ uint32_t passkey)
+{
+ /* sanity check */
+ if (interface_ready() == FALSE)
+ return BT_STATUS_NOT_READY;
+
+ return btif_dm_passkey_reply(bd_addr, accept, passkey);
+}
+
+static int ssp_reply(const bt_bdaddr_t *bd_addr, uint8_t accept)
+{
+ /* sanity check */
+ if (interface_ready() == FALSE)
+ return BT_STATUS_NOT_READY;
+
+ return btif_dm_ssp_reply(bd_addr, accept);
+}
+
+static const void* get_profile_interface (const char *profile_id)
+{
+ LOGI("get_profile_interface %s", profile_id);
+
+ /* check for supported profile interfaces */
+ if (is_profile(profile_id, BT_PROFILE_HANDSFREE_ID))
+ return btif_hf_get_interface();
+
+ if (is_profile(profile_id, BT_PROFILE_ADVANCED_AUDIO_ID))
+ return NULL;
+
+ return NULL;
+}
+
+static const bt_interface_t bluetoothInterface = {
+ sizeof(bt_interface_t),
+ init,
+ enable,
+ disable,
+ cleanup,
+ get_adapter_properties,
+ get_adapter_property,
+ set_adapter_property,
+ get_remote_device_properties,
+ get_remote_device_property,
+ set_remote_device_property,
+ get_remote_service_record,
+ start_discovery,
+ cancel_discovery,
+ create_bond,
+ remove_bond,
+ cancel_bond,
+ pin_reply,
+ passkey_reply,
+ ssp_reply,
+ get_profile_interface
+};
+
+const bt_interface_t* bluetooth__get_bluetooth_interface ()
+{
+ /* fixme -- add property to disable bt interface ? */
+
+ return &bluetoothInterface;
+}
+
+static int close_bluetooth_stack(struct hw_device_t* device)
+{
+ cleanup();
+ return 0;
+}
+
+static int open_bluetooth_stack (const struct hw_module_t* module, char const* name,
+struct hw_device_t** abstraction)
+{
+ bluetooth_device_t *stack = malloc(sizeof(bluetooth_device_t) );
+ memset(stack, 0, sizeof(bluetooth_device_t) );
+ stack->common.tag = HARDWARE_DEVICE_TAG;
+ stack->common.version = 0;
+ stack->common.module = (struct hw_module_t*)module;
+ stack->common.close = close_bluetooth_stack;
+ stack->get_bluetooth_interface = bluetooth__get_bluetooth_interface;
+ *abstraction = (struct hw_device_t*)stack;
+ return 0;
+}
+
+
+static struct hw_module_methods_t bt_stack_module_methods = {
+ .open = open_bluetooth_stack,
+};
+
+const struct hw_module_t HAL_MODULE_INFO_SYM = {
+ .tag = HARDWARE_MODULE_TAG,
+ .version_major = 1,
+ .version_minor = 0,
+ .id = BT_HARDWARE_MODULE_ID,
+ .name = "Bluetooth Stack",
+ .author = "The Android Open Source Project",
+ .methods = &bt_stack_module_methods
+};
+
diff --git a/btif/src/btif_core.c b/btif/src/btif_core.c
new file mode 100644
index 0000000..570a7c5
--- /dev/null
+++ b/btif/src/btif_core.c
@@ -0,0 +1,1038 @@
+/************************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * This program is the proprietary software of Broadcom Corporation and/or its
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
+ *
+ * Except as expressly set forth in the Authorized License,
+ *
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
+ * Broadcom integrated circuit products.
+ *
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT
+ * OF USE OR PERFORMANCE OF THE SOFTWARE.
+ *
+ * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR
+ * ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+ *
+ ************************************************************************************/
+
+/************************************************************************************
+ *
+ * Filename: btif_core.c
+ *
+ * Description: Contains core functionality related to interfacing between
+ * Bluetooth HAL and BTE core stack.
+ *
+ ***********************************************************************************/
+
+#include <hardware/bluetooth.h>
+#include <string.h>
+
+#define LOG_TAG "BTIF_CORE"
+
+#include "btif_api.h"
+#include "bta_api.h"
+#include "gki.h"
+#include "btu.h"
+#include "bte.h"
+#include "bd.h"
+#include "btif_storage.h"
+#include "btif_util.h"
+
+/************************************************************************************
+** Constants & Macros
+************************************************************************************/
+
+#ifndef BTIF_TASK_STACK_SIZE
+#define BTIF_TASK_STACK_SIZE 0//0x2000 /* In bytes */
+#endif
+
+#define BTIF_TASK_STR ((INT8 *) "BTIF")
+
+static UINT32 btif_task_stack[(BTIF_TASK_STACK_SIZE + 3) / 4];
+
+/* checks whether any HAL operation other than enable is permitted */
+static int btif_enabled = 0;
+static int btif_shutdown_pending = 0;
+
+/************************************************************************************
+** Local type definitions
+************************************************************************************/
+/* These type definitions are used when passing data from the HAL to BTIF context
+* in the downstream path for the adapter and remote_device property APIs */
+typedef struct {
+ bt_bdaddr_t bd_addr;
+ bt_property_type_t type;
+} btif_storage_read_t;
+
+typedef struct {
+ bt_bdaddr_t bd_addr;
+ bt_property_t prop;
+} btif_storage_write_t;
+
+typedef union {
+ btif_storage_read_t read_req;
+ btif_storage_write_t write_req;
+} btif_storage_req_t;
+/************************************************************************************
+** Static variables
+************************************************************************************/
+
+/************************************************************************************
+** Static functions
+************************************************************************************/
+static bt_status_t btif_init_bluetooth_evt(void);
+static bt_status_t btif_shutdown_bluetooth_evt(void);
+
+/* sends message to btif task */
+static void btif_sendmsg(void *p_msg);
+
+/************************************************************************************
+** Externs
+************************************************************************************/
+
+/** TODO: Move these to _common.h */
+void bte_main_boot_entry(void);
+void bte_main_enable(void);
+void bte_main_disable(void);
+void bte_main_shutdown(void);
+#if (defined(HCILP_INCLUDED) && HCILP_INCLUDED == TRUE)
+void bte_main_enable_lpm(BOOLEAN enable);
+#endif
+void bte_main_postload_cfg(void);
+
+/************************************************************************************
+** Functions
+************************************************************************************/
+
+
+/*****************************************************************************
+** Context switching functions
+*****************************************************************************/
+
+
+/*******************************************************************************
+**
+** Function btif_context_switched
+**
+** Description Callback used to execute transferred context callback
+**
+** p_msg : message to be executed in btif context
+**
+** Returns void
+**
+*******************************************************************************/
+
+static void btif_context_switched(void *p_msg)
+{
+ tBTIF_CONTEXT_SWITCH_CBACK *p;
+
+ BTIF_TRACE_VERBOSE0("btif_context_switched");
+
+ p = (tBTIF_CONTEXT_SWITCH_CBACK *) p_msg;
+
+ /* each callback knows how to parse the data */
+ if (p->p_cb)
+ p->p_cb(p->event, p->p_param);
+}
+
+
+/*******************************************************************************
+**
+** Function btif_transfer_context
+**
+** Description This function switches context to btif task
+**
+** p_cback : callback used to process message in btif context
+** event : event id of message
+** p_params : parameter area passed to callback (copied)
+** param_len : length of parameter area
+** p_copy_cback : If set this function will be invoked for deep copy
+**
+** Returns void
+**
+*******************************************************************************/
+
+bt_status_t btif_transfer_context (tBTIF_CBACK *p_cback, UINT16 event, char* p_params, int param_len, tBTIF_COPY_CBACK *p_copy_cback)
+{
+ tBTIF_CONTEXT_SWITCH_CBACK *p_msg;
+
+ BTIF_TRACE_VERBOSE2("btif_transfer_context event %d, len %d", event, param_len);
+
+ /* allocate and send message that will be executed in btif context */
+ if ((p_msg = (tBTIF_CONTEXT_SWITCH_CBACK *) GKI_getbuf(sizeof(tBTIF_CONTEXT_SWITCH_CBACK) + param_len)) != NULL)
+ {
+ p_msg->hdr.event = BT_EVT_CONTEXT_SWITCH_EVT; /* internal event */
+ p_msg->p_cb = p_cback;
+
+ p_msg->event = event; /* callback event */
+
+ /* check if caller has provided a copy callback to do the deep copy */
+ if (p_copy_cback)
+ {
+ p_copy_cback(event, p_msg->p_param, p_params);
+ }
+ else if (p_params)
+ {
+ memcpy(p_msg->p_param, p_params, param_len); /* callback parameter data */
+ }
+
+ btif_sendmsg(p_msg);
+ return BT_STATUS_SUCCESS;
+ }
+ else
+ {
+ /* let caller deal with a failed allocation */
+ return BT_STATUS_NOMEM;
+ }
+}
+
+/*******************************************************************************
+**
+** Function btif_task
+**
+** Description BTIF task handler managing all messages being passed
+** Bluetooth HAL and BTA.
+**
+** Returns void
+**
+*******************************************************************************/
+
+static void btif_task(UINT32 params)
+{
+ UINT16 event;
+ BT_HDR *p_msg;
+
+ BTIF_TRACE_DEBUG0("btif task starting");
+
+ btif_init_bluetooth_evt();
+
+ for(;;)
+ {
+ /* wait for specified events */
+ event = GKI_wait(0xFFFF, 0);
+
+ /*
+ * Wait for the trigger to init chip and stack. This trigger will
+ * be received by btu_task once the UART is opened and ready
+ */
+
+ if (event == BT_EVT_TRIGGER_STACK_INIT)
+ {
+ BTIF_TRACE_DEBUG0("btif_task: received trigger stack init event");
+ BTA_EnableBluetooth(bte_dm_evt);
+ }
+
+ if (event & EVENT_MASK(GKI_SHUTDOWN_EVT))
+ break;
+
+ if(event & TASK_MBOX_1_EVT_MASK)
+ {
+ while((p_msg = GKI_read_mbox(BTU_BTIF_MBOX)) != NULL)
+ {
+ BTIF_TRACE_VERBOSE1("btif task fetched event %x", p_msg->event);
+
+ switch (p_msg->event)
+ {
+ case BT_EVT_CONTEXT_SWITCH_EVT:
+ btif_context_switched(p_msg);
+ break;
+ default:
+ BTIF_TRACE_ERROR1("unhandled btif event (%d)", p_msg->event & BT_EVT_MASK);
+ break;
+ }
+
+ GKI_freebuf(p_msg);
+ }
+ }
+ }
+ btif_shutdown_bluetooth_evt();
+}
+
+
+/*******************************************************************************
+**
+** Function btif_sendmsg
+**
+** Description Sends msg to BTIF task
+**
+** Returns void
+**
+*******************************************************************************/
+
+void btif_sendmsg(void *p_msg)
+{
+ GKI_send_msg(BTIF_TASK, BTU_BTIF_MBOX, p_msg);
+}
+
+/*****************************************************************************
+**
+** btif core api functions
+**
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function btif_init_bluetooth
+**
+** Description Creates BTIF task and prepares BT scheduler for startup
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+
+bt_status_t btif_init_bluetooth(void)
+{
+ UINT8 status;
+
+ bte_main_boot_entry();
+
+ /* Start the BTIF task */
+ status = GKI_create_task(btif_task, BTIF_TASK, BTIF_TASK_STR,
+ (UINT16 *) ((UINT8 *)btif_task_stack + BTIF_TASK_STACK_SIZE),
+ sizeof(btif_task_stack));
+
+ if (status != GKI_SUCCESS)
+ return BT_STATUS_FAIL;
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function btif_init_bluetooth_evt
+**
+** Description Event indicating bluetooth init is completed
+** Attach btif_task to JVM
+**
+** Returns void
+**
+*******************************************************************************/
+
+static bt_status_t btif_init_bluetooth_evt(void)
+{
+ BTIF_TRACE_DEBUG1("%s: notify ASSOCIATE_JVM", __FUNCTION__);
+ CHECK_CALL_CBACK(bt_hal_cbacks, thread_evt_cb, ASSOCIATE_JVM);
+
+ return BT_STATUS_SUCCESS;
+}
+
+
+/*******************************************************************************
+**
+** Function btif_enable_bluetooth
+**
+** Description Performs chip power on and kickstarts OS scheduler
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+
+bt_status_t btif_enable_bluetooth(void)
+{
+ tBTA_STATUS status = BT_STATUS_SUCCESS;
+
+ LOGI("btif_enable_bluetooth");
+
+ if (btif_enabled == 1)
+ {
+ LOGD("already enabled\n");
+ return BT_STATUS_DONE;
+ }
+
+ /* add return status for create tasks functions ? */
+
+ /* Create the GKI tasks and run them */
+ bte_main_enable();
+
+ if (status != BTA_SUCCESS)
+ return BT_STATUS_FAIL;
+
+ return BT_STATUS_SUCCESS;
+}
+
+
+/*******************************************************************************
+**
+** Function btif_enable_bluetooth_evt
+**
+** Description Event indicating bluetooth enable is completed
+** Notifies HAL user with updated adapter state
+**
+** Returns void
+**
+*******************************************************************************/
+
+void btif_enable_bluetooth_evt(tBTA_STATUS status, BD_ADDR local_bd)
+{
+ bt_bdaddr_t bd_addr;
+ bdstr_t bdstr;
+
+ bdcpy(bd_addr.address, local_bd);
+ BTIF_TRACE_DEBUG3("%s: status %d, local bd [%s]", __FUNCTION__, status,
+ bd2str(&bd_addr, &bdstr));
+
+ bte_main_postload_cfg();
+#if (defined(HCILP_INCLUDED) && HCILP_INCLUDED == TRUE)
+ bte_main_enable_lpm(TRUE);
+#endif
+ /* add passing up bd address as well ? */
+
+ /* callback to HAL */
+ if (status == BTA_SUCCESS)
+ {
+ /* store state */
+ btif_enabled = 1;
+ CHECK_CALL_CBACK(bt_hal_cbacks, adapter_state_changed_cb, BT_STATE_ON);
+ }
+ else
+ {
+ btif_enabled = 0;
+ CHECK_CALL_CBACK(bt_hal_cbacks, adapter_state_changed_cb, BT_STATE_OFF);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btif_disable_bluetooth
+**
+** Description Inititates shutdown of Bluetooth system.
+** Any active links will be dropped and device entering
+** non connectable/discoverable mode
+**
+** Returns void
+**
+*******************************************************************************/
+
+bt_status_t btif_disable_bluetooth(void)
+{
+ tBTA_STATUS status;
+
+ if (btif_enabled == 0)
+ {
+ BTIF_TRACE_ERROR0("btif_disable_bluetooth : not yet enabled");
+ return BT_STATUS_FAIL;
+ }
+
+ BTIF_TRACE_DEBUG1("%s", __FUNCTION__);
+
+ status = BTA_DisableBluetooth();
+
+ if (status != BTA_SUCCESS)
+ {
+ BTIF_TRACE_ERROR1("disable bt failed (%d)", status);
+ return BT_STATUS_FAIL;
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function btif_disable_bluetooth_evt
+**
+** Description Event notifying BT disable is now complete.
+** Terminates main stack tasks and notifies HAL
+** user with updated BT state.
+**
+** Returns void
+**
+*******************************************************************************/
+
+void btif_disable_bluetooth_evt(void)
+{
+ BTIF_TRACE_DEBUG1("%s", __FUNCTION__);
+
+ bte_main_disable();
+
+ /* callback to HAL */
+ CHECK_CALL_CBACK(bt_hal_cbacks, adapter_state_changed_cb, BT_STATE_OFF);
+
+ /* update local state */
+ btif_enabled = 0;
+
+ if (btif_shutdown_pending)
+ {
+ btif_shutdown_bluetooth();
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function btif_shutdown_bluetooth
+**
+** Description Finalizes BT scheduler shutdown and terminates BTIF
+** task.
+**
+** Returns void
+**
+*******************************************************************************/
+
+bt_status_t btif_shutdown_bluetooth(void)
+{
+ BTIF_TRACE_DEBUG1("%s", __FUNCTION__);
+
+ if (btif_enabled)
+ {
+ BTIF_TRACE_WARNING0("shutdown while still enabled, initiate disable");
+
+ /* shutdown called prior to disabling, initiate disable */
+ btif_disable_bluetooth();
+ btif_shutdown_pending = 1;
+ return BT_STATUS_SUCCESS;
+ }
+
+ btif_shutdown_pending = 0;
+
+ GKI_destroy_task(BTIF_TASK);
+
+ bte_main_shutdown();
+
+ return BT_STATUS_SUCCESS;
+}
+
+static bt_status_t btif_shutdown_bluetooth_evt(void)
+{
+ BTIF_TRACE_DEBUG1("%s: notify DISASSOCIATE_JVM", __FUNCTION__);
+
+ CHECK_CALL_CBACK(bt_hal_cbacks, thread_evt_cb, DISASSOCIATE_JVM);
+
+ /* shutdown complete, all events notified and we reset HAL callbacks */
+ bt_hal_cbacks = NULL;
+
+ return BT_STATUS_SUCCESS;
+}
+
+
+
+/*****************************************************************************
+**
+** btif api adapter property functions
+**
+*****************************************************************************/
+
+static bt_status_t btif_in_get_adapter_properties(void)
+{
+ bt_property_t properties[6];
+ uint32_t num_props;
+
+ bt_bdaddr_t addr;
+ bt_bdname_t name;
+ bt_scan_mode_t mode;
+ uint32_t disc_timeout;
+ bt_bdaddr_t bonded_devices[BTM_SEC_MAX_DEVICE_RECORDS];
+ bt_uuid_t local_uuids[BT_MAX_NUM_UUIDS];
+ num_props = 0;
+
+ /* BD_ADDR */
+ BTIF_STORAGE_FILL_PROPERTY(&properties[num_props], BT_PROPERTY_BDADDR,
+ sizeof(addr), &addr);
+ btif_storage_get_adapter_property(&properties[num_props]);
+ num_props++;
+
+ /* BD_NAME */
+ BTIF_STORAGE_FILL_PROPERTY(&properties[num_props], BT_PROPERTY_BDNAME,
+ sizeof(name), &name);
+ btif_storage_get_adapter_property(&properties[num_props]);
+ num_props++;
+
+ /* SCAN_MODE */
+ BTIF_STORAGE_FILL_PROPERTY(&properties[num_props], BT_PROPERTY_ADAPTER_SCAN_MODE,
+ sizeof(mode), &mode);
+ btif_storage_get_adapter_property(&properties[num_props]);
+ num_props++;
+
+ /* DISC_TIMEOUT */
+ BTIF_STORAGE_FILL_PROPERTY(&properties[num_props], BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT,
+ sizeof(disc_timeout), &disc_timeout);
+ btif_storage_get_adapter_property(&properties[num_props]);
+ num_props++;
+
+ /* BONDED_DEVICES */
+ BTIF_STORAGE_FILL_PROPERTY(&properties[num_props], BT_PROPERTY_ADAPTER_BONDED_DEVICES,
+ sizeof(bonded_devices), bonded_devices);
+ btif_storage_get_adapter_property(&properties[num_props]);
+ num_props++;
+
+ /* LOCAL UUIDs */
+ BTIF_STORAGE_FILL_PROPERTY(&properties[num_props], BT_PROPERTY_UUIDS,
+ sizeof(local_uuids), local_uuids);
+ btif_storage_get_adapter_property(&properties[num_props]);
+ num_props++;
+
+ CHECK_CALL_CBACK(bt_hal_cbacks, adapter_properties_cb,
+ BT_STATUS_SUCCESS, num_props, properties);
+
+ return BT_STATUS_SUCCESS;
+}
+
+static bt_status_t btif_in_get_remote_device_properties(bt_bdaddr_t *bd_addr)
+{
+ bt_property_t remote_properties[8];
+ uint32_t num_props = 0;
+
+ bt_bdname_t name, alias;
+ uint32_t cod, devtype;
+ bt_uuid_t remote_uuids[BT_MAX_NUM_UUIDS];
+
+ memset(remote_properties, 0, sizeof(remote_properties));
+ BTIF_STORAGE_FILL_PROPERTY(&remote_properties[num_props], BT_PROPERTY_BDNAME,
+ sizeof(name), &name);
+ btif_storage_get_remote_device_property(bd_addr,
+ &remote_properties[num_props]);
+ num_props++;
+
+ BTIF_STORAGE_FILL_PROPERTY(&remote_properties[num_props], BT_PROPERTY_REMOTE_FRIENDLY_NAME,
+ sizeof(alias), &alias);
+ btif_storage_get_remote_device_property(bd_addr,
+ &remote_properties[num_props]);
+ num_props++;
+
+ BTIF_STORAGE_FILL_PROPERTY(&remote_properties[num_props], BT_PROPERTY_CLASS_OF_DEVICE,
+ sizeof(cod), &cod);
+ btif_storage_get_remote_device_property(bd_addr,
+ &remote_properties[num_props]);
+ num_props++;
+
+ BTIF_STORAGE_FILL_PROPERTY(&remote_properties[num_props], BT_PROPERTY_TYPE_OF_DEVICE,
+ sizeof(devtype), &devtype);
+ btif_storage_get_remote_device_property(bd_addr,
+ &remote_properties[num_props]);
+ num_props++;
+
+ BTIF_STORAGE_FILL_PROPERTY(&remote_properties[num_props], BT_PROPERTY_UUIDS,
+ sizeof(remote_uuids), remote_uuids);
+ btif_storage_get_remote_device_property(bd_addr,
+ &remote_properties[num_props]);
+ num_props++;
+
+ CHECK_CALL_CBACK(bt_hal_cbacks, remote_device_properties_cb,
+ BT_STATUS_SUCCESS, bd_addr, num_props, remote_properties);
+
+ return BT_STATUS_SUCCESS;
+}
+
+
+/*******************************************************************************
+**
+** Function execute_storage_request
+**
+** Description Executes adapter storage request in BTIF context
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+
+static void execute_storage_request(UINT16 event, char *p_param)
+{
+ uint8_t is_local;
+ int num_entries = 0;
+ bt_status_t status = BT_STATUS_SUCCESS;
+
+ BTIF_TRACE_EVENT1("execute storage request event : %d", event);
+
+ switch(event)
+ {
+ case BTIF_CORE_STORAGE_ADAPTER_WRITE:
+ {
+ btif_storage_req_t *p_req = (btif_storage_req_t*)p_param;
+ bt_property_t *p_prop = &(p_req->write_req.prop);
+ BTIF_TRACE_EVENT3("type: %d, len %d, 0x%x", p_prop->type,
+ p_prop->len, p_prop->val);
+
+ status = btif_storage_set_adapter_property(p_prop);
+ CHECK_CALL_CBACK(bt_hal_cbacks, adapter_properties_cb, status, 1, p_prop);
+ } break;
+
+ case BTIF_CORE_STORAGE_ADAPTER_READ:
+ {
+ btif_storage_req_t *p_req = (btif_storage_req_t*)p_param;
+ char buf[512];
+ bt_property_t prop;
+ prop.type = p_req->read_req.type;
+ prop.val = (void*)buf;
+ prop.len = sizeof(buf);
+
+ status = btif_storage_get_adapter_property(&prop);
+ CHECK_CALL_CBACK(bt_hal_cbacks, adapter_properties_cb, status, 1, &prop);
+ } break;
+
+ case BTIF_CORE_STORAGE_ADAPTER_READ_ALL:
+ {
+ status = btif_in_get_adapter_properties();
+ } break;
+
+ case BTIF_CORE_STORAGE_NOTIFY_STATUS:
+ {
+ CHECK_CALL_CBACK(bt_hal_cbacks, adapter_properties_cb, status, 0, NULL);
+ } break;
+
+ default:
+ BTIF_TRACE_ERROR2("%s invalid event id (%d)", __FUNCTION__, event);
+ break;
+ }
+}
+
+static void execute_storage_remote_request(UINT16 event, char *p_param)
+{
+ bt_status_t status = BT_STATUS_FAIL;
+ bt_property_t prop;
+
+ BTIF_TRACE_EVENT1("execute storage remote request event : %d", event);
+
+ switch (event)
+ {
+ case BTIF_CORE_STORAGE_REMOTE_READ:
+ {
+ char buf[1024];
+ btif_storage_req_t *p_req = (btif_storage_req_t*)p_param;
+ prop.type = p_req->read_req.type;
+ prop.val = (void*) buf;
+ prop.len = sizeof(buf);
+
+ status = btif_storage_get_remote_device_property(&(p_req->read_req.bd_addr),
+ &prop);
+ CHECK_CALL_CBACK(bt_hal_cbacks, remote_device_properties_cb,
+ status, &(p_req->read_req.bd_addr), 1, &prop);
+ }break;
+ case BTIF_CORE_STORAGE_REMOTE_WRITE:
+ {
+ btif_storage_req_t *p_req = (btif_storage_req_t*)p_param;
+ status = btif_storage_set_remote_device_property(&(p_req->write_req.bd_addr),
+ &(p_req->write_req.prop));
+ }break;
+ case BTIF_CORE_STORAGE_REMOTE_READ_ALL:
+ {
+ btif_storage_req_t *p_req = (btif_storage_req_t*)p_param;
+ btif_in_get_remote_device_properties(&p_req->read_req.bd_addr);
+ }break;
+ }
+}
+
+void btif_adapter_properties_evt(bt_status_t status, uint32_t num_props,
+ bt_property_t *p_props)
+{
+ CHECK_CALL_CBACK(bt_hal_cbacks, adapter_properties_cb,
+ status, num_props, p_props);
+
+}
+void btif_remote_properties_evt(bt_status_t status, bt_bdaddr_t *remote_addr,
+ uint32_t num_props, bt_property_t *p_props)
+{
+ CHECK_CALL_CBACK(bt_hal_cbacks, remote_device_properties_cb,
+ status, remote_addr, num_props, p_props);
+}
+
+/*******************************************************************************
+**
+** Function btif_in_storage_request_copy_cb
+**
+** Description Switch context callback function to perform the deep copy for
+** both the adapter and remote_device property API
+**
+** Returns None
+**
+*******************************************************************************/
+static void btif_in_storage_request_copy_cb(UINT16 event,
+ char *p_new_buf, char *p_old_buf)
+{
+ btif_storage_req_t *new_req = (btif_storage_req_t*)p_new_buf;
+ btif_storage_req_t *old_req = (btif_storage_req_t*)p_old_buf;
+
+ BTIF_TRACE_EVENT1("%s", __FUNCTION__);
+ switch (event)
+ {
+ case BTIF_CORE_STORAGE_REMOTE_WRITE:
+ case BTIF_CORE_STORAGE_ADAPTER_WRITE:
+ {
+ bdcpy(new_req->write_req.bd_addr.address, old_req->write_req.bd_addr.address);
+ /* Copy the member variables one at a time */
+ new_req->write_req.prop.type = old_req->write_req.prop.type;
+ new_req->write_req.prop.len = old_req->write_req.prop.len;
+
+ new_req->write_req.prop.val = (UINT8 *)(p_new_buf + sizeof(btif_storage_req_t));
+ memcpy(new_req->write_req.prop.val, old_req->write_req.prop.val,
+ old_req->write_req.prop.len);
+ }break;
+ }
+}
+
+/*******************************************************************************
+**
+** Function btif_get_adapter_properties
+**
+** Description Fetch all available properties (local & remote)
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+
+bt_status_t btif_get_adapter_properties(void)
+{
+ BTIF_TRACE_EVENT1("%s", __FUNCTION__);
+
+ if (btif_enabled == 0)
+ return BT_STATUS_FAIL;
+
+ return btif_transfer_context(execute_storage_request,
+ BTIF_CORE_STORAGE_ADAPTER_READ_ALL,
+ NULL, 0, NULL);
+}
+
+/*******************************************************************************
+**
+** Function btif_get_adapter_property
+**
+** Description Fetches property value from local cache
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+
+bt_status_t btif_get_adapter_property(bt_property_type_t type)
+{
+ btif_storage_req_t req;
+
+ BTIF_TRACE_EVENT2("%s %d", __FUNCTION__, type);
+
+ if (btif_enabled == 0)
+ return BT_STATUS_FAIL;
+
+ memset(&(req.read_req.bd_addr), 0, sizeof(bt_bdaddr_t));
+ req.read_req.type = type;
+
+ return btif_transfer_context(execute_storage_request,
+ BTIF_CORE_STORAGE_ADAPTER_READ,
+ (char*)&req, sizeof(btif_storage_req_t), NULL);
+}
+
+/*******************************************************************************
+**
+** Function btif_set_adapter_property
+**
+** Description Updates core stack with property value and stores it in
+** local cache
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+
+bt_status_t btif_set_adapter_property(const bt_property_t *property)
+{
+ btif_storage_req_t req;
+ bt_status_t status = BT_STATUS_SUCCESS;
+ int storage_req_id = BTIF_CORE_STORAGE_NOTIFY_STATUS; /* default */
+
+ BTIF_TRACE_EVENT3("btif_set_adapter_property type: %d, len %d, 0x%x",
+ property->type, property->len, property->val);
+
+ if (btif_enabled == 0)
+ return BT_STATUS_FAIL;
+
+ switch(property->type)
+ {
+ case BT_PROPERTY_BDNAME:
+ {
+ BTIF_TRACE_EVENT1("set property name : %s", (char *)property->val);
+
+ BTA_DmSetDeviceName((char *)property->val);
+
+ storage_req_id = BTIF_CORE_STORAGE_ADAPTER_WRITE;
+ }
+ break;
+
+ case BT_PROPERTY_ADAPTER_SCAN_MODE:
+ {
+ bt_scan_mode_t mode = *(bt_scan_mode_t*)property->val;
+ tBTA_DM_DISC disc_mode;
+ tBTA_DM_CONN conn_mode;
+
+ switch(mode)
+ {
+ case BT_SCAN_MODE_NONE:
+ disc_mode = BTA_DM_NON_DISC;
+ conn_mode = BTA_DM_NON_CONN;
+ break;
+
+ case BT_SCAN_MODE_CONNECTABLE:
+ disc_mode = BTA_DM_NON_DISC;
+ conn_mode = BTA_DM_CONN;
+ break;
+
+ case BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE:
+ disc_mode = BTA_DM_GENERAL_DISC;
+ conn_mode = BTA_DM_CONN;
+ break;
+
+ default:
+ BTIF_TRACE_ERROR1("invalid scan mode (0x%x)", mode);
+ return BT_STATUS_PARM_INVALID;
+ }
+
+ BTIF_TRACE_EVENT1("set property scan mode : %x", mode);
+
+ BTA_DmSetVisibility(disc_mode, conn_mode, BTA_DM_IGNORE, BTA_DM_IGNORE);
+
+ storage_req_id = BTIF_CORE_STORAGE_ADAPTER_WRITE;
+ }
+ break;
+ case BT_PROPERTY_BDADDR:
+ case BT_PROPERTY_UUIDS:
+ case BT_PROPERTY_ADAPTER_BONDED_DEVICES:
+ case BT_PROPERTY_REMOTE_FRIENDLY_NAME:
+ case BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT:
+ /* no write support through HAL, these properties are only populated from BTA events */
+ status = BT_STATUS_FAIL;
+ break;
+ default:
+ BTIF_TRACE_ERROR1("btif_get_adapter_property : invalid type %d",
+ property->type);
+ status = BT_STATUS_FAIL;
+ break;
+ }
+
+ if (storage_req_id != BTIF_CORE_STORAGE_NO_ACTION)
+ {
+ int btif_status;
+ /* pass on to storage for updating local database */
+
+ memset(&(req.write_req.bd_addr), 0, sizeof(bt_bdaddr_t));
+ memcpy(&(req.write_req.prop), property, sizeof(bt_property_t));
+
+ return btif_transfer_context(execute_storage_request,
+ storage_req_id,
+ (char*)&req,
+ sizeof(btif_storage_req_t)+property->len,
+ btif_in_storage_request_copy_cb);
+ }
+
+ return status;
+
+}
+
+/*******************************************************************************
+**
+** Function btif_get_remote_device_property
+**
+** Description Fetches the remote device property from the NVRAM
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+bt_status_t btif_get_remote_device_property(bt_bdaddr_t *remote_addr,
+ bt_property_type_t type)
+{
+ btif_storage_req_t req;
+
+ if (btif_enabled == 0)
+ return BT_STATUS_FAIL;
+
+ memcpy(&(req.read_req.bd_addr), remote_addr, sizeof(bt_bdaddr_t));
+ req.read_req.type = type;
+ return btif_transfer_context(execute_storage_remote_request,
+ BTIF_CORE_STORAGE_REMOTE_READ,
+ (char*)&req, sizeof(btif_storage_req_t),
+ NULL);
+}
+
+/*******************************************************************************
+**
+** Function btif_get_remote_device_properties
+**
+** Description Fetches all the remote device properties from NVRAM
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+bt_status_t btif_get_remote_device_properties(bt_bdaddr_t *remote_addr)
+{
+ btif_storage_req_t req;
+
+ if (btif_enabled == 0)
+ return BT_STATUS_FAIL;
+
+ memcpy(&(req.read_req.bd_addr), remote_addr, sizeof(bt_bdaddr_t));
+ return btif_transfer_context(execute_storage_remote_request,
+ BTIF_CORE_STORAGE_REMOTE_READ_ALL,
+ (char*)&req, sizeof(btif_storage_req_t),
+ NULL);
+}
+
+/*******************************************************************************
+**
+** Function btif_set_remote_device_property
+**
+** Description Writes the remote device property to NVRAM.
+** Currently, BT_PROPERTY_REMOTE_FRIENDLY_NAME is the only
+** remote device property that can be set
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+bt_status_t btif_set_remote_device_property(bt_bdaddr_t *remote_addr,
+ const bt_property_t *property)
+{
+ btif_storage_req_t req;
+
+ if (btif_enabled == 0)
+ return BT_STATUS_FAIL;
+
+ memcpy(&(req.write_req.bd_addr), remote_addr, sizeof(bt_bdaddr_t));
+ memcpy(&(req.write_req.prop), property, sizeof(bt_property_t));
+
+ return btif_transfer_context(execute_storage_remote_request,
+ BTIF_CORE_STORAGE_REMOTE_WRITE,
+ (char*)&req,
+ sizeof(btif_storage_req_t)+property->len,
+ btif_in_storage_request_copy_cb);
+}
+
+
+/*******************************************************************************
+**
+** Function btif_get_remote_service_record
+**
+** Description Looks up the service matching uuid on the remote device
+** and fetches the SCN and service_name if the UUID is found
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+bt_status_t btif_get_remote_service_record(bt_bdaddr_t *remote_addr,
+ bt_uuid_t *uuid)
+{
+ if (btif_enabled == 0)
+ return BT_STATUS_FAIL;
+
+ return btif_dm_get_remote_service_record(remote_addr, uuid);
+}
+
diff --git a/btif/src/btif_dm.c b/btif/src/btif_dm.c
new file mode 100644
index 0000000..ddd187a
--- /dev/null
+++ b/btif/src/btif_dm.c
@@ -0,0 +1,1159 @@
+/************************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * This program is the proprietary software of Broadcom Corporation and/or its
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
+ *
+ * Except as expressly set forth in the Authorized License,
+ *
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
+ * Broadcom integrated circuit products.
+ *
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT
+ * OF USE OR PERFORMANCE OF THE SOFTWARE.
+ *
+ * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR
+ * ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+ *
+ ************************************************************************************/
+
+/************************************************************************************
+ *
+ * Filename: btif_dm.c
+ *
+ * Description: Contains Device Management (DM) related functionality
+ *
+ *
+ ***********************************************************************************/
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <hardware/bluetooth.h>
+
+#include <utils/Log.h>
+
+#include "gki.h"
+#include "btu.h"
+#include "bd.h"
+#include "bta_api.h"
+#include "btif_api.h"
+#include "btif_util.h"
+#include "btif_storage.h"
+
+/******************************************************************************
+** Constants & Macros
+******************************************************************************/
+
+#define COD_UNCLASSIFIED ((0x1F) << 8)
+
+#define BTIF_DM_DEFAULT_INQ_MAX_RESULTS 0
+#define BTIF_DM_DEFAULT_INQ_MAX_DURATION 10
+
+typedef struct {
+ BD_ADDR bd_addr;
+ UINT8 is_temp;
+ UINT8 pin_code_len;
+} btif_dm_pairing_cb_t;
+
+#define BTA_SERVICE_ID_TO_SERVICE_MASK(id) (1 << (id))
+
+/******************************************************************************
+** Static functions
+******************************************************************************/
+static btif_dm_pairing_cb_t pairing_cb;
+static bt_status_t btif_dm_get_remote_services(bt_bdaddr_t *remote_addr);
+
+/******************************************************************************
+** Externs
+******************************************************************************/
+extern UINT16 bta_service_id_to_uuid_lkup_tbl [BTA_MAX_SERVICE_ID];
+
+/******************************************************************************
+** Functions
+******************************************************************************/
+
+/*******************************************************************************
+**
+** Function check_eir_remote_name
+**
+** Description Check if remote name is in the EIR data
+**
+** Returns TRUE if remote name found
+** Populate p_remote_name, if provided and remote name found
+**
+*******************************************************************************/
+static BOOLEAN check_eir_remote_name(tBTA_DM_SEARCH *p_search_data,
+ UINT8 *p_remote_name, UINT8 *p_remote_name_len)
+{
+ UINT8 *p_eir_remote_name = NULL;
+ UINT8 remote_name_len = 0;
+
+ /* Check EIR for remote name and services */
+ if (p_search_data->inq_res.p_eir)
+ {
+ p_eir_remote_name = BTA_CheckEirData(p_search_data->inq_res.p_eir,
+ BTM_EIR_COMPLETE_LOCAL_NAME_TYPE, &remote_name_len);
+ if (!p_eir_remote_name)
+ {
+ p_eir_remote_name = BTA_CheckEirData(p_search_data->inq_res.p_eir,
+ BTM_EIR_SHORTENED_LOCAL_NAME_TYPE, &remote_name_len);
+ }
+
+ if (p_eir_remote_name)
+ {
+ if (remote_name_len > BD_NAME_LEN)
+ remote_name_len = BD_NAME_LEN;
+
+ if (p_remote_name && p_remote_name_len)
+ {
+ memcpy(p_remote_name, p_eir_remote_name, remote_name_len);
+ *(p_remote_name + remote_name_len) = 0;
+ *p_remote_name_len = remote_name_len;
+ }
+
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+
+}
+
+/*******************************************************************************
+**
+** Function check_cached_remote_name
+**
+** Description Check if remote name is in the NVRAM cache
+**
+** Returns TRUE if remote name found
+** Populate p_remote_name, if provided and remote name found
+**
+*******************************************************************************/
+static BOOLEAN check_cached_remote_name(tBTA_DM_SEARCH *p_search_data,
+ UINT8 *p_remote_name, UINT8 *p_remote_name_len)
+{
+ bt_bdname_t bdname;
+ bt_bdaddr_t remote_bdaddr;
+ bt_property_t prop_name;
+
+ /* check if we already have it in our btif_storage cache */
+ bdcpy(remote_bdaddr.address, p_search_data->inq_res.bd_addr);
+ BTIF_STORAGE_FILL_PROPERTY(&prop_name, BT_PROPERTY_BDNAME,
+ sizeof(bt_bdname_t), &bdname);
+ if (btif_storage_get_remote_device_property(
+ &remote_bdaddr, &prop_name) == BT_STATUS_SUCCESS)
+ {
+ if (p_remote_name && p_remote_name_len)
+ {
+ strcpy((char *)p_remote_name, (char *)bdname.name);
+ *p_remote_name_len = strlen((char *)p_remote_name);
+ }
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function search_devices_copy_cb
+**
+** Description Deep copy callback for search devices event
+**
+** Returns void
+**
+*******************************************************************************/
+static void search_devices_copy_cb(UINT16 event, char *p_dest, char *p_src)
+{
+ tBTA_DM_SEARCH *p_dest_data = (tBTA_DM_SEARCH *) p_dest;
+ tBTA_DM_SEARCH *p_src_data = (tBTA_DM_SEARCH *) p_src;
+
+ if (!p_src)
+ return;
+
+ BTIF_TRACE_DEBUG2("%s: event=%s", __FUNCTION__, dump_dm_search_event(event));
+ memcpy(p_dest_data, p_src_data, sizeof(tBTA_DM_SEARCH));
+ switch (event)
+ {
+ case BTA_DM_INQ_RES_EVT:
+ {
+ if (p_src_data->inq_res.p_eir)
+ {
+ p_dest_data->inq_res.p_eir = (UINT8 *)(p_dest + sizeof(tBTA_DM_SEARCH));
+ memcpy(p_dest_data->inq_res.p_eir, p_src_data->inq_res.p_eir, HCI_EXT_INQ_RESPONSE_LEN);
+ }
+ }
+ break;
+
+ case BTA_DM_DISC_RES_EVT:
+ {
+ if (p_src_data->disc_res.raw_data_size && p_src_data->disc_res.p_raw_data)
+ {
+ p_dest_data->disc_res.p_raw_data = (UINT8 *)(p_dest + sizeof(tBTA_DM_SEARCH));
+ memcpy(p_dest_data->disc_res.p_raw_data,
+ p_src_data->disc_res.p_raw_data, p_src_data->disc_res.raw_data_size);
+ }
+ }
+ break;
+ }
+}
+
+/******************************************************************************
+**
+** BTIF DM callback events
+**
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function btif_dm_pin_req_evt
+**
+** Description Executes pin request event in btif context
+**
+** Returns void
+**
+*******************************************************************************/
+static void btif_dm_pin_req_evt(tBTA_DM_PIN_REQ *p_pin_req)
+{
+ bt_bdaddr_t bd_addr;
+ bt_bdname_t bd_name;
+ UINT32 cod;
+
+ bdcpy(bd_addr.address, p_pin_req->bd_addr);
+ memcpy(bd_name.name, p_pin_req->bd_name, BD_NAME_LEN);
+
+ memset(&pairing_cb, 0, sizeof(btif_dm_pairing_cb_t));
+ bdcpy(pairing_cb.bd_addr, p_pin_req->bd_addr);
+
+ cod = devclass2uint(p_pin_req->dev_class);
+
+ if ( cod == 0) {
+ LOGD("cod is 0, set as unclassified");
+ cod = COD_UNCLASSIFIED;
+ }
+
+ CHECK_CALL_CBACK(bt_hal_cbacks, pin_request_cb,
+ &bd_addr, &bd_name, cod);
+}
+
+/*******************************************************************************
+**
+** Function btif_dm_ssp_cfm_req_evt
+**
+** Description Executes SSP confirm request event in btif context
+**
+** Returns void
+**
+*******************************************************************************/
+static void btif_dm_ssp_cfm_req_evt(tBTA_DM_SP_CFM_REQ *p_ssp_cfm_req)
+{
+ bt_bdaddr_t bd_addr;
+ bt_bdname_t bd_name;
+ UINT32 cod;
+
+ BTIF_TRACE_DEBUG1("%s", __FUNCTION__);
+ bdcpy(bd_addr.address, p_ssp_cfm_req->bd_addr);
+ memcpy(bd_name.name, p_ssp_cfm_req->bd_name, BD_NAME_LEN);
+
+ /* Set the pairing_cb based on the local & remote authentication requirements */
+ memset(&pairing_cb, 0, sizeof(btif_dm_pairing_cb_t));
+ bdcpy(pairing_cb.bd_addr, p_ssp_cfm_req->bd_addr);
+
+ if ((p_ssp_cfm_req->loc_auth_req >= BTM_AUTH_AP_NO && p_ssp_cfm_req->rmt_auth_req >= BTM_AUTH_AP_NO) ||
+ (p_ssp_cfm_req->loc_auth_req == BTM_AUTH_AP_NO || p_ssp_cfm_req->loc_auth_req == BTM_AUTH_AP_YES) ||
+ (p_ssp_cfm_req->rmt_auth_req == BTM_AUTH_AP_NO || p_ssp_cfm_req->rmt_auth_req == BTM_AUTH_AP_YES))
+ pairing_cb.is_temp = FALSE;
+ else
+ pairing_cb.is_temp = TRUE;
+
+ /* If JustWorks auto-accept */
+ if (p_ssp_cfm_req->just_works)
+ {
+ BTIF_TRACE_EVENT1("%s: Auto-accept JustWorks pairing", __FUNCTION__);
+ btif_dm_ssp_reply(&bd_addr, TRUE);
+ return;
+ }
+
+ cod = devclass2uint(p_ssp_cfm_req->dev_class);
+
+ if ( cod == 0) {
+ LOGD("cod is 0, set as unclassified");
+ cod = COD_UNCLASSIFIED;
+ }
+
+ /* TODO: pairing variant? */
+ CHECK_CALL_CBACK(bt_hal_cbacks, ssp_request_cb, &bd_addr, &bd_name,
+ cod, BT_SSP_VARIANT_CONSENT,
+ p_ssp_cfm_req->num_val);
+}
+
+/*******************************************************************************
+**
+** Function btif_dm_auth_cmpl_evt
+**
+** Description Executes authentication complete event in btif context
+**
+** Returns void
+**
+*******************************************************************************/
+static void btif_dm_auth_cmpl_evt (tBTA_DM_AUTH_CMPL *p_auth_cmpl)
+{
+ /* Save link key, if not temporary */
+ bt_bdaddr_t bd_addr;
+ bt_status_t status = BT_STATUS_FAIL;
+ bt_bond_state_t state = BT_BOND_STATE_NONE;
+
+ bdcpy(bd_addr.address, p_auth_cmpl->bd_addr);
+ if ( (p_auth_cmpl->success == TRUE) && (p_auth_cmpl->key_present) )
+ {
+ if ((p_auth_cmpl->key_type < HCI_LKEY_TYPE_DEBUG_COMB) || (p_auth_cmpl->key_type == HCI_LKEY_TYPE_AUTH_COMB) ||
+ (p_auth_cmpl->key_type == HCI_LKEY_TYPE_CHANGED_COMB) || (!pairing_cb.is_temp))
+ {
+ bt_status_t ret;
+ BTIF_TRACE_DEBUG3("%s: Storing link key. key_type=0x%x, is_temp=%d",
+ __FUNCTION__, p_auth_cmpl->key_type, pairing_cb.is_temp);
+ ret = btif_storage_add_bonded_device(&bd_addr,
+ p_auth_cmpl->key, p_auth_cmpl->key_type,
+ pairing_cb.pin_code_len);
+ ASSERTC(ret == BT_STATUS_SUCCESS, "storing link key failed", ret);
+ }
+ else
+ {
+ BTIF_TRACE_DEBUG3("%s: Temporary key. Not storing. key_type=0x%x, is_temp=%d",
+ __FUNCTION__, p_auth_cmpl->key_type, pairing_cb.is_temp);
+ }
+ }
+
+ if (p_auth_cmpl->success)
+ {
+ status = BT_STATUS_SUCCESS;
+ state = BT_BOND_STATE_BONDED;
+
+ /* Trigger SDP on the device */
+ btif_dm_get_remote_services(&bd_addr);
+ }
+
+ CHECK_CALL_CBACK(bt_hal_cbacks, bond_state_changed_cb, status, &bd_addr, state);
+
+ memset(&pairing_cb, 0, sizeof(btif_dm_pairing_cb_t));
+}
+
+/******************************************************************************
+**
+** Function btif_dm_search_devices_evt
+**
+** Description Executes search devices callback events in btif context
+**
+** Returns void
+**
+******************************************************************************/
+static void btif_dm_search_devices_evt (UINT16 event, char *p_param)
+{
+ tBTA_DM_SEARCH *p_search_data;
+ BTIF_TRACE_EVENT2("%s event=%s", __FUNCTION__, dump_dm_search_event(event));
+
+ switch (event)
+ {
+ case BTA_DM_DISC_RES_EVT:
+ {
+ p_search_data = (tBTA_DM_SEARCH *)p_param;
+ /* Remote name update */
+ if (strlen((const char *) p_search_data->disc_res.bd_name))
+ {
+ bt_property_t properties[1];
+ bt_bdaddr_t bdaddr;
+ bt_status_t status;
+
+ properties[0].type = BT_PROPERTY_BDNAME;
+ properties[0].val = p_search_data->disc_res.bd_name;
+ properties[0].len = strlen((char *)p_search_data->disc_res.bd_name)+1;
+ bdcpy(bdaddr.address, p_search_data->disc_res.bd_addr);
+
+ status = btif_storage_set_remote_device_property(&bdaddr, &properties[0]);
+ ASSERTC(status == BT_STATUS_SUCCESS, "failed to save remote device property", status);
+ CHECK_CALL_CBACK(bt_hal_cbacks, remote_device_properties_cb,
+ status, &bdaddr, 1, properties);
+ }
+ /* TODO: Services? */
+ }
+ break;
+
+ case BTA_DM_INQ_RES_EVT:
+ {
+ /* inquiry result */
+ UINT32 cod;
+ UINT8 *p_eir_remote_name = NULL;
+ bt_bdname_t bdname;
+ bt_bdaddr_t bdaddr;
+ UINT8 remote_name_len;
+ UINT8 *p_cached_name = NULL;
+ tBTA_SERVICE_MASK services = 0;
+ bdstr_t bdstr;
+
+ p_search_data = (tBTA_DM_SEARCH *)p_param;
+ bdcpy(bdaddr.address, p_search_data->inq_res.bd_addr);
+
+ BTIF_TRACE_DEBUG3("%s() %s device_type = 0x%x\n", __FUNCTION__, bd2str(&bdaddr, &bdstr),
+#if (BLE_INCLUDED == TRUE)
+ p_search_data->inq_res.device_type);
+#else
+ BT_DEVICE_TYPE_BREDR);
+#endif
+ bdname.name[0] = 0;
+
+ cod = devclass2uint (p_search_data->inq_res.dev_class);
+
+ if ( cod == 0) {
+ LOGD("cod is 0, set as unclassified");
+ cod = COD_UNCLASSIFIED;
+ }
+
+ if (!check_eir_remote_name(p_search_data, bdname.name, &remote_name_len))
+ check_cached_remote_name(p_search_data, bdname.name, &remote_name_len);
+
+ /* Check EIR for remote name and services */
+ if (p_search_data->inq_res.p_eir)
+ {
+ BTA_GetEirService(p_search_data->inq_res.p_eir, &services);
+ BTIF_TRACE_DEBUG2("%s()EIR BTA services = %08X", __FUNCTION__, (UINT32)services);
+ /* TODO: Get the service list and check to see which uuids we got and send it back to the client. */
+ }
+
+
+ {
+ bt_property_t properties[5];
+ bt_device_type_t dev_type;
+ uint32_t num_properties = 0;
+ bt_status_t status;
+
+ memset(properties, 0, sizeof(properties));
+ /* BD_ADDR */
+ BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties],
+ BT_PROPERTY_BDADDR, sizeof(bdaddr), &bdaddr);
+ num_properties++;
+ /* BD_NAME */
+ /* Don't send BDNAME if it is empty */
+ if (bdname.name[0]) {
+ BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties],
+ BT_PROPERTY_BDNAME,
+ strlen((char *)bdname.name)+1, &bdname);
+ num_properties++;
+ }
+
+ /* DEV_CLASS */
+ BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties],
+ BT_PROPERTY_CLASS_OF_DEVICE, sizeof(cod), &cod);
+ num_properties++;
+ /* DEV_TYPE */
+#if (BLE_INCLUDED == TRUE)
+ /* FixMe: Assumption is that bluetooth.h and BTE enums match */
+ dev_type = p_search_data->inq_res.device_type;
+#else
+ dev_type = BT_DEVICE_TYPE_BREDR;
+#endif
+ BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties],
+ BT_PROPERTY_TYPE_OF_DEVICE, sizeof(dev_type), &dev_type);
+ num_properties++;
+ /* RSSI */
+ BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties],
+ BT_PROPERTY_REMOTE_RSSI, sizeof(int8_t),
+ &(p_search_data->inq_res.rssi));
+ num_properties++;
+
+ status = btif_storage_add_remote_device(&bdaddr, num_properties, properties);
+ ASSERTC(status == BT_STATUS_SUCCESS, "failed to save remote device (inquiry)", status);
+
+ /* Callback to notify upper layer of device */
+ CHECK_CALL_CBACK(bt_hal_cbacks, device_found_cb,
+ num_properties, properties);
+ }
+ }
+ break;
+
+ case BTA_DM_INQ_CMPL_EVT:
+ {
+ }
+ break;
+
+ case BTA_DM_DISC_CMPL_EVT:
+ case BTA_DM_SEARCH_CANCEL_CMPL_EVT:
+ {
+ CHECK_CALL_CBACK(bt_hal_cbacks, discovery_state_changed_cb, BT_DISCOVERY_STOPPED);
+ }
+ break;
+ }
+}
+
+/*******************************************************************************
+**
+** Function btif_dm_search_services_evt
+**
+** Description Executes search services event in btif context
+**
+** Returns void
+**
+*******************************************************************************/
+static void btif_dm_search_services_evt(UINT16 event, char *p_param)
+{
+ tBTA_DM_SEARCH *p_data = (tBTA_DM_SEARCH*)p_param;
+
+ BTIF_TRACE_EVENT2("%s: event = %d", __FUNCTION__, event);
+ switch (event)
+ {
+ case BTA_DM_DISC_RES_EVT:
+ {
+ bt_uuid_t uuid_arr[BT_MAX_NUM_UUIDS]; /* Max 32 services */
+ bt_property_t prop;
+ uint32_t i = 0, j = 0;
+ bt_bdaddr_t bd_addr;
+ bt_status_t ret;
+
+ bdcpy(bd_addr.address, p_data->disc_res.bd_addr);
+
+ BTIF_TRACE_DEBUG3("%s:(result=0x%x, services 0x%x)", __FUNCTION__,
+ p_data->disc_res.result, p_data->disc_res.services);
+ prop.type = BT_PROPERTY_UUIDS;
+ prop.val = (void*)uuid_arr;
+ prop.len = 0;
+ for (i=0; i < BTA_MAX_SERVICE_ID; i++)
+ {
+ if(p_data->disc_res.services
+ &(tBTA_SERVICE_MASK)(BTA_SERVICE_ID_TO_SERVICE_MASK(i)))
+ {
+ memset(&uuid_arr[j], 0, sizeof(bt_uuid_t));
+ uuid16_to_uuid128(bta_service_id_to_uuid_lkup_tbl[i], &uuid_arr[j]);
+ prop.len += sizeof(bt_uuid_t);
+ j++;
+ }
+ }
+ /* Also write this to the NVRAM */
+ ret = btif_storage_set_remote_device_property(&bd_addr, &prop);
+ ASSERTC(ret == BT_STATUS_SUCCESS, "storing remote services failed", ret);
+
+ /* Send the event to the BTIF */
+ CHECK_CALL_CBACK(bt_hal_cbacks, remote_device_properties_cb,
+ BT_STATUS_SUCCESS, &bd_addr, 1, &prop);
+ }
+ break;
+
+ default:
+ {
+ ASSERTC(0, "unhandled search services event", event);
+ }
+ break;
+ }
+}
+
+/*******************************************************************************
+**
+** Function btif_dm_remote_service_record_evt
+**
+** Description Executes search service record event in btif context
+**
+** Returns void
+**
+*******************************************************************************/
+static void btif_dm_remote_service_record_evt(UINT16 event, char *p_param)
+{
+ tBTA_DM_SEARCH *p_data = (tBTA_DM_SEARCH*)p_param;
+
+ BTIF_TRACE_EVENT2("%s: event = %d", __FUNCTION__, event);
+ switch (event)
+ {
+ case BTA_DM_DISC_RES_EVT:
+ {
+ bt_service_record_t rec;
+ bt_property_t prop;
+ uint32_t i = 0;
+ bt_bdaddr_t bd_addr;
+
+ memset(&rec, 0, sizeof(bt_service_record_t));
+ bdcpy(bd_addr.address, p_data->disc_res.bd_addr);
+
+ BTIF_TRACE_DEBUG3("%s:(result=0x%x, services 0x%x)", __FUNCTION__,
+ p_data->disc_res.result, p_data->disc_res.services);
+ prop.type = BT_PROPERTY_SERVICE_RECORD;
+ prop.val = (void*)&rec;
+ prop.len = sizeof(rec);
+
+ /* disc_res.result is overloaded with SCN. Cannot check result */
+ p_data->disc_res.services &= ~BTA_USER_SERVICE_MASK;
+ /* TODO: Get the UUID as well */
+ rec.channel = p_data->disc_res.result - 3;
+ /* TODO: Need to get the service name using p_raw_data */
+ rec.name[0] = 0;
+
+ CHECK_CALL_CBACK(bt_hal_cbacks, remote_device_properties_cb,
+ BT_STATUS_SUCCESS, &bd_addr, 1, &prop);
+ }
+ break;
+
+ default:
+ {
+ ASSERTC(0, "unhandled remote service record event", event);
+ }
+ break;
+ }
+}
+
+/*******************************************************************************
+**
+** Function btif_dm_upstreams_cback
+**
+** Description Executes UPSTREAMS events in btif context
+**
+** Returns void
+**
+*******************************************************************************/
+static void btif_dm_upstreams_evt(UINT16 event, char* p_param)
+{
+ tBTA_DM_SEC_EVT dm_event = (tBTA_DM_SEC_EVT)event;
+ tBTA_DM_SEC *p_data = (tBTA_DM_SEC*)p_param;
+
+ BTIF_TRACE_EVENT1("btif_dm_upstreams_cback ev: %d", event);
+
+ switch (event)
+ {
+ case BTA_DM_ENABLE_EVT:
+ {
+ BD_NAME bdname;
+ bt_status_t status;
+ bt_property_t prop;
+ prop.type = BT_PROPERTY_BDNAME;
+ prop.len = 0;
+ prop.val = (void*)bdname;
+
+ status = btif_storage_get_adapter_property(&prop);
+ /* Storage does not have a name yet.
+ ** Use the default name and write it to the chip
+ */
+ if (status != BT_STATUS_SUCCESS)
+ {
+ /* TODO: BTM_DEF_LOCAL_NAME should be configurable */
+ BTA_DmSetDeviceName(BTM_DEF_LOCAL_NAME);
+ /* Hmmm...Should we store this too??? */
+ }
+ else
+ {
+ /* A name exists in the storage. Make this the device name */
+ BTA_DmSetDeviceName((char*)prop.val);
+ }
+ /* This function will also trigger the adapter_properties_cb
+ ** and bonded_devices_info_cb
+ */
+ btif_storage_load_bonded_devices();
+ btif_enable_bluetooth_evt(p_data->enable.status, p_data->enable.bd_addr);
+ }
+ break;
+
+ case BTA_DM_DISABLE_EVT:
+ btif_disable_bluetooth_evt();
+ break;
+
+ case BTA_DM_PIN_REQ_EVT:
+ btif_dm_pin_req_evt(&p_data->pin_req);
+ break;
+
+ case BTA_DM_AUTH_CMPL_EVT:
+ btif_dm_auth_cmpl_evt(&p_data->auth_cmpl);
+ break;
+
+ case BTA_DM_SP_CFM_REQ_EVT:
+ btif_dm_ssp_cfm_req_evt(&p_data->cfm_req);
+ break;
+
+ case BTA_DM_AUTHORIZE_EVT:
+ case BTA_DM_LINK_DOWN_EVT:
+ case BTA_DM_SIG_STRENGTH_EVT:
+ case BTA_DM_BUSY_LEVEL_EVT:
+ case BTA_DM_BOND_CANCEL_CMPL_EVT:
+ case BTA_DM_SP_KEY_NOTIF_EVT:
+ case BTA_DM_SP_RMT_OOB_EVT:
+ case BTA_DM_SP_KEYPRESS_EVT:
+ case BTA_DM_ROLE_CHG_EVT:
+ case BTA_DM_BLE_KEY_EVT:
+ case BTA_DM_BLE_SEC_REQ_EVT:
+ case BTA_DM_BLE_PASSKEY_NOTIF_EVT:
+ case BTA_DM_BLE_PASSKEY_REQ_EVT:
+ case BTA_DM_BLE_OOB_REQ_EVT:
+ case BTA_DM_BLE_LOCAL_IR_EVT:
+ case BTA_DM_BLE_LOCAL_ER_EVT:
+ case BTA_DM_BLE_AUTH_CMPL_EVT:
+ default:
+ BTIF_TRACE_WARNING1( "btif_dm_cback : unhandled event (%d)", event );
+ break;
+ }
+} /* btui_security_cback() */
+
+
+/*******************************************************************************
+**
+** Function btif_dm_generic_evt
+**
+** Description Executes non-BTA upstream events in BTIF context
+**
+** Returns void
+**
+*******************************************************************************/
+static void btif_dm_generic_evt(UINT16 event, char* p_param)
+{
+ BTIF_TRACE_EVENT2("%s: event=%d", __FUNCTION__, event);
+ switch(event)
+ {
+ case BTIF_DM_CB_DISCOVERY_STARTED:
+ {
+ CHECK_CALL_CBACK(bt_hal_cbacks, discovery_state_changed_cb, BT_DISCOVERY_STARTED);
+ }
+ break;
+
+ case BTIF_DM_CB_REMOVED_BONDING:
+ {
+ bt_bdaddr_t *bd_addr = (bt_bdaddr_t*)p_param;
+ bt_status_t status;
+
+ status = btif_storage_remove_bonded_device(bd_addr);
+ ASSERTC(status == BT_STATUS_SUCCESS, "failed to delete bonded device", status);
+
+ CHECK_CALL_CBACK(bt_hal_cbacks, bond_state_changed_cb,
+ BT_STATUS_SUCCESS, bd_addr, BT_BOND_STATE_NONE);
+ }
+ break;
+
+ default:
+ {
+ BTIF_TRACE_WARNING2("%s : Unknown event 0x%x", __FUNCTION__, event);
+ }
+ break;
+ }
+}
+
+/*******************************************************************************
+**
+** Function bte_dm_evt
+**
+** Description Switches context from BTE to BTIF for all DM events
+**
+** Returns void
+**
+*******************************************************************************/
+
+void bte_dm_evt(tBTA_DM_SEC_EVT event, tBTA_DM_SEC *p_data)
+{
+ bt_status_t status;
+
+ /* switch context to btif task context (copy full union size for convenience) */
+ status = btif_transfer_context(btif_dm_upstreams_evt, (uint16_t)event, (void*)p_data, sizeof(tBTA_DM_SEC), NULL);
+
+ /* catch any failed context transfers */
+ ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status);
+}
+
+/*******************************************************************************
+**
+** Function bte_search_devices_evt
+**
+** Description Switches context from BTE to BTIF for DM search events
+**
+** Returns void
+**
+*******************************************************************************/
+static void bte_search_devices_evt(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH *p_data)
+{
+ UINT16 param_len = 0;
+
+ if (p_data)
+ param_len += sizeof(tBTA_DM_SEARCH);
+ /* Allocate buffer to hold the pointers (deep copy). The pointers will point to the end of the tBTA_DM_SEARCH */
+ switch (event)
+ {
+ case BTA_DM_INQ_RES_EVT:
+ {
+ if (p_data->inq_res.p_eir)
+ param_len += HCI_EXT_INQ_RESPONSE_LEN;
+ }
+ break;
+
+ case BTA_DM_DISC_RES_EVT:
+ {
+ if (p_data->disc_res.raw_data_size && p_data->disc_res.p_raw_data)
+ param_len += p_data->disc_res.raw_data_size;
+ }
+ break;
+ }
+ BTIF_TRACE_DEBUG3("%s event=%s param_len=%d", __FUNCTION__, dump_dm_search_event(event), param_len);
+
+ /* if remote name is available in EIR, set teh flag so that stack doesnt trigger RNR */
+ if (event == BTA_DM_INQ_RES_EVT)
+ p_data->inq_res.remt_name_not_required = check_eir_remote_name(p_data, NULL, NULL);
+
+ btif_transfer_context (btif_dm_search_devices_evt , (UINT16) event, (void *)p_data, param_len,
+ (param_len > sizeof(tBTA_DM_SEARCH)) ? search_devices_copy_cb : NULL);
+}
+
+/*******************************************************************************
+**
+** Function bte_dm_search_services_evt
+**
+** Description Switches context from BTE to BTIF for DM search services
+** event
+**
+** Returns void
+**
+*******************************************************************************/
+static void bte_dm_search_services_evt(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH *p_data)
+{
+ /* TODO: The only member that needs a deep copy is the p_raw_data. But not sure yet if this is needed. */
+ btif_transfer_context(btif_dm_search_services_evt, event, (char*)p_data, sizeof(tBTA_DM_SEARCH), NULL);
+}
+
+/*******************************************************************************
+**
+** Function bte_dm_remote_service_record_evt
+**
+** Description Switches context from BTE to BTIF for DM search service
+** record event
+**
+** Returns void
+**
+*******************************************************************************/
+static void bte_dm_remote_service_record_evt(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH *p_data)
+{
+ /* TODO: The only member that needs a deep copy is the p_raw_data. But not sure yet if this is needed. */
+ btif_transfer_context(btif_dm_remote_service_record_evt, event, (char*)p_data, sizeof(tBTA_DM_SEARCH), NULL);
+}
+
+/*****************************************************************************
+**
+** btif api functions (no context switch)
+**
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function btif_dm_start_discovery
+**
+** Description Start device discovery/inquiry
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+bt_status_t btif_dm_start_discovery(void)
+{
+ tBTA_DM_INQ inq_params;
+ tBTA_SERVICE_MASK services = 0;
+
+ BTIF_TRACE_EVENT1("%s", __FUNCTION__);
+ /* TODO: Do we need to handle multiple inquiries at the same time? */
+
+ /* Set inquiry params and call API */
+#if (BLE_INCLUDED == TRUE)
+ inq_params.mode = BTA_DM_GENERAL_INQUIRY|BTA_BLE_GENERAL_INQUIRY;
+#else
+ inq_params.mode = BTA_DM_GENERAL_INQUIRY;
+#endif
+ inq_params.duration = BTIF_DM_DEFAULT_INQ_MAX_DURATION;
+
+ inq_params.max_resps = BTIF_DM_DEFAULT_INQ_MAX_RESULTS;
+ inq_params.report_dup = TRUE;
+
+ inq_params.filter_type = BTA_DM_INQ_CLR;
+ /* TODO: Filter device by BDA needs to be implemented here */
+
+ /* find nearby devices */
+ BTA_DmSearch(&inq_params, services, bte_search_devices_evt);
+
+ /* Invoke the discovery_started callback */
+ btif_transfer_context(btif_dm_generic_evt, BTIF_DM_CB_DISCOVERY_STARTED, NULL, 0, NULL);
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function btif_dm_cancel_discovery
+**
+** Description Cancels search
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+bt_status_t btif_dm_cancel_discovery(void)
+{
+ BTIF_TRACE_EVENT1("%s", __FUNCTION__);
+ BTA_DmSearchCancel();
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function btif_dm_create_bond
+**
+** Description Initiate bonding with the specified device
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+bt_status_t btif_dm_create_bond(const bt_bdaddr_t *bd_addr)
+{
+ bdstr_t bdstr;
+
+ BTIF_TRACE_EVENT2("%s: bd_addr=%s", __FUNCTION__, bd2str((bt_bdaddr_t *) bd_addr, &bdstr));
+
+ /* TODO:
+ ** 1. Check if ACL is already up with this device
+ ** 2. Disable unpaired devices from connecting while we are bonding
+ ** 3. special handling for HID devices
+ */
+
+ BTA_DmBond ((UINT8 *)bd_addr->address);
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function btif_dm_cancel_bond
+**
+** Description Initiate bonding with the specified device
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+
+bt_status_t btif_dm_cancel_bond(const bt_bdaddr_t *bd_addr)
+{
+ bdstr_t bdstr;
+
+ BTIF_TRACE_EVENT2("%s: bd_addr=%s", __FUNCTION__, bd2str((bt_bdaddr_t *)bd_addr, &bdstr));
+
+ /* TODO:
+ ** 1. Check if ACL is already up with this device
+ ** 2. Restore scan modes
+ ** 3. special handling for HID devices
+ */
+ BTA_DmBondCancel ((UINT8 *)bd_addr->address);
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function btif_dm_remove_bond
+**
+** Description Removes bonding with the specified device
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+
+bt_status_t btif_dm_remove_bond(const bt_bdaddr_t *bd_addr)
+{
+ bdstr_t bdstr;
+
+ BTIF_TRACE_EVENT2("%s: bd_addr=%s", __FUNCTION__, bd2str((bt_bdaddr_t *)bd_addr, &bdstr));
+
+ /* TODO: special handling for HID devices */
+ if (BTA_DmRemoveDevice((UINT8 *)bd_addr->address) == BTA_SUCCESS)
+ {
+ BTIF_TRACE_DEBUG1("Successfully removed bonding with device: %s",
+ bd2str((bt_bdaddr_t *)bd_addr, &bdstr));
+
+ /* Device shall be removed from the storage in the btif context */
+ btif_transfer_context(btif_dm_generic_evt, BTIF_DM_CB_REMOVED_BONDING,
+ (char*)bd_addr, sizeof(bt_bdaddr_t), NULL);
+ }
+ else
+ {
+ /* TODO: ACL is already up with this device, disconnect and then issue RemoveBond */
+ BTIF_TRACE_WARNING0("ACL connection exists with device. Disconnect and issue remove bonding");
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function btif_dm_pin_reply
+**
+** Description BT legacy pairing - PIN code reply
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+
+bt_status_t btif_dm_pin_reply( const bt_bdaddr_t *bd_addr, uint8_t accept,
+ uint8_t pin_len, bt_pin_code_t *pin_code)
+{
+ BTIF_TRACE_EVENT2("%s: accept=%d", __FUNCTION__, accept);
+
+ BTA_DmPinReply( (UINT8 *)bd_addr->address, accept, pin_len, pin_code->pin);
+
+ if (accept)
+ pairing_cb.pin_code_len = pin_len;
+ else
+ memset(&pairing_cb, 0, sizeof(btif_dm_pairing_cb_t));
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function btif_dm_passkey_reply
+**
+** Description BT SSP passkey reply
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+
+bt_status_t btif_dm_passkey_reply(const bt_bdaddr_t *bd_addr,
+ uint8_t accept, uint32_t passkey)
+{
+ /* This is not implemented in the stack.
+ ** For devices with display, this is not needed
+ */
+ BTIF_TRACE_WARNING1("%s: Not implemented", __FUNCTION__);
+
+ return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+**
+** Function btif_dm_ssp_reply
+**
+** Description BT SSP Reply - Just Works & Numeric Comparison
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+
+bt_status_t btif_dm_ssp_reply(const bt_bdaddr_t *bd_addr, uint8_t accept)
+{
+ BTIF_TRACE_EVENT2("%s: accept=%d", __FUNCTION__, accept);
+ BTA_DmConfirm( (UINT8 *)bd_addr->address, accept);
+ if (!accept)
+ memset(&pairing_cb, 0, sizeof(btif_dm_pairing_cb_t));
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function btif_dm_get_adapter_property
+**
+** Description Queries the BTA for the adapter property
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+bt_status_t btif_dm_get_adapter_property(bt_property_t *prop)
+{
+ bt_status_t status;
+
+ BTIF_TRACE_EVENT2("%s: type=0x%x", __FUNCTION__, prop->type);
+ switch (prop->type)
+ {
+ case BT_PROPERTY_BDNAME:
+ {
+ bt_bdname_t *bd_name = (bt_bdname_t*)prop->val;
+ strcpy((char *)bd_name->name, BTM_DEF_LOCAL_NAME);
+ prop->len = strlen((char *)bd_name->name)+1;
+ }
+ break;
+
+ case BT_PROPERTY_ADAPTER_SCAN_MODE:
+ {
+ /* if the storage does not have it. Most likely app never set it. Default is NONE */
+ bt_scan_mode_t *mode = (bt_scan_mode_t*)prop->val;
+ *mode = BT_SCAN_MODE_NONE;
+ prop->len = sizeof(bt_scan_mode_t);
+ }
+ break;
+
+ case BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT:
+ {
+ uint32_t *tmt = (uint32_t*)prop->val;
+ *tmt = 0;
+ prop->len = sizeof(uint32_t);
+ }
+ break;
+
+ default:
+ prop->len = 0;
+ return BT_STATUS_FAIL;
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function btif_dm_get_remote_services
+**
+** Description Start SDP to get remote services
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+bt_status_t btif_dm_get_remote_services(bt_bdaddr_t *remote_addr)
+{
+ bdstr_t bdstr;
+
+ BTIF_TRACE_EVENT2("%s: remote_addr=%s", __FUNCTION__, bd2str(remote_addr, &bdstr));
+
+ BTA_DmDiscover(remote_addr->address, BTA_ALL_SERVICE_MASK,
+ bte_dm_search_services_evt, TRUE);
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function btif_dm_get_remote_service_record
+**
+** Description Start SDP to get remote service record
+**
+**
+** Returns bt_status_t
+*******************************************************************************/
+bt_status_t btif_dm_get_remote_service_record(bt_bdaddr_t *remote_addr,
+ bt_uuid_t *uuid)
+{
+ tSDP_UUID sdp_uuid;
+ bdstr_t bdstr;
+
+ BTIF_TRACE_EVENT2("%s: remote_addr=%s", __FUNCTION__, bd2str(remote_addr, &bdstr));
+
+ sdp_uuid.len = MAX_UUID_SIZE;
+ memcpy(sdp_uuid.uu.uuid128, uuid->uu, MAX_UUID_SIZE);
+
+ BTA_DmDiscoverUUID(remote_addr->address, &sdp_uuid,
+ bte_dm_remote_service_record_evt, TRUE);
+
+ return BT_STATUS_SUCCESS;
+}
diff --git a/btif/src/btif_hf.c b/btif/src/btif_hf.c
new file mode 100644
index 0000000..7f0e6bc
--- /dev/null
+++ b/btif/src/btif_hf.c
@@ -0,0 +1,1010 @@
+/************************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * This program is the proprietary software of Broadcom Corporation and/or its
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
+ *
+ * Except as expressly set forth in the Authorized License,
+ *
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
+ * Broadcom integrated circuit products.
+ *
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT
+ * OF USE OR PERFORMANCE OF THE SOFTWARE.
+ *
+ * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR
+ * ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+ *
+ ************************************************************************************/
+
+/************************************************************************************
+ *
+ * Filename: btif_hf.c
+ *
+ * Description: Handsfree Profile Bluetooth Interface
+ *
+ *
+ ***********************************************************************************/
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_hf.h>
+
+#define LOG_TAG "BTIF_HF"
+#include "btif_common.h"
+#include "btif_util.h"
+
+#include "bd.h"
+#include "bta_ag_api.h"
+
+/************************************************************************************
+** Constants & Macros
+************************************************************************************/
+/* TODO: Should these be moved to a conf file? */
+#define BTIF_HF_SERVICES (BTA_HSP_SERVICE_MASK | BTA_HFP_SERVICE_MASK)
+#define BTIF_HF_SECURITY (BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT)
+#define BTIF_HF_FEATURES (BTA_AG_FEAT_ECNR | \
+ BTA_AG_FEAT_REJECT | \
+ BTA_AG_FEAT_ECS | \
+ BTA_AG_FEAT_ECC | \
+ BTA_AG_FEAT_EXTERR | \
+ BTA_AG_FEAT_BTRH | \
+ BTA_AG_FEAT_VREC)
+#define BTIF_HSAG_SERVICE_NAME ("Headset Gateway")
+#define BTIF_HFAG_SERVICE_NAME ("Handsfree Gateway")
+
+#define BTIF_HF_ID_1 0
+
+/************************************************************************************
+** Local type definitions
+************************************************************************************/
+
+/************************************************************************************
+** Static variables
+************************************************************************************/
+static bthf_callbacks_t *bt_hf_callbacks = NULL;
+
+#define CHECK_BTHF_INIT() if (bt_hf_callbacks == NULL)\
+ {\
+ BTIF_TRACE_WARNING1("BTHF: %s: BTHF not initialized", __FUNCTION__);\
+ return BT_STATUS_NOT_READY;\
+ }\
+ else\
+ {\
+ BTIF_TRACE_EVENT1("BTHF: %s", __FUNCTION__);\
+ }
+
+
+/* BTIF-HF control block to map bdaddr to BTA handle */
+typedef struct _btif_hf_cb
+{
+ UINT16 handle;
+ bt_bdaddr_t connected_bda;
+ bthf_connection_state_t state;
+ bthf_vr_state_t vr_state;
+ tBTA_AG_PEER_FEAT peer_feat;
+ int num_active;
+ int num_held;
+ bthf_call_state_t call_setup_state;
+} btif_hf_cb_t;
+
+static btif_hf_cb_t btif_hf_cb;
+
+
+/************************************************************************************
+** Static functions
+************************************************************************************/
+
+/************************************************************************************
+** Externs
+************************************************************************************/
+
+/************************************************************************************
+** Functions
+************************************************************************************/
+
+/*******************************************************************************
+**
+** Function is_connected
+**
+** Description Internal function to check if HF is connected
+**
+** Returns TRUE if connected
+**
+*******************************************************************************/
+static BOOLEAN is_connected(bt_bdaddr_t *bd_addr)
+{
+ if ((btif_hf_cb.state == BTHF_CONNECTION_STATE_CONNECTED) &&
+ ((bd_addr == NULL) || (bdcmp(bd_addr->address, btif_hf_cb.connected_bda.address) == 0)))
+ return TRUE;
+ else
+ return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function callstate_to_callsetup
+**
+** Description Converts HAL call state to BTA call setup indicator value
+**
+** Returns BTA call indicator value
+**
+*******************************************************************************/
+static UINT8 callstate_to_callsetup(bthf_call_state_t call_state)
+{
+ UINT8 call_setup = 0;
+ if (call_state == BTHF_CALL_STATE_INCOMING)
+ call_setup = 1;
+ if (call_state == BTHF_CALL_STATE_DIALING)
+ call_setup = 2;
+ if (call_state == BTHF_CALL_STATE_ALERTING)
+ call_setup = 3;
+
+ return call_setup;
+}
+
+/*******************************************************************************
+**
+** Function send_at_result
+**
+** Description Send AT result code (OK/ERROR)
+**
+** Returns void
+**
+*******************************************************************************/
+static void send_at_result(UINT8 ok_flag, UINT16 errcode)
+{
+ tBTA_AG_RES_DATA ag_res;
+ memset (&ag_res, 0, sizeof (ag_res));
+
+ ag_res.ok_flag = ok_flag;
+ if (ok_flag == BTA_AG_OK_ERROR)
+ {
+ ag_res.errcode = errcode;
+ }
+
+ BTA_AgResult (btif_hf_cb.handle, BTA_AG_UNAT_RES, &ag_res);
+}
+
+/*******************************************************************************
+**
+** Function send_indicator_update
+**
+** Description Send indicator update (CIEV)
+**
+** Returns void
+**
+*******************************************************************************/
+static void send_indicator_update (UINT16 indicator, UINT16 value)
+{
+ tBTA_AG_RES_DATA ag_res;
+
+ memset(&ag_res, 0, sizeof(tBTA_AG_RES_DATA));
+ ag_res.ind.id = indicator;
+ ag_res.ind.value = value;
+
+ BTA_AgResult(BTA_AG_HANDLE_ALL, BTA_AG_IND_RES, &ag_res);
+}
+
+/*****************************************************************************
+** Section name (Group of functions)
+*****************************************************************************/
+
+/*****************************************************************************
+**
+** btif hf api functions (no context switch)
+**
+*****************************************************************************/
+
+
+/*******************************************************************************
+**
+** Function btif_hf_upstreams_evt
+**
+** Description Executes HF UPSTREAMS events in btif context
+**
+** Returns void
+**
+*******************************************************************************/
+static void btif_hf_upstreams_evt(UINT16 event, char* p_param)
+{
+ tBTA_AG *p_data = (tBTA_AG *)p_param;
+ bdstr_t bdstr;
+
+ BTIF_TRACE_DEBUG2("%s: event=%s", __FUNCTION__, dump_hf_event(event));
+
+ switch (event)
+ {
+ case BTA_AG_ENABLE_EVT:
+ case BTA_AG_DISABLE_EVT:
+ break;
+
+ case BTA_AG_REGISTER_EVT:
+ btif_hf_cb.handle = p_data->reg.hdr.handle;
+ break;
+
+ case BTA_AG_OPEN_EVT:
+ if (p_data->open.status == BTA_AG_SUCCESS)
+ {
+ bdcpy(btif_hf_cb.connected_bda.address, p_data->open.bd_addr);
+ btif_hf_cb.state = BTHF_CONNECTION_STATE_CONNECTED;
+ btif_hf_cb.peer_feat = 0;
+ }
+ else if (btif_hf_cb.state == BTHF_CONNECTION_STATE_CONNECTING)
+ {
+ btif_hf_cb.state = BTHF_CONNECTION_STATE_DISCONNECTED;
+ }
+ else
+ {
+ BTIF_TRACE_WARNING4("%s: AG open failed, but another device connected. status=%d state=%d connected device=%s",
+ __FUNCTION__, p_data->open.status, btif_hf_cb.state, bd2str(&btif_hf_cb.connected_bda, &bdstr));
+ break;
+ }
+
+ CHECK_CALL_CBACK(bt_hf_callbacks, connection_state_cb, btif_hf_cb.state, &btif_hf_cb.connected_bda);
+
+ if (p_data->open.status != BTA_AG_SUCCESS)
+ bdsetany(btif_hf_cb.connected_bda.address);
+ break;
+
+ case BTA_AG_CLOSE_EVT:
+ btif_hf_cb.state = BTHF_CONNECTION_STATE_DISCONNECTED;
+ CHECK_CALL_CBACK(bt_hf_callbacks, connection_state_cb, btif_hf_cb.state, &btif_hf_cb.connected_bda);
+ bdsetany(btif_hf_cb.connected_bda.address);
+ btif_hf_cb.peer_feat = 0;
+ break;
+
+ case BTA_AG_CONN_EVT:
+ btif_hf_cb.peer_feat = p_data->conn.peer_feat;
+ break;
+
+ case BTA_AG_AUDIO_OPEN_EVT:
+ CHECK_CALL_CBACK(bt_hf_callbacks, audio_state_cb, BTHF_AUDIO_STATE_CONNECTED, &btif_hf_cb.connected_bda);
+ break;
+
+ case BTA_AG_AUDIO_CLOSE_EVT:
+ CHECK_CALL_CBACK(bt_hf_callbacks, audio_state_cb, BTHF_AUDIO_STATE_DISCONNECTED, &btif_hf_cb.connected_bda);
+ break;
+
+ /* BTA auto-responds, silently discard */
+ case BTA_AG_SPK_EVT:
+ case BTA_AG_MIC_EVT:
+ CHECK_CALL_CBACK(bt_hf_callbacks, volume_cmd_cb,
+ (event == BTA_AG_SPK_EVT) ? BTHF_VOLUME_TYPE_SPK : BTHF_VOLUME_TYPE_MIC, p_data->val.num);
+ break;
+
+ case BTA_AG_AT_A_EVT:
+ CHECK_CALL_CBACK(bt_hf_callbacks, answer_call_cmd_cb);
+ break;
+
+ /* Java needs to send OK/ERROR for these commands */
+ case BTA_AG_AT_BLDN_EVT:
+ case BTA_AG_AT_D_EVT:
+ CHECK_CALL_CBACK(bt_hf_callbacks, dial_call_cmd_cb,
+ (event == BTA_AG_AT_D_EVT) ? p_data->val.str : NULL);
+ break;
+
+ case BTA_AG_AT_CHUP_EVT:
+ CHECK_CALL_CBACK(bt_hf_callbacks, hangup_call_cmd_cb);
+ break;
+
+ case BTA_AG_AT_CIND_EVT:
+ CHECK_CALL_CBACK(bt_hf_callbacks, cind_cmd_cb);
+ break;
+
+ case BTA_AG_AT_VTS_EVT:
+ CHECK_CALL_CBACK(bt_hf_callbacks, dtmf_cmd_cb, p_data->val.str[0]);
+ break;
+
+ case BTA_AG_AT_BVRA_EVT:
+ CHECK_CALL_CBACK(bt_hf_callbacks, vr_cmd_cb,
+ (p_data->val.num == 1) ? BTHF_VR_STATE_STARTED : BTHF_VR_STATE_STOPPED);
+ break;
+
+ case BTA_AG_AT_NREC_EVT:
+ CHECK_CALL_CBACK(bt_hf_callbacks, nrec_cmd_cb,
+ (p_data->val.num == 1) ? BTHF_NREC_START : BTHF_NREC_STOP);
+ break;
+
+ /* TODO: Add a callback for CBC */
+ case BTA_AG_AT_CBC_EVT:
+ break;
+
+ case BTA_AG_AT_CKPD_EVT:
+ CHECK_CALL_CBACK(bt_hf_callbacks, key_pressed_cmd_cb);
+ break;
+
+ /* Java needs to send OK/ERROR for these commands */
+ case BTA_AG_AT_CHLD_EVT:
+ CHECK_CALL_CBACK(bt_hf_callbacks, chld_cmd_cb, p_data->val.num);
+ break;
+
+ case BTA_AG_AT_CLCC_EVT:
+ CHECK_CALL_CBACK(bt_hf_callbacks, clcc_cmd_cb, p_data->val.num);
+ break;
+
+ case BTA_AG_AT_COPS_EVT:
+ CHECK_CALL_CBACK(bt_hf_callbacks, cops_cmd_cb);
+ break;
+
+ case BTA_AG_AT_UNAT_EVT:
+ CHECK_CALL_CBACK(bt_hf_callbacks, unknown_at_cmd_cb,
+ p_data->val.str);
+ break;
+
+ case BTA_AG_AT_CNUM_EVT:
+ CHECK_CALL_CBACK(bt_hf_callbacks, cnum_cmd_cb);
+ break;
+
+ /* TODO: Some of these commands may need to be sent to app. For now respond with error */
+ case BTA_AG_AT_BINP_EVT:
+ case BTA_AG_AT_BTRH_EVT:
+ send_at_result(BTA_AG_OK_ERROR, BTA_AG_ERR_OP_NOT_SUPPORTED);
+ break;
+
+
+ default:
+ BTIF_TRACE_WARNING2("%s: Unhandled event: %d", __FUNCTION__, event);
+ break;
+ }
+}
+
+/*******************************************************************************
+**
+** Function bte_hf_evt
+**
+** Description Switches context from BTE to BTIF for all HF events
+**
+** Returns void
+**
+*******************************************************************************/
+
+static void bte_hf_evt(tBTA_AG_EVT event, tBTA_AG *p_data)
+{
+ bt_status_t status;
+ int param_len = 0;
+
+ /* TODO: BTA sends the union members and not tBTA_AG. If using param_len=sizeof(tBTA_AG), we get a crash on memcpy */
+ if (BTA_AG_REGISTER_EVT == event)
+ param_len = sizeof(tBTA_AG_REGISTER);
+ else if (BTA_AG_OPEN_EVT == event)
+ param_len = sizeof(tBTA_AG_OPEN);
+ else if (BTA_AG_CONN_EVT == event)
+ param_len = sizeof(tBTA_AG_CONN);
+ else if ( (BTA_AG_CLOSE_EVT == event) || (BTA_AG_AUDIO_OPEN_EVT == event) || (BTA_AG_AUDIO_CLOSE_EVT == event))
+ param_len = sizeof(tBTA_AG_HDR);
+ else if (p_data)
+ param_len = sizeof(tBTA_AG_VAL);
+
+ /* switch context to btif task context (copy full union size for convenience) */
+ status = btif_transfer_context(btif_hf_upstreams_evt, (uint16_t)event, (void*)p_data, param_len, NULL);
+
+ /* catch any failed context transfers */
+ ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status);
+}
+
+
+/*******************************************************************************
+**
+** Function btif_hf_init
+**
+** Description initializes the hf interface
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t init( bthf_callbacks_t* callbacks )
+{
+ char * p_service_names[] = {BTIF_HSAG_SERVICE_NAME, BTIF_HFAG_SERVICE_NAME};
+
+ BTIF_TRACE_EVENT1("%s", __FUNCTION__);
+
+ bt_hf_callbacks = callbacks;
+
+ /* Enable and register with BTA-AG */
+ BTA_AgEnable (BTA_AG_PARSE, bte_hf_evt);
+ BTA_AgRegister(BTIF_HF_SERVICES, BTIF_HF_SECURITY, BTIF_HF_FEATURES,
+ p_service_names, BTIF_HF_ID_1);
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function connect
+**
+** Description connect to headset
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t connect( bt_bdaddr_t *bd_addr )
+{
+ CHECK_BTHF_INIT();
+
+ if (!is_connected(bd_addr))
+ {
+ btif_hf_cb.state = BTHF_CONNECTION_STATE_CONNECTING;
+ bdcpy(btif_hf_cb.connected_bda.address, bd_addr->address);
+
+ BTA_AgOpen(btif_hf_cb.handle, btif_hf_cb.connected_bda.address,
+ BTIF_HF_SECURITY, BTA_HSP_SERVICE_MASK | BTA_HFP_SERVICE_MASK);
+
+ return BT_STATUS_SUCCESS;
+ }
+
+ return BT_STATUS_BUSY;
+}
+
+/*******************************************************************************
+**
+** Function disconnect
+**
+** Description disconnect from headset
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t disconnect( bt_bdaddr_t *bd_addr )
+{
+ CHECK_BTHF_INIT();
+
+ if (is_connected(bd_addr))
+ {
+ BTA_AgClose(btif_hf_cb.handle);
+ return BT_STATUS_SUCCESS;
+ }
+
+ return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+**
+** Function connect_audio
+**
+** Description create an audio connection
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t connect_audio( bt_bdaddr_t *bd_addr )
+{
+ CHECK_BTHF_INIT();
+
+ if (is_connected(bd_addr))
+ {
+ BTA_AgAudioOpen(btif_hf_cb.handle);
+ return BT_STATUS_SUCCESS;
+ }
+
+ return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+**
+** Function disconnect_audio
+**
+** Description close the audio connection
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t disconnect_audio( bt_bdaddr_t *bd_addr )
+{
+ CHECK_BTHF_INIT();
+
+ if (is_connected(bd_addr))
+ {
+ BTA_AgAudioClose(btif_hf_cb.handle);
+ return BT_STATUS_SUCCESS;
+ }
+
+ return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+**
+** Function start_voice_recognition
+**
+** Description start voice recognition
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t start_voice_recognition()
+{
+ CHECK_BTHF_INIT();
+ if (is_connected(NULL))
+ {
+ tBTA_AG_RES_DATA ag_res;
+ memset(&ag_res, 0, sizeof(ag_res));
+ ag_res.state = 1;
+ BTA_AgResult (btif_hf_cb.handle, BTA_AG_BVRA_RES, &ag_res);
+
+ return BT_STATUS_SUCCESS;
+ }
+
+ return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+**
+** Function stop_voice_recognition
+**
+** Description stop voice recognition
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t stop_voice_recognition()
+{
+ CHECK_BTHF_INIT();
+
+ if (is_connected(NULL))
+ {
+ tBTA_AG_RES_DATA ag_res;
+ memset(&ag_res, 0, sizeof(ag_res));
+ ag_res.state = 0;
+ BTA_AgResult (btif_hf_cb.handle, BTA_AG_BVRA_RES, &ag_res);
+
+ return BT_STATUS_SUCCESS;
+ }
+
+ return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+**
+** Function volume_control
+**
+** Description volume control
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t volume_control(bthf_volume_type_t type, int volume)
+{
+ CHECK_BTHF_INIT();
+
+ tBTA_AG_RES_DATA ag_res;
+ memset(&ag_res, 0, sizeof(tBTA_AG_RES_DATA));
+ if (is_connected(NULL))
+ {
+ ag_res.num = volume;
+ BTA_AgResult(btif_hf_cb.handle,
+ (type == BTHF_VOLUME_TYPE_SPK) ? BTA_AG_SPK_RES : BTA_AG_MIC_RES,
+ &ag_res);
+ return BT_STATUS_SUCCESS;
+ }
+
+ return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+**
+** Function device_status_notification
+**
+** Description Combined device status change notification
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t device_status_notification(bthf_network_state_t ntk_state,
+ bthf_service_type_t svc_type, int signal, int batt_chg)
+{
+ CHECK_BTHF_INIT();
+
+ if (is_connected(NULL))
+ {
+ /* send all indicators to BTA.
+ ** BTA will make sure no duplicates are sent out
+ */
+ send_indicator_update(BTA_AG_IND_SERVICE,
+ (ntk_state == BTHF_NETWORK_STATE_AVAILABLE) ? 1 : 0);
+ send_indicator_update(BTA_AG_IND_ROAM,
+ (svc_type == BTHF_SERVICE_TYPE_HOME) ? 0 : 1);
+ send_indicator_update(BTA_AG_IND_SIGNAL, signal);
+ send_indicator_update(BTA_AG_IND_BATTCHG, batt_chg);
+ return BT_STATUS_SUCCESS;
+ }
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function cops_response
+**
+** Description Response for COPS command
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t cops_response(const char *cops)
+{
+ CHECK_BTHF_INIT();
+
+ if (is_connected(NULL))
+ {
+ tBTA_AG_RES_DATA ag_res;
+
+ /* Format the response */
+ sprintf (ag_res.str, "0,0,\"%s\"", cops);
+ ag_res.ok_flag = BTA_AG_OK_DONE;
+
+ BTA_AgResult (btif_hf_cb.handle, BTA_AG_COPS_RES, &ag_res);
+ return BT_STATUS_SUCCESS;
+ }
+ return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+**
+** Function cind_response
+**
+** Description Response for CIND command
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t cind_response(int svc, int num_active, int num_held,
+ bthf_call_state_t call_setup_state,
+ int signal, int roam, int batt_chg)
+{
+ CHECK_BTHF_INIT();
+
+ if (is_connected(NULL))
+ {
+ tBTA_AG_RES_DATA ag_res;
+
+ memset (&ag_res, 0, sizeof (ag_res));
+ sprintf (ag_res.str, "%d,%d,%d,%d,%d,%d,%d",
+ (num_active ? 1 : 0), /* Call state */
+ callstate_to_callsetup(call_setup_state), /* Callsetup state */
+ svc, /* network service */
+ signal, /* Signal strength */
+ roam, /* Roaming indicator */
+ batt_chg, /* Battery level */
+ (num_held ? 1 : 0)); /* Call held */
+
+ BTA_AgResult (btif_hf_cb.handle, BTA_AG_CIND_RES, &ag_res);
+
+ return BT_STATUS_SUCCESS;
+ }
+
+ return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+**
+** Function formatted_at_response
+**
+** Description Pre-formatted AT response, typically in response to unknown AT cmd
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t formatted_at_response(const char *rsp)
+{
+ CHECK_BTHF_INIT();
+ tBTA_AG_RES_DATA ag_res;
+
+ if (is_connected(NULL))
+ {
+ /* Format the response and send */
+ memset (&ag_res, 0, sizeof (ag_res));
+ strncpy(ag_res.str, rsp, BTA_AG_AT_MAX_LEN);
+ BTA_AgResult (btif_hf_cb.handle, BTA_AG_UNAT_RES, &ag_res);
+
+ return BT_STATUS_SUCCESS;
+ }
+
+ return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+**
+** Function at_response
+**
+** Description ok/error response
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t at_response(bthf_at_response_t response_code)
+{
+ CHECK_BTHF_INIT();
+
+ if (is_connected(NULL))
+ {
+ /* TODO: Fix the errcode */
+ send_at_result((response_code == BTHF_AT_RESPONSE_OK) ? BTA_AG_OK_DONE
+ : BTA_AG_OK_ERROR, 0);
+ }
+
+
+ return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+**
+** Function clcc_response
+**
+** Description response for CLCC command
+** Can be iteratively called for each call index. Call index
+** of 0 will be treated as NULL termination (Completes response)
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t clcc_response(int index, bthf_call_direction_t dir,
+ bthf_call_state_t state, bthf_call_mode_t mode,
+ bthf_call_mpty_type_t mpty, const char *number,
+ bthf_call_addrtype_t type)
+{
+ CHECK_BTHF_INIT();
+
+ if (is_connected(NULL))
+ {
+ tBTA_AG_RES_DATA ag_res;
+ int xx;
+
+ memset (&ag_res, 0, sizeof (ag_res));
+
+ /* Format the response */
+ if (index == 0)
+ {
+ ag_res.ok_flag = BTA_AG_OK_DONE;
+ }
+ else
+ {
+ BTIF_TRACE_EVENT6("clcc_response: [%d] dir %d state %d mode %d number = %s type = %d",
+ index, dir, state, mode, number, type);
+ xx = sprintf (ag_res.str, "%d,%d,%d,%d,%d",
+ index, dir, state, mode, mpty);
+
+ if (number)
+ {
+ if ((type == BTHF_CALL_ADDRTYPE_INTERNATIONAL) && (*number != '+'))
+ sprintf (&ag_res.str[xx], ",\"+%s\",%d", number, type);
+ else
+ sprintf (&ag_res.str[xx], ",\"%s\",%d", number, type);
+ }
+ }
+ BTA_AgResult (btif_hf_cb.handle, BTA_AG_CLCC_RES, &ag_res);
+
+ return BT_STATUS_SUCCESS;
+ }
+
+ return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+**
+** Function phone_state_change
+**
+** Description notify of a call state change
+** number & type: valid only for incoming & waiting call
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+
+static bt_status_t phone_state_change(int num_active, int num_held, bthf_call_state_t call_setup_state,
+ const char *number, bthf_call_addrtype_t type)
+{
+ tBTA_AG_RES res = 0xff;
+ tBTA_AG_RES_DATA ag_res;
+ bt_status_t status = BT_STATUS_SUCCESS;
+
+ CHECK_BTHF_INIT();
+
+ BTIF_TRACE_DEBUG6("phone_state_change: num_active=%d[%d] num_held=%d[%d]"\
+ " call_setup=%d [%d]", num_active, btif_hf_cb.num_active,
+ num_held, btif_hf_cb.num_held,
+ call_setup_state, btif_hf_cb.call_setup_state);
+
+ /* Check what has changed and update the corresponding indicators.
+ ** In ad
+ */
+
+ /* if all indicators are 0, send end call and return */
+ if (num_active == 0 && num_held == 0 && call_setup_state == BTHF_CALL_STATE_IDLE)
+ {
+ BTIF_TRACE_DEBUG1("%s: Phone on hook", __FUNCTION__);
+ BTA_AgResult (BTA_AG_HANDLE_ALL, BTA_AG_END_CALL_RES, NULL);
+ goto update_call_states;
+ }
+
+ /* Ringing call changed? */
+ if (call_setup_state != btif_hf_cb.call_setup_state)
+ {
+ BTIF_TRACE_DEBUG3("%s: Call setup states changed. old: %s new: %s",
+ __FUNCTION__, dump_hf_call_state(btif_hf_cb.call_setup_state),
+ dump_hf_call_state(call_setup_state));
+ memset(&ag_res, 0, sizeof(tBTA_AG_RES_DATA));
+
+ switch (call_setup_state)
+ {
+ case BTHF_CALL_STATE_IDLE:
+ {
+ switch (btif_hf_cb.call_setup_state)
+ {
+ case BTHF_CALL_STATE_INCOMING:
+ if (num_active > btif_hf_cb.num_active)
+ {
+ res = BTA_AG_IN_CALL_CONN_RES;
+ ag_res.audio_handle = btif_hf_cb.handle;
+ }
+ else if (num_held > btif_hf_cb.num_held)
+ res = BTA_AG_IN_CALL_HELD_RES;
+ else
+ res = BTA_AG_CALL_CANCEL_RES;
+ break;
+ case BTHF_CALL_STATE_DIALING:
+ case BTHF_CALL_STATE_ALERTING:
+ if (num_active > btif_hf_cb.num_active)
+ {
+ ag_res.audio_handle = btif_hf_cb.handle;
+ res = BTA_AG_OUT_CALL_CONN_RES;
+ }
+ else
+ res = BTA_AG_CALL_CANCEL_RES;
+ break;
+ default:
+ BTIF_TRACE_ERROR1("%s: Incorrect Call setup state transition", __FUNCTION__);
+ status = BT_STATUS_PARM_INVALID;
+ break;
+ }
+ } break;
+
+ case BTHF_CALL_STATE_INCOMING:
+ if (num_active || num_held)
+ res = BTA_AG_CALL_WAIT_RES;
+ else
+ res = BTA_AG_IN_CALL_RES;
+ if (number)
+ {
+ strcpy(ag_res.str, number);
+ ag_res.num = type;
+ }
+ break;
+ case BTHF_CALL_STATE_DIALING:
+ ag_res.audio_handle = btif_hf_cb.handle;
+ res = BTA_AG_OUT_CALL_ORIG_RES;
+ break;
+ case BTHF_CALL_STATE_ALERTING:
+ ag_res.audio_handle = btif_hf_cb.handle;
+ res = BTA_AG_OUT_CALL_ALERT_RES;
+ break;
+ default:
+ BTIF_TRACE_ERROR1("%s: Incorrect new ringing call state", __FUNCTION__);
+ status = BT_STATUS_PARM_INVALID;
+ break;
+ }
+ BTIF_TRACE_DEBUG3("%s: Call setup state changed. res=%d, audio_handle=%d", __FUNCTION__, res, ag_res.audio_handle);
+
+ if (res)
+ BTA_AgResult(BTA_AG_HANDLE_ALL, res, &ag_res);
+
+ /* update the call states and return */
+ goto update_call_states;
+ }
+
+ /* Active Changed? */
+ if (num_active != btif_hf_cb.num_active)
+ {
+ BTIF_TRACE_DEBUG3("%s: Active call states changed. old: %d new: %d", __FUNCTION__, btif_hf_cb.num_active, num_active);
+ send_indicator_update(BTA_AG_IND_CALL, (num_active ? 1 : 0));
+ }
+
+
+ /* Held Changed? */
+ if (num_held != btif_hf_cb.num_held)
+ {
+ BTIF_TRACE_DEBUG3("%s: Held call states changed. old: %d new: %d", __FUNCTION__, btif_hf_cb.num_held, num_held);
+ send_indicator_update(BTA_AG_IND_CALLHELD, ((num_held == 0) ? 0 : ((num_active == 0) ? 2 : 1)));
+ }
+
+ /* Calls Swapped? */
+ if ( (call_setup_state == btif_hf_cb.call_setup_state) &&
+ (num_active && num_held) &&
+ (num_active == btif_hf_cb.num_active) &&
+ (num_held == btif_hf_cb.num_held) )
+ {
+ BTIF_TRACE_DEBUG1("%s: Calls swapped", __FUNCTION__);
+ send_indicator_update(BTA_AG_IND_CALLHELD, 1);
+ }
+
+update_call_states:
+ btif_hf_cb.num_active = num_active;
+ btif_hf_cb.num_held = num_held;
+ btif_hf_cb.call_setup_state = call_setup_state;
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function cleanup
+**
+** Description Closes the HF interface
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static void cleanup( void )
+{
+ BTIF_TRACE_EVENT1("%s", __FUNCTION__);
+
+ if (bt_hf_callbacks)
+ {
+ /* De-register AG */
+ BTA_AgDeregister(btif_hf_cb.handle);
+ /* Disable AG */
+ BTA_AgDisable();
+ bt_hf_callbacks = NULL;
+ }
+}
+
+static const bthf_interface_t bthfInterface = {
+ sizeof(bt_interface_t),
+ init,
+ connect,
+ disconnect,
+ connect_audio,
+ disconnect_audio,
+ start_voice_recognition,
+ stop_voice_recognition,
+ volume_control,
+ device_status_notification,
+ cops_response,
+ cind_response,
+ formatted_at_response,
+ at_response,
+ clcc_response,
+ phone_state_change,
+ cleanup,
+};
+
+/*******************************************************************************
+**
+** Function btif_hf_get_interface
+**
+** Description Get the hf callback interface
+**
+** Returns bthf_interface_t
+**
+*******************************************************************************/
+const bthf_interface_t *btif_hf_get_interface()
+{
+ BTIF_TRACE_EVENT1("%s", __FUNCTION__);
+ return &bthfInterface;
+}
diff --git a/btif/src/btif_storage.c b/btif/src/btif_storage.c
new file mode 100644
index 0000000..a55821d
--- /dev/null
+++ b/btif/src/btif_storage.c
@@ -0,0 +1,1027 @@
+/************************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * This program is the proprietary software of Broadcom Corporation and/or its
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
+ *
+ * Except as expressly set forth in the Authorized License,
+ *
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
+ * Broadcom integrated circuit products.
+ *
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT
+ * OF USE OR PERFORMANCE OF THE SOFTWARE.
+ *
+ * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR
+ * ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+ *
+ ************************************************************************************/
+
+/************************************************************************************
+ *
+ * Filename: btif_storage.c
+ *
+ * Description: Stores the local BT adapter and remote device properties in
+ * NVRAM storage, typically as text files in the
+ * mobile's filesystem
+ *
+ *
+ * Data storage directory structure
+ *
+ * data
+ * `-- misc
+ * `-- bluedroid
+ * `-- LOCAL
+ * |-- adapter_info - Local adapter config
+ * |-- remote_devices - Remote devices and Timestamp
+ * |-- remote_devclass - Remote devices' COD
+ * |-- remote_devtype - Remote devices' type
+ * |-- remote_names - Remote devices' names
+ * |-- remote_aliases - Remote devices' Friendly names
+ * `-- remote_services - Remote devices' services
+ *
+ *
+ * adapter_info - Key/Value
+ * name <space> <Name of Local Bluetooth device>
+ * scan_mode <space> <Scan Mode>
+ * discovery_timeout <space> <Discovery Timeout in seconds>
+ *
+ * remote_devices - Key/Value
+ * <remote device bd_addr> <space> <Timestamp>
+ *
+ * remote_devclass - Key/Value
+ * <remote device bd_addr> <space> <Device class>
+ *
+ * remote_devtype - Key/Value
+ * <remote_device bd_addr><space> <Device Type>
+ *
+ * remote_names - Key/Value
+ * <remote_device bd_addr> <space> <Bluetooth device Name as reported by the controller>
+ *
+ * remote_linkkeys - Key/Value
+ * <remote device bd_addr > <space> <LinkKey> <space> <KeyType> <space> <PinLength>
+ *
+ * remote_aliases - Key/Value
+ * <remote device bd_addr> <space> <Friendy Name>
+ *
+ * remote_services - Key/Value
+ * <remote_device bd_addr> <space> <List of UUIDs separated by semicolons>
+ *
+ ***********************************************************************************/
+#include <stdlib.h>
+#include <time.h>
+
+#include <hardware/bluetooth.h>
+
+#define LOG_TAG "BTIF_STORAGE"
+
+#include "btif_api.h"
+
+#include "btif_util.h"
+#include "unv.h"
+#include "bd.h"
+
+/************************************************************************************
+** Constants & Macros
+************************************************************************************/
+
+#define BTIF_STORAGE_PATH_BLUEDROID "/data/misc/bluedroid"
+
+#define BTIF_STORAGE_PATH_ADAPTER_INFO "adapter_info"
+#define BTIF_STORAGE_PATH_REMOTE_DEVICES "remote_devices"
+#define BTIF_STORAGE_PATH_REMOTE_DEVCLASSES "remote_devclasses"
+#define BTIF_STORAGE_PATH_REMOTE_DEVTYPES "remote_devtypes"
+#define BTIF_STORAGE_PATH_REMOTE_NAMES "remote_names"
+#define BTIF_STORAGE_PATH_REMOTE_LINKKEYS "remote_linkkeys"
+#define BTIF_STORAGE_PATH_REMOTE_ALIASES "remote_aliases"
+#define BTIF_STORAGE_PATH_REMOTE_SERVICES "remote_services"
+
+#define BTIF_STORAGE_KEY_ADAPTER_NAME "name"
+#define BTIF_STORAGE_KEY_ADAPTER_SCANMODE "scan_mode"
+#define BTIF_STORAGE_KEY_ADAPTER_DISC_TIMEOUT "discovery_timeout"
+
+/* This is a local property to add a device found */
+#define BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP 0xFF
+
+#define BTIF_STORAGE_GET_ADAPTER_PROP(t,v,l,p) \
+ {p.type=t;p.val=v;p.len=l; btif_storage_get_adapter_property(&p);}
+
+#define BTIF_STORAGE_GET_REMOTE_PROP(b,t,v,l,p) \
+ {p.type=t;p.val=v;p.len=l;btif_storage_get_remote_device_property(b,&p);}
+
+#define STORAGE_BDADDR_STRING_SZ (18) /* 00:11:22:33:44:55 */
+#define STORAGE_UUID_STRING_SIZE (36+1) /* 00001200-0000-1000-8000-00805f9b34fb; */
+#define STORAGE_PINLEN_STRING_MAX_SIZE (2) /* ascii pinlen max chars */
+#define STORAGE_KEYTYPE_STRING_MAX_SIZE (1) /* ascii keytype max chars */
+
+#define STORAGE_KEY_TYPE_MAX (10)
+
+
+/* <18 char bd addr> <space> LIST< <36 char uuid> <;> > <keytype (dec)> <pinlen> */
+#define BTIF_REMOTE_SERVICES_ENTRY_SIZE_MAX (STORAGE_BDADDR_STRING_SZ + 1 +\
+ STORAGE_UUID_STRING_SIZE*BT_MAX_NUM_UUIDS + \
+ STORAGE_PINLEN_STRING_MAX_SIZE +\
+ STORAGE_KEYTYPE_STRING_MAX_SIZE)
+
+#define STORAGE_REMOTE_LINKKEYS_ENTRY_SIZE (LINK_KEY_LEN*2 + 1 + 2 + 1 + 2)
+
+/* currently remote services is the potentially largest entry */
+#define BTIF_STORAGE_MAX_LINE_SZ BTIF_REMOTE_SERVICES_ENTRY_SIZE_MAX
+
+/* check against unv max entry size at compile time */
+#if (BTIF_STORAGE_ENTRY_MAX_SIZE > UNV_MAXLINE_LENGTH)
+#error "btif storage entry size exceeds unv max line size"
+#endif
+
+/************************************************************************************
+** Local type definitions
+************************************************************************************/
+typedef struct {
+ uint32_t num_devices;
+ bt_bdaddr_t devices[BTM_SEC_MAX_DEVICE_RECORDS];
+} btif_bonded_devices_t;
+
+/************************************************************************************
+** Static variables
+************************************************************************************/
+
+/************************************************************************************
+** Static functions
+************************************************************************************/
+/*******************************************************************************
+**
+** Function btif_in_make_filename
+**
+** Description Internal helper function to create NVRAM file path
+** from address and filename
+**
+** Returns NVRAM file path if successfull, NULL otherwise
+**
+*******************************************************************************/
+static char* btif_in_make_filename(bt_bdaddr_t *bd_addr, char *fname)
+{
+ static char path[256];
+ bdstr_t bdstr;
+
+ if (fname == NULL)return NULL;
+ if (bd_addr)
+ {
+ sprintf(path, "%s/%s/%s", BTIF_STORAGE_PATH_BLUEDROID,
+ bd2str(bd_addr, &bdstr), fname);
+ }
+ else
+ {
+ /* local adapter */
+ sprintf(path, "%s/LOCAL/%s", BTIF_STORAGE_PATH_BLUEDROID, fname);
+ }
+
+ return (char*)path;
+}
+
+/*******************************************************************************
+**
+** Function btif_in_adapter_key_from_type
+**
+** Description Internal helper function to map a property type
+** to the NVRAM filename key
+**
+** Returns NVRAM filename key if successfull, 'NO_KEY' otherwise
+**
+*******************************************************************************/
+static const char *btif_in_get_adapter_key_from_type(bt_property_type_t type)
+{
+ switch (type)
+ {
+ case BT_PROPERTY_BDNAME:
+ return BTIF_STORAGE_KEY_ADAPTER_NAME;
+ case BT_PROPERTY_ADAPTER_SCAN_MODE:
+ return BTIF_STORAGE_KEY_ADAPTER_SCANMODE;
+ case BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT:
+ return BTIF_STORAGE_KEY_ADAPTER_DISC_TIMEOUT;
+ default:
+ /* return valid string to avoid passing NULL to NV RAM driver */
+ return "NO_KEY";
+ }
+}
+
+/*******************************************************************************
+**
+** Function btif_in_split_uuids_string_to_list
+**
+** Description Internal helper function to split the string of UUIDs
+** read from the NVRAM to an array
+**
+** Returns None
+**
+*******************************************************************************/
+static void btif_in_split_uuids_string_to_list(char *str, bt_uuid_t *p_uuid,
+ uint32_t *p_num_uuid)
+{
+ char buf[64];
+ char *p_start = str;
+ char *p_needle;
+ uint32_t num = 0;
+ do
+ {
+ p_needle = strchr(p_start, ';');
+ memset(buf, 0, sizeof(buf));
+ strncpy(buf, p_start, (p_needle-p_start));
+ string_to_uuid(buf, p_uuid + num);
+ num++;
+ p_start = ++p_needle;
+
+ } while (*p_start != 0);
+ *p_num_uuid = num;
+}
+
+/*******************************************************************************
+**
+** Function btif_in_str_to_property
+**
+** Description Internal helper function to convert the string read from
+** NVRAM into a property->val. Also sets the property->len.
+** Assumption is that property->val has enough memory to
+** store the string fetched from NVRAM
+**
+** Returns BT_STATUS_SUCCESS if successful, BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+static bt_status_t btif_in_str_to_property(char *value, bt_property_t *property)
+{
+ bt_status_t status = BT_STATUS_SUCCESS;
+ property->len = 0;
+
+ /* if Value is NULL, then just set the property->len to 0 and return.
+ This is possible if the entry does not exist */
+ if (value == NULL) {
+ status = BT_STATUS_FAIL;
+ }
+ switch (property->type)
+ {
+ case BT_PROPERTY_BDNAME:
+ case BT_PROPERTY_REMOTE_FRIENDLY_NAME:
+ {
+ *((char*)property->val) = 0;
+ if (value)
+ {
+ property->len = strlen(value)+1;
+ strcpy((char*)property->val, value);
+ }
+ } break;
+ case BT_PROPERTY_ADAPTER_SCAN_MODE:
+ case BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT:
+ {
+ *((uint32_t *)property->val) = 0;
+ if (value)
+ {
+ uint32_t ival;
+ property->len = sizeof(uint32_t);
+ ival = atoi(value);
+ memcpy((uint32_t*)property->val, &ival, sizeof(uint32_t));
+ }
+ } break;
+ case BT_PROPERTY_CLASS_OF_DEVICE:
+ case BT_PROPERTY_TYPE_OF_DEVICE:
+ {
+ *((uint32_t *)property->val) = 0;
+ if (value)
+ {
+ uint32_t ival;
+ property->len = sizeof(uint32_t);
+ ival = strtol(value, NULL, 16);
+ memcpy((uint32_t*)property->val, &ival, sizeof(uint32_t));
+ }
+ } break;
+ case BT_PROPERTY_UUIDS:
+ {
+ if (value)
+ {
+ bt_uuid_t *p_uuid = (bt_uuid_t*)property->val;
+ uint32_t num_uuids = 0;
+ btif_in_split_uuids_string_to_list(value, p_uuid, &num_uuids);
+ property->len = num_uuids * sizeof(bt_uuid_t);
+ }
+ } break;
+ default:
+ {
+ break;
+ }
+ }
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function btif_in_property_to_str
+**
+** Description Internal helper function to convert the property->val
+** to a string that can be written to the NVRAM
+**
+** Returns BT_STATUS_SUCCESS if successful, BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+static bt_status_t btif_in_property_to_str(bt_property_t *property, char *value)
+{
+ switch (property->type)
+ {
+ case BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP:
+ {
+ sprintf(value, "%d", (int)time(NULL));
+ }break;
+ case BT_PROPERTY_BDNAME:
+ case BT_PROPERTY_REMOTE_FRIENDLY_NAME:
+ {
+ strcpy(value, (char*)property->val);
+ }break;
+ case BT_PROPERTY_ADAPTER_SCAN_MODE:
+ case BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT:
+ {
+ sprintf(value, "%d", *((uint32_t*)property->val));
+ }break;
+ case BT_PROPERTY_CLASS_OF_DEVICE:
+ case BT_PROPERTY_TYPE_OF_DEVICE:
+ {
+ sprintf(value, "0x%x", *((uint32_t*)property->val));
+ }break;
+ case BT_PROPERTY_UUIDS:
+ {
+ uint32_t i;
+ char buf[64];
+ value[0] = 0;
+ for (i=0; i < (property->len)/sizeof(bt_uuid_t); i++)
+ {
+ bt_uuid_t *p_uuid = (bt_uuid_t*)property->val + i;
+ memset(buf, 0, sizeof(buf));
+ uuid_to_string(p_uuid, buf);
+ strcat(value, buf);
+ strcat(value, ";");
+ }
+ value[strlen(value)] = 0;
+ }break;
+ default:
+ {
+ return BT_STATUS_FAIL;
+ }
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function btif_in_get_remote_device_path_from_property
+**
+** Description Internal helper function to map a property type
+** to the NVRAM filename key
+**
+** Returns NVRAM filename key if successfull, NULL otherwise
+**
+*******************************************************************************/
+static char* btif_in_get_remote_device_path_from_property(bt_property_type_t type)
+{
+ switch (type)
+ {
+ case BT_PROPERTY_BDADDR:
+ case BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP:
+ return BTIF_STORAGE_PATH_REMOTE_DEVICES;
+ case BT_PROPERTY_BDNAME:
+ return BTIF_STORAGE_PATH_REMOTE_NAMES;
+ case BT_PROPERTY_CLASS_OF_DEVICE:
+ return BTIF_STORAGE_PATH_REMOTE_DEVCLASSES;
+ case BT_PROPERTY_TYPE_OF_DEVICE:
+ return BTIF_STORAGE_PATH_REMOTE_DEVTYPES;
+ case BT_PROPERTY_REMOTE_FRIENDLY_NAME:
+ return BTIF_STORAGE_PATH_REMOTE_ALIASES;
+ case BT_PROPERTY_UUIDS:
+ return BTIF_STORAGE_PATH_REMOTE_SERVICES;
+ default:
+ return NULL;
+ }
+}
+
+/*******************************************************************************
+**
+** Function btif_in_load_device_iter_cb
+**
+** Description Internal iterator callback from UNV when loading the
+** link-keys
+**
+** Returns
+**
+*******************************************************************************/
+
+int btif_in_load_device_iter_cb(char *key, char *value, void *userdata)
+{
+ btif_bonded_devices_t *p_bonded_devices = (btif_bonded_devices_t *)userdata;
+ DEV_CLASS dev_class = {0, 0, 0};
+ bt_bdaddr_t bd_addr;
+ LINK_KEY link_key;
+ uint8_t key_type;
+ uint8_t pin_length;
+ int offset = 0;
+ int8_t temp[3];
+ uint32_t i;
+
+ memset(temp, 0, sizeof(temp));
+
+ BTIF_TRACE_DEBUG3("%s %s %s", __FUNCTION__, key, value);
+
+ /* convert 32 char linkkey (fixed size) */
+ for (i = 0; i < LINK_KEY_LEN; i++)
+ {
+ memcpy(temp, value + (i * 2), 2);
+ link_key[i] = (uint8_t) strtol((const char *)temp, NULL, 16);
+ offset+=2;
+ }
+
+ /* skip space */
+ offset++;
+
+ /* convert decimal keytype (max 2 ascii chars) */
+ memset(temp, 0, sizeof(temp));
+ memcpy(temp, value + offset, 2);
+ key_type = (uint8_t)strtoul((const char *)temp, NULL, 10);
+
+ /* value + space */
+ offset+=2;
+
+ /* convert decimal pinlen (max 2 ascii chars) */
+ memset(temp, 0, sizeof(temp));
+ memcpy(temp, value + offset, 2);
+ pin_length = (uint8_t)strtoul((const char *)temp, NULL, 10);
+
+ /* convert bd address (keystring) */
+ str2bd(key, &bd_addr);
+
+ /* add extracted information to BTA security manager */
+ BTA_DmAddDevice(bd_addr.address, dev_class, link_key, 0, 0, key_type, 0);
+
+ /* Fill in the bonded devices */
+ memcpy(&p_bonded_devices->devices[p_bonded_devices->num_devices++], &bd_addr, sizeof(bt_bdaddr_t));
+
+ return 0;
+}
+
+/*******************************************************************************
+**
+** Function btif_in_fetch_bonded_devices
+**
+** Description Internal helper function to fetch the bonded devices
+** from NVRAM
+**
+** Returns BT_STATUS_SUCCESS if successful, BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+static bt_status_t btif_in_fetch_bonded_devices(btif_bonded_devices_t *p_bonded_devices)
+{
+ char *fname;
+ int ret;
+
+ memset(p_bonded_devices, 0, sizeof(btif_bonded_devices_t));
+
+ fname = btif_in_make_filename(NULL, BTIF_STORAGE_PATH_REMOTE_LINKKEYS);
+
+ if (fname == NULL)
+ return BT_STATUS_FAIL;
+
+ ret = unv_read_key_iter(fname, btif_in_load_device_iter_cb, p_bonded_devices);
+
+ if (ret < 0)
+ return BT_STATUS_FAIL;
+
+ return BT_STATUS_SUCCESS;
+}
+
+/************************************************************************************
+** Externs
+************************************************************************************/
+
+/************************************************************************************
+** Functions
+************************************************************************************/
+
+/** functions are synchronous.
+ * functions can be called by both internal modules such as BTIF_DM and by external entiries from HAL via BTIF_context_switch
+ * For OUT parameters, caller is expected to provide the memory.
+ * Caller is expected to provide a valid pointer to 'property->value' based on the property->type
+ */
+/*******************************************************************************
+**
+** Function btif_storage_get_adapter_property
+**
+** Description BTIF storage API - Fetches the adapter property->type
+** from NVRAM and fills property->val.
+** Caller should provide memory for property->val and
+** set the property->val
+**
+** Returns BT_STATUS_SUCCESS if the fetch was successful,
+** BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_storage_get_adapter_property(bt_property_t *property)
+{
+ bt_status_t status;
+ char *fname;
+ char *value;
+ int ret;
+ char linebuf[BTIF_STORAGE_MAX_LINE_SZ];
+
+ /* initialize property->len */
+ property->len = 0;
+
+ /* Special handling for adapter BD_ADDR and BONDED_DEVICES */
+ if (property->type == BT_PROPERTY_BDADDR)
+ {
+ BD_ADDR addr;
+ bt_bdaddr_t *bd_addr = (bt_bdaddr_t*)property->val;
+ BTM_GetLocalDeviceAddr(addr);
+ bdcpy(bd_addr->address, addr);
+ property->len = sizeof(bt_bdaddr_t);
+
+ return BT_STATUS_SUCCESS;
+ }
+ else if (property->type == BT_PROPERTY_ADAPTER_BONDED_DEVICES)
+ {
+ btif_bonded_devices_t bonded_devices;
+
+ btif_in_fetch_bonded_devices(&bonded_devices);
+
+ BTIF_TRACE_DEBUG2("%s: Number of bonded devices: %d", __FUNCTION__, bonded_devices.num_devices);
+
+ if (bonded_devices.num_devices > 0)
+ {
+ property->len = bonded_devices.num_devices * sizeof(bt_bdaddr_t);
+ memcpy(property->val, bonded_devices.devices, property->len);
+ }
+
+ /* if there are no bonded_devices, then length shall be 0 */
+ return BT_STATUS_SUCCESS;
+ }
+ else if (property->type == BT_PROPERTY_UUIDS)
+ {
+ /* publish list of local supported services */
+ bt_uuid_t *p_uuid = (bt_uuid_t*)property->val;
+ uint32_t num_uuids = 0;
+
+#if BTA_AG_INCLUDED == TRUE
+ uuid16_to_uuid128(UUID_SERVCLASS_AG_HANDSFREE, p_uuid + num_uuids);
+ num_uuids++;
+ uuid16_to_uuid128(UUID_SERVCLASS_HEADSET_AUDIO_GATEWAY, p_uuid + num_uuids);
+ num_uuids++;
+#endif
+
+ property->len = (num_uuids)*sizeof(bt_uuid_t);
+ return BT_STATUS_SUCCESS;
+ }
+
+ /* fall through for other properties */
+
+ /* create filepath */
+ fname = btif_in_make_filename(NULL, BTIF_STORAGE_PATH_ADAPTER_INFO);
+
+ if (fname == NULL)
+ {
+ return BT_STATUS_FAIL;
+ }
+
+ ret = unv_create_file(fname);
+
+ if (ret < 0)
+ {
+ return BT_STATUS_FAIL;
+ }
+
+ value = unv_read_key( fname,
+ btif_in_get_adapter_key_from_type(property->type),
+ linebuf, UNV_MAXLINE_LENGTH);
+
+ if (value == NULL)
+ {
+ /* properties not yet existing, request default values from bta */
+ return btif_dm_get_adapter_property(property);
+ }
+ else
+ {
+ /* convert to property_t data structure */
+ status = btif_in_str_to_property(value, property);
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function btif_storage_set_adapter_property
+**
+** Description BTIF storage API - Stores the adapter property
+** to NVRAM
+**
+** Returns BT_STATUS_SUCCESS if the store was successful,
+** BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_storage_set_adapter_property(bt_property_t *property)
+{
+ char *fname;
+ char value[1200];
+ int ret;
+
+ fname = btif_in_make_filename(NULL, BTIF_STORAGE_PATH_ADAPTER_INFO);
+ if (fname == NULL)
+ {
+ return BT_STATUS_FAIL;
+ }
+ ret = unv_create_file(fname);
+ if (ret < 0)
+ {
+ return BT_STATUS_FAIL;
+ }
+
+ if (btif_in_property_to_str(property, value) != BT_STATUS_SUCCESS)
+ {
+ return BT_STATUS_FAIL;
+ }
+ ret = unv_write_key(fname, btif_in_get_adapter_key_from_type(property->type), value);
+ if (ret < 0)
+ {
+ return BT_STATUS_FAIL;
+ }
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function btif_storage_get_remote_device_property
+**
+** Description BTIF storage API - Fetches the remote device property->type
+** from NVRAM and fills property->val.
+** Caller should provide memory for property->val and
+** set the property->val
+**
+** Returns BT_STATUS_SUCCESS if the fetch was successful,
+** BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_storage_get_remote_device_property(bt_bdaddr_t *remote_bd_addr,
+ bt_property_t *property)
+{
+ char linebuf[BTIF_STORAGE_MAX_LINE_SZ];
+ char *fname;
+ char *value;
+ int ret;
+ bdstr_t bdstr;
+
+ fname = btif_in_make_filename(NULL,
+ btif_in_get_remote_device_path_from_property(property->type));
+ if (fname == NULL)
+ {
+ return BT_STATUS_FAIL;
+ }
+
+ ret = unv_create_file(fname);
+ if (ret < 0)
+ {
+ return BT_STATUS_FAIL;
+ }
+
+ value = unv_read_key(fname, bd2str(remote_bd_addr, &bdstr), linebuf, BTIF_STORAGE_MAX_LINE_SZ);
+
+ return btif_in_str_to_property(value, property);
+}
+
+/*******************************************************************************
+**
+** Function btif_storage_set_remote_device_property
+**
+** Description BTIF storage API - Stores the remote device property
+** to NVRAM
+**
+** Returns BT_STATUS_SUCCESS if the store was successful,
+** BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_storage_set_remote_device_property(bt_bdaddr_t *remote_bd_addr,
+ bt_property_t *property)
+{
+ char value[1200];
+ char *fname;
+ bdstr_t bdstr;
+ int ret;
+
+ fname = btif_in_make_filename(NULL,
+ btif_in_get_remote_device_path_from_property(property->type));
+ if (fname == NULL)
+ {
+ return BT_STATUS_FAIL;
+ }
+ ret = unv_create_file(fname);
+ if (ret < 0)
+ {
+ return BT_STATUS_FAIL;
+ }
+ memset(value, 0, sizeof(value));
+
+ if (btif_in_property_to_str(property, value) != BT_STATUS_SUCCESS)
+ {
+ return BT_STATUS_FAIL;
+ }
+
+ ret = unv_write_key(fname, bd2str(remote_bd_addr, &bdstr), value);
+ if (ret < 0)
+ {
+ return BT_STATUS_FAIL;
+ }
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function btif_storage_add_remote_device
+**
+** Description BTIF storage API - Adds a newly discovered device to NVRAM
+** along with the timestamp. Also, stores the various
+** properties - RSSI, BDADDR, NAME (if found in EIR)
+**
+** Returns BT_STATUS_SUCCESS if the store was successful,
+** BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_storage_add_remote_device(bt_bdaddr_t *remote_bdaddr,
+ uint32_t num_properties,
+ bt_property_t *properties)
+{
+ uint32_t i = 0;
+ /* TODO: If writing a property, fails do we go back undo the earlier
+ * written properties? */
+ for (i=0; i < num_properties; i++)
+ {
+ /* Ignore the RSSI as this is not stored in DB */
+ if (properties[i].type == BT_PROPERTY_REMOTE_RSSI)
+ continue;
+
+ /* BD_ADDR for remote device needs special handling as we also store timestamp */
+ if (properties[i].type == BT_PROPERTY_BDADDR)
+ {
+ bt_property_t addr_prop;
+ memcpy(&addr_prop, &properties[i], sizeof(bt_property_t));
+ addr_prop.type = BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP;
+ btif_storage_set_remote_device_property(remote_bdaddr,
+ &addr_prop);
+ }
+ else
+ {
+ btif_storage_set_remote_device_property(remote_bdaddr,
+ &properties[i]);
+ }
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function btif_storage_add_bonded_device
+**
+** Description BTIF storage API - Adds the newly bonded device to NVRAM
+** along with the link-key, Key type and Pin key length
+**
+** Returns BT_STATUS_SUCCESS if the store was successful,
+** BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+
+bt_status_t btif_storage_add_bonded_device(bt_bdaddr_t *remote_bd_addr,
+ LINK_KEY link_key,
+ uint8_t key_type,
+ uint8_t pin_length)
+{
+ char value[STORAGE_REMOTE_LINKKEYS_ENTRY_SIZE];
+ uint32_t i = 0;
+ char *fname;
+ bdstr_t bdstr;
+ int ret;
+
+ fname = btif_in_make_filename(NULL,
+ BTIF_STORAGE_PATH_REMOTE_LINKKEYS);
+ if (fname == NULL)
+ {
+ return BT_STATUS_FAIL;
+ }
+ ret = unv_create_file(fname);
+
+ if (ret < 0)
+ {
+ return BT_STATUS_FAIL;
+ }
+
+ /* check ascii representations doesn't exceed max size */
+
+ if (key_type > STORAGE_KEY_TYPE_MAX)
+ return BT_STATUS_FAIL;
+
+ if (pin_length > PIN_CODE_LEN)
+ return BT_STATUS_FAIL;
+
+ memset(value, 0, sizeof(value));
+
+ for (i = 0; i < LINK_KEY_LEN; i++)
+ sprintf(value + (i * 2), "%2.2X", link_key[i]);
+
+ sprintf(value + (LINK_KEY_LEN*2), " %d %d", key_type, pin_length);
+
+ ret = unv_write_key(fname, bd2str(remote_bd_addr, &bdstr), value);
+
+ if (ret < 0)
+ {
+ return BT_STATUS_FAIL;
+ }
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function btif_storage_remove_bonded_device
+**
+** Description BTIF storage API - Deletes the bonded device from NVRAM
+**
+** Returns BT_STATUS_SUCCESS if the deletion was successful,
+** BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_storage_remove_bonded_device(bt_bdaddr_t *remote_bd_addr)
+{
+ char *fname;
+ int ret;
+ bdstr_t bdstr;
+
+ fname = btif_in_make_filename(NULL,
+ BTIF_STORAGE_PATH_REMOTE_LINKKEYS);
+ if (fname == NULL)
+ {
+ return BT_STATUS_FAIL;
+ }
+ ret = unv_create_file(fname);
+
+ if (ret < 0)
+ {
+ return BT_STATUS_FAIL;
+ }
+
+ ret = unv_remove_key(fname, bd2str(remote_bd_addr, &bdstr));
+
+ if (ret < 0)
+ {
+ return BT_STATUS_FAIL;
+ }
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function btif_storage_load_bonded_devices
+**
+** Description BTIF storage API - Loads all the bonded devices from NVRAM
+** and adds to the BTA.
+** Additionally, this API also invokes the adaper_properties_cb
+** and remote_device_properties_cb for each of the bonded devices.
+**
+** Returns BT_STATUS_SUCCESS if successful, BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_storage_load_bonded_devices(void)
+{
+ char *fname;
+ btif_bonded_devices_t bonded_devices;
+ uint32_t i = 0;
+ bt_property_t adapter_props[6];
+ uint32_t num_props = 0;
+ bt_property_t remote_properties[8];
+ bt_bdaddr_t addr;
+ bt_bdname_t name, alias;
+ bt_scan_mode_t mode;
+ uint32_t disc_timeout;
+ bt_bdaddr_t *devices_list;
+ bt_uuid_t local_uuids[BT_MAX_NUM_UUIDS];
+ bt_uuid_t remote_uuids[BT_MAX_NUM_UUIDS];
+ uint32_t cod, devtype;
+
+ btif_in_fetch_bonded_devices(&bonded_devices);
+
+ /* Now send the adapter_properties_cb with all adapter_properties */
+ {
+ memset(adapter_props, 0, sizeof(adapter_props));
+
+ /* BD_ADDR */
+ BTIF_STORAGE_GET_ADAPTER_PROP(BT_PROPERTY_BDADDR, &addr, sizeof(addr),
+ adapter_props[num_props]);
+ num_props++;
+
+ /* BD_NAME */
+ BTIF_STORAGE_GET_ADAPTER_PROP(BT_PROPERTY_BDNAME, &name, sizeof(name),
+ adapter_props[num_props]);
+ num_props++;
+
+ /* SCAN_MODE */
+ BTIF_STORAGE_GET_ADAPTER_PROP(BT_PROPERTY_ADAPTER_SCAN_MODE, &mode, sizeof(mode),
+ adapter_props[num_props]);
+ num_props++;
+
+ /* DISC_TIMEOUT */
+ BTIF_STORAGE_GET_ADAPTER_PROP(BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT,
+ &disc_timeout, sizeof(disc_timeout),
+ adapter_props[num_props]);
+ num_props++;
+
+ /* BONDED_DEVICES */
+ devices_list = (bt_bdaddr_t*)malloc(sizeof(bt_bdaddr_t)*bonded_devices.num_devices);
+ adapter_props[num_props].type = BT_PROPERTY_ADAPTER_BONDED_DEVICES;
+ adapter_props[num_props].len = bonded_devices.num_devices * sizeof(bt_bdaddr_t);
+ adapter_props[num_props].val = devices_list;
+ for (i=0; i < bonded_devices.num_devices; i++)
+ {
+ memcpy(devices_list + i, &bonded_devices.devices[i], sizeof(bt_bdaddr_t));
+ }
+ num_props++;
+
+ /* LOCAL UUIDs */
+ BTIF_STORAGE_GET_ADAPTER_PROP(BT_PROPERTY_UUIDS,
+ local_uuids, sizeof(local_uuids),
+ adapter_props[num_props]);
+ num_props++;
+
+ btif_adapter_properties_evt(BT_STATUS_SUCCESS, num_props, adapter_props);
+
+ free(devices_list);
+ }
+
+ BTIF_TRACE_EVENT2("%s: %d bonded devices found", __FUNCTION__, bonded_devices.num_devices);
+
+ {
+ for (i = 0; i < bonded_devices.num_devices; i++)
+ {
+ bt_bdaddr_t *p_remote_addr;
+
+ num_props = 0;
+ p_remote_addr = &bonded_devices.devices[i];
+ memset(remote_properties, 0, sizeof(remote_properties));
+ BTIF_STORAGE_GET_REMOTE_PROP(p_remote_addr, BT_PROPERTY_BDNAME,
+ &name, sizeof(name),
+ remote_properties[num_props]);
+ num_props++;
+
+ BTIF_STORAGE_GET_REMOTE_PROP(p_remote_addr, BT_PROPERTY_REMOTE_FRIENDLY_NAME,
+ &alias, sizeof(alias),
+ remote_properties[num_props]);
+ num_props++;
+
+ BTIF_STORAGE_GET_REMOTE_PROP(p_remote_addr, BT_PROPERTY_CLASS_OF_DEVICE,
+ &cod, sizeof(cod),
+ remote_properties[num_props]);
+ num_props++;
+
+ BTIF_STORAGE_GET_REMOTE_PROP(p_remote_addr, BT_PROPERTY_TYPE_OF_DEVICE,
+ &devtype, sizeof(devtype),
+ remote_properties[num_props]);
+ num_props++;
+
+ BTIF_STORAGE_GET_REMOTE_PROP(p_remote_addr, BT_PROPERTY_UUIDS,
+ remote_uuids, sizeof(remote_uuids),
+ remote_properties[num_props]);
+ num_props++;
+
+ btif_remote_properties_evt(BT_STATUS_SUCCESS, p_remote_addr,
+ num_props, remote_properties);
+ }
+ }
+ return BT_STATUS_SUCCESS;
+}
diff --git a/btif/src/btif_util.c b/btif/src/btif_util.c
new file mode 100644
index 0000000..ad3ba86
--- /dev/null
+++ b/btif/src/btif_util.c
@@ -0,0 +1,359 @@
+/************************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * This program is the proprietary software of Broadcom Corporation and/or its
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
+ *
+ * Except as expressly set forth in the Authorized License,
+ *
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
+ * Broadcom integrated circuit products.
+ *
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT
+ * OF USE OR PERFORMANCE OF THE SOFTWARE.
+ *
+ * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR
+ * ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+ *
+ ************************************************************************************/
+
+/************************************************************************************
+ *
+ * Filename: btif_util.c
+ *
+ * Description: Miscellaneous helper functions
+ *
+ *
+ ***********************************************************************************/
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_hf.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define LOG_TAG "BTIF_UTIL"
+#include "btif_common.h"
+#include "bta_api.h"
+#include "gki.h"
+#include "btu.h"
+#include "bte.h"
+#include "bd.h"
+#include "btif_dm.h"
+#include "btif_util.h"
+#include "bta_ag_api.h"
+
+
+/************************************************************************************
+** Constants & Macros
+************************************************************************************/
+
+/************************************************************************************
+** Local type definitions
+************************************************************************************/
+
+/************************************************************************************
+** Static variables
+************************************************************************************/
+
+/************************************************************************************
+** Static functions
+************************************************************************************/
+
+/************************************************************************************
+** Externs
+************************************************************************************/
+
+/************************************************************************************
+** Functions
+************************************************************************************/
+
+/*****************************************************************************
+** Logging helper functions
+*****************************************************************************/
+
+int str2bd(char *str, bt_bdaddr_t *addr)
+{
+ int32_t i = 0;
+ for (i = 0; i < 6; i++) {
+ addr->address[i] = (uint8_t) strtoul(str, (char **)&str, 16);
+ str++;
+ }
+ return 0;
+}
+
+char *bd2str(bt_bdaddr_t *bdaddr, bdstr_t *bdstr)
+{
+ char *addr = (char *) bdaddr->address;
+
+ sprintf((char*)bdstr, "%02x:%02x:%02x:%02x:%02x:%02x",
+ (int)addr[0],(int)addr[1],(int)addr[2],
+ (int)addr[3],(int)addr[4],(int)addr[5]);
+ return (char *)bdstr;
+}
+
+UINT32 devclass2uint(DEV_CLASS dev_class)
+{
+ UINT32 cod = 0;
+
+ /* if COD is 0, irrespective of the device type set it to Unclassified device */
+ cod = (dev_class[2]) | (dev_class[1] << 8) | (dev_class[0] << 16);
+
+ return cod;
+}
+
+static const UINT8 sdp_base_uuid[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB};
+
+void uuid16_to_uuid128(uint16_t uuid16, bt_uuid_t* uuid128)
+{
+ uint16_t uuid16_bo;
+ memset(uuid128, 0, sizeof(bt_uuid_t));
+
+ memcpy(uuid128->uu, sdp_base_uuid, MAX_UUID_SIZE);
+ uuid16_bo = ntohs(uuid16);
+ memcpy(uuid128->uu + 2, &uuid16_bo, sizeof(uint16_t));
+}
+
+void string_to_uuid(char *str, bt_uuid_t *p_uuid)
+{
+ uint32_t uuid0, uuid4;
+ uint16_t uuid1, uuid2, uuid3, uuid5;
+
+ sscanf(str, "%08x-%04hx-%04hx-%04hx-%08x%04hx",
+ &uuid0, &uuid1, &uuid2, &uuid3, &uuid4, &uuid5);
+
+ uuid0 = htonl(uuid0);
+ uuid1 = htons(uuid1);
+ uuid2 = htons(uuid2);
+ uuid3 = htons(uuid3);
+ uuid4 = htonl(uuid4);
+ uuid5 = htons(uuid5);
+
+ memcpy(&(p_uuid->uu[0]), &uuid0, 4);
+ memcpy(&(p_uuid->uu[4]), &uuid1, 2);
+ memcpy(&(p_uuid->uu[6]), &uuid2, 2);
+ memcpy(&(p_uuid->uu[8]), &uuid3, 2);
+ memcpy(&(p_uuid->uu[10]), &uuid4, 4);
+ memcpy(&(p_uuid->uu[14]), &uuid5, 2);
+
+ return;
+
+}
+
+void uuid_to_string(bt_uuid_t *p_uuid, char *str)
+{
+ uint32_t uuid0, uuid4;
+ uint16_t uuid1, uuid2, uuid3, uuid5;
+
+ memcpy(&uuid0, &(p_uuid->uu[0]), 4);
+ memcpy(&uuid1, &(p_uuid->uu[4]), 2);
+ memcpy(&uuid2, &(p_uuid->uu[6]), 2);
+ memcpy(&uuid3, &(p_uuid->uu[8]), 2);
+ memcpy(&uuid4, &(p_uuid->uu[10]), 4);
+ memcpy(&uuid5, &(p_uuid->uu[14]), 2);
+
+ sprintf((char *)str, "%.8x-%.4x-%.4x-%.4x-%.8x%.4x",
+ ntohl(uuid0), ntohs(uuid1),
+ ntohs(uuid2), ntohs(uuid3),
+ ntohl(uuid4), ntohs(uuid5));
+ return;
+}
+const char* dump_dm_search_event(UINT16 event)
+{
+ switch(event)
+ {
+ CASE_RETURN_STR(BTA_DM_INQ_RES_EVT)
+ CASE_RETURN_STR(BTA_DM_INQ_CMPL_EVT)
+ CASE_RETURN_STR(BTA_DM_DISC_RES_EVT)
+ CASE_RETURN_STR(BTA_DM_DISC_BLE_RES_EVT)
+ CASE_RETURN_STR(BTA_DM_DISC_CMPL_EVT)
+ CASE_RETURN_STR(BTA_DM_DI_DISC_CMPL_EVT)
+ CASE_RETURN_STR(BTA_DM_SEARCH_CANCEL_CMPL_EVT)
+
+ default:
+ return "UNKNOWN MSG ID";
+ }
+}
+
+
+const char* dump_property_type(bt_property_type_t type)
+{
+ switch(type)
+ {
+ CASE_RETURN_STR(BT_PROPERTY_BDNAME)
+ CASE_RETURN_STR(BT_PROPERTY_BDADDR)
+ CASE_RETURN_STR(BT_PROPERTY_UUIDS)
+ CASE_RETURN_STR(BT_PROPERTY_CLASS_OF_DEVICE)
+ CASE_RETURN_STR(BT_PROPERTY_TYPE_OF_DEVICE)
+ CASE_RETURN_STR(BT_PROPERTY_REMOTE_RSSI)
+ CASE_RETURN_STR(BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT)
+ CASE_RETURN_STR(BT_PROPERTY_ADAPTER_BONDED_DEVICES)
+ CASE_RETURN_STR(BT_PROPERTY_ADAPTER_SCAN_MODE)
+ CASE_RETURN_STR(BT_PROPERTY_REMOTE_FRIENDLY_NAME)
+
+ default:
+ return "UNKNOWN PROPERTY ID";
+ }
+}
+
+
+const char* dump_hf_event(UINT16 event)
+{
+ switch(event)
+ {
+ CASE_RETURN_STR(BTA_AG_ENABLE_EVT)
+ CASE_RETURN_STR(BTA_AG_REGISTER_EVT)
+ CASE_RETURN_STR(BTA_AG_OPEN_EVT)
+ CASE_RETURN_STR(BTA_AG_CLOSE_EVT)
+ CASE_RETURN_STR(BTA_AG_CONN_EVT)
+ CASE_RETURN_STR(BTA_AG_AUDIO_OPEN_EVT)
+ CASE_RETURN_STR(BTA_AG_AUDIO_CLOSE_EVT)
+ CASE_RETURN_STR(BTA_AG_SPK_EVT)
+ CASE_RETURN_STR(BTA_AG_MIC_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_CKPD_EVT)
+ CASE_RETURN_STR(BTA_AG_DISABLE_EVT)
+
+ CASE_RETURN_STR(BTA_AG_AT_A_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_D_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_CHLD_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_CHUP_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_CIND_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_VTS_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_BINP_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_BLDN_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_BVRA_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_NREC_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_CNUM_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_BTRH_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_CLCC_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_COPS_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_UNAT_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_CBC_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_BAC_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_BCS_EVT)
+
+ default:
+ return "UNKNOWN MSG ID";
+ }
+}
+
+
+const char* dump_hf_conn_state(UINT16 event)
+{
+ switch(event)
+ {
+ CASE_RETURN_STR(BTHF_CONNECTION_STATE_DISCONNECTED)
+ CASE_RETURN_STR(BTHF_CONNECTION_STATE_CONNECTING)
+ CASE_RETURN_STR(BTHF_CONNECTION_STATE_CONNECTED)
+ CASE_RETURN_STR(BTHF_CONNECTION_STATE_DISCONNECTING)
+ default:
+ return "UNKNOWN MSG ID";
+ }
+}
+
+const char* dump_hf_call_state(bthf_call_state_t call_state)
+{
+ switch(call_state)
+ {
+ CASE_RETURN_STR(BTHF_CALL_STATE_IDLE)
+ CASE_RETURN_STR(BTHF_CALL_STATE_ONHOLD)
+ CASE_RETURN_STR(BTHF_CALL_STATE_DIALING)
+ CASE_RETURN_STR(BTHF_CALL_STATE_ALERTING)
+ CASE_RETURN_STR(BTHF_CALL_STATE_INCOMING)
+ CASE_RETURN_STR(BTHF_CALL_STATE_WAITING)
+ CASE_RETURN_STR(BTHF_CALL_STATE_ACTIVE)
+ default:
+ return "UNKNOWN MSG ID";
+ }
+}
+
+const char* dump_thread_evt(bt_cb_thread_evt evt)
+{
+ switch(evt)
+ {
+ CASE_RETURN_STR(ASSOCIATE_JVM)
+ CASE_RETURN_STR(DISASSOCIATE_JVM)
+
+ default:
+ return "unknown thread evt";
+ }
+}
+
+
+const char* dump_hf_audio_state(UINT16 event)
+{
+ switch(event)
+ {
+ CASE_RETURN_STR(BTHF_AUDIO_STATE_DISCONNECTED)
+ CASE_RETURN_STR(BTHF_AUDIO_STATE_CONNECTING)
+ CASE_RETURN_STR(BTHF_AUDIO_STATE_CONNECTED)
+ CASE_RETURN_STR(BTHF_AUDIO_STATE_DISCONNECTING)
+ default:
+ return "UNKNOWN MSG ID";
+
+ }
+}
+
+
+const char* dump_adapter_scan_mode(bt_scan_mode_t mode)
+{
+ switch(mode)
+ {
+ CASE_RETURN_STR(BT_SCAN_MODE_NONE)
+ CASE_RETURN_STR(BT_SCAN_MODE_CONNECTABLE)
+ CASE_RETURN_STR(BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE)
+
+ default:
+ return "unknown scan mode";
+ }
+}
+
+const char* dump_bt_status(bt_status_t status)
+{
+ switch(status)
+ {
+ CASE_RETURN_STR(BT_STATUS_SUCCESS)
+ CASE_RETURN_STR(BT_STATUS_FAIL)
+ CASE_RETURN_STR(BT_STATUS_NOT_READY)
+ CASE_RETURN_STR(BT_STATUS_NOMEM)
+ CASE_RETURN_STR(BT_STATUS_BUSY)
+ CASE_RETURN_STR(BT_STATUS_UNSUPPORTED)
+
+ default:
+ return "unknown scan mode";
+ }
+}
+
+
+
diff --git a/gki/Android.mk b/gki/Android.mk
new file mode 100644
index 0000000..2317fc0
--- /dev/null
+++ b/gki/Android.mk
@@ -0,0 +1,33 @@
+ifneq ($(TARGET_SIMULATOR),true)
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_C_INCLUDES:= $(LOCAL_PATH)/common \
+ $(LOCAL_PATH)/ulinux \
+ $(LOCAL_PATH)/../include \
+ $(LOCAL_PATH)/../stack/include/
+
+
+LOCAL_CFLAGS += -Werror
+
+ifeq ($(BOARD_HAVE_BLUETOOTH_BCM),true)
+LOCAL_CFLAGS += \
+ -DBOARD_HAVE_BLUETOOTH_BCM
+endif
+
+LOCAL_PRELINK_MODULE:=false
+LOCAL_SRC_FILES:= \
+ ./ulinux/gki_ulinux.c \
+ ./common/gki_debug.c \
+ ./common/gki_time.c \
+ ./common/gki_buffer.c
+
+LOCAL_MODULE := libbt-brcm_gki
+LOCAL_MODULE_TAGS := eng
+LOCAL_SHARED_LIBRARIES := libcutils libc
+
+include $(BUILD_STATIC_LIBRARY)
+
+endif # TARGET_SIMULATOR != true
diff --git a/gki/common/gki.h b/gki/common/gki.h
new file mode 100644
index 0000000..a3272d5
--- /dev/null
+++ b/gki/common/gki.h
@@ -0,0 +1,490 @@
+/****************************************************************************
+**
+** Name gki.h
+**
+** Function This file contains GKI public definitions
+**
+**
+** Copyright (c) 1999-2011, Broadcom Corp., All Rights Reserved.
+** Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef GKI_H
+#define GKI_H
+
+#ifdef BUILDCFG
+#include "buildcfg.h"
+#endif
+
+/* Include platform-specific over-rides */
+#if (defined(NFC_STANDALONE) && (NFC_STANDALONE == TRUE))
+ #include "gki_target.h"
+#else
+ /* For non-nfc_standalone, include Bluetooth definitions */
+ #include "bt_target.h"
+#endif
+
+
+
+#include "bt_types.h"
+
+/* Error codes */
+#define GKI_SUCCESS 0x00
+#define GKI_FAILURE 0x01
+#define GKI_INVALID_TASK 0xF0
+#define GKI_INVALID_POOL 0xFF
+
+
+/************************************************************************
+** Mailbox definitions. Each task has 4 mailboxes that are used to
+** send buffers to the task.
+*/
+#define TASK_MBOX_0 0
+#define TASK_MBOX_1 1
+#define TASK_MBOX_2 2
+#define TASK_MBOX_3 3
+
+#define NUM_TASK_MBOX 4
+
+/************************************************************************
+** Event definitions.
+**
+** There are 4 reserved events used to signal messages rcvd in task mailboxes.
+** There are 4 reserved events used to signal timeout events.
+** There are 8 general purpose events available for applications.
+*/
+#define MAX_EVENTS 16
+
+#define TASK_MBOX_0_EVT_MASK 0x0001
+#define TASK_MBOX_1_EVT_MASK 0x0002
+#define TASK_MBOX_2_EVT_MASK 0x0004
+#define TASK_MBOX_3_EVT_MASK 0x0008
+
+
+#define TIMER_0 0
+#define TIMER_1 1
+#define TIMER_2 2
+#define TIMER_3 3
+
+#define TIMER_0_EVT_MASK 0x0010
+#define TIMER_1_EVT_MASK 0x0020
+#define TIMER_2_EVT_MASK 0x0040
+#define TIMER_3_EVT_MASK 0x0080
+
+#define APPL_EVT_0 8
+#define APPL_EVT_1 9
+#define APPL_EVT_2 10
+#define APPL_EVT_3 11
+#define APPL_EVT_4 12
+#define APPL_EVT_5 13
+#define APPL_EVT_6 14
+#define APPL_EVT_7 15
+
+#define EVENT_MASK(evt) ((UINT16)(0x0001 << (evt)))
+
+/************************************************************************
+** Max Time Queue
+**/
+#ifndef GKI_MAX_TIMER_QUEUES
+#define GKI_MAX_TIMER_QUEUES 3
+#endif
+
+/************************************************************************
+** Macro to determine the pool buffer size based on the GKI POOL ID at compile time.
+** Pool IDs index from 0 to GKI_NUM_FIXED_BUF_POOLS - 1
+*/
+
+#if (GKI_NUM_FIXED_BUF_POOLS < 1)
+
+#ifndef GKI_POOL_ID_0
+#define GKI_POOL_ID_0 0
+#endif /* ifndef GKI_POOL_ID_0 */
+
+#ifndef GKI_BUF0_SIZE
+#define GKI_BUF0_SIZE 0
+#endif /* ifndef GKI_BUF0_SIZE */
+
+#endif /* GKI_NUM_FIXED_BUF_POOLS < 1 */
+
+
+#if (GKI_NUM_FIXED_BUF_POOLS < 2)
+
+#ifndef GKI_POOL_ID_1
+#define GKI_POOL_ID_1 0
+#endif /* ifndef GKI_POOL_ID_1 */
+
+#ifndef GKI_BUF1_SIZE
+#define GKI_BUF1_SIZE 0
+#endif /* ifndef GKI_BUF1_SIZE */
+
+#endif /* GKI_NUM_FIXED_BUF_POOLS < 2 */
+
+
+#if (GKI_NUM_FIXED_BUF_POOLS < 3)
+
+#ifndef GKI_POOL_ID_2
+#define GKI_POOL_ID_2 0
+#endif /* ifndef GKI_POOL_ID_2 */
+
+#ifndef GKI_BUF2_SIZE
+#define GKI_BUF2_SIZE 0
+#endif /* ifndef GKI_BUF2_SIZE */
+
+#endif /* GKI_NUM_FIXED_BUF_POOLS < 3 */
+
+
+#if (GKI_NUM_FIXED_BUF_POOLS < 4)
+
+#ifndef GKI_POOL_ID_3
+#define GKI_POOL_ID_3 0
+#endif /* ifndef GKI_POOL_ID_4 */
+
+#ifndef GKI_BUF3_SIZE
+#define GKI_BUF3_SIZE 0
+#endif /* ifndef GKI_BUF3_SIZE */
+
+#endif /* GKI_NUM_FIXED_BUF_POOLS < 4 */
+
+
+#if (GKI_NUM_FIXED_BUF_POOLS < 5)
+
+#ifndef GKI_POOL_ID_4
+#define GKI_POOL_ID_4 0
+#endif /* ifndef GKI_POOL_ID_4 */
+
+#ifndef GKI_BUF4_SIZE
+#define GKI_BUF4_SIZE 0
+#endif /* ifndef GKI_BUF4_SIZE */
+
+#endif /* GKI_NUM_FIXED_BUF_POOLS < 5 */
+
+
+#if (GKI_NUM_FIXED_BUF_POOLS < 6)
+
+#ifndef GKI_POOL_ID_5
+#define GKI_POOL_ID_5 0
+#endif /* ifndef GKI_POOL_ID_5 */
+
+#ifndef GKI_BUF5_SIZE
+#define GKI_BUF5_SIZE 0
+#endif /* ifndef GKI_BUF5_SIZE */
+
+#endif /* GKI_NUM_FIXED_BUF_POOLS < 6 */
+
+
+#if (GKI_NUM_FIXED_BUF_POOLS < 7)
+
+#ifndef GKI_POOL_ID_6
+#define GKI_POOL_ID_6 0
+#endif /* ifndef GKI_POOL_ID_6 */
+
+#ifndef GKI_BUF6_SIZE
+#define GKI_BUF6_SIZE 0
+#endif /* ifndef GKI_BUF6_SIZE */
+
+#endif /* GKI_NUM_FIXED_BUF_POOLS < 7 */
+
+
+#if (GKI_NUM_FIXED_BUF_POOLS < 8)
+
+#ifndef GKI_POOL_ID_7
+#define GKI_POOL_ID_7 0
+#endif /* ifndef GKI_POOL_ID_7 */
+
+#ifndef GKI_BUF7_SIZE
+#define GKI_BUF7_SIZE 0
+#endif /* ifndef GKI_BUF7_SIZE */
+
+#endif /* GKI_NUM_FIXED_BUF_POOLS < 8 */
+
+
+#if (GKI_NUM_FIXED_BUF_POOLS < 9)
+
+#ifndef GKI_POOL_ID_8
+#define GKI_POOL_ID_8 0
+#endif /* ifndef GKI_POOL_ID_8 */
+
+#ifndef GKI_BUF8_SIZE
+#define GKI_BUF8_SIZE 0
+#endif /* ifndef GKI_BUF8_SIZE */
+
+#endif /* GKI_NUM_FIXED_BUF_POOLS < 9 */
+
+
+#if (GKI_NUM_FIXED_BUF_POOLS < 10)
+
+#ifndef GKI_POOL_ID_9
+#define GKI_POOL_ID_9 0
+#endif /* ifndef GKI_POOL_ID_9 */
+
+#ifndef GKI_BUF9_SIZE
+#define GKI_BUF9_SIZE 0
+#endif /* ifndef GKI_BUF9_SIZE */
+
+#endif /* GKI_NUM_FIXED_BUF_POOLS < 10 */
+
+
+#if (GKI_NUM_FIXED_BUF_POOLS < 11)
+
+#ifndef GKI_POOL_ID_10
+#define GKI_POOL_ID_10 0
+#endif /* ifndef GKI_POOL_ID_10 */
+
+#ifndef GKI_BUF10_SIZE
+#define GKI_BUF10_SIZE 0
+#endif /* ifndef GKI_BUF10_SIZE */
+
+#endif /* GKI_NUM_FIXED_BUF_POOLS < 11 */
+
+
+#if (GKI_NUM_FIXED_BUF_POOLS < 12)
+
+#ifndef GKI_POOL_ID_11
+#define GKI_POOL_ID_11 0
+#endif /* ifndef GKI_POOL_ID_11 */
+
+#ifndef GKI_BUF11_SIZE
+#define GKI_BUF11_SIZE 0
+#endif /* ifndef GKI_BUF11_SIZE */
+
+#endif /* GKI_NUM_FIXED_BUF_POOLS < 12 */
+
+
+#if (GKI_NUM_FIXED_BUF_POOLS < 13)
+
+#ifndef GKI_POOL_ID_12
+#define GKI_POOL_ID_12 0
+#endif /* ifndef GKI_POOL_ID_12 */
+
+#ifndef GKI_BUF12_SIZE
+#define GKI_BUF12_SIZE 0
+#endif /* ifndef GKI_BUF12_SIZE */
+
+#endif /* GKI_NUM_FIXED_BUF_POOLS < 13 */
+
+
+#if (GKI_NUM_FIXED_BUF_POOLS < 14)
+
+#ifndef GKI_POOL_ID_13
+#define GKI_POOL_ID_13 0
+#endif /* ifndef GKI_POOL_ID_13 */
+
+#ifndef GKI_BUF13_SIZE
+#define GKI_BUF13_SIZE 0
+#endif /* ifndef GKI_BUF13_SIZE */
+
+#endif /* GKI_NUM_FIXED_BUF_POOLS < 14 */
+
+
+#if (GKI_NUM_FIXED_BUF_POOLS < 15)
+
+#ifndef GKI_POOL_ID_14
+#define GKI_POOL_ID_14 0
+#endif /* ifndef GKI_POOL_ID_14 */
+
+#ifndef GKI_BUF14_SIZE
+#define GKI_BUF14_SIZE 0
+#endif /* ifndef GKI_BUF14_SIZE */
+
+#endif /* GKI_NUM_FIXED_BUF_POOLS < 15 */
+
+
+#if (GKI_NUM_FIXED_BUF_POOLS < 16)
+
+#ifndef GKI_POOL_ID_15
+#define GKI_POOL_ID_15 0
+#endif /* ifndef GKI_POOL_ID_15 */
+
+#ifndef GKI_BUF15_SIZE
+#define GKI_BUF15_SIZE 0
+#endif /* ifndef GKI_BUF15_SIZE */
+
+#endif /* GKI_NUM_FIXED_BUF_POOLS < 16 */
+
+
+/* Timer list entry callback type
+*/
+typedef void (TIMER_CBACK)(void *p_tle);
+#ifndef TIMER_PARAM_TYPE
+#ifdef WIN2000
+#define TIMER_PARAM_TYPE void *
+#else
+#define TIMER_PARAM_TYPE UINT32
+#endif
+#endif
+/* Define a timer list entry
+*/
+typedef struct _tle
+{
+ struct _tle *p_next;
+ struct _tle *p_prev;
+ TIMER_CBACK *p_cback;
+ INT32 ticks;
+ TIMER_PARAM_TYPE param;
+ UINT16 event;
+ UINT8 in_use;
+} TIMER_LIST_ENT;
+
+/* Define a timer list queue
+*/
+typedef struct
+{
+ TIMER_LIST_ENT *p_first;
+ TIMER_LIST_ENT *p_last;
+ INT32 last_ticks;
+} TIMER_LIST_Q;
+
+
+/***********************************************************************
+** This queue is a general purpose buffer queue, for application use.
+*/
+typedef struct
+{
+ void *p_first;
+ void *p_last;
+ UINT16 count;
+} BUFFER_Q;
+
+#define GKI_IS_QUEUE_EMPTY(p_q) ((p_q)->count == 0)
+
+/* Task constants
+*/
+#ifndef TASKPTR
+typedef void (*TASKPTR)(UINT32);
+#endif
+
+
+#define GKI_PUBLIC_POOL 0 /* General pool accessible to GKI_getbuf() */
+#define GKI_RESTRICTED_POOL 1 /* Inaccessible pool to GKI_getbuf() */
+
+/***********************************************************************
+** Function prototypes
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Task management
+*/
+GKI_API extern UINT8 GKI_create_task (TASKPTR, UINT8, INT8 *, UINT16 *, UINT16);
+GKI_API extern void GKI_destroy_task(UINT8 task_id);
+GKI_API extern void GKI_exit_task(UINT8);
+GKI_API extern UINT8 GKI_get_taskid(void);
+GKI_API extern void GKI_init(void);
+GKI_API extern void GKI_shutdown(void);
+GKI_API extern INT8 *GKI_map_taskname(UINT8);
+GKI_API extern UINT8 GKI_resume_task(UINT8);
+GKI_API extern void GKI_run(void *);
+GKI_API extern void GKI_freeze(void);
+GKI_API extern void GKI_stop(void);
+GKI_API extern UINT8 GKI_suspend_task(UINT8);
+GKI_API extern UINT8 GKI_is_task_running(UINT8);
+
+/* memory management
+*/
+GKI_API extern void GKI_shiftdown (UINT8 *p_mem, UINT32 len, UINT32 shift_amount);
+GKI_API extern void GKI_shiftup (UINT8 *p_dest, UINT8 *p_src, UINT32 len);
+
+/* To send buffers and events between tasks
+*/
+GKI_API extern UINT8 GKI_isend_event (UINT8, UINT16);
+GKI_API extern void GKI_isend_msg (UINT8, UINT8, void *);
+GKI_API extern void *GKI_read_mbox (UINT8);
+GKI_API extern void GKI_send_msg (UINT8, UINT8, void *);
+GKI_API extern UINT8 GKI_send_event (UINT8, UINT16);
+
+
+/* To get and release buffers, change owner and get size
+*/
+GKI_API extern void GKI_change_buf_owner (void *, UINT8);
+GKI_API extern UINT8 GKI_create_pool (UINT16, UINT16, UINT8, void *);
+GKI_API extern void GKI_delete_pool (UINT8);
+GKI_API extern void *GKI_find_buf_start (void *);
+GKI_API extern void GKI_freebuf (void *);
+GKI_API extern void *GKI_getbuf (UINT16);
+GKI_API extern UINT16 GKI_get_buf_size (void *);
+GKI_API extern void *GKI_getpoolbuf (UINT8);
+GKI_API extern UINT16 GKI_poolcount (UINT8);
+GKI_API extern UINT16 GKI_poolfreecount (UINT8);
+GKI_API extern UINT16 GKI_poolutilization (UINT8);
+GKI_API extern void GKI_register_mempool (void *p_mem);
+GKI_API extern UINT8 GKI_set_pool_permission(UINT8, UINT8);
+
+
+/* User buffer queue management
+*/
+GKI_API extern void *GKI_dequeue (BUFFER_Q *);
+GKI_API extern void GKI_enqueue (BUFFER_Q *, void *);
+GKI_API extern void GKI_enqueue_head (BUFFER_Q *, void *);
+GKI_API extern void *GKI_getfirst (BUFFER_Q *);
+GKI_API extern void *GKI_getlast (BUFFER_Q *);
+GKI_API extern void *GKI_getnext (void *);
+GKI_API extern void GKI_init_q (BUFFER_Q *);
+GKI_API extern BOOLEAN GKI_queue_is_empty(BUFFER_Q *);
+GKI_API extern void *GKI_remove_from_queue (BUFFER_Q *, void *);
+GKI_API extern UINT16 GKI_get_pool_bufsize (UINT8);
+
+/* Timer management
+*/
+GKI_API extern void GKI_add_to_timer_list (TIMER_LIST_Q *, TIMER_LIST_ENT *);
+GKI_API extern void GKI_delay(UINT32);
+GKI_API extern UINT32 GKI_get_tick_count(void);
+GKI_API extern INT8 *GKI_get_time_stamp(INT8 *);
+GKI_API extern void GKI_init_timer_list (TIMER_LIST_Q *);
+GKI_API extern void GKI_init_timer_list_entry (TIMER_LIST_ENT *);
+GKI_API extern INT32 GKI_ready_to_sleep (void);
+GKI_API extern void GKI_remove_from_timer_list (TIMER_LIST_Q *, TIMER_LIST_ENT *);
+GKI_API extern void GKI_start_timer(UINT8, INT32, BOOLEAN);
+GKI_API extern void GKI_stop_timer (UINT8);
+GKI_API extern void GKI_timer_update(INT32);
+GKI_API extern UINT16 GKI_update_timer_list (TIMER_LIST_Q *, INT32);
+GKI_API extern UINT32 GKI_get_remaining_ticks (TIMER_LIST_Q *, TIMER_LIST_ENT *);
+GKI_API extern UINT16 GKI_wait(UINT16, UINT32);
+
+/* Start and Stop system time tick callback
+ * true for start system tick if time queue is not empty
+ * false to stop system tick if time queue is empty
+*/
+typedef void (SYSTEM_TICK_CBACK)(BOOLEAN);
+
+/* Time queue management for system ticks
+*/
+GKI_API extern BOOLEAN GKI_timer_queue_empty (void);
+GKI_API extern void GKI_timer_queue_register_callback(SYSTEM_TICK_CBACK *);
+
+/* Disable Interrupts, Enable Interrupts
+*/
+GKI_API extern void GKI_enable(void);
+GKI_API extern void GKI_disable(void);
+GKI_API extern void GKI_sched_lock(void);
+GKI_API extern void GKI_sched_unlock(void);
+
+/* Allocate (Free) memory from an OS
+*/
+GKI_API extern void *GKI_os_malloc (UINT32);
+GKI_API extern void GKI_os_free (void *);
+
+/* os timer operation */
+GKI_API extern UINT32 GKI_get_os_tick_count(void);
+
+/* Exception handling
+*/
+GKI_API extern void GKI_exception (UINT16, char *);
+
+#if GKI_DEBUG == TRUE
+GKI_API extern void GKI_PrintBufferUsage(UINT8 *p_num_pools, UINT16 *p_cur_used);
+GKI_API extern void GKI_PrintBuffer(void);
+GKI_API extern void GKI_print_task(void);
+#else
+#undef GKI_PrintBufferUsage
+#define GKI_PrintBuffer() NULL
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+
diff --git a/gki/common/gki_buffer.c b/gki/common/gki_buffer.c
new file mode 100644
index 0000000..a32c275
--- /dev/null
+++ b/gki/common/gki_buffer.c
@@ -0,0 +1,1474 @@
+/********************************************************************************
+** *
+** Name gki_buffer.c *
+** *
+** Function this file contains GKI buffer handling functions *
+** *
+** *
+** Copyright (c) 1999-2009, Broadcom Corp., All Rights Reserved. *
+** Proprietary and confidential. *
+** *
+*********************************************************************************/
+#include "gki_int.h"
+
+#if (GKI_NUM_TOTAL_BUF_POOLS > 16)
+#error Number of pools out of range (16 Max)!
+#endif
+
+static void gki_add_to_pool_list(UINT8 pool_id);
+static void gki_remove_from_pool_list(UINT8 pool_id);
+
+/*******************************************************************************
+**
+** Function gki_init_free_queue
+**
+** Description Internal function called at startup to initialize a free
+** queue. It is called once for each free queue.
+**
+** Returns void
+**
+*******************************************************************************/
+static void gki_init_free_queue (UINT8 id, UINT16 size, UINT16 total, void *p_mem)
+{
+ UINT16 i;
+ UINT16 act_size;
+ BUFFER_HDR_T *hdr;
+ BUFFER_HDR_T *hdr1 = NULL;
+ UINT32 *magic;
+ INT32 tempsize = size;
+ tGKI_COM_CB *p_cb = &gki_cb.com;
+
+ /* Ensure an even number of longwords */
+ tempsize = (INT32)ALIGN_POOL(size);
+ act_size = (UINT16)(tempsize + BUFFER_PADDING_SIZE);
+
+ /* Remember pool start and end addresses */
+// btla-specific ++
+ if(p_mem)
+ {
+ p_cb->pool_start[id] = (UINT8 *)p_mem;
+ p_cb->pool_end[id] = (UINT8 *)p_mem + (act_size * total);
+ }
+// btla-specific --
+
+ p_cb->pool_size[id] = act_size;
+
+ p_cb->freeq[id].size = (UINT16) tempsize;
+ p_cb->freeq[id].total = total;
+ p_cb->freeq[id].cur_cnt = 0;
+ p_cb->freeq[id].max_cnt = 0;
+
+ /* Initialize index table */
+// btla-specific ++
+ if(p_mem)
+ {
+ hdr = (BUFFER_HDR_T *)p_mem;
+ p_cb->freeq[id].p_first = hdr;
+ for (i = 0; i < total; i++)
+ {
+ hdr->task_id = GKI_INVALID_TASK;
+ hdr->q_id = id;
+ hdr->status = BUF_STATUS_FREE;
+ magic = (UINT32 *)((UINT8 *)hdr + BUFFER_HDR_SIZE + tempsize);
+ *magic = MAGIC_NO;
+ hdr1 = hdr;
+ hdr = (BUFFER_HDR_T *)((UINT8 *)hdr + act_size);
+ hdr1->p_next = hdr;
+ }
+ hdr1->p_next = NULL;
+ p_cb->freeq[id].p_last = hdr1;
+ }
+// btla-specific --
+ return;
+}
+
+// btla-specific ++
+#ifdef GKI_USE_DEFERED_ALLOC_BUF_POOLS
+static BOOLEAN gki_alloc_free_queue(UINT8 id)
+{
+ FREE_QUEUE_T *Q;
+ tGKI_COM_CB *p_cb = &gki_cb.com;
+ GKI_TRACE("\ngki_alloc_free_queue in, id:%d \n", id);
+
+ Q = &p_cb->freeq[p_cb->pool_list[id]];
+
+ if(Q->p_first == 0)
+ {
+ void* p_mem = GKI_os_malloc((Q->size + BUFFER_PADDING_SIZE) * Q->total);
+ if(p_mem)
+ {
+ //re-initialize the queue with allocated memory
+ GKI_TRACE("\ngki_alloc_free_queue calling gki_init_free_queue, id:%d size:%d, totol:%d\n", id, Q->size, Q->total);
+ gki_init_free_queue(id, Q->size, Q->total, p_mem);
+ GKI_TRACE("\ngki_alloc_free_queue ret OK, id:%d size:%d, totol:%d\n", id, Q->size, Q->total);
+ return TRUE;
+ }
+ GKI_exception (GKI_ERROR_BUF_SIZE_TOOBIG, "gki_alloc_free_queue: Not enough memory");
+ }
+ GKI_TRACE("\ngki_alloc_free_queue out failed, id:%d\n", id);
+ return FALSE;
+}
+
+void gki_dealloc_free_queue(void)
+{
+ UINT8 i;
+ tGKI_COM_CB *p_cb = &gki_cb.com;
+
+ for (i=0; i < p_cb->curr_total_no_of_pools; i++)
+ {
+ if ( 0 < p_cb->freeq[i].max_cnt )
+ {
+ GKI_os_free(p_cb->pool_start[i]);
+
+ p_cb->freeq[i].cur_cnt = 0;
+ p_cb->freeq[i].max_cnt = 0;
+ p_cb->freeq[i].p_first = NULL;
+ p_cb->freeq[i].p_last = NULL;
+
+ p_cb->pool_start[i] = NULL;
+ p_cb->pool_end[i] = NULL;
+ p_cb->pool_size[i] = 0;
+ }
+ }
+}
+
+#endif
+// btla-specific --
+
+/*******************************************************************************
+**
+** Function gki_buffer_init
+**
+** Description Called once internally by GKI at startup to initialize all
+** buffers and free buffer pools.
+**
+** Returns void
+**
+*******************************************************************************/
+void gki_buffer_init(void)
+{
+ UINT8 i, tt, mb;
+ tGKI_COM_CB *p_cb = &gki_cb.com;
+
+ /* Initialize mailboxes */
+ for (tt = 0; tt < GKI_MAX_TASKS; tt++)
+ {
+ for (mb = 0; mb < NUM_TASK_MBOX; mb++)
+ {
+ p_cb->OSTaskQFirst[tt][mb] = NULL;
+ p_cb->OSTaskQLast [tt][mb] = NULL;
+ }
+ }
+
+ for (tt = 0; tt < GKI_NUM_TOTAL_BUF_POOLS; tt++)
+ {
+ p_cb->pool_start[tt] = NULL;
+ p_cb->pool_end[tt] = NULL;
+ p_cb->pool_size[tt] = 0;
+
+ p_cb->freeq[tt].p_first = 0;
+ p_cb->freeq[tt].p_last = 0;
+ p_cb->freeq[tt].size = 0;
+ p_cb->freeq[tt].total = 0;
+ p_cb->freeq[tt].cur_cnt = 0;
+ p_cb->freeq[tt].max_cnt = 0;
+ }
+
+ /* Use default from target.h */
+ p_cb->pool_access_mask = GKI_DEF_BUFPOOL_PERM_MASK;
+
+// btla-specific ++
+#if (!defined GKI_USE_DEFERED_ALLOC_BUF_POOLS && (GKI_USE_DYNAMIC_BUFFERS == TRUE))
+// btla-specific --
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 0)
+ p_cb->bufpool0 = (UINT8 *)GKI_os_malloc ((GKI_BUF0_SIZE + BUFFER_PADDING_SIZE) * GKI_BUF0_MAX);
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 1)
+ p_cb->bufpool1 = (UINT8 *)GKI_os_malloc ((GKI_BUF1_SIZE + BUFFER_PADDING_SIZE) * GKI_BUF1_MAX);
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 2)
+ p_cb->bufpool2 = (UINT8 *)GKI_os_malloc ((GKI_BUF2_SIZE + BUFFER_PADDING_SIZE) * GKI_BUF2_MAX);
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 3)
+ p_cb->bufpool3 = (UINT8 *)GKI_os_malloc ((GKI_BUF3_SIZE + BUFFER_PADDING_SIZE) * GKI_BUF3_MAX);
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 4)
+ p_cb->bufpool4 = (UINT8 *)GKI_os_malloc ((GKI_BUF4_SIZE + BUFFER_PADDING_SIZE) * GKI_BUF4_MAX);
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 5)
+ p_cb->bufpool5 = (UINT8 *)GKI_os_malloc ((GKI_BUF5_SIZE + BUFFER_PADDING_SIZE) * GKI_BUF5_MAX);
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 6)
+ p_cb->bufpool6 = (UINT8 *)GKI_os_malloc ((GKI_BUF6_SIZE + BUFFER_PADDING_SIZE) * GKI_BUF6_MAX);
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 7)
+ p_cb->bufpool7 = (UINT8 *)GKI_os_malloc ((GKI_BUF7_SIZE + BUFFER_PADDING_SIZE) * GKI_BUF7_MAX);
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 8)
+ p_cb->bufpool8 = (UINT8 *)GKI_os_malloc ((GKI_BUF8_SIZE + BUFFER_PADDING_SIZE) * GKI_BUF8_MAX);
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 9)
+ p_cb->bufpool9 = (UINT8 *)GKI_os_malloc ((GKI_BUF9_SIZE + BUFFER_PADDING_SIZE) * GKI_BUF9_MAX);
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 10)
+ p_cb->bufpool10 = (UINT8 *)GKI_os_malloc ((GKI_BUF10_SIZE + BUFFER_PADDING_SIZE) * GKI_BUF10_MAX);
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 11)
+ p_cb->bufpool11 = (UINT8 *)GKI_os_malloc ((GKI_BUF11_SIZE + BUFFER_PADDING_SIZE) * GKI_BUF11_MAX);
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 12)
+ p_cb->bufpool12 = (UINT8 *)GKI_os_malloc ((GKI_BUF12_SIZE + BUFFER_PADDING_SIZE) * GKI_BUF12_MAX);
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 13)
+ p_cb->bufpool13 = (UINT8 *)GKI_os_malloc ((GKI_BUF13_SIZE + BUFFER_PADDING_SIZE) * GKI_BUF13_MAX);
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 14)
+ p_cb->bufpool14 = (UINT8 *)GKI_os_malloc ((GKI_BUF14_SIZE + BUFFER_PADDING_SIZE) * GKI_BUF14_MAX);
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 15)
+ p_cb->bufpool15 = (UINT8 *)GKI_os_malloc ((GKI_BUF15_SIZE + BUFFER_PADDING_SIZE) * GKI_BUF15_MAX);
+#endif
+
+#endif
+
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 0)
+ gki_init_free_queue(0, GKI_BUF0_SIZE, GKI_BUF0_MAX, p_cb->bufpool0);
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 1)
+ gki_init_free_queue(1, GKI_BUF1_SIZE, GKI_BUF1_MAX, p_cb->bufpool1);
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 2)
+ gki_init_free_queue(2, GKI_BUF2_SIZE, GKI_BUF2_MAX, p_cb->bufpool2);
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 3)
+ gki_init_free_queue(3, GKI_BUF3_SIZE, GKI_BUF3_MAX, p_cb->bufpool3);
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 4)
+ gki_init_free_queue(4, GKI_BUF4_SIZE, GKI_BUF4_MAX, p_cb->bufpool4);
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 5)
+ gki_init_free_queue(5, GKI_BUF5_SIZE, GKI_BUF5_MAX, p_cb->bufpool5);
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 6)
+ gki_init_free_queue(6, GKI_BUF6_SIZE, GKI_BUF6_MAX, p_cb->bufpool6);
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 7)
+ gki_init_free_queue(7, GKI_BUF7_SIZE, GKI_BUF7_MAX, p_cb->bufpool7);
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 8)
+ gki_init_free_queue(8, GKI_BUF8_SIZE, GKI_BUF8_MAX, p_cb->bufpool8);
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 9)
+ gki_init_free_queue(9, GKI_BUF9_SIZE, GKI_BUF9_MAX, p_cb->bufpool9);
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 10)
+ gki_init_free_queue(10, GKI_BUF10_SIZE, GKI_BUF10_MAX, p_cb->bufpool10);
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 11)
+ gki_init_free_queue(11, GKI_BUF11_SIZE, GKI_BUF11_MAX, p_cb->bufpool11);
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 12)
+ gki_init_free_queue(12, GKI_BUF12_SIZE, GKI_BUF12_MAX, p_cb->bufpool12);
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 13)
+ gki_init_free_queue(13, GKI_BUF13_SIZE, GKI_BUF13_MAX, p_cb->bufpool13);
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 14)
+ gki_init_free_queue(14, GKI_BUF14_SIZE, GKI_BUF14_MAX, p_cb->bufpool14);
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 15)
+ gki_init_free_queue(15, GKI_BUF15_SIZE, GKI_BUF15_MAX, p_cb->bufpool15);
+#endif
+
+ /* add pools to the pool_list which is arranged in the order of size */
+ for(i=0; i < GKI_NUM_FIXED_BUF_POOLS ; i++)
+ {
+ p_cb->pool_list[i] = i;
+ }
+
+ p_cb->curr_total_no_of_pools = GKI_NUM_FIXED_BUF_POOLS;
+
+ return;
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_init_q
+**
+** Description Called by an application to initialize a buffer queue.
+**
+** Returns void
+**
+*******************************************************************************/
+void GKI_init_q (BUFFER_Q *p_q)
+{
+ p_q->p_first = p_q->p_last = NULL;
+ p_q->count = 0;
+
+ return;
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_getbuf
+**
+** Description Called by an application to get a free buffer which
+** is of size greater or equal to the requested size.
+**
+** Note: This routine only takes buffers from public pools.
+** It will not use any buffers from pools
+** marked GKI_RESTRICTED_POOL.
+**
+** Parameters size - (input) number of bytes needed.
+**
+** Returns A pointer to the buffer, or NULL if none available
+**
+*******************************************************************************/
+void *GKI_getbuf (UINT16 size)
+{
+ UINT8 i;
+ FREE_QUEUE_T *Q;
+ BUFFER_HDR_T *p_hdr;
+ tGKI_COM_CB *p_cb = &gki_cb.com;
+
+ if (size == 0)
+ {
+ GKI_exception (GKI_ERROR_BUF_SIZE_ZERO, "getbuf: Size is zero");
+ return (NULL);
+ }
+
+ /* Find the first buffer pool that is public that can hold the desired size */
+ for (i=0; i < p_cb->curr_total_no_of_pools; i++)
+ {
+ if ( size <= p_cb->freeq[p_cb->pool_list[i]].size )
+ break;
+ }
+
+ if(i == p_cb->curr_total_no_of_pools)
+ {
+ GKI_exception (GKI_ERROR_BUF_SIZE_TOOBIG, "getbuf: Size is too big");
+ return (NULL);
+ }
+
+ /* Make sure the buffers aren't disturbed til finished with allocation */
+ GKI_disable();
+
+ /* search the public buffer pools that are big enough to hold the size
+ * until a free buffer is found */
+ for ( ; i < p_cb->curr_total_no_of_pools; i++)
+ {
+ /* Only look at PUBLIC buffer pools (bypass RESTRICTED pools) */
+ if (((UINT16)1 << p_cb->pool_list[i]) & p_cb->pool_access_mask)
+ continue;
+
+ Q = &p_cb->freeq[p_cb->pool_list[i]];
+ if(Q->cur_cnt < Q->total)
+ {
+// btla-specific ++
+ #ifdef GKI_USE_DEFERED_ALLOC_BUF_POOLS
+ if(Q->p_first == 0 && gki_alloc_free_queue(i) != TRUE)
+ return NULL;
+ #endif
+// btla-specific --
+ p_hdr = Q->p_first;
+ Q->p_first = p_hdr->p_next;
+
+ if (!Q->p_first)
+ Q->p_last = NULL;
+
+ if(++Q->cur_cnt > Q->max_cnt)
+ Q->max_cnt = Q->cur_cnt;
+
+ GKI_enable();
+
+ p_hdr->task_id = GKI_get_taskid();
+
+ p_hdr->status = BUF_STATUS_UNLINKED;
+ p_hdr->p_next = NULL;
+ p_hdr->Type = 0;
+
+ return ((void *) ((UINT8 *)p_hdr + BUFFER_HDR_SIZE));
+ }
+ }
+
+ GKI_enable();
+
+ return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_getpoolbuf
+**
+** Description Called by an application to get a free buffer from
+** a specific buffer pool.
+**
+** Note: If there are no more buffers available from the pool,
+** the public buffers are searched for an available buffer.
+**
+** Parameters pool_id - (input) pool ID to get a buffer out of.
+**
+** Returns A pointer to the buffer, or NULL if none available
+**
+*******************************************************************************/
+void *GKI_getpoolbuf (UINT8 pool_id)
+{
+ FREE_QUEUE_T *Q;
+ BUFFER_HDR_T *p_hdr;
+ tGKI_COM_CB *p_cb = &gki_cb.com;
+
+ if (pool_id >= GKI_NUM_TOTAL_BUF_POOLS)
+ return (NULL);
+
+ /* Make sure the buffers aren't disturbed til finished with allocation */
+ GKI_disable();
+
+ Q = &p_cb->freeq[pool_id];
+ if(Q->cur_cnt < Q->total)
+ {
+// btla-specific ++
+#ifdef GKI_USE_DEFERED_ALLOC_BUF_POOLS
+ if(Q->p_first == 0 && gki_alloc_free_queue(pool_id) != TRUE)
+ return NULL;
+#endif
+// btla-specific --
+ p_hdr = Q->p_first;
+ Q->p_first = p_hdr->p_next;
+
+ if (!Q->p_first)
+ Q->p_last = NULL;
+
+ if(++Q->cur_cnt > Q->max_cnt)
+ Q->max_cnt = Q->cur_cnt;
+
+ GKI_enable();
+
+
+ p_hdr->task_id = GKI_get_taskid();
+
+ p_hdr->status = BUF_STATUS_UNLINKED;
+ p_hdr->p_next = NULL;
+ p_hdr->Type = 0;
+
+ return ((void *) ((UINT8 *)p_hdr + BUFFER_HDR_SIZE));
+ }
+
+ /* If here, no buffers in the specified pool */
+ GKI_enable();
+
+ /* try for free buffers in public pools */
+ return (GKI_getbuf(p_cb->freeq[pool_id].size));
+
+}
+
+/*******************************************************************************
+**
+** Function GKI_freebuf
+**
+** Description Called by an application to return a buffer to the free pool.
+**
+** Parameters p_buf - (input) address of the beginning of a buffer.
+**
+** Returns void
+**
+*******************************************************************************/
+void GKI_freebuf (void *p_buf)
+{
+ FREE_QUEUE_T *Q;
+ BUFFER_HDR_T *p_hdr;
+
+#if (GKI_ENABLE_BUF_CORRUPTION_CHECK == TRUE)
+ if (!p_buf || gki_chk_buf_damage(p_buf))
+ {
+ GKI_exception(GKI_ERROR_BUF_CORRUPTED, "Free - Buf Corrupted");
+ return;
+ }
+#endif
+
+ p_hdr = (BUFFER_HDR_T *) ((UINT8 *)p_buf - BUFFER_HDR_SIZE);
+
+ if (p_hdr->status != BUF_STATUS_UNLINKED)
+ {
+ GKI_exception(GKI_ERROR_FREEBUF_BUF_LINKED, "Freeing Linked Buf");
+ return;
+ }
+
+ if (p_hdr->q_id >= GKI_NUM_TOTAL_BUF_POOLS)
+ {
+ GKI_exception(GKI_ERROR_FREEBUF_BAD_QID, "Bad Buf QId");
+ return;
+ }
+
+ GKI_disable();
+
+ /*
+ ** Release the buffer
+ */
+ Q = &gki_cb.com.freeq[p_hdr->q_id];
+ if (Q->p_last)
+ Q->p_last->p_next = p_hdr;
+ else
+ Q->p_first = p_hdr;
+
+ Q->p_last = p_hdr;
+ p_hdr->p_next = NULL;
+ p_hdr->status = BUF_STATUS_FREE;
+ p_hdr->task_id = GKI_INVALID_TASK;
+ if (Q->cur_cnt > 0)
+ Q->cur_cnt--;
+
+ GKI_enable();
+
+ return;
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_get_buf_size
+**
+** Description Called by an application to get the size of a buffer.
+**
+** Parameters p_buf - (input) address of the beginning of a buffer.
+**
+** Returns the size of the buffer
+**
+*******************************************************************************/
+UINT16 GKI_get_buf_size (void *p_buf)
+{
+ BUFFER_HDR_T *p_hdr;
+
+ p_hdr = (BUFFER_HDR_T *)((UINT8 *) p_buf - BUFFER_HDR_SIZE);
+
+ if ((UINT32)p_hdr & 1)
+ return (0);
+
+ if (p_hdr->q_id < GKI_NUM_TOTAL_BUF_POOLS)
+ {
+ return (gki_cb.com.freeq[p_hdr->q_id].size);
+ }
+
+ return (0);
+}
+
+/*******************************************************************************
+**
+** Function gki_chk_buf_damage
+**
+** Description Called internally by OSS to check for buffer corruption.
+**
+** Returns TRUE if there is a problem, else FALSE
+**
+*******************************************************************************/
+BOOLEAN gki_chk_buf_damage(void *p_buf)
+{
+#if (GKI_ENABLE_BUF_CORRUPTION_CHECK == TRUE)
+
+ UINT32 *magic;
+ magic = (UINT32 *)((UINT8 *) p_buf + GKI_get_buf_size(p_buf));
+
+ if ((UINT32)magic & 1)
+ return (TRUE);
+
+ if (*magic == MAGIC_NO)
+ return (FALSE);
+
+ return (TRUE);
+
+#else
+
+ return (FALSE);
+
+#endif
+}
+
+/*******************************************************************************
+**
+** Function GKI_send_msg
+**
+** Description Called by applications to send a buffer to a task
+**
+** Returns Nothing
+**
+*******************************************************************************/
+void GKI_send_msg (UINT8 task_id, UINT8 mbox, void *msg)
+{
+ BUFFER_HDR_T *p_hdr;
+ tGKI_COM_CB *p_cb = &gki_cb.com;
+
+ /* If task non-existant or not started, drop buffer */
+ if ((task_id >= GKI_MAX_TASKS) || (mbox >= NUM_TASK_MBOX) || (p_cb->OSRdyTbl[task_id] == TASK_DEAD))
+ {
+ GKI_exception(GKI_ERROR_SEND_MSG_BAD_DEST, "Sending to unknown dest");
+ GKI_freebuf (msg);
+ return;
+ }
+
+#if (GKI_ENABLE_BUF_CORRUPTION_CHECK == TRUE)
+ if (gki_chk_buf_damage(msg))
+ {
+ GKI_exception(GKI_ERROR_BUF_CORRUPTED, "Send - Buffer corrupted");
+ return;
+ }
+#endif
+
+ p_hdr = (BUFFER_HDR_T *) ((UINT8 *) msg - BUFFER_HDR_SIZE);
+
+ if (p_hdr->status != BUF_STATUS_UNLINKED)
+ {
+ GKI_exception(GKI_ERROR_SEND_MSG_BUF_LINKED, "Send - buffer linked");
+ return;
+ }
+
+ GKI_disable();
+
+ if (p_cb->OSTaskQFirst[task_id][mbox])
+ p_cb->OSTaskQLast[task_id][mbox]->p_next = p_hdr;
+ else
+ p_cb->OSTaskQFirst[task_id][mbox] = p_hdr;
+
+ p_cb->OSTaskQLast[task_id][mbox] = p_hdr;
+
+ p_hdr->p_next = NULL;
+ p_hdr->status = BUF_STATUS_QUEUED;
+ p_hdr->task_id = task_id;
+
+
+ GKI_enable();
+
+ GKI_send_event(task_id, (UINT16)EVENT_MASK(mbox));
+
+ return;
+}
+
+/*******************************************************************************
+**
+** Function GKI_read_mbox
+**
+** Description Called by applications to read a buffer from one of
+** the task mailboxes. A task can only read its own mailbox.
+**
+** Parameters: mbox - (input) mailbox ID to read (0, 1, 2, or 3)
+**
+** Returns NULL if the mailbox was empty, else the address of a buffer
+**
+*******************************************************************************/
+void *GKI_read_mbox (UINT8 mbox)
+{
+ UINT8 task_id = GKI_get_taskid();
+ void *p_buf = NULL;
+ BUFFER_HDR_T *p_hdr;
+
+ if ((task_id >= GKI_MAX_TASKS) || (mbox >= NUM_TASK_MBOX))
+ return (NULL);
+
+ GKI_disable();
+
+ if (gki_cb.com.OSTaskQFirst[task_id][mbox])
+ {
+ p_hdr = gki_cb.com.OSTaskQFirst[task_id][mbox];
+ gki_cb.com.OSTaskQFirst[task_id][mbox] = p_hdr->p_next;
+
+ p_hdr->p_next = NULL;
+ p_hdr->status = BUF_STATUS_UNLINKED;
+
+ p_buf = (UINT8 *)p_hdr + BUFFER_HDR_SIZE;
+ }
+
+ GKI_enable();
+
+ return (p_buf);
+}
+
+
+
+/*******************************************************************************
+**
+** Function GKI_enqueue
+**
+** Description Enqueue a buffer at the tail of the queue
+**
+** Parameters: p_q - (input) pointer to a queue.
+** p_buf - (input) address of the buffer to enqueue
+**
+** Returns void
+**
+*******************************************************************************/
+void GKI_enqueue (BUFFER_Q *p_q, void *p_buf)
+{
+ BUFFER_HDR_T *p_hdr;
+
+#if (GKI_ENABLE_BUF_CORRUPTION_CHECK == TRUE)
+ if (gki_chk_buf_damage(p_buf))
+ {
+ GKI_exception(GKI_ERROR_BUF_CORRUPTED, "Enqueue - Buffer corrupted");
+ return;
+ }
+#endif
+
+ p_hdr = (BUFFER_HDR_T *) ((UINT8 *) p_buf - BUFFER_HDR_SIZE);
+
+ if (p_hdr->status != BUF_STATUS_UNLINKED)
+ {
+ GKI_exception(GKI_ERROR_ENQUEUE_BUF_LINKED, "Eneueue - buf already linked");
+ return;
+ }
+
+ GKI_disable();
+
+ /* Since the queue is exposed (C vs C++), keep the pointers in exposed format */
+ if (p_q->p_last)
+ {
+ BUFFER_HDR_T *p_last_hdr = (BUFFER_HDR_T *)((UINT8 *)p_q->p_last - BUFFER_HDR_SIZE);
+ p_last_hdr->p_next = p_hdr;
+ }
+ else
+ p_q->p_first = p_buf;
+
+ p_q->p_last = p_buf;
+ p_q->count++;
+
+ p_hdr->p_next = NULL;
+ p_hdr->status = BUF_STATUS_QUEUED;
+
+ GKI_enable();
+
+ return;
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_enqueue_head
+**
+** Description Enqueue a buffer at the head of the queue
+**
+** Parameters: p_q - (input) pointer to a queue.
+** p_buf - (input) address of the buffer to enqueue
+**
+** Returns void
+**
+*******************************************************************************/
+void GKI_enqueue_head (BUFFER_Q *p_q, void *p_buf)
+{
+ BUFFER_HDR_T *p_hdr;
+
+#if (GKI_ENABLE_BUF_CORRUPTION_CHECK == TRUE)
+ if (gki_chk_buf_damage(p_buf))
+ {
+ GKI_exception(GKI_ERROR_BUF_CORRUPTED, "Enqueue - Buffer corrupted");
+ return;
+ }
+#endif
+
+ p_hdr = (BUFFER_HDR_T *) ((UINT8 *) p_buf - BUFFER_HDR_SIZE);
+
+ if (p_hdr->status != BUF_STATUS_UNLINKED)
+ {
+ GKI_exception(GKI_ERROR_ENQUEUE_BUF_LINKED, "Eneueue head - buf already linked");
+ return;
+ }
+
+ GKI_disable();
+
+ if (p_q->p_first)
+ {
+ p_hdr->p_next = (BUFFER_HDR_T *)((UINT8 *)p_q->p_first - BUFFER_HDR_SIZE);
+ p_q->p_first = p_buf;
+ }
+ else
+ {
+ p_q->p_first = p_buf;
+ p_q->p_last = p_buf;
+ p_hdr->p_next = NULL;
+ }
+ p_q->count++;
+
+ p_hdr->status = BUF_STATUS_QUEUED;
+
+ GKI_enable();
+
+ return;
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_dequeue
+**
+** Description Dequeues a buffer from the head of a queue
+**
+** Parameters: p_q - (input) pointer to a queue.
+**
+** Returns NULL if queue is empty, else buffer
+**
+*******************************************************************************/
+void *GKI_dequeue (BUFFER_Q *p_q)
+{
+ BUFFER_HDR_T *p_hdr;
+
+ GKI_disable();
+
+ if (!p_q || !p_q->count)
+ {
+ GKI_enable();
+ return (NULL);
+ }
+
+ p_hdr = (BUFFER_HDR_T *)((UINT8 *)p_q->p_first - BUFFER_HDR_SIZE);
+
+ /* Keep buffers such that GKI header is invisible
+ */
+ if (p_hdr->p_next)
+ p_q->p_first = ((UINT8 *)p_hdr->p_next + BUFFER_HDR_SIZE);
+ else
+ {
+ p_q->p_first = NULL;
+ p_q->p_last = NULL;
+ }
+
+ p_q->count--;
+
+ p_hdr->p_next = NULL;
+ p_hdr->status = BUF_STATUS_UNLINKED;
+
+ GKI_enable();
+
+ return ((UINT8 *)p_hdr + BUFFER_HDR_SIZE);
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_remove_from_queue
+**
+** Description Dequeue a buffer from the middle of the queue
+**
+** Parameters: p_q - (input) pointer to a queue.
+** p_buf - (input) address of the buffer to enqueue
+**
+** Returns NULL if queue is empty, else buffer
+**
+*******************************************************************************/
+void *GKI_remove_from_queue (BUFFER_Q *p_q, void *p_buf)
+{
+ BUFFER_HDR_T *p_prev;
+ BUFFER_HDR_T *p_buf_hdr;
+
+ GKI_disable();
+
+ if (p_buf == p_q->p_first)
+ {
+ GKI_enable();
+ return (GKI_dequeue (p_q));
+ }
+
+ p_buf_hdr = (BUFFER_HDR_T *)((UINT8 *)p_buf - BUFFER_HDR_SIZE);
+ p_prev = (BUFFER_HDR_T *)((UINT8 *)p_q->p_first - BUFFER_HDR_SIZE);
+
+ for ( ; p_prev; p_prev = p_prev->p_next)
+ {
+ /* If the previous points to this one, move the pointers around */
+ if (p_prev->p_next == p_buf_hdr)
+ {
+ p_prev->p_next = p_buf_hdr->p_next;
+
+ /* If we are removing the last guy in the queue, update p_last */
+ if (p_buf == p_q->p_last)
+ p_q->p_last = p_prev + 1;
+
+ /* One less in the queue */
+ p_q->count--;
+
+ /* The buffer is now unlinked */
+ p_buf_hdr->p_next = NULL;
+ p_buf_hdr->status = BUF_STATUS_UNLINKED;
+
+ GKI_enable();
+ return (p_buf);
+ }
+ }
+
+ GKI_enable();
+ return (NULL);
+}
+
+/*******************************************************************************
+**
+** Function GKI_getfirst
+**
+** Description Return a pointer to the first buffer in a queue
+**
+** Parameters: p_q - (input) pointer to a queue.
+**
+** Returns NULL if queue is empty, else buffer address
+**
+*******************************************************************************/
+void *GKI_getfirst (BUFFER_Q *p_q)
+{
+ return (p_q->p_first);
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_getlast
+**
+** Description Return a pointer to the last buffer in a queue
+**
+** Parameters: p_q - (input) pointer to a queue.
+**
+** Returns NULL if queue is empty, else buffer address
+**
+*******************************************************************************/
+void *GKI_getlast (BUFFER_Q *p_q)
+{
+ return (p_q->p_last);
+}
+
+/*******************************************************************************
+**
+** Function GKI_getnext
+**
+** Description Return a pointer to the next buffer in a queue
+**
+** Parameters: p_buf - (input) pointer to the buffer to find the next one from.
+**
+** Returns NULL if no more buffers in the queue, else next buffer address
+**
+*******************************************************************************/
+void *GKI_getnext (void *p_buf)
+{
+ BUFFER_HDR_T *p_hdr;
+
+ p_hdr = (BUFFER_HDR_T *) ((UINT8 *) p_buf - BUFFER_HDR_SIZE);
+
+ if (p_hdr->p_next)
+ return ((UINT8 *)p_hdr->p_next + BUFFER_HDR_SIZE);
+ else
+ return (NULL);
+}
+
+
+
+/*******************************************************************************
+**
+** Function GKI_queue_is_empty
+**
+** Description Check the status of a queue.
+**
+** Parameters: p_q - (input) pointer to a queue.
+**
+** Returns TRUE if queue is empty, else FALSE
+**
+*******************************************************************************/
+BOOLEAN GKI_queue_is_empty(BUFFER_Q *p_q)
+{
+ return ((BOOLEAN) (p_q->count == 0));
+}
+
+/*******************************************************************************
+**
+** Function GKI_find_buf_start
+**
+** Description This function is called with an address inside a buffer,
+** and returns the start address ofthe buffer.
+**
+** The buffer should be one allocated from one of GKI's pools.
+**
+** Parameters: p_user_area - (input) address of anywhere in a GKI buffer.
+**
+** Returns void * - Address of the beginning of the specified buffer if successful,
+** otherwise NULL if unsuccessful
+**
+*******************************************************************************/
+void *GKI_find_buf_start (void *p_user_area)
+{
+ UINT16 xx, size;
+ UINT32 yy;
+ tGKI_COM_CB *p_cb = &gki_cb.com;
+ UINT8 *p_ua = (UINT8 *)p_user_area;
+
+ for (xx = 0; xx < GKI_NUM_TOTAL_BUF_POOLS; xx++)
+ {
+ if ((p_ua > p_cb->pool_start[xx]) && (p_ua < p_cb->pool_end[xx]))
+ {
+ yy = (UINT32)(p_ua - p_cb->pool_start[xx]);
+
+ size = p_cb->pool_size[xx];
+
+ yy = (yy / size) * size;
+
+ return ((void *) (p_cb->pool_start[xx] + yy + sizeof(BUFFER_HDR_T)) );
+ }
+ }
+
+ /* If here, invalid address - not in one of our buffers */
+ GKI_exception (GKI_ERROR_BUF_SIZE_ZERO, "GKI_get_buf_start:: bad addr");
+
+ return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_set_pool_permission
+**
+** Description This function is called to set or change the permissions for
+** the specified pool ID.
+**
+** Parameters pool_id - (input) pool ID to be set or changed
+** permission - (input) GKI_PUBLIC_POOL or GKI_RESTRICTED_POOL
+**
+** Returns GKI_SUCCESS if successful
+** GKI_INVALID_POOL if unsuccessful
+**
+*******************************************************************************/
+UINT8 GKI_set_pool_permission(UINT8 pool_id, UINT8 permission)
+{
+ tGKI_COM_CB *p_cb = &gki_cb.com;
+
+ if (pool_id < GKI_NUM_TOTAL_BUF_POOLS)
+ {
+ if (permission == GKI_RESTRICTED_POOL)
+ p_cb->pool_access_mask = (UINT16)(p_cb->pool_access_mask | (1 << pool_id));
+
+ else /* mark the pool as public */
+ p_cb->pool_access_mask = (UINT16)(p_cb->pool_access_mask & ~(1 << pool_id));
+
+ return (GKI_SUCCESS);
+ }
+ else
+ return (GKI_INVALID_POOL);
+}
+
+/*******************************************************************************
+**
+** Function gki_add_to_pool_list
+**
+** Description Adds pool to the pool list which is arranged in the
+** order of size
+**
+** Returns void
+**
+*******************************************************************************/
+static void gki_add_to_pool_list(UINT8 pool_id)
+{
+
+ INT32 i, j;
+ tGKI_COM_CB *p_cb = &gki_cb.com;
+
+ /* Find the position where the specified pool should be inserted into the list */
+ for(i=0; i < p_cb->curr_total_no_of_pools; i++)
+ {
+
+ if(p_cb->freeq[pool_id].size <= p_cb->freeq[ p_cb->pool_list[i] ].size)
+ break;
+ }
+
+ /* Insert the new buffer pool ID into the list of pools */
+ for(j = p_cb->curr_total_no_of_pools; j > i; j--)
+ {
+ p_cb->pool_list[j] = p_cb->pool_list[j-1];
+ }
+
+ p_cb->pool_list[i] = pool_id;
+
+ return;
+}
+
+/*******************************************************************************
+**
+** Function gki_remove_from_pool_list
+**
+** Description Removes pool from the pool list. Called when a pool is deleted
+**
+** Returns void
+**
+*******************************************************************************/
+static void gki_remove_from_pool_list(UINT8 pool_id)
+{
+ tGKI_COM_CB *p_cb = &gki_cb.com;
+ UINT8 i;
+
+ for(i=0; i < p_cb->curr_total_no_of_pools; i++)
+ {
+ if(pool_id == p_cb->pool_list[i])
+ break;
+ }
+
+ while (i < (p_cb->curr_total_no_of_pools - 1))
+ {
+ p_cb->pool_list[i] = p_cb->pool_list[i+1];
+ i++;
+ }
+
+ return;
+}
+
+/*******************************************************************************
+**
+** Function GKI_igetpoolbuf
+**
+** Description Called by an interrupt service routine to get a free buffer from
+** a specific buffer pool.
+**
+** Parameters pool_id - (input) pool ID to get a buffer out of.
+**
+** Returns A pointer to the buffer, or NULL if none available
+**
+*******************************************************************************/
+void *GKI_igetpoolbuf (UINT8 pool_id)
+{
+ FREE_QUEUE_T *Q;
+ BUFFER_HDR_T *p_hdr;
+
+ if (pool_id >= GKI_NUM_TOTAL_BUF_POOLS)
+ return (NULL);
+
+
+ Q = &gki_cb.com.freeq[pool_id];
+ if(Q->cur_cnt < Q->total)
+ {
+ p_hdr = Q->p_first;
+ Q->p_first = p_hdr->p_next;
+
+ if (!Q->p_first)
+ Q->p_last = NULL;
+
+ if(++Q->cur_cnt > Q->max_cnt)
+ Q->max_cnt = Q->cur_cnt;
+
+ p_hdr->task_id = GKI_get_taskid();
+
+ p_hdr->status = BUF_STATUS_UNLINKED;
+ p_hdr->p_next = NULL;
+ p_hdr->Type = 0;
+
+ return ((void *) ((UINT8 *)p_hdr + BUFFER_HDR_SIZE));
+ }
+
+ return (NULL);
+}
+
+/*******************************************************************************
+**
+** Function GKI_poolcount
+**
+** Description Called by an application to get the total number of buffers
+** in the specified buffer pool.
+**
+** Parameters pool_id - (input) pool ID to get the free count of.
+**
+** Returns the total number of buffers in the pool
+**
+*******************************************************************************/
+UINT16 GKI_poolcount (UINT8 pool_id)
+{
+ if (pool_id >= GKI_NUM_TOTAL_BUF_POOLS)
+ return (0);
+
+ return (gki_cb.com.freeq[pool_id].total);
+}
+
+/*******************************************************************************
+**
+** Function GKI_poolfreecount
+**
+** Description Called by an application to get the number of free buffers
+** in the specified buffer pool.
+**
+** Parameters pool_id - (input) pool ID to get the free count of.
+**
+** Returns the number of free buffers in the pool
+**
+*******************************************************************************/
+UINT16 GKI_poolfreecount (UINT8 pool_id)
+{
+ FREE_QUEUE_T *Q;
+
+ if (pool_id >= GKI_NUM_TOTAL_BUF_POOLS)
+ return (0);
+
+ Q = &gki_cb.com.freeq[pool_id];
+
+ return ((UINT16)(Q->total - Q->cur_cnt));
+}
+
+/*******************************************************************************
+**
+** Function GKI_change_buf_owner
+**
+** Description Called to change the task ownership of a buffer.
+**
+** Parameters: p_buf - (input) pointer to the buffer
+** task_id - (input) task id to change ownership to
+**
+** Returns void
+**
+*******************************************************************************/
+void GKI_change_buf_owner (void *p_buf, UINT8 task_id)
+{
+ BUFFER_HDR_T *p_hdr = (BUFFER_HDR_T *) ((UINT8 *) p_buf - BUFFER_HDR_SIZE);
+
+ p_hdr->task_id = task_id;
+
+ return;
+}
+
+#if (defined(GKI_SEND_MSG_FROM_ISR) && GKI_SEND_MSG_FROM_ISR == TRUE)
+/*******************************************************************************
+**
+** Function GKI_isend_msg
+**
+** Description Called from interrupt context to send a buffer to a task
+**
+** Returns Nothing
+**
+*******************************************************************************/
+void GKI_isend_msg (UINT8 task_id, UINT8 mbox, void *msg)
+{
+ BUFFER_HDR_T *p_hdr;
+ tGKI_COM_CB *p_cb = &gki_cb.com;
+
+ /* If task non-existant or not started, drop buffer */
+ if ((task_id >= GKI_MAX_TASKS) || (mbox >= NUM_TASK_MBOX) || (p_cb->OSRdyTbl[task_id] == TASK_DEAD))
+ {
+ GKI_exception(GKI_ERROR_SEND_MSG_BAD_DEST, "Sending to unknown dest");
+ GKI_freebuf (msg);
+ return;
+ }
+
+#if (GKI_ENABLE_BUF_CORRUPTION_CHECK == TRUE)
+ if (gki_chk_buf_damage(msg))
+ {
+ GKI_exception(GKI_ERROR_BUF_CORRUPTED, "Send - Buffer corrupted");
+ return;
+ }
+#endif
+
+#if (GKI_ENABLE_OWNER_CHECK == TRUE)
+ if (gki_chk_buf_owner(msg))
+ {
+ GKI_exception(GKI_ERROR_NOT_BUF_OWNER, "Send by non-owner");
+ return;
+ }
+#endif
+
+ p_hdr = (BUFFER_HDR_T *) ((UINT8 *) msg - BUFFER_HDR_SIZE);
+
+ if (p_hdr->status != BUF_STATUS_UNLINKED)
+ {
+ GKI_exception(GKI_ERROR_SEND_MSG_BUF_LINKED, "Send - buffer linked");
+ return;
+ }
+
+ if (p_cb->OSTaskQFirst[task_id][mbox])
+ p_cb->OSTaskQLast[task_id][mbox]->p_next = p_hdr;
+ else
+ p_cb->OSTaskQFirst[task_id][mbox] = p_hdr;
+
+ p_cb->OSTaskQLast[task_id][mbox] = p_hdr;
+
+ p_hdr->p_next = NULL;
+ p_hdr->status = BUF_STATUS_QUEUED;
+ p_hdr->task_id = task_id;
+
+ GKI_isend_event(task_id, (UINT16)EVENT_MASK(mbox));
+
+ return;
+}
+#endif
+
+/*******************************************************************************
+**
+** Function GKI_create_pool
+**
+** Description Called by applications to create a buffer pool.
+**
+** Parameters: size - (input) length (in bytes) of each buffer in the pool
+** count - (input) number of buffers to allocate for the pool
+** permission - (input) restricted or public access?
+** (GKI_PUBLIC_POOL or GKI_RESTRICTED_POOL)
+** p_mem_pool - (input) pointer to an OS memory pool, NULL if not provided
+**
+** Returns the buffer pool ID, which should be used in calls to
+** GKI_getpoolbuf(). If a pool could not be created, this
+** function returns 0xff.
+**
+*******************************************************************************/
+UINT8 GKI_create_pool (UINT16 size, UINT16 count, UINT8 permission, void *p_mem_pool)
+{
+ UINT8 xx;
+ UINT32 mem_needed;
+ INT32 tempsize = size;
+ tGKI_COM_CB *p_cb = &gki_cb.com;
+
+ /* First make sure the size of each pool has a valid size with room for the header info */
+ if (size > MAX_USER_BUF_SIZE)
+ return (GKI_INVALID_POOL);
+
+ /* First, look for an unused pool */
+ for (xx = 0; xx < GKI_NUM_TOTAL_BUF_POOLS; xx++)
+ {
+ if (!p_cb->pool_start[xx])
+ break;
+ }
+
+ if (xx == GKI_NUM_TOTAL_BUF_POOLS)
+ return (GKI_INVALID_POOL);
+
+ /* Ensure an even number of longwords */
+ tempsize = (INT32)ALIGN_POOL(size);
+
+ mem_needed = (tempsize + BUFFER_PADDING_SIZE) * count;
+
+ if (!p_mem_pool)
+ p_mem_pool = GKI_os_malloc(mem_needed);
+
+ if (p_mem_pool)
+ {
+ /* Initialize the new pool */
+ gki_init_free_queue (xx, size, count, p_mem_pool);
+ gki_add_to_pool_list(xx);
+ (void) GKI_set_pool_permission (xx, permission);
+ p_cb->curr_total_no_of_pools++;
+
+ return (xx);
+ }
+ else
+ return (GKI_INVALID_POOL);
+}
+
+/*******************************************************************************
+**
+** Function GKI_delete_pool
+**
+** Description Called by applications to delete a buffer pool. The function
+** calls the operating specific function to free the actual memory.
+** An exception is generated if an error is detected.
+**
+** Parameters: pool_id - (input) Id of the poll being deleted.
+**
+** Returns void
+**
+*******************************************************************************/
+void GKI_delete_pool (UINT8 pool_id)
+{
+ FREE_QUEUE_T *Q;
+ tGKI_COM_CB *p_cb = &gki_cb.com;
+
+ if ((pool_id >= GKI_NUM_TOTAL_BUF_POOLS) || (!p_cb->pool_start[pool_id]))
+ return;
+
+ GKI_disable();
+ Q = &p_cb->freeq[pool_id];
+
+ if (!Q->cur_cnt)
+ {
+ Q->size = 0;
+ Q->total = 0;
+ Q->cur_cnt = 0;
+ Q->max_cnt = 0;
+ Q->p_first = NULL;
+ Q->p_last = NULL;
+
+ GKI_os_free (p_cb->pool_start[pool_id]);
+
+ p_cb->pool_start[pool_id] = NULL;
+ p_cb->pool_end[pool_id] = NULL;
+ p_cb->pool_size[pool_id] = 0;
+
+ gki_remove_from_pool_list(pool_id);
+ p_cb->curr_total_no_of_pools--;
+ }
+ else
+ GKI_exception(GKI_ERROR_DELETE_POOL_BAD_QID, "Deleting bad pool");
+
+ GKI_enable();
+
+ return;
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_get_pool_bufsize
+**
+** Description Called by an application to get the size of buffers in a pool
+**
+** Parameters Pool ID.
+**
+** Returns the size of buffers in the pool
+**
+*******************************************************************************/
+UINT16 GKI_get_pool_bufsize (UINT8 pool_id)
+{
+ if (pool_id < GKI_NUM_TOTAL_BUF_POOLS)
+ return (gki_cb.com.freeq[pool_id].size);
+
+ return (0);
+}
+
+/*******************************************************************************
+**
+** Function GKI_poolutilization
+**
+** Description Called by an application to get the buffer utilization
+** in the specified buffer pool.
+**
+** Parameters pool_id - (input) pool ID to get the free count of.
+**
+** Returns % of buffers used from 0 to 100
+**
+*******************************************************************************/
+UINT16 GKI_poolutilization (UINT8 pool_id)
+{
+ FREE_QUEUE_T *Q;
+
+ if (pool_id >= GKI_NUM_TOTAL_BUF_POOLS)
+ return (100);
+
+ Q = &gki_cb.com.freeq[pool_id];
+
+ if (Q->total == 0)
+ return (100);
+
+ return ((Q->cur_cnt * 100) / Q->total);
+}
+
diff --git a/gki/common/gki_common.h b/gki/common/gki_common.h
new file mode 100644
index 0000000..6093abf
--- /dev/null
+++ b/gki/common/gki_common.h
@@ -0,0 +1,384 @@
+/****************************************************************************
+**
+** Name gki_common.h
+**
+** Function This file contains GKI private definitions
+**
+**
+** Copyright (c) 1999-2006, Broadcom Corp., All Rights Reserved.
+** Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef GKI_COMMON_H
+#define GKI_COMMON_H
+
+#include "gki.h"
+#include "dyn_mem.h"
+
+/* Task States: (For OSRdyTbl) */
+#define TASK_DEAD 0 /* b0000 */
+#define TASK_READY 1 /* b0001 */
+#define TASK_WAIT 2 /* b0010 */
+#define TASK_DELAY 4 /* b0100 */
+#define TASK_SUSPEND 8 /* b1000 */
+
+
+/********************************************************************
+** Internal Error codes
+*********************************************************************/
+#define GKI_ERROR_BUF_CORRUPTED 0xFFFF
+#define GKI_ERROR_NOT_BUF_OWNER 0xFFFE
+#define GKI_ERROR_FREEBUF_BAD_QID 0xFFFD
+#define GKI_ERROR_FREEBUF_BUF_LINKED 0xFFFC
+#define GKI_ERROR_SEND_MSG_BAD_DEST 0xFFFB
+#define GKI_ERROR_SEND_MSG_BUF_LINKED 0xFFFA
+#define GKI_ERROR_ENQUEUE_BUF_LINKED 0xFFF9
+#define GKI_ERROR_DELETE_POOL_BAD_QID 0xFFF8
+#define GKI_ERROR_BUF_SIZE_TOOBIG 0xFFF7
+#define GKI_ERROR_BUF_SIZE_ZERO 0xFFF6
+#define GKI_ERROR_ADDR_NOT_IN_BUF 0xFFF5
+
+
+/********************************************************************
+** Misc constants
+*********************************************************************/
+
+#define GKI_MAX_INT32 (0x7fffffffL)
+#define GKI_MAX_TIMESTAMP (0xffffffffL)
+
+/********************************************************************
+** Buffer Management Data Structures
+*********************************************************************/
+
+typedef struct _buffer_hdr
+{
+ struct _buffer_hdr *p_next; /* next buffer in the queue */
+ UINT8 q_id; /* id of the queue */
+ UINT8 task_id; /* task which allocated the buffer*/
+ UINT8 status; /* FREE, UNLINKED or QUEUED */
+ UINT8 Type;
+} BUFFER_HDR_T;
+
+typedef struct _free_queue
+{
+ BUFFER_HDR_T *p_first; /* first buffer in the queue */
+ BUFFER_HDR_T *p_last; /* last buffer in the queue */
+ UINT16 size; /* size of the buffers in the pool */
+ UINT16 total; /* toatal number of buffers */
+ UINT16 cur_cnt; /* number of buffers currently allocated */
+ UINT16 max_cnt; /* maximum number of buffers allocated at any time */
+} FREE_QUEUE_T;
+
+
+/* Buffer related defines
+*/
+#define ALIGN_POOL(pl_size) ( (((pl_size) + 3) / sizeof(UINT32)) * sizeof(UINT32))
+#define BUFFER_HDR_SIZE (sizeof(BUFFER_HDR_T)) /* Offset past header */
+#define BUFFER_PADDING_SIZE (sizeof(BUFFER_HDR_T) + sizeof(UINT32)) /* Header + Magic Number */
+#define MAX_USER_BUF_SIZE ((UINT16)0xffff - BUFFER_PADDING_SIZE) /* pool size must allow for header */
+#define MAGIC_NO 0xDDBADDBA
+
+#define BUF_STATUS_FREE 0
+#define BUF_STATUS_UNLINKED 1
+#define BUF_STATUS_QUEUED 2
+
+// btla-specific ++
+#define GKI_USE_DEFERED_ALLOC_BUF_POOLS
+// btla-specific --
+
+/* Exception related structures (Used in debug mode only)
+*/
+#if (GKI_DEBUG == TRUE)
+typedef struct
+{
+ UINT16 type;
+ UINT8 taskid;
+ UINT8 msg[GKI_MAX_EXCEPTION_MSGLEN];
+} EXCEPTION_T;
+#endif
+
+
+/* Put all GKI variables into one control block
+*/
+typedef struct
+{
+ /* Task management variables
+ */
+ /* The stack and stack size are not used on Windows
+ */
+// btla-specific ++
+#if (!defined GKI_USE_DEFERED_ALLOC_BUF_POOLS && (GKI_USE_DYNAMIC_BUFFERS == FALSE))
+// btla-specific --
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 0)
+ UINT8 bufpool0[(ALIGN_POOL(GKI_BUF0_SIZE) + BUFFER_PADDING_SIZE) * GKI_BUF0_MAX];
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 1)
+ UINT8 bufpool1[(ALIGN_POOL(GKI_BUF1_SIZE) + BUFFER_PADDING_SIZE) * GKI_BUF1_MAX];
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 2)
+ UINT8 bufpool2[(ALIGN_POOL(GKI_BUF2_SIZE) + BUFFER_PADDING_SIZE) * GKI_BUF2_MAX];
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 3)
+ UINT8 bufpool3[(ALIGN_POOL(GKI_BUF3_SIZE) + BUFFER_PADDING_SIZE) * GKI_BUF3_MAX];
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 4)
+ UINT8 bufpool4[(ALIGN_POOL(GKI_BUF4_SIZE) + BUFFER_PADDING_SIZE) * GKI_BUF4_MAX];
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 5)
+ UINT8 bufpool5[(ALIGN_POOL(GKI_BUF5_SIZE) + BUFFER_PADDING_SIZE) * GKI_BUF5_MAX];
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 6)
+ UINT8 bufpool6[(ALIGN_POOL(GKI_BUF6_SIZE) + BUFFER_PADDING_SIZE) * GKI_BUF6_MAX];
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 7)
+ UINT8 bufpool7[(ALIGN_POOL(GKI_BUF7_SIZE) + BUFFER_PADDING_SIZE) * GKI_BUF7_MAX];
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 8)
+ UINT8 bufpool8[(ALIGN_POOL(GKI_BUF8_SIZE) + BUFFER_PADDING_SIZE) * GKI_BUF8_MAX];
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 9)
+ UINT8 bufpool9[(ALIGN_POOL(GKI_BUF9_SIZE) + BUFFER_PADDING_SIZE) * GKI_BUF9_MAX];
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 10)
+ UINT8 bufpool10[(ALIGN_POOL(GKI_BUF10_SIZE) + BUFFER_PADDING_SIZE) * GKI_BUF10_MAX];
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 11)
+ UINT8 bufpool11[(ALIGN_POOL(GKI_BUF11_SIZE) + BUFFER_PADDING_SIZE) * GKI_BUF11_MAX];
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 12)
+ UINT8 bufpool12[(ALIGN_POOL(GKI_BUF12_SIZE) + BUFFER_PADDING_SIZE) * GKI_BUF12_MAX];
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 13)
+ UINT8 bufpool13[(ALIGN_POOL(GKI_BUF13_SIZE) + BUFFER_PADDING_SIZE) * GKI_BUF13_MAX];
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 14)
+ UINT8 bufpool14[(ALIGN_POOL(GKI_BUF14_SIZE) + BUFFER_PADDING_SIZE) * GKI_BUF14_MAX];
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 15)
+ UINT8 bufpool15[(ALIGN_POOL(GKI_BUF15_SIZE) + BUFFER_PADDING_SIZE) * GKI_BUF15_MAX];
+#endif
+
+#else
+/* Definitions for dynamic buffer use */
+#if (GKI_NUM_FIXED_BUF_POOLS > 0)
+ UINT8 *bufpool0;
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 1)
+ UINT8 *bufpool1;
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 2)
+ UINT8 *bufpool2;
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 3)
+ UINT8 *bufpool3;
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 4)
+ UINT8 *bufpool4;
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 5)
+ UINT8 *bufpool5;
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 6)
+ UINT8 *bufpool6;
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 7)
+ UINT8 *bufpool7;
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 8)
+ UINT8 *bufpool8;
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 9)
+ UINT8 *bufpool9;
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 10)
+ UINT8 *bufpool10;
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 11)
+ UINT8 *bufpool11;
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 12)
+ UINT8 *bufpool12;
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 13)
+ UINT8 *bufpool13;
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 14)
+ UINT8 *bufpool14;
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 15)
+ UINT8 *bufpool15;
+#endif
+
+#endif
+
+ UINT8 *OSStack[GKI_MAX_TASKS]; /* pointer to beginning of stack */
+ UINT16 OSStackSize[GKI_MAX_TASKS]; /* stack size available to each task */
+
+
+ INT8 *OSTName[GKI_MAX_TASKS]; /* name of the task */
+
+ UINT8 OSRdyTbl[GKI_MAX_TASKS]; /* current state of the task */
+ UINT16 OSWaitEvt[GKI_MAX_TASKS]; /* events that have to be processed by the task */
+ UINT16 OSWaitForEvt[GKI_MAX_TASKS]; /* events the task is waiting for*/
+
+ UINT32 OSTicks; /* system ticks from start */
+ UINT32 OSIdleCnt; /* idle counter */
+ INT16 OSDisableNesting; /* counter to keep track of interrupt disable nesting */
+ INT16 OSLockNesting; /* counter to keep track of sched lock nesting */
+ INT16 OSIntNesting; /* counter to keep track of interrupt nesting */
+
+ /* Timer related variables
+ */
+ INT32 OSTicksTilExp; /* Number of ticks till next timer expires */
+#if (defined(GKI_DELAY_STOP_SYS_TICK) && (GKI_DELAY_STOP_SYS_TICK > 0))
+ UINT32 OSTicksTilStop; /* inactivity delay timer; OS Ticks till stopping system tick */
+#endif
+ INT32 OSNumOrigTicks; /* Number of ticks between last timer expiration to the next one */
+
+ INT32 OSWaitTmr [GKI_MAX_TASKS]; /* ticks the task has to wait, for specific events */
+
+ /* Only take up space timers used in the system (GKI_NUM_TIMERS defined in target.h) */
+#if (GKI_NUM_TIMERS > 0)
+ INT32 OSTaskTmr0 [GKI_MAX_TASKS];
+ INT32 OSTaskTmr0R [GKI_MAX_TASKS];
+#endif
+
+#if (GKI_NUM_TIMERS > 1)
+ INT32 OSTaskTmr1 [GKI_MAX_TASKS];
+ INT32 OSTaskTmr1R [GKI_MAX_TASKS];
+#endif
+
+#if (GKI_NUM_TIMERS > 2)
+ INT32 OSTaskTmr2 [GKI_MAX_TASKS];
+ INT32 OSTaskTmr2R [GKI_MAX_TASKS];
+#endif
+
+#if (GKI_NUM_TIMERS > 3)
+ INT32 OSTaskTmr3 [GKI_MAX_TASKS];
+ INT32 OSTaskTmr3R [GKI_MAX_TASKS];
+#endif
+
+
+
+ /* Buffer related variables
+ */
+ BUFFER_HDR_T *OSTaskQFirst[GKI_MAX_TASKS][NUM_TASK_MBOX]; /* array of pointers to the first event in the task mailbox */
+ BUFFER_HDR_T *OSTaskQLast [GKI_MAX_TASKS][NUM_TASK_MBOX]; /* array of pointers to the last event in the task mailbox */
+
+ /* Define the buffer pool management variables
+ */
+ FREE_QUEUE_T freeq[GKI_NUM_TOTAL_BUF_POOLS];
+
+ UINT16 pool_buf_size[GKI_NUM_TOTAL_BUF_POOLS];
+ UINT16 pool_max_count[GKI_NUM_TOTAL_BUF_POOLS];
+ UINT16 pool_additions[GKI_NUM_TOTAL_BUF_POOLS];
+
+ /* Define the buffer pool start addresses
+ */
+ UINT8 *pool_start[GKI_NUM_TOTAL_BUF_POOLS]; /* array of pointers to the start of each buffer pool */
+ UINT8 *pool_end[GKI_NUM_TOTAL_BUF_POOLS]; /* array of pointers to the end of each buffer pool */
+ UINT16 pool_size[GKI_NUM_TOTAL_BUF_POOLS]; /* actual size of the buffers in a pool */
+
+ /* Define the buffer pool access control variables */
+ void *p_user_mempool; /* User O/S memory pool */
+ UINT16 pool_access_mask; /* Bits are set if the corresponding buffer pool is a restricted pool */
+ UINT8 pool_list[GKI_NUM_TOTAL_BUF_POOLS]; /* buffer pools arranged in the order of size */
+ UINT8 curr_total_no_of_pools; /* number of fixed buf pools + current number of dynamic pools */
+
+ BOOLEAN timer_nesting; /* flag to prevent timer interrupt nesting */
+
+ /* Time queue arrays */
+ TIMER_LIST_Q *timer_queues[GKI_MAX_TIMER_QUEUES];
+ /* System tick callback */
+ SYSTEM_TICK_CBACK *p_tick_cb;
+ BOOLEAN system_tick_running; /* TRUE if system tick is running. Valid only if p_tick_cb is not NULL */
+
+#if (GKI_DEBUG == TRUE)
+ UINT16 ExceptionCnt; /* number of GKI exceptions that have happened */
+ EXCEPTION_T Exception[GKI_MAX_EXCEPTION];
+#endif
+
+} tGKI_COM_CB;
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Internal GKI function prototypes
+*/
+GKI_API extern BOOLEAN gki_chk_buf_damage(void *);
+extern BOOLEAN gki_chk_buf_owner(void *);
+extern void gki_buffer_init (void);
+extern void gki_timers_init(void);
+extern void gki_adjust_timer_count (INT32);
+
+#ifdef GKI_USE_DEFERED_ALLOC_BUF_POOLS
+extern void gki_dealloc_free_queue(void);
+#endif
+
+extern void OSStartRdy(void);
+extern void OSCtxSw(void);
+extern void OSIntCtxSw(void);
+extern void OSSched(void);
+extern void OSIntEnter(void);
+extern void OSIntExit(void);
+
+
+/* Debug aids
+*/
+typedef void (*FP_PRINT)(char *, ...);
+
+#if (GKI_DEBUG == TRUE)
+
+typedef void (*PKT_PRINT)(UINT8 *, UINT16);
+
+extern void gki_print_task(FP_PRINT);
+extern void gki_print_exception(FP_PRINT);
+extern void gki_print_timer(FP_PRINT);
+extern void gki_print_stack(FP_PRINT);
+extern void gki_print_buffer(FP_PRINT);
+extern void gki_print_buffer_statistics(FP_PRINT, INT16);
+GKI_API extern void gki_print_used_bufs (FP_PRINT, UINT8);
+extern void gki_dump(UINT8 *, UINT16, FP_PRINT);
+extern void gki_dump2(UINT16 *, UINT16, FP_PRINT);
+extern void gki_dump4(UINT32 *, UINT16, FP_PRINT);
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/gki/common/gki_debug.c b/gki/common/gki_debug.c
new file mode 100644
index 0000000..3ec8fc5
--- /dev/null
+++ b/gki/common/gki_debug.c
@@ -0,0 +1,348 @@
+/****************************************************************************
+**
+** Name gki_debug.c
+**
+** Function this file contains some sample GKI debug aid functions
+**
+**
+** Copyright (c) 1999-2004, WIDCOMM Inc., All Rights Reserved.
+** Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "gki_int.h"
+
+#if (GKI_DEBUG == TRUE)
+
+const INT8 * const OSTaskStates[] =
+{
+ (INT8 *)"DEAD", /* 0 */
+ (INT8 *)"REDY", /* 1 */
+ (INT8 *)"WAIT", /* 2 */
+ (INT8 *)"",
+ (INT8 *)"DELY", /* 4 */
+ (INT8 *)"",
+ (INT8 *)"",
+ (INT8 *)"",
+ (INT8 *)"SUSP", /* 8 */
+};
+
+
+/*******************************************************************************
+**
+** Function GKI_PrintBufferUsage
+**
+** Description Displays Current Buffer Pool summary
+**
+** Returns void
+**
+*******************************************************************************/
+void GKI_PrintBufferUsage(UINT8 *p_num_pools, UINT16 *p_cur_used)
+{
+ int i;
+ FREE_QUEUE_T *p;
+ UINT8 num = gki_cb.com.curr_total_no_of_pools;
+ UINT16 cur[GKI_NUM_TOTAL_BUF_POOLS];
+
+ GKI_TRACE_0("");
+ GKI_TRACE_0("--- GKI Buffer Pool Summary (R - restricted, P - public) ---");
+
+ GKI_TRACE_0("POOL SIZE USED MAXU TOTAL");
+ GKI_TRACE_0("------------------------------");
+ for (i = 0; i < gki_cb.com.curr_total_no_of_pools; i++)
+ {
+ p = &gki_cb.com.freeq[i];
+ if ((1 << i) & gki_cb.com.pool_access_mask)
+ {
+ GKI_TRACE_5("%02d: (R), %4d, %3d, %3d, %3d",
+ i, p->size, p->cur_cnt, p->max_cnt, p->total);
+ }
+ else
+ {
+ GKI_TRACE_5("%02d: (P), %4d, %3d, %3d, %3d",
+ i, p->size, p->cur_cnt, p->max_cnt, p->total);
+ }
+ cur[i] = p->cur_cnt;
+ }
+ if (p_num_pools)
+ *p_num_pools = num;
+ if (p_cur_used)
+ memcpy(p_cur_used, cur, num*2);
+}
+
+/*******************************************************************************
+**
+** Function GKI_PrintBuffer
+**
+** Description Called internally by OSS to print the buffer pools
+**
+** Returns void
+**
+*******************************************************************************/
+void GKI_PrintBuffer(void)
+{
+ UINT16 i;
+ for(i=0; i<GKI_NUM_TOTAL_BUF_POOLS; i++)
+ {
+ GKI_TRACE_5("pool:%4u free %4u cur %3u max %3u total%3u", i, gki_cb.com.freeq[i].size,
+ gki_cb.com.freeq[i].cur_cnt, gki_cb.com.freeq[i].max_cnt, gki_cb.com.freeq[i].total);
+ }
+}
+
+/*******************************************************************************
+**
+** Function gki_calc_stack
+**
+** Description This function tries to calculate the amount of
+** stack used by looking non magic num. Magic num is consider
+** the first byte in the stack.
+**
+** Returns the number of unused byte on the stack. 4 in case of stack overrun
+**
+*******************************************************************************/
+UINT16 gki_calc_stack (UINT8 task)
+{
+ int j, stacksize;
+ UINT32 MagicNum;
+ UINT32 *p;
+
+ stacksize = (int) gki_cb.com.OSStackSize[task];
+ p = (UINT32 *)gki_cb.com.OSStack[task]; /* assume stack is aligned, */
+ MagicNum = *p;
+
+ for(j = 0; j < stacksize; j++)
+ {
+ if(*p++ != MagicNum) break;
+ }
+
+ return (j * sizeof(UINT32));
+}
+
+/*******************************************************************************
+**
+** Function GKI_print_task
+**
+** Description Print task stack usage.
+**
+** Returns void
+**
+*******************************************************************************/
+void GKI_print_task(void)
+{
+#ifdef _BT_WIN32
+ GKI_TRACE_0("Service not available under insight");
+#else
+ UINT8 TaskId;
+
+ GKI_TRACE_0("TID TASKNAME STATE FREE_STACK STACK");
+ for(TaskId=0; TaskId < GKI_MAX_TASKS; TaskId++)
+ {
+ if (gki_cb.com.OSRdyTbl[TaskId] != TASK_DEAD)
+ {
+ GKI_TRACE_5("%2u %-8s %-5s 0x%04X 0x%04X Bytes",
+ (UINT16)TaskId, gki_cb.com.OSTName[TaskId],
+ OSTaskStates[gki_cb.com.OSRdyTbl[TaskId]],
+ gki_calc_stack(TaskId), gki_cb.com.OSStackSize[TaskId]);
+
+ }
+ }
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function gki_print_buffer_statistics
+**
+** Description Called internally by OSS to print the buffer pools statistics
+**
+** Returns void
+**
+*******************************************************************************/
+void gki_print_buffer_statistics(FP_PRINT print, INT16 pool)
+{
+ UINT16 i;
+ BUFFER_HDR_T *hdr;
+ UINT16 size,act_size,maxbuffs;
+ UINT32 *magic;
+
+ if (pool > GKI_NUM_TOTAL_BUF_POOLS || pool < 0)
+ {
+ print("Not a valid Buffer pool\n");
+ return;
+ }
+
+ size = gki_cb.com.freeq[pool].size;
+ maxbuffs = gki_cb.com.freeq[pool].total;
+ act_size = size + BUFFER_PADDING_SIZE;
+ print("Buffer Pool[%u] size=%u cur_cnt=%u max_cnt=%u total=%u\n",
+ pool, gki_cb.com.freeq[pool].size,
+ gki_cb.com.freeq[pool].cur_cnt, gki_cb.com.freeq[pool].max_cnt, gki_cb.com.freeq[pool].total);
+
+ print(" Owner State Sanity\n");
+ print("----------------------------\n");
+ hdr = (BUFFER_HDR_T *)(gki_cb.com.pool_start[pool]);
+ for(i=0; i<maxbuffs; i++)
+ {
+ magic = (UINT32 *)((UINT8 *)hdr + BUFFER_HDR_SIZE + size);
+ print("%3d: 0x%02x %4d %10s\n", i, hdr->task_id, hdr->status, (*magic == MAGIC_NO)?"OK":"CORRUPTED");
+ hdr = (BUFFER_HDR_T *)((UINT8 *)hdr + act_size);
+ }
+ return;
+}
+
+
+/*******************************************************************************
+**
+** Function gki_print_used_bufs
+**
+** Description Dumps used buffers in the particular pool
+**
+*******************************************************************************/
+GKI_API void gki_print_used_bufs (FP_PRINT print, UINT8 pool_id)
+{
+ UINT8 *p_start;
+ UINT16 buf_size;
+ UINT16 num_bufs;
+ BUFFER_HDR_T *p_hdr;
+ UINT16 i;
+ UINT32 *magic;
+ UINT16 *p;
+
+
+ if (pool_id >= GKI_NUM_TOTAL_BUF_POOLS && gki_cb.com.pool_start[pool_id] != 0)
+ {
+ print("Not a valid Buffer pool\n");
+ return;
+ }
+
+ p_start = gki_cb.com.pool_start[pool_id];
+ buf_size = gki_cb.com.freeq[pool_id].size + BUFFER_PADDING_SIZE;
+ num_bufs = gki_cb.com.freeq[pool_id].total;
+
+ for (i = 0; i < num_bufs; i++, p_start += buf_size)
+ {
+ p_hdr = (BUFFER_HDR_T *)p_start;
+ magic = (UINT32 *)((UINT8 *)p_hdr + buf_size - sizeof(UINT32));
+ p = (UINT16 *) p_hdr;
+
+ if (p_hdr->status != BUF_STATUS_FREE)
+ {
+ print ("%d:0x%x (Q:%d,Task:%s,Stat:%d,%s) %04x %04x %04x %04x %04x %04x %04x %04x\n",
+ i, p_hdr,
+ p_hdr->q_id,
+ GKI_map_taskname(p_hdr->task_id),
+ p_hdr->status,
+ (*magic == MAGIC_NO)? "OK" : "CORRUPTED",
+ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function gki_print_task
+**
+** Description This function prints the task states.
+**
+** Returns void
+**
+*******************************************************************************/
+void gki_print_task (FP_PRINT print)
+{
+ UINT8 i;
+
+ print("TID VID TASKNAME STATE WAIT WAITFOR TIMEOUT STACK\n");
+ print("-------------------------------------------------\n");
+ for(i=0; i<GKI_MAX_TASKS; i++)
+ {
+ if (gki_cb.com.OSRdyTbl[i] != TASK_DEAD)
+ {
+ print("%2u %-8s %-5s %04X %04X %7u %u/%u Bytes\n",
+ (UINT16)i, gki_cb.com.OSTName[i],
+ OSTaskStates[gki_cb.com.OSRdyTbl[i]],
+ gki_cb.com.OSWaitEvt[i], gki_cb.com.OSWaitForEvt[i],
+ gki_cb.com.OSWaitTmr[i], gki_calc_stack(i), gki_cb.com.OSStackSize[i]);
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function gki_print_exception
+**
+** Description This function prints the exception information.
+**
+** Returns void
+**
+*******************************************************************************/
+void gki_print_exception(FP_PRINT print)
+{
+ UINT16 i;
+ EXCEPTION_T *pExp;
+
+ print ("GKI Exceptions:\n");
+ for (i = 0; i < gki_cb.com.ExceptionCnt; i++)
+ {
+ pExp = &gki_cb.com.Exception[i];
+ print("%d: Type=%d, Task=%d: %s\n", i,
+ (INT32)pExp->type, (INT32)pExp->taskid, (INT8 *)pExp->msg);
+ }
+}
+
+
+/*****************************************************************************/
+void gki_dump (UINT8 *s, UINT16 len, FP_PRINT print)
+{
+ UINT16 i, j;
+
+ for(i=0, j=0; i<len; i++)
+ {
+ if(j == 0)
+ print("\n%lX: %02X, ", &s[i], s[i]);
+ else if(j == 7)
+ print("%02X, ", s[i]);
+ else
+ print("%02X, ", s[i]);
+ if(++j == 16)
+ j=0;
+ }
+ print("\n");
+}
+
+void gki_dump2 (UINT16 *s, UINT16 len, FP_PRINT print)
+{
+ UINT16 i, j;
+
+ for(i=0, j=0; i<len; i++)
+ {
+ if(j == 0)
+ print("\n%lX: %04X, ", &s[i], s[i]);
+ else
+ print("%04X, ", s[i]);
+ if(++j == 8)
+ j=0;
+ }
+ print("\n");
+}
+
+void gki_dump4 (UINT32 *s, UINT16 len, FP_PRINT print)
+{
+ UINT16 i, j;
+
+ for(i=0, j=0; i<len; i++)
+ {
+ if(j == 0)
+ print("\n%lX: %08lX, ", &s[i], s[i]);
+ else
+ print("%08lX, ", s[i]);
+ if(++j == 4)
+ j=0;
+ }
+ print("\n");
+}
+
+
+#endif
diff --git a/gki/common/gki_inet.h b/gki/common/gki_inet.h
new file mode 100644
index 0000000..780e9a0
--- /dev/null
+++ b/gki/common/gki_inet.h
@@ -0,0 +1,42 @@
+/****************************************************************************
+**
+** Name gki_inet.h
+**
+** Function This file contains macros and interfaces for host-to-network
+** conversions used in Internet operations.
+**
+**
+** Copyright (c) 2002-2004, WIDCOMM Inc., All Rights Reserved.
+** Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef GKI_INET_H
+#define GKI_INET_H
+
+#include "data_types.h"
+
+#define htons ntohs
+#define htonl ntohl
+
+#define htonets nettohs
+#define htonetl nettohl
+
+#if BIG_ENDIAN == TRUE
+#define ntohs(n) (n)
+#define ntohl(n) (n)
+#define ntoh6(n) (n)
+
+#define nettohs(n) (n)
+#define nettohl(n) (n)
+#else
+extern UINT16 ntohs(UINT16 n);
+extern UINT32 ntohl(UINT32 n);
+extern UINT8 *ntoh6(UINT8 *p);
+
+#define nettohs(n) ((UINT16)((((n) << 8) & 0xff00) | (((n) >> 8) & 0x00ff)))
+#define nettohl(n) ((((n) & 0x000000ff) << 24) | (((n) << 8) & 0x00ff0000) | \
+ (((n) >> 8) & 0x0000ff00) | (((n) >> 24) & 0x000000ff))
+#endif
+
+#endif /* GKI_INET_H */
+
diff --git a/gki/common/gki_time.c b/gki/common/gki_time.c
new file mode 100644
index 0000000..8121654
--- /dev/null
+++ b/gki/common/gki_time.c
@@ -0,0 +1,1016 @@
+
+/****************************************************************************
+**
+** Name GKI_time.c
+**
+** Function this file contains GKI time related functions
+**
+** Copyright (c) 1999-2011, Broadcom Corp., All Rights Reserved.
+** Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "gki_int.h"
+
+#ifndef BT_ERROR_TRACE_0
+#define BT_ERROR_TRACE_0(l,m)
+#endif
+
+/* Make sure that this has been defined in target.h */
+#ifndef GKI_NUM_TIMERS
+#error NO TIMERS: Must define at least 1 timer in the system!
+#endif
+
+
+#define GKI_NO_NEW_TMRS_STARTED (0x7fffffffL) /* Largest signed positive timer count */
+#define GKI_UNUSED_LIST_ENTRY (0x80000000L) /* Marks an unused timer list entry (initial value) */
+#define GKI_MAX_INT32 (0x7fffffffL)
+
+/*******************************************************************************
+**
+** Function gki_timers_init
+**
+** Description This internal function is called once at startup to initialize
+** all the timer structures.
+**
+** Returns void
+**
+*******************************************************************************/
+void gki_timers_init(void)
+{
+ UINT8 tt;
+
+ gki_cb.com.OSTicksTilExp = 0; /* Remaining time (of OSTimeCurTimeout) before next timer expires */
+ gki_cb.com.OSNumOrigTicks = 0;
+#if (defined(GKI_DELAY_STOP_SYS_TICK) && (GKI_DELAY_STOP_SYS_TICK > 0))
+ gki_cb.com.OSTicksTilStop = 0; /* clear inactivity delay timer */
+#endif
+
+ for (tt = 0; tt < GKI_MAX_TASKS; tt++)
+ {
+ gki_cb.com.OSWaitTmr [tt] = 0;
+
+#if (GKI_NUM_TIMERS > 0)
+ gki_cb.com.OSTaskTmr0 [tt] = 0;
+ gki_cb.com.OSTaskTmr0R [tt] = 0;
+#endif
+
+#if (GKI_NUM_TIMERS > 1)
+ gki_cb.com.OSTaskTmr1 [tt] = 0;
+ gki_cb.com.OSTaskTmr1R [tt] = 0;
+#endif
+
+#if (GKI_NUM_TIMERS > 2)
+ gki_cb.com.OSTaskTmr2 [tt] = 0;
+ gki_cb.com.OSTaskTmr2R [tt] = 0;
+#endif
+
+#if (GKI_NUM_TIMERS > 3)
+ gki_cb.com.OSTaskTmr3 [tt] = 0;
+ gki_cb.com.OSTaskTmr3R [tt] = 0;
+#endif
+ }
+
+ for (tt = 0; tt < GKI_MAX_TIMER_QUEUES; tt++)
+ {
+ gki_cb.com.timer_queues[tt] = NULL;
+ }
+
+ gki_cb.com.p_tick_cb = NULL;
+ gki_cb.com.system_tick_running = FALSE;
+
+ return;
+}
+
+/*******************************************************************************
+**
+** Function gki_timers_is_timer_running
+**
+** Description This internal function is called to test if any gki timer are running
+**
+**
+** Returns TRUE if at least one time is running in the system, FALSE else.
+**
+*******************************************************************************/
+BOOLEAN gki_timers_is_timer_running(void)
+{
+ UINT8 tt;
+ for (tt = 0; tt < GKI_MAX_TASKS; tt++)
+ {
+
+#if (GKI_NUM_TIMERS > 0)
+ if(gki_cb.com.OSTaskTmr0 [tt])
+ {
+ return TRUE;
+ }
+#endif
+
+#if (GKI_NUM_TIMERS > 1)
+ if(gki_cb.com.OSTaskTmr1 [tt] )
+ {
+ return TRUE;
+ }
+#endif
+
+#if (GKI_NUM_TIMERS > 2)
+ if(gki_cb.com.OSTaskTmr2 [tt] )
+ {
+ return TRUE;
+ }
+#endif
+
+#if (GKI_NUM_TIMERS > 3)
+ if(gki_cb.com.OSTaskTmr3 [tt] )
+ {
+ return TRUE;
+ }
+#endif
+ }
+
+ return FALSE;
+
+}
+
+/*******************************************************************************
+**
+** Function GKI_get_tick_count
+**
+** Description This function returns the current system ticks
+**
+** Returns The current number of system ticks
+**
+*******************************************************************************/
+UINT32 GKI_get_tick_count(void)
+{
+ return gki_cb.com.OSTicks;
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_ready_to_sleep
+**
+** Description This function returns the number of system ticks until the
+** next timer will expire. It is typically called by a power
+** savings manager to find out how long it can have the system
+** sleep before it needs to service the next entry.
+**
+** Parameters: None
+**
+** Returns Number of ticks til the next timer expires
+** Note: the value is a signed value. This value should be
+** compared to x > 0, to avoid misinterpreting negative tick
+** values.
+**
+*******************************************************************************/
+INT32 GKI_ready_to_sleep (void)
+{
+ return (gki_cb.com.OSTicksTilExp);
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_start_timer
+**
+** Description An application can call this function to start one of
+** it's four general purpose timers. Any of the four timers
+** can be 1-shot or continuous. If a timer is already running,
+** it will be reset to the new parameters.
+**
+** Parameters tnum - (input) timer number to be started (TIMER_0,
+** TIMER_1, TIMER_2, or TIMER_3)
+** ticks - (input) the number of system ticks til the
+** timer expires.
+** is_continuous - (input) TRUE if timer restarts automatically,
+** else FALSE if it is a 'one-shot'.
+**
+** Returns void
+**
+*******************************************************************************/
+void GKI_start_timer (UINT8 tnum, INT32 ticks, BOOLEAN is_continuous)
+{
+ INT32 reload;
+ INT32 orig_ticks;
+ UINT8 task_id = GKI_get_taskid();
+ BOOLEAN bad_timer = FALSE;
+
+ if (ticks <= 0)
+ ticks = 1;
+
+ orig_ticks = ticks; /* save the ticks in case adjustment is necessary */
+
+
+ /* If continuous timer, set reload, else set it to 0 */
+ if (is_continuous)
+ reload = ticks;
+ else
+ reload = 0;
+
+ GKI_disable();
+
+ if(gki_timers_is_timer_running() == FALSE)
+ {
+#if (defined(GKI_DELAY_STOP_SYS_TICK) && (GKI_DELAY_STOP_SYS_TICK > 0))
+ /* if inactivity delay timer is not running, start system tick */
+ if(gki_cb.com.OSTicksTilStop == 0)
+ {
+#endif
+ if(gki_cb.com.p_tick_cb)
+ {
+ /* start system tick */
+ gki_cb.com.system_tick_running = TRUE;
+ (gki_cb.com.p_tick_cb) (TRUE);
+ }
+#if (defined(GKI_DELAY_STOP_SYS_TICK) && (GKI_DELAY_STOP_SYS_TICK > 0))
+ }
+ else
+ {
+ /* clear inactivity delay timer */
+ gki_cb.com.OSTicksTilStop = 0;
+ }
+#endif
+ }
+ /* Add the time since the last task timer update.
+ ** Note that this works when no timers are active since
+ ** both OSNumOrigTicks and OSTicksTilExp are 0.
+ */
+ if (GKI_MAX_INT32 - (gki_cb.com.OSNumOrigTicks - gki_cb.com.OSTicksTilExp) > ticks)
+ {
+ ticks += gki_cb.com.OSNumOrigTicks - gki_cb.com.OSTicksTilExp;
+ }
+ else
+ ticks = GKI_MAX_INT32;
+
+ switch (tnum)
+ {
+#if (GKI_NUM_TIMERS > 0)
+ case TIMER_0:
+ gki_cb.com.OSTaskTmr0R[task_id] = reload;
+ gki_cb.com.OSTaskTmr0 [task_id] = ticks;
+ break;
+#endif
+
+#if (GKI_NUM_TIMERS > 1)
+ case TIMER_1:
+ gki_cb.com.OSTaskTmr1R[task_id] = reload;
+ gki_cb.com.OSTaskTmr1 [task_id] = ticks;
+ break;
+#endif
+
+#if (GKI_NUM_TIMERS > 2)
+ case TIMER_2:
+ gki_cb.com.OSTaskTmr2R[task_id] = reload;
+ gki_cb.com.OSTaskTmr2 [task_id] = ticks;
+ break;
+#endif
+
+#if (GKI_NUM_TIMERS > 3)
+ case TIMER_3:
+ gki_cb.com.OSTaskTmr3R[task_id] = reload;
+ gki_cb.com.OSTaskTmr3 [task_id] = ticks;
+ break;
+#endif
+ default:
+ bad_timer = TRUE; /* Timer number is bad, so do not use */
+ }
+
+ /* Update the expiration timeout if a legitimate timer */
+ if (!bad_timer)
+ {
+ /* Only update the timeout value if it is less than any other newly started timers */
+ gki_adjust_timer_count (orig_ticks);
+ }
+
+ GKI_enable();
+
+}
+
+/*******************************************************************************
+**
+** Function GKI_stop_timer
+**
+** Description An application can call this function to stop one of
+** it's four general purpose timers. There is no harm in
+** stopping a timer that is already stopped.
+**
+** Parameters tnum - (input) timer number to be started (TIMER_0,
+** TIMER_1, TIMER_2, or TIMER_3)
+** Returns void
+**
+*******************************************************************************/
+void GKI_stop_timer (UINT8 tnum)
+{
+ UINT8 task_id = GKI_get_taskid();
+
+ switch (tnum)
+ {
+#if (GKI_NUM_TIMERS > 0)
+ case TIMER_0:
+ gki_cb.com.OSTaskTmr0R[task_id] = 0;
+ gki_cb.com.OSTaskTmr0 [task_id] = 0;
+ break;
+#endif
+
+#if (GKI_NUM_TIMERS > 1)
+ case TIMER_1:
+ gki_cb.com.OSTaskTmr1R[task_id] = 0;
+ gki_cb.com.OSTaskTmr1 [task_id] = 0;
+ break;
+#endif
+
+#if (GKI_NUM_TIMERS > 2)
+ case TIMER_2:
+ gki_cb.com.OSTaskTmr2R[task_id] = 0;
+ gki_cb.com.OSTaskTmr2 [task_id] = 0;
+ break;
+#endif
+
+#if (GKI_NUM_TIMERS > 3)
+ case TIMER_3:
+ gki_cb.com.OSTaskTmr3R[task_id] = 0;
+ gki_cb.com.OSTaskTmr3 [task_id] = 0;
+ break;
+#endif
+ }
+
+ GKI_disable();
+
+ if (gki_timers_is_timer_running() == FALSE)
+ {
+ if (gki_cb.com.p_tick_cb)
+ {
+#if (defined(GKI_DELAY_STOP_SYS_TICK) && (GKI_DELAY_STOP_SYS_TICK > 0))
+ /* if inactivity delay timer is not running */
+ if ((gki_cb.com.system_tick_running)&&(gki_cb.com.OSTicksTilStop == 0))
+ {
+ /* set inactivity delay timer */
+ /* when timer expires, system tick will be stopped */
+ gki_cb.com.OSTicksTilStop = GKI_DELAY_STOP_SYS_TICK;
+ }
+#else
+ gki_cb.com.system_tick_running = FALSE;
+ gki_cb.com.p_tick_cb(FALSE); /* stop system tick */
+#endif
+ }
+ }
+
+ GKI_enable();
+
+
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_timer_update
+**
+** Description This function is called by an OS to drive the GKI's timers.
+** It is typically called at every system tick to
+** update the timers for all tasks, and check for timeouts.
+**
+** Note: It has been designed to also allow for variable tick updates
+** so that systems with strict power savings requirements can
+** have the update occur at variable intervals.
+**
+** Parameters: ticks_since_last_update - (input) This is the number of TICKS that have
+** occurred since the last time GKI_timer_update was called.
+**
+** Returns void
+**
+*******************************************************************************/
+void GKI_timer_update (INT32 ticks_since_last_update)
+{
+ UINT8 task_id;
+ long next_expiration; /* Holds the next soonest expiration time after this update */
+
+ /* Increment the number of ticks used for time stamps */
+ gki_cb.com.OSTicks += ticks_since_last_update;
+
+ /* If any timers are running in any tasks, decrement the remaining time til
+ * the timer updates need to take place (next expiration occurs)
+ */
+ gki_cb.com.OSTicksTilExp -= ticks_since_last_update;
+
+ /* Don't allow timer interrupt nesting */
+ if (gki_cb.com.timer_nesting)
+ return;
+
+ gki_cb.com.timer_nesting = 1;
+
+#if (defined(GKI_DELAY_STOP_SYS_TICK) && (GKI_DELAY_STOP_SYS_TICK > 0))
+ /* if inactivity delay timer is set and expired */
+ if (gki_cb.com.OSTicksTilStop)
+ {
+ if( gki_cb.com.OSTicksTilStop <= (UINT32)ticks_since_last_update )
+ {
+ if(gki_cb.com.p_tick_cb)
+ {
+ gki_cb.com.system_tick_running = FALSE;
+ (gki_cb.com.p_tick_cb) (FALSE); /* stop system tick */
+ }
+ gki_cb.com.OSTicksTilStop = 0; /* clear inactivity delay timer */
+ gki_cb.com.timer_nesting = 0;
+ return;
+ }
+ else
+ gki_cb.com.OSTicksTilStop -= ticks_since_last_update;
+ }
+#endif
+
+ /* No need to update the ticks if no timeout has occurred */
+ if (gki_cb.com.OSTicksTilExp > 0)
+ {
+ gki_cb.com.timer_nesting = 0;
+ return;
+ }
+
+ next_expiration = GKI_NO_NEW_TMRS_STARTED;
+
+ /* If here then gki_cb.com.OSTicksTilExp <= 0. If negative, then increase gki_cb.com.OSNumOrigTicks
+ to account for the difference so timer updates below are decremented by the full number
+ of ticks. gki_cb.com.OSNumOrigTicks is reset at the bottom of this function so changing this
+ value only affects the timer updates below
+ */
+ gki_cb.com.OSNumOrigTicks -= gki_cb.com.OSTicksTilExp;
+
+#if GKI_TIMER_LIST_NOPREEMPT == TRUE
+ /* Protect this section because if a GKI_timer_stop happens between:
+ * - gki_cb.com.OSTaskTmr0[task_id] -= gki_cb.com.OSNumOrigTicks;
+ * - gki_cb.com.OSTaskTmr0[task_id] = gki_cb.com.OSTaskTmr0R[task_id];
+ * then the timer may appear stopped while it is about to be reloaded.
+ * Note: Not needed if this function cannot be preempted (typical).
+ */
+ GKI_disable();
+#endif
+
+ /* Check for OS Task Timers */
+ for (task_id = 0; task_id < GKI_MAX_TASKS; task_id++)
+ {
+ if (gki_cb.com.OSWaitTmr[task_id] > 0) /* If timer is running */
+ {
+ gki_cb.com.OSWaitTmr[task_id] -= gki_cb.com.OSNumOrigTicks;
+ if (gki_cb.com.OSWaitTmr[task_id] <= 0)
+ {
+ /* Timer Expired */
+ gki_cb.com.OSRdyTbl[task_id] = TASK_READY;
+ }
+ }
+
+#if (GKI_NUM_TIMERS > 0)
+ /* If any timer is running, decrement */
+ if (gki_cb.com.OSTaskTmr0[task_id] > 0)
+ {
+ gki_cb.com.OSTaskTmr0[task_id] -= gki_cb.com.OSNumOrigTicks;
+
+ if (gki_cb.com.OSTaskTmr0[task_id] <= 0)
+ {
+ /* Reload timer and set Timer 0 Expired event mask */
+ gki_cb.com.OSTaskTmr0[task_id] = gki_cb.com.OSTaskTmr0R[task_id];
+
+#if (defined(GKI_TIMER_UPDATES_FROM_ISR) && GKI_TIMER_UPDATES_FROM_ISR == TRUE)
+ GKI_isend_event (task_id, TIMER_0_EVT_MASK);
+#else
+ GKI_send_event (task_id, TIMER_0_EVT_MASK);
+#endif
+ }
+ }
+
+ /* Check to see if this timer is the next one to expire */
+ if (gki_cb.com.OSTaskTmr0[task_id] > 0 && gki_cb.com.OSTaskTmr0[task_id] < next_expiration)
+ next_expiration = gki_cb.com.OSTaskTmr0[task_id];
+#endif
+
+#if (GKI_NUM_TIMERS > 1)
+ /* If any timer is running, decrement */
+ if (gki_cb.com.OSTaskTmr1[task_id] > 0)
+ {
+ gki_cb.com.OSTaskTmr1[task_id] -= gki_cb.com.OSNumOrigTicks;
+
+ if (gki_cb.com.OSTaskTmr1[task_id] <= 0)
+ {
+ /* Reload timer and set Timer 1 Expired event mask */
+ gki_cb.com.OSTaskTmr1[task_id] = gki_cb.com.OSTaskTmr1R[task_id];
+
+#if (defined(GKI_TIMER_UPDATES_FROM_ISR) && GKI_TIMER_UPDATES_FROM_ISR == TRUE)
+ GKI_isend_event (task_id, TIMER_1_EVT_MASK);
+#else
+ GKI_send_event (task_id, TIMER_1_EVT_MASK);
+#endif
+ }
+ }
+
+ /* Check to see if this timer is the next one to expire */
+ if (gki_cb.com.OSTaskTmr1[task_id] > 0 && gki_cb.com.OSTaskTmr1[task_id] < next_expiration)
+ next_expiration = gki_cb.com.OSTaskTmr1[task_id];
+#endif
+
+#if (GKI_NUM_TIMERS > 2)
+ /* If any timer is running, decrement */
+ if (gki_cb.com.OSTaskTmr2[task_id] > 0)
+ {
+ gki_cb.com.OSTaskTmr2[task_id] -= gki_cb.com.OSNumOrigTicks;
+
+ if (gki_cb.com.OSTaskTmr2[task_id] <= 0)
+ {
+ /* Reload timer and set Timer 2 Expired event mask */
+ gki_cb.com.OSTaskTmr2[task_id] = gki_cb.com.OSTaskTmr2R[task_id];
+
+#if (defined(GKI_TIMER_UPDATES_FROM_ISR) && GKI_TIMER_UPDATES_FROM_ISR == TRUE)
+ GKI_isend_event (task_id, TIMER_2_EVT_MASK);
+#else
+ GKI_send_event (task_id, TIMER_2_EVT_MASK);
+#endif
+ }
+ }
+
+ /* Check to see if this timer is the next one to expire */
+ if (gki_cb.com.OSTaskTmr2[task_id] > 0 && gki_cb.com.OSTaskTmr2[task_id] < next_expiration)
+ next_expiration = gki_cb.com.OSTaskTmr2[task_id];
+#endif
+
+#if (GKI_NUM_TIMERS > 3)
+ /* If any timer is running, decrement */
+ if (gki_cb.com.OSTaskTmr3[task_id] > 0)
+ {
+ gki_cb.com.OSTaskTmr3[task_id] -= gki_cb.com.OSNumOrigTicks;
+
+ if (gki_cb.com.OSTaskTmr3[task_id] <= 0)
+ {
+ /* Reload timer and set Timer 3 Expired event mask */
+ gki_cb.com.OSTaskTmr3[task_id] = gki_cb.com.OSTaskTmr3R[task_id];
+
+#if (defined(GKI_TIMER_UPDATES_FROM_ISR) && GKI_TIMER_UPDATES_FROM_ISR == TRUE)
+ GKI_isend_event (task_id, TIMER_3_EVT_MASK);
+#else
+ GKI_send_event (task_id, TIMER_3_EVT_MASK);
+#endif
+ }
+ }
+
+ /* Check to see if this timer is the next one to expire */
+ if (gki_cb.com.OSTaskTmr3[task_id] > 0 && gki_cb.com.OSTaskTmr3[task_id] < next_expiration)
+ next_expiration = gki_cb.com.OSTaskTmr3[task_id];
+#endif
+
+ }
+
+#if GKI_TIMER_LIST_NOPREEMPT == TRUE
+ /* End the critical section */
+ GKI_enable();
+#endif
+
+ /* Set the next timer experation value if there is one to start */
+ if (next_expiration < GKI_NO_NEW_TMRS_STARTED)
+ {
+ gki_cb.com.OSTicksTilExp = gki_cb.com.OSNumOrigTicks = next_expiration;
+ }
+ else
+ {
+ gki_cb.com.OSTicksTilExp = gki_cb.com.OSNumOrigTicks = 0;
+ }
+
+ gki_cb.com.timer_nesting = 0;
+
+ return;
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_timer_queue_empty
+**
+** Description This function is called by applications to see whether the timer
+** queue is empty
+**
+** Parameters
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+BOOLEAN GKI_timer_queue_empty (void)
+{
+ UINT8 tt;
+
+ for (tt = 0; tt < GKI_MAX_TIMER_QUEUES; tt++)
+ {
+ if (gki_cb.com.timer_queues[tt])
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*******************************************************************************
+**
+** Function GKI_timer_queue_register_callback
+**
+** Description This function is called by applications to register system tick
+** start/stop callback for time queues
+**
+**
+** Parameters p_callback - (input) pointer to the system tick callback
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+void GKI_timer_queue_register_callback (SYSTEM_TICK_CBACK *p_callback)
+{
+ gki_cb.com.p_tick_cb = p_callback;
+
+ return;
+}
+
+/*******************************************************************************
+**
+** Function GKI_init_timer_list
+**
+** Description This function is called by applications when they
+** want to initialize a timer list.
+**
+** Parameters p_timer_listq - (input) pointer to the timer list queue object
+**
+** Returns void
+**
+*******************************************************************************/
+void GKI_init_timer_list (TIMER_LIST_Q *p_timer_listq)
+{
+ p_timer_listq->p_first = NULL;
+ p_timer_listq->p_last = NULL;
+ p_timer_listq->last_ticks = 0;
+
+ return;
+}
+
+/*******************************************************************************
+**
+** Function GKI_init_timer_list_entry
+**
+** Description This function is called by the applications when they
+** want to initialize a timer list entry. This must be
+** done prior to first use of the entry.
+**
+** Parameters p_tle - (input) pointer to a timer list queue entry
+**
+** Returns void
+**
+*******************************************************************************/
+void GKI_init_timer_list_entry (TIMER_LIST_ENT *p_tle)
+{
+ p_tle->p_next = NULL;
+ p_tle->p_prev = NULL;
+ p_tle->ticks = GKI_UNUSED_LIST_ENTRY;
+ p_tle->in_use = FALSE;
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_update_timer_list
+**
+** Description This function is called by the applications when they
+** want to update a timer list. This should be at every
+** timer list unit tick, e.g. once per sec, once per minute etc.
+**
+** Parameters p_timer_listq - (input) pointer to the timer list queue object
+** num_units_since_last_update - (input) number of units since the last update
+** (allows for variable unit update)
+**
+** NOTE: The following timer list update routines should not be used for exact time
+** critical purposes. The timer tasks should be used when exact timing is needed.
+**
+** Returns the number of timers that have expired
+**
+*******************************************************************************/
+UINT16 GKI_update_timer_list (TIMER_LIST_Q *p_timer_listq, INT32 num_units_since_last_update)
+{
+ TIMER_LIST_ENT *p_tle;
+ UINT16 num_time_out = 0;
+ INT32 rem_ticks;
+ INT32 temp_ticks;
+
+ p_tle = p_timer_listq->p_first;
+
+ /* First, get the guys who have previously timed out */
+ /* Note that the tick value of the timers should always be '0' */
+ while ((p_tle) && (p_tle->ticks <= 0))
+ {
+ num_time_out++;
+ p_tle = p_tle->p_next;
+ }
+
+ /* Timer entriy tick values are relative to the preceeding entry */
+ rem_ticks = num_units_since_last_update;
+
+ /* Now, adjust remaining timer entries */
+ while ((p_tle != NULL) && (rem_ticks > 0))
+ {
+ temp_ticks = p_tle->ticks;
+ p_tle->ticks -= rem_ticks;
+
+ /* See if this timer has just timed out */
+ if (p_tle->ticks <= 0)
+ {
+ /* We set the number of ticks to '0' so that the legacy code
+ * that assumes a '0' or nonzero value will still work as coded. */
+ p_tle->ticks = 0;
+
+ num_time_out++;
+ }
+
+ rem_ticks -= temp_ticks; /* Decrement the remaining ticks to process */
+ p_tle = p_tle->p_next;
+ }
+
+ if (p_timer_listq->last_ticks > 0)
+ {
+ p_timer_listq->last_ticks -= num_units_since_last_update;
+
+ /* If the last timer has expired set last_ticks to 0 so that other list update
+ * functions will calculate correctly
+ */
+ if (p_timer_listq->last_ticks < 0)
+ p_timer_listq->last_ticks = 0;
+ }
+
+ return (num_time_out);
+}
+
+/*******************************************************************************
+**
+** Function GKI_get_remaining_ticks
+**
+** Description This function is called by an application to get remaining
+** ticks to expire
+**
+** Parameters p_timer_listq - (input) pointer to the timer list queue object
+** p_target_tle - (input) pointer to a timer list queue entry
+**
+** Returns 0 if timer is not used or timer is not in the list
+** remaining ticks if success
+**
+*******************************************************************************/
+UINT32 GKI_get_remaining_ticks (TIMER_LIST_Q *p_timer_listq, TIMER_LIST_ENT *p_target_tle)
+{
+ TIMER_LIST_ENT *p_tle;
+ UINT32 rem_ticks = 0;
+
+ if (p_target_tle->in_use)
+ {
+ p_tle = p_timer_listq->p_first;
+
+ /* adding up all of ticks in previous entries */
+ while ((p_tle)&&(p_tle != p_target_tle))
+ {
+ rem_ticks += p_tle->ticks;
+ p_tle = p_tle->p_next;
+ }
+
+ /* if found target entry */
+ if (p_tle == p_target_tle)
+ {
+ rem_ticks += p_tle->ticks;
+ }
+ else
+ {
+ BT_ERROR_TRACE_0(TRACE_LAYER_GKI, "GKI_get_remaining_ticks: No timer entry in the list");
+ return(0);
+ }
+ }
+ else
+ {
+ BT_ERROR_TRACE_0(TRACE_LAYER_GKI, "GKI_get_remaining_ticks: timer entry is not active");
+ }
+
+ return (rem_ticks);
+}
+
+/*******************************************************************************
+**
+** Function GKI_add_to_timer_list
+**
+** Description This function is called by an application to add a timer
+** entry to a timer list.
+**
+** Note: A timer value of '0' will effectively insert an already
+** expired event. Negative tick values will be ignored.
+**
+** Parameters p_timer_listq - (input) pointer to the timer list queue object
+** p_tle - (input) pointer to a timer list queue entry
+**
+** Returns void
+**
+*******************************************************************************/
+void GKI_add_to_timer_list (TIMER_LIST_Q *p_timer_listq, TIMER_LIST_ENT *p_tle)
+{
+ UINT32 nr_ticks_total;
+ UINT8 tt;
+ TIMER_LIST_ENT *p_temp;
+
+ /* Only process valid tick values */
+ if (p_tle->ticks >= 0)
+ {
+ /* If this entry is the last in the list */
+ if (p_tle->ticks >= p_timer_listq->last_ticks)
+ {
+ /* If this entry is the only entry in the list */
+ if (p_timer_listq->p_first == NULL)
+ p_timer_listq->p_first = p_tle;
+ else
+ {
+ /* Insert the entry onto the end of the list */
+ if (p_timer_listq->p_last != NULL)
+ p_timer_listq->p_last->p_next = p_tle;
+
+ p_tle->p_prev = p_timer_listq->p_last;
+ }
+
+ p_tle->p_next = NULL;
+ p_timer_listq->p_last = p_tle;
+ nr_ticks_total = p_tle->ticks;
+ p_tle->ticks -= p_timer_listq->last_ticks;
+
+ p_timer_listq->last_ticks = nr_ticks_total;
+ }
+ else /* This entry needs to be inserted before the last entry */
+ {
+ /* Find the entry that the new one needs to be inserted in front of */
+ p_temp = p_timer_listq->p_first;
+ while (p_tle->ticks > p_temp->ticks)
+ {
+ /* Update the tick value if looking at an unexpired entry */
+ if (p_temp->ticks > 0)
+ p_tle->ticks -= p_temp->ticks;
+
+ p_temp = p_temp->p_next;
+ }
+
+ /* The new entry is the first in the list */
+ if (p_temp == p_timer_listq->p_first)
+ {
+ p_tle->p_next = p_timer_listq->p_first;
+ p_timer_listq->p_first->p_prev = p_tle;
+ p_timer_listq->p_first = p_tle;
+ }
+ else
+ {
+ p_temp->p_prev->p_next = p_tle;
+ p_tle->p_prev = p_temp->p_prev;
+ p_temp->p_prev = p_tle;
+ p_tle->p_next = p_temp;
+ }
+ p_temp->ticks -= p_tle->ticks;
+ }
+
+ p_tle->in_use = TRUE;
+
+ /* if we already add this timer queue to the array */
+ for (tt = 0; tt < GKI_MAX_TIMER_QUEUES; tt++)
+ {
+ if (gki_cb.com.timer_queues[tt] == p_timer_listq)
+ return;
+ }
+ /* add this timer queue to the array */
+ for (tt = 0; tt < GKI_MAX_TIMER_QUEUES; tt++)
+ {
+ if (gki_cb.com.timer_queues[tt] == NULL)
+ break;
+ }
+ if (tt < GKI_MAX_TIMER_QUEUES)
+ {
+ gki_cb.com.timer_queues[tt] = p_timer_listq;
+ }
+ }
+
+ return;
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_remove_from_timer_list
+**
+** Description This function is called by an application to remove a timer
+** entry from a timer list.
+**
+** Parameters p_timer_listq - (input) pointer to the timer list queue object
+** p_tle - (input) pointer to a timer list queue entry
+**
+** Returns void
+**
+*******************************************************************************/
+void GKI_remove_from_timer_list (TIMER_LIST_Q *p_timer_listq, TIMER_LIST_ENT *p_tle)
+{
+ UINT8 tt;
+
+ /* Verify that the entry is valid */
+ if (p_tle == NULL || p_tle->in_use == FALSE || p_timer_listq->p_first == NULL)
+ {
+ return;
+ }
+
+ /* Add the ticks remaining in this timer (if any) to the next guy in the list.
+ ** Note: Expired timers have a tick value of '0'.
+ */
+ if (p_tle->p_next != NULL)
+ {
+ p_tle->p_next->ticks += p_tle->ticks;
+ }
+ else
+ {
+ p_timer_listq->last_ticks -= p_tle->ticks;
+ }
+
+ /* Unlink timer from the list.
+ */
+ if (p_timer_listq->p_first == p_tle)
+ {
+ p_timer_listq->p_first = p_tle->p_next;
+
+ if (p_timer_listq->p_first != NULL)
+ p_timer_listq->p_first->p_prev = NULL;
+
+ if (p_timer_listq->p_last == p_tle)
+ p_timer_listq->p_last = NULL;
+ }
+ else
+ {
+ if (p_timer_listq->p_last == p_tle)
+ {
+ p_timer_listq->p_last = p_tle->p_prev;
+
+ if (p_timer_listq->p_last != NULL)
+ p_timer_listq->p_last->p_next = NULL;
+ }
+ else
+ {
+ if (p_tle->p_next != NULL && p_tle->p_next->p_prev == p_tle)
+ p_tle->p_next->p_prev = p_tle->p_prev;
+ else
+ {
+ /* Error case - chain messed up ?? */
+ return;
+ }
+
+ if (p_tle->p_prev != NULL && p_tle->p_prev->p_next == p_tle)
+ p_tle->p_prev->p_next = p_tle->p_next;
+ else
+ {
+ /* Error case - chain messed up ?? */
+ return;
+ }
+ }
+ }
+
+ p_tle->p_next = p_tle->p_prev = NULL;
+ p_tle->ticks = GKI_UNUSED_LIST_ENTRY;
+ p_tle->in_use = FALSE;
+
+ /* if timer queue is empty */
+ if (p_timer_listq->p_first == NULL && p_timer_listq->p_last == NULL)
+ {
+ for (tt = 0; tt < GKI_MAX_TIMER_QUEUES; tt++)
+ {
+ if (gki_cb.com.timer_queues[tt] == p_timer_listq)
+ {
+ gki_cb.com.timer_queues[tt] = NULL;
+ break;
+ }
+ }
+ }
+
+ return;
+}
+
+
+/*******************************************************************************
+**
+** Function gki_adjust_timer_count
+**
+** Description This function is called whenever a new timer or GKI_wait occurs
+** to adjust (if necessary) the current time til the first expiration.
+** This only needs to make an adjustment if the new timer (in ticks) is
+** less than the number of ticks remaining on the current timer.
+**
+** Parameters: ticks - (input) number of system ticks of the new timer entry
+**
+** NOTE: This routine MUST be called while interrupts are disabled to
+** avoid updates while adjusting the timer variables.
+**
+** Returns void
+**
+*******************************************************************************/
+void gki_adjust_timer_count (INT32 ticks)
+{
+ if (ticks > 0)
+ {
+ /* See if the new timer expires before the current first expiration */
+ if (gki_cb.com.OSNumOrigTicks == 0 || (ticks < gki_cb.com.OSTicksTilExp && gki_cb.com.OSTicksTilExp > 0))
+ {
+ gki_cb.com.OSNumOrigTicks = (gki_cb.com.OSNumOrigTicks - gki_cb.com.OSTicksTilExp) + ticks;
+ gki_cb.com.OSTicksTilExp = ticks;
+ }
+ }
+
+ return;
+}
diff --git a/gki/ulinux/data_types.h b/gki/ulinux/data_types.h
new file mode 100644
index 0000000..5263bba
--- /dev/null
+++ b/gki/ulinux/data_types.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Name data_types.h
+** $Header: /Bluetooth/gki/data_types.h 7 9/13/00 11:01a Jjose $
+**
+** Function this file contains common data type definitions used
+** throughout the Widcomm Bluetooth code
+**
+** Date Modification
+** -----------------------
+** 3/12/99 Create
+** 07/27/00 Added nettohs macro for Little Endian
+**
+** Copyright (c) 1999- 2002, Widcomm Inc., All Rights Reserved.
+** Proprietary and confidential.
+**
+*****************************************************************************/
+
+#ifndef DATA_TYPES_H
+#define DATA_TYPES_H
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+typedef unsigned char UINT8;
+typedef unsigned short UINT16;
+typedef unsigned long UINT32;
+typedef signed long INT32;
+typedef signed char INT8;
+typedef signed short INT16;
+typedef unsigned char BOOLEAN;
+
+
+typedef UINT32 TIME_STAMP;
+
+#ifndef TRUE
+#define TRUE (!FALSE)
+#endif
+
+typedef unsigned char UBYTE;
+
+#ifdef __arm
+#define PACKED __packed
+#define INLINE __inline
+#else
+#define PACKED
+#define INLINE
+#endif
+
+#ifndef BIG_ENDIAN
+#define BIG_ENDIAN FALSE
+#endif
+
+#define UINT16_LOW_BYTE(x) ((x) & 0xff)
+#define UINT16_HI_BYTE(x) ((x) >> 8)
+
+
+#define BCM_STRCAT_S(x1,x2,x3) strcat((x1),(x3))
+#define BCM_STRNCAT_S(x1,x2,x3,x4) strncat((x1),(x3),(x4))
+#define BCM_STRCPY_S(x1,x2,x3) strcpy((x1),(x3))
+#define BCM_STRNCPY_S(x1,x2,x3,x4) strncpy((x1),(x3),(x4))
+
+
+
+#endif
+
diff --git a/gki/ulinux/gki_int.h b/gki/ulinux/gki_int.h
new file mode 100644
index 0000000..4aaf500
--- /dev/null
+++ b/gki/ulinux/gki_int.h
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Name gki_int.h
+**
+** Function This file contains GKI private definitions
+**
+**
+** Copyright (c) 1999-2010, Widcomm Inc., All Rights Reserved.
+** Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef GKI_INT_H
+#define GKI_INT_H
+
+#include "gki_common.h"
+#include <pthread.h>
+#include <sys/prctl.h>
+
+/**********************************************************************
+** OS specific definitions
+*/
+/* The base priority used for pthread based GKI task. below value is to keep it retro compatible.
+ * It is recommended to use (GKI_MAX_TASKS+3), this will assign real time priorities GKI_MAX_TASKS-
+ * task_id -2 to the thread */
+#ifndef GKI_LINUX_BASE_PRIORITY
+#define GKI_LINUX_BASE_PRIORITY 30
+#endif
+
+/* The base policy used for pthread based GKI task. the sched defines are defined here to avoid undefined values due
+ * to missing header file, see pthread functions! Overall it is recommend however to use SCHED_NOMRAL */
+#define GKI_SCHED_NORMAL 0
+#define GKI_SCHED_FIFO 1
+#define GKI_SCHED_RR 2
+#ifndef GKI_LINUX_BASE_POLICY
+#define GKI_LINUX_BASE_POLICY GKI_SCHED_NORMAL
+#endif
+
+/* GKI timer bases should use GKI_SCHED_FIFO to ensure the least jitter possible */
+#ifndef GKI_LINUX_TIMER_POLICY
+#define GKI_LINUX_TIMER_POLICY GKI_SCHED_FIFO
+#endif
+
+/* the GKI_timer_update() thread should have the highest real time priority to ensue correct
+ * timer expiry.
+ */
+#ifndef GKI_LINUX_TIMER_TICK_PRIORITY
+#define GKI_LINUX_TIMER_TICK_PRIORITY GKI_LINUX_BASE_PRIORITY+2
+#endif
+
+/* the AV timer should preferably run above the gki timer tick to ensure precise AV timing
+ * If you observe AV jitter under have load you may increase this one */
+#ifndef GKI_LINUX_AV_TIMER_PRIORITY
+#define GKI_LINUX_AV_TIMER_PRIORITY GKI_LINUX_BASE_PRIORITY+3
+#endif
+
+/* defines by how much the nice value of the PROCESS should be changed. Values allowed:
+ * -19 to +19. a negative value give higher priority to btld compared to the default nice value
+ * of 20. in case of SCHED_NORMAL, a level of -5 should give a good btld/bt performance.
+ * In case of real time scheduling, leave default value.
+ */
+#ifndef GKI_LINUX_DEFAULT_NICE_INC
+#define GKI_LINUX_DEFAULT_NICE_INC -7
+#endif
+
+typedef struct
+{
+ pthread_mutex_t GKI_mutex;
+ pthread_t thread_id[GKI_MAX_TASKS];
+ pthread_mutex_t thread_evt_mutex[GKI_MAX_TASKS];
+ pthread_cond_t thread_evt_cond[GKI_MAX_TASKS];
+ pthread_mutex_t thread_timeout_mutex[GKI_MAX_TASKS];
+ pthread_cond_t thread_timeout_cond[GKI_MAX_TASKS];
+ int no_timer_suspend; /* 1: no suspend, 0 stop calling GKI_timer_update() */
+ pthread_mutex_t gki_timer_mutex;
+ pthread_cond_t gki_timer_cond;
+#if (GKI_DEBUG == TRUE)
+ pthread_mutex_t GKI_trace_mutex;
+#endif
+} tGKI_OS;
+
+/* condition to exit or continue GKI_run() timer loop */
+#define GKI_TIMER_TICK_RUN_COND 1
+#define GKI_TIMER_TICK_STOP_COND 0
+
+extern void gki_system_tick_start_stop_cback(BOOLEAN start);
+
+/* Contains common control block as well as OS specific variables */
+typedef struct
+{
+ tGKI_OS os;
+ tGKI_COM_CB com;
+} tGKI_CB;
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if GKI_DYNAMIC_MEMORY == FALSE
+GKI_API extern tGKI_CB gki_cb;
+#else
+GKI_API extern tGKI_CB *gki_cb_ptr;
+#define gki_cb (*gki_cb_ptr)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/gki/ulinux/gki_ulinux.c b/gki/ulinux/gki_ulinux.c
new file mode 100644
index 0000000..73e93dc
--- /dev/null
+++ b/gki/ulinux/gki_ulinux.c
@@ -0,0 +1,1355 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * This program is the proprietary software of Broadcom Corporation and/or its
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
+ *
+ * Except as expressly set forth in the Authorized License,
+ *
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
+ * Broadcom integrated circuit products.
+ *
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING
+ * OUT OF USE OR PERFORMANCE OF THE SOFTWARE.
+ *
+ * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM
+ * OR ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+ *
+ *****************************************************************************/
+
+/****************************************************************************
+**
+** Name gki_linux_pthreads.c
+**
+** Function pthreads version of Linux GKI. This version is used for
+** settop projects that already use pthreads and not pth.
+**
+*****************************************************************************/
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <sys/times.h>
+
+#include <pthread.h> /* must be 1st header defined */
+#include <time.h>
+#include "gki_int.h"
+
+#define LOG_TAG "GKI_LINUX"
+
+#include <utils/Log.h>
+
+/*****************************************************************************
+** Constants & Macros
+******************************************************************************/
+
+#ifndef GKI_TICK_TIMER_DEBUG
+#define GKI_TICK_TIMER_DEBUG FALSE
+#endif
+
+
+/* always log errors */
+#define GKI_ERROR_LOG(fmt, ...) LOGE ("##### ERROR : %s: " fmt "#####", __FUNCTION__, ## __VA_ARGS__)
+
+#if defined (GKI_TICK_TIMER_DEBUG) && (GKI_TICK_TIMER_DEBUG == TRUE)
+#define GKI_TIMER_TRACE(fmt, ...) LOGI ("%s: " fmt, __FUNCTION__, ## __VA_ARGS__)
+#else
+#define GKI_TIMER_TRACE(fmt, ...)
+#endif
+
+
+#define SCHED_NORMAL 0
+#define SCHED_FIFO 1
+#define SCHED_RR 2
+#define SCHED_BATCH 3
+
+#define NANOSEC_PER_MILLISEC (1000000)
+#define NSEC_PER_SEC (1000*NANOSEC_PER_MILLISEC)
+
+/* works only for 1ms to 1000ms heart beat ranges */
+#define LINUX_SEC (1000/TICKS_PER_SEC)
+
+#define LOCK(m) pthread_mutex_lock(&m)
+#define UNLOCK(m) pthread_mutex_unlock(&m)
+#define INIT(m) pthread_mutex_init(&m, NULL)
+
+#define WAKE_LOCK_ID "brcm_btld"
+#define PARTIAL_WAKE_LOCK 1
+
+#if GKI_DYNAMIC_MEMORY == FALSE
+tGKI_CB gki_cb;
+#endif
+
+#ifdef NO_GKI_RUN_RETURN
+static pthread_t timer_thread_id = 0;
+static int shutdown_timer = 0;
+#endif
+
+#ifndef GKI_SHUTDOWN_EVT
+#define GKI_SHUTDOWN_EVT APPL_EVT_7
+#endif
+
+/*****************************************************************************
+** Local type definitions
+******************************************************************************/
+
+#define pthread_cond_timedwait_monotonic pthread_cond_timedwait
+
+typedef struct
+{
+ UINT8 task_id; /* GKI task id */
+ TASKPTR task_entry; /* Task entry function*/
+ UINT32 params; /* Extra params to pass to task entry function */
+} gki_pthread_info_t;
+
+
+/*****************************************************************************
+** Static variables
+******************************************************************************/
+
+int g_GkiTimerWakeLockOn = 0;
+gki_pthread_info_t gki_pthread_info[GKI_MAX_TASKS];
+
+/*****************************************************************************
+** Static functions
+******************************************************************************/
+
+/*****************************************************************************
+** Externs
+******************************************************************************/
+
+extern int acquire_wake_lock(int lock, const char* id);
+extern int release_wake_lock(const char* id);
+
+/*****************************************************************************
+** Functions
+******************************************************************************/
+
+
+/*****************************************************************************
+**
+** Function gki_task_entry
+**
+** Description GKI pthread callback
+**
+** Returns void
+**
+*******************************************************************************/
+
+void gki_task_entry(UINT32 params)
+{
+ gki_pthread_info_t *p_pthread_info = (gki_pthread_info_t *)params;
+ gki_cb.os.thread_id[p_pthread_info->task_id] = pthread_self();
+
+ prctl(PR_SET_NAME, (unsigned long)gki_cb.com.OSTName[p_pthread_info->task_id], 0, 0, 0);
+
+ GKI_TRACE("gki_task_entry task_id=%i\n", p_pthread_info->task_id);
+
+ /* Call the actual thread entry point */
+ (p_pthread_info->task_entry)(p_pthread_info->params);
+
+ GKI_TRACE("gki_task task_id=%i terminating\n", p_pthread_info->task_id);
+
+ pthread_exit(0); /* GKI tasks have no return value */
+}
+/* end android */
+
+/*******************************************************************************
+**
+** Function GKI_init
+**
+** Description This function is called once at startup to initialize
+** all the timer structures.
+**
+** Returns void
+**
+*******************************************************************************/
+
+void GKI_init(void)
+{
+ pthread_mutexattr_t attr;
+ tGKI_OS *p_os;
+
+ memset (&gki_cb, 0, sizeof (gki_cb));
+
+ gki_buffer_init();
+ gki_timers_init();
+ gki_cb.com.OSTicks = (UINT32) times(0);
+
+ pthread_mutexattr_init(&attr);
+
+#ifndef __CYGWIN__
+ pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP);
+#endif
+ p_os = &gki_cb.os;
+ pthread_mutex_init(&p_os->GKI_mutex, &attr);
+ /* pthread_mutex_init(&GKI_sched_mutex, NULL); */
+#if (GKI_DEBUG == TRUE)
+ pthread_mutex_init(&p_os->GKI_trace_mutex, NULL);
+#endif
+ /* pthread_mutex_init(&thread_delay_mutex, NULL); */ /* used in GKI_delay */
+ /* pthread_cond_init (&thread_delay_cond, NULL); */
+
+ /* Initialiase GKI_timer_update suspend variables & mutexes to be in running state.
+ * this works too even if GKI_NO_TICK_STOP is defined in btld.txt */
+ p_os->no_timer_suspend = GKI_TIMER_TICK_RUN_COND;
+ pthread_mutex_init(&p_os->gki_timer_mutex, NULL);
+ pthread_cond_init(&p_os->gki_timer_cond, NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_get_os_tick_count
+**
+** Description This function is called to retrieve the native OS system tick.
+**
+** Returns Tick count of native OS.
+**
+*******************************************************************************/
+UINT32 GKI_get_os_tick_count(void)
+{
+ /* TODO - add any OS specific code here */
+ return (gki_cb.com.OSTicks);
+}
+
+/*******************************************************************************
+**
+** Function GKI_create_task
+**
+** Description This function is called to create a new OSS task.
+**
+** Parameters: task_entry - (input) pointer to the entry function of the task
+** task_id - (input) Task id is mapped to priority
+** taskname - (input) name given to the task
+** stack - (input) pointer to the top of the stack (highest memory location)
+** stacksize - (input) size of the stack allocated for the task
+**
+** Returns GKI_SUCCESS if all OK, GKI_FAILURE if any problem
+**
+** NOTE This function take some parameters that may not be needed
+** by your particular OS. They are here for compatability
+** of the function prototype.
+**
+*******************************************************************************/
+UINT8 GKI_create_task (TASKPTR task_entry, UINT8 task_id, INT8 *taskname, UINT16 *stack, UINT16 stacksize)
+{
+ UINT16 i;
+ UINT8 *p;
+ struct sched_param param;
+ int policy, ret = 0;
+ pthread_attr_t attr1;
+
+ GKI_TRACE( "GKI_create_task %x %d %s %x %d\n", task_entry, task_id, taskname, stack,
+ stacksize);
+
+ if (task_id >= GKI_MAX_TASKS)
+ {
+ GKI_TRACE("Error! task ID > max task allowed");
+ return (GKI_FAILURE);
+ }
+
+
+ gki_cb.com.OSRdyTbl[task_id] = TASK_READY;
+ gki_cb.com.OSTName[task_id] = taskname;
+ gki_cb.com.OSWaitTmr[task_id] = 0;
+ gki_cb.com.OSWaitEvt[task_id] = 0;
+
+ /* Initialize mutex and condition variable objects for events and timeouts */
+ pthread_mutex_init(&gki_cb.os.thread_evt_mutex[task_id], NULL);
+ pthread_cond_init (&gki_cb.os.thread_evt_cond[task_id], NULL);
+ pthread_mutex_init(&gki_cb.os.thread_timeout_mutex[task_id], NULL);
+ pthread_cond_init (&gki_cb.os.thread_timeout_cond[task_id], NULL);
+
+ pthread_attr_init(&attr1);
+ /* by default, pthread creates a joinable thread */
+#if ( FALSE == GKI_PTHREAD_JOINABLE )
+ pthread_attr_setdetachstate(&attr1, PTHREAD_CREATE_DETACHED);
+
+ GKI_TRACE("GKI creating task %i\n", task_id);
+#else
+ GKI_TRACE("GKI creating JOINABLE task %i\n", task_id);
+#endif
+
+ /* On Android, the new tasks starts running before 'gki_cb.os.thread_id[task_id]' is initialized */
+ /* Pass task_id to new task so it can initialize gki_cb.os.thread_id[task_id] for it calls GKI_wait */
+ gki_pthread_info[task_id].task_id = task_id;
+ gki_pthread_info[task_id].task_entry = task_entry;
+ gki_pthread_info[task_id].params = 0;
+
+ ret = pthread_create( &gki_cb.os.thread_id[task_id],
+ &attr1,
+ (void *)gki_task_entry,
+ &gki_pthread_info[task_id]);
+
+ if (ret != 0)
+ {
+ printf("pthread_create failed(%d), %s!\n\r", ret, taskname);
+ return GKI_FAILURE;
+ }
+
+ if(pthread_getschedparam(gki_cb.os.thread_id[task_id], &policy, &param)==0)
+ {
+#if (GKI_LINUX_BASE_POLICY!=GKI_SCHED_NORMAL)
+#if defined(PBS_SQL_TASK)
+ if (task_id == PBS_SQL_TASK)
+ {
+ GKI_TRACE("PBS SQL lowest priority task");
+ policy = SCHED_NORMAL;
+ }
+ else
+#endif
+#endif
+ {
+ /* check if define in gki_int.h is correct for this compile environment! */
+ policy = GKI_LINUX_BASE_POLICY;
+#if (GKI_LINUX_BASE_POLICY!=GKI_SCHED_NORMAL)
+ param.sched_priority = GKI_LINUX_BASE_PRIORITY - task_id - 2;
+#endif
+ }
+ pthread_setschedparam(gki_cb.os.thread_id[task_id], policy, &param);
+ }
+
+ GKI_TRACE( "Leaving GKI_create_task %x %d %x %s %x %d\n",
+ task_entry,
+ task_id,
+ gki_cb.os.thread_id[task_id],
+ taskname,
+ stack,
+ stacksize);
+
+ return (GKI_SUCCESS);
+}
+
+void GKI_destroy_task(UINT8 task_id)
+{
+#if ( FALSE == GKI_PTHREAD_JOINABLE )
+ int i = 0;
+#else
+ int result;
+#endif
+ if (gki_cb.com.OSRdyTbl[task_id] != TASK_DEAD)
+ {
+ gki_cb.com.OSRdyTbl[task_id] = TASK_DEAD;
+
+ /* paranoi settings, make sure that we do not execute any mailbox events */
+ gki_cb.com.OSWaitEvt[task_id] &= ~(TASK_MBOX_0_EVT_MASK|TASK_MBOX_1_EVT_MASK|
+ TASK_MBOX_2_EVT_MASK|TASK_MBOX_3_EVT_MASK);
+ GKI_send_event(task_id, EVENT_MASK(GKI_SHUTDOWN_EVT));
+
+#if ( FALSE == GKI_PTHREAD_JOINABLE )
+ i = 0;
+
+ while ((gki_cb.com.OSWaitEvt[task_id] != 0) && (++i < 10))
+ usleep(100 * 1000);
+#else
+ result = pthread_join( gki_cb.os.thread_id[task_id], NULL );
+ if ( result < 0 )
+ {
+ GKI_TRACE( "pthread_join() FAILED: result: %d", result );
+ }
+#endif
+ GKI_ERROR_LOG( "GKI_shutdown(): task %s dead\n", gki_cb.com.OSTName[task_id]);
+ GKI_exit_task(task_id);
+ }
+
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_shutdown
+**
+** Description shutdowns the GKI tasks/threads in from max task id to 0 and frees
+** pthread resources!
+** IMPORTANT: in case of join method, GKI_shutdown must be called outside
+** a GKI thread context!
+**
+** Returns void
+**
+*******************************************************************************/
+
+void GKI_shutdown(void)
+{
+ UINT8 task_id;
+#if ( FALSE == GKI_PTHREAD_JOINABLE )
+ int i = 0;
+#else
+ int result;
+#endif
+
+#ifdef GKI_USE_DEFERED_ALLOC_BUF_POOLS
+ gki_dealloc_free_queue();
+#endif
+
+ /* release threads and set as TASK_DEAD. going from low to high priority fixes
+ * GKI_exception problem due to btu->hci sleep request events */
+ for (task_id = GKI_MAX_TASKS; task_id > 0; task_id--)
+ {
+ if (gki_cb.com.OSRdyTbl[task_id - 1] != TASK_DEAD)
+ {
+ gki_cb.com.OSRdyTbl[task_id - 1] = TASK_DEAD;
+
+ /* paranoi settings, make sure that we do not execute any mailbox events */
+ gki_cb.com.OSWaitEvt[task_id-1] &= ~(TASK_MBOX_0_EVT_MASK|TASK_MBOX_1_EVT_MASK|
+ TASK_MBOX_2_EVT_MASK|TASK_MBOX_3_EVT_MASK);
+ GKI_send_event(task_id - 1, EVENT_MASK(GKI_SHUTDOWN_EVT));
+
+#if ( FALSE == GKI_PTHREAD_JOINABLE )
+ i = 0;
+
+ while ((gki_cb.com.OSWaitEvt[task_id - 1] != 0) && (++i < 10))
+ usleep(100 * 1000);
+#else
+ result = pthread_join( gki_cb.os.thread_id[task_id-1], NULL );
+
+ if ( result < 0 )
+ {
+ LOGE( "pthread_join() FAILED: result: %d", result );
+ }
+#endif
+ // GKI_ERROR_LOG( "GKI_shutdown(): task %s dead\n", gki_cb.com.OSTName[task_id]);
+ GKI_exit_task(task_id - 1);
+ }
+ }
+
+ /* Destroy mutex and condition variable objects */
+ pthread_mutex_destroy(&gki_cb.os.GKI_mutex);
+
+ /* pthread_mutex_destroy(&GKI_sched_mutex); */
+#if (GKI_DEBUG == TRUE)
+ pthread_mutex_destroy(&gki_cb.os.GKI_trace_mutex);
+#endif
+ /* pthread_mutex_destroy(&thread_delay_mutex);
+ pthread_cond_destroy (&thread_delay_cond); */
+#if ( FALSE == GKI_PTHREAD_JOINABLE )
+ i = 0;
+#endif
+
+#ifdef NO_GKI_RUN_RETURN
+ shutdown_timer = 1;
+#endif
+ if (g_GkiTimerWakeLockOn)
+ {
+ GKI_TRACE("GKI_shutdown : release_wake_lock(brcm_btld)");
+ release_wake_lock(WAKE_LOCK_ID);
+ g_GkiTimerWakeLockOn = 0;
+ }
+}
+
+/*******************************************************************************
+ **
+ ** Function gki_system_tick_start_stop_cback
+ **
+ ** Description This function runs a task
+ **
+ ** Parameters: start: TRUE start system tick (again), FALSE stop
+ **
+ ** Returns void
+ **
+ *********************************************************************************/
+
+void gki_system_tick_start_stop_cback(BOOLEAN start)
+{
+ tGKI_OS *p_os = &gki_cb.os;
+ volatile int *p_run_cond = &p_os->no_timer_suspend;
+ static int wake_lock_count;
+ if ( FALSE == start )
+ {
+ /* this can lead to a race condition. however as we only read this variable in the timer loop
+ * we should be fine with this approach. otherwise uncomment below mutexes.
+ */
+ /* GKI_disable(); */
+ *p_run_cond = GKI_TIMER_TICK_STOP_COND;
+ /* GKI_enable(); */
+
+ GKI_TIMER_TRACE(">>> STOP GKI_timer_update(), wake_lock_count:%d", --wake_lock_count);
+
+ release_wake_lock(WAKE_LOCK_ID);
+ g_GkiTimerWakeLockOn = 0;
+ }
+ else
+ {
+ /* restart GKI_timer_update() loop */
+ acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
+
+ g_GkiTimerWakeLockOn = 1;
+ *p_run_cond = GKI_TIMER_TICK_RUN_COND;
+
+ pthread_mutex_lock( &p_os->gki_timer_mutex );
+ pthread_cond_signal( &p_os->gki_timer_cond );
+ pthread_mutex_unlock( &p_os->gki_timer_mutex );
+
+ GKI_TIMER_TRACE(">>> START GKI_timer_update(), wake_lock_count:%d", ++wake_lock_count );
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_run
+**
+** Description This function runs a task
+****
+** Returns void
+**
+** NOTE This function is only needed for operating systems where
+** starting a task is a 2-step process. Most OS's do it in
+** one step, If your OS does it in one step, this function
+** should be empty.
+*********************************************************************************/
+
+#ifdef NO_GKI_RUN_RETURN
+void* timer_thread(void *arg)
+{
+ struct timespec delay;
+ int err;
+
+ while(!shutdown_timer)
+ {
+ delay.tv_sec = LINUX_SEC / 1000;
+ delay.tv_nsec = 1000 * 1000 * (LINUX_SEC%1000);
+
+ /* [u]sleep can't be used because it uses SIGALRM */
+
+ do {
+ err = nanosleep(&delay, &delay);
+ } while (err < 0 && errno ==EINTR);
+
+ GKI_timer_update(1);
+ }
+ GKI_TRACE("gki_ulinux: Exiting timer_thread");
+ pthread_exit(NULL);
+ return NULL;
+}
+#endif
+
+
+/*****************************************************************************
+**
+** Function gki_set_timer_scheduling
+**
+** Description helper function to set scheduling policy and priority of btdl
+**
+** Returns void
+**
+*******************************************************************************/
+
+static void gki_set_timer_scheduling( void )
+{
+ pid_t main_pid = getpid();
+ struct sched_param param;
+ int policy;
+
+ policy = sched_getscheduler(main_pid);
+
+ if ( policy != -1 )
+ {
+ GKI_TRACE("gki_set_timer_scheduling(()::scheduler current policy: %d", policy);
+
+ /* ensure highest priority in the system + 2 to allow space for read threads */
+ param.sched_priority = GKI_LINUX_TIMER_TICK_PRIORITY;
+
+ if ( 0!=sched_setscheduler(main_pid, GKI_LINUX_TIMER_POLICY, &param ) )
+ {
+ GKI_TRACE("sched_setscheduler() failed with error: %d", errno);
+ }
+ }
+ else
+ {
+ GKI_TRACE( "getscheduler failed: %d", errno);
+ }
+}
+
+
+/*****************************************************************************
+**
+** Function GKI_freeze
+**
+** Description Freeze GKI. Relevant only when NO_GKI_RUN_RETURN is defined
+**
+** Returns
+**
+*******************************************************************************/
+
+void GKI_freeze()
+{
+#ifdef NO_GKI_RUN_RETURN
+ shutdown_timer = 1;
+ /* Ensure that the timer thread exits */
+ pthread_join(timer_thread_id, NULL);
+#endif
+}
+
+/*****************************************************************************
+**
+** Function GKI_run
+**
+** Description Main GKI loop
+**
+** Returns
+**
+*******************************************************************************/
+
+void GKI_run (void *p_task_id)
+{
+ struct timespec delay;
+ int err;
+ volatile int * p_run_cond = &gki_cb.os.no_timer_suspend;
+
+#ifndef GKI_NO_TICK_STOP
+ /* adjust btld scheduling scheme now */
+ gki_set_timer_scheduling();
+
+ /* register start stop function which disable timer loop in GKI_run() when no timers are
+ * in any GKI/BTA/BTU this should save power when BTLD is idle! */
+ GKI_timer_queue_register_callback( gki_system_tick_start_stop_cback );
+ GKI_TRACE( "GKI_run(): Start/Stop GKI_timer_update_registered!" );
+#endif
+
+#ifdef NO_GKI_RUN_RETURN
+ pthread_attr_t timer_attr;
+
+ shutdown_timer = 0;
+
+ pthread_attr_init(&timer_attr);
+ if (pthread_create( &timer_thread_id,
+ &timer_attr,
+ timer_thread,
+ NULL) != 0 )
+ {
+ printf("GKI_run: pthread_create failed to create timer_thread!\n\r");
+ return;
+ }
+
+ prctl(PR_SET_NAME, (unsigned long)"gki timer", 0, 0, 0);
+
+#else
+ GKI_TRACE("GKI_run ");
+ for (;;)
+ {
+ do
+ {
+ /* adjust hear bit tick in btld by changning TICKS_PER_SEC!!!!! this formula works only for
+ * 1-1000ms heart beat units! */
+ delay.tv_sec = LINUX_SEC / 1000;
+ delay.tv_nsec = 1000 * 1000 * (LINUX_SEC % 1000);
+
+ /* [u]sleep can't be used because it uses SIGALRM */
+ do
+ {
+ err = nanosleep(&delay, &delay);
+ } while (err < 0 && errno == EINTR);
+
+ /* the unit should be alsways 1 (1 tick). only if you vary for some reason heart beat tick
+ * e.g. power saving you may want to provide more ticks
+ */
+ GKI_timer_update( 1 );
+ /* BT_TRACE_2( TRACE_LAYER_HCI, TRACE_TYPE_DEBUG, "update: tv_sec: %d, tv_nsec: %d", delay.tv_sec, delay.tv_nsec ); */
+ } while ( GKI_TIMER_TICK_RUN_COND == *p_run_cond );
+
+ /* currently on reason to exit above loop is no_timer_suspend == GKI_TIMER_TICK_STOP_COND
+ * block timer main thread till re-armed by */
+
+ GKI_TIMER_TRACE(">>> SUSPENDED GKI_timer_update()" );
+
+ pthread_mutex_lock( &gki_cb.os.gki_timer_mutex );
+ pthread_cond_wait( &gki_cb.os.gki_timer_cond, &gki_cb.os.gki_timer_mutex );
+ pthread_mutex_unlock( &gki_cb.os.gki_timer_mutex );
+
+ /* potentially we need to adjust os gki_cb.com.OSTicks */
+ GKI_TIMER_TRACE(">>> RESTARTED GKI_timer_update(): run_cond: %d",
+ *p_run_cond );
+
+ }
+#endif
+ return;
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_stop
+**
+** Description This function is called to stop
+** the tasks and timers when the system is being stopped
+**
+** Returns void
+**
+** NOTE This function is NOT called by the Widcomm stack and
+** profiles. If you want to use it in your own implementation,
+** put specific code here.
+**
+*******************************************************************************/
+
+void GKI_stop (void)
+{
+ UINT8 task_id;
+
+ /* gki_queue_timer_cback(FALSE); */
+ /* TODO - add code here if needed*/
+
+ for(task_id = 0; task_id<GKI_MAX_TASKS; task_id++)
+ {
+ if(gki_cb.com.OSRdyTbl[task_id] != TASK_DEAD)
+ {
+ GKI_exit_task(task_id);
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_wait
+**
+** Description This function is called by tasks to wait for a specific
+** event or set of events. The task may specify the duration
+** that it wants to wait for, or 0 if infinite.
+**
+** Parameters: flag - (input) the event or set of events to wait for
+** timeout - (input) the duration that the task wants to wait
+** for the specific events (in system ticks)
+**
+**
+** Returns the event mask of received events or zero if timeout
+**
+*******************************************************************************/
+UINT16 GKI_wait (UINT16 flag, UINT32 timeout)
+{
+ UINT16 evt;
+ UINT8 rtask;
+ struct timespec abstime = { 0, 0 };
+
+ int sec;
+ int nano_sec;
+
+ rtask = GKI_get_taskid();
+
+ GKI_TRACE("GKI_wait %d %x %d", rtask, flag, timeout);
+
+ gki_cb.com.OSWaitForEvt[rtask] = flag;
+
+ /* protect OSWaitEvt[rtask] from modification from an other thread */
+ pthread_mutex_lock(&gki_cb.os.thread_evt_mutex[rtask]);
+
+ if (!(gki_cb.com.OSWaitEvt[rtask] & flag))
+ {
+ if (timeout)
+ {
+ clock_gettime(CLOCK_MONOTONIC, &abstime);
+
+ /* add timeout */
+ sec = timeout / 1000;
+ nano_sec = (timeout % 1000) * NANOSEC_PER_MILLISEC;
+ abstime.tv_nsec += nano_sec;
+ if (abstime.tv_nsec > NSEC_PER_SEC)
+ {
+ abstime.tv_sec += (abstime.tv_nsec / NSEC_PER_SEC);
+ abstime.tv_nsec = abstime.tv_nsec % NSEC_PER_SEC;
+ }
+ abstime.tv_sec += sec;
+
+ pthread_cond_timedwait_monotonic(&gki_cb.os.thread_evt_cond[rtask],
+ &gki_cb.os.thread_evt_mutex[rtask], &abstime);
+
+ }
+ else
+ {
+ pthread_cond_wait(&gki_cb.os.thread_evt_cond[rtask], &gki_cb.os.thread_evt_mutex[rtask]);
+ }
+
+ /* TODO: check, this is probably neither not needed depending on phtread_cond_wait() implmentation,
+ e.g. it looks like it is implemented as a counter in which case multiple cond_signal
+ should NOT be lost! */
+
+ /* we are waking up after waiting for some events, so refresh variables
+ no need to call GKI_disable() here as we know that we will have some events as we've been waking
+ up after condition pending or timeout */
+
+ if (gki_cb.com.OSTaskQFirst[rtask][0])
+ gki_cb.com.OSWaitEvt[rtask] |= TASK_MBOX_0_EVT_MASK;
+ if (gki_cb.com.OSTaskQFirst[rtask][1])
+ gki_cb.com.OSWaitEvt[rtask] |= TASK_MBOX_1_EVT_MASK;
+ if (gki_cb.com.OSTaskQFirst[rtask][2])
+ gki_cb.com.OSWaitEvt[rtask] |= TASK_MBOX_2_EVT_MASK;
+ if (gki_cb.com.OSTaskQFirst[rtask][3])
+ gki_cb.com.OSWaitEvt[rtask] |= TASK_MBOX_3_EVT_MASK;
+
+ if (gki_cb.com.OSRdyTbl[rtask] == TASK_DEAD)
+ {
+ gki_cb.com.OSWaitEvt[rtask] = 0;
+ /* unlock thread_evt_mutex as pthread_cond_wait() does auto lock when cond is met */
+ pthread_mutex_unlock(&gki_cb.os.thread_evt_mutex[rtask]);
+ return (EVENT_MASK(GKI_SHUTDOWN_EVT));
+ }
+ }
+
+ /* Clear the wait for event mask */
+ gki_cb.com.OSWaitForEvt[rtask] = 0;
+
+ /* Return only those bits which user wants... */
+ evt = gki_cb.com.OSWaitEvt[rtask] & flag;
+
+ /* Clear only those bits which user wants... */
+ gki_cb.com.OSWaitEvt[rtask] &= ~flag;
+
+ /* unlock thread_evt_mutex as pthread_cond_wait() does auto lock mutex when cond is met */
+ pthread_mutex_unlock(&gki_cb.os.thread_evt_mutex[rtask]);
+
+ GKI_TRACE("GKI_wait %d %x %d %x done", rtask, flag, timeout, evt);
+ return (evt);
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_delay
+**
+** Description This function is called by tasks to sleep unconditionally
+** for a specified amount of time. The duration is in milliseconds
+**
+** Parameters: timeout - (input) the duration in milliseconds
+**
+** Returns void
+**
+*******************************************************************************/
+
+void GKI_delay (UINT32 timeout)
+{
+ UINT8 rtask = GKI_get_taskid();
+ struct timespec delay;
+ int err;
+
+ GKI_TRACE("GKI_delay %d %d", rtask, timeout);
+
+ delay.tv_sec = timeout / 1000;
+ delay.tv_nsec = 1000 * 1000 * (timeout%1000);
+
+ /* [u]sleep can't be used because it uses SIGALRM */
+
+ do {
+ err = nanosleep(&delay, &delay);
+ } while (err < 0 && errno ==EINTR);
+
+ /* Check if task was killed while sleeping */
+
+ /* NOTE : if you do not implement task killing, you do not need this check */
+
+ if (rtask && gki_cb.com.OSRdyTbl[rtask] == TASK_DEAD)
+ {
+ }
+
+ GKI_TRACE("GKI_delay %d %d done", rtask, timeout);
+
+ return;
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_send_event
+**
+** Description This function is called by tasks to send events to other
+** tasks. Tasks can also send events to themselves.
+**
+** Parameters: task_id - (input) The id of the task to which the event has to
+** be sent
+** event - (input) The event that has to be sent
+**
+**
+** Returns GKI_SUCCESS if all OK, else GKI_FAILURE
+**
+*******************************************************************************/
+
+UINT8 GKI_send_event (UINT8 task_id, UINT16 event)
+{
+ GKI_TRACE("GKI_send_event %d %x", task_id, event);
+
+ /* use efficient coding to avoid pipeline stalls */
+ if (task_id < GKI_MAX_TASKS)
+ {
+ /* protect OSWaitEvt[task_id] from manipulation in GKI_wait() */
+ pthread_mutex_lock(&gki_cb.os.thread_evt_mutex[task_id]);
+
+ /* Set the event bit */
+ gki_cb.com.OSWaitEvt[task_id] |= event;
+
+ pthread_cond_signal(&gki_cb.os.thread_evt_cond[task_id]);
+
+ pthread_mutex_unlock(&gki_cb.os.thread_evt_mutex[task_id]);
+
+ GKI_TRACE("GKI_send_event %d %x done", task_id, event);
+ return ( GKI_SUCCESS );
+ }
+ return (GKI_FAILURE);
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_isend_event
+**
+** Description This function is called from ISRs to send events to other
+** tasks. The only difference between this function and GKI_send_event
+** is that this function assumes interrupts are already disabled.
+**
+** Parameters: task_id - (input) The destination task Id for the event.
+** event - (input) The event flag
+**
+** Returns GKI_SUCCESS if all OK, else GKI_FAILURE
+**
+** NOTE This function is NOT called by the Widcomm stack and
+** profiles. If you want to use it in your own implementation,
+** put your code here, otherwise you can delete the entire
+** body of the function.
+**
+*******************************************************************************/
+UINT8 GKI_isend_event (UINT8 task_id, UINT16 event)
+{
+ GKI_TRACE("GKI_isend_event %d %x", task_id, event);
+ GKI_TRACE("GKI_isend_event %d %x done", task_id, event);
+ return GKI_send_event(task_id, event);
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_get_taskid
+**
+** Description This function gets the currently running task ID.
+**
+** Returns task ID
+**
+** NOTE The Widcomm upper stack and profiles may run as a single task.
+** If you only have one GKI task, then you can hard-code this
+** function to return a '1'. Otherwise, you should have some
+** OS-specific method to determine the current task.
+**
+*******************************************************************************/
+UINT8 GKI_get_taskid (void)
+{
+ int i;
+
+ pthread_t thread_id = pthread_self( );
+
+ GKI_TRACE("GKI_get_taskid %x", thread_id);
+
+ for (i = 0; i < GKI_MAX_TASKS; i++) {
+ if (gki_cb.os.thread_id[i] == thread_id) {
+ //GKI_TRACE("GKI_get_taskid %x %d done", thread_id, i);
+ return(i);
+ }
+ }
+
+ GKI_TRACE("GKI_get_taskid: task id = -1");
+
+ return(-1);
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_map_taskname
+**
+** Description This function gets the task name of the taskid passed as arg.
+** If GKI_MAX_TASKS is passed as arg the currently running task
+** name is returned
+**
+** Parameters: task_id - (input) The id of the task whose name is being
+** sought. GKI_MAX_TASKS is passed to get the name of the
+** currently running task.
+**
+** Returns pointer to task name
+**
+** NOTE this function needs no customization
+**
+*******************************************************************************/
+
+INT8 *GKI_map_taskname (UINT8 task_id)
+{
+ GKI_TRACE("GKI_map_taskname %d", task_id);
+
+ if (task_id < GKI_MAX_TASKS)
+ {
+ GKI_TRACE("GKI_map_taskname %d %s done", task_id, gki_cb.com.OSTName[task_id]);
+ return (gki_cb.com.OSTName[task_id]);
+ }
+ else if (task_id == GKI_MAX_TASKS )
+ {
+ return (gki_cb.com.OSTName[GKI_get_taskid()]);
+ }
+ else
+ {
+ return (INT8*)"BAD";
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_enable
+**
+** Description This function enables interrupts.
+**
+** Returns void
+**
+*******************************************************************************/
+void GKI_enable (void)
+{
+ GKI_TRACE("GKI_enable");
+ pthread_mutex_unlock(&gki_cb.os.GKI_mutex);
+ GKI_TRACE("Leaving GKI_enable");
+ return;
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_disable
+**
+** Description This function disables interrupts.
+**
+** Returns void
+**
+*******************************************************************************/
+
+void GKI_disable (void)
+{
+ GKI_TRACE("GKI_disable");
+
+ pthread_mutex_lock(&gki_cb.os.GKI_mutex);
+
+ GKI_TRACE("Leaving GKI_disable");
+ return;
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_exception
+**
+** Description This function throws an exception.
+** This is normally only called for a nonrecoverable error.
+**
+** Parameters: code - (input) The code for the error
+** msg - (input) The message that has to be logged
+**
+** Returns void
+**
+*******************************************************************************/
+
+void GKI_exception (UINT16 code, char *msg)
+{
+ UINT8 task_id;
+ int i = 0;
+
+ GKI_ERROR_LOG( "GKI_exception(): Task State Table\n");
+
+ for(task_id = 0; task_id < GKI_MAX_TASKS; task_id++)
+ {
+ GKI_ERROR_LOG( "TASK ID [%d] task name [%s] state [%d]\n",
+ task_id,
+ gki_cb.com.OSTName[task_id],
+ gki_cb.com.OSRdyTbl[task_id]);
+ }
+
+ GKI_TRACE("GKI_exception %d %s", code, msg);
+ GKI_ERROR_LOG( "\n********************************************************************\n");
+ GKI_ERROR_LOG( "* GKI_exception(): %d %s\n", code, msg);
+ GKI_ERROR_LOG( "********************************************************************\n");
+
+#if 0//(GKI_DEBUG == TRUE)
+ GKI_disable();
+
+ if (gki_cb.com.ExceptionCnt < GKI_MAX_EXCEPTION)
+ {
+ EXCEPTION_T *pExp;
+
+ pExp = &gki_cb.com.Exception[gki_cb.com.ExceptionCnt++];
+ pExp->type = code;
+ pExp->taskid = GKI_get_taskid();
+ strncpy((char *)pExp->msg, msg, GKI_MAX_EXCEPTION_MSGLEN - 1);
+ }
+
+ GKI_enable();
+#endif
+
+ GKI_TRACE("GKI_exception %d %s done", code, msg);
+
+
+ return;
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_get_time_stamp
+**
+** Description This function formats the time into a user area
+**
+** Parameters: tbuf - (output) the address to the memory containing the
+** formatted time
+**
+** Returns the address of the user area containing the formatted time
+** The format of the time is ????
+**
+** NOTE This function is only called by OBEX.
+**
+*******************************************************************************/
+INT8 *GKI_get_time_stamp (INT8 *tbuf)
+{
+ UINT32 ms_time;
+ UINT32 s_time;
+ UINT32 m_time;
+ UINT32 h_time;
+ INT8 *p_out = tbuf;
+
+ gki_cb.com.OSTicks = times(0);
+ ms_time = GKI_TICKS_TO_MS(gki_cb.com.OSTicks);
+ s_time = ms_time/100; /* 100 Ticks per second */
+ m_time = s_time/60;
+ h_time = m_time/60;
+
+ ms_time -= s_time*100;
+ s_time -= m_time*60;
+ m_time -= h_time*60;
+
+ *p_out++ = (INT8)((h_time / 10) + '0');
+ *p_out++ = (INT8)((h_time % 10) + '0');
+ *p_out++ = ':';
+ *p_out++ = (INT8)((m_time / 10) + '0');
+ *p_out++ = (INT8)((m_time % 10) + '0');
+ *p_out++ = ':';
+ *p_out++ = (INT8)((s_time / 10) + '0');
+ *p_out++ = (INT8)((s_time % 10) + '0');
+ *p_out++ = ':';
+ *p_out++ = (INT8)((ms_time / 10) + '0');
+ *p_out++ = (INT8)((ms_time % 10) + '0');
+ *p_out++ = ':';
+ *p_out = 0;
+
+ return (tbuf);
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_register_mempool
+**
+** Description This function registers a specific memory pool.
+**
+** Parameters: p_mem - (input) pointer to the memory pool
+**
+** Returns void
+**
+** NOTE This function is NOT called by the Widcomm stack and
+** profiles. If your OS has different memory pools, you
+** can tell GKI the pool to use by calling this function.
+**
+*******************************************************************************/
+void GKI_register_mempool (void *p_mem)
+{
+ gki_cb.com.p_user_mempool = p_mem;
+
+ return;
+}
+
+/*******************************************************************************
+**
+** Function GKI_os_malloc
+**
+** Description This function allocates memory
+**
+** Parameters: size - (input) The size of the memory that has to be
+** allocated
+**
+** Returns the address of the memory allocated, or NULL if failed
+**
+** NOTE This function is called by the Widcomm stack when
+** dynamic memory allocation is used. (see dyn_mem.h)
+**
+*******************************************************************************/
+void *GKI_os_malloc (UINT32 size)
+{
+ return (malloc(size));
+}
+
+/*******************************************************************************
+**
+** Function GKI_os_free
+**
+** Description This function frees memory
+**
+** Parameters: size - (input) The address of the memory that has to be
+** freed
+**
+** Returns void
+**
+** NOTE This function is NOT called by the Widcomm stack and
+** profiles. It is only called from within GKI if dynamic
+**
+*******************************************************************************/
+void GKI_os_free (void *p_mem)
+{
+ if(p_mem != NULL)
+ free(p_mem);
+ return;
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_suspend_task()
+**
+** Description This function suspends the task specified in the argument.
+**
+** Parameters: task_id - (input) the id of the task that has to suspended
+**
+** Returns GKI_SUCCESS if all OK, else GKI_FAILURE
+**
+** NOTE This function is NOT called by the Widcomm stack and
+** profiles. If you want to implement task suspension capability,
+** put specific code here.
+**
+*******************************************************************************/
+UINT8 GKI_suspend_task (UINT8 task_id)
+{
+ GKI_TRACE("GKI_suspend_task %d - NOT implemented", task_id);
+
+
+ GKI_TRACE("GKI_suspend_task %d done", task_id);
+
+ return (GKI_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_resume_task()
+**
+** Description This function resumes the task specified in the argument.
+**
+** Parameters: task_id - (input) the id of the task that has to resumed
+**
+** Returns GKI_SUCCESS if all OK
+**
+** NOTE This function is NOT called by the Widcomm stack and
+** profiles. If you want to implement task suspension capability,
+** put specific code here.
+**
+*******************************************************************************/
+UINT8 GKI_resume_task (UINT8 task_id)
+{
+ GKI_TRACE("GKI_resume_task %d - NOT implemented", task_id);
+
+
+ GKI_TRACE("GKI_resume_task %d done", task_id);
+
+ return (GKI_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_exit_task
+**
+** Description This function is called to stop a GKI task.
+**
+** Parameters: task_id - (input) the id of the task that has to be stopped
+**
+** Returns void
+**
+** NOTE This function is NOT called by the Widcomm stack and
+** profiles. If you want to use it in your own implementation,
+** put specific code here to kill a task.
+**
+*******************************************************************************/
+void GKI_exit_task (UINT8 task_id)
+{
+ GKI_disable();
+ gki_cb.com.OSRdyTbl[task_id] = TASK_DEAD;
+
+ /* Destroy mutex and condition variable objects */
+ pthread_mutex_destroy(&gki_cb.os.thread_evt_mutex[task_id]);
+ pthread_cond_destroy (&gki_cb.os.thread_evt_cond[task_id]);
+ pthread_mutex_destroy(&gki_cb.os.thread_timeout_mutex[task_id]);
+ pthread_cond_destroy (&gki_cb.os.thread_timeout_cond[task_id]);
+
+ GKI_enable();
+
+ //GKI_send_event(task_id, EVENT_MASK(GKI_SHUTDOWN_EVT));
+
+ GKI_TRACE("GKI_exit_task %d done", task_id);
+ return;
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_sched_lock
+**
+** Description This function is called by tasks to disable scheduler
+** task context switching.
+**
+** Returns void
+**
+** NOTE This function is NOT called by the Widcomm stack and
+** profiles. If you want to use it in your own implementation,
+** put code here to tell the OS to disable context switching.
+**
+*******************************************************************************/
+void GKI_sched_lock(void)
+{
+ GKI_TRACE("GKI_sched_lock");
+ return;
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_sched_unlock
+**
+** Description This function is called by tasks to enable scheduler switching.
+**
+** Returns void
+**
+** NOTE This function is NOT called by the Widcomm stack and
+** profiles. If you want to use it in your own implementation,
+** put code here to tell the OS to re-enable context switching.
+**
+*******************************************************************************/
+void GKI_sched_unlock(void)
+{
+ GKI_TRACE("GKI_sched_unlock");
+}
+
+
diff --git a/include/bt_target.h b/include/bt_target.h
new file mode 100644
index 0000000..67fb6d3
--- /dev/null
+++ b/include/bt_target.h
@@ -0,0 +1,3441 @@
+/****************************************************************************
+**
+** Name: bt_target.h
+**
+** Function this file contains definitions that will probably
+** change for each Bluetooth target system. This includes
+** such things as buffer pool sizes, number of tasks,
+** little endian/big endian conversions, etc...
+**
+** NOTE This file should always be included first.
+**
+**
+** Copyright (c) 1999-2010, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#ifndef BT_TARGET_H
+#define BT_TARGET_H
+
+#ifndef BUILDCFG
+#define BUILDCFG
+#endif
+#include "data_types.h"
+
+#ifdef BUILDCFG
+#include "buildcfg.h"
+#endif
+
+/* Include common GKI definitions used by this platform */
+#include "gki_target.h"
+
+#include "bt_types.h" /* This must be defined AFTER buildcfg.h */
+#include "dyn_mem.h" /* defines static and/or dynamic memory for components */
+
+/* #define BYPASS_AVDATATRACE */
+
+/******************************************************************************
+**
+** Platform-Specific
+**
+******************************************************************************/
+
+/* API macros for simulator */
+
+#define BTAPI
+
+#ifndef BTE_BSE_WRAPPER
+#ifdef BTE_SIM_APP
+#undef BTAPI
+#define BTAPI __declspec(dllexport)
+#endif
+#endif
+
+#define BT_API BTAPI
+#define BTU_API BTAPI
+#define A2D_API BTAPI
+#define VDP_API BTAPI
+#define AVDT_API BTAPI
+#define AVCT_API BTAPI
+#define AVRC_API BTAPI
+#define BIP_API BTAPI
+#define BNEP_API BTAPI
+#define BPP_API BTAPI
+#define BTM_API BTAPI
+#define CTP_API BTAPI
+#define DUN_API BTAPI
+#define FTP_API BTAPI
+#define GAP_API BTAPI
+#define GOEP_API BTAPI
+#define HCI_API BTAPI
+#define HCRP_API BTAPI
+#define HID_API BTAPI
+#define HFP_API BTAPI
+#define HSP2_API BTAPI
+#define ICP_API BTAPI
+#define L2C_API BTAPI
+#define OBX_API BTAPI
+#define OPP_API BTAPI
+#define PAN_API BTAPI
+#define RFC_API BTAPI
+#define RPC_API BTAPI
+#define SDP_API BTAPI
+#define SPP_API BTAPI
+#define TCS_API BTAPI
+#define XML_API BTAPI
+#define BTA_API BTAPI
+#define SBC_API BTAPI
+#define MCE_API BTAPI
+#define MCA_API BTAPI
+#define GATT_API BTAPI
+#define SMP_API BTAPI
+
+
+/******************************************************************************
+**
+** GKI Buffer Pools
+**
+******************************************************************************/
+
+/* Receives HCI events from the lower-layer. */
+#ifndef HCI_CMD_POOL_ID
+#define HCI_CMD_POOL_ID GKI_POOL_ID_2
+#endif
+
+#ifndef HCI_CMD_POOL_BUF_SIZE
+#define HCI_CMD_POOL_BUF_SIZE GKI_BUF2_SIZE
+#endif
+
+/* Receives ACL data packets from thelower-layer. */
+#ifndef HCI_ACL_POOL_ID
+#define HCI_ACL_POOL_ID GKI_POOL_ID_3
+#endif
+
+#ifndef HCI_ACL_POOL_BUF_SIZE
+#define HCI_ACL_POOL_BUF_SIZE GKI_BUF3_SIZE
+#endif
+
+/* Maximum number of buffers available for ACL receive data. */
+#ifndef HCI_ACL_BUF_MAX
+#define HCI_ACL_BUF_MAX GKI_BUF3_MAX
+#endif
+
+/* Receives SCO data packets from the lower-layer. */
+#ifndef HCI_SCO_POOL_ID
+#define HCI_SCO_POOL_ID GKI_POOL_ID_6
+#endif
+
+/* Not used. */
+#ifndef HCI_DATA_DESCR_POOL_ID
+#define HCI_DATA_DESCR_POOL_ID GKI_POOL_ID_0
+#endif
+
+/* Sends SDP data packets. */
+#ifndef SDP_POOL_ID
+#define SDP_POOL_ID GKI_POOL_ID_3
+#endif
+
+/* Sends RFCOMM command packets. */
+#ifndef RFCOMM_CMD_POOL_ID
+#define RFCOMM_CMD_POOL_ID GKI_POOL_ID_2
+#endif
+
+#ifndef RFCOMM_CMD_POOL_BUF_SIZE
+#define RFCOMM_CMD_POOL_BUF_SIZE GKI_BUF2_SIZE
+#endif
+
+/* Sends RFCOMM data packets. */
+#ifndef RFCOMM_DATA_POOL_ID
+#define RFCOMM_DATA_POOL_ID GKI_POOL_ID_3
+#endif
+
+#ifndef RFCOMM_DATA_POOL_BUF_SIZE
+#define RFCOMM_DATA_POOL_BUF_SIZE GKI_BUF3_SIZE
+#endif
+
+/* Sends L2CAP packets to the peer and HCI messages to the controller. */
+#ifndef L2CAP_CMD_POOL_ID
+#define L2CAP_CMD_POOL_ID GKI_POOL_ID_2
+#endif
+
+/* Sends L2CAP segmented packets in ERTM mode */
+#ifndef L2CAP_FCR_TX_POOL_ID
+#define L2CAP_FCR_TX_POOL_ID HCI_ACL_POOL_ID
+#endif
+
+/* Receives L2CAP segmented packets in ERTM mode */
+#ifndef L2CAP_FCR_RX_POOL_ID
+#define L2CAP_FCR_RX_POOL_ID HCI_ACL_POOL_ID
+#endif
+
+/* Used by BTM when it sends HCI commands to the controller. */
+#ifndef BTM_CMD_POOL_ID
+#define BTM_CMD_POOL_ID GKI_POOL_ID_2
+#endif
+
+/* Sends TCS messages. */
+#ifndef TCS_MSG_POOL_ID
+#define TCS_MSG_POOL_ID GKI_POOL_ID_2
+#endif
+
+#ifndef OBX_CMD_POOL_SIZE
+#define OBX_CMD_POOL_SIZE GKI_BUF2_SIZE
+#endif
+
+#ifndef OBX_LRG_DATA_POOL_SIZE
+#define OBX_LRG_DATA_POOL_SIZE GKI_BUF4_SIZE
+#endif
+
+#ifndef OBX_LRG_DATA_POOL_ID
+#define OBX_LRG_DATA_POOL_ID GKI_POOL_ID_4
+#endif
+
+/* Used for CTP discovery database. */
+#ifndef CTP_SDP_DB_POOL_ID
+#define CTP_SDP_DB_POOL_ID GKI_POOL_ID_3
+#endif
+
+/* Used for CTP data exchange feature. */
+#ifndef CTP_DATA_EXCHG_POOL_ID
+#define CTP_DATA_EXCHG_POOL_ID GKI_POOL_ID_2
+#endif
+
+/* Used to send data to L2CAP. */
+#ifndef GAP_DATA_POOL_ID
+#define GAP_DATA_POOL_ID GKI_POOL_ID_3
+#endif
+
+/* Used for SPP inquiry and discovery databases. */
+#ifndef SPP_DB_POOL_ID
+#define SPP_DB_POOL_ID GKI_POOL_ID_3
+#endif
+
+#ifndef SPP_DB_SIZE
+#define SPP_DB_SIZE GKI_BUF3_SIZE
+#endif
+
+/* HCRP protocol and internal commands. */
+#ifndef HCRP_CMD_POOL_ID
+#define HCRP_CMD_POOL_ID GKI_POOL_ID_2
+#endif
+
+#ifndef HCRP_CMD_POOL_SIZE
+#define HCRP_CMD_POOL_SIZE GKI_BUF2_SIZE
+#endif
+
+#ifndef BIP_EVT_POOL_SIZE
+#define BIP_EVT_POOL_SIZE GKI_BUF3_SIZE
+#endif
+
+#ifndef BIP_DB_SIZE
+#define BIP_DB_SIZE GKI_BUF3_SIZE
+#endif
+
+
+/* BNEP data and protocol messages. */
+#ifndef BNEP_POOL_ID
+#define BNEP_POOL_ID GKI_POOL_ID_3
+#endif
+
+/* RPC pool for temporary trace message buffers. */
+#ifndef RPC_SCRATCH_POOL_ID
+#define RPC_SCRATCH_POOL_ID GKI_POOL_ID_2
+#endif
+
+/* RPC scratch buffer size (not related to RPC_SCRATCH_POOL_ID) */
+#ifndef RPC_SCRATCH_BUF_SIZE
+#define RPC_SCRATCH_BUF_SIZE GKI_BUF3_SIZE
+#endif
+
+/* RPC pool for protocol messages */
+#ifndef RPC_MSG_POOL_ID
+#define RPC_MSG_POOL_ID GKI_POOL_ID_3
+#endif
+
+#ifndef RPC_MSG_POOL_SIZE
+#define RPC_MSG_POOL_SIZE GKI_BUF3_SIZE
+#endif
+
+/* AVDTP pool for protocol messages */
+#ifndef AVDT_CMD_POOL_ID
+#define AVDT_CMD_POOL_ID GKI_POOL_ID_2
+#endif
+
+/* AVDTP pool size for media packets in case of fragmentation */
+#ifndef AVDT_DATA_POOL_SIZE
+#define AVDT_DATA_POOL_SIZE GKI_BUF3_SIZE
+#endif
+
+#ifndef PAN_POOL_ID
+#define PAN_POOL_ID GKI_POOL_ID_3
+#endif
+
+/* UNV pool for read/write serialization */
+#ifndef UNV_MSG_POOL_ID
+#define UNV_MSG_POOL_ID GKI_POOL_ID_2
+#endif
+
+#ifndef UNV_MSG_POOL_SIZE
+#define UNV_MSG_POOL_SIZE GKI_BUF2_SIZE
+#endif
+
+/* AVCTP pool for protocol messages */
+#ifndef AVCT_CMD_POOL_ID
+#define AVCT_CMD_POOL_ID GKI_POOL_ID_1
+#endif
+
+#ifndef AVCT_META_CMD_POOL_ID
+#define AVCT_META_CMD_POOL_ID GKI_POOL_ID_2
+#endif
+
+/* AVRCP pool for protocol messages */
+#ifndef AVRC_CMD_POOL_ID
+#define AVRC_CMD_POOL_ID GKI_POOL_ID_1
+#endif
+
+/* AVRCP pool size for protocol messages */
+#ifndef AVRC_CMD_POOL_SIZE
+#define AVRC_CMD_POOL_SIZE GKI_BUF1_SIZE
+#endif
+
+/* AVRCP Metadata pool for protocol messages */
+#ifndef AVRC_META_CMD_POOL_ID
+#define AVRC_META_CMD_POOL_ID GKI_POOL_ID_2
+#endif
+
+/* AVRCP Metadata pool size for protocol messages */
+#ifndef AVRC_META_CMD_POOL_SIZE
+#define AVRC_META_CMD_POOL_SIZE GKI_BUF2_SIZE
+#endif
+
+
+/* AVRCP buffer size for browsing channel messages */
+#ifndef AVRC_BROWSE_POOL_SIZE
+#define AVRC_BROWSE_POOL_SIZE GKI_MAX_BUF_SIZE
+#endif
+
+/* HDP buffer size for the Pulse Oximeter */
+#ifndef BTA_HL_LRG_DATA_POOL_SIZE
+#define BTA_HL_LRG_DATA_POOL_SIZE GKI_BUF7_SIZE
+#endif
+
+#ifndef BTA_HL_LRG_DATA_POOL_ID
+#define BTA_HL_LRG_DATA_POOL_ID GKI_POOL_ID_7
+#endif
+
+/* GATT Server Database pool ID */
+#ifndef GATT_DB_POOL_ID
+#define GATT_DB_POOL_ID GKI_POOL_ID_8
+#endif
+
+/******************************************************************************
+**
+** Lower Layer Interface
+**
+******************************************************************************/
+
+/* Sends ACL data received over HCI to the upper stack. */
+#ifndef HCI_ACL_DATA_TO_UPPER
+#define HCI_ACL_DATA_TO_UPPER(p) {((BT_HDR *)p)->event = BT_EVT_TO_BTU_HCI_ACL; GKI_send_msg (BTU_TASK, BTU_HCI_RCV_MBOX, p);}
+#endif
+
+/* Sends SCO data received over HCI to the upper stack. */
+#ifndef HCI_SCO_DATA_TO_UPPER
+#define HCI_SCO_DATA_TO_UPPER(p) {((BT_HDR *)p)->event = BT_EVT_TO_BTU_HCI_SCO; GKI_send_msg (BTU_TASK, BTU_HCI_RCV_MBOX, p);}
+#endif
+
+/* Sends an HCI event received over HCI to theupper stack. */
+#ifndef HCI_EVT_TO_UPPER
+#define HCI_EVT_TO_UPPER(p) {((BT_HDR *)p)->event = BT_EVT_TO_BTU_HCI_EVT; GKI_send_msg (BTU_TASK, BTU_HCI_RCV_MBOX, p);}
+#endif
+
+/* Macro for allocating buffer for HCI commands */
+#ifndef HCI_GET_CMD_BUF
+#if (!defined(HCI_USE_VARIABLE_SIZE_CMD_BUF) || (HCI_USE_VARIABLE_SIZE_CMD_BUF == FALSE))
+/* Allocate fixed-size buffer from HCI_CMD_POOL (default case) */
+#define HCI_GET_CMD_BUF(paramlen) ((BT_HDR *)GKI_getpoolbuf (HCI_CMD_POOL_ID))
+#else
+/* Allocate smallest possible buffer (for platforms with limited RAM) */
+#define HCI_GET_CMD_BUF(paramlen) ((BT_HDR *)GKI_getbuf ((UINT16)(BT_HDR_SIZE + HCIC_PREAMBLE_SIZE + (paramlen))))
+#endif
+#endif /* HCI_GET_CMD_BUF */
+
+/******************************************************************************
+**
+** HCI Services (H4)
+**
+******************************************************************************/
+#ifndef HCISU_H4_INCLUDED
+#define HCISU_H4_INCLUDED FALSE
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+BT_API extern void bte_main_hci_send (BT_HDR *p_msg, UINT16 event);
+#if (HCISU_H4_INCLUDED == TRUE)
+BT_API extern void bte_main_lpm_allow_bt_device_sleep(void);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+/* Sends ACL data received from the upper stack to the BD/EDR HCI transport. */
+#ifndef HCI_ACL_DATA_TO_LOWER
+#define HCI_ACL_DATA_TO_LOWER(p) bte_main_hci_send((BT_HDR *)(p), BT_EVT_TO_LM_HCI_ACL);
+#endif
+
+#ifndef HCI_BLE_ACL_DATA_TO_LOWER
+#define HCI_BLE_ACL_DATA_TO_LOWER(p) bte_main_hci_send((BT_HDR *)(p), (UINT16)(BT_EVT_TO_LM_HCI_ACL|LOCAL_BLE_CONTROLLER_ID));
+#endif
+
+/* Sends SCO data received from the upper stack to the HCI transport. */
+#ifndef HCI_SCO_DATA_TO_LOWER
+#define HCI_SCO_DATA_TO_LOWER(p) bte_main_hci_send((BT_HDR *)(p), BT_EVT_TO_LM_HCI_SCO);
+#endif
+
+/* Sends an HCI command received from the upper stack to the BD/EDR HCI transport. */
+#ifndef HCI_CMD_TO_LOWER
+#define HCI_CMD_TO_LOWER(p) bte_main_hci_send((BT_HDR *)(p), BT_EVT_TO_LM_HCI_CMD);
+#endif
+
+/* Sends an LM Diagnosic command received from the upper stack to the HCI transport. */
+#ifndef HCI_LM_DIAG_TO_LOWER
+#define HCI_LM_DIAG_TO_LOWER(p) bte_main_hci_send((BT_HDR *)(p), BT_EVT_TO_LM_DIAG);
+#endif
+
+/* Send HCISU a message to allow BT sleep */
+#ifndef HCI_LP_ALLOW_BT_DEVICE_SLEEP
+#define HCI_LP_ALLOW_BT_DEVICE_SLEEP() bte_main_lpm_allow_bt_device_sleep()
+#endif
+
+/* If nonzero, the upper-layer sends at most this number of HCI commands to the lower-layer. */
+#ifndef HCI_MAX_SIMUL_CMDS
+#define HCI_MAX_SIMUL_CMDS 0
+#endif
+
+/* Timeout for receiving response to HCI command */
+#ifndef BTU_CMD_CMPL_TIMEOUT
+#define BTU_CMD_CMPL_TIMEOUT 8
+#endif
+
+/* If TRUE, BTU task will check HCISU again when HCI command timer expires */
+#ifndef BTU_CMD_CMPL_TOUT_DOUBLE_CHECK
+#define BTU_CMD_CMPL_TOUT_DOUBLE_CHECK FALSE
+#endif
+
+/* Use 2 second for low-resolution systems, override to 1 for high-resolution systems */
+#ifndef BT_1SEC_TIMEOUT
+#define BT_1SEC_TIMEOUT (2)
+#endif
+
+/* Quick Timer */
+/* if L2CAP_FCR_INCLUDED is TRUE then it should have 100 millisecond resolution */
+/* if none of them is included then QUICK_TIMER_TICKS_PER_SEC is set to 0 to exclude quick timer */
+#ifndef QUICK_TIMER_TICKS_PER_SEC
+#define QUICK_TIMER_TICKS_PER_SEC 100 /* 10ms timer */
+#endif
+
+/******************************************************************************
+**
+** BTM
+**
+******************************************************************************/
+/* if set to TRUE, stack will automatically send an HCI reset at start-up. To be
+set to FALSE for advanced start-up / shut-down procedures using USER_HW_ENABLE_API
+and USER_HW_DISABLE_API macros */
+#ifndef BTM_AUTOMATIC_HCI_RESET
+#define BTM_AUTOMATIC_HCI_RESET TRUE
+#endif
+
+/* Include BTM Discovery database and code. */
+#ifndef BTM_DISCOVERY_INCLUDED
+#define BTM_DISCOVERY_INCLUDED TRUE
+#endif
+
+/* Include inquiry code. */
+#ifndef BTM_INQUIRY_INCLUDED
+#define BTM_INQUIRY_INCLUDED TRUE
+#endif
+
+/* Cancel Inquiry on incoming SSP */
+#ifndef BTM_NO_SSP_ON_INQUIRY
+#define BTM_NO_SSP_ON_INQUIRY FALSE
+#endif
+
+/* Include periodic inquiry code (used when BTM_INQUIRY_INCLUDED is TRUE). */
+#ifndef BTM_PERIODIC_INQ_INCLUDED
+#define BTM_PERIODIC_INQ_INCLUDED TRUE
+#endif
+
+/* Include security authorization code */
+#ifndef BTM_AUTHORIZATION_INCLUDED
+#define BTM_AUTHORIZATION_INCLUDED TRUE
+#endif
+
+/* Includes SCO if TRUE */
+#ifndef BTM_SCO_INCLUDED
+#define BTM_SCO_INCLUDED TRUE /* TRUE includes SCO code */
+#endif
+
+/* Includes SCO if TRUE */
+#ifndef BTM_SCO_HCI_INCLUDED
+#define BTM_SCO_HCI_INCLUDED FALSE /* TRUE includes SCO over HCI code */
+#endif
+
+/* Includes WBS if TRUE */
+#ifndef BTM_WBS_INCLUDED
+#define BTM_WBS_INCLUDED TRUE /* TRUE includes WBS code */
+#endif
+
+/* Includes PCM2 support if TRUE */
+#ifndef BTM_PCM2_INCLUDED
+#define BTM_PCM2_INCLUDED FALSE
+#endif
+
+/* This is used to work around a controller bug that doesn't like Disconnect
+** issued while there is a role switch in progress
+*/
+#ifndef BTM_DISC_DURING_RS
+#define BTM_DISC_DURING_RS FALSE
+#endif
+
+/**************************
+** Initial SCO TX credit
+*************************/
+/* max TX SCO data packet size */
+#ifndef BTM_SCO_DATA_SIZE_MAX
+#define BTM_SCO_DATA_SIZE_MAX 240
+#endif
+
+/* maximum BTM buffering capacity */
+#ifndef BTM_SCO_MAX_BUF_CAP
+#define BTM_SCO_MAX_BUF_CAP (BTM_SCO_INIT_XMIT_CREDIT * 4)
+#endif
+
+/* The size in bytes of the BTM inquiry database. */
+#ifndef BTM_INQ_DB_SIZE
+#define BTM_INQ_DB_SIZE 12
+#endif
+
+/* This is set to enable automatic periodic inquiry at startup. */
+#ifndef BTM_ENABLE_AUTO_INQUIRY
+#define BTM_ENABLE_AUTO_INQUIRY FALSE
+#endif
+
+/* This is set to always try to acquire the remote device name. */
+#ifndef BTM_INQ_GET_REMOTE_NAME
+#define BTM_INQ_GET_REMOTE_NAME FALSE
+#endif
+
+/* The inquiry duration in 1.28 second units when auto inquiry is enabled. */
+#ifndef BTM_DEFAULT_INQ_DUR
+#define BTM_DEFAULT_INQ_DUR 5
+#endif
+
+/* The inquiry mode when auto inquiry is enabled. */
+#ifndef BTM_DEFAULT_INQ_MODE
+#define BTM_DEFAULT_INQ_MODE BTM_GENERAL_INQUIRY
+#endif
+
+/* The default periodic inquiry maximum delay when auto inquiry is enabled, in 1.28 second units. */
+#ifndef BTM_DEFAULT_INQ_MAX_DELAY
+#define BTM_DEFAULT_INQ_MAX_DELAY 30
+#endif
+
+/* The default periodic inquiry minimum delay when auto inquiry is enabled, in 1.28 second units. */
+#ifndef BTM_DEFAULT_INQ_MIN_DELAY
+#define BTM_DEFAULT_INQ_MIN_DELAY 20
+#endif
+
+/* The maximum age of entries in inquiry database in seconds ('0' disables feature). */
+#ifndef BTM_INQ_MAX_AGE
+#define BTM_INQ_MAX_AGE 0
+#endif
+
+/* The maximum age of entries in inquiry database based on inquiry response failure ('0' disables feature). */
+#ifndef BTM_INQ_AGE_BY_COUNT
+#define BTM_INQ_AGE_BY_COUNT 0
+#endif
+
+/* TRUE if controller does not support inquiry event filtering. */
+#ifndef BTM_BYPASS_EVENT_FILTERING
+#define BTM_BYPASS_EVENT_FILTERING FALSE
+#endif
+
+/* TRUE if inquiry filtering is desired from BTM. */
+#ifndef BTM_USE_INQ_RESULTS_FILTER
+#define BTM_USE_INQ_RESULTS_FILTER TRUE
+#endif
+
+/* The default scan mode */
+#ifndef BTM_DEFAULT_SCAN_TYPE
+#define BTM_DEFAULT_SCAN_TYPE BTM_SCAN_TYPE_INTERLACED
+#endif
+
+/* Should connections to unknown devices be allowed when not discoverable? */
+#ifndef BTM_ALLOW_CONN_IF_NONDISCOVER
+#define BTM_ALLOW_CONN_IF_NONDISCOVER FALSE
+#endif
+
+/* When connectable mode is set to TRUE, the device will respond to paging. */
+#ifndef BTM_IS_CONNECTABLE
+#define BTM_IS_CONNECTABLE FALSE
+#endif
+
+/* Sets the Page_Scan_Window: the length of time that the device is performing a page scan. */
+#ifndef BTM_DEFAULT_CONN_WINDOW
+#define BTM_DEFAULT_CONN_WINDOW 0x0012
+#endif
+
+/* Sets the Page_Scan_Activity: the interval between the start of two consecutive page scans. */
+#ifndef BTM_DEFAULT_CONN_INTERVAL
+#define BTM_DEFAULT_CONN_INTERVAL 0x0800
+#endif
+
+/* This is set to automatically perform inquiry scan on startup. */
+#ifndef BTM_IS_DISCOVERABLE
+#define BTM_IS_DISCOVERABLE FALSE
+#endif
+
+/* When automatic inquiry scan is enabled, this sets the discovery mode. */
+#ifndef BTM_DEFAULT_DISC_MODE
+#define BTM_DEFAULT_DISC_MODE BTM_GENERAL_DISCOVERABLE
+#endif
+
+/* When automatic inquiry scan is enabled, this sets the inquiry scan window. */
+#ifndef BTM_DEFAULT_DISC_WINDOW
+#define BTM_DEFAULT_DISC_WINDOW 0x0012
+#endif
+
+/* When automatic inquiry scan is enabled, this sets the inquiry scan interval. */
+#ifndef BTM_DEFAULT_DISC_INTERVAL
+#define BTM_DEFAULT_DISC_INTERVAL 0x0800
+#endif
+
+/* Sets the period, in seconds, to automatically perform service discovery. */
+#ifndef BTM_AUTO_DISCOVERY_PERIOD
+#define BTM_AUTO_DISCOVERY_PERIOD 0
+#endif
+
+/* The size in bytes of the BTM discovery database (if discovery is included). */
+#ifndef BTM_DISCOVERY_DB_SIZE
+#define BTM_DISCOVERY_DB_SIZE 4000
+#endif
+
+/* Number of milliseconds to delay BTU task startup upon device initialization. */
+#ifndef BTU_STARTUP_DELAY
+#define BTU_STARTUP_DELAY 0
+#endif
+
+/* Whether BTA is included in BTU task. */
+#ifndef BTU_BTA_INCLUDED
+#define BTU_BTA_INCLUDED FALSE
+#endif
+
+/* Number of seconds to wait to send an HCI Reset command upon device initialization. */
+#ifndef BTM_FIRST_RESET_DELAY
+#define BTM_FIRST_RESET_DELAY 0
+#endif
+
+/* The number of seconds to wait for controller module to reset after issuing an HCI Reset command. */
+#ifndef BTM_AFTER_RESET_TIMEOUT
+#define BTM_AFTER_RESET_TIMEOUT 0
+#endif
+
+/* The default class of device. */
+#ifndef BTM_INIT_CLASS_OF_DEVICE
+#define BTM_INIT_CLASS_OF_DEVICE "\x00\x1F\x00"
+#endif
+
+/* The number of SCO links. */
+#ifndef BTM_MAX_SCO_LINKS
+#define BTM_MAX_SCO_LINKS 3
+#endif
+
+/* The preferred type of SCO links (2-eSCO, 0-SCO). */
+#ifndef BTM_DEFAULT_SCO_MODE
+#define BTM_DEFAULT_SCO_MODE 2
+#endif
+
+/* The number of security records for peer devices. */
+#ifndef BTM_SEC_MAX_DEVICE_RECORDS
+#define BTM_SEC_MAX_DEVICE_RECORDS 8
+#endif
+
+/* The number of security records for services. */
+#ifndef BTM_SEC_MAX_SERVICE_RECORDS
+#define BTM_SEC_MAX_SERVICE_RECORDS 30
+#endif
+
+/* If True, force a retrieval of remote device name for each bond in case it's changed */
+#ifndef BTM_SEC_FORCE_RNR_FOR_DBOND
+#define BTM_SEC_FORCE_RNR_FOR_DBOND TRUE
+#endif
+
+/* Maximum device name length used in btm database. */
+#ifndef BTM_MAX_REM_BD_NAME_LEN
+#define BTM_MAX_REM_BD_NAME_LEN 20
+#endif
+
+/* Maximum local device name length stored btm database.
+ '0' disables storage of the local name in BTM */
+#ifndef BTM_MAX_LOC_BD_NAME_LEN
+#define BTM_MAX_LOC_BD_NAME_LEN 31
+#endif
+
+/* TRUE if default string is used, FALSE if device name is set in the application */
+#ifndef BTM_USE_DEF_LOCAL_NAME
+#define BTM_USE_DEF_LOCAL_NAME FALSE
+#endif
+
+/* Fixed Default String (Ignored if BTM_USE_DEF_LOCAL_NAME is FALSE) */
+#ifndef BTM_DEF_LOCAL_NAME
+#define BTM_DEF_LOCAL_NAME ""
+#endif
+
+/* Maximum service name stored with security authorization (0 if not needed) */
+#ifndef BTM_SEC_SERVICE_NAME_LEN
+#define BTM_SEC_SERVICE_NAME_LEN BT_MAX_SERVICE_NAME_LEN
+#endif
+
+/* Maximum number of pending security callback */
+#ifndef BTM_SEC_MAX_CALLBACKS
+#define BTM_SEC_MAX_CALLBACKS 7
+#endif
+
+/* Maximum length of the service name. */
+#ifndef BT_MAX_SERVICE_NAME_LEN
+#define BT_MAX_SERVICE_NAME_LEN 21
+#endif
+
+/* ACL buffer size in HCI Host Buffer Size command. */
+#ifndef BTM_ACL_BUF_SIZE
+#define BTM_ACL_BUF_SIZE 0
+#endif
+
+/* This is set to use the BTM power manager. */
+#ifndef BTM_PWR_MGR_INCLUDED
+#define BTM_PWR_MGR_INCLUDED TRUE
+#endif
+
+/* The maximum number of clients that can register with the power manager. */
+#ifndef BTM_MAX_PM_RECORDS
+#define BTM_MAX_PM_RECORDS 2
+#endif
+
+/* This is set to show debug trace messages for the power manager. */
+#ifndef BTM_PM_DEBUG
+#define BTM_PM_DEBUG FALSE
+#endif
+
+/* This is set to TRUE if link is to be unparked due to BTM_CreateSCO API. */
+#ifndef BTM_SCO_WAKE_PARKED_LINK
+#define BTM_SCO_WAKE_PARKED_LINK TRUE
+#endif
+
+/* May be set to the the name of a function used for vendor specific chip initialization */
+#ifndef BTM_APP_DEV_INIT
+/* #define BTM_APP_DEV_INIT myInitFunction() */
+#endif
+
+/* This is set to TRUE if the busy level change event is desired. (replace ACL change event) */
+#ifndef BTM_BUSY_LEVEL_CHANGE_INCLUDED
+#define BTM_BUSY_LEVEL_CHANGE_INCLUDED TRUE
+#endif
+
+/* If the user does not respond to security process requests within this many seconds,
+ * a negative response would be sent automatically.
+ * It's recommended to use a value between 30 and OBX_TIMEOUT_VALUE
+ * 30 is LMP response timeout value */
+#ifndef BTM_SEC_TIMEOUT_VALUE
+#define BTM_SEC_TIMEOUT_VALUE 35
+#endif
+
+/* Maximum number of callbacks that can be registered using BTM_RegisterForVSEvents */
+#ifndef BTM_MAX_VSE_CALLBACKS
+#define BTM_MAX_VSE_CALLBACKS 3
+#endif
+
+/* Number of streams for dual stack */
+#ifndef BTM_SYNC_INFO_NUM_STR
+#define BTM_SYNC_INFO_NUM_STR 2
+#endif
+
+/* Number of streams for dual stack in BT Controller */
+#ifndef BTM_SYNC_INFO_NUM_STR_BTC
+#define BTM_SYNC_INFO_NUM_STR_BTC 2
+#endif
+
+/******************************************
+** Lisbon Features
+*******************************************/
+/* This is set to TRUE if the server Extended Inquiry Response feature is desired. */
+/* server sends EIR to client */
+#ifndef BTM_EIR_SERVER_INCLUDED
+#define BTM_EIR_SERVER_INCLUDED TRUE
+#endif
+
+/* This is set to TRUE if the client Extended Inquiry Response feature is desired. */
+/* client inquiry to server */
+#ifndef BTM_EIR_CLIENT_INCLUDED
+#define BTM_EIR_CLIENT_INCLUDED TRUE
+#endif
+
+/* This is set to TRUE if the FEC is required for EIR packet. */
+#ifndef BTM_EIR_DEFAULT_FEC_REQUIRED
+#define BTM_EIR_DEFAULT_FEC_REQUIRED TRUE
+#endif
+
+/* User defined UUID look up table */
+#ifndef BTM_EIR_UUID_LKUP_TBL
+#endif
+
+/* The IO capability of the local device (for Simple Pairing) */
+#ifndef BTM_LOCAL_IO_CAPS
+#define BTM_LOCAL_IO_CAPS BTM_IO_CAP_IO
+#endif
+
+/* The default MITM Protection Requirement (for Simple Pairing)
+ * Possible values are BTM_AUTH_SP_YES or BTM_AUTH_SP_NO */
+#ifndef BTM_DEFAULT_AUTH_REQ
+#define BTM_DEFAULT_AUTH_REQ BTM_AUTH_SP_NO
+#endif
+
+/* The default MITM Protection Requirement for dedicated bonding using Simple Pairing
+ * Possible values are BTM_AUTH_AP_YES or BTM_AUTH_AP_NO */
+#ifndef BTM_DEFAULT_DD_AUTH_REQ
+#define BTM_DEFAULT_DD_AUTH_REQ BTM_AUTH_AP_YES
+#endif
+
+/* Include Out-of-Band implementation for Simple Pairing */
+#ifndef BTM_OOB_INCLUDED
+#define BTM_OOB_INCLUDED TRUE
+#endif
+
+/* TRUE to include Sniff Subrating */
+#ifndef BTM_SSR_INCLUDED
+#define BTM_SSR_INCLUDED TRUE
+#endif
+
+/*************************
+** End of Lisbon Features
+**************************/
+
+/* Used for conformance testing ONLY */
+#ifndef BTM_BLE_CONFORMANCE_TESTING
+#define BTM_BLE_CONFORMANCE_TESTING FALSE
+#endif
+
+
+/******************************************************************************
+**
+** L2CAP
+**
+******************************************************************************/
+
+/* Flow control and retransmission mode */
+
+#ifndef L2CAP_FCR_INCLUDED
+#define L2CAP_FCR_INCLUDED FALSE
+#endif
+
+/* The maximum number of simultaneous links that L2CAP can support. */
+#ifndef MAX_L2CAP_LINKS
+#define MAX_L2CAP_LINKS 4
+#endif
+
+/* The maximum number of simultaneous channels that L2CAP can support. */
+#ifndef MAX_L2CAP_CHANNELS
+#define MAX_L2CAP_CHANNELS 10
+#endif
+
+/* The maximum number of simultaneous applications that can register with L2CAP. */
+#ifndef MAX_L2CAP_CLIENTS
+#define MAX_L2CAP_CLIENTS 8
+#endif
+
+/* The number of seconds of link inactivity before a link is disconnected. */
+#ifndef L2CAP_LINK_INACTIVITY_TOUT
+#define L2CAP_LINK_INACTIVITY_TOUT 3
+#endif
+
+/* The number of seconds of link inactivity after bonding before a link is disconnected. */
+#ifndef L2CAP_BONDING_TIMEOUT
+#define L2CAP_BONDING_TIMEOUT 3
+#endif
+
+/* The time from the HCI connection complete to disconnect if no channel is established. */
+#ifndef L2CAP_LINK_STARTUP_TOUT
+#define L2CAP_LINK_STARTUP_TOUT 60
+#endif
+
+/* The L2CAP MTU; must be in accord with the HCI ACL pool size. */
+#ifndef L2CAP_MTU_SIZE
+#define L2CAP_MTU_SIZE 1691
+#endif
+
+/* The L2CAP MPS over Bluetooth; must be in accord with the FCR tx pool size and ACL down buffer size. */
+#ifndef L2CAP_MPS_OVER_BR_EDR
+#define L2CAP_MPS_OVER_BR_EDR 1010
+#endif
+
+/* This is set to enable host flow control. */
+#ifndef L2CAP_HOST_FLOW_CTRL
+#define L2CAP_HOST_FLOW_CTRL FALSE
+#endif
+
+/* If host flow control enabled, this is the number of buffers the controller can have unacknowledged. */
+#ifndef L2CAP_HOST_FC_ACL_BUFS
+#define L2CAP_HOST_FC_ACL_BUFS 20
+#endif
+
+/* The percentage of the queue size allowed before a congestion event is sent to the L2CAP client (typically 120%). */
+#ifndef L2CAP_FWD_CONG_THRESH
+#define L2CAP_FWD_CONG_THRESH 120
+#endif
+
+/* This is set to enable L2CAP to take the ACL link out of park mode when ACL data is to be sent. */
+#ifndef L2CAP_WAKE_PARKED_LINK
+#define L2CAP_WAKE_PARKED_LINK TRUE
+#endif
+
+/* Whether link wants to be the master or the slave. */
+#ifndef L2CAP_DESIRED_LINK_ROLE
+#define L2CAP_DESIRED_LINK_ROLE HCI_ROLE_SLAVE
+#endif
+
+/* Include Non-Flushable Packet Boundary Flag feature of Lisbon */
+#ifndef L2CAP_NON_FLUSHABLE_PB_INCLUDED
+#define L2CAP_NON_FLUSHABLE_PB_INCLUDED TRUE
+#endif
+
+/* Minimum number of ACL credit for high priority link */
+#ifndef L2CAP_HIGH_PRI_MIN_XMIT_QUOTA
+#define L2CAP_HIGH_PRI_MIN_XMIT_QUOTA 4
+#endif
+
+/* used for monitoring HCI ACL credit management */
+#ifndef L2CAP_HCI_FLOW_CONTROL_DEBUG
+#define L2CAP_HCI_FLOW_CONTROL_DEBUG TRUE
+#endif
+
+/* Used for calculating transmit buffers off of */
+#ifndef L2CAP_NUM_XMIT_BUFFS
+#define L2CAP_NUM_XMIT_BUFFS HCI_ACL_BUF_MAX
+#endif
+
+/* Unicast Connectionless Data */
+#ifndef L2CAP_UCD_INCLUDED
+#define L2CAP_UCD_INCLUDED FALSE
+#endif
+
+/* Unicast Connectionless Data MTU */
+#ifndef L2CAP_UCD_MTU
+#define L2CAP_UCD_MTU L2CAP_MTU_SIZE
+#endif
+
+/* Unicast Connectionless Data Idle Timeout */
+#ifndef L2CAP_UCD_IDLE_TIMEOUT
+#define L2CAP_UCD_IDLE_TIMEOUT 2
+#endif
+
+/* Unicast Connectionless Data Idle Timeout */
+#ifndef L2CAP_UCD_CH_PRIORITY
+#define L2CAP_UCD_CH_PRIORITY L2CAP_CHNL_PRIORITY_MEDIUM
+#endif
+
+/* Max clients on Unicast Connectionless Data */
+#ifndef L2CAP_MAX_UCD_CLIENTS
+#define L2CAP_MAX_UCD_CLIENTS 5
+#endif
+
+/* Used for features using fixed channels; set to zero if no fixed channels supported (BLE, etc.) */
+/* Excluding L2CAP signaling channel and UCD */
+#ifndef L2CAP_NUM_FIXED_CHNLS
+#define L2CAP_NUM_FIXED_CHNLS 4
+#endif
+
+/* First fixed channel supported */
+#ifndef L2CAP_FIRST_FIXED_CHNL
+#define L2CAP_FIRST_FIXED_CHNL 3
+#endif
+
+#ifndef L2CAP_LAST_FIXED_CHNL
+#define L2CAP_LAST_FIXED_CHNL (L2CAP_FIRST_FIXED_CHNL + L2CAP_NUM_FIXED_CHNLS - 1)
+#endif
+
+/* Round Robin service channels in link */
+#ifndef L2CAP_ROUND_ROBIN_CHANNEL_SERVICE
+#define L2CAP_ROUND_ROBIN_CHANNEL_SERVICE TRUE
+#endif
+
+/* Used for calculating transmit buffers off of */
+#ifndef L2CAP_NUM_XMIT_BUFFS
+#define L2CAP_NUM_XMIT_BUFFS HCI_ACL_BUF_MAX
+#endif
+
+/* Used for features using fixed channels; set to zero if no fixed channels supported (BLE, etc.) */
+#ifndef L2CAP_NUM_FIXED_CHNLS
+#define L2CAP_NUM_FIXED_CHNLS 1
+#endif
+
+/* First fixed channel supported */
+#ifndef L2CAP_FIRST_FIXED_CHNL
+#define L2CAP_FIRST_FIXED_CHNL 3
+#endif
+
+#ifndef L2CAP_LAST_FIXED_CHNL
+#define L2CAP_LAST_FIXED_CHNL (L2CAP_FIRST_FIXED_CHNL + L2CAP_NUM_FIXED_CHNLS - 1)
+#endif
+
+/* used for monitoring eL2CAP data flow */
+#ifndef L2CAP_ERTM_STATS
+#define L2CAP_ERTM_STATS FALSE
+#endif
+
+/* USED FOR FCR TEST ONLY: When TRUE generates bad tx and rx packets */
+#ifndef L2CAP_CORRUPT_ERTM_PKTS
+#define L2CAP_CORRUPT_ERTM_PKTS FALSE
+#endif
+
+/* Used for conformance testing ONLY: When TRUE lets scriptwrapper overwrite info response */
+#ifndef L2CAP_CONFORMANCE_TESTING
+#define L2CAP_CONFORMANCE_TESTING FALSE
+#endif
+
+
+#ifndef TIMER_PARAM_TYPE
+#ifdef WIN2000
+#define TIMER_PARAM_TYPE void *
+#else
+#define TIMER_PARAM_TYPE UINT32
+#endif
+#endif
+
+/******************************************************************************
+**
+** BLE
+**
+******************************************************************************/
+
+#ifndef BLE_INCLUDED
+#define BLE_INCLUDED FALSE
+#endif
+
+#ifndef LOCAL_BLE_CONTROLLER_ID
+#define LOCAL_BLE_CONTROLLER_ID (1)
+#endif
+
+/******************************************************************************
+**
+** ATT/GATT Protocol/Profile Settings
+**
+******************************************************************************/
+#ifndef ATT_INCLUDED
+#define ATT_INCLUDED FALSE
+#endif
+
+#ifndef ATT_DEBUG
+#define ATT_DEBUG FALSE
+#endif
+
+#ifndef GATT_SERVER_ENABLED
+#define GATT_SERVER_ENABLED FALSE
+#endif
+
+#ifndef GATT_CLIENT_ENABLED
+#define GATT_CLIENT_ENABLED FALSE
+#endif
+
+#ifndef GATT_MAX_SR_PROFILES
+#define GATT_MAX_SR_PROFILES 32 /* max is 32 */
+#endif
+
+#ifndef GATT_MAX_APPS
+#define GATT_MAX_APPS 10 /* note: 2 apps used internally GATT and GAP */
+#endif
+
+#ifndef GATT_MAX_CL_PROFILES
+#define GATT_MAX_CL_PROFILES 4
+#endif
+
+#ifndef GATT_MAX_PHY_CHANNEL
+#define GATT_MAX_PHY_CHANNEL 4
+#endif
+
+/* Used for conformance testing ONLY */
+#ifndef GATT_CONFORMANCE_TESTING
+#define GATT_CONFORMANCE_TESTING FALSE
+#endif
+
+/* number of background connection device allowence, ideally to be the same as WL size
+*/
+#ifndef GATT_MAX_BG_CONN_DEV
+#define GATT_MAX_BG_CONN_DEV 32
+#endif
+
+/******************************************************************************
+**
+** SMP
+**
+******************************************************************************/
+#ifndef SMP_INCLUDED
+#define SMP_INCLUDED FALSE
+#endif
+
+#ifndef SMP_DEBUG
+#define SMP_DEBUG FALSE
+#endif
+
+#ifndef SMP_DEFAULT_AUTH_REQ
+#define SMP_DEFAULT_AUTH_REQ SMP_AUTH_NB_ENC_ONLY
+#endif
+
+#ifndef SMP_MAX_ENC_KEY_SIZE
+#define SMP_MAX_ENC_KEY_SIZE 16
+#endif
+
+#ifndef SMP_MIN_ENC_KEY_SIZE
+#define SMP_MIN_ENC_KEY_SIZE 7
+#endif
+
+/* Used for conformance testing ONLY */
+#ifndef SMP_CONFORMANCE_TESTING
+#define SMP_CONFORMANCE_TESTING FALSE
+#endif
+
+/******************************************************************************
+**
+** SDP
+**
+******************************************************************************/
+
+/* This is set to enable SDP server functionality. */
+#ifndef SDP_SERVER_ENABLED
+#define SDP_SERVER_ENABLED TRUE
+#endif
+
+/* The maximum number of SDP records the server can support. */
+#ifndef SDP_MAX_RECORDS
+#define SDP_MAX_RECORDS 20
+#endif
+
+/* The maximum number of attributes in each record. */
+#ifndef SDP_MAX_REC_ATTR
+#if defined(HID_DEV_INCLUDED) && (HID_DEV_INCLUDED==TRUE)
+#define SDP_MAX_REC_ATTR 25
+#else
+#define SDP_MAX_REC_ATTR 13
+#endif
+#endif
+
+#ifndef SDP_MAX_PAD_LEN
+#define SDP_MAX_PAD_LEN 350
+#endif
+
+/* The maximum length, in bytes, of an attribute. */
+#ifndef SDP_MAX_ATTR_LEN
+#if defined(HID_DEV_INCLUDED) && (HID_DEV_INCLUDED==TRUE)
+#define SDP_MAX_ATTR_LEN 80
+#else
+#define SDP_MAX_ATTR_LEN 100
+#endif
+#endif
+
+/* The maximum number of attribute filters supported by SDP databases. */
+#ifndef SDP_MAX_ATTR_FILTERS
+#define SDP_MAX_ATTR_FILTERS 15
+#endif
+
+/* The maximum number of UUID filters supported by SDP databases. */
+#ifndef SDP_MAX_UUID_FILTERS
+#define SDP_MAX_UUID_FILTERS 3
+#endif
+
+/* This is set to enable SDP client functionality. */
+#ifndef SDP_CLIENT_ENABLED
+#define SDP_CLIENT_ENABLED TRUE
+#endif
+
+/* The maximum number of record handles retrieved in a search. */
+#ifndef SDP_MAX_DISC_SERVER_RECS
+#define SDP_MAX_DISC_SERVER_RECS 21
+#endif
+
+/* The size of a scratchpad buffer, in bytes, for storing the response to an attribute request. */
+#ifndef SDP_MAX_LIST_BYTE_COUNT
+#define SDP_MAX_LIST_BYTE_COUNT 4096
+#endif
+
+/* The maximum number of parameters in an SDP protocol element. */
+#ifndef SDP_MAX_PROTOCOL_PARAMS
+#define SDP_MAX_PROTOCOL_PARAMS 2
+#endif
+
+/* The maximum number of simultaneous client and server connections. */
+#ifndef SDP_MAX_CONNECTIONS
+#define SDP_MAX_CONNECTIONS 4
+#endif
+
+/* The MTU size for the L2CAP configuration. */
+#ifndef SDP_MTU_SIZE
+#define SDP_MTU_SIZE 256
+#endif
+
+/* The flush timeout for the L2CAP configuration. */
+#ifndef SDP_FLUSH_TO
+#define SDP_FLUSH_TO 0xFFFF
+#endif
+
+/* The name for security authorization. */
+#ifndef SDP_SERVICE_NAME
+#define SDP_SERVICE_NAME "Service Discovery"
+#endif
+
+/* The security level for BTM. */
+#ifndef SDP_SECURITY_LEVEL
+#define SDP_SECURITY_LEVEL BTM_SEC_NONE
+#endif
+
+/* Device identification feature. */
+#ifndef SDP_DI_INCLUDED
+#define SDP_DI_INCLUDED FALSE
+#endif
+
+/******************************************************************************
+**
+** RFCOMM
+**
+******************************************************************************/
+
+#ifndef RFCOMM_INCLUDED
+#define RFCOMM_INCLUDED FALSE
+#endif
+
+/* The maximum number of ports supported. */
+#ifndef MAX_RFC_PORTS
+#define MAX_RFC_PORTS 5
+#endif
+
+/* The maximum simultaneous links to different devices. */
+#ifndef MAX_BD_CONNECTIONS
+#define MAX_BD_CONNECTIONS 1
+#endif
+
+/* The port receive queue low watermark level, in bytes. */
+#ifndef PORT_RX_LOW_WM
+#define PORT_RX_LOW_WM 5000
+#endif
+
+/* The port receive queue high watermark level, in bytes. */
+#ifndef PORT_RX_HIGH_WM
+#define PORT_RX_HIGH_WM 8000
+#endif
+
+/* The port receive queue critical watermark level, in bytes. */
+#ifndef PORT_RX_CRITICAL_WM
+#define PORT_RX_CRITICAL_WM 12000
+#endif
+
+/* The port receive queue low watermark level, in number of buffers. */
+#ifndef PORT_RX_BUF_LOW_WM
+#define PORT_RX_BUF_LOW_WM 8
+#endif
+
+/* The port receive queue high watermark level, in number of buffers. */
+#ifndef PORT_RX_BUF_HIGH_WM
+#define PORT_RX_BUF_HIGH_WM 16
+#endif
+
+/* The port receive queue critical watermark level, in number of buffers. */
+#ifndef PORT_RX_BUF_CRITICAL_WM
+#define PORT_RX_BUF_CRITICAL_WM 22
+#endif
+
+/* The port transmit queue high watermark level, in bytes. */
+#ifndef PORT_TX_HIGH_WM
+#define PORT_TX_HIGH_WM 8000
+#endif
+
+/* The port transmit queue critical watermark level, in bytes. */
+#ifndef PORT_TX_CRITICAL_WM
+#define PORT_TX_CRITICAL_WM 10000
+#endif
+
+/* The port transmit queue high watermark level, in number of buffers. */
+#ifndef PORT_TX_BUF_HIGH_WM
+#define PORT_TX_BUF_HIGH_WM 16
+#endif
+
+/* The port transmit queue high watermark level, in number of buffers. */
+#ifndef PORT_TX_BUF_CRITICAL_WM
+#define PORT_TX_BUF_CRITICAL_WM 22
+#endif
+
+/* The RFCOMM multiplexer preferred flow control mechanism. */
+#ifndef PORT_FC_DEFAULT
+#define PORT_FC_DEFAULT PORT_FC_CREDIT
+#endif
+
+/* The maximum number of credits receiver sends to peer when using credit-based flow control. */
+#ifndef PORT_CREDIT_RX_MAX
+#define PORT_CREDIT_RX_MAX 16
+#endif
+
+/* The credit low watermark level. */
+#ifndef PORT_CREDIT_RX_LOW
+#define PORT_CREDIT_RX_LOW 8
+#endif
+
+/* Test code allowing l2cap FEC on RFCOMM.*/
+#ifndef PORT_ENABLE_L2CAP_FCR_TEST
+#define PORT_ENABLE_L2CAP_FCR_TEST FALSE
+#endif
+
+/* if application like BTA, Java or script test engine is running on other than BTU thread, */
+/* PORT_SCHEDULE_LOCK shall be defined as GKI_sched_lock() or GKI_disable() */
+#ifndef PORT_SCHEDULE_LOCK
+#define PORT_SCHEDULE_LOCK GKI_disable()
+#endif
+
+/* if application like BTA, Java or script test engine is running on other than BTU thread, */
+/* PORT_SCHEDULE_LOCK shall be defined as GKI_sched_unlock() or GKI_enable() */
+#ifndef PORT_SCHEDULE_UNLOCK
+#define PORT_SCHEDULE_UNLOCK GKI_enable()
+#endif
+
+/******************************************************************************
+**
+** TCS
+**
+******************************************************************************/
+
+#ifndef TCS_INCLUDED
+#define TCS_INCLUDED FALSE
+#endif
+
+/* If set to TRUE, gives lean TCS state machine configuration. */
+#ifndef TCS_LEAN
+#define TCS_LEAN FALSE
+#endif
+
+/* To include/exclude point-to-multipoint broadcast SETUP configuration. */
+#ifndef TCS_BCST_SETUP_INCLUDED
+#define TCS_BCST_SETUP_INCLUDED TRUE
+#endif
+
+/* To include/exclude supplementary services. */
+#ifndef TCS_SUPP_SVCS_INCLUDED
+#define TCS_SUPP_SVCS_INCLUDED TRUE
+#endif
+
+/* To include/exclude WUG master role. */
+#ifndef TCS_WUG_MASTER_INCLUDED
+#define TCS_WUG_MASTER_INCLUDED TRUE
+#endif
+
+/* To include/exclude WUG member role. */
+#ifndef TCS_WUG_MEMBER_INCLUDED
+#define TCS_WUG_MEMBER_INCLUDED TRUE
+#endif
+
+/* Maximum number of WUG members. */
+#ifndef TCS_MAX_WUG_MEMBERS
+#define TCS_MAX_WUG_MEMBERS 7
+#endif
+
+/* Widcomm specific acknowledgement message to ensure fast and robust operation of WUG FIMA procedure. */
+#ifndef TCS_WUG_LISTEN_ACPT_ACK_INCLUDED
+#define TCS_WUG_LISTEN_ACPT_ACK_INCLUDED TRUE
+#endif
+
+/* The number of simultaneous calls supported. */
+#ifndef TCS_MAX_NUM_SIMUL_CALLS
+#define TCS_MAX_NUM_SIMUL_CALLS 3
+#endif
+
+/* The number of devices the device can connect to. */
+#ifndef TCS_MAX_NUM_ACL_CONNS
+#define TCS_MAX_NUM_ACL_CONNS 7
+#endif
+
+/* The maximum length, in bytes, of the company specific information element. */
+#ifndef TCS_MAX_CO_SPEC_LEN
+#define TCS_MAX_CO_SPEC_LEN 40
+#endif
+
+/* The maximum length, in bytes, of the audio control information element . */
+#ifndef TCS_MAX_AUDIO_CTL_LEN
+#define TCS_MAX_AUDIO_CTL_LEN 40
+#endif
+
+/* (Dis)allow EDR ESCO */
+#ifndef TCS_AUDIO_USE_ESCO_EDR
+#define TCS_AUDIO_USE_ESCO_EDR FALSE
+#endif
+
+/******************************************************************************
+**
+** OBX
+**
+******************************************************************************/
+#ifndef OBX_INCLUDED
+#define OBX_INCLUDED FALSE
+#endif
+
+#ifndef OBX_CLIENT_INCLUDED
+#define OBX_CLIENT_INCLUDED TRUE
+#endif
+
+#ifndef OBX_SERVER_INCLUDED
+#define OBX_SERVER_INCLUDED TRUE
+#endif
+
+/* TRUE to include OBEX authentication/MD5 code */
+#ifndef OBX_MD5_INCLUDED
+#define OBX_MD5_INCLUDED TRUE
+#endif
+
+/* TRUE to include OBEX authentication/MD5 test code */
+#ifndef OBX_MD5_TEST_INCLUDED
+#define OBX_MD5_TEST_INCLUDED FALSE
+#endif
+
+/* TRUE to include OBEX 1.4 enhancement (including Obex Over L2CAP) */
+#ifndef OBX_14_INCLUDED
+#define OBX_14_INCLUDED FALSE
+#endif
+/* MD5 code is required to use OBEX 1.4 features (Reliable session) */
+#if (OBX_MD5_INCLUDED == FALSE)
+#undef OBX_14_INCLUDED
+#define OBX_14_INCLUDED FALSE
+#endif
+
+/* L2CAP FCR/eRTM mode is required to use OBEX Over L2CAP */
+#if (L2CAP_FCR_INCLUDED == FALSE)
+#undef OBX_14_INCLUDED
+#define OBX_14_INCLUDED FALSE
+#endif
+
+/* The timeout value (in seconds) for reliable sessions to remain in suspend. 0xFFFFFFFF for no timeout event. */
+#ifndef OBX_SESS_TIMEOUT_VALUE
+#define OBX_SESS_TIMEOUT_VALUE 600
+#endif
+
+/* The idle timeout value. 0 for no timeout event. */
+#ifndef OBX_TIMEOUT_VALUE
+#define OBX_TIMEOUT_VALUE 60
+#endif
+
+/* Timeout value used for disconnect */
+#ifndef OBX_DISC_TOUT_VALUE
+#define OBX_DISC_TOUT_VALUE 5
+#endif
+
+/* The maximum number of registered servers. */
+#ifndef OBX_NUM_SERVERS
+#define OBX_NUM_SERVERS 12
+#endif
+
+/* The maximum number of sessions per registered server. */
+#ifndef OBX_MAX_SR_SESSION
+#define OBX_MAX_SR_SESSION 4
+#endif
+
+/* The maximum number of sessions for all registered servers.
+ * (must be equal or bigger than OBX_NUM_SERVERS) */
+#ifndef OBX_NUM_SR_SESSIONS
+#define OBX_NUM_SR_SESSIONS 26
+#endif
+
+/* The maximum number of sessions per registered server.
+ * must be less than MAX_BD_CONNECTIONS */
+#ifndef OBX_MAX_SR_SESSION
+#define OBX_MAX_SR_SESSION 4
+#endif
+
+/* The maximum number of suspended sessions per registered servers. */
+#ifndef OBX_MAX_SUSPEND_SESSIONS
+#define OBX_MAX_SUSPEND_SESSIONS 4
+#endif
+
+/* The maximum number of active clients. */
+#ifndef OBX_NUM_CLIENTS
+#define OBX_NUM_CLIENTS 8
+#endif
+
+/* The maximum length of OBEX target header.*/
+#ifndef OBX_MAX_TARGET_LEN
+#define OBX_MAX_TARGET_LEN 16
+#endif
+
+/* The maximum length of authentication challenge realm.*/
+#ifndef OBX_MAX_REALM_LEN
+#define OBX_MAX_REALM_LEN 30
+#endif
+
+/* The maximum of GKI buffer queued at OBX before flow control L2CAP */
+#ifndef OBX_MAX_RX_QUEUE_COUNT
+#define OBX_MAX_RX_QUEUE_COUNT 3
+#endif
+
+/* This option is application when OBX_14_INCLUDED=TRUE
+ Pool ID where to reassemble the SDU.
+ This Pool will allow buffers to be used that are larger than
+ the L2CAP_MAX_MTU. */
+#ifndef OBX_USER_RX_POOL_ID
+#define OBX_USER_RX_POOL_ID OBX_LRG_DATA_POOL_ID
+#endif
+
+/* This option is application when OBX_14_INCLUDED=TRUE
+ Pool ID where to hold the SDU.
+ This Pool will allow buffers to be used that are larger than
+ the L2CAP_MAX_MTU. */
+#ifndef OBX_USER_TX_POOL_ID
+#define OBX_USER_TX_POOL_ID OBX_LRG_DATA_POOL_ID
+#endif
+
+/* This option is application when OBX_14_INCLUDED=TRUE
+GKI Buffer Pool ID used to hold MPS segments during SDU reassembly
+*/
+#ifndef OBX_FCR_RX_POOL_ID
+#define OBX_FCR_RX_POOL_ID HCI_ACL_POOL_ID
+#endif
+
+/* This option is application when OBX_14_INCLUDED=TRUE
+GKI Buffer Pool ID used to hold MPS segments used in (re)transmissions.
+L2CAP_DEFAULT_ERM_POOL_ID is specified to use the HCI ACL data pool.
+Note: This pool needs to have enough buffers to hold two times the window size negotiated
+ in the L2CA_SetFCROptions (2 * tx_win_size) to allow for retransmissions.
+ The size of each buffer must be able to hold the maximum MPS segment size passed in
+ L2CA_SetFCROptions plus BT_HDR (8) + HCI preamble (4) + L2CAP_MIN_OFFSET (11 - as of BT 2.1 + EDR Spec).
+*/
+#ifndef OBX_FCR_TX_POOL_ID
+#define OBX_FCR_TX_POOL_ID HCI_ACL_POOL_ID
+#endif
+
+/* This option is application when OBX_14_INCLUDED=TRUE
+Size of the transmission window when using enhanced retransmission mode. Not used
+in basic and streaming modes. Range: 1 - 63
+*/
+#ifndef OBX_FCR_OPT_TX_WINDOW_SIZE_BR_EDR
+#define OBX_FCR_OPT_TX_WINDOW_SIZE_BR_EDR 20
+#endif
+
+/* This option is application when OBX_14_INCLUDED=TRUE
+Number of transmission attempts for a single I-Frame before taking
+Down the connection. Used In ERTM mode only. Value is Ignored in basic and
+Streaming modes.
+Range: 0, 1-0xFF
+0 - infinite retransmissions
+1 - single transmission
+*/
+#ifndef OBX_FCR_OPT_MAX_TX_B4_DISCNT
+#define OBX_FCR_OPT_MAX_TX_B4_DISCNT 20
+#endif
+
+/* This option is application when OBX_14_INCLUDED=TRUE
+Retransmission Timeout
+Range: Minimum 2000 (2 secs) on BR/EDR when supporting PBF.
+ */
+#ifndef OBX_FCR_OPT_RETX_TOUT
+#define OBX_FCR_OPT_RETX_TOUT 2000
+#endif
+
+/* This option is application when OBX_14_INCLUDED=TRUE
+Monitor Timeout
+Range: Minimum 12000 (12 secs) on BR/EDR when supporting PBF.
+*/
+#ifndef OBX_FCR_OPT_MONITOR_TOUT
+#define OBX_FCR_OPT_MONITOR_TOUT 12000
+#endif
+
+/******************************************************************************
+**
+** BNEP
+**
+******************************************************************************/
+
+#ifndef BNEP_INCLUDED
+#define BNEP_INCLUDED FALSE
+#endif
+
+/* Protocol filtering is an optional feature. Bydefault it will be turned on */
+#ifndef BNEP_SUPPORTS_PROT_FILTERS
+#define BNEP_SUPPORTS_PROT_FILTERS TRUE
+#endif
+
+/* Multicast filtering is an optional feature. Bydefault it will be turned on */
+#ifndef BNEP_SUPPORTS_MULTI_FILTERS
+#define BNEP_SUPPORTS_MULTI_FILTERS TRUE
+#endif
+
+/* BNEP status API call is used mainly to get the L2CAP handle */
+#ifndef BNEP_SUPPORTS_STATUS_API
+#define BNEP_SUPPORTS_STATUS_API TRUE
+#endif
+
+/* This is just a debug function */
+#ifndef BNEP_SUPPORTS_DEBUG_DUMP
+#define BNEP_SUPPORTS_DEBUG_DUMP TRUE
+#endif
+
+#ifndef BNEP_SUPPORTS_ALL_UUID_LENGTHS
+#define BNEP_SUPPORTS_ALL_UUID_LENGTHS TRUE /* Otherwise it will support only 16bit UUIDs */
+#endif
+
+/*
+** When BNEP connection changes roles after the connection is established
+** we will do an authentication check again on the new role
+*/
+#ifndef BNEP_DO_AUTH_FOR_ROLE_SWITCH
+#define BNEP_DO_AUTH_FOR_ROLE_SWITCH TRUE
+#endif
+
+
+/* Maximum number of protocol filters supported. */
+#ifndef BNEP_MAX_PROT_FILTERS
+#define BNEP_MAX_PROT_FILTERS 5
+#endif
+
+/* Maximum number of multicast filters supported. */
+#ifndef BNEP_MAX_MULTI_FILTERS
+#define BNEP_MAX_MULTI_FILTERS 5
+#endif
+
+/* Minimum MTU size. */
+#ifndef BNEP_MIN_MTU_SIZE
+#define BNEP_MIN_MTU_SIZE L2CAP_MTU_SIZE
+#endif
+
+/* Preferred MTU size. */
+#ifndef BNEP_MTU_SIZE
+#define BNEP_MTU_SIZE BNEP_MIN_MTU_SIZE
+#endif
+
+/* Maximum size of user data, in bytes. */
+#ifndef BNEP_MAX_USER_DATA_SIZE
+#define BNEP_MAX_USER_DATA_SIZE 1500
+#endif
+
+/* Maximum number of buffers allowed in transmit data queue. */
+#ifndef BNEP_MAX_XMITQ_DEPTH
+#define BNEP_MAX_XMITQ_DEPTH 20
+#endif
+
+/* Maximum number BNEP of connections supported. */
+#ifndef BNEP_MAX_CONNECTIONS
+#define BNEP_MAX_CONNECTIONS 7
+#endif
+
+
+/******************************************************************************
+**
+** AVDTP
+**
+******************************************************************************/
+
+#ifndef AVDT_INCLUDED
+#define AVDT_INCLUDED FALSE
+#endif
+
+/* Include reporting capability in AVDTP */
+#ifndef AVDT_REPORTING
+#define AVDT_REPORTING TRUE
+#endif
+
+/* Include multiplexing capability in AVDTP */
+#ifndef AVDT_MULTIPLEXING
+#define AVDT_MULTIPLEXING TRUE
+#endif
+
+/* Number of simultaneous links to different peer devices. */
+#ifndef AVDT_NUM_LINKS
+#define AVDT_NUM_LINKS 2
+#endif
+
+/* Number of simultaneous stream endpoints. */
+#ifndef AVDT_NUM_SEPS
+#define AVDT_NUM_SEPS 3
+#endif
+
+/* Number of transport channels setup per media stream(audio or video) */
+#ifndef AVDT_NUM_CHANNELS
+
+#if AVDT_REPORTING == TRUE
+/* signaling, media and reporting channels */
+#define AVDT_NUM_CHANNELS 3
+#else
+/* signaling and media channels */
+#define AVDT_NUM_CHANNELS 2
+#endif
+
+#endif
+
+/* Number of transport channels setup by AVDT for all media streams
+ * AVDT_NUM_CHANNELS * Number of simultaneous streams.
+ */
+#ifndef AVDT_NUM_TC_TBL
+#define AVDT_NUM_TC_TBL 6
+#endif
+
+
+/* Maximum size in bytes of the codec capabilities information element. */
+#ifndef AVDT_CODEC_SIZE
+#define AVDT_CODEC_SIZE 10
+#endif
+
+/* Maximum size in bytes of the content protection information element. */
+#ifndef AVDT_PROTECT_SIZE
+#define AVDT_PROTECT_SIZE 90
+#endif
+
+/* Maximum number of GKI buffers in the fragment queue (for video frames).
+ * Must be less than the number of buffers in the buffer pool of size AVDT_DATA_POOL_SIZE */
+#ifndef AVDT_MAX_FRAG_COUNT
+#define AVDT_MAX_FRAG_COUNT 15
+#endif
+
+/******************************************************************************
+**
+** PAN
+**
+******************************************************************************/
+
+#ifndef PAN_INCLUDED
+#define PAN_INCLUDED FALSE
+#endif
+
+/* This will enable the PANU role */
+#ifndef PAN_SUPPORTS_ROLE_PANU
+#define PAN_SUPPORTS_ROLE_PANU TRUE
+#endif
+
+/* This will enable the GN role */
+#ifndef PAN_SUPPORTS_ROLE_GN
+#define PAN_SUPPORTS_ROLE_GN TRUE
+#endif
+
+/* This will enable the NAP role */
+#ifndef PAN_SUPPORTS_ROLE_NAP
+#define PAN_SUPPORTS_ROLE_NAP TRUE
+#endif
+
+/* This is just for debugging purposes */
+#ifndef PAN_SUPPORTS_DEBUG_DUMP
+#define PAN_SUPPORTS_DEBUG_DUMP TRUE
+#endif
+
+
+/* Maximum number of PAN connections allowed */
+#ifndef MAX_PAN_CONNS
+#define MAX_PAN_CONNS 7
+#endif
+
+/* Default service name for NAP role */
+#ifndef PAN_NAP_DEFAULT_SERVICE_NAME
+#define PAN_NAP_DEFAULT_SERVICE_NAME "Network Access Point Service"
+#endif
+
+/* Default service name for GN role */
+#ifndef PAN_GN_DEFAULT_SERVICE_NAME
+#define PAN_GN_DEFAULT_SERVICE_NAME "Group Network Service"
+#endif
+
+/* Default service name for PANU role */
+#ifndef PAN_PANU_DEFAULT_SERVICE_NAME
+#define PAN_PANU_DEFAULT_SERVICE_NAME "PAN User Service"
+#endif
+
+/* Default description for NAP role service */
+#ifndef PAN_NAP_DEFAULT_DESCRIPTION
+#define PAN_NAP_DEFAULT_DESCRIPTION "NAP"
+#endif
+
+/* Default description for GN role service */
+#ifndef PAN_GN_DEFAULT_DESCRIPTION
+#define PAN_GN_DEFAULT_DESCRIPTION "GN"
+#endif
+
+/* Default description for PANU role service */
+#ifndef PAN_PANU_DEFAULT_DESCRIPTION
+#define PAN_PANU_DEFAULT_DESCRIPTION "PANU"
+#endif
+
+/* Default Security level for PANU role. */
+#ifndef PAN_PANU_SECURITY_LEVEL
+#define PAN_PANU_SECURITY_LEVEL 0
+#endif
+
+/* Default Security level for GN role. */
+#ifndef PAN_GN_SECURITY_LEVEL
+#define PAN_GN_SECURITY_LEVEL 0
+#endif
+
+/* Default Security level for NAP role. */
+#ifndef PAN_NAP_SECURITY_LEVEL
+#define PAN_NAP_SECURITY_LEVEL 0
+#endif
+
+
+
+
+/******************************************************************************
+**
+** GAP
+**
+******************************************************************************/
+
+#ifndef GAP_INCLUDED
+#define GAP_INCLUDED FALSE
+#endif
+
+/* This is set to enable use of GAP L2CAP connections. */
+#ifndef GAP_CONN_INCLUDED
+#define GAP_CONN_INCLUDED TRUE
+#endif
+
+/* This is set to enable posting event for data write */
+#ifndef GAP_CONN_POST_EVT_INCLUDED
+#define GAP_CONN_POST_EVT_INCLUDED FALSE
+#endif
+
+/* The maximum number of simultaneous GAP L2CAP connections. */
+#ifndef GAP_MAX_CONNECTIONS
+#define GAP_MAX_CONNECTIONS 8
+#endif
+
+/******************************************************************************
+**
+** CTP
+**
+******************************************************************************/
+
+#ifndef CTP_INCLUDED
+#define CTP_INCLUDED FALSE
+#endif
+
+/* To include CTP gateway functionality or not. */
+#ifndef CTP_GW_INCLUDED
+#define CTP_GW_INCLUDED TRUE
+#endif
+
+/* The number of terminals supported. */
+#ifndef CTP_MAX_NUM_TLS
+#define CTP_MAX_NUM_TLS 7
+#endif
+
+/* If the controller can not support sniff mode when the SCO is up, set this to FALSE. */
+#ifndef CTP_USE_SNIFF_ON_SCO
+#define CTP_USE_SNIFF_ON_SCO FALSE
+#endif
+
+/* When ACL link between TL and GW is idle for more than this amount of seconds, the ACL may be put to low power mode. */
+#ifndef CTP_TL_IDLE_TIMEOUT
+#define CTP_TL_IDLE_TIMEOUT 90
+#endif
+
+/* To include CTP terminal functionality or not. */
+#ifndef CTP_TL_INCLUDED
+#define CTP_TL_INCLUDED TRUE
+#endif
+
+/* To include CTP device discovery functionality or not. */
+#ifndef CTP_DISCOVERY_INCLUDED
+#define CTP_DISCOVERY_INCLUDED TRUE
+#endif
+
+/* set to TRUE for controllers that do not support multi-point */
+#ifndef CTP_TL_WAIT_DISC
+#define CTP_TL_WAIT_DISC TRUE
+#endif
+
+/* The CTP inquiry database size. */
+#ifndef CTP_INQ_DB_SIZE
+#define CTP_INQ_DB_SIZE CTP_DISC_REC_SIZE
+#endif
+
+/* The CTP discovery record size. */
+#ifndef CTP_DISC_REC_SIZE
+#define CTP_DISC_REC_SIZE 60
+#endif
+
+/* CTP TL would try to re-establish L2CAP channel after channel is disconnected for this amount of seconds. */
+#ifndef CTP_GUARD_LINK_LOST
+#define CTP_GUARD_LINK_LOST 1
+#endif
+
+/* The link policy bitmap. */
+#ifndef CTP_DEFAULT_LINK_POLICY
+#define CTP_DEFAULT_LINK_POLICY 0x000F
+#endif
+
+/* The minimum period interval used for the sniff and park modes. */
+#ifndef CTP_DEF_LOWPWR_MIN_PERIOD
+#define CTP_DEF_LOWPWR_MIN_PERIOD 0x100
+#endif
+
+/* The maximum period interval used for the sniff and park modes. */
+#ifndef CTP_DEF_LOWPWR_MAX_PERIOD
+#define CTP_DEF_LOWPWR_MAX_PERIOD 0x1E0
+#endif
+
+/* The number of baseband receive slot sniff attempts. */
+#ifndef CTP_DEF_LOWPWR_ATTEMPT
+#define CTP_DEF_LOWPWR_ATTEMPT 0x200
+#endif
+
+/* The number of baseband receive slots for sniff timeout. */
+#ifndef CTP_DEF_LOWPWR_TIMEOUT
+#define CTP_DEF_LOWPWR_TIMEOUT 0x200
+#endif
+
+/* This is set if CTP is to use park mode. */
+#ifndef CTP_PARK_INCLUDED
+#define CTP_PARK_INCLUDED TRUE
+#endif
+
+/* This is set if CTP is to use sniff mode. */
+#ifndef CTP_SNIFF_INCLUDED
+#define CTP_SNIFF_INCLUDED TRUE
+#endif
+
+/* To include CTP data exchange functionality or not. */
+#ifndef CTP_DATA_EXCHG_FEATURE
+#define CTP_DATA_EXCHG_FEATURE FALSE
+#endif
+
+/* To include CTP GW intercom functionality or not. */
+#ifndef CTP_GW_INTERCOM_FEATURE
+#define CTP_GW_INTERCOM_FEATURE FALSE
+#endif
+
+/* The MTU size for L2CAP channel. */
+#ifndef CTP_MTU_SIZE
+#define CTP_MTU_SIZE 200
+#endif
+
+/* The L2CAP PSM for the data exchange feature. */
+#ifndef CTP_DATA_EXCHG_PSM
+#define CTP_DATA_EXCHG_PSM 13
+#endif
+
+/* The flush timeout for L2CAP channels. */
+#ifndef CTP_FLUSH_TO
+#define CTP_FLUSH_TO 0xFFFF
+#endif
+
+/* The default service name for CTP. */
+#ifndef CTP_DEFAULT_SERVICE_NAME
+#define CTP_DEFAULT_SERVICE_NAME "Cordless Telephony"
+#endif
+
+/* The CTP security level. */
+#ifndef CTP_SECURITY_LEVEL
+#define CTP_SECURITY_LEVEL (BTM_SEC_IN_AUTHORIZE | BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT)
+#endif
+
+/* The number of lines to the external network. */
+#ifndef CTP_MAX_LINES
+#define CTP_MAX_LINES 1
+#endif
+
+/* Test if the number of resources in TCS is consistent with CTP setting. */
+#ifndef CTP_TEST_FULL_TCS
+#define CTP_TEST_FULL_TCS TRUE
+#endif
+
+/* The default inquiry mode. */
+#ifndef CTP_DEFAULT_INQUIRY_MODE
+#define CTP_DEFAULT_INQUIRY_MODE BTM_GENERAL_INQUIRY
+#endif
+
+/* The default inquiry duration. */
+#ifndef CTP_DEFAULT_INQ_DURATION
+#define CTP_DEFAULT_INQ_DURATION 4
+#endif
+
+/* The maximum number of inquiry responses. */
+#ifndef CTP_DEFAULT_INQ_MAX_RESP
+#define CTP_DEFAULT_INQ_MAX_RESP 3
+#endif
+
+/* When TL does not create another L2CAP channel within this period of time GW declares that it's "Connected Limited". */
+#ifndef CTP_TL_CONN_TIMEOUT
+#define CTP_TL_CONN_TIMEOUT 5
+#endif
+
+/* The delay for ACL to completely disconnect (for intercom) before sending the connect request to GW. */
+#ifndef CTP_RECONNECT_DELAY
+#define CTP_RECONNECT_DELAY 5
+#endif
+
+/* How many times to retry connection when it has failed. */
+#ifndef CTP_RETRY_ON_CONN_ERR
+#define CTP_RETRY_ON_CONN_ERR 5
+#endif
+
+/******************************************************************************
+**
+** ICP
+**
+******************************************************************************/
+
+#ifndef ICP_INCLUDED
+#define ICP_INCLUDED FALSE
+#endif
+
+/* The ICP default MTU. */
+#ifndef ICP_MTU_SIZE
+#define ICP_MTU_SIZE 100
+#endif
+
+/* The ICP security level. */
+#ifndef ICP_SECURITY_LEVEL
+#define ICP_SECURITY_LEVEL BTM_SEC_NONE
+#endif
+
+/* The default service name for ICP. */
+#ifndef ICP_DEFAULT_SERVICE_NAME
+#define ICP_DEFAULT_SERVICE_NAME "Intercom"
+#endif
+
+/* The flush timeout for L2CAP channels. */
+#ifndef ICP_FLUSH_TO
+#define ICP_FLUSH_TO 0xFFFF
+#endif
+
+/******************************************************************************
+**
+** SPP
+**
+******************************************************************************/
+
+#ifndef SPP_INCLUDED
+#define SPP_INCLUDED FALSE
+#endif
+
+/* The SPP default MTU. */
+#ifndef SPP_DEFAULT_MTU
+#define SPP_DEFAULT_MTU 127
+#endif
+
+/* The interval, in seconds, that a client tries to reconnect to a service. */
+#ifndef SPP_RETRY_CONN_INTERVAL
+#define SPP_RETRY_CONN_INTERVAL 1
+#endif
+
+/* The SPP discoverable mode: limited or general. */
+#ifndef SPP_DISCOVERABLE_MODE
+#define SPP_DISCOVERABLE_MODE BTM_GENERAL_DISCOVERABLE
+#endif
+
+/* The maximum number of inquiry results returned in by inquiry procedure. */
+#ifndef SPP_DEF_INQ_MAX_RESP
+#define SPP_DEF_INQ_MAX_RESP 10
+#endif
+
+/* The SPP discovery record size. */
+#ifndef SPP_DISC_REC_SIZE
+#define SPP_DISC_REC_SIZE 60
+#endif
+
+#ifndef SPP_MAX_RECS_PER_DEVICE
+#define SPP_MAX_RECS_PER_DEVICE (SPP_DB_SIZE / SPP_DISC_REC_SIZE)
+#endif
+
+/* Inquiry duration in 1.28 second units. */
+#ifndef SPP_DEF_INQ_DURATION
+#define SPP_DEF_INQ_DURATION 9
+#endif
+
+/* keep the raw data received from SDP server in database. */
+#ifndef SDP_RAW_DATA_INCLUDED
+#define SDP_RAW_DATA_INCLUDED FALSE
+#endif
+
+/* TRUE, to allow JV to create L2CAP connection on SDP PSM. */
+#ifndef SDP_FOR_JV_INCLUDED
+#define SDP_FOR_JV_INCLUDED FALSE
+#endif
+
+/* Inquiry duration in 1.28 second units. */
+#ifndef SDP_DEBUG
+#define SDP_DEBUG TRUE
+#endif
+
+/******************************************************************************
+**
+** HSP2, HFP
+**
+******************************************************************************/
+
+#ifndef HSP2_INCLUDED
+#define HSP2_INCLUDED FALSE
+#endif
+
+/* Include the ability to perform inquiry for peer devices. */
+#ifndef HSP2_INQUIRY_INCLUDED
+#define HSP2_INQUIRY_INCLUDED TRUE
+#endif
+
+/* Include Audio Gateway specific code. */
+#ifndef HSP2_AG_INCLUDED
+#define HSP2_AG_INCLUDED TRUE
+#endif
+
+/* Include Headset Specific Code. */
+#ifndef HSP2_HS_INCLUDED
+#define HSP2_HS_INCLUDED TRUE
+#endif
+
+/* Include the ability to open an SCO connection for In-Band Ringing. */
+#ifndef HSP2_IB_RING_INCLUDED
+#define HSP2_IB_RING_INCLUDED TRUE
+#endif
+
+/* Include the ability to repeat a ring. */
+#ifndef HSP2_AG_REPEAT_RING
+#define HSP2_AG_REPEAT_RING TRUE
+#endif
+
+#ifndef HSP2_APP_CLOSES_ON_CKPD
+#define HSP2_APP_CLOSES_ON_CKPD FALSE
+#endif
+
+
+/* Include the ability to park a connection. */
+#ifndef HSP2_PARK_INCLUDED
+#define HSP2_PARK_INCLUDED TRUE
+#endif
+
+/* Include HSP State Machine debug trace messages. */
+#ifndef HSP2_FSM_DEBUG
+#define HSP2_FSM_DEBUG TRUE
+#endif
+
+/* The Module's Inquiry Scan Window. */
+#ifndef HSP2_INQ_SCAN_WINDOW
+#define HSP2_INQ_SCAN_WINDOW 0
+#endif
+
+/* The Module's Inquiry Scan Interval. */
+#ifndef HSP2_INQ_SCAN_INTERVAL
+#define HSP2_INQ_SCAN_INTERVAL 0
+#endif
+
+/* The Module's Page Scan Interval. */
+#ifndef HSP2_PAGE_SCAN_INTERVAL
+#define HSP2_PAGE_SCAN_INTERVAL 0
+#endif
+
+/* The Module's Page Scan Window. */
+#ifndef HSP2_PAGE_SCAN_WINDOW
+#define HSP2_PAGE_SCAN_WINDOW 0
+#endif
+
+/* The Park Mode's Minimum Beacon Period. */
+#ifndef HSP2_BEACON_MIN_PERIOD
+#define HSP2_BEACON_MIN_PERIOD 450
+#endif
+
+/* The Park Mode's Maximum Beacon Period. */
+#ifndef HSP2_BEACON_MAX_PERIOD
+#define HSP2_BEACON_MAX_PERIOD 500
+#endif
+
+/* The duration of the inquiry in seconds. */
+#ifndef HSP2_INQ_DURATION
+#define HSP2_INQ_DURATION 4
+#endif
+
+/* Maximum number of peer responses during an inquiry. */
+#ifndef HSP2_INQ_MAX_NUM_RESPS
+#define HSP2_INQ_MAX_NUM_RESPS 3
+#endif
+
+/* Maximum number of times to retry an inquiry prior to failure. */
+#ifndef HSP2_MAX_INQ_RETRY
+#define HSP2_MAX_INQ_RETRY 6
+#endif
+
+/* Maximum number of times to retry an RFCOMM connection prior to failure. */
+#ifndef HSP2_MAX_CONN_RETRY
+#define HSP2_MAX_CONN_RETRY 3
+#endif
+
+/* If the connect request failed for authentication reasons, do not retry */
+#ifndef HSP2_NO_RETRY_ON_AUTH_FAIL
+#define HSP2_NO_RETRY_ON_AUTH_FAIL TRUE
+#endif
+
+/* Maximum number of characters in an HSP2 device name. */
+#ifndef HSP2_MAX_NAME_LEN
+#define HSP2_MAX_NAME_LEN 32
+#endif
+
+/* The minimum speaker and/or microphone gain setting. */
+#ifndef HSP2_MIN_GAIN
+#define HSP2_MIN_GAIN 0
+#endif
+
+/* The maximum speaker and/or microphone setting. */
+#ifndef HSP2_MAX_GAIN
+#define HSP2_MAX_GAIN 15
+#endif
+
+/* The default value to send on an AT+CKPD. */
+#ifndef HSP2_KEYPRESS_DEFAULT
+#define HSP2_KEYPRESS_DEFAULT 200
+#endif
+
+/* Maximum amount a data that can be received per RFCOMM frame. */
+#ifndef HSP2_MAX_RFC_READ_LEN
+#define HSP2_MAX_RFC_READ_LEN 128
+#endif
+
+/* The time in seconds to wait for completion of a partial AT command or response from the peer. */
+#ifndef HSP2_AT_TO_INTERVAL
+#define HSP2_AT_TO_INTERVAL 30
+#endif
+
+/* The time to wait before repeating a ring to a peer Headset. */
+#ifndef HSP2_REPEAT_RING_TO
+#define HSP2_REPEAT_RING_TO 4
+#endif
+
+/* Time to wait for a response for an AT command */
+#ifndef HSP2_AT_RSP_TO
+#define HSP2_AT_RSP_TO 20
+#endif
+
+/* SCO packet type(s) to use (bitmask: see spec), 0 - device default (recommended) */
+#ifndef HSP2_SCO_PKT_TYPES
+#define HSP2_SCO_PKT_TYPES ((UINT16)0x0000)
+#endif
+
+/* The default settings of the SCO voice link. */
+#ifndef HSP2_DEFAULT_VOICE_SETTINGS
+#define HSP2_DEFAULT_VOICE_SETTINGS (HCI_INP_CODING_LINEAR | HCI_INP_DATA_FMT_2S_COMPLEMENT | HCI_INP_SAMPLE_SIZE_16BIT | HCI_AIR_CODING_FORMAT_CVSD)
+#endif
+
+#ifndef HSP2_MAX_AT_CMD_LENGTH
+#define HSP2_MAX_AT_CMD_LENGTH 16
+#endif
+
+#ifndef HSP2_MAX_AT_VAL_LENGTH
+#if (defined(HFP_INCLUDED) && HFP_INCLUDED == TRUE)
+#define HSP2_MAX_AT_VAL_LENGTH 310
+#else
+#define HSP2_MAX_AT_VAL_LENGTH 5
+#endif
+#endif
+
+
+#ifndef HSP2_SDP_DB_SIZE
+#define HSP2_SDP_DB_SIZE 300
+#endif
+
+
+/******************************************************************************
+**
+** HFP
+**
+******************************************************************************/
+
+#ifndef HFP_INCLUDED
+#define HFP_INCLUDED FALSE
+#endif
+
+/* Include Audio Gateway specific code. */
+#ifndef HFP_AG_INCLUDED
+#define HFP_AG_INCLUDED TRUE
+#endif
+
+/* Include Hand Free Specific Code. */
+#ifndef HFP_HF_INCLUDED
+#define HFP_HF_INCLUDED TRUE
+#endif
+
+/* Use AT interface instead of full blown API */
+#ifndef AT_INTERFACE
+#define AT_INTERFACE FALSE
+#endif
+
+/* HFP Manages SCO establishement for various procedures */
+#ifndef HFP_SCO_MGMT_INCLUDED
+#define HFP_SCO_MGMT_INCLUDED TRUE
+#endif
+
+/* CCAP compliant features and behavior desired */
+#ifndef CCAP_COMPLIANCE
+#define CCAP_COMPLIANCE TRUE
+#endif
+
+/* Caller ID string, part of +CLIP result code */
+#ifndef HFP_MAX_CLIP_INFO
+#define HFP_MAX_CLIP_INFO 45
+#endif
+
+#ifndef HFP_RPT_PEER_INFO_INCLUDED
+#define HFP_RPT_PEER_INFO_INCLUDED TRUE /* Reporting of peer features enabled */
+#endif
+
+/******************************************************************************
+**
+** HID
+**
+******************************************************************************/
+
+/* HID Device Role Included */
+#ifndef HID_DEV_INCLUDED
+#define HID_DEV_INCLUDED FALSE
+#endif
+
+#ifndef HID_DEV_PM_INCLUDED
+#define HID_DEV_PM_INCLUDED TRUE
+#endif
+
+/* The HID Device is a virtual cable */
+#ifndef HID_DEV_VIRTUAL_CABLE
+#define HID_DEV_VIRTUAL_CABLE TRUE
+#endif
+
+/* The HID device initiates the reconnections */
+#ifndef HID_DEV_RECONN_INITIATE
+#define HID_DEV_RECONN_INITIATE TRUE
+#endif
+
+/* THe HID device is normally connectable */
+#ifndef HID_DEV_NORMALLY_CONN
+#define HID_DEV_NORMALLY_CONN FALSE
+#endif
+
+/* The device is battery powered */
+#ifndef HID_DEV_BATTERY_POW
+#define HID_DEV_BATTERY_POW TRUE
+#endif
+
+/* Device is capable of waking up the host */
+#ifndef HID_DEV_REMOTE_WAKE
+#define HID_DEV_REMOTE_WAKE TRUE
+#endif
+
+/* Device needs host to close SDP channel after SDP is over */
+#ifndef HID_DEV_SDP_DISABLE
+#define HID_DEV_SDP_DISABLE TRUE
+#endif
+
+#ifndef HID_DEV_MTU_SIZE
+#define HID_DEV_MTU_SIZE 64
+#endif
+
+#ifndef HID_DEV_FLUSH_TO
+#define HID_DEV_FLUSH_TO 0xffff
+#endif
+
+#ifndef HID_DEV_PAGE_SCAN_WIN
+#define HID_DEV_PAGE_SCAN_WIN (0)
+#endif
+
+#ifndef HID_DEV_PAGE_SCAN_INT
+#define HID_DEV_PAGE_SCAN_INT (0)
+#endif
+
+#ifndef HID_DEV_MAX_CONN_RETRY
+#define HID_DEV_MAX_CONN_RETRY (15)
+#endif
+
+#ifndef HID_DEV_REPAGE_WIN
+#define HID_DEV_REPAGE_WIN (1)
+#endif
+
+#ifndef HID_DEV_SVC_NAME
+#define HID_DEV_SVC_NAME "HID"
+#endif
+
+#ifndef HID_DEV_SVC_DESCR
+#define HID_DEV_SVC_DESCR "3-button mouse and keyboard"
+#endif
+
+#ifndef HID_DEV_PROVIDER_NAME
+#define HID_DEV_PROVIDER_NAME "Widcomm"
+#endif
+
+#ifndef HID_DEV_REL_NUM
+#define HID_DEV_REL_NUM 0x0100
+#endif
+
+#ifndef HID_DEV_PARSER_VER
+#define HID_DEV_PARSER_VER 0x0111
+#endif
+
+#ifndef HID_DEV_SUBCLASS
+#define HID_DEV_SUBCLASS COD_MINOR_POINTING
+#endif
+
+#ifndef HID_DEV_COUNTRY_CODE
+#define HID_DEV_COUNTRY_CODE 0x33
+#endif
+
+#ifndef HID_DEV_SUP_TOUT
+#define HID_DEV_SUP_TOUT 0x8000
+#endif
+
+#ifndef HID_DEV_NUM_LANGS
+#define HID_DEV_NUM_LANGS 1
+#endif
+
+#ifndef HID_DEV_INACT_TIMEOUT
+#define HID_DEV_INACT_TIMEOUT 60
+#endif
+
+#ifndef HID_DEV_BUSY_MODE_PARAMS
+#define HID_DEV_BUSY_MODE_PARAMS { 320, 160, 10, 20, HCI_MODE_ACTIVE }
+#endif
+
+#ifndef HID_DEV_IDLE_MODE_PARAMS
+#define HID_DEV_IDLE_MODE_PARAMS { 320, 160, 10, 20, HCI_MODE_SNIFF }
+#endif
+
+#ifndef HID_DEV_SUSP_MODE_PARAMS
+#define HID_DEV_SUSP_MODE_PARAMS { 640, 320, 0, 0, HCI_MODE_PARK }
+#endif
+
+#ifndef HID_DEV_MAX_DESCRIPTOR_SIZE
+#define HID_DEV_MAX_DESCRIPTOR_SIZE 128 /* Max descriptor size */
+#endif
+
+#ifndef HID_DEV_LANGUAGELIST
+#define HID_DEV_LANGUAGELIST {0x35, 0x06, 0x09, 0x04, 0x09, 0x09, 0x01, 0x00}
+#endif
+
+#ifndef HID_DEV_LINK_SUPERVISION_TO
+#define HID_DEV_LINK_SUPERVISION_TO 0x8000
+#endif
+
+#ifndef HID_CONTROL_POOL_ID
+#define HID_CONTROL_POOL_ID 2
+#endif
+
+#ifndef HID_INTERRUPT_POOL_ID
+#define HID_INTERRUPT_POOL_ID 2
+#endif
+
+/*************************************************************************
+** Definitions for Both HID-Host & Device
+*/
+#ifndef HID_MAX_SVC_NAME_LEN
+#define HID_MAX_SVC_NAME_LEN 32
+#endif
+
+#ifndef HID_MAX_SVC_DESCR_LEN
+#define HID_MAX_SVC_DESCR_LEN 32
+#endif
+
+#ifndef HID_MAX_PROV_NAME_LEN
+#define HID_MAX_PROV_NAME_LEN 32
+#endif
+
+/*************************************************************************
+** Definitions for HID-Host
+*/
+#ifndef HID_HOST_INCLUDED
+#define HID_HOST_INCLUDED FALSE
+#endif
+
+#ifndef HID_HOST_MAX_DEVICES
+#define HID_HOST_MAX_DEVICES 7
+#endif
+
+#ifndef HID_HOST_MTU
+#define HID_HOST_MTU 640
+#endif
+
+#ifndef HID_HOST_FLUSH_TO
+#define HID_HOST_FLUSH_TO 0xffff
+#endif
+
+#ifndef HID_HOST_MAX_CONN_RETRY
+#define HID_HOST_MAX_CONN_RETRY (15)
+#endif
+
+#ifndef HID_HOST_REPAGE_WIN
+#define HID_HOST_REPAGE_WIN (2)
+#endif
+
+
+/******************************************************************************
+**
+** DUN and FAX
+**
+******************************************************************************/
+
+#ifndef DUN_INCLUDED
+#define DUN_INCLUDED FALSE
+#endif
+
+
+/******************************************************************************
+**
+** GOEP
+**
+******************************************************************************/
+
+#ifndef GOEP_INCLUDED
+#define GOEP_INCLUDED FALSE
+#endif
+
+/* This is set to enable GOEP non-blocking file system access functions. */
+#ifndef GOEP_FS_INCLUDED
+#define GOEP_FS_INCLUDED TRUE
+#endif
+
+/* GOEP authentication key size. */
+#ifndef GOEP_MAX_AUTH_KEY_SIZE
+#define GOEP_MAX_AUTH_KEY_SIZE 16
+#endif
+
+/* Maximum size of the realm authentication string. */
+#ifndef GOEP_MAX_AUTH_REALM_SIZE
+#define GOEP_MAX_AUTH_REALM_SIZE 16
+#endif
+
+/* Realm Character Set */
+#ifndef GOEP_REALM_CHARSET
+#define GOEP_REALM_CHARSET 0 /* ASCII */
+#endif
+
+/* This is set to the maximum length of path name allowed in the system (_MAX_PATH). */
+#ifndef GOEP_MAX_PATH_SIZE
+#define GOEP_MAX_PATH_SIZE 255
+#endif
+
+/* Specifies whether or not client's user id is required during obex authentication */
+#ifndef GOEP_SERVER_USERID_REQUIRED
+#define GOEP_SERVER_USERID_REQUIRED FALSE
+#endif
+
+/* This is set to the maximum length of file name allowed in the system (_MAX_FNAME). */
+#ifndef GOEP_MAX_FILE_SIZE
+#define GOEP_MAX_FILE_SIZE 128
+#endif
+
+/* Character used as path separator */
+#ifndef GOEP_PATH_SEPARATOR
+#define GOEP_PATH_SEPARATOR ((char) 0x5c) /* 0x2f ('/'), or 0x5c ('\') */
+#endif
+
+/******************************************************************************
+**
+** OPP
+**
+******************************************************************************/
+
+#ifndef OPP_INCLUDED
+#define OPP_INCLUDED FALSE
+#endif
+
+/* This is set to enable OPP client capabilities. */
+#ifndef OPP_CLIENT_INCLUDED
+#define OPP_CLIENT_INCLUDED FALSE
+#endif
+
+/* This is set to enable OPP server capabilities. */
+#ifndef OPP_SERVER_INCLUDED
+#define OPP_SERVER_INCLUDED FALSE
+#endif
+
+/* if the optional formating functions are to be included or not */
+#ifndef OPP_FORMAT_INCLUDED
+#define OPP_FORMAT_INCLUDED FALSE
+#endif
+
+/* Maximum number of client sessions allowed by server */
+#ifndef OPP_MAX_SRVR_SESS
+#define OPP_MAX_SRVR_SESS 3
+#endif
+
+/******************************************************************************
+**
+** FTP
+**
+******************************************************************************/
+
+#ifndef FTP_INCLUDED
+#define FTP_INCLUDED FALSE
+#endif
+
+/* This is set to enable FTP client capabilities. */
+#ifndef FTP_CLIENT_INCLUDED
+#define FTP_CLIENT_INCLUDED TRUE
+#endif
+
+/* This is set to enable FTP server capabilities. */
+#ifndef FTP_SERVER_INCLUDED
+#define FTP_SERVER_INCLUDED TRUE
+#endif
+
+/******************************************************************************
+**
+** XML Parser
+**
+******************************************************************************/
+
+#ifndef XML_STACK_SIZE
+#define XML_STACK_SIZE 7
+#endif
+
+/******************************************************************************
+**
+** BPP Printer
+**
+******************************************************************************/
+#ifndef BPP_DEBUG
+#define BPP_DEBUG FALSE
+#endif
+
+#ifndef BPP_INCLUDED
+#define BPP_INCLUDED FALSE
+#endif
+
+#ifndef BPP_SND_INCLUDED
+#define BPP_SND_INCLUDED FALSE
+#endif
+
+/* Maximum number of senders allowed to connect simultaneously
+** The maximum is 6 or (OBX_NUM_SERVERS / 2), whichever is smaller
+*/
+#ifndef BPP_PR_MAX_CON
+#define BPP_PR_MAX_CON 3
+#endif
+
+/* Service Name. maximum length: 248
+#ifndef BPP_SERVICE_NAME
+#define BPP_SERVICE_NAME "Basic Printing"
+#endif
+ */
+/* Document Format Supported. ASCII comma-delimited list of MIME type:version string
+#ifndef BPP_DOC_FORMAT_SUPPORTED
+#define BPP_DOC_FORMAT_SUPPORTED "application/vnd.pwg-xhtml-print:1.0,application/vnd.hp-PCL:5E,application/PDF"
+#endif
+
+#ifndef BPP_DOC_FORMAT_SUPPORTED_LEN
+#define BPP_DOC_FORMAT_SUPPORTED_LEN 77
+#endif
+ */
+/* Character repertoires.
+#ifndef BPP_CHARACTER_REPERTOIRES
+#define BPP_CHARACTER_REPERTOIRES {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}
+#endif
+ */
+/* XHTML formats.
+#ifndef BPP_XHTML_PRINT_FORMATS
+#define BPP_XHTML_PRINT_FORMATS "image/gif:89A,image/jpeg"
+#endif
+
+#ifndef BPP_XHTML_PRINT_FORMATS_LEN
+#define BPP_XHTML_PRINT_FORMATS_LEN 24
+#endif
+ */
+/* Color supported.
+#ifndef BPP_COLOR_SUPORTED
+#define BPP_COLOR_SUPORTED FALSE
+#endif
+ */
+/* 1284 ID string. First 2 bytes are the length.
+#ifndef BPP_1284ID
+#define BPP_1284ID "\x00\x48MANUFACTURER:ACME Manufacturing;COMMAND SET:PCL,MPL;MODEL:LaserBeam \?;"
+#endif
+
+#ifndef BPP_1284ID_LEN
+#define BPP_1284ID_LEN 72
+#endif
+ */
+/* Printer name.
+#ifndef BPP_PRINTER_NAME
+#define BPP_PRINTER_NAME "My Printer"
+#endif
+
+#ifndef BPP_PRINTER_NAME_LEN
+#define BPP_PRINTER_NAME_LEN 10
+#endif
+ */
+
+/* Printer location.
+#ifndef BPP_PRINTER_LOCATION
+#define BPP_PRINTER_LOCATION "Hotel Lobby"
+#endif
+
+#ifndef BPP_PRINTER_LOCATION_LEN
+#define BPP_PRINTER_LOCATION_LEN 11
+#endif
+ */
+/* Duplex printing supported.
+#ifndef BPP_DUPLEX_SUPPORTED
+#define BPP_DUPLEX_SUPPORTED TRUE
+#endif
+ */
+
+/* Media types supported.
+#ifndef BPP_MEDIA_TYPES_SUPPORTED
+#define BPP_MEDIA_TYPES_SUPPORTED "stationary,continuous-long,photographic-high-gloss,cardstock"
+#endif
+
+#ifndef BPP_MEDIA_TYPES_SUPPORTED_LEN
+#define BPP_MEDIA_TYPES_SUPPORTED_LEN 60
+#endif
+ */
+/* Maximum media with supported.
+#ifndef BPP_MAX_MEDIA_WIDTH
+#define BPP_MAX_MEDIA_WIDTH 205
+#endif
+ */
+/* Maximum media length supported.
+#ifndef BPP_MAX_MEDIA_LENGTH
+#define BPP_MAX_MEDIA_LENGTH 285
+#endif
+ */
+/* the maximum string len for the media size of medium loaded */
+#ifndef BPP_MEDIA_SIZE_LEN
+#define BPP_MEDIA_SIZE_LEN 33
+#endif
+
+/* Debug Trace the SOAP object, if TRUE */
+#ifndef BPP_TRACE_XML
+#define BPP_TRACE_XML TRUE
+#endif
+
+/* in case that the SOAP object does not all come in one OBEX packet,
+ * this size of data may be kept in the BPP control block for continuing parsing.
+ * The maximum is the size of the biggest GKI buffer (GKI_MAX_BUF_SIZE) */
+#ifndef BPP_SOAP_KEEP_SIZE
+#define BPP_SOAP_KEEP_SIZE 200
+#endif
+
+
+/******************************************************************************
+**
+** BIP
+**
+******************************************************************************/
+#ifndef BIP_INCLUDED
+#define BIP_INCLUDED FALSE
+#endif
+
+/* TRUE to include imaging initiator */
+#ifndef BIP_INITR_INCLUDED
+#define BIP_INITR_INCLUDED FALSE
+#endif
+
+/* TRUE to include imaging responder */
+#ifndef BIP_RSPDR_INCLUDED
+#define BIP_RSPDR_INCLUDED FALSE
+#endif
+
+/* TRUE to include image push feature */
+#ifndef BIP_PUSH_INCLUDED
+#define BIP_PUSH_INCLUDED TRUE
+#endif
+
+/* TRUE to include image pull feature */
+#ifndef BIP_PULL_INCLUDED
+#define BIP_PULL_INCLUDED TRUE
+#endif
+
+/* TRUE to include advanced image printing feature */
+#ifndef BIP_PRINTING_INCLUDED
+#define BIP_PRINTING_INCLUDED TRUE
+#endif
+
+/* TRUE to include automatic archive feature */
+#ifndef BIP_ARCHIVE_INCLUDED
+#define BIP_ARCHIVE_INCLUDED TRUE
+#endif
+
+/* TRUE to include remote camera feature */
+#ifndef BIP_CAMERA_INCLUDED
+#define BIP_CAMERA_INCLUDED TRUE
+#endif
+
+/* TRUE to include remote display feature */
+#ifndef BIP_DISPLAY_INCLUDED
+#define BIP_DISPLAY_INCLUDED TRUE
+#endif
+
+/* TRUE to include sanity check code for API functions */
+#ifndef BIP_SANITY_CHECKS
+#define BIP_SANITY_CHECKS TRUE
+#endif
+
+/* TRUE to show the received XML object in trace for conformance tests */
+#ifndef BIP_TRACE_XML
+#define BIP_TRACE_XML TRUE
+#endif
+
+/* in case that the received XML object is not complete, the XML parser state machine needs
+ * to keep a copy of the data from the last '<'
+ * This macro specifies the maximun amount of data for this purpose */
+#ifndef BIP_XML_CARRY_OVER_LEN
+#define BIP_XML_CARRY_OVER_LEN 100
+#endif
+
+/* minimum 4, maximum is 255. The value should be set to the maximum size of encoding string + 1. JPEG2000.
+ * If vendor specific format is supported, it might be bigger than 9 */
+#ifndef BIP_IMG_ENCODE_SIZE
+#define BIP_IMG_ENCODE_SIZE 9
+#endif
+
+/* MIME type: text/plain */
+#ifndef BIP_TYPE_SIZE
+#define BIP_TYPE_SIZE 20
+#endif
+
+/* example: iso-8895-1 */
+#ifndef BIP_CHARSET_SIZE
+#define BIP_CHARSET_SIZE 10
+#endif
+
+/* friendly name */
+#ifndef BIP_FNAME_SIZE
+#define BIP_FNAME_SIZE 20
+#endif
+
+/* service name */
+#ifndef BIP_SNAME_SIZE
+#define BIP_SNAME_SIZE 60
+#endif
+
+/* temporary storage file name(for file system access, may include path) */
+#ifndef BIP_TEMP_NAME_SIZE
+#define BIP_TEMP_NAME_SIZE 200
+#endif
+
+/* image file name */
+#ifndef BIP_IMG_NAME_SIZE
+#define BIP_IMG_NAME_SIZE 200
+#endif
+
+/* attachment file name */
+#ifndef BIP_ATT_NAME_SIZE
+#define BIP_ATT_NAME_SIZE 200
+#endif
+
+/* object (image, attachment, thumbnail) file name (may be used for file system) */
+#ifndef BIP_OBJ_NAME_SIZE
+#define BIP_OBJ_NAME_SIZE 200
+#endif
+
+
+
+/******************************************************************************
+**
+** HCRP
+**
+******************************************************************************/
+
+#ifndef HCRP_INCLUDED
+#define HCRP_INCLUDED FALSE
+#endif
+
+/* This is set to enable server. */
+#ifndef HCRP_SERVER_INCLUDED
+#define HCRP_SERVER_INCLUDED FALSE
+#endif
+
+/* This is set to enable client. */
+#ifndef HCRP_CLIENT_INCLUDED
+#define HCRP_CLIENT_INCLUDED FALSE
+#endif
+
+/* TRUE enables the notification option of the profile. */
+#ifndef HCRP_NOTIFICATION_INCLUDED
+#define HCRP_NOTIFICATION_INCLUDED TRUE
+#endif
+
+/* TRUE enables the vendor specific option of the profile. */
+#ifndef HCRP_VENDOR_SPEC_INCLUDED
+#define HCRP_VENDOR_SPEC_INCLUDED TRUE
+#endif
+
+/* TRUE enables state machine traces. */
+#ifndef HCRP_FSM_DEBUG
+#define HCRP_FSM_DEBUG FALSE
+#endif
+
+/* TRUE enables protocol message traces. */
+#ifndef HCRP_PROTO_DEBUG
+#define HCRP_PROTO_DEBUG FALSE
+#endif
+
+/* Maximum length used to store the service name (Minimum 1). */
+#ifndef HCRP_MAX_SERVICE_NAME_LEN
+#define HCRP_MAX_SERVICE_NAME_LEN 32
+#endif
+
+/* Maximum length used to store the device name (Minimum 1). */
+#ifndef HCRP_MAX_DEVICE_NAME_LEN
+#define HCRP_MAX_DEVICE_NAME_LEN 32
+#endif
+
+/* Maximum length of device location (Minimum 1) */
+#ifndef HCRP_MAX_DEVICE_LOC_LEN
+#define HCRP_MAX_DEVICE_LOC_LEN 32
+#endif
+
+/* Maximum length used to store the friendly name (Minimum 1). */
+#ifndef HCRP_MAX_FRIENDLY_NAME_LEN
+#define HCRP_MAX_FRIENDLY_NAME_LEN 32
+#endif
+
+/* Maximum length used to store the 1284 id string (Minimum 2 byte length field). */
+#ifndef HCRP_MAX_SDP_1284_ID_LEN
+#define HCRP_MAX_SDP_1284_ID_LEN 128
+#endif
+
+/* Maximum length for parameters to be processed for vendor specific commands. */
+#ifndef HCRP_MAX_VEND_SPEC_LEN
+#define HCRP_MAX_VEND_SPEC_LEN 4
+#endif
+
+/* Number of seconds to wait for 2nd GAP to open. */
+#ifndef HCRP_OPEN_CHAN_TOUT
+#define HCRP_OPEN_CHAN_TOUT 5
+#endif
+
+/* Number of seconds to wait for 2nd GAP to close. */
+#ifndef HCRP_CLOSE_CHAN_TOUT
+#define HCRP_CLOSE_CHAN_TOUT 3
+#endif
+
+/* Number of seconds to wait for the application to respond to a protocol request. */
+#ifndef HCRP_APPL_RSP_TOUT
+#define HCRP_APPL_RSP_TOUT 5
+#endif
+
+/* Number of seconds to wait for the peer device to respond to a protocol request. */
+#ifndef HCRP_CMD_RSP_TOUT
+#define HCRP_CMD_RSP_TOUT 7
+#endif
+
+/* Number of seconds between subsequent credit requests to the server when the send watermark has been exceeded. */
+#ifndef HCRP_CREDIT_REQ_UPDATES
+#define HCRP_CREDIT_REQ_UPDATES 1
+#endif
+
+/* Maximum number of results to return in a HCRP_FindServices search. */
+#ifndef HCRP_MAX_SEARCH_RESULTS
+#define HCRP_MAX_SEARCH_RESULTS 1
+#endif
+
+/* Maximum number of bytes to be reserved for searching for the client's notification record. */
+#ifndef HCRP_MAX_NOTIF_DISC_BUF
+#define HCRP_MAX_NOTIF_DISC_BUF 300
+#endif
+
+/* Maximum number of clients the server will allow to be registered for notifications. */
+#ifndef HCRP_MAX_NOTIF_CLIENTS
+#define HCRP_MAX_NOTIF_CLIENTS 3
+#endif
+
+/* Spec says minimum of two notification retries. */
+#ifndef HCRP_NOTIF_NUM_RETRIES
+#define HCRP_NOTIF_NUM_RETRIES 4
+#endif
+
+/*************************************************************************
+** Definitions for Multi-Client Server HCRP
+** Note: Many of the above HCRP definitions are also used
+** Maximum number of clients allowed to connect simultaneously
+** Must be less than ((GAP_MAX_CONNECTIONS - 1) / 2)
+*/
+#ifndef HCRPM_MAX_CLIENTS
+#define HCRPM_MAX_CLIENTS 3
+#endif
+
+
+/******************************************************************************
+**
+** PAN
+**
+******************************************************************************/
+
+#ifndef PAN_INCLUDED
+#define PAN_INCLUDED FALSE
+#endif
+
+
+/******************************************************************************
+**
+** SAP
+**
+******************************************************************************/
+
+#ifndef SAP_SERVER_INCLUDED
+#define SAP_SERVER_INCLUDED FALSE
+#endif
+
+
+/*************************************************************************
+ * A2DP Definitions
+ */
+#ifndef A2D_INCLUDED
+#define A2D_INCLUDED FALSE
+#endif
+
+/* TRUE to include SBC utility functions */
+#ifndef A2D_SBC_INCLUDED
+#define A2D_SBC_INCLUDED A2D_INCLUDED
+#endif
+
+/* TRUE to include MPEG-1,2 (mp3) utility functions */
+#ifndef A2D_M12_INCLUDED
+#define A2D_M12_INCLUDED A2D_INCLUDED
+#endif
+
+/* TRUE to include MPEG-2,4 (aac) utility functions */
+#ifndef A2D_M24_INCLUDED
+#define A2D_M24_INCLUDED A2D_INCLUDED
+#endif
+
+/*************************************************************************
+ * VDP Definitions
+ */
+#ifndef VDP_INCLUDED
+#define VDP_INCLUDED FALSE
+#endif
+
+/******************************************************************************
+**
+** AVCTP
+**
+******************************************************************************/
+
+#ifndef AVCT_INCLUDED
+#define AVCT_INCLUDED FALSE
+#endif
+
+/* Number of simultaneous ACL links to different peer devices. */
+#ifndef AVCT_NUM_LINKS
+#define AVCT_NUM_LINKS 2
+#endif
+
+/* Number of simultaneous AVCTP connections. */
+#ifndef AVCT_NUM_CONN
+#define AVCT_NUM_CONN 3
+#endif
+
+/* TRUE to support the browsing channel. */
+#ifndef AVCT_BROWSE_INCLUDED
+#define AVCT_BROWSE_INCLUDED TRUE
+#endif
+
+#if ((L2CAP_FCR_INCLUDED == FALSE) && (AVCT_BROWSE_INCLUDED == TRUE))
+#undef AVCT_BROWSE_INCLUDED
+#define AVCT_BROWSE_INCLUDED FALSE
+#endif
+
+/* Pool ID where to reassemble the SDU.
+ This Pool allows buffers to be used that are larger than
+ the L2CAP_MAX_MTU. */
+#ifndef AVCT_BR_USER_RX_POOL_ID
+#define AVCT_BR_USER_RX_POOL_ID HCI_ACL_POOL_ID
+#endif
+
+/* Pool ID where to hold the SDU.
+ This Pool allows buffers to be used that are larger than
+ the L2CAP_MAX_MTU. */
+#ifndef AVCT_BR_USER_TX_POOL_ID
+#define AVCT_BR_USER_TX_POOL_ID HCI_ACL_POOL_ID
+#endif
+
+/*
+GKI Buffer Pool ID used to hold MPS segments during SDU reassembly
+*/
+#ifndef AVCT_BR_FCR_RX_POOL_ID
+#define AVCT_BR_FCR_RX_POOL_ID HCI_ACL_POOL_ID
+#endif
+
+/*
+GKI Buffer Pool ID used to hold MPS segments used in (re)transmissions.
+L2CAP_DEFAULT_ERM_POOL_ID is specified to use the HCI ACL data pool.
+Note: This pool needs to have enough buffers to hold two times the window size negotiated
+ in the tL2CAP_FCR_OPTIONS (2 * tx_win_size) to allow for retransmissions.
+ The size of each buffer must be able to hold the maximum MPS segment size passed in
+ tL2CAP_FCR_OPTIONS plus BT_HDR (8) + HCI preamble (4) + L2CAP_MIN_OFFSET (11 - as of BT 2.1 + EDR Spec).
+*/
+#ifndef AVCT_BR_FCR_TX_POOL_ID
+#define AVCT_BR_FCR_TX_POOL_ID HCI_ACL_POOL_ID
+#endif
+
+/* AVCTP Browsing channel FCR Option:
+Size of the transmission window when using enhanced retransmission mode. Not used
+in basic and streaming modes. Range: 1 - 63
+*/
+#ifndef AVCT_BR_FCR_OPT_TX_WINDOW_SIZE
+#define AVCT_BR_FCR_OPT_TX_WINDOW_SIZE 10
+#endif
+
+/* AVCTP Browsing channel FCR Option:
+Number of transmission attempts for a single I-Frame before taking
+Down the connection. Used In ERTM mode only. Value is Ignored in basic and
+Streaming modes.
+Range: 0, 1-0xFF
+0 - infinite retransmissions
+1 - single transmission
+*/
+#ifndef AVCT_BR_FCR_OPT_MAX_TX_B4_DISCNT
+#define AVCT_BR_FCR_OPT_MAX_TX_B4_DISCNT 20
+#endif
+
+/* AVCTP Browsing channel FCR Option: Retransmission Timeout
+The AVRCP specification set a value in the range of 300 - 2000 ms
+Timeout (in msecs) to detect Lost I-Frames. Only used in Enhanced retransmission mode.
+Range: Minimum 2000 (2 secs) when supporting PBF.
+ */
+#ifndef AVCT_BR_FCR_OPT_RETX_TOUT
+#define AVCT_BR_FCR_OPT_RETX_TOUT 2000
+#endif
+
+/* AVCTP Browsing channel FCR Option: Monitor Timeout
+The AVRCP specification set a value in the range of 300 - 2000 ms
+Timeout (in msecs) to detect Lost S-Frames. Only used in Enhanced retransmission mode.
+Range: Minimum 12000 (12 secs) when supporting PBF.
+*/
+#ifndef AVCT_BR_FCR_OPT_MONITOR_TOUT
+#define AVCT_BR_FCR_OPT_MONITOR_TOUT 12000
+#endif
+
+/******************************************************************************
+**
+** AVRCP
+**
+******************************************************************************/
+
+#ifndef AVRC_INCLUDED
+#define AVRC_INCLUDED FALSE
+#endif
+
+/* TRUE to support AVRCP 1.3 - Metadata. */
+#ifndef AVRC_METADATA_INCLUDED
+#define AVRC_METADATA_INCLUDED TRUE
+#endif
+
+/* TRUE to support AVRCP 1.4 - Advanced Control. */
+#ifndef AVRC_ADV_CTRL_INCLUDED
+#define AVRC_ADV_CTRL_INCLUDED TRUE
+#endif
+
+/******************************************************************************
+**
+** MCAP
+**
+******************************************************************************/
+#ifndef MCA_INCLUDED
+#define MCA_INCLUDED FALSE
+#endif
+
+/* TRUE to support Clock Synchronization OpCodes */
+#ifndef MCA_SYNC_INCLUDED
+#define MCA_SYNC_INCLUDED FALSE
+#endif
+
+/* The MTU size for the L2CAP configuration on control channel. 48 is the minimal */
+#ifndef MCA_CTRL_MTU
+#define MCA_CTRL_MTU 60
+#endif
+
+/* The maximum number of registered MCAP instances. */
+#ifndef MCA_NUM_REGS
+#define MCA_NUM_REGS 3
+#endif
+
+/* The maximum number of control channels (to difference devices) per registered MCAP instances. */
+#ifndef MCA_NUM_LINKS
+#define MCA_NUM_LINKS 3
+#endif
+
+/* The maximum number of MDEP (including HDP echo) per registered MCAP instances. */
+#ifndef MCA_NUM_DEPS
+#define MCA_NUM_DEPS 3
+#endif
+
+/* The maximum number of MDL link per control channel. */
+#ifndef MCA_NUM_MDLS
+#define MCA_NUM_MDLS 4
+#endif
+
+/* Pool ID where to reassemble the SDU. */
+#ifndef MCA_USER_RX_POOL_ID
+#define MCA_USER_RX_POOL_ID HCI_ACL_POOL_ID
+#endif
+
+/* Pool ID where to hold the SDU. */
+#ifndef MCA_USER_TX_POOL_ID
+#define MCA_USER_TX_POOL_ID HCI_ACL_POOL_ID
+#endif
+
+/*
+GKI Buffer Pool ID used to hold MPS segments during SDU reassembly
+*/
+#ifndef MCA_FCR_RX_POOL_ID
+#define MCA_FCR_RX_POOL_ID HCI_ACL_POOL_ID
+#endif
+
+/*
+GKI Buffer Pool ID used to hold MPS segments used in (re)transmissions.
+L2CAP_DEFAULT_ERM_POOL_ID is specified to use the HCI ACL data pool.
+Note: This pool needs to have enough buffers to hold two times the window size negotiated
+ in the tL2CAP_FCR_OPTIONS (2 * tx_win_size) to allow for retransmissions.
+ The size of each buffer must be able to hold the maximum MPS segment size passed in
+ tL2CAP_FCR_OPTIONS plus BT_HDR (8) + HCI preamble (4) + L2CAP_MIN_OFFSET (11 - as of BT 2.1 + EDR Spec).
+*/
+#ifndef MCA_FCR_TX_POOL_ID
+#define MCA_FCR_TX_POOL_ID HCI_ACL_POOL_ID
+#endif
+
+/* MCAP control channel FCR Option:
+Size of the transmission window when using enhanced retransmission mode.
+1 is defined by HDP specification for control channel.
+*/
+#ifndef MCA_FCR_OPT_TX_WINDOW_SIZE
+#define MCA_FCR_OPT_TX_WINDOW_SIZE 1
+#endif
+
+/* MCAP control channel FCR Option:
+Number of transmission attempts for a single I-Frame before taking
+Down the connection. Used In ERTM mode only. Value is Ignored in basic and
+Streaming modes.
+Range: 0, 1-0xFF
+0 - infinite retransmissions
+1 - single transmission
+*/
+#ifndef MCA_FCR_OPT_MAX_TX_B4_DISCNT
+#define MCA_FCR_OPT_MAX_TX_B4_DISCNT 20
+#endif
+
+/* MCAP control channel FCR Option: Retransmission Timeout
+The AVRCP specification set a value in the range of 300 - 2000 ms
+Timeout (in msecs) to detect Lost I-Frames. Only used in Enhanced retransmission mode.
+Range: Minimum 2000 (2 secs) when supporting PBF.
+ */
+#ifndef MCA_FCR_OPT_RETX_TOUT
+#define MCA_FCR_OPT_RETX_TOUT 2000
+#endif
+
+/* MCAP control channel FCR Option: Monitor Timeout
+The AVRCP specification set a value in the range of 300 - 2000 ms
+Timeout (in msecs) to detect Lost S-Frames. Only used in Enhanced retransmission mode.
+Range: Minimum 12000 (12 secs) when supporting PBF.
+*/
+#ifndef MCA_FCR_OPT_MONITOR_TOUT
+#define MCA_FCR_OPT_MONITOR_TOUT 12000
+#endif
+
+/* MCAP control channel FCR Option: Maximum PDU payload size.
+The maximum number of payload octets that the local device can receive in a single PDU.
+*/
+#ifndef MCA_FCR_OPT_MPS_SIZE
+#define MCA_FCR_OPT_MPS_SIZE 1000
+#endif
+
+/* Shared transport */
+#ifndef NFC_SHARED_TRANSPORT_ENABLED
+#define NFC_SHARED_TRANSPORT_ENABLED FALSE
+#endif
+
+/******************************************************************************
+**
+** SER
+**
+******************************************************************************/
+
+#ifndef SER_INCLUDED
+#define SER_INCLUDED FALSE
+#endif
+
+/* Task which runs the serial application. */
+#ifndef SER_TASK
+#define SER_TASK BTE_APPL_TASK
+#endif
+
+/* Mailbox used by serial application. */
+#ifndef SER_MBOX
+#define SER_MBOX TASK_MBOX_1
+#endif
+
+/* Mailbox mask. */
+#ifndef SER_MBOX_MASK
+#define SER_MBOX_MASK TASK_MBOX_1_EVT_MASK
+#endif
+
+/* TX path application event. */
+#ifndef SER_TX_PATH_APPL_EVT
+#define SER_TX_PATH_APPL_EVT EVENT_MASK(APPL_EVT_3)
+#endif
+
+/* RX path application event. */
+#ifndef SER_RX_PATH_APPL_EVT
+#define SER_RX_PATH_APPL_EVT EVENT_MASK(APPL_EVT_4)
+#endif
+
+/******************************************************************************
+**
+** Sleep Mode (Low Power Mode)
+**
+******************************************************************************/
+
+#ifndef HCILP_INCLUDED
+#define HCILP_INCLUDED TRUE
+#endif
+
+/******************************************************************************
+**
+** RPC
+**
+******************************************************************************/
+
+#ifndef RPC_INCLUDED
+#define RPC_INCLUDED FALSE
+#endif
+
+/* RPCT task mailbox ID for messages coming from rpcgen code. */
+#ifndef RPCT_MBOX
+#define RPCT_MBOX TASK_MBOX_0
+#endif
+
+/* RPCT task event for mailbox. */
+#ifndef RPCT_RPC_MBOX_EVT
+#define RPCT_RPC_MBOX_EVT TASK_MBOX_0_EVT_MASK
+#endif
+
+/* RPCT task event from driver indicating RX data is ready. */
+#ifndef RPCT_RX_READY_EVT
+#define RPCT_RX_READY_EVT APPL_EVT_0
+#endif
+
+/* RPCT task event from driver indicating data TX is done. */
+#ifndef RPCT_TX_DONE_EVT
+#define RPCT_TX_DONE_EVT APPL_EVT_1
+#endif
+
+/* RPCT task event indicating data is in the circular buffer. */
+#ifndef RPCT_UCBUF_EVT
+#define RPCT_UCBUF_EVT APPL_EVT_2
+#endif
+
+/* Task ID of RPCGEN task. */
+#ifndef RPCGEN_TASK
+#define RPCGEN_TASK BTU_TASK
+#endif
+
+/* RPCGEN task event for messages coming from RPCT. */
+#ifndef RPCGEN_MSG_EVT
+#define RPCGEN_MSG_EVT TASK_MBOX_1_EVT_MASK
+#endif
+
+#ifndef RPCGEN_MSG_MBOX
+#define RPCGEN_MSG_MBOX TASK_MBOX_1
+#endif
+
+/* Size of circular buffer used to store diagnostic messages. */
+#ifndef RPCT_UCBUF_SIZE
+#define RPCT_UCBUF_SIZE 2000
+#endif
+
+/******************************************************************************
+**
+** SAP - Sample applications
+**
+******************************************************************************/
+
+#ifndef MMI_INCLUDED
+#define MMI_INCLUDED FALSE
+#endif
+
+/******************************************************************************
+**
+** APPL - Application Task
+**
+******************************************************************************/
+/* When TRUE indicates that an application task is to be run */
+#ifndef APPL_INCLUDED
+#define APPL_INCLUDED FALSE
+#endif
+
+/* When TRUE remote terminal code included (RPC MUST be included) */
+#ifndef RSI_INCLUDED
+#define RSI_INCLUDED FALSE
+#endif
+
+
+
+#define L2CAP_FEATURE_REQ_ID 73
+#define L2CAP_FEATURE_RSP_ID 173
+
+
+#define L2CAP_ENHANCED_FEATURES 0
+
+
+/******************************************************************************
+**
+** BTA
+**
+******************************************************************************/
+/* BTA EIR canned UUID list (default is dynamic) */
+#ifndef BTA_EIR_CANNED_UUID_LIST
+#define BTA_EIR_CANNED_UUID_LIST FALSE
+#endif
+
+/* Number of supported customer UUID in EIR */
+#ifndef BTA_EIR_SERVER_NUM_CUSTOM_UUID
+#define BTA_EIR_SERVER_NUM_CUSTOM_UUID 8
+#endif
+
+
+/******************************************************************************
+**
+** BTE
+**
+******************************************************************************/
+#ifndef BTE_PLATFORM_IDLE
+#define BTE_PLATFORM_IDLE
+#endif
+
+#ifndef BTE_IDLE_TASK_INCLUDED
+#define BTE_IDLE_TASK_INCLUDED TRUE
+#endif
+
+#ifndef BTE_PLATFORM_INITHW
+#define BTE_PLATFORM_INITHW
+#endif
+
+#ifndef BTE_BTA_CODE_INCLUDED
+#define BTE_BTA_CODE_INCLUDED FALSE
+#endif
+
+
+/******************************************************************************
+**
+** BTTRC
+**
+******************************************************************************/
+/* Whether to parse and display traces-> Platform specific implementation */
+#ifndef BTTRC_DISP
+#define BTTRC_DISP BTTRC_DispOnInsight
+#endif
+
+/******************************************************************************
+**
+** Tracing: Include trace header file here.
+**
+******************************************************************************/
+
+#include "bt_trace.h"
+
+#endif /* BT_TARGET_H */
+
diff --git a/include/bt_trace.h b/include/bt_trace.h
new file mode 100644
index 0000000..f9b9707
--- /dev/null
+++ b/include/bt_trace.h
@@ -0,0 +1,4763 @@
+/****************************************************************************/
+/* */
+/* Name: bt_trace.h */
+/* */
+/* Function this file contains definitions for implementing the */
+/* diagnostic trace message service. */
+/* */
+/* */
+/* Copyright (c) 1999-2011, Broadcom Corp., All Rights Reserved. */
+/* WIDCOMM Bluetooth Core. Proprietary and confidential. */
+/* */
+/****************************************************************************/
+#ifndef BT_TRACE_H
+#define BT_TRACE_H
+
+#ifndef BTTRC_INCLUDED
+#define BTTRC_INCLUDED FALSE
+#endif
+#ifndef BTTRC_PARSER_INCLUDED
+#define BTTRC_PARSER_INCLUDED FALSE
+#endif
+#ifndef MAX_TRACE_RAM_SIZE
+#define MAX_TRACE_RAM_SIZE 10000
+#endif
+
+/* BTE tracing IDs for debug purposes */
+/* LayerIDs for stack */
+#define BTTRC_ID_STK_GKI 1
+#define BTTRC_ID_STK_BTU 2
+#define BTTRC_ID_STK_HCI 3
+#define BTTRC_ID_STK_L2CAP 4
+#define BTTRC_ID_STK_RFCM_MX 5
+#define BTTRC_ID_STK_RFCM_PRT 6
+#define BTTRC_ID_STK_OBEX_C 7
+#define BTTRC_ID_STK_OBEX_S 8
+#define BTTRC_ID_STK_AVCT 9
+#define BTTRC_ID_STK_AVDT 10
+#define BTTRC_ID_STK_AVRC 11
+#define BTTRC_ID_STK_BIC 12
+#define BTTRC_ID_STK_BIS 13
+#define BTTRC_ID_STK_BNEP 14
+#define BTTRC_ID_STK_BPP 15
+#define BTTRC_ID_STK_BTM_ACL 16
+#define BTTRC_ID_STK_BTM_PM 17
+#define BTTRC_ID_STK_BTM_DEV_CTRL 18
+#define BTTRC_ID_STK_BTM_SVC_DSC 19
+#define BTTRC_ID_STK_BTM_INQ 20
+#define BTTRC_ID_STK_BTM_SCO 21
+#define BTTRC_ID_STK_BTM_SEC 22
+#define BTTRC_ID_STK_DUN 23
+#define BTTRC_ID_STK_HID 24
+#define BTTRC_ID_STK_HSP2 25
+#define BTTRC_ID_STK_CTP 26
+#define BTTRC_ID_STK_FTC 27
+#define BTTRC_ID_STK_FTS 28
+#define BTTRC_ID_STK_GAP 29
+#define BTTRC_ID_STK_GOEP 30
+#define BTTRC_ID_STK_HCRP 31
+#define BTTRC_ID_STK_ICP 32
+#define BTTRC_ID_STK_OPC 33
+#define BTTRC_ID_STK_OPS 34
+#define BTTRC_ID_STK_PAN 35
+#define BTTRC_ID_STK_SAP 36
+#define BTTRC_ID_STK_SDP 37
+#define BTTRC_ID_STK_SLIP 38
+#define BTTRC_ID_STK_SPP 39
+#define BTTRC_ID_STK_TCS 40
+#define BTTRC_ID_STK_VDP 41
+#define BTTRC_ID_STK_MCAP 42
+#define BTTRC_ID_STK_GATT 43
+#define BTTRC_ID_STK_SMP 44
+#define BTTRC_ID_STK_NFC 45
+#define BTTRC_ID_STK_NCI 46
+#define BTTRC_ID_STK_IDEP 47
+#define BTTRC_ID_STK_NDEP 48
+#define BTTRC_ID_STK_LLCP 49
+#define BTTRC_ID_STK_RW 50
+#define BTTRC_ID_STK_CE 51
+#define BTTRC_ID_STK_SNEP 52
+#define BTTRC_ID_STK_NDEF 53
+
+
+/* LayerIDs for BTA */
+#define BTTRC_ID_BTA_ACC 55 /* Advanced Camera Client */
+#define BTTRC_ID_BTA_AG 56 /* audio gateway */
+#define BTTRC_ID_BTA_AV 57 /* Advanced audio */
+#define BTTRC_ID_BTA_BIC 58 /* Basic Imaging Client */
+#define BTTRC_ID_BTA_BIS 59 /* Basic Imaging Server */
+#define BTTRC_ID_BTA_BP 60 /* Basic Printing Client */
+#define BTTRC_ID_BTA_CG 61
+#define BTTRC_ID_BTA_CT 62 /* cordless telephony terminal */
+#define BTTRC_ID_BTA_DG 63 /* data gateway */
+#define BTTRC_ID_BTA_DM 64 /* device manager */
+#define BTTRC_ID_BTA_DM_SRCH 65 /* device manager search */
+#define BTTRC_ID_BTA_DM_SEC 66 /* device manager security */
+#define BTTRC_ID_BTA_FM 67
+#define BTTRC_ID_BTA_FTC 68 /* file transfer client */
+#define BTTRC_ID_BTA_FTS 69 /* file transfer server */
+#define BTTRC_ID_BTA_HIDH 70
+#define BTTRC_ID_BTA_HIDD 71
+#define BTTRC_ID_BTA_JV 72
+#define BTTRC_ID_BTA_OPC 73 /* object push client */
+#define BTTRC_ID_BTA_OPS 74 /* object push server */
+#define BTTRC_ID_BTA_PAN 75 /* Personal Area Networking */
+#define BTTRC_ID_BTA_PR 76 /* Printer client */
+#define BTTRC_ID_BTA_SC 77 /* SIM Card Access server */
+#define BTTRC_ID_BTA_SS 78 /* synchronization server */
+#define BTTRC_ID_BTA_SYS 79 /* system manager */
+#define BTTRC_ID_AVDT_SCB 80 /* avdt scb */
+#define BTTRC_ID_AVDT_CCB 81 /* avdt ccb */
+
+// btla-specific ++
+/* LayerIDs added for BTL-A. Probably should modify bte_logmsg.c in future. */
+#define BTTRC_ID_STK_RFCOMM 82
+#define BTTRC_ID_STK_RFCOMM_DATA 83
+#define BTTRC_ID_STK_OBEX 84
+#define BTTRC_ID_STK_A2D 85
+#define BTTRC_ID_STK_BIP 86
+
+/* LayerIDs for BT APP */
+#define BTTRC_ID_BTAPP 87
+#define BTTRC_ID_BT_PROTOCOL 88 /* this is a temporary solution to allow dynamic
+ enable/disable of BT_PROTOCOL_TRACE */
+#define BTTRC_ID_MAX_ID BTTRC_ID_BT_PROTOCOL
+// btla-specific --
+#define BTTRC_ID_ALL_LAYERS 0xFF /* all trace layers */
+typedef UINT8 tBTTRC_LAYER_ID;
+
+/* Trace type definitions. Note that these are mutually exclusive in a trace. This
+means that any trace can be either error,warning,api,event or dbg */
+#define BTTRC_TYPE_ERROR 0x01 /* Traces for error situation */
+#define BTTRC_TYPE_WARNING 0x02 /* Traces for warning situation */
+#define BTTRC_TYPE_API 0x04 /* Traces for API */
+#define BTTRC_TYPE_EVENT 0x08 /* Traces for EVENT */
+#define BTTRC_TYPE_ACTION 0x10 /* Traces for Action functions */
+#define BTTRC_TYPE_DBG 0x20 /* Traces for debugging purpose */
+typedef UINT8 tBTTRC_TYPE;
+
+/* Masks to identify the stack that originated the trace */
+#define BTTRC_TRACE_LITE 0x80 /* MM Lite stack */
+#define BTTRC_TRACE_EMBD 0x40 /* Embedded host stack */
+
+/* Parameter datatypes used in Trace APIs */
+#define BTTRC_PARAM_UINT8 1
+#define BTTRC_PARAM_UINT16 2
+#define BTTRC_PARAM_UINT32 3
+typedef UINT8 tBTTRC_PARAM_TYPE;
+
+/* Special token definitions */
+#define BTTRC_TOKEN_SM_STATE 0xFFFF /* Token indicating the State of a State m/c */
+
+// btla-specific ++
+typedef struct {
+ tBTTRC_LAYER_ID layer_id;
+ tBTTRC_TYPE type; /* TODO: use tBTTRC_TYPE instead of "classical level 0-5" */
+} tBTTRC_LEVEL;
+
+typedef UINT8 (tBTTRC_SET_TRACE_LEVEL)( UINT8 );
+
+/* potentially to save flash, you could compile this out. however some functions may need adjustments! */
+#ifndef USE_TEXT_ID
+#define USE_TEXT_ID TRUE
+#endif
+
+typedef struct {
+ const tBTTRC_LAYER_ID layer_id_start;
+ const tBTTRC_LAYER_ID layer_id_end;
+ const tBTTRC_SET_TRACE_LEVEL *p_f;
+#if (USE_TEXT_ID==TRUE)
+ const char *trc_name;
+#endif
+} tBTTRC_FUNC_MAP;
+
+extern const tBTTRC_FUNC_MAP bttrc_set_level_map[];
+extern const UINT16 bttrc_map_size;
+extern BT_API tBTTRC_LEVEL * BTA_SysSetTraceLevel( tBTTRC_LEVEL * p_levels );
+// btla-specific --
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* External declaration for appl_trace_level here to avoid to add the declaration in all the files using APPL_TRACExxx macros */
+extern UINT8 appl_trace_level ;
+
+// btla-specific ++
+EXPORT_API extern void BTE_InitTraceLevels( void );
+// btla-specific --
+
+/* Prototype for message logging function. */
+EXPORT_API extern void LogMsg (UINT32 trace_set_mask, const char *fmt_str, ...);
+extern void LogMsg_0 (UINT32 trace_set_mask, const char *p_str);
+extern void LogMsg_1 (UINT32 trace_set_mask, const char *fmt_str, UINT32 p1);
+extern void LogMsg_2 (UINT32 trace_set_mask, const char *fmt_str, UINT32 p1, UINT32 p2);
+extern void LogMsg_3 (UINT32 trace_set_mask, const char *fmt_str, UINT32 p1, UINT32 p2,
+ UINT32 p3);
+extern void LogMsg_4 (UINT32 trace_set_mask, const char *fmt_str, UINT32 p1, UINT32 p2,
+ UINT32 p3, UINT32 p4);
+extern void LogMsg_5 (UINT32 trace_set_mask, const char *fmt_str, UINT32 p1, UINT32 p2,
+ UINT32 p3, UINT32 p4, UINT32 p5);
+extern void LogMsg_6 (UINT32 trace_set_mask, const char *fmt_str, UINT32 p1, UINT32 p2,
+ UINT32 p3, UINT32 p4, UINT32 p5, UINT32 p6);
+
+/* Prototype for stack tracing function. */
+EXPORT_API extern void BTTRC_StackTrace0(tBTTRC_LAYER_ID layer_id,
+ tBTTRC_TYPE type,
+ UINT16 token);
+EXPORT_API extern void BTTRC_StackTrace1(tBTTRC_LAYER_ID layer_id,
+ tBTTRC_TYPE type,
+ UINT16 token,
+ tBTTRC_PARAM_TYPE p1_type, UINT32 p1_val);
+EXPORT_API extern void BTTRC_StackTrace2(tBTTRC_LAYER_ID layer_id,
+ tBTTRC_TYPE type,
+ UINT16 token,
+ tBTTRC_PARAM_TYPE p1_type, UINT32 p1_val,
+ tBTTRC_PARAM_TYPE p2_type, UINT32 p2_val);
+EXPORT_API extern void BTTRC_StackTrace3(tBTTRC_LAYER_ID layer_id,
+ tBTTRC_TYPE type,
+ UINT16 token,
+ tBTTRC_PARAM_TYPE p1_type, UINT32 p1_val,
+ tBTTRC_PARAM_TYPE p2_type, UINT32 p2_val,
+ tBTTRC_PARAM_TYPE p3_type, UINT32 p3_val);
+EXPORT_API extern void BTTRC_StackTrace4(tBTTRC_LAYER_ID layer_id,
+ tBTTRC_TYPE type,
+ UINT16 token,
+ tBTTRC_PARAM_TYPE p1_type, UINT32 p1_val,
+ tBTTRC_PARAM_TYPE p2_type, UINT32 p2_val,
+ tBTTRC_PARAM_TYPE p3_type, UINT32 p3_val,
+ tBTTRC_PARAM_TYPE p4_type, UINT32 p4_val);
+EXPORT_API extern void BTTRC_StackTrace5(tBTTRC_LAYER_ID layer_id,
+ tBTTRC_TYPE type,
+ UINT16 token,
+ tBTTRC_PARAM_TYPE p1_type, UINT32 p1_val,
+ tBTTRC_PARAM_TYPE p2_type, UINT32 p2_val,
+ tBTTRC_PARAM_TYPE p3_type, UINT32 p3_val,
+ tBTTRC_PARAM_TYPE p4_type, UINT32 p4_val,
+ tBTTRC_PARAM_TYPE p5_type, UINT32 p5_val);
+EXPORT_API extern void BTTRC_StackTrace6(tBTTRC_LAYER_ID layer_id,
+ tBTTRC_TYPE type,
+ UINT16 token,
+ tBTTRC_PARAM_TYPE p1_type, UINT32 p1_val,
+ tBTTRC_PARAM_TYPE p2_type, UINT32 p2_val,
+ tBTTRC_PARAM_TYPE p3_type, UINT32 p3_val,
+ tBTTRC_PARAM_TYPE p4_type, UINT32 p4_val,
+ tBTTRC_PARAM_TYPE p5_type, UINT32 p5_val,
+ tBTTRC_PARAM_TYPE p6_type, UINT32 p6_val);
+
+// btla-specific ++
+/* p_levels must be a 0 terminated list ! */
+//EXPORT_API extern tBTTRC_LEVEL * BTA_SysSetTraceLevel( tBTTRC_LEVEL * p_levels );
+// btla-specific --
+
+#ifdef __cplusplus
+}
+#endif
+
+/******************************************************************************
+**
+** Trace configurable parameters
+**
+******************************************************************************/
+
+/* Enables or disables verbose trace information. */
+#ifndef BT_TRACE_VERBOSE
+#define BT_TRACE_VERBOSE FALSE
+#endif
+
+/* Enables or disables all trace messages. */
+#ifndef BT_USE_TRACES
+#define BT_USE_TRACES TRUE
+#endif
+
+
+/******************************************************************************
+**
+** Trace Levels
+**
+** The following values may be used for different levels:
+** BT_TRACE_LEVEL_NONE 0 * No trace messages to be generated
+** BT_TRACE_LEVEL_ERROR 1 * Error condition trace messages
+** BT_TRACE_LEVEL_WARNING 2 * Warning condition trace messages
+** BT_TRACE_LEVEL_API 3 * API traces
+** BT_TRACE_LEVEL_EVENT 4 * Debug messages for events
+** BT_TRACE_LEVEL_DEBUG 5 * Debug messages (general)
+******************************************************************************/
+
+// btla-specific ++
+/* Core Stack default trace levels */
+#ifndef HCI_INITIAL_TRACE_LEVEL
+#define HCI_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef BTM_INITIAL_TRACE_LEVEL
+#define BTM_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef L2CAP_INITIAL_TRACE_LEVEL
+#define L2CAP_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef LLCP_INITIAL_TRACE_LEVEL
+#define LLCP_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef AMP_INITIAL_TRACE_LEVEL
+#define AMP_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef RFCOMM_INITIAL_TRACE_LEVEL
+#define RFCOMM_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef OBX_INITIAL_TRACE_LEVEL
+#define OBX_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef SDP_INITIAL_TRACE_LEVEL
+#define SDP_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef TCS_INITIAL_TRACE_LEVEL
+#define TCS_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+/* Profile default trace levels */
+#ifndef DUN_INITIAL_TRACE_LEVEL
+#define DUN_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef GAP_INITIAL_TRACE_LEVEL
+#define GAP_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef GOEP_INITIAL_TRACE_LEVEL
+#define GOEP_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef HSP2_INITIAL_TRACE_LEVEL
+#define HSP2_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef SPP_INITIAL_TRACE_LEVEL
+#define SPP_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef ICP_INITIAL_TRACE_LEVEL
+#define ICP_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef CTP_INITIAL_TRACE_LEVEL
+#define CTP_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef HCRP_INITIAL_TRACE_LEVEL
+#define HCRP_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef HCRPM_INITIAL_TRACE_LEVEL
+#define HCRPM_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef BPP_INITIAL_TRACE_LEVEL
+#define BPP_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef BIP_INITIAL_TRACE_LEVEL
+#define BIP_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef BNEP_INITIAL_TRACE_LEVEL
+#define BNEP_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef PAN_INITIAL_TRACE_LEVEL
+#define PAN_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef SAP_INITIAL_TRACE_LEVEL
+#define SAP_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef FTP_INITIAL_TRACE_LEVEL
+#define FTP_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef OPP_INITIAL_TRACE_LEVEL
+#define OPP_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef HFP_INITIAL_TRACE_LEVEL
+#define HFP_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef PAP_INITIAL_TRACE_LEVEL
+#define PAP_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef A2D_INITIAL_TRACE_LEVEL
+#define A2D_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef VDP_INITIAL_TRACE_LEVEL
+#define VDP_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef AVDT_INITIAL_TRACE_LEVEL
+#define AVDT_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef AVCT_INITIAL_TRACE_LEVEL
+#define AVCT_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef AVRC_INITIAL_TRACE_LEVEL
+#define AVRC_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef MCA_INITIAL_TRACE_LEVEL
+#define MCA_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef HID_INITIAL_TRACE_LEVEL
+#define HID_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+/* Application and other default trace levels */
+#ifndef RPC_INITIAL_TRACE_LEVEL
+#define RPC_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef APPL_INITIAL_TRACE_LEVEL
+#define APPL_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef BT_TRACE_APPL
+#define BT_TRACE_APPL BT_USE_TRACES
+#endif
+
+#ifndef NFC_INITIAL_TRACE_LEVEL
+#define NFC_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef GATT_INITIAL_TRACE_LEVEL
+#define GATT_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef SMP_INITIAL_TRACE_LEVEL
+#define SMP_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+// btla-specific --
+
+
+#if (BTTRC_INCLUDED == TRUE)
+/***************************************************************************************/
+/* BTTRC MACROS */
+
+#define BTTRC_EVENT(lid, event, state) \
+ {BTTRC_StackTrace1(lid, BTTRC_TYPE_EVENT, event, BTTRC_PARAM_UINT8, state);}
+#define BTTRC_ACTION(lid, action) \
+ {BTTRC_StackTrace0(lid, BTTRC_TYPE_ACTION, action);}
+#define BTTRC_STATE(lid, state) \
+ {BTTRC_StackTrace1(lid, BTTRC_TYPE_EVENT, BTTRC_TOKEN_SM_STATE, BTTRC_PARAM_UINT8, state);}
+
+#define BTTRC_API0(lid, api) \
+ {BTTRC_StackTrace0(lid, BTTRC_TYPE_API, api);}
+#define BTTRC_API1(lid, api, p1_t,p1_v) \
+ {BTTRC_StackTrace1(lid, BTTRC_TYPE_API, api, p1_t,p1_v);}
+#define BTTRC_API2(lid, api, p1_t,p1_v,p2_t,p2_v) \
+ {BTTRC_StackTrace2(lid, BTTRC_TYPE_API, api, p1_t,p1_v,p2_t,p2_v);}
+#define BTTRC_API3(lid, api, p1_t,p1_v,p2_t,p2_v,p3_t,p3_v) \
+ {BTTRC_StackTrace3(lid, BTTRC_TYPE_API, api, p1_t,p1_v,p2_t,p2_v,p3_t,p3_v);}
+#define BTTRC_API4(lid, api, p1_t,p1_v,p2_t,p2_v,p3_t,p3_v,p4_t,p4_v) \
+ {BTTRC_StackTrace4(lid, BTTRC_TYPE_API, api, p1_t,p1_v,p2_t,p2_v,p3_t,p3_v,p4_t,p4_v);}
+#define BTTRC_API5(lid, api, p1_t,p1_v,p2_t,p2_v,p3_t,p3_v,p4_t,p4_v,p5_t,p5_v) \
+ {BTTRC_StackTrace5(lid, BTTRC_TYPE_API, api, p1_t,p1_v,p2_t,p2_v,p3_t,p3_v,p4_t,p4_v,p5_t,p5_v);}
+#define BTTRC_API6(lid, api, p1_t,p1_v,p2_t,p2_v,p3_t,p3_v,p4_t,p4_v,p5_t,p5_v,p6_t,p6_v) \
+ {BTTRC_StackTrace6(lid, BTTRC_TYPE_API, api, p1_t,p1_v,p2_t,p2_v,p3_t,p3_v,p4_t,p4_v,p5_t,p5_v,p6_t,p6_v);}
+
+
+#define BTTRC_DBG0(lid, dbg) \
+ {BTTRC_StackTrace0(lid, BTTRC_TYPE_DBG, dbg);}
+#define BTTRC_DBG1(lid, dbg, p1_t,p1_v) \
+ {BTTRC_StackTrace1(lid, BTTRC_TYPE_DBG, dbg, p1_t,p1_v);}
+#define BTTRC_DBG2(lid, dbg, p1_t,p1_v,p2_t,p2_v) \
+ {BTTRC_StackTrace2(lid, BTTRC_TYPE_DBG, dbg, p1_t,p1_v,p2_t,p2_v);}
+#define BTTRC_DBG3(lid, dbg, p1_t,p1_v,p2_t,p2_v,p3_t,p3_v) \
+ {BTTRC_StackTrace3(lid, BTTRC_TYPE_DBG, dbg, p1_t,p1_v,p2_t,p2_v,p3_t,p3_v);}
+#define BTTRC_DBG4(lid, dbg, p1_t,p1_v,p2_t,p2_v,p3_t,p3_v,p4_t,p4_v) \
+ {BTTRC_StackTrace4(lid, BTTRC_TYPE_DBG, dbg, p1_t,p1_v,p2_t,p2_v,p3_t,p3_v,p4_t,p4_v);}
+#define BTTRC_DBG5(lid, dbg, p1_t,p1_v,p2_t,p2_v,p3_t,p3_v,p4_t,p4_v,p5_t,p5_v) \
+ {BTTRC_StackTrace5(lid, BTTRC_TYPE_DBG, dbg, p1_t,p1_v,p2_t,p2_v,p3_t,p3_v,p4_t,p4_v,p5_t,p5_v);}
+#define BTTRC_DBG6(lid, dbg, p1_t,p1_v,p2_t,p2_v,p3_t,p3_v,p4_t,p4_v,p5_t,p5_v,p6_t,p6_v) \
+ {BTTRC_StackTrace6(lid, BTTRC_TYPE_DBG, dbg, p1_t,p1_v,p2_t,p2_v,p3_t,p3_v,p4_t,p4_v,p5_t,p5_v,p6_t,p6_v);}
+
+/***************************************************************************************/
+/*AVDT MACROS */
+
+#define BTTRC_AVDT_API0(api) \
+ BTTRC_API0(BTTRC_ID_STK_AVDT, api)
+#define BTTRC_AVDT_API1(api, p1_t, p1_v) \
+ BTTRC_API1(BTTRC_ID_STK_AVDT, api, p1_t, p1_v)
+#define BTTRC_AVDT_API2(api, p1_t, p1_v, p2_t, p2_v) \
+ BTTRC_API2(BTTRC_ID_STK_AVDT, api, p1_t, p1_v, p2_t, p2_v)
+/***************************************************************************************/
+/*AVDT_SCB MACROS */
+
+#define BTTRC_AVDT_SCB_EVENT(event, state) \
+ BTTRC_EVENT(BTTRC_ID_AVDT_SCB, event, state)
+#define BTTRC_AVDT_SCB_ACTION(action) \
+ BTTRC_ACTION(BTTRC_ID_AVDT_SCB, action)
+#define BTTRC_AVDT_SCB_STATE(next_state) \
+ BTTRC_STATE(BTTRC_ID_AVDT_SCB, next_state)
+
+#define BTTRC_AVDT_SCB_DBG0(dbg) \
+ BTTRC_DBG0(BTTRC_ID_AVDT_SCB, dbg)
+#define BTTRC_AVDT_SCB_DBG1(dbg, p1_t,p1_v) \
+ BTTRC_DBG1(BTTRC_ID_AVDT_SCB, dbg, p1_t,p1_v)
+#define BTTRC_AVDT_SCB_DBG2(dbg, p1_t,p1_v,p2_t,p2_v) \
+ BTTRC_DBG2(BTTRC_ID_AVDT_SCB, dbg, p1_t,p1_v,p2_t,p2_v)
+#define BTTRC_AVDT_SCB_DBG3(dbg, p1_t,p1_v,p2_t,p2_v,p3_t,p3_v) \
+ BTTRC_DBG3(BTTRC_ID_AVDT_SCB, dbg, p1_t,p1_v,p2_t,p2_v,p3_t,p3_v)
+#define BTTRC_AVDT_SCB_DBG4(dbg, p1_t,p1_v,p2_t,p2_v,p3_t,p3_v,p4_t,p4_v) \
+ BTTRC_DBG4(BTTRC_ID_AVDT_SCB, dbg, p1_t,p1_v,p2_t,p2_v,p3_t,p3_v,p4_t,p4_v)
+#define BTTRC_AVDT_SCB_DBG5(dbg, p1_t,p1_v,p2_t,p2_v,p3_t,p3_v,p4_t,p4_v,p5_t,p5_v) \
+ BTTRC_DBG5(BTTRC_ID_AVDT_SCB, dbg, p1_t,p1_v,p2_t,p2_v,p3_t,p3_v,p4_t,p4_v,p5_t,p5_v)
+#define BTTRC_AVDT_SCB_DBG6(dbg, p1_t,p1_v,p2_t,p2_v,p3_t,p3_v,p4_t,p4_v,p5_t,p5_v,p6_t,p6_v) \
+ BTTRC_DBG6(BTTRC_ID_AVDT_SCB, dbg, p1_t,p1_v,p2_t,p2_v,p3_t,p3_v,p4_t,p4_v,p5_t,p5_v,p6_t,p6_v)
+/***************************************************************************************/
+/*AVDT_CCB MACROS */
+
+#define BTTRC_AVDT_CCB_EVENT(event, state) \
+ BTTRC_EVENT(BTTRC_ID_AVDT_CCB, event, state)
+#define BTTRC_AVDT_CCB_ACTION(action) \
+ BTTRC_ACTION(BTTRC_ID_AVDT_CCB, action)
+#define BTTRC_AVDT_CCB_STATE(next_state) \
+ BTTRC_STATE(BTTRC_ID_AVDT_CCB, next_state)
+
+#define BTTRC_AVDT_CCB_DBG0(dbg) \
+ BTTRC_DBG0(BTTRC_ID_AVDT_CCB, dbg)
+#define BTTRC_AVDT_CCB_DBG1(dbg, p1_t,p1_v) \
+ BTTRC_DBG1(BTTRC_ID_AVDT_CCB, dbg, p1_t,p1_v)
+#define BTTRC_AVDT_CCB_DBG2(dbg, p1_t,p1_v,p2_t,p2_v) \
+ BTTRC_DBG2(BTTRC_ID_AVDT_CCB, dbg, p1_t,p1_v,p2_t,p2_v)
+#define BTTRC_AVDT_CCB_DBG3(dbg, p1_t,p1_v,p2_t,p2_v,p3_t,p3_v) \
+ BTTRC_DBG3(BTTRC_ID_AVDT_CCB, dbg, p1_t,p1_v,p2_t,p2_v,p3_t,p3_v)
+#define BTTRC_AVDT_CCB_DBG4(dbg, p1_t,p1_v,p2_t,p2_v,p3_t,p3_v,p4_t,p4_v) \
+ BTTRC_DBG4(BTTRC_ID_AVDT_CCB, dbg, p1_t,p1_v,p2_t,p2_v,p3_t,p3_v,p4_t,p4_v)
+#define BTTRC_AVDT_CCB_DBG5(dbg, p1_t,p1_v,p2_t,p2_v,p3_t,p3_v,p4_t,p4_v,p5_t,p5_v) \
+ BTTRC_DBG5(BTTRC_ID_AVDT_CCB, dbg, p1_t,p1_v,p2_t,p2_v,p3_t,p3_v,p4_t,p4_v,p5_t,p5_v)
+#define BTTRC_AVDT_CCB_DBG6(dbg, p1_t,p1_v,p2_t,p2_v,p3_t,p3_v,p4_t,p4_v,p5_t,p5_v,p6_t,p6_v) \
+ BTTRC_DBG6(BTTRC_ID_AVDT_CCB, dbg, p1_t,p1_v,p2_t,p2_v,p3_t,p3_v,p4_t,p4_v,p5_t,p5_v,p6_t,p6_v)
+/***************************************************************************************/
+
+#else /*BTTRC_INCLUDED*/
+
+/***************************************************************************************/
+/* BTTRC MACROS */
+
+#define BTTRC_EVENT(lid, event, state)
+#define BTTRC_ACTION(lid, action)
+#define BTTRC_STATE(lid, state)
+
+#define BTTRC_API0(lid, api)
+#define BTTRC_API1(lid, api, p1_t, p1_v)
+#define BTTRC_API2(lid, api, p1_t, p1_v, p2_t, p2_v)
+#define BTTRC_API3(lid, api, p1_t,p1_v,p2_t,p2_v,p3_t,p3_v)
+#define BTTRC_API4(lid, api, p1_t,p1_v,p2_t,p2_v,p3_t,p3_v,p4_t,p4_v)
+#define BTTRC_API5(lid, api, p1_t,p1_v,p2_t,p2_v,p3_t,p3_v,p4_t,p4_v,p5_t,p5_v)
+#define BTTRC_API6(lid, api, p1_t,p1_v,p2_t,p2_v,p3_t,p3_v,p4_t,p4_v,p5_t,p5_v,p6_t,p6_v)
+
+
+#define BTTRC_DBG0(lid, dbg)
+#define BTTRC_DBG1(lid, dbg, p1_t,p1_v)
+#define BTTRC_DBG2(lid, dbg, p1_t,p1_v,p2_t,p2_v)
+#define BTTRC_DBG3(lid, dbg, p1_t,p1_v,p2_t,p2_v,p3_t,p3_v)
+#define BTTRC_DBG4(lid, dbg, p1_t,p1_v,p2_t,p2_v,p3_t,p3_v,p4_t,p4_v)
+#define BTTRC_DBG5(lid, dbg, p1_t,p1_v,p2_t,p2_v,p3_t,p3_v,p4_t,p4_v,p5_t,p5_v)
+#define BTTRC_DBG6(lid, dbg, p1_t,p1_v,p2_t,p2_v,p3_t,p3_v,p4_t,p4_v,p5_t,p5_v,p6_t,p6_v)
+
+/***************************************************************************************/
+/*AVDT MACROS */
+#define BTTRC_AVDT_API0(api)
+#define BTTRC_AVDT_API1(api, p1_t,p1_v)
+#define BTTRC_AVDT_API2(api, p1_t,p1_v,p2_t,p2_v)
+/***************************************************************************************/
+/*AVDT_SCB MACROS */
+
+#define BTTRC_AVDT_SCB_EVENT(event, state)
+#define BTTRC_AVDT_SCB_ACTION(action)
+#define BTTRC_AVDT_SCB_STATE(next_state)
+
+#define BTTRC_AVDT_SCB_DBG0(dbg)
+#define BTTRC_AVDT_SCB_DBG1(dbg, p1_t,p1_v)
+#define BTTRC_AVDT_SCB_DBG2(dbg, p1_t,p1_v,p2_t,p2_v)
+#define BTTRC_AVDT_SCB_DBG3(dbg, p1_t,p1_v,p2_t,p2_v,p3_t,p3_v)
+#define BTTRC_AVDT_SCB_DBG4(dbg, p1_t,p1_v,p2_t,p2_v,p3_t,p3_v,p4_t,p4_v)
+#define BTTRC_AVDT_SCB_DBG5(dbg, p1_t,p1_v,p2_t,p2_v,p3_t,p3_v,p4_t,p4_v,p5_t,p5_v)
+#define BTTRC_AVDT_SCB_DBG6(dbg, p1_t,p1_v,p2_t,p2_v,p3_t,p3_v,p4_t,p4_v,p5_t,p5_v,p6_t,p6_v)
+
+/***************************************************************************************/
+/*AVDT_CCB MACROS */
+
+#define BTTRC_AVDT_CCB_EVENT(event, state)
+#define BTTRC_AVDT_CCB_ACTION(action)
+#define BTTRC_AVDT_CCB_STATE(next_state)
+
+#define BTTRC_AVDT_CCB_DBG0(dbg)
+#define BTTRC_AVDT_CCB_DBG1(dbg, p1_t,p1_v)
+#define BTTRC_AVDT_CCB_DBG2(dbg, p1_t,p1_v,p2_t,p2_v)
+#define BTTRC_AVDT_CCB_DBG3(dbg, p1_t,p1_v,p2_t,p2_v,p3_t,p3_v)
+#define BTTRC_AVDT_CCB_DBG4(dbg, p1_t,p1_v,p2_t,p2_v,p3_t,p3_v,p4_t,p4_v)
+#define BTTRC_AVDT_CCB_DBG5(dbg, p1_t,p1_v,p2_t,p2_v,p3_t,p3_v,p4_t,p4_v,p5_t,p5_v)
+#define BTTRC_AVDT_CCB_DBG6(dbg, p1_t,p1_v,p2_t,p2_v,p3_t,p3_v,p4_t,p4_v,p5_t,p5_v,p6_t,p6_v)
+
+/***************************************************************************************/
+
+#endif /*BTTRC_INCLUDED*/
+
+
+#if (BT_USE_TRACES == TRUE)
+
+#define BT_TRACE_0(l,t,m) LogMsg_0((TRACE_CTRL_GENERAL | (l) | TRACE_ORG_STACK | (t)),(m))
+#define BT_TRACE_1(l,t,m,p1) LogMsg_1(TRACE_CTRL_GENERAL | (l) | TRACE_ORG_STACK | (t),(m),(UINT32)(p1))
+#define BT_TRACE_2(l,t,m,p1,p2) LogMsg_2(TRACE_CTRL_GENERAL | (l) | TRACE_ORG_STACK | (t),(m),(UINT32)(p1), \
+ (UINT32)(p2))
+#define BT_TRACE_3(l,t,m,p1,p2,p3) LogMsg_3(TRACE_CTRL_GENERAL | (l) | TRACE_ORG_STACK | (t),(m),(UINT32)(p1), \
+ (UINT32)(p2),(UINT32)(p3))
+#define BT_TRACE_4(l,t,m,p1,p2,p3,p4) LogMsg_4(TRACE_CTRL_GENERAL | (l) | TRACE_ORG_STACK | (t),(m),(UINT32)(p1), \
+ (UINT32)(p2),(UINT32)(p3),(UINT32)(p4))
+#define BT_TRACE_5(l,t,m,p1,p2,p3,p4,p5) LogMsg_5(TRACE_CTRL_GENERAL | (l) | TRACE_ORG_STACK | (t),(m),(UINT32)(p1), \
+ (UINT32)(p2),(UINT32)(p3),(UINT32)(p4), \
+ (UINT32)(p5))
+#define BT_TRACE_6(l,t,m,p1,p2,p3,p4,p5,p6) LogMsg_6(TRACE_CTRL_GENERAL | (l) | TRACE_ORG_STACK | (t),(m),(UINT32)(p1), \
+ (UINT32)(p2),(UINT32)(p3),(UINT32)(p4), \
+ (UINT32)(p5),(UINT32)(p6))
+
+#define BT_ERROR_TRACE_0(l,m) LogMsg_0(TRACE_CTRL_GENERAL | (l) | TRACE_ORG_STACK | TRACE_TYPE_ERROR,(m))
+#define BT_ERROR_TRACE_1(l,m,p1) LogMsg_1(TRACE_CTRL_GENERAL | (l) | TRACE_ORG_STACK | TRACE_TYPE_ERROR,(m),(UINT32)(p1))
+#define BT_ERROR_TRACE_2(l,m,p1,p2) LogMsg_2(TRACE_CTRL_GENERAL | (l) | TRACE_ORG_STACK | TRACE_TYPE_ERROR,(m),(UINT32)(p1),(UINT32)(p2))
+#define BT_ERROR_TRACE_3(l,m,p1,p2,p3) LogMsg_3(TRACE_CTRL_GENERAL | (l) | TRACE_ORG_STACK | TRACE_TYPE_ERROR,(m),(UINT32)(p1),(UINT32)(p2),(UINT32)(p3))
+
+/* Define tracing for the HCI unit
+*/
+#define HCI_TRACE_ERROR0(m) {if (btu_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_0(TRACE_LAYER_HCI, TRACE_TYPE_ERROR, m);}
+#define HCI_TRACE_ERROR1(m,p1) {if (btu_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_1(TRACE_LAYER_HCI, TRACE_TYPE_ERROR, m,p1);}
+#define HCI_TRACE_ERROR2(m,p1,p2) {if (btu_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_2(TRACE_LAYER_HCI, TRACE_TYPE_ERROR, m,p1,p2);}
+#define HCI_TRACE_ERROR3(m,p1,p2,p3) {if (btu_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_3(TRACE_LAYER_HCI, TRACE_TYPE_ERROR, m,p1,p2,p3);}
+#define HCI_TRACE_ERROR4(m,p1,p2,p3,p4) {if (btu_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_4(TRACE_LAYER_HCI, TRACE_TYPE_ERROR, m,p1,p2,p3,p4);}
+#define HCI_TRACE_ERROR5(m,p1,p2,p3,p4,p5) {if (btu_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_5(TRACE_LAYER_HCI, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5);}
+#define HCI_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6) {if (btu_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_6(TRACE_LAYER_HCI, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5,p6);}
+
+#define HCI_TRACE_WARNING0(m) {if (btu_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_0(TRACE_LAYER_HCI, TRACE_TYPE_WARNING, m);}
+#define HCI_TRACE_WARNING1(m,p1) {if (btu_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_1(TRACE_LAYER_HCI, TRACE_TYPE_WARNING, m,p1);}
+#define HCI_TRACE_WARNING2(m,p1,p2) {if (btu_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_2(TRACE_LAYER_HCI, TRACE_TYPE_WARNING, m,p1,p2);}
+#define HCI_TRACE_WARNING3(m,p1,p2,p3) {if (btu_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_3(TRACE_LAYER_HCI, TRACE_TYPE_WARNING, m,p1,p2,p3);}
+#define HCI_TRACE_WARNING4(m,p1,p2,p3,p4) {if (btu_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_4(TRACE_LAYER_HCI, TRACE_TYPE_WARNING, m,p1,p2,p3,p4);}
+#define HCI_TRACE_WARNING5(m,p1,p2,p3,p4,p5) {if (btu_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_5(TRACE_LAYER_HCI, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5);}
+#define HCI_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6) {if (btu_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_6(TRACE_LAYER_HCI, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5,p6);}
+
+#define HCI_TRACE_EVENT0(m) {if (btu_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_0(TRACE_LAYER_HCI, TRACE_TYPE_EVENT, m);}
+#define HCI_TRACE_EVENT1(m,p1) {if (btu_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_1(TRACE_LAYER_HCI, TRACE_TYPE_EVENT, m, p1);}
+#define HCI_TRACE_EVENT2(m,p1,p2) {if (btu_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_2(TRACE_LAYER_HCI, TRACE_TYPE_EVENT, m,p1,p2);}
+#define HCI_TRACE_EVENT3(m,p1,p2,p3) {if (btu_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_3(TRACE_LAYER_HCI, TRACE_TYPE_EVENT, m,p1,p2,p3);}
+#define HCI_TRACE_EVENT4(m,p1,p2,p3,p4) {if (btu_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_4(TRACE_LAYER_HCI, TRACE_TYPE_EVENT, m,p1,p2,p3,p4);}
+#define HCI_TRACE_EVENT5(m,p1,p2,p3,p4,p5) {if (btu_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_5(TRACE_LAYER_HCI, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5);}
+#define HCI_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6) {if (btu_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_6(TRACE_LAYER_HCI, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5,p6);}
+
+#define HCI_TRACE_DEBUG0(m) {if (btu_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_0(TRACE_LAYER_HCI, TRACE_TYPE_DEBUG, m);}
+#define HCI_TRACE_DEBUG1(m,p1) {if (btu_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_1(TRACE_LAYER_HCI, TRACE_TYPE_DEBUG, m,p1);}
+#define HCI_TRACE_DEBUG2(m,p1,p2) {if (btu_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_2(TRACE_LAYER_HCI, TRACE_TYPE_DEBUG, m,p1,p2);}
+#define HCI_TRACE_DEBUG3(m,p1,p2,p3) {if (btu_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_3(TRACE_LAYER_HCI, TRACE_TYPE_DEBUG, m,p1,p2,p3);}
+#define HCI_TRACE_DEBUG4(m,p1,p2,p3,p4) {if (btu_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_4(TRACE_LAYER_HCI, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4);}
+#define HCI_TRACE_DEBUG5(m,p1,p2,p3,p4,p5) {if (btu_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_5(TRACE_LAYER_HCI, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5);}
+#define HCI_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) {if (btu_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_6(TRACE_LAYER_HCI, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5,p6);}
+
+
+/* Define tracing for BTM
+*/
+#define BTM_TRACE_ERROR0(m) {if (btm_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_0(TRACE_LAYER_BTM, TRACE_TYPE_ERROR, m);}
+#define BTM_TRACE_ERROR1(m,p1) {if (btm_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_1(TRACE_LAYER_BTM, TRACE_TYPE_ERROR, m,p1);}
+#define BTM_TRACE_ERROR2(m,p1,p2) {if (btm_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_2(TRACE_LAYER_BTM, TRACE_TYPE_ERROR, m,p1,p2);}
+#define BTM_TRACE_ERROR3(m,p1,p2,p3) {if (btm_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_3(TRACE_LAYER_BTM, TRACE_TYPE_ERROR, m,p1,p2,p3);}
+#define BTM_TRACE_ERROR4(m,p1,p2,p3,p4) {if (btm_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_4(TRACE_LAYER_BTM, TRACE_TYPE_ERROR, m,p1,p2,p3,p4);}
+#define BTM_TRACE_ERROR5(m,p1,p2,p3,p4,p5) {if (btm_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_5(TRACE_LAYER_BTM, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5);}
+#define BTM_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6) {if (btm_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_6(TRACE_LAYER_BTM, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5,p6);}
+
+#define BTM_TRACE_WARNING0(m) {if (btm_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_0(TRACE_LAYER_BTM, TRACE_TYPE_WARNING, m);}
+#define BTM_TRACE_WARNING1(m,p1) {if (btm_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_1(TRACE_LAYER_BTM, TRACE_TYPE_WARNING, m,p1);}
+#define BTM_TRACE_WARNING2(m,p1,p2) {if (btm_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_2(TRACE_LAYER_BTM, TRACE_TYPE_WARNING, m,p1,p2);}
+#define BTM_TRACE_WARNING3(m,p1,p2,p3) {if (btm_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_3(TRACE_LAYER_BTM, TRACE_TYPE_WARNING, m,p1,p2,p3);}
+#define BTM_TRACE_WARNING4(m,p1,p2,p3,p4) {if (btm_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_4(TRACE_LAYER_BTM, TRACE_TYPE_WARNING, m,p1,p2,p3,p4);}
+#define BTM_TRACE_WARNING5(m,p1,p2,p3,p4,p5) {if (btm_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_5(TRACE_LAYER_BTM, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5);}
+#define BTM_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6) {if (btm_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_6(TRACE_LAYER_BTM, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5,p6);}
+
+#define BTM_TRACE_API0(m) {if (btm_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_0(TRACE_LAYER_BTM, TRACE_TYPE_API, m);}
+#define BTM_TRACE_API1(m,p1) {if (btm_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_1(TRACE_LAYER_BTM, TRACE_TYPE_API, m, p1);}
+#define BTM_TRACE_API2(m,p1,p2) {if (btm_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_2(TRACE_LAYER_BTM, TRACE_TYPE_API, m,p1,p2);}
+#define BTM_TRACE_API3(m,p1,p2,p3) {if (btm_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_3(TRACE_LAYER_BTM, TRACE_TYPE_API, m,p1,p2,p3);}
+#define BTM_TRACE_API4(m,p1,p2,p3,p4) {if (btm_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_4(TRACE_LAYER_BTM, TRACE_TYPE_API, m,p1,p2,p3,p4);}
+#define BTM_TRACE_API5(m,p1,p2,p3,p4,p5) {if (btm_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_5(TRACE_LAYER_BTM, TRACE_TYPE_API, m,p1,p2,p3,p4,p5);}
+#define BTM_TRACE_API6(m,p1,p2,p3,p4,p5,p6) {if (btm_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_6(TRACE_LAYER_BTM, TRACE_TYPE_API, m,p1,p2,p3,p4,p5,p6);}
+
+#define BTM_TRACE_EVENT0(m) {if (btm_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_0(TRACE_LAYER_BTM, TRACE_TYPE_EVENT, m);}
+#define BTM_TRACE_EVENT1(m,p1) {if (btm_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_1(TRACE_LAYER_BTM, TRACE_TYPE_EVENT, m, p1);}
+#define BTM_TRACE_EVENT2(m,p1,p2) {if (btm_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_2(TRACE_LAYER_BTM, TRACE_TYPE_EVENT, m,p1,p2);}
+#define BTM_TRACE_EVENT3(m,p1,p2,p3) {if (btm_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_3(TRACE_LAYER_BTM, TRACE_TYPE_EVENT, m,p1,p2,p3);}
+#define BTM_TRACE_EVENT4(m,p1,p2,p3,p4) {if (btm_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_4(TRACE_LAYER_BTM, TRACE_TYPE_EVENT, m,p1,p2,p3,p4);}
+#define BTM_TRACE_EVENT5(m,p1,p2,p3,p4,p5) {if (btm_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_5(TRACE_LAYER_BTM, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5);}
+#define BTM_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6) {if (btm_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_6(TRACE_LAYER_BTM, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5,p6);}
+
+#define BTM_TRACE_DEBUG0(m) {if (btm_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_0(TRACE_LAYER_BTM, TRACE_TYPE_DEBUG, m);}
+#define BTM_TRACE_DEBUG1(m,p1) {if (btm_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_1(TRACE_LAYER_BTM, TRACE_TYPE_DEBUG, m,p1);}
+#define BTM_TRACE_DEBUG2(m,p1,p2) {if (btm_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_2(TRACE_LAYER_BTM, TRACE_TYPE_DEBUG, m,p1,p2);}
+#define BTM_TRACE_DEBUG3(m,p1,p2,p3) {if (btm_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_3(TRACE_LAYER_BTM, TRACE_TYPE_DEBUG, m,p1,p2,p3);}
+#define BTM_TRACE_DEBUG4(m,p1,p2,p3,p4) {if (btm_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_4(TRACE_LAYER_BTM, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4);}
+#define BTM_TRACE_DEBUG5(m,p1,p2,p3,p4,p5) {if (btm_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_5(TRACE_LAYER_BTM, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5);}
+#define BTM_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) {if (btm_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_6(TRACE_LAYER_BTM, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5,p6);}
+
+
+/* Define tracing for the L2CAP unit
+*/
+#define L2CAP_TRACE_ERROR0(m) {if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_0(TRACE_LAYER_L2CAP, TRACE_TYPE_ERROR, m);}
+#define L2CAP_TRACE_ERROR1(m,p1) {if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_1(TRACE_LAYER_L2CAP, TRACE_TYPE_ERROR, m,p1);}
+#define L2CAP_TRACE_ERROR2(m,p1,p2) {if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_2(TRACE_LAYER_L2CAP, TRACE_TYPE_ERROR, m,p1,p2);}
+#define L2CAP_TRACE_ERROR3(m,p1,p2,p3) {if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_3(TRACE_LAYER_L2CAP, TRACE_TYPE_ERROR, m,p1,p2,p3);}
+#define L2CAP_TRACE_ERROR4(m,p1,p2,p3,p4) {if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_4(TRACE_LAYER_L2CAP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4);}
+#define L2CAP_TRACE_ERROR5(m,p1,p2,p3,p4,p5) {if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_5(TRACE_LAYER_L2CAP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5);}
+#define L2CAP_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6) {if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_6(TRACE_LAYER_L2CAP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5,p6);}
+
+#define L2CAP_TRACE_WARNING0(m) {if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_0(TRACE_LAYER_L2CAP, TRACE_TYPE_WARNING, m);}
+#define L2CAP_TRACE_WARNING1(m,p1) {if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_1(TRACE_LAYER_L2CAP, TRACE_TYPE_WARNING, m,p1);}
+#define L2CAP_TRACE_WARNING2(m,p1,p2) {if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_2(TRACE_LAYER_L2CAP, TRACE_TYPE_WARNING, m,p1,p2);}
+#define L2CAP_TRACE_WARNING3(m,p1,p2,p3) {if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_3(TRACE_LAYER_L2CAP, TRACE_TYPE_WARNING, m,p1,p2,p3);}
+#define L2CAP_TRACE_WARNING4(m,p1,p2,p3,p4) {if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_4(TRACE_LAYER_L2CAP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4);}
+#define L2CAP_TRACE_WARNING5(m,p1,p2,p3,p4,p5) {if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_5(TRACE_LAYER_L2CAP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5);}
+#define L2CAP_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6) {if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_6(TRACE_LAYER_L2CAP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5,p6);}
+
+#define L2CAP_TRACE_API0(m) {if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_0(TRACE_LAYER_L2CAP, TRACE_TYPE_API, m);}
+#define L2CAP_TRACE_API1(m,p1) {if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_1(TRACE_LAYER_L2CAP, TRACE_TYPE_API, m,p1);}
+#define L2CAP_TRACE_API2(m,p1,p2) {if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_2(TRACE_LAYER_L2CAP, TRACE_TYPE_API, m,p1,p2);}
+#define L2CAP_TRACE_API3(m,p1,p2,p3) {if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_3(TRACE_LAYER_L2CAP, TRACE_TYPE_API, m,p1,p2,p3);}
+#define L2CAP_TRACE_API4(m,p1,p2,p3,p4) {if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_4(TRACE_LAYER_L2CAP, TRACE_TYPE_API, m,p1,p2,p3,p4);}
+#define L2CAP_TRACE_API5(m,p1,p2,p3,p4,p5) {if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_5(TRACE_LAYER_L2CAP, TRACE_TYPE_API, m,p1,p2,p3,p4,p5);}
+#define L2CAP_TRACE_API6(m,p1,p2,p3,p4,p5,p6) {if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_6(TRACE_LAYER_L2CAP, TRACE_TYPE_API, m,p1,p2,p3,p4,p5,p6);}
+
+#define L2CAP_TRACE_EVENT0(m) {if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_0(TRACE_LAYER_L2CAP, TRACE_TYPE_EVENT, m);}
+#define L2CAP_TRACE_EVENT1(m,p1) {if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_1(TRACE_LAYER_L2CAP, TRACE_TYPE_EVENT, m, p1);}
+#define L2CAP_TRACE_EVENT2(m,p1,p2) {if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_2(TRACE_LAYER_L2CAP, TRACE_TYPE_EVENT, m,p1,p2);}
+#define L2CAP_TRACE_EVENT3(m,p1,p2,p3) {if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_3(TRACE_LAYER_L2CAP, TRACE_TYPE_EVENT, m,p1,p2,p3);}
+#define L2CAP_TRACE_EVENT4(m,p1,p2,p3,p4) {if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_4(TRACE_LAYER_L2CAP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4);}
+#define L2CAP_TRACE_EVENT5(m,p1,p2,p3,p4,p5) {if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_5(TRACE_LAYER_L2CAP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5);}
+#define L2CAP_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6) {if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_6(TRACE_LAYER_L2CAP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5,p6);}
+
+#define L2CAP_TRACE_DEBUG0(m) {if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_0(TRACE_LAYER_L2CAP, TRACE_TYPE_DEBUG, m);}
+#define L2CAP_TRACE_DEBUG1(m,p1) {if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_1(TRACE_LAYER_L2CAP, TRACE_TYPE_DEBUG, m,p1);}
+#define L2CAP_TRACE_DEBUG2(m,p1,p2) {if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_2(TRACE_LAYER_L2CAP, TRACE_TYPE_DEBUG, m,p1,p2);}
+#define L2CAP_TRACE_DEBUG3(m,p1,p2,p3) {if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_3(TRACE_LAYER_L2CAP, TRACE_TYPE_DEBUG, m,p1,p2,p3);}
+#define L2CAP_TRACE_DEBUG4(m,p1,p2,p3,p4) {if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_4(TRACE_LAYER_L2CAP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4);}
+#define L2CAP_TRACE_DEBUG5(m,p1,p2,p3,p4,p5) {if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_5(TRACE_LAYER_L2CAP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5);}
+#define L2CAP_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) {if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_6(TRACE_LAYER_L2CAP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5,p6);}
+
+/* Define tracing for the LLCP unit
+*/
+#define LLCP_TRACE_ERROR0(m) {if (llcp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_0(TRACE_LAYER_LLCP, TRACE_TYPE_ERROR, m);}
+#define LLCP_TRACE_ERROR1(m,p1) {if (llcp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_1(TRACE_LAYER_LLCP, TRACE_TYPE_ERROR, m,p1);}
+#define LLCP_TRACE_ERROR2(m,p1,p2) {if (llcp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_2(TRACE_LAYER_LLCP, TRACE_TYPE_ERROR, m,p1,p2);}
+#define LLCP_TRACE_ERROR3(m,p1,p2,p3) {if (llcp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_3(TRACE_LAYER_LLCP, TRACE_TYPE_ERROR, m,p1,p2,p3);}
+#define LLCP_TRACE_ERROR4(m,p1,p2,p3,p4) {if (llcp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_4(TRACE_LAYER_LLCP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4);}
+#define LLCP_TRACE_ERROR5(m,p1,p2,p3,p4,p5) {if (llcp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_5(TRACE_LAYER_LLCP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5);}
+#define LLCP_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6) {if (llcp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_6(TRACE_LAYER_LLCP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5,p6);}
+
+#define LLCP_TRACE_WARNING0(m) {if (llcp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_0(TRACE_LAYER_LLCP, TRACE_TYPE_WARNING, m);}
+#define LLCP_TRACE_WARNING1(m,p1) {if (llcp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_1(TRACE_LAYER_LLCP, TRACE_TYPE_WARNING, m,p1);}
+#define LLCP_TRACE_WARNING2(m,p1,p2) {if (llcp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_2(TRACE_LAYER_LLCP, TRACE_TYPE_WARNING, m,p1,p2);}
+#define LLCP_TRACE_WARNING3(m,p1,p2,p3) {if (llcp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_3(TRACE_LAYER_LLCP, TRACE_TYPE_WARNING, m,p1,p2,p3);}
+#define LLCP_TRACE_WARNING4(m,p1,p2,p3,p4) {if (llcp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_4(TRACE_LAYER_LLCP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4);}
+#define LLCP_TRACE_WARNING5(m,p1,p2,p3,p4,p5) {if (llcp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_5(TRACE_LAYER_LLCP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5);}
+#define LLCP_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6) {if (llcp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_6(TRACE_LAYER_LLCP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5,p6);}
+
+#define LLCP_TRACE_API0(m) {if (llcp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_0(TRACE_LAYER_LLCP, TRACE_TYPE_API, m);}
+#define LLCP_TRACE_API1(m,p1) {if (llcp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_1(TRACE_LAYER_LLCP, TRACE_TYPE_API, m,p1);}
+#define LLCP_TRACE_API2(m,p1,p2) {if (llcp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_2(TRACE_LAYER_LLCP, TRACE_TYPE_API, m,p1,p2);}
+#define LLCP_TRACE_API3(m,p1,p2,p3) {if (llcp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_3(TRACE_LAYER_LLCP, TRACE_TYPE_API, m,p1,p2,p3);}
+#define LLCP_TRACE_API4(m,p1,p2,p3,p4) {if (llcp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_4(TRACE_LAYER_LLCP, TRACE_TYPE_API, m,p1,p2,p3,p4);}
+#define LLCP_TRACE_API5(m,p1,p2,p3,p4,p5) {if (llcp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_5(TRACE_LAYER_LLCP, TRACE_TYPE_API, m,p1,p2,p3,p4,p5);}
+#define LLCP_TRACE_API6(m,p1,p2,p3,p4,p5,p6) {if (llcp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_6(TRACE_LAYER_LLCP, TRACE_TYPE_API, m,p1,p2,p3,p4,p5,p6);}
+
+#define LLCP_TRACE_EVENT0(m) {if (llcp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_0(TRACE_LAYER_LLCP, TRACE_TYPE_EVENT, m);}
+#define LLCP_TRACE_EVENT1(m,p1) {if (llcp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_1(TRACE_LAYER_LLCP, TRACE_TYPE_EVENT, m, p1);}
+#define LLCP_TRACE_EVENT2(m,p1,p2) {if (llcp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_2(TRACE_LAYER_LLCP, TRACE_TYPE_EVENT, m,p1,p2);}
+#define LLCP_TRACE_EVENT3(m,p1,p2,p3) {if (llcp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_3(TRACE_LAYER_LLCP, TRACE_TYPE_EVENT, m,p1,p2,p3);}
+#define LLCP_TRACE_EVENT4(m,p1,p2,p3,p4) {if (llcp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_4(TRACE_LAYER_LLCP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4);}
+#define LLCP_TRACE_EVENT5(m,p1,p2,p3,p4,p5) {if (llcp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_5(TRACE_LAYER_LLCP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5);}
+#define LLCP_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6) {if (llcp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_6(TRACE_LAYER_LLCP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5,p6);}
+
+#define LLCP_TRACE_DEBUG0(m) {if (llcp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_0(TRACE_LAYER_LLCP, TRACE_TYPE_DEBUG, m);}
+#define LLCP_TRACE_DEBUG1(m,p1) {if (llcp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_1(TRACE_LAYER_LLCP, TRACE_TYPE_DEBUG, m,p1);}
+#define LLCP_TRACE_DEBUG2(m,p1,p2) {if (llcp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_2(TRACE_LAYER_LLCP, TRACE_TYPE_DEBUG, m,p1,p2);}
+#define LLCP_TRACE_DEBUG3(m,p1,p2,p3) {if (llcp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_3(TRACE_LAYER_LLCP, TRACE_TYPE_DEBUG, m,p1,p2,p3);}
+#define LLCP_TRACE_DEBUG4(m,p1,p2,p3,p4) {if (llcp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_4(TRACE_LAYER_LLCP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4);}
+#define LLCP_TRACE_DEBUG5(m,p1,p2,p3,p4,p5) {if (llcp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_5(TRACE_LAYER_LLCP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5);}
+#define LLCP_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) {if (llcp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_6(TRACE_LAYER_LLCP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5,p6);}
+
+/* Define tracing for the SDP unit
+*/
+#define SDP_TRACE_ERROR0(m) {if (sdp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_0(TRACE_LAYER_SDP, TRACE_TYPE_ERROR, m);}
+#define SDP_TRACE_ERROR1(m,p1) {if (sdp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_1(TRACE_LAYER_SDP, TRACE_TYPE_ERROR, m,p1);}
+#define SDP_TRACE_ERROR2(m,p1,p2) {if (sdp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_2(TRACE_LAYER_SDP, TRACE_TYPE_ERROR, m,p1,p2);}
+#define SDP_TRACE_ERROR3(m,p1,p2,p3) {if (sdp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_3(TRACE_LAYER_SDP, TRACE_TYPE_ERROR, m,p1,p2,p3);}
+#define SDP_TRACE_ERROR4(m,p1,p2,p3,p4) {if (sdp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_4(TRACE_LAYER_SDP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4);}
+#define SDP_TRACE_ERROR5(m,p1,p2,p3,p4,p5) {if (sdp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_5(TRACE_LAYER_SDP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5);}
+#define SDP_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6) {if (sdp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_6(TRACE_LAYER_SDP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5,p6);}
+
+#define SDP_TRACE_WARNING0(m) {if (sdp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_0(TRACE_LAYER_SDP, TRACE_TYPE_WARNING, m);}
+#define SDP_TRACE_WARNING1(m,p1) {if (sdp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_1(TRACE_LAYER_SDP, TRACE_TYPE_WARNING, m,p1);}
+#define SDP_TRACE_WARNING2(m,p1,p2) {if (sdp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_2(TRACE_LAYER_SDP, TRACE_TYPE_WARNING, m,p1,p2);}
+#define SDP_TRACE_WARNING3(m,p1,p2,p3) {if (sdp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_3(TRACE_LAYER_SDP, TRACE_TYPE_WARNING, m,p1,p2,p3);}
+#define SDP_TRACE_WARNING4(m,p1,p2,p3,p4) {if (sdp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_4(TRACE_LAYER_SDP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4);}
+#define SDP_TRACE_WARNING5(m,p1,p2,p3,p4,p5) {if (sdp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_5(TRACE_LAYER_SDP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5);}
+#define SDP_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6) {if (sdp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_6(TRACE_LAYER_SDP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5,p6);}
+
+#define SDP_TRACE_API0(m) {if (sdp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_0(TRACE_LAYER_SDP, TRACE_TYPE_API, m);}
+#define SDP_TRACE_API1(m,p1) {if (sdp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_1(TRACE_LAYER_SDP, TRACE_TYPE_API, m,p1);}
+#define SDP_TRACE_API2(m,p1,p2) {if (sdp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_2(TRACE_LAYER_SDP, TRACE_TYPE_API, m,p1,p2);}
+#define SDP_TRACE_API3(m,p1,p2,p3) {if (sdp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_3(TRACE_LAYER_SDP, TRACE_TYPE_API, m,p1,p2,p3);}
+#define SDP_TRACE_API4(m,p1,p2,p3,p4) {if (sdp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_4(TRACE_LAYER_SDP, TRACE_TYPE_API, m,p1,p2,p3,p4);}
+#define SDP_TRACE_API5(m,p1,p2,p3,p4,p5) {if (sdp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_5(TRACE_LAYER_SDP, TRACE_TYPE_API, m,p1,p2,p3,p4,p5);}
+#define SDP_TRACE_API6(m,p1,p2,p3,p4,p5,p6) {if (sdp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_6(TRACE_LAYER_SDP, TRACE_TYPE_API, m,p1,p2,p3,p4,p5,p6);}
+
+#define SDP_TRACE_EVENT0(m) {if (sdp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_0(TRACE_LAYER_SDP, TRACE_TYPE_EVENT, m);}
+#define SDP_TRACE_EVENT1(m,p1) {if (sdp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_1(TRACE_LAYER_SDP, TRACE_TYPE_EVENT, m, p1);}
+#define SDP_TRACE_EVENT2(m,p1,p2) {if (sdp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_2(TRACE_LAYER_SDP, TRACE_TYPE_EVENT, m,p1,p2);}
+#define SDP_TRACE_EVENT3(m,p1,p2,p3) {if (sdp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_3(TRACE_LAYER_SDP, TRACE_TYPE_EVENT, m,p1,p2,p3);}
+#define SDP_TRACE_EVENT4(m,p1,p2,p3,p4) {if (sdp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_4(TRACE_LAYER_SDP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4);}
+#define SDP_TRACE_EVENT5(m,p1,p2,p3,p4,p5) {if (sdp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_5(TRACE_LAYER_SDP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5);}
+#define SDP_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6) {if (sdp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_6(TRACE_LAYER_SDP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5,p6);}
+
+#define SDP_TRACE_DEBUG0(m) {if (sdp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_0(TRACE_LAYER_SDP, TRACE_TYPE_DEBUG, m);}
+#define SDP_TRACE_DEBUG1(m,p1) {if (sdp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_1(TRACE_LAYER_SDP, TRACE_TYPE_DEBUG, m,p1);}
+#define SDP_TRACE_DEBUG2(m,p1,p2) {if (sdp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_2(TRACE_LAYER_SDP, TRACE_TYPE_DEBUG, m,p1,p2);}
+#define SDP_TRACE_DEBUG3(m,p1,p2,p3) {if (sdp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_3(TRACE_LAYER_SDP, TRACE_TYPE_DEBUG, m,p1,p2,p3);}
+#define SDP_TRACE_DEBUG4(m,p1,p2,p3,p4) {if (sdp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_4(TRACE_LAYER_SDP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4);}
+#define SDP_TRACE_DEBUG5(m,p1,p2,p3,p4,p5) {if (sdp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_5(TRACE_LAYER_SDP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5);}
+#define SDP_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) {if (sdp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_6(TRACE_LAYER_SDP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5,p6);}
+
+/* Define tracing for the RFCOMM unit
+*/
+#define RFCOMM_TRACE_ERROR0(m) {if (rfc_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_0(TRACE_LAYER_RFCOMM, TRACE_TYPE_ERROR, m);}
+#define RFCOMM_TRACE_ERROR1(m,p1) {if (rfc_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_1(TRACE_LAYER_RFCOMM, TRACE_TYPE_ERROR, m,p1);}
+#define RFCOMM_TRACE_ERROR2(m,p1,p2) {if (rfc_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_2(TRACE_LAYER_RFCOMM, TRACE_TYPE_ERROR, m,p1,p2);}
+#define RFCOMM_TRACE_ERROR3(m,p1,p2,p3) {if (rfc_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_3(TRACE_LAYER_RFCOMM, TRACE_TYPE_ERROR, m,p1,p2,p3);}
+#define RFCOMM_TRACE_ERROR4(m,p1,p2,p3,p4) {if (rfc_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_4(TRACE_LAYER_RFCOMM, TRACE_TYPE_ERROR, m,p1,p2,p3,p4);}
+#define RFCOMM_TRACE_ERROR5(m,p1,p2,p3,p4,p5) {if (rfc_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_5(TRACE_LAYER_RFCOMM, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5);}
+#define RFCOMM_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6) {if (rfc_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_6(TRACE_LAYER_RFCOMM, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5,p6);}
+
+#define RFCOMM_TRACE_WARNING0(m) {if (rfc_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_0(TRACE_LAYER_RFCOMM, TRACE_TYPE_WARNING, m);}
+#define RFCOMM_TRACE_WARNING1(m,p1) {if (rfc_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_1(TRACE_LAYER_RFCOMM, TRACE_TYPE_WARNING, m,p1);}
+#define RFCOMM_TRACE_WARNING2(m,p1,p2) {if (rfc_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_2(TRACE_LAYER_RFCOMM, TRACE_TYPE_WARNING, m,p1,p2);}
+#define RFCOMM_TRACE_WARNING3(m,p1,p2,p3) {if (rfc_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_3(TRACE_LAYER_RFCOMM, TRACE_TYPE_WARNING, m,p1,p2,p3);}
+#define RFCOMM_TRACE_WARNING4(m,p1,p2,p3,p4) {if (rfc_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_4(TRACE_LAYER_RFCOMM, TRACE_TYPE_WARNING, m,p1,p2,p3,p4);}
+#define RFCOMM_TRACE_WARNING5(m,p1,p2,p3,p4,p5) {if (rfc_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_5(TRACE_LAYER_RFCOMM, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5);}
+#define RFCOMM_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6) {if (rfc_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_6(TRACE_LAYER_RFCOMM, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5,p6);}
+
+#define RFCOMM_TRACE_API0(m) {if (rfc_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_0(TRACE_LAYER_RFCOMM, TRACE_TYPE_API, m);}
+#define RFCOMM_TRACE_API1(m,p1) {if (rfc_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_1(TRACE_LAYER_RFCOMM, TRACE_TYPE_API, m,p1);}
+#define RFCOMM_TRACE_API2(m,p1,p2) {if (rfc_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_2(TRACE_LAYER_RFCOMM, TRACE_TYPE_API, m,p1,p2);}
+#define RFCOMM_TRACE_API3(m,p1,p2,p3) {if (rfc_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_3(TRACE_LAYER_RFCOMM, TRACE_TYPE_API, m,p1,p2,p3);}
+#define RFCOMM_TRACE_API4(m,p1,p2,p3,p4) {if (rfc_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_4(TRACE_LAYER_RFCOMM, TRACE_TYPE_API, m,p1,p2,p3,p4);}
+#define RFCOMM_TRACE_API5(m,p1,p2,p3,p4,p5) {if (rfc_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_5(TRACE_LAYER_RFCOMM, TRACE_TYPE_API, m,p1,p2,p3,p4,p5);}
+#define RFCOMM_TRACE_API6(m,p1,p2,p3,p4,p5,p6) {if (rfc_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_6(TRACE_LAYER_RFCOMM, TRACE_TYPE_API, m,p1,p2,p3,p4,p5,p6);}
+
+#define RFCOMM_TRACE_EVENT0(m) {if (rfc_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_0(TRACE_LAYER_RFCOMM, TRACE_TYPE_EVENT, m);}
+#define RFCOMM_TRACE_EVENT1(m,p1) {if (rfc_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_1(TRACE_LAYER_RFCOMM, TRACE_TYPE_EVENT, m, p1);}
+#define RFCOMM_TRACE_EVENT2(m,p1,p2) {if (rfc_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_2(TRACE_LAYER_RFCOMM, TRACE_TYPE_EVENT, m,p1,p2);}
+#define RFCOMM_TRACE_EVENT3(m,p1,p2,p3) {if (rfc_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_3(TRACE_LAYER_RFCOMM, TRACE_TYPE_EVENT, m,p1,p2,p3);}
+#define RFCOMM_TRACE_EVENT4(m,p1,p2,p3,p4) {if (rfc_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_4(TRACE_LAYER_RFCOMM, TRACE_TYPE_EVENT, m,p1,p2,p3,p4);}
+#define RFCOMM_TRACE_EVENT5(m,p1,p2,p3,p4,p5) {if (rfc_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_5(TRACE_LAYER_RFCOMM, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5);}
+#define RFCOMM_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6) {if (rfc_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_6(TRACE_LAYER_RFCOMM, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5,p6);}
+
+#define RFCOMM_TRACE_DEBUG0(m) {if (rfc_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_0(TRACE_LAYER_RFCOMM, TRACE_TYPE_DEBUG, m);}
+#define RFCOMM_TRACE_DEBUG1(m,p1) {if (rfc_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_1(TRACE_LAYER_RFCOMM, TRACE_TYPE_DEBUG, m,p1);}
+#define RFCOMM_TRACE_DEBUG2(m,p1,p2) {if (rfc_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_2(TRACE_LAYER_RFCOMM, TRACE_TYPE_DEBUG, m,p1,p2);}
+#define RFCOMM_TRACE_DEBUG3(m,p1,p2,p3) {if (rfc_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_3(TRACE_LAYER_RFCOMM, TRACE_TYPE_DEBUG, m,p1,p2,p3);}
+#define RFCOMM_TRACE_DEBUG4(m,p1,p2,p3,p4) {if (rfc_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_4(TRACE_LAYER_RFCOMM, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4);}
+#define RFCOMM_TRACE_DEBUG5(m,p1,p2,p3,p4,p5) {if (rfc_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_5(TRACE_LAYER_RFCOMM, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5);}
+#define RFCOMM_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) {if (rfc_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_6(TRACE_LAYER_RFCOMM, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5,p6);}
+
+/* Define tracing for Serial Port Profile
+*/
+#define SPP_TRACE_ERROR0(m) {if (spp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_0(TRACE_LAYER_SPP, TRACE_TYPE_ERROR, m);}
+#define SPP_TRACE_ERROR1(m,p1) {if (spp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_1(TRACE_LAYER_SPP, TRACE_TYPE_ERROR, m,p1);}
+#define SPP_TRACE_ERROR2(m,p1,p2) {if (spp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_2(TRACE_LAYER_SPP, TRACE_TYPE_ERROR, m,p1,p2);}
+#define SPP_TRACE_ERROR3(m,p1,p2,p3) {if (spp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_3(TRACE_LAYER_SPP, TRACE_TYPE_ERROR, m,p1,p2,p3);}
+#define SPP_TRACE_ERROR4(m,p1,p2,p3,p4) {if (spp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_4(TRACE_LAYER_SPP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4);}
+#define SPP_TRACE_ERROR5(m,p1,p2,p3,p4,p5) {if (spp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_5(TRACE_LAYER_SPP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5);}
+#define SPP_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6) {if (spp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_6(TRACE_LAYER_SPP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5,p6);}
+
+#define SPP_TRACE_WARNING0(m) {if (spp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_0(TRACE_LAYER_SPP, TRACE_TYPE_WARNING, m);}
+#define SPP_TRACE_WARNING1(m,p1) {if (spp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_1(TRACE_LAYER_SPP, TRACE_TYPE_WARNING, m,p1);}
+#define SPP_TRACE_WARNING2(m,p1,p2) {if (spp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_2(TRACE_LAYER_SPP, TRACE_TYPE_WARNING, m,p1,p2);}
+#define SPP_TRACE_WARNING3(m,p1,p2,p3) {if (spp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_3(TRACE_LAYER_SPP, TRACE_TYPE_WARNING, m,p1,p2,p3);}
+#define SPP_TRACE_WARNING4(m,p1,p2,p3,p4) {if (spp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_4(TRACE_LAYER_SPP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4);}
+#define SPP_TRACE_WARNING5(m,p1,p2,p3,p4,p5) {if (spp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_5(TRACE_LAYER_SPP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5);}
+#define SPP_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6) {if (spp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_6(TRACE_LAYER_SPP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5,p6);}
+
+#define SPP_TRACE_EVENT0(m) {if (spp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_0(TRACE_LAYER_SPP, TRACE_TYPE_EVENT, m);}
+#define SPP_TRACE_EVENT1(m,p1) {if (spp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_1(TRACE_LAYER_SPP, TRACE_TYPE_EVENT, m, p1);}
+#define SPP_TRACE_EVENT2(m,p1,p2) {if (spp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_2(TRACE_LAYER_SPP, TRACE_TYPE_EVENT, m,p1,p2);}
+#define SPP_TRACE_EVENT3(m,p1,p2,p3) {if (spp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_3(TRACE_LAYER_SPP, TRACE_TYPE_EVENT, m,p1,p2,p3);}
+#define SPP_TRACE_EVENT4(m,p1,p2,p3,p4) {if (spp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_4(TRACE_LAYER_SPP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4);}
+#define SPP_TRACE_EVENT5(m,p1,p2,p3,p4,p5) {if (spp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_5(TRACE_LAYER_SPP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5);}
+#define SPP_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6) {if (spp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_6(TRACE_LAYER_SPP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5,p6);}
+
+#define SPP_TRACE_API0(m) {if (spp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_0(TRACE_LAYER_SPP, TRACE_TYPE_API, m);}
+#define SPP_TRACE_API1(m,p1) {if (spp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_1(TRACE_LAYER_SPP, TRACE_TYPE_API, m, p1);}
+#define SPP_TRACE_API2(m,p1,p2) {if (spp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_2(TRACE_LAYER_SPP, TRACE_TYPE_API, m,p1,p2);}
+#define SPP_TRACE_API3(m,p1,p2,p3) {if (spp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_3(TRACE_LAYER_SPP, TRACE_TYPE_API, m,p1,p2,p3);}
+#define SPP_TRACE_API4(m,p1,p2,p3,p4) {if (spp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_4(TRACE_LAYER_SPP, TRACE_TYPE_API, m,p1,p2,p3,p4);}
+#define SPP_TRACE_API5(m,p1,p2,p3,p4,p5) {if (spp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_5(TRACE_LAYER_SPP, TRACE_TYPE_API, m,p1,p2,p3,p4,p5);}
+#define SPP_TRACE_API6(m,p1,p2,p3,p4,p5,p6) {if (spp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_6(TRACE_LAYER_SPP, TRACE_TYPE_API, m,p1,p2,p3,p4,p5,p6);}
+
+#define SPP_TRACE_DEBUG0(m) {if (spp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_0(TRACE_LAYER_SPP, TRACE_TYPE_DEBUG, m);}
+#define SPP_TRACE_DEBUG1(m,p1) {if (spp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_1(TRACE_LAYER_SPP, TRACE_TYPE_DEBUG, m,p1);}
+#define SPP_TRACE_DEBUG2(m,p1,p2) {if (spp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_2(TRACE_LAYER_SPP, TRACE_TYPE_DEBUG, m,p1,p2);}
+#define SPP_TRACE_DEBUG3(m,p1,p2,p3) {if (spp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_3(TRACE_LAYER_SPP, TRACE_TYPE_DEBUG, m,p1,p2,p3);}
+#define SPP_TRACE_DEBUG4(m,p1,p2,p3,p4) {if (spp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_4(TRACE_LAYER_SPP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4);}
+#define SPP_TRACE_DEBUG5(m,p1,p2,p3,p4,p5) {if (spp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_5(TRACE_LAYER_SPP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5);}
+#define SPP_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) {if (spp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_6(TRACE_LAYER_SPP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5,p6);}
+
+/* Generic Access Profile traces */
+#define GAP_TRACE_ERROR0(m) {if (gap_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_0(TRACE_LAYER_GAP, TRACE_TYPE_ERROR, m);}
+#define GAP_TRACE_ERROR1(m,p1) {if (gap_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_1(TRACE_LAYER_GAP, TRACE_TYPE_ERROR, m, p1);}
+#define GAP_TRACE_ERROR2(m,p1,p2) {if (gap_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_2(TRACE_LAYER_GAP, TRACE_TYPE_ERROR, m,p1,p2);}
+#define GAP_TRACE_ERROR3(m,p1,p2,p3) {if (gap_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_3(TRACE_LAYER_GAP, TRACE_TYPE_ERROR, m,p1,p2,p3);}
+#define GAP_TRACE_ERROR4(m,p1,p2,p3,p4) {if (gap_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_4(TRACE_LAYER_GAP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4);}
+#define GAP_TRACE_ERROR5(m,p1,p2,p3,p4,p5) {if (gap_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_5(TRACE_LAYER_GAP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5);}
+#define GAP_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6) {if (gap_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_6(TRACE_LAYER_GAP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5,p6);}
+
+#define GAP_TRACE_EVENT0(m) {if (gap_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_0(TRACE_LAYER_GAP, TRACE_TYPE_EVENT, m);}
+#define GAP_TRACE_EVENT1(m,p1) {if (gap_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_1(TRACE_LAYER_GAP, TRACE_TYPE_EVENT, m, p1);}
+#define GAP_TRACE_EVENT2(m,p1,p2) {if (gap_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_2(TRACE_LAYER_GAP, TRACE_TYPE_EVENT, m,p1,p2);}
+#define GAP_TRACE_EVENT3(m,p1,p2,p3) {if (gap_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_3(TRACE_LAYER_GAP, TRACE_TYPE_EVENT, m,p1,p2,p3);}
+#define GAP_TRACE_EVENT4(m,p1,p2,p3,p4) {if (gap_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_4(TRACE_LAYER_GAP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4);}
+#define GAP_TRACE_EVENT5(m,p1,p2,p3,p4,p5) {if (gap_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_5(TRACE_LAYER_GAP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5);}
+#define GAP_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6) {if (gap_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_6(TRACE_LAYER_GAP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5,p6);}
+
+#define GAP_TRACE_API0(m) {if (gap_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_0(TRACE_LAYER_GAP, TRACE_TYPE_API, m);}
+#define GAP_TRACE_API1(m,p1) {if (gap_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_1(TRACE_LAYER_GAP, TRACE_TYPE_API, m, p1);}
+#define GAP_TRACE_API2(m,p1,p2) {if (gap_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_2(TRACE_LAYER_GAP, TRACE_TYPE_API, m,p1,p2);}
+#define GAP_TRACE_API3(m,p1,p2,p3) {if (gap_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_3(TRACE_LAYER_GAP, TRACE_TYPE_API, m,p1,p2,p3);}
+#define GAP_TRACE_API4(m,p1,p2,p3,p4) {if (gap_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_4(TRACE_LAYER_GAP, TRACE_TYPE_API, m,p1,p2,p3,p4);}
+#define GAP_TRACE_API5(m,p1,p2,p3,p4,p5) {if (gap_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_5(TRACE_LAYER_GAP, TRACE_TYPE_API, m,p1,p2,p3,p4,p5);}
+#define GAP_TRACE_API6(m,p1,p2,p3,p4,p5,p6) {if (gap_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_6(TRACE_LAYER_GAP, TRACE_TYPE_API, m,p1,p2,p3,p4,p5,p6);}
+
+#define GAP_TRACE_WARNING0(m) {if (gap_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_0(TRACE_LAYER_GAP, TRACE_TYPE_WARNING, m);}
+#define GAP_TRACE_WARNING1(m,p1) {if (gap_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_1(TRACE_LAYER_GAP, TRACE_TYPE_WARNING, m, p1);}
+#define GAP_TRACE_WARNING2(m,p1,p2) {if (gap_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_2(TRACE_LAYER_GAP, TRACE_TYPE_WARNING, m,p1,p2);}
+#define GAP_TRACE_WARNING3(m,p1,p2,p3) {if (gap_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_3(TRACE_LAYER_GAP, TRACE_TYPE_WARNING, m,p1,p2,p3);}
+#define GAP_TRACE_WARNING4(m,p1,p2,p3,p4) {if (gap_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_4(TRACE_LAYER_GAP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4);}
+#define GAP_TRACE_WARNING5(m,p1,p2,p3,p4,p5) {if (gap_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_5(TRACE_LAYER_GAP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5);}
+#define GAP_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6) {if (gap_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_6(TRACE_LAYER_GAP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5,p6);}
+
+
+/* Define tracing for OBX
+*/
+#define OBX_TRACE_ERROR0(m) {if (obx_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_0(TRACE_LAYER_OBEX, TRACE_TYPE_ERROR, m);}
+#define OBX_TRACE_ERROR1(m,p1) {if (obx_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_1(TRACE_LAYER_OBEX, TRACE_TYPE_ERROR, m,p1);}
+#define OBX_TRACE_ERROR2(m,p1,p2) {if (obx_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_2(TRACE_LAYER_OBEX, TRACE_TYPE_ERROR, m,p1,p2);}
+#define OBX_TRACE_ERROR3(m,p1,p2,p3) {if (obx_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_3(TRACE_LAYER_OBEX, TRACE_TYPE_ERROR, m,p1,p2,p3);}
+#define OBX_TRACE_ERROR4(m,p1,p2,p3,p4) {if (obx_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_4(TRACE_LAYER_OBEX, TRACE_TYPE_ERROR, m,p1,p2,p3,p4);}
+#define OBX_TRACE_ERROR5(m,p1,p2,p3,p4,p5) {if (obx_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_5(TRACE_LAYER_OBEX, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5);}
+#define OBX_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6) {if (obx_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_6(TRACE_LAYER_OBEX, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5,p6);}
+
+#define OBX_TRACE_WARNING0(m) {if (obx_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_0(TRACE_LAYER_OBEX, TRACE_TYPE_WARNING, m);}
+#define OBX_TRACE_WARNING1(m,p1) {if (obx_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_1(TRACE_LAYER_OBEX, TRACE_TYPE_WARNING, m,p1);}
+#define OBX_TRACE_WARNING2(m,p1,p2) {if (obx_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_2(TRACE_LAYER_OBEX, TRACE_TYPE_WARNING, m,p1,p2);}
+#define OBX_TRACE_WARNING3(m,p1,p2,p3) {if (obx_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_3(TRACE_LAYER_OBEX, TRACE_TYPE_WARNING, m,p1,p2,p3);}
+#define OBX_TRACE_WARNING4(m,p1,p2,p3,p4) {if (obx_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_4(TRACE_LAYER_OBEX, TRACE_TYPE_WARNING, m,p1,p2,p3,p4);}
+#define OBX_TRACE_WARNING5(m,p1,p2,p3,p4,p5) {if (obx_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_5(TRACE_LAYER_OBEX, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5);}
+#define OBX_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6) {if (obx_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_6(TRACE_LAYER_OBEX, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5,p6);}
+
+#define OBX_TRACE_EVENT0(m) {if (obx_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_0(TRACE_LAYER_OBEX, TRACE_TYPE_EVENT, m);}
+#define OBX_TRACE_EVENT1(m,p1) {if (obx_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_1(TRACE_LAYER_OBEX, TRACE_TYPE_EVENT, m, p1);}
+#define OBX_TRACE_EVENT2(m,p1,p2) {if (obx_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_2(TRACE_LAYER_OBEX, TRACE_TYPE_EVENT, m,p1,p2);}
+#define OBX_TRACE_EVENT3(m,p1,p2,p3) {if (obx_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_3(TRACE_LAYER_OBEX, TRACE_TYPE_EVENT, m,p1,p2,p3);}
+#define OBX_TRACE_EVENT4(m,p1,p2,p3,p4) {if (obx_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_4(TRACE_LAYER_OBEX, TRACE_TYPE_EVENT, m,p1,p2,p3,p4);}
+#define OBX_TRACE_EVENT5(m,p1,p2,p3,p4,p5) {if (obx_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_5(TRACE_LAYER_OBEX, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5);}
+#define OBX_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6) {if (obx_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_6(TRACE_LAYER_OBEX, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5,p6);}
+
+#define OBX_TRACE_DEBUG0(m) {if (obx_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_0(TRACE_LAYER_OBEX, TRACE_TYPE_DEBUG, m);}
+#define OBX_TRACE_DEBUG1(m,p1) {if (obx_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_1(TRACE_LAYER_OBEX, TRACE_TYPE_DEBUG, m,p1);}
+#define OBX_TRACE_DEBUG2(m,p1,p2) {if (obx_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_2(TRACE_LAYER_OBEX, TRACE_TYPE_DEBUG, m,p1,p2);}
+#define OBX_TRACE_DEBUG3(m,p1,p2,p3) {if (obx_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_3(TRACE_LAYER_OBEX, TRACE_TYPE_DEBUG, m,p1,p2,p3);}
+#define OBX_TRACE_DEBUG4(m,p1,p2,p3,p4) {if (obx_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_4(TRACE_LAYER_OBEX, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4);}
+#define OBX_TRACE_DEBUG5(m,p1,p2,p3,p4,p5) {if (obx_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_5(TRACE_LAYER_OBEX, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5);}
+#define OBX_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) {if (obx_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_6(TRACE_LAYER_OBEX, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5,p6);}
+
+#define OBX_TRACE_API0(m) {if (obx_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_0(TRACE_LAYER_OBEX, TRACE_TYPE_API, m);}
+#define OBX_TRACE_API1(m,p1) {if (obx_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_1(TRACE_LAYER_OBEX, TRACE_TYPE_API, m, p1);}
+#define OBX_TRACE_API2(m,p1,p2) {if (obx_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_2(TRACE_LAYER_OBEX, TRACE_TYPE_API, m,p1,p2);}
+#define OBX_TRACE_API3(m,p1,p2,p3) {if (obx_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_3(TRACE_LAYER_OBEX, TRACE_TYPE_API, m,p1,p2,p3);}
+#define OBX_TRACE_API4(m,p1,p2,p3,p4) {if (obx_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_4(TRACE_LAYER_OBEX, TRACE_TYPE_API, m,p1,p2,p3,p4);}
+#define OBX_TRACE_API5(m,p1,p2,p3,p4,p5) {if (obx_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_5(TRACE_LAYER_OBEX, TRACE_TYPE_API, m,p1,p2,p3,p4,p5);}
+#define OBX_TRACE_API6(m,p1,p2,p3,p4,p5,p6) {if (obx_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_6(TRACE_LAYER_OBEX, TRACE_TYPE_API, m,p1,p2,p3,p4,p5,p6);}
+
+/* Define tracing for OBEX application profiles
+*/
+#define GOEP_TRACE_ERROR0(m) {if (goep_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_0(TRACE_LAYER_GOEP, TRACE_TYPE_ERROR, m);}
+#define GOEP_TRACE_ERROR1(m,p1) {if (goep_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_1(TRACE_LAYER_GOEP, TRACE_TYPE_ERROR, m,p1);}
+#define GOEP_TRACE_ERROR2(m,p1,p2) {if (goep_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_2(TRACE_LAYER_GOEP, TRACE_TYPE_ERROR, m,p1,p2);}
+#define GOEP_TRACE_ERROR3(m,p1,p2,p3) {if (goep_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_3(TRACE_LAYER_GOEP, TRACE_TYPE_ERROR, m,p1,p2,p3);}
+#define GOEP_TRACE_ERROR4(m,p1,p2,p3,p4) {if (goep_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_4(TRACE_LAYER_GOEP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4);}
+#define GOEP_TRACE_ERROR5(m,p1,p2,p3,p4,p5) {if (goep_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_5(TRACE_LAYER_GOEP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5);}
+#define GOEP_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6) {if (goep_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_6(TRACE_LAYER_GOEP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5,p6);}
+
+#define GOEP_TRACE_WARNING0(m) {if (goep_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_0(TRACE_LAYER_GOEP, TRACE_TYPE_WARNING, m);}
+#define GOEP_TRACE_WARNING1(m,p1) {if (goep_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_1(TRACE_LAYER_GOEP, TRACE_TYPE_WARNING, m,p1);}
+#define GOEP_TRACE_WARNING2(m,p1,p2) {if (goep_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_2(TRACE_LAYER_GOEP, TRACE_TYPE_WARNING, m,p1,p2);}
+#define GOEP_TRACE_WARNING3(m,p1,p2,p3) {if (goep_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_3(TRACE_LAYER_GOEP, TRACE_TYPE_WARNING, m,p1,p2,p3);}
+#define GOEP_TRACE_WARNING4(m,p1,p2,p3,p4) {if (goep_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_4(TRACE_LAYER_GOEP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4);}
+#define GOEP_TRACE_WARNING5(m,p1,p2,p3,p4,p5) {if (goep_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_5(TRACE_LAYER_GOEP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5);}
+#define GOEP_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6) {if (goep_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_6(TRACE_LAYER_GOEP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5,p6);}
+
+#define GOEP_TRACE_EVENT0(m) {if (goep_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_0(TRACE_LAYER_GOEP, TRACE_TYPE_EVENT, m);}
+#define GOEP_TRACE_EVENT1(m,p1) {if (goep_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_1(TRACE_LAYER_GOEP, TRACE_TYPE_EVENT, m, p1);}
+#define GOEP_TRACE_EVENT2(m,p1,p2) {if (goep_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_2(TRACE_LAYER_GOEP, TRACE_TYPE_EVENT, m,p1,p2);}
+#define GOEP_TRACE_EVENT3(m,p1,p2,p3) {if (goep_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_3(TRACE_LAYER_GOEP, TRACE_TYPE_EVENT, m,p1,p2,p3);}
+#define GOEP_TRACE_EVENT4(m,p1,p2,p3,p4) {if (goep_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_4(TRACE_LAYER_GOEP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4);}
+#define GOEP_TRACE_EVENT5(m,p1,p2,p3,p4,p5) {if (goep_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_5(TRACE_LAYER_GOEP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5);}
+#define GOEP_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6) {if (goep_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_6(TRACE_LAYER_GOEP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5,p6);}
+
+#define GOEP_TRACE_DEBUG0(m) {if (goep_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_0(TRACE_LAYER_GOEP, TRACE_TYPE_DEBUG, m);}
+#define GOEP_TRACE_DEBUG1(m,p1) {if (goep_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_1(TRACE_LAYER_GOEP, TRACE_TYPE_DEBUG, m,p1);}
+#define GOEP_TRACE_DEBUG2(m,p1,p2) {if (goep_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_2(TRACE_LAYER_GOEP, TRACE_TYPE_DEBUG, m,p1,p2);}
+#define GOEP_TRACE_DEBUG3(m,p1,p2,p3) {if (goep_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_3(TRACE_LAYER_GOEP, TRACE_TYPE_DEBUG, m,p1,p2,p3);}
+#define GOEP_TRACE_DEBUG4(m,p1,p2,p3,p4) {if (goep_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_4(TRACE_LAYER_GOEP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4);}
+#define GOEP_TRACE_DEBUG5(m,p1,p2,p3,p4,p5) {if (goep_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_5(TRACE_LAYER_GOEP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5);}
+#define GOEP_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) {if (goep_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_6(TRACE_LAYER_GOEP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5,p6);}
+
+#define GOEP_TRACE_API0(m) {if (goep_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_0(TRACE_LAYER_GOEP, TRACE_TYPE_API, m);}
+#define GOEP_TRACE_API1(m,p1) {if (goep_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_1(TRACE_LAYER_GOEP, TRACE_TYPE_API, m, p1);}
+#define GOEP_TRACE_API2(m,p1,p2) {if (goep_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_2(TRACE_LAYER_GOEP, TRACE_TYPE_API, m,p1,p2);}
+#define GOEP_TRACE_API3(m,p1,p2,p3) {if (goep_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_3(TRACE_LAYER_GOEP, TRACE_TYPE_API, m,p1,p2,p3);}
+#define GOEP_TRACE_API4(m,p1,p2,p3,p4) {if (goep_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_4(TRACE_LAYER_GOEP, TRACE_TYPE_API, m,p1,p2,p3,p4);}
+#define GOEP_TRACE_API5(m,p1,p2,p3,p4,p5) {if (goep_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_5(TRACE_LAYER_GOEP, TRACE_TYPE_API, m,p1,p2,p3,p4,p5);}
+#define GOEP_TRACE_API6(m,p1,p2,p3,p4,p5,p6) {if (goep_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_6(TRACE_LAYER_GOEP, TRACE_TYPE_API, m,p1,p2,p3,p4,p5,p6);}
+
+/* Define tracing for the BPP profile
+*/
+#define BPP_TRACE_ERROR0(m) {if (bpp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_0(TRACE_LAYER_BPP, TRACE_TYPE_ERROR, m);}
+#define BPP_TRACE_ERROR1(m,p1) {if (bpp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_1(TRACE_LAYER_BPP, TRACE_TYPE_ERROR, m,p1);}
+#define BPP_TRACE_ERROR2(m,p1,p2) {if (bpp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_2(TRACE_LAYER_BPP, TRACE_TYPE_ERROR, m,p1,p2);}
+#define BPP_TRACE_ERROR3(m,p1,p2,p3) {if (bpp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_3(TRACE_LAYER_BPP, TRACE_TYPE_ERROR, m,p1,p2,p3);}
+#define BPP_TRACE_ERROR4(m,p1,p2,p3,p4) {if (bpp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_4(TRACE_LAYER_BPP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4);}
+#define BPP_TRACE_ERROR5(m,p1,p2,p3,p4,p5) {if (bpp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_5(TRACE_LAYER_BPP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5);}
+#define BPP_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6) {if (bpp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_6(TRACE_LAYER_BPP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5,p6);}
+
+#define BPP_TRACE_WARNING0(m) {if (bpp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_0(TRACE_LAYER_BPP, TRACE_TYPE_WARNING, m);}
+#define BPP_TRACE_WARNING1(m,p1) {if (bpp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_1(TRACE_LAYER_BPP, TRACE_TYPE_WARNING, m,p1);}
+#define BPP_TRACE_WARNING2(m,p1,p2) {if (bpp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_2(TRACE_LAYER_BPP, TRACE_TYPE_WARNING, m,p1,p2);}
+#define BPP_TRACE_WARNING3(m,p1,p2,p3) {if (bpp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_3(TRACE_LAYER_BPP, TRACE_TYPE_WARNING, m,p1,p2,p3);}
+#define BPP_TRACE_WARNING4(m,p1,p2,p3,p4) {if (bpp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_4(TRACE_LAYER_BPP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4);}
+#define BPP_TRACE_WARNING5(m,p1,p2,p3,p4,p5) {if (bpp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_5(TRACE_LAYER_BPP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5);}
+#define BPP_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6) {if (bpp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_6(TRACE_LAYER_BPP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5,p6);}
+
+#define BPP_TRACE_EVENT0(m) {if (bpp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_0(TRACE_LAYER_BPP, TRACE_TYPE_EVENT, m);}
+#define BPP_TRACE_EVENT1(m,p1) {if (bpp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_1(TRACE_LAYER_BPP, TRACE_TYPE_EVENT, m, p1);}
+#define BPP_TRACE_EVENT2(m,p1,p2) {if (bpp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_2(TRACE_LAYER_BPP, TRACE_TYPE_EVENT, m,p1,p2);}
+#define BPP_TRACE_EVENT3(m,p1,p2,p3) {if (bpp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_3(TRACE_LAYER_BPP, TRACE_TYPE_EVENT, m,p1,p2,p3);}
+#define BPP_TRACE_EVENT4(m,p1,p2,p3,p4) {if (bpp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_4(TRACE_LAYER_BPP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4);}
+#define BPP_TRACE_EVENT5(m,p1,p2,p3,p4,p5) {if (bpp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_5(TRACE_LAYER_BPP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5);}
+#define BPP_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6) {if (bpp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_6(TRACE_LAYER_BPP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5,p6);}
+
+#define BPP_TRACE_DEBUG0(m) {if (bpp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_0(TRACE_LAYER_BPP, TRACE_TYPE_DEBUG, m);}
+#define BPP_TRACE_DEBUG1(m,p1) {if (bpp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_1(TRACE_LAYER_BPP, TRACE_TYPE_DEBUG, m,p1);}
+#define BPP_TRACE_DEBUG2(m,p1,p2) {if (bpp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_2(TRACE_LAYER_BPP, TRACE_TYPE_DEBUG, m,p1,p2);}
+#define BPP_TRACE_DEBUG3(m,p1,p2,p3) {if (bpp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_3(TRACE_LAYER_BPP, TRACE_TYPE_DEBUG, m,p1,p2,p3);}
+#define BPP_TRACE_DEBUG4(m,p1,p2,p3,p4) {if (bpp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_4(TRACE_LAYER_BPP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4);}
+#define BPP_TRACE_DEBUG5(m,p1,p2,p3,p4,p5) {if (bpp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_5(TRACE_LAYER_BPP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5);}
+#define BPP_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) {if (bpp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_6(TRACE_LAYER_BPP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5,p6);}
+
+#define BPP_TRACE_API0(m) {if (bpp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_0(TRACE_LAYER_BPP, TRACE_TYPE_API, m);}
+#define BPP_TRACE_API1(m,p1) {if (bpp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_1(TRACE_LAYER_BPP, TRACE_TYPE_API, m, p1);}
+#define BPP_TRACE_API2(m,p1,p2) {if (bpp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_2(TRACE_LAYER_BPP, TRACE_TYPE_API, m,p1,p2);}
+#define BPP_TRACE_API3(m,p1,p2,p3) {if (bpp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_3(TRACE_LAYER_BPP, TRACE_TYPE_API, m,p1,p2,p3);}
+#define BPP_TRACE_API4(m,p1,p2,p3,p4) {if (bpp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_4(TRACE_LAYER_BPP, TRACE_TYPE_API, m,p1,p2,p3,p4);}
+#define BPP_TRACE_API5(m,p1,p2,p3,p4,p5) {if (bpp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_5(TRACE_LAYER_BPP, TRACE_TYPE_API, m,p1,p2,p3,p4,p5);}
+#define BPP_TRACE_API6(m,p1,p2,p3,p4,p5,p6) {if (bpp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_6(TRACE_LAYER_BPP, TRACE_TYPE_API, m,p1,p2,p3,p4,p5,p6);}
+
+/* Define tracing for the BIP profile
+*/
+#define BIP_TRACE_ERROR0(m) {if (bip_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_0(TRACE_LAYER_BIP, TRACE_TYPE_ERROR, m);}
+#define BIP_TRACE_ERROR1(m,p1) {if (bip_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_1(TRACE_LAYER_BIP, TRACE_TYPE_ERROR, m,p1);}
+#define BIP_TRACE_ERROR2(m,p1,p2) {if (bip_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_2(TRACE_LAYER_BIP, TRACE_TYPE_ERROR, m,p1,p2);}
+#define BIP_TRACE_ERROR3(m,p1,p2,p3) {if (bip_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_3(TRACE_LAYER_BIP, TRACE_TYPE_ERROR, m,p1,p2,p3);}
+#define BIP_TRACE_ERROR4(m,p1,p2,p3,p4) {if (bip_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_4(TRACE_LAYER_BIP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4);}
+#define BIP_TRACE_ERROR5(m,p1,p2,p3,p4,p5) {if (bip_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_5(TRACE_LAYER_BIP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5);}
+#define BIP_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6) {if (bip_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_6(TRACE_LAYER_BIP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5,p6);}
+
+#define BIP_TRACE_WARNING0(m) {if (bip_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_0(TRACE_LAYER_BIP, TRACE_TYPE_WARNING, m);}
+#define BIP_TRACE_WARNING1(m,p1) {if (bip_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_1(TRACE_LAYER_BIP, TRACE_TYPE_WARNING, m,p1);}
+#define BIP_TRACE_WARNING2(m,p1,p2) {if (bip_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_2(TRACE_LAYER_BIP, TRACE_TYPE_WARNING, m,p1,p2);}
+#define BIP_TRACE_WARNING3(m,p1,p2,p3) {if (bip_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_3(TRACE_LAYER_BIP, TRACE_TYPE_WARNING, m,p1,p2,p3);}
+#define BIP_TRACE_WARNING4(m,p1,p2,p3,p4) {if (bip_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_4(TRACE_LAYER_BIP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4);}
+#define BIP_TRACE_WARNING5(m,p1,p2,p3,p4,p5) {if (bip_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_5(TRACE_LAYER_BIP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5);}
+#define BIP_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6) {if (bip_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_6(TRACE_LAYER_BIP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5,p6);}
+
+#define BIP_TRACE_EVENT0(m) {if (bip_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_0(TRACE_LAYER_BIP, TRACE_TYPE_EVENT, m);}
+#define BIP_TRACE_EVENT1(m,p1) {if (bip_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_1(TRACE_LAYER_BIP, TRACE_TYPE_EVENT, m, p1);}
+#define BIP_TRACE_EVENT2(m,p1,p2) {if (bip_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_2(TRACE_LAYER_BIP, TRACE_TYPE_EVENT, m,p1,p2);}
+#define BIP_TRACE_EVENT3(m,p1,p2,p3) {if (bip_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_3(TRACE_LAYER_BIP, TRACE_TYPE_EVENT, m,p1,p2,p3);}
+#define BIP_TRACE_EVENT4(m,p1,p2,p3,p4) {if (bip_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_4(TRACE_LAYER_BIP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4);}
+#define BIP_TRACE_EVENT5(m,p1,p2,p3,p4,p5) {if (bip_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_5(TRACE_LAYER_BIP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5);}
+#define BIP_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6) {if (bip_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_6(TRACE_LAYER_BIP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5,p6);}
+
+#define BIP_TRACE_DEBUG0(m) {if (bip_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_0(TRACE_LAYER_BIP, TRACE_TYPE_DEBUG, m);}
+#define BIP_TRACE_DEBUG1(m,p1) {if (bip_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_1(TRACE_LAYER_BIP, TRACE_TYPE_DEBUG, m,p1);}
+#define BIP_TRACE_DEBUG2(m,p1,p2) {if (bip_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_2(TRACE_LAYER_BIP, TRACE_TYPE_DEBUG, m,p1,p2);}
+#define BIP_TRACE_DEBUG3(m,p1,p2,p3) {if (bip_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_3(TRACE_LAYER_BIP, TRACE_TYPE_DEBUG, m,p1,p2,p3);}
+#define BIP_TRACE_DEBUG4(m,p1,p2,p3,p4) {if (bip_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_4(TRACE_LAYER_BIP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4);}
+#define BIP_TRACE_DEBUG5(m,p1,p2,p3,p4,p5) {if (bip_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_5(TRACE_LAYER_BIP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5);}
+#define BIP_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) {if (bip_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_6(TRACE_LAYER_BIP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5,p6);}
+
+#define BIP_TRACE_API0(m) {if (bip_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_0(TRACE_LAYER_BIP, TRACE_TYPE_API, m);}
+#define BIP_TRACE_API1(m,p1) {if (bip_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_1(TRACE_LAYER_BIP, TRACE_TYPE_API, m, p1);}
+#define BIP_TRACE_API2(m,p1,p2) {if (bip_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_2(TRACE_LAYER_BIP, TRACE_TYPE_API, m,p1,p2);}
+#define BIP_TRACE_API3(m,p1,p2,p3) {if (bip_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_3(TRACE_LAYER_BIP, TRACE_TYPE_API, m,p1,p2,p3);}
+#define BIP_TRACE_API4(m,p1,p2,p3,p4) {if (bip_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_4(TRACE_LAYER_BIP, TRACE_TYPE_API, m,p1,p2,p3,p4);}
+#define BIP_TRACE_API5(m,p1,p2,p3,p4,p5) {if (bip_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_5(TRACE_LAYER_BIP, TRACE_TYPE_API, m,p1,p2,p3,p4,p5);}
+#define BIP_TRACE_API6(m,p1,p2,p3,p4,p5,p6) {if (bip_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_6(TRACE_LAYER_BIP, TRACE_TYPE_API, m,p1,p2,p3,p4,p5,p6);}
+
+/* Define tracing for TCS
+*/
+#define TCS_TRACE_ERROR0(m) {if (tcs_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_0(TRACE_LAYER_TCS, TRACE_TYPE_ERROR, m);}
+#define TCS_TRACE_ERROR1(m,p1) {if (tcs_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_1(TRACE_LAYER_TCS, TRACE_TYPE_ERROR, m,p1);}
+#define TCS_TRACE_ERROR2(m,p1,p2) {if (tcs_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_2(TRACE_LAYER_TCS, TRACE_TYPE_ERROR, m,p1,p2);}
+#define TCS_TRACE_ERROR3(m,p1,p2,p3) {if (tcs_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_3(TRACE_LAYER_TCS, TRACE_TYPE_ERROR, m,p1,p2,p3);}
+#define TCS_TRACE_ERROR4(m,p1,p2,p3,p4) {if (tcs_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_4(TRACE_LAYER_TCS, TRACE_TYPE_ERROR, m,p1,p2,p3,p4);}
+#define TCS_TRACE_ERROR5(m,p1,p2,p3,p4,p5) {if (tcs_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_5(TRACE_LAYER_TCS, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5);}
+#define TCS_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6) {if (tcs_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_6(TRACE_LAYER_TCS, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5,p6);}
+
+#define TCS_TRACE_WARNING0(m) {if (tcs_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_0(TRACE_LAYER_TCS, TRACE_TYPE_WARNING, m);}
+#define TCS_TRACE_WARNING1(m,p1) {if (tcs_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_1(TRACE_LAYER_TCS, TRACE_TYPE_WARNING, m,p1);}
+#define TCS_TRACE_WARNING2(m,p1,p2) {if (tcs_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_2(TRACE_LAYER_TCS, TRACE_TYPE_WARNING, m,p1,p2);}
+#define TCS_TRACE_WARNING3(m,p1,p2,p3) {if (tcs_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_3(TRACE_LAYER_TCS, TRACE_TYPE_WARNING, m,p1,p2,p3);}
+#define TCS_TRACE_WARNING4(m,p1,p2,p3,p4) {if (tcs_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_4(TRACE_LAYER_TCS, TRACE_TYPE_WARNING, m,p1,p2,p3,p4);}
+#define TCS_TRACE_WARNING5(m,p1,p2,p3,p4,p5) {if (tcs_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_5(TRACE_LAYER_TCS, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5);}
+#define TCS_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6) {if (tcs_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_6(TRACE_LAYER_TCS, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5,p6);}
+
+#define TCS_TRACE_EVENT0(m) {if (tcs_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_0(TRACE_LAYER_TCS, TRACE_TYPE_EVENT, m);}
+#define TCS_TRACE_EVENT1(m,p1) {if (tcs_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_1(TRACE_LAYER_TCS, TRACE_TYPE_EVENT, m, p1);}
+#define TCS_TRACE_EVENT2(m,p1,p2) {if (tcs_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_2(TRACE_LAYER_TCS, TRACE_TYPE_EVENT, m,p1,p2);}
+#define TCS_TRACE_EVENT3(m,p1,p2,p3) {if (tcs_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_3(TRACE_LAYER_TCS, TRACE_TYPE_EVENT, m,p1,p2,p3);}
+#define TCS_TRACE_EVENT4(m,p1,p2,p3,p4) {if (tcs_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_4(TRACE_LAYER_TCS, TRACE_TYPE_EVENT, m,p1,p2,p3,p4);}
+#define TCS_TRACE_EVENT5(m,p1,p2,p3,p4,p5) {if (tcs_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_5(TRACE_LAYER_TCS, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5);}
+#define TCS_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6) {if (tcs_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_6(TRACE_LAYER_TCS, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5,p6);}
+
+#define TCS_TRACE_DEBUG0(m) {if (tcs_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_0(TRACE_LAYER_TCS, TRACE_TYPE_DEBUG, m);}
+#define TCS_TRACE_DEBUG1(m,p1) {if (tcs_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_1(TRACE_LAYER_TCS, TRACE_TYPE_DEBUG, m,p1);}
+#define TCS_TRACE_DEBUG2(m,p1,p2) {if (tcs_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_2(TRACE_LAYER_TCS, TRACE_TYPE_DEBUG, m,p1,p2);}
+#define TCS_TRACE_DEBUG3(m,p1,p2,p3) {if (tcs_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_3(TRACE_LAYER_TCS, TRACE_TYPE_DEBUG, m,p1,p2,p3);}
+#define TCS_TRACE_DEBUG4(m,p1,p2,p3,p4) {if (tcs_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_4(TRACE_LAYER_TCS, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4);}
+#define TCS_TRACE_DEBUG5(m,p1,p2,p3,p4,p5) {if (tcs_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_5(TRACE_LAYER_TCS, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5);}
+#define TCS_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) {if (tcs_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_6(TRACE_LAYER_TCS, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5,p6);}
+
+#define TCS_TRACE_API0(m) {if (tcs_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_0(TRACE_LAYER_TCS, TRACE_TYPE_API, m);}
+#define TCS_TRACE_API1(m,p1) {if (tcs_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_1(TRACE_LAYER_TCS, TRACE_TYPE_API, m, p1);}
+#define TCS_TRACE_API2(m,p1,p2) {if (tcs_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_2(TRACE_LAYER_TCS, TRACE_TYPE_API, m,p1,p2);}
+#define TCS_TRACE_API3(m,p1,p2,p3) {if (tcs_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_3(TRACE_LAYER_TCS, TRACE_TYPE_API, m,p1,p2,p3);}
+#define TCS_TRACE_API4(m,p1,p2,p3,p4) {if (tcs_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_4(TRACE_LAYER_TCS, TRACE_TYPE_API, m,p1,p2,p3,p4);}
+#define TCS_TRACE_API5(m,p1,p2,p3,p4,p5) {if (tcs_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_5(TRACE_LAYER_TCS, TRACE_TYPE_API, m,p1,p2,p3,p4,p5);}
+#define TCS_TRACE_API6(m,p1,p2,p3,p4,p5,p6) {if (tcs_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_6(TRACE_LAYER_TCS, TRACE_TYPE_API, m,p1,p2,p3,p4,p5,p6);}
+
+/* Define tracing for ICP
+*/
+#define ICP_TRACE_ERROR0(m) {if (icp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_0(TRACE_LAYER_ICP, TRACE_TYPE_ERROR, m);}
+#define ICP_TRACE_ERROR1(m,p1) {if (icp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_1(TRACE_LAYER_ICP, TRACE_TYPE_ERROR, m,p1);}
+#define ICP_TRACE_ERROR2(m,p1,p2) {if (icp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_2(TRACE_LAYER_ICP, TRACE_TYPE_ERROR, m,p1,p2);}
+#define ICP_TRACE_ERROR3(m,p1,p2,p3) {if (icp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_3(TRACE_LAYER_ICP, TRACE_TYPE_ERROR, m,p1,p2,p3);}
+#define ICP_TRACE_ERROR4(m,p1,p2,p3,p4) {if (icp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_4(TRACE_LAYER_ICP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4);}
+#define ICP_TRACE_ERROR5(m,p1,p2,p3,p4,p5) {if (icp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_5(TRACE_LAYER_ICP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5);}
+#define ICP_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6) {if (icp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_6(TRACE_LAYER_ICP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5,p6);}
+
+#define ICP_TRACE_WARNING0(m) {if (icp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_0(TRACE_LAYER_ICP, TRACE_TYPE_WARNING, m);}
+#define ICP_TRACE_WARNING1(m,p1) {if (icp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_1(TRACE_LAYER_ICP, TRACE_TYPE_WARNING, m,p1);}
+#define ICP_TRACE_WARNING2(m,p1,p2) {if (icp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_2(TRACE_LAYER_ICP, TRACE_TYPE_WARNING, m,p1,p2);}
+#define ICP_TRACE_WARNING3(m,p1,p2,p3) {if (icp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_3(TRACE_LAYER_ICP, TRACE_TYPE_WARNING, m,p1,p2,p3);}
+#define ICP_TRACE_WARNING4(m,p1,p2,p3,p4) {if (icp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_4(TRACE_LAYER_ICP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4);}
+#define ICP_TRACE_WARNING5(m,p1,p2,p3,p4,p5) {if (icp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_5(TRACE_LAYER_ICP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5);}
+#define ICP_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6) {if (icp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_6(TRACE_LAYER_ICP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5,p6);}
+
+#define ICP_TRACE_EVENT0(m) {if (icp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_0(TRACE_LAYER_ICP, TRACE_TYPE_EVENT, m);}
+#define ICP_TRACE_EVENT1(m,p1) {if (icp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_1(TRACE_LAYER_ICP, TRACE_TYPE_EVENT, m, p1);}
+#define ICP_TRACE_EVENT2(m,p1,p2) {if (icp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_2(TRACE_LAYER_ICP, TRACE_TYPE_EVENT, m,p1,p2);}
+#define ICP_TRACE_EVENT3(m,p1,p2,p3) {if (icp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_3(TRACE_LAYER_ICP, TRACE_TYPE_EVENT, m,p1,p2,p3);}
+#define ICP_TRACE_EVENT4(m,p1,p2,p3,p4) {if (icp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_4(TRACE_LAYER_ICP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4);}
+#define ICP_TRACE_EVENT5(m,p1,p2,p3,p4,p5) {if (icp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_5(TRACE_LAYER_ICP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5);}
+#define ICP_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6) {if (icp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_6(TRACE_LAYER_ICP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5,p6);}
+
+#define ICP_TRACE_DEBUG0(m) {if (icp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_0(TRACE_LAYER_ICP, TRACE_TYPE_DEBUG, m);}
+#define ICP_TRACE_DEBUG1(m,p1) {if (icp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_1(TRACE_LAYER_ICP, TRACE_TYPE_DEBUG, m,p1);}
+#define ICP_TRACE_DEBUG2(m,p1,p2) {if (icp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_2(TRACE_LAYER_ICP, TRACE_TYPE_DEBUG, m,p1,p2);}
+#define ICP_TRACE_DEBUG3(m,p1,p2,p3) {if (icp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_3(TRACE_LAYER_ICP, TRACE_TYPE_DEBUG, m,p1,p2,p3);}
+#define ICP_TRACE_DEBUG4(m,p1,p2,p3,p4) {if (icp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_4(TRACE_LAYER_ICP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4);}
+#define ICP_TRACE_DEBUG5(m,p1,p2,p3,p4,p5) {if (icp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_5(TRACE_LAYER_ICP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5);}
+#define ICP_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) {if (icp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_6(TRACE_LAYER_ICP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5,p6);}
+
+#define ICP_TRACE_API0(m) {if (icp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_0(TRACE_LAYER_ICP, TRACE_TYPE_API, m);}
+#define ICP_TRACE_API1(m,p1) {if (icp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_1(TRACE_LAYER_ICP, TRACE_TYPE_API, m, p1);}
+#define ICP_TRACE_API2(m,p1,p2) {if (icp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_2(TRACE_LAYER_ICP, TRACE_TYPE_API, m,p1,p2);}
+#define ICP_TRACE_API3(m,p1,p2,p3) {if (icp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_3(TRACE_LAYER_ICP, TRACE_TYPE_API, m,p1,p2,p3);}
+#define ICP_TRACE_API4(m,p1,p2,p3,p4) {if (icp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_4(TRACE_LAYER_ICP, TRACE_TYPE_API, m,p1,p2,p3,p4);}
+#define ICP_TRACE_API5(m,p1,p2,p3,p4,p5) {if (icp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_5(TRACE_LAYER_ICP, TRACE_TYPE_API, m,p1,p2,p3,p4,p5);}
+#define ICP_TRACE_API6(m,p1,p2,p3,p4,p5,p6) {if (icp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_6(TRACE_LAYER_ICP, TRACE_TYPE_API, m,p1,p2,p3,p4,p5,p6);}
+
+/* CTP */
+#define CTP_TRACE_ERROR0(m) {if (ctp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_0(TRACE_LAYER_CTP, TRACE_TYPE_ERROR, m);}
+#define CTP_TRACE_ERROR1(m,p1) {if (ctp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_1(TRACE_LAYER_CTP, TRACE_TYPE_ERROR, m,p1);}
+#define CTP_TRACE_ERROR2(m,p1,p2) {if (ctp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_2(TRACE_LAYER_CTP, TRACE_TYPE_ERROR, m,p1,p2);}
+#define CTP_TRACE_ERROR3(m,p1,p2,p3) {if (ctp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_3(TRACE_LAYER_CTP, TRACE_TYPE_ERROR, m,p1,p2,p3);}
+#define CTP_TRACE_ERROR4(m,p1,p2,p3,p4) {if (ctp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_4(TRACE_LAYER_CTP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4);}
+#define CTP_TRACE_ERROR5(m,p1,p2,p3,p4,p5) {if (ctp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_5(TRACE_LAYER_CTP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5);}
+#define CTP_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6) {if (ctp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_6(TRACE_LAYER_CTP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5,p6);}
+
+#define CTP_TRACE_WARNING0(m) {if (ctp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_0(TRACE_LAYER_CTP, TRACE_TYPE_WARNING, m);}
+#define CTP_TRACE_WARNING1(m,p1) {if (ctp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_1(TRACE_LAYER_CTP, TRACE_TYPE_WARNING, m,p1);}
+#define CTP_TRACE_WARNING2(m,p1,p2) {if (ctp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_2(TRACE_LAYER_CTP, TRACE_TYPE_WARNING, m,p1,p2);}
+#define CTP_TRACE_WARNING3(m,p1,p2,p3) {if (ctp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_3(TRACE_LAYER_CTP, TRACE_TYPE_WARNING, m,p1,p2,p3);}
+#define CTP_TRACE_WARNING4(m,p1,p2,p3,p4) {if (ctp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_4(TRACE_LAYER_CTP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4);}
+#define CTP_TRACE_WARNING5(m,p1,p2,p3,p4,p5) {if (ctp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_5(TRACE_LAYER_CTP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5);}
+#define CTP_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6) {if (ctp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_6(TRACE_LAYER_CTP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5,p6);}
+
+#define CTP_TRACE_EVENT0(m) {if (ctp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_0(TRACE_LAYER_CTP, TRACE_TYPE_EVENT, m);}
+#define CTP_TRACE_EVENT1(m,p1) {if (ctp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_1(TRACE_LAYER_CTP, TRACE_TYPE_EVENT, m, p1);}
+#define CTP_TRACE_EVENT2(m,p1,p2) {if (ctp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_2(TRACE_LAYER_CTP, TRACE_TYPE_EVENT, m,p1,p2);}
+#define CTP_TRACE_EVENT3(m,p1,p2,p3) {if (ctp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_3(TRACE_LAYER_CTP, TRACE_TYPE_EVENT, m,p1,p2,p3);}
+#define CTP_TRACE_EVENT4(m,p1,p2,p3,p4) {if (ctp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_4(TRACE_LAYER_CTP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4);}
+#define CTP_TRACE_EVENT5(m,p1,p2,p3,p4,p5) {if (ctp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_5(TRACE_LAYER_CTP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5);}
+#define CTP_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6) {if (ctp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_6(TRACE_LAYER_CTP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5,p6);}
+
+#define CTP_TRACE_DEBUG0(m) {if (ctp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_0(TRACE_LAYER_CTP, TRACE_TYPE_DEBUG, m);}
+#define CTP_TRACE_DEBUG1(m,p1) {if (ctp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_1(TRACE_LAYER_CTP, TRACE_TYPE_DEBUG, m,p1);}
+#define CTP_TRACE_DEBUG2(m,p1,p2) {if (ctp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_2(TRACE_LAYER_CTP, TRACE_TYPE_DEBUG, m,p1,p2);}
+#define CTP_TRACE_DEBUG3(m,p1,p2,p3) {if (ctp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_3(TRACE_LAYER_CTP, TRACE_TYPE_DEBUG, m,p1,p2,p3);}
+#define CTP_TRACE_DEBUG4(m,p1,p2,p3,p4) {if (ctp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_4(TRACE_LAYER_CTP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4);}
+#define CTP_TRACE_DEBUG5(m,p1,p2,p3,p4,p5) {if (ctp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_5(TRACE_LAYER_CTP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5);}
+#define CTP_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) {if (ctp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_6(TRACE_LAYER_CTP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5,p6);}
+
+
+/* define traces for HID Host */
+#define HIDH_TRACE_ERROR0(m) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_0(TRACE_LAYER_HID, TRACE_TYPE_ERROR, m);}
+#define HIDH_TRACE_ERROR1(m,p1) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_1(TRACE_LAYER_HID, TRACE_TYPE_ERROR, m, p1);}
+#define HIDH_TRACE_ERROR2(m,p1,p2) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_2(TRACE_LAYER_HID, TRACE_TYPE_ERROR, m,p1,p2);}
+#define HIDH_TRACE_ERROR3(m,p1,p2,p3) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_3(TRACE_LAYER_HID, TRACE_TYPE_ERROR, m,p1,p2,p3);}
+#define HIDH_TRACE_ERROR4(m,p1,p2,p3,p4) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_4(TRACE_LAYER_HID, TRACE_TYPE_ERROR, m,p1,p2,p3,p4);}
+#define HIDH_TRACE_ERROR5(m,p1,p2,p3,p4,p5) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_5(TRACE_LAYER_HID, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5);}
+#define HIDH_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_6(TRACE_LAYER_HID, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5,p6);}
+
+#define HIDH_TRACE_WARNING0(m) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_0(TRACE_LAYER_HID, TRACE_TYPE_WARNING, m);}
+#define HIDH_TRACE_WARNING1(m,p1) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_1(TRACE_LAYER_HID, TRACE_TYPE_WARNING, m,p1);}
+#define HIDH_TRACE_WARNING2(m,p1,p2) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_2(TRACE_LAYER_HID, TRACE_TYPE_WARNING, m,p1,p2);}
+#define HIDH_TRACE_WARNING3(m,p1,p2,p3) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_3(TRACE_LAYER_HID, TRACE_TYPE_WARNING, m,p1,p2,p3);}
+#define HIDH_TRACE_WARNING4(m,p1,p2,p3,p4) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_4(TRACE_LAYER_HID, TRACE_TYPE_WARNING, m,p1,p2,p3,p4);}
+#define HIDH_TRACE_WARNING5(m,p1,p2,p3,p4,p5) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_5(TRACE_LAYER_HID, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5);}
+#define HIDH_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_6(TRACE_LAYER_HID, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5,p6);}
+
+#define HIDH_TRACE_API0(m) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_0(TRACE_LAYER_HID, TRACE_TYPE_API, m);}
+#define HIDH_TRACE_API1(m,p1) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_1(TRACE_LAYER_HID, TRACE_TYPE_API, m, p1);}
+#define HIDH_TRACE_API2(m,p1,p2) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_2(TRACE_LAYER_HID, TRACE_TYPE_API, m,p1,p2);}
+#define HIDH_TRACE_API3(m,p1,p2,p3) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_3(TRACE_LAYER_HID, TRACE_TYPE_API, m,p1,p2,p3);}
+#define HIDH_TRACE_API4(m,p1,p2,p3,p4) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_4(TRACE_LAYER_HID, TRACE_TYPE_API, m,p1,p2,p3,p4);}
+#define HIDH_TRACE_API5(m,p1,p2,p3,p4,p5) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_5(TRACE_LAYER_HID, TRACE_TYPE_API, m,p1,p2,p3,p4,p5);}
+#define HIDH_TRACE_API6(m,p1,p2,p3,p4,p5,p6) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_6(TRACE_LAYER_HID, TRACE_TYPE_API, m,p1,p2,p3,p4,p5,p6);}
+
+#define HIDH_TRACE_EVENT0(m) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_0(TRACE_LAYER_HID, TRACE_TYPE_EVENT, m);}
+#define HIDH_TRACE_EVENT1(m,p1) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_1(TRACE_LAYER_HID, TRACE_TYPE_EVENT, m, p1);}
+#define HIDH_TRACE_EVENT2(m,p1,p2) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_2(TRACE_LAYER_HID, TRACE_TYPE_EVENT, m,p1,p2);}
+#define HIDH_TRACE_EVENT3(m,p1,p2,p3) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_3(TRACE_LAYER_HID, TRACE_TYPE_EVENT, m,p1,p2,p3);}
+#define HIDH_TRACE_EVENT4(m,p1,p2,p3,p4) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_4(TRACE_LAYER_HID, TRACE_TYPE_EVENT, m,p1,p2,p3,p4);}
+#define HIDH_TRACE_EVENT5(m,p1,p2,p3,p4,p5) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_5(TRACE_LAYER_HID, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5);}
+#define HIDH_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_6(TRACE_LAYER_HID, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5,p6);}
+
+#define HIDH_TRACE_DEBUG0(m) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_0(TRACE_LAYER_HID, TRACE_TYPE_DEBUG, m);}
+#define HIDH_TRACE_DEBUG1(m,p1) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_1(TRACE_LAYER_HID, TRACE_TYPE_DEBUG, m,p1);}
+#define HIDH_TRACE_DEBUG2(m,p1,p2) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_2(TRACE_LAYER_HID, TRACE_TYPE_DEBUG, m,p1,p2);}
+#define HIDH_TRACE_DEBUG3(m,p1,p2,p3) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_3(TRACE_LAYER_HID, TRACE_TYPE_DEBUG, m,p1,p2,p3);}
+#define HIDH_TRACE_DEBUG4(m,p1,p2,p3,p4) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_4(TRACE_LAYER_HID, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4);}
+#define HIDH_TRACE_DEBUG5(m,p1,p2,p3,p4,p5) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_5(TRACE_LAYER_HID, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5);}
+#define HIDH_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_6(TRACE_LAYER_HID, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5,p6);}
+
+/* define traces for HID Device */
+#define HIDD_TRACE_ERROR0(m) {if (hd_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_0(TRACE_LAYER_HID, TRACE_TYPE_ERROR, m);}
+#define HIDD_TRACE_ERROR1(m,p1) {if (hd_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_1(TRACE_LAYER_HID, TRACE_TYPE_ERROR, m, p1);}
+#define HIDD_TRACE_ERROR2(m,p1,p2) {if (hd_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_2(TRACE_LAYER_HID, TRACE_TYPE_ERROR, m,p1,p2);}
+#define HIDD_TRACE_ERROR3(m,p1,p2,p3) {if (hd_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_3(TRACE_LAYER_HID, TRACE_TYPE_ERROR, m,p1,p2,p3);}
+#define HIDD_TRACE_ERROR4(m,p1,p2,p3,p4) {if (hd_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_4(TRACE_LAYER_HID, TRACE_TYPE_ERROR, m,p1,p2,p3,p4);}
+#define HIDD_TRACE_ERROR5(m,p1,p2,p3,p4,p5) {if (hd_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_5(TRACE_LAYER_HID, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5);}
+#define HIDD_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6) {if (hd_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_6(TRACE_LAYER_HID, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5,p6);}
+
+#define HIDD_TRACE_WARNING0(m) {if (hd_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_0(TRACE_LAYER_HID, TRACE_TYPE_WARNING, m);}
+#define HIDD_TRACE_WARNING1(m,p1) {if (hd_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_1(TRACE_LAYER_HID, TRACE_TYPE_WARNING, m,p1);}
+#define HIDD_TRACE_WARNING2(m,p1,p2) {if (hd_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_2(TRACE_LAYER_HID, TRACE_TYPE_WARNING, m,p1,p2);}
+#define HIDD_TRACE_WARNING3(m,p1,p2,p3) {if (hd_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_3(TRACE_LAYER_HID, TRACE_TYPE_WARNING, m,p1,p2,p3);}
+#define HIDD_TRACE_WARNING4(m,p1,p2,p3,p4) {if (hd_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_4(TRACE_LAYER_HID, TRACE_TYPE_WARNING, m,p1,p2,p3,p4);}
+#define HIDD_TRACE_WARNING5(m,p1,p2,p3,p4,p5) {if (hd_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_5(TRACE_LAYER_HID, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5);}
+#define HIDD_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6) {if (hd_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_6(TRACE_LAYER_HID, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5,p6);}
+
+#define HIDD_TRACE_API0(m) {if (hd_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_0(TRACE_LAYER_HID, TRACE_TYPE_API, m);}
+#define HIDD_TRACE_API1(m,p1) {if (hd_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_1(TRACE_LAYER_HID, TRACE_TYPE_API, m, p1);}
+#define HIDD_TRACE_API2(m,p1,p2) {if (hd_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_2(TRACE_LAYER_HID, TRACE_TYPE_API, m,p1,p2);}
+#define HIDD_TRACE_API3(m,p1,p2,p3) {if (hd_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_3(TRACE_LAYER_HID, TRACE_TYPE_API, m,p1,p2,p3);}
+#define HIDD_TRACE_API4(m,p1,p2,p3,p4) {if (hd_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_4(TRACE_LAYER_HID, TRACE_TYPE_API, m,p1,p2,p3,p4);}
+#define HIDD_TRACE_API5(m,p1,p2,p3,p4,p5) {if (hd_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_5(TRACE_LAYER_HID, TRACE_TYPE_API, m,p1,p2,p3,p4,p5);}
+#define HIDD_TRACE_API6(m,p1,p2,p3,p4,p5,p6) {if (hd_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_6(TRACE_LAYER_HID, TRACE_TYPE_API, m,p1,p2,p3,p4,p5,p6);}
+
+#define HIDD_TRACE_EVENT0(m) {if (hd_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_0(TRACE_LAYER_HID, TRACE_TYPE_EVENT, m);}
+#define HIDD_TRACE_EVENT1(m,p1) {if (hd_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_1(TRACE_LAYER_HID, TRACE_TYPE_EVENT, m, p1);}
+#define HIDD_TRACE_EVENT2(m,p1,p2) {if (hd_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_2(TRACE_LAYER_HID, TRACE_TYPE_EVENT, m,p1,p2);}
+#define HIDD_TRACE_EVENT3(m,p1,p2,p3) {if (hd_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_3(TRACE_LAYER_HID, TRACE_TYPE_EVENT, m,p1,p2,p3);}
+#define HIDD_TRACE_EVENT4(m,p1,p2,p3,p4) {if (hd_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_4(TRACE_LAYER_HID, TRACE_TYPE_EVENT, m,p1,p2,p3,p4);}
+#define HIDD_TRACE_EVENT5(m,p1,p2,p3,p4,p5) {if (hd_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_5(TRACE_LAYER_HID, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5);}
+#define HIDD_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6) {if (hd_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_6(TRACE_LAYER_HID, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5,p6);}
+
+#define HIDD_TRACE_DEBUG0(m) {if (hd_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_0(TRACE_LAYER_HID, TRACE_TYPE_DEBUG, m);}
+#define HIDD_TRACE_DEBUG1(m,p1) {if (hd_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_1(TRACE_LAYER_HID, TRACE_TYPE_DEBUG, m,p1);}
+#define HIDD_TRACE_DEBUG2(m,p1,p2) {if (hd_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_2(TRACE_LAYER_HID, TRACE_TYPE_DEBUG, m,p1,p2);}
+#define HIDD_TRACE_DEBUG3(m,p1,p2,p3) {if (hd_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_3(TRACE_LAYER_HID, TRACE_TYPE_DEBUG, m,p1,p2,p3);}
+#define HIDD_TRACE_DEBUG4(m,p1,p2,p3,p4) {if (hd_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_4(TRACE_LAYER_HID, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4);}
+#define HIDD_TRACE_DEBUG5(m,p1,p2,p3,p4,p5) {if (hd_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_5(TRACE_LAYER_HID, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5);}
+#define HIDD_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) {if (hd_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_6(TRACE_LAYER_HID, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5,p6);}
+
+/* define traces for headset profile */
+#define HSP2_TRACE_ERROR0(pcb,m) {if (pcb->trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_0(TRACE_LAYER_HSP2, TRACE_TYPE_ERROR, m);}
+#define HSP2_TRACE_ERROR1(pcb,m,p1) {if (pcb->trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_1(TRACE_LAYER_HSP2, TRACE_TYPE_ERROR, m, p1);}
+#define HSP2_TRACE_ERROR2(pcb,m,p1,p2) {if (pcb->trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_2(TRACE_LAYER_HSP2, TRACE_TYPE_ERROR, m,p1,p2);}
+#define HSP2_TRACE_ERROR3(pcb,m,p1,p2,p3) {if (pcb->trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_3(TRACE_LAYER_HSP2, TRACE_TYPE_ERROR, m,p1,p2,p3);}
+#define HSP2_TRACE_ERROR4(pcb,m,p1,p2,p3,p4) {if (pcb->trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_4(TRACE_LAYER_HSP2, TRACE_TYPE_ERROR, m,p1,p2,p3,p4);}
+#define HSP2_TRACE_ERROR5(pcb,m,p1,p2,p3,p4,p5) {if (pcb->trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_5(TRACE_LAYER_HSP2, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5);}
+#define HSP2_TRACE_ERROR6(pcb,m,p1,p2,p3,p4,p5,p6) {if (pcb->trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_6(TRACE_LAYER_HSP2, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5,p6);}
+
+#define HSP2_TRACE_WARNING0(pcb,m) {if (pcb->trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_0(TRACE_LAYER_HSP2, TRACE_TYPE_WARNING, m);}
+#define HSP2_TRACE_WARNING1(pcb,m,p1) {if (pcb->trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_1(TRACE_LAYER_HSP2, TRACE_TYPE_WARNING, m,p1);}
+#define HSP2_TRACE_WARNING2(pcb,m,p1,p2) {if (pcb->trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_2(TRACE_LAYER_HSP2, TRACE_TYPE_WARNING, m,p1,p2);}
+#define HSP2_TRACE_WARNING3(pcb,m,p1,p2,p3) {if (pcb->trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_3(TRACE_LAYER_HSP2, TRACE_TYPE_WARNING, m,p1,p2,p3);}
+#define HSP2_TRACE_WARNING4(pcb,m,p1,p2,p3,p4) {if (pcb->trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_4(TRACE_LAYER_HSP2, TRACE_TYPE_WARNING, m,p1,p2,p3,p4);}
+#define HSP2_TRACE_WARNING5(pcb,m,p1,p2,p3,p4,p5) {if (pcb->trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_5(TRACE_LAYER_HSP2, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5);}
+#define HSP2_TRACE_WARNING6(pcb,m,p1,p2,p3,p4,p5,p6) {if (pcb->trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_6(TRACE_LAYER_HSP2, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5,p6);}
+
+#define HSP2_TRACE_API0(pcb,m) {if (pcb->trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_0(TRACE_LAYER_HSP2, TRACE_TYPE_API, m);}
+#define HSP2_TRACE_API1(pcb,m,p1) {if (pcb->trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_1(TRACE_LAYER_HSP2, TRACE_TYPE_API, m, p1);}
+#define HSP2_TRACE_API2(pcb,m,p1,p2) {if (pcb->trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_2(TRACE_LAYER_HSP2, TRACE_TYPE_API, m,p1,p2);}
+#define HSP2_TRACE_API3(pcb,m,p1,p2,p3) {if (pcb->trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_3(TRACE_LAYER_HSP2, TRACE_TYPE_API, m,p1,p2,p3);}
+#define HSP2_TRACE_API4(pcb,m,p1,p2,p3,p4) {if (pcb->trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_4(TRACE_LAYER_HSP2, TRACE_TYPE_API, m,p1,p2,p3,p4);}
+#define HSP2_TRACE_API5(pcb,m,p1,p2,p3,p4,p5) {if (pcb->trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_5(TRACE_LAYER_HSP2, TRACE_TYPE_API, m,p1,p2,p3,p4,p5);}
+#define HSP2_TRACE_API6(pcb,m,p1,p2,p3,p4,p5,p6) {if (pcb->trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_6(TRACE_LAYER_HSP2, TRACE_TYPE_API, m,p1,p2,p3,p4,p5,p6);}
+
+#define HSP2_TRACE_EVENT0(pcb,m) {if (pcb->trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_0(TRACE_LAYER_HSP2, TRACE_TYPE_EVENT, m);}
+#define HSP2_TRACE_EVENT1(pcb,m,p1) {if (pcb->trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_1(TRACE_LAYER_HSP2, TRACE_TYPE_EVENT, m, p1);}
+#define HSP2_TRACE_EVENT2(pcb,m,p1,p2) {if (pcb->trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_2(TRACE_LAYER_HSP2, TRACE_TYPE_EVENT, m,p1,p2);}
+#define HSP2_TRACE_EVENT3(pcb,m,p1,p2,p3) {if (pcb->trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_3(TRACE_LAYER_HSP2, TRACE_TYPE_EVENT, m,p1,p2,p3);}
+#define HSP2_TRACE_EVENT4(pcb,m,p1,p2,p3,p4) {if (pcb->trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_4(TRACE_LAYER_HSP2, TRACE_TYPE_EVENT, m,p1,p2,p3,p4);}
+#define HSP2_TRACE_EVENT5(pcb,m,p1,p2,p3,p4,p5) {if (pcb->trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_5(TRACE_LAYER_HSP2, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5);}
+#define HSP2_TRACE_EVENT6(pcb,m,p1,p2,p3,p4,p5,p6) {if (pcb->trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_6(TRACE_LAYER_HSP2, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5,p6);}
+
+#define HSP2_TRACE_DEBUG0(pcb,m) {if (pcb->trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_0(TRACE_LAYER_HSP2, TRACE_TYPE_DEBUG, m);}
+#define HSP2_TRACE_DEBUG1(pcb,m,p1) {if (pcb->trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_1(TRACE_LAYER_HSP2, TRACE_TYPE_DEBUG, m,p1);}
+#define HSP2_TRACE_DEBUG2(pcb,m,p1,p2) {if (pcb->trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_2(TRACE_LAYER_HSP2, TRACE_TYPE_DEBUG, m,p1,p2);}
+#define HSP2_TRACE_DEBUG3(pcb,m,p1,p2,p3) {if (pcb->trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_3(TRACE_LAYER_HSP2, TRACE_TYPE_DEBUG, m,p1,p2,p3);}
+#define HSP2_TRACE_DEBUG4(pcb,m,p1,p2,p3,p4) {if (pcb->trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_4(TRACE_LAYER_HSP2, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4);}
+#define HSP2_TRACE_DEBUG5(pcb,m,p1,p2,p3,p4,p5) {if (pcb->trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_5(TRACE_LAYER_HSP2, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5);}
+#define HSP2_TRACE_DEBUG6(pcb,m,p1,p2,p3,p4,p5,p6) {if (pcb->trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_6(TRACE_LAYER_HSP2, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5,p6);}
+
+/* Define tracing for the NFC unit
+*/
+#define NFC_TRACE_ERROR0(m) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_0(TRACE_LAYER_NFC, TRACE_TYPE_ERROR, m);}
+#define NFC_TRACE_ERROR1(m,p1) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_1(TRACE_LAYER_NFC, TRACE_TYPE_ERROR, m,p1);}
+#define NFC_TRACE_ERROR2(m,p1,p2) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_2(TRACE_LAYER_NFC, TRACE_TYPE_ERROR, m,p1,p2);}
+#define NFC_TRACE_ERROR3(m,p1,p2,p3) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_3(TRACE_LAYER_NFC, TRACE_TYPE_ERROR, m,p1,p2,p3);}
+#define NFC_TRACE_ERROR4(m,p1,p2,p3,p4) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_4(TRACE_LAYER_NFC, TRACE_TYPE_ERROR, m,p1,p2,p3,p4);}
+#define NFC_TRACE_ERROR5(m,p1,p2,p3,p4,p5) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_5(TRACE_LAYER_NFC, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5);}
+#define NFC_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_6(TRACE_LAYER_NFC, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5,p6);}
+
+#define NFC_TRACE_WARNING0(m) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_0(TRACE_LAYER_NFC, TRACE_TYPE_WARNING, m);}
+#define NFC_TRACE_WARNING1(m,p1) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_1(TRACE_LAYER_NFC, TRACE_TYPE_WARNING, m,p1);}
+#define NFC_TRACE_WARNING2(m,p1,p2) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_2(TRACE_LAYER_NFC, TRACE_TYPE_WARNING, m,p1,p2);}
+#define NFC_TRACE_WARNING3(m,p1,p2,p3) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_3(TRACE_LAYER_NFC, TRACE_TYPE_WARNING, m,p1,p2,p3);}
+#define NFC_TRACE_WARNING4(m,p1,p2,p3,p4) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_4(TRACE_LAYER_NFC, TRACE_TYPE_WARNING, m,p1,p2,p3,p4);}
+#define NFC_TRACE_WARNING5(m,p1,p2,p3,p4,p5) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_5(TRACE_LAYER_NFC, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5);}
+#define NFC_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_6(TRACE_LAYER_NFC, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5,p6);}
+
+#define NFC_TRACE_API0(m) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_0(TRACE_LAYER_NFC, TRACE_TYPE_API, m);}
+#define NFC_TRACE_API1(m,p1) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_1(TRACE_LAYER_NFC, TRACE_TYPE_API, m,p1);}
+#define NFC_TRACE_API2(m,p1,p2) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_2(TRACE_LAYER_NFC, TRACE_TYPE_API, m,p1,p2);}
+#define NFC_TRACE_API3(m,p1,p2,p3) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_3(TRACE_LAYER_NFC, TRACE_TYPE_API, m,p1,p2,p3);}
+#define NFC_TRACE_API4(m,p1,p2,p3,p4) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_4(TRACE_LAYER_NFC, TRACE_TYPE_API, m,p1,p2,p3,p4);}
+#define NFC_TRACE_API5(m,p1,p2,p3,p4,p5) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_5(TRACE_LAYER_NFC, TRACE_TYPE_API, m,p1,p2,p3,p4,p5);}
+#define NFC_TRACE_API6(m,p1,p2,p3,p4,p5,p6) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_6(TRACE_LAYER_NFC, TRACE_TYPE_API, m,p1,p2,p3,p4,p5,p6);}
+
+#define NFC_TRACE_EVENT0(m) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_0(TRACE_LAYER_NFC, TRACE_TYPE_EVENT, m);}
+#define NFC_TRACE_EVENT1(m,p1) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_1(TRACE_LAYER_NFC, TRACE_TYPE_EVENT, m, p1);}
+#define NFC_TRACE_EVENT2(m,p1,p2) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_2(TRACE_LAYER_NFC, TRACE_TYPE_EVENT, m,p1,p2);}
+#define NFC_TRACE_EVENT3(m,p1,p2,p3) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_3(TRACE_LAYER_NFC, TRACE_TYPE_EVENT, m,p1,p2,p3);}
+#define NFC_TRACE_EVENT4(m,p1,p2,p3,p4) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_4(TRACE_LAYER_NFC, TRACE_TYPE_EVENT, m,p1,p2,p3,p4);}
+#define NFC_TRACE_EVENT5(m,p1,p2,p3,p4,p5) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_5(TRACE_LAYER_NFC, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5);}
+#define NFC_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_6(TRACE_LAYER_NFC, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5,p6);}
+
+#define NFC_TRACE_DEBUG0(m) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_0(TRACE_LAYER_NFC, TRACE_TYPE_DEBUG, m);}
+#define NFC_TRACE_DEBUG1(m,p1) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_1(TRACE_LAYER_NFC, TRACE_TYPE_DEBUG, m,p1);}
+#define NFC_TRACE_DEBUG2(m,p1,p2) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_2(TRACE_LAYER_NFC, TRACE_TYPE_DEBUG, m,p1,p2);}
+#define NFC_TRACE_DEBUG3(m,p1,p2,p3) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_3(TRACE_LAYER_NFC, TRACE_TYPE_DEBUG, m,p1,p2,p3);}
+#define NFC_TRACE_DEBUG4(m,p1,p2,p3,p4) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_4(TRACE_LAYER_NFC, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4);}
+#define NFC_TRACE_DEBUG5(m,p1,p2,p3,p4,p5) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_5(TRACE_LAYER_NFC, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5);}
+#define NFC_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_6(TRACE_LAYER_NFC, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5,p6);}
+
+#define NCI_TRACE_ERROR0(m) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_0(TRACE_LAYER_NCI, TRACE_TYPE_ERROR, m);}
+#define NCI_TRACE_ERROR1(m,p1) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_1(TRACE_LAYER_NCI, TRACE_TYPE_ERROR, m,p1);}
+#define NCI_TRACE_ERROR2(m,p1,p2) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_2(TRACE_LAYER_NCI, TRACE_TYPE_ERROR, m,p1,p2);}
+#define NCI_TRACE_ERROR3(m,p1,p2,p3) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_3(TRACE_LAYER_NCI, TRACE_TYPE_ERROR, m,p1,p2,p3);}
+#define NCI_TRACE_ERROR4(m,p1,p2,p3,p4) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_4(TRACE_LAYER_NCI, TRACE_TYPE_ERROR, m,p1,p2,p3,p4);}
+#define NCI_TRACE_ERROR5(m,p1,p2,p3,p4,p5) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_5(TRACE_LAYER_NCI, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5);}
+#define NCI_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_6(TRACE_LAYER_NCI, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5,p6);}
+
+#define NCI_TRACE_WARNING0(m) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_0(TRACE_LAYER_NCI, TRACE_TYPE_WARNING, m);}
+#define NCI_TRACE_WARNING1(m,p1) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_1(TRACE_LAYER_NCI, TRACE_TYPE_WARNING, m,p1);}
+#define NCI_TRACE_WARNING2(m,p1,p2) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_2(TRACE_LAYER_NCI, TRACE_TYPE_WARNING, m,p1,p2);}
+#define NCI_TRACE_WARNING3(m,p1,p2,p3) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_3(TRACE_LAYER_NCI, TRACE_TYPE_WARNING, m,p1,p2,p3);}
+#define NCI_TRACE_WARNING4(m,p1,p2,p3,p4) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_4(TRACE_LAYER_NCI, TRACE_TYPE_WARNING, m,p1,p2,p3,p4);}
+#define NCI_TRACE_WARNING5(m,p1,p2,p3,p4,p5) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_5(TRACE_LAYER_NCI, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5);}
+#define NCI_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_6(TRACE_LAYER_NCI, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5,p6);}
+
+#define NCI_TRACE_API0(m) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_0(TRACE_LAYER_NCI, TRACE_TYPE_API, m);}
+#define NCI_TRACE_API1(m,p1) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_1(TRACE_LAYER_NCI, TRACE_TYPE_API, m,p1);}
+#define NCI_TRACE_API2(m,p1,p2) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_2(TRACE_LAYER_NCI, TRACE_TYPE_API, m,p1,p2);}
+#define NCI_TRACE_API3(m,p1,p2,p3) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_3(TRACE_LAYER_NCI, TRACE_TYPE_API, m,p1,p2,p3);}
+#define NCI_TRACE_API4(m,p1,p2,p3,p4) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_4(TRACE_LAYER_NCI, TRACE_TYPE_API, m,p1,p2,p3,p4);}
+#define NCI_TRACE_API5(m,p1,p2,p3,p4,p5) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_5(TRACE_LAYER_NCI, TRACE_TYPE_API, m,p1,p2,p3,p4,p5);}
+#define NCI_TRACE_API6(m,p1,p2,p3,p4,p5,p6) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_6(TRACE_LAYER_NCI, TRACE_TYPE_API, m,p1,p2,p3,p4,p5,p6);}
+
+#define NCI_TRACE_EVENT0(m) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_0(TRACE_LAYER_NCI, TRACE_TYPE_EVENT, m);}
+#define NCI_TRACE_EVENT1(m,p1) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_1(TRACE_LAYER_NCI, TRACE_TYPE_EVENT, m, p1);}
+#define NCI_TRACE_EVENT2(m,p1,p2) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_2(TRACE_LAYER_NCI, TRACE_TYPE_EVENT, m,p1,p2);}
+#define NCI_TRACE_EVENT3(m,p1,p2,p3) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_3(TRACE_LAYER_NCI, TRACE_TYPE_EVENT, m,p1,p2,p3);}
+#define NCI_TRACE_EVENT4(m,p1,p2,p3,p4) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_4(TRACE_LAYER_NCI, TRACE_TYPE_EVENT, m,p1,p2,p3,p4);}
+#define NCI_TRACE_EVENT5(m,p1,p2,p3,p4,p5) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_5(TRACE_LAYER_NCI, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5);}
+#define NCI_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_6(TRACE_LAYER_NCI, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5,p6);}
+
+#define NCI_TRACE_DEBUG0(m) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_0(TRACE_LAYER_NCI, TRACE_TYPE_DEBUG, m);}
+#define NCI_TRACE_DEBUG1(m,p1) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_1(TRACE_LAYER_NCI, TRACE_TYPE_DEBUG, m,p1);}
+#define NCI_TRACE_DEBUG2(m,p1,p2) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_2(TRACE_LAYER_NCI, TRACE_TYPE_DEBUG, m,p1,p2);}
+#define NCI_TRACE_DEBUG3(m,p1,p2,p3) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_3(TRACE_LAYER_NCI, TRACE_TYPE_DEBUG, m,p1,p2,p3);}
+#define NCI_TRACE_DEBUG4(m,p1,p2,p3,p4) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_4(TRACE_LAYER_NCI, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4);}
+#define NCI_TRACE_DEBUG5(m,p1,p2,p3,p4,p5) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_5(TRACE_LAYER_NCI, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5);}
+#define NCI_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) {if (nfc_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_6(TRACE_LAYER_NCI, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5,p6);}
+
+#define RW_TRACE_ERROR0(m) {if (rw_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_0(TRACE_LAYER_RW, TRACE_TYPE_ERROR, m);}
+#define RW_TRACE_ERROR1(m,p1) {if (rw_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_1(TRACE_LAYER_RW, TRACE_TYPE_ERROR, m,p1);}
+#define RW_TRACE_ERROR2(m,p1,p2) {if (rw_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_2(TRACE_LAYER_RW, TRACE_TYPE_ERROR, m,p1,p2);}
+#define RW_TRACE_ERROR3(m,p1,p2,p3) {if (rw_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_3(TRACE_LAYER_RW, TRACE_TYPE_ERROR, m,p1,p2,p3);}
+#define RW_TRACE_ERROR4(m,p1,p2,p3,p4) {if (rw_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_4(TRACE_LAYER_RW, TRACE_TYPE_ERROR, m,p1,p2,p3,p4);}
+#define RW_TRACE_ERROR5(m,p1,p2,p3,p4,p5) {if (rw_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_5(TRACE_LAYER_RW, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5);}
+#define RW_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6) {if (rw_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_6(TRACE_LAYER_RW, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5,p6);}
+
+#define RW_TRACE_WARNING0(m) {if (rw_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_0(TRACE_LAYER_RW, TRACE_TYPE_WARNING, m);}
+#define RW_TRACE_WARNING1(m,p1) {if (rw_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_1(TRACE_LAYER_RW, TRACE_TYPE_WARNING, m,p1);}
+#define RW_TRACE_WARNING2(m,p1,p2) {if (rw_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_2(TRACE_LAYER_RW, TRACE_TYPE_WARNING, m,p1,p2);}
+#define RW_TRACE_WARNING3(m,p1,p2,p3) {if (rw_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_3(TRACE_LAYER_RW, TRACE_TYPE_WARNING, m,p1,p2,p3);}
+#define RW_TRACE_WARNING4(m,p1,p2,p3,p4) {if (rw_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_4(TRACE_LAYER_RW, TRACE_TYPE_WARNING, m,p1,p2,p3,p4);}
+#define RW_TRACE_WARNING5(m,p1,p2,p3,p4,p5) {if (rw_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_5(TRACE_LAYER_RW, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5);}
+#define RW_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6) {if (rw_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_6(TRACE_LAYER_RW, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5,p6);}
+
+#define RW_TRACE_API0(m) {if (rw_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_0(TRACE_LAYER_RW, TRACE_TYPE_API, m);}
+#define RW_TRACE_API1(m,p1) {if (rw_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_1(TRACE_LAYER_RW, TRACE_TYPE_API, m,p1);}
+#define RW_TRACE_API2(m,p1,p2) {if (rw_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_2(TRACE_LAYER_RW, TRACE_TYPE_API, m,p1,p2);}
+#define RW_TRACE_API3(m,p1,p2,p3) {if (rw_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_3(TRACE_LAYER_RW, TRACE_TYPE_API, m,p1,p2,p3);}
+#define RW_TRACE_API4(m,p1,p2,p3,p4) {if (rw_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_4(TRACE_LAYER_RW, TRACE_TYPE_API, m,p1,p2,p3,p4);}
+#define RW_TRACE_API5(m,p1,p2,p3,p4,p5) {if (rw_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_5(TRACE_LAYER_RW, TRACE_TYPE_API, m,p1,p2,p3,p4,p5);}
+#define RW_TRACE_API6(m,p1,p2,p3,p4,p5,p6) {if (rw_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_6(TRACE_LAYER_RW, TRACE_TYPE_API, m,p1,p2,p3,p4,p5,p6);}
+
+#define RW_TRACE_EVENT0(m) {if (rw_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_0(TRACE_LAYER_RW, TRACE_TYPE_EVENT, m);}
+#define RW_TRACE_EVENT1(m,p1) {if (rw_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_1(TRACE_LAYER_RW, TRACE_TYPE_EVENT, m, p1);}
+#define RW_TRACE_EVENT2(m,p1,p2) {if (rw_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_2(TRACE_LAYER_RW, TRACE_TYPE_EVENT, m,p1,p2);}
+#define RW_TRACE_EVENT3(m,p1,p2,p3) {if (rw_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_3(TRACE_LAYER_RW, TRACE_TYPE_EVENT, m,p1,p2,p3);}
+#define RW_TRACE_EVENT4(m,p1,p2,p3,p4) {if (rw_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_4(TRACE_LAYER_RW, TRACE_TYPE_EVENT, m,p1,p2,p3,p4);}
+#define RW_TRACE_EVENT5(m,p1,p2,p3,p4,p5) {if (rw_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_5(TRACE_LAYER_RW, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5);}
+#define RW_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6) {if (rw_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_6(TRACE_LAYER_RW, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5,p6);}
+
+#define RW_TRACE_DEBUG0(m) {if (rw_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_0(TRACE_LAYER_RW, TRACE_TYPE_DEBUG, m);}
+#define RW_TRACE_DEBUG1(m,p1) {if (rw_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_1(TRACE_LAYER_RW, TRACE_TYPE_DEBUG, m,p1);}
+#define RW_TRACE_DEBUG2(m,p1,p2) {if (rw_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_2(TRACE_LAYER_RW, TRACE_TYPE_DEBUG, m,p1,p2);}
+#define RW_TRACE_DEBUG3(m,p1,p2,p3) {if (rw_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_3(TRACE_LAYER_RW, TRACE_TYPE_DEBUG, m,p1,p2,p3);}
+#define RW_TRACE_DEBUG4(m,p1,p2,p3,p4) {if (rw_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_4(TRACE_LAYER_RW, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4);}
+#define RW_TRACE_DEBUG5(m,p1,p2,p3,p4,p5) {if (rw_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_5(TRACE_LAYER_RW, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5);}
+#define RW_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) {if (rw_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_6(TRACE_LAYER_RW, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5,p6);}
+
+#define CE_TRACE_ERROR0(m) {if (ce_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_0(TRACE_LAYER_CE, TRACE_TYPE_ERROR, m);}
+#define CE_TRACE_ERROR1(m,p1) {if (ce_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_1(TRACE_LAYER_CE, TRACE_TYPE_ERROR, m,p1);}
+#define CE_TRACE_ERROR2(m,p1,p2) {if (ce_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_2(TRACE_LAYER_CE, TRACE_TYPE_ERROR, m,p1,p2);}
+#define CE_TRACE_ERROR3(m,p1,p2,p3) {if (ce_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_3(TRACE_LAYER_CE, TRACE_TYPE_ERROR, m,p1,p2,p3);}
+#define CE_TRACE_ERROR4(m,p1,p2,p3,p4) {if (ce_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_4(TRACE_LAYER_CE, TRACE_TYPE_ERROR, m,p1,p2,p3,p4);}
+#define CE_TRACE_ERROR5(m,p1,p2,p3,p4,p5) {if (ce_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_5(TRACE_LAYER_CE, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5);}
+#define CE_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6) {if (ce_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_6(TRACE_LAYER_CE, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5,p6);}
+
+#define CE_TRACE_WARNING0(m) {if (ce_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_0(TRACE_LAYER_CE, TRACE_TYPE_WARNING, m);}
+#define CE_TRACE_WARNING1(m,p1) {if (ce_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_1(TRACE_LAYER_CE, TRACE_TYPE_WARNING, m,p1);}
+#define CE_TRACE_WARNING2(m,p1,p2) {if (ce_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_2(TRACE_LAYER_CE, TRACE_TYPE_WARNING, m,p1,p2);}
+#define CE_TRACE_WARNING3(m,p1,p2,p3) {if (ce_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_3(TRACE_LAYER_CE, TRACE_TYPE_WARNING, m,p1,p2,p3);}
+#define CE_TRACE_WARNING4(m,p1,p2,p3,p4) {if (ce_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_4(TRACE_LAYER_CE, TRACE_TYPE_WARNING, m,p1,p2,p3,p4);}
+#define CE_TRACE_WARNING5(m,p1,p2,p3,p4,p5) {if (ce_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_5(TRACE_LAYER_CE, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5);}
+#define CE_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6) {if (ce_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_6(TRACE_LAYER_CE, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5,p6);}
+
+#define CE_TRACE_API0(m) {if (ce_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_0(TRACE_LAYER_CE, TRACE_TYPE_API, m);}
+#define CE_TRACE_API1(m,p1) {if (ce_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_1(TRACE_LAYER_CE, TRACE_TYPE_API, m,p1);}
+#define CE_TRACE_API2(m,p1,p2) {if (ce_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_2(TRACE_LAYER_CE, TRACE_TYPE_API, m,p1,p2);}
+#define CE_TRACE_API3(m,p1,p2,p3) {if (ce_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_3(TRACE_LAYER_CE, TRACE_TYPE_API, m,p1,p2,p3);}
+#define CE_TRACE_API4(m,p1,p2,p3,p4) {if (ce_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_4(TRACE_LAYER_CE, TRACE_TYPE_API, m,p1,p2,p3,p4);}
+#define CE_TRACE_API5(m,p1,p2,p3,p4,p5) {if (ce_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_5(TRACE_LAYER_CE, TRACE_TYPE_API, m,p1,p2,p3,p4,p5);}
+#define CE_TRACE_API6(m,p1,p2,p3,p4,p5,p6) {if (ce_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_6(TRACE_LAYER_CE, TRACE_TYPE_API, m,p1,p2,p3,p4,p5,p6);}
+
+#define CE_TRACE_EVENT0(m) {if (ce_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_0(TRACE_LAYER_CE, TRACE_TYPE_EVENT, m);}
+#define CE_TRACE_EVENT1(m,p1) {if (ce_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_1(TRACE_LAYER_CE, TRACE_TYPE_EVENT, m, p1);}
+#define CE_TRACE_EVENT2(m,p1,p2) {if (ce_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_2(TRACE_LAYER_CE, TRACE_TYPE_EVENT, m,p1,p2);}
+#define CE_TRACE_EVENT3(m,p1,p2,p3) {if (ce_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_3(TRACE_LAYER_CE, TRACE_TYPE_EVENT, m,p1,p2,p3);}
+#define CE_TRACE_EVENT4(m,p1,p2,p3,p4) {if (ce_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_4(TRACE_LAYER_CE, TRACE_TYPE_EVENT, m,p1,p2,p3,p4);}
+#define CE_TRACE_EVENT5(m,p1,p2,p3,p4,p5) {if (ce_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_5(TRACE_LAYER_CE, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5);}
+#define CE_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6) {if (ce_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_6(TRACE_LAYER_CE, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5,p6);}
+
+#define CE_TRACE_DEBUG0(m) {if (ce_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_0(TRACE_LAYER_CE, TRACE_TYPE_DEBUG, m);}
+#define CE_TRACE_DEBUG1(m,p1) {if (ce_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_1(TRACE_LAYER_CE, TRACE_TYPE_DEBUG, m,p1);}
+#define CE_TRACE_DEBUG2(m,p1,p2) {if (ce_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_2(TRACE_LAYER_CE, TRACE_TYPE_DEBUG, m,p1,p2);}
+#define CE_TRACE_DEBUG3(m,p1,p2,p3) {if (ce_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_3(TRACE_LAYER_CE, TRACE_TYPE_DEBUG, m,p1,p2,p3);}
+#define CE_TRACE_DEBUG4(m,p1,p2,p3,p4) {if (ce_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_4(TRACE_LAYER_CE, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4);}
+#define CE_TRACE_DEBUG5(m,p1,p2,p3,p4,p5) {if (ce_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_5(TRACE_LAYER_CE, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5);}
+#define CE_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) {if (ce_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_6(TRACE_LAYER_CE, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5,p6);}
+
+#define NDEF_TRACE_ERROR0(m) {if (ndef_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_0(TRACE_LAYER_NDEF, TRACE_TYPE_ERROR, m);}
+#define NDEF_TRACE_ERROR1(m,p1) {if (ndef_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_1(TRACE_LAYER_NDEF, TRACE_TYPE_ERROR, m,p1);}
+#define NDEF_TRACE_ERROR2(m,p1,p2) {if (ndef_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_2(TRACE_LAYER_NDEF, TRACE_TYPE_ERROR, m,p1,p2);}
+#define NDEF_TRACE_ERROR3(m,p1,p2,p3) {if (ndef_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_3(TRACE_LAYER_NDEF, TRACE_TYPE_ERROR, m,p1,p2,p3);}
+#define NDEF_TRACE_ERROR4(m,p1,p2,p3,p4) {if (ndef_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_4(TRACE_LAYER_NDEF, TRACE_TYPE_ERROR, m,p1,p2,p3,p4);}
+#define NDEF_TRACE_ERROR5(m,p1,p2,p3,p4,p5) {if (ndef_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_5(TRACE_LAYER_NDEF, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5);}
+#define NDEF_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6) {if (ndef_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_6(TRACE_LAYER_NDEF, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5,p6);}
+
+#define NDEF_TRACE_WARNING0(m) {if (ndef_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_0(TRACE_LAYER_NDEF, TRACE_TYPE_WARNING, m);}
+#define NDEF_TRACE_WARNING1(m,p1) {if (ndef_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_1(TRACE_LAYER_NDEF, TRACE_TYPE_WARNING, m,p1);}
+#define NDEF_TRACE_WARNING2(m,p1,p2) {if (ndef_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_2(TRACE_LAYER_NDEF, TRACE_TYPE_WARNING, m,p1,p2);}
+#define NDEF_TRACE_WARNING3(m,p1,p2,p3) {if (ndef_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_3(TRACE_LAYER_NDEF, TRACE_TYPE_WARNING, m,p1,p2,p3);}
+#define NDEF_TRACE_WARNING4(m,p1,p2,p3,p4) {if (ndef_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_4(TRACE_LAYER_NDEF, TRACE_TYPE_WARNING, m,p1,p2,p3,p4);}
+#define NDEF_TRACE_WARNING5(m,p1,p2,p3,p4,p5) {if (ndef_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_5(TRACE_LAYER_NDEF, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5);}
+#define NDEF_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6) {if (ndef_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_6(TRACE_LAYER_NDEF, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5,p6);}
+
+#define NDEF_TRACE_API0(m) {if (ndef_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_0(TRACE_LAYER_NDEF, TRACE_TYPE_API, m);}
+#define NDEF_TRACE_API1(m,p1) {if (ndef_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_1(TRACE_LAYER_NDEF, TRACE_TYPE_API, m,p1);}
+#define NDEF_TRACE_API2(m,p1,p2) {if (ndef_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_2(TRACE_LAYER_NDEF, TRACE_TYPE_API, m,p1,p2);}
+#define NDEF_TRACE_API3(m,p1,p2,p3) {if (ndef_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_3(TRACE_LAYER_NDEF, TRACE_TYPE_API, m,p1,p2,p3);}
+#define NDEF_TRACE_API4(m,p1,p2,p3,p4) {if (ndef_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_4(TRACE_LAYER_NDEF, TRACE_TYPE_API, m,p1,p2,p3,p4);}
+#define NDEF_TRACE_API5(m,p1,p2,p3,p4,p5) {if (ndef_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_5(TRACE_LAYER_NDEF, TRACE_TYPE_API, m,p1,p2,p3,p4,p5);}
+#define NDEF_TRACE_API6(m,p1,p2,p3,p4,p5,p6) {if (ndef_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_6(TRACE_LAYER_NDEF, TRACE_TYPE_API, m,p1,p2,p3,p4,p5,p6);}
+
+#define NDEF_TRACE_EVENT0(m) {if (ndef_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_0(TRACE_LAYER_NDEF, TRACE_TYPE_EVENT, m);}
+#define NDEF_TRACE_EVENT1(m,p1) {if (ndef_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_1(TRACE_LAYER_NDEF, TRACE_TYPE_EVENT, m, p1);}
+#define NDEF_TRACE_EVENT2(m,p1,p2) {if (ndef_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_2(TRACE_LAYER_NDEF, TRACE_TYPE_EVENT, m,p1,p2);}
+#define NDEF_TRACE_EVENT3(m,p1,p2,p3) {if (ndef_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_3(TRACE_LAYER_NDEF, TRACE_TYPE_EVENT, m,p1,p2,p3);}
+#define NDEF_TRACE_EVENT4(m,p1,p2,p3,p4) {if (ndef_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_4(TRACE_LAYER_NDEF, TRACE_TYPE_EVENT, m,p1,p2,p3,p4);}
+#define NDEF_TRACE_EVENT5(m,p1,p2,p3,p4,p5) {if (ndef_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_5(TRACE_LAYER_NDEF, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5);}
+#define NDEF_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6) {if (ndef_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_6(TRACE_LAYER_NDEF, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5,p6);}
+
+#define NDEF_TRACE_DEBUG0(m) {if (ndef_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_0(TRACE_LAYER_NDEF, TRACE_TYPE_DEBUG, m);}
+#define NDEF_TRACE_DEBUG1(m,p1) {if (ndef_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_1(TRACE_LAYER_NDEF, TRACE_TYPE_DEBUG, m,p1);}
+#define NDEF_TRACE_DEBUG2(m,p1,p2) {if (ndef_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_2(TRACE_LAYER_NDEF, TRACE_TYPE_DEBUG, m,p1,p2);}
+#define NDEF_TRACE_DEBUG3(m,p1,p2,p3) {if (ndef_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_3(TRACE_LAYER_NDEF, TRACE_TYPE_DEBUG, m,p1,p2,p3);}
+#define NDEF_TRACE_DEBUG4(m,p1,p2,p3,p4) {if (ndef_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_4(TRACE_LAYER_NDEF, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4);}
+#define NDEF_TRACE_DEBUG5(m,p1,p2,p3,p4,p5) {if (ndef_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_5(TRACE_LAYER_NDEF, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5);}
+#define NDEF_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) {if (ndef_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_6(TRACE_LAYER_NDEF, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5,p6);}
+
+/* Define tracing for the NFA unit
+*/
+#define NFA_TRACE_ERROR0(m) {if (nfa_sys_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_0(TRACE_LAYER_NFA, TRACE_TYPE_ERROR, m);}
+#define NFA_TRACE_ERROR1(m,p1) {if (nfa_sys_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_1(TRACE_LAYER_NFA, TRACE_TYPE_ERROR, m,p1);}
+#define NFA_TRACE_ERROR2(m,p1,p2) {if (nfa_sys_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_2(TRACE_LAYER_NFA, TRACE_TYPE_ERROR, m,p1,p2);}
+#define NFA_TRACE_ERROR3(m,p1,p2,p3) {if (nfa_sys_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_3(TRACE_LAYER_NFA, TRACE_TYPE_ERROR, m,p1,p2,p3);}
+#define NFA_TRACE_ERROR4(m,p1,p2,p3,p4) {if (nfa_sys_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_4(TRACE_LAYER_NFA, TRACE_TYPE_ERROR, m,p1,p2,p3,p4);}
+#define NFA_TRACE_ERROR5(m,p1,p2,p3,p4,p5) {if (nfa_sys_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_5(TRACE_LAYER_NFA, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5);}
+#define NFA_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6) {if (nfa_sys_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_6(TRACE_LAYER_NFA, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5,p6);}
+
+#define NFA_TRACE_WARNING0(m) {if (nfa_sys_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_0(TRACE_LAYER_NFA, TRACE_TYPE_WARNING, m);}
+#define NFA_TRACE_WARNING1(m,p1) {if (nfa_sys_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_1(TRACE_LAYER_NFA, TRACE_TYPE_WARNING, m,p1);}
+#define NFA_TRACE_WARNING2(m,p1,p2) {if (nfa_sys_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_2(TRACE_LAYER_NFA, TRACE_TYPE_WARNING, m,p1,p2);}
+#define NFA_TRACE_WARNING3(m,p1,p2,p3) {if (nfa_sys_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_3(TRACE_LAYER_NFA, TRACE_TYPE_WARNING, m,p1,p2,p3);}
+#define NFA_TRACE_WARNING4(m,p1,p2,p3,p4) {if (nfa_sys_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_4(TRACE_LAYER_NFA, TRACE_TYPE_WARNING, m,p1,p2,p3,p4);}
+#define NFA_TRACE_WARNING5(m,p1,p2,p3,p4,p5) {if (nfa_sys_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_5(TRACE_LAYER_NFA, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5);}
+#define NFA_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6) {if (nfa_sys_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_6(TRACE_LAYER_NFA, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5,p6);}
+
+#define NFA_TRACE_API0(m) {if (nfa_sys_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_0(TRACE_LAYER_NFA, TRACE_TYPE_API, m);}
+#define NFA_TRACE_API1(m,p1) {if (nfa_sys_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_1(TRACE_LAYER_NFA, TRACE_TYPE_API, m,p1);}
+#define NFA_TRACE_API2(m,p1,p2) {if (nfa_sys_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_2(TRACE_LAYER_NFA, TRACE_TYPE_API, m,p1,p2);}
+#define NFA_TRACE_API3(m,p1,p2,p3) {if (nfa_sys_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_3(TRACE_LAYER_NFA, TRACE_TYPE_API, m,p1,p2,p3);}
+#define NFA_TRACE_API4(m,p1,p2,p3,p4) {if (nfa_sys_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_4(TRACE_LAYER_NFA, TRACE_TYPE_API, m,p1,p2,p3,p4);}
+#define NFA_TRACE_API5(m,p1,p2,p3,p4,p5) {if (nfa_sys_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_5(TRACE_LAYER_NFA, TRACE_TYPE_API, m,p1,p2,p3,p4,p5);}
+#define NFA_TRACE_API6(m,p1,p2,p3,p4,p5,p6) {if (nfa_sys_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_6(TRACE_LAYER_NFA, TRACE_TYPE_API, m,p1,p2,p3,p4,p5,p6);}
+
+#define NFA_TRACE_EVENT0(m) {if (nfa_sys_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_0(TRACE_LAYER_NFA, TRACE_TYPE_EVENT, m);}
+#define NFA_TRACE_EVENT1(m,p1) {if (nfa_sys_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_1(TRACE_LAYER_NFA, TRACE_TYPE_EVENT, m, p1);}
+#define NFA_TRACE_EVENT2(m,p1,p2) {if (nfa_sys_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_2(TRACE_LAYER_NFA, TRACE_TYPE_EVENT, m,p1,p2);}
+#define NFA_TRACE_EVENT3(m,p1,p2,p3) {if (nfa_sys_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_3(TRACE_LAYER_NFA, TRACE_TYPE_EVENT, m,p1,p2,p3);}
+#define NFA_TRACE_EVENT4(m,p1,p2,p3,p4) {if (nfa_sys_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_4(TRACE_LAYER_NFA, TRACE_TYPE_EVENT, m,p1,p2,p3,p4);}
+#define NFA_TRACE_EVENT5(m,p1,p2,p3,p4,p5) {if (nfa_sys_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_5(TRACE_LAYER_NFA, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5);}
+#define NFA_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6) {if (nfa_sys_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_6(TRACE_LAYER_NFA, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5,p6);}
+
+#define NFA_TRACE_DEBUG0(m) {if (nfa_sys_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_0(TRACE_LAYER_NFA, TRACE_TYPE_DEBUG, m);}
+#define NFA_TRACE_DEBUG1(m,p1) {if (nfa_sys_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_1(TRACE_LAYER_NFA, TRACE_TYPE_DEBUG, m,p1);}
+#define NFA_TRACE_DEBUG2(m,p1,p2) {if (nfa_sys_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_2(TRACE_LAYER_NFA, TRACE_TYPE_DEBUG, m,p1,p2);}
+#define NFA_TRACE_DEBUG3(m,p1,p2,p3) {if (nfa_sys_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_3(TRACE_LAYER_NFA, TRACE_TYPE_DEBUG, m,p1,p2,p3);}
+#define NFA_TRACE_DEBUG4(m,p1,p2,p3,p4) {if (nfa_sys_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_4(TRACE_LAYER_NFA, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4);}
+#define NFA_TRACE_DEBUG5(m,p1,p2,p3,p4,p5) {if (nfa_sys_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_5(TRACE_LAYER_NFA, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5);}
+#define NFA_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) {if (nfa_sys_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_6(TRACE_LAYER_NFA, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5,p6);}
+
+#define MMI_TRACE_0(m)
+#define MMI_TRACE_1(m,p1)
+#define MMI_TRACE_2(m,p1,p2)
+#define MMI_TRACE_3(m,p1,p2,p3)
+#define MMI_TRACE_4(m,p1,p2,p3,p4)
+#define MMI_TRACE_5(m,p1,p2,p3,p4,p5)
+#define MMI_TRACE_6(m,p1,p2,p3,p4,p5,p6)
+
+#define MMI_DEBUG_0(m) BT_TRACE_0(TRACE_LAYER_HID, TRACE_TYPE_DEBUG, m)
+#define MMI_DEBUG_1(m,p1) BT_TRACE_1(TRACE_LAYER_HID, TRACE_TYPE_DEBUG, m,p1)
+#define MMI_DEBUG_2(m,p1,p2) BT_TRACE_2(TRACE_LAYER_HID, TRACE_TYPE_DEBUG, m,p1,p2)
+#define MMI_DEBUG_3(m,p1,p2,p3) BT_TRACE_3(TRACE_LAYER_HID, TRACE_TYPE_DEBUG, m,p1,p2,p3)
+#define MMI_DEBUG_4(m,p1,p2,p3,p4) BT_TRACE_4(TRACE_LAYER_HID, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4)
+#define MMI_DEBUG_5(m,p1,p2,p3,p4,p5) BT_TRACE_5(TRACE_LAYER_HID, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5)
+#define MMI_DEBUG_6(m,p1,p2,p3,p4,p5,p6) BT_TRACE_6(TRACE_LAYER_HID, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5,p6)
+
+#define MMI_WARNING_0(m) BT_TRACE_0(TRACE_LAYER_HID, TRACE_TYPE_WARNING, m)
+#define MMI_WARNING_1(m,p1) BT_TRACE_1(TRACE_LAYER_HID, TRACE_TYPE_WARNING, m,p1)
+#define MMI_WARNING_2(m,p1,p2) BT_TRACE_2(TRACE_LAYER_HID, TRACE_TYPE_WARNING, m,p1,p2)
+#define MMI_WARNING_3(m,p1,p2,p3) BT_TRACE_3(TRACE_LAYER_HID, TRACE_TYPE_WARNING, m,p1,p2,p3)
+#define MMI_WARNING_4(m,p1,p2,p3,p4) BT_TRACE_4(TRACE_LAYER_HID, TRACE_TYPE_WARNING, m,p1,p2,p3,p4)
+#define MMI_WARNING_5(m,p1,p2,p3,p4,p5) BT_TRACE_5(TRACE_LAYER_HID, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5)
+#define MMI_WARNING_6(m,p1,p2,p3,p4,p5,p6) BT_TRACE_6(TRACE_LAYER_HID, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5,p6)
+
+#define MMI_ERROR_0(m) BT_TRACE_0(TRACE_LAYER_HID, TRACE_TYPE_ERROR, m)
+#define MMI_ERROR_1(m,p1) BT_TRACE_1(TRACE_LAYER_HID, TRACE_TYPE_ERROR, m,p1)
+#define MMI_ERROR_2(m,p1,p2) BT_TRACE_2(TRACE_LAYER_HID, TRACE_TYPE_ERROR, m,p1,p2)
+#define MMI_ERROR_3(m,p1,p2,p3) BT_TRACE_3(TRACE_LAYER_HID, TRACE_TYPE_ERROR, m,p1,p2,p3)
+#define MMI_ERROR_4(m,p1,p2,p3,p4) BT_TRACE_4(TRACE_LAYER_HID, TRACE_TYPE_ERROR, m,p1,p2,p3,p4)
+#define MMI_ERROR_5(m,p1,p2,p3,p4,p5) BT_TRACE_5(TRACE_LAYER_HID, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5)
+#define MMI_ERROR_6(m,p1,p2,p3,p4,p5,p6) BT_TRACE_6(TRACE_LAYER_HID, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5,p6)
+
+#define TAK_TRACE_0(m) MMI_Echo(m)
+
+/* hid mouse module traces */
+
+#define MSKB_TRACE_0(m) MMI_Echo(m)
+#define MSKB_TRACE_1(m,p1) MMI_Echo(m,p1)
+#define MSKB_TRACE_2(m,p1,p2) MMI_Echo(m,p1,p2)
+#define MSKB_TRACE_3(m,p1,p2,p3) MMI_Echo(m,p1,p2,p3)
+#define MSKB_TRACE_4(m,p1,p2,p3,p4) MMI_Echo(m,p1,p2,p3,p4)
+#define MSKB_TRACE_5(m,p1,p2,p3,p4,p5) MMI_Echo(m,p1,p2,p3,p4,p5)
+#define MSKB_TRACE_6(m,p1,p2,p3,p4,p5,p6) MMI_Echo(m,p1,p2,p3,p4,p5,p6)
+
+#define MSKB_DEBUG_0(m) MMI_Echo(m)
+#define MSKB_DEBUG_1(m,p1) MMI_Echo(m,p1)
+#define MSKB_DEBUG_2(m,p1,p2) MMI_Echo(m,p1,p2)
+#define MSKB_DEBUG_3(m,p1,p2,p3) MMI_Echo(m,p1,p2,p3)
+#define MSKB_DEBUG_4(m,p1,p2,p3,p4) MMI_Echo(m,p1,p2,p3,p4)
+#define MSKB_DEBUG_5(m,p1,p2,p3,p4,p5) MMI_Echo(m,p1,p2,p3,p4,p5)
+#define MSKB_DEBUG_6(m,p1,p2,p3,p4,p5,p6) MMI_Echo(m,p1,p2,p3,p4,p5,p6)
+
+#define MSKB_ERROR_0(m) MMI_Echo(m)
+#define MSKB_ERROR_1(m,p1) MMI_Echo(m,p1)
+#define MSKB_ERROR_2(m,p1,p2) MMI_Echo(m,p1,p2)
+#define MSKB_ERROR_3(m,p1,p2,p3) MMI_Echo(m,p1,p2,p3)
+#define MSKB_ERROR_4(m,p1,p2,p3,p4) MMI_Echo(m,p1,p2,p3,p4)
+#define MSKB_ERROR_5(m,p1,p2,p3,p4,p5) MMI_Echo(m,p1,p2,p3,p4,p5)
+#define MSKB_ERROR_6(m,p1,p2,p3,p4,p5,p6) MMI_Echo(m,p1,p2,p3,p4,p5,p6)
+
+/* define traces for DUN */
+
+#define DUN_TRACE_ERROR0(m) {if (dun_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_0(TRACE_LAYER_DUN, TRACE_TYPE_ERROR, m);}
+#define DUN_TRACE_ERROR1(m,p1) {if (dun_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_1(TRACE_LAYER_DUN, TRACE_TYPE_ERROR, m, p1);}
+#define DUN_TRACE_ERROR2(m,p1,p2) {if (dun_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_2(TRACE_LAYER_DUN, TRACE_TYPE_ERROR, m,p1,p2);}
+#define DUN_TRACE_ERROR3(m,p1,p2,p3) {if (dun_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_3(TRACE_LAYER_DUN, TRACE_TYPE_ERROR, m,p1,p2,p3);}
+#define DUN_TRACE_ERROR4(m,p1,p2,p3,p4) {if (dun_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_4(TRACE_LAYER_DUN, TRACE_TYPE_ERROR, m,p1,p2,p3,p4);}
+#define DUN_TRACE_ERROR5(m,p1,p2,p3,p4,p5) {if (dun_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_5(TRACE_LAYER_DUN, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5);}
+#define DUN_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6) {if (dun_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_6(TRACE_LAYER_DUN, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5,p6);}
+
+#define DUN_TRACE_WARNING0(m) {if (dun_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_0(TRACE_LAYER_DUN, TRACE_TYPE_WARNING, m);}
+#define DUN_TRACE_WARNING1(m,p1) {if (dun_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_1(TRACE_LAYER_DUN, TRACE_TYPE_WARNING, m,p1);}
+#define DUN_TRACE_WARNING2(m,p1,p2) {if (dun_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_2(TRACE_LAYER_DUN, TRACE_TYPE_WARNING, m,p1,p2);}
+#define DUN_TRACE_WARNING3(m,p1,p2,p3) {if (dun_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_3(TRACE_LAYER_DUN, TRACE_TYPE_WARNING, m,p1,p2,p3);}
+#define DUN_TRACE_WARNING4(m,p1,p2,p3,p4) {if (dun_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_4(TRACE_LAYER_DUN, TRACE_TYPE_WARNING, m,p1,p2,p3,p4);}
+#define DUN_TRACE_WARNING5(m,p1,p2,p3,p4,p5) {if (dun_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_5(TRACE_LAYER_DUN, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5);}
+#define DUN_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6) {if (dun_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_6(TRACE_LAYER_DUN, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5,p6);}
+
+#define DUN_TRACE_API0(m) {if (dun_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_0(TRACE_LAYER_DUN, TRACE_TYPE_API, m);}
+#define DUN_TRACE_API1(m,p1) {if (dun_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_1(TRACE_LAYER_DUN, TRACE_TYPE_API, m, p1);}
+#define DUN_TRACE_API2(m,p1,p2) {if (dun_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_2(TRACE_LAYER_DUN, TRACE_TYPE_API, m,p1,p2);}
+#define DUN_TRACE_API3(m,p1,p2,p3) {if (dun_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_3(TRACE_LAYER_DUN, TRACE_TYPE_API, m,p1,p2,p3);}
+#define DUN_TRACE_API4(m,p1,p2,p3,p4) {if (dun_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_4(TRACE_LAYER_DUN, TRACE_TYPE_API, m,p1,p2,p3,p4);}
+#define DUN_TRACE_API5(m,p1,p2,p3,p4,p5) {if (dun_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_5(TRACE_LAYER_DUN, TRACE_TYPE_API, m,p1,p2,p3,p4,p5);}
+#define DUN_TRACE_API6(m,p1,p2,p3,p4,p5,p6) {if (dun_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_6(TRACE_LAYER_DUN, TRACE_TYPE_API, m,p1,p2,p3,p4,p5,p6);}
+
+#define DUN_TRACE_EVENT0(m) {if (dun_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_0(TRACE_LAYER_DUN, TRACE_TYPE_EVENT, m);}
+#define DUN_TRACE_EVENT1(m,p1) {if (dun_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_1(TRACE_LAYER_DUN, TRACE_TYPE_EVENT, m, p1);}
+#define DUN_TRACE_EVENT2(m,p1,p2) {if (dun_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_2(TRACE_LAYER_DUN, TRACE_TYPE_EVENT, m,p1,p2);}
+#define DUN_TRACE_EVENT3(m,p1,p2,p3) {if (dun_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_3(TRACE_LAYER_DUN, TRACE_TYPE_EVENT, m,p1,p2,p3);}
+#define DUN_TRACE_EVENT4(m,p1,p2,p3,p4) {if (dun_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_4(TRACE_LAYER_DUN, TRACE_TYPE_EVENT, m,p1,p2,p3,p4);}
+#define DUN_TRACE_EVENT5(m,p1,p2,p3,p4,p5) {if (dun_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_5(TRACE_LAYER_DUN, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5);}
+#define DUN_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6) {if (dun_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_6(TRACE_LAYER_DUN, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5,p6);}
+
+#define DUN_TRACE_DEBUG0(m) {if (dun_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_0(TRACE_LAYER_DUN, TRACE_TYPE_DEBUG, m);}
+#define DUN_TRACE_DEBUG1(m,p1) {if (dun_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_1(TRACE_LAYER_DUN, TRACE_TYPE_DEBUG, m,p1);}
+#define DUN_TRACE_DEBUG2(m,p1,p2) {if (dun_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_2(TRACE_LAYER_DUN, TRACE_TYPE_DEBUG, m,p1,p2);}
+#define DUN_TRACE_DEBUG3(m,p1,p2,p3) {if (dun_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_3(TRACE_LAYER_DUN, TRACE_TYPE_DEBUG, m,p1,p2,p3);}
+#define DUN_TRACE_DEBUG4(m,p1,p2,p3,p4) {if (dun_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_4(TRACE_LAYER_DUN, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4);}
+#define DUN_TRACE_DEBUG5(m,p1,p2,p3,p4,p5) {if (dun_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_5(TRACE_LAYER_DUN, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5);}
+#define DUN_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) {if (dun_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_6(TRACE_LAYER_DUN, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5,p6);}
+
+/* define traces for hardcopy cable replacement profile */
+
+#define HCRP_TRACE_ERROR0(m) {if (hcrp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_0(TRACE_LAYER_HCRP, TRACE_TYPE_ERROR, m);}
+#define HCRP_TRACE_ERROR1(m,p1) {if (hcrp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_1(TRACE_LAYER_HCRP, TRACE_TYPE_ERROR, m, p1);}
+#define HCRP_TRACE_ERROR2(m,p1,p2) {if (hcrp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_2(TRACE_LAYER_HCRP, TRACE_TYPE_ERROR, m,p1,p2);}
+#define HCRP_TRACE_ERROR3(m,p1,p2,p3) {if (hcrp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_3(TRACE_LAYER_HCRP, TRACE_TYPE_ERROR, m,p1,p2,p3);}
+#define HCRP_TRACE_ERROR4(m,p1,p2,p3,p4) {if (hcrp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_4(TRACE_LAYER_HCRP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4);}
+#define HCRP_TRACE_ERROR5(m,p1,p2,p3,p4,p5) {if (hcrp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_5(TRACE_LAYER_HCRP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5);}
+#define HCRP_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6) {if (hcrp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_6(TRACE_LAYER_HCRP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5,p6);}
+
+#define HCRP_TRACE_WARNING0(m) {if (hcrp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_0(TRACE_LAYER_HCRP, TRACE_TYPE_WARNING, m);}
+#define HCRP_TRACE_WARNING1(m,p1) {if (hcrp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_1(TRACE_LAYER_HCRP, TRACE_TYPE_WARNING, m,p1);}
+#define HCRP_TRACE_WARNING2(m,p1,p2) {if (hcrp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_2(TRACE_LAYER_HCRP, TRACE_TYPE_WARNING, m,p1,p2);}
+#define HCRP_TRACE_WARNING3(m,p1,p2,p3) {if (hcrp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_3(TRACE_LAYER_HCRP, TRACE_TYPE_WARNING, m,p1,p2,p3);}
+#define HCRP_TRACE_WARNING4(m,p1,p2,p3,p4) {if (hcrp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_4(TRACE_LAYER_HCRP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4);}
+#define HCRP_TRACE_WARNING5(m,p1,p2,p3,p4,p5) {if (hcrp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_5(TRACE_LAYER_HCRP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5);}
+#define HCRP_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6) {if (hcrp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_6(TRACE_LAYER_HCRP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5,p6);}
+
+#define HCRP_TRACE_API0(m) {if (hcrp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_0(TRACE_LAYER_HCRP, TRACE_TYPE_API, m);}
+#define HCRP_TRACE_API1(m,p1) {if (hcrp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_1(TRACE_LAYER_HCRP, TRACE_TYPE_API, m, p1);}
+#define HCRP_TRACE_API2(m,p1,p2) {if (hcrp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_2(TRACE_LAYER_HCRP, TRACE_TYPE_API, m,p1,p2);}
+#define HCRP_TRACE_API3(m,p1,p2,p3) {if (hcrp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_3(TRACE_LAYER_HCRP, TRACE_TYPE_API, m,p1,p2,p3);}
+#define HCRP_TRACE_API4(m,p1,p2,p3,p4) {if (hcrp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_4(TRACE_LAYER_HCRP, TRACE_TYPE_API, m,p1,p2,p3,p4);}
+#define HCRP_TRACE_API5(m,p1,p2,p3,p4,p5) {if (hcrp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_5(TRACE_LAYER_HCRP, TRACE_TYPE_API, m,p1,p2,p3,p4,p5);}
+#define HCRP_TRACE_API6(m,p1,p2,p3,p4,p5,p6) {if (hcrp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_6(TRACE_LAYER_HCRP, TRACE_TYPE_API, m,p1,p2,p3,p4,p5,p6);}
+
+#define HCRP_TRACE_EVENT0(m) {if (hcrp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_0(TRACE_LAYER_HCRP, TRACE_TYPE_EVENT, m);}
+#define HCRP_TRACE_EVENT1(m,p1) {if (hcrp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_1(TRACE_LAYER_HCRP, TRACE_TYPE_EVENT, m, p1);}
+#define HCRP_TRACE_EVENT2(m,p1,p2) {if (hcrp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_2(TRACE_LAYER_HCRP, TRACE_TYPE_EVENT, m,p1,p2);}
+#define HCRP_TRACE_EVENT3(m,p1,p2,p3) {if (hcrp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_3(TRACE_LAYER_HCRP, TRACE_TYPE_EVENT, m,p1,p2,p3);}
+#define HCRP_TRACE_EVENT4(m,p1,p2,p3,p4) {if (hcrp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_4(TRACE_LAYER_HCRP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4);}
+#define HCRP_TRACE_EVENT5(m,p1,p2,p3,p4,p5) {if (hcrp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_5(TRACE_LAYER_HCRP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5);}
+#define HCRP_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6) {if (hcrp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_6(TRACE_LAYER_HCRP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5,p6);}
+
+#define HCRP_TRACE_DEBUG0(m) {if (hcrp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_0(TRACE_LAYER_HCRP, TRACE_TYPE_DEBUG, m);}
+#define HCRP_TRACE_DEBUG1(m,p1) {if (hcrp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_1(TRACE_LAYER_HCRP, TRACE_TYPE_DEBUG, m,p1);}
+#define HCRP_TRACE_DEBUG2(m,p1,p2) {if (hcrp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_2(TRACE_LAYER_HCRP, TRACE_TYPE_DEBUG, m,p1,p2);}
+#define HCRP_TRACE_DEBUG3(m,p1,p2,p3) {if (hcrp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_3(TRACE_LAYER_HCRP, TRACE_TYPE_DEBUG, m,p1,p2,p3);}
+#define HCRP_TRACE_DEBUG4(m,p1,p2,p3,p4) {if (hcrp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_4(TRACE_LAYER_HCRP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4);}
+#define HCRP_TRACE_DEBUG5(m,p1,p2,p3,p4,p5) {if (hcrp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_5(TRACE_LAYER_HCRP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5);}
+#define HCRP_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) {if (hcrp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_6(TRACE_LAYER_HCRP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5,p6);}
+
+/* define traces for multi-client server hardcopy cable replacement profile */
+
+#define HCRPM_TRACE_ERROR0(m) {if (hcrpm_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_0(TRACE_LAYER_HCRP, TRACE_TYPE_ERROR, m);}
+#define HCRPM_TRACE_ERROR1(m,p1) {if (hcrpm_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_1(TRACE_LAYER_HCRP, TRACE_TYPE_ERROR, m, p1);}
+#define HCRPM_TRACE_ERROR2(m,p1,p2) {if (hcrpm_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_2(TRACE_LAYER_HCRP, TRACE_TYPE_ERROR, m,p1,p2);}
+#define HCRPM_TRACE_ERROR3(m,p1,p2,p3) {if (hcrpm_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_3(TRACE_LAYER_HCRP, TRACE_TYPE_ERROR, m,p1,p2,p3);}
+#define HCRPM_TRACE_ERROR4(m,p1,p2,p3,p4) {if (hcrpm_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_4(TRACE_LAYER_HCRP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4);}
+#define HCRPM_TRACE_ERROR5(m,p1,p2,p3,p4,p5) {if (hcrpm_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_5(TRACE_LAYER_HCRP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5);}
+#define HCRPM_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6) {if (hcrpm_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_6(TRACE_LAYER_HCRP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5,p6);}
+
+#define HCRPM_TRACE_WARNING0(m) {if (hcrpm_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_0(TRACE_LAYER_HCRP, TRACE_TYPE_WARNING, m);}
+#define HCRPM_TRACE_WARNING1(m,p1) {if (hcrpm_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_1(TRACE_LAYER_HCRP, TRACE_TYPE_WARNING, m,p1);}
+#define HCRPM_TRACE_WARNING2(m,p1,p2) {if (hcrpm_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_2(TRACE_LAYER_HCRP, TRACE_TYPE_WARNING, m,p1,p2);}
+#define HCRPM_TRACE_WARNING3(m,p1,p2,p3) {if (hcrpm_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_3(TRACE_LAYER_HCRP, TRACE_TYPE_WARNING, m,p1,p2,p3);}
+#define HCRPM_TRACE_WARNING4(m,p1,p2,p3,p4) {if (hcrpm_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_4(TRACE_LAYER_HCRP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4);}
+#define HCRPM_TRACE_WARNING5(m,p1,p2,p3,p4,p5) {if (hcrpm_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_5(TRACE_LAYER_HCRP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5);}
+#define HCRPM_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6) {if (hcrpm_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_6(TRACE_LAYER_HCRP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5,p6);}
+
+#define HCRPM_TRACE_API0(m) {if (hcrpm_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_0(TRACE_LAYER_HCRP, TRACE_TYPE_API, m);}
+#define HCRPM_TRACE_API1(m,p1) {if (hcrpm_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_1(TRACE_LAYER_HCRP, TRACE_TYPE_API, m, p1);}
+#define HCRPM_TRACE_API2(m,p1,p2) {if (hcrpm_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_2(TRACE_LAYER_HCRP, TRACE_TYPE_API, m,p1,p2);}
+#define HCRPM_TRACE_API3(m,p1,p2,p3) {if (hcrpm_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_3(TRACE_LAYER_HCRP, TRACE_TYPE_API, m,p1,p2,p3);}
+#define HCRPM_TRACE_API4(m,p1,p2,p3,p4) {if (hcrpm_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_4(TRACE_LAYER_HCRP, TRACE_TYPE_API, m,p1,p2,p3,p4);}
+#define HCRPM_TRACE_API5(m,p1,p2,p3,p4,p5) {if (hcrpm_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_5(TRACE_LAYER_HCRP, TRACE_TYPE_API, m,p1,p2,p3,p4,p5);}
+#define HCRPM_TRACE_API6(m,p1,p2,p3,p4,p5,p6) {if (hcrpm_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_6(TRACE_LAYER_HCRP, TRACE_TYPE_API, m,p1,p2,p3,p4,p5,p6);}
+
+#define HCRPM_TRACE_EVENT0(m) {if (hcrpm_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_0(TRACE_LAYER_HCRP, TRACE_TYPE_EVENT, m);}
+#define HCRPM_TRACE_EVENT1(m,p1) {if (hcrpm_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_1(TRACE_LAYER_HCRP, TRACE_TYPE_EVENT, m, p1);}
+#define HCRPM_TRACE_EVENT2(m,p1,p2) {if (hcrpm_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_2(TRACE_LAYER_HCRP, TRACE_TYPE_EVENT, m,p1,p2);}
+#define HCRPM_TRACE_EVENT3(m,p1,p2,p3) {if (hcrpm_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_3(TRACE_LAYER_HCRP, TRACE_TYPE_EVENT, m,p1,p2,p3);}
+#define HCRPM_TRACE_EVENT4(m,p1,p2,p3,p4) {if (hcrpm_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_4(TRACE_LAYER_HCRP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4);}
+#define HCRPM_TRACE_EVENT5(m,p1,p2,p3,p4,p5) {if (hcrpm_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_5(TRACE_LAYER_HCRP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5);}
+#define HCRPM_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6) {if (hcrpm_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_6(TRACE_LAYER_HCRP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5,p6);}
+
+#define HCRPM_TRACE_DEBUG0(m) {if (hcrpm_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_0(TRACE_LAYER_HCRP, TRACE_TYPE_DEBUG, m);}
+#define HCRPM_TRACE_DEBUG1(m,p1) {if (hcrpm_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_1(TRACE_LAYER_HCRP, TRACE_TYPE_DEBUG, m,p1);}
+#define HCRPM_TRACE_DEBUG2(m,p1,p2) {if (hcrpm_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_2(TRACE_LAYER_HCRP, TRACE_TYPE_DEBUG, m,p1,p2);}
+#define HCRPM_TRACE_DEBUG3(m,p1,p2,p3) {if (hcrpm_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_3(TRACE_LAYER_HCRP, TRACE_TYPE_DEBUG, m,p1,p2,p3);}
+#define HCRPM_TRACE_DEBUG4(m,p1,p2,p3,p4) {if (hcrpm_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_4(TRACE_LAYER_HCRP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4);}
+#define HCRPM_TRACE_DEBUG5(m,p1,p2,p3,p4,p5) {if (hcrpm_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_5(TRACE_LAYER_HCRP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5);}
+#define HCRPM_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) {if (hcrpm_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_6(TRACE_LAYER_HCRP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5,p6);}
+
+/* define traces for RPC */
+
+#define RPC_TRACE_ERROR0(m) {if (rpc_trace_level >= BT_TRACE_LEVEL_ERROR) LogMsg_0(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_RPC | TRACE_TYPE_ERROR, (m));}
+#define RPC_TRACE_ERROR1(m,p1) {if (rpc_trace_level >= BT_TRACE_LEVEL_ERROR) LogMsg_1(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_RPC | TRACE_TYPE_ERROR, \
+ (m), (UINT32)(p1));}
+#define RPC_TRACE_ERROR2(m,p1,p2) {if (rpc_trace_level >= BT_TRACE_LEVEL_ERROR) LogMsg_2(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_RPC | TRACE_TYPE_ERROR, \
+ (m), (UINT32)(p1), (UINT32)(p2));}
+#define RPC_TRACE_ERROR3(m,p1,p2,p3) {if (rpc_trace_level >= BT_TRACE_LEVEL_ERROR) LogMsg_3(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_RPC | TRACE_TYPE_ERROR, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3));}
+#define RPC_TRACE_ERROR4(m,p1,p2,p3,p4) {if (rpc_trace_level >= BT_TRACE_LEVEL_ERROR) LogMsg_4(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_RPC | TRACE_TYPE_ERROR, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4));}
+#define RPC_TRACE_ERROR5(m,p1,p2,p3,p4,p5) {if (rpc_trace_level >= BT_TRACE_LEVEL_ERROR) LogMsg_5(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_RPC | TRACE_TYPE_ERROR, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4), (UINT32)(p5));}
+#define RPC_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6) {if (rpc_trace_level >= BT_TRACE_LEVEL_ERROR) LogMsg_6(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_RPC | TRACE_TYPE_ERROR, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4), (UINT32)(p5), (UINT32)(p6));}
+
+#define RPC_TRACE_WARNING0(m) {if (rpc_trace_level >= BT_TRACE_LEVEL_WARNING) LogMsg_0(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_RPC | TRACE_TYPE_WARNING, (m));}
+#define RPC_TRACE_WARNING1(m,p1) {if (rpc_trace_level >= BT_TRACE_LEVEL_WARNING) LogMsg_1(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_RPC | TRACE_TYPE_WARNING, \
+ (m), (UINT32)(p1));}
+#define RPC_TRACE_WARNING2(m,p1,p2) {if (rpc_trace_level >= BT_TRACE_LEVEL_WARNING) LogMsg_2(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_RPC | TRACE_TYPE_WARNING, \
+ (m), (UINT32)(p1), (UINT32)(p2));}
+#define RPC_TRACE_WARNING3(m,p1,p2,p3) {if (rpc_trace_level >= BT_TRACE_LEVEL_WARNING) LogMsg_3(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_RPC | TRACE_TYPE_WARNING, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3));}
+#define RPC_TRACE_WARNING4(m,p1,p2,p3,p4) {if (rpc_trace_level >= BT_TRACE_LEVEL_WARNING) LogMsg_4(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_RPC | TRACE_TYPE_WARNING, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4));}
+#define RPC_TRACE_WARNING5(m,p1,p2,p3,p4,p5) {if (rpc_trace_level >= BT_TRACE_LEVEL_WARNING) LogMsg_5(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_RPC | TRACE_TYPE_WARNING, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4), (UINT32)(p5));}
+#define RPC_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6) {if (rpc_trace_level >= BT_TRACE_LEVEL_WARNING) LogMsg_6(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_RPC | TRACE_TYPE_WARNING, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4), (UINT32)(p5), (UINT32)(p6));}
+
+#define RPC_TRACE_API0(m) {if (rpc_trace_level >= BT_TRACE_LEVEL_API) LogMsg_0(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_RPC | TRACE_TYPE_API, (m));}
+#define RPC_TRACE_API1(m,p1) {if (rpc_trace_level >= BT_TRACE_LEVEL_API) LogMsg_1(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_RPC | TRACE_TYPE_API, \
+ (m), (UINT32)(p1));}
+#define RPC_TRACE_API2(m,p1,p2) {if (rpc_trace_level >= BT_TRACE_LEVEL_API) LogMsg_2(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_RPC | TRACE_TYPE_API, \
+ (m), (UINT32)(p1), (UINT32)(p2));}
+#define RPC_TRACE_API3(m,p1,p2,p3) {if (rpc_trace_level >= BT_TRACE_LEVEL_API) LogMsg_3(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_RPC | TRACE_TYPE_API, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3));}
+#define RPC_TRACE_API4(m,p1,p2,p3,p4) {if (rpc_trace_level >= BT_TRACE_LEVEL_API) LogMsg_4(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_RPC | TRACE_TYPE_API, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4));}
+#define RPC_TRACE_API5(m,p1,p2,p3,p4,p5) {if (rpc_trace_level >= BT_TRACE_LEVEL_API) LogMsg_5(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_RPC | TRACE_TYPE_API, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4), (UINT32)(p5));}
+#define RPC_TRACE_API6(m,p1,p2,p3,p4,p5,p6) {if (rpc_trace_level >= BT_TRACE_LEVEL_API) LogMsg_6(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_RPC | TRACE_TYPE_API, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4), (UINT32)(p5), (UINT32)(p6));}
+
+#define RPC_TRACE_EVENT0(m) {if (rpc_trace_level >= BT_TRACE_LEVEL_EVENT) LogMsg_0(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_RPC | TRACE_TYPE_EVENT, (m));}
+#define RPC_TRACE_EVENT1(m,p1) {if (rpc_trace_level >= BT_TRACE_LEVEL_EVENT) LogMsg_1(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_RPC | TRACE_TYPE_EVENT, \
+ (m), (UINT32)(p1));}
+#define RPC_TRACE_EVENT2(m,p1,p2) {if (rpc_trace_level >= BT_TRACE_LEVEL_EVENT) LogMsg_2(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_RPC | TRACE_TYPE_EVENT, \
+ (m), (UINT32)(p1), (UINT32)(p2));}
+#define RPC_TRACE_EVENT3(m,p1,p2,p3) {if (rpc_trace_level >= BT_TRACE_LEVEL_EVENT) LogMsg_3(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_RPC | TRACE_TYPE_EVENT, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3));}
+#define RPC_TRACE_EVENT4(m,p1,p2,p3,p4) {if (rpc_trace_level >= BT_TRACE_LEVEL_EVENT) LogMsg_4(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_RPC | TRACE_TYPE_EVENT, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4));}
+#define RPC_TRACE_EVENT5(m,p1,p2,p3,p4,p5) {if (rpc_trace_level >= BT_TRACE_LEVEL_EVENT) LogMsg_5(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_RPC | TRACE_TYPE_EVENT, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4), (UINT32)(p5));}
+#define RPC_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6) {if (rpc_trace_level >= BT_TRACE_LEVEL_EVENT) LogMsg_6(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_RPC | TRACE_TYPE_EVENT, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4), (UINT32)(p5), (UINT32)(p6));}
+
+#define RPC_TRACE_DEBUG0(m) {if (rpc_trace_level >= BT_TRACE_LEVEL_DEBUG) LogMsg_0(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_RPC | TRACE_TYPE_DEBUG, (m));}
+#define RPC_TRACE_DEBUG1(m,p1) {if (rpc_trace_level >= BT_TRACE_LEVEL_DEBUG) LogMsg_1(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_RPC | TRACE_TYPE_DEBUG, \
+ (m), (UINT32)(p1));}
+#define RPC_TRACE_DEBUG2(m,p1,p2) {if (rpc_trace_level >= BT_TRACE_LEVEL_DEBUG) LogMsg_2(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_RPC | TRACE_TYPE_DEBUG, \
+ (m), (UINT32)(p1), (UINT32)(p2));}
+#define RPC_TRACE_DEBUG3(m,p1,p2,p3) {if (rpc_trace_level >= BT_TRACE_LEVEL_DEBUG) LogMsg_3(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_RPC | TRACE_TYPE_DEBUG, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3));}
+#define RPC_TRACE_DEBUG4(m,p1,p2,p3,p4) {if (rpc_trace_level >= BT_TRACE_LEVEL_DEBUG) LogMsg_4(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_RPC | TRACE_TYPE_DEBUG, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4));}
+#define RPC_TRACE_DEBUG5(m,p1,p2,p3,p4,p5) {if (rpc_trace_level >= BT_TRACE_LEVEL_DEBUG) LogMsg_5(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_RPC | TRACE_TYPE_DEBUG, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4), (UINT32)(p5));}
+#define RPC_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) {if (rpc_trace_level >= BT_TRACE_LEVEL_DEBUG) LogMsg_6(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_RPC | TRACE_TYPE_DEBUG, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4), (UINT32)(p5), (UINT32)(p6));}
+
+/* define traces for BNEP */
+
+#define BNEP_TRACE_ERROR0(m) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_0(TRACE_LAYER_BNEP, TRACE_TYPE_ERROR, m);}
+#define BNEP_TRACE_ERROR1(m,p1) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_1(TRACE_LAYER_BNEP, TRACE_TYPE_ERROR, m, p1);}
+#define BNEP_TRACE_ERROR2(m,p1,p2) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_2(TRACE_LAYER_BNEP, TRACE_TYPE_ERROR, m,p1,p2);}
+#define BNEP_TRACE_ERROR3(m,p1,p2,p3) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_3(TRACE_LAYER_BNEP, TRACE_TYPE_ERROR, m,p1,p2,p3);}
+#define BNEP_TRACE_ERROR4(m,p1,p2,p3,p4) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_4(TRACE_LAYER_BNEP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4);}
+#define BNEP_TRACE_ERROR5(m,p1,p2,p3,p4,p5) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_5(TRACE_LAYER_BNEP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5);}
+#define BNEP_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_6(TRACE_LAYER_BNEP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5,p6);}
+
+#define BNEP_TRACE_WARNING0(m) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_0(TRACE_LAYER_BNEP, TRACE_TYPE_WARNING, m);}
+#define BNEP_TRACE_WARNING1(m,p1) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_1(TRACE_LAYER_BNEP, TRACE_TYPE_WARNING, m,p1);}
+#define BNEP_TRACE_WARNING2(m,p1,p2) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_2(TRACE_LAYER_BNEP, TRACE_TYPE_WARNING, m,p1,p2);}
+#define BNEP_TRACE_WARNING3(m,p1,p2,p3) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_3(TRACE_LAYER_BNEP, TRACE_TYPE_WARNING, m,p1,p2,p3);}
+#define BNEP_TRACE_WARNING4(m,p1,p2,p3,p4) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_4(TRACE_LAYER_BNEP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4);}
+#define BNEP_TRACE_WARNING5(m,p1,p2,p3,p4,p5) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_5(TRACE_LAYER_BNEP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5);}
+#define BNEP_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_6(TRACE_LAYER_BNEP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5,p6);}
+
+#define BNEP_TRACE_API0(m) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_0(TRACE_LAYER_BNEP, TRACE_TYPE_API, m);}
+#define BNEP_TRACE_API1(m,p1) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_1(TRACE_LAYER_BNEP, TRACE_TYPE_API, m, p1);}
+#define BNEP_TRACE_API2(m,p1,p2) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_2(TRACE_LAYER_BNEP, TRACE_TYPE_API, m,p1,p2);}
+#define BNEP_TRACE_API3(m,p1,p2,p3) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_3(TRACE_LAYER_BNEP, TRACE_TYPE_API, m,p1,p2,p3);}
+#define BNEP_TRACE_API4(m,p1,p2,p3,p4) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_4(TRACE_LAYER_BNEP, TRACE_TYPE_API, m,p1,p2,p3,p4);}
+#define BNEP_TRACE_API5(m,p1,p2,p3,p4,p5) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_5(TRACE_LAYER_BNEP, TRACE_TYPE_API, m,p1,p2,p3,p4,p5);}
+#define BNEP_TRACE_API6(m,p1,p2,p3,p4,p5,p6) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_6(TRACE_LAYER_BNEP, TRACE_TYPE_API, m,p1,p2,p3,p4,p5,p6);}
+
+#define BNEP_TRACE_EVENT0(m) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_0(TRACE_LAYER_BNEP, TRACE_TYPE_EVENT, m);}
+#define BNEP_TRACE_EVENT1(m,p1) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_1(TRACE_LAYER_BNEP, TRACE_TYPE_EVENT, m, p1);}
+#define BNEP_TRACE_EVENT2(m,p1,p2) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_2(TRACE_LAYER_BNEP, TRACE_TYPE_EVENT, m,p1,p2);}
+#define BNEP_TRACE_EVENT3(m,p1,p2,p3) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_3(TRACE_LAYER_BNEP, TRACE_TYPE_EVENT, m,p1,p2,p3);}
+#define BNEP_TRACE_EVENT4(m,p1,p2,p3,p4) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_4(TRACE_LAYER_BNEP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4);}
+#define BNEP_TRACE_EVENT5(m,p1,p2,p3,p4,p5) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_5(TRACE_LAYER_BNEP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5);}
+#define BNEP_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_6(TRACE_LAYER_BNEP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5,p6);}
+
+#define BNEP_TRACE_DEBUG0(m) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_0(TRACE_LAYER_BNEP, TRACE_TYPE_DEBUG, m);}
+#define BNEP_TRACE_DEBUG1(m,p1) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_1(TRACE_LAYER_BNEP, TRACE_TYPE_DEBUG, m,p1);}
+#define BNEP_TRACE_DEBUG2(m,p1,p2) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_2(TRACE_LAYER_BNEP, TRACE_TYPE_DEBUG, m,p1,p2);}
+#define BNEP_TRACE_DEBUG3(m,p1,p2,p3) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_3(TRACE_LAYER_BNEP, TRACE_TYPE_DEBUG, m,p1,p2,p3);}
+#define BNEP_TRACE_DEBUG4(m,p1,p2,p3,p4) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_4(TRACE_LAYER_BNEP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4);}
+#define BNEP_TRACE_DEBUG5(m,p1,p2,p3,p4,p5) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_5(TRACE_LAYER_BNEP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5);}
+#define BNEP_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_6(TRACE_LAYER_BNEP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5,p6);}
+
+/* define traces for PAN */
+
+#define PAN_TRACE_ERROR0(m) {if (pan_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_0(TRACE_LAYER_PAN, TRACE_TYPE_ERROR, m);}
+#define PAN_TRACE_ERROR1(m,p1) {if (pan_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_1(TRACE_LAYER_PAN, TRACE_TYPE_ERROR, m, p1);}
+#define PAN_TRACE_ERROR2(m,p1,p2) {if (pan_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_2(TRACE_LAYER_PAN, TRACE_TYPE_ERROR, m,p1,p2);}
+#define PAN_TRACE_ERROR3(m,p1,p2,p3) {if (pan_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_3(TRACE_LAYER_PAN, TRACE_TYPE_ERROR, m,p1,p2,p3);}
+#define PAN_TRACE_ERROR4(m,p1,p2,p3,p4) {if (pan_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_4(TRACE_LAYER_PAN, TRACE_TYPE_ERROR, m,p1,p2,p3,p4);}
+#define PAN_TRACE_ERROR5(m,p1,p2,p3,p4,p5) {if (pan_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_5(TRACE_LAYER_PAN, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5);}
+#define PAN_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6) {if (pan_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_6(TRACE_LAYER_PAN, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5,p6);}
+
+#define PAN_TRACE_WARNING0(m) {if (pan_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_0(TRACE_LAYER_PAN, TRACE_TYPE_WARNING, m);}
+#define PAN_TRACE_WARNING1(m,p1) {if (pan_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_1(TRACE_LAYER_PAN, TRACE_TYPE_WARNING, m,p1);}
+#define PAN_TRACE_WARNING2(m,p1,p2) {if (pan_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_2(TRACE_LAYER_PAN, TRACE_TYPE_WARNING, m,p1,p2);}
+#define PAN_TRACE_WARNING3(m,p1,p2,p3) {if (pan_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_3(TRACE_LAYER_PAN, TRACE_TYPE_WARNING, m,p1,p2,p3);}
+#define PAN_TRACE_WARNING4(m,p1,p2,p3,p4) {if (pan_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_4(TRACE_LAYER_PAN, TRACE_TYPE_WARNING, m,p1,p2,p3,p4);}
+#define PAN_TRACE_WARNING5(m,p1,p2,p3,p4,p5) {if (pan_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_5(TRACE_LAYER_PAN, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5);}
+#define PAN_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6) {if (pan_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_6(TRACE_LAYER_PAN, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5,p6);}
+
+#define PAN_TRACE_API0(m) {if (pan_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_0(TRACE_LAYER_PAN, TRACE_TYPE_API, m);}
+#define PAN_TRACE_API1(m,p1) {if (pan_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_1(TRACE_LAYER_PAN, TRACE_TYPE_API, m, p1);}
+#define PAN_TRACE_API2(m,p1,p2) {if (pan_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_2(TRACE_LAYER_PAN, TRACE_TYPE_API, m,p1,p2);}
+#define PAN_TRACE_API3(m,p1,p2,p3) {if (pan_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_3(TRACE_LAYER_PAN, TRACE_TYPE_API, m,p1,p2,p3);}
+#define PAN_TRACE_API4(m,p1,p2,p3,p4) {if (pan_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_4(TRACE_LAYER_PAN, TRACE_TYPE_API, m,p1,p2,p3,p4);}
+#define PAN_TRACE_API5(m,p1,p2,p3,p4,p5) {if (pan_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_5(TRACE_LAYER_PAN, TRACE_TYPE_API, m,p1,p2,p3,p4,p5);}
+#define PAN_TRACE_API6(m,p1,p2,p3,p4,p5,p6) {if (pan_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_6(TRACE_LAYER_PAN, TRACE_TYPE_API, m,p1,p2,p3,p4,p5,p6);}
+
+#define PAN_TRACE_EVENT0(m) {if (pan_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_0(TRACE_LAYER_PAN, TRACE_TYPE_EVENT, m);}
+#define PAN_TRACE_EVENT1(m,p1) {if (pan_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_1(TRACE_LAYER_PAN, TRACE_TYPE_EVENT, m, p1);}
+#define PAN_TRACE_EVENT2(m,p1,p2) {if (pan_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_2(TRACE_LAYER_PAN, TRACE_TYPE_EVENT, m,p1,p2);}
+#define PAN_TRACE_EVENT3(m,p1,p2,p3) {if (pan_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_3(TRACE_LAYER_PAN, TRACE_TYPE_EVENT, m,p1,p2,p3);}
+#define PAN_TRACE_EVENT4(m,p1,p2,p3,p4) {if (pan_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_4(TRACE_LAYER_PAN, TRACE_TYPE_EVENT, m,p1,p2,p3,p4);}
+#define PAN_TRACE_EVENT5(m,p1,p2,p3,p4,p5) {if (pan_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_5(TRACE_LAYER_PAN, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5);}
+#define PAN_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6) {if (pan_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_6(TRACE_LAYER_PAN, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5,p6);}
+
+#define PAN_TRACE_DEBUG0(m) {if (pan_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_0(TRACE_LAYER_PAN, TRACE_TYPE_DEBUG, m);}
+#define PAN_TRACE_DEBUG1(m,p1) {if (pan_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_1(TRACE_LAYER_PAN, TRACE_TYPE_DEBUG, m,p1);}
+#define PAN_TRACE_DEBUG2(m,p1,p2) {if (pan_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_2(TRACE_LAYER_PAN, TRACE_TYPE_DEBUG, m,p1,p2);}
+#define PAN_TRACE_DEBUG3(m,p1,p2,p3) {if (pan_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_3(TRACE_LAYER_PAN, TRACE_TYPE_DEBUG, m,p1,p2,p3);}
+#define PAN_TRACE_DEBUG4(m,p1,p2,p3,p4) {if (pan_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_4(TRACE_LAYER_PAN, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4);}
+#define PAN_TRACE_DEBUG5(m,p1,p2,p3,p4,p5) {if (pan_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_5(TRACE_LAYER_PAN, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5);}
+#define PAN_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) {if (pan_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_6(TRACE_LAYER_PAN, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5,p6);}
+
+/* define traces for SIM */
+
+#define SAP_TRACE_ERROR0(m) {if (sap_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_0(TRACE_LAYER_SAP, TRACE_TYPE_ERROR, m);}
+#define SAP_TRACE_ERROR1(m,p1) {if (sap_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_1(TRACE_LAYER_SAP, TRACE_TYPE_ERROR, m, p1);}
+#define SAP_TRACE_ERROR2(m,p1,p2) {if (sap_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_2(TRACE_LAYER_SAP, TRACE_TYPE_ERROR, m,p1,p2);}
+#define SAP_TRACE_ERROR3(m,p1,p2,p3) {if (sap_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_3(TRACE_LAYER_SAP, TRACE_TYPE_ERROR, m,p1,p2,p3);}
+#define SAP_TRACE_ERROR4(m,p1,p2,p3,p4) {if (sap_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_4(TRACE_LAYER_SAP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4);}
+#define SAP_TRACE_ERROR5(m,p1,p2,p3,p4,p5) {if (sap_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_5(TRACE_LAYER_SAP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5);}
+#define SAP_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6) {if (sap_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_6(TRACE_LAYER_SAP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5,p6);}
+
+#define SAP_TRACE_WARNING0(m) {if (sap_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_0(TRACE_LAYER_SAP, TRACE_TYPE_WARNING, m);}
+#define SAP_TRACE_WARNING1(m,p1) {if (sap_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_1(TRACE_LAYER_SAP, TRACE_TYPE_WARNING, m,p1);}
+#define SAP_TRACE_WARNING2(m,p1,p2) {if (sap_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_2(TRACE_LAYER_SAP, TRACE_TYPE_WARNING, m,p1,p2);}
+#define SAP_TRACE_WARNING3(m,p1,p2,p3) {if (sap_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_3(TRACE_LAYER_SAP, TRACE_TYPE_WARNING, m,p1,p2,p3);}
+#define SAP_TRACE_WARNING4(m,p1,p2,p3,p4) {if (sap_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_4(TRACE_LAYER_SAP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4);}
+#define SAP_TRACE_WARNING5(m,p1,p2,p3,p4,p5) {if (sap_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_5(TRACE_LAYER_SAP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5);}
+#define SAP_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6) {if (sap_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_6(TRACE_LAYER_SAP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5,p6);}
+
+#define SAP_TRACE_API0(m) {if (sap_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_0(TRACE_LAYER_SAP, TRACE_TYPE_API, m);}
+#define SAP_TRACE_API1(m,p1) {if (sap_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_1(TRACE_LAYER_SAP, TRACE_TYPE_API, m, p1);}
+#define SAP_TRACE_API2(m,p1,p2) {if (sap_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_2(TRACE_LAYER_SAP, TRACE_TYPE_API, m,p1,p2);}
+#define SAP_TRACE_API3(m,p1,p2,p3) {if (sap_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_3(TRACE_LAYER_SAP, TRACE_TYPE_API, m,p1,p2,p3);}
+#define SAP_TRACE_API4(m,p1,p2,p3,p4) {if (sap_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_4(TRACE_LAYER_SAP, TRACE_TYPE_API, m,p1,p2,p3,p4);}
+#define SAP_TRACE_API5(m,p1,p2,p3,p4,p5) {if (sap_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_5(TRACE_LAYER_SAP, TRACE_TYPE_API, m,p1,p2,p3,p4,p5);}
+#define SAP_TRACE_API6(m,p1,p2,p3,p4,p5,p6) {if (sap_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_6(TRACE_LAYER_SAP, TRACE_TYPE_API, m,p1,p2,p3,p4,p5,p6);}
+
+#define SAP_TRACE_EVENT0(m) {if (sap_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_0(TRACE_LAYER_SAP, TRACE_TYPE_EVENT, m);}
+#define SAP_TRACE_EVENT1(m,p1) {if (sap_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_1(TRACE_LAYER_SAP, TRACE_TYPE_EVENT, m, p1);}
+#define SAP_TRACE_EVENT2(m,p1,p2) {if (sap_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_2(TRACE_LAYER_SAP, TRACE_TYPE_EVENT, m,p1,p2);}
+#define SAP_TRACE_EVENT3(m,p1,p2,p3) {if (sap_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_3(TRACE_LAYER_SAP, TRACE_TYPE_EVENT, m,p1,p2,p3);}
+#define SAP_TRACE_EVENT4(m,p1,p2,p3,p4) {if (sap_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_4(TRACE_LAYER_SAP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4);}
+#define SAP_TRACE_EVENT5(m,p1,p2,p3,p4,p5) {if (sap_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_5(TRACE_LAYER_SAP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5);}
+#define SAP_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6) {if (sap_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_6(TRACE_LAYER_SAP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5,p6);}
+
+#define SAP_TRACE_DEBUG0(m) {if (sap_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_0(TRACE_LAYER_SAP, TRACE_TYPE_DEBUG, m);}
+#define SAP_TRACE_DEBUG1(m,p1) {if (sap_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_1(TRACE_LAYER_SAP, TRACE_TYPE_DEBUG, m,p1);}
+#define SAP_TRACE_DEBUG2(m,p1,p2) {if (sap_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_2(TRACE_LAYER_SAP, TRACE_TYPE_DEBUG, m,p1,p2);}
+#define SAP_TRACE_DEBUG3(m,p1,p2,p3) {if (sap_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_3(TRACE_LAYER_SAP, TRACE_TYPE_DEBUG, m,p1,p2,p3);}
+#define SAP_TRACE_DEBUG4(m,p1,p2,p3,p4) {if (sap_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_4(TRACE_LAYER_SAP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4);}
+#define SAP_TRACE_DEBUG5(m,p1,p2,p3,p4,p5) {if (sap_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_5(TRACE_LAYER_SAP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5);}
+#define SAP_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) {if (sap_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_6(TRACE_LAYER_SAP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5,p6);}
+
+/* Define tracing for OPP profile
+*/
+#define OPP_TRACE_ERROR0(m) {if (opp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_0(TRACE_LAYER_OPP, TRACE_TYPE_ERROR, m);}
+#define OPP_TRACE_ERROR1(m,p1) {if (opp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_1(TRACE_LAYER_OPP, TRACE_TYPE_ERROR, m,p1);}
+#define OPP_TRACE_ERROR2(m,p1,p2) {if (opp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_2(TRACE_LAYER_OPP, TRACE_TYPE_ERROR, m,p1,p2);}
+#define OPP_TRACE_ERROR3(m,p1,p2,p3) {if (opp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_3(TRACE_LAYER_OPP, TRACE_TYPE_ERROR, m,p1,p2,p3);}
+#define OPP_TRACE_ERROR4(m,p1,p2,p3,p4) {if (opp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_4(TRACE_LAYER_OPP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4);}
+#define OPP_TRACE_ERROR5(m,p1,p2,p3,p4,p5) {if (opp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_5(TRACE_LAYER_OPP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5);}
+#define OPP_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6) {if (opp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_6(TRACE_LAYER_OPP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5,p6);}
+
+#define OPP_TRACE_WARNING0(m) {if (opp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_0(TRACE_LAYER_OPP, TRACE_TYPE_WARNING, m);}
+#define OPP_TRACE_WARNING1(m,p1) {if (opp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_1(TRACE_LAYER_OPP, TRACE_TYPE_WARNING, m,p1);}
+#define OPP_TRACE_WARNING2(m,p1,p2) {if (opp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_2(TRACE_LAYER_OPP, TRACE_TYPE_WARNING, m,p1,p2);}
+#define OPP_TRACE_WARNING3(m,p1,p2,p3) {if (opp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_3(TRACE_LAYER_OPP, TRACE_TYPE_WARNING, m,p1,p2,p3);}
+#define OPP_TRACE_WARNING4(m,p1,p2,p3,p4) {if (opp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_4(TRACE_LAYER_OPP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4);}
+#define OPP_TRACE_WARNING5(m,p1,p2,p3,p4,p5) {if (opp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_5(TRACE_LAYER_OPP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5);}
+#define OPP_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6) {if (opp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_6(TRACE_LAYER_OPP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5,p6);}
+
+#define OPP_TRACE_EVENT0(m) {if (opp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_0(TRACE_LAYER_OPP, TRACE_TYPE_EVENT, m);}
+#define OPP_TRACE_EVENT1(m,p1) {if (opp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_1(TRACE_LAYER_OPP, TRACE_TYPE_EVENT, m, p1);}
+#define OPP_TRACE_EVENT2(m,p1,p2) {if (opp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_2(TRACE_LAYER_OPP, TRACE_TYPE_EVENT, m,p1,p2);}
+#define OPP_TRACE_EVENT3(m,p1,p2,p3) {if (opp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_3(TRACE_LAYER_OPP, TRACE_TYPE_EVENT, m,p1,p2,p3);}
+#define OPP_TRACE_EVENT4(m,p1,p2,p3,p4) {if (opp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_4(TRACE_LAYER_OPP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4);}
+#define OPP_TRACE_EVENT5(m,p1,p2,p3,p4,p5) {if (opp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_5(TRACE_LAYER_OPP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5);}
+#define OPP_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6) {if (opp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_6(TRACE_LAYER_OPP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5,p6);}
+
+#define OPP_TRACE_DEBUG0(m) {if (opp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_0(TRACE_LAYER_OPP, TRACE_TYPE_DEBUG, m);}
+#define OPP_TRACE_DEBUG1(m,p1) {if (opp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_1(TRACE_LAYER_OPP, TRACE_TYPE_DEBUG, m,p1);}
+#define OPP_TRACE_DEBUG2(m,p1,p2) {if (opp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_2(TRACE_LAYER_OPP, TRACE_TYPE_DEBUG, m,p1,p2);}
+#define OPP_TRACE_DEBUG3(m,p1,p2,p3) {if (opp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_3(TRACE_LAYER_OPP, TRACE_TYPE_DEBUG, m,p1,p2,p3);}
+#define OPP_TRACE_DEBUG4(m,p1,p2,p3,p4) {if (opp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_4(TRACE_LAYER_OPP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4);}
+#define OPP_TRACE_DEBUG5(m,p1,p2,p3,p4,p5) {if (opp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_5(TRACE_LAYER_OPP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5);}
+#define OPP_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) {if (opp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_6(TRACE_LAYER_OPP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5,p6);}
+
+/* Define tracing for FTP profile
+*/
+#define FTP_TRACE_ERROR0(m) {if (ftp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_0(TRACE_LAYER_FTP, TRACE_TYPE_ERROR, m);}
+#define FTP_TRACE_ERROR1(m,p1) {if (ftp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_1(TRACE_LAYER_FTP, TRACE_TYPE_ERROR, m,p1);}
+#define FTP_TRACE_ERROR2(m,p1,p2) {if (ftp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_2(TRACE_LAYER_FTP, TRACE_TYPE_ERROR, m,p1,p2);}
+#define FTP_TRACE_ERROR3(m,p1,p2,p3) {if (ftp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_3(TRACE_LAYER_FTP, TRACE_TYPE_ERROR, m,p1,p2,p3);}
+#define FTP_TRACE_ERROR4(m,p1,p2,p3,p4) {if (ftp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_4(TRACE_LAYER_FTP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4);}
+#define FTP_TRACE_ERROR5(m,p1,p2,p3,p4,p5) {if (ftp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_5(TRACE_LAYER_FTP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5);}
+#define FTP_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6) {if (ftp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_6(TRACE_LAYER_FTP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5,p6);}
+
+#define FTP_TRACE_WARNING0(m) {if (ftp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_0(TRACE_LAYER_FTP, TRACE_TYPE_WARNING, m);}
+#define FTP_TRACE_WARNING1(m,p1) {if (ftp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_1(TRACE_LAYER_FTP, TRACE_TYPE_WARNING, m,p1);}
+#define FTP_TRACE_WARNING2(m,p1,p2) {if (ftp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_2(TRACE_LAYER_FTP, TRACE_TYPE_WARNING, m,p1,p2);}
+#define FTP_TRACE_WARNING3(m,p1,p2,p3) {if (ftp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_3(TRACE_LAYER_FTP, TRACE_TYPE_WARNING, m,p1,p2,p3);}
+#define FTP_TRACE_WARNING4(m,p1,p2,p3,p4) {if (ftp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_4(TRACE_LAYER_FTP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4);}
+#define FTP_TRACE_WARNING5(m,p1,p2,p3,p4,p5) {if (ftp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_5(TRACE_LAYER_FTP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5);}
+#define FTP_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6) {if (ftp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_6(TRACE_LAYER_FTP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5,p6);}
+
+#define FTP_TRACE_EVENT0(m) {if (ftp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_0(TRACE_LAYER_FTP, TRACE_TYPE_EVENT, m);}
+#define FTP_TRACE_EVENT1(m,p1) {if (ftp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_1(TRACE_LAYER_FTP, TRACE_TYPE_EVENT, m, p1);}
+#define FTP_TRACE_EVENT2(m,p1,p2) {if (ftp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_2(TRACE_LAYER_FTP, TRACE_TYPE_EVENT, m,p1,p2);}
+#define FTP_TRACE_EVENT3(m,p1,p2,p3) {if (ftp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_3(TRACE_LAYER_FTP, TRACE_TYPE_EVENT, m,p1,p2,p3);}
+#define FTP_TRACE_EVENT4(m,p1,p2,p3,p4) {if (ftp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_4(TRACE_LAYER_FTP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4);}
+#define FTP_TRACE_EVENT5(m,p1,p2,p3,p4,p5) {if (ftp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_5(TRACE_LAYER_FTP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5);}
+#define FTP_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6) {if (ftp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_6(TRACE_LAYER_FTP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5,p6);}
+
+#define FTP_TRACE_DEBUG0(m) {if (ftp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_0(TRACE_LAYER_FTP, TRACE_TYPE_DEBUG, m);}
+#define FTP_TRACE_DEBUG1(m,p1) {if (ftp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_1(TRACE_LAYER_FTP, TRACE_TYPE_DEBUG, m,p1);}
+#define FTP_TRACE_DEBUG2(m,p1,p2) {if (ftp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_2(TRACE_LAYER_FTP, TRACE_TYPE_DEBUG, m,p1,p2);}
+#define FTP_TRACE_DEBUG3(m,p1,p2,p3) {if (ftp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_3(TRACE_LAYER_FTP, TRACE_TYPE_DEBUG, m,p1,p2,p3);}
+#define FTP_TRACE_DEBUG4(m,p1,p2,p3,p4) {if (ftp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_4(TRACE_LAYER_FTP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4);}
+#define FTP_TRACE_DEBUG5(m,p1,p2,p3,p4,p5) {if (ftp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_5(TRACE_LAYER_FTP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5);}
+#define FTP_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) {if (ftp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_6(TRACE_LAYER_FTP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5,p6);}
+
+/* Define tracing for the A2DP profile
+*/
+#define A2D_TRACE_ERROR0(m) {if (a2d_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_0(TRACE_LAYER_A2D, TRACE_TYPE_ERROR,m);}
+#define A2D_TRACE_ERROR1(m,p1) {if (a2d_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_1(TRACE_LAYER_A2D, TRACE_TYPE_ERROR,m,p1);}
+#define A2D_TRACE_ERROR2(m,p1,p2) {if (a2d_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_2(TRACE_LAYER_A2D, TRACE_TYPE_ERROR,m,p1,p2);}
+#define A2D_TRACE_ERROR3(m,p1,p2,p3) {if (a2d_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_3(TRACE_LAYER_A2D, TRACE_TYPE_ERROR,m,p1,p2,p3);}
+#define A2D_TRACE_ERROR4(m,p1,p2,p3,p4) {if (a2d_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_4(TRACE_LAYER_A2D, TRACE_TYPE_ERROR,m,p1,p2,p3,p4);}
+#define A2D_TRACE_ERROR5(m,p1,p2,p3,p4,p5) {if (a2d_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_5(TRACE_LAYER_A2D, TRACE_TYPE_ERROR,m,p1,p2,p3,p4,p5);}
+#define A2D_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6) {if (a2d_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_6(TRACE_LAYER_A2D, TRACE_TYPE_ERROR,m,p1,p2,p3,p4,p5,p6);}
+
+#define A2D_TRACE_WARNING0(m) {if (a2d_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_0(TRACE_LAYER_A2D, TRACE_TYPE_WARNING,m);}
+#define A2D_TRACE_WARNING1(m,p1) {if (a2d_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_1(TRACE_LAYER_A2D, TRACE_TYPE_WARNING,m,p1);}
+#define A2D_TRACE_WARNING2(m,p1,p2) {if (a2d_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_2(TRACE_LAYER_A2D, TRACE_TYPE_WARNING,m,p1,p2);}
+#define A2D_TRACE_WARNING3(m,p1,p2,p3) {if (a2d_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_3(TRACE_LAYER_A2D, TRACE_TYPE_WARNING,m,p1,p2,p3);}
+#define A2D_TRACE_WARNING4(m,p1,p2,p3,p4) {if (a2d_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_4(TRACE_LAYER_A2D, TRACE_TYPE_WARNING,m,p1,p2,p3,p4);}
+#define A2D_TRACE_WARNING5(m,p1,p2,p3,p4,p5) {if (a2d_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_5(TRACE_LAYER_A2D, TRACE_TYPE_WARNING,m,p1,p2,p3,p4,p5);}
+#define A2D_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6) {if (a2d_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_6(TRACE_LAYER_A2D, TRACE_TYPE_WARNING,m,p1,p2,p3,p4,p5,p6);}
+
+#define A2D_TRACE_EVENT0(m) {if (a2d_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_0(TRACE_LAYER_A2D, TRACE_TYPE_EVENT,m);}
+#define A2D_TRACE_EVENT1(m,p1) {if (a2d_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_1(TRACE_LAYER_A2D, TRACE_TYPE_EVENT,m, p1);}
+#define A2D_TRACE_EVENT2(m,p1,p2) {if (a2d_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_2(TRACE_LAYER_A2D, TRACE_TYPE_EVENT,m,p1,p2);}
+#define A2D_TRACE_EVENT3(m,p1,p2,p3) {if (a2d_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_3(TRACE_LAYER_A2D, TRACE_TYPE_EVENT,m,p1,p2,p3);}
+#define A2D_TRACE_EVENT4(m,p1,p2,p3,p4) {if (a2d_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_4(TRACE_LAYER_A2D, TRACE_TYPE_EVENT,m,p1,p2,p3,p4);}
+#define A2D_TRACE_EVENT5(m,p1,p2,p3,p4,p5) {if (a2d_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_5(TRACE_LAYER_A2D, TRACE_TYPE_EVENT,m,p1,p2,p3,p4,p5);}
+#define A2D_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6) {if (a2d_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_6(TRACE_LAYER_A2D, TRACE_TYPE_EVENT,m,p1,p2,p3,p4,p5,p6);}
+
+#define A2D_TRACE_DEBUG0(m) {if (a2d_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_0(TRACE_LAYER_A2D, TRACE_TYPE_DEBUG,m);}
+#define A2D_TRACE_DEBUG1(m,p1) {if (a2d_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_1(TRACE_LAYER_A2D, TRACE_TYPE_DEBUG,m,p1);}
+#define A2D_TRACE_DEBUG2(m,p1,p2) {if (a2d_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_2(TRACE_LAYER_A2D, TRACE_TYPE_DEBUG,m,p1,p2);}
+#define A2D_TRACE_DEBUG3(m,p1,p2,p3) {if (a2d_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_3(TRACE_LAYER_A2D, TRACE_TYPE_DEBUG,m,p1,p2,p3);}
+#define A2D_TRACE_DEBUG4(m,p1,p2,p3,p4) {if (a2d_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_4(TRACE_LAYER_A2D, TRACE_TYPE_DEBUG,m,p1,p2,p3,p4);}
+#define A2D_TRACE_DEBUG5(m,p1,p2,p3,p4,p5) {if (a2d_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_5(TRACE_LAYER_A2D, TRACE_TYPE_DEBUG,m,p1,p2,p3,p4,p5);}
+#define A2D_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) {if (a2d_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_6(TRACE_LAYER_A2D, TRACE_TYPE_DEBUG,m,p1,p2,p3,p4,p5,p6);}
+
+#define A2D_TRACE_API0(m) {if (a2d_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_0(TRACE_LAYER_A2D, TRACE_TYPE_API,m);}
+#define A2D_TRACE_API1(m,p1) {if (a2d_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_1(TRACE_LAYER_A2D, TRACE_TYPE_API,m, p1);}
+#define A2D_TRACE_API2(m,p1,p2) {if (a2d_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_2(TRACE_LAYER_A2D, TRACE_TYPE_API,m,p1,p2);}
+#define A2D_TRACE_API3(m,p1,p2,p3) {if (a2d_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_3(TRACE_LAYER_A2D, TRACE_TYPE_API,m,p1,p2,p3);}
+#define A2D_TRACE_API4(m,p1,p2,p3,p4) {if (a2d_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_4(TRACE_LAYER_A2D, TRACE_TYPE_API,m,p1,p2,p3,p4);}
+#define A2D_TRACE_API5(m,p1,p2,p3,p4,p5) {if (a2d_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_5(TRACE_LAYER_A2D, TRACE_TYPE_API,m,p1,p2,p3,p4,p5);}
+#define A2D_TRACE_API6(m,p1,p2,p3,p4,p5,p6) {if (a2d_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_6(TRACE_LAYER_A2D, TRACE_TYPE_API,m,p1,p2,p3,p4,p5,p6);}
+
+/* Define tracing for the VDP profile
+*/
+#define VDP_TRACE_ERROR0(m) {if (vdp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_0(TRACE_LAYER_AVP, TRACE_TYPE_ERROR,m);}
+#define VDP_TRACE_ERROR1(m,p1) {if (vdp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_1(TRACE_LAYER_AVP, TRACE_TYPE_ERROR,m,p1);}
+#define VDP_TRACE_ERROR2(m,p1,p2) {if (vdp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_2(TRACE_LAYER_AVP, TRACE_TYPE_ERROR,m,p1,p2);}
+#define VDP_TRACE_ERROR3(m,p1,p2,p3) {if (vdp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_3(TRACE_LAYER_AVP, TRACE_TYPE_ERROR,m,p1,p2,p3);}
+#define VDP_TRACE_ERROR4(m,p1,p2,p3,p4) {if (vdp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_4(TRACE_LAYER_AVP, TRACE_TYPE_ERROR,m,p1,p2,p3,p4);}
+#define VDP_TRACE_ERROR5(m,p1,p2,p3,p4,p5) {if (vdp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_5(TRACE_LAYER_AVP, TRACE_TYPE_ERROR,m,p1,p2,p3,p4,p5);}
+#define VDP_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6) {if (vdp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_6(TRACE_LAYER_AVP, TRACE_TYPE_ERROR,m,p1,p2,p3,p4,p5,p6);}
+
+#define VDP_TRACE_WARNING0(m) {if (vdp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_0(TRACE_LAYER_AVP, TRACE_TYPE_WARNING,m);}
+#define VDP_TRACE_WARNING1(m,p1) {if (vdp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_1(TRACE_LAYER_AVP, TRACE_TYPE_WARNING,m,p1);}
+#define VDP_TRACE_WARNING2(m,p1,p2) {if (vdp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_2(TRACE_LAYER_AVP, TRACE_TYPE_WARNING,m,p1,p2);}
+#define VDP_TRACE_WARNING3(m,p1,p2,p3) {if (vdp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_3(TRACE_LAYER_AVP, TRACE_TYPE_WARNING,m,p1,p2,p3);}
+#define VDP_TRACE_WARNING4(m,p1,p2,p3,p4) {if (vdp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_4(TRACE_LAYER_AVP, TRACE_TYPE_WARNING,m,p1,p2,p3,p4);}
+#define VDP_TRACE_WARNING5(m,p1,p2,p3,p4,p5) {if (vdp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_5(TRACE_LAYER_AVP, TRACE_TYPE_WARNING,m,p1,p2,p3,p4,p5);}
+#define VDP_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6) {if (vdp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_6(TRACE_LAYER_AVP, TRACE_TYPE_WARNING,m,p1,p2,p3,p4,p5,p6);}
+
+#define VDP_TRACE_EVENT0(m) {if (vdp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_0(TRACE_LAYER_AVP, TRACE_TYPE_EVENT,m);}
+#define VDP_TRACE_EVENT1(m,p1) {if (vdp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_1(TRACE_LAYER_AVP, TRACE_TYPE_EVENT,m, p1);}
+#define VDP_TRACE_EVENT2(m,p1,p2) {if (vdp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_2(TRACE_LAYER_AVP, TRACE_TYPE_EVENT,m,p1,p2);}
+#define VDP_TRACE_EVENT3(m,p1,p2,p3) {if (vdp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_3(TRACE_LAYER_AVP, TRACE_TYPE_EVENT,m,p1,p2,p3);}
+#define VDP_TRACE_EVENT4(m,p1,p2,p3,p4) {if (vdp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_4(TRACE_LAYER_AVP, TRACE_TYPE_EVENT,m,p1,p2,p3,p4);}
+#define VDP_TRACE_EVENT5(m,p1,p2,p3,p4,p5) {if (vdp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_5(TRACE_LAYER_AVP, TRACE_TYPE_EVENT,m,p1,p2,p3,p4,p5);}
+#define VDP_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6) {if (vdp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_6(TRACE_LAYER_AVP, TRACE_TYPE_EVENT,m,p1,p2,p3,p4,p5,p6);}
+
+#define VDP_TRACE_DEBUG0(m) {if (vdp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_0(TRACE_LAYER_AVP, TRACE_TYPE_DEBUG,m);}
+#define VDP_TRACE_DEBUG1(m,p1) {if (vdp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_1(TRACE_LAYER_AVP, TRACE_TYPE_DEBUG,m,p1);}
+#define VDP_TRACE_DEBUG2(m,p1,p2) {if (vdp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_2(TRACE_LAYER_AVP, TRACE_TYPE_DEBUG,m,p1,p2);}
+#define VDP_TRACE_DEBUG3(m,p1,p2,p3) {if (vdp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_3(TRACE_LAYER_AVP, TRACE_TYPE_DEBUG,m,p1,p2,p3);}
+#define VDP_TRACE_DEBUG4(m,p1,p2,p3,p4) {if (vdp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_4(TRACE_LAYER_AVP, TRACE_TYPE_DEBUG,m,p1,p2,p3,p4);}
+#define VDP_TRACE_DEBUG5(m,p1,p2,p3,p4,p5) {if (vdp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_5(TRACE_LAYER_AVP, TRACE_TYPE_DEBUG,m,p1,p2,p3,p4,p5);}
+#define VDP_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) {if (vdp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_6(TRACE_LAYER_AVP, TRACE_TYPE_DEBUG,m,p1,p2,p3,p4,p5,p6);}
+
+#define VDP_TRACE_API0(m) {if (vdp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_0(TRACE_LAYER_AVP, TRACE_TYPE_API,m);}
+#define VDP_TRACE_API1(m,p1) {if (vdp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_1(TRACE_LAYER_AVP, TRACE_TYPE_API,m, p1);}
+#define VDP_TRACE_API2(m,p1,p2) {if (vdp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_2(TRACE_LAYER_AVP, TRACE_TYPE_API,m,p1,p2);}
+#define VDP_TRACE_API3(m,p1,p2,p3) {if (vdp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_3(TRACE_LAYER_AVP, TRACE_TYPE_API,m,p1,p2,p3);}
+#define VDP_TRACE_API4(m,p1,p2,p3,p4) {if (vdp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_4(TRACE_LAYER_AVP, TRACE_TYPE_API,m,p1,p2,p3,p4);}
+#define VDP_TRACE_API5(m,p1,p2,p3,p4,p5) {if (vdp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_5(TRACE_LAYER_AVP, TRACE_TYPE_API,m,p1,p2,p3,p4,p5);}
+#define VDP_TRACE_API6(m,p1,p2,p3,p4,p5,p6) {if (vdp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_6(TRACE_LAYER_AVP, TRACE_TYPE_API,m,p1,p2,p3,p4,p5,p6);}
+
+
+/* Define tracing for the LM unit
+*/
+#define LMP_TRACE_ERROR0(m) {if (lmp_trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_0(TRACE_LAYER_LM, TRACE_TYPE_ERROR, m);}
+#define LMP_TRACE_ERROR1(m,p1) {if (lmp_trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_1(TRACE_LAYER_LM, TRACE_TYPE_ERROR, m,p1);}
+#define LMP_TRACE_ERROR2(m,p1,p2) {if (lmp_trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_2(TRACE_LAYER_LM, TRACE_TYPE_ERROR, m,p1,p2);}
+#define LMP_TRACE_ERROR3(m,p1,p2,p3) {if (lmp_trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_3(TRACE_LAYER_LM, TRACE_TYPE_ERROR, m,p1,p2,p3);}
+#define LMP_TRACE_ERROR4(m,p1,p2,p3,p4) {if (lmp_trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_4(TRACE_LAYER_LM, TRACE_TYPE_ERROR, m,p1,p2,p3,p4);}
+#define LMP_TRACE_ERROR5(m,p1,p2,p3,p4,p5) {if (lmp_trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_5(TRACE_LAYER_LM, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5);}
+#define LMP_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6) {if (lmp_trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_6(TRACE_LAYER_LM, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5,p6);}
+
+#define LMP_TRACE_WARNING0(m) {if (lmp_trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_0(TRACE_LAYER_LM, TRACE_TYPE_WARNING, m);}
+#define LMP_TRACE_WARNING1(m,p1) {if (lmp_trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_1(TRACE_LAYER_LM, TRACE_TYPE_WARNING, m,p1);}
+#define LMP_TRACE_WARNING2(m,p1,p2) {if (lmp_trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_2(TRACE_LAYER_LM, TRACE_TYPE_WARNING, m,p1,p2);}
+#define LMP_TRACE_WARNING3(m,p1,p2,p3) {if (lmp_trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_3(TRACE_LAYER_LM, TRACE_TYPE_WARNING, m,p1,p2,p3);}
+#define LMP_TRACE_WARNING4(m,p1,p2,p3,p4) {if (lmp_trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_4(TRACE_LAYER_LM, TRACE_TYPE_WARNING, m,p1,p2,p3,p4);}
+#define LMP_TRACE_WARNING5(m,p1,p2,p3,p4,p5) {if (lmp_trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_5(TRACE_LAYER_LM, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5);}
+#define LMP_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6) {if (lmp_trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_6(TRACE_LAYER_LM, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5,p6);}
+
+#define LMP_TRACE_EVENT0(m) {if (lmp_trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_0(TRACE_LAYER_LM, TRACE_TYPE_EVENT, m);}
+#define LMP_TRACE_EVENT1(m,p1) {if (lmp_trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_1(TRACE_LAYER_LM, TRACE_TYPE_EVENT, m, p1);}
+#define LMP_TRACE_EVENT2(m,p1,p2) {if (lmp_trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_2(TRACE_LAYER_LM, TRACE_TYPE_EVENT, m,p1,p2);}
+#define LMP_TRACE_EVENT3(m,p1,p2,p3) {if (lmp_trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_3(TRACE_LAYER_LM, TRACE_TYPE_EVENT, m,p1,p2,p3);}
+#define LMP_TRACE_EVENT4(m,p1,p2,p3,p4) {if (lmp_trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_4(TRACE_LAYER_LM, TRACE_TYPE_EVENT, m,p1,p2,p3,p4);}
+#define LMP_TRACE_EVENT5(m,p1,p2,p3,p4,p5) {if (lmp_trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_5(TRACE_LAYER_LM, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5);}
+#define LMP_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6) {if (lmp_trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_6(TRACE_LAYER_LM, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5,p6);}
+
+#define LMP_TRACE_DEBUG0(m) {if (lmp_trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_0(TRACE_LAYER_LM, TRACE_TYPE_DEBUG, m);}
+#define LMP_TRACE_DEBUG1(m,p1) {if (lmp_trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_1(TRACE_LAYER_LM, TRACE_TYPE_DEBUG, m,p1);}
+#define LMP_TRACE_DEBUG2(m,p1,p2) {if (lmp_trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_2(TRACE_LAYER_LM, TRACE_TYPE_DEBUG, m,p1,p2);}
+#define LMP_TRACE_DEBUG3(m,p1,p2,p3) {if (lmp_trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_3(TRACE_LAYER_LM, TRACE_TYPE_DEBUG, m,p1,p2,p3);}
+#define LMP_TRACE_DEBUG4(m,p1,p2,p3,p4) {if (lmp_trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_4(TRACE_LAYER_LM, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4);}
+#define LMP_TRACE_DEBUG5(m,p1,p2,p3,p4,p5) {if (lmp_trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_5(TRACE_LAYER_LM, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5);}
+#define LMP_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) {if (lmp_trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_6(TRACE_LAYER_LM, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5,p6);}
+
+/* Define tracing for the LC unit
+*/
+#define LC_TRACE_ERROR0(m) {if (lc_trace_level & trace_map[BT_TRACE_LEVEL_ERROR]) BT_TRACE_0(TRACE_LAYER_LC, TRACE_TYPE_ERROR, m);}
+#define LC_TRACE_ERROR1(m,p1) {if (lc_trace_level & trace_map[BT_TRACE_LEVEL_ERROR]) BT_TRACE_1(TRACE_LAYER_LC, TRACE_TYPE_ERROR, m,p1);}
+#define LC_TRACE_ERROR2(m,p1,p2) {if (lc_trace_level & trace_map[BT_TRACE_LEVEL_ERROR]) BT_TRACE_2(TRACE_LAYER_LC, TRACE_TYPE_ERROR, m,p1,p2);}
+#define LC_TRACE_ERROR3(m,p1,p2,p3) {if (lc_trace_level & trace_map[BT_TRACE_LEVEL_ERROR]) BT_TRACE_3(TRACE_LAYER_LC, TRACE_TYPE_ERROR, m,p1,p2,p3);}
+#define LC_TRACE_ERROR4(m,p1,p2,p3,p4) {if (lc_trace_level & trace_map[BT_TRACE_LEVEL_ERROR]) BT_TRACE_4(TRACE_LAYER_LC, TRACE_TYPE_ERROR, m,p1,p2,p3,p4);}
+#define LC_TRACE_ERROR5(m,p1,p2,p3,p4,p5) {if (lc_trace_level & trace_map[BT_TRACE_LEVEL_ERROR]) BT_TRACE_5(TRACE_LAYER_LC, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5);}
+#define LC_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6) {if (lc_trace_level & trace_map[BT_TRACE_LEVEL_ERROR]) BT_TRACE_6(TRACE_LAYER_LC, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5,p6);}
+
+#define LC_TRACE_WARNING0(m) {if (lc_trace_level & trace_map[BT_TRACE_LEVEL_WARNING]) BT_TRACE_0(TRACE_LAYER_LC, TRACE_TYPE_WARNING, m);}
+#define LC_TRACE_WARNING1(m,p1) {if (lc_trace_level & trace_map[BT_TRACE_LEVEL_WARNING]) BT_TRACE_1(TRACE_LAYER_LC, TRACE_TYPE_WARNING, m,p1);}
+#define LC_TRACE_WARNING2(m,p1,p2) {if (lc_trace_level & trace_map[BT_TRACE_LEVEL_WARNING]) BT_TRACE_2(TRACE_LAYER_LC, TRACE_TYPE_WARNING, m,p1,p2);}
+#define LC_TRACE_WARNING3(m,p1,p2,p3) {if (lc_trace_level & trace_map[BT_TRACE_LEVEL_WARNING]) BT_TRACE_3(TRACE_LAYER_LC, TRACE_TYPE_WARNING, m,p1,p2,p3);}
+#define LC_TRACE_WARNING4(m,p1,p2,p3,p4) {if (lc_trace_level & trace_map[BT_TRACE_LEVEL_WARNING]) BT_TRACE_4(TRACE_LAYER_LC, TRACE_TYPE_WARNING, m,p1,p2,p3,p4);}
+#define LC_TRACE_WARNING5(m,p1,p2,p3,p4,p5) {if (lc_trace_level & trace_map[BT_TRACE_LEVEL_WARNING]) BT_TRACE_5(TRACE_LAYER_LC, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5);}
+#define LC_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6) {if (lc_trace_level & trace_map[BT_TRACE_LEVEL_WARNING]) BT_TRACE_6(TRACE_LAYER_LC, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5,p6);}
+
+#define LC_TRACE_EVENT0(m) {if (lc_trace_level & trace_map[BT_TRACE_LEVEL_EVENT]) BT_TRACE_0(TRACE_LAYER_LC, TRACE_TYPE_EVENT, m);}
+#define LC_TRACE_EVENT1(m,p1) {if (lc_trace_level & trace_map[BT_TRACE_LEVEL_EVENT]) BT_TRACE_1(TRACE_LAYER_LC, TRACE_TYPE_EVENT, m, p1);}
+#define LC_TRACE_EVENT2(m,p1,p2) {if (lc_trace_level & trace_map[BT_TRACE_LEVEL_EVENT]) BT_TRACE_2(TRACE_LAYER_LC, TRACE_TYPE_EVENT, m,p1,p2);}
+#define LC_TRACE_EVENT3(m,p1,p2,p3) {if (lc_trace_level & trace_map[BT_TRACE_LEVEL_EVENT]) BT_TRACE_3(TRACE_LAYER_LC, TRACE_TYPE_EVENT, m,p1,p2,p3);}
+#define LC_TRACE_EVENT4(m,p1,p2,p3,p4) {if (lc_trace_level & trace_map[BT_TRACE_LEVEL_EVENT]) BT_TRACE_4(TRACE_LAYER_LC, TRACE_TYPE_EVENT, m,p1,p2,p3,p4);}
+#define LC_TRACE_EVENT5(m,p1,p2,p3,p4,p5) {if (lc_trace_level & trace_map[BT_TRACE_LEVEL_EVENT]) BT_TRACE_5(TRACE_LAYER_LC, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5);}
+#define LC_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6) {if (lc_trace_level & trace_map[BT_TRACE_LEVEL_EVENT]) BT_TRACE_6(TRACE_LAYER_LC, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5,p6);}
+
+#define LC_TRACE_DEBUG0(m) {if (lc_trace_level & trace_map[BT_TRACE_LEVEL_DEBUG]) BT_TRACE_0(TRACE_LAYER_LC, TRACE_TYPE_DEBUG, m);}
+#define LC_TRACE_DEBUG1(m,p1) {if (lc_trace_level & trace_map[BT_TRACE_LEVEL_DEBUG]) BT_TRACE_1(TRACE_LAYER_LC, TRACE_TYPE_DEBUG, m,p1);}
+#define LC_TRACE_DEBUG2(m,p1,p2) {if (lc_trace_level & trace_map[BT_TRACE_LEVEL_DEBUG]) BT_TRACE_2(TRACE_LAYER_LC, TRACE_TYPE_DEBUG, m,p1,p2);}
+#define LC_TRACE_DEBUG3(m,p1,p2,p3) {if (lc_trace_level & trace_map[BT_TRACE_LEVEL_DEBUG]) BT_TRACE_3(TRACE_LAYER_LC, TRACE_TYPE_DEBUG, m,p1,p2,p3);}
+#define LC_TRACE_DEBUG4(m,p1,p2,p3,p4) {if (lc_trace_level & trace_map[BT_TRACE_LEVEL_DEBUG]) BT_TRACE_5(TRACE_LAYER_LC, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5);}
+#define LC_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) {if (lc_trace_level & trace_map[BT_TRACE_LEVEL_DEBUG]) BT_TRACE_6(TRACE_LAYER_LC, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5,p6);}
+
+/* Define tracing for the Serial Dongle Application SDA
+*/
+#define SDA_TRACE_ERROR0(m) {if (sda_config_cb.sda_trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_0(m);}
+#define SDA_TRACE_ERROR1(m,p1) {if (sda_config_cb.sda_trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_1(m,p1);}
+#define SDA_TRACE_ERROR2(m,p1,p2) {if (sda_config_cb.sda_trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_2(m,p1,p2);}
+#define SDA_TRACE_ERROR3(m,p1,p2,p3) {if (sda_config_cb.sda_trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_3(m,p1,p2,p3);}
+#define SDA_TRACE_ERROR4(m,p1,p2,p3,p4) {if (sda_config_cb.sda_trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_4(m,p1,p2,p3,p4);}
+#define SDA_TRACE_ERROR5(m,p1,p2,p3,p4,p5) {if (sda_config_cb.sda_trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_5(m,p1,p2,p3,p4,p5);}
+#define SDA_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6) {if (sda_config_cb.sda_trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_6(m,p1,p2,p3,p4,p5,p6);}
+
+#define SDA_TRACE_WARNING0(m) {if (sda_config_cb.sda_trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_0(m);}
+#define SDA_TRACE_WARNING1(m,p1) {if (sda_config_cb.sda_trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_1(m,p1);}
+#define SDA_TRACE_WARNING2(m,p1,p2) {if (sda_config_cb.sda_trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_2(m,p1,p2);}
+#define SDA_TRACE_WARNING3(m,p1,p2,p3) {if (sda_config_cb.sda_trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_3(m,p1,p2,p3);}
+#define SDA_TRACE_WARNING4(m,p1,p2,p3,p4) {if (sda_config_cb.sda_trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_4(m,p1,p2,p3,p4);}
+#define SDA_TRACE_WARNING5(m,p1,p2,p3,p4,p5) {if (sda_config_cb.sda_trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_5(m,p1,p2,p3,p4,p5);}
+#define SDA_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6) {if (sda_config_cb.sda_trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_6(m,p1,p2,p3,p4,p5,p6);}
+
+#define SDA_TRACE_EVENT0(m) {if (sda_config_cb.sda_trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_0(m);}
+#define SDA_TRACE_EVENT1(m,p1) {if (sda_config_cb.sda_trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_1(m, p1);}
+#define SDA_TRACE_EVENT2(m,p1,p2) {if (sda_config_cb.sda_trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_2(m,p1,p2);}
+#define SDA_TRACE_EVENT3(m,p1,p2,p3) {if (sda_config_cb.sda_trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_3(m,p1,p2,p3);}
+#define SDA_TRACE_EVENT4(m,p1,p2,p3,p4) {if (sda_config_cb.sda_trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_4(m,p1,p2,p3,p4);}
+#define SDA_TRACE_EVENT5(m,p1,p2,p3,p4,p5) {if (sda_config_cb.sda_trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_5(m,p1,p2,p3,p4,p5);}
+#define SDA_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6) {if (sda_config_cb.sda_trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_6(m,p1,p2,p3,p4,p5,p6);}
+
+#define SDA_TRACE_DEBUG0(m) {if (sda_config_cb.sda_trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_0(m);}
+#define SDA_TRACE_DEBUG1(m,p1) {if (sda_config_cb.sda_trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_1(m,p1);}
+#define SDA_TRACE_DEBUG2(m,p1,p2) {if (sda_config_cb.sda_trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_2(m,p1,p2);}
+#define SDA_TRACE_DEBUG3(m,p1,p2,p3) {if (sda_config_cb.sda_trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_3(m,p1,p2,p3);}
+#define SDA_TRACE_DEBUG4(m,p1,p2,p3,p4) {if (sda_config_cb.sda_trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_4(m,p1,p2,p3,p4);}
+#define SDA_TRACE_DEBUG5(m,p1,p2,p3,p4,p5) {if (sda_config_cb.sda_trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_5(m,p1,p2,p3,p4,p5);}
+#define SDA_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) {if (sda_config_cb.sda_trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_6(m,p1,p2,p3,p4,p5,p6);}
+
+/* AVDTP
+*/
+#define AVDT_TRACE_ERROR0(m) {if (avdt_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_0(TRACE_LAYER_AVP, TRACE_TYPE_ERROR, m);}
+#define AVDT_TRACE_ERROR1(m,p1) {if (avdt_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_1(TRACE_LAYER_AVP, TRACE_TYPE_ERROR, m,p1);}
+#define AVDT_TRACE_ERROR2(m,p1,p2) {if (avdt_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_2(TRACE_LAYER_AVP, TRACE_TYPE_ERROR, m,p1,p2);}
+#define AVDT_TRACE_ERROR3(m,p1,p2,p3) {if (avdt_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_3(TRACE_LAYER_AVP, TRACE_TYPE_ERROR, m,p1,p2,p3);}
+#define AVDT_TRACE_ERROR4(m,p1,p2,p3,p4) {if (avdt_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_4(TRACE_LAYER_AVP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4);}
+#define AVDT_TRACE_ERROR5(m,p1,p2,p3,p4,p5) {if (avdt_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_5(TRACE_LAYER_AVP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5);}
+#define AVDT_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6) {if (avdt_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_6(TRACE_LAYER_AVP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5,p6);}
+
+#define AVDT_TRACE_WARNING0(m) {if (avdt_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_0(TRACE_LAYER_AVP, TRACE_TYPE_WARNING, m);}
+#define AVDT_TRACE_WARNING1(m,p1) {if (avdt_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_1(TRACE_LAYER_AVP, TRACE_TYPE_WARNING, m,p1);}
+#define AVDT_TRACE_WARNING2(m,p1,p2) {if (avdt_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_2(TRACE_LAYER_AVP, TRACE_TYPE_WARNING, m,p1,p2);}
+#define AVDT_TRACE_WARNING3(m,p1,p2,p3) {if (avdt_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_3(TRACE_LAYER_AVP, TRACE_TYPE_WARNING, m,p1,p2,p3);}
+#define AVDT_TRACE_WARNING4(m,p1,p2,p3,p4) {if (avdt_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_4(TRACE_LAYER_AVP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4);}
+#define AVDT_TRACE_WARNING5(m,p1,p2,p3,p4,p5) {if (avdt_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_5(TRACE_LAYER_AVP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5);}
+#define AVDT_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6) {if (avdt_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_6(TRACE_LAYER_AVP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5,p6);}
+
+#define AVDT_TRACE_EVENT0(m) {if (avdt_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_0(TRACE_LAYER_AVP, TRACE_TYPE_EVENT, m);}
+#define AVDT_TRACE_EVENT1(m,p1) {if (avdt_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_1(TRACE_LAYER_AVP, TRACE_TYPE_EVENT, m, p1);}
+#define AVDT_TRACE_EVENT2(m,p1,p2) {if (avdt_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_2(TRACE_LAYER_AVP, TRACE_TYPE_EVENT, m,p1,p2);}
+#define AVDT_TRACE_EVENT3(m,p1,p2,p3) {if (avdt_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_3(TRACE_LAYER_AVP, TRACE_TYPE_EVENT, m,p1,p2,p3);}
+#define AVDT_TRACE_EVENT4(m,p1,p2,p3,p4) {if (avdt_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_4(TRACE_LAYER_AVP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4);}
+#define AVDT_TRACE_EVENT5(m,p1,p2,p3,p4,p5) {if (avdt_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_5(TRACE_LAYER_AVP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5);}
+#define AVDT_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6) {if (avdt_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_6(TRACE_LAYER_AVP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5,p6);}
+
+#define AVDT_TRACE_DEBUG0(m) {if (avdt_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_0(TRACE_LAYER_AVP, TRACE_TYPE_DEBUG, m);}
+#define AVDT_TRACE_DEBUG1(m,p1) {if (avdt_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_1(TRACE_LAYER_AVP, TRACE_TYPE_DEBUG, m,p1);}
+#define AVDT_TRACE_DEBUG2(m,p1,p2) {if (avdt_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_2(TRACE_LAYER_AVP, TRACE_TYPE_DEBUG, m,p1,p2);}
+#define AVDT_TRACE_DEBUG3(m,p1,p2,p3) {if (avdt_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_3(TRACE_LAYER_AVP, TRACE_TYPE_DEBUG, m,p1,p2,p3);}
+#define AVDT_TRACE_DEBUG4(m,p1,p2,p3,p4) {if (avdt_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_4(TRACE_LAYER_AVP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4);}
+#define AVDT_TRACE_DEBUG5(m,p1,p2,p3,p4,p5) {if (avdt_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_5(TRACE_LAYER_AVP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5);}
+#define AVDT_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) {if (avdt_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_6(TRACE_LAYER_AVP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5,p6);}
+
+#define AVDT_TRACE_API0(m) {if (avdt_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_0(TRACE_LAYER_AVP, TRACE_TYPE_API, m);}
+#define AVDT_TRACE_API1(m,p1) {if (avdt_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_1(TRACE_LAYER_AVP, TRACE_TYPE_API, m,p1);}
+#define AVDT_TRACE_API2(m,p1,p2) {if (avdt_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_2(TRACE_LAYER_AVP, TRACE_TYPE_API, m,p1,p2);}
+#define AVDT_TRACE_API3(m,p1,p2,p3) {if (avdt_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_3(TRACE_LAYER_AVP, TRACE_TYPE_API, m,p1,p2,p3);}
+#define AVDT_TRACE_API4(m,p1,p2,p3,p4) {if (avdt_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_4(TRACE_LAYER_AVP, TRACE_TYPE_API, m,p1,p2,p3,p4);}
+#define AVDT_TRACE_API5(m,p1,p2,p3,p4,p5) {if (avdt_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_5(TRACE_LAYER_AVP, TRACE_TYPE_API, m,p1,p2,p3,p4,p5);}
+#define AVDT_TRACE_API6(m,p1,p2,p3,p4,p5,p6) {if (avdt_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_6(TRACE_LAYER_AVP, TRACE_TYPE_API, m,p1,p2,p3,p4,p5,p6);}
+
+/* Define tracing for the AVCTP protocol
+*/
+#define AVCT_TRACE_ERROR0(m) {if (avct_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_0(TRACE_LAYER_AVP, TRACE_TYPE_ERROR, m);}
+#define AVCT_TRACE_ERROR1(m,p1) {if (avct_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_1(TRACE_LAYER_AVP, TRACE_TYPE_ERROR, m,p1);}
+#define AVCT_TRACE_ERROR2(m,p1,p2) {if (avct_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_2(TRACE_LAYER_AVP, TRACE_TYPE_ERROR, m,p1,p2);}
+#define AVCT_TRACE_ERROR3(m,p1,p2,p3) {if (avct_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_3(TRACE_LAYER_AVP, TRACE_TYPE_ERROR, m,p1,p2,p3);}
+#define AVCT_TRACE_ERROR4(m,p1,p2,p3,p4) {if (avct_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_4(TRACE_LAYER_AVP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4);}
+#define AVCT_TRACE_ERROR5(m,p1,p2,p3,p4,p5) {if (avct_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_5(TRACE_LAYER_AVP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5);}
+#define AVCT_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6) {if (avct_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_6(TRACE_LAYER_AVP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5,p6);}
+
+#define AVCT_TRACE_WARNING0(m) {if (avct_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_0(TRACE_LAYER_AVP, TRACE_TYPE_WARNING, m);}
+#define AVCT_TRACE_WARNING1(m,p1) {if (avct_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_1(TRACE_LAYER_AVP, TRACE_TYPE_WARNING, m,p1);}
+#define AVCT_TRACE_WARNING2(m,p1,p2) {if (avct_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_2(TRACE_LAYER_AVP, TRACE_TYPE_WARNING, m,p1,p2);}
+#define AVCT_TRACE_WARNING3(m,p1,p2,p3) {if (avct_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_3(TRACE_LAYER_AVP, TRACE_TYPE_WARNING, m,p1,p2,p3);}
+#define AVCT_TRACE_WARNING4(m,p1,p2,p3,p4) {if (avct_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_4(TRACE_LAYER_AVP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4);}
+#define AVCT_TRACE_WARNING5(m,p1,p2,p3,p4,p5) {if (avct_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_5(TRACE_LAYER_AVP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5);}
+#define AVCT_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6) {if (avct_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_6(TRACE_LAYER_AVP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5,p6);}
+
+#define AVCT_TRACE_EVENT0(m) {if (avct_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_0(TRACE_LAYER_AVP, TRACE_TYPE_EVENT, m);}
+#define AVCT_TRACE_EVENT1(m,p1) {if (avct_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_1(TRACE_LAYER_AVP, TRACE_TYPE_EVENT, m, p1);}
+#define AVCT_TRACE_EVENT2(m,p1,p2) {if (avct_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_2(TRACE_LAYER_AVP, TRACE_TYPE_EVENT, m,p1,p2);}
+#define AVCT_TRACE_EVENT3(m,p1,p2,p3) {if (avct_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_3(TRACE_LAYER_AVP, TRACE_TYPE_EVENT, m,p1,p2,p3);}
+#define AVCT_TRACE_EVENT4(m,p1,p2,p3,p4) {if (avct_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_4(TRACE_LAYER_AVP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4);}
+#define AVCT_TRACE_EVENT5(m,p1,p2,p3,p4,p5) {if (avct_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_5(TRACE_LAYER_AVP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5);}
+#define AVCT_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6) {if (avct_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_6(TRACE_LAYER_AVP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5,p6);}
+
+#define AVCT_TRACE_DEBUG0(m) {if (avct_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_0(TRACE_LAYER_AVP, TRACE_TYPE_DEBUG, m);}
+#define AVCT_TRACE_DEBUG1(m,p1) {if (avct_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_1(TRACE_LAYER_AVP, TRACE_TYPE_DEBUG, m,p1);}
+#define AVCT_TRACE_DEBUG2(m,p1,p2) {if (avct_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_2(TRACE_LAYER_AVP, TRACE_TYPE_DEBUG, m,p1,p2);}
+#define AVCT_TRACE_DEBUG3(m,p1,p2,p3) {if (avct_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_3(TRACE_LAYER_AVP, TRACE_TYPE_DEBUG, m,p1,p2,p3);}
+#define AVCT_TRACE_DEBUG4(m,p1,p2,p3,p4) {if (avct_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_4(TRACE_LAYER_AVP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4);}
+#define AVCT_TRACE_DEBUG5(m,p1,p2,p3,p4,p5) {if (avct_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_5(TRACE_LAYER_AVP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5);}
+#define AVCT_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) {if (avct_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_6(TRACE_LAYER_AVP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5,p6);}
+
+#define AVCT_TRACE_API0(m) {if (avct_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_0(TRACE_LAYER_AVP, TRACE_TYPE_API, m);}
+#define AVCT_TRACE_API1(m,p1) {if (avct_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_1(TRACE_LAYER_AVP, TRACE_TYPE_API, m,p1);}
+#define AVCT_TRACE_API2(m,p1,p2) {if (avct_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_2(TRACE_LAYER_AVP, TRACE_TYPE_API, m,p1,p2);}
+#define AVCT_TRACE_API3(m,p1,p2,p3) {if (avct_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_3(TRACE_LAYER_AVP, TRACE_TYPE_API, m,p1,p2,p3);}
+#define AVCT_TRACE_API4(m,p1,p2,p3,p4) {if (avct_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_4(TRACE_LAYER_AVP, TRACE_TYPE_API, m,p1,p2,p3,p4);}
+#define AVCT_TRACE_API5(m,p1,p2,p3,p4,p5) {if (avct_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_5(TRACE_LAYER_AVP, TRACE_TYPE_API, m,p1,p2,p3,p4,p5);}
+#define AVCT_TRACE_API6(m,p1,p2,p3,p4,p5,p6) {if (avct_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_6(TRACE_LAYER_AVP, TRACE_TYPE_API, m,p1,p2,p3,p4,p5,p6);}
+
+
+/* Define tracing for the AVRCP profile
+*/
+#define AVRC_TRACE_ERROR0(m) {if (avrc_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_0(TRACE_LAYER_AVP, TRACE_TYPE_ERROR,m);}
+#define AVRC_TRACE_ERROR1(m,p1) {if (avrc_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_1(TRACE_LAYER_AVP, TRACE_TYPE_ERROR,m,p1);}
+#define AVRC_TRACE_ERROR2(m,p1,p2) {if (avrc_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_2(TRACE_LAYER_AVP, TRACE_TYPE_ERROR,m,p1,p2);}
+#define AVRC_TRACE_ERROR3(m,p1,p2,p3) {if (avrc_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_3(TRACE_LAYER_AVP, TRACE_TYPE_ERROR,m,p1,p2,p3);}
+#define AVRC_TRACE_ERROR4(m,p1,p2,p3,p4) {if (avrc_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_4(TRACE_LAYER_AVP, TRACE_TYPE_ERROR,m,p1,p2,p3,p4);}
+#define AVRC_TRACE_ERROR5(m,p1,p2,p3,p4,p5) {if (avrc_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_5(TRACE_LAYER_AVP, TRACE_TYPE_ERROR,m,p1,p2,p3,p4,p5);}
+#define AVRC_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6) {if (avrc_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_6(TRACE_LAYER_AVP, TRACE_TYPE_ERROR,m,p1,p2,p3,p4,p5,p6);}
+
+#define AVRC_TRACE_WARNING0(m) {if (avrc_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_0(TRACE_LAYER_AVP, TRACE_TYPE_WARNING,m);}
+#define AVRC_TRACE_WARNING1(m,p1) {if (avrc_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_1(TRACE_LAYER_AVP, TRACE_TYPE_WARNING,m,p1);}
+#define AVRC_TRACE_WARNING2(m,p1,p2) {if (avrc_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_2(TRACE_LAYER_AVP, TRACE_TYPE_WARNING,m,p1,p2);}
+#define AVRC_TRACE_WARNING3(m,p1,p2,p3) {if (avrc_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_3(TRACE_LAYER_AVP, TRACE_TYPE_WARNING,m,p1,p2,p3);}
+#define AVRC_TRACE_WARNING4(m,p1,p2,p3,p4) {if (avrc_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_4(TRACE_LAYER_AVP, TRACE_TYPE_WARNING,m,p1,p2,p3,p4);}
+#define AVRC_TRACE_WARNING5(m,p1,p2,p3,p4,p5) {if (avrc_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_5(TRACE_LAYER_AVP, TRACE_TYPE_WARNING,m,p1,p2,p3,p4,p5);}
+#define AVRC_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6) {if (avrc_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_6(TRACE_LAYER_AVP, TRACE_TYPE_WARNING,m,p1,p2,p3,p4,p5,p6);}
+
+#define AVRC_TRACE_EVENT0(m) {if (avrc_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_0(TRACE_LAYER_AVP, TRACE_TYPE_EVENT,m);}
+#define AVRC_TRACE_EVENT1(m,p1) {if (avrc_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_1(TRACE_LAYER_AVP, TRACE_TYPE_EVENT,m, p1);}
+#define AVRC_TRACE_EVENT2(m,p1,p2) {if (avrc_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_2(TRACE_LAYER_AVP, TRACE_TYPE_EVENT,m,p1,p2);}
+#define AVRC_TRACE_EVENT3(m,p1,p2,p3) {if (avrc_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_3(TRACE_LAYER_AVP, TRACE_TYPE_EVENT,m,p1,p2,p3);}
+#define AVRC_TRACE_EVENT4(m,p1,p2,p3,p4) {if (avrc_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_4(TRACE_LAYER_AVP, TRACE_TYPE_EVENT,m,p1,p2,p3,p4);}
+#define AVRC_TRACE_EVENT5(m,p1,p2,p3,p4,p5) {if (avrc_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_5(TRACE_LAYER_AVP, TRACE_TYPE_EVENT,m,p1,p2,p3,p4,p5);}
+#define AVRC_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6) {if (avrc_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_6(TRACE_LAYER_AVP, TRACE_TYPE_EVENT,m,p1,p2,p3,p4,p5,p6);}
+
+#define AVRC_TRACE_DEBUG0(m) {if (avrc_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_0(TRACE_LAYER_AVP, TRACE_TYPE_DEBUG,m);}
+#define AVRC_TRACE_DEBUG1(m,p1) {if (avrc_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_1(TRACE_LAYER_AVP, TRACE_TYPE_DEBUG,m,p1);}
+#define AVRC_TRACE_DEBUG2(m,p1,p2) {if (avrc_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_2(TRACE_LAYER_AVP, TRACE_TYPE_DEBUG,m,p1,p2);}
+#define AVRC_TRACE_DEBUG3(m,p1,p2,p3) {if (avrc_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_3(TRACE_LAYER_AVP, TRACE_TYPE_DEBUG,m,p1,p2,p3);}
+#define AVRC_TRACE_DEBUG4(m,p1,p2,p3,p4) {if (avrc_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_4(TRACE_LAYER_AVP, TRACE_TYPE_DEBUG,m,p1,p2,p3,p4);}
+#define AVRC_TRACE_DEBUG5(m,p1,p2,p3,p4,p5) {if (avrc_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_5(TRACE_LAYER_AVP, TRACE_TYPE_DEBUG,m,p1,p2,p3,p4,p5);}
+#define AVRC_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) {if (avrc_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_6(TRACE_LAYER_AVP, TRACE_TYPE_DEBUG,m,p1,p2,p3,p4,p5,p6);}
+
+#define AVRC_TRACE_API0(m) {if (avrc_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_0(TRACE_LAYER_AVP, TRACE_TYPE_API,m);}
+#define AVRC_TRACE_API1(m,p1) {if (avrc_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_1(TRACE_LAYER_AVP, TRACE_TYPE_API,m, p1);}
+#define AVRC_TRACE_API2(m,p1,p2) {if (avrc_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_2(TRACE_LAYER_AVP, TRACE_TYPE_API,m,p1,p2);}
+#define AVRC_TRACE_API3(m,p1,p2,p3) {if (avrc_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_3(TRACE_LAYER_AVP, TRACE_TYPE_API,m,p1,p2,p3);}
+#define AVRC_TRACE_API4(m,p1,p2,p3,p4) {if (avrc_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_4(TRACE_LAYER_AVP, TRACE_TYPE_API,m,p1,p2,p3,p4);}
+#define AVRC_TRACE_API5(m,p1,p2,p3,p4,p5) {if (avrc_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_5(TRACE_LAYER_AVP, TRACE_TYPE_API,m,p1,p2,p3,p4,p5);}
+#define AVRC_TRACE_API6(m,p1,p2,p3,p4,p5,p6) {if (avrc_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_6(TRACE_LAYER_AVP, TRACE_TYPE_API,m,p1,p2,p3,p4,p5,p6);}
+
+/* MCAP
+*/
+#define MCA_TRACE_ERROR0(m) {if (mca_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_0(TRACE_LAYER_MCA, TRACE_TYPE_ERROR, m);}
+#define MCA_TRACE_ERROR1(m,p1) {if (mca_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_1(TRACE_LAYER_MCA, TRACE_TYPE_ERROR, m,p1);}
+#define MCA_TRACE_ERROR2(m,p1,p2) {if (mca_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_2(TRACE_LAYER_MCA, TRACE_TYPE_ERROR, m,p1,p2);}
+#define MCA_TRACE_ERROR3(m,p1,p2,p3) {if (mca_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_3(TRACE_LAYER_MCA, TRACE_TYPE_ERROR, m,p1,p2,p3);}
+#define MCA_TRACE_ERROR4(m,p1,p2,p3,p4) {if (mca_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_4(TRACE_LAYER_MCA, TRACE_TYPE_ERROR, m,p1,p2,p3,p4);}
+#define MCA_TRACE_ERROR5(m,p1,p2,p3,p4,p5) {if (mca_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_5(TRACE_LAYER_MCA, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5);}
+#define MCA_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6) {if (mca_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_6(TRACE_LAYER_MCA, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5,p6);}
+
+#define MCA_TRACE_WARNING0(m) {if (mca_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_0(TRACE_LAYER_MCA, TRACE_TYPE_WARNING, m);}
+#define MCA_TRACE_WARNING1(m,p1) {if (mca_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_1(TRACE_LAYER_MCA, TRACE_TYPE_WARNING, m,p1);}
+#define MCA_TRACE_WARNING2(m,p1,p2) {if (mca_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_2(TRACE_LAYER_MCA, TRACE_TYPE_WARNING, m,p1,p2);}
+#define MCA_TRACE_WARNING3(m,p1,p2,p3) {if (mca_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_3(TRACE_LAYER_MCA, TRACE_TYPE_WARNING, m,p1,p2,p3);}
+#define MCA_TRACE_WARNING4(m,p1,p2,p3,p4) {if (mca_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_4(TRACE_LAYER_MCA, TRACE_TYPE_WARNING, m,p1,p2,p3,p4);}
+#define MCA_TRACE_WARNING5(m,p1,p2,p3,p4,p5) {if (mca_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_5(TRACE_LAYER_MCA, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5);}
+#define MCA_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6) {if (mca_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_6(TRACE_LAYER_MCA, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5,p6);}
+
+#define MCA_TRACE_EVENT0(m) {if (mca_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_0(TRACE_LAYER_MCA, TRACE_TYPE_EVENT, m);}
+#define MCA_TRACE_EVENT1(m,p1) {if (mca_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_1(TRACE_LAYER_MCA, TRACE_TYPE_EVENT, m, p1);}
+#define MCA_TRACE_EVENT2(m,p1,p2) {if (mca_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_2(TRACE_LAYER_MCA, TRACE_TYPE_EVENT, m,p1,p2);}
+#define MCA_TRACE_EVENT3(m,p1,p2,p3) {if (mca_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_3(TRACE_LAYER_MCA, TRACE_TYPE_EVENT, m,p1,p2,p3);}
+#define MCA_TRACE_EVENT4(m,p1,p2,p3,p4) {if (mca_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_4(TRACE_LAYER_MCA, TRACE_TYPE_EVENT, m,p1,p2,p3,p4);}
+#define MCA_TRACE_EVENT5(m,p1,p2,p3,p4,p5) {if (mca_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_5(TRACE_LAYER_MCA, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5);}
+#define MCA_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6) {if (mca_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_6(TRACE_LAYER_MCA, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5,p6);}
+
+#define MCA_TRACE_DEBUG0(m) {if (mca_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_0(TRACE_LAYER_MCA, TRACE_TYPE_DEBUG, m);}
+#define MCA_TRACE_DEBUG1(m,p1) {if (mca_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_1(TRACE_LAYER_MCA, TRACE_TYPE_DEBUG, m,p1);}
+#define MCA_TRACE_DEBUG2(m,p1,p2) {if (mca_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_2(TRACE_LAYER_MCA, TRACE_TYPE_DEBUG, m,p1,p2);}
+#define MCA_TRACE_DEBUG3(m,p1,p2,p3) {if (mca_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_3(TRACE_LAYER_MCA, TRACE_TYPE_DEBUG, m,p1,p2,p3);}
+#define MCA_TRACE_DEBUG4(m,p1,p2,p3,p4) {if (mca_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_4(TRACE_LAYER_MCA, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4);}
+#define MCA_TRACE_DEBUG5(m,p1,p2,p3,p4,p5) {if (mca_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_5(TRACE_LAYER_MCA, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5);}
+#define MCA_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) {if (mca_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_6(TRACE_LAYER_MCA, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5,p6);}
+
+#define MCA_TRACE_API0(m) {if (mca_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_0(TRACE_LAYER_MCA, TRACE_TYPE_API, m);}
+#define MCA_TRACE_API1(m,p1) {if (mca_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_1(TRACE_LAYER_MCA, TRACE_TYPE_API, m,p1);}
+#define MCA_TRACE_API2(m,p1,p2) {if (mca_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_2(TRACE_LAYER_MCA, TRACE_TYPE_API, m,p1,p2);}
+#define MCA_TRACE_API3(m,p1,p2,p3) {if (mca_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_3(TRACE_LAYER_MCA, TRACE_TYPE_API, m,p1,p2,p3);}
+#define MCA_TRACE_API4(m,p1,p2,p3,p4) {if (mca_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_4(TRACE_LAYER_MCA, TRACE_TYPE_API, m,p1,p2,p3,p4);}
+#define MCA_TRACE_API5(m,p1,p2,p3,p4,p5) {if (mca_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_5(TRACE_LAYER_MCA, TRACE_TYPE_API, m,p1,p2,p3,p4,p5);}
+#define MCA_TRACE_API6(m,p1,p2,p3,p4,p5,p6) {if (mca_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_6(TRACE_LAYER_MCA, TRACE_TYPE_API, m,p1,p2,p3,p4,p5,p6);}
+
+/* Define tracing for the AMP unit
+*/
+#define AMP_TRACE_ERROR0(m) {if (amp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_0(TRACE_LAYER_AMP, TRACE_TYPE_ERROR, m);}
+#define AMP_TRACE_ERROR1(m,p1) {if (amp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_1(TRACE_LAYER_AMP, TRACE_TYPE_ERROR, m,p1);}
+#define AMP_TRACE_ERROR2(m,p1,p2) {if (amp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_2(TRACE_LAYER_AMP, TRACE_TYPE_ERROR, m,p1,p2);}
+#define AMP_TRACE_ERROR3(m,p1,p2,p3) {if (amp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_3(TRACE_LAYER_AMP, TRACE_TYPE_ERROR, m,p1,p2,p3);}
+#define AMP_TRACE_ERROR4(m,p1,p2,p3,p4) {if (amp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_4(TRACE_LAYER_AMP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4);}
+#define AMP_TRACE_ERROR5(m,p1,p2,p3,p4,p5) {if (amp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_5(TRACE_LAYER_AMP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5);}
+#define AMP_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6) {if (amp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_6(TRACE_LAYER_AMP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5,p6);}
+
+#define AMP_TRACE_WARNING0(m) {if (amp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_0(TRACE_LAYER_AMP, TRACE_TYPE_WARNING, m);}
+#define AMP_TRACE_WARNING1(m,p1) {if (amp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_1(TRACE_LAYER_AMP, TRACE_TYPE_WARNING, m,p1);}
+#define AMP_TRACE_WARNING2(m,p1,p2) {if (amp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_2(TRACE_LAYER_AMP, TRACE_TYPE_WARNING, m,p1,p2);}
+#define AMP_TRACE_WARNING3(m,p1,p2,p3) {if (amp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_3(TRACE_LAYER_AMP, TRACE_TYPE_WARNING, m,p1,p2,p3);}
+#define AMP_TRACE_WARNING4(m,p1,p2,p3,p4) {if (amp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_4(TRACE_LAYER_AMP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4);}
+#define AMP_TRACE_WARNING5(m,p1,p2,p3,p4,p5) {if (amp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_5(TRACE_LAYER_AMP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5);}
+#define AMP_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6) {if (amp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_6(TRACE_LAYER_AMP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5,p6);}
+
+#define AMP_TRACE_API0(m) {if (amp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_0(TRACE_LAYER_AMP, TRACE_TYPE_API, m);}
+#define AMP_TRACE_API1(m,p1) {if (amp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_1(TRACE_LAYER_AMP, TRACE_TYPE_API, m,p1);}
+#define AMP_TRACE_API2(m,p1,p2) {if (amp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_2(TRACE_LAYER_AMP, TRACE_TYPE_API, m,p1,p2);}
+#define AMP_TRACE_API3(m,p1,p2,p3) {if (amp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_3(TRACE_LAYER_AMP, TRACE_TYPE_API, m,p1,p2,p3);}
+#define AMP_TRACE_API4(m,p1,p2,p3,p4) {if (amp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_4(TRACE_LAYER_AMP, TRACE_TYPE_API, m,p1,p2,p3,p4);}
+#define AMP_TRACE_API5(m,p1,p2,p3,p4,p5) {if (amp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_5(TRACE_LAYER_AMP, TRACE_TYPE_API, m,p1,p2,p3,p4,p5);}
+#define AMP_TRACE_API6(m,p1,p2,p3,p4,p5,p6) {if (amp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_6(TRACE_LAYER_AMP, TRACE_TYPE_API, m,p1,p2,p3,p4,p5,p6);}
+
+#define AMP_TRACE_EVENT0(m) {if (amp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_0(TRACE_LAYER_AMP, TRACE_TYPE_EVENT, m);}
+#define AMP_TRACE_EVENT1(m,p1) {if (amp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_1(TRACE_LAYER_AMP, TRACE_TYPE_EVENT, m, p1);}
+#define AMP_TRACE_EVENT2(m,p1,p2) {if (amp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_2(TRACE_LAYER_AMP, TRACE_TYPE_EVENT, m,p1,p2);}
+#define AMP_TRACE_EVENT3(m,p1,p2,p3) {if (amp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_3(TRACE_LAYER_AMP, TRACE_TYPE_EVENT, m,p1,p2,p3);}
+#define AMP_TRACE_EVENT4(m,p1,p2,p3,p4) {if (amp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_4(TRACE_LAYER_AMP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4);}
+#define AMP_TRACE_EVENT5(m,p1,p2,p3,p4,p5) {if (amp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_5(TRACE_LAYER_AMP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5);}
+#define AMP_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6) {if (amp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_6(TRACE_LAYER_AMP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5,p6);}
+
+#define AMP_TRACE_DEBUG0(m) {if (amp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_0(TRACE_LAYER_AMP, TRACE_TYPE_DEBUG, m);}
+#define AMP_TRACE_DEBUG1(m,p1) {if (amp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_1(TRACE_LAYER_AMP, TRACE_TYPE_DEBUG, m,p1);}
+#define AMP_TRACE_DEBUG2(m,p1,p2) {if (amp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_2(TRACE_LAYER_AMP, TRACE_TYPE_DEBUG, m,p1,p2);}
+#define AMP_TRACE_DEBUG3(m,p1,p2,p3) {if (amp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_3(TRACE_LAYER_AMP, TRACE_TYPE_DEBUG, m,p1,p2,p3);}
+#define AMP_TRACE_DEBUG4(m,p1,p2,p3,p4) {if (amp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_4(TRACE_LAYER_AMP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4);}
+#define AMP_TRACE_DEBUG5(m,p1,p2,p3,p4,p5) {if (amp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_5(TRACE_LAYER_AMP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5);}
+#define AMP_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) {if (amp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_6(TRACE_LAYER_AMP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5,p6);}
+
+/* Define tracing for the ATT/GATT unit
+*/
+#define GATT_TRACE_ERROR0(m) {if (gatt_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_0(TRACE_LAYER_ATT, TRACE_TYPE_ERROR, m);}
+#define GATT_TRACE_ERROR1(m,p1) {if (gatt_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_1(TRACE_LAYER_ATT, TRACE_TYPE_ERROR, m,p1);}
+#define GATT_TRACE_ERROR2(m,p1,p2) {if (gatt_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_2(TRACE_LAYER_ATT, TRACE_TYPE_ERROR, m,p1,p2);}
+#define GATT_TRACE_ERROR3(m,p1,p2,p3) {if (gatt_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_3(TRACE_LAYER_ATT, TRACE_TYPE_ERROR, m,p1,p2,p3);}
+#define GATT_TRACE_ERROR4(m,p1,p2,p3,p4) {if (gatt_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_4(TRACE_LAYER_ATT, TRACE_TYPE_ERROR, m,p1,p2,p3,p4);}
+#define GATT_TRACE_ERROR5(m,p1,p2,p3,p4,p5) {if (gatt_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_5(TRACE_LAYER_ATT, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5);}
+#define GATT_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6) {if (gatt_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_6(TRACE_LAYER_ATT, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5,p6);}
+
+#define GATT_TRACE_WARNING0(m) {if (gatt_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_0(TRACE_LAYER_ATT, TRACE_TYPE_WARNING, m);}
+#define GATT_TRACE_WARNING1(m,p1) {if (gatt_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_1(TRACE_LAYER_ATT, TRACE_TYPE_WARNING, m,p1);}
+#define GATT_TRACE_WARNING2(m,p1,p2) {if (gatt_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_2(TRACE_LAYER_ATT, TRACE_TYPE_WARNING, m,p1,p2);}
+#define GATT_TRACE_WARNING3(m,p1,p2,p3) {if (gatt_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_3(TRACE_LAYER_ATT, TRACE_TYPE_WARNING, m,p1,p2,p3);}
+#define GATT_TRACE_WARNING4(m,p1,p2,p3,p4) {if (gatt_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_4(TRACE_LAYER_ATT, TRACE_TYPE_WARNING, m,p1,p2,p3,p4);}
+#define GATT_TRACE_WARNING5(m,p1,p2,p3,p4,p5) {if (gatt_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_5(TRACE_LAYER_ATT, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5);}
+#define GATT_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6) {if (gatt_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_6(TRACE_LAYER_ATT, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5,p6);}
+
+#define GATT_TRACE_API0(m) {if (gatt_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_0(TRACE_LAYER_ATT, TRACE_TYPE_API, m);}
+#define GATT_TRACE_API1(m,p1) {if (gatt_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_1(TRACE_LAYER_ATT, TRACE_TYPE_API, m,p1);}
+#define GATT_TRACE_API2(m,p1,p2) {if (gatt_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_2(TRACE_LAYER_ATT, TRACE_TYPE_API, m,p1,p2);}
+#define GATT_TRACE_API3(m,p1,p2,p3) {if (gatt_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_3(TRACE_LAYER_ATT, TRACE_TYPE_API, m,p1,p2,p3);}
+#define GATT_TRACE_API4(m,p1,p2,p3,p4) {if (gatt_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_4(TRACE_LAYER_ATT, TRACE_TYPE_API, m,p1,p2,p3,p4);}
+#define GATT_TRACE_API5(m,p1,p2,p3,p4,p5) {if (gatt_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_5(TRACE_LAYER_ATT, TRACE_TYPE_API, m,p1,p2,p3,p4,p5);}
+#define GATT_TRACE_API6(m,p1,p2,p3,p4,p5,p6) {if (gatt_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_6(TRACE_LAYER_ATT, TRACE_TYPE_API, m,p1,p2,p3,p4,p5,p6);}
+
+#define GATT_TRACE_EVENT0(m) {if (gatt_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_0(TRACE_LAYER_ATT, TRACE_TYPE_EVENT, m);}
+#define GATT_TRACE_EVENT1(m,p1) {if (gatt_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_1(TRACE_LAYER_ATT, TRACE_TYPE_EVENT, m, p1);}
+#define GATT_TRACE_EVENT2(m,p1,p2) {if (gatt_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_2(TRACE_LAYER_ATT, TRACE_TYPE_EVENT, m,p1,p2);}
+#define GATT_TRACE_EVENT3(m,p1,p2,p3) {if (gatt_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_3(TRACE_LAYER_ATT, TRACE_TYPE_EVENT, m,p1,p2,p3);}
+#define GATT_TRACE_EVENT4(m,p1,p2,p3,p4) {if (gatt_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_4(TRACE_LAYER_ATT, TRACE_TYPE_EVENT, m,p1,p2,p3,p4);}
+#define GATT_TRACE_EVENT5(m,p1,p2,p3,p4,p5) {if (gatt_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_5(TRACE_LAYER_ATT, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5);}
+#define GATT_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6) {if (gatt_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_6(TRACE_LAYER_ATT, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5,p6);}
+
+#define GATT_TRACE_DEBUG0(m) {if (gatt_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_0(TRACE_LAYER_ATT, TRACE_TYPE_DEBUG, m);}
+#define GATT_TRACE_DEBUG1(m,p1) {if (gatt_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_1(TRACE_LAYER_ATT, TRACE_TYPE_DEBUG, m,p1);}
+#define GATT_TRACE_DEBUG2(m,p1,p2) {if (gatt_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_2(TRACE_LAYER_ATT, TRACE_TYPE_DEBUG, m,p1,p2);}
+#define GATT_TRACE_DEBUG3(m,p1,p2,p3) {if (gatt_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_3(TRACE_LAYER_ATT, TRACE_TYPE_DEBUG, m,p1,p2,p3);}
+#define GATT_TRACE_DEBUG4(m,p1,p2,p3,p4) {if (gatt_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_4(TRACE_LAYER_ATT, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4);}
+#define GATT_TRACE_DEBUG5(m,p1,p2,p3,p4,p5) {if (gatt_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_5(TRACE_LAYER_ATT, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5);}
+#define GATT_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) {if (gatt_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_6(TRACE_LAYER_ATT, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5,p6);}
+
+/* Define tracing for the SMP unit
+*/
+#define SMP_TRACE_ERROR0(m) {if (smp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_0(TRACE_LAYER_SMP, TRACE_TYPE_ERROR, m);}
+#define SMP_TRACE_ERROR1(m,p1) {if (smp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_1(TRACE_LAYER_SMP, TRACE_TYPE_ERROR, m,p1);}
+#define SMP_TRACE_ERROR2(m,p1,p2) {if (smp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_2(TRACE_LAYER_SMP, TRACE_TYPE_ERROR, m,p1,p2);}
+#define SMP_TRACE_ERROR3(m,p1,p2,p3) {if (smp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_3(TRACE_LAYER_SMP, TRACE_TYPE_ERROR, m,p1,p2,p3);}
+#define SMP_TRACE_ERROR4(m,p1,p2,p3,p4) {if (smp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_4(TRACE_LAYER_SMP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4);}
+#define SMP_TRACE_ERROR5(m,p1,p2,p3,p4,p5) {if (smp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_5(TRACE_LAYER_SMP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5);}
+#define SMP_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6) {if (smp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE_6(TRACE_LAYER_SMP, TRACE_TYPE_ERROR, m,p1,p2,p3,p4,p5,p6);}
+
+#define SMP_TRACE_WARNING0(m) {if (smp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_0(TRACE_LAYER_SMP, TRACE_TYPE_WARNING, m);}
+#define SMP_TRACE_WARNING1(m,p1) {if (smp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_1(TRACE_LAYER_SMP, TRACE_TYPE_WARNING, m,p1);}
+#define SMP_TRACE_WARNING2(m,p1,p2) {if (smp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_2(TRACE_LAYER_SMP, TRACE_TYPE_WARNING, m,p1,p2);}
+#define SMP_TRACE_WARNING3(m,p1,p2,p3) {if (smp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_3(TRACE_LAYER_SMP, TRACE_TYPE_WARNING, m,p1,p2,p3);}
+#define SMP_TRACE_WARNING4(m,p1,p2,p3,p4) {if (smp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_4(TRACE_LAYER_SMP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4);}
+#define SMP_TRACE_WARNING5(m,p1,p2,p3,p4,p5) {if (smp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_5(TRACE_LAYER_SMP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5);}
+#define SMP_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6) {if (smp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE_6(TRACE_LAYER_SMP, TRACE_TYPE_WARNING, m,p1,p2,p3,p4,p5,p6);}
+
+#define SMP_TRACE_API0(m) {if (smp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_0(TRACE_LAYER_SMP, TRACE_TYPE_API, m);}
+#define SMP_TRACE_API1(m,p1) {if (smp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_1(TRACE_LAYER_SMP, TRACE_TYPE_API, m,p1);}
+#define SMP_TRACE_API2(m,p1,p2) {if (smp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_2(TRACE_LAYER_SMP, TRACE_TYPE_API, m,p1,p2);}
+#define SMP_TRACE_API3(m,p1,p2,p3) {if (smp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_3(TRACE_LAYER_SMP, TRACE_TYPE_API, m,p1,p2,p3);}
+#define SMP_TRACE_API4(m,p1,p2,p3,p4) {if (smp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_4(TRACE_LAYER_SMP, TRACE_TYPE_API, m,p1,p2,p3,p4);}
+#define SMP_TRACE_API5(m,p1,p2,p3,p4,p5) {if (smp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_5(TRACE_LAYER_SMP, TRACE_TYPE_API, m,p1,p2,p3,p4,p5);}
+#define SMP_TRACE_API6(m,p1,p2,p3,p4,p5,p6) {if (smp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE_6(TRACE_LAYER_SMP, TRACE_TYPE_API, m,p1,p2,p3,p4,p5,p6);}
+
+#define SMP_TRACE_EVENT0(m) {if (smp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_0(TRACE_LAYER_SMP, TRACE_TYPE_EVENT, m);}
+#define SMP_TRACE_EVENT1(m,p1) {if (smp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_1(TRACE_LAYER_SMP, TRACE_TYPE_EVENT, m, p1);}
+#define SMP_TRACE_EVENT2(m,p1,p2) {if (smp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_2(TRACE_LAYER_SMP, TRACE_TYPE_EVENT, m,p1,p2);}
+#define SMP_TRACE_EVENT3(m,p1,p2,p3) {if (smp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_3(TRACE_LAYER_SMP, TRACE_TYPE_EVENT, m,p1,p2,p3);}
+#define SMP_TRACE_EVENT4(m,p1,p2,p3,p4) {if (smp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_4(TRACE_LAYER_SMP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4);}
+#define SMP_TRACE_EVENT5(m,p1,p2,p3,p4,p5) {if (smp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_5(TRACE_LAYER_SMP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5);}
+#define SMP_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6) {if (smp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE_6(TRACE_LAYER_SMP, TRACE_TYPE_EVENT, m,p1,p2,p3,p4,p5,p6);}
+
+#define SMP_TRACE_DEBUG0(m) {if (smp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_0(TRACE_LAYER_SMP, TRACE_TYPE_DEBUG, m);}
+#define SMP_TRACE_DEBUG1(m,p1) {if (smp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_1(TRACE_LAYER_SMP, TRACE_TYPE_DEBUG, m,p1);}
+#define SMP_TRACE_DEBUG2(m,p1,p2) {if (smp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_2(TRACE_LAYER_SMP, TRACE_TYPE_DEBUG, m,p1,p2);}
+#define SMP_TRACE_DEBUG3(m,p1,p2,p3) {if (smp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_3(TRACE_LAYER_SMP, TRACE_TYPE_DEBUG, m,p1,p2,p3);}
+#define SMP_TRACE_DEBUG4(m,p1,p2,p3,p4) {if (smp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_4(TRACE_LAYER_SMP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4);}
+#define SMP_TRACE_DEBUG5(m,p1,p2,p3,p4,p5) {if (smp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_5(TRACE_LAYER_SMP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5);}
+#define SMP_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) {if (smp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE_6(TRACE_LAYER_SMP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5,p6);}
+
+/* END OF USE TRACES */
+#else
+
+#define BT_TRACE_0(l,t,m)
+#define BT_TRACE_1(l,t,m,p1)
+#define BT_TRACE_2(l,t,m,p1,p2)
+#define BT_TRACE_3(l,t,m,p1,p2,p3)
+#define BT_TRACE_4(l,t,m,p1,p2,p3,p4)
+#define BT_TRACE_5(l,t,m,p1,p2,p3,p4,p5)
+#define BT_TRACE_6(l,t,m,p1,p2,p3,p4,p5,p6)
+
+#define BT_ERROR_TRACE_0(l,m)
+#define BT_ERROR_TRACE_1(l,m,p1)
+#define BT_ERROR_TRACE_2(l,m,p1,p2)
+#define BT_ERROR_TRACE_3(l,m,p1,p2,p3)
+
+/* Define tracing for the HCI unit
+*/
+#define HCI_TRACE_ERROR0(m)
+#define HCI_TRACE_ERROR1(m,p1)
+#define HCI_TRACE_ERROR2(m,p1,p2)
+#define HCI_TRACE_ERROR3(m,p1,p2,p3)
+#define HCI_TRACE_ERROR4(m,p1,p2,p3,p4)
+#define HCI_TRACE_ERROR5(m,p1,p2,p3,p4,p5)
+#define HCI_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6)
+
+#define HCI_TRACE_WARNING0(m)
+#define HCI_TRACE_WARNING1(m,p1)
+#define HCI_TRACE_WARNING2(m,p1,p2)
+#define HCI_TRACE_WARNING3(m,p1,p2,p3)
+#define HCI_TRACE_WARNING4(m,p1,p2,p3,p4)
+#define HCI_TRACE_WARNING5(m,p1,p2,p3,p4,p5)
+#define HCI_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6)
+
+#define HCI_TRACE_EVENT0(m)
+#define HCI_TRACE_EVENT1(m,p1)
+#define HCI_TRACE_EVENT2(m,p1,p2)
+#define HCI_TRACE_EVENT3(m,p1,p2,p3)
+#define HCI_TRACE_EVENT4(m,p1,p2,p3,p4)
+#define HCI_TRACE_EVENT5(m,p1,p2,p3,p4,p5)
+#define HCI_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6)
+
+#define HCI_TRACE_DEBUG0(m)
+#define HCI_TRACE_DEBUG1(m,p1)
+#define HCI_TRACE_DEBUG2(m,p1,p2)
+#define HCI_TRACE_DEBUG3(m,p1,p2,p3)
+#define HCI_TRACE_DEBUG4(m,p1,p2,p3,p4)
+#define HCI_TRACE_DEBUG5(m,p1,p2,p3,p4,p5)
+#define HCI_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6)
+
+
+/* Define tracing for BTM
+*/
+#define BTM_TRACE_ERROR0(m)
+#define BTM_TRACE_ERROR1(m,p1)
+#define BTM_TRACE_ERROR2(m,p1,p2)
+#define BTM_TRACE_ERROR3(m,p1,p2,p3)
+#define BTM_TRACE_ERROR4(m,p1,p2,p3,p4)
+#define BTM_TRACE_ERROR5(m,p1,p2,p3,p4,p5)
+#define BTM_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6)
+
+#define BTM_TRACE_WARNING0(m)
+#define BTM_TRACE_WARNING1(m,p1)
+#define BTM_TRACE_WARNING2(m,p1,p2)
+#define BTM_TRACE_WARNING3(m,p1,p2,p3)
+#define BTM_TRACE_WARNING4(m,p1,p2,p3,p4)
+#define BTM_TRACE_WARNING5(m,p1,p2,p3,p4,p5)
+#define BTM_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6)
+
+#define BTM_TRACE_API0(m)
+#define BTM_TRACE_API1(m,p1)
+#define BTM_TRACE_API2(m,p1,p2)
+#define BTM_TRACE_API3(m,p1,p2,p3)
+#define BTM_TRACE_API4(m,p1,p2,p3,p4)
+#define BTM_TRACE_API5(m,p1,p2,p3,p4,p5)
+#define BTM_TRACE_API6(m,p1,p2,p3,p4,p5,p6)
+
+#define BTM_TRACE_EVENT0(m)
+#define BTM_TRACE_EVENT1(m,p1)
+#define BTM_TRACE_EVENT2(m,p1,p2)
+#define BTM_TRACE_EVENT3(m,p1,p2,p3)
+#define BTM_TRACE_EVENT4(m,p1,p2,p3,p4)
+#define BTM_TRACE_EVENT5(m,p1,p2,p3,p4,p5)
+#define BTM_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6)
+
+#define BTM_TRACE_DEBUG0(m)
+#define BTM_TRACE_DEBUG1(m,p1)
+#define BTM_TRACE_DEBUG2(m,p1,p2)
+#define BTM_TRACE_DEBUG3(m,p1,p2,p3)
+#define BTM_TRACE_DEBUG4(m,p1,p2,p3,p4)
+#define BTM_TRACE_DEBUG5(m,p1,p2,p3,p4,p5)
+#define BTM_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6)
+
+
+/* Define tracing for the L2CAP unit
+*/
+#define L2CAP_TRACE_ERROR0(m)
+#define L2CAP_TRACE_ERROR1(m,p1)
+#define L2CAP_TRACE_ERROR2(m,p1,p2)
+#define L2CAP_TRACE_ERROR3(m,p1,p2,p3)
+#define L2CAP_TRACE_ERROR4(m,p1,p2,p3,p4)
+#define L2CAP_TRACE_ERROR5(m,p1,p2,p3,p4,p5)
+#define L2CAP_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6)
+
+#define L2CAP_TRACE_WARNING0(m)
+#define L2CAP_TRACE_WARNING1(m,p1)
+#define L2CAP_TRACE_WARNING2(m,p1,p2)
+#define L2CAP_TRACE_WARNING3(m,p1,p2,p3)
+#define L2CAP_TRACE_WARNING4(m,p1,p2,p3,p4)
+#define L2CAP_TRACE_WARNING5(m,p1,p2,p3,p4,p5)
+#define L2CAP_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6)
+
+#define L2CAP_TRACE_API0(m)
+#define L2CAP_TRACE_API1(m,p1)
+#define L2CAP_TRACE_API2(m,p1,p2)
+#define L2CAP_TRACE_API3(m,p1,p2,p3)
+#define L2CAP_TRACE_API4(m,p1,p2,p3,p4)
+#define L2CAP_TRACE_API5(m,p1,p2,p3,p4,p5)
+#define L2CAP_TRACE_API6(m,p1,p2,p3,p4,p5,p6)
+
+#define L2CAP_TRACE_EVENT0(m)
+#define L2CAP_TRACE_EVENT1(m,p1)
+#define L2CAP_TRACE_EVENT2(m,p1,p2)
+#define L2CAP_TRACE_EVENT3(m,p1,p2,p3)
+#define L2CAP_TRACE_EVENT4(m,p1,p2,p3,p4)
+#define L2CAP_TRACE_EVENT5(m,p1,p2,p3,p4,p5)
+#define L2CAP_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6)
+
+#define L2CAP_TRACE_DEBUG0(m)
+#define L2CAP_TRACE_DEBUG1(m,p1)
+#define L2CAP_TRACE_DEBUG2(m,p1,p2)
+#define L2CAP_TRACE_DEBUG3(m,p1,p2,p3)
+#define L2CAP_TRACE_DEBUG4(m,p1,p2,p3,p4)
+#define L2CAP_TRACE_DEBUG5(m,p1,p2,p3,p4,p5)
+#define L2CAP_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6)
+
+/* Define tracing for the LLCP unit
+*/
+#define LLCP_TRACE_ERROR0(m)
+#define LLCP_TRACE_ERROR1(m,p1)
+#define LLCP_TRACE_ERROR2(m,p1,p2)
+#define LLCP_TRACE_ERROR3(m,p1,p2,p3)
+#define LLCP_TRACE_ERROR4(m,p1,p2,p3,p4)
+#define LLCP_TRACE_ERROR5(m,p1,p2,p3,p4,p5)
+#define LLCP_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6)
+
+#define LLCP_TRACE_WARNING0(m)
+#define LLCP_TRACE_WARNING1(m,p1)
+#define LLCP_TRACE_WARNING2(m,p1,p2)
+#define LLCP_TRACE_WARNING3(m,p1,p2,p3)
+#define LLCP_TRACE_WARNING4(m,p1,p2,p3,p4)
+#define LLCP_TRACE_WARNING5(m,p1,p2,p3,p4,p5)
+#define LLCP_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6)
+
+#define LLCP_TRACE_API0(m)
+#define LLCP_TRACE_API1(m,p1)
+#define LLCP_TRACE_API2(m,p1,p2)
+#define LLCP_TRACE_API3(m,p1,p2,p3)
+#define LLCP_TRACE_API4(m,p1,p2,p3,p4)
+#define LLCP_TRACE_API5(m,p1,p2,p3,p4,p5)
+#define LLCP_TRACE_API6(m,p1,p2,p3,p4,p5,p6)
+
+#define LLCP_TRACE_EVENT0(m)
+#define LLCP_TRACE_EVENT1(m,p1)
+#define LLCP_TRACE_EVENT2(m,p1,p2)
+#define LLCP_TRACE_EVENT3(m,p1,p2,p3)
+#define LLCP_TRACE_EVENT4(m,p1,p2,p3,p4)
+#define LLCP_TRACE_EVENT5(m,p1,p2,p3,p4,p5)
+#define LLCP_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6)
+
+#define LLCP_TRACE_DEBUG0(m)
+#define LLCP_TRACE_DEBUG1(m,p1)
+#define LLCP_TRACE_DEBUG2(m,p1,p2)
+#define LLCP_TRACE_DEBUG3(m,p1,p2,p3)
+#define LLCP_TRACE_DEBUG4(m,p1,p2,p3,p4)
+#define LLCP_TRACE_DEBUG5(m,p1,p2,p3,p4,p5)
+#define LLCP_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6)
+
+/* Define tracing for the SDP unit
+*/
+#define SDP_TRACE_ERROR0(m)
+#define SDP_TRACE_ERROR1(m,p1)
+#define SDP_TRACE_ERROR2(m,p1,p2)
+#define SDP_TRACE_ERROR3(m,p1,p2,p3)
+#define SDP_TRACE_ERROR4(m,p1,p2,p3,p4)
+#define SDP_TRACE_ERROR5(m,p1,p2,p3,p4,p5)
+#define SDP_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6)
+
+#define SDP_TRACE_WARNING0(m)
+#define SDP_TRACE_WARNING1(m,p1)
+#define SDP_TRACE_WARNING2(m,p1,p2)
+#define SDP_TRACE_WARNING3(m,p1,p2,p3)
+#define SDP_TRACE_WARNING4(m,p1,p2,p3,p4)
+#define SDP_TRACE_WARNING5(m,p1,p2,p3,p4,p5)
+#define SDP_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6)
+
+#define SDP_TRACE_API0(m)
+#define SDP_TRACE_API1(m,p1)
+#define SDP_TRACE_API2(m,p1,p2)
+#define SDP_TRACE_API3(m,p1,p2,p3)
+#define SDP_TRACE_API4(m,p1,p2,p3,p4)
+#define SDP_TRACE_API5(m,p1,p2,p3,p4,p5)
+#define SDP_TRACE_API6(m,p1,p2,p3,p4,p5,p6)
+
+#define SDP_TRACE_EVENT0(m)
+#define SDP_TRACE_EVENT1(m,p1)
+#define SDP_TRACE_EVENT2(m,p1,p2)
+#define SDP_TRACE_EVENT3(m,p1,p2,p3)
+#define SDP_TRACE_EVENT4(m,p1,p2,p3,p4)
+#define SDP_TRACE_EVENT5(m,p1,p2,p3,p4,p5)
+#define SDP_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6)
+
+#define SDP_TRACE_DEBUG0(m)
+#define SDP_TRACE_DEBUG1(m,p1)
+#define SDP_TRACE_DEBUG2(m,p1,p2)
+#define SDP_TRACE_DEBUG3(m,p1,p2,p3)
+#define SDP_TRACE_DEBUG4(m,p1,p2,p3,p4)
+#define SDP_TRACE_DEBUG5(m,p1,p2,p3,p4,p5)
+#define SDP_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6)
+
+/* Define tracing for the RFCOMM unit
+*/
+#define RFCOMM_TRACE_ERROR0(m)
+#define RFCOMM_TRACE_ERROR1(m,p1)
+#define RFCOMM_TRACE_ERROR2(m,p1,p2)
+#define RFCOMM_TRACE_ERROR3(m,p1,p2,p3)
+#define RFCOMM_TRACE_ERROR4(m,p1,p2,p3,p4)
+#define RFCOMM_TRACE_ERROR5(m,p1,p2,p3,p4,p5)
+#define RFCOMM_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6)
+
+#define RFCOMM_TRACE_WARNING0(m)
+#define RFCOMM_TRACE_WARNING1(m,p1)
+#define RFCOMM_TRACE_WARNING2(m,p1,p2)
+#define RFCOMM_TRACE_WARNING3(m,p1,p2,p3)
+#define RFCOMM_TRACE_WARNING4(m,p1,p2,p3,p4)
+#define RFCOMM_TRACE_WARNING5(m,p1,p2,p3,p4,p5)
+#define RFCOMM_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6)
+
+#define RFCOMM_TRACE_API0(m)
+#define RFCOMM_TRACE_API1(m,p1)
+#define RFCOMM_TRACE_API2(m,p1,p2)
+#define RFCOMM_TRACE_API3(m,p1,p2,p3)
+#define RFCOMM_TRACE_API4(m,p1,p2,p3,p4)
+#define RFCOMM_TRACE_API5(m,p1,p2,p3,p4,p5)
+#define RFCOMM_TRACE_API6(m,p1,p2,p3,p4,p5,p6)
+
+#define RFCOMM_TRACE_EVENT0(m)
+#define RFCOMM_TRACE_EVENT1(m,p1)
+#define RFCOMM_TRACE_EVENT2(m,p1,p2)
+#define RFCOMM_TRACE_EVENT3(m,p1,p2,p3)
+#define RFCOMM_TRACE_EVENT4(m,p1,p2,p3,p4)
+#define RFCOMM_TRACE_EVENT5(m,p1,p2,p3,p4,p5)
+#define RFCOMM_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6)
+
+#define RFCOMM_TRACE_DEBUG0(m)
+#define RFCOMM_TRACE_DEBUG1(m,p1)
+#define RFCOMM_TRACE_DEBUG2(m,p1,p2)
+#define RFCOMM_TRACE_DEBUG3(m,p1,p2,p3)
+#define RFCOMM_TRACE_DEBUG4(m,p1,p2,p3,p4)
+#define RFCOMM_TRACE_DEBUG5(m,p1,p2,p3,p4,p5)
+#define RFCOMM_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6)
+
+/* Define tracing for Serial Port Profile
+*/
+#define SPP_TRACE_ERROR0(m)
+#define SPP_TRACE_ERROR1(m,p1)
+#define SPP_TRACE_ERROR2(m,p1,p2)
+#define SPP_TRACE_ERROR3(m,p1,p2,p3)
+#define SPP_TRACE_ERROR4(m,p1,p2,p3,p4)
+#define SPP_TRACE_ERROR5(m,p1,p2,p3,p4,p5)
+#define SPP_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6)
+
+#define SPP_TRACE_WARNING0(m)
+#define SPP_TRACE_WARNING1(m,p1)
+#define SPP_TRACE_WARNING2(m,p1,p2)
+#define SPP_TRACE_WARNING3(m,p1,p2,p3)
+#define SPP_TRACE_WARNING4(m,p1,p2,p3,p4)
+#define SPP_TRACE_WARNING5(m,p1,p2,p3,p4,p5)
+#define SPP_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6)
+
+#define SPP_TRACE_EVENT0(m)
+#define SPP_TRACE_EVENT1(m,p1)
+#define SPP_TRACE_EVENT2(m,p1,p2)
+#define SPP_TRACE_EVENT3(m,p1,p2,p3)
+#define SPP_TRACE_EVENT4(m,p1,p2,p3,p4)
+#define SPP_TRACE_EVENT5(m,p1,p2,p3,p4,p5)
+#define SPP_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6)
+
+#define SPP_TRACE_API0(m)
+#define SPP_TRACE_API1(m,p1)
+#define SPP_TRACE_API2(m,p1,p2)
+#define SPP_TRACE_API3(m,p1,p2,p3)
+#define SPP_TRACE_API4(m,p1,p2,p3,p4)
+#define SPP_TRACE_API5(m,p1,p2,p3,p4,p5)
+#define SPP_TRACE_API6(m,p1,p2,p3,p4,p5,p6)
+
+#define SPP_TRACE_DEBUG0(m)
+#define SPP_TRACE_DEBUG1(m,p1)
+#define SPP_TRACE_DEBUG2(m,p1,p2)
+#define SPP_TRACE_DEBUG3(m,p1,p2,p3)
+#define SPP_TRACE_DEBUG4(m,p1,p2,p3,p4)
+#define SPP_TRACE_DEBUG5(m,p1,p2,p3,p4,p5)
+#define SPP_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6)
+
+
+/* Generic Access Profile traces */
+#define GAP_TRACE_ERROR0(m)
+#define GAP_TRACE_ERROR1(m,p1)
+#define GAP_TRACE_ERROR2(m,p1,p2)
+#define GAP_TRACE_ERROR3(m,p1,p2,p3)
+#define GAP_TRACE_ERROR4(m,p1,p2,p3,p4)
+#define GAP_TRACE_ERROR5(m,p1,p2,p3,p4,p5)
+#define GAP_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6)
+
+#define GAP_TRACE_EVENT0(m)
+#define GAP_TRACE_EVENT1(m,p1)
+#define GAP_TRACE_EVENT2(m,p1,p2)
+#define GAP_TRACE_EVENT3(m,p1,p2,p3)
+#define GAP_TRACE_EVENT4(m,p1,p2,p3,p4)
+#define GAP_TRACE_EVENT5(m,p1,p2,p3,p4,p5)
+#define GAP_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6)
+
+#define GAP_TRACE_API0(m)
+#define GAP_TRACE_API1(m,p1)
+#define GAP_TRACE_API2(m,p1,p2)
+#define GAP_TRACE_API3(m,p1,p2,p3)
+#define GAP_TRACE_API4(m,p1,p2,p3,p4)
+#define GAP_TRACE_API5(m,p1,p2,p3,p4,p5)
+#define GAP_TRACE_API6(m,p1,p2,p3,p4,p5,p6)
+
+#define GAP_TRACE_WARNING0(m)
+#define GAP_TRACE_WARNING1(m,p1)
+#define GAP_TRACE_WARNING2(m,p1,p2)
+#define GAP_TRACE_WARNING3(m,p1,p2,p3)
+#define GAP_TRACE_WARNING4(m,p1,p2,p3,p4)
+#define GAP_TRACE_WARNING5(m,p1,p2,p3,p4,p5)
+#define GAP_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6)
+
+
+/* Define tracing for OBX
+*/
+#define OBX_TRACE_ERROR0(m)
+#define OBX_TRACE_ERROR1(m,p1)
+#define OBX_TRACE_ERROR2(m,p1,p2)
+#define OBX_TRACE_ERROR3(m,p1,p2,p3)
+#define OBX_TRACE_ERROR4(m,p1,p2,p3,p4)
+#define OBX_TRACE_ERROR5(m,p1,p2,p3,p4,p5)
+#define OBX_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6)
+
+#define OBX_TRACE_WARNING0(m)
+#define OBX_TRACE_WARNING1(m,p1)
+#define OBX_TRACE_WARNING2(m,p1,p2)
+#define OBX_TRACE_WARNING3(m,p1,p2,p3)
+#define OBX_TRACE_WARNING4(m,p1,p2,p3,p4)
+#define OBX_TRACE_WARNING5(m,p1,p2,p3,p4,p5)
+#define OBX_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6)
+
+#define OBX_TRACE_EVENT0(m)
+#define OBX_TRACE_EVENT1(m,p1)
+#define OBX_TRACE_EVENT2(m,p1,p2)
+#define OBX_TRACE_EVENT3(m,p1,p2,p3)
+#define OBX_TRACE_EVENT4(m,p1,p2,p3,p4)
+#define OBX_TRACE_EVENT5(m,p1,p2,p3,p4,p5)
+#define OBX_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6)
+
+#define OBX_TRACE_DEBUG0(m)
+#define OBX_TRACE_DEBUG1(m,p1)
+#define OBX_TRACE_DEBUG2(m,p1,p2)
+#define OBX_TRACE_DEBUG3(m,p1,p2,p3)
+#define OBX_TRACE_DEBUG4(m,p1,p2,p3,p4)
+#define OBX_TRACE_DEBUG5(m,p1,p2,p3,p4,p5)
+#define OBX_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6)
+
+#define OBX_TRACE_API0(m)
+#define OBX_TRACE_API1(m,p1)
+#define OBX_TRACE_API2(m,p1,p2)
+#define OBX_TRACE_API3(m,p1,p2,p3)
+#define OBX_TRACE_API4(m,p1,p2,p3,p4)
+#define OBX_TRACE_API5(m,p1,p2,p3,p4,p5)
+#define OBX_TRACE_API6(m,p1,p2,p3,p4,p5,p6)
+
+/* Define tracing for GOEP application profiles
+*/
+#define GOEP_TRACE_ERROR0(m)
+#define GOEP_TRACE_ERROR1(m,p1)
+#define GOEP_TRACE_ERROR2(m,p1,p2)
+#define GOEP_TRACE_ERROR3(m,p1,p2,p3)
+#define GOEP_TRACE_ERROR4(m,p1,p2,p3,p4)
+#define GOEP_TRACE_ERROR5(m,p1,p2,p3,p4,p5)
+#define GOEP_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6)
+
+#define GOEP_TRACE_WARNING0(m)
+#define GOEP_TRACE_WARNING1(m,p1)
+#define GOEP_TRACE_WARNING2(m,p1,p2)
+#define GOEP_TRACE_WARNING3(m,p1,p2,p3)
+#define GOEP_TRACE_WARNING4(m,p1,p2,p3,p4)
+#define GOEP_TRACE_WARNING5(m,p1,p2,p3,p4,p5)
+#define GOEP_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6)
+
+#define GOEP_TRACE_EVENT0(m)
+#define GOEP_TRACE_EVENT1(m,p1)
+#define GOEP_TRACE_EVENT2(m,p1,p2)
+#define GOEP_TRACE_EVENT3(m,p1,p2,p3)
+#define GOEP_TRACE_EVENT4(m,p1,p2,p3,p4)
+#define GOEP_TRACE_EVENT5(m,p1,p2,p3,p4,p5)
+#define GOEP_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6)
+
+#define GOEP_TRACE_DEBUG0(m)
+#define GOEP_TRACE_DEBUG1(m,p1)
+#define GOEP_TRACE_DEBUG2(m,p1,p2)
+#define GOEP_TRACE_DEBUG3(m,p1,p2,p3)
+#define GOEP_TRACE_DEBUG4(m,p1,p2,p3,p4)
+#define GOEP_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6)
+
+#define GOEP_TRACE_API0(m)
+#define GOEP_TRACE_API1(m,p1)
+#define GOEP_TRACE_API2(m,p1,p2)
+#define GOEP_TRACE_API3(m,p1,p2,p3)
+#define GOEP_TRACE_API4(m,p1,p2,p3,p4)
+#define GOEP_TRACE_API5(m,p1,p2,p3,p4,p5)
+#define GOEP_TRACE_API6(m,p1,p2,p3,p4,p5,p6)
+
+/* Define tracing for the BPP profile
+*/
+#define BPP_TRACE_ERROR0(m)
+#define BPP_TRACE_ERROR1(m,p1)
+#define BPP_TRACE_ERROR2(m,p1,p2)
+#define BPP_TRACE_ERROR3(m,p1,p2,p3)
+#define BPP_TRACE_ERROR4(m,p1,p2,p3,p4)
+#define BPP_TRACE_ERROR5(m,p1,p2,p3,p4,p5)
+#define BPP_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6)
+
+#define BPP_TRACE_WARNING0(m)
+#define BPP_TRACE_WARNING1(m,p1)
+#define BPP_TRACE_WARNING2(m,p1,p2)
+#define BPP_TRACE_WARNING3(m,p1,p2,p3)
+#define BPP_TRACE_WARNING4(m,p1,p2,p3,p4)
+#define BPP_TRACE_WARNING5(m,p1,p2,p3,p4,p5)
+#define BPP_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6)
+
+#define BPP_TRACE_EVENT0(m)
+#define BPP_TRACE_EVENT1(m,p1)
+#define BPP_TRACE_EVENT2(m,p1,p2)
+#define BPP_TRACE_EVENT3(m,p1,p2,p3)
+#define BPP_TRACE_EVENT4(m,p1,p2,p3,p4)
+#define BPP_TRACE_EVENT5(m,p1,p2,p3,p4,p5)
+#define BPP_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6)
+
+#define BPP_TRACE_DEBUG0(m)
+#define BPP_TRACE_DEBUG1(m,p1)
+#define BPP_TRACE_DEBUG2(m,p1,p2)
+#define BPP_TRACE_DEBUG3(m,p1,p2,p3)
+#define BPP_TRACE_DEBUG4(m,p1,p2,p3,p4)
+#define BPP_TRACE_DEBUG5(m,p1,p2,p3,p4,p5)
+#define BPP_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6)
+
+#define BPP_TRACE_API0(m)
+#define BPP_TRACE_API1(m,p1)
+#define BPP_TRACE_API2(m,p1,p2)
+#define BPP_TRACE_API3(m,p1,p2,p3)
+#define BPP_TRACE_API4(m,p1,p2,p3,p4)
+#define BPP_TRACE_API5(m,p1,p2,p3,p4,p5)
+#define BPP_TRACE_API6(m,p1,p2,p3,p4,p5,p6)
+
+/* Define tracing for the BIP profile
+*/
+#define BIP_TRACE_ERROR0(m)
+#define BIP_TRACE_ERROR1(m,p1)
+#define BIP_TRACE_ERROR2(m,p1,p2)
+#define BIP_TRACE_ERROR3(m,p1,p2,p3)
+#define BIP_TRACE_ERROR4(m,p1,p2,p3,p4)
+#define BIP_TRACE_ERROR5(m,p1,p2,p3,p4,p5)
+#define BIP_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6)
+
+#define BIP_TRACE_WARNING0(m)
+#define BIP_TRACE_WARNING1(m,p1)
+#define BIP_TRACE_WARNING2(m,p1,p2)
+#define BIP_TRACE_WARNING3(m,p1,p2,p3)
+#define BIP_TRACE_WARNING4(m,p1,p2,p3,p4)
+#define BIP_TRACE_WARNING5(m,p1,p2,p3,p4,p5)
+#define BIP_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6)
+
+#define BIP_TRACE_EVENT0(m)
+#define BIP_TRACE_EVENT1(m,p1)
+#define BIP_TRACE_EVENT2(m,p1,p2)
+#define BIP_TRACE_EVENT3(m,p1,p2,p3)
+#define BIP_TRACE_EVENT4(m,p1,p2,p3,p4)
+#define BIP_TRACE_EVENT5(m,p1,p2,p3,p4,p5)
+#define BIP_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6)
+
+#define BIP_TRACE_DEBUG0(m)
+#define BIP_TRACE_DEBUG1(m,p1)
+#define BIP_TRACE_DEBUG2(m,p1,p2)
+#define BIP_TRACE_DEBUG3(m,p1,p2,p3)
+#define BIP_TRACE_DEBUG4(m,p1,p2,p3,p4)
+#define BIP_TRACE_DEBUG5(m,p1,p2,p3,p4,p5)
+#define BIP_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6)
+
+#define BIP_TRACE_API0(m)
+#define BIP_TRACE_API1(m,p1)
+#define BIP_TRACE_API2(m,p1,p2)
+#define BIP_TRACE_API3(m,p1,p2,p3)
+#define BIP_TRACE_API4(m,p1,p2,p3,p4)
+#define BIP_TRACE_API5(m,p1,p2,p3,p4,p5)
+#define BIP_TRACE_API6(m,p1,p2,p3,p4,p5,p6)
+
+/* Define tracing for TCS
+*/
+#define TCS_TRACE_ERROR0(m)
+#define TCS_TRACE_ERROR1(m,p1)
+#define TCS_TRACE_ERROR2(m,p1,p2)
+#define TCS_TRACE_ERROR3(m,p1,p2,p3)
+#define TCS_TRACE_ERROR4(m,p1,p2,p3,p4)
+#define TCS_TRACE_ERROR5(m,p1,p2,p3,p4,p5)
+#define TCS_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6)
+
+#define TCS_TRACE_WARNING0(m)
+#define TCS_TRACE_WARNING1(m,p1)
+#define TCS_TRACE_WARNING2(m,p1,p2)
+#define TCS_TRACE_WARNING3(m,p1,p2,p3)
+#define TCS_TRACE_WARNING4(m,p1,p2,p3,p4)
+#define TCS_TRACE_WARNING5(m,p1,p2,p3,p4,p5)
+#define TCS_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6)
+
+#define TCS_TRACE_EVENT0(m)
+#define TCS_TRACE_EVENT1(m,p1)
+#define TCS_TRACE_EVENT2(m,p1,p2)
+#define TCS_TRACE_EVENT3(m,p1,p2,p3)
+#define TCS_TRACE_EVENT4(m,p1,p2,p3,p4)
+#define TCS_TRACE_EVENT5(m,p1,p2,p3,p4,p5)
+#define TCS_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6)
+
+#define TCS_TRACE_DEBUG0(m)
+#define TCS_TRACE_DEBUG1(m,p1)
+#define TCS_TRACE_DEBUG2(m,p1,p2)
+#define TCS_TRACE_DEBUG3(m,p1,p2,p3)
+#define TCS_TRACE_DEBUG4(m,p1,p2,p3,p4)
+#define TCS_TRACE_DEBUG5(m,p1,p2,p3,p4,p5)
+#define TCS_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6)
+
+#define TCS_TRACE_API0(m)
+#define TCS_TRACE_API1(m,p1)
+#define TCS_TRACE_API2(m,p1,p2)
+#define TCS_TRACE_API3(m,p1,p2,p3)
+#define TCS_TRACE_API4(m,p1,p2,p3,p4)
+#define TCS_TRACE_API5(m,p1,p2,p3,p4,p5)
+#define TCS_TRACE_API6(m,p1,p2,p3,p4,p5,p6)
+
+/* Define tracing for ICP
+*/
+#define ICP_TRACE_ERROR0(m)
+#define ICP_TRACE_ERROR1(m,p1)
+#define ICP_TRACE_ERROR2(m,p1,p2)
+#define ICP_TRACE_ERROR3(m,p1,p2,p3)
+#define ICP_TRACE_ERROR4(m,p1,p2,p3,p4)
+#define ICP_TRACE_ERROR5(m,p1,p2,p3,p4,p5)
+#define ICP_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6)
+
+#define ICP_TRACE_WARNING0(m)
+#define ICP_TRACE_WARNING1(m,p1)
+#define ICP_TRACE_WARNING2(m,p1,p2)
+#define ICP_TRACE_WARNING3(m,p1,p2,p3)
+#define ICP_TRACE_WARNING4(m,p1,p2,p3,p4)
+#define ICP_TRACE_WARNING5(m,p1,p2,p3,p4,p5)
+#define ICP_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6)
+
+#define ICP_TRACE_EVENT0(m)
+#define ICP_TRACE_EVENT1(m,p1)
+#define ICP_TRACE_EVENT2(m,p1,p2)
+#define ICP_TRACE_EVENT3(m,p1,p2,p3)
+#define ICP_TRACE_EVENT4(m,p1,p2,p3,p4)
+#define ICP_TRACE_EVENT5(m,p1,p2,p3,p4,p5)
+#define ICP_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6)
+
+#define ICP_TRACE_DEBUG0(m)
+#define ICP_TRACE_DEBUG1(m,p1)
+#define ICP_TRACE_DEBUG2(m,p1,p2)
+#define ICP_TRACE_DEBUG3(m,p1,p2,p3)
+#define ICP_TRACE_DEBUG4(m,p1,p2,p3,p4)
+#define ICP_TRACE_DEBUG5(m,p1,p2,p3,p4,p5)
+#define ICP_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6)
+
+#define ICP_TRACE_API0(m)
+#define ICP_TRACE_API1(m,p1)
+#define ICP_TRACE_API2(m,p1,p2)
+#define ICP_TRACE_API3(m,p1,p2,p3)
+#define ICP_TRACE_API4(m,p1,p2,p3,p4)
+#define ICP_TRACE_API5(m,p1,p2,p3,p4,p5)
+#define ICP_TRACE_API6(m,p1,p2,p3,p4,p5,p6)
+
+/* Define tracing for CTP
+*/
+#define CTP_TRACE_ERROR0(m)
+#define CTP_TRACE_ERROR1(m,p1)
+#define CTP_TRACE_ERROR2(m,p1,p2)
+#define CTP_TRACE_ERROR3(m,p1,p2,p3)
+#define CTP_TRACE_ERROR4(m,p1,p2,p3,p4)
+#define CTP_TRACE_ERROR5(m,p1,p2,p3,p4,p5)
+#define CTP_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6)
+
+#define CTP_TRACE_WARNING0(m)
+#define CTP_TRACE_WARNING1(m,p1)
+#define CTP_TRACE_WARNING2(m,p1,p2)
+#define CTP_TRACE_WARNING3(m,p1,p2,p3)
+#define CTP_TRACE_WARNING4(m,p1,p2,p3,p4)
+#define CTP_TRACE_WARNING5(m,p1,p2,p3,p4,p5)
+#define CTP_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6)
+
+#define CTP_TRACE_EVENT0(m)
+#define CTP_TRACE_EVENT1(m,p1)
+#define CTP_TRACE_EVENT2(m,p1,p2)
+#define CTP_TRACE_EVENT3(m,p1,p2,p3)
+#define CTP_TRACE_EVENT4(m,p1,p2,p3,p4)
+#define CTP_TRACE_EVENT5(m,p1,p2,p3,p4,p5)
+#define CTP_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6)
+
+#define CTP_TRACE_DEBUG0(m)
+#define CTP_TRACE_DEBUG1(m,p1)
+#define CTP_TRACE_DEBUG2(m,p1,p2)
+#define CTP_TRACE_DEBUG3(m,p1,p2,p3)
+#define CTP_TRACE_DEBUG4(m,p1,p2,p3,p4)
+#define CTP_TRACE_DEBUG5(m,p1,p2,p3,p4,p5)
+#define CTP_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6)
+
+#define CTP_TRACE_API0(m)
+#define CTP_TRACE_API1(m,p1)
+#define CTP_TRACE_API2(m,p1,p2)
+#define CTP_TRACE_API3(m,p1,p2,p3)
+#define CTP_TRACE_API4(m,p1,p2,p3,p4)
+#define CTP_TRACE_API5(m,p1,p2,p3,p4,p5)
+#define CTP_TRACE_API6(m,p1,p2,p3,p4,p5,p6)
+
+/* define traces for headset profile */
+
+#define HSP2_TRACE_ERROR0(pcb,m)
+#define HSP2_TRACE_ERROR1(pcb,m,p1)
+#define HSP2_TRACE_ERROR2(pcb,m,p1,p2)
+#define HSP2_TRACE_ERROR3(pcb,m,p1,p2,p3)
+#define HSP2_TRACE_ERROR4(pcb,m,p1,p2,p3,p4)
+#define HSP2_TRACE_ERROR5(pcb,m,p1,p2,p3,p4,p5)
+#define HSP2_TRACE_ERROR6(pcb,m,p1,p2,p3,p4,p5,p6)
+
+#define HSP2_TRACE_WARNING0(pcb,m)
+#define HSP2_TRACE_WARNING1(pcb,m,p1)
+#define HSP2_TRACE_WARNING2(pcb,m,p1,p2)
+#define HSP2_TRACE_WARNING3(pcb,m,p1,p2,p3)
+#define HSP2_TRACE_WARNING4(pcb,m,p1,p2,p3,p4)
+#define HSP2_TRACE_WARNING5(pcb,m,p1,p2,p3,p4,p5)
+#define HSP2_TRACE_WARNING6(pcb,m,p1,p2,p3,p4,p5,p6)
+
+#define HSP2_TRACE_API0(pcb,m)
+#define HSP2_TRACE_API1(pcb,m,p1)
+#define HSP2_TRACE_API2(pcb,m,p1,p2)
+#define HSP2_TRACE_API3(pcb,m,p1,p2,p3)
+#define HSP2_TRACE_API4(pcb,m,p1,p2,p3,p4)
+#define HSP2_TRACE_API5(pcb,m,p1,p2,p3,p4,p5)
+#define HSP2_TRACE_API6(pcb,m,p1,p2,p3,p4,p5,p6)
+
+#define HSP2_TRACE_EVENT0(pcb,m)
+#define HSP2_TRACE_EVENT1(pcb,m,p1)
+#define HSP2_TRACE_EVENT2(pcb,m,p1,p2)
+#define HSP2_TRACE_EVENT3(pcb,m,p1,p2,p3)
+#define HSP2_TRACE_EVENT4(pcb,m,p1,p2,p3,p4)
+#define HSP2_TRACE_EVENT5(pcb,m,p1,p2,p3,p4,p5)
+#define HSP2_TRACE_EVENT6(pcb,m,p1,p2,p3,p4,p5,p6)
+
+#define HSP2_TRACE_DEBUG0(pcb,m)
+#define HSP2_TRACE_DEBUG1(pcb,m,p1)
+#define HSP2_TRACE_DEBUG2(pcb,m,p1,p2)
+#define HSP2_TRACE_DEBUG3(pcb,m,p1,p2,p3)
+#define HSP2_TRACE_DEBUG4(pcb,m,p1,p2,p3,p4)
+#define HSP2_TRACE_DEBUG5(pcb,m,p1,p2,p3,p4,p5)
+#define HSP2_TRACE_DEBUG6(pcb,m,p1,p2,p3,p4,p5,p6)
+
+/* Define tracing for the NFC unit
+*/
+#define NFC_TRACE_ERROR0(m)
+#define NFC_TRACE_ERROR1(m,p1)
+#define NFC_TRACE_ERROR2(m,p1,p2)
+#define NFC_TRACE_ERROR3(m,p1,p2,p3)
+#define NFC_TRACE_ERROR4(m,p1,p2,p3,p4)
+#define NFC_TRACE_ERROR5(m,p1,p2,p3,p4,p5)
+#define NFC_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6)
+
+#define NFC_TRACE_WARNING0(m)
+#define NFC_TRACE_WARNING1(m,p1)
+#define NFC_TRACE_WARNING2(m,p1,p2)
+#define NFC_TRACE_WARNING3(m,p1,p2,p3)
+#define NFC_TRACE_WARNING4(m,p1,p2,p3,p4)
+#define NFC_TRACE_WARNING5(m,p1,p2,p3,p4,p5)
+#define NFC_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6)
+
+#define NFC_TRACE_API0(m)
+#define NFC_TRACE_API1(m,p1)
+#define NFC_TRACE_API2(m,p1,p2)
+#define NFC_TRACE_API3(m,p1,p2,p3)
+#define NFC_TRACE_API4(m,p1,p2,p3,p4)
+#define NFC_TRACE_API5(m,p1,p2,p3,p4,p5)
+#define NFC_TRACE_API6(m,p1,p2,p3,p4,p5,p6)
+
+#define NFC_TRACE_EVENT0(m)
+#define NFC_TRACE_EVENT1(m,p1)
+#define NFC_TRACE_EVENT2(m,p1,p2)
+#define NFC_TRACE_EVENT3(m,p1,p2,p3)
+#define NFC_TRACE_EVENT4(m,p1,p2,p3,p4)
+#define NFC_TRACE_EVENT5(m,p1,p2,p3,p4,p5)
+#define NFC_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6)
+
+#define NFC_TRACE_DEBUG0(m)
+#define NFC_TRACE_DEBUG1(m,p1)
+#define NFC_TRACE_DEBUG2(m,p1,p2)
+#define NFC_TRACE_DEBUG3(m,p1,p2,p3)
+#define NFC_TRACE_DEBUG4(m,p1,p2,p3,p4)
+#define NFC_TRACE_DEBUG5(m,p1,p2,p3,p4,p5)
+#define NFC_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6)
+
+#define NCI_TRACE_ERROR0(m)
+#define NCI_TRACE_ERROR1(m,p1)
+#define NCI_TRACE_ERROR2(m,p1,p2)
+#define NCI_TRACE_ERROR3(m,p1,p2,p3)
+#define NCI_TRACE_ERROR4(m,p1,p2,p3,p4)
+#define NCI_TRACE_ERROR5(m,p1,p2,p3,p4,p5)
+#define NCI_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6)
+
+#define NCI_TRACE_WARNING0(m)
+#define NCI_TRACE_WARNING1(m,p1)
+#define NCI_TRACE_WARNING2(m,p1,p2)
+#define NCI_TRACE_WARNING3(m,p1,p2,p3)
+#define NCI_TRACE_WARNING4(m,p1,p2,p3,p4)
+#define NCI_TRACE_WARNING5(m,p1,p2,p3,p4,p5)
+#define NCI_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6)
+
+#define NCI_TRACE_API0(m)
+#define NCI_TRACE_API1(m,p1)
+#define NCI_TRACE_API2(m,p1,p2)
+#define NCI_TRACE_API3(m,p1,p2,p3)
+#define NCI_TRACE_API4(m,p1,p2,p3,p4)
+#define NCI_TRACE_API5(m,p1,p2,p3,p4,p5)
+#define NCI_TRACE_API6(m,p1,p2,p3,p4,p5,p6)
+
+#define NCI_TRACE_EVENT0(m)
+#define NCI_TRACE_EVENT1(m,p1)
+#define NCI_TRACE_EVENT2(m,p1,p2)
+#define NCI_TRACE_EVENT3(m,p1,p2,p3)
+#define NCI_TRACE_EVENT4(m,p1,p2,p3,p4)
+#define NCI_TRACE_EVENT5(m,p1,p2,p3,p4,p5)
+#define NCI_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6)
+
+#define NCI_TRACE_DEBUG0(m)
+#define NCI_TRACE_DEBUG1(m,p1)
+#define NCI_TRACE_DEBUG2(m,p1,p2)
+#define NCI_TRACE_DEBUG3(m,p1,p2,p3)
+#define NCI_TRACE_DEBUG4(m,p1,p2,p3,p4)
+#define NCI_TRACE_DEBUG5(m,p1,p2,p3,p4,p5)
+#define NCI_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6)
+
+#define RW_TRACE_ERROR0(m)
+#define RW_TRACE_ERROR1(m,p1)
+#define RW_TRACE_ERROR2(m,p1,p2)
+#define RW_TRACE_ERROR3(m,p1,p2,p3)
+#define RW_TRACE_ERROR4(m,p1,p2,p3,p4)
+#define RW_TRACE_ERROR5(m,p1,p2,p3,p4,p5)
+#define RW_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6)
+
+#define RW_TRACE_WARNING0(m)
+#define RW_TRACE_WARNING1(m,p1)
+#define RW_TRACE_WARNING2(m,p1,p2)
+#define RW_TRACE_WARNING3(m,p1,p2,p3)
+#define RW_TRACE_WARNING4(m,p1,p2,p3,p4)
+#define RW_TRACE_WARNING5(m,p1,p2,p3,p4,p5)
+#define RW_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6) }
+
+#define RW_TRACE_API0(m)
+#define RW_TRACE_API1(m,p1)
+#define RW_TRACE_API2(m,p1,p2)
+#define RW_TRACE_API3(m,p1,p2,p3)
+#define RW_TRACE_API4(m,p1,p2,p3,p4)
+#define RW_TRACE_API5(m,p1,p2,p3,p4,p5)
+#define RW_TRACE_API6(m,p1,p2,p3,p4,p5,p6)
+
+#define RW_TRACE_EVENT0(m)
+#define RW_TRACE_EVENT1(m,p1)
+#define RW_TRACE_EVENT2(m,p1,p2)
+#define RW_TRACE_EVENT3(m,p1,p2,p3)
+#define RW_TRACE_EVENT4(m,p1,p2,p3,p4)
+#define RW_TRACE_EVENT5(m,p1,p2,p3,p4,p5)
+#define RW_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6)
+
+#define RW_TRACE_DEBUG0(m)
+#define RW_TRACE_DEBUG1(m,p1)
+#define RW_TRACE_DEBUG2(m,p1,p2)
+#define RW_TRACE_DEBUG3(m,p1,p2,p3)
+#define RW_TRACE_DEBUG4(m,p1,p2,p3,p4)
+#define RW_TRACE_DEBUG5(m,p1,p2,p3,p4,p5)
+#define RW_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6)
+
+#define CE_TRACE_ERROR0(m)
+#define CE_TRACE_ERROR1(m,p1)
+#define CE_TRACE_ERROR2(m,p1,p2)
+#define CE_TRACE_ERROR3(m,p1,p2,p3)
+#define CE_TRACE_ERROR4(m,p1,p2,p3,p4)
+#define CE_TRACE_ERROR5(m,p1,p2,p3,p4,p5)
+#define CE_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6)
+
+#define CE_TRACE_WARNING0(m)
+#define CE_TRACE_WARNING1(m,p1)
+#define CE_TRACE_WARNING2(m,p1,p2)
+#define CE_TRACE_WARNING3(m,p1,p2,p3)
+#define CE_TRACE_WARNING4(m,p1,p2,p3,p4)
+#define CE_TRACE_WARNING5(m,p1,p2,p3,p4,p5)
+#define CE_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6)
+
+#define CE_TRACE_API0(m)
+#define CE_TRACE_API1(m,p1)
+#define CE_TRACE_API2(m,p1,p2)
+#define CE_TRACE_API3(m,p1,p2,p3)
+#define CE_TRACE_API4(m,p1,p2,p3,p4)
+#define CE_TRACE_API5(m,p1,p2,p3,p4,p5)
+#define CE_TRACE_API6(m,p1,p2,p3,p4,p5,p6)
+
+#define CE_TRACE_EVENT0(m)
+#define CE_TRACE_EVENT1(m,p1)
+#define CE_TRACE_EVENT2(m,p1,p2)
+#define CE_TRACE_EVENT3(m,p1,p2,p3)
+#define CE_TRACE_EVENT4(m,p1,p2,p3,p4)
+#define CE_TRACE_EVENT5(m,p1,p2,p3,p4,p5)
+#define CE_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6)
+
+#define CE_TRACE_DEBUG0(m)
+#define CE_TRACE_DEBUG1(m,p1)
+#define CE_TRACE_DEBUG2(m,p1,p2)
+#define CE_TRACE_DEBUG3(m,p1,p2,p3)
+#define CE_TRACE_DEBUG4(m,p1,p2,p3,p4)
+#define CE_TRACE_DEBUG5(m,p1,p2,p3,p4,p5)
+#define CE_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6)
+
+#define NDEF_TRACE_ERROR0(m)
+#define NDEF_TRACE_ERROR1(m,p1)
+#define NDEF_TRACE_ERROR2(m,p1,p2)
+#define NDEF_TRACE_ERROR3(m,p1,p2,p3)
+#define NDEF_TRACE_ERROR4(m,p1,p2,p3,p4)
+#define NDEF_TRACE_ERROR5(m,p1,p2,p3,p4,p5)
+#define NDEF_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6)
+
+#define NDEF_TRACE_WARNING0(m)
+#define NDEF_TRACE_WARNING1(m,p1)
+#define NDEF_TRACE_WARNING2(m,p1,p2)
+#define NDEF_TRACE_WARNING3(m,p1,p2,p3)
+#define NDEF_TRACE_WARNING4(m,p1,p2,p3,p4)
+#define NDEF_TRACE_WARNING5(m,p1,p2,p3,p4,p5)
+#define NDEF_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6)
+
+#define NDEF_TRACE_API0(m)
+#define NDEF_TRACE_API1(m,p1)
+#define NDEF_TRACE_API2(m,p1,p2)
+#define NDEF_TRACE_API3(m,p1,p2,p3)
+#define NDEF_TRACE_API4(m,p1,p2,p3,p4)
+#define NDEF_TRACE_API5(m,p1,p2,p3,p4,p5)
+#define NDEF_TRACE_API6(m,p1,p2,p3,p4,p5,p6)
+
+#define NDEF_TRACE_EVENT0(m)
+#define NDEF_TRACE_EVENT1(m,p1)
+#define NDEF_TRACE_EVENT2(m,p1,p2)
+#define NDEF_TRACE_EVENT3(m,p1,p2,p3)
+#define NDEF_TRACE_EVENT4(m,p1,p2,p3,p4)
+#define NDEF_TRACE_EVENT5(m,p1,p2,p3,p4,p5)
+#define NDEF_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6)
+
+#define NDEF_TRACE_DEBUG0(m)
+#define NDEF_TRACE_DEBUG1(m,p1)
+#define NDEF_TRACE_DEBUG2(m,p1,p2)
+#define NDEF_TRACE_DEBUG3(m,p1,p2,p3)
+#define NDEF_TRACE_DEBUG4(m,p1,p2,p3,p4)
+#define NDEF_TRACE_DEBUG5(m,p1,p2,p3,p4,p5)
+#define NDEF_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6)
+
+/* Define tracing for the NFA unit
+*/
+#define NFA_TRACE_ERROR0(m)
+#define NFA_TRACE_ERROR1(m,p1)
+#define NFA_TRACE_ERROR2(m,p1,p2)
+#define NFA_TRACE_ERROR3(m,p1,p2,p3)
+#define NFA_TRACE_ERROR4(m,p1,p2,p3,p4)
+#define NFA_TRACE_ERROR5(m,p1,p2,p3,p4,p5)
+#define NFA_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6)
+
+#define NFA_TRACE_WARNING0(m)
+#define NFA_TRACE_WARNING1(m,p1)
+#define NFA_TRACE_WARNING2(m,p1,p2)
+#define NFA_TRACE_WARNING3(m,p1,p2,p3)
+#define NFA_TRACE_WARNING4(m,p1,p2,p3,p4)
+#define NFA_TRACE_WARNING5(m,p1,p2,p3,p4,p5)
+#define NFA_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6)
+
+#define NFA_TRACE_API0(m)
+#define NFA_TRACE_API1(m,p1)
+#define NFA_TRACE_API2(m,p1,p2)
+#define NFA_TRACE_API3(m,p1,p2,p3)
+#define NFA_TRACE_API4(m,p1,p2,p3,p4)
+#define NFA_TRACE_API5(m,p1,p2,p3,p4,p5)
+#define NFA_TRACE_API6(m,p1,p2,p3,p4,p5,p6)
+
+#define NFA_TRACE_EVENT0(m)
+#define NFA_TRACE_EVENT1(m,p1)
+#define NFA_TRACE_EVENT2(m,p1,p2)
+#define NFA_TRACE_EVENT3(m,p1,p2,p3)
+#define NFA_TRACE_EVENT4(m,p1,p2,p3,p4)
+#define NFA_TRACE_EVENT5(m,p1,p2,p3,p4,p5)
+#define NFA_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6)
+
+#define NFA_TRACE_DEBUG0(m)
+#define NFA_TRACE_DEBUG1(m,p1)
+#define NFA_TRACE_DEBUG2(m,p1,p2)
+#define NFA_TRACE_DEBUG3(m,p1,p2,p3)
+#define NFA_TRACE_DEBUG4(m,p1,p2,p3,p4)
+#define NFA_TRACE_DEBUG5(m,p1,p2,p3,p4,p5)
+#define NFA_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6)
+
+
+/* define traces for HID Host */
+#define HIDH_TRACE_ERROR0(m)
+#define HIDH_TRACE_ERROR1(m,p1)
+#define HIDH_TRACE_ERROR2(m,p1,p2)
+#define HIDH_TRACE_ERROR3(m,p1,p2,p3)
+#define HIDH_TRACE_ERROR4(m,p1,p2,p3,p4)
+#define HIDH_TRACE_ERROR5(m,p1,p2,p3,p4,p5)
+#define HIDH_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6)
+
+#define HIDH_TRACE_WARNING0(m)
+#define HIDH_TRACE_WARNING1(m,p1)
+#define HIDH_TRACE_WARNING2(m,p1,p2)
+#define HIDH_TRACE_WARNING3(m,p1,p2,p3)
+#define HIDH_TRACE_WARNING4(m,p1,p2,p3,p4)
+#define HIDH_TRACE_WARNING5(m,p1,p2,p3,p4,p5)
+#define HIDH_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6)
+
+#define HIDH_TRACE_API0(m)
+#define HIDH_TRACE_API1(m,p1)
+#define HIDH_TRACE_API2(m,p1,p2)
+#define HIDH_TRACE_API3(m,p1,p2,p3)
+#define HIDH_TRACE_API4(m,p1,p2,p3,p4)
+#define HIDH_TRACE_API5(m,p1,p2,p3,p4,p5)
+#define HIDH_TRACE_API6(m,p1,p2,p3,p4,p5,p6)
+
+#define HIDH_TRACE_EVENT0(m)
+#define HIDH_TRACE_EVENT1(m,p1)
+#define HIDH_TRACE_EVENT2(m,p1,p2)
+#define HIDH_TRACE_EVENT3(m,p1,p2,p3)
+#define HIDH_TRACE_EVENT4(m,p1,p2,p3,p4)
+#define HIDH_TRACE_EVENT5(m,p1,p2,p3,p4,p5)
+#define HIDH_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6)
+
+#define HIDH_TRACE_DEBUG0(m)
+#define HIDH_TRACE_DEBUG1(m,p1)
+#define HIDH_TRACE_DEBUG2(m,p1,p2)
+#define HIDH_TRACE_DEBUG3(m,p1,p2,p3)
+#define HIDH_TRACE_DEBUG4(m,p1,p2,p3,p4)
+#define HIDH_TRACE_DEBUG5(m,p1,p2,p3,p4,p5)
+#define HIDH_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6)
+
+/* define traces for HID Device */
+#define HIDD_TRACE_ERROR0(m)
+#define HIDD_TRACE_ERROR1(m,p1)
+#define HIDD_TRACE_ERROR2(m,p1,p2)
+#define HIDD_TRACE_ERROR3(m,p1,p2,p3)
+#define HIDD_TRACE_ERROR4(m,p1,p2,p3,p4)
+#define HIDD_TRACE_ERROR5(m,p1,p2,p3,p4,p5)
+#define HIDD_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6)
+
+#define HIDD_TRACE_WARNING0(m)
+#define HIDD_TRACE_WARNING1(m,p1)
+#define HIDD_TRACE_WARNING2(m,p1,p2)
+#define HIDD_TRACE_WARNING3(m,p1,p2,p3)
+#define HIDD_TRACE_WARNING4(m,p1,p2,p3,p4)
+#define HIDD_TRACE_WARNING5(m,p1,p2,p3,p4,p5)
+#define HIDD_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6)
+
+#define HIDD_TRACE_API0(m)
+#define HIDD_TRACE_API1(m,p1)
+#define HIDD_TRACE_API2(m,p1,p2)
+#define HIDD_TRACE_API3(m,p1,p2,p3)
+#define HIDD_TRACE_API4(m,p1,p2,p3,p4)
+#define HIDD_TRACE_API5(m,p1,p2,p3,p4,p5)
+#define HIDD_TRACE_API6(m,p1,p2,p3,p4,p5,p6)
+
+#define HIDD_TRACE_EVENT0(m)
+#define HIDD_TRACE_EVENT1(m,p1)
+#define HIDD_TRACE_EVENT2(m,p1,p2)
+#define HIDD_TRACE_EVENT3(m,p1,p2,p3)
+#define HIDD_TRACE_EVENT4(m,p1,p2,p3,p4)
+#define HIDD_TRACE_EVENT5(m,p1,p2,p3,p4,p5)
+#define HIDD_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6)
+
+#define HIDD_TRACE_DEBUG0(m)
+#define HIDD_TRACE_DEBUG1(m,p1)
+#define HIDD_TRACE_DEBUG2(m,p1,p2)
+#define HIDD_TRACE_DEBUG3(m,p1,p2,p3)
+#define HIDD_TRACE_DEBUG4(m,p1,p2,p3,p4)
+#define HIDD_TRACE_DEBUG5(m,p1,p2,p3,p4,p5)
+#define HIDD_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6)
+
+/* define traces for DUN */
+
+#define DUN_TRACE_ERROR0(m)
+#define DUN_TRACE_ERROR1(m,p1)
+#define DUN_TRACE_ERROR2(m,p1,p2)
+#define DUN_TRACE_ERROR3(m,p1,p2,p3)
+#define DUN_TRACE_ERROR4(m,p1,p2,p3,p4)
+#define DUN_TRACE_ERROR5(m,p1,p2,p3,p4,p5)
+#define DUN_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6)
+
+#define DUN_TRACE_WARNING0(m)
+#define DUN_TRACE_WARNING1(m,p1)
+#define DUN_TRACE_WARNING2(m,p1,p2)
+#define DUN_TRACE_WARNING3(m,p1,p2,p3)
+#define DUN_TRACE_WARNING4(m,p1,p2,p3,p4)
+#define DUN_TRACE_WARNING5(m,p1,p2,p3,p4,p5)
+#define DUN_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6)
+
+#define DUN_TRACE_API0(m)
+#define DUN_TRACE_API1(m,p1)
+#define DUN_TRACE_API2(m,p1,p2)
+#define DUN_TRACE_API3(m,p1,p2,p3)
+#define DUN_TRACE_API4(m,p1,p2,p3,p4)
+#define DUN_TRACE_API5(m,p1,p2,p3,p4,p5)
+#define DUN_TRACE_API6(m,p1,p2,p3,p4,p5,p6)
+
+#define DUN_TRACE_EVENT0(m)
+#define DUN_TRACE_EVENT1(m,p1)
+#define DUN_TRACE_EVENT2(m,p1,p2)
+#define DUN_TRACE_EVENT3(m,p1,p2,p3)
+#define DUN_TRACE_EVENT4(m,p1,p2,p3,p4)
+#define DUN_TRACE_EVENT5(m,p1,p2,p3,p4,p5)
+#define DUN_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6)
+
+#define DUN_TRACE_DEBUG0(m)
+#define DUN_TRACE_DEBUG1(m,p1)
+#define DUN_TRACE_DEBUG2(m,p1,p2)
+#define DUN_TRACE_DEBUG3(m,p1,p2,p3)
+#define DUN_TRACE_DEBUG4(m,p1,p2,p3,p4)
+#define DUN_TRACE_DEBUG5(m,p1,p2,p3,p4,p5)
+#define DUN_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6)
+
+/* define traces for HCRP */
+
+#define HCRP_TRACE_ERROR0(m)
+#define HCRP_TRACE_ERROR1(m,p1)
+#define HCRP_TRACE_ERROR2(m,p1,p2)
+#define HCRP_TRACE_ERROR3(m,p1,p2,p3)
+#define HCRP_TRACE_ERROR4(m,p1,p2,p3,p4)
+#define HCRP_TRACE_ERROR5(m,p1,p2,p3,p4,p5)
+#define HCRP_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6)
+
+#define HCRP_TRACE_WARNING0(m)
+#define HCRP_TRACE_WARNING1(m,p1)
+#define HCRP_TRACE_WARNING2(m,p1,p2)
+#define HCRP_TRACE_WARNING3(m,p1,p2,p3)
+#define HCRP_TRACE_WARNING4(m,p1,p2,p3,p4)
+#define HCRP_TRACE_WARNING5(m,p1,p2,p3,p4,p5)
+#define HCRP_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6)
+
+#define HCRP_TRACE_API0(m)
+#define HCRP_TRACE_API1(m,p1)
+#define HCRP_TRACE_API2(m,p1,p2)
+#define HCRP_TRACE_API3(m,p1,p2,p3)
+#define HCRP_TRACE_API4(m,p1,p2,p3,p4)
+#define HCRP_TRACE_API5(m,p1,p2,p3,p4,p5)
+#define HCRP_TRACE_API6(m,p1,p2,p3,p4,p5,p6)
+
+#define HCRP_TRACE_EVENT0(m)
+#define HCRP_TRACE_EVENT1(m,p1)
+#define HCRP_TRACE_EVENT2(m,p1,p2)
+#define HCRP_TRACE_EVENT3(m,p1,p2,p3)
+#define HCRP_TRACE_EVENT4(m,p1,p2,p3,p4)
+#define HCRP_TRACE_EVENT5(m,p1,p2,p3,p4,p5)
+#define HCRP_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6)
+
+#define HCRP_TRACE_DEBUG0(m)
+#define HCRP_TRACE_DEBUG1(m,p1)
+#define HCRP_TRACE_DEBUG2(m,p1,p2)
+#define HCRP_TRACE_DEBUG3(m,p1,p2,p3)
+#define HCRP_TRACE_DEBUG4(m,p1,p2,p3,p4)
+#define HCRP_TRACE_DEBUG5(m,p1,p2,p3,p4,p5)
+#define HCRP_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6)
+
+
+/* define traces for HCRP */
+
+#define HCRPM_TRACE_ERROR0(m)
+#define HCRPM_TRACE_ERROR1(m,p1)
+#define HCRPM_TRACE_ERROR2(m,p1,p2)
+#define HCRPM_TRACE_ERROR3(m,p1,p2,p3)
+#define HCRPM_TRACE_ERROR4(m,p1,p2,p3,p4)
+#define HCRPM_TRACE_ERROR5(m,p1,p2,p3,p4,p5)
+#define HCRPM_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6)
+
+#define HCRPM_TRACE_WARNING0(m)
+#define HCRPM_TRACE_WARNING1(m,p1)
+#define HCRPM_TRACE_WARNING2(m,p1,p2)
+#define HCRPM_TRACE_WARNING3(m,p1,p2,p3)
+#define HCRPM_TRACE_WARNING4(m,p1,p2,p3,p4)
+#define HCRPM_TRACE_WARNING5(m,p1,p2,p3,p4,p5)
+#define HCRPM_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6)
+
+#define HCRPM_TRACE_API0(m)
+#define HCRPM_TRACE_API1(m,p1)
+#define HCRPM_TRACE_API2(m,p1,p2)
+#define HCRPM_TRACE_API3(m,p1,p2,p3)
+#define HCRPM_TRACE_API4(m,p1,p2,p3,p4)
+#define HCRPM_TRACE_API5(m,p1,p2,p3,p4,p5)
+#define HCRPM_TRACE_API6(m,p1,p2,p3,p4,p5,p6)
+
+#define HCRPM_TRACE_EVENT0(m)
+#define HCRPM_TRACE_EVENT1(m,p1)
+#define HCRPM_TRACE_EVENT2(m,p1,p2)
+#define HCRPM_TRACE_EVENT3(m,p1,p2,p3)
+#define HCRPM_TRACE_EVENT4(m,p1,p2,p3,p4)
+#define HCRPM_TRACE_EVENT5(m,p1,p2,p3,p4,p5)
+#define HCRPM_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6)
+
+#define HCRPM_TRACE_DEBUG0(m)
+#define HCRPM_TRACE_DEBUG1(m,p1)
+#define HCRPM_TRACE_DEBUG2(m,p1,p2)
+#define HCRPM_TRACE_DEBUG3(m,p1,p2,p3)
+#define HCRPM_TRACE_DEBUG4(m,p1,p2,p3,p4)
+#define HCRPM_TRACE_DEBUG5(m,p1,p2,p3,p4,p5)
+#define HCRPM_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6)
+
+/* define traces for RPC */
+
+#define RPC_TRACE_ERROR0(m)
+#define RPC_TRACE_ERROR1(m,p1)
+#define RPC_TRACE_ERROR2(m,p1,p2)
+#define RPC_TRACE_ERROR3(m,p1,p2,p3)
+#define RPC_TRACE_ERROR4(m,p1,p2,p3,p4)
+#define RPC_TRACE_ERROR5(m,p1,p2,p3,p4,p5)
+#define RPC_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6)
+
+#define RPC_TRACE_WARNING0(m)
+#define RPC_TRACE_WARNING1(m,p1)
+#define RPC_TRACE_WARNING2(m,p1,p2)
+#define RPC_TRACE_WARNING3(m,p1,p2,p3)
+#define RPC_TRACE_WARNING4(m,p1,p2,p3,p4)
+#define RPC_TRACE_WARNING5(m,p1,p2,p3,p4,p5)
+#define RPC_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6)
+
+#define RPC_TRACE_API0(m)
+#define RPC_TRACE_API1(m,p1)
+#define RPC_TRACE_API2(m,p1,p2)
+#define RPC_TRACE_API3(m,p1,p2,p3)
+#define RPC_TRACE_API4(m,p1,p2,p3,p4)
+#define RPC_TRACE_API5(m,p1,p2,p3,p4,p5)
+#define RPC_TRACE_API6(m,p1,p2,p3,p4,p5,p6)
+
+#define RPC_TRACE_EVENT0(m)
+#define RPC_TRACE_EVENT1(m,p1)
+#define RPC_TRACE_EVENT2(m,p1,p2)
+#define RPC_TRACE_EVENT3(m,p1,p2,p3)
+#define RPC_TRACE_EVENT4(m,p1,p2,p3,p4)
+#define RPC_TRACE_EVENT5(m,p1,p2,p3,p4,p5)
+#define RPC_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6)
+
+#define RPC_TRACE_DEBUG0(m)
+#define RPC_TRACE_DEBUG1(m,p1)
+#define RPC_TRACE_DEBUG2(m,p1,p2)
+#define RPC_TRACE_DEBUG3(m,p1,p2,p3)
+#define RPC_TRACE_DEBUG4(m,p1,p2,p3,p4)
+#define RPC_TRACE_DEBUG5(m,p1,p2,p3,p4,p5)
+#define RPC_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6)
+
+/* define traces for BNEP */
+
+#define BNEP_TRACE_ERROR0(m)
+#define BNEP_TRACE_ERROR1(m,p1)
+#define BNEP_TRACE_ERROR2(m,p1,p2)
+#define BNEP_TRACE_ERROR3(m,p1,p2,p3)
+#define BNEP_TRACE_ERROR4(m,p1,p2,p3,p4)
+#define BNEP_TRACE_ERROR5(m,p1,p2,p3,p4,p5)
+#define BNEP_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6)
+
+#define BNEP_TRACE_WARNING0(m)
+#define BNEP_TRACE_WARNING1(m,p1)
+#define BNEP_TRACE_WARNING2(m,p1,p2)
+#define BNEP_TRACE_WARNING3(m,p1,p2,p3)
+#define BNEP_TRACE_WARNING4(m,p1,p2,p3,p4)
+#define BNEP_TRACE_WARNING5(m,p1,p2,p3,p4,p5)
+#define BNEP_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6)
+
+#define BNEP_TRACE_API0(m)
+#define BNEP_TRACE_API1(m,p1)
+#define BNEP_TRACE_API2(m,p1,p2)
+#define BNEP_TRACE_API3(m,p1,p2,p3)
+#define BNEP_TRACE_API4(m,p1,p2,p3,p4)
+#define BNEP_TRACE_API5(m,p1,p2,p3,p4,p5)
+#define BNEP_TRACE_API6(m,p1,p2,p3,p4,p5,p6)
+
+#define BNEP_TRACE_EVENT0(m)
+#define BNEP_TRACE_EVENT1(m,p1)
+#define BNEP_TRACE_EVENT2(m,p1,p2)
+#define BNEP_TRACE_EVENT3(m,p1,p2,p3)
+#define BNEP_TRACE_EVENT4(m,p1,p2,p3,p4)
+#define BNEP_TRACE_EVENT5(m,p1,p2,p3,p4,p5)
+#define BNEP_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6)
+
+#define BNEP_TRACE_DEBUG0(m)
+#define BNEP_TRACE_DEBUG1(m,p1)
+#define BNEP_TRACE_DEBUG2(m,p1,p2)
+#define BNEP_TRACE_DEBUG3(m,p1,p2,p3)
+#define BNEP_TRACE_DEBUG4(m,p1,p2,p3,p4)
+#define BNEP_TRACE_DEBUG5(m,p1,p2,p3,p4,p5)
+#define BNEP_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6)
+
+/* hid module traces */
+
+#define MSKB_TRACE_0(m)
+#define MSKB_TRACE_1(m,p1)
+#define MSKB_TRACE_2(m,p1,p2)
+#define MSKB_TRACE_3(m,p1,p2,p3)
+#define MSKB_TRACE_4(m,p1,p2,p3,p4)
+#define MSKB_TRACE_5(m,p1,p2,p3,p4,p5)
+#define MSKB_TRACE_6(m,p1,p2,p3,p4,p5,p6)
+
+#define MSKB_DEBUG_0(m)
+#define MSKB_DEBUG_1(m,p1)
+#define MSKB_DEBUG_2(m,p1,p2)
+#define MSKB_DEBUG_3(m,p1,p2,p3)
+#define MSKB_DEBUG_4(m,p1,p2,p3,p4)
+#define MSKB_DEBUG_5(m,p1,p2,p3,p4,p5)
+#define MSKB_DEBUG_6(m,p1,p2,p3,p4,p5,p6)
+
+#define MSKB_ERROR_0(m)
+#define MSKB_ERROR_1(m,p1)
+#define MSKB_ERROR_2(m,p1,p2)
+#define MSKB_ERROR_3(m,p1,p2,p3)
+#define MSKB_ERROR_4(m,p1,p2,p3,p4)
+#define MSKB_ERROR_5(m,p1,p2,p3,p4,p5)
+#define MSKB_ERROR_6(m,p1,p2,p3,p4,p5,p6)
+
+/* define traces for PAN */
+
+#define PAN_TRACE_ERROR0(m)
+#define PAN_TRACE_ERROR1(m,p1)
+#define PAN_TRACE_ERROR2(m,p1,p2)
+#define PAN_TRACE_ERROR3(m,p1,p2,p3)
+#define PAN_TRACE_ERROR4(m,p1,p2,p3,p4)
+#define PAN_TRACE_ERROR5(m,p1,p2,p3,p4,p5)
+#define PAN_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6)
+
+#define PAN_TRACE_WARNING0(m)
+#define PAN_TRACE_WARNING1(m,p1)
+#define PAN_TRACE_WARNING2(m,p1,p2)
+#define PAN_TRACE_WARNING3(m,p1,p2,p3)
+#define PAN_TRACE_WARNING4(m,p1,p2,p3,p4)
+#define PAN_TRACE_WARNING5(m,p1,p2,p3,p4,p5)
+#define PAN_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6)
+
+#define PAN_TRACE_API0(m)
+#define PAN_TRACE_API1(m,p1)
+#define PAN_TRACE_API2(m,p1,p2)
+#define PAN_TRACE_API3(m,p1,p2,p3)
+#define PAN_TRACE_API4(m,p1,p2,p3,p4)
+#define PAN_TRACE_API5(m,p1,p2,p3,p4,p5)
+#define PAN_TRACE_API6(m,p1,p2,p3,p4,p5,p6)
+
+#define PAN_TRACE_EVENT0(m)
+#define PAN_TRACE_EVENT1(m,p1)
+#define PAN_TRACE_EVENT2(m,p1,p2)
+#define PAN_TRACE_EVENT3(m,p1,p2,p3)
+#define PAN_TRACE_EVENT4(m,p1,p2,p3,p4)
+#define PAN_TRACE_EVENT5(m,p1,p2,p3,p4,p5)
+#define PAN_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6)
+
+#define PAN_TRACE_DEBUG0(m)
+#define PAN_TRACE_DEBUG1(m,p1)
+#define PAN_TRACE_DEBUG2(m,p1,p2)
+#define PAN_TRACE_DEBUG3(m,p1,p2,p3)
+#define PAN_TRACE_DEBUG4(m,p1,p2,p3,p4)
+#define PAN_TRACE_DEBUG5(m,p1,p2,p3,p4,p5)
+#define PAN_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6)
+
+/* define traces for SIM */
+
+#define SAP_TRACE_ERROR0(m)
+#define SAP_TRACE_ERROR1(m,p1)
+#define SAP_TRACE_ERROR2(m,p1,p2)
+#define SAP_TRACE_ERROR3(m,p1,p2,p3)
+#define SAP_TRACE_ERROR4(m,p1,p2,p3,p4)
+#define SAP_TRACE_ERROR5(m,p1,p2,p3,p4,p5)
+#define SAP_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6)
+
+#define SAP_TRACE_WARNING0(m)
+#define SAP_TRACE_WARNING1(m,p1)
+#define SAP_TRACE_WARNING2(m,p1,p2)
+#define SAP_TRACE_WARNING3(m,p1,p2,p3)
+#define SAP_TRACE_WARNING4(m,p1,p2,p3,p4)
+#define SAP_TRACE_WARNING5(m,p1,p2,p3,p4,p5)
+#define SAP_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6)
+
+#define SAP_TRACE_API0(m)
+#define SAP_TRACE_API1(m,p1)
+#define SAP_TRACE_API2(m,p1,p2)
+#define SAP_TRACE_API3(m,p1,p2,p3)
+#define SAP_TRACE_API4(m,p1,p2,p3,p4)
+#define SAP_TRACE_API5(m,p1,p2,p3,p4,p5)
+#define SAP_TRACE_API6(m,p1,p2,p3,p4,p5,p6)
+
+#define SAP_TRACE_EVENT0(m)
+#define SAP_TRACE_EVENT1(m,p1)
+#define SAP_TRACE_EVENT2(m,p1,p2)
+#define SAP_TRACE_EVENT3(m,p1,p2,p3)
+#define SAP_TRACE_EVENT4(m,p1,p2,p3,p4)
+#define SAP_TRACE_EVENT5(m,p1,p2,p3,p4,p5)
+#define SAP_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6)
+
+#define SAP_TRACE_DEBUG0(m)
+#define SAP_TRACE_DEBUG1(m,p1)
+#define SAP_TRACE_DEBUG2(m,p1,p2)
+#define SAP_TRACE_DEBUG3(m,p1,p2,p3)
+#define SAP_TRACE_DEBUG4(m,p1,p2,p3,p4)
+#define SAP_TRACE_DEBUG5(m,p1,p2,p3,p4,p5)
+#define SAP_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6)
+
+/* Define tracing for the OPP profile
+*/
+#define OPP_TRACE_ERROR0(m)
+#define OPP_TRACE_ERROR1(m,p1)
+#define OPP_TRACE_ERROR2(m,p1,p2)
+#define OPP_TRACE_ERROR3(m,p1,p2,p3)
+#define OPP_TRACE_ERROR4(m,p1,p2,p3,p4)
+#define OPP_TRACE_ERROR5(m,p1,p2,p3,p4,p5)
+#define OPP_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6)
+
+#define OPP_TRACE_WARNING0(m)
+#define OPP_TRACE_WARNING1(m,p1)
+#define OPP_TRACE_WARNING2(m,p1,p2)
+#define OPP_TRACE_WARNING3(m,p1,p2,p3)
+#define OPP_TRACE_WARNING4(m,p1,p2,p3,p4)
+#define OPP_TRACE_WARNING5(m,p1,p2,p3,p4,p5)
+#define OPP_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6)
+
+#define OPP_TRACE_EVENT0(m)
+#define OPP_TRACE_EVENT1(m,p1)
+#define OPP_TRACE_EVENT2(m,p1,p2)
+#define OPP_TRACE_EVENT3(m,p1,p2,p3)
+#define OPP_TRACE_EVENT4(m,p1,p2,p3,p4)
+#define OPP_TRACE_EVENT5(m,p1,p2,p3,p4,p5)
+#define OPP_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6)
+
+#define OPP_TRACE_DEBUG0(m)
+#define OPP_TRACE_DEBUG1(m,p1)
+#define OPP_TRACE_DEBUG2(m,p1,p2)
+#define OPP_TRACE_DEBUG3(m,p1,p2,p3)
+#define OPP_TRACE_DEBUG4(m,p1,p2,p3,p4)
+#define OPP_TRACE_DEBUG5(m,p1,p2,p3,p4,p5)
+#define OPP_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6)
+
+#define OPP_TRACE_API0(m)
+#define OPP_TRACE_API1(m,p1)
+#define OPP_TRACE_API2(m,p1,p2)
+#define OPP_TRACE_API3(m,p1,p2,p3)
+#define OPP_TRACE_API4(m,p1,p2,p3,p4)
+#define OPP_TRACE_API5(m,p1,p2,p3,p4,p5)
+#define OPP_TRACE_API6(m,p1,p2,p3,p4,p5,p6)
+
+/* Define tracing for the FTP profile
+*/
+#define FTP_TRACE_ERROR0(m)
+#define FTP_TRACE_ERROR1(m,p1)
+#define FTP_TRACE_ERROR2(m,p1,p2)
+#define FTP_TRACE_ERROR3(m,p1,p2,p3)
+#define FTP_TRACE_ERROR4(m,p1,p2,p3,p4)
+#define FTP_TRACE_ERROR5(m,p1,p2,p3,p4,p5)
+#define FTP_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6)
+
+#define FTP_TRACE_WARNING0(m)
+#define FTP_TRACE_WARNING1(m,p1)
+#define FTP_TRACE_WARNING2(m,p1,p2)
+#define FTP_TRACE_WARNING3(m,p1,p2,p3)
+#define FTP_TRACE_WARNING4(m,p1,p2,p3,p4)
+#define FTP_TRACE_WARNING5(m,p1,p2,p3,p4,p5)
+#define FTP_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6)
+
+#define FTP_TRACE_EVENT0(m)
+#define FTP_TRACE_EVENT1(m,p1)
+#define FTP_TRACE_EVENT2(m,p1,p2)
+#define FTP_TRACE_EVENT3(m,p1,p2,p3)
+#define FTP_TRACE_EVENT4(m,p1,p2,p3,p4)
+#define FTP_TRACE_EVENT5(m,p1,p2,p3,p4,p5)
+#define FTP_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6)
+
+#define FTP_TRACE_DEBUG0(m)
+#define FTP_TRACE_DEBUG1(m,p1)
+#define FTP_TRACE_DEBUG2(m,p1,p2)
+#define FTP_TRACE_DEBUG3(m,p1,p2,p3)
+#define FTP_TRACE_DEBUG4(m,p1,p2,p3,p4)
+#define FTP_TRACE_DEBUG5(m,p1,p2,p3,p4,p5)
+#define FTP_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6)
+
+#define FTP_TRACE_API0(m)
+#define FTP_TRACE_API1(m,p1)
+#define FTP_TRACE_API2(m,p1,p2)
+#define FTP_TRACE_API3(m,p1,p2,p3)
+#define FTP_TRACE_API4(m,p1,p2,p3,p4)
+#define FTP_TRACE_API5(m,p1,p2,p3,p4,p5)
+#define FTP_TRACE_API6(m,p1,p2,p3,p4,p5,p6)
+
+
+/* Define tracing for the A2DP profile
+*/
+#define A2D_TRACE_ERROR0(m)
+#define A2D_TRACE_ERROR1(m,p1)
+#define A2D_TRACE_ERROR2(m,p1,p2)
+#define A2D_TRACE_ERROR3(m,p1,p2,p3)
+#define A2D_TRACE_ERROR4(m,p1,p2,p3,p4)
+#define A2D_TRACE_ERROR5(m,p1,p2,p3,p4,p5)
+#define A2D_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6)
+
+#define A2D_TRACE_WARNING0(m)
+#define A2D_TRACE_WARNING1(m,p1)
+#define A2D_TRACE_WARNING2(m,p1,p2)
+#define A2D_TRACE_WARNING3(m,p1,p2,p3)
+#define A2D_TRACE_WARNING4(m,p1,p2,p3,p4)
+#define A2D_TRACE_WARNING5(m,p1,p2,p3,p4,p5)
+#define A2D_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6)
+
+#define A2D_TRACE_EVENT0(m)
+#define A2D_TRACE_EVENT1(m,p1)
+#define A2D_TRACE_EVENT2(m,p1,p2)
+#define A2D_TRACE_EVENT3(m,p1,p2,p3)
+#define A2D_TRACE_EVENT4(m,p1,p2,p3,p4)
+#define A2D_TRACE_EVENT5(m,p1,p2,p3,p4,p5)
+#define A2D_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6)
+
+#define A2D_TRACE_DEBUG0(m)
+#define A2D_TRACE_DEBUG1(m,p1)
+#define A2D_TRACE_DEBUG2(m,p1,p2)
+#define A2D_TRACE_DEBUG3(m,p1,p2,p3)
+#define A2D_TRACE_DEBUG4(m,p1,p2,p3,p4)
+#define A2D_TRACE_DEBUG5(m,p1,p2,p3,p4,p5)
+#define A2D_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6)
+
+#define A2D_TRACE_API0(m)
+#define A2D_TRACE_API1(m,p1)
+#define A2D_TRACE_API2(m,p1,p2)
+#define A2D_TRACE_API3(m,p1,p2,p3)
+#define A2D_TRACE_API4(m,p1,p2,p3,p4)
+#define A2D_TRACE_API5(m,p1,p2,p3,p4,p5)
+#define A2D_TRACE_API6(m,p1,p2,p3,p4,p5,p6)
+
+/* Define tracing for the VDP profile
+*/
+#define VDP_TRACE_ERROR0(m)
+#define VDP_TRACE_ERROR1(m,p1)
+#define VDP_TRACE_ERROR2(m,p1,p2)
+#define VDP_TRACE_ERROR3(m,p1,p2,p3)
+#define VDP_TRACE_ERROR4(m,p1,p2,p3,p4)
+#define VDP_TRACE_ERROR5(m,p1,p2,p3,p4,p5)
+#define VDP_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6)
+
+#define VDP_TRACE_WARNING0(m)
+#define VDP_TRACE_WARNING1(m,p1)
+#define VDP_TRACE_WARNING2(m,p1,p2)
+#define VDP_TRACE_WARNING3(m,p1,p2,p3)
+#define VDP_TRACE_WARNING4(m,p1,p2,p3,p4)
+#define VDP_TRACE_WARNING5(m,p1,p2,p3,p4,p5)
+#define VDP_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6)
+
+#define VDP_TRACE_EVENT0(m)
+#define VDP_TRACE_EVENT1(m,p1)
+#define VDP_TRACE_EVENT2(m,p1,p2)
+#define VDP_TRACE_EVENT3(m,p1,p2,p3)
+#define VDP_TRACE_EVENT4(m,p1,p2,p3,p4)
+#define VDP_TRACE_EVENT5(m,p1,p2,p3,p4,p5)
+#define VDP_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6)
+
+#define VDP_TRACE_DEBUG0(m)
+#define VDP_TRACE_DEBUG1(m,p1)
+#define VDP_TRACE_DEBUG2(m,p1,p2)
+#define VDP_TRACE_DEBUG3(m,p1,p2,p3)
+#define VDP_TRACE_DEBUG4(m,p1,p2,p3,p4)
+#define VDP_TRACE_DEBUG5(m,p1,p2,p3,p4,p5)
+#define VDP_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6)
+
+#define VDP_TRACE_API0(m)
+#define VDP_TRACE_API1(m,p1)
+#define VDP_TRACE_API2(m,p1,p2)
+#define VDP_TRACE_API3(m,p1,p2,p3)
+#define VDP_TRACE_API4(m,p1,p2,p3,p4)
+#define VDP_TRACE_API5(m,p1,p2,p3,p4,p5)
+#define VDP_TRACE_API6(m,p1,p2,p3,p4,p5,p6)
+
+
+/* Define tracing for the LM unit
+*/
+#define LMP_TRACE_ERROR0(m)
+#define LMP_TRACE_ERROR1(m,p1)
+#define LMP_TRACE_ERROR2(m,p1,p2)
+#define LMP_TRACE_ERROR3(m,p1,p2,p3)
+#define LMP_TRACE_ERROR4(m,p1,p2,p3,p4)
+#define LMP_TRACE_ERROR5(m,p1,p2,p3,p4,p5)
+#define LMP_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6)
+
+#define LMP_TRACE_WARNING0(m)
+#define LMP_TRACE_WARNING1(m,p1)
+#define LMP_TRACE_WARNING2(m,p1,p2)
+#define LMP_TRACE_WARNING3(m,p1,p2,p3)
+#define LMP_TRACE_WARNING4(m,p1,p2,p3,p4)
+#define LMP_TRACE_WARNING5(m,p1,p2,p3,p4,p5)
+#define LMP_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6)
+
+#define LMP_TRACE_EVENT0(m)
+#define LMP_TRACE_EVENT1(m,p1)
+#define LMP_TRACE_EVENT2(m,p1,p2)
+#define LMP_TRACE_EVENT3(m,p1,p2,p3)
+#define LMP_TRACE_EVENT4(m,p1,p2,p3,p4)
+#define LMP_TRACE_EVENT5(m,p1,p2,p3,p4,p5)
+#define LMP_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6)
+
+#define LMP_TRACE_DEBUG0(m)
+#define LMP_TRACE_DEBUG1(m,p1)
+#define LMP_TRACE_DEBUG2(m,p1,p2)
+#define LMP_TRACE_DEBUG3(m,p1,p2,p3)
+#define LMP_TRACE_DEBUG4(m,p1,p2,p3,p4)
+#define LMP_TRACE_DEBUG5(m,p1,p2,p3,p4,p5)
+#define LMP_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6)
+
+/* Define tracing for the LC unit
+*/
+#define LC_TRACE_ERROR0(m)
+#define LC_TRACE_ERROR1(m,p1)
+#define LC_TRACE_ERROR2(m,p1,p2)
+#define LC_TRACE_ERROR3(m,p1,p2,p3)
+#define LC_TRACE_ERROR4(m,p1,p2,p3,p4)
+#define LC_TRACE_ERROR5(m,p1,p2,p3,p4,p5)
+#define LC_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6)
+
+#define LC_TRACE_WARNING0(m)
+#define LC_TRACE_WARNING1(m,p1)
+#define LC_TRACE_WARNING2(m,p1,p2)
+#define LC_TRACE_WARNING3(m,p1,p2,p3)
+#define LC_TRACE_WARNING4(m,p1,p2,p3,p4)
+#define LC_TRACE_WARNING5(m,p1,p2,p3,p4,p5)
+#define LC_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6)
+
+#define LC_TRACE_EVENT0(m)
+#define LC_TRACE_EVENT1(m,p1)
+#define LC_TRACE_EVENT2(m,p1,p2)
+#define LC_TRACE_EVENT3(m,p1,p2,p3)
+#define LC_TRACE_EVENT4(m,p1,p2,p3,p4)
+#define LC_TRACE_EVENT5(m,p1,p2,p3,p4,p5)
+#define LC_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6)
+
+#define LC_TRACE_DEBUG0(m)
+#define LC_TRACE_DEBUG1(m,p1)
+#define LC_TRACE_DEBUG2(m,p1,p2)
+#define LC_TRACE_DEBUG3(m,p1,p2,p3)
+#define LC_TRACE_DEBUG4(m,p1,p2,p3,p4)
+#define LC_TRACE_DEBUG5(m,p1,p2,p3,p4,p5)
+#define LC_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6)
+
+#define SDA_TRACE_ERROR0(m)
+#define SDA_TRACE_ERROR1(m,p1)
+#define SDA_TRACE_ERROR2(m,p1,p2)
+#define SDA_TRACE_ERROR3(m,p1,p2,p3)
+#define SDA_TRACE_ERROR4(m,p1,p2,p3,p4)
+#define SDA_TRACE_ERROR5(m,p1,p2,p3,p4,p5)
+#define SDA_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6)
+
+#define SDA_TRACE_WARNING0(m)
+#define SDA_TRACE_WARNING1(m,p1)
+#define SDA_TRACE_WARNING2(m,p1,p2)
+#define SDA_TRACE_WARNING3(m,p1,p2,p3)
+#define SDA_TRACE_WARNING4(m,p1,p2,p3,p4)
+#define SDA_TRACE_WARNING5(m,p1,p2,p3,p4,p5)
+#define SDA_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6)
+
+#define SDA_TRACE_EVENT0(m)
+#define SDA_TRACE_EVENT1(m,p1)
+#define SDA_TRACE_EVENT2(m,p1,p2)
+#define SDA_TRACE_EVENT3(m,p1,p2,p3)
+#define SDA_TRACE_EVENT4(m,p1,p2,p3,p4)
+#define SDA_TRACE_EVENT5(m,p1,p2,p3,p4,p5)
+#define SDA_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6)
+
+#define SDA_TRACE_DEBUG0(m)
+#define SDA_TRACE_DEBUG1(m,p1)
+#define SDA_TRACE_DEBUG2(m,p1,p2)
+#define SDA_TRACE_DEBUG3(m,p1,p2,p3)
+#define SDA_TRACE_DEBUG4(m,p1,p2,p3,p4)
+#define SDA_TRACE_DEBUG5(m,p1,p2,p3,p4,p5)
+#define SDA_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6)
+
+/* AVDTP
+*/
+#define AVDT_TRACE_ERROR0(m)
+#define AVDT_TRACE_ERROR1(m,p1)
+#define AVDT_TRACE_ERROR2(m,p1,p2)
+#define AVDT_TRACE_ERROR3(m,p1,p2,p3)
+#define AVDT_TRACE_ERROR4(m,p1,p2,p3,p4)
+#define AVDT_TRACE_ERROR5(m,p1,p2,p3,p4,p5)
+#define AVDT_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6)
+
+#define AVDT_TRACE_WARNING0(m)
+#define AVDT_TRACE_WARNING1(m,p1)
+#define AVDT_TRACE_WARNING2(m,p1,p2)
+#define AVDT_TRACE_WARNING3(m,p1,p2,p3)
+#define AVDT_TRACE_WARNING4(m,p1,p2,p3,p4)
+#define AVDT_TRACE_WARNING5(m,p1,p2,p3,p4,p5)
+#define AVDT_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6)
+
+#define AVDT_TRACE_EVENT0(m)
+#define AVDT_TRACE_EVENT1(m,p1)
+#define AVDT_TRACE_EVENT2(m,p1,p2)
+#define AVDT_TRACE_EVENT3(m,p1,p2,p3)
+#define AVDT_TRACE_EVENT4(m,p1,p2,p3,p4)
+#define AVDT_TRACE_EVENT5(m,p1,p2,p3,p4,p5)
+#define AVDT_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6)
+
+#define AVDT_TRACE_DEBUG0(m)
+#define AVDT_TRACE_DEBUG1(m,p1)
+#define AVDT_TRACE_DEBUG2(m,p1,p2)
+#define AVDT_TRACE_DEBUG3(m,p1,p2,p3)
+#define AVDT_TRACE_DEBUG4(m,p1,p2,p3,p4)
+#define AVDT_TRACE_DEBUG5(m,p1,p2,p3,p4,p5)
+#define AVDT_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6)
+
+#define AVDT_TRACE_API0(m)
+#define AVDT_TRACE_API1(m,p1)
+#define AVDT_TRACE_API2(m,p1,p2)
+#define AVDT_TRACE_API3(m,p1,p2,p3)
+#define AVDT_TRACE_API4(m,p1,p2,p3,p4)
+#define AVDT_TRACE_API5(m,p1,p2,p3,p4,p5)
+#define AVDT_TRACE_API6(m,p1,p2,p3,p4,p5,p6)
+
+/* Define tracing for the AVCTP protocol
+*/
+#define AVCT_TRACE_ERROR0(m)
+#define AVCT_TRACE_ERROR1(m,p1)
+#define AVCT_TRACE_ERROR2(m,p1,p2)
+#define AVCT_TRACE_ERROR3(m,p1,p2,p3)
+#define AVCT_TRACE_ERROR4(m,p1,p2,p3,p4)
+#define AVCT_TRACE_ERROR5(m,p1,p2,p3,p4,p5)
+#define AVCT_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6)
+
+#define AVCT_TRACE_WARNING0(m)
+#define AVCT_TRACE_WARNING1(m,p1)
+#define AVCT_TRACE_WARNING2(m,p1,p2)
+#define AVCT_TRACE_WARNING3(m,p1,p2,p3)
+#define AVCT_TRACE_WARNING4(m,p1,p2,p3,p4)
+#define AVCT_TRACE_WARNING5(m,p1,p2,p3,p4,p5)
+#define AVCT_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6)
+
+#define AVCT_TRACE_EVENT0(m)
+#define AVCT_TRACE_EVENT1(m,p1)
+#define AVCT_TRACE_EVENT2(m,p1,p2)
+#define AVCT_TRACE_EVENT3(m,p1,p2,p3)
+#define AVCT_TRACE_EVENT4(m,p1,p2,p3,p4)
+#define AVCT_TRACE_EVENT5(m,p1,p2,p3,p4,p5)
+#define AVCT_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6)
+
+#define AVCT_TRACE_DEBUG0(m)
+#define AVCT_TRACE_DEBUG1(m,p1)
+#define AVCT_TRACE_DEBUG2(m,p1,p2)
+#define AVCT_TRACE_DEBUG3(m,p1,p2,p3)
+#define AVCT_TRACE_DEBUG4(m,p1,p2,p3,p4)
+#define AVCT_TRACE_DEBUG5(m,p1,p2,p3,p4,p5)
+#define AVCT_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6)
+
+#define AVCT_TRACE_API0(m)
+#define AVCT_TRACE_API1(m,p1)
+#define AVCT_TRACE_API2(m,p1,p2)
+#define AVCT_TRACE_API3(m,p1,p2,p3)
+#define AVCT_TRACE_API4(m,p1,p2,p3,p4)
+#define AVCT_TRACE_API5(m,p1,p2,p3,p4,p5)
+#define AVCT_TRACE_API6(m,p1,p2,p3,p4,p5,p6)
+
+
+/* Define tracing for the AVRCP profile
+*/
+#define AVRC_TRACE_ERROR0(m)
+#define AVRC_TRACE_ERROR1(m,p1)
+#define AVRC_TRACE_ERROR2(m,p1,p2)
+#define AVRC_TRACE_ERROR3(m,p1,p2,p3)
+#define AVRC_TRACE_ERROR4(m,p1,p2,p3,p4)
+#define AVRC_TRACE_ERROR5(m,p1,p2,p3,p4,p5)
+#define AVRC_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6)
+
+#define AVRC_TRACE_WARNING0(m)
+#define AVRC_TRACE_WARNING1(m,p1)
+#define AVRC_TRACE_WARNING2(m,p1,p2)
+#define AVRC_TRACE_WARNING3(m,p1,p2,p3)
+#define AVRC_TRACE_WARNING4(m,p1,p2,p3,p4)
+#define AVRC_TRACE_WARNING5(m,p1,p2,p3,p4,p5)
+#define AVRC_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6)
+
+#define AVRC_TRACE_EVENT0(m)
+#define AVRC_TRACE_EVENT1(m,p1)
+#define AVRC_TRACE_EVENT2(m,p1,p2)
+#define AVRC_TRACE_EVENT3(m,p1,p2,p3)
+#define AVRC_TRACE_EVENT4(m,p1,p2,p3,p4)
+#define AVRC_TRACE_EVENT5(m,p1,p2,p3,p4,p5)
+#define AVRC_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6)
+
+#define AVRC_TRACE_DEBUG0(m)
+#define AVRC_TRACE_DEBUG1(m,p1)
+#define AVRC_TRACE_DEBUG2(m,p1,p2)
+#define AVRC_TRACE_DEBUG3(m,p1,p2,p3)
+#define AVRC_TRACE_DEBUG4(m,p1,p2,p3,p4)
+#define AVRC_TRACE_DEBUG5(m,p1,p2,p3,p4,p5)
+#define AVRC_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6)
+
+#define AVRC_TRACE_API0(m)
+#define AVRC_TRACE_API1(m,p1)
+#define AVRC_TRACE_API2(m,p1,p2)
+#define AVRC_TRACE_API3(m,p1,p2,p3)
+#define AVRC_TRACE_API4(m,p1,p2,p3,p4)
+#define AVRC_TRACE_API5(m,p1,p2,p3,p4,p5)
+#define AVRC_TRACE_API6(m,p1,p2,p3,p4,p5,p6)
+
+/* MCAP
+*/
+#define MCA_TRACE_ERROR0(m)
+#define MCA_TRACE_ERROR1(m,p1)
+#define MCA_TRACE_ERROR2(m,p1,p2)
+#define MCA_TRACE_ERROR3(m,p1,p2,p3)
+#define MCA_TRACE_ERROR4(m,p1,p2,p3,p4)
+#define MCA_TRACE_ERROR5(m,p1,p2,p3,p4,p5)
+#define MCA_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6)
+
+#define MCA_TRACE_WARNING0(m)
+#define MCA_TRACE_WARNING1(m,p1)
+#define MCA_TRACE_WARNING2(m,p1,p2)
+#define MCA_TRACE_WARNING3(m,p1,p2,p3)
+#define MCA_TRACE_WARNING4(m,p1,p2,p3,p4)
+#define MCA_TRACE_WARNING5(m,p1,p2,p3,p4,p5)
+#define MCA_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6)
+
+#define MCA_TRACE_EVENT0(m)
+#define MCA_TRACE_EVENT1(m,p1)
+#define MCA_TRACE_EVENT2(m,p1,p2)
+#define MCA_TRACE_EVENT3(m,p1,p2,p3)
+#define MCA_TRACE_EVENT4(m,p1,p2,p3,p4)
+#define MCA_TRACE_EVENT5(m,p1,p2,p3,p4,p5)
+#define MCA_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6)
+
+#define MCA_TRACE_DEBUG0(m)
+#define MCA_TRACE_DEBUG1(m,p1)
+#define MCA_TRACE_DEBUG2(m,p1,p2)
+#define MCA_TRACE_DEBUG3(m,p1,p2,p3)
+#define MCA_TRACE_DEBUG4(m,p1,p2,p3,p4)
+#define MCA_TRACE_DEBUG5(m,p1,p2,p3,p4,p5)
+#define MCA_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6)
+
+#define MCA_TRACE_API0(m)
+#define MCA_TRACE_API1(m,p1)
+#define MCA_TRACE_API2(m,p1,p2)
+#define MCA_TRACE_API3(m,p1,p2,p3)
+#define MCA_TRACE_API4(m,p1,p2,p3,p4)
+#define MCA_TRACE_API5(m,p1,p2,p3,p4,p5)
+#define MCA_TRACE_API6(m,p1,p2,p3,p4,p5,p6)
+
+/* Define tracing for the AMP unit
+*/
+#define AMP_TRACE_ERROR0(m)
+#define AMP_TRACE_ERROR1(m,p1)
+#define AMP_TRACE_ERROR2(m,p1,p2)
+#define AMP_TRACE_ERROR3(m,p1,p2,p3)
+#define AMP_TRACE_ERROR4(m,p1,p2,p3,p4)
+#define AMP_TRACE_ERROR5(m,p1,p2,p3,p4,p5)
+#define AMP_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6)
+
+#define AMP_TRACE_WARNING0(m)
+#define AMP_TRACE_WARNING1(m,p1)
+#define AMP_TRACE_WARNING2(m,p1,p2)
+#define AMP_TRACE_WARNING3(m,p1,p2,p3)
+#define AMP_TRACE_WARNING4(m,p1,p2,p3,p4)
+#define AMP_TRACE_WARNING5(m,p1,p2,p3,p4,p5)
+#define AMP_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6)
+
+#define AMP_TRACE_API0(m)
+#define AMP_TRACE_API1(m,p1)
+#define AMP_TRACE_API2(m,p1,p2)
+#define AMP_TRACE_API3(m,p1,p2,p3)
+#define AMP_TRACE_API4(m,p1,p2,p3,p4)
+#define AMP_TRACE_API5(m,p1,p2,p3,p4,p5)
+#define AMP_TRACE_API6(m,p1,p2,p3,p4,p5,p6)
+
+#define AMP_TRACE_EVENT0(m)
+#define AMP_TRACE_EVENT1(m,p1)
+#define AMP_TRACE_EVENT2(m,p1,p2)
+#define AMP_TRACE_EVENT3(m,p1,p2,p3)
+#define AMP_TRACE_EVENT4(m,p1,p2,p3,p4)
+#define AMP_TRACE_EVENT5(m,p1,p2,p3,p4,p5)
+#define AMP_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6)
+
+#define AMP_TRACE_DEBUG0(m)
+#define AMP_TRACE_DEBUG1(m,p1)
+#define AMP_TRACE_DEBUG2(m,p1,p2)
+#define AMP_TRACE_DEBUG3(m,p1,p2,p3)
+#define AMP_TRACE_DEBUG4(m,p1,p2,p3,p4)
+#define AMP_TRACE_DEBUG5(m,p1,p2,p3,p4,p5)
+#define AMP_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6)
+
+/* Define tracing for the GATT
+*/
+#define GATT_TRACE_ERROR0(m)
+#define GATT_TRACE_ERROR1(m,p1)
+#define GATT_TRACE_ERROR2(m,p1,p2)
+#define GATT_TRACE_ERROR3(m,p1,p2,p3)
+#define GATT_TRACE_ERROR4(m,p1,p2,p3,p4)
+#define GATT_TRACE_ERROR5(m,p1,p2,p3,p4,p5)
+#define GATT_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6)
+
+#define GATT_TRACE_WARNING0(m)
+#define GATT_TRACE_WARNING1(m,p1)
+#define GATT_TRACE_WARNING2(m,p1,p2)
+#define GATT_TRACE_WARNING3(m,p1,p2,p3)
+#define GATT_TRACE_WARNING4(m,p1,p2,p3,p4)
+#define GATT_TRACE_WARNING5(m,p1,p2,p3,p4,p5)
+#define GATT_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6)
+
+#define GATT_TRACE_API0(m)
+#define GATT_TRACE_API1(m,p1)
+#define GATT_TRACE_API2(m,p1,p2)
+#define GATT_TRACE_API3(m,p1,p2,p3)
+#define GATT_TRACE_API4(m,p1,p2,p3,p4)
+#define GATT_TRACE_API5(m,p1,p2,p3,p4,p5)
+#define GATT_TRACE_API6(m,p1,p2,p3,p4,p5,p6)
+
+#define GATT_TRACE_EVENT0(m)
+#define GATT_TRACE_EVENT1(m,p1)
+#define GATT_TRACE_EVENT2(m,p1,p2)
+#define GATT_TRACE_EVENT3(m,p1,p2,p3)
+#define GATT_TRACE_EVENT4(m,p1,p2,p3,p4)
+#define GATT_TRACE_EVENT5(m,p1,p2,p3,p4,p5)
+#define GATT_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6)
+
+#define GATT_TRACE_DEBUG0(m)
+#define GATT_TRACE_DEBUG1(m,p1)
+#define GATT_TRACE_DEBUG2(m,p1,p2)
+#define GATT_TRACE_DEBUG3(m,p1,p2,p3)
+#define GATT_TRACE_DEBUG4(m,p1,p2,p3,p4)
+#define GATT_TRACE_DEBUG5(m,p1,p2,p3,p4,p5)
+#define GATT_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6)
+
+/* Define tracing for the SMP unit
+*/
+#define SMP_TRACE_ERROR0(m)
+#define SMP_TRACE_ERROR1(m,p1)
+#define SMP_TRACE_ERROR2(m,p1,p2)
+#define SMP_TRACE_ERROR3(m,p1,p2,p3)
+#define SMP_TRACE_ERROR4(m,p1,p2,p3,p4)
+#define SMP_TRACE_ERROR5(m,p1,p2,p3,p4,p5)
+#define SMP_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6)
+
+#define SMP_TRACE_WARNING0(m)
+#define SMP_TRACE_WARNING1(m,p1)
+#define SMP_TRACE_WARNING2(m,p1,p2)
+#define SMP_TRACE_WARNING3(m,p1,p2,p3)
+#define SMP_TRACE_WARNING4(m,p1,p2,p3,p4)
+#define SMP_TRACE_WARNING5(m,p1,p2,p3,p4,p5)
+#define SMP_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6)
+
+#define SMP_TRACE_API0(m)
+#define SMP_TRACE_API1(m,p1)
+#define SMP_TRACE_API2(m,p1,p2)
+#define SMP_TRACE_API3(m,p1,p2,p3)
+#define SMP_TRACE_API4(m,p1,p2,p3,p4)
+#define SMP_TRACE_API5(m,p1,p2,p3,p4,p5)
+#define SMP_TRACE_API6(m,p1,p2,p3,p4,p5,p6)
+
+#define SMP_TRACE_EVENT0(m)
+#define SMP_TRACE_EVENT1(m,p1)
+#define SMP_TRACE_EVENT2(m,p1,p2)
+#define SMP_TRACE_EVENT3(m,p1,p2,p3)
+#define SMP_TRACE_EVENT4(m,p1,p2,p3,p4)
+#define SMP_TRACE_EVENT5(m,p1,p2,p3,p4,p5)
+#define SMP_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6)
+
+#define SMP_TRACE_DEBUG0(m)
+#define SMP_TRACE_DEBUG1(m,p1)
+#define SMP_TRACE_DEBUG2(m,p1,p2)
+#define SMP_TRACE_DEBUG3(m,p1,p2,p3)
+#define SMP_TRACE_DEBUG4(m,p1,p2,p3,p4)
+#define SMP_TRACE_DEBUG5(m,p1,p2,p3,p4,p5)
+#define SMP_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6)
+
+#endif
+
+#if (BT_TRACE_BTIF == TRUE)
+
+extern UINT8 btif_trace_level;
+
+/* define traces for application */
+#define BTIF_TRACE_ERROR0(m) {if (btif_trace_level >= BT_TRACE_LEVEL_ERROR) LogMsg_0(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_ERROR, (m));}
+#define BTIF_TRACE_ERROR1(m,p1) {if (btif_trace_level >= BT_TRACE_LEVEL_ERROR) LogMsg_1(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_ERROR, \
+ (m), (UINT32)(p1));}
+#define BTIF_TRACE_ERROR2(m,p1,p2) {if (btif_trace_level >= BT_TRACE_LEVEL_ERROR) LogMsg_2(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_ERROR, \
+ (m), (UINT32)(p1), (UINT32)(p2));}
+#define BTIF_TRACE_ERROR3(m,p1,p2,p3) {if (btif_trace_level >= BT_TRACE_LEVEL_ERROR) LogMsg_3(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_ERROR, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3));}
+#define BTIF_TRACE_ERROR4(m,p1,p2,p3,p4) {if (btif_trace_level >= BT_TRACE_LEVEL_ERROR) LogMsg_4(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_ERROR, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4));}
+#define BTIF_TRACE_ERROR5(m,p1,p2,p3,p4,p5) {if (btif_trace_level >= BT_TRACE_LEVEL_ERROR) LogMsg_5(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_ERROR, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4), (UINT32)(p5));}
+#define BTIF_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6) {if (btif_trace_level >= BT_TRACE_LEVEL_ERROR) LogMsg_6(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_ERROR, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4), (UINT32)(p5), (UINT32)(p6));}
+
+#define BTIF_TRACE_WARNING0(m) {if (btif_trace_level >= BT_TRACE_LEVEL_WARNING) LogMsg_0(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_WARNING, (m));}
+#define BTIF_TRACE_WARNING1(m,p1) {if (btif_trace_level >= BT_TRACE_LEVEL_WARNING) LogMsg_1(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_WARNING, \
+ (m), (UINT32)(p1));}
+#define BTIF_TRACE_WARNING2(m,p1,p2) {if (btif_trace_level >= BT_TRACE_LEVEL_WARNING) LogMsg_2(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_WARNING, \
+ (m), (UINT32)(p1), (UINT32)(p2));}
+#define BTIF_TRACE_WARNING3(m,p1,p2,p3) {if (btif_trace_level >= BT_TRACE_LEVEL_WARNING) LogMsg_3(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_WARNING, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3));}
+#define BTIF_TRACE_WARNING4(m,p1,p2,p3,p4) {if (btif_trace_level >= BT_TRACE_LEVEL_WARNING) LogMsg_4(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_WARNING, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4));}
+#define BTIF_TRACE_WARNING5(m,p1,p2,p3,p4,p5) {if (btif_trace_level >= BT_TRACE_LEVEL_WARNING) LogMsg_5(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_WARNING, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4), (UINT32)(p5));}
+#define BTIF_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6) {if (btif_trace_level >= BT_TRACE_LEVEL_WARNING) LogMsg_6(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_WARNING, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4), (UINT32)(p5), (UINT32)(p6));}
+
+#define BTIF_TRACE_API0(m) {if (btif_trace_level >= BT_TRACE_LEVEL_API) LogMsg_0(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_API, (m));}
+#define BTIF_TRACE_API1(m,p1) {if (btif_trace_level >= BT_TRACE_LEVEL_API) LogMsg_1(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_API, \
+ (m), (UINT32)(p1));}
+#define BTIF_TRACE_API2(m,p1,p2) {if (btif_trace_level >= BT_TRACE_LEVEL_API) LogMsg_2(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_API, \
+ (m), (UINT32)(p1), (UINT32)(p2));}
+#define BTIF_TRACE_API3(m,p1,p2,p3) {if (btif_trace_level >= BT_TRACE_LEVEL_API) LogMsg_3(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_API, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3));}
+#define BTIF_TRACE_API4(m,p1,p2,p3,p4) {if (btif_trace_level >= BT_TRACE_LEVEL_API) LogMsg_4(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_API, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4));}
+#define BTIF_TRACE_API5(m,p1,p2,p3,p4,p5) {if (btif_trace_level >= BT_TRACE_LEVEL_API) LogMsg_5(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_API, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4), (UINT32)(p5));}
+#define BTIF_TRACE_API6(m,p1,p2,p3,p4,p5,p6) {if (btif_trace_level >= BT_TRACE_LEVEL_API) LogMsg_6(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_API, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4), (UINT32)(p5), (UINT32)(p6));}
+
+#define BTIF_TRACE_EVENT0(m) {if (btif_trace_level >= BT_TRACE_LEVEL_EVENT) LogMsg_0(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_EVENT, (m));}
+#define BTIF_TRACE_EVENT1(m,p1) {if (btif_trace_level >= BT_TRACE_LEVEL_EVENT) LogMsg_1(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_EVENT, \
+ (m), (UINT32)(p1));}
+#define BTIF_TRACE_EVENT2(m,p1,p2) {if (btif_trace_level >= BT_TRACE_LEVEL_EVENT) LogMsg_2(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_EVENT, \
+ (m), (UINT32)(p1), (UINT32)(p2));}
+#define BTIF_TRACE_EVENT3(m,p1,p2,p3) {if (btif_trace_level >= BT_TRACE_LEVEL_EVENT) LogMsg_3(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_EVENT, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3));}
+#define BTIF_TRACE_EVENT4(m,p1,p2,p3,p4) {if (btif_trace_level >= BT_TRACE_LEVEL_EVENT) LogMsg_4(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_EVENT, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4));}
+#define BTIF_TRACE_EVENT5(m,p1,p2,p3,p4,p5) {if (btif_trace_level >= BT_TRACE_LEVEL_EVENT) LogMsg_5(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_EVENT, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4), (UINT32)(p5));}
+#define BTIF_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6) {if (btif_trace_level >= BT_TRACE_LEVEL_EVENT) LogMsg_6(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_EVENT, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4), (UINT32)(p5), (UINT32)(p6));}
+
+#define BTIF_TRACE_DEBUG0(m) {if (btif_trace_level >= BT_TRACE_LEVEL_DEBUG) LogMsg_0(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_DEBUG, (m));}
+#define BTIF_TRACE_DEBUG1(m,p1) {if (btif_trace_level >= BT_TRACE_LEVEL_DEBUG) LogMsg_1(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_DEBUG, \
+ (m), (UINT32)(p1));}
+#define BTIF_TRACE_DEBUG2(m,p1,p2) {if (btif_trace_level >= BT_TRACE_LEVEL_DEBUG) LogMsg_2(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_DEBUG, \
+ (m), (UINT32)(p1), (UINT32)(p2));}
+#define BTIF_TRACE_DEBUG3(m,p1,p2,p3) {if (btif_trace_level >= BT_TRACE_LEVEL_DEBUG) LogMsg_3(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_DEBUG, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3));}
+#define BTIF_TRACE_DEBUG4(m,p1,p2,p3,p4) {if (btif_trace_level >= BT_TRACE_LEVEL_DEBUG) LogMsg_4(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_DEBUG, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4));}
+#define BTIF_TRACE_DEBUG5(m,p1,p2,p3,p4,p5) {if (btif_trace_level >= BT_TRACE_LEVEL_DEBUG) LogMsg_5(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_DEBUG, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4), (UINT32)(p5));}
+#define BTIF_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) {if (btif_trace_level >= BT_TRACE_LEVEL_DEBUG) LogMsg_6(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_DEBUG, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4), (UINT32)(p5), (UINT32)(p6));}
+
+#define BTIF_TRACE_VERBOSE0(m) {if (btif_trace_level >= BT_TRACE_LEVEL_VERBOSE) LogMsg_0(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_DEBUG, (m));}
+#define BTIF_TRACE_VERBOSE1(m,p1) {if (btif_trace_level >= BT_TRACE_LEVEL_VERBOSE) LogMsg_1(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_DEBUG, \
+ (m), (UINT32)(p1));}
+#define BTIF_TRACE_VERBOSE2(m,p1,p2) {if (btif_trace_level >= BT_TRACE_LEVEL_VERBOSE) LogMsg_2(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_DEBUG, \
+ (m), (UINT32)(p1), (UINT32)(p2));}
+#define BTIF_TRACE_VERBOSE3(m,p1,p2,p3) {if (btif_trace_level >= BT_TRACE_LEVEL_VERBOSE) LogMsg_3(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_DEBUG, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3));}
+#define BTIF_TRACE_VERBOSE4(m,p1,p2,p3,p4) {if (btif_trace_level >= BT_TRACE_LEVEL_VERBOSE) LogMsg_4(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_DEBUG, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4));}
+#define BTIF_TRACE_VERBOSE5(m,p1,p2,p3,p4,p5) {if (btif_trace_level >= BT_TRACE_LEVEL_VERBOSE) LogMsg_5(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_DEBUG, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4), (UINT32)(p5));}
+#define BTIF_TRACE_VERBOSE6(m,p1,p2,p3,p4,p5,p6) {if (btif_trace_level >= BT_TRACE_LEVEL_VERBOSE) LogMsg_6(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_DEBUG, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4), (UINT32)(p5), (UINT32)(p6));}
+
+#else
+/* define traces for Application */
+
+#define BTIF_TRACE_ERROR0(m)
+#define BTIF_TRACE_ERROR1(m,p1)
+#define BTIF_TRACE_ERROR2(m,p1,p2)
+#define BTIF_TRACE_ERROR3(m,p1,p2,p3)
+#define BTIF_TRACE_ERROR4(m,p1,p2,p3,p4)
+#define BTIF_TRACE_ERROR5(m,p1,p2,p3,p4,p5)
+#define BTIF_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6)
+
+#define BTIF_TRACE_WARNING0(m)
+#define BTIF_TRACE_WARNING1(m,p1)
+#define BTIF_TRACE_WARNING2(m,p1,p2)
+#define BTIF_TRACE_WARNING3(m,p1,p2,p3)
+#define BTIF_TRACE_WARNING4(m,p1,p2,p3,p4)
+#define BTIF_TRACE_WARNING5(m,p1,p2,p3,p4,p5)
+#define BTIF_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6)
+
+#define BTIF_TRACE_API0(m)
+#define BTIF_TRACE_API1(m,p1)
+#define BTIF_TRACE_API2(m,p1,p2)
+#define BTIF_TRACE_API3(m,p1,p2,p3)
+#define BTIF_TRACE_API4(m,p1,p2,p3,p4)
+#define BTIF_TRACE_API5(m,p1,p2,p3,p4,p5)
+#define BTIF_TRACE_API6(m,p1,p2,p3,p4,p5,p6)
+
+#define BTIF_TRACE_EVENT0(m)
+#define BTIF_TRACE_EVENT1(m,p1)
+#define BTIF_TRACE_EVENT2(m,p1,p2)
+#define BTIF_TRACE_EVENT3(m,p1,p2,p3)
+#define BTIF_TRACE_EVENT4(m,p1,p2,p3,p4)
+#define BTIF_TRACE_EVENT5(m,p1,p2,p3,p4,p5)
+#define BTIF_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6)
+
+#define BTIF_TRACE_DEBUG0(m)
+#define BTIF_TRACE_DEBUG1(m,p1)
+#define BTIF_TRACE_DEBUG2(m,p1,p2)
+#define BTIF_TRACE_DEBUG3(m,p1,p2,p3)
+#define BTIF_TRACE_DEBUG4(m,p1,p2,p3,p4)
+#define BTIF_TRACE_DEBUG5(m,p1,p2,p3,p4,p5)
+#define BTIF_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6)
+
+
+#define BTIF_TRACE_VERBOSE0(m)
+#define BTIF_TRACE_VERBOSE1(m,p1)
+#define BTIF_TRACE_VERBOSE2(m,p1,p2)
+#define BTIF_TRACE_VERBOSE3(m,p1,p2,p3)
+#define BTIF_TRACE_VERBOSE4(m,p1,p2,p3,p4)
+#define BTIF_TRACE_VERBOSE5(m,p1,p2,p3,p4,p5)
+#define BTIF_TRACE_VERBOSE6(m,p1,p2,p3,p4,p5,p6)
+
+#endif
+
+
+#if (BT_USE_TRACES == TRUE || BT_TRACE_APPL == TRUE)
+
+/* define traces for application */
+#define APPL_TRACE_ERROR0(m) {if (appl_trace_level >= BT_TRACE_LEVEL_ERROR) LogMsg_0(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_ERROR, (m));}
+#define APPL_TRACE_ERROR1(m,p1) {if (appl_trace_level >= BT_TRACE_LEVEL_ERROR) LogMsg_1(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_ERROR, \
+ (m), (UINT32)(p1));}
+#define APPL_TRACE_ERROR2(m,p1,p2) {if (appl_trace_level >= BT_TRACE_LEVEL_ERROR) LogMsg_2(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_ERROR, \
+ (m), (UINT32)(p1), (UINT32)(p2));}
+#define APPL_TRACE_ERROR3(m,p1,p2,p3) {if (appl_trace_level >= BT_TRACE_LEVEL_ERROR) LogMsg_3(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_ERROR, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3));}
+#define APPL_TRACE_ERROR4(m,p1,p2,p3,p4) {if (appl_trace_level >= BT_TRACE_LEVEL_ERROR) LogMsg_4(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_ERROR, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4));}
+#define APPL_TRACE_ERROR5(m,p1,p2,p3,p4,p5) {if (appl_trace_level >= BT_TRACE_LEVEL_ERROR) LogMsg_5(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_ERROR, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4), (UINT32)(p5));}
+#define APPL_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6) {if (appl_trace_level >= BT_TRACE_LEVEL_ERROR) LogMsg_6(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_ERROR, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4), (UINT32)(p5), (UINT32)(p6));}
+
+#define APPL_TRACE_WARNING0(m) {if (appl_trace_level >= BT_TRACE_LEVEL_WARNING) LogMsg_0(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_WARNING, (m));}
+#define APPL_TRACE_WARNING1(m,p1) {if (appl_trace_level >= BT_TRACE_LEVEL_WARNING) LogMsg_1(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_WARNING, \
+ (m), (UINT32)(p1));}
+#define APPL_TRACE_WARNING2(m,p1,p2) {if (appl_trace_level >= BT_TRACE_LEVEL_WARNING) LogMsg_2(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_WARNING, \
+ (m), (UINT32)(p1), (UINT32)(p2));}
+#define APPL_TRACE_WARNING3(m,p1,p2,p3) {if (appl_trace_level >= BT_TRACE_LEVEL_WARNING) LogMsg_3(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_WARNING, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3));}
+#define APPL_TRACE_WARNING4(m,p1,p2,p3,p4) {if (appl_trace_level >= BT_TRACE_LEVEL_WARNING) LogMsg_4(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_WARNING, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4));}
+#define APPL_TRACE_WARNING5(m,p1,p2,p3,p4,p5) {if (appl_trace_level >= BT_TRACE_LEVEL_WARNING) LogMsg_5(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_WARNING, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4), (UINT32)(p5));}
+#define APPL_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6) {if (appl_trace_level >= BT_TRACE_LEVEL_WARNING) LogMsg_6(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_WARNING, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4), (UINT32)(p5), (UINT32)(p6));}
+
+#define APPL_TRACE_API0(m) {if (appl_trace_level >= BT_TRACE_LEVEL_API) LogMsg_0(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_API, (m));}
+#define APPL_TRACE_API1(m,p1) {if (appl_trace_level >= BT_TRACE_LEVEL_API) LogMsg_1(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_API, \
+ (m), (UINT32)(p1));}
+#define APPL_TRACE_API2(m,p1,p2) {if (appl_trace_level >= BT_TRACE_LEVEL_API) LogMsg_2(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_API, \
+ (m), (UINT32)(p1), (UINT32)(p2));}
+#define APPL_TRACE_API3(m,p1,p2,p3) {if (appl_trace_level >= BT_TRACE_LEVEL_API) LogMsg_3(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_API, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3));}
+#define APPL_TRACE_API4(m,p1,p2,p3,p4) {if (appl_trace_level >= BT_TRACE_LEVEL_API) LogMsg_4(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_API, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4));}
+#define APPL_TRACE_API5(m,p1,p2,p3,p4,p5) {if (appl_trace_level >= BT_TRACE_LEVEL_API) LogMsg_5(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_API, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4), (UINT32)(p5));}
+#define APPL_TRACE_API6(m,p1,p2,p3,p4,p5,p6) {if (appl_trace_level >= BT_TRACE_LEVEL_API) LogMsg_6(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_API, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4), (UINT32)(p5), (UINT32)(p6));}
+
+#define APPL_TRACE_EVENT0(m) {if (appl_trace_level >= BT_TRACE_LEVEL_EVENT) LogMsg_0(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_EVENT, (m));}
+#define APPL_TRACE_EVENT1(m,p1) {if (appl_trace_level >= BT_TRACE_LEVEL_EVENT) LogMsg_1(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_EVENT, \
+ (m), (UINT32)(p1));}
+#define APPL_TRACE_EVENT2(m,p1,p2) {if (appl_trace_level >= BT_TRACE_LEVEL_EVENT) LogMsg_2(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_EVENT, \
+ (m), (UINT32)(p1), (UINT32)(p2));}
+#define APPL_TRACE_EVENT3(m,p1,p2,p3) {if (appl_trace_level >= BT_TRACE_LEVEL_EVENT) LogMsg_3(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_EVENT, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3));}
+#define APPL_TRACE_EVENT4(m,p1,p2,p3,p4) {if (appl_trace_level >= BT_TRACE_LEVEL_EVENT) LogMsg_4(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_EVENT, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4));}
+#define APPL_TRACE_EVENT5(m,p1,p2,p3,p4,p5) {if (appl_trace_level >= BT_TRACE_LEVEL_EVENT) LogMsg_5(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_EVENT, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4), (UINT32)(p5));}
+#define APPL_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6) {if (appl_trace_level >= BT_TRACE_LEVEL_EVENT) LogMsg_6(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_EVENT, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4), (UINT32)(p5), (UINT32)(p6));}
+
+#define APPL_TRACE_DEBUG0(m) {if (appl_trace_level >= BT_TRACE_LEVEL_DEBUG) LogMsg_0(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_DEBUG, (m));}
+#define APPL_TRACE_DEBUG1(m,p1) {if (appl_trace_level >= BT_TRACE_LEVEL_DEBUG) LogMsg_1(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_DEBUG, \
+ (m), (UINT32)(p1));}
+#define APPL_TRACE_DEBUG2(m,p1,p2) {if (appl_trace_level >= BT_TRACE_LEVEL_DEBUG) LogMsg_2(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_DEBUG, \
+ (m), (UINT32)(p1), (UINT32)(p2));}
+#define APPL_TRACE_DEBUG3(m,p1,p2,p3) {if (appl_trace_level >= BT_TRACE_LEVEL_DEBUG) LogMsg_3(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_DEBUG, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3));}
+#define APPL_TRACE_DEBUG4(m,p1,p2,p3,p4) {if (appl_trace_level >= BT_TRACE_LEVEL_DEBUG) LogMsg_4(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_DEBUG, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4));}
+#define APPL_TRACE_DEBUG5(m,p1,p2,p3,p4,p5) {if (appl_trace_level >= BT_TRACE_LEVEL_DEBUG) LogMsg_5(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_DEBUG, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4), (UINT32)(p5));}
+#define APPL_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) {if (appl_trace_level >= BT_TRACE_LEVEL_DEBUG) LogMsg_6(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_DEBUG, \
+ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4), (UINT32)(p5), (UINT32)(p6));}
+#else
+/* define traces for Application */
+
+#define APPL_TRACE_ERROR0(m)
+#define APPL_TRACE_ERROR1(m,p1)
+#define APPL_TRACE_ERROR2(m,p1,p2)
+#define APPL_TRACE_ERROR3(m,p1,p2,p3)
+#define APPL_TRACE_ERROR4(m,p1,p2,p3,p4)
+#define APPL_TRACE_ERROR5(m,p1,p2,p3,p4,p5)
+#define APPL_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6)
+
+#define APPL_TRACE_WARNING0(m)
+#define APPL_TRACE_WARNING1(m,p1)
+#define APPL_TRACE_WARNING2(m,p1,p2)
+#define APPL_TRACE_WARNING3(m,p1,p2,p3)
+#define APPL_TRACE_WARNING4(m,p1,p2,p3,p4)
+#define APPL_TRACE_WARNING5(m,p1,p2,p3,p4,p5)
+#define APPL_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6)
+
+#define APPL_TRACE_API0(m)
+#define APPL_TRACE_API1(m,p1)
+#define APPL_TRACE_API2(m,p1,p2)
+#define APPL_TRACE_API3(m,p1,p2,p3)
+#define APPL_TRACE_API4(m,p1,p2,p3,p4)
+#define APPL_TRACE_API5(m,p1,p2,p3,p4,p5)
+#define APPL_TRACE_API6(m,p1,p2,p3,p4,p5,p6)
+
+#define APPL_TRACE_EVENT0(m)
+#define APPL_TRACE_EVENT1(m,p1)
+#define APPL_TRACE_EVENT2(m,p1,p2)
+#define APPL_TRACE_EVENT3(m,p1,p2,p3)
+#define APPL_TRACE_EVENT4(m,p1,p2,p3,p4)
+#define APPL_TRACE_EVENT5(m,p1,p2,p3,p4,p5)
+#define APPL_TRACE_EVENT6(m,p1,p2,p3,p4,p5,p6)
+
+#define APPL_TRACE_DEBUG0(m)
+#define APPL_TRACE_DEBUG1(m,p1)
+#define APPL_TRACE_DEBUG2(m,p1,p2)
+#define APPL_TRACE_DEBUG3(m,p1,p2,p3)
+#define APPL_TRACE_DEBUG4(m,p1,p2,p3,p4)
+#define APPL_TRACE_DEBUG5(m,p1,p2,p3,p4,p5)
+#define APPL_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6)
+
+#endif
+
+#if ((MMI_INCLUDED == TRUE) && (!defined(HID_MSKB_INCLUDED) || (HID_MSKB_INCLUDED == FALSE)))
+/* UI for sample applications */
+#define SAP_TRACE_0(m) MMI_Echo(m)
+#define SAP_TRACE_1(m,p1) MMI_Echo(m,p1)
+#define SAP_TRACE_2(m,p1,p2) MMI_Echo(m,p1,p2)
+#define SAP_TRACE_3(m,p1,p2,p3) MMI_Echo(m,p1,p2,p3)
+#define SAP_TRACE_4(m,p1,p2,p3,p4) MMI_Echo(m,p1,p2,p3,p4)
+#define SAP_TRACE_5(m,p1,p2,p3,p4,p5) MMI_Echo(m,p1,p2,p3,p4,p5)
+#define SAP_TRACE_6(m,p1,p2,p3,p4,p5,p6) MMI_Echo(m,p1,p2,p3,p4,p5,p6)
+#else
+#define SAP_TRACE_0(m)
+#define SAP_TRACE_1(m,p1)
+#define SAP_TRACE_2(m,p1,p2)
+#define SAP_TRACE_3(m,p1,p2,p3)
+#define SAP_TRACE_4(m,p1,p2,p3,p4)
+#define SAP_TRACE_5(m,p1,p2,p3,p4,p5)
+#define SAP_TRACE_6(m,p1,p2,p3,p4,p5,p6)
+
+#endif /* End of MMI_INCLUDED */
+#if defined(DRV_DEBUG_MSG) && (DRV_DEBUG_MSG == TRUE)
+/* Driver Trace macros
+*/
+#define DRV_TRACE_WARNING0(m) APPL_TRACE_WARNING0(m)
+#define DRV_TRACE_WARNING1(m,p1) APPL_TRACE_WARNING1(m,p1)
+#define DRV_TRACE_WARNING2(m,p1,p2) APPL_TRACE_WARNING2(m,p1,p2)
+#define DRV_TRACE_WARNING3(m,p1,p2,p3) APPL_TRACE_WARNING3(m,p1,p2,p3)
+#define DRV_TRACE_WARNING4(m,p1,p2,p3,p4) APPL_TRACE_WARNING4(m,p1,p2,p3,p4)
+#define DRV_TRACE_WARNING5(m,p1,p2,p3,p4,p5) APPL_TRACE_WARNING5(m,p1,p2,p3,p4,p5)
+#define DRV_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6) APPL_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6)
+#else
+/* Driver Trace macros
+*/
+#define DRV_TRACE_WARNING0(m)
+#define DRV_TRACE_WARNING1(m,p1)
+#define DRV_TRACE_WARNING2(m,p1,p2)
+#define DRV_TRACE_WARNING3(m,p1,p2,p3)
+#define DRV_TRACE_WARNING4(m,p1,p2,p3,p4)
+#define DRV_TRACE_WARNING5(m,p1,p2,p3,p4,p5)
+#define DRV_TRACE_WARNING6(m,p1,p2,p3,p4,p5,p6)
+#endif
+
+#define DRV_TRACE_ERROR0(m) APPL_TRACE_ERROR0(m)
+#define DRV_TRACE_ERROR1(m,p1) APPL_TRACE_ERROR1(m,p1)
+#define DRV_TRACE_ERROR2(m,p1,p2) APPL_TRACE_ERROR2(m,p1,p2)
+#define DRV_TRACE_ERROR3(m,p1,p2,p3) APPL_TRACE_ERROR3(m,p1,p2,p3)
+#define DRV_TRACE_ERROR4(m,p1,p2,p3,p4) APPL_TRACE_ERROR4(m,p1,p2,p3,p4)
+#define DRV_TRACE_ERROR5(m,p1,p2,p3,p4,p5) APPL_TRACE_ERROR5(m,p1,p2,p3,p4,p5)
+#define DRV_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6) APPL_TRACE_ERROR6(m,p1,p2,p3,p4,p5,p6)
+
+/* Driver Trace macros
+*/
+#define DRV_TRACE_DEBUG0(m) APPL_TRACE_DEBUG0(m)
+#define DRV_TRACE_DEBUG1(m,p1) APPL_TRACE_DEBUG1(m,p1)
+#define DRV_TRACE_DEBUG2(m,p1,p2) APPL_TRACE_DEBUG2(m,p1,p2)
+#define DRV_TRACE_DEBUG3(m,p1,p2,p3) APPL_TRACE_DEBUG3(m,p1,p2,p3)
+#define DRV_TRACE_DEBUG4(m,p1,p2,p3,p4) APPL_TRACE_DEBUG4(m,p1,p2,p3,p4)
+#define DRV_TRACE_DEBUG5(m,p1,p2,p3,p4,p5) APPL_TRACE_DEBUG5(m,p1,p2,p3,p4,p5)
+#define DRV_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) APPL_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6)
+
+
+#endif /* BT_TRACE_H */
+
+
diff --git a/include/bte.h b/include/bte.h
new file mode 100644
index 0000000..afc6386
--- /dev/null
+++ b/include/bte.h
@@ -0,0 +1,106 @@
+/*****************************************************************************
+**
+** Name: bte.h
+**
+** Description: this file contains constants and definitions for the bte project
+**
+**
+** Copyright (c) 2001-2004, WIDCOMM Inc., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+#ifndef BTE_H
+#define BTE_H
+
+#include <semaphore.h>
+#include <signal.h>
+#include <pthread.h>
+#include "bt_target.h"
+
+/* by default on shutdown, baudrate is reset 115kbits. this should NOT be need for platforms
+ * that kill BTE driver and remove/reset BT chip
+ */
+#ifndef BTE_RESET_BAUD_ON_BT_DISABLE
+#define BTE_RESET_BAUD_ON_BT_DISABLE TRUE
+#endif
+
+/* Target Modes (based on jumper settings on hardware [see user manual]) */
+enum
+{
+ /* BTE BBY */
+ /* J3 J4 SW3-3 SW3-2 SW3-1 */
+ /* -------------------------------------------- */
+ BTE_MODE_SERIAL_APP, /* OUT OUT OFF OFF OFF Sample serial port application */
+ BTE_MODE_APPL, /* IN OUT OFF OFF ON Target used with Tester through RPC */
+ BTE_MODE_RESERVED, /* OUT IN OFF ON OFF Reserved */
+ BTE_MODE_SAMPLE_APPS, /* IN IN OFF ON ON Sample applications (ICP/HSP) */
+ BTE_MODE_DONGLE, /* not yet supported ON OFF OFF Dongle mode */
+ BTE_MODE_APPL_PROTOCOL_TRACE, /* this is a fake mode do allow protocol tracing in application without rpc */
+ BTE_MODE_INVALID
+};
+
+extern volatile UINT8 bte_target_mode; /* indicates the mode that the board is running in */
+
+/* Startup options */
+extern UINT32 bte_startup_options; /* Switch and jumper settings at startup */
+void bte_get_startup_options(UINT32 *p_options); /* Platform specific function for getting startup options */
+
+#define BTE_OPTIONS_TARGET_MODE_MASK 0x00000007 /* bits 2-0 indicate target mode (QuickConnect: jp3 & jp4, BBY: SW3-1 & SW3-2)*/
+
+
+/****************************************************************************
+ * Definitions to define which type of application gets built
+ ****************************************************************************/
+#define BUILD_HCITOOL FALSE
+#define BUILD_L2PING FALSE
+
+
+#define LINUX_FM_DRIVER_INCLUDED FALSE
+
+
+/* hcisu userial operations. should probably go into bt_types to avoid collisions! */
+#define BT_EVT_TO_HCISU_USERIAL_OP (0x0080 | BT_EVT_HCISU)
+/* operation for above hcisu event */
+#define BT_HCISU_USERIAL_OPEN (0) /* open serial port calling USERIAL_Open() */
+#define BT_HCISU_USERIAL_CLOSE (1) /* close userial port */
+/* options associated with close op */
+#define BT_HCISU_USERIAL_CL_NO_DIS_BT 0 /* do not touch bt_wake and power gpio */
+#define BT_HCISU_USERIAL_CL_DIS_BT 1 /* put power and bt_wake into defined off state to preserve
+ power */
+/* status codes for callback */
+#define BTE_HCISU_USERIAL_FAIL 0
+#define BTE_HCISU_USERIAL_OK 1
+typedef void (tUSERIAL_MSG_CBACK) (int status);
+typedef struct tHCISU_USERIAL_MSG_tag {
+ BT_HDR hdr;
+ tUSERIAL_MSG_CBACK *p_cback;
+ UINT8 port; /* port number */
+ UINT8 op;
+ UINT8 option; /* option for operation. depends on operation */
+} tHCISU_USERIAL_MSG;
+
+extern void bte_hcisu_userial_oper( tUSERIAL_MSG_CBACK *p_cback, UINT8 port, UINT8 op, UINT8 option );
+
+/* Pointer to function for sending HCI commands and data to the HCI tranport */
+extern int (*p_bte_hci_send)(UINT16 port, BT_HDR *p_msg);
+
+
+/* Protocol trace mask */
+extern UINT32 bte_proto_trace_mask;
+
+/* Version string */
+extern const UINT8 bte_version_string[];
+
+typedef struct tBAUD_REG_tag {
+ UINT8 DHBR;
+ UINT8 DLBR;
+ UINT8 ExplicitBaudRate0;
+ UINT8 ExplicitBaudRate1;
+ UINT8 ExplicitBaudRate2;
+ UINT8 ExplicitBaudRate3;
+} tBAUD_REG;
+
+#include "gki.h"
+
+extern const tBAUD_REG baud_rate_regs[];
+
+#endif /* BTE_H */
diff --git a/include/bte_appl.h b/include/bte_appl.h
new file mode 100644
index 0000000..45f6771
--- /dev/null
+++ b/include/bte_appl.h
@@ -0,0 +1,179 @@
+/*****************************************************************************
+** *
+** Name: bte_appl.h *
+** *
+** Description: This is the interface file for the bte application task *
+** *
+** Copyright (c) 2002-2009 Broadcom Corp., All Rights Reserved. *
+** WIDCOMM Bluetooth Core. Proprietary and confidential. *
+******************************************************************************/
+
+#ifndef BTE_APPL_H
+#define BTE_APPL_H
+
+#include "btm_int.h"
+#include "bta_api.h"
+#include "bta_sys.h"
+#include "bte.h"
+
+/* Maximum length for serial port device name */
+#ifndef BTE_APPL_MAX_USERIAL_DEV_NAME
+#define BTE_APPL_MAX_USERIAL_DEV_NAME (256)
+#endif
+#ifndef BTAPP_AHF_API_SUPPORT
+#define BTAPP_AHF_API_SUPPORT FALSE
+#endif
+
+/* BTA APP_IDs */
+#define UI_DM_ID 1
+#define UI_PRM_ID 20
+/* this defines the enabled BTA modules. client may not be defined as those are enabled at run time.
+ * they are defined for completeness. please check with bta_sys.h for new modules.
+ * BTA_ID_DM serves as flag for BTA_EnableBluetooth()
+ * BTA_ID_RES can be used to fs ID in bte_appl.
+ */
+
+#define BTAPP_NUM_ID_BLOCKS ((BTA_ID_MAX/32)+1) /* number of 32 bit required to store one bit per
+ btapp id */
+
+#define BTAPP_APPL_MAIL_EVENT(x) (x<<8) /* define bte_appl task mail box event. LSB contains
+ BTA_ID_xxx (see bta_sys.h) */
+#define BTAPP_APPL_MAIL_EVT 0xff00 /* high byte contains bitmap of application module event */
+
+/* helper macro to copy BTA callack data y into message buffer x, for event data structure z */
+#define MEMCPY_APPL_MSG(x, y, z) memcpy( (void *)(((UINT8 *)x)+sizeof(BT_HDR)), (void *)y, sizeof(z) )
+
+/* Event masks for BTE_APPL_TASK */
+#define BTE_APPL_STARTUP_EVT EVENT_MASK(APPL_EVT_0) /* Bluetooth has started */
+#define BTE_APPL_SHUTDOWN_EVT EVENT_MASK(APPL_EVT_1) /* Bluetooth is shutting down */
+#define BTE_APPL_SOCKET_RX_EVT EVENT_MASK(APPL_EVT_2) /* Socket data ready to be read */
+#define BTE_APPL_DBUS_RX_EVT EVENT_MASK(APPL_EVT_3) /* DBUS message ready to be read */
+#define BTE_APPL_BTA_ENABLE_EVT EVENT_MASK(APPL_EVT_4) /* BTA Enabled event */
+
+
+/* Application configuration */
+#define BTE_APPL_PATCHRAM_PATH_MAXLEN 128
+#define BTE_APPL_CONTACTS_DB_PATH 256
+
+typedef struct {
+ char patchram_path[BTE_APPL_PATCHRAM_PATH_MAXLEN+1];
+ UINT32 patchram_addr;
+ UINT32 reconfig_baud;
+ UINT32 clock_rate; /* clock rate (for uart baud calculation) */
+ BD_ADDR local_addr; /* local bd addr */
+ BD_ADDR rem_addr;
+ UINT8 lpm_enabled;
+ UINT8 bt_wake_polarity;
+ UINT8 host_wake_polarity;
+ BOOLEAN ag_enable_3way_conf;
+ UINT16 ag_voice_settings;
+ UINT8 ag_vsc_pcm_config[5];
+ UINT8 ag_vsc_sco_pcm[5];
+ /*tBTM_CMPL_CB*/ tBTM_DEV_STATUS_CB *p_reset_cplt_cb; /* Current reset_cplt_cb */
+ char contacts_db[BTE_APPL_CONTACTS_DB_PATH+1];
+ UINT32 bta_module_state[BTAPP_NUM_ID_BLOCKS]; /* state of enabled bta modules */
+#if (BTAPP_AHF_API_SUPPORT==TRUE)
+ UINT8 afh_first;
+ UINT8 afh_last;
+#endif
+} tBTE_APPL_CFG;
+
+extern tBTE_APPL_CFG bte_appl_cfg;
+
+typedef struct {
+ pthread_mutex_t mutex; /* mutex to protect below signal condition */
+ pthread_cond_t cond; /* signal event */
+} tBTAPP_SEMAPHORE;
+
+/* helper functions to handle pthread conditions event from outside GKI */
+extern void bte_create_semaphore( tBTAPP_SEMAPHORE * p_sema );
+extern void bte_wait_semaphore( tBTAPP_SEMAPHORE * p_sema, unsigned msecs_to );
+extern void bte_signal_semaphore( tBTAPP_SEMAPHORE * p_sema );
+extern void bte_destroy_semaphore( tBTAPP_SEMAPHORE * p_sema );
+
+/* global application control block storing global application states and variables */
+typedef struct tBTE_APPL_CB_tag {
+ sigset_t signal_handler_set; /* signal handler set used by signal handler thread */
+#if ( TRUE == BTE_RESET_BAUD_ON_BT_DISABLE )
+ tBTAPP_SEMAPHORE shutdown_semaphore; /* used to sync with terminate handler initated ops */
+#endif
+ BOOLEAN amp_enabled; /* TRUE if AMP is in use */
+} tBTE_APPL_CB;
+
+extern tBTE_APPL_CB bte_appl_cb;
+
+/* Exports the application task */
+extern void BTE_appl_task(UINT32 params);
+extern int BTAPP_enable_bta( const UINT32 bta_module_state[BTAPP_NUM_ID_BLOCKS], int includingFM );
+extern int BTAPP_disable_bta( const UINT32 bta_module_state[BTAPP_NUM_ID_BLOCKS], int includingFM );
+
+extern UINT8 appl_trace_level;
+#define BT_PCM_CLK_IDX 1
+#ifndef BT_PCM_DEF_CLK
+#define BT_PCM_DEF_CLK 4 /* defaults to 2048khz PCM clk */
+#endif
+#define BT_PCM_SYNC_MS_ROLE_IDX 3
+#define BT_PCM_CLK_MS_ROLE_IDX 4
+#ifndef BT_PCM_DEF_ROLE
+#define BT_PCM_DEF_ROLE 0x00 /* assume slave as default */
+#endif
+
+/* helper macros to set, clear and get current BTA module id in a 32bit ARRAY!! */
+/* set bit id to 1 in UINT32 a[] NO RANGE CHECK!*/
+#define BTAPP_SET_BTA_MOD(id, a) { a[id/32] |= (UINT32)(1<<(id % 32)); }
+
+/* set bit id to 0 (cleared) in UINT32 a[] NO RANGE CHECK */
+#define BTAPP_CLEAR_BTA_MOD(id, a) { a[id/32] &= (UINT32)!(1<<(id % 32)); }
+
+/* tests if bit id is 1 in UINT32 a[] NO RANGE CHECK */
+#define BTAPP_BTA_MOD_IS_SET(id, a) (a[id/32] & (UINT32)(1<<(id % 32)))
+
+/* update this list either via btld.txt or directly here by adding the new profiles as per bta_sys.h.
+ * each xxx_LISTx may only contain 32 bits */
+#ifndef BTAPP_BTA_MODULES_LIST0
+#define BTAPP_BTA_MODULES_LIST0 (\
+ ( 1<<BTA_ID_DM ) | \
+ ( 1<<BTA_ID_DG ) | \
+ ( 1<<BTA_ID_AG ) | \
+ ( 1<<BTA_ID_OPC )| \
+ ( 1<<BTA_ID_OPS )| \
+ ( 1<<BTA_ID_FTS )| \
+ ( 1<<BTA_ID_PAN )| \
+ ( 1<<BTA_ID_PR ) | \
+ ( 1<<BTA_ID_SC) | \
+ ( 1<<BTA_ID_AV ) | \
+ ( 1<<BTA_ID_HH ) | \
+ ( 1<<BTA_ID_PBS) | \
+ ( 1<<BTA_ID_FMTX)| \
+ ( 1<<BTA_ID_JV) | \
+ ( 1<<BTA_ID_MSE) \
+ )
+#endif
+
+#define BTAPP_LIST1_BLOCK 32 /* next 32 bit block */
+#ifndef BTAPP_BTA_MODULES_LIST1
+#define BTAPP_BTA_MODULES_LIST1 (\
+ ( 1<<(BTA_ID_MAX-BTAPP_LIST1_BLOCK) ) | \
+ ( 1<<(BTA_ID_MSE-BTAPP_LIST1_BLOCK) ) | \
+ 0 \
+ )
+#endif
+/* for future GPS etc support. goes int LIST1 above */
+#if 0
+ ( 1<<(BTA_ID_SSR-BTAPP_LIST1_BLOCK) ) \
+ ( 1<<(BTA_ID_MSE-BTAPP_LIST1_BLOCK) ) \
+ ( 1<<(BTA_ID_MCE-BTAPP_LIST1_BLOCK) )
+#endif
+
+/* used application init default in bte_main.c, bte_appl_cfg */
+#ifndef BTAPP_DEFAULT_MODULES
+#if (1==BTAPP_NUM_ID_BLOCKS)
+#define BTAPP_DEFAULT_MODULES {BTAPP_BTA_MODULES_LIST0} /* max 32 modules IDs */
+#elif (2==BTAPP_NUM_ID_BLOCKS)
+#define BTAPP_DEFAULT_MODULES {BTAPP_BTA_MODULES_LIST0, BTAPP_BTA_MODULES_LIST1} /* 64 module IDs max */
+#else
+#error "Define more BTAPP_BTA_MODULES_LISTx"
+#endif
+#endif
+
+#endif /* BTE_APPL_H */
diff --git a/include/buildcfg.h b/include/buildcfg.h
new file mode 100644
index 0000000..773f0b3
--- /dev/null
+++ b/include/buildcfg.h
@@ -0,0 +1,6 @@
+//Based on the target variant one of these would be picked
+#ifdef TARGET_CRESPO
+#include "buildcfg_crespo.h"
+#else
+#include "buildcfg_maguro.h"
+#endif
diff --git a/include/buildcfg_crespo.h b/include/buildcfg_crespo.h
new file mode 100644
index 0000000..83778d3
--- /dev/null
+++ b/include/buildcfg_crespo.h
@@ -0,0 +1,236 @@
+#ifndef BUILDCFG_H
+#define BUILDCFG_H
+#define AVCT_INCLUDED FALSE
+#define AVRC_INCLUDED FALSE
+//#define AVRC_METADATA_INCLUDED TRUE
+//#define AVRC_ADV_CTRL_INCLUDED FALSE
+#define AVDT_INCLUDED FALSE
+#define AT91_MAIN_INCLUDED FALSE
+#define AT91_DRV_INCLUDED FALSE
+#define AT91_LIB_INCLUDED FALSE
+#define AT91_GKI_INCLUDED FALSE
+#define UNV_INCLUDED FALSE
+#define BBY_MAIN_INCLUDED FALSE
+#define A2D_INCLUDED FALSE
+#define A2D_SBC_INCLUDED FALSE
+#define A2D_M12_INCLUDED FALSE
+#define A2D_M24_INCLUDED FALSE
+#define VDP_INCLUDED FALSE
+#define VDP_H263_INCLUDED FALSE
+#define VDP_MPEG_INCLUDED FALSE
+#define VDP_VEND_INCLUDED FALSE
+#define BIP_INCLUDED FALSE
+#define BIP_INITR_INCLUDED FALSE
+#define BIP_RSPDR_INCLUDED FALSE
+#define BIP_PUSH_INCLUDED FALSE
+#define BIP_PULL_INCLUDED FALSE
+#define BIP_PRINTING_INCLUDED FALSE
+#define BIP_ARCHIVE_INCLUDED FALSE
+#define BIP_CAMERA_INCLUDED FALSE
+#define BIP_DISPLAY_INCLUDED FALSE
+#define BPP_INCLUDED FALSE
+#define BPP_SND_INCLUDED FALSE
+#define DUN_INCLUDED FALSE
+#define GAP_INCLUDED FALSE
+#define GOEP_INCLUDED FALSE
+#define GOEP_FS_INCLUDED FALSE
+#define GATT_PTS FALSE
+#define HCITHIN_INCLUDED FALSE
+#define BTM_SEC_MAX_SERVICE_RECORDS 32
+#define L2CAP_INCLUDED TRUE
+#define L2CAP_LINK_INACTIVITY_TOUT 4
+#define L2CAP_FCR_INCLUDED TRUE
+#define L2CAP_EXTFEA_SUPPORTED_MASK (L2CAP_EXTFEA_ENH_RETRANS | L2CAP_EXTFEA_STREAM_MODE | L2CAP_EXTFEA_NO_CRC | L2CAP_EXTFEA_FIXED_CHNLS)
+#define OBX_INCLUDED TRUE
+#define OBX_SERVER_INCLUDED TRUE
+#define OBX_CLIENT_INCLUDED TRUE
+#define OBX_MD5_INCLUDED FALSE
+#define OBX_MD5_TEST_INCLUDED FALSE
+#define OBX_14_INCLUDED FALSE
+#define BTUI_OPS_FORMATS (BTA_OP_VCARD21_MASK | BTA_OP_VCAL_MASK | BTA_OP_VNOTE_MASK | BTA_OP_ANY_MASK)
+#define BTA_OPC_SENDING_ABORT TRUE
+#define RFCOMM_INCLUDED TRUE
+#define MAX_RFC_PORTS 30
+#define MAX_BD_CONNECTIONS 7
+#define BTA_RFC_MTU_SIZE (L2CAP_MTU_SIZE-L2CAP_MIN_OFFSET-RFCOMM_DATA_OVERHEAD)
+#define BTA_JV_DEF_RFC_MTU BTA_RFC_MTU_SIZE
+#define PORT_TX_BUF_HIGH_WM 15
+#define PORT_RX_BUF_HIGH_WM 10
+#define PORT_RX_BUF_LOW_WM 4
+#define PORT_RX_BUF_CRITICAL_WM 15
+#define PORT_TX_BUF_CRITICAL_WM 25
+#define PORT_RX_LOW_WM (BTA_RFC_MTU_SIZE * PORT_RX_BUF_LOW_WM)
+#define PORT_RX_HIGH_WM (BTA_RFC_MTU_SIZE * PORT_RX_BUF_HIGH_WM)
+#define PORT_RX_CRITICAL_WM (BTA_RFC_MTU_SIZE * PORT_RX_BUF_CRITICAL_WM)
+#define PORT_TX_HIGH_WM (BTA_RFC_MTU_SIZE * PORT_TX_BUF_HIGH_WM)
+#define PORT_TX_CRITICAL_WM (BTA_RFC_MTU_SIZE * PORT_TX_BUF_CRITICAL_WM)
+#define BTA_DUN_MTU BTA_RFC_MTU_SIZE
+#define BTA_SPP_MTU BTA_RFC_MTU_SIZE
+#define BTA_FAX_MTU BTA_RFC_MTU_SIZE
+#define SDP_DI_INCLUDED TRUE
+#define SDP_RAW_DATA_INCLUDED TRUE
+#define SDP_RAW_PDU_INCLUDED TRUE
+#define SDP_POOL_ID 3
+#define BNEP_INCLUDED FALSE
+#define PAN_INCLUDED FALSE
+#define SAP_SERVER_INCLUDED FALSE
+#define HID_DEV_INCLUDED FALSE
+#define HID_HOST_INCLUDED FALSE
+#define BLE_INCLUDED FALSE
+#define BTM_BLE_CONFORMANCE_TESTING FALSE
+#define ATT_INCLUDED FALSE
+#define ATT_DEBUG FALSE
+#define GATTS_APPU_USE_GATT_TRACE FALSE
+#define GATT_CLIENT_ENABLED FALSE
+#define GATT_SERVER_ENABLED FALSE
+#define SMP_INCLUDED FALSE
+#define SMP_HOST_ENCRYPT_INCLUDED FALSE
+#define CE_TEST_INCLUDED FALSE
+#define SER_INCLUDED FALSE
+#define RPC_INCLUDED FALSE
+#define MMI_INCLUDED FALSE
+#define SAP_INCLUDED FALSE
+#define SBC_NO_PCM_CPY_OPTION FALSE
+#define SBC_IPAQ_OPT FALSE
+#define SBC_IS_64_MULT_IN_QUANTIZER FALSE
+//#define MCA_INCLUDED TRUE
+#define BTE_HCIUTILS_HOOK_INCLUDED FALSE
+#define BTA_INCLUDED TRUE
+#define BTA_AG_INCLUDED TRUE
+#define BTA_CT_INCLUDED FALSE
+#define BTA_CG_INCLUDED FALSE
+#define BTA_DG_INCLUDED FALSE
+#define BTA_FT_INCLUDED FALSE
+#define BTA_OP_INCLUDED FALSE
+#define BTA_PR_INCLUDED FALSE
+#define BTA_SS_INCLUDED FALSE
+#define BTA_DM_INCLUDED TRUE
+#define BTA_DI_INCLUDED FALSE
+#define BTA_BI_INCLUDED FALSE
+#define BTA_SC_INCLUDED FALSE
+#define BTA_PAN_INCLUDED FALSE
+#define BTA_FS_INCLUDED TRUE
+#define BTA_AC_INCLUDED FALSE
+#define BTA_HD_INCLUDED FALSE
+#define BTA_HH_INCLUDED FALSE
+#define HH_USE_BTHID FALSE
+#define BTA_AR_INCLUDED FALSE
+#define BTA_AV_INCLUDED FALSE
+#define BTA_AV_VDP_INCLUDED FALSE
+#define BTA_AVK_INCLUDED FALSE
+#define BTA_PBS_INCLUDED FALSE
+#define BTA_PBC_INCLUDED FALSE
+#define BTA_FM_INCLUDED FALSE
+#define BTA_FM_DEBUG FALSE
+#define BTA_FMTX_INCLUDED FALSE
+#define BTA_FMTX_DEBUG FALSE
+#define BTA_FMTX_FMRX_SWITCH_WORKAROUND FALSE
+#define BTA_FMTX_US_FCC_RULES FALSE
+#define BTA_HS_INCLUDED FALSE
+#define BTA_MSE_INCLUDED FALSE
+#define BTA_MCE_INCLUDED FALSE
+#define BTA_PLAYBACK_INCLUDED FALSE
+#define BTA_SSR_INCLUDED FALSE
+#define BTA_JV_INCLUDED FALSE
+#define BTA_EIR_CANNED_UUID_LIST FALSE
+#define BTA_GATT_INCLUDED FALSE
+#define BTA_HL_INCLUDED TRUE
+#define BTA_HL_DEBUG TRUE
+#define RSI_INCLUDED TRUE
+#define RPC_TRACE_ONLY FALSE
+#define ANDROID_APP_INCLUDED TRUE
+#define ANDROID_USE_LOGCAT TRUE
+#define LINUX_GKI_INCLUDED TRUE
+#define TICKS_PER_SEC 10
+#define QUICK_TIMER_TICKS_PER_SEC 10
+#define BTA_SYS_TIMER_PERIOD 100
+#define GKI_BUF1_SIZE 288
+#define GKI_BUF3_MAX 100
+#define GKI_BUF3_SIZE (4096+16)
+#define GKI_BUF4_SIZE (8080+26)
+#define GKI_SHUTDOWN_EVT APPL_EVT_7
+#define GKI_PTHREAD_JOINABLE TRUE
+#define LINUX_DRV_INCLUDED TRUE
+#define LINUX_OS TRUE
+#define BTU_TASK 0
+#define BTIF_TASK 1
+#define GKI_MAX_TASKS 2
+//#define BTE_APPL_TASK 2
+//#define SBC_ENCODE_TASK 3
+//#define AV_SRC_READ_TASK 4
+//#define PBS_SQL_TASK 5
+#define BTM_APP_DEV_INIT bte_main_post_reset_init
+#define BTE_RESET_BAUD_ON_BT_DISABLE FALSE
+#define BTE_IDLE_TASK_INCLUDED FALSE
+#define APPL_INCLUDED TRUE
+#define USE_UART_HCI TRUE
+#define BTU_BTA_INCLUDED TRUE
+#define BTUI_DEFAULT_LOCAL_NAME "BRCM Bluetooth"
+#define SBC_FOR_EMBEDDED_LINUX TRUE
+#define UPIO_INCLUDED TRUE
+#define BTA_DM_REMOTE_DEVICE_NAME_LENGTH 248
+#define BTM_MAX_REM_BD_NAME_LEN 248
+#define BTM_MAX_LOC_BD_NAME_LEN 248
+#define BTM_USE_DEF_LOCAL_NAME TRUE
+#define BTM_DEF_LOCAL_NAME "Galaxy Nexus BlueDroid"
+#define BTM_INQ_DB_SIZE 40
+#define BTM_SEC_MAX_DEVICE_RECORDS 100
+#define BTM_SEC_FORCE_RNR_FOR_DBOND FALSE
+#define BTM_AUTOMATIC_HCI_RESET FALSE
+#define AVDT_VERSION 0x0102
+#define BTA_SIMUL_AV_HFP_NOT_SUPPORTED TRUE
+#define BTA_AG_AT_MAX_LEN 512
+#define BTA_AVRCP_FF_RW_SUPPORT TRUE
+#define BTM_MAX_SCO_LINKS 2
+#define BTA_AG_SCO_PKT_TYPES (BTM_SCO_LINK_ONLY_MASK | BTM_SCO_PKT_TYPES_MASK_EV3 | BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 | BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 | BTM_SCO_PKT_TYPES_MASK_NO_3_EV5)
+#define BTAPP_AV_SECMASK (BTA_SEC_AUTHENTICATE | BTA_SEC_AUTHORIZE)
+#define BTA_AV_MAX_A2DP_MTU 668
+#define BTA_AV_RET_TOUT 15
+#define PORCHE_PAIRING_CONFLICT TRUE
+#define BTA_AV_CO_CP_SCMS_T FALSE
+#define AVDT_CONNECT_CP_ONLY FALSE
+#define BTL_CFG_USE_CONF_FILE FALSE
+#define BTAPP_AHF_API_SUPPORT TRUE
+#define BTAPP_TESTMODE_INCLUDED TRUE
+#define HCILP_INCLUDED TRUE
+#define HCISU_H4_INCLUDED TRUE
+#define BT_PCM_DEF_CLK 0
+#define BT_PCM_DEF_ROLE 0
+#define BT_USE_TRACES TRUE
+#define BT_TRACE_BTIF TRUE
+#define BTTRC_INCLUDED FALSE
+#define BT_TRACE_VERBOSE FALSE
+#define BTTRC_PARSER_INCLUDED FALSE
+#define MAX_TRACE_RAM_SIZE 10000
+#define OBX_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_ERROR
+//#define LOG_NDEBUG 1
+//#define LOG_NDDEBUG 1
+//#define LOG_NIDEBUG 1
+#define BTSNOOPDISP_INCLUDED TRUE
+#define BTSNOOP_FILENAME "/data/misc/bluedroid/btsnoop_hci.log"
+#define SNOOP_CONFIG_PATH "/data/misc/bluedroid/btsnoop_enabled"
+#define BTM_ALLOW_CONN_IF_NONDISCOVER TRUE
+#define BTLA_REL_2_X TRUE
+#define BTA_FM_DEBUG TRUE
+#define BTAPP_FM_USE_HW_POKE_VOLUME FALSE
+#define BTAPP_FM_AUDIO_PATH BTA_FM_AUDIO_DAC
+#define BTAPP_DM_SUPPORTED_SERVICES (BTA_HSP_SERVICE_MASK | BTA_HFP_SERVICE_MASK | BTA_A2DP_SERVICE_MASK | BTA_HID_SERVICE_MASK | BTA_OPP_SERVICE_MASK | BTA_BPP_SERVICE_MASK | BTA_NAP_SERVICE_MASK | BTA_PANU_SERVICE_MASK | BTA_HL_SERVICE_MASK)
+#define PBAP_ZERO_VCARD_IN_DB FALSE
+#define BTA_DM_SDP_DB_SIZE 4096
+#define BTA_BUSAPP_INCLUDED TRUE
+#define MAX_L2CAP_CLIENTS 15
+#define FTS_REJECT_INVALID_OBEX_SET_PATH_REQ TRUE
+#define HID_HOST_MAX_CONN_RETRY (3)
+#define BTAPP_TEST_OOB_INCLUDED TRUE
+#define ENABLE_PCM_LOGGER FALSE
+#define BTM_DISC_DURING_RS TRUE
+#define PAN_DTUN TRUE
+#define BT_UART_PORT "/dev/s3c2410_serial0"
+#define BTM_WBS_INCLUDED FALSE
+
+#define NO_GKI_RUN_RETURN TRUE
+
+#define BTE_MAIN_CFG_DEFAULT_PATCHFILE_NAME ("/vendor/firmware/bcm4329.hcd")
+
+#define AG_VOICE_SETTINGS HCI_DEFAULT_VOICE_SETTINGS
+#endif
diff --git a/include/buildcfg_maguro.h b/include/buildcfg_maguro.h
new file mode 100644
index 0000000..556f8dd
--- /dev/null
+++ b/include/buildcfg_maguro.h
@@ -0,0 +1,235 @@
+#ifndef BUILDCFG_H
+#define BUILDCFG_H
+#define AVCT_INCLUDED FALSE
+#define AVRC_INCLUDED FALSE
+#define AVDT_INCLUDED FALSE
+#define AVDTC_INCLUDED FALSE # Makefile only
+#define AT91_MAIN_INCLUDED FALSE
+#define AT91_DRV_INCLUDED FALSE
+#define AT91_LIB_INCLUDED FALSE
+#define AT91_GKI_INCLUDED FALSE
+#define UNV_INCLUDED FALSE
+#define BBY_MAIN_INCLUDED FALSE
+#define A2D_INCLUDED FALSE
+#define A2D_SBC_INCLUDED FALSE
+#define A2D_M12_INCLUDED FALSE
+#define A2D_M24_INCLUDED FALSE
+#define VDP_INCLUDED FALSE
+#define VDP_H263_INCLUDED FALSE
+#define VDP_MPEG_INCLUDED FALSE
+#define VDP_VEND_INCLUDED FALSE
+#define BIP_INCLUDED FALSE
+#define BIP_INITR_INCLUDED FALSE
+#define BIP_RSPDR_INCLUDED FALSE
+#define BIP_PUSH_INCLUDED FALSE
+#define BIP_PULL_INCLUDED FALSE
+#define BIP_PRINTING_INCLUDED FALSE
+#define BIP_ARCHIVE_INCLUDED FALSE
+#define BIP_CAMERA_INCLUDED FALSE
+#define BIP_DISPLAY_INCLUDED FALSE
+#define BPP_INCLUDED FALSE
+#define BPP_SND_INCLUDED FALSE
+#define BTM_INCLUDED FALSE # Makefile only
+#define BTU_INCLUDED FALSE # Makefile only
+#define BTUTHIN_INCLUDED FALSE # Makefile only
+#define DUN_INCLUDED FALSE
+#define GAP_INCLUDED FALSE
+#define GOEP_INCLUDED FALSE
+#define GOEP_FS_INCLUDED FALSE
+#define GATT_PTS FALSE
+#define HCIC_INCLUDED TRUE # Makefile only
+#define HCITHIN_INCLUDED FALSE
+#define BTM_SEC_MAX_SERVICE_RECORDS 32
+#define L2CAP_INCLUDED TRUE
+#define L2CAP_LINK_INACTIVITY_TOUT 4
+#define L2CAP_FCR_INCLUDED TRUE
+#define L2CAP_EXTFEA_SUPPORTED_MASK (L2CAP_EXTFEA_ENH_RETRANS | L2CAP_EXTFEA_STREAM_MODE | L2CAP_EXTFEA_NO_CRC | L2CAP_EXTFEA_FIXED_CHNLS)
+#define OBX_INCLUDED TRUE
+#define OBX_SERVER_INCLUDED TRUE
+#define OBX_CLIENT_INCLUDED TRUE
+#define OBX_MD5_INCLUDED FALSE
+#define OBX_MD5_TEST_INCLUDED FALSE
+#define OBX_14_INCLUDED FALSE
+#define BTUI_OPS_FORMATS (BTA_OP_VCARD21_MASK | BTA_OP_VCAL_MASK | BTA_OP_VNOTE_MASK | BTA_OP_ANY_MASK)
+#define BTA_OPC_SENDING_ABORT TRUE
+#define RFCOMM_INCLUDED TRUE
+#define MAX_RFC_PORTS 30
+#define MAX_BD_CONNECTIONS 7
+#define BTA_RFC_MTU_SIZE (L2CAP_MTU_SIZE-L2CAP_MIN_OFFSET-RFCOMM_DATA_OVERHEAD)
+#define PORT_TX_BUF_HIGH_WM 10
+#define PORT_RX_BUF_HIGH_WM 10
+#define PORT_RX_BUF_LOW_WM 4
+#define PORT_RX_BUF_CRITICAL_WM 15
+#define PORT_TX_BUF_CRITICAL_WM 15
+#define PORT_RX_LOW_WM (BTA_RFC_MTU_SIZE * PORT_RX_BUF_LOW_WM)
+#define PORT_RX_HIGH_WM (BTA_RFC_MTU_SIZE * PORT_RX_BUF_HIGH_WM)
+#define PORT_RX_CRITICAL_WM (BTA_RFC_MTU_SIZE * PORT_RX_BUF_CRITICAL_WM)
+#define PORT_TX_HIGH_WM (BTA_RFC_MTU_SIZE * PORT_TX_BUF_HIGH_WM)
+#define PORT_TX_CRITICAL_WM (BTA_RFC_MTU_SIZE * PORT_TX_BUF_CRITICAL_WM)
+#define BTA_DUN_MTU BTA_RFC_MTU_SIZE
+#define BTA_SPP_MTU BTA_RFC_MTU_SIZE
+#define BTA_FAX_MTU BTA_RFC_MTU_SIZE
+#define SDP_INCLUDED TRUE # Makefile only
+#define SDP_DI_INCLUDED TRUE
+#define SDP_RAW_DATA_INCLUDED TRUE
+#define SDP_RAW_PDU_INCLUDED TRUE
+#define SDP_POOL_ID 3
+#define SDP_MAX_REC_ATTR 25
+#define SDP_MAX_ATTR_LEN 400
+#define SDP_MAX_PAD_LEN 600
+#define XML_INCLUDED TRUE # Makefile only
+#define BNEP_INCLUDED FALSE
+#define PAN_INCLUDED FALSE
+#define ANT_INCLUDED FALSE
+#define SAP_SERVER_INCLUDED FALSE
+#define HID_DEV_INCLUDED FALSE
+#define HID_HOST_INCLUDED FALSE
+#define BLE_INCLUDED FALSE
+#define BTM_BLE_CONFORMANCE_TESTING FALSE
+#define ATT_INCLUDED FALSE
+#define ATT_DEBUG FALSE
+#define GATTS_APPU_USE_GATT_TRACE FALSE
+#define GATT_CLIENT_ENABLED FALSE
+#define GATT_SERVER_ENABLED FALSE
+#define SMP_INCLUDED FALSE
+#define SMP_HOST_ENCRYPT_INCLUDED FALSE
+#define CE_TEST_INCLUDED FALSE
+#define FLASHEXE_INCLUDED TRUE # Makefile only
+#define SER_INCLUDED FALSE
+#define RPC_INCLUDED FALSE
+#define HSA_INCLUDED FALSE # Makefile only
+#define MMI_INCLUDED FALSE
+#define SAP_INCLUDED FALSE
+#define SBC_ENCODER_INCLUDED FALSE # Makefile only
+#define SBC_DECODER_INCLUDED FALSE # Makefile only
+#define SBC_NO_PCM_CPY_OPTION FALSE
+#define SBC_IPAQ_OPT FALSE
+#define SBC_IS_64_MULT_IN_QUANTIZER FALSE
+#define BTE_HCIUTILS_HOOK_INCLUDED FALSE
+#define BTA_INCLUDED TRUE
+#define BTA_AG_INCLUDED TRUE
+#define BTA_CT_INCLUDED FALSE
+#define BTA_CG_INCLUDED FALSE
+#define BTA_DG_INCLUDED FALSE
+#define BTA_FT_INCLUDED FALSE
+#define BTA_OP_INCLUDED FALSE
+#define BTA_PR_INCLUDED FALSE
+#define BTA_SS_INCLUDED FALSE
+#define BTA_DM_INCLUDED TRUE
+#define BTA_DI_INCLUDED FALSE
+#define BTA_BI_INCLUDED FALSE
+#define BTA_SC_INCLUDED FALSE
+#define BTA_PAN_INCLUDED FALSE
+#define BTA_FS_INCLUDED TRUE
+#define BTA_AC_INCLUDED FALSE
+#define BTA_HD_INCLUDED FALSE
+#define BTA_HH_INCLUDED FALSE
+#define HH_USE_BTHID FALSE
+#define BTA_AR_INCLUDED FALSE
+#define BTA_AV_INCLUDED FALSE
+#define BTA_AV_VDP_INCLUDED FALSE
+#define BTA_AVK_INCLUDED FALSE
+#define BTA_PBS_INCLUDED FALSE
+#define BTA_PBC_INCLUDED FALSE
+#define BTA_FM_INCLUDED FALSE
+#define BTA_FM_DEBUG FALSE
+#define BTA_FMTX_INCLUDED FALSE
+#define BTA_FMTX_DEBUG FALSE
+#define BTA_FMTX_FMRX_SWITCH_WORKAROUND FALSE
+#define BTA_FMTX_US_FCC_RULES FALSE
+#define BTA_HS_INCLUDED FALSE
+#define BTA_MSE_INCLUDED FALSE
+#define BTA_MCE_INCLUDED FALSE
+#define BTA_PLAYBACK_INCLUDED FALSE
+#define BTA_SSR_INCLUDED FALSE
+#define BTA_JV_INCLUDED FALSE
+#define BTA_EIR_CANNED_UUID_LIST FALSE
+#define BTA_GATT_INCLUDED FALSE
+#define MMP_INCLUDED FALSE # Makefile only
+#define BTELIB_INCLUDED FALSE # Makefile only
+#define RSI_INCLUDED TRUE
+#define RPC_TRACE_ONLY FALSE
+#define ANDROID_APP_INCLUDED TRUE
+#define ANDROID_USE_LOGCAT TRUE
+#define LINUX_GKI_INCLUDED TRUE
+#define TICKS_PER_SEC 10
+#define QUICK_TIMER_TICKS_PER_SEC 10
+#define BTA_SYS_TIMER_PERIOD 100
+#define GKI_BUF1_SIZE 288
+#define GKI_BUF3_MAX 200
+#define GKI_BUF3_SIZE (4096+16)
+#define GKI_BUF4_SIZE (8080+26)
+#define GKI_SHUTDOWN_EVT APPL_EVT_7
+#define GKI_PTHREAD_JOINABLE TRUE
+#define LINUX_DRV_INCLUDED TRUE
+#define LINUX_OS TRUE
+#define BTU_TASK 0
+#define BTIF_TASK 1
+#define GKI_MAX_TASKS 2
+#define BTM_APP_DEV_INIT bte_main_post_reset_init
+#define BTE_IDLE_TASK_INCLUDED FALSE
+#define APPL_INCLUDED TRUE
+#define USE_UART_HCI TRUE
+#define BTU_BTA_INCLUDED TRUE
+#define BTUI_DEFAULT_LOCAL_NAME "BRCM Bluetooth"
+#define SBC_FOR_EMBEDDED_LINUX TRUE
+#define UPIO_INCLUDED TRUE
+#define BTA_DM_REMOTE_DEVICE_NAME_LENGTH 248
+#define BTM_MAX_REM_BD_NAME_LEN 248
+#define BTM_MAX_LOC_BD_NAME_LEN 248
+#define BTM_USE_DEF_LOCAL_NAME TRUE
+#define BTM_DEF_LOCAL_NAME "Galaxy Nexus BlueDroid"
+#define BTM_INQ_DB_SIZE 40
+#define BTM_SEC_MAX_DEVICE_RECORDS 100
+#define BTM_SEC_FORCE_RNR_FOR_DBOND FALSE
+#define BTM_AUTOMATIC_HCI_RESET FALSE
+#define AVDT_VERSION 0x0102
+#define BTA_SIMUL_AV_HFP_NOT_SUPPORTED TRUE
+#define BTA_AG_AT_MAX_LEN 512
+#define BTA_AVRCP_FF_RW_SUPPORT TRUE
+#define BTM_MAX_SCO_LINKS 2
+#define BTA_AG_SCO_PKT_TYPES (BTM_SCO_LINK_ONLY_MASK | BTM_SCO_PKT_TYPES_MASK_EV3 | BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 | BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 | BTM_SCO_PKT_TYPES_MASK_NO_3_EV5)
+#define BTAPP_AV_SECMASK (BTA_SEC_AUTHENTICATE | BTA_SEC_AUTHORIZE)
+#define BTA_AV_MAX_A2DP_MTU 668
+#define BTA_AV_RET_TOUT 15
+#define PORCHE_PAIRING_CONFLICT TRUE
+#define BTA_AV_CO_CP_SCMS_T FALSE
+#define AVDT_CONNECT_CP_ONLY FALSE
+#define BTL_CFG_USE_CONF_FILE FALSE
+#define BTAPP_AHF_API_SUPPORT TRUE
+#define BTAPP_TESTMODE_INCLUDED TRUE
+#define HCILP_INCLUDED TRUE
+#define HCISU_H4_INCLUDED TRUE
+#define BT_USE_TRACES TRUE
+#define BT_TRACE_BTIF TRUE
+#define BTTRC_INCLUDED FALSE
+#define BT_TRACE_VERBOSE FALSE
+#define BTTRC_PARSER_INCLUDED FALSE
+#define MAX_TRACE_RAM_SIZE 10000
+#define OBX_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_ERROR
+//#define LOG_NDEBUG 1
+//#define LOG_NDDEBUG 1
+//#define LOG_NIDEBUG 1
+#define BTSNOOPDISP_INCLUDED TRUE
+#define BTSNOOP_FILENAME "/data/misc/bluedroid/btsnoop_hci.log"
+#define SNOOP_CONFIG_PATH "/data/misc/bluedroid/btsnoop_enabled"
+#define BTM_ALLOW_CONN_IF_NONDISCOVER TRUE
+#define BTLA_REL_2_X TRUE
+#define BTAPP_DM_SUPPORTED_SERVICES (BTA_HSP_SERVICE_MASK | BTA_HFP_SERVICE_MASK | BTA_A2DP_SERVICE_MASK | BTA_HID_SERVICE_MASK | BTA_OPP_SERVICE_MASK | BTA_BPP_SERVICE_MASK)
+#define PBAP_ZERO_VCARD_IN_DB FALSE
+#define BTA_DM_SDP_DB_SIZE 4096
+#define BTA_BUSAPP_INCLUDED TRUE
+#define MAX_L2CAP_CLIENTS 15
+#define FTS_REJECT_INVALID_OBEX_SET_PATH_REQ TRUE
+#define HID_HOST_MAX_CONN_RETRY (3)
+#define BTAPP_TEST_OOB_INCLUDED TRUE
+#define ENABLE_PCM_LOGGER FALSE
+#define BTM_DISC_DURING_RS TRUE
+#define BT_UART_PORT "/dev/ttyO1"
+#define BTM_WBS_INCLUDED FALSE
+#define HL_INCLUDED FALSE
+#define NO_GKI_RUN_RETURN TRUE
+#define BTE_MAIN_CFG_DEFAULT_PATCHFILE_NAME ("/vendor/firmware/bcm4330.hcd")
+#define AG_VOICE_SETTINGS HCI_DEFAULT_VOICE_SETTINGS
+#endif
+
diff --git a/include/gki_target.h b/include/gki_target.h
new file mode 100644
index 0000000..6430a81
--- /dev/null
+++ b/include/gki_target.h
@@ -0,0 +1,486 @@
+/****************************************************************************
+**
+** Name: gki_target.h
+**
+** Function this file contains platform-specific GKI defintions
+** to be included by bt_target.h, nfc_target.h, and other
+** target header files.
+**
+** NOTE This file should always be included first.
+**
+**
+** Copyright (c) 1999-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef GKI_TARGET_H
+#define GKI_TARGET_H
+
+#ifdef BUILDCFG
+#include "buildcfg.h"
+#endif
+
+#include "data_types.h"
+
+/* Operating System Selection */
+#ifndef BTE_SIM_APP
+#define _GKI_ARM
+#define _GKI_STANDALONE
+#else
+#define _BT_WIN32
+#endif
+
+/* define prefix for exporting APIs from libraries */
+#define EXPORT_API
+
+#ifndef BTE_BSE_WRAPPER
+#ifdef BTE_SIM_APP
+#undef EXPORT_API
+#define EXPORT_API __declspec(dllexport)
+#endif
+#endif
+
+#define GKI_API EXPORT_API
+#define UDRV_API EXPORT_API
+
+#ifndef GKI_DEBUG
+#define GKI_DEBUG FALSE
+#endif
+
+
+#if defined (GKI_DEBUG) && (GKI_DEBUG == TRUE)
+#define GKI_TRACE(fmt, ...) LOGI ("%s: " fmt, __FUNCTION__, ## __VA_ARGS__)
+#else
+#define GKI_TRACE(fmt, ...)
+#endif
+
+/******************************************************************************
+**
+** Task configuration
+**
+******************************************************************************/
+
+/* Definitions of task IDs for inter-task messaging */
+#ifndef MMI_TASK
+#define MMI_TASK 0
+#endif
+
+#ifndef HCISU_TASK
+#define HCISU_TASK 1
+#endif
+
+#ifndef NCI_TASK
+#define NCI_TASK 2
+#endif
+
+#ifndef NFC_TASK
+#define NFC_TASK 3
+#endif
+
+#ifndef BTU_TASK
+#define BTU_TASK 4
+#endif
+
+/* BTE Application, Sample Apps, or Serial port Demo based on JP3 and JP4 setting) */
+#ifndef BTE_APPL_TASK
+#define BTE_APPL_TASK 5
+#endif
+
+#ifndef DEV_MGR_TASK
+#define DEV_MGR_TASK 6
+#endif
+
+#ifndef ISE_SCR_TASK
+#define ISE_SCR_TASK 7
+#endif
+
+#ifndef UCODEC_TASK
+#define UCODEC_TASK 8
+#endif
+
+#ifndef RPCT_TASK
+#define RPCT_TASK 9
+#endif
+
+#ifndef UNV_TASK
+#define UNV_TASK 10
+#endif
+
+#ifndef BTE_IDLE_TASK
+#define BTE_IDLE_TASK 11
+#endif
+
+#ifndef UIPC_TASK
+#define UIPC_TASK 12
+#endif
+
+#ifndef HCISU_AMP_TASK
+#define HCISU_AMP_TASK 13
+#endif
+
+
+/* The number of GKI tasks in the software system. */
+#ifndef GKI_MAX_TASKS
+#define GKI_MAX_TASKS 14
+#endif
+
+/******************************************************************************
+**
+** Timer configuration
+**
+******************************************************************************/
+
+/* The number of GKI timers in the software system. */
+#ifndef GKI_NUM_TIMERS
+#define GKI_NUM_TIMERS 3
+#endif
+
+/* A conversion value for translating ticks to calculate GKI timer. */
+#ifndef TICKS_PER_SEC
+#define TICKS_PER_SEC 100
+#endif
+
+/************************************************************************
+** Utility macros converting ticks to time with user define OS ticks per sec
+**/
+#ifndef GKI_MS_TO_TICKS
+#define GKI_MS_TO_TICKS(x) ((x) / (1000 / TICKS_PER_SEC))
+#endif
+
+#ifndef GKI_SECS_TO_TICKS
+#define GKI_SECS_TO_TICKS(x) ((x) * (TICKS_PER_SEC))
+#endif
+
+#ifndef GKI_TICKS_TO_MS
+#define GKI_TICKS_TO_MS(x) ((x) * 1000 / TICKS_PER_SEC)
+#endif
+
+#ifndef GKI_TICKS_TO_SECS
+#define GKI_TICKS_TO_SECS(x) ((x) / TICKS_PER_SEC)
+#endif
+
+
+
+/* TICK per second from OS (OS dependent change this macro accordingly to various OS) */
+#ifndef OS_TICKS_PER_SEC
+#define OS_TICKS_PER_SEC 1000
+#endif
+
+/************************************************************************
+** Utility macros converting ticks to time with user define OS ticks per sec
+**/
+
+#ifndef GKI_OS_TICKS_TO_MS
+#define GKI_OS_TICKS_TO_MS(x) ((x) * 1000 / OS_TICKS_PER_SEC)
+#endif
+
+
+#ifndef GKI_OS_TICKS_TO_SECS
+#define GKI_OS_TICKS_TO_SECS(x) ((x) / OS_TICKS_PER_SEC))
+#endif
+
+
+/* delay in ticks before stopping system tick. */
+#ifndef GKI_DELAY_STOP_SYS_TICK
+#define GKI_DELAY_STOP_SYS_TICK 10
+#endif
+
+/* Option to guarantee no preemption during timer expiration (most system don't need this) */
+#ifndef GKI_TIMER_LIST_NOPREEMPT
+#define GKI_TIMER_LIST_NOPREEMPT FALSE
+#endif
+
+/******************************************************************************
+**
+** Buffer configuration
+**
+******************************************************************************/
+
+/* TRUE if GKI uses dynamic buffers. */
+#ifndef GKI_USE_DYNAMIC_BUFFERS
+#define GKI_USE_DYNAMIC_BUFFERS FALSE
+#endif
+
+/* The size of the buffers in pool 0. */
+#ifndef GKI_BUF0_SIZE
+#define GKI_BUF0_SIZE 64
+#endif
+
+/* The number of buffers in buffer pool 0. */
+#ifndef GKI_BUF0_MAX
+#define GKI_BUF0_MAX 48
+#endif
+
+/* The ID of buffer pool 0. */
+#ifndef GKI_POOL_ID_0
+#define GKI_POOL_ID_0 0
+#endif
+
+/* The size of the buffers in pool 1. */
+#ifndef GKI_BUF1_SIZE
+#define GKI_BUF1_SIZE 128
+#endif
+
+/* The number of buffers in buffer pool 1. */
+#ifndef GKI_BUF1_MAX
+#define GKI_BUF1_MAX 26
+#endif
+
+/* The ID of buffer pool 1. */
+#ifndef GKI_POOL_ID_1
+#define GKI_POOL_ID_1 1
+#endif
+
+/* The size of the buffers in pool 2. */
+#ifndef GKI_BUF2_SIZE
+#define GKI_BUF2_SIZE 660
+#endif
+
+/* The number of buffers in buffer pool 2. */
+#ifndef GKI_BUF2_MAX
+#define GKI_BUF2_MAX 45
+#endif
+
+/* The ID of buffer pool 2. */
+#ifndef GKI_POOL_ID_2
+#define GKI_POOL_ID_2 2
+#endif
+
+/* The size of the buffers in pool 3. */
+#ifndef GKI_BUF3_SIZE
+#define GKI_BUF3_SIZE 1800
+#endif
+
+/* The number of buffers in buffer pool 3. */
+#ifndef GKI_BUF3_MAX
+#define GKI_BUF3_MAX 30
+#endif
+
+/* The ID of buffer pool 3. */
+#ifndef GKI_POOL_ID_3
+#define GKI_POOL_ID_3 3
+#endif
+
+/* The size of the largest PUBLIC fixed buffer in system. */
+#ifndef GKI_MAX_BUF_SIZE
+#define GKI_MAX_BUF_SIZE GKI_BUF3_SIZE
+#endif
+
+/* The pool ID of the largest PUBLIC fixed buffer in system. */
+#ifndef GKI_MAX_BUF_SIZE_POOL_ID
+#define GKI_MAX_BUF_SIZE_POOL_ID GKI_POOL_ID_3
+#endif
+
+/* RESERVED buffer pool for OBX */
+/* Ideally there should be 1 buffer for each instance for RX data, and some number
+of TX buffers based on active instances. OBX will only use these if packet size
+requires it. In most cases the large packets are used in only one direction so
+the other direction will use smaller buffers.
+Devices with small amount of RAM should limit the number of active obex objects.
+*/
+/* The size of the buffers in pool 4. */
+#ifndef GKI_BUF4_SIZE
+#define GKI_BUF4_SIZE 0x2000
+#endif
+
+/* The number of buffers in buffer pool 4. */
+#ifndef GKI_BUF4_MAX
+#define GKI_BUF4_MAX (OBX_NUM_SERVERS + OBX_NUM_CLIENTS)
+#endif
+
+/* The ID of buffer pool 4. */
+#ifndef GKI_POOL_ID_4
+#define GKI_POOL_ID_4 4
+#endif
+
+/* The number of fixed GKI buffer pools.
+eL2CAP requires Pool ID 5
+If BTM_SCO_HCI_INCLUDED is FALSE, Pool ID 6 is unnecessary, otherwise set to 7
+If BTA_HL_INCLUDED is FALSE then Pool ID 7 is uncessary and set the following to 7, otherwise set to 8
+If BLE_INCLUDED is FALSE then Pool ID 8 is uncessary and set the following to 8, otherwise set to 9
+If HCIUTILS_HOOK_INCLUDED is TRUE then Pool ID 9 is needed
+*/
+// btla-specific ++
+#ifndef GKI_NUM_FIXED_BUF_POOLS
+#if (defined(BTE_HCIUTILS_HOOK_INCLUDED) && (BTE_HCIUTILS_HOOK_INCLUDED == TRUE))
+#define GKI_NUM_FIXED_BUF_POOLS 10
+#else
+#define GKI_NUM_FIXED_BUF_POOLS 9
+#endif
+#endif
+// btla-specific --
+
+/* The buffer pool usage mask. */
+#ifndef GKI_DEF_BUFPOOL_PERM_MASK
+#define GKI_DEF_BUFPOOL_PERM_MASK 0xfff0
+#endif
+
+/* The number of fixed and dynamic buffer pools */
+#ifndef GKI_NUM_TOTAL_BUF_POOLS
+#define GKI_NUM_TOTAL_BUF_POOLS 10
+#endif
+
+/* The following is intended to be a reserved pool for L2CAP
+Flow control and retransmissions and intentionally kept out
+of order */
+
+/* The number of buffers in buffer pool 5. */
+#ifndef GKI_BUF5_MAX
+#define GKI_BUF5_MAX 64
+#endif
+
+/* The ID of buffer pool 5. */
+#ifndef GKI_POOL_ID_5
+#define GKI_POOL_ID_5 5
+#endif
+
+/* The size of the buffers in pool 5
+** Special pool used by l2cap retransmissions only. This size based on segment
+** that will fit into both DH5 and 2-DH3 packet types after accounting for GKI
+** header. 13 bytes of max headers allows us a 339 payload max. (in btui_app.txt)
+** Note: 748 used for insight scriptwrapper with CAT-2 scripts.
+*/
+#ifndef GKI_BUF5_SIZE
+#define GKI_BUF5_SIZE 748
+#endif
+
+/* The buffer corruption check flag. */
+#ifndef GKI_ENABLE_BUF_CORRUPTION_CHECK
+#define GKI_ENABLE_BUF_CORRUPTION_CHECK TRUE
+#endif
+
+/* The GKI severe error macro. */
+#ifndef GKI_SEVERE
+#define GKI_SEVERE(code)
+#endif
+
+/* TRUE if GKI includes debug functionality. */
+#ifndef GKI_DEBUG
+#define GKI_DEBUG FALSE
+#endif
+
+/* Maximum number of exceptions logged. */
+#ifndef GKI_MAX_EXCEPTION
+#define GKI_MAX_EXCEPTION 8
+#endif
+
+/* Maximum number of chars stored for each exception message. */
+#ifndef GKI_MAX_EXCEPTION_MSGLEN
+#define GKI_MAX_EXCEPTION_MSGLEN 64
+#endif
+
+#ifndef GKI_SEND_MSG_FROM_ISR
+#define GKI_SEND_MSG_FROM_ISR FALSE
+#endif
+
+
+/* The following is intended to be a reserved pool for SCO
+over HCI data and intentionally kept out of order */
+
+/* The ID of buffer pool 6. */
+#ifndef GKI_POOL_ID_6
+#define GKI_POOL_ID_6 6
+#endif
+
+/* The size of the buffers in pool 6,
+ BUF_SIZE = max SCO data 255 + sizeof(BT_HDR) = 8 + SCO packet header 3 + padding 2 = 268 */
+#ifndef GKI_BUF6_SIZE
+#define GKI_BUF6_SIZE 268
+#endif
+
+/* The number of buffers in buffer pool 6. */
+#ifndef GKI_BUF6_MAX
+#define GKI_BUF6_MAX 60
+#endif
+
+
+/* The following pool is a dedicated pool for HDP
+ If a shared pool is more desirable then
+ 1. set BTA_HL_LRG_DATA_POOL_ID to the desired Gki Pool ID
+ 2. make sure that the shared pool size is larger than 9472
+ 3. adjust GKI_NUM_FIXED_BUF_POOLS accordingly since
+ POOL ID 7 is not needed
+*/
+
+/* The ID of buffer pool 7. */
+#ifndef GKI_POOL_ID_7
+#define GKI_POOL_ID_7 7
+#endif
+
+/* The size of the buffers in pool 7 */
+#ifndef GKI_BUF7_SIZE
+#define GKI_BUF7_SIZE 9472
+#endif
+
+/* The number of buffers in buffer pool 7. */
+#ifndef GKI_BUF7_MAX
+#define GKI_BUF7_MAX 2
+#endif
+
+/* The following pool is a dedicated pool for GATT
+ If a shared pool is more desirable then
+ 1. set GATT_DB_POOL_ID to the desired Gki Pool ID
+ 2. make sure that the shared pool size fit a common GATT database needs
+ 3. adjust GKI_NUM_FIXED_BUF_POOLS accordingly since
+ POOL ID 8 is not needed
+*/
+
+/* The ID of buffer pool 8. */
+#ifndef GKI_POOL_ID_8
+#define GKI_POOL_ID_8 8
+#endif
+
+/* The size of the buffers in pool 8 */
+#ifndef GKI_BUF8_SIZE
+#define GKI_BUF8_SIZE 128
+#endif
+
+/* The number of buffers in buffer pool 8. */
+#ifndef GKI_BUF8_MAX
+#define GKI_BUF8_MAX 30
+#endif
+
+// btla-specific ++
+/* The following pool is a dedicated pool for HCIUTILS */
+#ifndef GKI_POOL_ID_9
+#define GKI_POOL_ID_9 9
+#endif
+
+#ifndef GKI_BUF9_SIZE
+#define GKI_BUF9_SIZE 256
+#endif
+
+#ifndef GKI_BUF9_MAX
+#define GKI_BUF9_MAX 250
+#endif
+// btla-specific --
+
+/* GKI Trace Macros */
+#define GKI_TRACE_0(m) LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI | TRACE_TYPE_GENERIC,m)
+#define GKI_TRACE_1(m,p1) LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI | TRACE_TYPE_GENERIC,m,p1)
+#define GKI_TRACE_2(m,p1,p2) LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI | TRACE_TYPE_GENERIC,m,p1,p2)
+#define GKI_TRACE_3(m,p1,p2,p3) LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI | TRACE_TYPE_GENERIC,m,p1,p2,p3)
+#define GKI_TRACE_4(m,p1,p2,p3,p4) LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI | TRACE_TYPE_GENERIC,m,p1,p2,p3,p4)
+#define GKI_TRACE_5(m,p1,p2,p3,p4,p5) LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI | TRACE_TYPE_GENERIC,m,p1,p2,p3,p4,p5)
+#define GKI_TRACE_6(m,p1,p2,p3,p4,p5,p6) LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI | TRACE_TYPE_GENERIC,m,p1,p2,p3,p4,p5,p6)
+
+#define GKI_TRACE_ERROR_0(m) LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI | TRACE_TYPE_ERROR,m)
+#define GKI_TRACE_ERROR_1(m,p1) LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI | TRACE_TYPE_ERROR,m,p1)
+#define GKI_TRACE_ERROR_2(m,p1,p2) LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI | TRACE_TYPE_ERROR,m,p1,p2)
+#define GKI_TRACE_ERROR_3(m,p1,p2,p3) LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI | TRACE_TYPE_ERROR,m,p1,p2,p3)
+#define GKI_TRACE_ERROR_4(m,p1,p2,p3,p4) LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI | TRACE_TYPE_ERROR,m,p1,p2,p3,p4)
+#define GKI_TRACE_ERROR_5(m,p1,p2,p3,p4,p5) LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI | TRACE_TYPE_ERROR,m,p1,p2,p3,p4,p5)
+#define GKI_TRACE_ERROR_6(m,p1,p2,p3,p4,p5,p6) LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI | TRACE_TYPE_ERROR,m,p1,p2,p3,p4,p5,p6)
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+EXPORT_API extern void LogMsg (UINT32 trace_set_mask, const char *fmt_str, ...);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GKI_TARGET_H */
diff --git a/main/Android.mk b/main/Android.mk
new file mode 100644
index 0000000..f30a24a
--- /dev/null
+++ b/main/Android.mk
@@ -0,0 +1,85 @@
+LOCAL_PATH:= $(call my-dir)
+
+#
+# Bluetooth HW module
+#
+
+include $(CLEAR_VARS)
+
+# HAL layer
+LOCAL_SRC_FILES:= \
+ ../btif/src/bluetooth.c\
+
+# platform specific
+LOCAL_SRC_FILES+= \
+ bte_main.c \
+ bte_init.c \
+ bte_version.c \
+ bte_logmsg.c\
+
+# BTIF
+LOCAL_SRC_FILES += \
+ ../btif/src/btif_core.c \
+ ../btif/src/btif_dm.c \
+ ../btif/src/btif_storage.c \
+ ../btif/src/btif_util.c \
+ ../btif/src/btif_hf.c \
+
+# callouts
+LOCAL_SRC_FILES+= \
+ ../btif/co/bta_sys_co.c \
+ ../btif/co/bta_fs_co.c \
+ ../btif/co/bta_ag_co.c \
+ ../btif/co/bta_dm_co.c \
+
+# candidates for vendor lib (keep here for now)
+LOCAL_SRC_FILES+= \
+ ../udrv/ulinux/unv_linux.c\
+
+
+LOCAL_C_INCLUDES+= . \
+ $(LOCAL_PATH)/../bta/include \
+ $(LOCAL_PATH)/../bta/sys \
+ $(LOCAL_PATH)/../bta/dm \
+ $(LOCAL_PATH)/../gki/common \
+ $(LOCAL_PATH)/../gki/ulinux \
+ $(LOCAL_PATH)/../include \
+ $(LOCAL_PATH)/../stack/include \
+ $(LOCAL_PATH)/../stack/l2cap \
+ $(LOCAL_PATH)/../stack/btm \
+ $(LOCAL_PATH)/../hcis \
+ $(LOCAL_PATH)/../hcis/include \
+ $(LOCAL_PATH)/../hcis/patchram \
+ $(LOCAL_PATH)/../udrv/include \
+ $(LOCAL_PATH)/../btif/include \
+ $(LOCAL_PATH)/../vendor/libvendor/include\
+
+LOCAL_CFLAGS += -DBUILDCFG -Werror
+
+ifeq ($(TARGET_PRODUCT), full_crespo)
+ LOCAL_CFLAGS += -DTARGET_CRESPO
+else
+ LOCAL_CFLAGS += -DTARGET_MAGURO
+endif
+
+# Fix this
+#ifeq ($(TARGET_VARIANT), eng)
+# LOCAL_CFLAGS += -O2 # and other production release flags
+#else
+# LOCAL_CFLAGS +=
+#endif
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libpower \
+ libbt-vendor
+
+#LOCAL_WHOLE_STATIC_LIBRARIES := libbt-brcm_gki libbt-brcm_stack libbt-brcm_bta
+LOCAL_STATIC_LIBRARIES := libbt-brcm_gki libbt-brcm_stack libbt-brcm_bta
+
+LOCAL_MODULE := bluetooth.default
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
+LOCAL_MODULE_TAGS := eng
+
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/main/bte_init.c b/main/bte_init.c
new file mode 100644
index 0000000..638f2be
--- /dev/null
+++ b/main/bte_init.c
@@ -0,0 +1,523 @@
+/*****************************************************************************
+** *
+** Name: bte_init.c *
+** *
+** Description: This module contains the routines that initialize the *
+** stack components. It must be called before the BTU task *
+** is started. *
+** *
+** Note: If using dynamic memory, the control bloacks for *
+** each component must already be allocated *
+** *
+** Copyright (c) 2000-2011, Broadcom Corp., All Rights Reserved. *
+** Broadcom Bluetooth Core. Proprietary and confidential. *
+******************************************************************************/
+
+#include "bt_target.h"
+#include <string.h>
+
+#ifndef BTA_INCLUDED
+#define BTA_INCLUDED FALSE
+#endif
+
+/* Include initialization functions definitions */
+#if (defined(RFCOMM_INCLUDED) && RFCOMM_INCLUDED == TRUE)
+#include "port_api.h"
+#endif
+
+#if (defined(TCS_INCLUDED) && TCS_INCLUDED == TRUE)
+#include "tcs_api.h"
+#endif
+
+#if (defined(OBX_INCLUDED) && OBX_INCLUDED == TRUE)
+#include "obx_api.h"
+#endif
+
+#if (defined(BNEP_INCLUDED) && BNEP_INCLUDED == TRUE)
+#include "bnep_api.h"
+#endif
+
+#if (defined(GAP_INCLUDED) && GAP_INCLUDED == TRUE)
+#include "gap_api.h"
+#endif
+
+#if ((defined(CTP_INCLUDED) && CTP_INCLUDED == TRUE))
+#include "ctp_api.h"
+#endif
+
+#if ((defined(ICP_INCLUDED) && ICP_INCLUDED == TRUE))
+#include "icp_api.h"
+#endif
+
+#if (defined(SPP_INCLUDED) && SPP_INCLUDED == TRUE)
+#include "spp_api.h"
+#endif
+
+#if (defined(DUN_INCLUDED) && DUN_INCLUDED == TRUE)
+#include "dun_api.h"
+#endif
+
+#if (defined(GOEP_INCLUDED) && GOEP_INCLUDED == TRUE)
+#include "goep_util.h"
+#endif /* GOEP included */
+
+#if (defined(FTP_INCLUDED) && FTP_INCLUDED == TRUE)
+#include "ftp_api.h"
+#endif /* FTP */
+
+#if (defined(OPP_INCLUDED) && OPP_INCLUDED == TRUE)
+#include "opp_api.h"
+#endif /* OPP */
+
+#if (defined(BIP_INCLUDED) && BIP_INCLUDED == TRUE)
+#include "bip_api.h"
+#endif
+
+#if (defined(BTU_BTA_INCLUDED) && BTU_BTA_INCLUDED == TRUE)
+#if (defined(BTA_BI_INCLUDED) && BTA_BI_INCLUDED == TRUE)
+#include "bta_bi_api.h"
+#endif
+#endif
+
+#if (defined(HFP_INCLUDED) && HFP_INCLUDED == TRUE)
+#include "hfp_api.h"
+#endif
+
+#if ((defined(HSP2_INCLUDED) && HSP2_INCLUDED == TRUE)) || \
+ ((defined(HFP_INCLUDED) && HFP_INCLUDED == TRUE))
+#include "hsp2_api.h"
+#endif
+
+#if (defined(HCRP_INCLUDED) && HCRP_INCLUDED == TRUE)
+#if (defined(HCRP_CLIENT_INCLUDED) && HCRP_CLIENT_INCLUDED == TRUE)
+#include "hcrp_api.h"
+#endif
+#if (defined(HCRP_SERVER_INCLUDED) && HCRP_SERVER_INCLUDED == TRUE)
+#include "hcrpm_api.h"
+#endif
+#endif
+
+#if (defined(BPP_INCLUDED) && BPP_INCLUDED == TRUE)
+#include "bpp_api.h"
+#endif
+
+#if (defined(PAN_INCLUDED) && PAN_INCLUDED == TRUE)
+#include "pan_api.h"
+#endif
+
+#if (defined(AVRC_INCLUDED) && AVRC_INCLUDED == TRUE)
+#include "avrc_api.h"
+#endif
+
+#if (defined(A2D_INCLUDED) && A2D_INCLUDED == TRUE)
+#include "a2d_api.h"
+#endif
+
+#if (defined(VDP_INCLUDED) && VDP_INCLUDED == TRUE)
+#include "vdp_api.h"
+#endif
+
+#if (defined(HID_DEV_INCLUDED) && HID_DEV_INCLUDED == TRUE)
+#include "hidd_api.h"
+#endif
+
+#if (defined(HID_HOST_INCLUDED) && HID_HOST_INCLUDED == TRUE)
+#include "hidh_api.h"
+#endif
+
+#if (defined(SAP_SERVER_INCLUDED) && SAP_SERVER_INCLUDED == TRUE)
+#include "sap_api.h"
+#endif /* SAP_SERVER_INCLUDED */
+
+#if (defined(MCA_INCLUDED) && MCA_INCLUDED == TRUE)
+#include "mca_api.h"
+#endif
+
+#if (defined(BLE_INCLUDED) && BLE_INCLUDED == TRUE)
+#include "gatt_api.h"
+#if (defined(SMP_INCLUDED) && SMP_INCLUDED == TRUE)
+#include "smp_api.h"
+#endif
+#endif
+
+// btla-specific ++
+/***** BTA Modules ******/
+#if BTA_INCLUDED == TRUE && BTA_DYNAMIC_MEMORY == TRUE
+#include "bta_api.h"
+#include "bta_sys.h"
+
+#if BTA_AC_INCLUDED == TRUE
+#include "bta_acs_int.h"
+#include "bta_acc_int.h"
+#endif
+
+#if BTA_AG_INCLUDED == TRUE
+#include "bta_ag_int.h"
+#endif
+
+#if BTA_HS_INCLUDED == TRUE
+#include "bta_hs_int.h"
+#endif
+
+#include "bta_dm_int.h"
+
+#if BTA_DG_INCLUDED == TRUE
+#include "bta_dg_api.h"
+#include "bta_dg_int.h"
+#endif
+
+#if BTA_FT_INCLUDED == TRUE
+#include "bta_ftc_int.h"
+#include "bta_fts_int.h"
+#endif
+
+#if BTA_PBC_INCLUDED == TRUE
+#include "bta_pbc_int.h"
+#endif
+
+#if BTA_PBS_INCLUDED == TRUE
+#include "bta_pbs_int.h"
+#endif
+
+#if BTA_OP_INCLUDED == TRUE
+#include "bta_opc_int.h"
+#include "bta_ops_int.h"
+#endif
+
+#if BTA_SS_INCLUDED==TRUE
+#include "bta_ss_int.h"
+#endif
+
+#if BTA_CT_INCLUDED==TRUE
+#include "bta_ct_int.h"
+#endif
+
+#if BTA_CG_INCLUDED==TRUE
+#include "bta_cg_int.h"
+#endif
+
+#if BTA_BI_INCLUDED==TRUE
+#include "bta_bic_int.h"
+#include "bta_bis_int.h"
+#endif
+
+#if BTA_PR_INCLUDED==TRUE
+#include "bta_pr_int.h"
+#endif
+
+#if BTA_AR_INCLUDED==TRUE
+#include "bta_ar_int.h"
+#endif
+#if BTA_AV_INCLUDED==TRUE
+#include "bta_av_int.h"
+#endif
+#if BTA_AVK_INCLUDED==TRUE
+#include "bta_avk_int.h"
+#endif
+
+#if BTA_SC_INCLUDED==TRUE
+#include "bta_sc_int.h"
+#endif
+
+#if BTA_HD_INCLUDED==TRUE
+#include "bta_hd_int.h"
+#endif
+
+#if BTA_HH_INCLUDED==TRUE
+#include "bta_hh_int.h"
+#endif
+
+#if BTA_FM_INCLUDED==TRUE
+#include "bta_fm_int.h"
+#endif
+
+#if BTA_FMTX_INCLUDED==TRUE
+#include "bta_fmtx_int.h"
+#endif
+
+#if BTA_JV_INCLUDED==TRUE
+#include "bta_jv_int.h"
+tBTA_JV_CB *bta_jv_cb_ptr = NULL;
+#endif
+
+#if BTA_MCE_INCLUDED == TRUE
+#include "bta_mce_int.h"
+#endif
+
+#if BTA_MSE_INCLUDED == TRUE
+#include "bta_mse_int.h"
+#endif
+
+#if BTA_HL_INCLUDED == TRUE
+#include "bta_hl_int.h"
+#endif
+
+#if BTA_GATT_INCLUDED == TRUE
+#include "bta_gattc_int.h"
+#include "bta_gatts_int.h"
+#endif
+
+#if BTA_PAN_INCLUDED==TRUE
+#include "bta_pan_int.h"
+#endif
+
+#include "bta_sys_int.h"
+
+/* control block for patch ram downloading */
+#include "bta_prm_int.h"
+
+#endif /* BTA_INCLUDED */
+// btla-specific --
+
+/*****************************************************************************
+** F U N C T I O N S *
+******************************************************************************/
+
+/*****************************************************************************
+**
+** Function BTE_InitStack
+**
+** Description Initialize control block memory for each component.
+**
+** Note: The core stack components must be called
+** before creating the BTU Task. The rest of the
+** components can be initialized at a later time if desired
+** as long as the component's init function is called
+** before accessing any of its functions.
+**
+** Returns void
+**
+******************************************************************************/
+BT_API void BTE_InitStack(void)
+{
+/* Initialize the optional stack components */
+
+/****************************
+** RFCOMM and its profiles **
+*****************************/
+#if (defined(RFCOMM_INCLUDED) && RFCOMM_INCLUDED == TRUE)
+ RFCOMM_Init();
+
+#if (defined(SPP_INCLUDED) && SPP_INCLUDED == TRUE)
+ SPP_Init();
+#endif /* SPP */
+
+#if (defined(DUN_INCLUDED) && DUN_INCLUDED == TRUE)
+ DUN_Init();
+#endif /* DUN */
+
+#if (defined(HSP2_INCLUDED) && HSP2_INCLUDED == TRUE)
+ HSP2_Init();
+#endif /* HSP2 */
+
+#if (defined(HFP_INCLUDED) && HFP_INCLUDED == TRUE)
+ HFP_Init();
+#endif /* HFP */
+
+/**************************
+** OBEX and its profiles **
+***************************/
+#if (defined(OBX_INCLUDED) && OBX_INCLUDED == TRUE)
+ OBX_Init();
+#if (defined(BIP_INCLUDED) && BIP_INCLUDED == TRUE)
+ BIP_Init();
+#if (defined(BTU_BTA_INCLUDED) && BTU_BTA_INCLUDED == TRUE)
+#if (defined(BTA_BI_INCLUDED) && BTA_BI_INCLUDED == TRUE)
+ BTA_BicInit();
+#endif /* BTA BI */
+#endif
+#endif /* BIP */
+
+#if (defined(GOEP_INCLUDED) && GOEP_INCLUDED == TRUE)
+ GOEP_Init();
+#endif /* GOEP */
+
+
+#if (defined(FTP_INCLUDED) && FTP_INCLUDED == TRUE)
+ FTP_Init();
+#endif
+#if (defined(OPP_INCLUDED) && OPP_INCLUDED == TRUE)
+ OPP_Init();
+#endif
+
+#if (defined(BPP_INCLUDED) && BPP_INCLUDED == TRUE)
+ BPP_Init();
+#endif /* BPP */
+#endif /* OBX */
+
+
+#endif /* RFCOMM Included */
+
+/*************************
+** TCS and its profiles **
+**************************/
+#if (defined(TCS_INCLUDED) && TCS_INCLUDED == TRUE)
+ TCS_Init();
+
+#if (defined(CTP_INCLUDED) && CTP_INCLUDED == TRUE)
+ CTP_Init();
+#endif /* CTP_INCLUDED */
+
+#if (defined(ICP_INCLUDED) && ICP_INCLUDED == TRUE)
+ ICP_Init();
+#endif /* ICP_INCLUDED */
+
+#endif /* TCS_INCLUDED */
+
+
+/**************************
+** BNEP and its profiles **
+***************************/
+#if (defined(BNEP_INCLUDED) && BNEP_INCLUDED == TRUE)
+ BNEP_Init();
+
+#if (defined(PAN_INCLUDED) && PAN_INCLUDED == TRUE)
+ PAN_Init();
+#endif /* PAN */
+#endif /* BNEP Included */
+
+
+/**************************
+** AVDT and its profiles **
+***************************/
+#if (defined(A2D_INCLUDED) && A2D_INCLUDED == TRUE)
+ A2D_Init();
+#endif /* AADP */
+
+#if (defined(VDP_INCLUDED) && VDP_INCLUDED == TRUE)
+ VDP_Init();
+#endif
+
+#if (defined(AVRC_INCLUDED) && AVRC_INCLUDED == TRUE)
+ AVRC_Init();
+#endif
+
+
+/***********
+** Others **
+************/
+#if (defined(GAP_INCLUDED) && GAP_INCLUDED == TRUE)
+ GAP_Init();
+#endif /* GAP Included */
+
+#if (defined(HCRP_INCLUDED) && HCRP_INCLUDED == TRUE)
+#if (defined(HCRP_CLIENT_INCLUDED) && HCRP_CLIENT_INCLUDED == TRUE)
+ HCRP_Init();
+#endif
+#if (defined(HCRP_SERVER_INCLUDED) && HCRP_SERVER_INCLUDED == TRUE)
+ HCRPM_Init();
+#endif
+#endif /* HCRP Included */
+
+#if (defined(SAP_SERVER_INCLUDED) && SAP_SERVER_INCLUDED == TRUE)
+ SAP_Init();
+#endif /* SAP_SERVER_INCLUDED */
+
+#if (defined(HID_DEV_INCLUDED) && HID_DEV_INCLUDED == TRUE)
+ HID_DevInit();
+#endif
+#if (defined(HID_HOST_INCLUDED) && HID_HOST_INCLUDED == TRUE)
+ HID_HostInit();
+#endif
+
+#if (defined(MCA_INCLUDED) && MCA_INCLUDED == TRUE)
+ MCA_Init();
+#endif /* SAP_SERVER_INCLUDED */
+
+/****************
+** BTA Modules **
+*****************/
+// btla-specific ++
+#if (BTA_INCLUDED == TRUE && BTA_DYNAMIC_MEMORY == TRUE)
+ memset((void*)bta_sys_cb_ptr, 0, sizeof(tBTA_SYS_CB));
+ memset((void*)bta_dm_cb_ptr, 0, sizeof(tBTA_DM_CB));
+ memset((void*)bta_dm_search_cb_ptr, 0, sizeof(tBTA_DM_SEARCH_CB));
+ memset((void*)bta_dm_di_cb_ptr, 0, sizeof(tBTA_DM_DI_CB));
+ memset((void*)bta_prm_cb_ptr, 0, sizeof(tBTA_PRM_CB));
+
+#if BTA_AC_INCLUDED == TRUE
+ memset((void*)bta_acc_cb_ptr, 0, sizeof(tBTA_ACC_CB));
+ memset((void*)bta_acs_cb_ptr, 0, sizeof(tBTA_ACS_CB));
+#endif
+#if BTA_AG_INCLUDED == TRUE
+ memset((void*)bta_ag_cb_ptr, 0, sizeof(tBTA_AG_CB));
+#endif
+#if BTA_HS_INCLUDED == TRUE
+ memset((void*)bta_hs_cb_ptr, 0, sizeof(tBTA_HS_CB));
+#endif
+#if BTA_DG_INCLUDED == TRUE
+ memset((void*)bta_dg_cb_ptr, 0, sizeof(tBTA_DG_CB));
+#endif
+#if BTA_FT_INCLUDED==TRUE
+ memset((void*)bta_ftc_cb_ptr, 0, sizeof(tBTA_FTC_CB));
+ memset((void*)bta_fts_cb_ptr, 0, sizeof(tBTA_FTS_CB));
+#endif
+#if BTA_PBC_INCLUDED==TRUE
+ memset((void*)bta_pbc_cb_ptr, 0, sizeof(tBTA_PBC_CB));
+#endif
+#if BTA_PBS_INCLUDED==TRUE
+ memset((void*)bta_pbs_cb_ptr, 0, sizeof(tBTA_PBS_CB));
+#endif
+#if BTA_OP_INCLUDED==TRUE
+ memset((void*)bta_opc_cb_ptr, 0, sizeof(tBTA_OPC_CB));
+ memset((void*)bta_ops_cb_ptr, 0, sizeof(tBTA_OPS_CB));
+#endif
+#if BTA_SS_INCLUDED==TRUE
+ memset((void*)bta_ss_cb_ptr, 0, sizeof(tBTA_SS_CB));
+#endif
+#if BTA_CT_INCLUDED==TRUE
+ memset((void*)bta_ct_cb_ptr, 0, sizeof(tBTA_CT_CB));
+#endif
+#if BTA_CG_INCLUDED==TRUE
+ memset((void*)bta_cg_cb_ptr, 0, sizeof(tBTA_CG_CB));
+#endif
+#if BTA_BI_INCLUDED==TRUE
+ memset((void *)bta_bic_cb_ptr, 0, sizeof(tBTA_BIC_CB));
+ memset((void *)bta_bis_cb_ptr, 0, sizeof(tBTA_BIS_CB));
+#endif
+#if BTA_AR_INCLUDED==TRUE
+ memset((void *)bta_ar_cb_ptr, 0, sizeof(tBTA_AR_CB));
+#endif
+#if BTA_AV_INCLUDED==TRUE
+ memset((void *)bta_av_cb_ptr, 0, sizeof(tBTA_AV_CB));
+#endif
+#if BTA_AVK_INCLUDED==TRUE
+ memset((void *)bta_avk_cb_ptr, 0, sizeof(tBTA_AVK_CB));
+#endif
+#if BTA_PR_INCLUDED==TRUE
+ memset((void *)bta_pr_cb_ptr, 0, sizeof(tBTA_PR_CB));
+#endif
+#if BTA_SC_INCLUDED==TRUE
+ memset((void *)bta_sc_cb_ptr, 0, sizeof(tBTA_SC_CB));
+#endif
+#if BTA_HD_INCLUDED==TRUE
+ memset((void *)bta_hd_cb_ptr, 0, sizeof(tBTA_HD_CB));
+#endif
+#if BTA_HH_INCLUDED==TRUE
+ memset((void *)bta_hh_cb_ptr, 0, sizeof(tBTA_HH_CB));
+#endif
+#if BTA_FM_INCLUDED==TRUE
+ memset((void *)bta_fm_cb_ptr, 0, sizeof(tBTA_FM_CB));
+#endif
+#if BTA_FMTX_INCLUDED==TRUE
+ memset((void *)bta_fmtx_cb_ptr, 0, sizeof(tBTA_FMTX_CB));
+#endif
+#if 0
+#if BTA_JV_INCLUDED==TRUE
+ memset((void *)bta_jv_cb_ptr, 0, sizeof(tBTA_JV_CB));
+#endif
+#endif
+#if BTA_HL_INCLUDED==TRUE
+ memset((void *)bta_hl_cb_ptr, 0, sizeof(tBTA_HL_CB));
+#endif
+#if BTA_GATT_INCLUDED==TRUE
+ memset((void *)bta_gattc_cb_ptr, 0, sizeof(tBTA_GATTC_CB));
+ memset((void *)bta_gatts_cb_ptr, 0, sizeof(tBTA_GATTS_CB));
+#endif
+#if BTA_PAN_INCLUDED==TRUE
+ memset((void *)bta_pan_cb_ptr, 0, sizeof(tBTA_PAN_CB));
+#endif
+
+#endif /* BTA_INCLUDED == TRUE */
+// btla-specific --
+}
diff --git a/main/bte_logmsg.c b/main/bte_logmsg.c
new file mode 100644
index 0000000..494c1a6
--- /dev/null
+++ b/main/bte_logmsg.c
@@ -0,0 +1,589 @@
+/*****************************************************************************
+**
+** Name: bte_logmsg.c
+**
+** Description: Contains the LogMsg wrapper routines for BTE. It routes calls
+** the appropriate application's LogMsg equivalent.
+**
+** Copyright (c) 2001-2011, WIDCOMM Inc., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include "gki.h"
+#include "bte.h"
+
+#include "bte_appl.h"
+
+#if MMI_INCLUDED == TRUE
+#include "mmi.h"
+#endif
+
+/* always enable trace framework */
+
+#include "btu.h"
+#include "l2c_api.h"
+#if (RFCOMM_INCLUDED==TRUE)
+#include "port_api.h"
+#endif
+#if (OBX_INCLUDED==TRUE)
+#include "obx_api.h"
+#endif
+#if (AVCT_INCLUDED==TRUE)
+#include "avct_api.h"
+#endif
+#if (AVDT_INCLUDED==TRUE)
+#include "avdt_api.h"
+#endif
+#if (AVRC_INCLUDED==TRUE)
+#include "avrc_api.h"
+#endif
+#if (AVDT_INCLUDED==TRUE)
+#include "avdt_api.h"
+#endif
+#if (A2D_INCLUDED==TRUE)
+#include "a2d_api.h"
+#endif
+#if (BIP_INCLUDED==TRUE)
+#include "bip_api.h"
+#endif
+#if (BNEP_INCLUDED==TRUE)
+#include "bnep_api.h"
+#endif
+#if (BPP_INCLUDED==TRUE)
+#include "bpp_api.h"
+#endif
+#include "btm_api.h"
+#if (DUN_INCLUDED==TRUE)
+#include "dun_api.h"
+#endif
+#if (GAP_INCLUDED==TRUE)
+#include "gap_api.h"
+#endif
+#if (GOEP_INCLUDED==TRUE)
+#include "goep_util.h"
+#endif
+#if (HCRP_INCLUDED==TRUE)
+#include "hcrp_api.h"
+#endif
+#if (PAN_INCLUDED==TRUE)
+#include "pan_api.h"
+#endif
+#include "sdp_api.h"
+#if (VDP_INCLUDED==TRUE)
+#include "vdp_api.h"
+#endif
+
+#if (BLE_INCLUDED==TRUE)
+#include "gatt_api.h"
+#endif
+
+ /* LayerIDs for BTA, currently everything maps onto appl_trace_level */
+#if (BTA_INCLUDED==TRUE)
+#include "bta_api.h"
+#endif
+
+
+#if defined(__CYGWIN__) || defined(__linux__)
+#undef RPC_INCLUDED
+#define RPC_INCLUDED TRUE
+
+#include <sys/time.h>
+#include <time.h>
+
+#if (defined(ANDROID_USE_LOGCAT) && (ANDROID_USE_LOGCAT==TRUE))
+#define LOG_TAG "BTLD"
+
+#ifndef LINUX_NATIVE
+#include <cutils/log.h>
+#define LOGI0(s) __android_log_write(ANDROID_LOG_INFO, NULL, s)
+#define LOGD0(s) __android_log_write(ANDROID_LOG_DEBUG, NULL, s)
+#define LOGW0(s) __android_log_write(ANDROID_LOG_WARN, NULL, s)
+#define LOGE0(s) __android_log_write(ANDROID_LOG_ERROR, NULL, s)
+
+#else
+#undef ANDROID_USE_LOGCAT
+#endif
+
+#endif
+
+
+//#include "btl_cfg.h"
+#define BTL_GLOBAL_PROP_TRC_FLAG "TRC_BTAPP"
+
+
+#ifndef BTE_LOG_BUF_SIZE
+#define BTE_LOG_BUF_SIZE 1024
+#endif
+#define BTE_LOG_MAX_SIZE (BTE_LOG_BUF_SIZE - 12)
+
+
+//#define BTE_MAP_TRACE_LEVEL FALSE
+/* map by default BTE trace levels onto android trace levels */
+#ifndef BTE_MAP_TRACE_LEVEL
+#define BTE_MAP_TRACE_LEVEL TRUE
+#endif
+
+// #define BTE_ANDROID_INTERNAL_TIMESTAMP TRUE
+/* by default no internal timestamp. adb logcate -v time allows having timestamps */
+#ifndef BTE_ANDROID_INTERNAL_TIMESTAMP
+#define BTE_ANDROID_INTERNAL_TIMESTAMP FALSE
+#endif
+#if (BTE_ANDROID_INTERNAL_TIMESTAMP==TRUE)
+#define MSG_BUFFER_OFFSET strlen(buffer)
+#else
+#define MSG_BUFFER_OFFSET 0
+#endif
+
+//#define DBG_TRACE
+
+#if defined( DBG_TRACE )
+#define DBG_TRACE_API0( m ) BT_TRACE_0( TRACE_LAYER_HCI, TRACE_TYPE_API, m )
+#define DBG_TRACE_WARNING2( m, p0, p1 ) BT_TRACE_2( TRACE_LAYER_BTM, (TRACE_ORG_APPL|TRACE_TYPE_WARNING), m, p0, p1 )
+#else
+#define DBG_TRACE_API0( m )
+#define DBG_TRACE_WARNING2( m, p0, p1 )
+#endif
+#define DBG_TRACE_DEBUG2( m, p0, p1 ) BT_TRACE_2( TRACE_LAYER_BTM, (TRACE_ORG_APPL|TRACE_TYPE_DEBUG), m, p0, p1 )
+
+void
+LogMsg(UINT32 trace_set_mask, const char *fmt_str, ...)
+{
+ static char buffer[BTE_LOG_BUF_SIZE];
+
+ va_list ap;
+#if (BTE_ANDROID_INTERNAL_TIMESTAMP==TRUE)
+ struct timeval tv;
+ struct timezone tz;
+ struct tm *tm;
+ time_t t;
+
+ gettimeofday(&tv, &tz);
+ time(&t);
+ tm = localtime(&t);
+
+ sprintf(buffer, "%02d:%02d:%02d.%03d ", tm->tm_hour, tm->tm_min, tm->tm_sec,
+ tv.tv_usec / 1000);
+#endif
+ va_start(ap, fmt_str);
+ vsnprintf(&buffer[MSG_BUFFER_OFFSET], BTE_LOG_MAX_SIZE, fmt_str, ap);
+ va_end(ap);
+
+#if (defined(ANDROID_USE_LOGCAT) && (ANDROID_USE_LOGCAT==TRUE))
+#if (BTE_MAP_TRACE_LEVEL==TRUE)
+ switch ( TRACE_GET_TYPE(trace_set_mask) )
+ {
+ case TRACE_TYPE_ERROR:
+ LOGE0(buffer);
+ break;
+ case TRACE_TYPE_WARNING:
+ LOGW0(buffer);
+ break;
+ case TRACE_TYPE_API:
+ case TRACE_TYPE_EVENT:
+ LOGI0(buffer);
+ break;
+ case TRACE_TYPE_DEBUG:
+ LOGD0(buffer);
+ break;
+ default:
+ LOGE0(buffer); /* we should never get this */
+ break;
+ }
+#else
+ LOGI0(buffer);
+#endif
+#else
+ write(2, buffer, strlen(buffer));
+ write(2, "\n", 1);
+#endif
+}
+
+void
+ScrLog(UINT32 trace_set_mask, const char *fmt_str, ...)
+{
+ static char buffer[BTE_LOG_BUF_SIZE];
+
+ va_list ap;
+ struct timeval tv;
+ struct timezone tz;
+ struct tm *tm;
+ time_t t;
+
+ gettimeofday(&tv, &tz);
+ time(&t);
+ tm = localtime(&t);
+
+ sprintf(buffer, "%02d:%02d:%02d.%03ld ", tm->tm_hour, tm->tm_min, tm->tm_sec,
+ tv.tv_usec / 1000);
+
+ va_start(ap, fmt_str);
+ vsnprintf(&buffer[strlen(buffer)], BTE_LOG_MAX_SIZE, fmt_str, ap);
+ va_end(ap);
+
+#if (defined(ANDROID_USE_LOGCAT) && (ANDROID_USE_LOGCAT==TRUE))
+ LOGI0(buffer);
+#else
+ write(2, buffer, strlen(buffer));
+ write(2, "\n", 1);
+#endif
+}
+
+/* this function should go into BTAPP_DM for example */
+BT_API UINT8 BTAPP_SetTraceLevel( UINT8 new_level )
+{
+ if (new_level != 0xFF)
+ appl_trace_level = new_level;
+
+ return (appl_trace_level);
+}
+
+BTU_API UINT8 BTU_SetTraceLevel( UINT8 new_level )
+{
+ if (new_level != 0xFF)
+ btu_cb.trace_level = new_level;
+
+ return (btu_cb.trace_level);
+}
+
+
+
+
+/********************************************************************************
+ **
+ ** Function Name: BTA_SysSetTraceLevel
+ **
+ ** Purpose: set or reads the different Trace Levels of layer IDs (see bt_trace.h,
+ ** BTTRC_ID_xxxx
+ **
+ ** Input Parameters: Array with trace layers to set to a given level or read. a layer ID of 0
+ ** defines the end of the list
+ ** WARNING: currently type should be 0-5! or FF for reading!!!!
+ **
+ ** Returns:
+ ** input array with trace levels for given layer id
+ **
+ *********************************************************************************/
+BT_API tBTTRC_LEVEL * BTA_SysSetTraceLevel(tBTTRC_LEVEL * p_levels)
+{
+ const tBTTRC_FUNC_MAP *p_f_map;
+ tBTTRC_LEVEL *p_l = p_levels;
+
+ DBG_TRACE_API0( "BTA_SysSetTraceLevel()" );
+
+ while (0 != p_l->layer_id)
+ {
+ p_f_map = &bttrc_set_level_map[0];
+
+ while (0 != p_f_map->layer_id_start)
+ {
+ printf("BTA_SysSetTraceLevel - trace id in map start = %d end= %d, paramter id = %d\r\n", p_f_map->layer_id_start, p_f_map->layer_id_end, p_l->layer_id );
+ /* as p_f_map is ordered by increasing layer id, go to next map entry as long end id
+ * is smaller */
+ //if (p_f_map->layer_id_end < p_l->layer_id)
+ //{
+ //p_f_map++;
+ //}
+ //else
+ {
+ /* check if layer_id actually false into a range or if it is note existing in the map */
+ if ((NULL != p_f_map->p_f) && (p_f_map->layer_id_start <= p_l->layer_id) && (p_f_map->layer_id_end >= p_l->layer_id) )
+ {
+ DBG_TRACE_DEBUG2( "BTA_SysSetTraceLevel( id:%d, level:%d ): setting/reading",
+ p_l->layer_id, p_l->type );
+ p_l->type = p_f_map->p_f(p_l->type);
+ break;
+ }
+ else
+ {
+ DBG_TRACE_WARNING2( "BTA_SysSetTraceLevel( id:%d, level:%d ): MISSING Set function OR ID in map!",
+ p_l->layer_id, p_l->type );
+ }
+ /* set/read next trace level by getting out ot map loop */
+ //p_l++;
+ //break;
+ }
+ p_f_map++;
+ }
+ //if (0 == p_f_map->layer_id_start)
+ {
+ DBG_TRACE_WARNING2( "BTA_SysSetTraceLevel( id:%d, level:%d ): ID NOT FOUND in map. Skip to next",
+ p_l->layer_id, p_l->type );
+ p_l++;
+ }
+ }
+
+ return p_levels;
+} /* BTA_SysSetTraceLevel() */
+
+/* make sure list is order by increasing layer id!!! */
+const tBTTRC_FUNC_MAP bttrc_set_level_map[] = {
+ { BTTRC_ID_STK_BTU, BTTRC_ID_STK_HCI, (const tBTTRC_SET_TRACE_LEVEL *)BTU_SetTraceLevel, "TRC_HCI" },
+ { BTTRC_ID_STK_L2CAP, BTTRC_ID_STK_L2CAP, (const tBTTRC_SET_TRACE_LEVEL *)L2CA_SetTraceLevel, "TRC_L2CAP" },
+#if (RFCOMM_INCLUDED==TRUE)
+ { BTTRC_ID_STK_RFCOMM, BTTRC_ID_STK_RFCOMM_DATA, (const tBTTRC_SET_TRACE_LEVEL *)PORT_SetTraceLevel, "TRC_RFCOMM" },
+#endif
+#if (OBX_INCLUDED==TRUE)
+ { BTTRC_ID_STK_OBEX, BTTRC_ID_STK_OBEX, (const tBTTRC_SET_TRACE_LEVEL *)OBX_SetTraceLevel, "TRC_OBEX" },
+#endif
+#if (AVCT_INCLUDED==TRUE)
+ { BTTRC_ID_STK_AVCT, BTTRC_ID_STK_AVCT, (tBTTRC_SET_TRACE_LEVEL *)NULL, "TRC_AVCT" },
+#endif
+#if (AVDT_INCLUDED==TRUE)
+ { BTTRC_ID_STK_AVDT, BTTRC_ID_STK_AVDT, (const tBTTRC_SET_TRACE_LEVEL *)AVDT_SetTraceLevel, "TRC_AVDT" },
+#endif
+#if (AVRC_INCLUDED==TRUE)
+ { BTTRC_ID_STK_AVRC, BTTRC_ID_STK_AVRC, (const tBTTRC_SET_TRACE_LEVEL *)AVRC_SetTraceLevel, "TRC_AVRC" },
+#endif
+#if (AVDT_INCLUDED==TRUE)
+ { BTTRC_ID_AVDT_SCB, BTTRC_ID_AVDT_CCB, (tBTTRC_SET_TRACE_LEVEL *)NULL, "TRC_AVDT_SCB" },
+#endif
+#if (A2D_INCLUDED==TRUE)
+ { BTTRC_ID_STK_A2D, BTTRC_ID_STK_A2D, (const tBTTRC_SET_TRACE_LEVEL *)A2D_SetTraceLevel, "TRC_A2D" },
+#endif
+#if (BIP_INCLUDED==TRUE)
+ { BTTRC_ID_STK_BIP, BTTRC_ID_STK_BIP, (const tBTTRC_SET_TRACE_LEVEL *)BIP_SetTraceLevel, "TRC_BIP" },
+#endif
+#if (BNEP_INCLUDED==TRUE)
+ { BTTRC_ID_STK_BNEP, BTTRC_ID_STK_BNEP, (const tBTTRC_SET_TRACE_LEVEL *)BNEP_SetTraceLevel, "TRC_BNEP" },
+#endif
+#if (BPP_INCLUDED==TRUE)
+ { BTTRC_ID_STK_BPP, BTTRC_ID_STK_BPP, (const tBTTRC_SET_TRACE_LEVEL *)BPP_SetTraceLevel, "TRC_BPP" },
+#endif
+ { BTTRC_ID_STK_BTM_ACL, BTTRC_ID_STK_BTM_SEC, (const tBTTRC_SET_TRACE_LEVEL *)BTM_SetTraceLevel, "TRC_BTM" },
+#if (DUN_INCLUDED==TRUE)
+ { BTTRC_ID_STK_DUN, BTTRC_ID_STK_DUN, (const tBTTRC_SET_TRACE_LEVEL *)DUN_SetTraceLevel, "TRC_DUN" },
+#endif
+#if (GAP_INCLUDED==TRUE)
+ { BTTRC_ID_STK_GAP, BTTRC_ID_STK_GAP, (const tBTTRC_SET_TRACE_LEVEL *)GAP_SetTraceLevel, "TRC_GAP" },
+#endif
+#if (GOEP_INCLUDED==TRUE)
+ { BTTRC_ID_STK_GOEP, BTTRC_ID_STK_GOEP, (const tBTTRC_SET_TRACE_LEVEL *)GOEP_SetTraceLevel, "TRC_GOEP" },
+#endif
+#if (HCRP_INCLUDED==TRUE)
+ { BTTRC_ID_STK_HCRP, BTTRC_ID_STK_HCRP, (const tBTTRC_SET_TRACE_LEVEL *)HCRP_SetTraceLevel, "TRC_HCRP" },
+#endif
+#if (PAN_INCLUDED==TRUE)
+ { BTTRC_ID_STK_PAN, BTTRC_ID_STK_PAN, (const tBTTRC_SET_TRACE_LEVEL *)PAN_SetTraceLevel, "TRC_PAN" },
+#endif
+#if (SAP_SERVER_INCLUDED==TRUE)
+ { BTTRC_ID_STK_SAP, BTTRC_ID_STK_SAP, (tBTTRC_SET_TRACE_LEVEL *)NULL, "TRC_SAP" },
+#endif
+ { BTTRC_ID_STK_SDP, BTTRC_ID_STK_SDP, (const tBTTRC_SET_TRACE_LEVEL *)SDP_SetTraceLevel, "TRC_SDP" },
+#if (VDP_INCLUDED==TRUE)
+ { BTTRC_ID_STK_VDP, BTTRC_ID_STK_VDP, (const tBTTRC_SET_TRACE_LEVEL *)VDP_SetTraceLevel, "TRC_VDP" },
+#endif
+#if (BLE_INCLUDED==TRUE)
+ { BTTRC_ID_STK_GATT, BTTRC_ID_STK_GATT, (const tBTTRC_SET_TRACE_LEVEL *)GATT_SetTraceLevel , "TRC_GATT" },
+#endif
+#if (BLE_INCLUDED==TRUE)
+ { BTTRC_ID_STK_SMP, BTTRC_ID_STK_SMP, (const tBTTRC_SET_TRACE_LEVEL *)SMP_SetTraceLevel , "TRC_SMP" },
+#endif
+
+ /* LayerIDs for BTA, currently everything maps onto appl_trace_level. BTL_GLOBAL_PROP_TRC_FLAG
+ * serves as flag in property. if present, the whole table is scanned. */
+#if (BTA_INCLUDED==TRUE)
+ { BTTRC_ID_BTA_ACC, BTTRC_ID_BTAPP, (const tBTTRC_SET_TRACE_LEVEL *)BTAPP_SetTraceLevel, BTL_GLOBAL_PROP_TRC_FLAG },
+#endif
+
+#if 0
+ {BTTRC_ID_BTA_HF 39 /* headset/handsfree AG & HF */
+ {BTTRC_ID_BTA_AV 40 /* Advanced audio */
+ {BTTRC_ID_BTA_BIP 41 /* Basic Imaging Client */
+ {BTTRC_ID_BTA_BP 42 /* Basic Printing Client */
+ {BTTRC_ID_BTA_CTP 43 /* cordless telephony profile */
+ {BTTRC_ID_BTA_DG 44 /* data gateway */
+ {BTTRC_ID_BTA_DM 45 /* device manager */
+ {BTTRC_ID_BTA_FM 46
+ {BTTRC_ID_BTA_FS 47 /* File System */
+ {BTTRC_ID_BTA_FTP 48 /* file transfer client & server */
+ {BTTRC_ID_BTA_HID 49 /* hidc & hidd */
+ {BTTRC_ID_BTA_JV 50 /* java connector */
+ {BTTRC_ID_BTA_OPP 51 /* object push client */
+ {BTTRC_ID_BTA_PAN 52 /* Personal Area Networking */
+ {BTTRC_ID_BTA_PR 53 /* Printer module */
+ {BTTRC_ID_BTA_SC 54 /* SIM Card Access module */
+ {BTTRC_ID_BTA_SS 55 /* synchronization module */
+ {BTTRC_ID_BTA_SYS 56 /* system manager */
+ {BTTRC_ID_BTA_SSR 57 /* GPS sensor */
+ {BTTRC_ID_BTA_ME 58 /* message equipement server/client */
+
+ /* LayerIDs for BT APP */
+ { BTTRC_ID_BTAPP, BTTRC_ID_BTAPP, (const tBTTRC_SET_TRACE_LEVEL *)BTAPP_SetTraceLevel, "BTAPP" },
+#endif
+
+ { 0, 0, NULL, "" }
+};
+
+const UINT16 bttrc_map_size = sizeof(bttrc_set_level_map)/sizeof(tBTTRC_FUNC_MAP);
+#endif
+
+/********************************************************************************
+ **
+ ** Function Name: BTE_InitTraceLevels
+ **
+ ** Purpose: This function can be used to set the boot time reading it from the
+ ** platform.
+ ** WARNING: it is called under BTU context and it blocks the BTU task
+ ** till it returns (sync call)
+ **
+ ** Input Parameters: None, platform to provide levels
+ ** Returns:
+ ** Newly set levels, if any!
+ **
+ *********************************************************************************/
+BT_API void BTE_InitTraceLevels( void )
+{
+ /* read and set trace levels from android property system and call the different
+ * XXX_SetTraceLevel().
+ */
+#if ( BT_USE_TRACES==TRUE )
+ /* read runtime trace settings after init of control block */
+
+ // BLUEDROID MOD
+ //if ( !btl_cfg_get_trace_prop() )
+ {
+#if defined(BTL_CFG_USE_CONF_FILE) && (BTL_CFG_USE_CONF_FILE==TRUE)
+ if (NULL!=bte_appl_cfg.p_conf_params)
+ {
+ if ( 0 > btl_cfg_set_by_idx_conf( &conf_table, bte_appl_cfg.p_conf_params,
+ BTL_CFG_CONF_TRACE) )
+ {
+ BT_TRACE_0( TRACE_LAYER_NONE, TRACE_TYPE_DEBUG, "[bttrc] using compile default trace settings" );
+ }
+ /* free up property settings data from conf file as needed anymore */
+ GKI_os_free(bte_appl_cfg.p_conf_params);
+ bte_appl_cfg.p_conf_params = NULL;
+ BT_TRACE_0( TRACE_LAYER_NONE, TRACE_TYPE_DEBUG, "BTE_InitTraceLevels(): freed p_conf_params" );
+ }
+ else
+ {
+ BT_TRACE_0( TRACE_LAYER_NONE, TRACE_TYPE_DEBUG, "[bttrc] using compile default trace settings" );
+ }
+#else
+ BT_TRACE_0( TRACE_LAYER_NONE, TRACE_TYPE_DEBUG, "[bttrc] using compile default trace settings" );
+#endif
+ }
+#endif
+}
+
+
+/********************************************************************************
+ **
+ ** Function Name: LogMsg_0
+ **
+ ** Purpose: Encodes a trace message that has no parameter arguments
+ **
+ ** Input Parameters: trace_set_mask: tester trace type.
+ ** fmt_str: displayable string.
+ ** Returns:
+ ** Nothing.
+ **
+ *********************************************************************************/
+void LogMsg_0(UINT32 trace_set_mask, const char *fmt_str) {
+ LogMsg(trace_set_mask, fmt_str);
+}
+
+/********************************************************************************
+ **
+ ** Function Name: LogMsg_1
+ **
+ ** Purpose: Encodes a trace message that has one parameter argument
+ **
+ ** Input Parameters: trace_set_mask: tester trace type.
+ ** fmt_str: displayable string.
+ ** Returns:
+ ** Nothing.
+ **
+ *********************************************************************************/
+void LogMsg_1(UINT32 trace_set_mask, const char *fmt_str, UINT32 p1) {
+
+ LogMsg(trace_set_mask, fmt_str, p1);
+}
+
+/********************************************************************************
+ **
+ ** Function Name: LogMsg_2
+ **
+ ** Purpose: Encodes a trace message that has two parameter arguments
+ **
+ ** Input Parameters: trace_set_mask: tester trace type.
+ ** fmt_str: displayable string.
+ ** Returns:
+ ** Nothing.
+ **
+ *********************************************************************************/
+void LogMsg_2(UINT32 trace_set_mask, const char *fmt_str, UINT32 p1, UINT32 p2) {
+ LogMsg(trace_set_mask, fmt_str, p1, p2);
+}
+
+/********************************************************************************
+ **
+ ** Function Name: LogMsg_3
+ **
+ ** Purpose: Encodes a trace message that has three parameter arguments
+ **
+ ** Input Parameters: trace_set_mask: tester trace type.
+ ** fmt_str: displayable string.
+ ** Returns:
+ ** Nothing.
+ **
+ *********************************************************************************/
+void LogMsg_3(UINT32 trace_set_mask, const char *fmt_str, UINT32 p1, UINT32 p2,
+ UINT32 p3) {
+ LogMsg(trace_set_mask, fmt_str, p1, p2, p3);
+}
+
+/********************************************************************************
+ **
+ ** Function Name: LogMsg_4
+ **
+ ** Purpose: Encodes a trace message that has four parameter arguments
+ **
+ ** Input Parameters: trace_set_mask: tester trace type.
+ ** fmt_str: displayable string.
+ ** Returns:
+ ** Nothing.
+ **
+ *********************************************************************************/
+void LogMsg_4(UINT32 trace_set_mask, const char *fmt_str, UINT32 p1, UINT32 p2,
+ UINT32 p3, UINT32 p4) {
+ LogMsg(trace_set_mask, fmt_str, p1, p2, p3, p4);
+}
+
+/********************************************************************************
+ **
+ ** Function Name: LogMsg_5
+ **
+ ** Purpose: Encodes a trace message that has five parameter arguments
+ **
+ ** Input Parameters: trace_set_mask: tester trace type.
+ ** fmt_str: displayable string.
+ ** Returns:
+ ** Nothing.
+ **
+ *********************************************************************************/
+void LogMsg_5(UINT32 trace_set_mask, const char *fmt_str, UINT32 p1, UINT32 p2,
+ UINT32 p3, UINT32 p4, UINT32 p5) {
+ LogMsg(trace_set_mask, fmt_str, p1, p2, p3, p4, p5);
+}
+
+/********************************************************************************
+ **
+ ** Function Name: LogMsg_6
+ **
+ ** Purpose: Encodes a trace message that has six parameter arguments
+ **
+ ** Input Parameters: trace_set_mask: tester trace type.
+ ** fmt_str: displayable string.
+ ** Returns:
+ ** Nothing.
+ **
+ *********************************************************************************/
+void LogMsg_6(UINT32 trace_set_mask, const char *fmt_str, UINT32 p1, UINT32 p2,
+ UINT32 p3, UINT32 p4, UINT32 p5, UINT32 p6) {
+ LogMsg(trace_set_mask, fmt_str, p1, p2, p3, p4, p5, p6);
+}
diff --git a/main/bte_main.c b/main/bte_main.c
new file mode 100644
index 0000000..5def921
--- /dev/null
+++ b/main/bte_main.c
@@ -0,0 +1,550 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * This program is the proprietary software of Broadcom Corporation and/or its
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
+ *
+ * Except as expressly set forth in the Authorized License,
+ *
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
+ * Broadcom integrated circuit products.
+ *
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT
+ * OF USE OR PERFORMANCE OF THE SOFTWARE.
+ *
+ * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR
+ * ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Filename: bte_main.c
+ *
+ * Description: Contains BTE core stack initialization and shutdown code
+ *
+ ******************************************************************************/
+#include <fcntl.h>
+#include <stdlib.h>
+
+#include "gki.h"
+#include "bd.h"
+#include "btu.h"
+#include "bte.h"
+#include "bta_api.h"
+#include "bt_vendor_lib.h"
+
+/*******************************************************************************
+** Constants & Macros
+*******************************************************************************/
+
+/*******************************************************************************
+** Local type definitions
+*******************************************************************************/
+
+/*******************************************************************************
+** Static variables
+*******************************************************************************/
+static bt_vendor_interface_t *bt_vendor_if=NULL;
+static const bt_vendor_callbacks_t vnd_callbacks;
+static BOOLEAN lpm_enabled = FALSE;
+
+/*******************************************************************************
+** Static functions
+*******************************************************************************/
+static void bte_main_in_hw_init(void);
+
+/*******************************************************************************
+** Externs
+*******************************************************************************/
+BTU_API extern UINT32 btu_task (UINT32 param);
+BTU_API extern void BTE_Init (void);
+BT_API extern void BTE_LoadStack(void);
+BT_API void BTE_UnloadStack(void);
+extern void scru_flip_bda (BD_ADDR dst, const BD_ADDR src);
+extern void btsnoop_init(void);
+extern void btsnoop_open(void);
+extern void btsnoop_close(void);
+extern void btsnoop_cleanup (void);
+
+
+
+/*******************************************************************************
+** System Task Configuration
+*******************************************************************************/
+
+/* bluetooth protocol stack (BTU) task */
+#ifndef BTE_BTU_STACK_SIZE
+#define BTE_BTU_STACK_SIZE 0//0x2000 /* In bytes */
+#endif
+#define BTE_BTU_TASK_STR ((INT8 *) "BTU")
+UINT32 bte_btu_stack[(BTE_BTU_STACK_SIZE + 3) / 4];
+
+/******************************************************************************
+**
+** Function bte_main_in_hw_init
+**
+** Description Internal helper function for chip hardware init
+**
+** Returns None
+**
+******************************************************************************/
+void bte_main_in_hw_init(void)
+{
+ GKI_delay(200);
+
+ if ( (bt_vendor_if = (bt_vendor_interface_t *) bt_vendor_get_interface()) == NULL)
+ {
+ APPL_TRACE_ERROR0("!!! Failed to get BtVendorInterface !!!");
+ }
+ else
+ {
+ int result = bt_vendor_if->init(&vnd_callbacks);
+ APPL_TRACE_EVENT1("libbt-vendor init returns %d", result);
+ }
+}
+
+/******************************************************************************
+**
+** Function bte_main_boot_entry
+**
+** Description BTE MAIN API - Entry point for BTE chip/stack initialization
+**
+** Returns None
+**
+******************************************************************************/
+void bte_main_boot_entry(void)
+{
+ /* initialize OS */
+ GKI_init();
+
+ bte_main_in_hw_init();
+
+#if (BTTRC_INCLUDED == TRUE)
+ /* Initialize trace feature */
+ BTTRC_TraceInit(MAX_TRACE_RAM_SIZE, &BTE_TraceLogBuf[0], BTTRC_METHOD_RAM);
+#endif
+
+ /* Initialize BTE control block */
+ BTE_Init();
+}
+
+/******************************************************************************
+**
+** Function bte_main_shutdown
+**
+** Description BTE MAIN API - Shutdown code for BTE chip/stack
+**
+** Returns None
+**
+******************************************************************************/
+void bte_main_shutdown()
+{
+ if (bt_vendor_if)
+ bt_vendor_if->cleanup();
+
+ bt_vendor_if = NULL;
+ GKI_shutdown();
+}
+
+/******************************************************************************
+**
+** Function bte_main_enable
+**
+** Description BTE MAIN API - Creates all the BTE tasks. Should be called
+** part of the Bluetooth stack enable sequence
+**
+** Returns None
+**
+******************************************************************************/
+void bte_main_enable(void)
+{
+ APPL_TRACE_DEBUG1("%s", __FUNCTION__);
+ lpm_enabled = FALSE;
+
+ if (bt_vendor_if)
+ {
+ /* toggle chip power to ensure we will reset chip in case
+ a previous stack shutdown wasn't completed gracefully */
+ bt_vendor_if->set_power(BT_VENDOR_CHIP_PWR_OFF);
+ bt_vendor_if->set_power(BT_VENDOR_CHIP_PWR_ON);
+
+ bt_vendor_if->preload(NULL);
+ }
+
+ GKI_create_task((TASKPTR)btu_task, BTU_TASK, BTE_BTU_TASK_STR,
+ (UINT16 *) ((UINT8 *)bte_btu_stack + BTE_BTU_STACK_SIZE),
+ sizeof(bte_btu_stack));
+
+ GKI_run(0);
+}
+
+/******************************************************************************
+**
+** Function bte_main_disable
+**
+** Description BTE MAIN API - Destroys all the BTE tasks. Should be called
+** part of the Bluetooth stack disable sequence
+**
+** Returns None
+**
+******************************************************************************/
+void bte_main_disable(void)
+{
+ APPL_TRACE_DEBUG1("%s", __FUNCTION__);
+
+ GKI_destroy_task(BTU_TASK);
+
+ GKI_freeze();
+
+ if (bt_vendor_if)
+ bt_vendor_if->set_power(BT_VENDOR_CHIP_PWR_OFF);
+}
+
+/******************************************************************************
+**
+** Function bte_main_postload_cfg
+**
+** Description BTE MAIN API - Stack postload configuration
+**
+** Returns None
+**
+******************************************************************************/
+void bte_main_postload_cfg(void)
+{
+ if (bt_vendor_if)
+ bt_vendor_if->postload(NULL);
+}
+
+#if (defined(HCILP_INCLUDED) && HCILP_INCLUDED == TRUE)
+/******************************************************************************
+**
+** Function bte_main_enable_lpm
+**
+** Description BTE MAIN API - Enable/Disable low power mode operation
+**
+** Returns None
+**
+******************************************************************************/
+void bte_main_enable_lpm(BOOLEAN enable)
+{
+ int result = -1;
+
+ if (bt_vendor_if)
+ result = bt_vendor_if->lpm( \
+ (enable == TRUE) ? BT_VENDOR_LPM_ENABLE : BT_VENDOR_LPM_DISABLE \
+ );
+
+ APPL_TRACE_EVENT2("vendor lib lpm enable=%d return %d", enable, result);
+}
+
+/******************************************************************************
+**
+** Function bte_main_lpm_allow_bt_device_sleep
+**
+** Description BTE MAIN API - Allow BT controller goest to sleep
+**
+** Returns None
+**
+******************************************************************************/
+void bte_main_lpm_allow_bt_device_sleep()
+{
+ int result = -1;
+
+ if ((bt_vendor_if) && (lpm_enabled == TRUE))
+ result = bt_vendor_if->lpm(BT_VENDOR_LPM_WAKE_DEASSERT);
+
+ APPL_TRACE_DEBUG1("vendor lib lpm deassertion return %d", result);
+}
+
+/******************************************************************************
+**
+** Function bte_main_lpm_wake_bt_device
+**
+** Description BTE MAIN API - Wake BT controller up if it is in sleep mode
+**
+** Returns None
+**
+******************************************************************************/
+void bte_main_lpm_wake_bt_device()
+{
+ int result = -1;
+
+ if ((bt_vendor_if) && (lpm_enabled == TRUE))
+ result = bt_vendor_if->lpm(BT_VENDOR_LPM_WAKE_ASSERT);
+
+ APPL_TRACE_DEBUG1("vendor lib lpm assertion return %d", result);
+}
+#endif // HCILP_INCLUDED
+
+/******************************************************************************
+**
+** Function bte_main_hci_send
+**
+** Description BTE MAIN API - This function is called by the upper stack to
+** send an HCI message. The function displays a protocol trace
+** message (if enabled), and then calls the 'transmit' function
+** associated with the currently selected HCI transport
+**
+** Returns None
+**
+******************************************************************************/
+void bte_main_hci_send (BT_HDR *p_msg, UINT16 event)
+{
+ UINT16 sub_event = event & BT_SUB_EVT_MASK; /* local controller ID */
+
+ p_msg->event = event;
+
+
+ if((sub_event == LOCAL_BR_EDR_CONTROLLER_ID) || \
+ (sub_event == LOCAL_BLE_CONTROLLER_ID))
+ {
+ if (bt_vendor_if)
+ bt_vendor_if->transmit_buf((TRANSAC)p_msg, \
+ (char *) (p_msg + 1), \
+ p_msg->len);
+ else
+ GKI_freebuf(p_msg);
+ }
+ else
+ {
+ APPL_TRACE_ERROR0("Invalid Controller ID. Discarding message.");
+ GKI_freebuf(p_msg);
+ }
+}
+
+/******************************************************************************
+**
+** Function bte_main_post_reset_init
+**
+** Description BTE MAIN API - This function is mapped to BTM_APP_DEV_INIT
+** and shall be automatically called from BTE after HCI_Reset
+**
+** Returns None
+**
+******************************************************************************/
+void bte_main_post_reset_init()
+{
+ BTM_ContinueReset();
+}
+
+/*****************************************************************************
+**
+** libbt-vendor Callback Functions
+**
+*****************************************************************************/
+
+/******************************************************************************
+**
+** Function preload_cb
+**
+** Description VENDOR LIB CALLBACK API - This function is called
+** when vendor lib completed stack preload process
+**
+** Returns None
+**
+******************************************************************************/
+static void preload_cb(TRANSAC transac, bt_vendor_preload_result_t result)
+{
+ APPL_TRACE_EVENT1("vnd preload_cb %d [0:SUCCESS 1:FAIL]", result);
+
+// if (result == BT_VENDOR_PRELOAD_SUCCESS)
+ /* keep going even if firmware patch file is missing */
+ {
+ /* notify BTU task that libbt-vendor is ready */
+ GKI_send_event(BTU_TASK, TASK_MBOX_0_EVT_MASK);
+ }
+}
+
+/******************************************************************************
+**
+** Function postload_cb
+**
+** Description VENDOR LIB CALLBACK API - This function is called
+** when vendor lib completed stack postload process
+**
+** Returns None
+**
+******************************************************************************/
+static void postload_cb(TRANSAC transac, bt_vendor_postload_result_t result)
+{
+ APPL_TRACE_EVENT1("vnd postload_cb %d", result);
+}
+
+/******************************************************************************
+**
+** Function lpm_cb
+**
+** Description VENDOR LIB CALLBACK API - This function is called
+** back from vendor lib to indicate the current LPM state
+**
+** Returns None
+**
+******************************************************************************/
+static void lpm_cb(bt_vendor_lpm_request_result_t result)
+{
+ APPL_TRACE_EVENT1("vnd lpm_result_cb %d", result);
+ lpm_enabled = (result == BT_VENDOR_LPM_ENABLED) ? TRUE : FALSE;
+}
+
+/******************************************************************************
+**
+** Function hostwake_ind
+**
+** Description VENDOR LIB CALLOUT API - This function is called
+** from vendor lib to indicate the HostWake event
+**
+** Returns None
+**
+******************************************************************************/
+static void hostwake_ind(bt_vendor_low_power_event_t event)
+{
+ APPL_TRACE_EVENT1("vnd hostwake_ind %d", event);
+}
+
+/******************************************************************************
+**
+** Function alloc
+**
+** Description VENDOR LIB CALLOUT API - This function is called
+** from vendor lib to request for data buffer allocation
+**
+** Returns NULL / pointer to allocated buffer
+**
+******************************************************************************/
+static char *alloc(int size)
+{
+ BT_HDR *p_hdr = NULL;
+
+// APPL_TRACE_DEBUG1("vnd alloc size=%d", size);
+
+ p_hdr = (BT_HDR *) GKI_getbuf ((UINT16) size);
+
+ if (p_hdr == NULL)
+ {
+ APPL_TRACE_WARNING0("alloc returns NO BUFFER!");
+ }
+
+ return ((char *) p_hdr);
+}
+
+/******************************************************************************
+**
+** Function dealloc
+**
+** Description VENDOR LIB CALLOUT API - This function is called
+** from vendor lib to release the data buffer allocated
+** through the alloc call earlier.
+**
+** Returns bt_vnd_status_t
+**
+******************************************************************************/
+static int dealloc(TRANSAC transac, char *p_buf)
+{
+ GKI_freebuf(transac);
+ return BT_VENDOR_STATUS_SUCCESS;
+}
+
+/******************************************************************************
+**
+** Function data_ind
+**
+** Description VENDOR LIB CALLOUT API - This function is called
+** from vendor lib to pass in the received HCI packets.
+**
+** The core stack is responsible for releasing the data buffer
+** passed in from vendor lib once the core stack has done with
+** it.
+**
+** Returns bt_vnd_status_t
+**
+******************************************************************************/
+static int data_ind(TRANSAC transac, char *p_buf, int len)
+{
+ BT_HDR *p_msg = (BT_HDR *) transac;
+
+// APPL_TRACE_DEBUG2("vnd data_ind event=0x%04X (len=%d)", p_msg->event, len);
+
+
+ GKI_send_msg (BTU_TASK, BTU_HCI_RCV_MBOX, transac);
+ return BT_VENDOR_STATUS_SUCCESS;
+}
+
+/******************************************************************************
+**
+** Function tx_result
+**
+** Description VENDOR LIB CALLBACK API - This function is called
+** from vendor lib once it has processed/sent the prior data
+** buffer which core stack passed to it through transmit_buf
+** call earlier.
+**
+** The core stack is responsible for releasing the data buffer
+** if it has been completedly processed.
+**
+** Returns bt_vnd_status_t
+**
+******************************************************************************/
+static int tx_result(TRANSAC transac, char *p_buf, \
+ bt_vendor_transmit_result_t result)
+{
+ /*
+ APPL_TRACE_DEBUG2("vnd tx_result %d (event=%04X)", result, \
+ ((BT_HDR *)transac)->event);
+ */
+
+ if (result == BT_VENDOR_TX_FRAGMENT)
+ {
+ GKI_send_msg (BTU_TASK, BTU_HCI_RCV_MBOX, transac);
+ }
+ else
+ {
+ GKI_freebuf(transac);
+ }
+
+ return BT_VENDOR_STATUS_SUCCESS;
+}
+
+/*****************************************************************************
+** The libbt-vendor Callback Functions Table
+*****************************************************************************/
+static const bt_vendor_callbacks_t vnd_callbacks = {
+ sizeof(bt_vendor_callbacks_t),
+ preload_cb,
+ postload_cb,
+ lpm_cb,
+ hostwake_ind,
+ alloc,
+ dealloc,
+ data_ind,
+ tx_result
+};
+
diff --git a/main/bte_version.c b/main/bte_version.c
new file mode 100644
index 0000000..96e3a41
--- /dev/null
+++ b/main/bte_version.c
@@ -0,0 +1,14 @@
+/*****************************************************************************/
+/* */
+/* Name: bte_version.c */
+/* */
+/* Description: */
+/* BTE Version string declaration. */
+/* */
+/* Copyright (c) 2001 - 2004, WIDCOMM Inc., All Rights Reserved. */
+/* WIDCOMM Bluetooth Core. Proprietary and confidential. */
+/*****************************************************************************/
+#include "bt_types.h"
+
+const UINT8 bte_version_string[] = "BCM1200_PI_10.3.20.33";
+
diff --git a/stack/Android.mk b/stack/Android.mk
new file mode 100644
index 0000000..29d59d4
--- /dev/null
+++ b/stack/Android.mk
@@ -0,0 +1,188 @@
+ifneq ($(TARGET_SIMULATOR),true)
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_C_INCLUDES:= . \
+ $(LOCAL_PATH)/include \
+ $(LOCAL_PATH)/avct \
+ $(LOCAL_PATH)/btm \
+ $(LOCAL_PATH)/l2cap \
+ $(LOCAL_PATH)/avdt \
+ $(LOCAL_PATH)/gatt \
+ $(LOCAL_PATH)/gap \
+ $(LOCAL_PATH)/bip \
+ $(LOCAL_PATH)/pan \
+ $(LOCAL_PATH)/bpp \
+ $(LOCAL_PATH)/bnep \
+ $(LOCAL_PATH)/hid \
+ $(LOCAL_PATH)/obx \
+ $(LOCAL_PATH)/sdp \
+ $(LOCAL_PATH)/smp \
+ $(LOCAL_PATH)/amp \
+ $(LOCAL_PATH)/amp/security \
+ $(LOCAL_PATH)/../include \
+ $(LOCAL_PATH)/../gki/common \
+ $(LOCAL_PATH)/../gki/ulinux \
+ $(LOCAL_PATH)/../udrv/include \
+ $(LOCAL_PATH)/../rpc/include \
+ $(LOCAL_PATH)/../hcis \
+ $(LOCAL_PATH)/../ctrlr/include \
+ $(LOCAL_PATH)/../bta/include \
+ $(LOCAL_PATH)/../bta/sys \
+ $(LOCAL_PATH)/../brcm/include
+
+ifeq ($(BOARD_HAVE_BLUETOOTH_BCM),true)
+LOCAL_CFLAGS += \
+ -DBOARD_HAVE_BLUETOOTH_BCM
+endif
+
+LOCAL_PRELINK_MODULE:=false
+LOCAL_SRC_FILES:= \
+ ./dun/dun_api.c \
+ ./avrc/avrc_bld_tg.c \
+ ./avrc/avrc_api.c \
+ ./avrc/avrc_utils.c \
+ ./avrc/avrc_pars_ct.c \
+ ./avrc/avrc_sdp.c \
+ ./avrc/avrc_pars_tg.c \
+ ./avrc/avrc_bld_ct.c \
+ ./avrc/avrc_opt.c \
+ ./hid/hidd_conn.c \
+ ./hid/hidd_mgmt.c \
+ ./hid/hidh_api.c \
+ ./hid/hidd_pm.c \
+ ./hid/hidh_conn.c \
+ ./hid/hidd_api.c \
+ ./bnep/bnep_main.c \
+ ./bnep/bnep_utils.c \
+ ./bnep/bnep_api.c \
+ ./hcic/hciblecmds.c \
+ ./hcic/hcicmds.c \
+ ./btm/btm_ble.c \
+ ./btm/btm_sec.c \
+ ./btm/btm_inq.c \
+ ./btm/btm_ble_addr.c \
+ ./btm/btm_ble_bgconn.c \
+ ./btm/btm_main.c \
+ ./btm/btm_dev.c \
+ ./btm/btm_ble_gap.c \
+ ./btm/btm_acl.c \
+ ./btm/btm_sco.c \
+ ./btm/btm_pm.c \
+ ./btm/btm_devctl.c \
+ ./rfcomm/rfc_utils.c \
+ ./rfcomm/port_rfc.c \
+ ./rfcomm/rfc_l2cap_if.c \
+ ./rfcomm/rfc_mx_fsm.c \
+ ./rfcomm/port_utils.c \
+ ./rfcomm/rfc_port_fsm.c \
+ ./rfcomm/rfc_port_if.c \
+ ./rfcomm/port_api.c \
+ ./rfcomm/rfc_ts_frames.c \
+ ./mcap/mca_dact.c \
+ ./mcap/mca_dsm.c \
+ ./mcap/mca_l2c.c \
+ ./mcap/mca_main.c \
+ ./mcap/mca_csm.c \
+ ./mcap/mca_cact.c \
+ ./mcap/mca_api.c \
+ ./gatt/gatt_sr.c \
+ ./gatt/gatt_cl.c \
+ ./gatt/gatt_api.c \
+ ./gatt/gatt_auth.c \
+ ./gatt/gatt_utils.c \
+ ./gatt/gatt_main.c \
+ ./gatt/att_protocol.c \
+ ./gatt/gatt_attr.c \
+ ./gatt/gatt_db.c \
+ ./obx/hdrs/obx_dutf.c \
+ ./obx/hdrs/obx_dwchar.c \
+ ./obx/hdrs/obx_gen.c \
+ ./obx/hdrs/obx_dunic.c \
+ ./obx/hdrs/utfc.c \
+ ./obx/hdrs/obx_dbtp.c \
+ ./obx/hdrs/obx_dauth.c \
+ ./obx/hdrs/obx_ebtp.c \
+ ./obx/hdrs/obx_wchar.c \
+ ./obx/hdrs/obx_eunic.c \
+ ./obx/hdrs/obx_eopt.c \
+ ./obx/hdrs/obx_dopt.c \
+ ./obx/hdrs/obx_ewchar.c \
+ ./obx/hdrs/obx_eutf.c \
+ ./obx/obx_csm.c \
+ ./obx/obx_ssm.c \
+ ./obx/obx_cact.c \
+ ./obx/obx_md5.c \
+ ./obx/obx_rfc.c \
+ ./obx/obx_main.c \
+ ./obx/obx_sapi.c \
+ ./obx/obx_l2c.c \
+ ./obx/obx_sact.c \
+ ./obx/obx_utils.c \
+ ./obx/obx_capi.c \
+ ./avct/avct_bcb_act.c \
+ ./avct/avct_l2c_br.c \
+ ./avct/avct_api.c \
+ ./avct/avct_l2c.c \
+ ./avct/avct_lcb.c \
+ ./avct/avct_ccb.c \
+ ./avct/avct_lcb_act.c \
+ ./smp/smp_main.c \
+ ./smp/smp_l2c.c \
+ ./smp/smp_cmac.c \
+ ./smp/smp_utils.c \
+ ./smp/smp_act.c \
+ ./smp/smp_keys.c \
+ ./smp/smp_api.c \
+ ./smp/aes.c \
+ ./avdt/avdt_ccb.c \
+ ./avdt/avdt_scb_act.c \
+ ./avdt/avdt_msg.c \
+ ./avdt/avdt_ccb_act.c \
+ ./avdt/avdt_api.c \
+ ./avdt/avdt_scb.c \
+ ./avdt/avdt_ad.c \
+ ./avdt/avdt_l2c.c \
+ ./sdp/sdp_server.c \
+ ./sdp/sdp_main.c \
+ ./sdp/sdp_db.c \
+ ./sdp/sdp_utils.c \
+ ./sdp/sdp_api.c \
+ ./sdp/sdp_discovery.c \
+ ./xml/xml_parse.c \
+ ./xml/xml_vlist.c \
+ ./xml/xml_erp.c \
+ ./xml/xml_flp.c \
+ ./xml/xml_mlp.c \
+ ./xml/xml_bld.c \
+ ./a2dp/a2d_api.c \
+ ./a2dp/a2d_m24.c \
+ ./a2dp/a2d_m12.c \
+ ./a2dp/a2d_sbc.c \
+ ./pan/pan_main.c \
+ ./pan/pan_api.c \
+ ./pan/pan_utils.c \
+ ./btu/btu_hcif.c \
+ ./btu/btu_init.c \
+ ./btu/btu_task.c \
+ ./l2cap/l2c_fcr.c \
+ ./l2cap/l2c_ucd.c \
+ ./l2cap/l2c_main.c \
+ ./l2cap/l2c_api.c \
+ ./l2cap/l2c_utils.c \
+ ./l2cap/l2c_csm.c \
+ ./l2cap/l2c_link.c \
+ ./l2cap/l2c_ble.c \
+ ./goep/goep_fs.c \
+ ./goep/goep_trace.c \
+ ./goep/goep_util.c
+
+LOCAL_MODULE := libbt-brcm_stack
+LOCAL_MODULE_TAGS := eng
+LOCAL_SHARED_LIBRARIES := libcutils libc
+
+include $(BUILD_STATIC_LIBRARY)
+
+endif # TARGET_SIMULATOR != true
diff --git a/stack/a2dp/a2d_api.c b/stack/a2dp/a2d_api.c
new file mode 100644
index 0000000..dbff646
--- /dev/null
+++ b/stack/a2dp/a2d_api.c
@@ -0,0 +1,382 @@
+/*****************************************************************************
+**
+** Name: a2d_api.c
+**
+** Description:Common API for the Advanced Audio Distribution Profile (A2DP)
+**
+** Copyright (c) 2002-2009, Broadcom Corp., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include <string.h>
+#include "bt_target.h"
+#include "sdpdefs.h"
+#include "a2d_api.h"
+#include "a2d_int.h"
+#include "avdt_api.h"
+
+/*****************************************************************************
+** Global data
+*****************************************************************************/
+#if A2D_DYNAMIC_MEMORY == FALSE
+tA2D_CB a2d_cb;
+#endif
+
+
+/******************************************************************************
+**
+** Function a2d_sdp_cback
+**
+** Description This is the SDP callback function used by A2D_FindService.
+** This function will be executed by SDP when the service
+** search is completed. If the search is successful, it
+** finds the first record in the database that matches the
+** UUID of the search. Then retrieves various parameters
+** from the record. When it is finished it calls the
+** application callback function.
+**
+** Returns Nothing.
+**
+******************************************************************************/
+static void a2d_sdp_cback(UINT16 status)
+{
+ tSDP_DISC_REC *p_rec = NULL;
+ tSDP_DISC_ATTR *p_attr;
+ BOOLEAN found = FALSE;
+ tA2D_Service a2d_svc;
+ tSDP_PROTOCOL_ELEM elem;
+
+ A2D_TRACE_API1("a2d_sdp_cback status: %d", status);
+
+ if (status == SDP_SUCCESS)
+ {
+ /* loop through all records we found */
+ do
+ {
+ /* get next record; if none found, we're done */
+ if ((p_rec = SDP_FindServiceInDb(a2d_cb.find.p_db,
+ a2d_cb.find.service_uuid, p_rec)) == NULL)
+ {
+ break;
+ }
+ memset(&a2d_svc, 0, sizeof(tA2D_Service));
+
+ /* get service name */
+ if ((p_attr = SDP_FindAttributeInRec(p_rec,
+ ATTR_ID_SERVICE_NAME)) != NULL)
+ {
+ a2d_svc.p_service_name = (char *) p_attr->attr_value.v.array;
+ a2d_svc.service_len = SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
+ }
+
+ /* get provider name */
+ if ((p_attr = SDP_FindAttributeInRec(p_rec,
+ ATTR_ID_PROVIDER_NAME)) != NULL)
+ {
+ a2d_svc.p_provider_name = (char *) p_attr->attr_value.v.array;
+ a2d_svc.provider_len = SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
+ }
+
+ /* get supported features */
+ if ((p_attr = SDP_FindAttributeInRec(p_rec,
+ ATTR_ID_SUPPORTED_FEATURES)) != NULL)
+ {
+ a2d_svc.features = p_attr->attr_value.v.u16;
+ }
+
+ /* get AVDTP version */
+ if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_AVDTP, &elem))
+ {
+ a2d_svc.avdt_version = elem.params[0];
+ A2D_TRACE_DEBUG1("avdt_version: 0x%x", a2d_svc.avdt_version);
+ }
+
+ /* we've got everything, we're done */
+ found = TRUE;
+ break;
+
+ } while (TRUE);
+ }
+
+ a2d_cb.find.service_uuid = 0;
+ /* return info from sdp record in app callback function */
+ if (a2d_cb.find.p_cback != NULL)
+ {
+ (*a2d_cb.find.p_cback)(found, &a2d_svc);
+ }
+
+ return;
+}
+
+/*******************************************************************************
+**
+** Function a2d_set_avdt_sdp_ver
+**
+** Description This function allows the script wrapper to change the
+** avdt version of a2dp.
+**
+** Returns None
+**
+*******************************************************************************/
+void a2d_set_avdt_sdp_ver (UINT16 avdt_sdp_ver)
+{
+ a2d_cb.avdt_sdp_ver = avdt_sdp_ver;
+}
+
+/******************************************************************************
+**
+** Function A2D_AddRecord
+**
+** Description This function is called by a server application to add
+** SRC or SNK information to an SDP record. Prior to
+** calling this function the application must call
+** SDP_CreateRecord() to create an SDP record.
+**
+** Input Parameters:
+** service_uuid: Indicates SRC or SNK.
+**
+** p_service_name: Pointer to a null-terminated character
+** string containing the service name.
+**
+** p_provider_name: Pointer to a null-terminated character
+** string containing the provider name.
+**
+** features: Profile supported features.
+**
+** sdp_handle: SDP handle returned by SDP_CreateRecord().
+**
+** Output Parameters:
+** None.
+**
+** Returns A2D_SUCCESS if function execution succeeded,
+** A2D_INVALID_PARAMS if bad parameters are given.
+** A2D_FAIL if function execution failed.
+**
+******************************************************************************/
+tA2D_STATUS A2D_AddRecord(UINT16 service_uuid, char *p_service_name, char *p_provider_name,
+ UINT16 features, UINT32 sdp_handle)
+{
+ UINT16 browse_list[1];
+ BOOLEAN result = TRUE;
+ UINT8 temp[8];
+ UINT8 *p;
+ tSDP_PROTOCOL_ELEM proto_list [A2D_NUM_PROTO_ELEMS];
+
+ A2D_TRACE_API1("A2D_AddRecord uuid: %x", service_uuid);
+
+ if( (sdp_handle == 0) ||
+ (service_uuid != UUID_SERVCLASS_AUDIO_SOURCE && service_uuid != UUID_SERVCLASS_AUDIO_SINK) )
+ return A2D_INVALID_PARAMS;
+
+ /* add service class id list */
+ result &= SDP_AddServiceClassIdList(sdp_handle, 1, &service_uuid);
+
+ memset((void*) proto_list, 0 , A2D_NUM_PROTO_ELEMS*sizeof(tSDP_PROTOCOL_ELEM));
+
+ /* add protocol descriptor list */
+ proto_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+ proto_list[0].num_params = 1;
+ proto_list[0].params[0] = AVDT_PSM;
+ proto_list[1].protocol_uuid = UUID_PROTOCOL_AVDTP;
+ proto_list[1].num_params = 1;
+ proto_list[1].params[0] = a2d_cb.avdt_sdp_ver;
+
+ result &= SDP_AddProtocolList(sdp_handle, A2D_NUM_PROTO_ELEMS, proto_list);
+
+ /* add profile descriptor list */
+ result &= SDP_AddProfileDescriptorList(sdp_handle, UUID_SERVCLASS_ADV_AUDIO_DISTRIBUTION, A2D_VERSION);
+
+ /* add supported feature */
+ if (features != 0)
+ {
+ p = temp;
+ UINT16_TO_BE_STREAM(p, features);
+ result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SUPPORTED_FEATURES, UINT_DESC_TYPE,
+ (UINT32)2, (UINT8*)temp);
+ }
+
+ /* add provider name */
+ if (p_provider_name != NULL)
+ {
+ result &= SDP_AddAttribute(sdp_handle, ATTR_ID_PROVIDER_NAME, TEXT_STR_DESC_TYPE,
+ (UINT32)(strlen(p_provider_name)+1), (UINT8 *) p_provider_name);
+ }
+
+ /* add service name */
+ if (p_service_name != NULL)
+ {
+ result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE,
+ (UINT32)(strlen(p_service_name)+1), (UINT8 *) p_service_name);
+ }
+
+ /* add browse group list */
+ browse_list[0] = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
+ result &= SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, browse_list);
+
+
+ return (result ? A2D_SUCCESS : A2D_FAIL);
+}
+
+/******************************************************************************
+**
+** Function A2D_FindService
+**
+** Description This function is called by a client application to
+** perform service discovery and retrieve SRC or SNK SDP
+** record information from a server. Information is
+** returned for the first service record found on the
+** server that matches the service UUID. The callback
+** function will be executed when service discovery is
+** complete. There can only be one outstanding call to
+** A2D_FindService() at a time; the application must wait
+** for the callback before it makes another call to
+** the function.
+**
+** Input Parameters:
+** service_uuid: Indicates SRC or SNK.
+**
+** bd_addr: BD address of the peer device.
+**
+** p_db: Pointer to the information to initialize
+** the discovery database.
+**
+** p_cback: Pointer to the A2D_FindService()
+** callback function.
+**
+** Output Parameters:
+** None.
+**
+** Returns A2D_SUCCESS if function execution succeeded,
+** A2D_INVALID_PARAMS if bad parameters are given.
+** A2D_BUSY if discovery is already in progress.
+** A2D_FAIL if function execution failed.
+**
+******************************************************************************/
+tA2D_STATUS A2D_FindService(UINT16 service_uuid, BD_ADDR bd_addr,
+ tA2D_SDP_DB_PARAMS *p_db, tA2D_FIND_CBACK *p_cback)
+{
+ tSDP_UUID uuid_list;
+ BOOLEAN result = TRUE;
+ UINT16 a2d_attr_list[] = {ATTR_ID_SERVICE_CLASS_ID_LIST, /* update A2D_NUM_ATTR, if changed */
+ ATTR_ID_BT_PROFILE_DESC_LIST,
+ ATTR_ID_SUPPORTED_FEATURES,
+ ATTR_ID_SERVICE_NAME,
+ ATTR_ID_PROTOCOL_DESC_LIST,
+ ATTR_ID_PROVIDER_NAME};
+
+ A2D_TRACE_API1("A2D_FindService uuid: %x", service_uuid);
+ if( (service_uuid != UUID_SERVCLASS_AUDIO_SOURCE && service_uuid != UUID_SERVCLASS_AUDIO_SINK) ||
+ p_db == NULL || p_db->p_db == NULL || p_cback == NULL)
+ return A2D_INVALID_PARAMS;
+
+ if( a2d_cb.find.service_uuid == UUID_SERVCLASS_AUDIO_SOURCE ||
+ a2d_cb.find.service_uuid == UUID_SERVCLASS_AUDIO_SINK)
+ return A2D_BUSY;
+
+ /* set up discovery database */
+ uuid_list.len = LEN_UUID_16;
+ uuid_list.uu.uuid16 = service_uuid;
+
+ if(p_db->p_attrs == NULL || p_db->num_attr == 0)
+ {
+ p_db->p_attrs = a2d_attr_list;
+ p_db->num_attr = A2D_NUM_ATTR;
+ }
+
+ result = SDP_InitDiscoveryDb(p_db->p_db, p_db->db_len, 1, &uuid_list, p_db->num_attr,
+ p_db->p_attrs);
+
+ if (result == TRUE)
+ {
+ /* store service_uuid and discovery db pointer */
+ a2d_cb.find.p_db = p_db->p_db;
+ a2d_cb.find.service_uuid = service_uuid;
+ a2d_cb.find.p_cback = p_cback;
+
+ /* perform service search */
+ result = SDP_ServiceSearchAttributeRequest(bd_addr, p_db->p_db, a2d_sdp_cback);
+ if(FALSE == result)
+ {
+ a2d_cb.find.service_uuid = 0;
+ }
+ }
+
+ return (result ? A2D_SUCCESS : A2D_FAIL);
+}
+
+/******************************************************************************
+**
+** Function A2D_SetTraceLevel
+**
+** Description Sets the trace level for A2D. If 0xff is passed, the
+** current trace level is returned.
+**
+** Input Parameters:
+** new_level: The level to set the A2D tracing to:
+** 0xff-returns the current setting.
+** 0-turns off tracing.
+** >= 1-Errors.
+** >= 2-Warnings.
+** >= 3-APIs.
+** >= 4-Events.
+** >= 5-Debug.
+**
+** Returns The new trace level or current trace level if
+** the input parameter is 0xff.
+**
+******************************************************************************/
+UINT8 A2D_SetTraceLevel (UINT8 new_level)
+{
+ if (new_level != 0xFF)
+ a2d_cb.trace_level = new_level;
+
+ return (a2d_cb.trace_level);
+}
+
+/******************************************************************************
+** Function A2D_BitsSet
+**
+** Description Check the given num for the number of bits set
+** Returns A2D_SET_ONE_BIT, if one and only one bit is set
+** A2D_SET_ZERO_BIT, if all bits clear
+** A2D_SET_MULTL_BIT, if multiple bits are set
+******************************************************************************/
+UINT8 A2D_BitsSet(UINT8 num)
+{
+ UINT8 count;
+ BOOLEAN res;
+ if(num == 0)
+ res = A2D_SET_ZERO_BIT;
+ else
+ {
+ count = (num & (num - 1));
+ res = ((count==0)?A2D_SET_ONE_BIT:A2D_SET_MULTL_BIT);
+ }
+ return res;
+}
+
+/*******************************************************************************
+**
+** Function A2D_Init
+**
+** Description This function is called to initialize the control block
+** for this layer. It must be called before accessing any
+** other API functions for this layer. It is typically called
+** once during the start up of the stack.
+**
+** Returns void
+**
+*******************************************************************************/
+void A2D_Init(void)
+{
+ memset(&a2d_cb, 0, sizeof(tA2D_CB));
+
+ a2d_cb.avdt_sdp_ver = AVDT_VERSION;
+
+#if defined(A2D_INITIAL_TRACE_LEVEL)
+ a2d_cb.trace_level = A2D_INITIAL_TRACE_LEVEL;
+#else
+ a2d_cb.trace_level = BT_TRACE_LEVEL_NONE;
+#endif
+}
+
diff --git a/stack/a2dp/a2d_int.h b/stack/a2dp/a2d_int.h
new file mode 100644
index 0000000..07cf34c
--- /dev/null
+++ b/stack/a2dp/a2d_int.h
@@ -0,0 +1,70 @@
+/*****************************************************************************
+**
+** Name: a2d_int.h
+**
+** Description:A2DP internal header file
+**
+** Copyright (c) 2002-2009, Broadcom Corp., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef A2D_INT_H
+#define A2D_INT_H
+
+#include "a2d_api.h"
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+#define A2D_VERSION 0x0102
+
+/* Number of attributes in A2D SDP record. */
+#define A2D_NUM_ATTR 6
+
+/* Number of protocol elements in protocol element list. */
+#define A2D_NUM_PROTO_ELEMS 2
+
+/*****************************************************************************
+** Type definitions
+*****************************************************************************/
+
+/* Control block used by A2D_FindService(). */
+typedef struct
+{
+ tA2D_FIND_CBACK *p_cback; /* pointer to application callback */
+ tSDP_DISCOVERY_DB *p_db; /* pointer to discovery database */
+ UINT16 service_uuid; /* service UUID of search */
+} tA2D_FIND_CB;
+
+typedef struct
+{
+ tA2D_FIND_CB find; /* find service control block */
+ UINT8 trace_level;
+ BOOLEAN use_desc;
+ UINT16 avdt_sdp_ver; /* AVDTP version */
+} tA2D_CB;
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/******************************************************************************
+** Main Control Block
+*******************************************************************************/
+#if A2D_DYNAMIC_MEMORY == FALSE
+A2D_API extern tA2D_CB a2d_cb;
+#else
+A2D_API extern tA2D_CB *a2d_cb_ptr;
+#define a2d_cb (*a2d_cb_ptr)
+#endif
+
+/* Used only for conformance testing */
+A2D_API extern void a2d_set_avdt_sdp_ver (UINT16 avdt_sdp_ver);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* A2D_INT_H */
diff --git a/stack/a2dp/a2d_m12.c b/stack/a2dp/a2d_m12.c
new file mode 100644
index 0000000..3c9fb98
--- /dev/null
+++ b/stack/a2dp/a2d_m12.c
@@ -0,0 +1,141 @@
+/*****************************************************************************
+**
+** Name: a2d_m12.c
+**
+** Description:utility functions to help build and parse MPEG-1, 2 Audio
+** Codec Information Element and Media Payload.
+** Copyright (c) 2002-2004, WIDCOMM Inc., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include "bt_target.h"
+
+#if (A2D_M12_INCLUDED == TRUE)
+#include "a2d_api.h"
+#include "a2d_int.h"
+#include "a2d_m12.h"
+
+
+/******************************************************************************
+**
+** Function A2D_BldM12Info
+**
+** Description This function is called by an application to build
+** the MPEG-1, 2 Audio Media Codec Capabilities byte sequence
+** beginning from the LOSC octet.
+** media_type: Indicates Audio, or Multimedia.
+**
+** p_ie: The MPEG-1, 2 Audio Codec Information Element information.
+**
+** Output Parameters:
+** p_result: the resulting codec info byte sequence.
+**
+** Returns A2D_SUCCESS if function execution succeeded.
+** Error status code, otherwise.
+******************************************************************************/
+tA2D_STATUS A2D_BldM12Info(UINT8 media_type, tA2D_M12_CIE *p_ie, UINT8 *p_result)
+{
+ tA2D_STATUS status;
+ UINT8 *p_vbr;
+
+ if( p_ie == NULL || p_result == NULL ||
+ (p_ie->layer & ~A2D_M12_IE_LAYER_MSK) ||
+ (p_ie->ch_mode & ~A2D_M12_IE_CH_MD_MSK) ||
+ (p_ie->samp_freq & ~A2D_M12_IE_SAMP_FREQ_MSK) ||
+ (p_ie->bitrate & ~A2D_M12_IE_BITRATE_MSK))
+ {
+ /* if any unused bit is set */
+ status = A2D_INVALID_PARAMS;
+ }
+ else
+ {
+ status = A2D_SUCCESS;
+ *p_result++ = A2D_M12_INFO_LEN;
+ *p_result++ = media_type;
+ *p_result++ = A2D_MEDIA_CT_M12;
+
+ /* Media Codec Specific Information Element */
+ *p_result = p_ie->layer | p_ie->ch_mode;
+ if(p_ie->crc)
+ *p_result |= A2D_M12_IE_CRC_MSK;
+ p_result++;
+
+ *p_result = p_ie->samp_freq;
+ if(p_ie->mpf)
+ *p_result |= A2D_M12_IE_MPF_MSK;
+ p_result++;
+
+ p_vbr = p_result;
+ UINT16_TO_BE_STREAM(p_result, p_ie->bitrate);
+ if(p_ie->vbr)
+ *p_vbr |= A2D_M12_IE_VBR_MSK;
+ }
+ return status;
+}
+
+/******************************************************************************
+**
+** Function A2D_ParsM12Info
+**
+** Description This function is called by an application to parse
+** the MPEG-1, 2 Audio Media Codec Capabilities byte sequence
+** beginning from the LOSC octet.
+** Input Parameters:
+** p_info: the byte sequence to parse.
+**
+** for_caps: TRUE, if the byte sequence is for get capabilities response.
+**
+** Output Parameters:
+** p_ie: The MPEG-1, 2 Audio Codec Information Element information.
+**
+** Returns A2D_SUCCESS if function execution succeeded.
+** Error status code, otherwise.
+******************************************************************************/
+tA2D_STATUS A2D_ParsM12Info(tA2D_M12_CIE *p_ie, UINT8 *p_info, BOOLEAN for_caps)
+{
+ tA2D_STATUS status;
+ UINT8 losc;
+ UINT8 mt;
+
+ if( p_ie == NULL || p_info == NULL)
+ status = A2D_INVALID_PARAMS;
+ else
+ {
+ losc = *p_info++;
+ mt = *p_info++;
+ /* If the function is called for the wrong Media Type or Media Codec Type */
+ if(losc != A2D_M12_INFO_LEN || *p_info != A2D_MEDIA_CT_M12)
+ status = A2D_WRONG_CODEC;
+ else
+ {
+ p_info++;
+ p_ie->layer = *p_info & A2D_M12_IE_LAYER_MSK;
+ p_ie->crc = (*p_info & A2D_M12_IE_CRC_MSK) >> 4;
+ p_ie->ch_mode = *p_info & A2D_M12_IE_CH_MD_MSK;
+ p_info++;
+ p_ie->mpf = (*p_info & A2D_M12_IE_MPF_MSK) >> 6;
+ p_ie->samp_freq = *p_info & A2D_M12_IE_SAMP_FREQ_MSK;
+ p_info++;
+ p_ie->vbr = (*p_info & A2D_M12_IE_VBR_MSK) >> 7;
+ BE_STREAM_TO_UINT16(p_ie->bitrate, p_info);
+ p_ie->bitrate &= A2D_M12_IE_BITRATE_MSK;
+
+ status = A2D_SUCCESS;
+ if(for_caps == FALSE)
+ {
+ if(A2D_BitsSet(p_ie->layer) != A2D_SET_ONE_BIT)
+ status = A2D_BAD_LAYER;
+ if(A2D_BitsSet(p_ie->ch_mode) != A2D_SET_ONE_BIT)
+ status = A2D_BAD_CH_MODE;
+ if(A2D_BitsSet(p_ie->samp_freq) != A2D_SET_ONE_BIT)
+ status = A2D_BAD_SAMP_FREQ;
+ if((A2D_BitsSet((UINT8)(p_ie->bitrate&0xFF)) +
+ A2D_BitsSet((UINT8)((p_ie->bitrate&0xFF00)>>8)))!= A2D_SET_ONE_BIT)
+ status = A2D_BAD_BIT_RATE;
+ }
+ }
+ }
+ return status;
+}
+
+#endif /* A2D_M12_INCLUDED == TRUE */
diff --git a/stack/a2dp/a2d_m24.c b/stack/a2dp/a2d_m24.c
new file mode 100644
index 0000000..d8df766
--- /dev/null
+++ b/stack/a2dp/a2d_m24.c
@@ -0,0 +1,149 @@
+/*****************************************************************************
+**
+** Name: a2d_m24.c
+**
+** Description:utility functions to help build and parse MPEG-2, 4 AAC
+** Codec Information Element and Media Payload.
+** Copyright (c) 2002-2004, WIDCOMM Inc., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+
+#if (A2D_M24_INCLUDED == TRUE)
+#include "a2d_api.h"
+#include "a2d_int.h"
+#include "a2d_m24.h"
+
+
+/******************************************************************************
+**
+** Function A2D_BldM24Info
+**
+** Description This function is called by an application to build
+** the MPEG-2, 4 AAC Media Codec Capabilities byte sequence
+** beginning from the LOSC octet.
+** Input Parameters:
+** media_type: Indicates Audio, or Multimedia.
+**
+** p_ie: MPEG-2, 4 AAC Codec Information Element information.
+**
+** Output Parameters:
+** p_result: the resulting codec info byte sequence.
+**
+** Returns A2D_SUCCESS if function execution succeeded.
+** Error status code, otherwise.
+******************************************************************************/
+tA2D_STATUS A2D_BldM24Info(UINT8 media_type, tA2D_M24_CIE *p_ie, UINT8 *p_result)
+{
+ tA2D_STATUS status;
+ UINT16 bitrate45;
+
+ if( p_ie == NULL || p_result == NULL ||
+ (p_ie->obj_type & ~A2D_M24_IE_OBJ_MSK) ||
+ (p_ie->samp_freq & ~A2D_M24_IE_SAMP_FREQ_MSK) ||
+ (p_ie->chnl & ~A2D_M24_IE_CHNL_MSK) ||
+ (p_ie->bitrate & ~A2D_M24_IE_BITRATE_MSK))
+ {
+ /* if any unused bit is set */
+ status = A2D_INVALID_PARAMS;
+ }
+ else
+ {
+ status = A2D_SUCCESS;
+ *p_result++ = A2D_M24_INFO_LEN;
+ *p_result++ = media_type;
+ *p_result++ = A2D_MEDIA_CT_M24;
+
+ /* Media Codec Specific Information Element */
+ *p_result++ = p_ie->obj_type;
+
+ UINT16_TO_BE_STREAM(p_result, p_ie->samp_freq);
+ p_result--;
+ *p_result++ |= p_ie->chnl;
+
+ *p_result = (p_ie->bitrate & A2D_M24_IE_BITRATE3_MSK) >> 16;
+ if(p_ie->vbr)
+ *p_result |= A2D_M24_IE_VBR_MSK;
+ p_result++;
+ bitrate45 = (UINT16)(p_ie->bitrate & A2D_M24_IE_BITRATE45_MSK);
+ UINT16_TO_BE_STREAM(p_result, bitrate45);
+ }
+ return status;
+}
+
+/******************************************************************************
+**
+** Function A2D_ParsM24Info
+**
+** Description This function is called by an application to parse
+** the MPEG-2, 4 AAC Media Codec Capabilities byte sequence
+** beginning from the LOSC octet.
+** Input Parameters:
+** p_info: the byte sequence to parse.
+**
+** for_caps: TRUE, if the byte sequence is for get capabilities response.
+**
+** Output Parameters:
+** p_ie: MPEG-2, 4 AAC Codec Information Element information.
+**
+** Returns A2D_SUCCESS if function execution succeeded.
+** Error status code, otherwise.
+******************************************************************************/
+tA2D_STATUS A2D_ParsM24Info(tA2D_M24_CIE *p_ie, UINT8 *p_info, BOOLEAN for_caps)
+{
+ tA2D_STATUS status;
+ UINT8 vbr;
+ UINT16 u16;
+ UINT8 losc;
+ UINT8 mt;
+
+ if( p_ie == NULL || p_info == NULL)
+ status = A2D_INVALID_PARAMS;
+ else
+ {
+ losc = *p_info++;
+ mt = *p_info++;
+ /* If the function is called for the wrong Media Type or Media Codec Type */
+ if(losc != A2D_M24_INFO_LEN || *p_info != A2D_MEDIA_CT_M24)
+ status = A2D_WRONG_CODEC;
+ else
+ {
+ p_info++;
+ p_ie->obj_type = *p_info++;
+ BE_STREAM_TO_UINT16(p_ie->samp_freq, p_info);
+ p_ie->chnl = p_ie->samp_freq & A2D_M24_IE_CHNL_MSK;
+ p_ie->samp_freq &= A2D_M24_IE_SAMP_FREQ_MSK;
+ vbr = *p_info++;
+ BE_STREAM_TO_UINT16(u16, p_info); /* u16 contains the octect4, 5 of bterate */
+
+ p_ie->vbr = (vbr & A2D_M24_IE_VBR_MSK) >> 7;
+ vbr &= ~A2D_M24_IE_VBR_MSK; /* vbr has become the octect3 of bitrate */
+ p_ie->bitrate = vbr;
+ p_ie->bitrate <<= 16;
+ p_ie->bitrate += u16;
+
+ status = A2D_SUCCESS;
+ if(for_caps == FALSE)
+ {
+ if(A2D_BitsSet(p_ie->obj_type) != A2D_SET_ONE_BIT)
+ status = A2D_BAD_OBJ_TYPE;
+
+ if((A2D_BitsSet((UINT8)(p_ie->samp_freq&0xFF)) +
+ A2D_BitsSet((UINT8)((p_ie->samp_freq&0xFF00)>>8)))!= A2D_SET_ONE_BIT)
+ status = A2D_BAD_SAMP_FREQ;
+
+ if(A2D_BitsSet(p_ie->chnl) != A2D_SET_ONE_BIT)
+ status = A2D_BAD_CHANNEL;
+
+ /* BitRate must be greater than zero when specifying AAC configuration */
+ if (p_ie->bitrate == 0)
+ status = A2D_BAD_BIT_RATE;
+ }
+ }
+ }
+ return status;
+}
+#endif /* (A2D_M24_INCLUDED == TRUE) */
+
diff --git a/stack/a2dp/a2d_sbc.c b/stack/a2dp/a2d_sbc.c
new file mode 100644
index 0000000..cec335a
--- /dev/null
+++ b/stack/a2dp/a2d_sbc.c
@@ -0,0 +1,386 @@
+/*****************************************************************************
+**
+** Name: a2d_sbc.c
+**
+** Description:utility functions to help build and parse SBC
+** Codec Information Element and Media Payload.
+** Copyright (c) 2002-2004, WIDCOMM Inc., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include "bt_target.h"
+
+#if (A2D_SBC_INCLUDED == TRUE)
+#include <string.h>
+#include "a2d_api.h"
+#include "a2d_int.h"
+#include "a2d_sbc.h"
+
+/*************************************************************************************************
+ * SBC descramble code
+ * Purpose: to tie the SBC code with BTE/mobile stack code,
+ * especially for the case when the SBC is ported into a third-party Multimedia chip
+ *
+ * Algorithm:
+ * init process: all counters reset to 0,
+ * calculate base_index: (6 + s16NumOfChannels*s16NumOfSubBands/2)
+ * scramble side: the init process happens every time SBC_Encoder_Init() is called.
+ * descramble side: it would be nice to know if he "init" process has happened.
+ * alter the SBC SYNC word 0x9C (1001 1100) to 0x8C (1000 1100).
+ *
+ * scramble process:
+ * The CRC byte:
+ * Every SBC frame has a frame header.
+ * The 1st byte is the sync word and the following 2 bytes are about the stream format.
+ * They are supposed to be "constant" within a "song"
+ * The 4th byte is the CRC byte. The CRC byte is bound to be random.
+ * Derive 2 items from the CRC byte; one is the "use" bit, the other is the "index".
+ *
+ * SBC keeps 2 sets of "use" & "index"; derived the current and the previous frame.
+ *
+ * The "use" bit is any bit in SBC_PRTC_USE_MASK is set.
+ * If set, SBC uses the "index" from the current frame.
+ * If not set, SBC uses the "index" from the previous frame or 0.
+ *
+ * index = (CRC & 0x3) + ((CRC & 0x30) >> 2) // 8 is the max index
+ *
+ * if(index > 0)
+ * {
+ * p = &u8frame[base_index];
+ * if((index&1)&&(u16PacketLength > (base_index+index*2)))
+ * {
+ * // odd index: swap 2 bytes
+ * tmp = p[index];
+ * p[index] = p[index*2];
+ * p[index*2] = tmp;
+ * }
+ * else
+ * {
+ * // even index: shift by 3
+ * tmp = (p[index] >> 3) + (p[index] << 5);
+ * p[index] = tmp;
+ * }
+ * }
+ * //else index is 0. The frame stays unaltered
+ *
+ */
+#define A2D_SBC_SYNC_WORD 0x9C
+#define A2D_SBC_CRC_IDX 3
+#define A2D_SBC_USE_MASK 0x64
+#define A2D_SBC_SYNC_MASK 0x10
+#define A2D_SBC_CIDX 0
+#define A2D_SBC_LIDX 1
+#define A2D_SBC_CH_M_BITS 0xC /* channel mode bits: 0: mono; 1 ch */
+#define A2D_SBC_SUBBAND_BIT 0x1 /* num of subband bit: 0:4; 1: 8 */
+
+#define A2D_SBC_GET_IDX(sc) (((sc) & 0x3) + (((sc) & 0x30) >> 2))
+
+typedef struct
+{
+ UINT8 use;
+ UINT8 idx;
+} tA2D_SBC_FR_CB;
+
+typedef struct
+{
+ tA2D_SBC_FR_CB fr[2];
+ UINT8 index;
+ UINT8 base;
+} tA2D_SBC_DS_CB;
+
+static tA2D_SBC_DS_CB a2d_sbc_ds_cb;
+/*int a2d_count = 0;*/
+/******************************************************************************
+**
+** Function A2D_SbcChkFrInit
+**
+** Description check if need to init the descramble control block.
+**
+** Returns nothing.
+******************************************************************************/
+void A2D_SbcChkFrInit(UINT8 *p_pkt)
+{
+ UINT8 fmt;
+ UINT8 num_chnl = 1;
+ UINT8 num_subband = 4;
+
+ if((p_pkt[0] & A2D_SBC_SYNC_MASK) == 0)
+ {
+ a2d_cb.use_desc = TRUE;
+ fmt = p_pkt[1];
+ p_pkt[0] |= A2D_SBC_SYNC_MASK;
+ memset(&a2d_sbc_ds_cb, 0, sizeof(tA2D_SBC_DS_CB));
+ if(fmt & A2D_SBC_CH_M_BITS)
+ num_chnl = 2;
+ if(fmt & A2D_SBC_SUBBAND_BIT)
+ num_subband = 8;
+ a2d_sbc_ds_cb.base = 6 + num_chnl*num_subband/2;
+ /*printf("base: %d\n", a2d_sbc_ds_cb.base);
+ a2d_count = 0;*/
+ }
+}
+
+/******************************************************************************
+**
+** Function A2D_SbcDescramble
+**
+** Description descramble the packet.
+**
+** Returns nothing.
+******************************************************************************/
+void A2D_SbcDescramble(UINT8 *p_pkt, UINT16 len)
+{
+ tA2D_SBC_FR_CB *p_cur, *p_last;
+ UINT32 idx, tmp, tmp2;
+
+ if(a2d_cb.use_desc)
+ {
+ /* c2l */
+ p_last = &a2d_sbc_ds_cb.fr[A2D_SBC_LIDX];
+ p_cur = &a2d_sbc_ds_cb.fr[A2D_SBC_CIDX];
+ p_last->idx = p_cur->idx;
+ p_last->use = p_cur->use;
+ /* getc */
+ p_cur->use = p_pkt[A2D_SBC_CRC_IDX] & A2D_SBC_USE_MASK;
+ p_cur->idx = A2D_SBC_GET_IDX(p_pkt[A2D_SBC_CRC_IDX]);
+ a2d_sbc_ds_cb.index = (p_cur->use)?A2D_SBC_CIDX:A2D_SBC_LIDX;
+ /*
+ printf("%05d: ar[%02d]: x%02x, msk: x%02x, use: %s, idx: %02d, ",
+ a2d_count++,
+ A2D_SBC_CRC_IDX, p_pkt[A2D_SBC_CRC_IDX], A2D_SBC_USE_MASK,
+ (p_cur->use)?"cur":"lst", p_cur->idx);
+ */
+ /* descramble */
+ idx = a2d_sbc_ds_cb.fr[a2d_sbc_ds_cb.index].idx;
+ if(idx > 0)
+ {
+ p_pkt = &p_pkt[a2d_sbc_ds_cb.base];
+ if((idx&1) && (len > (a2d_sbc_ds_cb.base+(idx<<1))))
+ {
+ tmp2 = (idx<<1);
+ tmp = p_pkt[idx];
+ p_pkt[idx] = p_pkt[tmp2];
+ p_pkt[tmp2] = tmp;
+ /*
+ printf("tmp2: %02d, len: %d, idx: %d\n",
+ tmp2, len, a2d_sbc_ds_cb.fr[a2d_sbc_ds_cb.index].idx);
+ */
+ }
+ else
+ {
+ tmp2 = p_pkt[idx];
+ tmp = (tmp2>>3)+(tmp2<<5);
+ p_pkt[idx] = (UINT8)tmp;
+ /*
+ printf("tmp: x%02x, len: %d, idx: %d(cmp:%d)\n",
+ (UINT8)tmp2, len, a2d_sbc_ds_cb.fr[a2d_sbc_ds_cb.index].idx,
+ (a2d_sbc_ds_cb.base+(idx<<1)));
+ */
+ }
+ }
+ /*
+ else
+ {
+ printf("!!!!\n");
+ }
+ */
+ }
+}
+
+/******************************************************************************
+**
+** Function A2D_BldSbcInfo
+**
+** Description This function is called by an application to build
+** the SBC Media Codec Capabilities byte sequence
+** beginning from the LOSC octet.
+** Input Parameters:
+** media_type: Indicates Audio, or Multimedia.
+**
+** p_ie: The SBC Codec Information Element information.
+**
+** Output Parameters:
+** p_result: the resulting codec info byte sequence.
+**
+** Returns A2D_SUCCESS if function execution succeeded.
+** Error status code, otherwise.
+******************************************************************************/
+tA2D_STATUS A2D_BldSbcInfo(UINT8 media_type, tA2D_SBC_CIE *p_ie, UINT8 *p_result)
+{
+ tA2D_STATUS status;
+
+ if( p_ie == NULL || p_result == NULL ||
+ (p_ie->samp_freq & ~A2D_SBC_IE_SAMP_FREQ_MSK) ||
+ (p_ie->ch_mode & ~A2D_SBC_IE_CH_MD_MSK) ||
+ (p_ie->block_len & ~A2D_SBC_IE_BLOCKS_MSK) ||
+ (p_ie->num_subbands & ~A2D_SBC_IE_SUBBAND_MSK) ||
+ (p_ie->alloc_mthd & ~A2D_SBC_IE_ALLOC_MD_MSK) ||
+ (p_ie->max_bitpool < p_ie->min_bitpool) ||
+ (p_ie->max_bitpool < A2D_SBC_IE_MIN_BITPOOL) ||
+ (p_ie->max_bitpool > A2D_SBC_IE_MAX_BITPOOL) ||
+ (p_ie->min_bitpool < A2D_SBC_IE_MIN_BITPOOL) ||
+ (p_ie->min_bitpool > A2D_SBC_IE_MAX_BITPOOL) )
+ {
+ /* if any unused bit is set */
+ status = A2D_INVALID_PARAMS;
+ }
+ else
+ {
+ status = A2D_SUCCESS;
+ *p_result++ = A2D_SBC_INFO_LEN;
+ *p_result++ = media_type;
+ *p_result++ = A2D_MEDIA_CT_SBC;
+
+ /* Media Codec Specific Information Element */
+ *p_result++ = p_ie->samp_freq | p_ie->ch_mode;
+
+ *p_result++ = p_ie->block_len | p_ie->num_subbands | p_ie->alloc_mthd;
+
+ *p_result++ = p_ie->min_bitpool;
+ *p_result = p_ie->max_bitpool;
+ }
+ return status;
+}
+
+/******************************************************************************
+**
+** Function A2D_ParsSbcInfo
+**
+** Description This function is called by an application to parse
+** the SBC Media Codec Capabilities byte sequence
+** beginning from the LOSC octet.
+** Input Parameters:
+** p_info: the byte sequence to parse.
+**
+** for_caps: TRUE, if the byte sequence is for get capabilities response.
+**
+** Output Parameters:
+** p_ie: The SBC Codec Information Element information.
+**
+** Returns A2D_SUCCESS if function execution succeeded.
+** Error status code, otherwise.
+******************************************************************************/
+tA2D_STATUS A2D_ParsSbcInfo(tA2D_SBC_CIE *p_ie, UINT8 *p_info, BOOLEAN for_caps)
+{
+ tA2D_STATUS status;
+ UINT8 losc;
+ UINT8 mt;
+
+ if( p_ie == NULL || p_info == NULL)
+ status = A2D_INVALID_PARAMS;
+ else
+ {
+ losc = *p_info++;
+ mt = *p_info++;
+ /* If the function is called for the wrong Media Type or Media Codec Type */
+ if(losc != A2D_SBC_INFO_LEN || *p_info != A2D_MEDIA_CT_SBC)
+ status = A2D_WRONG_CODEC;
+ else
+ {
+ p_info++;
+ p_ie->samp_freq = *p_info & A2D_SBC_IE_SAMP_FREQ_MSK;
+ p_ie->ch_mode = *p_info & A2D_SBC_IE_CH_MD_MSK;
+ p_info++;
+ p_ie->block_len = *p_info & A2D_SBC_IE_BLOCKS_MSK;
+ p_ie->num_subbands = *p_info & A2D_SBC_IE_SUBBAND_MSK;
+ p_ie->alloc_mthd = *p_info & A2D_SBC_IE_ALLOC_MD_MSK;
+ p_info++;
+ p_ie->min_bitpool = *p_info++;
+ p_ie->max_bitpool = *p_info;
+ status = A2D_SUCCESS;
+ if(p_ie->min_bitpool < A2D_SBC_IE_MIN_BITPOOL || p_ie->min_bitpool > A2D_SBC_IE_MAX_BITPOOL )
+ status = A2D_BAD_MIN_BITPOOL;
+
+ if(p_ie->max_bitpool < A2D_SBC_IE_MIN_BITPOOL || p_ie->max_bitpool > A2D_SBC_IE_MAX_BITPOOL ||
+ p_ie->max_bitpool < p_ie->min_bitpool)
+ status = A2D_BAD_MAX_BITPOOL;
+
+ if(for_caps == FALSE)
+ {
+ if(A2D_BitsSet(p_ie->samp_freq) != A2D_SET_ONE_BIT)
+ status = A2D_BAD_SAMP_FREQ;
+ if(A2D_BitsSet(p_ie->ch_mode) != A2D_SET_ONE_BIT)
+ status = A2D_BAD_CH_MODE;
+ if(A2D_BitsSet(p_ie->block_len) != A2D_SET_ONE_BIT)
+ status = A2D_BAD_BLOCK_LEN;
+ if(A2D_BitsSet(p_ie->num_subbands) != A2D_SET_ONE_BIT)
+ status = A2D_BAD_SUBBANDS;
+ if(A2D_BitsSet(p_ie->alloc_mthd) != A2D_SET_ONE_BIT)
+ status = A2D_BAD_ALLOC_MTHD;
+ }
+ }
+ }
+ return status;
+}
+
+/******************************************************************************
+**
+** Function A2D_BldSbcMplHdr
+**
+** Description This function is called by an application to parse
+** the SBC Media Payload header.
+** Input Parameters:
+** frag: 1, if fragmented. 0, otherwise.
+**
+** start: 1, if the starting packet of a fragmented frame.
+**
+** last: 1, if the last packet of a fragmented frame.
+**
+** num: If frag is 1, this is the number of remaining fragments
+** (including this fragment) of this frame.
+** If frag is 0, this is the number of frames in this packet.
+**
+** Output Parameters:
+** p_dst: the resulting media payload header byte sequence.
+**
+** Returns void.
+******************************************************************************/
+void A2D_BldSbcMplHdr(UINT8 *p_dst, BOOLEAN frag, BOOLEAN start, BOOLEAN last, UINT8 num)
+{
+ if(p_dst)
+ {
+ *p_dst = 0;
+ if(frag)
+ *p_dst |= A2D_SBC_HDR_F_MSK;
+ if(start)
+ *p_dst |= A2D_SBC_HDR_S_MSK;
+ if(last)
+ *p_dst |= A2D_SBC_HDR_L_MSK;
+ *p_dst |= (A2D_SBC_HDR_NUM_MSK & num);
+ }
+}
+
+/******************************************************************************
+**
+** Function A2D_ParsSbcMplHdr
+**
+** Description This function is called by an application to parse
+** the SBC Media Payload header.
+** Input Parameters:
+** p_src: the byte sequence to parse..
+**
+** Output Parameters:
+** frag: 1, if fragmented. 0, otherwise.
+**
+** start: 1, if the starting packet of a fragmented frame.
+**
+** last: 1, if the last packet of a fragmented frame.
+**
+** num: If frag is 1, this is the number of remaining fragments
+** (including this fragment) of this frame.
+** If frag is 0, this is the number of frames in this packet.
+**
+** Returns void.
+******************************************************************************/
+void A2D_ParsSbcMplHdr(UINT8 *p_src, BOOLEAN *p_frag, BOOLEAN *p_start, BOOLEAN *p_last, UINT8 *p_num)
+{
+ if(p_src && p_frag && p_start && p_last && p_num)
+ {
+ *p_frag = (*p_src & A2D_SBC_HDR_F_MSK) ? TRUE: FALSE;
+ *p_start= (*p_src & A2D_SBC_HDR_S_MSK) ? TRUE: FALSE;
+ *p_last = (*p_src & A2D_SBC_HDR_L_MSK) ? TRUE: FALSE;
+ *p_num = (*p_src & A2D_SBC_HDR_NUM_MSK);
+ }
+}
+
+#endif /* A2D_SBC_INCLUDED == TRUE */
diff --git a/stack/avct/avct_api.c b/stack/avct/avct_api.c
new file mode 100644
index 0000000..d1d5cee
--- /dev/null
+++ b/stack/avct/avct_api.c
@@ -0,0 +1,453 @@
+/*****************************************************************************
+**
+** Name: avct_api.c
+**
+** Description: This module contains API of the audio/video control
+** transport protocol.
+**
+** Copyright (c) 2003-2008, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include <string.h>
+#include "data_types.h"
+#include "bt_target.h"
+#include "gki.h"
+#include "l2c_api.h"
+#include "l2cdefs.h"
+#include "btm_api.h"
+#include "avct_api.h"
+#include "avct_int.h"
+
+/* Control block for AVCT */
+#if AVCT_DYNAMIC_MEMORY == FALSE
+tAVCT_CB avct_cb;
+#endif
+
+/*******************************************************************************
+**
+** Function AVCT_Register
+**
+** Description This is the system level registration function for the
+** AVCTP protocol. This function initializes AVCTP and
+** prepares the protocol stack for its use. This function
+** must be called once by the system or platform using AVCTP
+** before the other functions of the API an be used.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void AVCT_Register(UINT16 mtu, UINT16 mtu_br, UINT8 sec_mask)
+{
+ AVCT_TRACE_API0("AVCT_Register");
+
+ /* register PSM with L2CAP */
+ L2CA_Register(AVCT_PSM, (tL2CAP_APPL_INFO *) &avct_l2c_appl);
+
+ /* set security level */
+ BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_AVCTP, sec_mask, AVCT_PSM, 0, 0);
+ BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_AVCTP, sec_mask, AVCT_PSM, 0, 0);
+
+ /* initialize AVCTP data structures */
+ memset(&avct_cb, 0, sizeof(tAVCT_CB));
+
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+ /* Include the browsing channel which uses eFCR */
+ L2CA_Register(AVCT_BR_PSM, (tL2CAP_APPL_INFO *) &avct_l2c_br_appl);
+
+ BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_AVCTP_BROWSE, sec_mask, AVCT_BR_PSM, 0, 0);
+ BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_AVCTP_BROWSE, sec_mask, AVCT_BR_PSM, 0, 0);
+
+ if (mtu_br < AVCT_MIN_BROWSE_MTU)
+ mtu_br = AVCT_MIN_BROWSE_MTU;
+ avct_cb.mtu_br = mtu_br;
+#endif
+
+#if defined(AVCT_INITIAL_TRACE_LEVEL)
+ avct_cb.trace_level = AVCT_INITIAL_TRACE_LEVEL;
+#else
+ avct_cb.trace_level = BT_TRACE_LEVEL_NONE;
+#endif
+
+ if (mtu < AVCT_MIN_CONTROL_MTU)
+ mtu = AVCT_MIN_CONTROL_MTU;
+ /* store mtu */
+ avct_cb.mtu = mtu;
+}
+
+/*******************************************************************************
+**
+** Function AVCT_Deregister
+**
+** Description This function is called to deregister use AVCTP protocol.
+** It is called when AVCTP is no longer being used by any
+** application in the system. Before this function can be
+** called, all connections must be removed with
+** AVCT_RemoveConn().
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void AVCT_Deregister(void)
+{
+ AVCT_TRACE_API0("AVCT_Deregister");
+
+ /* deregister PSM with L2CAP */
+ L2CA_Deregister(AVCT_PSM);
+}
+
+/*******************************************************************************
+**
+** Function AVCT_CreateConn
+**
+** Description Create an AVCTP connection. There are two types of
+** connections, initiator and acceptor, as determined by
+** the p_cc->role parameter. When this function is called to
+** create an initiator connection, an AVCTP connection to
+** the peer device is initiated if one does not already exist.
+** If an acceptor connection is created, the connection waits
+** passively for an incoming AVCTP connection from a peer device.
+**
+**
+** Returns AVCT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+UINT16 AVCT_CreateConn(UINT8 *p_handle, tAVCT_CC *p_cc, BD_ADDR peer_addr)
+{
+ UINT16 result = AVCT_SUCCESS;
+ tAVCT_CCB *p_ccb;
+ tAVCT_LCB *p_lcb;
+
+ AVCT_TRACE_API2("AVCT_CreateConn: %d, control:%d", p_cc->role, p_cc->control);
+
+ /* Allocate ccb; if no ccbs, return failure */
+ if ((p_ccb = avct_ccb_alloc(p_cc)) == NULL)
+ {
+ result = AVCT_NO_RESOURCES;
+ }
+ else
+ {
+ /* get handle */
+ *p_handle = avct_ccb_to_idx(p_ccb);
+
+ /* if initiator connection */
+ if (p_cc->role == AVCT_INT)
+ {
+ /* find link; if none allocate a new one */
+ if ((p_lcb = avct_lcb_by_bd(peer_addr)) == NULL)
+ {
+ if ((p_lcb = avct_lcb_alloc(peer_addr)) == NULL)
+ {
+ /* no link resources; free ccb as well */
+ avct_ccb_dealloc(p_ccb, AVCT_NO_EVT, 0, NULL);
+ result = AVCT_NO_RESOURCES;
+ }
+ }
+ /* check if PID already in use */
+ else if (avct_lcb_has_pid(p_lcb, p_cc->pid))
+ {
+ avct_ccb_dealloc(p_ccb, AVCT_NO_EVT, 0, NULL);
+ result = AVCT_PID_IN_USE;
+ }
+
+ if (result == AVCT_SUCCESS)
+ {
+ /* bind lcb to ccb */
+ p_ccb->p_lcb = p_lcb;
+ AVCT_TRACE_DEBUG1("ch_state: %d", p_lcb->ch_state);
+ avct_lcb_event(p_lcb, AVCT_LCB_UL_BIND_EVT, (tAVCT_LCB_EVT *) &p_ccb);
+ }
+ }
+ }
+ return result;
+}
+
+/*******************************************************************************
+**
+** Function AVCT_RemoveConn
+**
+** Description Remove an AVCTP connection. This function is called when
+** the application is no longer using a connection. If this
+** is the last connection to a peer the L2CAP channel for AVCTP
+** will be closed.
+**
+**
+** Returns AVCT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+UINT16 AVCT_RemoveConn(UINT8 handle)
+{
+ UINT16 result = AVCT_SUCCESS;
+ tAVCT_CCB *p_ccb;
+
+ AVCT_TRACE_API0("AVCT_RemoveConn");
+
+ /* map handle to ccb */
+ if ((p_ccb = avct_ccb_by_idx(handle)) == NULL)
+ {
+ result = AVCT_BAD_HANDLE;
+ }
+ /* if connection not bound to lcb, dealloc */
+ else if (p_ccb->p_lcb == NULL)
+ {
+ avct_ccb_dealloc(p_ccb, AVCT_NO_EVT, 0, NULL);
+ }
+ /* send unbind event to lcb */
+ else
+ {
+ avct_lcb_event(p_ccb->p_lcb, AVCT_LCB_UL_UNBIND_EVT, (tAVCT_LCB_EVT *) &p_ccb);
+ }
+ return result;
+}
+
+/*******************************************************************************
+**
+** Function AVCT_CreateBrowse
+**
+** Description Create an AVCTP Browse channel. There are two types of
+** connections, initiator and acceptor, as determined by
+** the role parameter. When this function is called to
+** create an initiator connection, the Browse channel to
+** the peer device is initiated if one does not already exist.
+** If an acceptor connection is created, the connection waits
+** passively for an incoming AVCTP connection from a peer device.
+**
+**
+** Returns AVCT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+UINT16 AVCT_CreateBrowse (UINT8 handle, UINT8 role)
+{
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+ UINT16 result = AVCT_SUCCESS;
+ tAVCT_CCB *p_ccb;
+ tAVCT_BCB *p_bcb;
+ int index;
+
+ AVCT_TRACE_API1("AVCT_CreateBrowse: %d", role);
+
+ /* map handle to ccb */
+ if ((p_ccb = avct_ccb_by_idx(handle)) == NULL)
+ {
+ return AVCT_BAD_HANDLE;
+ }
+ else
+ {
+ /* mark this CCB as supporting browsing channel */
+ if ((p_ccb->allocated & AVCT_ALOC_BCB) == 0)
+ {
+ p_ccb->allocated |= AVCT_ALOC_BCB;
+ }
+ }
+
+ /* if initiator connection */
+ if (role == AVCT_INT)
+ {
+ /* the link control block must exist before this function is called as INT. */
+ if (p_ccb->p_lcb == NULL)
+ {
+ result = AVCT_NOT_OPEN;
+ }
+ else
+ {
+ /* find link; if none allocate a new one */
+ index = p_ccb->p_lcb->allocated;
+ if (index > AVCT_NUM_LINKS)
+ {
+ result = AVCT_BAD_HANDLE;
+ }
+ else
+ {
+ p_bcb = &avct_cb.bcb[index - 1];
+ p_bcb->allocated = index;
+ }
+ }
+
+ if (result == AVCT_SUCCESS)
+ {
+ /* bind bcb to ccb */
+ p_ccb->p_bcb = p_bcb;
+ AVCT_TRACE_DEBUG1("ch_state: %d", p_bcb->ch_state);
+ avct_bcb_event(p_bcb, AVCT_LCB_UL_BIND_EVT, (tAVCT_LCB_EVT *) &p_ccb);
+ }
+ }
+
+ return result;
+#else
+ return AVCT_NO_RESOURCES;
+#endif
+}
+
+/*******************************************************************************
+**
+** Function AVCT_RemoveBrowse
+**
+** Description Remove an AVCTP Browse channel. This function is called when
+** the application is no longer using a connection. If this
+** is the last connection to a peer the L2CAP channel for AVCTP
+** will be closed.
+**
+**
+** Returns AVCT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+UINT16 AVCT_RemoveBrowse (UINT8 handle)
+{
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+ UINT16 result = AVCT_SUCCESS;
+ tAVCT_CCB *p_ccb;
+
+ AVCT_TRACE_API0("AVCT_RemoveBrowse");
+
+ /* map handle to ccb */
+ if ((p_ccb = avct_ccb_by_idx(handle)) == NULL)
+ {
+ result = AVCT_BAD_HANDLE;
+ }
+ else if (p_ccb->p_bcb != NULL)
+ /* send unbind event to bcb */
+ {
+ avct_bcb_event(p_ccb->p_bcb, AVCT_LCB_UL_UNBIND_EVT, (tAVCT_LCB_EVT *) &p_ccb);
+ }
+ return result;
+#else
+ return AVCT_NO_RESOURCES;
+#endif
+}
+
+/*******************************************************************************
+**
+** Function AVCT_GetBrowseMtu
+**
+** Description Get the peer_mtu for the AVCTP Browse channel of the given
+** connection.
+**
+** Returns the peer browsing channel MTU.
+**
+*******************************************************************************/
+UINT16 AVCT_GetBrowseMtu (UINT8 handle)
+{
+ UINT16 peer_mtu = AVCT_MIN_BROWSE_MTU;
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+ tAVCT_CCB *p_ccb;
+
+ if ((p_ccb = avct_ccb_by_idx(handle)) != NULL && p_ccb->p_bcb != NULL)
+ {
+ peer_mtu = p_ccb->p_bcb->peer_mtu;
+ }
+#endif
+ return peer_mtu;
+}
+
+/*******************************************************************************
+**
+** Function AVCT_GetPeerMtu
+**
+** Description Get the peer_mtu for the AVCTP channel of the given
+** connection.
+**
+** Returns the peer MTU size.
+**
+*******************************************************************************/
+UINT16 AVCT_GetPeerMtu (UINT8 handle)
+{
+ UINT16 peer_mtu = L2CAP_DEFAULT_MTU;
+ tAVCT_CCB *p_ccb;
+
+ /* map handle to ccb */
+ if ((p_ccb = avct_ccb_by_idx(handle)) != NULL)
+ {
+ if (p_ccb->p_lcb)
+ {
+ peer_mtu = p_ccb->p_lcb->peer_mtu;
+ }
+ }
+
+ return peer_mtu;
+}
+
+/*******************************************************************************
+**
+** Function AVCT_MsgReq
+**
+** Description Send an AVCTP message to a peer device. In calling
+** AVCT_MsgReq(), the application should keep track of the
+** congestion state of AVCTP as communicated with events
+** AVCT_CONG_IND_EVT and AVCT_UNCONG_IND_EVT. If the
+** application calls AVCT_MsgReq() when AVCTP is congested
+** the message may be discarded. The application may make its
+** first call to AVCT_MsgReq() after it receives an
+** AVCT_CONNECT_CFM_EVT or AVCT_CONNECT_IND_EVT on control channel or
+** AVCT_BROWSE_CONN_CFM_EVT or AVCT_BROWSE_CONN_IND_EVT on browsing channel.
+**
+** p_msg->layer_specific must be set to
+** AVCT_DATA_CTRL for control channel traffic;
+** AVCT_DATA_BROWSE for for browse channel traffic.
+**
+** Returns AVCT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+UINT16 AVCT_MsgReq(UINT8 handle, UINT8 label, UINT8 cr, BT_HDR *p_msg)
+{
+ UINT16 result = AVCT_SUCCESS;
+ tAVCT_CCB *p_ccb;
+ tAVCT_UL_MSG ul_msg;
+
+ AVCT_TRACE_API0("AVCT_MsgReq");
+
+ /* verify p_msg parameter */
+ if (p_msg == NULL)
+ {
+ return AVCT_NO_RESOURCES;
+ }
+ AVCT_TRACE_API1("len: %d", p_msg->len);
+
+ /* map handle to ccb */
+ if ((p_ccb = avct_ccb_by_idx(handle)) == NULL)
+ {
+ result = AVCT_BAD_HANDLE;
+ GKI_freebuf(p_msg);
+ }
+ /* verify channel is bound to link */
+ else if (p_ccb->p_lcb == NULL)
+ {
+ result = AVCT_NOT_OPEN;
+ GKI_freebuf(p_msg);
+ }
+
+ if (result == AVCT_SUCCESS)
+ {
+ ul_msg.p_buf = p_msg;
+ ul_msg.p_ccb = p_ccb;
+ ul_msg.label = label;
+ ul_msg.cr = cr;
+
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+ /* send msg event to bcb */
+ if (p_msg->layer_specific == AVCT_DATA_BROWSE)
+ {
+ if (p_ccb->p_bcb == NULL && (p_ccb->allocated & AVCT_ALOC_BCB) == 0)
+ {
+ /* BCB channel is not open and not allocated */
+ result = AVCT_BAD_HANDLE;
+ GKI_freebuf(p_msg);
+ }
+ else
+ {
+ p_ccb->p_bcb = avct_bcb_by_lcb(p_ccb->p_lcb);
+ avct_bcb_event(p_ccb->p_bcb, AVCT_LCB_UL_MSG_EVT, (tAVCT_LCB_EVT *) &ul_msg);
+ }
+ }
+ /* send msg event to lcb */
+ else
+#endif
+ {
+ avct_lcb_event(p_ccb->p_lcb, AVCT_LCB_UL_MSG_EVT, (tAVCT_LCB_EVT *) &ul_msg);
+ }
+ }
+ return result;
+}
+
diff --git a/stack/avct/avct_bcb_act.c b/stack/avct/avct_bcb_act.c
new file mode 100644
index 0000000..ad6d651
--- /dev/null
+++ b/stack/avct/avct_bcb_act.c
@@ -0,0 +1,749 @@
+/*****************************************************************************
+**
+** Name: avct_bcb_act.c
+**
+** Description: This module contains action functions of the browsing control
+** state machine.
+**
+** Copyright (c) 2003-2008, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include <string.h>
+#include "data_types.h"
+#include "bt_target.h"
+#include "avct_api.h"
+#include "avct_int.h"
+#include "gki.h"
+
+
+#include "btm_api.h"
+
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/* action function list */
+const tAVCT_BCB_ACTION avct_bcb_action[] = {
+ avct_bcb_chnl_open, /* AVCT_LCB_CHNL_OPEN */
+ avct_bcb_chnl_disc, /* AVCT_LCB_CHNL_DISC */
+ avct_bcb_send_msg, /* AVCT_LCB_SEND_MSG */
+ avct_bcb_open_ind, /* AVCT_LCB_OPEN_IND */
+ avct_bcb_open_fail, /* AVCT_LCB_OPEN_FAIL */
+ avct_bcb_close_ind, /* AVCT_LCB_CLOSE_IND */
+ avct_bcb_close_cfm, /* AVCT_LCB_CLOSE_CFM */
+ avct_bcb_msg_ind, /* AVCT_LCB_MSG_IND */
+ avct_bcb_cong_ind, /* AVCT_LCB_CONG_IND */
+ avct_bcb_bind_conn, /* AVCT_LCB_BIND_CONN */
+ avct_bcb_bind_fail, /* AVCT_LCB_BIND_FAIL */
+ avct_bcb_unbind_disc, /* AVCT_LCB_UNBIND_DISC */
+ avct_bcb_chk_disc, /* AVCT_LCB_CHK_DISC */
+ avct_bcb_discard_msg, /* AVCT_LCB_DISCARD_MSG */
+ avct_bcb_dealloc, /* AVCT_LCB_DEALLOC */
+ avct_bcb_free_msg_ind /* AVCT_LCB_FREE_MSG_IND */
+};
+
+
+/*******************************************************************************
+**
+** Function avct_bcb_msg_asmbl
+**
+** Description Reassemble incoming message.
+**
+**
+** Returns Pointer to reassembled message; NULL if no message
+** available.
+**
+*******************************************************************************/
+static BT_HDR *avct_bcb_msg_asmbl(tAVCT_BCB *p_bcb, BT_HDR *p_buf)
+{
+ UINT8 *p;
+ UINT8 pkt_type;
+ BT_HDR *p_ret = NULL;
+
+ /* parse the message header */
+ p = (UINT8 *)(p_buf + 1) + p_buf->offset;
+ AVCT_PRS_PKT_TYPE(p, pkt_type);
+
+ /* must be single packet - can not fragment */
+ if (pkt_type == AVCT_PKT_TYPE_SINGLE)
+ {
+ p_ret = p_buf;
+ }
+ else
+ {
+ GKI_freebuf(p_buf);
+ AVCT_TRACE_WARNING1("Pkt type=%d - fragmentation not allowed. drop it", pkt_type);
+ }
+ return p_ret;
+}
+
+
+/*******************************************************************************
+**
+** Function avct_bcb_chnl_open
+**
+** Description Open L2CAP channel to peer
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_bcb_chnl_open(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+ UINT16 result = AVCT_RESULT_FAIL;
+ tAVCT_LCB *p_lcb = avct_lcb_by_bcb(p_bcb);
+ tL2CAP_ERTM_INFO ertm_info;
+
+ BTM_SetOutService(p_lcb->peer_addr, BTM_SEC_SERVICE_AVCTP_BROWSE, 0);
+
+ /* Set the FCR options: Browsing channel mandates ERTM */
+ ertm_info.preferred_mode = avct_l2c_br_fcr_opts_def.mode;
+ ertm_info.allowed_modes = L2CAP_FCR_CHAN_OPT_ERTM;
+ ertm_info.user_rx_pool_id = AVCT_BR_USER_RX_POOL_ID;
+ ertm_info.user_tx_pool_id = AVCT_BR_USER_TX_POOL_ID;
+ ertm_info.fcr_rx_pool_id = AVCT_BR_FCR_RX_POOL_ID;
+ ertm_info.fcr_tx_pool_id = AVCT_BR_FCR_TX_POOL_ID;
+
+ /* call l2cap connect req */
+ p_bcb->ch_state = AVCT_CH_CONN;
+ if ((p_bcb->ch_lcid = L2CA_ErtmConnectReq(AVCT_BR_PSM, p_lcb->peer_addr, &ertm_info)) == 0)
+ {
+ /* if connect req failed, send ourselves close event */
+ avct_bcb_event(p_bcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT *) &result);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avct_bcb_unbind_disc
+**
+** Description call callback with disconnect event.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_bcb_unbind_disc(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+ p_data->p_ccb->p_bcb = NULL;
+ (*p_data->p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_data->p_ccb), AVCT_BROWSE_DISCONN_CFM_EVT, 0, NULL);
+}
+
+/*******************************************************************************
+**
+** Function avct_bcb_open_ind
+**
+** Description Handle an LL_OPEN event. For each allocated ccb already
+** bound to this lcb, send a connect event. For each
+** unbound ccb with a new PID, bind that ccb to this lcb and
+** send a connect event.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_bcb_open_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+ tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
+ tAVCT_CCB *p_ccb_bind = NULL;
+ int i;
+ BOOLEAN bind = FALSE;
+ tAVCT_UL_MSG ul_msg;
+
+ for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
+ {
+ /* if ccb allocated and */
+ if (p_ccb->allocated)
+ {
+ /* if bound to this lcb send connect confirm event */
+ if (p_ccb->p_bcb == p_bcb)
+ {
+ bind = TRUE;
+ p_ccb_bind = p_ccb;
+ p_ccb->cc.p_ctrl_cback(avct_ccb_to_idx(p_ccb), AVCT_BROWSE_CONN_CFM_EVT,
+ 0, p_ccb->p_lcb->peer_addr);
+ }
+ /* if unbound acceptor and lcb e */
+ else if ((p_ccb->p_bcb == NULL) && (p_ccb->cc.role == AVCT_ACP) &&
+ (p_ccb->p_lcb != NULL))
+ {
+ /* bind ccb to lcb and send connect ind event */
+ bind = TRUE;
+ p_ccb_bind = p_ccb;
+ p_ccb->p_bcb = p_bcb;
+ p_ccb->cc.p_ctrl_cback(avct_ccb_to_idx(p_ccb), AVCT_BROWSE_CONN_IND_EVT,
+ 0, p_ccb->p_lcb->peer_addr);
+ }
+ }
+ }
+
+ /* if no ccbs bound to this lcb, disconnect */
+ if (bind == FALSE)
+ {
+ avct_bcb_event(p_bcb, AVCT_LCB_INT_CLOSE_EVT, p_data);
+ }
+ else if (p_bcb->p_tx_msg)
+ {
+ if (p_ccb_bind)
+ {
+ ul_msg.p_buf = p_bcb->p_tx_msg;
+ ul_msg.p_ccb = p_ccb_bind;
+ ul_msg.label = (UINT8)(p_bcb->p_tx_msg->layer_specific & 0xFF);
+ ul_msg.cr = (UINT8)((p_bcb->p_tx_msg->layer_specific & 0xFF00) >> 8);
+ p_bcb->p_tx_msg->layer_specific = AVCT_DATA_BROWSE;
+ p_bcb->p_tx_msg = NULL;
+
+ /* send msg event to bcb */
+ avct_bcb_event(p_bcb, AVCT_LCB_UL_MSG_EVT, (tAVCT_LCB_EVT *) &ul_msg);
+ }
+ else
+ {
+ GKI_freebuf (p_bcb->p_tx_msg);
+ p_bcb->p_tx_msg = NULL;
+ }
+
+ }
+}
+
+/*******************************************************************************
+**
+** Function avct_bcb_open_fail
+**
+** Description L2CAP channel open attempt failed. Mark the ccbs
+** as NULL bcb.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_bcb_open_fail(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+ tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
+ int i;
+
+ for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
+ {
+ if (p_ccb->allocated && (p_ccb->p_bcb == p_bcb))
+ {
+ p_ccb->p_bcb = NULL;
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function avct_bcb_close_ind
+**
+** Description L2CAP channel closed by peer. Deallocate any initiator
+** ccbs on this lcb and send disconnect ind event.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_bcb_close_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+ tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
+ tAVCT_LCB *p_lcb = avct_lcb_by_bcb(p_bcb);
+ int i;
+
+ for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
+ {
+ if (p_ccb->allocated && (p_ccb->p_bcb == p_bcb))
+ {
+ if (p_ccb->cc.role == AVCT_INT)
+ {
+ (*p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_ccb), AVCT_BROWSE_DISCONN_CFM_EVT, 0, p_lcb->peer_addr);
+ }
+ else
+ {
+ (*p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_ccb), AVCT_BROWSE_DISCONN_IND_EVT, 0, NULL);
+ }
+ p_ccb->p_bcb = NULL;
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function avct_bcb_close_cfm
+**
+** Description L2CAP channel closed by us. Deallocate any initiator
+** ccbs on this lcb and send disconnect ind or cfm event.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_bcb_close_cfm(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+ tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
+ int i;
+ UINT8 event = 0;
+ BOOLEAN ch_close = p_bcb->ch_close; /* Whether BCB initiated channel close */
+ tAVCT_CTRL_CBACK *p_cback;
+
+ p_bcb->ch_close = FALSE;
+ p_bcb->allocated = 0;
+ for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
+ {
+ if (p_ccb->allocated && (p_ccb->p_bcb == p_bcb))
+ {
+ /* if this ccb initiated close send disconnect cfm otherwise ind */
+ if (ch_close)
+ {
+ event = AVCT_BROWSE_DISCONN_CFM_EVT;
+ }
+ else
+ {
+ event = AVCT_BROWSE_DISCONN_IND_EVT;
+ }
+
+ p_cback = p_ccb->cc.p_ctrl_cback;
+ p_ccb->p_bcb = NULL;
+ if (p_ccb->p_lcb == NULL)
+ avct_ccb_dealloc(p_ccb, AVCT_NO_EVT, 0, NULL);
+ (*p_cback)(avct_ccb_to_idx(p_ccb), event,
+ p_data->result, NULL);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function avct_bcb_bind_conn
+**
+** Description Bind ccb to lcb and send connect cfm event.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_bcb_bind_conn(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+ tAVCT_LCB *p_lcb = avct_lcb_by_bcb(p_bcb);
+ p_data->p_ccb->p_bcb = p_bcb;
+ (*p_data->p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_data->p_ccb),
+ AVCT_BROWSE_CONN_CFM_EVT, 0, p_lcb->peer_addr);
+}
+
+/*******************************************************************************
+**
+** Function avct_bcb_chk_disc
+**
+** Description A ccb wants to close; if it is the last ccb on this lcb,
+** close channel. Otherwise just deallocate and call
+** callback.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_bcb_chk_disc(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+ AVCT_TRACE_WARNING0("avct_bcb_chk_disc");
+ p_bcb->ch_close = avct_bcb_last_ccb(p_bcb, p_data->p_ccb);
+ if (p_bcb->ch_close)
+ {
+ AVCT_TRACE_WARNING0("b closing");
+ avct_bcb_event(p_bcb, AVCT_LCB_INT_CLOSE_EVT, p_data);
+ }
+ else
+ {
+ AVCT_TRACE_WARNING0("b unbind_disc");
+ avct_bcb_unbind_disc(p_bcb, p_data);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avct_bcb_chnl_disc
+**
+** Description Disconnect L2CAP channel.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_bcb_chnl_disc(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+ L2CA_DisconnectReq(p_bcb->ch_lcid);
+}
+
+/*******************************************************************************
+**
+** Function avct_bcb_bind_fail
+**
+** Description Deallocate ccb and call callback with connect event
+** with failure result.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_bcb_bind_fail(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+ p_data->p_ccb->p_bcb = NULL;
+ (*p_data->p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_data->p_ccb), AVCT_BROWSE_CONN_CFM_EVT, AVCT_RESULT_FAIL, NULL);
+}
+
+/*******************************************************************************
+**
+** Function avct_bcb_cong_ind
+**
+** Description Handle congestion indication from L2CAP.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_bcb_cong_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+ tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
+ int i;
+ UINT8 event;
+ tAVCT_LCB *p_lcb = avct_lcb_by_bcb(p_bcb);
+
+ /* set event */
+ event = (p_data->cong) ? AVCT_BROWSE_CONG_IND_EVT : AVCT_BROWSE_UNCONG_IND_EVT;
+
+ /* send event to all ccbs on this lcb */
+ for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
+ {
+ if (p_ccb->allocated && (p_ccb->p_bcb == p_bcb))
+ {
+ (*p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_ccb), event, 0, p_lcb->peer_addr);
+ }
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function avct_bcb_discard_msg
+**
+** Description Discard a message sent in from the API.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_bcb_discard_msg(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+ AVCT_TRACE_WARNING0("save msg in control block");
+
+ if (p_bcb->p_tx_msg)
+ {
+ GKI_freebuf(p_bcb->p_tx_msg);
+ p_bcb->p_tx_msg = NULL;
+ }
+
+ /* if control channel is up, save the message and open the browsing channel */
+ if (p_data->ul_msg.p_ccb->p_lcb)
+ {
+ p_bcb->p_tx_msg = p_data->ul_msg.p_buf;
+
+ if (p_bcb->p_tx_msg)
+ {
+ p_bcb->p_tx_msg->layer_specific = (p_data->ul_msg.cr << 8) + p_data->ul_msg.label;
+
+ /* the channel is closed, opening or closing - open it again */
+ AVCT_TRACE_DEBUG2("ch_state: %d, allocated:%d", p_bcb->ch_state, p_bcb->allocated);
+ p_bcb->allocated = p_data->ul_msg.p_ccb->p_lcb->allocated;
+ AVCT_TRACE_DEBUG2("ch_state: %d, allocated:%d", p_bcb->ch_state, p_bcb->allocated);
+ avct_bcb_event(p_bcb, AVCT_LCB_UL_BIND_EVT, (tAVCT_LCB_EVT *) p_data->ul_msg.p_ccb);
+ }
+ }
+ else
+ GKI_freebuf(p_data->ul_msg.p_buf);
+}
+
+/*******************************************************************************
+**
+** Function avct_bcb_send_msg
+**
+** Description Build and send an AVCTP message.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_bcb_send_msg(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+ UINT16 curr_msg_len;
+ UINT8 pkt_type = AVCT_PKT_TYPE_SINGLE;
+ UINT8 hdr_len;
+ BT_HDR *p_buf;
+ UINT8 *p;
+
+ /* store msg len */
+ curr_msg_len = p_data->ul_msg.p_buf->len;
+
+ /* initialize packet type and other stuff */
+ if (curr_msg_len > (p_bcb->peer_mtu - AVCT_HDR_LEN_SINGLE))
+ {
+ AVCT_TRACE_ERROR3 ("avct_bcb_send_msg msg len (%d) exceeds peer mtu(%d-%d)!!", curr_msg_len, p_bcb->peer_mtu, AVCT_HDR_LEN_SINGLE);
+ GKI_freebuf(p_data->ul_msg.p_buf);
+ return;
+ }
+
+ /* set header len */
+ hdr_len = avct_lcb_pkt_type_len[pkt_type];
+ p_buf = p_data->ul_msg.p_buf;
+
+ /* set up to build header */
+ p_buf->len += hdr_len;
+ p_buf->offset -= hdr_len;
+ p = (UINT8 *)(p_buf + 1) + p_buf->offset;
+
+ /* build header */
+ AVCT_BLD_HDR(p, p_data->ul_msg.label, pkt_type, p_data->ul_msg.cr);
+ UINT16_TO_BE_STREAM(p, p_data->ul_msg.p_ccb->cc.pid);
+
+ /* send message to L2CAP */
+ L2CA_DataWrite(p_bcb->ch_lcid, p_buf);
+ return;
+}
+
+/*******************************************************************************
+**
+** Function avct_bcb_free_msg_ind
+**
+** Description Discard an incoming AVCTP message.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_bcb_free_msg_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+ if (p_data)
+ GKI_freebuf(p_data->p_buf);
+ return;
+}
+
+/*******************************************************************************
+**
+** Function avct_bcb_msg_ind
+**
+** Description Handle an incoming AVCTP message.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_bcb_msg_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+ UINT8 *p;
+ UINT8 label, type, cr_ipid;
+ UINT16 pid;
+ tAVCT_CCB *p_ccb;
+ BT_HDR *p_buf;
+ tAVCT_LCB *p_lcb = avct_lcb_by_bcb(p_bcb);
+
+ /* this p_buf is to be reported through p_msg_cback. The layer_specific
+ * needs to be set properly to indicate that it is received through
+ * broasing channel */
+ p_data->p_buf->layer_specific = AVCT_DATA_BROWSE;
+
+ /* reassemble message; if no message available (we received a fragment) return */
+ if ((p_data->p_buf = avct_bcb_msg_asmbl(p_bcb, p_data->p_buf)) == NULL)
+ {
+ return;
+ }
+
+ p = (UINT8 *)(p_data->p_buf + 1) + p_data->p_buf->offset;
+
+ /* parse header byte */
+ AVCT_PRS_HDR(p, label, type, cr_ipid);
+
+ /* check for invalid cr_ipid */
+ if (cr_ipid == AVCT_CR_IPID_INVALID)
+ {
+ AVCT_TRACE_WARNING1("Invalid cr_ipid", cr_ipid);
+ GKI_freebuf(p_data->p_buf);
+ return;
+ }
+
+ /* parse and lookup PID */
+ BE_STREAM_TO_UINT16(pid, p);
+ if ((p_ccb = avct_lcb_has_pid(p_lcb, pid)) != NULL)
+ {
+ /* PID found; send msg up, adjust bt hdr and call msg callback */
+ p_data->p_buf->offset += AVCT_HDR_LEN_SINGLE;
+ p_data->p_buf->len -= AVCT_HDR_LEN_SINGLE;
+ (*p_ccb->cc.p_msg_cback)(avct_ccb_to_idx(p_ccb), label, cr_ipid, p_data->p_buf);
+ }
+ else
+ {
+ /* PID not found; drop message */
+ AVCT_TRACE_WARNING1("No ccb for PID=%x", pid);
+ GKI_freebuf(p_data->p_buf);
+
+ /* if command send reject */
+ if (cr_ipid == AVCT_CMD)
+ {
+ if ((p_buf = (BT_HDR *) GKI_getpoolbuf(AVCT_CMD_POOL_ID)) != NULL)
+ {
+ p_buf->len = AVCT_HDR_LEN_SINGLE;
+ p_buf->offset = AVCT_MSG_OFFSET - AVCT_HDR_LEN_SINGLE;
+ p = (UINT8 *)(p_buf + 1) + p_buf->offset;
+ AVCT_BLD_HDR(p, label, AVCT_PKT_TYPE_SINGLE, AVCT_REJ);
+ UINT16_TO_BE_STREAM(p, pid);
+ L2CA_DataWrite(p_bcb->ch_lcid, p_buf);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function avct_bcb_dealloc
+**
+** Description Deallocate a link control block.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avct_bcb_dealloc(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+ tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
+ tAVCT_CCB *p_ccb_found = NULL;
+ BOOLEAN found = FALSE;
+ int i;
+
+ AVCT_TRACE_DEBUG1("avct_bcb_dealloc %d", p_bcb->allocated);
+
+ for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
+ {
+ /* if ccb allocated and */
+ if (p_ccb->allocated)
+ {
+ if (p_ccb->p_bcb == p_bcb)
+ {
+ p_ccb_found = p_ccb;
+ p_ccb->p_bcb = NULL;
+ AVCT_TRACE_DEBUG1("avct_bcb_dealloc used by ccb: %d", i);
+ found = TRUE;
+ break;
+ }
+ }
+ }
+
+ /* the browsing channel is down. Check if we have pending messages */
+ if (p_bcb->p_tx_msg != NULL)
+ {
+ GKI_freebuf(p_bcb->p_tx_msg);
+ }
+ memset(p_bcb, 0, sizeof(tAVCT_BCB));
+}
+
+/*******************************************************************************
+**
+** Function avct_close_bcb
+**
+** Description this function is called right before LCB disconnects.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_close_bcb(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
+{
+ tAVCT_BCB *p_bcb = avct_bcb_by_lcb(p_lcb);
+ if (p_bcb->allocated)
+ {
+ avct_bcb_event(p_bcb, AVCT_LCB_UL_UNBIND_EVT, p_data);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function avct_lcb_by_bcb
+**
+** Description This lookup function finds the lcb for a bcb.
+**
+** Returns pointer to the lcb.
+**
+*******************************************************************************/
+tAVCT_LCB *avct_lcb_by_bcb(tAVCT_BCB *p_bcb)
+{
+ return &avct_cb.lcb[p_bcb->allocated - 1];
+}
+
+/*******************************************************************************
+**
+** Function avct_bcb_by_lcb
+**
+** Description This lookup function finds the bcb for a lcb.
+**
+** Returns pointer to the lcb.
+**
+*******************************************************************************/
+tAVCT_BCB *avct_bcb_by_lcb(tAVCT_LCB *p_lcb)
+{
+ return &avct_cb.bcb[p_lcb->allocated - 1];
+}
+
+/*******************************************************************************
+**
+** Function avct_bcb_last_ccb
+**
+** Description See if given ccb is only one on the bcb.
+**
+**
+** Returns 0, if ccb is last, (ccb index + 1) otherwise.
+**
+*******************************************************************************/
+UINT8 avct_bcb_last_ccb(tAVCT_BCB *p_bcb, tAVCT_CCB *p_ccb_last)
+{
+ tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
+ int i;
+ UINT8 idx = 0;
+
+ for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
+ {
+ if (p_ccb->allocated && (p_ccb->p_bcb == p_bcb))
+ {
+ if (p_ccb != p_ccb_last)
+ return 0;
+ idx = (UINT8)(i + 1);
+ }
+ }
+ return idx;
+}
+
+/*******************************************************************************
+**
+** Function avct_bcb_by_lcid
+**
+** Description Find the BCB associated with the L2CAP LCID
+**
+**
+** Returns pointer to the lcb, or NULL if none found.
+**
+*******************************************************************************/
+tAVCT_BCB *avct_bcb_by_lcid(UINT16 lcid)
+{
+ tAVCT_BCB *p_bcb = &avct_cb.bcb[0];
+ int i;
+
+ for (i = 0; i < AVCT_NUM_LINKS; i++, p_bcb++)
+ {
+ if (p_bcb->allocated && (p_bcb->ch_lcid == lcid))
+ {
+ break;
+ }
+ }
+
+ if (i == AVCT_NUM_LINKS)
+ {
+ p_bcb = NULL;
+ /* out of lcbs */
+ AVCT_TRACE_WARNING1("No bcb for lcid %x", lcid);
+ }
+
+ return p_bcb;
+}
+#endif /* (AVCT_BROWSE_INCLUDED == TRUE) */
diff --git a/stack/avct/avct_ccb.c b/stack/avct/avct_ccb.c
new file mode 100644
index 0000000..89465a2
--- /dev/null
+++ b/stack/avct/avct_ccb.c
@@ -0,0 +1,137 @@
+/*****************************************************************************
+**
+** Name: avct_ccb.c
+**
+** Description: This module contains functions which operate on the
+** AVCTP connection control block.
+**
+** Copyright (c) 2003-2004, WIDCOMM Inc., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include <string.h>
+#include "data_types.h"
+#include "bt_target.h"
+#include "avct_api.h"
+#include "avct_int.h"
+
+/*******************************************************************************
+**
+** Function avct_ccb_alloc
+**
+** Description Allocate a connection control block; copy parameters to ccb.
+**
+**
+** Returns pointer to the ccb, or NULL if none could be allocated.
+**
+*******************************************************************************/
+tAVCT_CCB *avct_ccb_alloc(tAVCT_CC *p_cc)
+{
+ tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
+ int i;
+
+ for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
+ {
+ if (!p_ccb->allocated)
+ {
+ p_ccb->allocated = AVCT_ALOC_LCB;
+ memcpy(&p_ccb->cc, p_cc, sizeof(tAVCT_CC));
+ AVCT_TRACE_DEBUG1("avct_ccb_alloc %d", i);
+ break;
+ }
+ }
+
+ if (i == AVCT_NUM_CONN)
+ {
+ /* out of ccbs */
+ p_ccb = NULL;
+ AVCT_TRACE_WARNING0("Out of ccbs");
+ }
+ return p_ccb;
+}
+
+/*******************************************************************************
+**
+** Function avct_ccb_dealloc
+**
+** Description Deallocate a connection control block and call application
+** callback.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avct_ccb_dealloc(tAVCT_CCB *p_ccb, UINT8 event, UINT16 result, BD_ADDR bd_addr)
+{
+ tAVCT_CTRL_CBACK *p_cback = p_ccb->cc.p_ctrl_cback;
+
+ AVCT_TRACE_DEBUG1("avct_ccb_dealloc %d", avct_ccb_to_idx(p_ccb));
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+ if(p_ccb->p_bcb == NULL)
+ memset(p_ccb, 0, sizeof(tAVCT_CCB));
+ else
+ {
+ /* control channel is down, but the browsing channel is still connected 0 disconnect it now */
+ avct_bcb_event(p_ccb->p_bcb, AVCT_LCB_UL_UNBIND_EVT, (tAVCT_LCB_EVT *) &p_ccb);
+ p_ccb->p_lcb = NULL;
+ }
+#else
+ memset(p_ccb, 0, sizeof(tAVCT_CCB));
+#endif
+
+ if (event != AVCT_NO_EVT)
+ {
+ (*p_cback)(avct_ccb_to_idx(p_ccb), event, result, bd_addr);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avct_ccb_to_idx
+**
+** Description Given a pointer to an ccb, return its index.
+**
+**
+** Returns Index of ccb.
+**
+*******************************************************************************/
+UINT8 avct_ccb_to_idx(tAVCT_CCB *p_ccb)
+{
+ /* use array arithmetic to determine index */
+ return (UINT8) (p_ccb - avct_cb.ccb);
+}
+
+/*******************************************************************************
+**
+** Function avct_ccb_by_idx
+**
+** Description Return ccb pointer based on ccb index (or handle).
+**
+**
+** Returns pointer to the ccb, or NULL if none found.
+**
+*******************************************************************************/
+tAVCT_CCB *avct_ccb_by_idx(UINT8 idx)
+{
+ tAVCT_CCB *p_ccb;
+
+ /* verify index */
+ if (idx < AVCT_NUM_CONN)
+ {
+ p_ccb = &avct_cb.ccb[idx];
+
+ /* verify ccb is allocated */
+ if (!p_ccb->allocated)
+ {
+ p_ccb = NULL;
+ AVCT_TRACE_WARNING1("ccb %d not allocated", idx);
+ }
+ }
+ else
+ {
+ p_ccb = NULL;
+ AVCT_TRACE_WARNING1("No ccb for idx %d", idx);
+ }
+ return p_ccb;
+}
diff --git a/stack/avct/avct_defs.h b/stack/avct/avct_defs.h
new file mode 100644
index 0000000..dd03c1e
--- /dev/null
+++ b/stack/avct/avct_defs.h
@@ -0,0 +1,51 @@
+/*****************************************************************************
+**
+** Name: avct_defs.h
+**
+** Description: This contains constants definitions and other information
+** from the AVCTP specification. This file is intended for
+** use internal to AVCT only.
+**
+**
+** Copyright (c) 2003-2004, WIDCOMM Inc., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef AVCT_DEFS_H
+#define AVCT_DEFS_H
+
+/*****************************************************************************
+** constants
+*****************************************************************************/
+
+/* packet type */
+#define AVCT_PKT_TYPE_SINGLE 0 /* single packet */
+#define AVCT_PKT_TYPE_START 1 /* start packet */
+#define AVCT_PKT_TYPE_CONT 2 /* continue packet */
+#define AVCT_PKT_TYPE_END 3 /* end packet */
+
+/* header lengths for different packet types */
+#define AVCT_HDR_LEN_SINGLE 3
+#define AVCT_HDR_LEN_START 4
+#define AVCT_HDR_LEN_CONT 1
+#define AVCT_HDR_LEN_END 1
+
+/* invalid cr+ipid value */
+#define AVCT_CR_IPID_INVALID 1
+
+/*****************************************************************************
+** message parsing and building macros
+*****************************************************************************/
+
+#define AVCT_BLD_HDR(p, label, type, cr_ipid) \
+ *(p)++ = ((label) << 4) | ((type) << 2) | (cr_ipid);
+
+#define AVCT_PRS_HDR(p, label, type, cr_ipid) \
+ label = *(p) >> 4; \
+ type = (*(p) >> 2) & 3; \
+ cr_ipid = *(p)++ & 3;
+
+#define AVCT_PRS_PKT_TYPE(p, type) \
+ type = (*(p) >> 2) & 3;
+
+#endif /* AVCT_DEFS_H */
diff --git a/stack/avct/avct_int.h b/stack/avct/avct_int.h
new file mode 100644
index 0000000..d67c404
--- /dev/null
+++ b/stack/avct/avct_int.h
@@ -0,0 +1,227 @@
+/*****************************************************************************
+**
+** Name: avct_int.h
+**
+** Description: This file contains interfaces which are internal to AVCTP.
+**
+**
+** Copyright (c) 2003-2008, Broadcom Corp., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef AVCT_INT_H
+#define AVCT_INT_H
+
+#include "gki.h"
+#include "avct_api.h"
+#include "avct_defs.h"
+#include "l2c_api.h"
+
+/*****************************************************************************
+** constants
+*****************************************************************************/
+
+/* lcb state machine events */
+enum {
+ AVCT_LCB_UL_BIND_EVT,
+ AVCT_LCB_UL_UNBIND_EVT,
+ AVCT_LCB_UL_MSG_EVT,
+ AVCT_LCB_INT_CLOSE_EVT,
+ AVCT_LCB_LL_OPEN_EVT,
+ AVCT_LCB_LL_CLOSE_EVT,
+ AVCT_LCB_LL_MSG_EVT,
+ AVCT_LCB_LL_CONG_EVT
+};
+
+
+/* "states" used for L2CAP channel */
+#define AVCT_CH_IDLE 0 /* No connection */
+#define AVCT_CH_CONN 1 /* Waiting for connection confirm */
+#define AVCT_CH_CFG 2 /* Waiting for configuration complete */
+#define AVCT_CH_OPEN 3 /* Channel opened */
+
+/* "no event" indicator used by ccb dealloc */
+#define AVCT_NO_EVT 0xFF
+
+/*****************************************************************************
+** data types
+*****************************************************************************/
+/* sub control block type - common data members for tAVCT_LCB and tAVCT_BCB */
+typedef struct {
+ UINT16 peer_mtu; /* peer l2c mtu */
+ UINT16 ch_result; /* L2CAP connection result value */
+ UINT16 ch_lcid; /* L2CAP channel LCID */
+ UINT8 allocated; /* 0, not allocated. index+1, otherwise. */
+ UINT8 state; /* The state machine state */
+ UINT8 ch_state; /* L2CAP channel state */
+ UINT8 ch_flags; /* L2CAP configuration flags */
+} tAVCT_SCB;
+
+/* link control block type */
+typedef struct {
+ UINT16 peer_mtu; /* peer l2c mtu */
+ UINT16 ch_result; /* L2CAP connection result value */
+ UINT16 ch_lcid; /* L2CAP channel LCID */
+ UINT8 allocated; /* 0, not allocated. index+1, otherwise. */
+ UINT8 state; /* The state machine state */
+ UINT8 ch_state; /* L2CAP channel state */
+ UINT8 ch_flags; /* L2CAP configuration flags */
+ BT_HDR *p_rx_msg; /* Message being reassembled */
+ UINT16 conflict_lcid; /* L2CAP channel LCID */
+ BD_ADDR peer_addr; /* BD address of peer */
+ BUFFER_Q tx_q; /* Transmit data buffer queue */
+ BOOLEAN cong; /* TRUE, if congested */
+} tAVCT_LCB;
+
+/* browse control block type */
+typedef struct {
+ UINT16 peer_mtu; /* peer l2c mtu */
+ UINT16 ch_result; /* L2CAP connection result value */
+ UINT16 ch_lcid; /* L2CAP channel LCID */
+ UINT8 allocated; /* 0, not allocated. index+1, otherwise. */
+ UINT8 state; /* The state machine state */
+ UINT8 ch_state; /* L2CAP channel state */
+ UINT8 ch_flags; /* L2CAP configuration flags */
+ BT_HDR *p_tx_msg; /* Message to be sent - in case the browsing channel is not open when MsgReg is called */
+ UINT8 ch_close; /* CCB index+1, if CCB initiated channel close */
+} tAVCT_BCB;
+
+#define AVCT_ALOC_LCB 0x01
+#define AVCT_ALOC_BCB 0x02
+/* connection control block */
+typedef struct {
+ tAVCT_CC cc; /* parameters from connection creation */
+ tAVCT_LCB *p_lcb; /* Associated LCB */
+ tAVCT_BCB *p_bcb; /* associated BCB */
+ BOOLEAN ch_close; /* Whether CCB initiated channel close */
+ UINT8 allocated; /* Whether LCB/BCB is allocated */
+} tAVCT_CCB;
+
+/* data type associated with UL_MSG_EVT */
+typedef struct {
+ BT_HDR *p_buf;
+ tAVCT_CCB *p_ccb;
+ UINT8 label;
+ UINT8 cr;
+} tAVCT_UL_MSG;
+
+/* union associated with lcb state machine events */
+typedef union {
+ tAVCT_UL_MSG ul_msg;
+ BT_HDR *p_buf;
+ tAVCT_CCB *p_ccb;
+ UINT16 result;
+ BOOLEAN cong;
+ UINT8 err_code;
+} tAVCT_LCB_EVT;
+
+/* Control block for AVCT */
+typedef struct {
+ tAVCT_LCB lcb[AVCT_NUM_LINKS]; /* link control blocks */
+ tAVCT_BCB bcb[AVCT_NUM_LINKS]; /* browse control blocks */
+ tAVCT_CCB ccb[AVCT_NUM_CONN]; /* connection control blocks */
+ UINT16 mtu; /* our L2CAP MTU */
+ UINT16 mtu_br; /* our L2CAP MTU for the Browsing channel */
+ UINT8 trace_level; /* trace level */
+} tAVCT_CB;
+
+/*****************************************************************************
+** function declarations
+*****************************************************************************/
+
+/* LCB function declarations */
+extern void avct_lcb_event(tAVCT_LCB *p_lcb, UINT8 event, tAVCT_LCB_EVT *p_data);
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+extern void avct_bcb_event(tAVCT_BCB *p_bcb, UINT8 event, tAVCT_LCB_EVT *p_data);
+extern void avct_close_bcb(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
+extern tAVCT_LCB *avct_lcb_by_bcb(tAVCT_BCB *p_bcb);
+extern tAVCT_BCB *avct_bcb_by_lcb(tAVCT_LCB *p_lcb);
+extern BOOLEAN avct_bcb_last_ccb(tAVCT_BCB *p_bcb, tAVCT_CCB *p_ccb_last);
+extern tAVCT_BCB *avct_bcb_by_lcid(UINT16 lcid);
+#endif
+extern tAVCT_LCB *avct_lcb_by_bd(BD_ADDR bd_addr);
+extern tAVCT_LCB *avct_lcb_alloc(BD_ADDR bd_addr);
+extern void avct_lcb_dealloc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
+extern tAVCT_LCB *avct_lcb_by_lcid(UINT16 lcid);
+extern tAVCT_CCB *avct_lcb_has_pid(tAVCT_LCB *p_lcb, UINT16 pid);
+extern BOOLEAN avct_lcb_last_ccb(tAVCT_LCB *p_lcb, tAVCT_CCB *p_ccb_last);
+
+/* LCB action functions */
+extern void avct_lcb_chnl_open(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
+extern void avct_lcb_unbind_disc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
+extern void avct_lcb_open_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
+extern void avct_lcb_open_fail(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
+extern void avct_lcb_close_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
+extern void avct_lcb_close_cfm(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
+extern void avct_lcb_bind_conn(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
+extern void avct_lcb_chk_disc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
+extern void avct_lcb_chnl_disc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
+extern void avct_lcb_bind_fail(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
+extern void avct_lcb_cong_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
+extern void avct_lcb_discard_msg(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
+extern void avct_lcb_send_msg(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
+extern void avct_lcb_msg_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
+extern void avct_lcb_free_msg_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
+
+/* BCB action functions */
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+typedef void (*tAVCT_BCB_ACTION)(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
+extern void avct_bcb_chnl_open(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
+extern void avct_bcb_unbind_disc(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
+extern void avct_bcb_open_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
+extern void avct_bcb_open_fail(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
+extern void avct_bcb_close_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
+extern void avct_bcb_close_cfm(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
+extern void avct_bcb_bind_conn(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
+extern void avct_bcb_chk_disc(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
+extern void avct_bcb_chnl_disc(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
+extern void avct_bcb_bind_fail(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
+extern void avct_bcb_cong_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
+extern void avct_bcb_discard_msg(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
+extern void avct_bcb_send_msg(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
+extern void avct_bcb_msg_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
+extern void avct_bcb_free_msg_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
+
+extern void avct_bcb_dealloc(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
+
+extern const tAVCT_BCB_ACTION avct_bcb_action[];
+extern const UINT8 avct_lcb_pkt_type_len[];
+extern const tL2CAP_FCR_OPTS avct_l2c_br_fcr_opts_def;
+#endif
+
+/* CCB function declarations */
+extern tAVCT_CCB *avct_ccb_alloc(tAVCT_CC *p_cc);
+extern void avct_ccb_dealloc(tAVCT_CCB *p_ccb, UINT8 event, UINT16 result, BD_ADDR bd_addr);
+extern UINT8 avct_ccb_to_idx(tAVCT_CCB *p_ccb);
+extern tAVCT_CCB *avct_ccb_by_idx(UINT8 idx);
+
+
+/*****************************************************************************
+** global data
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* Main control block */
+#if AVCT_DYNAMIC_MEMORY == FALSE
+AVCT_API extern tAVCT_CB avct_cb;
+#else
+AVCT_API extern tAVCT_CB *avct_cb_ptr;
+#define avct_cb (*avct_cb_ptr)
+#endif
+
+/* L2CAP callback registration structure */
+extern const tL2CAP_APPL_INFO avct_l2c_appl;
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+extern const tL2CAP_APPL_INFO avct_l2c_br_appl;
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVCT_INT_H */
+
+
diff --git a/stack/avct/avct_l2c.c b/stack/avct/avct_l2c.c
new file mode 100644
index 0000000..cf1a652
--- /dev/null
+++ b/stack/avct/avct_l2c.c
@@ -0,0 +1,421 @@
+/*****************************************************************************
+**
+** Name: avct_l2c.c
+**
+** Description: This AVCTP module interfaces to L2CAP
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include <string.h>
+#include "data_types.h"
+#include "bt_target.h"
+#include "avct_api.h"
+#include "avct_int.h"
+#include "l2c_api.h"
+#include "l2cdefs.h"
+
+/* Configuration flags. */
+#define AVCT_L2C_CFG_IND_DONE (1<<0)
+#define AVCT_L2C_CFG_CFM_DONE (1<<1)
+
+/* callback function declarations */
+void avct_l2c_connect_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id);
+void avct_l2c_connect_cfm_cback(UINT16 lcid, UINT16 result);
+void avct_l2c_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg);
+void avct_l2c_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg);
+void avct_l2c_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed);
+void avct_l2c_disconnect_cfm_cback(UINT16 lcid, UINT16 result);
+void avct_l2c_congestion_ind_cback(UINT16 lcid, BOOLEAN is_congested);
+void avct_l2c_data_ind_cback(UINT16 lcid, BT_HDR *p_buf);
+
+/* L2CAP callback function structure */
+const tL2CAP_APPL_INFO avct_l2c_appl = {
+ avct_l2c_connect_ind_cback,
+ avct_l2c_connect_cfm_cback,
+ NULL,
+ avct_l2c_config_ind_cback,
+ avct_l2c_config_cfm_cback,
+ avct_l2c_disconnect_ind_cback,
+ avct_l2c_disconnect_cfm_cback,
+ NULL,
+ avct_l2c_data_ind_cback,
+ avct_l2c_congestion_ind_cback,
+ NULL /* tL2CA_TX_COMPLETE_CB */
+};
+
+/*******************************************************************************
+**
+** Function avct_l2c_is_passive
+**
+** Description check is the CCB associated with the given LCB was created
+** as passive
+**
+** Returns TRUE, if the given LCB is created as AVCT_PASSIVE
+**
+*******************************************************************************/
+static BOOLEAN avct_l2c_is_passive (tAVCT_LCB *p_lcb)
+{
+ BOOLEAN is_passive = FALSE;
+ tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
+ int i;
+
+ for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
+ {
+ if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb))
+ {
+ AVCT_TRACE_DEBUG1("avct_l2c_is_ct control:x%x", p_ccb->cc.control);
+ if (p_ccb->cc.control & AVCT_PASSIVE)
+ {
+ is_passive = TRUE;
+ break;
+ }
+ }
+ }
+ return is_passive;
+}
+
+/*******************************************************************************
+**
+** Function avct_l2c_connect_ind_cback
+**
+** Description This is the L2CAP connect indication callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void avct_l2c_connect_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id)
+{
+ tAVCT_LCB *p_lcb;
+ UINT16 result = L2CAP_CONN_OK;
+ tL2CAP_CFG_INFO cfg;
+
+ /* do we already have a channel for this peer? */
+ if ((p_lcb = avct_lcb_by_bd(bd_addr)) == NULL)
+ {
+ /* no, allocate lcb */
+ if ((p_lcb = avct_lcb_alloc(bd_addr)) == NULL)
+ {
+ /* no ccb available, reject L2CAP connection */
+ result = L2CAP_CONN_NO_RESOURCES;
+ }
+ }
+ /* else we already have a channel for this peer */
+ else
+ {
+ if (!avct_l2c_is_passive (p_lcb) || (p_lcb->ch_state == AVCT_CH_OPEN))
+ {
+ /* this LCB included CT role - reject */
+ result = L2CAP_CONN_NO_RESOURCES;
+ }
+ else
+ {
+ /* TG role only - accept the connection from CT. move the channel ID to the conflict list */
+ p_lcb->conflict_lcid = p_lcb->ch_lcid;
+ AVCT_TRACE_DEBUG1("avct_l2c_connect_ind_cback conflict_lcid:0x%x", p_lcb->conflict_lcid);
+ }
+ }
+
+ if(p_lcb)
+ {
+ AVCT_TRACE_DEBUG3("avct_l2c_connect_ind_cback: 0x%x, res: %d, ch_state: %d",
+ lcid, result, p_lcb->ch_state);
+ }
+ /* Send L2CAP connect rsp */
+ L2CA_ConnectRsp(bd_addr, id, lcid, result, 0);
+
+ /* if result ok, proceed with connection */
+ if (result == L2CAP_CONN_OK)
+ {
+ /* store LCID */
+ p_lcb->ch_lcid = lcid;
+
+ /* transition to configuration state */
+ p_lcb->ch_state = AVCT_CH_CFG;
+
+ /* Send L2CAP config req */
+ memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+ cfg.mtu_present = TRUE;
+ cfg.mtu = avct_cb.mtu;
+ L2CA_ConfigReq(lcid, &cfg);
+ AVCT_TRACE_DEBUG0("avct_l2c snd Cfg Req");
+ }
+
+#if (BT_USE_TRACES == TRUE)
+ if(p_lcb)
+ AVCT_TRACE_DEBUG1("ch_state cni: %d ", p_lcb->ch_state);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function avct_l2c_connect_cfm_cback
+**
+** Description This is the L2CAP connect confirm callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void avct_l2c_connect_cfm_cback(UINT16 lcid, UINT16 result)
+{
+ tAVCT_LCB *p_lcb;
+ tL2CAP_CFG_INFO cfg;
+
+ /* look up lcb for this channel */
+ if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL)
+ {
+ AVCT_TRACE_DEBUG4("avct_l2c_connect_cfm_cback lcid:0x%x result: %d ch_state: %d, conflict_lcid:0x%x",
+ lcid, result, p_lcb->ch_state, p_lcb->conflict_lcid);
+ /* if in correct state */
+ if (p_lcb->ch_state == AVCT_CH_CONN)
+ {
+ /* if result successful */
+ if (result == L2CAP_CONN_OK)
+ {
+ /* set channel state */
+ p_lcb->ch_state = AVCT_CH_CFG;
+
+ /* Send L2CAP config req */
+ memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+ cfg.mtu_present = TRUE;
+ cfg.mtu = avct_cb.mtu;
+ L2CA_ConfigReq(lcid, &cfg);
+ AVCT_TRACE_DEBUG0("avct_l2c snd Cfg Req");
+ }
+ /* else failure */
+ else
+ {
+ AVCT_TRACE_DEBUG1("avct_l2c_connect_cfm_cback conflict_lcid:0x%x", p_lcb->conflict_lcid);
+ if (p_lcb->conflict_lcid == lcid)
+ p_lcb->conflict_lcid = 0;
+ else
+ avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT *) &result);
+ }
+ }
+ else if (p_lcb->conflict_lcid == lcid)
+ {
+ /* we must be in AVCT_CH_CFG state for the ch_lcid channel */
+ AVCT_TRACE_DEBUG2("avct_l2c_connect_cfm_cback ch_state: %d, conflict_lcid:0x%x", p_lcb->ch_state, p_lcb->conflict_lcid);
+ if (result == L2CAP_CONN_OK)
+ {
+ /* just in case the peer also accepts our connection - Send L2CAP disconnect req */
+ L2CA_DisconnectReq(lcid);
+ }
+ p_lcb->conflict_lcid = 0;
+ }
+ AVCT_TRACE_DEBUG1("ch_state cnc: %d ", p_lcb->ch_state);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avct_l2c_config_cfm_cback
+**
+** Description This is the L2CAP config confirm callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void avct_l2c_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
+{
+ tAVCT_LCB *p_lcb;
+
+ /* look up lcb for this channel */
+ if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL)
+ {
+ AVCT_TRACE_DEBUG3("avct_l2c_config_cfm_cback: 0x%x, ch_state: %d, res: %d",
+ lcid, p_lcb->ch_state, p_cfg->result);
+ /* if in correct state */
+ if (p_lcb->ch_state == AVCT_CH_CFG)
+ {
+ /* if result successful */
+ if (p_cfg->result == L2CAP_CFG_OK)
+ {
+ /* update flags */
+ p_lcb->ch_flags |= AVCT_L2C_CFG_CFM_DONE;
+
+ /* if configuration complete */
+ if (p_lcb->ch_flags & AVCT_L2C_CFG_IND_DONE)
+ {
+ p_lcb->ch_state = AVCT_CH_OPEN;
+ avct_lcb_event(p_lcb, AVCT_LCB_LL_OPEN_EVT, NULL);
+ }
+ }
+ /* else failure */
+ else
+ {
+ AVCT_TRACE_DEBUG1("ERROR avct_l2c_config_cfm_cback L2CA_DisconnectReq %d ", p_lcb->ch_state);
+ /* store result value */
+ p_lcb->ch_result = p_cfg->result;
+
+ /* Send L2CAP disconnect req */
+ L2CA_DisconnectReq(lcid);
+ }
+ }
+ AVCT_TRACE_DEBUG1("ch_state cfc: %d ", p_lcb->ch_state);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avct_l2c_config_ind_cback
+**
+** Description This is the L2CAP config indication callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void avct_l2c_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
+{
+ tAVCT_LCB *p_lcb;
+
+ /* look up lcb for this channel */
+ if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL)
+ {
+ AVCT_TRACE_DEBUG2("avct_l2c_config_ind_cback: 0x%x, ch_state: %d", lcid, p_lcb->ch_state);
+ /* store the mtu in tbl */
+ if (p_cfg->mtu_present)
+ {
+ p_lcb->peer_mtu = p_cfg->mtu;
+ }
+ else
+ {
+ p_lcb->peer_mtu = L2CAP_DEFAULT_MTU;
+ }
+
+ /* send L2CAP configure response */
+ memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO));
+ p_cfg->result = L2CAP_CFG_OK;
+ L2CA_ConfigRsp(lcid, p_cfg);
+
+ /* if first config ind */
+ if ((p_lcb->ch_flags & AVCT_L2C_CFG_IND_DONE) == 0)
+ {
+ /* update flags */
+ p_lcb->ch_flags |= AVCT_L2C_CFG_IND_DONE;
+
+ /* if configuration complete */
+ if (p_lcb->ch_flags & AVCT_L2C_CFG_CFM_DONE)
+ {
+ p_lcb->ch_state = AVCT_CH_OPEN;
+ avct_lcb_event(p_lcb, AVCT_LCB_LL_OPEN_EVT, NULL);
+ }
+ }
+ AVCT_TRACE_DEBUG1("ch_state cfi: %d ", p_lcb->ch_state);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avct_l2c_disconnect_ind_cback
+**
+** Description This is the L2CAP disconnect indication callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void avct_l2c_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed)
+{
+ tAVCT_LCB *p_lcb;
+ UINT16 result = AVCT_RESULT_FAIL;
+
+ /* look up lcb for this channel */
+ if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL)
+ {
+ AVCT_TRACE_DEBUG2("avct_l2c_disconnect_ind_cback: 0x%x, ch_state: %d", lcid, p_lcb->ch_state);
+ if (ack_needed)
+ {
+ /* send L2CAP disconnect response */
+ L2CA_DisconnectRsp(lcid);
+ }
+
+ avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT *) &result);
+ AVCT_TRACE_DEBUG1("ch_state di: %d ", p_lcb->ch_state);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avct_l2c_disconnect_cfm_cback
+**
+** Description This is the L2CAP disconnect confirm callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void avct_l2c_disconnect_cfm_cback(UINT16 lcid, UINT16 result)
+{
+ tAVCT_LCB *p_lcb;
+ UINT16 res;
+
+ /* look up lcb for this channel */
+ if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL)
+ {
+ AVCT_TRACE_DEBUG3("avct_l2c_disconnect_cfm_cback: 0x%x, ch_state: %d, res: %d",
+ lcid, p_lcb->ch_state, result);
+ /* result value may be previously stored */
+ res = (p_lcb->ch_result != 0) ? p_lcb->ch_result : result;
+ p_lcb->ch_result = 0;
+
+ avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT *) &res);
+ AVCT_TRACE_DEBUG1("ch_state dc: %d ", p_lcb->ch_state);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avct_l2c_congestion_ind_cback
+**
+** Description This is the L2CAP congestion indication callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void avct_l2c_congestion_ind_cback(UINT16 lcid, BOOLEAN is_congested)
+{
+ tAVCT_LCB *p_lcb;
+
+ AVCT_TRACE_DEBUG1("avct_l2c_congestion_ind_cback: 0x%x", lcid);
+ /* look up lcb for this channel */
+ if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL)
+ {
+ avct_lcb_event(p_lcb, AVCT_LCB_LL_CONG_EVT, (tAVCT_LCB_EVT *) &is_congested);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avct_l2c_data_ind_cback
+**
+** Description This is the L2CAP data indication callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void avct_l2c_data_ind_cback(UINT16 lcid, BT_HDR *p_buf)
+{
+ tAVCT_LCB *p_lcb;
+
+ AVCT_TRACE_DEBUG1("avct_l2c_data_ind_cback: 0x%x", lcid);
+ /* look up lcb for this channel */
+ if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL)
+ {
+ avct_lcb_event(p_lcb, AVCT_LCB_LL_MSG_EVT, (tAVCT_LCB_EVT *) &p_buf);
+ }
+ else /* prevent buffer leak */
+ {
+ AVCT_TRACE_WARNING0("ERROR -> avct_l2c_data_ind_cback drop buffer");
+ GKI_freebuf(p_buf);
+ }
+}
+
diff --git a/stack/avct/avct_l2c_br.c b/stack/avct/avct_l2c_br.c
new file mode 100644
index 0000000..e333edf
--- /dev/null
+++ b/stack/avct/avct_l2c_br.c
@@ -0,0 +1,397 @@
+/*****************************************************************************
+**
+** Name: avct_l2c_br.c
+**
+** Description: This AVCTP module interfaces to L2CAP
+**
+** Copyright (c) 2008, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include <string.h>
+#include "data_types.h"
+#include "bt_target.h"
+#include "avct_api.h"
+#include "avct_int.h"
+#include "l2c_api.h"
+#include "l2cdefs.h"
+
+/* Configuration flags. */
+#define AVCT_L2C_CFG_IND_DONE (1<<0)
+#define AVCT_L2C_CFG_CFM_DONE (1<<1)
+
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/* callback function declarations */
+void avct_l2c_br_connect_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id);
+void avct_l2c_br_connect_cfm_cback(UINT16 lcid, UINT16 result);
+void avct_l2c_br_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg);
+void avct_l2c_br_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg);
+void avct_l2c_br_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed);
+void avct_l2c_br_disconnect_cfm_cback(UINT16 lcid, UINT16 result);
+void avct_l2c_br_congestion_ind_cback(UINT16 lcid, BOOLEAN is_congested);
+void avct_l2c_br_data_ind_cback(UINT16 lcid, BT_HDR *p_buf);
+
+/* L2CAP callback function structure */
+const tL2CAP_APPL_INFO avct_l2c_br_appl = {
+ avct_l2c_br_connect_ind_cback,
+ avct_l2c_br_connect_cfm_cback,
+ NULL,
+ avct_l2c_br_config_ind_cback,
+ avct_l2c_br_config_cfm_cback,
+ avct_l2c_br_disconnect_ind_cback,
+ avct_l2c_br_disconnect_cfm_cback,
+ NULL,
+ avct_l2c_br_data_ind_cback,
+ avct_l2c_br_congestion_ind_cback,
+ NULL /* tL2CA_TX_COMPLETE_CB */
+};
+
+/* Browsing channel eL2CAP default options */
+const tL2CAP_FCR_OPTS avct_l2c_br_fcr_opts_def = {
+ L2CAP_FCR_ERTM_MODE, /* Mandatory for Browsing channel */
+ AVCT_BR_FCR_OPT_TX_WINDOW_SIZE, /* Tx window size */
+ AVCT_BR_FCR_OPT_MAX_TX_B4_DISCNT, /* Maximum transmissions before disconnecting */
+ AVCT_BR_FCR_OPT_RETX_TOUT, /* Retransmission timeout (2 secs) */
+ AVCT_BR_FCR_OPT_MONITOR_TOUT, /* Monitor timeout (12 secs) */
+ L2CAP_DEFAULT_ERM_MPS /* MPS segment size */
+};
+
+/*******************************************************************************
+**
+** Function avct_l2c_br_connect_ind_cback
+**
+** Description This is the L2CAP connect indication callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void avct_l2c_br_connect_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id)
+{
+ tAVCT_LCB *p_lcb;
+ UINT16 result = L2CAP_CONN_NO_RESOURCES;
+ tL2CAP_CFG_INFO cfg;
+ tAVCT_BCB *p_bcb;
+ tL2CAP_ERTM_INFO ertm_info;
+
+ memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+ cfg.mtu_present = TRUE;
+
+ if ((p_lcb = avct_lcb_by_bd(bd_addr)) != NULL)
+ {
+ /* control channel exists */
+ p_bcb = avct_bcb_by_lcb(p_lcb);
+
+ if (!p_bcb->allocated)
+ {
+ /* browsing channel does not exist yet and the browsing channel is registered
+ * - accept connection */
+ p_bcb->allocated = p_lcb->allocated; /* copy the index from lcb */
+
+ result = L2CAP_CONN_OK;
+ cfg.mtu = avct_cb.mtu_br;
+
+ cfg.fcr_present = TRUE;
+ cfg.fcr = avct_l2c_br_fcr_opts_def;
+ }
+ }
+ /* else no control channel yet, reject */
+
+ /* Set the FCR options: Browsing channel mandates ERTM */
+ ertm_info.preferred_mode = cfg.fcr.mode;
+ ertm_info.allowed_modes = L2CAP_FCR_CHAN_OPT_ERTM;
+ ertm_info.user_rx_pool_id = AVCT_BR_USER_RX_POOL_ID;
+ ertm_info.user_tx_pool_id = AVCT_BR_USER_TX_POOL_ID;
+ ertm_info.fcr_rx_pool_id = AVCT_BR_FCR_RX_POOL_ID;
+ ertm_info.fcr_tx_pool_id = AVCT_BR_FCR_TX_POOL_ID;
+
+ /* Send L2CAP connect rsp */
+ L2CA_ErtmConnectRsp(bd_addr, id, lcid, result, 0, &ertm_info);
+
+ /* if result ok, proceed with connection */
+ if (result == L2CAP_CONN_OK)
+ {
+ /* store LCID */
+ p_bcb->ch_lcid = lcid;
+
+ /* transition to configuration state */
+ p_bcb->ch_state = AVCT_CH_CFG;
+
+ /* Send L2CAP config req */
+ L2CA_ConfigReq(lcid, &cfg);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avct_l2c_br_connect_cfm_cback
+**
+** Description This is the L2CAP connect confirm callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void avct_l2c_br_connect_cfm_cback(UINT16 lcid, UINT16 result)
+{
+ tAVCT_BCB *p_lcb;
+ tL2CAP_CFG_INFO cfg;
+
+ /* look up lcb for this channel */
+ if ((p_lcb = avct_bcb_by_lcid(lcid)) != NULL)
+ {
+ /* if in correct state */
+ if (p_lcb->ch_state == AVCT_CH_CONN)
+ {
+ /* if result successful */
+ if (result == L2CAP_CONN_OK)
+ {
+ /* set channel state */
+ p_lcb->ch_state = AVCT_CH_CFG;
+
+ /* Send L2CAP config req */
+ memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+
+ cfg.mtu_present = TRUE;
+ cfg.mtu = avct_cb.mtu_br;
+
+ cfg.fcr_present = TRUE;
+ cfg.fcr = avct_l2c_br_fcr_opts_def;
+
+ L2CA_ConfigReq(lcid, &cfg);
+ }
+ /* else failure */
+ else
+ {
+ avct_bcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT *) &result);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function avct_l2c_br_config_cfm_cback
+**
+** Description This is the L2CAP config confirm callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void avct_l2c_br_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
+{
+ tAVCT_BCB *p_lcb;
+
+ /* look up lcb for this channel */
+ if ((p_lcb = avct_bcb_by_lcid(lcid)) != NULL)
+ {
+ /* if in correct state */
+ if (p_lcb->ch_state == AVCT_CH_CFG)
+ {
+ /* if result successful */
+ if (p_cfg->result == L2CAP_CFG_OK)
+ {
+ /* update flags */
+ p_lcb->ch_flags |= AVCT_L2C_CFG_CFM_DONE;
+
+ /* if configuration complete */
+ if (p_lcb->ch_flags & AVCT_L2C_CFG_IND_DONE)
+ {
+ p_lcb->ch_state = AVCT_CH_OPEN;
+ avct_bcb_event(p_lcb, AVCT_LCB_LL_OPEN_EVT, NULL);
+ }
+ }
+ /* else failure */
+ else
+ {
+ /* store result value */
+ p_lcb->ch_result = p_cfg->result;
+
+ /* Send L2CAP disconnect req */
+ L2CA_DisconnectReq(lcid);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function avct_l2c_br_config_ind_cback
+**
+** Description This is the L2CAP config indication callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void avct_l2c_br_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
+{
+ tAVCT_BCB *p_lcb;
+ UINT16 max_mtu = GKI_MAX_BUF_SIZE - L2CAP_MIN_OFFSET - BT_HDR_SIZE;
+
+ /* Don't include QoS nor flush timeout in the response since we
+ currently always accept these values. Note: fcr_present is left
+ untouched since l2cap negotiates this internally
+ */
+ p_cfg->flush_to_present = FALSE;
+ p_cfg->qos_present = FALSE;
+
+ /* look up lcb for this channel */
+ if ((p_lcb = avct_bcb_by_lcid(lcid)) != NULL)
+ {
+ /* store the mtu in tbl */
+ if (p_cfg->mtu_present)
+ {
+ p_lcb->peer_mtu = p_cfg->mtu;
+ }
+ else
+ {
+ p_lcb->peer_mtu = L2CAP_DEFAULT_MTU;
+ }
+
+ if (p_lcb->peer_mtu > max_mtu)
+ {
+ p_lcb->peer_mtu = p_cfg->mtu = max_mtu;
+
+ /* Must tell the peer what the adjusted value is */
+ p_cfg->mtu_present = TRUE;
+ }
+ else /* Don't include in the response */
+ p_cfg->mtu_present = FALSE;
+ AVCT_TRACE_DEBUG2 ("avct_l2c_br_config_ind_cback peer_mtu:%d use:%d", p_lcb->peer_mtu, max_mtu);
+
+ if (p_lcb->peer_mtu >= AVCT_MIN_BROWSE_MTU)
+ p_cfg->result = L2CAP_CFG_OK;
+ else
+ {
+ p_cfg->result = L2CAP_CFG_UNACCEPTABLE_PARAMS;
+ p_cfg->mtu_present = TRUE;
+ p_cfg->mtu = AVCT_MIN_BROWSE_MTU;
+ }
+
+ /* send L2CAP configure response */
+ L2CA_ConfigRsp(lcid, p_cfg);
+
+ if (p_cfg->result != L2CAP_CFG_OK)
+ {
+ return;
+ }
+
+ /* if first config ind */
+ if ((p_lcb->ch_flags & AVCT_L2C_CFG_IND_DONE) == 0)
+ {
+ /* update flags */
+ p_lcb->ch_flags |= AVCT_L2C_CFG_IND_DONE;
+
+ /* if configuration complete */
+ if (p_lcb->ch_flags & AVCT_L2C_CFG_CFM_DONE)
+ {
+ p_lcb->ch_state = AVCT_CH_OPEN;
+ avct_bcb_event(p_lcb, AVCT_LCB_LL_OPEN_EVT, NULL);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function avct_l2c_br_disconnect_ind_cback
+**
+** Description This is the L2CAP disconnect indication callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void avct_l2c_br_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed)
+{
+ tAVCT_BCB *p_lcb;
+ UINT16 result = AVCT_RESULT_FAIL;
+
+ /* look up lcb for this channel */
+ if ((p_lcb = avct_bcb_by_lcid(lcid)) != NULL)
+ {
+ if (ack_needed)
+ {
+ /* send L2CAP disconnect response */
+ L2CA_DisconnectRsp(lcid);
+ }
+
+ avct_bcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT *) &result);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avct_l2c_br_disconnect_cfm_cback
+**
+** Description This is the L2CAP disconnect confirm callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void avct_l2c_br_disconnect_cfm_cback(UINT16 lcid, UINT16 result)
+{
+ tAVCT_BCB *p_lcb;
+ UINT16 res;
+
+ /* look up lcb for this channel */
+ if ((p_lcb = avct_bcb_by_lcid(lcid)) != NULL)
+ {
+ /* result value may be previously stored */
+ res = (p_lcb->ch_result != 0) ? p_lcb->ch_result : result;
+ p_lcb->ch_result = 0;
+
+ avct_bcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT *) &res);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avct_l2c_br_congestion_ind_cback
+**
+** Description This is the L2CAP congestion indication callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void avct_l2c_br_congestion_ind_cback(UINT16 lcid, BOOLEAN is_congested)
+{
+ tAVCT_BCB *p_lcb;
+
+ /* look up lcb for this channel */
+ if ((p_lcb = avct_bcb_by_lcid(lcid)) != NULL)
+ {
+ avct_bcb_event(p_lcb, AVCT_LCB_LL_CONG_EVT, (tAVCT_LCB_EVT *) &is_congested);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avct_l2c_br_data_ind_cback
+**
+** Description This is the L2CAP data indication callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void avct_l2c_br_data_ind_cback(UINT16 lcid, BT_HDR *p_buf)
+{
+ tAVCT_BCB *p_lcb;
+
+ /* look up lcb for this channel */
+ if ((p_lcb = avct_bcb_by_lcid(lcid)) != NULL)
+ {
+ avct_bcb_event(p_lcb, AVCT_LCB_LL_MSG_EVT, (tAVCT_LCB_EVT *) &p_buf);
+ }
+ else /* prevent buffer leak */
+ GKI_freebuf(p_buf);
+}
+#endif /* (AVCT_BROWSE_INCLUDED == TRUE) */
+
+
diff --git a/stack/avct/avct_lcb.c b/stack/avct/avct_lcb.c
new file mode 100644
index 0000000..f7127a3
--- /dev/null
+++ b/stack/avct/avct_lcb.c
@@ -0,0 +1,459 @@
+/*****************************************************************************
+**
+** Name: avct_lcb.c
+**
+** Description: This module contains the link control state
+** machine and functions which operate on the link
+** control block.
+**
+** Copyright (c) 2003-2008, WIDCOMM Inc., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include <string.h>
+#include "data_types.h"
+#include "bt_target.h"
+#include "avct_api.h"
+#include "avct_int.h"
+#include "gki.h"
+
+/*****************************************************************************
+** state machine constants and types
+*****************************************************************************/
+
+#if BT_TRACE_VERBOSE == TRUE
+
+/* verbose state strings for trace */
+const char * const avct_lcb_st_str[] = {
+ "LCB_IDLE_ST",
+ "LCB_OPENING_ST",
+ "LCB_OPEN_ST",
+ "LCB_CLOSING_ST"
+};
+
+/* verbose event strings for trace */
+const char * const avct_lcb_evt_str[] = {
+ "UL_BIND_EVT",
+ "UL_UNBIND_EVT",
+ "UL_MSG_EVT",
+ "INT_CLOSE_EVT",
+ "LL_OPEN_EVT",
+ "LL_CLOSE_EVT",
+ "LL_MSG_EVT",
+ "LL_CONG_EVT"
+};
+
+#endif
+
+/* lcb state machine states */
+enum {
+ AVCT_LCB_IDLE_ST,
+ AVCT_LCB_OPENING_ST,
+ AVCT_LCB_OPEN_ST,
+ AVCT_LCB_CLOSING_ST
+};
+
+/* state machine action enumeration list */
+enum {
+ AVCT_LCB_CHNL_OPEN,
+ AVCT_LCB_CHNL_DISC,
+ AVCT_LCB_SEND_MSG,
+ AVCT_LCB_OPEN_IND,
+ AVCT_LCB_OPEN_FAIL,
+ AVCT_LCB_CLOSE_IND,
+ AVCT_LCB_CLOSE_CFM,
+ AVCT_LCB_MSG_IND,
+ AVCT_LCB_CONG_IND,
+ AVCT_LCB_BIND_CONN,
+ AVCT_LCB_BIND_FAIL,
+ AVCT_LCB_UNBIND_DISC,
+ AVCT_LCB_CHK_DISC,
+ AVCT_LCB_DISCARD_MSG,
+ AVCT_LCB_DEALLOC,
+ AVCT_LCB_FREE_MSG_IND,
+ AVCT_LCB_NUM_ACTIONS
+};
+
+#define AVCT_LCB_IGNORE AVCT_LCB_NUM_ACTIONS
+
+/* type for action functions */
+typedef void (*tAVCT_LCB_ACTION)(tAVCT_LCB *p_ccb, tAVCT_LCB_EVT *p_data);
+
+/* action function list */
+const tAVCT_LCB_ACTION avct_lcb_action[] = {
+ avct_lcb_chnl_open,
+ avct_lcb_chnl_disc,
+ avct_lcb_send_msg,
+ avct_lcb_open_ind,
+ avct_lcb_open_fail,
+ avct_lcb_close_ind,
+ avct_lcb_close_cfm,
+ avct_lcb_msg_ind,
+ avct_lcb_cong_ind,
+ avct_lcb_bind_conn,
+ avct_lcb_bind_fail,
+ avct_lcb_unbind_disc,
+ avct_lcb_chk_disc,
+ avct_lcb_discard_msg,
+ avct_lcb_dealloc,
+ avct_lcb_free_msg_ind
+};
+
+/* state table information */
+#define AVCT_LCB_ACTIONS 2 /* number of actions */
+#define AVCT_LCB_NEXT_STATE 2 /* position of next state */
+#define AVCT_LCB_NUM_COLS 3 /* number of columns in state tables */
+
+/* state table for idle state */
+const UINT8 avct_lcb_st_idle[][AVCT_LCB_NUM_COLS] = {
+/* Event Action 1 Action 2 Next state */
+/* UL_BIND_EVT */ {AVCT_LCB_CHNL_OPEN, AVCT_LCB_IGNORE, AVCT_LCB_OPENING_ST},
+/* UL_UNBIND_EVT */ {AVCT_LCB_UNBIND_DISC, AVCT_LCB_IGNORE, AVCT_LCB_IDLE_ST},
+/* UL_MSG_EVT */ {AVCT_LCB_DISCARD_MSG, AVCT_LCB_IGNORE, AVCT_LCB_IDLE_ST},
+/* INT_CLOSE_EVT */ {AVCT_LCB_IGNORE, AVCT_LCB_IGNORE, AVCT_LCB_IDLE_ST},
+/* LL_OPEN_EVT */ {AVCT_LCB_OPEN_IND, AVCT_LCB_IGNORE, AVCT_LCB_OPEN_ST},
+/* LL_CLOSE_EVT */ {AVCT_LCB_CLOSE_IND, AVCT_LCB_DEALLOC, AVCT_LCB_IDLE_ST},
+/* LL_MSG_EVT */ {AVCT_LCB_FREE_MSG_IND, AVCT_LCB_IGNORE, AVCT_LCB_IDLE_ST},
+/* LL_CONG_EVT */ {AVCT_LCB_IGNORE, AVCT_LCB_IGNORE, AVCT_LCB_IDLE_ST}
+};
+
+/* state table for opening state */
+const UINT8 avct_lcb_st_opening[][AVCT_LCB_NUM_COLS] = {
+/* Event Action 1 Action 2 Next state */
+/* UL_BIND_EVT */ {AVCT_LCB_IGNORE, AVCT_LCB_IGNORE, AVCT_LCB_OPENING_ST},
+/* UL_UNBIND_EVT */ {AVCT_LCB_UNBIND_DISC, AVCT_LCB_IGNORE, AVCT_LCB_OPENING_ST},
+/* UL_MSG_EVT */ {AVCT_LCB_DISCARD_MSG, AVCT_LCB_IGNORE, AVCT_LCB_OPENING_ST},
+/* INT_CLOSE_EVT */ {AVCT_LCB_CHNL_DISC, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST},
+/* LL_OPEN_EVT */ {AVCT_LCB_OPEN_IND, AVCT_LCB_IGNORE, AVCT_LCB_OPEN_ST},
+/* LL_CLOSE_EVT */ {AVCT_LCB_OPEN_FAIL, AVCT_LCB_DEALLOC, AVCT_LCB_IDLE_ST},
+/* LL_MSG_EVT */ {AVCT_LCB_FREE_MSG_IND, AVCT_LCB_IGNORE, AVCT_LCB_OPENING_ST},
+/* LL_CONG_EVT */ {AVCT_LCB_CONG_IND, AVCT_LCB_IGNORE, AVCT_LCB_OPENING_ST}
+};
+
+/* state table for open state */
+const UINT8 avct_lcb_st_open[][AVCT_LCB_NUM_COLS] = {
+/* Event Action 1 Action 2 Next state */
+/* UL_BIND_EVT */ {AVCT_LCB_BIND_CONN, AVCT_LCB_IGNORE, AVCT_LCB_OPEN_ST},
+/* UL_UNBIND_EVT */ {AVCT_LCB_CHK_DISC, AVCT_LCB_IGNORE, AVCT_LCB_OPEN_ST},
+/* UL_MSG_EVT */ {AVCT_LCB_SEND_MSG, AVCT_LCB_IGNORE, AVCT_LCB_OPEN_ST},
+/* INT_CLOSE_EVT */ {AVCT_LCB_CHNL_DISC, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST},
+/* LL_OPEN_EVT */ {AVCT_LCB_IGNORE, AVCT_LCB_IGNORE, AVCT_LCB_OPEN_ST},
+/* LL_CLOSE_EVT */ {AVCT_LCB_CLOSE_IND, AVCT_LCB_DEALLOC, AVCT_LCB_IDLE_ST},
+/* LL_MSG_EVT */ {AVCT_LCB_MSG_IND, AVCT_LCB_IGNORE, AVCT_LCB_OPEN_ST},
+/* LL_CONG_EVT */ {AVCT_LCB_CONG_IND, AVCT_LCB_IGNORE, AVCT_LCB_OPEN_ST}
+};
+
+/* state table for closing state */
+const UINT8 avct_lcb_st_closing[][AVCT_LCB_NUM_COLS] = {
+/* Event Action 1 Action 2 Next state */
+/* UL_BIND_EVT */ {AVCT_LCB_BIND_FAIL, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST},
+/* UL_UNBIND_EVT */ {AVCT_LCB_IGNORE, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST},
+/* UL_MSG_EVT */ {AVCT_LCB_DISCARD_MSG, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST},
+/* INT_CLOSE_EVT */ {AVCT_LCB_IGNORE, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST},
+/* LL_OPEN_EVT */ {AVCT_LCB_IGNORE, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST},
+/* LL_CLOSE_EVT */ {AVCT_LCB_CLOSE_CFM, AVCT_LCB_DEALLOC, AVCT_LCB_IDLE_ST},
+/* LL_MSG_EVT */ {AVCT_LCB_FREE_MSG_IND, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST},
+/* LL_CONG_EVT */ {AVCT_LCB_IGNORE, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST}
+};
+
+/* type for state table */
+typedef const UINT8 (*tAVCT_LCB_ST_TBL)[AVCT_LCB_NUM_COLS];
+
+/* state table */
+const tAVCT_LCB_ST_TBL avct_lcb_st_tbl[] = {
+ avct_lcb_st_idle,
+ avct_lcb_st_opening,
+ avct_lcb_st_open,
+ avct_lcb_st_closing
+};
+
+/*******************************************************************************
+**
+** Function avct_lcb_event
+**
+** Description State machine event handling function for lcb
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_lcb_event(tAVCT_LCB *p_lcb, UINT8 event, tAVCT_LCB_EVT *p_data)
+{
+ tAVCT_LCB_ST_TBL state_table;
+ UINT8 action;
+ int i;
+
+#if BT_TRACE_VERBOSE == TRUE
+ AVCT_TRACE_EVENT3("LCB lcb=%d event=%s state=%s", p_lcb->allocated, avct_lcb_evt_str[event], avct_lcb_st_str[p_lcb->state]);
+#else
+ AVCT_TRACE_EVENT3("LCB lcb=%d event=%d state=%d", p_lcb->allocated, event, p_lcb->state);
+#endif
+
+ /* look up the state table for the current state */
+ state_table = avct_lcb_st_tbl[p_lcb->state];
+
+ /* set next state */
+ p_lcb->state = state_table[event][AVCT_LCB_NEXT_STATE];
+
+ /* execute action functions */
+ for (i = 0; i < AVCT_LCB_ACTIONS; i++)
+ {
+ if ((action = state_table[event][i]) != AVCT_LCB_IGNORE)
+ {
+ (*avct_lcb_action[action])(p_lcb, p_data);
+ }
+ else
+ {
+ break;
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function avct_bcb_event
+**
+** Description State machine event handling function for lcb
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+void avct_bcb_event(tAVCT_BCB *p_bcb, UINT8 event, tAVCT_LCB_EVT *p_data)
+{
+ tAVCT_LCB_ST_TBL state_table;
+ UINT8 action;
+ int i;
+
+#if BT_TRACE_VERBOSE == TRUE
+ AVCT_TRACE_EVENT3("BCB lcb=%d event=%s state=%s", p_bcb->allocated, avct_lcb_evt_str[event], avct_lcb_st_str[p_bcb->state]);
+#else
+ AVCT_TRACE_EVENT3("BCB lcb=%d event=%d state=%d", p_bcb->allocated, event, p_bcb->state);
+#endif
+
+ /* look up the state table for the current state */
+ state_table = avct_lcb_st_tbl[p_bcb->state];
+
+ /* set next state */
+ p_bcb->state = state_table[event][AVCT_LCB_NEXT_STATE];
+
+ /* execute action functions */
+ for (i = 0; i < AVCT_LCB_ACTIONS; i++)
+ {
+ if ((action = state_table[event][i]) != AVCT_LCB_IGNORE)
+ {
+ (*avct_bcb_action[action])(p_bcb, p_data);
+ }
+ else
+ {
+ break;
+ }
+ }
+}
+#endif
+
+/*******************************************************************************
+**
+** Function avct_lcb_by_bd
+**
+** Description This lookup function finds the lcb for a BD address.
+**
+**
+** Returns pointer to the lcb, or NULL if none found.
+**
+*******************************************************************************/
+tAVCT_LCB *avct_lcb_by_bd(BD_ADDR bd_addr)
+{
+ tAVCT_LCB *p_lcb = &avct_cb.lcb[0];
+ int i;
+
+ for (i = 0; i < AVCT_NUM_LINKS; i++, p_lcb++)
+ {
+ /* if allocated lcb has matching lcb */
+ if (p_lcb->allocated && (!memcmp(p_lcb->peer_addr, bd_addr, BD_ADDR_LEN)))
+ {
+ break;
+ }
+ }
+
+ if (i == AVCT_NUM_LINKS)
+ {
+ /* if no lcb found */
+ p_lcb = NULL;
+
+ AVCT_TRACE_DEBUG6("No lcb for addr %02x-%02x-%02x-%02x-%02x-%02x",
+ bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
+ }
+ return p_lcb;
+}
+
+/*******************************************************************************
+**
+** Function avct_lcb_alloc
+**
+** Description Allocate a link control block.
+**
+**
+** Returns pointer to the lcb, or NULL if none could be allocated.
+**
+*******************************************************************************/
+tAVCT_LCB *avct_lcb_alloc(BD_ADDR bd_addr)
+{
+ tAVCT_LCB *p_lcb = &avct_cb.lcb[0];
+ int i;
+
+ for (i = 0; i < AVCT_NUM_LINKS; i++, p_lcb++)
+ {
+ if (!p_lcb->allocated)
+ {
+ p_lcb->allocated = (UINT8)(i + 1);
+ memcpy(p_lcb->peer_addr, bd_addr, BD_ADDR_LEN);
+ AVCT_TRACE_DEBUG1("avct_lcb_alloc %d", p_lcb->allocated);
+ break;
+ }
+ }
+
+ if (i == AVCT_NUM_LINKS)
+ {
+ /* out of lcbs */
+ p_lcb = NULL;
+ AVCT_TRACE_WARNING0("Out of lcbs");
+ }
+ return p_lcb;
+}
+
+/*******************************************************************************
+**
+** Function avct_lcb_dealloc
+**
+** Description Deallocate a link control block.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avct_lcb_dealloc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
+{
+ tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
+ BOOLEAN found = FALSE;
+ int i;
+
+ AVCT_TRACE_DEBUG1("avct_lcb_dealloc %d", p_lcb->allocated);
+
+ for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
+ {
+ /* if ccb allocated and */
+ if (p_ccb->allocated)
+ {
+ if (p_ccb->p_lcb == p_lcb)
+ {
+ AVCT_TRACE_DEBUG1("avct_lcb_dealloc used by ccb: %d", i);
+ found = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (!found)
+ {
+ AVCT_TRACE_DEBUG0("avct_lcb_dealloc now");
+
+ /* clear reassembled msg buffer if in use */
+ if (p_lcb->p_rx_msg != NULL)
+ {
+ GKI_freebuf(p_lcb->p_rx_msg);
+ }
+ memset(p_lcb, 0, sizeof(tAVCT_LCB));
+ }
+}
+
+/*******************************************************************************
+**
+** Function avct_lcb_by_lcid
+**
+** Description Find the LCB associated with the L2CAP LCID
+**
+**
+** Returns pointer to the lcb, or NULL if none found.
+**
+*******************************************************************************/
+tAVCT_LCB *avct_lcb_by_lcid(UINT16 lcid)
+{
+ tAVCT_LCB *p_lcb = &avct_cb.lcb[0];
+ int i;
+
+ for (i = 0; i < AVCT_NUM_LINKS; i++, p_lcb++)
+ {
+ if (p_lcb->allocated && ((p_lcb->ch_lcid == lcid) || (p_lcb->conflict_lcid == lcid)))
+ {
+ break;
+ }
+ }
+
+ if (i == AVCT_NUM_LINKS)
+ {
+ /* out of lcbs */
+ p_lcb = NULL;
+ AVCT_TRACE_WARNING1("No lcb for lcid %x", lcid);
+ }
+
+ return p_lcb;
+}
+
+/*******************************************************************************
+**
+** Function avct_lcb_has_pid
+**
+** Description See if any ccbs on this lcb have a particular pid.
+**
+**
+** Returns Pointer to CCB if PID found, NULL otherwise.
+**
+*******************************************************************************/
+tAVCT_CCB *avct_lcb_has_pid(tAVCT_LCB *p_lcb, UINT16 pid)
+{
+ tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
+ int i;
+
+ for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
+ {
+ if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb) && (p_ccb->cc.pid == pid))
+ {
+ return p_ccb;
+ }
+ }
+ return NULL;
+}
+
+/*******************************************************************************
+**
+** Function avct_lcb_last_ccb
+**
+** Description See if given ccb is only one on the lcb.
+**
+**
+** Returns TRUE if ccb is last, FALSE otherwise.
+**
+*******************************************************************************/
+BOOLEAN avct_lcb_last_ccb(tAVCT_LCB *p_lcb, tAVCT_CCB *p_ccb_last)
+{
+ tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
+ int i;
+
+ AVCT_TRACE_WARNING0("avct_lcb_last_ccb");
+ for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
+ {
+ AVCT_TRACE_WARNING6("%x: aloc:%d, lcb:0x%x/0x%x, ccb:0x%x/0x%x",
+ i, p_ccb->allocated, p_ccb->p_lcb, p_lcb, p_ccb, p_ccb_last);
+ if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb) && (p_ccb != p_ccb_last))
+ {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+
+
diff --git a/stack/avct/avct_lcb_act.c b/stack/avct/avct_lcb_act.c
new file mode 100644
index 0000000..8d48c10
--- /dev/null
+++ b/stack/avct/avct_lcb_act.c
@@ -0,0 +1,690 @@
+/*****************************************************************************
+**
+** Name: avct_lcb_act.c
+**
+** Description: This module contains action functions of the link control
+** state machine.
+**
+** Copyright (c) 2003-2008, Broadcom Corp., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include <string.h>
+#include "data_types.h"
+#include "bt_target.h"
+#include "avct_api.h"
+#include "avct_int.h"
+#include "gki.h"
+#include "btm_api.h"
+
+/* packet header length lookup table */
+const UINT8 avct_lcb_pkt_type_len[] = {
+ AVCT_HDR_LEN_SINGLE,
+ AVCT_HDR_LEN_START,
+ AVCT_HDR_LEN_CONT,
+ AVCT_HDR_LEN_END
+};
+
+/*******************************************************************************
+**
+** Function avct_lcb_msg_asmbl
+**
+** Description Reassemble incoming message.
+**
+**
+** Returns Pointer to reassembled message; NULL if no message
+** available.
+**
+*******************************************************************************/
+static BT_HDR *avct_lcb_msg_asmbl(tAVCT_LCB *p_lcb, BT_HDR *p_buf)
+{
+ UINT8 *p;
+ UINT8 pkt_type;
+ BT_HDR *p_ret;
+ UINT16 buf_len;
+
+ /* parse the message header */
+ p = (UINT8 *)(p_buf + 1) + p_buf->offset;
+ AVCT_PRS_PKT_TYPE(p, pkt_type);
+
+ /* quick sanity check on length */
+ if (p_buf->len < avct_lcb_pkt_type_len[pkt_type])
+ {
+ GKI_freebuf(p_buf);
+ AVCT_TRACE_WARNING0("Bad length during reassembly");
+ p_ret = NULL;
+ }
+ /* single packet */
+ else if (pkt_type == AVCT_PKT_TYPE_SINGLE)
+ {
+ /* if reassembly in progress drop message and process new single */
+ if (p_lcb->p_rx_msg != NULL)
+ {
+ GKI_freebuf(p_lcb->p_rx_msg);
+ p_lcb->p_rx_msg = NULL;
+ AVCT_TRACE_WARNING0("Got single during reassembly");
+ }
+ p_ret = p_buf;
+ }
+ /* start packet */
+ else if (pkt_type == AVCT_PKT_TYPE_START)
+ {
+ /* if reassembly in progress drop message and process new start */
+ if (p_lcb->p_rx_msg != NULL)
+ {
+ GKI_freebuf(p_lcb->p_rx_msg);
+ AVCT_TRACE_WARNING0("Got start during reassembly");
+ }
+ p_lcb->p_rx_msg = p_buf;
+
+ /* copy first header byte over nosp */
+ *(p + 1) = *p;
+
+ /* set offset to point to where to copy next */
+ p_lcb->p_rx_msg->offset += p_lcb->p_rx_msg->len;
+
+ /* adjust length for packet header */
+ p_lcb->p_rx_msg->len -= 1;
+
+ p_ret = NULL;
+ }
+ /* continue or end */
+ else
+ {
+ /* if no reassembly in progress drop message */
+ if (p_lcb->p_rx_msg == NULL)
+ {
+ GKI_freebuf(p_buf);
+ AVCT_TRACE_WARNING1("Pkt type=%d out of order", pkt_type);
+ p_ret = NULL;
+ }
+ else
+ {
+ /* get size of buffer holding assembled message */
+ buf_len = GKI_get_buf_size(p_lcb->p_rx_msg) - sizeof(BT_HDR);
+
+ /* adjust offset and len of fragment for header byte */
+ p_buf->offset += AVCT_HDR_LEN_CONT;
+ p_buf->len -= AVCT_HDR_LEN_CONT;
+
+ /* verify length */
+ if ((p_lcb->p_rx_msg->offset + p_buf->len) > buf_len)
+ {
+ /* won't fit; free everything */
+ GKI_freebuf(p_lcb->p_rx_msg);
+ p_lcb->p_rx_msg = NULL;
+ GKI_freebuf(p_buf);
+ p_ret = NULL;
+ AVCT_TRACE_WARNING0("Fragmented message to big!");
+ }
+ else
+ {
+ /* copy contents of p_buf to p_rx_msg */
+ memcpy((UINT8 *)(p_lcb->p_rx_msg + 1) + p_lcb->p_rx_msg->offset,
+ (UINT8 *)(p_buf + 1) + p_buf->offset, p_buf->len);
+
+ if (pkt_type == AVCT_PKT_TYPE_END)
+ {
+ p_lcb->p_rx_msg->offset -= p_lcb->p_rx_msg->len;
+ p_lcb->p_rx_msg->len += p_buf->len;
+ p_ret = p_lcb->p_rx_msg;
+ p_lcb->p_rx_msg = NULL;
+ }
+ else
+ {
+ p_lcb->p_rx_msg->offset += p_buf->len;
+ p_lcb->p_rx_msg->len += p_buf->len;
+ p_ret = NULL;
+ }
+ GKI_freebuf(p_buf);
+ }
+ }
+ }
+ return p_ret;
+}
+
+
+/*******************************************************************************
+**
+** Function avct_lcb_chnl_open
+**
+** Description Open L2CAP channel to peer
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_lcb_chnl_open(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
+{
+ UINT16 result = AVCT_RESULT_FAIL;
+
+ BTM_SetOutService(p_lcb->peer_addr, BTM_SEC_SERVICE_AVCTP, 0);
+ /* call l2cap connect req */
+ p_lcb->ch_state = AVCT_CH_CONN;
+ if ((p_lcb->ch_lcid = L2CA_ConnectReq(AVCT_PSM, p_lcb->peer_addr)) == 0)
+ {
+ /* if connect req failed, send ourselves close event */
+ avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT *) &result);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avct_lcb_unbind_disc
+**
+** Description Deallocate ccb and call callback with disconnect event.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_lcb_unbind_disc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
+{
+ avct_ccb_dealloc(p_data->p_ccb, AVCT_DISCONNECT_CFM_EVT, 0, NULL);
+}
+
+/*******************************************************************************
+**
+** Function avct_lcb_open_ind
+**
+** Description Handle an LL_OPEN event. For each allocated ccb already
+** bound to this lcb, send a connect event. For each
+** unbound ccb with a new PID, bind that ccb to this lcb and
+** send a connect event.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_lcb_open_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
+{
+ tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
+ int i;
+ BOOLEAN bind = FALSE;
+
+ for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
+ {
+ /* if ccb allocated and */
+ if (p_ccb->allocated)
+ {
+ /* if bound to this lcb send connect confirm event */
+ if (p_ccb->p_lcb == p_lcb)
+ {
+ bind = TRUE;
+ L2CA_SetTxPriority(p_lcb->ch_lcid, L2CAP_CHNL_PRIORITY_HIGH);
+ p_ccb->cc.p_ctrl_cback(avct_ccb_to_idx(p_ccb), AVCT_CONNECT_CFM_EVT,
+ 0, p_lcb->peer_addr);
+ }
+ /* if unbound acceptor and lcb doesn't already have a ccb for this PID */
+ else if ((p_ccb->p_lcb == NULL) && (p_ccb->cc.role == AVCT_ACP) &&
+ (avct_lcb_has_pid(p_lcb, p_ccb->cc.pid) == NULL))
+ {
+ /* bind ccb to lcb and send connect ind event */
+ bind = TRUE;
+ p_ccb->p_lcb = p_lcb;
+ L2CA_SetTxPriority(p_lcb->ch_lcid, L2CAP_CHNL_PRIORITY_HIGH);
+ p_ccb->cc.p_ctrl_cback(avct_ccb_to_idx(p_ccb), AVCT_CONNECT_IND_EVT,
+ 0, p_lcb->peer_addr);
+ }
+ }
+ }
+
+ /* if no ccbs bound to this lcb, disconnect */
+ if (bind == FALSE)
+ {
+ avct_lcb_event(p_lcb, AVCT_LCB_INT_CLOSE_EVT, p_data);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avct_lcb_open_fail
+**
+** Description L2CAP channel open attempt failed. Deallocate any ccbs
+** on this lcb and send connect confirm event with failure.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_lcb_open_fail(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
+{
+ tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
+ int i;
+
+ for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
+ {
+ if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb))
+ {
+ avct_ccb_dealloc(p_ccb, AVCT_CONNECT_CFM_EVT,
+ p_data->result, p_lcb->peer_addr);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function avct_lcb_close_ind
+**
+** Description L2CAP channel closed by peer. Deallocate any initiator
+** ccbs on this lcb and send disconnect ind event.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_lcb_close_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
+{
+ tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
+ int i;
+
+ for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
+ {
+ if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb))
+ {
+ if (p_ccb->cc.role == AVCT_INT)
+ {
+ avct_ccb_dealloc(p_ccb, AVCT_DISCONNECT_IND_EVT,
+ 0, p_lcb->peer_addr);
+ }
+ else
+ {
+ p_ccb->p_lcb = NULL;
+ (*p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_ccb), AVCT_DISCONNECT_IND_EVT,
+ 0, p_lcb->peer_addr);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function avct_lcb_close_cfm
+**
+** Description L2CAP channel closed by us. Deallocate any initiator
+** ccbs on this lcb and send disconnect ind or cfm event.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_lcb_close_cfm(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
+{
+ tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
+ int i;
+ UINT8 event;
+
+ for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
+ {
+ if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb))
+ {
+ /* if this ccb initiated close send disconnect cfm otherwise ind */
+ if (p_ccb->ch_close)
+ {
+ p_ccb->ch_close = FALSE;
+ event = AVCT_DISCONNECT_CFM_EVT;
+ }
+ else
+ {
+ event = AVCT_DISCONNECT_IND_EVT;
+ }
+
+ if (p_ccb->cc.role == AVCT_INT)
+ {
+ avct_ccb_dealloc(p_ccb, event, p_data->result, p_lcb->peer_addr);
+ }
+ else
+ {
+ p_ccb->p_lcb = NULL;
+ (*p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_ccb), event,
+ p_data->result, p_lcb->peer_addr);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function avct_lcb_bind_conn
+**
+** Description Bind ccb to lcb and send connect cfm event.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_lcb_bind_conn(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
+{
+ p_data->p_ccb->p_lcb = p_lcb;
+ (*p_data->p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_data->p_ccb),
+ AVCT_CONNECT_CFM_EVT, 0, p_lcb->peer_addr);
+}
+
+/*******************************************************************************
+**
+** Function avct_lcb_chk_disc
+**
+** Description A ccb wants to close; if it is the last ccb on this lcb,
+** close channel. Otherwise just deallocate and call
+** callback.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_lcb_chk_disc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
+{
+ AVCT_TRACE_WARNING0("avct_lcb_chk_disc");
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+ avct_close_bcb(p_lcb, p_data);
+#endif
+ if (avct_lcb_last_ccb(p_lcb, p_data->p_ccb))
+ {
+ AVCT_TRACE_WARNING0("closing");
+ p_data->p_ccb->ch_close = TRUE;
+ avct_lcb_event(p_lcb, AVCT_LCB_INT_CLOSE_EVT, p_data);
+ }
+ else
+ {
+ AVCT_TRACE_WARNING0("dealloc ccb");
+ avct_lcb_unbind_disc(p_lcb, p_data);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avct_lcb_chnl_disc
+**
+** Description Disconnect L2CAP channel.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_lcb_chnl_disc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
+{
+ L2CA_DisconnectReq(p_lcb->ch_lcid);
+}
+
+/*******************************************************************************
+**
+** Function avct_lcb_bind_fail
+**
+** Description Deallocate ccb and call callback with connect event
+** with failure result.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_lcb_bind_fail(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
+{
+ avct_ccb_dealloc(p_data->p_ccb, AVCT_CONNECT_CFM_EVT, AVCT_RESULT_FAIL, NULL);
+}
+
+/*******************************************************************************
+**
+** Function avct_lcb_cong_ind
+**
+** Description Handle congestion indication from L2CAP.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_lcb_cong_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
+{
+ tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
+ int i;
+ UINT8 event;
+ BT_HDR *p_buf;
+
+ /* set event */
+ event = (p_data->cong) ? AVCT_CONG_IND_EVT : AVCT_UNCONG_IND_EVT;
+ p_lcb->cong = p_data->cong;
+ if (p_lcb->cong == FALSE && GKI_getfirst(&p_lcb->tx_q))
+ {
+ while ( !p_lcb->cong && (p_buf = (BT_HDR *)GKI_dequeue(&p_lcb->tx_q)) != NULL)
+ {
+ if (L2CA_DataWrite(p_lcb->ch_lcid, p_buf) == L2CAP_DW_CONGESTED)
+ {
+ p_lcb->cong = TRUE;
+ }
+ }
+ }
+
+ /* send event to all ccbs on this lcb */
+ for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
+ {
+ if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb))
+ {
+ (*p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_ccb), event, 0, p_lcb->peer_addr);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function avct_lcb_discard_msg
+**
+** Description Discard a message sent in from the API.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_lcb_discard_msg(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
+{
+ AVCT_TRACE_WARNING0("Dropping msg");
+
+ GKI_freebuf(p_data->ul_msg.p_buf);
+}
+
+/*******************************************************************************
+**
+** Function avct_lcb_send_msg
+**
+** Description Build and send an AVCTP message.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_lcb_send_msg(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
+{
+ UINT16 curr_msg_len;
+ UINT8 pkt_type;
+ UINT8 hdr_len;
+ BT_HDR *p_buf;
+ UINT8 *p;
+ UINT8 nosp = 0; /* number of subsequent packets */
+ UINT16 temp;
+ UINT16 buf_size = p_lcb->peer_mtu + L2CAP_MIN_OFFSET + BT_HDR_SIZE;
+
+
+ /* store msg len */
+ curr_msg_len = p_data->ul_msg.p_buf->len;
+
+ /* initialize packet type and other stuff */
+ if (curr_msg_len <= (p_lcb->peer_mtu - AVCT_HDR_LEN_SINGLE))
+ {
+ pkt_type = AVCT_PKT_TYPE_SINGLE;
+ }
+ else
+ {
+ pkt_type = AVCT_PKT_TYPE_START;
+ temp = (curr_msg_len + AVCT_HDR_LEN_START - p_lcb->peer_mtu);
+ nosp = temp / (p_lcb->peer_mtu - 1) + 1;
+ if ( (temp % (p_lcb->peer_mtu - 1)) != 0)
+ nosp++;
+ }
+
+ /* while we haven't sent all packets */
+ while (curr_msg_len != 0)
+ {
+ /* set header len */
+ hdr_len = avct_lcb_pkt_type_len[pkt_type];
+
+ /* if remaining msg must be fragmented */
+ if (p_data->ul_msg.p_buf->len > (p_lcb->peer_mtu - hdr_len))
+ {
+ /* get a new buffer for fragment we are sending */
+ if ((p_buf = (BT_HDR *) GKI_getbuf(buf_size)) == NULL)
+ {
+ /* whoops; free original msg buf and bail */
+ AVCT_TRACE_ERROR0 ("avct_lcb_send_msg cannot alloc buffer!!");
+ GKI_freebuf(p_data->ul_msg.p_buf);
+ break;
+ }
+
+ /* copy portion of data from current message to new buffer */
+ p_buf->offset = L2CAP_MIN_OFFSET + hdr_len;
+ p_buf->len = p_lcb->peer_mtu - hdr_len;
+
+ memcpy((UINT8 *)(p_buf + 1) + p_buf->offset,
+ (UINT8 *)(p_data->ul_msg.p_buf + 1) + p_data->ul_msg.p_buf->offset, p_buf->len);
+
+ p_data->ul_msg.p_buf->offset += p_buf->len;
+ p_data->ul_msg.p_buf->len -= p_buf->len;
+ }
+ else
+ {
+ p_buf = p_data->ul_msg.p_buf;
+ }
+
+ curr_msg_len -= p_buf->len;
+
+ /* set up to build header */
+ p_buf->len += hdr_len;
+ p_buf->offset -= hdr_len;
+ p = (UINT8 *)(p_buf + 1) + p_buf->offset;
+
+ /* build header */
+ AVCT_BLD_HDR(p, p_data->ul_msg.label, pkt_type, p_data->ul_msg.cr);
+ if (pkt_type == AVCT_PKT_TYPE_START)
+ {
+ UINT8_TO_STREAM(p, nosp);
+ }
+ if ((pkt_type == AVCT_PKT_TYPE_START) || (pkt_type == AVCT_PKT_TYPE_SINGLE))
+ {
+ UINT16_TO_BE_STREAM(p, p_data->ul_msg.p_ccb->cc.pid);
+ }
+
+ if (p_lcb->cong == TRUE)
+ {
+ GKI_enqueue (&p_lcb->tx_q, p_buf);
+ }
+
+ /* send message to L2CAP */
+ else
+ {
+ if (L2CA_DataWrite(p_lcb->ch_lcid, p_buf) == L2CAP_DW_CONGESTED)
+ {
+ p_lcb->cong = TRUE;
+ }
+ }
+
+ /* update pkt type for next packet */
+ if (curr_msg_len > (p_lcb->peer_mtu - AVCT_HDR_LEN_END))
+ {
+ pkt_type = AVCT_PKT_TYPE_CONT;
+ }
+ else
+ {
+ pkt_type = AVCT_PKT_TYPE_END;
+ }
+ }
+ AVCT_TRACE_DEBUG1 ("avct_lcb_send_msg tx_q_count:%d", p_lcb->tx_q.count);
+ return;
+}
+
+/*******************************************************************************
+**
+** Function avct_lcb_free_msg_ind
+**
+** Description Discard an incoming AVCTP message.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_lcb_free_msg_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
+{
+ if (p_data)
+ GKI_freebuf(p_data->p_buf);
+ return;
+}
+
+/*******************************************************************************
+**
+** Function avct_lcb_msg_ind
+**
+** Description Handle an incoming AVCTP message.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_lcb_msg_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
+{
+ UINT8 *p;
+ UINT8 label, type, cr_ipid;
+ UINT16 pid;
+ tAVCT_CCB *p_ccb;
+ BT_HDR *p_buf;
+
+ /* this p_buf is to be reported through p_msg_cback. The layer_specific
+ * needs to be set properly to indicate that it is received through
+ * control channel */
+ p_data->p_buf->layer_specific = AVCT_DATA_CTRL;
+
+ /* reassemble message; if no message available (we received a fragment) return */
+ if ((p_data->p_buf = avct_lcb_msg_asmbl(p_lcb, p_data->p_buf)) == NULL)
+ {
+ return;
+ }
+
+ p = (UINT8 *)(p_data->p_buf + 1) + p_data->p_buf->offset;
+
+ /* parse header byte */
+ AVCT_PRS_HDR(p, label, type, cr_ipid);
+
+ /* check for invalid cr_ipid */
+ if (cr_ipid == AVCT_CR_IPID_INVALID)
+ {
+ AVCT_TRACE_WARNING1("Invalid cr_ipid", cr_ipid);
+ GKI_freebuf(p_data->p_buf);
+ return;
+ }
+
+ /* parse and lookup PID */
+ BE_STREAM_TO_UINT16(pid, p);
+ if ((p_ccb = avct_lcb_has_pid(p_lcb, pid)) != NULL)
+ {
+ /* PID found; send msg up, adjust bt hdr and call msg callback */
+ p_data->p_buf->offset += AVCT_HDR_LEN_SINGLE;
+ p_data->p_buf->len -= AVCT_HDR_LEN_SINGLE;
+ (*p_ccb->cc.p_msg_cback)(avct_ccb_to_idx(p_ccb), label, cr_ipid, p_data->p_buf);
+ }
+ else
+ {
+ /* PID not found; drop message */
+ AVCT_TRACE_WARNING1("No ccb for PID=%x", pid);
+ GKI_freebuf(p_data->p_buf);
+
+ /* if command send reject */
+ if (cr_ipid == AVCT_CMD)
+ {
+ if ((p_buf = (BT_HDR *) GKI_getpoolbuf(AVCT_CMD_POOL_ID)) != NULL)
+ {
+ p_buf->len = AVCT_HDR_LEN_SINGLE;
+ p_buf->offset = AVCT_MSG_OFFSET - AVCT_HDR_LEN_SINGLE;
+ p = (UINT8 *)(p_buf + 1) + p_buf->offset;
+ AVCT_BLD_HDR(p, label, AVCT_PKT_TYPE_SINGLE, AVCT_REJ);
+ UINT16_TO_BE_STREAM(p, pid);
+ L2CA_DataWrite(p_lcb->ch_lcid, p_buf);
+ }
+ }
+ }
+}
diff --git a/stack/avdt/avdt_ad.c b/stack/avdt/avdt_ad.c
new file mode 100644
index 0000000..cebbb93
--- /dev/null
+++ b/stack/avdt/avdt_ad.c
@@ -0,0 +1,615 @@
+/*****************************************************************************
+**
+** Name: avdt_ad.c
+**
+** Description: This module contains the AVDTP adaption layer.
+**
+** Copyright (c) 2002-2004, WIDCOMM Inc., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include <string.h>
+#include "data_types.h"
+#include "bt_target.h"
+#include "avdt_api.h"
+#include "avdtc_api.h"
+#include "avdt_int.h"
+#include "l2c_api.h"
+#include "l2cdefs.h"
+#include "wcassert.h"
+
+
+/*******************************************************************************
+**
+** Function avdt_ad_type_to_tcid
+**
+** Description Derives the TCID from the channel type and SCB.
+**
+**
+** Returns TCID value.
+**
+*******************************************************************************/
+UINT8 avdt_ad_type_to_tcid(UINT8 type, tAVDT_SCB *p_scb)
+{
+ UINT8 scb_idx;
+
+ if (type == AVDT_CHAN_SIG)
+ {
+ return 0;
+ }
+ else
+ {
+ scb_idx = avdt_scb_to_hdl(p_scb) - 1;
+ /*
+ AVDT_TRACE_DEBUG2("type: %d, tcid: %d", type, ((scb_idx * (AVDT_CHAN_NUM_TYPES - 1)) + type));
+ */
+ return ((scb_idx * (AVDT_CHAN_NUM_TYPES - 1)) + type);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ad_tcid_to_type
+**
+** Description Derives the channel type from the TCID.
+**
+**
+** Returns Channel type value.
+**
+*******************************************************************************/
+static UINT8 avdt_ad_tcid_to_type(UINT8 tcid)
+{
+ UINT8 type;
+
+ if (tcid == 0)
+ {
+ type = AVDT_CHAN_SIG;
+ }
+ else
+ {
+ /* tcid translates to type based on number of channels, as follows:
+ ** only media channel : tcid=1,2,3,4,5,6... type=1,1,1,1,1,1...
+ ** media and report : tcid=1,2,3,4,5,6... type=1,2,1,2,1,2...
+ ** media, report, recov : tcid=1,2,3,4,5,6... type=1,2,3,1,2,3...
+ */
+ type = ((tcid + AVDT_CHAN_NUM_TYPES - 2) % (AVDT_CHAN_NUM_TYPES - 1)) + 1;
+ }
+ AVDT_TRACE_DEBUG2("tcid: %d, type: %d", tcid, type);
+ return type;
+}
+
+
+/*******************************************************************************
+**
+** Function avdt_ad_init
+**
+** Description Initialize adaption layer.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_ad_init(void)
+{
+ int i;
+ tAVDT_TC_TBL *p_tbl = avdt_cb.ad.tc_tbl;
+ memset(&avdt_cb.ad, 0, sizeof(tAVDT_AD));
+
+ /* make sure the peer_mtu is a valid value */
+ for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++)
+ {
+ p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function avdt_ad_tc_tbl_by_st
+**
+** Description Find adaption layer transport channel table entry matching
+** the given state.
+**
+**
+** Returns Pointer to matching entry. For control channel it returns
+** the matching entry. For media or other it returns the
+** first matching entry (there could be more than one).
+**
+*******************************************************************************/
+tAVDT_TC_TBL *avdt_ad_tc_tbl_by_st(UINT8 type, tAVDT_CCB *p_ccb, UINT8 state)
+{
+ int i;
+ tAVDT_TC_TBL *p_tbl = avdt_cb.ad.tc_tbl;
+ UINT8 ccb_idx;
+
+ if (p_ccb == NULL)
+ {
+ /* resending security req */
+ for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++)
+ {
+ /* must be AVDT_CHAN_SIG - tcid always zero */
+ if ((p_tbl->tcid == 0) &&
+ (p_tbl->state == state))
+ {
+ break;
+ }
+ }
+ }
+ else
+ {
+ ccb_idx = avdt_ccb_to_idx(p_ccb);
+
+ for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++)
+ {
+ if (type == AVDT_CHAN_SIG)
+ {
+ /* if control channel, tcid always zero */
+ if ((p_tbl->tcid == 0) &&
+ (p_tbl->ccb_idx == ccb_idx) &&
+ (p_tbl->state == state))
+ {
+ break;
+ }
+ }
+ else
+ {
+ /* if other channel, tcid is always > zero */
+ if ((p_tbl->tcid > 0) &&
+ (p_tbl->ccb_idx == ccb_idx) &&
+ (p_tbl->state == state))
+ {
+ break;
+ }
+ }
+ }
+ }
+
+ /* if nothing found return null */
+ if (i == AVDT_NUM_TC_TBL)
+ {
+ p_tbl = NULL;
+ }
+
+ return p_tbl;
+}
+
+
+/*******************************************************************************
+**
+** Function avdt_ad_tc_tbl_by_lcid
+**
+** Description Find adaption layer transport channel table entry by LCID.
+**
+**
+** Returns Pointer to entry.
+**
+*******************************************************************************/
+tAVDT_TC_TBL *avdt_ad_tc_tbl_by_lcid(UINT16 lcid)
+{
+ UINT8 idx;
+
+ idx = avdt_cb.ad.lcid_tbl[lcid - L2CAP_BASE_APPL_CID];
+
+ if (idx < AVDT_NUM_TC_TBL)
+ {
+ return &avdt_cb.ad.tc_tbl[idx];
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function avdt_ad_tc_tbl_by_type
+**
+** Description This function retrieves the transport channel table entry
+** for a particular channel.
+**
+**
+** Returns Pointer to transport channel table entry.
+**
+*******************************************************************************/
+tAVDT_TC_TBL *avdt_ad_tc_tbl_by_type(UINT8 type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb)
+{
+ UINT8 tcid;
+ int i;
+ tAVDT_TC_TBL *p_tbl = avdt_cb.ad.tc_tbl;
+ UINT8 ccb_idx = avdt_ccb_to_idx(p_ccb);
+
+ /* get tcid from type, scb */
+ tcid = avdt_ad_type_to_tcid(type, p_scb);
+
+ for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++)
+ {
+ if ((p_tbl->tcid == tcid) && (p_tbl->ccb_idx == ccb_idx))
+ {
+ break;
+ }
+ }
+
+ WC_ASSERT(i != AVDT_NUM_TC_TBL);
+
+ return p_tbl;
+}
+
+
+/*******************************************************************************
+**
+** Function avdt_ad_tc_tbl_alloc
+**
+** Description Allocate an entry in the traffic channel table.
+**
+**
+** Returns Pointer to entry.
+**
+*******************************************************************************/
+tAVDT_TC_TBL *avdt_ad_tc_tbl_alloc(tAVDT_CCB *p_ccb)
+{
+ int i;
+ tAVDT_TC_TBL *p_tbl = avdt_cb.ad.tc_tbl;
+
+ /* find next free entry in tc table */
+ for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++)
+ {
+ if (p_tbl->state == AVDT_AD_ST_UNUSED)
+ {
+ break;
+ }
+ }
+
+ /* sanity check */
+ WC_ASSERT(i != AVDT_NUM_TC_TBL);
+
+ /* initialize entry */
+ p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
+ p_tbl->cfg_flags = 0;
+ p_tbl->ccb_idx = avdt_ccb_to_idx(p_ccb);
+ p_tbl->state = AVDT_AD_ST_IDLE;
+
+ return p_tbl;
+}
+
+/*******************************************************************************
+**
+** Function avdt_ad_tc_tbl_to_idx
+**
+** Description Convert a transport channel table entry to an index.
+**
+**
+** Returns Index value.
+**
+*******************************************************************************/
+UINT8 avdt_ad_tc_tbl_to_idx(tAVDT_TC_TBL *p_tbl)
+{
+ AVDT_TRACE_DEBUG1("avdt_ad_tc_tbl_to_idx: %d", (p_tbl - avdt_cb.ad.tc_tbl));
+ /* use array arithmetic to determine index */
+ return (UINT8) (p_tbl - avdt_cb.ad.tc_tbl);
+}
+
+/*******************************************************************************
+**
+** Function avdt_ad_tc_close_ind
+**
+** Description This function is called by the L2CAP interface when the
+** L2CAP channel is closed. It looks up the CCB or SCB for
+** the channel and sends it a close event. The reason
+** parameter is the same value passed by the L2CAP
+** callback function.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_ad_tc_close_ind(tAVDT_TC_TBL *p_tbl, UINT16 reason)
+{
+ tAVDT_CCB *p_ccb;
+ tAVDT_SCB *p_scb;
+ tAVDT_SCB_TC_CLOSE close;
+
+ close.old_tc_state = p_tbl->state;
+ /* clear avdt_ad_tc_tbl entry */
+ p_tbl->state = AVDT_AD_ST_UNUSED;
+ p_tbl->cfg_flags = 0;
+ p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
+
+ AVDT_TRACE_DEBUG2("avdt_ad_tc_close_ind tcid: %d, old: %d",
+ p_tbl->tcid, close.old_tc_state);
+ /* if signaling channel, notify ccb that channel open */
+ if (p_tbl->tcid == 0)
+ {
+ p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx);
+ avdt_ccb_event(p_ccb, AVDT_CCB_LL_CLOSE_EVT, NULL);
+ }
+ /* if media or other channel, notify scb that channel close */
+ else
+ {
+ /* look up scb in stream routing table by ccb, tcid */
+ p_scb = avdt_scb_by_hdl(avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].scb_hdl);
+ if (p_scb != NULL)
+ {
+ close.tcid = p_tbl->tcid;
+ close.type = avdt_ad_tcid_to_type(p_tbl->tcid);
+ avdt_scb_event(p_scb, AVDT_SCB_TC_CLOSE_EVT, (tAVDT_SCB_EVT *)&close);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ad_tc_open_ind
+**
+** Description This function is called by the L2CAP interface when
+** the L2CAP channel is opened. It looks up the CCB or SCB
+** for the channel and sends it an open event.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_ad_tc_open_ind(tAVDT_TC_TBL *p_tbl)
+{
+ tAVDT_CCB *p_ccb;
+ tAVDT_SCB *p_scb;
+ tAVDT_OPEN open;
+ tAVDT_EVT_HDR evt;
+
+ p_tbl->state = AVDT_AD_ST_OPEN;
+
+ /* if signaling channel, notify ccb that channel open */
+ if (p_tbl->tcid == 0)
+ {
+ /* set the signal channel to use high priority within the ACL link */
+ L2CA_SetTxPriority(avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][AVDT_CHAN_SIG].lcid, L2CAP_CHNL_PRIORITY_HIGH);
+
+ p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx);
+ /* use err_param to indicate the role of connection.
+ * AVDT_ACP, if ACP */
+ evt.err_param = AVDT_INT;
+ if(p_tbl->cfg_flags & AVDT_L2C_CFG_CONN_ACP)
+ {
+ evt.err_param = AVDT_ACP;
+ }
+ avdt_ccb_event(p_ccb, AVDT_CCB_LL_OPEN_EVT, (tAVDT_CCB_EVT *)&evt);
+ }
+ /* if media or other channel, notify scb that channel open */
+ else
+ {
+ /* look up scb in stream routing table by ccb, tcid */
+ p_scb = avdt_scb_by_hdl(avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].scb_hdl);
+
+ /* put lcid in event data */
+ if (p_scb != NULL)
+ {
+ open.peer_mtu = p_tbl->peer_mtu;
+ open.lcid = avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].lcid;
+ open.hdr.err_code = avdt_ad_tcid_to_type(p_tbl->tcid);
+ avdt_scb_event(p_scb, AVDT_SCB_TC_OPEN_EVT, (tAVDT_SCB_EVT *) &open);
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function avdt_ad_tc_cong_ind
+**
+** Description This function is called by the L2CAP interface layer when
+** L2CAP calls the congestion callback. It looks up the CCB
+** or SCB for the channel and sends it a congestion event.
+** The is_congested parameter is the same value passed by
+** the L2CAP callback function.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_ad_tc_cong_ind(tAVDT_TC_TBL *p_tbl, BOOLEAN is_congested)
+{
+ tAVDT_CCB *p_ccb;
+ tAVDT_SCB *p_scb;
+
+ /* if signaling channel, notify ccb of congestion */
+ if (p_tbl->tcid == 0)
+ {
+ p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx);
+ avdt_ccb_event(p_ccb, AVDT_CCB_LL_CONG_EVT, (tAVDT_CCB_EVT *) &is_congested);
+ }
+ /* if media or other channel, notify scb that channel open */
+ else
+ {
+ /* look up scb in stream routing table by ccb, tcid */
+ p_scb = avdt_scb_by_hdl(avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].scb_hdl);
+ if (p_scb != NULL)
+ {
+ avdt_scb_event(p_scb, AVDT_SCB_TC_CONG_EVT, (tAVDT_SCB_EVT *) &is_congested);
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function avdt_ad_tc_data_ind
+**
+** Description This function is called by the L2CAP interface layer when
+** incoming data is received from L2CAP. It looks up the CCB
+** or SCB for the channel and routes the data accordingly.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_ad_tc_data_ind(tAVDT_TC_TBL *p_tbl, BT_HDR *p_buf)
+{
+ tAVDT_CCB *p_ccb;
+ tAVDT_SCB *p_scb;
+
+ /* store type (media, recovery, reporting) */
+ p_buf->layer_specific = avdt_ad_tcid_to_type(p_tbl->tcid);
+
+
+ /* if signaling channel, handle control message */
+ if (p_tbl->tcid == 0)
+ {
+ p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx);
+ avdt_msg_ind(p_ccb, p_buf);
+ }
+ /* if media or other channel, send event to scb */
+ else
+ {
+ p_scb = avdt_scb_by_hdl(avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].scb_hdl);
+ if (p_scb != NULL)
+ {
+ avdt_scb_event(p_scb, AVDT_SCB_TC_DATA_EVT, (tAVDT_SCB_EVT *) &p_buf);
+ }
+ else
+ GKI_freebuf(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ad_write_req
+**
+** Description This function is called by a CCB or SCB to send data to a
+** transport channel. It looks up the LCID of the channel
+** based on the type, CCB, and SCB (if present). Then it
+** passes the data to L2CA_DataWrite().
+**
+**
+** Returns AVDT_AD_SUCCESS, if data accepted, else FALSE
+** AVDT_AD_CONGESTED, if data accepted and the channel is congested
+** AVDT_AD_FAILED, if error
+**
+*******************************************************************************/
+UINT8 avdt_ad_write_req(UINT8 type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb, BT_HDR *p_buf)
+{
+ UINT8 tcid;
+
+ /* get tcid from type, scb */
+ tcid = avdt_ad_type_to_tcid(type, p_scb);
+
+
+ return L2CA_DataWrite(avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid, p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function avdt_ad_open_req
+**
+** Description This function is called by a CCB or SCB to open a transport
+** channel. This function allocates and initializes a
+** transport channel table entry. The channel can be opened
+** in two roles: as an initiator or acceptor. When opened
+** as an initiator the function will start an L2CAP connection.
+** When opened as an acceptor the function simply configures
+** the table entry to listen for an incoming channel.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_ad_open_req(UINT8 type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb, UINT8 role)
+{
+ tAVDT_TC_TBL *p_tbl;
+ UINT16 lcid;
+
+ p_tbl = avdt_ad_tc_tbl_alloc(p_ccb);
+
+ p_tbl->tcid = avdt_ad_type_to_tcid(type, p_scb);
+ AVDT_TRACE_DEBUG3("avdt_ad_open_req: type: %d, role: %d, tcid:%d",
+ type, role, p_tbl->tcid);
+
+ if (type == AVDT_CHAN_SIG)
+ {
+ /* if signaling, get mtu from registration control block */
+ p_tbl->my_mtu = avdt_cb.rcb.ctrl_mtu;
+ p_tbl->my_flush_to = L2CAP_DEFAULT_FLUSH_TO;
+ }
+ else
+ {
+ /* otherwise get mtu from scb */
+ p_tbl->my_mtu = p_scb->cs.mtu;
+ p_tbl->my_flush_to = p_scb->cs.flush_to;
+
+ /* also set scb_hdl in rt_tbl */
+ avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][p_tbl->tcid].scb_hdl = avdt_scb_to_hdl(p_scb);
+ AVDT_TRACE_DEBUG3("avdt_cb.ad.rt_tbl[%d][%d].scb_hdl = %d",
+ avdt_ccb_to_idx(p_ccb), p_tbl->tcid,
+ avdt_scb_to_hdl(p_scb));
+ }
+
+ /* if we're acceptor, we're done; just sit back and listen */
+ if (role == AVDT_ACP)
+ {
+ p_tbl->state = AVDT_AD_ST_ACP;
+ }
+ /* else we're inititator, start the L2CAP connection */
+ else
+ {
+ p_tbl->state = AVDT_AD_ST_CONN;
+
+ /* call l2cap connect req */
+ if ((lcid = L2CA_ConnectReq(AVDT_PSM, p_ccb->peer_addr)) != 0)
+ {
+ /* if connect req ok, store tcid in lcid table */
+ avdt_cb.ad.lcid_tbl[lcid - L2CAP_BASE_APPL_CID] = avdt_ad_tc_tbl_to_idx(p_tbl);
+ AVDT_TRACE_DEBUG2("avdt_cb.ad.lcid_tbl[%d] = %d",
+ (lcid - L2CAP_BASE_APPL_CID), avdt_ad_tc_tbl_to_idx(p_tbl));
+
+ avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][p_tbl->tcid].lcid = lcid;
+ AVDT_TRACE_DEBUG3("avdt_cb.ad.rt_tbl[%d][%d].lcid = 0x%x",
+ avdt_ccb_to_idx(p_ccb), p_tbl->tcid,
+ lcid);
+ }
+ else
+ {
+ /* if connect req failed, call avdt_ad_tc_close_ind() */
+ avdt_ad_tc_close_ind(p_tbl, 0);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ad_close_req
+**
+** Description This function is called by a CCB or SCB to close a
+** transport channel. The function looks up the LCID for the
+** channel and calls L2CA_DisconnectReq().
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_ad_close_req(UINT8 type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb)
+{
+ UINT8 tcid;
+ tAVDT_TC_TBL *p_tbl;
+
+ p_tbl = avdt_ad_tc_tbl_by_type(type, p_ccb, p_scb);
+ AVDT_TRACE_DEBUG1("avdt_ad_close_req state: %d", p_tbl->state);
+
+ switch(p_tbl->state)
+ {
+ case AVDT_AD_ST_UNUSED:
+ /* probably for reporting */
+ break;
+ case AVDT_AD_ST_ACP:
+ /* if we're listening on this channel, send ourselves a close ind */
+ avdt_ad_tc_close_ind(p_tbl, 0);
+ break;
+ default:
+ /* get tcid from type, scb */
+ tcid = avdt_ad_type_to_tcid(type, p_scb);
+
+ /* call l2cap disconnect req */
+ L2CA_DisconnectReq(avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid);
+ }
+}
+
diff --git a/stack/avdt/avdt_api.c b/stack/avdt/avdt_api.c
new file mode 100644
index 0000000..02e9e57
--- /dev/null
+++ b/stack/avdt/avdt_api.c
@@ -0,0 +1,1370 @@
+/*****************************************************************************
+**
+** Name: avdt_api.c
+**
+** Description: This module contains API of the audio/video distribution
+** transport protocol.
+**
+** Copyright (c) 2002-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include <string.h>
+#include "data_types.h"
+#include "bt_target.h"
+#include "avdt_api.h"
+#include "avdtc_api.h"
+#include "avdt_int.h"
+#include "l2c_api.h"
+#include "btm_api.h"
+#include "btu.h"
+
+
+#if (defined BTTRC_INCLUDED && BTTRC_INCLUDED == TRUE)
+#include "bttrc_str_ids.h"
+#endif
+
+/* Control block for AVDT */
+#if AVDT_DYNAMIC_MEMORY == FALSE
+tAVDT_CB avdt_cb;
+#endif
+
+
+/*******************************************************************************
+**
+** Function avdt_process_timeout
+**
+** Description This function is called by BTU when an AVDTP timer
+** expires. The function sends a timer event to the
+** appropriate CCB or SCB state machine.
+**
+** This function is for use internal to the stack only.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void avdt_process_timeout(TIMER_LIST_ENT *p_tle)
+{
+ UINT8 event = 0;
+ UINT8 err_code = AVDT_ERR_TIMEOUT;
+
+ switch (p_tle->event)
+ {
+ case BTU_TTYPE_AVDT_CCB_RET:
+ event = AVDT_CCB_RET_TOUT_EVT + AVDT_CCB_MKR;
+ break;
+
+ case BTU_TTYPE_AVDT_CCB_RSP:
+ event = AVDT_CCB_RSP_TOUT_EVT + AVDT_CCB_MKR;
+ break;
+
+ case BTU_TTYPE_AVDT_CCB_IDLE:
+ event = AVDT_CCB_IDLE_TOUT_EVT + AVDT_CCB_MKR;
+ break;
+
+ case BTU_TTYPE_AVDT_SCB_TC:
+ event = AVDT_SCB_TC_TOUT_EVT;
+ break;
+
+ default:
+ break;
+ }
+
+ if (event & AVDT_CCB_MKR)
+ {
+ avdt_ccb_event((tAVDT_CCB *) p_tle->param, (UINT8) (event & ~AVDT_CCB_MKR),
+ (tAVDT_CCB_EVT *) &err_code);
+ }
+ else
+ {
+ avdt_scb_event((tAVDT_SCB *) p_tle->param, event, NULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function AVDT_Register
+**
+** Description This is the system level registration function for the
+** AVDTP protocol. This function initializes AVDTP and
+** prepares the protocol stack for its use. This function
+** must be called once by the system or platform using AVDTP
+** before the other functions of the API an be used.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void AVDT_Register(tAVDT_REG *p_reg, tAVDT_CTRL_CBACK *p_cback)
+{
+
+ BTTRC_AVDT_API0(AVDT_TRACE_API_REGISTER);
+
+ /* register PSM with L2CAP */
+ L2CA_Register(AVDT_PSM, (tL2CAP_APPL_INFO *) &avdt_l2c_appl);
+
+ /* set security level */
+ BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_AVDTP, p_reg->sec_mask,
+ AVDT_PSM, BTM_SEC_PROTO_AVDT, AVDT_CHAN_SIG);
+ BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_AVDTP, p_reg->sec_mask,
+ AVDT_PSM, BTM_SEC_PROTO_AVDT, AVDT_CHAN_SIG);
+
+ /* do not use security on the media channel */
+ BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_AVDTP_NOSEC, BTM_SEC_NONE,
+ AVDT_PSM, BTM_SEC_PROTO_AVDT, AVDT_CHAN_MEDIA);
+ BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_AVDTP_NOSEC, BTM_SEC_NONE,
+ AVDT_PSM, BTM_SEC_PROTO_AVDT, AVDT_CHAN_MEDIA);
+
+#if AVDT_REPORTING == TRUE
+ /* do not use security on the reporting channel */
+ BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_AVDTP_NOSEC, BTM_SEC_NONE,
+ AVDT_PSM, BTM_SEC_PROTO_AVDT, AVDT_CHAN_REPORT);
+ BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_AVDTP_NOSEC, BTM_SEC_NONE,
+ AVDT_PSM, BTM_SEC_PROTO_AVDT, AVDT_CHAN_REPORT);
+#endif
+
+ /* initialize AVDTP data structures */
+ avdt_scb_init();
+ avdt_ccb_init();
+ avdt_ad_init();
+#if defined(AVDT_INITIAL_TRACE_LEVEL)
+ avdt_cb.trace_level = AVDT_INITIAL_TRACE_LEVEL;
+#else
+ avdt_cb.trace_level = BT_TRACE_LEVEL_NONE;
+#endif
+
+ /* copy registration struct */
+ memcpy(&avdt_cb.rcb, p_reg, sizeof(tAVDT_REG));
+ avdt_cb.p_conn_cback = p_cback;
+}
+
+/*******************************************************************************
+**
+** Function AVDT_Deregister
+**
+** Description This function is called to deregister use AVDTP protocol.
+** It is called when AVDTP is no longer being used by any
+** application in the system. Before this function can be
+** called, all streams must be removed with AVDT_RemoveStream().
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void AVDT_Deregister(void)
+{
+ BTTRC_AVDT_API0(AVDT_TRACE_API_DEREGISTER);
+
+ /* deregister PSM with L2CAP */
+ L2CA_Deregister(AVDT_PSM);
+}
+
+/*******************************************************************************
+**
+** Function AVDT_CreateStream
+**
+** Description Create a stream endpoint. After a stream endpoint is
+** created an application can initiate a connection between
+** this endpoint and an endpoint on a peer device. In
+** addition, a peer device can discover, get the capabilities,
+** and connect to this endpoint.
+**
+**
+** Returns AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+UINT16 AVDT_CreateStream(UINT8 *p_handle, tAVDT_CS *p_cs)
+{
+ UINT16 result = AVDT_SUCCESS;
+ tAVDT_SCB *p_scb;
+
+ BTTRC_AVDT_API0(AVDT_TRACE_API_CREATESTREAM);
+
+ /* Verify parameters; if invalid, return failure */
+ if (((p_cs->cfg.psc_mask & (~AVDT_PSC)) != 0) || (p_cs->p_ctrl_cback == NULL))
+ {
+ result = AVDT_BAD_PARAMS;
+ }
+ /* Allocate scb; if no scbs, return failure */
+ else if ((p_scb = avdt_scb_alloc(p_cs)) == NULL)
+ {
+ result = AVDT_NO_RESOURCES;
+ }
+ else
+ {
+ *p_handle = avdt_scb_to_hdl(p_scb);
+ }
+ return result;
+}
+
+/*******************************************************************************
+**
+** Function AVDT_RemoveStream
+**
+** Description Remove a stream endpoint. This function is called when
+** the application is no longer using a stream endpoint.
+** If this function is called when the endpoint is connected
+** the connection is closed and then the stream endpoint
+** is removed.
+**
+**
+** Returns AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+UINT16 AVDT_RemoveStream(UINT8 handle)
+{
+ UINT16 result = AVDT_SUCCESS;
+ tAVDT_SCB *p_scb;
+
+
+ BTTRC_AVDT_API0(AVDT_TRACE_API_REMOVESTREAM);
+
+ /* look up scb */
+ if ((p_scb = avdt_scb_by_hdl(handle)) == NULL)
+ {
+ result = AVDT_BAD_HANDLE;
+ }
+ else
+ {
+ /* send remove event to scb */
+ avdt_scb_event(p_scb, AVDT_SCB_API_REMOVE_EVT, NULL);
+ }
+ return result;
+}
+
+/*******************************************************************************
+**
+** Function AVDT_DiscoverReq
+**
+** Description This function initiates a connection to the AVDTP service
+** on the peer device, if not already present, and discovers
+** the stream endpoints on the peer device. (Please note
+** that AVDTP discovery is unrelated to SDP discovery).
+** This function can be called at any time regardless of whether
+** there is an AVDTP connection to the peer device.
+**
+** When discovery is complete, an AVDT_DISCOVER_CFM_EVT
+** is sent to the application via its callback function.
+** The application must not call AVDT_GetCapReq() or
+** AVDT_DiscoverReq() again to the same device until
+** discovery is complete.
+**
+** The memory addressed by sep_info is allocated by the
+** application. This memory is written to by AVDTP as part
+** of the discovery procedure. This memory must remain
+** accessible until the application receives the
+** AVDT_DISCOVER_CFM_EVT.
+**
+** Returns AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+UINT16 AVDT_DiscoverReq(BD_ADDR bd_addr, tAVDT_SEP_INFO *p_sep_info,
+ UINT8 max_seps, tAVDT_CTRL_CBACK *p_cback)
+{
+ tAVDT_CCB *p_ccb;
+ UINT16 result = AVDT_SUCCESS;
+ tAVDT_CCB_EVT evt;
+
+ BTTRC_AVDT_API0(AVDT_TRACE_API_DISCOVER_REQ);
+
+ /* find channel control block for this bd addr; if none, allocate one */
+ if ((p_ccb = avdt_ccb_by_bd(bd_addr)) == NULL)
+ {
+ if ((p_ccb = avdt_ccb_alloc(bd_addr)) == NULL)
+ {
+ /* could not allocate channel control block */
+ result = AVDT_NO_RESOURCES;
+ }
+ }
+
+ if (result == AVDT_SUCCESS)
+ {
+ /* make sure no discovery or get capabilities req already in progress */
+ if (p_ccb->proc_busy)
+ {
+ result = AVDT_BUSY;
+ }
+ /* send event to ccb */
+ else
+ {
+ evt.discover.p_sep_info = p_sep_info;
+ evt.discover.num_seps = max_seps;
+ evt.discover.p_cback = p_cback;
+ avdt_ccb_event(p_ccb, AVDT_CCB_API_DISCOVER_REQ_EVT, &evt);
+ }
+ }
+ return result;
+}
+
+/*******************************************************************************
+**
+** Function avdt_get_cap_req
+**
+** Description internal function to serve both AVDT_GetCapReq and
+** AVDT_GetAllCapReq
+**
+** Returns AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+static UINT16 avdt_get_cap_req(BD_ADDR bd_addr, tAVDT_CCB_API_GETCAP *p_evt)
+{
+ tAVDT_CCB *p_ccb = NULL;
+ UINT16 result = AVDT_SUCCESS;
+
+ /* verify SEID */
+ if ((p_evt->single.seid < AVDT_SEID_MIN) || (p_evt->single.seid > AVDT_SEID_MAX))
+ {
+ AVDT_TRACE_ERROR1("seid: %d", p_evt->single.seid);
+ result = AVDT_BAD_PARAMS;
+ }
+ /* find channel control block for this bd addr; if none, allocate one */
+ else if ((p_ccb = avdt_ccb_by_bd(bd_addr)) == NULL)
+ {
+ if ((p_ccb = avdt_ccb_alloc(bd_addr)) == NULL)
+ {
+ /* could not allocate channel control block */
+ result = AVDT_NO_RESOURCES;
+ }
+ }
+
+ if (result == AVDT_SUCCESS)
+ {
+ /* make sure no discovery or get capabilities req already in progress */
+ if (p_ccb->proc_busy)
+ {
+ result = AVDT_BUSY;
+ }
+ /* send event to ccb */
+ else
+ {
+ avdt_ccb_event(p_ccb, AVDT_CCB_API_GETCAP_REQ_EVT, (tAVDT_CCB_EVT *)p_evt);
+ }
+ }
+ return result;
+}
+
+/*******************************************************************************
+**
+** Function AVDT_GetCapReq
+**
+** Description This function initiates a connection to the AVDTP service
+** on the peer device, if not already present, and gets the
+** capabilities of a stream endpoint on the peer device.
+** This function can be called at any time regardless of
+** whether there is an AVDTP connection to the peer device.
+**
+** When the procedure is complete, an AVDT_GETCAP_CFM_EVT is
+** sent to the application via its callback function. The
+** application must not call AVDT_GetCapReq() or
+** AVDT_DiscoverReq() again until the procedure is complete.
+**
+** The memory pointed to by p_cfg is allocated by the
+** application. This memory is written to by AVDTP as part
+** of the get capabilities procedure. This memory must
+** remain accessible until the application receives
+** the AVDT_GETCAP_CFM_EVT.
+**
+** Returns AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+UINT16 AVDT_GetCapReq(BD_ADDR bd_addr, UINT8 seid, tAVDT_CFG *p_cfg, tAVDT_CTRL_CBACK *p_cback)
+{
+ tAVDT_CCB_API_GETCAP getcap;
+
+ BTTRC_AVDT_API1(AVDT_TRACE_API_GETCAP_REQ, BTTRC_PARAM_UINT8, seid);
+
+ getcap.single.seid = seid;
+ getcap.single.sig_id = AVDT_SIG_GETCAP;
+ getcap.p_cfg = p_cfg;
+ getcap.p_cback = p_cback;
+ return avdt_get_cap_req (bd_addr, &getcap);
+}
+
+/*******************************************************************************
+**
+** Function AVDT_GetAllCapReq
+**
+** Description This function initiates a connection to the AVDTP service
+** on the peer device, if not already present, and gets the
+** capabilities of a stream endpoint on the peer device.
+** This function can be called at any time regardless of
+** whether there is an AVDTP connection to the peer device.
+**
+** When the procedure is complete, an AVDT_GETCAP_CFM_EVT is
+** sent to the application via its callback function. The
+** application must not call AVDT_GetCapReq() or
+** AVDT_DiscoverReq() again until the procedure is complete.
+**
+** The memory pointed to by p_cfg is allocated by the
+** application. This memory is written to by AVDTP as part
+** of the get capabilities procedure. This memory must
+** remain accessible until the application receives
+** the AVDT_GETCAP_CFM_EVT.
+**
+** Returns AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+UINT16 AVDT_GetAllCapReq(BD_ADDR bd_addr, UINT8 seid, tAVDT_CFG *p_cfg, tAVDT_CTRL_CBACK *p_cback)
+{
+ tAVDT_CCB_API_GETCAP getcap;
+
+ BTTRC_AVDT_API1(AVDT_TRACE_API_GET_ALLCAP_REQ, BTTRC_PARAM_UINT8, seid);
+
+ getcap.single.seid = seid;
+ getcap.single.sig_id = AVDT_SIG_GET_ALLCAP;
+ getcap.p_cfg = p_cfg;
+ getcap.p_cback = p_cback;
+ return avdt_get_cap_req (bd_addr, &getcap);
+}
+
+/*******************************************************************************
+**
+** Function AVDT_DelayReport
+**
+** Description This functions sends a Delay Report to the peer device
+** that is associated with a particular SEID.
+** This function is called by SNK device.
+**
+** Returns AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+UINT16 AVDT_DelayReport(UINT8 handle, UINT8 seid, UINT16 delay)
+{
+ tAVDT_SCB *p_scb;
+ UINT16 result = AVDT_SUCCESS;
+ tAVDT_SCB_EVT evt;
+
+ BTTRC_AVDT_API0(AVDT_TRACE_API_DELAY_REPORT);
+
+ /* map handle to scb */
+ if ((p_scb = avdt_scb_by_hdl(handle)) == NULL)
+ {
+ result = AVDT_BAD_HANDLE;
+ }
+ else
+ /* send event to scb */
+ {
+ evt.apidelay.hdr.seid = seid;
+ evt.apidelay.delay = delay;
+ avdt_scb_event(p_scb, AVDT_SCB_API_DELAY_RPT_REQ_EVT, &evt);
+ }
+
+ return result;
+}
+
+/*******************************************************************************
+**
+** Function AVDT_OpenReq
+**
+** Description This function initiates a connection to the AVDTP service
+** on the peer device, if not already present, and connects
+** to a stream endpoint on a peer device. When the connection
+** is completed, an AVDT_OPEN_CFM_EVT is sent to the
+** application via the control callback function for this handle.
+**
+** Returns AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+UINT16 AVDT_OpenReq(UINT8 handle, BD_ADDR bd_addr, UINT8 seid, tAVDT_CFG *p_cfg)
+{
+ tAVDT_CCB *p_ccb = NULL;
+ tAVDT_SCB *p_scb = NULL;
+ UINT16 result = AVDT_SUCCESS;
+ tAVDT_SCB_EVT evt;
+
+ BTTRC_AVDT_API0(AVDT_TRACE_API_OPEN_REQ);
+
+
+ /* verify SEID */
+ if ((seid < AVDT_SEID_MIN) || (seid > AVDT_SEID_MAX))
+ {
+ result = AVDT_BAD_PARAMS;
+ }
+ /* map handle to scb */
+ else if ((p_scb = avdt_scb_by_hdl(handle)) == NULL)
+ {
+ result = AVDT_BAD_HANDLE;
+ }
+ /* find channel control block for this bd addr; if none, allocate one */
+ else if ((p_ccb = avdt_ccb_by_bd(bd_addr)) == NULL)
+ {
+ if ((p_ccb = avdt_ccb_alloc(bd_addr)) == NULL)
+ {
+ /* could not allocate channel control block */
+ result = AVDT_NO_RESOURCES;
+ }
+ }
+
+ /* send event to scb */
+ if (result == AVDT_SUCCESS)
+ {
+ evt.msg.config_cmd.hdr.seid = seid;
+ evt.msg.config_cmd.hdr.ccb_idx = avdt_ccb_to_idx(p_ccb);
+ evt.msg.config_cmd.int_seid = handle;
+ evt.msg.config_cmd.p_cfg = p_cfg;
+ avdt_scb_event(p_scb, AVDT_SCB_API_SETCONFIG_REQ_EVT, &evt);
+ }
+ return result;
+}
+
+/*******************************************************************************
+**
+** Function AVDT_ConfigRsp
+**
+** Description Respond to a configure request from the peer device. This
+** function must be called if the application receives an
+** AVDT_CONFIG_IND_EVT through its control callback.
+**
+**
+** Returns AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+UINT16 AVDT_ConfigRsp(UINT8 handle, UINT8 label, UINT8 error_code, UINT8 category)
+{
+ tAVDT_SCB *p_scb;
+ tAVDT_SCB_EVT evt;
+ UINT16 result = AVDT_SUCCESS;
+ UINT8 event_code;
+
+ BTTRC_AVDT_API0(AVDT_TRACE_API_CONFIG_RSP);
+
+ /* map handle to scb */
+ if ((p_scb = avdt_scb_by_hdl(handle)) == NULL)
+ {
+ result = AVDT_BAD_HANDLE;
+ }
+ /* handle special case when this function is called but peer has not send
+ ** a configuration cmd; ignore and return error result
+ */
+ else if (!p_scb->in_use)
+ {
+ result = AVDT_BAD_HANDLE;
+ }
+ /* send event to scb */
+ else
+ {
+ evt.msg.hdr.err_code = error_code;
+ evt.msg.hdr.err_param = category;
+ evt.msg.hdr.label = label;
+ if (error_code == 0)
+ {
+ event_code = AVDT_SCB_API_SETCONFIG_RSP_EVT;
+ }
+ else
+ {
+ event_code = AVDT_SCB_API_SETCONFIG_REJ_EVT;
+ }
+ avdt_scb_event(p_scb, event_code, &evt);
+ }
+
+ return result;
+}
+
+/*******************************************************************************
+**
+** Function AVDT_StartReq
+**
+** Description Start one or more stream endpoints. This initiates the
+** transfer of media packets for the streams. All stream
+** endpoints must previously be opened. When the streams
+** are started, an AVDT_START_CFM_EVT is sent to the
+** application via the control callback function for each stream.
+**
+**
+** Returns AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+UINT16 AVDT_StartReq(UINT8 *p_handles, UINT8 num_handles)
+{
+ tAVDT_SCB *p_scb = NULL;
+ tAVDT_CCB_EVT evt;
+ UINT16 result = AVDT_SUCCESS;
+ int i;
+
+ BTTRC_AVDT_API0(AVDT_TRACE_API_START_REQ);
+
+ if ((num_handles == 0) || (num_handles > AVDT_NUM_SEPS))
+ {
+ result = AVDT_BAD_PARAMS;
+ }
+ else
+ {
+ /* verify handles */
+ for (i = 0; i < num_handles; i++)
+ {
+ if ((p_scb = avdt_scb_by_hdl(p_handles[i])) == NULL)
+ {
+ result = AVDT_BAD_HANDLE;
+ break;
+ }
+ }
+ }
+
+ if (result == AVDT_SUCCESS)
+ {
+ if (p_scb->p_ccb == NULL)
+ {
+ result = AVDT_BAD_HANDLE;
+ }
+ else
+ {
+ /* send event to ccb */
+ memcpy(evt.msg.multi.seid_list, p_handles, num_handles);
+ evt.msg.multi.num_seps = num_handles;
+ avdt_ccb_event(p_scb->p_ccb, AVDT_CCB_API_START_REQ_EVT, &evt);
+ }
+ }
+ return result;
+}
+
+/*******************************************************************************
+**
+** Function AVDT_SuspendReq
+**
+** Description Suspend one or more stream endpoints. This suspends the
+** transfer of media packets for the streams. All stream
+** endpoints must previously be open and started. When the
+** streams are suspended, an AVDT_SUSPEND_CFM_EVT is sent to
+** the application via the control callback function for
+** each stream.
+**
+**
+** Returns AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+UINT16 AVDT_SuspendReq(UINT8 *p_handles, UINT8 num_handles)
+{
+ tAVDT_SCB *p_scb = NULL;
+ tAVDT_CCB_EVT evt;
+ UINT16 result = AVDT_SUCCESS;
+ int i;
+
+ BTTRC_AVDT_API0(AVDT_TRACE_API_SUSPEND_REQ);
+
+ if ((num_handles == 0) || (num_handles > AVDT_NUM_SEPS))
+ {
+ result = AVDT_BAD_PARAMS;
+ }
+ else
+ {
+ /* verify handles */
+ for (i = 0; i < num_handles; i++)
+ {
+ if ((p_scb = avdt_scb_by_hdl(p_handles[i])) == NULL)
+ {
+ result = AVDT_BAD_HANDLE;
+ break;
+ }
+ }
+ }
+
+ if (result == AVDT_SUCCESS)
+ {
+ if (p_scb->p_ccb == NULL)
+ {
+ result = AVDT_BAD_HANDLE;
+ }
+ else
+ {
+ /* send event to ccb */
+ memcpy(evt.msg.multi.seid_list, p_handles, num_handles);
+ evt.msg.multi.num_seps = num_handles;
+ avdt_ccb_event(p_scb->p_ccb, AVDT_CCB_API_SUSPEND_REQ_EVT, &evt);
+ }
+ }
+
+ return result;
+}
+
+/*******************************************************************************
+**
+** Function AVDT_CloseReq
+**
+** Description Close a stream endpoint. This stops the transfer of media
+** packets and closes the transport channel associated with
+** this stream endpoint. When the stream is closed, an
+** AVDT_CLOSE_CFM_EVT is sent to the application via the
+** control callback function for this handle.
+**
+**
+** Returns AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+UINT16 AVDT_CloseReq(UINT8 handle)
+{
+ tAVDT_SCB *p_scb;
+ UINT16 result = AVDT_SUCCESS;
+
+ BTTRC_AVDT_API0(AVDT_TRACE_API_CLOSE_REQ);
+
+ /* map handle to scb */
+ if ((p_scb = avdt_scb_by_hdl(handle)) == NULL)
+ {
+ result = AVDT_BAD_HANDLE;
+ }
+ else
+ /* send event to scb */
+ {
+ avdt_scb_event(p_scb, AVDT_SCB_API_CLOSE_REQ_EVT, NULL);
+ }
+
+ return result;
+}
+
+/*******************************************************************************
+**
+** Function AVDT_ReconfigReq
+**
+** Description Reconfigure a stream endpoint. This allows the application
+** to change the codec or content protection capabilities of
+** a stream endpoint after it has been opened. This function
+** can only be called if the stream is opened but not started
+** or if the stream has been suspended. When the procedure
+** is completed, an AVDT_RECONFIG_CFM_EVT is sent to the
+** application via the control callback function for this handle.
+**
+**
+** Returns AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+UINT16 AVDT_ReconfigReq(UINT8 handle, tAVDT_CFG *p_cfg)
+{
+ tAVDT_SCB *p_scb;
+ UINT16 result = AVDT_SUCCESS;
+ tAVDT_SCB_EVT evt;
+
+ BTTRC_AVDT_API0(AVDT_TRACE_API_RECONFIG_REQ);
+
+ /* map handle to scb */
+ if ((p_scb = avdt_scb_by_hdl(handle)) == NULL)
+ {
+ result = AVDT_BAD_HANDLE;
+ }
+ /* send event to scb */
+ else
+ {
+ /* force psc_mask to zero */
+ p_cfg->psc_mask = 0;
+
+ evt.msg.reconfig_cmd.p_cfg = p_cfg;
+ avdt_scb_event(p_scb, AVDT_SCB_API_RECONFIG_REQ_EVT, &evt);
+ }
+ return result;
+}
+
+/*******************************************************************************
+**
+** Function AVDT_ReconfigRsp
+**
+** Description Respond to a reconfigure request from the peer device.
+** This function must be called if the application receives
+** an AVDT_RECONFIG_IND_EVT through its control callback.
+**
+**
+** Returns AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+UINT16 AVDT_ReconfigRsp(UINT8 handle, UINT8 label, UINT8 error_code, UINT8 category)
+{
+ tAVDT_SCB *p_scb;
+ tAVDT_SCB_EVT evt;
+ UINT16 result = AVDT_SUCCESS;
+
+ BTTRC_AVDT_API0(AVDT_TRACE_API_RECONFIG_RSP);
+
+ /* map handle to scb */
+ if ((p_scb = avdt_scb_by_hdl(handle)) == NULL)
+ {
+ result = AVDT_BAD_HANDLE;
+ }
+ /* send event to scb */
+ else
+ {
+ evt.msg.hdr.err_code = error_code;
+ evt.msg.hdr.err_param = category;
+ evt.msg.hdr.label = label;
+ avdt_scb_event(p_scb, AVDT_SCB_API_RECONFIG_RSP_EVT, &evt);
+ }
+
+ return result;
+}
+
+/*******************************************************************************
+**
+** Function AVDT_SecurityReq
+**
+** Description Send a security request to the peer device. When the
+** security procedure is completed, an AVDT_SECURITY_CFM_EVT
+** is sent to the application via the control callback function
+** for this handle. (Please note that AVDTP security procedures
+** are unrelated to Bluetooth link level security.)
+**
+**
+** Returns AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+UINT16 AVDT_SecurityReq(UINT8 handle, UINT8 *p_data, UINT16 len)
+{
+ tAVDT_SCB *p_scb;
+ UINT16 result = AVDT_SUCCESS;
+ tAVDT_SCB_EVT evt;
+
+ BTTRC_AVDT_API0(AVDT_TRACE_API_SECURITY_REQ);
+
+ /* map handle to scb */
+ if ((p_scb = avdt_scb_by_hdl(handle)) == NULL)
+ {
+ result = AVDT_BAD_HANDLE;
+ }
+ /* send event to scb */
+ else
+ {
+ evt.msg.security_rsp.p_data = p_data;
+ evt.msg.security_rsp.len = len;
+ avdt_scb_event(p_scb, AVDT_SCB_API_SECURITY_REQ_EVT, &evt);
+ }
+ return result;
+}
+
+/*******************************************************************************
+**
+** Function AVDT_SecurityRsp
+**
+** Description Respond to a security request from the peer device.
+** This function must be called if the application receives
+** an AVDT_SECURITY_IND_EVT through its control callback.
+** (Please note that AVDTP security procedures are unrelated
+** to Bluetooth link level security.)
+**
+**
+** Returns AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+UINT16 AVDT_SecurityRsp(UINT8 handle, UINT8 label, UINT8 error_code,
+ UINT8 *p_data, UINT16 len)
+{
+ tAVDT_SCB *p_scb;
+ UINT16 result = AVDT_SUCCESS;
+ tAVDT_SCB_EVT evt;
+
+ BTTRC_AVDT_API0(AVDT_TRACE_API_SECURITY_RSP);
+
+ /* map handle to scb */
+ if ((p_scb = avdt_scb_by_hdl(handle)) == NULL)
+ {
+ result = AVDT_BAD_HANDLE;
+ }
+ /* send event to scb */
+ else
+ {
+ evt.msg.security_rsp.hdr.err_code = error_code;
+ evt.msg.security_rsp.hdr.label = label;
+ evt.msg.security_rsp.p_data = p_data;
+ evt.msg.security_rsp.len = len;
+ avdt_scb_event(p_scb, AVDT_SCB_API_SECURITY_RSP_EVT, &evt);
+ }
+ return result;
+}
+
+/*******************************************************************************
+**
+** Function AVDT_WriteReq
+**
+** Description Send a media packet to the peer device. The stream must
+** be started before this function is called. Also, this
+** function can only be called if the stream is a SRC.
+**
+** When AVDTP has sent the media packet and is ready for the
+** next packet, an AVDT_WRITE_CFM_EVT is sent to the
+** application via the control callback. The application must
+** wait for the AVDT_WRITE_CFM_EVT before it makes the next
+** call to AVDT_WriteReq(). If the applications calls
+** AVDT_WriteReq() before it receives the event the packet
+** will not be sent. The application may make its first call
+** to AVDT_WriteReq() after it receives an AVDT_START_CFM_EVT
+** or AVDT_START_IND_EVT.
+**
+** The application passes the packet using the BT_HDR structure.
+** This structure is described in section 2.1. The offset
+** field must be equal to or greater than AVDT_MEDIA_OFFSET.
+** This allows enough space in the buffer for the L2CAP and
+** AVDTP headers.
+**
+** The memory pointed to by p_pkt must be a GKI buffer
+** allocated by the application. This buffer will be freed
+** by the protocol stack; the application must not free
+** this buffer.
+**
+**
+** Returns AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+UINT16 AVDT_WriteReq(UINT8 handle, BT_HDR *p_pkt, UINT32 time_stamp, UINT8 m_pt)
+{
+ tAVDT_SCB *p_scb;
+ tAVDT_SCB_EVT evt;
+ UINT16 result = AVDT_SUCCESS;
+
+ BTTRC_AVDT_API0(AVDT_TRACE_API_WRITE_REQ);
+
+ /* map handle to scb */
+ if ((p_scb = avdt_scb_by_hdl(handle)) == NULL)
+ {
+ result = AVDT_BAD_HANDLE;
+ }
+ else
+ {
+ evt.apiwrite.p_buf = p_pkt;
+ evt.apiwrite.time_stamp = time_stamp;
+ evt.apiwrite.m_pt = m_pt;
+#if AVDT_MULTIPLEXING == TRUE
+ GKI_init_q (&evt.apiwrite.frag_q);
+#endif
+ avdt_scb_event(p_scb, AVDT_SCB_API_WRITE_REQ_EVT, &evt);
+ }
+
+ return result;
+}
+
+/*******************************************************************************
+**
+** Function AVDT_ConnectReq
+**
+** Description This function initiates an AVDTP signaling connection
+** to the peer device. When the connection is completed, an
+** AVDT_CONNECT_IND_EVT is sent to the application via its
+** control callback function. If the connection attempt fails
+** an AVDT_DISCONNECT_IND_EVT is sent. The security mask
+** parameter overrides the outgoing security mask set in
+** AVDT_Register().
+**
+** Returns AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+UINT16 AVDT_ConnectReq(BD_ADDR bd_addr, UINT8 sec_mask, tAVDT_CTRL_CBACK *p_cback)
+{
+ tAVDT_CCB *p_ccb = NULL;
+ UINT16 result = AVDT_SUCCESS;
+ tAVDT_CCB_EVT evt;
+
+ BTTRC_AVDT_API0(AVDT_TRACE_API_CONNECT_REQ);
+
+ /* find channel control block for this bd addr; if none, allocate one */
+ if ((p_ccb = avdt_ccb_by_bd(bd_addr)) == NULL)
+ {
+ if ((p_ccb = avdt_ccb_alloc(bd_addr)) == NULL)
+ {
+ /* could not allocate channel control block */
+ result = AVDT_NO_RESOURCES;
+ }
+ }
+ else if (p_ccb->ll_opened == FALSE)
+ {
+ AVDT_TRACE_WARNING0("AVDT_ConnectReq: CCB LL is in the middle of opening");
+
+ /* ccb was already allocated for the incoming signalling. */
+ result = AVDT_BUSY;
+ }
+
+ if (result == AVDT_SUCCESS)
+ {
+ /* send event to ccb */
+ evt.connect.p_cback = p_cback;
+ evt.connect.sec_mask = sec_mask;
+ avdt_ccb_event(p_ccb, AVDT_CCB_API_CONNECT_REQ_EVT, &evt);
+ }
+ return result;
+}
+
+/*******************************************************************************
+**
+** Function AVDT_DisconnectReq
+**
+** Description This function disconnect an AVDTP signaling connection
+** to the peer device. When disconnected an
+** AVDT_DISCONNECT_IND_EVT is sent to the application via its
+** control callback function.
+**
+** Returns AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+UINT16 AVDT_DisconnectReq(BD_ADDR bd_addr, tAVDT_CTRL_CBACK *p_cback)
+{
+ tAVDT_CCB *p_ccb = NULL;
+ UINT16 result = AVDT_SUCCESS;
+ tAVDT_CCB_EVT evt;
+
+ BTTRC_AVDT_API0(AVDT_TRACE_API_DISCONNECT_REQ);
+
+
+ /* find channel control block for this bd addr; if none, error */
+ if ((p_ccb = avdt_ccb_by_bd(bd_addr)) == NULL)
+ {
+ result = AVDT_BAD_PARAMS;
+ }
+
+ if (result == AVDT_SUCCESS)
+ {
+ /* send event to ccb */
+ evt.disconnect.p_cback = p_cback;
+ avdt_ccb_event(p_ccb, AVDT_CCB_API_DISCONNECT_REQ_EVT, &evt);
+ }
+ return result;
+}
+
+/*******************************************************************************
+**
+** Function AVDT_GetL2CapChannel
+**
+** Description Get the L2CAP CID used by the handle.
+**
+** Returns CID if successful, otherwise 0.
+**
+*******************************************************************************/
+UINT16 AVDT_GetL2CapChannel(UINT8 handle)
+{
+ tAVDT_SCB *p_scb;
+ tAVDT_CCB *p_ccb;
+ UINT8 tcid;
+ UINT16 lcid = 0;
+
+ /* map handle to scb */
+ if (((p_scb = avdt_scb_by_hdl(handle)) != NULL)
+ && ((p_ccb = p_scb->p_ccb) != NULL))
+ {
+ /* get tcid from type, scb */
+ tcid = avdt_ad_type_to_tcid(AVDT_CHAN_MEDIA, p_scb);
+
+ lcid = avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid;
+ }
+
+ BTTRC_AVDT_API1(AVDT_TRACE_API_GET_L2CAP_CHAN, BTTRC_PARAM_UINT16, lcid);
+
+ return (lcid);
+}
+
+/*******************************************************************************
+**
+** Function AVDT_GetSignalChannel
+**
+** Description Get the L2CAP CID used by the signal channel of the given handle.
+**
+** Returns CID if successful, otherwise 0.
+**
+*******************************************************************************/
+UINT16 AVDT_GetSignalChannel(UINT8 handle, BD_ADDR bd_addr)
+{
+ tAVDT_SCB *p_scb;
+ tAVDT_CCB *p_ccb;
+ UINT8 tcid = 0; /* tcid is always 0 for signal channel */
+ UINT16 lcid = 0;
+
+ /* map handle to scb */
+ if (((p_scb = avdt_scb_by_hdl(handle)) != NULL)
+ && ((p_ccb = p_scb->p_ccb) != NULL))
+ {
+ lcid = avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid;
+ }
+ else if ((p_ccb = avdt_ccb_by_bd(bd_addr)) != NULL)
+ {
+ lcid = avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid;
+ }
+
+ BTTRC_AVDT_API1(AVDT_TRACE_API_GET_SIGNAL_CHAN, BTTRC_PARAM_UINT16, lcid);
+
+ return (lcid);
+}
+
+#if AVDT_MULTIPLEXING == TRUE
+/*******************************************************************************
+**
+** Function AVDT_WriteDataReq
+**
+** Description Send a media packet to the peer device. The stream must
+** be started before this function is called. Also, this
+** function can only be called if the stream is a SRC.
+**
+** When AVDTP has sent the media packet and is ready for the
+** next packet, an AVDT_WRITE_CFM_EVT is sent to the
+** application via the control callback. The application must
+** wait for the AVDT_WRITE_CFM_EVT before it makes the next
+** call to AVDT_WriteDataReq(). If the applications calls
+** AVDT_WriteDataReq() before it receives the event the packet
+** will not be sent. The application may make its first call
+** to AVDT_WriteDataReq() after it receives an
+** AVDT_START_CFM_EVT or AVDT_START_IND_EVT.
+**
+** Returns AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+AVDT_API extern UINT16 AVDT_WriteDataReq(UINT8 handle, UINT8 *p_data, UINT32 data_len,
+ UINT32 time_stamp, UINT8 m_pt, UINT8 marker)
+{
+
+ tAVDT_SCB *p_scb;
+ tAVDT_SCB_EVT evt;
+ UINT16 result = AVDT_SUCCESS;
+
+ BTTRC_AVDT_API1(AVDT_TRACE_API_WRITE_DATA_REQ, BTTRC_PARAM_UINT32, data_len);
+
+ do
+ {
+ /* check length of media frame */
+ if(data_len > AVDT_MAX_MEDIA_SIZE)
+ {
+ result = AVDT_BAD_PARAMS;
+ break;
+ }
+ /* map handle to scb */
+ if ((p_scb = avdt_scb_by_hdl(handle)) == NULL)
+ {
+ result = AVDT_BAD_HANDLE;
+ break;
+ }
+ AVDT_TRACE_WARNING1("mux_tsid_media:%d", p_scb->curr_cfg.mux_tsid_media);
+
+ if (p_scb->p_pkt != NULL
+ || p_scb->p_ccb == NULL
+ || !GKI_queue_is_empty(&p_scb->frag_q)
+ || p_scb->frag_off != 0
+ || p_scb->curr_cfg.mux_tsid_media == 0)
+ {
+ result = AVDT_ERR_BAD_STATE;
+ AVDT_TRACE_WARNING4("p_scb->p_pkt=%x, p_scb->p_ccb=%x, IsQueueEmpty=%x, p_scb->frag_off=%x",
+ p_scb->p_pkt, p_scb->p_ccb, GKI_queue_is_empty(&p_scb->frag_q), p_scb->frag_off);
+ break;
+ }
+ evt.apiwrite.p_buf = 0; /* it will indicate using of fragments queue frag_q */
+ /* create queue of media fragments */
+ GKI_init_q (&evt.apiwrite.frag_q);
+
+ /* compose fragments from media payload and put fragments into gueue */
+ avdt_scb_queue_frags(p_scb, &p_data, &data_len, &evt.apiwrite.frag_q);
+
+ if(GKI_queue_is_empty(&evt.apiwrite.frag_q))
+ {
+ AVDT_TRACE_WARNING0("AVDT_WriteDataReq out of GKI buffers");
+ result = AVDT_ERR_RESOURCE;
+ break;
+ }
+ evt.apiwrite.data_len = data_len;
+ evt.apiwrite.p_data = p_data;
+
+ /* process the fragments queue */
+ evt.apiwrite.time_stamp = time_stamp;
+ evt.apiwrite.m_pt = m_pt | (marker<<7);
+ avdt_scb_event(p_scb, AVDT_SCB_API_WRITE_REQ_EVT, &evt);
+ } while (0);
+
+#if (BT_USE_TRACES == TRUE)
+ if(result != AVDT_SUCCESS)
+ {
+ AVDT_TRACE_WARNING1("*** AVDT_WriteDataReq failed result=%d",result);
+ }
+#endif
+ return result;
+}
+#endif
+
+#if AVDT_MULTIPLEXING == TRUE
+/*******************************************************************************
+**
+** Function AVDT_SetMediaBuf
+**
+** Description Assigns buffer for media packets or forbids using of assigned
+** buffer if argument p_buf is NULL. This function can only
+** be called if the stream is a SNK.
+**
+** AVDTP uses this buffer to reassemble fragmented media packets.
+** When AVDTP receives a complete media packet, it calls the
+** p_media_cback assigned by AVDT_CreateStream().
+** This function can be called during callback to assign a
+** different buffer for next media packet or can leave the current
+** buffer for next packet.
+**
+** Returns AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+AVDT_API extern UINT16 AVDT_SetMediaBuf(UINT8 handle, UINT8 *p_buf, UINT32 buf_len)
+{
+ tAVDT_SCB *p_scb;
+ UINT16 result = AVDT_SUCCESS;
+
+ BTTRC_AVDT_API0(AVDT_TRACE_API_SET_MEDIABUF);
+
+ /* map handle to scb */
+ if ((p_scb = avdt_scb_by_hdl(handle)) == NULL)
+ {
+ result = AVDT_BAD_HANDLE;
+ }
+ else
+ {
+ if(p_buf && p_scb->cs.p_media_cback == NULL)
+ result = AVDT_NO_RESOURCES;
+ else
+ {
+ p_scb->p_media_buf = p_buf;
+ p_scb->media_buf_len = buf_len;
+ }
+ }
+
+ return result;
+}
+#endif
+
+#if AVDT_REPORTING == TRUE
+/*******************************************************************************
+**
+** Function AVDT_SendReport
+**
+** Description
+**
+**
+**
+** Returns
+**
+*******************************************************************************/
+UINT16 AVDT_SendReport(UINT8 handle, AVDT_REPORT_TYPE type,
+ tAVDT_REPORT_DATA *p_data)
+{
+ tAVDT_SCB *p_scb;
+ UINT16 result = AVDT_BAD_PARAMS;
+ BT_HDR *p_pkt;
+ tAVDT_TC_TBL *p_tbl;
+ UINT8 *p, *plen, *pm1, *p_end;
+#if AVDT_MULTIPLEXING == TRUE
+ UINT8 *p_al, u;
+#endif
+ UINT32 ssrc;
+ UINT16 len;
+
+ BTTRC_AVDT_API0(AVDT_TRACE_API_SEND_REPORT);
+
+ /* map handle to scb && verify parameters */
+ if (((p_scb = avdt_scb_by_hdl(handle)) != NULL)
+ && (p_scb->p_ccb != NULL)
+ && (((type == AVDT_RTCP_PT_SR) && (p_scb->cs.tsep == AVDT_TSEP_SRC)) ||
+ ((type == AVDT_RTCP_PT_RR) && (p_scb->cs.tsep == AVDT_TSEP_SNK)) ||
+ (type == AVDT_RTCP_PT_SDES)) )
+ {
+ result = AVDT_NO_RESOURCES;
+
+ /* build SR - assume fit in one packet */
+ p_tbl = avdt_ad_tc_tbl_by_type(AVDT_CHAN_REPORT, p_scb->p_ccb, p_scb);
+ if((p_tbl->state == AVDT_AD_ST_OPEN) &&
+ (p_pkt = (BT_HDR *)GKI_getbuf(p_tbl->peer_mtu)) != NULL)
+ {
+ p_pkt->offset = L2CAP_MIN_OFFSET;
+ p = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+#if AVDT_MULTIPLEXING == TRUE
+ if(p_scb->curr_cfg.psc_mask & AVDT_PSC_MUX)
+ {
+ /* Adaptation Layer header later */
+ p_al = p;
+ p += 2;
+ }
+#endif
+ pm1 = p;
+ *p++ = AVDT_MEDIA_OCTET1 | 1;
+ *p++ = type;
+ /* save the location for length */
+ plen = p;
+ p+= 2;
+ ssrc = avdt_scb_gen_ssrc(p_scb);
+ UINT32_TO_BE_STREAM(p, ssrc);
+
+ switch(type)
+ {
+ case AVDT_RTCP_PT_SR: /* Sender Report */
+ *pm1 = AVDT_MEDIA_OCTET1;
+ UINT32_TO_BE_STREAM(p, p_data->sr.ntp_sec);
+ UINT32_TO_BE_STREAM(p, p_data->sr.ntp_frac);
+ UINT32_TO_BE_STREAM(p, p_data->sr.rtp_time);
+ UINT32_TO_BE_STREAM(p, p_data->sr.pkt_count);
+ UINT32_TO_BE_STREAM(p, p_data->sr.octet_count);
+ break;
+
+ case AVDT_RTCP_PT_RR: /* Receiver Report */
+ *p++ = p_data->rr.frag_lost;
+ AVDT_TRACE_API1("packet_lost: %d", p_data->rr.packet_lost);
+ p_data->rr.packet_lost &= 0xFFFFFF;
+ AVDT_TRACE_API1("packet_lost: %d", p_data->rr.packet_lost);
+ UINT24_TO_BE_STREAM(p, p_data->rr.packet_lost);
+ UINT32_TO_BE_STREAM(p, p_data->rr.seq_num_rcvd);
+ UINT32_TO_BE_STREAM(p, p_data->rr.jitter);
+ UINT32_TO_BE_STREAM(p, p_data->rr.lsr);
+ UINT32_TO_BE_STREAM(p, p_data->rr.dlsr);
+ break;
+
+ case AVDT_RTCP_PT_SDES: /* Source Description */
+ *p++ = AVDT_RTCP_SDES_CNAME;
+ len = strlen((char *)p_data->cname);
+ if(len > AVDT_MAX_CNAME_SIZE)
+ len = AVDT_MAX_CNAME_SIZE;
+ *p++ = (UINT8)len;
+ BCM_STRNCPY_S((char *)p, len+1, (char *)p_data->cname, len+1);
+ p += len;
+ break;
+ }
+ p_end = p;
+ len = p - pm1 - 1;
+ UINT16_TO_BE_STREAM(plen, len);
+
+#if AVDT_MULTIPLEXING == TRUE
+ if(p_scb->curr_cfg.psc_mask & AVDT_PSC_MUX)
+ {
+ /* Adaptation Layer header */
+ p = p_al;
+ len++;
+ UINT16_TO_BE_STREAM(p_al, len );
+ /* TSID, no-fragment bit and coding of length(9-bit length field) */
+ u = *p;
+ *p = (p_scb->curr_cfg.mux_tsid_report<<3) | AVDT_ALH_LCODE_9BITM0;
+ if(u)
+ *p |= AVDT_ALH_LCODE_9BITM1;
+ }
+#endif
+
+ /* set the actual payload length */
+ p_pkt->len = p_end - p;
+ /* send the packet */
+ if(L2CAP_DW_FAILED != avdt_ad_write_req(AVDT_CHAN_REPORT, p_scb->p_ccb, p_scb, p_pkt))
+ result = AVDT_SUCCESS;
+ }
+ }
+
+ return result;
+}
+#endif
+
+/******************************************************************************
+**
+** Function AVDT_SetTraceLevel
+**
+** Description Sets the trace level for AVDT. If 0xff is passed, the
+** current trace level is returned.
+**
+** Input Parameters:
+** new_level: The level to set the AVDT tracing to:
+** 0xff-returns the current setting.
+** 0-turns off tracing.
+** >= 1-Errors.
+** >= 2-Warnings.
+** >= 3-APIs.
+** >= 4-Events.
+** >= 5-Debug.
+**
+** Returns The new trace level or current trace level if
+** the input parameter is 0xff.
+**
+******************************************************************************/
+UINT8 AVDT_SetTraceLevel (UINT8 new_level)
+{
+ if (new_level != 0xFF)
+ avdt_cb.trace_level = new_level;
+
+ return (avdt_cb.trace_level);
+}
+
diff --git a/stack/avdt/avdt_ccb.c b/stack/avdt/avdt_ccb.c
new file mode 100644
index 0000000..ea1990d
--- /dev/null
+++ b/stack/avdt/avdt_ccb.c
@@ -0,0 +1,452 @@
+/*****************************************************************************
+**
+** Name: avdt_ccb.c
+**
+** Description: This module contains the channel control block state
+** machine and functions which operate on the channel
+** control block.
+**
+** Copyright (c) 2002-2008, Broadcom Corp., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include <string.h>
+#include "data_types.h"
+#include "bt_target.h"
+#include "avdt_api.h"
+#include "avdtc_api.h"
+#include "avdt_int.h"
+#include "gki.h"
+#include "btu.h"
+
+/*****************************************************************************
+** state machine constants and types
+*****************************************************************************/
+#if AVDT_DEBUG == TRUE
+
+/* verbose state strings for trace */
+const char * const avdt_ccb_st_str[] = {
+ "CCB_IDLE_ST",
+ "CCB_OPENING_ST",
+ "CCB_OPEN_ST",
+ "CCB_CLOSING_ST"
+};
+
+/* verbose event strings for trace */
+const char * const avdt_ccb_evt_str[] = {
+ "API_DISCOVER_REQ_EVT",
+ "API_GETCAP_REQ_EVT",
+ "API_START_REQ_EVT",
+ "API_SUSPEND_REQ_EVT",
+ "API_DISCOVER_RSP_EVT",
+ "API_GETCAP_RSP_EVT",
+ "API_START_RSP_EVT",
+ "API_SUSPEND_RSP_EVT",
+ "API_CONNECT_REQ_EVT",
+ "API_DISCONNECT_REQ_EVT",
+ "MSG_DISCOVER_CMD_EVT",
+ "MSG_GETCAP_CMD_EVT",
+ "MSG_START_CMD_EVT",
+ "MSG_SUSPEND_CMD_EVT",
+ "MSG_DISCOVER_RSP_EVT",
+ "MSG_GETCAP_RSP_EVT",
+ "MSG_START_RSP_EVT",
+ "MSG_SUSPEND_RSP_EVT",
+ "RCVRSP_EVT",
+ "SENDMSG_EVT",
+ "RET_TOUT_EVT",
+ "RSP_TOUT_EVT",
+ "IDLE_TOUT_EVT",
+ "UL_OPEN_EVT",
+ "UL_CLOSE_EVT",
+ "LL_OPEN_EVT",
+ "LL_CLOSE_EVT",
+ "LL_CONG_EVT"
+};
+
+#endif
+
+
+/* action function list */
+const tAVDT_CCB_ACTION avdt_ccb_action[] = {
+ avdt_ccb_chan_open,
+ avdt_ccb_chan_close,
+ avdt_ccb_chk_close,
+ avdt_ccb_hdl_discover_cmd,
+ avdt_ccb_hdl_discover_rsp,
+ avdt_ccb_hdl_getcap_cmd,
+ avdt_ccb_hdl_getcap_rsp,
+ avdt_ccb_hdl_start_cmd,
+ avdt_ccb_hdl_start_rsp,
+ avdt_ccb_hdl_suspend_cmd,
+ avdt_ccb_hdl_suspend_rsp,
+ avdt_ccb_snd_discover_cmd,
+ avdt_ccb_snd_discover_rsp,
+ avdt_ccb_snd_getcap_cmd,
+ avdt_ccb_snd_getcap_rsp,
+ avdt_ccb_snd_start_cmd,
+ avdt_ccb_snd_start_rsp,
+ avdt_ccb_snd_suspend_cmd,
+ avdt_ccb_snd_suspend_rsp,
+ avdt_ccb_clear_cmds,
+ avdt_ccb_cmd_fail,
+ avdt_ccb_free_cmd,
+ avdt_ccb_cong_state,
+ avdt_ccb_ret_cmd,
+ avdt_ccb_snd_cmd,
+ avdt_ccb_snd_msg,
+ avdt_ccb_set_reconn,
+ avdt_ccb_clr_reconn,
+ avdt_ccb_chk_reconn,
+ avdt_ccb_chk_timer,
+ avdt_ccb_set_conn,
+ avdt_ccb_set_disconn,
+ avdt_ccb_do_disconn,
+ avdt_ccb_ll_closed,
+ avdt_ccb_ll_opened,
+ avdt_ccb_dealloc
+};
+
+/* state table information */
+#define AVDT_CCB_ACTIONS 2 /* number of actions */
+#define AVDT_CCB_NEXT_STATE 2 /* position of next state */
+#define AVDT_CCB_NUM_COLS 3 /* number of columns in state tables */
+
+/* state table for idle state */
+const UINT8 avdt_ccb_st_idle[][AVDT_CCB_NUM_COLS] = {
+/* Event Action 1 Action 2 Next state */
+/* API_DISCOVER_REQ_EVT */ {AVDT_CCB_SND_DISCOVER_CMD, AVDT_CCB_CHAN_OPEN, AVDT_CCB_OPENING_ST},
+/* API_GETCAP_REQ_EVT */ {AVDT_CCB_SND_GETCAP_CMD, AVDT_CCB_CHAN_OPEN, AVDT_CCB_OPENING_ST},
+/* API_START_REQ_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+/* API_SUSPEND_REQ_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+/* API_DISCOVER_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+/* API_GETCAP_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+/* API_START_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+/* API_SUSPEND_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+/* API_CONNECT_REQ_EVT */ {AVDT_CCB_SET_CONN, AVDT_CCB_CHAN_OPEN, AVDT_CCB_OPENING_ST},
+/* API_DISCONNECT_REQ_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+/* MSG_DISCOVER_CMD_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+/* MSG_GETCAP_CMD_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+/* MSG_START_CMD_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+/* MSG_SUSPEND_CMD_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+/* MSG_DISCOVER_RSP_EVT */ {AVDT_CCB_HDL_DISCOVER_RSP, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+/* MSG_GETCAP_RSP_EVT */ {AVDT_CCB_HDL_GETCAP_RSP, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+/* MSG_START_RSP_EVT */ {AVDT_CCB_HDL_START_RSP, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+/* MSG_SUSPEND_RSP_EVT */ {AVDT_CCB_HDL_SUSPEND_RSP, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+/* RCVRSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+/* SENDMSG_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+/* RET_TOUT_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+/* RSP_TOUT_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+/* IDLE_TOUT_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+/* UL_OPEN_EVT */ {AVDT_CCB_CHAN_OPEN, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+/* UL_CLOSE_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+/* LL_OPEN_EVT */ {AVDT_CCB_LL_OPENED, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST},
+/* LL_CLOSE_EVT */ {AVDT_CCB_LL_CLOSED, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+/* LL_CONG_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST}
+};
+
+/* state table for opening state */
+const UINT8 avdt_ccb_st_opening[][AVDT_CCB_NUM_COLS] = {
+/* Event Action 1 Action 2 Next state */
+/* API_DISCOVER_REQ_EVT */ {AVDT_CCB_SND_DISCOVER_CMD, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+/* API_GETCAP_REQ_EVT */ {AVDT_CCB_SND_GETCAP_CMD, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+/* API_START_REQ_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+/* API_SUSPEND_REQ_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+/* API_DISCOVER_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+/* API_GETCAP_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+/* API_START_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+/* API_SUSPEND_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+/* API_CONNECT_REQ_EVT */ {AVDT_CCB_SET_CONN, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+/* API_DISCONNECT_REQ_EVT */ {AVDT_CCB_SET_DISCONN, AVDT_CCB_DO_DISCONN, AVDT_CCB_CLOSING_ST},
+/* MSG_DISCOVER_CMD_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+/* MSG_GETCAP_CMD_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+/* MSG_START_CMD_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+/* MSG_SUSPEND_CMD_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+/* MSG_DISCOVER_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+/* MSG_GETCAP_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+/* MSG_START_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+/* MSG_SUSPEND_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+/* RCVRSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+/* SENDMSG_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+/* RET_TOUT_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+/* RSP_TOUT_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+/* IDLE_TOUT_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+/* UL_OPEN_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+/* UL_CLOSE_EVT */ {AVDT_CCB_CLEAR_CMDS, AVDT_CCB_CHAN_CLOSE, AVDT_CCB_CLOSING_ST},
+/* LL_OPEN_EVT */ {AVDT_CCB_SND_CMD, AVDT_CCB_LL_OPENED, AVDT_CCB_OPEN_ST},
+/* LL_CLOSE_EVT */ {AVDT_CCB_LL_CLOSED, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+/* LL_CONG_EVT */ {AVDT_CCB_CONG_STATE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST}
+};
+
+/* state table for open state */
+const UINT8 avdt_ccb_st_open[][AVDT_CCB_NUM_COLS] = {
+/* Event Action 1 Action 2 Next state */
+/* API_DISCOVER_REQ_EVT */ {AVDT_CCB_SND_DISCOVER_CMD, AVDT_CCB_SND_CMD, AVDT_CCB_OPEN_ST},
+/* API_GETCAP_REQ_EVT */ {AVDT_CCB_SND_GETCAP_CMD, AVDT_CCB_SND_CMD, AVDT_CCB_OPEN_ST},
+/* API_START_REQ_EVT */ {AVDT_CCB_SND_START_CMD, AVDT_CCB_SND_CMD, AVDT_CCB_OPEN_ST},
+/* API_SUSPEND_REQ_EVT */ {AVDT_CCB_SND_SUSPEND_CMD, AVDT_CCB_SND_CMD, AVDT_CCB_OPEN_ST},
+/* API_DISCOVER_RSP_EVT */ {AVDT_CCB_SND_DISCOVER_RSP, AVDT_CCB_SND_CMD, AVDT_CCB_OPEN_ST},
+/* API_GETCAP_RSP_EVT */ {AVDT_CCB_SND_GETCAP_RSP, AVDT_CCB_SND_CMD, AVDT_CCB_OPEN_ST},
+/* API_START_RSP_EVT */ {AVDT_CCB_SND_START_RSP, AVDT_CCB_SND_CMD, AVDT_CCB_OPEN_ST},
+/* API_SUSPEND_RSP_EVT */ {AVDT_CCB_SND_SUSPEND_RSP, AVDT_CCB_SND_CMD, AVDT_CCB_OPEN_ST},
+/* API_CONNECT_REQ_EVT */ {AVDT_CCB_SET_CONN, AVDT_CCB_LL_OPENED, AVDT_CCB_OPEN_ST},
+/* API_DISCONNECT_REQ_EVT */ {AVDT_CCB_SET_DISCONN, AVDT_CCB_DO_DISCONN, AVDT_CCB_CLOSING_ST},
+/* MSG_DISCOVER_CMD_EVT */ {AVDT_CCB_HDL_DISCOVER_CMD, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST},
+/* MSG_GETCAP_CMD_EVT */ {AVDT_CCB_HDL_GETCAP_CMD, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST},
+/* MSG_START_CMD_EVT */ {AVDT_CCB_HDL_START_CMD, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST},
+/* MSG_SUSPEND_CMD_EVT */ {AVDT_CCB_HDL_SUSPEND_CMD, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST},
+/* MSG_DISCOVER_RSP_EVT */ {AVDT_CCB_CHK_CLOSE, AVDT_CCB_HDL_DISCOVER_RSP, AVDT_CCB_OPEN_ST},
+/* MSG_GETCAP_RSP_EVT */ {AVDT_CCB_CHK_CLOSE, AVDT_CCB_HDL_GETCAP_RSP, AVDT_CCB_OPEN_ST},
+/* MSG_START_RSP_EVT */ {AVDT_CCB_HDL_START_RSP, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST},
+/* MSG_SUSPEND_RSP_EVT */ {AVDT_CCB_HDL_SUSPEND_RSP, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST},
+/* RCVRSP_EVT */ {AVDT_CCB_FREE_CMD, AVDT_CCB_SND_CMD, AVDT_CCB_OPEN_ST},
+/* SENDMSG_EVT */ {AVDT_CCB_SND_MSG, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST},
+/* RET_TOUT_EVT */ {AVDT_CCB_RET_CMD, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST},
+/* RSP_TOUT_EVT */ {AVDT_CCB_CMD_FAIL, AVDT_CCB_SND_CMD, AVDT_CCB_OPEN_ST},
+/* IDLE_TOUT_EVT */ {AVDT_CCB_CLEAR_CMDS, AVDT_CCB_CHAN_CLOSE, AVDT_CCB_CLOSING_ST},
+/* UL_OPEN_EVT */ {AVDT_CCB_CHK_TIMER, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST},
+/* UL_CLOSE_EVT */ {AVDT_CCB_CHK_CLOSE, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST},
+/* LL_OPEN_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST},
+/* LL_CLOSE_EVT */ {AVDT_CCB_LL_CLOSED, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+/* LL_CONG_EVT */ {AVDT_CCB_CONG_STATE, AVDT_CCB_SND_MSG, AVDT_CCB_OPEN_ST}
+};
+
+/* state table for closing state */
+const UINT8 avdt_ccb_st_closing[][AVDT_CCB_NUM_COLS] = {
+/* Event Action 1 Action 2 Next state */
+/* API_DISCOVER_REQ_EVT */ {AVDT_CCB_SET_RECONN, AVDT_CCB_SND_DISCOVER_CMD, AVDT_CCB_CLOSING_ST},
+/* API_GETCAP_REQ_EVT */ {AVDT_CCB_SET_RECONN, AVDT_CCB_SND_GETCAP_CMD, AVDT_CCB_CLOSING_ST},
+/* API_START_REQ_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+/* API_SUSPEND_REQ_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+/* API_DISCOVER_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+/* API_GETCAP_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+/* API_START_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+/* API_SUSPEND_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+/* API_CONNECT_REQ_EVT */ {AVDT_CCB_SET_RECONN, AVDT_CCB_SET_CONN, AVDT_CCB_CLOSING_ST},
+/* API_DISCONNECT_REQ_EVT */ {AVDT_CCB_CLR_RECONN, AVDT_CCB_SET_DISCONN, AVDT_CCB_CLOSING_ST},
+/* MSG_DISCOVER_CMD_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+/* MSG_GETCAP_CMD_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+/* MSG_START_CMD_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+/* MSG_SUSPEND_CMD_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+/* MSG_DISCOVER_RSP_EVT */ {AVDT_CCB_HDL_DISCOVER_RSP, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+/* MSG_GETCAP_RSP_EVT */ {AVDT_CCB_HDL_GETCAP_RSP, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+/* MSG_START_RSP_EVT */ {AVDT_CCB_HDL_START_RSP, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+/* MSG_SUSPEND_RSP_EVT */ {AVDT_CCB_HDL_SUSPEND_RSP, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+/* RCVRSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+/* SENDMSG_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+/* RET_TOUT_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+/* RSP_TOUT_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+/* IDLE_TOUT_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+/* UL_OPEN_EVT */ {AVDT_CCB_SET_RECONN, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+/* UL_CLOSE_EVT */ {AVDT_CCB_CLR_RECONN, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+/* LL_OPEN_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+/* LL_CLOSE_EVT */ {AVDT_CCB_CHK_RECONN, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+/* LL_CONG_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST}
+};
+
+/* type for state table */
+typedef const UINT8 (*tAVDT_CCB_ST_TBL)[AVDT_CCB_NUM_COLS];
+
+/* state table */
+const tAVDT_CCB_ST_TBL avdt_ccb_st_tbl[] = {
+ avdt_ccb_st_idle,
+ avdt_ccb_st_opening,
+ avdt_ccb_st_open,
+ avdt_ccb_st_closing
+};
+
+/*******************************************************************************
+**
+** Function avdt_ccb_init
+**
+** Description Initialize channel control block module.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_ccb_init(void)
+{
+ memset(&avdt_cb.ccb[0], 0, sizeof(tAVDT_CCB) * AVDT_NUM_LINKS);
+ avdt_cb.p_ccb_act = (tAVDT_CCB_ACTION *) avdt_ccb_action;
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_event
+**
+** Description State machine event handling function for ccb
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_ccb_event(tAVDT_CCB *p_ccb, UINT8 event, tAVDT_CCB_EVT *p_data)
+{
+ tAVDT_CCB_ST_TBL state_table;
+ UINT8 action;
+ int i;
+
+#if AVDT_DEBUG == TRUE
+ AVDT_TRACE_EVENT3("CCB ccb=%d event=%s state=%s", avdt_ccb_to_idx(p_ccb), avdt_ccb_evt_str[event], avdt_ccb_st_str[p_ccb->state]);
+#endif
+ BTTRC_AVDT_CCB_EVENT(event, p_ccb->state);
+
+ /* look up the state table for the current state */
+ state_table = avdt_ccb_st_tbl[p_ccb->state];
+
+ /* set next state */
+ if (p_ccb->state != state_table[event][AVDT_CCB_NEXT_STATE])
+ BTTRC_AVDT_CCB_STATE(state_table[event][AVDT_CCB_NEXT_STATE]);
+ p_ccb->state = state_table[event][AVDT_CCB_NEXT_STATE];
+
+ /* execute action functions */
+ for (i = 0; i < AVDT_CCB_ACTIONS; i++)
+ {
+ if ((action = state_table[event][i]) != AVDT_CCB_IGNORE)
+ {
+ BTTRC_AVDT_CCB_ACTION(action);
+ (*avdt_cb.p_ccb_act[action])(p_ccb, p_data);
+ }
+ else
+ {
+ break;
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function avdt_ccb_by_bd
+**
+** Description This lookup function finds the ccb for a BD address.
+**
+**
+** Returns pointer to the ccb, or NULL if none found.
+**
+*******************************************************************************/
+tAVDT_CCB *avdt_ccb_by_bd(BD_ADDR bd_addr)
+{
+ tAVDT_CCB *p_ccb = &avdt_cb.ccb[0];
+ int i;
+
+ for (i = 0; i < AVDT_NUM_LINKS; i++, p_ccb++)
+ {
+ /* if allocated ccb has matching ccb */
+ if (p_ccb->allocated && (!memcmp(p_ccb->peer_addr, bd_addr, BD_ADDR_LEN)))
+ {
+ break;
+ }
+ }
+
+ if (i == AVDT_NUM_LINKS)
+ {
+ /* if no ccb found */
+ p_ccb = NULL;
+
+ AVDT_TRACE_DEBUG6("No ccb for addr %02x-%02x-%02x-%02x-%02x-%02x",
+ bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
+ }
+ return p_ccb;
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_alloc
+**
+** Description Allocate a channel control block.
+**
+**
+** Returns pointer to the ccb, or NULL if none could be allocated.
+**
+*******************************************************************************/
+tAVDT_CCB *avdt_ccb_alloc(BD_ADDR bd_addr)
+{
+ tAVDT_CCB *p_ccb = &avdt_cb.ccb[0];
+ int i;
+
+ for (i = 0; i < AVDT_NUM_LINKS; i++, p_ccb++)
+ {
+ if (!p_ccb->allocated)
+ {
+ p_ccb->allocated = TRUE;
+ memcpy(p_ccb->peer_addr, bd_addr, BD_ADDR_LEN);
+ GKI_init_q(&p_ccb->cmd_q);
+ GKI_init_q(&p_ccb->rsp_q);
+ p_ccb->timer_entry.param = (UINT32) p_ccb;
+ AVDT_TRACE_DEBUG1("avdt_ccb_alloc %d", i);
+ break;
+ }
+ }
+
+ if (i == AVDT_NUM_LINKS)
+ {
+ /* out of ccbs */
+ p_ccb = NULL;
+ AVDT_TRACE_WARNING0("Out of ccbs");
+ }
+ return p_ccb;
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_dealloc
+**
+** Description Deallocate a stream control block.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_dealloc(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ AVDT_TRACE_DEBUG1("avdt_ccb_dealloc %d", avdt_ccb_to_idx(p_ccb));
+ btu_stop_timer(&p_ccb->timer_entry);
+ memset(p_ccb, 0, sizeof(tAVDT_CCB));
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_to_idx
+**
+** Description Given a pointer to an ccb, return its index.
+**
+**
+** Returns Index of ccb.
+**
+*******************************************************************************/
+UINT8 avdt_ccb_to_idx(tAVDT_CCB *p_ccb)
+{
+ /* use array arithmetic to determine index */
+ return (UINT8) (p_ccb - avdt_cb.ccb);
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_by_idx
+**
+** Description Return ccb pointer based on ccb index.
+**
+**
+** Returns pointer to the ccb, or NULL if none found.
+**
+*******************************************************************************/
+tAVDT_CCB *avdt_ccb_by_idx(UINT8 idx)
+{
+ tAVDT_CCB *p_ccb;
+
+ /* verify index */
+ if (idx < AVDT_NUM_LINKS)
+ {
+ p_ccb = &avdt_cb.ccb[idx];
+ }
+ else
+ {
+ p_ccb = NULL;
+ AVDT_TRACE_WARNING1("No ccb for idx %d", idx);
+ }
+ return p_ccb;
+}
+
diff --git a/stack/avdt/avdt_ccb_act.c b/stack/avdt/avdt_ccb_act.c
new file mode 100644
index 0000000..87de480
--- /dev/null
+++ b/stack/avdt/avdt_ccb_act.c
@@ -0,0 +1,1095 @@
+/*****************************************************************************
+**
+** Name: avdt_ccb_act.c
+**
+** Description: This module contains the action functions associated
+** with the channel control block state machine.
+**
+** Copyright (c) 2006-2008, Broadcom Corp., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include <string.h>
+#include "data_types.h"
+#include "bt_target.h"
+#include "avdt_api.h"
+#include "avdtc_api.h"
+#include "avdt_int.h"
+#include "gki.h"
+#include "btu.h"
+#include "btm_api.h"
+
+/*******************************************************************************
+**
+** Function avdt_ccb_clear_ccb
+**
+** Description This function clears out certain buffers, queues, and
+** other data elements of a ccb.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+static void avdt_ccb_clear_ccb(tAVDT_CCB *p_ccb)
+{
+ BT_HDR *p_buf;
+
+ /* clear certain ccb variables */
+ p_ccb->cong = FALSE;
+ p_ccb->ret_count = 0;
+
+ /* free message being fragmented */
+ if (p_ccb->p_curr_msg != NULL)
+ {
+ GKI_freebuf(p_ccb->p_curr_msg);
+ p_ccb->p_curr_msg = NULL;
+ }
+
+ /* free message being reassembled */
+ if (p_ccb->p_rx_msg != NULL)
+ {
+ GKI_freebuf(p_ccb->p_rx_msg);
+ p_ccb->p_rx_msg = NULL;
+ }
+
+ /* clear out response queue */
+ while ((p_buf = (BT_HDR *) GKI_dequeue(&p_ccb->rsp_q)) != NULL)
+ {
+ GKI_freebuf(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_chan_open
+**
+** Description This function calls avdt_ad_open_req() to
+** initiate a signaling channel connection.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_chan_open(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ BTM_SetOutService(p_ccb->peer_addr, BTM_SEC_SERVICE_AVDTP, AVDT_CHAN_SIG);
+ avdt_ad_open_req(AVDT_CHAN_SIG, p_ccb, NULL, AVDT_INT);
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_chan_close
+**
+** Description This function calls avdt_ad_close_req() to close a
+** signaling channel connection.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_chan_close(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ /* close the transport channel used by this CCB */
+ avdt_ad_close_req(AVDT_CHAN_SIG, p_ccb, NULL);
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_chk_close
+**
+** Description This function checks for active streams on this CCB.
+** If there are none, it starts an idle timer.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_chk_close(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ int i;
+ tAVDT_SCB *p_scb = &avdt_cb.scb[0];
+
+ /* see if there are any active scbs associated with this ccb */
+ for (i = 0; i < AVDT_NUM_SEPS; i++, p_scb++)
+ {
+ if ((p_scb->allocated) && (p_scb->p_ccb == p_ccb))
+ {
+ break;
+ }
+ }
+
+ /* if no active scbs start idle timer */
+ if (i == AVDT_NUM_SEPS)
+ {
+ btu_start_timer(&p_ccb->timer_entry, BTU_TTYPE_AVDT_CCB_IDLE, avdt_cb.rcb.idle_tout);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_hdl_discover_cmd
+**
+** Description This function is called when a discover command is
+** received from the peer. It gathers up the stream
+** information for all allocated streams and initiates
+** sending of a discover response.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_hdl_discover_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ tAVDT_SEP_INFO sep_info[AVDT_NUM_SEPS];
+ tAVDT_SCB *p_scb = &avdt_cb.scb[0];
+ int i;
+
+ p_data->msg.discover_rsp.p_sep_info = sep_info;
+ p_data->msg.discover_rsp.num_seps = 0;
+
+ /* for all allocated scbs */
+ for (i = 0; i < AVDT_NUM_SEPS; i++, p_scb++)
+ {
+ if (p_scb->allocated)
+ {
+ /* copy sep info */
+ sep_info[i].in_use = p_scb->in_use;
+ sep_info[i].seid = i + 1;
+ sep_info[i].media_type = p_scb->cs.media_type;
+ sep_info[i].tsep = p_scb->cs.tsep;
+
+ p_data->msg.discover_rsp.num_seps++;
+ }
+ }
+
+ /* send response */
+ avdt_ccb_event(p_ccb, AVDT_CCB_API_DISCOVER_RSP_EVT, p_data);
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_hdl_discover_rsp
+**
+** Description This function is called when a discover response or
+** reject is received from the peer. It calls the application
+** callback function with the results.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_hdl_discover_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ /* we're done with procedure */
+ p_ccb->proc_busy = FALSE;
+
+ /* call app callback with results */
+ (*p_ccb->proc_cback)(0, p_ccb->peer_addr, AVDT_DISCOVER_CFM_EVT,
+ (tAVDT_CTRL *)(&p_data->msg.discover_rsp));
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_hdl_getcap_cmd
+**
+** Description This function is called when a get capabilities command
+** is received from the peer. It retrieves the stream
+** configuration for the requested stream and initiates
+** sending of a get capabilities response.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_hdl_getcap_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ tAVDT_SCB *p_scb;
+
+ /* look up scb for seid sent to us */
+ p_scb = avdt_scb_by_hdl(p_data->msg.single.seid);
+
+ p_data->msg.svccap.p_cfg = &p_scb->cs.cfg;
+
+ avdt_ccb_event(p_ccb, AVDT_CCB_API_GETCAP_RSP_EVT, p_data);
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_hdl_getcap_rsp
+**
+** Description This function is called with a get capabilities response
+** or reject is received from the peer. It calls the
+** application callback function with the results.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_hdl_getcap_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ /* we're done with procedure */
+ p_ccb->proc_busy = FALSE;
+
+ /* call app callback with results */
+ (*p_ccb->proc_cback)(0, p_ccb->peer_addr, AVDT_GETCAP_CFM_EVT,
+ (tAVDT_CTRL *)(&p_data->msg.svccap));
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_hdl_start_cmd
+**
+** Description This function is called when a start command is received
+** from the peer. It verifies that all requested streams
+** are in the proper state. If so, it initiates sending of
+** a start response. Otherwise it sends a start reject.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_hdl_start_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ UINT8 seid;
+ UINT8 err_code;
+
+ /* verify all streams in the right state */
+ if ((seid = avdt_scb_verify(p_ccb, AVDT_VERIFY_START, p_data->msg.multi.seid_list,
+ p_data->msg.multi.num_seps, &err_code)) == 0)
+ {
+ /* we're ok, send response */
+ avdt_ccb_event(p_ccb, AVDT_CCB_API_START_RSP_EVT, p_data);
+ }
+ else
+ {
+ /* not ok, send reject */
+ p_data->msg.hdr.err_code = err_code;
+ p_data->msg.hdr.err_param = seid;
+ avdt_msg_send_rej(p_ccb, AVDT_SIG_START, &p_data->msg);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_hdl_start_rsp
+**
+** Description This function is called when a start response or reject
+** is received from the peer. Using the SEIDs stored in the
+** current command message, it sends a start response or start
+** reject event to each SCB associated with the command.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_hdl_start_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ UINT8 event;
+ int i;
+ UINT8 *p;
+ tAVDT_SCB *p_scb;
+
+ /* determine rsp or rej event */
+ event = (p_data->msg.hdr.err_code == 0) ?
+ AVDT_SCB_MSG_START_RSP_EVT : AVDT_SCB_MSG_START_REJ_EVT;
+
+ /* get to where seid's are stashed in current cmd */
+ p = (UINT8 *)(p_ccb->p_curr_cmd + 1);
+
+ /* little trick here; length of current command equals number of streams */
+ for (i = 0; i < p_ccb->p_curr_cmd->len; i++)
+ {
+ if ((p_scb = avdt_scb_by_hdl(p[i])) != NULL)
+ {
+ avdt_scb_event(p_scb, event, (tAVDT_SCB_EVT *) &p_data->msg);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_hdl_suspend_cmd
+**
+** Description This function is called when a suspend command is received
+** from the peer. It verifies that all requested streams are
+** in the proper state. If so, it initiates sending of a
+** suspend response. Otherwise it sends a suspend reject.
+
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_hdl_suspend_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ UINT8 seid;
+ UINT8 err_code;
+
+ /* verify all streams in the right state */
+ if ((seid = avdt_scb_verify(p_ccb, AVDT_VERIFY_SUSPEND, p_data->msg.multi.seid_list,
+ p_data->msg.multi.num_seps, &err_code)) == 0)
+ {
+ /* we're ok, send response */
+ avdt_ccb_event(p_ccb, AVDT_CCB_API_SUSPEND_RSP_EVT, p_data);
+ }
+ else
+ {
+ /* not ok, send reject */
+ p_data->msg.hdr.err_code = err_code;
+ p_data->msg.hdr.err_param = seid;
+ avdt_msg_send_rej(p_ccb, AVDT_SIG_SUSPEND, &p_data->msg);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_hdl_suspend_rsp
+**
+** Description This function is called when a suspend response or reject
+** is received from the peer. Using the SEIDs stored in the
+** current command message, it sends a suspend response or
+** suspend reject event to each SCB associated with the command.
+**
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_hdl_suspend_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ UINT8 event;
+ int i;
+ UINT8 *p;
+ tAVDT_SCB *p_scb;
+
+ /* determine rsp or rej event */
+ event = (p_data->msg.hdr.err_code == 0) ?
+ AVDT_SCB_MSG_SUSPEND_RSP_EVT : AVDT_SCB_MSG_SUSPEND_REJ_EVT;
+
+ /* get to where seid's are stashed in current cmd */
+ p = (UINT8 *)(p_ccb->p_curr_cmd + 1);
+
+ /* little trick here; length of current command equals number of streams */
+ for (i = 0; i < p_ccb->p_curr_cmd->len; i++)
+ {
+ if ((p_scb = avdt_scb_by_hdl(p[i])) != NULL)
+ {
+ avdt_scb_event(p_scb, event, (tAVDT_SCB_EVT *) &p_data->msg);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_snd_discover_cmd
+**
+** Description This function is called to send a discover command to the
+** peer. It copies variables needed for the procedure from
+** the event to the CCB. It marks the CCB as busy and then
+** sends a discover command.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_snd_discover_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ /* store info in ccb struct */
+ p_ccb->p_proc_data = p_data->discover.p_sep_info;
+ p_ccb->proc_cback = p_data->discover.p_cback;
+ p_ccb->proc_param = p_data->discover.num_seps;
+
+ /* we're busy */
+ p_ccb->proc_busy = TRUE;
+
+ /* build and queue discover req */
+ avdt_msg_send_cmd(p_ccb, NULL, AVDT_SIG_DISCOVER, NULL);
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_snd_discover_rsp
+**
+** Description This function is called to send a discover response to
+** the peer. It takes the stream information passed in the
+** event and sends a discover response.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_snd_discover_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ /* send response */
+ avdt_msg_send_rsp(p_ccb, AVDT_SIG_DISCOVER, &p_data->msg);
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_snd_getcap_cmd
+**
+** Description This function is called to send a get capabilities command
+** to the peer. It copies variables needed for the procedure
+** from the event to the CCB. It marks the CCB as busy and
+** then sends a get capabilities command.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_snd_getcap_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ UINT8 sig_id = AVDT_SIG_GETCAP;
+
+ /* store info in ccb struct */
+ p_ccb->p_proc_data = p_data->getcap.p_cfg;
+ p_ccb->proc_cback = p_data->getcap.p_cback;
+
+ /* we're busy */
+ p_ccb->proc_busy = TRUE;
+
+ /* build and queue discover req */
+ if (p_data->msg.hdr.sig_id == AVDT_SIG_GET_ALLCAP)
+ sig_id = AVDT_SIG_GET_ALLCAP;
+
+ avdt_msg_send_cmd(p_ccb, NULL, sig_id, (tAVDT_MSG *) &p_data->getcap.single);
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_snd_getcap_rsp
+**
+** Description This function is called to send a get capabilities response
+** to the peer. It takes the stream information passed in the
+** event and sends a get capabilities response.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_snd_getcap_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ UINT8 sig_id = AVDT_SIG_GETCAP;
+
+ if (p_data->msg.hdr.sig_id == AVDT_SIG_GET_ALLCAP)
+ sig_id = AVDT_SIG_GET_ALLCAP;
+
+ /* send response */
+ avdt_msg_send_rsp(p_ccb, sig_id, &p_data->msg);
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_snd_start_cmd
+**
+** Description This function is called to send a start command to the
+** peer. It verifies that all requested streams are in the
+** proper state. If so, it sends a start command. Otherwise
+** send ourselves back a start reject.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_snd_start_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ int i;
+ tAVDT_SCB *p_scb;
+ tAVDT_MSG avdt_msg;
+ UINT8 seid_list[AVDT_NUM_SEPS];
+
+ /* make copy of our seid list */
+ memcpy(seid_list, p_data->msg.multi.seid_list, p_data->msg.multi.num_seps);
+
+ /* verify all streams in the right state */
+ if ((avdt_msg.hdr.err_param = avdt_scb_verify(p_ccb, AVDT_VERIFY_OPEN, p_data->msg.multi.seid_list,
+ p_data->msg.multi.num_seps, &avdt_msg.hdr.err_code)) == 0)
+ {
+ /* set peer seid list in messsage */
+ avdt_scb_peer_seid_list(&p_data->msg.multi);
+
+ /* send command */
+ avdt_msg_send_cmd(p_ccb, seid_list, AVDT_SIG_START, &p_data->msg);
+ }
+ else
+ {
+ /* failed; send ourselves a reject for each stream */
+ for (i = 0; i < p_data->msg.multi.num_seps; i++)
+ {
+ if ((p_scb = avdt_scb_by_hdl(seid_list[i])) != NULL)
+ {
+ avdt_scb_event(p_scb, AVDT_SCB_MSG_START_REJ_EVT, (tAVDT_SCB_EVT *) &avdt_msg.hdr);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_snd_start_rsp
+**
+** Description This function is called to send a start response to the
+** peer. It takes the stream information passed in the event
+** and sends a start response. Then it sends a start event
+** to the SCB for each stream.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_snd_start_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ tAVDT_SCB *p_scb;
+ int i;
+
+ /* send response message */
+ avdt_msg_send_rsp(p_ccb, AVDT_SIG_START, &p_data->msg);
+
+ /* send start event to each scb */
+ for (i = 0; i < p_data->msg.multi.num_seps; i++)
+ {
+ if ((p_scb = avdt_scb_by_hdl(p_data->msg.multi.seid_list[i])) != NULL)
+ {
+ avdt_scb_event(p_scb, AVDT_SCB_MSG_START_CMD_EVT, NULL);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_snd_suspend_cmd
+**
+** Description This function is called to send a suspend command to the
+** peer. It verifies that all requested streams are in the
+** proper state. If so, it sends a suspend command.
+** Otherwise it calls the callback function for each requested
+** stream and sends a suspend confirmation with failure.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_snd_suspend_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ int i;
+ tAVDT_SCB *p_scb;
+ tAVDT_MSG avdt_msg;
+ UINT8 seid_list[AVDT_NUM_SEPS];
+
+ /* make copy of our seid list */
+ memcpy(seid_list, p_data->msg.multi.seid_list, p_data->msg.multi.num_seps);
+
+ /* verify all streams in the right state */
+ if ((avdt_msg.hdr.err_param = avdt_scb_verify(p_ccb, AVDT_VERIFY_STREAMING, p_data->msg.multi.seid_list,
+ p_data->msg.multi.num_seps, &avdt_msg.hdr.err_code)) == 0)
+ {
+ /* set peer seid list in messsage */
+ avdt_scb_peer_seid_list(&p_data->msg.multi);
+
+ /* send command */
+ avdt_msg_send_cmd(p_ccb, seid_list, AVDT_SIG_SUSPEND, &p_data->msg);
+ }
+ else
+ {
+ /* failed; send ourselves a reject for each stream */
+ for (i = 0; i < p_data->msg.multi.num_seps; i++)
+ {
+ if ((p_scb = avdt_scb_by_hdl(seid_list[i])) != NULL)
+ {
+ avdt_scb_event(p_scb, AVDT_SCB_MSG_SUSPEND_REJ_EVT, (tAVDT_SCB_EVT *) &avdt_msg.hdr);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_snd_suspend_rsp
+**
+** Description This function is called to send a suspend response to the
+** peer. It takes the stream information passed in the event
+** and sends a suspend response. Then it sends a suspend event
+** to the SCB for each stream.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_snd_suspend_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ tAVDT_SCB *p_scb;
+ int i;
+
+ /* send response message */
+ avdt_msg_send_rsp(p_ccb, AVDT_SIG_SUSPEND, &p_data->msg);
+
+ /* send start event to each scb */
+ for (i = 0; i < p_data->msg.multi.num_seps; i++)
+ {
+ if ((p_scb = avdt_scb_by_hdl(p_data->msg.multi.seid_list[i])) != NULL)
+ {
+ avdt_scb_event(p_scb, AVDT_SCB_MSG_SUSPEND_CMD_EVT, NULL);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_clear_cmds
+**
+** Description This function is called when the signaling channel is
+** closed to clean up any pending commands. For each pending
+** command in the command queue, it frees the command and
+** calls the application callback function indicating failure.
+** Certain CCB variables are also initialized.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_clear_cmds(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ int i;
+ tAVDT_SCB *p_scb = &avdt_cb.scb[0];
+ UINT8 err_code = AVDT_ERR_CONNECT;
+
+ /* clear the ccb */
+ avdt_ccb_clear_ccb(p_ccb);
+
+ /* clear out command queue; this is a little tricky here; we need
+ ** to handle the case where there is a command on deck in p_curr_cmd,
+ ** plus we need to clear out the queue
+ */
+ do
+ {
+ /* we know p_curr_cmd = NULL after this */
+ avdt_ccb_cmd_fail(p_ccb, (tAVDT_CCB_EVT *) &err_code);
+
+ /* set up next message */
+ p_ccb->p_curr_cmd = (BT_HDR *) GKI_dequeue(&p_ccb->cmd_q);
+
+ } while (p_ccb->p_curr_cmd != NULL);
+
+ /* send a CC_CLOSE_EVT any active scbs associated with this ccb */
+ for (i = 0; i < AVDT_NUM_SEPS; i++, p_scb++)
+ {
+ if ((p_scb->allocated) && (p_scb->p_ccb == p_ccb))
+ {
+ avdt_scb_event(p_scb, AVDT_SCB_CC_CLOSE_EVT, NULL);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_cmd_fail
+**
+** Description This function is called when there is a response timeout.
+** The currently pending command is freed and we fake a
+** reject message back to ourselves.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_cmd_fail(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ tAVDT_MSG msg;
+ UINT8 evt;
+ tAVDT_SCB *p_scb;
+
+ if (p_ccb->p_curr_cmd != NULL)
+ {
+ /* set up data */
+ msg.hdr.err_code = p_data->err_code;
+ msg.hdr.err_param = 0;
+ msg.hdr.ccb_idx = avdt_ccb_to_idx(p_ccb);
+
+ /* pretend that we received a rej message */
+ evt = avdt_msg_rej_2_evt[p_ccb->p_curr_cmd->event - 1];
+
+ if (evt & AVDT_CCB_MKR)
+ {
+ avdt_ccb_event(p_ccb, (UINT8) (evt & ~AVDT_CCB_MKR), (tAVDT_CCB_EVT *) &msg);
+ }
+ else
+ {
+ /* we get the scb out of the current cmd */
+ p_scb = avdt_scb_by_hdl(*((UINT8 *)(p_ccb->p_curr_cmd + 1)));
+ if (p_scb != NULL)
+ {
+ avdt_scb_event(p_scb, evt, (tAVDT_SCB_EVT *) &msg);
+ }
+ }
+
+ GKI_freebuf(p_ccb->p_curr_cmd);
+ p_ccb->p_curr_cmd = NULL;
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_free_cmd
+**
+** Description This function is called when a response is received for a
+** currently pending command. The command is freed.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_free_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ if (p_ccb->p_curr_cmd != NULL)
+ {
+ GKI_freebuf(p_ccb->p_curr_cmd);
+ p_ccb->p_curr_cmd = NULL;
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_cong_state
+**
+** Description This function is called to set the congestion state for
+** the CCB.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_cong_state(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ p_ccb->cong = p_data->llcong;
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_ret_cmd
+**
+** Description This function is called to retransmit the currently
+** pending command. The retransmission count is incremented.
+** If the count reaches the maximum number of retransmissions,
+** the event is treated as a response timeout.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_ret_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ UINT8 err_code = AVDT_ERR_TIMEOUT;
+ BT_HDR *p_msg;
+
+ p_ccb->ret_count++;
+ if (p_ccb->ret_count == AVDT_RET_MAX)
+ {
+ /* command failed */
+ p_ccb->ret_count = 0;
+ avdt_ccb_cmd_fail(p_ccb, (tAVDT_CCB_EVT *) &err_code);
+
+ /* go to next queued command */
+ avdt_ccb_snd_cmd(p_ccb, p_data);
+ }
+ else
+ {
+ /* if command pending and we're not congested and not sending a fragment */
+ if ((!p_ccb->cong) && (p_ccb->p_curr_msg == NULL) && (p_ccb->p_curr_cmd != NULL))
+ {
+ /* make copy of message in p_curr_cmd and send it */
+ if ((p_msg = (BT_HDR *) GKI_getpoolbuf(AVDT_CMD_POOL_ID)) != NULL)
+ {
+ memcpy(p_msg, p_ccb->p_curr_cmd,
+ (sizeof(BT_HDR) + p_ccb->p_curr_cmd->offset + p_ccb->p_curr_cmd->len));
+ avdt_msg_send(p_ccb, p_msg);
+ }
+ }
+
+ /* restart timer */
+ btu_start_timer(&p_ccb->timer_entry, BTU_TTYPE_AVDT_CCB_RET, avdt_cb.rcb.ret_tout);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_snd_cmd
+**
+** Description This function is called the send the next command,
+** if any, in the command queue.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_snd_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ BT_HDR *p_msg;
+
+ /* do we have commands to send? send next command; make sure we're clear;
+ ** not congested, not sending fragment, not waiting for response
+ */
+ if ((!p_ccb->cong) && (p_ccb->p_curr_msg == NULL) && (p_ccb->p_curr_cmd == NULL))
+ {
+ if ((p_msg = (BT_HDR *) GKI_dequeue(&p_ccb->cmd_q)) != NULL)
+ {
+ /* make a copy of buffer in p_curr_cmd */
+ if ((p_ccb->p_curr_cmd = (BT_HDR *) GKI_getpoolbuf(AVDT_CMD_POOL_ID)) != NULL)
+ {
+ memcpy(p_ccb->p_curr_cmd, p_msg, (sizeof(BT_HDR) + p_msg->offset + p_msg->len));
+
+ avdt_msg_send(p_ccb, p_msg);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_snd_msg
+**
+** Description
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_snd_msg(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ BT_HDR *p_msg;
+
+ /* if not congested */
+ if (!p_ccb->cong)
+ {
+ /* are we sending a fragmented message? continue sending fragment */
+ if (p_ccb->p_curr_msg != NULL)
+ {
+ avdt_msg_send(p_ccb, NULL);
+ }
+ /* do we have responses to send? send them */
+ else if (!GKI_queue_is_empty(&p_ccb->rsp_q))
+ {
+ while ((p_msg = (BT_HDR *) GKI_dequeue(&p_ccb->rsp_q)) != NULL)
+ {
+ if (avdt_msg_send(p_ccb, p_msg) == TRUE)
+ {
+ /* break out if congested */
+ break;
+ }
+ }
+ }
+
+ /* do we have commands to send? send next command */
+ avdt_ccb_snd_cmd(p_ccb, NULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_set_reconn
+**
+** Description This function is called to enable a reconnect attempt when
+** a channel transitions from closing to idle state. It sets
+** the reconn variable to TRUE.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_set_reconn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ p_ccb->reconn = TRUE;
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_clr_reconn
+**
+** Description This function is called to clear the reconn variable.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_clr_reconn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ p_ccb->reconn = FALSE;
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_chk_reconn
+**
+** Description This function is called to check if a reconnect attempt
+** is enabled. If enabled, it sends an AVDT_CCB_UL_OPEN_EVT
+** to the CCB. If disabled, the CCB is deallocated.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_chk_reconn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ UINT8 err_code = AVDT_ERR_CONNECT;
+
+ if (p_ccb->reconn)
+ {
+ p_ccb->reconn = FALSE;
+
+ /* clear out ccb */
+ avdt_ccb_clear_ccb(p_ccb);
+
+ /* clear out current command, if any */
+ avdt_ccb_cmd_fail(p_ccb, (tAVDT_CCB_EVT *) &err_code);
+
+ /* reopen the signaling channel */
+ avdt_ccb_event(p_ccb, AVDT_CCB_UL_OPEN_EVT, NULL);
+ }
+ else
+ {
+ avdt_ccb_ll_closed(p_ccb, NULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_chk_timer
+**
+** Description This function stops the CCB timer if the idle timer is
+** running.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_chk_timer(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ if (p_ccb->timer_entry.event == BTU_TTYPE_AVDT_CCB_IDLE)
+ {
+ btu_stop_timer(&p_ccb->timer_entry);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_set_conn
+**
+** Description Set CCB variables associated with AVDT_ConnectReq().
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_set_conn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ /* save callback */
+ p_ccb->p_conn_cback = p_data->connect.p_cback;
+
+ /* set security level */
+ BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_AVDTP, p_data->connect.sec_mask,
+ AVDT_PSM, BTM_SEC_PROTO_AVDT, AVDT_CHAN_SIG);
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_set_disconn
+**
+** Description Set CCB variables associated with AVDT_DisconnectReq().
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_set_disconn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ /*
+ AVDT_TRACE_EVENT2("avdt_ccb_set_disconn:conn:x%x, api:x%x",
+ p_ccb->p_conn_cback, p_data->disconnect.p_cback);
+ */
+ /* save callback */
+ if (p_data->disconnect.p_cback)
+ p_ccb->p_conn_cback = p_data->disconnect.p_cback;
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_do_disconn
+**
+** Description Do action associated with AVDT_DisconnectReq().
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_do_disconn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ /* clear any pending commands */
+ avdt_ccb_clear_cmds(p_ccb, NULL);
+
+ /* close channel */
+ avdt_ccb_chan_close(p_ccb, NULL);
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_ll_closed
+**
+** Description Clear commands from and deallocate CCB.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_ll_closed(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ tAVDT_CTRL_CBACK *p_cback;
+ BD_ADDR bd_addr;
+ tAVDT_CTRL avdt_ctrl;
+
+ /* clear any pending commands */
+ avdt_ccb_clear_cmds(p_ccb, NULL);
+
+ /* save callback pointer, bd addr */
+ p_cback = p_ccb->p_conn_cback;
+ if (!p_cback)
+ p_cback = avdt_cb.p_conn_cback;
+ memcpy(bd_addr, p_ccb->peer_addr, BD_ADDR_LEN);
+
+ /* dealloc ccb */
+ avdt_ccb_dealloc(p_ccb, NULL);
+
+ /* call callback */
+ if (p_cback)
+ {
+ avdt_ctrl.hdr.err_code = 0;
+ (*p_cback)(0, bd_addr, AVDT_DISCONNECT_IND_EVT, &avdt_ctrl);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_ll_opened
+**
+** Description Call callback on open.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_ll_opened(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ tAVDT_CTRL avdt_ctrl;
+
+ p_ccb->ll_opened = TRUE;
+
+ if (!p_ccb->p_conn_cback)
+ p_ccb->p_conn_cback = avdt_cb.p_conn_cback;
+
+ /* call callback */
+ if (p_ccb->p_conn_cback)
+ {
+ avdt_ctrl.hdr.err_code = 0;
+ avdt_ctrl.hdr.err_param = p_data->msg.hdr.err_param;
+ (*p_ccb->p_conn_cback)(0, p_ccb->peer_addr, AVDT_CONNECT_IND_EVT, &avdt_ctrl);
+ }
+}
diff --git a/stack/avdt/avdt_defs.h b/stack/avdt/avdt_defs.h
new file mode 100644
index 0000000..4f67853
--- /dev/null
+++ b/stack/avdt/avdt_defs.h
@@ -0,0 +1,192 @@
+/*****************************************************************************
+**
+** Name: avdt_defs.h
+**
+** Description: This contains constants definitions and other information
+** from the AVDTP specification. This file is intended for
+** use internal to AVDT only.
+**
+**
+** Copyright (c) 2002-2010, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef AVDT_DEFS_H
+#define AVDT_DEFS_H
+
+/*****************************************************************************
+** constants
+*****************************************************************************/
+
+/* signalling packet type */
+#define AVDT_PKT_TYPE_SINGLE 0 /* single packet */
+#define AVDT_PKT_TYPE_START 1 /* start packet */
+#define AVDT_PKT_TYPE_CONT 2 /* continue packet */
+#define AVDT_PKT_TYPE_END 3 /* end packet */
+
+/* signalling message type */
+#define AVDT_MSG_TYPE_CMD 0 /* command */
+#define AVDT_MSG_TYPE_GRJ 1 /* general reject */
+#define AVDT_MSG_TYPE_RSP 2 /* response accept */
+#define AVDT_MSG_TYPE_REJ 3 /* response reject */
+
+/* signalling messages */
+#define AVDT_SIG_DISCOVER 1 /* discover */
+#define AVDT_SIG_GETCAP 2 /* get capabilities */
+#define AVDT_SIG_SETCONFIG 3 /* set configuration */
+#define AVDT_SIG_GETCONFIG 4 /* get configuration */
+#define AVDT_SIG_RECONFIG 5 /* reconfigure */
+#define AVDT_SIG_OPEN 6 /* open */
+#define AVDT_SIG_START 7 /* start */
+#define AVDT_SIG_CLOSE 8 /* close */
+#define AVDT_SIG_SUSPEND 9 /* suspend */
+#define AVDT_SIG_ABORT 10 /* abort */
+#define AVDT_SIG_SECURITY 11 /* security control */
+#define AVDT_SIG_GET_ALLCAP 12 /* get all capabilities */
+#define AVDT_SIG_DELAY_RPT 13 /* delay report */
+
+/* maximum signal value */
+#define AVDT_SIG_MAX AVDT_SIG_DELAY_RPT
+
+/* used for general reject */
+#define AVDT_SIG_NONE 0
+
+/* some maximum and minimum sizes of signalling messages */
+#define AVDT_DISCOVER_REQ_MIN 1
+#define AVDT_DISCOVER_REQ_MAX 124
+
+/* service category information element field values */
+#define AVDT_CAT_TRANS 1 /* Media Transport */
+#define AVDT_CAT_REPORT 2 /* Reporting */
+#define AVDT_CAT_RECOV 3 /* Recovery */
+#define AVDT_CAT_PROTECT 4 /* Content Protection */
+#define AVDT_CAT_HDRCMP 5 /* Header Compression */
+#define AVDT_CAT_MUX 6 /* Multiplexing */
+#define AVDT_CAT_CODEC 7 /* Media Codec */
+#define AVDT_CAT_DELAY_RPT 8 /* Delay Reporting */
+#define AVDT_CAT_MAX_CUR AVDT_CAT_DELAY_RPT
+
+/* min/max lengths of service category information elements */
+#define AVDT_LEN_TRANS_MIN 0
+#define AVDT_LEN_REPORT_MIN 0
+#define AVDT_LEN_RECOV_MIN 3
+#define AVDT_LEN_PROTECT_MIN 2
+#define AVDT_LEN_HDRCMP_MIN 1
+#define AVDT_LEN_MUX_MIN 3
+#define AVDT_LEN_CODEC_MIN 2
+#define AVDT_LEN_DELAY_RPT_MIN 0
+
+#define AVDT_LEN_TRANS_MAX 0
+#define AVDT_LEN_REPORT_MAX 0
+#define AVDT_LEN_RECOV_MAX 3
+#define AVDT_LEN_PROTECT_MAX 255
+#define AVDT_LEN_HDRCMP_MAX 1
+#define AVDT_LEN_MUX_MAX 7
+#define AVDT_LEN_CODEC_MAX 255
+#define AVDT_LEN_DELAY_RPT_MAX 0
+
+/* minimum possible size of configuration or capabilities data */
+#define AVDT_LEN_CFG_MIN 2
+
+/* minimum and maximum lengths for different message types */
+#define AVDT_LEN_SINGLE 1
+#define AVDT_LEN_SETCONFIG_MIN 2
+#define AVDT_LEN_RECONFIG_MIN 1
+#define AVDT_LEN_MULTI_MIN 1
+#define AVDT_LEN_SECURITY_MIN 1
+#define AVDT_LEN_DELAY_RPT 3
+
+/* header lengths for different packet types */
+#define AVDT_LEN_TYPE_SINGLE 2 /* single packet */
+#define AVDT_LEN_TYPE_START 3 /* start packet */
+#define AVDT_LEN_TYPE_CONT 1 /* continue packet */
+#define AVDT_LEN_TYPE_END 1 /* end packet */
+
+/* length of general reject message */
+#define AVDT_LEN_GEN_REJ 2
+
+/* recovery service capabilities information elements */
+#define AVDT_RECOV_MRWS_MIN 0x01 /* min value for maximum recovery window */
+#define AVDT_RECOV_MRWS_MAX 0x18 /* max value for maximum recovery window */
+#define AVDT_RECOV_MNMP_MIN 0x01 /* min value for maximum number of media packets */
+#define AVDT_RECOV_MNMP_MAX 0x18 /* max value for maximum number of media packets */
+
+/* SEID value range */
+#define AVDT_SEID_MIN 0x01
+#define AVDT_SEID_MAX 0x3E
+
+/* first byte of media packet header */
+#define AVDT_MEDIA_OCTET1 0x80
+
+/* for adaptation layer header */
+#define AVDT_ALH_LCODE_MASK 0x03 /* coding of length field */
+#define AVDT_ALH_LCODE_NONE 0x00 /* No length field present. Take length from l2cap */
+#define AVDT_ALH_LCODE_16BIT 0x01 /* 16bit length field */
+#define AVDT_ALH_LCODE_9BITM0 0x02 /* 9 bit length field, MSB = 0, 8 LSBs in 1 octet following */
+#define AVDT_ALH_LCODE_9BITM1 0x03 /* 9 bit length field, MSB = 1, 8 LSBs in 1 octet following */
+
+#define AVDT_ALH_FRAG_MASK 0x04 /* set this for continuation packet */
+
+/*****************************************************************************
+** message parsing and building macros
+*****************************************************************************/
+
+#define AVDT_MSG_PRS_HDR(p, lbl, pkt, msg) \
+ lbl = *(p) >> 4; \
+ pkt = (*(p) >> 2) & 0x03; \
+ msg = *(p)++ & 0x03;
+
+#define AVDT_MSG_PRS_DISC(p, seid, in_use, type, tsep) \
+ seid = *(p) >> 2; \
+ in_use = (*(p)++ >> 1) & 0x01; \
+ type = *(p) >> 4; \
+ tsep = (*(p)++ >> 3) & 0x01;
+
+#define AVDT_MSG_PRS_SIG(p, sig) \
+ sig = *(p)++ & 0x3F;
+
+#define AVDT_MSG_PRS_SEID(p, seid) \
+ seid = *(p)++ >> 2;
+
+#define AVDT_MSG_PRS_PKT_TYPE(p, pkt) \
+ pkt = (*(p) >> 2) & 0x03;
+
+#define AVDT_MSG_PRS_OCTET1(p, o_v, o_p, o_x, o_cc) \
+ o_v = *(p) >> 6; \
+ o_p = (*(p) >> 5) & 0x01; \
+ o_x = (*(p) >> 4) & 0x01; \
+ o_cc = *(p)++ & 0x0F;
+
+#define AVDT_MSG_PRS_RPT_OCTET1(p, o_v, o_p, o_cc) \
+ o_v = *(p) >> 6; \
+ o_p = (*(p) >> 5) & 0x01; \
+ o_cc = *(p)++ & 0x1F;
+
+#define AVDT_MSG_PRS_M_PT(p, m_pt, marker) \
+ marker = *(p) >> 7; \
+ m_pt = *(p)++ & 0x7F;
+
+#define AVDT_MSG_BLD_HDR(p, lbl, pkt, msg) \
+ *(p)++ = (UINT8) ((lbl) << 4) | ((pkt) << 2) | (msg);
+
+#define AVDT_MSG_BLD_DISC(p, seid, in_use, type, tsep) \
+ *(p)++ = (UINT8) (((seid) << 2) | ((in_use) << 1)); \
+ *(p)++ = (UINT8) (((type) << 4) | ((tsep) << 3));
+
+#define AVDT_MSG_BLD_SIG(p, sig) \
+ *(p)++ = (UINT8) (sig);
+
+#define AVDT_MSG_BLD_SEID(p, seid) \
+ *(p)++ = (UINT8) ((seid) << 2);
+
+#define AVDT_MSG_BLD_ERR(p, err) \
+ *(p)++ = (UINT8) (err);
+
+#define AVDT_MSG_BLD_PARAM(p, param) \
+ *(p)++ = (UINT8) (param);
+
+#define AVDT_MSG_BLD_NOSP(p, nosp) \
+ *(p)++ = (UINT8) (nosp);
+
+#endif /* AVDT_DEFS_H */
+
diff --git a/stack/avdt/avdt_int.h b/stack/avdt/avdt_int.h
new file mode 100644
index 0000000..837e943
--- /dev/null
+++ b/stack/avdt/avdt_int.h
@@ -0,0 +1,733 @@
+/*****************************************************************************
+**
+** Name: avdt_int.h
+**
+** Description: This file contains interfaces which are internal to AVDTP.
+**
+**
+** Copyright (c) 2002-2009, Broadcom Corp., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef AVDT_INT_H
+#define AVDT_INT_H
+
+#include "gki.h"
+#include "avdt_api.h"
+#include "avdtc_api.h"
+#include "avdt_defs.h"
+#include "l2c_api.h"
+#include "btm_api.h"
+
+#ifndef AVDT_DEBUG
+#if (!defined BTTRC_INCLUDED || BTTRC_INCLUDED == FALSE)
+#define AVDT_DEBUG TRUE
+#else
+#define AVDT_DEBUG FALSE
+#endif
+#endif
+
+
+/*****************************************************************************
+** constants
+*****************************************************************************/
+
+/* channel types */
+enum {
+ AVDT_CHAN_SIG, /* signaling channel */
+ AVDT_CHAN_MEDIA, /* media channel */
+#if AVDT_REPORTING == TRUE
+ AVDT_CHAN_REPORT, /* reporting channel */
+#endif
+ AVDT_CHAN_NUM_TYPES
+};
+
+/* protocol service capabilities of this AVDTP implementation */
+/* for now multiplexing will be used only for fragmentation */
+#if ((AVDT_MULTIPLEXING == TRUE) && (AVDT_REPORTING == TRUE))
+#define AVDT_PSC (AVDT_PSC_TRANS | AVDT_PSC_MUX | AVDT_PSC_REPORT | AVDT_PSC_DELAY_RPT)
+#define AVDT_LEG_PSC (AVDT_PSC_TRANS | AVDT_PSC_MUX | AVDT_PSC_REPORT)
+#else /* AVDT_MULTIPLEXING && AVDT_REPORTING */
+
+#if (AVDT_MULTIPLEXING == TRUE)
+#define AVDT_PSC (AVDT_PSC_TRANS | AVDT_PSC_MUX | AVDT_PSC_DELAY_RPT)
+#define AVDT_LEG_PSC (AVDT_PSC_TRANS | AVDT_PSC_MUX)
+#else /* AVDT_MULTIPLEXING */
+
+#if (AVDT_REPORTING == TRUE)
+#define AVDT_PSC (AVDT_PSC_TRANS | AVDT_PSC_REPORT | AVDT_PSC_DELAY_RPT)
+#define AVDT_LEG_PSC (AVDT_PSC_TRANS | AVDT_PSC_REPORT)
+#else /* AVDT_REPORTING */
+#define AVDT_PSC (AVDT_PSC_TRANS | AVDT_PSC_DELAY_RPT)
+#define AVDT_LEG_PSC (AVDT_PSC_TRANS)
+#endif /* AVDT_REPORTING */
+
+#endif /* AVDT_MULTIPLEXING */
+
+#endif /* AVDT_MULTIPLEXING && AVDT_REPORTING */
+
+/* initiator/acceptor signaling roles */
+#define AVDT_CLOSE_ACP 0
+#define AVDT_CLOSE_INT 1
+#define AVDT_OPEN_ACP 2
+#define AVDT_OPEN_INT 3
+
+/* states for avdt_scb_verify */
+#define AVDT_VERIFY_OPEN 0
+#define AVDT_VERIFY_STREAMING 1
+#define AVDT_VERIFY_SUSPEND 2
+#define AVDT_VERIFY_START 3
+
+/* to distinguish CCB events from SCB events */
+#define AVDT_CCB_MKR 0x80
+
+/* offset where AVDTP signaling message header starts in message */
+#define AVDT_HDR_OFFSET (L2CAP_MIN_OFFSET + AVDT_NUM_SEPS)
+
+/* offset where AVDTP signaling message content starts;
+** use the size of a start header since it's the largest possible
+** layout of signaling message in a buffer is:
+**
+** | BT_HDR | SCB handles | L2CAP + HCI header | AVDTP header | data ... |
+**
+** Note that we "hide" the scb handles at the top of the message buffer.
+*/
+#define AVDT_MSG_OFFSET (L2CAP_MIN_OFFSET + AVDT_NUM_SEPS + AVDT_LEN_TYPE_START)
+
+/* scb transport channel connect timeout value */
+#define AVDT_SCB_TC_CONN_TOUT 10
+
+/* scb transport channel disconnect timeout value */
+#define AVDT_SCB_TC_DISC_TOUT 10
+
+/* maximum number of command retransmissions */
+#ifndef AVDT_RET_MAX
+#define AVDT_RET_MAX 1
+#endif
+
+
+/* ccb state machine states */
+enum {
+ AVDT_CCB_IDLE_ST,
+ AVDT_CCB_OPENING_ST,
+ AVDT_CCB_OPEN_ST,
+ AVDT_CCB_CLOSING_ST
+};
+
+/* state machine action enumeration list */
+enum {
+ AVDT_CCB_CHAN_OPEN,
+ AVDT_CCB_CHAN_CLOSE,
+ AVDT_CCB_CHK_CLOSE,
+ AVDT_CCB_HDL_DISCOVER_CMD,
+ AVDT_CCB_HDL_DISCOVER_RSP,
+ AVDT_CCB_HDL_GETCAP_CMD,
+ AVDT_CCB_HDL_GETCAP_RSP,
+ AVDT_CCB_HDL_START_CMD,
+ AVDT_CCB_HDL_START_RSP,
+ AVDT_CCB_HDL_SUSPEND_CMD,
+ AVDT_CCB_HDL_SUSPEND_RSP,
+ AVDT_CCB_SND_DISCOVER_CMD,
+ AVDT_CCB_SND_DISCOVER_RSP,
+ AVDT_CCB_SND_GETCAP_CMD,
+ AVDT_CCB_SND_GETCAP_RSP,
+ AVDT_CCB_SND_START_CMD,
+ AVDT_CCB_SND_START_RSP,
+ AVDT_CCB_SND_SUSPEND_CMD,
+ AVDT_CCB_SND_SUSPEND_RSP,
+ AVDT_CCB_CLEAR_CMDS,
+ AVDT_CCB_CMD_FAIL,
+ AVDT_CCB_FREE_CMD,
+ AVDT_CCB_CONG_STATE,
+ AVDT_CCB_RET_CMD,
+ AVDT_CCB_SND_CMD,
+ AVDT_CCB_SND_MSG,
+ AVDT_CCB_SET_RECONN,
+ AVDT_CCB_CLR_RECONN,
+ AVDT_CCB_CHK_RECONN,
+ AVDT_CCB_CHK_TIMER,
+ AVDT_CCB_SET_CONN,
+ AVDT_CCB_SET_DISCONN,
+ AVDT_CCB_DO_DISCONN,
+ AVDT_CCB_LL_CLOSED,
+ AVDT_CCB_LL_OPENED,
+ AVDT_CCB_DEALLOC,
+ AVDT_CCB_NUM_ACTIONS
+};
+
+#define AVDT_CCB_IGNORE AVDT_CCB_NUM_ACTIONS
+
+/* ccb state machine events */
+enum {
+ AVDT_CCB_API_DISCOVER_REQ_EVT,
+ AVDT_CCB_API_GETCAP_REQ_EVT,
+ AVDT_CCB_API_START_REQ_EVT,
+ AVDT_CCB_API_SUSPEND_REQ_EVT,
+ AVDT_CCB_API_DISCOVER_RSP_EVT,
+ AVDT_CCB_API_GETCAP_RSP_EVT,
+ AVDT_CCB_API_START_RSP_EVT,
+ AVDT_CCB_API_SUSPEND_RSP_EVT,
+ AVDT_CCB_API_CONNECT_REQ_EVT,
+ AVDT_CCB_API_DISCONNECT_REQ_EVT,
+ AVDT_CCB_MSG_DISCOVER_CMD_EVT,
+ AVDT_CCB_MSG_GETCAP_CMD_EVT,
+ AVDT_CCB_MSG_START_CMD_EVT,
+ AVDT_CCB_MSG_SUSPEND_CMD_EVT,
+ AVDT_CCB_MSG_DISCOVER_RSP_EVT,
+ AVDT_CCB_MSG_GETCAP_RSP_EVT,
+ AVDT_CCB_MSG_START_RSP_EVT,
+ AVDT_CCB_MSG_SUSPEND_RSP_EVT,
+ AVDT_CCB_RCVRSP_EVT,
+ AVDT_CCB_SENDMSG_EVT,
+ AVDT_CCB_RET_TOUT_EVT,
+ AVDT_CCB_RSP_TOUT_EVT,
+ AVDT_CCB_IDLE_TOUT_EVT,
+ AVDT_CCB_UL_OPEN_EVT,
+ AVDT_CCB_UL_CLOSE_EVT,
+ AVDT_CCB_LL_OPEN_EVT,
+ AVDT_CCB_LL_CLOSE_EVT,
+ AVDT_CCB_LL_CONG_EVT
+};
+
+
+/* scb state machine states; these state values are private to this module so
+** the scb state cannot be read or set by actions functions
+*/
+enum {
+ AVDT_SCB_IDLE_ST,
+ AVDT_SCB_CONF_ST,
+ AVDT_SCB_OPENING_ST,
+ AVDT_SCB_OPEN_ST,
+ AVDT_SCB_STREAM_ST,
+ AVDT_SCB_CLOSING_ST
+};
+
+/* state machine action enumeration list */
+enum {
+ AVDT_SCB_HDL_ABORT_CMD,
+ AVDT_SCB_HDL_ABORT_RSP,
+ AVDT_SCB_HDL_CLOSE_CMD,
+ AVDT_SCB_HDL_CLOSE_RSP,
+ AVDT_SCB_HDL_GETCONFIG_CMD,
+ AVDT_SCB_HDL_GETCONFIG_RSP,
+ AVDT_SCB_HDL_OPEN_CMD,
+ AVDT_SCB_HDL_OPEN_REJ,
+ AVDT_SCB_HDL_OPEN_RSP,
+ AVDT_SCB_HDL_PKT,
+ AVDT_SCB_DROP_PKT,
+ AVDT_SCB_HDL_RECONFIG_CMD,
+ AVDT_SCB_HDL_RECONFIG_RSP,
+ AVDT_SCB_HDL_SECURITY_CMD,
+ AVDT_SCB_HDL_SECURITY_RSP,
+ AVDT_SCB_HDL_SETCONFIG_CMD,
+ AVDT_SCB_HDL_SETCONFIG_REJ,
+ AVDT_SCB_HDL_SETCONFIG_RSP,
+ AVDT_SCB_HDL_START_CMD,
+ AVDT_SCB_HDL_START_RSP,
+ AVDT_SCB_HDL_SUSPEND_CMD,
+ AVDT_SCB_HDL_SUSPEND_RSP,
+ AVDT_SCB_HDL_TC_CLOSE,
+#if AVDT_REPORTING == TRUE
+ AVDT_SCB_HDL_TC_CLOSE_STO,
+#endif
+ AVDT_SCB_HDL_TC_OPEN,
+#if AVDT_REPORTING == TRUE
+ AVDT_SCB_HDL_TC_OPEN_STO,
+#endif
+ AVDT_SCB_SND_DELAY_RPT_REQ,
+ AVDT_SCB_HDL_DELAY_RPT_CMD,
+ AVDT_SCB_HDL_DELAY_RPT_RSP,
+ AVDT_SCB_HDL_WRITE_REQ,
+ AVDT_SCB_SND_ABORT_REQ,
+ AVDT_SCB_SND_ABORT_RSP,
+ AVDT_SCB_SND_CLOSE_REQ,
+ AVDT_SCB_SND_STREAM_CLOSE,
+ AVDT_SCB_SND_CLOSE_RSP,
+ AVDT_SCB_SND_GETCONFIG_REQ,
+ AVDT_SCB_SND_GETCONFIG_RSP,
+ AVDT_SCB_SND_OPEN_REQ,
+ AVDT_SCB_SND_OPEN_RSP,
+ AVDT_SCB_SND_RECONFIG_REQ,
+ AVDT_SCB_SND_RECONFIG_RSP,
+ AVDT_SCB_SND_SECURITY_REQ,
+ AVDT_SCB_SND_SECURITY_RSP,
+ AVDT_SCB_SND_SETCONFIG_REQ,
+ AVDT_SCB_SND_SETCONFIG_REJ,
+ AVDT_SCB_SND_SETCONFIG_RSP,
+ AVDT_SCB_SND_TC_CLOSE,
+ AVDT_SCB_CB_ERR,
+ AVDT_SCB_CONG_STATE,
+ AVDT_SCB_REJ_STATE,
+ AVDT_SCB_REJ_IN_USE,
+ AVDT_SCB_REJ_NOT_IN_USE,
+ AVDT_SCB_SET_REMOVE,
+ AVDT_SCB_FREE_PKT,
+ AVDT_SCB_CLR_PKT,
+ AVDT_SCB_CHK_SND_PKT,
+ AVDT_SCB_TC_TIMER,
+ AVDT_SCB_CLR_VARS,
+ AVDT_SCB_DEALLOC,
+ AVDT_SCB_NUM_ACTIONS
+};
+
+#define AVDT_SCB_IGNORE AVDT_SCB_NUM_ACTIONS
+
+/* scb state machine events */
+enum {
+ AVDT_SCB_API_REMOVE_EVT,
+ AVDT_SCB_API_WRITE_REQ_EVT,
+ AVDT_SCB_API_GETCONFIG_REQ_EVT,
+ AVDT_SCB_API_DELAY_RPT_REQ_EVT,
+ AVDT_SCB_API_SETCONFIG_REQ_EVT,
+ AVDT_SCB_API_OPEN_REQ_EVT,
+ AVDT_SCB_API_CLOSE_REQ_EVT,
+ AVDT_SCB_API_RECONFIG_REQ_EVT,
+ AVDT_SCB_API_SECURITY_REQ_EVT,
+ AVDT_SCB_API_ABORT_REQ_EVT,
+ AVDT_SCB_API_GETCONFIG_RSP_EVT,
+ AVDT_SCB_API_SETCONFIG_RSP_EVT,
+ AVDT_SCB_API_SETCONFIG_REJ_EVT,
+ AVDT_SCB_API_OPEN_RSP_EVT,
+ AVDT_SCB_API_CLOSE_RSP_EVT,
+ AVDT_SCB_API_RECONFIG_RSP_EVT,
+ AVDT_SCB_API_SECURITY_RSP_EVT,
+ AVDT_SCB_API_ABORT_RSP_EVT,
+ AVDT_SCB_MSG_SETCONFIG_CMD_EVT,
+ AVDT_SCB_MSG_GETCONFIG_CMD_EVT,
+ AVDT_SCB_MSG_OPEN_CMD_EVT,
+ AVDT_SCB_MSG_START_CMD_EVT,
+ AVDT_SCB_MSG_SUSPEND_CMD_EVT,
+ AVDT_SCB_MSG_CLOSE_CMD_EVT,
+ AVDT_SCB_MSG_ABORT_CMD_EVT,
+ AVDT_SCB_MSG_RECONFIG_CMD_EVT,
+ AVDT_SCB_MSG_SECURITY_CMD_EVT,
+ AVDT_SCB_MSG_DELAY_RPT_CMD_EVT,
+ AVDT_SCB_MSG_DELAY_RPT_RSP_EVT,
+ AVDT_SCB_MSG_SETCONFIG_RSP_EVT,
+ AVDT_SCB_MSG_GETCONFIG_RSP_EVT,
+ AVDT_SCB_MSG_OPEN_RSP_EVT,
+ AVDT_SCB_MSG_START_RSP_EVT,
+ AVDT_SCB_MSG_SUSPEND_RSP_EVT,
+ AVDT_SCB_MSG_CLOSE_RSP_EVT,
+ AVDT_SCB_MSG_ABORT_RSP_EVT,
+ AVDT_SCB_MSG_RECONFIG_RSP_EVT,
+ AVDT_SCB_MSG_SECURITY_RSP_EVT,
+ AVDT_SCB_MSG_SETCONFIG_REJ_EVT,
+ AVDT_SCB_MSG_OPEN_REJ_EVT,
+ AVDT_SCB_MSG_START_REJ_EVT,
+ AVDT_SCB_MSG_SUSPEND_REJ_EVT,
+ AVDT_SCB_TC_TOUT_EVT,
+ AVDT_SCB_TC_OPEN_EVT,
+ AVDT_SCB_TC_CLOSE_EVT,
+ AVDT_SCB_TC_CONG_EVT,
+ AVDT_SCB_TC_DATA_EVT,
+ AVDT_SCB_CC_CLOSE_EVT
+};
+
+/* adaption layer number of stream routing table entries */
+#if AVDT_REPORTING == TRUE
+/* 2 channels(1 media, 1 report) for each SEP and one for signalling */
+#define AVDT_NUM_RT_TBL ((AVDT_NUM_SEPS<<1) + 1)
+#else
+#define AVDT_NUM_RT_TBL (AVDT_NUM_SEPS + 1)
+#endif
+
+/* adaption layer number of transport channel table entries - moved to target.h
+#define AVDT_NUM_TC_TBL (AVDT_NUM_SEPS + AVDT_NUM_LINKS) */
+
+/* "states" used in transport channel table */
+#define AVDT_AD_ST_UNUSED 0 /* Unused - unallocated */
+#define AVDT_AD_ST_IDLE 1 /* No connection */
+#define AVDT_AD_ST_ACP 2 /* Waiting to accept a connection */
+#define AVDT_AD_ST_INT 3 /* Initiating a connection */
+#define AVDT_AD_ST_CONN 4 /* Waiting for connection confirm */
+#define AVDT_AD_ST_CFG 5 /* Waiting for configuration complete */
+#define AVDT_AD_ST_OPEN 6 /* Channel opened */
+#define AVDT_AD_ST_SEC_INT 7 /* Security process as INT */
+#define AVDT_AD_ST_SEC_ACP 8 /* Security process as ACP */
+
+/* Configuration flags. tAVDT_TC_TBL.cfg_flags */
+#define AVDT_L2C_CFG_IND_DONE (1<<0)
+#define AVDT_L2C_CFG_CFM_DONE (1<<1)
+#define AVDT_L2C_CFG_CONN_INT (1<<2)
+#define AVDT_L2C_CFG_CONN_ACP (1<<3)
+
+
+/* result code for avdt_ad_write_req() (L2CA_DataWrite()) */
+#define AVDT_AD_FAILED L2CAP_DW_FAILED /* FALSE */
+#define AVDT_AD_SUCCESS L2CAP_DW_SUCCESS /* TRUE */
+#define AVDT_AD_CONGESTED L2CAP_DW_CONGESTED /* 2 */
+
+/*****************************************************************************
+** data types
+*****************************************************************************/
+
+/* msg union of all message parameter types */
+typedef union {
+ tAVDT_EVT_HDR hdr;
+ tAVDT_EVT_HDR single;
+ tAVDT_SETCONFIG config_cmd;
+ tAVDT_CONFIG reconfig_cmd;
+ tAVDT_MULTI multi;
+ tAVDT_SECURITY security_cmd;
+ tAVDT_DISCOVER discover_rsp;
+ tAVDT_CONFIG svccap;
+ tAVDT_SECURITY security_rsp;
+ tAVDT_DELAY_RPT delay_rpt_cmd;
+} tAVDT_MSG;
+
+/* data type for AVDT_CCB_API_DISCOVER_REQ_EVT */
+typedef struct {
+ tAVDT_CTRL_CBACK *p_cback;
+ tAVDT_SEP_INFO *p_sep_info;
+ UINT8 num_seps;
+} tAVDT_CCB_API_DISCOVER;
+
+/* data type for AVDT_CCB_API_GETCAP_REQ_EVT */
+typedef struct {
+ tAVDT_EVT_HDR single;
+ tAVDT_CTRL_CBACK *p_cback;
+ tAVDT_CFG *p_cfg;
+} tAVDT_CCB_API_GETCAP;
+
+/* data type for AVDT_CCB_API_CONNECT_REQ_EVT */
+typedef struct {
+ tAVDT_CTRL_CBACK *p_cback;
+ UINT8 sec_mask;
+} tAVDT_CCB_API_CONNECT;
+
+/* data type for AVDT_CCB_API_DISCONNECT_REQ_EVT */
+typedef struct {
+ tAVDT_CTRL_CBACK *p_cback;
+} tAVDT_CCB_API_DISCONNECT;
+
+/* union associated with ccb state machine events */
+typedef union {
+ tAVDT_CCB_API_DISCOVER discover;
+ tAVDT_CCB_API_GETCAP getcap;
+ tAVDT_CCB_API_CONNECT connect;
+ tAVDT_CCB_API_DISCONNECT disconnect;
+ tAVDT_MSG msg;
+ BOOLEAN llcong;
+ UINT8 err_code;
+} tAVDT_CCB_EVT;
+
+/* channel control block type */
+typedef struct {
+ BD_ADDR peer_addr; /* BD address of peer */
+ TIMER_LIST_ENT timer_entry; /* CCB timer list entry */
+ BUFFER_Q cmd_q; /* Queue for outgoing command messages */
+ BUFFER_Q rsp_q; /* Queue for outgoing response and reject messages */
+ tAVDT_CTRL_CBACK *proc_cback; /* Procedure callback function */
+ tAVDT_CTRL_CBACK *p_conn_cback; /* Connection/disconnection callback function */
+ void *p_proc_data; /* Pointer to data storage for procedure */
+ BT_HDR *p_curr_cmd; /* Current command being sent awaiting response */
+ BT_HDR *p_curr_msg; /* Current message being sent */
+ BT_HDR *p_rx_msg; /* Current message being received */
+ BOOLEAN allocated; /* Whether ccb is allocated */
+ UINT8 state; /* The CCB state machine state */
+ BOOLEAN ll_opened; /* TRUE if LL is opened */
+ BOOLEAN proc_busy; /* TRUE when a discover or get capabilities procedure in progress */
+ UINT8 proc_param; /* Procedure parameter; either SEID for get capabilities or number of SEPS for discover */
+ BOOLEAN cong; /* Whether signaling channel is congested */
+ UINT8 label; /* Message header "label" (sequence number) */
+ BOOLEAN reconn; /* If TRUE, reinitiate connection after transitioning from CLOSING to IDLE state */
+ UINT8 ret_count; /* Command retransmission count */
+} tAVDT_CCB;
+
+/* type for action functions */
+typedef void (*tAVDT_CCB_ACTION)(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+
+/* type for AVDT_SCB_API_WRITE_REQ_EVT */
+typedef struct {
+ BT_HDR *p_buf;
+ UINT32 time_stamp;
+#if AVDT_MULTIPLEXING == TRUE
+ BUFFER_Q frag_q; /* Queue for outgoing media fragments. p_buf should be 0 */
+ UINT8 *p_data;
+ UINT32 data_len;
+#endif
+ UINT8 m_pt;
+} tAVDT_SCB_APIWRITE;
+
+/* type for AVDT_SCB_TC_CLOSE_EVT */
+typedef struct {
+ UINT8 old_tc_state; /* channel state before closed */
+ UINT8 tcid; /* TCID */
+ UINT8 type; /* channel type */
+} tAVDT_SCB_TC_CLOSE;
+
+/* type for scb event data */
+typedef union {
+ tAVDT_MSG msg;
+ tAVDT_SCB_APIWRITE apiwrite;
+ tAVDT_DELAY_RPT apidelay;
+ tAVDT_OPEN open;
+ tAVDT_SCB_TC_CLOSE close;
+ BOOLEAN llcong;
+ BT_HDR *p_pkt;
+} tAVDT_SCB_EVT;
+
+/* stream control block type */
+typedef struct {
+ tAVDT_CS cs; /* stream creation struct */
+ tAVDT_CFG curr_cfg; /* current configuration */
+ tAVDT_CFG req_cfg; /* requested configuration */
+ TIMER_LIST_ENT timer_entry; /* timer entry */
+ BT_HDR *p_pkt; /* packet waiting to be sent */
+ tAVDT_CCB *p_ccb; /* ccb associated with this scb */
+ UINT16 media_seq; /* media packet sequence number */
+ BOOLEAN allocated; /* whether scb is allocated or unused */
+ BOOLEAN in_use; /* whether stream being used by peer */
+ UINT8 role; /* initiator/acceptor role in current procedure */
+ BOOLEAN remove; /* whether CB is marked for removal */
+ UINT8 state; /* state machine state */
+ UINT8 peer_seid; /* SEID of peer stream */
+ UINT8 curr_evt; /* current event; set only by state machine */
+ BOOLEAN cong; /* Whether media transport channel is congested */
+ UINT8 close_code; /* Error code received in close response */
+#if AVDT_MULTIPLEXING == TRUE
+ BUFFER_Q frag_q; /* Queue for outgoing media fragments */
+ UINT32 frag_off; /* length of already received media fragments */
+ UINT32 frag_org_len; /* original length before fragmentation of receiving media packet */
+ UINT8 *p_next_frag; /* next fragment to send */
+ UINT8 *p_media_buf; /* buffer for media packet assigned by AVDT_SetMediaBuf */
+ UINT32 media_buf_len; /* length of buffer for media packet assigned by AVDT_SetMediaBuf */
+#endif
+} tAVDT_SCB;
+
+/* type for action functions */
+typedef void (*tAVDT_SCB_ACTION)(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+
+/* adaption layer type for transport channel table */
+typedef struct {
+ UINT16 peer_mtu; /* L2CAP mtu of the peer device */
+ UINT16 my_mtu; /* Our MTU for this channel */
+ UINT16 my_flush_to; /* Our flush timeout for this channel */
+ UINT16 lcid;
+ UINT8 tcid; /* transport channel id */
+ UINT8 ccb_idx; /* channel control block associated with this tc */
+ UINT8 state; /* transport channel state */
+ UINT8 cfg_flags; /* L2CAP configuration flags */
+ UINT8 id;
+} tAVDT_TC_TBL;
+
+/* adaption layer type for stream routing table */
+typedef struct {
+ UINT16 lcid; /* L2CAP LCID of the associated transport channel */
+ UINT8 scb_hdl; /* stream control block associated with this tc */
+} tAVDT_RT_TBL;
+
+
+/* adaption layer control block */
+typedef struct {
+ tAVDT_RT_TBL rt_tbl[AVDT_NUM_LINKS][AVDT_NUM_RT_TBL];
+ tAVDT_TC_TBL tc_tbl[AVDT_NUM_TC_TBL];
+ UINT8 lcid_tbl[MAX_L2CAP_CHANNELS]; /* map LCID to tc_tbl index */
+} tAVDT_AD;
+
+/* Control block for AVDT */
+typedef struct {
+ tAVDT_REG rcb; /* registration control block */
+ tAVDT_CCB ccb[AVDT_NUM_LINKS]; /* channel control blocks */
+ tAVDT_SCB scb[AVDT_NUM_SEPS]; /* stream control blocks */
+ tAVDT_AD ad; /* adaption layer control block */
+ tAVDTC_CTRL_CBACK *p_conf_cback; /* conformance callback function */
+ tAVDT_CCB_ACTION *p_ccb_act; /* pointer to CCB action functions */
+ tAVDT_SCB_ACTION *p_scb_act; /* pointer to SCB action functions */
+ tAVDT_CTRL_CBACK *p_conn_cback; /* connection callback function */
+ UINT8 trace_level; /* trace level */
+} tAVDT_CB;
+
+
+/*****************************************************************************
+** function declarations
+*****************************************************************************/
+
+/* CCB function declarations */
+extern void avdt_ccb_init(void);
+extern void avdt_ccb_event(tAVDT_CCB *p_ccb, UINT8 event, tAVDT_CCB_EVT *p_data);
+extern tAVDT_CCB *avdt_ccb_by_bd(BD_ADDR bd_addr);
+extern tAVDT_CCB *avdt_ccb_alloc(BD_ADDR bd_addr);
+extern void avdt_ccb_dealloc(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern UINT8 avdt_ccb_to_idx(tAVDT_CCB *p_ccb);
+extern tAVDT_CCB *avdt_ccb_by_idx(UINT8 idx);
+
+/* CCB action functions */
+extern void avdt_ccb_chan_open(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_chan_close(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_chk_close(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_hdl_discover_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_hdl_discover_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_hdl_getcap_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_hdl_getcap_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_hdl_start_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_hdl_start_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_hdl_suspend_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_hdl_suspend_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_snd_discover_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_snd_discover_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_snd_getcap_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_snd_getcap_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_snd_start_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_snd_start_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_snd_suspend_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_snd_suspend_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_clear_cmds(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_cmd_fail(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_free_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_cong_state(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_ret_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_snd_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_snd_msg(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_set_reconn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_clr_reconn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_chk_reconn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_chk_timer(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_set_conn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_set_disconn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_do_disconn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_ll_closed(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_ll_opened(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+
+/* SCB function prototypes */
+extern void avdt_scb_event(tAVDT_SCB *p_scb, UINT8 event, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_init(void);
+extern tAVDT_SCB *avdt_scb_alloc(tAVDT_CS *p_cs);
+extern void avdt_scb_dealloc(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern UINT8 avdt_scb_to_hdl(tAVDT_SCB *p_scb);
+extern tAVDT_SCB *avdt_scb_by_hdl(UINT8 hdl);
+extern UINT8 avdt_scb_verify(tAVDT_CCB *p_ccb, UINT8 state, UINT8 *p_seid, UINT16 num_seid, UINT8 *p_err_code);
+extern void avdt_scb_peer_seid_list(tAVDT_MULTI *p_multi);
+extern UINT32 avdt_scb_gen_ssrc(tAVDT_SCB *p_scb);
+
+/* SCB action functions */
+extern void avdt_scb_hdl_abort_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_abort_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_close_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_close_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_getconfig_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_getconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_open_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_open_rej(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_open_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_drop_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_reconfig_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_reconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_security_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_security_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_setconfig_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_setconfig_rej(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_setconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_start_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_start_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_suspend_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_suspend_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_delay_rpt_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_delay_rpt_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_delay_rpt_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_tc_close(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_tc_open(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_tc_close_sto(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_tc_open_sto(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_write_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_abort_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_abort_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_close_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_stream_close(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_close_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_getconfig_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_getconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_open_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_open_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_reconfig_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_reconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_security_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_security_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_setconfig_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_setconfig_rej(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_setconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_tc_close(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_cb_err(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_cong_state(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_rej_state(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_rej_in_use(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_rej_not_in_use(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_set_remove(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_free_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_chk_snd_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_clr_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_tc_timer(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_clr_vars(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_queue_frags(tAVDT_SCB *p_scb, UINT8 **pp_data, UINT32 *p_data_len, BUFFER_Q *pq);
+
+/* msg function declarations */
+extern BOOLEAN avdt_msg_send(tAVDT_CCB *p_ccb, BT_HDR *p_msg);
+extern void avdt_msg_send_cmd(tAVDT_CCB *p_ccb, void *p_scb, UINT8 sig_id, tAVDT_MSG *p_params);
+extern void avdt_msg_send_rsp(tAVDT_CCB *p_ccb, UINT8 sig_id, tAVDT_MSG *p_params);
+extern void avdt_msg_send_rej(tAVDT_CCB *p_ccb, UINT8 sig_id, tAVDT_MSG *p_params);
+extern void avdt_msg_send_grej(tAVDT_CCB *p_ccb, UINT8 sig_id, tAVDT_MSG *p_params);
+extern void avdt_msg_ind(tAVDT_CCB *p_ccb, BT_HDR *p_buf);
+
+/* adaption layer function declarations */
+extern void avdt_ad_init(void);
+extern UINT8 avdt_ad_type_to_tcid(UINT8 type, tAVDT_SCB *p_scb);
+extern tAVDT_TC_TBL *avdt_ad_tc_tbl_by_st(UINT8 type, tAVDT_CCB *p_ccb, UINT8 state);
+extern tAVDT_TC_TBL *avdt_ad_tc_tbl_by_lcid(UINT16 lcid);
+extern tAVDT_TC_TBL *avdt_ad_tc_tbl_alloc(tAVDT_CCB *p_ccb);
+extern UINT8 avdt_ad_tc_tbl_to_idx(tAVDT_TC_TBL *p_tbl);
+extern void avdt_ad_tc_close_ind(tAVDT_TC_TBL *p_tbl, UINT16 reason);
+extern void avdt_ad_tc_open_ind(tAVDT_TC_TBL *p_tbl);
+extern void avdt_ad_tc_cong_ind(tAVDT_TC_TBL *p_tbl, BOOLEAN is_congested);
+extern void avdt_ad_tc_data_ind(tAVDT_TC_TBL *p_tbl, BT_HDR *p_buf);
+extern tAVDT_TC_TBL *avdt_ad_tc_tbl_by_type(UINT8 type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb);
+extern UINT8 avdt_ad_write_req(UINT8 type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb, BT_HDR *p_buf);
+extern void avdt_ad_open_req(UINT8 type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb, UINT8 role);
+extern void avdt_ad_close_req(UINT8 type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb);
+
+extern void avdt_process_timeout(TIMER_LIST_ENT *p_tle);
+
+/*****************************************************************************
+** macros
+*****************************************************************************/
+
+/* we store the scb and the label in the layer_specific field of the
+** current cmd
+*/
+#define AVDT_BLD_LAYERSPEC(ls, msg, label) \
+ ls = (((label) << 4) | (msg))
+
+#define AVDT_LAYERSPEC_LABEL(ls) ((UINT8)((ls) >> 4))
+
+#define AVDT_LAYERSPEC_MSG(ls) ((UINT8)((ls) & 0x000F))
+
+/*****************************************************************************
+** global data
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/******************************************************************************
+** Main Control Block
+*******************************************************************************/
+#if AVDT_DYNAMIC_MEMORY == FALSE
+AVDT_API extern tAVDT_CB avdt_cb;
+#else
+AVDT_API extern tAVDT_CB *avdt_cb_ptr;
+#define avdt_cb (*avdt_cb_ptr)
+#endif
+
+
+/* L2CAP callback registration structure */
+extern const tL2CAP_APPL_INFO avdt_l2c_appl;
+
+/* reject message event lookup table */
+extern const UINT8 avdt_msg_rej_2_evt[];
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVDT_INT_H */
diff --git a/stack/avdt/avdt_l2c.c b/stack/avdt/avdt_l2c.c
new file mode 100644
index 0000000..ecab37d
--- /dev/null
+++ b/stack/avdt/avdt_l2c.c
@@ -0,0 +1,508 @@
+/*****************************************************************************
+**
+** Name: avdt_l2c.c
+**
+** Description: This AVDTP adaption layer module interfaces to L2CAP
+**
+** Copyright (c) 2002-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include <string.h>
+#include "data_types.h"
+#include "bt_target.h"
+#include "avdt_api.h"
+#include "avdtc_api.h"
+#include "avdt_int.h"
+#include "l2c_api.h"
+#include "l2cdefs.h"
+#include "btm_api.h"
+#include "btm_int.h"
+
+
+/* callback function declarations */
+void avdt_l2c_connect_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id);
+void avdt_l2c_connect_cfm_cback(UINT16 lcid, UINT16 result);
+void avdt_l2c_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg);
+void avdt_l2c_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg);
+void avdt_l2c_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed);
+void avdt_l2c_disconnect_cfm_cback(UINT16 lcid, UINT16 result);
+void avdt_l2c_congestion_ind_cback(UINT16 lcid, BOOLEAN is_congested);
+void avdt_l2c_data_ind_cback(UINT16 lcid, BT_HDR *p_buf);
+
+/* L2CAP callback function structure */
+const tL2CAP_APPL_INFO avdt_l2c_appl = {
+ avdt_l2c_connect_ind_cback,
+ avdt_l2c_connect_cfm_cback,
+ NULL,
+ avdt_l2c_config_ind_cback,
+ avdt_l2c_config_cfm_cback,
+ avdt_l2c_disconnect_ind_cback,
+ avdt_l2c_disconnect_cfm_cback,
+ NULL,
+ avdt_l2c_data_ind_cback,
+ avdt_l2c_congestion_ind_cback,
+ NULL /* tL2CA_TX_COMPLETE_CB */
+};
+
+/*******************************************************************************
+**
+** Function avdt_sec_check_complete_term
+**
+** Description The function called when Security Manager finishes
+** verification of the service side connection
+**
+** Returns void
+**
+*******************************************************************************/
+static void avdt_sec_check_complete_term (BD_ADDR bd_addr, void *p_ref_data, UINT8 res)
+{
+ tAVDT_CCB *p_ccb = NULL;
+ tL2CAP_CFG_INFO cfg;
+ tAVDT_TC_TBL *p_tbl;
+
+ AVDT_TRACE_DEBUG1("avdt_sec_check_complete_term res: %d", res);
+ if (!bd_addr)
+ {
+ AVDT_TRACE_WARNING0("avdt_sec_check_complete_term: NULL BD_ADDR");
+ return;
+
+ }
+ p_ccb = avdt_ccb_by_bd(bd_addr);
+
+ p_tbl = avdt_ad_tc_tbl_by_st(AVDT_CHAN_SIG, p_ccb, AVDT_AD_ST_SEC_ACP);
+ if (p_tbl == NULL)
+ return;
+
+ if (res == BTM_SUCCESS)
+ {
+ /* Send response to the L2CAP layer. */
+ L2CA_ConnectRsp (bd_addr, p_tbl->id, p_tbl->lcid, L2CAP_CONN_OK, L2CAP_CONN_OK);
+
+ /* store idx in LCID table, store LCID in routing table */
+ avdt_cb.ad.lcid_tbl[p_tbl->lcid - L2CAP_BASE_APPL_CID] = avdt_ad_tc_tbl_to_idx(p_tbl);
+ avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][p_tbl->tcid].lcid = p_tbl->lcid;
+
+ /* transition to configuration state */
+ p_tbl->state = AVDT_AD_ST_CFG;
+
+ /* Send L2CAP config req */
+ memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+ cfg.mtu_present = TRUE;
+ cfg.mtu = p_tbl->my_mtu;
+ cfg.flush_to_present = TRUE;
+ cfg.flush_to = p_tbl->my_flush_to;
+ L2CA_ConfigReq(p_tbl->lcid, &cfg);
+ }
+ else
+ {
+ L2CA_ConnectRsp (bd_addr, p_tbl->id, p_tbl->lcid, L2CAP_CONN_SECURITY_BLOCK, L2CAP_CONN_OK);
+ avdt_ad_tc_close_ind(p_tbl, L2CAP_CONN_SECURITY_BLOCK);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_sec_check_complete_orig
+**
+** Description The function called when Security Manager finishes
+** verification of the service side connection
+**
+** Returns void
+**
+*******************************************************************************/
+static void avdt_sec_check_complete_orig (BD_ADDR bd_addr, void *p_ref_data, UINT8 res)
+{
+ tAVDT_CCB *p_ccb = NULL;
+ tL2CAP_CFG_INFO cfg;
+ tAVDT_TC_TBL *p_tbl;
+
+ AVDT_TRACE_DEBUG1("avdt_sec_check_complete_orig res: %d", res);
+ if (bd_addr)
+ p_ccb = avdt_ccb_by_bd(bd_addr);
+ p_tbl = avdt_ad_tc_tbl_by_st(AVDT_CHAN_SIG, p_ccb, AVDT_AD_ST_SEC_INT);
+ if(p_tbl == NULL)
+ return;
+
+ if( res == BTM_SUCCESS )
+ {
+ /* set channel state */
+ p_tbl->state = AVDT_AD_ST_CFG;
+
+ /* Send L2CAP config req */
+ memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+ cfg.mtu_present = TRUE;
+ cfg.mtu = p_tbl->my_mtu;
+ cfg.flush_to_present = TRUE;
+ cfg.flush_to = p_tbl->my_flush_to;
+ L2CA_ConfigReq(p_tbl->lcid, &cfg);
+ }
+ else
+ {
+ L2CA_DisconnectReq (p_tbl->lcid);
+ avdt_ad_tc_close_ind(p_tbl, L2CAP_CONN_SECURITY_BLOCK);
+ }
+}
+/*******************************************************************************
+**
+** Function avdt_l2c_connect_ind_cback
+**
+** Description This is the L2CAP connect indication callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void avdt_l2c_connect_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id)
+{
+ tAVDT_CCB *p_ccb;
+ tAVDT_TC_TBL *p_tbl = NULL;
+ UINT16 result;
+ tL2CAP_CFG_INFO cfg;
+ tBTM_STATUS rc;
+
+ /* do we already have a control channel for this peer? */
+ if ((p_ccb = avdt_ccb_by_bd(bd_addr)) == NULL)
+ {
+ /* no, allocate ccb */
+ if ((p_ccb = avdt_ccb_alloc(bd_addr)) == NULL)
+ {
+ /* no ccb available, reject L2CAP connection */
+ result = L2CAP_CONN_NO_RESOURCES;
+ }
+ else
+ {
+ /* allocate and set up entry; first channel is always signaling */
+ p_tbl = avdt_ad_tc_tbl_alloc(p_ccb);
+ p_tbl->my_mtu = avdt_cb.rcb.ctrl_mtu;
+ p_tbl->my_flush_to = L2CAP_DEFAULT_FLUSH_TO;
+ p_tbl->tcid = AVDT_CHAN_SIG;
+ p_tbl->lcid = lcid;
+ p_tbl->id = id;
+ p_tbl->state = AVDT_AD_ST_SEC_ACP;
+ p_tbl->cfg_flags = AVDT_L2C_CFG_CONN_ACP;
+
+ /* Check the security */
+ rc = btm_sec_mx_access_request (bd_addr, AVDT_PSM,
+ FALSE, BTM_SEC_PROTO_AVDT,
+ AVDT_CHAN_SIG,
+ &avdt_sec_check_complete_term, NULL);
+ if(rc == BTM_CMD_STARTED)
+ {
+ L2CA_ConnectRsp (p_ccb->peer_addr, p_tbl->id, lcid, L2CAP_CONN_PENDING, L2CAP_CONN_OK);
+ }
+ return;
+ }
+ }
+ /* deal with simultaneous control channel connect case */
+ else if ((p_tbl = avdt_ad_tc_tbl_by_st(AVDT_CHAN_SIG, p_ccb, AVDT_AD_ST_CONN)) != NULL)
+ {
+ /* reject their connection */
+ result = L2CAP_CONN_NO_RESOURCES;
+ }
+ /* this must be a traffic channel; are we accepting a traffic channel
+ ** for this ccb?
+ */
+ else if ((p_tbl = avdt_ad_tc_tbl_by_st(AVDT_CHAN_MEDIA, p_ccb, AVDT_AD_ST_ACP)) != NULL)
+ {
+ /* yes; proceed with connection */
+ result = L2CAP_CONN_OK;
+ }
+#if AVDT_REPORTING == TRUE
+ /* this must be a reporting channel; are we accepting a reporting channel
+ ** for this ccb?
+ */
+ else if ((p_tbl = avdt_ad_tc_tbl_by_st(AVDT_CHAN_REPORT, p_ccb, AVDT_AD_ST_ACP)) != NULL)
+ {
+ /* yes; proceed with connection */
+ result = L2CAP_CONN_OK;
+ }
+#endif
+ /* else we're not listening for traffic channel; reject */
+ else
+ {
+ result = L2CAP_CONN_NO_PSM;
+ }
+
+ /* Send L2CAP connect rsp */
+ L2CA_ConnectRsp(bd_addr, id, lcid, result, 0);
+
+ /* if result ok, proceed with connection */
+ if (result == L2CAP_CONN_OK)
+ {
+ /* store idx in LCID table, store LCID in routing table */
+ avdt_cb.ad.lcid_tbl[lcid - L2CAP_BASE_APPL_CID] = avdt_ad_tc_tbl_to_idx(p_tbl);
+ avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][p_tbl->tcid].lcid = lcid;
+
+ /* transition to configuration state */
+ p_tbl->state = AVDT_AD_ST_CFG;
+
+ /* Send L2CAP config req */
+ memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+ cfg.mtu_present = TRUE;
+ cfg.mtu = p_tbl->my_mtu;
+ cfg.flush_to_present = TRUE;
+ cfg.flush_to = p_tbl->my_flush_to;
+ L2CA_ConfigReq(lcid, &cfg);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_l2c_connect_cfm_cback
+**
+** Description This is the L2CAP connect confirm callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void avdt_l2c_connect_cfm_cback(UINT16 lcid, UINT16 result)
+{
+ tAVDT_TC_TBL *p_tbl;
+ tL2CAP_CFG_INFO cfg;
+ tAVDT_CCB *p_ccb;
+
+ AVDT_TRACE_DEBUG2("avdt_l2c_connect_cfm_cback lcid: %d, result: %d",
+ lcid, result);
+ /* look up info for this channel */
+ if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL)
+ {
+ /* if in correct state */
+ if (p_tbl->state == AVDT_AD_ST_CONN)
+ {
+ /* if result successful */
+ if (result == L2CAP_CONN_OK)
+ {
+ if(p_tbl->tcid != AVDT_CHAN_SIG)
+ {
+ /* set channel state */
+ p_tbl->state = AVDT_AD_ST_CFG;
+
+ /* Send L2CAP config req */
+ memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+ cfg.mtu_present = TRUE;
+ cfg.mtu = p_tbl->my_mtu;
+ cfg.flush_to_present = TRUE;
+ cfg.flush_to = p_tbl->my_flush_to;
+ L2CA_ConfigReq(lcid, &cfg);
+ }
+ else
+ {
+ p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx);
+ if(p_ccb == NULL)
+ {
+ result = L2CAP_CONN_NO_RESOURCES;
+ }
+ else
+ {
+ /* set channel state */
+ p_tbl->state = AVDT_AD_ST_SEC_INT;
+ p_tbl->lcid = lcid;
+ p_tbl->cfg_flags = AVDT_L2C_CFG_CONN_INT;
+
+ /* Check the security */
+ btm_sec_mx_access_request (p_ccb->peer_addr, AVDT_PSM,
+ TRUE, BTM_SEC_PROTO_AVDT,
+ AVDT_CHAN_SIG,
+ &avdt_sec_check_complete_orig, NULL);
+ }
+ }
+ }
+
+ /* failure; notify adaption that channel closed */
+ if (result != L2CAP_CONN_OK)
+ {
+ avdt_ad_tc_close_ind(p_tbl, result);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_l2c_config_cfm_cback
+**
+** Description This is the L2CAP config confirm callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void avdt_l2c_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
+{
+ tAVDT_TC_TBL *p_tbl;
+
+ /* look up info for this channel */
+ if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL)
+ {
+ /* if in correct state */
+ if (p_tbl->state == AVDT_AD_ST_CFG)
+ {
+ /* if result successful */
+ if (p_cfg->result == L2CAP_CONN_OK)
+ {
+ /* update cfg_flags */
+ p_tbl->cfg_flags |= AVDT_L2C_CFG_CFM_DONE;
+
+ /* if configuration complete */
+ if (p_tbl->cfg_flags & AVDT_L2C_CFG_IND_DONE)
+ {
+ avdt_ad_tc_open_ind(p_tbl);
+ }
+ }
+ /* else failure */
+ else
+ {
+ /* Send L2CAP disconnect req */
+ L2CA_DisconnectReq(lcid);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_l2c_config_ind_cback
+**
+** Description This is the L2CAP config indication callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void avdt_l2c_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
+{
+ tAVDT_TC_TBL *p_tbl;
+
+ /* look up info for this channel */
+ if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL)
+ {
+ /* store the mtu in tbl */
+ if (p_cfg->mtu_present)
+ {
+ p_tbl->peer_mtu = p_cfg->mtu;
+ }
+ else
+ {
+ p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
+ }
+ AVDT_TRACE_DEBUG2("peer_mtu: %d, lcid: x%x",p_tbl->peer_mtu, lcid);
+
+ /* send L2CAP configure response */
+ memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO));
+ p_cfg->result = L2CAP_CFG_OK;
+ L2CA_ConfigRsp(lcid, p_cfg);
+
+ /* if first config ind */
+ if ((p_tbl->cfg_flags & AVDT_L2C_CFG_IND_DONE) == 0)
+ {
+ /* update cfg_flags */
+ p_tbl->cfg_flags |= AVDT_L2C_CFG_IND_DONE;
+
+ /* if configuration complete */
+ if (p_tbl->cfg_flags & AVDT_L2C_CFG_CFM_DONE)
+ {
+ avdt_ad_tc_open_ind(p_tbl);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_l2c_disconnect_ind_cback
+**
+** Description This is the L2CAP disconnect indication callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void avdt_l2c_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed)
+{
+ tAVDT_TC_TBL *p_tbl;
+
+ AVDT_TRACE_DEBUG2("avdt_l2c_disconnect_ind_cback lcid: %d, ack_needed: %d",
+ lcid, ack_needed);
+ /* look up info for this channel */
+ if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL)
+ {
+ if (ack_needed)
+ {
+ /* send L2CAP disconnect response */
+ L2CA_DisconnectRsp(lcid);
+ }
+
+ avdt_ad_tc_close_ind(p_tbl, 0);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_l2c_disconnect_cfm_cback
+**
+** Description This is the L2CAP disconnect confirm callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void avdt_l2c_disconnect_cfm_cback(UINT16 lcid, UINT16 result)
+{
+ tAVDT_TC_TBL *p_tbl;
+
+ AVDT_TRACE_DEBUG2("avdt_l2c_disconnect_cfm_cback lcid: %d, result: %d",
+ lcid, result);
+ /* look up info for this channel */
+ if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL)
+ {
+ avdt_ad_tc_close_ind(p_tbl, result);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_l2c_congestion_ind_cback
+**
+** Description This is the L2CAP congestion indication callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void avdt_l2c_congestion_ind_cback(UINT16 lcid, BOOLEAN is_congested)
+{
+ tAVDT_TC_TBL *p_tbl;
+
+ /* look up info for this channel */
+ if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL)
+ {
+ avdt_ad_tc_cong_ind(p_tbl, is_congested);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_l2c_data_ind_cback
+**
+** Description This is the L2CAP data indication callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void avdt_l2c_data_ind_cback(UINT16 lcid, BT_HDR *p_buf)
+{
+ tAVDT_TC_TBL *p_tbl;
+
+ /* look up info for this channel */
+ if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL)
+ {
+ avdt_ad_tc_data_ind(p_tbl, p_buf);
+ }
+ else /* prevent buffer leak */
+ GKI_freebuf(p_buf);
+}
+
diff --git a/stack/avdt/avdt_msg.c b/stack/avdt/avdt_msg.c
new file mode 100644
index 0000000..35066f9
--- /dev/null
+++ b/stack/avdt/avdt_msg.c
@@ -0,0 +1,1879 @@
+/*****************************************************************************
+**
+** Name: avdt_msg.c
+**
+** Description: This module contains functions for parsing and building
+** AVDTP signaling messages. It also contains functions
+** called by the SCB or CCB state machines for sending
+** command, response, and reject messages. It also contains
+** a function that processes incoming messages and dispatches
+** them to the appropriate SCB or CCB.
+**
+** Copyright (c) 2002-2010, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include <string.h>
+#include "data_types.h"
+#include "bt_target.h"
+#include "avdt_api.h"
+#include "avdtc_api.h"
+#include "avdt_int.h"
+#include "gki.h"
+#include "btu.h"
+
+/*****************************************************************************
+** constants
+*****************************************************************************/
+
+/* mask of all psc values */
+#define AVDT_MSG_PSC_MASK (AVDT_PSC_TRANS | AVDT_PSC_REPORT | AVDT_PSC_DELAY_RPT | \
+ AVDT_PSC_RECOV | AVDT_PSC_HDRCMP | AVDT_PSC_MUX)
+#define AVDT_PSC_PROTECT (1<<4) /* Content Protection */
+#define AVDT_PSC_CODEC (1<<7) /* codec */
+
+
+/*****************************************************************************
+** type definitions
+*****************************************************************************/
+
+/* type for message building functions */
+typedef void (*tAVDT_MSG_BLD)(UINT8 **p, tAVDT_MSG *p_msg);
+
+/* type for message parsing functions */
+typedef UINT8 (*tAVDT_MSG_PRS)(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len);
+
+
+/*****************************************************************************
+** local function declarations
+*****************************************************************************/
+
+static void avdt_msg_bld_none(UINT8 **p, tAVDT_MSG *p_msg);
+static void avdt_msg_bld_single(UINT8 **p, tAVDT_MSG *p_msg);
+static void avdt_msg_bld_setconfig_cmd(UINT8 **p, tAVDT_MSG *p_msg);
+static void avdt_msg_bld_reconfig_cmd(UINT8 **p, tAVDT_MSG *p_msg);
+static void avdt_msg_bld_multi(UINT8 **p, tAVDT_MSG *p_msg);
+static void avdt_msg_bld_security_cmd(UINT8 **p, tAVDT_MSG *p_msg);
+static void avdt_msg_bld_discover_rsp(UINT8 **p, tAVDT_MSG *p_msg);
+static void avdt_msg_bld_svccap(UINT8 **p, tAVDT_MSG *p_msg);
+static void avdt_msg_bld_security_rsp(UINT8 **p, tAVDT_MSG *p_msg);
+static void avdt_msg_bld_all_svccap(UINT8 **p, tAVDT_MSG *p_msg);
+static void avdt_msg_bld_delay_rpt(UINT8 **p, tAVDT_MSG *p_msg);
+
+static UINT8 avdt_msg_prs_none(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len);
+static UINT8 avdt_msg_prs_single(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len);
+static UINT8 avdt_msg_prs_setconfig_cmd(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len);
+static UINT8 avdt_msg_prs_reconfig_cmd(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len);
+static UINT8 avdt_msg_prs_multi(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len);
+static UINT8 avdt_msg_prs_security_cmd(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len);
+static UINT8 avdt_msg_prs_discover_rsp(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len);
+static UINT8 avdt_msg_prs_svccap(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len);
+static UINT8 avdt_msg_prs_all_svccap(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len);
+static UINT8 avdt_msg_prs_security_rsp(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len);
+static UINT8 avdt_msg_prs_delay_rpt (tAVDT_MSG *p_msg, UINT8 *p, UINT16 len);
+
+/*****************************************************************************
+** constants
+*****************************************************************************/
+
+/* table of information element minimum lengths used for parsing */
+const UINT8 avdt_msg_ie_len_min[] = {
+ 0, /* unused */
+ AVDT_LEN_TRANS_MIN, /* media transport */
+ AVDT_LEN_REPORT_MIN, /* reporting */
+ AVDT_LEN_RECOV_MIN, /* recovery */
+ AVDT_LEN_PROTECT_MIN, /* content protection */
+ AVDT_LEN_HDRCMP_MIN, /* header compression */
+ AVDT_LEN_MUX_MIN, /* multiplexing */
+ AVDT_LEN_CODEC_MIN, /* codec */
+ AVDT_LEN_DELAY_RPT_MIN /* delay report */
+};
+
+/* table of information element minimum lengths used for parsing */
+const UINT8 avdt_msg_ie_len_max[] = {
+ 0, /* unused */
+ AVDT_LEN_TRANS_MAX, /* media transport */
+ AVDT_LEN_REPORT_MAX, /* reporting */
+ AVDT_LEN_RECOV_MAX, /* recovery */
+ AVDT_LEN_PROTECT_MAX, /* content protection */
+ AVDT_LEN_HDRCMP_MAX, /* header compression */
+ AVDT_LEN_MUX_MAX, /* multiplexing */
+ AVDT_LEN_CODEC_MAX, /* codec */
+ AVDT_LEN_DELAY_RPT_MAX /* delay report */
+};
+
+/* table of error codes used when decoding information elements */
+const UINT8 avdt_msg_ie_err[] = {
+ 0, /* unused */
+ AVDT_ERR_MEDIA_TRANS, /* media transport */
+ AVDT_ERR_LENGTH, /* reporting */
+ AVDT_ERR_RECOV_FMT, /* recovery */
+ AVDT_ERR_CP_FMT, /* content protection */
+ AVDT_ERR_ROHC_FMT, /* header compression */
+ AVDT_ERR_MUX_FMT, /* multiplexing */
+ AVDT_ERR_SERVICE, /* codec */
+ AVDT_ERR_SERVICE /* delay report ?? */
+};
+
+/* table of packet type minimum lengths */
+static const UINT8 avdt_msg_pkt_type_len[] = {
+ AVDT_LEN_TYPE_SINGLE,
+ AVDT_LEN_TYPE_START,
+ AVDT_LEN_TYPE_CONT,
+ AVDT_LEN_TYPE_END
+};
+
+/* function table for building command messages */
+const tAVDT_MSG_BLD avdt_msg_bld_cmd[] = {
+ avdt_msg_bld_none, /* discover */
+ avdt_msg_bld_single, /* get capabilities */
+ avdt_msg_bld_setconfig_cmd, /* set configuration */
+ avdt_msg_bld_single, /* get configuration */
+ avdt_msg_bld_reconfig_cmd, /* reconfigure */
+ avdt_msg_bld_single, /* open */
+ avdt_msg_bld_multi, /* start */
+ avdt_msg_bld_single, /* close */
+ avdt_msg_bld_multi, /* suspend */
+ avdt_msg_bld_single, /* abort */
+ avdt_msg_bld_security_cmd, /* security control */
+ avdt_msg_bld_single, /* get all capabilities */
+ avdt_msg_bld_delay_rpt /* delay report */
+};
+
+/* function table for building response messages */
+const tAVDT_MSG_BLD avdt_msg_bld_rsp[] = {
+ avdt_msg_bld_discover_rsp, /* discover */
+ avdt_msg_bld_svccap, /* get capabilities */
+ avdt_msg_bld_none, /* set configuration */
+ avdt_msg_bld_all_svccap, /* get configuration */
+ avdt_msg_bld_none, /* reconfigure */
+ avdt_msg_bld_none, /* open */
+ avdt_msg_bld_none, /* start */
+ avdt_msg_bld_none, /* close */
+ avdt_msg_bld_none, /* suspend */
+ avdt_msg_bld_none, /* abort */
+ avdt_msg_bld_security_rsp, /* security control */
+ avdt_msg_bld_all_svccap, /* get all capabilities */
+ avdt_msg_bld_none /* delay report */
+};
+
+/* function table for parsing command messages */
+const tAVDT_MSG_PRS avdt_msg_prs_cmd[] = {
+ avdt_msg_prs_none, /* discover */
+ avdt_msg_prs_single, /* get capabilities */
+ avdt_msg_prs_setconfig_cmd, /* set configuration */
+ avdt_msg_prs_single, /* get configuration */
+ avdt_msg_prs_reconfig_cmd, /* reconfigure */
+ avdt_msg_prs_single, /* open */
+ avdt_msg_prs_multi, /* start */
+ avdt_msg_prs_single, /* close */
+ avdt_msg_prs_multi, /* suspend */
+ avdt_msg_prs_single, /* abort */
+ avdt_msg_prs_security_cmd, /* security control */
+ avdt_msg_prs_single, /* get all capabilities */
+ avdt_msg_prs_delay_rpt /* delay report */
+};
+
+/* function table for parsing response messages */
+const tAVDT_MSG_PRS avdt_msg_prs_rsp[] = {
+ avdt_msg_prs_discover_rsp, /* discover */
+ avdt_msg_prs_svccap, /* get capabilities */
+ avdt_msg_prs_none, /* set configuration */
+ avdt_msg_prs_all_svccap, /* get configuration */
+ avdt_msg_prs_none, /* reconfigure */
+ avdt_msg_prs_none, /* open */
+ avdt_msg_prs_none, /* start */
+ avdt_msg_prs_none, /* close */
+ avdt_msg_prs_none, /* suspend */
+ avdt_msg_prs_none, /* abort */
+ avdt_msg_prs_security_rsp, /* security control */
+ avdt_msg_prs_all_svccap, /* get all capabilities */
+ avdt_msg_prs_none /* delay report */
+};
+
+/* command message-to-event lookup table */
+const UINT8 avdt_msg_cmd_2_evt[] = {
+ AVDT_CCB_MSG_DISCOVER_CMD_EVT + AVDT_CCB_MKR, /* discover */
+ AVDT_CCB_MSG_GETCAP_CMD_EVT + AVDT_CCB_MKR, /* get capabilities */
+ AVDT_SCB_MSG_SETCONFIG_CMD_EVT, /* set configuration */
+ AVDT_SCB_MSG_GETCONFIG_CMD_EVT, /* get configuration */
+ AVDT_SCB_MSG_RECONFIG_CMD_EVT, /* reconfigure */
+ AVDT_SCB_MSG_OPEN_CMD_EVT, /* open */
+ AVDT_CCB_MSG_START_CMD_EVT + AVDT_CCB_MKR, /* start */
+ AVDT_SCB_MSG_CLOSE_CMD_EVT, /* close */
+ AVDT_CCB_MSG_SUSPEND_CMD_EVT + AVDT_CCB_MKR, /* suspend */
+ AVDT_SCB_MSG_ABORT_CMD_EVT, /* abort */
+ AVDT_SCB_MSG_SECURITY_CMD_EVT, /* security control */
+ AVDT_CCB_MSG_GETCAP_CMD_EVT + AVDT_CCB_MKR, /* get all capabilities */
+ AVDT_SCB_MSG_DELAY_RPT_CMD_EVT /* delay report */
+};
+
+/* response message-to-event lookup table */
+const UINT8 avdt_msg_rsp_2_evt[] = {
+ AVDT_CCB_MSG_DISCOVER_RSP_EVT + AVDT_CCB_MKR, /* discover */
+ AVDT_CCB_MSG_GETCAP_RSP_EVT + AVDT_CCB_MKR, /* get capabilities */
+ AVDT_SCB_MSG_SETCONFIG_RSP_EVT, /* set configuration */
+ AVDT_SCB_MSG_GETCONFIG_RSP_EVT, /* get configuration */
+ AVDT_SCB_MSG_RECONFIG_RSP_EVT, /* reconfigure */
+ AVDT_SCB_MSG_OPEN_RSP_EVT, /* open */
+ AVDT_CCB_MSG_START_RSP_EVT + AVDT_CCB_MKR, /* start */
+ AVDT_SCB_MSG_CLOSE_RSP_EVT, /* close */
+ AVDT_CCB_MSG_SUSPEND_RSP_EVT + AVDT_CCB_MKR, /* suspend */
+ AVDT_SCB_MSG_ABORT_RSP_EVT, /* abort */
+ AVDT_SCB_MSG_SECURITY_RSP_EVT, /* security control */
+ AVDT_CCB_MSG_GETCAP_RSP_EVT + AVDT_CCB_MKR, /* get all capabilities */
+ AVDT_SCB_MSG_DELAY_RPT_RSP_EVT /* delay report */
+};
+
+/* reject message-to-event lookup table */
+const UINT8 avdt_msg_rej_2_evt[] = {
+ AVDT_CCB_MSG_DISCOVER_RSP_EVT + AVDT_CCB_MKR, /* discover */
+ AVDT_CCB_MSG_GETCAP_RSP_EVT + AVDT_CCB_MKR, /* get capabilities */
+ AVDT_SCB_MSG_SETCONFIG_REJ_EVT, /* set configuration */
+ AVDT_SCB_MSG_GETCONFIG_RSP_EVT, /* get configuration */
+ AVDT_SCB_MSG_RECONFIG_RSP_EVT, /* reconfigure */
+ AVDT_SCB_MSG_OPEN_REJ_EVT, /* open */
+ AVDT_CCB_MSG_START_RSP_EVT + AVDT_CCB_MKR, /* start */
+ AVDT_SCB_MSG_CLOSE_RSP_EVT, /* close */
+ AVDT_CCB_MSG_SUSPEND_RSP_EVT + AVDT_CCB_MKR, /* suspend */
+ AVDT_SCB_MSG_ABORT_RSP_EVT, /* abort */
+ AVDT_SCB_MSG_SECURITY_RSP_EVT, /* security control */
+ AVDT_CCB_MSG_GETCAP_RSP_EVT + AVDT_CCB_MKR, /* get all capabilities */
+ 0 /* delay report */
+};
+
+/*******************************************************************************
+**
+** Function avdt_msg_bld_cfg
+**
+** Description This function builds the configuration parameters contained
+** in a command or response message.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+static void avdt_msg_bld_cfg(UINT8 **p, tAVDT_CFG *p_cfg)
+{
+ UINT8 len;
+
+ /* for now, just build media transport, codec, and content protection, and multiplexing */
+
+ /* media transport */
+ if (p_cfg->psc_mask & AVDT_PSC_TRANS)
+ {
+ *(*p)++ = AVDT_CAT_TRANS;
+ *(*p)++ = 0; /* length */
+ }
+
+#if AVDT_REPORTING == TRUE
+ /* reporting transport */
+ if (p_cfg->psc_mask & AVDT_PSC_REPORT)
+ {
+ *(*p)++ = AVDT_CAT_REPORT;
+ *(*p)++ = 0; /* length */
+ }
+#endif
+
+ /* codec */
+ if (p_cfg->num_codec != 0)
+ {
+ *(*p)++ = AVDT_CAT_CODEC;
+ len = p_cfg->codec_info[0] + 1;
+ if( len > AVDT_CODEC_SIZE )
+ len = AVDT_CODEC_SIZE;
+
+ memcpy(*p, p_cfg->codec_info, len);
+ *p += len;
+ }
+
+ /* content protection */
+ if (p_cfg->num_protect != 0)
+ {
+ *(*p)++ = AVDT_CAT_PROTECT;
+ len = p_cfg->protect_info[0] + 1;
+ if( len > AVDT_PROTECT_SIZE )
+ len = AVDT_PROTECT_SIZE;
+
+ memcpy(*p, p_cfg->protect_info, len);
+ *p += len;
+ }
+
+#if AVDT_MULTIPLEXING == TRUE
+ /* multiplexing */
+ if (p_cfg->psc_mask & AVDT_PSC_MUX)
+ {
+ *(*p)++ = AVDT_CAT_MUX;
+ /* length */
+ if (p_cfg->psc_mask & AVDT_PSC_RECOV)
+ *(*p)++ = 7; /* frag (1) + media + report + recovery */
+ else if (p_cfg->psc_mask & AVDT_PSC_REPORT)
+ *(*p)++ = 5; /* frag (1) + media + report */
+ else
+ *(*p)++ = 3; /* frag (1) + media */
+
+ /* allow fragmentation */
+ if(p_cfg->mux_mask & AVDT_MUX_FRAG)
+ *(*p)++ = 0x80;
+ else
+ *(*p)++ = 0;
+
+ /* media transport session */
+ *(*p)++ = p_cfg->mux_tsid_media<<3; /* TSID */
+ *(*p)++ = p_cfg->mux_tcid_media<<3; /* TCID */
+
+ if (p_cfg->psc_mask & AVDT_PSC_RECOV)
+ {
+ /* reporting transport session */
+ *(*p)++ = p_cfg->mux_tsid_report<<3; /* TSID */
+ *(*p)++ = p_cfg->mux_tcid_report<<3; /* TCID */
+ /* recovery transport session */
+ *(*p)++ = p_cfg->mux_tsid_recov<<3; /* TSID */
+ *(*p)++ = p_cfg->mux_tcid_recov<<3; /* TCID */
+ }
+ else if (p_cfg->psc_mask & AVDT_PSC_REPORT)
+ {
+ /* reporting transport session */
+ *(*p)++ = p_cfg->mux_tsid_report<<3; /* TSID */
+ *(*p)++ = p_cfg->mux_tcid_report<<3; /* TCID */
+ }
+ }
+#endif
+
+ /* delay report */
+ if (p_cfg->psc_mask & AVDT_PSC_DELAY_RPT)
+ {
+ *(*p)++ = AVDT_CAT_DELAY_RPT;
+ *(*p)++ = 0; /* length */
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_bld_none
+**
+** Description This message building function builds an empty message.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+static void avdt_msg_bld_none(UINT8 **p, tAVDT_MSG *p_msg)
+{
+ return;
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_bld_single
+**
+** Description This message building function builds a message containing
+** a single SEID.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+static void avdt_msg_bld_single(UINT8 **p, tAVDT_MSG *p_msg)
+{
+ AVDT_MSG_BLD_SEID(*p, p_msg->single.seid);
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_bld_setconfig_cmd
+**
+** Description This message building function builds a set configuration
+** command message.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+static void avdt_msg_bld_setconfig_cmd(UINT8 **p, tAVDT_MSG *p_msg)
+{
+ AVDT_MSG_BLD_SEID(*p, p_msg->config_cmd.hdr.seid);
+ AVDT_MSG_BLD_SEID(*p, p_msg->config_cmd.int_seid);
+ avdt_msg_bld_cfg(p, p_msg->config_cmd.p_cfg);
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_bld_reconfig_cmd
+**
+** Description This message building function builds a reconfiguration
+** command message.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+static void avdt_msg_bld_reconfig_cmd(UINT8 **p, tAVDT_MSG *p_msg)
+{
+ AVDT_MSG_BLD_SEID(*p, p_msg->reconfig_cmd.hdr.seid);
+
+ /* force psc mask zero to build only codec and security */
+ p_msg->reconfig_cmd.p_cfg->psc_mask = 0;
+ avdt_msg_bld_cfg(p, p_msg->reconfig_cmd.p_cfg);
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_bld_multi
+**
+** Description This message building function builds a message containing
+** multiple SEID's.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+static void avdt_msg_bld_multi(UINT8 **p, tAVDT_MSG *p_msg)
+{
+ int i;
+
+ for (i = 0; i < p_msg->multi.num_seps; i++)
+ {
+ AVDT_MSG_BLD_SEID(*p, p_msg->multi.seid_list[i]);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_bld_security_cmd
+**
+** Description This message building function builds a security
+** command message.
+**
+** Returns void.
+**
+*******************************************************************************/
+static void avdt_msg_bld_security_cmd(UINT8 **p, tAVDT_MSG *p_msg)
+{
+ AVDT_MSG_BLD_SEID(*p, p_msg->security_cmd.hdr.seid);
+ memcpy(*p, p_msg->security_cmd.p_data, p_msg->security_cmd.len);
+ *p += p_msg->security_cmd.len;
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_bld_delay_rpt
+**
+** Description This message building function builds a delay report
+** command message.
+**
+** Returns void.
+**
+*******************************************************************************/
+static void avdt_msg_bld_delay_rpt(UINT8 **p, tAVDT_MSG *p_msg)
+{
+ AVDT_MSG_BLD_SEID(*p, p_msg->delay_rpt_cmd.hdr.seid);
+ UINT16_TO_BE_STREAM(*p, p_msg->delay_rpt_cmd.delay);
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_bld_discover_rsp
+**
+** Description This message building function builds a discover
+** response message.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+static void avdt_msg_bld_discover_rsp(UINT8 **p, tAVDT_MSG *p_msg)
+{
+ int i;
+
+ for (i = 0; i < p_msg->discover_rsp.num_seps; i++)
+ {
+ /* build discover rsp info */
+ AVDT_MSG_BLD_DISC(*p, p_msg->discover_rsp.p_sep_info[i].seid,
+ p_msg->discover_rsp.p_sep_info[i].in_use,
+ p_msg->discover_rsp.p_sep_info[i].media_type,
+ p_msg->discover_rsp.p_sep_info[i].tsep);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_bld_svccap
+**
+** Description This message building function builds a message containing
+** service capabilities parameters.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+static void avdt_msg_bld_svccap(UINT8 **p, tAVDT_MSG *p_msg)
+{
+ tAVDT_CFG cfg;
+
+ /* make sure the delay report category is not reported */
+ memcpy (&cfg, p_msg->svccap.p_cfg, sizeof(tAVDT_CFG));
+ cfg.psc_mask &= ~AVDT_PSC_DELAY_RPT;
+ avdt_msg_bld_cfg(p, &cfg);
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_bld_all_svccap
+**
+** Description This message building function builds a message containing
+** service capabilities parameters.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+static void avdt_msg_bld_all_svccap(UINT8 **p, tAVDT_MSG *p_msg)
+{
+ avdt_msg_bld_cfg(p, p_msg->svccap.p_cfg);
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_bld_security_rsp
+**
+** Description This message building function builds a security
+** response message.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+static void avdt_msg_bld_security_rsp(UINT8 **p, tAVDT_MSG *p_msg)
+{
+ memcpy(*p, p_msg->security_rsp.p_data, p_msg->security_rsp.len);
+ *p += p_msg->security_rsp.len;
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_prs_cfg
+**
+** Description This message parsing function parses the configuration
+** parameters field of a message.
+**
+**
+** Returns Error code or zero if no error, and element that failed
+** in p_elem.
+**
+*******************************************************************************/
+static UINT8 avdt_msg_prs_cfg(tAVDT_CFG *p_cfg, UINT8 *p, UINT16 len, UINT8* p_elem, UINT8 sig_id)
+{
+ UINT8 *p_end;
+ UINT8 elem = 0;
+ UINT8 elem_len;
+ UINT8 tmp;
+ UINT8 err = 0;
+ UINT8 protect_offset = 0;
+
+ if (!p_cfg)
+ {
+ AVDT_TRACE_ERROR0 ("not expecting this cfg");
+ return AVDT_ERR_BAD_STATE;
+ }
+
+ p_cfg->psc_mask = 0;
+ p_cfg->num_codec = 0;
+ p_cfg->num_protect = 0;
+#if AVDT_MULTIPLEXING == TRUE
+ p_cfg->mux_mask = 0;
+#endif
+
+ /* while there is still data to parse */
+ p_end = p + len;
+ while ((p < p_end) && (err == 0))
+ {
+ /* verify overall length */
+ if ((p_end - p) < AVDT_LEN_CFG_MIN)
+ {
+ err = AVDT_ERR_PAYLOAD;
+ break;
+ }
+
+ /* get and verify info elem id, length */
+ elem = *p++;
+ elem_len = *p++;
+
+ if ((elem == 0) || (elem > AVDT_CAT_MAX_CUR))
+ {
+ /* this may not be really bad.
+ * It may be a service category that is too new for us.
+ * allow these to be parsed without reporting an error.
+ * If this is a "capability" (as in GetCapRsp & GetConfigRsp), this is filtered out.
+ * If this is a Configuration (as in SetConfigCmd & ReconfigCmd),
+ * this will be marked as an error in the caller of this function */
+ if ((sig_id == AVDT_SIG_SETCONFIG) || (sig_id == AVDT_SIG_RECONFIG))
+ {
+ /* Cannot accept unknown category. */
+ err = AVDT_ERR_CATEGORY;
+ break;
+ }
+ else /* GETCAP or GET_ALLCAP */
+ {
+ /* Skip unknown categories. */
+ p += elem_len;
+ AVDT_TRACE_DEBUG2("skipping unknown service category=%d len: %d", elem, elem_len);
+ continue;
+ }
+ }
+
+ if ((elem_len > avdt_msg_ie_len_max[elem]) ||
+ (elem_len < avdt_msg_ie_len_min[elem]))
+ {
+ err = avdt_msg_ie_err[elem];
+ break;
+ }
+
+ /* add element to psc mask, but mask out codec or protect */
+ p_cfg->psc_mask |= (1 << elem);
+ AVDT_TRACE_DEBUG3("elem=%d elem_len: %d psc_mask=0x%x", elem, elem_len, p_cfg->psc_mask);
+
+ /* parse individual information elements with additional parameters */
+ switch (elem)
+ {
+ case AVDT_CAT_RECOV:
+ p_cfg->recov_type = *p++;
+ p_cfg->recov_mrws = *p++;
+ p_cfg->recov_mnmp = *p++;
+ if (p_cfg->recov_type != AVDT_RECOV_RFC2733)
+ {
+ err = AVDT_ERR_RECOV_TYPE;
+ }
+ else if ((p_cfg->recov_mrws < AVDT_RECOV_MRWS_MIN) ||
+ (p_cfg->recov_mrws > AVDT_RECOV_MRWS_MAX) ||
+ (p_cfg->recov_mnmp < AVDT_RECOV_MNMP_MIN) ||
+ (p_cfg->recov_mnmp > AVDT_RECOV_MNMP_MAX))
+ {
+ err = AVDT_ERR_RECOV_FMT;
+ }
+ break;
+
+ case AVDT_CAT_PROTECT:
+ p_cfg->psc_mask &= ~AVDT_PSC_PROTECT;
+ if ((elem_len + protect_offset) < AVDT_PROTECT_SIZE)
+ {
+ p_cfg->num_protect++;
+ p_cfg->protect_info[protect_offset] = elem_len;
+ protect_offset++;
+ memcpy(&p_cfg->protect_info[protect_offset], p, elem_len);
+ protect_offset += elem_len;
+ }
+ p += elem_len;
+ break;
+
+ case AVDT_CAT_HDRCMP:
+ p_cfg->hdrcmp_mask = *p++;
+ break;
+
+#if AVDT_MULTIPLEXING == TRUE
+ case AVDT_CAT_MUX:
+ /* verify length */
+ AVDT_TRACE_WARNING2("psc_mask=0x%x elem_len=%d", p_cfg->psc_mask, elem_len);
+ if( ((0 == (p_cfg->psc_mask & (AVDT_PSC_RECOV|AVDT_PSC_REPORT))) && (elem_len != 3))
+ || ((p_cfg->psc_mask & AVDT_PSC_RECOV) && (elem_len != 7))
+ || ((p_cfg->psc_mask & AVDT_PSC_REPORT) && (elem_len != 5)) )
+ {
+ err = AVDT_ERR_MUX_FMT;
+ break;
+ }
+
+ /* parse fragmentation */
+ p_cfg->mux_mask = *p++ & (UINT8)AVDT_MUX_FRAG;
+
+ /* parse TSIDs and TCIDs */
+ if(--elem_len)
+ p_cfg->mux_tsid_media = (*p++)>>3;
+ else
+ break;
+
+ if(--elem_len)
+ p_cfg->mux_tcid_media = (*p++)>>3;
+ else
+ break;
+
+ if(--elem_len)
+ p_cfg->mux_tsid_report = (*p++)>>3;
+ else
+ break;
+
+ if(--elem_len)
+ p_cfg->mux_tcid_report = (*p++)>>3;
+ else
+ break;
+
+ if(--elem_len)
+ p_cfg->mux_tsid_recov = (*p++)>>3;
+ else
+ break;
+
+ if(--elem_len)
+ p_cfg->mux_tcid_recov = (*p++)>>3;
+ else
+ break;
+ break;
+#endif
+
+ case AVDT_CAT_CODEC:
+ p_cfg->psc_mask &= ~AVDT_PSC_CODEC;
+ tmp = elem_len;
+ if (elem_len >= AVDT_CODEC_SIZE)
+ {
+ tmp = AVDT_CODEC_SIZE - 1;
+ }
+ p_cfg->num_codec++;
+ p_cfg->codec_info[0] = elem_len;
+ memcpy(&p_cfg->codec_info[1], p, tmp);
+ p += elem_len;
+ break;
+
+ case AVDT_CAT_DELAY_RPT:
+ break;
+
+ default:
+ p += elem_len;
+ break;
+ } /* switch */
+ } /* while ! err, !end*/
+ *p_elem = elem;
+ AVDT_TRACE_DEBUG3("err=0x%x, elem:0x%x psc_mask=0x%x", err, elem, p_cfg->psc_mask);
+
+ return err;
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_prs_none
+**
+** Description This message parsing function parses a message with no parameters.
+
+**
+**
+** Returns Error code or zero if no error.
+**
+*******************************************************************************/
+static UINT8 avdt_msg_prs_none(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len)
+{
+ return 0;
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_prs_single
+**
+** Description This message parsing function parses a message with a
+** single SEID.
+**
+**
+** Returns Error code or zero if no error.
+**
+*******************************************************************************/
+static UINT8 avdt_msg_prs_single(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len)
+{
+ UINT8 err = 0;
+
+ /* verify len */
+ if (len != AVDT_LEN_SINGLE)
+ {
+ err = AVDT_ERR_LENGTH;
+ }
+ else
+ {
+ AVDT_MSG_PRS_SEID(p, p_msg->single.seid);
+
+ if (avdt_scb_by_hdl(p_msg->single.seid) == NULL)
+ {
+ err = AVDT_ERR_SEID;
+ }
+ }
+ return err;
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_prs_setconfig_cmd
+**
+** Description This message parsing function parses a set configuration
+** command message.
+**
+**
+** Returns Error code or zero if no error.
+**
+*******************************************************************************/
+static UINT8 avdt_msg_prs_setconfig_cmd(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len)
+{
+ UINT8 err = 0;
+
+ p_msg->hdr.err_param = 0;
+
+ /* verify len */
+ if (len < AVDT_LEN_SETCONFIG_MIN)
+ {
+ err = AVDT_ERR_LENGTH;
+ }
+ else
+ {
+ /* get seids */
+ AVDT_MSG_PRS_SEID(p, p_msg->config_cmd.hdr.seid);
+ if (avdt_scb_by_hdl(p_msg->config_cmd.hdr.seid) == NULL)
+ {
+ err = AVDT_ERR_SEID;
+ }
+
+ AVDT_MSG_PRS_SEID(p, p_msg->config_cmd.int_seid);
+ if ((p_msg->config_cmd.int_seid < AVDT_SEID_MIN) ||
+ (p_msg->config_cmd.int_seid > AVDT_SEID_MAX))
+ {
+ err = AVDT_ERR_SEID;
+ }
+ }
+
+ if (!err)
+ {
+ /* parse configuration parameters */
+ len -= 2;
+ err = avdt_msg_prs_cfg(p_msg->config_cmd.p_cfg, p, len, &p_msg->hdr.err_param, AVDT_SIG_SETCONFIG);
+
+ if (!err)
+ {
+ /* verify protocol service capabilities are supported */
+ if (((p_msg->config_cmd.p_cfg->psc_mask & (~AVDT_PSC)) != 0) ||
+ (p_msg->config_cmd.p_cfg->num_codec == 0))
+ {
+ err = AVDT_ERR_INVALID_CAP;
+ }
+ }
+ }
+
+ return err;
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_prs_reconfig_cmd
+**
+** Description This message parsing function parses a reconfiguration
+** command message.
+**
+**
+** Returns Error code or zero if no error.
+**
+*******************************************************************************/
+static UINT8 avdt_msg_prs_reconfig_cmd(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len)
+{
+ UINT8 err = 0;
+
+ p_msg->hdr.err_param = 0;
+
+ /* verify len */
+ if (len < AVDT_LEN_RECONFIG_MIN)
+ {
+ err = AVDT_ERR_LENGTH;
+ }
+ else
+ {
+ /* get seid */
+ AVDT_MSG_PRS_SEID(p, p_msg->reconfig_cmd.hdr.seid);
+ if (avdt_scb_by_hdl(p_msg->reconfig_cmd.hdr.seid) == NULL)
+ {
+ err = AVDT_ERR_SEID;
+ }
+ else
+ {
+ /* parse config parameters */
+ len--;
+ err = avdt_msg_prs_cfg(p_msg->config_cmd.p_cfg, p, len, &p_msg->hdr.err_param, AVDT_SIG_RECONFIG);
+
+ /* verify no protocol service capabilities in parameters */
+ if (!err)
+ {
+ AVDT_TRACE_DEBUG2("avdt_msg_prs_reconfig_cmd psc_mask=0x%x/0x%x", p_msg->config_cmd.p_cfg->psc_mask, AVDT_MSG_PSC_MASK);
+ if ((p_msg->config_cmd.p_cfg->psc_mask != 0) ||
+ (p_msg->config_cmd.p_cfg->num_codec == 0 && p_msg->config_cmd.p_cfg->num_protect == 0))
+ {
+ err = AVDT_ERR_INVALID_CAP;
+ }
+ }
+ }
+ }
+ return err;
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_prs_multi
+**
+** Description This message parsing function parses a message containing
+** multiple SEID's.
+**
+**
+** Returns Error code or zero if no error.
+**
+*******************************************************************************/
+static UINT8 avdt_msg_prs_multi(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len)
+{
+ int i;
+ UINT8 err = 0;
+
+ p_msg->hdr.err_param = 0;
+
+ /* verify len */
+ if (len < AVDT_LEN_MULTI_MIN || (len > AVDT_NUM_SEPS))
+ {
+ err = AVDT_ERR_LENGTH;
+ }
+ else
+ {
+ /* get and verify all seps */
+ for (i = 0; i < len; i++)
+ {
+ AVDT_MSG_PRS_SEID(p, p_msg->multi.seid_list[i]);
+ if (avdt_scb_by_hdl(p_msg->multi.seid_list[i]) == NULL)
+ {
+ err = AVDT_ERR_SEID;
+ p_msg->hdr.err_param = p_msg->multi.seid_list[i];
+ break;
+ }
+ }
+ p_msg->multi.num_seps = (UINT8)i;
+ }
+
+ return err;
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_prs_security_cmd
+**
+** Description This message parsing function parses a security
+** command message.
+**
+**
+** Returns Error code or zero if no error.
+**
+*******************************************************************************/
+static UINT8 avdt_msg_prs_security_cmd(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len)
+{
+ UINT8 err = 0;
+
+ /* verify len */
+ if (len < AVDT_LEN_SECURITY_MIN)
+ {
+ err = AVDT_ERR_LENGTH;
+ }
+ else
+ {
+ /* get seid */
+ AVDT_MSG_PRS_SEID(p, p_msg->security_cmd.hdr.seid);
+ if (avdt_scb_by_hdl(p_msg->security_cmd.hdr.seid) == NULL)
+ {
+ err = AVDT_ERR_SEID;
+ }
+ else
+ {
+ p_msg->security_cmd.p_data = p;
+ p_msg->security_cmd.len = len - 1;
+ }
+ }
+ return err;
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_prs_discover_rsp
+**
+** Description This message parsing function parses a discover
+** response message.
+**
+**
+** Returns Error code or zero if no error.
+**
+*******************************************************************************/
+static UINT8 avdt_msg_prs_discover_rsp(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len)
+{
+ int i;
+ UINT8 err = 0;
+
+ /* determine number of seps; seps in msg is len/2, but set to minimum
+ ** of seps app has supplied memory for and seps in msg
+ */
+ if (p_msg->discover_rsp.num_seps > (len / 2))
+ {
+ p_msg->discover_rsp.num_seps = (len / 2);
+ }
+
+ /* parse out sep info */
+ for (i = 0; i < p_msg->discover_rsp.num_seps; i++)
+ {
+ /* parse discover rsp info */
+ AVDT_MSG_PRS_DISC(p, p_msg->discover_rsp.p_sep_info[i].seid,
+ p_msg->discover_rsp.p_sep_info[i].in_use,
+ p_msg->discover_rsp.p_sep_info[i].media_type,
+ p_msg->discover_rsp.p_sep_info[i].tsep);
+
+ /* verify that seid is valid */
+ if ((p_msg->discover_rsp.p_sep_info[i].seid < AVDT_SEID_MIN) ||
+ (p_msg->discover_rsp.p_sep_info[i].seid > AVDT_SEID_MAX))
+ {
+ err = AVDT_ERR_SEID;
+ break;
+ }
+ }
+
+ return err;
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_prs_svccap
+**
+** Description This message parsing function parses a message containing
+** service capabilities parameters.
+**
+**
+** Returns Error code or zero if no error.
+**
+*******************************************************************************/
+static UINT8 avdt_msg_prs_svccap(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len)
+{
+ /* parse parameters */
+ UINT8 err = avdt_msg_prs_cfg(p_msg->svccap.p_cfg, p, len, &p_msg->hdr.err_param, AVDT_SIG_GETCAP);
+ if (p_msg->svccap.p_cfg)
+ {
+ p_msg->svccap.p_cfg->psc_mask &= AVDT_LEG_PSC;
+ }
+
+ return (err);
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_prs_all_svccap
+**
+** Description This message parsing function parses a message containing
+** service capabilities parameters.
+**
+**
+** Returns Error code or zero if no error.
+**
+*******************************************************************************/
+static UINT8 avdt_msg_prs_all_svccap(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len)
+{
+ UINT8 err = avdt_msg_prs_cfg(p_msg->svccap.p_cfg, p, len, &p_msg->hdr.err_param, AVDT_SIG_GET_ALLCAP);
+ if (p_msg->svccap.p_cfg)
+ {
+ p_msg->svccap.p_cfg->psc_mask &= AVDT_MSG_PSC_MASK;
+ }
+ return (err);
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_prs_security_rsp
+**
+** Description This message parsing function parsing a security
+** response message.
+**
+**
+** Returns Error code or zero if no error.
+**
+*******************************************************************************/
+static UINT8 avdt_msg_prs_security_rsp(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len)
+{
+ p_msg->security_rsp.p_data = p;
+ p_msg->security_rsp.len = len;
+
+ return 0;
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_prs_rej
+**
+** Description
+**
+**
+** Returns Error code or zero if no error.
+**
+*******************************************************************************/
+static UINT8 avdt_msg_prs_rej(tAVDT_MSG *p_msg, UINT8 *p, UINT8 sig)
+{
+ if ((sig == AVDT_SIG_SETCONFIG) || (sig == AVDT_SIG_RECONFIG))
+ {
+ p_msg->hdr.err_param = *p++;
+ p_msg->hdr.err_code = *p;
+ }
+ else if ((sig == AVDT_SIG_START) || (sig == AVDT_SIG_SUSPEND))
+ {
+ AVDT_MSG_PRS_SEID(p, p_msg->hdr.err_param);
+ p_msg->hdr.err_code = *p;
+ }
+ else
+ {
+ p_msg->hdr.err_code = *p;
+ }
+
+ return 0;
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_prs_delay_rpt
+**
+** Description This message parsing function parses a security
+** command message.
+**
+**
+** Returns Error code or zero if no error.
+**
+*******************************************************************************/
+static UINT8 avdt_msg_prs_delay_rpt (tAVDT_MSG *p_msg, UINT8 *p, UINT16 len)
+{
+ UINT8 err = 0;
+
+ /* verify len */
+ if (len != AVDT_LEN_DELAY_RPT)
+ {
+ AVDT_TRACE_WARNING2("avdt_msg_prs_delay_rpt expected len: %u got: %u", AVDT_LEN_DELAY_RPT, len);
+ err = AVDT_ERR_LENGTH;
+ }
+ else
+ {
+ /* get seid */
+ AVDT_MSG_PRS_SEID (p, p_msg->delay_rpt_cmd.hdr.seid);
+
+ if (avdt_scb_by_hdl(p_msg->delay_rpt_cmd.hdr.seid) == NULL)
+ {
+ err = AVDT_ERR_SEID;
+ }
+ else
+ {
+ BE_STREAM_TO_UINT16 (p_msg->delay_rpt_cmd.delay, p);
+ AVDT_TRACE_DEBUG1("avdt_msg_prs_delay_rpt delay: %u", p_msg->delay_rpt_cmd.delay);
+ }
+ }
+ return err;
+}
+
+
+/*******************************************************************************
+**
+** Function avdt_msg_send
+**
+** Description Send, and if necessary fragment the next message.
+**
+**
+** Returns Congested state; TRUE if CCB congested, FALSE if not.
+**
+*******************************************************************************/
+BOOLEAN avdt_msg_send(tAVDT_CCB *p_ccb, BT_HDR *p_msg)
+{
+ UINT16 curr_msg_len;
+ UINT8 pkt_type;
+ UINT8 hdr_len;
+ tAVDT_TC_TBL *p_tbl;
+ BT_HDR *p_buf;
+ UINT8 *p;
+ UINT8 label;
+ UINT8 msg;
+ UINT8 sig;
+ UINT8 nosp = 0; /* number of subsequent packets */
+
+ /* look up transport channel table entry to get peer mtu */
+ p_tbl = avdt_ad_tc_tbl_by_type(AVDT_CHAN_SIG, p_ccb, NULL);
+
+ /* set the current message if there is a message passed in */
+ if (p_msg != NULL)
+ {
+ p_ccb->p_curr_msg = p_msg;
+ }
+
+ /* store copy of curr_msg->len */
+ curr_msg_len = p_ccb->p_curr_msg->len;
+
+ /* while not congested and we haven't sent it all */
+ while ((!p_ccb->cong) && (p_ccb->p_curr_msg != NULL))
+ {
+ /* check what kind of message we've got here; we are using the offset
+ ** to indicate that a message is being fragmented
+ */
+
+ /* if message isn't being fragmented and it fits in mtu */
+ if ((p_ccb->p_curr_msg->offset == AVDT_MSG_OFFSET) &&
+ (p_ccb->p_curr_msg->len <= p_tbl->peer_mtu - AVDT_LEN_TYPE_SINGLE))
+ {
+ pkt_type = AVDT_PKT_TYPE_SINGLE;
+ hdr_len = AVDT_LEN_TYPE_SINGLE;
+ p_buf = p_ccb->p_curr_msg;
+ }
+ /* if message isn't being fragmented and it doesn't fit in mtu */
+ else if ((p_ccb->p_curr_msg->offset == AVDT_MSG_OFFSET) &&
+ (p_ccb->p_curr_msg->len > p_tbl->peer_mtu - AVDT_LEN_TYPE_SINGLE))
+ {
+ pkt_type = AVDT_PKT_TYPE_START;
+ hdr_len = AVDT_LEN_TYPE_START;
+ nosp = (p_ccb->p_curr_msg->len + AVDT_LEN_TYPE_START - p_tbl->peer_mtu) /
+ (p_tbl->peer_mtu - 1) + 2;
+
+ /* get a new buffer for fragment we are sending */
+ if ((p_buf = (BT_HDR *) GKI_getpoolbuf(AVDT_CMD_POOL_ID)) == NULL)
+ {
+ /* do we even want to try and recover from this? could do so
+ by setting retransmission timer */
+ return TRUE;
+ }
+
+ /* copy portion of data from current message to new buffer */
+ p_buf->offset = L2CAP_MIN_OFFSET + hdr_len;
+ p_buf->len = p_tbl->peer_mtu - hdr_len;
+ memcpy((UINT8 *)(p_buf + 1) + p_buf->offset,
+ (UINT8 *)(p_ccb->p_curr_msg + 1) + p_ccb->p_curr_msg->offset, p_buf->len);
+ }
+ /* if message is being fragmented and remaining bytes don't fit in mtu */
+ else if ((p_ccb->p_curr_msg->offset > AVDT_MSG_OFFSET) &&
+ (p_ccb->p_curr_msg->len > (p_tbl->peer_mtu - AVDT_LEN_TYPE_CONT)))
+ {
+ pkt_type = AVDT_PKT_TYPE_CONT;
+ hdr_len = AVDT_LEN_TYPE_CONT;
+
+ /* get a new buffer for fragment we are sending */
+ if ((p_buf = (BT_HDR *) GKI_getpoolbuf(AVDT_CMD_POOL_ID)) == NULL)
+ {
+ /* do we even want to try and recover from this? could do so
+ by setting retransmission timer */
+ return TRUE;
+ }
+
+ /* copy portion of data from current message to new buffer */
+ p_buf->offset = L2CAP_MIN_OFFSET + hdr_len;
+ p_buf->len = p_tbl->peer_mtu - hdr_len;
+ memcpy((UINT8 *)(p_buf + 1) + p_buf->offset,
+ (UINT8 *)(p_ccb->p_curr_msg + 1) + p_ccb->p_curr_msg->offset, p_buf->len);
+ }
+ /* if message is being fragmented and remaining bytes do fit in mtu */
+ else
+ {
+ pkt_type = AVDT_PKT_TYPE_END;
+ hdr_len = AVDT_LEN_TYPE_END;
+ p_buf = p_ccb->p_curr_msg;
+ }
+
+ /* label, sig id, msg type are in hdr of p_curr_msg */
+ label = AVDT_LAYERSPEC_LABEL(p_ccb->p_curr_msg->layer_specific);
+ msg = AVDT_LAYERSPEC_MSG(p_ccb->p_curr_msg->layer_specific);
+ sig = (UINT8) p_ccb->p_curr_msg->event;
+ AVDT_TRACE_DEBUG3("avdt_msg_send label:%d, msg:%d, sig:%d", label, msg, sig);
+
+ /* keep track of how much of msg we've sent */
+ curr_msg_len -= p_buf->len;
+ if (curr_msg_len == 0)
+ {
+ /* entire message sent; mark as finished */
+ p_ccb->p_curr_msg = NULL;
+
+ /* start timer here for commands */
+ if (msg == AVDT_MSG_TYPE_CMD)
+ {
+ /* if retransmit timeout set to zero, sig doesn't use retransmit */
+ if ((sig == AVDT_SIG_DISCOVER) || (sig == AVDT_SIG_GETCAP) ||
+ (sig == AVDT_SIG_SECURITY) || (avdt_cb.rcb.ret_tout == 0))
+ {
+ btu_start_timer(&p_ccb->timer_entry, BTU_TTYPE_AVDT_CCB_RSP, avdt_cb.rcb.sig_tout);
+ }
+ else if (sig != AVDT_SIG_DELAY_RPT)
+ {
+ btu_start_timer(&p_ccb->timer_entry, BTU_TTYPE_AVDT_CCB_RET, avdt_cb.rcb.ret_tout);
+ }
+ }
+ }
+ else
+ {
+ /* message being fragmented and not completely sent */
+ p_ccb->p_curr_msg->len -= p_buf->len;
+ p_ccb->p_curr_msg->offset += p_buf->len;
+ }
+
+ /* set up to build header */
+ p_buf->len += hdr_len;
+ p_buf->offset -= hdr_len;
+ p = (UINT8 *)(p_buf + 1) + p_buf->offset;
+
+ /* build header */
+ AVDT_MSG_BLD_HDR(p, label, pkt_type, msg);
+ if (pkt_type == AVDT_PKT_TYPE_START)
+ {
+ AVDT_MSG_BLD_NOSP(p, nosp);
+ }
+ if ((pkt_type == AVDT_PKT_TYPE_START) || (pkt_type == AVDT_PKT_TYPE_SINGLE))
+ {
+ AVDT_MSG_BLD_SIG(p, sig);
+ }
+
+ /* send msg buffer down */
+ avdt_ad_write_req(AVDT_CHAN_SIG, p_ccb, NULL, p_buf);
+ }
+ return (p_ccb->cong);
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_asmbl
+**
+** Description Reassemble incoming message.
+**
+**
+** Returns Pointer to reassembled message; NULL if no message
+** available.
+**
+*******************************************************************************/
+BT_HDR *avdt_msg_asmbl(tAVDT_CCB *p_ccb, BT_HDR *p_buf)
+{
+ UINT8 *p;
+ UINT8 pkt_type;
+ BT_HDR *p_ret;
+ UINT16 buf_len;
+
+ /* parse the message header */
+ p = (UINT8 *)(p_buf + 1) + p_buf->offset;
+ AVDT_MSG_PRS_PKT_TYPE(p, pkt_type);
+
+ /* quick sanity check on length */
+ if (p_buf->len < avdt_msg_pkt_type_len[pkt_type])
+ {
+ GKI_freebuf(p_buf);
+ AVDT_TRACE_WARNING0("Bad length during reassembly");
+ p_ret = NULL;
+ }
+ /* single packet */
+ else if (pkt_type == AVDT_PKT_TYPE_SINGLE)
+ {
+ /* if reassembly in progress drop message and process new single */
+ if (p_ccb->p_rx_msg != NULL)
+ {
+ GKI_freebuf(p_ccb->p_rx_msg);
+ p_ccb->p_rx_msg = NULL;
+ AVDT_TRACE_WARNING0("Got single during reassembly");
+ }
+ p_ret = p_buf;
+ }
+ /* start packet */
+ else if (pkt_type == AVDT_PKT_TYPE_START)
+ {
+ /* if reassembly in progress drop message and process new single */
+ if (p_ccb->p_rx_msg != NULL)
+ {
+ GKI_freebuf(p_ccb->p_rx_msg);
+ AVDT_TRACE_WARNING0("Got start during reassembly");
+ }
+ p_ccb->p_rx_msg = p_buf;
+
+ /* copy first header byte over nosp */
+ *(p + 1) = *p;
+
+ /* set offset to point to where to copy next */
+ p_ccb->p_rx_msg->offset += p_ccb->p_rx_msg->len;
+
+ /* adjust length for packet header */
+ p_ccb->p_rx_msg->len -= 1;
+
+ p_ret = NULL;
+ }
+ /* continue or end */
+ else
+ {
+ /* if no reassembly in progress drop message */
+ if (p_ccb->p_rx_msg == NULL)
+ {
+ GKI_freebuf(p_buf);
+ AVDT_TRACE_WARNING1("Pkt type=%d out of order", pkt_type);
+ p_ret = NULL;
+ }
+ else
+ {
+ /* get size of buffer holding assembled message */
+ buf_len = GKI_get_buf_size(p_ccb->p_rx_msg) - sizeof(BT_HDR);
+
+ /* adjust offset and len of fragment for header byte */
+ p_buf->offset += AVDT_LEN_TYPE_CONT;
+ p_buf->len -= AVDT_LEN_TYPE_CONT;
+
+ /* verify length */
+ if ((p_ccb->p_rx_msg->offset + p_buf->len) > buf_len)
+ {
+ /* won't fit; free everything */
+ GKI_freebuf(p_ccb->p_rx_msg);
+ p_ccb->p_rx_msg = NULL;
+ GKI_freebuf(p_buf);
+ p_ret = NULL;
+ }
+ else
+ {
+ /* copy contents of p_buf to p_rx_msg */
+ memcpy((UINT8 *)(p_ccb->p_rx_msg + 1) + p_ccb->p_rx_msg->offset,
+ (UINT8 *)(p_buf + 1) + p_buf->offset, p_buf->len);
+
+ if (pkt_type == AVDT_PKT_TYPE_END)
+ {
+ p_ccb->p_rx_msg->offset -= p_ccb->p_rx_msg->len;
+ p_ccb->p_rx_msg->len += p_buf->len;
+ p_ret = p_ccb->p_rx_msg;
+ p_ccb->p_rx_msg = NULL;
+ }
+ else
+ {
+ p_ccb->p_rx_msg->offset += p_buf->len;
+ p_ccb->p_rx_msg->len += p_buf->len;
+ p_ret = NULL;
+ }
+ GKI_freebuf(p_buf);
+ }
+ }
+ }
+ return p_ret;
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_send_cmd
+**
+** Description This function is called to send a command message. The
+** sig_id parameter indicates the message type, p_params
+** points to the message parameters, if any. It gets a buffer
+** from the AVDTP command pool, executes the message building
+** function for this message type. It then queues the message
+** in the command queue for this CCB.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_msg_send_cmd(tAVDT_CCB *p_ccb, void *p_scb, UINT8 sig_id, tAVDT_MSG *p_params)
+{
+ BT_HDR *p_buf;
+ UINT8 *p;
+ UINT8 *p_start;
+
+ /* get a buffer */
+ p_buf = (BT_HDR *) GKI_getpoolbuf(AVDT_CMD_POOL_ID);
+ if (p_buf == NULL)
+ {
+ AVDT_TRACE_ERROR0("avdt_msg_send_cmd out of buffer!!");
+ return;
+ }
+
+ /* set up gki buf pointer and offset */
+ p_buf->offset = AVDT_MSG_OFFSET;
+ p_start = p = (UINT8 *)(p_buf + 1) + p_buf->offset;
+
+ /* execute parameter building function to build message */
+ (*avdt_msg_bld_cmd[sig_id - 1])(&p, p_params);
+
+ /* set len */
+ p_buf->len = (UINT16) (p - p_start);
+
+ /* now store scb hdls, if any, in buf */
+ if (p_scb != NULL)
+ {
+ p = (UINT8 *)(p_buf + 1);
+
+ /* for start and suspend, p_scb points to array of handles */
+ if ((sig_id == AVDT_SIG_START) || (sig_id == AVDT_SIG_SUSPEND))
+ {
+ memcpy(p, (UINT8 *) p_scb, p_buf->len);
+ }
+ /* for all others, p_scb points to scb as usual */
+ else
+ {
+ *p = avdt_scb_to_hdl((tAVDT_SCB *) p_scb);
+ }
+ }
+
+ /* stash sig, label, and message type in buf */
+ p_buf->event = sig_id;
+ AVDT_BLD_LAYERSPEC(p_buf->layer_specific, AVDT_MSG_TYPE_CMD, p_ccb->label);
+
+ /* increment label */
+ p_ccb->label = (p_ccb->label + 1) % 16;
+
+ /* queue message and trigger ccb to send it */
+ GKI_enqueue(&p_ccb->cmd_q, p_buf);
+ avdt_ccb_event(p_ccb, AVDT_CCB_SENDMSG_EVT, NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function avdt_msg_send_rsp
+**
+** Description This function is called to send a response message. The
+** sig_id parameter indicates the message type, p_params
+** points to the message parameters, if any. It gets a buffer
+** from the AVDTP command pool, executes the message building
+** function for this message type. It then queues the message
+** in the response queue for this CCB.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_msg_send_rsp(tAVDT_CCB *p_ccb, UINT8 sig_id, tAVDT_MSG *p_params)
+{
+ BT_HDR *p_buf;
+ UINT8 *p;
+ UINT8 *p_start;
+
+ /* get a buffer */
+ p_buf = (BT_HDR *) GKI_getpoolbuf(AVDT_CMD_POOL_ID);
+ if (p_buf == NULL) return;
+
+ /* set up gki buf pointer and offset */
+ p_buf->offset = AVDT_MSG_OFFSET;
+ p_start = p = (UINT8 *)(p_buf + 1) + p_buf->offset;
+
+ /* execute parameter building function to build message */
+ (*avdt_msg_bld_rsp[sig_id - 1])(&p, p_params);
+
+ /* set length */
+ p_buf->len = (UINT16) (p - p_start);
+
+ /* stash sig, label, and message type in buf */
+ p_buf->event = sig_id;
+ AVDT_BLD_LAYERSPEC(p_buf->layer_specific, AVDT_MSG_TYPE_RSP, p_params->hdr.label);
+
+ /* queue message and trigger ccb to send it */
+ GKI_enqueue(&p_ccb->rsp_q, p_buf);
+ avdt_ccb_event(p_ccb, AVDT_CCB_SENDMSG_EVT, NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function avdt_msg_send_rej
+**
+** Description This function is called to send a reject message. The
+** sig_id parameter indicates the message type. It gets
+** a buffer from the AVDTP command pool and builds the
+** message based on the message type and the error code.
+** It then queues the message in the response queue for
+** this CCB.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_msg_send_rej(tAVDT_CCB *p_ccb, UINT8 sig_id, tAVDT_MSG *p_params)
+{
+ BT_HDR *p_buf;
+ UINT8 *p;
+ UINT8 *p_start;
+
+ /* get a buffer */
+ p_buf = (BT_HDR *) GKI_getpoolbuf(AVDT_CMD_POOL_ID);
+ if (p_buf == NULL) return;
+
+ /* set up gki buf pointer and offset */
+ p_buf->offset = AVDT_MSG_OFFSET;
+ p_start = p = (UINT8 *)(p_buf + 1) + p_buf->offset;
+
+ /* if sig id included, build into message */
+ if (sig_id != AVDT_SIG_NONE)
+ {
+ /* if this sig has a parameter, add the parameter */
+ if ((sig_id == AVDT_SIG_SETCONFIG) ||
+ (sig_id == AVDT_SIG_RECONFIG))
+ {
+ AVDT_MSG_BLD_PARAM(p, p_params->hdr.err_param);
+ }
+ else if ((sig_id == AVDT_SIG_START) ||
+ (sig_id == AVDT_SIG_SUSPEND))
+ {
+ AVDT_MSG_BLD_SEID(p, p_params->hdr.err_param);
+ }
+
+ /* add the error code */
+ AVDT_MSG_BLD_ERR(p, p_params->hdr.err_code);
+ }
+ AVDT_TRACE_DEBUG0("avdt_msg_send_rej");
+
+ /* calculate length */
+ p_buf->len = (UINT16) (p - p_start);
+
+ /* stash sig, label, and message type in buf */
+ p_buf->event = sig_id;
+ AVDT_BLD_LAYERSPEC(p_buf->layer_specific, AVDT_MSG_TYPE_REJ, p_params->hdr.label);
+
+ /* queue message and trigger ccb to send it */
+ GKI_enqueue(&p_ccb->rsp_q, p_buf);
+ avdt_ccb_event(p_ccb, AVDT_CCB_SENDMSG_EVT, NULL);
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_send_grej
+**
+** Description This function is called to send a general reject message. The
+** sig_id parameter indicates the message type. It gets
+** a buffer from the AVDTP command pool and builds the
+** message based on the message type and the error code.
+** It then queues the message in the response queue for
+** this CCB.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_msg_send_grej(tAVDT_CCB *p_ccb, UINT8 sig_id, tAVDT_MSG *p_params)
+{
+ BT_HDR *p_buf;
+ UINT8 *p;
+ UINT8 *p_start;
+
+ /* get a buffer */
+ p_buf = (BT_HDR *) GKI_getpoolbuf(AVDT_CMD_POOL_ID);
+ if (p_buf == NULL) return;
+
+ /* set up gki buf pointer and offset */
+ p_buf->offset = AVDT_MSG_OFFSET;
+ p_start = p = (UINT8 *)(p_buf + 1) + p_buf->offset;
+
+ /* calculate length */
+ p_buf->len = (UINT16) (p - p_start);
+
+ /* stash sig, label, and message type in buf */
+ p_buf->event = sig_id;
+ AVDT_BLD_LAYERSPEC(p_buf->layer_specific, AVDT_MSG_TYPE_GRJ, p_params->hdr.label);
+ //p_buf->event = 0;
+ //AVDT_BLD_LAYERSPEC(p_buf->layer_specific, 0, p_params->hdr.label);
+ AVDT_TRACE_DEBUG0("avdt_msg_send_grej");
+
+ /* queue message and trigger ccb to send it */
+ GKI_enqueue(&p_ccb->rsp_q, p_buf);
+ avdt_ccb_event(p_ccb, AVDT_CCB_SENDMSG_EVT, NULL);
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_ind
+**
+** Description This function is called by the adaption layer when an
+** incoming message is received on the signaling channel.
+** It parses the message and sends an event to the appropriate
+** SCB or CCB for the message.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_msg_ind(tAVDT_CCB *p_ccb, BT_HDR *p_buf)
+{
+ tAVDT_SCB *p_scb;
+ UINT8 *p;
+ BOOLEAN ok = TRUE;
+ BOOLEAN handle_rsp = FALSE;
+ BOOLEAN gen_rej = FALSE;
+ UINT8 label;
+ UINT8 pkt_type;
+ UINT8 msg_type;
+ UINT8 sig = 0;
+ tAVDT_MSG msg;
+ tAVDT_CFG cfg;
+ UINT8 err;
+ UINT8 evt = 0;
+ UINT8 scb_hdl;
+
+ /* reassemble message; if no message available (we received a fragment) return */
+ if ((p_buf = avdt_msg_asmbl(p_ccb, p_buf)) == NULL)
+ {
+ return;
+ }
+
+ p = (UINT8 *)(p_buf + 1) + p_buf->offset;
+
+ /* parse the message header */
+ AVDT_MSG_PRS_HDR(p, label, pkt_type, msg_type);
+
+ /* AVDT_TRACE_DEBUG1("msg_type=%d", msg_type); */
+ /* set up label and ccb_idx in message hdr */
+ msg.hdr.label = label;
+ msg.hdr.ccb_idx = avdt_ccb_to_idx(p_ccb);
+
+ /* verify msg type */
+ if (msg_type == AVDT_MSG_TYPE_GRJ)
+ {
+ AVDT_TRACE_WARNING1("Dropping msg msg_type=%d", msg_type);
+ ok = FALSE;
+ }
+ /* check for general reject */
+ else if ((msg_type == AVDT_MSG_TYPE_REJ) && (p_buf->len == AVDT_LEN_GEN_REJ))
+ {
+ gen_rej = TRUE;
+ if (p_ccb->p_curr_cmd != NULL)
+ {
+ msg.hdr.sig_id = sig = (UINT8) p_ccb->p_curr_cmd->event;
+ evt = avdt_msg_rej_2_evt[sig - 1];
+ msg.hdr.err_code = AVDT_ERR_NSC;
+ msg.hdr.err_param = 0;
+ }
+ }
+ else /* not a general reject */
+ {
+ /* get and verify signal */
+ AVDT_MSG_PRS_SIG(p, sig);
+ msg.hdr.sig_id = sig;
+ if ((sig == 0) || (sig > AVDT_SIG_MAX))
+ {
+ AVDT_TRACE_WARNING2("Dropping msg sig=%d msg_type:%d", sig, msg_type);
+ ok = FALSE;
+
+ /* send a general reject */
+ if (msg_type == AVDT_MSG_TYPE_CMD)
+ {
+ avdt_msg_send_grej(p_ccb, sig, &msg);
+ }
+ }
+ }
+
+ if (ok && !gen_rej)
+ {
+ /* skip over header (msg length already verified during reassembly) */
+ p_buf->len -= AVDT_LEN_TYPE_SINGLE;
+
+ /* set up to parse message */
+ if ((msg_type == AVDT_MSG_TYPE_RSP) && (sig == AVDT_SIG_DISCOVER))
+ {
+ /* parse discover rsp message to struct supplied by app */
+ msg.discover_rsp.p_sep_info = (tAVDT_SEP_INFO *) p_ccb->p_proc_data;
+ msg.discover_rsp.num_seps = p_ccb->proc_param;
+ }
+ else if ((msg_type == AVDT_MSG_TYPE_RSP) &&
+ ((sig == AVDT_SIG_GETCAP) || (sig == AVDT_SIG_GET_ALLCAP)))
+ {
+ /* parse discover rsp message to struct supplied by app */
+ msg.svccap.p_cfg = (tAVDT_CFG *) p_ccb->p_proc_data;
+ }
+ else if ((msg_type == AVDT_MSG_TYPE_RSP) && (sig == AVDT_SIG_GETCONFIG))
+ {
+ /* parse get config rsp message to struct allocated locally */
+ msg.svccap.p_cfg = &cfg;
+ }
+ else if ((msg_type == AVDT_MSG_TYPE_CMD) && (sig == AVDT_SIG_SETCONFIG))
+ {
+ /* parse config cmd message to struct allocated locally */
+ msg.config_cmd.p_cfg = &cfg;
+ }
+ else if ((msg_type == AVDT_MSG_TYPE_CMD) && (sig == AVDT_SIG_RECONFIG))
+ {
+ /* parse reconfig cmd message to struct allocated locally */
+ msg.reconfig_cmd.p_cfg = &cfg;
+ }
+
+ /* parse message; while we're at it map message sig to event */
+ if (msg_type == AVDT_MSG_TYPE_CMD)
+ {
+ msg.hdr.err_code = err = (*avdt_msg_prs_cmd[sig - 1])(&msg, p, p_buf->len);
+ evt = avdt_msg_cmd_2_evt[sig - 1];
+ }
+ else if (msg_type == AVDT_MSG_TYPE_RSP)
+ {
+ msg.hdr.err_code = err = (*avdt_msg_prs_rsp[sig - 1])(&msg, p, p_buf->len);
+ evt = avdt_msg_rsp_2_evt[sig - 1];
+ }
+ else /* msg_type == AVDT_MSG_TYPE_REJ */
+ {
+ err = avdt_msg_prs_rej(&msg, p, sig);
+ evt = avdt_msg_rej_2_evt[sig - 1];
+ }
+
+ /* if parsing failed */
+ if (err != 0)
+ {
+ AVDT_TRACE_WARNING2("Parsing failed sig=%d err=0x%x", sig, err);
+
+ /* if its a rsp or rej, drop it; if its a cmd, send a rej;
+ ** note special case for abort; never send abort reject
+ */
+ ok = FALSE;
+ if ((msg_type == AVDT_MSG_TYPE_CMD) && (sig != AVDT_SIG_ABORT))
+ {
+ avdt_msg_send_rej(p_ccb, sig, &msg);
+ }
+ }
+ }
+
+ /* if its a rsp or rej, check sent cmd to see if we're waiting for
+ ** the rsp or rej. If we didn't send a cmd for it, drop it. If
+ ** it does match a cmd, stop timer for the cmd.
+ */
+ if (ok)
+ {
+ if ((msg_type == AVDT_MSG_TYPE_RSP) || (msg_type == AVDT_MSG_TYPE_REJ))
+ {
+ if ((p_ccb->p_curr_cmd != NULL) &&
+ (p_ccb->p_curr_cmd->event == sig) &&
+ (AVDT_LAYERSPEC_LABEL(p_ccb->p_curr_cmd->layer_specific) == label))
+ {
+ /* stop timer */
+ btu_stop_timer(&p_ccb->timer_entry);
+
+ /* clear retransmission count */
+ p_ccb->ret_count = 0;
+
+ /* later in this function handle ccb event */
+ handle_rsp = TRUE;
+ }
+ else
+ {
+ ok = FALSE;
+ AVDT_TRACE_WARNING2("Cmd not found for rsp sig=%d label=%d", sig, label);
+ }
+ }
+ }
+
+ if (ok)
+ {
+ /* if it's a ccb event send to ccb */
+ if (evt & AVDT_CCB_MKR)
+ {
+ avdt_ccb_event(p_ccb, (UINT8)(evt & ~AVDT_CCB_MKR), (tAVDT_CCB_EVT *) &msg);
+ }
+ /* if it's a scb event */
+ else
+ {
+ /* Scb events always have a single seid. For cmd, get seid from
+ ** message. For rej and rsp, get seid from p_curr_cmd.
+ */
+ if (msg_type == AVDT_MSG_TYPE_CMD)
+ {
+ scb_hdl = msg.single.seid;
+ }
+ else
+ {
+ scb_hdl = *((UINT8 *)(p_ccb->p_curr_cmd + 1));
+ }
+
+ /* Map seid to the scb and send it the event. For cmd, seid has
+ ** already been verified by parsing function.
+ */
+ if (evt && (p_scb = avdt_scb_by_hdl(scb_hdl)) != NULL)
+ {
+ avdt_scb_event(p_scb, evt, (tAVDT_SCB_EVT *) &msg);
+ }
+ }
+ }
+
+ /* free message buffer */
+ GKI_freebuf(p_buf);
+
+ /* if its a rsp or rej, send event to ccb to free associated
+ ** cmd msg buffer and handle cmd queue
+ */
+ if (handle_rsp)
+ {
+ avdt_ccb_event(p_ccb, AVDT_CCB_RCVRSP_EVT, NULL);
+ }
+}
diff --git a/stack/avdt/avdt_scb.c b/stack/avdt/avdt_scb.c
new file mode 100644
index 0000000..346d1ad
--- /dev/null
+++ b/stack/avdt/avdt_scb.c
@@ -0,0 +1,787 @@
+/*****************************************************************************
+**
+** Name: avdt_scb.c
+**
+** Description: This module contains the stream control block and
+** functions which operate on the stream control block.
+**
+** Copyright (c) 2002-2008, Broadcom Corp., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include <string.h>
+#include "data_types.h"
+#include "bt_target.h"
+#include "avdt_api.h"
+#include "avdtc_api.h"
+#include "avdt_int.h"
+#include "gki.h"
+#include "btu.h"
+
+/*****************************************************************************
+** state machine constants and types
+*****************************************************************************/
+#if AVDT_DEBUG == TRUE
+
+/* verbose state strings for trace */
+const char * const avdt_scb_st_str[] = {
+ "SCB_IDLE_ST",
+ "SCB_CONF_ST",
+ "SCB_OPENING_ST",
+ "SCB_OPEN_ST",
+ "SCB_STREAM_ST",
+ "SCB_CLOSING_ST"
+};
+
+/* verbose event strings for trace */
+const char * const avdt_scb_evt_str[] = {
+ "API_REMOVE_EVT",
+ "API_WRITE_REQ_EVT",
+ "API_GETCONFIG_REQ_EVT",
+ "API_DELAY_RPT_REQ",
+ "API_SETCONFIG_REQ_EVT",
+ "API_OPEN_REQ_EVT",
+ "API_CLOSE_REQ_EVT",
+ "API_RECONFIG_REQ_EVT",
+ "API_SECURITY_REQ_EVT",
+ "API_ABORT_REQ_EVT",
+ "API_GETCONFIG_RSP_EVT",
+ "API_SETCONFIG_RSP_EVT",
+ "API_SETCONFIG_REJ_EVT",
+ "API_OPEN_RSP_EVT",
+ "API_CLOSE_RSP_EVT",
+ "API_RECONFIG_RSP_EVT",
+ "API_SECURITY_RSP_EVT",
+ "API_ABORT_RSP_EVT",
+ "MSG_SETCONFIG_CMD_EVT",
+ "MSG_GETCONFIG_CMD_EVT",
+ "MSG_OPEN_CMD_EVT",
+ "MSG_START_CMD_EVT",
+ "MSG_SUSPEND_CMD_EVT",
+ "MSG_CLOSE_CMD_EVT",
+ "MSG_ABORT_CMD_EVT",
+ "MSG_RECONFIG_CMD_EVT",
+ "MSG_SECURITY_CMD_EVT",
+ "MSG_DELAY_RPT_CMD_EVT",
+ "MSG_DELAY_RPT_RSP_EVT",
+ "MSG_SETCONFIG_RSP_EVT",
+ "MSG_GETCONFIG_RSP_EVT",
+ "MSG_OPEN_RSP_EVT",
+ "MSG_START_RSP_EVT",
+ "MSG_SUSPEND_RSP_EVT",
+ "MSG_CLOSE_RSP_EVT",
+ "MSG_ABORT_RSP_EVT",
+ "MSG_RECONFIG_RSP_EVT",
+ "MSG_SECURITY_RSP_EVT",
+ "MSG_SETCONFIG_REJ_EVT",
+ "MSG_OPEN_REJ_EVT",
+ "MSG_START_REJ_EVT",
+ "MSG_SUSPEND_REJ_EVT",
+ "TC_TOUT_EVT",
+ "TC_OPEN_EVT",
+ "TC_CLOSE_EVT",
+ "TC_CONG_EVT",
+ "TC_DATA_EVT",
+ "CC_CLOSE_EVT"
+};
+
+#endif
+
+
+/* action function list */
+const tAVDT_SCB_ACTION avdt_scb_action[] = {
+ avdt_scb_hdl_abort_cmd,
+ avdt_scb_hdl_abort_rsp,
+ avdt_scb_hdl_close_cmd,
+ avdt_scb_hdl_close_rsp,
+ avdt_scb_hdl_getconfig_cmd,
+ avdt_scb_hdl_getconfig_rsp,
+ avdt_scb_hdl_open_cmd,
+ avdt_scb_hdl_open_rej,
+ avdt_scb_hdl_open_rsp,
+ avdt_scb_hdl_pkt,
+ avdt_scb_drop_pkt,
+ avdt_scb_hdl_reconfig_cmd,
+ avdt_scb_hdl_reconfig_rsp,
+ avdt_scb_hdl_security_cmd,
+ avdt_scb_hdl_security_rsp,
+ avdt_scb_hdl_setconfig_cmd,
+ avdt_scb_hdl_setconfig_rej,
+ avdt_scb_hdl_setconfig_rsp,
+ avdt_scb_hdl_start_cmd,
+ avdt_scb_hdl_start_rsp,
+ avdt_scb_hdl_suspend_cmd,
+ avdt_scb_hdl_suspend_rsp,
+ avdt_scb_hdl_tc_close,
+#if AVDT_REPORTING == TRUE
+ avdt_scb_hdl_tc_close_sto,
+#endif
+ avdt_scb_hdl_tc_open,
+#if AVDT_REPORTING == TRUE
+ avdt_scb_hdl_tc_open_sto,
+#endif
+ avdt_scb_snd_delay_rpt_req,
+ avdt_scb_hdl_delay_rpt_cmd,
+ avdt_scb_hdl_delay_rpt_rsp,
+ avdt_scb_hdl_write_req,
+ avdt_scb_snd_abort_req,
+ avdt_scb_snd_abort_rsp,
+ avdt_scb_snd_close_req,
+ avdt_scb_snd_stream_close,
+ avdt_scb_snd_close_rsp,
+ avdt_scb_snd_getconfig_req,
+ avdt_scb_snd_getconfig_rsp,
+ avdt_scb_snd_open_req,
+ avdt_scb_snd_open_rsp,
+ avdt_scb_snd_reconfig_req,
+ avdt_scb_snd_reconfig_rsp,
+ avdt_scb_snd_security_req,
+ avdt_scb_snd_security_rsp,
+ avdt_scb_snd_setconfig_req,
+ avdt_scb_snd_setconfig_rej,
+ avdt_scb_snd_setconfig_rsp,
+ avdt_scb_snd_tc_close,
+ avdt_scb_cb_err,
+ avdt_scb_cong_state,
+ avdt_scb_rej_state,
+ avdt_scb_rej_in_use,
+ avdt_scb_rej_not_in_use,
+ avdt_scb_set_remove,
+ avdt_scb_free_pkt,
+ avdt_scb_clr_pkt,
+ avdt_scb_chk_snd_pkt,
+ avdt_scb_tc_timer,
+ avdt_scb_clr_vars,
+ avdt_scb_dealloc
+};
+
+/* state table information */
+#define AVDT_SCB_ACTIONS 2 /* number of actions */
+#define AVDT_SCB_NEXT_STATE 2 /* position of next state */
+#define AVDT_SCB_NUM_COLS 3 /* number of columns in state tables */
+
+/* state table for idle state */
+const UINT8 avdt_scb_st_idle[][AVDT_SCB_NUM_COLS] = {
+/* Event Action 1 Action 2 Next state */
+/* API_REMOVE_EVT */ {AVDT_SCB_DEALLOC, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* API_WRITE_REQ_EVT */ {AVDT_SCB_FREE_PKT, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* API_GETCONFIG_REQ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* API_DELAY_RPT_REQ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* API_SETCONFIG_REQ_EVT */ {AVDT_SCB_SND_SETCONFIG_REQ, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* API_OPEN_REQ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* API_CLOSE_REQ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* API_RECONFIG_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* API_SECURITY_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* API_ABORT_REQ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* API_GETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* API_SETCONFIG_RSP_EVT */ {AVDT_SCB_SND_SETCONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* API_SETCONFIG_REJ_EVT */ {AVDT_SCB_SND_SETCONFIG_REJ, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* API_OPEN_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* API_CLOSE_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* API_RECONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* API_SECURITY_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* API_ABORT_RSP_EVT */ {AVDT_SCB_SND_ABORT_RSP, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* MSG_SETCONFIG_CMD_EVT */ {AVDT_SCB_HDL_SETCONFIG_CMD, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* MSG_GETCONFIG_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* MSG_OPEN_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* MSG_START_CMD_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* MSG_SUSPEND_CMD_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* MSG_CLOSE_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* MSG_ABORT_CMD_EVT */ {AVDT_SCB_HDL_ABORT_CMD, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* MSG_RECONFIG_CMD_EVT */ {AVDT_SCB_REJ_NOT_IN_USE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* MSG_SECURITY_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* MSG_DELAY_RPT_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* MSG_DELAY_RPT_RSP_EVT */ {AVDT_SCB_HDL_DELAY_RPT_RSP, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* MSG_SETCONFIG_RSP_EVT */ {AVDT_SCB_HDL_SETCONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* MSG_GETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* MSG_OPEN_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* MSG_START_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* MSG_SUSPEND_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* MSG_CLOSE_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* MSG_ABORT_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* MSG_RECONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* MSG_SECURITY_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* MSG_SETCONFIG_REJ_EVT */ {AVDT_SCB_HDL_SETCONFIG_REJ, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* MSG_OPEN_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* MSG_START_REJ_EVT */ {AVDT_SCB_HDL_START_RSP, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* MSG_SUSPEND_REJ_EVT */ {AVDT_SCB_HDL_SUSPEND_RSP, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* TC_TOUT_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* TC_OPEN_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* TC_CLOSE_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* TC_CONG_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* TC_DATA_EVT */ {AVDT_SCB_DROP_PKT, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* CC_CLOSE_EVT */ {AVDT_SCB_CLR_VARS, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}
+};
+
+/* state table for configured state */
+const UINT8 avdt_scb_st_conf[][AVDT_SCB_NUM_COLS] = {
+/* Event Action 1 Action 2 Next state */
+/* API_REMOVE_EVT */ {AVDT_SCB_SND_ABORT_REQ, AVDT_SCB_SET_REMOVE, AVDT_SCB_CONF_ST},
+/* API_WRITE_REQ_EVT */ {AVDT_SCB_FREE_PKT, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* API_GETCONFIG_REQ_EVT */ {AVDT_SCB_SND_GETCONFIG_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* API_DELAY_RPT_REQ_EVT */ {AVDT_SCB_SND_DELAY_RPT_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* API_SETCONFIG_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* API_OPEN_REQ_EVT */ {AVDT_SCB_SND_OPEN_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* API_CLOSE_REQ_EVT */ {AVDT_SCB_SND_ABORT_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* API_RECONFIG_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* API_SECURITY_REQ_EVT */ {AVDT_SCB_SND_SECURITY_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* API_ABORT_REQ_EVT */ {AVDT_SCB_SND_ABORT_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* API_GETCONFIG_RSP_EVT */ {AVDT_SCB_SND_GETCONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* API_SETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* API_SETCONFIG_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* API_OPEN_RSP_EVT */ {AVDT_SCB_SND_OPEN_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* API_CLOSE_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* API_RECONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* API_SECURITY_RSP_EVT */ {AVDT_SCB_SND_SECURITY_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* API_ABORT_RSP_EVT */ {AVDT_SCB_SND_ABORT_RSP, AVDT_SCB_HDL_TC_CLOSE, AVDT_SCB_IDLE_ST},
+/* MSG_SETCONFIG_CMD_EVT */ {AVDT_SCB_REJ_IN_USE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* MSG_GETCONFIG_CMD_EVT */ {AVDT_SCB_HDL_GETCONFIG_CMD, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* MSG_OPEN_CMD_EVT */ {AVDT_SCB_HDL_OPEN_CMD, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* MSG_START_CMD_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* MSG_SUSPEND_CMD_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* MSG_CLOSE_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* MSG_ABORT_CMD_EVT */ {AVDT_SCB_HDL_ABORT_CMD, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* MSG_RECONFIG_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* MSG_SECURITY_CMD_EVT */ {AVDT_SCB_HDL_SECURITY_CMD, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* MSG_DELAY_RPT_CMD_EVT */ {AVDT_SCB_HDL_DELAY_RPT_CMD, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* MSG_DELAY_RPT_RSP_EVT */ {AVDT_SCB_HDL_DELAY_RPT_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* MSG_SETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* MSG_GETCONFIG_RSP_EVT */ {AVDT_SCB_HDL_GETCONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* MSG_OPEN_RSP_EVT */ {AVDT_SCB_HDL_OPEN_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* MSG_START_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* MSG_SUSPEND_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* MSG_CLOSE_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* MSG_ABORT_RSP_EVT */ {AVDT_SCB_HDL_ABORT_RSP, AVDT_SCB_HDL_TC_CLOSE, AVDT_SCB_IDLE_ST},
+/* MSG_RECONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* MSG_SECURITY_RSP_EVT */ {AVDT_SCB_HDL_SECURITY_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* MSG_SETCONFIG_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* MSG_OPEN_REJ_EVT */ {AVDT_SCB_HDL_OPEN_REJ, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* MSG_START_REJ_EVT */ {AVDT_SCB_HDL_START_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* MSG_SUSPEND_REJ_EVT */ {AVDT_SCB_HDL_SUSPEND_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* TC_TOUT_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* TC_OPEN_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* TC_CLOSE_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* TC_CONG_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* TC_DATA_EVT */ {AVDT_SCB_DROP_PKT, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* CC_CLOSE_EVT */ {AVDT_SCB_HDL_TC_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}
+};
+
+/* state table for opening state */
+const UINT8 avdt_scb_st_opening[][AVDT_SCB_NUM_COLS] = {
+/* Event Action 1 Action 2 Next state */
+/* API_REMOVE_EVT */ {AVDT_SCB_SND_CLOSE_REQ, AVDT_SCB_SET_REMOVE, AVDT_SCB_CLOSING_ST},
+/* API_WRITE_REQ_EVT */ {AVDT_SCB_FREE_PKT, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* API_GETCONFIG_REQ_EVT */ {AVDT_SCB_SND_GETCONFIG_REQ, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* API_DELAY_RPT_REQ_EVT */ {AVDT_SCB_SND_DELAY_RPT_REQ, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* API_SETCONFIG_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* API_OPEN_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* API_CLOSE_REQ_EVT */ {AVDT_SCB_SND_CLOSE_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* API_RECONFIG_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* API_SECURITY_REQ_EVT */ {AVDT_SCB_SND_SECURITY_REQ, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* API_ABORT_REQ_EVT */ {AVDT_SCB_SND_ABORT_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* API_GETCONFIG_RSP_EVT */ {AVDT_SCB_SND_GETCONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* API_SETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* API_SETCONFIG_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* API_OPEN_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* API_CLOSE_RSP_EVT */ {AVDT_SCB_SND_CLOSE_RSP, AVDT_SCB_SND_TC_CLOSE, AVDT_SCB_CLOSING_ST},
+/* API_RECONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* API_SECURITY_RSP_EVT */ {AVDT_SCB_SND_SECURITY_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* API_ABORT_RSP_EVT */ {AVDT_SCB_SND_ABORT_RSP, AVDT_SCB_SND_TC_CLOSE, AVDT_SCB_CLOSING_ST},
+/* MSG_SETCONFIG_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* MSG_GETCONFIG_CMD_EVT */ {AVDT_SCB_HDL_GETCONFIG_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* MSG_OPEN_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* MSG_START_CMD_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* MSG_SUSPEND_CMD_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* MSG_CLOSE_CMD_EVT */ {AVDT_SCB_HDL_CLOSE_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* MSG_ABORT_CMD_EVT */ {AVDT_SCB_HDL_ABORT_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* MSG_RECONFIG_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* MSG_SECURITY_CMD_EVT */ {AVDT_SCB_HDL_SECURITY_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* MSG_DELAY_RPT_CMD_EVT */ {AVDT_SCB_HDL_DELAY_RPT_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* MSG_DELAY_RPT_RSP_EVT */ {AVDT_SCB_HDL_DELAY_RPT_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* MSG_SETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* MSG_GETCONFIG_RSP_EVT */ {AVDT_SCB_HDL_GETCONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* MSG_OPEN_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* MSG_START_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* MSG_SUSPEND_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* MSG_CLOSE_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* MSG_ABORT_RSP_EVT */ {AVDT_SCB_SND_TC_CLOSE, AVDT_SCB_HDL_ABORT_RSP, AVDT_SCB_CLOSING_ST},
+/* MSG_RECONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* MSG_SECURITY_RSP_EVT */ {AVDT_SCB_HDL_SECURITY_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* MSG_SETCONFIG_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* MSG_OPEN_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* MSG_START_REJ_EVT */ {AVDT_SCB_HDL_START_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* MSG_SUSPEND_REJ_EVT */ {AVDT_SCB_HDL_SUSPEND_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* TC_TOUT_EVT */ {AVDT_SCB_SND_ABORT_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* TC_OPEN_EVT */ {AVDT_SCB_HDL_TC_OPEN, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* TC_CLOSE_EVT */ {AVDT_SCB_HDL_TC_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* TC_CONG_EVT */ {AVDT_SCB_CONG_STATE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* TC_DATA_EVT */ {AVDT_SCB_DROP_PKT, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* CC_CLOSE_EVT */ {AVDT_SCB_SND_TC_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}
+};
+
+/* state table for open state */
+const UINT8 avdt_scb_st_open[][AVDT_SCB_NUM_COLS] = {
+/* Event Action 1 Action 2 Next state */
+/* API_REMOVE_EVT */ {AVDT_SCB_SND_CLOSE_REQ, AVDT_SCB_SET_REMOVE, AVDT_SCB_CLOSING_ST},
+/* API_WRITE_REQ_EVT */ {AVDT_SCB_FREE_PKT, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* API_GETCONFIG_REQ_EVT */ {AVDT_SCB_SND_GETCONFIG_REQ, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* API_DELAY_RPT_REQ_EVT */ {AVDT_SCB_SND_DELAY_RPT_REQ, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* API_SETCONFIG_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* API_OPEN_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* API_CLOSE_REQ_EVT */ {AVDT_SCB_SND_CLOSE_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* API_RECONFIG_REQ_EVT */ {AVDT_SCB_SND_RECONFIG_REQ, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* API_SECURITY_REQ_EVT */ {AVDT_SCB_SND_SECURITY_REQ, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* API_ABORT_REQ_EVT */ {AVDT_SCB_SND_ABORT_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* API_GETCONFIG_RSP_EVT */ {AVDT_SCB_SND_GETCONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* API_SETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* API_SETCONFIG_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* API_OPEN_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* API_CLOSE_RSP_EVT */ {AVDT_SCB_SND_CLOSE_RSP, AVDT_SCB_TC_TIMER, AVDT_SCB_CLOSING_ST},
+/* API_RECONFIG_RSP_EVT */ {AVDT_SCB_SND_RECONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* API_SECURITY_RSP_EVT */ {AVDT_SCB_SND_SECURITY_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* API_ABORT_RSP_EVT */ {AVDT_SCB_SND_ABORT_RSP, AVDT_SCB_TC_TIMER, AVDT_SCB_CLOSING_ST},
+/* MSG_SETCONFIG_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* MSG_GETCONFIG_CMD_EVT */ {AVDT_SCB_HDL_GETCONFIG_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* MSG_OPEN_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* MSG_START_CMD_EVT */ {AVDT_SCB_HDL_START_CMD, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* MSG_SUSPEND_CMD_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* MSG_CLOSE_CMD_EVT */ {AVDT_SCB_HDL_CLOSE_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* MSG_ABORT_CMD_EVT */ {AVDT_SCB_HDL_ABORT_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* MSG_RECONFIG_CMD_EVT */ {AVDT_SCB_HDL_RECONFIG_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* MSG_SECURITY_CMD_EVT */ {AVDT_SCB_HDL_SECURITY_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* MSG_DELAY_RPT_CMD_EVT */ {AVDT_SCB_HDL_DELAY_RPT_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* MSG_DELAY_RPT_RSP_EVT */ {AVDT_SCB_HDL_DELAY_RPT_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* MSG_SETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* MSG_GETCONFIG_RSP_EVT */ {AVDT_SCB_HDL_GETCONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* MSG_OPEN_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* MSG_START_RSP_EVT */ {AVDT_SCB_HDL_START_RSP, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* MSG_SUSPEND_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* MSG_CLOSE_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* MSG_ABORT_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* MSG_RECONFIG_RSP_EVT */ {AVDT_SCB_HDL_RECONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* MSG_SECURITY_RSP_EVT */ {AVDT_SCB_HDL_SECURITY_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* MSG_SETCONFIG_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* MSG_OPEN_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* MSG_START_REJ_EVT */ {AVDT_SCB_HDL_START_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* MSG_SUSPEND_REJ_EVT */ {AVDT_SCB_HDL_SUSPEND_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* TC_TOUT_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+#if AVDT_REPORTING == TRUE
+/* TC_OPEN_EVT */ {AVDT_SCB_HDL_TC_OPEN_STO, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* TC_CLOSE_EVT */ {AVDT_SCB_HDL_TC_CLOSE_STO, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+#else
+/* TC_OPEN_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* TC_CLOSE_EVT */ {AVDT_SCB_HDL_TC_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+#endif
+/* TC_CONG_EVT */ {AVDT_SCB_CONG_STATE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* TC_DATA_EVT */ {AVDT_SCB_DROP_PKT, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* CC_CLOSE_EVT */ {AVDT_SCB_SND_TC_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}
+};
+
+/* state table for streaming state */
+const UINT8 avdt_scb_st_stream[][AVDT_SCB_NUM_COLS] = {
+/* Event Action 1 Action 2 Next state */
+/* API_REMOVE_EVT */ {AVDT_SCB_SND_STREAM_CLOSE, AVDT_SCB_SET_REMOVE, AVDT_SCB_CLOSING_ST},
+/* API_WRITE_REQ_EVT */ {AVDT_SCB_HDL_WRITE_REQ, AVDT_SCB_CHK_SND_PKT, AVDT_SCB_STREAM_ST},
+/* API_GETCONFIG_REQ_EVT */ {AVDT_SCB_SND_GETCONFIG_REQ, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* API_DELAY_RPT_REQ_EVT */ {AVDT_SCB_SND_DELAY_RPT_REQ, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* API_SETCONFIG_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* API_OPEN_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* API_CLOSE_REQ_EVT */ {AVDT_SCB_SND_STREAM_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* API_RECONFIG_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* API_SECURITY_REQ_EVT */ {AVDT_SCB_SND_SECURITY_REQ, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* API_ABORT_REQ_EVT */ {AVDT_SCB_SND_ABORT_REQ, AVDT_SCB_CLR_PKT, AVDT_SCB_CLOSING_ST},
+/* API_GETCONFIG_RSP_EVT */ {AVDT_SCB_SND_GETCONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* API_SETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* API_SETCONFIG_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* API_OPEN_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* API_CLOSE_RSP_EVT */ {AVDT_SCB_SND_CLOSE_RSP, AVDT_SCB_TC_TIMER, AVDT_SCB_CLOSING_ST},
+/* API_RECONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* API_SECURITY_RSP_EVT */ {AVDT_SCB_SND_SECURITY_RSP, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* API_ABORT_RSP_EVT */ {AVDT_SCB_SND_ABORT_RSP, AVDT_SCB_TC_TIMER, AVDT_SCB_CLOSING_ST},
+/* MSG_SETCONFIG_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* MSG_GETCONFIG_CMD_EVT */ {AVDT_SCB_HDL_GETCONFIG_CMD, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* MSG_OPEN_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* MSG_START_CMD_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* MSG_SUSPEND_CMD_EVT */ {AVDT_SCB_HDL_SUSPEND_CMD, AVDT_SCB_CLR_PKT, AVDT_SCB_OPEN_ST},
+/* MSG_CLOSE_CMD_EVT */ {AVDT_SCB_HDL_CLOSE_CMD, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* MSG_ABORT_CMD_EVT */ {AVDT_SCB_HDL_ABORT_CMD, AVDT_SCB_CLR_PKT, AVDT_SCB_STREAM_ST},
+/* MSG_RECONFIG_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* MSG_SECURITY_CMD_EVT */ {AVDT_SCB_HDL_SECURITY_CMD, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* MSG_DELAY_RPT_CMD_EVT */ {AVDT_SCB_HDL_DELAY_RPT_CMD, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* MSG_DELAY_RPT_RSP_EVT */ {AVDT_SCB_HDL_DELAY_RPT_RSP, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* MSG_SETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* MSG_GETCONFIG_RSP_EVT */ {AVDT_SCB_HDL_GETCONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* MSG_OPEN_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* MSG_START_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* MSG_SUSPEND_RSP_EVT */ {AVDT_SCB_HDL_SUSPEND_RSP, AVDT_SCB_CLR_PKT, AVDT_SCB_OPEN_ST},
+/* MSG_CLOSE_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* MSG_ABORT_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* MSG_RECONFIG_RSP_EVT */ {AVDT_SCB_HDL_RECONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* MSG_SECURITY_RSP_EVT */ {AVDT_SCB_HDL_SECURITY_RSP, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* MSG_SETCONFIG_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* MSG_OPEN_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* MSG_START_REJ_EVT */ {AVDT_SCB_HDL_START_RSP, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* MSG_SUSPEND_REJ_EVT */ {AVDT_SCB_HDL_SUSPEND_RSP, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* TC_TOUT_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* TC_OPEN_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* TC_CLOSE_EVT */ {AVDT_SCB_HDL_TC_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* TC_CONG_EVT */ {AVDT_SCB_CONG_STATE, AVDT_SCB_CHK_SND_PKT, AVDT_SCB_STREAM_ST},
+/* TC_DATA_EVT */ {AVDT_SCB_HDL_PKT, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* CC_CLOSE_EVT */ {AVDT_SCB_SND_TC_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}
+};
+
+/* state table for closing state */
+const UINT8 avdt_scb_st_closing[][AVDT_SCB_NUM_COLS] = {
+/* Event Action 1 Action 2 Next state */
+/* API_REMOVE_EVT */ {AVDT_SCB_SET_REMOVE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* API_WRITE_REQ_EVT */ {AVDT_SCB_FREE_PKT, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* API_GETCONFIG_REQ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* API_DELAY_RPT_REQ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* API_SETCONFIG_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* API_OPEN_REQ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* API_CLOSE_REQ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* API_RECONFIG_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* API_SECURITY_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* API_ABORT_REQ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* API_GETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* API_SETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* API_SETCONFIG_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* API_OPEN_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* API_CLOSE_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* API_RECONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* API_SECURITY_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* API_ABORT_RSP_EVT */ {AVDT_SCB_SND_ABORT_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* MSG_SETCONFIG_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* MSG_GETCONFIG_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* MSG_OPEN_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* MSG_START_CMD_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* MSG_SUSPEND_CMD_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* MSG_CLOSE_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* MSG_ABORT_CMD_EVT */ {AVDT_SCB_HDL_ABORT_CMD, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* MSG_RECONFIG_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* MSG_SECURITY_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* MSG_DELAY_RPT_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* MSG_DELAY_RPT_RSP_EVT */ {AVDT_SCB_HDL_DELAY_RPT_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* MSG_SETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* MSG_GETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* MSG_OPEN_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* MSG_START_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* MSG_SUSPEND_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* MSG_CLOSE_RSP_EVT */ {AVDT_SCB_SND_TC_CLOSE, AVDT_SCB_HDL_CLOSE_RSP, AVDT_SCB_CLOSING_ST},
+/* MSG_ABORT_RSP_EVT */ {AVDT_SCB_SND_TC_CLOSE, AVDT_SCB_HDL_ABORT_RSP, AVDT_SCB_CLOSING_ST},
+/* MSG_RECONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* MSG_SECURITY_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* MSG_SETCONFIG_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* MSG_OPEN_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* MSG_START_REJ_EVT */ {AVDT_SCB_HDL_START_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* MSG_SUSPEND_REJ_EVT */ {AVDT_SCB_HDL_SUSPEND_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* TC_TOUT_EVT */ {AVDT_SCB_SND_TC_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* TC_OPEN_EVT */ {AVDT_SCB_SND_TC_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* TC_CLOSE_EVT */ {AVDT_SCB_HDL_TC_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* TC_CONG_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* TC_DATA_EVT */ {AVDT_SCB_DROP_PKT, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* CC_CLOSE_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}
+};
+
+/* type for state table */
+typedef const UINT8 (*tAVDT_SCB_ST_TBL)[AVDT_SCB_NUM_COLS];
+
+/* state table */
+const tAVDT_SCB_ST_TBL avdt_scb_st_tbl[] = {
+ avdt_scb_st_idle,
+ avdt_scb_st_conf,
+ avdt_scb_st_opening,
+ avdt_scb_st_open,
+ avdt_scb_st_stream,
+ avdt_scb_st_closing
+};
+
+
+/*******************************************************************************
+**
+** Function avdt_scb_event
+**
+** Description State machine event handling function for scb
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_event(tAVDT_SCB *p_scb, UINT8 event, tAVDT_SCB_EVT *p_data)
+{
+ tAVDT_SCB_ST_TBL state_table;
+ UINT8 action;
+ int i;
+
+#if AVDT_DEBUG == TRUE
+ AVDT_TRACE_EVENT4("SCB hdl=%d event=%d/%s state=%s", avdt_scb_to_hdl(p_scb), event, avdt_scb_evt_str[event], avdt_scb_st_str[p_scb->state]);
+#endif
+ BTTRC_AVDT_SCB_EVENT(event, p_scb->state);
+
+ /* set current event */
+ p_scb->curr_evt = event;
+
+ /* look up the state table for the current state */
+ state_table = avdt_scb_st_tbl[p_scb->state];
+
+ /* set next state */
+ if (p_scb->state != state_table[event][AVDT_SCB_NEXT_STATE])
+ BTTRC_AVDT_SCB_STATE(state_table[event][AVDT_SCB_NEXT_STATE]);
+ p_scb->state = state_table[event][AVDT_SCB_NEXT_STATE];
+
+
+ /* execute action functions */
+ for (i = 0; i < AVDT_SCB_ACTIONS; i++)
+ {
+ if ((action = state_table[event][i]) != AVDT_SCB_IGNORE)
+ {
+ BTTRC_AVDT_SCB_ACTION(action);
+ (*avdt_cb.p_scb_act[action])(p_scb, p_data);
+ }
+ else
+ {
+ break;
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function avdt_scb_init
+**
+** Description Initialize stream control block module.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_init(void)
+{
+ memset(&avdt_cb.scb[0], 0, sizeof(tAVDT_SCB) * AVDT_NUM_SEPS);
+ avdt_cb.p_scb_act = (tAVDT_SCB_ACTION *) avdt_scb_action;
+}
+
+
+/*******************************************************************************
+**
+** Function avdt_scb_alloc
+**
+** Description Allocate a stream control block.
+**
+**
+** Returns pointer to the scb, or NULL if none could be allocated.
+**
+*******************************************************************************/
+tAVDT_SCB *avdt_scb_alloc(tAVDT_CS *p_cs)
+{
+ tAVDT_SCB *p_scb = &avdt_cb.scb[0];
+ int i;
+
+ /* find available scb */
+ for (i = 0; i < AVDT_NUM_SEPS; i++, p_scb++)
+ {
+ if (!p_scb->allocated)
+ {
+ memset(p_scb,0,sizeof(tAVDT_SCB));
+ p_scb->allocated = TRUE;
+ p_scb->p_ccb = NULL;
+ memcpy(&p_scb->cs, p_cs, sizeof(tAVDT_CS));
+#if AVDT_MULTIPLEXING == TRUE
+ /* initialize fragments gueue */
+ GKI_init_q(&p_scb->frag_q);
+
+ if(p_cs->cfg.psc_mask & AVDT_PSC_MUX)
+ {
+ p_scb->cs.cfg.mux_tcid_media = avdt_ad_type_to_tcid(AVDT_CHAN_MEDIA, p_scb);
+#if AVDT_REPORTING == TRUE
+ if(p_cs->cfg.psc_mask & AVDT_PSC_REPORT)
+ {
+ p_scb->cs.cfg.mux_tcid_report = avdt_ad_type_to_tcid(AVDT_CHAN_REPORT, p_scb);
+ }
+#endif
+ }
+#endif
+ p_scb->timer_entry.param = (UINT32) p_scb;
+ AVDT_TRACE_DEBUG2("avdt_scb_alloc hdl=%d, psc_mask:0x%x", i+1, p_cs->cfg.psc_mask);
+ break;
+ }
+ }
+
+ if (i == AVDT_NUM_SEPS)
+ {
+ /* out of ccbs */
+ p_scb = NULL;
+ AVDT_TRACE_WARNING0("Out of scbs");
+ }
+
+ return p_scb;
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_dealloc
+**
+** Description Deallocate a stream control block.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_scb_dealloc(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+#if AVDT_MULTIPLEXING == TRUE
+ void *p_buf;
+#endif
+
+ AVDT_TRACE_DEBUG1("avdt_scb_dealloc hdl=%d", avdt_scb_to_hdl(p_scb));
+ btu_stop_timer(&p_scb->timer_entry);
+
+#if AVDT_MULTIPLEXING == TRUE
+ /* free fragments we're holding, if any; it shouldn't happen */
+ while ((p_buf = GKI_dequeue (&p_scb->frag_q)) != NULL)
+ GKI_freebuf(p_buf);
+#endif
+
+ memset(p_scb, 0, sizeof(tAVDT_SCB));
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_to_hdl
+**
+** Description Given a pointer to an scb, return its handle (or seid).
+**
+**
+** Returns Index of scb.
+**
+*******************************************************************************/
+UINT8 avdt_scb_to_hdl(tAVDT_SCB *p_scb)
+{
+ return (UINT8) (p_scb - avdt_cb.scb + 1);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_by_hdl
+**
+** Description Given an scb handle (or seid), return a pointer to the scb.
+**
+**
+** Returns Pointer to scb or NULL if index is out of range or scb
+** is not allocated.
+**
+*******************************************************************************/
+tAVDT_SCB *avdt_scb_by_hdl(UINT8 hdl)
+{
+ tAVDT_SCB *p_scb;
+
+ /* verify index */
+ if ((hdl > 0) && (hdl <= AVDT_NUM_SEPS))
+ {
+ p_scb = &avdt_cb.scb[hdl - 1];
+
+ /* verify scb is allocated */
+ if (!p_scb->allocated)
+ {
+ p_scb = NULL;
+ AVDT_TRACE_WARNING1("scb hdl %d not allocated", hdl);
+ }
+ }
+ else
+ {
+ p_scb = NULL;
+ AVDT_TRACE_WARNING1("scb hdl %d out of range", hdl);
+ }
+ return p_scb;
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_verify
+**
+** Description Verify the condition of a list of scbs.
+**
+**
+** Returns SEID that failed, or 0 if success.
+**
+*******************************************************************************/
+UINT8 avdt_scb_verify(tAVDT_CCB *p_ccb, UINT8 state, UINT8 *p_seid, UINT16 num_seid, UINT8 *p_err_code)
+{
+ int i;
+ tAVDT_SCB *p_scb;
+ UINT8 nsc_mask;
+ UINT8 chk_state;
+ UINT8 ret = 0;
+
+ AVDT_TRACE_DEBUG1("avdt_scb_verify state %d", state);
+ /* set nonsupported command mask */
+ /* translate public state into private state */
+ nsc_mask = 0;
+ chk_state = AVDT_SCB_STREAM_ST;
+ switch(state)
+ {
+ case AVDT_VERIFY_SUSPEND:
+ nsc_mask = AVDT_NSC_SUSPEND;
+ break;
+ case AVDT_VERIFY_OPEN:
+ case AVDT_VERIFY_START:
+ chk_state = AVDT_SCB_OPEN_ST;
+ break;
+ }
+
+ /* verify every scb */
+ for (i = 0; i < num_seid; i++)
+ {
+ if ((p_scb = avdt_scb_by_hdl(p_seid[i])) == NULL)
+ {
+ *p_err_code = AVDT_ERR_BAD_STATE;
+ break;
+ }
+ else if ((p_scb->state != chk_state) || (p_scb->p_ccb != p_ccb))
+ {
+ *p_err_code = AVDT_ERR_BAD_STATE;
+ break;
+ }
+ else if (p_scb->cs.nsc_mask & nsc_mask)
+ {
+ *p_err_code = AVDT_ERR_NSC;
+ break;
+ }
+ }
+
+ if (i != num_seid)
+ {
+ ret = p_seid[i];
+ }
+ AVDT_TRACE_DEBUG3("avdt_scb_verify state %d, nsc_mask0x%x, ret: %d",
+ chk_state, nsc_mask, ret);
+ return ret;
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_peer_seid_list
+**
+** Description Given a list of SCB handles, return a list of peer SEIDs
+** for the handles, copied in place into the struct passed in.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_peer_seid_list(tAVDT_MULTI *p_multi)
+{
+ int i;
+ tAVDT_SCB *p_scb;
+
+ for (i = 0; i < p_multi->num_seps; i++)
+ {
+ if ((p_scb = avdt_scb_by_hdl(p_multi->seid_list[i])) != NULL)
+ {
+ p_multi->seid_list[i] = p_scb->peer_seid;
+ }
+ }
+}
+
diff --git a/stack/avdt/avdt_scb_act.c b/stack/avdt/avdt_scb_act.c
new file mode 100644
index 0000000..1784713
--- /dev/null
+++ b/stack/avdt/avdt_scb_act.c
@@ -0,0 +1,2111 @@
+/*****************************************************************************
+**
+** Name: avdt_scb_act.c
+**
+** Description: This module contains the action functions associated
+** with the stream control block state machine.
+**
+** Copyright (c) 2002-2008, Broadcom Corp., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include <string.h>
+#include "data_types.h"
+#include "bt_target.h"
+#include "avdt_api.h"
+#include "avdtc_api.h"
+#include "avdt_int.h"
+#include "gki.h"
+#include "btu.h"
+
+/* This table is used to lookup the callback event that matches a particular
+** state machine API request event. Note that state machine API request
+** events are at the beginning of the event list starting at zero, thus
+** allowing for this table.
+*/
+const UINT8 avdt_scb_cback_evt[] = {
+ 0, /* API_REMOVE_EVT (no event) */
+ AVDT_WRITE_CFM_EVT, /* API_WRITE_REQ_EVT */
+ 0, /* API_GETCONFIG_REQ_EVT (no event) */
+ 0, /* API_DELAY_RPT_REQ_EVT (no event) */
+ AVDT_OPEN_CFM_EVT, /* API_SETCONFIG_REQ_EVT */
+ AVDT_OPEN_CFM_EVT, /* API_OPEN_REQ_EVT */
+ AVDT_CLOSE_CFM_EVT, /* API_CLOSE_REQ_EVT */
+ AVDT_RECONFIG_CFM_EVT, /* API_RECONFIG_REQ_EVT */
+ AVDT_SECURITY_CFM_EVT, /* API_SECURITY_REQ_EVT */
+ 0 /* API_ABORT_REQ_EVT (no event) */
+};
+
+/* This table is used to look up the callback event based on the signaling
+** role when the stream is closed.
+*/
+const UINT8 avdt_scb_role_evt[] = {
+ AVDT_CLOSE_IND_EVT, /* AVDT_CLOSE_ACP */
+ AVDT_CLOSE_CFM_EVT, /* AVDT_CLOSE_INT */
+ AVDT_CLOSE_IND_EVT, /* AVDT_OPEN_ACP */
+ AVDT_OPEN_CFM_EVT /* AVDT_OPEN_INT */
+};
+
+/*******************************************************************************
+**
+** Function avdt_scb_gen_ssrc
+**
+** Description This function generates a SSRC number unique to the stream.
+**
+** Returns SSRC value.
+**
+*******************************************************************************/
+UINT32 avdt_scb_gen_ssrc(tAVDT_SCB *p_scb)
+{
+ /* combine the value of the media type and codec type of the SCB */
+ return ((UINT32)(p_scb->cs.cfg.codec_info[1] | p_scb->cs.cfg.codec_info[2]));
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_abort_cmd
+**
+** Description This function sends the SCB an AVDT_SCB_API_ABORT_RSP_EVT
+** to initiate sending of an abort response message.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_abort_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ p_scb->role = AVDT_CLOSE_ACP;
+ avdt_scb_event(p_scb, AVDT_SCB_API_ABORT_RSP_EVT, p_data);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_abort_rsp
+**
+** Description This function is an empty function; it serves as a
+** placeholder for a conformance API action function.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_abort_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ return;
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_close_cmd
+**
+** Description This function sends the SCB an AVDT_SCB_API_CLOSE_RSP_EVT
+** to initiate sending of a close response message.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_close_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ p_scb->role = AVDT_CLOSE_ACP;
+ avdt_scb_event(p_scb, AVDT_SCB_API_CLOSE_RSP_EVT, p_data);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_close_rsp
+**
+** Description This function sets the close_code variable to the error
+** code returned in the close response.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_close_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ p_scb->close_code = p_data->msg.hdr.err_code;
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_getconfig_cmd
+**
+** Description This function retrieves the configuration parameters of
+** the SCB and sends the SCB an AVDT_SCB_API_GETCONFIG_RSP_EVT
+** to initiate sending of a get configuration response message.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_getconfig_cmd(tAVDT_SCB *p_scb,tAVDT_SCB_EVT *p_data)
+{
+ p_data->msg.svccap.p_cfg = &p_scb->curr_cfg;
+
+ avdt_scb_event(p_scb, AVDT_SCB_API_GETCONFIG_RSP_EVT, p_data);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_getconfig_rsp
+**
+** Description This function is an empty function; it serves as a
+** placeholder for a conformance API action function.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_getconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ return;
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_open_cmd
+**
+** Description This function sends the SCB an AVDT_SCB_API_OPEN_RSP_EVT
+** to initiate sending of an open response message.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_open_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ avdt_scb_event(p_scb, AVDT_SCB_API_OPEN_RSP_EVT, p_data);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_open_rej
+**
+** Description This function calls the application callback function
+** indicating the open request has failed. It initializes
+** certain SCB variables and sends a AVDT_CCB_UL_CLOSE_EVT
+** to the CCB.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_open_rej(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ /* do exactly same as setconfig reject */
+ avdt_scb_hdl_setconfig_rej(p_scb, p_data);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_open_rsp
+**
+** Description This function calls avdt_ad_open_req() to initiate
+** connection of the transport channel for this stream.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_open_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ /* initiate opening of trans channels for this SEID */
+ p_scb->role = AVDT_OPEN_INT;
+ avdt_ad_open_req(AVDT_CHAN_MEDIA, p_scb->p_ccb, p_scb, AVDT_INT);
+
+ /* start tc connect timer */
+ btu_start_timer(&p_scb->timer_entry, BTU_TTYPE_AVDT_SCB_TC, AVDT_SCB_TC_CONN_TOUT);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_pkt_no_frag
+**
+** Description
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_pkt_no_frag(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ UINT8 *p, *p_start;
+ UINT8 o_v, o_p, o_x, o_cc;
+ UINT8 m_pt;
+ UINT8 marker;
+ UINT16 seq;
+ UINT32 time_stamp;
+ UINT32 ssrc;
+ UINT16 offset;
+ UINT16 ex_len;
+ UINT8 pad_len = 0;
+
+ p = p_start = (UINT8 *)(p_data->p_pkt + 1) + p_data->p_pkt->offset;
+
+ /* parse media packet header */
+ AVDT_MSG_PRS_OCTET1(p, o_v, o_p, o_x, o_cc);
+ AVDT_MSG_PRS_M_PT(p, m_pt, marker);
+ BE_STREAM_TO_UINT16(seq, p);
+ BE_STREAM_TO_UINT32(time_stamp, p);
+ BE_STREAM_TO_UINT32(ssrc, p);
+
+ /* skip over any csrc's in packet */
+ p += o_cc * 4;
+
+ /* check for and skip over extension header */
+ if (o_x)
+ {
+ p += 2;
+ BE_STREAM_TO_UINT16(ex_len, p);
+ p += ex_len * 4;
+ }
+
+ /* save our new offset */
+ offset = (UINT16) (p - p_start);
+
+ /* adjust length for any padding at end of packet */
+ if (o_p)
+ {
+ /* padding length in last byte of packet */
+ pad_len = *(p_start + p_data->p_pkt->len);
+ }
+
+ /* do sanity check */
+ if ((offset > p_data->p_pkt->len) || ((pad_len + offset) > p_data->p_pkt->len))
+ {
+ AVDT_TRACE_WARNING0("Got bad media packet");
+ GKI_freebuf(p_data->p_pkt);
+ }
+ /* adjust offset and length and send it up */
+ else
+ {
+ p_data->p_pkt->len -= (offset + pad_len);
+ p_data->p_pkt->offset += offset;
+
+ if (p_scb->cs.p_data_cback != NULL)
+ {
+ /* report sequence number */
+ p_data->p_pkt->layer_specific = seq;
+ (*p_scb->cs.p_data_cback)(avdt_scb_to_hdl(p_scb), p_data->p_pkt,
+ time_stamp, (UINT8)(m_pt | (marker<<7)));
+ }
+ else
+ {
+#if AVDT_MULTIPLEXING == TRUE
+ if ((p_scb->cs.p_media_cback != NULL)
+ && (p_scb->p_media_buf != NULL)
+ && (p_scb->media_buf_len > p_data->p_pkt->len))
+ {
+ /* media buffer enough length is assigned by application. Lets use it*/
+ memcpy(p_scb->p_media_buf,(UINT8*)(p_data->p_pkt + 1) + p_data->p_pkt->offset,
+ p_data->p_pkt->len);
+ (*p_scb->cs.p_media_cback)(avdt_scb_to_hdl(p_scb),p_scb->p_media_buf,
+ p_scb->media_buf_len,time_stamp,seq,m_pt,marker);
+ }
+#endif
+ GKI_freebuf(p_data->p_pkt);
+ }
+ }
+}
+
+#if AVDT_REPORTING == TRUE
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_report
+**
+** Description
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+UINT8 * avdt_scb_hdl_report(tAVDT_SCB *p_scb, UINT8 *p, UINT16 len)
+{
+ UINT16 result = AVDT_SUCCESS;
+ UINT8 *p_start = p;
+ UINT32 ssrc;
+ UINT8 o_v, o_p, o_cc;
+ UINT16 pkt_len;
+ AVDT_REPORT_TYPE pt;
+ tAVDT_REPORT_DATA report, *p_rpt;
+
+ AVDT_TRACE_DEBUG0( "avdt_scb_hdl_report");
+ if(p_scb->cs.p_report_cback)
+ {
+ p_rpt = &report;
+ /* parse report packet header */
+ AVDT_MSG_PRS_RPT_OCTET1(p, o_v, o_p, o_cc);
+ pt = *p++;
+ BE_STREAM_TO_UINT16(pkt_len, p);
+ BE_STREAM_TO_UINT32(ssrc, p);
+
+ switch(pt)
+ {
+ case AVDT_RTCP_PT_SR: /* the packet type - SR (Sender Report) */
+ BE_STREAM_TO_UINT32(report.sr.ntp_sec, p);
+ BE_STREAM_TO_UINT32(report.sr.ntp_frac, p);
+ BE_STREAM_TO_UINT32(report.sr.rtp_time, p);
+ BE_STREAM_TO_UINT32(report.sr.pkt_count, p);
+ BE_STREAM_TO_UINT32(report.sr.octet_count, p);
+ break;
+
+ case AVDT_RTCP_PT_RR: /* the packet type - RR (Receiver Report) */
+ report.rr.frag_lost = *p;
+ BE_STREAM_TO_UINT32(report.rr.packet_lost, p);
+ report.rr.packet_lost &= 0xFFFFFF;
+ BE_STREAM_TO_UINT32(report.rr.seq_num_rcvd, p);
+ BE_STREAM_TO_UINT32(report.rr.jitter, p);
+ BE_STREAM_TO_UINT32(report.rr.lsr, p);
+ BE_STREAM_TO_UINT32(report.rr.dlsr, p);
+ break;
+
+ case AVDT_RTCP_PT_SDES: /* the packet type - SDES (Source Description) */
+ if(*p == AVDT_RTCP_SDES_CNAME)
+ {
+ p_rpt = (tAVDT_REPORT_DATA *)(p+2);
+ }
+ else
+ {
+ AVDT_TRACE_WARNING5( " - SDES SSRC=0x%08x sc=%d %d len=%d %s",
+ ssrc, o_cc, *p, *(p+1), p+2);
+ result = AVDT_BUSY;
+ }
+ break;
+
+ default:
+ AVDT_TRACE_ERROR1( "Bad Report pkt - packet type: %d", pt);
+ result = AVDT_BAD_PARAMS;
+ }
+
+ if(result == AVDT_SUCCESS)
+ (*p_scb->cs.p_report_cback)(avdt_scb_to_hdl(p_scb), pt, p_rpt);
+
+ }
+ p_start += len;
+ return p_start;
+}
+#endif
+
+#if AVDT_MULTIPLEXING == TRUE
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_pkt_frag
+**
+** Description
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_pkt_frag(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ /* Fields of Adaptation Layer Header */
+ UINT8 al_tsid,al_frag,al_lcode;
+ UINT16 al_len;
+ /* media header fields */
+ UINT8 o_v, o_p, o_x, o_cc;
+ UINT8 m_pt;
+ UINT8 marker;
+ UINT16 seq;
+ UINT32 time_stamp;
+ UINT32 ssrc;
+ UINT16 ex_len;
+ UINT8 pad_len;
+ /* other variables */
+ UINT8 *p; /* current pointer */
+ UINT8 *p_end; /* end of all packet */
+ UINT8 *p_payload; /* pointer to media fragment payload in the buffer */
+ UINT32 payload_len; /* payload length */
+ UINT16 frag_len; /* fragment length */
+
+ p = (UINT8 *)(p_data->p_pkt + 1) + p_data->p_pkt->offset;
+ p_end = p + p_data->p_pkt->len;
+ /* parse all fragments */
+ while(p < p_end)
+ {
+ if (p_end - p < 4) /* length check. maximum length of AL header = 4 */
+ {
+ AVDT_TRACE_WARNING2("p_end: 0x%x - p:0x%x < 4", p_end, p);
+ break;
+ }
+
+ /* parse first byte */
+ al_tsid = (*p)>>3;
+ al_frag = ( (*p) >> 2 ) & 0x01;
+ al_lcode = (*p++) & AVDT_ALH_LCODE_MASK;
+
+ /* in case of TSID=00000, a second AL header byte, before the length field,
+ ** is expected and contains the actual TSID, aligned with MSB */
+ if(al_tsid == 0)
+ al_tsid = *p++;
+
+ /* get remaining media length on base of lcode */
+ switch(al_lcode)
+ {
+ case AVDT_ALH_LCODE_NONE: /* No length field present. Take length from l2cap */
+ al_len = (UINT16)(p_end - p);
+ break;
+ case AVDT_ALH_LCODE_16BIT: /* 16 bit length field */
+ BE_STREAM_TO_UINT16(al_len, p);
+ break;
+ case AVDT_ALH_LCODE_9BITM0: /* 9 bit length field, MSB = 0, 8 LSBs in 1 octet following */
+ al_len = *p++;
+ break;
+ default: /* 9 bit length field, MSB = 1, 8 LSBs in 1 octet following */
+ al_len =(UINT16)*p++ + 0x100;
+ }
+
+ /* max fragment length */
+ frag_len = (UINT16)(p_end - p);
+ /* if it isn't last fragment */
+ if(frag_len >= al_len)
+ frag_len = al_len;
+
+ /* check TSID corresponds to config */
+ if (al_tsid != p_scb->curr_cfg.mux_tsid_media)
+ {
+#if AVDT_REPORTING == TRUE
+ if((p_scb->curr_cfg.psc_mask & AVDT_PSC_REPORT) &&
+ (al_tsid == p_scb->curr_cfg.mux_tsid_report))
+ {
+ /* parse reporting packet */
+ p = avdt_scb_hdl_report(p_scb, p, frag_len);
+ continue;
+ }
+ else
+#endif
+ {
+ AVDT_TRACE_WARNING2("bad tsid: %d, mux_tsid_media:%d", al_tsid, p_scb->curr_cfg.mux_tsid_media);
+ break;
+ }
+ }
+ /* check are buffer for assembling and related callback set */
+ else if ((p_scb->p_media_buf == NULL) || (p_scb->cs.p_media_cback == NULL))
+ {
+ AVDT_TRACE_WARNING0("NULL p_media_buf or p_media_cback");
+ break;
+ }
+
+
+ /* it is media fragment beginning */
+ if(!al_frag) /* is it first fragment of original media packet */
+ {
+ AVDT_TRACE_DEBUG2("al:%d media:%d",
+ al_len, p_scb->media_buf_len);
+
+ p_scb->frag_off = 0;
+ p_scb->frag_org_len = al_len; /* total length of original media packet */
+ /* length check: minimum length of media header is 12 */
+ if (p_scb->frag_org_len < 12)
+ {
+ AVDT_TRACE_WARNING1("bad al_len: %d(<12)", al_len);
+ break;
+ }
+ /* check that data fit into buffer */
+ if (al_len > p_scb->media_buf_len)
+ {
+ AVDT_TRACE_WARNING2("bad al_len: %d(>%d)", al_len, p_scb->media_buf_len);
+ break;
+ }
+ /* make sure it is the last fragment in l2cap packet */
+ if (p + al_len < p_end)
+ {
+ AVDT_TRACE_WARNING2("bad al_len: %d(>%d)", al_len, p_scb->media_buf_len);
+ break;
+ }
+ }
+ else
+ {
+ AVDT_TRACE_DEBUG4("al:%d media:%d frag_org_len:%d frag_off:%d",
+ al_len, p_scb->media_buf_len, p_scb->frag_org_len, p_scb->frag_off);
+
+ /* check that remaining length from AL header equals to original len - length of already received fragments */
+ if(al_len != p_scb->frag_org_len - p_scb->frag_off)
+ {
+ AVDT_TRACE_WARNING4("al_len:%d != (frag_org_len:%d - frag_off:%d) %d",
+ al_len, p_scb->frag_org_len, p_scb->frag_off,
+ (p_scb->frag_org_len- p_scb->frag_off));
+ break;
+ }
+
+ /* do sanity check */
+ if (p_scb->frag_off == 0)
+ {
+ AVDT_TRACE_WARNING0("frag_off=0");
+ break;
+ }
+ }
+ /* do common sanity check */
+ if((p_scb->frag_org_len <= p_scb->frag_off) || (p_scb->frag_org_len >= p_scb->media_buf_len))
+ {
+ AVDT_TRACE_WARNING3("common sanity frag_off:%d frag_org_len:%d media_buf_len:%d",
+ p_scb->frag_off, p_scb->frag_org_len, p_scb->media_buf_len);
+ break;
+ }
+
+ AVDT_TRACE_DEBUG4("Received fragment org_len=%d off=%d al_len=%d frag_len=%d",
+ p_scb->frag_org_len, p_scb->frag_off, al_len, frag_len);
+
+ /* copy fragment into buffer */
+ memcpy(p_scb->p_media_buf + p_scb->frag_off, p, frag_len);
+ p_scb->frag_off += frag_len;
+ /* move to the next fragment */
+ p += frag_len;
+ /* if it is last fragment in original media packet then process total media pocket */
+ if(p_scb->frag_off == p_scb->frag_org_len)
+ {
+ p_payload = p_scb->p_media_buf;
+
+ /* media header */
+ AVDT_MSG_PRS_OCTET1(p_payload, o_v, o_p, o_x, o_cc);
+ AVDT_MSG_PRS_M_PT(p_payload, m_pt, marker);
+ BE_STREAM_TO_UINT16(seq, p_payload);
+ BE_STREAM_TO_UINT32(time_stamp, p_payload);
+ BE_STREAM_TO_UINT32(ssrc, p_payload);
+
+ /* skip over any csrc's in packet */
+ p_payload += o_cc * 4;
+
+ /* check for and skip over extension header */
+ if (o_x)
+ {
+ if(p_scb->p_media_buf + p_scb->frag_off - p_payload < 4)
+ {
+ AVDT_TRACE_WARNING3("length check frag_off:%d p_media_buf:%d p_payload:%d",
+ p_scb->frag_off, p_scb->p_media_buf, p_payload);
+ break;/* length check */
+ }
+ p_payload += 2;
+ BE_STREAM_TO_UINT16(ex_len, p_payload);
+ p_payload += ex_len * 4;
+ }
+
+ if(p_payload >= p_scb->p_media_buf + p_scb->frag_off)
+ {
+ AVDT_TRACE_WARNING3("length check2 frag_off:%d p_media_buf:%d p_payload:%d",
+ p_scb->frag_off, p_scb->p_media_buf, p_payload);
+ break;/* length check */
+ }
+
+ /* adjust length for any padding at end of packet */
+ if (o_p)
+ {
+ /* padding length in last byte of packet */
+ pad_len = *(p_scb->p_media_buf + p_scb->frag_off - 1);
+ }
+ else
+ pad_len = 0;
+ /* payload length */
+ payload_len = (UINT32)(p_scb->p_media_buf + p_scb->frag_off - pad_len - p_payload);
+
+ AVDT_TRACE_DEBUG2("Received last fragment header=%d len=%d",
+ p_payload - p_scb->p_media_buf,payload_len);
+
+ /* send total media packet up */
+ if (p_scb->cs.p_media_cback != NULL)
+ {
+ (*p_scb->cs.p_media_cback)(avdt_scb_to_hdl(p_scb), p_payload,
+ payload_len, time_stamp, seq, m_pt, marker);
+ }
+ }
+ } /* while(p < p_end) */
+
+ if(p < p_end)
+ {
+ AVDT_TRACE_WARNING0("*** Got bad media packet");
+ }
+ GKI_freebuf(p_data->p_pkt);
+}
+#endif
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_pkt
+**
+** Description
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+#if AVDT_REPORTING == TRUE
+ UINT8 *p;
+#endif
+
+#if AVDT_MULTIPLEXING == TRUE
+ /* select right function in dependance of is fragmentation supported or not */
+ if( 0 != (p_scb->curr_cfg.psc_mask & AVDT_PSC_MUX))
+ {
+ avdt_scb_hdl_pkt_frag(p_scb, p_data);
+ }
+ else
+#endif
+#if AVDT_REPORTING == TRUE
+ if(p_data->p_pkt->layer_specific == AVDT_CHAN_REPORT)
+ {
+ p = (UINT8 *)(p_data->p_pkt + 1) + p_data->p_pkt->offset;
+ avdt_scb_hdl_report(p_scb, p, p_data->p_pkt->len);
+ GKI_freebuf(p_data->p_pkt);
+ }
+ else
+#endif
+ avdt_scb_hdl_pkt_no_frag(p_scb, p_data);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_drop_pkt
+**
+** Description Drop an incoming media packet. This function is called if
+** a media packet is received in any state besides streaming.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_drop_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ GKI_freebuf(p_data->p_pkt);
+ AVDT_TRACE_WARNING0("Dropped incoming media packet");
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_reconfig_cmd
+**
+** Description This function calls the application callback function
+** with a reconfiguration indication.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_reconfig_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ /* if command not supported */
+ if (p_scb->cs.nsc_mask & AVDT_NSC_RECONFIG)
+ {
+ /* send reject */
+ p_data->msg.hdr.err_code = AVDT_ERR_NSC;
+ p_data->msg.hdr.err_param = 0;
+ avdt_scb_event(p_scb, AVDT_SCB_API_RECONFIG_RSP_EVT, p_data);
+ }
+ else
+ {
+ /* store requested configuration */
+ memcpy(&p_scb->req_cfg, p_data->msg.reconfig_cmd.p_cfg, sizeof(tAVDT_CFG));
+
+ /* call application callback */
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+ NULL,
+ AVDT_RECONFIG_IND_EVT,
+ (tAVDT_CTRL *) &p_data->msg.reconfig_cmd);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_reconfig_rsp
+**
+** Description This function calls the application callback function
+** with a reconfiguration confirm.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_reconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ if (p_data->msg.hdr.err_code == 0)
+ {
+ /* store new configuration */
+ if (p_scb->req_cfg.num_codec > 0)
+ {
+ p_scb->curr_cfg.num_codec = p_scb->req_cfg.num_codec;
+ memcpy(p_scb->curr_cfg.codec_info, p_scb->req_cfg.codec_info, AVDT_CODEC_SIZE);
+ }
+ if (p_scb->req_cfg.num_protect > 0)
+ {
+ p_scb->curr_cfg.num_protect = p_scb->req_cfg.num_protect;
+ memcpy(p_scb->curr_cfg.protect_info, p_scb->req_cfg.protect_info, AVDT_PROTECT_SIZE);
+ }
+ }
+
+ p_data->msg.svccap.p_cfg = &p_scb->curr_cfg;
+
+ /* call application callback */
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+ NULL,
+ AVDT_RECONFIG_CFM_EVT,
+ (tAVDT_CTRL *) &p_data->msg.svccap);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_security_cmd
+**
+** Description This function calls the application callback with a
+** security indication.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_security_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ /* if command not supported */
+ if (p_scb->cs.nsc_mask & AVDT_NSC_SECURITY)
+ {
+ /* send reject */
+ p_data->msg.hdr.err_code = AVDT_ERR_NSC;
+ avdt_scb_event(p_scb, AVDT_SCB_API_SECURITY_RSP_EVT, p_data);
+ }
+ else
+ {
+ /* call application callback */
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+ NULL,
+ AVDT_SECURITY_IND_EVT,
+ (tAVDT_CTRL *) &p_data->msg.security_cmd);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_security_rsp
+**
+** Description This function calls the application callback with a
+** security confirm.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_security_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ /* call application callback */
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+ NULL,
+ AVDT_SECURITY_CFM_EVT,
+ (tAVDT_CTRL *) &p_data->msg.security_cmd);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_setconfig_cmd
+**
+** Description This function marks the SCB as in use and copies the
+** configuration and peer SEID to the SCB. It then calls
+** the application callback with a configuration indication.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_setconfig_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ tAVDT_CFG *p_cfg;
+
+ if (!p_scb->in_use)
+ {
+ p_cfg = p_data->msg.config_cmd.p_cfg;
+ if(p_scb->cs.cfg.codec_info[AVDT_CODEC_TYPE_INDEX] == p_cfg->codec_info[AVDT_CODEC_TYPE_INDEX])
+ {
+ /* set sep as in use */
+ p_scb->in_use = TRUE;
+
+ /* copy info to scb */
+ p_scb->p_ccb = avdt_ccb_by_idx(p_data->msg.config_cmd.hdr.ccb_idx);
+ p_scb->peer_seid = p_data->msg.config_cmd.int_seid;
+ memcpy(&p_scb->req_cfg, p_cfg, sizeof(tAVDT_CFG));
+ /* call app callback */
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+ p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL,
+ AVDT_CONFIG_IND_EVT,
+ (tAVDT_CTRL *) &p_data->msg.config_cmd);
+ }
+ else
+ {
+ p_data->msg.hdr.err_code = AVDT_ERR_UNSUP_CFG;
+ p_data->msg.hdr.err_param = 0;
+ avdt_msg_send_rej(avdt_ccb_by_idx(p_data->msg.hdr.ccb_idx),
+ p_data->msg.hdr.sig_id, &p_data->msg);
+ }
+ }
+ else
+ {
+ avdt_scb_rej_in_use(p_scb, p_data);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_setconfig_rej
+**
+** Description This function marks the SCB as not in use and calls the
+** application callback with an open confirm indicating failure.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_setconfig_rej(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ /* clear scb variables */
+ avdt_scb_clr_vars(p_scb, p_data);
+
+ /* tell ccb we're done with signaling channel */
+ avdt_ccb_event(avdt_ccb_by_idx(p_data->msg.hdr.ccb_idx), AVDT_CCB_UL_CLOSE_EVT, NULL);
+
+ /* call application callback */
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+ NULL,
+ AVDT_OPEN_CFM_EVT,
+ (tAVDT_CTRL *) &p_data->msg.hdr);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_setconfig_rsp
+**
+** Description This function sends the SCB an AVDT_SCB_API_OPEN_REQ_EVT
+** to initiate sending of an open command message.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_setconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ tAVDT_EVT_HDR single;
+
+ if (p_scb->p_ccb != NULL)
+ {
+ /* save configuration */
+ memcpy(&p_scb->curr_cfg, &p_scb->req_cfg, sizeof(tAVDT_CFG));
+
+ /* initiate open */
+ single.seid = p_scb->peer_seid;
+ avdt_scb_event(p_scb, AVDT_SCB_API_OPEN_REQ_EVT, (tAVDT_SCB_EVT *) &single);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_start_cmd
+**
+** Description This function calls the application callback with a
+** start indication.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_start_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+ p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL,
+ AVDT_START_IND_EVT,
+ NULL);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_start_rsp
+**
+** Description This function calls the application callback with a
+** start confirm.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_start_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+ p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL,
+ AVDT_START_CFM_EVT,
+ (tAVDT_CTRL *) &p_data->msg.hdr);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_suspend_cmd
+**
+** Description This function calls the application callback with a suspend
+** indication.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_suspend_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+ p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL,
+ AVDT_SUSPEND_IND_EVT,
+ NULL);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_suspend_rsp
+**
+** Description This function calls the application callback with a suspend
+** confirm.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_suspend_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+ p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL,
+ AVDT_SUSPEND_CFM_EVT,
+ (tAVDT_CTRL *) &p_data->msg.hdr);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_tc_close
+**
+** Description This function is called when the transport channel is
+** closed. It marks the SCB as not in use and
+** initializes certain SCB parameters. It then sends
+** an AVDT_CCB_UL_CLOSE_EVT to the CCB if the SCB
+** initiated the close. It then checks to see if the SCB
+** is to be removed. If it is it deallocates the SCB. Finally,
+** it calls the application callback with a close indication.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_tc_close(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ UINT8 hdl = avdt_scb_to_hdl(p_scb);
+ tAVDT_CTRL_CBACK *p_ctrl_cback = p_scb->cs.p_ctrl_cback;
+ tAVDT_CTRL avdt_ctrl;
+ UINT8 event;
+ tAVDT_CCB *p_ccb = p_scb->p_ccb;
+ BD_ADDR remote_addr;
+
+
+ memcpy (remote_addr, p_ccb->peer_addr, BD_ADDR_LEN);
+
+ /* set up hdr */
+ avdt_ctrl.hdr.err_code = p_scb->close_code;
+
+ /* clear sep variables */
+ avdt_scb_clr_vars(p_scb, p_data);
+ p_scb->media_seq = 0;
+ p_scb->cong = FALSE;
+
+ /* free pkt we're holding, if any */
+ if (p_scb->p_pkt != NULL)
+ {
+ GKI_freebuf(p_scb->p_pkt);
+ p_scb->p_pkt = NULL;
+ }
+
+ /* stop transport channel timer */
+ btu_stop_timer(&p_scb->timer_entry);
+
+ if ((p_scb->role == AVDT_CLOSE_INT) || (p_scb->role == AVDT_OPEN_INT))
+ {
+ /* tell ccb we're done with signaling channel */
+ avdt_ccb_event(p_ccb, AVDT_CCB_UL_CLOSE_EVT, NULL);
+ }
+ event = (p_scb->role == AVDT_CLOSE_INT) ? AVDT_CLOSE_CFM_EVT : AVDT_CLOSE_IND_EVT;
+ p_scb->role = AVDT_CLOSE_ACP;
+
+ if (p_scb->remove)
+ {
+ avdt_scb_dealloc(p_scb, NULL);
+ }
+
+ /* call app callback */
+ (*p_ctrl_cback)(hdl, remote_addr, event, &avdt_ctrl);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_snd_delay_rpt_req
+**
+** Description This function calls the application callback with a delay
+** report.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_delay_rpt_req (tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_DELAY_RPT, (tAVDT_MSG *) &p_data->apidelay);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_delay_rpt_cmd
+**
+** Description This function calls the application callback with a delay
+** report.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_delay_rpt_cmd (tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+ p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL,
+ AVDT_DELAY_REPORT_EVT,
+ (tAVDT_CTRL *) &p_data->msg.hdr);
+
+ if (p_scb->p_ccb)
+ avdt_msg_send_rsp(p_scb->p_ccb, AVDT_SIG_DELAY_RPT, &p_data->msg);
+ else
+ avdt_scb_rej_not_in_use(p_scb, p_data);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_delay_rpt_rsp
+**
+** Description This function calls the application callback with a delay
+** report.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_delay_rpt_rsp (tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+ p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL,
+ AVDT_DELAY_REPORT_CFM_EVT,
+ (tAVDT_CTRL *) &p_data->msg.hdr);
+}
+
+#if AVDT_REPORTING == TRUE
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_tc_close_sto
+**
+** Description This function is called when a channel is closed in OPEN
+** state. Check the channel type and process accordingly.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_tc_close_sto(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ tAVDT_CTRL avdt_ctrl;
+ /* AVDT_CHAN_SIG does not visit this action */
+ if(p_data && p_data->close.type != AVDT_CHAN_MEDIA)
+ {
+ /* it's reporting or recovery channel,
+ * the channel close in open state means the peer does not support it */
+ if(p_data->close.old_tc_state == AVDT_AD_ST_OPEN)
+ {
+ avdt_ctrl.hdr.err_code = 0;
+ avdt_ctrl.hdr.err_param = 0;
+ /* call app callback */
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+ p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL,
+ AVDT_REPORT_DISCONN_EVT, &avdt_ctrl);
+ }
+ }
+ else
+ {
+ /* must be in OPEN state. need to go back to idle */
+ avdt_scb_event(p_scb, AVDT_SCB_MSG_ABORT_RSP_EVT, NULL);
+ avdt_scb_hdl_tc_close(p_scb, p_data);
+ }
+}
+#endif
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_tc_open
+**
+** Description This function is called when the transport channel is
+** opened while in the opening state. It calls the
+** application callback with an open indication or open
+** confirm depending on who initiated the open procedure.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_tc_open(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ UINT8 event;
+#if AVDT_REPORTING == TRUE
+ UINT8 role;
+#endif
+
+ /* stop transport channel connect timer */
+ btu_stop_timer(&p_scb->timer_entry);
+
+ event = (p_scb->role == AVDT_OPEN_INT) ? AVDT_OPEN_CFM_EVT : AVDT_OPEN_IND_EVT;
+ p_data->open.hdr.err_code = 0;
+
+ AVDT_TRACE_DEBUG3("psc_mask: cfg: 0x%x, req:0x%x, cur: 0x%x",
+ p_scb->cs.cfg.psc_mask, p_scb->req_cfg.psc_mask, p_scb->curr_cfg.psc_mask);
+#if AVDT_REPORTING == TRUE
+ if(p_scb->curr_cfg.psc_mask & AVDT_PSC_REPORT)
+ {
+ /* open the reporting channel, if both devices support it */
+ role = (p_scb->role == AVDT_OPEN_INT) ? AVDT_INT : AVDT_ACP;
+ avdt_ad_open_req(AVDT_CHAN_REPORT, p_scb->p_ccb, p_scb, role);
+ }
+#endif
+
+ /* call app callback */
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+ p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL,
+ event,
+ (tAVDT_CTRL *) &p_data->open);
+}
+
+#if AVDT_REPORTING == TRUE
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_tc_open_sto
+**
+** Description This function is called when the transport channel is
+** opened while in the opening state. It calls the
+** application callback with an open indication or open
+** confirm depending on who initiated the open procedure.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_tc_open_sto(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ tAVDT_CTRL avdt_ctrl;
+ /* open reporting channel here, when it is implemented */
+
+ /* call app callback */
+ if(p_data->open.hdr.err_code == AVDT_CHAN_REPORT)
+ {
+ avdt_ctrl.hdr.err_code = 0;
+ avdt_ctrl.hdr.err_param = 1;
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+ p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL,
+ AVDT_REPORT_CONN_EVT, &avdt_ctrl);
+ }
+}
+#endif
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_write_req_no_frag
+**
+** Description This function frees the media packet currently stored in
+** the SCB, if any. Then it builds a new media packet from
+** with the passed in buffer and stores it in the SCB.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_write_req_no_frag(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ UINT8 *p;
+ UINT32 ssrc;
+
+ /* free packet we're holding, if any; to be replaced with new */
+ if (p_scb->p_pkt != NULL)
+ {
+ GKI_freebuf(p_scb->p_pkt);
+
+ /* this shouldn't be happening */
+ AVDT_TRACE_WARNING0("Dropped media packet; congested");
+ }
+
+ /* build a media packet */
+
+ ssrc = avdt_scb_gen_ssrc(p_scb);
+
+ p_data->apiwrite.p_buf->len += AVDT_MEDIA_HDR_SIZE;
+ p_data->apiwrite.p_buf->offset -= AVDT_MEDIA_HDR_SIZE;
+
+ p = (UINT8 *)(p_data->apiwrite.p_buf + 1) + p_data->apiwrite.p_buf->offset;
+
+ UINT8_TO_BE_STREAM(p, AVDT_MEDIA_OCTET1);
+ UINT8_TO_BE_STREAM(p, p_data->apiwrite.m_pt);
+ UINT16_TO_BE_STREAM(p, p_scb->media_seq);
+ UINT32_TO_BE_STREAM(p, p_data->apiwrite.time_stamp);
+ UINT32_TO_BE_STREAM(p, ssrc);
+
+ p_scb->media_seq++;
+
+ /* store it */
+ p_scb->p_pkt = p_data->apiwrite.p_buf;
+}
+
+#if AVDT_MULTIPLEXING == TRUE
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_write_req_frag
+**
+** Description This function builds a new fragments of media packet from
+** the passed in buffers and stores them in the SCB.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_write_req_frag(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ UINT8 *p;
+ UINT32 ssrc;
+ BT_HDR *p_frag;
+
+ /* free fragments we're holding, if any; it shouldn't happen */
+ if (!GKI_queue_is_empty(&p_scb->frag_q))
+ {
+ while((p_frag = (BT_HDR*)GKI_dequeue (&p_scb->frag_q)) != NULL)
+ GKI_freebuf(p_frag);
+
+ /* this shouldn't be happening */
+ AVDT_TRACE_WARNING0("*** Dropped media packet; congested");
+ }
+
+ /* build a media fragments */
+ p_scb->frag_off = p_data->apiwrite.data_len;
+ p_scb->p_next_frag = p_data->apiwrite.p_data;
+
+ ssrc = avdt_scb_gen_ssrc(p_scb);
+
+ /* get first packet */
+ p_frag = (BT_HDR*)GKI_getfirst (&p_data->apiwrite.frag_q);
+ /* posit on Adaptation Layer header */
+ p_frag->len += AVDT_AL_HDR_SIZE + AVDT_MEDIA_HDR_SIZE;
+ p_frag->offset -= AVDT_AL_HDR_SIZE + AVDT_MEDIA_HDR_SIZE;
+ p = (UINT8 *)(p_frag + 1) + p_frag->offset;
+
+ /* Adaptation Layer header */
+ /* TSID, no-fragment bit and coding of length(in 2 length octets following) */
+ *p++ = (p_scb->curr_cfg.mux_tsid_media<<3) | AVDT_ALH_LCODE_16BIT;
+
+ /* length of all remaining transport packet */
+ UINT16_TO_BE_STREAM(p, p_frag->layer_specific+AVDT_MEDIA_HDR_SIZE );
+ /* media header */
+ UINT8_TO_BE_STREAM(p, AVDT_MEDIA_OCTET1);
+ UINT8_TO_BE_STREAM(p, p_data->apiwrite.m_pt);
+ UINT16_TO_BE_STREAM(p, p_scb->media_seq);
+ UINT32_TO_BE_STREAM(p, p_data->apiwrite.time_stamp);
+ UINT32_TO_BE_STREAM(p, ssrc);
+ p_scb->media_seq++;
+
+ while((p_frag = (BT_HDR*)GKI_getnext (p_frag)) != NULL)
+ {
+ /* posit on Adaptation Layer header */
+ p_frag->len += AVDT_AL_HDR_SIZE;
+ p_frag->offset -= AVDT_AL_HDR_SIZE;
+ p = (UINT8 *)(p_frag + 1) + p_frag->offset;
+ /* Adaptation Layer header */
+ /* TSID, fragment bit and coding of length(in 2 length octets following) */
+ *p++ = (p_scb->curr_cfg.mux_tsid_media<<3) | (AVDT_ALH_FRAG_MASK|AVDT_ALH_LCODE_16BIT);
+
+ /* length of all remaining transport packet */
+ UINT16_TO_BE_STREAM(p, p_frag->layer_specific );
+ }
+
+ /* store it */
+ p_scb->frag_q = p_data->apiwrite.frag_q;
+}
+#endif
+
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_write_req
+**
+** Description This function calls one of the two versions of building functions
+** for case with and without fragmentation
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_write_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+#if AVDT_MULTIPLEXING == TRUE
+ if (GKI_queue_is_empty(&p_data->apiwrite.frag_q))
+#endif
+ avdt_scb_hdl_write_req_no_frag(p_scb, p_data);
+#if AVDT_MULTIPLEXING == TRUE
+ else
+ avdt_scb_hdl_write_req_frag(p_scb, p_data);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_snd_abort_req
+**
+** Description This function sends an abort command message.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_abort_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ tAVDT_EVT_HDR hdr;
+
+ if (p_scb->p_ccb != NULL)
+ {
+ p_scb->role = AVDT_CLOSE_INT;
+
+ hdr.seid = p_scb->peer_seid;
+
+ avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_ABORT, (tAVDT_MSG *) &hdr);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_snd_abort_rsp
+**
+** Description This function sends an abort response message.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_abort_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ avdt_msg_send_rsp(avdt_ccb_by_idx(p_data->msg.hdr.ccb_idx), AVDT_SIG_ABORT,
+ &p_data->msg);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_snd_close_req
+**
+** Description This function sends a close command message.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_close_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ tAVDT_EVT_HDR hdr;
+
+ p_scb->role = AVDT_CLOSE_INT;
+
+ hdr.seid = p_scb->peer_seid;
+
+ avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_CLOSE, (tAVDT_MSG *) &hdr);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_snd_stream_close
+**
+** Description This function sends a close command message.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_stream_close(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+#if AVDT_MULTIPLEXING == TRUE
+ BT_HDR *p_frag;
+
+ AVDT_TRACE_WARNING2("avdt_scb_snd_stream_close c:%d, off:%d",
+ p_scb->frag_q.count, p_scb->frag_off);
+ /* clean fragments queue */
+ while((p_frag = (BT_HDR*)GKI_dequeue (&p_scb->frag_q)) != NULL)
+ GKI_freebuf(p_frag);
+ p_scb->frag_off = 0;
+#endif
+ if (p_scb->p_pkt)
+ {
+ GKI_freebuf(p_scb->p_pkt);
+ p_scb->p_pkt = NULL;
+ }
+
+#if 0
+ if(p_scb->cong)
+ p_scb->cong = FALSE;
+
+ /* p_scb->curr_cfg.mux_tsid_media == 0 */
+#endif
+ avdt_scb_snd_close_req(p_scb, p_data);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_snd_close_rsp
+**
+** Description This function sends a close response message.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_close_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ avdt_msg_send_rsp(p_scb->p_ccb, AVDT_SIG_CLOSE, &p_data->msg);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_snd_getconfig_req
+**
+** Description This function sends a get configuration command message.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_getconfig_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ tAVDT_EVT_HDR hdr;
+
+ hdr.seid = p_scb->peer_seid;
+
+ avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_GETCONFIG, (tAVDT_MSG *) &hdr);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_snd_getconfig_rsp
+**
+** Description This function sends a get configuration response message.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_getconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ avdt_msg_send_rsp(p_scb->p_ccb, AVDT_SIG_GETCONFIG, &p_data->msg);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_snd_open_req
+**
+** Description This function sends an open command message.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_open_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ tAVDT_EVT_HDR hdr;
+
+ hdr.seid = p_scb->peer_seid;
+
+ avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_OPEN, (tAVDT_MSG *) &hdr);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_snd_open_rsp
+**
+** Description This function sends an open response message. It also
+** calls avdt_ad_open_req() to accept a transport channel
+** connection.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_open_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ /* notify adaption that we're waiting for transport channel open */
+ p_scb->role = AVDT_OPEN_ACP;
+ avdt_ad_open_req(AVDT_CHAN_MEDIA, p_scb->p_ccb, p_scb, AVDT_ACP);
+
+ /* send response */
+ avdt_msg_send_rsp(p_scb->p_ccb, AVDT_SIG_OPEN, &p_data->msg);
+
+ /* start tc connect timer */
+ btu_start_timer(&p_scb->timer_entry, BTU_TTYPE_AVDT_SCB_TC, AVDT_SCB_TC_CONN_TOUT);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_snd_reconfig_req
+**
+** Description This function stores the configuration parameters in the
+** SCB and sends a reconfiguration command message.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_reconfig_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ memcpy(&p_scb->req_cfg, p_data->msg.config_cmd.p_cfg, sizeof(tAVDT_CFG));
+ p_data->msg.hdr.seid = p_scb->peer_seid;
+ avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_RECONFIG, &p_data->msg);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_snd_reconfig_rsp
+**
+** Description This function stores the configuration parameters in the
+** SCB and sends a reconfiguration response message.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_reconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ if (p_data->msg.hdr.err_code == 0)
+ {
+ /* store new configuration */
+ if (p_scb->req_cfg.num_codec > 0)
+ {
+ p_scb->curr_cfg.num_codec = p_scb->req_cfg.num_codec;
+ memcpy(p_scb->curr_cfg.codec_info, p_scb->req_cfg.codec_info, AVDT_CODEC_SIZE);
+ }
+ if (p_scb->req_cfg.num_protect > 0)
+ {
+ p_scb->curr_cfg.num_protect = p_scb->req_cfg.num_protect;
+ memcpy(p_scb->curr_cfg.protect_info, p_scb->req_cfg.protect_info, AVDT_PROTECT_SIZE);
+ }
+
+ /* send response */
+ avdt_msg_send_rsp(p_scb->p_ccb, AVDT_SIG_RECONFIG, &p_data->msg);
+ }
+ else
+ {
+ /* send reject */
+ avdt_msg_send_rej(p_scb->p_ccb, AVDT_SIG_RECONFIG, &p_data->msg);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_snd_security_req
+**
+** Description This function sends a security command message.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_security_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ p_data->msg.hdr.seid = p_scb->peer_seid;
+ avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_SECURITY, &p_data->msg);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_snd_security_rsp
+**
+** Description This function sends a security response message.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_security_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ if (p_data->msg.hdr.err_code == 0)
+ {
+ avdt_msg_send_rsp(p_scb->p_ccb, AVDT_SIG_SECURITY, &p_data->msg);
+ }
+ else
+ {
+ avdt_msg_send_rej(p_scb->p_ccb, AVDT_SIG_SECURITY, &p_data->msg);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_snd_setconfig_rej
+**
+** Description This function marks the SCB as not in use and sends a
+** set configuration reject message.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_setconfig_rej(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ if (p_scb->p_ccb != NULL)
+ {
+ avdt_msg_send_rej(p_scb->p_ccb, AVDT_SIG_SETCONFIG, &p_data->msg);
+
+ /* clear scb variables */
+ avdt_scb_clr_vars(p_scb, p_data);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_snd_setconfig_req
+**
+** Description This function marks the SCB as in use and copies the
+** configuration parameters to the SCB. Then the function
+** sends a set configuration command message and initiates
+** opening of the signaling channel.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_setconfig_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ tAVDT_CFG *p_req, *p_cfg;
+
+ /* copy API parameters to scb, set scb as in use */
+ p_scb->in_use = TRUE;
+ p_scb->p_ccb = avdt_ccb_by_idx(p_data->msg.config_cmd.hdr.ccb_idx);
+ p_scb->peer_seid = p_data->msg.config_cmd.hdr.seid;
+ p_req = p_data->msg.config_cmd.p_cfg;
+ p_cfg = &p_scb->cs.cfg;
+#if AVDT_MULTIPLEXING == TRUE
+ p_req->mux_tsid_media = p_cfg->mux_tsid_media;
+ p_req->mux_tcid_media = p_cfg->mux_tcid_media;
+ if(p_req->psc_mask & AVDT_PSC_REPORT)
+ {
+ p_req->mux_tsid_report = p_cfg->mux_tsid_report;
+ p_req->mux_tcid_report = p_cfg->mux_tcid_report;
+ }
+#endif
+ memcpy(&p_scb->req_cfg, p_data->msg.config_cmd.p_cfg, sizeof(tAVDT_CFG));
+
+ avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_SETCONFIG, &p_data->msg);
+
+ /* tell ccb to open channel */
+ avdt_ccb_event(p_scb->p_ccb, AVDT_CCB_UL_OPEN_EVT, NULL);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_snd_setconfig_rsp
+**
+** Description This function copies the requested configuration into the
+** current configuration and sends a set configuration
+** response message.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_setconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ if (p_scb->p_ccb != NULL)
+ {
+ memcpy(&p_scb->curr_cfg, &p_scb->req_cfg, sizeof(tAVDT_CFG));
+
+ avdt_msg_send_rsp(p_scb->p_ccb, AVDT_SIG_SETCONFIG, &p_data->msg);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_snd_tc_close
+**
+** Description This function calls avdt_ad_close_req() to close the
+** transport channel for this SCB.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_tc_close(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+#if AVDT_REPORTING == TRUE
+ if(p_scb->curr_cfg.psc_mask & AVDT_PSC_REPORT)
+ avdt_ad_close_req(AVDT_CHAN_REPORT, p_scb->p_ccb, p_scb);
+#endif
+ avdt_ad_close_req(AVDT_CHAN_MEDIA, p_scb->p_ccb, p_scb);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_cb_err
+**
+** Description This function calls the application callback function
+** indicating an error.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_cb_err(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ tAVDT_CTRL avdt_ctrl;
+
+ /* set error code and parameter */
+ avdt_ctrl.hdr.err_code = AVDT_ERR_BAD_STATE;
+ avdt_ctrl.hdr.err_param = 0;
+
+ /* call callback, using lookup table to get callback event */
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+ NULL,
+ avdt_scb_cback_evt[p_scb->curr_evt],
+ &avdt_ctrl);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_cong_state
+**
+** Description This function sets the congestion state of the SCB media
+** transport channel.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_cong_state(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ p_scb->cong = p_data->llcong;
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_rej_state
+**
+** Description This function sends a reject message to the peer indicating
+** incorrect state for the received command message.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_rej_state(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ p_data->msg.hdr.err_code = AVDT_ERR_BAD_STATE;
+ p_data->msg.hdr.err_param = 0;
+ avdt_msg_send_rej(avdt_ccb_by_idx(p_data->msg.hdr.ccb_idx),
+ p_data->msg.hdr.sig_id, &p_data->msg);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_rej_in_use
+**
+** Description This function sends a reject message to the peer indicating
+** the stream is in use.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_rej_in_use(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ p_data->msg.hdr.err_code = AVDT_ERR_IN_USE;
+ p_data->msg.hdr.err_param = 0;
+ avdt_msg_send_rej(avdt_ccb_by_idx(p_data->msg.hdr.ccb_idx),
+ p_data->msg.hdr.sig_id, &p_data->msg);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_rej_not_in_use
+**
+** Description This function sends a reject message to the peer indicating
+** the stream is in use.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_rej_not_in_use(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ p_data->msg.hdr.err_code = AVDT_ERR_NOT_IN_USE;
+ p_data->msg.hdr.err_param = 0;
+ avdt_msg_send_rej(avdt_ccb_by_idx(p_data->msg.hdr.ccb_idx),
+ p_data->msg.hdr.sig_id, &p_data->msg);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_set_remove
+**
+** Description This function marks an SCB to be removed.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_set_remove(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ p_scb->remove = TRUE;
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_free_pkt
+**
+** Description This function frees the media packet passed in.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_free_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ tAVDT_CTRL avdt_ctrl;
+#if AVDT_MULTIPLEXING == TRUE
+ BT_HDR *p_frag;
+#endif
+
+ /* set error code and parameter */
+ avdt_ctrl.hdr.err_code = AVDT_ERR_BAD_STATE;
+ avdt_ctrl.hdr.err_param = 0;
+
+ /* p_buf can be NULL in case using of fragments queue frag_q */
+ if(p_data->apiwrite.p_buf)
+ GKI_freebuf(p_data->apiwrite.p_buf);
+
+#if AVDT_MULTIPLEXING == TRUE
+ /* clean fragments queue */
+ while((p_frag = (BT_HDR*)GKI_dequeue (&p_data->apiwrite.frag_q)) != NULL)
+ GKI_freebuf(p_frag);
+#endif
+
+ AVDT_TRACE_WARNING0("Dropped media packet");
+
+ /* we need to call callback to keep data flow going */
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), NULL, AVDT_WRITE_CFM_EVT,
+ &avdt_ctrl);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_clr_pkt
+**
+** Description This function frees the media packet stored in the SCB.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_clr_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ tAVDT_CTRL avdt_ctrl;
+ tAVDT_CCB *p_ccb;
+ UINT8 tcid;
+ UINT16 lcid;
+#if AVDT_MULTIPLEXING == TRUE
+ BT_HDR *p_frag;
+#endif
+
+ /* set error code and parameter */
+ avdt_ctrl.hdr.err_code = AVDT_ERR_BAD_STATE;
+ avdt_ctrl.hdr.err_param = 0;
+ /* flush the media data queued at L2CAP */
+ if((p_ccb = p_scb->p_ccb) != NULL)
+ {
+ /* get tcid from type, scb */
+ tcid = avdt_ad_type_to_tcid(AVDT_CHAN_MEDIA, p_scb);
+
+ lcid = avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid;
+ L2CA_FlushChannel (lcid, L2CAP_FLUSH_CHANS_ALL);
+ }
+
+ if (p_scb->p_pkt != NULL)
+ {
+ GKI_freebuf(p_scb->p_pkt);
+ p_scb->p_pkt = NULL;
+
+ AVDT_TRACE_DEBUG0("Dropped stored media packet");
+
+ /* we need to call callback to keep data flow going */
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), NULL, AVDT_WRITE_CFM_EVT,
+ &avdt_ctrl);
+ }
+#if AVDT_MULTIPLEXING == TRUE
+ else if(!GKI_queue_is_empty (&p_scb->frag_q))
+ {
+ AVDT_TRACE_DEBUG0("Dropped fragments queue");
+ /* clean fragments queue */
+ while((p_frag = (BT_HDR*)GKI_dequeue (&p_scb->frag_q)) != NULL)
+ GKI_freebuf(p_frag);
+
+ p_scb->frag_off = 0;
+
+ /* we need to call callback to keep data flow going */
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), NULL, AVDT_WRITE_CFM_EVT,
+ &avdt_ctrl);
+ }
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function avdt_scb_chk_snd_pkt
+**
+** Description This function checks if the SCB is congested, and if not
+** congested it sends a stored media packet, if any. After it
+** sends the packet it calls the application callback function
+** with a write confirm.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_chk_snd_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ tAVDT_CTRL avdt_ctrl;
+ BT_HDR *p_pkt;
+#if AVDT_MULTIPLEXING == TRUE
+ BOOLEAN sent = FALSE;
+ UINT8 res = AVDT_AD_SUCCESS;
+ tAVDT_SCB_EVT data;
+#endif
+
+ avdt_ctrl.hdr.err_code = 0;
+
+ if (!p_scb->cong)
+ {
+ if (p_scb->p_pkt != NULL)
+ {
+ p_pkt = p_scb->p_pkt;
+ p_scb->p_pkt = NULL;
+ avdt_ad_write_req(AVDT_CHAN_MEDIA, p_scb->p_ccb, p_scb, p_pkt);
+
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), NULL, AVDT_WRITE_CFM_EVT, &avdt_ctrl);
+ }
+#if AVDT_MULTIPLEXING == TRUE
+ else
+ {
+#if 0
+ AVDT_TRACE_DEBUG1("num_q=%d",
+ L2CA_FlushChannel(avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_scb->p_ccb)][avdt_ad_type_to_tcid(AVDT_CHAN_MEDIA, p_scb)].lcid),
+ L2CAP_FLUSH_CHANS_GET);
+#endif
+ while((p_pkt = (BT_HDR*)GKI_dequeue (&p_scb->frag_q)) != NULL)
+ {
+ sent = TRUE;
+ AVDT_TRACE_DEBUG1("Send fragment len=%d",p_pkt->len);
+ /* fragments queue contains fragment to send */
+ res = avdt_ad_write_req(AVDT_CHAN_MEDIA, p_scb->p_ccb, p_scb, p_pkt);
+ if(AVDT_AD_CONGESTED == res)
+ {
+ p_scb->cong = TRUE;
+ AVDT_TRACE_DEBUG0("avdt/l2c congested!!");
+ break;/* exit loop if channel became congested */
+ }
+ }
+ AVDT_TRACE_DEBUG2("res=%d left=%d",res, p_scb->frag_off);
+
+ if(p_scb->frag_off)
+ {
+ if(AVDT_AD_SUCCESS == res || GKI_queue_is_empty (&p_scb->frag_q))
+ {
+ /* all buffers were sent to L2CAP, compose more to queue */
+ avdt_scb_queue_frags(p_scb, &p_scb->p_next_frag, &p_scb->frag_off, &p_scb->frag_q);
+ if(!GKI_queue_is_empty (&p_scb->frag_q))
+ {
+ data.llcong = p_scb->cong;
+ avdt_scb_event(p_scb, AVDT_SCB_TC_CONG_EVT, &data);
+ }
+ }
+ }
+
+ /* Send event AVDT_WRITE_CFM_EVT if it was last fragment */
+ else if (sent && GKI_queue_is_empty (&p_scb->frag_q))
+ {
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), NULL, AVDT_WRITE_CFM_EVT, &avdt_ctrl);
+ }
+ }
+#endif
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_tc_timer
+**
+** Description This function is called to start a timer when the peer
+** initiates closing of the stream. The timer verifies that
+** the peer disconnects the transport channel.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_tc_timer(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ btu_start_timer(&p_scb->timer_entry, BTU_TTYPE_AVDT_SCB_TC, AVDT_SCB_TC_DISC_TOUT);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_clr_vars
+**
+** Description This function initializes certain SCB variables.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_clr_vars(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ p_scb->in_use = FALSE;
+ p_scb->p_ccb = NULL;
+ p_scb->peer_seid = 0;
+}
+
+#if AVDT_MULTIPLEXING == TRUE
+/*******************************************************************************
+**
+** Function avdt_scb_queue_frags
+**
+** Description This function breaks media payload into fragments
+** and put the fragments in the given queue.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_queue_frags(tAVDT_SCB *p_scb, UINT8 **pp_data, UINT32 *p_data_len, BUFFER_Q *pq)
+{
+ UINT16 lcid;
+ UINT16 num_frag;
+ UINT16 mtu_used;
+ UINT8 *p;
+ BOOLEAN al_hdr = FALSE;
+ UINT8 tcid;
+ tAVDT_TC_TBL *p_tbl;
+ UINT16 buf_size;
+ UINT16 offset = AVDT_MEDIA_OFFSET + AVDT_AL_HDR_SIZE;
+ UINT16 cont_offset = offset - AVDT_MEDIA_HDR_SIZE;
+ BT_HDR *p_frag;
+
+ tcid = avdt_ad_type_to_tcid(AVDT_CHAN_MEDIA, p_scb);
+ lcid = avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_scb->p_ccb)][tcid].lcid;
+
+ if( p_scb->frag_off != 0)
+ {
+ /* continuing process is usually triggered by un-congest event.
+ * the number of buffers at L2CAP is very small (if not 0).
+ * we do not need to L2CA_FlushChannel() */
+ offset = cont_offset;
+ al_hdr = TRUE;
+ num_frag = AVDT_MAX_FRAG_COUNT;
+ }
+ else
+ {
+ num_frag = L2CA_FlushChannel(lcid, L2CAP_FLUSH_CHANS_GET);
+ AVDT_TRACE_DEBUG2("num_q=%d lcid=%d", num_frag, lcid);
+ if(num_frag >= AVDT_MAX_FRAG_COUNT)
+ {
+ num_frag = 0;
+ }
+ else
+ {
+ num_frag = AVDT_MAX_FRAG_COUNT - num_frag;
+ }
+ }
+
+ /* look up transport channel table entry to get peer mtu */
+ p_tbl = avdt_ad_tc_tbl_by_type(AVDT_CHAN_MEDIA, p_scb->p_ccb, p_scb);
+ buf_size = p_tbl->peer_mtu + BT_HDR_SIZE;
+ AVDT_TRACE_DEBUG3("peer_mtu: %d, buf_size: %d num_frag=%d",
+ p_tbl->peer_mtu, buf_size, num_frag);
+
+ if(buf_size > AVDT_DATA_POOL_SIZE)
+ buf_size = AVDT_DATA_POOL_SIZE;
+
+ mtu_used = buf_size - BT_HDR_SIZE;
+
+ while(*p_data_len && num_frag)
+ {
+ /* allocate buffer for fragment */
+ if(NULL == (p_frag = (BT_HDR*)GKI_getbuf(buf_size)))
+ {
+ AVDT_TRACE_WARNING1("avdt_scb_queue_frags len=%d(out of GKI buffers)",*p_data_len);
+ break;
+ }
+ /* fill fragment by chunk of media payload */
+ p_frag->layer_specific = *p_data_len;/* length of all remaining transport packet */
+ p_frag->offset = offset;
+ /* adjust packet offset for continuing packets */
+ offset = cont_offset;
+
+ p_frag->len = mtu_used - p_frag->offset;
+ if(p_frag->len > *p_data_len)
+ p_frag->len = *p_data_len;
+ memcpy((UINT8*)(p_frag+1) + p_frag->offset, *pp_data, p_frag->len);
+ *pp_data += p_frag->len;
+ *p_data_len -= p_frag->len;
+ AVDT_TRACE_DEBUG1("Prepared fragment len=%d", p_frag->len);
+
+ if(al_hdr)
+ {
+ /* Adaptation Layer header */
+ p_frag->len += AVDT_AL_HDR_SIZE;
+ p_frag->offset -= AVDT_AL_HDR_SIZE;
+ p = (UINT8 *)(p_frag + 1) + p_frag->offset;
+ /* TSID, fragment bit and coding of length(in 2 length octets following) */
+ *p++ = (p_scb->curr_cfg.mux_tsid_media<<3) | (AVDT_ALH_FRAG_MASK|AVDT_ALH_LCODE_16BIT);
+
+ /* length of all remaining transport packet */
+ UINT16_TO_BE_STREAM(p, p_frag->layer_specific );
+ }
+ /* put fragment into gueue */
+ GKI_enqueue(pq, p_frag);
+ num_frag--;
+ }
+}
+#endif
+
diff --git a/stack/avrc/avrc_api.c b/stack/avrc/avrc_api.c
new file mode 100644
index 0000000..dd7e752
--- /dev/null
+++ b/stack/avrc/avrc_api.c
@@ -0,0 +1,1132 @@
+/*****************************************************************************
+**
+** Name: avrc_api.c
+**
+** Description:Interface to AVRCP mandatory commands
+**
+** Copyright (c) 2003-2010, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include <string.h>
+
+#include "gki.h"
+#include "avrc_api.h"
+#include "avrc_int.h"
+#include "wcassert.h"
+
+/*****************************************************************************
+** Global data
+*****************************************************************************/
+
+
+#define AVRC_MAX_RCV_CTRL_EVT AVCT_BROWSE_UNCONG_IND_EVT
+
+static const UINT8 avrc_ctrl_event_map[] =
+{
+ AVRC_OPEN_IND_EVT, /* AVCT_CONNECT_CFM_EVT */
+ AVRC_OPEN_IND_EVT, /* AVCT_CONNECT_IND_EVT */
+ AVRC_CLOSE_IND_EVT, /* AVCT_DISCONNECT_CFM_EVT */
+ AVRC_CLOSE_IND_EVT, /* AVCT_DISCONNECT_IND_EVT */
+ AVRC_CONG_IND_EVT, /* AVCT_CONG_IND_EVT */
+ AVRC_UNCONG_IND_EVT,/* AVCT_UNCONG_IND_EVT */
+ AVRC_BROWSE_OPEN_IND_EVT, /* AVCT_BROWSE_CONN_CFM_EVT */
+ AVRC_BROWSE_OPEN_IND_EVT, /* AVCT_BROWSE_CONN_IND_EVT */
+ AVRC_BROWSE_CLOSE_IND_EVT, /* AVCT_BROWSE_DISCONN_CFM_EVT */
+ AVRC_BROWSE_CLOSE_IND_EVT, /* AVCT_BROWSE_DISCONN_IND_EVT */
+ AVRC_BROWSE_CONG_IND_EVT, /* AVCT_BROWSE_CONG_IND_EVT */
+ AVRC_BROWSE_UNCONG_IND_EVT /* AVCT_BROWSE_UNCONG_IND_EVT */
+};
+
+#define AVRC_OP_DROP 0xFE /* use this unused opcode to indication no need to call the callback function */
+#define AVRC_OP_DROP_N_FREE 0xFD /* use this unused opcode to indication no need to call the callback function & free buffer */
+
+/******************************************************************************
+**
+** Function avrc_ctrl_cback
+**
+** Description This is the callback function used by AVCTP to report
+** received link events.
+**
+** Returns Nothing.
+**
+******************************************************************************/
+static void avrc_ctrl_cback(UINT8 handle, UINT8 event, UINT16 result,
+ BD_ADDR peer_addr)
+{
+ UINT8 avrc_event;
+
+ if (event <= AVRC_MAX_RCV_CTRL_EVT && avrc_cb.ccb[handle].p_ctrl_cback)
+ {
+ avrc_event = avrc_ctrl_event_map[event];
+ if (event == AVCT_CONNECT_CFM_EVT)
+ {
+ if (result != 0) /* failed */
+ avrc_event = AVRC_CLOSE_IND_EVT;
+ }
+ (*avrc_cb.ccb[handle].p_ctrl_cback)(handle, avrc_event, result, peer_addr);
+ }
+ /* else drop the unknown event*/
+}
+
+/******************************************************************************
+**
+** Function avrc_get_data_ptr
+**
+** Description If the offset in the received buffer is smaller than required
+** move the portion of data AVRC cares.
+**
+** Returns Nothing.
+**
+******************************************************************************/
+static UINT8 * avrc_get_data_ptr(BT_HDR *p_pkt)
+{
+ UINT8 *p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset;
+ int i, gap;
+
+ if (p_pkt->offset < AVCT_MSG_OFFSET)
+ {
+ gap = AVCT_MSG_OFFSET - p_pkt->offset;
+ for(i=p_pkt->len; i>0; i--)
+ {
+ *(p_data + i + gap) = *(p_data + i);
+ }
+ p_pkt->offset += gap;
+ p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset;
+ }
+ *p_data = AVRC_RSP_IMPL_STBL;
+ return p_data;
+}
+
+#if (AVRC_METADATA_INCLUDED == TRUE)
+/******************************************************************************
+**
+** Function avrc_prep_end_frag
+**
+** Description This function prepares an end response fragment
+**
+**
+** Returns Nothing.
+**
+******************************************************************************/
+static void avrc_prep_end_frag(UINT8 handle)
+{
+ tAVRC_FRAG_CB *p_fcb;
+ BT_HDR *p_pkt_new;
+ UINT8 *p_data;
+
+ AVRC_TRACE_DEBUG0 ("avrc_prep_end_frag" );
+ p_fcb = &avrc_cb.fcb[handle];
+ p_pkt_new = p_fcb->p_fmsg;
+ p_pkt_new->len -= (AVRC_MAX_CTRL_DATA_LEN - AVRC_VENDOR_HDR_SIZE - AVRC_MIN_META_HDR_SIZE);
+ p_pkt_new->offset += (AVRC_MAX_CTRL_DATA_LEN - AVRC_VENDOR_HDR_SIZE - AVRC_MIN_META_HDR_SIZE);
+ p_data = (UINT8 *)(p_pkt_new+1) + p_pkt_new->offset;
+ *p_data++ = (AVRC_RSP_ACCEPT & AVRC_CTYPE_MASK);
+ *p_data++ = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT);
+ *p_data++ = AVRC_OP_VENDOR;
+ AVRC_CO_ID_TO_BE_STREAM(p_data, AVRC_CO_METADATA);
+ *p_data++ = p_fcb->frag_pdu;
+ *p_data++ = AVRC_PKT_END;
+ UINT16_TO_BE_STREAM(p_data, (p_pkt_new->len - AVRC_VENDOR_HDR_SIZE - AVRC_MIN_META_HDR_SIZE)); /* 4=pdu, pkt_type & len */
+}
+
+/******************************************************************************
+**
+** Function avrc_send_continue_frag
+**
+** Description This function sends a continue response fragment
+**
+**
+** Returns Nothing.
+**
+******************************************************************************/
+static void avrc_send_continue_frag(UINT8 handle, UINT8 label)
+{
+ tAVRC_FRAG_CB *p_fcb;
+ BT_HDR *p_pkt_old, *p_pkt;
+ UINT8 *p_old, *p_data;
+ UINT8 cr = AVCT_RSP;
+ tAVRC_RSP rej_rsp;
+
+ p_fcb = &avrc_cb.fcb[handle];
+ p_pkt = p_fcb->p_fmsg;
+
+ AVRC_TRACE_DEBUG1 ("avrc_send_continue_frag len(%d) / AVRC_MAX_CTRL_DATA_LEN", p_pkt->len );
+ if (p_pkt->len > AVRC_MAX_CTRL_DATA_LEN)
+ {
+ p_pkt_old = p_fcb->p_fmsg;
+ p_pkt = (BT_HDR *)GKI_getbuf((UINT16)(AVRC_PACKET_LEN + AVCT_MSG_OFFSET + BT_HDR_SIZE));
+ if (p_pkt)
+ {
+ p_pkt->len = AVRC_MAX_CTRL_DATA_LEN;
+ p_pkt->offset = AVCT_MSG_OFFSET;
+ p_pkt->layer_specific = p_pkt_old->layer_specific;
+ p_pkt->event = p_pkt_old->event;
+ p_old = (UINT8 *)(p_pkt_old+1) + p_pkt_old->offset;
+ p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset;
+ memcpy (p_data, p_old, AVRC_MAX_CTRL_DATA_LEN);
+ /* use AVRC continue packet type */
+ p_data += AVRC_VENDOR_HDR_SIZE;
+ p_data++; /* pdu */
+ *p_data++ = AVRC_PKT_CONTINUE;
+ UINT16_TO_BE_STREAM(p_data, (AVRC_MAX_CTRL_DATA_LEN - AVRC_VENDOR_HDR_SIZE - 4)); /* 4=pdu, pkt_type & len */
+
+ /* prepare the left over for as an end fragment */
+ avrc_prep_end_frag (handle);
+ }
+ else
+ {
+ /* use the current GKI buffer to send Internal error status */
+ p_pkt = p_fcb->p_fmsg;
+ p_fcb->p_fmsg = NULL;
+ p_fcb->frag_enabled = FALSE;
+ AVRC_TRACE_ERROR0 ("AVRC_MsgReq no buffers for fragmentation - send internal error" );
+ p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset;
+ *p_data++ = AVRC_PDU_REQUEST_CONTINUATION_RSP;
+ *p_data++ = 0;
+ UINT16_TO_BE_STREAM(p_data, 0);
+ p_pkt->len = 4;
+ rej_rsp.pdu = AVRC_PDU_REQUEST_CONTINUATION_RSP;
+ rej_rsp.status = AVRC_STS_INTERNAL_ERR;
+ AVRC_BldResponse( handle, (tAVRC_RESPONSE *)&rej_rsp, &p_pkt);
+ cr = AVCT_RSP;
+ }
+ }
+ else
+ {
+ /* end fragment. clean the control block */
+ p_fcb->frag_enabled = FALSE;
+ p_fcb->p_fmsg = NULL;
+ }
+ AVCT_MsgReq( handle, label, cr, p_pkt);
+}
+
+/******************************************************************************
+**
+** Function avrc_proc_vendor_command
+**
+** Description This function processes received vendor command.
+**
+**
+** Returns if not NULL, the response to send right away.
+**
+******************************************************************************/
+static BT_HDR * avrc_proc_vendor_command(UINT8 handle, UINT8 label,
+ BT_HDR *p_pkt, tAVRC_MSG_VENDOR *p_msg)
+{
+ BT_HDR *p_rsp = NULL;
+ UINT8 *p_data;
+ UINT8 *p_begin;
+ UINT8 pkt_type;
+ BOOLEAN abort_frag = FALSE;
+ tAVRC_STS status = AVRC_STS_NO_ERROR;
+ tAVRC_FRAG_CB *p_fcb;
+
+ p_begin = (UINT8 *)(p_pkt+1) + p_pkt->offset;
+ p_data = p_begin + AVRC_VENDOR_HDR_SIZE;
+ pkt_type = *(p_data + 1) & AVRC_PKT_TYPE_MASK;
+
+ if (pkt_type != AVRC_PKT_SINGLE)
+ {
+ /* reject - commands can only be in single packets at AVRCP level */
+ AVRC_TRACE_ERROR1 ("commands must be in single packet pdu:0x%x", *p_data );
+ /* use the current GKI buffer to send the reject */
+ status = AVRC_STS_BAD_CMD;
+ }
+ /* check if there are fragments waiting to be sent */
+ else if (avrc_cb.fcb[handle].frag_enabled)
+ {
+ p_fcb = &avrc_cb.fcb[handle];
+ if (p_msg->company_id == AVRC_CO_METADATA)
+ {
+ switch (*p_data)
+ {
+ case AVRC_PDU_ABORT_CONTINUATION_RSP:
+ /* aborted by CT - send accept response */
+ abort_frag = TRUE;
+ p_begin = (UINT8 *)(p_pkt+1) + p_pkt->offset;
+ *p_begin = (AVRC_RSP_ACCEPT & AVRC_CTYPE_MASK);
+ if (*(p_data + 4) != p_fcb->frag_pdu)
+ {
+ *p_begin = (AVRC_RSP_REJ & AVRC_CTYPE_MASK);
+ *(p_data + 4) = AVRC_STS_BAD_PARAM;
+ }
+ else
+ {
+ p_data = (p_begin + AVRC_VENDOR_HDR_SIZE + 2);
+ UINT16_TO_BE_STREAM(p_data, 0);
+ p_pkt->len = (p_data - p_begin);
+ }
+ AVCT_MsgReq( handle, label, AVCT_RSP, p_pkt);
+ p_msg->hdr.opcode = AVRC_OP_DROP; /* used the p_pkt to send response */
+ break;
+
+ case AVRC_PDU_REQUEST_CONTINUATION_RSP:
+ if (*(p_data + 4) == p_fcb->frag_pdu)
+ {
+ avrc_send_continue_frag(handle, label);
+ p_msg->hdr.opcode = AVRC_OP_DROP_N_FREE;
+ }
+ else
+ {
+ /* the pdu id does not match - reject the command using the current GKI buffer */
+ AVRC_TRACE_ERROR2("avrc_proc_vendor_command continue pdu: 0x%x does not match current re-assembly pdu: 0x%x",
+ *(p_data + 4), p_fcb->frag_pdu);
+ status = AVRC_STS_BAD_PARAM;
+ abort_frag = TRUE;
+ }
+ break;
+
+ default:
+ /* implicit abort */
+ abort_frag = TRUE;
+ }
+ }
+ else
+ {
+ abort_frag = TRUE;
+ /* implicit abort */
+ }
+
+ if (abort_frag)
+ {
+ if (p_fcb->p_fmsg)
+ GKI_freebuf(p_fcb->p_fmsg);
+ p_fcb->p_fmsg = NULL;
+ p_fcb->frag_enabled = FALSE;
+ }
+ }
+
+ if (status != AVRC_STS_NO_ERROR)
+ {
+ /* use the current GKI buffer to build/send the reject message */
+ p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset;
+ *p_data++ = AVRC_RSP_REJ;
+ p_data += AVRC_VENDOR_HDR_SIZE; /* pdu */
+ *p_data++ = 0; /* pkt_type */
+ UINT16_TO_BE_STREAM(p_data, 1); /* len */
+ *p_data++ = status; /* error code */
+ p_pkt->len = AVRC_VENDOR_HDR_SIZE + 5;
+ p_rsp = p_pkt;
+ }
+
+ return p_rsp;
+}
+
+/******************************************************************************
+**
+** Function avrc_proc_far_msg
+**
+** Description This function processes vendor command/response fragmetation
+** and reassembly
+**
+** Returns 0, to report the message with msg_cback .
+**
+******************************************************************************/
+static UINT8 avrc_proc_far_msg(UINT8 handle, UINT8 label, UINT8 cr, BT_HDR **pp_pkt, tAVRC_MSG_VENDOR *p_msg)
+{
+ BT_HDR *p_pkt = *pp_pkt;
+ UINT8 *p_data;
+ BOOLEAN drop = FALSE;
+ BT_HDR *p_rsp = NULL;
+ BT_HDR *p_cmd = NULL;
+ BOOLEAN req_continue = FALSE;
+ BT_HDR *p_pkt_new = NULL;
+ UINT8 pkt_type;
+ UINT16 buf_len;
+ tAVRC_RASM_CB *p_rcb;
+ tAVRC_NEXT_CMD avrc_cmd;
+
+ p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset;
+ pkt_type = *(p_data + 1) & AVRC_PKT_TYPE_MASK;
+ AVRC_TRACE_DEBUG1 ("pkt_type %d", pkt_type );
+ p_rcb = &avrc_cb.rcb[handle];
+ if (p_msg->company_id == AVRC_CO_METADATA)
+ {
+ /* check if the message needs to be re-assembled */
+ if (pkt_type == AVRC_PKT_SINGLE || pkt_type == AVRC_PKT_START)
+ {
+ /* previous fragments need to be dropped, when received another new message */
+ p_rcb->rasm_offset = 0;
+ if (p_rcb->p_rmsg)
+ {
+ GKI_freebuf(p_rcb->p_rmsg);
+ p_rcb->p_rmsg = NULL;
+ }
+ }
+
+ if (pkt_type != AVRC_PKT_SINGLE && cr == AVCT_RSP)
+ {
+ /* not a single response packet - need to re-assemble metadata messages */
+ if (pkt_type == AVRC_PKT_START)
+ {
+ p_rcb->rasm_offset = p_pkt->offset;
+ p_rcb->p_rmsg = p_pkt;
+ /* set offset to point to where to copy next - use the same re-asm logic as AVCT */
+ p_rcb->p_rmsg->offset += p_rcb->p_rmsg->len;
+ p_rcb->rasm_pdu = *p_data;
+ req_continue = TRUE;
+ }
+ else
+ {
+ /* get size of buffer holding assembled message */
+ buf_len = GKI_get_buf_size (p_rcb->p_rmsg) - sizeof(BT_HDR);
+ /* adjust offset and len of fragment for header byte */
+ p_pkt->offset += (AVRC_VENDOR_HDR_SIZE + AVRC_MIN_META_HDR_SIZE);
+ p_pkt->len -= (AVRC_VENDOR_HDR_SIZE + AVRC_MIN_META_HDR_SIZE);
+ /* verify length */
+ if ((p_rcb->p_rmsg->offset + p_pkt->len) > buf_len)
+ {
+ AVRC_TRACE_WARNING0("Fragmented message too big! - report the partial message");
+ p_pkt->len = buf_len - p_rcb->p_rmsg->offset;
+ pkt_type = AVRC_PKT_END;
+ }
+
+ /* copy contents of p_pkt to p_rx_msg */
+ memcpy((UINT8 *)(p_rcb->p_rmsg + 1) + p_rcb->p_rmsg->offset,
+ (UINT8 *)(p_pkt + 1) + p_pkt->offset, p_pkt->len);
+
+ if (pkt_type == AVRC_PKT_END)
+ {
+ p_rcb->p_rmsg->offset = p_rcb->rasm_offset;
+ p_rcb->p_rmsg->len += p_pkt->len;
+ p_pkt_new = p_rcb->p_rmsg;
+ p_rcb->rasm_offset = 0;
+ p_rcb->p_rmsg = NULL;
+ p_msg->p_vendor_data = (UINT8 *)(p_pkt_new+1) + p_pkt_new->offset;
+ p_msg->hdr.ctype = p_msg->p_vendor_data[0] & AVRC_CTYPE_MASK;
+ p_msg->p_vendor_data += AVRC_VENDOR_HDR_SIZE; /* 6 = ctype, subunit*, opcode & CO_ID */
+ p_msg->vendor_len = p_pkt_new->len - AVRC_VENDOR_HDR_SIZE;
+ p_data = p_msg->p_vendor_data + 1; /* skip pdu */
+ *p_data++ = AVRC_PKT_SINGLE;
+ UINT16_TO_BE_STREAM(p_data, (p_msg->vendor_len - AVRC_MIN_META_HDR_SIZE));
+ AVRC_TRACE_DEBUG3("end frag:%d, total len:%d, offset:%d", p_pkt->len, p_pkt_new->len, p_pkt_new->offset);
+ }
+ else
+ {
+ p_rcb->p_rmsg->offset += p_pkt->len;
+ p_rcb->p_rmsg->len += p_pkt->len;
+ p_pkt_new = NULL;
+ req_continue = TRUE;
+ }
+ GKI_freebuf(p_pkt);
+ *pp_pkt = p_pkt_new;
+ }
+ }
+
+ if (cr == AVCT_CMD)
+ {
+ p_rsp = avrc_proc_vendor_command(handle, label, *pp_pkt, p_msg);
+ if (p_rsp)
+ {
+ AVCT_MsgReq( handle, label, AVCT_RSP, p_rsp);
+ drop = 3;
+ }
+ else if (p_msg->hdr.opcode == AVRC_OP_DROP)
+ {
+ drop = 1;
+ }
+ else if (p_msg->hdr.opcode == AVRC_OP_DROP_N_FREE)
+ drop = 4;
+
+ }
+ else if (cr == AVCT_RSP && req_continue == TRUE)
+ {
+ avrc_cmd.pdu = AVRC_PDU_REQUEST_CONTINUATION_RSP;
+ avrc_cmd.status = AVRC_STS_NO_ERROR;
+ avrc_cmd.target_pdu = p_rcb->rasm_pdu;
+ if (AVRC_BldCommand ((tAVRC_COMMAND *)&avrc_cmd, &p_cmd) == AVRC_STS_NO_ERROR)
+ {
+ cr = AVCT_CMD;
+ drop = 2;
+ AVRC_MsgReq (handle, (UINT8)(label+1), cr, p_cmd);
+ }
+ }
+ }
+ return drop;
+}
+#endif /* (AVRC_METADATA_INCLUDED == TRUE) */
+
+/******************************************************************************
+**
+** Function avrc_msg_cback
+**
+** Description This is the callback function used by AVCTP to report
+** received AV control messages.
+**
+** Returns Nothing.
+**
+******************************************************************************/
+static void avrc_msg_cback(UINT8 handle, UINT8 label, UINT8 cr,
+ BT_HDR *p_pkt)
+{
+ UINT8 opcode;
+ tAVRC_MSG msg;
+ UINT8 *p_data;
+ UINT8 *p_begin;
+ BOOLEAN drop = FALSE;
+ BOOLEAN free = TRUE;
+ BT_HDR *p_rsp = NULL;
+ UINT8 *p_rsp_data;
+ int xx;
+ BOOLEAN reject = FALSE;
+#if (BT_USE_TRACES == TRUE)
+ char *p_drop_msg = "dropped";
+#endif
+ tAVRC_MSG_VENDOR *p_msg = &msg.vendor;
+
+ if (cr == AVCT_CMD &&
+ (p_pkt->layer_specific & AVCT_DATA_CTRL && AVRC_PACKET_LEN < sizeof(p_pkt->len)))
+ {
+ /* Ignore the invalid AV/C command frame */
+#if (BT_USE_TRACES == TRUE)
+ p_drop_msg = "dropped - too long AV/C cmd frame size";
+#endif
+ GKI_freebuf(p_pkt);
+ return;
+ }
+
+ if (cr == AVCT_REJ)
+ {
+ /* The peer thinks that this PID is no longer open - remove this handle */
+ /* */
+ GKI_freebuf(p_pkt);
+ AVCT_RemoveConn(handle);
+ return;
+ }
+
+ p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset;
+ memset(&msg, 0, sizeof(tAVRC_MSG) );
+#if ((AVRC_ADV_CTRL_INCLUDED == TRUE) && (AVCT_BROWSE_INCLUDED == TRUE))
+ if (p_pkt->layer_specific == AVCT_DATA_BROWSE)
+ {
+ opcode = AVRC_OP_BROWSE;
+ msg.browse.hdr.ctype= cr;
+ msg.browse.p_browse_data = p_data;
+ msg.browse.browse_len = p_pkt->len;
+ msg.browse.p_browse_pkt = p_pkt;
+ }
+ else
+#endif
+ {
+ msg.hdr.ctype = p_data[0] & AVRC_CTYPE_MASK;
+ AVRC_TRACE_DEBUG4("avrc_msg_cback handle:%d, ctype:%d, offset:%d, len: %d",
+ handle, msg.hdr.ctype, p_pkt->offset, p_pkt->len);
+ msg.hdr.subunit_type = (p_data[1] & AVRC_SUBTYPE_MASK) >> AVRC_SUBTYPE_SHIFT;
+ msg.hdr.subunit_id = p_data[1] & AVRC_SUBID_MASK;
+ opcode = p_data[2];
+ }
+
+ if ( ((avrc_cb.ccb[handle].control & AVRC_CT_TARGET) && (cr == AVCT_CMD)) ||
+ ((avrc_cb.ccb[handle].control & AVRC_CT_CONTROL) && (cr == AVCT_RSP)) )
+ {
+
+ switch(opcode)
+ {
+ case AVRC_OP_UNIT_INFO:
+ if (cr == AVCT_CMD)
+ {
+ /* send the response to the peer */
+ p_rsp = p_pkt; /* this also sets free = FALSE, drop = TRUE */
+ /* check & set the offset. set response code, set subunit_type & subunit_id,
+ set AVRC_OP_UNIT_INFO */
+ p_rsp_data = avrc_get_data_ptr(p_pkt) + AVRC_AVC_HDR_SIZE; /* 3 bytes: ctype, subunit*, opcode */
+ *p_rsp_data++ = 7;
+ /* Panel subunit & id=0 */
+ *p_rsp_data++ = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT);
+ AVRC_CO_ID_TO_BE_STREAM(p_rsp_data, avrc_cb.ccb[handle].company_id);
+ p_rsp->len = (UINT16) (p_rsp_data - (UINT8 *)(p_rsp + 1) - p_rsp->offset);
+ cr = AVCT_RSP;
+#if (BT_USE_TRACES == TRUE)
+ p_drop_msg = "auto respond";
+#endif
+ }
+ else
+ {
+ /* parse response */
+ p_data += 4; /* 3 bytes: ctype, subunit*, opcode + octet 3 (is 7)*/
+ msg.unit.unit_type = (*p_data & AVRC_SUBTYPE_MASK) >> AVRC_SUBTYPE_SHIFT;
+ msg.unit.unit = *p_data & AVRC_SUBID_MASK;
+ p_data++;
+ AVRC_BE_STREAM_TO_CO_ID(msg.unit.company_id, p_data);
+ }
+ break;
+
+ case AVRC_OP_SUB_INFO:
+ if (cr == AVCT_CMD)
+ {
+ /* send the response to the peer */
+ p_rsp = p_pkt; /* this also sets free = FALSE, drop = TRUE */
+ /* check & set the offset. set response code, set (subunit_type & subunit_id),
+ set AVRC_OP_SUB_INFO, set (page & extention code) */
+ p_rsp_data = avrc_get_data_ptr(p_pkt) + 4;
+ /* Panel subunit & id=0 */
+ *p_rsp_data++ = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT);
+ memset(p_rsp_data, AVRC_CMD_OPRND_PAD, AVRC_SUBRSP_OPRND_BYTES);
+ p_rsp_data += AVRC_SUBRSP_OPRND_BYTES;
+ p_rsp->len = (UINT16) (p_rsp_data - (UINT8 *)(p_rsp + 1) - p_rsp->offset);
+ cr = AVCT_RSP;
+#if (BT_USE_TRACES == TRUE)
+ p_drop_msg = "auto responded";
+#endif
+ }
+ else
+ {
+ /* parse response */
+ p_data += AVRC_AVC_HDR_SIZE; /* 3 bytes: ctype, subunit*, opcode */
+ msg.sub.page = (*p_data++ >> AVRC_SUB_PAGE_SHIFT) & AVRC_SUB_PAGE_MASK;
+ xx = 0;
+ while (*p_data != AVRC_CMD_OPRND_PAD && xx<AVRC_SUB_TYPE_LEN)
+ {
+ msg.sub.subunit_type[xx] = *p_data++ >> AVRC_SUBTYPE_SHIFT;
+ if (msg.sub.subunit_type[xx] == AVRC_SUB_PANEL)
+ msg.sub.panel = TRUE;
+ xx++;
+ }
+ }
+ break;
+
+ case AVRC_OP_VENDOR:
+ p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset;
+ p_begin = p_data;
+ if (p_pkt->len < AVRC_VENDOR_HDR_SIZE) /* 6 = ctype, subunit*, opcode & CO_ID */
+ {
+ if (cr == AVCT_CMD)
+ reject = TRUE;
+ else
+ drop = TRUE;
+ break;
+ }
+ p_data += AVRC_AVC_HDR_SIZE; /* skip the first 3 bytes: ctype, subunit*, opcode */
+ AVRC_BE_STREAM_TO_CO_ID(p_msg->company_id, p_data);
+ p_msg->p_vendor_data = p_data;
+ p_msg->vendor_len = p_pkt->len - (p_data - p_begin);
+
+#if (AVRC_METADATA_INCLUDED == TRUE)
+ drop = avrc_proc_far_msg(handle, label, cr, &p_pkt, p_msg);
+ if (drop)
+ {
+ free = FALSE;
+ if (drop == 4)
+ free = TRUE;
+#if (BT_USE_TRACES == TRUE)
+ switch (drop)
+ {
+ case 1:
+ p_drop_msg = "sent_frag";
+ break;
+ case 2:
+ p_drop_msg = "req_cont";
+ break;
+ case 3:
+ p_drop_msg = "sent_frag3";
+ break;
+ case 4:
+ p_drop_msg = "sent_frag_free";
+ break;
+ default:
+ p_drop_msg = "sent_fragd";
+ }
+#endif
+ }
+#endif /* (AVRC_METADATA_INCLUDED == TRUE) */
+ break;
+
+ case AVRC_OP_PASS_THRU:
+ if (p_pkt->len < 5) /* 3 bytes: ctype, subunit*, opcode & op_id & len */
+ {
+ if (cr == AVCT_CMD)
+ reject = TRUE;
+ else
+ drop = TRUE;
+ break;
+ }
+ p_data += AVRC_AVC_HDR_SIZE; /* skip the first 3 bytes: ctype, subunit*, opcode */
+ msg.pass.op_id = (AVRC_PASS_OP_ID_MASK & *p_data);
+ if (AVRC_PASS_STATE_MASK & *p_data)
+ msg.pass.state = TRUE;
+ else
+ msg.pass.state = FALSE;
+ p_data++;
+ msg.pass.pass_len = *p_data++;
+ if (msg.pass.pass_len != p_pkt->len - 5)
+ msg.pass.pass_len = p_pkt->len - 5;
+ if (msg.pass.pass_len)
+ msg.pass.p_pass_data = p_data;
+ else
+ msg.pass.p_pass_data = NULL;
+ break;
+
+#if ((AVRC_ADV_CTRL_INCLUDED == TRUE) && (AVCT_BROWSE_INCLUDED == TRUE))
+ case AVRC_OP_BROWSE:
+ /* the event data is handled already.
+ * this empty "case" is to keep the message from being rejected by the default case. */
+ break;
+#endif
+
+ default:
+ if ((avrc_cb.ccb[handle].control & AVRC_CT_TARGET) && (cr == AVCT_CMD))
+ {
+ /* reject unsupported opcode */
+ reject = TRUE;
+ }
+ drop = TRUE;
+ break;
+ }
+ }
+ else /* drop the event */
+ {
+#if ((AVRC_ADV_CTRL_INCLUDED == TRUE) && (AVCT_BROWSE_INCLUDED == TRUE))
+ if (opcode != AVRC_OP_BROWSE)
+#endif
+ drop = TRUE;
+ }
+
+ if (reject)
+ {
+ /* reject unsupported opcode */
+ p_rsp = p_pkt; /* this also sets free = FALSE, drop = TRUE */
+ p_rsp_data = avrc_get_data_ptr(p_pkt);
+ *p_rsp_data = AVRC_RSP_REJ;
+#if (BT_USE_TRACES == TRUE)
+ p_drop_msg = "rejected";
+#endif
+ cr = AVCT_RSP;
+ drop = TRUE;
+ }
+
+ if (p_rsp)
+ {
+ /* set to send response right away */
+ AVCT_MsgReq( handle, label, cr, p_rsp);
+ free = FALSE;
+ drop = TRUE;
+ }
+
+ if (drop == FALSE)
+ {
+ msg.hdr.opcode = opcode;
+ (*avrc_cb.ccb[handle].p_msg_cback)(handle, label, opcode, &msg);
+ }
+#if (BT_USE_TRACES == TRUE)
+ else
+ {
+ AVRC_TRACE_WARNING5("avrc_msg_cback %s msg handle:%d, control:%d, cr:%d, opcode:x%x",
+ p_drop_msg,
+ handle, avrc_cb.ccb[handle].control, cr, opcode);
+ }
+#endif
+
+#if ((AVRC_ADV_CTRL_INCLUDED == TRUE) && (AVCT_BROWSE_INCLUDED == TRUE))
+ if (opcode == AVRC_OP_BROWSE && msg.browse.p_browse_pkt == NULL)
+ {
+ free = FALSE;
+ }
+#endif
+
+ if (free)
+ GKI_freebuf(p_pkt);
+}
+
+
+
+
+/******************************************************************************
+**
+** Function avrc_pass_msg
+**
+** Description Compose a PASS THROUGH command according to p_msg
+**
+** Input Parameters:
+** p_msg: Pointer to PASS THROUGH message structure.
+**
+** Output Parameters:
+** None.
+**
+** Returns pointer to a valid GKI buffer if successful.
+** NULL if p_msg is NULL.
+**
+******************************************************************************/
+static BT_HDR * avrc_pass_msg(tAVRC_MSG_PASS *p_msg)
+{
+ BT_HDR *p_cmd = NULL;
+ UINT8 *p_data;
+
+ WC_ASSERT(p_msg != NULL);
+ WC_ASSERT(AVRC_CMD_POOL_SIZE > (AVRC_MIN_CMD_LEN+p_msg->pass_len));
+
+ if ((p_cmd = (BT_HDR *) GKI_getpoolbuf(AVRC_CMD_POOL_ID)) != NULL)
+ {
+ p_cmd->offset = AVCT_MSG_OFFSET;
+ p_cmd->layer_specific = AVCT_DATA_CTRL;
+ p_data = (UINT8 *)(p_cmd + 1) + p_cmd->offset;
+ *p_data++ = (p_msg->hdr.ctype & AVRC_CTYPE_MASK);
+ *p_data++ = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT); /* Panel subunit & id=0 */
+ *p_data++ = AVRC_OP_PASS_THRU;
+ *p_data = (AVRC_PASS_OP_ID_MASK&p_msg->op_id);
+ if (p_msg->state)
+ *p_data |= AVRC_PASS_STATE_MASK;
+ p_data++;
+
+ if (p_msg->op_id == AVRC_ID_VENDOR)
+ {
+ *p_data++ = p_msg->pass_len;
+ if (p_msg->pass_len && p_msg->p_pass_data)
+ {
+ memcpy(p_data, p_msg->p_pass_data, p_msg->pass_len);
+ p_data += p_msg->pass_len;
+ }
+ }
+ else /* set msg len to 0 for other op_id */
+ {
+ /* set msg len to 0 for other op_id */
+ *p_data++ = 0;
+ }
+ p_cmd->len = (UINT16) (p_data - (UINT8 *)(p_cmd + 1) - p_cmd->offset);
+ }
+ return p_cmd;
+}
+
+/******************************************************************************
+**
+** Function AVRC_Open
+**
+** Description This function is called to open a connection to AVCTP.
+** The connection can be either an initiator or acceptor, as
+** determined by the p_ccb->stream parameter.
+** The connection can be a target, a controller or for both role,
+** as determined by the p_ccb->control parameter.
+** By definition, a target connection is an acceptor connection
+** that waits for an incoming AVCTP connection from the peer.
+** The connection remains available to the application until
+** the application closes it by calling AVRC_Close(). The
+** application does not need to reopen the connection after an
+** AVRC_CLOSE_IND_EVT is received.
+**
+** Input Parameters:
+** p_ccb->company_id: Company Identifier.
+**
+** p_ccb->p_ctrl_cback: Pointer to control callback function.
+**
+** p_ccb->p_msg_cback: Pointer to message callback function.
+**
+** p_ccb->conn: AVCTP connection role. This is set to
+** AVCTP_INT for initiator connections and AVCTP_ACP
+** for acceptor connections.
+**
+** p_ccb->control: Control role. This is set to
+** AVRC_CT_TARGET for target connections, AVRC_CT_CONTROL
+** for control connections or (AVRC_CT_TARGET|AVRC_CT_CONTROL)
+** for connections that support both roles.
+**
+** peer_addr: BD address of peer device. This value is
+** only used for initiator connections; for acceptor
+** connections it can be set to NULL.
+**
+** Output Parameters:
+** p_handle: Pointer to handle. This parameter is only
+** valid if AVRC_SUCCESS is returned.
+**
+** Returns AVRC_SUCCESS if successful.
+** AVRC_NO_RESOURCES if there are not enough resources to open
+** the connection.
+**
+******************************************************************************/
+UINT16 AVRC_Open(UINT8 *p_handle, tAVRC_CONN_CB *p_ccb, BD_ADDR_PTR peer_addr)
+{
+ UINT16 status;
+ tAVCT_CC cc;
+
+ cc.p_ctrl_cback = avrc_ctrl_cback; /* Control callback */
+ cc.p_msg_cback = avrc_msg_cback; /* Message callback */
+ cc.pid = UUID_SERVCLASS_AV_REMOTE_CONTROL; /* Profile ID */
+ cc.role = p_ccb->conn; /* Initiator/acceptor role */
+ cc.control = p_ccb->control; /* Control role (Control/Target) */
+
+ status = AVCT_CreateConn(p_handle, &cc, peer_addr);
+ if (status == AVCT_SUCCESS)
+ {
+ memcpy(&avrc_cb.ccb[*p_handle], p_ccb, sizeof(tAVRC_CONN_CB));
+#if (AVRC_METADATA_INCLUDED == TRUE)
+ memset(&avrc_cb.fcb[*p_handle], 0, sizeof(tAVRC_FRAG_CB));
+ memset(&avrc_cb.rcb[*p_handle], 0, sizeof(tAVRC_RASM_CB));
+#endif
+ }
+ AVRC_TRACE_DEBUG4("AVRC_Open role: %d, control:%d status:%d, handle:%d", cc.role, cc.control, status, *p_handle);
+
+ return status;
+}
+
+/******************************************************************************
+**
+** Function AVRC_Close
+**
+** Description Close a connection opened with AVRC_Open().
+** This function is called when the
+** application is no longer using a connection.
+**
+** Input Parameters:
+** handle: Handle of this connection.
+**
+** Output Parameters:
+** None.
+**
+** Returns AVRC_SUCCESS if successful.
+** AVRC_BAD_HANDLE if handle is invalid.
+**
+******************************************************************************/
+UINT16 AVRC_Close(UINT8 handle)
+{
+ AVRC_TRACE_DEBUG1("AVRC_Close handle:%d", handle);
+ return AVCT_RemoveConn(handle);
+}
+
+#if ((AVRC_ADV_CTRL_INCLUDED == TRUE) && (AVCT_BROWSE_INCLUDED == TRUE))
+/******************************************************************************
+**
+** Function AVRC_OpenBrowse
+**
+** Description This function is called to open a browsing connection to AVCTP.
+** The connection can be either an initiator or acceptor, as
+** determined by the p_conn_role.
+** The handle is returned by a previous call to AVRC_Open.
+**
+** Returns AVRC_SUCCESS if successful.
+** AVRC_NO_RESOURCES if there are not enough resources to open
+** the connection.
+**
+******************************************************************************/
+UINT16 AVRC_OpenBrowse(UINT8 handle, UINT8 conn_role)
+{
+ return AVCT_CreateBrowse(handle, conn_role);
+}
+
+/******************************************************************************
+**
+** Function AVRC_CloseBrowse
+**
+** Description Close a connection opened with AVRC_OpenBrowse().
+** This function is called when the
+** application is no longer using a connection.
+**
+** Returns AVRC_SUCCESS if successful.
+** AVRC_BAD_HANDLE if handle is invalid.
+**
+******************************************************************************/
+UINT16 AVRC_CloseBrowse(UINT8 handle)
+{
+ return AVCT_RemoveBrowse(handle);
+}
+#endif
+
+/******************************************************************************
+**
+** Function AVRC_MsgReq
+**
+** Description This function is used to send the AVRCP byte stream in p_pkt
+** down to AVCTP.
+**
+** It is expected that p_pkt->offset is at least AVCT_MSG_OFFSET
+** p_pkt->layer_specific is AVCT_DATA_CTRL or AVCT_DATA_BROWSE
+** p_pkt->event is AVRC_OP_VENDOR, AVRC_OP_PASS_THRU or AVRC_OP_BROWSE
+** The above BT_HDR settings are set by the AVRC_Bld* functions.
+**
+** Returns AVRC_SUCCESS if successful.
+** AVRC_BAD_HANDLE if handle is invalid.
+**
+******************************************************************************/
+UINT16 AVRC_MsgReq (UINT8 handle, UINT8 label, UINT8 ctype, BT_HDR *p_pkt)
+{
+#if (AVRC_METADATA_INCLUDED == TRUE)
+ UINT8 *p_data;
+ UINT8 cr = AVCT_CMD;
+ BOOLEAN chk_frag = TRUE;
+ UINT8 *p_start = NULL;
+ tAVRC_FRAG_CB *p_fcb;
+ UINT16 len;
+ BT_HDR *p_pkt_new;
+#if ((AVRC_ADV_CTRL_INCLUDED == TRUE) && (AVCT_BROWSE_INCLUDED == TRUE))
+ UINT16 peer_mtu;
+#endif
+
+ if (!p_pkt)
+ return AVRC_BAD_PARAM;
+
+ if (ctype >= AVRC_RSP_NOT_IMPL)
+ cr = AVCT_RSP;
+
+ if (p_pkt->event == AVRC_OP_VENDOR)
+ {
+ /* add AVRCP Vendor Dependent headers */
+ p_start = ((UINT8 *)(p_pkt + 1) + p_pkt->offset);
+ p_pkt->offset -= AVRC_VENDOR_HDR_SIZE;
+ p_pkt->len += AVRC_VENDOR_HDR_SIZE;
+ p_data = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ *p_data++ = (ctype & AVRC_CTYPE_MASK);
+ *p_data++ = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT);
+ *p_data++ = AVRC_OP_VENDOR;
+ AVRC_CO_ID_TO_BE_STREAM(p_data, AVRC_CO_METADATA);
+ }
+ else if (p_pkt->event == AVRC_OP_PASS_THRU)
+ {
+ /* add AVRCP Pass Through headers */
+ p_start = ((UINT8 *)(p_pkt + 1) + p_pkt->offset);
+ p_pkt->offset -= AVRC_PASS_THRU_SIZE;
+ p_pkt->len += AVRC_PASS_THRU_SIZE;
+ p_data = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ *p_data++ = (ctype & AVRC_CTYPE_MASK);
+ *p_data++ = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT);
+ *p_data++ = AVRC_OP_PASS_THRU;/* opcode */
+ *p_data++ = AVRC_ID_VENDOR; /* operation id */
+ *p_data++ = 5; /* operation data len */
+ AVRC_CO_ID_TO_BE_STREAM(p_data, AVRC_CO_METADATA);
+ }
+#if ((AVRC_ADV_CTRL_INCLUDED == TRUE) && (AVCT_BROWSE_INCLUDED == TRUE))
+ else
+ {
+ chk_frag = FALSE;
+ peer_mtu = AVCT_GetBrowseMtu (handle);
+ if (p_pkt->len > (peer_mtu-AVCT_HDR_LEN_SINGLE))
+ {
+ AVRC_TRACE_ERROR3 ("p_pkt->len(%d) > peer_mtu(%d-%d)", p_pkt->len, peer_mtu, AVCT_HDR_LEN_SINGLE );
+ GKI_freebuf(p_pkt);
+ return AVRC_MSG_TOO_BIG;
+ }
+ }
+#endif
+
+ /* abandon previous fragments */
+ p_fcb = &avrc_cb.fcb[handle];
+ if (p_fcb->frag_enabled)
+ p_fcb->frag_enabled = FALSE;
+
+ if (p_fcb->p_fmsg)
+ {
+ GKI_freebuf(p_fcb->p_fmsg);
+ p_fcb->p_fmsg = NULL;
+ }
+
+ /* AVRCP spec has not defined any control channel commands that needs fragmentation at this level
+ * check for fragmentation only on the response */
+ if ((cr == AVCT_RSP) && (chk_frag == TRUE))
+ {
+ if (p_pkt->len > AVRC_MAX_CTRL_DATA_LEN)
+ {
+ AVRC_TRACE_DEBUG1 ("p_pkt->len(%d) > AVRC_MAX_CTRL_DATA_LEN", p_pkt->len );
+ p_pkt_new = (BT_HDR *)GKI_getbuf((UINT16)(AVRC_PACKET_LEN + AVCT_MSG_OFFSET + BT_HDR_SIZE));
+ if (p_pkt_new)
+ {
+ p_fcb->frag_enabled = TRUE;
+ p_fcb->p_fmsg = p_pkt;
+ p_fcb->frag_pdu = *p_start;
+ p_pkt = p_pkt_new;
+ p_pkt_new = p_fcb->p_fmsg;
+ p_pkt->len = AVRC_MAX_CTRL_DATA_LEN;
+ p_pkt->offset = p_pkt_new->offset;
+ p_pkt->layer_specific = p_pkt_new->layer_specific;
+ p_pkt->event = p_pkt_new->event;
+ p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset;
+ p_start -= AVRC_VENDOR_HDR_SIZE;
+ memcpy (p_data, p_start, AVRC_MAX_CTRL_DATA_LEN);
+ /* use AVRC start packet type */
+ p_data += AVRC_VENDOR_HDR_SIZE;
+ p_data++; /* pdu */
+ *p_data++ = AVRC_PKT_START;
+ len = (AVRC_MAX_CTRL_DATA_LEN - AVRC_VENDOR_HDR_SIZE - AVRC_MIN_META_HDR_SIZE); /* 4 pdu, pkt_type & len */
+ UINT16_TO_BE_STREAM(p_data, len);
+
+ /* prepare the left over for as an end fragment */
+ avrc_prep_end_frag (handle);
+ AVRC_TRACE_DEBUG3 ("p_pkt len:%d/%d, next len:%d", p_pkt->len, len, p_fcb->p_fmsg->len );
+ }
+ else
+ {
+ AVRC_TRACE_ERROR0 ("AVRC_MsgReq no buffers for fragmentation" );
+ GKI_freebuf(p_pkt);
+ return AVRC_NO_RESOURCES;
+ }
+ }
+ }
+
+ return AVCT_MsgReq( handle, label, cr, p_pkt);
+#else
+ return AVRC_NO_RESOURCES;
+#endif
+}
+
+
+/******************************************************************************
+**
+** Function AVRC_PassCmd
+**
+** Description Send a PASS THROUGH command to the peer device. This
+** function can only be called for controller role connections.
+** Any response message from the peer is passed back through
+** the tAVRC_MSG_CBACK callback function.
+**
+** Input Parameters:
+** handle: Handle of this connection.
+**
+** label: Transaction label.
+**
+** p_msg: Pointer to PASS THROUGH message structure.
+**
+** Output Parameters:
+** None.
+**
+** Returns AVRC_SUCCESS if successful.
+** AVRC_BAD_HANDLE if handle is invalid.
+**
+******************************************************************************/
+UINT16 AVRC_PassCmd(UINT8 handle, UINT8 label, tAVRC_MSG_PASS *p_msg)
+{
+ BT_HDR *p_buf;
+ WC_ASSERT(p_msg != NULL);
+ if (p_msg)
+ {
+ p_msg->hdr.ctype = AVRC_CMD_CTRL;
+ p_buf = avrc_pass_msg(p_msg);
+ if (p_buf)
+ return AVCT_MsgReq( handle, label, AVCT_CMD, p_buf);
+ }
+ return AVRC_NO_RESOURCES;
+}
+
+/******************************************************************************
+**
+** Function AVRC_PassRsp
+**
+** Description Send a PASS THROUGH response to the peer device. This
+** function can only be called for target role connections.
+** This function must be called when a PASS THROUGH command
+** message is received from the peer through the
+** tAVRC_MSG_CBACK callback function.
+**
+** Input Parameters:
+** handle: Handle of this connection.
+**
+** label: Transaction label. Must be the same value as
+** passed with the command message in the callback function.
+**
+** p_msg: Pointer to PASS THROUGH message structure.
+**
+** Output Parameters:
+** None.
+**
+** Returns AVRC_SUCCESS if successful.
+** AVRC_BAD_HANDLE if handle is invalid.
+**
+******************************************************************************/
+UINT16 AVRC_PassRsp(UINT8 handle, UINT8 label, tAVRC_MSG_PASS *p_msg)
+{
+ BT_HDR *p_buf;
+ WC_ASSERT(p_msg != NULL);
+ if (p_msg)
+ {
+ p_buf = avrc_pass_msg(p_msg);
+ if (p_buf)
+ return AVCT_MsgReq( handle, label, AVCT_RSP, p_buf);
+ }
+ return AVRC_NO_RESOURCES;
+}
+
diff --git a/stack/avrc/avrc_bld_ct.c b/stack/avrc/avrc_bld_ct.c
new file mode 100644
index 0000000..a1d5fa1
--- /dev/null
+++ b/stack/avrc/avrc_bld_ct.c
@@ -0,0 +1,1102 @@
+/*****************************************************************************
+**
+** Name: avrc_bld_ct.c
+**
+** Description:Interface to AVRCP build message functions for the Control Role
+**
+** Copyright (c) 2008-2008, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include <string.h>
+
+#include "gki.h"
+#include "avrc_api.h"
+#include "avrc_defs.h"
+#include "avrc_int.h"
+
+/*****************************************************************************
+** Global data
+*****************************************************************************/
+
+
+#if (AVRC_METADATA_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function avrc_bld_get_capability_cmd
+**
+** Description This function builds the Get Capability command.
+**
+** Returns AVRC_STS_NO_ERROR, if the command is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_get_capability_cmd (tAVRC_GET_CAPS_CMD *p_cmd, BT_HDR *p_pkt)
+{
+ UINT8 *p_data, *p_start;
+
+ if (!AVRC_IS_VALID_CAP_ID(p_cmd->capability_id))
+ {
+ AVRC_TRACE_ERROR1("avrc_bld_get_capability_cmd bad capability_id:0x%x", p_cmd->capability_id);
+ return AVRC_STS_BAD_PARAM;
+ }
+
+ AVRC_TRACE_API0("avrc_bld_get_capability_cmd");
+ /* get the existing length, if any, and also the num attributes */
+ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_start + 2; /* pdu + rsvd */
+
+ /* add fixed lenth - capability_id(1) */
+ UINT16_TO_BE_STREAM(p_data, 1);
+ /* add the capability_id */
+ UINT8_TO_BE_STREAM(p_data, p_cmd->capability_id);
+ p_pkt->len = (p_data - p_start);
+
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function avrc_bld_list_app_settings_attr_cmd
+**
+** Description This function builds the List Application Settings Attribute
+** command.
+**
+** Returns AVRC_STS_NO_ERROR, if the command is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_list_app_settings_attr_cmd (tAVRC_CMD *p_cmd, BT_HDR *p_pkt)
+{
+ AVRC_TRACE_API0("avrc_bld_list_app_settings_attr_cmd");
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function avrc_bld_list_app_settings_values_cmd
+**
+** Description This function builds the List Application Setting Values
+** command.
+**
+** Returns AVRC_STS_NO_ERROR, if the command is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_list_app_settings_values_cmd (tAVRC_LIST_APP_VALUES_CMD *p_cmd, BT_HDR *p_pkt)
+{
+ UINT8 *p_data, *p_start;
+
+ if (!AVRC_IsValidPlayerAttr(p_cmd->attr_id))
+ {
+ AVRC_TRACE_ERROR1("avrc_bld_list_app_settings_values_cmd bad attr:0x%x", p_cmd->attr_id);
+ return AVRC_STS_BAD_PARAM;
+ }
+
+ AVRC_TRACE_API0("avrc_bld_list_app_settings_values_cmd");
+ /* get the existing length, if any, and also the num attributes */
+ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_start + 2; /* pdu + rsvd */
+
+ /* add fixed lenth - attr_id(1) */
+ UINT16_TO_BE_STREAM(p_data, 1);
+ /* add the attr_id */
+ UINT8_TO_BE_STREAM(p_data, p_cmd->attr_id);
+ p_pkt->len = (p_data - p_start);
+
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function avrc_bld_get_cur_app_setting_value_cmd
+**
+** Description This function builds the Get Current Application Setting Value
+** or the Get Application Setting Attribute Text command.
+**
+** Returns AVRC_STS_NO_ERROR, if the command is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_get_cur_app_setting_value_cmd (tAVRC_GET_CUR_APP_VALUE_CMD *p_cmd, BT_HDR *p_pkt)
+{
+ UINT8 *p_data, *p_start;
+ UINT8 *p_len;
+ UINT16 len = 0;
+ UINT8 xx;
+ UINT8 *p_count;
+
+ /* get the existing length, if any, and also the num attributes */
+ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ p_len = p_data = p_start + 2; /* pdu + rsvd */
+
+ BE_STREAM_TO_UINT16(len, p_data);
+ p_count = p_data;
+ if (len == 0)
+ {
+ /* first time initialize the attribute count */
+ *p_count = 0;
+ p_data++;
+ len = 1;
+ }
+ else
+ {
+ p_data = p_start + p_pkt->len;
+ }
+
+ for (xx=0; xx<p_cmd->num_attr; xx++)
+ {
+ if (AVRC_IsValidPlayerAttr(p_cmd->attrs[xx]))
+ {
+ (*p_count)++;
+ UINT8_TO_BE_STREAM(p_data, p_cmd->attrs[xx]);
+ len++;
+ }
+ }
+ UINT16_TO_BE_STREAM(p_len, len);
+ p_pkt->len = (p_data - p_start);
+
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function avrc_bld_set_app_setting_value_cmd
+**
+** Description This function builds the Set Application Setting Value
+** command.
+**
+** Returns AVRC_STS_NO_ERROR, if the command is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_set_app_setting_value_cmd (tAVRC_SET_APP_VALUE_CMD *p_cmd, BT_HDR *p_pkt)
+{
+ UINT8 *p_data, *p_start;
+ UINT8 *p_len;
+ UINT16 len;
+ UINT8 xx;
+ UINT8 *p_count;
+
+ if (!p_cmd->p_vals)
+ {
+ AVRC_TRACE_ERROR0("avrc_bld_set_app_setting_value_cmd NULL parameter");
+ return AVRC_STS_BAD_PARAM;
+ }
+
+ AVRC_TRACE_API1("avrc_bld_set_app_setting_value_cmd num_val:%d", p_cmd->num_val);
+ /* get the existing length, if any, and also the num attributes */
+ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_len = p_start + 2; /* pdu + rsvd */
+
+ BE_STREAM_TO_UINT16(len, p_data);
+ p_count = p_data;
+ if (len == 0)
+ {
+ /* first time initialize the attribute count */
+ *p_count = 0;
+ p_data++;
+ len = 1;
+ }
+ else
+ {
+ p_data = p_start + p_pkt->len;
+ }
+
+
+ for (xx=0; xx<p_cmd->num_val; xx++)
+ {
+ AVRC_TRACE_DEBUG3("[%d] id/val = 0x%x/0x%x", xx, p_cmd->p_vals[xx].attr_id, p_cmd->p_vals[xx].attr_val);
+ if (avrc_is_valid_player_attrib_value(p_cmd->p_vals[xx].attr_id, p_cmd->p_vals[xx].attr_val))
+ {
+ (*p_count)++;
+ UINT8_TO_BE_STREAM(p_data, p_cmd->p_vals[xx].attr_id);
+ UINT8_TO_BE_STREAM(p_data, p_cmd->p_vals[xx].attr_val);
+ len += 2;
+ }
+ }
+
+ UINT16_TO_BE_STREAM(p_len, len);
+ p_pkt->len = (p_data - p_start);
+
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function avrc_bld_get_app_setting_attr_text_cmd
+**
+** Description This function builds the Get Application Setting Attribute Text
+** command.
+**
+** Returns AVRC_STS_NO_ERROR, if the command is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_get_app_setting_attr_text_cmd (tAVRC_GET_APP_ATTR_TXT_CMD *p_cmd, BT_HDR *p_pkt)
+{
+ AVRC_TRACE_API0("avrc_bld_get_app_setting_attr_text_cmd");
+ return avrc_bld_get_cur_app_setting_value_cmd((tAVRC_GET_CUR_APP_VALUE_CMD *)p_cmd, p_pkt);
+
+}
+
+/*******************************************************************************
+**
+** Function avrc_bld_get_app_setting_value_text_cmd
+**
+** Description This function builds the Get Application Setting Value Text
+** command.
+**
+** Returns AVRC_STS_NO_ERROR, if the command is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_get_app_setting_value_text_cmd (tAVRC_GET_APP_VAL_TXT_CMD *p_cmd, BT_HDR *p_pkt)
+{
+ UINT8 *p_data, *p_start;
+ UINT8 *p_len;
+ UINT16 len = 0;
+ UINT8 xx;
+ UINT8 *p_count;
+
+ AVRC_TRACE_API0("avrc_bld_get_app_setting_value_text_cmd");
+ /* get the existing length, if any, and also the num attributes */
+ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_len = p_start + 2; /* pdu + rsvd */
+
+ BE_STREAM_TO_UINT16(len, p_data);
+ p_count = p_data + 1;
+ if (len == 0)
+ {
+ /* first time initialize the attribute count */
+ UINT8_TO_BE_STREAM(p_data, p_cmd->attr_id);
+ *p_count = 0;
+ p_data++;
+ len = 2;
+ }
+ else
+ {
+ p_data = p_start + p_pkt->len;
+ }
+
+ for (xx=0; xx<p_cmd->num_val; xx++)
+ {
+ (*p_count)++;
+ UINT8_TO_BE_STREAM(p_data, p_cmd->vals[xx]);
+ len++;
+ }
+ UINT16_TO_BE_STREAM(p_len, len);
+ p_pkt->len = (p_data - p_start);
+
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function avrc_bld_inform_charset_cmd
+**
+** Description This function builds the Inform Displayable Character Set
+** command.
+**
+** Returns AVRC_STS_NO_ERROR, if the command is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_inform_charset_cmd (tAVRC_INFORM_CHARSET_CMD *p_cmd, BT_HDR *p_pkt)
+{
+ UINT8 *p_data, *p_start;
+ UINT16 len = 0;
+ UINT8 xx;
+
+ AVRC_TRACE_API0("avrc_bld_inform_charset_cmd");
+ /* get the existing length, if any, and also the num attributes */
+ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_start + 2; /* pdu + rsvd */
+
+ len = 1 + (p_cmd->num_id << 1);
+ UINT16_TO_BE_STREAM(p_data, len);
+
+ UINT8_TO_BE_STREAM(p_data, p_cmd->num_id);
+ for (xx=0; xx<p_cmd->num_id; xx++)
+ {
+ UINT16_TO_BE_STREAM(p_data, p_cmd->charsets[xx]);
+ }
+
+ p_pkt->len = (p_data - p_start);
+
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function avrc_bld_inform_battery_status_cmd
+**
+** Description This function builds the Inform Battery Status
+** command.
+**
+** Returns AVRC_STS_NO_ERROR, if the command is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_inform_battery_status_cmd (tAVRC_BATTERY_STATUS_CMD *p_cmd, BT_HDR *p_pkt)
+{
+ UINT8 *p_data, *p_start;
+
+ if (!AVRC_IS_VALID_BATTERY_STATUS(p_cmd->battery_status))
+ {
+ AVRC_TRACE_ERROR1("avrc_bld_inform_battery_status_cmd bad battery_status:0x%x", p_cmd->battery_status);
+ return AVRC_STS_BAD_PARAM;
+ }
+
+ AVRC_TRACE_API0("avrc_bld_inform_battery_status_cmd");
+ /* get the existing length, if any, and also the num attributes */
+ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_start + 2; /* pdu + rsvd */
+ /* add fixed lenth - battery_status(1) */
+ UINT16_TO_BE_STREAM(p_data, 1);
+ /* add the battery_status */
+ UINT8_TO_BE_STREAM(p_data, p_cmd->battery_status);
+
+ p_pkt->len = (p_data - p_start);
+
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function avrc_bld_get_elem_attrs_cmd
+**
+** Description This function builds the Get Element Attributes
+** command.
+**
+** Returns AVRC_STS_NO_ERROR, if the command is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_get_elem_attrs_cmd (tAVRC_GET_ELEM_ATTRS_CMD *p_cmd, BT_HDR *p_pkt)
+{
+ UINT8 *p_data, *p_start;
+ UINT8 *p_len;
+ UINT16 len = 0;
+ UINT8 xx;
+ UINT8 *p_count;
+
+ AVRC_TRACE_API0("avrc_bld_get_elem_attrs_cmd");
+ /* get the existing length, if any, and also the num attributes */
+ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ p_len = p_start + 2; /* pdu + rsvd */
+ p_data = p_len + 2;
+
+ /* 8 byte identifier 0 - PLAYING - the only valid one */
+ UINT32_TO_BE_STREAM(p_data, 0);
+ UINT32_TO_BE_STREAM(p_data, 0);
+
+ p_count = p_data;
+ p_data++;
+ *p_count = 0;
+ len = 9;
+ for (xx=0; xx<p_cmd->num_attr; xx++)
+ {
+ if (AVRC_IS_VALID_MEDIA_ATTRIBUTE(p_cmd->attrs[xx]))
+ {
+ (*p_count)++;
+ UINT32_TO_BE_STREAM(p_data, p_cmd->attrs[xx]);
+ len += 4;
+ }
+ }
+ UINT16_TO_BE_STREAM(p_len, len);
+ p_pkt->len = (p_data - p_start);
+
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function avrc_bld_get_play_status_cmd
+**
+** Description This function builds the Get Play Status
+** command.
+**
+** Returns AVRC_STS_NO_ERROR, if the command is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_get_play_status_cmd (tAVRC_CMD *p_cmd, BT_HDR *p_pkt)
+{
+ AVRC_TRACE_API0("avrc_bld_get_play_status_cmd");
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function avrc_bld_notify_cmd
+**
+** Description This function builds the Register Notification command.
+**
+**
+** Returns AVRC_STS_NO_ERROR, if the command is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_notify_cmd (tAVRC_REG_NOTIF_CMD *p_cmd, BT_HDR *p_pkt)
+{
+ UINT8 *p_data, *p_start;
+
+ AVRC_TRACE_API0("avrc_bld_notify_cmd");
+ if (!AVRC_IS_VALID_EVENT_ID(p_cmd->event_id))
+ {
+ AVRC_TRACE_ERROR1("avrc_bld_notify_cmd bad event_id:0x%x", p_cmd->event_id);
+ return AVRC_STS_BAD_PARAM;
+ }
+
+ /* get the existing length, if any, and also the num attributes */
+ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_start + 2; /* pdu + rsvd */
+
+ /* add fixed lenth 5 - event_id (1) + interval(4) */
+ UINT16_TO_BE_STREAM(p_data, 5);
+ UINT8_TO_BE_STREAM(p_data, p_cmd->event_id);
+ UINT32_TO_BE_STREAM(p_data, p_cmd->param);
+ p_pkt->len = (p_data - p_start);
+
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function avrc_bld_next_cmd
+**
+** Description This function builds the Request Continue or Abort command.
+**
+**
+** Returns AVRC_STS_NO_ERROR, if the command is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_next_cmd (tAVRC_NEXT_CMD *p_cmd, BT_HDR *p_pkt)
+{
+ UINT8 *p_data, *p_start;
+
+ AVRC_TRACE_API0("avrc_bld_next_cmd");
+
+ /* get the existing length, if any, and also the num attributes */
+ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_start + 2; /* pdu + rsvd */
+
+ /* add fixed lenth 1 - pdu_id (1) */
+ UINT16_TO_BE_STREAM(p_data, 1);
+ UINT8_TO_BE_STREAM(p_data, p_cmd->target_pdu);
+ p_pkt->len = (p_data - p_start);
+
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function avrc_bld_group_navigation_cmd
+**
+** Description This function builds the Group Navigation
+** command.
+**
+** Returns AVRC_STS_NO_ERROR, if the command is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+tAVRC_STS avrc_bld_group_navigation_cmd (UINT16 navi_id, BT_HDR *p_pkt)
+{
+ UINT8 *p_data;
+
+ if (!AVRC_IS_VALID_GROUP(navi_id))
+ {
+ AVRC_TRACE_ERROR1("avrc_bld_group_navigation_cmd bad navigation op id: %d", navi_id);
+ return AVRC_STS_BAD_PARAM;
+ }
+
+ AVRC_TRACE_API0("avrc_bld_group_navigation_cmd");
+ p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset;
+ UINT16_TO_BE_STREAM(p_data, navi_id);
+ p_pkt->len = 2;
+ return AVRC_STS_NO_ERROR;
+}
+
+/*****************************************************************************
+** the following commands are introduced in AVRCP 1.4
+*****************************************************************************/
+
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function avrc_bld_set_addr_player_cmd
+**
+** Description This function builds the Set Addresses Player command.
+**
+**
+** Returns AVRC_STS_NO_ERROR, if the command is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_set_addr_player_cmd (tAVRC_SET_ADDR_PLAYER_CMD *p_cmd, BT_HDR *p_pkt)
+{
+ UINT8 *p_data, *p_start;
+
+ AVRC_TRACE_API0("avrc_bld_set_addr_player_cmd");
+ /* get the existing length, if any, and also the num attributes */
+ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_start + 2; /* pdu + rsvd */
+ /* add fixed lenth - player_id(2) */
+ UINT16_TO_BE_STREAM(p_data, 2);
+ UINT16_TO_BE_STREAM(p_data, p_cmd->player_id);
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function avrc_bld_set_abs_volume_cmd
+**
+** Description This function builds the Set Absolute Volume command.
+**
+**
+** Returns AVRC_STS_NO_ERROR, if the command is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_set_abs_volume_cmd (tAVRC_SET_VOLUME_CMD *p_cmd, BT_HDR *p_pkt)
+{
+ UINT8 *p_data, *p_start;
+
+ AVRC_TRACE_API0("avrc_bld_set_abs_volume_cmd");
+ /* get the existing length, if any, and also the num attributes */
+ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_start + 2; /* pdu + rsvd */
+ /* add fixed lenth 1 - volume (1) */
+ UINT16_TO_BE_STREAM(p_data, 1);
+ UINT8_TO_BE_STREAM(p_data, (AVRC_MAX_VOLUME & p_cmd->volume));
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function avrc_bld_set_browsed_player_cmd
+**
+** Description This function builds the Set Browsed Player command.
+**
+** This message goes through the Browsing channel and is
+** valid only when AVCT_BROWSE_INCLUDED compile option is TRUE
+**
+** Returns AVRC_STS_NO_ERROR, if the command is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+static tAVRC_STS avrc_bld_set_browsed_player_cmd (tAVRC_SET_BR_PLAYER_CMD *p_cmd, BT_HDR *p_pkt)
+{
+ UINT8 *p_data, *p_start;
+
+ AVRC_TRACE_API0("avrc_bld_set_browsed_player_cmd");
+ /* get the existing length, if any, and also the num attributes */
+ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_start + 1; /* pdu */
+ /* add fixed lenth - player_id(2) */
+ UINT16_TO_BE_STREAM(p_data, 2);
+ UINT16_TO_BE_STREAM(p_data, p_cmd->player_id);
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+#endif
+
+/*******************************************************************************
+**
+** Function avrc_bld_get_folder_items_cmd
+**
+** Description This function builds the Get Folder Items command.
+**
+** This message goes through the Browsing channel and is
+** valid only when AVCT_BROWSE_INCLUDED compile option is TRUE
+**
+** Returns AVRC_STS_NO_ERROR, if the command is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+static tAVRC_STS avrc_bld_get_folder_items_cmd (tAVRC_GET_ITEMS_CMD *p_cmd, BT_HDR *p_pkt)
+{
+ UINT8 *p_data, *p_start;
+ UINT8 *p_len, xx;
+ UINT16 len = 0;
+
+ AVRC_TRACE_API0("avrc_bld_get_folder_items_cmd");
+ if (p_cmd->scope > AVRC_SCOPE_NOW_PLAYING || p_cmd->start_item > p_cmd->end_item)
+ {
+ AVRC_TRACE_ERROR3("bad scope:0x%x or range (%d-%d)", p_cmd->scope, p_cmd->start_item, p_cmd->end_item);
+ return AVRC_STS_BAD_PARAM;
+ }
+
+ /* get the existing length, if any, and also the num attributes */
+ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ p_len = p_start + 1; /* pdu */
+ p_data = p_len + 2;
+
+ UINT8_TO_BE_STREAM(p_data, p_cmd->scope);
+ UINT32_TO_BE_STREAM(p_data, p_cmd->start_item);
+ UINT32_TO_BE_STREAM(p_data, p_cmd->end_item);
+ /* do not allow us to send the command with attribute list when scope is player list */
+ if (p_cmd->scope == AVRC_SCOPE_PLAYER_LIST)
+ p_cmd->attr_count = 0;
+
+ UINT8_TO_BE_STREAM(p_data, p_cmd->attr_count);
+ len = 10;
+ if ((p_cmd->attr_count != AVRC_FOLDER_ITEM_COUNT_NONE) &&
+ (p_cmd->attr_count > 0))
+ {
+ if (p_cmd->p_attr_list)
+ {
+ for (xx=0; xx<p_cmd->attr_count; xx++)
+ {
+ UINT32_TO_BE_STREAM(p_data, p_cmd->p_attr_list[xx]);
+ len += 4;
+ }
+ }
+ else
+ {
+ AVRC_TRACE_ERROR1("attr_count:%d but NULL p_attr_list", p_cmd->attr_count);
+ return AVRC_STS_BAD_PARAM;
+ }
+ }
+
+ UINT16_TO_BE_STREAM(p_len, len);
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+#endif
+
+/*******************************************************************************
+**
+** Function avrc_bld_change_path_cmd
+**
+** Description This function builds the Change Path command.
+**
+** This message goes through the Browsing channel and is
+** valid only when AVCT_BROWSE_INCLUDED compile option is TRUE
+**
+** Returns AVRC_STS_NO_ERROR, if the command is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+static tAVRC_STS avrc_bld_change_path_cmd (tAVRC_CHG_PATH_CMD *p_cmd, BT_HDR *p_pkt)
+{
+ UINT8 *p_data, *p_start;
+
+ AVRC_TRACE_API0("avrc_bld_change_path_cmd");
+ if (p_cmd->direction != AVRC_DIR_UP && p_cmd->direction != AVRC_DIR_DOWN)
+ {
+ AVRC_TRACE_ERROR1("AVRC_BldChangePathCmd bad direction:%d", p_cmd->direction);
+ return AVRC_STS_BAD_PARAM;
+ }
+
+ /* get the existing length, if any, and also the num attributes */
+ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_start + 1; /* pdu */
+ /* add fixed lenth - uid_counter(2) + direction(1) + uid(8) */
+ UINT16_TO_BE_STREAM(p_data, 11);
+ UINT16_TO_BE_STREAM(p_data, p_cmd->uid_counter);
+ *p_data++ = p_cmd->direction;
+ ARRAY_TO_BE_STREAM(p_data, p_cmd->folder_uid, AVRC_UID_SIZE);
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+#endif
+
+/*******************************************************************************
+**
+** Function avrc_bld_get_item_attrs_cmd
+**
+** Description This function builds the Get Item Attributes command.
+**
+** This message goes through the Browsing channel and is
+** valid only when AVCT_BROWSE_INCLUDED compile option is TRUE
+**
+** Returns AVRC_STS_NO_ERROR, if the command is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+static tAVRC_STS avrc_bld_get_item_attrs_cmd (tAVRC_GET_ATTRS_CMD *p_cmd, BT_HDR *p_pkt)
+{
+ UINT8 *p_data, *p_start;
+ UINT8 *p_len, xx;
+ UINT16 len;
+ UINT8 *p_count;
+
+ AVRC_TRACE_API0("avrc_bld_get_item_attrs_cmd");
+ if (p_cmd->scope > AVRC_SCOPE_NOW_PLAYING)
+ {
+ AVRC_TRACE_ERROR1("bad scope:%d", p_cmd->scope);
+ return AVRC_STS_BAD_PARAM;
+ }
+
+ /* get the existing length, if any, and also the num attributes */
+ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ p_len = p_start + 1; /* pdu */
+ p_data = p_len + 2;
+
+ UINT8_TO_BE_STREAM(p_data, p_cmd->scope);
+ ARRAY_TO_BE_STREAM(p_data, p_cmd->uid, AVRC_UID_SIZE);
+ UINT16_TO_BE_STREAM(p_data, p_cmd->uid_counter);
+ //UINT8_TO_BE_STREAM(p_data, p_cmd->attr_count);
+ p_count = p_data++;
+ len = AVRC_UID_SIZE + 4;
+ *p_count = 0;
+
+ if (p_cmd->attr_count>0)
+ {
+ if (p_cmd->p_attr_list)
+ {
+ for (xx=0; xx<p_cmd->attr_count; xx++)
+ {
+ if (AVRC_IS_VALID_MEDIA_ATTRIBUTE(p_cmd->p_attr_list[xx]))
+ {
+ (*p_count)++;
+ UINT32_TO_BE_STREAM(p_data, p_cmd->p_attr_list[xx]);
+ len += 4;
+ }
+#if (BT_USE_TRACES == TRUE)
+ else
+ {
+ AVRC_TRACE_ERROR1("invalid attr id:%d", p_cmd->p_attr_list[xx]);
+ }
+#endif
+ }
+ }
+#if (BT_USE_TRACES == TRUE)
+ else
+ {
+ AVRC_TRACE_ERROR1("attr_count:%d, NULL p_attr_list", p_cmd->attr_count);
+ }
+#endif
+ }
+ UINT16_TO_BE_STREAM(p_len, len);
+
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+#endif
+
+/*******************************************************************************
+**
+** Function avrc_bld_search_cmd
+**
+** Description This function builds the Search command.
+**
+** This message goes through the Browsing channel and is
+** valid only when AVCT_BROWSE_INCLUDED compile option is TRUE
+**
+** Returns AVRC_STS_NO_ERROR, if the command is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+static tAVRC_STS avrc_bld_search_cmd (tAVRC_SEARCH_CMD *p_cmd, BT_HDR *p_pkt)
+{
+ UINT8 *p_data, *p_start;
+ UINT16 len;
+
+ AVRC_TRACE_API0("avrc_bld_search_cmd");
+ if (!p_cmd->string.p_str)
+ {
+ AVRC_TRACE_ERROR0("null string");
+ return AVRC_STS_BAD_PARAM;
+ }
+
+ /* get the existing length, if any, and also the num attributes */
+ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_start + 1; /* pdu */
+ /* variable lenth */
+ len = p_cmd->string.str_len + 4;
+ UINT16_TO_BE_STREAM(p_data, len);
+
+ UINT16_TO_BE_STREAM(p_data, p_cmd->string.charset_id);
+ UINT16_TO_BE_STREAM(p_data, p_cmd->string.str_len);
+ ARRAY_TO_BE_STREAM(p_data, p_cmd->string.p_str, p_cmd->string.str_len);
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+#endif
+
+/*******************************************************************************
+**
+** Function avrc_bld_play_item_cmd
+**
+** Description This function builds the Play Item command.
+**
+**
+** Returns AVRC_STS_NO_ERROR, if the command is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_play_item_cmd (tAVRC_PLAY_ITEM_CMD *p_cmd, BT_HDR *p_pkt)
+{
+ UINT8 *p_data, *p_start;
+
+ AVRC_TRACE_API0("avrc_bld_play_item_cmd");
+ /* get the existing length, if any, and also the num attributes */
+ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_start + 2; /* pdu + rsvd */
+
+ /* fixed lenth - scope(1) + uid(8) + uid_counter(2) */
+ UINT16_TO_BE_STREAM(p_data, 11);
+
+ UINT8_TO_BE_STREAM(p_data, p_cmd->scope);
+ ARRAY_TO_BE_STREAM(p_data, p_cmd->uid, AVRC_UID_SIZE);
+ UINT16_TO_BE_STREAM(p_data, p_cmd->uid_counter);
+ p_pkt->len = (p_data - p_start);
+
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function avrc_bld_add_to_now_playing_cmd
+**
+** Description This function builds the Add to Now Playing command.
+**
+**
+** Returns AVRC_STS_NO_ERROR, if the command is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_add_to_now_playing_cmd (tAVRC_ADD_TO_PLAY_CMD *p_cmd, BT_HDR *p_pkt)
+{
+ AVRC_TRACE_API0("avrc_bld_add_to_now_playing_cmd");
+ return avrc_bld_play_item_cmd((tAVRC_PLAY_ITEM_CMD *)p_cmd, p_pkt);
+}
+
+#endif /* AVRC_ADV_CTRL_INCLUDED=TRUE */
+
+/*******************************************************************************
+**
+** Function avrc_bld_init_cmd_buffer
+**
+** Description This function initializes the command buffer based on PDU
+**
+** Returns NULL, if no GKI buffer or failure to build the message.
+** Otherwise, the GKI buffer that contains the initialized message.
+**
+*******************************************************************************/
+static BT_HDR *avrc_bld_init_cmd_buffer(tAVRC_COMMAND *p_cmd)
+{
+ UINT16 offset, chnl = AVCT_DATA_CTRL, len=AVRC_META_CMD_POOL_SIZE;
+ BT_HDR *p_pkt=NULL;
+ UINT8 opcode;
+
+ opcode = avrc_opcode_from_pdu(p_cmd->pdu);
+ AVRC_TRACE_API2("avrc_bld_init_cmd_buffer: pdu=%x, opcode=%x", p_cmd->pdu, opcode);
+
+ switch (opcode)
+ {
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+ case AVRC_OP_BROWSE:
+ chnl = AVCT_DATA_BROWSE;
+ offset = AVCT_BROWSE_OFFSET;
+ len = AVRC_BROWSE_POOL_SIZE;
+ break;
+#endif /* AVCT_BROWSE_INCLUDED */
+
+ case AVRC_OP_PASS_THRU:
+ offset = AVRC_MSG_PASS_THRU_OFFSET;
+ break;
+
+ case AVRC_OP_VENDOR:
+ offset = AVRC_MSG_VENDOR_OFFSET;
+ break;
+ }
+
+ /* allocate and initialize the buffer */
+ p_pkt = (BT_HDR *)GKI_getbuf(len);
+ if (p_pkt)
+ {
+ UINT8 *p_data, *p_start;
+
+ p_pkt->layer_specific = chnl;
+ p_pkt->event = opcode;
+ p_pkt->offset = offset;
+ p_data = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ p_start = p_data;
+
+ /* pass thru - group navigation - has a two byte op_id, so dont do it here */
+ if (opcode != AVRC_OP_PASS_THRU)
+ *p_data++ = p_cmd->pdu;
+
+ switch (opcode)
+ {
+ case AVRC_OP_VENDOR:
+ /* reserved 0, packet_type 0 */
+ UINT8_TO_BE_STREAM(p_data, 0);
+ /* continue to the next "case to add length */
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+ case AVRC_OP_BROWSE:
+#endif
+ /* add fixed lenth - 0 */
+ UINT16_TO_BE_STREAM(p_data, 0);
+ break;
+ }
+
+ p_pkt->len = (p_data - p_start);
+ }
+ p_cmd->cmd.opcode = opcode;
+ return p_pkt;
+}
+
+/*******************************************************************************
+**
+** Function AVRC_BldCommand
+**
+** Description This function builds the given AVRCP command to the given
+** GKI buffer
+**
+** Returns AVRC_STS_NO_ERROR, if the command is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+tAVRC_STS AVRC_BldCommand( tAVRC_COMMAND *p_cmd, BT_HDR **pp_pkt)
+{
+ tAVRC_STS status = AVRC_STS_BAD_PARAM;
+ BT_HDR *p_pkt;
+ BOOLEAN alloc = FALSE;
+
+ AVRC_TRACE_API2("AVRC_BldCommand: pdu=%x status=%x", p_cmd->cmd.pdu, p_cmd->cmd.status);
+ if (!p_cmd || !pp_pkt)
+ {
+ AVRC_TRACE_API2("AVRC_BldCommand. Invalid parameters passed. p_cmd=%p, pp_pkt=%p", p_cmd, pp_pkt);
+ return AVRC_STS_BAD_PARAM;
+ }
+
+ if (*pp_pkt == NULL)
+ {
+ if ((*pp_pkt = avrc_bld_init_cmd_buffer(p_cmd)) == NULL)
+ {
+ AVRC_TRACE_API0("AVRC_BldCommand: Failed to initialize command buffer");
+ return AVRC_STS_INTERNAL_ERR;
+ }
+ alloc = TRUE;
+ }
+ status = AVRC_STS_NO_ERROR;
+ p_pkt = *pp_pkt;
+
+ switch (p_cmd->pdu)
+ {
+ case AVRC_PDU_NEXT_GROUP: /* 0x00 */
+ case AVRC_PDU_PREV_GROUP: /* 0x01 */
+ status = avrc_bld_group_navigation_cmd (p_cmd->pdu, p_pkt);
+ break;
+
+ case AVRC_PDU_GET_CAPABILITIES:
+ status = avrc_bld_get_capability_cmd(&p_cmd->get_caps, p_pkt);
+ break;
+
+ case AVRC_PDU_LIST_PLAYER_APP_ATTR:
+ status = avrc_bld_list_app_settings_attr_cmd(&p_cmd->list_app_attr, p_pkt);
+ break;
+
+ case AVRC_PDU_LIST_PLAYER_APP_VALUES:
+ status = avrc_bld_list_app_settings_values_cmd(&p_cmd->list_app_values, p_pkt);
+ break;
+
+ case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE:
+ status = avrc_bld_get_cur_app_setting_value_cmd(&p_cmd->get_cur_app_val, p_pkt);
+ break;
+
+ case AVRC_PDU_SET_PLAYER_APP_VALUE:
+ status = avrc_bld_set_app_setting_value_cmd(&p_cmd->set_app_val, p_pkt);
+ break;
+
+ case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT:
+ status = avrc_bld_get_app_setting_attr_text_cmd(&p_cmd->get_app_attr_txt, p_pkt);
+ break;
+
+ case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT:
+ status = avrc_bld_get_app_setting_value_text_cmd(&p_cmd->get_app_val_txt, p_pkt);
+ break;
+
+ case AVRC_PDU_INFORM_DISPLAY_CHARSET:
+ status = avrc_bld_inform_charset_cmd(&p_cmd->inform_charset, p_pkt);
+ break;
+
+ case AVRC_PDU_INFORM_BATTERY_STAT_OF_CT:
+ status = avrc_bld_inform_battery_status_cmd(&p_cmd->inform_battery_status, p_pkt);
+ break;
+
+ case AVRC_PDU_GET_ELEMENT_ATTR:
+ status = avrc_bld_get_elem_attrs_cmd(&p_cmd->get_elem_attrs, p_pkt);
+ break;
+
+ case AVRC_PDU_GET_PLAY_STATUS:
+ status = avrc_bld_get_play_status_cmd(&p_cmd->get_play_status, p_pkt);
+ break;
+
+ case AVRC_PDU_REGISTER_NOTIFICATION:
+ status = avrc_bld_notify_cmd(&p_cmd->reg_notif, p_pkt);
+ break;
+
+ case AVRC_PDU_REQUEST_CONTINUATION_RSP: /* 0x40 */
+ status = avrc_bld_next_cmd(&p_cmd->continu, p_pkt);
+ break;
+
+ case AVRC_PDU_ABORT_CONTINUATION_RSP: /* 0x41 */
+ status = avrc_bld_next_cmd(&p_cmd->abort, p_pkt);
+ break;
+
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
+ case AVRC_PDU_SET_ABSOLUTE_VOLUME: /* 0x50 */
+ status = avrc_bld_set_abs_volume_cmd(&p_cmd->volume, p_pkt);
+ break;
+
+ case AVRC_PDU_SET_ADDRESSED_PLAYER: /* 0x60 */
+ status = avrc_bld_set_addr_player_cmd(&p_cmd->addr_player, p_pkt);
+ break;
+
+ case AVRC_PDU_PLAY_ITEM: /* 0x74 */
+ status = avrc_bld_play_item_cmd(&p_cmd->play_item, p_pkt);
+ break;
+
+ case AVRC_PDU_ADD_TO_NOW_PLAYING: /* 0x90 */
+ status = avrc_bld_add_to_now_playing_cmd(&p_cmd->add_to_play, p_pkt);
+ break;
+
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+ case AVRC_PDU_SET_BROWSED_PLAYER: /* 0x70 */
+ status = avrc_bld_set_browsed_player_cmd(&p_cmd->br_player, p_pkt);
+ break;
+
+ case AVRC_PDU_GET_FOLDER_ITEMS: /* 0x71 */
+ status = avrc_bld_get_folder_items_cmd(&p_cmd->get_items, p_pkt);
+ break;
+
+ case AVRC_PDU_CHANGE_PATH: /* 0x72 */
+ status = avrc_bld_change_path_cmd(&p_cmd->chg_path, p_pkt);
+ break;
+
+ case AVRC_PDU_GET_ITEM_ATTRIBUTES: /* 0x73 */
+ status = avrc_bld_get_item_attrs_cmd(&p_cmd->get_attrs, p_pkt);
+ break;
+
+ case AVRC_PDU_SEARCH: /* 0x80 */
+ status = avrc_bld_search_cmd(&p_cmd->search, p_pkt);
+ break;
+#endif
+#endif
+
+ }
+
+ if (alloc && (status != AVRC_STS_NO_ERROR) )
+ {
+ GKI_freebuf(p_pkt);
+ *pp_pkt = NULL;
+ }
+ AVRC_TRACE_API1("AVRC_BldCommand: returning %d", status);
+ return status;
+}
+#endif /* (AVRC_METADATA_INCLUDED == TRUE) */
+
diff --git a/stack/avrc/avrc_bld_tg.c b/stack/avrc/avrc_bld_tg.c
new file mode 100644
index 0000000..667499e
--- /dev/null
+++ b/stack/avrc/avrc_bld_tg.c
@@ -0,0 +1,1547 @@
+/*****************************************************************************
+**
+** Name: avrc_bld_tg.c
+**
+** Description:Interface to AVRCP build message functions for the Target Role
+**
+** Copyright (c) 2008-2008, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include <string.h>
+
+#include "gki.h"
+#include "avrc_api.h"
+#include "avrc_defs.h"
+#include "avrc_int.h"
+
+/*****************************************************************************
+** Global data
+*****************************************************************************/
+#if (AVRC_METADATA_INCLUDED == TRUE)
+
+/*******************************************************************************
+**
+** Function avrc_bld_get_capability_rsp
+**
+** Description This function builds the Get Capability response.
+**
+** Returns AVRC_STS_NO_ERROR, if the response is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_get_capability_rsp (tAVRC_GET_CAPS_RSP *p_rsp, BT_HDR *p_pkt)
+{
+ UINT8 *p_data, *p_start, *p_len, *p_count;
+ UINT16 len = 0;
+ UINT8 xx;
+ UINT32 *p_company_id;
+ UINT8 *p_event_id;
+ tAVRC_STS status = AVRC_STS_NO_ERROR;
+
+ if (!(AVRC_IS_VALID_CAP_ID(p_rsp->capability_id)))
+ {
+ AVRC_TRACE_ERROR1("avrc_bld_get_capability_rsp bad parameter. p_rsp: %x", p_rsp);
+ status = AVRC_STS_BAD_PARAM;
+ return status;
+ }
+
+ AVRC_TRACE_API0("avrc_bld_get_capability_rsp");
+ /* get the existing length, if any, and also the num attributes */
+ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_len = p_start + 2; /* pdu + rsvd */
+
+ BE_STREAM_TO_UINT16(len, p_data);
+ UINT8_TO_BE_STREAM(p_data, p_rsp->capability_id);
+ p_count = p_data;
+
+ if (len == 0)
+ {
+ *p_count = p_rsp->count;
+ p_data++;
+ len = 2; /* move past the capability_id and count */
+ }
+ else
+ {
+ p_data = p_start + p_pkt->len;
+ *p_count += p_rsp->count;
+ }
+
+ if (p_rsp->capability_id == AVRC_CAP_COMPANY_ID)
+ {
+ p_company_id = p_rsp->param.company_id;
+ for (xx=0; xx< p_rsp->count; xx++)
+ {
+ UINT24_TO_BE_STREAM(p_data, p_company_id[xx]);
+ }
+ len += p_rsp->count * 3;
+ }
+ else
+ {
+ p_event_id = p_rsp->param.event_id;
+ *p_count = 0;
+ for (xx=0; xx< p_rsp->count; xx++)
+ {
+ if (AVRC_IS_VALID_EVENT_ID(p_event_id[xx]))
+ {
+ (*p_count)++;
+ UINT8_TO_BE_STREAM(p_data, p_event_id[xx]);
+ }
+ }
+ len += (*p_count);
+ }
+ UINT16_TO_BE_STREAM(p_len, len);
+ p_pkt->len = (p_data - p_start);
+ status = AVRC_STS_NO_ERROR;
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function avrc_bld_list_app_settings_attr_rsp
+**
+** Description This function builds the List Application Settings Attribute
+** response.
+**
+** Returns AVRC_STS_NO_ERROR, if the response is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_list_app_settings_attr_rsp (tAVRC_LIST_APP_ATTR_RSP *p_rsp, BT_HDR *p_pkt)
+{
+ UINT8 *p_data, *p_start, *p_len, *p_num;
+ UINT16 len = 0;
+ UINT8 xx;
+
+ AVRC_TRACE_API0("avrc_bld_list_app_settings_attr_rsp");
+ /* get the existing length, if any, and also the num attributes */
+ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_len = p_start + 2; /* pdu + rsvd */
+
+ BE_STREAM_TO_UINT16(len, p_data);
+ p_num = p_data;
+ if (len == 0)
+ {
+ /* first time initialize the attribute count */
+ *p_num = 0;
+ p_data++;
+ }
+ else
+ {
+ p_data = p_start + p_pkt->len;
+ }
+
+ for (xx=0; xx<p_rsp->num_attr; xx++)
+ {
+ if(AVRC_IsValidPlayerAttr(p_rsp->attrs[xx]))
+ {
+ (*p_num)++;
+ UINT8_TO_BE_STREAM(p_data, p_rsp->attrs[xx]);
+ }
+ }
+
+ len = *p_num + 1;
+ UINT16_TO_BE_STREAM(p_len, len);
+ p_pkt->len = (p_data - p_start);
+
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function avrc_bld_list_app_settings_values_rsp
+**
+** Description This function builds the List Application Setting Values
+** response.
+**
+** Returns AVRC_STS_NO_ERROR, if the response is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_list_app_settings_values_rsp (tAVRC_LIST_APP_VALUES_RSP *p_rsp, BT_HDR *p_pkt)
+{
+ UINT8 *p_data, *p_start, *p_len, *p_num;
+ UINT8 xx;
+ UINT16 len;
+
+ AVRC_TRACE_API0("avrc_bld_list_app_settings_values_rsp");
+
+ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_len = p_start + 2; /* pdu + rsvd */
+
+ /* get the existing length, if any, and also the num attributes */
+ BE_STREAM_TO_UINT16(len, p_data);
+ p_num = p_data;
+ /* first time initialize the attribute count */
+ if (len == 0)
+ {
+ *p_num = p_rsp->num_val;
+ p_data++;
+ }
+ else
+ {
+ p_data = p_start + p_pkt->len;
+ *p_num += p_rsp->num_val;
+ }
+
+
+ for (xx=0; xx<p_rsp->num_val; xx++)
+ {
+ UINT8_TO_BE_STREAM(p_data, p_rsp->vals[xx]);
+ }
+
+ len = *p_num + 1;
+ UINT16_TO_BE_STREAM(p_len, len);
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function avrc_bld_get_cur_app_setting_value_rsp
+**
+** Description This function builds the Get Current Application Setting Value
+** response.
+**
+** Returns AVRC_STS_NO_ERROR, if the response is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_get_cur_app_setting_value_rsp (tAVRC_GET_CUR_APP_VALUE_RSP *p_rsp, BT_HDR *p_pkt)
+{
+ UINT8 *p_data, *p_start, *p_len, *p_count;
+ UINT16 len;
+ UINT8 xx;
+
+ if (!p_rsp->p_vals)
+ {
+ AVRC_TRACE_ERROR0("avrc_bld_get_cur_app_setting_value_rsp NULL parameter");
+ return AVRC_STS_BAD_PARAM;
+ }
+
+ AVRC_TRACE_API0("avrc_bld_get_cur_app_setting_value_rsp");
+ /* get the existing length, if any, and also the num attributes */
+ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_len = p_start + 2; /* pdu + rsvd */
+
+ BE_STREAM_TO_UINT16(len, p_data);
+ p_count = p_data;
+ if (len == 0)
+ {
+ /* first time initialize the attribute count */
+ *p_count = 0;
+ p_data++;
+ }
+ else
+ {
+ p_data = p_start + p_pkt->len;
+ }
+
+ for (xx=0; xx<p_rsp->num_val; xx++)
+ {
+ if (avrc_is_valid_player_attrib_value(p_rsp->p_vals[xx].attr_id, p_rsp->p_vals[xx].attr_val))
+ {
+ (*p_count)++;
+ UINT8_TO_BE_STREAM(p_data, p_rsp->p_vals[xx].attr_id);
+ UINT8_TO_BE_STREAM(p_data, p_rsp->p_vals[xx].attr_val);
+ }
+ }
+ len = ((*p_count) << 1) + 1;
+ UINT16_TO_BE_STREAM(p_len, len);
+ p_pkt->len = (p_data - p_start);
+
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function avrc_bld_set_app_setting_value_rsp
+**
+** Description This function builds the Set Application Setting Value
+** response.
+**
+** Returns AVRC_STS_NO_ERROR, if the response is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_set_app_setting_value_rsp (tAVRC_RSP *p_rsp, BT_HDR *p_pkt)
+{
+ /* nothing to be added. */
+ AVRC_TRACE_API0("avrc_bld_set_app_setting_value_rsp");
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function avrc_bld_app_setting_text_rsp
+**
+** Description This function builds the Get Application Settings Attribute Text
+** or Get Application Settings Value Text response.
+**
+** Returns AVRC_STS_NO_ERROR, if the response is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_app_setting_text_rsp (tAVRC_GET_APP_ATTR_TXT_RSP *p_rsp, BT_HDR *p_pkt)
+{
+ UINT8 *p_data, *p_start, *p_len, *p_count;
+ UINT16 len, len_left;
+ UINT8 xx;
+ tAVRC_STS sts = AVRC_STS_NO_ERROR;
+ UINT8 num_added = 0;
+
+ if (!p_rsp->p_attrs)
+ {
+ AVRC_TRACE_ERROR0("avrc_bld_app_setting_text_rsp NULL parameter");
+ return AVRC_STS_BAD_PARAM;
+ }
+ /* get the existing length, if any, and also the num attributes */
+ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_len = p_start + 2; /* pdu + rsvd */
+ len_left = GKI_get_buf_size(p_pkt) - BT_HDR_SIZE - p_pkt->offset - p_pkt->len;
+
+ BE_STREAM_TO_UINT16(len, p_data);
+ p_count = p_data;
+
+ if (len == 0)
+ {
+ *p_count = 0;
+ p_data++;
+ }
+ else
+ {
+ p_data = p_start + p_pkt->len;
+ }
+
+ for (xx=0; xx<p_rsp->num_attr; xx++)
+ {
+ if (len_left < (p_rsp->p_attrs[xx].str_len + 4))
+ {
+ AVRC_TRACE_ERROR3("avrc_bld_app_setting_text_rsp out of room (str_len:%d, left:%d)",
+ xx, p_rsp->p_attrs[xx].str_len, len_left);
+ p_rsp->num_attr = num_added;
+ sts = AVRC_STS_INTERNAL_ERR;
+ break;
+ }
+ if ( !p_rsp->p_attrs[xx].str_len || !p_rsp->p_attrs[xx].p_str )
+ {
+ AVRC_TRACE_ERROR1("avrc_bld_app_setting_text_rsp NULL attr text[%d]", xx);
+ continue;
+ }
+ UINT8_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].attr_id);
+ UINT16_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].charset_id);
+ UINT8_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].str_len);
+ ARRAY_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].p_str, p_rsp->p_attrs[xx].str_len);
+ (*p_count)++;
+ num_added++;
+ }
+ len = p_data - p_count;
+ UINT16_TO_BE_STREAM(p_len, len);
+ p_pkt->len = (p_data - p_start);
+
+ return sts;
+}
+
+/*******************************************************************************
+**
+** Function avrc_bld_get_app_setting_attr_text_rsp
+**
+** Description This function builds the Get Application Setting Attribute Text
+** response.
+**
+** Returns AVRC_STS_NO_ERROR, if the response is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_get_app_setting_attr_text_rsp (tAVRC_GET_APP_ATTR_TXT_RSP *p_rsp, BT_HDR *p_pkt)
+{
+ AVRC_TRACE_API0("avrc_bld_get_app_setting_attr_text_rsp");
+ return avrc_bld_app_setting_text_rsp(p_rsp, p_pkt);
+}
+
+/*******************************************************************************
+**
+** Function avrc_bld_get_app_setting_value_text_rsp
+**
+** Description This function builds the Get Application Setting Value Text
+** response.
+**
+** Returns AVRC_STS_NO_ERROR, if the response is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_get_app_setting_value_text_rsp (tAVRC_GET_APP_ATTR_TXT_RSP *p_rsp, BT_HDR *p_pkt)
+{
+ AVRC_TRACE_API0("avrc_bld_get_app_setting_value_text_rsp");
+ return avrc_bld_app_setting_text_rsp(p_rsp, p_pkt);
+}
+
+/*******************************************************************************
+**
+** Function avrc_bld_inform_charset_rsp
+**
+** Description This function builds the Inform Displayable Character Set
+** response.
+**
+** Returns AVRC_STS_NO_ERROR, if the response is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_inform_charset_rsp (tAVRC_RSP *p_rsp, BT_HDR *p_pkt)
+{
+ /* nothing to be added. */
+ AVRC_TRACE_API0("avrc_bld_inform_charset_rsp");
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function avrc_bld_inform_battery_status_rsp
+**
+** Description This function builds the Inform Battery Status
+** response.
+**
+** Returns AVRC_STS_NO_ERROR, if the response is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_inform_battery_status_rsp (tAVRC_RSP *p_rsp, BT_HDR *p_pkt)
+{
+ /* nothing to be added. */
+ AVRC_TRACE_API0("avrc_bld_inform_battery_status_rsp");
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function avrc_bld_get_elem_attrs_rsp
+**
+** Description This function builds the Get Element Attributes
+** response.
+**
+** Returns AVRC_STS_NO_ERROR, if the response is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_get_elem_attrs_rsp (tAVRC_GET_ELEM_ATTRS_RSP *p_rsp, BT_HDR *p_pkt)
+{
+ UINT8 *p_data, *p_start, *p_len, *p_count;
+ UINT16 len;
+ UINT8 xx;
+
+ AVRC_TRACE_API0("avrc_bld_get_elem_attrs_rsp");
+ if (!p_rsp->p_attrs)
+ {
+ AVRC_TRACE_ERROR0("avrc_bld_get_elem_attrs_rsp NULL parameter");
+ return AVRC_STS_BAD_PARAM;
+ }
+
+ /* get the existing length, if any, and also the num attributes */
+ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_len = p_start + 2; /* pdu + rsvd */
+
+ BE_STREAM_TO_UINT16(len, p_data);
+ p_count = p_data;
+
+ if (len == 0)
+ {
+ *p_count = 0;
+ p_data++;
+ }
+ else
+ {
+ p_data = p_start + p_pkt->len;
+ }
+
+ for (xx=0; xx<p_rsp->num_attr; xx++)
+ {
+ if (!AVRC_IS_VALID_MEDIA_ATTRIBUTE(p_rsp->p_attrs[xx].attr_id))
+ {
+ AVRC_TRACE_ERROR2("avrc_bld_get_elem_attrs_rsp invalid attr id[%d]: %d", xx, p_rsp->p_attrs[xx].attr_id);
+ continue;
+ }
+ if ( !p_rsp->p_attrs[xx].name.p_str )
+ {
+ p_rsp->p_attrs[xx].name.str_len = 0;
+ }
+ UINT32_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].attr_id);
+ UINT16_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].name.charset_id);
+ UINT16_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].name.str_len);
+ ARRAY_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].name.p_str, p_rsp->p_attrs[xx].name.str_len);
+ (*p_count)++;
+ }
+ len = p_data - p_count;
+ UINT16_TO_BE_STREAM(p_len, len);
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function avrc_bld_get_play_status_rsp
+**
+** Description This function builds the Get Play Status
+** response.
+**
+** Returns AVRC_STS_NO_ERROR, if the response is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_get_play_status_rsp (tAVRC_GET_PLAY_STATUS_RSP *p_rsp, BT_HDR *p_pkt)
+{
+ UINT8 *p_data, *p_start;
+
+ AVRC_TRACE_API0("avrc_bld_get_play_status_rsp");
+ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_start + 2;
+
+ /* add fixed lenth - song len(4) + song position(4) + status(1) */
+ UINT16_TO_BE_STREAM(p_data, 9);
+ UINT32_TO_BE_STREAM(p_data, p_rsp->song_len);
+ UINT32_TO_BE_STREAM(p_data, p_rsp->song_pos);
+ UINT8_TO_BE_STREAM(p_data, p_rsp->play_status);
+ p_pkt->len = (p_data - p_start);
+
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function avrc_bld_notify_rsp
+**
+** Description This function builds the Notification response.
+**
+** Returns AVRC_STS_NO_ERROR, if the response is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_notify_rsp (tAVRC_REG_NOTIF_RSP *p_rsp, BT_HDR *p_pkt)
+{
+ UINT8 *p_data, *p_start;
+ UINT8 *p_len;
+ UINT16 len = 0;
+ UINT8 xx;
+ tAVRC_STS status = AVRC_STS_NO_ERROR;
+
+ AVRC_TRACE_API0("avrc_bld_notify_rsp");
+
+ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_len = p_start + 2; /* pdu + rsvd */
+ p_data += 2;
+
+ UINT8_TO_BE_STREAM(p_data, p_rsp->event_id);
+ switch (p_rsp->event_id)
+ {
+ case AVRC_EVT_PLAY_STATUS_CHANGE: /* 0x01 */
+ /* p_rsp->param.play_status >= AVRC_PLAYSTATE_STOPPED is always TRUE */
+ if ((p_rsp->param.play_status <= AVRC_PLAYSTATE_REV_SEEK) ||
+ (p_rsp->param.play_status == AVRC_PLAYSTATE_ERROR) )
+ {
+ UINT8_TO_BE_STREAM(p_data, p_rsp->param.play_status);
+ len = 2;
+ }
+ else
+ {
+ AVRC_TRACE_ERROR0("bad play state");
+ status = AVRC_STS_BAD_PARAM;
+ }
+ break;
+
+ case AVRC_EVT_TRACK_CHANGE: /* 0x02 */
+ ARRAY_TO_BE_STREAM(p_data, p_rsp->param.track, AVRC_UID_SIZE);
+ len = (UINT8)(AVRC_UID_SIZE + 1);
+ break;
+
+ case AVRC_EVT_TRACK_REACHED_END: /* 0x03 */
+ case AVRC_EVT_TRACK_REACHED_START: /* 0x04 */
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
+ case AVRC_EVT_NOW_PLAYING_CHANGE: /* 0x09 */
+ case AVRC_EVT_AVAL_PLAYERS_CHANGE: /* 0x0a */
+#endif
+ len = 1;
+ break;
+
+ case AVRC_EVT_PLAY_POS_CHANGED: /* 0x05 */
+ UINT32_TO_BE_STREAM(p_data, p_rsp->param.play_pos);
+ len = 5;
+ break;
+
+ case AVRC_EVT_BATTERY_STATUS_CHANGE: /* 0x06 */
+ if (AVRC_IS_VALID_BATTERY_STATUS(p_rsp->param.battery_status))
+ {
+ UINT8_TO_BE_STREAM(p_data, p_rsp->param.battery_status);
+ len = 2;
+ }
+ else
+ {
+ AVRC_TRACE_ERROR0("bad battery status");
+ status = AVRC_STS_BAD_PARAM;
+ }
+ break;
+
+ case AVRC_EVT_SYSTEM_STATUS_CHANGE: /* 0x07 */
+ if (AVRC_IS_VALID_SYSTEM_STATUS(p_rsp->param.system_status))
+ {
+ UINT8_TO_BE_STREAM(p_data, p_rsp->param.system_status);
+ len = 2;
+ }
+ else
+ {
+ AVRC_TRACE_ERROR0("bad system status");
+ status = AVRC_STS_BAD_PARAM;
+ }
+ break;
+
+ case AVRC_EVT_APP_SETTING_CHANGE: /* 0x08 */
+ if (p_rsp->param.player_setting.num_attr > AVRC_MAX_APP_SETTINGS)
+ p_rsp->param.player_setting.num_attr = AVRC_MAX_APP_SETTINGS;
+
+ if (p_rsp->param.player_setting.num_attr > 0)
+ {
+ UINT8_TO_BE_STREAM(p_data, p_rsp->param.player_setting.num_attr);
+ len = 2;
+ for (xx=0; xx<p_rsp->param.player_setting.num_attr; xx++)
+ {
+ if (avrc_is_valid_player_attrib_value(p_rsp->param.player_setting.attr_id[xx], p_rsp->param.player_setting.attr_value[xx]))
+ {
+ UINT8_TO_BE_STREAM(p_data, p_rsp->param.player_setting.attr_id[xx]);
+ UINT8_TO_BE_STREAM(p_data, p_rsp->param.player_setting.attr_value[xx]);
+ }
+ else
+ {
+ AVRC_TRACE_ERROR0("bad player app seeting attribute or value");
+ status = AVRC_STS_BAD_PARAM;
+ break;
+ }
+ len += 2;
+ }
+ }
+ else
+ status = AVRC_STS_BAD_PARAM;
+ break;
+
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
+ case AVRC_EVT_ADDR_PLAYER_CHANGE: /* 0x0b */
+ UINT16_TO_BE_STREAM(p_data, p_rsp->param.addr_player.player_id); /* player_id */
+ UINT16_TO_BE_STREAM(p_data, p_rsp->param.addr_player.uid_counter); /* uid counter */
+ len = 5;
+ break;
+
+ case AVRC_EVT_UIDS_CHANGE: /* 0x0c */
+ UINT16_TO_BE_STREAM(p_data, p_rsp->param.uid_counter); /* uid counter */
+ len = 3;
+ break;
+
+ case AVRC_EVT_VOLUME_CHANGE: /* 0x0d */
+ UINT8_TO_BE_STREAM(p_data, (UINT8)(p_rsp->param.volume&AVRC_MAX_VOLUME));
+ len = 2;
+ break;
+#endif
+
+ default:
+ status = AVRC_STS_BAD_PARAM;
+ AVRC_TRACE_ERROR0("unknown event_id");
+ }
+
+ UINT16_TO_BE_STREAM(p_len, len);
+ p_pkt->len = (p_data - p_start);
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function avrc_bld_next_rsp
+**
+** Description This function builds the Request Continue or Abort
+** response.
+**
+** Returns AVRC_STS_NO_ERROR, if the response is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_next_rsp (tAVRC_RSP *p_rsp, BT_HDR *p_pkt)
+{
+ /* nothing to be added. */
+ AVRC_TRACE_API0("avrc_bld_next_rsp");
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function avrc_bld_group_navigation_rsp
+**
+** Description This function builds the Group Navigation
+** response.
+**
+** Returns AVRC_STS_NO_ERROR, if the response is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+tAVRC_STS avrc_bld_group_navigation_rsp (UINT16 navi_id, BT_HDR *p_pkt)
+{
+ UINT8 *p_data;
+
+ if (!AVRC_IS_VALID_GROUP(navi_id))
+ {
+ AVRC_TRACE_ERROR1("avrc_bld_group_navigation_rsp bad navigation op id: %d", navi_id);
+ return AVRC_STS_BAD_PARAM;
+ }
+
+ AVRC_TRACE_API0("avrc_bld_group_navigation_rsp");
+ p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset;
+ UINT16_TO_BE_STREAM(p_data, navi_id);
+ p_pkt->len = 2;
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function avrc_bld_rejected_rsp
+**
+** Description This function builds the General Response response.
+**
+** Returns AVRC_STS_NO_ERROR, if the response is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_rejected_rsp( tAVRC_RSP *p_rsp, BT_HDR *p_pkt )
+{
+ UINT8 *p_data, *p_start;
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+ UINT8 opcode = avrc_opcode_from_pdu(p_rsp->pdu);
+#endif
+
+ AVRC_TRACE_API2("avrc_bld_rejected_rsp: status=%d, pdu:x%x", p_rsp->status, p_rsp->pdu);
+
+ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+ if (opcode == AVRC_OP_BROWSE)
+ {
+ p_data = p_start + 1;
+ if (avrc_opcode_from_pdu(*p_start) != AVRC_OP_BROWSE)
+ {
+ /* if the given opcode is not recognized as a browsing command opcode, use general reject command */
+ *p_start = AVRC_PDU_GENERAL_REJECT;
+ }
+ }
+ else
+#endif
+ {
+ p_data = p_start + 2;
+ }
+ AVRC_TRACE_DEBUG1("pdu:x%x", *p_start);
+
+ UINT16_TO_BE_STREAM(p_data, 1);
+ UINT8_TO_BE_STREAM(p_data, p_rsp->status);
+ p_pkt->len = p_data - p_start;
+
+ return AVRC_STS_NO_ERROR;
+}
+
+
+/*****************************************************************************
+** the following commands are introduced in AVRCP 1.4
+*****************************************************************************/
+
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function avrc_bld_ctrl_status_rsp
+**
+** Description This function builds the responses with a UINT8 parameter.
+**
+**
+** Returns AVRC_STS_NO_ERROR, if the response is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_ctrl_status_rsp (tAVRC_RSP *p_rsp, BT_HDR *p_pkt)
+{
+ UINT8 *p_data, *p_start;
+
+ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_start + 2; /* pdu + rsvd */
+
+ /* add fixed lenth - status(1) */
+ UINT16_TO_BE_STREAM(p_data, 1);
+ UINT8_TO_BE_STREAM(p_data, p_rsp->status);
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function avrc_bld_set_addr_player_rsp
+**
+** Description This function builds the Set Addresses Player response.
+**
+**
+** Returns AVRC_STS_NO_ERROR, if the response is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_set_addr_player_rsp (tAVRC_RSP *p_rsp, BT_HDR *p_pkt)
+{
+ AVRC_TRACE_API0("avrc_bld_set_addr_player_rsp");
+ return avrc_bld_ctrl_status_rsp(p_rsp, p_pkt);
+}
+
+/*******************************************************************************
+**
+** Function avrc_bld_set_abs_volume_rsp
+**
+** Description This function builds the Set Absolute Volume response.
+**
+**
+** Returns AVRC_STS_NO_ERROR, if the response is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_set_abs_volume_rsp (tAVRC_SET_VOLUME_RSP *p_rsp, BT_HDR *p_pkt)
+{
+ p_rsp->status = (p_rsp->volume & AVRC_MAX_VOLUME);
+ AVRC_TRACE_API2("avrc_bld_set_abs_volume_rsp volume:%d, sts:%d", p_rsp->volume, p_rsp->status);
+ return avrc_bld_ctrl_status_rsp((tAVRC_RSP *)p_rsp, p_pkt);
+}
+
+
+/*******************************************************************************
+**
+** Function avrc_bld_set_browsed_player_rsp
+**
+** Description This function builds the Set Browsed Player response.
+**
+** This message goes through the Browsing channel and is
+** valid only when AVCT_BROWSE_INCLUDED compile option is TRUE
+**
+** Returns AVRC_STS_NO_ERROR, if the response is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+static tAVRC_STS avrc_bld_set_browsed_player_rsp (tAVRC_SET_BR_PLAYER_RSP *p_rsp, BT_HDR *p_pkt)
+{
+ UINT8 *p_data, *p_start;
+ UINT8 *p_len, xx;
+ UINT16 len;
+ tAVRC_NAME *p_folders = p_rsp->p_folders;
+ UINT16 len_left;
+ UINT8 *p_num;
+ UINT16 mtu;
+
+ AVRC_TRACE_API0("avrc_bld_set_browsed_player_rsp");
+ /* make sure the given GKI buffer can accomodate this response */
+ len_left = GKI_get_buf_size(p_pkt) - BT_HDR_SIZE;
+ p_data = (UINT8 *)(p_pkt + 1);
+ BE_STREAM_TO_UINT16 (mtu, p_data);
+ if (len_left > mtu)
+ {
+ len_left = mtu;
+ }
+ len_left = len_left - p_pkt->offset - p_pkt->len;
+ AVRC_TRACE_DEBUG2("len_left:%d, mtu:%d ", len_left, mtu);
+
+ /* get the existing length, if any, and also the num attributes */
+ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_len = p_start + 1; /* pdu */
+
+ /* the existing len */
+ BE_STREAM_TO_UINT16(len, p_data);
+ p_num = p_data + 9;
+ if (len == 0)
+ {
+ /* first time initialize the attribute count */
+ UINT8_TO_BE_STREAM(p_data, p_rsp->status);
+ UINT16_TO_BE_STREAM(p_data, p_rsp->uid_counter);
+ UINT32_TO_BE_STREAM(p_data, p_rsp->num_items);
+ UINT16_TO_BE_STREAM(p_data, p_rsp->charset_id);
+ *p_num = 0;
+ p_data++;
+ len = 10;
+ len_left -= 12; /* assuming that we would never use a GKI buffer that is too small for headers */
+ }
+ else
+ {
+ p_data = p_start + p_pkt->len;
+ }
+
+ for (xx=0; (xx<p_rsp->folder_depth) && (len_left>(p_folders[xx].str_len + 2)); xx++)
+ {
+ (*p_num)++;
+ UINT16_TO_BE_STREAM(p_data, p_folders[xx].str_len);
+ ARRAY_TO_BE_STREAM(p_data, p_folders[xx].p_str, p_folders[xx].str_len);
+ len += (p_folders[xx].str_len + 2);
+ }
+ UINT16_TO_BE_STREAM(p_len, len);
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+#endif
+
+
+/*******************************************************************************
+**
+** Function avrc_bld_get_folder_items_rsp
+**
+** Description This function builds the Get Folder Items response.
+** The error code is returned in *p_status.
+** AVRC_STS_INTERNAL_ERR means no GKI buffers.
+** Try again later or with smaller item_count
+**
+** This message goes through the Browsing channel and is
+** valid only when AVCT_BROWSE_INCLUDED compile option is TRUE
+**
+** Returns AVRC_STS_NO_ERROR, if the response is built successfully
+** AVRC_STS_INTERNAL_ERR, if the given GKI buffer does not have enough room
+** Otherwise, the error code.
+**
+*******************************************************************************/
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+static tAVRC_STS avrc_bld_get_folder_items_rsp (tAVRC_GET_ITEMS_RSP *p_rsp, BT_HDR *p_pkt)
+{
+ UINT8 *p_data, *p_start;
+ UINT8 *p_len, xx;
+ UINT16 len;
+ UINT16 item_len;
+ UINT8 *p_item_len, yy;
+ tAVRC_ITEM_PLAYER *p_player;
+ tAVRC_ITEM_FOLDER *p_folder;
+ tAVRC_ITEM_MEDIA *p_media;
+ tAVRC_ATTR_ENTRY *p_attr;
+ tAVRC_ITEM *p_item_list = p_rsp->p_item_list;
+ tAVRC_STS status = AVRC_STS_NO_ERROR;
+ UINT16 len_left;
+ UINT8 *p_num, *p;
+ UINT8 *p_item_start, *p_attr_count;
+ UINT16 item_count;
+ UINT16 mtu;
+
+ AVRC_TRACE_API0("avrc_bld_get_folder_items_rsp");
+ /* make sure the given GKI buffer can accomodate this response */
+ len_left = GKI_get_buf_size(p_pkt) - BT_HDR_SIZE;
+ p = (UINT8 *)(p_pkt + 1);
+ BE_STREAM_TO_UINT16 (mtu, p);
+ if (len_left > mtu)
+ len_left = mtu;
+ len_left = len_left - p_pkt->offset - p_pkt->len;
+
+ /* get the existing length, if any, and also the num attributes */
+ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_len = p_start + 1; /* pdu */
+
+ /* the existing len */
+ BE_STREAM_TO_UINT16(len, p_data);
+ p_num = p_data + 3;
+ if (len == 0)
+ {
+ /* first time initialize the attribute count */
+ UINT8_TO_BE_STREAM(p_data, p_rsp->status);
+ UINT16_TO_BE_STREAM(p_data, p_rsp->uid_counter);
+ item_count = 0;
+ p_data+= 2;
+ len = 5;
+ len_left -= 5;
+ }
+ else
+ {
+ p_data = p_start + p_pkt->len;
+ p = p_num;
+ BE_STREAM_TO_UINT16 (item_count, p);
+ }
+ AVRC_TRACE_DEBUG3("len:%d, len_left:%d, num:%d", len, len_left, item_count);
+
+ /* min len required = item_type(1) + item len(2) + min item (14) = 17 */
+ for (xx=0; xx<p_rsp->item_count && len_left > 17; xx++)
+ {
+ p_item_start = p_data;
+ UINT8_TO_BE_STREAM(p_data, p_item_list[xx].item_type);
+ /* variable item lenth - save the location to add length */
+ p_item_len = p_data;
+ p_data += 2;
+ item_len = 0;
+ len_left -= 3; /* item_type(1) + item len(2) */
+ switch (p_item_list[xx].item_type)
+ {
+ case AVRC_ITEM_PLAYER:
+ /* min len required: 2 + 1 + 4 + 1 + 16 + 2 + 2 = 30 + str_len */
+ p_player = &p_item_list[xx].u.player;
+ item_len = AVRC_FEATURE_MASK_SIZE + p_player->name.str_len + 12;
+ if ((len_left > item_len) &&
+ p_player->name.p_str &&
+ (p_player->major_type & AVRC_MJ_TYPE_INVALID) == 0 &&
+ (p_player->sub_type & AVRC_SUB_TYPE_INVALID) == 0 &&
+ (p_player->play_status <= AVRC_PLAYSTATE_REV_SEEK || p_player->play_status == AVRC_PLAYSTATE_ERROR) )
+ {
+ UINT16_TO_BE_STREAM(p_data, p_player->player_id);
+ UINT8_TO_BE_STREAM(p_data, p_player->major_type);
+ UINT32_TO_BE_STREAM(p_data, p_player->sub_type);
+ UINT8_TO_BE_STREAM(p_data, p_player->play_status);
+ ARRAY_TO_BE_STREAM(p_data, p_player->features, AVRC_FEATURE_MASK_SIZE);
+ UINT16_TO_BE_STREAM(p_data, p_player->name.charset_id);
+ UINT16_TO_BE_STREAM(p_data, p_player->name.str_len);
+ ARRAY_TO_BE_STREAM(p_data, p_player->name.p_str, p_player->name.str_len);
+ }
+ else
+ {
+ p_data = p_item_start;
+ }
+ break;
+
+ case AVRC_ITEM_FOLDER:
+ /* min len required: 8 + 1 + 1 + 2 + 2 = 14 + str_len */
+ p_folder = &p_item_list[xx].u.folder;
+ item_len = AVRC_UID_SIZE + p_folder->name.str_len + 6;
+ if ((len_left > item_len) &&
+ p_folder->name.p_str &&
+ p_folder->type <= AVRC_FOLDER_TYPE_YEARS &&
+ p_folder->playable <= TRUE)
+ {
+ ARRAY_TO_BE_STREAM(p_data, p_folder->uid, AVRC_UID_SIZE);
+ UINT8_TO_BE_STREAM(p_data, p_folder->type);
+ UINT8_TO_BE_STREAM(p_data, p_folder->playable);
+ UINT16_TO_BE_STREAM(p_data, p_folder->name.charset_id);
+ UINT16_TO_BE_STREAM(p_data, p_folder->name.str_len);
+ ARRAY_TO_BE_STREAM(p_data, p_folder->name.p_str, p_folder->name.str_len);
+ }
+ else
+ {
+ p_data = p_item_start;
+ }
+ break;
+
+ case AVRC_ITEM_MEDIA:
+ /* min len required: 8 + 1 + 2 + 2 + 1 = 14 + str_len */
+ p_media = &p_item_list[xx].u.media;
+ item_len = AVRC_UID_SIZE + p_media->name.str_len + 6;
+ if ((len_left > item_len) &&
+ p_media->name.p_str &&
+ p_media->type <= AVRC_MEDIA_TYPE_VIDEO)
+ {
+ ARRAY_TO_BE_STREAM(p_data, p_media->uid, AVRC_UID_SIZE);
+ UINT8_TO_BE_STREAM(p_data, p_media->type);
+ UINT16_TO_BE_STREAM(p_data, p_media->name.charset_id);
+ UINT16_TO_BE_STREAM(p_data, p_media->name.str_len);
+ ARRAY_TO_BE_STREAM(p_data, p_media->name.p_str, p_media->name.str_len);
+ p_attr_count = p_data++;
+ *p_attr_count = 0;
+ len_left -= item_len;
+ if (p_media->attr_count>0)
+ {
+ p_attr = p_media->p_attr_list;
+ for (yy=0; yy<p_media->attr_count && len_left > 8; yy++)
+ {
+ if (p_attr[yy].name.p_str &&
+ AVRC_IS_VALID_MEDIA_ATTRIBUTE(p_attr[yy].attr_id) &&
+ (len_left >= (p_attr[yy].name.str_len + 8)) )
+ {
+ (*p_attr_count) ++;
+ UINT32_TO_BE_STREAM(p_data, p_attr[yy].attr_id);
+ UINT16_TO_BE_STREAM(p_data, p_attr[yy].name.charset_id);
+ UINT16_TO_BE_STREAM(p_data, p_attr[yy].name.str_len);
+ ARRAY_TO_BE_STREAM(p_data, p_attr[yy].name.p_str, p_attr[yy].name.str_len);
+ item_len += (p_attr[yy].name.str_len + 8);
+ len_left -= (p_attr[yy].name.str_len + 8);
+ }
+ }
+ }
+ }
+ else
+ {
+ p_data = p_item_start;
+ }
+ break;
+ } /* switch item_type */
+
+ if (p_item_start != p_data)
+ {
+ /* successfully added the item */
+ item_count++;
+ /* fill in variable item lenth */
+ UINT16_TO_BE_STREAM(p_item_len, item_len);
+ }
+ else
+ {
+ /* some item is not added properly - set an error status */
+ if (len_left > item_len)
+ status = AVRC_STS_INTERNAL_ERR;
+ else
+ status = AVRC_STS_BAD_PARAM;
+ }
+
+ len += item_len;
+ len += 3; /* the item_type(1) and item_len(2) */
+ AVRC_TRACE_DEBUG4("len:%d, len_left:%d, num:%d, item_len:%d", len, len_left, item_count, item_len);
+ } /* for item_count */
+
+ UINT16_TO_BE_STREAM(p_num, item_count);
+ UINT16_TO_BE_STREAM(p_len, len);
+ p_pkt->len = (p_data - p_start);
+
+ if (p_rsp->item_count != xx)
+ {
+ p_rsp->item_count = xx;
+ if (status == AVRC_STS_NO_ERROR)
+ status = AVRC_STS_INTERNAL_ERR;
+ }
+
+ return status;
+}
+#endif
+
+
+/*******************************************************************************
+**
+** Function avrc_bld_change_path_rsp
+**
+** Description This function builds the Change Path response.
+**
+** This message goes through the Browsing channel and is
+** valid only when AVCT_BROWSE_INCLUDED compile option is TRUE
+**
+** Returns AVRC_STS_NO_ERROR, if the response is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+static tAVRC_STS avrc_bld_change_path_rsp (tAVRC_CHG_PATH_RSP *p_rsp, BT_HDR *p_pkt)
+{
+ UINT8 *p_data, *p_start;
+
+ /* get the existing length, if any, and also the num attributes */
+ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_start + 1; /* pdu */
+ /* add fixed lenth - status(1) + num_items(4) */
+ UINT16_TO_BE_STREAM(p_data, 5);
+ UINT8_TO_BE_STREAM(p_data, p_rsp->status);
+ UINT32_TO_BE_STREAM(p_data, p_rsp->num_items);
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+#endif
+
+
+/*******************************************************************************
+**
+** Function avrc_bld_get_item_attrs_rsp
+**
+** Description This function builds the Get Item Attributes response.
+**
+** This message goes through the Browsing channel and is
+** valid only when AVCT_BROWSE_INCLUDED compile option is TRUE
+**
+** Returns AVRC_STS_NO_ERROR, if the response is built successfully
+** AVRC_STS_INTERNAL_ERR, if the given GKI buffer does not have enough room
+** Otherwise, the error code.
+**
+*******************************************************************************/
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+static tAVRC_STS avrc_bld_get_item_attrs_rsp (tAVRC_GET_ATTRS_RSP *p_rsp, BT_HDR *p_pkt)
+{
+ UINT8 *p_data, *p_start;
+ UINT8 *p_len, xx;
+ UINT16 len, len_left;
+ UINT8 *p_num;
+ UINT16 mtu;
+
+ AVRC_TRACE_API0("avrc_bld_get_item_attrs_rsp");
+ /* calculate the GKI buffer size needed and validate the parameters */
+ if (!p_rsp->p_attr_list)
+ {
+ AVRC_TRACE_ERROR0("NULL p_attr_list");
+ return AVRC_STS_BAD_PARAM;
+ }
+
+ /* check the length before adding the attr to the message */
+ len = 2;
+ for (xx=0; xx<p_rsp->attr_count; xx++)
+ {
+ if(p_rsp->p_attr_list[xx].name.p_str == 0 ||
+ !AVRC_IS_VALID_MEDIA_ATTRIBUTE(p_rsp->p_attr_list[xx].attr_id))
+ {
+ AVRC_TRACE_ERROR2("[%d] NULL p_attr_list str or bad attr_id:%d", xx, p_rsp->p_attr_list[xx].attr_id);
+ return AVRC_STS_BAD_PARAM;
+ }
+ len += (p_rsp->p_attr_list[xx].name.str_len + 8);
+ }
+ len_left = GKI_get_buf_size(p_pkt) - BT_HDR_SIZE;
+ p_data = (UINT8 *)(p_pkt + 1);
+ BE_STREAM_TO_UINT16 (mtu, p_data);
+ if (len_left > mtu)
+ {
+ len_left = mtu;
+ }
+ len_left = len_left - p_pkt->offset - p_pkt->len;
+
+ AVRC_TRACE_DEBUG3("len_left:%d, mtu:%d len needed:%d", len_left, mtu, len);
+ if (len_left < 11) /* 11 is 4/attr_id + 2/charset_id + 2/str_len + 3/first timer/attr count & len */
+ {
+ return AVRC_STS_INTERNAL_ERR;
+ }
+ if (len > len_left)
+ {
+ AVRC_TRACE_ERROR0("The GKI buffer does not have enough room to hold the given data.");
+ }
+
+ /* get the existing length, if any, and also the num attributes */
+ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_len = p_start + 1; /* pdu */
+
+ /* the existing len */
+ BE_STREAM_TO_UINT16(len, p_data);
+ p_num = p_data + 1;
+ if (len == 0)
+ {
+ /* first time initialize the attribute count */
+ UINT8_TO_BE_STREAM(p_data, p_rsp->status);
+ *p_num = 0;
+ p_data++;
+ len = 2;
+ len_left -= 3;
+ }
+ else
+ {
+ p_data = p_start + p_pkt->len;
+ }
+
+
+ for (xx=0; (xx<p_rsp->attr_count) && (len_left>9); xx++)
+ {
+ (*p_num)++;
+ UINT32_TO_BE_STREAM(p_data, p_rsp->p_attr_list[xx].attr_id);
+ UINT16_TO_BE_STREAM(p_data, p_rsp->p_attr_list[xx].name.charset_id);
+ UINT16_TO_BE_STREAM(p_data, p_rsp->p_attr_list[xx].name.str_len);
+ len_left -= 8;
+ if (p_rsp->p_attr_list[xx].name.str_len > len_left)
+ p_rsp->p_attr_list[xx].name.str_len = len_left;
+ ARRAY_TO_BE_STREAM(p_data, p_rsp->p_attr_list[xx].name.p_str, p_rsp->p_attr_list[xx].name.str_len);
+ len_left -= p_rsp->p_attr_list[xx].name.str_len;
+ len += (p_rsp->p_attr_list[xx].name.str_len + 8);
+ }
+
+ UINT16_TO_BE_STREAM(p_len, len);
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+#endif
+
+
+/*******************************************************************************
+**
+** Function avrc_bld_search_rsp
+**
+** Description This function builds the Search response.
+**
+** This message goes through the Browsing channel and is
+** valid only when AVCT_BROWSE_INCLUDED compile option is TRUE
+**
+** Returns AVRC_STS_NO_ERROR, if the response is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+static tAVRC_STS avrc_bld_search_rsp (tAVRC_SEARCH_RSP *p_rsp, BT_HDR *p_pkt)
+{
+ UINT8 *p_data, *p_start, *p_len;
+
+ AVRC_TRACE_API0("avrc_bld_search_rsp");
+ /* get the existing length, if any, and also the num attributes */
+ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_len = p_start + 1; /* pdu */
+
+ /* add fixed lenth - status(1) + uid_counter(2) + num_items(4) */
+ UINT16_TO_BE_STREAM(p_data, 7);
+ UINT8_TO_BE_STREAM(p_data, p_rsp->status);
+ UINT16_TO_BE_STREAM(p_data, p_rsp->uid_counter);
+ UINT32_TO_BE_STREAM(p_data, p_rsp->num_items);
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+#endif
+
+
+/*******************************************************************************
+**
+** Function avrc_bld_play_item_rsp
+**
+** Description This function builds the Play Item response.
+**
+**
+** Returns AVRC_STS_NO_ERROR, if the response is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_play_item_rsp (tAVRC_RSP *p_rsp, BT_HDR *p_pkt)
+{
+ AVRC_TRACE_API0("avrc_bld_play_item_rsp");
+ return avrc_bld_ctrl_status_rsp(p_rsp, p_pkt);
+}
+
+
+/*******************************************************************************
+**
+** Function avrc_bld_add_to_now_playing_rsp
+**
+** Description This function builds the Add to Now Playing response.
+**
+** Returns AVRC_STS_NO_ERROR, if the response is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_add_to_now_playing_rsp (tAVRC_RSP *p_rsp, BT_HDR *p_pkt)
+{
+ AVRC_TRACE_API0("avrc_bld_add_to_now_playing_rsp");
+ return avrc_bld_ctrl_status_rsp(p_rsp, p_pkt);
+}
+
+#endif /* AVRC_ADV_CTRL_INCLUDED=TRUE */
+
+/*******************************************************************************
+**
+** Function avrc_bld_init_rsp_buffer
+**
+** Description This function initializes the response buffer based on PDU
+**
+** Returns NULL, if no GKI buffer or failure to build the message.
+** Otherwise, the GKI buffer that contains the initialized message.
+**
+*******************************************************************************/
+static BT_HDR *avrc_bld_init_rsp_buffer(tAVRC_RESPONSE *p_rsp)
+{
+ UINT16 offset, chnl = AVCT_DATA_CTRL, len=AVRC_META_CMD_POOL_SIZE;
+ BT_HDR *p_pkt=NULL;
+ UINT8 opcode = avrc_opcode_from_pdu(p_rsp->pdu);
+
+ AVRC_TRACE_API3("avrc_bld_init_rsp_buffer: pdu=%x, opcode=%x/%x", p_rsp->pdu, opcode, p_rsp->rsp.opcode);
+ if (opcode != p_rsp->rsp.opcode && p_rsp->rsp.status != AVRC_STS_NO_ERROR && avrc_is_valid_opcode(p_rsp->rsp.opcode))
+ {
+ opcode = p_rsp->rsp.opcode;
+ AVRC_TRACE_API1("opcode=%x", opcode);
+ }
+
+ switch (opcode)
+ {
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+ case AVRC_OP_BROWSE:
+ chnl = AVCT_DATA_BROWSE;
+ offset = AVCT_BROWSE_OFFSET;
+ len = AVRC_BROWSE_POOL_SIZE;
+ break;
+#endif /* AVCT_BROWSE_INCLUDED */
+
+ case AVRC_OP_PASS_THRU:
+ offset = AVRC_MSG_PASS_THRU_OFFSET;
+ break;
+
+ case AVRC_OP_VENDOR:
+ offset = AVRC_MSG_VENDOR_OFFSET;
+ if (p_rsp->pdu == AVRC_PDU_GET_ELEMENT_ATTR)
+ len = AVRC_BROWSE_POOL_SIZE;
+ break;
+ }
+
+ /* allocate and initialize the buffer */
+ p_pkt = (BT_HDR *)GKI_getbuf(len);
+ if (p_pkt)
+ {
+ UINT8 *p_data, *p_start;
+
+ p_pkt->layer_specific = chnl;
+ p_pkt->event = opcode;
+ p_pkt->offset = offset;
+ p_data = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ p_start = p_data;
+
+ /* pass thru - group navigation - has a two byte op_id, so dont do it here */
+ if (opcode != AVRC_OP_PASS_THRU)
+ *p_data++ = p_rsp->pdu;
+
+ switch (opcode)
+ {
+ case AVRC_OP_VENDOR:
+ /* reserved 0, packet_type 0 */
+ UINT8_TO_BE_STREAM(p_data, 0);
+ /* continue to the next "case to add length */
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+ case AVRC_OP_BROWSE:
+#endif
+ /* add fixed lenth - 0 */
+ UINT16_TO_BE_STREAM(p_data, 0);
+ break;
+ }
+
+ p_pkt->len = (p_data - p_start);
+ }
+ p_rsp->rsp.opcode = opcode;
+ return p_pkt;
+}
+
+/*******************************************************************************
+**
+** Function AVRC_BldResponse
+**
+** Description This function builds the given AVRCP response to the given
+** GKI buffer
+**
+** Returns AVRC_STS_NO_ERROR, if the response is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+tAVRC_STS AVRC_BldResponse( UINT8 handle, tAVRC_RESPONSE *p_rsp, BT_HDR **pp_pkt)
+{
+ tAVRC_STS status = AVRC_STS_BAD_PARAM;
+ BT_HDR *p_pkt;
+ BOOLEAN alloc = FALSE;
+#if ((AVRC_ADV_CTRL_INCLUDED == TRUE) && (AVCT_BROWSE_INCLUDED == TRUE))
+ UINT8 *p;
+ UINT16 peer_mtu;
+#endif
+
+ if (!p_rsp || !pp_pkt)
+ {
+ AVRC_TRACE_API2("AVRC_BldResponse. Invalid parameters passed. p_rsp=%p, pp_pkt=%p", p_rsp, pp_pkt);
+ return AVRC_STS_BAD_PARAM;
+ }
+
+ if (*pp_pkt == NULL)
+ {
+ if ((*pp_pkt = avrc_bld_init_rsp_buffer(p_rsp)) == NULL)
+ {
+ AVRC_TRACE_API0("AVRC_BldResponse: Failed to initialize response buffer");
+ return AVRC_STS_INTERNAL_ERR;
+ }
+#if ((AVRC_ADV_CTRL_INCLUDED == TRUE) && (AVCT_BROWSE_INCLUDED == TRUE))
+ if ((*pp_pkt)->layer_specific == AVCT_DATA_BROWSE)
+ {
+ p = (UINT8 *)((*pp_pkt) + 1);
+ peer_mtu = AVCT_GetBrowseMtu(handle) - AVCT_HDR_LEN_SINGLE;
+ UINT16_TO_BE_STREAM(p, peer_mtu);
+ }
+#endif
+ alloc = TRUE;
+ }
+ status = AVRC_STS_NO_ERROR;
+ p_pkt = *pp_pkt;
+
+ AVRC_TRACE_API2("AVRC_BldResponse: pdu=%x status=%x", p_rsp->rsp.pdu, p_rsp->rsp.status);
+ if (p_rsp->rsp.status != AVRC_STS_NO_ERROR)
+ {
+ return( avrc_bld_rejected_rsp(&p_rsp->rsp, p_pkt) );
+ }
+
+ switch (p_rsp->pdu)
+ {
+ case AVRC_PDU_NEXT_GROUP:
+ case AVRC_PDU_PREV_GROUP:
+ status = avrc_bld_group_navigation_rsp(p_rsp->pdu, p_pkt);
+ break;
+
+ case AVRC_PDU_GET_CAPABILITIES:
+ status = avrc_bld_get_capability_rsp(&p_rsp->get_caps, p_pkt);
+ break;
+
+ case AVRC_PDU_LIST_PLAYER_APP_ATTR:
+ status = avrc_bld_list_app_settings_attr_rsp(&p_rsp->list_app_attr, p_pkt);
+ break;
+
+ case AVRC_PDU_LIST_PLAYER_APP_VALUES:
+ status = avrc_bld_list_app_settings_values_rsp(&p_rsp->list_app_values, p_pkt);
+ break;
+
+ case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE:
+ status = avrc_bld_get_cur_app_setting_value_rsp(&p_rsp->get_cur_app_val, p_pkt);
+ break;
+
+ case AVRC_PDU_SET_PLAYER_APP_VALUE:
+ status = avrc_bld_set_app_setting_value_rsp(&p_rsp->set_app_val, p_pkt);
+ break;
+
+ case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT:
+ status = avrc_bld_get_app_setting_attr_text_rsp(&p_rsp->get_app_attr_txt, p_pkt);
+ break;
+
+ case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT:
+ status = avrc_bld_get_app_setting_value_text_rsp(&p_rsp->get_app_val_txt, p_pkt);
+ break;
+
+ case AVRC_PDU_INFORM_DISPLAY_CHARSET:
+ status = avrc_bld_inform_charset_rsp(&p_rsp->inform_charset, p_pkt);
+ break;
+
+ case AVRC_PDU_INFORM_BATTERY_STAT_OF_CT:
+ status = avrc_bld_inform_battery_status_rsp(&p_rsp->inform_battery_status, p_pkt);
+ break;
+
+ case AVRC_PDU_GET_ELEMENT_ATTR:
+ status = avrc_bld_get_elem_attrs_rsp(&p_rsp->get_elem_attrs, p_pkt);
+ break;
+
+ case AVRC_PDU_GET_PLAY_STATUS:
+ status = avrc_bld_get_play_status_rsp(&p_rsp->get_play_status, p_pkt);
+ break;
+
+ case AVRC_PDU_REGISTER_NOTIFICATION:
+ status = avrc_bld_notify_rsp(&p_rsp->reg_notif, p_pkt);
+ break;
+
+ case AVRC_PDU_REQUEST_CONTINUATION_RSP: /* 0x40 */
+ status = avrc_bld_next_rsp(&p_rsp->continu, p_pkt);
+ break;
+
+ case AVRC_PDU_ABORT_CONTINUATION_RSP: /* 0x41 */
+ status = avrc_bld_next_rsp(&p_rsp->abort, p_pkt);
+ break;
+
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
+ case AVRC_PDU_SET_ABSOLUTE_VOLUME: /* 0x50 */
+ status = avrc_bld_set_abs_volume_rsp(&p_rsp->volume, p_pkt);
+ break;
+
+ case AVRC_PDU_SET_ADDRESSED_PLAYER: /* 0x60 */
+ status = avrc_bld_set_addr_player_rsp(&p_rsp->addr_player, p_pkt);
+ break;
+
+ case AVRC_PDU_PLAY_ITEM: /* 0x74 */
+ status = avrc_bld_play_item_rsp(&p_rsp->play_item, p_pkt);
+ break;
+
+ case AVRC_PDU_ADD_TO_NOW_PLAYING: /* 0x90 */
+ status = avrc_bld_add_to_now_playing_rsp(&p_rsp->add_to_play, p_pkt);
+ break;
+
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+ case AVRC_PDU_SET_BROWSED_PLAYER: /* 0x70 */
+ status = avrc_bld_set_browsed_player_rsp(&p_rsp->br_player, p_pkt);
+ break;
+
+ case AVRC_PDU_GET_FOLDER_ITEMS: /* 0x71 */
+ status = avrc_bld_get_folder_items_rsp(&p_rsp->get_items, p_pkt);
+ break;
+
+ case AVRC_PDU_CHANGE_PATH: /* 0x72 */
+ status = avrc_bld_change_path_rsp(&p_rsp->chg_path, p_pkt);
+ break;
+
+ case AVRC_PDU_GET_ITEM_ATTRIBUTES: /* 0x73 */
+ status = avrc_bld_get_item_attrs_rsp(&p_rsp->get_attrs, p_pkt);
+ break;
+
+ case AVRC_PDU_SEARCH: /* 0x80 */
+ status = avrc_bld_search_rsp(&p_rsp->search, p_pkt);
+ break;
+#endif
+#endif
+ }
+
+ if (alloc && (status != AVRC_STS_NO_ERROR) )
+ {
+ GKI_freebuf(p_pkt);
+ *pp_pkt = NULL;
+ }
+ AVRC_TRACE_API1("AVRC_BldResponse: returning %d", status);
+ return status;
+}
+
+#endif /* (AVRC_METADATA_INCLUDED == TRUE)*/
+
diff --git a/stack/avrc/avrc_int.h b/stack/avrc/avrc_int.h
new file mode 100644
index 0000000..33e561c
--- /dev/null
+++ b/stack/avrc/avrc_int.h
@@ -0,0 +1,146 @@
+/*****************************************************************************
+**
+** Name: avrc_int.h
+**
+** Description:AVRCP internal header file.
+**
+** Copyright (c) 2003-2006, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+
+#ifndef AVRC_INT_H
+#define AVRC_INT_H
+
+#include "avct_defs.h"
+#include "avrc_api.h"
+
+/* DEBUG FLAGS
+ *
+ * #define META_DEBUG_ENABLED
+ */
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+/* Number of attributes in AVRC SDP record. */
+#define AVRC_NUM_ATTR 6
+
+/* Number of protocol elements in protocol element list. */
+#define AVRC_NUM_PROTO_ELEMS 2
+
+#ifndef AVRC_MIN_CMD_LEN
+#define AVRC_MIN_CMD_LEN 20
+#endif
+
+#define AVRC_UNIT_OPRND_BYTES 5
+#define AVRC_SUB_OPRND_BYTES 4
+#define AVRC_SUBRSP_OPRND_BYTES 3
+#define AVRC_SUB_PAGE_MASK 7
+#define AVRC_SUB_PAGE_SHIFT 4
+#define AVRC_SUB_EXT_CODE 7
+#define AVRC_PASS_OP_ID_MASK 0x7F
+#define AVRC_PASS_STATE_MASK 0x80
+#define AVRC_CMD_OPRND_PAD 0xFF
+
+#define AVRC_CTYPE_MASK 0x0F
+#define AVRC_SUBTYPE_MASK 0xF8
+#define AVRC_SUBTYPE_SHIFT 3
+#define AVRC_SUBID_MASK 0x07
+#define AVRC_SUBID_IGNORE 0x07
+
+#define AVRC_SINGLE_PARAM_SIZE 1
+#define AVRC_METADATA_PKT_TYPE_MASK 0x03
+#define AVRC_PASS_THOUGH_MSG_MASK 0x80 /* MSB of msg_type indicates the PAS THROUGH msg */
+#define AVRC_VENDOR_UNIQUE_MASK 0x70 /* vendor unique id */
+
+
+/* Company ID is 24-bit integer We can not use the macros in bt_types.h */
+#define AVRC_CO_ID_TO_BE_STREAM(p, u32) {*(p)++ = (UINT8)((u32) >> 16); *(p)++ = (UINT8)((u32) >> 8); *(p)++ = (UINT8)(u32); }
+#define AVRC_BE_STREAM_TO_CO_ID(u32, p) {u32 = (((UINT32)(*((p) + 2))) + (((UINT32)(*((p) + 1))) << 8) + (((UINT32)(*(p))) << 16)); (p) += 3;}
+
+#define AVRC_AVC_HDR_SIZE 3 /* ctype, subunit*, opcode */
+
+#define AVRC_MIN_META_HDR_SIZE 4 /* pdu id(1), packet type(1), param len(2) */
+#define AVRC_MIN_BROWSE_HDR_SIZE 3 /* pdu id(1), param len(2) */
+
+#define AVRC_VENDOR_HDR_SIZE 6 /* ctype, subunit*, opcode, CO_ID */
+#define AVRC_MSG_VENDOR_OFFSET 23
+#define AVRC_MIN_VENDOR_SIZE (AVRC_MSG_VENDOR_OFFSET + BT_HDR_SIZE + AVRC_MIN_META_HDR_SIZE)
+
+#define AVRC_PASS_THRU_SIZE 8
+#define AVRC_MSG_PASS_THRU_OFFSET 25
+#define AVRC_MIN_PASS_THRU_SIZE (AVRC_MSG_PASS_THRU_OFFSET + BT_HDR_SIZE + 4)
+
+#define AVRC_MIN_BROWSE_SIZE (AVCT_BROWSE_OFFSET + BT_HDR_SIZE + AVRC_MIN_BROWSE_HDR_SIZE)
+
+#define AVRC_CTRL_PKT_LEN(pf, pk) {pf = (UINT8 *)((pk) + 1) + (pk)->offset + 2;}
+
+#define AVRC_MAX_CTRL_DATA_LEN (AVRC_PACKET_LEN)
+
+/*****************************************************************************
+** Type definitions
+*****************************************************************************/
+
+#if (AVRC_METADATA_INCLUDED == TRUE)
+/* type for Metadata fragmentation control block */
+typedef struct
+{
+ BT_HDR *p_fmsg; /* the fragmented message */
+ UINT8 frag_pdu; /* the PDU ID for fragmentation */
+ BOOLEAN frag_enabled; /* fragmentation flag */
+} tAVRC_FRAG_CB;
+
+/* type for Metadata re-assembly control block */
+typedef struct
+{
+ BT_HDR *p_rmsg; /* the received message */
+ UINT16 rasm_offset; /* re-assembly flag, the offset of the start fragment */
+ UINT8 rasm_pdu; /* the PDU ID for re-assembly */
+} tAVRC_RASM_CB;
+#endif
+
+typedef struct
+{
+ tAVRC_CONN_CB ccb[AVCT_NUM_CONN];
+#if (AVRC_METADATA_INCLUDED == TRUE)
+ tAVRC_FRAG_CB fcb[AVCT_NUM_CONN];
+ tAVRC_RASM_CB rcb[AVCT_NUM_CONN];
+#endif
+ tAVRC_FIND_CBACK *p_cback; /* pointer to application callback */
+ tSDP_DISCOVERY_DB *p_db; /* pointer to discovery database */
+ UINT16 service_uuid; /* service UUID to search */
+ UINT8 trace_level;
+} tAVRC_CB;
+
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/******************************************************************************
+** Main Control Block
+*******************************************************************************/
+#if AVRC_DYNAMIC_MEMORY == FALSE
+AVRC_API extern tAVRC_CB avrc_cb;
+#else
+AVRC_API extern tAVRC_CB *avrc_cb_ptr;
+#define avrc_cb (*avrc_cb_ptr)
+#endif
+
+extern BOOLEAN avrc_is_valid_pdu_id(UINT8 pdu_id);
+extern BOOLEAN avrc_is_valid_player_attrib_value(UINT8 attrib, UINT8 value);
+extern BT_HDR * avrc_alloc_ctrl_pkt (UINT8 pdu);
+extern tAVRC_STS avrc_pars_pass_thru(tAVRC_MSG_PASS *p_msg, UINT16 *p_vendor_unique_id);
+extern UINT8 avrc_opcode_from_pdu(UINT8 pdu);
+extern BOOLEAN avrc_is_valid_opcode(UINT8 opcode);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVRC_INT_H */
+
diff --git a/stack/avrc/avrc_opt.c b/stack/avrc/avrc_opt.c
new file mode 100644
index 0000000..7711655
--- /dev/null
+++ b/stack/avrc/avrc_opt.c
@@ -0,0 +1,222 @@
+/*****************************************************************************
+**
+** Name: avrc_opt.c
+**
+** Description:Interface to AVRCP optional commands
+**
+** Copyright (c) 2003-2006, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include <string.h>
+
+#include "gki.h"
+#include "avrc_api.h"
+#include "avrc_int.h"
+
+#include "wcassert.h"
+
+
+/******************************************************************************
+**
+** Function avrc_vendor_msg
+**
+** Description Compose a VENDOR DEPENDENT command according to p_msg
+**
+** Input Parameters:
+** p_msg: Pointer to VENDOR DEPENDENT message structure.
+**
+** Output Parameters:
+** None.
+**
+** Returns pointer to a valid GKI buffer if successful.
+** NULL if p_msg is NULL.
+**
+******************************************************************************/
+static BT_HDR * avrc_vendor_msg(tAVRC_MSG_VENDOR *p_msg)
+{
+ BT_HDR *p_cmd;
+ UINT8 *p_data;
+
+ WC_ASSERT(p_msg != NULL);
+
+#if AVRC_METADATA_INCLUDED == TRUE
+ WC_ASSERT(AVRC_META_CMD_POOL_SIZE > (AVRC_MIN_CMD_LEN+p_msg->vendor_len));
+ if ((p_cmd = (BT_HDR *) GKI_getpoolbuf(AVRC_META_CMD_POOL_ID)) != NULL)
+#else
+ WC_ASSERT(AVRC_CMD_POOL_SIZE > (AVRC_MIN_CMD_LEN+p_msg->vendor_len));
+ if ((p_cmd = (BT_HDR *) GKI_getpoolbuf(AVRC_CMD_POOL_ID)) != NULL)
+#endif
+ {
+ p_cmd->offset = AVCT_MSG_OFFSET;
+ p_data = (UINT8 *)(p_cmd + 1) + p_cmd->offset;
+ *p_data++ = (p_msg->hdr.ctype & AVRC_CTYPE_MASK);
+ *p_data++ = (p_msg->hdr.subunit_type << AVRC_SUBTYPE_SHIFT) | p_msg->hdr.subunit_id;
+ *p_data++ = AVRC_OP_VENDOR;
+ AVRC_CO_ID_TO_BE_STREAM(p_data, p_msg->company_id);
+ if(p_msg->vendor_len && p_msg->p_vendor_data)
+ {
+ memcpy(p_data, p_msg->p_vendor_data, p_msg->vendor_len);
+ }
+ p_cmd->len = (UINT16) (p_data + p_msg->vendor_len - (UINT8 *)(p_cmd + 1) - p_cmd->offset);
+ p_cmd->layer_specific = AVCT_DATA_CTRL;
+ }
+ return p_cmd;
+}
+
+/******************************************************************************
+**
+** Function AVRC_UnitCmd
+**
+** Description Send a UNIT INFO command to the peer device. This
+** function can only be called for controller role connections.
+** Any response message from the peer is passed back through
+** the tAVRC_MSG_CBACK callback function.
+**
+** Input Parameters:
+** handle: Handle of this connection.
+**
+** label: Transaction label.
+**
+** Output Parameters:
+** None.
+**
+** Returns AVRC_SUCCESS if successful.
+** AVRC_BAD_HANDLE if handle is invalid.
+**
+******************************************************************************/
+UINT16 AVRC_UnitCmd(UINT8 handle, UINT8 label)
+{
+ BT_HDR *p_cmd;
+ UINT8 *p_data;
+
+ if ((p_cmd = (BT_HDR *) GKI_getpoolbuf(AVRC_CMD_POOL_ID)) != NULL)
+ {
+ p_cmd->offset = AVCT_MSG_OFFSET;
+ p_data = (UINT8 *)(p_cmd + 1) + p_cmd->offset;
+ *p_data++ = AVRC_CMD_STATUS;
+ /* unit & id ignore */
+ *p_data++ = (AVRC_SUB_UNIT << AVRC_SUBTYPE_SHIFT) | AVRC_SUBID_IGNORE;
+ *p_data++ = AVRC_OP_UNIT_INFO;
+ memset(p_data, AVRC_CMD_OPRND_PAD, AVRC_UNIT_OPRND_BYTES);
+ p_cmd->len = p_data + AVRC_UNIT_OPRND_BYTES - (UINT8 *)(p_cmd + 1) - p_cmd->offset;
+ p_cmd->layer_specific = AVCT_DATA_CTRL;
+ }
+ return AVCT_MsgReq( handle, label, AVCT_CMD, p_cmd);
+}
+
+/******************************************************************************
+**
+** Function AVRC_SubCmd
+**
+** Description Send a SUBUNIT INFO command to the peer device. This
+** function can only be called for controller role connections.
+** Any response message from the peer is passed back through
+** the tAVRC_MSG_CBACK callback function.
+**
+** Input Parameters:
+** handle: Handle of this connection.
+**
+** label: Transaction label.
+**
+** page: Specifies which part of the subunit type table
+** is requested. For AVRCP it is typically zero.
+** Value range is 0-7.
+**
+** Output Parameters:
+** None.
+**
+** Returns AVRC_SUCCESS if successful.
+** AVRC_BAD_HANDLE if handle is invalid.
+**
+******************************************************************************/
+UINT16 AVRC_SubCmd(UINT8 handle, UINT8 label, UINT8 page)
+{
+ BT_HDR *p_cmd;
+ UINT8 *p_data;
+
+ if ((p_cmd = (BT_HDR *) GKI_getpoolbuf(AVRC_CMD_POOL_ID)) != NULL)
+ {
+ p_cmd->offset = AVCT_MSG_OFFSET;
+ p_data = (UINT8 *)(p_cmd + 1) + p_cmd->offset;
+ *p_data++ = AVRC_CMD_STATUS;
+ /* unit & id ignore */
+ *p_data++ = (AVRC_SUB_UNIT << AVRC_SUBTYPE_SHIFT) | AVRC_SUBID_IGNORE;
+ *p_data++ = AVRC_OP_SUB_INFO;
+ *p_data++ = ((page&AVRC_SUB_PAGE_MASK) << AVRC_SUB_PAGE_SHIFT) | AVRC_SUB_EXT_CODE;
+ memset(p_data, AVRC_CMD_OPRND_PAD, AVRC_SUB_OPRND_BYTES);
+ p_cmd->len = p_data + AVRC_SUB_OPRND_BYTES - (UINT8 *)(p_cmd + 1) - p_cmd->offset;
+ p_cmd->layer_specific = AVCT_DATA_CTRL;
+ }
+ return AVCT_MsgReq( handle, label, AVCT_CMD, p_cmd);
+}
+
+/******************************************************************************
+**
+** Function AVRC_VendorCmd
+**
+** Description Send a VENDOR DEPENDENT command to the peer device. This
+** function can only be called for controller role connections.
+** Any response message from the peer is passed back through
+** the tAVRC_MSG_CBACK callback function.
+**
+** Input Parameters:
+** handle: Handle of this connection.
+**
+** label: Transaction label.
+**
+** p_msg: Pointer to VENDOR DEPENDENT message structure.
+**
+** Output Parameters:
+** None.
+**
+** Returns AVRC_SUCCESS if successful.
+** AVRC_BAD_HANDLE if handle is invalid.
+**
+******************************************************************************/
+UINT16 AVRC_VendorCmd(UINT8 handle, UINT8 label, tAVRC_MSG_VENDOR *p_msg)
+{
+ BT_HDR *p_buf = avrc_vendor_msg(p_msg);
+ if (p_buf)
+ return AVCT_MsgReq( handle, label, AVCT_CMD, p_buf);
+ else
+ return AVCT_NO_RESOURCES;
+}
+
+
+/******************************************************************************
+**
+** Function AVRC_VendorRsp
+**
+** Description Send a VENDOR DEPENDENT response to the peer device. This
+** function can only be called for target role connections.
+** This function must be called when a VENDOR DEPENDENT
+** command message is received from the peer through the
+** tAVRC_MSG_CBACK callback function.
+**
+** Input Parameters:
+** handle: Handle of this connection.
+**
+** label: Transaction label. Must be the same value as
+** passed with the command message in the callback function.
+**
+** p_msg: Pointer to VENDOR DEPENDENT message structure.
+**
+** Output Parameters:
+** None.
+**
+** Returns AVRC_SUCCESS if successful.
+** AVRC_BAD_HANDLE if handle is invalid.
+**
+******************************************************************************/
+UINT16 AVRC_VendorRsp(UINT8 handle, UINT8 label, tAVRC_MSG_VENDOR *p_msg)
+{
+ BT_HDR *p_buf = avrc_vendor_msg(p_msg);
+ if (p_buf)
+ return AVCT_MsgReq( handle, label, AVCT_RSP, p_buf);
+ else
+ return AVCT_NO_RESOURCES;
+}
+
+
+
diff --git a/stack/avrc/avrc_pars_ct.c b/stack/avrc/avrc_pars_ct.c
new file mode 100644
index 0000000..4feb256
--- /dev/null
+++ b/stack/avrc/avrc_pars_ct.c
@@ -0,0 +1,663 @@
+/*****************************************************************************
+**
+** Name: avrc_pars_ct.c
+**
+** Description:Interface to AVRCP parse message functions for the Control Role
+**
+** Copyright (c) 2008-2008, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include <string.h>
+
+#include "gki.h"
+#include "avrc_api.h"
+#include "avrc_defs.h"
+#include "avrc_int.h"
+
+/*****************************************************************************
+** Global data
+*****************************************************************************/
+
+#if (AVRC_METADATA_INCLUDED == TRUE)
+
+/*******************************************************************************
+**
+** Function avrc_pars_vendor_rsp
+**
+** Description This function parses the vendor specific commands defined by
+** Bluetooth SIG
+**
+** Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully.
+** Otherwise, the error code defined by AVRCP 1.4
+**
+*******************************************************************************/
+static tAVRC_STS avrc_pars_vendor_rsp(tAVRC_MSG_VENDOR *p_msg, tAVRC_RESPONSE *p_result, UINT8 *p_buf, UINT16 buf_len)
+{
+ tAVRC_STS status = AVRC_STS_NO_ERROR;
+ UINT8 *p = p_msg->p_vendor_data;
+ UINT16 len;
+ UINT8 xx, yy;
+ tAVRC_NOTIF_RSP_PARAM *p_param;
+ tAVRC_APP_SETTING *p_app_set;
+ tAVRC_APP_SETTING_TEXT *p_app_txt;
+ tAVRC_ATTR_ENTRY *p_entry;
+ UINT32 *p_u32;
+ UINT8 *p_u8;
+ UINT16 size_needed;
+
+ BE_STREAM_TO_UINT8 (p_result->pdu, p);
+ p++; /* skip the reserved/packe_type byte */
+ BE_STREAM_TO_UINT16 (len, p);
+ AVRC_TRACE_DEBUG4("avrc_pars_vendor_rsp() ctype:0x%x pdu:0x%x, len:%d/0x%x", p_msg->hdr.ctype, p_result->pdu, len, len);
+ if (p_msg->hdr.ctype == AVRC_RSP_REJ)
+ {
+ p_result->rsp.status = *p;
+ return p_result->rsp.status;
+ }
+
+ switch (p_result->pdu)
+ {
+ case AVRC_PDU_GET_CAPABILITIES: /* 0x10 */
+ p_result->get_caps.capability_id = *p++;
+ if (AVRC_IS_VALID_CAP_ID(p_result->get_caps.capability_id))
+ {
+ p_result->get_caps.count = *p++;
+ if (p_result->get_caps.capability_id == AVRC_CAP_COMPANY_ID)
+ {
+ p_u32 = p_result->get_caps.param.company_id;
+ for (xx=0; xx<p_result->get_caps.count; xx++)
+ {
+ AVRC_BE_STREAM_TO_CO_ID (p_u32[xx], p);
+ }
+ }
+ else
+ {
+ p_u8 = p_result->get_caps.param.event_id;
+ for (xx=0; xx<p_result->get_caps.count; xx++)
+ {
+ BE_STREAM_TO_UINT8 (p_u8[xx], p);
+ }
+ }
+ }
+ else
+ status = AVRC_STS_BAD_PARAM;
+ break;
+
+ case AVRC_PDU_LIST_PLAYER_APP_ATTR: /* 0x11 */
+ BE_STREAM_TO_UINT8 (p_result->list_app_attr.num_attr, p);
+ p_u8 = p_result->list_app_attr.attrs;
+ for(xx=0, yy=0; xx< p_result->list_app_attr.num_attr; xx++)
+ {
+ /* only report the valid player app attributes */
+ if (AVRC_IsValidPlayerAttr(*p))
+ p_u8[yy++] = *p;
+ p++;
+ }
+ p_result->list_app_attr.num_attr = yy;
+ break;
+
+ case AVRC_PDU_LIST_PLAYER_APP_VALUES: /* 0x12 */
+ BE_STREAM_TO_UINT8 (p_result->list_app_values.num_val, p);
+ p_u8 = p_result->list_app_values.vals;
+ for(xx=0; xx< p_result->list_app_values.num_val; xx++)
+ {
+ p_u8[xx] = *p++;
+ }
+ break;
+
+ case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE: /* 0x13 */
+ BE_STREAM_TO_UINT8 (p_result->get_cur_app_val.num_val, p);
+ size_needed = sizeof(tAVRC_APP_SETTING);
+ if (p_buf)
+ {
+ p_result->get_cur_app_val.p_vals = (tAVRC_APP_SETTING *)p_buf;
+ p_app_set = p_result->get_cur_app_val.p_vals;
+ for(xx=0; ((xx< p_result->get_cur_app_val.num_val) && (buf_len > size_needed)); xx++)
+ {
+ buf_len -= size_needed;
+ BE_STREAM_TO_UINT8 (p_app_set[xx].attr_id, p);
+ BE_STREAM_TO_UINT8 (p_app_set[xx].attr_val, p);
+ }
+ if (xx != p_result->get_cur_app_val.num_val)
+ {
+ AVRC_TRACE_ERROR2("GET_CUR_PLAYER_APP_VALUE not enough room:%d orig num_val:%d",
+ xx, p_result->get_cur_app_val.num_val);
+ p_result->get_cur_app_val.num_val = xx;
+ }
+ }
+ else
+ {
+ AVRC_TRACE_ERROR2("GET_CUR_PLAYER_APP_VALUE not enough room:len: %d needed for struct: %d", buf_len, size_needed);
+ status = AVRC_STS_INTERNAL_ERR;
+ }
+ break;
+
+ case AVRC_PDU_SET_PLAYER_APP_VALUE: /* 0x14 */
+ case AVRC_PDU_INFORM_DISPLAY_CHARSET: /* 0x17 */
+ case AVRC_PDU_INFORM_BATTERY_STAT_OF_CT:/* 0x18 */
+ /* no additional parameters */
+ if (len != 0)
+ status = AVRC_STS_INTERNAL_ERR;
+ break;
+
+ case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT: /* 0x15 */
+ case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT:/* 0x16 */
+ BE_STREAM_TO_UINT8 (p_result->get_app_attr_txt.num_attr, p);
+ size_needed = sizeof(tAVRC_APP_SETTING_TEXT) * p_result->get_app_attr_txt.num_attr;
+ if (p_buf && (buf_len > size_needed))
+ {
+ p_result->get_app_attr_txt.p_attrs = (tAVRC_APP_SETTING_TEXT *)p_buf;
+ p_app_txt = p_result->get_app_attr_txt.p_attrs;
+ p_u8 = p_buf + size_needed;
+ buf_len -= size_needed;
+ for(xx=0; xx< p_result->get_app_attr_txt.num_attr; xx++)
+ {
+ BE_STREAM_TO_UINT8 (p_app_txt[xx].attr_id, p);
+ BE_STREAM_TO_UINT16 (p_app_txt[xx].charset_id, p);
+ BE_STREAM_TO_UINT8 (p_app_txt[xx].str_len, p);
+ p_app_txt[xx].p_str = p_u8;
+ if (buf_len > p_app_txt[xx].str_len)
+ {
+ BE_STREAM_TO_ARRAY(p, p_u8, p_app_txt[xx].str_len);
+ p_u8 += p_app_txt[xx].str_len;
+ buf_len -= p_app_txt[xx].str_len;
+ }
+ else
+ {
+ AVRC_TRACE_ERROR4("GET_CUR_PLAYER_APP_VALUE not enough room:[%d] len orig/left: %d/%d, orig num_attr:%d",
+ xx, p_app_txt[xx].str_len, buf_len, p_result->get_app_attr_txt.num_attr);
+ p_app_txt[xx].str_len = (UINT8)buf_len;
+ BE_STREAM_TO_ARRAY(p, p_u8, p_app_txt[xx].str_len);
+ p_result->get_app_attr_txt.num_attr = xx+1;
+ status = AVRC_STS_INTERNAL_ERR;
+ break;
+ }
+ }
+ }
+ else
+ {
+ AVRC_TRACE_ERROR2("GET_CUR_PLAYER_APP_VALUE not enough room:len: %d needed for struct: %d", buf_len, size_needed);
+ status = AVRC_STS_INTERNAL_ERR;
+ }
+ break;
+
+ case AVRC_PDU_GET_ELEMENT_ATTR: /* 0x20 */
+ BE_STREAM_TO_UINT8 (p_result->get_elem_attrs.num_attr, p);
+ size_needed = sizeof(tAVRC_ATTR_ENTRY) * p_result->get_elem_attrs.num_attr;
+ if (p_buf && (buf_len > size_needed))
+ {
+ p_result->get_elem_attrs.p_attrs = (tAVRC_ATTR_ENTRY *)p_buf;
+ p_entry = p_result->get_elem_attrs.p_attrs;
+ p_u8 = p_buf + size_needed;
+ buf_len -= size_needed;
+ for(xx=0; xx< p_result->get_elem_attrs.num_attr; xx++)
+ {
+ BE_STREAM_TO_UINT32 (p_entry[xx].attr_id, p);
+ BE_STREAM_TO_UINT16 (p_entry[xx].name.charset_id, p);
+ BE_STREAM_TO_UINT16 (p_entry[xx].name.str_len, p);
+ p_entry[xx].name.p_str = p_u8;
+ if (buf_len > p_entry[xx].name.str_len)
+ {
+ BE_STREAM_TO_ARRAY(p, p_u8, p_entry[xx].name.str_len);
+ p_u8 += p_entry[xx].name.str_len;
+ buf_len -= p_entry[xx].name.str_len;
+ }
+ else
+ {
+ AVRC_TRACE_ERROR4("GET_ELEMENT_ATTR not enough room:[%d] len orig/left: %d/%d, orig num_attr:%d",
+ xx, p_entry[xx].name.str_len, buf_len, p_result->get_elem_attrs.num_attr);
+ p_entry[xx].name.str_len = buf_len;
+ BE_STREAM_TO_ARRAY(p, p_u8, p_entry[xx].name.str_len);
+ p_result->get_elem_attrs.num_attr = xx + 1;
+ status = AVRC_STS_INTERNAL_ERR;
+ break;
+ }
+ }
+ }
+ else
+ {
+ AVRC_TRACE_ERROR2("GET_ELEMENT_ATTR not enough room:len: %d needed for struct: %d", buf_len, size_needed);
+ status = AVRC_STS_INTERNAL_ERR;
+ }
+ break;
+
+ case AVRC_PDU_GET_PLAY_STATUS: /* 0x30 */
+ BE_STREAM_TO_UINT32 (p_result->get_play_status.song_len, p);
+ BE_STREAM_TO_UINT32 (p_result->get_play_status.song_pos, p);
+ BE_STREAM_TO_UINT8 (p_result->get_play_status.play_status, p);
+ if (len != 9)
+ status = AVRC_STS_INTERNAL_ERR;
+ break;
+
+ case AVRC_PDU_REGISTER_NOTIFICATION: /* 0x31 */
+ BE_STREAM_TO_UINT8 (p_result->reg_notif.event_id, p);
+ p_param = &p_result->reg_notif.param;
+ switch (p_result->reg_notif.event_id)
+ {
+ case AVRC_EVT_PLAY_STATUS_CHANGE: /* 0x01 */
+ BE_STREAM_TO_UINT8 (p_param->play_status, p);
+ if ((p_param->play_status > AVRC_PLAYSTATE_REV_SEEK) &&
+ (p_param->play_status != AVRC_PLAYSTATE_ERROR) )
+ {
+ status = AVRC_STS_BAD_PARAM;
+ }
+ break;
+
+ case AVRC_EVT_TRACK_CHANGE: /* 0x02 */
+ BE_STREAM_TO_ARRAY (p, p_param->track, AVRC_UID_SIZE);
+ break;
+
+ case AVRC_EVT_TRACK_REACHED_END: /* 0x03 */
+ case AVRC_EVT_TRACK_REACHED_START: /* 0x04 */
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
+ case AVRC_EVT_NOW_PLAYING_CHANGE: /* 0x09 */
+ case AVRC_EVT_AVAL_PLAYERS_CHANGE: /* 0x0a */
+#endif /* (AVRC_ADV_CTRL_INCLUDED == TRUE) */
+ /* these events do not have additional parameters */
+ break;
+
+ case AVRC_EVT_PLAY_POS_CHANGED: /* 0x05 */
+ BE_STREAM_TO_UINT32 (p_param->play_pos, p);
+ break;
+
+ case AVRC_EVT_BATTERY_STATUS_CHANGE:/* 0x06 */
+ BE_STREAM_TO_UINT8 (p_param->battery_status, p);
+ if (!AVRC_IS_VALID_BATTERY_STATUS(p_param->battery_status))
+ {
+ status = AVRC_STS_BAD_PARAM;
+ }
+ break;
+
+ case AVRC_EVT_SYSTEM_STATUS_CHANGE: /* 0x07 */
+ BE_STREAM_TO_UINT8 (p_param->system_status, p);
+ if (!AVRC_IS_VALID_SYSTEM_STATUS(p_param->system_status))
+ {
+ status = AVRC_STS_BAD_PARAM;
+ }
+ break;
+
+ case AVRC_EVT_APP_SETTING_CHANGE: /* 0x08 */
+ BE_STREAM_TO_UINT8 (p_param->player_setting.num_attr, p);
+ if (p_param->player_setting.num_attr > AVRC_MAX_APP_SETTINGS)
+ p_param->player_setting.num_attr = AVRC_MAX_APP_SETTINGS;
+ for (xx=0; xx<p_param->player_setting.num_attr; xx++)
+ {
+ BE_STREAM_TO_UINT8 (p_param->player_setting.attr_id[xx], p);
+ BE_STREAM_TO_UINT8 (p_param->player_setting.attr_value[xx], p);
+ if (!avrc_is_valid_player_attrib_value(p_param->player_setting.attr_id[xx], p_param->player_setting.attr_value[xx]))
+ {
+ status = AVRC_STS_BAD_PARAM;
+ break;
+ }
+ }
+ break;
+
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
+ case AVRC_EVT_ADDR_PLAYER_CHANGE: /* 0x0b */
+ BE_STREAM_TO_UINT16 (p_param->addr_player.player_id, p);
+ BE_STREAM_TO_UINT16 (p_param->addr_player.uid_counter, p);
+ break;
+
+ case AVRC_EVT_UIDS_CHANGE: /* 0x0c */
+ BE_STREAM_TO_UINT16 (p_param->uid_counter, p);
+ break;
+
+ case AVRC_EVT_VOLUME_CHANGE: /* 0x0d */
+ BE_STREAM_TO_UINT8 (p_param->volume, p);
+ break;
+#endif /* (AVRC_ADV_CTRL_INCLUDED == TRUE) */
+
+ default:
+ status = AVRC_STS_BAD_PARAM;
+ break;
+ }
+ break;
+
+ /* case AVRC_PDU_REQUEST_CONTINUATION_RSP: 0x40 */
+ /* case AVRC_PDU_ABORT_CONTINUATION_RSP: 0x41 */
+
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
+ case AVRC_PDU_SET_ABSOLUTE_VOLUME: /* 0x50 */
+ case AVRC_PDU_SET_ADDRESSED_PLAYER: /* 0x60 */
+ case AVRC_PDU_PLAY_ITEM: /* 0x74 */
+ case AVRC_PDU_ADD_TO_NOW_PLAYING: /* 0x90 */
+ BE_STREAM_TO_UINT8 (p_result->volume.volume, p);
+ if (len != 1)
+ status = AVRC_STS_INTERNAL_ERR;
+ break;
+#endif /* (AVRC_ADV_CTRL_INCLUDED == TRUE) */
+
+ default:
+ status = AVRC_STS_BAD_CMD;
+ break;
+ }
+
+ return status;
+}
+
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function avrc_pars_browsing_rsp
+**
+** Description This function parses the commands that go through the
+** browsing channel
+**
+** Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully.
+** Otherwise, the error code defined by AVRCP 1.4
+**
+*******************************************************************************/
+static tAVRC_STS avrc_pars_browsing_rsp(tAVRC_MSG_BROWSE *p_msg, tAVRC_RESPONSE *p_result, UINT8 *p_buf, UINT16 buf_len)
+{
+ tAVRC_STS status = AVRC_STS_NO_ERROR;
+ UINT8 *p = p_msg->p_browse_data;
+ UINT16 len;
+ int i, count;
+ UINT8 *p_left = p_buf;
+ tAVRC_ITEM *p_item;
+ tAVRC_ITEM_PLAYER *p_player;
+ tAVRC_ITEM_FOLDER *p_folder;
+ tAVRC_ITEM_MEDIA *p_media;
+ tAVRC_ATTR_ENTRY *p_attrs;
+ UINT16 item_len;
+ UINT8 xx;
+ UINT16 size_needed;
+
+ p_result->pdu = *p++;
+ BE_STREAM_TO_UINT16 (len, p);
+ BE_STREAM_TO_UINT8 (status, p);
+ AVRC_TRACE_DEBUG4("avrc_pars_browsing_rsp() pdu:0x%x, len:%d/0x%x, status:0x%x", p_result->pdu, len, len, status);
+ if (status != AVRC_STS_NO_ERROR)
+ return status;
+
+ switch (p_result->pdu)
+ {
+ case AVRC_PDU_SET_BROWSED_PLAYER: /* 0x70 */
+ BE_STREAM_TO_UINT16 (p_result->br_player.uid_counter, p);
+ BE_STREAM_TO_UINT32 (p_result->br_player.num_items, p);
+ BE_STREAM_TO_UINT16 (p_result->br_player.charset_id, p);
+ BE_STREAM_TO_UINT8 (p_result->br_player.folder_depth, p);
+ p_result->br_player.p_folders = NULL;
+ if (p_result->br_player.folder_depth == 0)
+ return status;
+
+ size_needed = sizeof(tAVRC_NAME) * p_result->br_player.folder_depth;
+ if (p_buf && (buf_len > size_needed))
+ {
+ p_result->br_player.p_folders = (tAVRC_NAME *)p_buf;
+ p_left = p_buf + size_needed;
+ count = p_result->br_player.folder_depth;
+ buf_len -= size_needed;
+ for (i=0; i<count; i++)
+ {
+ p_result->br_player.p_folders[i].p_str = p_left;
+ BE_STREAM_TO_UINT16 (p_result->br_player.p_folders[i].str_len, p);
+ if (buf_len > p_result->br_player.p_folders[i].str_len)
+ {
+ BE_STREAM_TO_ARRAY (p, p_result->br_player.p_folders[i].p_str, p_result->br_player.p_folders[i].str_len);
+ p_left += p_result->br_player.p_folders[i].str_len;
+ buf_len -= p_result->br_player.p_folders[i].str_len;
+ }
+ else
+ {
+ AVRC_TRACE_ERROR4("SET_BROWSED_PLAYER not enough room:[%d] len orig/left: %d/%d, orig depth:%d",
+ i, p_result->br_player.p_folders[i].str_len, buf_len, p_result->br_player.folder_depth);
+ p_result->br_player.p_folders[i].str_len = buf_len;
+ BE_STREAM_TO_ARRAY (p, p_result->br_player.p_folders[i].p_str, p_result->br_player.p_folders[i].str_len);
+ p_result->br_player.folder_depth = i+1;
+ status = AVRC_STS_INTERNAL_ERR;
+ break;
+ }
+ }
+ }
+ else
+ {
+ AVRC_TRACE_ERROR2("SET_BROWSED_PLAYER not enough room:len: %d needed for struct: %d", buf_len, size_needed);
+ status = AVRC_STS_INTERNAL_ERR;
+ }
+ break;
+
+ case AVRC_PDU_GET_FOLDER_ITEMS: /* 0x71 */
+ BE_STREAM_TO_UINT16 (p_result->get_items.uid_counter, p);
+ BE_STREAM_TO_UINT16 (p_result->get_items.item_count, p);
+ p_result->get_items.p_item_list = NULL;
+ if (p_result->get_items.item_count == 0)
+ return status;
+ size_needed = sizeof(tAVRC_ITEM) * p_result->get_items.item_count;
+ if (p_buf && (buf_len > size_needed))
+ {
+ p_result->get_items.p_item_list = p_item = (tAVRC_ITEM *)p_buf;
+ p_left = p_buf + size_needed;
+ count = p_result->get_items.item_count;
+ buf_len -= size_needed;
+ for (i=0; i<count; i++)
+ {
+ BE_STREAM_TO_UINT8 (p_item[i].item_type, p);
+ BE_STREAM_TO_UINT16 (item_len, p);
+ AVRC_TRACE_DEBUG3("[%d] type:%d len left:%d", i, p_item[i].item_type, buf_len);
+ switch(p_item[i].item_type)
+ {
+ case AVRC_ITEM_PLAYER:
+ p_player = &p_item[i].u.player;
+ BE_STREAM_TO_UINT16 (p_player->player_id, p);
+ BE_STREAM_TO_UINT8 (p_player->major_type, p);
+ BE_STREAM_TO_UINT32 (p_player->sub_type, p);
+ BE_STREAM_TO_UINT8 (p_player->play_status, p);
+ BE_STREAM_TO_ARRAY (p, p_player->features, AVRC_FEATURE_MASK_SIZE);
+ BE_STREAM_TO_UINT16 (p_player->name.charset_id, p);
+ BE_STREAM_TO_UINT16 (p_player->name.str_len, p);
+ p_player->name.p_str = p_left;
+ if (buf_len > p_player->name.str_len)
+ {
+ p_left += p_player->name.str_len;
+ BE_STREAM_TO_ARRAY (p, p_player->name.p_str, p_player->name.str_len);
+ buf_len -= p_player->name.str_len;
+ }
+ else
+ {
+ AVRC_TRACE_ERROR4("GET_FOLDER_ITEMS player not enough room:[%d] len orig/left: %d/%d, orig item count:%d",
+ i, p_player->name.str_len, buf_len, p_result->get_items.item_count);
+ p_player->name.str_len = buf_len;
+ BE_STREAM_TO_ARRAY (p, p_player->name.p_str, p_player->name.str_len);
+ p_result->get_items.item_count = i+1;
+ return AVRC_STS_INTERNAL_ERR;
+ }
+ break;
+
+ case AVRC_ITEM_FOLDER:
+ p_folder = &p_item[i].u.folder;
+ BE_STREAM_TO_ARRAY (p, p_folder->uid, AVRC_UID_SIZE);
+ BE_STREAM_TO_UINT8 (p_folder->type, p);
+ BE_STREAM_TO_UINT8 (p_folder->playable, p);
+ BE_STREAM_TO_UINT16 (p_folder->name.charset_id, p);
+ BE_STREAM_TO_UINT16 (p_folder->name.str_len, p);
+ p_folder->name.p_str = p_left;
+ if (buf_len > p_folder->name.str_len)
+ {
+ p_left += p_folder->name.str_len;
+ BE_STREAM_TO_ARRAY (p, p_folder->name.p_str, p_folder->name.str_len);
+ buf_len -= p_folder->name.str_len;
+ }
+ else
+ {
+ AVRC_TRACE_ERROR4("GET_FOLDER_ITEMS folder not enough room:[%d] len orig/left: %d/%d, orig item count:%d",
+ i, p_folder->name.str_len, buf_len, p_result->get_items.item_count);
+ p_folder->name.str_len = buf_len;
+ BE_STREAM_TO_ARRAY (p, p_folder->name.p_str, p_folder->name.str_len);
+ p_result->get_items.item_count = i+1;
+ return AVRC_STS_INTERNAL_ERR;
+ }
+ break;
+
+ case AVRC_ITEM_MEDIA:
+ p_media = &p_item[i].u.media;
+ BE_STREAM_TO_ARRAY (p, p_media->uid, AVRC_UID_SIZE);
+ BE_STREAM_TO_UINT8 (p_media->type, p);
+ BE_STREAM_TO_UINT16 (p_media->name.charset_id, p);
+ BE_STREAM_TO_UINT16 (p_media->name.str_len, p);
+ p_media->name.p_str = p_left;
+ if (buf_len < p_media->name.str_len)
+ {
+ AVRC_TRACE_ERROR4("GET_FOLDER_ITEMS media not enough room:[%d] len orig/left: %d/%d, orig item count:%d",
+ i, p_media->name.str_len, buf_len, p_result->get_items.item_count);
+ p_media->name.str_len = buf_len;
+ BE_STREAM_TO_ARRAY (p, p_media->name.p_str, p_media->name.str_len);
+ p_media->attr_count = 0;
+ p_media->p_attr_list = NULL;
+ p_result->get_items.item_count = i+1;
+ return AVRC_STS_INTERNAL_ERR;
+ }
+ p_left += p_media->name.str_len;
+ buf_len -= p_media->name.str_len;
+ BE_STREAM_TO_ARRAY (p, p_media->name.p_str, p_media->name.str_len);
+ BE_STREAM_TO_UINT8 (p_media->attr_count, p);
+ size_needed = sizeof(tAVRC_ATTR_ENTRY) * p_media->attr_count;
+ if (buf_len < size_needed)
+ {
+ AVRC_TRACE_ERROR4("GET_FOLDER_ITEMS media not enough room:[%d] attr_count orig/left: %d/%d, orig item count:%d",
+ i, p_media->attr_count, buf_len, p_result->get_items.item_count);
+ p_media->name.str_len = buf_len;
+ BE_STREAM_TO_ARRAY (p, p_media->name.p_str, p_media->name.str_len);
+ p_media->attr_count = 0;
+ p_media->p_attr_list = NULL;
+ p_result->get_items.item_count = i+1;
+ return AVRC_STS_INTERNAL_ERR;
+ }
+ p_media->p_attr_list = p_attrs = (tAVRC_ATTR_ENTRY *)p_left;
+ p_left += size_needed;
+ buf_len -= size_needed;
+ for (xx= 0; xx<p_media->attr_count; xx++)
+ {
+ BE_STREAM_TO_UINT32 (p_attrs[xx].attr_id, p);
+ BE_STREAM_TO_UINT16 (p_attrs[xx].name.charset_id, p);
+ BE_STREAM_TO_UINT16 (p_attrs[xx].name.str_len, p);
+ p_attrs[xx].name.p_str = p_left;
+ if (buf_len > p_attrs[xx].name.str_len)
+ {
+ p_left += p_attrs[xx].name.str_len;
+ BE_STREAM_TO_ARRAY (p, p_attrs[xx].name.p_str, p_attrs[xx].name.str_len);
+ buf_len -= p_attrs[xx].name.str_len;
+ }
+ else
+ {
+ AVRC_TRACE_ERROR4("GET_FOLDER_ITEMS media not enough room:[%d] attr name len orig/left: %d/%d, orig item count:%d",
+ i, p_attrs[xx].name.str_len, buf_len, p_result->get_items.item_count);
+ p_attrs[xx].name.str_len = buf_len;
+ BE_STREAM_TO_ARRAY (p, p_attrs[xx].name.p_str, p_attrs[xx].name.str_len);
+ p_media->attr_count = xx+1;
+ p_result->get_items.item_count = i+1;
+ return AVRC_STS_INTERNAL_ERR;
+ }
+ }
+ break;
+ }
+ }
+ }
+ break;
+
+ case AVRC_PDU_CHANGE_PATH: /* 0x72 */
+ BE_STREAM_TO_UINT32 (p_result->chg_path.num_items, p);
+ break;
+
+ case AVRC_PDU_GET_ITEM_ATTRIBUTES: /* 0x73 */
+ BE_STREAM_TO_UINT8 (p_result->get_attrs.attr_count, p);
+ p_result->get_attrs.p_attr_list = p_attrs = NULL;
+ if (p_result->get_attrs.attr_count == 0)
+ return status;
+
+ size_needed = sizeof(tAVRC_ATTR_ENTRY) * p_result->get_attrs.attr_count;
+ if (p_buf && (buf_len > size_needed))
+ {
+ p_result->get_attrs.p_attr_list = p_attrs = (tAVRC_ATTR_ENTRY *)p_left;
+ p_left += size_needed;
+ buf_len -= size_needed;
+ for (xx= 0; xx<p_result->get_attrs.attr_count; xx++)
+ {
+ BE_STREAM_TO_UINT32 (p_attrs[xx].attr_id, p);
+ BE_STREAM_TO_UINT16 (p_attrs[xx].name.charset_id, p);
+ BE_STREAM_TO_UINT16 (p_attrs[xx].name.str_len, p);
+ p_attrs[xx].name.p_str = p_left;
+ if (buf_len > p_attrs[xx].name.str_len)
+ {
+ p_left += p_attrs[xx].name.str_len;
+ BE_STREAM_TO_ARRAY (p, p_attrs[xx].name.p_str, p_attrs[xx].name.str_len);
+ buf_len -= p_attrs[xx].name.str_len;
+ }
+ else
+ {
+ AVRC_TRACE_ERROR4("GET_ITEM_ATTRIBUTES not enough room:[%d] len orig/left: %d/%d, orig attr_count:%d",
+ xx, p_attrs[xx].name.str_len, buf_len, p_result->get_attrs.attr_count);
+ p_attrs[xx].name.str_len = buf_len;
+ BE_STREAM_TO_ARRAY (p, p_attrs[xx].name.p_str, p_attrs[xx].name.str_len);
+ p_result->get_attrs.attr_count = xx+1;
+ status = AVRC_STS_INTERNAL_ERR;
+ break;
+ }
+ }
+ }
+ break;
+
+ case AVRC_PDU_SEARCH: /* 0x80 */
+ BE_STREAM_TO_UINT16 (p_result->search.uid_counter, p);
+ BE_STREAM_TO_UINT32 (p_result->search.num_items, p);
+ break;
+
+ default:
+ status = AVRC_STS_BAD_CMD;
+ break;
+ }
+
+ return status;
+}
+#endif /* (AVCT_BROWSE_INCLUDED == TRUE)*/
+
+/*******************************************************************************
+**
+** Function AVRC_ParsResponse
+**
+** Description This function is a superset of AVRC_ParsMetadata to parse the response.
+**
+** Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully.
+** Otherwise, the error code defined by AVRCP 1.4
+**
+*******************************************************************************/
+tAVRC_STS AVRC_ParsResponse (tAVRC_MSG *p_msg, tAVRC_RESPONSE *p_result, UINT8 *p_buf, UINT16 buf_len)
+{
+ tAVRC_STS status = AVRC_STS_INTERNAL_ERR;
+ UINT16 id;
+
+ if (p_msg && p_result)
+ {
+ switch (p_msg->hdr.opcode)
+ {
+ case AVRC_OP_VENDOR: /* 0x00 Vendor-dependent commands */
+ status = avrc_pars_vendor_rsp(&p_msg->vendor, p_result, p_buf, buf_len);
+ break;
+
+ case AVRC_OP_PASS_THRU: /* 0x7C panel subunit opcode */
+ status = avrc_pars_pass_thru(&p_msg->pass, &id);
+ if (status == AVRC_STS_NO_ERROR)
+ {
+ p_result->pdu = (UINT8)id;
+ }
+ break;
+
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+ case AVRC_OP_BROWSE:
+ status = avrc_pars_browsing_rsp(&p_msg->browse, p_result, p_buf, buf_len);
+ break;
+#endif /* (AVCT_BROWSE_INCLUDED == TRUE) */
+
+ default:
+ AVRC_TRACE_ERROR1("AVRC_ParsCommand() unknown opcode:0x%x", p_msg->hdr.opcode);
+ break;
+ }
+ p_result->rsp.opcode = p_msg->hdr.opcode;
+ p_result->rsp.status = status;
+ }
+ return status;
+}
+
+
+#endif /* (AVRC_METADATA_INCLUDED == TRUE) */
diff --git a/stack/avrc/avrc_pars_tg.c b/stack/avrc/avrc_pars_tg.c
new file mode 100644
index 0000000..8237655
--- /dev/null
+++ b/stack/avrc/avrc_pars_tg.c
@@ -0,0 +1,452 @@
+/*****************************************************************************
+**
+** Name: avrc_pars_tg.c
+**
+** Description:Interface to AVRCP parse message functions for the Target Role
+**
+** Copyright (c) 2008-2008, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include <string.h>
+
+#include "gki.h"
+#include "avrc_api.h"
+#include "avrc_defs.h"
+#include "avrc_int.h"
+
+/*****************************************************************************
+** Global data
+*****************************************************************************/
+#if (AVRC_METADATA_INCLUDED == TRUE)
+
+/*******************************************************************************
+**
+** Function avrc_pars_vendor_cmd
+**
+** Description This function parses the vendor specific commands defined by
+** Bluetooth SIG
+**
+** Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully.
+** Otherwise, the error code defined by AVRCP 1.4
+**
+*******************************************************************************/
+static tAVRC_STS avrc_pars_vendor_cmd(tAVRC_MSG_VENDOR *p_msg, tAVRC_COMMAND *p_result, UINT8 *p_buf, UINT16 buf_len)
+{
+ tAVRC_STS status = AVRC_STS_NO_ERROR;
+ UINT8 *p = p_msg->p_vendor_data;
+ UINT16 len;
+ UINT8 xx, yy;
+ UINT8 *p_u8;
+ UINT16 *p_u16;
+ UINT32 u32, u32_2, *p_u32;
+ tAVRC_APP_SETTING *p_app_set;
+ UINT16 size_needed;
+
+ p_result->pdu = *p++;
+ AVRC_TRACE_DEBUG1("avrc_pars_vendor_cmd() pdu:0x%x", p_result->pdu);
+ if (!AVRC_IsValidAvcType (p_result->pdu, p_msg->hdr.ctype))
+ {
+ AVRC_TRACE_DEBUG0("avrc_pars_vendor_cmd() detects wrong AV/C type!");
+ status = AVRC_STS_BAD_CMD;
+ }
+
+ p++; /* skip the reserved byte */
+ BE_STREAM_TO_UINT16 (len, p);
+ if ((len+4) != (p_msg->vendor_len))
+ {
+ status = AVRC_STS_INTERNAL_ERR;
+ }
+
+ if (status != AVRC_STS_NO_ERROR)
+ return status;
+
+ switch (p_result->pdu)
+ {
+ case AVRC_PDU_GET_CAPABILITIES: /* 0x10 */
+ p_result->get_caps.capability_id = *p++;
+ if (!AVRC_IS_VALID_CAP_ID(p_result->get_caps.capability_id))
+ status = AVRC_STS_BAD_PARAM;
+ else if (len != 1)
+ status = AVRC_STS_INTERNAL_ERR;
+ break;
+
+ case AVRC_PDU_LIST_PLAYER_APP_ATTR: /* 0x11 */
+ /* no additional parameters */
+ if (len != 0)
+ status = AVRC_STS_INTERNAL_ERR;
+ break;
+
+ case AVRC_PDU_LIST_PLAYER_APP_VALUES: /* 0x12 */
+ p_result->list_app_values.attr_id = *p++;
+ if (!AVRC_IS_VALID_ATTRIBUTE(p_result->list_app_values.attr_id))
+ status = AVRC_STS_BAD_PARAM;
+ else if (len != 1)
+ status = AVRC_STS_INTERNAL_ERR;
+ break;
+
+ case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE: /* 0x13 */
+ case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT: /* 0x15 */
+ BE_STREAM_TO_UINT8 (p_result->get_cur_app_val.num_attr, p);
+ if (len != (p_result->get_cur_app_val.num_attr+1))
+ {
+ status = AVRC_STS_INTERNAL_ERR;
+ break;
+ }
+ p_u8 = p_result->get_cur_app_val.attrs;
+ for (xx=0, yy=0; xx< p_result->get_cur_app_val.num_attr; xx++)
+ {
+ /* only report the valid player app attributes */
+ if (AVRC_IsValidPlayerAttr(*p))
+ p_u8[yy++] = *p;
+ p++;
+ }
+ p_result->get_cur_app_val.num_attr = yy;
+ if (yy == 0)
+ {
+ status = AVRC_STS_BAD_PARAM;
+ }
+ break;
+
+ case AVRC_PDU_SET_PLAYER_APP_VALUE: /* 0x14 */
+ BE_STREAM_TO_UINT8 (p_result->set_app_val.num_val, p);
+ size_needed = sizeof(tAVRC_APP_SETTING);
+ if (p_buf && (len == ((p_result->set_app_val.num_val<<1) + 1)))
+ {
+ p_result->set_app_val.p_vals = (tAVRC_APP_SETTING *)p_buf;
+ p_app_set = p_result->set_app_val.p_vals;
+ for (xx=0; ((xx< p_result->set_app_val.num_val) && (buf_len > size_needed)); xx++)
+ {
+ p_app_set[xx].attr_id = *p++;
+ p_app_set[xx].attr_val = *p++;
+ if (!avrc_is_valid_player_attrib_value(p_app_set[xx].attr_id, p_app_set[xx].attr_val))
+ status = AVRC_STS_BAD_PARAM;
+ }
+ if (xx != p_result->set_app_val.num_val)
+ {
+ AVRC_TRACE_ERROR2("AVRC_PDU_SET_PLAYER_APP_VALUE not enough room:%d orig num_val:%d",
+ xx, p_result->set_app_val.num_val);
+ p_result->set_app_val.num_val = xx;
+ }
+ }
+ else
+ {
+ AVRC_TRACE_ERROR0("AVRC_PDU_SET_PLAYER_APP_VALUE NULL decode buffer or bad len");
+ status = AVRC_STS_INTERNAL_ERR;
+ }
+ break;
+
+ case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT:/* 0x16 */
+ if (len < 3)
+ status = AVRC_STS_INTERNAL_ERR;
+ else
+ {
+ BE_STREAM_TO_UINT8 (p_result->get_app_val_txt.attr_id, p);
+ if (!AVRC_IS_VALID_ATTRIBUTE(p_result->get_app_val_txt.attr_id))
+ status = AVRC_STS_BAD_PARAM;
+ else
+ {
+ BE_STREAM_TO_UINT8 (p_result->get_app_val_txt.num_val, p);
+ if ( (len - 2/* attr_id & num_val */) != p_result->get_app_val_txt.num_val)
+ status = AVRC_STS_INTERNAL_ERR;
+ else
+ {
+ p_u8 = p_result->get_app_val_txt.vals;
+ for (xx=0; xx< p_result->get_app_val_txt.num_val; xx++)
+ {
+ p_u8[xx] = *p++;
+ if (!avrc_is_valid_player_attrib_value(p_result->get_app_val_txt.attr_id, p_u8[xx]))
+ {
+ status = AVRC_STS_BAD_PARAM;
+ break;
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ case AVRC_PDU_INFORM_DISPLAY_CHARSET: /* 0x17 */
+ if (len < 3)
+ status = AVRC_STS_INTERNAL_ERR;
+ else
+ {
+ BE_STREAM_TO_UINT8 (p_result->inform_charset.num_id, p);
+ if ( (len - 1/* num_id */) != p_result->inform_charset.num_id * 2)
+ status = AVRC_STS_INTERNAL_ERR;
+ else
+ {
+ p_u16 = p_result->inform_charset.charsets;
+ if (p_result->inform_charset.num_id > AVRC_MAX_CHARSET_SIZE)
+ p_result->inform_charset.num_id = AVRC_MAX_CHARSET_SIZE;
+ for (xx=0; xx< p_result->inform_charset.num_id; xx++)
+ {
+ BE_STREAM_TO_UINT16 (p_u16[xx], p);
+ }
+ }
+ }
+ break;
+
+ case AVRC_PDU_INFORM_BATTERY_STAT_OF_CT:/* 0x18 */
+ if (len != 1)
+ status = AVRC_STS_INTERNAL_ERR;
+ else
+ {
+ p_result->inform_battery_status.battery_status = *p++;
+ if (!AVRC_IS_VALID_BATTERY_STATUS(p_result->inform_battery_status.battery_status))
+ status = AVRC_STS_BAD_PARAM;
+ }
+ break;
+
+ case AVRC_PDU_GET_ELEMENT_ATTR: /* 0x20 */
+ if (len < 9) /* UID/8 and num_attr/1 */
+ status = AVRC_STS_INTERNAL_ERR;
+ else
+ {
+ BE_STREAM_TO_UINT32 (u32, p);
+ BE_STREAM_TO_UINT32 (u32_2, p);
+ if (u32== 0 && u32_2 == 0)
+ {
+ BE_STREAM_TO_UINT8 (p_result->get_elem_attrs.num_attr, p);
+ if ( (len - 9/* UID/8 and num_attr/1 */) != (p_result->get_elem_attrs.num_attr * 4))
+ status = AVRC_STS_INTERNAL_ERR;
+ else
+ {
+ p_u32 = p_result->get_elem_attrs.attrs;
+ if (p_result->get_elem_attrs.num_attr > AVRC_MAX_ELEM_ATTR_SIZE)
+ p_result->get_elem_attrs.num_attr = AVRC_MAX_ELEM_ATTR_SIZE;
+ for (xx=0; xx< p_result->get_elem_attrs.num_attr; xx++)
+ {
+ BE_STREAM_TO_UINT32 (p_u32[xx], p);
+ }
+ }
+ }
+ else
+ status = AVRC_STS_NOT_FOUND;
+ }
+ break;
+
+ case AVRC_PDU_GET_PLAY_STATUS: /* 0x30 */
+ /* no additional parameters */
+ if (len != 0)
+ status = AVRC_STS_INTERNAL_ERR;
+ break;
+
+ case AVRC_PDU_REGISTER_NOTIFICATION: /* 0x31 */
+ if (len != 5)
+ status = AVRC_STS_INTERNAL_ERR;
+ BE_STREAM_TO_UINT8 (p_result->reg_notif.event_id, p);
+ BE_STREAM_TO_UINT32 (p_result->reg_notif.param, p);
+ break;
+
+ /* case AVRC_PDU_REQUEST_CONTINUATION_RSP: 0x40 */
+ /* case AVRC_PDU_ABORT_CONTINUATION_RSP: 0x41 */
+
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
+ case AVRC_PDU_SET_ABSOLUTE_VOLUME: /* 0x50 */
+ if (len != 1)
+ status = AVRC_STS_INTERNAL_ERR;
+ p_result->volume.volume = *p++;
+ break;
+
+ case AVRC_PDU_SET_ADDRESSED_PLAYER: /* 0x60 */
+ if (len != 2)
+ status = AVRC_STS_INTERNAL_ERR;
+ BE_STREAM_TO_UINT16 (p_result->addr_player.player_id, p);
+ break;
+
+ case AVRC_PDU_PLAY_ITEM: /* 0x74 */
+ case AVRC_PDU_ADD_TO_NOW_PLAYING: /* 0x90 */
+ if (len != (AVRC_UID_SIZE + 3))
+ status = AVRC_STS_INTERNAL_ERR;
+ BE_STREAM_TO_UINT8 (p_result->play_item.scope, p);
+ if (p_result->play_item.scope > AVRC_SCOPE_NOW_PLAYING)
+ {
+ status = AVRC_STS_BAD_SCOPE;
+ }
+ BE_STREAM_TO_ARRAY (p, p_result->play_item.uid, AVRC_UID_SIZE);
+ BE_STREAM_TO_UINT16 (p_result->play_item.uid_counter, p);
+ break;
+#endif /* (AVRC_ADV_CTRL_INCLUDED == TRUE) */
+
+ default:
+ status = AVRC_STS_BAD_CMD;
+ break;
+ }
+
+ return status;
+}
+
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function avrc_pars_browsing
+**
+** Description This function parses the commands that go through the
+** browsing channel
+**
+** Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully.
+** Otherwise, the error code defined by AVRCP+1
+**
+*******************************************************************************/
+static tAVRC_STS avrc_pars_browsing_cmd(tAVRC_MSG_BROWSE *p_msg, tAVRC_COMMAND *p_result, UINT8 *p_buf, UINT16 buf_len)
+{
+ tAVRC_STS status = AVRC_STS_NO_ERROR;
+ UINT8 *p = p_msg->p_browse_data;
+ UINT16 len;
+ int i, count;
+
+ p_result->pdu = *p++;
+ AVRC_TRACE_DEBUG1("avrc_pars_browsing_cmd() pdu:0x%x", p_result->pdu);
+ BE_STREAM_TO_UINT16 (len, p);
+ switch (p_result->pdu)
+ {
+ case AVRC_PDU_SET_BROWSED_PLAYER: /* 0x70 */
+ BE_STREAM_TO_UINT16 (p_result->br_player.player_id, p);
+ break;
+
+ case AVRC_PDU_GET_FOLDER_ITEMS: /* 0x71 */
+ BE_STREAM_TO_UINT8 (p_result->get_items.scope, p);
+ if (p_result->get_items.scope > AVRC_SCOPE_NOW_PLAYING)
+ {
+ status = AVRC_STS_BAD_SCOPE;
+ }
+ BE_STREAM_TO_UINT32 (p_result->get_items.start_item, p);
+ BE_STREAM_TO_UINT32 (p_result->get_items.end_item, p);
+ if (p_result->get_items.start_item > p_result->get_items.end_item)
+ {
+ status = AVRC_STS_BAD_RANGE;
+ }
+ BE_STREAM_TO_UINT8 (p_result->get_items.attr_count, p);
+ p_result->get_items.p_attr_list = NULL;
+ if (p_result->get_items.attr_count && p_buf &&
+ (p_result->get_items.attr_count != AVRC_FOLDER_ITEM_COUNT_NONE))
+ {
+ p_result->get_items.p_attr_list = (UINT32 *)p_buf;
+ count = p_result->get_items.attr_count;
+ if (buf_len < (count<<2))
+ p_result->get_items.attr_count = count = (buf_len >> 2);
+ for (i=0; i<count; i++)
+ {
+ BE_STREAM_TO_UINT32 (p_result->get_items.p_attr_list[i], p);
+ }
+ }
+ break;
+
+ case AVRC_PDU_CHANGE_PATH: /* 0x72 */
+ BE_STREAM_TO_UINT16 (p_result->chg_path.uid_counter, p);
+ BE_STREAM_TO_UINT8 (p_result->chg_path.direction, p);
+ if (p_result->chg_path.direction != AVRC_DIR_UP && p_result->chg_path.direction != AVRC_DIR_DOWN)
+ {
+ status = AVRC_STS_BAD_DIR;
+ }
+ BE_STREAM_TO_ARRAY (p, p_result->chg_path.folder_uid, AVRC_UID_SIZE);
+ break;
+
+ case AVRC_PDU_GET_ITEM_ATTRIBUTES: /* 0x73 */
+ BE_STREAM_TO_UINT8 (p_result->get_attrs.scope, p);
+ if (p_result->get_attrs.scope > AVRC_SCOPE_NOW_PLAYING)
+ {
+ status = AVRC_STS_BAD_SCOPE;
+ break;
+ }
+ BE_STREAM_TO_ARRAY (p, p_result->get_attrs.uid, AVRC_UID_SIZE);
+ BE_STREAM_TO_UINT16 (p_result->get_attrs.uid_counter, p);
+ BE_STREAM_TO_UINT8 (p_result->get_attrs.attr_count, p);
+ p_result->get_attrs.p_attr_list = NULL;
+ if (p_result->get_attrs.attr_count && p_buf)
+ {
+ p_result->get_attrs.p_attr_list = (UINT32 *)p_buf;
+ count = p_result->get_attrs.attr_count;
+ if (buf_len < (count<<2))
+ p_result->get_attrs.attr_count = count = (buf_len >> 2);
+ for (i=0, count=0; i<p_result->get_attrs.attr_count; i++)
+ {
+ BE_STREAM_TO_UINT32 (p_result->get_attrs.p_attr_list[count], p);
+ if (AVRC_IS_VALID_MEDIA_ATTRIBUTE(p_result->get_attrs.p_attr_list[count]))
+ {
+ count++;
+ }
+ }
+
+ if (p_result->get_attrs.attr_count != count && count == 0)
+ status = AVRC_STS_BAD_PARAM;
+ else
+ p_result->get_attrs.attr_count = count;
+ }
+ break;
+
+ case AVRC_PDU_SEARCH: /* 0x80 */
+ BE_STREAM_TO_UINT16 (p_result->search.string.charset_id, p);
+ BE_STREAM_TO_UINT16 (p_result->search.string.str_len, p);
+ p_result->search.string.p_str = p_buf;
+ if (p_buf)
+ {
+ if (buf_len > p_result->search.string.str_len)
+ buf_len = p_result->search.string.str_len;
+ BE_STREAM_TO_ARRAY (p, p_buf, p_result->search.string.str_len);
+ }
+ else
+ {
+ status = AVRC_STS_INTERNAL_ERR;
+ }
+ break;
+
+ default:
+ status = AVRC_STS_BAD_CMD;
+ break;
+ }
+ return status;
+}
+#endif /* AVCT_BROWSE_INCLUDED == TRUE*/
+
+/*******************************************************************************
+**
+** Function AVRC_ParsCommand
+**
+** Description This function is a superset of AVRC_ParsMetadata to parse the command.
+**
+** Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully.
+** Otherwise, the error code defined by AVRCP 1.4
+**
+*******************************************************************************/
+tAVRC_STS AVRC_ParsCommand (tAVRC_MSG *p_msg, tAVRC_COMMAND *p_result, UINT8 *p_buf, UINT16 buf_len)
+{
+ tAVRC_STS status = AVRC_STS_INTERNAL_ERR;
+ UINT16 id;
+
+ if (p_msg && p_result)
+ {
+ switch (p_msg->hdr.opcode)
+ {
+ case AVRC_OP_VENDOR: /* 0x00 Vendor-dependent commands */
+ status = avrc_pars_vendor_cmd(&p_msg->vendor, p_result, p_buf, buf_len);
+ break;
+
+ case AVRC_OP_PASS_THRU: /* 0x7C panel subunit opcode */
+ status = avrc_pars_pass_thru(&p_msg->pass, &id);
+ if (status == AVRC_STS_NO_ERROR)
+ {
+ p_result->pdu = (UINT8)id;
+ }
+ break;
+
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+ case AVRC_OP_BROWSE:
+ status = avrc_pars_browsing_cmd(&p_msg->browse, p_result, p_buf, buf_len);
+ break;
+#endif /*(AVCT_BROWSE_INCLUDED == TRUE)*/
+
+ default:
+ AVRC_TRACE_ERROR1("AVRC_ParsCommand() unknown opcode:0x%x", p_msg->hdr.opcode);
+ break;
+ }
+ p_result->cmd.opcode = p_msg->hdr.opcode;
+ p_result->cmd.status = status;
+ }
+ AVRC_TRACE_DEBUG1("AVRC_ParsCommand() return status:0x%x", status);
+ return status;
+}
+
+#endif /* (AVRC_METADATA_INCLUDED == TRUE) */
+
diff --git a/stack/avrc/avrc_sdp.c b/stack/avrc/avrc_sdp.c
new file mode 100644
index 0000000..ad2024e
--- /dev/null
+++ b/stack/avrc/avrc_sdp.c
@@ -0,0 +1,318 @@
+/*****************************************************************************
+**
+** Name: avrc_sdp.c
+**
+** Description: AVRCP SDP related functions
+**
+** Copyright (c) 2003-2006, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include <string.h>
+
+#include "gki.h"
+#include "avrc_api.h"
+#include "avrc_int.h"
+
+/*****************************************************************************
+** Global data
+*****************************************************************************/
+#if AVRC_DYNAMIC_MEMORY == FALSE
+tAVRC_CB avrc_cb;
+#endif
+
+/* update AVRC_NUM_PROTO_ELEMS if this constant is changed */
+const tSDP_PROTOCOL_ELEM avrc_proto_list [] =
+{
+ {UUID_PROTOCOL_L2CAP, 1, {AVCT_PSM, 0} },
+#if AVRC_ADV_CTRL_INCLUDED == TRUE
+ {UUID_PROTOCOL_AVCTP, 1, {AVCT_REV_1_3, 0} }
+#else
+#if AVRC_METADATA_INCLUDED == TRUE
+ {UUID_PROTOCOL_AVCTP, 1, {AVCT_REV_1_2, 0} }
+#else
+ {UUID_PROTOCOL_AVCTP, 1, {AVCT_REV_1_0, 0} }
+#endif
+#endif
+};
+
+#if AVRC_ADV_CTRL_INCLUDED == TRUE
+const tSDP_PROTO_LIST_ELEM avrc_add_proto_list [] =
+{
+ {AVRC_NUM_PROTO_ELEMS,
+ {
+ {UUID_PROTOCOL_L2CAP, 1, {AVCT_BR_PSM, 0} },
+ {UUID_PROTOCOL_AVCTP, 1, {AVCT_REV_1_3, 0} }}}
+};
+#endif
+
+
+/******************************************************************************
+**
+** Function avrc_sdp_cback
+**
+** Description This is the SDP callback function used by A2D_FindService.
+** This function will be executed by SDP when the service
+** search is completed. If the search is successful, it
+** finds the first record in the database that matches the
+** UUID of the search. Then retrieves various parameters
+** from the record. When it is finished it calls the
+** application callback function.
+**
+** Returns Nothing.
+**
+******************************************************************************/
+static void avrc_sdp_cback(UINT16 status)
+{
+ AVRC_TRACE_API1("avrc_sdp_cback status: %d", status);
+
+ /* reset service_uuid, so can start another find service */
+ avrc_cb.service_uuid = 0;
+
+ /* return info from sdp record in app callback function */
+ (*avrc_cb.p_cback) (status);
+
+ return;
+}
+
+/******************************************************************************
+**
+** Function AVRC_FindService
+**
+** Description This function is called by the application to perform service
+** discovery and retrieve AVRCP SDP record information from a
+** peer device. Information is returned for the first service
+** record found on the server that matches the service UUID.
+** The callback function will be executed when service discovery
+** is complete. There can only be one outstanding call to
+** AVRC_FindService() at a time; the application must wait for
+** the callback before it makes another call to the function.
+** The application is responsible for allocating memory for the
+** discovery database. It is recommended that the size of the
+** discovery database be at least 300 bytes. The application
+** can deallocate the memory after the callback function has
+** executed.
+**
+** Input Parameters:
+** service_uuid: Indicates TG(UUID_SERVCLASS_AV_REM_CTRL_TARGET)
+** or CT(UUID_SERVCLASS_AV_REMOTE_CONTROL)
+**
+** bd_addr: BD address of the peer device.
+**
+** p_db: SDP discovery database parameters.
+**
+** p_cback: Pointer to the callback function.
+**
+** Output Parameters:
+** None.
+**
+** Returns AVRC_SUCCESS if successful.
+** AVRC_BAD_PARAMS if discovery database parameters are invalid.
+** AVRC_NO_RESOURCES if there are not enough resources to
+** perform the service search.
+**
+******************************************************************************/
+UINT16 AVRC_FindService(UINT16 service_uuid, BD_ADDR bd_addr,
+ tAVRC_SDP_DB_PARAMS *p_db, tAVRC_FIND_CBACK *p_cback)
+{
+ tSDP_UUID uuid_list;
+ BOOLEAN result = TRUE;
+ UINT16 a2d_attr_list[] = {ATTR_ID_SERVICE_CLASS_ID_LIST, /* update AVRC_NUM_ATTR, if changed */
+ ATTR_ID_PROTOCOL_DESC_LIST,
+ ATTR_ID_BT_PROFILE_DESC_LIST,
+ ATTR_ID_SERVICE_NAME,
+ ATTR_ID_SUPPORTED_FEATURES,
+ ATTR_ID_PROVIDER_NAME};
+
+ AVRC_TRACE_API1("AVRC_FindService uuid: %x", service_uuid);
+ if( (service_uuid != UUID_SERVCLASS_AV_REM_CTRL_TARGET && service_uuid != UUID_SERVCLASS_AV_REMOTE_CONTROL) ||
+ p_db == NULL || p_db->p_db == NULL || p_cback == NULL)
+ return AVRC_BAD_PARAM;
+
+ /* check if it is busy */
+ if( avrc_cb.service_uuid == UUID_SERVCLASS_AV_REM_CTRL_TARGET ||
+ avrc_cb.service_uuid == UUID_SERVCLASS_AV_REMOTE_CONTROL)
+ return AVRC_NO_RESOURCES;
+
+ /* set up discovery database */
+ uuid_list.len = LEN_UUID_16;
+ uuid_list.uu.uuid16 = service_uuid;
+
+ if(p_db->p_attrs == NULL || p_db->num_attr == 0)
+ {
+ p_db->p_attrs = a2d_attr_list;
+ p_db->num_attr = AVRC_NUM_ATTR;
+ }
+
+ result = SDP_InitDiscoveryDb(p_db->p_db, p_db->db_len, 1, &uuid_list, p_db->num_attr,
+ p_db->p_attrs);
+
+ if (result == TRUE)
+ {
+ /* store service_uuid and discovery db pointer */
+ avrc_cb.p_db = p_db->p_db;
+ avrc_cb.service_uuid = service_uuid;
+ avrc_cb.p_cback = p_cback;
+
+ /* perform service search */
+ result = SDP_ServiceSearchAttributeRequest(bd_addr, p_db->p_db, avrc_sdp_cback);
+ }
+
+ return (result ? AVRC_SUCCESS : AVRC_FAIL);
+}
+
+/******************************************************************************
+**
+** Function AVRC_AddRecord
+**
+** Description This function is called to build an AVRCP SDP record.
+** Prior to calling this function the application must
+** call SDP_CreateRecord() to create an SDP record.
+**
+** Input Parameters:
+** service_uuid: Indicates TG(UUID_SERVCLASS_AV_REM_CTRL_TARGET)
+** or CT(UUID_SERVCLASS_AV_REMOTE_CONTROL)
+**
+** p_service_name: Pointer to a null-terminated character
+** string containing the service name.
+** If service name is not used set this to NULL.
+**
+** p_provider_name: Pointer to a null-terminated character
+** string containing the provider name.
+** If provider name is not used set this to NULL.
+**
+** categories: Supported categories.
+**
+** sdp_handle: SDP handle returned by SDP_CreateRecord().
+**
+** Output Parameters:
+** None.
+**
+** Returns AVRC_SUCCESS if successful.
+** AVRC_NO_RESOURCES if not enough resources to build the SDP record.
+**
+******************************************************************************/
+UINT16 AVRC_AddRecord(UINT16 service_uuid, char *p_service_name,
+ char *p_provider_name, UINT16 categories, UINT32 sdp_handle)
+{
+ UINT16 browse_list[1];
+ BOOLEAN result = TRUE;
+ UINT8 temp[8];
+ UINT8 *p;
+ UINT16 count = 1;
+ UINT16 class_list[2];
+
+
+ AVRC_TRACE_API1("AVRC_AddRecord uuid: %x", service_uuid);
+
+ if( service_uuid != UUID_SERVCLASS_AV_REM_CTRL_TARGET && service_uuid != UUID_SERVCLASS_AV_REMOTE_CONTROL )
+ return AVRC_BAD_PARAM;
+
+ /* add service class id list */
+ class_list[0] = service_uuid;
+#if AVRC_ADV_CTRL_INCLUDED == TRUE
+ if( service_uuid == UUID_SERVCLASS_AV_REMOTE_CONTROL )
+ {
+ class_list[1] = UUID_SERVCLASS_AV_REM_CTRL_CONTROL;
+ count = 2;
+ }
+#endif
+ result &= SDP_AddServiceClassIdList(sdp_handle, count, class_list);
+
+ /* add protocol descriptor list */
+ result &= SDP_AddProtocolList(sdp_handle, AVRC_NUM_PROTO_ELEMS, (tSDP_PROTOCOL_ELEM *)avrc_proto_list);
+
+ /* add profile descriptor list */
+#if AVRC_ADV_CTRL_INCLUDED == TRUE
+ result &= SDP_AddProfileDescriptorList(sdp_handle, UUID_SERVCLASS_AV_REMOTE_CONTROL, AVRC_REV_1_4);
+ /* additional protocol list to include browsing channel */
+ result &= SDP_AddAdditionProtoLists( sdp_handle, 1, (tSDP_PROTO_LIST_ELEM *)avrc_add_proto_list);
+#else
+#if AVRC_METADATA_INCLUDED == TRUE
+ result &= SDP_AddProfileDescriptorList(sdp_handle, UUID_SERVCLASS_AV_REMOTE_CONTROL, AVRC_REV_1_3);
+#else
+ result &= SDP_AddProfileDescriptorList(sdp_handle, UUID_SERVCLASS_AV_REMOTE_CONTROL, AVRC_REV_1_0);
+#endif
+#endif
+
+ /* add supported categories */
+ p = temp;
+ UINT16_TO_BE_STREAM(p, categories);
+ result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SUPPORTED_FEATURES, UINT_DESC_TYPE,
+ (UINT32)2, (UINT8*)temp);
+
+ /* add provider name */
+ if (p_provider_name != NULL)
+ {
+ result &= SDP_AddAttribute(sdp_handle, ATTR_ID_PROVIDER_NAME, TEXT_STR_DESC_TYPE,
+ (UINT32)(strlen(p_provider_name)+1), (UINT8 *) p_provider_name);
+ }
+
+ /* add service name */
+ if (p_service_name != NULL)
+ {
+ result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE,
+ (UINT32)(strlen(p_service_name)+1), (UINT8 *) p_service_name);
+ }
+
+ /* add browse group list */
+ browse_list[0] = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
+ result &= SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, browse_list);
+
+
+ return (result ? AVRC_SUCCESS : AVRC_FAIL);
+}
+
+
+
+/******************************************************************************
+**
+** Function AVRC_SetTraceLevel
+**
+** Description Sets the trace level for AVRC. If 0xff is passed, the
+** current trace level is returned.
+**
+** Input Parameters:
+** new_level: The level to set the AVRC tracing to:
+** 0xff-returns the current setting.
+** 0-turns off tracing.
+** >= 1-Errors.
+** >= 2-Warnings.
+** >= 3-APIs.
+** >= 4-Events.
+** >= 5-Debug.
+**
+** Returns The new trace level or current trace level if
+** the input parameter is 0xff.
+**
+******************************************************************************/
+UINT8 AVRC_SetTraceLevel (UINT8 new_level)
+{
+ if (new_level != 0xFF)
+ avrc_cb.trace_level = new_level;
+
+ return (avrc_cb.trace_level);
+}
+
+/*******************************************************************************
+**
+** Function AVRC_Init
+**
+** Description This function is called at stack startup to allocate the
+** control block (if using dynamic memory), and initializes the
+** control block and tracing level.
+**
+** Returns void
+**
+*******************************************************************************/
+void AVRC_Init(void)
+{
+ memset(&avrc_cb, 0, sizeof(tAVRC_CB));
+
+#if defined(AVRC_INITIAL_TRACE_LEVEL)
+ avrc_cb.trace_level = AVRC_INITIAL_TRACE_LEVEL;
+#else
+ avrc_cb.trace_level = BT_TRACE_LEVEL_NONE;
+#endif
+}
+
diff --git a/stack/avrc/avrc_utils.c b/stack/avrc/avrc_utils.c
new file mode 100644
index 0000000..b9eef9b
--- /dev/null
+++ b/stack/avrc/avrc_utils.c
@@ -0,0 +1,254 @@
+/*****************************************************************************
+**
+** Name: avrc_utils.c
+**
+** Description: Utility functions to validate AVRC command/response paramaters
+**
+** Copyright (c) 2003-2008, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include <string.h>
+
+#include "gki.h"
+#include "avrc_api.h"
+#include "avrc_int.h"
+
+
+#if (AVRC_METADATA_INCLUDED == TRUE)
+
+/**************************************************************************
+**
+** Function AVRC_IsValidAvcType
+**
+** Description Check if correct AVC type is specified
+**
+** Returns returns TRUE if it is valid
+**
+**
+*******************************************************************************/
+BOOLEAN AVRC_IsValidAvcType(UINT8 pdu_id, UINT8 avc_type)
+{
+ BOOLEAN result=FALSE;
+
+ if (avc_type < AVRC_RSP_NOT_IMPL) /* command msg */
+ {
+ switch (pdu_id)
+ {
+ case AVRC_PDU_GET_CAPABILITIES: /* 0x10 */
+ case AVRC_PDU_LIST_PLAYER_APP_ATTR: /* 0x11 */
+ case AVRC_PDU_LIST_PLAYER_APP_VALUES: /* 0x12 */
+ case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE: /* 0x13 */
+ case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT: /* 0x15 */
+ case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT: /* 0x16 */
+ case AVRC_PDU_GET_ELEMENT_ATTR: /* 0x20 */
+ case AVRC_PDU_GET_PLAY_STATUS: /* 0x30 */
+ if (avc_type == AVRC_CMD_STATUS)
+ result=TRUE;
+ break;
+
+ case AVRC_PDU_SET_PLAYER_APP_VALUE: /* 0x14 */
+ case AVRC_PDU_INFORM_DISPLAY_CHARSET: /* 0x17 */
+ case AVRC_PDU_INFORM_BATTERY_STAT_OF_CT: /* 0x18 */
+ case AVRC_PDU_REQUEST_CONTINUATION_RSP: /* 0x40 */
+ case AVRC_PDU_ABORT_CONTINUATION_RSP: /* 0x41 */
+ if (avc_type == AVRC_CMD_CTRL)
+ result=TRUE;
+ break;
+
+ case AVRC_PDU_REGISTER_NOTIFICATION: /* 0x31 */
+ if (avc_type == AVRC_CMD_NOTIF)
+ result=TRUE;
+ break;
+
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
+ case AVRC_PDU_SET_ABSOLUTE_VOLUME: /* 0x50 */
+ case AVRC_PDU_SET_ADDRESSED_PLAYER: /* 0x60 */
+ case AVRC_PDU_PLAY_ITEM: /* 0x74 */
+ case AVRC_PDU_ADD_TO_NOW_PLAYING: /* 0x90 */
+ if (avc_type == AVRC_CMD_CTRL)
+ result=TRUE;
+ break;
+#endif
+ }
+ }
+ else /* response msg */
+ {
+ if (avc_type >= AVRC_RSP_NOT_IMPL &&
+ avc_type <= AVRC_RSP_INTERIM )
+ result=TRUE;
+ }
+
+ return result;
+}
+
+/*******************************************************************************
+**
+** Function avrc_is_valid_player_attrib_value
+**
+** Description Check if the given attrib value is valid for its attribute
+**
+**
+** Returns returns TRUE if it is valid
+**
+*******************************************************************************/
+BOOLEAN avrc_is_valid_player_attrib_value(UINT8 attrib, UINT8 value)
+{
+ BOOLEAN result=FALSE;
+
+ switch(attrib)
+ {
+ case AVRC_PLAYER_SETTING_EQUALIZER:
+ if ((value > 0) &&
+ (value <= AVRC_PLAYER_VAL_ON))
+ result=TRUE;
+ break;
+
+ case AVRC_PLAYER_SETTING_REPEAT:
+ if ((value > 0) &&
+ (value <= AVRC_PLAYER_VAL_GROUP_REPEAT))
+ result=TRUE;
+ break;
+
+ case AVRC_PLAYER_SETTING_SHUFFLE:
+ case AVRC_PLAYER_SETTING_SCAN:
+ if ((value > 0) &&
+ (value <= AVRC_PLAYER_VAL_GROUP_SHUFFLE))
+ result=TRUE;
+ break;
+ }
+
+ if (attrib >= AVRC_PLAYER_SETTING_LOW_MENU_EXT &&
+ attrib <= AVRC_PLAYER_SETTING_HIGH_MENU_EXT)
+ result = TRUE;
+
+ if (!result)
+ AVRC_TRACE_ERROR2("avrc_is_valid_player_attrib_value() found not matching attrib(x%x)-value(x%x) pair!", attrib, value);
+
+ return result;
+}
+
+/*******************************************************************************
+**
+** Function AVRC_IsValidPlayerAttr
+**
+** Description Check if the given attrib value is a valid one
+**
+**
+** Returns returns TRUE if it is valid
+**
+*******************************************************************************/
+BOOLEAN AVRC_IsValidPlayerAttr(UINT8 attr)
+{
+ BOOLEAN result=FALSE;
+
+ if ( (attr >= AVRC_PLAYER_SETTING_EQUALIZER && attr <= AVRC_PLAYER_SETTING_SCAN) ||
+ (attr >= AVRC_PLAYER_SETTING_LOW_MENU_EXT && attr <= AVRC_PLAYER_SETTING_HIGH_MENU_EXT) )
+ {
+ result = TRUE;
+ }
+
+ return result;
+}
+
+
+
+/*******************************************************************************
+**
+** Function avrc_pars_pass_thru
+**
+** Description This function parses the pass thru commands defined by
+** Bluetooth SIG
+**
+** Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully.
+** Otherwise, the error code defined by AVRCP 1.4
+**
+*******************************************************************************/
+tAVRC_STS avrc_pars_pass_thru(tAVRC_MSG_PASS *p_msg, UINT16 *p_vendor_unique_id)
+{
+ UINT8 *p_data;
+ UINT32 co_id;
+ UINT16 id;
+ tAVRC_STS status = AVRC_STS_BAD_CMD;
+
+ if (p_msg->op_id == AVRC_ID_VENDOR && p_msg->pass_len == AVRC_PASS_THRU_GROUP_LEN)
+ {
+ p_data = p_msg->p_pass_data;
+ AVRC_BE_STREAM_TO_CO_ID (co_id, p_data);
+ if (co_id == AVRC_CO_METADATA)
+ {
+ BE_STREAM_TO_UINT16 (id, p_data);
+ if (AVRC_IS_VALID_GROUP(id))
+ {
+ *p_vendor_unique_id = id;
+ status = AVRC_STS_NO_ERROR;
+ }
+ }
+ }
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function avrc_opcode_from_pdu
+**
+** Description This function returns the opcode of the given pdu
+**
+** Returns AVRC_OP_VENDOR, AVRC_OP_PASS_THRU or AVRC_OP_BROWSE
+**
+*******************************************************************************/
+UINT8 avrc_opcode_from_pdu(UINT8 pdu)
+{
+ UINT8 opcode = 0;
+
+ switch (pdu)
+ {
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+ case AVRC_PDU_SET_BROWSED_PLAYER:
+ case AVRC_PDU_GET_FOLDER_ITEMS:
+ case AVRC_PDU_CHANGE_PATH:
+ case AVRC_PDU_GET_ITEM_ATTRIBUTES:
+ case AVRC_PDU_SEARCH:
+ case AVRC_PDU_GENERAL_REJECT:
+ opcode = AVRC_OP_BROWSE;
+ break;
+#endif /* AVCT_BROWSE_INCLUDED */
+
+ case AVRC_PDU_NEXT_GROUP:
+ case AVRC_PDU_PREV_GROUP: /* pass thru */
+ opcode = AVRC_OP_PASS_THRU;
+ break;
+
+ default: /* vendor */
+ opcode = AVRC_OP_VENDOR;
+ break;
+ }
+
+ return opcode;
+}
+
+/*******************************************************************************
+**
+** Function avrc_is_valid_opcode
+**
+** Description This function returns the opcode of the given pdu
+**
+** Returns AVRC_OP_VENDOR, AVRC_OP_PASS_THRU or AVRC_OP_BROWSE
+**
+*******************************************************************************/
+BOOLEAN avrc_is_valid_opcode(UINT8 opcode)
+{
+ BOOLEAN is_valid = FALSE;
+ switch (opcode)
+ {
+ case AVRC_OP_BROWSE:
+ case AVRC_OP_PASS_THRU:
+ case AVRC_OP_VENDOR:
+ is_valid = TRUE;
+ break;
+ }
+ return is_valid;
+}
+
+#endif /* (AVRC_METADATA_INCLUDED == TRUE) */
+
diff --git a/stack/bnep/bnep_api.c b/stack/bnep/bnep_api.c
new file mode 100644
index 0000000..28a7c6b
--- /dev/null
+++ b/stack/bnep/bnep_api.c
@@ -0,0 +1,768 @@
+/*****************************************************************************/
+/* */
+/* Name: bnep_api.c */
+/* */
+/* Description: this file contains the BNEP API code */
+/* */
+/* */
+/* Copyright (c) 2001-2004, WIDCOMM Inc., All Rights Reserved. */
+/* WIDCOMM Bluetooth Core. Proprietary and confidential. */
+/*****************************************************************************/
+
+#include <string.h>
+#include "bnep_api.h"
+#include "bnep_int.h"
+
+/*******************************************************************************
+**
+** Function BNEP_Init
+**
+** Description This function initializes the BNEP unit. It should be called
+** before accessing any other APIs to initialize the control block
+**
+** Returns void
+**
+*******************************************************************************/
+void BNEP_Init (void)
+{
+ memset (&bnep_cb, 0, sizeof (tBNEP_CB));
+
+#if defined(BNEP_INITIAL_TRACE_LEVEL)
+ bnep_cb.trace_level = BNEP_INITIAL_TRACE_LEVEL;
+#else
+ bnep_cb.trace_level = BT_TRACE_LEVEL_NONE; /* No traces */
+#endif
+
+ /* Start a timer to read our BD address */
+ btu_start_timer (&bnep_cb.bnep_tle, BTU_TTYPE_BNEP, 2);
+}
+
+
+/*******************************************************************************
+**
+** Function BNEP_Register
+**
+** Description This function is called by the upper layer to register
+** its callbacks with BNEP
+**
+** Parameters: p_reg_info - contains all callback function pointers
+**
+**
+** Returns BNEP_SUCCESS if registered successfully
+** BNEP_FAILURE if connection state callback is missing
+**
+*******************************************************************************/
+tBNEP_RESULT BNEP_Register (tBNEP_REGISTER *p_reg_info)
+{
+ /* There should be connection state call back registered */
+ if ((!p_reg_info) || (!(p_reg_info->p_conn_state_cb)))
+ return BNEP_SECURITY_FAIL;
+
+ bnep_cb.p_conn_ind_cb = p_reg_info->p_conn_ind_cb;
+ bnep_cb.p_conn_state_cb = p_reg_info->p_conn_state_cb;
+ bnep_cb.p_data_ind_cb = p_reg_info->p_data_ind_cb;
+ bnep_cb.p_data_buf_cb = p_reg_info->p_data_buf_cb;
+ bnep_cb.p_filter_ind_cb = p_reg_info->p_filter_ind_cb;
+ bnep_cb.p_mfilter_ind_cb = p_reg_info->p_mfilter_ind_cb;
+ bnep_cb.p_tx_data_flow_cb = p_reg_info->p_tx_data_flow_cb;
+
+ if (bnep_register_with_l2cap ())
+ return BNEP_SECURITY_FAIL;
+
+ bnep_cb.profile_registered = TRUE;
+
+ return BNEP_SUCCESS;
+}
+
+
+/*******************************************************************************
+**
+** Function BNEP_Deregister
+**
+** Description This function is called by the upper layer to de-register
+** its callbacks.
+**
+** Parameters: void
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BNEP_Deregister (void)
+{
+ /* Clear all the call backs registered */
+ bnep_cb.p_conn_ind_cb = NULL;
+ bnep_cb.p_conn_state_cb = NULL;
+ bnep_cb.p_data_ind_cb = NULL;
+ bnep_cb.p_data_buf_cb = NULL;
+ bnep_cb.p_filter_ind_cb = NULL;
+ bnep_cb.p_mfilter_ind_cb = NULL;
+
+ bnep_cb.profile_registered = FALSE;
+ L2CA_Deregister (BT_PSM_BNEP);
+}
+
+
+/*******************************************************************************
+**
+** Function BNEP_Connect
+**
+** Description This function creates a BNEP connection to a remote
+** device.
+**
+** Parameters: p_rem_addr - BD_ADDR of the peer
+** src_uuid - source uuid for the connection
+** dst_uuid - destination uuid for the connection
+** p_handle - pointer to return the handle for the connection
+**
+** Returns BNEP_SUCCESS if connection started
+** BNEP_NO_RESOURCES if no resources
+**
+*******************************************************************************/
+tBNEP_RESULT BNEP_Connect (BD_ADDR p_rem_bda,
+ tBT_UUID *src_uuid,
+ tBT_UUID *dst_uuid,
+ UINT16 *p_handle)
+{
+ UINT16 cid;
+ tBNEP_CONN *p_bcb = bnepu_find_bcb_by_bd_addr (p_rem_bda);
+
+ BNEP_TRACE_API6 ("BNEP_Connect() BDA: %02x-%02x-%02x-%02x-%02x-%02x",
+ p_rem_bda[0], p_rem_bda[1], p_rem_bda[2],
+ p_rem_bda[3], p_rem_bda[4], p_rem_bda[5]);
+
+ if (!bnep_cb.profile_registered)
+ return BNEP_WRONG_STATE;
+
+ /* Both source and destination UUID lengths should be same */
+ if (src_uuid->len != dst_uuid->len)
+ return BNEP_CONN_FAILED_UUID_SIZE;
+
+#if (!defined (BNEP_SUPPORTS_ALL_UUID_LENGTHS) || BNEP_SUPPORTS_ALL_UUID_LENGTHS == FALSE)
+ if (src_uuid->len != 2)
+ return BNEP_CONN_FAILED_UUID_SIZE;
+#endif
+
+ if (!p_bcb)
+ {
+ if ((p_bcb = bnepu_allocate_bcb (p_rem_bda)) == NULL)
+ return (BNEP_NO_RESOURCES);
+ }
+ else if (p_bcb->con_state != BNEP_STATE_CONNECTED)
+ return BNEP_WRONG_STATE;
+ else
+ {
+ /* Backup current UUID values to restore if role change fails */
+ memcpy ((UINT8 *)&(p_bcb->prv_src_uuid), (UINT8 *)&(p_bcb->src_uuid), sizeof (tBT_UUID));
+ memcpy ((UINT8 *)&(p_bcb->prv_dst_uuid), (UINT8 *)&(p_bcb->dst_uuid), sizeof (tBT_UUID));
+ }
+
+ /* We are the originator of this connection */
+ p_bcb->con_flags |= BNEP_FLAGS_IS_ORIG;
+
+ memcpy ((UINT8 *)&(p_bcb->src_uuid), (UINT8 *)src_uuid, sizeof (tBT_UUID));
+ memcpy ((UINT8 *)&(p_bcb->dst_uuid), (UINT8 *)dst_uuid, sizeof (tBT_UUID));
+
+ if (p_bcb->con_state == BNEP_STATE_CONNECTED)
+ {
+ /* Transition to the next appropriate state, waiting for connection confirm. */
+ p_bcb->con_state = BNEP_STATE_SEC_CHECKING;
+
+ BNEP_TRACE_API1 ("BNEP initiating security procedures for src uuid 0x%x",
+ p_bcb->src_uuid.uu.uuid16);
+
+#if (defined (BNEP_DO_AUTH_FOR_ROLE_SWITCH) && BNEP_DO_AUTH_FOR_ROLE_SWITCH == TRUE)
+ btm_sec_mx_access_request (p_bcb->rem_bda, BT_PSM_BNEP, TRUE,
+ BTM_SEC_PROTO_BNEP,
+ bnep_get_uuid32(src_uuid),
+ &bnep_sec_check_complete, p_bcb);
+#else
+ bnep_sec_check_complete (p_bcb->rem_bda, p_bcb, BTM_SUCCESS);
+#endif
+
+ }
+ else
+ {
+ /* Transition to the next appropriate state, waiting for connection confirm. */
+ p_bcb->con_state = BNEP_STATE_CONN_START;
+
+ if ((cid = L2CA_ConnectReq (BT_PSM_BNEP, p_bcb->rem_bda)) != 0)
+ {
+ p_bcb->l2cap_cid = cid;
+
+ }
+ else
+ {
+ BNEP_TRACE_ERROR0 ("BNEP - Originate failed");
+ if (bnep_cb.p_conn_state_cb)
+ (*bnep_cb.p_conn_state_cb) (p_bcb->handle, p_bcb->rem_bda, BNEP_CONN_FAILED, FALSE);
+ bnepu_release_bcb (p_bcb);
+ return BNEP_CONN_FAILED;
+ }
+
+ /* Start timer waiting for connect */
+ btu_start_timer (&p_bcb->conn_tle, BTU_TTYPE_BNEP, BNEP_CONN_TIMEOUT);
+ }
+
+ *p_handle = p_bcb->handle;
+ return (BNEP_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function BNEP_ConnectResp
+**
+** Description This function is called in responce to connection indication
+**
+**
+** Parameters: handle - handle given in the connection indication
+** resp - responce for the connection indication
+**
+** Returns BNEP_SUCCESS if connection started
+** BNEP_WRONG_HANDLE if the connection is not found
+** BNEP_WRONG_STATE if the responce is not expected
+**
+*******************************************************************************/
+tBNEP_RESULT BNEP_ConnectResp (UINT16 handle, tBNEP_RESULT resp)
+{
+ tBNEP_CONN *p_bcb;
+ UINT16 resp_code = BNEP_SETUP_CONN_OK;
+
+ if ((!handle) || (handle > BNEP_MAX_CONNECTIONS))
+ return (BNEP_WRONG_HANDLE);
+
+ p_bcb = &(bnep_cb.bcb[handle - 1]);
+
+ if (p_bcb->con_state != BNEP_STATE_CONN_SETUP ||
+ (!(p_bcb->con_flags & BNEP_FLAGS_SETUP_RCVD)))
+ return (BNEP_WRONG_STATE);
+
+ BNEP_TRACE_API2 ("BNEP_ConnectResp() for handle %d, responce %d", handle, resp);
+
+ /* Form appropriate responce based on profile responce */
+ if (resp == BNEP_CONN_FAILED_SRC_UUID) resp_code = BNEP_SETUP_INVALID_SRC_UUID;
+ else if (resp == BNEP_CONN_FAILED_DST_UUID) resp_code = BNEP_SETUP_INVALID_DEST_UUID;
+ else if (resp == BNEP_CONN_FAILED_UUID_SIZE) resp_code = BNEP_SETUP_INVALID_UUID_SIZE;
+ else if (resp == BNEP_SUCCESS) resp_code = BNEP_SETUP_CONN_OK;
+ else resp_code = BNEP_SETUP_CONN_NOT_ALLOWED;
+
+ bnep_send_conn_responce (p_bcb, resp_code);
+ p_bcb->con_flags &= (~BNEP_FLAGS_SETUP_RCVD);
+
+ if (resp == BNEP_SUCCESS)
+ bnep_connected (p_bcb);
+ else if (p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED)
+ {
+ /* Restore the original parameters */
+ p_bcb->con_state = BNEP_STATE_CONNECTED;
+ p_bcb->con_flags &= (~BNEP_FLAGS_SETUP_RCVD);
+
+ memcpy ((UINT8 *)&(p_bcb->src_uuid), (UINT8 *)&(p_bcb->prv_src_uuid), sizeof (tBT_UUID));
+ memcpy ((UINT8 *)&(p_bcb->dst_uuid), (UINT8 *)&(p_bcb->prv_dst_uuid), sizeof (tBT_UUID));
+ }
+
+ /* Process remaining part of the setup message (extension headers) */
+ if (p_bcb->p_pending_data)
+ {
+ UINT8 extension_present = TRUE, *p, ext_type;
+ UINT16 rem_len;
+
+ rem_len = p_bcb->p_pending_data->len;
+ p = (UINT8 *)(p_bcb->p_pending_data + 1) + p_bcb->p_pending_data->offset;
+ while (extension_present && p && rem_len)
+ {
+ ext_type = *p++;
+ extension_present = ext_type >> 7;
+ ext_type &= 0x7F;
+
+ /* if unknown extension present stop processing */
+ if (ext_type)
+ break;
+
+ p = bnep_process_control_packet (p_bcb, p, &rem_len, TRUE);
+ }
+
+ GKI_freebuf (p_bcb->p_pending_data);
+ p_bcb->p_pending_data = NULL;
+ }
+ return (BNEP_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function BNEP_Disconnect
+**
+** Description This function is called to close the specified connection.
+**
+** Parameters: handle - handle of the connection
+**
+** Returns BNEP_SUCCESS if connection is disconnected
+** BNEP_WRONG_HANDLE if no connection is not found
+**
+*******************************************************************************/
+tBNEP_RESULT BNEP_Disconnect (UINT16 handle)
+{
+ tBNEP_CONN *p_bcb;
+
+ if ((!handle) || (handle > BNEP_MAX_CONNECTIONS))
+ return (BNEP_WRONG_HANDLE);
+
+ p_bcb = &(bnep_cb.bcb[handle - 1]);
+
+ if (p_bcb->con_state == BNEP_STATE_IDLE)
+ return (BNEP_WRONG_HANDLE);
+
+ BNEP_TRACE_API1 ("BNEP_Disconnect() for handle %d", handle);
+
+ L2CA_DisconnectReq (p_bcb->l2cap_cid);
+
+ bnepu_release_bcb (p_bcb);
+
+ return (BNEP_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function BNEP_WriteBuf
+**
+** Description This function sends data in a GKI buffer on BNEP connection
+**
+** Parameters: handle - handle of the connection to write
+** p_dest_addr - BD_ADDR/Ethernet addr of the destination
+** p_buf - pointer to address of buffer with data
+** protocol - protocol type of the packet
+** p_src_addr - (optional) BD_ADDR/ethernet address of the source
+** (should be NULL if it is local BD Addr)
+** fw_ext_present - forwarded extensions present
+**
+** Returns: BNEP_WRONG_HANDLE - if passed handle is not valid
+** BNEP_MTU_EXCEDED - If the data length is greater than MTU
+** BNEP_IGNORE_CMD - If the packet is filtered out
+** BNEP_Q_SIZE_EXCEEDED - If the Tx Q is full
+** BNEP_SUCCESS - If written successfully
+**
+*******************************************************************************/
+tBNEP_RESULT BNEP_WriteBuf (UINT16 handle,
+ UINT8 *p_dest_addr,
+ BT_HDR *p_buf,
+ UINT16 protocol,
+ UINT8 *p_src_addr,
+ BOOLEAN fw_ext_present)
+{
+ tBNEP_CONN *p_bcb;
+ UINT8 *p_data;
+
+ if ((!handle) || (handle > BNEP_MAX_CONNECTIONS))
+ {
+ GKI_freebuf (p_buf);
+ return (BNEP_WRONG_HANDLE);
+ }
+
+ p_bcb = &(bnep_cb.bcb[handle - 1]);
+ /* Check MTU size */
+ if (p_buf->len > BNEP_MTU_SIZE)
+ {
+ BNEP_TRACE_ERROR2 ("BNEP_Write() length %d exceeded MTU %d", p_buf->len, BNEP_MTU_SIZE);
+ GKI_freebuf (p_buf);
+ return (BNEP_MTU_EXCEDED);
+ }
+
+ /* Check if the packet should be filtered out */
+ p_data = (UINT8 *)(p_buf + 1) + p_buf->offset;
+ if (bnep_is_packet_allowed (p_bcb, p_dest_addr, protocol, fw_ext_present, p_data) != BNEP_SUCCESS)
+ {
+ /*
+ ** If packet is filtered and ext headers are present
+ ** drop the data and forward the ext headers
+ */
+ if (fw_ext_present)
+ {
+ UINT8 ext, length;
+ UINT16 org_len, new_len;
+ /* parse the extension headers and findout the new packet len */
+ org_len = p_buf->len;
+ new_len = 0;
+ do {
+
+ ext = *p_data++;
+ length = *p_data++;
+ p_data += length;
+
+ new_len += (length + 2);
+
+ if (new_len > org_len)
+ {
+ GKI_freebuf (p_buf);
+ return BNEP_IGNORE_CMD;
+ }
+
+ } while (ext & 0x80);
+
+ if (protocol != BNEP_802_1_P_PROTOCOL)
+ protocol = 0;
+ else
+ {
+ new_len += 4;
+ p_data[2] = 0;
+ p_data[3] = 0;
+ }
+ p_buf->len = new_len;
+ }
+ else
+ {
+ GKI_freebuf (p_buf);
+ return BNEP_IGNORE_CMD;
+ }
+ }
+
+ /* Check transmit queue */
+ if (p_bcb->xmit_q.count >= BNEP_MAX_XMITQ_DEPTH)
+ {
+ GKI_freebuf (p_buf);
+ return (BNEP_Q_SIZE_EXCEEDED);
+ }
+
+ /* Build the BNEP header */
+ bnepu_build_bnep_hdr (p_bcb, p_buf, protocol, p_src_addr, p_dest_addr, fw_ext_present);
+
+ /* Send the data or queue it up */
+ bnepu_check_send_packet (p_bcb, p_buf);
+
+ return (BNEP_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function BNEP_Write
+**
+** Description This function sends data over a BNEP connection
+**
+** Parameters: handle - handle of the connection to write
+** p_dest_addr - BD_ADDR/Ethernet addr of the destination
+** p_data - pointer to data start
+** protocol - protocol type of the packet
+** p_src_addr - (optional) BD_ADDR/ethernet address of the source
+** (should be NULL if it is local BD Addr)
+** fw_ext_present - forwarded extensions present
+**
+** Returns: BNEP_WRONG_HANDLE - if passed handle is not valid
+** BNEP_MTU_EXCEDED - If the data length is greater than MTU
+** BNEP_IGNORE_CMD - If the packet is filtered out
+** BNEP_Q_SIZE_EXCEEDED - If the Tx Q is full
+** BNEP_NO_RESOURCES - If not able to allocate a buffer
+** BNEP_SUCCESS - If written successfully
+**
+*******************************************************************************/
+tBNEP_RESULT BNEP_Write (UINT16 handle,
+ UINT8 *p_dest_addr,
+ UINT8 *p_data,
+ UINT16 len,
+ UINT16 protocol,
+ UINT8 *p_src_addr,
+ BOOLEAN fw_ext_present)
+{
+ BT_HDR *p_buf;
+ tBNEP_CONN *p_bcb;
+ UINT8 *p;
+
+ /* Check MTU size. Consider the possibility of having extension headers */
+ if (len > BNEP_MTU_SIZE)
+ {
+ BNEP_TRACE_ERROR2 ("BNEP_Write() length %d exceeded MTU %d", len, BNEP_MTU_SIZE);
+ return (BNEP_MTU_EXCEDED);
+ }
+
+ if ((!handle) || (handle > BNEP_MAX_CONNECTIONS))
+ return (BNEP_WRONG_HANDLE);
+
+ p_bcb = &(bnep_cb.bcb[handle - 1]);
+
+ /* Check if the packet should be filtered out */
+ if (bnep_is_packet_allowed (p_bcb, p_dest_addr, protocol, fw_ext_present, p_data) != BNEP_SUCCESS)
+ {
+ /*
+ ** If packet is filtered and ext headers are present
+ ** drop the data and forward the ext headers
+ */
+ if (fw_ext_present)
+ {
+ UINT8 ext, length;
+ UINT16 org_len, new_len;
+ /* parse the extension headers and findout the new packet len */
+ org_len = len;
+ new_len = 0;
+ p = p_data;
+ do {
+
+ ext = *p_data++;
+ length = *p_data++;
+ p_data += length;
+
+ new_len += (length + 2);
+
+ if (new_len > org_len)
+ return BNEP_IGNORE_CMD;
+
+ } while (ext & 0x80);
+
+ if (protocol != BNEP_802_1_P_PROTOCOL)
+ protocol = 0;
+ else
+ {
+ new_len += 4;
+ p_data[2] = 0;
+ p_data[3] = 0;
+ }
+ len = new_len;
+ p_data = p;
+ }
+ else
+ return BNEP_IGNORE_CMD;
+ }
+
+ /* Check transmit queue */
+ if (p_bcb->xmit_q.count >= BNEP_MAX_XMITQ_DEPTH)
+ return (BNEP_Q_SIZE_EXCEEDED);
+
+ /* Get a buffer to copy teh data into */
+ if ((p_buf = (BT_HDR *)GKI_getpoolbuf (BNEP_POOL_ID)) == NULL)
+ {
+ BNEP_TRACE_ERROR0 ("BNEP_Write() not able to get buffer");
+ return (BNEP_NO_RESOURCES);
+ }
+
+ p_buf->len = len;
+ p_buf->offset = BNEP_MINIMUM_OFFSET;
+ p = (UINT8 *)(p_buf + 1) + BNEP_MINIMUM_OFFSET;
+
+ memcpy (p, p_data, len);
+
+ /* Build the BNEP header */
+ bnepu_build_bnep_hdr (p_bcb, p_buf, protocol, p_src_addr, p_dest_addr, fw_ext_present);
+
+ /* Send the data or queue it up */
+ bnepu_check_send_packet (p_bcb, p_buf);
+
+ return (BNEP_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function BNEP_SetProtocolFilters
+**
+** Description This function sets the protocol filters on peer device
+**
+** Parameters: handle - Handle for the connection
+** num_filters - total number of filter ranges
+** p_start_array - Array of beginings of all protocol ranges
+** p_end_array - Array of ends of all protocol ranges
+**
+** Returns BNEP_WRONG_HANDLE - if the connection handle is not valid
+** BNEP_SET_FILTER_FAIL - if the connection is in wrong state
+** BNEP_TOO_MANY_FILTERS - if too many filters
+** BNEP_SUCCESS - if request sent successfully
+**
+*******************************************************************************/
+tBNEP_RESULT BNEP_SetProtocolFilters (UINT16 handle,
+ UINT16 num_filters,
+ UINT16 *p_start_array,
+ UINT16 *p_end_array)
+{
+#if (defined (BNEP_SUPPORTS_PROT_FILTERS) && BNEP_SUPPORTS_PROT_FILTERS == TRUE)
+ UINT16 xx;
+ tBNEP_CONN *p_bcb;
+
+ if ((!handle) || (handle > BNEP_MAX_CONNECTIONS))
+ return (BNEP_WRONG_HANDLE);
+
+ p_bcb = &(bnep_cb.bcb[handle - 1]);
+
+ /* Check the connection state */
+ if ((p_bcb->con_state != BNEP_STATE_CONNECTED) &&
+ (!(p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED)))
+ return (BNEP_WRONG_STATE);
+
+ /* Validate the parameters */
+ if (num_filters && (!p_start_array || !p_end_array))
+ return (BNEP_SET_FILTER_FAIL);
+
+ if (num_filters > BNEP_MAX_PROT_FILTERS)
+ return (BNEP_TOO_MANY_FILTERS);
+
+ /* Fill the filter values in connnection block */
+ for (xx = 0; xx < num_filters; xx++)
+ {
+ p_bcb->sent_prot_filter_start[xx] = *p_start_array++;
+ p_bcb->sent_prot_filter_end[xx] = *p_end_array++;
+ }
+
+ p_bcb->sent_num_filters = num_filters;
+
+ bnepu_send_peer_our_filters (p_bcb);
+
+ return (BNEP_SUCCESS);
+#else
+ return (BNEP_SET_FILTER_FAIL);
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function BNEP_SetMulticastFilters
+**
+** Description This function sets the filters for multicast addresses for BNEP.
+**
+** Parameters: handle - Handle for the connection
+** num_filters - total number of filter ranges
+** p_start_array - Pointer to sequence of beginings of all
+** multicast address ranges
+** p_end_array - Pointer to sequence of ends of all
+** multicast address ranges
+**
+** Returns BNEP_WRONG_HANDLE - if the connection handle is not valid
+** BNEP_SET_FILTER_FAIL - if the connection is in wrong state
+** BNEP_TOO_MANY_FILTERS - if too many filters
+** BNEP_SUCCESS - if request sent successfully
+**
+*******************************************************************************/
+tBNEP_RESULT BNEP_SetMulticastFilters (UINT16 handle,
+ UINT16 num_filters,
+ UINT8 *p_start_array,
+ UINT8 *p_end_array)
+{
+#if (defined (BNEP_SUPPORTS_MULTI_FILTERS) && BNEP_SUPPORTS_MULTI_FILTERS == TRUE)
+ UINT16 xx;
+ tBNEP_CONN *p_bcb;
+
+ if ((!handle) || (handle > BNEP_MAX_CONNECTIONS))
+ return (BNEP_WRONG_HANDLE);
+
+ p_bcb = &(bnep_cb.bcb[handle - 1]);
+
+ /* Check the connection state */
+ if ((p_bcb->con_state != BNEP_STATE_CONNECTED) &&
+ (!(p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED)))
+ return (BNEP_WRONG_STATE);
+
+ /* Validate the parameters */
+ if (num_filters && (!p_start_array || !p_end_array))
+ return (BNEP_SET_FILTER_FAIL);
+
+ if (num_filters > BNEP_MAX_MULTI_FILTERS)
+ return (BNEP_TOO_MANY_FILTERS);
+
+ /* Fill the multicast filter values in connnection block */
+ for (xx = 0; xx < num_filters; xx++)
+ {
+ memcpy (p_bcb->sent_mcast_filter_start[xx], p_start_array, BD_ADDR_LEN);
+ memcpy (p_bcb->sent_mcast_filter_end[xx], p_end_array, BD_ADDR_LEN);
+
+ p_start_array += BD_ADDR_LEN;
+ p_end_array += BD_ADDR_LEN;
+ }
+
+ p_bcb->sent_mcast_filters = num_filters;
+
+ bnepu_send_peer_our_multi_filters (p_bcb);
+
+ return (BNEP_SUCCESS);
+#else
+ return (BNEP_SET_FILTER_FAIL);
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function BNEP_GetMyBdAddr
+**
+** Description This function returns a pointer to the local device BD address.
+** If the BD address has not been read yet, it returns NULL.
+**
+** Returns the BD address
+**
+*******************************************************************************/
+UINT8 *BNEP_GetMyBdAddr (void)
+{
+ if (bnep_cb.got_my_bd_addr)
+ return (bnep_cb.my_bda);
+ else
+ return (NULL);
+}
+
+/*******************************************************************************
+**
+** Function BNEP_SetTraceLevel
+**
+** Description This function sets the trace level for BNEP. If called with
+** a value of 0xFF, it simply reads the current trace level.
+**
+** Returns the new (current) trace level
+**
+*******************************************************************************/
+UINT8 BNEP_SetTraceLevel (UINT8 new_level)
+{
+ if (new_level != 0xFF)
+ bnep_cb.trace_level = new_level;
+
+ return (bnep_cb.trace_level);
+}
+
+
+/*******************************************************************************
+**
+** Function BNEP_GetStatus
+**
+** Description This function gets the status information for BNEP connection
+**
+** Returns BNEP_SUCCESS - if the status is available
+** BNEP_NO_RESOURCES - if no structure is passed for output
+** BNEP_WRONG_HANDLE - if the handle is invalid
+** BNEP_WRONG_STATE - if not in connected state
+**
+*******************************************************************************/
+tBNEP_RESULT BNEP_GetStatus (UINT16 handle, tBNEP_STATUS *p_status)
+{
+#if (defined (BNEP_SUPPORTS_STATUS_API) && BNEP_SUPPORTS_STATUS_API == TRUE)
+ tBNEP_CONN *p_bcb;
+
+ if (!p_status)
+ return BNEP_NO_RESOURCES;
+
+ if ((!handle) || (handle > BNEP_MAX_CONNECTIONS))
+ return (BNEP_WRONG_HANDLE);
+
+ p_bcb = &(bnep_cb.bcb[handle - 1]);
+
+ memset (p_status, 0, sizeof (tBNEP_STATUS));
+ if ((p_bcb->con_state != BNEP_STATE_CONNECTED) &&
+ (!(p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED)))
+ return BNEP_WRONG_STATE;
+
+ /* Read the status parameters from the connection control block */
+ p_status->con_status = BNEP_STATUS_CONNECTED;
+ p_status->l2cap_cid = p_bcb->l2cap_cid;
+ p_status->rem_mtu_size = p_bcb->rem_mtu_size;
+ p_status->xmit_q_depth = p_bcb->xmit_q.count;
+ p_status->sent_num_filters = p_bcb->sent_num_filters;
+ p_status->sent_mcast_filters = p_bcb->sent_mcast_filters;
+ p_status->rcvd_num_filters = p_bcb->rcvd_num_filters;
+ p_status->rcvd_mcast_filters = p_bcb->rcvd_mcast_filters;
+
+ memcpy (p_status->rem_bda, p_bcb->rem_bda, BD_ADDR_LEN);
+ memcpy (&(p_status->src_uuid), &(p_bcb->src_uuid), sizeof (tBT_UUID));
+ memcpy (&(p_status->dst_uuid), &(p_bcb->dst_uuid), sizeof (tBT_UUID));
+
+ return BNEP_SUCCESS;
+#else
+ return (BNEP_IGNORE_CMD);
+#endif
+}
+
+
diff --git a/stack/bnep/bnep_int.h b/stack/bnep/bnep_int.h
new file mode 100644
index 0000000..a849052
--- /dev/null
+++ b/stack/bnep/bnep_int.h
@@ -0,0 +1,238 @@
+/****************************************************************************/
+/* */
+/* Name: bnep_int.h */
+/* */
+/* Function this file contains internally used BNEP definitions */
+/* */
+/* */
+/* Copyright (c) 2001-2004, WIDCOMM Inc., All Rights Reserved. */
+/* WIDCOMM Bluetooth Core. Proprietary and confidential. */
+/* */
+/****************************************************************************/
+#ifndef BNEP_INT_H
+#define BNEP_INT_H
+
+#include "bt_target.h"
+#include "gki.h"
+#include "bnep_api.h"
+#include "btm_int.h"
+#include "btu.h"
+
+
+/* BNEP frame types
+*/
+#define BNEP_FRAME_GENERAL_ETHERNET 0x00
+#define BNEP_FRAME_CONTROL 0x01
+#define BNEP_FRAME_COMPRESSED_ETHERNET 0x02
+#define BNEP_FRAME_COMPRESSED_ETHERNET_SRC_ONLY 0x03
+#define BNEP_FRAME_COMPRESSED_ETHERNET_DEST_ONLY 0x04
+
+
+/* BNEP filter control message types
+*/
+#define BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD 0x00
+#define BNEP_SETUP_CONNECTION_REQUEST_MSG 0x01
+#define BNEP_SETUP_CONNECTION_RESPONSE_MSG 0x02
+#define BNEP_FILTER_NET_TYPE_SET_MSG 0x03
+#define BNEP_FILTER_NET_TYPE_RESPONSE_MSG 0x04
+#define BNEP_FILTER_MULTI_ADDR_SET_MSG 0x05
+#define BNEP_FILTER_MULTI_ADDR_RESPONSE_MSG 0x06
+
+
+/* BNEP header extension types
+*/
+#define BNEP_EXTENSION_FILTER_CONTROL 0x00
+
+
+/* BNEP Setup Connection response codes
+*/
+#define BNEP_SETUP_CONN_OK 0x0000
+#define BNEP_SETUP_INVALID_DEST_UUID 0x0001
+#define BNEP_SETUP_INVALID_SRC_UUID 0x0002
+#define BNEP_SETUP_INVALID_UUID_SIZE 0x0003
+#define BNEP_SETUP_CONN_NOT_ALLOWED 0x0004
+
+
+/* BNEP filter control response codes
+*/
+#define BNEP_FILTER_CRL_OK 0x0000
+#define BNEP_FILTER_CRL_UNSUPPORTED 0x0001
+#define BNEP_FILTER_CRL_BAD_RANGE 0x0002
+#define BNEP_FILTER_CRL_MAX_REACHED 0x0003
+#define BNEP_FILTER_CRL_SECURITY_ERR 0x0004
+
+
+/* 802.1p protocol packet will have actual protocol field in side the payload */
+#define BNEP_802_1_P_PROTOCOL 0x8100
+
+/* Timeout definitions.
+*/
+#define BNEP_CONN_TIMEOUT 20 /* Connection related timeout */
+#define BNEP_HOST_TIMEOUT 200 /* host responce timeout */
+#define BNEP_FILTER_SET_TIMEOUT 10
+
+/* Define the Out-Flow default values. */
+#define BNEP_OFLOW_QOS_FLAG 0
+#define BNEP_OFLOW_SERV_TYPE 0
+#define BNEP_OFLOW_TOKEN_RATE 0
+#define BNEP_OFLOW_TOKEN_BUCKET_SIZE 0
+#define BNEP_OFLOW_PEAK_BANDWIDTH 0
+#define BNEP_OFLOW_LATENCY 0
+#define BNEP_OFLOW_DELAY_VARIATION 0
+
+/* Define the In-Flow default values. */
+#define BNEP_IFLOW_QOS_FLAG 0
+#define BNEP_IFLOW_SERV_TYPE 0
+#define BNEP_IFLOW_TOKEN_RATE 0
+#define BNEP_IFLOW_TOKEN_BUCKET_SIZE 0
+#define BNEP_IFLOW_PEAK_BANDWIDTH 0
+#define BNEP_IFLOW_LATENCY 0
+#define BNEP_IFLOW_DELAY_VARIATION 0
+
+#define BNEP_FLUSH_TO 0xFFFF
+
+#define BNEP_MAX_RETRANSMITS 3
+
+/* Define the BNEP Connection Control Block
+*/
+typedef struct
+{
+#define BNEP_STATE_IDLE 0
+#define BNEP_STATE_CONN_START 1
+#define BNEP_STATE_CFG_SETUP 2
+#define BNEP_STATE_CONN_SETUP 3
+#define BNEP_STATE_SEC_CHECKING 4
+#define BNEP_STATE_SETUP_RCVD 5
+#define BNEP_STATE_CONNECTED 6
+ UINT8 con_state;
+
+#define BNEP_FLAGS_IS_ORIG 0x01
+#define BNEP_FLAGS_HIS_CFG_DONE 0x02
+#define BNEP_FLAGS_MY_CFG_DONE 0x04
+#define BNEP_FLAGS_L2CAP_CONGESTED 0x08
+#define BNEP_FLAGS_FILTER_RESP_PEND 0x10
+#define BNEP_FLAGS_MULTI_RESP_PEND 0x20
+#define BNEP_FLAGS_SETUP_RCVD 0x40
+#define BNEP_FLAGS_CONN_COMPLETED 0x80
+ UINT8 con_flags;
+ BT_HDR *p_pending_data;
+
+ UINT16 l2cap_cid;
+ BD_ADDR rem_bda;
+ UINT16 rem_mtu_size;
+ TIMER_LIST_ENT conn_tle;
+ BUFFER_Q xmit_q;
+
+ UINT16 sent_num_filters;
+ UINT16 sent_prot_filter_start[BNEP_MAX_PROT_FILTERS];
+ UINT16 sent_prot_filter_end[BNEP_MAX_PROT_FILTERS];
+
+ UINT16 sent_mcast_filters;
+ BD_ADDR sent_mcast_filter_start[BNEP_MAX_MULTI_FILTERS];
+ BD_ADDR sent_mcast_filter_end[BNEP_MAX_MULTI_FILTERS];
+
+ UINT16 rcvd_num_filters;
+ UINT16 rcvd_prot_filter_start[BNEP_MAX_PROT_FILTERS];
+ UINT16 rcvd_prot_filter_end[BNEP_MAX_PROT_FILTERS];
+
+ UINT16 rcvd_mcast_filters;
+ BD_ADDR rcvd_mcast_filter_start[BNEP_MAX_MULTI_FILTERS];
+ BD_ADDR rcvd_mcast_filter_end[BNEP_MAX_MULTI_FILTERS];
+
+ UINT16 bad_pkts_rcvd;
+ UINT8 re_transmits;
+ UINT16 handle;
+ tBT_UUID prv_src_uuid;
+ tBT_UUID prv_dst_uuid;
+ tBT_UUID src_uuid;
+ tBT_UUID dst_uuid;
+
+} tBNEP_CONN;
+
+
+/* The main BNEP control block
+*/
+typedef struct
+{
+ tL2CAP_CFG_INFO l2cap_my_cfg; /* My L2CAP config */
+ tBNEP_CONN bcb[BNEP_MAX_CONNECTIONS];
+
+ tBNEP_CONNECT_IND_CB *p_conn_ind_cb;
+ tBNEP_CONN_STATE_CB *p_conn_state_cb;
+ tBNEP_DATA_IND_CB *p_data_ind_cb;
+ tBNEP_DATA_BUF_CB *p_data_buf_cb;
+ tBNEP_FILTER_IND_CB *p_filter_ind_cb;
+ tBNEP_MFILTER_IND_CB *p_mfilter_ind_cb;
+ tBNEP_TX_DATA_FLOW_CB *p_tx_data_flow_cb;
+
+ tL2CAP_APPL_INFO reg_info;
+
+ TIMER_LIST_ENT bnep_tle;
+ BOOLEAN profile_registered; /* TRUE when we got our BD addr */
+ UINT8 trace_level;
+ BOOLEAN got_my_bd_addr; /* TRUE when we got our BD addr */
+ BD_ADDR my_bda; /* BD Address of this device */
+
+} tBNEP_CB;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Global BNEP data
+*/
+#if BNEP_DYNAMIC_MEMORY == FALSE
+BNEP_API extern tBNEP_CB bnep_cb;
+#else
+BNEP_API extern tBNEP_CB *bnep_cb_ptr;
+#define bnep_cb (*bnep_cb_ptr)
+#endif
+
+/* Functions provided by bnep_main.c
+*/
+extern tBNEP_RESULT bnep_register_with_l2cap (void);
+extern void bnep_disconnect (tBNEP_CONN *p_bcb, UINT16 reason);
+extern tBNEP_CONN *bnep_conn_originate (UINT8 *p_bd_addr);
+extern void bnep_process_timeout (TIMER_LIST_ENT *p_tle);
+extern void bnep_connected (tBNEP_CONN *p_bcb);
+
+
+/* Functions provided by bnep_utils.c
+*/
+extern tBNEP_CONN *bnepu_find_bcb_by_cid (UINT16 cid);
+extern tBNEP_CONN *bnepu_find_bcb_by_bd_addr (UINT8 *p_bda);
+extern tBNEP_CONN *bnepu_allocate_bcb (BD_ADDR p_rem_bda);
+extern void bnepu_release_bcb (tBNEP_CONN *p_bcb);
+extern void bnepu_send_peer_our_filters (tBNEP_CONN *p_bcb);
+extern void bnepu_send_peer_our_multi_filters (tBNEP_CONN *p_bcb);
+extern BOOLEAN bnepu_does_dest_support_prot (tBNEP_CONN *p_bcb, UINT16 protocol);
+extern void bnepu_build_bnep_hdr (tBNEP_CONN *p_bcb, BT_HDR *p_buf, UINT16 protocol,
+ UINT8 *p_src_addr, UINT8 *p_dest_addr, BOOLEAN ext_bit);
+extern void test_bnepu_build_bnep_hdr (tBNEP_CONN *p_bcb, BT_HDR *p_buf, UINT16 protocol,
+ UINT8 *p_src_addr, UINT8 *p_dest_addr, UINT8 type);
+
+extern tBNEP_CONN *bnepu_get_route_to_dest (UINT8 *p_bda);
+extern void bnepu_check_send_packet (tBNEP_CONN *p_bcb, BT_HDR *p_buf);
+extern void bnep_send_command_not_understood (tBNEP_CONN *p_bcb, UINT8 cmd_code);
+extern void bnepu_process_peer_filter_set (tBNEP_CONN *p_bcb, UINT8 *p_filters, UINT16 len);
+extern void bnepu_process_peer_filter_rsp (tBNEP_CONN *p_bcb, UINT8 *p_data);
+extern void bnepu_process_multicast_filter_rsp (tBNEP_CONN *p_bcb, UINT8 *p_data);
+extern void bnep_send_conn_req (tBNEP_CONN *p_bcb);
+extern void bnep_send_conn_responce (tBNEP_CONN *p_bcb, UINT16 resp_code);
+extern void bnep_process_setup_conn_req (tBNEP_CONN *p_bcb, UINT8 *p_setup, UINT8 len);
+extern void bnep_process_setup_conn_responce (tBNEP_CONN *p_bcb, UINT8 *p_setup);
+extern UINT8 *bnep_process_control_packet (tBNEP_CONN *p_bcb, UINT8 *p, UINT16 *len, BOOLEAN is_ext);
+extern void bnep_sec_check_complete (BD_ADDR bd_addr, void *p_ref_data, UINT8 result);
+extern tBNEP_RESULT bnep_is_packet_allowed (tBNEP_CONN *p_bcb, BD_ADDR p_dest_addr, UINT16 protocol, BOOLEAN fw_ext_present, UINT8 *p_data);
+extern UINT32 bnep_get_uuid32 (tBT_UUID *src_uuid);
+extern void bnep_dump_status (void);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+
diff --git a/stack/bnep/bnep_main.c b/stack/bnep/bnep_main.c
new file mode 100644
index 0000000..fca0d22
--- /dev/null
+++ b/stack/bnep/bnep_main.c
@@ -0,0 +1,825 @@
+/*****************************************************************************
+**
+** Name: bnep_main.c
+**
+** Description: this file contains the main BNEP functions
+**
+**
+** Copyright (c) 2001-2008, Broadcom Corp., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+
+#include "bt_target.h"
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "gki.h"
+#include "bt_types.h"
+#include "l2cdefs.h"
+#include "hcidefs.h"
+#include "hcimsgs.h"
+
+#include "l2c_api.h"
+#include "l2cdefs.h"
+
+#include "btu.h"
+#include "btm_api.h"
+
+#include "bnep_api.h"
+#include "bnep_int.h"
+
+
+/********************************************************************************/
+/* G L O B A L B N E P D A T A */
+/********************************************************************************/
+#if BNEP_DYNAMIC_MEMORY == FALSE
+tBNEP_CB bnep_cb;
+#endif
+
+const UINT16 bnep_frame_hdr_sizes[] = {14, 1, 2, 8, 8};
+
+/********************************************************************************/
+/* L O C A L F U N C T I O N P R O T O T Y P E S */
+/********************************************************************************/
+static void bnep_connect_ind (BD_ADDR bd_addr, UINT16 l2cap_cid, UINT16 psm, UINT8 l2cap_id);
+static void bnep_connect_cfm (UINT16 l2cap_cid, UINT16 result);
+static void bnep_config_ind (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg);
+static void bnep_config_cfm (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg);
+static void bnep_disconnect_ind (UINT16 l2cap_cid, BOOLEAN ack_needed);
+static void bnep_disconnect_cfm (UINT16 l2cap_cid, UINT16 result);
+static void bnep_data_ind (UINT16 l2cap_cid, BT_HDR *p_msg);
+static void bnep_congestion_ind (UINT16 lcid, BOOLEAN is_congested);
+
+static void bnep_read_addr_cb (void *p_bda);
+
+
+/*******************************************************************************
+**
+** Function bnep_register_with_l2cap
+**
+** Description This function registers BNEP PSM with L2CAP
+**
+** Returns void
+**
+*******************************************************************************/
+tBNEP_RESULT bnep_register_with_l2cap (void)
+{
+ /* Initialize the L2CAP configuration. We only care about MTU and flush */
+ memset(&bnep_cb.l2cap_my_cfg, 0, sizeof(tL2CAP_CFG_INFO));
+
+ bnep_cb.l2cap_my_cfg.mtu_present = TRUE;
+ bnep_cb.l2cap_my_cfg.mtu = BNEP_MTU_SIZE;
+ bnep_cb.l2cap_my_cfg.flush_to_present = TRUE;
+ bnep_cb.l2cap_my_cfg.flush_to = BNEP_FLUSH_TO;
+
+ bnep_cb.reg_info.pL2CA_ConnectInd_Cb = bnep_connect_ind;
+ bnep_cb.reg_info.pL2CA_ConnectCfm_Cb = bnep_connect_cfm;
+ bnep_cb.reg_info.pL2CA_ConfigInd_Cb = bnep_config_ind;
+ bnep_cb.reg_info.pL2CA_ConfigCfm_Cb = bnep_config_cfm;
+ bnep_cb.reg_info.pL2CA_DisconnectInd_Cb = bnep_disconnect_ind;
+ bnep_cb.reg_info.pL2CA_DisconnectCfm_Cb = bnep_disconnect_cfm;
+ bnep_cb.reg_info.pL2CA_DataInd_Cb = bnep_data_ind;
+ bnep_cb.reg_info.pL2CA_CongestionStatus_Cb = bnep_congestion_ind;
+
+ /* Now, register with L2CAP */
+ if (!L2CA_Register (BT_PSM_BNEP, &bnep_cb.reg_info))
+ {
+ BNEP_TRACE_ERROR0 ("BNEP - Registration failed");
+ return BNEP_SECURITY_FAIL;
+ }
+
+ return BNEP_SUCCESS;
+}
+
+
+/*******************************************************************************
+**
+** Function bnep_connect_ind
+**
+** Description This function handles an inbound connection indication
+** from L2CAP. This is the case where we are acting as a
+** server.
+**
+** Returns void
+**
+*******************************************************************************/
+static void bnep_connect_ind (BD_ADDR bd_addr, UINT16 l2cap_cid, UINT16 psm, UINT8 l2cap_id)
+{
+ tBNEP_CONN *p_bcb = bnepu_find_bcb_by_bd_addr (bd_addr);
+
+ /* If we are not acting as server, or already have a connection, or have */
+ /* no more resources to handle the connection, reject the connection. */
+ if (!(bnep_cb.profile_registered) || (p_bcb)
+ || ((p_bcb = bnepu_allocate_bcb(bd_addr)) == NULL))
+ {
+ L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_NO_PSM, 0);
+ return;
+ }
+
+ /* Transition to the next appropriate state, waiting for config setup. */
+ p_bcb->con_state = BNEP_STATE_CFG_SETUP;
+
+ /* Save the L2CAP Channel ID. */
+ p_bcb->l2cap_cid = l2cap_cid;
+
+ /* Send response to the L2CAP layer. */
+ L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_OK, L2CAP_CONN_OK);
+
+ /* Send a Configuration Request. */
+ L2CA_ConfigReq (l2cap_cid, &bnep_cb.l2cap_my_cfg);
+
+ /* Start timer waiting for config setup */
+ btu_start_timer (&p_bcb->conn_tle, BTU_TTYPE_BNEP, BNEP_CONN_TIMEOUT);
+
+ BNEP_TRACE_EVENT1("BNEP - Rcvd L2CAP conn ind, CID: 0x%x", p_bcb->l2cap_cid);
+
+}
+
+
+/*******************************************************************************
+**
+** Function bnep_connect_cfm
+**
+** Description This function handles the connect confirm events
+** from L2CAP. This is the case when we are acting as a
+** client and have sent a connect request.
+**
+** Returns void
+**
+*******************************************************************************/
+static void bnep_connect_cfm (UINT16 l2cap_cid, UINT16 result)
+{
+ tBNEP_CONN *bcb;
+
+ /* Find CCB based on CID */
+ if ((bcb = bnepu_find_bcb_by_cid (l2cap_cid)) == NULL)
+ {
+ BNEP_TRACE_WARNING1 ("BNEP - Rcvd conn cnf for unknown CID 0x%x", l2cap_cid);
+ return;
+ }
+
+ /* If the connection response contains success status, then */
+ /* Transition to the next state and startup the timer. */
+ if ((result == L2CAP_CONN_OK) && (bcb->con_state == BNEP_STATE_CONN_START))
+ {
+ bcb->con_state = BNEP_STATE_CFG_SETUP;
+
+ /* Send a Configuration Request. */
+ L2CA_ConfigReq (l2cap_cid, &bnep_cb.l2cap_my_cfg);
+
+ /* Start timer waiting for config results */
+ btu_start_timer (&bcb->conn_tle, BTU_TTYPE_BNEP, BNEP_CONN_TIMEOUT);
+
+ BNEP_TRACE_EVENT1 ("BNEP - got conn cnf, sent cfg req, CID: 0x%x", bcb->l2cap_cid);
+ }
+ else
+ {
+ BNEP_TRACE_WARNING2 ("BNEP - Rcvd conn cnf with error: 0x%x CID 0x%x", result, bcb->l2cap_cid);
+
+ /* Tell the upper layer, if he has a callback */
+ if (bnep_cb.p_conn_state_cb &&
+ bcb->con_flags & BNEP_FLAGS_IS_ORIG)
+ {
+ (*bnep_cb.p_conn_state_cb) (bcb->handle, bcb->rem_bda, BNEP_CONN_FAILED, FALSE);
+ }
+
+ bnepu_release_bcb (bcb);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bnep_config_ind
+**
+** Description This function processes the L2CAP configuration indication
+** event.
+**
+** Returns void
+**
+*******************************************************************************/
+static void bnep_config_ind (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg)
+{
+ tBNEP_CONN *p_bcb;
+ UINT16 result, mtu = 0;
+
+ /* Find CCB based on CID */
+ if ((p_bcb = bnepu_find_bcb_by_cid (l2cap_cid)) == NULL)
+ {
+ BNEP_TRACE_WARNING1 ("BNEP - Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid);
+ return;
+ }
+
+ BNEP_TRACE_EVENT1 ("BNEP - Rcvd cfg ind, CID: 0x%x", l2cap_cid);
+
+ /* Remember the remote MTU size */
+ if ((!p_cfg->mtu_present) || (p_cfg->mtu < BNEP_MIN_MTU_SIZE))
+ {
+ mtu = p_cfg->mtu;
+ p_cfg->flush_to_present = FALSE;
+ p_cfg->mtu_present = TRUE;
+ p_cfg->mtu = BNEP_MIN_MTU_SIZE;
+ p_cfg->result = result = L2CAP_CFG_UNACCEPTABLE_PARAMS;
+ }
+ else
+ {
+ if (p_cfg->mtu > BNEP_MTU_SIZE)
+ p_bcb->rem_mtu_size = BNEP_MTU_SIZE;
+ else
+ p_bcb->rem_mtu_size = p_cfg->mtu;
+
+ /* For now, always accept configuration from the other side */
+ p_cfg->flush_to_present = FALSE;
+ p_cfg->mtu_present = FALSE;
+ p_cfg->result = result = L2CAP_CFG_OK;
+ }
+
+ L2CA_ConfigRsp (l2cap_cid, p_cfg);
+
+ if (result != L2CAP_CFG_OK)
+ {
+ BNEP_TRACE_EVENT2 ("BNEP - Rcvd cfg ind with bad MTU %d, CID: 0x%x", mtu, l2cap_cid);
+ return;
+ }
+
+ p_bcb->con_flags |= BNEP_FLAGS_HIS_CFG_DONE;
+
+ if (p_bcb->con_flags & BNEP_FLAGS_MY_CFG_DONE)
+ {
+ p_bcb->con_state = BNEP_STATE_SEC_CHECKING;
+
+ /* Start timer waiting for setup or response */
+ btu_start_timer (&p_bcb->conn_tle, BTU_TTYPE_BNEP, BNEP_HOST_TIMEOUT);
+
+ if (p_bcb->con_flags & BNEP_FLAGS_IS_ORIG)
+ {
+ btm_sec_mx_access_request (p_bcb->rem_bda, BT_PSM_BNEP, TRUE,
+ BTM_SEC_PROTO_BNEP,
+ bnep_get_uuid32(&(p_bcb->src_uuid)),
+ &bnep_sec_check_complete, p_bcb);
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function bnep_config_cfm
+**
+** Description This function processes the L2CAP configuration confirmation
+** event.
+**
+** Returns void
+**
+*******************************************************************************/
+static void bnep_config_cfm (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg)
+{
+ tBNEP_CONN *p_bcb;
+
+ BNEP_TRACE_EVENT2 ("BNEP - Rcvd cfg cfm, CID: 0x%x Result: %d", l2cap_cid, p_cfg->result);
+
+ /* Find CCB based on CID */
+ if ((p_bcb = bnepu_find_bcb_by_cid (l2cap_cid)) == NULL)
+ {
+ BNEP_TRACE_WARNING1 ("BNEP - Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid);
+ return;
+ }
+
+ /* For now, always accept configuration from the other side */
+ if (p_cfg->result == L2CAP_CFG_OK)
+ {
+ p_bcb->con_flags |= BNEP_FLAGS_MY_CFG_DONE;
+
+ if (p_bcb->con_flags & BNEP_FLAGS_HIS_CFG_DONE)
+ {
+ p_bcb->con_state = BNEP_STATE_SEC_CHECKING;
+
+ /* Start timer waiting for setup or response */
+ btu_start_timer (&p_bcb->conn_tle, BTU_TTYPE_BNEP, BNEP_HOST_TIMEOUT);
+
+ if (p_bcb->con_flags & BNEP_FLAGS_IS_ORIG)
+ {
+ btm_sec_mx_access_request (p_bcb->rem_bda, BT_PSM_BNEP, TRUE,
+ BTM_SEC_PROTO_BNEP,
+ bnep_get_uuid32(&(p_bcb->src_uuid)),
+ &bnep_sec_check_complete, p_bcb);
+ }
+ }
+ }
+ else
+ {
+ /* Tell the upper layer, if he has a callback */
+ if ((p_bcb->con_flags & BNEP_FLAGS_IS_ORIG) && (bnep_cb.p_conn_state_cb))
+ {
+ (*bnep_cb.p_conn_state_cb) (p_bcb->handle, p_bcb->rem_bda, BNEP_CONN_FAILED_CFG, FALSE);
+ }
+
+ L2CA_DisconnectReq (p_bcb->l2cap_cid);
+
+ bnepu_release_bcb (p_bcb);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function bnep_disconnect_ind
+**
+** Description This function handles a disconnect event from L2CAP. If
+** requested to, we ack the disconnect before dropping the CCB
+**
+** Returns void
+**
+*******************************************************************************/
+static void bnep_disconnect_ind (UINT16 l2cap_cid, BOOLEAN ack_needed)
+{
+ tBNEP_CONN *p_bcb;
+
+ if (ack_needed)
+ L2CA_DisconnectRsp (l2cap_cid);
+
+ /* Find CCB based on CID */
+ if ((p_bcb = bnepu_find_bcb_by_cid (l2cap_cid)) == NULL)
+ {
+ BNEP_TRACE_WARNING1 ("BNEP - Rcvd L2CAP disc, unknown CID: 0x%x", l2cap_cid);
+ return;
+ }
+
+ BNEP_TRACE_EVENT1 ("BNEP - Rcvd L2CAP disc, CID: 0x%x", l2cap_cid);
+
+ /* Tell the user if he has a callback */
+ if (p_bcb->con_state == BNEP_STATE_CONNECTED)
+ {
+ if (bnep_cb.p_conn_state_cb)
+ (*bnep_cb.p_conn_state_cb)(p_bcb->handle, p_bcb->rem_bda, BNEP_CONN_DISCONNECTED, FALSE);
+ }
+ else
+ {
+ if (((p_bcb->con_flags & BNEP_FLAGS_IS_ORIG) && (bnep_cb.p_conn_state_cb)) ||
+ p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED)
+ (*bnep_cb.p_conn_state_cb) (p_bcb->handle, p_bcb->rem_bda, BNEP_CONN_FAILED, FALSE);
+ }
+
+ bnepu_release_bcb (p_bcb);
+}
+
+
+
+/*******************************************************************************
+**
+** Function bnep_disconnect_cfm
+**
+** Description This function gets the disconnect confirm event from L2CAP
+**
+** Returns void
+**
+*******************************************************************************/
+static void bnep_disconnect_cfm (UINT16 l2cap_cid, UINT16 result)
+{
+ BNEP_TRACE_EVENT2 ("BNEP - Rcvd L2CAP disc cfm, CID: 0x%x, Result 0x%x", l2cap_cid, result);
+}
+
+
+
+/*******************************************************************************
+**
+** Function bnep_congestion_ind
+**
+** Description This is a callback function called by L2CAP when
+** congestion status changes
+**
+*******************************************************************************/
+static void bnep_congestion_ind (UINT16 l2cap_cid, BOOLEAN is_congested)
+{
+ tBNEP_CONN *p_bcb;
+
+ /* Find BCB based on CID */
+ if ((p_bcb = bnepu_find_bcb_by_cid (l2cap_cid)) == NULL)
+ {
+ BNEP_TRACE_WARNING1 ("BNEP - Rcvd L2CAP cong, unknown CID: 0x%x", l2cap_cid);
+ return;
+ }
+
+ if (is_congested)
+ {
+ p_bcb->con_flags |= BNEP_FLAGS_L2CAP_CONGESTED;
+ if(bnep_cb.p_tx_data_flow_cb)
+ {
+ bnep_cb.p_tx_data_flow_cb(p_bcb->handle, BNEP_TX_FLOW_OFF);
+ }
+ }
+ else
+ {
+ p_bcb->con_flags &= ~BNEP_FLAGS_L2CAP_CONGESTED;
+
+ if(bnep_cb.p_tx_data_flow_cb)
+ {
+ bnep_cb.p_tx_data_flow_cb(p_bcb->handle, BNEP_TX_FLOW_ON);
+ }
+
+ /* While not congested, send as many buffers as we can */
+ while (!(p_bcb->con_flags & BNEP_FLAGS_L2CAP_CONGESTED))
+ {
+ BT_HDR *p_buf = (BT_HDR *)GKI_dequeue (&p_bcb->xmit_q);
+
+ if (!p_buf)
+ break;
+
+ L2CA_DataWrite (l2cap_cid, p_buf);
+ }
+ }
+}
+
+
+
+/*******************************************************************************
+**
+** Function bnep_data_ind
+**
+** Description This function is called when data is received from L2CAP.
+** if we are the originator of the connection, we are the SDP
+** client, and the received message is queued up for the client.
+**
+** If we are the destination of the connection, we are the SDP
+** server, so the message is passed to the server processing
+** function.
+**
+** Returns void
+**
+*******************************************************************************/
+static void bnep_data_ind (UINT16 l2cap_cid, BT_HDR *p_buf)
+{
+ tBNEP_CONN *p_bcb;
+ UINT8 *p = (UINT8 *)(p_buf + 1) + p_buf->offset;
+ UINT16 rem_len = p_buf->len;
+ UINT8 type, ctrl_type, ext_type = 0;
+ BOOLEAN extension_present, fw_ext_present;
+ UINT16 protocol = 0;
+ UINT8 *p_src_addr, *p_dst_addr;
+
+
+ /* Find CCB based on CID */
+ if ((p_bcb = bnepu_find_bcb_by_cid (l2cap_cid)) == NULL)
+ {
+ BNEP_TRACE_WARNING1 ("BNEP - Rcvd L2CAP data, unknown CID: 0x%x", l2cap_cid);
+ GKI_freebuf (p_buf);
+ return;
+ }
+
+ /* Get the type and extension bits */
+ type = *p++;
+ extension_present = type >> 7;
+ type &= 0x7f;
+ if ((rem_len <= bnep_frame_hdr_sizes[type]) || (rem_len > BNEP_MTU_SIZE))
+ {
+ BNEP_TRACE_EVENT2 ("BNEP - rcvd frame, bad len: %d type: 0x%02x", p_buf->len, type);
+ GKI_freebuf (p_buf);
+ return;
+ }
+
+ rem_len--;
+
+ if ((p_bcb->con_state != BNEP_STATE_CONNECTED) &&
+ (!(p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED)) &&
+ (type != BNEP_FRAME_CONTROL))
+ {
+ BNEP_TRACE_WARNING2 ("BNEP - Ignored L2CAP data while in state: %d, CID: 0x%x",
+ p_bcb->con_state, l2cap_cid);
+
+ if (extension_present)
+ {
+ /*
+ ** When there is no connection if a data packet is received
+ ** with unknown control extension headers then those should be processed
+ ** according to complain/ignore law
+ */
+ UINT8 ext, length, *p_data;
+ UINT16 org_len, new_len;
+ /* parse the extension headers and process unknown control headers */
+ org_len = rem_len;
+ new_len = 0;
+ p_data = p;
+ do {
+
+ ext = *p++;
+ length = *p++;
+ p += length;
+
+ if ((!(ext & 0x7F)) && (*p > BNEP_FILTER_MULTI_ADDR_RESPONSE_MSG))
+ bnep_send_command_not_understood (p_bcb, *p);
+
+ new_len += (length + 2);
+
+ if (new_len > org_len)
+ break;
+
+ } while (ext & 0x80);
+ }
+
+ GKI_freebuf (p_buf);
+ return;
+ }
+
+ if (type > BNEP_FRAME_COMPRESSED_ETHERNET_DEST_ONLY)
+ {
+ BNEP_TRACE_EVENT1 ("BNEP - rcvd frame, unknown type: 0x%02x", type);
+ GKI_freebuf (p_buf);
+ return;
+ }
+
+ BNEP_TRACE_DEBUG3 ("BNEP - rcv frame, type: %d len: %d Ext: %d", type, p_buf->len, extension_present);
+
+ /* Initialize addresses to 'not supplied' */
+ p_src_addr = p_dst_addr = NULL;
+
+ switch (type)
+ {
+ case BNEP_FRAME_GENERAL_ETHERNET:
+ p_dst_addr = p;
+ p += BD_ADDR_LEN;
+ p_src_addr = p;
+ p += BD_ADDR_LEN;
+ BE_STREAM_TO_UINT16 (protocol, p);
+ rem_len -= 14;
+ break;
+
+ case BNEP_FRAME_CONTROL:
+ ctrl_type = *p;
+ p = bnep_process_control_packet (p_bcb, p, &rem_len, FALSE);
+
+ if (ctrl_type == BNEP_SETUP_CONNECTION_REQUEST_MSG &&
+ p_bcb->con_state != BNEP_STATE_CONNECTED &&
+ extension_present && p && rem_len)
+ {
+ p_bcb->p_pending_data = (BT_HDR *)GKI_getbuf (rem_len);
+ if (p_bcb->p_pending_data)
+ {
+ memcpy ((UINT8 *)(p_bcb->p_pending_data + 1), p, rem_len);
+ p_bcb->p_pending_data->len = rem_len;
+ p_bcb->p_pending_data->offset = 0;
+ }
+ }
+ else
+ {
+ while (extension_present && p && rem_len)
+ {
+ ext_type = *p++;
+ extension_present = ext_type >> 7;
+ ext_type &= 0x7F;
+
+ /* if unknown extension present stop processing */
+ if (ext_type)
+ break;
+
+ p = bnep_process_control_packet (p_bcb, p, &rem_len, TRUE);
+ }
+ }
+ GKI_freebuf (p_buf);
+ return;
+
+ case BNEP_FRAME_COMPRESSED_ETHERNET:
+ BE_STREAM_TO_UINT16 (protocol, p);
+ rem_len -= 2;
+ break;
+
+ case BNEP_FRAME_COMPRESSED_ETHERNET_SRC_ONLY:
+ p_src_addr = p;
+ p += BD_ADDR_LEN;
+ BE_STREAM_TO_UINT16 (protocol, p);
+ rem_len -= 8;
+ break;
+
+ case BNEP_FRAME_COMPRESSED_ETHERNET_DEST_ONLY:
+ p_dst_addr = p;
+ p += BD_ADDR_LEN;
+ BE_STREAM_TO_UINT16 (protocol, p);
+ rem_len -= 8;
+ break;
+ }
+
+ /* Process the header extension if there is one */
+ while (extension_present && p && rem_len)
+ {
+ ext_type = *p;
+ extension_present = ext_type >> 7;
+ ext_type &= 0x7F;
+
+ /* if unknown extension present stop processing */
+ if (ext_type)
+ {
+ BNEP_TRACE_EVENT1 ("Data extension type 0x%x found", ext_type);
+ break;
+ }
+
+ p++;
+ rem_len--;
+ p = bnep_process_control_packet (p_bcb, p, &rem_len, TRUE);
+ }
+
+ p_buf->offset += p_buf->len - rem_len;
+ p_buf->len = rem_len;
+
+ /* Always give the upper layer MAC addresses */
+ if (!p_src_addr)
+ p_src_addr = (UINT8 *) p_bcb->rem_bda;
+
+ if (!p_dst_addr)
+ p_dst_addr = (UINT8 *) bnep_cb.my_bda;
+
+ /* check whether there are any extensions to be forwarded */
+ if (ext_type)
+ fw_ext_present = TRUE;
+ else
+ fw_ext_present = FALSE;
+
+ if (bnep_cb.p_data_buf_cb)
+ {
+ (*bnep_cb.p_data_buf_cb)(p_bcb->handle, p_src_addr, p_dst_addr, protocol, p_buf, fw_ext_present);
+ }
+ else if (bnep_cb.p_data_ind_cb)
+ {
+ (*bnep_cb.p_data_ind_cb)(p_bcb->handle, p_src_addr, p_dst_addr, protocol, p, rem_len, fw_ext_present);
+ GKI_freebuf (p_buf);
+ }
+}
+
+
+
+/*******************************************************************************
+**
+** Function bnep_process_timeout
+**
+** Description This function processes a timeout. If it is a startup
+** timeout, we check for reading our BD address. If it
+** is an L2CAP timeout, we send a disconnect req to L2CAP.
+**
+** Returns void
+**
+*******************************************************************************/
+void bnep_process_timeout (TIMER_LIST_ENT *p_tle)
+{
+ tBNEP_CONN *p_bcb;
+
+ if (!p_tle->param)
+ {
+ if (!bnep_cb.got_my_bd_addr)
+ {
+ if (BTM_IsDeviceUp())
+ BTM_ReadLocalDeviceAddr (bnep_read_addr_cb);
+
+ btu_start_timer (&bnep_cb.bnep_tle, BTU_TTYPE_BNEP, 2);
+ }
+ return;
+ }
+
+ p_bcb = (tBNEP_CONN *)p_tle->param;
+
+ BNEP_TRACE_EVENT4 ("BNEP - CCB timeout in state: %d CID: 0x%x flags %x, re_transmit %d",
+ p_bcb->con_state, p_bcb->l2cap_cid, p_bcb->con_flags, p_bcb->re_transmits);
+
+ if (p_bcb->con_state == BNEP_STATE_CONN_SETUP)
+ {
+ BNEP_TRACE_EVENT2 ("BNEP - CCB timeout in state: %d CID: 0x%x",
+ p_bcb->con_state, p_bcb->l2cap_cid);
+
+ if (!(p_bcb->con_flags & BNEP_FLAGS_IS_ORIG))
+ {
+ L2CA_DisconnectReq (p_bcb->l2cap_cid);
+
+ bnepu_release_bcb (p_bcb);
+ return;
+ }
+
+ if (p_bcb->re_transmits++ != BNEP_MAX_RETRANSMITS)
+ {
+ bnep_send_conn_req (p_bcb);
+ btu_start_timer (&p_bcb->conn_tle, BTU_TTYPE_BNEP, BNEP_CONN_TIMEOUT);
+ }
+ else
+ {
+ L2CA_DisconnectReq (p_bcb->l2cap_cid);
+
+ if ((p_bcb->con_flags & BNEP_FLAGS_IS_ORIG) && (bnep_cb.p_conn_state_cb))
+ (*bnep_cb.p_conn_state_cb) (p_bcb->handle, p_bcb->rem_bda, BNEP_CONN_FAILED, FALSE);
+
+ bnepu_release_bcb (p_bcb);
+ return;
+ }
+ }
+ else if (p_bcb->con_state != BNEP_STATE_CONNECTED)
+ {
+ BNEP_TRACE_EVENT2 ("BNEP - CCB timeout in state: %d CID: 0x%x",
+ p_bcb->con_state, p_bcb->l2cap_cid);
+
+ L2CA_DisconnectReq (p_bcb->l2cap_cid);
+
+ /* Tell the user if he has a callback */
+ if ((p_bcb->con_flags & BNEP_FLAGS_IS_ORIG) && (bnep_cb.p_conn_state_cb))
+ (*bnep_cb.p_conn_state_cb) (p_bcb->handle, p_bcb->rem_bda, BNEP_CONN_FAILED, FALSE);
+
+ bnepu_release_bcb (p_bcb);
+ }
+#if (defined (BNEP_SUPPORTS_PROT_FILTERS) && BNEP_SUPPORTS_PROT_FILTERS == TRUE)
+ else if (p_bcb->con_flags & BNEP_FLAGS_FILTER_RESP_PEND)
+ {
+ if (p_bcb->re_transmits++ != BNEP_MAX_RETRANSMITS)
+ {
+ bnepu_send_peer_our_filters (p_bcb);
+ btu_start_timer (&p_bcb->conn_tle, BTU_TTYPE_BNEP, BNEP_FILTER_SET_TIMEOUT);
+ }
+ else
+ {
+ L2CA_DisconnectReq (p_bcb->l2cap_cid);
+
+ /* Tell the user if he has a callback */
+ if (bnep_cb.p_conn_state_cb)
+ (*bnep_cb.p_conn_state_cb) (p_bcb->handle, p_bcb->rem_bda, BNEP_SET_FILTER_FAIL, FALSE);
+
+ bnepu_release_bcb (p_bcb);
+ return;
+ }
+ }
+#endif
+#if (defined (BNEP_SUPPORTS_MULTI_FILTERS) && BNEP_SUPPORTS_MULTI_FILTERS == TRUE)
+ else if (p_bcb->con_flags & BNEP_FLAGS_MULTI_RESP_PEND)
+ {
+ if (p_bcb->re_transmits++ != BNEP_MAX_RETRANSMITS)
+ {
+ bnepu_send_peer_our_multi_filters (p_bcb);
+ btu_start_timer (&p_bcb->conn_tle, BTU_TTYPE_BNEP, BNEP_FILTER_SET_TIMEOUT);
+ }
+ else
+ {
+ L2CA_DisconnectReq (p_bcb->l2cap_cid);
+
+ /* Tell the user if he has a callback */
+ if (bnep_cb.p_conn_state_cb)
+ (*bnep_cb.p_conn_state_cb) (p_bcb->handle, p_bcb->rem_bda, BNEP_SET_FILTER_FAIL, FALSE);
+
+ bnepu_release_bcb (p_bcb);
+ return;
+ }
+ }
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function bnep_connected
+**
+** Description This function is called when a connection is established
+** (after config).
+**
+** Returns void
+**
+*******************************************************************************/
+void bnep_connected (tBNEP_CONN *p_bcb)
+{
+ BOOLEAN is_role_change;
+
+ if (p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED)
+ is_role_change = TRUE;
+ else
+ is_role_change = FALSE;
+
+ p_bcb->con_state = BNEP_STATE_CONNECTED;
+ p_bcb->con_flags |= BNEP_FLAGS_CONN_COMPLETED;
+ p_bcb->con_flags &= (~BNEP_FLAGS_SETUP_RCVD);
+
+ /* Ensure timer is stopped */
+ btu_stop_timer (&p_bcb->conn_tle);
+ p_bcb->re_transmits = 0;
+
+ /* Tell the upper layer, if he has a callback */
+ if (bnep_cb.p_conn_state_cb)
+ (*bnep_cb.p_conn_state_cb) (p_bcb->handle, p_bcb->rem_bda, BNEP_SUCCESS, is_role_change);
+}
+
+
+/*******************************************************************************
+**
+** Function bnep_read_addr_cb
+**
+** Description This function is called by BTM when the local BD address
+** is read. It saves the BD address, and flags it as read.
+**
+** Returns void
+**
+*******************************************************************************/
+static void bnep_read_addr_cb (void *p_bda)
+{
+ UINT8 *bda = (UINT8 *)p_bda;
+ if (p_bda &&
+ (bda[0] | bda[1] | bda[2] | bda[3] | bda[4] | bda[5]) != 0)
+ {
+ /* Save my BD address */
+ memcpy (bnep_cb.my_bda, p_bda, BD_ADDR_LEN);
+
+ bnep_cb.got_my_bd_addr = TRUE;
+ }
+ else
+ /* Retry after a couple seconds */
+ btu_start_timer (&bnep_cb.bnep_tle, BTU_TTYPE_BNEP, 2);
+}
+
diff --git a/stack/bnep/bnep_utils.c b/stack/bnep/bnep_utils.c
new file mode 100644
index 0000000..22c2730
--- /dev/null
+++ b/stack/bnep/bnep_utils.c
@@ -0,0 +1,1449 @@
+/*****************************************************************************/
+/* */
+/* Name: bnep_utils.c */
+/* */
+/* Description: this file contains BNEP utility functions */
+/* */
+/* */
+/* Copyright (c) 2001-2004, WIDCOMM Inc., All Rights Reserved. */
+/* WIDCOMM Bluetooth Core. Proprietary and confidential. */
+/*****************************************************************************/
+#include <stdio.h>
+#include <string.h>
+#include "gki.h"
+#include "bt_types.h"
+#include "bnep_int.h"
+#include "btu.h"
+#include "btm_int.h"
+
+
+/********************************************************************************/
+/* L O C A L F U N C T I O N P R O T O T Y P E S */
+/********************************************************************************/
+static UINT8 *bnepu_init_hdr (BT_HDR *p_buf, UINT16 hdr_len, UINT8 pkt_type);
+
+void bnepu_process_peer_multicast_filter_set (tBNEP_CONN *p_bcb, UINT8 *p_filters, UINT16 len);
+void bnepu_send_peer_multicast_filter_rsp (tBNEP_CONN *p_bcb, UINT16 response_code);
+
+
+/*******************************************************************************
+**
+** Function bnepu_find_bcb_by_cid
+**
+** Description This function searches the bcb table for an entry with the
+** passed CID.
+**
+** Returns the BCB address, or NULL if not found.
+**
+*******************************************************************************/
+tBNEP_CONN *bnepu_find_bcb_by_cid (UINT16 cid)
+{
+ UINT16 xx;
+ tBNEP_CONN *p_bcb;
+
+ /* Look through each connection control block */
+ for (xx = 0, p_bcb = bnep_cb.bcb; xx < BNEP_MAX_CONNECTIONS; xx++, p_bcb++)
+ {
+ if ((p_bcb->con_state != BNEP_STATE_IDLE) && (p_bcb->l2cap_cid == cid))
+ return (p_bcb);
+ }
+
+ /* If here, not found */
+ return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function bnepu_find_bcb_by_bd_addr
+**
+** Description This function searches the BCB table for an entry with the
+** passed Bluetooth Address.
+**
+** Returns the BCB address, or NULL if not found.
+**
+*******************************************************************************/
+tBNEP_CONN *bnepu_find_bcb_by_bd_addr (UINT8 *p_bda)
+{
+ UINT16 xx;
+ tBNEP_CONN *p_bcb;
+
+ /* Look through each connection control block */
+ for (xx = 0, p_bcb = bnep_cb.bcb; xx < BNEP_MAX_CONNECTIONS; xx++, p_bcb++)
+ {
+ if (p_bcb->con_state != BNEP_STATE_IDLE)
+ {
+ if (!memcmp ((UINT8 *)(p_bcb->rem_bda), p_bda, BD_ADDR_LEN))
+ return (p_bcb);
+ }
+ }
+
+ /* If here, not found */
+ return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function bnepu_allocate_bcb
+**
+** Description This function allocates a new BCB.
+**
+** Returns BCB address, or NULL if none available.
+**
+*******************************************************************************/
+tBNEP_CONN *bnepu_allocate_bcb (BD_ADDR p_rem_bda)
+{
+ UINT16 xx;
+ tBNEP_CONN *p_bcb;
+
+ /* Look through each connection control block for a free one */
+ for (xx = 0, p_bcb = bnep_cb.bcb; xx < BNEP_MAX_CONNECTIONS; xx++, p_bcb++)
+ {
+ if (p_bcb->con_state == BNEP_STATE_IDLE)
+ {
+ memset ((UINT8 *)p_bcb, 0, sizeof (tBNEP_CONN));
+
+ p_bcb->conn_tle.param = (UINT32) p_bcb;
+
+ memcpy ((UINT8 *)(p_bcb->rem_bda), (UINT8 *)p_rem_bda, BD_ADDR_LEN);
+ p_bcb->handle = xx + 1;
+
+ return (p_bcb);
+ }
+ }
+
+ /* If here, no free BCB found */
+ return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function bnepu_release_bcb
+**
+** Description This function releases a BCB.
+**
+** Returns void
+**
+*******************************************************************************/
+void bnepu_release_bcb (tBNEP_CONN *p_bcb)
+{
+ /* Ensure timer is stopped */
+ btu_stop_timer (&p_bcb->conn_tle);
+
+ /* Drop any response pointer we may be holding */
+ p_bcb->con_state = BNEP_STATE_IDLE;
+ p_bcb->p_pending_data = NULL;
+
+ /* Free transmit queue */
+ while (p_bcb->xmit_q.count)
+ {
+ GKI_freebuf (GKI_dequeue (&p_bcb->xmit_q));
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function bnep_send_conn_req
+**
+** Description This function sends a BNEP connection request to peer
+**
+** Returns void
+**
+*******************************************************************************/
+void bnep_send_conn_req (tBNEP_CONN *p_bcb)
+{
+ BT_HDR *p_buf;
+ UINT8 *p, *p_start;
+
+ BNEP_TRACE_DEBUG1 ("BNEP sending setup req with dst uuid %x", p_bcb->dst_uuid.uu.uuid16);
+ if ((p_buf = (BT_HDR *)GKI_getpoolbuf (BNEP_POOL_ID)) == NULL)
+ {
+ BNEP_TRACE_ERROR0 ("BNEP - not able to send connection request");
+ return;
+ }
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p = p_start = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ /* Put in BNEP frame type - filter control */
+ UINT8_TO_BE_STREAM (p, BNEP_FRAME_CONTROL);
+
+ /* Put in filter message type - set filters */
+ UINT8_TO_BE_STREAM (p, BNEP_SETUP_CONNECTION_REQUEST_MSG);
+
+ UINT8_TO_BE_STREAM (p, p_bcb->dst_uuid.len);
+
+ if (p_bcb->dst_uuid.len == 2)
+ {
+ UINT16_TO_BE_STREAM (p, p_bcb->dst_uuid.uu.uuid16);
+ UINT16_TO_BE_STREAM (p, p_bcb->src_uuid.uu.uuid16);
+ }
+#if (defined (BNEP_SUPPORTS_ALL_UUID_LENGTHS) && BNEP_SUPPORTS_ALL_UUID_LENGTHS == TRUE)
+ else if (p_bcb->dst_uuid.len == 4)
+ {
+ UINT32_TO_BE_STREAM (p, p_bcb->dst_uuid.uu.uuid32);
+ UINT32_TO_BE_STREAM (p, p_bcb->src_uuid.uu.uuid32);
+ }
+ else
+ {
+ memcpy (p, p_bcb->dst_uuid.uu.uuid128, p_bcb->dst_uuid.len);
+ p += p_bcb->dst_uuid.len;
+ memcpy (p, p_bcb->src_uuid.uu.uuid128, p_bcb->dst_uuid.len);
+ p += p_bcb->dst_uuid.len;
+ }
+#endif
+
+ p_buf->len = (UINT16)(p - p_start);
+
+ bnepu_check_send_packet (p_bcb, p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function bnep_send_conn_responce
+**
+** Description This function sends a BNEP setup response to peer
+**
+** Returns void
+**
+*******************************************************************************/
+void bnep_send_conn_responce (tBNEP_CONN *p_bcb, UINT16 resp_code)
+{
+ BT_HDR *p_buf;
+ UINT8 *p;
+
+ BNEP_TRACE_EVENT1 ("BNEP - bnep_send_conn_responce for CID: 0x%x", p_bcb->l2cap_cid);
+ if ((p_buf = (BT_HDR *)GKI_getpoolbuf (BNEP_POOL_ID)) == NULL)
+ {
+ BNEP_TRACE_ERROR0 ("BNEP - not able to send connection response");
+ return;
+ }
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ /* Put in BNEP frame type - filter control */
+ UINT8_TO_BE_STREAM (p, BNEP_FRAME_CONTROL);
+
+ /* Put in filter message type - set filters */
+ UINT8_TO_BE_STREAM (p, BNEP_SETUP_CONNECTION_RESPONSE_MSG);
+
+ UINT16_TO_BE_STREAM (p, resp_code);
+
+ p_buf->len = 4;
+
+ bnepu_check_send_packet (p_bcb, p_buf);
+
+}
+
+
+/*******************************************************************************
+**
+** Function bnepu_send_peer_our_filters
+**
+** Description This function sends our filters to a peer
+**
+** Returns void
+**
+*******************************************************************************/
+void bnepu_send_peer_our_filters (tBNEP_CONN *p_bcb)
+{
+#if (defined (BNEP_SUPPORTS_PROT_FILTERS) && BNEP_SUPPORTS_PROT_FILTERS == TRUE)
+ BT_HDR *p_buf;
+ UINT8 *p;
+ UINT16 xx;
+
+ BNEP_TRACE_DEBUG0 ("BNEP sending peer our filters");
+
+ if ((p_buf = (BT_HDR *)GKI_getpoolbuf (BNEP_POOL_ID)) == NULL)
+ {
+ BNEP_TRACE_ERROR0 ("BNEP - no buffer send filters");
+ return;
+ }
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ /* Put in BNEP frame type - filter control */
+ UINT8_TO_BE_STREAM (p, BNEP_FRAME_CONTROL);
+
+ /* Put in filter message type - set filters */
+ UINT8_TO_BE_STREAM (p, BNEP_FILTER_NET_TYPE_SET_MSG);
+
+ UINT16_TO_BE_STREAM (p, (4 * p_bcb->sent_num_filters));
+ for (xx = 0; xx < p_bcb->sent_num_filters; xx++)
+ {
+ UINT16_TO_BE_STREAM (p, p_bcb->sent_prot_filter_start[xx]);
+ UINT16_TO_BE_STREAM (p, p_bcb->sent_prot_filter_end[xx]);
+ }
+
+ p_buf->len = 4 + (4 * p_bcb->sent_num_filters);
+
+ bnepu_check_send_packet (p_bcb, p_buf);
+
+ p_bcb->con_flags |= BNEP_FLAGS_FILTER_RESP_PEND;
+
+ /* Start timer waiting for setup response */
+ btu_start_timer (&p_bcb->conn_tle, BTU_TTYPE_BNEP, BNEP_FILTER_SET_TIMEOUT);
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function bnepu_send_peer_our_multi_filters
+**
+** Description This function sends our multicast filters to a peer
+**
+** Returns void
+**
+*******************************************************************************/
+void bnepu_send_peer_our_multi_filters (tBNEP_CONN *p_bcb)
+{
+#if (defined (BNEP_SUPPORTS_MULTI_FILTERS) && BNEP_SUPPORTS_MULTI_FILTERS == TRUE)
+ BT_HDR *p_buf;
+ UINT8 *p;
+ UINT16 xx;
+
+ BNEP_TRACE_DEBUG0 ("BNEP sending peer our multicast filters");
+
+ if ((p_buf = (BT_HDR *)GKI_getpoolbuf (BNEP_POOL_ID)) == NULL)
+ {
+ BNEP_TRACE_ERROR0 ("BNEP - no buffer to send multicast filters");
+ return;
+ }
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ /* Put in BNEP frame type - filter control */
+ UINT8_TO_BE_STREAM (p, BNEP_FRAME_CONTROL);
+
+ /* Put in filter message type - set filters */
+ UINT8_TO_BE_STREAM (p, BNEP_FILTER_MULTI_ADDR_SET_MSG);
+
+ UINT16_TO_BE_STREAM (p, (2 * BD_ADDR_LEN * p_bcb->sent_mcast_filters));
+ for (xx = 0; xx < p_bcb->sent_mcast_filters; xx++)
+ {
+ memcpy (p, p_bcb->sent_mcast_filter_start[xx], BD_ADDR_LEN);
+ p += BD_ADDR_LEN;
+ memcpy (p, p_bcb->sent_mcast_filter_end[xx], BD_ADDR_LEN);
+ p += BD_ADDR_LEN;
+ }
+
+ p_buf->len = 4 + (2 * BD_ADDR_LEN * p_bcb->sent_mcast_filters);
+
+ bnepu_check_send_packet (p_bcb, p_buf);
+
+ p_bcb->con_flags |= BNEP_FLAGS_MULTI_RESP_PEND;
+
+ /* Start timer waiting for setup response */
+ btu_start_timer (&p_bcb->conn_tle, BTU_TTYPE_BNEP, BNEP_FILTER_SET_TIMEOUT);
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function bnepu_send_peer_filter_rsp
+**
+** Description This function sends a filter response to a peer
+**
+** Returns void
+**
+*******************************************************************************/
+void bnepu_send_peer_filter_rsp (tBNEP_CONN *p_bcb, UINT16 response_code)
+{
+ BT_HDR *p_buf;
+ UINT8 *p;
+
+ BNEP_TRACE_DEBUG0 ("BNEP sending filter response");
+ if ((p_buf = (BT_HDR *)GKI_getpoolbuf (BNEP_POOL_ID)) == NULL)
+ {
+ BNEP_TRACE_ERROR0 ("BNEP - no buffer filter rsp");
+ return;
+ }
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ /* Put in BNEP frame type - filter control */
+ UINT8_TO_BE_STREAM (p, BNEP_FRAME_CONTROL);
+
+ /* Put in filter message type - set filters */
+ UINT8_TO_BE_STREAM (p, BNEP_FILTER_NET_TYPE_RESPONSE_MSG);
+
+ UINT16_TO_BE_STREAM (p, response_code);
+
+ p_buf->len = 4;
+
+ bnepu_check_send_packet (p_bcb, p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function bnep_send_command_not_understood
+**
+** Description This function sends a BNEP command not understood message
+**
+** Returns void
+**
+*******************************************************************************/
+void bnep_send_command_not_understood (tBNEP_CONN *p_bcb, UINT8 cmd_code)
+{
+ BT_HDR *p_buf;
+ UINT8 *p;
+
+ BNEP_TRACE_EVENT2 ("BNEP - bnep_send_command_not_understood for CID: 0x%x, cmd 0x%x", p_bcb->l2cap_cid, cmd_code);
+ if ((p_buf = (BT_HDR *)GKI_getpoolbuf (BNEP_POOL_ID)) == NULL)
+ {
+ BNEP_TRACE_ERROR0 ("BNEP - not able to send connection response");
+ return;
+ }
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ /* Put in BNEP frame type - filter control */
+ UINT8_TO_BE_STREAM (p, BNEP_FRAME_CONTROL);
+
+ /* Put in filter message type - set filters */
+ UINT8_TO_BE_STREAM (p, BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD);
+
+ UINT8_TO_BE_STREAM (p, cmd_code);
+
+ p_buf->len = 3;
+
+ bnepu_check_send_packet (p_bcb, p_buf);
+
+}
+
+
+/*******************************************************************************
+**
+** Function bnepu_check_send_packet
+**
+** Description This function tries to send a packet to L2CAP.
+** If L2CAP is flow controlled, it enqueues the
+** packet to the transmit queue
+**
+** Returns void
+**
+*******************************************************************************/
+void bnepu_check_send_packet (tBNEP_CONN *p_bcb, BT_HDR *p_buf)
+{
+ BNEP_TRACE_EVENT1 ("BNEP - bnepu_check_send_packet for CID: 0x%x", p_bcb->l2cap_cid);
+ if (p_bcb->con_flags & BNEP_FLAGS_L2CAP_CONGESTED)
+ {
+ if (p_bcb->xmit_q.count >= BNEP_MAX_XMITQ_DEPTH)
+ {
+ BNEP_TRACE_EVENT1 ("BNEP - congested, dropping buf, CID: 0x%x", p_bcb->l2cap_cid);
+
+ GKI_freebuf (p_buf);
+ }
+ else
+ {
+ GKI_enqueue (&p_bcb->xmit_q, p_buf);
+ }
+ }
+ else
+ {
+ L2CA_DataWrite (p_bcb->l2cap_cid, p_buf);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function bnepu_build_bnep_hdr
+**
+** Description This function builds the BNEP header for a packet
+** Extension headers are not sent yet, so there is no
+** check for that.
+**
+** Returns void
+**
+*******************************************************************************/
+void bnepu_build_bnep_hdr (tBNEP_CONN *p_bcb, BT_HDR *p_buf, UINT16 protocol,
+ UINT8 *p_src_addr, UINT8 *p_dest_addr, BOOLEAN fw_ext_present)
+{
+ UINT8 ext_bit, *p = (UINT8 *)NULL;
+ UINT8 type = BNEP_FRAME_COMPRESSED_ETHERNET;
+
+ ext_bit = fw_ext_present ? 0x80 : 0x00;
+
+ if ((p_src_addr) && (memcmp (p_src_addr, bnep_cb.my_bda, BD_ADDR_LEN)))
+ type = BNEP_FRAME_COMPRESSED_ETHERNET_SRC_ONLY;
+
+ if (memcmp (p_dest_addr, p_bcb->rem_bda, BD_ADDR_LEN))
+ type = (type == BNEP_FRAME_COMPRESSED_ETHERNET) ? BNEP_FRAME_COMPRESSED_ETHERNET_DEST_ONLY : BNEP_FRAME_GENERAL_ETHERNET;
+
+ if (!p_src_addr)
+ p_src_addr = (UINT8 *)bnep_cb.my_bda;
+
+ switch (type)
+ {
+ case BNEP_FRAME_GENERAL_ETHERNET:
+ p = bnepu_init_hdr (p_buf, 15, (UINT8)(ext_bit | BNEP_FRAME_GENERAL_ETHERNET));
+
+ memcpy (p, p_dest_addr, BD_ADDR_LEN);
+ p += BD_ADDR_LEN;
+
+ memcpy (p, p_src_addr, BD_ADDR_LEN);
+ p += BD_ADDR_LEN;
+ break;
+
+ case BNEP_FRAME_COMPRESSED_ETHERNET:
+ p = bnepu_init_hdr (p_buf, 3, (UINT8)(ext_bit | BNEP_FRAME_COMPRESSED_ETHERNET));
+ break;
+
+ case BNEP_FRAME_COMPRESSED_ETHERNET_SRC_ONLY:
+ p = bnepu_init_hdr (p_buf, 9, (UINT8)(ext_bit | BNEP_FRAME_COMPRESSED_ETHERNET_SRC_ONLY));
+
+ memcpy (p, p_src_addr, BD_ADDR_LEN);
+ p += BD_ADDR_LEN;
+ break;
+
+ case BNEP_FRAME_COMPRESSED_ETHERNET_DEST_ONLY:
+ p = bnepu_init_hdr (p_buf, 9, (UINT8)(ext_bit | BNEP_FRAME_COMPRESSED_ETHERNET_DEST_ONLY));
+
+ memcpy (p, p_dest_addr, BD_ADDR_LEN);
+ p += BD_ADDR_LEN;
+ break;
+ }
+
+ UINT16_TO_BE_STREAM (p, protocol);
+}
+
+
+/*******************************************************************************
+**
+** Function bnepu_init_hdr
+**
+** Description This function initializes the BNEP header
+**
+** Returns pointer to header in buffer
+**
+*******************************************************************************/
+static UINT8 *bnepu_init_hdr (BT_HDR *p_buf, UINT16 hdr_len, UINT8 pkt_type)
+{
+ UINT8 *p = (UINT8 *)(p_buf + 1) + p_buf->offset;
+
+ /* See if we need to make space in the buffer */
+ if (p_buf->offset < (hdr_len + L2CAP_MIN_OFFSET))
+ {
+ UINT16 xx, diff = BNEP_MINIMUM_OFFSET - p_buf->offset;
+ p = p + p_buf->len - 1;
+ for (xx = 0; xx < p_buf->len; xx++, p--)
+ p[diff] = *p;
+
+ p_buf->offset = BNEP_MINIMUM_OFFSET;
+ p = (UINT8 *)(p_buf + 1) + p_buf->offset;
+ }
+
+ p_buf->len += hdr_len;
+ p_buf->offset -= hdr_len;
+ p -= hdr_len;
+
+ *p++ = pkt_type;
+
+ return (p);
+}
+
+
+/*******************************************************************************
+**
+** Function bnep_process_setup_conn_req
+**
+** Description This function processes a peer's setup connection request
+** message. The destination UUID is verified and response sent
+** Connection open indication will be given to PAN profile
+**
+** Returns void
+**
+*******************************************************************************/
+void bnep_process_setup_conn_req (tBNEP_CONN *p_bcb, UINT8 *p_setup, UINT8 len)
+{
+ BNEP_TRACE_EVENT1 ("BNEP - bnep_process_setup_conn_req for CID: 0x%x", p_bcb->l2cap_cid);
+
+ if (p_bcb->con_state != BNEP_STATE_CONN_SETUP &&
+ p_bcb->con_state != BNEP_STATE_SEC_CHECKING &&
+ p_bcb->con_state != BNEP_STATE_CONNECTED)
+ {
+ BNEP_TRACE_ERROR1 ("BNEP - setup request in bad state %d", p_bcb->con_state);
+ bnep_send_conn_responce (p_bcb, BNEP_SETUP_CONN_NOT_ALLOWED);
+ return;
+ }
+
+ /* Check if we already initiated security check or if waiting for user responce */
+ if (p_bcb->con_flags & BNEP_FLAGS_SETUP_RCVD)
+ {
+ BNEP_TRACE_EVENT0 ("BNEP - Duplicate Setup message received while doing security check");
+ return;
+ }
+
+ /* Check if peer is the originator */
+ if (p_bcb->con_state != BNEP_STATE_CONNECTED &&
+ (!(p_bcb->con_flags & BNEP_FLAGS_SETUP_RCVD)) &&
+ (p_bcb->con_flags & BNEP_FLAGS_IS_ORIG))
+ {
+ BNEP_TRACE_ERROR1 ("BNEP - setup request when we are originator", p_bcb->con_state);
+ bnep_send_conn_responce (p_bcb, BNEP_SETUP_CONN_NOT_ALLOWED);
+ return;
+ }
+
+ if (p_bcb->con_state == BNEP_STATE_CONNECTED)
+ {
+ memcpy ((UINT8 *)&(p_bcb->prv_src_uuid), (UINT8 *)&(p_bcb->src_uuid), sizeof (tBT_UUID));
+ memcpy ((UINT8 *)&(p_bcb->prv_dst_uuid), (UINT8 *)&(p_bcb->dst_uuid), sizeof (tBT_UUID));
+ }
+
+ p_bcb->dst_uuid.len = p_bcb->src_uuid.len = len;
+
+ if (p_bcb->dst_uuid.len == 2)
+ {
+ /* because peer initiated connection keep src uuid as dst uuid */
+ BE_STREAM_TO_UINT16 (p_bcb->src_uuid.uu.uuid16, p_setup);
+ BE_STREAM_TO_UINT16 (p_bcb->dst_uuid.uu.uuid16, p_setup);
+
+ /* If nothing has changed don't bother the profile */
+ if (p_bcb->con_state == BNEP_STATE_CONNECTED &&
+ p_bcb->src_uuid.uu.uuid16 == p_bcb->prv_src_uuid.uu.uuid16 &&
+ p_bcb->dst_uuid.uu.uuid16 == p_bcb->prv_dst_uuid.uu.uuid16)
+ {
+ bnep_send_conn_responce (p_bcb, BNEP_SETUP_CONN_OK);
+ return;
+ }
+ }
+#if (defined (BNEP_SUPPORTS_ALL_UUID_LENGTHS) && BNEP_SUPPORTS_ALL_UUID_LENGTHS == TRUE)
+ else if (p_bcb->dst_uuid.len == 4)
+ {
+ BE_STREAM_TO_UINT32 (p_bcb->src_uuid.uu.uuid32, p_setup);
+ BE_STREAM_TO_UINT32 (p_bcb->dst_uuid.uu.uuid32, p_setup);
+ }
+ else if (p_bcb->dst_uuid.len == 16)
+ {
+ memcpy (p_bcb->src_uuid.uu.uuid128, p_setup, p_bcb->src_uuid.len);
+ p_setup += p_bcb->src_uuid.len;
+ memcpy (p_bcb->dst_uuid.uu.uuid128, p_setup, p_bcb->dst_uuid.len);
+ p_setup += p_bcb->dst_uuid.len;
+ }
+#endif
+ else
+ {
+ BNEP_TRACE_ERROR1 ("BNEP - Bad UID len %d in ConnReq", p_bcb->dst_uuid.len);
+ bnep_send_conn_responce (p_bcb, BNEP_SETUP_INVALID_UUID_SIZE);
+ return;
+ }
+
+ p_bcb->con_state = BNEP_STATE_SEC_CHECKING;
+ p_bcb->con_flags |= BNEP_FLAGS_SETUP_RCVD;
+
+ BNEP_TRACE_EVENT1 ("BNEP initiating security check for incoming call for uuid 0x%x", p_bcb->src_uuid.uu.uuid16);
+#if (!defined (BNEP_DO_AUTH_FOR_ROLE_SWITCH) || BNEP_DO_AUTH_FOR_ROLE_SWITCH == FALSE)
+ if (p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED)
+ bnep_sec_check_complete (p_bcb->rem_bda, p_bcb, BTM_SUCCESS);
+ else
+#endif
+ btm_sec_mx_access_request (p_bcb->rem_bda, BT_PSM_BNEP, FALSE,
+ BTM_SEC_PROTO_BNEP, bnep_get_uuid32(&(p_bcb->src_uuid)),
+ &bnep_sec_check_complete, p_bcb);
+
+ return;
+}
+
+
+/*******************************************************************************
+**
+** Function bnep_process_setup_conn_responce
+**
+** Description This function processes a peer's setup connection response
+** message. The response code is verified and
+** Connection open indication will be given to PAN profile
+**
+** Returns void
+**
+*******************************************************************************/
+void bnep_process_setup_conn_responce (tBNEP_CONN *p_bcb, UINT8 *p_setup)
+{
+ tBNEP_RESULT resp;
+ UINT16 resp_code;
+
+ BNEP_TRACE_DEBUG0 ("BNEP received setup responce");
+ /* The state should be either SETUP or CONNECTED */
+ if (p_bcb->con_state != BNEP_STATE_CONN_SETUP)
+ {
+ /* Should we disconnect ? */
+ BNEP_TRACE_ERROR1 ("BNEP - setup response in bad state %d", p_bcb->con_state);
+ return;
+ }
+
+ /* Check if we are the originator */
+ if (!(p_bcb->con_flags & BNEP_FLAGS_IS_ORIG))
+ {
+ BNEP_TRACE_ERROR1 ("BNEP - setup response when we are not originator", p_bcb->con_state);
+ return;
+ }
+
+ BE_STREAM_TO_UINT16 (resp_code, p_setup);
+
+ switch (resp_code)
+ {
+ case BNEP_SETUP_INVALID_SRC_UUID:
+ resp = BNEP_CONN_FAILED_SRC_UUID;
+ break;
+
+ case BNEP_SETUP_INVALID_DEST_UUID:
+ resp = BNEP_CONN_FAILED_DST_UUID;
+ break;
+
+ case BNEP_SETUP_INVALID_UUID_SIZE:
+ resp = BNEP_CONN_FAILED_UUID_SIZE;
+ break;
+
+ case BNEP_SETUP_CONN_NOT_ALLOWED:
+ default:
+ resp = BNEP_CONN_FAILED;
+ break;
+ }
+
+ /* Check the responce code */
+ if (resp_code != BNEP_SETUP_CONN_OK)
+ {
+ if (p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED)
+ {
+ BNEP_TRACE_EVENT1 ("BNEP - role change response is %d", resp_code);
+
+ /* Restore the earlier BNEP status */
+ p_bcb->con_state = BNEP_STATE_CONNECTED;
+ p_bcb->con_flags &= (~BNEP_FLAGS_SETUP_RCVD);
+ memcpy ((UINT8 *)&(p_bcb->src_uuid), (UINT8 *)&(p_bcb->prv_src_uuid), sizeof (tBT_UUID));
+ memcpy ((UINT8 *)&(p_bcb->dst_uuid), (UINT8 *)&(p_bcb->prv_dst_uuid), sizeof (tBT_UUID));
+
+ /* Ensure timer is stopped */
+ btu_stop_timer (&p_bcb->conn_tle);
+ p_bcb->re_transmits = 0;
+
+ /* Tell the user if he has a callback */
+ if (bnep_cb.p_conn_state_cb)
+ (*bnep_cb.p_conn_state_cb) (p_bcb->handle, p_bcb->rem_bda, resp, TRUE);
+
+ return;
+ }
+ else
+ {
+ BNEP_TRACE_ERROR1 ("BNEP - setup response %d is not OK", resp_code);
+
+ L2CA_DisconnectReq (p_bcb->l2cap_cid);
+
+ /* Tell the user if he has a callback */
+ if ((p_bcb->con_flags & BNEP_FLAGS_IS_ORIG) && (bnep_cb.p_conn_state_cb))
+ (*bnep_cb.p_conn_state_cb) (p_bcb->handle, p_bcb->rem_bda, resp, FALSE);
+
+ bnepu_release_bcb (p_bcb);
+ return;
+ }
+ }
+
+ /* Received successful responce */
+ bnep_connected (p_bcb);
+}
+
+
+/*******************************************************************************
+**
+** Function bnep_process_control_packet
+**
+** Description This function processes a peer's setup connection request
+** message. The destination UUID is verified and response sent
+** Connection open indication will be given to PAN profile
+**
+** Returns void
+**
+*******************************************************************************/
+UINT8 *bnep_process_control_packet (tBNEP_CONN *p_bcb, UINT8 *p, UINT16 *rem_len, BOOLEAN is_ext)
+{
+ UINT8 control_type;
+ BOOLEAN bad_pkt = FALSE;
+ UINT16 len, ext_len = 0;
+
+ if (is_ext)
+ {
+ ext_len = *p++;
+ *rem_len = *rem_len - 1;
+ }
+
+ control_type = *p++;
+ *rem_len = *rem_len - 1;
+
+ BNEP_TRACE_EVENT3 ("BNEP processing control packet rem_len %d, is_ext %d, ctrl_type %d", *rem_len, is_ext, control_type);
+
+ switch (control_type)
+ {
+ case BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD:
+ BNEP_TRACE_ERROR1 ("BNEP Received Cmd not understood for ctl pkt type: %d", *p);
+ p++;
+ *rem_len = *rem_len - 1;
+ break;
+
+ case BNEP_SETUP_CONNECTION_REQUEST_MSG:
+ len = *p++;
+ if (*rem_len < ((2 * len) + 1))
+ {
+ bad_pkt = TRUE;
+ BNEP_TRACE_ERROR0 ("BNEP Received Setup message with bad length");
+ break;
+ }
+ if (!is_ext)
+ bnep_process_setup_conn_req (p_bcb, p, (UINT8)len);
+ p += (2 * len);
+ *rem_len = *rem_len - (2 * len) - 1;
+ break;
+
+ case BNEP_SETUP_CONNECTION_RESPONSE_MSG:
+ if (!is_ext)
+ bnep_process_setup_conn_responce (p_bcb, p);
+ p += 2;
+ *rem_len = *rem_len - 2;
+ break;
+
+ case BNEP_FILTER_NET_TYPE_SET_MSG:
+ BE_STREAM_TO_UINT16 (len, p);
+ if (*rem_len < (len + 2))
+ {
+ bad_pkt = TRUE;
+ BNEP_TRACE_ERROR0 ("BNEP Received Filter set message with bad length");
+ break;
+ }
+ bnepu_process_peer_filter_set (p_bcb, p, len);
+ p += len;
+ *rem_len = *rem_len - len - 2;
+ break;
+
+ case BNEP_FILTER_NET_TYPE_RESPONSE_MSG:
+ bnepu_process_peer_filter_rsp (p_bcb, p);
+ p += 2;
+ *rem_len = *rem_len - 2;
+ break;
+
+ case BNEP_FILTER_MULTI_ADDR_SET_MSG:
+ BE_STREAM_TO_UINT16 (len, p);
+ if (*rem_len < (len + 2))
+ {
+ bad_pkt = TRUE;
+ BNEP_TRACE_ERROR0 ("BNEP Received Multicast Filter Set message with bad length");
+ break;
+ }
+ bnepu_process_peer_multicast_filter_set (p_bcb, p, len);
+ p += len;
+ *rem_len = *rem_len - len - 2;
+ break;
+
+ case BNEP_FILTER_MULTI_ADDR_RESPONSE_MSG:
+ bnepu_process_multicast_filter_rsp (p_bcb, p);
+ p += 2;
+ *rem_len = *rem_len - 2;
+ break;
+
+ default :
+ BNEP_TRACE_ERROR1 ("BNEP - bad ctl pkt type: %d", control_type);
+ bnep_send_command_not_understood (p_bcb, control_type);
+ if (is_ext)
+ {
+ p += (ext_len - 1);
+ *rem_len -= (ext_len - 1);
+ }
+ break;
+ }
+
+ if (bad_pkt)
+ {
+ BNEP_TRACE_ERROR1 ("BNEP - bad ctl pkt length: %d", *rem_len);
+ *rem_len = 0;
+ return NULL;
+ }
+
+ return p;
+}
+
+
+/*******************************************************************************
+**
+** Function bnepu_process_peer_filter_set
+**
+** Description This function processes a peer's filter control
+** 'set' message. The filters are stored in the BCB,
+** and an appropriate filter response message sent.
+**
+** Returns void
+**
+*******************************************************************************/
+void bnepu_process_peer_filter_set (tBNEP_CONN *p_bcb, UINT8 *p_filters, UINT16 len)
+{
+#if (defined (BNEP_SUPPORTS_PROT_FILTERS) && BNEP_SUPPORTS_PROT_FILTERS == TRUE)
+ UINT16 num_filters = 0;
+ UINT16 xx, resp_code = BNEP_FILTER_CRL_OK;
+ UINT16 start, end;
+ UINT8 *p_temp_filters;
+
+ if ((p_bcb->con_state != BNEP_STATE_CONNECTED) &&
+ (!(p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED)))
+ {
+ BNEP_TRACE_DEBUG0 ("BNEP received filter set from peer when there is no connection");
+ return;
+ }
+
+ BNEP_TRACE_DEBUG0 ("BNEP received filter set from peer");
+ /* Check for length not a multiple of 4 */
+ if (len & 3)
+ {
+ BNEP_TRACE_EVENT1 ("BNEP - bad filter len: %d", len);
+ bnepu_send_peer_filter_rsp (p_bcb, BNEP_FILTER_CRL_BAD_RANGE);
+ return;
+ }
+
+ if (len)
+ num_filters = (UINT16) (len >> 2);
+
+ /* Validate filter values */
+ if (num_filters <= BNEP_MAX_PROT_FILTERS)
+ {
+ p_temp_filters = p_filters;
+ for (xx = 0; xx < num_filters; xx++)
+ {
+ BE_STREAM_TO_UINT16 (start, p_temp_filters);
+ BE_STREAM_TO_UINT16 (end, p_temp_filters);
+
+ if (start > end)
+ {
+ resp_code = BNEP_FILTER_CRL_BAD_RANGE;
+ break;
+ }
+ }
+ }
+ else
+ resp_code = BNEP_FILTER_CRL_MAX_REACHED;
+
+ if (resp_code != BNEP_FILTER_CRL_OK)
+ {
+ bnepu_send_peer_filter_rsp (p_bcb, resp_code);
+ return;
+ }
+
+ if (bnep_cb.p_filter_ind_cb)
+ (*bnep_cb.p_filter_ind_cb) (p_bcb->handle, TRUE, 0, len, p_filters);
+
+ p_bcb->rcvd_num_filters = num_filters;
+ for (xx = 0; xx < num_filters; xx++)
+ {
+ BE_STREAM_TO_UINT16 (start, p_filters);
+ BE_STREAM_TO_UINT16 (end, p_filters);
+
+ p_bcb->rcvd_prot_filter_start[xx] = start;
+ p_bcb->rcvd_prot_filter_end[xx] = end;
+ }
+
+ bnepu_send_peer_filter_rsp (p_bcb, resp_code);
+#else
+ bnepu_send_peer_filter_rsp (p_bcb, BNEP_FILTER_CRL_UNSUPPORTED);
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function bnepu_process_peer_filter_rsp
+**
+** Description This function processes a peer's filter control
+** 'response' message.
+**
+** Returns void
+**
+*******************************************************************************/
+void bnepu_process_peer_filter_rsp (tBNEP_CONN *p_bcb, UINT8 *p_data)
+{
+#if (defined (BNEP_SUPPORTS_PROT_FILTERS) && BNEP_SUPPORTS_PROT_FILTERS == TRUE)
+ UINT16 resp_code;
+ tBNEP_RESULT result;
+
+ BNEP_TRACE_DEBUG0 ("BNEP received filter responce");
+ /* The state should be CONNECTED */
+ if ((p_bcb->con_state != BNEP_STATE_CONNECTED) &&
+ (!(p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED)))
+ {
+ BNEP_TRACE_ERROR1 ("BNEP - filter response in bad state %d", p_bcb->con_state);
+ return;
+ }
+
+ /* Check if we are the originator */
+ if (!(p_bcb->con_flags & BNEP_FLAGS_FILTER_RESP_PEND))
+ {
+ BNEP_TRACE_ERROR0 ("BNEP - filter response when not expecting");
+ return;
+ }
+
+ /* Ensure timer is stopped */
+ btu_stop_timer (&p_bcb->conn_tle);
+ p_bcb->con_flags &= ~BNEP_FLAGS_FILTER_RESP_PEND;
+ p_bcb->re_transmits = 0;
+
+ BE_STREAM_TO_UINT16 (resp_code, p_data);
+
+ result = BNEP_SUCCESS;
+ if (resp_code != BNEP_FILTER_CRL_OK)
+ result = BNEP_SET_FILTER_FAIL;
+
+ if (bnep_cb.p_filter_ind_cb)
+ (*bnep_cb.p_filter_ind_cb) (p_bcb->handle, FALSE, result, 0, NULL);
+
+ return;
+#endif
+}
+
+
+
+/*******************************************************************************
+**
+** Function bnepu_process_multicast_filter_rsp
+**
+** Description This function processes multicast filter control
+** 'response' message.
+**
+** Returns void
+**
+*******************************************************************************/
+void bnepu_process_multicast_filter_rsp (tBNEP_CONN *p_bcb, UINT8 *p_data)
+{
+#if (defined (BNEP_SUPPORTS_MULTI_FILTERS) && BNEP_SUPPORTS_MULTI_FILTERS == TRUE)
+ UINT16 resp_code;
+ tBNEP_RESULT result;
+
+ BNEP_TRACE_DEBUG0 ("BNEP received multicast filter responce");
+ /* The state should be CONNECTED */
+ if ((p_bcb->con_state != BNEP_STATE_CONNECTED) &&
+ (!(p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED)))
+ {
+ BNEP_TRACE_ERROR1 ("BNEP - multicast filter response in bad state %d", p_bcb->con_state);
+ return;
+ }
+
+ /* Check if we are the originator */
+ if (!(p_bcb->con_flags & BNEP_FLAGS_MULTI_RESP_PEND))
+ {
+ BNEP_TRACE_ERROR0 ("BNEP - multicast filter response when not expecting");
+ return;
+ }
+
+ /* Ensure timer is stopped */
+ btu_stop_timer (&p_bcb->conn_tle);
+ p_bcb->con_flags &= ~BNEP_FLAGS_MULTI_RESP_PEND;
+ p_bcb->re_transmits = 0;
+
+ BE_STREAM_TO_UINT16 (resp_code, p_data);
+
+ result = BNEP_SUCCESS;
+ if (resp_code != BNEP_FILTER_CRL_OK)
+ result = BNEP_SET_FILTER_FAIL;
+
+ if (bnep_cb.p_mfilter_ind_cb)
+ (*bnep_cb.p_mfilter_ind_cb) (p_bcb->handle, FALSE, result, 0, NULL);
+
+ return;
+#endif
+}
+
+
+
+/*******************************************************************************
+**
+** Function bnepu_process_peer_multicast_filter_set
+**
+** Description This function processes a peer's filter control
+** 'set' message. The filters are stored in the BCB,
+** and an appropriate filter response message sent.
+**
+** Returns void
+**
+*******************************************************************************/
+void bnepu_process_peer_multicast_filter_set (tBNEP_CONN *p_bcb, UINT8 *p_filters, UINT16 len)
+{
+#if (defined (BNEP_SUPPORTS_MULTI_FILTERS) && BNEP_SUPPORTS_MULTI_FILTERS == TRUE)
+ UINT16 resp_code = BNEP_FILTER_CRL_OK;
+ UINT16 num_filters, xx;
+ UINT8 *p_temp_filters, null_bda[BD_ADDR_LEN] = {0,0,0,0,0,0};
+
+ if ((p_bcb->con_state != BNEP_STATE_CONNECTED) &&
+ (!(p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED)))
+ {
+ BNEP_TRACE_DEBUG0 ("BNEP received multicast filter set from peer when there is no connection");
+ return;
+ }
+
+ if (len % 12)
+ {
+ BNEP_TRACE_EVENT1 ("BNEP - bad filter len: %d", len);
+ bnepu_send_peer_multicast_filter_rsp (p_bcb, BNEP_FILTER_CRL_BAD_RANGE);
+ return;
+ }
+
+ if (len > (BNEP_MAX_MULTI_FILTERS * 2 * BD_ADDR_LEN))
+ {
+ BNEP_TRACE_EVENT0 ("BNEP - Too many filters");
+ bnepu_send_peer_multicast_filter_rsp (p_bcb, BNEP_FILTER_CRL_MAX_REACHED);
+ return;
+ }
+
+ num_filters = 0;
+ if (len)
+ num_filters = (UINT16) (len / 12);
+
+ /* Validate filter values */
+ if (num_filters <= BNEP_MAX_MULTI_FILTERS)
+ {
+ p_temp_filters = p_filters;
+ for (xx = 0; xx < num_filters; xx++)
+ {
+ if (memcmp (p_temp_filters, p_temp_filters + BD_ADDR_LEN, BD_ADDR_LEN) > 0)
+ {
+ bnepu_send_peer_multicast_filter_rsp (p_bcb, BNEP_FILTER_CRL_BAD_RANGE);
+ return;
+ }
+
+ p_temp_filters += (BD_ADDR_LEN * 2);
+ }
+ }
+
+ p_bcb->rcvd_mcast_filters = num_filters;
+ for (xx = 0; xx < num_filters; xx++)
+ {
+ memcpy (p_bcb->rcvd_mcast_filter_start[xx], p_filters, BD_ADDR_LEN);
+ memcpy (p_bcb->rcvd_mcast_filter_end[xx], p_filters + BD_ADDR_LEN, BD_ADDR_LEN);
+ p_filters += (BD_ADDR_LEN * 2);
+
+ /* Check if any of the ranges have all zeros as both starting and ending addresses */
+ if ((memcmp (null_bda, p_bcb->rcvd_mcast_filter_start[xx], BD_ADDR_LEN) == 0) &&
+ (memcmp (null_bda, p_bcb->rcvd_mcast_filter_end[xx], BD_ADDR_LEN) == 0))
+ {
+ p_bcb->rcvd_mcast_filters = 0xFFFF;
+ break;
+ }
+ }
+
+ BNEP_TRACE_EVENT1 ("BNEP multicast filters %d", p_bcb->rcvd_mcast_filters);
+ bnepu_send_peer_multicast_filter_rsp (p_bcb, resp_code);
+
+ if (bnep_cb.p_mfilter_ind_cb)
+ (*bnep_cb.p_mfilter_ind_cb) (p_bcb->handle, TRUE, 0, len, p_filters);
+#else
+ bnepu_send_peer_multicast_filter_rsp (p_bcb, BNEP_FILTER_CRL_UNSUPPORTED);
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function bnepu_send_peer_multicast_filter_rsp
+**
+** Description This function sends a filter response to a peer
+**
+** Returns void
+**
+*******************************************************************************/
+void bnepu_send_peer_multicast_filter_rsp (tBNEP_CONN *p_bcb, UINT16 response_code)
+{
+ BT_HDR *p_buf;
+ UINT8 *p;
+
+ BNEP_TRACE_DEBUG1 ("BNEP sending multicast filter response %d", response_code);
+ if ((p_buf = (BT_HDR *)GKI_getpoolbuf (BNEP_POOL_ID)) == NULL)
+ {
+ BNEP_TRACE_ERROR0 ("BNEP - no buffer filter rsp");
+ return;
+ }
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ /* Put in BNEP frame type - filter control */
+ UINT8_TO_BE_STREAM (p, BNEP_FRAME_CONTROL);
+
+ /* Put in filter message type - set filters */
+ UINT8_TO_BE_STREAM (p, BNEP_FILTER_MULTI_ADDR_RESPONSE_MSG);
+
+ UINT16_TO_BE_STREAM (p, response_code);
+
+ p_buf->len = 4;
+
+ bnepu_check_send_packet (p_bcb, p_buf);
+}
+
+
+
+/*******************************************************************************
+**
+** Function bnep_sec_check_complete
+**
+** Description This function is registered with BTM and will be called
+** after completing the security procedures
+**
+** Returns void
+**
+*******************************************************************************/
+void bnep_sec_check_complete (BD_ADDR bd_addr, void *p_ref_data, UINT8 result)
+{
+ tBNEP_CONN *p_bcb = (tBNEP_CONN *)p_ref_data;
+ UINT16 resp_code = BNEP_SETUP_CONN_OK;
+ BOOLEAN is_role_change;
+
+ BNEP_TRACE_EVENT1 ("BNEP security callback returned result %d", result);
+ if (p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED)
+ is_role_change = TRUE;
+ else
+ is_role_change = FALSE;
+
+ /* check if the port is still waiting for security to complete */
+ if (p_bcb->con_state != BNEP_STATE_SEC_CHECKING)
+ {
+ BNEP_TRACE_ERROR1 ("BNEP Connection in wrong state %d when security is completed", p_bcb->con_state);
+ return;
+ }
+
+ /* if it is outgoing call and result is FAILURE return security fail error */
+ if (!(p_bcb->con_flags & BNEP_FLAGS_SETUP_RCVD))
+ {
+ if (result != BTM_SUCCESS)
+ {
+ if (p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED)
+ {
+ /* Tell the user that role change is failed because of security */
+ if (bnep_cb.p_conn_state_cb)
+ (*bnep_cb.p_conn_state_cb) (p_bcb->handle, p_bcb->rem_bda, BNEP_SECURITY_FAIL, is_role_change);
+
+ p_bcb->con_state = BNEP_STATE_CONNECTED;
+ memcpy ((UINT8 *)&(p_bcb->src_uuid), (UINT8 *)&(p_bcb->prv_src_uuid), sizeof (tBT_UUID));
+ memcpy ((UINT8 *)&(p_bcb->dst_uuid), (UINT8 *)&(p_bcb->prv_dst_uuid), sizeof (tBT_UUID));
+ return;
+ }
+
+ L2CA_DisconnectReq (p_bcb->l2cap_cid);
+
+ /* Tell the user if he has a callback */
+ if (bnep_cb.p_conn_state_cb)
+ (*bnep_cb.p_conn_state_cb) (p_bcb->handle, p_bcb->rem_bda, BNEP_SECURITY_FAIL, is_role_change);
+
+ bnepu_release_bcb (p_bcb);
+ return;
+ }
+
+ /* Transition to the next appropriate state, waiting for connection confirm. */
+ p_bcb->con_state = BNEP_STATE_CONN_SETUP;
+
+ bnep_send_conn_req (p_bcb);
+ btu_start_timer (&p_bcb->conn_tle, BTU_TTYPE_BNEP, BNEP_CONN_TIMEOUT);
+ return;
+ }
+
+ /* it is an incoming call respond appropriately */
+ if (result != BTM_SUCCESS)
+ {
+ bnep_send_conn_responce (p_bcb, BNEP_SETUP_CONN_NOT_ALLOWED);
+ if (p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED)
+ {
+ /* Role change is failed because of security. Revert back to connected state */
+ p_bcb->con_state = BNEP_STATE_CONNECTED;
+ p_bcb->con_flags &= (~BNEP_FLAGS_SETUP_RCVD);
+ memcpy ((UINT8 *)&(p_bcb->src_uuid), (UINT8 *)&(p_bcb->prv_src_uuid), sizeof (tBT_UUID));
+ memcpy ((UINT8 *)&(p_bcb->dst_uuid), (UINT8 *)&(p_bcb->prv_dst_uuid), sizeof (tBT_UUID));
+ return;
+ }
+
+ L2CA_DisconnectReq (p_bcb->l2cap_cid);
+
+ bnepu_release_bcb (p_bcb);
+ return;
+ }
+
+ if (bnep_cb.p_conn_ind_cb)
+ {
+ p_bcb->con_state = BNEP_STATE_CONN_SETUP;
+ (*bnep_cb.p_conn_ind_cb) (p_bcb->handle, p_bcb->rem_bda, &p_bcb->dst_uuid, &p_bcb->src_uuid, is_role_change);
+ }
+ else
+ {
+ /* Profile didn't register connection indication call back */
+ bnep_send_conn_responce (p_bcb, resp_code);
+ bnep_connected (p_bcb);
+ }
+
+ return;
+}
+
+
+/*******************************************************************************
+**
+** Function bnep_is_packet_allowed
+**
+** Description This function verifies whether the protocol passes through
+** the protocol filters set by the peer
+**
+** Returns BNEP_SUCCESS - if the protocol is allowed
+** BNEP_IGNORE_CMD - if the protocol is filtered out
+**
+*******************************************************************************/
+tBNEP_RESULT bnep_is_packet_allowed (tBNEP_CONN *p_bcb,
+ BD_ADDR p_dest_addr,
+ UINT16 protocol,
+ BOOLEAN fw_ext_present,
+ UINT8 *p_data)
+{
+#if (defined (BNEP_SUPPORTS_PROT_FILTERS) && BNEP_SUPPORTS_PROT_FILTERS == TRUE)
+ if (p_bcb->rcvd_num_filters)
+ {
+ UINT16 i, proto;
+
+ /* Findout the actual protocol to check for the filtering */
+ proto = protocol;
+ if (proto == BNEP_802_1_P_PROTOCOL)
+ {
+ if (fw_ext_present)
+ {
+ UINT8 len, ext;
+ /* parse the extension headers and findout actual protocol */
+ do {
+
+ ext = *p_data++;
+ len = *p_data++;
+ p_data += len;
+
+ } while (ext & 0x80);
+ }
+ p_data += 2;
+ BE_STREAM_TO_UINT16 (proto, p_data);
+ }
+
+ for (i=0; i<p_bcb->rcvd_num_filters; i++)
+ {
+ if ((p_bcb->rcvd_prot_filter_start[i] <= proto) &&
+ (proto <= p_bcb->rcvd_prot_filter_end[i]))
+ break;
+ }
+
+ if (i == p_bcb->rcvd_num_filters)
+ {
+ BNEP_TRACE_DEBUG1 ("Ignoring protocol 0x%x in BNEP data write", proto);
+ return BNEP_IGNORE_CMD;
+ }
+ }
+#endif
+
+#if (defined (BNEP_SUPPORTS_MULTI_FILTERS) && BNEP_SUPPORTS_MULTI_FILTERS == TRUE)
+ /* Ckeck for multicast address filtering */
+ if ((p_dest_addr[0] & 0x01) &&
+ p_bcb->rcvd_mcast_filters)
+ {
+ UINT16 i;
+
+ /* Check if every multicast should be filtered */
+ if (p_bcb->rcvd_mcast_filters != 0xFFFF)
+ {
+ /* Check if the address is mentioned in the filter range */
+ for (i = 0; i < p_bcb->rcvd_mcast_filters; i++)
+ {
+ if ((memcmp (p_bcb->rcvd_mcast_filter_start[i], p_dest_addr, BD_ADDR_LEN) <= 0) &&
+ (memcmp (p_bcb->rcvd_mcast_filter_end[i], p_dest_addr, BD_ADDR_LEN) >= 0))
+ break;
+ }
+ }
+
+ /*
+ ** If every multicast should be filtered or the address is not in the filter range
+ ** drop the packet
+ */
+ if ((p_bcb->rcvd_mcast_filters == 0xFFFF) || (i == p_bcb->rcvd_mcast_filters))
+ {
+ BNEP_TRACE_DEBUG6 ("Ignoring multicast address %x.%x.%x.%x.%x.%x in BNEP data write",
+ p_dest_addr[0], p_dest_addr[1], p_dest_addr[2],
+ p_dest_addr[3], p_dest_addr[4], p_dest_addr[5]);
+ return BNEP_IGNORE_CMD;
+ }
+ }
+#endif
+
+ return BNEP_SUCCESS;
+}
+
+
+
+
+
+/*******************************************************************************
+**
+** Function bnep_get_uuid32
+**
+** Description This function returns the 32 bit equivalent of the given UUID
+**
+** Returns UINT32 - 32 bit equivalent of the UUID
+**
+*******************************************************************************/
+UINT32 bnep_get_uuid32 (tBT_UUID *src_uuid)
+{
+ UINT32 result;
+
+ if (src_uuid->len == 2)
+ return ((UINT32)src_uuid->uu.uuid16);
+ else if (src_uuid->len == 4)
+ return (src_uuid->uu.uuid32 & 0x0000FFFF);
+ else
+ {
+ result = src_uuid->uu.uuid128[2];
+ result = (result << 8) | (src_uuid->uu.uuid128[3]);
+ return result;
+ }
+}
+
+
+
+
+/*******************************************************************************
+**
+** Function bnep_dump_status
+**
+** Description This function dumps the bnep control block and connection
+** blocks information
+**
+** Returns none
+**
+*******************************************************************************/
+void bnep_dump_status (void)
+{
+#if (defined (BNEP_SUPPORTS_DEBUG_DUMP) && BNEP_SUPPORTS_DEBUG_DUMP == TRUE)
+ UINT16 i;
+ char buff[200];
+ tBNEP_CONN *p_bcb;
+
+ BNEP_TRACE_DEBUG6 ("BNEP my BD Addr %x.%x.%x.%x.%x.%x",
+ bnep_cb.my_bda[0], bnep_cb.my_bda[1], bnep_cb.my_bda[2],
+ bnep_cb.my_bda[3], bnep_cb.my_bda[4], bnep_cb.my_bda[5]);
+ BNEP_TRACE_DEBUG3 ("profile registered %d, trace %d, got_my_bd_addr %d",
+ bnep_cb.profile_registered, bnep_cb.trace_level, bnep_cb.got_my_bd_addr);
+
+ for (i = 0, p_bcb = bnep_cb.bcb; i < BNEP_MAX_CONNECTIONS; i++, p_bcb++)
+ {
+ sprintf (buff, "%d state %d, flags 0x%x, cid %d, pfilts %d, mfilts %d, src 0x%x, dst 0x%x, BD %x.%x.%x.%x.%x.%x",
+ i, p_bcb->con_state, p_bcb->con_flags, p_bcb->l2cap_cid,
+ p_bcb->rcvd_num_filters, p_bcb->rcvd_mcast_filters,
+ p_bcb->src_uuid.uu.uuid16, p_bcb->dst_uuid.uu.uuid16,
+ p_bcb->rem_bda[0], p_bcb->rem_bda[1], p_bcb->rem_bda[2],
+ p_bcb->rem_bda[3], p_bcb->rem_bda[4], p_bcb->rem_bda[5]);
+
+ BNEP_TRACE_DEBUG0 (buff);
+ }
+#endif
+}
+
+
diff --git a/stack/btm/btm_acl.c b/stack/btm/btm_acl.c
new file mode 100644
index 0000000..aebbfec
--- /dev/null
+++ b/stack/btm/btm_acl.c
@@ -0,0 +1,3126 @@
+/*****************************************************************************
+**
+** Name: btm_acl.c
+**
+** Description: This file contains functions that handle ACL connections.
+** This includes operations such as hold and sniff modes,
+** supported packet types.
+**
+** This module contains both internal and external (API)
+** functions. External (API) functions are distinguishable
+** by their names beginning with uppercase BTM.
+**
+**
+** Copyright (c) 2000-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stddef.h>
+
+#include "bt_types.h"
+#include "bt_target.h"
+#include "gki.h"
+#include "hcimsgs.h"
+#include "btu.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "l2c_int.h"
+#include "hcidefs.h"
+static void btm_establish_continue (tACL_CONN *p_acl_cb);
+
+#define BTM_DEV_REPLY_TIMEOUT 3 /* 3 second timeout waiting for responses */
+
+/*******************************************************************************
+**
+** Function btm_acl_init
+**
+** Description This function is called at BTM startup to initialize
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_acl_init (void)
+{
+ BTM_TRACE_DEBUG0 ("btm_acl_init");
+#if 0 /* cleared in btm_init; put back in if called from anywhere else! */
+ memset (&btm_cb.acl_db, 0, sizeof (btm_cb.acl_db));
+#if RFCOMM_INCLUDED == TRUE
+ memset (btm_cb.btm_scn, 0, BTM_MAX_SCN); /* Initialize the SCN usage to FALSE */
+#endif
+ btm_cb.btm_def_link_policy = 0;
+#if (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE)
+ btm_cb.p_bl_changed_cb = NULL;
+#else
+ btm_cb.p_acl_changed_cb = NULL;
+#endif
+#endif
+
+ /* Initialize nonzero defaults */
+ btm_cb.btm_def_link_super_tout = HCI_DEFAULT_INACT_TOUT;
+ btm_cb.acl_disc_reason = 0xff ;
+}
+
+/*******************************************************************************
+**
+** Function btm_bda_to_acl
+**
+** Description This function returns the FIRST acl_db entry for the passed BDA.
+**
+** Returns Returns pointer to the ACL DB for the requested BDA if found.
+** NULL if not found.
+**
+*******************************************************************************/
+tACL_CONN *btm_bda_to_acl (BD_ADDR bda)
+{
+ tACL_CONN *p = &btm_cb.acl_db[0];
+ UINT16 xx;
+ if (bda)
+ {
+ for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p++)
+ {
+ if ((p->in_use) && (!memcmp (p->remote_addr, bda, BD_ADDR_LEN)))
+ {
+ BTM_TRACE_DEBUG0 ("btm_bda_to_acl found");
+ return(p);
+ }
+ }
+ }
+ BTM_TRACE_DEBUG0 ("btm_bda_to_acl Not found");
+
+ /* If here, no BD Addr found */
+ return((tACL_CONN *)NULL);
+}
+
+/*******************************************************************************
+**
+** Function btm_handle_to_acl_index
+**
+** Description This function returns the FIRST acl_db entry for the passed hci_handle.
+**
+** Returns index to the acl_db or MAX_L2CAP_LINKS.
+**
+*******************************************************************************/
+UINT8 btm_handle_to_acl_index (UINT16 hci_handle)
+{
+ tACL_CONN *p = &btm_cb.acl_db[0];
+ UINT8 xx;
+ BTM_TRACE_DEBUG0 ("btm_handle_to_acl_index");
+ for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p++)
+ {
+ if ((p->in_use) && (p->hci_handle == hci_handle))
+ {
+ break;
+ }
+ }
+
+ /* If here, no BD Addr found */
+ return(xx);
+}
+
+
+/*******************************************************************************
+**
+** Function btm_acl_created
+**
+** Description This function is called by L2CAP when an ACL connection
+** is created.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_acl_created (BD_ADDR bda, DEV_CLASS dc, BD_NAME bdn,
+ UINT16 hci_handle, UINT8 link_role, UINT8 is_le_link)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ UINT8 yy;
+ tACL_CONN *p;
+ UINT8 xx;
+
+ BTM_TRACE_DEBUG3 ("btm_acl_created hci_handle=%d link_role=%d is_le_link=%d",
+ hci_handle,link_role, is_le_link);
+ /* Ensure we don't have duplicates */
+ p = btm_bda_to_acl(bda);
+ if (p != (tACL_CONN *)NULL)
+ {
+ p->hci_handle = hci_handle;
+ p->link_role = link_role;
+#if BLE_INCLUDED == TRUE
+ p->is_le_link = is_le_link;
+#endif
+ BTM_TRACE_DEBUG6 ("Duplicate btm_acl_created: RemBdAddr: %02x%02x%02x%02x%02x%02x",
+ bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
+ BTM_SetLinkPolicy(p->remote_addr, &btm_cb.btm_def_link_policy);
+ return;
+ }
+
+ /* Allocate acl_db entry */
+ for (xx = 0, p = &btm_cb.acl_db[0]; xx < MAX_L2CAP_LINKS; xx++, p++)
+ {
+ if (!p->in_use)
+ {
+ p->in_use = TRUE;
+ p->hci_handle = hci_handle;
+ p->link_role = link_role;
+ p->link_up_issued = FALSE;
+#if BLE_INCLUDED == TRUE
+ p->is_le_link = is_le_link;
+#endif
+ p->restore_pkt_types = 0; /* Only exists while SCO is active */
+ p->switch_role_state = BTM_ACL_SWKEY_STATE_IDLE;
+
+#if BTM_PWR_MGR_INCLUDED == FALSE
+ p->mode = BTM_ACL_MODE_NORMAL;
+#else
+ btm_pm_sm_alloc(xx);
+#endif /* BTM_PWR_MGR_INCLUDED == FALSE */
+
+ memcpy (p->remote_addr, bda, BD_ADDR_LEN);
+
+ if (dc)
+ memcpy (p->remote_dc, dc, DEV_CLASS_LEN);
+
+ if (bdn)
+ memcpy (p->remote_name, bdn, BTM_MAX_REM_BD_NAME_LEN);
+
+
+ /* Check if we already know features for this device */
+ p_dev_rec = btm_find_dev_by_handle (hci_handle);
+
+#if (BLE_INCLUDED == TRUE)
+ if (p_dev_rec )
+ {
+ BTM_TRACE_DEBUG1 ("device_type=0x%x", p_dev_rec->device_type);
+ }
+#endif
+
+
+ if (p_dev_rec
+#if (BLE_INCLUDED == TRUE)
+ && p_dev_rec->device_type != BT_DEVICE_TYPE_BLE
+#endif
+ )
+ {
+
+ /* if BR/EDR do something more */
+ btsnd_hcic_read_rmt_clk_offset (p->hci_handle);
+ btsnd_hcic_rmt_ver_req (p->hci_handle);
+
+ for (yy = 0; yy < BD_FEATURES_LEN; yy++)
+ {
+ if (p_dev_rec->features[yy])
+ {
+ memcpy (p->features, p_dev_rec->features, BD_FEATURES_LEN);
+ if (BTM_SEC_MODE_SP == btm_cb.security_mode &&
+ HCI_SIMPLE_PAIRING_SUPPORTED(p->features))
+ {
+ /* if SM4 supported, check peer support for SM4
+ * The remote controller supports SSP according to saved remote features
+ * read the extended feature page 1 for the host support for SSP */
+ if (btsnd_hcic_rmt_ext_features (p_dev_rec->hci_handle, 1))
+ return;
+ }
+ /* peer does not support SSP */
+ p_dev_rec->sm4 |= BTM_SM4_KNOWN;
+
+ btm_establish_continue (p);
+ return;
+ }
+ }
+ }
+#if (BLE_INCLUDED == TRUE)
+ /* If here, features are not known yet */
+ if (p_dev_rec && p_dev_rec->device_type == BT_DEVICE_TYPE_BLE)
+ {
+ btm_establish_continue(p);
+
+ if (link_role == HCI_ROLE_MASTER)
+ {
+ btm_ble_update_bg_state();
+ btm_ble_resume_bg_conn (NULL, FALSE);
+
+ btsnd_hcic_ble_read_remote_feat(p->hci_handle);
+ }
+ }
+ else
+#endif
+ {
+ btsnd_hcic_rmt_features_req (p->hci_handle);
+ }
+
+ /* read page 1 - on rmt feature event for buffer reasons */
+ return;
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function btm_acl_report_role_change
+**
+** Description This function is called when the local device is deemed
+** to be down. It notifies L2CAP of the failure.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_acl_report_role_change (UINT8 hci_status, BD_ADDR bda)
+{
+ tBTM_ROLE_SWITCH_CMPL ref_data;
+ BTM_TRACE_DEBUG0 ("btm_acl_report_role_change");
+ if (btm_cb.devcb.p_switch_role_cb && (bda &&
+ (0 == memcmp(btm_cb.devcb.switch_role_ref_data.remote_bd_addr, bda, BD_ADDR_LEN))))
+ {
+ memset (&btm_cb.devcb.switch_role_ref_data, 0, sizeof(tBTM_ROLE_SWITCH_CMPL));
+ ref_data.hci_status = hci_status;
+ memcpy (&ref_data, &btm_cb.devcb.switch_role_ref_data, sizeof(tBTM_ROLE_SWITCH_CMPL));
+ (*btm_cb.devcb.p_switch_role_cb)(&ref_data);
+ btm_cb.devcb.p_switch_role_cb = NULL;
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_acl_removed
+**
+** Description This function is called by L2CAP when an ACL connection
+** is removed. Since only L2CAP creates ACL links, we use
+** the L2CAP link index as our index into the control blocks.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_acl_removed (BD_ADDR bda)
+{
+ tACL_CONN *p;
+#if (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE)
+ tBTM_BL_EVENT_DATA evt_data;
+#endif
+#if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE)
+ tBTM_SEC_DEV_REC *p_dev_rec=NULL;
+ UINT16 combined_mode;
+#endif
+
+ BTM_TRACE_DEBUG0 ("btm_acl_removed");
+ p = btm_bda_to_acl(bda);
+ if (p != (tACL_CONN *)NULL)
+ {
+ p->in_use = FALSE;
+
+ /* if the disconnected channel has a pending role switch, clear it now */
+ btm_acl_report_role_change(HCI_ERR_NO_CONNECTION, bda);
+
+ /* Only notify if link up has had a chance to be issued */
+ if (p->link_up_issued)
+ {
+ p->link_up_issued = FALSE;
+
+ /* If anyone cares, tell him database changed */
+#if (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE)
+ if (btm_cb.p_bl_changed_cb)
+ {
+ evt_data.event = BTM_BL_DISCN_EVT;
+ evt_data.discn.p_bda = bda;
+
+ (*btm_cb.p_bl_changed_cb)(&evt_data);
+ }
+
+ btm_acl_update_busy_level (BTM_BLI_ACL_DOWN_EVT);
+#else
+ if (btm_cb.p_acl_changed_cb)
+ (*btm_cb.p_acl_changed_cb) (bda, NULL, NULL, NULL, FALSE);
+#endif
+ }
+
+#if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE)
+
+ BTM_TRACE_DEBUG4 ("acl hci_handle=%d is_le_link=%d connectable_mode=0x%0x link_role=%d",
+ p->hci_handle,
+ p->is_le_link,
+ btm_cb.ble_ctr_cb.inq_var.connectable_mode,
+ p->link_role);
+
+
+ /* If we are LE connectable, check if we need to start advertising again */
+ if ( p->is_le_link && (btm_cb.ble_ctr_cb.inq_var.connectable_mode != BTM_BLE_NON_CONNECTABLE) )
+ {
+ tACL_CONN *pa = &btm_cb.acl_db[0];
+ UINT16 xx;
+
+ for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, pa++)
+ {
+ /* If any other LE link is up, we are still not connectable */
+ if (pa->in_use && pa->is_le_link)
+ return;
+ }
+ combined_mode = (btm_cb.ble_ctr_cb.inq_var.connectable_mode | btm_cb.btm_inq_vars.connectable_mode);
+ btm_ble_set_connectability ( combined_mode );
+ }
+
+ p_dev_rec = btm_find_dev(bda);
+ if ( p_dev_rec)
+ {
+ BTM_TRACE_DEBUG1("before update p_dev_rec->sec_flags=0x%x", p_dev_rec->sec_flags);
+ if (p->is_le_link)
+ {
+ BTM_TRACE_DEBUG0("LE link down");
+ p_dev_rec->sec_flags &= ~(BTM_SEC_ENCRYPTED | BTM_SEC_ROLE_SWITCHED);
+ if ( (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN) == 0)
+ {
+ BTM_TRACE_DEBUG0("Not Bonded");
+ p_dev_rec->sec_flags &= ~(BTM_SEC_AUTHENTICATED | BTM_SEC_LINK_KEY_AUTHED);
+ }
+ else
+ {
+ BTM_TRACE_DEBUG0("Bonded");
+ }
+ }
+ else
+ {
+ BTM_TRACE_DEBUG0("Bletooth link down");
+ p_dev_rec->sec_flags &= ~(BTM_SEC_AUTHORIZED | BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED | BTM_SEC_ROLE_SWITCHED);
+ }
+ BTM_TRACE_DEBUG1("after update p_dev_rec->sec_flags=0x%x", p_dev_rec->sec_flags);
+ }
+ else
+ {
+ BTM_TRACE_ERROR0("Device not found");
+
+ }
+#endif
+
+ return;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function btm_acl_device_down
+**
+** Description This function is called when the local device is deemed
+** to be down. It notifies L2CAP of the failure.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_acl_device_down (void)
+{
+ tACL_CONN *p = &btm_cb.acl_db[0];
+ UINT16 xx;
+ BTM_TRACE_DEBUG0 ("btm_acl_device_down");
+ for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p++)
+ {
+ if (p->in_use)
+ {
+ BTM_TRACE_DEBUG1 ("hci_handle=%d HCI_ERR_HW_FAILURE ",p->hci_handle );
+ l2c_link_hci_disc_comp (p->hci_handle, HCI_ERR_HW_FAILURE);
+ }
+ }
+}
+
+#if (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function btm_acl_update_busy_level
+**
+** Description This function is called to update the busy level of the system
+** .
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_acl_update_busy_level (tBTM_BLI_EVENT event)
+{
+ tBTM_BL_UPDATE_DATA evt;
+ UINT8 busy_level;
+ BTM_TRACE_DEBUG0 ("btm_acl_update_busy_level");
+ switch (event)
+ {
+ case BTM_BLI_ACL_UP_EVT:
+ BTM_TRACE_DEBUG0 ("BTM_BLI_ACL_UP_EVT");
+ btm_cb.num_acl++;
+ break;
+ case BTM_BLI_ACL_DOWN_EVT:
+ if (btm_cb.num_acl)
+ {
+ btm_cb.num_acl--;
+ BTM_TRACE_DEBUG1 ("BTM_BLI_ACL_DOWN_EVT", btm_cb.num_acl);
+ }
+ else
+ {
+ BTM_TRACE_ERROR0 ("BTM_BLI_ACL_DOWN_EVT issued, but num_acl already zero !!!");
+ }
+ break;
+ case BTM_BLI_PAGE_EVT:
+ BTM_TRACE_DEBUG0 ("BTM_BLI_PAGE_EVT");
+ btm_cb.is_paging = TRUE;
+ break;
+ case BTM_BLI_PAGE_DONE_EVT:
+ BTM_TRACE_DEBUG0 ("BTM_BLI_PAGE_DONE_EVT");
+ btm_cb.is_paging = FALSE;
+ break;
+ case BTM_BLI_INQ_EVT:
+ BTM_TRACE_DEBUG0 ("BTM_BLI_INQ_EVT");
+ btm_cb.is_inquiry = TRUE;
+ break;
+ case BTM_BLI_INQ_DONE_EVT:
+ BTM_TRACE_DEBUG0 ("BTM_BLI_INQ_DONE_EVT");
+ btm_cb.is_inquiry = FALSE;
+ break;
+ }
+ if (btm_cb.is_paging || btm_cb.is_inquiry)
+ busy_level = 10;
+ else
+ busy_level = (UINT8)btm_cb.num_acl;
+
+ if (busy_level != btm_cb.busy_level)
+ {
+ evt.event = BTM_BL_UPDATE_EVT;
+ evt.busy_level = busy_level;
+ btm_cb.busy_level = busy_level;
+ if (btm_cb.p_bl_changed_cb && (btm_cb.bl_evt_mask & BTM_BL_UPDATE_MASK))
+ {
+ (*btm_cb.p_bl_changed_cb)((tBTM_BL_EVENT_DATA *)&evt);
+ }
+ }
+}
+#endif
+
+
+/*******************************************************************************
+**
+** Function BTM_GetRole
+**
+** Description This function is called to get the role of the local device
+** for the ACL connection with the specified remote device
+**
+** Returns BTM_SUCCESS if connection exists.
+** BTM_UNKNOWN_ADDR if no active link with bd addr specified
+**
+*******************************************************************************/
+tBTM_STATUS BTM_GetRole (BD_ADDR remote_bd_addr, UINT8 *p_role)
+{
+ tACL_CONN *p;
+ BTM_TRACE_DEBUG0 ("BTM_GetRole");
+ if ((p = btm_bda_to_acl(remote_bd_addr)) == NULL)
+ {
+ *p_role = BTM_ROLE_UNDEFINED;
+ return(BTM_UNKNOWN_ADDR);
+ }
+
+ /* Get the current role */
+ *p_role = p->link_role;
+ return(BTM_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_SwitchRole
+**
+** Description This function is called to switch role between master and
+** slave. If role is already set it will do nothing. If the
+** command was initiated, the callback function is called upon
+** completion.
+**
+** Returns BTM_SUCCESS if already in specified role.
+** BTM_CMD_STARTED if command issued to controller.
+** BTM_NO_RESOURCES if couldn't allocate memory to issue command
+** BTM_UNKNOWN_ADDR if no active link with bd addr specified
+** BTM_MODE_UNSUPPORTED if local device does not support role switching
+** BTM_BUSY if the previous command is not completed
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SwitchRole (BD_ADDR remote_bd_addr, UINT8 new_role, tBTM_CMPL_CB *p_cb)
+{
+ tACL_CONN *p;
+ tBTM_SEC_DEV_REC *p_dev_rec = NULL;
+#if BTM_SCO_INCLUDED == TRUE
+ BOOLEAN is_sco_active;
+#endif
+#if BTM_PWR_MGR_INCLUDED == TRUE
+ tBTM_STATUS status;
+ tBTM_PM_MODE pwr_mode;
+ tBTM_PM_PWR_MD settings;
+#endif
+#if (BT_USE_TRACES == TRUE)
+ BD_ADDR_PTR p_bda;
+#endif
+ BTM_TRACE_API6 ("BTM_SwitchRole BDA: %02x-%02x-%02x-%02x-%02x-%02x",
+ remote_bd_addr[0], remote_bd_addr[1], remote_bd_addr[2],
+ remote_bd_addr[3], remote_bd_addr[4], remote_bd_addr[5]);
+
+ /* Make sure the local device supports switching */
+ if (!(HCI_SWITCH_SUPPORTED(btm_cb.devcb.local_features)))
+ return(BTM_MODE_UNSUPPORTED);
+
+ if (btm_cb.devcb.p_switch_role_cb && p_cb)
+ {
+#if (BT_USE_TRACES == TRUE)
+ p_bda = btm_cb.devcb.switch_role_ref_data.remote_bd_addr;
+ BTM_TRACE_DEBUG6 ("Role switch on other device is in progress 0x%02x%02x%02x%02x%02x%02x",
+ p_bda[0], p_bda[1], p_bda[2],
+ p_bda[3], p_bda[4], p_bda[5]);
+#endif
+ return(BTM_BUSY);
+ }
+
+ if ((p = btm_bda_to_acl(remote_bd_addr)) == NULL)
+ return(BTM_UNKNOWN_ADDR);
+
+ /* Finished if already in desired role */
+ if (p->link_role == new_role)
+ return(BTM_SUCCESS);
+
+#if BTM_SCO_INCLUDED == TRUE
+ /* Check if there is any SCO Active on this BD Address */
+ is_sco_active = btm_is_sco_active_by_bdaddr(remote_bd_addr);
+
+ if (is_sco_active == TRUE)
+ return(BTM_NO_RESOURCES);
+#endif
+
+ /* Ignore role switch request if the previous request was not completed */
+ if (p->switch_role_state != BTM_ACL_SWKEY_STATE_IDLE)
+ {
+ BTM_TRACE_DEBUG1 ("BTM_SwitchRole busy: %d",
+ p->switch_role_state);
+ return(BTM_BUSY);
+ }
+
+ /* Cannot switch role while parked or sniffing */
+#if BTM_PWR_MGR_INCLUDED == FALSE
+ if (p->mode == HCI_MODE_PARK)
+ {
+ if (!btsnd_hcic_exit_park_mode (p->hci_handle))
+ return(BTM_NO_RESOURCES);
+
+ p->switch_role_state = BTM_ACL_SWKEY_STATE_MODE_CHANGE;
+ }
+ else if (p->mode == HCI_MODE_SNIFF)
+ {
+ if (!btsnd_hcic_exit_sniff_mode (p->hci_handle))
+ return(BTM_NO_RESOURCES);
+
+ p->switch_role_state = BTM_ACL_SWKEY_STATE_MODE_CHANGE;
+ }
+#else /* power manager is in use */
+
+ if ((status = BTM_ReadPowerMode(p->remote_addr, &pwr_mode)) != BTM_SUCCESS)
+ return(status);
+
+ /* Wake up the link if in sniff or park before attempting switch */
+ if (pwr_mode == BTM_PM_MD_PARK || pwr_mode == BTM_PM_MD_SNIFF)
+ {
+/* Coverity FALSE-POSITIVE error from Coverity tool. Please do NOT remove following comment. */
+/* coverity[uninit_use_in_call] False-positive: setting the mode to BTM_PM_MD_ACTIVE only uses settings.mode
+ the other data members of tBTM_PM_PWR_MD are ignored
+*/
+ settings.mode = BTM_PM_MD_ACTIVE;
+ status = BTM_SetPowerMode (BTM_PM_SET_ONLY_ID, p->remote_addr, &settings);
+ if (status != BTM_CMD_STARTED)
+ return(BTM_WRONG_MODE);
+
+ p->switch_role_state = BTM_ACL_SWKEY_STATE_MODE_CHANGE;
+ }
+#endif
+ /* some devices do not support switch while encryption is on */
+ else
+ {
+ if (((p_dev_rec = btm_find_dev (remote_bd_addr)) != NULL)
+ && ((p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED) != 0)
+ && !BTM_EPR_AVAILABLE(p))
+ {
+ /* bypass turning off encryption if change link key is already doing it */
+ if (p->encrypt_state != BTM_ACL_ENCRYPT_STATE_ENCRYPT_OFF)
+ {
+ if (!btsnd_hcic_set_conn_encrypt (p->hci_handle, FALSE))
+ return(BTM_NO_RESOURCES);
+ else
+ p->encrypt_state = BTM_ACL_ENCRYPT_STATE_ENCRYPT_OFF;
+ }
+
+ p->switch_role_state = BTM_ACL_SWKEY_STATE_ENCRYPTION_OFF;
+ }
+ else
+ {
+ if (!btsnd_hcic_switch_role (remote_bd_addr, new_role))
+ return(BTM_NO_RESOURCES);
+
+ p->switch_role_state = BTM_ACL_SWKEY_STATE_IN_PROGRESS;
+
+#if BTM_DISC_DURING_RS == TRUE
+ if (p_dev_rec)
+ p_dev_rec->rs_disc_pending = BTM_SEC_RS_PENDING;
+#endif
+ }
+ }
+
+ /* Initialize return structure in case request fails */
+ if (p_cb)
+ {
+ memcpy (btm_cb.devcb.switch_role_ref_data.remote_bd_addr, remote_bd_addr,
+ BD_ADDR_LEN);
+ btm_cb.devcb.switch_role_ref_data.role = new_role;
+ /* initialized to an error code */
+ btm_cb.devcb.switch_role_ref_data.hci_status = HCI_ERR_UNSUPPORTED_VALUE;
+ btm_cb.devcb.p_switch_role_cb = p_cb;
+ }
+ return(BTM_CMD_STARTED);
+}
+
+/*******************************************************************************
+**
+** Function BTM_ChangeLinkKey
+**
+** Description This function is called to change the link key of the
+** connection.
+**
+** Returns BTM_CMD_STARTED if command issued to controller.
+** BTM_NO_RESOURCES if couldn't allocate memory to issue command
+** BTM_UNKNOWN_ADDR if no active link with bd addr specified
+** BTM_BUSY if the previous command is not completed
+**
+*******************************************************************************/
+tBTM_STATUS BTM_ChangeLinkKey (BD_ADDR remote_bd_addr, tBTM_CMPL_CB *p_cb)
+{
+ tACL_CONN *p;
+ tBTM_SEC_DEV_REC *p_dev_rec = NULL;
+#if BTM_PWR_MGR_INCLUDED == TRUE
+ tBTM_STATUS status;
+ tBTM_PM_MODE pwr_mode;
+ tBTM_PM_PWR_MD settings;
+#endif
+ BTM_TRACE_DEBUG0 ("BTM_ChangeLinkKey");
+ if ((p = btm_bda_to_acl(remote_bd_addr)) == NULL)
+ return(BTM_UNKNOWN_ADDR);
+
+ /* Ignore change link key request if the previsous request has not completed */
+ if (p->change_key_state != BTM_ACL_SWKEY_STATE_IDLE)
+ {
+ BTM_TRACE_DEBUG0 ("Link key change request declined since the previous request for this device has not completed ");
+ return(BTM_BUSY);
+ }
+
+ memset (&btm_cb.devcb.chg_link_key_ref_data, 0, sizeof(tBTM_CHANGE_KEY_CMPL));
+
+ /* Cannot change key while parked */
+#if BTM_PWR_MGR_INCLUDED == FALSE
+ if (p->mode == HCI_MODE_PARK)
+ {
+ if (!btsnd_hcic_exit_park_mode (p->hci_handle))
+ return(BTM_NO_RESOURCES);
+
+ p->change_key_state = BTM_ACL_SWKEY_STATE_MODE_CHANGE;
+ }
+#else /* power manager is in use */
+
+
+ if ((status = BTM_ReadPowerMode(p->remote_addr, &pwr_mode)) != BTM_SUCCESS)
+ return(status);
+
+ /* Wake up the link if in park before attempting to change link keys */
+ if (pwr_mode == BTM_PM_MD_PARK)
+ {
+/* Coverity: FALSE-POSITIVE error from Coverity tool. Please do NOT remove following comment. */
+/* coverity[uninit_use_in_call] False-positive: setting the mode to BTM_PM_MD_ACTIVE only uses settings.mode
+ the other data members of tBTM_PM_PWR_MD are ignored
+*/
+ settings.mode = BTM_PM_MD_ACTIVE;
+ status = BTM_SetPowerMode (BTM_PM_SET_ONLY_ID, p->remote_addr, &settings);
+ if (status != BTM_CMD_STARTED)
+ return(BTM_WRONG_MODE);
+
+ p->change_key_state = BTM_ACL_SWKEY_STATE_MODE_CHANGE;
+ }
+#endif
+ /* some devices do not support change of link key while encryption is on */
+ else if (((p_dev_rec = btm_find_dev (remote_bd_addr)) != NULL)
+ && ((p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED) != 0) && !BTM_EPR_AVAILABLE(p))
+ {
+ /* bypass turning off encryption if switch role is already doing it */
+ if (p->encrypt_state != BTM_ACL_ENCRYPT_STATE_ENCRYPT_OFF)
+ {
+ if (!btsnd_hcic_set_conn_encrypt (p->hci_handle, FALSE))
+ return(BTM_NO_RESOURCES);
+ else
+ p->encrypt_state = BTM_ACL_ENCRYPT_STATE_ENCRYPT_OFF;
+ }
+
+ p->change_key_state = BTM_ACL_SWKEY_STATE_ENCRYPTION_OFF;
+ }
+ else /* Ok to initiate change of link key */
+ {
+ if (!btsnd_hcic_change_link_key (p->hci_handle))
+ return(BTM_NO_RESOURCES);
+
+ p->change_key_state = BTM_ACL_SWKEY_STATE_IN_PROGRESS;
+ }
+
+ /* Initialize return structure in case request fails */
+ memcpy (btm_cb.devcb.chg_link_key_ref_data.remote_bd_addr, remote_bd_addr,
+ BD_ADDR_LEN);
+ btm_cb.devcb.p_chg_link_key_cb = p_cb;
+ return(BTM_CMD_STARTED);
+}
+
+/*******************************************************************************
+**
+** Function btm_acl_link_key_change
+**
+** Description This function is called to when a change link key event
+** is received.
+**
+*******************************************************************************/
+void btm_acl_link_key_change (UINT16 handle, UINT8 status)
+{
+ tBTM_CHANGE_KEY_CMPL *p_data;
+ tACL_CONN *p;
+ UINT8 xx;
+ BTM_TRACE_DEBUG0 ("btm_acl_link_key_change");
+ /* Look up the connection by handle and set the current mode */
+ xx = btm_handle_to_acl_index(handle);
+
+ /* don't assume that we can never get a bad hci_handle */
+ if (xx >= MAX_L2CAP_LINKS)
+ return;
+
+ p_data = &btm_cb.devcb.chg_link_key_ref_data;
+ p = &btm_cb.acl_db[xx];
+ p_data->hci_status = status;
+
+ /* if switching state is switching we need to turn encryption on */
+ /* if idle, we did not change encryption */
+ if (p->change_key_state == BTM_ACL_SWKEY_STATE_SWITCHING)
+ {
+ /* Make sure there's not also a role switch going on before re-enabling */
+ if (p->switch_role_state != BTM_ACL_SWKEY_STATE_SWITCHING)
+ {
+ if (btsnd_hcic_set_conn_encrypt (p->hci_handle, TRUE))
+ {
+ p->encrypt_state = BTM_ACL_ENCRYPT_STATE_ENCRYPT_ON;
+ p->change_key_state = BTM_ACL_SWKEY_STATE_ENCRYPTION_ON;
+ return;
+ }
+ }
+ else /* Set the state and wait for change link key */
+ {
+ p->change_key_state = BTM_ACL_SWKEY_STATE_ENCRYPTION_ON;
+ return;
+ }
+ }
+
+ /* Set the switch_role_state to IDLE since the reply received from HCI */
+ /* regardless of its result either success or failed. */
+ if (p->change_key_state == BTM_ACL_SWKEY_STATE_IN_PROGRESS)
+ {
+ p->change_key_state = BTM_ACL_SWKEY_STATE_IDLE;
+ p->encrypt_state = BTM_ACL_ENCRYPT_STATE_IDLE;
+ }
+
+ if (btm_cb.devcb.p_chg_link_key_cb)
+ {
+ (*btm_cb.devcb.p_chg_link_key_cb)((void *)p_data);
+ btm_cb.devcb.p_chg_link_key_cb = NULL;
+ }
+
+ BTM_TRACE_ERROR2("Change Link Key Complete Event: Handle 0x%02x, HCI Status 0x%02x",
+ handle, p_data->hci_status);
+}
+
+/*******************************************************************************
+**
+** Function btm_acl_encrypt_change
+**
+** Description This function is when encryption of the connection is
+** completed by the LM. Checks to see if a role switch or
+** change of link key was active and initiates or continues
+** process if needed.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_acl_encrypt_change (UINT16 handle, UINT8 status, UINT8 encr_enable)
+{
+ tACL_CONN *p;
+ UINT8 xx;
+#if (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE)
+ tBTM_BL_ROLE_CHG_DATA evt;
+#endif
+#if BTM_DISC_DURING_RS == TRUE
+ tBTM_SEC_DEV_REC *p_dev_rec;
+#endif
+ BTM_TRACE_DEBUG3 ("btm_acl_encrypt_change handle=%d status=%d encr_enabl=%d", handle, status, encr_enable);
+ xx = btm_handle_to_acl_index(handle);
+ /* don't assume that we can never get a bad hci_handle */
+ if (xx < MAX_L2CAP_LINKS)
+ p = &btm_cb.acl_db[xx];
+ else
+ return;
+
+ /* Process Role Switch if active */
+ if (p->switch_role_state == BTM_ACL_SWKEY_STATE_ENCRYPTION_OFF)
+ {
+ /* if encryption turn off failed we still will try to switch role */
+ if (encr_enable)
+ {
+ p->switch_role_state = BTM_ACL_SWKEY_STATE_IDLE;
+ p->encrypt_state = BTM_ACL_ENCRYPT_STATE_IDLE;
+ }
+ else
+ {
+ p->switch_role_state = BTM_ACL_SWKEY_STATE_SWITCHING;
+ p->encrypt_state = BTM_ACL_ENCRYPT_STATE_TEMP_FUNC;
+ }
+
+ if (!btsnd_hcic_switch_role (p->remote_addr, (UINT8)!p->link_role))
+ {
+ p->switch_role_state = BTM_ACL_SWKEY_STATE_IDLE;
+ p->encrypt_state = BTM_ACL_ENCRYPT_STATE_IDLE;
+ btm_acl_report_role_change(btm_cb.devcb.switch_role_ref_data.hci_status, p->remote_addr);
+ }
+#if BTM_DISC_DURING_RS == TRUE
+ else
+ {
+ if ((p_dev_rec = btm_find_dev (p->remote_addr)) != NULL)
+ p_dev_rec->rs_disc_pending = BTM_SEC_RS_PENDING;
+ }
+#endif
+
+ }
+ /* Finished enabling Encryption after role switch */
+ else if (p->switch_role_state == BTM_ACL_SWKEY_STATE_ENCRYPTION_ON)
+ {
+ p->switch_role_state = BTM_ACL_SWKEY_STATE_IDLE;
+ p->encrypt_state = BTM_ACL_ENCRYPT_STATE_IDLE;
+ btm_acl_report_role_change(btm_cb.devcb.switch_role_ref_data.hci_status, p->remote_addr);
+
+#if (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE)
+ /* if role change event is registered, report it now */
+ if (btm_cb.p_bl_changed_cb && (btm_cb.bl_evt_mask & BTM_BL_ROLE_CHG_MASK))
+ {
+ evt.event = BTM_BL_ROLE_CHG_EVT;
+ evt.new_role = btm_cb.devcb.switch_role_ref_data.role;
+ evt.p_bda = btm_cb.devcb.switch_role_ref_data.remote_bd_addr;
+ evt.hci_status = btm_cb.devcb.switch_role_ref_data.hci_status;
+ (*btm_cb.p_bl_changed_cb)((tBTM_BL_EVENT_DATA *)&evt);
+
+ BTM_TRACE_DEBUG3("Role Switch Event: new_role 0x%02x, HCI Status 0x%02x, rs_st:%d",
+ evt.new_role, evt.hci_status, p->switch_role_state);
+ }
+#endif
+
+#if BTM_DISC_DURING_RS == TRUE
+ /* If a disconnect is pending, issue it now that role switch has completed */
+ if ((p_dev_rec = btm_find_dev (p->remote_addr)) != NULL)
+ {
+ if (p_dev_rec->rs_disc_pending == BTM_SEC_DISC_PENDING)
+ {
+ BTM_TRACE_WARNING0("btm_acl_encrypt_change -> Issuing delayed HCI_Disconnect!!!");
+ btsnd_hcic_disconnect(p_dev_rec->hci_handle, HCI_ERR_PEER_USER);
+ }
+ BTM_TRACE_ERROR2("btm_acl_encrypt_change: tBTM_SEC_DEV:0x%x rs_disc_pending=%d",
+ (UINT32)p_dev_rec, p_dev_rec->rs_disc_pending);
+ p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING; /* reset flag */
+ }
+#endif
+ }
+
+
+ /* Process Change Link Key if active */
+ if (p->change_key_state == BTM_ACL_SWKEY_STATE_ENCRYPTION_OFF)
+ {
+ /* if encryption turn off failed we still will try to change link key */
+ if (encr_enable)
+ {
+ p->change_key_state = BTM_ACL_SWKEY_STATE_IDLE;
+ p->encrypt_state = BTM_ACL_ENCRYPT_STATE_IDLE;
+ }
+ else
+ {
+ p->encrypt_state = BTM_ACL_ENCRYPT_STATE_TEMP_FUNC;
+ p->change_key_state = BTM_ACL_SWKEY_STATE_SWITCHING;
+ }
+
+ if (!btsnd_hcic_change_link_key (p->hci_handle))
+ {
+ p->encrypt_state = BTM_ACL_ENCRYPT_STATE_IDLE;
+ p->change_key_state = BTM_ACL_SWKEY_STATE_IDLE;
+ if (btm_cb.devcb.p_chg_link_key_cb)
+ {
+ (*btm_cb.devcb.p_chg_link_key_cb)(&btm_cb.devcb.chg_link_key_ref_data);
+ btm_cb.devcb.p_chg_link_key_cb = NULL;
+ }
+ }
+ }
+ /* Finished enabling Encryption after changing link key */
+ else if (p->change_key_state == BTM_ACL_SWKEY_STATE_ENCRYPTION_ON)
+ {
+ p->encrypt_state = BTM_ACL_ENCRYPT_STATE_IDLE;
+ p->change_key_state = BTM_ACL_SWKEY_STATE_IDLE;
+ if (btm_cb.devcb.p_chg_link_key_cb)
+ {
+ (*btm_cb.devcb.p_chg_link_key_cb)(&btm_cb.devcb.chg_link_key_ref_data);
+ btm_cb.devcb.p_chg_link_key_cb = NULL;
+ }
+ }
+}
+/*******************************************************************************
+**
+** Function BTM_SetLinkPolicy
+**
+** Description Create and send HCI "Write Policy Set" command
+**
+** Returns status of the operation
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetLinkPolicy (BD_ADDR remote_bda, UINT16 *settings)
+{
+ tACL_CONN *p;
+ UINT8 *localFeatures = BTM_ReadLocalFeatures();
+ BTM_TRACE_DEBUG0 ("BTM_SetLinkPolicy");
+/* BTM_TRACE_API1 ("BTM_SetLinkPolicy: requested settings: 0x%04x", *settings ); */
+
+ /* First, check if hold mode is supported */
+ if (*settings != HCI_DISABLE_ALL_LM_MODES)
+ {
+ if ( (*settings & HCI_ENABLE_MASTER_SLAVE_SWITCH) && (!HCI_SWITCH_SUPPORTED(localFeatures)) )
+ {
+ *settings &= (~HCI_ENABLE_MASTER_SLAVE_SWITCH);
+ BTM_TRACE_API1 ("BTM_SetLinkPolicy switch not supported (settings: 0x%04x)", *settings );
+ }
+ if ( (*settings & HCI_ENABLE_HOLD_MODE) && (!HCI_HOLD_MODE_SUPPORTED(localFeatures)) )
+ {
+ *settings &= (~HCI_ENABLE_HOLD_MODE);
+ BTM_TRACE_API1 ("BTM_SetLinkPolicy hold not supported (settings: 0x%04x)", *settings );
+ }
+ if ( (*settings & HCI_ENABLE_SNIFF_MODE) && (!HCI_SNIFF_MODE_SUPPORTED(localFeatures)) )
+ {
+ *settings &= (~HCI_ENABLE_SNIFF_MODE);
+ BTM_TRACE_API1 ("BTM_SetLinkPolicy sniff not supported (settings: 0x%04x)", *settings );
+ }
+ if ( (*settings & HCI_ENABLE_PARK_MODE) && (!HCI_PARK_MODE_SUPPORTED(localFeatures)) )
+ {
+ *settings &= (~HCI_ENABLE_PARK_MODE);
+ BTM_TRACE_API1 ("BTM_SetLinkPolicy park not supported (settings: 0x%04x)", *settings );
+ }
+ }
+
+ if ((p = btm_bda_to_acl(remote_bda)) != NULL)
+ return(btsnd_hcic_write_policy_set (p->hci_handle, *settings) ? BTM_CMD_STARTED : BTM_NO_RESOURCES);
+
+ /* If here, no BD Addr found */
+ return(BTM_UNKNOWN_ADDR);
+}
+
+/*******************************************************************************
+**
+** Function BTM_SetDefaultLinkPolicy
+**
+** Description Set the default value for HCI "Write Policy Set" command
+** to use when an ACL link is created.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTM_SetDefaultLinkPolicy (UINT16 settings)
+{
+ BTM_TRACE_DEBUG0 ("BTM_SetDefaultLinkPolicy");
+ btm_cb.btm_def_link_policy = settings;
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_ReadLinkPolicy
+**
+** Description This function is called to read the link policy settings.
+** The address of link policy results are returned in the callback.
+** (tBTM_LNK_POLICY_RESULTS)
+**
+** Returns status of the operation
+**
+*******************************************************************************/
+tBTM_STATUS BTM_ReadLinkPolicy (BD_ADDR remote_bda, tBTM_CMPL_CB *p_cb)
+{
+ tACL_CONN *p;
+
+ BTM_TRACE_API6 ("BTM_ReadLinkPolicy: RemBdAddr: %02x%02x%02x%02x%02x%02x",
+ remote_bda[0], remote_bda[1], remote_bda[2],
+ remote_bda[3], remote_bda[4], remote_bda[5]);
+
+ /* If someone already waiting on the version, do not allow another */
+ if (btm_cb.devcb.p_rlinkp_cmpl_cb)
+ return(BTM_BUSY);
+
+ p = btm_bda_to_acl(remote_bda);
+ if (p != (tACL_CONN *)NULL)
+ {
+ btu_start_timer (&btm_cb.devcb.rlinkp_timer, BTU_TTYPE_BTM_ACL, BTM_DEV_REPLY_TIMEOUT);
+ btm_cb.devcb.p_rlinkp_cmpl_cb = p_cb;
+
+ if (!btsnd_hcic_read_policy_set (p->hci_handle))
+ {
+ btu_stop_timer (&btm_cb.devcb.rlinkp_timer);
+ btm_cb.devcb.p_rlinkp_cmpl_cb = NULL;
+ return(BTM_NO_RESOURCES);
+ }
+
+ return(BTM_CMD_STARTED);
+ }
+
+ /* If here, no BD Addr found */
+ return(BTM_UNKNOWN_ADDR);
+}
+
+
+/*******************************************************************************
+**
+** Function btm_read_link_policy_complete
+**
+** Description This function is called when the command complete message
+** is received from the HCI for the read local link policy request.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_read_link_policy_complete (UINT8 *p)
+{
+ tBTM_CMPL_CB *p_cb = btm_cb.devcb.p_rlinkp_cmpl_cb;
+ tBTM_LNK_POLICY_RESULTS lnkpol;
+ UINT16 handle;
+ tACL_CONN *p_acl_cb = &btm_cb.acl_db[0];
+ UINT16 index;
+ BTM_TRACE_DEBUG0 ("btm_read_link_policy_complete");
+ btu_stop_timer (&btm_cb.devcb.rlinkp_timer);
+
+ /* If there was a callback address for read local version, call it */
+ btm_cb.devcb.p_rlinkp_cmpl_cb = NULL;
+
+ if (p_cb)
+ {
+ STREAM_TO_UINT8 (lnkpol.hci_status, p);
+
+ if (lnkpol.hci_status == HCI_SUCCESS)
+ {
+ lnkpol.status = BTM_SUCCESS;
+
+ STREAM_TO_UINT16 (handle, p);
+
+ STREAM_TO_UINT16 (lnkpol.settings, p);
+
+ /* Search through the list of active channels for the correct BD Addr */
+ for (index = 0; index < MAX_L2CAP_LINKS; index++, p_acl_cb++)
+ {
+ if ((p_acl_cb->in_use) && (handle == p_acl_cb->hci_handle))
+ {
+ memcpy (lnkpol.rem_bda, p_acl_cb->remote_addr, BD_ADDR_LEN);
+ break;
+ }
+ }
+ }
+ else
+ lnkpol.status = BTM_ERR_PROCESSING;
+
+ (*p_cb)(&lnkpol);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function btm_read_remote_version_complete
+**
+** Description This function is called when the command complete message
+** is received from the HCI for the remote version info.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_read_remote_version_complete (UINT8 *p)
+{
+ tACL_CONN *p_acl_cb = &btm_cb.acl_db[0];
+ UINT8 status;
+ UINT16 handle;
+ int xx;
+ BTM_TRACE_DEBUG0 ("btm_read_remote_version_complete");
+ STREAM_TO_UINT8 (status, p);
+ if (status == HCI_SUCCESS)
+ {
+ STREAM_TO_UINT16 (handle, p);
+
+ /* Look up the connection by handle and copy features */
+ for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_acl_cb++)
+ {
+ if ((p_acl_cb->in_use) && (p_acl_cb->hci_handle == handle))
+ {
+ STREAM_TO_UINT8 (p_acl_cb->lmp_version, p);
+ STREAM_TO_UINT16 (p_acl_cb->manufacturer, p);
+ STREAM_TO_UINT16 (p_acl_cb->lmp_subversion, p);
+ break;
+ }
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function btm_read_remote_features_complete
+**
+** Description This function is called when the remote extended features
+** complete event is received from the HCI.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_read_remote_features_complete (UINT8 *p)
+{
+ tACL_CONN *p_acl_cb = &btm_cb.acl_db[0];
+ UINT8 status;
+ UINT16 handle;
+ int xx, yy;
+ UINT8 req_pend;
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ BTM_TRACE_DEBUG0 ("btm_read_remote_features_complete");
+ STREAM_TO_UINT8 (status, p);
+ if (status == HCI_SUCCESS)
+ {
+ STREAM_TO_UINT16 (handle, p);
+
+ /* Look up the connection by handle and copy features */
+ for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_acl_cb++)
+ {
+ if ((p_acl_cb->in_use) && (p_acl_cb->hci_handle == handle))
+ {
+ for (yy = 0; yy < BD_FEATURES_LEN; yy++)
+ STREAM_TO_UINT8 (p_acl_cb->features[yy], p);
+
+ p_dev_rec = btm_find_dev_by_handle (handle);
+ if (!p_dev_rec)
+ {
+ /* Get a new device; might be doing dedicated bonding */
+ p_dev_rec = btm_find_or_alloc_dev (p_acl_cb->remote_addr);
+ }
+
+ memcpy (p_dev_rec->features, p_acl_cb->features, BD_FEATURES_LEN);
+
+ if (BTM_SEC_MODE_SP == btm_cb.security_mode &&
+ HCI_SIMPLE_PAIRING_SUPPORTED(p_acl_cb->features))
+ {
+ /* if SM4 supported, check peer support for SM4
+ * The remote controller supports SSP
+ * read the extended feature page 1 for the host support for SSP */
+ if (btsnd_hcic_rmt_ext_features (handle, 1))
+ break;
+ }
+ else
+ {
+ req_pend = (p_dev_rec->sm4 & BTM_SM4_REQ_PEND);
+ p_dev_rec->sm4 = BTM_SM4_KNOWN;
+ if (req_pend)
+ {
+ l2cu_resubmit_pending_sec_req (p_dev_rec->bd_addr);
+ }
+ }
+
+ btm_establish_continue (p_acl_cb);
+ break;
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_read_remote_ext_features_complete
+**
+** Description This function is called when the remote extended features
+** complete event is received from the HCI.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_read_remote_ext_features_complete (UINT8 *p)
+{
+ tACL_CONN *p_acl_cb = &btm_cb.acl_db[0];
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ UINT8 status, page_num, max_page;
+ UINT16 handle;
+ int xx;
+ BD_FEATURES ext_features; /* extended Features suported by the device */
+ UINT8 req_pend;
+ BTM_TRACE_DEBUG0 ("btm_read_remote_ext_features_complete");
+ STREAM_TO_UINT8 (status, p);
+ if (status == HCI_SUCCESS)
+ {
+ STREAM_TO_UINT16 (handle, p);
+
+ /* Look up the connection by handle and copy features */
+ for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_acl_cb++)
+ {
+ if ((p_acl_cb->in_use) && (p_acl_cb->hci_handle == handle))
+ {
+ STREAM_TO_UINT8 (page_num, p);
+ STREAM_TO_UINT8 (max_page, p);
+ p_dev_rec = btm_find_dev_by_handle (handle);
+ if (!p_dev_rec)
+ p_dev_rec = btm_find_or_alloc_dev (p_acl_cb->remote_addr);
+
+ req_pend = (p_dev_rec->sm4 & BTM_SM4_REQ_PEND);
+
+ if (page_num == 1 && max_page >= 1)
+ {
+ /* only the byte 0 of page 1 is used right now */
+ STREAM_TO_UINT8 (ext_features[0], p);
+
+ if (HCI_SSP_HOST_SUPPORTED(ext_features))
+ {
+ p_dev_rec->sm4 = BTM_SM4_TRUE;
+ }
+ }
+
+ BTM_TRACE_API5 ("ext_features_complt page_num:%d max_page:%d f[0]:x%02x, sm4:%x, pend:%d",
+ page_num, max_page, *p, p_dev_rec->sm4, req_pend);
+
+ if (!BTM_SEC_IS_SM4(p_dev_rec->sm4))
+ {
+ p_dev_rec->sm4 = BTM_SM4_KNOWN;
+ }
+
+ if (req_pend)
+ l2cu_resubmit_pending_sec_req (p_dev_rec->bd_addr);
+
+ btm_establish_continue (p_acl_cb);
+
+ break;
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_read_remote_ext_features_failed
+**
+** Description This function is called when the remote extended features
+** complete event returns a failed status.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_read_remote_ext_features_failed (UINT8 status)
+{
+ BTM_TRACE_ERROR1 ("btm_read_remote_ext_features_failed (status 0x%02x)", status);
+}
+
+/*******************************************************************************
+**
+** Function btm_establish_continue
+**
+** Description This function is called when the command complete message
+** is received from the HCI for the read local link policy request.
+**
+** Returns void
+**
+*******************************************************************************/
+static void btm_establish_continue (tACL_CONN *p_acl_cb)
+{
+#if (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE)
+ tBTM_BL_EVENT_DATA evt_data;
+#endif
+ BTM_TRACE_DEBUG0 ("btm_establish_continue");
+#if (!defined(BTM_BYPASS_EXTRA_ACL_SETUP) || BTM_BYPASS_EXTRA_ACL_SETUP == FALSE)
+#if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE)
+ if (!p_acl_cb->is_le_link)
+#endif
+ {
+ /* For now there are a some devices that do not like sending */
+ /* commands events and data at the same time. */
+ /* Set the packet types to the default allowed by the device */
+ btm_set_packet_types (p_acl_cb, btm_cb.btm_acl_pkt_types_supported);
+
+ if (btm_cb.btm_def_link_policy)
+ BTM_SetLinkPolicy (p_acl_cb->remote_addr, &btm_cb.btm_def_link_policy);
+
+ BTM_SetLinkSuperTout (p_acl_cb->remote_addr, btm_cb.btm_def_link_super_tout);
+ }
+#endif
+ p_acl_cb->link_up_issued = TRUE;
+
+ /* If anyone cares, tell him database changed */
+#if (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE)
+ if (btm_cb.p_bl_changed_cb)
+ {
+ evt_data.event = BTM_BL_CONN_EVT;
+ evt_data.conn.p_bda = p_acl_cb->remote_addr;
+ evt_data.conn.p_bdn = p_acl_cb->remote_name;
+ evt_data.conn.p_dc = p_acl_cb->remote_dc;
+ evt_data.conn.p_features = p_acl_cb->features;
+
+
+ (*btm_cb.p_bl_changed_cb)(&evt_data);
+ }
+ btm_acl_update_busy_level (BTM_BLI_ACL_UP_EVT);
+#else
+ if (btm_cb.p_acl_changed_cb)
+ (*btm_cb.p_acl_changed_cb) (p_acl_cb->remote_addr,
+ p_acl_cb->remote_dc,
+ p_acl_cb->remote_name,
+ p_acl_cb->features,
+ TRUE);
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_SetDefaultLinkSuperTout
+**
+** Description Set the default value for HCI "Write Link Supervision Timeout"
+** command to use when an ACL link is created.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTM_SetDefaultLinkSuperTout (UINT16 timeout)
+{
+ BTM_TRACE_DEBUG0 ("BTM_SetDefaultLinkSuperTout");
+ btm_cb.btm_def_link_super_tout = timeout;
+}
+
+/*******************************************************************************
+**
+** Function BTM_SetLinkSuperTout
+**
+** Description Create and send HCI "Write Link Supervision Timeout" command
+**
+** Returns status of the operation
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetLinkSuperTout (BD_ADDR remote_bda, UINT16 timeout)
+{
+ tACL_CONN *p = btm_bda_to_acl(remote_bda);
+
+ BTM_TRACE_DEBUG0 ("BTM_SetLinkSuperTout");
+ if (p != (tACL_CONN *)NULL)
+ {
+ p->link_super_tout = timeout;
+
+ /* Only send if current role is Master; 2.0 spec requires this */
+ if (p->link_role == BTM_ROLE_MASTER)
+ {
+ if (!btsnd_hcic_write_link_super_tout (LOCAL_BR_EDR_CONTROLLER_ID,
+ p->hci_handle, timeout))
+ return(BTM_NO_RESOURCES);
+
+ return(BTM_CMD_STARTED);
+ }
+ else
+ return(BTM_SUCCESS);
+ }
+
+ /* If here, no BD Addr found */
+ return(BTM_UNKNOWN_ADDR);
+}
+
+/*******************************************************************************
+**
+** Function BTM_RegForLstoEvt
+**
+** Description register for the HCI "Link Supervision Timeout Change" event
+**
+** Returns void
+**
+*******************************************************************************/
+void BTM_RegForLstoEvt (tBTM_LSTO_CBACK *p_cback)
+{
+ BTM_TRACE_DEBUG0 ("BTM_RegForLstoEvt");
+ btm_cb.p_lsto_cback = p_cback;
+}
+
+/*******************************************************************************
+**
+** Function btm_proc_lsto_evt
+**
+** Description process the HCI "Link Supervision Timeout Change" event
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_proc_lsto_evt(UINT16 handle, UINT16 timeout)
+{
+ UINT8 xx;
+
+ BTM_TRACE_DEBUG0 ("btm_proc_lsto_evt");
+ if (btm_cb.p_lsto_cback)
+ {
+ /* Look up the connection by handle and set the current mode */
+ xx = btm_handle_to_acl_index(handle);
+
+ /* don't assume that we can never get a bad hci_handle */
+ if (xx < MAX_L2CAP_LINKS)
+ {
+ (*btm_cb.p_lsto_cback)(btm_cb.acl_db[xx].remote_addr, timeout);
+ }
+ }
+}
+
+#if BTM_PWR_MGR_INCLUDED == FALSE
+/*******************************************************************************
+**
+** Function BTM_SetHoldMode
+**
+** Description This function is called to set a connection into hold mode.
+** A check is made if the connection is in sniff or park mode,
+** and if yes, the hold mode is ignored.
+**
+** Returns status of the operation
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetHoldMode (BD_ADDR remote_bda, UINT16 min_interval, UINT16 max_interval)
+{
+ tACL_CONN *p;
+
+ BTM_TRACE_DEBUG0 ("BTM_SetHoldMode");
+ /* First, check if hold mode is supported */
+ if (!HCI_HOLD_MODE_SUPPORTED(BTM_ReadLocalFeatures()))
+ return(BTM_MODE_UNSUPPORTED);
+
+ p = btm_bda_to_acl(remote_bda);
+ if (p != (tACL_CONN *)NULL)
+ {
+ /* If the connection is in park or sniff mode, forget about holding it */
+ if (p->mode != BTM_ACL_MODE_NORMAL)
+ return(BTM_SUCCESS);
+
+ if (!btsnd_hcic_hold_mode (p->hci_handle, max_interval, min_interval))
+ return(BTM_NO_RESOURCES);
+
+ return(BTM_CMD_STARTED);
+ }
+
+ /* If here, no BD Addr found */
+ return(BTM_UNKNOWN_ADDR);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_SetSniffMode
+**
+** Description This function is called to set a connection into sniff mode.
+** A check is made if the connection is already in sniff or park
+** mode, and if yes, the sniff mode is ignored.
+**
+** Returns status of the operation
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetSniffMode (BD_ADDR remote_bda, UINT16 min_period, UINT16 max_period,
+ UINT16 attempt, UINT16 timeout)
+{
+ tACL_CONN *p;
+ BTM_TRACE_DEBUG0 ("BTM_SetSniffMode");
+ /* First, check if sniff mode is supported */
+ if (!HCI_SNIFF_MODE_SUPPORTED(BTM_ReadLocalFeatures()))
+ return(BTM_MODE_UNSUPPORTED);
+
+ p = btm_bda_to_acl(remote_bda);
+ if (p != (tACL_CONN *)NULL)
+ {
+ /* If the connection is in park mode, forget about sniffing it */
+ if (p->mode != BTM_ACL_MODE_NORMAL)
+ return(BTM_WRONG_MODE);
+
+ if (!btsnd_hcic_sniff_mode (p->hci_handle, max_period,
+ min_period, attempt, timeout))
+ return(BTM_NO_RESOURCES);
+
+ return(BTM_CMD_STARTED);
+ }
+
+ /* If here, no BD Addr found */
+ return(BTM_UNKNOWN_ADDR);
+}
+
+
+
+
+/*******************************************************************************
+**
+** Function BTM_CancelSniffMode
+**
+** Description This function is called to put a connection out of sniff mode.
+** A check is made if the connection is already in sniff mode,
+** and if not, the cancel sniff mode is ignored.
+**
+** Returns status of the operation
+**
+*******************************************************************************/
+tBTM_STATUS BTM_CancelSniffMode (BD_ADDR remote_bda)
+{
+ tACL_CONN *p = btm_bda_to_acl(remote_bda);
+ BTM_TRACE_DEBUG0 ("BTM_CancelSniffMode ");
+ if (p == (tACL_CONN *)NULL)
+ return(BTM_UNKNOWN_ADDR);
+
+ /* If the connection is not in sniff mode, cannot cancel */
+ if (p->mode != BTM_ACL_MODE_SNIFF)
+ return(BTM_WRONG_MODE);
+
+ if (!btsnd_hcic_exit_sniff_mode (p->hci_handle))
+ return(BTM_NO_RESOURCES);
+
+ return(BTM_CMD_STARTED);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_SetParkMode
+**
+** Description This function is called to set a connection into park mode.
+** A check is made if the connection is already in sniff or park
+** mode, and if yes, the park mode is ignored.
+**
+** Returns status of the operation
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetParkMode (BD_ADDR remote_bda, UINT16 beacon_min_period, UINT16 beacon_max_period)
+{
+ tACL_CONN *p;
+
+ BTM_TRACE_DEBUG0 ("BTM_SetParkMode");
+ /* First, check if park mode is supported */
+ if (!HCI_PARK_MODE_SUPPORTED(BTM_ReadLocalFeatures()))
+ return(BTM_MODE_UNSUPPORTED);
+
+ p = btm_bda_to_acl(remote_bda);
+ if (p != (tACL_CONN *)NULL)
+ {
+ /* If the connection is in sniff mode, forget about parking it */
+ if (p->mode != BTM_ACL_MODE_NORMAL)
+ return(BTM_WRONG_MODE);
+
+ /* no park mode if SCO exists -- CR#1982, 1.1 errata 1124
+ command status event should be returned /w error code 0x0C "Command Disallowed"
+ Let LM do this.
+ */
+ if (!btsnd_hcic_park_mode (p->hci_handle,
+ beacon_max_period, beacon_min_period))
+ return(BTM_NO_RESOURCES);
+
+ return(BTM_CMD_STARTED);
+ }
+
+ /* If here, no BD Addr found */
+ return(BTM_UNKNOWN_ADDR);
+}
+
+/*******************************************************************************
+**
+** Function BTM_CancelParkMode
+**
+** Description This function is called to put a connection out of park mode.
+** A check is made if the connection is already in park mode,
+** and if not, the cancel sniff mode is ignored.
+**
+** Returns status of the operation
+**
+*******************************************************************************/
+tBTM_STATUS BTM_CancelParkMode (BD_ADDR remote_bda)
+{
+ tACL_CONN *p;
+
+ BTM_TRACE_DEBUG0 ("BTM_CancelParkMode");
+ p = btm_bda_to_acl(remote_bda);
+ if (p != (tACL_CONN *)NULL)
+ {
+ /* If the connection is not in park mode, cannot cancel */
+ if (p->mode != BTM_ACL_MODE_PARK)
+ return(BTM_WRONG_MODE);
+
+ if (!btsnd_hcic_exit_park_mode (p->hci_handle))
+ return(BTM_NO_RESOURCES);
+
+ return(BTM_CMD_STARTED);
+ }
+
+ /* If here, no BD Addr found */
+ return(BTM_UNKNOWN_ADDR);
+}
+#endif /* BTM_PWR_MGR_INCLUDED == FALSE */
+
+
+/*******************************************************************************
+**
+** Function BTM_SetPacketTypes
+**
+** Description This function is set the packet types used for a specific
+** ACL connection,
+**
+** Returns status of the operation
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetPacketTypes (BD_ADDR remote_bda, UINT16 pkt_types)
+{
+ tACL_CONN *p;
+ BTM_TRACE_DEBUG0 ("BTM_SetPacketTypes");
+
+ if ((p = btm_bda_to_acl(remote_bda)) != NULL)
+ return(btm_set_packet_types (p, pkt_types));
+
+ /* If here, no BD Addr found */
+ return(BTM_UNKNOWN_ADDR);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_ReadPacketTypes
+**
+** Description This function is set the packet types used for a specific
+** ACL connection,
+**
+** Returns packet types supported for the connection, or 0 if no BD address
+**
+*******************************************************************************/
+UINT16 BTM_ReadPacketTypes (BD_ADDR remote_bda)
+{
+ tACL_CONN *p;
+
+ BTM_TRACE_DEBUG0 ("BTM_ReadPacketTypes");
+ p = btm_bda_to_acl(remote_bda);
+ if (p != (tACL_CONN *)NULL)
+ {
+ return(p->pkt_types_mask);
+ }
+
+ /* If here, no BD Addr found */
+ return(0);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_ReadAclMode
+**
+** Description This returns the current mode for a specific
+** ACL connection.
+**
+** Input Param remote_bda - device address of desired ACL connection
+**
+** Output Param p_mode - address where the current mode is copied into.
+** BTM_ACL_MODE_NORMAL
+** BTM_ACL_MODE_HOLD
+** BTM_ACL_MODE_SNIFF
+** BTM_ACL_MODE_PARK
+** (valid only if return code is BTM_SUCCESS)
+**
+** Returns BTM_SUCCESS if successful,
+** BTM_UNKNOWN_ADDR if bd addr is not active or bad
+**
+*******************************************************************************/
+#if BTM_PWR_MGR_INCLUDED == FALSE
+tBTM_STATUS BTM_ReadAclMode (BD_ADDR remote_bda, UINT8 *p_mode)
+{
+ tACL_CONN *p;
+
+ BTM_TRACE_API6 ("BTM_ReadAclMode: RemBdAddr: %02x%02x%02x%02x%02x%02x",
+ remote_bda[0], remote_bda[1], remote_bda[2],
+ remote_bda[3], remote_bda[4], remote_bda[5]);
+
+ p = btm_bda_to_acl(remote_bda);
+ if (p != (tACL_CONN *)NULL)
+ {
+ *p_mode = p->mode;
+ return(BTM_SUCCESS);
+ }
+
+ /* If here, no BD Addr found */
+ return(BTM_UNKNOWN_ADDR);
+}
+#endif /* BTM_PWR_MGR_INCLUDED == FALSE */
+
+/*******************************************************************************
+**
+** Function BTM_ReadClockOffset
+**
+** Description This returns the clock offset for a specific
+** ACL connection.
+**
+** Input Param remote_bda - device address of desired ACL connection
+**
+** Returns clock-offset or 0 if unknown
+**
+*******************************************************************************/
+UINT16 BTM_ReadClockOffset (BD_ADDR remote_bda)
+{
+ tACL_CONN *p;
+
+ BTM_TRACE_API6 ("BTM_ReadClockOffset: RemBdAddr: %02x%02x%02x%02x%02x%02x",
+ remote_bda[0], remote_bda[1], remote_bda[2],
+ remote_bda[3], remote_bda[4], remote_bda[5]);
+
+ if ( (p = btm_bda_to_acl(remote_bda)) != NULL)
+ return(p->clock_offset);
+
+ /* If here, no BD Addr found */
+ return(0);
+}
+
+/*******************************************************************************
+**
+** Function BTM_IsAclConnectionUp
+**
+** Description This function is called to check if an ACL connection exists
+** to a specific remote BD Address.
+**
+** Returns TRUE if connection is up, else FALSE.
+**
+*******************************************************************************/
+BOOLEAN BTM_IsAclConnectionUp (BD_ADDR remote_bda)
+{
+ tACL_CONN *p;
+
+ BTM_TRACE_API6 ("BTM_ReadClockOffset: RemBdAddr: %02x%02x%02x%02x%02x%02x",
+ remote_bda[0], remote_bda[1], remote_bda[2],
+ remote_bda[3], remote_bda[4], remote_bda[5]);
+
+ p = btm_bda_to_acl(remote_bda);
+ if (p != (tACL_CONN *)NULL)
+ {
+ return(TRUE);
+ }
+
+ /* If here, no BD Addr found */
+ return(FALSE);
+}
+
+/*******************************************************************************
+**
+** Function BTM_GetNumAclLinks
+**
+** Description This function is called to count the number of
+** ACL links that are active.
+**
+** Returns UINT16 Number of active ACL links
+**
+*******************************************************************************/
+UINT16 BTM_GetNumAclLinks (void)
+{
+#if (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE)
+ return(UINT16)btm_cb.num_acl;
+#else
+ tACL_CONN *p = &btm_cb.acl_db[0];
+ UINT16 xx, yy;
+ BTM_TRACE_DEBUG0 ("BTM_GetNumAclLinks");
+ for (xx = yy = 0; xx < MAX_L2CAP_LINKS; xx++, p++)
+ {
+ if (p->in_use)
+ yy++;
+ }
+
+ return(yy);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function btm_get_acl_disc_reason_code
+**
+** Description This function is called to get the disconnection reason code
+** returned by the HCI at disconnection complete event.
+**
+** Returns TRUE if connection is up, else FALSE.
+**
+*******************************************************************************/
+UINT16 btm_get_acl_disc_reason_code (void)
+{
+ UINT8 res = btm_cb.acl_disc_reason;
+ BTM_TRACE_DEBUG0 ("btm_get_acl_disc_reason_code");
+ return(res);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_GetHCIConnHandle
+**
+** Description This function is called to get the handle for an ACL connection
+** to a specific remote BD Address.
+**
+** Returns the handle of the connection, or 0xFFFF if none.
+**
+*******************************************************************************/
+UINT16 BTM_GetHCIConnHandle (BD_ADDR remote_bda)
+{
+ tACL_CONN *p;
+ BTM_TRACE_DEBUG0 ("BTM_GetHCIConnHandle");
+ p = btm_bda_to_acl(remote_bda);
+ if (p != (tACL_CONN *)NULL)
+ {
+ return(p->hci_handle);
+ }
+
+ /* If here, no BD Addr found */
+ return(0xFFFF);
+}
+
+#if BTM_PWR_MGR_INCLUDED == FALSE
+/*******************************************************************************
+**
+** Function btm_process_mode_change
+**
+** Description This function is called when an HCI mode change event occurs.
+**
+** Input Parms hci_status - status of the event (HCI_SUCCESS if no errors)
+** hci_handle - connection handle associated with the change
+** mode - HCI_MODE_ACTIVE, HCI_MODE_HOLD, HCI_MODE_SNIFF, or HCI_MODE_PARK
+** interval - number of baseband slots (meaning depends on mode)
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_process_mode_change (UINT8 hci_status, UINT16 hci_handle, UINT8 mode, UINT16 interval)
+{
+ tACL_CONN *p;
+ UINT8 xx;
+ BTM_TRACE_DEBUG0 ("btm_process_mode_change");
+ if (hci_status != HCI_SUCCESS)
+ {
+ BTM_TRACE_WARNING1 ("BTM: HCI Mode Change Error Status: 0x%02x", hci_status);
+ }
+
+ /* Look up the connection by handle and set the current mode */
+ xx = btm_handle_to_acl_index(hci_handle);
+
+ /* don't assume that we can never get a bad hci_handle */
+ if (xx >= MAX_L2CAP_LINKS)
+ return;
+
+ p = &btm_cb.acl_db[xx];
+
+ /* If status is not success mode does not mean anything */
+ if (hci_status == HCI_SUCCESS)
+ p->mode = mode;
+
+ /* If mode change was because of an active role switch or change link key */
+ btm_cont_rswitch_or_chglinkkey(p, btm_find_dev(p->remote_addr), hci_status);
+}
+#endif /* BTM_PWR_MGR_INCLUDED == FALSE */
+
+/*******************************************************************************
+**
+** Function btm_process_clk_off_comp_evt
+**
+** Description This function is called when clock offset command completes.
+**
+** Input Parms hci_handle - connection handle associated with the change
+** clock offset
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_process_clk_off_comp_evt (UINT16 hci_handle, UINT16 clock_offset)
+{
+ UINT8 xx;
+ BTM_TRACE_DEBUG0 ("btm_process_clk_off_comp_evt");
+ /* Look up the connection by handle and set the current mode */
+ if ((xx = btm_handle_to_acl_index(hci_handle)) < MAX_L2CAP_LINKS)
+ btm_cb.acl_db[xx].clock_offset = clock_offset;
+}
+
+/*******************************************************************************
+**
+** Function btm_acl_role_changed
+**
+** Description This function is called whan a link's master/slave role change
+** event or command status event (with error) is received.
+** It updates the link control block, and calls
+** the registered callback with status and role (if registered).
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_acl_role_changed (UINT8 hci_status, BD_ADDR bd_addr, UINT8 new_role)
+{
+ UINT8 *p_bda = (bd_addr) ? bd_addr : btm_cb.devcb.switch_role_ref_data.remote_bd_addr;
+ tACL_CONN *p = btm_bda_to_acl(p_bda);
+ tBTM_ROLE_SWITCH_CMPL *p_data = &btm_cb.devcb.switch_role_ref_data;
+#if (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE)
+ tBTM_BL_ROLE_CHG_DATA evt;
+#endif
+#if BTM_DISC_DURING_RS == TRUE
+ tBTM_SEC_DEV_REC *p_dev_rec;
+#endif
+ BTM_TRACE_DEBUG0 ("btm_acl_role_changed");
+ /* Ignore any stray events */
+ if (p == NULL)
+ {
+ /* it could be a failure */
+ if (hci_status != HCI_SUCCESS)
+ btm_acl_report_role_change(hci_status, bd_addr);
+ return;
+ }
+
+ p_data->hci_status = hci_status;
+
+ if (hci_status == HCI_SUCCESS)
+ {
+ p_data->role = new_role;
+ memcpy(p_data->remote_bd_addr, p_bda, BD_ADDR_LEN);
+
+ /* Update cached value */
+ p->link_role = new_role;
+
+ /* Reload LSTO: link supervision timeout is reset in the LM after a role switch */
+ if (new_role == BTM_ROLE_MASTER)
+ {
+ BTM_SetLinkSuperTout (p->remote_addr, p->link_super_tout);
+ }
+ }
+ else
+ {
+ /* so the BTM_BL_ROLE_CHG_EVT uses the old role */
+ new_role = p->link_role;
+ }
+
+ /* Check if any SCO req is pending for role change */
+ btm_sco_chk_pend_rolechange (p->hci_handle);
+
+ /* if switching state is switching we need to turn encryption on */
+ /* if idle, we did not change encryption */
+ if (p->switch_role_state == BTM_ACL_SWKEY_STATE_SWITCHING)
+ {
+ /* Make sure there's not also a change link key going on before re-enabling */
+ if (p->change_key_state != BTM_ACL_SWKEY_STATE_SWITCHING)
+ {
+ if (btsnd_hcic_set_conn_encrypt (p->hci_handle, TRUE))
+ {
+ p->encrypt_state = BTM_ACL_ENCRYPT_STATE_ENCRYPT_ON;
+ p->switch_role_state = BTM_ACL_SWKEY_STATE_ENCRYPTION_ON;
+ return;
+ }
+ }
+ else /* Set the state and wait for change link key */
+ {
+ p->switch_role_state = BTM_ACL_SWKEY_STATE_ENCRYPTION_ON;
+ return;
+ }
+ }
+
+ /* Set the switch_role_state to IDLE since the reply received from HCI */
+ /* regardless of its result either success or failed. */
+ if (p->switch_role_state == BTM_ACL_SWKEY_STATE_IN_PROGRESS)
+ {
+ p->switch_role_state = BTM_ACL_SWKEY_STATE_IDLE;
+ p->encrypt_state = BTM_ACL_ENCRYPT_STATE_IDLE;
+ }
+
+ /* if role switch complete is needed, report it now */
+ btm_acl_report_role_change(hci_status, bd_addr);
+
+#if (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE)
+ /* if role change event is registered, report it now */
+ if (btm_cb.p_bl_changed_cb && (btm_cb.bl_evt_mask & BTM_BL_ROLE_CHG_MASK))
+ {
+ evt.event = BTM_BL_ROLE_CHG_EVT;
+ evt.new_role = new_role;
+ evt.p_bda = p_bda;
+ evt.hci_status = hci_status;
+ (*btm_cb.p_bl_changed_cb)((tBTM_BL_EVENT_DATA *)&evt);
+ }
+
+ BTM_TRACE_DEBUG3("Role Switch Event: new_role 0x%02x, HCI Status 0x%02x, rs_st:%d",
+ p_data->role, p_data->hci_status, p->switch_role_state);
+#endif
+
+#if BTM_DISC_DURING_RS == TRUE
+ /* If a disconnect is pending, issue it now that role switch has completed */
+ if ((p_dev_rec = btm_find_dev (p_bda)) != NULL)
+ {
+ if (p_dev_rec->rs_disc_pending == BTM_SEC_DISC_PENDING)
+ {
+ BTM_TRACE_WARNING0("btm_acl_role_changed -> Issuing delayed HCI_Disconnect!!!");
+ btsnd_hcic_disconnect(p_dev_rec->hci_handle, HCI_ERR_PEER_USER);
+ }
+ BTM_TRACE_ERROR2("tBTM_SEC_DEV:0x%x rs_disc_pending=%d", (UINT32)p_dev_rec, p_dev_rec->rs_disc_pending);
+ p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING; /* reset flag */
+ }
+
+#endif
+
+}
+
+#if (RFCOMM_INCLUDED==TRUE)
+/*******************************************************************************
+**
+** Function BTM_AllocateSCN
+**
+** Description Look through the Server Channel Numbers for a free one.
+**
+** Returns Allocated SCN number or 0 if none.
+**
+*******************************************************************************/
+
+UINT8 BTM_AllocateSCN(void)
+{
+ UINT8 x;
+ BTM_TRACE_DEBUG0 ("BTM_AllocateSCN");
+
+ // stack reserves scn 1 for HFP, HSP we still do the correct way
+ for (x = 1; x < BTM_MAX_SCN; x++)
+ {
+ if (!btm_cb.btm_scn[x])
+ {
+ btm_cb.btm_scn[x] = TRUE;
+ return(x+1);
+ }
+ }
+
+ return(0); /* No free ports */
+}
+
+/*******************************************************************************
+**
+** Function BTM_TryAllocateSCN
+**
+** Description Try to allocate a fixed server channel
+**
+** Returns Returns TRUE if server channel was available
+**
+*******************************************************************************/
+
+BOOLEAN BTM_TryAllocateSCN(UINT8 scn)
+{
+ UINT8 x;
+
+ /* Make sure we don't exceed max port range.
+ * Stack reserves scn 1 for HFP, HSP we still do the correct way.
+ */
+ if ( (scn>=BTM_MAX_SCN) || (scn == 1) )
+ return FALSE;
+
+ /* check if this port is available */
+ if (!btm_cb.btm_scn[scn-1])
+ {
+ btm_cb.btm_scn[scn-1] = TRUE;
+ return TRUE;
+ }
+
+ return (FALSE); /* Port was busy */
+}
+
+/*******************************************************************************
+**
+** Function BTM_FreeSCN
+**
+** Description Free the specified SCN.
+**
+** Returns TRUE or FALSE
+**
+*******************************************************************************/
+BOOLEAN BTM_FreeSCN(UINT8 scn)
+{
+ BTM_TRACE_DEBUG0 ("BTM_FreeSCN ");
+ if (scn <= BTM_MAX_SCN)
+ {
+ btm_cb.btm_scn[scn-1] = FALSE;
+ return(TRUE);
+ }
+ else
+ return(FALSE); /* Illegal SCN passed in */
+}
+
+#else
+
+/* Make dummy functions for the RPC to link against */
+UINT8 BTM_AllocateSCN(void)
+{
+ return(0);
+}
+
+BOOLEAN BTM_FreeSCN(UINT8 scn)
+{
+ return(FALSE);
+}
+
+#endif
+
+
+/*******************************************************************************
+**
+** Function btm_acl_timeout
+**
+** Description This function is called when a timer list entry expires.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_acl_timeout (TIMER_LIST_ENT *p_tle)
+{
+ UINT32 timer_type = p_tle->param;
+
+ BTM_TRACE_DEBUG0 ("btm_acl_timeout");
+ if (timer_type == TT_DEV_RLNKP)
+ {
+ tBTM_CMPL_CB *p_cb = btm_cb.devcb.p_rlinkp_cmpl_cb;
+ tBTM_LNK_POLICY_RESULTS lnkpol;
+
+ lnkpol.status = BTM_ERR_PROCESSING;
+ lnkpol.settings = 0;
+
+ btm_cb.devcb.p_rlinkp_cmpl_cb = NULL;
+
+ if (p_cb)
+ (*p_cb)(&lnkpol);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_set_packet_types
+**
+** Description This function sets the packet types used for a specific
+** ACL connection. It is called internally by btm_acl_created
+** or by an application/profile by BTM_SetPacketTypes.
+**
+** Returns status of the operation
+**
+*******************************************************************************/
+tBTM_STATUS btm_set_packet_types (tACL_CONN *p, UINT16 pkt_types)
+{
+ UINT16 temp_pkt_types;
+ BTM_TRACE_DEBUG0 ("btm_set_packet_types");
+ /* Save in the ACL control blocks, types that we support */
+ temp_pkt_types = (pkt_types & BTM_ACL_SUPPORTED_PKTS_MASK &
+ btm_cb.btm_acl_pkt_types_supported);
+
+ /* OR in any exception packet types if at least 2.0 version of spec */
+ if (btm_cb.devcb.local_version.hci_version >= HCI_PROTO_VERSION_2_0)
+ {
+ temp_pkt_types |= ((pkt_types & BTM_ACL_EXCEPTION_PKTS_MASK) |
+ (btm_cb.btm_acl_pkt_types_supported & BTM_ACL_EXCEPTION_PKTS_MASK));
+ }
+ else
+ {
+ temp_pkt_types &= (~BTM_ACL_EXCEPTION_PKTS_MASK);
+ }
+
+ /* Exclude packet types not supported by the peer */
+ btm_acl_chk_peer_pkt_type_support (p, &temp_pkt_types);
+
+ BTM_TRACE_DEBUG1 ("SetPacketType Mask -> 0x%04x", temp_pkt_types);
+
+ if (!btsnd_hcic_change_conn_type (p->hci_handle, temp_pkt_types))
+ {
+ return(BTM_NO_RESOURCES);
+ }
+
+ p->pkt_types_mask = temp_pkt_types;
+
+ return(BTM_CMD_STARTED);
+}
+
+/*******************************************************************************
+**
+** Function btm_get_max_packet_size
+**
+** Returns Returns maximum packet size that can be used for current
+** connection, 0 if connection is not established
+**
+*******************************************************************************/
+UINT16 btm_get_max_packet_size (BD_ADDR addr)
+{
+ tACL_CONN *p = btm_bda_to_acl(addr);
+ UINT16 pkt_types = 0;
+ UINT16 pkt_size = 0;
+ BTM_TRACE_DEBUG0 ("btm_get_max_packet_size");
+ if (p != NULL)
+ {
+ pkt_types = p->pkt_types_mask;
+ }
+ else
+ {
+ /* Special case for when info for the local device is requested */
+ if (memcmp (btm_cb.devcb.local_addr, addr, BD_ADDR_LEN) == 0)
+ {
+ pkt_types = btm_cb.btm_acl_pkt_types_supported;
+ }
+ }
+
+ if (pkt_types)
+ {
+ if (!(pkt_types & BTM_ACL_PKT_TYPES_MASK_NO_3_DH5))
+ pkt_size = HCI_EDR3_DH5_PACKET_SIZE;
+ else if (!(pkt_types & BTM_ACL_PKT_TYPES_MASK_NO_2_DH5))
+ pkt_size = HCI_EDR2_DH5_PACKET_SIZE;
+ else if (!(pkt_types & BTM_ACL_PKT_TYPES_MASK_NO_3_DH3))
+ pkt_size = HCI_EDR3_DH3_PACKET_SIZE;
+ else if (pkt_types & BTM_ACL_PKT_TYPES_MASK_DH5)
+ pkt_size = HCI_DH5_PACKET_SIZE;
+ else if (!(pkt_types & BTM_ACL_PKT_TYPES_MASK_NO_2_DH3))
+ pkt_size = HCI_EDR2_DH3_PACKET_SIZE;
+ else if (pkt_types & BTM_ACL_PKT_TYPES_MASK_DM5)
+ pkt_size = HCI_DM5_PACKET_SIZE;
+ else if (pkt_types & BTM_ACL_PKT_TYPES_MASK_DH3)
+ pkt_size = HCI_DH3_PACKET_SIZE;
+ else if (pkt_types & BTM_ACL_PKT_TYPES_MASK_DM3)
+ pkt_size = HCI_DM3_PACKET_SIZE;
+ else if (!(pkt_types & BTM_ACL_PKT_TYPES_MASK_NO_3_DH1))
+ pkt_size = HCI_EDR3_DH1_PACKET_SIZE;
+ else if (!(pkt_types & BTM_ACL_PKT_TYPES_MASK_NO_2_DH1))
+ pkt_size = HCI_EDR2_DH1_PACKET_SIZE;
+ else if (pkt_types & BTM_ACL_PKT_TYPES_MASK_DH1)
+ pkt_size = HCI_DH1_PACKET_SIZE;
+ else if (pkt_types & BTM_ACL_PKT_TYPES_MASK_DM1)
+ pkt_size = HCI_DM1_PACKET_SIZE;
+ }
+
+#ifdef BRCM_VS
+ /* Using HCI size 1017 instead of 1021 */
+ if ((pkt_size == HCI_EDR3_DH5_PACKET_SIZE)
+ && (btu_cb.hcit_acl_data_size == 1017))
+ pkt_size = 1017;
+#endif
+
+ return(pkt_size);
+}
+
+/*******************************************************************************
+**
+** Function BTM_ReadRemoteVersion
+**
+** Returns If connected report peer device info
+**
+*******************************************************************************/
+tBTM_STATUS BTM_ReadRemoteVersion (BD_ADDR addr, UINT8 *lmp_version,
+ UINT16 *manufacturer, UINT16 *lmp_sub_version)
+{
+ tACL_CONN *p = btm_bda_to_acl(addr);
+ BTM_TRACE_DEBUG0 ("BTM_ReadRemoteVersion");
+ if (p == NULL)
+ return(BTM_UNKNOWN_ADDR);
+
+ if (lmp_version)
+ *lmp_version = p->lmp_version;
+
+ if (manufacturer)
+ *manufacturer = p->manufacturer;
+
+ if (lmp_sub_version)
+ *lmp_sub_version = p->lmp_subversion;
+
+ return(BTM_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function BTM_ReadRemoteFeatures
+**
+** Returns pointer to the features string
+**
+*******************************************************************************/
+UINT8 *BTM_ReadRemoteFeatures (BD_ADDR addr)
+{
+ tACL_CONN *p = btm_bda_to_acl(addr);
+ BTM_TRACE_DEBUG0 ("BTM_ReadRemoteFeatures");
+ if (p == NULL)
+ {
+ return(NULL);
+ }
+
+ return(p->features);
+}
+
+/*******************************************************************************
+**
+** Function BTM_RegBusyLevelNotif
+**
+** Description This function is called to register a callback to receive
+** busy level change events.
+**
+** Returns BTM_SUCCESS if successfully registered, otherwise error
+**
+*******************************************************************************/
+#if (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE)
+tBTM_STATUS BTM_RegBusyLevelNotif (tBTM_BL_CHANGE_CB *p_cb, UINT8 *p_level,
+ tBTM_BL_EVENT_MASK evt_mask)
+{
+ BTM_TRACE_DEBUG0 ("BTM_RegBusyLevelNotif");
+ if (p_level)
+ *p_level = btm_cb.busy_level;
+
+ btm_cb.bl_evt_mask = evt_mask;
+
+ if (!p_cb)
+ btm_cb.p_bl_changed_cb = NULL;
+ else if (btm_cb.p_bl_changed_cb)
+ return(BTM_BUSY);
+ else
+ btm_cb.p_bl_changed_cb = p_cb;
+
+ return(BTM_SUCCESS);
+}
+#else
+/*******************************************************************************
+**
+** Function BTM_AclRegisterForChanges
+**
+** Returns This function is called to register a callback for when the
+** ACL database changes, i.e. new entry or entry deleted.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_AclRegisterForChanges (tBTM_ACL_DB_CHANGE_CB *p_cb)
+{
+ BTM_TRACE_DEBUG0 ("BTM_AclRegisterForChanges");
+ if (!p_cb)
+ btm_cb.p_acl_changed_cb = NULL;
+ else if (btm_cb.p_acl_changed_cb)
+ return(BTM_BUSY);
+ else
+ btm_cb.p_acl_changed_cb = p_cb;
+
+ return(BTM_SUCCESS);
+}
+#endif
+
+/*******************************************************************************
+**
+** Function BTM_SetQoS
+**
+** Description This function is called to setup QoS
+**
+** Returns status of the operation
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetQoS (BD_ADDR bd, FLOW_SPEC *p_flow, tBTM_CMPL_CB *p_cb)
+{
+ tACL_CONN *p = &btm_cb.acl_db[0];
+
+ BTM_TRACE_API6 ("BTM_SetQoS: BdAddr: %02x%02x%02x%02x%02x%02x",
+ bd[0], bd[1], bd[2],
+ bd[3], bd[4], bd[5]);
+
+ /* If someone already waiting on the version, do not allow another */
+ if (btm_cb.devcb.p_qossu_cmpl_cb)
+ return(BTM_BUSY);
+
+ if ( (p = btm_bda_to_acl(bd)) != NULL)
+ {
+ btu_start_timer (&btm_cb.devcb.qossu_timer, BTU_TTYPE_BTM_ACL, BTM_DEV_REPLY_TIMEOUT);
+ btm_cb.devcb.p_qossu_cmpl_cb = p_cb;
+
+ if (!btsnd_hcic_qos_setup (p->hci_handle, p_flow->qos_flags, p_flow->service_type,
+ p_flow->token_rate, p_flow->peak_bandwidth, p_flow->latency,p_flow->delay_variation))
+ {
+ btm_cb.devcb.p_qossu_cmpl_cb = NULL;
+ btu_stop_timer(&btm_cb.devcb.qossu_timer);
+ return(BTM_NO_RESOURCES);
+ }
+ else
+ return(BTM_CMD_STARTED);
+ }
+
+ /* If here, no BD Addr found */
+ return(BTM_UNKNOWN_ADDR);
+}
+
+/*******************************************************************************
+**
+** Function btm_qos_setup_complete
+**
+** Description This function is called when the command complete message
+** is received from the HCI for the qos setup request.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_qos_setup_complete (UINT8 status, UINT16 handle, FLOW_SPEC *p_flow)
+{
+ tBTM_CMPL_CB *p_cb = btm_cb.devcb.p_qossu_cmpl_cb;
+ tBTM_QOS_SETUP_CMPL qossu;
+ BTM_TRACE_DEBUG0 ("btm_qos_setup_complete");
+ btu_stop_timer (&btm_cb.devcb.qossu_timer);
+
+ btm_cb.devcb.p_qossu_cmpl_cb = NULL;
+
+ if (p_cb)
+ {
+ memset(&qossu, 0, sizeof(tBTM_QOS_SETUP_CMPL));
+ qossu.status = status;
+ qossu.handle = handle;
+ if (p_flow != NULL)
+ {
+ qossu.flow.qos_flags = p_flow->qos_flags;
+ qossu.flow.service_type = p_flow->service_type;
+ qossu.flow.token_rate = p_flow->token_rate;
+ qossu.flow.peak_bandwidth = p_flow->peak_bandwidth;
+ qossu.flow.latency = p_flow->latency;
+ qossu.flow.delay_variation = p_flow->delay_variation;
+ }
+ BTM_TRACE_DEBUG1 ("BTM: p_flow->delay_variation: 0x%02x",
+ qossu.flow.delay_variation);
+ (*p_cb)(&qossu);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_ReadRSSI
+**
+** Description This function is called to read the link policy settings.
+** The address of link policy results are returned in the callback.
+** (tBTM_RSSI_RESULTS)
+**
+** Returns BTM_CMD_STARTED if successfully initiated or error code
+**
+*******************************************************************************/
+tBTM_STATUS BTM_ReadRSSI (BD_ADDR remote_bda, tBTM_CMPL_CB *p_cb)
+{
+ tACL_CONN *p;
+
+ BTM_TRACE_API6 ("BTM_ReadRSSI: RemBdAddr: %02x%02x%02x%02x%02x%02x",
+ remote_bda[0], remote_bda[1], remote_bda[2],
+ remote_bda[3], remote_bda[4], remote_bda[5]);
+
+ /* If someone already waiting on the version, do not allow another */
+ if (btm_cb.devcb.p_rssi_cmpl_cb)
+ return(BTM_BUSY);
+
+ p = btm_bda_to_acl(remote_bda);
+ if (p != (tACL_CONN *)NULL)
+ {
+ btu_start_timer (&btm_cb.devcb.rssi_timer, BTU_TTYPE_BTM_ACL,
+ BTM_DEV_REPLY_TIMEOUT);
+
+ btm_cb.devcb.p_rssi_cmpl_cb = p_cb;
+
+ if (!btsnd_hcic_read_rssi (p->hci_handle))
+ {
+ btm_cb.devcb.p_rssi_cmpl_cb = NULL;
+ btu_stop_timer (&btm_cb.devcb.rssi_timer);
+ return(BTM_NO_RESOURCES);
+ }
+ else
+ return(BTM_CMD_STARTED);
+ }
+
+ /* If here, no BD Addr found */
+ return(BTM_UNKNOWN_ADDR);
+}
+
+/*******************************************************************************
+**
+** Function BTM_ReadLinkQuality
+**
+** Description This function is called to read the link qulaity.
+** The value of the link quality is returned in the callback.
+** (tBTM_LINK_QUALITY_RESULTS)
+**
+** Returns BTM_CMD_STARTED if successfully initiated or error code
+**
+*******************************************************************************/
+tBTM_STATUS BTM_ReadLinkQuality (BD_ADDR remote_bda, tBTM_CMPL_CB *p_cb)
+{
+ tACL_CONN *p;
+
+ BTM_TRACE_API6 ("BTM_ReadLinkQuality: RemBdAddr: %02x%02x%02x%02x%02x%02x",
+ remote_bda[0], remote_bda[1], remote_bda[2],
+ remote_bda[3], remote_bda[4], remote_bda[5]);
+
+ /* If someone already waiting on the version, do not allow another */
+ if (btm_cb.devcb.p_lnk_qual_cmpl_cb)
+ return(BTM_BUSY);
+
+ p = btm_bda_to_acl(remote_bda);
+ if (p != (tACL_CONN *)NULL)
+ {
+ btu_start_timer (&btm_cb.devcb.lnk_quality_timer, BTU_TTYPE_BTM_ACL,
+ BTM_DEV_REPLY_TIMEOUT);
+ btm_cb.devcb.p_lnk_qual_cmpl_cb = p_cb;
+
+ if (!btsnd_hcic_get_link_quality (p->hci_handle))
+ {
+ btu_stop_timer (&btm_cb.devcb.lnk_quality_timer);
+ btm_cb.devcb.p_lnk_qual_cmpl_cb = NULL;
+ return(BTM_NO_RESOURCES);
+ }
+ else
+ return(BTM_CMD_STARTED);
+ }
+
+ /* If here, no BD Addr found */
+ return(BTM_UNKNOWN_ADDR);
+}
+
+/*******************************************************************************
+**
+** Function BTM_ReadTxPower
+**
+** Description This function is called to read the current
+** TX power of the connection. The tx power level results
+** are returned in the callback.
+** (tBTM_RSSI_RESULTS)
+**
+** Returns BTM_CMD_STARTED if successfully initiated or error code
+**
+*******************************************************************************/
+tBTM_STATUS BTM_ReadTxPower (BD_ADDR remote_bda, tBTM_CMPL_CB *p_cb)
+{
+ tACL_CONN *p;
+ BOOLEAN ret;
+#define BTM_READ_RSSI_TYPE_CUR 0x00
+#define BTM_READ_RSSI_TYPE_MAX 0X01
+
+ BTM_TRACE_API6 ("BTM_ReadTxPower: RemBdAddr: %02x%02x%02x%02x%02x%02x",
+ remote_bda[0], remote_bda[1], remote_bda[2],
+ remote_bda[3], remote_bda[4], remote_bda[5]);
+
+ /* If someone already waiting on the version, do not allow another */
+ if (btm_cb.devcb.p_tx_power_cmpl_cb)
+ return(BTM_BUSY);
+
+ p = btm_bda_to_acl(remote_bda);
+ if (p != (tACL_CONN *)NULL)
+ {
+ btu_start_timer (&btm_cb.devcb.tx_power_timer, BTU_TTYPE_BTM_ACL,
+ BTM_DEV_REPLY_TIMEOUT);
+
+ btm_cb.devcb.p_tx_power_cmpl_cb = p_cb;
+
+#if BLE_INCLUDED == TRUE
+ if (p->is_le_link)
+ {
+ memcpy(btm_cb.devcb.read_tx_pwr_addr, remote_bda, BD_ADDR_LEN);
+ ret = btsnd_hcic_ble_read_adv_chnl_tx_power();
+ }
+ else
+#endif
+ {
+ ret = btsnd_hcic_read_tx_power (p->hci_handle, BTM_READ_RSSI_TYPE_CUR);
+ }
+ if (!ret)
+ {
+ btm_cb.devcb.p_tx_power_cmpl_cb = NULL;
+ btu_stop_timer (&btm_cb.devcb.tx_power_timer);
+ return(BTM_NO_RESOURCES);
+ }
+ else
+ return(BTM_CMD_STARTED);
+ }
+
+ /* If here, no BD Addr found */
+ return (BTM_UNKNOWN_ADDR);
+}
+/*******************************************************************************
+**
+** Function btm_read_tx_power_complete
+**
+** Description This function is called when the command complete message
+** is received from the HCI for the read tx power request.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_read_tx_power_complete (UINT8 *p, BOOLEAN is_ble)
+{
+ tBTM_CMPL_CB *p_cb = btm_cb.devcb.p_tx_power_cmpl_cb;
+ tBTM_TX_POWER_RESULTS results;
+ UINT16 handle;
+ tACL_CONN *p_acl_cb = &btm_cb.acl_db[0];
+ UINT16 index;
+ BTM_TRACE_DEBUG0 ("btm_read_tx_power_complete");
+ btu_stop_timer (&btm_cb.devcb.tx_power_timer);
+
+ /* If there was a callback registered for read rssi, call it */
+ btm_cb.devcb.p_tx_power_cmpl_cb = NULL;
+
+ if (p_cb)
+ {
+ STREAM_TO_UINT8 (results.hci_status, p);
+
+ if (results.hci_status == HCI_SUCCESS)
+ {
+ results.status = BTM_SUCCESS;
+
+ if (!is_ble)
+ {
+ STREAM_TO_UINT16 (handle, p);
+ STREAM_TO_UINT8 (results.tx_power, p);
+
+ /* Search through the list of active channels for the correct BD Addr */
+ for (index = 0; index < MAX_L2CAP_LINKS; index++, p_acl_cb++)
+ {
+ if ((p_acl_cb->in_use) && (handle == p_acl_cb->hci_handle))
+ {
+ memcpy (results.rem_bda, p_acl_cb->remote_addr, BD_ADDR_LEN);
+ break;
+ }
+ }
+ }
+#if BLE_INCLUDED == TRUE
+ else
+ {
+ STREAM_TO_UINT8 (results.tx_power, p);
+ memcpy(results.rem_bda, btm_cb.devcb.read_tx_pwr_addr, BD_ADDR_LEN);
+ }
+#endif
+ BTM_TRACE_DEBUG2 ("BTM TX power Complete: tx_power %d, hci status 0x%02x",
+ results.tx_power, results.hci_status);
+ }
+ else
+ results.status = BTM_ERR_PROCESSING;
+
+ (*p_cb)(&results);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_read_rssi_complete
+**
+** Description This function is called when the command complete message
+** is received from the HCI for the read rssi request.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_read_rssi_complete (UINT8 *p)
+{
+ tBTM_CMPL_CB *p_cb = btm_cb.devcb.p_rssi_cmpl_cb;
+ tBTM_RSSI_RESULTS results;
+ UINT16 handle;
+ tACL_CONN *p_acl_cb = &btm_cb.acl_db[0];
+ UINT16 index;
+ BTM_TRACE_DEBUG0 ("btm_read_rssi_complete");
+ btu_stop_timer (&btm_cb.devcb.rssi_timer);
+
+ /* If there was a callback registered for read rssi, call it */
+ btm_cb.devcb.p_rssi_cmpl_cb = NULL;
+
+ if (p_cb)
+ {
+ STREAM_TO_UINT8 (results.hci_status, p);
+
+ if (results.hci_status == HCI_SUCCESS)
+ {
+ results.status = BTM_SUCCESS;
+
+ STREAM_TO_UINT16 (handle, p);
+
+ STREAM_TO_UINT8 (results.rssi, p);
+ BTM_TRACE_DEBUG2 ("BTM RSSI Complete: rssi %d, hci status 0x%02x",
+ results.rssi, results.hci_status);
+
+ /* Search through the list of active channels for the correct BD Addr */
+ for (index = 0; index < MAX_L2CAP_LINKS; index++, p_acl_cb++)
+ {
+ if ((p_acl_cb->in_use) && (handle == p_acl_cb->hci_handle))
+ {
+ memcpy (results.rem_bda, p_acl_cb->remote_addr, BD_ADDR_LEN);
+ break;
+ }
+ }
+ }
+ else
+ results.status = BTM_ERR_PROCESSING;
+
+ (*p_cb)(&results);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_read_link_quality_complete
+**
+** Description This function is called when the command complete message
+** is received from the HCI for the read link quality.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_read_link_quality_complete (UINT8 *p)
+{
+ tBTM_CMPL_CB *p_cb = btm_cb.devcb.p_lnk_qual_cmpl_cb;
+ tBTM_LINK_QUALITY_RESULTS results;
+ UINT16 handle;
+ tACL_CONN *p_acl_cb = &btm_cb.acl_db[0];
+ UINT16 index;
+ BTM_TRACE_DEBUG0 ("btm_read_link_quality_complete");
+ btu_stop_timer (&btm_cb.devcb.rssi_timer);
+
+ /* If there was a callback registered for read rssi, call it */
+ btm_cb.devcb.p_lnk_qual_cmpl_cb = NULL;
+
+ if (p_cb)
+ {
+ STREAM_TO_UINT8 (results.hci_status, p);
+
+ if (results.hci_status == HCI_SUCCESS)
+ {
+ results.status = BTM_SUCCESS;
+
+ STREAM_TO_UINT16 (handle, p);
+
+ STREAM_TO_UINT8 (results.link_quality, p);
+ BTM_TRACE_DEBUG2 ("BTM Link Quality Complete: Link Quality %d, hci status 0x%02x",
+ results.link_quality, results.hci_status);
+
+ /* Search through the list of active channels for the correct BD Addr */
+ for (index = 0; index < MAX_L2CAP_LINKS; index++, p_acl_cb++)
+ {
+ if ((p_acl_cb->in_use) && (handle == p_acl_cb->hci_handle))
+ {
+ memcpy (results.rem_bda, p_acl_cb->remote_addr, BD_ADDR_LEN);
+ break;
+ }
+ }
+ }
+ else
+ results.status = BTM_ERR_PROCESSING;
+
+ (*p_cb)(&results);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_remove_acl
+**
+** Description This function is called to disconnect an ACL connection
+**
+** Returns BTM_SUCCESS if successfully initiated, otherwise BTM_NO_RESOURCES.
+**
+*******************************************************************************/
+tBTM_STATUS btm_remove_acl (BD_ADDR bd_addr)
+{
+ UINT16 hci_handle = BTM_GetHCIConnHandle(bd_addr);
+ tBTM_STATUS status = BTM_SUCCESS;
+
+ BTM_TRACE_DEBUG0 ("btm_remove_acl");
+#if BTM_DISC_DURING_RS == TRUE
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr);
+
+ /* Role Switch is pending, postpone until completed */
+ if (p_dev_rec && (p_dev_rec->rs_disc_pending == BTM_SEC_RS_PENDING))
+ {
+ p_dev_rec->rs_disc_pending = BTM_SEC_DISC_PENDING;
+ }
+ else /* otherwise can disconnect right away */
+#endif
+
+ if (hci_handle != 0xFFFF)
+ {
+ if (!btsnd_hcic_disconnect (hci_handle, HCI_ERR_PEER_USER))
+ status = BTM_NO_RESOURCES;
+ }
+ else
+ status = BTM_UNKNOWN_ADDR;
+
+ return status;
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_SetTraceLevel
+**
+** Description This function sets the trace level for BTM. If called with
+** a value of 0xFF, it simply returns the current trace level.
+**
+** Returns The new or current trace level
+**
+*******************************************************************************/
+UINT8 BTM_SetTraceLevel (UINT8 new_level)
+{
+ BTM_TRACE_DEBUG0 ("BTM_SetTraceLevel");
+ if (new_level != 0xFF)
+ btm_cb.trace_level = new_level;
+
+ return(btm_cb.trace_level);
+}
+
+/*******************************************************************************
+**
+** Function btm_cont_rswitch_or_chglinkkey
+**
+** Description This function is called to continue processing an active
+** role switch or change of link key procedure. It first
+** disables encryption if enabled and EPR is not supported
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_cont_rswitch_or_chglinkkey (tACL_CONN *p, tBTM_SEC_DEV_REC *p_dev_rec,
+ UINT8 hci_status)
+{
+ BOOLEAN sw_ok = TRUE;
+ BOOLEAN chlk_ok = TRUE;
+ BTM_TRACE_DEBUG0 ("btm_cont_rswitch_or_chglinkkey ");
+ /* Check to see if encryption needs to be turned off if pending
+ change of link key or role switch */
+ if (p->switch_role_state == BTM_ACL_SWKEY_STATE_MODE_CHANGE ||
+ p->change_key_state == BTM_ACL_SWKEY_STATE_MODE_CHANGE)
+ {
+ /* Must turn off Encryption first if necessary */
+ /* Some devices do not support switch or change of link key while encryption is on */
+ if (p_dev_rec != NULL && ((p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED) != 0)
+ && !BTM_EPR_AVAILABLE(p))
+ {
+ if (btsnd_hcic_set_conn_encrypt (p->hci_handle, FALSE))
+ {
+ p->encrypt_state = BTM_ACL_ENCRYPT_STATE_ENCRYPT_OFF;
+ if (p->switch_role_state == BTM_ACL_SWKEY_STATE_MODE_CHANGE)
+ p->switch_role_state = BTM_ACL_SWKEY_STATE_ENCRYPTION_OFF;
+
+ if (p->change_key_state == BTM_ACL_SWKEY_STATE_MODE_CHANGE)
+ p->change_key_state = BTM_ACL_SWKEY_STATE_ENCRYPTION_OFF;
+ }
+ else
+ {
+ /* Error occurred; set states back to Idle */
+ if (p->switch_role_state == BTM_ACL_SWKEY_STATE_MODE_CHANGE)
+ sw_ok = FALSE;
+
+ if (p->change_key_state == BTM_ACL_SWKEY_STATE_MODE_CHANGE)
+ chlk_ok = FALSE;
+ }
+ }
+ else /* Encryption not used or EPR supported, continue with switch
+ and/or change of link key */
+ {
+ if (p->switch_role_state == BTM_ACL_SWKEY_STATE_MODE_CHANGE)
+ {
+ p->switch_role_state = BTM_ACL_SWKEY_STATE_IN_PROGRESS;
+#if BTM_DISC_DURING_RS == TRUE
+ if (p_dev_rec)
+ p_dev_rec->rs_disc_pending = BTM_SEC_RS_PENDING;
+#endif
+ sw_ok = btsnd_hcic_switch_role (p->remote_addr, (UINT8)!p->link_role);
+ }
+
+ if (p->change_key_state == BTM_ACL_SWKEY_STATE_MODE_CHANGE)
+ {
+ p->switch_role_state = BTM_ACL_SWKEY_STATE_IN_PROGRESS;
+ chlk_ok = btsnd_hcic_change_link_key (p->hci_handle);
+ }
+ }
+
+ if (!sw_ok)
+ {
+ p->switch_role_state = BTM_ACL_SWKEY_STATE_IDLE;
+ btm_acl_report_role_change(hci_status, p->remote_addr);
+ }
+
+ if (!chlk_ok)
+ {
+ p->change_key_state = BTM_ACL_SWKEY_STATE_IDLE;
+ if (btm_cb.devcb.p_chg_link_key_cb)
+ {
+ btm_cb.devcb.chg_link_key_ref_data.hci_status = hci_status;
+ (*btm_cb.devcb.p_chg_link_key_cb)(&btm_cb.devcb.chg_link_key_ref_data);
+ btm_cb.devcb.p_chg_link_key_cb = NULL;
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_acl_resubmit_page
+**
+** Description send pending page request
+**
+*******************************************************************************/
+void btm_acl_resubmit_page (void)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ BT_HDR *p_buf;
+ UINT8 *pp;
+ BD_ADDR bda;
+ BTM_TRACE_DEBUG0 ("btm_acl_resubmit_page");
+ /* If there were other page request schedule can start the next one */
+ if ((p_buf = (BT_HDR *)GKI_dequeue (&btm_cb.page_queue)) != NULL)
+ {
+ /* skip 3 (2 bytes opcode and 1 byte len) to get to the bd_addr
+ * for both create_conn and rmt_name */
+ pp = (UINT8 *)(p_buf + 1) + p_buf->offset + 3;
+
+ STREAM_TO_BDADDR (bda, pp);
+
+ p_dev_rec = btm_find_or_alloc_dev (bda);
+
+ memcpy (btm_cb.connecting_bda, p_dev_rec->bd_addr, BD_ADDR_LEN);
+ memcpy (btm_cb.connecting_dc, p_dev_rec->dev_class, DEV_CLASS_LEN);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p_buf);
+ }
+ else
+ btm_cb.paging = FALSE;
+}
+
+/*******************************************************************************
+**
+** Function btm_acl_reset_paging
+**
+** Description set paging to FALSE and free the page queue - called at hci_reset
+**
+*******************************************************************************/
+void btm_acl_reset_paging (void)
+{
+ BT_HDR *p;
+ BTM_TRACE_DEBUG0 ("btm_acl_reset_paging");
+ /* If we sent reset we are definitely not paging any more */
+ while ((p = (BT_HDR *)GKI_dequeue(&btm_cb.page_queue)) != NULL)
+ GKI_freebuf (p);
+
+ btm_cb.paging = FALSE;
+}
+
+/*******************************************************************************
+**
+** Function btm_acl_set_discing
+**
+** Description set discing to the given value
+**
+*******************************************************************************/
+void btm_acl_set_discing (BOOLEAN discing)
+{
+ BTM_TRACE_DEBUG0 ("btm_acl_set_discing");
+ btm_cb.discing = discing;
+}
+
+/*******************************************************************************
+**
+** Function btm_acl_paging
+**
+** Description send a paging command or queue it in btm_cb
+**
+*******************************************************************************/
+void btm_acl_paging (BT_HDR *p, BD_ADDR bda)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+
+ BTM_TRACE_DEBUG4 ("btm_acl_paging discing:%d, paging:%d BDA: %06x%06x",
+ btm_cb.discing, btm_cb.paging,
+ (bda[0]<<16) + (bda[1]<<8) + bda[2], (bda[3]<<16) + (bda[4] << 8) + bda[5]);
+ if (btm_cb.discing)
+ {
+ btm_cb.paging = TRUE;
+ GKI_enqueue (&btm_cb.page_queue, p);
+ }
+ else
+ {
+ if (!BTM_ACL_IS_CONNECTED (bda))
+ {
+ BTM_TRACE_DEBUG2 ("connecting_bda: %06x%06x",
+ (btm_cb.connecting_bda[0]<<16) + (btm_cb.connecting_bda[1]<<8) + btm_cb.connecting_bda[2],
+ (btm_cb.connecting_bda[3]<<16) + (btm_cb.connecting_bda[4] << 8) + btm_cb.connecting_bda[5]);
+ if (btm_cb.paging &&
+ memcmp (bda, btm_cb.connecting_bda, BD_ADDR_LEN) != 0)
+ {
+ GKI_enqueue (&btm_cb.page_queue, p);
+ }
+ else
+ {
+ p_dev_rec = btm_find_or_alloc_dev (bda);
+ memcpy (btm_cb.connecting_bda, p_dev_rec->bd_addr, BD_ADDR_LEN);
+ memcpy (btm_cb.connecting_dc, p_dev_rec->dev_class, DEV_CLASS_LEN);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ }
+
+ btm_cb.paging = TRUE;
+ }
+ else /* ACL is already up */
+ {
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_acl_notif_conn_collision
+**
+** Description Send connection collision event to upper layer if registered
+**
+** Returns TRUE if sent out to upper layer,
+** FALSE if BTM_BUSY_LEVEL_CHANGE_INCLUDED == FALSE, or no one
+** needs the notification.
+**
+** Note: Function only used if BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE
+**
+*******************************************************************************/
+BOOLEAN btm_acl_notif_conn_collision (BD_ADDR bda)
+{
+#if (BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE)
+ tBTM_BL_EVENT_DATA evt_data;
+
+ /* Report possible collision to the upper layer. */
+ if (btm_cb.p_bl_changed_cb)
+ {
+ BTM_TRACE_DEBUG6 ("btm_acl_notif_conn_collision: RemBdAddr: %02x%02x%02x%02x%02x%02x",
+ bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
+
+ evt_data.event = BTM_BL_COLLISION_EVT;
+ evt_data.conn.p_bda = bda;
+ (*btm_cb.p_bl_changed_cb)(&evt_data);
+ return TRUE;
+ }
+ else
+ return FALSE;
+#else
+ return FALSE;
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function btm_acl_chk_peer_pkt_type_support
+**
+** Description Check if peer supports requested packets
+**
+*******************************************************************************/
+void btm_acl_chk_peer_pkt_type_support (tACL_CONN *p, UINT16 *p_pkt_type)
+{
+ /* 3 and 5 slot packets? */
+ if (!HCI_3_SLOT_PACKETS_SUPPORTED(p->features))
+ *p_pkt_type &= ~(BTM_ACL_PKT_TYPES_MASK_DH3 +BTM_ACL_PKT_TYPES_MASK_DM3);
+
+ if (!HCI_5_SLOT_PACKETS_SUPPORTED(p->features))
+ *p_pkt_type &= ~(BTM_ACL_PKT_TYPES_MASK_DH5 + BTM_ACL_PKT_TYPES_MASK_DM5);
+
+ /* If HCI version > 2.0, then also check EDR packet types */
+ if (btm_cb.devcb.local_version.hci_version >= HCI_PROTO_VERSION_2_0)
+ {
+ /* 2 and 3 MPS support? */
+ if (!HCI_EDR_ACL_2MPS_SUPPORTED(p->features))
+ /* Not supported. Add 'not_supported' mask for all 2MPS packet types */
+ *p_pkt_type |= (BTM_ACL_PKT_TYPES_MASK_NO_2_DH1 + BTM_ACL_PKT_TYPES_MASK_NO_2_DH3 + BTM_ACL_PKT_TYPES_MASK_NO_2_DH5);
+
+ if (!HCI_EDR_ACL_3MPS_SUPPORTED(p->features))
+ /* Not supported. Add 'not_supported' mask for all 3MPS packet types */
+ *p_pkt_type |= (BTM_ACL_PKT_TYPES_MASK_NO_3_DH1 + BTM_ACL_PKT_TYPES_MASK_NO_3_DH3 + BTM_ACL_PKT_TYPES_MASK_NO_3_DH5);
+
+ /* EDR 3 and 5 slot support? */
+ if (HCI_EDR_ACL_2MPS_SUPPORTED(p->features) || HCI_EDR_ACL_3MPS_SUPPORTED(p->features))
+ {
+ if (!HCI_3_SLOT_EDR_ACL_SUPPORTED(p->features))
+ /* Not supported. Add 'not_supported' mask for all 3-slot EDR packet types */
+ *p_pkt_type |= (BTM_ACL_PKT_TYPES_MASK_NO_2_DH3 + BTM_ACL_PKT_TYPES_MASK_NO_3_DH3);
+
+ if (!HCI_5_SLOT_EDR_ACL_SUPPORTED(p->features))
+ /* Not supported. Add 'not_supported' mask for all 5-slot EDR packet types */
+ *p_pkt_type |= (BTM_ACL_PKT_TYPES_MASK_NO_2_DH5 + BTM_ACL_PKT_TYPES_MASK_NO_3_DH5);
+ }
+ }
+}
diff --git a/stack/btm/btm_ble.c b/stack/btm/btm_ble.c
new file mode 100644
index 0000000..e34b8e2
--- /dev/null
+++ b/stack/btm/btm_ble.c
@@ -0,0 +1,1888 @@
+/*****************************************************************************
+**
+** Name: btm_ble.c
+**
+** Description: This file contains functions for BLE device control utilities,
+** and LE security functions.
+**
+**
+**
+** Copyright (c) 1999-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+
+#include <string.h>
+
+#include "bt_types.h"
+#include "hcimsgs.h"
+#include "btu.h"
+#include "btm_int.h"
+#include "btm_ble_api.h"
+#include "smp_api.h"
+
+#if SMP_INCLUDED == TRUE
+extern BOOLEAN AES_CMAC ( BT_OCTET16 key, UINT8 *input, UINT16 length, UINT16 tlen, UINT8 *p_signature);
+extern void smp_link_encrypted(BD_ADDR bda, UINT8 encr_enable);
+extern BOOLEAN smp_proc_ltk_request(BD_ADDR bda);
+#endif
+
+static void btm_ble_update_active_bgconn_scan_params(void);
+
+/*******************************************************************************/
+/* External Function to be called by other modules */
+/*******************************************************************************/
+/********************************************************
+**
+** Function BTM_SecAddBleDevice
+**
+** Description Add/modify device. This function will be normally called
+** during host startup to restore all required information
+** for a LE device stored in the NVRAM.
+**
+** Parameters: bd_addr - BD address of the peer
+** bd_name - Name of the peer device. NULL if unknown.
+** dev_type - Remote device's device type.
+** addr_type - LE device address type.
+**
+** Returns TRUE if added OK, else FALSE
+**
+*******************************************************************************/
+BOOLEAN BTM_SecAddBleDevice (BD_ADDR bd_addr, BD_NAME bd_name, tBT_DEVICE_TYPE dev_type,
+ tBLE_ADDR_TYPE addr_type)
+{
+#if BLE_INCLUDED == TRUE
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ UINT8 i = 0;
+ tBTM_INQ_INFO *p_info=NULL;
+
+ BTM_TRACE_DEBUG1 ("BTM_SecAddBleDevice dev_type=0x%x", dev_type);
+ p_dev_rec = btm_find_dev (bd_addr);
+
+ if (!p_dev_rec)
+ {
+ BTM_TRACE_DEBUG0("Add a new device");
+
+ /* There is no device record, allocate one.
+ * If we can not find an empty spot for this one, let it fail. */
+ for (i = 0; i < BTM_SEC_MAX_DEVICE_RECORDS; i++)
+ {
+ if (!(btm_cb.sec_dev_rec[i].sec_flags & BTM_SEC_IN_USE))
+ {
+ BTM_TRACE_DEBUG1 ("allocate a new dev rec idx=0x%x ", i );
+ p_dev_rec = &btm_cb.sec_dev_rec[i];
+
+ /* Mark this record as in use and initialize */
+ memset (p_dev_rec, 0, sizeof (tBTM_SEC_DEV_REC));
+ p_dev_rec->sec_flags = BTM_SEC_IN_USE;
+ memcpy (p_dev_rec->bd_addr, bd_addr, BD_ADDR_LEN);
+ p_dev_rec->hci_handle = BTM_GetHCIConnHandle (bd_addr);
+
+ /* update conn params, use default value for background connection params */
+ p_dev_rec->conn_params.min_conn_int =
+ p_dev_rec->conn_params.max_conn_int =
+ p_dev_rec->conn_params.supervision_tout =
+ p_dev_rec->conn_params.slave_latency = BTM_BLE_CONN_PARAM_UNDEF;
+
+ BTM_TRACE_DEBUG1 ("hci_handl=0x%x ", p_dev_rec->hci_handle );
+ break;
+ }
+ }
+
+ if (!p_dev_rec)
+ return(FALSE);
+ }
+ else
+ {
+ BTM_TRACE_DEBUG0("Device already exist");
+ }
+
+ memset(p_dev_rec->sec_bd_name, 0, sizeof(tBTM_BD_NAME));
+
+ if (bd_name && bd_name[0])
+ {
+ p_dev_rec->sec_flags |= BTM_SEC_NAME_KNOWN;
+ BCM_STRNCPY_S ((char *)p_dev_rec->sec_bd_name, sizeof (p_dev_rec->sec_bd_name),
+ (char *)bd_name, BTM_MAX_REM_BD_NAME_LEN);
+ }
+ p_dev_rec->device_type = dev_type;
+ p_dev_rec->ble.ble_addr_type = addr_type;
+ BTM_TRACE_DEBUG3 ("p_dev_rec->device_type =0x%x addr_type=0x%x sec_flags=0x%x",
+ dev_type, addr_type, p_dev_rec->sec_flags);
+
+ /* sync up with the Inq Data base*/
+ p_info = BTM_InqDbRead(bd_addr);
+ if (p_info)
+ {
+ p_info->results.ble_addr_type = p_dev_rec->ble.ble_addr_type ;
+ p_info->results.device_type = p_dev_rec->device_type;
+ BTM_TRACE_DEBUG2 ("InqDb device_type =0x%x addr_type=0x%x",
+ p_info->results.device_type, p_info->results.ble_addr_type);
+ }
+
+#endif
+ return(TRUE);
+}
+
+/*******************************************************************************
+**
+** Function BTM_SecAddBleKey
+**
+** Description Add/modify LE device information. This function will be
+** normally called during host startup to restore all required
+** information stored in the NVRAM.
+**
+** Parameters: bd_addr - BD address of the peer
+** p_le_key - LE key values.
+** key_type - LE SMP key type.
+*
+** Returns TRUE if added OK, else FALSE
+**
+*******************************************************************************/
+BOOLEAN BTM_SecAddBleKey (BD_ADDR bd_addr, tBTM_LE_KEY_VALUE *p_le_key, tBTM_LE_KEY_TYPE key_type)
+{
+#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE)
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ BTM_TRACE_DEBUG0 ("BTM_SecAddBleKey");
+ p_dev_rec = btm_find_dev (bd_addr);
+ if (!p_dev_rec || !p_le_key ||
+ (key_type != BTM_LE_KEY_PENC && key_type != BTM_LE_KEY_PID &&
+ key_type != BTM_LE_KEY_PCSRK && key_type != BTM_LE_KEY_LENC))
+ {
+ BTM_TRACE_WARNING3 ("BTM_SecAddLeKey() No BT Link Key, Wrong Type, or No Device record \
+ for bdaddr: %08x%04x, Type: %d",
+ (bd_addr[0]<<24)+(bd_addr[1]<<16)+(bd_addr[2]<<8)+bd_addr[3],
+ (bd_addr[4]<<8)+bd_addr[5], key_type);
+ return(FALSE);
+ }
+
+ BTM_TRACE_DEBUG3 ("BTM_SecAddLeKey() BDA: %08x%04x, Type: 0x%02x",
+ (bd_addr[0]<<24)+(bd_addr[1]<<16)+(bd_addr[2]<<8)+bd_addr[3],
+ (bd_addr[4]<<8)+bd_addr[5], key_type);
+
+ if (key_type == BTM_LE_KEY_PENC || key_type == BTM_LE_KEY_PID ||
+ key_type == BTM_LE_KEY_PCSRK || key_type == BTM_LE_KEY_LENC ||
+ key_type == BTM_LE_KEY_LCSRK)
+ {
+ btm_sec_save_le_key (bd_addr, key_type, p_le_key, FALSE);
+ }
+
+#endif
+
+ return(TRUE);
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleLoadLocalKeys
+**
+** Description Local local identity key, encryption root or sign counter.
+**
+** Parameters: key_type: type of key, can be BTM_BLE_KEY_TYPE_ID, BTM_BLE_KEY_TYPE_ER
+** or BTM_BLE_KEY_TYPE_COUNTER.
+** p_key: pointer to the key.
+*
+** Returns non2.
+**
+*******************************************************************************/
+void BTM_BleLoadLocalKeys(UINT8 key_type, tBTM_BLE_LOCAL_KEYS *p_key)
+{
+#if BLE_INCLUDED == TRUE
+ tBTM_DEVCB *p_devcb = &btm_cb.devcb;
+ BTM_TRACE_DEBUG0 ("BTM_BleLoadLocalKeys");
+ if (p_key != NULL)
+ {
+ switch (key_type)
+ {
+ case BTM_BLE_KEY_TYPE_ID:
+ memcpy(&p_devcb->id_keys, &p_key->id_keys, sizeof(tBTM_BLE_LOCAL_ID_KEYS));
+ break;
+
+ case BTM_BLE_KEY_TYPE_ER:
+ memcpy(p_devcb->er, p_key->er, sizeof(BT_OCTET16));
+ break;
+
+ default:
+ BTM_TRACE_ERROR1("unknow local key type: %d", key_type);
+ break;
+ }
+ }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function BTM_GetDeviceEncRoot
+**
+** Description This function is called to read the local device encryption
+** root.
+**
+** Returns void
+** the local device ER is copied into er
+**
+*******************************************************************************/
+void BTM_GetDeviceEncRoot (BT_OCTET16 er)
+{
+ BTM_TRACE_DEBUG0 ("BTM_GetDeviceEncRoot");
+
+#if BLE_INCLUDED == TRUE
+ memcpy (er, btm_cb.devcb.er, BT_OCTET16_LEN);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function BTM_GetDeviceIDRoot
+**
+** Description This function is called to read the local device identity
+** root.
+**
+** Returns void
+** the local device IR is copied into irk
+**
+*******************************************************************************/
+void BTM_GetDeviceIDRoot (BT_OCTET16 irk)
+{
+ BTM_TRACE_DEBUG0 ("BTM_GetDeviceIDRoot ");
+
+#if BLE_INCLUDED == TRUE
+ memcpy (irk, btm_cb.devcb.id_keys.irk, BT_OCTET16_LEN);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function BTM_GetDeviceDHK
+**
+** Description This function is called to read the local device DHK.
+**
+** Returns void
+** the local device DHK is copied into dhk
+**
+*******************************************************************************/
+void BTM_GetDeviceDHK (BT_OCTET16 dhk)
+{
+#if BLE_INCLUDED == TRUE
+ BTM_TRACE_DEBUG0 ("BTM_GetDeviceDHK");
+ memcpy (dhk, btm_cb.devcb.id_keys.dhk, BT_OCTET16_LEN);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function BTM_ReadConnectionAddr
+**
+** Description This function is called to set the local device random address
+** .
+**
+** Returns void
+**
+*******************************************************************************/
+void BTM_ReadConnectionAddr (BD_ADDR conn_addr)
+{
+#if BLE_INCLUDED == TRUE
+ BTM_TRACE_DEBUG0 ("BTM_ReadConnectionAddr");
+ if (btm_cb.ble_ctr_cb.inq_var.own_addr_type == BLE_ADDR_PUBLIC)
+ {
+ BTM_GetLocalDeviceAddr(conn_addr);
+ }
+ else
+ {
+ memcpy (conn_addr, btm_cb.ble_ctr_cb.addr_mgnt_cb.private_addr, BD_ADDR_LEN);
+ }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function BTM_SecurityGrant
+**
+** Description This function is called to grant security process.
+**
+** Parameters bd_addr - peer device bd address.
+** res - result of the operation BTM_SUCCESS if success.
+** Otherwise, BTM_REPEATED_ATTEMPTS is too many attempts.
+**
+** Returns None
+**
+*******************************************************************************/
+void BTM_SecurityGrant(BD_ADDR bd_addr, UINT8 res)
+{
+#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE)
+ tSMP_STATUS res_smp = (res == BTM_SUCCESS) ? SMP_SUCCESS : SMP_REPEATED_ATTEMPTS;
+ BTM_TRACE_DEBUG0 ("BTM_SecurityGrant");
+ SMP_SecurityGrant(bd_addr, res_smp);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function BTM_BlePasskeyReply
+**
+** Description This function is called after Security Manager submitted
+** passkey request to the application.
+**
+** Parameters: bd_addr - Address of the device for which passkey was requested
+** res - result of the operation BTM_SUCCESS if success
+** key_len - length in bytes of the Passkey
+** p_passkey - pointer to array with the passkey
+** trusted_mask - bitwise OR of trusted services (array of UINT32)
+**
+*******************************************************************************/
+void BTM_BlePasskeyReply (BD_ADDR bd_addr, UINT8 res, UINT32 passkey)
+{
+#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE)
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr);
+ tSMP_STATUS res_smp = (res == BTM_SUCCESS) ? SMP_SUCCESS : SMP_PASSKEY_ENTRY_FAIL;
+
+ p_dev_rec->sec_flags |= BTM_SEC_LINK_KEY_AUTHED;
+ BTM_TRACE_DEBUG0 ("BTM_BlePasskeyReply");
+ SMP_PasskeyReply(bd_addr, res_smp, passkey);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleOobDataReply
+**
+** Description This function is called to provide the OOB data for
+** SMP in response to BTM_LE_OOB_REQ_EVT
+**
+** Parameters: bd_addr - Address of the peer device
+** res - result of the operation SMP_SUCCESS if success
+** p_data - simple pairing Randomizer C.
+**
+*******************************************************************************/
+void BTM_BleOobDataReply(BD_ADDR bd_addr, UINT8 res, UINT8 len, UINT8 *p_data)
+{
+#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE)
+ tSMP_STATUS res_smp = (res == BTM_SUCCESS) ? SMP_SUCCESS : SMP_OOB_FAIL;
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr);
+
+ BTM_TRACE_DEBUG0 ("BTM_BleOobDataReply");
+ p_dev_rec->sec_flags |= BTM_SEC_LINK_KEY_AUTHED;
+ SMP_OobDataReply(bd_addr, res_smp, len, p_data);
+#endif
+}
+
+/******************************************************************************
+**
+** Function BTM_BleSetConnScanParams
+**
+** Description Set scan parameter used in BLE connection request
+**
+** Parameters: scan_interval: scan interval
+** scan_window: scan window
+**
+** Returns void
+**
+*******************************************************************************/
+void BTM_BleSetConnScanParams (UINT16 scan_interval, UINT16 scan_window)
+{
+#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE)
+ tBTM_BLE_CB *p_ble_cb = &btm_cb.ble_ctr_cb;
+ BOOLEAN new_param = FALSE;
+
+ if (BTM_BLE_VALID_PRAM(scan_interval, BTM_BLE_SCAN_INT_MIN, BTM_BLE_SCAN_INT_MAX) &&
+ BTM_BLE_VALID_PRAM(scan_window, BTM_BLE_SCAN_WIN_MIN, BTM_BLE_SCAN_WIN_MAX))
+ {
+ btu_stop_timer(&p_ble_cb->scan_param_idle_timer);
+
+ if (p_ble_cb->scan_int != scan_interval)
+ {
+ p_ble_cb->scan_int = scan_interval;
+ new_param = TRUE;
+ }
+
+ if (p_ble_cb->scan_win != scan_window)
+ {
+ p_ble_cb->scan_win = scan_window;
+ new_param = TRUE;
+ }
+
+ if (new_param)
+ btm_ble_update_active_bgconn_scan_params();
+ }
+ else
+ {
+ BTM_TRACE_ERROR0("Illegal Connection Scan Parameters");
+ }
+#endif
+}
+
+/********************************************************
+**
+** Function BTM_BleSetPrefConnParams
+**
+** Description Set a peripheral's preferred connection parameters
+**
+** Parameters: bd_addr - BD address of the peripheral
+** scan_interval: scan interval
+** scan_window: scan window
+** min_conn_int - minimum preferred connection interval
+** max_conn_int - maximum preferred connection interval
+** slave_latency - preferred slave latency
+** supervision_tout - preferred supervision timeout
+**
+** Returns void
+**
+*******************************************************************************/
+void BTM_BleSetPrefConnParams (BD_ADDR bd_addr,
+ UINT16 min_conn_int, UINT16 max_conn_int,
+ UINT16 slave_latency, UINT16 supervision_tout)
+{
+#if BLE_INCLUDED == TRUE
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr);
+
+ BTM_TRACE_API4 ("BTM_BleSetPrefConnParams min: %u max: %u latency: %u \
+ tout: %u",
+ min_conn_int, max_conn_int, slave_latency, supervision_tout);
+
+ if (BTM_BLE_VALID_PRAM(min_conn_int, BTM_BLE_CONN_INT_MIN, BTM_BLE_CONN_INT_MAX) &&
+ BTM_BLE_VALID_PRAM(max_conn_int, BTM_BLE_CONN_INT_MIN, BTM_BLE_CONN_INT_MAX) &&
+ BTM_BLE_VALID_PRAM(supervision_tout, BTM_BLE_CONN_SUP_TOUT_MIN, BTM_BLE_CONN_SUP_TOUT_MAX) &&
+ slave_latency <= BTM_BLE_CONN_LATENCY_MAX)
+ {
+ if (p_dev_rec)
+ {
+ /* expect conn int and stout and slave latency to be updated all together */
+ if (min_conn_int != BTM_BLE_CONN_PARAM_UNDEF || max_conn_int != BTM_BLE_CONN_PARAM_UNDEF)
+ {
+ if (min_conn_int != BTM_BLE_CONN_PARAM_UNDEF)
+ p_dev_rec->conn_params.min_conn_int = min_conn_int;
+ else
+ p_dev_rec->conn_params.min_conn_int = max_conn_int;
+
+ if (max_conn_int != BTM_BLE_CONN_PARAM_UNDEF)
+ p_dev_rec->conn_params.max_conn_int = max_conn_int;
+ else
+ p_dev_rec->conn_params.max_conn_int = min_conn_int;
+
+ if (slave_latency != BTM_BLE_CONN_PARAM_UNDEF)
+ p_dev_rec->conn_params.slave_latency = slave_latency;
+ else
+ p_dev_rec->conn_params.slave_latency = BTM_BLE_CONN_SLAVE_LATENCY_DEF;
+
+ if (supervision_tout != BTM_BLE_CONN_PARAM_UNDEF)
+ p_dev_rec->conn_params.supervision_tout = supervision_tout;
+ else
+ p_dev_rec->conn_params.slave_latency = BTM_BLE_CONN_TIMEOUT_DEF;
+
+ }
+
+ }
+ else
+ {
+ BTM_TRACE_ERROR0("Unknown Device, setting rejected");
+ }
+ }
+ else
+ {
+ BTM_TRACE_ERROR0("Illegal Connection Parameters");
+ }
+#endif /* BLE_INCLUDED */
+}
+
+/*******************************************************************************
+**
+** Function BTM_ReadDevInfo
+**
+** Description This function is called to read the device/address type
+** of BD address.
+**
+** Parameter remote_bda: remote device address
+** p_dev_type: output parameter to read the device type.
+** p_addr_type: output parameter to read the address type.
+**
+*******************************************************************************/
+void BTM_ReadDevInfo (BD_ADDR remote_bda, tBT_DEVICE_TYPE *p_dev_type, tBLE_ADDR_TYPE *p_addr_type)
+{
+#if BLE_INCLUDED == TRUE
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (remote_bda);
+ tBTM_INQ_INFO *p_inq_info = BTM_InqDbRead(remote_bda);
+
+ *p_dev_type = BT_DEVICE_TYPE_BREDR;
+ *p_addr_type = BLE_ADDR_PUBLIC;
+
+ if (!p_dev_rec)
+ {
+ /* Check with the BT manager if details about remote device are known */
+ if (p_inq_info != NULL)
+ {
+ *p_dev_type = p_inq_info->results.device_type ;
+ *p_addr_type = p_inq_info->results.ble_addr_type;
+ }
+ /* unknown device, assume BR/EDR */
+ }
+ else /* there is a security device record exisitng */
+ {
+ /* new inquiry result, overwrite device type in security device record */
+ if (p_inq_info)
+ {
+ p_dev_rec->device_type = p_inq_info->results.device_type;
+ p_dev_rec->ble.ble_addr_type = p_inq_info->results.ble_addr_type;
+ }
+ *p_dev_type = p_dev_rec->device_type;
+ *p_addr_type = p_dev_rec->ble.ble_addr_type;
+
+ }
+
+ BTM_TRACE_DEBUG2 ("btm_find_dev_type - device_type = %d addr_type = %d", *p_dev_type , *p_addr_type);
+#endif
+
+ return;
+}
+
+
+/*******************************************************************************
+** Internal Functions
+*******************************************************************************/
+#if BLE_INCLUDED == TRUE
+
+/*******************************************************************************
+**
+** Function btm_ble_update_active_bgconn_scan_params
+**
+** Description This function is called to update the scan parameter if background
+** connection has been active.
+**
+*******************************************************************************/
+static void btm_ble_update_active_bgconn_scan_params(void)
+{
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+ tBTM_BLE_SEL_CBACK *p_select_cback;
+
+ /* if active , cancel and restart and apply the params */
+ if (p_cb->bg_conn_state == BLE_BG_CONN_ACTIVE)
+ {
+ if (p_cb->bg_conn_type == BTM_BLE_CONN_AUTO)
+ {
+ if (btm_ble_start_auto_conn(FALSE))
+ btm_ble_start_auto_conn(TRUE);
+ }
+ else if (p_cb->bg_conn_type == BTM_BLE_CONN_SELECTIVE)
+ {
+ p_select_cback = p_cb->p_select_cback;
+ if (btm_ble_start_select_conn(FALSE, NULL))
+ btm_ble_start_select_conn(TRUE, p_select_cback);
+ }
+ }
+ return;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_check_link_type
+**
+** Description This function is to check the link type is BLE or BR/EDR.
+**
+** Returns TRUE if BLE link; FALSE if BR/EDR.
+**
+*******************************************************************************/
+BOOLEAN btm_ble_check_link_type (BD_ADDR bd_addr)
+{
+ tACL_CONN *p;
+ BTM_TRACE_DEBUG0 ("btm_ble_check_link_type");
+ if ((p = btm_bda_to_acl(bd_addr)) != NULL)
+ return p->is_le_link;
+ else
+ return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_rand_enc_complete
+**
+** Description This function is the callback functions for HCI_Rand command
+** and HCI_Encrypt command is completed.
+** This message is received from the HCI.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_rand_enc_complete (UINT8 *p, UINT16 op_code, tBTM_RAND_ENC_CB *p_enc_cplt_cback)
+{
+ tBTM_RAND_ENC params;
+ UINT8 *p_dest = params.param_buf;
+
+ BTM_TRACE_DEBUG0 ("btm_ble_rand_enc_complete");
+
+ memset(&params, 0, sizeof(tBTM_RAND_ENC));
+
+ /* If there was a callback address for vcs complete, call it */
+ if (p_enc_cplt_cback && p)
+ {
+ /* Pass paramters to the callback function */
+ STREAM_TO_UINT8(params.status, p); /* command status */
+
+ if (params.status == HCI_SUCCESS)
+ {
+ params.opcode = op_code;
+
+ if (op_code == HCI_BLE_RAND)
+ params.param_len = BT_OCTET8_LEN;
+ else
+ params.param_len = BT_OCTET16_LEN;
+
+ memcpy(p_dest, p, params.param_len); /* Fetch return info from HCI event message */
+ }
+ if (p_enc_cplt_cback)
+ (*p_enc_cplt_cback)(&params); /* Call the Encryption complete callback function */
+ }
+}
+
+
+#if (SMP_INCLUDED == TRUE)
+
+/*******************************************************************************
+**
+** Function btm_ble_get_enc_key_type
+**
+** Description This function is to increment local sign counter
+** Returns None
+**
+*******************************************************************************/
+void btm_ble_increment_sign_ctr(BD_ADDR bd_addr, BOOLEAN is_local )
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+
+ BTM_TRACE_DEBUG1 ("btm_ble_increment_sign_ctr is_local=%d", is_local);
+
+ if ((p_dev_rec = btm_find_dev (bd_addr)) != NULL)
+ {
+ if (is_local)
+ p_dev_rec->ble.keys.local_counter++;
+ else
+ p_dev_rec->ble.keys.counter++;
+ BTM_TRACE_DEBUG3 ("is_local=%d local sign counter=%d peer sign counter=%d",
+ is_local,
+ p_dev_rec->ble.keys.local_counter,
+ p_dev_rec->ble.keys.counter);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_get_enc_key_type
+**
+** Description This function is to get the BLE key type that has been exchanged
+** in betweem local device and peer device.
+**
+** Returns p_key_type: output parameter to carry the key type value.
+**
+*******************************************************************************/
+BOOLEAN btm_ble_get_enc_key_type(BD_ADDR bd_addr, UINT8 *p_key_types)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+
+ BTM_TRACE_DEBUG0 ("btm_ble_get_enc_key_type");
+
+ if ((p_dev_rec = btm_find_dev (bd_addr)) != NULL)
+ {
+ *p_key_types = p_dev_rec->ble.key_type;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function btm_get_local_div
+**
+** Description This function is called to read the local DIV
+**
+** Returns TURE - if a valid DIV is availavle
+*******************************************************************************/
+BOOLEAN btm_get_local_div (BD_ADDR bd_addr, UINT16 *p_div)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ BOOLEAN status = FALSE;
+ BTM_TRACE_DEBUG0 ("btm_get_local_div");
+
+ BTM_TRACE_DEBUG6("bd_addr:%02x-%02x-%02x-%02x-%02x-%02x",
+ bd_addr[0],bd_addr[1],
+ bd_addr[2],bd_addr[3],
+ bd_addr[4],bd_addr[5]);
+
+ p_dev_rec = btm_find_dev (bd_addr);
+
+ if (p_dev_rec && p_dev_rec->ble.keys.div)
+ {
+ status = TRUE;
+ *p_div = p_dev_rec->ble.keys.div;
+ }
+ BTM_TRACE_DEBUG2 ("btm_get_local_div status=%d (1-OK) DIV=0x%x", status, *p_div);
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_save_le_key
+**
+** Description This function is called by the SMP to update
+** an BLE key. SMP is internal, whereas all the keys shall
+** be sent to the application. The function is also called
+** when application passes ble key stored in NVRAM to the btm_sec.
+** pass_to_application parameter is false in this case.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sec_save_le_key(BD_ADDR bd_addr, tBTM_LE_KEY_TYPE key_type, tBTM_LE_KEY_VALUE *p_keys,
+ BOOLEAN pass_to_application)
+{
+ tBTM_SEC_DEV_REC *p_rec;
+ tBTM_LE_EVT_DATA cb_data;
+
+ BTM_TRACE_DEBUG2 ("btm_sec_save_le_key key_type=0x%x pass_to_application=%d",key_type, pass_to_application);
+ /* Store the updated key in the device database */
+
+ BTM_TRACE_DEBUG6("bd_addr:%02x-%02x-%02x-%02x-%02x-%02x",
+ bd_addr[0],bd_addr[1],
+ bd_addr[2],bd_addr[3],
+ bd_addr[4],bd_addr[5]);
+
+ if ((p_rec = btm_find_dev (bd_addr)) != NULL && p_keys)
+ {
+ switch (key_type)
+ {
+ case BTM_LE_KEY_PENC:
+ memcpy(p_rec->ble.keys.ltk, p_keys->penc_key.ltk, BT_OCTET16_LEN);
+ memcpy(p_rec->ble.keys.rand, p_keys->penc_key.rand, BT_OCTET8_LEN);
+ p_rec->ble.keys.sec_level = p_keys->penc_key.sec_level;
+ p_rec->ble.keys.ediv = p_keys->penc_key.ediv;
+ p_rec->ble.keys.key_size = p_keys->penc_key.key_size;
+ p_rec->ble.key_type |= BTM_LE_KEY_PENC;
+ p_rec->sec_flags |= BTM_SEC_LINK_KEY_KNOWN;
+ if (p_keys->penc_key.sec_level == SMP_SEC_AUTHENTICATED)
+ p_rec->sec_flags |= BTM_SEC_LINK_KEY_AUTHED;
+ else
+ p_rec->sec_flags &= ~BTM_SEC_LINK_KEY_AUTHED;
+ BTM_TRACE_DEBUG3("BTM_LE_KEY_PENC key_type=0x%x sec_flags=0x%x sec_leve=0x%x",
+ p_rec->ble.key_type,
+ p_rec->sec_flags,
+ p_rec->ble.keys.sec_level);
+ break;
+
+ case BTM_LE_KEY_PID:
+ memcpy(p_rec->ble.keys.irk, p_keys->pid_key, BT_OCTET16_LEN);
+ p_rec->ble.key_type |= BTM_LE_KEY_PID;
+ BTM_TRACE_DEBUG1("BTM_LE_KEY_PID key_type=0x%x save peer IRK", p_rec->ble.key_type);
+ break;
+
+ case BTM_LE_KEY_PCSRK:
+ memcpy(p_rec->ble.keys.csrk, p_keys->pcsrk_key.csrk, BT_OCTET16_LEN);
+ p_rec->ble.keys.srk_sec_level = p_keys->pcsrk_key.sec_level;
+ p_rec->ble.keys.counter = p_keys->pcsrk_key.counter;
+ p_rec->ble.key_type |= BTM_LE_KEY_PCSRK;
+ p_rec->sec_flags |= BTM_SEC_LINK_KEY_KNOWN;
+ if ( p_keys->pcsrk_key.sec_level== SMP_SEC_AUTHENTICATED)
+ p_rec->sec_flags |= BTM_SEC_LINK_KEY_AUTHED;
+ else
+ p_rec->sec_flags &= ~BTM_SEC_LINK_KEY_AUTHED;
+
+ BTM_TRACE_DEBUG4("BTM_LE_KEY_PCSRK key_type=0x%x sec_flags=0x%x sec_level=0x%x peer_counter=%d",
+ p_rec->ble.key_type,
+ p_rec->sec_flags,
+ p_rec->ble.keys.srk_sec_level,
+ p_rec->ble.keys.counter );
+ break;
+
+ case BTM_LE_KEY_LENC:
+ p_rec->ble.keys.div = p_keys->lenc_key.div; /* update DIV */
+ p_rec->ble.keys.sec_level = p_keys->lenc_key.sec_level;
+ p_rec->ble.keys.key_size = p_keys->lenc_key.key_size;
+ p_rec->ble.key_type |= BTM_LE_KEY_LENC;
+
+ BTM_TRACE_DEBUG4("BTM_LE_KEY_LENC key_type=0x%x DIV=0x%x key_size=0x%x sec_level=0x%x",
+ p_rec->ble.key_type,
+ p_rec->ble.keys.div,
+ p_rec->ble.keys.key_size,
+ p_rec->ble.keys.sec_level );
+ break;
+
+ case BTM_LE_KEY_LCSRK:/* local CSRK has been delivered */
+ p_rec->ble.keys.div = p_keys->lcsrk_key.div; /* update DIV */
+ p_rec->ble.keys.local_csrk_sec_level = p_keys->lcsrk_key.sec_level;
+ p_rec->ble.keys.local_counter = p_keys->lcsrk_key.counter;
+ p_rec->ble.key_type |= BTM_LE_KEY_LCSRK;
+ BTM_TRACE_DEBUG4("BTM_LE_KEY_LCSRK key_type=0x%x DIV=0x%x scrk_sec_level=0x%x local_counter=%d",
+ p_rec->ble.key_type,
+ p_rec->ble.keys.div,
+ p_rec->ble.keys.local_csrk_sec_level,
+ p_rec->ble.keys.local_counter );
+ break;
+
+ default:
+ BTM_TRACE_WARNING1("btm_sec_save_le_key (Bad key_type 0x%02x)", key_type);
+ return;
+ }
+
+ BTM_TRACE_DEBUG3 ("BLE key type 0x%02x updated for BDA: %08x%04x (btm_sec_save_le_key)", key_type,
+ (bd_addr[0]<<24)+(bd_addr[1]<<16)+(bd_addr[2]<<8)+bd_addr[3],
+ (bd_addr[4]<<8)+bd_addr[5]);
+
+ /* Notify the application that one of the BLE keys has been updated
+ If link key is in progress, it will get sent later.*/
+ if (pass_to_application && btm_cb.api.p_le_callback)
+ {
+ cb_data.key.p_key_value = p_keys;
+ cb_data.key.key_type = key_type;
+
+ (*btm_cb.api.p_le_callback) (BTM_LE_KEY_EVT, bd_addr, &cb_data);
+ }
+ return;
+ }
+
+ BTM_TRACE_WARNING3 ("BLE key type 0x%02x called for Unknown BDA or type: %08x%04x !! (btm_sec_save_le_key)", key_type,
+ (bd_addr[0]<<24)+(bd_addr[1]<<16)+(bd_addr[2]<<8)+bd_addr[3],
+ (bd_addr[4]<<8)+bd_addr[5]);
+
+ if (p_rec)
+ {
+ BTM_TRACE_DEBUG1 ("sec_flags=0x%x", p_rec->sec_flags);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_update_sec_key_size
+**
+** Description update the current lin kencryption key size
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_update_sec_key_size(BD_ADDR bd_addr, UINT8 enc_key_size)
+{
+ tBTM_SEC_DEV_REC *p_rec;
+
+ BTM_TRACE_DEBUG1("btm_ble_update_sec_key_size enc_key_size = %d", enc_key_size);
+
+ if ((p_rec = btm_find_dev (bd_addr)) != NULL )
+ {
+ p_rec->enc_key_size = enc_key_size;
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_read_sec_key_size
+**
+** Description update the current lin kencryption key size
+**
+** Returns void
+**
+*******************************************************************************/
+UINT8 btm_ble_read_sec_key_size(BD_ADDR bd_addr)
+{
+ tBTM_SEC_DEV_REC *p_rec;
+
+ if ((p_rec = btm_find_dev (bd_addr)) != NULL )
+ {
+ return p_rec->enc_key_size;
+ }
+ else
+ return 0;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_link_sec_check
+**
+** Description Check BLE link security level match.
+**
+** Returns TRUE: check is OK and the *p_sec_req_act contain the action
+**
+*******************************************************************************/
+void btm_ble_link_sec_check(BD_ADDR bd_addr, tBTM_LE_AUTH_REQ auth_req, tBTM_BLE_SEC_REQ_ACT *p_sec_req_act)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr);
+ UINT8 req_sec_level, cur_sec_level;
+
+ BTM_TRACE_DEBUG1 ("btm_ble_link_sec_check auth_req =0x%x", auth_req);
+
+ if (p_dev_rec == NULL)
+ {
+ BTM_TRACE_ERROR0 ("btm_ble_link_sec_check received for unknown device");
+ return;
+ }
+
+ if (p_dev_rec->sec_state == BTM_SEC_STATE_ENCRYPTING)
+ {
+ /* race condition: discard the security request while master is encrypting the link */
+ *p_sec_req_act = BTM_BLE_SEC_REQ_ACT_DISCARD;
+ }
+ else
+ {
+ req_sec_level = BTM_LE_SEC_UNAUTHENTICATE;
+ if ((auth_req == (BTM_LE_AUTH_REQ_BOND|BTM_LE_AUTH_REQ_MITM)) ||
+ (auth_req == (BTM_LE_AUTH_REQ_MITM)) )
+ {
+ req_sec_level = BTM_LE_SEC_AUTHENTICATED;
+ }
+
+ BTM_TRACE_DEBUG1 ("dev_rec sec_flags=0x%x", p_dev_rec->sec_flags);
+
+ /* currently encrpted */
+ if (p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED)
+ {
+ if (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_AUTHED)
+ cur_sec_level = BTM_LE_SEC_AUTHENTICATED;
+ else
+ cur_sec_level = BTM_LE_SEC_UNAUTHENTICATE;
+ }
+ else /* unencrypted link */
+ {
+ /* if bonded, get the key security level */
+ if (p_dev_rec->ble.key_type & BTM_LE_KEY_PENC)
+ cur_sec_level = p_dev_rec->ble.keys.sec_level;
+ else
+ cur_sec_level = BTM_LE_SEC_NONE;
+ }
+
+ if (cur_sec_level >= req_sec_level)
+ {
+ if (cur_sec_level == BTM_LE_SEC_NONE)
+ {
+ *p_sec_req_act = BTM_BLE_SEC_REQ_ACT_NONE;
+ }
+ else
+ {
+ /* To avoid re-encryption on an encrypted link for an equal condition encryption
+ if (p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED)
+ *p_sec_req_act = BTM_BLE_SEC_REQ_ACT_DISCARD;
+ else
+ */
+ *p_sec_req_act = BTM_BLE_SEC_REQ_ACT_ENCRYPT;
+ }
+ }
+ else
+ {
+ *p_sec_req_act = BTM_BLE_SEC_REQ_ACT_PAIR; /* start the pariring process to upgrade the keys*/
+ }
+ }
+
+ BTM_TRACE_DEBUG3("cur_sec_level=%d req_sec_level=%d sec_req_act=%d",
+ cur_sec_level,
+ req_sec_level,
+ *p_sec_req_act);
+
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_set_encryption
+**
+** Description This function is called to ensure that LE connection is
+** encrypted. Should be called only on an open connection.
+** Typically only needed for connections that first want to
+** bring up unencrypted links, then later encrypt them.
+**
+** Returns void
+** the local device ER is copied into er
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_set_encryption (BD_ADDR bd_addr, void *p_ref_data, UINT8 link_role)
+{
+ tBTM_STATUS cmd = BTM_NO_RESOURCES;
+ tBTM_BLE_SEC_ACT sec_act = *(tBTM_BLE_SEC_ACT *)p_ref_data ;
+ tBTM_SEC_DEV_REC *p_rec = btm_find_dev (bd_addr);
+
+ BTM_TRACE_DEBUG2 ("btm_ble_set_encryption sec_act=0x%x role_master=%d", sec_act, p_rec->role_master);
+
+ if (p_rec == NULL)
+ {
+ return(BTM_WRONG_MODE);
+ }
+
+ if (sec_act == BTM_BLE_SEC_ENCRYPT_MITM)
+ {
+ p_rec->security_required |= BTM_SEC_IN_MITM;
+ }
+
+ switch (sec_act)
+ {
+ case BTM_BLE_SEC_ENCRYPT:
+ if (link_role == BTM_ROLE_MASTER)
+ {
+ /* start link layer encryption using the security info stored */
+ btm_ble_start_encrypt(bd_addr, FALSE, NULL);
+ p_rec->sec_state = BTM_SEC_STATE_ENCRYPTING;
+ cmd = BTM_CMD_STARTED;
+ break;
+ }
+ /* if salve role then fall through to call SMP_Pair below which will send a
+ sec_request to request the master to encrypt the link */
+ case BTM_BLE_SEC_ENCRYPT_NO_MITM:
+ case BTM_BLE_SEC_ENCRYPT_MITM:
+
+ if (SMP_Pair(bd_addr) == SMP_STARTED)
+ {
+ cmd = BTM_CMD_STARTED;
+ p_rec->sec_state = BTM_SEC_STATE_AUTHENTICATING;
+ }
+ break;
+
+ default:
+ cmd = BTM_SUCCESS;
+ break;
+ }
+ return cmd;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_ltk_request
+**
+** Description This function is called when encryption request is received
+** on a slave device.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_ltk_request(UINT16 handle, UINT8 rand[8], UINT16 ediv)
+{
+ tBTM_CB *p_cb = &btm_cb;
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev_by_handle (handle);
+ BT_OCTET8 dummy_stk = {0};
+
+ BTM_TRACE_DEBUG0 ("btm_ble_ltk_request");
+
+ p_cb->ediv = ediv;
+
+ memcpy(p_cb->enc_rand, rand, BT_OCTET8_LEN);
+
+ if (!smp_proc_ltk_request(p_dev_rec->bd_addr))
+ btm_ble_ltk_request_reply(p_dev_rec->bd_addr, FALSE, dummy_stk);
+
+
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_start_encrypt
+**
+** Description This function is called to start LE encryption.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BOOLEAN btm_ble_start_encrypt(BD_ADDR bda, BOOLEAN use_stk, BT_OCTET16 stk)
+{
+ tBTM_CB *p_cb = &btm_cb;
+ tBTM_SEC_DEV_REC *p_rec = btm_find_dev (bda);
+ BT_OCTET8 dummy_rand = {0};
+
+ BTM_TRACE_DEBUG0 ("btm_ble_start_encrypt");
+
+ if (!p_rec ||
+ (p_rec && p_rec->sec_state == BTM_SEC_STATE_ENCRYPTING))
+ return FALSE;
+
+ if (p_rec->sec_state == BTM_SEC_STATE_IDLE)
+ p_rec->sec_state = BTM_SEC_STATE_ENCRYPTING;
+ p_cb->enc_handle = p_rec->hci_handle;
+
+ if (use_stk)
+ {
+ if (!btsnd_hcic_ble_start_enc(p_rec->hci_handle, dummy_rand, 0, stk))
+ return FALSE;
+ }
+ else
+ {
+ if (!btsnd_hcic_ble_start_enc(p_rec->hci_handle, p_rec->ble.keys.rand,
+ p_rec->ble.keys.ediv, p_rec->ble.keys.ltk))
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_link_encrypted
+**
+** Description This function is called when LE link encrption status is changed.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_link_encrypted(BD_ADDR bd_addr, UINT8 encr_enable)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr);
+
+ BTM_TRACE_DEBUG1 ("btm_ble_link_encrypted encr_enable=%d", encr_enable);
+
+ smp_link_encrypted(bd_addr, encr_enable);
+
+ if (p_dev_rec)
+ {
+ BTM_TRACE_DEBUG1(" p_dev_rec->sec_flags=0x%x", p_dev_rec->sec_flags);
+
+ if (encr_enable && p_dev_rec->enc_key_size == 0)
+ p_dev_rec->enc_key_size = p_dev_rec->ble.keys.key_size;
+
+ if (p_dev_rec->p_callback)
+ {
+ if (p_dev_rec->sec_state == BTM_SEC_STATE_ENCRYPTING)
+ {
+ if (encr_enable)
+ btm_sec_dev_rec_cback_event(p_dev_rec, BTM_SUCCESS);
+ else if (p_dev_rec->role_master)
+ btm_sec_dev_rec_cback_event(p_dev_rec, BTM_ERR_PROCESSING);
+ }
+ }
+ p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+ }
+}
+
+/*******************************************************************************
+** Function btm_enc_proc_ltk
+** Description send LTK reply when it's ready.
+*******************************************************************************/
+static void btm_enc_proc_ltk(tSMP_ENC *p)
+{
+ UINT8 i;
+ BTM_TRACE_DEBUG0 ("btm_enc_proc_ltk");
+ if (p && p->param_len == BT_OCTET16_LEN)
+ {
+ for (i = 0; i < (BT_OCTET16_LEN - btm_cb.key_size); i ++)
+ p->param_buf[BT_OCTET16_LEN - i - 1] = 0;
+ btsnd_hcic_ble_ltk_req_reply(btm_cb.enc_handle, p->param_buf);
+ }
+}
+
+/*******************************************************************************
+** Function btm_enc_proc_slave_y
+** Description calculate LTK when Y is ready
+*******************************************************************************/
+static void btm_enc_proc_slave_y(tSMP_ENC *p)
+{
+ UINT16 div, y;
+ UINT8 *pp = p->param_buf;
+ tBTM_CB *p_cb = &btm_cb;
+ tSMP_ENC output;
+ tBTM_SEC_DEV_REC *p_dev_rec;
+
+ BTM_TRACE_DEBUG0 ("btm_enc_proc_slave_y");
+ if (p != NULL)
+ {
+ STREAM_TO_UINT16(y, pp);
+
+ div = p_cb->ediv ^ y;
+ p_dev_rec = btm_find_dev_by_handle (p_cb->enc_handle);
+
+ if ( p_dev_rec &&
+ p_dev_rec->ble.keys.div == div )
+ {
+ BTM_TRACE_DEBUG0 ("LTK request OK");
+ /* calculating LTK , LTK = E er(div) */
+ SMP_Encrypt(p_cb->devcb.er, BT_OCTET16_LEN, (UINT8 *)&div, 2, &output);
+ btm_enc_proc_ltk(&output);
+ }
+ else
+ {
+ BTM_TRACE_DEBUG0 ("LTK request failed - send negative reply");
+ btsnd_hcic_ble_ltk_req_neg_reply(p_cb->enc_handle);
+ if (p_dev_rec)
+ btm_ble_link_encrypted(p_dev_rec->bd_addr, 0);
+
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_ltk_request_reply
+**
+** Description This function is called to send a LTK request reply on a slave
+** device.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_ltk_request_reply(BD_ADDR bda, BOOLEAN use_stk, BT_OCTET16 stk)
+{
+ tBTM_SEC_DEV_REC *p_rec = btm_find_dev (bda);
+ tBTM_CB *p_cb = &btm_cb;
+ tSMP_ENC output;
+
+ if (p_rec == NULL)
+ {
+ BTM_TRACE_ERROR0("btm_ble_ltk_request_reply received for unknown device");
+ return;
+ }
+
+ BTM_TRACE_DEBUG0 ("btm_ble_ltk_request_reply");
+ p_cb->enc_handle = p_rec->hci_handle;
+ p_cb->key_size = p_rec->ble.keys.key_size;
+
+ BTM_TRACE_ERROR1("key size = %d", p_rec->ble.keys.key_size);
+ if (use_stk)
+ {
+ btsnd_hcic_ble_ltk_req_reply(btm_cb.enc_handle, stk);
+ }
+ else /* calculate LTK using peer device */
+ {
+ /* generate Y= Encrypt(DHK, Rand) received from encrypt request */
+ SMP_Encrypt(p_cb->devcb.id_keys.dhk, BT_OCTET16_LEN, p_cb->enc_rand,
+ BT_OCTET8_LEN, &output);
+ btm_enc_proc_slave_y(&output);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_io_capabilities_req
+**
+** Description This function is called to handle SMP get IO capability request.
+**
+** Returns void
+**
+*******************************************************************************/
+UINT8 btm_ble_io_capabilities_req(tBTM_SEC_DEV_REC *p_dev_rec, tBTM_LE_IO_REQ *p_data)
+{
+ UINT8 callback_rc = BTM_SUCCESS;
+ BTM_TRACE_DEBUG0 ("btm_ble_io_capabilities_req");
+ if (btm_cb.api.p_le_callback)
+ {
+ /* the callback function implementation may change the IO capability... */
+ callback_rc = (*btm_cb.api.p_le_callback) (BTM_LE_IO_REQ_EVT, p_dev_rec->bd_addr, (tBTM_LE_EVT_DATA *)p_data);
+ }
+#if BTM_OOB_INCLUDED == TRUE
+ if ((callback_rc == BTM_SUCCESS) || (BTM_OOB_UNKNOWN != p_data->oob_data))
+#else
+ if (callback_rc == BTM_SUCCESS)
+#endif
+ {
+ p_data->auth_req &= BTM_LE_AUTH_REQ_MASK;
+
+ BTM_TRACE_DEBUG2 ("btm_ble_io_capabilities_req 1: p_dev_rec->security_required = %d auth_req:%d",
+ p_dev_rec->security_required, p_data->auth_req);
+ BTM_TRACE_DEBUG2 ("btm_ble_io_capabilities_req 2: i_keys=0x%x r_keys=0x%x (bit 0-LTK 1-IRK 2-CSRK)",
+ p_data->init_keys,
+ p_data->resp_keys);
+
+ /* if authentication requires MITM protection, put on the mask */
+ if (p_dev_rec->security_required & BTM_SEC_IN_MITM)
+ p_data->auth_req |= BTM_LE_AUTH_REQ_MITM;
+
+ if (!(p_data->auth_req & SMP_AUTH_BOND))
+ {
+ BTM_TRACE_DEBUG0("Non bonding: No keys should be exchanged");
+ p_data->init_keys = 0;
+ p_data->resp_keys = 0;
+ }
+
+ BTM_TRACE_DEBUG1 ("btm_ble_io_capabilities_req 3: auth_req:%d", p_data->auth_req);
+ BTM_TRACE_DEBUG2 ("btm_ble_io_capabilities_req 4: i_keys=0x%x r_keys=0x%x",
+ p_data->init_keys,
+ p_data->resp_keys);
+
+ BTM_TRACE_DEBUG2 ("btm_ble_io_capabilities_req 5: p_data->io_cap = %d auth_req:%d",
+ p_data->io_cap, p_data->auth_req);
+
+ /* remove MITM protection requirement if IO cap does not allow it */
+ if ((p_data->io_cap == BTM_IO_CAP_NONE) && p_data->oob_data == SMP_OOB_NONE)
+ p_data->auth_req &= ~BTM_LE_AUTH_REQ_MITM;
+
+ BTM_TRACE_DEBUG3 ("btm_ble_io_capabilities_req 6: IO_CAP:%d oob_data:%d auth_req:%d",
+ p_data->io_cap, p_data->oob_data, p_data->auth_req);
+ }
+ return callback_rc;
+}
+
+/*****************************************************************************
+** Function btm_proc_smp_cback
+**
+** Description This function is the SMP callback handler.
+**
+******************************************************************************/
+UINT8 btm_proc_smp_cback(tSMP_EVT event, BD_ADDR bd_addr, tSMP_EVT_DATA *p_data)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr);
+ UINT8 res;
+
+ BTM_TRACE_DEBUG1 ("btm_proc_smp_cback event = %d", event);
+
+ if (p_dev_rec != NULL)
+ {
+ switch (event)
+ {
+ case SMP_IO_CAP_REQ_EVT:
+ btm_ble_io_capabilities_req(p_dev_rec, (tBTM_LE_IO_REQ *)&p_data->io_req);
+ break;
+
+ case SMP_PASSKEY_REQ_EVT:
+ case SMP_PASSKEY_NOTIF_EVT:
+ case SMP_OOB_REQ_EVT:
+ p_dev_rec->sec_flags |= BTM_SEC_LINK_KEY_AUTHED;
+ case SMP_SEC_REQUEST_EVT:
+ case SMP_COMPLT_EVT:
+ if (btm_cb.api.p_le_callback)
+ {
+ /* the callback function implementation may change the IO capability... */
+ BTM_TRACE_DEBUG1 ("btm_cb.api.p_le_callback=0x%x", btm_cb.api.p_le_callback );
+ (*btm_cb.api.p_le_callback) (event, bd_addr, (tBTM_LE_EVT_DATA *)p_data);
+ }
+ else
+ {
+ BTM_TRACE_ERROR0 ("btm_proc_smp_cback: btm_cb.api.p_le_callback ==NULL");
+ }
+
+ if (event == SMP_COMPLT_EVT)
+ {
+ BTM_TRACE_DEBUG2 ("evt=SMP_COMPLT_EVT before update sec_level=0x%x sec_flags=0x%x", p_data->cmplt.sec_level , p_dev_rec->sec_flags );
+
+ res = (p_data->cmplt.reason == SMP_SUCCESS) ? BTM_SUCCESS : BTM_ERR_PROCESSING;
+
+ BTM_TRACE_DEBUG3 ("after update result=%d sec_level=0x%x sec_flags=0x%x",
+ res, p_data->cmplt.sec_level , p_dev_rec->sec_flags );
+
+ btm_sec_dev_rec_cback_event(p_dev_rec, res);
+
+ if (p_data->cmplt.is_pair_cancel && btm_cb.api.p_bond_cancel_cmpl_callback )
+ {
+ BTM_TRACE_DEBUG0 ("Pairing Cancel completed");
+ (*btm_cb.api.p_bond_cancel_cmpl_callback)(BTM_SUCCESS);
+ }
+#if BTM_BLE_CONFORMANCE_TESTING == TRUE
+ if (res != BTM_SUCCESS)
+ {
+ if (!btm_cb.devcb.no_disc_if_pair_fail)
+ {
+ BTM_TRACE_DEBUG0 ("Pairing failed - Remove ACL");
+ btm_remove_acl(bd_addr);
+ }
+ else
+ {
+ BTM_TRACE_DEBUG0 ("Pairing failed - Not Removing ACL");
+ p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+ }
+ }
+#else
+ if (res != BTM_SUCCESS)
+ btm_remove_acl(bd_addr);
+#endif
+
+ BTM_TRACE_DEBUG3 ("btm_cb pairing_state=%x pairing_flags=%x pin_code_len=%x",
+ btm_cb.pairing_state,
+ btm_cb.pairing_flags,
+ btm_cb.pin_code_len );
+ BTM_TRACE_DEBUG6 ("btm_cb.pairing_bda %02x:%02x:%02x:%02x:%02x:%02x",
+ btm_cb.pairing_bda[0], btm_cb.pairing_bda[1], btm_cb.pairing_bda[2],
+ btm_cb.pairing_bda[3], btm_cb.pairing_bda[4], btm_cb.pairing_bda[5]);
+
+ memset (btm_cb.pairing_bda, 0xff, BD_ADDR_LEN);
+ btm_cb.pairing_flags = 0;
+ }
+ break;
+
+ default:
+ BTM_TRACE_DEBUG1 ("unknown event = %d", event);
+ break;
+
+
+ }
+ }
+ else
+ {
+ BTM_TRACE_ERROR0("btm_proc_smp_cback received for unknown device");
+ }
+
+ return 0;
+}
+
+#endif /* SMP_INCLUDED */
+#endif /* BLE_INCLUDED */
+
+
+/*******************************************************************************
+**
+** Function BTM_BleDataSignature
+**
+** Description This function is called to sign the data using AES128 CMAC
+** algorith.
+**
+** Parameter bd_addr: target device the data to be signed for.
+** p_text: singing data
+** len: length of the data to be signed.
+** signature: output parameter where data signature is going to
+** be stored.
+**
+** Returns TRUE if signing sucessul, otherwise FALSE.
+**
+*******************************************************************************/
+BOOLEAN BTM_BleDataSignature (BD_ADDR bd_addr, UINT8 *p_text, UINT16 len,
+ BLE_SIGNATURE signature)
+{
+ BOOLEAN ret = FALSE;
+#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE)
+ tBTM_SEC_DEV_REC *p_rec = btm_find_dev (bd_addr);
+ UINT8 *p_buf, *pp;
+
+ BT_OCTET16 er;
+ UINT16 div;
+ UINT8 temp[4]; /* for (r || DIV) r=1*/
+ UINT16 r=1;
+ UINT8 *p=temp, *p_mac = (UINT8 *)signature;
+ tSMP_ENC output;
+ BT_OCTET16 local_csrk;
+
+ BTM_TRACE_DEBUG0 ("BTM_BleDataSignature");
+ if (p_rec == NULL)
+ {
+ BTM_TRACE_ERROR0("data signing can not be done from unknow device");
+ }
+ else
+ {
+ if ((p_buf = (UINT8 *)GKI_getbuf((UINT16)(len + 4))) != NULL)
+ {
+ BTM_TRACE_DEBUG0("Start to generate Local CSRK");
+ /* prepare plain text */
+ if (p_text)
+ {
+ memcpy(p_buf, p_text, len);
+ pp = (p_buf + len);
+ }
+
+#if BTM_BLE_CONFORMANCE_TESTING == TRUE
+ if ( btm_cb.devcb.enable_test_local_sign_cntr)
+ {
+ BTM_TRACE_DEBUG1 ("Use Test local counter value from script counter_val=%d", btm_cb.devcb.test_local_sign_cntr);
+ UINT32_TO_STREAM(pp, btm_cb.devcb.test_local_sign_cntr);
+ }
+ else
+ {
+ UINT32_TO_STREAM(pp, p_rec->ble.keys.local_counter);
+ }
+#else
+ UINT32_TO_STREAM(pp, p_rec->ble.keys.local_counter);
+#endif
+ /* compute local csrk */
+ if (btm_get_local_div(bd_addr, &div))
+ {
+ BTM_TRACE_DEBUG1 ("compute_csrk div=%x", div);
+ BTM_GetDeviceEncRoot(er);
+
+ /* CSRK = d1(ER, DIV, 1) */
+ UINT16_TO_STREAM(p, div);
+ UINT16_TO_STREAM(p, r);
+
+ if (!SMP_Encrypt(er, BT_OCTET16_LEN, temp, 4, &output))
+ {
+ BTM_TRACE_ERROR0("Local CSRK generation failed ");
+ }
+ else
+ {
+ BTM_TRACE_DEBUG0("local CSRK generation success");
+ memcpy((void *)local_csrk, output.param_buf, BT_OCTET16_LEN);
+
+
+#if BTM_BLE_CONFORMANCE_TESTING == TRUE
+ if (btm_cb.devcb.enable_test_local_sign_cntr)
+ {
+ UINT32_TO_STREAM(p_mac, btm_cb.devcb.test_local_sign_cntr);
+ }
+ else
+ {
+ UINT32_TO_STREAM(p_mac, p_rec->ble.keys.local_counter);
+ }
+#else
+ UINT32_TO_STREAM(p_mac, p_rec->ble.keys.local_counter);
+#endif
+
+ if ((ret = AES_CMAC(local_csrk, p_buf, (UINT16)(len + 4), BTM_CMAC_TLEN_SIZE, p_mac)) == TRUE)
+ {
+ btm_ble_increment_sign_ctr(bd_addr, TRUE);
+
+#if BTM_BLE_CONFORMANCE_TESTING == TRUE
+ if ( btm_cb.devcb.enable_test_mac_val)
+ {
+ BTM_TRACE_DEBUG0 ("Use MAC value from script");
+ memcpy(p_mac, btm_cb.devcb.test_mac, BTM_CMAC_TLEN_SIZE);
+ }
+#endif
+ }
+ BTM_TRACE_DEBUG1("BTM_BleDataSignature p_mac = %d", p_mac);
+ BTM_TRACE_DEBUG4("p_mac[0] = 0x%02x p_mac[1] = 0x%02x p_mac[2] = 0x%02x p_mac[3] = 0x%02x",
+ *p_mac, *(p_mac + 1), *(p_mac + 2), *(p_mac + 3));
+ BTM_TRACE_DEBUG4("p_mac[4] = 0x%02x p_mac[5] = 0x%02x p_mac[6] = 0x%02x p_mac[7] = 0x%02x",
+ *(p_mac + 4), *(p_mac + 5), *(p_mac + 6), *(p_mac + 7));
+
+ GKI_freebuf(p_buf);
+ }
+ }
+ }
+ }
+#endif /* BLE_INCLUDED */
+ return ret;
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleVerifySignature
+**
+** Description This function is called to verify the data signature
+**
+** Parameter bd_addr: target device the data to be signed for.
+** p_orig: original data before signature.
+** len: length of the signing data
+** counter: counter used when doing data signing
+** p_comp: signature to be compared against.
+
+** Returns TRUE if signature verified correctly; otherwise FALSE.
+**
+*******************************************************************************/
+BOOLEAN BTM_BleVerifySignature (BD_ADDR bd_addr, UINT8 *p_orig, UINT16 len, UINT32 counter,
+ UINT8 *p_comp)
+{
+ BOOLEAN verified = FALSE;
+#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE)
+ tBTM_SEC_DEV_REC *p_rec = btm_find_dev (bd_addr);
+ UINT8 p_mac[BTM_CMAC_TLEN_SIZE];
+
+ if (p_rec == NULL || (p_rec && !(p_rec->ble.key_type & BTM_LE_KEY_PCSRK)))
+ {
+ BTM_TRACE_ERROR0("can not verify signature for unknown device");
+ }
+ else if (counter < p_rec->ble.keys.counter)
+ {
+ BTM_TRACE_ERROR0("signature received with out dated sign counter");
+ }
+ else if (p_orig == NULL)
+ {
+ BTM_TRACE_ERROR0("No signature to verify");
+ }
+ else
+ {
+ BTM_TRACE_DEBUG2 ("BTM_BleVerifySignature rcv_cnt=%d >= expected_cnt=%d", counter, p_rec->ble.keys.counter);
+
+ if (AES_CMAC(p_rec->ble.keys.csrk, p_orig, len, BTM_CMAC_TLEN_SIZE, p_mac))
+ {
+ if (memcmp(p_mac, p_comp, BTM_CMAC_TLEN_SIZE) == 0)
+ {
+ btm_ble_increment_sign_ctr(bd_addr, FALSE);
+ verified = TRUE;
+ }
+ }
+ }
+#endif /* BLE_INCLUDED */
+ return verified;
+}
+
+#if BLE_INCLUDED == TRUE
+/*******************************************************************************
+** Utility functions for LE device IR/ER generation
+*******************************************************************************/
+/*******************************************************************************
+**
+** Function btm_notify_new_key
+**
+** Description This function is to notify application new keys have been
+** generated.
+**
+** Returns void
+**
+*******************************************************************************/
+static void btm_notify_new_key(UINT8 key_type)
+{
+ tBTM_BLE_LOCAL_KEYS *p_locak_keys = NULL;
+
+ BTM_TRACE_DEBUG1 ("btm_notify_new_key key_type=%d", key_type);
+
+ if (btm_cb.api.p_le_key_callback)
+ {
+ switch (key_type)
+ {
+ case BTM_BLE_KEY_TYPE_ID:
+ BTM_TRACE_DEBUG0 ("BTM_BLE_KEY_TYPE_ID");
+ p_locak_keys = (tBTM_BLE_LOCAL_KEYS *)&btm_cb.devcb.id_keys;
+ break;
+
+ case BTM_BLE_KEY_TYPE_ER:
+ BTM_TRACE_DEBUG0 ("BTM_BLE_KEY_TYPE_ER");
+ p_locak_keys = (tBTM_BLE_LOCAL_KEYS *)&btm_cb.devcb.er;
+ break;
+
+ default:
+ BTM_TRACE_ERROR1("unknown key type: %d", key_type);
+ break;
+ }
+ if (p_locak_keys != NULL)
+ (*btm_cb.api.p_le_key_callback) (key_type, p_locak_keys);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_process_er2
+**
+** Description This function is called when ER is generated, store it in
+** local control block.
+**
+** Returns void
+**
+*******************************************************************************/
+static void btm_ble_process_er2(tBTM_RAND_ENC *p)
+{
+ BTM_TRACE_DEBUG0 ("btm_ble_process_er2");
+
+ if (p &&p->opcode == HCI_BLE_RAND)
+ {
+ memcpy(&btm_cb.devcb.er[8], p->param_buf, BT_OCTET8_LEN);
+ btm_notify_new_key(BTM_BLE_KEY_TYPE_ER);
+ }
+ else
+ {
+ BTM_TRACE_ERROR0("Generating ER2 exception.");
+ memset(&btm_cb.devcb.er, 0, sizeof(BT_OCTET16));
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_process_er
+**
+** Description This function is called when ER is generated, store it in
+** local control block.
+**
+** Returns void
+**
+*******************************************************************************/
+static void btm_ble_process_er(tBTM_RAND_ENC *p)
+{
+ BTM_TRACE_DEBUG0 ("btm_ble_process_er");
+
+ if (p &&p->opcode == HCI_BLE_RAND)
+ {
+ memcpy(&btm_cb.devcb.er[0], p->param_buf, BT_OCTET8_LEN);
+
+ if (!btsnd_hcic_ble_rand((void *)btm_ble_process_er2))
+ {
+ memset(&btm_cb.devcb.er, 0, sizeof(BT_OCTET16));
+ BTM_TRACE_ERROR0("Generating ER2 failed.");
+ }
+ }
+ else
+ {
+ BTM_TRACE_ERROR0("Generating ER1 exception.");
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_process_irk
+**
+** Description This function is called when IRK is generated, store it in
+** local control block.
+**
+** Returns void
+**
+*******************************************************************************/
+static void btm_ble_process_irk(tSMP_ENC *p)
+{
+ BTM_TRACE_DEBUG0 ("btm_ble_process_irk");
+ if (p &&p->opcode == HCI_BLE_ENCRYPT)
+ {
+ memcpy(btm_cb.devcb.id_keys.irk, p->param_buf, BT_OCTET16_LEN);
+ btm_notify_new_key(BTM_BLE_KEY_TYPE_ID);
+ }
+ else
+ {
+ BTM_TRACE_ERROR0("Generating IRK exception.");
+ }
+
+ /* proceed generate ER */
+ if (!btsnd_hcic_ble_rand((void *)btm_ble_process_er))
+ {
+ BTM_TRACE_ERROR0("Generating ER failed.");
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_process_dhk
+**
+** Description This function is called when DHK is calculated, store it in
+** local control block, and proceed to generate ER, a 128-bits
+** random number.
+**
+** Returns void
+**
+*******************************************************************************/
+static void btm_ble_process_dhk(tSMP_ENC *p)
+{
+#if SMP_INCLUDED == TRUE
+ UINT8 btm_ble_irk_pt = 0x01;
+ tSMP_ENC output;
+
+ BTM_TRACE_DEBUG0 ("btm_ble_process_dhk");
+
+ if (p && p->opcode == HCI_BLE_ENCRYPT)
+ {
+ memcpy(btm_cb.devcb.id_keys.dhk, p->param_buf, BT_OCTET16_LEN);
+ BTM_TRACE_DEBUG0("BLE DHK generated.");
+
+ /* IRK = D1(IR, 1) */
+ if (!SMP_Encrypt(btm_cb.devcb.id_keys.ir, BT_OCTET16_LEN, &btm_ble_irk_pt,
+ 1, &output))
+ {
+ /* reset all identity root related key */
+ memset(&btm_cb.devcb.id_keys, 0, sizeof(tBTM_BLE_LOCAL_ID_KEYS));
+ }
+ else
+ {
+ btm_ble_process_irk(&output);
+ }
+ }
+ else
+ {
+ /* reset all identity root related key */
+ memset(&btm_cb.devcb.id_keys, 0, sizeof(tBTM_BLE_LOCAL_ID_KEYS));
+ }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_process_ir2
+**
+** Description This function is called when IR is generated, proceed to calculate
+** DHK = Eir({0x03, 0, 0 ...})
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void btm_ble_process_ir2(tBTM_RAND_ENC *p)
+{
+#if SMP_INCLUDED == TRUE
+ UINT8 btm_ble_dhk_pt = 0x03;
+ tSMP_ENC output;
+
+ BTM_TRACE_DEBUG0 ("btm_ble_process_ir2");
+
+ if (p && p->opcode == HCI_BLE_RAND)
+ {
+ /* remembering in control block */
+ memcpy(&btm_cb.devcb.id_keys.ir[8], p->param_buf, BT_OCTET8_LEN);
+ /* generate DHK= Eir({0x03, 0x00, 0x00 ...}) */
+
+
+ SMP_Encrypt(btm_cb.devcb.id_keys.ir, BT_OCTET16_LEN, &btm_ble_dhk_pt,
+ 1, &output);
+ btm_ble_process_dhk(&output);
+
+ BTM_TRACE_DEBUG0("BLE IR generated.");
+ }
+ else
+ {
+ memset(&btm_cb.devcb.id_keys, 0, sizeof(tBTM_BLE_LOCAL_ID_KEYS));
+ }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_process_ir
+**
+** Description This function is called when IR is generated, proceed to calculate
+** DHK = Eir({0x02, 0, 0 ...})
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void btm_ble_process_ir(tBTM_RAND_ENC *p)
+{
+ BTM_TRACE_DEBUG0 ("btm_ble_process_ir");
+
+ if (p && p->opcode == HCI_BLE_RAND)
+ {
+ /* remembering in control block */
+ memcpy(btm_cb.devcb.id_keys.ir, p->param_buf, BT_OCTET8_LEN);
+
+ if (!btsnd_hcic_ble_rand((void *)btm_ble_process_ir2))
+ {
+ BTM_TRACE_ERROR0("Generating IR2 failed.");
+ memset(&btm_cb.devcb.id_keys, 0, sizeof(tBTM_BLE_LOCAL_ID_KEYS));
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_reset_id
+**
+** Description This function is called to reset LE device identity.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_reset_id( void )
+{
+ BTM_TRACE_DEBUG0 ("btm_ble_reset_id");
+
+ /* regenrate Identity Root*/
+ if (!btsnd_hcic_ble_rand((void *)btm_ble_process_ir))
+ {
+ BTM_TRACE_DEBUG0("Generating IR failed.");
+ }
+}
+
+#if BTM_BLE_CONFORMANCE_TESTING == TRUE
+/*******************************************************************************
+**
+** Function btm_ble_set_no_disc_if_pair_fail
+**
+** Description This function indicates that whether no disconnect of the ACL
+** should be used if pairing failed
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_set_no_disc_if_pair_fail(BOOLEAN disable_disc )
+{
+ BTM_TRACE_DEBUG1 ("btm_ble_set_disc_enable_if_pair_fail disable_disc=%d", disable_disc);
+ btm_cb.devcb.no_disc_if_pair_fail = disable_disc;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_set_test_mac_value
+**
+** Description This function set test MAC value
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_set_test_mac_value(BOOLEAN enable, UINT8 *p_test_mac_val )
+{
+ BTM_TRACE_DEBUG1 ("btm_ble_set_test_mac_value enable=%d", enable);
+ btm_cb.devcb.enable_test_mac_val = enable;
+ memcpy(btm_cb.devcb.test_mac, p_test_mac_val, BT_OCTET8_LEN);
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_set_test_local_sign_cntr_value
+**
+** Description This function set test local sign counter value
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_set_test_local_sign_cntr_value(BOOLEAN enable, UINT32 test_local_sign_cntr )
+{
+ BTM_TRACE_DEBUG2 ("btm_ble_set_test_local_sign_cntr_value enable=%d local_sign_cntr=%d",
+ enable, test_local_sign_cntr);
+ btm_cb.devcb.enable_test_local_sign_cntr = enable;
+ btm_cb.devcb.test_local_sign_cntr = test_local_sign_cntr;
+}
+
+#endif /* BTM_BLE_CONFORMANCE_TESTING */
+
+
+#endif /* BLE_INCLUDED */
diff --git a/stack/btm/btm_ble_addr.c b/stack/btm/btm_ble_addr.c
new file mode 100644
index 0000000..08a3018
--- /dev/null
+++ b/stack/btm/btm_ble_addr.c
@@ -0,0 +1,371 @@
+/*****************************************************************************
+**
+** Name: btm_ble_addr.c
+**
+** Description: This file contains functions for BLE address management.
+**
+**
+**
+** Copyright (c) 1999-2010, Broadcom Corp., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+
+#include <string.h>
+
+#include "bt_types.h"
+#include "hcimsgs.h"
+#include "btu.h"
+#include "btm_int.h"
+
+
+#if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE)
+ #include "smp_api.h"
+ #define BTM_BLE_PRIVATE_ADDR_INT 900 /* 15 minutes minimum for random address refreshing */
+
+/*******************************************************************************
+**
+** Function btm_gen_resolve_paddr_cmpl
+**
+** Description This is callback functioin when resolvable private address
+** generation is complete.
+**
+** Returns void
+**
+*******************************************************************************/
+static void btm_gen_resolve_paddr_cmpl(tSMP_ENC *p)
+{
+ tBTM_LE_RANDOM_CB *p_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+ tBTM_BLE_INQ_CB *p_inq_cb = &btm_cb.ble_ctr_cb.inq_var;
+ BTM_TRACE_EVENT0 ("btm_gen_resolve_paddr_cmpl");
+ if (p && p->param_buf)
+ {
+ /* get the high bytes of the random address */
+ p_cb->private_addr[2] = p->param_buf[0];
+ p_cb->private_addr[1] = p->param_buf[1];
+ p_cb->private_addr[0] = p->param_buf[2];
+ /* mask off the 1st MSB */
+ p_cb->private_addr[0] &= 0xfe;
+ /* set the 2nd MSB to be 1 */
+ p_cb->private_addr[0] |= 0x02;
+ /* set it to controller */
+ btsnd_hcic_ble_set_random_addr(p_cb->private_addr);
+
+ p_inq_cb->own_addr_type = BLE_ADDR_RANDOM;
+
+ /* start a periodical timer to refresh random addr */
+ btu_stop_timer(&p_cb->raddr_timer_ent);
+ btu_start_timer (&p_cb->raddr_timer_ent, BTU_TTYPE_BLE_RANDOM_ADDR,
+ BTM_BLE_PRIVATE_ADDR_INT);
+
+ /* if adv is active, restart adv with new private addr */
+ if (p_inq_cb->adv_mode == BTM_BLE_ADV_ENABLE)
+ {
+ btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_DISABLE);
+
+ btsnd_hcic_ble_write_adv_params (p_inq_cb->adv_interval_min,
+ p_inq_cb->adv_interval_max,
+ p_inq_cb->evt_type,
+ p_inq_cb->own_addr_type,
+ p_inq_cb->direct_bda.type,
+ p_inq_cb->direct_bda.bda,
+ p_inq_cb->adv_chnl_map,
+ p_inq_cb->afp);
+ }
+ }
+ else
+ {
+ /* random address set failure */
+ BTM_TRACE_DEBUG0("set random address failed");
+ }
+}
+/*******************************************************************************
+**
+** Function btm_gen_resolve_paddr_low
+**
+** Description This function is called when random address has generate the
+** random number base for low 3 byte bd address.
+**
+** Returns void
+**
+*******************************************************************************/
+static void btm_gen_resolve_paddr_low(tBTM_RAND_ENC *p)
+{
+#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE)
+ tBTM_LE_RANDOM_CB *p_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+ tSMP_ENC output;
+
+ BTM_TRACE_EVENT0 ("btm_gen_resolve_paddr_low");
+ if (p && p->param_buf)
+ {
+ p_cb->private_addr[5] = p->param_buf[0];
+ p_cb->private_addr[4] = p->param_buf[1];
+ p_cb->private_addr[3] = p->param_buf[2];
+
+ /* encrypt with ur IRK */
+ if (!SMP_Encrypt(btm_cb.devcb.id_keys.irk, BT_OCTET16_LEN, p->param_buf, 3, &output))
+ {
+ btm_gen_resolve_paddr_cmpl(NULL);
+ }
+ else
+ {
+ btm_gen_resolve_paddr_cmpl(&output);
+ }
+ }
+#endif
+}
+/*******************************************************************************
+**
+** Function btm_gen_resolvable_private_addr
+**
+** Description This function generate a resolvable private address.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_gen_resolvable_private_addr (void)
+{
+ BTM_TRACE_EVENT0 ("btm_gen_resolvable_private_addr");
+ /* generate 3B rand as BD LSB, SRK with it, get BD MSB */
+ if (!btsnd_hcic_ble_rand((void *)btm_gen_resolve_paddr_low))
+ btm_gen_resolve_paddr_cmpl(NULL);
+}
+/*******************************************************************************
+**
+** Function btm_gen_non_resolve_paddr_cmpl
+**
+** Description This is the callback function when non-resolvable private
+** function is generated and write to controller.
+**
+** Returns void
+**
+*******************************************************************************/
+static void btm_gen_non_resolve_paddr_cmpl(tBTM_RAND_ENC *p)
+{
+ tBTM_LE_RANDOM_CB *p_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+ UINT8 *pp;
+ BTM_TRACE_EVENT0 ("btm_gen_non_resolve_paddr_cmpl");
+ if (p && p->param_buf)
+ {
+ pp = p->param_buf;
+ STREAM_TO_BDADDR(p_cb->private_addr, pp);
+ /* mask off the 2 MSB */
+ p_cb->private_addr[0] &= 0xfc;
+ /* write to controller */
+ btsnd_hcic_ble_set_random_addr(p_cb->private_addr);
+
+ btm_cb.ble_ctr_cb.inq_var.own_addr_type = BLE_ADDR_RANDOM;
+ }
+ else
+ {
+ BTM_TRACE_DEBUG0("btm_gen_non_resolvable_private_addr failed");
+ }
+}
+/*******************************************************************************
+**
+** Function btm_gen_non_resolvable_private_addr
+**
+** Description This function generate a non-resolvable private address.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_gen_non_resolvable_private_addr (void)
+{
+ BTM_TRACE_EVENT0 ("btm_gen_non_resolvable_private_addr");
+ if (!btsnd_hcic_ble_rand((void *)btm_gen_non_resolve_paddr_cmpl))
+ {
+ btm_gen_non_resolve_paddr_cmpl(NULL);
+ }
+}
+ #if SMP_INCLUDED == TRUE
+/*******************************************************************************
+** Utility functions for Random address resolving
+*******************************************************************************/
+/*******************************************************************************
+**
+** Function btm_ble_resolve_address_cmpl
+**
+** Description This function sends the random address resolving complete
+** callback.
+**
+** Returns None.
+**
+*******************************************************************************/
+static void btm_ble_resolve_address_cmpl(void)
+{
+ tBTM_LE_RANDOM_CB *p_mgnt_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+ tBTM_SEC_DEV_REC *p_dev_rec = NULL;
+
+ BTM_TRACE_EVENT0 ("btm_ble_resolve_address_cmpl");
+ if (p_mgnt_cb->index < BTM_SEC_MAX_DEVICE_RECORDS)
+ p_dev_rec = &btm_cb.sec_dev_rec[p_mgnt_cb->index];
+
+ p_mgnt_cb->busy = FALSE;
+
+ (* p_mgnt_cb->p_resolve_cback)(p_dev_rec, p_mgnt_cb->p);
+}
+/*******************************************************************************
+**
+** Function btm_ble_proc_resolve_x
+**
+** Description This function compares the X with random address 3 MSO bytes
+** to find a match, if not match, continue for next record.
+**
+** Returns None.
+**
+*******************************************************************************/
+static BOOLEAN btm_ble_proc_resolve_x(tSMP_ENC *p)
+{
+ tBTM_LE_RANDOM_CB *p_mgnt_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+ UINT8 comp[3];
+ BTM_TRACE_EVENT0 ("btm_ble_proc_resolve_x");
+ /* compare the hash with 3 LSB of bd address */
+ comp[0] = p_mgnt_cb->random_bda[5];
+ comp[1] = p_mgnt_cb->random_bda[4];
+ comp[2] = p_mgnt_cb->random_bda[3];
+
+ if (p && p->param_buf)
+ {
+ if (!memcmp(p->param_buf, &comp[0], 3))
+ {
+ /* match is found */
+ BTM_TRACE_EVENT0 ("match is found");
+ btm_ble_resolve_address_cmpl();
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+/*******************************************************************************
+**
+** Function btm_ble_match_random_bda
+**
+** Description This function match the random address to the appointed device
+** record, starting from calculating IRK. If record index exceed
+** the maximum record number, matching failed and send callback.
+**
+** Returns None.
+**
+*******************************************************************************/
+static BOOLEAN btm_ble_match_random_bda(UINT16 rec_index)
+{
+#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE)
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ tBTM_LE_RANDOM_CB *p_mgnt_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+ UINT8 rand[3];
+ tSMP_ENC output;
+
+ /* use the 3 MSB of bd address as prand */
+ rand[0] = p_mgnt_cb->random_bda[2];
+ rand[1] = p_mgnt_cb->random_bda[1];
+ rand[2] = p_mgnt_cb->random_bda[0];
+
+ BTM_TRACE_EVENT1("btm_ble_match_random_bda rec_index = %d", rec_index);
+
+ if (rec_index < BTM_SEC_MAX_DEVICE_RECORDS)
+ {
+ p_dev_rec = &btm_cb.sec_dev_rec[rec_index];
+
+ BTM_TRACE_ERROR2("sec_flags = %02x device_type = %d", p_dev_rec->sec_flags, p_dev_rec->device_type);
+
+ if ((p_dev_rec->device_type == BT_DEVICE_TYPE_BLE) &&
+ (p_dev_rec->ble.key_type & BTM_LE_KEY_PID))
+ {
+ /* generate X = E irk(R0, R1, R2) and R is random address 3 LSO */
+ SMP_Encrypt(p_dev_rec->ble.keys.irk, BT_OCTET16_LEN,
+ &rand[0], 3, &output);
+ return btm_ble_proc_resolve_x(&output);
+ }
+ else
+ {
+ // not completed
+ return FALSE;
+ }
+ }
+ else /* no match found */
+ {
+ btm_ble_resolve_address_cmpl();
+ return TRUE;
+ }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_resolve_random_addr
+**
+** Description This function is called to resolve a random address.
+**
+** Returns pointer to the security record of the device whom a random
+** address is matched to.
+**
+*******************************************************************************/
+void btm_ble_resolve_random_addr(BD_ADDR random_bda, tBTM_BLE_RESOLVE_CBACK * p_cback, void *p)
+{
+ tBTM_LE_RANDOM_CB *p_mgnt_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+
+ BTM_TRACE_EVENT0 ("btm_ble_resolve_random_addr");
+ if ( !p_mgnt_cb->busy)
+ {
+ p_mgnt_cb->p = p;
+ p_mgnt_cb->busy = TRUE;
+ p_mgnt_cb->index = 0;
+ p_mgnt_cb->p_resolve_cback = p_cback;
+ memcpy(p_mgnt_cb->random_bda, random_bda, BD_ADDR_LEN);
+ /* start to resolve random address */
+ /* check for next security record */
+ while (TRUE)
+ {
+ if (btm_ble_match_random_bda(p_mgnt_cb->index++))
+ {
+ // match found or went through the list
+ break;
+ }
+ }
+ }
+ else
+ (*p_cback)(NULL, p);
+}
+ #endif
+/*******************************************************************************
+** address mapping between pseudo address and real connection address
+*******************************************************************************/
+/*******************************************************************************
+**
+** Function btm_ble_map_bda_to_conn_bda
+**
+** Description This function map a BD address to the real connection address
+** and return the connection address type.
+*******************************************************************************/
+tBLE_ADDR_TYPE btm_ble_map_bda_to_conn_bda(BD_ADDR bd_addr)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = NULL;
+ BTM_TRACE_EVENT0 ("btm_ble_map_bda_to_conn_bda");
+ if ((p_dev_rec = btm_find_dev (bd_addr)) != NULL &&
+ p_dev_rec->device_type == BT_DEVICE_TYPE_BLE)
+ {
+ if (p_dev_rec->ble.ble_addr_type != BLE_ADDR_PUBLIC)
+ {
+ memcpy(bd_addr, p_dev_rec->ble.static_addr, BD_ADDR_LEN);
+ }
+ return p_dev_rec->ble.ble_addr_type;
+ }
+ else
+ return BLE_ADDR_PUBLIC;
+}
+/*******************************************************************************
+**
+** Function btm_ble_map_bda_to_pseudo_bda
+**
+** Description This function map a BD address to a pseudo address when the
+** address given is a random address.
+**
+*******************************************************************************/
+void btm_ble_map_bda_to_pseudo_bda(BD_ADDR bd_addr)
+{
+ BTM_TRACE_EVENT0 ("btm_ble_map_bda_to_pseudo_bda");
+}
+#endif
+
+
diff --git a/stack/btm/btm_ble_bgconn.c b/stack/btm/btm_ble_bgconn.c
new file mode 100644
index 0000000..bf574ab
--- /dev/null
+++ b/stack/btm/btm_ble_bgconn.c
@@ -0,0 +1,604 @@
+/*****************************************************************************
+**
+** Name: btm_ble_bgconn.c
+**
+** Description: This file contains functions for BLE whitelist operation.
+**
+**
+**
+** Copyright (c) 1999-2010, Broadcom Corp., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+
+#include <string.h>
+
+#include "bt_types.h"
+#include "btu.h"
+#include "btm_int.h"
+#include "l2c_int.h"
+#include "hcimsgs.h"
+
+#ifndef BTM_BLE_SCAN_PARAM_TOUT
+#define BTM_BLE_SCAN_PARAM_TOUT 50 /* 50 seconds */
+#endif
+
+#if (BLE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function btm_update_scanner_filter_policy
+**
+** Description This function update the filter policy of scnner or advertiser.
+*******************************************************************************/
+void btm_update_scanner_filter_policy(tBTM_BLE_SFP scan_policy)
+{
+ tBTM_BLE_INQ_CB *p_inq = &btm_cb.ble_ctr_cb.inq_var;
+ BTM_TRACE_EVENT0 ("btm_update_scanner_filter_policy");
+ btm_cb.ble_ctr_cb.inq_var.sfp = scan_policy;
+
+ btsnd_hcic_ble_set_scan_params ((UINT8)((p_inq->scan_type == BTM_BLE_SCAN_MODE_NONE) ? BTM_BLE_SCAN_MODE_ACTI: p_inq->scan_type),
+ (UINT16)(!p_inq->scan_interval ? BTM_BLE_GAP_DISC_SCAN_INT : p_inq->scan_interval),
+ (UINT16)(!p_inq->scan_window ? BTM_BLE_GAP_DISC_SCAN_WIN : p_inq->scan_window),
+ BLE_ADDR_PUBLIC,
+ scan_policy);
+}
+/*******************************************************************************
+**
+** Function btm_update_adv_filter_policy
+**
+** Description This function update the filter policy of scnner or advertiser.
+*******************************************************************************/
+void btm_update_adv_filter_policy(tBTM_BLE_AFP adv_policy)
+{
+ tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
+ BTM_TRACE_EVENT0 ("btm_update_adv_filter_policy");
+ p_cb->afp = adv_policy;
+}
+/*******************************************************************************
+**
+** Function btm_update_dev_to_white_list
+**
+** Description This function adds a device into white list.
+*******************************************************************************/
+BOOLEAN btm_update_dev_to_white_list(BOOLEAN to_add, BD_ADDR bd_addr, tBLE_ADDR_TYPE addr_type)
+{
+ /* look up the sec device record, and find the address */
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ BD_ADDR dummy_bda = {0};
+ BOOLEAN started = FALSE, suspend = FALSE;
+
+ if (btm_cb.btm_inq_vars.inq_active)
+ {
+ suspend = TRUE;
+ btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_DISABLE, BTM_BLE_DUPLICATE_ENABLE);
+ }
+
+ if ((p_dev_rec = btm_find_dev (bd_addr)) != NULL &&
+ p_dev_rec->device_type == BT_DEVICE_TYPE_BLE)
+ {
+ BTM_TRACE_DEBUG0("btm_update_dev_to_white_list 1");
+
+ if ((to_add && p_cb->num_empty_filter == 0) ||
+ (!to_add && p_cb->num_empty_filter == p_cb->max_filter_entries))
+ {
+ BTM_TRACE_ERROR1("num_entry available in controller: %d", p_cb->num_empty_filter);
+ return started;
+ }
+
+
+ if ( p_dev_rec->ble.ble_addr_type == BLE_ADDR_PUBLIC)
+ {
+ if (to_add)
+ started = btsnd_hcic_ble_add_white_list (BLE_ADDR_PUBLIC, bd_addr);
+ else
+ started = btsnd_hcic_ble_remove_from_white_list (BLE_ADDR_PUBLIC, bd_addr);
+ }
+ else
+ {
+ if (BLE_ADDR_IS_STATIC(bd_addr))
+ {
+ if (to_add)
+ started = btsnd_hcic_ble_add_white_list (BLE_ADDR_RANDOM, bd_addr);
+ else
+ started = btsnd_hcic_ble_remove_from_white_list (BLE_ADDR_RANDOM, bd_addr);
+
+ }
+ if (memcmp(p_dev_rec->ble.reconn_addr, dummy_bda, BD_ADDR_LEN) != 0)
+ {
+ if (to_add)
+ started = btsnd_hcic_ble_add_white_list (BLE_ADDR_RANDOM, p_dev_rec->ble.reconn_addr);
+ else
+ started = btsnd_hcic_ble_remove_from_white_list (BLE_ADDR_RANDOM, p_dev_rec->ble.reconn_addr);
+ }
+ }
+ }
+ /* if not a known device, shall we add it? */
+ else
+ {
+ if (to_add)
+ started = btsnd_hcic_ble_add_white_list (addr_type, bd_addr);
+ else
+ started = btsnd_hcic_ble_remove_from_white_list (addr_type, bd_addr);
+ }
+
+ if (suspend)
+ {
+ btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_ENABLE, BTM_BLE_DUPLICATE_DISABLE);
+ }
+
+ return started;
+}
+/*******************************************************************************
+**
+** Function btm_ble_clear_white_list
+**
+** Description This function clears the white list.
+*******************************************************************************/
+void btm_ble_clear_white_list (void)
+{
+ BTM_TRACE_EVENT0 ("btm_ble_clear_white_list");
+ btsnd_hcic_ble_clear_white_list();
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_clear_white_list_complete
+**
+** Description This function clears the white list complete.
+*******************************************************************************/
+void btm_ble_clear_white_list_complete(UINT8 *p_data, UINT16 evt_len)
+{
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+ UINT8 status;
+ BTM_TRACE_EVENT0 ("btm_ble_clear_white_list_complete");
+ STREAM_TO_UINT8 (status, p_data);
+
+ if (status == HCI_SUCCESS)
+ p_cb->num_empty_filter = p_cb->max_filter_entries;
+
+}
+/*******************************************************************************
+**
+** Function btm_ble_add_2_white_list_complete
+**
+** Description This function read the current white list size.
+*******************************************************************************/
+void btm_ble_add_2_white_list_complete(UINT8 *p, UINT16 evt_len)
+{
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+ BTM_TRACE_EVENT0 ("btm_ble_add_2_white_list_complete");
+
+ if (*p == HCI_SUCCESS)
+ {
+ p_cb->num_empty_filter --;
+ }
+}
+/*******************************************************************************
+**
+** Function btm_ble_add_2_white_list_complete
+**
+** Description This function read the current white list size.
+*******************************************************************************/
+void btm_ble_remove_from_white_list_complete(UINT8 *p, UINT16 evt_len)
+{
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+ BTM_TRACE_EVENT0 ("btm_ble_remove_from_white_list_complete");
+ if (*p == HCI_SUCCESS)
+ {
+ p_cb->num_empty_filter ++;
+ }
+}
+/*******************************************************************************
+**
+** Function btm_ble_find_dev_in_whitelist
+**
+** Description This function check if the device is in the white list
+*******************************************************************************/
+BOOLEAN btm_ble_find_dev_in_whitelist(BD_ADDR bd_addr)
+{
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+ UINT8 i;
+
+ BTM_TRACE_EVENT0 ("btm_ble_find_dev_in_whitelist");
+
+ /* empty wl */
+ if (p_cb->num_empty_filter == p_cb->max_filter_entries)
+ {
+ BTM_TRACE_DEBUG0("white list empty");
+ return FALSE;
+ }
+
+ for (i = 0; i < BTM_BLE_MAX_BG_CONN_DEV_NUM && i < p_cb->max_filter_entries; i ++)
+ {
+ if (memcmp(p_cb->bg_conn_dev_list[i], bd_addr, BD_ADDR_LEN) == 0)
+ return TRUE;
+ }
+ return FALSE;
+}
+/*******************************************************************************
+**
+** Function btm_ble_count_unconn_dev_in_whitelist
+**
+** Description This function check the number of unconnected device in white list.
+*******************************************************************************/
+UINT8 btm_ble_count_unconn_dev_in_whitelist(void)
+{
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+ UINT8 count = 0, i;
+ BD_ADDR dummy_bda ={0};
+
+ BTM_TRACE_EVENT0 ("btm_ble_find_dev_in_whitelist");
+
+ for (i = 0; i < BTM_BLE_MAX_BG_CONN_DEV_NUM && i < p_cb->max_filter_entries; i ++)
+ {
+ if (memcmp(p_cb->bg_conn_dev_list[i], dummy_bda, BD_ADDR_LEN) != 0 &&
+ !BTM_IsAclConnectionUp(p_cb->bg_conn_dev_list[i]))
+ {
+ count ++;
+ }
+ }
+ return count;
+}
+/*******************************************************************************
+**
+** Function btm_update_bg_conn_list
+**
+** Description This function update the local background connection device list.
+*******************************************************************************/
+BOOLEAN btm_update_bg_conn_list(BOOLEAN to_add, BD_ADDR bd_addr)
+{
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+ UINT8 i;
+ BD_ADDR dummy_bda = {0};
+ BTM_TRACE_EVENT0 ("btm_update_bg_conn_list");
+ if ((to_add && (p_cb->bg_conn_dev_num == BTM_BLE_MAX_BG_CONN_DEV_NUM || p_cb->num_empty_filter == 0)) ||
+ (!to_add && p_cb->num_empty_filter == p_cb->max_filter_entries))
+ {
+ BTM_TRACE_DEBUG1("num_empty_filter = %d", p_cb->num_empty_filter);
+ return FALSE;
+ }
+
+ for (i = 0; i < BTM_BLE_MAX_BG_CONN_DEV_NUM && i < p_cb->max_filter_entries; i ++)
+ {
+ /* to add */
+ if (memcmp(p_cb->bg_conn_dev_list[i], dummy_bda, BD_ADDR_LEN) == 0 && to_add)
+ {
+ memcpy(p_cb->bg_conn_dev_list[i], bd_addr, BD_ADDR_LEN);
+ p_cb->bg_conn_dev_num ++;
+ return TRUE;
+ }
+ /* to remove */
+ if (!to_add && memcmp(p_cb->bg_conn_dev_list[i], bd_addr, BD_ADDR_LEN) == 0)
+ {
+ memset(p_cb->bg_conn_dev_list[i], 0, BD_ADDR_LEN);
+ p_cb->bg_conn_dev_num --;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+/*******************************************************************************
+**
+** Function btm_write_bg_conn_wl
+**
+** Description This function write background connection device list into
+** controller.
+*******************************************************************************/
+void btm_write_bg_conn_wl(void)
+{
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+ UINT8 i;
+ BTM_TRACE_EVENT0 ("btm_write_bg_conn_wl");
+ btm_ble_clear_white_list();
+
+ for (i = 0; i < p_cb->bg_conn_dev_num; i ++)
+ {
+ if (!btm_update_dev_to_white_list(TRUE, p_cb->bg_conn_dev_list[i], BLE_ADDR_PUBLIC))
+ break;
+ }
+ return;
+}
+/*******************************************************************************
+**
+** Function btm_ble_start_auto_conn
+**
+** Description This function is to start/stop auto connection procedure.
+**
+** Parameters start: TRUE to start; FALSE to stop.
+**
+** Returns void
+**
+*******************************************************************************/
+BOOLEAN btm_ble_start_auto_conn(BOOLEAN start)
+{
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+ BD_ADDR dummy_bda = {0};
+ BOOLEAN exec = TRUE;
+ UINT16 scan_int, scan_win;
+
+ scan_int = (p_cb->scan_int == BTM_BLE_CONN_PARAM_UNDEF) ? BTM_BLE_CONN_EST_SCAN_INT : p_cb->scan_int;
+ scan_win = (p_cb->scan_win == BTM_BLE_CONN_PARAM_UNDEF) ? BTM_BLE_CONN_EST_SCAN_WIND : p_cb->scan_win;
+
+ if (start)
+ {
+ if (!l2cb.is_ble_connecting &&
+ btm_ble_count_unconn_dev_in_whitelist() > 0)
+ {
+ if (p_cb->bg_conn_state != BLE_BG_CONN_ACTIVE && p_cb->bg_conn_dev_num > 0)
+ {
+ if (!btsnd_hcic_ble_create_ll_conn (scan_int, /* UINT16 scan_int */
+ scan_win, /* UINT16 scan_win */
+ 0x01, /* UINT8 white_list */
+ BLE_ADDR_PUBLIC, /* UINT8 addr_type_peer */
+ dummy_bda, /* BD_ADDR bda_peer */
+ BLE_ADDR_PUBLIC, /* UINT8 addr_type_own */
+ BTM_BLE_CONN_INT_MIN_DEF, /* UINT16 conn_int_min */
+ BTM_BLE_CONN_INT_MAX_DEF, /* UINT16 conn_int_max */
+ BTM_BLE_CONN_SLAVE_LATENCY_DEF, /* UINT16 conn_latency */
+ BTM_BLE_CONN_TIMEOUT_DEF, /* UINT16 conn_timeout */
+ 0, /* UINT16 min_len */
+ 0)) /* UINT16 max_len */
+ {
+ /* start auto connection failed */
+ exec = FALSE;
+ }
+ else
+ {
+ p_cb->bg_conn_state = BLE_BG_CONN_ACTIVE;
+ }
+ }
+ }
+ else
+ exec = FALSE;
+ }
+ else
+ {
+ if (p_cb->bg_conn_state == BLE_BG_CONN_ACTIVE)
+ {
+ if (!btsnd_hcic_ble_create_conn_cancel())
+ exec = FALSE;
+ else
+ p_cb->bg_conn_state = BLE_BG_CONN_IDLE;
+ }
+ }
+ return exec;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_start_select_conn
+**
+** Description This function is to start/stop selective connection procedure.
+**
+** Parameters start: TRUE to start; FALSE to stop.
+** p_select_cback: callback function to return application
+** selection.
+**
+** Returns BOOLEAN: selective connectino procedure is started.
+**
+*******************************************************************************/
+BOOLEAN btm_ble_start_select_conn(BOOLEAN start,tBTM_BLE_SEL_CBACK *p_select_cback)
+{
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+ UINT16 scan_int, scan_win;
+
+ BTM_TRACE_EVENT0 ("btm_ble_start_select_conn");
+
+ scan_int = (p_cb->scan_int == BTM_BLE_CONN_PARAM_UNDEF) ? BTM_BLE_CONN_EST_SCAN_INT : p_cb->scan_int;
+ scan_win = (p_cb->scan_win == BTM_BLE_CONN_PARAM_UNDEF) ? BTM_BLE_CONN_EST_SCAN_WIND : p_cb->scan_win;
+
+ if (start)
+ {
+ if (!btm_cb.btm_inq_vars.inq_active)
+ {
+ btm_cb.ble_ctr_cb.p_select_cback = p_select_cback;
+
+ btm_update_scanner_filter_policy(SP_ADV_WL);
+
+ if (!btsnd_hcic_ble_set_scan_params(BTM_BLE_SCAN_MODE_PASS, /* use passive scan by default */
+ scan_int, /* scan interval */
+ scan_win, /* scan window */
+ BLE_ADDR_PUBLIC, /* own device, DUMO always use public */
+ SP_ADV_WL) /* process advertising packets only from devices in the White List */
+ )
+ return FALSE;
+
+ if (p_cb->inq_var.adv_mode == BTM_BLE_ADV_ENABLE)
+ {
+ BTM_TRACE_ERROR0("peripheral device cannot initiate a selective connection");
+ return FALSE;
+ }
+ else if (p_cb->bg_conn_dev_num > 0 && btm_ble_count_unconn_dev_in_whitelist() > 0 )
+ {
+
+ if (!btsnd_hcic_ble_set_scan_enable(TRUE, TRUE)) /* duplicate filtering enabled */
+ return FALSE;
+
+ /* mark up inquiry status flag */
+ btm_cb.btm_inq_vars.inq_active = TRUE;
+ btm_cb.ble_ctr_cb.inq_var.proc_mode = BTM_BLE_SELECT_SCAN;
+
+ p_cb->bg_conn_state = BLE_BG_CONN_ACTIVE;
+
+ }
+ }
+ else
+ {
+ BTM_TRACE_ERROR0("scan active, can not start selective connection procedure");
+ return FALSE;
+ }
+ }
+ else /* disable selective connection mode */
+ {
+ p_cb->p_select_cback = NULL;
+ btm_cb.btm_inq_vars.inq_active = FALSE;
+ btm_cb.ble_ctr_cb.inq_var.proc_mode = BTM_BLE_INQUIRY_NONE;
+
+ btm_update_scanner_filter_policy(SP_ADV_ALL);
+
+ /* stop scanning */
+ if (p_cb->bg_conn_dev_num > 0)
+ {
+ if (!btsnd_hcic_ble_set_scan_enable(FALSE, TRUE)) /* duplicate filtering enabled */
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+/*******************************************************************************
+**
+** Function btm_ble_initiate_select_conn
+**
+** Description This function is to start/stop selective connection procedure.
+**
+** Parameters start: TRUE to start; FALSE to stop.
+** p_select_cback: callback function to return application
+** selection.
+**
+** Returns BOOLEAN: selective connectino procedure is started.
+**
+*******************************************************************************/
+void btm_ble_initiate_select_conn(BD_ADDR bda)
+{
+ UINT8 addr_type;
+ BTM_TRACE_EVENT0 ("btm_ble_initiate_select_conn");
+ addr_type = btm_ble_map_bda_to_conn_bda(bda);
+
+ /* use direct connection procedure to initiate connection */
+ if (!L2CA_ConnectFixedChnl(L2CAP_ATT_CID, bda))
+ {
+ BTM_TRACE_ERROR0("btm_ble_initiate_select_conn failed");
+ }
+}
+/*******************************************************************************
+**
+** Function btm_ble_suspend_bg_sele_conn
+**
+** Description This function is to suspend an active background connection
+** procedure.
+**
+** Parameters none.
+**
+** Returns none.
+**
+*******************************************************************************/
+void btm_ble_suspend_bg_sele_conn(void)
+{
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+ BTM_TRACE_EVENT0 ("btm_ble_suspend_bg_sele_conn");
+
+ if (p_cb->bg_conn_type == BTM_BLE_CONN_SELECTIVE)
+ {
+ p_cb->bg_conn_state = BLE_BG_CONN_SUSPEND;
+ btm_ble_start_select_conn(FALSE, NULL);
+ }
+}
+/*******************************************************************************
+**
+** Function btm_ble_suspend_bg_conn
+**
+** Description This function is to suspend an active background connection
+** procedure.
+**
+** Parameters none.
+**
+** Returns none.
+**
+*******************************************************************************/
+void btm_ble_suspend_bg_conn(void)
+{
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+ BTM_TRACE_EVENT0 ("btm_ble_suspend_bg_conn");
+
+ if (p_cb->bg_conn_type == BTM_BLE_CONN_AUTO)
+ {
+ if (btm_ble_start_auto_conn(FALSE))
+ p_cb->bg_conn_state = BLE_BG_CONN_SUSPEND;
+ }
+}
+/*******************************************************************************
+**
+** Function btm_ble_scan_param_idle
+**
+** Description This function is to process the scan parameter idle timeout
+** timeout.
+********************************************************************************/
+void btm_ble_scan_param_idle(void)
+{
+ BTM_BleSetConnScanParams(BTM_BLE_CONN_EST_SCAN_INT_LO, BTM_BLE_CONN_EST_SCAN_WIND_LO);
+}
+/*******************************************************************************
+**
+** Function btm_ble_resume_bg_conn
+**
+** Description This function is to resume a background auto connection
+** procedure.
+**
+** Parameters none.
+**
+** Returns none.
+**
+*******************************************************************************/
+BOOLEAN btm_ble_resume_bg_conn(tBTM_BLE_SEL_CBACK *p_sele_callback, BOOLEAN def_param)
+{
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+ BOOLEAN ret = FALSE;
+
+ if (p_cb->bg_conn_state != BLE_BG_CONN_ACTIVE )
+ {
+ if (def_param)
+ {
+ p_cb->scan_int = BTM_BLE_CONN_PARAM_UNDEF;
+ p_cb->scan_win = BTM_BLE_CONN_PARAM_UNDEF;
+
+ /* start scan param idle timer */
+ btu_start_timer(&p_cb->scan_param_idle_timer,
+ BTU_TTYPE_BLE_SCAN_PARAM_IDLE,
+ BTM_BLE_SCAN_PARAM_TOUT);
+ }
+
+ if (p_cb->bg_conn_type == BTM_BLE_CONN_AUTO)
+ ret = btm_ble_start_auto_conn(TRUE);
+
+ if (p_cb->bg_conn_type == BTM_BLE_CONN_SELECTIVE)
+ {
+ /* terminate selective connection mode if all devices are connected */
+ if (btm_ble_count_unconn_dev_in_whitelist() == 0)
+ {
+ btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_DISABLE, BTM_BLE_DUPLICATE_DISABLE);
+ btm_cb.ble_ctr_cb.inq_var.proc_mode = BTM_BLE_INQUIRY_NONE;
+ btm_cb.btm_inq_vars.inq_active = FALSE;
+ }
+ else if (!btm_cb.btm_inq_vars.inq_active)
+ btm_ble_start_select_conn(TRUE, btm_cb.ble_ctr_cb.p_select_cback);
+ }
+
+ if (ret)
+ p_cb->bg_conn_state = BLE_BG_CONN_ACTIVE;
+
+ }
+
+ return ret;
+}
+/*******************************************************************************
+**
+** Function btm_ble_update_bg_state
+**
+** Description This function is to update the bg connection status.
+**
+** Parameters none.
+**
+** Returns none.
+**
+*******************************************************************************/
+void btm_ble_update_bg_state(void)
+{
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+
+ if (!l2cb.is_ble_connecting && (p_cb->bg_conn_state != BLE_BG_CONN_SUSPEND))
+ p_cb->bg_conn_state = BLE_BG_CONN_IDLE;
+
+}
+
+#endif
+
diff --git a/stack/btm/btm_ble_gap.c b/stack/btm/btm_ble_gap.c
new file mode 100644
index 0000000..9092d5d
--- /dev/null
+++ b/stack/btm/btm_ble_gap.c
@@ -0,0 +1,2072 @@
+/*****************************************************************************
+**
+** Name: btm_ble_gap.c
+**
+** Description: This file contains functions for BLE GAP.
+**
+**
+**
+** Copyright (c) 2008-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+
+#include <string.h>
+#include <stdio.h>
+#include <stddef.h>
+
+#include "bt_types.h"
+#include "btu.h"
+#include "btm_int.h"
+#include "hcimsgs.h"
+#if (GAP_INCLUDED == TRUE)
+#include "gap_api.h"
+#endif
+
+#if (BLE_INCLUDED == TRUE)
+#define BTM_BLE_NAME_SHORT 0x01
+#define BTM_BLE_NAME_CMPL 0x02
+
+#define BTM_BLE_FILTER_TARGET_UNKNOWN 0xff
+#define BTM_BLE_POLICY_UNKNOWN 0xff
+
+#define BLE_RESOLVE_ADDR_MSB 0x40 /* most significant bit, bit7, bit6 is 01 to be resolvable random */
+#define BLE_RESOLVE_ADDR_MASK 0xc0 /* bit 6, and bit7 */
+#define BTM_BLE_IS_RESOLVE_BDA(x) ((x[0] & BLE_RESOLVE_ADDR_MASK) == BLE_RESOLVE_ADDR_MSB)
+
+#define BTM_EXT_BLE_RMT_NAME_TIMEOUT 30
+static tBLE_BD_ADDR le_bda_any ={BLE_ADDR_PUBLIC, {0x00,0x00,0x00,0x00,0x00,0x00}};
+
+
+#define BTM_BLE_VALID_CONN_DIRECT(x) (memcmp(&le_bda_any, x, sizeof(tBLE_BD_ADDR)) != 0)
+
+/*******************************************************************************
+** Local functions
+*******************************************************************************/
+static void btm_ble_update_adv_flag(UINT8 flag);
+static void btm_ble_process_adv_pkt_cont(BD_ADDR bda, UINT8 addr_type, UINT8 evt_type, UINT8 *p);
+static UINT8 *btm_ble_build_adv_data(tBTM_BLE_AD_MASK *p_data_mask, UINT8 **p_dst, tBTM_BLE_ADV_DATA *p_data);
+
+
+
+
+
+
+
+
+/*******************************************************************************
+**
+** Function BTM_BleReset
+**
+** Description This function is called to reset ULP controller.
+**
+** Parameters None.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTM_BleReset(void)
+{
+ btsnd_hcic_ble_reset();
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleObserve
+**
+** Description This procedure keep the device listening for advertising
+** events from a broadcast device.
+**
+** Parameters start: start or stop observe.
+** white_list: use white list in observer mode or not.
+**
+** Returns void
+**
+*******************************************************************************/
+tBTM_STATUS BTM_BleObserve(BOOLEAN start, UINT8 duration,
+ tBTM_INQ_RESULTS_CB *p_results_cb, tBTM_CMPL_CB *p_cmpl_cb)
+{
+ tBTM_BLE_INQ_CB *p_inq = &btm_cb.ble_ctr_cb.inq_var;
+ tBTM_STATUS status = BTM_NO_RESOURCES;
+
+ BTM_TRACE_EVENT0 ("BTM_BleObserve ");
+
+ if (start)
+ {
+ if (p_inq->proc_mode != BTM_BLE_INQUIRY_NONE)
+ return BTM_BUSY;
+
+ btm_cb.btm_inq_vars.p_inq_results_cb = p_results_cb;
+ btm_cb.btm_inq_vars.p_inq_cmpl_cb = p_cmpl_cb;
+
+ /* allow config scanning type */
+ if (btsnd_hcic_ble_set_scan_params ((UINT8)((p_inq->scan_type == BTM_BLE_SCAN_MODE_NONE) ? BTM_BLE_SCAN_MODE_ACTI: p_inq->scan_type),
+ (UINT16)(!p_inq->scan_interval ? BTM_BLE_GAP_DISC_SCAN_INT : p_inq->scan_interval),
+ (UINT16)(!p_inq->scan_window ? BTM_BLE_GAP_DISC_SCAN_WIN : p_inq->scan_window),
+ BLE_ADDR_PUBLIC,
+ BTM_BLE_DEFAULT_SFP)) /* assume observe always not using white list */
+ {
+ /* start scan, disable duplicate filtering */
+ if (btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_ENABLE, BTM_BLE_DUPLICATE_DISABLE))
+ {
+ status = BTM_SUCCESS;
+ p_inq->proc_mode = BTM_BLE_OBSERVE;
+ btm_cb.btm_inq_vars.inq_active = TRUE;
+
+ if (duration != 0)
+ {
+ /* start inquiry timer */
+ btu_start_timer (&p_inq->inq_timer_ent, BTU_TTYPE_BLE_INQUIRY, duration);
+ }
+ }
+ }
+ }
+ else if (p_inq->proc_mode == BTM_BLE_OBSERVE)
+ {
+ btm_ble_stop_scan();
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleBroadcast
+**
+** Description This function is to start or stop broadcasting.
+**
+** Parameters start: start or stop broadcasting.
+**
+** Returns status.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_BleBroadcast(BOOLEAN start)
+{
+ tBTM_STATUS status = BTM_NO_RESOURCES;
+ tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
+ UINT8 evt_type = p_cb->scan_rsp ? BTM_BLE_DISCOVER_EVT: BTM_BLE_NON_CONNECT_EVT;
+
+#ifdef BTM_BLE_PC_ADV_TEST_MODE
+ if (BTM_BLE_PC_ADV_TEST_MODE)
+ {
+ evt_type = p_cb->scan_rsp ? BTM_BLE_CONNECT_EVT: BTM_BLE_NON_CONNECT_EVT;
+ }
+#endif
+
+ if (start && p_cb->adv_mode == BTM_BLE_ADV_DISABLE)
+ {
+ /* update adv params */
+ if (!btsnd_hcic_ble_write_adv_params ((UINT16)(p_cb->adv_interval_min ? p_cb->adv_interval_min : BTM_BLE_GAP_ADV_INT),
+ (UINT16)(p_cb->adv_interval_max ? p_cb->adv_interval_max : BTM_BLE_GAP_ADV_INT),
+ evt_type,
+ p_cb->own_addr_type,
+ p_cb->direct_bda.type, p_cb->direct_bda.bda,
+ p_cb->adv_chnl_map,
+ p_cb->afp))
+
+ status = BTM_NO_RESOURCES;
+ else
+ p_cb->evt_type = evt_type;
+
+ if (btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_ENABLE))
+ {
+ p_cb->adv_mode = BTM_BLE_ADV_ENABLE;
+
+ status = BTM_SUCCESS;
+ }
+ }
+ else if (!start && p_cb->adv_mode == BTM_BLE_ADV_ENABLE)
+ {
+ if (btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_DISABLE))
+ {
+ p_cb->adv_mode = BTM_BLE_ADV_DISABLE;
+
+ status = BTM_SUCCESS;
+ }
+ }
+ else
+ {
+ status = BTM_WRONG_MODE;
+ BTM_TRACE_ERROR2("Can not %s Broadcast, device %s in Broadcast mode",
+ (start ? "Start" : "Stop"), (start ? "alerady" :"not"));
+ }
+
+ return status;
+}
+
+
+
+
+
+
+
+/*******************************************************************************
+**
+** Function BTM_RegisterScanReqEvt
+**
+** Description This function is called to register a scan request callback
+** on the advertiser.
+**
+** Parameters p_scan_req_cback: scan request callback. If NULL, remove the
+** registration.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTM_RegisterScanReqEvt(tBTM_BLE_SCAN_REQ_CBACK *p_scan_req_cback)
+{
+#ifdef BTM_BLE_PC_ADV_TEST_MODE // For general stack code (e.g. BTInsight testing), we simply do not define it to exclude or set it to TRUE to include
+ if (BTM_BLE_PC_ADV_TEST_MODE) // For stack component, it is always defined and maps to a global variable g_bDraculaAdvertisingMode
+ {
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+ p_cb->p_scan_req_cback = p_scan_req_cback;
+ }
+#endif
+}
+/*******************************************************************************
+**
+** Function BTM_BleConfigPrivacy
+**
+** Description This function is called to enable or disable the privacy in
+** the local device.
+**
+** Parameters enable: TRUE to enable it; FALSE to disable it.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTM_BleConfigPrivacy(BOOLEAN enable)
+{
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+ BTM_TRACE_EVENT0 (" BTM_BleConfigPrivacy");
+ p_cb->privacy = enable;
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleSetBgConnType
+**
+** Description This function is called to set BLE connectable mode for a
+** peripheral device.
+**
+** Parameters bg_conn_type: it can be auto connection, or selective connection.
+** p_select_cback: callback function when selective connection procedure
+** is being used.
+**
+** Returns void
+**
+*******************************************************************************/
+BOOLEAN BTM_BleSetBgConnType(tBTM_BLE_CONN_TYPE bg_conn_type,
+ tBTM_BLE_SEL_CBACK *p_select_cback)
+{
+ BOOLEAN started = TRUE;
+
+ BTM_TRACE_EVENT0 ("BTM_BleSetBgConnType ");
+
+ if (btm_cb.ble_ctr_cb.bg_conn_type != bg_conn_type)
+ {
+ switch (bg_conn_type)
+ {
+ case BTM_BLE_CONN_AUTO:
+ btm_ble_start_auto_conn(TRUE);
+ break;
+
+ case BTM_BLE_CONN_SELECTIVE:
+ if (btm_cb.ble_ctr_cb.bg_conn_type == BTM_BLE_CONN_AUTO)
+ {
+ btm_ble_start_auto_conn(FALSE);
+ }
+ started = btm_ble_start_select_conn(TRUE, p_select_cback);
+ break;
+
+ case BTM_BLE_CONN_NONE:
+ if (btm_cb.ble_ctr_cb.bg_conn_type == BTM_BLE_CONN_AUTO)
+ {
+ btm_ble_start_auto_conn(FALSE);
+ }
+ else if (btm_cb.ble_ctr_cb.bg_conn_type == BTM_BLE_CONN_SELECTIVE)
+ {
+ btm_ble_start_select_conn(FALSE, NULL);
+ }
+ started = TRUE;
+ break;
+
+ default:
+ BTM_TRACE_ERROR1("invalid bg connection type : %d ", bg_conn_type);
+ started = FALSE;
+ break;
+ }
+
+ if (started)
+ btm_cb.ble_ctr_cb.bg_conn_type = bg_conn_type;
+ }
+ return started;
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleUpdateBgConnDev
+**
+** Description This function is called to add or remove a device into/from
+** background connection procedure. The background connection
+* procedure is decided by the background connection type, it can be
+* auto connection, or selective connection.
+**
+** Parameters add_remove: TRUE to add; FALSE to remove.
+** remote_bda: device address to add/remove.
+**
+** Returns void
+**
+*******************************************************************************/
+BOOLEAN BTM_BleUpdateBgConnDev(BOOLEAN add_remove, BD_ADDR remote_bda)
+{
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+ tBTM_BLE_SEL_CBACK *p_select_cback;
+ BOOLEAN ret = TRUE;
+
+ BTM_TRACE_EVENT0 (" BTM_BleUpdateBgConnDev");
+
+ /* if auto connection is active */
+ if (p_cb->bg_conn_state == BLE_BG_CONN_ACTIVE)
+ {
+ if (p_cb->bg_conn_type == BTM_BLE_CONN_AUTO)
+ {
+ /* terminate auto connection first */
+ ret = btm_ble_start_auto_conn(FALSE);
+ }
+ else if (p_cb->bg_conn_type == BTM_BLE_CONN_SELECTIVE)
+ {
+ p_select_cback = btm_cb.ble_ctr_cb.p_select_cback;
+ ret = btm_ble_start_select_conn(FALSE, NULL);
+ }
+ }
+ if (ret)
+ {
+ /* update white list */
+ ret = btm_update_bg_conn_list(add_remove, remote_bda);
+ btm_update_dev_to_white_list(add_remove, remote_bda, BLE_ADDR_PUBLIC);
+ }
+
+ if (ret && p_cb->bg_conn_state == BLE_BG_CONN_IDLE)
+ {
+ if (p_cb->bg_conn_type == BTM_BLE_CONN_AUTO)
+ {
+ /* restart auto connection */
+ btm_ble_start_auto_conn(TRUE);
+ }
+ else if (p_cb->bg_conn_type == BTM_BLE_CONN_SELECTIVE)
+ {
+ p_select_cback = btm_cb.ble_ctr_cb.p_select_cback;
+ btm_ble_start_select_conn(TRUE, p_select_cback);
+ }
+ }
+ return ret;
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleSetConnMode
+**
+** Description This function is called to set BLE connectable mode for a
+** peripheral device.
+**
+** Parameters directed: is directed connectable mode, or non-directed.
+** p_dir_bda: connectable direct initiator's LE device address
+**
+** Returns void
+**
+*******************************************************************************/
+tBTM_STATUS BTM_BleSetConnMode(BOOLEAN directed, tBLE_BD_ADDR *p_dir_bda)
+{
+ tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
+ tBTM_STATUS status = BTM_SUCCESS;
+ BD_ADDR reconn_bda;
+
+ BTM_TRACE_EVENT0 ("BTM_BleSetConnMode ");
+
+ memcpy(&p_cb->direct_bda, &le_bda_any, sizeof(tBLE_BD_ADDR));
+ p_cb->own_addr_type = BLE_ADDR_PUBLIC;
+
+ if (directed)
+ {
+ if (p_dir_bda)
+ {
+ memcpy(&p_cb->direct_bda, p_dir_bda, sizeof(tBLE_BD_ADDR));
+
+ if (btm_cb.ble_ctr_cb.privacy /* && GAP privacy ad reconnect addr exist */)
+ {
+ /* write reconnect address to controller*/
+ btsnd_hcic_ble_set_random_addr(reconn_bda);
+ }
+ /* else use static address or publich address */
+
+ }
+ else
+ status = BTM_ILLEGAL_VALUE;
+ }
+ else /* undirected connecatable */
+ {
+ if (btm_cb.ble_ctr_cb.privacy /* GAP privacy flag enabled */)
+ {
+ /* generate resolvable private address */
+ btm_gen_resolvable_private_addr();
+ } /* else use publich address */
+
+ }
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleSetAdvParams
+**
+** Description This function is called to set advertising parameters.
+**
+** Parameters adv_int_min: minimum advertising interval
+** adv_int_max: maximum advertising interval
+** p_dir_bda: connectable direct initiator's LE device address
+** chnl_map: advertising channel map.
+**
+** Returns void
+**
+*******************************************************************************/
+tBTM_STATUS BTM_BleSetAdvParams(UINT16 adv_int_min, UINT16 adv_int_max,
+ tBLE_BD_ADDR *p_dir_bda,
+ tBTM_BLE_ADV_CHNL_MAP chnl_map)
+{
+ tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
+ tBTM_STATUS status = BTM_SUCCESS;
+
+ BTM_TRACE_EVENT0 ("BTM_BleSetAdvParams");
+
+ if (!BTM_BLE_VALID_PRAM(adv_int_min, BTM_BLE_ADV_INT_MIN, BTM_BLE_ADV_INT_MAX) ||
+ !BTM_BLE_VALID_PRAM(adv_int_max, BTM_BLE_ADV_INT_MIN, BTM_BLE_ADV_INT_MAX))
+ {
+ return BTM_ILLEGAL_VALUE;
+ }
+
+ p_cb->adv_interval_min = adv_int_min;
+ p_cb->adv_interval_max = adv_int_max;
+ p_cb->adv_chnl_map = chnl_map;
+
+ if (p_dir_bda)
+ {
+ memcpy(&p_cb->direct_bda, p_dir_bda, sizeof(tBLE_BD_ADDR));
+ }
+ else
+ memcpy(&p_cb->direct_bda, &le_bda_any, sizeof(tBLE_BD_ADDR));
+
+ if (p_cb->adv_mode == BTM_BLE_ADV_ENABLE)
+ {
+ BTM_TRACE_EVENT0 ("update params for an active adv");
+
+ if (p_cb->connectable_mode == BTM_BLE_NON_CONNECTABLE)
+ {
+ if (BTM_BLE_VALID_CONN_DIRECT(&p_cb->direct_bda))
+ p_cb->evt_type = BTM_BLE_CONNECT_DIR_EVT;
+ else
+ p_cb->evt_type = BTM_BLE_CONNECT_EVT;
+
+ BTM_TRACE_DEBUG1(" evt_type = %d", p_cb->evt_type);
+ }
+
+ if (!btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_DISABLE))
+ status = BTM_NO_RESOURCES;
+ else
+ /* update adv params */
+ if (!btsnd_hcic_ble_write_adv_params (p_cb->adv_interval_min,
+ p_cb->adv_interval_max,
+ p_cb->evt_type,
+ p_cb->own_addr_type,
+ p_cb->direct_bda.type,
+ p_cb->direct_bda.bda,
+ p_cb->adv_chnl_map,
+ p_cb->afp))
+
+ status = BTM_NO_RESOURCES;
+
+ else if (!btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_ENABLE))
+ {
+ p_cb->adv_mode = BTM_BLE_ADV_DISABLE;
+
+ status = BTM_NO_RESOURCES;
+ }
+
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleReadAdvParams
+**
+** Description This function is called to set advertising parameters.
+**
+** Parameters adv_int_min: minimum advertising interval
+** adv_int_max: maximum advertising interval
+** p_dir_bda: connectable direct initiator's LE device address
+** chnl_map: advertising channel map.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTM_BleReadAdvParams (UINT16 *adv_int_min, UINT16 *adv_int_max,
+ tBLE_BD_ADDR *p_dir_bda, tBTM_BLE_ADV_CHNL_MAP *p_chnl_map)
+{
+ tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
+
+ BTM_TRACE_EVENT0 ("BTM_BleReadAdvParams ");
+
+ *adv_int_min = p_cb->adv_interval_min;
+ *adv_int_max = p_cb->adv_interval_max;
+ *p_chnl_map = p_cb->adv_chnl_map;
+
+ if (p_dir_bda != NULL)
+ {
+ memcpy(p_dir_bda, &p_cb->direct_bda, sizeof(tBLE_BD_ADDR));
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_BleSetScanParams
+**
+** Description This function is called to set Scan parameters.
+**
+** Parameters adv_int_min: minimum advertising interval
+** adv_int_max: maximum advertising interval
+** p_dir_bda: connectable direct initiator's LE device address
+** chnl_map: advertising channel map.
+** scan_type: active scan or passive scan
+**
+** Returns void
+**
+*******************************************************************************/
+void BTM_BleSetScanParams(UINT16 scan_interval, UINT16 scan_window, tBTM_BLE_SCAN_MODE scan_mode)
+{
+ tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
+
+ BTM_TRACE_EVENT0 (" BTM_BleSetScanParams");
+
+ if (BTM_BLE_VALID_PRAM(scan_interval, BTM_BLE_SCAN_INT_MIN, BTM_BLE_SCAN_INT_MAX) &&
+ BTM_BLE_VALID_PRAM(scan_window, BTM_BLE_SCAN_WIN_MIN, BTM_BLE_SCAN_WIN_MAX) &&
+ (scan_mode == BTM_BLE_SCAN_MODE_ACTI || scan_mode == BTM_BLE_SCAN_MODE_PASS))
+ {
+ p_cb->scan_type = scan_mode;
+
+ if (BTM_BLE_CONN_PARAM_UNDEF != scan_interval)
+ p_cb->scan_interval = scan_interval;
+
+ if (BTM_BLE_CONN_PARAM_UNDEF != scan_window)
+ p_cb->scan_window = scan_window;
+ }
+ else
+ {
+ BTM_TRACE_ERROR2("Illegal params: scan_interval = %d scan_window = %d",
+ scan_interval, scan_window);
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleWriteScanRsp
+**
+** Description This function is called to write LE scan response.
+**
+** Parameters: p_scan_rsp: scan response information.
+**
+** Returns void
+**
+*******************************************************************************/
+tBTM_STATUS BTM_BleWriteScanRsp(tBTM_BLE_AD_MASK data_mask, tBTM_BLE_ADV_DATA *p_data)
+{
+ tBTM_STATUS status = BTM_NO_RESOURCES;
+ UINT8 rsp_data[BTM_BLE_AD_DATA_LEN],
+ *p = rsp_data;
+
+ BTM_TRACE_EVENT0 (" BTM_BleWriteScanRsp");
+ memset(rsp_data, 0, BTM_BLE_AD_DATA_LEN);
+ btm_ble_build_adv_data(&data_mask, &p, p_data);
+
+ if (btsnd_hcic_ble_set_scan_rsp_data((UINT8)(p - rsp_data), rsp_data))
+ {
+ status = BTM_SUCCESS;
+
+ if (p_data != NULL)
+ btm_cb.ble_ctr_cb.inq_var.scan_rsp = TRUE;
+ else
+ btm_cb.ble_ctr_cb.inq_var.scan_rsp = FALSE;
+ }
+ else
+ status = BTM_ILLEGAL_VALUE;
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleWriteAdvData
+**
+** Description This function is called to write advertising data.
+**
+** Parameters: None.
+**
+** Returns void
+**
+*******************************************************************************/
+tBTM_STATUS BTM_BleWriteAdvData(tBTM_BLE_AD_MASK data_mask, tBTM_BLE_ADV_DATA *p_data)
+{
+ tBTM_BLE_LOCAL_ADV_DATA *p_cb_data = &btm_cb.ble_ctr_cb.inq_var.adv_data;
+ UINT8 *p;
+ UINT16 mask = data_mask;
+
+ memset(p_cb_data, 0, sizeof(tBTM_BLE_LOCAL_ADV_DATA));
+ p = p_cb_data->ad_data;
+ p_cb_data->data_mask = data_mask;
+
+ BTM_TRACE_EVENT0 ("BTM_BleWriteAdvData ");
+ p_cb_data->p_flags = btm_ble_build_adv_data(&mask, &p, p_data);
+
+ p_cb_data->p_pad = p;
+
+ if (data_mask != 0)
+ {
+ BTM_TRACE_ERROR0("Partial data write into ADV");
+ }
+
+ p_cb_data->data_mask &= ~mask;
+
+ if (btsnd_hcic_ble_set_adv_data((UINT8)(p_cb_data->p_pad - p_cb_data->ad_data),
+ p_cb_data->ad_data))
+ return BTM_SUCCESS;
+ else
+ return BTM_NO_RESOURCES;
+
+}
+
+/*******************************************************************************
+**
+** Function BTM_CheckAdvData
+**
+** Description This function is called to get ADV data for a specific type.
+**
+** Parameters p_adv - pointer of ADV data
+** type - finding ADV data type
+** p_length - return the length of ADV data not including type
+**
+** Returns pointer of ADV data
+**
+*******************************************************************************/
+UINT8 *BTM_CheckAdvData( UINT8 *p_adv, UINT8 type, UINT8 *p_length)
+{
+ UINT8 *p = p_adv;
+ UINT8 length;
+ UINT8 adv_type;
+ BTM_TRACE_API1("BTM_CheckAdvData type=0x%02X", type);
+
+ STREAM_TO_UINT8(length, p);
+
+ while ( length && (p - p_adv <= BTM_BLE_CACHE_ADV_DATA_MAX))
+ {
+ STREAM_TO_UINT8(adv_type, p);
+
+ if ( adv_type == type )
+ {
+ /* length doesn't include itself */
+ *p_length = length - 1; /* minus the length of type */
+ return p;
+ }
+ p += length - 1; /* skip the length of data */
+ STREAM_TO_UINT8(length, p);
+ }
+
+ *p_length = 0;
+ return NULL;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_build_adv_data
+**
+** Description This function is called build the adv data and rsp data.
+*******************************************************************************/
+static UINT8 *btm_ble_build_adv_data(tBTM_BLE_AD_MASK *p_data_mask, UINT8 **p_dst, tBTM_BLE_ADV_DATA *p_data)
+{
+ UINT16 data_mask = *p_data_mask;
+ UINT8 *p = *p_dst,
+ *p_flag = NULL;
+ UINT16 len = BTM_BLE_AD_DATA_LEN, cp_len = 0;
+ UINT8 i = 0;
+ tBTM_BLE_ATTR *p_attr;
+ tBTM_BLE_PROP_ELEM *p_elem;
+
+ BTM_TRACE_EVENT0 (" btm_ble_build_adv_data");
+
+ /* build the adv data structure and build the data string */
+ if (data_mask)
+ {
+ /* flags */
+ if (data_mask & BTM_BLE_AD_BIT_FLAGS)
+ {
+ *p++ = 2;
+ *p++ = BTM_BLE_AD_TYPE_FLAG;
+ p_flag = p;
+ if (p_data)
+ *p++ = p_data->flag;
+ else
+ *p++ = 0;
+
+ len -= 3;
+
+ data_mask &= ~BTM_BLE_AD_BIT_FLAGS;
+ }
+ /* device name */
+ if (len > 2 && data_mask & BTM_BLE_AD_BIT_DEV_NAME)
+ {
+ if (strlen(btm_cb.cfg.bd_name) > (UINT16)(len - 2))
+ {
+ *p++ = len - 2 + 1;
+ *p++ = BTM_BLE_AD_TYPE_NAME_SHORT;
+ ARRAY_TO_STREAM(p, btm_cb.cfg.bd_name, len - 2);
+ }
+ else
+ {
+ cp_len = (UINT16)strlen(btm_cb.cfg.bd_name);
+ *p++ = cp_len + 1;
+ *p++ = BTM_BLE_AD_TYPE_NAME_CMPL;
+ ARRAY_TO_STREAM(p, btm_cb.cfg.bd_name, cp_len);
+ }
+
+ len -= (cp_len + 2);
+ data_mask &= ~BTM_BLE_AD_BIT_DEV_NAME;
+ }
+ /* manufacturer data */
+ if (len > 2 && data_mask & BTM_BLE_AD_BIT_MANU &&
+ p_data && p_data->manu.len != 0 && p_data->manu.p_val)
+ {
+ if (p_data->manu.len > (len - 2))
+ cp_len = len - 2;
+ else
+ cp_len = p_data->manu.len;
+
+ *p++ = cp_len + 1;
+ *p++ = BTM_BLE_AD_TYPE_MANU;
+ ARRAY_TO_STREAM(p, p_data->manu.p_val, cp_len);
+
+ len -= (cp_len + 2);
+ data_mask &= ~BTM_BLE_AD_BIT_MANU;
+ }
+ /* TX power */
+ if (len > 2 && data_mask & BTM_BLE_AD_BIT_TX_PWR)
+ {
+ *p++ = 2;
+ *p++ = BTM_BLE_AD_TYPE_TX_PWR;
+ *p++ = btm_cb.ble_ctr_cb.inq_var.tx_power;
+ len -= 3;
+
+ data_mask &= ~BTM_BLE_AD_BIT_TX_PWR;
+ }
+ /* services */
+ if (len > 2 && data_mask & BTM_BLE_AD_BIT_SERVICE &&
+ p_data && p_data->services.num_service != 0 &&
+ p_data->services.p_uuid)
+ {
+ if (p_data->services.num_service * 2 > (len - 2))
+ {
+ cp_len = (len - 2)/2;
+ *p ++ = 1 + cp_len * 2;
+ *p++ = BTM_BLE_AD_TYPE_SRV_PART;
+ }
+ else
+ {
+ cp_len = p_data->services.num_service;
+ *p++ = 1 + cp_len * 2;
+ *p++ = BTM_BLE_AD_TYPE_SRV_CMPL;
+ }
+ for (i = 0; i < cp_len; i ++)
+ {
+ UINT16_TO_STREAM(p, *(p_data->services.p_uuid + i));
+ }
+
+ len -= (cp_len * 2 + 2);
+ data_mask &= ~BTM_BLE_AD_BIT_SERVICE;
+ }
+ if (len >= 6 && data_mask & BTM_BLE_AD_BIT_INT_RANGE &&
+ p_data)
+ {
+ *p++ = 5;
+ *p++ = BTM_BLE_AD_TYPE_INT_RANGE;
+ UINT16_TO_STREAM(p, p_data->int_range.low);
+ UINT16_TO_STREAM(p, p_data->int_range.hi);
+ len -= 6;
+ data_mask &= ~BTM_BLE_AD_BIT_INT_RANGE;
+ }
+ if (data_mask & BTM_BLE_AD_BIT_ATTR && p_data && p_data->attr.num_attr != 0)
+ {
+ for (i = 0; i < p_data->attr.num_attr ; i ++)
+ {
+ p_attr = p_data->attr.attr_list + i;
+
+ if (len >= (2 + 2 + p_attr->data_len))/* len byte(1) + ATTR type(1) + Uuid len(2) + value length */
+ {
+ *p ++ = p_attr->data_len + 2 + 1; /* Uuid len + value length */
+ *p ++ = BTM_BLE_AD_TYPE_ATTR;
+ UINT16_TO_STREAM(p, p_attr->uuid);
+ ARRAY_TO_STREAM(p, p_attr->p_data, p_attr->data_len);
+
+ len -= (4 + p_attr->data_len);
+ }
+ else
+ break;
+ }
+ if (i == p_data->attr.num_attr)
+ data_mask &= ~BTM_BLE_AD_BIT_ATTR;
+ }
+ if (data_mask & BTM_BLE_AD_BIT_PROPRIETARY && p_data && p_data->p_proprietary)
+ {
+ for (i = 0; i < p_data->p_proprietary->num_elem ; i ++)
+ {
+ p_elem = p_data->p_proprietary->p_elem + i;
+
+ if (len >= (2 + p_elem->len))/* len byte(1) + ATTR type(1) + Uuid len(2) + value length */
+ {
+ *p ++ = p_elem->len + 1; /* Uuid len + value length */
+ *p ++ = p_elem->adv_type;
+ ARRAY_TO_STREAM(p, p_elem->p_val, p_elem->len);
+
+ len -= (2 + p_elem->len);
+ }
+ else
+ {
+ BTM_TRACE_WARNING0("data exceed max adv packet length");
+ break;
+ }
+ }
+ data_mask &= ~BTM_BLE_AD_BIT_PROPRIETARY;
+ }
+ }
+
+ *p_data_mask = data_mask;
+ *p_dst = p;
+
+ return p_flag;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_set_discoverability
+**
+** Description This function is called to set BLE discoverable mode.
+**
+** Parameters: mode: discoverability mode.
+**
+** Returns void
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_set_discoverability(UINT16 combined_mode)
+{
+ tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
+ UINT16 mode = (combined_mode & BTM_BLE_DISCOVERABLE_MASK);
+ UINT8 flag = 0;
+ UINT8 new_mode = BTM_BLE_ADV_ENABLE;
+ UINT8 evt_type = (p_cb->connectable_mode == BTM_BLE_NON_CONNECTABLE) ? \
+ ((p_cb->scan_rsp) ? BTM_BLE_DISCOVER_EVT : BTM_BLE_NON_CONNECT_EVT )\
+ : BTM_BLE_CONNECT_EVT;
+ tBTM_STATUS status = BTM_SUCCESS;
+
+ BTM_TRACE_EVENT2 ("btm_ble_set_discoverability mode=0x%0x combined_mode=0x%x", mode, combined_mode);
+
+ /*** Check mode parameter ***/
+ if (mode > BTM_BLE_MAX_DISCOVERABLE)
+ return(BTM_ILLEGAL_VALUE);
+
+ p_cb->br_edr_supported_flag |= (combined_mode & BTM_DISCOVERABLE_MASK);
+ p_cb->discoverable_mode = mode;
+
+ if (!p_cb->br_edr_supported_flag)
+ {
+ flag = BTM_BLE_BREDR_NOT_SPT;
+ BTM_TRACE_DEBUG1("btm_ble_set_discoverability (BREDR not sup)flag=0x%x",flag);
+ }
+
+ BTM_TRACE_DEBUG1 ("br_edr_supported=0x%x", p_cb->br_edr_supported_flag);
+
+ if (mode == BTM_BLE_LIMITED_DISCOVERABLE || mode == BTM_BLE_GENERAL_DISCOVERABLE)
+ {
+ BTM_TRACE_EVENT0 ("mode == BTM_BLE_LIMITED_DISCOVERABLE ");
+ /* write ADV data with limited disc flag */
+ if (mode == BTM_BLE_LIMITED_DISCOVERABLE)
+ flag |= BTM_BLE_LIMIT_DISC_FLAG ;
+ else
+ flag |= BTM_BLE_GEN_DISC_FLAG;
+ }
+ else /* non-discoverable */
+ {
+ BTM_TRACE_EVENT0 ("mode == BTM_BLE_NON_DISCOVERABLE ");
+
+ if (p_cb->connectable_mode == BTM_BLE_NON_CONNECTABLE)
+ {
+ p_cb->br_edr_supported_flag = 0;
+
+ BTM_TRACE_EVENT0 ("always disable adv in non-discoverable non-connectable mode if no scan rsp ");
+ if (!p_cb->scan_rsp )
+ new_mode = BTM_BLE_ADV_DISABLE;
+ }
+ else
+ {
+ if (BTM_BLE_VALID_CONN_DIRECT(&p_cb->direct_bda))
+ {
+ BTM_TRACE_DEBUG0("evt_type = BTM_BLE_CONNECT_DIR_EVT");
+ evt_type = BTM_BLE_CONNECT_DIR_EVT;
+ }
+ else
+ {
+ BTM_TRACE_DEBUG0(" evt_type = BTM_BLE_CONNECT_EVT");
+ evt_type = BTM_BLE_CONNECT_EVT;
+ }
+ }
+ }
+ btm_ble_update_adv_flag(flag);
+
+ /* update adv params if start advertising */
+ BTM_TRACE_EVENT2 ("evt_type=0x%x p-cb->evt_type=0x%x ", evt_type, p_cb->evt_type);
+ if (new_mode == BTM_BLE_ADV_ENABLE && evt_type != p_cb->evt_type)
+ {
+ if (p_cb->adv_mode == BTM_BLE_ADV_ENABLE)
+ {
+ BTM_TRACE_EVENT0 ("Set Adv disable");
+ p_cb->adv_mode = BTM_BLE_ADV_DISABLE;
+ btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_DISABLE);
+ }
+
+ /* update adv params */
+ if (!btsnd_hcic_ble_write_adv_params ((UINT16)(p_cb->adv_interval_min ? p_cb->adv_interval_min : BTM_BLE_GAP_ADV_INT),
+ (UINT16)(p_cb->adv_interval_max ? p_cb->adv_interval_max : BTM_BLE_GAP_ADV_INT),
+ evt_type,
+ p_cb->own_addr_type,
+ p_cb->direct_bda.type, p_cb->direct_bda.bda,
+ p_cb->adv_chnl_map,
+ p_cb->afp))
+
+ status = BTM_NO_RESOURCES;
+ else
+ p_cb->evt_type = evt_type;
+
+ }
+ if (status == BTM_SUCCESS && p_cb->adv_mode != new_mode)
+ {
+ /* update advertising mode */
+ if (!btsnd_hcic_ble_set_adv_enable (new_mode))
+ status = BTM_NO_RESOURCES;
+ else
+ p_cb->adv_mode = new_mode;
+ }
+
+ /* set up stop advertising timer */
+ if (status == BTM_SUCCESS && mode == BTM_BLE_LIMITED_DISCOVERABLE)
+ {
+ BTM_TRACE_EVENT1 ("start timer for limited disc mode duration=%d (30 secs)", BTM_BLE_GAP_LIM_TOUT);
+ /* start Tgap(lim_timeout) */
+ btu_start_timer (&p_cb->inq_timer_ent, BTU_TTYPE_BLE_GAP_LIM_DISC,
+ BTM_BLE_GAP_LIM_TOUT);
+ }
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_set_connectability
+**
+** Description This function is called to set BLE connectability mode.
+**
+** Parameters: mode: connectability mode.
+**
+** Returns void
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_set_connectability(UINT16 combined_mode)
+{
+ tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
+ UINT16 mode = (combined_mode & BTM_BLE_CONNECTABLE_MASK);
+ UINT8 cur_flag = 0;
+ UINT8 cur_br_edr_not_sup_flag;
+ UINT8 new_flag;
+ UINT8 new_mode = BTM_BLE_ADV_ENABLE;
+ UINT8 evt_type = (p_cb->scan_rsp) ? BTM_BLE_DISCOVER_EVT: BTM_BLE_NON_CONNECT_EVT;
+ tBTM_STATUS status = BTM_SUCCESS;
+
+ BTM_TRACE_EVENT2 ("btm_ble_set_connectability mode=0x%0x combined_mode=0x%x", mode, combined_mode);
+
+ /*** Check mode parameter ***/
+ if (mode > BTM_BLE_MAX_CONNECTABLE)
+ return(BTM_ILLEGAL_VALUE);
+ if (btm_cb.ble_ctr_cb.inq_var.adv_data.p_flags)
+ cur_flag = *btm_cb.ble_ctr_cb.inq_var.adv_data.p_flags ;
+ cur_br_edr_not_sup_flag = (cur_flag & ((UINT8) BTM_BLE_BREDR_NOT_SPT));
+
+ p_cb->br_edr_supported_flag |= ((combined_mode & BTM_CONNECTABLE_MASK) << 4);
+ if (p_cb->br_edr_supported_flag && cur_br_edr_not_sup_flag)
+ {
+ new_flag = cur_flag & ((UINT8) (~BTM_BLE_BREDR_NOT_SPT));
+ BTM_TRACE_EVENT2 ("new flag=0x%x cur flag=0x%x",new_flag, cur_flag);
+ btm_ble_update_adv_flag(new_flag);
+ }
+ p_cb->connectable_mode = mode;
+
+ if (mode == BTM_BLE_NON_CONNECTABLE)
+ {
+ if (p_cb->discoverable_mode == BTM_BLE_NON_DISCOVERABLE)
+ {
+ p_cb->br_edr_supported_flag = 0;
+ BTM_TRACE_EVENT0 ("always disable adv in non-discoverable non-connectable mode with no scan rsp");
+ if(!p_cb->scan_rsp)
+ new_mode = BTM_BLE_ADV_DISABLE;
+ }
+ }
+ else /* connectable */
+ {
+ BTM_TRACE_DEBUG2("btm_ble_set_connectability: mode = %04x discoverable_mode= %02x", mode, p_cb->discoverable_mode);
+
+ if (BTM_BLE_VALID_CONN_DIRECT(&p_cb->direct_bda))
+ {
+ BTM_TRACE_DEBUG0("evt_type = BTM_BLE_CONNECT_DIR_EVT");
+ evt_type = BTM_BLE_CONNECT_DIR_EVT;
+ }
+ else
+ {
+ BTM_TRACE_DEBUG0(" evt_type = BTM_BLE_CONNECT_EVT");
+ evt_type = BTM_BLE_CONNECT_EVT;
+ }
+ }
+
+ /* update adv params if needed */
+ if (p_cb->evt_type != evt_type && new_mode == BTM_BLE_ADV_ENABLE)
+ {
+ if (p_cb->adv_mode == BTM_BLE_ADV_ENABLE)
+ {
+ p_cb->adv_mode = BTM_BLE_ADV_DISABLE;
+ btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_DISABLE);
+ }
+
+ if (!btsnd_hcic_ble_write_adv_params ((UINT16)(p_cb->adv_interval_min ? p_cb->adv_interval_min : BTM_BLE_GAP_ADV_INT),
+ (UINT16)(p_cb->adv_interval_max ? p_cb->adv_interval_max : BTM_BLE_GAP_ADV_INT),
+ evt_type,
+ p_cb->own_addr_type,
+ p_cb->direct_bda.type,
+ p_cb->direct_bda.bda,
+ p_cb->adv_chnl_map,
+ p_cb->afp))
+ status = BTM_NO_RESOURCES;
+ else
+ p_cb->evt_type = evt_type;
+ }
+ /* update advertising mode */
+ if (status == BTM_SUCCESS && new_mode != p_cb->adv_mode)
+ {
+ if (btsnd_hcic_ble_set_adv_enable (new_mode))
+ {
+ status = BTM_SUCCESS;
+
+ p_cb->adv_mode = new_mode;
+ }
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_start_inquiry
+**
+** Description This function is called to start BLE inquiry procedure.
+** If the duration is zero, the periodic inquiry mode is cancelled.
+**
+** Parameters: mode - GENERAL or LIMITED inquiry
+** p_inq_params - pointer to the BLE inquiry parameter.
+** p_results_cb - callback returning pointer to results (tBTM_INQ_RESULTS)
+** p_cmpl_cb - callback indicating the end of an inquiry
+**
+**
+**
+** Returns BTM_CMD_STARTED if successfully started
+** BTM_ILLEGAL_VALUE if a bad parameter is detected
+** BTM_NO_RESOURCES if could not allocate a message buffer
+** BTM_SUCCESS - if cancelling the periodic inquiry
+** BTM_BUSY - if an inquiry is already active
+** BTM_WRONG_MODE if the device is not up.
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_start_inquiry (UINT8 mode, UINT8 duration)
+{
+ tBTM_STATUS status = BTM_NO_RESOURCES;
+ tBTM_BLE_INQ_CB *p_inq = &btm_cb.ble_ctr_cb.inq_var;
+
+ BTM_TRACE_DEBUG2("btm_ble_start_inquiry: mode = %02x inq_active = %d", mode, btm_cb.btm_inq_vars.inq_active);
+
+ if (p_inq->proc_mode != BTM_BLE_INQUIRY_NONE)
+ {
+ BTM_TRACE_ERROR0("LE scan is active, can not start inquiry");
+ return(BTM_BUSY);
+ }
+
+ btm_update_scanner_filter_policy(SP_ADV_ALL);
+
+ /* start scan, already enable duplicate filtering */
+ if (btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_ENABLE, BTM_BLE_DUPLICATE_DISABLE))
+ {
+ status = BTM_SUCCESS;
+ p_inq->proc_mode = mode;
+
+ if (duration != 0)
+ {
+ /* start inquiry timer */
+ btu_start_timer (&p_inq->inq_timer_ent, BTU_TTYPE_BLE_INQUIRY, duration);
+ }
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_read_remote_name_cmpl
+**
+** Description This function is called when BLE remote name is received.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_read_remote_name_cmpl(BOOLEAN status, BD_ADDR bda, UINT16 length, char *p_name)
+{
+ UINT8 hci_status = HCI_SUCCESS;
+ BD_NAME bd_name;
+
+ memset(bd_name, 0, BD_NAME_LEN);
+ memcpy((UINT8*)bd_name, p_name, length);
+
+ if ((!status) || (length==0))
+ {
+ hci_status = HCI_ERR_HOST_TIMEOUT;
+ }
+
+ btm_process_remote_name(bda, bd_name, length, hci_status);
+ btm_sec_rmt_name_request_complete (bda, (UINT8 *)p_name, hci_status);
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_read_remote_name
+**
+** Description This function read remote LE device name using GATT read
+** procedure.
+**
+** Parameters: None.
+**
+** Returns void
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_read_remote_name(BD_ADDR remote_bda, tBTM_INQ_INFO *p_cur, tBTM_CMPL_CB *p_cb)
+{
+ tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+
+ if (p_cur &&
+ p_cur->results.ble_evt_type != BTM_BLE_EVT_CONN_ADV &&
+ p_cur->results.ble_evt_type != BTM_BLE_EVT_CONN_DIR_ADV)
+ {
+ BTM_TRACE_DEBUG0("name request to non-connectable device failed.");
+ return BTM_ERR_PROCESSING;
+ }
+
+ /* read remote device name using GATT procedure */
+ if (p_inq->remname_active)
+ return BTM_BUSY;
+
+ if (!GAP_BleReadPeerDevName(remote_bda, btm_ble_read_remote_name_cmpl))
+ return BTM_BUSY;
+
+ p_inq->p_remname_cmpl_cb = p_cb;
+ p_inq->remname_active = TRUE;
+
+ memcpy(p_inq->remname_bda, remote_bda, BD_ADDR_LEN);
+
+ btu_start_timer (&p_inq->rmt_name_timer_ent,
+ BTU_TTYPE_BTM_RMT_NAME,
+ BTM_EXT_BLE_RMT_NAME_TIMEOUT);
+
+ return BTM_CMD_STARTED;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_cancel_remote_name
+**
+** Description This function cancel read remote LE device name.
+**
+** Parameters: None.
+**
+** Returns void
+**
+*******************************************************************************/
+BOOLEAN btm_ble_cancel_remote_name(BD_ADDR remote_bda)
+{
+ tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+ BOOLEAN status;
+
+ status = GAP_BleCancelReadPeerDevName(remote_bda);
+
+ p_inq->remname_active = FALSE;
+ memset(p_inq->remname_bda, 0, BD_ADDR_LEN);
+ btu_stop_timer(&p_inq->rmt_name_timer_ent);
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_update_adv_flag
+**
+** Description This function update the limited discoverable flag in the adv
+** data.
+**
+** Parameters: None.
+**
+** Returns void
+**
+*******************************************************************************/
+static void btm_ble_update_adv_flag(UINT8 flag)
+{
+ tBTM_BLE_LOCAL_ADV_DATA *p_adv_data = &btm_cb.ble_ctr_cb.inq_var.adv_data;
+ UINT8 *p;
+
+ BTM_TRACE_DEBUG1 ("btm_ble_update_adv_flag new=0x%x", flag);
+
+ if (p_adv_data->p_flags != NULL)
+ {
+ BTM_TRACE_DEBUG1 ("btm_ble_update_adv_flag old=0x%x", *p_adv_data->p_flags);
+ *p_adv_data->p_flags = flag;
+ }
+ else /* no FLAGS in ADV data*/
+ {
+ p = (p_adv_data->p_pad == NULL) ? p_adv_data->ad_data : p_adv_data->p_pad;
+ /* need 3 bytes space to stuff in the flags, if not */
+ /* erase all written data, just for flags */
+ if ((BTM_BLE_AD_DATA_LEN - (p - p_adv_data->ad_data)) < 3)
+ {
+ p = p_adv_data->p_pad = p_adv_data->ad_data;
+ memset(p_adv_data->ad_data, 0, BTM_BLE_AD_DATA_LEN);
+ }
+
+ *p++ = 2;
+ *p++ = BTM_BLE_AD_TYPE_FLAG;
+ p_adv_data->p_flags = p;
+ *p++ = flag;
+ p_adv_data->p_pad = p;
+ }
+
+ if (btsnd_hcic_ble_set_adv_data((UINT8)(p_adv_data->p_pad - p_adv_data->ad_data),
+ p_adv_data->ad_data))
+ p_adv_data->data_mask |= BTM_BLE_AD_BIT_FLAGS;
+
+}
+
+#if 0
+/*******************************************************************************
+**
+** Function btm_ble_parse_adv_data
+**
+** Description This function parse the adv data into a structure.
+**
+** Returns pointer to entry, or NULL if not found
+**
+*******************************************************************************/
+static void btm_ble_parse_adv_data(tBTM_INQ_INFO *p_info, UINT8 *p_data,
+ UINT8 len, tBTM_BLE_INQ_DATA *p_adv_data, UINT8 *p_buf)
+{
+ UINT8 *p_cur = p_data;
+ UINT8 ad_len, ad_type, ad_flag;
+ tBTM_BLE_ATTR *p_attr;
+
+ BTM_TRACE_EVENT0 (" btm_ble_parse_adv_data");
+
+ while (len > 0)
+ {
+ BTM_TRACE_DEBUG1("btm_ble_parse_adv_data: len = %d", len);
+ if ((ad_len = *p_cur ++) == 0)
+ break;
+
+ ad_type = *p_cur ++;
+
+ BTM_TRACE_DEBUG2(" ad_type = %02x ad_len = %d", ad_type, ad_len);
+
+ switch (ad_type)
+ {
+ case BTM_BLE_AD_TYPE_NAME_SHORT:
+
+ case BTM_BLE_AD_TYPE_NAME_CMPL:
+ p_adv_data->ad_mask |= BTM_BLE_AD_BIT_DEV_NAME;
+ if (p_info)
+ {
+ p_info->remote_name_type =(ad_type == BTM_BLE_AD_TYPE_NAME_SHORT) ?
+ BTM_BLE_NAME_SHORT: BTM_BLE_NAME_CMPL;
+ memcpy(p_info->remote_name, p_cur, ad_len -1);
+ p_info->remote_name[ad_len] = 0;
+ p_adv_data->p_remote_name = p_info->remote_name;
+ p_info->remote_name_len = p_adv_data->remote_name_len = ad_len - 1;
+ BTM_TRACE_DEBUG1("BTM_BLE_AD_TYPE_NAME name = %s",p_adv_data->p_remote_name);
+ }
+ p_cur += (ad_len -1);
+
+ break;
+
+ case BTM_BLE_AD_TYPE_FLAG:
+ p_adv_data->ad_mask |= BTM_BLE_AD_BIT_FLAGS;
+ ad_flag = *p_cur ++;
+ p_adv_data->flag = (UINT8)(ad_flag & BTM_BLE_ADV_FLAG_MASK) ;
+ BTM_TRACE_DEBUG3("BTM_BLE_AD_TYPE_FLAG flag = %s | %s | %s",
+ (p_adv_data->flag & BTM_BLE_LIMIT_DISC_FLAG)? "LE_LIMIT_DISC" : "",
+ (p_adv_data->flag & BTM_BLE_GEN_DISC_FLAG)? "LE_GENERAL_DISC" : "",
+ (p_adv_data->flag & BTM_BLE_BREDR_NOT_SPT)? "LE Only device" : "");
+ break;
+
+ case BTM_BLE_AD_TYPE_TX_PWR:
+ p_adv_data->ad_mask |= BTM_BLE_AD_BIT_TX_PWR;
+ p_adv_data->tx_power_level = (INT8)*p_cur ++;
+ BTM_TRACE_DEBUG1("BTM_BLE_AD_TYPE_TX_PWR tx_level = %d", p_adv_data->tx_power_level);
+ break;
+
+ case BTM_BLE_AD_TYPE_ATTR:
+ p_adv_data->ad_mask |= BTM_BLE_AD_BIT_ATTR;
+ p_attr = &p_adv_data->attr_data.attr_list[p_adv_data->attr_data.num_attr];
+ p_attr->uuid = *p_cur ++;
+
+ if (ad_len > 3)
+ {
+ p_attr->data_len = ad_len - 3;
+ p_attr->p_data = p_buf;
+ memcpy(p_attr->p_data, p_cur, p_attr->data_len);
+ p_buf += p_attr->data_len;
+ }
+
+ p_adv_data->attr_data.num_attr ++;
+ BTM_TRACE_DEBUG2("BTM_BLE_AD_TYPE_ATTR[%d] uuid = 0x%04x",p_adv_data->attr_data.num_attr, p_attr->uuid);
+ break;
+
+ case BTM_BLE_AD_TYPE_MANU:
+
+ case BTM_BLE_AD_TYPE_SRV_CMPL:
+ case BTM_BLE_AD_TYPE_SRV_PART:
+ p_adv_data->ad_mask |= ad_type;
+ /* need allocate memory to store UUID list */
+ p_adv_data->service.num_service = (ad_len - 1)/2;
+ BTM_TRACE_DEBUG1("service UUID list, num = %d", p_adv_data->service.num_service);
+
+ default:
+ p_cur += (ad_len - 1);
+ break;
+ }
+ len -= (ad_len + 1);
+ }
+}
+#endif
+
+/*******************************************************************************
+**
+** Function btm_ble_cache_adv_data
+**
+** Description Update advertising cache data.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_cache_adv_data(tBTM_INQ_RESULTS *p_cur, UINT8 data_len, UINT8 *p, UINT8 evt_type)
+{
+ tBTM_BLE_INQ_CB *p_le_inq_cb = &btm_cb.ble_ctr_cb.inq_var;
+ UINT8 *p_cache;
+ UINT8 length;
+
+ /* cache adv report/scan response data */
+ if (evt_type != BTM_BLE_SCAN_RSP_EVT)
+ {
+ p_le_inq_cb->adv_len = 0;
+ memset(p_le_inq_cb->adv_data_cache, 0, BTM_BLE_CACHE_ADV_DATA_MAX);
+ }
+
+ if (data_len > 0)
+ {
+ p_cache = &p_le_inq_cb->adv_data_cache[p_le_inq_cb->adv_len];
+ STREAM_TO_UINT8(length, p);
+ while ( length && ((p_le_inq_cb->adv_len + length + 1) <= BTM_BLE_CACHE_ADV_DATA_MAX))
+ {
+ /* copy from the length byte & data into cache */
+ memcpy(p_cache, p-1, length+1);
+ /* advance the cache pointer past data */
+ p_cache += length+1;
+ /* increment cache length */
+ p_le_inq_cb->adv_len += length+1;
+ /* skip the length of data */
+ p += length;
+ STREAM_TO_UINT8(length, p);
+ }
+ }
+
+ /* parse service UUID from adv packet and save it in inq db eir_uuid */
+ /* TODO */
+}
+/*******************************************************************************
+**
+** Function btm_ble_is_discoverable
+**
+** Description check ADV flag to make sure device is discoverable and match
+** the search condition
+**
+** Parameters
+**
+** Returns void
+**
+*******************************************************************************/
+BOOLEAN btm_ble_is_discoverable(BD_ADDR bda, UINT8 evt_type, UINT8 *p)
+{
+ BOOLEAN is_discoverable = FALSE;
+ UINT8 *p_flag, flag = 0;
+ UINT8 data_len;
+ tBTM_INQ_PARMS *p_cond = &btm_cb.btm_inq_vars.inqparms;
+
+ STREAM_TO_UINT8 (data_len, p);
+
+ /* for observer, always "discoverable */
+ if (btm_cb.ble_ctr_cb.inq_var.proc_mode == BTM_BLE_OBSERVE ||
+ (btm_cb.ble_ctr_cb.inq_var.proc_mode == BTM_BLE_SELECT_SCAN &&
+ btm_cb.ble_ctr_cb.bg_conn_type == BTM_BLE_CONN_SELECTIVE))
+ return TRUE;
+
+ /* does not match filter condition */
+ if (p_cond->filter_cond_type == BTM_FILTER_COND_BD_ADDR &&
+ memcmp(bda, p_cond->filter_cond.bdaddr_cond, BD_ADDR_LEN) != 0)
+ {
+ BTM_TRACE_DEBUG0("BD ADDR does not meet filter condition");
+ return FALSE;
+ }
+
+ /* scan response does not include the flag */
+ if (evt_type == BTM_BLE_SCAN_RSP_EVT)
+ return FALSE;
+
+ if (data_len > BTM_BLE_ADV_DATA_LEN_MAX)
+ {
+ BTM_TRACE_WARNING1("ADV data too long %d. discard", data_len);
+ return FALSE;
+ }
+
+ if (data_len != 0)
+ {
+ if ((p_flag = BTM_CheckAdvData(p, BTM_BLE_AD_TYPE_FLAG, &data_len)) != NULL)
+ {
+ flag = * p_flag;
+
+ if ((btm_cb.ble_ctr_cb.inq_var.proc_mode == BTM_BLE_GENERAL_INQUIRY) &&
+ (flag & (BTM_BLE_LIMIT_DISC_FLAG|BTM_BLE_GEN_DISC_FLAG)) != 0)
+ {
+ BTM_TRACE_DEBUG0("Find Generable Discoverable device");
+ is_discoverable = TRUE;
+ }
+
+ else if (btm_cb.ble_ctr_cb.inq_var.proc_mode == BTM_BLE_LIMITED_INQUIRY &&
+ (flag & BTM_BLE_LIMIT_DISC_FLAG) != 0)
+ {
+ BTM_TRACE_DEBUG0("Find limited discoverable device");
+ is_discoverable = TRUE;
+ }
+
+ }
+ }
+
+ if (!is_discoverable)
+ {
+ BTM_TRACE_ERROR1("discoverable flag not desired: %d", flag);
+ }
+
+ return is_discoverable;
+}
+/*******************************************************************************
+**
+** Function btm_ble_update_inq_result
+**
+** Description Update adv packet information into inquiry result.
+**
+** Parameters
+**
+** Returns void
+**
+*******************************************************************************/
+BOOLEAN btm_ble_update_inq_result(tINQ_DB_ENT *p_i, UINT8 addr_type, UINT8 evt_type, UINT8 *p)
+{
+ BOOLEAN to_report = TRUE;
+ tBTM_INQ_RESULTS *p_cur = &p_i->inq_info.results;
+ UINT8 len;
+ UINT8 *p_flag;
+ tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+ UINT8 data_len, rssi;
+ tBTM_BLE_INQ_CB *p_le_inq_cb = &btm_cb.ble_ctr_cb.inq_var;
+ UINT8 *p1;
+
+ STREAM_TO_UINT8 (data_len, p);
+
+ if (data_len > BTM_BLE_ADV_DATA_LEN_MAX)
+ {
+ BTM_TRACE_WARNING1("EIR data too long %d. discard", data_len);
+ return FALSE;
+ }
+ btm_ble_cache_adv_data(p_cur, data_len, p, evt_type);
+
+ p1 = (p + data_len);
+ STREAM_TO_UINT8 (rssi, p1);
+
+ /* Save the info */
+ p_cur->inq_result_type = BTM_INQ_RESULT_BLE;
+ p_cur->ble_addr_type = addr_type;
+ p_cur->rssi = rssi;
+
+ /* active scan, always wait until get scan_rsp to report the result */
+ if ((btm_cb.ble_ctr_cb.inq_var.scan_type == BTM_BLE_SCAN_MODE_ACTI &&
+ (evt_type == BTM_BLE_CONNECT_EVT || evt_type == BTM_BLE_DISCOVER_EVT)))
+ {
+ p_i->scan_rsp = FALSE;
+ to_report = FALSE;
+ }
+ else
+ p_i->scan_rsp = TRUE;
+
+ if (p_i->inq_count != p_inq->inq_counter)
+ p_cur->device_type = BT_DEVICE_TYPE_BLE;
+ else
+ p_cur->device_type |= BT_DEVICE_TYPE_BLE;
+
+ if (evt_type != BTM_BLE_SCAN_RSP_EVT)
+ p_cur->ble_evt_type = evt_type;
+
+ p_i->inq_count = p_inq->inq_counter; /* Mark entry for current inquiry */
+
+ if (p_le_inq_cb->adv_len != 0)
+ {
+ if ((p_flag = BTM_CheckAdvData(p_le_inq_cb->adv_data_cache, BTM_BLE_AD_TYPE_FLAG, &len)) != NULL)
+ p_cur->flag = * p_flag;
+ }
+
+ /* if BR/EDR not supported is not set, assume is a DUMO device */
+ if ((p_cur->flag & BTM_BLE_BREDR_NOT_SPT) == 0)
+ {
+ BTM_TRACE_ERROR0("BR/EDR NOT support bit not set, treat as DUMO");
+ p_cur->device_type |= BT_DEVICE_TYPE_DUMO;
+ }
+ else
+ {
+ BTM_TRACE_DEBUG0("BR/EDR NOT SUPPORT bit set, LE only device");
+ }
+
+ return to_report;
+
+}
+
+/*******************************************************************************
+**
+** Function btm_send_sel_conn_callback
+**
+** Description send selection connection request callback.
+**
+** Parameters
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_send_sel_conn_callback(BD_ADDR remote_bda, UINT8 evt_type, UINT8 *p_data, UINT8 addr_type)
+{
+ UINT8 data_len, len;
+ UINT8 *p_dev_name, remname[31] = {0};
+
+ if (btm_cb.ble_ctr_cb.p_select_cback == NULL ||
+ /* non-connectable device */
+ (evt_type != BTM_BLE_EVT_CONN_ADV && evt_type != BTM_BLE_EVT_CONN_DIR_ADV))
+ return;
+
+ STREAM_TO_UINT8 (data_len, p_data);
+
+ /* get the device name if exist in ADV data */
+ if (data_len != 0)
+ {
+ p_dev_name = BTM_CheckAdvData(p_data, BTM_BLE_AD_TYPE_NAME_CMPL, &len);
+
+ if (p_dev_name == NULL)
+ p_dev_name = BTM_CheckAdvData(p_data, BTM_BLE_AD_TYPE_NAME_SHORT, &len);
+
+ if (p_dev_name)
+ memcpy(remname, p_dev_name, len);
+ }
+ /* allow connection */
+ if ((* btm_cb.ble_ctr_cb.p_select_cback)(remote_bda, remname))
+ {
+ /* terminate selective connection, initiate connection */
+ btm_ble_initiate_select_conn(remote_bda);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_resolve_random_addr_cmpl
+**
+** Description resolve random address complete callback.
+**
+** Returns void
+**
+*******************************************************************************/
+static void btm_ble_resolve_random_addr_cmpl(void * p_rec, void *p)
+{
+ tBTM_SEC_DEV_REC *match_rec = (tBTM_SEC_DEV_REC *) p_rec;
+ UINT8 addr_type = BLE_ADDR_RANDOM;
+ BD_ADDR bda;
+ UINT8 *pp = (UINT8 *)p + 1;
+ UINT8 evt_type;
+
+ BTM_TRACE_EVENT0 ("btm_ble_resolve_random_addr_cmpl ");
+
+ STREAM_TO_UINT8 (evt_type, pp);
+ STREAM_TO_UINT8 (addr_type, pp);
+ STREAM_TO_BDADDR (bda, pp);
+
+ if (match_rec)
+ {
+ BTM_TRACE_ERROR0("Random match");
+ memcpy(match_rec->ble.cur_rand_addr, bda, BD_ADDR_LEN);
+ memcpy(bda, match_rec->bd_addr, BD_ADDR_LEN);
+ }
+ else
+ {
+ BTM_TRACE_ERROR0("Random unmatch");
+ }
+
+ btm_ble_process_adv_pkt_cont(bda, addr_type, evt_type, pp);
+
+ return;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_process_adv_pkt
+**
+** Description This function is called when adv packet report events are
+** received from the device. It updates the inquiry database.
+** If the inquiry database is full, the oldest entry is discarded.
+**
+** Parameters
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_process_adv_pkt (UINT8 *p_data)
+{
+ BD_ADDR bda;
+ UINT8 evt_type = 0, *p = p_data;
+ UINT8 addr_type = 0;
+
+ BTM_TRACE_EVENT0 ("btm_ble_process_adv_pkt ");
+
+ /* always get one device at a time */
+ p ++;
+
+ /* Extract inquiry results */
+ STREAM_TO_UINT8 (evt_type, p);
+ STREAM_TO_UINT8 (addr_type, p);
+ STREAM_TO_BDADDR (bda, p);
+
+#ifdef BTM_BLE_PC_ADV_TEST_MODE // For general stack code (e.g. BTInsight testing), we simply do not define it to exclude or set it to TRUE to include
+ if (BTM_BLE_PC_ADV_TEST_MODE) // For stack component, it is always defined and maps to a global variable g_bDraculaAdvertisingMode
+ {
+ if (btm_cb.ble_ctr_cb.p_scan_req_cback)
+ (*btm_cb.ble_ctr_cb.p_scan_req_cback)(bda, addr_type, evt_type);
+ }
+#endif
+
+ /* Only process the results if the inquiry is still active */
+ if (!btm_cb.btm_inq_vars.inq_active &&
+ (btm_cb.ble_ctr_cb.bg_conn_type != BTM_BLE_CONN_SELECTIVE ||
+ /* or selective auto connection is active */
+ btm_cb.ble_ctr_cb.p_select_cback == NULL))
+ return;
+
+
+#if SMP_INCLUDED == TRUE
+ if (addr_type == BLE_ADDR_RANDOM && BTM_BLE_IS_RESOLVE_BDA(bda))
+ {
+ btm_ble_resolve_random_addr(bda, btm_ble_resolve_random_addr_cmpl, p_data);
+ }
+ else
+#endif
+ btm_ble_process_adv_pkt_cont(bda, addr_type, evt_type, p);
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_process_adv_pkt_cont
+**
+** Description This function is called after random address resolution is
+** done, and proceed to process adv packet.
+**
+** Parameters
+**
+** Returns void
+**
+*******************************************************************************/
+static void btm_ble_process_adv_pkt_cont(BD_ADDR bda, UINT8 addr_type, UINT8 evt_type, UINT8 *p)
+{
+ tINQ_DB_ENT *p_i;
+ BOOLEAN to_report = FALSE;
+ tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+ tBTM_INQ_RESULTS_CB *p_inq_results_cb = p_inq->p_inq_results_cb;
+ tBTM_BLE_INQ_CB *p_le_inq_cb = &btm_cb.ble_ctr_cb.inq_var;
+
+ p_i = btm_inq_db_find (bda);
+
+ /* Check if this address has already been processed for this inquiry */
+ if (btm_inq_find_bdaddr(bda))
+ {
+ /* never been report as an LE device */
+ if ((p_i &&
+ (!(p_i->inq_info.results.device_type & BT_DEVICE_TYPE_BLE) ||
+ /* scan repsonse to be updated */
+ (!p_i->scan_rsp)))
+ ||
+ btm_cb.ble_ctr_cb.inq_var.proc_mode == BTM_BLE_OBSERVE)
+ {
+ BTM_TRACE_DEBUG0("update new BLE information ");
+ to_report = TRUE;
+ }
+ else
+ {
+ BTM_TRACE_DEBUG0("LE in le_bd_db already");
+ /* if yes, skip it */
+ return; /* assumption: one result per event */
+ }
+ }
+ else /* not been processed int his round */
+ {
+ BTM_TRACE_DEBUG0("new LE BD_ADDR");
+ to_report = TRUE;
+ }
+
+ /* If existing entry, use that, else get a new one (possibly reusing the oldest) */
+ if (p_i == NULL)
+ {
+ if (btm_ble_is_discoverable(bda, evt_type, p))
+ {
+ if ((p_i = btm_inq_db_new (bda)) != NULL)
+ {
+ p_inq->inq_cmpl_info.num_resp++;
+ BTM_TRACE_DEBUG0("adv pkt process: new record is added into inq db");
+ to_report = TRUE;
+ }
+ else
+ return;
+ }
+ else
+ {
+ BTM_TRACE_ERROR0("discard adv pkt");
+ return;
+ }
+ }
+ else if (p_i->inq_count != p_inq->inq_counter) /* first time seen in this inquiry */
+ {
+ p_inq->inq_cmpl_info.num_resp++;
+ }
+
+ /* update the LE device information in inquiry database */
+ if (to_report)
+ {
+ to_report = btm_ble_update_inq_result(p_i, addr_type, evt_type, p);
+ }
+
+#if BTM_USE_INQ_RESULTS_FILTER == TRUE
+ /* If the number of responses found and limited, issue a cancel inquiry */
+ if (p_inq->inqparms.max_resps &&
+ p_inq->inq_cmpl_info.num_resp == p_inq->inqparms.max_resps)
+ {
+ /* new device */
+ if (p_i == NULL ||
+ (/* assume a DUMO device, BR/EDR inquiry is always active */
+ p_i && p_i->inq_info.results.device_type == BT_DEVICE_TYPE_BLE && p_i->scan_rsp))
+ {
+ BTM_TRACE_WARNING0("INQ RES: Extra Response Received...cancelling inquiry..");
+
+ if (!(p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE) )
+ btsnd_hcic_inq_cancel();
+
+ /* stop LE scan now */
+ btm_ble_stop_scan();
+
+#if BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE
+ btm_acl_update_busy_level (BTM_BLI_INQ_DONE_EVT);
+#endif
+ }
+ }
+#endif
+
+ /* background connection in selective connection mode */
+ if (btm_cb.ble_ctr_cb.bg_conn_type == BTM_BLE_CONN_SELECTIVE)
+ {
+ btm_send_sel_conn_callback(bda, evt_type, p, addr_type);
+ }
+ else if (p_inq_results_cb && to_report)
+ {
+ BTM_TRACE_DEBUG0("BTMINQ LE: Found devices, send callback btm_inqrslt_cb");
+
+ if (p_inq->inq_active)
+ (p_inq_results_cb)((tBTM_INQ_RESULTS *) &p_i->inq_info.results, p_le_inq_cb->adv_data_cache);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_stop_scan
+**
+** Description Stop the BLE scan.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_stop_scan(void)
+{
+ tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
+ tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+
+ BTM_TRACE_EVENT0 ("btm_ble_stop_scan ");
+
+ btu_stop_timer (&p_cb->inq_timer_ent);
+
+ /* Clear the inquiry callback if set */
+ p_cb->scan_type = BTM_BLE_SCAN_MODE_NONE;
+ p_cb->proc_mode = BTM_BLE_INQUIRY_NONE;
+
+ /* stop discovery now */
+ btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_DISABLE, BTM_BLE_DUPLICATE_ENABLE);
+
+ /* If we have a callback registered for inquiry complete, call it */
+ BTM_TRACE_DEBUG2 ("BTM Inq Compl Callback: status 0x%02x, num results %d",
+ p_inq->inq_cmpl_info.status, p_inq->inq_cmpl_info.num_resp);
+
+ btm_update_scanner_filter_policy(SP_ADV_ALL);
+
+ btm_process_inq_complete(HCI_SUCCESS, (UINT8)(p_inq->inqparms.mode & BTM_BLE_INQUIRY_MASK));
+
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_stop_adv
+**
+** Description Stop the BLE advertising.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_stop_adv(void)
+{
+ BTM_TRACE_EVENT0 (" btm_ble_stop_adv");
+
+ if (btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_DISABLE))
+ {
+ btm_cb.ble_ctr_cb.inq_var.adv_mode = BTM_BLE_ADV_DISABLE;
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_timeout
+**
+** Description Called when BTM BLE inquiry timer expires
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_timeout(TIMER_LIST_ENT *p_tle)
+{
+ BTM_TRACE_EVENT0 ("btm_ble_timeout");
+
+ switch (p_tle->event)
+ {
+ case BTU_TTYPE_BLE_INQUIRY:
+ btm_ble_stop_scan();
+ break;
+
+ case BTU_TTYPE_BLE_GAP_LIM_DISC:
+ /* lim_timeout expiried, limited discovery should exit now */
+ btm_ble_update_adv_flag(BTM_BLE_NON_LIMIT_DISC_FLAG);
+
+ btm_ble_stop_adv();
+ break;
+
+ case BTU_TTYPE_BLE_RANDOM_ADDR:
+ if (btm_cb.ble_ctr_cb.inq_var.adv_mode == BTM_BLE_ADV_ENABLE &&
+ btm_cb.ble_ctr_cb.inq_var.own_addr_type == BLE_ADDR_RANDOM)
+ {
+ /* refresh the random addr */
+ btm_gen_resolvable_private_addr();
+ }
+ break;
+
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_connected
+**
+** Description This function is when a LE connection to the peer device is
+** establsihed
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_connected (UINT8 *bda, UINT16 handle, UINT8 enc_mode, UINT8 role)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bda);
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+
+ BTM_TRACE_EVENT0 ("btm_ble_connected");
+
+ /* Commenting out trace due to obf/compilation problems.
+ */
+#if (BT_USE_TRACES == TRUE)
+ if (p_dev_rec)
+ {
+ BTM_TRACE_EVENT4 ("Security Manager: btm_sec_connected : handle:%d enc_mode:%d bda:%x RName:%s",
+ handle, enc_mode,
+ (bda[2]<<24)+(bda[3]<<16)+(bda[4]<<8)+bda[5],
+ p_dev_rec->sec_bd_name);
+
+ BTM_TRACE_DEBUG1 ("btm_ble_connected sec_flags=0x%x",p_dev_rec->sec_flags);
+ }
+ else
+ {
+ BTM_TRACE_EVENT3 ("Security Manager: btm_sec_connected: handle:%d enc_mode:%d bda:%x ",
+ handle, enc_mode,
+ (bda[2]<<24)+(bda[3]<<16)+(bda[4]<<8)+bda[5]);
+ }
+#endif
+
+ if (!p_dev_rec)
+ {
+ /* There is no device record for new connection. Allocate one */
+ p_dev_rec = btm_sec_alloc_dev (bda);
+ }
+ else /* Update the timestamp for this device */
+ {
+ p_dev_rec->timestamp = btm_cb.dev_rec_count++;
+ }
+
+ p_dev_rec->device_type = BT_DEVICE_TYPE_BLE;
+ p_dev_rec->hci_handle = handle;
+ if (role == HCI_ROLE_MASTER)
+ p_dev_rec->role_master = TRUE;
+
+ p_cb->inq_var.adv_mode = BTM_BLE_ADV_DISABLE;
+
+ return;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_read_remote_features_complete
+**
+** Description This function is called when the command complete message
+** is received from the HCI for the read LE remote feature supported
+** complete event.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_read_remote_features_complete(UINT8 *p)
+{
+ tACL_CONN *p_acl_cb = &btm_cb.acl_db[0];
+ UINT8 size;
+ UINT16 handle;
+ int xx, yy;
+ tBTM_SEC_DEV_REC *p_dev_rec;
+
+ BTM_TRACE_EVENT0 ("btm_ble_read_remote_features_complete ");
+
+ STREAM_TO_UINT16 (handle, p);
+ STREAM_TO_UINT8 (size, p);
+
+ /* Look up the connection by handle and copy features */
+ for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_acl_cb++)
+ {
+ if ((p_acl_cb->in_use) && (p_acl_cb->hci_handle == handle))
+ {
+ for (yy = 0; yy < BD_FEATURES_LEN; yy++)
+ STREAM_TO_UINT8 (p_acl_cb->features[yy], p);
+
+ p_dev_rec = btm_find_dev_by_handle (handle);
+ if (!p_dev_rec)
+ {
+ /* Get a new device; might be doing dedicated bonding */
+ p_dev_rec = btm_find_or_alloc_dev (p_acl_cb->remote_addr);
+ }
+
+ memcpy (p_dev_rec->features, p_acl_cb->features, BD_FEATURES_LEN);
+ break;
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_write_adv_enable_complete
+**
+** Description This function process the write adv enable command complete.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_write_adv_enable_complete(UINT8 * p)
+{
+ tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
+
+ /* if write adv enable/disbale not succeed */
+ if (*p != HCI_SUCCESS)
+ {
+ /* toggle back the adv mode */
+ p_cb->adv_mode = !p_cb->adv_mode;
+ }
+}
+/*******************************************************************************
+**
+** Function btm_ble_init
+**
+** Description Initialize the control block variable values.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_init (void)
+{
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+
+ BTM_TRACE_EVENT0 ("btm_ble_init ");
+
+ memset(p_cb, 0, sizeof(tBTM_BLE_CB));
+
+ p_cb->inq_var.adv_mode = BTM_BLE_ADV_DISABLE;
+ p_cb->inq_var.scan_type = BTM_BLE_SCAN_MODE_NONE;
+ p_cb->inq_var.adv_chnl_map = BTM_BLE_DEFAULT_ADV_CHNL_MAP;
+ p_cb->inq_var.afp = BTM_BLE_DEFAULT_AFP;
+ p_cb->inq_var.sfp = BTM_BLE_DEFAULT_SFP;
+ p_cb->inq_var.connectable_mode = BTM_BLE_NON_CONNECTABLE;
+ p_cb->inq_var.discoverable_mode = BTM_BLE_NON_DISCOVERABLE;
+
+ /* for background connection, reset connection params to be undefined */
+ p_cb->scan_int = p_cb->scan_win = BTM_BLE_CONN_PARAM_UNDEF;
+
+ p_cb->inq_var.evt_type = BTM_BLE_UNKNOWN_EVT;
+}
+
+#endif /* BLE_INCLUDED */
diff --git a/stack/btm/btm_ble_int.h b/stack/btm/btm_ble_int.h
new file mode 100644
index 0000000..b03e124
--- /dev/null
+++ b/stack/btm/btm_ble_int.h
@@ -0,0 +1,285 @@
+/*****************************************************************************
+**
+** Name: btm_ble_int.h
+**
+** Description: this file contains the main Bluetooth Manager (BTM)
+** internal definitions.
+**
+** Copyright (c) 1999-2008, Broadcom Corp., All Rights Reserved
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+
+#ifndef BTM_BLE_INT_H
+#define BTM_BLE_INT_H
+
+#include "bt_target.h"
+#include "gki.h"
+#include "hcidefs.h"
+#include "btm_ble_api.h"
+#include "btm_int.h"
+
+#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE
+#include "smp_api.h"
+#endif
+
+#define BTM_BLE_CONNECT_EVT 0x00
+#define BTM_BLE_CONNECT_DIR_EVT 0x01
+#define BTM_BLE_DISCOVER_EVT 0x02
+#define BTM_BLE_NON_CONNECT_EVT 0x03
+#define BTM_BLE_SCAN_RSP_EVT 0x04
+#define BTM_BLE_SCAN_REQ_EVT 0x06
+#define BTM_BLE_UNKNOWN_EVT 0xff
+
+#define BTM_BLE_UNKNOWN_EVT 0xff
+
+/* scanning enable status */
+#define BTM_BLE_SCAN_ENABLE 0x01
+#define BTM_BLE_SCAN_DISABLE 0x00
+
+/* advertising enable status */
+#define BTM_BLE_ADV_ENABLE 0x01
+#define BTM_BLE_ADV_DISABLE 0x00
+
+/* use the high 4 bits unused by inquiry mode */
+#define BTM_BLE_SELECT_SCAN 0x20
+#define BTM_BLE_NAME_REQUEST 0x40
+#define BTM_BLE_OBSERVE 0x80
+
+#define BTM_BLE_MAX_WL_ENTRY 1
+#define BTM_BLE_AD_DATA_LEN 31
+
+#define BTM_BLE_ENC_MASK 0x03
+
+#define BTM_BLE_DUPLICATE_ENABLE 1
+#define BTM_BLE_DUPLICATE_DISABLE 0
+
+#define BTM_BLE_GAP_DISC_SCAN_INT 18 /* Interval(scan_int) = 11.25 ms= 0x0010 * 0.625 ms */
+#define BTM_BLE_GAP_DISC_SCAN_WIN 18 /* scan_window = 11.25 ms= 0x0010 * 0.625 ms */
+#define BTM_BLE_GAP_ADV_INT 512 /* Tgap(gen_disc) = 1.28 s= 512 * 0.625 ms */
+#define BTM_BLE_GAP_LIM_TOUT 30 /* Tgap(lim_timeout) = 30.72 s max, round down to 30 */
+
+
+#define BTM_BLE_SEC_REQ_ACT_NONE 0
+#define BTM_BLE_SEC_REQ_ACT_ENCRYPT 1 /* encrypt the link using current key or key refresh */
+#define BTM_BLE_SEC_REQ_ACT_PAIR 2
+#define BTM_BLE_SEC_REQ_ACT_DISCARD 3 /* discard the sec request while encryption is started but not completed */
+typedef UINT8 tBTM_BLE_SEC_REQ_ACT;
+
+
+
+typedef struct
+{
+ UINT16 data_mask;
+ UINT8 *p_flags;
+ UINT8 ad_data[BTM_BLE_AD_DATA_LEN];
+ UINT8 *p_pad;
+}tBTM_BLE_LOCAL_ADV_DATA;
+
+typedef struct
+{
+ UINT32 inq_count; /* Used for determining if a response has already been */
+ /* received for the current inquiry operation. (We do not */
+ /* want to flood the caller with multiple responses from */
+ /* the same device. */
+ BOOLEAN scan_rsp;
+ tBLE_BD_ADDR le_bda;
+} tINQ_LE_BDADDR;
+
+#define BTM_BLE_ADV_DATA_LEN_MAX 31
+#define BTM_BLE_CACHE_ADV_DATA_MAX 62
+
+#define BTM_BLE_VALID_PRAM(x, min, max) (((x) >= (min) && (x) <= (max)) || ((x) == BTM_BLE_CONN_PARAM_UNDEF))
+
+typedef struct
+{
+
+ UINT16 discoverable_mode;
+ UINT16 connectable_mode;
+ UINT16 br_edr_supported_flag; /* combined BR EDR discoverable and connectable mode */
+ /* only meaningful when it is zero. This means
+ BR EDR is not supported*/
+ UINT8 proc_mode; /* current procedure mode : inquiry or discovery */
+
+ UINT16 scan_window;
+ UINT16 scan_interval;
+ UINT8 scan_type; /* current scan type: active or passive */
+ UINT16 adv_interval_min;
+ UINT16 adv_interval_max;
+ tBLE_ADDR_TYPE own_addr_type;
+ tBTM_BLE_AFP afp; /* advertising filter policy */
+ tBTM_BLE_SFP sfp; /* scanning filter policy */
+
+ UINT8 evt_type;
+ UINT8 adv_mode;
+ tBLE_BD_ADDR direct_bda;
+
+ UINT8 adv_len;
+ UINT8 adv_data_cache[BTM_BLE_CACHE_ADV_DATA_MAX];
+
+ /* inquiry BD addr database */
+ UINT8 num_bd_entries;
+ UINT8 max_bd_entries;
+
+ tBLE_BD_ADDR local_bda;
+
+ tBTM_BLE_LOCAL_ADV_DATA adv_data;
+ tBTM_BLE_ADV_CHNL_MAP adv_chnl_map;
+
+ TIMER_LIST_ENT inq_timer_ent;
+ BOOLEAN scan_rsp;
+ UINT8 state; /* Current state that the inquiry process is in */
+ UINT8 tx_power;
+} tBTM_BLE_INQ_CB;
+
+
+/* random address resolving complete callback */
+typedef void (tBTM_BLE_RESOLVE_CBACK) (void * match_rec, void *p);
+
+/* random address management control block */
+typedef struct
+{
+ BD_ADDR private_addr;
+ BD_ADDR random_bda;
+ BOOLEAN busy;
+ UINT16 index;
+ tBTM_BLE_RESOLVE_CBACK *p_resolve_cback;
+ void *p;
+ TIMER_LIST_ENT raddr_timer_ent;
+} tBTM_LE_RANDOM_CB;
+
+#define BTM_BLE_MAX_BG_CONN_DEV_NUM 10
+
+typedef struct
+{
+ UINT16 min_conn_int;
+ UINT16 max_conn_int;
+ UINT16 slave_latency;
+ UINT16 supervision_tout;
+
+}tBTM_LE_CONN_PRAMS;
+
+/* Define BLE Device Management control structure
+*/
+typedef struct
+{
+ /*****************************************************
+ ** BLE Inquiry
+ *****************************************************/
+ tBTM_BLE_INQ_CB inq_var;
+
+ /* background connection procedure cb value */
+ tBTM_BLE_CONN_TYPE bg_conn_type;
+ UINT16 scan_int;
+ UINT16 scan_win;
+ tBTM_BLE_SEL_CBACK *p_select_cback;
+ TIMER_LIST_ENT scan_param_idle_timer;
+
+ UINT8 bg_conn_dev_num;
+ BD_ADDR bg_conn_dev_list[BTM_BLE_MAX_BG_CONN_DEV_NUM];
+
+#define BLE_BG_CONN_IDLE 0
+#define BLE_BG_CONN_ACTIVE 1
+#define BLE_BG_CONN_SUSPEND 2
+
+ UINT8 bg_conn_state;
+
+ /* random address management control block */
+ tBTM_LE_RANDOM_CB addr_mgnt_cb;
+
+ /* white list information */
+ UINT8 num_empty_filter; /* Number of entries in white list */
+ UINT8 max_filter_entries; /* Maximum number of entries that can be stored */
+ BOOLEAN enabled;
+ BOOLEAN privacy; /* privacy enabled or disabled */
+
+#ifdef BTM_BLE_PC_ADV_TEST_MODE
+ tBTM_BLE_SCAN_REQ_CBACK *p_scan_req_cback;
+#endif
+
+} tBTM_BLE_CB;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void btm_ble_timeout(TIMER_LIST_ENT *p_tle);
+extern void btm_ble_process_adv_pkt (UINT8 *p);
+extern void btm_ble_proc_scan_rsp_rpt (UINT8 *p);
+extern tBTM_STATUS btm_ble_read_remote_name(BD_ADDR remote_bda, tBTM_INQ_INFO *p_cur, tBTM_CMPL_CB *p_cb);
+extern BOOLEAN btm_ble_cancel_remote_name(BD_ADDR remote_bda);
+
+extern tBTM_STATUS btm_ble_set_discoverability(UINT16 combined_mode);
+extern tBTM_STATUS btm_ble_set_connectability(UINT16 combined_mode);
+extern tBTM_STATUS btm_ble_start_inquiry (UINT8 mode, UINT8 duration);
+
+extern void btm_ble_stop_scan(void);
+extern void btm_ble_att_db_init(void);
+extern void btm_ble_init (void);
+extern void btm_ble_connected (UINT8 *bda, UINT16 handle, UINT8 enc_mode, UINT8 role);
+extern void btm_ble_read_remote_features_complete(UINT8 *p);
+extern void btm_ble_stop_adv(void);
+extern void btm_ble_write_adv_enable_complete(UINT8 * p);
+
+/* LE security function from btm_sec.c */
+#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE
+extern void btm_ble_link_sec_check(BD_ADDR bd_addr, tBTM_LE_AUTH_REQ auth_req, tBTM_BLE_SEC_REQ_ACT *p_sec_req_act);
+extern void btm_ble_ltk_request_reply(BD_ADDR bda, BOOLEAN use_stk, BT_OCTET16 stk);
+extern UINT8 btm_proc_smp_cback(tSMP_EVT event, BD_ADDR bd_addr, tSMP_EVT_DATA *p_data);
+extern tBTM_STATUS btm_ble_set_encryption (BD_ADDR bd_addr, void *p_ref_data, UINT8 link_role);
+extern void btm_ble_ltk_request(UINT16 handle, UINT8 rand[8], UINT16 ediv);
+extern BOOLEAN btm_ble_start_encrypt(BD_ADDR bda, BOOLEAN use_stk, BT_OCTET16 stk);
+extern void btm_ble_link_encrypted(BD_ADDR bd_addr, UINT8 encr_enable);
+#endif
+
+/* LE device management functions */
+extern void btm_ble_reset_id( void );
+
+/* security related functions */
+extern void btm_ble_increment_sign_ctr(BD_ADDR bd_addr, BOOLEAN is_local );
+extern BOOLEAN btm_get_local_div (BD_ADDR bd_addr, UINT16 *p_div);
+extern BOOLEAN btm_ble_check_link_type (BD_ADDR bd_addr);
+extern BOOLEAN btm_ble_get_enc_key_type(BD_ADDR bd_addr, UINT8 *p_key_types);
+
+extern void btm_ble_rand_enc_complete (UINT8 *p, UINT16 op_code, tBTM_RAND_ENC_CB *p_enc_cplt_cback);
+extern void btm_sec_save_le_key(BD_ADDR bd_addr, tBTM_LE_KEY_TYPE key_type, tBTM_LE_KEY_VALUE *p_keys, BOOLEAN pass_to_application);
+extern void btm_ble_update_sec_key_size(BD_ADDR bd_addr, UINT8 enc_key_size);
+extern UINT8 btm_ble_read_sec_key_size(BD_ADDR bd_addr);
+
+/* white list function */
+extern BOOLEAN btm_update_dev_to_white_list(BOOLEAN to_add, BD_ADDR bd_addr,tBLE_ADDR_TYPE addr_type);
+extern BOOLEAN btm_update_bg_conn_list(BOOLEAN to_add, BD_ADDR bd_addr);
+extern void btm_update_scanner_filter_policy(tBTM_BLE_SFP scan_policy);
+extern void btm_update_adv_filter_policy(tBTM_BLE_AFP adv_policy);
+extern void btm_ble_clear_white_list (void);
+extern void btm_write_bg_conn_wl(void);
+
+/* background connection function */
+extern void btm_ble_suspend_bg_conn(void);
+extern BOOLEAN btm_ble_resume_bg_conn(tBTM_BLE_SEL_CBACK *p_sele_callback, BOOLEAN def_param);
+extern void btm_ble_update_bg_state(void);
+extern void btm_ble_initiate_select_conn(BD_ADDR bda);
+extern BOOLEAN btm_ble_start_auto_conn(BOOLEAN start);
+extern BOOLEAN btm_ble_start_select_conn(BOOLEAN start,tBTM_BLE_SEL_CBACK *p_select_cback);
+extern BOOLEAN btm_ble_find_dev_in_whitelist(BD_ADDR bd_addr);
+extern BOOLEAN btm_ble_renew_bg_conn_params(BOOLEAN add, BD_ADDR bd_addr);
+extern void btm_ble_scan_param_idle(void);
+extern UINT8 btm_ble_count_unconn_dev_in_whitelist(void);
+
+/* BLE address management */
+extern tBLE_ADDR_TYPE btm_ble_map_bda_to_conn_bda(BD_ADDR bda);
+extern void btm_gen_resolvable_private_addr (void);
+extern void btm_gen_non_resolvable_private_addr (void);
+extern void btm_ble_resolve_random_addr(BD_ADDR random_bda, tBTM_BLE_RESOLVE_CBACK * p_cback, void *p);
+
+#if BTM_BLE_CONFORMANCE_TESTING == TRUE
+BT_API extern void btm_ble_set_no_disc_if_pair_fail (BOOLEAN disble_disc);
+BT_API extern void btm_ble_set_test_mac_value (BOOLEAN enable, UINT8 *p_test_mac_val);
+BT_API extern void btm_ble_set_test_local_sign_cntr_value(BOOLEAN enable, UINT32 test_local_sign_cntr);
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/stack/btm/btm_dev.c b/stack/btm/btm_dev.c
new file mode 100644
index 0000000..3651589
--- /dev/null
+++ b/stack/btm/btm_dev.c
@@ -0,0 +1,451 @@
+/*****************************************************************************
+** *
+** Name: btm_dev.c *
+** *
+** Description: This file contains functions for the Bluetooth Device *
+** Manager *
+** *
+** Copyright (c) 1999-2011, Broadcom Corp., All Rights Reserved. *
+** Broadcom Bluetooth Core. Proprietary and confidential. *
+******************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stddef.h>
+
+#include "bt_types.h"
+#include "gki.h"
+#include "hcimsgs.h"
+#include "btu.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "hcidefs.h"
+#include "l2c_api.h"
+static tBTM_SEC_DEV_REC *btm_find_oldest_dev (void);
+
+/*******************************************************************************
+**
+** Function BTM_SecAddDevice
+**
+** Description Add/modify device. This function will be normally called
+** during host startup to restore all required information
+** stored in the NVRAM.
+**
+** Parameters: bd_addr - BD address of the peer
+** dev_class - Device Class
+** bd_name - Name of the peer device. NULL if unknown.
+** features - Remote device's supported features. NULL if not known
+** trusted_mask - Bitwise OR of services that do not
+** require authorization. (array of UINT32)
+** link_key - Connection link key. NULL if unknown.
+**
+** Returns TRUE if added OK, else FALSE
+**
+*******************************************************************************/
+BOOLEAN BTM_SecAddDevice (BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NAME bd_name,
+ BD_FEATURES features, UINT32 trusted_mask[],
+ LINK_KEY link_key, UINT8 key_type, tBTM_IO_CAP io_cap)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ int i;
+
+ p_dev_rec = btm_find_dev (bd_addr);
+ if (!p_dev_rec)
+ {
+ /* There is no device record, allocate one.
+ * If we can not find an empty spot for this one, let it fail. */
+ for (i = 0; i < BTM_SEC_MAX_DEVICE_RECORDS; i++)
+ {
+ if (!(btm_cb.sec_dev_rec[i].sec_flags & BTM_SEC_IN_USE))
+ {
+ p_dev_rec = &btm_cb.sec_dev_rec[i];
+
+ /* Mark this record as in use and initialize */
+ memset (p_dev_rec, 0, sizeof (tBTM_SEC_DEV_REC));
+ p_dev_rec->sec_flags = BTM_SEC_IN_USE;
+ memcpy (p_dev_rec->bd_addr, bd_addr, BD_ADDR_LEN);
+ p_dev_rec->hci_handle = BTM_GetHCIConnHandle (bd_addr);
+
+#if BLE_INCLUDED == TRUE
+ /* use default value for background connection params */
+ /* update conn params, use default value for background connection params */
+ memset(&p_dev_rec->conn_params, 0xff, sizeof(tBTM_LE_CONN_PRAMS));
+#endif
+ break;
+ }
+ }
+
+ if (!p_dev_rec)
+ return(FALSE);
+ }
+
+ p_dev_rec->timestamp = btm_cb.dev_rec_count++;
+
+ if (dev_class)
+ memcpy (p_dev_rec->dev_class, dev_class, DEV_CLASS_LEN);
+
+ memset(p_dev_rec->sec_bd_name, 0, sizeof(tBTM_BD_NAME));
+
+ if (bd_name && bd_name[0])
+ {
+ p_dev_rec->sec_flags |= BTM_SEC_NAME_KNOWN;
+ BCM_STRNCPY_S ((char *)p_dev_rec->sec_bd_name, sizeof (p_dev_rec->sec_bd_name),
+ (char *)bd_name, BTM_MAX_REM_BD_NAME_LEN);
+ }
+
+ if (features)
+ memcpy (p_dev_rec->features, features, sizeof (BD_FEATURES));
+ else
+ memset (p_dev_rec->features, 0, sizeof (BD_FEATURES));
+
+ BTM_SEC_COPY_TRUSTED_DEVICE(trusted_mask, p_dev_rec->trusted_mask);
+
+ if (link_key)
+ {
+ BTM_TRACE_EVENT6 ("BTM_SecAddDevice() BDA: %02x:%02x:%02x:%02x:%02x:%02x",
+ bd_addr[0], bd_addr[1], bd_addr[2],
+ bd_addr[3], bd_addr[4], bd_addr[5]);
+ p_dev_rec->sec_flags |= BTM_SEC_LINK_KEY_KNOWN;
+ memcpy (p_dev_rec->link_key, link_key, LINK_KEY_LEN);
+ p_dev_rec->link_key_type = key_type;
+ }
+
+#if defined(BSA_MIXED_MODE_INCLUDED) && (BSA_MIXED_MODE_INCLUDED == TRUE)
+ p_dev_rec->sm4 = BTM_SM4_KNOWN;
+#endif
+
+ p_dev_rec->rmt_io_caps = io_cap;
+
+ return(TRUE);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_SecDeleteDevice
+**
+** Description Free resources associated with the device.
+**
+** Parameters: bd_addr - BD address of the peer
+**
+** Returns TRUE if removed OK, FALSE if not found or ACL link is active
+**
+*******************************************************************************/
+BOOLEAN BTM_SecDeleteDevice (BD_ADDR bd_addr)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+
+ if (BTM_IsAclConnectionUp(bd_addr))
+ {
+ BTM_TRACE_WARNING0("BTM_SecDeleteDevice FAILED: Cannot Delete when connection is active");
+ return(FALSE);
+ }
+
+ if ((p_dev_rec = btm_find_dev (bd_addr)) == NULL)
+ return(FALSE);
+
+ btm_sec_free_dev (p_dev_rec);
+
+ /* Tell controller to get rid of the link key if it has one stored */
+ BTM_DeleteStoredLinkKey (bd_addr, NULL);
+
+ return(TRUE);
+}
+
+/*******************************************************************************
+**
+** Function BTM_SecReadDevName
+**
+** Description Looks for the device name in the security database for the
+** specified BD address.
+**
+** Returns Pointer to the name or NULL
+**
+*******************************************************************************/
+char *BTM_SecReadDevName (BD_ADDR bd_addr)
+{
+ char *p_name = NULL;
+ tBTM_SEC_DEV_REC *p_srec;
+
+ if ((p_srec = btm_find_dev(bd_addr)) != NULL)
+ p_name = (char *)p_srec->sec_bd_name;
+
+ return(p_name);
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_alloc_dev
+**
+** Description Look for the record in the device database for the record
+** with specified handle
+**
+** Returns Pointer to the record or NULL
+**
+*******************************************************************************/
+tBTM_SEC_DEV_REC *btm_sec_alloc_dev (BD_ADDR bd_addr)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = NULL;
+ tBTM_INQ_INFO *p_inq_info;
+ int i;
+ BTM_TRACE_EVENT0 ("btm_sec_alloc_dev");
+ for (i = 0; i < BTM_SEC_MAX_DEVICE_RECORDS; i++)
+ {
+ if (!(btm_cb.sec_dev_rec[i].sec_flags & BTM_SEC_IN_USE))
+ {
+ p_dev_rec = &btm_cb.sec_dev_rec[i];
+ break;
+ }
+ }
+
+ if (!p_dev_rec)
+ p_dev_rec = btm_find_oldest_dev();
+
+ memset (p_dev_rec, 0, sizeof (tBTM_SEC_DEV_REC));
+
+ p_dev_rec->sec_flags = BTM_SEC_IN_USE;
+
+ /* Check with the BT manager if details about remote device are known */
+ /* outgoing connection */
+ if ((p_inq_info = BTM_InqDbRead(bd_addr)) != NULL)
+ {
+ memcpy (p_dev_rec->dev_class, p_inq_info->results.dev_class, DEV_CLASS_LEN);
+
+#if BLE_INCLUDED == TRUE
+ p_dev_rec->device_type = p_inq_info->results.device_type;
+ p_dev_rec->ble.ble_addr_type = p_inq_info->results.ble_addr_type;
+
+ /* update conn params, use default value for background connection params */
+ memset(&p_dev_rec->conn_params, 0xff, sizeof(tBTM_LE_CONN_PRAMS));
+#endif
+
+#if BTM_INQ_GET_REMOTE_NAME == TRUE
+ if (p_inq_info->remote_name_state == BTM_INQ_RMT_NAME_DONE)
+ {
+ BCM_STRNCPY_S ((char *)p_dev_rec->sec_bd_name, sizeof (p_dev_rec->sec_bd_name),
+ (char *)p_inq_info->remote_name, BTM_MAX_REM_BD_NAME_LEN);
+ p_dev_rec->sec_flags |= BTM_SEC_NAME_KNOWN;
+ }
+#endif
+ }
+ else
+ {
+#if BLE_INCLUDED == TRUE
+ p_dev_rec->device_type = BT_DEVICE_TYPE_BREDR; /* initialize it as BR/EDR device */
+ /* update conn params, use default value for background connection params */
+ memset(&p_dev_rec->conn_params, 0xff, sizeof(tBTM_LE_CONN_PRAMS));
+#endif
+
+ if (!memcmp (bd_addr, btm_cb.connecting_bda, BD_ADDR_LEN))
+ memcpy (p_dev_rec->dev_class, btm_cb.connecting_dc, DEV_CLASS_LEN);
+ }
+
+ memcpy (p_dev_rec->bd_addr, bd_addr, BD_ADDR_LEN);
+
+ p_dev_rec->hci_handle = BTM_GetHCIConnHandle (bd_addr);
+ p_dev_rec->timestamp = btm_cb.dev_rec_count++;
+
+ return(p_dev_rec);
+}
+
+
+/*******************************************************************************
+**
+** Function btm_sec_free_dev
+**
+** Description Mark device record as not used
+**
+*******************************************************************************/
+void btm_sec_free_dev (tBTM_SEC_DEV_REC *p_dev_rec)
+{
+ p_dev_rec->sec_flags = 0;
+
+#if BLE_INCLUDED == TRUE
+ /* Clear out any saved BLE keys */
+ btm_sec_clear_ble_keys (p_dev_rec);
+#endif
+
+
+}
+
+/*******************************************************************************
+**
+** Function btm_dev_support_switch
+**
+** Description This function is called by the L2CAP to check if remote
+** device supports role switch
+**
+** Parameters: bd_addr - Address of the peer device
+**
+** Returns TRUE if device is known and role switch is supported
+**
+*******************************************************************************/
+BOOLEAN btm_dev_support_switch (BD_ADDR bd_addr)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ UINT8 xx;
+ BOOLEAN feature_empty = TRUE;
+
+#if BTM_SCO_INCLUDED == TRUE
+ /* Role switch is not allowed if a SCO is up */
+ if (btm_is_sco_active_by_bdaddr(bd_addr))
+ return(FALSE);
+#endif
+ p_dev_rec = btm_find_dev (bd_addr);
+ if (p_dev_rec && HCI_SWITCH_SUPPORTED(btm_cb.devcb.local_features))
+ {
+ if (HCI_SWITCH_SUPPORTED(p_dev_rec->features))
+ {
+ BTM_TRACE_DEBUG0("btm_dev_support_switch return TRUE (feature found)");
+ return (TRUE);
+ }
+
+ /* If the feature field is all zero, we never received them */
+ for (xx = 0 ; xx < BD_FEATURES_LEN ; xx++)
+ {
+ if (p_dev_rec->features[xx] != 0x00)
+ {
+ feature_empty = FALSE; /* at least one is != 0 */
+ break;
+ }
+ }
+
+ /* If we don't know peer's capabilities, assume it supports Role-switch */
+ if (feature_empty)
+ {
+ BTM_TRACE_DEBUG0("btm_dev_support_switch return TRUE (feature empty)");
+ return (TRUE);
+ }
+ }
+
+ BTM_TRACE_DEBUG0("btm_dev_support_switch return FALSE");
+ return(FALSE);
+}
+
+/*******************************************************************************
+**
+** Function btm_find_dev_by_handle
+**
+** Description Look for the record in the device database for the record
+** with specified handle
+**
+** Returns Pointer to the record or NULL
+**
+*******************************************************************************/
+tBTM_SEC_DEV_REC *btm_find_dev_by_handle (UINT16 handle)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = &btm_cb.sec_dev_rec[0];
+ int i;
+
+ for (i = 0; i < BTM_SEC_MAX_DEVICE_RECORDS; i++, p_dev_rec++)
+ {
+ if ((p_dev_rec->sec_flags & BTM_SEC_IN_USE)
+ && (p_dev_rec->hci_handle == handle))
+ return(p_dev_rec);
+ }
+ return(NULL);
+}
+
+/*******************************************************************************
+**
+** Function btm_find_dev
+**
+** Description Look for the record in the device database for the record
+** with specified BD address
+**
+** Returns Pointer to the record or NULL
+**
+*******************************************************************************/
+tBTM_SEC_DEV_REC *btm_find_dev (BD_ADDR bd_addr)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = &btm_cb.sec_dev_rec[0];
+ int i;
+
+ if (bd_addr)
+ {
+ for (i = 0; i < BTM_SEC_MAX_DEVICE_RECORDS; i++, p_dev_rec++)
+ {
+ if ((p_dev_rec->sec_flags & BTM_SEC_IN_USE)
+ && (!memcmp (p_dev_rec->bd_addr, bd_addr, BD_ADDR_LEN)))
+ return(p_dev_rec);
+ }
+ }
+ return(NULL);
+}
+
+/*******************************************************************************
+**
+** Function btm_find_or_alloc_dev
+**
+** Description Look for the record in the device database for the record
+** with specified BD address
+**
+** Returns Pointer to the record or NULL
+**
+*******************************************************************************/
+tBTM_SEC_DEV_REC *btm_find_or_alloc_dev (BD_ADDR bd_addr)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ BTM_TRACE_EVENT0 ("btm_find_or_alloc_dev");
+ if ((p_dev_rec = btm_find_dev (bd_addr)) == NULL)
+ {
+
+ /* Allocate a new device record or reuse the oldest one */
+ p_dev_rec = btm_sec_alloc_dev (bd_addr);
+ }
+ return(p_dev_rec);
+}
+
+/*******************************************************************************
+**
+** Function btm_find_oldest_dev
+**
+** Description Locates the oldest device in use. It first looks for
+** the oldest non-paired device. If all devices are paired it
+** deletes the oldest paired device.
+**
+** Returns Pointer to the record or NULL
+**
+*******************************************************************************/
+tBTM_SEC_DEV_REC *btm_find_oldest_dev (void)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = &btm_cb.sec_dev_rec[0];
+ tBTM_SEC_DEV_REC *p_oldest = p_dev_rec;
+ UINT32 ot = 0xFFFFFFFF;
+ int i;
+
+ /* First look for the non-paired devices for the oldest entry */
+ for (i = 0; i < BTM_SEC_MAX_DEVICE_RECORDS; i++, p_dev_rec++)
+ {
+ if (((p_dev_rec->sec_flags & BTM_SEC_IN_USE) == 0)
+ || ((p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN) != 0))
+ continue; /* Device is paired so skip it */
+
+ if (p_dev_rec->timestamp < ot)
+ {
+ p_oldest = p_dev_rec;
+ ot = p_dev_rec->timestamp;
+ }
+ }
+
+ if (ot != 0xFFFFFFFF)
+ return(p_oldest);
+
+ /* All devices are paired; find the oldest */
+ p_dev_rec = &btm_cb.sec_dev_rec[0];
+ for (i = 0; i < BTM_SEC_MAX_DEVICE_RECORDS; i++, p_dev_rec++)
+ {
+ if ((p_dev_rec->sec_flags & BTM_SEC_IN_USE) == 0)
+ continue;
+
+ if (p_dev_rec->timestamp < ot)
+ {
+ p_oldest = p_dev_rec;
+ ot = p_dev_rec->timestamp;
+ }
+ }
+ return(p_oldest);
+}
+
+
diff --git a/stack/btm/btm_devctl.c b/stack/btm/btm_devctl.c
new file mode 100644
index 0000000..f668caf
--- /dev/null
+++ b/stack/btm/btm_devctl.c
@@ -0,0 +1,1935 @@
+/*****************************************************************************
+**
+** Name: btm_devctl.c
+**
+** Description: This file contains functions that handle BTM interface
+** functions for the Bluetooth device including Rest, HCI
+** buffer size and others
+**
+** Copyright (c) 1999-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stddef.h>
+
+#include "bt_types.h"
+#include "hcimsgs.h"
+#include "btu.h"
+#include "btm_int.h"
+#include "l2c_int.h"
+
+#if BLE_INCLUDED == TRUE
+#include "gatt_int.h"
+
+#if GAP_INCLUDED == TRUE
+#include "gap_api.h"
+#include "gattdefs.h"
+#endif
+
+#endif /* BLE_INCLUDED */
+
+/* BTM_APP_DEV_INIT should be defined if additional controller initialization is
+** needed by the application to be performed after the HCI reset
+*/
+#ifdef BTM_APP_DEV_INIT
+extern void BTM_APP_DEV_INIT(void);
+#endif
+
+#ifdef BTA_PRM_CHECK_FW_VER
+extern BOOLEAN BTA_PRM_CHECK_FW_VER(UINT8 *p);
+#endif
+
+#ifndef TT_DEV_RESET_MASK
+#define TT_DEV_RESET_MASK 0xff
+#endif
+
+/********************************************************************************/
+/* L O C A L D A T A D E F I N I T I O N S */
+/********************************************************************************/
+
+#ifndef BTM_DEV_RESET_TIMEOUT
+#define BTM_DEV_RESET_TIMEOUT 4
+#endif
+
+#define BTM_DEV_REPLY_TIMEOUT 2 /* 1 second expiration time is not good. Timer may start between 0 and 1 second. */
+ /* if it starts at the very end of the 0 second, timer will expire really easily. */
+
+#define BTM_INFO_TIMEOUT 5 /* 5 seconds for info response */
+
+/* After Reset a timeout can be specified in the target.h for specific targets
+ * that may require additional time to reset
+ * otherwise no timeout is required
+*/
+#ifndef BTM_AFTER_RESET_TIMEOUT
+#define BTM_AFTER_RESET_TIMEOUT 0
+#endif
+
+/* Internal baseband so the parameters such as local features, version etc. are known
+so there is no need to issue HCI commands and wait for responses at BTM initialization */
+#ifndef BTM_INTERNAL_BB
+#define BTM_INTERNAL_BB FALSE
+#endif
+
+/* The local version information in the format specified in the HCI read local version
+response message */
+#ifndef BTM_INTERNAL_LOCAL_VER
+#define BTM_INTERNAL_LOCAL_VER {0x00, 0x01, 0x05, 0x81, 0x01, 0x30, 0x00, 0x40, 0x8D}
+#endif
+
+/* The local features information in the format specified in the HCI read local features
+response message */
+#ifndef BTM_INTERNAL_LOCAL_FEA
+#define BTM_INTERNAL_LOCAL_FEA {0x00, 0xFF, 0xF9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}
+#endif
+
+#ifndef BTM_SET_DEV_NAME_UPON_RESET
+#define BTM_SET_DEV_NAME_UPON_RESET TRUE
+#endif
+
+/* host SCO buffer size */
+#ifndef BTM_SCO_HOST_BUF_SIZE
+#define BTM_SCO_HOST_BUF_SIZE 0xff
+#endif
+
+#ifndef BTM_GPS_UIPC_CH_NB
+#define BTM_GPS_UIPC_CH_NB UIPC_CH_ID_1
+#endif
+
+/********************************************************************************/
+/* L O C A L F U N C T I O N P R O T O T Y P E S */
+/********************************************************************************/
+static void btm_dev_reset (void);
+static void btm_after_reset_hold_complete (void);
+static void btm_continue_reset (void);
+
+/*******************************************************************************
+**
+** Function btm_dev_init
+**
+** Description This function is on the BTM startup
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_dev_init (void)
+{
+#if 0 /* cleared in btm_init; put back in if called from anywhere else! */
+ memset (&btm_cb.devcb, 0, sizeof (tBTM_DEVCB));
+#endif
+
+ /* Initialize nonzero defaults */
+#if (BTM_MAX_LOC_BD_NAME_LEN > 0)
+ memset(btm_cb.cfg.bd_name, 0, sizeof(tBTM_LOC_BD_NAME));
+#if (BTM_USE_DEF_LOCAL_NAME == TRUE)
+ BCM_STRNCPY_S(btm_cb.cfg.bd_name, sizeof(btm_cb.cfg.bd_name), BTM_DEF_LOCAL_NAME, BTM_MAX_LOC_BD_NAME_LEN);
+#endif
+#endif
+
+ btm_cb.devcb.reset_timer.param = (TIMER_PARAM_TYPE)TT_DEV_RESET;
+ btm_cb.devcb.rln_timer.param = (TIMER_PARAM_TYPE)TT_DEV_RLN;
+ btm_cb.devcb.rlinkp_timer.param = (TIMER_PARAM_TYPE)TT_DEV_RLNKP;
+
+ btm_cb.btm_acl_pkt_types_supported = BTM_ACL_PKT_TYPES_MASK_DH1 + BTM_ACL_PKT_TYPES_MASK_DM1 +
+ BTM_ACL_PKT_TYPES_MASK_DH3 + BTM_ACL_PKT_TYPES_MASK_DM3 +
+ BTM_ACL_PKT_TYPES_MASK_DH5 + BTM_ACL_PKT_TYPES_MASK_DM5;
+
+ btm_cb.btm_sco_pkt_types_supported = BTM_SCO_PKT_TYPES_MASK_HV1 +
+ BTM_SCO_PKT_TYPES_MASK_HV2 +
+ BTM_SCO_PKT_TYPES_MASK_HV3 +
+ BTM_SCO_PKT_TYPES_MASK_EV3 +
+ BTM_SCO_PKT_TYPES_MASK_EV4 +
+ BTM_SCO_PKT_TYPES_MASK_EV5;
+
+ btm_cb.first_disabled_channel = 0xff; /* To allow disabling 0th channel alone */
+ btm_cb.last_disabled_channel = 0xff; /* To allow disabling 0th channel alone */
+
+#if (BTM_AUTOMATIC_HCI_RESET == TRUE)
+
+#if (BTM_FIRST_RESET_DELAY > 0)
+ btm_cb.devcb.state = BTM_DEV_STATE_WAIT_RESET_CMPLT;
+ btu_start_timer (&btm_cb.devcb.reset_timer, BTU_TTYPE_BTM_DEV_CTL, BTM_FIRST_RESET_DELAY);
+#else
+ btm_dev_reset();
+#endif
+
+#else
+ BTM_TRACE_EVENT0 ("BTM_AUTOMATIC_HCI_RESET is FALSE, so skip btm reset for now");
+#endif
+
+}
+
+
+/*******************************************************************************
+**
+** Function btm_db_reset
+**
+** Description This function is called by BTM_DeviceReset and clears out any
+** pending callbacks for inquiries, discoveries, other pending
+** functions that may be in progress.
+**
+** Returns void
+**
+*******************************************************************************/
+static void btm_db_reset (void)
+{
+ tBTM_CMPL_CB *p_cb;
+ tBTM_STATUS status = BTM_DEV_RESET;
+
+ btm_inq_db_reset();
+
+ if (btm_cb.devcb.p_rln_cmpl_cb)
+ {
+ p_cb = btm_cb.devcb.p_rln_cmpl_cb;
+ btm_cb.devcb.p_rln_cmpl_cb = NULL;
+
+ if (p_cb)
+ (*p_cb)((void *) NULL);
+ }
+
+ if (btm_cb.devcb.p_rlinkp_cmpl_cb)
+ {
+ p_cb = btm_cb.devcb.p_rlinkp_cmpl_cb;
+ btm_cb.devcb.p_rlinkp_cmpl_cb = NULL;
+
+ if (p_cb)
+ (*p_cb)((void *) &status);
+ }
+
+ if (btm_cb.devcb.p_rssi_cmpl_cb)
+ {
+ p_cb = btm_cb.devcb.p_rssi_cmpl_cb;
+ btm_cb.devcb.p_rssi_cmpl_cb = NULL;
+
+ if (p_cb)
+ (*p_cb)((tBTM_RSSI_RESULTS *) &status);
+ }
+}
+
+
+
+/*******************************************************************************
+**
+** Function btm_dev_absent
+**
+** Description This function is called by when it is detected that the
+** device is not connected any more.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_dev_absent (void)
+{
+ btm_cb.devcb.state = BTM_DEV_STATE_WAIT_RESET_CMPLT;
+
+ btm_db_reset ();
+ btm_inq_db_reset();
+
+ /* If anyone wants device status notifications, give him one */
+ btm_report_device_status (BTM_DEV_STATUS_DOWN);
+
+ btu_stop_timer (&btm_cb.devcb.reset_timer);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_DeviceReset
+**
+** Description This function is called to reset the HCI. Callback function
+** if provided is called when startup of the device is
+** completed.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTM_DeviceReset (tBTM_CMPL_CB *p_cb)
+{
+ tBTM_STATUS status;
+
+ /* If device is already resetting, do not allow another */
+ if ((!btm_cb.devcb.p_reset_cmpl_cb) || (btm_cb.devcb.p_reset_cmpl_cb == p_cb))
+ {
+ /* Flush all ACL connections */
+ btm_acl_device_down();
+
+ /* Clear the callback, so application would not hang on reset */
+ btm_db_reset();
+
+ /* Save address of the completion routine, if provided */
+ btm_cb.devcb.p_reset_cmpl_cb = p_cb;
+
+ btm_dev_reset ();
+ }
+ else
+ {
+ /* pass an error to the bad callback, another one was already provided */
+ if (p_cb)
+ {
+ status = BTM_ILLEGAL_VALUE;
+ p_cb (&status);
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_IsDeviceUp
+**
+** Description This function is called to check if the device is up.
+**
+** Returns TRUE if device is up, else FALSE
+**
+*******************************************************************************/
+BOOLEAN BTM_IsDeviceUp (void)
+{
+ return ((BOOLEAN) (btm_cb.devcb.state == BTM_DEV_STATE_READY));
+}
+
+/*******************************************************************************
+**
+** Function BTM_SetAfhChannels
+**
+** Description This function is called disable channels
+**
+** Returns tBTM_STATUS
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetAfhChannels (UINT8 first, UINT8 last)
+{
+ BTM_TRACE_API4 ("BTM_SetAfhChannels first: %d (%d) last: %d (%d)",
+ first, btm_cb.first_disabled_channel, last,
+ btm_cb.last_disabled_channel);
+
+ /* Make sure the local device supports the feature before sending */
+ if ((!HCI_LMP_AFH_CAP_MASTR_SUPPORTED(btm_cb.devcb.local_features)) &&
+ (!HCI_LMP_AFH_CLASS_SLAVE_SUPPORTED(btm_cb.devcb.local_features)) &&
+ (!HCI_LMP_AFH_CLASS_MASTR_SUPPORTED(btm_cb.devcb.local_features)))
+ return (BTM_MODE_UNSUPPORTED);
+
+ if (!BTM_IsDeviceUp())
+ return (BTM_WRONG_MODE);
+
+ if ((btm_cb.first_disabled_channel != first)
+ || (btm_cb.last_disabled_channel != last))
+ {
+ if (btsnd_hcic_set_afh_channels (first, last))
+ {
+ btm_cb.first_disabled_channel = first;
+ btm_cb.last_disabled_channel = last;
+ }
+ else
+ return (BTM_NO_RESOURCES);
+ }
+ return (BTM_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function BTM_SetAfhChannelAssessment
+**
+** Description This function is called to set the channel assessment mode on or off
+**
+** Returns none
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetAfhChannelAssessment (BOOLEAN enable_or_disable)
+{
+ /* whatever app wants if device is not 1.2 scan type should be STANDARD */
+ if (!HCI_LMP_AFH_CAP_SLAVE_SUPPORTED(btm_cb.devcb.local_features))
+ return (BTM_MODE_UNSUPPORTED);
+
+ if (!btsnd_hcic_write_afh_channel_assessment_mode (enable_or_disable))
+ return (BTM_NO_RESOURCES);
+
+ return (BTM_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function BTM_ContinueReset
+**
+** Description This function is called by the application to continue
+** initialization after the application has completed its
+** vendor specific sequence. It is only used when
+** BTM_APP_DEV_INIT is defined in target.h.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTM_ContinueReset (void)
+{
+#ifdef BTM_APP_DEV_INIT
+ btm_continue_reset();
+#endif
+}
+
+/*******************************************************************************
+**
+** Function btm_dev_reset
+**
+** Description Local function called to send a reset command
+**
+** Returns void
+**
+*******************************************************************************/
+static void btm_dev_reset (void)
+{
+ btm_cb.devcb.state = BTM_DEV_STATE_WAIT_RESET_CMPLT;
+
+ /* flush out the command complete queue and command transmit queue */
+ btu_hcif_flush_cmd_queue();
+
+ /* Start reset timer. When timer expires we will send first command */
+ /* from the setup sequence */
+
+ btu_start_timer (&btm_cb.devcb.reset_timer, BTU_TTYPE_BTM_DEV_CTL,
+ BTM_DEV_RESET_TIMEOUT);
+ btsnd_hcic_reset (LOCAL_BR_EDR_CONTROLLER_ID);
+}
+
+
+/*******************************************************************************
+**
+** Function btm_get_hci_buf_size
+**
+** Description Local function called to send a read buffer size command
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_get_hci_buf_size (void)
+{
+
+ btu_start_timer (&btm_cb.devcb.reset_timer, BTU_TTYPE_BTM_DEV_CTL, BTM_DEV_REPLY_TIMEOUT);
+
+ /* Send a Read Buffer Size message to the Host Controller. */
+ btsnd_hcic_read_buffer_size ();
+
+}
+#if BLE_INCLUDED == TRUE
+/*******************************************************************************
+**
+** Function btm_read_ble_wl_size
+**
+** Description Local function called to send a read BLE buffer size command
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_read_ble_wl_size(void)
+{
+ BTM_TRACE_DEBUG0("btm_read_ble_wl_size ");
+ btu_start_timer (&btm_cb.devcb.reset_timer, BTU_TTYPE_BTM_DEV_CTL, BTM_DEV_REPLY_TIMEOUT);
+
+ /* Send a Read Buffer Size message to the Host Controller. */
+ btsnd_hcic_ble_read_white_list_size();
+}
+/*******************************************************************************
+**
+** Function btm_get_ble_buffer_size
+**
+** Description Local function called to send a read BLE buffer size command
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_get_ble_buffer_size(void)
+{
+ BTM_TRACE_DEBUG0("btm_get_ble_buffer_size ");
+ btu_start_timer (&btm_cb.devcb.reset_timer, BTU_TTYPE_BTM_DEV_CTL, BTM_DEV_REPLY_TIMEOUT);
+
+ /* Send a Read Buffer Size message to the Host Controller. */
+ btsnd_hcic_ble_read_buffer_size ();
+}
+#endif
+/*******************************************************************************
+**
+** Function btm_get_local_version
+**
+** Description Local function called to send a read local version to controller
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_get_local_version (void)
+{
+
+ btu_start_timer (&btm_cb.devcb.reset_timer, BTU_TTYPE_BTM_DEV_CTL, BTM_DEV_REPLY_TIMEOUT);
+
+ /* Send a Read Local Version message to the Host Controller. */
+ btsnd_hcic_read_local_ver (LOCAL_BR_EDR_CONTROLLER_ID);
+ btsnd_hcic_read_bd_addr ();
+
+#if BTM_PWR_MGR_INCLUDED == TRUE
+ btm_pm_reset();
+#endif
+
+}
+
+/*******************************************************************************
+**
+** Function btm_get_local_features
+**
+** Description Local function called to send a read local features
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_get_local_features (void)
+{
+ btu_start_timer (&btm_cb.devcb.reset_timer, BTU_TTYPE_BTM_DEV_CTL, BTM_DEV_REPLY_TIMEOUT);
+
+ btsnd_hcic_read_local_features ();
+}
+
+/*******************************************************************************
+**
+** Function btm_dev_timeout
+**
+** Description This function is called when a timer list entry expires.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_dev_timeout (TIMER_LIST_ENT *p_tle)
+{
+ TIMER_PARAM_TYPE timer_type = (TIMER_PARAM_TYPE)p_tle->param;
+
+ if ((timer_type & TT_DEV_RESET_MASK) == TT_DEV_RESET)
+ {
+ /* Call device reset as long as there is timeout*/
+ btm_dev_reset();
+ }
+ else if (timer_type == (TIMER_PARAM_TYPE)TT_DEV_RLN)
+ {
+ tBTM_CMPL_CB *p_cb = btm_cb.devcb.p_rln_cmpl_cb;
+
+ btm_cb.devcb.p_rln_cmpl_cb = NULL;
+
+ if (p_cb)
+ (*p_cb)((void *) NULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_reset_complete
+**
+** Description This function is called when command complete for HCI_Reset
+** is received. It does not make sense to send next command
+** because device is resetting after command complete is
+** received. Just start timer and set required state.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_reset_complete (void)
+{
+ int devinx;
+
+ BTM_TRACE_EVENT0 ("btm_reset_complete");
+
+#ifdef BRCM_VS
+ btm_vs_reset_complete();
+#endif
+
+
+ /* Handle if btm initiated the reset */
+ if (btm_cb.devcb.state == BTM_DEV_STATE_WAIT_RESET_CMPLT)
+ {
+ /* Tell L2CAP that all connections are gone */
+ l2cu_device_reset ();
+
+ /* Clear current security state */
+ for (devinx = 0; devinx < BTM_SEC_MAX_DEVICE_RECORDS; devinx++)
+ {
+ btm_cb.sec_dev_rec[devinx].sec_state = BTM_SEC_STATE_IDLE;
+ }
+
+ /* After the reset controller should restore all parameters to defaults. */
+ btm_cb.btm_inq_vars.inq_counter = 1;
+ btm_cb.btm_inq_vars.inq_scan_window = HCI_DEF_INQUIRYSCAN_WINDOW;
+ btm_cb.btm_inq_vars.inq_scan_period = HCI_DEF_INQUIRYSCAN_INTERVAL;
+ btm_cb.btm_inq_vars.inq_scan_type = HCI_DEF_SCAN_TYPE;
+
+ btm_cb.btm_inq_vars.page_scan_window = HCI_DEF_PAGESCAN_WINDOW;
+ btm_cb.btm_inq_vars.page_scan_period = HCI_DEF_PAGESCAN_INTERVAL;
+ btm_cb.btm_inq_vars.page_scan_type = HCI_DEF_SCAN_TYPE;
+
+#if (BTM_AFTER_RESET_TIMEOUT > 0)
+ btu_start_timer (&btm_cb.devcb.reset_timer, BTU_TTYPE_BTM_DEV_CTL,
+ BTM_AFTER_RESET_TIMEOUT);
+#else
+ btm_cb.devcb.state = BTM_DEV_STATE_WAIT_AFTER_RESET;
+ btm_after_reset_hold_complete();
+#endif
+
+#if (BLE_INCLUDED == TRUE)
+ btm_cb.ble_ctr_cb.bg_conn_state = BLE_BG_CONN_IDLE;
+ btm_cb.ble_ctr_cb.bg_conn_dev_num = 0;
+ btm_cb.ble_ctr_cb.bg_conn_type = BTM_BLE_CONN_NONE;
+ btm_cb.ble_ctr_cb.p_select_cback = NULL;
+ memset(&btm_cb.ble_ctr_cb.bg_conn_dev_list, 0, (sizeof(BD_ADDR)*BTM_BLE_MAX_BG_CONN_DEV_NUM));
+ gatt_reset_bgdev_list();
+#endif
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_continue_reset
+**
+** Description This function is called when wait period expired after
+** device reset or called by the application to continue
+** initialization after the application has completed its
+** vendor specific sequence.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_continue_reset (void)
+{
+
+ /* Reinitialize the default class of device */
+#if BTM_INTERNAL_BB == TRUE
+ btsnd_hcic_read_bd_addr ();
+#if BTM_PWR_MGR_INCLUDED == TRUE
+ btm_pm_reset();
+#endif
+#endif
+
+ btm_get_hci_buf_size ();
+
+ /* default device class */
+ BTM_SetDeviceClass((UINT8 *) BTM_INIT_CLASS_OF_DEVICE);
+
+#if (BTM_MAX_LOC_BD_NAME_LEN > 0) && (BTM_SET_DEV_NAME_UPON_RESET == TRUE)
+ BTM_SetLocalDeviceName(btm_cb.cfg.bd_name);
+#elif BTM_USE_DEF_LOCAL_NAME == TRUE
+ BTM_SetLocalDeviceName(BTM_DEF_LOCAL_NAME);
+#endif
+
+ BTM_SetPinType (btm_cb.cfg.pin_type, btm_cb.cfg.pin_code, btm_cb.cfg.pin_code_len);
+}
+
+/*******************************************************************************
+**
+** Function btm_after_reset_hold_complete
+**
+** Description This function is called when wait period expired after
+** device reset. Continue intitialization
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_after_reset_hold_complete (void)
+{
+#ifdef BTM_APP_DEV_INIT
+ btu_stop_timer(&btm_cb.devcb.reset_timer);
+ BTM_APP_DEV_INIT();
+#else
+ btm_continue_reset();
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function btm_read_hci_buf_size_complete
+**
+** Description This function is called when command complete for
+** get HCI buffer size is received. Start timer and send
+** read local featues request
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_read_hci_buf_size_complete (UINT8 *p, UINT16 evt_len)
+{
+ UINT8 status;
+ UINT8 lm_sco_buf_size;
+ UINT16 lm_num_acl_bufs;
+ UINT16 lm_num_sco_bufs;
+ UINT16 acl_buf_size;
+
+ STREAM_TO_UINT8 (status, p);
+ if (status == HCI_SUCCESS)
+ {
+ STREAM_TO_UINT16 (btu_cb.hcit_acl_data_size, p);
+ STREAM_TO_UINT8 (lm_sco_buf_size, p);
+ STREAM_TO_UINT16 (lm_num_acl_bufs, p);
+ STREAM_TO_UINT16 (lm_num_sco_bufs, p);
+
+ btu_cb.hcit_acl_pkt_size = btu_cb.hcit_acl_data_size + HCI_DATA_PREAMBLE_SIZE;
+
+ l2c_link_processs_num_bufs (lm_num_acl_bufs);
+
+#if BTM_ACL_BUF_SIZE > 0
+ acl_buf_size = (BTM_ACL_BUF_SIZE < L2CAP_MTU_SIZE) ? BTM_ACL_BUF_SIZE : L2CAP_MTU_SIZE;
+#else
+ acl_buf_size = L2CAP_MTU_SIZE;
+#endif
+ /* Tell the controller what our buffer sizes are. ?? Need SCO info */
+ btsnd_hcic_set_host_buf_size (acl_buf_size, BTM_SCO_HOST_BUF_SIZE, L2CAP_HOST_FC_ACL_BUFS, 10);
+
+#if L2CAP_HOST_FLOW_CTRL == TRUE
+ btsnd_hcic_set_host_flow_ctrl (HCI_HOST_FLOW_CTRL_ACL_ON);
+#endif
+ }
+
+ /* Set the device into connectable and/or discoverable mode (if configured to do so) */
+#if BTM_IS_CONNECTABLE == TRUE
+ (void) BTM_SetConnectability (BTM_CONNECTABLE, BTM_DEFAULT_CONN_WINDOW, BTM_DEFAULT_CONN_INTERVAL);
+#endif
+
+#if BTM_IS_DISCOVERABLE == TRUE
+ (void) BTM_SetDiscoverability (BTM_DEFAULT_DISC_MODE, BTM_DEFAULT_DISC_WINDOW, BTM_DEFAULT_DISC_INTERVAL);
+#endif
+
+#if BTM_INTERNAL_BB == TRUE
+ {
+ UINT8 buf[9] = BTM_INTERNAL_LOCAL_VER;
+ btm_read_local_version_complete( buf, 9 );
+ }
+#else
+ btm_get_local_version ();
+#endif
+}
+
+#if (BLE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function btm_read_ble_buf_size_complete
+**
+** Description This function is called when command complete for
+** get HCI buffer size is received. Start timer and send
+** read local featues request
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_read_ble_buf_size_complete (UINT8 *p, UINT16 evt_len)
+{
+ UINT8 status;
+ UINT16 lm_num_le_bufs;
+
+ BTM_TRACE_DEBUG0("btm_read_ble_buf_size_complete ");
+ STREAM_TO_UINT8 (status, p);
+ if (status == HCI_SUCCESS)
+ {
+ STREAM_TO_UINT16 (btu_cb.hcit_ble_acl_data_size, p);
+ STREAM_TO_UINT8 (lm_num_le_bufs, p);
+
+ btu_cb.hcit_ble_acl_pkt_size = btu_cb.hcit_ble_acl_data_size + HCI_DATA_PREAMBLE_SIZE;
+
+ l2c_link_processs_ble_num_bufs (lm_num_le_bufs);
+ }
+
+#if BTM_INTERNAL_BB == TRUE
+ {
+ UINT8 buf[9] = BTM_INTERNAL_LOCAL_FEA;
+ btm_read_local_features_complete( buf, 9 );
+ }
+#else
+#ifdef BRCM_VS
+ btm_brcm_feat_init();
+#else
+ /* get local feature if BRCM specific feature is not included */
+ btm_get_local_features ();
+#endif
+#endif
+
+}
+
+/*******************************************************************************
+**
+** Function btm_read_white_list_size_complete
+**
+** Description This function read the current white list size.
+*******************************************************************************/
+void btm_read_white_list_size_complete(UINT8 *p, UINT16 evt_len)
+{
+ UINT8 status;
+
+ BTM_TRACE_DEBUG0("btm_read_white_list_size_complete ");
+ STREAM_TO_UINT8 (status, p);
+
+ if (status == HCI_SUCCESS)
+ {
+ STREAM_TO_UINT8(btm_cb.ble_ctr_cb.max_filter_entries, p);
+ btm_cb.ble_ctr_cb.num_empty_filter = btm_cb.ble_ctr_cb.max_filter_entries;
+ }
+
+ btm_get_ble_buffer_size();
+}
+
+#endif
+/*******************************************************************************
+**
+** Function btm_read_local_version_complete
+**
+** Description This function is called when local BD Addr read complete
+** message is received from the HCI.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_read_local_version_complete (UINT8 *p, UINT16 evt_len)
+{
+ tBTM_VERSION_INFO *p_vi = &btm_cb.devcb.local_version;
+ UINT8 status;
+
+#ifdef BTA_PRM_CHECK_FW_VER
+ if(BTA_PRM_CHECK_FW_VER(p))
+ return;
+#endif
+
+ STREAM_TO_UINT8 (status, p);
+ if (status == HCI_SUCCESS)
+ {
+
+ STREAM_TO_UINT8 (p_vi->hci_version, p);
+ STREAM_TO_UINT16 (p_vi->hci_revision, p);
+ STREAM_TO_UINT8 (p_vi->lmp_version, p);
+ STREAM_TO_UINT16 (p_vi->manufacturer, p);
+ STREAM_TO_UINT16 (p_vi->lmp_subversion, p);
+ }
+
+#if BLE_INCLUDED == TRUE
+ {
+ btm_read_ble_wl_size();
+ }
+#elif BTM_INTERNAL_BB == TRUE
+ {
+ UINT8 buf[9] = BTM_INTERNAL_LOCAL_FEA;
+ btm_read_local_features_complete( buf, 9 );
+ }
+#else
+#ifdef BRCM_VS
+ btm_brcm_feat_init();
+#else
+ /* get local feature if BRCM specific feature is not included */
+ btm_get_local_features ();
+#endif
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function btm_read_local_features_complete
+**
+** Description This function is called when local features read is complete.
+** This is the last step of the startup sequence.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_read_local_features_complete (UINT8 *p, UINT16 evt_len)
+{
+ tBTM_DEVCB *p_devcb = &btm_cb.devcb;
+ tBTM_CMPL_CB *p_cb = p_devcb->p_reset_cmpl_cb;
+ UINT8 status;
+ UINT16 xx;
+ UINT8 last;
+ UINT8 first;
+
+ btu_stop_timer (&btm_cb.devcb.reset_timer);
+ /* If there was a callback address for reset complete, call it */
+ p_devcb->p_reset_cmpl_cb = NULL;
+
+ STREAM_TO_UINT8 (status, p);
+ if (status == HCI_SUCCESS)
+ {
+ /* stop guard timer to avoid accidental timeout */
+ btu_stop_timer(&p_devcb->reset_timer);
+
+ p_devcb->state = BTM_DEV_STATE_READY;
+
+ /* Extract features and create "btm_acl_pkt_types_supported" flag
+ */
+ for (xx = 0; xx < HCI_NUM_FEATURE_BYTES; xx++)
+ STREAM_TO_UINT8 (p_devcb->local_features[xx], p);
+
+ /* Create ACL supported packet types mask
+ */
+ btm_cb.btm_acl_pkt_types_supported = (BTM_ACL_PKT_TYPES_MASK_DH1 +
+ BTM_ACL_PKT_TYPES_MASK_DM1);
+
+ if (HCI_3_SLOT_PACKETS_SUPPORTED(p_devcb->local_features))
+ btm_cb.btm_acl_pkt_types_supported |= (BTM_ACL_PKT_TYPES_MASK_DH3 +
+ BTM_ACL_PKT_TYPES_MASK_DM3);
+
+ if (HCI_5_SLOT_PACKETS_SUPPORTED(p_devcb->local_features))
+ btm_cb.btm_acl_pkt_types_supported |= (BTM_ACL_PKT_TYPES_MASK_DH5 +
+ BTM_ACL_PKT_TYPES_MASK_DM5);
+
+ /* _NO_X_DXX masks are reserved before ver 2.0.
+ Set them only for later versions of controller */
+ if (btm_cb.devcb.local_version.hci_version >= HCI_PROTO_VERSION_2_0)
+ {
+
+ /* Add in EDR related ACL types */
+ if (!HCI_EDR_ACL_2MPS_SUPPORTED(p_devcb->local_features))
+ {
+ btm_cb.btm_acl_pkt_types_supported |= (BTM_ACL_PKT_TYPES_MASK_NO_2_DH1 +
+ BTM_ACL_PKT_TYPES_MASK_NO_2_DH3 +
+ BTM_ACL_PKT_TYPES_MASK_NO_2_DH5);
+ }
+
+ if (!HCI_EDR_ACL_3MPS_SUPPORTED(p_devcb->local_features))
+ {
+ btm_cb.btm_acl_pkt_types_supported |= (BTM_ACL_PKT_TYPES_MASK_NO_3_DH1 +
+ BTM_ACL_PKT_TYPES_MASK_NO_3_DH3 +
+ BTM_ACL_PKT_TYPES_MASK_NO_3_DH5);
+ }
+
+ /* Check to see if 3 and 5 slot packets are available */
+ if (HCI_EDR_ACL_2MPS_SUPPORTED(p_devcb->local_features) ||
+ HCI_EDR_ACL_3MPS_SUPPORTED(p_devcb->local_features))
+ {
+ if (!HCI_3_SLOT_EDR_ACL_SUPPORTED(p_devcb->local_features))
+ btm_cb.btm_acl_pkt_types_supported |= (BTM_ACL_PKT_TYPES_MASK_NO_2_DH3 +
+ BTM_ACL_PKT_TYPES_MASK_NO_3_DH3);
+
+ if (!HCI_5_SLOT_EDR_ACL_SUPPORTED(p_devcb->local_features))
+ btm_cb.btm_acl_pkt_types_supported |= (BTM_ACL_PKT_TYPES_MASK_NO_2_DH5 +
+ BTM_ACL_PKT_TYPES_MASK_NO_3_DH5);
+ }
+ }
+
+ BTM_TRACE_DEBUG1("Local supported ACL packet types: 0x%04x",
+ btm_cb.btm_acl_pkt_types_supported);
+
+ /* Create (e)SCO supported packet types mask
+ */
+ btm_cb.btm_sco_pkt_types_supported = 0;
+#if BTM_SCO_INCLUDED == TRUE
+ btm_cb.sco_cb.esco_supported = FALSE;
+#endif
+ if (HCI_SCO_LINK_SUPPORTED(p_devcb->local_features))
+ {
+ btm_cb.btm_sco_pkt_types_supported = BTM_SCO_PKT_TYPES_MASK_HV1;
+
+ if (HCI_HV2_PACKETS_SUPPORTED(p_devcb->local_features))
+ btm_cb.btm_sco_pkt_types_supported |= BTM_SCO_PKT_TYPES_MASK_HV2;
+
+ if (HCI_HV3_PACKETS_SUPPORTED(p_devcb->local_features))
+ btm_cb.btm_sco_pkt_types_supported |= BTM_SCO_PKT_TYPES_MASK_HV3;
+ }
+
+ if (HCI_ESCO_EV3_SUPPORTED(p_devcb->local_features))
+ btm_cb.btm_sco_pkt_types_supported |= BTM_SCO_PKT_TYPES_MASK_EV3;
+
+ if (HCI_ESCO_EV4_SUPPORTED(p_devcb->local_features))
+ btm_cb.btm_sco_pkt_types_supported |= BTM_SCO_PKT_TYPES_MASK_EV4;
+
+ if (HCI_ESCO_EV5_SUPPORTED(p_devcb->local_features))
+ btm_cb.btm_sco_pkt_types_supported |= BTM_SCO_PKT_TYPES_MASK_EV5;
+#if BTM_SCO_INCLUDED == TRUE
+ if (btm_cb.btm_sco_pkt_types_supported & BTM_ESCO_LINK_ONLY_MASK)
+ {
+ btm_cb.sco_cb.esco_supported = TRUE;
+
+ /* Add in EDR related eSCO types */
+ if (HCI_EDR_ESCO_2MPS_SUPPORTED(p_devcb->local_features))
+ {
+ if (!HCI_3_SLOT_EDR_ESCO_SUPPORTED(p_devcb->local_features))
+ btm_cb.btm_sco_pkt_types_supported |= BTM_SCO_PKT_TYPES_MASK_NO_2_EV5;
+ }
+ else
+ {
+ btm_cb.btm_sco_pkt_types_supported |= (BTM_SCO_PKT_TYPES_MASK_NO_2_EV3 +
+ BTM_SCO_PKT_TYPES_MASK_NO_2_EV5);
+ }
+
+ if (HCI_EDR_ESCO_3MPS_SUPPORTED(p_devcb->local_features))
+ {
+ if (!HCI_3_SLOT_EDR_ESCO_SUPPORTED(p_devcb->local_features))
+ btm_cb.btm_sco_pkt_types_supported |= BTM_SCO_PKT_TYPES_MASK_NO_3_EV5;
+ }
+ else
+ {
+ btm_cb.btm_sco_pkt_types_supported |= (BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 +
+ BTM_SCO_PKT_TYPES_MASK_NO_3_EV5);
+ }
+ }
+#endif
+
+ BTM_TRACE_DEBUG1("Local supported SCO packet types: 0x%04x",
+ btm_cb.btm_sco_pkt_types_supported);
+
+ /* Create Default Policy Settings
+ */
+ if (HCI_SWITCH_SUPPORTED(p_devcb->local_features))
+ btm_cb.btm_def_link_policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH;
+ else
+ btm_cb.btm_def_link_policy &= ~HCI_ENABLE_MASTER_SLAVE_SWITCH;
+
+ if (HCI_HOLD_MODE_SUPPORTED(p_devcb->local_features))
+ btm_cb.btm_def_link_policy |= HCI_ENABLE_HOLD_MODE;
+ else
+ btm_cb.btm_def_link_policy &= ~HCI_ENABLE_HOLD_MODE;
+
+ if (HCI_SNIFF_MODE_SUPPORTED(p_devcb->local_features))
+ btm_cb.btm_def_link_policy |= HCI_ENABLE_SNIFF_MODE;
+ else
+ btm_cb.btm_def_link_policy &= ~HCI_ENABLE_SNIFF_MODE;
+
+ if (HCI_PARK_MODE_SUPPORTED(p_devcb->local_features))
+ btm_cb.btm_def_link_policy |= HCI_ENABLE_PARK_MODE;
+ else
+ btm_cb.btm_def_link_policy &= ~HCI_ENABLE_PARK_MODE;
+
+ btm_sec_dev_reset ();
+
+ /* If 802.11 present might have to disable some channels */
+ if (btm_cb.last_disabled_channel != 0xff)
+ {
+ last = btm_cb.last_disabled_channel;
+ first = btm_cb.first_disabled_channel;
+ btm_cb.last_disabled_channel = 0xff;
+ btm_cb.first_disabled_channel = 0xff;
+ BTM_SetAfhChannels(first, last);
+ }
+
+#if ((BTM_EIR_SERVER_INCLUDED == TRUE)||(BTM_EIR_CLIENT_INCLUDED == TRUE))
+ if (HCI_LMP_INQ_RSSI_SUPPORTED(p_devcb->local_features))
+ {
+ if (HCI_EXT_INQ_RSP_SUPPORTED(p_devcb->local_features))
+ BTM_SetInquiryMode (BTM_INQ_RESULT_EXTENDED);
+ else
+ BTM_SetInquiryMode (BTM_INQ_RESULT_WITH_RSSI);
+ }
+#else
+ if (HCI_LMP_INQ_RSSI_SUPPORTED(p_devcb->local_features))
+ BTM_SetInquiryMode (BTM_INQ_RESULT_WITH_RSSI);
+#endif
+#if L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE
+ if( HCI_NON_FLUSHABLE_PB_SUPPORTED(p_devcb->local_features))
+ l2cu_set_non_flushable_pbf(TRUE);
+ else
+ l2cu_set_non_flushable_pbf(FALSE);
+#endif
+ BTM_SetPageScanType (BTM_DEFAULT_SCAN_TYPE);
+ BTM_SetInquiryScanType (BTM_DEFAULT_SCAN_TYPE);
+
+ /* If anyone wants device status notifications, give him one */
+ btm_report_device_status (BTM_DEV_STATUS_UP);
+
+#ifdef BRCM_VS
+ btm_brcm_arc_init();
+#endif
+
+ /* Reset sequence is complete. If this was an application originated */
+ /* reset, tell him its done. */
+ if (p_cb)
+ (*p_cb)((void *) NULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_get_voice_coding_support
+**
+** Description This function is provides a way to get the voice coding schemes
+** supported the device.
+**
+** Returns A bit mask - Bit 0 if set indicates CVSD support
+** Bit 1 if set indicates PCM A-law support
+** Bit 2 if set indicates PCM Mu-law support
+**
+*******************************************************************************/
+
+UINT8 btm_get_voice_coding_support( void )
+{
+ UINT8 code = 0;
+
+ if( HCI_LMP_CVSD_SUPPORTED(btm_cb.devcb.local_features) ) code |= 0x01 ;
+ if( HCI_LMP_A_LAW_SUPPORTED(btm_cb.devcb.local_features) ) code |= 0x02 ;
+ if( HCI_LMP_U_LAW_SUPPORTED(btm_cb.devcb.local_features) ) code |= 0x04 ;
+
+ return code ;
+}
+
+/*******************************************************************************
+**
+** Function BTM_SetLocalDeviceName
+**
+** Description This function is called to set the local device name.
+**
+** Returns status of the operation
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetLocalDeviceName (char *p_name)
+{
+ UINT8 *p;
+#if BLE_INCLUDED == TRUE && GAP_INCLUDED == TRUE
+ tGAP_BLE_ATTR_VALUE attr_value;
+#endif
+
+ if (!p_name || !p_name[0] || (strlen ((char *)p_name) > BD_NAME_LEN))
+ return (BTM_ILLEGAL_VALUE);
+
+ if (btm_cb.devcb.state == BTM_DEV_STATE_WAIT_RESET_CMPLT ||
+ btm_cb.devcb.state == BTM_DEV_STATE_WAIT_AFTER_RESET)
+ return (BTM_DEV_RESET);
+
+#if BTM_MAX_LOC_BD_NAME_LEN > 0
+ /* Save the device name if local storage is enabled */
+ p = (UINT8 *)btm_cb.cfg.bd_name;
+ if (p != (UINT8 *)p_name)
+ {
+ BCM_STRNCPY_S(btm_cb.cfg.bd_name, sizeof(btm_cb.cfg.bd_name), p_name, BTM_MAX_LOC_BD_NAME_LEN);
+ btm_cb.cfg.bd_name[BTM_MAX_LOC_BD_NAME_LEN] = '\0';
+ }
+#else
+ p = (UINT8 *)p_name;
+#endif
+
+#if BLE_INCLUDED == TRUE && GAP_INCLUDED == TRUE
+ attr_value.p_dev_name = (UINT8 *)p_name;
+ GAP_BleAttrDBUpdate(GATT_UUID_GAP_DEVICE_NAME, &attr_value);
+#endif
+
+ if (btsnd_hcic_change_name(p))
+ return (BTM_CMD_STARTED);
+ else
+ return (BTM_NO_RESOURCES);
+}
+
+
+
+/*******************************************************************************
+**
+** Function BTM_ReadLocalDeviceName
+**
+** Description This function is called to read the local device name.
+**
+** Returns status of the operation
+** If success, BTM_SUCCESS is returned and p_name points stored
+** local device name
+** If BTM doesn't store local device name, BTM_NO_RESOURCES is
+** is returned and p_name is set to NULL
+**
+*******************************************************************************/
+tBTM_STATUS BTM_ReadLocalDeviceName (char **p_name)
+{
+#if BTM_MAX_LOC_BD_NAME_LEN > 0
+ *p_name = btm_cb.cfg.bd_name;
+ return(BTM_SUCCESS);
+#else
+ *p_name = NULL;
+ return(BTM_NO_RESOURCES);
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_ReadLocalDeviceNameFromController
+**
+** Description Get local device name from controller. Do not use cached
+** name (used to get chip-id prior to btm reset complete).
+**
+** Returns BTM_CMD_STARTED if successful, otherwise an error
+**
+*******************************************************************************/
+tBTM_STATUS BTM_ReadLocalDeviceNameFromController (tBTM_CMPL_CB *p_rln_cmpl_cback)
+{
+ /* Check if rln already in progress */
+ if (btm_cb.devcb.p_rln_cmpl_cb)
+ return(BTM_NO_RESOURCES);
+
+ /* Save callback */
+ btm_cb.devcb.p_rln_cmpl_cb = p_rln_cmpl_cback;
+
+ btsnd_hcic_read_name();
+ btu_start_timer (&btm_cb.devcb.rln_timer, BTU_TTYPE_BTM_DEV_CTL, BTM_DEV_REPLY_TIMEOUT);
+
+ return BTM_CMD_STARTED;
+}
+
+/*******************************************************************************
+**
+** Function btm_read_local_name_complete
+**
+** Description This function is called when local name read complete.
+** message is received from the HCI.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_read_local_name_complete (UINT8 *p, UINT16 evt_len)
+{
+ tBTM_CMPL_CB *p_cb = btm_cb.devcb.p_rln_cmpl_cb;
+ UINT8 status;
+
+ btu_stop_timer (&btm_cb.devcb.rln_timer);
+
+ /* If there was a callback address for read local name, call it */
+ btm_cb.devcb.p_rln_cmpl_cb = NULL;
+
+ if (p_cb)
+ {
+ STREAM_TO_UINT8 (status, p);
+
+ if (status == HCI_SUCCESS)
+ (*p_cb)(p);
+ else
+ (*p_cb)(NULL);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_GetLocalDeviceAddr
+**
+** Description This function is called to read the local device address
+**
+** Returns void
+** the local device address is copied into bd_addr
+**
+*******************************************************************************/
+void BTM_GetLocalDeviceAddr (BD_ADDR bd_addr)
+{
+ memcpy (bd_addr, btm_cb.devcb.local_addr, BD_ADDR_LEN);
+}
+
+/*******************************************************************************
+**
+** Function BTM_ReadLocalDeviceAddr
+**
+** Description This function is called to read the local device address
+**
+** Returns status of the operation
+**
+*******************************************************************************/
+tBTM_STATUS BTM_ReadLocalDeviceAddr (tBTM_CMPL_CB *p_cb)
+{
+ if(p_cb)
+ (*p_cb)(btm_cb.devcb.local_addr);
+
+ return (BTM_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function btm_read_local_addr_complete
+**
+** Description This function is called when local BD Addr read complete
+** message is received from the HCI.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_read_local_addr_complete (UINT8 *p, UINT16 evt_len)
+{
+ UINT8 status;
+
+ STREAM_TO_UINT8 (status, p);
+
+ if (status == HCI_SUCCESS)
+ {
+ STREAM_TO_BDADDR (btm_cb.devcb.local_addr, p);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_ReadLocalVersion
+**
+** Description This function is called to read the local device version
+**
+** Returns status of the operation
+**
+*******************************************************************************/
+tBTM_STATUS BTM_ReadLocalVersion (tBTM_VERSION_INFO *p_vers)
+{
+ /* Make sure the device has retrieved the info (not being reset) */
+ if (btm_cb.devcb.state < BTM_DEV_STATE_READY)
+ return (BTM_DEV_RESET);
+
+ *p_vers = btm_cb.devcb.local_version;
+
+ return (BTM_SUCCESS);
+}
+
+
+
+
+/*******************************************************************************
+**
+** Function BTM_SetDeviceClass
+**
+** Description This function is called to set the local device class
+**
+** Returns status of the operation
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetDeviceClass (DEV_CLASS dev_class)
+{
+ if(!memcmp (btm_cb.devcb.dev_class, dev_class, DEV_CLASS_LEN))
+ return(BTM_SUCCESS);
+
+ memcpy (btm_cb.devcb.dev_class, dev_class, DEV_CLASS_LEN);
+
+ if (btm_cb.devcb.state == BTM_DEV_STATE_WAIT_RESET_CMPLT ||
+ btm_cb.devcb.state == BTM_DEV_STATE_WAIT_AFTER_RESET)
+ return (BTM_DEV_RESET);
+
+ if (!btsnd_hcic_write_dev_class (dev_class))
+ return (BTM_NO_RESOURCES);
+
+ return (BTM_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_ReadDeviceClass
+**
+** Description This function is called to read the local device class
+**
+** Returns pointer to the device class
+**
+*******************************************************************************/
+UINT8 *BTM_ReadDeviceClass (void)
+{
+ return ((UINT8 *)btm_cb.devcb.dev_class);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_ReadLocalFeatures
+**
+** Description This function is called to read the local features
+**
+** Returns pointer to the local features string
+**
+*******************************************************************************/
+UINT8 *BTM_ReadLocalFeatures (void)
+{
+ return (btm_cb.devcb.local_features);
+}
+
+/*******************************************************************************
+**
+** Function BTM_ReadBrcmFeatures
+**
+** Description This function is called to read the Broadcom specific features
+**
+** Returns pointer to the Broadcom features string
+**
+*******************************************************************************/
+UINT8 *BTM_ReadBrcmFeatures (void)
+{
+ return (btm_cb.devcb.brcm_features);
+}
+
+/*******************************************************************************
+**
+** Function BTM_RegisterForDeviceStatusNotif
+**
+** Description This function is called to register for device status
+** change notifications.
+**
+** If one registration is already there calling function should
+** save the pointer to the function that is return and
+** call it when processing of the event is complete
+**
+** Returns status of the operation
+**
+*******************************************************************************/
+tBTM_DEV_STATUS_CB *BTM_RegisterForDeviceStatusNotif (tBTM_DEV_STATUS_CB *p_cb)
+{
+ tBTM_DEV_STATUS_CB *p_prev = btm_cb.devcb.p_dev_status_cb;
+
+ btm_cb.devcb.p_dev_status_cb = p_cb;
+ return (p_prev);
+}
+
+/*******************************************************************************
+**
+** Function BTM_VendorSpecificCommand
+**
+** Description Send a vendor specific HCI command to the controller.
+**
+** Returns
+** BTM_SUCCESS Command sent. Does not expect command complete
+** event. (command cmpl callback param is NULL)
+** BTM_CMD_STARTED Command sent. Waiting for command cmpl event.
+**
+** Notes
+** Opcode will be OR'd with HCI_GRP_VENDOR_SPECIFIC.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_VendorSpecificCommand(UINT16 opcode, UINT8 param_len,
+ UINT8 *p_param_buf, tBTM_VSC_CMPL_CB *p_cb)
+{
+ void *p_buf;
+
+ BTM_TRACE_EVENT2 ("BTM: BTM_VendorSpecificCommand: Opcode: 0x%04X, ParamLen: %i.",
+ opcode, param_len);
+
+ /* Allocate a buffer to hold HCI command plus the callback function */
+ if ((p_buf = GKI_getbuf((UINT16)(sizeof(BT_HDR) + sizeof (tBTM_CMPL_CB *) +
+ param_len + HCIC_PREAMBLE_SIZE))) != NULL)
+ {
+ /* Send the HCI command (opcode will be OR'd with HCI_GRP_VENDOR_SPECIFIC) */
+ btsnd_hcic_vendor_spec_cmd (p_buf, opcode, param_len, p_param_buf, (void *)p_cb);
+
+ /* Return value */
+ if (p_cb != NULL)
+ return (BTM_CMD_STARTED);
+ else
+ return (BTM_SUCCESS);
+ }
+ else
+ return (BTM_NO_RESOURCES);
+
+}
+
+
+/*******************************************************************************
+**
+** Function btm_vsc_complete
+**
+** Description This function is called when local HCI Vendor Specific
+** Command complete message is received from the HCI.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_vsc_complete (UINT8 *p, UINT16 opcode, UINT16 evt_len,
+ tBTM_CMPL_CB *p_vsc_cplt_cback)
+{
+ tBTM_VSC_CMPL vcs_cplt_params;
+
+ /* If there was a callback address for vcs complete, call it */
+ if (p_vsc_cplt_cback)
+ {
+ /* Pass paramters to the callback function */
+ vcs_cplt_params.opcode = opcode; /* Number of bytes in return info */
+ vcs_cplt_params.param_len = evt_len; /* Number of bytes in return info */
+ vcs_cplt_params.p_param_buf = p;
+ (*p_vsc_cplt_cback)(&vcs_cplt_params); /* Call the VSC complete callback function */
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTM_RegisterForVSEvents
+**
+** Description This function is called to register/deregister for vendor
+** specific HCI events.
+**
+** If is_register=TRUE, then the function will be registered;
+** if is_register=FALSE, then the function will be deregistered.
+**
+** Returns BTM_SUCCESS if successful,
+** BTM_BUSY if maximum number of callbacks have already been
+** registered.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_RegisterForVSEvents (tBTM_VS_EVT_CB *p_cb, BOOLEAN is_register)
+{
+ tBTM_STATUS retval = BTM_SUCCESS;
+ UINT8 i, free_idx = BTM_MAX_VSE_CALLBACKS;
+
+ /* See if callback is already registered */
+ for (i=0; i<BTM_MAX_VSE_CALLBACKS; i++)
+ {
+ if (btm_cb.devcb.p_vend_spec_cb[i] == NULL)
+ {
+ /* Found a free slot. Store index */
+ free_idx = i;
+ }
+ else if (btm_cb.devcb.p_vend_spec_cb[i] == p_cb)
+ {
+ /* Found callback in lookup table. If deregistering, clear the entry. */
+ if (is_register == FALSE)
+ {
+ btm_cb.devcb.p_vend_spec_cb[i] = NULL;
+ BTM_TRACE_EVENT0("BTM Deregister For VSEvents is successfully");
+ }
+ return (BTM_SUCCESS);
+ }
+ }
+
+ /* Didn't find callback. Add callback to free slot if registering */
+ if (is_register)
+ {
+ if (free_idx < BTM_MAX_VSE_CALLBACKS)
+ {
+ btm_cb.devcb.p_vend_spec_cb[free_idx] = p_cb;
+ BTM_TRACE_EVENT0("BTM Register For VSEvents is successfully");
+ }
+ else
+ {
+ /* No free entries available */
+ BTM_TRACE_ERROR0 ("BTM_RegisterForVSEvents: too many callbacks registered");
+
+ retval = BTM_NO_RESOURCES;
+ }
+ }
+
+ return (retval);
+}
+
+/*******************************************************************************
+**
+** Function btm_vendor_specific_evt
+**
+** Description Process event HCI_VENDOR_SPECIFIC_EVT
+**
+** Note: Some controllers do not send command complete, so
+** the callback and busy flag are cleared here also.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_vendor_specific_evt (UINT8 *p, UINT8 evt_len)
+{
+ UINT8 i;
+
+ BTM_TRACE_DEBUG0 ("BTM Event: Vendor Specific event from controller");
+
+ for (i=0; i<BTM_MAX_VSE_CALLBACKS; i++)
+ {
+ if (btm_cb.devcb.p_vend_spec_cb[i])
+ (*btm_cb.devcb.p_vend_spec_cb[i])(evt_len, p);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_WritePageTimeout
+**
+** Description Send HCI Write Page Timeout.
+**
+** Returns
+** BTM_SUCCESS Command sent.
+** BTM_NO_RESOURCES If out of resources to send the command.
+**
+**
+*******************************************************************************/
+tBTM_STATUS BTM_WritePageTimeout(UINT16 timeout)
+{
+ BTM_TRACE_EVENT1 ("BTM: BTM_WritePageTimeout: Timeout: %d.", timeout);
+
+ /* Send the HCI command */
+ if (btsnd_hcic_write_page_tout (timeout))
+ return (BTM_SUCCESS);
+ else
+ return (BTM_NO_RESOURCES);
+}
+
+/*******************************************************************************
+**
+** Function BTM_WriteVoiceSettings
+**
+** Description Send HCI Write Voice Settings command.
+** See hcidefs.h for settings bitmask values.
+**
+** Returns
+** BTM_SUCCESS Command sent.
+** BTM_NO_RESOURCES If out of resources to send the command.
+**
+**
+*******************************************************************************/
+tBTM_STATUS BTM_WriteVoiceSettings(UINT16 settings)
+{
+ BTM_TRACE_EVENT1 ("BTM: BTM_WriteVoiceSettings: Settings: 0x%04x.", settings);
+
+ /* Send the HCI command */
+ if (btsnd_hcic_write_voice_settings ((UINT16)(settings & 0x03ff)))
+ return (BTM_SUCCESS);
+
+ return (BTM_NO_RESOURCES);
+}
+
+/*******************************************************************************
+**
+** Function BTM_EnableTestMode
+**
+** Description Send HCI the enable device under test command.
+**
+** Note: Controller can only be taken out of this mode by
+** resetting the controller.
+**
+** Returns
+** BTM_SUCCESS Command sent.
+** BTM_NO_RESOURCES If out of resources to send the command.
+**
+**
+*******************************************************************************/
+tBTM_STATUS BTM_EnableTestMode(void)
+{
+ UINT8 cond;
+
+ BTM_TRACE_EVENT0 ("BTM: BTM_EnableTestMode");
+
+ /* set auto accept connection as this is needed during test mode */
+ /* Allocate a buffer to hold HCI command */
+ cond = HCI_DO_AUTO_ACCEPT_CONNECT;
+ if (!btsnd_hcic_set_event_filter(HCI_FILTER_CONNECTION_SETUP,
+ HCI_FILTER_COND_NEW_DEVICE,
+ &cond, sizeof(cond)))
+ {
+ return (BTM_NO_RESOURCES);
+ }
+
+ /* put device to connectable mode */
+ if (!BTM_SetConnectability(BTM_CONNECTABLE, BTM_DEFAULT_CONN_WINDOW,
+ BTM_DEFAULT_CONN_INTERVAL) == BTM_SUCCESS)
+ {
+ return BTM_NO_RESOURCES;
+ }
+
+ /* put device to discoverable mode */
+ if (!BTM_SetDiscoverability(BTM_GENERAL_DISCOVERABLE, BTM_DEFAULT_DISC_WINDOW,
+ BTM_DEFAULT_DISC_INTERVAL) == BTM_SUCCESS)
+ {
+ return BTM_NO_RESOURCES;
+ }
+
+ /* mask off all of event from controller */
+ if (!btsnd_hcic_set_event_mask(LOCAL_BR_EDR_CONTROLLER_ID,
+ (UINT8 *)"\x00\x00\x00\x00\x00\x00\x00\x00"))
+ {
+ return BTM_NO_RESOURCES;
+ }
+
+ /* Send the HCI command */
+ if (btsnd_hcic_enable_test_mode ())
+ return (BTM_SUCCESS);
+ else
+ return (BTM_NO_RESOURCES);
+}
+
+/*******************************************************************************
+**
+** Function btm_get_hci_version
+**
+** Description Local function called to retrieve the current HCI version
+**
+** Returns Bluetooth HCI Version returned by the controller
+**
+*******************************************************************************/
+UINT8 btm_get_hci_version (void)
+{
+ return (btm_cb.devcb.local_version.hci_version);
+}
+
+
+
+/*******************************************************************************
+**
+** Function BTM_ReadStoredLinkKey
+**
+** Description This function is called to obtain link key for the specified
+** device from the NVRAM storage attached to the Bluetooth
+** controller.
+**
+** Parameters: bd_addr - Address of the device
+** p_cb - Call back function to be called to return
+** the results
+**
+*******************************************************************************/
+tBTM_STATUS BTM_ReadStoredLinkKey (BD_ADDR bd_addr, tBTM_CMPL_CB *p_cb)
+{
+ BD_ADDR local_bd_addr;
+ BOOLEAN read_all_flag = FALSE;
+
+ /* Check if the previous command is completed */
+ if (btm_cb.devcb.p_stored_link_key_cmpl_cb)
+ return (BTM_BUSY);
+
+ if (!bd_addr)
+ {
+ /* This is to read all the link keys */
+ read_all_flag = TRUE;
+
+ /* We don't care the BD address. Just pass a non zero pointer */
+ bd_addr = local_bd_addr;
+ }
+
+ BTM_TRACE_EVENT1 ("BTM: BTM_ReadStoredLinkKey: Read_All: %s",
+ read_all_flag ? "TRUE" : "FALSE");
+
+ /* Send the HCI command */
+ btm_cb.devcb.p_stored_link_key_cmpl_cb = p_cb;
+ if (btsnd_hcic_read_stored_key (bd_addr, read_all_flag))
+ return (BTM_SUCCESS);
+ else
+ return (BTM_NO_RESOURCES);
+
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_WriteStoredLinkKey
+**
+** Description This function is called to write link keys for the specified
+** device addresses to the NVRAM storage attached to the Bluetooth
+** controller.
+**
+** Parameters: num_keys - Number of link keys
+** bd_addr - Addresses of the devices
+** link_key - Link Keys to be stored
+** p_cb - Call back function to be called to return
+** the results
+**
+*******************************************************************************/
+tBTM_STATUS BTM_WriteStoredLinkKey (UINT8 num_keys,
+ BD_ADDR *bd_addr,
+ LINK_KEY *link_key,
+ tBTM_CMPL_CB *p_cb)
+{
+ /* Check if the previous command is completed */
+ if (btm_cb.devcb.p_stored_link_key_cmpl_cb)
+ return (BTM_BUSY);
+
+ BTM_TRACE_EVENT1 ("BTM: BTM_WriteStoredLinkKey: num_keys: %d", num_keys);
+
+ /* Check the maximum number of link keys */
+ if(num_keys > HCI_MAX_NUM_OF_LINK_KEYS_PER_CMMD)
+ num_keys = HCI_MAX_NUM_OF_LINK_KEYS_PER_CMMD;
+
+ /* Send the HCI command */
+ btm_cb.devcb.p_stored_link_key_cmpl_cb = p_cb;
+ if (btsnd_hcic_write_stored_key (num_keys, bd_addr, link_key))
+ return (BTM_SUCCESS);
+ else
+ return (BTM_NO_RESOURCES);
+
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_DeleteStoredLinkKey
+**
+** Description This function is called to delete link key for the specified
+** device addresses from the NVRAM storage attached to the Bluetooth
+** controller.
+**
+** Parameters: bd_addr - Addresses of the devices
+** p_cb - Call back function to be called to return
+** the results
+**
+*******************************************************************************/
+tBTM_STATUS BTM_DeleteStoredLinkKey(BD_ADDR bd_addr, tBTM_CMPL_CB *p_cb)
+{
+ BD_ADDR local_bd_addr;
+ BOOLEAN delete_all_flag = FALSE;
+
+ /* Check if the previous command is completed */
+ if (btm_cb.devcb.p_stored_link_key_cmpl_cb)
+ return (BTM_BUSY);
+
+ if (!bd_addr)
+ {
+ /* This is to delete all link keys */
+ delete_all_flag = TRUE;
+
+ /* We don't care the BD address. Just pass a non zero pointer */
+ bd_addr = local_bd_addr;
+ }
+
+ BTM_TRACE_EVENT1 ("BTM: BTM_DeleteStoredLinkKey: delete_all_flag: %s",
+ delete_all_flag ? "TRUE" : "FALSE");
+
+ /* Send the HCI command */
+ btm_cb.devcb.p_stored_link_key_cmpl_cb = p_cb;
+ if (!btsnd_hcic_delete_stored_key (bd_addr, delete_all_flag))
+ {
+ return (BTM_NO_RESOURCES);
+ }
+ else
+ return (BTM_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function btm_read_stored_link_key_complete
+**
+** Description This function is called when the command complete message
+** is received from the HCI for the read stored link key command.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_read_stored_link_key_complete (UINT8 *p)
+{
+ tBTM_CMPL_CB *p_cb = btm_cb.devcb.p_stored_link_key_cmpl_cb;
+ tBTM_READ_STORED_LINK_KEY_COMPLETE result;
+
+ /* If there was a callback registered for read stored link key, call it */
+ btm_cb.devcb.p_stored_link_key_cmpl_cb = NULL;
+
+ if (p_cb)
+ {
+ /* Set the call back event to indicate command complete */
+ result.event = BTM_CB_EVT_READ_STORED_LINK_KEYS;
+
+ /* Extract the result fields from the HCI event if status is success */
+ STREAM_TO_UINT8 (result.status, p);
+ if (result.status == HCI_SUCCESS)
+ {
+ STREAM_TO_UINT16 (result.max_keys, p);
+ STREAM_TO_UINT16 (result.read_keys, p);
+ }
+ else
+ {
+ BTM_TRACE_WARNING1("Read stored link key status %d", result.status);
+ result.max_keys = 0;
+ result.read_keys = 0;
+ }
+ /* Call the call back and pass the result */
+ (*p_cb)(&result);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function btm_write_stored_link_key_complete
+**
+** Description This function is called when the command complete message
+** is received from the HCI for the write stored link key command.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_write_stored_link_key_complete (UINT8 *p)
+{
+ tBTM_CMPL_CB *p_cb = btm_cb.devcb.p_stored_link_key_cmpl_cb;
+ tBTM_WRITE_STORED_LINK_KEY_COMPLETE result;
+
+ /* If there was a callback registered for read stored link key, call it */
+ btm_cb.devcb.p_stored_link_key_cmpl_cb = NULL;
+
+ if (p_cb)
+ {
+ /* Set the call back event to indicate command complete */
+ result.event = BTM_CB_EVT_WRITE_STORED_LINK_KEYS;
+
+ /* Extract the result fields from the HCI event */
+ STREAM_TO_UINT8 (result.status, p);
+ STREAM_TO_UINT8 (result.num_keys, p);
+
+ /* Call the call back and pass the result */
+ (*p_cb)(&result);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function btm_delete_stored_link_key_complete
+**
+** Description This function is called when the command complete message
+** is received from the HCI for the delete stored link key command.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_delete_stored_link_key_complete (UINT8 *p)
+{
+ tBTM_CMPL_CB *p_cb = btm_cb.devcb.p_stored_link_key_cmpl_cb;
+ tBTM_DELETE_STORED_LINK_KEY_COMPLETE result;
+
+ /* If there was a callback registered for read stored link key, call it */
+ btm_cb.devcb.p_stored_link_key_cmpl_cb = NULL;
+
+ if (p_cb)
+ {
+ /* Set the call back event to indicate command complete */
+ result.event = BTM_CB_EVT_DELETE_STORED_LINK_KEYS;
+
+ /* Extract the result fields from the HCI event */
+ STREAM_TO_UINT8 (result.status, p);
+ STREAM_TO_UINT16 (result.num_keys, p);
+
+ /* Call the call back and pass the result */
+ (*p_cb)(&result);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function btm_return_link_keys_evt
+**
+** Description This function is called when the return link keys event
+** is received from the HCI for the read stored link key command.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_return_link_keys_evt (tBTM_RETURN_LINK_KEYS_EVT *result)
+{
+ tBTM_CMPL_CB *p_cb = btm_cb.devcb.p_stored_link_key_cmpl_cb;
+ UINT8 i, *p, *p1;
+ UINT8 bd_addr[BD_ADDR_LEN];
+ UINT8 link_key[LINK_KEY_LEN];
+
+ /* Call the call back to pass the link keys to application */
+ if (p_cb)
+ {
+ /* Change the BD addr and Link key in to big endian order */
+ p = (UINT8 *)(result + 1);
+ for (i=0; i<result->num_keys; i++)
+ {
+ /* Initialize the backup pointer */
+ p1 = p;
+
+ /* Extract the BD Addr and Link Key */
+ REVERSE_STREAM_TO_ARRAY(bd_addr, p1, BD_ADDR_LEN);
+ REVERSE_STREAM_TO_ARRAY(link_key, p1, LINK_KEY_LEN);
+
+ /* Write the BD Addr and Link Key back in big endian format */
+ ARRAY_TO_STREAM(p, bd_addr, BD_ADDR_LEN);
+ ARRAY_TO_STREAM(p, link_key, LINK_KEY_LEN);
+ }
+
+ (*p_cb)(result);
+ }
+}
+
+
+
+/*******************************************************************************
+**
+** Function btm_report_device_status
+**
+** Description This function is called when there is a change in the device
+** status. This function will report the new device status to
+** the application
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_report_device_status (tBTM_DEV_STATUS status)
+{
+ tBTM_DEV_STATUS_CB *p_cb = btm_cb.devcb.p_dev_status_cb;
+
+ /* Call the call back to pass the device status to application */
+ if (p_cb)
+ (*p_cb)(status);
+}
+
+
diff --git a/stack/btm/btm_inq.c b/stack/btm/btm_inq.c
new file mode 100644
index 0000000..f42cdc1
--- /dev/null
+++ b/stack/btm/btm_inq.c
@@ -0,0 +1,3233 @@
+/*****************************************************************************
+**
+** Name: btm_inq.c
+**
+** Description: This file contains functions that handle inquiries. These
+** include setting discoverable mode, controlling the mode
+** of the Baseband, and maintaining a small database of
+** inquiry responses, with API for people to browse it.
+**
+** NOTE: Only ONE inquiry is allowed to run at a time
+** (including periodic inquiries);
+**
+**
+** Copyright (c) 1999-2012, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stddef.h>
+
+#include "bt_types.h"
+#include "gki.h"
+#include "hcimsgs.h"
+#include "btu.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "hcidefs.h"
+
+#define BTM_INQ_REPLY_TIMEOUT 3 /* 3 second timeout waiting for responses */
+
+/* TRUE to enable DEBUG traces for btm_inq */
+#ifndef BTM_INQ_DEBUG
+#define BTM_INQ_DEBUG FALSE
+#endif
+/********************************************************************************/
+/* L O C A L D A T A D E F I N I T I O N S */
+/********************************************************************************/
+static const LAP general_inq_lap = {0x9e,0x8b,0x33};
+static const LAP limited_inq_lap = {0x9e,0x8b,0x00};
+
+#if (( BTM_EIR_CLIENT_INCLUDED == TRUE )||( BTM_EIR_SERVER_INCLUDED == TRUE ))
+#ifndef BTM_EIR_UUID_LKUP_TBL
+const UINT16 BTM_EIR_UUID_LKUP_TBL[BTM_EIR_MAX_SERVICES] =
+{
+ UUID_SERVCLASS_SERVICE_DISCOVERY_SERVER,
+/* UUID_SERVCLASS_BROWSE_GROUP_DESCRIPTOR, */
+/* UUID_SERVCLASS_PUBLIC_BROWSE_GROUP, */
+ UUID_SERVCLASS_SERIAL_PORT,
+ UUID_SERVCLASS_LAN_ACCESS_USING_PPP,
+ UUID_SERVCLASS_DIALUP_NETWORKING,
+ UUID_SERVCLASS_IRMC_SYNC,
+ UUID_SERVCLASS_OBEX_OBJECT_PUSH,
+ UUID_SERVCLASS_OBEX_FILE_TRANSFER,
+ UUID_SERVCLASS_IRMC_SYNC_COMMAND,
+ UUID_SERVCLASS_HEADSET,
+ UUID_SERVCLASS_CORDLESS_TELEPHONY,
+ UUID_SERVCLASS_AUDIO_SOURCE,
+ UUID_SERVCLASS_AUDIO_SINK,
+ UUID_SERVCLASS_AV_REM_CTRL_TARGET,
+/* UUID_SERVCLASS_ADV_AUDIO_DISTRIBUTION, */
+ UUID_SERVCLASS_AV_REMOTE_CONTROL,
+/* UUID_SERVCLASS_VIDEO_CONFERENCING, */
+ UUID_SERVCLASS_INTERCOM,
+ UUID_SERVCLASS_FAX,
+ UUID_SERVCLASS_HEADSET_AUDIO_GATEWAY,
+/* UUID_SERVCLASS_WAP, */
+/* UUID_SERVCLASS_WAP_CLIENT, */
+ UUID_SERVCLASS_PANU,
+ UUID_SERVCLASS_NAP,
+ UUID_SERVCLASS_GN,
+ UUID_SERVCLASS_DIRECT_PRINTING,
+/* UUID_SERVCLASS_REFERENCE_PRINTING, */
+ UUID_SERVCLASS_IMAGING,
+ UUID_SERVCLASS_IMAGING_RESPONDER,
+ UUID_SERVCLASS_IMAGING_AUTO_ARCHIVE,
+ UUID_SERVCLASS_IMAGING_REF_OBJECTS,
+ UUID_SERVCLASS_HF_HANDSFREE,
+ UUID_SERVCLASS_AG_HANDSFREE,
+ UUID_SERVCLASS_DIR_PRT_REF_OBJ_SERVICE,
+/* UUID_SERVCLASS_REFLECTED_UI, */
+ UUID_SERVCLASS_BASIC_PRINTING,
+ UUID_SERVCLASS_PRINTING_STATUS,
+ UUID_SERVCLASS_HUMAN_INTERFACE,
+ UUID_SERVCLASS_CABLE_REPLACEMENT,
+ UUID_SERVCLASS_HCRP_PRINT,
+ UUID_SERVCLASS_HCRP_SCAN,
+/* UUID_SERVCLASS_COMMON_ISDN_ACCESS, */
+/* UUID_SERVCLASS_VIDEO_CONFERENCING_GW, */
+/* UUID_SERVCLASS_UDI_MT, */
+/* UUID_SERVCLASS_UDI_TA, */
+/* UUID_SERVCLASS_VCP, */
+ UUID_SERVCLASS_SAP,
+ UUID_SERVCLASS_PBAP_PCE,
+ UUID_SERVCLASS_PBAP_PSE,
+ UUID_SERVCLASS_PHONE_ACCESS,
+ UUID_SERVCLASS_HEADSET_HS,
+ UUID_SERVCLASS_PNP_INFORMATION,
+/* UUID_SERVCLASS_GENERIC_NETWORKING, */
+/* UUID_SERVCLASS_GENERIC_FILETRANSFER, */
+/* UUID_SERVCLASS_GENERIC_AUDIO, */
+/* UUID_SERVCLASS_GENERIC_TELEPHONY, */
+/* UUID_SERVCLASS_UPNP_SERVICE, */
+/* UUID_SERVCLASS_UPNP_IP_SERVICE, */
+/* UUID_SERVCLASS_ESDP_UPNP_IP_PAN, */
+/* UUID_SERVCLASS_ESDP_UPNP_IP_LAP, */
+/* UUID_SERVCLASS_ESDP_UPNP_IP_L2CAP, */
+ UUID_SERVCLASS_VIDEO_SOURCE,
+ UUID_SERVCLASS_VIDEO_SINK,
+/* UUID_SERVCLASS_VIDEO_DISTRIBUTION */
+ UUID_SERVCLASS_MESSAGE_ACCESS,
+ UUID_SERVCLASS_MESSAGE_NOTIFICATION,
+ UUID_SERVCLASS_HDP_SOURCE,
+ UUID_SERVCLASS_HDP_SINK
+};
+#else
+/*
+If customized UUID look-up table needs to be used,
+the followings should be defined in buildcfg.h.
+BTM_EIR_UUID_LKUP_TBL = <customized UUID list>
+BTM_EIR_MAX_SERVICES = <number of UUID in list>
+*/
+#if (BTM_EIR_MAX_SERVICES == 0)
+const UINT16 BTM_EIR_UUID_LKUP_TBL[];
+#else
+extern UINT16 BTM_EIR_UUID_LKUP_TBL[BTM_EIR_MAX_SERVICES];
+#endif
+#endif
+#endif /* BTM_EIR_UUID_LKUP_TBL*/
+
+/********************************************************************************/
+/* L O C A L F U N C T I O N P R O T O T Y P E S */
+/********************************************************************************/
+static void btm_initiate_inquiry (tBTM_INQUIRY_VAR_ST *p_inq);
+static tBTM_STATUS btm_set_inq_event_filter (UINT8 filter_cond_type, tBTM_INQ_FILT_COND *p_filt_cond);
+static void btm_clr_inq_result_flt (void);
+
+#if ((BTM_EIR_SERVER_INCLUDED == TRUE)||(BTM_EIR_CLIENT_INCLUDED == TRUE))
+static UINT8 btm_convert_uuid_to_eir_service( UINT16 uuid16 );
+#endif
+#if (BTM_EIR_CLIENT_INCLUDED == TRUE)
+static void btm_set_eir_uuid( UINT8 *p_eir, tBTM_INQ_RESULTS *p_results );
+static UINT8 *btm_eir_get_uuid_list( UINT8 *p_eir, UINT8 uuid_size,
+ UINT8 *p_num_uuid, UINT8 *p_uuid_list_type );
+static UINT16 btm_convert_uuid_to_uuid16( UINT8 *p_uuid, UINT8 uuid_size );
+#endif
+
+/*******************************************************************************
+**
+** Function BTM_SetDiscoverability
+**
+** Description This function is called to set the device into or out of
+** discoverable mode. Discoverable mode means inquiry
+** scans are enabled. If a value of '0' is entered for window or
+** interval, the default values are used.
+**
+** Returns BTM_SUCCESS if successful
+** BTM_BUSY if a setting of the filter is already in progress
+** BTM_NO_RESOURCES if couldn't get a memory pool buffer
+** BTM_ILLEGAL_VALUE if a bad parameter was detected
+** BTM_WRONG_MODE if the device is not up.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetDiscoverability (UINT16 inq_mode, UINT16 window, UINT16 interval)
+{
+ UINT8 scan_mode = 0;
+ UINT16 service_class;
+ UINT8 *p_cod;
+ UINT8 major, minor;
+ DEV_CLASS cod;
+ LAP temp_lap[2];
+ BOOLEAN is_limited;
+ BOOLEAN cod_limited;
+
+ BTM_TRACE_API0 ("BTM_SetDiscoverability");
+#if (BLE_INCLUDED == TRUE && BLE_INCLUDED == TRUE)
+ if (btm_ble_set_discoverability((UINT16)(inq_mode))
+ == BTM_SUCCESS)
+ {
+ btm_cb.btm_inq_vars.discoverable_mode &= (~BTM_BLE_DISCOVERABLE_MASK);
+ btm_cb.btm_inq_vars.discoverable_mode |= (inq_mode & BTM_BLE_CONNECTABLE_MASK);
+ }
+ inq_mode &= ~BTM_BLE_DISCOVERABLE_MASK;
+#endif
+
+ /*** Check mode parameter ***/
+ if (inq_mode > BTM_MAX_DISCOVERABLE)
+ return (BTM_ILLEGAL_VALUE);
+
+ /* Make sure the controller is active */
+ if (btm_cb.devcb.state < BTM_DEV_STATE_READY)
+ return (BTM_DEV_RESET);
+
+ /* If the window and/or interval is '0', set to default values */
+ if (!window)
+ window = BTM_DEFAULT_DISC_WINDOW;
+
+ if (!interval)
+ interval = BTM_DEFAULT_DISC_INTERVAL;
+
+ BTM_TRACE_API3 ("BTM_SetDiscoverability: mode %d [NonDisc-0, Lim-1, Gen-2], window 0x%04x, interval 0x%04x",
+ inq_mode, window, interval);
+
+ /*** Check for valid window and interval parameters ***/
+ /*** Only check window and duration if mode is connectable ***/
+ if (inq_mode != BTM_NON_DISCOVERABLE)
+ {
+ /* window must be less than or equal to interval */
+ if (window < HCI_MIN_INQUIRYSCAN_WINDOW ||
+ window > HCI_MAX_INQUIRYSCAN_WINDOW ||
+ interval < HCI_MIN_INQUIRYSCAN_INTERVAL ||
+ interval > HCI_MAX_INQUIRYSCAN_INTERVAL ||
+ window > interval)
+ {
+ return (BTM_ILLEGAL_VALUE);
+ }
+ }
+
+ /* Set the IAC if needed */
+ if (inq_mode != BTM_NON_DISCOVERABLE)
+ {
+ if (inq_mode & BTM_LIMITED_DISCOVERABLE)
+ {
+ /* Use the GIAC and LIAC codes for limited discoverable mode */
+ memcpy (temp_lap[0], limited_inq_lap, LAP_LEN);
+ memcpy (temp_lap[1], general_inq_lap, LAP_LEN);
+
+ if (!btsnd_hcic_write_cur_iac_lap (2, (LAP * const) temp_lap))
+ return (BTM_NO_RESOURCES); /* Cannot continue */
+ }
+ else
+ {
+ if (!btsnd_hcic_write_cur_iac_lap (1, (LAP * const) &general_inq_lap))
+ return (BTM_NO_RESOURCES); /* Cannot continue */
+ }
+
+ scan_mode |= HCI_INQUIRY_SCAN_ENABLED;
+ }
+
+ /* Send down the inquiry scan window and period if changed */
+ if ((window != btm_cb.btm_inq_vars.inq_scan_window) ||
+ (interval != btm_cb.btm_inq_vars.inq_scan_period))
+ {
+ if (btsnd_hcic_write_inqscan_cfg (interval, window))
+ {
+ btm_cb.btm_inq_vars.inq_scan_window = window;
+ btm_cb.btm_inq_vars.inq_scan_period = interval;
+ }
+ else
+ return (BTM_NO_RESOURCES);
+ }
+
+ if (btm_cb.btm_inq_vars.connectable_mode & BTM_CONNECTABLE_MASK)
+ scan_mode |= HCI_PAGE_SCAN_ENABLED;
+
+ if (btsnd_hcic_write_scan_enable (scan_mode))
+ {
+ btm_cb.btm_inq_vars.discoverable_mode &= (~BTM_DISCOVERABLE_MASK);
+ btm_cb.btm_inq_vars.discoverable_mode |= inq_mode;
+ }
+ else
+ return (BTM_NO_RESOURCES);
+
+ /* Change the service class bit if mode has changed */
+ p_cod = BTM_ReadDeviceClass();
+ BTM_COD_SERVICE_CLASS(service_class, p_cod);
+ is_limited = (inq_mode & BTM_LIMITED_DISCOVERABLE) ? TRUE : FALSE;
+ cod_limited = (service_class & BTM_COD_SERVICE_LMTD_DISCOVER) ? TRUE : FALSE;
+ if (is_limited ^ cod_limited)
+ {
+ BTM_COD_MINOR_CLASS(minor, p_cod );
+ BTM_COD_MAJOR_CLASS(major, p_cod );
+ if (is_limited)
+ service_class |= BTM_COD_SERVICE_LMTD_DISCOVER;
+ else
+ service_class &= ~BTM_COD_SERVICE_LMTD_DISCOVER;
+
+ FIELDS_TO_COD(cod, minor, major, service_class);
+ (void) BTM_SetDeviceClass (cod);
+ }
+
+ return (BTM_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function BTM_SetInquiryScanType
+**
+** Description This function is called to set the iquiry scan-type to
+** standard or interlaced.
+**
+** Returns BTM_SUCCESS if successful
+** BTM_MODE_UNSUPPORTED if not a 1.2 device
+** BTM_WRONG_MODE if the device is not up.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetInquiryScanType (UINT16 scan_type)
+{
+
+ BTM_TRACE_API0 ("BTM_SetInquiryScanType");
+ if (scan_type != BTM_SCAN_TYPE_STANDARD && scan_type != BTM_SCAN_TYPE_INTERLACED)
+ return (BTM_ILLEGAL_VALUE);
+
+ /* whatever app wants if device is not 1.2 scan type should be STANDARD */
+ if (!HCI_LMP_INTERLACED_INQ_SCAN_SUPPORTED(btm_cb.devcb.local_features))
+ return (BTM_MODE_UNSUPPORTED);
+
+ /* Check for scan type if configuration has been changed */
+ if (scan_type != btm_cb.btm_inq_vars.inq_scan_type)
+ {
+ if (BTM_IsDeviceUp())
+ {
+ if (btsnd_hcic_write_inqscan_type ((UINT8)scan_type))
+ btm_cb.btm_inq_vars.inq_scan_type = scan_type;
+ else
+ return (BTM_NO_RESOURCES);
+ }
+ else return (BTM_WRONG_MODE);
+ }
+ return (BTM_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function BTM_SetPageScanType
+**
+** Description This function is called to set the page scan-type to
+** standard or interlaced.
+**
+** Returns BTM_SUCCESS if successful
+** BTM_MODE_UNSUPPORTED if not a 1.2 device
+** BTM_WRONG_MODE if the device is not up.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetPageScanType (UINT16 scan_type)
+{
+ BTM_TRACE_API0 ("BTM_SetPageScanType");
+ if (scan_type != BTM_SCAN_TYPE_STANDARD && scan_type != BTM_SCAN_TYPE_INTERLACED)
+ return (BTM_ILLEGAL_VALUE);
+
+ /* whatever app wants if device is not 1.2 scan type should be STANDARD */
+ if (!HCI_LMP_INTERLACED_PAGE_SCAN_SUPPORTED(btm_cb.devcb.local_features))
+ return (BTM_MODE_UNSUPPORTED);
+
+ /* Check for scan type if configuration has been changed */
+ if (scan_type != btm_cb.btm_inq_vars.page_scan_type)
+ {
+ if (BTM_IsDeviceUp())
+ {
+ if (btsnd_hcic_write_pagescan_type ((UINT8)scan_type))
+ btm_cb.btm_inq_vars.page_scan_type = scan_type;
+ else
+ return (BTM_NO_RESOURCES);
+ }
+ else return (BTM_WRONG_MODE);
+ }
+ return (BTM_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_SetInquiryMode
+**
+** Description This function is called to set standard or with RSSI
+** mode of the inquiry for local device.
+**
+** Output Params: mode - standard, with RSSI, extended
+**
+** Returns BTM_SUCCESS if successful
+** BTM_NO_RESOURCES if couldn't get a memory pool buffer
+** BTM_ILLEGAL_VALUE if a bad parameter was detected
+** BTM_WRONG_MODE if the device is not up.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetInquiryMode (UINT8 mode)
+{
+ BTM_TRACE_API0 ("BTM_SetInquiryMode");
+ if (mode == BTM_INQ_RESULT_STANDARD)
+ {
+ /* mandatory mode */
+ }
+ else if (mode == BTM_INQ_RESULT_WITH_RSSI)
+ {
+ if (!HCI_LMP_INQ_RSSI_SUPPORTED(btm_cb.devcb.local_features))
+ return (BTM_MODE_UNSUPPORTED);
+ }
+#if (( BTM_EIR_CLIENT_INCLUDED == TRUE )||( BTM_EIR_SERVER_INCLUDED == TRUE ))
+ else if (mode == BTM_INQ_RESULT_EXTENDED)
+ {
+ if (!HCI_EXT_INQ_RSP_SUPPORTED(btm_cb.devcb.local_features))
+ return (BTM_MODE_UNSUPPORTED);
+ }
+#endif
+ else
+ return (BTM_ILLEGAL_VALUE);
+
+ if (!BTM_IsDeviceUp())
+ return (BTM_WRONG_MODE);
+
+ if (!btsnd_hcic_write_inquiry_mode (mode))
+ return (BTM_NO_RESOURCES);
+
+ return (BTM_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function BTM_ReadDiscoverability
+**
+** Description This function is called to read the current discoverability
+** mode of the device.
+**
+** Output Params: p_window - current inquiry scan duration
+** p_interval - current inquiry scan interval
+**
+** Returns BTM_NON_DISCOVERABLE, BTM_LIMITED_DISCOVERABLE, or
+** BTM_GENERAL_DISCOVERABLE
+**
+*******************************************************************************/
+UINT16 BTM_ReadDiscoverability (UINT16 *p_window, UINT16 *p_interval)
+{
+ BTM_TRACE_API0 ("BTM_ReadDiscoverability");
+ if (p_window)
+ *p_window = btm_cb.btm_inq_vars.inq_scan_window;
+
+ if (p_interval)
+ *p_interval = btm_cb.btm_inq_vars.inq_scan_period;
+
+ return (btm_cb.btm_inq_vars.discoverable_mode);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_SetPeriodicInquiryMode
+**
+** Description This function is called to set the device periodic inquiry mode.
+** If the duration is zero, the periodic inquiry mode is cancelled.
+**
+** Note: We currently do not allow concurrent inquiry and periodic inquiry.
+**
+** Parameters: p_inqparms - pointer to the inquiry information
+** mode - GENERAL or LIMITED inquiry
+** duration - length in 1.28 sec intervals (If '0', the inquiry is CANCELLED)
+** max_resps - maximum amount of devices to search for before ending the inquiry
+** filter_cond_type - BTM_CLR_INQUIRY_FILTER, BTM_FILTER_COND_DEVICE_CLASS, or
+** BTM_FILTER_COND_BD_ADDR
+** filter_cond - value for the filter (based on filter_cond_type)
+**
+** max_delay - maximum amount of time between successive inquiries
+** min_delay - minimum amount of time between successive inquiries
+** p_results_cb - callback returning pointer to results (tBTM_INQ_RESULTS)
+**
+** Returns BTM_CMD_STARTED if successfully started
+** BTM_ILLEGAL_VALUE if a bad parameter is detected
+** BTM_NO_RESOURCES if could not allocate a message buffer
+** BTM_SUCCESS - if cancelling the periodic inquiry
+** BTM_BUSY - if an inquiry is already active
+** BTM_WRONG_MODE if the device is not up.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetPeriodicInquiryMode (tBTM_INQ_PARMS *p_inqparms, UINT16 max_delay,
+ UINT16 min_delay, tBTM_INQ_RESULTS_CB *p_results_cb)
+{
+ tBTM_STATUS status;
+ tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+
+ BTM_TRACE_API6 ("BTM_SetPeriodicInquiryMode: mode: %d, dur: %d, rsps: %d, flt: %d, min: %d, max: %d",
+ p_inqparms->mode, p_inqparms->duration, p_inqparms->max_resps,
+ p_inqparms->filter_cond_type, min_delay, max_delay);
+
+ /*** Make sure the device is ready ***/
+ if (!BTM_IsDeviceUp())
+ return (BTM_WRONG_MODE);
+
+ /* Only one active inquiry is allowed in this implementation.
+ Also do not allow an inquiry if the inquiry filter is being updated */
+ if (p_inq->inq_active || p_inq->inqfilt_active)
+ return (BTM_BUSY);
+
+ /* If illegal parameters return FALSE */
+ if (p_inqparms->mode != BTM_GENERAL_INQUIRY &&
+ p_inqparms->mode != BTM_LIMITED_INQUIRY)
+ return (BTM_ILLEGAL_VALUE);
+
+ /* Verify the parameters for this command */
+ if (p_inqparms->duration < BTM_MIN_INQUIRY_LEN ||
+ p_inqparms->duration > BTM_MAX_INQUIRY_LENGTH ||
+ min_delay <= p_inqparms->duration ||
+ min_delay < BTM_PER_INQ_MIN_MIN_PERIOD ||
+ min_delay > BTM_PER_INQ_MAX_MIN_PERIOD ||
+ max_delay <= min_delay ||
+ max_delay < BTM_PER_INQ_MIN_MAX_PERIOD ||
+ max_delay > BTM_PER_INQ_MAX_MAX_PERIOD)
+ {
+ return (BTM_ILLEGAL_VALUE);
+ }
+
+ /* Save the inquiry parameters to be used upon the completion of setting/clearing the inquiry filter */
+ p_inq->inqparms = *p_inqparms;
+ p_inq->per_min_delay = min_delay;
+ p_inq->per_max_delay = max_delay;
+ p_inq->inq_cmpl_info.num_resp = 0; /* Clear the results counter */
+ p_inq->p_inq_results_cb = p_results_cb;
+
+ p_inq->inq_active = (UINT8)((p_inqparms->mode == BTM_LIMITED_INQUIRY) ?
+ (BTM_LIMITED_INQUIRY_ACTIVE | BTM_PERIODIC_INQUIRY_ACTIVE) :
+ (BTM_GENERAL_INQUIRY_ACTIVE | BTM_PERIODIC_INQUIRY_ACTIVE));
+
+#if (defined(BTM_BYPASS_EVENT_FILTERING) && BTM_BYPASS_EVENT_FILTERING == TRUE)
+ BTM_TRACE_WARNING0("BTM: Bypassing event filtering...");
+
+ p_inq->state = BTM_INQ_ACTIVE_STATE;
+ p_inq->inqfilt_active = FALSE;
+ btm_initiate_inquiry (p_inq);
+ status = BTM_CMD_STARTED;
+#else
+ /* If a filter is specified, then save it for later and clear the current filter.
+ The setting of the filter is done upon completion of clearing of the previous
+ filter.
+ */
+ if (p_inqparms->filter_cond_type != BTM_CLR_INQUIRY_FILTER)
+ {
+ p_inq->state = BTM_INQ_CLR_FILT_STATE;
+ p_inqparms->filter_cond_type = BTM_CLR_INQUIRY_FILTER;
+ }
+ else /* The filter is not being used so simply clear it; the inquiry can start after this operation */
+ p_inq->state = BTM_INQ_SET_FILT_STATE;
+
+ /* Before beginning the inquiry the current filter must be cleared, so initiate the command */
+ if ((status = btm_set_inq_event_filter (p_inqparms->filter_cond_type, &p_inqparms->filter_cond)) != BTM_CMD_STARTED)
+ {
+ /* If set filter command is not succesful reset the state */
+ p_inq->p_inq_results_cb = NULL;
+ p_inq->state = BTM_INQ_INACTIVE_STATE;
+
+ }
+
+#endif
+ return (status);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_CancelPeriodicInquiry
+**
+** Description This function cancels a periodic inquiry
+**
+** Returns
+** BTM_NO_RESOURCES if could not allocate a message buffer
+** BTM_SUCCESS - if cancelling the periodic inquiry
+** BTM_WRONG_MODE if the device is not up.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_CancelPeriodicInquiry(void)
+{
+ tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+ tBTM_STATUS status = BTM_SUCCESS;
+ BTM_TRACE_API0 ("BTM_CancelPeriodicInquiry called");
+
+ /*** Make sure the device is ready ***/
+ if (!BTM_IsDeviceUp())
+ return (BTM_WRONG_MODE);
+
+ /* Only cancel if one is active */
+ if (btm_cb.btm_inq_vars.inq_active & BTM_PERIODIC_INQUIRY_ACTIVE)
+ {
+ btm_cb.btm_inq_vars.inq_active = BTM_INQUIRY_INACTIVE;
+ btm_cb.btm_inq_vars.p_inq_results_cb = (tBTM_INQ_RESULTS_CB *) NULL;
+
+ if (!btsnd_hcic_exit_per_inq ())
+ status = BTM_NO_RESOURCES;
+
+ /* If the event filter is in progress, mark it so that the processing of the return
+ event will be ignored */
+ if(p_inq->inqfilt_active)
+ p_inq->pending_filt_complete_event++;
+
+ p_inq->inqfilt_active = FALSE;
+ p_inq->inq_counter++;
+ }
+
+ return (status);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_SetConnectability
+**
+** Description This function is called to set the device into or out of
+** connectable mode. Discoverable mode means page scans enabled.
+**
+** Returns BTM_SUCCESS if successful
+** BTM_ILLEGAL_VALUE if a bad parameter is detected
+** BTM_NO_RESOURCES if could not allocate a message buffer
+** BTM_WRONG_MODE if the device is not up.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetConnectability (UINT16 page_mode, UINT16 window, UINT16 interval)
+{
+ UINT8 scan_mode = 0;
+ tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+
+ BTM_TRACE_API0 ("BTM_SetConnectability");
+
+#if (BLE_INCLUDED == TRUE && BLE_INCLUDED == TRUE)
+ if (btm_ble_set_connectability(page_mode) == BTM_SUCCESS)
+ {
+ p_inq->connectable_mode &= (~BTM_BLE_CONNECTABLE_MASK);
+ p_inq->connectable_mode |= (page_mode & BTM_BLE_CONNECTABLE_MASK);
+ }
+ page_mode &= ~BTM_BLE_CONNECTABLE_MASK;
+
+#endif
+
+ /*** Check mode parameter ***/
+ if (page_mode != BTM_NON_CONNECTABLE && page_mode != BTM_CONNECTABLE)
+ return (BTM_ILLEGAL_VALUE);
+
+ /* Make sure the controller is active */
+ if (btm_cb.devcb.state < BTM_DEV_STATE_READY)
+ return (BTM_DEV_RESET);
+
+ /* If the window and/or interval is '0', set to default values */
+ if (!window)
+ window = BTM_DEFAULT_CONN_WINDOW;
+
+ if (!interval)
+ interval = BTM_DEFAULT_CONN_INTERVAL;
+
+ BTM_TRACE_API3 ("BTM_SetConnectability: mode %d [NonConn-0, Conn-1], window 0x%04x, interval 0x%04x",
+ page_mode, window, interval);
+
+ /*** Check for valid window and interval parameters ***/
+ /*** Only check window and duration if mode is connectable ***/
+ if (page_mode == BTM_CONNECTABLE)
+ {
+ /* window must be less than or equal to interval */
+ if (window < HCI_MIN_PAGESCAN_WINDOW ||
+ window > HCI_MAX_PAGESCAN_WINDOW ||
+ interval < HCI_MIN_PAGESCAN_INTERVAL ||
+ interval > HCI_MAX_PAGESCAN_INTERVAL ||
+ window > interval)
+ {
+ return (BTM_ILLEGAL_VALUE);
+ }
+
+ scan_mode |= HCI_PAGE_SCAN_ENABLED;
+ }
+
+ if ((window != p_inq->page_scan_window) ||
+ (interval != p_inq->page_scan_period))
+ {
+ p_inq->page_scan_window = window;
+ p_inq->page_scan_period = interval;
+ if (!btsnd_hcic_write_pagescan_cfg (interval, window))
+ return (BTM_NO_RESOURCES);
+ }
+
+ /* Keep the inquiry scan as previouosly set */
+ if (p_inq->discoverable_mode & BTM_DISCOVERABLE_MASK)
+ scan_mode |= HCI_INQUIRY_SCAN_ENABLED;
+
+ if (btsnd_hcic_write_scan_enable (scan_mode))
+ {
+ p_inq->connectable_mode &= (~BTM_CONNECTABLE_MASK);
+ p_inq->connectable_mode |= page_mode;
+
+ return (BTM_SUCCESS);
+ }
+
+ return (BTM_NO_RESOURCES);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_ReadConnectability
+**
+** Description This function is called to read the current discoverability
+** mode of the device.
+** Output Params p_window - current page scan duration
+** p_interval - current time between page scans
+**
+** Returns BTM_NON_CONNECTABLE or BTM_CONNECTABLE
+**
+*******************************************************************************/
+UINT16 BTM_ReadConnectability (UINT16 *p_window, UINT16 *p_interval)
+{
+ BTM_TRACE_API0 ("BTM_ReadConnectability");
+ if (p_window)
+ *p_window = btm_cb.btm_inq_vars.page_scan_window;
+
+ if (p_interval)
+ *p_interval = btm_cb.btm_inq_vars.page_scan_period;
+
+ return (btm_cb.btm_inq_vars.connectable_mode);
+}
+
+
+
+/*******************************************************************************
+**
+** Function BTM_IsInquiryActive
+**
+** Description This function returns a bit mask of the current inquiry state
+**
+** Returns BTM_INQUIRY_INACTIVE if inactive (0)
+** BTM_LIMITED_INQUIRY_ACTIVE if a limted inquiry is active
+** BTM_GENERAL_INQUIRY_ACTIVE if a general inquiry is active
+** BTM_PERIODIC_INQUIRY_ACTIVE if a periodic inquiry is active
+**
+*******************************************************************************/
+UINT16 BTM_IsInquiryActive (void)
+{
+ BTM_TRACE_API0 ("BTM_IsInquiryActive");
+
+ return(btm_cb.btm_inq_vars.inq_active);
+}
+
+
+
+/*******************************************************************************
+**
+** Function BTM_CancelInquiry
+**
+** Description This function cancels an inquiry if active
+**
+** Returns BTM_SUCCESS if successful
+** BTM_NO_RESOURCES if could not allocate a message buffer
+** BTM_WRONG_MODE if the device is not up.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_CancelInquiry(void)
+{
+ tBTM_STATUS status = BTM_SUCCESS;
+ tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+
+ BTM_TRACE_API0 ("BTM_CancelInquiry called");
+
+ /*** Make sure the device is ready ***/
+ if (!BTM_IsDeviceUp())
+ return (BTM_WRONG_MODE);
+
+ /* Only cancel if not in periodic mode, otherwise the caller should call BTM_CancelPeriodicMode */
+ if (p_inq->inq_active &&
+ (!(p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE)))
+ {
+ p_inq->inq_active = BTM_INQUIRY_INACTIVE;
+ p_inq->state = BTM_INQ_INACTIVE_STATE;
+ p_inq->p_inq_results_cb = (tBTM_INQ_RESULTS_CB *) NULL; /* Do not notify caller anymore */
+ p_inq->p_inq_cmpl_cb = (tBTM_CMPL_CB *) NULL; /* Do not notify caller anymore */
+
+ /* If the event filter is in progress, mark it so that the processing of the return
+ event will be ignored */
+ if (p_inq->inqfilt_active)
+ {
+ p_inq->inqfilt_active = FALSE;
+ p_inq->pending_filt_complete_event++;
+ }
+ /* Initiate the cancel inquiry */
+ else
+ {
+ if (!btsnd_hcic_inq_cancel())
+ status = BTM_NO_RESOURCES;
+#if BLE_INCLUDED == TRUE
+ if ((p_inq->inqparms.mode & BTM_BLE_INQUIRY_MASK) != 0)
+ btm_ble_stop_scan();
+#endif
+ }
+
+#if (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE)
+ btm_acl_update_busy_level (BTM_BLI_INQ_DONE_EVT);
+#endif
+
+ p_inq->inq_counter++;
+ btm_clr_inq_result_flt();
+ }
+
+ return (status);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_StartInquiry
+**
+** Description This function is called to start an inquiry.
+**
+** Parameters: p_inqparms - pointer to the inquiry information
+** mode - GENERAL or LIMITED inquiry
+** duration - length in 1.28 sec intervals (If '0', the inquiry is CANCELLED)
+** max_resps - maximum amount of devices to search for before ending the inquiry
+** filter_cond_type - BTM_CLR_INQUIRY_FILTER, BTM_FILTER_COND_DEVICE_CLASS, or
+** BTM_FILTER_COND_BD_ADDR
+** filter_cond - value for the filter (based on filter_cond_type)
+**
+** p_results_cb - Pointer to the callback routine which gets called
+** upon receipt of an inquiry result. If this field is
+** NULL, the application is not notified.
+**
+** p_cmpl_cb - Pointer to the callback routine which gets called
+** upon completion. If this field is NULL, the
+** application is not notified when completed.
+** Returns tBTM_STATUS
+** BTM_CMD_STARTED if successfully initiated
+** BTM_BUSY if already in progress
+** BTM_ILLEGAL_VALUE if parameter(s) are out of range
+** BTM_NO_RESOURCES if could not allocate resources to start the command
+** BTM_WRONG_MODE if the device is not up.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_StartInquiry (tBTM_INQ_PARMS *p_inqparms, tBTM_INQ_RESULTS_CB *p_results_cb,
+ tBTM_CMPL_CB *p_cmpl_cb)
+{
+ tBTM_STATUS status;
+ tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+
+ BTM_TRACE_API4 ("BTM_StartInquiry: mode: %d, dur: %d, rsps: %d, flt: %d",
+ p_inqparms->mode, p_inqparms->duration, p_inqparms->max_resps,
+ p_inqparms->filter_cond_type);
+
+ /* Only one active inquiry is allowed in this implementation.
+ Also do not allow an inquiry if the inquiry filter is being updated */
+ if (p_inq->inq_active || p_inq->inqfilt_active)
+ return (BTM_BUSY);
+
+ /*** Make sure the device is ready ***/
+ if (!BTM_IsDeviceUp())
+ return (BTM_WRONG_MODE);
+
+ if ((p_inqparms->mode & BTM_BR_INQUIRY_MASK)!= BTM_GENERAL_INQUIRY &&
+ (p_inqparms->mode & BTM_BR_INQUIRY_MASK)!= BTM_LIMITED_INQUIRY)
+ return (BTM_ILLEGAL_VALUE);
+
+ /* Save the inquiry parameters to be used upon the completion of setting/clearing the inquiry filter */
+ p_inq->inqparms = *p_inqparms;
+#if (BLE_INCLUDED == TRUE)
+ p_inq->inqparms.mode = (UINT8)(p_inq->inqparms.mode & BTM_BLE_INQUIRY_MASK) | (UINT8)(1 << (p_inqparms->mode & BTM_BR_INQUIRY_MASK));
+#else
+ p_inq->inqparms.mode = (UINT8)(1 << (p_inqparms->mode & BTM_BR_INQUIRY_MASK));
+#endif
+
+ /* Initialize the inquiry variables */
+ p_inq->state = BTM_INQ_ACTIVE_STATE;
+ p_inq->p_inq_cmpl_cb = p_cmpl_cb;
+ p_inq->p_inq_results_cb = p_results_cb;
+ p_inq->inq_cmpl_info.num_resp = 0; /* Clear the results counter */
+ p_inq->inq_active = (UINT8)(1 << (p_inqparms->mode & BTM_BR_INQUIRY_MASK));
+
+ BTM_TRACE_DEBUG1("BTM_StartInquiry: p_inq->inq_active = 0x%02x", p_inq->inq_active);
+
+/* start LE inquiry here if requested */
+#if BLE_INCLUDED == TRUE
+ if (p_inqparms->mode & BTM_BLE_INQUIRY_MASK)
+ {
+ /* BLE for now does not support filter condition for inquiry */
+ if (btm_ble_start_inquiry((UINT8)(p_inqparms->mode & BTM_BLE_INQUIRY_MASK),
+ p_inq->inqparms.duration) != BTM_SUCCESS)
+ {
+ BTM_TRACE_ERROR0("Err Starting LE Inquiry.");
+ p_inq->inqparms.mode &= ~ BTM_BLE_INQUIRY_MASK;
+ }
+
+ p_inqparms->mode &= ~BTM_BLE_INQUIRY_MASK;
+
+ BTM_TRACE_DEBUG1("BTM_StartInquiry: mode = %02x", p_inqparms->mode);
+ }
+#endif /* end of BLE_INCLUDED */
+
+#if (defined(BTM_BYPASS_EVENT_FILTERING) && BTM_BYPASS_EVENT_FILTERING == TRUE)
+ BTM_TRACE_WARNING0("BTM: Bypassing event filtering...");
+ p_inq->inqfilt_active = FALSE;
+ btm_initiate_inquiry (p_inq);
+ status = BTM_CMD_STARTED;
+#else
+ /* If a filter is specified, then save it for later and clear the current filter.
+ The setting of the filter is done upon completion of clearing of the previous
+ filter.
+ */
+ switch (p_inqparms->filter_cond_type)
+ {
+ case BTM_CLR_INQUIRY_FILTER:
+ p_inq->state = BTM_INQ_SET_FILT_STATE;
+ break;
+
+ case BTM_FILTER_COND_DEVICE_CLASS:
+ case BTM_FILTER_COND_BD_ADDR:
+ /* The filter is not being used so simply clear it;
+ the inquiry can start after this operation */
+ p_inq->state = BTM_INQ_CLR_FILT_STATE;
+ p_inqparms->filter_cond_type = BTM_CLR_INQUIRY_FILTER;
+ /* =============>>>> adding LE filtering here ????? */
+ break;
+
+ default:
+ return (BTM_ILLEGAL_VALUE);
+ }
+
+ /* Before beginning the inquiry the current filter must be cleared, so initiate the command */
+ if ((status = btm_set_inq_event_filter (p_inqparms->filter_cond_type, &p_inqparms->filter_cond)) != BTM_CMD_STARTED)
+ p_inq->state = BTM_INQ_INACTIVE_STATE;
+#endif
+ return (status);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_ReadRemoteDeviceName
+**
+** Description This function initiates a remote device HCI command to the
+** controller and calls the callback when the process has completed.
+**
+** Input Params: remote_bda - device address of name to retrieve
+** p_cb - callback function called when BTM_CMD_STARTED
+** is returned.
+** A pointer to tBTM_REMOTE_DEV_NAME is passed to the
+** callback.
+**
+** Returns
+** BTM_CMD_STARTED is returned if the request was successfully sent
+** to HCI.
+** BTM_BUSY if already in progress
+** BTM_UNKNOWN_ADDR if device address is bad
+** BTM_NO_RESOURCES if could not allocate resources to start the command
+** BTM_WRONG_MODE if the device is not up.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_ReadRemoteDeviceName (BD_ADDR remote_bda, tBTM_CMPL_CB *p_cb)
+{
+ tBTM_INQ_INFO *p_cur = NULL;
+ tINQ_DB_ENT *p_i;
+
+#if BLE_INCLUDED == TRUE
+ tBT_DEVICE_TYPE dev_type;
+ tBLE_ADDR_TYPE addr_type;
+#endif
+
+ BTM_TRACE_API6 ("BTM_ReadRemoteDeviceName: bd addr [%02x%02x%02x%02x%02x%02x]",
+ remote_bda[0], remote_bda[1], remote_bda[2],
+ remote_bda[3], remote_bda[4], remote_bda[5]);
+
+ /* Use the remote device's clock offset if it is in the local inquiry database */
+ if ((p_i = btm_inq_db_find (remote_bda)) != NULL)
+ {
+ p_cur = &p_i->inq_info;
+
+#if (BTM_INQ_GET_REMOTE_NAME == TRUE)
+ p_cur->remote_name_state = BTM_INQ_RMT_NAME_EMPTY;
+#endif
+ }
+ BTM_TRACE_API0 ("no device found in inquiry db");
+
+#if (BLE_INCLUDED == TRUE)
+ BTM_ReadDevInfo(remote_bda, &dev_type, &addr_type);
+ if (dev_type == BT_DEVICE_TYPE_BLE)
+ {
+ return btm_ble_read_remote_name(remote_bda, p_cur, p_cb);
+ }
+ else
+#endif
+
+ return (btm_initiate_rem_name (remote_bda, p_cur, BTM_RMT_NAME_EXT,
+ BTM_EXT_RMT_NAME_TIMEOUT, p_cb));
+}
+
+/*******************************************************************************
+**
+** Function BTM_CancelRemoteDeviceName
+**
+** Description This function initiates the cancel request for the specified
+** remote device.
+**
+** Input Params: None
+**
+** Returns
+** BTM_CMD_STARTED is returned if the request was successfully sent
+** to HCI.
+** BTM_NO_RESOURCES if could not allocate resources to start the command
+** BTM_WRONG_MODE if there is not an active remote name request.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_CancelRemoteDeviceName (void)
+{
+ tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+
+#if BLE_INCLUDED == TRUE
+ tBT_DEVICE_TYPE dev_type;
+ tBLE_ADDR_TYPE addr_type;
+#endif
+
+ BTM_TRACE_API0 ("BTM_CancelRemoteDeviceName()");
+
+ /* Make sure there is not already one in progress */
+ if (p_inq->remname_active)
+ {
+#if BLE_INCLUDED == TRUE
+ BTM_ReadDevInfo(p_inq->remname_bda, &dev_type, &addr_type);
+ if (dev_type == BT_DEVICE_TYPE_BLE)
+ {
+ if (btm_ble_cancel_remote_name(p_inq->remname_bda))
+ return (BTM_CMD_STARTED);
+ else
+ return (BTM_UNKNOWN_ADDR);
+ }
+ else
+#endif
+ if (btsnd_hcic_rmt_name_req_cancel (p_inq->remname_bda))
+ return (BTM_CMD_STARTED);
+ else
+ return (BTM_NO_RESOURCES);
+ }
+ else
+ return (BTM_WRONG_MODE);
+}
+
+/*******************************************************************************
+**
+** Function BTM_InqFirstResult
+**
+** Description This function looks through the inquiry database for the first
+** used entrysince the LAST inquiry. This is used in conjunction
+** with BTM_InqNext by applications as a way to walk through the
+** inquiry results database.
+**
+** Returns pointer to first in-use entry, or NULL if DB is empty
+**
+*******************************************************************************/
+tBTM_INQ_INFO *BTM_InqFirstResult (void)
+{
+ UINT16 xx;
+ tINQ_DB_ENT *p_ent = btm_cb.btm_inq_vars.inq_db;
+ UINT32 cur_inq_count = btm_cb.btm_inq_vars.inq_counter - 1;
+
+ for (xx = 0; xx < BTM_INQ_DB_SIZE; xx++, p_ent++)
+ {
+ if (p_ent->in_use && p_ent->inq_count == cur_inq_count)
+ return (&p_ent->inq_info);
+ }
+
+ /* If here, no used entry found */
+ return ((tBTM_INQ_INFO *)NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_InqNextResult
+**
+** Description This function looks through the inquiry database for the next
+** used entrysince the LAST inquiry. If the input parameter is NULL,
+** the first entry is returned.
+**
+** Returns pointer to next in-use entry, or NULL if no more found.
+**
+*******************************************************************************/
+tBTM_INQ_INFO *BTM_InqNextResult (tBTM_INQ_INFO *p_cur)
+{
+ tINQ_DB_ENT *p_ent;
+ UINT16 inx;
+ UINT32 cur_inq_count = btm_cb.btm_inq_vars.inq_counter - 1;
+
+ if (p_cur)
+ {
+ p_ent = (tINQ_DB_ENT *) ((UINT8 *)p_cur - offsetof (tINQ_DB_ENT, inq_info));
+ inx = (UINT16)((p_ent - btm_cb.btm_inq_vars.inq_db) + 1);
+
+ for (p_ent = &btm_cb.btm_inq_vars.inq_db[inx]; inx < BTM_INQ_DB_SIZE; inx++, p_ent++)
+ {
+ if (p_ent->in_use && p_ent->inq_count == cur_inq_count)
+ return (&p_ent->inq_info);
+ }
+
+ /* If here, more entries found */
+ return ((tBTM_INQ_INFO *)NULL);
+ }
+ else
+ return (BTM_InqDbFirst());
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_InqDbRead
+**
+** Description This function looks through the inquiry database for a match
+** based on Bluetooth Device Address. This is the application's
+** interface to get the inquiry details of a specific BD address.
+**
+** Returns pointer to entry, or NULL if not found
+**
+*******************************************************************************/
+tBTM_INQ_INFO *BTM_InqDbRead (BD_ADDR p_bda)
+{
+ UINT16 xx;
+ tINQ_DB_ENT *p_ent = btm_cb.btm_inq_vars.inq_db;
+
+ BTM_TRACE_API6 ("BTM_InqDbRead: bd addr [%02x%02x%02x%02x%02x%02x]",
+ p_bda[0], p_bda[1], p_bda[2], p_bda[3], p_bda[4], p_bda[5]);
+
+ for (xx = 0; xx < BTM_INQ_DB_SIZE; xx++, p_ent++)
+ {
+ if ((p_ent->in_use) && (!memcmp (p_ent->inq_info.results.remote_bd_addr, p_bda, BD_ADDR_LEN)))
+ return (&p_ent->inq_info);
+ }
+
+ /* If here, not found */
+ return ((tBTM_INQ_INFO *)NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_InqDbFirst
+**
+** Description This function looks through the inquiry database for the first
+** used entry, and returns that. This is used in conjunction with
+** BTM_InqDbNext by applications as a way to walk through the
+** inquiry database.
+**
+** Returns pointer to first in-use entry, or NULL if DB is empty
+**
+*******************************************************************************/
+tBTM_INQ_INFO *BTM_InqDbFirst (void)
+{
+ UINT16 xx;
+ tINQ_DB_ENT *p_ent = btm_cb.btm_inq_vars.inq_db;
+
+ for (xx = 0; xx < BTM_INQ_DB_SIZE; xx++, p_ent++)
+ {
+ if (p_ent->in_use)
+ return (&p_ent->inq_info);
+ }
+
+ /* If here, no used entry found */
+ return ((tBTM_INQ_INFO *)NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_InqDbNext
+**
+** Description This function looks through the inquiry database for the next
+** used entry, and returns that. If the input parameter is NULL,
+** the first entry is returned.
+**
+** Returns pointer to next in-use entry, or NULL if no more found.
+**
+*******************************************************************************/
+tBTM_INQ_INFO *BTM_InqDbNext (tBTM_INQ_INFO *p_cur)
+{
+ tINQ_DB_ENT *p_ent;
+ UINT16 inx;
+
+ if (p_cur)
+ {
+ p_ent = (tINQ_DB_ENT *) ((UINT8 *)p_cur - offsetof (tINQ_DB_ENT, inq_info));
+ inx = (UINT16)((p_ent - btm_cb.btm_inq_vars.inq_db) + 1);
+
+ for (p_ent = &btm_cb.btm_inq_vars.inq_db[inx]; inx < BTM_INQ_DB_SIZE; inx++, p_ent++)
+ {
+ if (p_ent->in_use)
+ return (&p_ent->inq_info);
+ }
+
+ /* If here, more entries found */
+ return ((tBTM_INQ_INFO *)NULL);
+ }
+ else
+ return (BTM_InqDbFirst());
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_ClearInqDb
+**
+** Description This function is called to clear out a device or all devices
+** from the inquiry database.
+**
+** Parameter p_bda - (input) BD_ADDR -> Address of device to clear
+** (NULL clears all entries)
+**
+** Returns BTM_BUSY if an inquiry, get remote name, or event filter
+** is active, otherwise BTM_SUCCESS
+**
+*******************************************************************************/
+tBTM_STATUS BTM_ClearInqDb (BD_ADDR p_bda)
+{
+ tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+
+ /* If an inquiry or remote name is in progress return busy */
+ if (p_inq->inq_active != BTM_INQUIRY_INACTIVE ||
+ p_inq->inqfilt_active)
+ return (BTM_BUSY);
+
+ btm_clr_inq_db(p_bda);
+
+ return (BTM_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_ReadNumInqDbEntries
+**
+** Returns This function returns the number of entries in the inquiry database.
+**
+*******************************************************************************/
+UINT8 BTM_ReadNumInqDbEntries (void)
+{
+ UINT8 num_entries;
+ UINT8 num_results;
+ tINQ_DB_ENT *p_ent = btm_cb.btm_inq_vars.inq_db;
+
+ for (num_entries = 0, num_results = 0; num_entries < BTM_INQ_DB_SIZE; num_entries++, p_ent++)
+ {
+ if (p_ent->in_use)
+ num_results++;
+ }
+
+ return (num_results);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_InquiryRegisterForChanges
+**
+** Returns This function is called to register a callback for when the
+** inquiry database changes, i.e. new entry or entry deleted.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_InquiryRegisterForChanges (tBTM_INQ_DB_CHANGE_CB *p_cb)
+{
+ if (!p_cb)
+ btm_cb.btm_inq_vars.p_inq_change_cb = NULL;
+ else if (btm_cb.btm_inq_vars.p_inq_change_cb)
+ return (BTM_BUSY);
+ else
+ btm_cb.btm_inq_vars.p_inq_change_cb = p_cb;
+
+ return (BTM_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_SetInquiryFilterCallback
+**
+** Description Host can register to be asked whenever an inquiry result
+** is received. If host does not like the device no name
+** request is issued for the device
+**
+** Returns void
+**
+*******************************************************************************/
+void BTM_SetInquiryFilterCallback (tBTM_FILTER_CB *p_callback)
+{
+ btm_cb.p_inq_filter_cb = p_callback;
+}
+
+/*******************************************************************************
+**
+** Function BTM_ReadInquiryRspTxPower
+**
+** Description This command will read the inquiry Transmit Power level used
+** to transmit the FHS and EIR data packets.
+** This can be used directly in the Tx Power Level EIR data type.
+**
+** Returns BTM_SUCCESS if successful
+**
+*******************************************************************************/
+tBTM_STATUS BTM_ReadInquiryRspTxPower (tBTM_CMPL_CB *p_cb)
+{
+ if (btm_cb.devcb.p_txpwer_cmpl_cb)
+ return (BTM_BUSY);
+
+ btu_start_timer (&btm_cb.devcb.txpwer_timer, BTU_TTYPE_BTM_ACL, BTM_INQ_REPLY_TIMEOUT );
+
+
+ btm_cb.devcb.p_txpwer_cmpl_cb = p_cb;
+
+ if (!btsnd_hcic_read_inq_tx_power ())
+ {
+ btm_cb.devcb.p_txpwer_cmpl_cb = NULL;
+ btu_stop_timer (&btm_cb.devcb.txpwer_timer);
+ return (BTM_NO_RESOURCES);
+ }
+ else
+ return (BTM_CMD_STARTED);
+}
+/*******************************************************************************
+**
+** Function BTM_WriteInquiryTxPower
+**
+** Description This command is used to write the inquiry transmit power level
+** used to transmit the inquiry (ID) data packets. The Controller
+** should use the supported TX power level closest to the Tx_Power
+** parameter.
+**
+** Returns BTM_SUCCESS if successful
+**
+*******************************************************************************/
+tBTM_STATUS BTM_WriteInquiryTxPower (INT8 tx_power)
+{
+ tBTM_STATUS status = BTM_SUCCESS;
+
+ if (tx_power < BTM_MIN_INQ_TX_POWER || tx_power > BTM_MAX_INQ_TX_POWER)
+ {
+ status = BTM_ILLEGAL_VALUE;
+ }
+ else if (!btsnd_hcic_write_inq_tx_power(tx_power))
+ status = BTM_NO_RESOURCES;
+
+ return status;
+}
+/*********************************************************************************
+**********************************************************************************
+** **
+** BTM Internal Inquiry Functions **
+** **
+**********************************************************************************
+*********************************************************************************/
+/*******************************************************************************
+**
+** Function btm_inq_db_reset
+**
+** Description This function is called at at reset to clear the inquiry
+** database & pending callback.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_inq_db_reset (void)
+{
+ tBTM_REMOTE_DEV_NAME rem_name;
+ tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+ UINT8 num_responses;
+ UINT8 temp_inq_active;
+ tBTM_STATUS status;
+
+ btu_stop_timer (&p_inq->inq_timer_ent);
+
+ /* If an inquiry or periodic inquiry is active, reset the mode to inactive */
+ if (p_inq->inq_active != BTM_INQUIRY_INACTIVE)
+ {
+ temp_inq_active = p_inq->inq_active; /* Save so state can change BEFORE
+ callback is called */
+ p_inq->inq_active = BTM_INQUIRY_INACTIVE;
+
+ /* If not a periodic inquiry, the complete callback must be called to notify caller */
+ if (temp_inq_active == BTM_LIMITED_INQUIRY_ACTIVE ||
+ temp_inq_active == BTM_GENERAL_INQUIRY_ACTIVE)
+ {
+ if (p_inq->p_inq_cmpl_cb)
+ {
+ num_responses = 0;
+ (*p_inq->p_inq_cmpl_cb)(&num_responses);
+ }
+ }
+ }
+
+ /* Cancel a remote name request if active, and notify the caller (if waiting) */
+ if (p_inq->remname_active )
+ {
+ btu_stop_timer (&p_inq->rmt_name_timer_ent);
+ p_inq->remname_active = FALSE;
+ memset(p_inq->remname_bda, 0, BD_ADDR_LEN);
+
+ if (p_inq->p_remname_cmpl_cb)
+ {
+ rem_name.status = BTM_DEV_RESET;
+
+ (*p_inq->p_remname_cmpl_cb)(&rem_name);
+ p_inq->p_remname_cmpl_cb = NULL;
+ }
+ }
+
+ /* Cancel an inquiry filter request if active, and notify the caller (if waiting) */
+ if (p_inq->inqfilt_active)
+ {
+ p_inq->inqfilt_active = FALSE;
+
+ if (p_inq->p_inqfilter_cmpl_cb)
+ {
+ status = BTM_DEV_RESET;
+ (*p_inq->p_inqfilter_cmpl_cb)(&status);
+ }
+ }
+
+ p_inq->state = BTM_INQ_INACTIVE_STATE;
+ p_inq->pending_filt_complete_event = 0;
+ p_inq->p_inq_results_cb = NULL;
+ btm_clr_inq_db(NULL); /* Clear out all the entries in the database */
+ btm_clr_inq_result_flt();
+
+ p_inq->discoverable_mode = BTM_NON_DISCOVERABLE;
+ p_inq->connectable_mode = BTM_NON_CONNECTABLE;
+ p_inq->page_scan_type = BTM_SCAN_TYPE_STANDARD;
+ p_inq->inq_scan_type = BTM_SCAN_TYPE_STANDARD;
+
+#if BLE_INCLUDED == TRUE
+ p_inq->discoverable_mode |= BTM_BLE_NON_DISCOVERABLE;
+ p_inq->connectable_mode |= BTM_BLE_NON_CONNECTABLE;
+#endif
+ return;
+}
+
+
+/*********************************************************************************
+**
+** Function btm_inq_db_init
+**
+** Description This function is called at startup to initialize the inquiry
+** database.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_inq_db_init (void)
+{
+#if 0 /* cleared in btm_init; put back in if called from anywhere else! */
+ memset (&btm_cb.btm_inq_vars, 0, sizeof (tBTM_INQUIRY_VAR_ST));
+#endif
+ btm_cb.btm_inq_vars.no_inc_ssp = BTM_NO_SSP_ON_INQUIRY;
+}
+
+/*********************************************************************************
+**
+** Function btm_inq_stop_on_ssp
+**
+** Description This function is called on incoming SSP
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_inq_stop_on_ssp(void)
+{
+ UINT8 normal_active = (BTM_GENERAL_INQUIRY_ACTIVE|BTM_LIMITED_INQUIRY_ACTIVE);
+
+#if (BTM_INQ_DEBUG == TRUE)
+ BTM_TRACE_DEBUG4 ("btm_inq_stop_on_ssp: no_inc_ssp=%d inq_active:0x%x state:%d inqfilt_active:%d",
+ btm_cb.btm_inq_vars.no_inc_ssp, btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state, btm_cb.btm_inq_vars.inqfilt_active);
+#endif
+ if (btm_cb.btm_inq_vars.no_inc_ssp)
+ {
+ if (btm_cb.btm_inq_vars.state == BTM_INQ_ACTIVE_STATE)
+ {
+ if (btm_cb.btm_inq_vars.inq_active & BTM_PERIODIC_INQUIRY_ACTIVE)
+ {
+ BTM_CancelPeriodicInquiry();
+ }
+ else if (btm_cb.btm_inq_vars.inq_active & normal_active)
+ {
+ /* can not call BTM_CancelInquiry() here. We need to report inquiry complete evt */
+ btsnd_hcic_inq_cancel();
+ }
+ }
+ /* do not allow inquiry to start */
+ btm_cb.btm_inq_vars.inq_active |= BTM_SSP_INQUIRY_ACTIVE;
+ }
+}
+
+/*********************************************************************************
+**
+** Function btm_inq_clear_ssp
+**
+** Description This function is called when pairing_state becomes idle
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_inq_clear_ssp(void)
+{
+ btm_cb.btm_inq_vars.inq_active &= ~BTM_SSP_INQUIRY_ACTIVE;
+}
+
+/*********************************************************************************
+**
+** Function btm_clr_inq_db
+**
+** Description This function is called to clear out a device or all devices
+** from the inquiry database.
+**
+** Parameter p_bda - (input) BD_ADDR -> Address of device to clear
+** (NULL clears all entries)
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_clr_inq_db (BD_ADDR p_bda)
+{
+ tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+ tINQ_DB_ENT *p_ent = p_inq->inq_db;
+ UINT16 xx;
+
+#if (BTM_INQ_DEBUG == TRUE)
+ BTM_TRACE_DEBUG2 ("btm_clr_inq_db: inq_active:0x%x state:%d",
+ btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state);
+#endif
+ for (xx = 0; xx < BTM_INQ_DB_SIZE; xx++, p_ent++)
+ {
+ if (p_ent->in_use)
+ {
+ /* If this is the specified BD_ADDR or clearing all devices */
+ if (p_bda == NULL ||
+ (!memcmp (p_ent->inq_info.results.remote_bd_addr, p_bda, BD_ADDR_LEN)))
+ {
+ p_ent->in_use = FALSE;
+#if (BTM_INQ_GET_REMOTE_NAME == TRUE)
+ p_ent->inq_info.remote_name_state = BTM_INQ_RMT_NAME_EMPTY;
+#endif
+
+ if (btm_cb.btm_inq_vars.p_inq_change_cb)
+ (*btm_cb.btm_inq_vars.p_inq_change_cb) (&p_ent->inq_info, FALSE);
+ }
+ }
+ }
+#if (BTM_INQ_DEBUG == TRUE)
+ BTM_TRACE_DEBUG2 ("inq_active:0x%x state:%d",
+ btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state);
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function btm_clr_inq_result_flt
+**
+** Description This function looks through the bdaddr database for a match
+** based on Bluetooth Device Address
+**
+** Returns TRUE if found, else FALSE (new entry)
+**
+*******************************************************************************/
+static void btm_clr_inq_result_flt (void)
+{
+#if BTM_USE_INQ_RESULTS_FILTER == TRUE
+ tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+
+ if (p_inq->p_bd_db)
+ {
+ GKI_freebuf(p_inq->p_bd_db);
+ p_inq->p_bd_db = NULL;
+ }
+ p_inq->num_bd_entries = 0;
+ p_inq->max_bd_entries = 0;
+#endif
+}
+
+/*******************************************************************************
+**
+** Function btm_inq_find_bdaddr
+**
+** Description This function looks through the bdaddr database for a match
+** based on Bluetooth Device Address
+**
+** Returns TRUE if found, else FALSE (new entry)
+**
+*******************************************************************************/
+BOOLEAN btm_inq_find_bdaddr (BD_ADDR p_bda)
+{
+#if BTM_USE_INQ_RESULTS_FILTER == TRUE
+ tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+ tINQ_BDADDR *p_db = &p_inq->p_bd_db[0];
+ UINT16 xx;
+
+ /* Don't bother searching, database doesn't exist or periodic mode */
+ if ((p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE) || !p_db)
+ return (FALSE);
+
+ for (xx = 0; xx < p_inq->num_bd_entries; xx++, p_db++)
+ {
+ if (!memcmp(p_db->bd_addr, p_bda, BD_ADDR_LEN)
+ && p_db->inq_count == p_inq->inq_counter)
+ return (TRUE);
+ }
+
+ if (xx < p_inq->max_bd_entries)
+ {
+ p_db->inq_count = p_inq->inq_counter;
+ memcpy(p_db->bd_addr, p_bda, BD_ADDR_LEN);
+ p_inq->num_bd_entries++;
+ }
+
+#endif
+ /* If here, New Entry */
+ return (FALSE);
+}
+
+/*******************************************************************************
+**
+** Function btm_inq_db_find
+**
+** Description This function looks through the inquiry database for a match
+** based on Bluetooth Device Address
+**
+** Returns pointer to entry, or NULL if not found
+**
+*******************************************************************************/
+tINQ_DB_ENT *btm_inq_db_find (BD_ADDR p_bda)
+{
+ UINT16 xx;
+ tINQ_DB_ENT *p_ent = btm_cb.btm_inq_vars.inq_db;
+
+ for (xx = 0; xx < BTM_INQ_DB_SIZE; xx++, p_ent++)
+ {
+ if ((p_ent->in_use) && (!memcmp (p_ent->inq_info.results.remote_bd_addr, p_bda, BD_ADDR_LEN)))
+ return (p_ent);
+ }
+
+ /* If here, not found */
+ return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function btm_inq_db_new
+**
+** Description This function looks through the inquiry database for an unused
+** entry. If no entry is free, it allocates the oldest entry.
+**
+** Returns pointer to entry
+**
+*******************************************************************************/
+tINQ_DB_ENT *btm_inq_db_new (BD_ADDR p_bda)
+{
+ UINT16 xx;
+ tINQ_DB_ENT *p_ent = btm_cb.btm_inq_vars.inq_db;
+ tINQ_DB_ENT *p_old = btm_cb.btm_inq_vars.inq_db;
+ UINT32 ot = 0xFFFFFFFF;
+
+ for (xx = 0; xx < BTM_INQ_DB_SIZE; xx++, p_ent++)
+ {
+ if (!p_ent->in_use)
+ {
+ memset (p_ent, 0, sizeof (tINQ_DB_ENT));
+ memcpy (p_ent->inq_info.results.remote_bd_addr, p_bda, BD_ADDR_LEN);
+ p_ent->in_use = TRUE;
+
+#if (BTM_INQ_GET_REMOTE_NAME==TRUE)
+ p_ent->inq_info.remote_name_state = BTM_INQ_RMT_NAME_EMPTY;
+#endif
+
+ return (p_ent);
+ }
+
+ if (p_ent->time_of_resp < ot)
+ {
+ p_old = p_ent;
+ ot = p_ent->time_of_resp;
+ }
+ }
+
+ /* If here, no free entry found. Return the oldest. */
+
+ /* Before deleting the oldest, if anyone is registered for change */
+ /* notifications, then tell him we are deleting an entry. */
+ if (btm_cb.btm_inq_vars.p_inq_change_cb)
+ (*btm_cb.btm_inq_vars.p_inq_change_cb) (&p_old->inq_info, FALSE);
+
+ memset (p_old, 0, sizeof (tINQ_DB_ENT));
+ memcpy (p_old->inq_info.results.remote_bd_addr, p_bda, BD_ADDR_LEN);
+ p_old->in_use = TRUE;
+
+#if (BTM_INQ_GET_REMOTE_NAME==TRUE)
+ p_old->inq_info.remote_name_state = BTM_INQ_RMT_NAME_EMPTY;
+#endif
+
+ return (p_old);
+}
+
+
+/*******************************************************************************
+**
+** Function btm_set_inq_event_filter
+**
+** Description This function is called to set the inquiry event filter.
+** It is called by either internally, or by the external API function
+** (BTM_SetInqEventFilter). It is used internally as part of the
+** inquiry processing.
+**
+** Input Params:
+** filter_cond_type - this is the type of inquiry filter to apply:
+** BTM_FILTER_COND_DEVICE_CLASS,
+** BTM_FILTER_COND_BD_ADDR, or
+** BTM_CLR_INQUIRY_FILTER
+**
+** p_filt_cond - this is either a BD_ADDR or DEV_CLASS depending on the
+** filter_cond_type (See section 4.7.3 of Core Spec 1.0b).
+**
+** Returns BTM_CMD_STARTED if successfully initiated
+** BTM_NO_RESOURCES if couldn't get a memory pool buffer
+** BTM_ILLEGAL_VALUE if a bad parameter was detected
+**
+*******************************************************************************/
+static tBTM_STATUS btm_set_inq_event_filter (UINT8 filter_cond_type,
+ tBTM_INQ_FILT_COND *p_filt_cond)
+{
+ UINT8 condition_length = DEV_CLASS_LEN * 2;
+ UINT8 condition_buf[DEV_CLASS_LEN * 2];
+ UINT8 *p_cond = condition_buf; /* points to the condition to pass to HCI */
+
+#if (BTM_INQ_DEBUG == TRUE)
+ BTM_TRACE_DEBUG1 ("btm_set_inq_event_filter: filter type %d [Clear-0, COD-1, BDADDR-2]",
+ filter_cond_type);
+ BTM_TRACE_DEBUG6 (" condition [%02x%02x%02x %02x%02x%02x]",
+ p_filt_cond->bdaddr_cond[0], p_filt_cond->bdaddr_cond[1], p_filt_cond->bdaddr_cond[2],
+ p_filt_cond->bdaddr_cond[3], p_filt_cond->bdaddr_cond[4], p_filt_cond->bdaddr_cond[5]);
+#endif
+
+ /* Load the correct filter condition to pass to the lower layer */
+ switch (filter_cond_type)
+ {
+ case BTM_FILTER_COND_DEVICE_CLASS:
+ /* copy the device class and device class fields into contiguous memory to send to HCI */
+ memcpy (condition_buf, p_filt_cond->cod_cond.dev_class, DEV_CLASS_LEN);
+ memcpy (&condition_buf[DEV_CLASS_LEN],
+ p_filt_cond->cod_cond.dev_class_mask, DEV_CLASS_LEN);
+
+ /* condition length should already be set as the default */
+ break;
+
+ case BTM_FILTER_COND_BD_ADDR:
+ p_cond = p_filt_cond->bdaddr_cond;
+
+ /* condition length should already be set as the default */
+ break;
+
+ case BTM_CLR_INQUIRY_FILTER:
+ condition_length = 0;
+ break;
+
+ default:
+ return (BTM_ILLEGAL_VALUE); /* Bad parameter was passed in */
+ }
+
+ btm_cb.btm_inq_vars.inqfilt_active = TRUE;
+
+ /* Filter the inquiry results for the specified condition type and value */
+ if (btsnd_hcic_set_event_filter(HCI_FILTER_INQUIRY_RESULT, filter_cond_type,
+ p_cond, condition_length))
+
+ return (BTM_CMD_STARTED);
+ else
+ return (BTM_NO_RESOURCES);
+}
+
+
+/*******************************************************************************
+**
+** Function btm_event_filter_complete
+**
+** Description This function is called when a set event filter has completed.
+** Note: This routine currently only handles inquiry filters.
+** Connection filters are ignored for now.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_event_filter_complete (UINT8 *p)
+{
+ UINT8 hci_status;
+ tBTM_STATUS status;
+ tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+ tBTM_CMPL_CB *p_cb = p_inq->p_inqfilter_cmpl_cb;
+
+#if (BTM_INQ_DEBUG == TRUE)
+ BTM_TRACE_DEBUG3 ("btm_event_filter_complete: inq_active:0x%x state:%d inqfilt_active:%d",
+ btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state, btm_cb.btm_inq_vars.inqfilt_active);
+#endif
+ /* If the filter complete event is from an old or cancelled request, ignore it */
+ if(p_inq->pending_filt_complete_event)
+ {
+ p_inq->pending_filt_complete_event--;
+ return;
+ }
+
+ /* Only process the inquiry filter; Ignore the connection filter until it
+ is used by the upper layers */
+ if (p_inq->inqfilt_active == TRUE )
+ {
+ /* Extract the returned status from the buffer */
+ STREAM_TO_UINT8 (hci_status, p);
+ if (hci_status != HCI_SUCCESS)
+ {
+ /* If standalone operation, return the error status; if embedded in the inquiry, continue the inquiry */
+ BTM_TRACE_WARNING1 ("BTM Warning: Set Event Filter Failed (HCI returned 0x%x)", hci_status);
+ status = BTM_ERR_PROCESSING;
+ }
+ else
+ status = BTM_SUCCESS;
+
+ /* If the set filter was initiated externally (via BTM_SetInqEventFilter), call the
+ callback function to notify the initiator that it has completed */
+ if (p_inq->state == BTM_INQ_INACTIVE_STATE)
+ {
+ p_inq->inqfilt_active = FALSE;
+ if (p_cb)
+ (*p_cb) (&status);
+ }
+ else /* An inquiry is active (the set filter command was internally generated),
+ process the next state of the process (Set a new filter or start the inquiry). */
+ {
+ if(status != BTM_SUCCESS)
+ {
+ /* Process the inquiry complete (Error Status) */
+ btm_process_inq_complete (BTM_ERR_PROCESSING, (UINT8)(p_inq->inqparms.mode & BTM_BR_INQUIRY_MASK));
+
+ /* btm_process_inq_complete() does not restore the following settings on periodic inquiry */
+ p_inq->inqfilt_active = FALSE;
+ p_inq->inq_active = BTM_INQUIRY_INACTIVE;
+ p_inq->state = BTM_INQ_INACTIVE_STATE;
+
+ return;
+ }
+
+ /* Check to see if a new filter needs to be set up */
+ if (p_inq->state == BTM_INQ_CLR_FILT_STATE)
+ {
+ if ((status = btm_set_inq_event_filter (p_inq->inqparms.filter_cond_type, &p_inq->inqparms.filter_cond)) == BTM_CMD_STARTED)
+ {
+ p_inq->state = BTM_INQ_SET_FILT_STATE;
+ }
+ else /* Error setting the filter: Call the initiator's callback function to indicate a failure */
+ {
+ p_inq->inqfilt_active = FALSE;
+
+ /* Process the inquiry complete (Error Status) */
+ btm_process_inq_complete (BTM_ERR_PROCESSING, (UINT8)(p_inq->inqparms.mode & BTM_BR_INQUIRY_MASK));
+ }
+ }
+ else /* Initiate the Inquiry or Periodic Inquiry */
+ {
+ p_inq->state = BTM_INQ_ACTIVE_STATE;
+ p_inq->inqfilt_active = FALSE;
+ btm_initiate_inquiry (p_inq);
+ }
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function btm_initiate_inquiry
+**
+** Description This function is called to start an inquiry or periodic inquiry
+** upon completion of the setting and/or clearing of the inquiry filter.
+**
+** Inputs: p_inq (btm_cb.btm_inq_vars) - pointer to saved inquiry information
+** mode - GENERAL or LIMITED inquiry
+** duration - length in 1.28 sec intervals (If '0', the inquiry is CANCELLED)
+** max_resps - maximum amount of devices to search for before ending the inquiry
+** filter_cond_type - BTM_CLR_INQUIRY_FILTER, BTM_FILTER_COND_DEVICE_CLASS, or
+** BTM_FILTER_COND_BD_ADDR
+** filter_cond - value for the filter (based on filter_cond_type)
+**
+** Returns If an error occurs the initiator's callback is called with the error status.
+**
+*******************************************************************************/
+static void btm_initiate_inquiry (tBTM_INQUIRY_VAR_ST *p_inq)
+{
+ const LAP *lap;
+ tBTM_INQ_PARMS *p_inqparms = &p_inq->inqparms;
+
+#if (BTM_INQ_DEBUG == TRUE)
+ BTM_TRACE_DEBUG3 ("btm_initiate_inquiry: inq_active:0x%x state:%d inqfilt_active:%d",
+ btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state, btm_cb.btm_inq_vars.inqfilt_active);
+#endif
+#if (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE)
+ btm_acl_update_busy_level (BTM_BLI_INQ_EVT);
+#endif
+
+ if (p_inq->inq_active & BTM_SSP_INQUIRY_ACTIVE)
+ {
+ btm_process_inq_complete (BTM_NO_RESOURCES, (UINT8)(p_inqparms->mode & BTM_BR_INQUIRY_MASK));
+ return;
+ }
+
+ /* Make sure the number of responses doesn't overflow the database configuration */
+ p_inqparms->max_resps = (UINT8)((p_inqparms->max_resps <= BTM_INQ_DB_SIZE) ? p_inqparms->max_resps : BTM_INQ_DB_SIZE);
+
+ lap = (p_inq->inq_active & BTM_LIMITED_INQUIRY_ACTIVE) ? &limited_inq_lap : &general_inq_lap;
+
+ if (p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE)
+ {
+ if (!btsnd_hcic_per_inq_mode (p_inq->per_max_delay,
+ p_inq->per_min_delay,
+ *lap, p_inqparms->duration,
+ p_inqparms->max_resps))
+ btm_process_inq_complete (BTM_NO_RESOURCES, (UINT8)(p_inqparms->mode & BTM_BR_INQUIRY_MASK));
+ }
+ else
+ {
+#if BTM_USE_INQ_RESULTS_FILTER == TRUE
+ btm_clr_inq_result_flt();
+
+ /* Allocate memory to hold bd_addrs responding */
+ if ((p_inq->p_bd_db = (tINQ_BDADDR *)GKI_getbuf(GKI_MAX_BUF_SIZE)) != NULL)
+ {
+ p_inq->max_bd_entries = (UINT16)(GKI_MAX_BUF_SIZE / sizeof(tINQ_BDADDR));
+ memset(p_inq->p_bd_db, 0, GKI_MAX_BUF_SIZE);
+/* BTM_TRACE_DEBUG1("btm_initiate_inquiry: memory allocated for %d bdaddrs",
+ p_inq->max_bd_entries); */
+ }
+
+ if (!btsnd_hcic_inquiry(*lap, p_inqparms->duration, 0))
+#else
+ if (!btsnd_hcic_inquiry(*lap, p_inqparms->duration, p_inqparms->max_resps))
+#endif /* BTM_USE_INQ_RESULTS_FILTER */
+ btm_process_inq_complete (BTM_NO_RESOURCES, (UINT8)(p_inqparms->mode & BTM_BR_INQUIRY_MASK));
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_process_inq_results
+**
+** Description This function is called when inquiry results are received from
+** the device. It updates the inquiry database. If the inquiry
+** database is full, the oldest entry is discarded.
+**
+** Parameters inq_res_mode - BTM_INQ_RESULT_STANDARD
+** BTM_INQ_RESULT_WITH_RSSI
+** BTM_INQ_RESULT_EXTENDED
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_process_inq_results (UINT8 *p, UINT8 inq_res_mode)
+{
+ UINT8 num_resp, xx;
+ BD_ADDR bda;
+ tINQ_DB_ENT *p_i;
+ tBTM_INQ_RESULTS *p_cur;
+ BOOLEAN is_new = TRUE;
+ BOOLEAN update = FALSE;
+ INT8 i_rssi;
+ tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+ tBTM_INQ_RESULTS_CB *p_inq_results_cb = p_inq->p_inq_results_cb;
+ UINT8 page_scan_rep_mode = 0;
+ UINT8 page_scan_per_mode = 0;
+ UINT8 page_scan_mode = 0;
+ UINT8 rssi = 0;
+ DEV_CLASS dc;
+ UINT16 clock_offset;
+#if (BTM_EIR_CLIENT_INCLUDED == TRUE)
+ UINT8 *p_eir_data = NULL;
+#if (BTM_INQ_GET_REMOTE_NAME==TRUE)
+ UINT8 remote_name_len;
+#endif
+#endif
+
+#if (BTM_INQ_DEBUG == TRUE)
+ BTM_TRACE_DEBUG3 ("btm_process_inq_results inq_active:0x%x state:%d inqfilt_active:%d",
+ btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state, btm_cb.btm_inq_vars.inqfilt_active);
+#endif
+ /* Only process the results if the inquiry is still active */
+ if (!p_inq->inq_active)
+ return;
+
+ STREAM_TO_UINT8 (num_resp, p);
+
+ for (xx = 0; xx < num_resp; xx++)
+ {
+ update = FALSE;
+ /* Extract inquiry results */
+ STREAM_TO_BDADDR (bda, p);
+ STREAM_TO_UINT8 (page_scan_rep_mode, p);
+ STREAM_TO_UINT8 (page_scan_per_mode, p);
+
+ if (inq_res_mode == BTM_INQ_RESULT_STANDARD)
+ {
+ STREAM_TO_UINT8(page_scan_mode, p);
+ }
+
+ STREAM_TO_DEVCLASS (dc, p);
+ STREAM_TO_UINT16 (clock_offset, p);
+ if (inq_res_mode != BTM_INQ_RESULT_STANDARD)
+ {
+ STREAM_TO_UINT8(rssi, p);
+ }
+
+ p_i = btm_inq_db_find (bda);
+
+#if BTM_USE_INQ_RESULTS_FILTER == TRUE
+ /* Only process the num_resp is smaller than max_resps.
+ If results are queued to BTU task while canceling inquiry,
+ or when more than one result is in this response, > max_resp
+ responses could be processed which can confuse some apps
+ */
+ if (p_inq->inqparms.max_resps &&
+ p_inq->inq_cmpl_info.num_resp >= p_inq->inqparms.max_resps
+#if BLE_INCLUDED == TRUE
+ /* new device response */
+ && ( p_i == NULL ||
+ /* exisiting device with BR/EDR info */
+ (p_i && (p_i->inq_info.results.device_type & BT_DEVICE_TYPE_BREDR) != 0)
+ )
+#endif
+
+ )
+ {
+/* BTM_TRACE_WARNING0("INQ RES: Extra Response Received...ignoring"); */
+ return;
+ }
+#endif
+
+ /* Check if this address has already been processed for this inquiry */
+ if (btm_inq_find_bdaddr(bda))
+ {
+/* BTM_TRACE_DEBUG6("BDA seen before [%02x%02x %02x%02x %02x%02x]",
+ bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);*/
+ /* By default suppose no update needed */
+ i_rssi = (INT8)rssi;
+
+ /* If this new RSSI is higher than the last one */
+ if(p_inq->inqparms.report_dup && (rssi != 0) &&
+ p_i && (i_rssi > p_i->inq_info.results.rssi || p_i->inq_info.results.rssi == 0
+#if BLE_INCLUDED == TRUE
+ /* BR/EDR inquiry information update */
+ || (p_i->inq_info.results.device_type & BT_DEVICE_TYPE_BREDR) != 0
+#endif
+ ))
+ {
+ p_cur = &p_i->inq_info.results;
+ BTM_TRACE_DEBUG2("update RSSI new:%d, old:%d", i_rssi, p_cur->rssi);
+ p_cur->rssi = i_rssi;
+ update = TRUE;
+ }
+ /* If we received a second Extended Inq Event for an already */
+ /* discovered device, this is because for the first one EIR was not received */
+ else if ((inq_res_mode == BTM_INQ_RESULT_EXTENDED) && (p_i))
+ {
+ p_cur = &p_i->inq_info.results;
+ update = TRUE;
+ }
+ /* If no update needed continue with next response (if any) */
+ else
+ continue;
+ }
+
+ /* Host can be registered to verify comming BDA or DC */
+ if (btm_cb.p_inq_filter_cb)
+ {
+ if (!(* btm_cb.p_inq_filter_cb) (bda, dc))
+ {
+ continue;
+ }
+ }
+
+ /* If existing entry, use that, else get a new one (possibly reusing the oldest) */
+ if (p_i == NULL)
+ {
+ p_i = btm_inq_db_new (bda);
+ is_new = TRUE;
+ }
+
+ /* If an entry for the device already exists, overwrite it ONLY if it is from
+ a previous inquiry. (Ignore it if it is a duplicate response from the same
+ inquiry.
+ */
+ else if (p_i->inq_count == p_inq->inq_counter
+#if (BLE_INCLUDED == TRUE )
+ && (p_i->inq_info.results.device_type & BT_DEVICE_TYPE_BREDR)
+#endif
+ )
+ is_new = FALSE;
+
+ /* keep updating RSSI to have latest value */
+ if( inq_res_mode != BTM_INQ_RESULT_STANDARD )
+ p_i->inq_info.results.rssi = (INT8)rssi;
+ else
+ p_i->inq_info.results.rssi = BTM_INQ_RES_IGNORE_RSSI;
+
+ if (is_new == TRUE)
+ {
+ /* Save the info */
+ p_cur = &p_i->inq_info.results;
+ p_cur->page_scan_rep_mode = page_scan_rep_mode;
+ p_cur->page_scan_per_mode = page_scan_per_mode;
+ p_cur->page_scan_mode = page_scan_mode;
+ p_cur->dev_class[0] = dc[0];
+ p_cur->dev_class[1] = dc[1];
+ p_cur->dev_class[2] = dc[2];
+ p_cur->clock_offset = clock_offset | BTM_CLOCK_OFFSET_VALID;
+
+ p_i->time_of_resp = GKI_get_tick_count ();
+
+ if (p_i->inq_count != p_inq->inq_counter)
+ p_inq->inq_cmpl_info.num_resp++; /* A new response was found */
+
+#if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE)
+ p_cur->inq_result_type = BTM_INQ_RESULT_BR;
+ if (p_i->inq_count != p_inq->inq_counter)
+ {
+ p_cur->device_type = BT_DEVICE_TYPE_BREDR;
+ p_i->scan_rsp = FALSE;
+ }
+ else
+ p_cur->device_type |= BT_DEVICE_TYPE_BREDR;
+#endif
+ p_i->inq_count = p_inq->inq_counter; /* Mark entry for current inquiry */
+
+#if BTM_USE_INQ_RESULTS_FILTER == TRUE
+ /* If the number of responses found and not unlimited, issue a cancel inquiry */
+ if (!(p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE) &&
+ p_inq->inqparms.max_resps &&
+ p_inq->inq_cmpl_info.num_resp == p_inq->inqparms.max_resps
+#if BLE_INCLUDED == TRUE
+ /* BLE scanning is active and received adv */
+ && ((((p_inq->inqparms.mode & BTM_BLE_INQUIRY_MASK) != 0) &&
+ p_cur->device_type == BT_DEVICE_TYPE_DUMO && p_i->scan_rsp) ||
+ (p_inq->inqparms.mode & BTM_BLE_INQUIRY_MASK) == 0)
+#endif
+ )
+ {
+/* BTM_TRACE_DEBUG0("BTMINQ: Found devices, cancelling inquiry..."); */
+ btsnd_hcic_inq_cancel();
+
+#if BLE_INCLUDED == TRUE
+ if ((p_inq->inqparms.mode & BTM_BLE_INQUIRY_MASK) != 0)
+ btm_ble_stop_scan();
+#endif
+
+
+#if (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE)
+ btm_acl_update_busy_level (BTM_BLI_INQ_DONE_EVT);
+#endif
+ }
+#endif
+ /* Initialize flag to FALSE. This flag is set/used by application */
+ p_i->inq_info.appl_knows_rem_name = FALSE;
+ }
+
+ if (is_new || update)
+ {
+#if (BTM_INQ_GET_REMOTE_NAME==TRUE)
+#if (BTM_EIR_CLIENT_INCLUDED == TRUE)
+ if( inq_res_mode == BTM_INQ_RESULT_EXTENDED )
+ {
+ if((p_eir_data = BTM_CheckEirData( p, BTM_EIR_COMPLETE_LOCAL_NAME_TYPE,
+ &remote_name_len )) == NULL)
+ {
+ p_eir_data = BTM_CheckEirData( p, BTM_EIR_SHORTENED_LOCAL_NAME_TYPE,
+ &remote_name_len );
+ }
+
+ if( p_eir_data )
+ {
+ if( remote_name_len > BTM_MAX_REM_BD_NAME_LEN )
+ remote_name_len = BTM_MAX_REM_BD_NAME_LEN;
+
+ p_i->inq_info.remote_name_len = remote_name_len;
+ memcpy( p_i->inq_info.remote_name, p_eir_data, p_i->inq_info.remote_name_len );
+ p_i->inq_info.remote_name[p_i->inq_info.remote_name_len] = 0;
+ p_i->inq_info.remote_name_state = BTM_INQ_RMT_NAME_DONE;
+ }
+ else
+ p_i->inq_info.remote_name_state = BTM_INQ_RMT_NAME_EMPTY;
+ }
+ else
+#endif
+ {
+ /* Clear out the device name so that it can be re-read */
+ p_i->inq_info.remote_name_state = BTM_INQ_RMT_NAME_EMPTY;
+ }
+#endif /*(BTM_INQ_GET_REMOTE_NAME==TRUE)*/
+
+#if (BTM_EIR_CLIENT_INCLUDED == TRUE)
+ if( inq_res_mode == BTM_INQ_RESULT_EXTENDED )
+ {
+ memset( p_cur->eir_uuid, 0,
+ BTM_EIR_SERVICE_ARRAY_SIZE * (BTM_EIR_ARRAY_BITS/8));
+ /* set bit map of UUID list from received EIR */
+ btm_set_eir_uuid( p, p_cur );
+ p_eir_data = p;
+ }
+ else
+ p_eir_data = NULL;
+#endif
+
+ /* If a callback is registered, call it with the results */
+ if (p_inq_results_cb)
+#if (BTM_EIR_CLIENT_INCLUDED == TRUE)
+ (p_inq_results_cb)((tBTM_INQ_RESULTS *) p_cur, p_eir_data);
+#else
+ (p_inq_results_cb)((tBTM_INQ_RESULTS *) p_cur, NULL);
+#endif
+
+ /* If anyone is registered for change notifications, then tell him we added an entry. */
+ if (p_inq->p_inq_change_cb)
+ (*p_inq->p_inq_change_cb) (&p_i->inq_info, TRUE);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_sort_inq_result
+**
+** Description This function is called when inquiry complete is received
+** from the device to sort inquiry results based on rssi.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sort_inq_result(void)
+{
+ UINT8 xx, yy, num_resp;
+ tINQ_DB_ENT *p_tmp = NULL;
+ tINQ_DB_ENT *p_ent = btm_cb.btm_inq_vars.inq_db;
+ tINQ_DB_ENT *p_next = btm_cb.btm_inq_vars.inq_db+1;
+ int size;
+
+ num_resp = (btm_cb.btm_inq_vars.inq_cmpl_info.num_resp<BTM_INQ_DB_SIZE)?
+ btm_cb.btm_inq_vars.inq_cmpl_info.num_resp: BTM_INQ_DB_SIZE;
+
+ if((p_tmp = (tINQ_DB_ENT *)GKI_getbuf(sizeof(tINQ_DB_ENT))) != NULL)
+ {
+ size = sizeof(tINQ_DB_ENT);
+ for(xx = 0; xx < num_resp-1; xx++, p_ent++)
+ {
+ for(yy = xx+1, p_next = p_ent+1; yy < num_resp; yy++, p_next++)
+ {
+ if(p_ent->inq_info.results.rssi < p_next->inq_info.results.rssi)
+ {
+ memcpy (p_tmp, p_next, size);
+ memcpy (p_next, p_ent, size);
+ memcpy (p_ent, p_tmp, size);
+ }
+ }
+ }
+
+ GKI_freebuf(p_tmp);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_process_inq_complete
+**
+** Description This function is called when inquiry complete is received
+** from the device. Call the callback if not in periodic inquiry
+** mode AND it is not NULL (The caller wants the event).
+**
+** The callback pass back the status and the number of responses
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_process_inq_complete (UINT8 status, UINT8 mode)
+{
+ tBTM_CMPL_CB *p_inq_cb = btm_cb.btm_inq_vars.p_inq_cmpl_cb;
+ tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+
+#if (BTM_INQ_GET_REMOTE_NAME==TRUE)
+ tBTM_INQ_INFO *p_cur;
+ UINT8 tempstate;
+#endif
+
+ p_inq->inqparms.mode &= ~(mode);
+
+#if (BTM_INQ_DEBUG == TRUE)
+ BTM_TRACE_DEBUG3 ("btm_process_inq_complete inq_active:0x%x state:%d inqfilt_active:%d",
+ btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state, btm_cb.btm_inq_vars.inqfilt_active);
+#endif
+#if (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE)
+ btm_acl_update_busy_level (BTM_BLI_INQ_DONE_EVT);
+#endif
+ /* Ignore any stray or late complete messages if the inquiry is not active */
+ if (p_inq->inq_active)
+ {
+ p_inq->inq_cmpl_info.status = (tBTM_STATUS)((status == HCI_SUCCESS) ? BTM_SUCCESS : BTM_ERR_PROCESSING);
+
+#if (BTM_INQ_GET_REMOTE_NAME==TRUE)
+ if (p_inq->inq_cmpl_info.status == BTM_SUCCESS)
+ {
+ for (p_cur = BTM_InqDbFirst(); p_cur; p_cur = BTM_InqDbNext (p_cur))
+ {
+ if (p_cur->remote_name_state == BTM_INQ_RMT_NAME_EMPTY)
+ {
+ tempstate = p_cur->remote_name_state;
+ p_cur->remote_name_state = BTM_INQ_RMT_NAME_PENDING;
+
+ if (btm_initiate_rem_name (p_cur->results.remote_bd_addr,
+ p_cur, BTM_RMT_NAME_INQ,
+ BTM_INQ_RMT_NAME_TIMEOUT, NULL) != BTM_CMD_STARTED)
+ p_cur->remote_name_state = tempstate;
+ else
+ return;
+ }
+ }
+ }
+#endif
+
+ /* Notify caller that the inquiry has completed; (periodic inquiries do not send completion events */
+ if (!(p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE) && p_inq->inqparms.mode == 0)
+ {
+ p_inq->state = BTM_INQ_INACTIVE_STATE;
+
+ /* Increment so the start of a next inquiry has a new count */
+ p_inq->inq_counter++;
+
+ btm_clr_inq_result_flt();
+
+ if((p_inq->inq_cmpl_info.status == BTM_SUCCESS) && HCI_LMP_INQ_RSSI_SUPPORTED(btm_cb.devcb.local_features))
+ {
+ btm_sort_inq_result();
+ }
+
+ /* Clear the results callback if set */
+ p_inq->p_inq_results_cb = (tBTM_INQ_RESULTS_CB *) NULL;
+ p_inq->inq_active = BTM_INQUIRY_INACTIVE;
+ p_inq->p_inq_cmpl_cb = (tBTM_CMPL_CB *) NULL;
+
+ /* If we have a callback registered for inquiry complete, call it */
+ BTM_TRACE_DEBUG2 ("BTM Inq Compl Callback: status 0x%02x, num results %d",
+ p_inq->inq_cmpl_info.status, p_inq->inq_cmpl_info.num_resp);
+
+ if (p_inq_cb)
+ (p_inq_cb)((tBTM_INQUIRY_CMPL *) &p_inq->inq_cmpl_info);
+ }
+
+ }
+#if (BTM_INQ_DEBUG == TRUE)
+ BTM_TRACE_DEBUG3 ("inq_active:0x%x state:%d inqfilt_active:%d",
+ btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state, btm_cb.btm_inq_vars.inqfilt_active);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function btm_initiate_rem_name
+**
+** Description This function looks initiates a remote name request. It is called
+** either by GAP or by the API call BTM_ReadRemoteDeviceName.
+**
+** Input Params: p_cur - pointer to an inquiry result structure (NULL if nonexistent)
+** p_cb - callback function called when BTM_CMD_STARTED
+** is returned.
+** A pointer to tBTM_REMOTE_DEV_NAME is passed to the
+** callback.
+**
+** Returns
+** BTM_CMD_STARTED is returned if the request was sent to HCI.
+** BTM_BUSY if already in progress
+** BTM_NO_RESOURCES if could not allocate resources to start the command
+** BTM_WRONG_MODE if the device is not up.
+**
+*******************************************************************************/
+tBTM_STATUS btm_initiate_rem_name (BD_ADDR remote_bda, tBTM_INQ_INFO *p_cur,
+ UINT8 origin, UINT32 timeout, tBTM_CMPL_CB *p_cb)
+{
+ tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+ BOOLEAN cmd_ok;
+
+
+ /*** Make sure the device is ready ***/
+ if (!BTM_IsDeviceUp())
+ return (BTM_WRONG_MODE);
+
+
+ if (origin == BTM_RMT_NAME_SEC)
+ {
+ cmd_ok = btsnd_hcic_rmt_name_req (remote_bda, HCI_PAGE_SCAN_REP_MODE_R1,
+ HCI_MANDATARY_PAGE_SCAN_MODE, 0);
+ if (cmd_ok)
+ return BTM_CMD_STARTED;
+ else
+ return BTM_NO_RESOURCES;
+ }
+ /* Make sure there are no two remote name requests from external API in progress */
+ else if (origin == BTM_RMT_NAME_EXT)
+ {
+ if (p_inq->remname_active)
+ {
+ return (BTM_BUSY);
+ }
+ else
+ {
+ /* If there is no remote name request running,call the callback function and start timer */
+ p_inq->p_remname_cmpl_cb = p_cb;
+ memcpy(p_inq->remname_bda, remote_bda, BD_ADDR_LEN);
+ btu_start_timer (&p_inq->rmt_name_timer_ent,
+ BTU_TTYPE_BTM_RMT_NAME,
+ timeout);
+
+ /* If the database entry exists for the device, use its clock offset */
+ if (p_cur)
+ {
+ cmd_ok = btsnd_hcic_rmt_name_req (remote_bda,
+ p_cur->results.page_scan_rep_mode,
+ p_cur->results.page_scan_mode,
+ (UINT16)(p_cur->results.clock_offset |
+ BTM_CLOCK_OFFSET_VALID));
+ }
+ else /* Otherwise use defaults and mark the clock offset as invalid */
+ {
+ cmd_ok = btsnd_hcic_rmt_name_req (remote_bda, HCI_PAGE_SCAN_REP_MODE_R1,
+ HCI_MANDATARY_PAGE_SCAN_MODE, 0);
+ }
+ if (cmd_ok)
+ {
+ p_inq->remname_active = TRUE;
+ return BTM_CMD_STARTED;
+ }
+ else
+ return BTM_NO_RESOURCES;
+ }
+ }
+ /* If the inquire feature is on */
+#if (BTM_INQ_GET_REMOTE_NAME==TRUE)
+
+ else if (origin == BTM_RMT_NAME_INQ)
+ {
+ /* If the database entry exists for the device, use its clock offset */
+ if (p_cur)
+ {
+ cmd_ok = btsnd_hcic_rmt_name_req (remote_bda,
+ p_cur->results.page_scan_rep_mode,
+ p_cur->results.page_scan_mode,
+ (UINT16)(p_cur->results.clock_offset |
+ BTM_CLOCK_OFFSET_VALID));
+ }
+ else
+ {
+ cmd_ok = FALSE
+ }
+
+ if (cmd_ok)
+ return BTM_CMD_STARTED;
+ else
+ return BTM_NO_RESOURCES;
+ }
+#endif
+ else
+ {
+
+ return BTM_ILLEGAL_VALUE;
+
+
+ }
+
+
+}
+
+/*******************************************************************************
+**
+** Function btm_process_remote_name
+**
+** Description This function is called when a remote name is received from
+** the device. If remote names are cached, it updates the inquiry
+** database.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_process_remote_name (BD_ADDR bda, BD_NAME bdn, UINT16 evt_len, UINT8 hci_status)
+{
+ tBTM_REMOTE_DEV_NAME rem_name = {0};
+ tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+ tBTM_CMPL_CB *p_cb = p_inq->p_remname_cmpl_cb;
+ UINT8 *p_n1;
+
+ UINT16 temp_evt_len;
+
+#if (BTM_INQ_GET_REMOTE_NAME==TRUE)
+ /*** These are only used if part of the Inquiry Process ***/
+ tBTM_CMPL_CB *p_inq_cb;
+ tINQ_DB_ENT *p_i = NULL;
+ UINT8 *p_n;
+ tBTM_INQ_INFO *p_cur;
+#endif
+#if BLE_INCLUDED == TRUE
+ tBT_DEVICE_TYPE dev_type;
+ tBLE_ADDR_TYPE addr_type;
+#endif
+
+
+ if (bda != NULL)
+ {
+ BTM_TRACE_EVENT6("BDA %02x:%02x:%02x:%02x:%02x:%02x",bda[0], bda[1],
+ bda[2], bda[3],
+ bda[4], bda[5]);
+ }
+
+ BTM_TRACE_EVENT6("Inquire BDA %02x:%02x:%02x:%02x:%02x:%02x",p_inq->remname_bda[0], p_inq->remname_bda[1],
+ p_inq->remname_bda[2], p_inq->remname_bda[3],
+ p_inq->remname_bda[4], p_inq->remname_bda[5]);
+
+
+
+ /* If the inquire BDA and remote DBA are the same, then stop the timer and set the active to false */
+ if ((p_inq->remname_active ==TRUE)&&
+ (((bda != NULL) &&
+ (memcmp(bda, p_inq->remname_bda,BD_ADDR_LEN)==0)) || bda == NULL))
+
+ {
+#if BLE_INCLUDED == TRUE
+ BTM_ReadDevInfo(p_inq->remname_bda, &dev_type, &addr_type);
+ if (dev_type == BT_DEVICE_TYPE_BLE)
+ {
+ if (hci_status == HCI_ERR_UNSPECIFIED)
+ btm_ble_cancel_remote_name(p_inq->remname_bda);
+ }
+#endif
+ btu_stop_timer (&p_inq->rmt_name_timer_ent);
+ p_inq->remname_active = FALSE;
+ /* Clean up and return the status if the command was not successful */
+ /* Note: If part of the inquiry, the name is not stored, and the */
+ /* inquiry complete callback is called. */
+
+ if ((hci_status == HCI_SUCCESS))
+ {
+ /* Copy the name from the data stream into the return structure */
+ /* Note that even if it is not being returned, it is used as a */
+ /* temporary buffer. */
+ p_n1 = (UINT8 *)rem_name.remote_bd_name;
+ rem_name.length = (evt_len < BD_NAME_LEN) ? evt_len : BD_NAME_LEN;
+ rem_name.status = BTM_SUCCESS;
+ temp_evt_len = rem_name.length;
+
+ while (temp_evt_len > 0)
+ {
+ *p_n1++ = *bdn++;
+ temp_evt_len--;
+ }
+ }
+
+
+ /* If processing a stand alone remote name then report the error in the callback */
+ else
+ {
+ rem_name.status = BTM_BAD_VALUE_RET;
+ rem_name.length = 0;
+ rem_name.remote_bd_name[0] = 0;
+ }
+ /* Reset the remote BAD to zero and call callback if possible */
+ memset(p_inq->remname_bda, 0, BD_ADDR_LEN);
+
+ p_inq->p_remname_cmpl_cb = NULL;
+ if (p_cb)
+ (p_cb)((tBTM_REMOTE_DEV_NAME *)&rem_name);
+ }
+
+
+#if (BTM_INQ_GET_REMOTE_NAME==TRUE)
+ /* If existing entry, update the name */
+ if ((bda != NULL) && ((p_i = btm_inq_db_find (bda)) != NULL)
+ && (hci_status == HCI_SUCCESS))
+ {
+ p_i->inq_info.remote_name_state = BTM_INQ_RMT_NAME_DONE;
+ p_n = p_i->inq_info.remote_name;
+ memset(p_n, 0, BTM_MAX_REM_BD_NAME_LEN + 1);
+ p_i->inq_info.remote_name_len = (rem_name.length < BTM_MAX_REM_BD_NAME_LEN) ?
+ rem_name.length : BTM_MAX_REM_BD_NAME_LEN;
+ evt_len = p_i->inq_info.remote_name_len;
+ p_n1 = (UINT8 *)rem_name.remote_bd_name;
+ while (evt_len > 0)
+ {
+ *p_n++ = *p_n1++;
+ evt_len--;
+ }
+
+ if (btm_cb.btm_inq_vars.p_inq_change_cb)
+ (*btm_cb.btm_inq_vars.p_inq_change_cb) (&p_i->inq_info, TRUE);
+ }
+ else
+ {
+ if (p_i)
+ p_i->inq_info.remote_name_state = BTM_INQ_RMT_NAME_FAILED;
+ else
+ {
+ /* Find the entry which is currently doing name request */
+ for (p_cur = BTM_InqDbFirst(); p_cur; p_cur = BTM_InqDbNext (p_cur))
+ {
+ if (p_cur->remote_name_state == BTM_INQ_RMT_NAME_PENDING)
+ {
+ /* Should be only one */
+ p_cur->remote_name_state = BTM_INQ_RMT_NAME_FAILED;
+ break;
+ }
+ }
+ }
+ }
+
+ /* If an inquiry is in progress then update other entries */
+ if (p_inq->inq_active)
+ {
+ /* Check if there are any more entries inquired but not named */
+ for (p_cur = BTM_InqDbFirst(); p_cur; p_cur = BTM_InqDbNext (p_cur))
+ {
+ if (p_cur->remote_name_state == BTM_INQ_RMT_NAME_EMPTY)
+ {
+ p_cur->remote_name_state = BTM_INQ_RMT_NAME_PENDING;
+#if (BLE_INCLUDED == TRUE)
+ BTM_ReadDevInfo(remote_bda, &dev_type, &addr_type);
+ if (dev_type == BT_DEVICE_TYPE_BLE)
+ {
+ if (btm_ble_read_remote_name(remote_bda, p_cur, p_cb) != BTM_CMD_STARTED)
+ p_cur->remote_name_state = BTM_INQ_RMT_NAME_FAILED;
+ else
+ return;
+ }
+ else
+#endif
+ {
+ if (btm_initiate_rem_name (p_cur->results.remote_bd_addr,
+ p_cur, BTM_RMT_NAME_INQ,
+ BTM_INQ_RMT_NAME_TIMEOUT, NULL) != BTM_CMD_STARTED)
+ p_cur->remote_name_state = BTM_INQ_RMT_NAME_FAILED;
+ else
+ return;
+ }
+ }
+ }
+
+ /* The inquiry has finished so call the callback for the inquiry */
+ p_inq_cb = p_inq->p_inq_cmpl_cb;
+ p_inq->state = BTM_INQ_INACTIVE_STATE;
+ p_inq->inq_active = BTM_INQUIRY_INACTIVE;
+ p_inq->p_inq_cmpl_cb = NULL;
+
+ /* If we have a callback registered for inquiry complete, call it */
+ if (p_inq_cb)
+ (p_inq_cb)((tBTM_INQUIRY_CMPL *) &p_inq->inq_cmpl_info);
+
+ /* In some cases we can not get name of the device once but will be */
+ /* able to do it next time. Until we have better solution we will */
+ /* try to get name every time */
+ for (p_cur = BTM_InqDbFirst(); p_cur; p_cur = BTM_InqDbNext (p_cur))
+ {
+ if (p_cur->remote_name_state == BTM_INQ_RMT_NAME_FAILED)
+ p_cur->remote_name_state = BTM_INQ_RMT_NAME_EMPTY;
+ }
+ }
+#endif /* BTM_INQ_GET_REMOTE_NAME == TRUE */
+}
+
+/*******************************************************************************
+**
+** Function btm_inq_rmt_name_failed
+**
+** Description This function is if timeout expires while getting remote
+** name. This is done for devices that incorrectly do not
+** report operation failure
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_inq_rmt_name_failed (void)
+{
+ BTM_TRACE_ERROR1 ("btm_inq_rmt_name_failed() remname_active=%d", btm_cb.btm_inq_vars.remname_active);
+
+ if (btm_cb.btm_inq_vars.remname_active)
+ btm_process_remote_name (btm_cb.btm_inq_vars.remname_bda, NULL, 0, HCI_ERR_UNSPECIFIED);
+ else
+ btm_process_remote_name (NULL, NULL, 0, HCI_ERR_UNSPECIFIED);
+
+ btm_sec_rmt_name_request_complete (NULL, NULL, HCI_ERR_UNSPECIFIED);
+}
+/*******************************************************************************
+**
+** Function btm_read_linq_tx_power_complete
+**
+** Description read inquiry tx power level complete callback function.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_read_linq_tx_power_complete(UINT8 *p)
+{
+ tBTM_CMPL_CB *p_cb = btm_cb.devcb.p_txpwer_cmpl_cb;
+ tBTM_INQ_TXPWR_RESULTS results;
+
+ btu_stop_timer (&btm_cb.devcb.txpwer_timer);
+ /* If there was a callback registered for read inq tx power, call it */
+ btm_cb.devcb.p_txpwer_cmpl_cb = NULL;
+
+ if (p_cb)
+ {
+ STREAM_TO_UINT8 (results.hci_status, p);
+
+ if (results.hci_status == HCI_SUCCESS)
+ {
+ results.status = BTM_SUCCESS;
+
+ STREAM_TO_UINT8 (results.tx_power, p);
+ BTM_TRACE_EVENT2 ("BTM INQ TX POWER Complete: tx_power %d, hci status 0x%02x",
+ results.tx_power, results.hci_status);
+ }
+ else
+ results.status = BTM_ERR_PROCESSING;
+
+ (*p_cb)(&results);
+ }
+
+}
+/*******************************************************************************
+**
+** Function BTM_WriteEIR
+**
+** Description This function is called to write EIR data to controller.
+**
+** Parameters p_buff - allocated HCI command buffer including extended
+** inquriry response
+**
+** Returns BTM_SUCCESS - if successful
+** BTM_MODE_UNSUPPORTED - if local device cannot support it
+**
+*******************************************************************************/
+tBTM_STATUS BTM_WriteEIR( BT_HDR *p_buff )
+{
+#if (BTM_EIR_SERVER_INCLUDED == TRUE)
+ if (HCI_EXT_INQ_RSP_SUPPORTED(btm_cb.devcb.local_features))
+ {
+ BTM_TRACE_API0("Write Extended Inquiry Response to controller");
+ btsnd_hcic_write_ext_inquiry_response (p_buff, BTM_EIR_DEFAULT_FEC_REQUIRED);
+ return BTM_SUCCESS;
+ }
+ else
+ {
+ GKI_freebuf(p_buff);
+ return BTM_MODE_UNSUPPORTED;
+ }
+#else
+ GKI_freebuf(p_buff);
+ return BTM_SUCCESS;
+#endif
+}
+
+/*******************************************************************************
+**
+** Function BTM_CheckEirData
+**
+** Description This function is called to get EIR data from significant part.
+**
+** Parameters p_eir - pointer of EIR significant part
+** type - finding EIR data type
+** p_length - return the length of EIR data not including type
+**
+** Returns pointer of EIR data
+**
+*******************************************************************************/
+UINT8 *BTM_CheckEirData( UINT8 *p_eir, UINT8 type, UINT8 *p_length )
+{
+#if (BTM_EIR_CLIENT_INCLUDED == TRUE)
+ UINT8 *p = p_eir;
+ UINT8 length;
+ UINT8 eir_type;
+ BTM_TRACE_API1("BTM_CheckEirData type=0x%02X", type);
+
+ STREAM_TO_UINT8(length, p);
+ while( length && (p - p_eir <= HCI_EXT_INQ_RESPONSE_LEN))
+ {
+ STREAM_TO_UINT8(eir_type, p);
+ if( eir_type == type )
+ {
+ /* length doesn't include itself */
+ *p_length = length - 1; /* minus the length of type */
+ return p;
+ }
+ p += length - 1; /* skip the length of data */
+ STREAM_TO_UINT8(length, p);
+ }
+
+ *p_length = 0;
+ return NULL;
+#else
+ return NULL;
+#endif
+}
+
+/*******************************************************************************
+**
+** Function btm_convert_uuid_to_eir_service
+**
+** Description This function is called to get the bit position of UUID.
+**
+** Parameters uuid16 - UUID 16-bit
+**
+** Returns BTM EIR service ID if found
+** BTM_EIR_MAX_SERVICES - if not found
+**
+*******************************************************************************/
+#if (( BTM_EIR_CLIENT_INCLUDED == TRUE )||( BTM_EIR_SERVER_INCLUDED == TRUE ))
+static UINT8 btm_convert_uuid_to_eir_service( UINT16 uuid16 )
+{
+ UINT8 xx;
+
+ for( xx = 0; xx < BTM_EIR_MAX_SERVICES; xx++ )
+ {
+ if( uuid16 == BTM_EIR_UUID_LKUP_TBL[xx])
+ {
+ return xx;
+ }
+ }
+ return BTM_EIR_MAX_SERVICES;
+}
+#endif
+
+/*******************************************************************************
+**
+** Function BTM_HasEirService
+**
+** Description This function is called to know if UUID in bit map of UUID.
+**
+** Parameters p_eir_uuid - bit map of UUID list
+** uuid16 - UUID 16-bit
+**
+** Returns TRUE - if found
+** FALSE - if not found
+**
+*******************************************************************************/
+BOOLEAN BTM_HasEirService( UINT32 *p_eir_uuid, UINT16 uuid16 )
+{
+#if ((BTM_EIR_SERVER_INCLUDED == TRUE)||(BTM_EIR_CLIENT_INCLUDED == TRUE))
+ UINT8 service_id;
+
+ service_id = btm_convert_uuid_to_eir_service(uuid16);
+ if( service_id < BTM_EIR_MAX_SERVICES )
+ return( BTM_EIR_HAS_SERVICE( p_eir_uuid, service_id ));
+ else
+ return( FALSE );
+#else
+ return( FALSE );
+#endif
+}
+
+/*******************************************************************************
+**
+** Function BTM_HasInquiryEirService
+**
+** Description This function is called to know if UUID in bit map of UUID list.
+**
+** Parameters p_results - inquiry results
+** uuid16 - UUID 16-bit
+**
+** Returns BTM_EIR_FOUND - if found
+** BTM_EIR_NOT_FOUND - if not found and it is complete list
+** BTM_EIR_UNKNOWN - if not found and it is not complete list
+**
+*******************************************************************************/
+tBTM_EIR_SEARCH_RESULT BTM_HasInquiryEirService( tBTM_INQ_RESULTS *p_results, UINT16 uuid16 )
+{
+#if ((BTM_EIR_SERVER_INCLUDED == TRUE)||(BTM_EIR_CLIENT_INCLUDED == TRUE))
+ if( BTM_HasEirService( p_results->eir_uuid, uuid16 ))
+ {
+ return BTM_EIR_FOUND;
+ }
+ else if( p_results->eir_complete_list )
+ {
+ return BTM_EIR_NOT_FOUND;
+ }
+ else
+ return BTM_EIR_UNKNOWN;
+#else
+ return BTM_EIR_UNKNOWN;
+#endif
+}
+
+/*******************************************************************************
+**
+** Function BTM_AddEirService
+**
+** Description This function is called to add a service in bit map of UUID list.
+**
+** Parameters p_eir_uuid - bit mask of UUID list for EIR
+** uuid16 - UUID 16-bit
+**
+** Returns None
+**
+*******************************************************************************/
+void BTM_AddEirService( UINT32 *p_eir_uuid, UINT16 uuid16 )
+{
+#if ((BTM_EIR_SERVER_INCLUDED == TRUE)||(BTM_EIR_CLIENT_INCLUDED == TRUE))
+ UINT8 service_id;
+
+ service_id = btm_convert_uuid_to_eir_service(uuid16);
+ if( service_id < BTM_EIR_MAX_SERVICES )
+ BTM_EIR_SET_SERVICE( p_eir_uuid, service_id );
+#endif
+}
+
+/*******************************************************************************
+**
+** Function BTM_RemoveEirService
+**
+** Description This function is called to remove a service in bit map of UUID list.
+**
+** Parameters p_eir_uuid - bit mask of UUID list for EIR
+** uuid16 - UUID 16-bit
+**
+** Returns None
+**
+*******************************************************************************/
+void BTM_RemoveEirService( UINT32 *p_eir_uuid, UINT16 uuid16 )
+{
+#if (BTM_EIR_SERVER_INCLUDED == TRUE)
+ UINT8 service_id;
+
+ service_id = btm_convert_uuid_to_eir_service(uuid16);
+ if( service_id < BTM_EIR_MAX_SERVICES )
+ BTM_EIR_CLR_SERVICE( p_eir_uuid, service_id );
+#endif
+}
+
+/*******************************************************************************
+**
+** Function BTM_GetEirSupportedServices
+**
+** Description This function is called to get UUID list from bit map of UUID list.
+**
+** Parameters p_eir_uuid - bit mask of UUID list for EIR
+** p - reference of current pointer of EIR
+** max_num_uuid16 - max number of UUID can be written in EIR
+** num_uuid16 - number of UUID have been written in EIR
+**
+** Returns BTM_EIR_MORE_16BITS_UUID_TYPE, if it has more than max
+** BTM_EIR_COMPLETE_16BITS_UUID_TYPE, otherwise
+**
+*******************************************************************************/
+UINT8 BTM_GetEirSupportedServices( UINT32 *p_eir_uuid, UINT8 **p,
+ UINT8 max_num_uuid16, UINT8 *p_num_uuid16)
+{
+#if (BTM_EIR_SERVER_INCLUDED == TRUE)
+ UINT8 service_index;
+
+ *p_num_uuid16 = 0;
+
+ for(service_index = 0; service_index < BTM_EIR_MAX_SERVICES; service_index++)
+ {
+ if( BTM_EIR_HAS_SERVICE( p_eir_uuid, service_index ))
+ {
+ if( *p_num_uuid16 < max_num_uuid16 )
+ {
+ UINT16_TO_STREAM(*p, BTM_EIR_UUID_LKUP_TBL[service_index]);
+ (*p_num_uuid16)++;
+ }
+ /* if max number of UUIDs are stored and found one more */
+ else
+ {
+ return BTM_EIR_MORE_16BITS_UUID_TYPE;
+ }
+ }
+ }
+ return BTM_EIR_COMPLETE_16BITS_UUID_TYPE;
+#else
+ return BTM_EIR_COMPLETE_16BITS_UUID_TYPE;
+#endif
+}
+
+/*******************************************************************************
+**
+** Function BTM_GetEirUuidList
+**
+** Description This function parses EIR and returns UUID list.
+**
+** Parameters p_eir - EIR
+** uuid_size - LEN_UUID_16, LEN_UUID_32, LEN_UUID_128
+** p_num_uuid - return number of UUID in found list
+** p_uuid_list - return UUID list
+** max_num_uuid - maximum number of UUID to be returned
+**
+** Returns 0 - if not found
+** BTM_EIR_COMPLETE_16BITS_UUID_TYPE
+** BTM_EIR_MORE_16BITS_UUID_TYPE
+** BTM_EIR_COMPLETE_32BITS_UUID_TYPE
+** BTM_EIR_MORE_32BITS_UUID_TYPE
+** BTM_EIR_COMPLETE_128BITS_UUID_TYPE
+** BTM_EIR_MORE_128BITS_UUID_TYPE
+**
+*******************************************************************************/
+UINT8 BTM_GetEirUuidList( UINT8 *p_eir, UINT8 uuid_size, UINT8 *p_num_uuid,
+ UINT8 *p_uuid_list, UINT8 max_num_uuid)
+{
+#if (BTM_EIR_CLIENT_INCLUDED == TRUE)
+ UINT8 *p_uuid_data;
+ UINT8 type;
+ UINT8 yy, xx;
+ UINT16 *p_uuid16 = (UINT16 *)p_uuid_list;
+ UINT32 *p_uuid32 = (UINT32 *)p_uuid_list;
+ char buff[LEN_UUID_128 * 2 + 1];
+
+ p_uuid_data = btm_eir_get_uuid_list( p_eir, uuid_size, p_num_uuid, &type );
+ if( p_uuid_data == NULL )
+ {
+ return 0x00;
+ }
+
+ if( *p_num_uuid > max_num_uuid )
+ {
+ BTM_TRACE_WARNING2("BTM_GetEirUuidList number of uuid in EIR = %d, size of uuid list = %d",
+ *p_num_uuid, max_num_uuid );
+ *p_num_uuid = max_num_uuid;
+ }
+
+ BTM_TRACE_DEBUG2("BTM_GetEirUuidList type = %02X, number of uuid = %d", type, *p_num_uuid );
+
+ if( uuid_size == LEN_UUID_16 )
+ {
+ for( yy = 0; yy < *p_num_uuid; yy++ )
+ {
+ STREAM_TO_UINT16(*(p_uuid16 + yy), p_uuid_data);
+ BTM_TRACE_DEBUG1(" 0x%04X", *(p_uuid16 + yy));
+ }
+ }
+ else if( uuid_size == LEN_UUID_32 )
+ {
+ for( yy = 0; yy < *p_num_uuid; yy++ )
+ {
+ STREAM_TO_UINT32(*(p_uuid32 + yy), p_uuid_data);
+ BTM_TRACE_DEBUG1(" 0x%08X", *(p_uuid32 + yy));
+ }
+ }
+ else if( uuid_size == LEN_UUID_128 )
+ {
+ for( yy = 0; yy < *p_num_uuid; yy++ )
+ {
+ STREAM_TO_ARRAY16(p_uuid_list + yy * LEN_UUID_128, p_uuid_data);
+ for( xx = 0; xx < LEN_UUID_128; xx++ )
+ sprintf(buff + xx*2, "%02X", *(p_uuid_list + yy * LEN_UUID_128 + xx));
+ BTM_TRACE_DEBUG1(" 0x%s", buff);
+ }
+ }
+
+ return type;
+#else
+ *p_num_uuid = 0;
+ return 0x00;
+#endif
+}
+
+
+#if (BTM_EIR_CLIENT_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function btm_eir_get_uuid_list
+**
+** Description This function searches UUID list in EIR.
+**
+** Parameters p_eir - address of EIR
+** uuid_size - size of UUID to find
+** p_num_uuid - number of UUIDs found
+** p_uuid_list_type - EIR data type
+**
+** Returns NULL - if UUID list with uuid_size is not found
+** beginning of UUID list in EIR - otherwise
+**
+*******************************************************************************/
+static UINT8 *btm_eir_get_uuid_list( UINT8 *p_eir, UINT8 uuid_size,
+ UINT8 *p_num_uuid, UINT8 *p_uuid_list_type )
+{
+ UINT8 *p_uuid_data;
+ UINT8 complete_type, more_type;
+ UINT8 uuid_len;
+
+ switch( uuid_size )
+ {
+ case LEN_UUID_16:
+ complete_type = BTM_EIR_COMPLETE_16BITS_UUID_TYPE;
+ more_type = BTM_EIR_MORE_16BITS_UUID_TYPE;
+ break;
+ case LEN_UUID_32:
+ complete_type = BTM_EIR_COMPLETE_32BITS_UUID_TYPE;
+ more_type = BTM_EIR_MORE_32BITS_UUID_TYPE;
+ break;
+ case LEN_UUID_128:
+ complete_type = BTM_EIR_COMPLETE_128BITS_UUID_TYPE;
+ more_type = BTM_EIR_MORE_128BITS_UUID_TYPE;
+ break;
+ default:
+ *p_num_uuid = 0;
+ return NULL;
+ break;
+ }
+
+ p_uuid_data = BTM_CheckEirData( p_eir, complete_type, &uuid_len );
+ if(p_uuid_data == NULL)
+ {
+ p_uuid_data = BTM_CheckEirData( p_eir, more_type, &uuid_len );
+ *p_uuid_list_type = more_type;
+ }
+ else
+ {
+ *p_uuid_list_type = complete_type;
+ }
+
+ *p_num_uuid = uuid_len / uuid_size;
+ return p_uuid_data;
+}
+
+/*******************************************************************************
+**
+** Function btm_convert_uuid_to_uuid16
+**
+** Description This function converts UUID to UUID 16-bit.
+**
+** Parameters p_uuid - address of UUID
+** uuid_size - size of UUID
+**
+** Returns 0 - if UUID cannot be converted to UUID 16-bit
+** UUID 16-bit - otherwise
+**
+*******************************************************************************/
+static UINT16 btm_convert_uuid_to_uuid16( UINT8 *p_uuid, UINT8 uuid_size )
+{
+ static const UINT8 base_uuid[LEN_UUID_128] = {0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ UINT16 uuid16 = 0;
+ UINT32 uuid32;
+ BOOLEAN is_base_uuid;
+ UINT8 xx;
+
+ switch (uuid_size)
+ {
+ case LEN_UUID_16:
+ STREAM_TO_UINT16 (uuid16, p_uuid);
+ break;
+ case LEN_UUID_32:
+ STREAM_TO_UINT32 (uuid32, p_uuid);
+ if (uuid32 < 0x10000)
+ uuid16 = (UINT16) uuid32;
+ break;
+ case LEN_UUID_128:
+ /* See if we can compress his UUID down to 16 or 32bit UUIDs */
+ is_base_uuid = TRUE;
+ for (xx = 0; xx < LEN_UUID_128 - 4; xx++)
+ {
+ if (p_uuid[xx] != base_uuid[xx])
+ {
+ is_base_uuid = FALSE;
+ break;
+ }
+ }
+ if (is_base_uuid)
+ {
+ if ((p_uuid[LEN_UUID_128 - 1] == 0) && (p_uuid[LEN_UUID_128 - 2] == 0))
+ {
+ p_uuid += (LEN_UUID_128 - 4);
+ STREAM_TO_UINT16(uuid16, p_uuid);
+ }
+ }
+ break;
+ default:
+ BTM_TRACE_WARNING0("btm_convert_uuid_to_uuid16 invalid uuid size");
+ break;
+ }
+
+ return( uuid16);
+}
+
+/*******************************************************************************
+**
+** Function btm_set_eir_uuid
+**
+** Description This function is called to store received UUID into inquiry result.
+**
+** Parameters p_eir - pointer of EIR significant part
+** p_results - pointer of inquiry result
+**
+** Returns None
+**
+*******************************************************************************/
+void btm_set_eir_uuid( UINT8 *p_eir, tBTM_INQ_RESULTS *p_results )
+{
+ UINT8 *p_uuid_data;
+ UINT8 num_uuid;
+ UINT16 uuid16;
+ UINT8 yy;
+ UINT8 type = BTM_EIR_MORE_16BITS_UUID_TYPE;
+
+ p_uuid_data = btm_eir_get_uuid_list( p_eir, LEN_UUID_16, &num_uuid, &type );
+
+ if(type == BTM_EIR_COMPLETE_16BITS_UUID_TYPE)
+ {
+ p_results->eir_complete_list = TRUE;
+ }
+ else
+ {
+ p_results->eir_complete_list = FALSE;
+ }
+
+ BTM_TRACE_API1("btm_set_eir_uuid eir_complete_list=0x%02X", p_results->eir_complete_list);
+
+ if( p_uuid_data )
+ {
+ for( yy = 0; yy < num_uuid; yy++ )
+ {
+ STREAM_TO_UINT16(uuid16, p_uuid_data);
+ BTM_AddEirService( p_results->eir_uuid, uuid16 );
+ }
+ }
+
+ p_uuid_data = btm_eir_get_uuid_list( p_eir, LEN_UUID_32, &num_uuid, &type );
+ if( p_uuid_data )
+ {
+ for( yy = 0; yy < num_uuid; yy++ )
+ {
+ uuid16 = btm_convert_uuid_to_uuid16( p_uuid_data, LEN_UUID_32 );
+ p_uuid_data += LEN_UUID_32;
+ if( uuid16 )
+ BTM_AddEirService( p_results->eir_uuid, uuid16 );
+ }
+ }
+
+ p_uuid_data = btm_eir_get_uuid_list( p_eir, LEN_UUID_128, &num_uuid, &type );
+ if( p_uuid_data )
+ {
+ for( yy = 0; yy < num_uuid; yy++ )
+ {
+ uuid16 = btm_convert_uuid_to_uuid16( p_uuid_data, LEN_UUID_128 );
+ p_uuid_data += LEN_UUID_128;
+ if( uuid16 )
+ BTM_AddEirService( p_results->eir_uuid, uuid16 );
+ }
+ }
+
+ BTM_TRACE_DEBUG2("btm_set_eir_uuid eir_uuid=0x%08X %08X",
+ p_results->eir_uuid[1], p_results->eir_uuid[0] );
+}
+#endif
+
diff --git a/stack/btm/btm_int.h b/stack/btm/btm_int.h
new file mode 100644
index 0000000..644359c
--- /dev/null
+++ b/stack/btm/btm_int.h
@@ -0,0 +1,1099 @@
+/*****************************************************************************
+**
+** Name: btm_int.h
+**
+** Description: this file contains the main Bluetooth Manager (BTM)
+** internal definitions.
+**
+** Copyright (c) 1999-2011, Broadcom Corp., All Rights Reserved
+** Broadcom Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+#ifndef BTM_INT_H
+#define BTM_INT_H
+
+#include "bt_target.h"
+#include "gki.h"
+#include "hcidefs.h"
+
+#if RFCOMM_INCLUDED == TRUE
+#include "rfcdefs.h"
+#endif
+
+#include "btm_api.h"
+
+#if (BLE_INCLUDED == TRUE)
+#include "btm_ble_int.h"
+#if (SMP_INCLUDED == TRUE)
+#include "smp_api.h"
+#endif
+#endif
+
+#if BTM_MAX_LOC_BD_NAME_LEN > 0
+typedef char tBTM_LOC_BD_NAME[BTM_MAX_LOC_BD_NAME_LEN + 1];
+#endif
+
+#define BTM_ACL_IS_CONNECTED(bda) (btm_bda_to_acl (bda) != NULL)
+
+/* Definitions for Server Channel Number (SCN) management
+*/
+#define BTM_MAX_SCN PORT_MAX_RFC_PORTS
+
+/* Define masks for supported and exception 2.0 ACL packet types
+*/
+#define BTM_ACL_SUPPORTED_PKTS_MASK (HCI_PKT_TYPES_MASK_DM1 | \
+ HCI_PKT_TYPES_MASK_DH1 | \
+ HCI_PKT_TYPES_MASK_DM3 | \
+ HCI_PKT_TYPES_MASK_DH3 | \
+ HCI_PKT_TYPES_MASK_DM5 | \
+ HCI_PKT_TYPES_MASK_DH5)
+
+#define BTM_ACL_EXCEPTION_PKTS_MASK (HCI_PKT_TYPES_MASK_NO_2_DH1 | \
+ HCI_PKT_TYPES_MASK_NO_3_DH1 | \
+ HCI_PKT_TYPES_MASK_NO_2_DH3 | \
+ HCI_PKT_TYPES_MASK_NO_3_DH3 | \
+ HCI_PKT_TYPES_MASK_NO_2_DH5 | \
+ HCI_PKT_TYPES_MASK_NO_3_DH5)
+
+#define BTM_EPR_AVAILABLE(p) ((HCI_ATOMIC_ENCRYPT_SUPPORTED((p)->features) && \
+ HCI_ATOMIC_ENCRYPT_SUPPORTED(btm_cb.devcb.local_features)) \
+ ? TRUE : FALSE)
+
+#define BTM_IS_BRCM_CONTROLLER() (btm_cb.devcb.local_version.manufacturer == LMP_COMPID_BROADCOM)
+
+
+/* Define the ACL Management control structure
+*/
+typedef struct
+{
+ UINT16 hci_handle;
+ UINT16 pkt_types_mask;
+ UINT16 restore_pkt_types; /* when coming in/out of SCO connection restore the packet types */
+ UINT16 clock_offset;
+ BD_ADDR remote_addr;
+ DEV_CLASS remote_dc;
+ BD_NAME remote_name;
+
+ UINT16 manufacturer;
+ UINT16 lmp_subversion;
+ UINT16 link_super_tout;
+ BD_FEATURES features; /* Features suported by the device */
+ UINT8 lmp_version;
+
+ BOOLEAN in_use;
+ UINT8 link_role;
+ BOOLEAN link_up_issued; /* True if busy_level link up has been issued */
+
+#define BTM_ACL_SWKEY_STATE_IDLE 0
+#define BTM_ACL_SWKEY_STATE_MODE_CHANGE 1
+#define BTM_ACL_SWKEY_STATE_ENCRYPTION_OFF 2
+#define BTM_ACL_SWKEY_STATE_SWITCHING 3
+#define BTM_ACL_SWKEY_STATE_ENCRYPTION_ON 4
+#define BTM_ACL_SWKEY_STATE_IN_PROGRESS 5
+ UINT8 switch_role_state;
+ UINT8 change_key_state;
+
+#define BTM_ACL_ENCRYPT_STATE_IDLE 0
+#define BTM_ACL_ENCRYPT_STATE_ENCRYPT_OFF 1 /* encryption turning off */
+#define BTM_ACL_ENCRYPT_STATE_TEMP_FUNC 2 /* temporarily off for change link key or role switch */
+#define BTM_ACL_ENCRYPT_STATE_ENCRYPT_ON 3 /* encryption turning on */
+ UINT8 encrypt_state; /* overall BTM encryption state */
+
+#if BTM_PWR_MGR_INCLUDED == FALSE
+ UINT8 mode;
+#endif /* BTM_PWR_MGR_INCLUDED */
+#if BLE_INCLUDED == TRUE
+ UINT8 is_le_link;
+#endif
+
+} tACL_CONN;
+
+/*****************************************************
+** TIMER Definitions
+******************************************************/
+#define TT_DEV_RESET 1
+#define TT_DEV_RLN 2
+#define TT_DEV_RLNKP 4 /* Read Link Policy Settings */
+
+/* Define the Device Management control structure
+*/
+typedef struct
+{
+ tBTM_DEV_STATUS_CB *p_dev_status_cb; /* Device status change callback */
+ tBTM_VS_EVT_CB *p_vend_spec_cb[BTM_MAX_VSE_CALLBACKS]; /* Register for vendor specific events */
+
+ tBTM_CMPL_CB *p_stored_link_key_cmpl_cb; /* Read/Write/Delete stored link key */
+
+ TIMER_LIST_ENT reset_timer;
+ tBTM_CMPL_CB *p_reset_cmpl_cb; /* Callback function to be called */
+ /* when startup of the device is done */
+ TIMER_LIST_ENT rln_timer;
+ tBTM_CMPL_CB *p_rln_cmpl_cb; /* Callback function to be called when */
+ /* read local name function complete */
+ TIMER_LIST_ENT rlinkp_timer;
+ tBTM_CMPL_CB *p_rlinkp_cmpl_cb; /* Callback function to be called when */
+ /* read link policy function completes */
+ TIMER_LIST_ENT rssi_timer;
+ tBTM_CMPL_CB *p_rssi_cmpl_cb; /* Callback function to be called when */
+ /* read rssi function completes */
+ TIMER_LIST_ENT lnk_quality_timer;
+ tBTM_CMPL_CB *p_lnk_qual_cmpl_cb;/* Callback function to be called when */
+ /* read link quality function completes */
+ TIMER_LIST_ENT txpwer_timer;
+ tBTM_CMPL_CB *p_txpwer_cmpl_cb; /* Callback function to be called when */
+ /* read inq tx power function completes */
+
+ TIMER_LIST_ENT qossu_timer;
+ tBTM_CMPL_CB *p_qossu_cmpl_cb; /* Callback function to be called when */
+ /* qos setup function completes */
+
+ tBTM_ROLE_SWITCH_CMPL switch_role_ref_data;
+ tBTM_CMPL_CB *p_switch_role_cb; /* Callback function to be called when */
+ /* requested switch role is completed */
+
+ tBTM_CHANGE_KEY_CMPL chg_link_key_ref_data;
+ tBTM_CMPL_CB *p_chg_link_key_cb; /* Callback function to be called when */
+ /* change of link key is completed */
+
+ TIMER_LIST_ENT tx_power_timer;
+ tBTM_CMPL_CB *p_tx_power_cmpl_cb; /* Callback function to be called */
+
+ BD_ADDR local_addr; /* BD_ADDR of the local device */
+ tBTM_VERSION_INFO local_version; /* Local Version Information */
+ BD_FEATURES local_features; /* Local features bit mask */
+ DEV_CLASS dev_class; /* Local device class */
+#if BLE_INCLUDED == TRUE
+ BD_ADDR read_tx_pwr_addr; /* read TX power target address */
+
+ tBTM_BLE_LOCAL_ID_KEYS id_keys; /* local BLE ID keys */
+ BT_OCTET16 er; /* BLE encryption key */
+
+#if BTM_BLE_CONFORMANCE_TESTING == TRUE
+ BOOLEAN no_disc_if_pair_fail;
+ BOOLEAN enable_test_mac_val;
+ BT_OCTET8 test_mac;
+ BOOLEAN enable_test_local_sign_cntr;
+ UINT32 test_local_sign_cntr;
+#endif
+
+
+#endif /* BLE_INCLUDED */
+
+#define BTM_DEV_STATE_WAIT_RESET_CMPLT 0
+#define BTM_DEV_STATE_WAIT_AFTER_RESET 1
+#define BTM_DEV_STATE_READY 2
+
+ UINT8 state;
+ tBTM_IO_CAP loc_io_caps; /* IO capability of the local device */
+ BOOLEAN loc_auth_req; /* the auth_req flag */
+ BD_FEATURES brcm_features; /* Broadcom specific features bit mask */
+} tBTM_DEVCB;
+
+
+/* Define the structures and constants used for inquiry
+*/
+
+/* Definitions of limits for inquiries */
+#define BTM_PER_INQ_MIN_MAX_PERIOD HCI_PER_INQ_MIN_MAX_PERIOD
+#define BTM_PER_INQ_MAX_MAX_PERIOD HCI_PER_INQ_MAX_MAX_PERIOD
+#define BTM_PER_INQ_MIN_MIN_PERIOD HCI_PER_INQ_MIN_MIN_PERIOD
+#define BTM_PER_INQ_MAX_MIN_PERIOD HCI_PER_INQ_MAX_MIN_PERIOD
+#define BTM_MAX_INQUIRY_LENGTH HCI_MAX_INQUIRY_LENGTH
+#define BTM_MIN_INQUIRY_LEN 0x01
+
+#define BTM_MIN_INQ_TX_POWER -70
+#define BTM_MAX_INQ_TX_POWER 20
+
+#if BTM_USE_INQ_RESULTS_FILTER == TRUE
+typedef struct
+{
+ UINT32 inq_count; /* Used for determining if a response has already been */
+ /* received for the current inquiry operation. (We do not */
+ /* want to flood the caller with multiple responses from */
+ /* the same device. */
+ BD_ADDR bd_addr;
+} tINQ_BDADDR;
+#endif
+
+typedef struct
+{
+ UINT32 time_of_resp;
+ UINT32 inq_count; /* "timestamps" the entry with a particular inquiry count */
+ /* Used for determining if a response has already been */
+ /* received for the current inquiry operation. (We do not */
+ /* want to flood the caller with multiple responses from */
+ /* the same device. */
+ tBTM_INQ_INFO inq_info;
+ BOOLEAN in_use;
+
+#if (BLE_INCLUDED == TRUE)
+ BOOLEAN scan_rsp;
+#endif
+} tINQ_DB_ENT;
+
+
+typedef struct
+{
+ tBTM_CMPL_CB *p_remname_cmpl_cb;
+
+#define BTM_EXT_RMT_NAME_TIMEOUT 40
+
+
+ TIMER_LIST_ENT rmt_name_timer_ent;
+
+ UINT16 discoverable_mode;
+ UINT16 connectable_mode;
+ UINT16 page_scan_window;
+ UINT16 page_scan_period;
+ UINT16 inq_scan_window;
+ UINT16 inq_scan_period;
+ UINT16 inq_scan_type;
+ UINT16 page_scan_type; /* current page scan type */
+
+ BD_ADDR remname_bda; /* Name of bd addr for active remote name request */
+#define BTM_RMT_NAME_INACTIVE 0
+#define BTM_RMT_NAME_EXT 0x1 /* Initiated through API */
+#define BTM_RMT_NAME_SEC 0x2 /* Initiated internally by security manager */
+#define BTM_RMT_NAME_INQ 0x4 /* Remote name initiated internally by inquiry */
+ BOOLEAN remname_active; /* State of a remote name request by external API */
+
+ tBTM_CMPL_CB *p_inq_cmpl_cb;
+ tBTM_INQ_RESULTS_CB *p_inq_results_cb;
+ tBTM_CMPL_CB *p_inqfilter_cmpl_cb; /* Called (if not NULL) after inquiry filter completed */
+ tBTM_INQ_DB_CHANGE_CB *p_inq_change_cb; /* Inquiry database changed callback */
+ UINT32 inq_counter; /* Counter incremented each time an inquiry completes */
+ /* Used for determining whether or not duplicate devices */
+ /* have responded to the same inquiry */
+ TIMER_LIST_ENT inq_timer_ent;
+#if BTM_USE_INQ_RESULTS_FILTER == TRUE
+ tINQ_BDADDR *p_bd_db; /* Pointer to memory that holds bdaddrs */
+ UINT16 num_bd_entries; /* Number of entries in database */
+ UINT16 max_bd_entries; /* Maximum number of entries that can be stored */
+#endif
+ tINQ_DB_ENT inq_db[BTM_INQ_DB_SIZE];
+ tBTM_INQ_PARMS inqparms; /* Contains the parameters for the current inquiry */
+ tBTM_INQUIRY_CMPL inq_cmpl_info; /* Status and number of responses from the last inquiry */
+
+ UINT16 per_min_delay; /* Current periodic minimum delay */
+ UINT16 per_max_delay; /* Current periodic maximum delay */
+ BOOLEAN inqfilt_active;
+ UINT8 pending_filt_complete_event; /* to take care of btm_event_filter_complete corresponding to */
+ /* inquiry that has been cancelled*/
+ UINT8 inqfilt_type; /* Contains the inquiry filter type (BD ADDR, COD, or Clear) */
+
+#define BTM_INQ_INACTIVE_STATE 0
+#define BTM_INQ_CLR_FILT_STATE 1 /* Currently clearing the inquiry filter preceeding the inquiry request */
+ /* (bypassed if filtering is not used) */
+#define BTM_INQ_SET_FILT_STATE 2 /* Sets the new filter (or turns off filtering) in this state */
+#define BTM_INQ_ACTIVE_STATE 3 /* Actual inquiry or periodic inquiry is in progress */
+#define BTM_INQ_REMNAME_STATE 4 /* Remote name requests are active */
+
+ UINT8 state; /* Current state that the inquiry process is in */
+ UINT8 inq_active; /* Bit Mask indicating type of inquiry is active */
+ BOOLEAN no_inc_ssp; /* TRUE, to stop inquiry on incoming SSP */
+} tBTM_INQUIRY_VAR_ST;
+
+/* The MSB of the clock offset field indicates that the offset is valid if TRUE */
+#define BTM_CLOCK_OFFSET_VALID 0x8000
+
+/* Define the structures needed by security management
+*/
+
+#define BTM_SEC_INVALID_HANDLE 0xFFFF
+
+typedef UINT8 *BTM_BD_NAME_PTR; /* Pointer to Device name */
+
+/* Security callback is called by this unit when security
+** procedures are completed. Parameters are
+** BD Address of remote
+** Result of the operation
+*/
+typedef tBTM_SEC_CBACK tBTM_SEC_CALLBACK;
+
+typedef void (tBTM_SCO_IND_CBACK) (UINT16 sco_inx) ;
+
+/* MACROs to convert from SCO packet types mask to ESCO and back */
+#define BTM_SCO_PKT_TYPE_MASK ( HCI_PKT_TYPES_MASK_HV1 \
+ | HCI_PKT_TYPES_MASK_HV2 \
+ | HCI_PKT_TYPES_MASK_HV3)
+
+/* Mask defining only the SCO types of an esco packet type */
+#define BTM_ESCO_PKT_TYPE_MASK ( HCI_ESCO_PKT_TYPES_MASK_HV1 \
+ | HCI_ESCO_PKT_TYPES_MASK_HV2 \
+ | HCI_ESCO_PKT_TYPES_MASK_HV3)
+
+#define BTM_SCO_2_ESCO(scotype) ((UINT16)(((scotype) & BTM_SCO_PKT_TYPE_MASK) >> 5))
+#define BTM_ESCO_2_SCO(escotype) ((UINT16)(((escotype) & BTM_ESCO_PKT_TYPE_MASK) << 5))
+
+/* Define masks for supported and exception 2.0 SCO packet types
+*/
+#define BTM_SCO_SUPPORTED_PKTS_MASK (HCI_ESCO_PKT_TYPES_MASK_HV1 | \
+ HCI_ESCO_PKT_TYPES_MASK_HV2 | \
+ HCI_ESCO_PKT_TYPES_MASK_HV3 | \
+ HCI_ESCO_PKT_TYPES_MASK_EV3 | \
+ HCI_ESCO_PKT_TYPES_MASK_EV4 | \
+ HCI_ESCO_PKT_TYPES_MASK_EV5)
+
+#define BTM_SCO_EXCEPTION_PKTS_MASK (HCI_ESCO_PKT_TYPES_MASK_NO_2_EV3 | \
+ HCI_ESCO_PKT_TYPES_MASK_NO_3_EV3 | \
+ HCI_ESCO_PKT_TYPES_MASK_NO_2_EV5 | \
+ HCI_ESCO_PKT_TYPES_MASK_NO_3_EV5)
+
+
+#define BTM_SCO_ROUTE_UNKNOWN 0xff
+
+/* Define the structure that contains (e)SCO data */
+typedef struct
+{
+ tBTM_ESCO_CBACK *p_esco_cback; /* Callback for eSCO events */
+ tBTM_ESCO_PARAMS setup;
+ tBTM_ESCO_DATA data; /* Connection complete information */
+ UINT8 hci_status;
+} tBTM_ESCO_INFO;
+
+/* Define the structure used for SCO Management
+*/
+typedef struct
+{
+ tBTM_ESCO_INFO esco; /* Current settings */
+#if BTM_SCO_HCI_INCLUDED == TRUE
+ BUFFER_Q xmit_data_q; /* SCO data transmitting queue */
+#endif
+ tBTM_SCO_CB *p_conn_cb; /* Callback for when connected */
+ tBTM_SCO_CB *p_disc_cb; /* Callback for when disconnect */
+ UINT16 state; /* The state of the SCO link */
+ UINT16 hci_handle; /* HCI Handle */
+ BOOLEAN is_orig; /* TRUE if the originator */
+ BOOLEAN rem_bd_known; /* TRUE if remote BD addr known */
+
+} tSCO_CONN;
+
+/* SCO Management control block */
+typedef struct
+{
+ tBTM_SCO_IND_CBACK *app_sco_ind_cb;
+#if BTM_SCO_HCI_INCLUDED == TRUE
+ tBTM_SCO_DATA_CB *p_data_cb; /* Callback for SCO data over HCI */
+ UINT32 xmit_window_size; /* Total SCO window in bytes */
+#endif
+ tSCO_CONN sco_db[BTM_MAX_SCO_LINKS];
+ tBTM_ESCO_PARAMS def_esco_parms;
+ BD_ADDR xfer_addr;
+ UINT16 sco_disc_reason;
+ BOOLEAN esco_supported; /* TRUE if 1.2 cntlr AND supports eSCO links */
+ tBTM_SCO_TYPE desired_sco_mode;
+ tBTM_SCO_TYPE xfer_sco_type;
+ tBTM_SCO_PCM_PARAM sco_pcm_param;
+ tBTM_SCO_CODEC_TYPE codec_in_use; /* None, CVSD, MSBC, etc. */
+#if BTM_SCO_HCI_INCLUDED == TRUE
+ tBTM_SCO_ROUTE_TYPE sco_path;
+#endif
+
+} tSCO_CB;
+
+
+#if BTM_SCO_INCLUDED == TRUE
+extern void btm_set_sco_ind_cback( tBTM_SCO_IND_CBACK *sco_ind_cb );
+extern void btm_accept_sco_link(UINT16 sco_inx, tBTM_ESCO_PARAMS *p_setup,
+ tBTM_SCO_CB *p_conn_cb, tBTM_SCO_CB *p_disc_cb);
+extern void btm_reject_sco_link(UINT16 sco_inx );
+extern void btm_sco_chk_pend_rolechange (UINT16 hci_handle);
+#else
+#define btm_accept_sco_link(sco_inx, p_setup, p_conn_cb, p_disc_cb)
+#define btm_reject_sco_link(sco_inx)
+#define btm_set_sco_ind_cback(sco_ind_cb)
+#define btm_sco_chk_pend_rolechange(hci_handle)
+#endif /* BTM_SCO_INCLUDED */
+
+/*
+** Define structure for Security Service Record.
+** A record exists for each service registered with the Security Manager
+*/
+typedef struct
+{
+ UINT32 mx_proto_id; /* Service runs over this multiplexer protocol */
+ UINT32 orig_mx_chan_id; /* Channel on the multiplexer protocol */
+ UINT32 term_mx_chan_id; /* Channel on the multiplexer protocol */
+ UINT16 psm; /* L2CAP PSM value */
+ UINT16 security_flags; /* Bitmap of required security features */
+ UINT8 service_id; /* Passed in authorization callback */
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ UINT16 ucd_security_flags; /* Bitmap of required security features for UCD */
+#endif
+#if BTM_SEC_SERVICE_NAME_LEN > 0
+ UINT8 orig_service_name[BTM_SEC_SERVICE_NAME_LEN + 1];
+ UINT8 term_service_name[BTM_SEC_SERVICE_NAME_LEN + 1];
+#endif
+} tBTM_SEC_SERV_REC;
+
+#if BLE_INCLUDED == TRUE
+/* LE Security information of device in Slave Role */
+typedef struct
+{
+ BT_OCTET16 irk; /* peer diverified identity root */
+ BT_OCTET16 ltk; /* peer long term key */
+ BT_OCTET16 csrk; /* peer SRK peer device used to secured sign local data */
+
+ BT_OCTET8 rand; /* random vector for LTK generation */
+ UINT16 ediv; /* LTK diversifier of this slave device */
+ UINT16 div; /* local DIV to generate local LTK=d1(ER,DIV,0) and CSRK=d1(ER,DIV,1) */
+ UINT8 sec_level; /* local pairing security level */
+ UINT8 key_size; /* key size of the LTK delivered to peer device */
+ UINT8 srk_sec_level; /* security property of peer SRK for this device */
+ UINT8 local_csrk_sec_level; /* security property of local CSRK for this device */
+
+ UINT32 counter; /* peer sign counter for verifying rcv signed cmd */
+ UINT32 local_counter; /* local sign counter for sending signed write cmd*/
+}tBTM_SEC_BLE_KEYS;
+
+#endif /* BLE_INCLUDED */
+
+typedef struct
+{
+ tBLE_ADDR_TYPE ble_addr_type; /* LE device type: public or random address */
+ BD_ADDR reconn_addr; /* reconnect address */
+ BD_ADDR cur_rand_addr; /* current random address */
+ BD_ADDR static_addr; /* static address */
+
+#if SMP_INCLUDED == TRUE
+ tBTM_LE_KEY_TYPE key_type; /* bit mask of valid key types in record */
+ tBTM_SEC_BLE_KEYS keys; /* LE device security info in slave rode */
+#endif
+} tBTM_SEC_BLE;
+
+/*
+** Define structure for Security Device Record.
+** A record exists for each device authenticated with this device
+*/
+typedef struct
+{
+ tBTM_SEC_SERV_REC *p_cur_service;
+ tBTM_SEC_CALLBACK *p_callback;
+ void *p_ref_data;
+ UINT32 timestamp; /* Timestamp of the last connection */
+ UINT32 trusted_mask[BTM_SEC_SERVICE_ARRAY_SIZE]; /* Bitwise OR of trusted services */
+ UINT16 hci_handle; /* Handle to connection when exists */
+ UINT16 clock_offset; /* Latest known clock offset */
+ BD_ADDR bd_addr; /* BD_ADDR of the device */
+ DEV_CLASS dev_class; /* DEV_CLASS of the device */
+ LINK_KEY link_key; /* Device link key */
+
+#define BTM_SEC_AUTHORIZED BTM_SEC_FLAG_AUTHORIZED
+#define BTM_SEC_AUTHENTICATED BTM_SEC_FLAG_AUTHENTICATED
+#define BTM_SEC_ENCRYPTED BTM_SEC_FLAG_ENCRYPTED
+#define BTM_SEC_NAME_KNOWN 0x08
+#define BTM_SEC_LINK_KEY_KNOWN BTM_SEC_FLAG_LKEY_KNOWN
+#define BTM_SEC_LINK_KEY_AUTHED 0x20
+#define BTM_SEC_ROLE_SWITCHED 0x40
+#define BTM_SEC_IN_USE 0x80
+
+ tBTM_BD_NAME sec_bd_name; /* User friendly name of the device. (may be truncated to save space in dev_rec table) */
+ UINT8 sec_flags; /* Current device security state */
+ BD_FEATURES features; /* Features suported by the device */
+
+#define BTM_SEC_STATE_IDLE 0
+#define BTM_SEC_STATE_AUTHENTICATING 1
+#define BTM_SEC_STATE_ENCRYPTING 2
+#define BTM_SEC_STATE_GETTING_NAME 3
+#define BTM_SEC_STATE_AUTHORIZING 4
+#define BTM_SEC_STATE_SWITCHING_ROLE 5
+#define BTM_SEC_STATE_DISCONNECTING 6
+#define BTM_SEC_STATE_DELAY_FOR_ENC 7 /* delay to check for encryption to work around controller problems */
+
+ UINT8 sec_state; /* Operating state */
+ BOOLEAN is_originator; /* TRUE if device is originating connection */
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ BOOLEAN is_ucd; /* TRUE if device is sending or receiving UCD */
+ /* if incoming security failed, received UCD will be discarded */
+#endif
+ BOOLEAN role_master; /* TRUE if current mode is master */
+ UINT16 security_required; /* Security required for connection */
+ BOOLEAN link_key_not_sent; /* link key notification has not been sent waiting for name */
+ UINT8 link_key_type; /* Type of key used in pairing */
+ BOOLEAN link_key_changed; /* Changed link key during current connection */
+
+#define BTM_SM4_UNKNOWN 0x00
+#define BTM_SM4_KNOWN 0x10
+#define BTM_SM4_TRUE 0x11
+#define BTM_SM4_REQ_PEND 0x08 /* set this bit when getting remote features */
+#define BTM_SM4_UPGRADE 0x04 /* set this bit when upgrading link key */
+#define BTM_SM4_RETRY 0x02 /* set this bit to retry on HCI_ERR_KEY_MISSING or HCI_ERR_LMP_ERR_TRANS_COLLISION */
+#define BTM_SM4_DD_ACP 0x20 /* set this bit to indicate peer initiated dedicated bonding */
+#define BTM_SM4_CONN_PEND 0x40 /* set this bit to indicate accepting acl conn; to be cleared on btm_acl_created */
+ UINT8 sm4; /* BTM_SM4_TRUE, if the peer supports SM4 */
+ tBTM_IO_CAP rmt_io_caps; /* IO capability of the peer device */
+ BOOLEAN rmt_auth_req; /* the auth_req flag as in the IO caps rsp evt */
+
+#if (BLE_INCLUDED == TRUE)
+ UINT8 enc_key_size; /* current link encryption key size */
+ tBTM_SEC_BLE ble;
+ tBT_DEVICE_TYPE device_type;
+ tBTM_LE_CONN_PRAMS conn_params;
+#endif
+
+// btla-specific ++
+#if BTM_DISC_DURING_RS == TRUE
+#define BTM_SEC_RS_NOT_PENDING 0 /* Role Switch not in progress */
+#define BTM_SEC_RS_PENDING 1 /* Role Switch in progress */
+#define BTM_SEC_DISC_PENDING 2 /* Disconnect is pending */
+ UINT8 rs_disc_pending;
+#endif
+// btla-specific --
+} tBTM_SEC_DEV_REC;
+
+#define BTM_SEC_IS_SM4(sm) ((BOOLEAN)(BTM_SM4_TRUE == ((sm)&BTM_SM4_TRUE)))
+#define BTM_SEC_IS_SM4_LEGACY(sm) ((BOOLEAN)(BTM_SM4_KNOWN == ((sm)&BTM_SM4_TRUE)))
+#define BTM_SEC_IS_SM4_UNKNOWN(sm) ((BOOLEAN)(BTM_SM4_UNKNOWN == ((sm)&BTM_SM4_TRUE)))
+
+
+/*
+** Define device configuration structure
+*/
+typedef struct
+{
+#if BTM_MAX_LOC_BD_NAME_LEN > 0
+ tBTM_LOC_BD_NAME bd_name; /* local Bluetooth device name */
+#endif
+ BOOLEAN pin_type; /* TRUE if PIN type is fixed */
+ UINT8 pin_code_len; /* Bonding information */
+ PIN_CODE pin_code; /* PIN CODE if pin type is fixed */
+ BOOLEAN connectable; /* If TRUE page scan should be enabled */
+ UINT8 def_inq_scan_mode; /* ??? limited/general/none */
+} tBTM_CFG;
+
+#if BTM_PWR_MGR_INCLUDED == TRUE
+enum
+{
+ BTM_PM_ST_ACTIVE = BTM_PM_STS_ACTIVE,
+ BTM_PM_ST_HOLD = BTM_PM_STS_HOLD,
+ BTM_PM_ST_SNIFF = BTM_PM_STS_SNIFF,
+ BTM_PM_ST_PARK = BTM_PM_STS_PARK,
+ BTM_PM_ST_PENDING = BTM_PM_STS_PENDING
+};
+typedef UINT8 tBTM_PM_STATE;
+
+enum
+{
+ BTM_PM_SET_MODE_EVT, /* Set power mode API is called. */
+ BTM_PM_UPDATE_EVT,
+ BTM_PM_RD_MODE_EVT /* Read power mode API is called. */
+};
+typedef UINT8 tBTM_PM_EVENT;
+
+typedef struct
+{
+ UINT16 event;
+ UINT16 len;
+ UINT8 link_ind;
+} tBTM_PM_MSG_DATA;
+
+typedef struct
+{
+ UINT8 hci_status;
+ UINT8 mode;
+ UINT16 interval;
+} tBTM_PM_MD_CHG_DATA;
+
+typedef struct
+{
+ UINT8 pm_id; /* the entity that calls SetPowerMode API */
+ tBTM_PM_PWR_MD *p_pmd;
+} tBTM_PM_SET_MD_DATA;
+
+typedef struct
+{
+ void *p_data;
+ UINT8 link_ind;
+} tBTM_PM_SM_DATA;
+
+typedef struct
+{
+ tBTM_PM_PWR_MD req_mode[BTM_MAX_PM_RECORDS+1]; /* the desired mode and parameters of the connection*/
+ tBTM_PM_PWR_MD set_mode; /* the mode and parameters sent down to the host controller. */
+ UINT16 interval; /* the interval from last mode change event. */
+#if (BTM_SSR_INCLUDED == TRUE)
+ UINT16 max_lat; /* stored SSR maximum latency */
+ UINT16 min_rmt_to;/* stored SSR minimum remote timeout */
+ UINT16 min_loc_to;/* stored SSR minimum local timeout */
+#endif
+ tBTM_PM_STATE state; /* contains the current mode of the connection */
+ BOOLEAN chg_ind; /* a request change indication */
+} tBTM_PM_MCB;
+
+#define BTM_PM_REC_NOT_USED 0
+typedef struct
+{
+ tBTM_PM_STATUS_CBACK *cback;/* to notify the registered party of mode change event */
+ UINT8 mask; /* registered request mask. 0, if this entry is not used */
+} tBTM_PM_RCB;
+#endif /* BTM_PWR_MGR_INCLUDED */
+
+enum
+{
+ BTM_BLI_ACL_UP_EVT,
+ BTM_BLI_ACL_DOWN_EVT,
+ BTM_BLI_PAGE_EVT,
+ BTM_BLI_PAGE_DONE_EVT,
+ BTM_BLI_INQ_EVT,
+ BTM_BLI_INQ_DONE_EVT
+};
+typedef UINT8 tBTM_BLI_EVENT;
+
+/* Pairing State */
+enum
+{
+ BTM_PAIR_STATE_IDLE, /* Idle */
+ BTM_PAIR_STATE_GET_REM_NAME, /* Getting the remote name (to check for SM4) */
+ BTM_PAIR_STATE_WAIT_PIN_REQ, /* Started authentication, waiting for PIN req (PIN is pre-fetched) */
+ BTM_PAIR_STATE_WAIT_LOCAL_PIN, /* Waiting for local PIN code */
+ BTM_PAIR_STATE_WAIT_NUMERIC_CONFIRM, /* Waiting user 'yes' to numeric confirmation */
+ BTM_PAIR_STATE_KEY_ENTRY, /* Key entry state (we are a keyboard) */
+ BTM_PAIR_STATE_WAIT_LOCAL_OOB_RSP, /* Waiting for local response to peer OOB data */
+ BTM_PAIR_STATE_WAIT_LOCAL_IOCAPS, /* Waiting for local IO capabilities and OOB data */
+ BTM_PAIR_STATE_INCOMING_SSP, /* Incoming SSP (got peer IO caps when idle) */
+ BTM_PAIR_STATE_WAIT_AUTH_COMPLETE, /* All done, waiting authentication cpmplete */
+ BTM_PAIR_STATE_WAIT_DISCONNECT /* Waiting to disconnect the ACL */
+};
+typedef UINT8 tBTM_PAIRING_STATE;
+
+#define BTM_PAIR_FLAGS_WE_STARTED_DD 0x01 /* We want to do dedicated bonding */
+#define BTM_PAIR_FLAGS_PEER_STARTED_DD 0x02 /* Peer initiated dedicated bonding */
+#define BTM_PAIR_FLAGS_DISC_WHEN_DONE 0x04
+#define BTM_PAIR_FLAGS_PIN_REQD 0x08 /* set this bit when pin_callback is called */
+#define BTM_PAIR_FLAGS_PRE_FETCH_PIN 0x10 /* set this bit when pre-fetch pin */
+#define BTM_PAIR_FLAGS_REJECTED_CONNECT 0x20 /* set this bit when rejected incoming connection */
+
+typedef struct
+{
+ BOOLEAN is_mux;
+ BD_ADDR bd_addr;
+ UINT16 psm;
+ BOOLEAN is_orig;
+ tBTM_SEC_CALLBACK *p_callback;
+ void *p_ref_data;
+ UINT32 mx_proto_id;
+ UINT32 mx_chan_id;
+} tBTM_SEC_QUEUE_ENTRY;
+
+#if (L2CAP_UCD_INCLUDED == TRUE)
+
+#define CONN_ORIENT_TERM 0x00 /* incoming connection oriented */
+#define CONN_ORIENT_ORIG 0x01 /* outgoing connection oriented */
+#define CONNLESS_TERM 0x02 /* incoming connectionless */
+#define CONNLESS_ORIG 0x03 /* outgoing connectionless */
+#define CONNECTION_TYPE_ORIG_MASK 0x01 /* mask for direction */
+#define CONNECTION_TYPE_CONNLESS_MASK 0x02 /* mask for connectionless or not */
+typedef UINT8 CONNECTION_TYPE;
+
+#else
+
+#define CONN_ORIENT_TERM FALSE
+#define CONN_ORIENT_ORIG TRUE
+typedef BOOLEAN CONNECTION_TYPE;
+
+#endif /* (L2CAP_UCD_INCLUDED == TRUE) */
+
+/* Define a structure to hold all the BTM data
+*/
+
+#define BTM_STATE_BUFFER_SIZE 5 /* size of state buffer */
+
+#if (BTM_PCM2_INCLUDED == TRUE)
+/* Define pcm2_action */
+enum
+{
+ BTM_PCM2_ACT_NONE,
+ BTM_PCM2_ACT_SENT_ARC,
+ BTM_PCM2_READ_PARAM,
+ BTM_PCM2_WRITE_PARAM,
+};
+typedef UINT8 tBTM_PCM2_ACTION;
+#endif
+
+typedef struct
+{
+ tBTM_CFG cfg; /* Device configuration */
+
+ /****************************************************
+ ** ACL Management
+ ****************************************************/
+ tACL_CONN acl_db[MAX_L2CAP_LINKS];
+#if( RFCOMM_INCLUDED==TRUE)
+ UINT8 btm_scn[BTM_MAX_SCN]; /* current SCNs: TRUE if SCN is in use */
+#endif
+ UINT16 btm_def_link_policy;
+ UINT16 btm_def_link_super_tout;
+
+#if (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE)
+ tBTM_BL_EVENT_MASK bl_evt_mask;
+ tBTM_BL_CHANGE_CB *p_bl_changed_cb; /* Callback for when Busy Level changed */
+#else
+ tBTM_ACL_DB_CHANGE_CB *p_acl_changed_cb; /* Callback for when ACL DB changed */
+#endif
+
+ tBTM_LSTO_CBACK *p_lsto_cback; /* for link supervision timeout change event */
+
+ /****************************************************
+ ** Power Management
+ ****************************************************/
+#if BTM_PWR_MGR_INCLUDED == TRUE
+ tBTM_PM_MCB pm_mode_db[MAX_L2CAP_LINKS]; /* per ACL link */
+ tBTM_PM_RCB pm_reg_db[BTM_MAX_PM_RECORDS+1]; /* per application/module */
+ UINT8 pm_pend_link; /* the index of acl_db, which has a pending PM cmd */
+ UINT8 pm_pend_id; /* the id pf the module, which has a pending PM cmd */
+#endif /* BTM_PWR_MGR_INCLUDED == TRUE */
+
+ /*****************************************************
+ ** Device control
+ *****************************************************/
+ tBTM_DEVCB devcb;
+
+ /*****************************************************
+ ** BLE Device controllers
+ *****************************************************/
+#if (BLE_INCLUDED == TRUE)
+ tBTM_BLE_CB ble_ctr_cb;
+
+ UINT16 enc_handle;
+ BT_OCTET8 enc_rand; /* received rand value from LTK request*/
+ UINT16 ediv; /* received ediv value from LTK request */
+ UINT8 key_size;
+#endif
+
+ /* Packet types supported by the local device */
+ UINT16 btm_acl_pkt_types_supported;
+ UINT16 btm_sco_pkt_types_supported;
+
+
+ /*****************************************************
+ ** Inquiry
+ *****************************************************/
+ tBTM_INQUIRY_VAR_ST btm_inq_vars;
+ tBTM_FILTER_CB *p_inq_filter_cb; /* Callback that can be set if host */
+ /* wants to verify inquiry filters */
+
+ /*****************************************************
+ ** SCO Management
+ *****************************************************/
+#if BTM_SCO_INCLUDED == TRUE
+ tSCO_CB sco_cb;
+#endif
+
+ /*****************************************************
+ ** Security Management
+ *****************************************************/
+ tBTM_APPL_INFO api;
+
+#define BTM_SEC_MAX_RMT_NAME_CALLBACKS 2
+ tBTM_RMT_NAME_CALLBACK *p_rmt_name_callback[BTM_SEC_MAX_RMT_NAME_CALLBACKS];
+
+ tBTM_FILTER_CB *p_conn_filter_cb; /* Callback that can be set if host */
+ /* wants to verify connectability filters*/
+
+ tBTM_SEC_DEV_REC *p_collided_dev_rec;
+ TIMER_LIST_ENT sec_collision_tle;
+ UINT32 collision_start_time;
+ UINT32 max_collision_delay;
+ UINT32 dev_rec_count; /* Counter used for device record timestamp */
+ UINT8 security_mode;
+ BOOLEAN pairing_disabled;
+ BOOLEAN connect_only_paired;
+ BOOLEAN security_mode_changed; /* mode changed during bonding */
+ BOOLEAN pin_type_changed; /* pin type changed during bonding */
+ BOOLEAN sec_req_pending; /* TRUE if a request is pending */
+// btla-specific ++
+#ifdef PORCHE_PAIRING_CONFLICT
+ UINT8 pin_code_len_saved; /* for legacy devices */
+#endif
+// btla-specific --
+
+ UINT8 pin_code_len; /* for legacy devices */
+ PIN_CODE pin_code; /* for legacy devices */
+ tBTM_PAIRING_STATE pairing_state; /* The current pairing state */
+ UINT8 pairing_flags; /* The current pairing flags */
+ BD_ADDR pairing_bda; /* The device currently pairing */
+ TIMER_LIST_ENT pairing_tle; /* Timer for pairing process */
+ UINT16 disc_handle; /* for legacy devices */
+ UINT8 disc_reason; /* for legacy devices */
+ tBTM_SEC_SERV_REC sec_serv_rec[BTM_SEC_MAX_SERVICE_RECORDS];
+ tBTM_SEC_DEV_REC sec_dev_rec[BTM_SEC_MAX_DEVICE_RECORDS];
+ tBTM_SEC_SERV_REC *p_out_serv;
+ tBTM_MKEY_CALLBACK *mkey_cback;
+
+ BD_ADDR connecting_bda;
+ DEV_CLASS connecting_dc;
+
+ UINT8 first_disabled_channel;
+ UINT8 last_disabled_channel;
+
+ UINT8 acl_disc_reason;
+ UINT8 trace_level;
+#if (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE)
+ UINT8 num_acl; /* num of active ACL links */
+ UINT8 busy_level; /* the current busy level */
+ BOOLEAN is_paging; /* TRUE, if paging is in progess */
+ BOOLEAN is_inquiry; /* TRUE, if inquiry is in progess */
+#endif
+ BUFFER_Q page_queue;
+ BOOLEAN paging;
+ BOOLEAN discing;
+ BUFFER_Q sec_pending_q; /* pending sequrity requests in tBTM_SEC_QUEUE_ENTRY format */
+
+#if (!defined(BT_TRACE_VERBOSE) || (BT_TRACE_VERBOSE == FALSE))
+ char state_temp_buffer[BTM_STATE_BUFFER_SIZE];
+#endif
+
+#if (defined(BTM_PCM2_INCLUDED) && BTM_PCM2_INCLUDED == TRUE)
+ UINT16 sys_features;
+ UINT8 pcm2_params[BRCM_PCM2_SETUP_WRITE_SIZE];
+ tBTM_PCM2_ACTION pcm2_action;
+#endif
+
+} tBTM_CB;
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#if BTM_DYNAMIC_MEMORY == FALSE
+BTM_API extern tBTM_CB btm_cb;
+#else
+BTM_API extern tBTM_CB *btm_cb_ptr;
+#define btm_cb (*btm_cb_ptr)
+#endif
+
+/* Internal functions provided by btm_main.c
+********************************************
+*/
+extern void btm_init (void);
+
+/* Internal functions provided by btm_inq.c
+*******************************************
+*/
+extern tBTM_STATUS btm_initiate_rem_name (BD_ADDR remote_bda,
+ tBTM_INQ_INFO *p_cur,
+ UINT8 origin, UINT32 timeout,
+ tBTM_CMPL_CB *p_cb);
+
+extern void btm_process_remote_name (BD_ADDR bda, BD_NAME name, UINT16 evt_len,
+ UINT8 hci_status);
+extern void btm_inq_rmt_name_failed(void);
+
+/* Inquiry related functions */
+extern void btm_clr_inq_db (BD_ADDR p_bda);
+extern void btm_inq_db_init (void);
+extern void btm_process_inq_results (UINT8 *p, UINT8 inq_res_mode);
+extern void btm_process_inq_complete (UINT8 status, UINT8 mode);
+extern void btm_event_filter_complete (UINT8 *p);
+extern void btm_inq_stop_on_ssp(void);
+extern void btm_inq_clear_ssp(void);
+extern tINQ_DB_ENT *btm_inq_db_find (BD_ADDR p_bda);
+extern BOOLEAN btm_inq_find_bdaddr (BD_ADDR p_bda);
+
+#if (BTM_EIR_CLIENT_INCLUDED == TRUE)
+extern BOOLEAN btm_lookup_eir(BD_ADDR_PTR p_rem_addr);
+#endif
+
+/* Internal functions provided by btm_acl.c
+********************************************
+*/
+extern void btm_acl_init (void);
+extern void btm_acl_timeout (TIMER_LIST_ENT *p_tle);
+extern void btm_acl_created (BD_ADDR bda, DEV_CLASS dc, BD_NAME bdn,
+ UINT16 hci_handle, UINT8 link_role, UINT8 is_le_link);
+extern void btm_acl_removed (BD_ADDR bda);
+extern void btm_acl_device_down (void);
+extern void btm_acl_update_busy_level (tBTM_BLI_EVENT event);
+extern void btm_acl_link_key_change (UINT16 handle, UINT8 status);
+
+extern void btm_cont_rswitch_or_chglinkkey (tACL_CONN *p,
+ tBTM_SEC_DEV_REC *p_dev_rec,
+ UINT8 hci_status);
+
+extern UINT8 btm_handle_to_acl_index (UINT16 hci_handle);
+extern void btm_read_link_policy_complete (UINT8 *p);
+extern void btm_read_rssi_complete (UINT8 *p);
+extern void btm_read_tx_power_complete (UINT8 *p, BOOLEAN is_ble);
+extern void btm_read_link_quality_complete (UINT8 *p);
+extern tBTM_STATUS btm_set_packet_types (tACL_CONN *p, UINT16 pkt_types);
+extern void btm_process_clk_off_comp_evt (UINT16 hci_handle, UINT16 clock_offset);
+extern void btm_acl_role_changed (UINT8 hci_status, BD_ADDR bd_addr, UINT8 new_role);
+extern void btm_acl_encrypt_change (UINT16 handle, UINT8 status, UINT8 encr_enable);
+BTM_API extern UINT16 btm_get_acl_disc_reason_code (void);
+BTM_API extern tBTM_STATUS btm_remove_acl (BD_ADDR bd_addr);
+extern void btm_read_remote_features_complete (UINT8 *p);
+extern void btm_read_remote_ext_features_complete (UINT8 *p);
+extern void btm_read_remote_ext_features_failed (UINT8 status);
+extern void btm_read_remote_version_complete (UINT8 *p);
+// btla-specific ++
+extern void btm_acl_chk_peer_pkt_type_support (tACL_CONN *p, UINT16 *p_pkt_type);
+// btla-specific --
+/* Read maximum data packet that can be sent over current connection */
+extern UINT16 btm_get_max_packet_size (BD_ADDR addr);
+extern tACL_CONN *btm_bda_to_acl (BD_ADDR bda);
+extern BOOLEAN btm_acl_notif_conn_collision (BD_ADDR bda);
+
+#if BTM_PWR_MGR_INCLUDED == FALSE
+extern void btm_process_mode_change (UINT8 hci_status, UINT16 hci_handle, UINT8 mode,
+ UINT16 interval);
+
+/* Internal functions provided by btm_pm.c
+********************************************
+*/
+#else
+extern void btm_pm_reset(void);
+extern void btm_pm_sm_alloc(UINT8 ind);
+extern void btm_pm_proc_cmd_status(UINT8 status);
+extern void btm_pm_proc_mode_change (UINT8 hci_status, UINT16 hci_handle, UINT8 mode,
+ UINT16 interval);
+extern void btm_pm_proc_ssr_evt (UINT8 *p, UINT16 evt_len);
+#if BTM_SCO_INCLUDED == TRUE
+extern void btm_sco_chk_pend_unpark (UINT8 hci_status, UINT16 hci_handle);
+#else
+#define btm_sco_chk_pend_unpark(hci_status, hci_handle)
+#endif /* BTM_SCO_INCLUDED */
+#endif /* BTM_PWR_MGR_INCLUDED == FALSE */
+extern void btm_qos_setup_complete (UINT8 status, UINT16 handle, FLOW_SPEC *p_flow);
+
+
+/* Internal functions provided by btm_sco.c
+********************************************
+*/
+extern void btm_sco_init (void);
+extern void btm_sco_connected (UINT8 hci_status, BD_ADDR bda, UINT16 hci_handle,
+ tBTM_ESCO_DATA *p_esco_data);
+extern void btm_esco_proc_conn_chg (UINT8 status, UINT16 handle, UINT8 tx_interval,
+ UINT8 retrans_window, UINT16 rx_pkt_len,
+ UINT16 tx_pkt_len);
+extern void btm_sco_conn_req (BD_ADDR bda, DEV_CLASS dev_class, UINT8 link_type);
+extern void btm_sco_removed (UINT16 hci_handle, UINT8 reason);
+extern void btm_sco_acl_removed (BD_ADDR bda);
+extern void btm_route_sco_data (BT_HDR *p_msg);
+extern BOOLEAN btm_is_sco_active (UINT16 handle);
+extern void btm_remove_sco_links (BD_ADDR bda);
+extern BOOLEAN btm_is_sco_active_by_bdaddr (BD_ADDR remote_bda);
+
+extern tBTM_SCO_TYPE btm_read_def_esco_mode (tBTM_ESCO_PARAMS *p_parms);
+extern UINT16 btm_find_scb_by_handle (UINT16 handle);
+extern void btm_sco_flush_sco_data(UINT16 sco_inx);
+
+/* Internal functions provided by btm_devctl.c
+**********************************************
+*/
+extern void btm_dev_init (void);
+extern void btm_dev_absent (void);
+extern void btm_dev_timeout (TIMER_LIST_ENT *p_tle);
+extern void btm_reset_complete (void);
+extern void btm_read_local_version_complete (UINT8 *p, UINT16 evt_len);
+extern void btm_read_hci_buf_size_complete (UINT8 *p, UINT16 evt_len);
+extern void btm_read_local_features_complete (UINT8 *p, UINT16 evt_len);
+extern void btm_read_local_name_complete (UINT8 *p, UINT16 evt_len);
+extern void btm_read_local_addr_complete (UINT8 *p, UINT16 evt_len);
+extern void btm_get_local_features (void);
+
+#if (BLE_INCLUDED == TRUE)
+extern void btm_read_ble_buf_size_complete (UINT8 *p, UINT16 evt_len);
+extern void btm_read_white_list_size_complete(UINT8 *p, UINT16 evt_len);
+extern void btm_ble_add_2_white_list_complete(UINT8 *p, UINT16 evt_len);
+extern void btm_ble_remove_from_white_list_complete(UINT8 *p, UINT16 evt_len);
+extern void btm_ble_clear_white_list_complete(UINT8 *p, UINT16 evt_len);
+#endif /* BLE_INCLUDED */
+
+/* Vendor Specific Command complete evt handler */
+extern void btm_vsc_complete (UINT8 *p, UINT16 cc_opcode, UINT16 evt_len,
+ tBTM_CMPL_CB *p_vsc_cplt_cback);
+extern void btm_inq_db_reset (void);
+extern void btm_vendor_specific_evt (UINT8 *p, UINT8 evt_len);
+extern UINT8 btm_get_hci_version (void);
+extern void btm_read_stored_link_key_complete (UINT8 *p);
+extern void btm_write_stored_link_key_complete (UINT8 *p);
+extern void btm_delete_stored_link_key_complete (UINT8 *p);
+extern void btm_return_link_keys_evt (tBTM_RETURN_LINK_KEYS_EVT *result);
+extern void btm_report_device_status (tBTM_DEV_STATUS status);
+
+
+/* Internal functions provided by btm_dev.c
+**********************************************
+*/
+extern BOOLEAN btm_dev_support_switch (BD_ADDR bd_addr);
+extern UINT8 btm_get_voice_coding_support (void);
+
+extern tBTM_SEC_DEV_REC *btm_sec_alloc_dev (BD_ADDR bd_addr);
+extern void btm_sec_free_dev (tBTM_SEC_DEV_REC *p_dev_rec);
+extern tBTM_SEC_DEV_REC *btm_find_dev (BD_ADDR bd_addr);
+extern tBTM_SEC_DEV_REC *btm_find_or_alloc_dev (BD_ADDR bd_addr);
+extern tBTM_SEC_DEV_REC *btm_find_dev_by_handle (UINT16 handle);
+
+/* Internal functions provided by btm_sec.c
+**********************************************
+*/
+extern BOOLEAN btm_dev_support_switch (BD_ADDR bd_addr);
+extern tBTM_STATUS btm_sec_l2cap_access_req (BD_ADDR bd_addr, UINT16 psm,
+ UINT16 handle, CONNECTION_TYPE conn_type,
+ tBTM_SEC_CALLBACK *p_callback, void *p_ref_data);
+extern tBTM_STATUS btm_sec_mx_access_request (BD_ADDR bd_addr, UINT16 psm, BOOLEAN is_originator,
+ UINT32 mx_proto_id, UINT32 mx_chan_id,
+ tBTM_SEC_CALLBACK *p_callback, void *p_ref_data);
+extern void btm_sec_conn_req (UINT8 *bda, UINT8 *dc);
+extern void btm_create_conn_cancel_complete (UINT8 *p);
+extern void btm_proc_lsto_evt(UINT16 handle, UINT16 timeout);
+extern void btm_read_linq_tx_power_complete (UINT8 *p);
+
+extern void btm_sec_init (UINT8 sec_mode);
+extern void btm_sec_dev_reset (void);
+extern void btm_sec_abort_access_req (BD_ADDR bd_addr);
+extern void btm_sec_auth_complete (UINT16 handle, UINT8 status);
+extern void btm_sec_mkey_comp_event (UINT16 handle, UINT8 status, UINT8 key_flg);
+extern void btm_sec_encrypt_change (UINT16 handle, UINT8 status, UINT8 encr_enable);
+extern void btm_sec_connected (UINT8 *bda, UINT16 handle, UINT8 status, UINT8 enc_mode);
+extern tBTM_STATUS btm_sec_disconnect (UINT16 handle, UINT8 reason);
+extern void btm_sec_disconnected (UINT16 handle, UINT8 reason);
+extern void btm_sec_rmt_name_request_complete (UINT8 *bd_addr, UINT8 *bd_name, UINT8 status);
+extern void btm_sec_rmt_host_support_feat_evt (UINT8 *p);
+extern void btm_io_capabilities_req (UINT8 *p);
+extern void btm_io_capabilities_rsp (UINT8 *p);
+extern void btm_proc_sp_req_evt (tBTM_SP_EVT event, UINT8 *p);
+extern void btm_keypress_notif_evt (UINT8 *p);
+extern void btm_simple_pair_complete (UINT8 *p);
+extern void btm_sec_link_key_notification (UINT8 *p_bda, UINT8 *p_link_key, UINT8 key_type);
+extern void btm_sec_link_key_request (UINT8 *p_bda);
+extern void btm_sec_pin_code_request (UINT8 *p_bda);
+extern void btm_sec_update_clock_offset (UINT16 handle, UINT16 clock_offset);
+extern void btm_sec_dev_rec_cback_event (tBTM_SEC_DEV_REC *p_dev_rec, UINT8 res);
+
+#if BLE_INCLUDED == TRUE
+extern void btm_sec_clear_ble_keys (tBTM_SEC_DEV_REC *p_dev_rec);
+extern BOOLEAN btm_sec_find_bonded_dev (UINT8 start_idx, UINT8 *p_found_idx, tBTM_SEC_DEV_REC *p_rec);
+extern BOOLEAN btm_sec_is_a_bonded_dev (BD_ADDR bda);
+#endif /* BLE_INCLUDED */
+
+extern tINQ_DB_ENT *btm_inq_db_new (BD_ADDR p_bda);
+
+#if BTM_OOB_INCLUDED == TRUE
+extern void btm_rem_oob_req (UINT8 *p);
+extern void btm_read_local_oob_complete (UINT8 *p);
+#else
+#define btm_rem_oob_req(p)
+#define btm_read_local_oob_complete(p)
+#endif
+
+extern void btm_acl_resubmit_page (void);
+extern void btm_acl_reset_paging (void);
+extern void btm_acl_paging (BT_HDR *p, BD_ADDR dest);
+extern void btm_acl_set_discing (BOOLEAN discing);
+extern UINT8 btm_sec_clr_service_by_psm (UINT16 psm);
+
+#ifdef BRCM_VS
+extern void btm_brcm_feat_init(void);
+extern void btm_vs_reset_complete (void);
+extern void btm_brcm_arc_init (void);
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/stack/btm/btm_main.c b/stack/btm/btm_main.c
new file mode 100644
index 0000000..42489e1
--- /dev/null
+++ b/stack/btm/btm_main.c
@@ -0,0 +1,59 @@
+/*****************************************************************************
+**
+** Name: btm_main.c
+**
+** Description: This file contains the definition of the btm control block
+** when BTM_DYNAMIC_MEMORY is used.
+**
+**
+** Copyright (c) 2002-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+
+#include "bt_types.h"
+#include "bt_target.h"
+#include <string.h>
+#include "btm_int.h"
+
+/* Global BTM control block structure
+*/
+#if BTM_DYNAMIC_MEMORY == FALSE
+tBTM_CB btm_cb;
+#endif
+
+/*******************************************************************************
+**
+** Function btm_init
+**
+** Description This function is called at BTM startup to allocate the
+** control block (if using dynamic memory), and initializes the
+** tracing level. It then initializes the various components of
+** btm.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_init (void)
+{
+ /* All fields are cleared; nonzero fields are reinitialized in appropriate function */
+ memset(&btm_cb, 0, sizeof(tBTM_CB));
+
+#if defined(BTM_INITIAL_TRACE_LEVEL)
+ btm_cb.trace_level = BTM_INITIAL_TRACE_LEVEL;
+#else
+ btm_cb.trace_level = BT_TRACE_LEVEL_NONE; /* No traces */
+#endif
+ /* TODO Bluedroid - Hardcoded trace level. Needs to be configurable */
+ btm_cb.trace_level = BT_TRACE_LEVEL_DEBUG;
+ /* Initialize BTM component structures */
+ btm_inq_db_init(); /* Inquiry Database and Structures */
+ btm_acl_init(); /* ACL Database and Structures */
+ btm_sec_init(BTM_SEC_MODE_SP); /* Security Manager Database and Structures */
+#if BTM_SCO_INCLUDED == TRUE
+ btm_sco_init(); /* SCO Database and Structures (If included) */
+#endif
+
+ btm_dev_init(); /* Device Manager Structures & HCI_Reset */
+}
+
+
diff --git a/stack/btm/btm_pm.c b/stack/btm/btm_pm.c
new file mode 100644
index 0000000..169a1b3
--- /dev/null
+++ b/stack/btm/btm_pm.c
@@ -0,0 +1,985 @@
+/*****************************************************************************/
+/* */
+/* Name: btm_pm.c */
+/* */
+/* Description: This file contains functions that manages ACL link modes. */
+/* This includes operations such as active, hold, */
+/* park and sniff modes. */
+/* */
+/* This module contains both internal and external (API) */
+/* functions. External (API) functions are distinguishable */
+/* by their names beginning with uppercase BTM. */
+/* */
+/* */
+/* Copyright (c) 2000-2009, Broadcom Corp., All Rights Reserved. */
+/* WIDCOMM Bluetooth Core. Proprietary and confidential. */
+/*****************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stddef.h>
+#include "bt_types.h"
+#include "gki.h"
+#include "hcimsgs.h"
+#include "btu.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "l2c_int.h"
+#include "hcidefs.h"
+
+
+#if BTM_PWR_MGR_INCLUDED == TRUE
+
+/* This compile option is only useful when the FW has a bug
+ * it automatically uses single slot when entering SNIFF mode, but does not restore the setting
+ * This issue was found when A2DP link goes into sniff and existing sniff still has choppy audio.
+ * If this issue is seen, look for FW solution first.
+ * This work around code will be removed later. */
+#ifndef BTM_PM_SNIFF_SLOT_WORK_AROUND
+#define BTM_PM_SNIFF_SLOT_WORK_AROUND FALSE
+#endif
+
+/*****************************************************************************/
+/* to handle different modes */
+/*****************************************************************************/
+#define BTM_PM_STORED_MASK 0x80 /* set this mask if the command is stored */
+#define BTM_PM_NUM_SET_MODES 3 /* only hold, sniff & park */
+
+/* Usage: (ptr_features[ offset ] & mask )?TRUE:FALSE */
+/* offset to supported feature */
+const UINT8 btm_pm_mode_off[BTM_PM_NUM_SET_MODES] = {0, 0, 1};
+/* mask to supported feature */
+const UINT8 btm_pm_mode_msk[BTM_PM_NUM_SET_MODES] = {0x40, 0x80, 0x01};
+
+#define BTM_PM_GET_MD1 1
+#define BTM_PM_GET_MD2 2
+#define BTM_PM_GET_COMP 3
+
+const UINT8 btm_pm_md_comp_matrix[BTM_PM_NUM_SET_MODES*BTM_PM_NUM_SET_MODES] =
+{
+ BTM_PM_GET_COMP,
+ BTM_PM_GET_MD2,
+ BTM_PM_GET_MD2,
+
+ BTM_PM_GET_MD1,
+ BTM_PM_GET_COMP,
+ BTM_PM_GET_MD1,
+
+ BTM_PM_GET_MD1,
+ BTM_PM_GET_MD2,
+ BTM_PM_GET_COMP
+};
+
+/* function prototype */
+static int btm_pm_find_acl_ind(BD_ADDR remote_bda);
+static tBTM_STATUS btm_pm_snd_md_req( UINT8 pm_id, int link_ind, tBTM_PM_PWR_MD *p_mode );
+
+/*
+#ifdef BTM_PM_DEBUG
+#undef BTM_PM_DEBUG
+#define BTM_PM_DEBUG TRUE
+#endif
+*/
+
+#if BTM_PM_DEBUG == TRUE
+const char * btm_pm_state_str[] =
+{
+ "pm_active_state",
+ "pm_hold_state",
+ "pm_sniff_state",
+ "pm_park_state",
+ "pm_pend_state"
+};
+
+const char * btm_pm_event_str[] =
+{
+ "pm_set_mode_event",
+ "pm_hci_sts_event",
+ "pm_mod_chg_event",
+ "pm_update_event"
+};
+
+const char * btm_pm_action_str[] =
+{
+ "pm_set_mode_action",
+ "pm_update_db_action",
+ "pm_mod_chg_action",
+ "pm_hci_sts_action",
+ "pm_update_action"
+};
+#endif
+
+/*****************************************************************************/
+/* P U B L I C F U N C T I O N S */
+/*****************************************************************************/
+/*******************************************************************************
+**
+** Function BTM_PmRegister
+**
+** Description register or deregister with power manager
+**
+** Returns BTM_SUCCESS if successful,
+** BTM_NO_RESOURCES if no room to hold registration
+** BTM_ILLEGAL_VALUE
+**
+*******************************************************************************/
+tBTM_STATUS BTM_PmRegister (UINT8 mask, UINT8 *p_pm_id, tBTM_PM_STATUS_CBACK *p_cb)
+{
+ int xx;
+
+ /* de-register */
+ if(mask & BTM_PM_DEREG)
+ {
+ if(*p_pm_id >= BTM_MAX_PM_RECORDS)
+ return BTM_ILLEGAL_VALUE;
+ btm_cb.pm_reg_db[*p_pm_id].mask = BTM_PM_REC_NOT_USED;
+ return BTM_SUCCESS;
+ }
+
+ for(xx=0; xx<BTM_MAX_PM_RECORDS; xx++)
+ {
+ /* find an unused entry */
+ if(btm_cb.pm_reg_db[xx].mask == BTM_PM_REC_NOT_USED)
+ {
+ /* if register for notification, should provide callback routine */
+ if(mask & BTM_PM_REG_NOTIF)
+ {
+ if(p_cb == NULL)
+ return BTM_ILLEGAL_VALUE;
+ btm_cb.pm_reg_db[xx].cback = p_cb;
+ }
+ btm_cb.pm_reg_db[xx].mask = mask;
+ *p_pm_id = xx;
+ return BTM_SUCCESS;
+ }
+ }
+
+ return BTM_NO_RESOURCES;
+}
+
+/*******************************************************************************
+**
+** Function BTM_SetPowerMode
+**
+** Description store the mode in control block or
+** alter ACL connection behavior.
+**
+** Returns BTM_SUCCESS if successful,
+** BTM_UNKNOWN_ADDR if bd addr is not active or bad
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetPowerMode (UINT8 pm_id, BD_ADDR remote_bda, tBTM_PM_PWR_MD *p_mode)
+{
+ UINT8 *p_features;
+ int ind, acl_ind;
+ tBTM_PM_MCB *p_cb = NULL; /* per ACL link */
+ tBTM_PM_MODE mode;
+ int temp_pm_id;
+
+
+ if(pm_id >= BTM_MAX_PM_RECORDS)
+ pm_id = BTM_PM_SET_ONLY_ID;
+
+ if(p_mode == NULL)
+ return BTM_ILLEGAL_VALUE;
+
+ BTM_TRACE_API3( "BTM_SetPowerMode: pm_id %d BDA: %08x mode:0x%x", pm_id,
+ (remote_bda[2]<<24)+(remote_bda[3]<<16)+(remote_bda[4]<<8)+remote_bda[5], p_mode->mode);
+
+ /* take out the force bit */
+ mode = p_mode->mode & ~BTM_PM_MD_FORCE;
+
+ acl_ind = btm_pm_find_acl_ind(remote_bda);
+ if(acl_ind == MAX_L2CAP_LINKS)
+ return (BTM_UNKNOWN_ADDR);
+
+ p_cb = &(btm_cb.pm_mode_db[acl_ind]);
+
+ if(mode != BTM_PM_MD_ACTIVE)
+ {
+ /* check if the requested mode is supported */
+ ind = mode - BTM_PM_MD_HOLD; /* make it base 0 */
+ p_features = BTM_ReadLocalFeatures();
+ if( !(p_features[ btm_pm_mode_off[ind] ] & btm_pm_mode_msk[ind] ) )
+ return BTM_MODE_UNSUPPORTED;
+ }
+
+ if(mode == p_cb->state) /* the requested mode is current mode */
+ {
+ /* already in the requested mode and the current interval has less latency than the max */
+ if( (mode == BTM_PM_MD_ACTIVE) ||
+ ((p_mode->mode & BTM_PM_MD_FORCE) && (p_mode->max >= p_cb->interval) && (p_mode->min <= p_cb->interval)) ||
+ ((p_mode->mode & BTM_PM_MD_FORCE)==0 && (p_mode->max >= p_cb->interval)) )
+ {
+ BTM_TRACE_DEBUG4( "BTM_SetPowerMode: mode:0x%x interval %d max:%d, min:%d", p_mode->mode, p_cb->interval, p_mode->max, p_mode->min);
+ return BTM_SUCCESS;
+ }
+ }
+
+ temp_pm_id = pm_id;
+ if(pm_id == BTM_PM_SET_ONLY_ID)
+ temp_pm_id = BTM_MAX_PM_RECORDS;
+
+ /* update mode database */
+ if( ((pm_id != BTM_PM_SET_ONLY_ID) &&
+ (btm_cb.pm_reg_db[pm_id].mask & BTM_PM_REG_SET))
+ || ((pm_id == BTM_PM_SET_ONLY_ID) && (btm_cb.pm_pend_link != MAX_L2CAP_LINKS)) )
+ {
+#if BTM_PM_DEBUG == TRUE
+ BTM_TRACE_DEBUG2( "BTM_SetPowerMode: Saving cmd acl_ind %d temp_pm_id %d", acl_ind,temp_pm_id);
+#endif
+ /* Make sure mask is set to BTM_PM_REG_SET */
+ btm_cb.pm_reg_db[temp_pm_id].mask |= BTM_PM_REG_SET;
+ *(&p_cb->req_mode[temp_pm_id]) = *((tBTM_PM_PWR_MD *)p_mode);
+ p_cb->chg_ind = TRUE;
+ }
+
+#if BTM_PM_DEBUG == TRUE
+ BTM_TRACE_DEBUG2( "btm_pm state:0x%x, pm_pend_link: %d", p_cb->state, btm_cb.pm_pend_link);
+#endif
+ /* if mode == hold or pending, return */
+ if( (p_cb->state == BTM_PM_STS_HOLD) ||
+ (p_cb->state == BTM_PM_STS_PENDING) ||
+ (btm_cb.pm_pend_link != MAX_L2CAP_LINKS) ) /* command pending */
+ {
+ if(acl_ind != btm_cb.pm_pend_link)
+ {
+ /* set the stored mask */
+ p_cb->state |= BTM_PM_STORED_MASK;
+ BTM_TRACE_DEBUG1( "btm_pm state stored:%d",acl_ind);
+ }
+ return BTM_CMD_STORED;
+ }
+
+
+
+ return btm_pm_snd_md_req(pm_id, acl_ind, p_mode);
+}
+
+/*******************************************************************************
+**
+** Function BTM_ReadPowerMode
+**
+** Description This returns the current mode for a specific
+** ACL connection.
+**
+** Input Param remote_bda - device address of desired ACL connection
+**
+** Output Param p_mode - address where the current mode is copied into.
+** BTM_ACL_MODE_NORMAL
+** BTM_ACL_MODE_HOLD
+** BTM_ACL_MODE_SNIFF
+** BTM_ACL_MODE_PARK
+** (valid only if return code is BTM_SUCCESS)
+**
+** Returns BTM_SUCCESS if successful,
+** BTM_UNKNOWN_ADDR if bd addr is not active or bad
+**
+*******************************************************************************/
+tBTM_STATUS BTM_ReadPowerMode (BD_ADDR remote_bda, tBTM_PM_MODE *p_mode)
+{
+ int acl_ind;
+
+ if( (acl_ind = btm_pm_find_acl_ind(remote_bda)) == MAX_L2CAP_LINKS)
+ return (BTM_UNKNOWN_ADDR);
+
+ *p_mode = btm_cb.pm_mode_db[acl_ind].state;
+ return BTM_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function BTM_SetSsrParams
+**
+** Description This sends the given SSR parameters for the given ACL
+** connection if it is in ACTIVE mode.
+**
+** Input Param remote_bda - device address of desired ACL connection
+** max_lat - maximum latency (in 0.625ms)(0-0xFFFE)
+** min_rmt_to - minimum remote timeout
+** min_loc_to - minimum local timeout
+**
+**
+** Returns BTM_SUCCESS if the HCI command is issued successful,
+** BTM_UNKNOWN_ADDR if bd addr is not active or bad
+** BTM_CMD_STORED if the command is stored
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetSsrParams (BD_ADDR remote_bda, UINT16 max_lat,
+ UINT16 min_rmt_to, UINT16 min_loc_to)
+{
+#if (BTM_SSR_INCLUDED == TRUE)
+ int acl_ind;
+ tBTM_PM_MCB *p_cb;
+
+ if( (acl_ind = btm_pm_find_acl_ind(remote_bda)) == MAX_L2CAP_LINKS)
+ return (BTM_UNKNOWN_ADDR);
+
+ if(BTM_PM_STS_ACTIVE == btm_cb.pm_mode_db[acl_ind].state ||
+ BTM_PM_STS_SNIFF == btm_cb.pm_mode_db[acl_ind].state)
+ {
+ if (btsnd_hcic_sniff_sub_rate(btm_cb.acl_db[acl_ind].hci_handle, max_lat,
+ min_rmt_to, min_loc_to))
+ return BTM_SUCCESS;
+ else
+ return BTM_NO_RESOURCES;
+ }
+ p_cb = &btm_cb.pm_mode_db[acl_ind];
+ p_cb->max_lat = max_lat;
+ p_cb->min_rmt_to = min_rmt_to;
+ p_cb->min_loc_to = min_loc_to;
+ return BTM_CMD_STORED;
+#else
+ return BTM_ILLEGAL_ACTION;
+#endif
+}
+
+/*******************************************************************************
+**
+** Function btm_pm_reset
+**
+** Description as a part of the BTM reset process.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_pm_reset(void)
+{
+ int xx;
+ tBTM_PM_STATUS_CBACK *cb = NULL;
+
+ /* clear the pending request for application */
+ if( (btm_cb.pm_pend_id != BTM_PM_SET_ONLY_ID) &&
+ (btm_cb.pm_reg_db[btm_cb.pm_pend_id].mask & BTM_PM_REG_NOTIF) )
+ {
+ cb = btm_cb.pm_reg_db[btm_cb.pm_pend_id].cback;
+ }
+
+ /* no command pending */
+ btm_cb.pm_pend_link = MAX_L2CAP_LINKS;
+
+ /* clear the register record */
+ for(xx=0; xx<BTM_MAX_PM_RECORDS; xx++)
+ {
+ btm_cb.pm_reg_db[xx].mask = BTM_PM_REC_NOT_USED;
+ }
+
+ if(cb != NULL)
+ (*cb)(btm_cb.acl_db[btm_cb.pm_pend_link].remote_addr, BTM_PM_STS_ERROR, BTM_DEV_RESET, 0);
+}
+
+/*******************************************************************************
+**
+** Function btm_pm_sm_alloc
+**
+** Description This function initializes the control block of an ACL link.
+** It is called when an ACL connection is created.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_pm_sm_alloc(UINT8 ind)
+{
+ tBTM_PM_MCB *p_db = &btm_cb.pm_mode_db[ind]; /* per ACL link */
+ memset (p_db, 0, sizeof(tBTM_PM_MCB));
+ p_db->state = BTM_PM_ST_ACTIVE;
+#if BTM_PM_DEBUG == TRUE
+ BTM_TRACE_DEBUG2( "btm_pm_sm_alloc ind:%d st:%d", ind, p_db->state);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function btm_pm_find_acl_ind
+**
+** Description This function initializes the control block of an ACL link.
+** It is called when an ACL connection is created.
+**
+** Returns void
+**
+*******************************************************************************/
+static int btm_pm_find_acl_ind(BD_ADDR remote_bda)
+{
+ tACL_CONN *p = &btm_cb.acl_db[0];
+ UINT8 xx;
+
+ for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p++)
+ {
+ if ((p->in_use) && (!memcmp (p->remote_addr, remote_bda, BD_ADDR_LEN)))
+ {
+#if BTM_PM_DEBUG == TRUE
+ BTM_TRACE_DEBUG2( "btm_pm_find_acl_ind ind:%d, st:%d", xx, btm_cb.pm_mode_db[xx].state);
+#endif
+ break;
+ }
+ }
+ return xx;
+}
+
+/*******************************************************************************
+**
+** Function btm_pm_compare_modes
+** Description get the "more active" mode of the 2
+** Returns void
+**
+*******************************************************************************/
+static tBTM_PM_PWR_MD * btm_pm_compare_modes(tBTM_PM_PWR_MD *p_md1, tBTM_PM_PWR_MD *p_md2, tBTM_PM_PWR_MD *p_res)
+{
+ UINT8 res;
+
+ if(p_md1 == NULL)
+ {
+ *p_res = *p_md2;
+ p_res->mode &= ~BTM_PM_MD_FORCE;
+
+ return p_md2;
+ }
+
+ if(p_md2->mode == BTM_PM_MD_ACTIVE || p_md1->mode == BTM_PM_MD_ACTIVE)
+ {
+ return NULL;
+ }
+
+ /* check if force bit is involved */
+ if(p_md1->mode & BTM_PM_MD_FORCE)
+ {
+ *p_res = *p_md1;
+ p_res->mode &= ~BTM_PM_MD_FORCE;
+ return p_res;
+ }
+
+ if(p_md2->mode & BTM_PM_MD_FORCE)
+ {
+ *p_res = *p_md2;
+ p_res->mode &= ~BTM_PM_MD_FORCE;
+ return p_res;
+ }
+
+ res = (p_md1->mode - 1) * BTM_PM_NUM_SET_MODES + (p_md2->mode - 1);
+ res = btm_pm_md_comp_matrix[res];
+ switch(res)
+ {
+ case BTM_PM_GET_MD1:
+ *p_res = *p_md1;
+ return p_md1;
+
+ case BTM_PM_GET_MD2:
+ *p_res = *p_md2;
+ return p_md2;
+
+ case BTM_PM_GET_COMP:
+ p_res->mode = p_md1->mode;
+ /* min of the two */
+ p_res->max = (p_md1->max < p_md2->max)? (p_md1->max) : (p_md2->max);
+ /* max of the two */
+ p_res->min = (p_md1->min > p_md2->min)? (p_md1->min) : (p_md2->min);
+
+ /* the intersection is NULL */
+ if( p_res->max < p_res->min)
+ return NULL;
+
+ if(p_res->mode == BTM_PM_MD_SNIFF)
+ {
+ /* max of the two */
+ p_res->attempt = (p_md1->attempt > p_md2->attempt)? (p_md1->attempt) : (p_md2->attempt);
+ p_res->timeout = (p_md1->timeout > p_md2->timeout)? (p_md1->timeout) : (p_md2->timeout);
+ }
+ return p_res;
+ }
+ return NULL;
+}
+
+/*******************************************************************************
+**
+** Function btm_pm_get_set_mode
+** Description get the resulting mode from the registered parties, then compare it
+** with the requested mode, if the command is from an unregistered party.
+** Returns void
+**
+*******************************************************************************/
+static tBTM_PM_MODE btm_pm_get_set_mode(UINT8 pm_id, tBTM_PM_MCB *p_cb, tBTM_PM_PWR_MD *p_mode, tBTM_PM_PWR_MD *p_res)
+{
+ int xx, loop_max;
+ tBTM_PM_PWR_MD *p_md = NULL;
+
+ if(p_mode != NULL && p_mode->mode & BTM_PM_MD_FORCE)
+ {
+ *p_res = *p_mode;
+ p_res->mode &= ~BTM_PM_MD_FORCE;
+ return p_res->mode;
+ }
+
+ if(!p_mode)
+ loop_max = BTM_MAX_PM_RECORDS+1;
+ else
+ loop_max = BTM_MAX_PM_RECORDS;
+
+ for( xx=0; xx<loop_max; xx++)
+ {
+ /* g through all the registered "set" parties */
+ if(btm_cb.pm_reg_db[xx].mask & BTM_PM_REG_SET)
+ {
+ if(p_cb->req_mode[xx].mode == BTM_PM_MD_ACTIVE)
+ {
+ /* if at least one registered (SET) party says ACTIVE, stay active */
+ return BTM_PM_MD_ACTIVE;
+ }
+ else
+ {
+ /* if registered parties give conflicting information, stay active */
+ if( (btm_pm_compare_modes(p_md, &p_cb->req_mode[xx], p_res)) == NULL)
+ return BTM_PM_MD_ACTIVE;
+ p_md = p_res;
+ }
+ }
+ }
+
+ /* if the resulting mode is NULL(nobody registers SET), use the requested mode */
+ if(p_md == NULL)
+ {
+ if(p_mode)
+ *p_res = *((tBTM_PM_PWR_MD *)p_mode);
+ else /* p_mode is NULL when btm_pm_snd_md_req is called from btm_pm_proc_mode_change */
+ return BTM_PM_MD_ACTIVE;
+ }
+ else
+ {
+ /* if the command is from unregistered party,
+ compare the resulting mode from registered party*/
+ if( (pm_id == BTM_PM_SET_ONLY_ID) &&
+ ((btm_pm_compare_modes(p_mode, p_md, p_res)) == NULL) )
+ return BTM_PM_MD_ACTIVE;
+ }
+
+ return p_res->mode;
+}
+
+/*******************************************************************************
+**
+** Function btm_pm_snd_md_req
+** Description get the resulting mode and send the resuest to host controller
+** Returns tBTM_STATUS
+**, BOOLEAN *p_chg_ind
+*******************************************************************************/
+static tBTM_STATUS btm_pm_snd_md_req(UINT8 pm_id, int link_ind, tBTM_PM_PWR_MD *p_mode)
+{
+ tBTM_PM_PWR_MD md_res;
+ tBTM_PM_MODE mode;
+ tBTM_PM_MCB *p_cb = &btm_cb.pm_mode_db[link_ind];
+ BOOLEAN chg_ind = FALSE;
+
+ mode = btm_pm_get_set_mode(pm_id, p_cb, p_mode, &md_res);
+ md_res.mode = mode;
+
+#if BTM_PM_DEBUG == TRUE
+ BTM_TRACE_DEBUG2( "btm_pm_snd_md_req link_ind:%d, mode: %d",
+ link_ind, mode);
+#endif
+
+ if( p_cb->state == mode)
+ {
+ /* already in the resulting mode */
+ if( (mode == BTM_PM_MD_ACTIVE) ||
+ ((md_res.max >= p_cb->interval) && (md_res.min <= p_cb->interval)) )
+ return BTM_CMD_STORED;
+ /* Otherwise, needs to wake, then sleep */
+ chg_ind = TRUE;
+ }
+ p_cb->chg_ind = chg_ind;
+
+ /* cannot go directly from current mode to resulting mode. */
+ if( mode != BTM_PM_MD_ACTIVE && p_cb->state != BTM_PM_MD_ACTIVE)
+ p_cb->chg_ind = TRUE; /* needs to wake, then sleep */
+
+ if(p_cb->chg_ind == TRUE) /* needs to wake first */
+ md_res.mode = BTM_PM_MD_ACTIVE;
+#if (BTM_SSR_INCLUDED == TRUE)
+ else if(BTM_PM_MD_SNIFF == md_res.mode && p_cb->max_lat)
+ {
+ btsnd_hcic_sniff_sub_rate(btm_cb.acl_db[link_ind].hci_handle, p_cb->max_lat,
+ p_cb->min_rmt_to, p_cb->min_loc_to);
+ p_cb->max_lat = 0;
+ }
+#endif
+ /* Default is failure */
+ btm_cb.pm_pend_link = MAX_L2CAP_LINKS;
+
+ /* send the appropriate HCI command */
+ btm_cb.pm_pend_id = pm_id;
+
+#if BTM_PM_DEBUG == TRUE
+ BTM_TRACE_DEBUG2("btm_pm_snd_md_req state:0x%x, link_ind: %d", p_cb->state, link_ind);
+#endif
+ switch(md_res.mode)
+ {
+ case BTM_PM_MD_ACTIVE:
+ switch(p_cb->state)
+ {
+ case BTM_PM_MD_SNIFF:
+ if (btsnd_hcic_exit_sniff_mode(btm_cb.acl_db[link_ind].hci_handle))
+ {
+ btm_cb.pm_pend_link = link_ind;
+ }
+ break;
+ case BTM_PM_MD_PARK:
+ if (btsnd_hcic_exit_park_mode(btm_cb.acl_db[link_ind].hci_handle))
+ {
+ btm_cb.pm_pend_link = link_ind;
+ }
+ break;
+ default:
+ /* Failure btm_cb.pm_pend_link = MAX_L2CAP_LINKS */
+ break;
+ }
+ break;
+
+ case BTM_PM_MD_HOLD:
+ if (btsnd_hcic_hold_mode (btm_cb.acl_db[link_ind].hci_handle,
+ md_res.max, md_res.min))
+ {
+ btm_cb.pm_pend_link = link_ind;
+ }
+ break;
+
+ case BTM_PM_MD_SNIFF:
+ if (btsnd_hcic_sniff_mode (btm_cb.acl_db[link_ind].hci_handle,
+ md_res.max, md_res.min, md_res.attempt,
+ md_res.timeout))
+ {
+ btm_cb.pm_pend_link = link_ind;
+ }
+ break;
+
+ case BTM_PM_MD_PARK:
+ if (btsnd_hcic_park_mode (btm_cb.acl_db[link_ind].hci_handle,
+ md_res.max, md_res.min))
+ {
+ btm_cb.pm_pend_link = link_ind;
+ }
+ break;
+ default:
+ /* Failure btm_cb.pm_pend_link = MAX_L2CAP_LINKS */
+ break;
+ }
+
+ if(btm_cb.pm_pend_link == MAX_L2CAP_LINKS)
+ {
+ /* the command was not sent */
+#if BTM_PM_DEBUG == TRUE
+ BTM_TRACE_DEBUG1( "pm_pend_link: %d",btm_cb.pm_pend_link);
+#endif
+ return (BTM_NO_RESOURCES);
+ }
+
+ return BTM_CMD_STARTED;
+}
+
+/*******************************************************************************
+**
+** Function btm_pm_check_stored
+**
+** Description This function is called when an HCI command status event occurs
+** to check if there's any PM command issued while waiting for
+** HCI command status.
+**
+** Returns none.
+**
+*******************************************************************************/
+static void btm_pm_check_stored(void)
+{
+ int xx;
+ for(xx=0; xx<MAX_L2CAP_LINKS; xx++)
+ {
+ if(btm_cb.pm_mode_db[xx].state & BTM_PM_STORED_MASK)
+ {
+ btm_cb.pm_mode_db[xx].state &= ~BTM_PM_STORED_MASK;
+ BTM_TRACE_DEBUG1( "btm_pm_check_stored :%d", xx);
+ btm_pm_snd_md_req(BTM_PM_SET_ONLY_ID, xx, NULL);
+ break;
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function btm_pm_proc_cmd_status
+**
+** Description This function is called when an HCI command status event occurs
+** for power manager related commands.
+**
+** Input Parms status - status of the event (HCI_SUCCESS if no errors)
+**
+** Returns none.
+**
+*******************************************************************************/
+void btm_pm_proc_cmd_status(UINT8 status)
+{
+ tBTM_PM_MCB *p_cb;
+ tBTM_PM_STATUS pm_status;
+
+ if(btm_cb.pm_pend_link >= MAX_L2CAP_LINKS)
+ return;
+
+ p_cb = &btm_cb.pm_mode_db[btm_cb.pm_pend_link];
+
+ if(status == HCI_SUCCESS)
+ {
+ p_cb->state = BTM_PM_ST_PENDING;
+ pm_status = BTM_PM_STS_PENDING;
+#if BTM_PM_DEBUG == TRUE
+ BTM_TRACE_DEBUG1( "btm_pm_proc_cmd_status new state:0x%x", p_cb->state);
+#endif
+ }
+ else /* the command was not successfull. Stay in the same state */
+ {
+ pm_status = BTM_PM_STS_ERROR;
+ }
+
+ /* notify the caller is appropriate */
+ if( (btm_cb.pm_pend_id != BTM_PM_SET_ONLY_ID) &&
+ (btm_cb.pm_reg_db[btm_cb.pm_pend_id].mask & BTM_PM_REG_NOTIF) )
+ {
+ (*btm_cb.pm_reg_db[btm_cb.pm_pend_id].cback)(btm_cb.acl_db[btm_cb.pm_pend_link].remote_addr, pm_status, 0, status);
+ }
+
+ /* no pending cmd now */
+#if BTM_PM_DEBUG == TRUE
+ BTM_TRACE_DEBUG3( "btm_pm_proc_cmd_status state:0x%x, pm_pend_link: %d(new: %d)",
+ p_cb->state, btm_cb.pm_pend_link, MAX_L2CAP_LINKS);
+#endif
+ btm_cb.pm_pend_link = MAX_L2CAP_LINKS;
+
+ btm_pm_check_stored();
+}
+
+/*******************************************************************************
+**
+** Function btm_process_mode_change
+**
+** Description This function is called when an HCI mode change event occurs.
+**
+** Input Parms hci_status - status of the event (HCI_SUCCESS if no errors)
+** hci_handle - connection handle associated with the change
+** mode - HCI_MODE_ACTIVE, HCI_MODE_HOLD, HCI_MODE_SNIFF, or HCI_MODE_PARK
+** interval - number of baseband slots (meaning depends on mode)
+**
+** Returns none.
+**
+*******************************************************************************/
+void btm_pm_proc_mode_change (UINT8 hci_status, UINT16 hci_handle, UINT8 mode, UINT16 interval)
+{
+ tACL_CONN *p;
+ tBTM_PM_MCB *p_cb = NULL;
+ int xx, yy, zz;
+ tBTM_PM_STATE old_state;
+ tL2C_LCB *p_lcb;
+
+ /* get the index to acl_db */
+ if ((xx = btm_handle_to_acl_index(hci_handle)) >= MAX_L2CAP_LINKS)
+ return;
+
+ p = &btm_cb.acl_db[xx];
+
+ /*** 2035 and 2045 work around: If mode is active and coming out of a SCO disconnect, restore packet types ***/
+ if (mode == HCI_MODE_ACTIVE)
+ {
+ if(BTM_GetNumScoLinks() == 0)
+ {
+ if(p->restore_pkt_types)
+ {
+ BTM_TRACE_DEBUG3("btm mode change AFTER unsniffing; hci hdl 0x%x, types 0x%02x/0x%02x",
+ hci_handle, p->pkt_types_mask, p->restore_pkt_types);
+ p->pkt_types_mask = p->restore_pkt_types;
+ p->restore_pkt_types = 0; /* Only exists while SCO is active */
+ btsnd_hcic_change_conn_type (p->hci_handle, p->pkt_types_mask);
+ }
+#if (BTM_PM_SNIFF_SLOT_WORK_AROUND == TRUE)
+ else
+ {
+ BTM_TRACE_DEBUG2("btm mode change AFTER unsniffing; hci hdl 0x%x, types 0x%02x",
+ hci_handle, btm_cb.btm_acl_pkt_types_supported);
+ btm_set_packet_types (p, btm_cb.btm_acl_pkt_types_supported);
+ }
+#endif
+ }
+#if (BTM_PM_SNIFF_SLOT_WORK_AROUND == TRUE)
+ else
+ {
+ /* Mode changed from Sniff to Active while SCO is open. */
+ /* Packet types of active mode, not sniff mode, should be used for ACL when SCO is closed. */
+ p->restore_pkt_types = btm_cb.btm_acl_pkt_types_supported;
+
+ /* Exclude packet types not supported by the peer */
+ btm_acl_chk_peer_pkt_type_support (p, &p->restore_pkt_types);
+ }
+#endif
+ }
+#if (BTM_PM_SNIFF_SLOT_WORK_AROUND == TRUE)
+ else if (mode == HCI_MODE_SNIFF)
+ {
+ BTM_TRACE_DEBUG1("btm mode change to sniff; hci hdl 0x%x use single slot",
+ hci_handle);
+ btm_set_packet_types (p, (HCI_PKT_TYPES_MASK_DM1 | HCI_PKT_TYPES_MASK_DH1));
+ }
+#endif
+
+ /* update control block */
+ p_cb = &(btm_cb.pm_mode_db[xx]);
+ old_state = p_cb->state;
+ p_cb->state = mode;
+ p_cb->interval = interval;
+#if BTM_PM_DEBUG == TRUE
+ BTM_TRACE_DEBUG2( "btm_pm_proc_mode_change new state:0x%x (old:0x%x)", p_cb->state, old_state);
+#endif
+
+ if ((p_cb->state == HCI_MODE_ACTIVE) &&
+ ((p_lcb = l2cu_find_lcb_by_bd_addr (p->remote_addr)) != NULL))
+ {
+ /* There might be any pending packets due to SNIFF or PENDING state */
+ /* Trigger L2C to start transmission of the pending packets. */
+ BTM_TRACE_DEBUG0 ("btm mode change to active; check l2c_link for outgoing packets");
+ l2c_link_check_send_pkts (p_lcb, NULL, NULL);
+
+ btu_stop_timer (&p_lcb->timer_entry);
+ }
+
+ /* notify registered parties */
+ for(yy=0; yy<=BTM_MAX_PM_RECORDS; yy++)
+ {
+ /* set req_mode HOLD mode->ACTIVE */
+ if( (mode == BTM_PM_MD_ACTIVE) && (p_cb->req_mode[yy].mode == BTM_PM_MD_HOLD) )
+ p_cb->req_mode[yy].mode = BTM_PM_MD_ACTIVE;
+ }
+
+ /* new request has been made. - post a message to BTU task */
+ if(old_state & BTM_PM_STORED_MASK)
+ {
+#if BTM_PM_DEBUG == TRUE
+ BTM_TRACE_DEBUG1( "btm_pm_proc_mode_change: Sending stored req:%d", xx);
+#endif
+ btm_pm_snd_md_req(BTM_PM_SET_ONLY_ID, xx, NULL);
+ }
+ else
+ {
+ for(zz=0; zz<MAX_L2CAP_LINKS; zz++)
+ {
+ if(btm_cb.pm_mode_db[zz].chg_ind == TRUE)
+ {
+#if BTM_PM_DEBUG == TRUE
+ BTM_TRACE_DEBUG1( "btm_pm_proc_mode_change: Sending PM req :%d", zz);
+#endif
+ btm_pm_snd_md_req(BTM_PM_SET_ONLY_ID, zz, NULL);
+ break;
+ }
+ }
+ }
+
+
+ /* notify registered parties */
+ for(yy=0; yy<BTM_MAX_PM_RECORDS; yy++)
+ {
+ if(btm_cb.pm_reg_db[yy].mask & BTM_PM_REG_NOTIF)
+ {
+ (*btm_cb.pm_reg_db[yy].cback)( p->remote_addr, mode, interval, hci_status);
+ }
+ }
+
+ /* If mode change was because of an active role switch or change link key */
+ btm_cont_rswitch_or_chglinkkey(p, btm_find_dev(p->remote_addr), hci_status);
+}
+
+/*******************************************************************************
+**
+** Function btm_pm_proc_ssr_evt
+**
+** Description This function is called when an HCI sniff subrating event occurs.
+**
+** Returns none.
+**
+*******************************************************************************/
+#if (BTM_SSR_INCLUDED == TRUE)
+void btm_pm_proc_ssr_evt (UINT8 *p, UINT16 evt_len)
+{
+ UINT8 status;
+ UINT16 handle;
+ UINT16 max_tx_lat, max_rx_lat;
+ int xx, yy;
+ tBTM_PM_MCB *p_cb;
+ tACL_CONN *p_acl=NULL;
+ UINT16 use_ssr = TRUE;
+
+ STREAM_TO_UINT8 (status, p);
+
+ STREAM_TO_UINT16 (handle, p);
+ /* get the index to acl_db */
+ if ((xx = btm_handle_to_acl_index(handle)) >= MAX_L2CAP_LINKS)
+ return;
+
+ STREAM_TO_UINT16 (max_tx_lat, p);
+ STREAM_TO_UINT16 (max_rx_lat, p);
+ p_cb = &(btm_cb.pm_mode_db[xx]);
+
+ p_acl = &btm_cb.acl_db[xx];
+ if(p_cb->interval == max_rx_lat)
+ {
+ /* using legacy sniff */
+ use_ssr = FALSE;
+ }
+
+ /* notify registered parties */
+ for(yy=0; yy<BTM_MAX_PM_RECORDS; yy++)
+ {
+ if(btm_cb.pm_reg_db[yy].mask & BTM_PM_REG_NOTIF)
+ {
+ if( p_acl)
+ {
+ (*btm_cb.pm_reg_db[yy].cback)( p_acl->remote_addr, BTM_PM_STS_SSR, use_ssr, status);
+ }
+ }
+ }
+}
+#endif
+#else /* BTM_PWR_MGR_INCLUDED == TRUE */
+
+/*******************************************************************************
+**
+** Functions BTM_PmRegister, BTM_SetPowerMode, and BTM_ReadPowerMode
+**
+** Description Stubbed versions for BTM_PWR_MGR_INCLUDED = FALSE
+**
+** Returns BTM_MODE_UNSUPPORTED.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_PmRegister (UINT8 mask, UINT8 *p_pm_id, tBTM_PM_STATUS_CBACK *p_cb)
+{
+ return BTM_MODE_UNSUPPORTED;
+}
+
+tBTM_STATUS BTM_SetPowerMode (UINT8 pm_id, BD_ADDR remote_bda, tBTM_PM_PWR_MD *p_mode)
+{
+ return BTM_MODE_UNSUPPORTED;
+}
+
+tBTM_STATUS BTM_ReadPowerMode (BD_ADDR remote_bda, tBTM_PM_MODE *p_mode)
+{
+ return BTM_MODE_UNSUPPORTED;
+}
+
+#endif
+
+/*******************************************************************************
+**
+** Function BTM_IsPowerManagerOn
+**
+** Description This function is called to check if power manager is included.
+** in the BTE version.
+**
+** Returns BTM_PWR_MGR_INCLUDED.
+**
+*******************************************************************************/
+BOOLEAN BTM_IsPowerManagerOn (void)
+{
+ return BTM_PWR_MGR_INCLUDED;
+}
diff --git a/stack/btm/btm_sco.c b/stack/btm/btm_sco.c
new file mode 100644
index 0000000..394ac0a
--- /dev/null
+++ b/stack/btm/btm_sco.c
@@ -0,0 +1,1741 @@
+/*****************************************************************************
+**
+** Name: btm_sco.c
+**
+** Description: This file contains functions that handle SCO connections.
+** This includes operations such as connect, disconnect,
+** change supported packet types.
+**
+** This module contains both internal and external (API)
+** functions. External (API) functions are distinguishable
+** by their names beginning with uppercase BTM.
+**
+** Copyright (c) 2000-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+
+#include <string.h>
+#include "bt_types.h"
+#include "bt_target.h"
+#include "gki.h"
+#include "bt_types.h"
+#include "hcimsgs.h"
+#include "btu.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "hcidefs.h"
+
+#if BTM_SCO_INCLUDED == TRUE
+
+/********************************************************************************/
+/* L O C A L D A T A D E F I N I T I O N S */
+/********************************************************************************/
+
+#define SCO_ST_UNUSED 0
+#define SCO_ST_LISTENING 1
+#define SCO_ST_W4_CONN_RSP 2
+#define SCO_ST_CONNECTING 3
+#define SCO_ST_CONNECTED 4
+#define SCO_ST_DISCONNECTING 5
+#define SCO_ST_PEND_UNPARK 6
+#define SCO_ST_PEND_ROLECHANGE 7
+
+/********************************************************************************/
+/* L O C A L F U N C T I O N P R O T O T Y P E S */
+/********************************************************************************/
+
+static const tBTM_ESCO_PARAMS btm_esco_defaults =
+{
+ BTM_64KBITS_RATE, /* TX Bandwidth (64 kbits/sec) */
+ BTM_64KBITS_RATE, /* RX Bandwidth (64 kbits/sec) */
+ 0x000a, /* 10 ms (HS/HF can use EV3, 2-EV3, 3-EV3) */
+ 0x0060, /* Inp Linear, Air CVSD, 2s Comp, 16bit */
+ (BTM_SCO_PKT_TYPES_MASK_HV1 + /* Packet Types */
+ BTM_SCO_PKT_TYPES_MASK_HV2 +
+ BTM_SCO_PKT_TYPES_MASK_HV3 +
+ BTM_SCO_PKT_TYPES_MASK_EV3 +
+ BTM_SCO_PKT_TYPES_MASK_EV4 +
+ BTM_SCO_PKT_TYPES_MASK_EV5),
+ BTM_ESCO_RETRANS_POWER /* Retransmission Effort (Power) */
+};
+
+/*******************************************************************************
+**
+** Function btm_sco_flush_sco_data
+**
+** Description This function is called to flush the SCO data for this channel.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sco_flush_sco_data(UINT16 sco_inx)
+{
+#if BTM_SCO_HCI_INCLUDED == TRUE
+#if (BTM_MAX_SCO_LINKS>0)
+ tSCO_CONN *p ;
+ BT_HDR *p_buf;
+
+ if (sco_inx < BTM_MAX_SCO_LINKS)
+ {
+ p = &btm_cb.sco_cb.sco_db[sco_inx];
+ while (p->xmit_data_q.p_first)
+ {
+ if ((p_buf = (BT_HDR *)GKI_dequeue (&p->xmit_data_q)) != NULL)
+ GKI_freebuf (p_buf);
+ }
+ }
+#endif
+#endif
+}
+/*******************************************************************************
+**
+** Function btm_sco_init
+**
+** Description This function is called at BTM startup to initialize
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sco_init (void)
+{
+#if 0 /* cleared in btm_init; put back in if called from anywhere else! */
+ memset (&btm_cb.sco_cb, 0, sizeof(tSCO_CB));
+#endif
+ /* Initialize nonzero defaults */
+ btm_cb.sco_cb.sco_disc_reason = BTM_INVALID_SCO_DISC_REASON;
+
+ btm_cb.sco_cb.def_esco_parms = btm_esco_defaults; /* Initialize with defaults */
+ btm_cb.sco_cb.desired_sco_mode = BTM_DEFAULT_SCO_MODE;
+}
+
+/*******************************************************************************
+**
+** Function btm_esco_conn_rsp
+**
+** Description This function is called upon receipt of an (e)SCO connection
+** request event (BTM_ESCO_CONN_REQ_EVT) to accept or reject
+** the request. Parameters used to negotiate eSCO links.
+** If p_parms is NULL, then default values are used.
+** If the link type of the incoming request is SCO, then only
+** the tx_bw, max_latency, content format, and packet_types are
+** valid. The hci_status parameter should be
+** ([0x0] to accept, [0x0d..0x0f] to reject)
+**
+** Returns void
+**
+*******************************************************************************/
+static void btm_esco_conn_rsp (UINT16 sco_inx, UINT8 hci_status, BD_ADDR bda,
+ tBTM_ESCO_PARAMS *p_parms)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+ tSCO_CONN *p_sco = NULL;
+ tBTM_ESCO_PARAMS *p_setup;
+ UINT16 temp_pkt_types;
+
+ if (sco_inx < BTM_MAX_SCO_LINKS)
+ p_sco = &btm_cb.sco_cb.sco_db[sco_inx];
+
+ /* Reject the connect request if refused by caller or wrong state */
+ if (hci_status != HCI_SUCCESS || p_sco == NULL)
+ {
+ if (p_sco)
+ {
+ p_sco->state = (p_sco->state == SCO_ST_W4_CONN_RSP) ? SCO_ST_LISTENING
+ : SCO_ST_UNUSED;
+ }
+
+ if (!btm_cb.sco_cb.esco_supported)
+ {
+ if (!btsnd_hcic_reject_conn (bda, hci_status))
+ {
+ BTM_TRACE_ERROR0("Could not reject (e)SCO conn: No Buffer!!!");
+ }
+ }
+ else
+ {
+ if (!btsnd_hcic_reject_esco_conn (bda, hci_status))
+ {
+ BTM_TRACE_ERROR0("Could not reject (e)SCO conn: No Buffer!!!");
+ }
+ }
+ }
+ else /* Connection is being accepted */
+ {
+ p_sco->state = SCO_ST_CONNECTING;
+ if (btm_cb.devcb.local_version.hci_version >= HCI_PROTO_VERSION_1_2)
+ {
+ p_setup = &p_sco->esco.setup;
+ /* If parameters not specified use the default */
+ if (p_parms)
+ *p_setup = *p_parms;
+ else /* Use the last setup passed thru BTM_SetEscoMode (or defaults) */
+ {
+ *p_setup = btm_cb.sco_cb.def_esco_parms;
+ }
+
+ temp_pkt_types = (p_setup->packet_types &
+ BTM_SCO_SUPPORTED_PKTS_MASK &
+ btm_cb.btm_sco_pkt_types_supported);
+
+ /* Make sure at least one eSCO packet type is sent, else might confuse peer */
+ /* Taking this out to confirm with BQB tests
+ ** Real application would like to include this though, as many devices
+ ** do not retry with SCO only if an eSCO connection fails.
+ if (!(temp_pkt_types & BTM_ESCO_LINK_ONLY_MASK))
+ {
+ temp_pkt_types |= BTM_SCO_PKT_TYPES_MASK_EV3;
+ }
+ */
+ /* If SCO request, remove eSCO packet types (conformance) */
+ if (p_sco->esco.data.link_type == BTM_LINK_TYPE_SCO)
+ {
+ temp_pkt_types &= BTM_SCO_LINK_ONLY_MASK;
+
+ if (btm_cb.devcb.local_version.hci_version >= HCI_PROTO_VERSION_2_0)
+ {
+ temp_pkt_types |= BTM_SCO_EXCEPTION_PKTS_MASK;
+ }
+ }
+ /* OR in any exception packet types if at least 2.0 version of spec */
+ else if (btm_cb.devcb.local_version.hci_version >= HCI_PROTO_VERSION_2_0)
+ {
+ temp_pkt_types |= ((p_setup->packet_types & BTM_SCO_EXCEPTION_PKTS_MASK) |
+ (btm_cb.btm_sco_pkt_types_supported & BTM_SCO_EXCEPTION_PKTS_MASK));
+ }
+
+ if (btsnd_hcic_accept_esco_conn (bda, p_setup->tx_bw, p_setup->rx_bw,
+ p_setup->max_latency, p_setup->voice_contfmt,
+ p_setup->retrans_effort, temp_pkt_types))
+ {
+ p_setup->packet_types = temp_pkt_types;
+ }
+ else
+ {
+ BTM_TRACE_ERROR0("Could not accept SCO conn: No Buffer!!!");
+ }
+ }
+ else /* Controller is version 1.1 or earlier */
+ {
+ btsnd_hcic_accept_conn (bda, 0);
+ }
+ }
+#endif
+}
+
+
+#if BTM_SCO_HCI_INCLUDED == TRUE
+/*******************************************************************************
+**
+** Function btm_sco_check_send_pkts
+**
+** Description This function is called to check if it can send packets
+** to the Host Controller.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sco_check_send_pkts (UINT16 sco_inx)
+{
+ BT_HDR *p_buf;
+ tSCO_CB *p_cb = &btm_cb.sco_cb;
+ tSCO_CONN *p_ccb = &p_cb->sco_db[sco_inx];
+
+ /* If there is data to send, send it now */
+ while (p_ccb->xmit_data_q.p_first != NULL)
+ {
+ p_buf = NULL;
+
+#if BTM_SCO_HCI_DEBUG
+ BTM_TRACE_DEBUG1 ("btm: [%d] buf in xmit_data_q", p_ccb->xmit_data_q.count );
+#endif
+ p_buf = (BT_HDR *)GKI_dequeue (&p_ccb->xmit_data_q);
+
+ HCI_SCO_DATA_TO_LOWER (p_buf);
+ }
+}
+#endif /* BTM_SCO_HCI_INCLUDED == TRUE */
+
+/*******************************************************************************
+**
+** Function btm_route_sco_data
+**
+** Description Route received SCO data.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_route_sco_data(BT_HDR *p_msg)
+{
+#if BTM_SCO_HCI_INCLUDED == TRUE
+ UINT16 sco_inx, handle;
+ UINT8 *p = (UINT8 *)(p_msg + 1) + p_msg->offset;
+ UINT8 pkt_size = 0;
+ UINT8 pkt_status = 0;
+
+ /* Extract Packet_Status_Flag and handle */
+ STREAM_TO_UINT16 (handle, p);
+ pkt_status = HCID_GET_EVENT(handle);
+ handle = HCID_GET_HANDLE (handle);
+
+ STREAM_TO_UINT8 (pkt_size, p);
+
+ if ((sco_inx = btm_find_scb_by_handle(handle)) != BTM_MAX_SCO_LINKS )
+ {
+ /* send data callback */
+ if (!btm_cb.sco_cb.p_data_cb )
+ /* if no data callback registered, just free the buffer */
+ GKI_freebuf (p_msg);
+ else
+ {
+ (*btm_cb.sco_cb.p_data_cb)(sco_inx, p_msg, (tBTM_SCO_DATA_FLAG) pkt_status);
+ }
+ }
+ else /* no mapping handle SCO connection is active, free the buffer */
+ {
+ GKI_freebuf (p_msg);
+ }
+#else
+ GKI_freebuf(p_msg);
+#endif
+}
+
+
+
+/*******************************************************************************
+**
+** Function BTM_WriteScoData
+**
+** Description This function write SCO data to a specified instance. The data
+** to be written p_buf needs to carry an offset of
+** HCI_SCO_PREAMBLE_SIZE bytes, and the data length can not
+** exceed BTM_SCO_DATA_SIZE_MAX bytes, whose default value is set
+** to 60 and is configurable. Data longer than the maximum bytes
+** will be truncated.
+**
+** Returns BTM_SUCCESS: data write is successful
+** BTM_ILLEGAL_VALUE: SCO data contains illegal offset value.
+** BTM_SCO_BAD_LENGTH: SCO data length exceeds the max SCO packet
+** size.
+** BTM_NO_RESOURCES: no resources.
+** BTM_UNKNOWN_ADDR: unknown SCO connection handle, or SCO is not
+** routed via HCI.
+**
+**
+*******************************************************************************/
+tBTM_STATUS BTM_WriteScoData (UINT16 sco_inx, BT_HDR *p_buf)
+{
+#if (BTM_SCO_HCI_INCLUDED == TRUE) && (BTM_MAX_SCO_LINKS>0)
+ tSCO_CONN *p_ccb = &btm_cb.sco_cb.sco_db[sco_inx];
+ UINT8 *p;
+ tBTM_STATUS status = BTM_SUCCESS;
+
+ if (sco_inx < BTM_MAX_SCO_LINKS && btm_cb.sco_cb.p_data_cb &&
+ p_ccb->state == SCO_ST_CONNECTED)
+ {
+ /* Ensure we have enough space in the buffer for the SCO and HCI headers */
+ if (p_buf->offset < HCI_SCO_PREAMBLE_SIZE)
+ {
+ BTM_TRACE_ERROR1 ("BTM SCO - cannot send buffer, offset: %d", p_buf->offset);
+ GKI_freebuf (p_buf);
+ status = BTM_ILLEGAL_VALUE;
+ }
+ else /* write HCI header */
+ {
+ /* Step back 3 bytes to add the headers */
+ p_buf->offset -= HCI_SCO_PREAMBLE_SIZE;
+ /* Set the pointer to the beginning of the data */
+ p = (UINT8 *)(p_buf + 1) + p_buf->offset;
+ /* add HCI handle */
+ UINT16_TO_STREAM (p, p_ccb->hci_handle);
+ /* only sent the first BTM_SCO_DATA_SIZE_MAX bytes data if more than max,
+ and set warning status */
+ if (p_buf->len > BTM_SCO_DATA_SIZE_MAX)
+ {
+ p_buf->len = BTM_SCO_DATA_SIZE_MAX;
+ status = BTM_SCO_BAD_LENGTH;
+ }
+
+ UINT8_TO_STREAM (p, (UINT8)p_buf->len);
+ p_buf->len += HCI_SCO_PREAMBLE_SIZE;
+
+ GKI_enqueue (&p_ccb->xmit_data_q, p_buf);
+
+ btm_sco_check_send_pkts (sco_inx);
+ }
+ }
+ else
+ {
+ GKI_freebuf(p_buf);
+
+ BTM_TRACE_WARNING2 ("BTM_WriteScoData, invalid sco index: %d at state [%d]",
+ sco_inx, btm_cb.sco_cb.sco_db[sco_inx].state);
+ status = BTM_UNKNOWN_ADDR;
+ }
+
+ return (status);
+
+#else
+ return (BTM_NO_RESOURCES);
+#endif
+}
+
+#if (BTM_MAX_SCO_LINKS>0)
+/*******************************************************************************
+**
+** Function btm_send_connect_request
+**
+** Description This function is called to respond to SCO connect indications
+**
+** Returns void
+**
+*******************************************************************************/
+static tBTM_STATUS btm_send_connect_request(UINT16 acl_handle,
+ tBTM_ESCO_PARAMS *p_setup)
+{
+ UINT16 temp_pkt_types;
+ UINT8 xx;
+ tACL_CONN *p_acl;
+
+ /* Send connect request depending on version of spec */
+ if (!btm_cb.sco_cb.esco_supported)
+ {
+ if (!btsnd_hcic_add_SCO_conn (acl_handle, BTM_ESCO_2_SCO(p_setup->packet_types)))
+ return (BTM_NO_RESOURCES);
+ }
+ else
+ {
+ temp_pkt_types = (p_setup->packet_types & BTM_SCO_SUPPORTED_PKTS_MASK &
+ btm_cb.btm_sco_pkt_types_supported);
+
+ /* OR in any exception packet types if at least 2.0 version of spec */
+ if (btm_cb.devcb.local_version.hci_version >= HCI_PROTO_VERSION_2_0)
+ {
+ temp_pkt_types |= ((p_setup->packet_types & BTM_SCO_EXCEPTION_PKTS_MASK) |
+ (btm_cb.btm_sco_pkt_types_supported & BTM_SCO_EXCEPTION_PKTS_MASK));
+ }
+
+ /* Finally, remove EDR eSCO if the remote device doesn't support it */
+ /* UPF25: Only SCO was brought up in this case */
+ btm_handle_to_acl_index(acl_handle);
+ if ((xx = btm_handle_to_acl_index(acl_handle)) < MAX_L2CAP_LINKS)
+ {
+ p_acl = &btm_cb.acl_db[xx];
+ if (!HCI_EDR_ESCO_2MPS_SUPPORTED(p_acl->features))
+ {
+
+ BTM_TRACE_WARNING0("BTM Remote does not support 2-EDR eSCO");
+ temp_pkt_types |= (HCI_ESCO_PKT_TYPES_MASK_NO_2_EV3 |
+ HCI_ESCO_PKT_TYPES_MASK_NO_2_EV5);
+ }
+ if (!HCI_EDR_ESCO_3MPS_SUPPORTED(p_acl->features))
+ {
+
+ BTM_TRACE_WARNING0("BTM Remote does not support 3-EDR eSCO");
+ temp_pkt_types |= (HCI_ESCO_PKT_TYPES_MASK_NO_3_EV3 |
+ HCI_ESCO_PKT_TYPES_MASK_NO_3_EV5);
+ }
+ }
+
+
+ BTM_TRACE_API6(" txbw 0x%x, rxbw 0x%x, lat 0x%x, voice 0x%x, retrans 0x%02x, pkt 0x%04x",
+ p_setup->tx_bw, p_setup->rx_bw,
+ p_setup->max_latency, p_setup->voice_contfmt,
+ p_setup->retrans_effort, temp_pkt_types);
+
+ if (!btsnd_hcic_setup_esco_conn(acl_handle,
+ p_setup->tx_bw,
+ p_setup->rx_bw,
+ p_setup->max_latency,
+ p_setup->voice_contfmt,
+ p_setup->retrans_effort,
+ temp_pkt_types))
+ return (BTM_NO_RESOURCES);
+ else
+ p_setup->packet_types = temp_pkt_types;
+ }
+
+ return (BTM_CMD_STARTED);
+}
+#endif
+
+/*******************************************************************************
+**
+** Function btm_set_sco_ind_cback
+**
+** Description This function is called to register for TCS SCO connect
+** indications.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_set_sco_ind_cback( tBTM_SCO_IND_CBACK *sco_ind_cb )
+{
+ btm_cb.sco_cb.app_sco_ind_cb = sco_ind_cb;
+}
+
+/*******************************************************************************
+**
+** Function btm_accept_sco_link
+**
+** Description This function is called to respond to TCS SCO connect
+** indications
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_accept_sco_link(UINT16 sco_inx, tBTM_ESCO_PARAMS *p_setup,
+ tBTM_SCO_CB *p_conn_cb, tBTM_SCO_CB *p_disc_cb)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+ tSCO_CONN *p_sco;
+
+ if (sco_inx >= BTM_MAX_SCO_LINKS)
+ {
+ BTM_TRACE_ERROR1("btm_accept_sco_link: Invalid sco_inx(%d)", sco_inx);
+ return;
+ }
+
+ /* Link role is ignored in for this message */
+ p_sco = &btm_cb.sco_cb.sco_db[sco_inx];
+ p_sco->p_conn_cb = p_conn_cb;
+ p_sco->p_disc_cb = p_disc_cb;
+ p_sco->esco.data.link_type = BTM_LINK_TYPE_ESCO; /* Accept with all supported types */
+
+ BTM_TRACE_DEBUG1("TCS accept SCO: Packet Types 0x%04x", p_setup->packet_types);
+
+ btm_esco_conn_rsp(sco_inx, HCI_SUCCESS, p_sco->esco.data.bd_addr, p_setup);
+#else
+ btm_reject_sco_link(sco_inx);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function btm_reject_sco_link
+**
+** Description This function is called to respond to SCO connect indications
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_reject_sco_link( UINT16 sco_inx )
+{
+ btm_esco_conn_rsp(sco_inx, HCI_ERR_HOST_REJECT_RESOURCES,
+ btm_cb.sco_cb.sco_db[sco_inx].esco.data.bd_addr, NULL);
+}
+
+/*******************************************************************************
+**
+** Function BTM_CreateSco
+**
+** Description This function is called to create an SCO connection. If the
+** "is_orig" flag is TRUE, the connection will be originated,
+** otherwise BTM will wait for the other side to connect.
+**
+** NOTE: If BTM_IGNORE_SCO_PKT_TYPE is passed in the pkt_types
+** parameter the default packet types is used.
+**
+** Returns BTM_UNKNOWN_ADDR if the ACL connection is not up
+** BTM_BUSY if another SCO being set up to
+** the same BD address
+** BTM_NO_RESOURCES if the max SCO limit has been reached
+** BTM_CMD_STARTED if the connection establishment is started.
+** In this case, "*p_sco_inx" is filled in
+** with the sco index used for the connection.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_CreateSco (BD_ADDR remote_bda, BOOLEAN is_orig, UINT16 pkt_types,
+ UINT16 *p_sco_inx, tBTM_SCO_CB *p_conn_cb,
+ tBTM_SCO_CB *p_disc_cb)
+{
+#if (BTM_MAX_SCO_LINKS > 0)
+ tBTM_ESCO_PARAMS *p_setup;
+ tSCO_CONN *p = &btm_cb.sco_cb.sco_db[0];
+ UINT16 xx;
+ UINT16 acl_handle = 0;
+ UINT16 temp_pkt_types;
+ tACL_CONN *p_acl;
+
+#if (BTM_PWR_MGR_INCLUDED == TRUE) && (BTM_SCO_WAKE_PARKED_LINK == TRUE)
+ tBTM_PM_MODE md;
+ tBTM_PM_PWR_MD pm;
+#else
+ UINT8 mode;
+#endif
+
+ *p_sco_inx = BTM_INVALID_SCO_INDEX;
+
+ /* If originating, ensure that there is an ACL connection to the BD Address */
+ if (is_orig)
+ {
+ if ((!remote_bda) || ((acl_handle = BTM_GetHCIConnHandle (remote_bda)) == 0xFFFF))
+ return (BTM_UNKNOWN_ADDR);
+ }
+
+ if (remote_bda)
+ {
+ /* If any SCO is being established to the remote BD address, refuse this */
+ for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++)
+ {
+ if (((p->state == SCO_ST_CONNECTING) || (p->state == SCO_ST_LISTENING)
+ || (p->state == SCO_ST_PEND_UNPARK))
+ && (!memcmp (p->esco.data.bd_addr, remote_bda, BD_ADDR_LEN)))
+ {
+ return (BTM_BUSY);
+ }
+ }
+ }
+ else
+ {
+ /* Support only 1 wildcard BD address at a time */
+ for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++)
+ {
+ if ((p->state == SCO_ST_LISTENING) && (!p->rem_bd_known))
+ return (BTM_BUSY);
+ }
+ }
+
+ /* Now, try to find an unused control block, and kick off the SCO establishment */
+ for (xx = 0, p = &btm_cb.sco_cb.sco_db[0]; xx < BTM_MAX_SCO_LINKS; xx++, p++)
+ {
+ if (p->state == SCO_ST_UNUSED)
+ {
+ if (remote_bda)
+ {
+ if (is_orig)
+ {
+ /* can not create SCO link if in park mode */
+#if (BTM_PWR_MGR_INCLUDED == TRUE) && (BTM_SCO_WAKE_PARKED_LINK == TRUE)
+ if(BTM_ReadPowerMode(remote_bda, &md) == BTM_SUCCESS)
+ {
+ if (md == BTM_PM_MD_PARK || md == BTM_PM_MD_SNIFF)
+ {
+/* Coverity: FALSE-POSITIVE error from Coverity tool. Please do NOT remove following comment. */
+/* coverity[uninit_use_in_call] False-positive: setting the mode to BTM_PM_MD_ACTIVE only uses settings.mode
+ the other data members of tBTM_PM_PWR_MD are ignored
+*/
+ pm.mode = BTM_PM_MD_ACTIVE;
+ BTM_SetPowerMode(BTM_PM_SET_ONLY_ID, remote_bda, &pm);
+ p->state = SCO_ST_PEND_UNPARK;
+ }
+ }
+#elif BTM_PWR_MGR_INCLUDED == TRUE
+ if( (BTM_ReadPowerMode(remote_bda, &mode) == BTM_SUCCESS) && (mode == BTM_PM_MD_PARK) )
+ return (BTM_WRONG_MODE);
+#else
+ if( (BTM_ReadAclMode(remote_bda, &mode) == BTM_SUCCESS) && (mode == BTM_ACL_MODE_PARK) )
+ return (BTM_WRONG_MODE);
+#endif
+ }
+ memcpy (p->esco.data.bd_addr, remote_bda, BD_ADDR_LEN);
+ p->rem_bd_known = TRUE;
+ }
+ else
+ p->rem_bd_known = FALSE;
+
+ /* Link role is ignored in for this message */
+ if (pkt_types == BTM_IGNORE_SCO_PKT_TYPE)
+ pkt_types = btm_cb.sco_cb.def_esco_parms.packet_types;
+
+ p_setup = &p->esco.setup;
+ *p_setup = btm_cb.sco_cb.def_esco_parms;
+ p_setup->packet_types = (btm_cb.sco_cb.desired_sco_mode == BTM_LINK_TYPE_SCO)
+ ? (pkt_types & BTM_SCO_LINK_ONLY_MASK) : pkt_types;
+
+ temp_pkt_types = (p_setup->packet_types & BTM_SCO_SUPPORTED_PKTS_MASK &
+ btm_cb.btm_sco_pkt_types_supported);
+
+ /* OR in any exception packet types if at least 2.0 version of spec */
+ if (btm_cb.devcb.local_version.hci_version >= HCI_PROTO_VERSION_2_0)
+ {
+ if (btm_cb.sco_cb.desired_sco_mode == HCI_LINK_TYPE_ESCO)
+ {
+ temp_pkt_types |= ((p_setup->packet_types & BTM_SCO_EXCEPTION_PKTS_MASK) |
+ (btm_cb.btm_sco_pkt_types_supported & BTM_SCO_EXCEPTION_PKTS_MASK));
+ }
+ else /* Only using SCO packet types; turn off EDR also */
+ {
+ temp_pkt_types |= BTM_SCO_EXCEPTION_PKTS_MASK;
+ }
+ }
+
+ p_setup->packet_types = temp_pkt_types;
+ p->p_conn_cb = p_conn_cb;
+ p->p_disc_cb = p_disc_cb;
+ p->hci_handle = BTM_INVALID_HCI_HANDLE;
+ p->is_orig = is_orig;
+
+ if( p->state != SCO_ST_PEND_UNPARK )
+ {
+ if (is_orig)
+ {
+ /* If role change is in progress, do not proceed with SCO setup
+ * Wait till role change is complete */
+ p_acl = btm_bda_to_acl(remote_bda);
+ if (p_acl && p_acl->switch_role_state != BTM_ACL_SWKEY_STATE_IDLE)
+ {
+ BTM_TRACE_API1("Role Change is in progress for ACL handle 0x%04x",acl_handle);
+ p->state = SCO_ST_PEND_ROLECHANGE;
+
+ }
+ }
+ }
+
+ if( p->state != SCO_ST_PEND_UNPARK && p->state != SCO_ST_PEND_ROLECHANGE )
+ {
+ if (is_orig)
+ {
+ BTM_TRACE_API2("BTM_CreateSco -> (e)SCO Link for ACL handle 0x%04x, Desired Type %d",
+ acl_handle, btm_cb.sco_cb.desired_sco_mode);
+
+ if ((btm_send_connect_request(acl_handle, p_setup)) != BTM_CMD_STARTED)
+ return (BTM_NO_RESOURCES);
+
+ p->state = SCO_ST_CONNECTING;
+ }
+ else
+ p->state = SCO_ST_LISTENING;
+ }
+
+ *p_sco_inx = xx;
+
+ return (BTM_CMD_STARTED);
+ }
+ }
+
+#endif
+ /* If here, all SCO blocks in use */
+ return (BTM_NO_RESOURCES);
+}
+
+#if (BTM_PWR_MGR_INCLUDED == TRUE) && (BTM_SCO_WAKE_PARKED_LINK == TRUE)
+/*******************************************************************************
+**
+** Function btm_sco_chk_pend_unpark
+**
+** Description This function is called by BTIF when there is a mode change
+** event to see if there are SCO commands waiting for the unpark.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sco_chk_pend_unpark (UINT8 hci_status, UINT16 hci_handle)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+ UINT16 xx;
+ UINT16 acl_handle;
+ tSCO_CONN *p = &btm_cb.sco_cb.sco_db[0];
+
+ for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++)
+ {
+ if ((p->state == SCO_ST_PEND_UNPARK) &&
+ ((acl_handle = BTM_GetHCIConnHandle (p->esco.data.bd_addr)) == hci_handle))
+
+ {
+ BTM_TRACE_API3("btm_sco_chk_pend_unpark -> (e)SCO Link for ACL handle 0x%04x, Desired Type %d, hci_status 0x%02x",
+ acl_handle, btm_cb.sco_cb.desired_sco_mode, hci_status);
+
+ if ((btm_send_connect_request(acl_handle, &p->esco.setup)) == BTM_CMD_STARTED)
+ p->state = SCO_ST_CONNECTING;
+ }
+ }
+#endif
+}
+#endif
+
+/*******************************************************************************
+**
+** Function btm_sco_chk_pend_rolechange
+**
+** Description This function is called by BTIF when there is a role change
+** event to see if there are SCO commands waiting for the role change.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sco_chk_pend_rolechange (UINT16 hci_handle)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+ UINT16 xx;
+ UINT16 acl_handle;
+ tSCO_CONN *p = &btm_cb.sco_cb.sco_db[0];
+
+ for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++)
+ {
+ if ((p->state == SCO_ST_PEND_ROLECHANGE) &&
+ ((acl_handle = BTM_GetHCIConnHandle (p->esco.data.bd_addr)) == hci_handle))
+
+ {
+ BTM_TRACE_API1("btm_sco_chk_pend_rolechange -> (e)SCO Link for ACL handle 0x%04x", acl_handle);
+
+ if ((btm_send_connect_request(acl_handle, &p->esco.setup)) == BTM_CMD_STARTED)
+ p->state = SCO_ST_CONNECTING;
+ }
+ }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function btm_sco_conn_req
+**
+** Description This function is called by BTIF when an SCO connection
+** request is received from a remote.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sco_conn_req (BD_ADDR bda, DEV_CLASS dev_class, UINT8 link_type)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+ tSCO_CB *p_sco = &btm_cb.sco_cb;
+ tSCO_CONN *p = &p_sco->sco_db[0];
+ UINT16 xx;
+ tBTM_ESCO_CONN_REQ_EVT_DATA evt_data;
+
+ for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++)
+ {
+ /*
+ * If the sco state is in the SCO_ST_CONNECTING state, we still need
+ * to return accept sco to avoid race conditon for sco creation
+ */
+ if (((p->state == SCO_ST_LISTENING && p->rem_bd_known) || p->state == SCO_ST_CONNECTING)
+ && (!memcmp (p->esco.data.bd_addr, bda, BD_ADDR_LEN)))
+ {
+ /* If this guy was a wildcard, he is not one any more */
+ p->rem_bd_known = TRUE;
+ p->esco.data.link_type = link_type;
+ p->state = SCO_ST_W4_CONN_RSP;
+ memcpy (p->esco.data.bd_addr, bda, BD_ADDR_LEN);
+
+ /* If no callback, auto-accept the connection if packet types match */
+ if (!p->esco.p_esco_cback)
+ {
+ /* If requesting eSCO reject if default parameters are SCO only */
+ if ((link_type == BTM_LINK_TYPE_ESCO
+ && !(p_sco->def_esco_parms.packet_types & BTM_ESCO_LINK_ONLY_MASK)
+ && ((p_sco->def_esco_parms.packet_types & BTM_SCO_EXCEPTION_PKTS_MASK)
+ == BTM_SCO_EXCEPTION_PKTS_MASK))
+
+ /* Reject request if SCO is desired but no SCO packets delected */
+ || (link_type == BTM_LINK_TYPE_SCO
+ && !(p_sco->def_esco_parms.packet_types & BTM_SCO_LINK_ONLY_MASK)))
+ {
+ btm_esco_conn_rsp(xx, HCI_ERR_HOST_REJECT_RESOURCES, bda, NULL);
+ }
+ else /* Accept the request */
+ {
+ btm_esco_conn_rsp(xx, HCI_SUCCESS, bda, NULL);
+ }
+ }
+ else /* Notify upper layer of connect indication */
+ {
+ memcpy(evt_data.bd_addr, bda, BD_ADDR_LEN);
+ memcpy(evt_data.dev_class, dev_class, DEV_CLASS_LEN);
+ evt_data.link_type = link_type;
+ evt_data.sco_inx = xx;
+ p->esco.p_esco_cback(BTM_ESCO_CONN_REQ_EVT, (tBTM_ESCO_EVT_DATA *)&evt_data);
+ }
+
+ return;
+ }
+ }
+
+ /* TCS usage */
+ if (btm_cb.sco_cb.app_sco_ind_cb)
+ {
+ /* Now, try to find an unused control block */
+ for (xx = 0, p = &btm_cb.sco_cb.sco_db[0]; xx < BTM_MAX_SCO_LINKS; xx++, p++)
+ {
+ if (p->state == SCO_ST_UNUSED)
+ {
+ p->is_orig = FALSE;
+ p->state = SCO_ST_LISTENING;
+
+ p->esco.data.link_type = link_type;
+ memcpy (p->esco.data.bd_addr, bda, BD_ADDR_LEN);
+ p->rem_bd_known = TRUE;
+ break;
+ }
+ }
+ if( xx < BTM_MAX_SCO_LINKS)
+ {
+ btm_cb.sco_cb.app_sco_ind_cb(xx);
+ return;
+ }
+ }
+
+#endif
+ /* If here, no one wants the SCO connection. Reject it */
+ BTM_TRACE_WARNING0("btm_sco_conn_req: No one wants this SCO connection; rejecting it");
+ btm_esco_conn_rsp(BTM_MAX_SCO_LINKS, HCI_ERR_HOST_REJECT_RESOURCES, bda, NULL);
+}
+
+/*******************************************************************************
+**
+** Function btm_sco_connected
+**
+** Description This function is called by BTIF when an (e)SCO connection
+** is connected.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sco_connected (UINT8 hci_status, BD_ADDR bda, UINT16 hci_handle,
+ tBTM_ESCO_DATA *p_esco_data)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+ tSCO_CONN *p = &btm_cb.sco_cb.sco_db[0];
+ UINT16 xx;
+ BOOLEAN spt = FALSE;
+ tBTM_CHG_ESCO_PARAMS parms;
+#endif
+
+ btm_cb.sco_cb.sco_disc_reason = hci_status;
+
+#if (BTM_MAX_SCO_LINKS>0)
+ for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++)
+ {
+ if (((p->state == SCO_ST_CONNECTING) ||
+ (p->state == SCO_ST_LISTENING) ||
+ (p->state == SCO_ST_W4_CONN_RSP))
+ && (p->rem_bd_known)
+ && (!bda || !memcmp (p->esco.data.bd_addr, bda, BD_ADDR_LEN)))
+ {
+ if (hci_status != HCI_SUCCESS)
+ {
+ /* Report the error if originator, otherwise remain in Listen mode */
+ if (p->is_orig)
+ {
+ /* If role switch is pending, we need try again after role switch is complete */
+ if(hci_status == HCI_ERR_ROLE_SWITCH_PENDING)
+ {
+ BTM_TRACE_API1("Role Change pending for HCI handle 0x%04x",hci_handle);
+ p->state = SCO_ST_PEND_ROLECHANGE;
+ }
+ /* avoid calling disconnect callback because of sco creation race */
+ else if (hci_status != HCI_ERR_LMP_ERR_TRANS_COLLISION)
+ {
+ p->state = SCO_ST_UNUSED;
+ (*p->p_disc_cb)(xx);
+ }
+ }
+ else
+ {
+ /* Notify the upper layer that incoming sco connection has failed. */
+ if (p->state == SCO_ST_CONNECTING)
+ {
+ p->state = SCO_ST_UNUSED;
+ (*p->p_disc_cb)(xx);
+ }
+ else
+ p->state = SCO_ST_LISTENING;
+ }
+
+ return;
+ }
+
+ if (p->state == SCO_ST_LISTENING)
+ spt = TRUE;
+
+ p->state = SCO_ST_CONNECTED;
+ p->hci_handle = hci_handle;
+
+ if (!btm_cb.sco_cb.esco_supported)
+ {
+ p->esco.data.link_type = BTM_LINK_TYPE_SCO;
+ if (spt)
+ {
+ parms.packet_types = p->esco.setup.packet_types;
+ /* Keep the other parameters the same for SCO */
+ parms.max_latency = p->esco.setup.max_latency;
+ parms.retrans_effort = p->esco.setup.retrans_effort;
+
+ BTM_ChangeEScoLinkParms(xx, &parms);
+ }
+ }
+ else
+ {
+ if (p_esco_data)
+ p->esco.data = *p_esco_data;
+ }
+
+ (*p->p_conn_cb)(xx);
+
+ return;
+ }
+ }
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function btm_find_scb_by_handle
+**
+** Description Look through all active SCO connection for a match based on the
+** HCI handle.
+**
+** Returns index to matched SCO connection CB, or BTM_MAX_SCO_LINKS if
+** no match.
+**
+*******************************************************************************/
+UINT16 btm_find_scb_by_handle (UINT16 handle)
+{
+ int xx;
+ tSCO_CONN *p = &btm_cb.sco_cb.sco_db[0];
+
+ for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++)
+ {
+ if ((p->state == SCO_ST_CONNECTED) && (p->hci_handle == handle))
+ {
+ return (xx);
+ }
+ }
+
+ /* If here, no match found */
+ return (xx);
+}
+
+/*******************************************************************************
+**
+** Function BTM_RemoveSco
+**
+** Description This function is called to remove a specific SCO connection.
+**
+** Returns status of the operation
+**
+*******************************************************************************/
+tBTM_STATUS BTM_RemoveSco (UINT16 sco_inx)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+ tSCO_CONN *p = &btm_cb.sco_cb.sco_db[sco_inx];
+ UINT16 tempstate;
+
+ /* Validity check */
+ if ((sco_inx >= BTM_MAX_SCO_LINKS) || (p->state == SCO_ST_UNUSED))
+ return (BTM_UNKNOWN_ADDR);
+
+ /* If no HCI handle, simply drop the connection and return */
+ if (p->hci_handle == BTM_INVALID_HCI_HANDLE || p->state == SCO_ST_PEND_UNPARK)
+ {
+ p->hci_handle = BTM_INVALID_HCI_HANDLE;
+ p->state = SCO_ST_UNUSED;
+ p->esco.p_esco_cback = NULL; /* Deregister the eSCO event callback */
+ return (BTM_SUCCESS);
+ }
+
+ tempstate = p->state;
+ p->state = SCO_ST_DISCONNECTING;
+
+ if (!btsnd_hcic_disconnect (p->hci_handle, HCI_ERR_PEER_USER))
+ {
+ p->state = tempstate;
+ return (BTM_NO_RESOURCES);
+ }
+
+ return (BTM_CMD_STARTED);
+#else
+ return (BTM_NO_RESOURCES);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function btm_remove_sco_links
+**
+** Description This function is called to remove all sco links for an ACL link.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_remove_sco_links (BD_ADDR bda)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+ tSCO_CONN *p = &btm_cb.sco_cb.sco_db[0];
+ UINT16 xx;
+
+ for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++)
+ {
+ if (p->rem_bd_known && (!memcmp (p->esco.data.bd_addr, bda, BD_ADDR_LEN)))
+ {
+ BTM_RemoveSco(xx);
+ }
+ }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function btm_sco_removed
+**
+** Description This function is called by BTIF when an SCO connection
+** is removed.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sco_removed (UINT16 hci_handle, UINT8 reason)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+ tSCO_CONN *p = &btm_cb.sco_cb.sco_db[0];
+ UINT16 xx;
+#endif
+
+ btm_cb.sco_cb.sco_disc_reason = reason;
+
+#if (BTM_MAX_SCO_LINKS>0)
+ p = &btm_cb.sco_cb.sco_db[0];
+ for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++)
+ {
+ if ((p->state != SCO_ST_UNUSED) && (p->state != SCO_ST_LISTENING) && (p->hci_handle == hci_handle))
+ {
+ btm_sco_flush_sco_data(xx);
+
+ p->state = SCO_ST_UNUSED;
+ p->hci_handle = BTM_INVALID_HCI_HANDLE;
+ p->rem_bd_known = FALSE;
+ p->esco.p_esco_cback = NULL; /* Deregister eSCO callback */
+ (*p->p_disc_cb)(xx);
+
+ return;
+ }
+ }
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function btm_sco_acl_removed
+**
+** Description This function is called when an ACL connection is
+** removed. If the BD address is NULL, it is assumed that
+** the local device is down, and all SCO links are removed.
+** If a specific BD address is passed, only SCO connections
+** to that BD address are removed.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sco_acl_removed (BD_ADDR bda)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+ tSCO_CONN *p = &btm_cb.sco_cb.sco_db[0];
+ UINT16 xx;
+
+ for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++)
+ {
+ if (p->state != SCO_ST_UNUSED)
+ {
+ if ((!bda) || (!memcmp (p->esco.data.bd_addr, bda, BD_ADDR_LEN) && p->rem_bd_known))
+ {
+ btm_sco_flush_sco_data(xx);
+
+ p->state = SCO_ST_UNUSED;
+ p->esco.p_esco_cback = NULL; /* Deregister eSCO callback */
+ (*p->p_disc_cb)(xx);
+ }
+ }
+ }
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_SetScoPacketTypes
+**
+** Description This function is called to set the packet types used for
+** a specific SCO connection,
+**
+** Parameters pkt_types - One or more of the following
+** BTM_SCO_PKT_TYPES_MASK_HV1
+** BTM_SCO_PKT_TYPES_MASK_HV2
+** BTM_SCO_PKT_TYPES_MASK_HV3
+** BTM_SCO_PKT_TYPES_MASK_EV3
+** BTM_SCO_PKT_TYPES_MASK_EV4
+** BTM_SCO_PKT_TYPES_MASK_EV5
+** BTM_SCO_PKT_TYPES_MASK_NO_2_EV3
+** BTM_SCO_PKT_TYPES_MASK_NO_3_EV3
+** BTM_SCO_PKT_TYPES_MASK_NO_2_EV5
+** BTM_SCO_PKT_TYPES_MASK_NO_3_EV5
+**
+** BTM_SCO_LINK_ALL_MASK - enables all supported types
+**
+** Returns status of the operation
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetScoPacketTypes (UINT16 sco_inx, UINT16 pkt_types)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+ tBTM_CHG_ESCO_PARAMS parms;
+ tSCO_CONN *p;
+
+ /* Validity check */
+ if (sco_inx >= BTM_MAX_SCO_LINKS)
+ return (BTM_UNKNOWN_ADDR);
+
+ p = &btm_cb.sco_cb.sco_db[sco_inx];
+ parms.packet_types = pkt_types;
+
+ /* Keep the other parameters the same for SCO */
+ parms.max_latency = p->esco.setup.max_latency;
+ parms.retrans_effort = p->esco.setup.retrans_effort;
+
+ return (BTM_ChangeEScoLinkParms(sco_inx, &parms));
+#else
+ return (BTM_UNKNOWN_ADDR);
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_ReadScoPacketTypes
+**
+** Description This function is read the packet types used for a specific
+** SCO connection.
+**
+** Returns Packet types supported for the connection
+** One or more of the following (bitmask):
+** BTM_SCO_PKT_TYPES_MASK_HV1
+** BTM_SCO_PKT_TYPES_MASK_HV2
+** BTM_SCO_PKT_TYPES_MASK_HV3
+** BTM_SCO_PKT_TYPES_MASK_EV3
+** BTM_SCO_PKT_TYPES_MASK_EV4
+** BTM_SCO_PKT_TYPES_MASK_EV5
+** BTM_SCO_PKT_TYPES_MASK_NO_2_EV3
+** BTM_SCO_PKT_TYPES_MASK_NO_3_EV3
+** BTM_SCO_PKT_TYPES_MASK_NO_2_EV5
+** BTM_SCO_PKT_TYPES_MASK_NO_3_EV5
+**
+*******************************************************************************/
+UINT16 BTM_ReadScoPacketTypes (UINT16 sco_inx)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+ tSCO_CONN *p = &btm_cb.sco_cb.sco_db[sco_inx];
+
+ /* Validity check */
+ if ((sco_inx < BTM_MAX_SCO_LINKS) && (p->state == SCO_ST_CONNECTED))
+ return (p->esco.setup.packet_types);
+ else
+ return (0);
+#else
+ return (0);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function BTM_ReadScoDiscReason
+**
+** Description This function is returns the reason why an (e)SCO connection
+** has been removed. It contains the value until read, or until
+** another (e)SCO connection has disconnected.
+**
+** Returns HCI reason or BTM_INVALID_SCO_DISC_REASON if not set.
+**
+*******************************************************************************/
+UINT16 BTM_ReadScoDiscReason (void)
+{
+ UINT16 res = btm_cb.sco_cb.sco_disc_reason;
+ btm_cb.sco_cb.sco_disc_reason = BTM_INVALID_SCO_DISC_REASON;
+ return (res);
+}
+
+/*******************************************************************************
+**
+** Function BTM_ReadDeviceScoPacketTypes
+**
+** Description This function is read the SCO packet types that
+** the device supports.
+**
+** Returns Packet types supported by the device.
+** One or more of the following (bitmask):
+** BTM_SCO_PKT_TYPES_MASK_HV1
+** BTM_SCO_PKT_TYPES_MASK_HV2
+** BTM_SCO_PKT_TYPES_MASK_HV3
+** BTM_SCO_PKT_TYPES_MASK_EV3
+** BTM_SCO_PKT_TYPES_MASK_EV4
+** BTM_SCO_PKT_TYPES_MASK_EV5
+** BTM_SCO_PKT_TYPES_MASK_NO_2_EV3
+** BTM_SCO_PKT_TYPES_MASK_NO_3_EV3
+** BTM_SCO_PKT_TYPES_MASK_NO_2_EV5
+** BTM_SCO_PKT_TYPES_MASK_NO_3_EV5
+**
+*******************************************************************************/
+UINT16 BTM_ReadDeviceScoPacketTypes (void)
+{
+ return (btm_cb.btm_sco_pkt_types_supported);
+}
+
+/*******************************************************************************
+**
+** Function BTM_ReadScoHandle
+**
+** Description This function is used to read the HCI handle used for a specific
+** SCO connection,
+**
+** Returns handle for the connection, or 0xFFFF if invalid SCO index.
+**
+*******************************************************************************/
+UINT16 BTM_ReadScoHandle (UINT16 sco_inx)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+ tSCO_CONN *p = &btm_cb.sco_cb.sco_db[sco_inx];
+
+ /* Validity check */
+ if ((sco_inx < BTM_MAX_SCO_LINKS) && (p->state == SCO_ST_CONNECTED))
+ return (p->hci_handle);
+ else
+ return (BTM_INVALID_HCI_HANDLE);
+#else
+ return (BTM_INVALID_HCI_HANDLE);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function BTM_ReadScoBdAddr
+**
+** Description This function is read the remote BD Address for a specific
+** SCO connection,
+**
+** Returns pointer to BD address or NULL if not known
+**
+*******************************************************************************/
+UINT8 *BTM_ReadScoBdAddr (UINT16 sco_inx)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+ tSCO_CONN *p = &btm_cb.sco_cb.sco_db[sco_inx];
+
+ /* Validity check */
+ if ((sco_inx < BTM_MAX_SCO_LINKS) && (p->rem_bd_known))
+ return (p->esco.data.bd_addr);
+ else
+ return (NULL);
+#else
+ return (NULL);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function BTM_SetEScoMode
+**
+** Description This function sets up the negotiated parameters for SCO or
+** eSCO, and sets as the default mode used for outgoing calls to
+** BTM_CreateSco. It does not change any currently active (e)SCO links.
+** Note: Incoming (e)SCO connections will always use packet types
+** supported by the controller. If eSCO is not desired the
+** feature should be disabled in the controller's feature mask.
+**
+** Returns BTM_SUCCESS if the successful.
+** BTM_BUSY if there are one or more active (e)SCO links.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetEScoMode (tBTM_SCO_TYPE sco_mode, tBTM_ESCO_PARAMS *p_parms)
+{
+ tSCO_CB *p_esco = &btm_cb.sco_cb;
+ tBTM_ESCO_PARAMS *p_def = &p_esco->def_esco_parms;
+
+ if (p_esco->esco_supported)
+ {
+ if (p_parms)
+ {
+ if (sco_mode == BTM_LINK_TYPE_ESCO)
+ *p_def = *p_parms; /* Save as the default parameters */
+ else /* Load only the SCO packet types */
+ {
+ p_def->packet_types = p_parms->packet_types;
+ p_def->tx_bw = BTM_64KBITS_RATE;
+ p_def->rx_bw = BTM_64KBITS_RATE;
+ p_def->max_latency = 0x000a;
+ p_def->voice_contfmt = 0x0060;
+ p_def->retrans_effort = 0;
+
+ /* OR in any exception packet types if at least 2.0 version of spec */
+ if (btm_cb.devcb.local_version.hci_version >= HCI_PROTO_VERSION_2_0)
+ {
+ p_def->packet_types |= BTM_SCO_EXCEPTION_PKTS_MASK;
+ }
+ }
+ }
+ p_esco->desired_sco_mode = sco_mode;
+ BTM_TRACE_API1("BTM_SetEScoMode -> mode %d", sco_mode);
+ }
+ else
+ {
+ p_esco->desired_sco_mode = BTM_LINK_TYPE_SCO;
+ p_def->packet_types &= BTM_SCO_LINK_ONLY_MASK;
+ p_def->retrans_effort = 0;
+ BTM_TRACE_API0("BTM_SetEScoMode -> mode SCO (eSCO not supported)");
+ }
+
+ BTM_TRACE_DEBUG6(" txbw 0x%08x, rxbw 0x%08x, max_lat 0x%04x, voice 0x%04x, pkt 0x%04x, rtx effort 0x%02x",
+ p_def->tx_bw, p_def->rx_bw, p_def->max_latency,
+ p_def->voice_contfmt, p_def->packet_types,
+ p_def->retrans_effort);
+
+ return (BTM_SUCCESS);
+}
+
+
+
+/*******************************************************************************
+**
+** Function BTM_RegForEScoEvts
+**
+** Description This function registers a SCO event callback with the
+** specified instance. It should be used to received
+** connection indication events and change of link parameter
+** events.
+**
+** Returns BTM_SUCCESS if the successful.
+** BTM_ILLEGAL_VALUE if there is an illegal sco_inx
+** BTM_MODE_UNSUPPORTED if controller version is not BT1.2 or
+** later or does not support eSCO.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_RegForEScoEvts (UINT16 sco_inx, tBTM_ESCO_CBACK *p_esco_cback)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+ if (!btm_cb.sco_cb.esco_supported)
+ {
+ btm_cb.sco_cb.sco_db[sco_inx].esco.p_esco_cback = NULL;
+ return (BTM_MODE_UNSUPPORTED);
+ }
+
+ if (sco_inx < BTM_MAX_SCO_LINKS &&
+ btm_cb.sco_cb.sco_db[sco_inx].state != SCO_ST_UNUSED)
+ {
+ btm_cb.sco_cb.sco_db[sco_inx].esco.p_esco_cback = p_esco_cback;
+ return (BTM_SUCCESS);
+ }
+ return (BTM_ILLEGAL_VALUE);
+#else
+ return (BTM_MODE_UNSUPPORTED);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function BTM_ReadEScoLinkParms
+**
+** Description This function returns the current eSCO link parameters for
+** the specified handle. This can be called anytime a connection
+** is active, but is typically called after receiving the SCO
+** opened callback.
+**
+** Note: If called over a 1.1 controller, only the packet types
+** field has meaning.
+**
+** Returns BTM_SUCCESS if returned data is valid connection.
+** BTM_WRONG_MODE if no connection with a peer device or bad sco_inx.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_ReadEScoLinkParms (UINT16 sco_inx, tBTM_ESCO_DATA *p_parms)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+ BTM_TRACE_API1("BTM_ReadEScoLinkParms -> sco_inx 0x%04x", sco_inx);
+
+ if (sco_inx < BTM_MAX_SCO_LINKS &&
+ btm_cb.sco_cb.sco_db[sco_inx].state >= SCO_ST_CONNECTED)
+ {
+ *p_parms = btm_cb.sco_cb.sco_db[sco_inx].esco.data;
+ return (BTM_SUCCESS);
+ }
+#endif
+
+ memset(p_parms, 0, sizeof(tBTM_ESCO_DATA));
+ return (BTM_WRONG_MODE);
+}
+
+/*******************************************************************************
+**
+** Function BTM_ChangeEScoLinkParms
+**
+** Description This function requests renegotiation of the parameters on
+** the current eSCO Link. If any of the changes are accepted
+** by the controllers, the BTM_ESCO_CHG_EVT event is sent in
+** the tBTM_ESCO_CBACK function with the current settings of
+** the link. The callback is registered through the call to
+** BTM_SetEScoMode.
+**
+** Note: If called over a SCO link (including 1.1 controller),
+** a change packet type request is sent out instead.
+**
+** Returns BTM_CMD_STARTED if command is successfully initiated.
+** BTM_NO_RESOURCES - not enough resources to initiate command.
+** BTM_WRONG_MODE if no connection with a peer device or bad sco_inx.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_ChangeEScoLinkParms (UINT16 sco_inx, tBTM_CHG_ESCO_PARAMS *p_parms)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+ tBTM_ESCO_PARAMS *p_setup;
+ tSCO_CONN *p_sco;
+ UINT16 temp_pkt_types;
+
+ /* Make sure sco handle is valid and on an active link */
+ if (sco_inx >= BTM_MAX_SCO_LINKS ||
+ btm_cb.sco_cb.sco_db[sco_inx].state != SCO_ST_CONNECTED)
+ return (BTM_WRONG_MODE);
+
+ p_sco = &btm_cb.sco_cb.sco_db[sco_inx];
+ p_setup = &p_sco->esco.setup;
+
+ /* If SCO connection OR eSCO not supported just send change packet types */
+ if (p_sco->esco.data.link_type == BTM_LINK_TYPE_SCO ||
+ !btm_cb.sco_cb.esco_supported)
+ {
+ p_setup->packet_types = p_parms->packet_types &
+ (btm_cb.btm_sco_pkt_types_supported & BTM_SCO_LINK_ONLY_MASK);
+
+
+ BTM_TRACE_API2("BTM_ChangeEScoLinkParms -> SCO Link for handle 0x%04x, pkt 0x%04x",
+ p_sco->hci_handle, p_setup->packet_types);
+
+ if (!btsnd_hcic_change_conn_type (p_sco->hci_handle,
+ BTM_ESCO_2_SCO(p_setup->packet_types)))
+ return (BTM_NO_RESOURCES);
+ }
+ else
+ {
+ temp_pkt_types = (p_parms->packet_types & BTM_SCO_SUPPORTED_PKTS_MASK &
+ btm_cb.btm_sco_pkt_types_supported);
+
+ /* OR in any exception packet types if at least 2.0 version of spec */
+ if (btm_cb.devcb.local_version.hci_version >= HCI_PROTO_VERSION_2_0)
+ {
+ temp_pkt_types |= ((p_parms->packet_types & BTM_SCO_EXCEPTION_PKTS_MASK) |
+ (btm_cb.btm_sco_pkt_types_supported & BTM_SCO_EXCEPTION_PKTS_MASK));
+ }
+
+ BTM_TRACE_API1("BTM_ChangeEScoLinkParms -> eSCO Link for handle 0x%04x", p_sco->hci_handle);
+ BTM_TRACE_API6(" txbw 0x%x, rxbw 0x%x, lat 0x%x, voice 0x%x, retrans 0x%02x, pkt 0x%04x",
+ p_setup->tx_bw, p_setup->rx_bw, p_parms->max_latency,
+ p_setup->voice_contfmt, p_parms->retrans_effort, temp_pkt_types);
+
+ /* When changing an existing link, only change latency, retrans, and pkts */
+ if (!btsnd_hcic_setup_esco_conn(p_sco->hci_handle, p_setup->tx_bw,
+ p_setup->rx_bw, p_parms->max_latency,
+ p_setup->voice_contfmt,
+ p_parms->retrans_effort,
+ temp_pkt_types))
+ return (BTM_NO_RESOURCES);
+ else
+ p_parms->packet_types = temp_pkt_types;
+ }
+
+ return (BTM_CMD_STARTED);
+#else
+ return (BTM_WRONG_MODE);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function BTM_EScoConnRsp
+**
+** Description This function is called upon receipt of an (e)SCO connection
+** request event (BTM_ESCO_CONN_REQ_EVT) to accept or reject
+** the request. Parameters used to negotiate eSCO links.
+** If p_parms is NULL, then values set through BTM_SetEScoMode
+** are used.
+** If the link type of the incoming request is SCO, then only
+** the tx_bw, max_latency, content format, and packet_types are
+** valid. The hci_status parameter should be
+** ([0x0] to accept, [0x0d..0x0f] to reject)
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTM_EScoConnRsp (UINT16 sco_inx, UINT8 hci_status, tBTM_ESCO_PARAMS *p_parms)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+ if (sco_inx < BTM_MAX_SCO_LINKS &&
+ btm_cb.sco_cb.sco_db[sco_inx].state == SCO_ST_W4_CONN_RSP)
+ {
+ btm_esco_conn_rsp(sco_inx, hci_status,
+ btm_cb.sco_cb.sco_db[sco_inx].esco.data.bd_addr,
+ p_parms);
+ }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function btm_read_def_esco_mode
+**
+** Description This function copies the current default esco settings into
+** the return buffer.
+**
+** Returns tBTM_SCO_TYPE
+**
+*******************************************************************************/
+tBTM_SCO_TYPE btm_read_def_esco_mode (tBTM_ESCO_PARAMS *p_parms)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+ *p_parms = btm_cb.sco_cb.def_esco_parms;
+ return btm_cb.sco_cb.desired_sco_mode;
+#else
+ return BTM_LINK_TYPE_SCO;
+#endif
+}
+
+/*******************************************************************************
+**
+** Function btm_esco_proc_conn_chg
+**
+** Description This function is called by BTIF when an SCO connection
+** is changed.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_esco_proc_conn_chg (UINT8 status, UINT16 handle, UINT8 tx_interval,
+ UINT8 retrans_window, UINT16 rx_pkt_len,
+ UINT16 tx_pkt_len)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+ tSCO_CONN *p = &btm_cb.sco_cb.sco_db[0];
+ tBTM_CHG_ESCO_EVT_DATA data;
+ UINT16 xx;
+
+ BTM_TRACE_EVENT2("btm_esco_proc_conn_chg -> handle 0x%04x, status 0x%02x",
+ handle, status);
+
+ for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++)
+ {
+ if (p->state == SCO_ST_CONNECTED && handle == p->hci_handle)
+ {
+ /* If upper layer wants notification */
+ if (p->esco.p_esco_cback)
+ {
+ memcpy(data.bd_addr, p->esco.data.bd_addr, BD_ADDR_LEN);
+ data.hci_status = status;
+ data.sco_inx = xx;
+ data.rx_pkt_len = p->esco.data.rx_pkt_len = rx_pkt_len;
+ data.tx_pkt_len = p->esco.data.tx_pkt_len = tx_pkt_len;
+ data.tx_interval = p->esco.data.tx_interval = tx_interval;
+ data.retrans_window = p->esco.data.retrans_window = retrans_window;
+
+ (*p->esco.p_esco_cback)(BTM_ESCO_CHG_EVT,
+ (tBTM_ESCO_EVT_DATA *)&data);
+ }
+ return;
+ }
+ }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function btm_is_sco_active
+**
+** Description This function is called to see if a SCO handle is already in
+** use.
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+BOOLEAN btm_is_sco_active (UINT16 handle)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+ UINT16 xx;
+ tSCO_CONN *p = &btm_cb.sco_cb.sco_db[0];
+
+ for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++)
+ {
+ if (handle == p->hci_handle && p->state == SCO_ST_CONNECTED)
+ return (TRUE);
+ }
+#endif
+ return (FALSE);
+}
+
+/*******************************************************************************
+**
+** Function BTM_GetNumScoLinks
+**
+** Description This function returns the number of active sco links.
+**
+** Returns UINT8
+**
+*******************************************************************************/
+UINT8 BTM_GetNumScoLinks (void)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+ tSCO_CONN *p = &btm_cb.sco_cb.sco_db[0];
+ UINT16 xx;
+ UINT8 num_scos = 0;
+
+ for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++)
+ {
+ switch (p->state)
+ {
+ case SCO_ST_W4_CONN_RSP:
+ case SCO_ST_CONNECTING:
+ case SCO_ST_CONNECTED:
+ case SCO_ST_DISCONNECTING:
+ case SCO_ST_PEND_UNPARK:
+ num_scos++;
+ }
+ }
+ return (num_scos);
+#else
+ return (0);
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function btm_is_sco_active_by_bdaddr
+**
+** Description This function is called to see if a SCO active to a bd address.
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+BOOLEAN btm_is_sco_active_by_bdaddr (BD_ADDR remote_bda)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+ UINT8 xx;
+ tSCO_CONN *p = &btm_cb.sco_cb.sco_db[0];
+
+ /* If any SCO is being established to the remote BD address, refuse this */
+ for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++)
+ {
+ if ((!memcmp (p->esco.data.bd_addr, remote_bda, BD_ADDR_LEN)) && (p->state == SCO_ST_CONNECTED))
+ {
+ return (TRUE);
+ }
+ }
+#endif
+ return (FALSE);
+}
+#else /* SCO_EXCLUDED == TRUE (Link in stubs) */
+
+tBTM_STATUS BTM_CreateSco (BD_ADDR remote_bda, BOOLEAN is_orig,
+ UINT16 pkt_types, UINT16 *p_sco_inx,
+ tBTM_SCO_CB *p_conn_cb,
+ tBTM_SCO_CB *p_disc_cb) {return (BTM_NO_RESOURCES);}
+tBTM_STATUS BTM_RemoveSco (UINT16 sco_inx) {return (BTM_NO_RESOURCES);}
+tBTM_STATUS BTM_SetScoPacketTypes (UINT16 sco_inx, UINT16 pkt_types) {return (BTM_NO_RESOURCES);}
+UINT16 BTM_ReadScoPacketTypes (UINT16 sco_inx) {return (0);}
+UINT16 BTM_ReadDeviceScoPacketTypes (void) {return (0);}
+UINT16 BTM_ReadScoHandle (UINT16 sco_inx) {return (BTM_INVALID_HCI_HANDLE);}
+UINT8 *BTM_ReadScoBdAddr(UINT16 sco_inx) {return((UINT8 *) NULL);}
+UINT16 BTM_ReadScoDiscReason (void) {return (BTM_INVALID_SCO_DISC_REASON);}
+tBTM_STATUS BTM_SetEScoMode (tBTM_SCO_TYPE sco_mode, tBTM_ESCO_PARAMS *p_parms) {return (BTM_MODE_UNSUPPORTED);}
+tBTM_STATUS BTM_RegForEScoEvts (UINT16 sco_inx, tBTM_ESCO_CBACK *p_esco_cback) { return (BTM_ILLEGAL_VALUE);}
+tBTM_STATUS BTM_ReadEScoLinkParms (UINT16 sco_inx, tBTM_ESCO_DATA *p_parms) { return (BTM_MODE_UNSUPPORTED);}
+tBTM_STATUS BTM_ChangeEScoLinkParms (UINT16 sco_inx, tBTM_CHG_ESCO_PARAMS *p_parms) { return (BTM_MODE_UNSUPPORTED);}
+void BTM_EScoConnRsp (UINT16 sco_inx, UINT8 hci_status, tBTM_ESCO_PARAMS *p_parms) {}
+UINT8 BTM_GetNumScoLinks (void) {return (0);}
+
+#endif /* If SCO is being used */
diff --git a/stack/btm/btm_sec.c b/stack/btm/btm_sec.c
new file mode 100644
index 0000000..7ccf7a0
--- /dev/null
+++ b/stack/btm/btm_sec.c
@@ -0,0 +1,5612 @@
+/*****************************************************************************
+** *
+** Name: btm_sec.c *
+** *
+** Description: This file contains functions for the Bluetooth Security *
+** Manager *
+** *
+** Copyright (c) 1999-2011, Broadcom Corp., All Rights Reserved. *
+** Broadcom Bluetooth Core. Proprietary and confidential. *
+******************************************************************************/
+
+#include <string.h>
+#include "bt_types.h"
+#include "hcimsgs.h"
+#include "btu.h"
+#include "btm_int.h"
+#include "l2c_int.h"
+
+#if (BT_USE_TRACES == TRUE && BT_TRACE_VERBOSE == FALSE)
+/* needed for sprintf() */
+#include <stdio.h>
+#endif
+
+#if BLE_INCLUDED == TRUE
+ #include "gatt_int.h"
+#endif
+
+#define BTM_SEC_MAX_COLLISION_DELAY (GKI_SECS_TO_TICKS(5))
+
+#ifdef APPL_AUTH_WRITE_EXCEPTION
+BOOLEAN (APPL_AUTH_WRITE_EXCEPTION)(BD_ADDR bd_addr);
+#endif
+
+/********************************************************************************/
+/* L O C A L F U N C T I O N P R O T O T Y P E S */
+/********************************************************************************/
+static tBTM_SEC_SERV_REC *btm_sec_find_first_serv (BOOLEAN is_originator, UINT16 psm);
+static tBTM_SEC_SERV_REC *btm_sec_find_next_serv (tBTM_SEC_SERV_REC *p_cur);
+static tBTM_SEC_SERV_REC *btm_sec_find_mx_serv (UINT8 is_originator, UINT16 psm,
+ UINT32 mx_proto_id,
+ UINT32 mx_chan_id);
+
+static tBTM_STATUS btm_sec_execute_procedure (tBTM_SEC_DEV_REC *p_dev_rec);
+static BOOLEAN btm_sec_start_get_name (tBTM_SEC_DEV_REC *p_dev_rec);
+static BOOLEAN btm_sec_start_authentication (tBTM_SEC_DEV_REC *p_dev_rec);
+static BOOLEAN btm_sec_start_encryption (tBTM_SEC_DEV_REC *p_dev_rec);
+static void btm_sec_collision_timeout (TIMER_LIST_ENT *p_tle);
+static void btm_restore_mode(void);
+static void btm_sec_pairing_timeout (TIMER_LIST_ENT *p_tle);
+static tBTM_STATUS btm_sec_dd_create_conn (tBTM_SEC_DEV_REC *p_dev_rec);
+static void btm_sec_change_pairing_state (tBTM_PAIRING_STATE new_state);
+
+#if (BT_USE_TRACES == TRUE)
+static char *btm_pair_state_descr (tBTM_PAIRING_STATE state);
+#endif
+
+static void btm_sec_check_pending_reqs(void);
+static BOOLEAN btm_sec_queue_mx_request (BD_ADDR bd_addr, UINT16 psm, BOOLEAN is_orig,
+ UINT32 mx_proto_id, UINT32 mx_chan_id,
+ tBTM_SEC_CALLBACK *p_callback, void *p_ref_data);
+static void btm_sec_bond_cancel_complete (void);
+static void btm_send_link_key_notif (tBTM_SEC_DEV_REC *p_dev_rec);
+static BOOLEAN btm_sec_check_prefetch_pin (tBTM_SEC_DEV_REC *p_dev_rec);
+
+static UINT8 btm_sec_start_authorization (tBTM_SEC_DEV_REC *p_dev_rec);
+BOOLEAN btm_sec_are_all_trusted(UINT32 p_mask[]);
+
+static tBTM_STATUS btm_sec_send_hci_disconnect (tBTM_SEC_DEV_REC *p_dev_rec, UINT8 reason);
+tBTM_SEC_DEV_REC *btm_sec_find_dev_by_sec_state (UINT8 state);
+
+static BOOLEAN btm_sec_set_security_level ( CONNECTION_TYPE conn_type, char *p_name, UINT8 service_id,
+ UINT16 sec_level, UINT16 psm, UINT32 mx_proto_id,
+ UINT32 mx_chan_id);
+
+/* TRUE - authenticated link key is possible */
+static const BOOLEAN btm_sec_io_map [BTM_IO_CAP_MAX][BTM_IO_CAP_MAX] =
+{
+ /* OUT, IO, IN, NONE */
+/* OUT */ {FALSE, FALSE, TRUE, FALSE},
+/* IO */ {FALSE, TRUE, TRUE, FALSE},
+/* IN */ {TRUE, TRUE, TRUE, FALSE},
+/* NONE */ {FALSE, FALSE, FALSE, FALSE}
+};
+/* BTM_IO_CAP_OUT 0 DisplayOnly */
+/* BTM_IO_CAP_IO 1 DisplayYesNo */
+/* BTM_IO_CAP_IN 2 KeyboardOnly */
+/* BTM_IO_CAP_NONE 3 NoInputNoOutput */
+
+/*******************************************************************************
+**
+** Function BTM_SecRegister
+**
+** Description Application manager calls this function to register for
+** security services. There can be one and only one application
+** saving link keys. BTM allows only first registration.
+**
+** Returns TRUE if registered OK, else FALSE
+**
+*******************************************************************************/
+BOOLEAN BTM_SecRegister (tBTM_APPL_INFO *p_cb_info)
+{
+#if BLE_INCLUDED == TRUE
+ BT_OCTET16 temp_value = {0};
+#endif
+
+ BTM_TRACE_EVENT0 ("BTM_Sec: application registered");
+
+#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE
+ BTM_TRACE_ERROR1 ("BTM_SecRegister:p_cb_info->p_le_callback == 0x%x ", p_cb_info->p_le_callback);
+
+ if (p_cb_info->p_le_callback)
+ {
+#if SMP_INCLUDED == TRUE
+ BTM_TRACE_EVENT0 ("BTM_Sec: SMP_Register( btm_proc_smp_cback )");
+ SMP_Register(btm_proc_smp_cback);
+#endif
+ /* if no IR is loaded, need to regenerate all the keys */
+ if (memcmp(btm_cb.devcb.id_keys.ir, &temp_value, sizeof(BT_OCTET16)) == 0)
+ {
+ btm_ble_reset_id();
+ }
+ }
+ else
+ {
+ BTM_TRACE_ERROR0 ("BTM_SecRegister:p_cb_info->p_le_callback == NULL ");
+ }
+#endif
+
+
+
+ btm_cb.api = *p_cb_info;
+#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE
+ BTM_TRACE_ERROR1 ("BTM_SecRegister: btm_cb.api.p_le_callback = 0x%x ", btm_cb.api.p_le_callback);
+#endif
+ BTM_TRACE_EVENT0 ("BTM_Sec: application registered");
+ return(TRUE);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_SecRegisterLinkKeyNotificationCallback
+**
+** Description Application manager calls this function to register for
+** link key notification. When there is nobody registered
+** we should avoid changing link key
+**
+** Returns TRUE if registered OK, else FALSE
+**
+*******************************************************************************/
+BOOLEAN BTM_SecRegisterLinkKeyNotificationCallback (tBTM_LINK_KEY_CALLBACK *p_callback)
+{
+ btm_cb.api.p_link_key_callback = p_callback;
+ return(TRUE);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_SecAddRmtNameNotifyCallback
+**
+** Description Any profile can register to be notified when name of the
+** remote device is resolved.
+**
+** Returns TRUE if registered OK, else FALSE
+**
+*******************************************************************************/
+BOOLEAN BTM_SecAddRmtNameNotifyCallback (tBTM_RMT_NAME_CALLBACK *p_callback)
+{
+ int i;
+
+ for (i = 0; i < BTM_SEC_MAX_RMT_NAME_CALLBACKS; i++)
+ {
+ if (btm_cb.p_rmt_name_callback[i] == NULL)
+ {
+ btm_cb.p_rmt_name_callback[i] = p_callback;
+ return(TRUE);
+ }
+ }
+
+ return(FALSE);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_SecDeleteRmtNameNotifyCallback
+**
+** Description Any profile can deregister notification when a new Link Key
+** is generated per connection.
+**
+** Returns TRUE if OK, else FALSE
+**
+*******************************************************************************/
+BOOLEAN BTM_SecDeleteRmtNameNotifyCallback (tBTM_RMT_NAME_CALLBACK *p_callback)
+{
+ int i;
+
+ for (i = 0; i < BTM_SEC_MAX_RMT_NAME_CALLBACKS; i++)
+ {
+ if (btm_cb.p_rmt_name_callback[i] == p_callback)
+ {
+ btm_cb.p_rmt_name_callback[i] = NULL;
+ return(TRUE);
+ }
+ }
+
+ return(FALSE);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_SecSetConnectFilterCallback
+**
+** Description Host can register to be asked whenever a HCI connection
+** request is received. In the registered function host
+** suppose to check connectibility filters. Yes/No result
+** should be returned syncronously
+**
+** Returns void
+**
+*******************************************************************************/
+void BTM_SecSetConnectFilterCallback (tBTM_FILTER_CB *p_callback)
+{
+ btm_cb.p_conn_filter_cb = p_callback;
+}
+
+/*******************************************************************************
+**
+** Function BTM_GetSecurityMode
+**
+** Description Get security mode for the device
+**
+** Returns void
+**
+*******************************************************************************/
+UINT8 BTM_GetSecurityMode (void)
+{
+ return(btm_cb.security_mode);
+}
+
+/*******************************************************************************
+**
+** Function BTM_GetSecurityFlags
+**
+** Description Get security flags for the device
+**
+** Returns BOOLEAN TRUE or FALSE is device found
+**
+*******************************************************************************/
+BOOLEAN BTM_GetSecurityFlags (BD_ADDR bd_addr, UINT8 * p_sec_flags)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+
+ if ((p_dev_rec = btm_find_dev (bd_addr)) != NULL)
+ {
+ *p_sec_flags = p_dev_rec->sec_flags;
+ return(TRUE);
+ }
+ BTM_TRACE_ERROR0 ("BTM_GetSecurityFlags false");
+ return(FALSE);
+}
+
+/*******************************************************************************
+**
+** Function BTM_SetSecurityMode
+**
+** Description Set security mode for the device
+**
+** Returns void
+**
+*******************************************************************************/
+void BTM_SetSecurityMode (UINT8 security_mode)
+{
+ UINT8 old_mode = btm_cb.security_mode;
+
+ UINT8 sp_mode = HCI_SPD_MODE_ENABLED;
+ UINT8 sp_debug_mode = HCI_SPD_MODE_DISABLED;
+
+ switch (security_mode)
+ {
+#if (BTM_PRE_LISBON_INCLUDED == TRUE)
+ case BTM_SEC_MODE_NONE:
+ case BTM_SEC_MODE_SERVICE:
+ case BTM_SEC_MODE_LINK:
+ break;
+#endif
+
+ case BTM_SEC_MODE_SP_DEBUG:
+ sp_debug_mode = HCI_SPD_MODE_ENABLED;
+ break;
+ case BTM_SEC_MODE_SP:
+ /* the default is enabled */
+ break;
+ default:
+ BTM_TRACE_ERROR1 ("BTM_SetSecurityMode: unknown mode:%d", security_mode);
+ return;
+ }
+ btm_cb.security_mode = security_mode;
+
+ if (HCI_SIMPLE_PAIRING_SUPPORTED(btm_cb.devcb.local_features))
+ {
+ /* Lisbon devices and only use BTM_SEC_MODE_SP */
+ btm_cb.security_mode = BTM_SEC_MODE_SP;
+ BTM_TRACE_DEBUG2("BTM_SetSecurityMode: SP:%d, debug:%d", sp_mode, sp_debug_mode);
+ btsnd_hcic_write_simple_pairing_mode(sp_mode);
+ btsnd_hcic_write_simp_pair_debug_mode(sp_debug_mode);
+ return;
+ }
+
+ /* must be a pre-Lisbon device */
+#if (BTM_PRE_LISBON_INCLUDED == TRUE)
+ /* If previously security mode was Link Level and now lesser notify */
+ /* controller not to perform authentication, encryption on startup */
+ if ((old_mode == BTM_SEC_MODE_LINK)
+ && ( security_mode != BTM_SEC_MODE_LINK))
+ {
+ BTM_TRACE_DEBUG0("BTM_SetSecurityMode: Authen Enable -> FALSE");
+ btsnd_hcic_write_auth_enable (FALSE);
+ btsnd_hcic_write_encr_mode (HCI_ENCRYPT_MODE_DISABLED);
+ }
+
+ /* If previously security is increased to Link Level notify */
+ /* controller to perform authentication, encryption on startup */
+ if ((old_mode != BTM_SEC_MODE_LINK)
+ && ( security_mode == BTM_SEC_MODE_LINK))
+ {
+ BTM_TRACE_DEBUG0("BTM_SetSecurityMode: Authen Enable -> TRUE");
+ btsnd_hcic_write_auth_enable (TRUE);
+ btsnd_hcic_write_encr_mode (HCI_ENCRYPT_MODE_POINT_TO_POINT);
+ }
+#endif /* BTM_PRE_LISBON_INCLUDED == TRUE */
+}
+
+/*******************************************************************************
+**
+** Function BTM_SetPinType
+**
+** Description Set PIN type for the device.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTM_SetPinType (UINT8 pin_type, PIN_CODE pin_code, UINT8 pin_code_len)
+{
+ BTM_TRACE_API3 ("BTM_SetPinType: pin type %d [variable-0, fixed-1], code %s, length %d",
+ pin_type, (char *) pin_code, pin_code_len);
+
+ /* If device is not up security mode will be set as a part of startup */
+ if ( (btm_cb.cfg.pin_type != pin_type)
+ && (btm_cb.devcb.state > BTM_DEV_STATE_WAIT_AFTER_RESET) )
+ {
+ btsnd_hcic_write_pin_type (pin_type);
+ }
+
+ btm_cb.cfg.pin_type = pin_type;
+ btm_cb.cfg.pin_code_len = pin_code_len;
+ memcpy (btm_cb.cfg.pin_code, pin_code, pin_code_len);
+}
+
+/*******************************************************************************
+**
+** Function BTM_SetPairableMode
+**
+** Description Enable or disable pairing
+**
+** Parameters allow_pairing - (TRUE or FALSE) whether or not the device
+** allows pairing.
+** connect_only_paired - (TRUE or FALSE) whether or not to
+** only allow paired devices to connect.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTM_SetPairableMode (BOOLEAN allow_pairing, BOOLEAN connect_only_paired)
+{
+ BTM_TRACE_API2 ("BTM_SetPairableMode() allow_pairing: %u connect_only_paired: %u", allow_pairing, connect_only_paired);
+
+ btm_cb.pairing_disabled = !allow_pairing;
+ btm_cb.connect_only_paired = connect_only_paired;
+}
+
+
+#define BTM_NO_AVAIL_SEC_SERVICES ((UINT16) 0xffff)
+
+/*******************************************************************************
+**
+** Function BTM_SetUCDSecurityLevel
+**
+** Description Register UCD service security level with Security Manager
+**
+** Parameters: is_originator - TRUE if originating the connection, FALSE if not
+** p_name - Name of the service relevant only if
+** authorization will show this name to user. ignored
+** if BTM_SEC_SERVICE_NAME_LEN is 0.
+** service_id - service ID for the service passed to authorization callback
+** sec_level - bit mask of the security features
+** psm - L2CAP PSM
+** mx_proto_id - protocol ID of multiplexing proto below
+** mx_chan_id - channel ID of multiplexing proto below
+**
+** Returns TRUE if registered OK, else FALSE
+**
+*******************************************************************************/
+BOOLEAN BTM_SetUCDSecurityLevel (BOOLEAN is_originator, char *p_name, UINT8 service_id,
+ UINT16 sec_level, UINT16 psm, UINT32 mx_proto_id,
+ UINT32 mx_chan_id)
+{
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ CONNECTION_TYPE conn_type;
+
+ if (is_originator)
+ conn_type = CONNLESS_ORIG;
+ else
+ conn_type = CONNLESS_TERM;
+
+ return(btm_sec_set_security_level (conn_type, p_name, service_id,
+ sec_level, psm, mx_proto_id, mx_chan_id));
+#else
+ return FALSE;
+#endif
+}
+
+/*******************************************************************************
+**
+** Function BTM_SetSecurityLevel
+**
+** Description Register service security level with Security Manager
+**
+** Parameters: is_originator - TRUE if originating the connection, FALSE if not
+** p_name - Name of the service relevant only if
+** authorization will show this name to user. ignored
+** if BTM_SEC_SERVICE_NAME_LEN is 0.
+** service_id - service ID for the service passed to authorization callback
+** sec_level - bit mask of the security features
+** psm - L2CAP PSM
+** mx_proto_id - protocol ID of multiplexing proto below
+** mx_chan_id - channel ID of multiplexing proto below
+**
+** Returns TRUE if registered OK, else FALSE
+**
+*******************************************************************************/
+BOOLEAN BTM_SetSecurityLevel (BOOLEAN is_originator, char *p_name, UINT8 service_id,
+ UINT16 sec_level, UINT16 psm, UINT32 mx_proto_id,
+ UINT32 mx_chan_id)
+{
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ CONNECTION_TYPE conn_type;
+
+ if (is_originator)
+ conn_type = CONN_ORIENT_ORIG;
+ else
+ conn_type = CONN_ORIENT_TERM;
+
+ return(btm_sec_set_security_level (conn_type, p_name, service_id,
+ sec_level, psm, mx_proto_id, mx_chan_id));
+#else
+ return(btm_sec_set_security_level (is_originator, p_name, service_id,
+ sec_level, psm, mx_proto_id, mx_chan_id));
+#endif
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_set_security_level
+**
+** Description Register service security level with Security Manager
+**
+** Parameters: conn_type - TRUE if originating the connection, FALSE if not
+** p_name - Name of the service relevant only if
+** authorization will show this name to user. ignored
+** if BTM_SEC_SERVICE_NAME_LEN is 0.
+** service_id - service ID for the service passed to authorization callback
+** sec_level - bit mask of the security features
+** psm - L2CAP PSM
+** mx_proto_id - protocol ID of multiplexing proto below
+** mx_chan_id - channel ID of multiplexing proto below
+**
+** Returns TRUE if registered OK, else FALSE
+**
+*******************************************************************************/
+static BOOLEAN btm_sec_set_security_level (CONNECTION_TYPE conn_type, char *p_name, UINT8 service_id,
+ UINT16 sec_level, UINT16 psm, UINT32 mx_proto_id,
+ UINT32 mx_chan_id)
+{
+ tBTM_SEC_SERV_REC *p_srec;
+ UINT16 index;
+ UINT16 first_unused_record = BTM_NO_AVAIL_SEC_SERVICES;
+ BOOLEAN record_allocated = FALSE;
+ BOOLEAN is_originator;
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ BOOLEAN is_ucd;
+
+ if (conn_type & CONNECTION_TYPE_ORIG_MASK)
+ is_originator = TRUE;
+ else
+ is_originator = FALSE;
+
+ if (conn_type & CONNECTION_TYPE_CONNLESS_MASK )
+ {
+ is_ucd = TRUE;
+ }
+ else
+ {
+ is_ucd = FALSE;
+ }
+#else
+ is_originator = conn_type;
+#endif
+
+ /* See if the record can be reused (same service name, psm, mx_proto_id,
+ service_id, and mx_chan_id), or obtain the next unused record */
+
+ p_srec = &btm_cb.sec_serv_rec[0];
+
+
+ for (index = 0; index < BTM_SEC_MAX_SERVICE_RECORDS; index++, p_srec++)
+ {
+ /* Check if there is already a record for this service */
+ if (p_srec->security_flags & BTM_SEC_IN_USE)
+ {
+#if BTM_SEC_SERVICE_NAME_LEN > 0
+ if (p_srec->psm == psm &&
+ p_srec->mx_proto_id == mx_proto_id &&
+ service_id == p_srec->service_id &&
+ (!strncmp (p_name, (char *) p_srec->orig_service_name,
+ BTM_SEC_SERVICE_NAME_LEN) ||
+ !strncmp (p_name, (char *) p_srec->term_service_name,
+ BTM_SEC_SERVICE_NAME_LEN)))
+#else
+ if (p_srec->psm == psm &&
+ p_srec->mx_proto_id == mx_proto_id &&
+ service_id == p_srec->service_id)
+#endif
+ {
+ record_allocated = TRUE;
+ break;
+ }
+ }
+ /* Mark the first available service record */
+ else if (!record_allocated)
+ {
+ memset (p_srec, 0, sizeof(tBTM_SEC_SERV_REC));
+ record_allocated = TRUE;
+ first_unused_record = index;
+ }
+ }
+
+ if (!record_allocated)
+ {
+ BTM_TRACE_WARNING1("BTM_SEC_REG: Out of Service Records (%d)", BTM_SEC_MAX_SERVICE_RECORDS);
+ return(record_allocated);
+ }
+
+ /* Process the request if service record is valid */
+ /* If a duplicate service wasn't found, use the first available */
+ if (index >= BTM_SEC_MAX_SERVICE_RECORDS)
+ {
+ index = first_unused_record;
+ p_srec = &btm_cb.sec_serv_rec[index];
+ }
+
+ p_srec->psm = psm;
+ p_srec->service_id = service_id;
+ p_srec->mx_proto_id = mx_proto_id;
+
+ if (is_originator)
+ {
+ p_srec->orig_mx_chan_id = mx_chan_id;
+#if BTM_SEC_SERVICE_NAME_LEN > 0
+ BCM_STRNCPY_S ((char *)p_srec->orig_service_name, sizeof(p_srec->orig_service_name), p_name, BTM_SEC_SERVICE_NAME_LEN);
+#endif
+ /* clear out the old setting, just in case it exists */
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ if ( is_ucd )
+ {
+ p_srec->ucd_security_flags &=
+ ~(BTM_SEC_OUT_AUTHORIZE | BTM_SEC_OUT_ENCRYPT | BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_MITM |
+ BTM_SEC_FORCE_MASTER | BTM_SEC_ATTEMPT_MASTER | BTM_SEC_FORCE_SLAVE | BTM_SEC_ATTEMPT_SLAVE);
+ }
+ else
+#endif
+ {
+ p_srec->security_flags &=
+ ~(BTM_SEC_OUT_AUTHORIZE | BTM_SEC_OUT_ENCRYPT | BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_MITM |
+ BTM_SEC_FORCE_MASTER | BTM_SEC_ATTEMPT_MASTER | BTM_SEC_FORCE_SLAVE | BTM_SEC_ATTEMPT_SLAVE);
+ }
+
+ /* Parameter validation. Originator should not set requirements for incoming connections */
+ sec_level &= ~(BTM_SEC_IN_AUTHORIZE | BTM_SEC_IN_ENCRYPT | BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_MITM);
+
+ if (btm_cb.security_mode == BTM_SEC_MODE_SP)
+ {
+ if (sec_level & BTM_SEC_OUT_AUTHENTICATE)
+ sec_level |= BTM_SEC_OUT_MITM;
+ }
+
+ /* Make sure the authenticate bit is set, when encrypt bit is set */
+ if (sec_level & BTM_SEC_OUT_ENCRYPT)
+ sec_level |= BTM_SEC_OUT_AUTHENTICATE;
+
+ /* outgoing connections usually set the security level right before
+ * the connection is initiated.
+ * set it to be the outgoing service */
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ if ( is_ucd == FALSE )
+#endif
+ {
+ btm_cb.p_out_serv = p_srec;
+ }
+ }
+ else
+ {
+ p_srec->term_mx_chan_id = mx_chan_id;
+#if BTM_SEC_SERVICE_NAME_LEN > 0
+ BCM_STRNCPY_S ((char *)p_srec->term_service_name, sizeof(p_srec->term_service_name), p_name, BTM_SEC_SERVICE_NAME_LEN);
+#endif
+ /* clear out the old setting, just in case it exists */
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ if ( is_ucd )
+ {
+ p_srec->ucd_security_flags &=
+ ~(BTM_SEC_IN_AUTHORIZE | BTM_SEC_IN_ENCRYPT | BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_MITM |
+ BTM_SEC_FORCE_MASTER | BTM_SEC_ATTEMPT_MASTER | BTM_SEC_FORCE_SLAVE | BTM_SEC_ATTEMPT_SLAVE);
+ }
+ else
+#endif
+ {
+ p_srec->security_flags &=
+ ~(BTM_SEC_IN_AUTHORIZE | BTM_SEC_IN_ENCRYPT | BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_MITM |
+ BTM_SEC_FORCE_MASTER | BTM_SEC_ATTEMPT_MASTER | BTM_SEC_FORCE_SLAVE | BTM_SEC_ATTEMPT_SLAVE);
+ }
+
+ /* Parameter validation. Acceptor should not set requirements for outgoing connections */
+ sec_level &= ~(BTM_SEC_OUT_AUTHORIZE | BTM_SEC_OUT_ENCRYPT | BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_MITM);
+
+ if (btm_cb.security_mode == BTM_SEC_MODE_SP)
+ {
+ if (sec_level & BTM_SEC_IN_AUTHENTICATE)
+ sec_level |= BTM_SEC_IN_MITM;
+ }
+
+ /* Make sure the authenticate bit is set, when encrypt bit is set */
+ if (sec_level & BTM_SEC_IN_ENCRYPT)
+ sec_level |= BTM_SEC_IN_AUTHENTICATE;
+ }
+
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ if ( is_ucd )
+ {
+ p_srec->security_flags |= (UINT16)(BTM_SEC_IN_USE);
+ p_srec->ucd_security_flags |= (UINT16)(sec_level | BTM_SEC_IN_USE);
+ }
+ else
+ {
+ p_srec->security_flags |= (UINT16)(sec_level | BTM_SEC_IN_USE);
+ }
+
+ BTM_TRACE_API6("BTM_SEC_REG[%d]: id %d, conn_type 0x%x, psm 0x%04x, proto_id %d, chan_id %d",
+ index, service_id, conn_type, psm, mx_proto_id, mx_chan_id);
+
+ BTM_TRACE_API2(" : security_flags: 0x%04x, ucd_security_flags: 0x%04x",
+ p_srec->security_flags, p_srec->ucd_security_flags);
+
+#if BTM_SEC_SERVICE_NAME_LEN > 0
+ BTM_TRACE_API2(" : service name [%s] (up to %d chars saved)",
+ p_name, BTM_SEC_SERVICE_NAME_LEN);
+#endif
+#else
+ p_srec->security_flags |= (UINT16)(sec_level | BTM_SEC_IN_USE);
+
+ BTM_TRACE_API6("BTM_SEC_REG[%d]: id %d, is_orig %d, psm 0x%04x, proto_id %d, chan_id %d",
+ index, service_id, is_originator, psm, mx_proto_id, mx_chan_id);
+
+#if BTM_SEC_SERVICE_NAME_LEN > 0
+ BTM_TRACE_API3(" : sec: 0x%x, service name [%s] (up to %d chars saved)",
+ p_srec->security_flags, p_name, BTM_SEC_SERVICE_NAME_LEN);
+#endif
+#endif
+
+
+ return(record_allocated);
+}
+
+/*******************************************************************************
+**
+** Function BTM_SecClrService
+**
+** Description Removes specified service record(s) from the security database.
+** All service records with the specified name are removed.
+** Typically used only by devices with limited RAM so that it can
+** reuse an old security service record.
+**
+** Note: Unpredictable results may occur if a service is cleared
+** that is still in use by an application/profile.
+**
+** Parameters Service ID - Id of the service to remove. ('0' removes all service
+** records (except SDP).
+**
+** Returns Number of records that were freed.
+**
+*******************************************************************************/
+UINT8 BTM_SecClrService (UINT8 service_id)
+{
+ tBTM_SEC_SERV_REC *p_srec = &btm_cb.sec_serv_rec[0];
+ UINT8 num_freed = 0;
+ int i;
+
+ for (i = 0; i < BTM_SEC_MAX_SERVICE_RECORDS; i++, p_srec++)
+ {
+ /* Delete services with specified name (if in use and not SDP) */
+ if ((p_srec->security_flags & BTM_SEC_IN_USE) && (p_srec->psm != BT_PSM_SDP) &&
+ (!service_id || (service_id == p_srec->service_id)))
+ {
+ BTM_TRACE_API2("BTM_SEC_CLR[%d]: id %d", i, service_id);
+ p_srec->security_flags = 0;
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ p_srec->ucd_security_flags = 0;
+#endif
+ num_freed++;
+ }
+ }
+
+ return(num_freed);
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_clr_service_by_psm
+**
+** Description Removes specified service record from the security database.
+** All service records with the specified psm are removed.
+** Typically used by L2CAP to free up the service record used
+** by dynamic PSM clients when the channel is closed.
+** The given psm must be a virtual psm.
+**
+** Parameters Service ID - Id of the service to remove. ('0' removes all service
+** records (except SDP).
+**
+** Returns Number of records that were freed.
+**
+*******************************************************************************/
+UINT8 btm_sec_clr_service_by_psm (UINT16 psm)
+{
+ tBTM_SEC_SERV_REC *p_srec = &btm_cb.sec_serv_rec[0];
+ UINT8 num_freed = 0;
+ int i;
+
+ for (i = 0; i < BTM_SEC_MAX_SERVICE_RECORDS; i++, p_srec++)
+ {
+ /* Delete services with specified name (if in use and not SDP) */
+ if ((p_srec->security_flags & BTM_SEC_IN_USE) && (p_srec->psm == psm) )
+ {
+ BTM_TRACE_API2("BTM_SEC_CLR[%d]: id %d ", i, p_srec->service_id);
+ p_srec->security_flags = 0;
+ num_freed++;
+ }
+ }
+ BTM_TRACE_API2("btm_sec_clr_service_by_psm psm:0x%x num_freed:%d", psm, num_freed);
+
+ return(num_freed);
+}
+
+/*******************************************************************************
+**
+** Function BTM_SecClrUCDService
+**
+** Description
+**
+** Parameters Service ID - Id of the service to remove.
+** ('0' removes all service records )
+**
+** Returns Number of records that were cleared.
+**
+*******************************************************************************/
+UINT8 BTM_SecClrUCDService (UINT8 service_id)
+{
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ tBTM_SEC_SERV_REC *p_srec = &btm_cb.sec_serv_rec[0];
+ UINT8 num_cleared = 0;
+ int i;
+
+ for (i = 0; i < BTM_SEC_MAX_SERVICE_RECORDS; i++, p_srec++)
+ {
+ /* Delete services with specified name (if in use and not SDP) */
+ if ((p_srec->security_flags & BTM_SEC_IN_USE) &&
+ (!service_id || (service_id == (UINT32)p_srec->service_id)))
+ {
+ BTM_TRACE_API2("BTM_UCD_SEC_CLR[%d]: id %d", i, service_id);
+ p_srec->ucd_security_flags = 0;
+ num_cleared++;
+ }
+ }
+
+ return(num_cleared);
+#else
+ return(0);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function BTM_PINCodeReply
+**
+** Description This function is called after Security Manager submitted
+** PIN code request to the UI.
+**
+** Parameters: bd_addr - Address of the device for which PIN was requested
+** res - result of the operation BTM_SUCCESS if success
+** pin_len - length in bytes of the PIN Code
+** p_pin - pointer to array with the PIN Code
+** trusted_mask - bitwise OR of trusted services (array of UINT32)
+**
+*******************************************************************************/
+void BTM_PINCodeReply (BD_ADDR bd_addr, UINT8 res, UINT8 pin_len, UINT8 *p_pin, UINT32 trusted_mask[])
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+
+ BTM_TRACE_API4 ("BTM_PINCodeReply(): PairState: %s PairFlags: 0x%02x PinLen:%d Result:%d",
+ btm_pair_state_descr(btm_cb.pairing_state), btm_cb.pairing_flags, pin_len, res);
+
+ /* If timeout already expired or has been canceled, ignore the reply */
+ if (btm_cb.pairing_state != BTM_PAIR_STATE_WAIT_LOCAL_PIN)
+ {
+ BTM_TRACE_WARNING1 ("BTM_PINCodeReply() - Wrong State: %d", btm_cb.pairing_state);
+ return;
+ }
+
+ if (memcmp (bd_addr, btm_cb.pairing_bda, BD_ADDR_LEN) != 0)
+ {
+ BTM_TRACE_ERROR0 ("BTM_PINCodeReply() - Wrong BD Addr");
+ return;
+ }
+
+ if ((p_dev_rec = btm_find_dev (bd_addr)) == NULL)
+ {
+ BTM_TRACE_ERROR0 ("BTM_PINCodeReply() - no dev CB");
+ return;
+ }
+
+ if ( (pin_len > PIN_CODE_LEN) || (pin_len == 0) || (p_pin == NULL) )
+ res = BTM_ILLEGAL_VALUE;
+
+ if (res != BTM_SUCCESS)
+ {
+ if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_PEER_STARTED_DD)
+ {
+ /* use BTM_PAIR_STATE_WAIT_AUTH_COMPLETE to report authentication failed event */
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_AUTH_COMPLETE);
+ btm_cb.acl_disc_reason = HCI_ERR_HOST_REJECT_SECURITY;
+
+ btsnd_hcic_pin_code_neg_reply (bd_addr);
+ }
+ else
+ {
+ p_dev_rec->security_required = BTM_SEC_NONE;
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+ }
+ return;
+ }
+ if (trusted_mask)
+ BTM_SEC_COPY_TRUSTED_DEVICE(trusted_mask, p_dev_rec->trusted_mask);
+ p_dev_rec->sec_flags |= BTM_SEC_LINK_KEY_AUTHED;
+
+ if ( (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD)
+ && (p_dev_rec->hci_handle == BTM_SEC_INVALID_HANDLE)
+ && (btm_cb.security_mode_changed == FALSE) )
+ {
+ /* This is start of the dedicated bonding if local device is 2.0 */
+ btm_cb.pin_code_len = pin_len;
+ memcpy (btm_cb.pin_code, p_pin, pin_len);
+
+ btm_cb.security_mode_changed = TRUE;
+#ifdef APPL_AUTH_WRITE_EXCEPTION
+ if(!(APPL_AUTH_WRITE_EXCEPTION)(p_dev_rec->bd_addr))
+#endif
+ btsnd_hcic_write_auth_enable (TRUE);
+
+ btm_cb.acl_disc_reason = 0xff ;
+
+ /* if we rejected incoming connection request, we have to wait HCI_Connection_Complete event */
+ /* before originating */
+ if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_REJECTED_CONNECT)
+ {
+ BTM_TRACE_WARNING0 ("BTM_PINCodeReply(): waiting HCI_Connection_Complete after rejected incoming connection");
+ /* we change state little bit early so btm_sec_connected() will originate connection */
+ /* when existing ACL link is down completely */
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_PIN_REQ);
+ }
+ /* if we already accepted incoming connection from pairing device */
+ else if (p_dev_rec->sm4 & BTM_SM4_CONN_PEND)
+ {
+ BTM_TRACE_WARNING0 ("BTM_PINCodeReply(): link is connecting so wait pin code request from peer");
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_PIN_REQ);
+ }
+ else if (btm_sec_dd_create_conn(p_dev_rec) != BTM_CMD_STARTED)
+ {
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+ p_dev_rec->sec_flags &= ~BTM_SEC_LINK_KEY_AUTHED;
+
+ (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr, p_dev_rec->dev_class,
+ p_dev_rec->sec_bd_name, HCI_ERR_AUTH_FAILURE);
+ }
+ return;
+ }
+
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_AUTH_COMPLETE);
+ btm_cb.acl_disc_reason = HCI_SUCCESS;
+
+#ifdef PORCHE_PAIRING_CONFLICT
+ BTM_TRACE_EVENT2("BTM_PINCodeReply(): Saving pin_len: %d btm_cb.pin_code_len: %d", pin_len, btm_cb.pin_code_len);
+ /* if this was not pre-fetched, save the PIN */
+ if (btm_cb.pin_code_len == 0)
+ memcpy (btm_cb.pin_code, p_pin, pin_len);
+ btm_cb.pin_code_len_saved = pin_len;
+#endif
+ btsnd_hcic_pin_code_req_reply (bd_addr, pin_len, p_pin);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_DeviceAuthorized
+**
+** Description This function is called after Security Manager submitted
+** authorization request to the UI.
+**
+** Parameters: bd_addr - Address of the device for which PIN was requested
+** res - result of the operation BTM_SUCCESS if success
+**
+*******************************************************************************/
+void BTM_DeviceAuthorized (BD_ADDR bd_addr, UINT8 res, UINT32 trusted_mask[])
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+
+ if ((p_dev_rec = btm_find_dev (bd_addr)) == NULL)
+ {
+ BTM_TRACE_WARNING6 ("Security Manager: Attempting Authorization of Unknown Device Address [%02x%02x%02x%02x%02x%02x]",
+ bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
+ return;
+ }
+
+ BTM_TRACE_EVENT4 ("Security Manager: authorized status:%d State:%d Trusted:%08x %08x",
+ res, (p_dev_rec) ? p_dev_rec->sec_state : 0, trusted_mask[0], trusted_mask[1]);
+
+ if (res == BTM_SUCCESS)
+ {
+ p_dev_rec->sec_flags |= BTM_SEC_AUTHORIZED;
+ if (trusted_mask)
+ BTM_SEC_COPY_TRUSTED_DEVICE(trusted_mask, p_dev_rec->trusted_mask);
+ }
+
+ if (p_dev_rec->sec_state != BTM_SEC_STATE_AUTHORIZING)
+ return;
+
+ p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+
+ if (res != BTM_SUCCESS)
+ {
+ btm_sec_dev_rec_cback_event (p_dev_rec, res);
+ return;
+ }
+
+ if ((res = (UINT8)btm_sec_execute_procedure (p_dev_rec)) != BTM_CMD_STARTED)
+ {
+ btm_sec_dev_rec_cback_event (p_dev_rec, res);
+ }
+}
+
+
+
+/*******************************************************************************
+**
+** Function BTM_SecBond
+**
+** Description This function is called to perform bonding with peer device.
+** If the connection is already up, but not secure, pairing
+** is attempted. If already paired BTM_SUCCESS is returned.
+**
+** Parameters: bd_addr - Address of the device to bond
+** pin_len - length in bytes of the PIN Code
+** p_pin - pointer to array with the PIN Code
+** trusted_mask - bitwise OR of trusted services (array of UINT32)
+**
+** Note: After 2.1 parameters are not used and preserved here not to change API
+*******************************************************************************/
+tBTM_STATUS BTM_SecBond (BD_ADDR bd_addr, UINT8 pin_len, UINT8 *p_pin, UINT32 trusted_mask[])
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ tBTM_STATUS status;
+#if SMP_INCLUDED == TRUE
+ tACL_CONN *p=NULL;
+ BOOLEAN is_le_slave_role=FALSE;
+#endif
+ BTM_TRACE_API6 ("BTM_SecBond BDA: %02x:%02x:%02x:%02x:%02x:%02x",
+ bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
+
+ /* Other security process is in progress */
+ if (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)
+ {
+ BTM_TRACE_ERROR1 ("BTM_SecBond: already busy in state: %s", btm_pair_state_descr(btm_cb.pairing_state));
+ return(BTM_WRONG_MODE);
+ }
+
+
+ p_dev_rec = btm_find_or_alloc_dev (bd_addr);
+ BTM_TRACE_DEBUG1 ("before update sec_flags=0x%x", p_dev_rec->sec_flags);
+
+
+#if SMP_INCLUDED == TRUE
+ p = btm_bda_to_acl(bd_addr);
+ if (p && p->is_le_link )
+ {
+ if (p_dev_rec->sec_state == BTM_SEC_STATE_AUTHENTICATING)
+ {
+ BTM_TRACE_ERROR1 ("BTM_SecBond: LE already busy in state: %x", p_dev_rec->sec_state );
+ return(BTM_WRONG_MODE);
+ }
+
+ if (p->link_role == BTM_ROLE_SLAVE)
+ {
+ is_le_slave_role = TRUE;
+ BTM_TRACE_DEBUG0 ("LE Link Slave" );
+ }
+ else
+ {
+ BTM_TRACE_DEBUG0 ("LE Link Maste" );
+ }
+ }
+ else
+ {
+ BTM_TRACE_DEBUG0 ("No LE Link" );
+ }
+
+ if (!is_le_slave_role)
+ {
+ /* Finished if connection is active and already paired */
+ if ( (p_dev_rec->hci_handle != BTM_SEC_INVALID_HANDLE)
+ && (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED) )
+ {
+ BTM_TRACE_WARNING0("BTM_SecBond -> Already Paired");
+ return(BTM_SUCCESS);
+ }
+ }
+#else
+ /* Finished if connection is active and already paired */
+ if ( (p_dev_rec->hci_handle != BTM_SEC_INVALID_HANDLE)
+ && (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED) )
+ {
+ BTM_TRACE_WARNING0("BTM_SecBond -> Already Paired");
+ return(BTM_SUCCESS);
+ }
+#endif
+
+ /* Tell controller to get rid of the link key if it has one stored */
+ if ((BTM_DeleteStoredLinkKey (bd_addr, NULL)) != BTM_SUCCESS)
+ return(BTM_NO_RESOURCES);
+
+ /* Save the PIN code if we got a valid one */
+ if (p_pin && (pin_len <= PIN_CODE_LEN) && (pin_len != 0))
+ {
+ btm_cb.pin_code_len = pin_len;
+ memcpy (btm_cb.pin_code, p_pin, PIN_CODE_LEN);
+ }
+
+ memcpy (btm_cb.pairing_bda, bd_addr, BD_ADDR_LEN);
+
+ btm_cb.pairing_flags = BTM_PAIR_FLAGS_WE_STARTED_DD;
+
+ p_dev_rec->security_required = BTM_SEC_OUT_AUTHENTICATE;
+ p_dev_rec->is_originator = TRUE;
+ if (trusted_mask)
+ BTM_SEC_COPY_TRUSTED_DEVICE(trusted_mask, p_dev_rec->trusted_mask);
+
+
+
+#if SMP_INCLUDED == TRUE
+
+ if (!is_le_slave_role)
+ {
+ p_dev_rec->sec_flags &= ~(BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED
+ | BTM_SEC_ROLE_SWITCHED | BTM_SEC_LINK_KEY_AUTHED);
+
+ }
+
+ /* LE device, do SMP pairing */
+ if (p_dev_rec->device_type == BT_DEVICE_TYPE_BLE)
+ {
+ if (SMP_Pair(p_dev_rec->bd_addr) == SMP_STARTED)
+ {
+ p_dev_rec->sec_state = BTM_SEC_STATE_AUTHENTICATING;
+ return BTM_CMD_STARTED;
+ }
+ else
+ return(BTM_NO_RESOURCES);
+ }
+#else
+ p_dev_rec->sec_flags &= ~(BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED
+ | BTM_SEC_ROLE_SWITCHED | BTM_SEC_LINK_KEY_AUTHED);
+#endif
+
+ BTM_TRACE_DEBUG1 ("after update sec_flags=0x%x", p_dev_rec->sec_flags);
+ if (!HCI_SIMPLE_PAIRING_SUPPORTED(btm_cb.devcb.local_features))
+ {
+ /* The special case when we authenticate keyboard. Set pin type to fixed */
+ /* It would be probably better to do it from the application, but it is */
+ /* complicated */
+ if (((p_dev_rec->dev_class[1] & BTM_COD_MAJOR_CLASS_MASK) == BTM_COD_MAJOR_PERIPHERAL)
+ && (p_dev_rec->dev_class[2] & BTM_COD_MINOR_KEYBOARD)
+ && (btm_cb.cfg.pin_type != HCI_PIN_TYPE_FIXED))
+ {
+ btm_cb.pin_type_changed = TRUE;
+ btsnd_hcic_write_pin_type (HCI_PIN_TYPE_FIXED);
+ }
+ }
+
+ BTM_TRACE_EVENT1("BTM_SecBond: Local device supports SSP=%d", HCI_SIMPLE_PAIRING_SUPPORTED(btm_cb.devcb.local_features));
+
+ BTM_TRACE_EVENT4(" remote_features=%02x-%02x-%02x-%02x",
+ p_dev_rec->features[0], p_dev_rec->features[1], p_dev_rec->features[2], p_dev_rec->features[3]);
+ BTM_TRACE_EVENT4(" %02x-%02x-%02x-%02x",
+ p_dev_rec->features[4], p_dev_rec->features[5], p_dev_rec->features[6], p_dev_rec->features[7]);
+
+ BTM_TRACE_EVENT2 ("BTM_SecBond: Remote sm4: 0x%x HCI Handle: 0x%04x", p_dev_rec->sm4, p_dev_rec->hci_handle);
+
+#if BTM_SEC_FORCE_RNR_FOR_DBOND == TRUE
+ p_dev_rec->sec_flags &= ~BTM_SEC_NAME_KNOWN;
+#endif
+
+ /* If connection already exists... */
+ if (p_dev_rec->hci_handle != BTM_SEC_INVALID_HANDLE)
+ {
+ if (!btm_sec_start_authentication (p_dev_rec))
+ return(BTM_NO_RESOURCES);
+
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_PIN_REQ);
+
+ /* Mark lcb as bonding */
+ l2cu_update_lcb_4_bonding (bd_addr, TRUE);
+ return(BTM_CMD_STARTED);
+ }
+
+ BTM_TRACE_DEBUG2 ("sec mode: %d sm4:x%x", btm_cb.security_mode, p_dev_rec->sm4);
+ if (!HCI_SIMPLE_PAIRING_SUPPORTED(btm_cb.devcb.local_features)
+ || (p_dev_rec->sm4 == BTM_SM4_KNOWN))
+ {
+ if ( btm_sec_check_prefetch_pin (p_dev_rec) )
+ return(BTM_CMD_STARTED);
+ }
+ if (BTM_SEC_MODE_SP == btm_cb.security_mode && BTM_SEC_IS_SM4_UNKNOWN(p_dev_rec->sm4))
+ {
+ /* local is 2.1 and peer is unknown */
+ if ((p_dev_rec->sm4 & BTM_SM4_CONN_PEND) == 0)
+ {
+ /* we are not accepting connection request from peer
+ * -> RNR (to learn if peer is 2.1)
+ * RNR when no ACL causes HCI_RMT_HOST_SUP_FEAT_NOTIFY_EVT */
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_GET_REM_NAME);
+ BTM_ReadRemoteDeviceName(bd_addr, NULL);
+ }
+ else
+ {
+ /* We are accepting connection request from peer */
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_PIN_REQ);
+ }
+ BTM_TRACE_DEBUG3 ("State:%s sm4: 0x%x sec_state:%d", btm_pair_state_descr (btm_cb.pairing_state), p_dev_rec->sm4, p_dev_rec->sec_state);
+ return BTM_CMD_STARTED;
+ }
+
+ /* both local and peer are 2.1 */
+ status = btm_sec_dd_create_conn(p_dev_rec);
+
+ if (status != BTM_CMD_STARTED)
+ {
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+ }
+
+ return status;
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_SecBondCancel
+**
+** Description This function is called to cancel ongoing bonding process
+** with peer device.
+**
+** Parameters: bd_addr - Address of the peer device
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SecBondCancel (BD_ADDR bd_addr)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+#if SMP_INCLUDED == TRUE
+ tACL_CONN *p=NULL;
+#endif
+
+ BTM_TRACE_API2 ("BTM_SecBondCancel() State: %s flags:0x%x",
+ btm_pair_state_descr (btm_cb.pairing_state), btm_cb.pairing_flags);
+
+ if (((p_dev_rec = btm_find_dev (bd_addr)) == NULL)
+ || (memcmp (btm_cb.pairing_bda, bd_addr, BD_ADDR_LEN) != 0) )
+ return BTM_UNKNOWN_ADDR;
+
+#if SMP_INCLUDED == TRUE
+ p = btm_bda_to_acl(bd_addr);
+ if (p && p->is_le_link &&
+ (p_dev_rec->sec_state == BTM_SEC_STATE_AUTHENTICATING))
+ {
+ BTM_TRACE_DEBUG0 ("Cancel LE pairing");
+ if (SMP_PairCancel(bd_addr))
+ {
+ return BTM_CMD_STARTED;
+ }
+ else
+ {
+ return BTM_WRONG_MODE;
+ }
+ }
+
+#endif
+ BTM_TRACE_DEBUG2 ("hci_handle:0x%x sec_state:%d", p_dev_rec->hci_handle, p_dev_rec->sec_state );
+ if (BTM_PAIR_STATE_WAIT_LOCAL_PIN == btm_cb.pairing_state &&
+ BTM_PAIR_FLAGS_WE_STARTED_DD & btm_cb.pairing_flags)
+ {
+ /* pre-fetching pin for dedicated bonding */
+ btm_sec_bond_cancel_complete();
+ return BTM_SUCCESS;
+ }
+
+ /* If this BDA is in a bonding procedure */
+ if ( (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)
+ && (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD))
+ {
+ /* If the HCI link is up */
+ if (p_dev_rec->hci_handle != BTM_SEC_INVALID_HANDLE)
+ {
+ /* If some other thread disconnecting, we do not send second command */
+ if (p_dev_rec->sec_state == BTM_SEC_STATE_DISCONNECTING)
+ return(BTM_CMD_STARTED);
+
+ /* If the HCI link was set up by Bonding process */
+ if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_DISC_WHEN_DONE)
+ return btm_sec_send_hci_disconnect(p_dev_rec, HCI_ERR_PEER_USER);
+ else
+ l2cu_update_lcb_4_bonding(bd_addr, FALSE);
+
+ return BTM_NOT_AUTHORIZED;
+ }
+ else /*HCI link is not up */
+ {
+ /* If the HCI link creation was started by Bonding process */
+ if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_DISC_WHEN_DONE)
+ {
+ if (btsnd_hcic_create_conn_cancel(bd_addr))
+ return BTM_CMD_STARTED;
+
+ return BTM_NO_RESOURCES;
+ }
+
+ return BTM_NOT_AUTHORIZED;
+ }
+ }
+
+ return BTM_WRONG_MODE;
+}
+
+/*******************************************************************************
+**
+** Function BTM_SecUseMasterLinkKey
+**
+** Description This function is called to tell master of the piconet to
+** switch to master link key
+**
+** Parameters: use_master_key - If true Master Link Key shoul be used
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SecUseMasterLinkKey (BOOLEAN use_master_key)
+{
+ return(btsnd_hcic_master_link_key (use_master_key) ? BTM_SUCCESS :
+ BTM_NO_RESOURCES);
+}
+
+/*******************************************************************************
+**
+** Function BTM_SetMasterKeyCompCback
+**
+** Description This function is called to register for the master key complete
+** status event.
+**
+** Parameters: mkey_cback - callback registered with the security manager
+**
+*******************************************************************************/
+void BTM_SetMasterKeyCompCback( tBTM_MKEY_CALLBACK *mkey_cback )
+{
+ btm_cb.mkey_cback = mkey_cback;
+}
+
+/*******************************************************************************
+**
+** Function BTM_SecGetDeviceLinkKey
+**
+** Description This function is called to obtain link key for the device
+** it returns BTM_SUCCESS if link key is available, or
+** BTM_UNKNOWN_ADDR if Security Manager does not know about
+** the device or device record does not contain link key info
+**
+** Parameters: bd_addr - Address of the device
+** link_key - Link Key is copied into this array
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SecGetDeviceLinkKey (BD_ADDR bd_addr, LINK_KEY link_key)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+
+ if (((p_dev_rec = btm_find_dev (bd_addr)) != NULL)
+ && (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN))
+ {
+ memcpy (link_key, p_dev_rec->link_key, LINK_KEY_LEN);
+ return(BTM_SUCCESS);
+ }
+ return(BTM_UNKNOWN_ADDR);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_SetEncryption
+**
+** Description This function is called to ensure that connection is
+** encrypted. Should be called only on an open connection.
+** Typically only needed for connections that first want to
+** bring up unencrypted links, then later encrypt them.
+**
+** Parameters: bd_addr - Address of the peer device
+** p_callback - Pointer to callback function called if
+** this function returns PENDING after required
+** procedures are completed. Can be set to NULL
+** if status is not desired.
+** p_ref_data - pointer to any data the caller wishes to receive
+** in the callback function upon completion.
+* can be set to NULL if not used.
+**
+** Returns BTM_SUCCESS - already encrypted
+** BTM_PENDING - command will be returned in the callback
+** BTM_WRONG_MODE- connection not up.
+** BTM_BUSY - security procedures are currently active
+** BTM_MODE_UNSUPPORTED - if security manager not linked in.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetEncryption (BD_ADDR bd_addr, tBTM_SEC_CBACK *p_callback,
+ void *p_ref_data)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ tBTM_STATUS rc;
+
+#if BLE_INCLUDED == TRUE
+ tACL_CONN *p;
+ p = btm_bda_to_acl(bd_addr);
+#endif
+
+ p_dev_rec = btm_find_dev (bd_addr);
+ if (!p_dev_rec || (p_dev_rec->hci_handle == BTM_SEC_INVALID_HANDLE))
+ {
+ /* Connection should be up and runnning */
+ BTM_TRACE_WARNING0 ("Security Manager: BTM_SetEncryption not connected");
+
+ if (p_callback)
+ (*p_callback) (bd_addr, p_ref_data, BTM_WRONG_MODE);
+
+ return(BTM_WRONG_MODE);
+ }
+
+
+ if (
+#if BLE_INCLUDED == TRUE
+ !p->is_le_link &&
+#endif
+ (p_dev_rec->sec_flags & (BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED))
+ == (BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED))
+ {
+ BTM_TRACE_EVENT0 ("Security Manager: BTM_SetEncryption already encrypted");
+
+ if (p_callback)
+ (*p_callback) (bd_addr, p_ref_data, BTM_SUCCESS);
+
+ return(BTM_SUCCESS);
+ }
+
+ if (p_dev_rec->p_callback)
+ {
+ /* Connection should be up and runnning */
+ BTM_TRACE_WARNING0 ("Security Manager: BTM_SetEncryption busy");
+
+ if (p_callback)
+ (*p_callback) (bd_addr, p_ref_data, BTM_BUSY);
+
+ return(BTM_BUSY);
+ }
+
+ p_dev_rec->p_callback = p_callback;
+ p_dev_rec->p_ref_data = p_ref_data;
+ p_dev_rec->security_required |= (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT);
+ p_dev_rec->is_originator = FALSE;
+
+ BTM_TRACE_API4 ("Security Manager: BTM_SetEncryption Handle:%d State:%d Flags:0x%x Required:0x%x",
+ p_dev_rec->hci_handle, p_dev_rec->sec_state, p_dev_rec->sec_flags,
+ p_dev_rec->security_required);
+#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE
+ if (p->is_le_link)
+ {
+ rc = btm_ble_set_encryption(bd_addr, p_ref_data, p->link_role);
+ }
+ else
+#endif
+
+ rc = btm_sec_execute_procedure (p_dev_rec);
+
+ if ( rc != BTM_CMD_STARTED)
+ {
+ if (p_callback)
+ {
+ p_dev_rec->p_callback = NULL;
+ (*p_callback) (bd_addr, p_dev_rec->p_ref_data, rc);
+ }
+ }
+ return(rc);
+}
+
+/*******************************************************************************
+ * disconnect the ACL link, if it's not done yet.
+*******************************************************************************/
+static tBTM_STATUS btm_sec_send_hci_disconnect (tBTM_SEC_DEV_REC *p_dev_rec, UINT8 reason)
+{
+ UINT8 old_state = p_dev_rec->sec_state;
+
+ BTM_TRACE_EVENT2 ("btm_sec_send_hci_disconnect: handle:0x%x, reason=0x%x",
+ p_dev_rec->hci_handle, reason);
+
+ /* if some other thread disconnecting, we do not send second command */
+ if (BTM_SEC_STATE_DISCONNECTING != old_state)
+ {
+ p_dev_rec->sec_state = BTM_SEC_STATE_DISCONNECTING;
+
+#if BTM_DISC_DURING_RS == TRUE
+ /* If a Role Switch is in progress, delay the HCI Disconnect to avoid controller problem (4329B1) */
+ if (p_dev_rec->rs_disc_pending == BTM_SEC_RS_PENDING)
+ {
+ BTM_TRACE_ERROR0("RS in progress - Set DISC Pending flag in btm_sec_send_hci_disconnect to delay disconnect");
+ p_dev_rec->rs_disc_pending = BTM_SEC_DISC_PENDING;
+ return BTM_SUCCESS;
+ }
+#endif
+ /* Tear down the HCI link */
+ if (!btsnd_hcic_disconnect (p_dev_rec->hci_handle, reason))
+ {
+ /* could not send disconnect. restore old state */
+ p_dev_rec->sec_state = old_state;
+ return(BTM_NO_RESOURCES);
+ }
+ }
+ return(BTM_CMD_STARTED);
+}
+
+/*******************************************************************************
+**
+** Function BTM_ConfirmReqReply
+**
+** Description This function is called to confirm the numeric value for
+** Simple Pairing in response to BTM_SP_CFM_REQ_EVT
+**
+** Parameters: res - result of the operation BTM_SUCCESS if success
+** bd_addr - Address of the peer device
+**
+*******************************************************************************/
+void BTM_ConfirmReqReply(tBTM_STATUS res, BD_ADDR bd_addr)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+
+ BTM_TRACE_EVENT2 ("BTM_ConfirmReqReply() State: %s Res: %u",
+ btm_pair_state_descr(btm_cb.pairing_state), res);
+
+ /* If timeout already expired or has been canceled, ignore the reply */
+ if ( (btm_cb.pairing_state != BTM_PAIR_STATE_WAIT_NUMERIC_CONFIRM)
+ || (memcmp (btm_cb.pairing_bda, bd_addr, BD_ADDR_LEN) != 0) )
+ return;
+
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_AUTH_COMPLETE);
+
+ if ( (res == BTM_SUCCESS) || (res == BTM_SUCCESS_NO_SECURITY) )
+ {
+ btm_cb.acl_disc_reason = HCI_SUCCESS;
+
+ if (res == BTM_SUCCESS)
+ {
+ if ((p_dev_rec = btm_find_dev (bd_addr)) != NULL)
+ p_dev_rec->sec_flags |= BTM_SEC_LINK_KEY_AUTHED;
+ }
+
+ btsnd_hcic_user_conf_reply (bd_addr, TRUE);
+ }
+ else
+ {
+ /* Report authentication failed event from state BTM_PAIR_STATE_WAIT_AUTH_COMPLETE */
+ btm_cb.acl_disc_reason = HCI_ERR_HOST_REJECT_SECURITY;
+ btsnd_hcic_user_conf_reply (bd_addr, FALSE);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTM_PasskeyReqReply
+**
+** Description This function is called to provide the passkey for
+** Simple Pairing in response to BTM_SP_KEY_REQ_EVT
+**
+** Parameters: res - result of the operation BTM_SUCCESS if success
+** bd_addr - Address of the peer device
+** passkey - numeric value in the range of
+** BTM_MIN_PASSKEY_VAL(0) - BTM_MAX_PASSKEY_VAL(999999(0xF423F)).
+**
+*******************************************************************************/
+#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
+void BTM_PasskeyReqReply(tBTM_STATUS res, BD_ADDR bd_addr, UINT32 passkey)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+
+ BTM_TRACE_API2 ("BTM_PasskeyReqReply: State: %s res:%d",
+ btm_pair_state_descr(btm_cb.pairing_state), res);
+
+ if ( (btm_cb.pairing_state == BTM_PAIR_STATE_IDLE)
+ || (memcmp (btm_cb.pairing_bda, bd_addr, BD_ADDR_LEN) != 0) )
+ {
+ return;
+ }
+
+ /* If timeout already expired or has been canceled, ignore the reply */
+ if ( (btm_cb.pairing_state == BTM_PAIR_STATE_WAIT_AUTH_COMPLETE) && (res != BTM_SUCCESS) )
+ {
+ if ((p_dev_rec = btm_find_dev (bd_addr)) != NULL)
+ {
+ btm_cb.acl_disc_reason = HCI_ERR_HOST_REJECT_SECURITY;
+
+ if (p_dev_rec->hci_handle != BTM_SEC_INVALID_HANDLE)
+ btm_sec_send_hci_disconnect (p_dev_rec, HCI_ERR_AUTH_FAILURE);
+ else
+ BTM_SecBondCancel(bd_addr);
+
+ p_dev_rec->sec_flags &= ~(BTM_SEC_LINK_KEY_AUTHED | BTM_SEC_LINK_KEY_KNOWN);
+
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+ return;
+ }
+ }
+ else if (btm_cb.pairing_state != BTM_PAIR_STATE_KEY_ENTRY)
+ return;
+
+ if (passkey > BTM_MAX_PASSKEY_VAL)
+ res = BTM_ILLEGAL_VALUE;
+
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_AUTH_COMPLETE);
+
+ if (res != BTM_SUCCESS)
+ {
+ /* use BTM_PAIR_STATE_WAIT_AUTH_COMPLETE to report authentication failed event */
+ btm_cb.acl_disc_reason = HCI_ERR_HOST_REJECT_SECURITY;
+ btsnd_hcic_user_passkey_neg_reply (bd_addr);
+ }
+ else
+ {
+ btm_cb.acl_disc_reason = HCI_SUCCESS;
+ btsnd_hcic_user_passkey_reply (bd_addr, passkey);
+ }
+}
+#endif
+
+/*******************************************************************************
+**
+** Function BTM_SendKeypressNotif
+**
+** Description This function is used during the passkey entry model
+** by a device with KeyboardOnly IO capabilities
+** (very likely to be a HID Device).
+** It is called by a HID Device to inform the remote device when
+** a key has been entered or erased.
+**
+** Parameters: bd_addr - Address of the peer device
+** type - notification type
+**
+*******************************************************************************/
+#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
+void BTM_SendKeypressNotif(BD_ADDR bd_addr, tBTM_SP_KEY_TYPE type)
+{
+ /* This API only make sense between PASSKEY_REQ and SP complete */
+ if (btm_cb.pairing_state == BTM_PAIR_STATE_KEY_ENTRY)
+ btsnd_hcic_send_keypress_notif (bd_addr, type);
+}
+#endif
+
+#if BTM_OOB_INCLUDED == TRUE
+/*******************************************************************************
+**
+** Function BTM_IoCapRsp
+**
+** Description This function is called in response to BTM_SP_IO_REQ_EVT
+** When the event data io_req.oob_data is set to BTM_OOB_UNKNOWN
+** by the tBTM_SP_CALLBACK implementation, this function is
+** called to provide the actual response
+**
+** Parameters: bd_addr - Address of the peer device
+** io_cap - The IO capability of local device.
+** oob - BTM_OOB_NONE or BTM_OOB_PRESENT.
+** auth_req- MITM protection required or not.
+**
+*******************************************************************************/
+void BTM_IoCapRsp(BD_ADDR bd_addr, tBTM_IO_CAP io_cap, tBTM_OOB_DATA oob, tBTM_AUTH_REQ auth_req)
+{
+ BTM_TRACE_EVENT3 ("BTM_IoCapRsp: state: %s oob: %d io_cap: %d",
+ btm_pair_state_descr(btm_cb.pairing_state), oob, io_cap);
+
+ if ( (btm_cb.pairing_state != BTM_PAIR_STATE_WAIT_LOCAL_IOCAPS)
+ || (memcmp (btm_cb.pairing_bda, bd_addr, BD_ADDR_LEN) != 0) )
+ return;
+
+ if (oob < BTM_OOB_UNKNOWN && io_cap < BTM_IO_CAP_MAX)
+ {
+ btm_cb.devcb.loc_auth_req = auth_req;
+ btm_cb.devcb.loc_io_caps = io_cap;
+
+ if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD)
+ auth_req = (BTM_AUTH_DD_BOND | (auth_req&BTM_AUTH_YN_BIT));
+
+ btsnd_hcic_io_cap_req_reply (bd_addr, io_cap, oob, auth_req);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTM_ReadLocalOobData
+**
+** Description This function is called to read the local OOB data from
+** LM
+**
+*******************************************************************************/
+tBTM_STATUS BTM_ReadLocalOobData(void)
+{
+ tBTM_STATUS status = BTM_SUCCESS;
+
+ if (btsnd_hcic_read_local_oob_data() == FALSE)
+ status = BTM_NO_RESOURCES;
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function BTM_RemoteOobDataReply
+**
+** Description This function is called to provide the remote OOB data for
+** Simple Pairing in response to BTM_SP_RMT_OOB_EVT
+**
+** Parameters: bd_addr - Address of the peer device
+** c - simple pairing Hash C.
+** r - simple pairing Randomizer C.
+**
+*******************************************************************************/
+void BTM_RemoteOobDataReply(tBTM_STATUS res, BD_ADDR bd_addr, BT_OCTET16 c, BT_OCTET16 r)
+{
+ BTM_TRACE_EVENT2 ("BTM_RemoteOobDataReply(): State: %s res:%d",
+ btm_pair_state_descr(btm_cb.pairing_state), res);
+
+ /* If timeout already expired or has been canceled, ignore the reply */
+ if (btm_cb.pairing_state != BTM_PAIR_STATE_WAIT_LOCAL_OOB_RSP)
+ return;
+
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_AUTH_COMPLETE);
+
+ if (res != BTM_SUCCESS)
+ {
+ /* use BTM_PAIR_STATE_WAIT_AUTH_COMPLETE to report authentication failed event */
+ btm_cb.acl_disc_reason = HCI_ERR_HOST_REJECT_SECURITY;
+ btsnd_hcic_rem_oob_neg_reply (bd_addr);
+ }
+ else
+ {
+ btm_cb.acl_disc_reason = HCI_SUCCESS;
+ btsnd_hcic_rem_oob_reply (bd_addr, c, r);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTM_BuildOobData
+**
+** Description This function is called to build the OOB data payload to
+** be sent over OOB (non-Bluetooth) link
+**
+** Parameters: p_data - the location for OOB data
+** max_len - p_data size.
+** c - simple pairing Hash C.
+** r - simple pairing Randomizer C.
+** name_len- 0, local device name would not be included.
+** otherwise, the local device name is included for
+** up to this specified length
+**
+** Returns Number of bytes in p_data.
+**
+*******************************************************************************/
+UINT16 BTM_BuildOobData(UINT8 *p_data, UINT16 max_len, BT_OCTET16 c,
+ BT_OCTET16 r, UINT8 name_len)
+{
+ UINT8 *p = p_data;
+ UINT16 len = 0;
+ UINT16 delta;
+#if BTM_MAX_LOC_BD_NAME_LEN > 0
+ UINT16 name_size;
+ UINT8 name_type = BTM_EIR_SHORTENED_LOCAL_NAME_TYPE;
+#endif
+
+ if (p_data && max_len >= BTM_OOB_MANDATORY_SIZE)
+ {
+ /* add mandatory part */
+ UINT16_TO_STREAM(p, len);
+ BDADDR_TO_STREAM(p, btm_cb.devcb.local_addr);
+
+ len = BTM_OOB_MANDATORY_SIZE;
+ max_len -= len;
+
+ /* now optional part */
+
+ /* add Hash C */
+ delta = BTM_OOB_HASH_C_SIZE + 2;
+ if (max_len >= delta)
+ {
+ *p++ = BTM_OOB_HASH_C_SIZE + 1;
+ *p++ = BTM_EIR_OOB_SSP_HASH_C_TYPE;
+ ARRAY_TO_STREAM(p, c, BTM_OOB_HASH_C_SIZE);
+ len += delta;
+ max_len -= delta;
+ }
+
+ /* add Rand R */
+ delta = BTM_OOB_RAND_R_SIZE + 2;
+ if (max_len >= delta)
+ {
+ *p++ = BTM_OOB_RAND_R_SIZE + 1;
+ *p++ = BTM_EIR_OOB_SSP_RAND_R_TYPE;
+ ARRAY_TO_STREAM(p, r, BTM_OOB_RAND_R_SIZE);
+ len += delta;
+ max_len -= delta;
+ }
+
+ /* add class of device */
+ delta = BTM_OOB_COD_SIZE + 2;
+ if (max_len >= delta)
+ {
+ *p++ = BTM_OOB_COD_SIZE + 1;
+ *p++ = BTM_EIR_OOB_COD_TYPE;
+ DEVCLASS_TO_STREAM(p, btm_cb.devcb.dev_class);
+ len += delta;
+ max_len -= delta;
+ }
+#if BTM_MAX_LOC_BD_NAME_LEN > 0
+ name_size = name_len;
+ if (name_size > strlen(btm_cb.cfg.bd_name))
+ {
+ name_type = BTM_EIR_COMPLETE_LOCAL_NAME_TYPE;
+ name_size = (UINT16)strlen(btm_cb.cfg.bd_name);
+ }
+ delta = name_size + 2;
+ if (max_len >= delta)
+ {
+ *p++ = name_size + 1;
+ *p++ = name_type;
+ ARRAY_TO_STREAM (p, btm_cb.cfg.bd_name, name_size);
+ len += delta;
+ max_len -= delta;
+ }
+#endif
+ /* update len */
+ p = p_data;
+ UINT16_TO_STREAM(p, len);
+ }
+ return len;
+}
+
+/*******************************************************************************
+**
+** Function BTM_ReadOobData
+**
+** Description This function is called to parse the OOB data payload
+** received over OOB (non-Bluetooth) link
+**
+** Parameters: p_data - the location for OOB data
+** eir_tag - The associated EIR tag to read the data.
+** *p_len(output) - the length of the data with the given tag.
+**
+** Returns the beginning of the data with the given tag.
+** NULL, if the tag is not found.
+**
+*******************************************************************************/
+UINT8 * BTM_ReadOobData(UINT8 *p_data, UINT8 eir_tag, UINT8 *p_len)
+{
+ UINT8 *p = p_data;
+ UINT16 max_len;
+ UINT8 len, type;
+ UINT8 *p_ret = NULL;
+ UINT8 ret_len = 0;
+
+ if (p_data)
+ {
+ STREAM_TO_UINT16(max_len, p);
+ if (max_len >= BTM_OOB_MANDATORY_SIZE)
+ {
+ if (BTM_EIR_OOB_BD_ADDR_TYPE == eir_tag)
+ {
+ p_ret = p; /* the location for bd_addr */
+ ret_len = BTM_OOB_BD_ADDR_SIZE;
+ }
+ else
+ {
+ p += BD_ADDR_LEN;
+ max_len -= BTM_OOB_MANDATORY_SIZE;
+ /* now the optional data in EIR format */
+ while (max_len > 0)
+ {
+ len = *p++; /* tag data len + 1 */
+ type = *p++;
+ if (eir_tag == type)
+ {
+ p_ret = p;
+ ret_len = len - 1;
+ break;
+ }
+ /* the data size of this tag is len + 1 (tag data len + 2) */
+ if (max_len > len)
+ {
+ max_len -= len;
+ max_len--;
+ len--;
+ p += len;
+ }
+ else
+ max_len = 0;
+ }
+ }
+ }
+ }
+
+ if (p_len)
+ *p_len = ret_len;
+
+ return p_ret;
+}
+#endif
+
+/*******************************************************************************
+**
+** Function BTM_SetOutService
+**
+** Description This function is called to set the service for
+** outgoing connections.
+**
+** If the profile/application calls BTM_SetSecurityLevel
+** before initiating a connection, this function does not
+** need to be called.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTM_SetOutService(BD_ADDR bd_addr, UINT8 service_id, UINT32 mx_chan_id)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ tBTM_SEC_SERV_REC *p_serv_rec = &btm_cb.sec_serv_rec[0];
+ int i;
+
+ btm_cb.p_out_serv = p_serv_rec;
+ p_dev_rec = btm_find_dev (bd_addr);
+
+ for (i = 0; i < BTM_SEC_MAX_SERVICE_RECORDS; i++, p_serv_rec++)
+ {
+ if ((p_serv_rec->security_flags & BTM_SEC_IN_USE)
+ && (p_serv_rec->service_id == service_id)
+ && (p_serv_rec->orig_mx_chan_id == mx_chan_id))
+ {
+ BTM_TRACE_API4("BTM_SetOutService p_out_serv id %d, psm 0x%04x, proto_id %d, chan_id %d",
+ p_serv_rec->service_id, p_serv_rec->psm, p_serv_rec->mx_proto_id, p_serv_rec->orig_mx_chan_id);
+ btm_cb.p_out_serv = p_serv_rec;
+ if (p_dev_rec)
+ p_dev_rec->p_cur_service = p_serv_rec;
+ break;
+ }
+ }
+}
+
+/************************************************************************
+** I N T E R N A L F U N C T I O N S
+*************************************************************************/
+/*******************************************************************************
+**
+** Function btm_sec_check_upgrade
+**
+** Description This function is called to check if the existing link key
+** needs to be upgraded.
+**
+** Returns void
+**
+*******************************************************************************/
+static void btm_sec_check_upgrade(tBTM_SEC_DEV_REC *p_dev_rec, BOOLEAN is_originator)
+{
+ tBTM_SP_UPGRADE evt_data;
+ UINT16 mtm_check = is_originator ? BTM_SEC_OUT_MITM : BTM_SEC_IN_MITM;
+
+ if (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN)
+ {
+
+ BTM_TRACE_DEBUG5 ("btm_sec_check_upgrade id:%d, link_key_typet:%d, rmt_io_caps:%d, chk flags:x%x, flags:x%x",
+ p_dev_rec->p_cur_service->service_id, p_dev_rec->link_key_type, p_dev_rec->rmt_io_caps,
+ mtm_check, p_dev_rec->p_cur_service->security_flags);
+ /* Already have a link key to the connected peer. Is the link key secure enough?
+ ** Is a link key upgrade even possible?
+ */
+ if ((p_dev_rec->security_required & mtm_check) /* needs MITM */
+ && (p_dev_rec->link_key_type == BTM_LKEY_TYPE_UNAUTH_COMB) /* has unauthenticated link key */
+ && (p_dev_rec->rmt_io_caps < BTM_IO_CAP_MAX) /* a valid peer IO cap */
+ && (btm_sec_io_map[p_dev_rec->rmt_io_caps][btm_cb.devcb.loc_io_caps])) /* authenticated link key is possible */
+ {
+ BTM_TRACE_DEBUG1 ("need upgrade!! sec_flags:0x%x", p_dev_rec->sec_flags);
+ /* upgrade is possible: check if the application wants the upgrade.
+ * If the application is configured to use a global MITM flag,
+ * it probably would not want to upgrade the link key based on the security level database */
+ memcpy (evt_data.bd_addr, p_dev_rec->bd_addr, BD_ADDR_LEN);
+ evt_data.upgrade = TRUE;
+ if (btm_cb.api.p_sp_callback)
+ (*btm_cb.api.p_sp_callback) (BTM_SP_UPGRADE_EVT, (tBTM_SP_EVT_DATA *)&evt_data);
+
+ BTM_TRACE_DEBUG1 ("evt_data.upgrade:0x%x", evt_data.upgrade);
+ if (evt_data.upgrade)
+ {
+ /* if the application confirms the upgrade, set the upgrade bit */
+ p_dev_rec->sm4 |= BTM_SM4_UPGRADE;
+
+ /* Clear the link key known to go through authentication/pairing again */
+ p_dev_rec->sec_flags &= ~(BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LINK_KEY_AUTHED);
+ p_dev_rec->sec_flags &= ~BTM_SEC_AUTHENTICATED;
+ BTM_TRACE_DEBUG1 ("sec_flags:0x%x", p_dev_rec->sec_flags);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_l2cap_access_req
+**
+** Description This function is called by the L2CAP to grant permission to
+** establish L2CAP connection to or from the peer device.
+**
+** Parameters: bd_addr - Address of the peer device
+** psm - L2CAP PSM
+** is_originator - TRUE if protocol above L2CAP originates
+** connection
+** p_callback - Pointer to callback function called if
+** this function returns PENDING after required
+** procedures are complete. MUST NOT BE NULL.
+**
+** Returns tBTM_STATUS
+**
+*******************************************************************************/
+#define BTM_SEC_OUT_FLAGS (BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT | BTM_SEC_OUT_AUTHORIZE)
+#define BTM_SEC_IN_FLAGS (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT | BTM_SEC_IN_AUTHORIZE)
+
+tBTM_STATUS btm_sec_l2cap_access_req (BD_ADDR bd_addr, UINT16 psm, UINT16 handle,
+ CONNECTION_TYPE conn_type,
+ tBTM_SEC_CALLBACK *p_callback,
+ void *p_ref_data)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ tBTM_SEC_SERV_REC *p_serv_rec;
+ UINT16 security_required;
+ UINT16 old_security_required;
+ BOOLEAN old_is_originator;
+ tBTM_STATUS rc = BTM_SUCCESS;
+ BOOLEAN chk_acp_auth_done = FALSE;
+ BOOLEAN is_originator;
+
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ if (conn_type & CONNECTION_TYPE_ORIG_MASK)
+ is_originator = TRUE;
+ else
+ is_originator = FALSE;
+
+ BTM_TRACE_DEBUG2 ("btm_sec_l2cap_access_req conn_type:0x%x, 0x%x", conn_type, p_ref_data);
+#else
+ is_originator = conn_type;
+
+ BTM_TRACE_DEBUG2 ("btm_sec_l2cap_access_req is_originator:%d, 0x%x", is_originator, p_ref_data);
+#endif
+
+ /* Find or get oldest record */
+ p_dev_rec = btm_find_or_alloc_dev (bd_addr);
+
+ p_dev_rec->hci_handle = handle;
+
+ /* Find the service record for the PSM */
+ p_serv_rec = btm_sec_find_first_serv (conn_type, psm);
+
+ /* If there is no application registered with this PSM do not allow connection */
+ if (!p_serv_rec)
+ {
+ BTM_TRACE_WARNING1 ("btm_sec_l2cap_access_req() PSM:%d no application registerd", psm);
+
+ (*p_callback) (bd_addr, p_ref_data, BTM_MODE_UNSUPPORTED);
+
+ return(BTM_MODE_UNSUPPORTED);
+ }
+
+ /* SDP connection we will always let through */
+ if (BT_PSM_SDP == psm)
+ {
+ (*p_callback) (bd_addr, p_ref_data, BTM_SUCCESS_NO_SECURITY);
+
+ return(BTM_SUCCESS);
+ }
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ if ( conn_type & CONNECTION_TYPE_CONNLESS_MASK )
+ {
+ security_required = p_serv_rec->ucd_security_flags;
+
+ rc = BTM_CMD_STARTED;
+ if (is_originator)
+ {
+ if (((security_required & BTM_SEC_OUT_FLAGS) == 0) ||
+ ((((security_required & BTM_SEC_OUT_FLAGS) == BTM_SEC_OUT_AUTHENTICATE) && (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED))) ||
+ ((((security_required & BTM_SEC_OUT_FLAGS) == (BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT)) && (p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED))) ||
+ ((((security_required & BTM_SEC_OUT_FLAGS) == BTM_SEC_OUT_FLAGS) && (p_dev_rec->sec_flags & BTM_SEC_AUTHORIZED))) )
+ {
+ rc = BTM_SUCCESS;
+ }
+ }
+ else
+ {
+ if (((security_required & BTM_SEC_IN_FLAGS) == 0) ||
+ ((((security_required & BTM_SEC_IN_FLAGS) == BTM_SEC_IN_AUTHENTICATE) && (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED))) ||
+ ((((security_required & BTM_SEC_IN_FLAGS) == (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT)) && (p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED))) ||
+ ((((security_required & BTM_SEC_IN_FLAGS) == BTM_SEC_IN_FLAGS) && (p_dev_rec->sec_flags & BTM_SEC_AUTHORIZED))) )
+ {
+ rc = BTM_SUCCESS;
+ }
+ }
+
+ if (rc == BTM_SUCCESS)
+ {
+ if (p_callback)
+ (*p_callback) (bd_addr, (void *)p_ref_data, BTM_SUCCESS);
+
+ return(BTM_SUCCESS);
+ }
+ }
+ else
+#endif
+ {
+ security_required = p_serv_rec->security_flags;
+ }
+
+ /* there are some devices (moto KRZR) which connects to several services at the same time */
+ /* we will process one after another */
+ if ( (p_dev_rec->p_callback) || (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) )
+ {
+ BTM_TRACE_EVENT2 ("btm_sec_l2cap_access_req() - busy - PSM:%d delayed state: %s",
+ psm, btm_pair_state_descr(btm_cb.pairing_state));
+ rc = BTM_CMD_STARTED;
+ if ((BTM_SEC_MODE_SP != btm_cb.security_mode)
+ || ((BTM_SEC_MODE_SP == btm_cb.security_mode) && (BTM_SM4_KNOWN == p_dev_rec->sm4))
+ )
+ {
+ BTM_TRACE_EVENT2 ("security_flags:x%x, sec_flags:x%x", security_required, p_dev_rec->sec_flags);
+ /* legacy mode - local is legacy or local is lisbon/peer is legacy */
+ if (is_originator)
+ {
+ if (((security_required & BTM_SEC_OUT_FLAGS) == 0) ||
+ ((((security_required & BTM_SEC_OUT_FLAGS) == BTM_SEC_OUT_AUTHENTICATE) && (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED))) ||
+ ((((security_required & BTM_SEC_OUT_FLAGS) == (BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT)) && (p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED))) ||
+ ((((security_required & BTM_SEC_OUT_FLAGS) == BTM_SEC_OUT_FLAGS) && (p_dev_rec->sec_flags & BTM_SEC_AUTHORIZED))) )
+ {
+ rc = BTM_SUCCESS;
+ }
+ }
+ else
+ {
+ if (((security_required & BTM_SEC_IN_FLAGS) == 0) ||
+ ((((security_required & BTM_SEC_IN_FLAGS) == BTM_SEC_IN_AUTHENTICATE) && (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED))) ||
+ ((((security_required & BTM_SEC_IN_FLAGS) == (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT)) && (p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED))) ||
+ ((((security_required & BTM_SEC_IN_FLAGS) == BTM_SEC_IN_FLAGS) && (p_dev_rec->sec_flags & BTM_SEC_AUTHORIZED))) )
+ {
+ rc = BTM_SUCCESS;
+ }
+ }
+
+ if (rc == BTM_SUCCESS)
+ {
+ if (p_callback)
+ (*p_callback) (bd_addr, (void *)p_ref_data, BTM_SUCCESS);
+
+ return(BTM_SUCCESS);
+ }
+ }
+
+ btm_cb.sec_req_pending = TRUE;
+ return(BTM_CMD_STARTED);
+ }
+
+ /* Save pointer to service record */
+ p_dev_rec->p_cur_service = p_serv_rec;
+
+
+ /* mess /w security_required in btm_sec_l2cap_access_req for Lisbon */
+ if (btm_cb.security_mode == BTM_SEC_MODE_SP)
+ {
+ if (is_originator)
+ {
+ if (BTM_SEC_IS_SM4(p_dev_rec->sm4))
+ {
+ /* SM4 to SM4 -> always authenticate & encrypt */
+ security_required |= (BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT);
+ }
+ else
+ {
+ if ( !(BTM_SM4_KNOWN & p_dev_rec->sm4))
+ {
+ BTM_TRACE_DEBUG1 ("remote features unknown!!sec_flags:0x%x", p_dev_rec->sec_flags);
+ /* the remote features are not known yet */
+ p_dev_rec->sm4 |= BTM_SM4_REQ_PEND;
+
+ return(BTM_CMD_STARTED);
+ }
+ }
+ }
+ else
+ {
+ /* responder */
+ if (BTM_SEC_IS_SM4(p_dev_rec->sm4))
+ {
+ /* SM4 to SM4: the acceptor needs to make sure the authentication is already done */
+ chk_acp_auth_done = TRUE;
+ /* SM4 to SM4 -> always authenticate & encrypt */
+ security_required |= (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT);
+ }
+ else
+ {
+ if ( !(BTM_SM4_KNOWN & p_dev_rec->sm4))
+ {
+ BTM_TRACE_DEBUG1 ("(rsp) remote features unknown!!sec_flags:0x%x", p_dev_rec->sec_flags);
+ /* the remote features are not known yet */
+ p_dev_rec->sm4 |= BTM_SM4_REQ_PEND;
+
+ return(BTM_CMD_STARTED);
+ }
+ }
+ }
+ }
+
+ BTM_TRACE_DEBUG4 ("btm_sec_l2cap_access_req() sm4:0x%x, sec_flags:0x%x, security_required:0x%x chk:%d",
+ p_dev_rec->sm4, p_dev_rec->sec_flags, security_required, chk_acp_auth_done);
+
+ old_security_required = p_dev_rec->security_required;
+ old_is_originator = p_dev_rec->is_originator;
+ p_dev_rec->security_required = security_required;
+ p_dev_rec->p_ref_data = p_ref_data;
+ p_dev_rec->is_originator = is_originator;
+
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ if ( conn_type & CONNECTION_TYPE_CONNLESS_MASK )
+ p_dev_rec->is_ucd = TRUE;
+ else
+ p_dev_rec->is_ucd = FALSE;
+#endif
+
+ /* If there are multiple service records used through the same PSM */
+ /* leave security decision for the multiplexor on the top */
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ if (((btm_sec_find_next_serv (p_serv_rec)) != NULL)
+ &&(!( conn_type & CONNECTION_TYPE_CONNLESS_MASK ))) /* if not UCD */
+#else
+ if ((btm_sec_find_next_serv (p_serv_rec)) != NULL)
+#endif
+ {
+ BTM_TRACE_DEBUG2 ("no next_serv sm4:0x%x, chk:%d", p_dev_rec->sm4, chk_acp_auth_done);
+ if (!BTM_SEC_IS_SM4(p_dev_rec->sm4))
+ {
+ BTM_TRACE_EVENT1 ("Security Manager: l2cap_access_req PSM:%d postponed for multiplexer", psm);
+ /* pre-Lisbon: restore the old settings */
+ p_dev_rec->security_required = old_security_required;
+ p_dev_rec->is_originator = old_is_originator;
+
+ (*p_callback) (bd_addr, p_ref_data, BTM_SUCCESS);
+
+ return(BTM_SUCCESS);
+ }
+ }
+
+ /* if the originator is using dynamic PSM in legacy mode, do not start any security process now.
+ * The layer above L2CAP needs to carry out the security requirement after L2CAP connect response is received*/
+ if (is_originator && (btm_cb.security_mode != BTM_SEC_MODE_SP || !BTM_SEC_IS_SM4(p_dev_rec->sm4)) && (psm >= 0x1001))
+ {
+ BTM_TRACE_EVENT1 ("dynamic PSM:0x%x in legacy mode - postponed for upper layer", psm);
+ /* restore the old settings */
+ p_dev_rec->security_required = old_security_required;
+ p_dev_rec->is_originator = old_is_originator;
+
+ (*p_callback) (bd_addr, p_ref_data, BTM_SUCCESS);
+
+ return(BTM_SUCCESS);
+ }
+
+ if (chk_acp_auth_done)
+ {
+ BTM_TRACE_DEBUG2 ("(SM4 to SM4) btm_sec_l2cap_access_req rspd. authenticated: x%x, enc: x%x",
+ (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED), (p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED));
+ /* SM4, but we do not know for sure which level of security we need.
+ * as long as we have a link key, it's OK */
+ if ((0 == (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED))
+ ||(0 == (p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED)))
+ {
+ rc = BTM_DELAY_CHECK;
+ /*
+ 2046 may report HCI_Encryption_Change and L2C Connection Request out of sequence
+ because of data path issues. Delay this disconnect a little bit
+ */
+ BTM_TRACE_ERROR0 ("peer should have initiated security process by now (SM4 to SM4)");
+ p_dev_rec->p_callback = p_callback;
+ p_dev_rec->sec_state = BTM_SEC_STATE_DELAY_FOR_ENC;
+ (*p_callback) (bd_addr, p_ref_data, rc);
+
+ return(BTM_SUCCESS);
+ }
+ }
+
+ p_dev_rec->p_callback = p_callback;
+
+ /* Although authentication and encryption are per connection */
+ /* authorization is per access request. For example when serial connection */
+ /* is up and authorized and client requests to read file (access to other */
+ /* scn, we need to request user's permission again. */
+ p_dev_rec->sec_flags &= ~BTM_SEC_AUTHORIZED;
+
+ if (BTM_SEC_IS_SM4(p_dev_rec->sm4))
+ {
+ /* If we already have a link key to the connected peer, is the link key secure enough ? */
+ btm_sec_check_upgrade(p_dev_rec, is_originator);
+ }
+
+ BTM_TRACE_EVENT6 ("Security Manager: l2cap_access_req PSM:%d Handle:%d State:%d Flags:0x%x Required:0x%x Service ID:%d",
+ psm, handle, p_dev_rec->sec_state, p_dev_rec->sec_flags, p_dev_rec->security_required, p_dev_rec->p_cur_service->service_id);
+
+ if ((rc = btm_sec_execute_procedure (p_dev_rec)) != BTM_CMD_STARTED)
+ {
+ p_dev_rec->p_callback = NULL;
+ (*p_callback) (bd_addr, p_dev_rec->p_ref_data, (UINT8)rc);
+ }
+
+ return(rc);
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_mx_access_request
+**
+** Description This function is called by all Multiplexing Protocols during
+** establishing connection to or from peer device to grant
+** permission to establish application connection.
+**
+** Parameters: bd_addr - Address of the peer device
+** psm - L2CAP PSM
+** is_originator - TRUE if protocol above L2CAP originates
+** connection
+** mx_proto_id - protocol ID of the multiplexer
+** mx_chan_id - multiplexer channel to reach application
+** p_callback - Pointer to callback function called if
+** this function returns PENDING after required
+** procedures are completed
+** p_ref_data - Pointer to any reference data needed by the
+** the callback function.
+**
+** Returns BTM_CMD_STARTED
+**
+*******************************************************************************/
+tBTM_STATUS btm_sec_mx_access_request (BD_ADDR bd_addr, UINT16 psm, BOOLEAN is_originator,
+ UINT32 mx_proto_id, UINT32 mx_chan_id,
+ tBTM_SEC_CALLBACK *p_callback, void *p_ref_data)
+
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ tBTM_SEC_SERV_REC *p_serv_rec;
+ tBTM_STATUS rc;
+
+ BTM_TRACE_DEBUG1 ("btm_sec_mx_access_request is_originator:%d", is_originator);
+ /* Find or get oldest record */
+ p_dev_rec = btm_find_or_alloc_dev (bd_addr);
+
+ /* Find the service record for the PSM */
+ p_serv_rec = btm_sec_find_mx_serv (is_originator, psm, mx_proto_id, mx_chan_id);
+
+ /* If there is no application registered with this PSM do not allow connection */
+ if (!p_serv_rec)
+ {
+ if (p_callback)
+ (*p_callback) (bd_addr, p_ref_data, BTM_MODE_UNSUPPORTED);
+
+ BTM_TRACE_ERROR3 ("Security Manager: MX service not found PSM:%d Proto:%d SCN:%d",
+ psm, mx_proto_id, mx_chan_id);
+ return BTM_NO_RESOURCES;
+ }
+
+ /* there are some devices (moto phone) which connects to several services at the same time */
+ /* we will process one after another */
+ if ( (p_dev_rec->p_callback) || (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) )
+ {
+ BTM_TRACE_EVENT4 ("btm_sec_mx_access_request service PSM:%d Proto:%d SCN:%d delayed state: %s",
+ psm, mx_proto_id, mx_chan_id, btm_pair_state_descr(btm_cb.pairing_state));
+
+ btm_sec_queue_mx_request (bd_addr, psm, is_originator, mx_proto_id, mx_chan_id, p_callback, p_ref_data);
+ return BTM_CMD_STARTED;
+ }
+
+ p_dev_rec->p_cur_service = p_serv_rec;
+ p_dev_rec->security_required = p_serv_rec->security_flags;
+
+ if (BTM_SEC_MODE_SP == btm_cb.security_mode)
+ {
+ if (BTM_SEC_IS_SM4(p_dev_rec->sm4))
+ {
+ /* If we already have a link key, check if that link key is good enough */
+ btm_sec_check_upgrade(p_dev_rec, is_originator);
+ }
+ }
+
+ p_dev_rec->is_originator = is_originator;
+ p_dev_rec->p_callback = p_callback;
+ p_dev_rec->p_ref_data = p_ref_data;
+
+ /* Although authentication and encryption are per connection */
+ /* authorization is per access request. For example when serial connection */
+ /* is up and authorized and client requests to read file (access to other */
+ /* scn, we need to request user's permission again. */
+ p_dev_rec->sec_flags &= ~(BTM_SEC_AUTHORIZED);
+
+ BTM_TRACE_EVENT6 ("Security Manager: mx_access_req proto_id:%d chan_id:%d State:%d Flags:0x%x Required:0x%x Service ID:%d",
+ mx_proto_id, mx_chan_id, p_dev_rec->sec_state, p_dev_rec->sec_flags, p_dev_rec->security_required, p_dev_rec->p_cur_service->service_id);
+
+ if ((rc = btm_sec_execute_procedure (p_dev_rec)) != BTM_CMD_STARTED)
+ {
+ if (p_callback)
+ {
+ p_dev_rec->p_callback = NULL;
+
+ (*p_callback) (bd_addr, p_ref_data, (UINT8)rc);
+ }
+ }
+
+ return rc;
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_conn_req
+**
+** Description This function is when the peer device is requesting
+** connection
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sec_conn_req (UINT8 *bda, UINT8 *dc)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bda);
+
+ /* Some device may request a connection before we are done with the HCI_Reset sequence */
+ if (btm_cb.devcb.state != BTM_DEV_STATE_READY)
+ {
+ BTM_TRACE_EVENT0 ("Security Manager: connect request when device not ready");
+ btsnd_hcic_reject_conn (bda, HCI_ERR_HOST_REJECT_DEVICE);
+ return;
+ }
+
+ /* Security guys wants us not to allow connection from not paired devices */
+
+ /* Check if connection is allowed for only paired devices */
+ if (btm_cb.connect_only_paired)
+ {
+ if (!p_dev_rec || !(p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_AUTHED))
+ {
+ BTM_TRACE_EVENT0 ("Security Manager: connect request from non-paired device");
+ btsnd_hcic_reject_conn (bda, HCI_ERR_HOST_REJECT_DEVICE);
+ return;
+ }
+ }
+
+#if BTM_ALLOW_CONN_IF_NONDISCOVER == FALSE
+ /* If non-discoverable, only allow known devices to connect */
+ if (btm_cb.btm_inq_vars.discoverable_mode == BTM_NON_DISCOVERABLE)
+ {
+ if (!p_dev_rec)
+ {
+ BTM_TRACE_EVENT0 ("Security Manager: connect request from not paired device");
+ btsnd_hcic_reject_conn (bda, HCI_ERR_HOST_REJECT_DEVICE);
+ return;
+ }
+ }
+#endif
+
+ /* Host can be registered to verify comming BDA or DC */
+ if (btm_cb.p_conn_filter_cb)
+ {
+ if (!(* btm_cb.p_conn_filter_cb) (bda, dc))
+ {
+ BTM_TRACE_EVENT0 ("Security Manager: connect request did not pass filter");
+
+ /* incomming call did not pass connection filters. Reject */
+ btsnd_hcic_reject_conn (bda, HCI_ERR_HOST_REJECT_DEVICE);
+ return;
+ }
+ }
+
+ if ((btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)
+ &&(btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD)
+ &&(!memcmp (btm_cb.pairing_bda, bda, BD_ADDR_LEN)))
+ {
+ BTM_TRACE_EVENT0 ("Security Manager: reject connect request from bonding device");
+
+ /* incoming connection from bonding device is rejected */
+ btm_cb.pairing_flags |= BTM_PAIR_FLAGS_REJECTED_CONNECT;
+ btsnd_hcic_reject_conn (bda, HCI_ERR_HOST_REJECT_DEVICE);
+ return;
+ }
+
+ /* Host is not interested or approved connection. Save BDA and DC and */
+ /* pass request to L2CAP */
+ memcpy (btm_cb.connecting_bda, bda, BD_ADDR_LEN);
+ memcpy (btm_cb.connecting_dc, dc, DEV_CLASS_LEN);
+
+ if (l2c_link_hci_conn_req (bda))
+ {
+ if (!p_dev_rec)
+ {
+ /* accept the connection -> allocate a device record */
+ p_dev_rec = btm_sec_alloc_dev (bda);
+ }
+ if (p_dev_rec)
+ {
+ p_dev_rec->sm4 |= BTM_SM4_CONN_PEND;
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_bond_cancel_complete
+**
+** Description This function is called to report bond cancel complete
+** event.
+**
+** Returns void
+**
+*******************************************************************************/
+static void btm_sec_bond_cancel_complete (void)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+
+ if ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_DISC_WHEN_DONE) ||
+ (BTM_PAIR_STATE_WAIT_LOCAL_PIN == btm_cb.pairing_state &&
+ BTM_PAIR_FLAGS_WE_STARTED_DD & btm_cb.pairing_flags))
+ {
+ /* for dedicated bonding in legacy mode, authentication happens at "link level"
+ * btm_sec_connected is called with failed status.
+ * In theory, the code that handles is_pairing_device/TRUE should clean out security related code.
+ * However, this function may clean out the security related flags and btm_sec_connected would not know
+ * this function also needs to do proper clean up.
+ */
+ if ((p_dev_rec = btm_find_dev (btm_cb.pairing_bda)) != NULL)
+ p_dev_rec->security_required = BTM_SEC_NONE;
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+
+ /* Notify application that the cancel succeeded */
+ if (btm_cb.api.p_bond_cancel_cmpl_callback)
+ btm_cb.api.p_bond_cancel_cmpl_callback(BTM_SUCCESS);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_create_conn_cancel_complete
+**
+** Description This function is called when the command complete message
+** is received from the HCI for the create connection cancel
+** command.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_create_conn_cancel_complete (UINT8 *p)
+{
+ UINT8 status;
+
+ STREAM_TO_UINT8 (status, p);
+ BTM_TRACE_EVENT2 ("btm_create_conn_cancel_complete(): in State: %s status:%d",
+ btm_pair_state_descr(btm_cb.pairing_state), status);
+
+ /* if the create conn cancel cmd was issued by the bond cancel,
+ ** the application needs to be notified that bond cancel succeeded
+ */
+ switch (status)
+ {
+ case HCI_SUCCESS:
+ btm_sec_bond_cancel_complete();
+ break;
+ case HCI_ERR_CONNECTION_EXISTS:
+ case HCI_ERR_NO_CONNECTION:
+ default:
+ /* Notify application of the error */
+ if (btm_cb.api.p_bond_cancel_cmpl_callback)
+ btm_cb.api.p_bond_cancel_cmpl_callback(BTM_ERR_PROCESSING);
+ break;
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_check_pending_reqs
+**
+** Description This function is called at the end of the security procedure
+** to let L2CAP and RFCOMM know to re-submit any pending requests
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sec_check_pending_reqs (void)
+{
+ tBTM_SEC_QUEUE_ENTRY *p_e;
+ BUFFER_Q bq;
+
+ if (btm_cb.pairing_state == BTM_PAIR_STATE_IDLE)
+ {
+ /* First, resubmit L2CAP requests */
+ if (btm_cb.sec_req_pending)
+ {
+ btm_cb.sec_req_pending = FALSE;
+ l2cu_resubmit_pending_sec_req (NULL);
+ }
+
+ /* Now, re-submit anything in the mux queue */
+ bq = btm_cb.sec_pending_q;
+
+ GKI_init_q (&btm_cb.sec_pending_q);
+
+ while ((p_e = (tBTM_SEC_QUEUE_ENTRY *)GKI_dequeue (&bq)) != NULL)
+ {
+ /* Check that the ACL is still up before starting security procedures */
+ if (btm_bda_to_acl(p_e->bd_addr) != NULL)
+ {
+ BTM_TRACE_EVENT4 ("btm_sec_check_pending_reqs() submitting PSM: 0x%04x Is_Orig: %u mx_proto_id: %u mx_chan_id: %u",
+ p_e->psm, p_e->is_orig, p_e->mx_proto_id, p_e->mx_chan_id);
+
+ btm_sec_mx_access_request (p_e->bd_addr, p_e->psm, p_e->is_orig,
+ p_e->mx_proto_id, p_e->mx_chan_id,
+ p_e->p_callback, p_e->p_ref_data);
+ }
+
+ GKI_freebuf (p_e);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_init
+**
+** Description This function is on the SEC startup
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sec_init (UINT8 sec_mode)
+{
+#if 0 /* cleared in btm_init; put back in if calling from anywhere else! */
+ int i;
+
+ memset (btm_cb.sec_serv_rec, 0, sizeof (btm_cb.sec_serv_rec));
+ memset (btm_cb.sec_dev_rec, 0, sizeof (btm_cb.sec_dev_rec));
+ memset (&btm_cb.pairing_tle, 0, sizeof(TIMER_LIST_ENT));
+
+#endif
+ btm_cb.security_mode = sec_mode;
+ memset (btm_cb.pairing_bda, 0xff, BD_ADDR_LEN);
+ btm_cb.max_collision_delay = BTM_SEC_MAX_COLLISION_DELAY;
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_device_down
+**
+** Description This function should be called when device is disabled or
+** turned off
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sec_device_down (void)
+{
+ BTM_TRACE_EVENT1 ("btm_sec_device_down() State: %s", btm_pair_state_descr(btm_cb.pairing_state));
+
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_dev_reset
+**
+** Description This function should be called after device reset
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sec_dev_reset (void)
+{
+#if (BTM_PRE_LISBON_INCLUDED == TRUE)
+ if (btm_cb.security_mode == BTM_SEC_MODE_LINK)
+ {
+ btsnd_hcic_write_auth_enable (TRUE);
+ btsnd_hcic_write_encr_mode (HCI_ENCRYPT_MODE_POINT_TO_POINT);
+ }
+#endif
+#if (BTM_PRE_LISBON_INCLUDED == TRUE)
+ else
+#endif
+ /* this function is only called from btm_read_local_features_complete()
+ * right now. */
+ if (HCI_SIMPLE_PAIRING_SUPPORTED(btm_cb.devcb.local_features))
+ {
+ btsnd_hcic_write_simple_pairing_mode(HCI_SP_MODE_ENABLED);
+#if BLE_INCLUDED == TRUE
+ btsnd_hcic_set_event_mask(LOCAL_BR_EDR_CONTROLLER_ID,
+ (UINT8 *)HCI_DUMO_EVENT_MASK_EXT);
+#else
+ btsnd_hcic_set_event_mask(LOCAL_BR_EDR_CONTROLLER_ID,
+ (UINT8 *)HCI_LISBON_EVENT_MASK_EXT);
+#endif
+ /* set the default IO capabilities */
+ btm_cb.devcb.loc_io_caps = BTM_LOCAL_IO_CAPS;
+ /* add mx service to use no security */
+#if (RFCOMM_INCLUDED == TRUE)
+ BTM_SetSecurityLevel(FALSE, "RFC_MUX", BTM_SEC_SERVICE_RFC_MUX,
+ BTM_SEC_NONE, BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM, 0);
+#endif
+ }
+ else
+ {
+ btm_cb.security_mode = BTM_SEC_MODE_SERVICE;
+ }
+
+ BTM_TRACE_DEBUG1 ("btm_sec_dev_reset sec mode: %d", btm_cb.security_mode);
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_abort_access_req
+**
+** Description This function is called by the L2CAP or RFCOMM to abort
+** the pending operation.
+**
+** Parameters: bd_addr - Address of the peer device
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sec_abort_access_req (BD_ADDR bd_addr)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr);
+
+ if (!p_dev_rec)
+ return;
+
+ if (btm_cb.api.p_abort_callback)
+ (*btm_cb.api.p_abort_callback)(bd_addr, p_dev_rec->dev_class, p_dev_rec->sec_bd_name);
+
+ if ((p_dev_rec->sec_state != BTM_SEC_STATE_AUTHORIZING)
+ && (p_dev_rec->sec_state != BTM_SEC_STATE_AUTHENTICATING))
+ return;
+
+ p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+ p_dev_rec->p_callback = NULL;
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_dd_create_conn
+**
+** Description This function is called to create the ACL connection for
+** the dedicated boding process
+**
+** Returns void
+**
+*******************************************************************************/
+static tBTM_STATUS btm_sec_dd_create_conn (tBTM_SEC_DEV_REC *p_dev_rec)
+{
+ tL2C_LCB *p_lcb;
+
+ /* Make sure an L2cap link control block is available */
+ if ((p_lcb = l2cu_allocate_lcb (p_dev_rec->bd_addr, TRUE)) == NULL)
+ {
+ BTM_TRACE_WARNING6 ("Security Manager: failed allocate LCB [%02x%02x%02x%02x%02x%02x]",
+ p_dev_rec->bd_addr[0], p_dev_rec->bd_addr[1], p_dev_rec->bd_addr[2],
+ p_dev_rec->bd_addr[3], p_dev_rec->bd_addr[4], p_dev_rec->bd_addr[5]);
+
+ return(BTM_NO_RESOURCES);
+ }
+
+ /* set up the control block to indicated dedicated bonding */
+ btm_cb.pairing_flags |= BTM_PAIR_FLAGS_DISC_WHEN_DONE;
+
+ if (l2cu_create_conn(p_lcb) == FALSE)
+ {
+ BTM_TRACE_WARNING6 ("Security Manager: failed create [%02x%02x%02x%02x%02x%02x]",
+ p_dev_rec->bd_addr[0], p_dev_rec->bd_addr[1], p_dev_rec->bd_addr[2],
+ p_dev_rec->bd_addr[3], p_dev_rec->bd_addr[4], p_dev_rec->bd_addr[5]);
+
+ l2cu_release_lcb(p_lcb);
+ return(BTM_NO_RESOURCES);
+ }
+
+#if (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE)
+ btm_acl_update_busy_level (BTM_BLI_PAGE_EVT);
+#endif
+
+ BTM_TRACE_DEBUG6 ("Security Manager: btm_sec_dd_create_conn [%02x%02x%02x%02x%02x%02x]",
+ p_dev_rec->bd_addr[0], p_dev_rec->bd_addr[1], p_dev_rec->bd_addr[2],
+ p_dev_rec->bd_addr[3], p_dev_rec->bd_addr[4], p_dev_rec->bd_addr[5]);
+
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_PIN_REQ);
+
+ return(BTM_CMD_STARTED);
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_rmt_name_request_complete
+**
+** Description This function is called when remote name was obtained from
+** the peer device
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sec_rmt_name_request_complete (UINT8 *p_bd_addr, UINT8 *p_bd_name, UINT8 status)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ int i;
+ DEV_CLASS dev_class;
+ UINT8 old_sec_state;
+
+ BTM_TRACE_EVENT0 ("btm_sec_rmt_name_request_complete");
+ if (((p_bd_addr == NULL) && !BTM_ACL_IS_CONNECTED(btm_cb.connecting_bda))
+ || ((p_bd_addr != NULL) && !BTM_ACL_IS_CONNECTED(p_bd_addr)))
+ {
+ btm_acl_resubmit_page();
+ }
+
+ /* If remote name request failed, p_bd_addr is null and we need to search */
+ /* based on state assuming that we are doing 1 at a time */
+ if (p_bd_addr)
+ p_dev_rec = btm_find_dev (p_bd_addr);
+ else
+ {
+ p_dev_rec = &btm_cb.sec_dev_rec[0];
+
+ for (i = 0; i < BTM_SEC_MAX_DEVICE_RECORDS; i++, p_dev_rec++)
+ {
+ if ((p_dev_rec->sec_flags & BTM_SEC_IN_USE)
+ && (p_dev_rec->sec_state == BTM_SEC_STATE_GETTING_NAME))
+ {
+ p_bd_addr = p_dev_rec->bd_addr;
+ break;
+ }
+ }
+
+ if (i == BTM_SEC_MAX_DEVICE_RECORDS)
+ p_dev_rec = NULL;
+ }
+
+
+ /* Commenting out trace due to obf/compilation problems.
+ */
+#if (BT_USE_TRACES == TRUE)
+ if (!p_bd_name)
+ p_bd_name = (UINT8 *)"";
+
+ if (p_dev_rec)
+ {
+ BTM_TRACE_EVENT5 ("Security Manager: rmt_name_complete PairState: %s RemName: %s status: %d State:%d p_dev_rec: 0x%08x ",
+ btm_pair_state_descr (btm_cb.pairing_state), p_bd_name,
+ status, p_dev_rec->sec_state, p_dev_rec);
+ }
+ else
+ {
+ BTM_TRACE_EVENT3 ("Security Manager: rmt_name_complete PairState: %s RemName: %s status: %d",
+ btm_pair_state_descr (btm_cb.pairing_state), p_bd_name,
+ status);
+ }
+#endif
+
+ if (p_dev_rec)
+ {
+ old_sec_state = p_dev_rec->sec_state;
+ if (status == HCI_SUCCESS)
+ {
+ BCM_STRNCPY_S ((char *)p_dev_rec->sec_bd_name, sizeof (p_dev_rec->sec_bd_name), (char *)p_bd_name, BTM_MAX_REM_BD_NAME_LEN);
+ p_dev_rec->sec_flags |= BTM_SEC_NAME_KNOWN;
+ BTM_TRACE_EVENT1 ("setting BTM_SEC_NAME_KNOWN sec_flags:0x%x", p_dev_rec->sec_flags);
+ }
+ else
+ {
+ /* Notify all clients waiting for name to be resolved even if it failed so clients can continue */
+ p_dev_rec->sec_bd_name[0] = 0;
+ }
+
+ if (p_dev_rec->sec_state == BTM_SEC_STATE_GETTING_NAME)
+ p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+
+ /* Notify all clients waiting for name to be resolved */
+ for (i = 0;i < BTM_SEC_MAX_RMT_NAME_CALLBACKS; i++)
+ {
+ if (btm_cb.p_rmt_name_callback[i])
+ (*btm_cb.p_rmt_name_callback[i])(p_bd_addr, p_dev_rec->dev_class,
+ p_dev_rec->sec_bd_name);
+ }
+ }
+ else
+ {
+ dev_class[0] = 0;
+ dev_class[1] = 0;
+ dev_class[2] = 0;
+
+ /* Notify all clients waiting for name to be resolved even if not found so clients can continue */
+ for (i = 0;i < BTM_SEC_MAX_RMT_NAME_CALLBACKS; i++)
+ {
+ if (btm_cb.p_rmt_name_callback[i])
+ (*btm_cb.p_rmt_name_callback[i])(p_bd_addr, dev_class, (UINT8 *)"");
+ }
+
+ return;
+ }
+
+ /* If we were delaying asking UI for a PIN because name was not resolved, ask now */
+ if ( (btm_cb.pairing_state == BTM_PAIR_STATE_WAIT_LOCAL_PIN) && p_bd_addr
+ && (memcmp (btm_cb.pairing_bda, p_bd_addr, BD_ADDR_LEN) == 0) )
+ {
+ BTM_TRACE_EVENT2 ("btm_sec_rmt_name_request_complete() delayed pin now being requested flags:0x%x, (p_pin_callback=0x%p)", btm_cb.pairing_flags, btm_cb.api.p_pin_callback);
+
+ if (((btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) == 0) &&
+ ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_PIN_REQD) == 0) &&
+ btm_cb.api.p_pin_callback)
+ {
+ BTM_TRACE_EVENT0 ("btm_sec_rmt_name_request_complete() calling pin_callback");
+ btm_cb.pairing_flags |= BTM_PAIR_FLAGS_PIN_REQD;
+ (*btm_cb.api.p_pin_callback) (p_dev_rec->bd_addr, p_dev_rec->dev_class, p_bd_name);
+ }
+
+ /* Set the same state again to force the timer to be restarted */
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_LOCAL_PIN);
+ return;
+ }
+
+ /* Check if we were delaying bonding because name was not resolved */
+ if ( btm_cb.pairing_state == BTM_PAIR_STATE_GET_REM_NAME)
+ {
+ if (p_bd_addr && memcmp (btm_cb.pairing_bda, p_bd_addr, BD_ADDR_LEN) == 0)
+ {
+ BTM_TRACE_EVENT2 ("btm_sec_rmt_name_request_complete() continue bonding sm4: 0x%04x, status:0x%x", p_dev_rec->sm4, status);
+ if (status != HCI_SUCCESS)
+ {
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+
+ (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr, p_dev_rec->dev_class,
+ p_dev_rec->sec_bd_name, status);
+ return;
+ }
+
+ /* if peer is very old legacy devices, HCI_RMT_HOST_SUP_FEAT_NOTIFY_EVT is not reported */
+ if (BTM_SEC_IS_SM4_UNKNOWN(p_dev_rec->sm4))
+ {
+ /* set the KNOWN flag only if BTM_PAIR_FLAGS_REJECTED_CONNECT is not set.
+ * If it is set, there may be a race condition */
+ BTM_TRACE_EVENT1 ("btm_sec_rmt_name_request_complete IS_SM4_UNKNOWN Flags:0x%04x", btm_cb.pairing_flags);
+ if ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_REJECTED_CONNECT) == 0)
+ {
+ p_dev_rec->sm4 |= BTM_SM4_KNOWN;
+ }
+ }
+
+ /* BT 2.1 or carkit, bring up the connection to force the peer to request PIN.
+ ** Else prefetch (btm_sec_check_prefetch_pin will do the prefetching if needed)
+ */
+ if ((p_dev_rec->sm4 != BTM_SM4_KNOWN) || !btm_sec_check_prefetch_pin(p_dev_rec))
+ {
+ /* if we rejected incoming connection request, we have to wait HCI_Connection_Complete event */
+ /* before originating */
+ if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_REJECTED_CONNECT)
+ {
+ BTM_TRACE_WARNING0 ("btm_sec_rmt_name_request_complete: waiting HCI_Connection_Complete after rejecting connection");
+ }
+ /* Both we and the peer are 2.1 - continue to create connection */
+ else if (btm_sec_dd_create_conn(p_dev_rec) != BTM_CMD_STARTED)
+ {
+ BTM_TRACE_WARNING0 ("btm_sec_rmt_name_request_complete: failed to start connection");
+
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+
+ (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr, p_dev_rec->dev_class,
+ p_dev_rec->sec_bd_name, HCI_ERR_MEMORY_FULL);
+ }
+ }
+ return;
+ }
+ else
+ {
+ BTM_TRACE_WARNING0 ("btm_sec_rmt_name_request_complete: wrong BDA, retry with pairing BDA");
+
+ BTM_ReadRemoteDeviceName (btm_cb.pairing_bda, NULL);
+ return;
+ }
+ }
+
+ /* check if we were delaying link_key_callback because name was not resolved */
+ if (p_dev_rec->link_key_not_sent)
+ {
+ /* If HCI connection complete has not arrived, wait for it */
+ if (p_dev_rec->hci_handle == BTM_SEC_INVALID_HANDLE)
+ return;
+
+ p_dev_rec->link_key_not_sent = FALSE;
+ btm_send_link_key_notif(p_dev_rec);
+
+ /* If its not us who perform authentication, we should tell stackserver */
+ /* that some authentication has been completed */
+ /* This is required when different entities receive link notification and auth complete */
+ if (!(p_dev_rec->security_required & BTM_SEC_OUT_AUTHENTICATE))
+ {
+ if (btm_cb.api.p_auth_complete_callback)
+ (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr,
+ p_dev_rec->dev_class,
+ p_dev_rec->sec_bd_name, HCI_SUCCESS);
+
+ }
+ }
+
+ /* If this is a bonding procedure can disconnect the link now */
+ if ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD)
+ && (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED))
+ {
+ BTM_TRACE_WARNING0 ("btm_sec_rmt_name_request_complete (none/ce)");
+ p_dev_rec->security_required &= ~(BTM_SEC_OUT_AUTHENTICATE);
+ l2cu_start_post_bond_timer(p_dev_rec->hci_handle);
+ return;
+ }
+
+ if (old_sec_state != BTM_SEC_STATE_GETTING_NAME)
+ return;
+
+ /* If get name failed, notify the waiting layer */
+ if (status != HCI_SUCCESS)
+ {
+ btm_sec_dev_rec_cback_event (p_dev_rec, BTM_ERR_PROCESSING);
+ return;
+ }
+
+ if (p_dev_rec->sm4 & BTM_SM4_REQ_PEND)
+ {
+ BTM_TRACE_EVENT0 ("waiting for remote features!!");
+ return;
+ }
+
+ /* Remote Name succeeded, execute the next security procedure, if any */
+ status = (UINT8)btm_sec_execute_procedure (p_dev_rec);
+
+ /* If result is pending reply from the user or from the device is pending */
+ if (status == BTM_CMD_STARTED)
+ return;
+
+ /* There is no next procedure or start of procedure failed, notify the waiting layer */
+ btm_sec_dev_rec_cback_event (p_dev_rec, status);
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_rmt_host_support_feat_evt
+**
+** Description This function is called when the
+** HCI_RMT_HOST_SUP_FEAT_NOTIFY_EVT is received
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sec_rmt_host_support_feat_evt (UINT8 *p)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ BD_ADDR bd_addr; /* peer address */
+ BD_FEATURES features;
+
+ STREAM_TO_BDADDR (bd_addr, p);
+ p_dev_rec = btm_find_or_alloc_dev (bd_addr);
+
+ BTM_TRACE_EVENT2 ("btm_sec_rmt_host_support_feat_evt sm4: 0x%x p[0]: 0x%x", p_dev_rec->sm4, p[0]);
+
+ if (BTM_SEC_IS_SM4_UNKNOWN(p_dev_rec->sm4))
+ {
+ p_dev_rec->sm4 = BTM_SM4_KNOWN;
+ STREAM_TO_ARRAY(features, p, BD_FEATURES_LEN);
+ if (HCI_SSP_HOST_SUPPORTED(features))
+ {
+ p_dev_rec->sm4 = BTM_SM4_TRUE;
+ }
+ BTM_TRACE_EVENT2 ("btm_sec_rmt_host_support_feat_evt sm4: 0x%x features[0]: 0x%x", p_dev_rec->sm4, features[0]);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_io_capabilities_req
+**
+** Description This function is called when LM request for the IO
+** capability of the local device and
+** if the OOB data is present for the device in the event
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_io_capabilities_req (UINT8 *p)
+{
+ tBTM_SP_IO_REQ evt_data;
+ UINT8 err_code = 0;
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ BOOLEAN is_orig = TRUE;
+ UINT8 callback_rc = BTM_SUCCESS;
+
+ STREAM_TO_BDADDR (evt_data.bd_addr, p);
+
+ /* setup the default response according to compile options */
+ /* assume that the local IO capability does not change
+ * loc_io_caps is initialized with the default value */
+ evt_data.io_cap = btm_cb.devcb.loc_io_caps;
+ evt_data.oob_data = BTM_OOB_NONE;
+ evt_data.auth_req = BTM_DEFAULT_AUTH_REQ;
+
+ BTM_TRACE_EVENT1 ("btm_io_capabilities_req() State: %s", btm_pair_state_descr(btm_cb.pairing_state));
+
+ p_dev_rec = btm_find_or_alloc_dev (evt_data.bd_addr);
+ p_dev_rec->sm4 |= BTM_SM4_TRUE;
+
+ BTM_TRACE_EVENT3 ("btm_io_capabilities_req() State: %s Flags: 0x%04x p_cur_service: 0x%08x",
+ btm_pair_state_descr(btm_cb.pairing_state), btm_cb.pairing_flags, p_dev_rec->p_cur_service);
+
+ if (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)
+ {
+ if (btm_cb.pairing_state == BTM_PAIR_STATE_INCOMING_SSP)
+ {
+ /* received IO capability response already-> not the originator of SSP */
+ is_orig = FALSE;
+
+ if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_PEER_STARTED_DD)
+ evt_data.auth_req = BTM_DEFAULT_DD_AUTH_REQ;
+ }
+ /* security is already in progress */
+ else if (btm_cb.pairing_state == BTM_PAIR_STATE_WAIT_PIN_REQ)
+ {
+/* coverity[uninit_use_in_call]
+Event uninit_use_in_call: Using uninitialized element of array "evt_data.bd_addr" in call to function "memcmp"
+False-positive: evt_data.bd_addr is set at the beginning with: STREAM_TO_BDADDR (evt_data.bd_addr, p);
+*/
+ if (memcmp (evt_data.bd_addr, btm_cb.pairing_bda, BD_ADDR_LEN))
+ {
+ /* and it's not the device in bonding -> reject it */
+ err_code = HCI_ERR_HOST_BUSY_PAIRING;
+ }
+ else
+ {
+ /* local device initiated dedicated bonding */
+ evt_data.auth_req = BTM_DEFAULT_DD_AUTH_REQ;
+ }
+ }
+ else
+ {
+ err_code = HCI_ERR_HOST_BUSY_PAIRING;
+ }
+ }
+
+ /* paring is not allowed */
+ if (btm_cb.pairing_disabled)
+ err_code = HCI_ERR_PAIRING_NOT_ALLOWED;
+
+ if (err_code != 0)
+ {
+/* coverity[uninit_use_in_call]
+Event uninit_use_in_call: Using uninitialized element of array "evt_data.bd_addr" in call to function "memcmp"
+False-positive: evt_data.bd_addr is set at the beginning with: STREAM_TO_BDADDR (evt_data.bd_addr, p);
+*/
+ btsnd_hcic_io_cap_req_neg_reply(evt_data.bd_addr, err_code);
+ return;
+ }
+
+ evt_data.is_orig = is_orig;
+
+ if (is_orig)
+ {
+ /* local device initiated the pairing non-bonding -> use p_cur_service */
+ if (!(btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) &&
+ p_dev_rec->p_cur_service &&
+ (p_dev_rec->p_cur_service->security_flags & BTM_SEC_OUT_AUTHENTICATE))
+ {
+ evt_data.auth_req = (p_dev_rec->p_cur_service->security_flags & BTM_SEC_OUT_MITM) ? BTM_AUTH_SP_YES : BTM_AUTH_SP_NO;
+ }
+ }
+
+ /* Notify L2CAP to increase timeout */
+ l2c_pin_code_request (evt_data.bd_addr);
+
+ memcpy (btm_cb.pairing_bda, evt_data.bd_addr, BD_ADDR_LEN);
+
+/* coverity[uninit_use_in_call]
+Event uninit_use_in_call: Using uninitialized element of array "evt_data.bd_addr" in call to function "memcmp"
+False-positive: False-positive: evt_data.bd_addr is set at the beginning with: STREAM_TO_BDADDR (evt_data.bd_addr, p);
+*/
+ if (!memcmp (evt_data.bd_addr, btm_cb.connecting_bda, BD_ADDR_LEN))
+ memcpy (p_dev_rec->dev_class, btm_cb.connecting_dc, DEV_CLASS_LEN);
+
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_LOCAL_IOCAPS);
+
+ callback_rc = BTM_SUCCESS;
+ if (p_dev_rec->sm4 & BTM_SM4_UPGRADE)
+ {
+ p_dev_rec->sm4 &= ~BTM_SM4_UPGRADE;
+
+ /* link key upgrade: always use SPGB_YES - assuming we want to save the link key */
+ evt_data.auth_req = BTM_AUTH_SPGB_YES;
+ }
+ else if (btm_cb.api.p_sp_callback)
+ {
+ /* the callback function implementation may change the IO capability... */
+ callback_rc = (*btm_cb.api.p_sp_callback) (BTM_SP_IO_REQ_EVT, (tBTM_SP_EVT_DATA *)&evt_data);
+ }
+
+#if BTM_OOB_INCLUDED == TRUE
+ if ((callback_rc == BTM_SUCCESS) || (BTM_OOB_UNKNOWN != evt_data.oob_data))
+#else
+ if (callback_rc == BTM_SUCCESS)
+#endif
+ {
+ if ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD))
+ {
+ evt_data.auth_req = (BTM_AUTH_DD_BOND | (evt_data.auth_req & BTM_AUTH_YN_BIT));
+ }
+
+ /* if the user does not indicate "reply later" by setting the oob_data to unknown
+ * send the response right now. Save the current IO capability in the control block */
+ btm_cb.devcb.loc_auth_req = evt_data.auth_req;
+ btm_cb.devcb.loc_io_caps = evt_data.io_cap;
+
+ BTM_TRACE_EVENT4 ("btm_io_capabilities_req: State: %s IO_CAP:%d oob_data:%d auth_req:%d",
+ btm_pair_state_descr(btm_cb.pairing_state), evt_data.io_cap,
+ evt_data.oob_data, evt_data.auth_req);
+
+ btsnd_hcic_io_cap_req_reply(evt_data.bd_addr, evt_data.io_cap,
+ evt_data.oob_data, evt_data.auth_req);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_io_capabilities_rsp
+**
+** Description This function is called when the IO capability of the
+** specified device is received
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_io_capabilities_rsp (UINT8 *p)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ tBTM_SP_IO_RSP evt_data;
+
+ STREAM_TO_BDADDR (evt_data.bd_addr, p);
+ STREAM_TO_UINT8 (evt_data.io_cap, p);
+ STREAM_TO_UINT8 (evt_data.oob_data, p);
+ STREAM_TO_UINT8 (evt_data.auth_req, p);
+
+ /* Allocate a new device record or reuse the oldest one */
+ p_dev_rec = btm_find_or_alloc_dev (evt_data.bd_addr);
+
+ /* If no security is in progress, this indicates incoming security */
+ if (btm_cb.pairing_state == BTM_PAIR_STATE_IDLE)
+ {
+ memcpy (btm_cb.pairing_bda, evt_data.bd_addr, BD_ADDR_LEN);
+
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_INCOMING_SSP);
+
+ /* Make sure we reset the trusted mask to help against attacks */
+ BTM_SEC_CLR_TRUSTED_DEVICE(p_dev_rec->trusted_mask);
+
+ /* work around for FW bug */
+ btm_inq_stop_on_ssp();
+ }
+
+ /* Notify L2CAP to increase timeout */
+ l2c_pin_code_request (evt_data.bd_addr);
+
+ /* We must have a device record here.
+ * Use the connecting device's CoD for the connection */
+/* coverity[uninit_use_in_call]
+Event uninit_use_in_call: Using uninitialized element of array "evt_data.bd_addr" in call to function "memcmp"
+FALSE-POSITIVE error from Coverity test-tool. evt_data.bd_addr is set at the beginning with: STREAM_TO_BDADDR (evt_data.bd_addr, p);
+*/
+ if (!memcmp (evt_data.bd_addr, btm_cb.connecting_bda, BD_ADDR_LEN))
+ memcpy (p_dev_rec->dev_class, btm_cb.connecting_dc, DEV_CLASS_LEN);
+
+ /* peer sets dedicated bonding bit and we did not initiate dedicated bonding */
+ if (btm_cb.pairing_state == BTM_PAIR_STATE_INCOMING_SSP /* peer initiated bonding */
+ && (evt_data.auth_req & BTM_AUTH_DD_BOND) ) /* and dedicated bonding bit is set */
+ {
+ btm_cb.pairing_flags |= BTM_PAIR_FLAGS_PEER_STARTED_DD;
+ }
+
+ /* save the IO capability in the device record */
+ p_dev_rec->rmt_io_caps = evt_data.io_cap;
+ p_dev_rec->rmt_auth_req = evt_data.auth_req;
+
+ if (btm_cb.api.p_sp_callback)
+ (*btm_cb.api.p_sp_callback) (BTM_SP_IO_RSP_EVT, (tBTM_SP_EVT_DATA *)&evt_data);
+}
+
+/*******************************************************************************
+**
+** Function btm_proc_sp_req_evt
+**
+** Description This function is called to process/report
+** HCI_USER_CONFIRMATION_REQUEST_EVT
+** or HCI_USER_PASSKEY_REQUEST_EVT
+** or HCI_USER_PASSKEY_NOTIFY_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_proc_sp_req_evt (tBTM_SP_EVT event, UINT8 *p)
+{
+ tBTM_STATUS status = BTM_ERR_PROCESSING;
+ tBTM_SP_EVT_DATA evt_data;
+ UINT8 *p_bda = evt_data.cfm_req.bd_addr;
+ tBTM_SEC_DEV_REC *p_dev_rec;
+
+ /* All events start with bd_addr */
+ STREAM_TO_BDADDR (p_bda, p);
+
+ BTM_TRACE_EVENT4 ("btm_proc_sp_req_evt() BDA: %08x%04x event: 0x%x, State: %s",
+ (p_bda[0]<<24) + (p_bda[1]<<16) + (p_bda[2]<<8) + p_bda[3], (p_bda[4] << 8) + p_bda[5],
+ event, btm_pair_state_descr(btm_cb.pairing_state));
+
+ if ( ((p_dev_rec = btm_find_dev (p_bda)) != NULL)
+ && (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)
+ && (memcmp (btm_cb.pairing_bda, p_bda, BD_ADDR_LEN) == 0) )
+ {
+ memcpy (evt_data.cfm_req.bd_addr, p_dev_rec->bd_addr, BD_ADDR_LEN);
+ memcpy (evt_data.cfm_req.dev_class, p_dev_rec->dev_class, DEV_CLASS_LEN);
+
+ BCM_STRNCPY_S ((char *)evt_data.cfm_req.bd_name, sizeof(evt_data.cfm_req.bd_name), (char *)p_dev_rec->sec_bd_name, BTM_MAX_REM_BD_NAME_LEN);
+
+ switch (event)
+ {
+ case BTM_SP_CFM_REQ_EVT:
+ /* Numeric confirmation. Need user to conf the passkey */
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_NUMERIC_CONFIRM);
+
+ /* The device record must be allocated in the "IO cap exchange" step */
+ STREAM_TO_UINT32 (evt_data.cfm_req.num_val, p);
+
+ evt_data.cfm_req.just_works = TRUE;
+
+ /* process user confirm req in association with the auth_req param */
+#if (BTM_LOCAL_IO_CAPS == BTM_IO_CAP_IO)
+ if ( (p_dev_rec->rmt_io_caps == BTM_IO_CAP_IO)
+ && (btm_cb.devcb.loc_io_caps == BTM_IO_CAP_IO)
+ && ((p_dev_rec->rmt_auth_req & BTM_AUTH_SP_YES) || (btm_cb.devcb.loc_auth_req & BTM_AUTH_SP_YES)) )
+ {
+ /* Both devices are DisplayYesNo and one or both devices want to authenticate
+ -> use authenticated link key */
+ evt_data.cfm_req.just_works = FALSE;
+ }
+#endif
+ BTM_TRACE_DEBUG5 ("btm_proc_sp_req_evt() just_works:%d, io loc:%d, rmt:%d, auth loc:%d, rmt:%d",
+ evt_data.cfm_req.just_works, btm_cb.devcb.loc_io_caps, p_dev_rec->rmt_io_caps,
+ btm_cb.devcb.loc_auth_req, p_dev_rec->rmt_auth_req);
+
+ evt_data.cfm_req.loc_auth_req = btm_cb.devcb.loc_auth_req;
+ evt_data.cfm_req.rmt_auth_req = p_dev_rec->rmt_auth_req;
+ break;
+
+ case BTM_SP_KEY_NOTIF_EVT:
+ /* Passkey notification (other side is a keyboard) */
+ STREAM_TO_UINT32 (evt_data.key_notif.passkey, p);
+
+ BTM_TRACE_DEBUG1 ("BTM_SP_KEY_NOTIF_EVT: passkey: %u", evt_data.key_notif.passkey);
+
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_AUTH_COMPLETE);
+ break;
+
+#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
+ case BTM_SP_KEY_REQ_EVT:
+ /* HCI_USER_PASSKEY_REQUEST_EVT */
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_KEY_ENTRY);
+ break;
+#endif
+ }
+
+ if (btm_cb.api.p_sp_callback)
+ {
+ status = (*btm_cb.api.p_sp_callback) (event, (tBTM_SP_EVT_DATA *)&evt_data);
+ if (status != BTM_NOT_AUTHORIZED)
+ {
+ return;
+ }
+ /* else BTM_NOT_AUTHORIZED means when the app wants to reject the req right now */
+ }
+ else if ( (event == BTM_SP_CFM_REQ_EVT) && (evt_data.cfm_req.just_works == TRUE) )
+ {
+ /* automatically reply with just works if no sp_cback */
+ status = BTM_SUCCESS;
+ }
+
+ if (event == BTM_SP_CFM_REQ_EVT)
+ {
+ BTM_TRACE_DEBUG1 ("calling BTM_ConfirmReqReply with status: %d", status);
+ BTM_ConfirmReqReply (status, p_bda);
+ }
+#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
+ else if (event == BTM_SP_KEY_REQ_EVT)
+ {
+ BTM_PasskeyReqReply(status, p_bda, 0);
+ }
+#endif
+ return;
+ }
+
+ /* Something bad. we can only fail this connection */
+ btm_cb.acl_disc_reason = HCI_ERR_HOST_REJECT_SECURITY;
+
+ if (BTM_SP_CFM_REQ_EVT == event)
+ {
+ btsnd_hcic_user_conf_reply (p_bda, FALSE);
+ }
+ else if (BTM_SP_KEY_NOTIF_EVT == event)
+ {
+ /* do nothing -> it very unlikely to happen.
+ This event is most likely to be received by a HID host when it first connects to a HID device.
+ Usually the Host initiated the connection in this case.
+ On Mobile platforms, if there's a security process happening,
+ the host probably can not initiate another connection.
+ BTW (PC) is another story. */
+ if (NULL != (p_dev_rec = btm_find_dev (p_bda)) )
+ {
+ btm_sec_disconnect (p_dev_rec->hci_handle, HCI_ERR_AUTH_FAILURE);
+ }
+ }
+#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
+ else
+ {
+ btsnd_hcic_user_passkey_neg_reply(p_bda);
+ }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function btm_keypress_notif_evt
+**
+** Description This function is called when a key press notification is
+** received
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_keypress_notif_evt (UINT8 *p)
+{
+ tBTM_SP_KEYPRESS evt_data;
+ UINT8 *p_bda;
+
+ /* parse & report BTM_SP_KEYPRESS_EVT */
+ if (btm_cb.api.p_sp_callback)
+ {
+ p_bda = evt_data.bd_addr;
+
+ STREAM_TO_BDADDR (p_bda, p);
+ evt_data.notif_type = *p;
+
+ (*btm_cb.api.p_sp_callback) (BTM_SP_KEYPRESS_EVT, (tBTM_SP_EVT_DATA *)&evt_data);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_simple_pair_complete
+**
+** Description This function is called when simple pairing process is
+** complete
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_simple_pair_complete (UINT8 *p)
+{
+ tBTM_SP_COMPLT evt_data;
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ UINT8 status;
+ BOOLEAN disc = FALSE;
+
+ status = *p++;
+ STREAM_TO_BDADDR (evt_data.bd_addr, p);
+
+ if ((p_dev_rec = btm_find_dev (evt_data.bd_addr)) == NULL)
+ {
+ BTM_TRACE_ERROR2 ("btm_simple_pair_complete() with unknown BDA: %08x%04x",
+ (evt_data.bd_addr[0]<<24) + (evt_data.bd_addr[1]<<16) + (evt_data.bd_addr[2]<<8) + evt_data.bd_addr[3],
+ (evt_data.bd_addr[4] << 8) + evt_data.bd_addr[5]);
+ return;
+ }
+
+ BTM_TRACE_EVENT3 ("btm_simple_pair_complete() Pair State: %s Status:%d sec_state: %u",
+ btm_pair_state_descr(btm_cb.pairing_state), status, p_dev_rec->sec_state);
+
+ evt_data.status = BTM_ERR_PROCESSING;
+ if (status == HCI_SUCCESS)
+ {
+ evt_data.status = BTM_SUCCESS;
+ p_dev_rec->sec_flags |= BTM_SEC_AUTHENTICATED;
+ }
+ else
+ {
+ if (status == HCI_ERR_PAIRING_NOT_ALLOWED)
+ {
+ /* The test spec wants the peer device to get this failure code. */
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_DISCONNECT);
+
+ /* Change the timer to 1 second */
+ btu_start_timer (&btm_cb.pairing_tle, BTU_TTYPE_USER_FUNC, BT_1SEC_TIMEOUT);
+ }
+ else if (memcmp (btm_cb.pairing_bda, evt_data.bd_addr, BD_ADDR_LEN) == 0)
+ {
+ /* stop the timer */
+ btu_stop_timer (&btm_cb.pairing_tle);
+
+ if (p_dev_rec->sec_state != BTM_SEC_STATE_AUTHENTICATING)
+ {
+ /* the initiating side: will receive auth complete event. disconnect ACL at that time */
+ disc = TRUE;
+ }
+ }
+ else
+ disc = TRUE;
+ }
+
+ /* Let the pairing state stay active, p_auth_complete_callback will report the failure */
+ memcpy (evt_data.bd_addr, p_dev_rec->bd_addr, BD_ADDR_LEN);
+ memcpy (evt_data.dev_class, p_dev_rec->dev_class, DEV_CLASS_LEN);
+
+ if (btm_cb.api.p_sp_callback)
+ (*btm_cb.api.p_sp_callback) (BTM_SP_COMPLT_EVT, (tBTM_SP_EVT_DATA *)&evt_data);
+
+ if (disc)
+ {
+ /* simple pairing failed */
+ btm_sec_send_hci_disconnect (p_dev_rec, HCI_ERR_AUTH_FAILURE);
+ }
+}
+
+#if BTM_OOB_INCLUDED == TRUE
+/*******************************************************************************
+**
+** Function btm_rem_oob_req
+**
+** Description This function is called to process/report
+** HCI_REMOTE_OOB_DATA_REQUEST_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_rem_oob_req (UINT8 *p)
+{
+ UINT8 *p_bda;
+ tBTM_SP_RMT_OOB evt_data;
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ BT_OCTET16 c;
+ BT_OCTET16 r;
+
+ p_bda = evt_data.bd_addr;
+
+ STREAM_TO_BDADDR (p_bda, p);
+
+ BTM_TRACE_EVENT6 ("btm_rem_oob_req() BDA: %02x:%02x:%02x:%02x:%02x:%02x",
+ p_bda[0], p_bda[1], p_bda[2], p_bda[3], p_bda[4], p_bda[5]);
+
+ if ( (NULL != (p_dev_rec = btm_find_dev (p_bda))) &&
+ btm_cb.api.p_sp_callback)
+ {
+ memcpy (evt_data.bd_addr, p_dev_rec->bd_addr, BD_ADDR_LEN);
+ memcpy (evt_data.dev_class, p_dev_rec->dev_class, DEV_CLASS_LEN);
+ BCM_STRNCPY_S((char *)evt_data.bd_name, sizeof(evt_data.bd_name), (char *)p_dev_rec->sec_bd_name, BTM_MAX_REM_BD_NAME_LEN+1);
+
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_LOCAL_OOB_RSP);
+ if ((*btm_cb.api.p_sp_callback) (BTM_SP_RMT_OOB_EVT, (tBTM_SP_EVT_DATA *)&evt_data) == BTM_NOT_AUTHORIZED)
+ {
+ BTM_RemoteOobDataReply(TRUE, p_bda, c, r);
+ }
+ return;
+ }
+
+ /* something bad. we can only fail this connection */
+ btm_cb.acl_disc_reason = HCI_ERR_HOST_REJECT_SECURITY;
+ btsnd_hcic_rem_oob_neg_reply (p_bda);
+}
+
+/*******************************************************************************
+**
+** Function btm_read_local_oob_complete
+**
+** Description This function is called when read local oob data is
+** completed by the LM
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_read_local_oob_complete (UINT8 *p)
+{
+ tBTM_SP_LOC_OOB evt_data;
+ UINT8 status = *p++;
+
+ BTM_TRACE_EVENT1 ("btm_read_local_oob_complete:%d", status);
+ if (status == HCI_SUCCESS)
+ {
+ evt_data.status = BTM_SUCCESS;
+ STREAM_TO_ARRAY16(evt_data.c, p);
+ STREAM_TO_ARRAY16(evt_data.r, p);
+ }
+ else
+ evt_data.status = BTM_ERR_PROCESSING;
+
+ if (btm_cb.api.p_sp_callback)
+ (*btm_cb.api.p_sp_callback) (BTM_SP_LOC_OOB_EVT, (tBTM_SP_EVT_DATA *)&evt_data);
+}
+#endif /* BTM_OOB_INCLUDED */
+
+/*******************************************************************************
+**
+** Function btm_sec_auth_collision
+**
+** Description This function is called when authentication or encryption
+** needs to be retried at a later time.
+**
+** Returns void
+**
+*******************************************************************************/
+static void btm_sec_auth_collision (UINT16 handle)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+
+ if (!btm_cb.collision_start_time)
+ btm_cb.collision_start_time = GKI_get_tick_count ();
+
+ if ((GKI_get_tick_count () - btm_cb.collision_start_time) < btm_cb.max_collision_delay)
+ {
+ if (handle == BTM_SEC_INVALID_HANDLE)
+ {
+ if ((p_dev_rec = btm_sec_find_dev_by_sec_state (BTM_SEC_STATE_AUTHENTICATING)) == NULL)
+ p_dev_rec = btm_sec_find_dev_by_sec_state (BTM_SEC_STATE_ENCRYPTING);
+ }
+ else
+ p_dev_rec = btm_find_dev_by_handle (handle);
+
+ if (p_dev_rec != NULL)
+ {
+ BTM_TRACE_DEBUG1 ("btm_sec_auth_collision: state %d (retrying in a moment...)", p_dev_rec->sec_state);
+ /* We will restart authentication after timeout */
+ if (p_dev_rec->sec_state == BTM_SEC_STATE_AUTHENTICATING || p_dev_rec->sec_state == BTM_SEC_STATE_ENCRYPTING)
+ p_dev_rec->sec_state = 0;
+
+ btm_cb.p_collided_dev_rec = p_dev_rec;
+ btm_cb.sec_collision_tle.param = (UINT32) btm_sec_collision_timeout;
+ btu_start_timer (&btm_cb.sec_collision_tle, BTU_TTYPE_USER_FUNC, BT_1SEC_TIMEOUT);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_auth_complete
+**
+** Description This function is when authentication of the connection is
+** completed by the LM
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sec_auth_complete (UINT16 handle, UINT8 status)
+{
+ UINT8 old_sm4;
+ tBTM_PAIRING_STATE old_state = btm_cb.pairing_state;
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev_by_handle (handle);
+ BOOLEAN are_bonding = FALSE;
+
+ /* Commenting out trace due to obf/compilation problems.
+ */
+#if (BT_USE_TRACES == TRUE)
+ if (p_dev_rec)
+ {
+ BTM_TRACE_EVENT6 ("Security Manager: auth_complete PairState: %s handle:%u status:%d dev->sec_state: %u Bda:%08x, RName:%s",
+ btm_pair_state_descr (btm_cb.pairing_state),
+ handle, status,
+ p_dev_rec->sec_state,
+ (p_dev_rec->bd_addr[2]<<24)+(p_dev_rec->bd_addr[3]<<16)+(p_dev_rec->bd_addr[4]<<8)+p_dev_rec->bd_addr[5],
+ p_dev_rec->sec_bd_name);
+ }
+ else
+ {
+ BTM_TRACE_EVENT3 ("Security Manager: auth_complete PairState: %s handle:%u status:%d",
+ btm_pair_state_descr (btm_cb.pairing_state),
+ handle, status);
+ }
+#endif
+
+ /* For transaction collision we need to wait and repeat. There is no need */
+ /* for random timeout because only slave should receive the result */
+ if ((status == HCI_ERR_LMP_ERR_TRANS_COLLISION) || (status == HCI_ERR_DIFF_TRANSACTION_COLLISION))
+ {
+ btm_sec_auth_collision(handle);
+ return;
+ }
+ btm_cb.collision_start_time = 0;
+
+ btm_restore_mode();
+
+ /* Check if connection was made just to do bonding. If we authenticate
+ the connection that is up, this is the last event received.
+ */
+ if (p_dev_rec
+ && (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD)
+ && !(btm_cb.pairing_flags & BTM_PAIR_FLAGS_DISC_WHEN_DONE))
+ {
+ p_dev_rec->security_required &= ~BTM_SEC_OUT_AUTHENTICATE;
+
+ l2cu_start_post_bond_timer (p_dev_rec->hci_handle);
+ }
+
+ if (!p_dev_rec)
+ return;
+
+ /* keep the old sm4 flag and clear the retry bit in control block */
+ old_sm4 = p_dev_rec->sm4;
+ p_dev_rec->sm4 &= ~BTM_SM4_RETRY;
+
+ if ( (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)
+ && (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD)
+ && (memcmp (p_dev_rec->bd_addr, btm_cb.pairing_bda, BD_ADDR_LEN) == 0) )
+ are_bonding = TRUE;
+
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+
+ if (p_dev_rec->sec_state != BTM_SEC_STATE_AUTHENTICATING)
+ {
+ if ( (btm_cb.api.p_auth_complete_callback && status != HCI_SUCCESS)
+ && (old_state != BTM_PAIR_STATE_IDLE) )
+ {
+ (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr,
+ p_dev_rec->dev_class,
+ p_dev_rec->sec_bd_name, status);
+ }
+ return;
+ }
+
+ /* There can be a race condition, when we are starting authentication and
+ ** the peer device is doing encryption.
+ ** If first we receive encryption change up, then initiated authentication
+ ** can not be performed. According to the spec we can not do authentication
+ ** on the encrypted link, so device is correct.
+ */
+ if ((status == HCI_ERR_COMMAND_DISALLOWED)
+ && ((p_dev_rec->sec_flags & (BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED)) ==
+ (BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED)))
+ {
+ status = HCI_SUCCESS;
+ }
+ /* Currently we do not notify user if it is a keyboard which connects */
+ /* User probably Disabled the keyboard while it was asleap. Let her try */
+ if (btm_cb.api.p_auth_complete_callback)
+ {
+ /* report the suthentication status */
+ if (old_state != BTM_PAIR_STATE_IDLE)
+ (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr,
+ p_dev_rec->dev_class,
+ p_dev_rec->sec_bd_name, status);
+ }
+
+ p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+
+ /* If this is a bonding procedure can disconnect the link now */
+ if (are_bonding)
+ {
+ p_dev_rec->security_required &= ~BTM_SEC_OUT_AUTHENTICATE;
+
+ if (status != HCI_SUCCESS)
+ btm_sec_send_hci_disconnect (p_dev_rec, HCI_ERR_PEER_USER);
+ else
+ l2cu_start_post_bond_timer (p_dev_rec->hci_handle);
+
+ return;
+ }
+
+ /* If authentication failed, notify the waiting layer */
+ if (status != HCI_SUCCESS)
+ {
+ if ((old_sm4 & BTM_SM4_RETRY) == 0)
+ {
+ /* allow retry only once */
+ if (status == HCI_ERR_LMP_ERR_TRANS_COLLISION)
+ {
+ /* not retried yet. set the retry bit */
+ p_dev_rec->sm4 |= BTM_SM4_RETRY;
+ BTM_TRACE_DEBUG2 ("Collision retry sm4:x%x sec_flags:0x%x", p_dev_rec->sm4, p_dev_rec->sec_flags);
+ }
+ /* this retry for missing key is for Lisbon or later only.
+ * Legacy device do not need this. the controller will drive the retry automatically */
+ else if (HCI_ERR_KEY_MISSING == status && BTM_SEC_IS_SM4(p_dev_rec->sm4))
+ {
+ /* not retried yet. set the retry bit */
+ p_dev_rec->sm4 |= BTM_SM4_RETRY;
+ p_dev_rec->sec_flags &= ~BTM_SEC_LINK_KEY_KNOWN;
+ BTM_TRACE_DEBUG2 ("Retry for missing key sm4:x%x sec_flags:0x%x", p_dev_rec->sm4, p_dev_rec->sec_flags);
+
+ /* With BRCM controller, we do not need to delete the stored link key in controller.
+ If the stack may sit on top of other controller, we may need this
+ BTM_DeleteStoredLinkKey (bd_addr, NULL); */
+ }
+
+ if (p_dev_rec->sm4 & BTM_SM4_RETRY)
+ {
+ btm_sec_execute_procedure (p_dev_rec);
+ return;
+ }
+ }
+
+ btm_sec_dev_rec_cback_event (p_dev_rec, BTM_ERR_PROCESSING);
+
+ if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_DISC_WHEN_DONE)
+ {
+ btm_sec_send_hci_disconnect (p_dev_rec, HCI_ERR_AUTH_FAILURE);
+ }
+ return;
+ }
+
+ p_dev_rec->sec_flags |= BTM_SEC_AUTHENTICATED;
+
+ /* Authentication succeeded, execute the next security procedure, if any */
+ status = btm_sec_execute_procedure (p_dev_rec);
+
+ /* If there is no next procedure, or procedure failed to start, notify the caller */
+ if (status != BTM_CMD_STARTED)
+ btm_sec_dev_rec_cback_event (p_dev_rec, status);
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_mkey_comp_event
+**
+** Description This function is when encryption of the connection is
+** completed by the LM
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sec_mkey_comp_event (UINT16 handle, UINT8 status, UINT8 key_flg)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev_by_handle (handle);
+ UINT8 bd_addr[BD_ADDR_LEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} ;
+
+ BTM_TRACE_EVENT2 ("Security Manager: mkey comp status:%d State:%d",
+ status, (p_dev_rec) ? p_dev_rec->sec_state : 0);
+
+ /* If encryption setup failed, notify the waiting layer */
+ /* There is no next procedure or start of procedure failed, notify the waiting layer */
+ if (btm_cb.mkey_cback)
+ {
+ if (!p_dev_rec)
+ (btm_cb.mkey_cback)(bd_addr, status, key_flg );
+ else
+ (btm_cb.mkey_cback)(p_dev_rec->bd_addr, status, key_flg );
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_encrypt_change
+**
+** Description This function is when encryption of the connection is
+** completed by the LM
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sec_encrypt_change (UINT16 handle, UINT8 status, UINT8 encr_enable)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev_by_handle (handle);
+
+ BTM_TRACE_EVENT3 ("Security Manager: encrypt_change status:%d State:%d, encr_enable = %d",
+ status, (p_dev_rec) ? p_dev_rec->sec_state : 0, encr_enable);
+ BTM_TRACE_DEBUG1 ("before update p_dev_rec->sec_flags=0x%x", p_dev_rec->sec_flags );
+
+ /* For transaction collision we need to wait and repeat. There is no need */
+ /* for random timeout because only slave should receive the result */
+ if ((status == HCI_ERR_LMP_ERR_TRANS_COLLISION) || (status == HCI_ERR_DIFF_TRANSACTION_COLLISION))
+ {
+ btm_sec_auth_collision(handle);
+ return;
+ }
+ btm_cb.collision_start_time = 0;
+
+ if (!p_dev_rec)
+ return;
+
+ if ((status == HCI_SUCCESS) && encr_enable)
+ p_dev_rec->sec_flags |= (BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED);
+
+ /* It is possible that we decrypted the link to perform role switch */
+ /* mark link not to be encrypted, so that when we execute security next time it will kick in again */
+ if ((status == HCI_SUCCESS) && !encr_enable)
+ p_dev_rec->sec_flags &= ~BTM_SEC_ENCRYPTED;
+
+ BTM_TRACE_DEBUG1 ("after update p_dev_rec->sec_flags=0x%x", p_dev_rec->sec_flags );
+#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE
+ if (p_dev_rec->device_type == BT_DEVICE_TYPE_BLE)
+ {
+ btm_ble_link_encrypted(p_dev_rec->bd_addr, encr_enable);
+ return;
+ }
+ else
+ /* BR/EDR connection, update the encryption key size to be 16 as always */
+ p_dev_rec->enc_key_size = 16;
+#endif
+
+ /* If this encryption was started by peer do not need to do anything */
+ if (p_dev_rec->sec_state != BTM_SEC_STATE_ENCRYPTING)
+ {
+ if (BTM_SEC_STATE_DELAY_FOR_ENC == p_dev_rec->sec_state)
+ {
+ p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+ p_dev_rec->p_callback = NULL;
+ l2cu_resubmit_pending_sec_req (p_dev_rec->bd_addr);
+ }
+ return;
+ }
+
+ p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+
+ /* If encryption setup failed, notify the waiting layer */
+ if (status != HCI_SUCCESS)
+ {
+ btm_sec_dev_rec_cback_event (p_dev_rec, BTM_ERR_PROCESSING);
+ return;
+ }
+
+ /* Encryption setup succeeded, execute the next security procedure, if any */
+ status = (UINT8)btm_sec_execute_procedure (p_dev_rec);
+
+ /* If there is no next procedure, or procedure failed to start, notify the caller */
+ if (status != BTM_CMD_STARTED)
+ btm_sec_dev_rec_cback_event (p_dev_rec, status);
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_create_conn
+**
+** Description This function records current role and forwards request to
+** HCI
+**
+** Returns void
+**
+*******************************************************************************/
+BOOLEAN btm_sec_create_conn (BD_ADDR bda, UINT16 packet_types,
+ UINT8 page_scan_rep_mode, UINT8 page_scan_mode,
+ UINT16 clock_offset, UINT8 allow_switch)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_or_alloc_dev (bda);
+
+ memcpy (btm_cb.connecting_bda, p_dev_rec->bd_addr, BD_ADDR_LEN);
+ memcpy (btm_cb.connecting_dc, p_dev_rec->dev_class, DEV_CLASS_LEN);
+
+ btm_cb.acl_disc_reason = 0xff ;
+
+ p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+ p_dev_rec->role_master = TRUE;
+
+ /* If any SCO link up, do not allow a switch */
+ if (BTM_GetNumScoLinks() != 0)
+ allow_switch = HCI_CR_CONN_NOT_ALLOW_SWITCH;
+
+ return(btsnd_hcic_create_conn (bda, packet_types, page_scan_rep_mode,
+ page_scan_mode, clock_offset, allow_switch));
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_connect_after_reject_timeout
+**
+** Description Connection for bonding could not start because of the collision
+** Initiate outgoing connection
+**
+** Returns Pointer to the TLE struct
+**
+*******************************************************************************/
+static void btm_sec_connect_after_reject_timeout (TIMER_LIST_ENT *p_tle)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_cb.p_collided_dev_rec;
+
+ BTM_TRACE_EVENT0 ("btm_sec_connect_after_reject_timeout()");
+ btm_cb.sec_collision_tle.param = 0;
+ btm_cb.p_collided_dev_rec = 0;
+
+ if (btm_sec_dd_create_conn(p_dev_rec) != BTM_CMD_STARTED)
+ {
+ BTM_TRACE_WARNING0 ("Security Manager: btm_sec_connect_after_reject_timeout: failed to start connection");
+
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+
+ (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr, p_dev_rec->dev_class,
+ p_dev_rec->sec_bd_name, HCI_ERR_MEMORY_FULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_connected
+**
+** Description This function is when a connection to the peer device is
+** establsihed
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sec_connected (UINT8 *bda, UINT16 handle, UINT8 status, UINT8 enc_mode)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bda);
+ UINT8 res;
+ BOOLEAN is_pairing_device = FALSE;
+ tACL_CONN *p_acl_cb;
+
+ btm_acl_resubmit_page();
+
+ /* Commenting out trace due to obf/compilation problems.
+ */
+#if (BT_USE_TRACES == TRUE)
+ if (p_dev_rec)
+ {
+ BTM_TRACE_EVENT6 ("Security Manager: btm_sec_connected in state: %s handle:%d status:%d enc_mode:%d bda:%x RName:%s",
+ btm_pair_state_descr(btm_cb.pairing_state), handle, status, enc_mode,
+ (bda[2]<<24)+(bda[3]<<16)+(bda[4]<<8)+bda[5],
+ p_dev_rec->sec_bd_name);
+ }
+ else
+ {
+ BTM_TRACE_EVENT5 ("Security Manager: btm_sec_connected in state: %s handle:%d status:%d enc_mode:%d bda:%x ",
+ btm_pair_state_descr(btm_cb.pairing_state), handle, status, enc_mode,
+ (bda[2]<<24)+(bda[3]<<16)+(bda[4]<<8)+bda[5]);
+ }
+#endif
+
+ if (!p_dev_rec)
+ {
+ /* There is no device record for new connection. Allocate one */
+ if (status == HCI_SUCCESS)
+ {
+ p_dev_rec = btm_sec_alloc_dev (bda);
+ }
+ else
+ {
+ /* can not find the device record and the status is error,
+ * just ignore it */
+ return;
+ }
+ }
+ else /* Update the timestamp for this device */
+ {
+ p_dev_rec->timestamp = btm_cb.dev_rec_count++;
+ if (p_dev_rec->sm4 & BTM_SM4_CONN_PEND)
+ {
+ /* tell L2CAP it's a bonding connection. */
+ if ( (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)
+ && (memcmp (btm_cb.pairing_bda, p_dev_rec->bd_addr, BD_ADDR_LEN) == 0)
+ && (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) )
+ {
+ /* if incoming connection failed while pairing, then try to connect and continue */
+ /* Motorola S9 disconnects without asking pin code */
+ if ((status != HCI_SUCCESS)&&(btm_cb.pairing_state == BTM_PAIR_STATE_WAIT_PIN_REQ))
+ {
+ BTM_TRACE_WARNING0 ("Security Manager: btm_sec_connected: incoming connection failed without asking PIN");
+
+ p_dev_rec->sm4 &= ~BTM_SM4_CONN_PEND;
+ if (p_dev_rec->sec_flags & BTM_SEC_NAME_KNOWN)
+ {
+ /* Start timer with 0 to initiate connection with new LCB */
+ /* because L2CAP will delete current LCB with this event */
+ btm_cb.p_collided_dev_rec = p_dev_rec;
+ btm_cb.sec_collision_tle.param = (UINT32) btm_sec_connect_after_reject_timeout;
+ btu_start_timer (&btm_cb.sec_collision_tle, BTU_TTYPE_USER_FUNC, 0);
+ }
+ else
+ {
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_GET_REM_NAME);
+ BTM_ReadRemoteDeviceName(p_dev_rec->bd_addr, NULL);
+ }
+#if BTM_DISC_DURING_RS == TRUE
+ p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING; /* reset flag */
+#endif
+ return;
+ }
+ else
+ {
+ l2cu_update_lcb_4_bonding(p_dev_rec->bd_addr, TRUE);
+ }
+ }
+ /* always clear the pending flag */
+ p_dev_rec->sm4 &= ~BTM_SM4_CONN_PEND;
+ }
+ }
+
+#if BTM_DISC_DURING_RS == TRUE
+ p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING; /* reset flag */
+#endif
+
+ if ( (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)
+ && (memcmp (btm_cb.pairing_bda, bda, BD_ADDR_LEN) == 0) )
+ {
+ /* if we rejected incoming connection from bonding device */
+ if ((status == HCI_ERR_HOST_REJECT_DEVICE)
+ &&(btm_cb.pairing_flags & BTM_PAIR_FLAGS_REJECTED_CONNECT))
+ {
+ BTM_TRACE_WARNING2 ("Security Manager: btm_sec_connected: HCI_Conn_Comp Flags:0x%04x, sm4: 0x%x",
+ btm_cb.pairing_flags, p_dev_rec->sm4);
+
+ btm_cb.pairing_flags &= ~BTM_PAIR_FLAGS_REJECTED_CONNECT;
+ if (BTM_SEC_IS_SM4_UNKNOWN(p_dev_rec->sm4))
+ {
+ /* Try again: RNR when no ACL causes HCI_RMT_HOST_SUP_FEAT_NOTIFY_EVT */
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_GET_REM_NAME);
+ BTM_ReadRemoteDeviceName(bda, NULL);
+ return;
+ }
+
+ /* if we already have pin code */
+ if (btm_cb.pairing_state != BTM_PAIR_STATE_WAIT_LOCAL_PIN)
+ {
+ /* Start timer with 0 to initiate connection with new LCB */
+ /* because L2CAP will delete current LCB with this event */
+ btm_cb.p_collided_dev_rec = p_dev_rec;
+ btm_cb.sec_collision_tle.param = (UINT32) btm_sec_connect_after_reject_timeout;
+ btu_start_timer (&btm_cb.sec_collision_tle, BTU_TTYPE_USER_FUNC, 0);
+ }
+
+ return;
+ }
+ /* wait for incoming connection without resetting pairing state */
+ else if (status == HCI_ERR_CONNECTION_EXISTS)
+ {
+ BTM_TRACE_WARNING0 ("Security Manager: btm_sec_connected: Wait for incoming connection");
+ return;
+ }
+
+ is_pairing_device = TRUE;
+ }
+
+ /* If connection was made to do bonding restore link security if changed */
+ btm_restore_mode();
+
+ /* if connection fails during pin request, notify application */
+ if (status != HCI_SUCCESS)
+ {
+ /* If connection failed because of during pairing, need to tell user */
+ if (is_pairing_device)
+ {
+ p_dev_rec->security_required &= ~BTM_SEC_OUT_AUTHENTICATE;
+ p_dev_rec->sec_flags &= ~(BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LINK_KEY_AUTHED);
+ BTM_TRACE_DEBUG1 ("security_required:%x ", p_dev_rec->security_required );
+
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+
+ /* We need to notify host that the key is not known any more */
+ if (btm_cb.api.p_auth_complete_callback)
+ {
+ (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr,
+ p_dev_rec->dev_class,
+ p_dev_rec->sec_bd_name, status);
+ }
+ }
+ else if ((status == HCI_ERR_AUTH_FAILURE) ||
+ (status == HCI_ERR_KEY_MISSING) ||
+ (status == HCI_ERR_HOST_REJECT_SECURITY) ||
+ (status == HCI_ERR_PAIRING_NOT_ALLOWED) ||
+ (status == HCI_ERR_UNIT_KEY_USED) ||
+ (status == HCI_ERR_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED) ||
+ (status == HCI_ERR_ENCRY_MODE_NOT_ACCEPTABLE) ||
+ (status == HCI_ERR_REPEATED_ATTEMPTS))
+ {
+ p_dev_rec->security_required &= ~BTM_SEC_OUT_AUTHENTICATE;
+ p_dev_rec->sec_flags &= ~BTM_SEC_LINK_KEY_KNOWN;
+
+ /* We need to notify host that the key is not known any more */
+ if (btm_cb.api.p_auth_complete_callback)
+ {
+ (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr,
+ p_dev_rec->dev_class,
+ p_dev_rec->sec_bd_name, status);
+ }
+ }
+
+ if (status == HCI_ERR_CONNECTION_TOUT || status == HCI_ERR_LMP_RESPONSE_TIMEOUT ||
+ status == HCI_ERR_UNSPECIFIED || status == HCI_ERR_PAGE_TIMEOUT)
+ btm_sec_dev_rec_cback_event (p_dev_rec, BTM_DEVICE_TIMEOUT);
+ else
+ btm_sec_dev_rec_cback_event (p_dev_rec, BTM_ERR_PROCESSING);
+
+ return;
+ }
+
+ /* If initiated dedicated bonding, return the link key now, and initiate disconnect */
+ /* If dedicated bonding, and we now have a link key, we are all done */
+ if ( is_pairing_device
+ && (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN) )
+ {
+ if (p_dev_rec->link_key_not_sent)
+ {
+ p_dev_rec->link_key_not_sent = FALSE;
+ btm_send_link_key_notif(p_dev_rec);
+ }
+
+ p_dev_rec->security_required &= ~BTM_SEC_OUT_AUTHENTICATE;
+
+ /* remember flag before it is initialized */
+ if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD)
+ res = TRUE;
+ else
+ res = FALSE;
+
+ if (btm_cb.api.p_auth_complete_callback)
+ (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr,
+ p_dev_rec->dev_class,
+ p_dev_rec->sec_bd_name, HCI_SUCCESS);
+
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+
+ if ( res )
+ {
+ /* Let l2cap start bond timer */
+ l2cu_update_lcb_4_bonding (p_dev_rec->bd_addr, TRUE);
+ }
+
+ return;
+ }
+
+ p_dev_rec->hci_handle = handle;
+
+ /* role may not be correct here, it will be updated by l2cap, but we need to */
+ /* notify btm_acl that link is up, so starting of rmt name request will not */
+ /* set paging flag up */
+ p_acl_cb = btm_bda_to_acl(bda);
+ if (p_acl_cb)
+ {
+ /* whatever is in btm_establish_continue() without reporting the BTM_BL_CONN_EVT event */
+#if (!defined(BTM_BYPASS_EXTRA_ACL_SETUP) || BTM_BYPASS_EXTRA_ACL_SETUP == FALSE)
+ /* For now there are a some devices that do not like sending */
+ /* commands events and data at the same time. */
+ /* Set the packet types to the default allowed by the device */
+ btm_set_packet_types (p_acl_cb, btm_cb.btm_acl_pkt_types_supported);
+
+ if (btm_cb.btm_def_link_policy)
+ BTM_SetLinkPolicy (p_acl_cb->remote_addr, &btm_cb.btm_def_link_policy);
+#endif
+
+ BTM_SetLinkSuperTout (p_acl_cb->remote_addr, btm_cb.btm_def_link_super_tout);
+ }
+ btm_acl_created (bda, p_dev_rec->dev_class, p_dev_rec->sec_bd_name, handle, HCI_ROLE_SLAVE, FALSE);
+
+ /* Initialize security flags. We need to do that because some */
+ /* authorization complete could have come after the connection is dropped */
+ /* and that would set wrong flag that link has been authorized already */
+ p_dev_rec->sec_flags &= ~(BTM_SEC_AUTHORIZED | BTM_SEC_AUTHENTICATED |
+ BTM_SEC_ENCRYPTED | BTM_SEC_ROLE_SWITCHED);
+
+ if (enc_mode != HCI_ENCRYPT_MODE_DISABLED)
+ p_dev_rec->sec_flags |= (BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED);
+
+ if (btm_cb.security_mode == BTM_SEC_MODE_LINK)
+ p_dev_rec->sec_flags |= BTM_SEC_AUTHENTICATED;
+
+ p_dev_rec->link_key_changed = FALSE;
+
+ /* After connection is established we perform security if we do not know */
+ /* the name, or if we are originator because some procedure can have */
+ /* been scheduled while connection was down */
+ BTM_TRACE_DEBUG1 ("is_originator:%d ", p_dev_rec->is_originator);
+ if (!(p_dev_rec->sec_flags & BTM_SEC_NAME_KNOWN) || p_dev_rec->is_originator)
+ {
+ if ((res = btm_sec_execute_procedure (p_dev_rec)) != BTM_CMD_STARTED)
+ btm_sec_dev_rec_cback_event (p_dev_rec, res);
+ }
+ return;
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_role_changed
+**
+** Description This function is colled when controller reports role
+** changed, or failed command status for Role Change request
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sec_role_changed (void *p_ref_data)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = (tBTM_SEC_DEV_REC *)p_ref_data;
+ UINT8 res;
+
+ BTM_TRACE_EVENT0 ("Security Manager: role changed");
+
+ /* If this role switch was started by peer do not need to do anything */
+ if (p_dev_rec->sec_state != BTM_SEC_STATE_SWITCHING_ROLE)
+ return;
+
+ /* If serurity required was to FORCE switch and it failed, notify the waiting layer */
+ if (((p_dev_rec->security_required & BTM_SEC_FORCE_MASTER) && !p_dev_rec->role_master)
+ || ((p_dev_rec->security_required & BTM_SEC_FORCE_SLAVE) && p_dev_rec->role_master))
+ {
+ btm_sec_dev_rec_cback_event (p_dev_rec, BTM_ERR_PROCESSING);
+ return;
+ }
+
+ p_dev_rec->sec_flags |= BTM_SEC_ROLE_SWITCHED;
+
+ p_dev_rec->security_required &= ~(BTM_SEC_FORCE_MASTER | BTM_SEC_ATTEMPT_MASTER |
+ BTM_SEC_FORCE_SLAVE | BTM_SEC_ATTEMPT_SLAVE);
+
+ p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+
+ if ((res = (UINT8)btm_sec_execute_procedure (p_dev_rec)) != BTM_CMD_STARTED)
+ {
+ btm_sec_dev_rec_cback_event (p_dev_rec, res);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_disconnect
+**
+** Description This function is called to disconnect HCI link
+**
+** Returns btm status
+**
+*******************************************************************************/
+tBTM_STATUS btm_sec_disconnect (UINT16 handle, UINT8 reason)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev_by_handle (handle);
+
+ /* In some weird race condition we may not have a record */
+ if (!p_dev_rec)
+ {
+ btsnd_hcic_disconnect (handle, reason);
+ return(BTM_SUCCESS);
+ }
+
+ /* If we are in the process of bonding we need to tell client that auth failed */
+ if ( (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)
+ && (memcmp (btm_cb.pairing_bda, p_dev_rec->bd_addr, BD_ADDR_LEN) == 0)
+ && (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) )
+ {
+ /* we are currently doing bonding. Link will be disconnected when done */
+ btm_cb.pairing_flags |= BTM_PAIR_FLAGS_DISC_WHEN_DONE;
+ return(BTM_BUSY);
+ }
+
+ return(btm_sec_send_hci_disconnect(p_dev_rec, reason));
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_disconnected
+**
+** Description This function is when a connection to the peer device is
+** dropped
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sec_disconnected (UINT16 handle, UINT8 reason)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev_by_handle (handle);
+ UINT8 old_pairing_flags = btm_cb.pairing_flags;
+ int result = HCI_ERR_AUTH_FAILURE;
+
+ /* If page was delayed for disc complete, can do it now */
+ btm_cb.discing = FALSE;
+
+ btm_acl_resubmit_page();
+
+ if (!p_dev_rec)
+ return;
+
+#if BTM_DISC_DURING_RS == TRUE
+ BTM_TRACE_ERROR0("btm_sec_disconnected - Clearing Pending flag");
+ p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING; /* reset flag */
+#endif
+
+ /* clear unused flags */
+ p_dev_rec->sm4 &= BTM_SM4_TRUE;
+
+ BTM_TRACE_EVENT6("btm_sec_disconnected() sec_req:x%x State: %s reason:%d bda:%04x%08x RName:%s",
+ p_dev_rec->security_required, btm_pair_state_descr(btm_cb.pairing_state), reason, (p_dev_rec->bd_addr[0]<<8)+p_dev_rec->bd_addr[1],
+ (p_dev_rec->bd_addr[2]<<24)+(p_dev_rec->bd_addr[3]<<16)+(p_dev_rec->bd_addr[4]<<8)+p_dev_rec->bd_addr[5], p_dev_rec->sec_bd_name);
+
+ BTM_TRACE_EVENT1("before Update sec_flags=0x%x", p_dev_rec->sec_flags);
+
+ /* If we are in the process of bonding we need to tell client that auth failed */
+ if ( (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)
+ && (memcmp (btm_cb.pairing_bda, p_dev_rec->bd_addr, BD_ADDR_LEN) == 0))
+ {
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+ p_dev_rec->sec_flags &= ~BTM_SEC_LINK_KEY_KNOWN;
+ if (btm_cb.api.p_auth_complete_callback)
+ {
+ /* If the disconnection reason is REPEATED_ATTEMPTS,
+ send this error message to complete callback function
+ to display the error message of Repeated attempts.
+ All others, send HCI_ERR_AUTH_FAILURE. */
+ if (reason == HCI_ERR_REPEATED_ATTEMPTS)
+ {
+ result = HCI_ERR_REPEATED_ATTEMPTS;
+ }
+ else if (old_pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD)
+ {
+ result = HCI_ERR_HOST_REJECT_SECURITY;
+ }
+ (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr, p_dev_rec->dev_class,
+ p_dev_rec->sec_bd_name, reason);
+ }
+ }
+
+ p_dev_rec->hci_handle = BTM_SEC_INVALID_HANDLE;
+ p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+
+#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE
+ p_dev_rec->enc_key_size = 0;
+ btm_ble_resume_bg_conn(NULL, TRUE);
+ /* see sec_flags processing in btm_acl_removed */
+#endif
+ p_dev_rec->sec_flags &= ~(BTM_SEC_AUTHORIZED | BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED | BTM_SEC_ROLE_SWITCHED);
+
+ p_dev_rec->security_required = BTM_SEC_NONE;
+ p_dev_rec->p_callback = NULL; /* when the peer device time out the authentication before we do, this call back must be reset here */
+ BTM_TRACE_EVENT1("after Update sec_flags=0x%x", p_dev_rec->sec_flags);
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_link_key_notification
+**
+** Description This function is called when a new connection link key is
+** generated
+**
+** Returns Pointer to the record or NULL
+**
+*******************************************************************************/
+void btm_sec_link_key_notification (UINT8 *p_bda, UINT8 *p_link_key, UINT8 key_type)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_or_alloc_dev (p_bda);
+ BOOLEAN we_are_bonding = FALSE;
+
+ BTM_TRACE_EVENT3 ("btm_sec_link_key_notification() BDA:%04x%08x, TYPE: %d",
+ (p_bda[0]<<8)+p_bda[1], (p_bda[2]<<24)+(p_bda[3]<<16)+(p_bda[4]<<8)+p_bda[5],
+ key_type);
+
+ /* If connection was made to do bonding restore link security if changed */
+ btm_restore_mode();
+
+ /* Override the key type if version is pre-1.1 */
+ if (btm_cb.devcb.local_version.hci_version < HCI_VERSION_1_1)
+ p_dev_rec->link_key_type = BTM_LKEY_TYPE_IGNORE;
+ if (key_type != BTM_LKEY_TYPE_CHANGED_COMB)
+ p_dev_rec->link_key_type = key_type;
+
+ p_dev_rec->sec_flags |= BTM_SEC_LINK_KEY_KNOWN;
+
+ memcpy (p_dev_rec->link_key, p_link_key, LINK_KEY_LEN);
+
+ if ( (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)
+ && (memcmp (btm_cb.pairing_bda, p_bda, BD_ADDR_LEN) == 0) )
+ {
+ if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD)
+ we_are_bonding = TRUE;
+ else
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+ }
+
+ /* If name is not known at this point delay calling callback until the name is */
+ /* resolved. Unless it is a HID Device and we really need to send all link keys. */
+ if ((!(p_dev_rec->sec_flags & BTM_SEC_NAME_KNOWN)
+ && ((p_dev_rec->dev_class[1] & BTM_COD_MAJOR_CLASS_MASK) != BTM_COD_MAJOR_PERIPHERAL)) )
+ {
+ BTM_TRACE_EVENT3 ("btm_sec_link_key_notification() Delayed BDA: %08x%04x Type:%d",
+ (p_bda[0]<<24) + (p_bda[1]<<16) + (p_bda[2]<<8) + p_bda[3], (p_bda[4] << 8) + p_bda[5], key_type);
+
+ p_dev_rec->link_key_not_sent = TRUE;
+
+ /* If it is for bonding nothing else will follow, so we need to start name resolution */
+ if (we_are_bonding)
+ {
+ if (!(btsnd_hcic_rmt_name_req (p_bda, HCI_PAGE_SCAN_REP_MODE_R1, HCI_MANDATARY_PAGE_SCAN_MODE, 0)))
+ btm_inq_rmt_name_failed();
+ }
+
+ BTM_TRACE_EVENT3 ("rmt_io_caps:%d, sec_flags:x%x, dev_class[1]:x%02x", p_dev_rec->rmt_io_caps, p_dev_rec->sec_flags, p_dev_rec->dev_class[1])
+ return;
+ }
+
+ /* If its not us who perform authentication, we should tell stackserver */
+ /* that some authentication has been completed */
+ /* This is required when different entities receive link notification and auth complete */
+ if (!(p_dev_rec->security_required & BTM_SEC_OUT_AUTHENTICATE))
+ {
+ if (btm_cb.api.p_auth_complete_callback)
+ (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr, p_dev_rec->dev_class,
+ p_dev_rec->sec_bd_name, HCI_SUCCESS);
+ }
+
+ /* We will save link key only if the user authorized it - BTE report link key in all cases */
+#ifdef BRCM_NONE_BTE
+ if (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_AUTHED)
+#endif
+ {
+ if (btm_cb.api.p_link_key_callback)
+ {
+ (*btm_cb.api.p_link_key_callback) (p_bda, p_dev_rec->dev_class, p_dev_rec->sec_bd_name,
+ p_link_key, p_dev_rec->link_key_type);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_link_key_request
+**
+** Description This function is called when controller requests link key
+**
+** Returns Pointer to the record or NULL
+**
+*******************************************************************************/
+void btm_sec_link_key_request (UINT8 *p_bda)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_or_alloc_dev (p_bda);
+
+ BTM_TRACE_EVENT6 ("btm_sec_link_key_request() BDA: %02x:%02x:%02x:%02x:%02x:%02x",
+ p_bda[0], p_bda[1], p_bda[2], p_bda[3], p_bda[4], p_bda[5]);
+
+ if (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN)
+ {
+ btsnd_hcic_link_key_req_reply (p_bda, p_dev_rec->link_key);
+ return;
+ }
+
+ /* Notify L2CAP to increase timeout */
+ l2c_pin_code_request (p_bda);
+
+ /* Only ask the host for a key if this guy is not already bonding */
+ if ( (btm_cb.pairing_state == BTM_PAIR_STATE_IDLE)
+ || (memcmp (p_bda, btm_cb.pairing_bda, BD_ADDR_LEN) != 0) )
+ {
+ if (btm_cb.api.p_link_key_req_callback)
+ {
+ if ((*btm_cb.api.p_link_key_req_callback)(p_bda, p_dev_rec->link_key) == BTM_SUCCESS)
+ {
+ btsnd_hcic_link_key_req_reply (p_bda, p_dev_rec->link_key);
+ return;
+ }
+ }
+ }
+
+ /* The link key is not in the database and it is not known to the manager */
+ btsnd_hcic_link_key_neg_reply (p_bda);
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_pairing_timeout
+**
+** Description This function is called when host does not provide PIN
+** within requested time
+**
+** Returns Pointer to the TLE struct
+**
+*******************************************************************************/
+static void btm_sec_pairing_timeout (TIMER_LIST_ENT *p_tle)
+{
+ tBTM_CB *p_cb = &btm_cb;
+ tBTM_SEC_DEV_REC *p_dev_rec;
+#if BTM_OOB_INCLUDED == TRUE
+#if (BTM_LOCAL_IO_CAPS == BTM_IO_CAP_NONE)
+ tBTM_AUTH_REQ auth_req = BTM_AUTH_AP_NO;
+#else
+ tBTM_AUTH_REQ auth_req = BTM_AUTH_AP_YES;
+#endif
+#endif
+ UINT8 name[2];
+
+ p_cb->pairing_tle.param = 0;
+/* Coverity: FALSE-POSITIVE error from Coverity tool. Please do NOT remove following comment. */
+/* coverity[UNUSED_VALUE] pointer p_dev_rec is actually used several times... This is a Coverity false-positive, i.e. a fake issue.
+*/
+ p_dev_rec = btm_find_dev (p_cb->pairing_bda);
+
+ BTM_TRACE_EVENT2 ("btm_sec_pairing_timeout() State: %s Flags: %u",
+ btm_pair_state_descr(p_cb->pairing_state), p_cb->pairing_flags);
+
+ switch (p_cb->pairing_state)
+ {
+ case BTM_PAIR_STATE_WAIT_PIN_REQ:
+ btm_sec_bond_cancel_complete();
+ break;
+
+ case BTM_PAIR_STATE_WAIT_LOCAL_PIN:
+ if ( (btm_cb.pairing_flags & BTM_PAIR_FLAGS_PRE_FETCH_PIN) == 0)
+ btsnd_hcic_pin_code_neg_reply (p_cb->pairing_bda);
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+ /* We need to notify the UI that no longer need the PIN */
+ if (btm_cb.api.p_auth_complete_callback)
+ {
+ if (p_dev_rec == NULL)
+ {
+ name[0] = 0;
+ (*btm_cb.api.p_auth_complete_callback) (p_cb->pairing_bda,
+ NULL,
+ name, HCI_ERR_CONNECTION_TOUT);
+ }
+ else
+ (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr,
+ p_dev_rec->dev_class,
+ p_dev_rec->sec_bd_name, HCI_ERR_CONNECTION_TOUT);
+ }
+ break;
+
+ case BTM_PAIR_STATE_WAIT_NUMERIC_CONFIRM:
+ btsnd_hcic_user_conf_reply (p_cb->pairing_bda, FALSE);
+ /* btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE); */
+ break;
+
+#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
+ case BTM_PAIR_STATE_KEY_ENTRY:
+ btsnd_hcic_user_passkey_neg_reply(p_cb->pairing_bda);
+ /* btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE); */
+ break;
+#endif /* !BTM_IO_CAP_NONE */
+
+#if BTM_OOB_INCLUDED == TRUE
+ case BTM_PAIR_STATE_WAIT_LOCAL_IOCAPS:
+ if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD)
+ auth_req |= BTM_AUTH_DD_BOND;
+
+ btsnd_hcic_io_cap_req_reply (p_cb->pairing_bda, btm_cb.devcb.loc_io_caps,
+ BTM_OOB_NONE, auth_req);
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+ break;
+
+ case BTM_PAIR_STATE_WAIT_LOCAL_OOB_RSP:
+ btsnd_hcic_rem_oob_neg_reply (p_cb->pairing_bda);
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+ break;
+#endif /* BTM_OOB_INCLUDED */
+
+ case BTM_PAIR_STATE_WAIT_DISCONNECT:
+ /* simple pairing failed. Started a 1-sec timer at simple pairing complete.
+ * now it's time to tear down the ACL link*/
+ if (p_dev_rec == NULL)
+ {
+ BTM_TRACE_ERROR2 ("btm_sec_pairing_timeout() BTM_PAIR_STATE_WAIT_DISCONNECT unknown BDA: %08x%04x",
+ (p_cb->pairing_bda[0]<<24) + (p_cb->pairing_bda[1]<<16) + (p_cb->pairing_bda[2]<<8) + p_cb->pairing_bda[3],
+ (p_cb->pairing_bda[4] << 8) + p_cb->pairing_bda[5]);
+ break;
+ }
+ btm_sec_send_hci_disconnect (p_dev_rec, HCI_ERR_AUTH_FAILURE);
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+ break;
+
+ default:
+ BTM_TRACE_WARNING1 ("btm_sec_pairing_timeout() not processed state: %s", btm_pair_state_descr(btm_cb.pairing_state));
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+ break;
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_pin_code_request
+**
+** Description This function is called when controller requests PIN code
+**
+** Returns Pointer to the record or NULL
+**
+*******************************************************************************/
+void btm_sec_pin_code_request (UINT8 *p_bda)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ tBTM_CB *p_cb = &btm_cb;
+
+ BTM_TRACE_EVENT3 ("btm_sec_pin_code_request() State: %s, BDA:%04x%08x",
+ btm_pair_state_descr(btm_cb.pairing_state),
+ (p_bda[0]<<8)+p_bda[1], (p_bda[2]<<24)+(p_bda[3]<<16)+(p_bda[4]<<8)+p_bda[5] );
+
+ if (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)
+ {
+ if ( (memcmp (p_bda, btm_cb.pairing_bda, BD_ADDR_LEN) == 0) &&
+ (btm_cb.pairing_state == BTM_PAIR_STATE_WAIT_AUTH_COMPLETE) )
+ {
+ /* fake this out - porshe carkit issue - */
+// btm_cb.pairing_state = BTM_PAIR_STATE_IDLE;
+ if(! btm_cb.pin_code_len_saved)
+ {
+ btsnd_hcic_pin_code_neg_reply (p_bda);
+ return;
+ }
+ else
+ {
+ btsnd_hcic_pin_code_req_reply (p_bda, btm_cb.pin_code_len_saved, p_cb->pin_code);
+ return;
+ }
+ }
+ else if ((btm_cb.pairing_state != BTM_PAIR_STATE_WAIT_PIN_REQ)
+ || memcmp (p_bda, btm_cb.pairing_bda, BD_ADDR_LEN) != 0)
+ {
+ BTM_TRACE_WARNING1 ("btm_sec_pin_code_request() rejected - state: %s",
+ btm_pair_state_descr(btm_cb.pairing_state));
+
+#ifdef PORCHE_PAIRING_CONFLICT
+ /* reply pin code again due to counter in_rand when local initiates pairing */
+ BTM_TRACE_EVENT0 ("btm_sec_pin_code_request from remote dev. for local initiated pairing");
+ if(! btm_cb.pin_code_len_saved)
+ {
+ btsnd_hcic_pin_code_neg_reply (p_bda);
+ }
+ else
+ {
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_AUTH_COMPLETE);
+ btsnd_hcic_pin_code_req_reply (p_bda, btm_cb.pin_code_len_saved, p_cb->pin_code);
+ }
+#else
+ btsnd_hcic_pin_code_neg_reply (p_bda);
+#endif
+ return;
+ }
+ }
+
+ p_dev_rec = btm_find_or_alloc_dev (p_bda);
+ /* received PIN code request. must be non-sm4 */
+ p_dev_rec->sm4 = BTM_SM4_KNOWN;
+
+ if (btm_cb.pairing_state == BTM_PAIR_STATE_IDLE)
+ {
+ memcpy (btm_cb.pairing_bda, p_bda, BD_ADDR_LEN);
+
+ btm_cb.pairing_flags = BTM_PAIR_FLAGS_PEER_STARTED_DD;
+ /* Make sure we reset the trusted mask to help against attacks */
+ BTM_SEC_CLR_TRUSTED_DEVICE(p_dev_rec->trusted_mask);
+ }
+
+ if (!p_cb->pairing_disabled && (p_cb->cfg.pin_type == HCI_PIN_TYPE_FIXED))
+ {
+ BTM_TRACE_EVENT0 ("btm_sec_pin_code_request fixed pin replying");
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_AUTH_COMPLETE);
+ btsnd_hcic_pin_code_req_reply (p_bda, p_cb->cfg.pin_code_len, p_cb->cfg.pin_code);
+ return;
+ }
+
+ /* Use the connecting device's CoD for the connection */
+ if ( (!memcmp (p_bda, p_cb->connecting_bda, BD_ADDR_LEN))
+ && (p_cb->connecting_dc[0] || p_cb->connecting_dc[1] || p_cb->connecting_dc[2]) )
+ memcpy (p_dev_rec->dev_class, p_cb->connecting_dc, DEV_CLASS_LEN);
+
+ /* We could have started connection after asking user for the PIN code */
+ if (btm_cb.pin_code_len != 0)
+ {
+ BTM_TRACE_EVENT0 ("btm_sec_pin_code_request bonding sending reply");
+ btsnd_hcic_pin_code_req_reply (p_bda, btm_cb.pin_code_len, p_cb->pin_code);
+
+#ifdef PORCHE_PAIRING_CONFLICT
+ btm_cb.pin_code_len_saved = btm_cb.pin_code_len;
+#endif
+
+ /* Mark that we forwarded received from the user PIN code */
+ btm_cb.pin_code_len = 0;
+
+ /* We can change mode back right away, that other connection being established */
+ /* is not forced to be secure - found a FW issue, so we can not do this
+ btm_restore_mode(); */
+
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_AUTH_COMPLETE);
+ }
+
+ /* If pairing disabled OR (no PIN callback and not bonding) */
+ /* OR we could not allocate entry in the database reject pairing request */
+ else if (p_cb->pairing_disabled
+ || (p_cb->api.p_pin_callback == NULL)
+
+ /* OR Microsoft keyboard can for some reason try to establish connection */
+ /* the only thing we can do here is to shut it up. Normally we will be originator */
+ /* for keyboard bonding */
+ || (!p_dev_rec->is_originator
+ && ((p_dev_rec->dev_class[1] & BTM_COD_MAJOR_CLASS_MASK) == BTM_COD_MAJOR_PERIPHERAL)
+ && (p_dev_rec->dev_class[2] & BTM_COD_MINOR_KEYBOARD)) )
+ {
+ BTM_TRACE_WARNING3("btm_sec_pin_code_request(): Pairing disabled:%d; PIN callback:%x, Dev Rec:%x!",
+ p_cb->pairing_disabled, p_cb->api.p_pin_callback, p_dev_rec);
+
+ btsnd_hcic_pin_code_neg_reply (p_bda);
+ }
+ /* Notify upper layer of PIN request and start expiration timer */
+ else
+ {
+ btm_cb.pin_code_len_saved = 0;
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_LOCAL_PIN);
+ /* Pin code request can not come at the same time as connection request */
+ memcpy (p_cb->connecting_bda, p_bda, BD_ADDR_LEN);
+ memcpy (p_cb->connecting_dc, p_dev_rec->dev_class, DEV_CLASS_LEN);
+
+ /* Check if the name is known */
+ /* Even if name is not known we might not be able to get one */
+ /* this is the case when we are already getting something from the */
+ /* device, so HCI level is flow controlled */
+ /* Also cannot send remote name request while paging, i.e. connection is not completed */
+ if (p_dev_rec->sec_flags & BTM_SEC_NAME_KNOWN)
+ {
+ BTM_TRACE_EVENT0 ("btm_sec_pin_code_request going for callback");
+
+ btm_cb.pairing_flags |= BTM_PAIR_FLAGS_PIN_REQD;
+ if (p_cb->api.p_pin_callback)
+ (*p_cb->api.p_pin_callback) (p_bda, p_dev_rec->dev_class, p_dev_rec->sec_bd_name);
+ }
+ else
+ {
+ BTM_TRACE_EVENT0 ("btm_sec_pin_code_request going for remote name");
+
+ /* We received PIN code request for the device with unknown name */
+ /* it is not user friendly just to ask for the PIN without name */
+ /* try to get name at first */
+ if (!btsnd_hcic_rmt_name_req (p_dev_rec->bd_addr,
+ HCI_PAGE_SCAN_REP_MODE_R1,
+ HCI_MANDATARY_PAGE_SCAN_MODE, 0))
+ {
+ p_dev_rec->sec_flags |= BTM_SEC_NAME_KNOWN;
+ p_dev_rec->sec_bd_name[0] = 'f';
+ p_dev_rec->sec_bd_name[1] = '0';
+ BTM_TRACE_ERROR0 ("can not send rmt_name_req?? fake a name and call callback");
+
+ btm_cb.pairing_flags |= BTM_PAIR_FLAGS_PIN_REQD;
+ if (p_cb->api.p_pin_callback)
+ (*p_cb->api.p_pin_callback) (p_bda, p_dev_rec->dev_class, p_dev_rec->sec_bd_name);
+ }
+ }
+ }
+
+ return;
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_update_clock_offset
+**
+** Description This function is called to update clock offset
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sec_update_clock_offset (UINT16 handle, UINT16 clock_offset)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ tBTM_INQ_INFO *p_inq_info;
+
+ if ((p_dev_rec = btm_find_dev_by_handle (handle)) == NULL)
+ return;
+
+ p_dev_rec->clock_offset = clock_offset | BTM_CLOCK_OFFSET_VALID;
+
+ if ((p_inq_info = BTM_InqDbRead(p_dev_rec->bd_addr)) == NULL)
+ return;
+
+ p_inq_info->results.clock_offset = clock_offset | BTM_CLOCK_OFFSET_VALID;
+}
+
+
+/******************************************************************
+** S T A T I C F U N C T I O N S
+*******************************************************************/
+
+/*******************************************************************************
+**
+** Function btm_sec_execute_procedure
+**
+** Description This function is called to start required security
+** procedure. There is a case when multiplexing protocol
+** calls this function on the originating side, connection to
+** the peer will not be established. This function in this
+** case performs only authorization.
+**
+** Returns BTM_SUCCESS - permission is granted
+** BTM_CMD_STARTED - in process
+** BTM_NO_RESOURCES - permission declined
+**
+*******************************************************************************/
+static tBTM_STATUS btm_sec_execute_procedure (tBTM_SEC_DEV_REC *p_dev_rec)
+{
+ BTM_TRACE_EVENT3 ("btm_sec_execute_procedure: Required:0x%x Flags:0x%x State:%d",
+ p_dev_rec->security_required, p_dev_rec->sec_flags, p_dev_rec->sec_state);
+
+ /* There is a chance that we are getting name. Wait until done. */
+ if (p_dev_rec->sec_state != 0)
+ return(BTM_CMD_STARTED);
+
+ /* If any security is required, get the name first */
+ if (!(p_dev_rec->sec_flags & BTM_SEC_NAME_KNOWN)
+ && (p_dev_rec->hci_handle != BTM_SEC_INVALID_HANDLE))
+ {
+ BTM_TRACE_EVENT0 ("Security Manager: Start get name");
+ if (!btm_sec_start_get_name (p_dev_rec))
+ {
+ return(BTM_NO_RESOURCES);
+ }
+ return(BTM_CMD_STARTED);
+ }
+
+ /* If connection is not authenticated and authentication is required */
+ /* start authentication and return PENDING to the caller */
+ if ((!(p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED))
+ && (( p_dev_rec->is_originator && (p_dev_rec->security_required & BTM_SEC_OUT_AUTHENTICATE))
+ || (!p_dev_rec->is_originator && (p_dev_rec->security_required & BTM_SEC_IN_AUTHENTICATE)))
+ && (p_dev_rec->hci_handle != BTM_SEC_INVALID_HANDLE))
+ {
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ /* if incoming UCD packet, discard it */
+ if ( !p_dev_rec->is_originator && (p_dev_rec->is_ucd == TRUE ))
+ return(BTM_FAILED_ON_SECURITY);
+#endif
+
+ BTM_TRACE_EVENT0 ("Security Manager: Start authentication");
+
+ if (!btm_sec_start_authentication (p_dev_rec))
+ {
+ return(BTM_NO_RESOURCES);
+ }
+ return(BTM_CMD_STARTED);
+ }
+
+ /* If connection is not encrypted and encryption is required */
+ /* start encryption and return PENDING to the caller */
+ if (!(p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED)
+ && (( p_dev_rec->is_originator && (p_dev_rec->security_required & BTM_SEC_OUT_ENCRYPT))
+ || (!p_dev_rec->is_originator && (p_dev_rec->security_required & BTM_SEC_IN_ENCRYPT)))
+ && (p_dev_rec->hci_handle != BTM_SEC_INVALID_HANDLE))
+ {
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ /* if incoming UCD packet, discard it */
+ if ( !p_dev_rec->is_originator && (p_dev_rec->is_ucd == TRUE ))
+ return(BTM_FAILED_ON_SECURITY);
+#endif
+
+ BTM_TRACE_EVENT0 ("Security Manager: Start encryption");
+
+ if (!btm_sec_start_encryption (p_dev_rec))
+ {
+ return(BTM_NO_RESOURCES);
+ }
+ return(BTM_CMD_STARTED);
+ }
+
+ /* If connection is not authorized and authorization is required */
+ /* start authorization and return PENDING to the caller */
+ if (!(p_dev_rec->sec_flags & BTM_SEC_AUTHORIZED)
+ && (( p_dev_rec->is_originator && (p_dev_rec->security_required & BTM_SEC_OUT_AUTHORIZE))
+ || (!p_dev_rec->is_originator && (p_dev_rec->security_required & BTM_SEC_IN_AUTHORIZE))))
+ {
+ BTM_TRACE_EVENT2 ("service id:%d, is trusted:%d",
+ p_dev_rec->p_cur_service->service_id,
+ (BTM_SEC_IS_SERVICE_TRUSTED(p_dev_rec->trusted_mask,
+ p_dev_rec->p_cur_service->service_id)));
+ if ((btm_sec_are_all_trusted(p_dev_rec->trusted_mask) == FALSE) &&
+ (p_dev_rec->p_cur_service->service_id < BTM_SEC_MAX_SERVICES) &&
+ (BTM_SEC_IS_SERVICE_TRUSTED(p_dev_rec->trusted_mask,
+ p_dev_rec->p_cur_service->service_id) == FALSE))
+ {
+ BTM_TRACE_EVENT0 ("Security Manager: Start authorization");
+ return(btm_sec_start_authorization (p_dev_rec));
+ }
+ }
+
+ /* All required security procedures already established */
+ p_dev_rec->security_required &= ~(BTM_SEC_OUT_AUTHORIZE | BTM_SEC_IN_AUTHORIZE |
+ BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_IN_AUTHENTICATE |
+ BTM_SEC_OUT_ENCRYPT | BTM_SEC_IN_ENCRYPT |
+ BTM_SEC_FORCE_MASTER | BTM_SEC_ATTEMPT_MASTER |
+ BTM_SEC_FORCE_SLAVE | BTM_SEC_ATTEMPT_SLAVE);
+
+ BTM_TRACE_EVENT2 ("Security Manager: trusted:0x%04x%04x", p_dev_rec->trusted_mask[1], p_dev_rec->trusted_mask[0]);
+ BTM_TRACE_EVENT0 ("Security Manager: access granted");
+
+ return(BTM_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function btm_sec_start_get_name
+**
+** Description This function is called to start get name procedure
+**
+** Returns TRUE if started
+**
+*******************************************************************************/
+static BOOLEAN btm_sec_start_get_name (tBTM_SEC_DEV_REC *p_dev_rec)
+{
+ UINT8 tempstate = p_dev_rec->sec_state;
+
+ p_dev_rec->sec_state = BTM_SEC_STATE_GETTING_NAME;
+
+ /* Device should be connected, no need to provide correct page params */
+ /* 0 and NULL are as timeout and callback params because they are not used in security get name case */
+ if ((btm_initiate_rem_name (p_dev_rec->bd_addr, NULL, BTM_RMT_NAME_SEC,
+ 0, NULL)) != BTM_CMD_STARTED)
+ {
+ p_dev_rec->sec_state = tempstate;
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_start_authentication
+**
+** Description This function is called to start authentication
+**
+** Returns TRUE if started
+**
+*******************************************************************************/
+static BOOLEAN btm_sec_start_authentication (tBTM_SEC_DEV_REC *p_dev_rec)
+{
+ p_dev_rec->sec_state = BTM_SEC_STATE_AUTHENTICATING;
+
+ return(btsnd_hcic_auth_request (p_dev_rec->hci_handle));
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_start_encryption
+**
+** Description This function is called to start encryption
+**
+** Returns TRUE if started
+**
+*******************************************************************************/
+static BOOLEAN btm_sec_start_encryption (tBTM_SEC_DEV_REC *p_dev_rec)
+{
+ if (!btsnd_hcic_set_conn_encrypt (p_dev_rec->hci_handle, TRUE))
+ return(FALSE);
+
+ p_dev_rec->sec_state = BTM_SEC_STATE_ENCRYPTING;
+ return(TRUE);
+}
+
+
+/*******************************************************************************
+**
+** Function btm_sec_start_authorization
+**
+** Description This function is called to start authorization
+**
+** Returns TRUE if started
+**
+*******************************************************************************/
+static UINT8 btm_sec_start_authorization (tBTM_SEC_DEV_REC *p_dev_rec)
+{
+ UINT8 result;
+ UINT8 *p_service_name = NULL;
+ UINT8 service_id;
+
+ if ((p_dev_rec->sec_flags & BTM_SEC_NAME_KNOWN)
+ || (p_dev_rec->hci_handle == BTM_SEC_INVALID_HANDLE))
+ {
+ if (!btm_cb.api.p_authorize_callback)
+ return(BTM_MODE_UNSUPPORTED);
+
+ if (p_dev_rec->p_cur_service)
+ {
+#if BTM_SEC_SERVICE_NAME_LEN > 0
+ if (p_dev_rec->is_originator)
+ p_service_name = p_dev_rec->p_cur_service->orig_service_name;
+ else
+ p_service_name = p_dev_rec->p_cur_service->term_service_name;
+#endif
+ service_id = p_dev_rec->p_cur_service->service_id;
+ }
+ else
+ service_id = 0;
+
+ p_dev_rec->sec_state = BTM_SEC_STATE_AUTHORIZING;
+ result = (*btm_cb.api.p_authorize_callback) (p_dev_rec->bd_addr,
+ p_dev_rec->dev_class,
+ p_dev_rec->sec_bd_name,
+ p_service_name,
+ service_id,
+ p_dev_rec->is_originator);
+ if (result == BTM_SUCCESS)
+ {
+ p_dev_rec->sec_flags |= BTM_SEC_AUTHORIZED;
+ p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+ }
+ return(result);
+ }
+ btm_sec_start_get_name (p_dev_rec);
+ return(BTM_CMD_STARTED);
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_are_all_trusted
+**
+** Description This function is called check if all services are trusted
+**
+** Returns TRUE if all are trusted, otherwise FALSE
+**
+*******************************************************************************/
+BOOLEAN btm_sec_are_all_trusted(UINT32 p_mask[])
+{
+ int trusted_inx;
+ for (trusted_inx = 0; trusted_inx < BTM_SEC_SERVICE_ARRAY_SIZE; trusted_inx++)
+ {
+ if (p_mask[trusted_inx] != BTM_SEC_TRUST_ALL)
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_find_first_serv
+**
+** Description Look for the first record in the service database
+** with specified PSM
+**
+** Returns Pointer to the record or NULL
+**
+*******************************************************************************/
+static tBTM_SEC_SERV_REC *btm_sec_find_first_serv (CONNECTION_TYPE conn_type, UINT16 psm)
+{
+ tBTM_SEC_SERV_REC *p_serv_rec = &btm_cb.sec_serv_rec[0];
+ int i;
+ BOOLEAN is_originator;
+
+#if (L2CAP_UCD_INCLUDED == TRUE)
+
+ if ( conn_type & CONNECTION_TYPE_ORIG_MASK )
+ is_originator = TRUE;
+ else
+ is_originator = FALSE;
+#else
+ is_originator = conn_type;
+#endif
+
+ if (is_originator && btm_cb.p_out_serv && btm_cb.p_out_serv->psm == psm)
+ {
+ /* If this is outgoing connection and the PSM matches p_out_serv,
+ * use it as the current service */
+ return btm_cb.p_out_serv;
+ }
+
+ /* otherwise, just find the first record with the specified PSM */
+ for (i = 0; i < BTM_SEC_MAX_SERVICE_RECORDS; i++, p_serv_rec++)
+ {
+ if ( (p_serv_rec->security_flags & BTM_SEC_IN_USE) && (p_serv_rec->psm == psm) )
+ return(p_serv_rec);
+ }
+ return(NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function btm_sec_find_next_serv
+**
+** Description Look for the next record in the service database
+** with specified PSM
+**
+** Returns Pointer to the record or NULL
+**
+*******************************************************************************/
+static tBTM_SEC_SERV_REC *btm_sec_find_next_serv (tBTM_SEC_SERV_REC *p_cur)
+{
+ tBTM_SEC_SERV_REC *p_serv_rec = &btm_cb.sec_serv_rec[0];
+ int i;
+
+ for (i = 0; i < BTM_SEC_MAX_SERVICE_RECORDS; i++, p_serv_rec++)
+ {
+ if ((p_serv_rec->security_flags & BTM_SEC_IN_USE)
+ && (p_serv_rec->psm == p_cur->psm) )
+ {
+ if (p_cur != p_serv_rec)
+ {
+ return(p_serv_rec);
+ }
+ }
+ }
+ return(NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function btm_sec_find_mx_serv
+**
+** Description Look for the record in the service database with specified
+** PSM and multiplexor channel information
+**
+** Returns Pointer to the record or NULL
+**
+*******************************************************************************/
+static tBTM_SEC_SERV_REC *btm_sec_find_mx_serv (UINT8 is_originator, UINT16 psm,
+ UINT32 mx_proto_id, UINT32 mx_chan_id)
+{
+ tBTM_SEC_SERV_REC *p_out_serv = btm_cb.p_out_serv;
+ tBTM_SEC_SERV_REC *p_serv_rec = &btm_cb.sec_serv_rec[0];
+ int i;
+
+ BTM_TRACE_DEBUG0 ("btm_sec_find_mx_serv");
+ if (is_originator && p_out_serv && p_out_serv->psm == psm
+ && p_out_serv->mx_proto_id == mx_proto_id
+ && p_out_serv->orig_mx_chan_id == mx_chan_id)
+ {
+ /* If this is outgoing connection and the parameters match p_out_serv,
+ * use it as the current service */
+ return btm_cb.p_out_serv;
+ }
+
+ /* otherwise, the old way */
+ for (i = 0; i < BTM_SEC_MAX_SERVICE_RECORDS; i++, p_serv_rec++)
+ {
+ if ((p_serv_rec->security_flags & BTM_SEC_IN_USE)
+ && (p_serv_rec->psm == psm)
+ && (p_serv_rec->mx_proto_id == mx_proto_id)
+ && (( is_originator && (p_serv_rec->orig_mx_chan_id == mx_chan_id))
+ || (!is_originator && (p_serv_rec->term_mx_chan_id == mx_chan_id))))
+ {
+ return(p_serv_rec);
+ }
+ }
+ return(NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function btm_sec_collision_timeout
+**
+** Description Encryption could not start because of the collision
+** try to do it again
+**
+** Returns Pointer to the TLE struct
+**
+*******************************************************************************/
+static void btm_sec_collision_timeout (TIMER_LIST_ENT *p_tle)
+{
+ tBTM_STATUS status;
+
+ BTM_TRACE_EVENT0 ("btm_sec_collision_timeout()");
+ btm_cb.sec_collision_tle.param = 0;
+
+ status = btm_sec_execute_procedure (btm_cb.p_collided_dev_rec);
+
+ /* If result is pending reply from the user or from the device is pending */
+ if (status != BTM_CMD_STARTED)
+ {
+ /* There is no next procedure or start of procedure failed, notify the waiting layer */
+ btm_sec_dev_rec_cback_event (btm_cb.p_collided_dev_rec, status);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_link_key_request
+**
+** Description This function is called when controller requests link key
+**
+** Returns Pointer to the record or NULL
+**
+*******************************************************************************/
+static void btm_send_link_key_notif (tBTM_SEC_DEV_REC *p_dev_rec)
+{
+ if (btm_cb.api.p_link_key_callback)
+ (*btm_cb.api.p_link_key_callback) (p_dev_rec->bd_addr, p_dev_rec->dev_class,
+ p_dev_rec->sec_bd_name, p_dev_rec->link_key,
+ p_dev_rec->link_key_type);
+}
+
+/*******************************************************************************
+**
+** Function BTM_ReadTrustedMask
+**
+** Description Get trusted mask for the peer device
+**
+** Parameters: bd_addr - Address of the device
+**
+** Returns NULL, if the device record is not found.
+** otherwise, the trusted mask
+**
+*******************************************************************************/
+UINT32 * BTM_ReadTrustedMask (BD_ADDR bd_addr)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+
+ if ((p_dev_rec = btm_find_dev (bd_addr)) != NULL)
+ {
+ return(p_dev_rec->trusted_mask);
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_restore_mode
+**
+** Description This function returns the security mode to previous setting
+** if it was changed during bonding.
+**
+**
+** Parameters: void
+**
+*******************************************************************************/
+static void btm_restore_mode(void)
+{
+ if (btm_cb.security_mode_changed)
+ {
+ btm_cb.security_mode_changed = FALSE;
+ BTM_TRACE_DEBUG1("btm_restore_mode: Authen Enable -> %d", (btm_cb.security_mode == BTM_SEC_MODE_LINK));
+ btsnd_hcic_write_auth_enable ((UINT8)(btm_cb.security_mode == BTM_SEC_MODE_LINK));
+ }
+
+ if (btm_cb.pin_type_changed)
+ {
+ btm_cb.pin_type_changed = FALSE;
+ btsnd_hcic_write_pin_type (btm_cb.cfg.pin_type);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function btm_sec_find_dev_by_sec_state
+**
+** Description Look for the record in the device database for the device
+** which is being authenticated or encrypted
+**
+** Returns Pointer to the record or NULL
+**
+*******************************************************************************/
+tBTM_SEC_DEV_REC *btm_sec_find_dev_by_sec_state (UINT8 state)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = &btm_cb.sec_dev_rec[0];
+ int i;
+
+ for (i = 0; i < BTM_SEC_MAX_DEVICE_RECORDS; i++, p_dev_rec++)
+ {
+ if ((p_dev_rec->sec_flags & BTM_SEC_IN_USE)
+ && (p_dev_rec->sec_state == state))
+ return(p_dev_rec);
+ }
+ return(NULL);
+}
+
+/*******************************************************************************
+**
+** Function BTM_snd_conn_encrypt
+**
+** Description This function is called to start/stop encryption
+** Used by JSR-82
+**
+** Returns TRUE if request started
+**
+*******************************************************************************/
+BOOLEAN BTM_snd_conn_encrypt (UINT16 handle, BOOLEAN enable)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev_by_handle (handle);
+
+ BTM_TRACE_EVENT2 ("BTM_snd_conn_encrypt Security Manager: encrypt_change p_dev_rec : 0x%x, enable = %s", p_dev_rec, (enable == TRUE) ? "TRUE" : "FALSE");
+
+ if (!p_dev_rec)
+ {
+ BTM_TRACE_EVENT1 ("BTM_snd_conn_encrypt Error no p_dev_rec : 0x%x\n", p_dev_rec);
+ return(FALSE);
+ }
+
+ if ( p_dev_rec->sec_state == BTM_SEC_STATE_IDLE)
+ {
+ if (!btsnd_hcic_set_conn_encrypt (handle, enable))
+ return(FALSE);
+
+ p_dev_rec->sec_state = BTM_SEC_STATE_ENCRYPTING;
+
+ return(TRUE);
+ }
+ else
+ return(FALSE);
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_change_pairing_state
+**
+** Description This function is called to change pairing state
+**
+*******************************************************************************/
+static void btm_sec_change_pairing_state (tBTM_PAIRING_STATE new_state)
+{
+ tBTM_PAIRING_STATE old_state = btm_cb.pairing_state;
+
+ BTM_TRACE_EVENT1 ("btm_sec_change_pairing_state Old: %s", btm_pair_state_descr(btm_cb.pairing_state));
+ BTM_TRACE_EVENT2 ("btm_sec_change_pairing_state New: %s pairing_flags:0x%x",btm_pair_state_descr(new_state), btm_cb.pairing_flags);
+
+ btm_cb.pairing_state = new_state;
+
+ if (new_state == BTM_PAIR_STATE_IDLE)
+ {
+ btu_stop_timer (&btm_cb.pairing_tle);
+
+ btm_cb.pairing_flags = 0;
+ btm_cb.pin_code_len = 0;
+
+ /* Make sure the the lcb shows we are not bonding */
+ l2cu_update_lcb_4_bonding (btm_cb.pairing_bda, FALSE);
+
+ btm_restore_mode();
+ btm_sec_check_pending_reqs();
+ btm_inq_clear_ssp();
+
+ memset (btm_cb.pairing_bda, 0xFF, BD_ADDR_LEN);
+ }
+ else
+ {
+ /* If transitionng out of idle, mark the lcb as bonding */
+ if (old_state == BTM_PAIR_STATE_IDLE)
+ l2cu_update_lcb_4_bonding (btm_cb.pairing_bda, TRUE);
+
+ btm_cb.pairing_tle.param = (TIMER_PARAM_TYPE)btm_sec_pairing_timeout;
+
+ btu_start_timer (&btm_cb.pairing_tle, BTU_TTYPE_USER_FUNC, BTM_SEC_TIMEOUT_VALUE);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function btm_pair_state_descr
+**
+** Description Return state description for tracing
+**
+*******************************************************************************/
+#if (BT_USE_TRACES == TRUE)
+static char *btm_pair_state_descr (tBTM_PAIRING_STATE state)
+{
+#if (BT_TRACE_VERBOSE == TRUE)
+ switch (state)
+ {
+ case BTM_PAIR_STATE_IDLE: return("IDLE");
+ case BTM_PAIR_STATE_GET_REM_NAME: return("GET_REM_NAME");
+ case BTM_PAIR_STATE_WAIT_PIN_REQ: return("WAIT_PIN_REQ");
+ case BTM_PAIR_STATE_WAIT_LOCAL_PIN: return("WAIT_LOCAL_PIN");
+ case BTM_PAIR_STATE_WAIT_NUMERIC_CONFIRM: return("WAIT_NUM_CONFIRM");
+ case BTM_PAIR_STATE_KEY_ENTRY: return("KEY_ENTRY");
+ case BTM_PAIR_STATE_WAIT_LOCAL_OOB_RSP: return("WAIT_LOCAL_OOB_RSP");
+ case BTM_PAIR_STATE_WAIT_LOCAL_IOCAPS: return("WAIT_LOCAL_IOCAPS");
+ case BTM_PAIR_STATE_INCOMING_SSP: return("INCOMING_SSP");
+ case BTM_PAIR_STATE_WAIT_AUTH_COMPLETE: return("WAIT_AUTH_COMPLETE");
+ case BTM_PAIR_STATE_WAIT_DISCONNECT: return("WAIT_DISCONNECT");
+ }
+
+ return("???");
+#else
+ sprintf(btm_cb.state_temp_buffer,"%hu",state);
+
+ return(btm_cb.state_temp_buffer);
+#endif
+}
+#endif
+
+
+/*******************************************************************************
+**
+** Function btm_sec_dev_rec_cback_event
+**
+** Description This function calls the callback function with the given
+** result and clear the callback function.
+**
+** Parameters: void
+**
+*******************************************************************************/
+void btm_sec_dev_rec_cback_event (tBTM_SEC_DEV_REC *p_dev_rec, UINT8 res)
+{
+ tBTM_SEC_CALLBACK *p_callback = p_dev_rec->p_callback;
+
+ if (p_dev_rec->p_callback)
+ {
+ p_dev_rec->p_callback = NULL;
+
+ (*p_callback) (p_dev_rec->bd_addr, p_dev_rec->p_ref_data, res);
+
+ }
+ btm_sec_check_pending_reqs();
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_queue_mx_request
+**
+** Description Return state description for tracing
+**
+*******************************************************************************/
+static BOOLEAN btm_sec_queue_mx_request (BD_ADDR bd_addr, UINT16 psm, BOOLEAN is_orig,
+ UINT32 mx_proto_id, UINT32 mx_chan_id,
+ tBTM_SEC_CALLBACK *p_callback, void *p_ref_data)
+{
+ tBTM_SEC_QUEUE_ENTRY *p_e;
+
+ p_e = (tBTM_SEC_QUEUE_ENTRY *)GKI_getbuf (sizeof(tBTM_SEC_QUEUE_ENTRY));
+
+ if (p_e)
+ {
+ p_e->psm = psm;
+ p_e->is_orig = is_orig;
+ p_e->p_callback = p_callback;
+ p_e->p_ref_data = p_ref_data;
+ p_e->mx_proto_id = mx_proto_id;
+ p_e->mx_chan_id = mx_chan_id;
+
+ memcpy (p_e->bd_addr, bd_addr, BD_ADDR_LEN);
+
+ BTM_TRACE_EVENT4 ("btm_sec_queue_mx_request() PSM: 0x%04x Is_Orig: %u mx_proto_id: %u mx_chan_id: %u",
+ psm, is_orig, mx_proto_id, mx_chan_id);
+
+ GKI_enqueue (&btm_cb.sec_pending_q, p_e);
+
+ return(TRUE);
+ }
+
+ return(FALSE);
+}
+
+static BOOLEAN btm_sec_check_prefetch_pin (tBTM_SEC_DEV_REC *p_dev_rec)
+{
+ UINT8 major = (UINT8)(p_dev_rec->dev_class[1] & BTM_COD_MAJOR_CLASS_MASK);
+ UINT8 minor = (UINT8)(p_dev_rec->dev_class[2] & BTM_COD_MINOR_CLASS_MASK);
+ BOOLEAN rv = FALSE;
+
+ if ((major == BTM_COD_MAJOR_AUDIO)
+ && ((minor == BTM_COD_MINOR_CONFM_HANDSFREE) || (minor == BTM_COD_MINOR_CAR_AUDIO)) )
+ {
+ BTM_TRACE_EVENT2 ("btm_sec_check_prefetch_pin: Skipping pre-fetch PIN for carkit COD Major: 0x%02x Minor: 0x%02x", major, minor);
+
+ if (btm_cb.security_mode_changed == FALSE)
+ {
+ btm_cb.security_mode_changed = TRUE;
+#ifdef APPL_AUTH_WRITE_EXCEPTION
+ if(!(APPL_AUTH_WRITE_EXCEPTION)(p_dev_rec->bd_addr))
+#endif
+ btsnd_hcic_write_auth_enable (TRUE);
+ }
+ }
+ else
+ {
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_LOCAL_PIN);
+
+ /* If we got a PIN, use that, else try to get one */
+ if (btm_cb.pin_code_len)
+ {
+ BTM_PINCodeReply (p_dev_rec->bd_addr, BTM_SUCCESS, btm_cb.pin_code_len, btm_cb.pin_code, p_dev_rec->trusted_mask);
+ }
+ else
+ {
+ /* pin was not supplied - pre-fetch pin code now */
+ if (btm_cb.api.p_pin_callback && ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_PIN_REQD) == 0))
+ {
+ BTM_TRACE_DEBUG0("btm_sec_check_prefetch_pin: PIN code callback called");
+ if (btm_bda_to_acl(p_dev_rec->bd_addr) == NULL)
+ btm_cb.pairing_flags |= BTM_PAIR_FLAGS_PIN_REQD;
+ (btm_cb.api.p_pin_callback) (p_dev_rec->bd_addr, p_dev_rec->dev_class, p_dev_rec->sec_bd_name);
+ }
+ }
+
+ rv = TRUE;
+ }
+
+ return rv;
+}
+
+#if (BLE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function btm_sec_clear_ble_keys
+**
+** Description This function is called to clear out the BLE keys.
+** Typically when devices are removed in BTM_SecDeleteDevice,
+** or when a new BT Link key is generated.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sec_clear_ble_keys (tBTM_SEC_DEV_REC *p_dev_rec)
+{
+
+ BTM_TRACE_DEBUG0 ("btm_sec_clear_ble_keys: Clearing BLE Keys");
+#if (SMP_INCLUDED== TRUE)
+ p_dev_rec->ble.key_type = 0;
+ memset (&p_dev_rec->ble.keys, 0, sizeof(tBTM_SEC_BLE_KEYS));
+#endif
+ gatt_delete_dev_from_srv_chg_clt_list(p_dev_rec->bd_addr);
+}
+
+
+/*******************************************************************************
+**
+** Function btm_sec_is_a_bonded_dev
+**
+** Description Is the specified device is a bonded device
+**
+** Returns TRUE - dev is bonded
+**
+*******************************************************************************/
+BOOLEAN btm_sec_is_a_bonded_dev (BD_ADDR bda)
+{
+
+ tBTM_SEC_DEV_REC *p_dev_rec= btm_find_dev (bda);
+ BOOLEAN is_bonded= FALSE;
+
+#if (SMP_INCLUDED== TRUE)
+ if (p_dev_rec && (p_dev_rec->ble.key_type || (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN)))
+ {
+ is_bonded = TRUE;
+ }
+#endif
+ BTM_TRACE_DEBUG1 ("btm_sec_is_a_bonded_dev is_bonded=%d", is_bonded);
+ return(is_bonded);
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_find_bonded_dev
+**
+** Description Find a bonded device starting from the specified index
+**
+** Returns TRUE - found a bonded device
+**
+*******************************************************************************/
+BOOLEAN btm_sec_find_bonded_dev (UINT8 start_idx, UINT8 *p_found_idx, tBTM_SEC_DEV_REC *p_rec)
+{
+ BOOLEAN found= FALSE;
+
+#if (SMP_INCLUDED== TRUE)
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ int i;
+ if (start_idx >= BTM_SEC_MAX_DEVICE_RECORDS)
+ {
+ BTM_TRACE_DEBUG0 ("LE bonded device not found");
+ return found;
+ }
+
+ p_dev_rec = &btm_cb.sec_dev_rec[start_idx];
+ for (i = start_idx; i < BTM_SEC_MAX_DEVICE_RECORDS; i++, p_dev_rec++)
+ {
+ if (p_dev_rec->ble.key_type || (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN))
+ {
+ *p_found_idx = i;
+ p_rec = p_dev_rec;
+ break;
+ }
+ }
+ BTM_TRACE_DEBUG1 ("btm_sec_find_bonded_dev=%d", found);
+#endif
+ return(found);
+}
+#endif /* BLE_INCLUDED */
+
diff --git a/stack/btu/btu_hcif.c b/stack/btu/btu_hcif.c
new file mode 100644
index 0000000..26b0b8f
--- /dev/null
+++ b/stack/btu/btu_hcif.c
@@ -0,0 +1,2257 @@
+/*****************************************************************************
+**
+** Name: btu_hcif.c
+**
+** Description: This file contains functions that interface with the HCI
+** transport. On the receive side, it routes events to
+** the appropriate handler, e.g. L2CAP, ScoMgr. On the
+** transmit side, it manages the command transmission.
+**
+**
+** Copyright (c) 1999-2012, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "gki.h"
+#include "bt_types.h"
+#include "hcimsgs.h"
+#include "btu.h"
+#include "l2c_int.h"
+#include "btm_api.h"
+#include "btm_int.h"
+
+// btla-specific ++
+#define LOG_TAG "BTLD"
+#if (defined(ANDROID_APP_INCLUDED) && (ANDROID_APP_INCLUDED == TRUE) && (!defined(LINUX_NATIVE)) )
+#include <cutils/log.h>
+#else
+#define LOGV(format, ...) fprintf (stdout, LOG_TAG format"\n", ## __VA_ARGS__)
+#define LOGE(format, ...) fprintf (stderr, LOG_TAG format"\n", ## __VA_ARGS__)
+#define LOGI(format, ...) fprintf (stdout, LOG_TAG format"\n", ## __VA_ARGS__)
+#endif
+
+// btla-specific ++
+/* BTE application task */
+#if APPL_INCLUDED == TRUE
+#include "bte_appl.h"
+#endif
+// btla-specific --
+
+/********************************************************************************/
+/* L O C A L F U N C T I O N P R O T O T Y P E S */
+/********************************************************************************/
+static void btu_hcif_inquiry_comp_evt (UINT8 *p, UINT16 evt_len);
+static void btu_hcif_inquiry_result_evt (UINT8 *p, UINT16 evt_len);
+static void btu_hcif_inquiry_rssi_result_evt (UINT8 *p, UINT16 evt_len);
+#if (BTM_EIR_CLIENT_INCLUDED == TRUE)
+static void btu_hcif_extended_inquiry_result_evt (UINT8 *p, UINT16 evt_len);
+#endif
+
+static void btu_hcif_connection_comp_evt (UINT8 *p, UINT16 evt_len);
+static void btu_hcif_connection_request_evt (UINT8 *p, UINT16 evt_len);
+static void btu_hcif_disconnection_comp_evt (UINT8 *p, UINT16 evt_len);
+static void btu_hcif_authentication_comp_evt (UINT8 *p, UINT16 evt_len);
+static void btu_hcif_rmt_name_request_comp_evt (UINT8 *p, UINT16 evt_len);
+static void btu_hcif_encryption_change_evt (UINT8 *p, UINT16 evt_len);
+static void btu_hcif_change_conn_link_key_evt (UINT8 *p, UINT16 evt_len);
+static void btu_hcif_master_link_key_comp_evt (UINT8 *p, UINT16 evt_len);
+static void btu_hcif_read_rmt_features_comp_evt (UINT8 *p, UINT16 evt_len);
+static void btu_hcif_read_rmt_ext_features_comp_evt (UINT8 *p, UINT16 evt_len);
+static void btu_hcif_read_rmt_version_comp_evt (UINT8 *p, UINT16 evt_len);
+static void btu_hcif_qos_setup_comp_evt (UINT8 *p, UINT16 evt_len);
+static void btu_hcif_command_complete_evt (UINT8 controller_id, UINT8 *p, UINT16 evt_len);
+static void btu_hcif_command_status_evt (UINT8 controller_id, UINT8 *p, UINT16 evt_len);
+static void btu_hcif_hardware_error_evt (UINT8 *p, UINT16 evt_len);
+static void btu_hcif_flush_occured_evt (UINT8 *p, UINT16 evt_len);
+static void btu_hcif_role_change_evt (UINT8 *p, UINT16 evt_len);
+static void btu_hcif_num_compl_data_pkts_evt (UINT8 *p, UINT16 evt_len);
+static void btu_hcif_mode_change_evt (UINT8 *p, UINT16 evt_len);
+static void btu_hcif_return_link_keys_evt (UINT8 *p, UINT16 evt_len);
+static void btu_hcif_pin_code_request_evt (UINT8 *p, UINT16 evt_len);
+static void btu_hcif_link_key_request_evt (UINT8 *p, UINT16 evt_len);
+static void btu_hcif_link_key_notification_evt (UINT8 *p, UINT16 evt_len);
+static void btu_hcif_loopback_command_evt (UINT8 *p, UINT16 evt_len);
+static void btu_hcif_data_buf_overflow_evt (UINT8 *p, UINT16 evt_len);
+static void btu_hcif_max_slots_changed_evt (UINT8 *p, UINT16 evt_len);
+static void btu_hcif_read_clock_off_comp_evt (UINT8 *p, UINT16 evt_len);
+static void btu_hcif_conn_pkt_type_change_evt (UINT8 *p, UINT16 evt_len);
+static void btu_hcif_qos_violation_evt (UINT8 *p, UINT16 evt_len);
+static void btu_hcif_page_scan_mode_change_evt (UINT8 *p, UINT16 evt_len);
+static void btu_hcif_page_scan_rep_mode_chng_evt (UINT8 *p, UINT16 evt_len);
+static void btu_hcif_esco_connection_comp_evt(UINT8 *p, UINT16 evt_len);
+static void btu_hcif_esco_connection_chg_evt(UINT8 *p, UINT16 evt_len);
+
+/* Simple Pairing Events */
+static void btu_hcif_host_support_evt (UINT8 *p, UINT16 evt_len);
+static void btu_hcif_io_cap_request_evt (UINT8 *p, UINT16 evt_len);
+static void btu_hcif_io_cap_response_evt (UINT8 *p, UINT16 evt_len);
+static void btu_hcif_user_conf_request_evt (UINT8 *p, UINT16 evt_len);
+static void btu_hcif_user_passkey_request_evt (UINT8 *p, UINT16 evt_len);
+static void btu_hcif_user_passkey_notif_evt (UINT8 *p, UINT16 evt_len);
+static void btu_hcif_keypress_notif_evt (UINT8 *p, UINT16 evt_len);
+static void btu_hcif_link_super_tout_evt (UINT8 *p, UINT16 evt_len);
+
+ #if BTM_OOB_INCLUDED == TRUE
+static void btu_hcif_rem_oob_request_evt (UINT8 *p, UINT16 evt_len);
+ #endif
+
+static void btu_hcif_simple_pair_complete_evt (UINT8 *p, UINT16 evt_len);
+ #if L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE
+static void btu_hcif_enhanced_flush_complete_evt (UINT8 *p, UINT16 evt_len);
+ #endif
+
+ #if (BTM_SSR_INCLUDED == TRUE)
+static void btu_hcif_ssr_evt (UINT8 *p, UINT16 evt_len);
+ #endif /* BTM_SSR_INCLUDED == TRUE */
+
+ #if (HID_DEV_INCLUDED == TRUE) && (HID_DEV_PM_INCLUDED == TRUE)
+extern void hidd_pm_proc_mode_change( UINT8 hci_status, UINT8 mode, UINT16 interval );
+ #endif
+
+
+ #if BLE_INCLUDED == TRUE
+static void btu_ble_ll_conn_complete_evt (UINT8 *p, UINT16 evt_len);
+static void btu_ble_process_adv_pkt (UINT8 *p, UINT16 evt_len);
+static void btu_ble_read_remote_feat_evt (UINT8 *p, UINT16 evt_len);
+static void btu_ble_ll_conn_param_upd_evt (UINT8 *p, UINT16 evt_len);
+static void btu_ble_proc_ltk_req (UINT8 *p, UINT16 evt_len);
+static void btu_hcif_encyption_key_refresh_cmpl_evt (UINT8 *p, UINT16 evt_len);
+ #endif
+/*******************************************************************************
+**
+** Function btu_hcif_store_cmd
+**
+** Description This function stores a copy of an outgoing command and
+** and sets a timer waiting for a event in response to the
+** command.
+**
+** Returns void
+**
+*******************************************************************************/
+static void btu_hcif_store_cmd (UINT8 controller_id, BT_HDR *p_buf)
+{
+ tHCI_CMD_CB * p_hci_cmd_cb = &(btu_cb.hci_cmd_cb[controller_id]);
+ UINT16 opcode;
+ BT_HDR *p_cmd;
+ UINT8 *p = (UINT8 *)(p_buf + 1) + p_buf->offset;
+
+ /* get command opcode */
+ STREAM_TO_UINT16 (opcode, p);
+
+ /* don't do anything for certain commands */
+ if ((opcode == HCI_RESET) || (opcode == HCI_HOST_NUM_PACKETS_DONE))
+ {
+ return;
+ }
+
+ /* allocate buffer (HCI_GET_CMD_BUF will either get a buffer from HCI_CMD_POOL or from 'best-fit' pool) */
+ if ((p_cmd = HCI_GET_CMD_BUF(p_buf->len + p_buf->offset - HCIC_PREAMBLE_SIZE)) == NULL)
+ {
+ return;
+ }
+
+ /* copy buffer */
+ memcpy (p_cmd, p_buf, sizeof(BT_HDR));
+
+ /* If vendor specific save the callback function */
+ if ((opcode & HCI_GRP_VENDOR_SPECIFIC) == HCI_GRP_VENDOR_SPECIFIC
+#if BLE_INCLUDED == TRUE
+ || (opcode == HCI_BLE_RAND )
+ || (opcode == HCI_BLE_ENCRYPT)
+#endif
+ )
+ {
+#if 0
+ BT_TRACE_2 (TRACE_LAYER_HCI, TRACE_TYPE_DEBUG,
+ "Storing VSC callback opcode=0x%04x, Callback function=0x%07x",
+ opcode, *(UINT32 *)(p_buf + 1));
+#endif
+ memcpy ((UINT8 *)(p_cmd + 1), (UINT8 *)(p_buf + 1), sizeof(void *));
+ }
+
+ memcpy ((UINT8 *)(p_cmd + 1) + p_cmd->offset,
+ (UINT8 *)(p_buf + 1) + p_buf->offset, p_buf->len);
+
+ /* queue copy of cmd */
+ GKI_enqueue(&(p_hci_cmd_cb->cmd_cmpl_q), p_cmd);
+
+ /* start timer */
+ if (BTU_CMD_CMPL_TIMEOUT > 0)
+ {
+#if (defined(BTU_CMD_CMPL_TOUT_DOUBLE_CHECK) && BTU_CMD_CMPL_TOUT_DOUBLE_CHECK == TRUE)
+ p_hci_cmd_cb->checked_hcisu = FALSE;
+#endif
+ btu_start_timer (&(p_hci_cmd_cb->cmd_cmpl_timer),
+ (UINT16)(BTU_TTYPE_BTU_CMD_CMPL + controller_id),
+ BTU_CMD_CMPL_TIMEOUT);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btu_hcif_process_event
+**
+** Description This function is called when an event is received from
+** the Host Controller.
+**
+** Returns void
+**
+*******************************************************************************/
+void btu_hcif_process_event (UINT8 controller_id, BT_HDR *p_msg)
+{
+ UINT8 *p = (UINT8 *)(p_msg + 1) + p_msg->offset;
+ UINT8 hci_evt_code, hci_evt_len;
+#if BLE_INCLUDED == TRUE
+ UINT8 ble_sub_code;
+#endif
+ STREAM_TO_UINT8 (hci_evt_code, p);
+ STREAM_TO_UINT8 (hci_evt_len, p);
+
+ switch (hci_evt_code)
+ {
+ case HCI_INQUIRY_COMP_EVT:
+ btu_hcif_inquiry_comp_evt (p, hci_evt_len);
+ break;
+ case HCI_INQUIRY_RESULT_EVT:
+ btu_hcif_inquiry_result_evt (p, hci_evt_len);
+ break;
+ case HCI_INQUIRY_RSSI_RESULT_EVT:
+ btu_hcif_inquiry_rssi_result_evt (p, hci_evt_len);
+ break;
+#if (BTM_EIR_CLIENT_INCLUDED == TRUE)
+ case HCI_EXTENDED_INQUIRY_RESULT_EVT:
+ btu_hcif_extended_inquiry_result_evt (p, hci_evt_len);
+ break;
+#endif
+ case HCI_CONNECTION_COMP_EVT:
+ btu_hcif_connection_comp_evt (p, hci_evt_len);
+ break;
+ case HCI_CONNECTION_REQUEST_EVT:
+ btu_hcif_connection_request_evt (p, hci_evt_len);
+ break;
+ case HCI_DISCONNECTION_COMP_EVT:
+ btu_hcif_disconnection_comp_evt (p, hci_evt_len);
+ break;
+ case HCI_AUTHENTICATION_COMP_EVT:
+ btu_hcif_authentication_comp_evt (p, hci_evt_len);
+ break;
+ case HCI_RMT_NAME_REQUEST_COMP_EVT:
+ btu_hcif_rmt_name_request_comp_evt (p, hci_evt_len);
+ break;
+ case HCI_ENCRYPTION_CHANGE_EVT:
+ btu_hcif_encryption_change_evt (p, hci_evt_len);
+ break;
+#if BLE_INCLUDED == TRUE
+ case HCI_ENCRYPTION_KEY_REFRESH_COMP_EVT:
+ btu_hcif_encyption_key_refresh_cmpl_evt(p, hci_evt_len);
+ break;
+#endif
+ case HCI_CHANGE_CONN_LINK_KEY_EVT:
+ btu_hcif_change_conn_link_key_evt (p, hci_evt_len);
+ break;
+ case HCI_MASTER_LINK_KEY_COMP_EVT:
+ btu_hcif_master_link_key_comp_evt (p, hci_evt_len);
+ break;
+ case HCI_READ_RMT_FEATURES_COMP_EVT:
+ btu_hcif_read_rmt_features_comp_evt (p, hci_evt_len);
+ break;
+ case HCI_READ_RMT_EXT_FEATURES_COMP_EVT:
+ btu_hcif_read_rmt_ext_features_comp_evt (p, hci_evt_len);
+ break;
+ case HCI_READ_RMT_VERSION_COMP_EVT:
+ btu_hcif_read_rmt_version_comp_evt (p, hci_evt_len);
+ break;
+ case HCI_QOS_SETUP_COMP_EVT:
+ btu_hcif_qos_setup_comp_evt (p, hci_evt_len);
+ break;
+ case HCI_COMMAND_COMPLETE_EVT:
+ btu_hcif_command_complete_evt (controller_id, p, hci_evt_len);
+ break;
+ case HCI_COMMAND_STATUS_EVT:
+ btu_hcif_command_status_evt (controller_id, p, hci_evt_len);
+ break;
+ case HCI_HARDWARE_ERROR_EVT:
+ btu_hcif_hardware_error_evt (p, hci_evt_len);
+ break;
+ case HCI_FLUSH_OCCURED_EVT:
+ btu_hcif_flush_occured_evt (p, hci_evt_len);
+ break;
+ case HCI_ROLE_CHANGE_EVT:
+ btu_hcif_role_change_evt (p, hci_evt_len);
+ break;
+ case HCI_NUM_COMPL_DATA_PKTS_EVT:
+ btu_hcif_num_compl_data_pkts_evt (p, hci_evt_len);
+ break;
+ case HCI_MODE_CHANGE_EVT:
+ btu_hcif_mode_change_evt (p, hci_evt_len);
+ break;
+ case HCI_RETURN_LINK_KEYS_EVT:
+ btu_hcif_return_link_keys_evt (p, hci_evt_len);
+ break;
+ case HCI_PIN_CODE_REQUEST_EVT:
+ btu_hcif_pin_code_request_evt (p, hci_evt_len);
+ break;
+ case HCI_LINK_KEY_REQUEST_EVT:
+ btu_hcif_link_key_request_evt (p, hci_evt_len);
+ break;
+ case HCI_LINK_KEY_NOTIFICATION_EVT:
+ btu_hcif_link_key_notification_evt (p, hci_evt_len);
+ break;
+ case HCI_LOOPBACK_COMMAND_EVT:
+ btu_hcif_loopback_command_evt (p, hci_evt_len);
+ break;
+ case HCI_DATA_BUF_OVERFLOW_EVT:
+ btu_hcif_data_buf_overflow_evt (p, hci_evt_len);
+ break;
+ case HCI_MAX_SLOTS_CHANGED_EVT:
+ btu_hcif_max_slots_changed_evt (p, hci_evt_len);
+ break;
+ case HCI_READ_CLOCK_OFF_COMP_EVT:
+ btu_hcif_read_clock_off_comp_evt (p, hci_evt_len);
+ break;
+ case HCI_CONN_PKT_TYPE_CHANGE_EVT:
+ btu_hcif_conn_pkt_type_change_evt (p, hci_evt_len);
+ break;
+ case HCI_QOS_VIOLATION_EVT:
+ btu_hcif_qos_violation_evt (p, hci_evt_len);
+ break;
+ case HCI_PAGE_SCAN_MODE_CHANGE_EVT:
+ btu_hcif_page_scan_mode_change_evt (p, hci_evt_len);
+ break;
+ case HCI_PAGE_SCAN_REP_MODE_CHNG_EVT:
+ btu_hcif_page_scan_rep_mode_chng_evt (p, hci_evt_len);
+ break;
+ case HCI_ESCO_CONNECTION_COMP_EVT:
+ btu_hcif_esco_connection_comp_evt (p, hci_evt_len);
+ break;
+ case HCI_ESCO_CONNECTION_CHANGED_EVT:
+ btu_hcif_esco_connection_chg_evt (p, hci_evt_len);
+ break;
+#if (BTM_SSR_INCLUDED == TRUE)
+ case HCI_SNIFF_SUB_RATE_EVT:
+ btu_hcif_ssr_evt (p, hci_evt_len);
+ break;
+#endif /* BTM_SSR_INCLUDED == TRUE */
+ case HCI_RMT_HOST_SUP_FEAT_NOTIFY_EVT:
+ btu_hcif_host_support_evt (p, hci_evt_len);
+ break;
+ case HCI_IO_CAPABILITY_REQUEST_EVT:
+ btu_hcif_io_cap_request_evt (p, hci_evt_len);
+ break;
+ case HCI_IO_CAPABILITY_RESPONSE_EVT:
+ btu_hcif_io_cap_response_evt (p, hci_evt_len);
+ break;
+ case HCI_USER_CONFIRMATION_REQUEST_EVT:
+ btu_hcif_user_conf_request_evt (p, hci_evt_len);
+ break;
+ case HCI_USER_PASSKEY_REQUEST_EVT:
+ btu_hcif_user_passkey_request_evt (p, hci_evt_len);
+ break;
+#if BTM_OOB_INCLUDED == TRUE
+ case HCI_REMOTE_OOB_DATA_REQUEST_EVT:
+ btu_hcif_rem_oob_request_evt (p, hci_evt_len);
+ break;
+#endif
+ case HCI_SIMPLE_PAIRING_COMPLETE_EVT:
+ btu_hcif_simple_pair_complete_evt (p, hci_evt_len);
+ break;
+ case HCI_USER_PASSKEY_NOTIFY_EVT:
+ btu_hcif_user_passkey_notif_evt (p, hci_evt_len);
+ break;
+ case HCI_KEYPRESS_NOTIFY_EVT:
+ btu_hcif_keypress_notif_evt (p, hci_evt_len);
+ break;
+ case HCI_LINK_SUPER_TOUT_CHANGED_EVT:
+ btu_hcif_link_super_tout_evt (p, hci_evt_len);
+ break;
+#if L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE
+ case HCI_ENHANCED_FLUSH_COMPLETE_EVT:
+ btu_hcif_enhanced_flush_complete_evt (p, hci_evt_len);
+ break;
+#endif
+
+#if (BLE_INCLUDED == TRUE)
+ case HCI_BLE_EVENT:
+ STREAM_TO_UINT8 (ble_sub_code, p);
+
+ BT_TRACE_2 (TRACE_LAYER_HCI, TRACE_TYPE_EVENT, "BLE HCI(id=%d) event = 0x%02x)",
+ hci_evt_code, ble_sub_code);
+
+ switch (ble_sub_code)
+ {
+ case HCI_BLE_ADV_PKT_RPT_EVT: /* result of inquiry */
+ btu_ble_process_adv_pkt(p, hci_evt_len);
+ break;
+ case HCI_BLE_CONN_COMPLETE_EVT:
+ btu_ble_ll_conn_complete_evt(p, hci_evt_len);
+ break;
+ case HCI_BLE_LL_CONN_PARAM_UPD_EVT:
+ btu_ble_ll_conn_param_upd_evt(p, hci_evt_len);
+ break;
+ case HCI_BLE_READ_REMOTE_FEAT_CMPL_EVT:
+ btu_ble_read_remote_feat_evt(p, hci_evt_len);
+ break;
+ case HCI_BLE_LTK_REQ_EVT: /* received only at slave device */
+ btu_ble_proc_ltk_req(p, hci_evt_len);
+ break;
+ }
+ break;
+#endif /* BLE_INCLUDED */
+ case HCI_VENDOR_SPECIFIC_EVT:
+ btm_vendor_specific_evt (p, hci_evt_len);
+ break;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function btu_hcif_send_cmd
+**
+** Description This function is called to check if it can send commands
+** to the Host Controller. It may be passed the address of
+** a packet to send.
+**
+** Returns void
+**
+*******************************************************************************/
+void btu_hcif_send_cmd (UINT8 controller_id, BT_HDR *p_buf)
+{
+ tHCI_CMD_CB * p_hci_cmd_cb = &(btu_cb.hci_cmd_cb[controller_id]);
+
+#if ((L2CAP_HOST_FLOW_CTRL == TRUE)||defined(HCI_TESTER))
+ UINT8 *pp;
+ UINT16 code;
+#endif
+
+ /* If there are already commands in the queue, then enqueue this command */
+ if ((p_buf) && (p_hci_cmd_cb->cmd_xmit_q.count))
+ {
+ GKI_enqueue (&(p_hci_cmd_cb->cmd_xmit_q), p_buf);
+ p_buf = NULL;
+ }
+
+ /* Allow for startup case, where no acks may be received */
+ if ( ((controller_id == LOCAL_BR_EDR_CONTROLLER_ID)
+ && (p_hci_cmd_cb->cmd_window == 0)
+ && (btm_cb.devcb.state == BTM_DEV_STATE_WAIT_RESET_CMPLT)) )
+ {
+ p_hci_cmd_cb->cmd_window = p_hci_cmd_cb->cmd_xmit_q.count + 1;
+ }
+
+ /* See if we can send anything */
+ while (p_hci_cmd_cb->cmd_window != 0)
+ {
+ if (!p_buf)
+ p_buf = (BT_HDR *)GKI_dequeue (&(p_hci_cmd_cb->cmd_xmit_q));
+
+ if (p_buf)
+ {
+ btu_hcif_store_cmd(controller_id, p_buf);
+
+#if ((L2CAP_HOST_FLOW_CTRL == TRUE)||defined(HCI_TESTER))
+ pp = (UINT8 *)(p_buf + 1) + p_buf->offset;
+
+ STREAM_TO_UINT16 (code, pp);
+
+ /*
+ * We do not need to decrease window for host flow control,
+ * host flow control does not receive an event back from controller
+ */
+ if (code != HCI_HOST_NUM_PACKETS_DONE)
+#endif
+ p_hci_cmd_cb->cmd_window--;
+
+ if (controller_id == LOCAL_BR_EDR_CONTROLLER_ID)
+ {
+ HCI_CMD_TO_LOWER(p_buf);
+ }
+ else
+ {
+ /* Unknown controller */
+ BT_TRACE_1 (TRACE_LAYER_HCI, TRACE_TYPE_WARNING, "BTU HCI(ctrl id=%d) controller ID not recognized", controller_id);
+ GKI_freebuf(p_buf);;
+ }
+
+ p_buf = NULL;
+ }
+ else
+ break;
+ }
+
+ if (p_buf)
+ GKI_enqueue (&(p_hci_cmd_cb->cmd_xmit_q), p_buf);
+
+#if (defined(HCILP_INCLUDED) && HCILP_INCLUDED == TRUE)
+ if (controller_id == LOCAL_BR_EDR_CONTROLLER_ID)
+ {
+ /* check if controller can go to sleep */
+ btu_check_bt_sleep ();
+ }
+#endif
+
+}
+
+
+/*******************************************************************************
+**
+** Function btu_hcif_send_host_rdy_for_data
+**
+** Description This function is called to check if it can send commands
+** to the Host Controller. It may be passed the address of
+** a packet to send.
+**
+** Returns void
+**
+*******************************************************************************/
+void btu_hcif_send_host_rdy_for_data(void)
+{
+ UINT16 num_pkts[MAX_L2CAP_LINKS + 4]; /* 3 SCO connections */
+ UINT16 handles[MAX_L2CAP_LINKS + 4];
+ UINT8 num_ents;
+
+ /* Get the L2CAP numbers */
+ num_ents = l2c_link_pkts_rcvd (num_pkts, handles);
+
+ /* Get the SCO numbers */
+ /* No SCO for now ?? */
+
+ if (num_ents)
+ {
+ btsnd_hcic_host_num_xmitted_pkts (num_ents, handles, num_pkts);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btu_hcif_inquiry_comp_evt
+**
+** Description Process event HCI_INQUIRY_COMP_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+static void btu_hcif_inquiry_comp_evt (UINT8 *p, UINT16 evt_len)
+{
+ UINT8 status;
+
+ STREAM_TO_UINT8 (status, p);
+
+ /* Tell inquiry processing that we are done */
+ btm_process_inq_complete(status, BTM_BR_INQUIRY_MASK);
+}
+
+
+/*******************************************************************************
+**
+** Function btu_hcif_inquiry_result_evt
+**
+** Description Process event HCI_INQUIRY_RESULT_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+static void btu_hcif_inquiry_result_evt (UINT8 *p, UINT16 evt_len)
+{
+ /* Store results in the cache */
+ btm_process_inq_results (p, BTM_INQ_RESULT_STANDARD);
+}
+
+/*******************************************************************************
+**
+** Function btu_hcif_inquiry_rssi_result_evt
+**
+** Description Process event HCI_INQUIRY_RSSI_RESULT_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+static void btu_hcif_inquiry_rssi_result_evt (UINT8 *p, UINT16 evt_len)
+{
+ /* Store results in the cache */
+ btm_process_inq_results (p, BTM_INQ_RESULT_WITH_RSSI);
+}
+
+/*******************************************************************************
+**
+** Function btu_hcif_extended_inquiry_result_evt
+**
+** Description Process event HCI_EXTENDED_INQUIRY_RESULT_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+#if (BTM_EIR_CLIENT_INCLUDED == TRUE)
+static void btu_hcif_extended_inquiry_result_evt (UINT8 *p, UINT16 evt_len)
+{
+ /* Store results in the cache */
+ btm_process_inq_results (p, BTM_INQ_RESULT_EXTENDED);
+}
+#endif
+
+/*******************************************************************************
+**
+** Function btu_hcif_connection_comp_evt
+**
+** Description Process event HCI_CONNECTION_COMP_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+static void btu_hcif_connection_comp_evt (UINT8 *p, UINT16 evt_len)
+{
+ UINT8 status;
+ UINT16 handle;
+ BD_ADDR bda;
+ UINT8 link_type;
+ UINT8 enc_mode;
+#if BTM_SCO_INCLUDED == TRUE
+ tBTM_ESCO_DATA esco_data;
+#endif
+
+ STREAM_TO_UINT8 (status, p);
+ STREAM_TO_UINT16 (handle, p);
+ STREAM_TO_BDADDR (bda, p);
+ STREAM_TO_UINT8 (link_type, p);
+ STREAM_TO_UINT8 (enc_mode, p);
+
+ handle = HCID_GET_HANDLE (handle);
+
+ if (link_type == HCI_LINK_TYPE_ACL)
+ {
+ btm_sec_connected (bda, handle, status, enc_mode);
+
+ l2c_link_hci_conn_comp (status, handle, bda);
+ }
+#if BTM_SCO_INCLUDED == TRUE
+ else
+ {
+ memset(&esco_data, 0, sizeof(tBTM_ESCO_DATA));
+ /* esco_data.link_type = HCI_LINK_TYPE_SCO; already zero */
+ memcpy (esco_data.bd_addr, bda, BD_ADDR_LEN);
+ btm_sco_connected (status, bda, handle, &esco_data);
+ }
+#endif /* BTM_SCO_INCLUDED */
+}
+
+
+/*******************************************************************************
+**
+** Function btu_hcif_connection_request_evt
+**
+** Description Process event HCI_CONNECTION_REQUEST_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+static void btu_hcif_connection_request_evt (UINT8 *p, UINT16 evt_len)
+{
+ BD_ADDR bda;
+ DEV_CLASS dc;
+ UINT8 link_type;
+
+ STREAM_TO_BDADDR (bda, p);
+ STREAM_TO_DEVCLASS (dc, p);
+ STREAM_TO_UINT8 (link_type, p);
+
+ /* Pass request to security manager to check connect filters before */
+ /* passing request to l2cap */
+ if (link_type == HCI_LINK_TYPE_ACL)
+ {
+ btm_sec_conn_req (bda, dc);
+ }
+#if BTM_SCO_INCLUDED == TRUE
+ else
+ {
+ btm_sco_conn_req (bda, dc, link_type);
+ }
+#endif /* BTM_SCO_INCLUDED */
+}
+
+
+/*******************************************************************************
+**
+** Function btu_hcif_disconnection_comp_evt
+**
+** Description Process event HCI_DISCONNECTION_COMP_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+static void btu_hcif_disconnection_comp_evt (UINT8 *p, UINT16 evt_len)
+{
+ UINT8 status;
+ UINT16 handle;
+ UINT8 reason;
+
+ STREAM_TO_UINT8 (status, p);
+ STREAM_TO_UINT16 (handle, p);
+ STREAM_TO_UINT8 (reason, p);
+
+ handle = HCID_GET_HANDLE (handle);
+
+#if BTM_SCO_INCLUDED == TRUE
+ /* If L2CAP doesn't know about it, send it to SCO */
+ if (!l2c_link_hci_disc_comp (handle, reason))
+ btm_sco_removed (handle, reason);
+#else
+ l2c_link_hci_disc_comp (handle, reason);
+#endif /* BTM_SCO_INCLUDED */
+
+ /* Notify security manager */
+ btm_sec_disconnected (handle, reason);
+}
+
+/*******************************************************************************
+**
+** Function btu_hcif_authentication_comp_evt
+**
+** Description Process event HCI_AUTHENTICATION_COMP_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+static void btu_hcif_authentication_comp_evt (UINT8 *p, UINT16 evt_len)
+{
+ UINT8 status;
+ UINT16 handle;
+
+ STREAM_TO_UINT8 (status, p);
+ STREAM_TO_UINT16 (handle, p);
+
+ btm_sec_auth_complete (handle, status);
+}
+
+
+/*******************************************************************************
+**
+** Function btu_hcif_rmt_name_request_comp_evt
+**
+** Description Process event HCI_RMT_NAME_REQUEST_COMP_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+static void btu_hcif_rmt_name_request_comp_evt (UINT8 *p, UINT16 evt_len)
+{
+ UINT8 status;
+ BD_ADDR bd_addr;
+
+ STREAM_TO_UINT8 (status, p);
+ STREAM_TO_BDADDR (bd_addr, p);
+
+ evt_len -= (1 + BD_ADDR_LEN);
+
+ btm_process_remote_name (bd_addr, p, evt_len, status);
+
+ btm_sec_rmt_name_request_complete (bd_addr, p, status);
+}
+
+
+/*******************************************************************************
+**
+** Function btu_hcif_encryption_change_evt
+**
+** Description Process event HCI_ENCRYPTION_CHANGE_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+static void btu_hcif_encryption_change_evt (UINT8 *p, UINT16 evt_len)
+{
+ UINT8 status;
+ UINT16 handle;
+ UINT8 encr_enable;
+
+ STREAM_TO_UINT8 (status, p);
+ STREAM_TO_UINT16 (handle, p);
+ STREAM_TO_UINT8 (encr_enable, p);
+
+ btm_acl_encrypt_change (handle, status, encr_enable);
+ btm_sec_encrypt_change (handle, status, encr_enable);
+}
+
+
+/*******************************************************************************
+**
+** Function btu_hcif_change_conn_link_key_evt
+**
+** Description Process event HCI_CHANGE_CONN_LINK_KEY_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+static void btu_hcif_change_conn_link_key_evt (UINT8 *p, UINT16 evt_len)
+{
+ UINT8 status;
+ UINT16 handle;
+
+ STREAM_TO_UINT8 (status, p);
+ STREAM_TO_UINT16 (handle, p);
+
+ btm_acl_link_key_change (handle, status);
+}
+
+
+/*******************************************************************************
+**
+** Function btu_hcif_master_link_key_comp_evt
+**
+** Description Process event HCI_MASTER_LINK_KEY_COMP_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+static void btu_hcif_master_link_key_comp_evt (UINT8 *p, UINT16 evt_len)
+{
+ UINT8 status;
+ UINT16 handle;
+ UINT8 key_flg;
+
+ STREAM_TO_UINT8 (status, p);
+ STREAM_TO_UINT16 (handle, p);
+ STREAM_TO_UINT8 (key_flg, p);
+
+ btm_sec_mkey_comp_event (handle, status, key_flg);
+}
+
+
+/*******************************************************************************
+**
+** Function btu_hcif_read_rmt_features_comp_evt
+**
+** Description Process event HCI_READ_RMT_FEATURES_COMP_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+static void btu_hcif_read_rmt_features_comp_evt (UINT8 *p, UINT16 evt_len)
+{
+ btm_read_remote_features_complete(p);
+}
+
+/*******************************************************************************
+**
+** Function btu_hcif_read_rmt_ext_features_comp_evt
+**
+** Description Process event HCI_READ_RMT_EXT_FEATURES_COMP_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+static void btu_hcif_read_rmt_ext_features_comp_evt (UINT8 *p, UINT16 evt_len)
+{
+ /* Status is in first byte of stream */
+ if (*p == HCI_SUCCESS)
+ btm_read_remote_ext_features_complete(p);
+ else
+ btm_read_remote_ext_features_failed(*p);
+}
+
+/*******************************************************************************
+**
+** Function btu_hcif_read_rmt_version_comp_evt
+**
+** Description Process event HCI_READ_RMT_VERSION_COMP_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+static void btu_hcif_read_rmt_version_comp_evt (UINT8 *p, UINT16 evt_len)
+{
+ btm_read_remote_version_complete (p);
+}
+
+
+/*******************************************************************************
+**
+** Function btu_hcif_qos_setup_comp_evt
+**
+** Description Process event HCI_QOS_SETUP_COMP_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+static void btu_hcif_qos_setup_comp_evt (UINT8 *p, UINT16 evt_len)
+{
+ UINT8 status;
+ UINT16 handle;
+ FLOW_SPEC flow;
+
+ STREAM_TO_UINT8 (status, p);
+ STREAM_TO_UINT16 (handle, p);
+ STREAM_TO_UINT8 (flow.qos_flags, p);
+ STREAM_TO_UINT8 (flow.service_type, p);
+ STREAM_TO_UINT32 (flow.token_rate, p);
+ STREAM_TO_UINT32 (flow.peak_bandwidth, p);
+ STREAM_TO_UINT32 (flow.latency, p);
+ STREAM_TO_UINT32 (flow.delay_variation, p);
+
+ btm_qos_setup_complete(status, handle, &flow);
+}
+
+
+/*******************************************************************************
+**
+** Function btu_hcif_esco_connection_comp_evt
+**
+** Description Process event HCI_ESCO_CONNECTION_COMP_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+static void btu_hcif_esco_connection_comp_evt (UINT8 *p, UINT16 evt_len)
+{
+#if BTM_SCO_INCLUDED == TRUE
+ tBTM_ESCO_DATA data;
+ UINT16 handle;
+ BD_ADDR bda;
+ UINT8 status;
+
+ STREAM_TO_UINT8 (status, p);
+ STREAM_TO_UINT16 (handle, p);
+ STREAM_TO_BDADDR (bda, p);
+
+ STREAM_TO_UINT8 (data.link_type, p);
+ STREAM_TO_UINT8 (data.tx_interval, p);
+ STREAM_TO_UINT8 (data.retrans_window, p);
+ STREAM_TO_UINT16 (data.rx_pkt_len, p);
+ STREAM_TO_UINT16 (data.tx_pkt_len, p);
+ STREAM_TO_UINT8 (data.air_mode, p);
+
+ memcpy (data.bd_addr, bda, BD_ADDR_LEN);
+ btm_sco_connected (status, bda, handle, &data);
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function btu_hcif_esco_connection_chg_evt
+**
+** Description Process event HCI_ESCO_CONNECTION_CHANGED_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+static void btu_hcif_esco_connection_chg_evt (UINT8 *p, UINT16 evt_len)
+{
+#if BTM_SCO_INCLUDED == TRUE
+ UINT16 handle;
+ UINT16 tx_pkt_len;
+ UINT16 rx_pkt_len;
+ UINT8 status;
+ UINT8 tx_interval;
+ UINT8 retrans_window;
+
+ STREAM_TO_UINT8 (status, p);
+ STREAM_TO_UINT16 (handle, p);
+
+ STREAM_TO_UINT8 (tx_interval, p);
+ STREAM_TO_UINT8 (retrans_window, p);
+ STREAM_TO_UINT16 (rx_pkt_len, p);
+ STREAM_TO_UINT16 (tx_pkt_len, p);
+
+ btm_esco_proc_conn_chg (status, handle, tx_interval, retrans_window,
+ rx_pkt_len, tx_pkt_len);
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function btu_hcif_hdl_command_complete
+**
+** Description Handle command complete event
+**
+** Returns void
+**
+*******************************************************************************/
+static void btu_hcif_hdl_command_complete (UINT16 opcode, UINT8 *p, UINT16 evt_len,
+ void *p_cplt_cback, UINT8 ctr_id)
+{
+ switch (opcode)
+ {
+ case HCI_RESET:
+ btm_reset_complete (); /* BR/EDR */
+ break;
+
+ case HCI_INQUIRY_CANCEL:
+ /* Tell inquiry processing that we are done */
+ btm_process_inq_complete(HCI_SUCCESS, BTM_BR_INQUIRY_MASK);
+ break;
+ case HCI_SET_EVENT_FILTER:
+ btm_event_filter_complete (p);
+ break;
+
+ case HCI_READ_STORED_LINK_KEY:
+ btm_read_stored_link_key_complete (p);
+ break;
+
+ case HCI_WRITE_STORED_LINK_KEY:
+ btm_write_stored_link_key_complete (p);
+ break;
+
+ case HCI_DELETE_STORED_LINK_KEY:
+ btm_delete_stored_link_key_complete (p);
+ break;
+
+ case HCI_READ_LOCAL_VERSION_INFO:
+ btm_read_local_version_complete (p, evt_len);
+ break;
+
+ case HCI_READ_POLICY_SETTINGS:
+ btm_read_link_policy_complete (p);
+ break;
+
+ case HCI_READ_BUFFER_SIZE:
+ btm_read_hci_buf_size_complete (p, evt_len);
+ break;
+
+ case HCI_READ_LOCAL_FEATURES:
+ btm_read_local_features_complete (p, evt_len);
+ break;
+
+ case HCI_READ_LOCAL_NAME:
+ btm_read_local_name_complete (p, evt_len);
+ break;
+
+ case HCI_READ_BD_ADDR:
+ btm_read_local_addr_complete (p, evt_len);
+ break;
+
+ case HCI_GET_LINK_QUALITY:
+ btm_read_link_quality_complete (p);
+ break;
+
+ case HCI_READ_RSSI:
+ btm_read_rssi_complete (p);
+ break;
+
+ case HCI_READ_TRANSMIT_POWER_LEVEL:
+ btm_read_tx_power_complete(p, FALSE);
+ break;
+
+ case HCI_CREATE_CONNECTION_CANCEL:
+ btm_create_conn_cancel_complete(p);
+ break;
+
+ case HCI_READ_LOCAL_OOB_DATA:
+#if BTM_OOB_INCLUDED == TRUE
+ btm_read_local_oob_complete(p);
+#endif
+ break;
+
+
+ case HCI_READ_INQ_TX_POWER_LEVEL:
+ btm_read_linq_tx_power_complete (p);
+ break;
+
+#if (BLE_INCLUDED == TRUE)
+/* BLE Commands */
+ case HCI_BLE_READ_WHITE_LIST_SIZE :
+ btm_read_white_list_size_complete(p, evt_len);
+ break;
+
+ case HCI_BLE_ADD_WHITE_LIST:
+ btm_ble_add_2_white_list_complete(p, evt_len);
+ break;
+
+ case HCI_BLE_CLEAR_WHITE_LIST:
+ btm_ble_clear_white_list_complete(p, evt_len);
+ break;
+
+ case HCI_BLE_REMOVE_WHITE_LIST:
+ btm_ble_remove_from_white_list_complete(p, evt_len);
+ break;
+
+ case HCI_BLE_RAND:
+ case HCI_BLE_ENCRYPT:
+
+ btm_ble_rand_enc_complete (p, opcode, (tBTM_RAND_ENC_CB *)p_cplt_cback);
+ break;
+ case HCI_BLE_READ_BUFFER_SIZE:
+ btm_read_ble_buf_size_complete(p, evt_len);
+ break;
+
+ case HCI_BLE_READ_ADV_CHNL_TX_POWER:
+ btm_read_tx_power_complete(p, TRUE);
+ break;
+
+ case HCI_BLE_WRITE_ADV_ENABLE:
+ btm_ble_write_adv_enable_complete(p);
+ break;
+
+#endif /* (BLE_INCLUDED == TRUE) */
+
+ default:
+ if ((opcode & HCI_GRP_VENDOR_SPECIFIC) == HCI_GRP_VENDOR_SPECIFIC)
+ btm_vsc_complete (p, opcode, evt_len, (tBTM_CMPL_CB *)p_cplt_cback);
+ break;
+ }
+}
+
+/*******************************************************************************
+**
+** Function btu_hcif_command_complete_evt
+**
+** Description Process event HCI_COMMAND_COMPLETE_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+static void btu_hcif_command_complete_evt (UINT8 controller_id, UINT8 *p, UINT16 evt_len)
+{
+ tHCI_CMD_CB *p_hci_cmd_cb = &(btu_cb.hci_cmd_cb[controller_id]);
+ UINT16 cc_opcode;
+ BT_HDR *p_cmd;
+ void *p_cplt_cback = NULL;
+
+ STREAM_TO_UINT8 (p_hci_cmd_cb->cmd_window, p);
+
+#if (defined(HCI_MAX_SIMUL_CMDS) && (HCI_MAX_SIMUL_CMDS > 0))
+ if (p_hci_cmd_cb->cmd_window > HCI_MAX_SIMUL_CMDS)
+ p_hci_cmd_cb->cmd_window = HCI_MAX_SIMUL_CMDS;
+#endif
+
+ STREAM_TO_UINT16 (cc_opcode, p);
+
+ evt_len -= 3;
+
+ /* only do this for certain commands */
+ if ((cc_opcode != HCI_RESET) && (cc_opcode != HCI_HOST_NUM_PACKETS_DONE) &&
+ (cc_opcode != HCI_COMMAND_NONE))
+ {
+ /* dequeue and free stored command */
+
+/* always use cmd code check, when one cmd timeout waiting for cmd_cmpl,
+ it'll cause the rest of the command goes in wrong order */
+ p_cmd = (BT_HDR *) GKI_getfirst (&p_hci_cmd_cb->cmd_cmpl_q);
+
+ while (p_cmd)
+ {
+ UINT16 opcode_dequeued;
+ UINT8 *p_dequeued;
+
+ /* Make sure dequeued command is for the command_cplt received */
+ p_dequeued = (UINT8 *)(p_cmd + 1) + p_cmd->offset;
+ STREAM_TO_UINT16 (opcode_dequeued, p_dequeued);
+
+ if (opcode_dequeued != cc_opcode)
+ {
+ /* opcode does not match, check next command in the queue */
+ p_cmd = (BT_HDR *) GKI_getnext(p_cmd);
+ continue;
+ }
+ GKI_remove_from_queue(&p_hci_cmd_cb->cmd_cmpl_q, p_cmd);
+
+ /* If command was a VSC, then extract command_complete callback */
+ if ((cc_opcode & HCI_GRP_VENDOR_SPECIFIC) == HCI_GRP_VENDOR_SPECIFIC
+#if BLE_INCLUDED == TRUE
+ || (cc_opcode == HCI_BLE_RAND )
+ || (cc_opcode == HCI_BLE_ENCRYPT)
+#endif
+ )
+ {
+ p_cplt_cback = *((void **)(p_cmd + 1));
+ }
+
+// btla-specific ++
+#if (defined(BTE_HCIUTILS_HOOK_INCLUDED) && (BTE_HCIUTILS_HOOK_INCLUDED == TRUE))
+ HCIUTILS_COPY_AND_SEND_TO_BTE_APPL(BT_EVT_TO_LM_HCI_CMD, p_cmd);
+#else
+ GKI_freebuf (p_cmd);
+#endif
+// btla-specific --
+
+ break;
+ }
+
+ /* if more commands in queue restart timer */
+ if (BTU_CMD_CMPL_TIMEOUT > 0)
+ {
+ if (!GKI_queue_is_empty (&(p_hci_cmd_cb->cmd_cmpl_q)))
+ {
+#if (defined(BTU_CMD_CMPL_TOUT_DOUBLE_CHECK) && BTU_CMD_CMPL_TOUT_DOUBLE_CHECK == TRUE)
+ p_hci_cmd_cb->checked_hcisu = FALSE;
+#endif
+ btu_start_timer (&(p_hci_cmd_cb->cmd_cmpl_timer),
+ (UINT16)(BTU_TTYPE_BTU_CMD_CMPL + controller_id),
+ BTU_CMD_CMPL_TIMEOUT);
+ }
+ else
+ {
+ btu_stop_timer (&(p_hci_cmd_cb->cmd_cmpl_timer));
+ }
+ }
+ }
+
+ /* handle event */
+ btu_hcif_hdl_command_complete (cc_opcode, p, evt_len, p_cplt_cback, controller_id);
+
+ /* see if we can send more commands */
+ btu_hcif_send_cmd (controller_id, NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function btu_hcif_hdl_command_status
+**
+** Description Handle a command status event
+**
+** Returns void
+**
+*******************************************************************************/
+static void btu_hcif_hdl_command_status (UINT16 opcode, UINT8 status, UINT8 *p_cmd,
+ void *p_vsc_status_cback, UINT8 controller_id)
+{
+ BD_ADDR bd_addr;
+ UINT16 handle;
+#if BTM_SCO_INCLUDED == TRUE
+ tBTM_ESCO_DATA esco_data;
+#endif
+
+#if BTM_PWR_MGR_INCLUDED == TRUE
+ switch (opcode)
+ {
+ case HCI_EXIT_SNIFF_MODE:
+ case HCI_EXIT_PARK_MODE:
+#if BTM_SCO_WAKE_PARKED_LINK == TRUE
+ if (status != HCI_SUCCESS)
+ {
+ /* Allow SCO initiation to continue if waiting for change mode event */
+ if (p_cmd != NULL)
+ {
+ p_cmd++; /* bypass length field */
+ STREAM_TO_UINT16 (handle, p_cmd);
+ btm_sco_chk_pend_unpark (status, handle);
+ }
+ }
+#endif
+ /* Case Falls Through */
+
+ case HCI_HOLD_MODE:
+ case HCI_SNIFF_MODE:
+ case HCI_PARK_MODE:
+ btm_pm_proc_cmd_status(status);
+ break;
+
+ default:
+#endif /* BTM_PWR_MGR_INCLUDED */
+ /* If command failed to start, we may need to tell BTM */
+ if (status != HCI_SUCCESS)
+ {
+ switch (opcode)
+ {
+ case HCI_INQUIRY:
+ /* Tell inquiry processing that we are done */
+ btm_process_inq_complete(status, BTM_BR_INQUIRY_MASK);
+ break;
+
+ case HCI_RMT_NAME_REQUEST:
+ /* Tell inquiry processing that we are done */
+ btm_process_remote_name (NULL, NULL, 0, status);
+
+ btm_sec_rmt_name_request_complete (NULL, NULL, status);
+ break;
+
+ case HCI_CHANGE_CONN_LINK_KEY:
+ /* Let host know we're done with error */
+ /* read handle out of stored command */
+ if (p_cmd != NULL)
+ {
+ p_cmd++;
+ STREAM_TO_UINT16 (handle, p_cmd);
+
+ btm_acl_link_key_change (handle, status);
+ }
+ break;
+
+ case HCI_QOS_SETUP_COMP_EVT:
+ /* Tell qos setup that we are done */
+ btm_qos_setup_complete(status,0,NULL);
+ break;
+
+ case HCI_SWITCH_ROLE:
+ /* Tell BTM that the command failed */
+ /* read bd addr out of stored command */
+ if (p_cmd != NULL)
+ {
+ p_cmd++;
+ STREAM_TO_BDADDR (bd_addr, p_cmd);
+ btm_acl_role_changed(status, bd_addr, BTM_ROLE_UNDEFINED);
+ }
+ else
+ btm_acl_role_changed(status, NULL, BTM_ROLE_UNDEFINED);
+ l2c_link_role_changed (NULL, BTM_ROLE_UNDEFINED, HCI_ERR_COMMAND_DISALLOWED);
+ break;
+
+ case HCI_CREATE_CONNECTION:
+ /* read bd addr out of stored command */
+ if (p_cmd != NULL)
+ {
+ p_cmd++;
+ STREAM_TO_BDADDR (bd_addr, p_cmd);
+ btm_sec_connected (bd_addr, HCI_INVALID_HANDLE, status, 0);
+ l2c_link_hci_conn_comp (status, HCI_INVALID_HANDLE, bd_addr);
+ }
+ break;
+
+ case HCI_READ_RMT_EXT_FEATURES_COMP_EVT:
+// btla-specific ++
+ btu_hcif_read_rmt_ext_features_comp_evt (p_cmd - 3, 0);
+// btla-specific --
+ break;
+
+ case HCI_AUTHENTICATION_REQUESTED:
+ /* Device refused to start authentication. That should be treated as authentication failure. */
+ btm_sec_auth_complete (BTM_INVALID_HCI_HANDLE, status);
+ break;
+
+ case HCI_SET_CONN_ENCRYPTION:
+ /* Device refused to start encryption. That should be treated as encryption failure. */
+ btm_sec_encrypt_change (BTM_INVALID_HCI_HANDLE, status, FALSE);
+ break;
+
+#if BTM_SCO_INCLUDED == TRUE
+ case HCI_SETUP_ESCO_CONNECTION:
+ /* read handle out of stored command */
+ if (p_cmd != NULL)
+ {
+ p_cmd++;
+ STREAM_TO_UINT16 (handle, p_cmd);
+
+ /* Determine if initial connection failed or is a change of setup */
+ if (btm_is_sco_active(handle))
+ btm_esco_proc_conn_chg (status, handle, 0, 0, 0, 0);
+ else
+ btm_sco_connected (status, NULL, handle, &esco_data);
+ }
+ break;
+#endif
+
+/* This is commented out until an upper layer cares about returning event
+#if L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE
+ case HCI_ENHANCED_FLUSH:
+ break;
+#endif
+*/
+ default:
+ if ((opcode & HCI_GRP_VENDOR_SPECIFIC) == HCI_GRP_VENDOR_SPECIFIC)
+ btm_vsc_complete (&status, opcode, 1, (tBTM_CMPL_CB *)p_vsc_status_cback);
+ break;
+ }
+
+ }
+ else
+ {
+ if ((opcode & HCI_GRP_VENDOR_SPECIFIC) == HCI_GRP_VENDOR_SPECIFIC)
+ btm_vsc_complete (&status, opcode, 1, (tBTM_CMPL_CB *)p_vsc_status_cback);
+ }
+#if BTM_PWR_MGR_INCLUDED == TRUE
+ }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function btu_hcif_command_status_evt
+**
+** Description Process event HCI_COMMAND_STATUS_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+static void btu_hcif_command_status_evt (UINT8 controller_id, UINT8 *p, UINT16 evt_len)
+{
+ tHCI_CMD_CB * p_hci_cmd_cb = &(btu_cb.hci_cmd_cb[controller_id]);
+ UINT8 status;
+ UINT16 opcode;
+ BT_HDR *p_cmd = NULL;
+ UINT16 cmd_opcode;
+ UINT8 *p_data = NULL;
+ void *p_vsc_status_cback = NULL;
+
+ STREAM_TO_UINT8 (status, p);
+ STREAM_TO_UINT8 (p_hci_cmd_cb->cmd_window, p);
+
+#if (defined(HCI_MAX_SIMUL_CMDS) && (HCI_MAX_SIMUL_CMDS > 0))
+ if (p_hci_cmd_cb->cmd_window > HCI_MAX_SIMUL_CMDS)
+ p_hci_cmd_cb->cmd_window = HCI_MAX_SIMUL_CMDS;
+#endif
+
+ STREAM_TO_UINT16 (opcode, p);
+
+ /* only do this for certain commands */
+ if ((opcode != HCI_RESET) && (opcode != HCI_HOST_NUM_PACKETS_DONE) &&
+ (opcode != HCI_COMMAND_NONE))
+ {
+ /* dequeue stored command */
+ if ((p_cmd = (BT_HDR *) GKI_dequeue (&(p_hci_cmd_cb->cmd_cmpl_q))) != NULL)
+ {
+ /* verify event opcode matches command opcode */
+ p_data = (UINT8 *)(p_cmd + 1) + p_cmd->offset;
+ STREAM_TO_UINT16 (cmd_opcode, p_data);
+
+ if (cmd_opcode != opcode)
+ {
+ p_data = NULL;
+ BT_TRACE_2 (TRACE_LAYER_HCI, TRACE_TYPE_WARNING,
+ "Event mismatch opcode=%X cmd opcode=%X", opcode, cmd_opcode);
+ }
+ /* If command was a VSC, then extract command_status callback */
+ else if ((cmd_opcode & HCI_GRP_VENDOR_SPECIFIC) == HCI_GRP_VENDOR_SPECIFIC)
+ {
+ p_vsc_status_cback = *((void **)(p_cmd + 1));
+ }
+ }
+
+ /* if more commands in queue restart timer */
+ if (BTU_CMD_CMPL_TIMEOUT > 0)
+ {
+ if (!GKI_queue_is_empty (&(p_hci_cmd_cb->cmd_cmpl_q)))
+ {
+#if (defined(BTU_CMD_CMPL_TOUT_DOUBLE_CHECK) && BTU_CMD_CMPL_TOUT_DOUBLE_CHECK == TRUE)
+ p_hci_cmd_cb->checked_hcisu = FALSE;
+#endif
+ btu_start_timer (&(p_hci_cmd_cb->cmd_cmpl_timer),
+ (UINT16)(BTU_TTYPE_BTU_CMD_CMPL + controller_id),
+ BTU_CMD_CMPL_TIMEOUT);
+ }
+ else
+ {
+ btu_stop_timer (&(p_hci_cmd_cb->cmd_cmpl_timer));
+ }
+ }
+ }
+
+ /* handle command */
+ btu_hcif_hdl_command_status (opcode, status, p_data, p_vsc_status_cback, controller_id);
+
+ /* free stored command */
+ if (p_cmd != NULL)
+ {
+// btla-specific ++
+#if (defined(BTE_HCIUTILS_HOOK_INCLUDED) && (BTE_HCIUTILS_HOOK_INCLUDED == TRUE))
+ HCIUTILS_COPY_AND_SEND_TO_BTE_APPL(BT_EVT_TO_LM_HCI_CMD, p_cmd);
+#else
+ GKI_freebuf (p_cmd);
+#endif
+// btla-specific --
+ }
+
+ /* See if we can forward any more commands */
+ btu_hcif_send_cmd (controller_id, NULL);
+}
+
+/*******************************************************************************
+**
+** Function btu_hcif_cmd_timeout
+**
+** Description Handle a command timeout
+**
+** Returns void
+**
+*******************************************************************************/
+void btu_hcif_cmd_timeout (UINT8 controller_id)
+{
+ tHCI_CMD_CB * p_hci_cmd_cb = &(btu_cb.hci_cmd_cb[controller_id]);
+ BT_HDR *p_cmd;
+ UINT8 *p;
+ void *p_cplt_cback = NULL;
+ UINT16 opcode;
+// btla-specific ++
+ UINT16 event;
+// btla-specific --
+
+#if (defined(BTU_CMD_CMPL_TOUT_DOUBLE_CHECK) && BTU_CMD_CMPL_TOUT_DOUBLE_CHECK == TRUE)
+ if (!(p_hci_cmd_cb->checked_hcisu))
+ {
+ BT_TRACE_1 (TRACE_LAYER_HCI, TRACE_TYPE_WARNING, "BTU HCI(id=%d) command timeout - double check HCISU", controller_id);
+
+ /* trigger HCISU to read any pending data in transport buffer */
+ GKI_send_event(HCISU_TASK, HCISU_EVT_MASK);
+
+ btu_start_timer (&(p_hci_cmd_cb->cmd_cmpl_timer),
+ (UINT16)(BTU_TTYPE_BTU_CMD_CMPL + controller_id),
+ 2); /* start short timer, if timer is set to 1 then it could expire before HCISU checks. */
+
+ p_hci_cmd_cb->checked_hcisu = TRUE;
+
+ return;
+ }
+#endif
+
+ /* set the controller cmd window to 1, as if we received a response, so
+ ** the flow of commands from the stack doesn't hang */
+ p_hci_cmd_cb->cmd_window = 1;
+
+ /* get queued command */
+ if ((p_cmd = (BT_HDR *) GKI_dequeue (&(p_hci_cmd_cb->cmd_cmpl_q))) == NULL)
+ {
+ BT_TRACE_0 (TRACE_LAYER_HCI, TRACE_TYPE_WARNING, "Cmd timeout; no cmd in queue");
+ return;
+ }
+
+ /* if more commands in queue restart timer */
+ if (BTU_CMD_CMPL_TIMEOUT > 0)
+ {
+ if (!GKI_queue_is_empty (&(p_hci_cmd_cb->cmd_cmpl_q)))
+ {
+#if (defined(BTU_CMD_CMPL_TOUT_DOUBLE_CHECK) && BTU_CMD_CMPL_TOUT_DOUBLE_CHECK == TRUE)
+ p_hci_cmd_cb->checked_hcisu = FALSE;
+#endif
+ btu_start_timer (&(p_hci_cmd_cb->cmd_cmpl_timer),
+ (UINT16)(BTU_TTYPE_BTU_CMD_CMPL + controller_id),
+ BTU_CMD_CMPL_TIMEOUT);
+ }
+ }
+
+ p = (UINT8 *)(p_cmd + 1) + p_cmd->offset;
+#if (NFC_INCLUDED == TRUE)
+ if (controller_id == NFC_CONTROLLER_ID)
+ {
+ //TODO call nfc_ncif_cmd_timeout
+ BT_TRACE_2 (TRACE_LAYER_HCI, TRACE_TYPE_WARNING, "BTU NCI command timeout - header 0x%02x%02x", p[0], p[1]);
+ return;
+ }
+#endif
+
+ /* get opcode from stored command */
+ STREAM_TO_UINT16 (opcode, p);
+
+// btla-specific ++
+#if (defined(ANDROID_APP_INCLUDED) && (ANDROID_APP_INCLUDED == TRUE))
+ LOGE("######################################################################");
+ LOGE("#");
+ LOGE("# WARNING : BTU HCI(id=%d) command timeout. opcode=0x%x", controller_id, opcode);
+ LOGE("#");
+ LOGE("######################################################################");
+#else
+ BT_TRACE_2 (TRACE_LAYER_HCI, TRACE_TYPE_WARNING, "BTU HCI(id=%d) command timeout. opcode=0x%x", controller_id, opcode);
+#endif
+// btla-specific ++
+
+ /* send stack a fake command complete or command status, but first determine
+ ** which to send
+ */
+ switch (opcode)
+ {
+ case HCI_HOLD_MODE:
+ case HCI_SNIFF_MODE:
+ case HCI_EXIT_SNIFF_MODE:
+ case HCI_PARK_MODE:
+ case HCI_EXIT_PARK_MODE:
+ case HCI_INQUIRY:
+ case HCI_RMT_NAME_REQUEST:
+ case HCI_QOS_SETUP_COMP_EVT:
+ case HCI_CREATE_CONNECTION:
+ case HCI_CHANGE_CONN_LINK_KEY:
+ case HCI_SWITCH_ROLE:
+ case HCI_READ_RMT_EXT_FEATURES_COMP_EVT:
+ case HCI_AUTHENTICATION_REQUESTED:
+ case HCI_SET_CONN_ENCRYPTION:
+#if BTM_SCO_INCLUDED == TRUE
+ case HCI_SETUP_ESCO_CONNECTION:
+#endif
+ /* fake a command status */
+ btu_hcif_hdl_command_status (opcode, HCI_ERR_UNSPECIFIED, p, NULL, controller_id);
+ break;
+
+ default:
+ /* If vendor specific restore the callback function */
+ if ((opcode & HCI_GRP_VENDOR_SPECIFIC) == HCI_GRP_VENDOR_SPECIFIC
+#if BLE_INCLUDED == TRUE
+ || (opcode == HCI_BLE_RAND ) ||
+ (opcode == HCI_BLE_ENCRYPT)
+#endif
+ )
+ {
+ p_cplt_cback = *((void **)(p_cmd + 1));
+#if 0
+ BT_TRACE_2 (TRACE_LAYER_HCI, TRACE_TYPE_DEBUG,
+ "Restoring VSC callback for opcode=0x%04x, Callback function=0x%07x",
+ opcode, (UINT32)p_cplt_cback);
+#endif
+ }
+
+ /* fake a command complete; first create a fake event */
+// btla-specific ++
+ event = HCI_ERR_UNSPECIFIED;
+ btu_hcif_hdl_command_complete (opcode, (UINT8 *)&event, 1, p_cplt_cback, controller_id);
+// btla-specific --
+ break;
+ }
+
+ /* free stored command */
+ GKI_freebuf(p_cmd);
+
+ /* If anyone wants device status notifications, give him one */
+ btm_report_device_status (BTM_DEV_STATUS_CMD_TOUT);
+
+ /* See if we can forward any more commands */
+ btu_hcif_send_cmd (controller_id, NULL);
+}
+
+/*******************************************************************************
+**
+** Function btu_hcif_hardware_error_evt
+**
+** Description Process event HCI_HARDWARE_ERROR_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+static void btu_hcif_hardware_error_evt (UINT8 *p, UINT16 evt_len)
+{
+ BT_TRACE_0 (TRACE_LAYER_HCI, TRACE_TYPE_ERROR, "Ctlr H/w error event");
+
+ /* If anyone wants device status notifications, give him one. */
+ btm_report_device_status (BTM_DEV_STATUS_DOWN);
+
+ /* Reset the controller */
+ if (BTM_IsDeviceUp())
+ BTM_DeviceReset (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function btu_hcif_flush_occured_evt
+**
+** Description Process event HCI_FLUSH_OCCURED_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+static void btu_hcif_flush_occured_evt (UINT8 *p, UINT16 evt_len)
+{
+}
+
+
+/*******************************************************************************
+**
+** Function btu_hcif_role_change_evt
+**
+** Description Process event HCI_ROLE_CHANGE_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+static void btu_hcif_role_change_evt (UINT8 *p, UINT16 evt_len)
+{
+ UINT8 status;
+ BD_ADDR bda;
+ UINT8 role;
+
+ STREAM_TO_UINT8 (status, p);
+ STREAM_TO_BDADDR (bda, p);
+ STREAM_TO_UINT8 (role, p);
+
+ l2c_link_role_changed (bda, role, status);
+ btm_acl_role_changed(status, bda, role);
+}
+
+
+/*******************************************************************************
+**
+** Function btu_hcif_num_compl_data_pkts_evt
+**
+** Description Process event HCI_NUM_COMPL_DATA_PKTS_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+static void btu_hcif_num_compl_data_pkts_evt (UINT8 *p, UINT16 evt_len)
+{
+ /* Process for L2CAP and SCO */
+ l2c_link_process_num_completed_pkts (p);
+
+ /* Send on to SCO */
+ /*?? No SCO for now */
+}
+
+/*******************************************************************************
+**
+** Function btu_hcif_mode_change_evt
+**
+** Description Process event HCI_MODE_CHANGE_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+static void btu_hcif_mode_change_evt (UINT8 *p, UINT16 evt_len)
+{
+ UINT8 status;
+ UINT16 handle;
+ UINT8 current_mode;
+ UINT16 interval;
+
+ STREAM_TO_UINT8 (status, p);
+
+ STREAM_TO_UINT16 (handle, p);
+ STREAM_TO_UINT8 (current_mode, p);
+ STREAM_TO_UINT16 (interval, p);
+#if BTM_PWR_MGR_INCLUDED == TRUE
+#if BTM_SCO_WAKE_PARKED_LINK == TRUE
+ btm_sco_chk_pend_unpark (status, handle);
+#endif
+ btm_pm_proc_mode_change (status, handle, current_mode, interval);
+#else
+ btm_process_mode_change (status, handle, current_mode, interval);
+#endif /* BTM_PWR_MGR_INCLUDED == TRUE */
+
+#if (HID_DEV_INCLUDED == TRUE) && (HID_DEV_PM_INCLUDED == TRUE)
+ hidd_pm_proc_mode_change( status, current_mode, interval ) ;
+#endif
+}
+
+/*******************************************************************************
+**
+** Function btu_hcif_ssr_evt
+**
+** Description Process event HCI_SNIFF_SUB_RATE_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+ #if (BTM_SSR_INCLUDED == TRUE)
+static void btu_hcif_ssr_evt (UINT8 *p, UINT16 evt_len)
+{
+#if (BTM_PWR_MGR_INCLUDED == TRUE)
+ btm_pm_proc_ssr_evt(p, evt_len);
+#endif
+}
+ #endif
+
+
+/*******************************************************************************
+**
+** Function btu_hcif_return_link_keys_evt
+**
+** Description Process event HCI_RETURN_LINK_KEYS_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+
+static void btu_hcif_return_link_keys_evt (UINT8 *p, UINT16 evt_len)
+{
+ UINT8 num_keys;
+ tBTM_RETURN_LINK_KEYS_EVT *result;
+
+ /* get the number of link keys */
+ num_keys = *p;
+
+ /* If there are no link keys don't call the call back */
+ if (!num_keys)
+ return;
+
+ /* Take one extra byte at the beginning to specify event */
+ result = (tBTM_RETURN_LINK_KEYS_EVT *)(--p);
+ result->event = BTM_CB_EVT_RETURN_LINK_KEYS;
+
+ /* Call the BTM function to pass the link keys to application */
+ btm_return_link_keys_evt (result);
+}
+
+
+/*******************************************************************************
+**
+** Function btu_hcif_pin_code_request_evt
+**
+** Description Process event HCI_PIN_CODE_REQUEST_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+static void btu_hcif_pin_code_request_evt (UINT8 *p, UINT16 evt_len)
+{
+ BD_ADDR bda;
+
+ STREAM_TO_BDADDR (bda, p);
+
+ /* Tell L2CAP that there was a PIN code request, */
+ /* it may need to stretch timeouts */
+ l2c_pin_code_request (bda);
+
+ btm_sec_pin_code_request (bda);
+}
+
+
+/*******************************************************************************
+**
+** Function btu_hcif_link_key_request_evt
+**
+** Description Process event HCI_LINK_KEY_REQUEST_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+static void btu_hcif_link_key_request_evt (UINT8 *p, UINT16 evt_len)
+{
+ BD_ADDR bda;
+
+ STREAM_TO_BDADDR (bda, p);
+ btm_sec_link_key_request (bda);
+}
+
+
+/*******************************************************************************
+**
+** Function btu_hcif_link_key_notification_evt
+**
+** Description Process event HCI_LINK_KEY_NOTIFICATION_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+static void btu_hcif_link_key_notification_evt (UINT8 *p, UINT16 evt_len)
+{
+ BD_ADDR bda;
+ LINK_KEY key;
+ UINT8 key_type;
+
+ STREAM_TO_BDADDR (bda, p);
+ STREAM_TO_ARRAY16 (key, p);
+ STREAM_TO_UINT8 (key_type, p);
+
+ btm_sec_link_key_notification (bda, key, key_type);
+}
+
+
+/*******************************************************************************
+**
+** Function btu_hcif_loopback_command_evt
+**
+** Description Process event HCI_LOOPBACK_COMMAND_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+static void btu_hcif_loopback_command_evt (UINT8 *p, UINT16 evt_len)
+{
+}
+
+
+/*******************************************************************************
+**
+** Function btu_hcif_data_buf_overflow_evt
+**
+** Description Process event HCI_DATA_BUF_OVERFLOW_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+static void btu_hcif_data_buf_overflow_evt (UINT8 *p, UINT16 evt_len)
+{
+}
+
+
+/*******************************************************************************
+**
+** Function btu_hcif_max_slots_changed_evt
+**
+** Description Process event HCI_MAX_SLOTS_CHANGED_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+static void btu_hcif_max_slots_changed_evt (UINT8 *p, UINT16 evt_len)
+{
+}
+
+
+/*******************************************************************************
+**
+** Function btu_hcif_read_clock_off_comp_evt
+**
+** Description Process event HCI_READ_CLOCK_OFF_COMP_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+static void btu_hcif_read_clock_off_comp_evt (UINT8 *p, UINT16 evt_len)
+{
+ UINT8 status;
+ UINT16 handle;
+ UINT16 clock_offset;
+
+ STREAM_TO_UINT8 (status, p);
+
+ /* If failed to get clock offset just drop the result */
+ if (status != HCI_SUCCESS)
+ return;
+
+ STREAM_TO_UINT16 (handle, p);
+ STREAM_TO_UINT16 (clock_offset, p);
+
+ handle = HCID_GET_HANDLE (handle);
+
+ btm_process_clk_off_comp_evt (handle, clock_offset);
+ btm_sec_update_clock_offset (handle, clock_offset);
+}
+
+
+/*******************************************************************************
+**
+** Function btu_hcif_conn_pkt_type_change_evt
+**
+** Description Process event HCI_CONN_PKT_TYPE_CHANGE_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+static void btu_hcif_conn_pkt_type_change_evt (UINT8 *p, UINT16 evt_len)
+{
+}
+
+
+/*******************************************************************************
+**
+** Function btu_hcif_qos_violation_evt
+**
+** Description Process event HCI_QOS_VIOLATION_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+static void btu_hcif_qos_violation_evt (UINT8 *p, UINT16 evt_len)
+{
+ UINT16 handle;
+
+ STREAM_TO_UINT16 (handle, p);
+
+ handle = HCID_GET_HANDLE (handle);
+
+
+ l2c_link_hci_qos_violation (handle);
+}
+
+
+/*******************************************************************************
+**
+** Function btu_hcif_page_scan_mode_change_evt
+**
+** Description Process event HCI_PAGE_SCAN_MODE_CHANGE_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+static void btu_hcif_page_scan_mode_change_evt (UINT8 *p, UINT16 evt_len)
+{
+}
+
+
+/*******************************************************************************
+**
+** Function btu_hcif_page_scan_rep_mode_chng_evt
+**
+** Description Process event HCI_PAGE_SCAN_REP_MODE_CHNG_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+static void btu_hcif_page_scan_rep_mode_chng_evt (UINT8 *p, UINT16 evt_len)
+{
+}
+
+/**********************************************
+** Simple Pairing Events
+***********************************************/
+
+/*******************************************************************************
+**
+** Function btu_hcif_host_support_evt
+**
+** Description Process event HCI_RMT_HOST_SUP_FEAT_NOTIFY_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+static void btu_hcif_host_support_evt (UINT8 *p, UINT16 evt_len)
+{
+ btm_sec_rmt_host_support_feat_evt(p);
+}
+
+/*******************************************************************************
+**
+** Function btu_hcif_io_cap_request_evt
+**
+** Description Process event HCI_IO_CAPABILITY_REQUEST_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+static void btu_hcif_io_cap_request_evt (UINT8 *p, UINT16 evt_len)
+{
+ btm_io_capabilities_req(p);
+}
+
+
+/*******************************************************************************
+**
+** Function btu_hcif_io_cap_response_evt
+**
+** Description Process event HCI_IO_CAPABILITY_RESPONSE_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+static void btu_hcif_io_cap_response_evt (UINT8 *p, UINT16 evt_len)
+{
+ btm_io_capabilities_rsp(p);
+}
+
+
+/*******************************************************************************
+**
+** Function btu_hcif_user_conf_request_evt
+**
+** Description Process event HCI_USER_CONFIRMATION_REQUEST_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+static void btu_hcif_user_conf_request_evt (UINT8 *p, UINT16 evt_len)
+{
+ btm_proc_sp_req_evt(BTM_SP_CFM_REQ_EVT, p);
+}
+
+
+/*******************************************************************************
+**
+** Function btu_hcif_user_passkey_request_evt
+**
+** Description Process event HCI_USER_PASSKEY_REQUEST_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+static void btu_hcif_user_passkey_request_evt (UINT8 *p, UINT16 evt_len)
+{
+ btm_proc_sp_req_evt(BTM_SP_KEY_REQ_EVT, p);
+}
+
+/*******************************************************************************
+**
+** Function btu_hcif_user_passkey_notif_evt
+**
+** Description Process event HCI_USER_PASSKEY_NOTIFY_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+static void btu_hcif_user_passkey_notif_evt (UINT8 *p, UINT16 evt_len)
+{
+ btm_proc_sp_req_evt(BTM_SP_KEY_NOTIF_EVT, p);
+}
+
+/*******************************************************************************
+**
+** Function btu_hcif_keypress_notif_evt
+**
+** Description Process event HCI_KEYPRESS_NOTIFY_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+static void btu_hcif_keypress_notif_evt (UINT8 *p, UINT16 evt_len)
+{
+ btm_keypress_notif_evt(p);
+}
+
+/*******************************************************************************
+**
+** Function btu_hcif_link_super_tout_evt
+**
+** Description Process event HCI_LINK_SUPER_TOUT_CHANGED_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+static void btu_hcif_link_super_tout_evt (UINT8 *p, UINT16 evt_len)
+{
+ UINT16 handle, timeout;
+ STREAM_TO_UINT16 (handle, p);
+ STREAM_TO_UINT16 (timeout, p);
+
+ btm_proc_lsto_evt(handle, timeout);
+}
+
+/*******************************************************************************
+**
+** Function btu_hcif_rem_oob_request_evt
+**
+** Description Process event HCI_REMOTE_OOB_DATA_REQUEST_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+ #if BTM_OOB_INCLUDED == TRUE
+static void btu_hcif_rem_oob_request_evt (UINT8 *p, UINT16 evt_len)
+{
+ btm_rem_oob_req(p);
+}
+ #endif
+
+/*******************************************************************************
+**
+** Function btu_hcif_simple_pair_complete_evt
+**
+** Description Process event HCI_SIMPLE_PAIRING_COMPLETE_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+static void btu_hcif_simple_pair_complete_evt (UINT8 *p, UINT16 evt_len)
+{
+ btm_simple_pair_complete(p);
+}
+/*******************************************************************************
+**
+** Function btu_hcif_flush_cmd_queue
+**
+** Description Flush the HCI command complete queue and transmit queue when
+** needed.
+**
+** Returns void
+**
+*******************************************************************************/
+void btu_hcif_flush_cmd_queue(void)
+{
+ BT_HDR *p_cmd;
+
+ btu_cb.hci_cmd_cb[0].cmd_window = 0;
+ while ((p_cmd = (BT_HDR *) GKI_dequeue (&btu_cb.hci_cmd_cb[0].cmd_cmpl_q)) != NULL)
+ {
+ GKI_freebuf (p_cmd);
+ }
+ while ((p_cmd = (BT_HDR *) GKI_dequeue (&btu_cb.hci_cmd_cb[0].cmd_xmit_q)) != NULL)
+ {
+ GKI_freebuf (p_cmd);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btu_hcif_enhanced_flush_complete_evt
+**
+** Description Process event HCI_ENHANCED_FLUSH_COMPLETE_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+#if L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE
+static void btu_hcif_enhanced_flush_complete_evt (UINT8 *p, UINT16 evt_len)
+{
+/* This is empty until an upper layer cares about returning event */
+}
+#endif
+/**********************************************
+** End of Simple Pairing Events
+***********************************************/
+
+
+/**********************************************
+** BLE Events
+***********************************************/
+#if (defined BLE_INCLUDED) && (BLE_INCLUDED == TRUE)
+static void btu_hcif_encyption_key_refresh_cmpl_evt (UINT8 *p, UINT16 evt_len)
+{
+ UINT8 status;
+ UINT16 handle;
+
+ STREAM_TO_UINT8 (status, p);
+ STREAM_TO_UINT16 (handle, p);
+
+ btm_sec_encrypt_change (handle, status, 1);
+}
+
+static void btu_ble_process_adv_pkt (UINT8 *p, UINT16 evt_len)
+{
+ BT_TRACE_0 (TRACE_LAYER_HCI, TRACE_TYPE_EVENT, "btu_ble_process_adv_pkt");
+
+ btm_ble_process_adv_pkt(p);
+}
+
+
+static void btu_ble_ll_conn_complete_evt ( UINT8 *p, UINT16 evt_len)
+{
+ UINT8 role, status, bda_type;
+ UINT16 handle;
+ BD_ADDR bda;
+ UINT16 conn_interval, conn_latency, conn_timeout;
+ UINT16 combined_mode;
+
+ STREAM_TO_UINT8 (status, p);
+ STREAM_TO_UINT16 (handle, p);
+ STREAM_TO_UINT8 (role, p);
+ STREAM_TO_UINT8 (bda_type, p);
+ STREAM_TO_BDADDR (bda, p);
+ STREAM_TO_UINT16 (conn_interval, p);
+ STREAM_TO_UINT16 (conn_latency, p);
+ STREAM_TO_UINT16 (conn_timeout, p);
+
+ handle = HCID_GET_HANDLE (handle);
+
+ if (status == 0)
+ {
+ btm_ble_connected(bda, handle, HCI_ENCRYPT_MODE_DISABLED, role);
+
+ l2cble_conn_comp (handle, role, bda, bda_type, conn_interval,
+ conn_latency, conn_timeout);
+ }
+ else
+ {
+ /* If we are LE connectable, check if we need to start advertising again */
+ if (btm_cb.ble_ctr_cb.inq_var.connectable_mode != BTM_BLE_NON_CONNECTABLE)
+ {
+ tACL_CONN *pa = &btm_cb.acl_db[0];
+ UINT16 xx;
+
+ for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, pa++)
+ {
+ /* If any other LE link is up, we are still not connectable */
+ if (pa->in_use && pa->is_le_link)
+ return;
+ }
+ combined_mode = (btm_cb.ble_ctr_cb.inq_var.connectable_mode | btm_cb.btm_inq_vars.connectable_mode);
+ btm_ble_set_connectability ( combined_mode );
+ }
+ }
+}
+
+static void btu_ble_ll_conn_param_upd_evt (UINT8 *p, UINT16 evt_len)
+{
+/* This is empty until an upper layer cares about returning event */
+}
+
+static void btu_ble_read_remote_feat_evt (UINT8 *p, UINT16 evt_len)
+{
+ btm_ble_read_remote_features_complete(p);
+}
+
+static void btu_ble_proc_ltk_req (UINT8 *p, UINT16 evt_len)
+{
+ UINT16 ediv, handle;
+ UINT8 *pp;
+
+ STREAM_TO_UINT16(handle, p);
+ pp = p + 8;
+ STREAM_TO_UINT16(ediv, pp);
+#if SMP_INCLUDED == TRUE
+ btm_ble_ltk_request(handle, p, ediv);
+#endif
+ /* This is empty until an upper layer cares about returning event */
+}
+/**********************************************
+** End of BLE Events Handler
+***********************************************/
+#endif /* BLE_INCLUDED */
+
diff --git a/stack/btu/btu_init.c b/stack/btu/btu_init.c
new file mode 100644
index 0000000..b1b7b2b
--- /dev/null
+++ b/stack/btu/btu_init.c
@@ -0,0 +1,143 @@
+/*****************************************************************************
+** *
+** Name: btu_init.c *
+** *
+** Description: This module contains the routines that load and shutdown *
+** the core stack components. *
+** *
+** Copyright (c) 2000-2011, Broadcom Corp., All Rights Reserved. *
+** Broadcom Bluetooth Core. Proprietary and confidential. *
+******************************************************************************/
+
+#include "bt_target.h"
+#include <string.h>
+#include "dyn_mem.h"
+
+#include "btu.h"
+#include "btm_int.h"
+#include "sdpint.h"
+#include "l2c_int.h"
+
+#if (BLE_INCLUDED == TRUE)
+#include "gatt_api.h"
+#include "gatt_int.h"
+#if SMP_INCLUDED == TRUE
+#include "smp_int.h"
+#endif
+#endif
+
+extern void PLATFORM_DisableHciTransport(UINT8 bDisable);
+/*****************************************************************************
+** V A R I A B L E S *
+******************************************************************************/
+const BD_ADDR BT_BD_ANY = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+/*****************************************************************************
+** F U N C T I O N S *
+******************************************************************************/
+/*****************************************************************************
+**
+** Function btu_init_core
+**
+** Description Initialize control block memory for each core component.
+**
+**
+** Returns void
+**
+******************************************************************************/
+void btu_init_core(void)
+{
+ /* Initialize the mandatory core stack components */
+ btm_init();
+
+ l2c_init();
+
+ sdp_init();
+
+#if BLE_INCLUDED == TRUE
+ gatt_init();
+#if (defined(SMP_INCLUDED) && SMP_INCLUDED == TRUE)
+ SMP_Init();
+#endif
+ btm_ble_init();
+#endif
+}
+
+
+/*****************************************************************************
+**
+** Function BTE_Init
+**
+** Description Initializes the BTU control block.
+**
+** NOTE: Must be called before creating any tasks
+** (RPC, BTU, HCIT, APPL, etc.)
+**
+** Returns void
+**
+******************************************************************************/
+void BTE_Init(void)
+{
+ int i = 0;
+
+ memset (&btu_cb, 0, sizeof (tBTU_CB));
+ btu_cb.hcit_acl_pkt_size = BTU_DEFAULT_DATA_SIZE + HCI_DATA_PREAMBLE_SIZE;
+#if (BLE_INCLUDED == TRUE)
+ btu_cb.hcit_ble_acl_pkt_size = BTU_DEFAULT_BLE_DATA_SIZE + HCI_DATA_PREAMBLE_SIZE;
+#endif
+ btu_cb.trace_level = BT_TRACE_LEVEL_DEBUG; //HCI_INITIAL_TRACE_LEVEL;
+
+ for ( i = 0; i < BTU_MAX_LOCAL_CTRLS; i++ ) /* include BR/EDR */
+ btu_cb.hci_cmd_cb[i].cmd_window = 1;
+}
+
+
+/*****************************************************************************
+**
+** Function BTU_AclPktSize
+**
+** Description export the ACL packet size.
+**
+** Returns UINT16
+**
+******************************************************************************/
+UINT16 BTU_AclPktSize(void)
+{
+ return btu_cb.hcit_acl_pkt_size;
+}
+/*****************************************************************************
+**
+** Function BTU_BleAclPktSize
+**
+** Description export the BLE ACL packet size.
+**
+** Returns UINT16
+**
+******************************************************************************/
+UINT16 BTU_BleAclPktSize(void)
+{
+#if BLE_INCLUDED == TRUE
+ return btu_cb.hcit_ble_acl_pkt_size;
+#else
+ return 0;
+#endif
+}
+
+/*******************************************************************************
+**
+** Function btu_uipc_rx_cback
+**
+** Description
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void btu_uipc_rx_cback(BT_HDR *p_msg)
+{
+ BT_TRACE_3 (TRACE_LAYER_BTM, TRACE_TYPE_DEBUG, "btu_uipc_rx_cback event 0x%x, len %d, offset %d",
+ p_msg->event, p_msg->len, p_msg->offset);
+ GKI_send_msg(BTU_TASK, BTU_HCI_RCV_MBOX, p_msg);
+
+}
+
diff --git a/stack/btu/btu_task.c b/stack/btu/btu_task.c
new file mode 100644
index 0000000..5753154
--- /dev/null
+++ b/stack/btu/btu_task.c
@@ -0,0 +1,819 @@
+/*****************************************************************************/
+/* */
+/* Name: btu_task.c */
+/* */
+/* Description: this file contains the main Bluetooth Upper Layer */
+/* processing loop. The Widcomm implementations of L2CAP */
+/* RFCOMM, SDP and the BTIf run as one GKI task. This */
+/* btu_task switches between them. */
+/* */
+/* Note that there will always be an L2CAP, but there may */
+/* or may not be an RFCOMM or SDP. Whether these layers */
+/* are present or not is determined by compile switches. */
+/* */
+/* Copyright (c) 1999-2011, Broadcom Corp., All Rights Reserved. */
+/* Broadcom Corp Bluetooth Core. Proprietary and confidential. */
+/*****************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "bt_target.h"
+#include "gki.h"
+#include "bt_types.h"
+#include "hcimsgs.h"
+#include "l2c_int.h"
+#include "btu.h"
+
+#include "sdpint.h"
+
+#if ( defined(RFCOMM_INCLUDED) && RFCOMM_INCLUDED == TRUE )
+#include "port_api.h"
+#include "port_ext.h"
+#endif
+
+#include "btm_api.h"
+#include "btm_int.h"
+
+#if (defined(EVAL) && EVAL == TRUE)
+#include "btu_eval.h"
+#endif
+
+#if GAP_INCLUDED == TRUE
+#include "gap_int.h"
+#endif
+
+#if (defined(OBX_INCLUDED) && OBX_INCLUDED == TRUE)
+#include "obx_int.h"
+
+#if (defined(BIP_INCLUDED) && BIP_INCLUDED == TRUE)
+#include "bip_int.h"
+#endif /* BIP */
+
+#if (BPP_SND_INCLUDED == TRUE || BPP_INCLUDED == TRUE)
+#include "bpp_int.h"
+#endif /* BPP */
+
+#endif /* OBX */
+
+#include "bt_trace.h"
+
+/* BTE application task */
+#if APPL_INCLUDED == TRUE
+#include "bte_appl.h"
+#endif
+
+#if (defined(RPC_INCLUDED) && RPC_INCLUDED == TRUE)
+#include "rpct_main.h"
+#endif
+
+#if (defined(BNEP_INCLUDED) && BNEP_INCLUDED == TRUE)
+#include "bnep_int.h"
+#endif
+
+#if (defined(PAN_INCLUDED) && PAN_INCLUDED == TRUE)
+#include "pan_int.h"
+#endif
+
+#if (defined(SAP_SERVER_INCLUDED) && SAP_SERVER_INCLUDED == TRUE)
+#include "sap_int.h"
+#endif
+
+#if (defined(HID_DEV_INCLUDED) && HID_DEV_INCLUDED == TRUE )
+#include "hidd_int.h"
+#endif
+
+#if (defined(HID_HOST_INCLUDED) && HID_HOST_INCLUDED == TRUE )
+#include "hidh_int.h"
+#endif
+
+#if (defined(AVDT_INCLUDED) && AVDT_INCLUDED == TRUE)
+#include "avdt_int.h"
+#else
+extern void avdt_rcv_sync_info (BT_HDR *p_buf); /* this is for hci_test */
+#endif
+
+#if (defined(MCA_INCLUDED) && MCA_INCLUDED == TRUE)
+#include "mca_api.h"
+#include "mca_defs.h"
+#include "mca_int.h"
+#endif
+
+
+#if (defined(BTU_BTA_INCLUDED) && BTU_BTA_INCLUDED == TRUE)
+#include "bta_sys.h"
+#endif
+
+#if (BLE_INCLUDED == TRUE)
+#include "gatt_int.h"
+#if (SMP_INCLUDED == TRUE)
+#include "smp_int.h"
+#endif
+#include "btm_ble_int.h"
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+BT_API extern void BTE_InitStack(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+/* Define BTU storage area
+*/
+#if BTU_DYNAMIC_MEMORY == FALSE
+tBTU_CB btu_cb;
+#endif
+
+
+/* Define a function prototype to allow a generic timeout handler */
+typedef void (tUSER_TIMEOUT_FUNC) (TIMER_LIST_ENT *p_tle);
+
+/*******************************************************************************
+**
+** Function btu_task
+**
+** Description This is the main task of the Bluetooth Upper Layers unit.
+** It sits in a loop waiting for messages, and dispatches them
+** to the appropiate handlers.
+**
+** Returns should never return
+**
+*******************************************************************************/
+BTU_API UINT32 btu_task (UINT32 param)
+{
+ UINT16 event;
+ BT_HDR *p_msg;
+ UINT8 i;
+ UINT16 mask;
+ BOOLEAN handled;
+
+#if (defined(HCISU_H4_INCLUDED) && HCISU_H4_INCLUDED == TRUE)
+ /* wait an event that HCISU is ready */
+ GKI_wait(0xFFFF, 0);
+#endif
+ /* Initialize the mandatory core stack control blocks
+ (BTU, BTM, L2CAP, and SDP)
+ */
+ btu_init_core();
+
+ /* Initialize any optional stack components */
+ BTE_InitStack();
+
+#if (defined(BTU_BTA_INCLUDED) && BTU_BTA_INCLUDED == TRUE)
+ bta_sys_init();
+#endif
+
+ /* Initialise platform trace levels at this point as BTE_InitStack() and bta_sys_init()
+ * reset the control blocks and preset the trace level with XXX_INITIAL_TRACE_LEVEL
+ */
+#if ( BT_USE_TRACES==TRUE )
+ BTE_InitTraceLevels();
+#endif
+
+ /* Send a startup evt message to BTIF_TASK to kickstart the init procedure */
+ GKI_send_event(BTIF_TASK, BT_EVT_TRIGGER_STACK_INIT);
+
+ /* Wait for, and process, events */
+ for (;;)
+ {
+ event = GKI_wait (0xFFFF, 0);
+
+ if (event & TASK_MBOX_0_EVT_MASK)
+ {
+ /* Process all messages in the queue */
+ while ((p_msg = (BT_HDR *) GKI_read_mbox (BTU_HCI_RCV_MBOX)) != NULL)
+ {
+ /* Determine the input message type. */
+ switch (p_msg->event & BT_EVT_MASK)
+ {
+ case BT_EVT_TO_BTU_HCI_ACL:
+ /* All Acl Data goes to L2CAP */
+ l2c_rcv_acl_data (p_msg);
+ break;
+
+ case BT_EVT_TO_BTU_L2C_SEG_XMIT:
+ /* L2CAP segment transmit complete */
+ l2c_link_segments_xmitted (p_msg);
+ break;
+
+ case BT_EVT_TO_BTU_HCI_SCO:
+#if BTM_SCO_INCLUDED == TRUE
+ btm_route_sco_data (p_msg);
+ break;
+#endif
+
+ case BT_EVT_TO_BTU_HCI_EVT:
+ btu_hcif_process_event ((UINT8)(p_msg->event & BT_SUB_EVT_MASK), p_msg);
+ GKI_freebuf(p_msg);
+
+#if (defined(HCILP_INCLUDED) && HCILP_INCLUDED == TRUE)
+ /* If host receives events which it doesn't response to, */
+ /* host should start idle timer to enter sleep mode. */
+ btu_check_bt_sleep ();
+#endif
+ break;
+
+ case BT_EVT_TO_BTU_HCI_CMD:
+ btu_hcif_send_cmd ((UINT8)(p_msg->event & BT_SUB_EVT_MASK), p_msg);
+ break;
+
+#if (defined(OBX_INCLUDED) && OBX_INCLUDED == TRUE)
+#if (defined(OBX_SERVER_INCLUDED) && OBX_SERVER_INCLUDED == TRUE)
+ case BT_EVT_TO_OBX_SR_MSG:
+ obx_sr_proc_evt((tOBX_PORT_EVT *)(p_msg + 1));
+ GKI_freebuf (p_msg);
+ break;
+
+ case BT_EVT_TO_OBX_SR_L2C_MSG:
+ obx_sr_proc_l2c_evt((tOBX_L2C_EVT_MSG *)(p_msg + 1));
+ GKI_freebuf (p_msg);
+ break;
+#endif
+
+#if (defined(OBX_CLIENT_INCLUDED) && OBX_CLIENT_INCLUDED == TRUE)
+ case BT_EVT_TO_OBX_CL_MSG:
+ obx_cl_proc_evt((tOBX_PORT_EVT *)(p_msg + 1));
+ GKI_freebuf (p_msg);
+ break;
+
+ case BT_EVT_TO_OBX_CL_L2C_MSG:
+ obx_cl_proc_l2c_evt((tOBX_L2C_EVT_MSG *)(p_msg + 1));
+ GKI_freebuf (p_msg);
+ break;
+#endif
+
+#if (defined(BIP_INCLUDED) && BIP_INCLUDED == TRUE)
+ case BT_EVT_TO_BIP_CMDS :
+ bip_proc_btu_event(p_msg);
+ GKI_freebuf (p_msg);
+ break;
+#endif /* BIP */
+#if (BPP_SND_INCLUDED == TRUE || BPP_INCLUDED == TRUE)
+ case BT_EVT_TO_BPP_PR_CMDS:
+ bpp_pr_proc_event(p_msg);
+ GKI_freebuf (p_msg);
+ break;
+ case BT_EVT_TO_BPP_SND_CMDS:
+ bpp_snd_proc_event(p_msg);
+ GKI_freebuf (p_msg);
+ break;
+
+#endif /* BPP */
+
+#endif /* OBX */
+
+#if (defined(SAP_SERVER_INCLUDED) && SAP_SERVER_INCLUDED == TRUE)
+ case BT_EVT_TO_BTU_SAP :
+ sap_proc_btu_event(p_msg);
+ GKI_freebuf (p_msg);
+ break;
+#endif /* SAP */
+#if (defined(GAP_CONN_INCLUDED) && GAP_CONN_INCLUDED == TRUE && GAP_CONN_POST_EVT_INCLUDED == TRUE)
+ case BT_EVT_TO_GAP_MSG :
+ gap_proc_btu_event(p_msg);
+ GKI_freebuf (p_msg);
+ break;
+#endif
+ case BT_EVT_TO_START_TIMER :
+ /* Start free running 1 second timer for list management */
+ GKI_start_timer (TIMER_0, GKI_SECS_TO_TICKS (1), TRUE);
+ GKI_freebuf (p_msg);
+ break;
+
+#if defined(QUICK_TIMER_TICKS_PER_SEC) && (QUICK_TIMER_TICKS_PER_SEC > 0)
+ case BT_EVT_TO_START_QUICK_TIMER :
+ GKI_start_timer (TIMER_2, QUICK_TIMER_TICKS, TRUE);
+ GKI_freebuf (p_msg);
+ break;
+#endif
+
+ default:
+ i = 0;
+ mask = (UINT16) (p_msg->event & BT_EVT_MASK);
+ handled = FALSE;
+
+ for (; !handled && i < BTU_MAX_REG_EVENT; i++)
+ {
+ if (btu_cb.event_reg[i].event_cb == NULL)
+ continue;
+
+ if (mask == btu_cb.event_reg[i].event_range)
+ {
+ if (btu_cb.event_reg[i].event_cb)
+ {
+ btu_cb.event_reg[i].event_cb(p_msg);
+ handled = TRUE;
+ }
+ }
+ }
+
+ if (handled == FALSE)
+ GKI_freebuf (p_msg);
+
+ break;
+ }
+ }
+ }
+
+
+ if (event & TIMER_0_EVT_MASK)
+ {
+ TIMER_LIST_ENT *p_tle;
+
+ GKI_update_timer_list (&btu_cb.timer_queue, 1);
+
+ while ((btu_cb.timer_queue.p_first) && (!btu_cb.timer_queue.p_first->ticks))
+ {
+ p_tle = btu_cb.timer_queue.p_first;
+ GKI_remove_from_timer_list (&btu_cb.timer_queue, p_tle);
+
+ switch (p_tle->event)
+ {
+ case BTU_TTYPE_BTM_DEV_CTL:
+ btm_dev_timeout(p_tle);
+ break;
+
+ case BTU_TTYPE_BTM_ACL:
+ btm_acl_timeout(p_tle);
+ break;
+
+ case BTU_TTYPE_L2CAP_LINK:
+ case BTU_TTYPE_L2CAP_CHNL:
+ case BTU_TTYPE_L2CAP_HOLD:
+ case BTU_TTYPE_L2CAP_INFO:
+ case BTU_TTYPE_L2CAP_FCR_ACK:
+
+ l2c_process_timeout (p_tle);
+ break;
+
+ case BTU_TTYPE_SDP:
+ sdp_conn_timeout ((tCONN_CB *)p_tle->param);
+ break;
+
+ case BTU_TTYPE_BTM_RMT_NAME:
+ btm_inq_rmt_name_failed();
+ break;
+
+#if (defined(RFCOMM_INCLUDED) && RFCOMM_INCLUDED == TRUE)
+ case BTU_TTYPE_RFCOMM_MFC:
+ case BTU_TTYPE_RFCOMM_PORT:
+ rfcomm_process_timeout (p_tle);
+ break;
+
+#endif /* If defined(RFCOMM_INCLUDED) && RFCOMM_INCLUDED == TRUE */
+
+#if ((defined(BNEP_INCLUDED) && BNEP_INCLUDED == TRUE))
+ case BTU_TTYPE_BNEP:
+ bnep_process_timeout(p_tle);
+ break;
+#endif
+
+
+#if (defined(AVDT_INCLUDED) && AVDT_INCLUDED == TRUE)
+ case BTU_TTYPE_AVDT_CCB_RET:
+ case BTU_TTYPE_AVDT_CCB_RSP:
+ case BTU_TTYPE_AVDT_CCB_IDLE:
+ case BTU_TTYPE_AVDT_SCB_TC:
+ avdt_process_timeout(p_tle);
+ break;
+#endif
+
+#if (defined(OBX_INCLUDED) && OBX_INCLUDED == TRUE)
+#if (defined(OBX_CLIENT_INCLUDED) && OBX_CLIENT_INCLUDED == TRUE)
+ case BTU_TTYPE_OBX_CLIENT_TO:
+ obx_cl_timeout(p_tle);
+ break;
+#endif
+#if (defined(OBX_SERVER_INCLUDED) && OBX_SERVER_INCLUDED == TRUE)
+ case BTU_TTYPE_OBX_SERVER_TO:
+ obx_sr_timeout(p_tle);
+ break;
+
+ case BTU_TTYPE_OBX_SVR_SESS_TO:
+ obx_sr_sess_timeout(p_tle);
+ break;
+#endif
+#endif
+
+#if (defined(SAP_SERVER_INCLUDED) && SAP_SERVER_INCLUDED == TRUE)
+ case BTU_TTYPE_SAP_TO:
+ sap_process_timeout(p_tle);
+ break;
+#endif
+
+ case BTU_TTYPE_BTU_CMD_CMPL:
+ btu_hcif_cmd_timeout((UINT8)(p_tle->event - BTU_TTYPE_BTU_CMD_CMPL));
+ break;
+
+#if (defined(HID_HOST_INCLUDED) && HID_HOST_INCLUDED == TRUE)
+ case BTU_TTYPE_HID_HOST_REPAGE_TO :
+ hidh_proc_repage_timeout(p_tle);
+ break;
+#endif
+
+#if (defined(BLE_INCLUDED) && BLE_INCLUDED == TRUE)
+ case BTU_TTYPE_BLE_INQUIRY:
+ case BTU_TTYPE_BLE_GAP_LIM_DISC:
+ case BTU_TTYPE_BLE_RANDOM_ADDR:
+ btm_ble_timeout(p_tle);
+ break;
+
+ case BTU_TTYPE_BLE_SCAN_PARAM_IDLE:
+ btm_ble_scan_param_idle();
+ break;
+
+ case BTU_TTYPE_ATT_WAIT_FOR_RSP:
+ gatt_rsp_timeout(p_tle);
+ break;
+
+ case BTU_TTYPE_ATT_WAIT_FOR_IND_ACK:
+ gatt_ind_ack_timeout(p_tle);
+ break;
+#if (defined(SMP_INCLUDED) && SMP_INCLUDED == TRUE)
+ case BTU_TTYPE_SMP_PAIRING_CMD:
+ smp_rsp_timeout(p_tle);
+ break;
+#endif
+
+#endif
+
+#if (MCA_INCLUDED == TRUE)
+ case BTU_TTYPE_MCA_CCB_RSP:
+ mca_process_timeout(p_tle);
+ break;
+#endif
+ case BTU_TTYPE_USER_FUNC:
+ {
+ tUSER_TIMEOUT_FUNC *p_uf = (tUSER_TIMEOUT_FUNC *)p_tle->param;
+ (*p_uf)(p_tle);
+ }
+ break;
+
+ default:
+ i = 0;
+ handled = FALSE;
+
+ for (; !handled && i < BTU_MAX_REG_TIMER; i++)
+ {
+ if (btu_cb.timer_reg[i].timer_cb == NULL)
+ continue;
+ if (btu_cb.timer_reg[i].p_tle == p_tle)
+ {
+ btu_cb.timer_reg[i].timer_cb(p_tle);
+ handled = TRUE;
+ }
+ }
+ break;
+ }
+ }
+
+ /* if timer list is empty stop periodic GKI timer */
+ if (btu_cb.timer_queue.p_first == NULL)
+ {
+ GKI_stop_timer(TIMER_0);
+ }
+ }
+
+#if defined(QUICK_TIMER_TICKS_PER_SEC) && (QUICK_TIMER_TICKS_PER_SEC > 0)
+ if (event & TIMER_2_EVT_MASK)
+ {
+ btu_process_quick_timer_evt();
+ }
+#endif
+
+
+#if (RPC_INCLUDED == TRUE)
+ /* if RPC message queue event */
+ if (event & RPCGEN_MSG_EVT)
+ {
+ if ((p_msg = (BT_HDR *) GKI_read_mbox(RPCGEN_MSG_MBOX)) != NULL)
+ RPCT_RpcgenMsg(p_msg); /* handle RPC message queue */
+ }
+#endif
+
+#if (defined(BTU_BTA_INCLUDED) && BTU_BTA_INCLUDED == TRUE)
+ if (event & TASK_MBOX_2_EVT_MASK)
+ {
+ while ((p_msg = (BT_HDR *) GKI_read_mbox(TASK_MBOX_2)) != NULL)
+ {
+ bta_sys_event(p_msg);
+ }
+ }
+
+ if (event & TIMER_1_EVT_MASK)
+ {
+ bta_sys_timer_update();
+ }
+#endif
+
+ if (event & EVENT_MASK(APPL_EVT_7))
+ break;
+ }
+
+ return(0);
+}
+
+/*******************************************************************************
+**
+** Function btu_start_timer
+**
+** Description Start a timer for the specified amount of time.
+** NOTE: The timeout resolution is in SECONDS! (Even
+** though the timer structure field is ticks)
+**
+** Returns void
+**
+*******************************************************************************/
+void btu_start_timer (TIMER_LIST_ENT *p_tle, UINT16 type, UINT32 timeout)
+{
+ BT_HDR *p_msg;
+ /* if timer list is currently empty, start periodic GKI timer */
+ if (btu_cb.timer_queue.p_first == NULL)
+ {
+ /* if timer starts on other than BTU task */
+ if (GKI_get_taskid() != BTU_TASK)
+ {
+ /* post event to start timer in BTU task */
+ if ((p_msg = (BT_HDR *)GKI_getbuf(BT_HDR_SIZE)) != NULL)
+ {
+ p_msg->event = BT_EVT_TO_START_TIMER;
+ GKI_send_msg (BTU_TASK, TASK_MBOX_0, p_msg);
+ }
+ }
+ else
+ {
+ /* Start free running 1 second timer for list management */
+ GKI_start_timer (TIMER_0, GKI_SECS_TO_TICKS (1), TRUE);
+ }
+ }
+
+ GKI_remove_from_timer_list (&btu_cb.timer_queue, p_tle);
+
+ p_tle->event = type;
+ p_tle->ticks = timeout; /* Save the number of seconds for the timer */
+
+ GKI_add_to_timer_list (&btu_cb.timer_queue, p_tle);
+}
+
+/*******************************************************************************
+**
+** Function btu_remaining_time
+**
+** Description Return amount of time to expire
+**
+** Returns time in second
+**
+*******************************************************************************/
+UINT32 btu_remaining_time (TIMER_LIST_ENT *p_tle)
+{
+ return(GKI_get_remaining_ticks (&btu_cb.timer_queue, p_tle));
+}
+
+/*******************************************************************************
+**
+** Function btu_stop_timer
+**
+** Description Stop a timer.
+**
+** Returns void
+**
+*******************************************************************************/
+void btu_stop_timer (TIMER_LIST_ENT *p_tle)
+{
+ GKI_remove_from_timer_list (&btu_cb.timer_queue, p_tle);
+
+ /* if timer list is empty stop periodic GKI timer */
+ if (btu_cb.timer_queue.p_first == NULL)
+ {
+ GKI_stop_timer(TIMER_0);
+ }
+
+}
+
+#if defined(QUICK_TIMER_TICKS_PER_SEC) && (QUICK_TIMER_TICKS_PER_SEC > 0)
+/*******************************************************************************
+**
+** Function btu_start_quick_timer
+**
+** Description Start a timer for the specified amount of time.
+** NOTE: The timeout resolution depends on including modules.
+** QUICK_TIMER_TICKS_PER_SEC should be used to convert from
+** time to ticks.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void btu_start_quick_timer (TIMER_LIST_ENT *p_tle, UINT16 type, UINT32 timeout)
+{
+ BT_HDR *p_msg;
+
+ /* if timer list is currently empty, start periodic GKI timer */
+ if (btu_cb.quick_timer_queue.p_first == NULL)
+ {
+ /* script test calls stack API without posting event */
+ if (GKI_get_taskid() != BTU_TASK)
+ {
+ /* post event to start timer in BTU task */
+ if ((p_msg = (BT_HDR *)GKI_getbuf(BT_HDR_SIZE)) != NULL)
+ {
+ p_msg->event = BT_EVT_TO_START_QUICK_TIMER;
+ GKI_send_msg (BTU_TASK, TASK_MBOX_0, p_msg);
+ }
+ }
+ else
+ GKI_start_timer(TIMER_2, QUICK_TIMER_TICKS, TRUE);
+ }
+
+ GKI_remove_from_timer_list (&btu_cb.quick_timer_queue, p_tle);
+
+ p_tle->event = type;
+ p_tle->ticks = timeout; /* Save the number of ticks for the timer */
+
+ GKI_add_to_timer_list (&btu_cb.quick_timer_queue, p_tle);
+}
+
+
+/*******************************************************************************
+**
+** Function btu_stop_quick_timer
+**
+** Description Stop a timer.
+**
+** Returns void
+**
+*******************************************************************************/
+void btu_stop_quick_timer (TIMER_LIST_ENT *p_tle)
+{
+ GKI_remove_from_timer_list (&btu_cb.quick_timer_queue, p_tle);
+
+ /* if timer list is empty stop periodic GKI timer */
+ if (btu_cb.quick_timer_queue.p_first == NULL)
+ {
+ GKI_stop_timer(TIMER_2);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btu_process_quick_timer_evt
+**
+** Description Process quick timer event
+**
+** Returns void
+**
+*******************************************************************************/
+void btu_process_quick_timer_evt(void)
+{
+ process_quick_timer_evt(&btu_cb.quick_timer_queue);
+
+ /* if timer list is empty stop periodic GKI timer */
+ if (btu_cb.quick_timer_queue.p_first == NULL)
+ {
+ GKI_stop_timer(TIMER_2);
+ }
+}
+
+/*******************************************************************************
+**
+** Function process_quick_timer_evt
+**
+** Description Process quick timer event
+**
+** Returns void
+**
+*******************************************************************************/
+void process_quick_timer_evt(TIMER_LIST_Q *p_tlq)
+{
+ TIMER_LIST_ENT *p_tle;
+
+ GKI_update_timer_list (p_tlq, 1);
+
+ while ((p_tlq->p_first) && (!p_tlq->p_first->ticks))
+ {
+ p_tle = p_tlq->p_first;
+ GKI_remove_from_timer_list (p_tlq, p_tle);
+
+ switch (p_tle->event)
+ {
+ case BTU_TTYPE_L2CAP_CHNL: /* monitor or retransmission timer */
+ case BTU_TTYPE_L2CAP_FCR_ACK: /* ack timer */
+ l2c_process_timeout (p_tle);
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+#endif /* defined(QUICK_TIMER_TICKS_PER_SEC) && (QUICK_TIMER_TICKS_PER_SEC > 0) */
+
+
+
+void btu_register_timer (TIMER_LIST_ENT *p_tle, UINT16 type, UINT32 timeout, tBTU_TIMER_CALLBACK timer_cb)
+{
+ UINT8 i = 0;
+ INT8 first = -1;
+ for (; i < BTU_MAX_REG_TIMER; i++)
+ {
+ if (btu_cb.timer_reg[i].p_tle == NULL && first < 0)
+ first = i;
+ if (btu_cb.timer_reg[i].p_tle == p_tle)
+ {
+ btu_cb.timer_reg[i].timer_cb = timer_cb;
+ btu_start_timer(p_tle, type, timeout);
+ first = -1;
+ break;
+ }
+ }
+
+ if (first >= 0 && first < BTU_MAX_REG_TIMER)
+ {
+ btu_cb.timer_reg[first].timer_cb = timer_cb;
+ btu_cb.timer_reg[first].p_tle = p_tle;
+ btu_start_timer(p_tle, type, timeout);
+ }
+
+}
+
+
+void btu_deregister_timer(TIMER_LIST_ENT *p_tle)
+{
+ UINT8 i = 0;
+
+ for (; i < BTU_MAX_REG_TIMER; i++)
+ {
+ if (btu_cb.timer_reg[i].p_tle == p_tle)
+ {
+ btu_stop_timer(p_tle);
+ btu_cb.timer_reg[i].timer_cb = NULL;
+ btu_cb.timer_reg[i].p_tle = NULL;
+ break;
+ }
+ }
+}
+
+void btu_register_event_range (UINT16 start, tBTU_EVENT_CALLBACK event_cb)
+{
+ UINT8 i = 0;
+ INT8 first = -1;
+
+ for (; i < BTU_MAX_REG_EVENT; i++)
+ {
+ if (btu_cb.event_reg[i].event_cb == NULL && first < 0)
+ first = i;
+
+ if (btu_cb.event_reg[i].event_range == start)
+ {
+ btu_cb.event_reg[i].event_cb = event_cb;
+
+ if (!event_cb)
+ btu_cb.event_reg[i].event_range = 0;
+
+ first = -1;
+ }
+ }
+
+ /* if not deregistering && an empty index was found in range, register */
+ if (event_cb && first >= 0 && first < BTU_MAX_REG_EVENT)
+ {
+ btu_cb.event_reg[first].event_range = start;
+ btu_cb.event_reg[first].event_cb = event_cb;
+ }
+}
+
+
+void btu_deregister_event_range (UINT16 range)
+{
+ btu_register_event_range(range, NULL);
+}
+
+#if (defined(HCILP_INCLUDED) && HCILP_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function btu_check_bt_sleep
+**
+** Description This function is called to check if controller can go to sleep.
+**
+** Returns void
+**
+*******************************************************************************/
+void btu_check_bt_sleep (void)
+{
+ if ((btu_cb.hci_cmd_cb[LOCAL_BR_EDR_CONTROLLER_ID].cmd_cmpl_q.count == 0)
+ &&(btu_cb.hci_cmd_cb[LOCAL_BR_EDR_CONTROLLER_ID].cmd_xmit_q.count == 0))
+ {
+ if (l2cb.controller_xmit_window == l2cb.num_lm_acl_bufs)
+ {
+ /* enable dev to sleep in the cmd cplt and cmd status only and num cplt packet */
+ HCI_LP_ALLOW_BT_DEVICE_SLEEP();
+ }
+ }
+}
+#endif
diff --git a/stack/dun/dun_api.c b/stack/dun/dun_api.c
new file mode 100644
index 0000000..ce7380e
--- /dev/null
+++ b/stack/dun/dun_api.c
@@ -0,0 +1,592 @@
+/*****************************************************************************/
+/* */
+/* Name: dun_api.c */
+/* */
+/* Description: This file contains the DUN API routines */
+/* */
+/* */
+/* Copyright (c) 1999-2009, Broadcom Corp., All Rights Reserved. */
+/* Broadcom Bluetooth Core. Proprietary and confidential. */
+/*****************************************************************************/
+
+#include <string.h>
+#include "bt_target.h"
+#include "btm_api.h"
+#include "port_api.h"
+#include "dun_api.h"
+#include "dun_int.h"
+#include "rfcdefs.h"
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+/* Number of attributes in DUN and Fax SDP records. */
+#define DUN_NUM_ATTR_DUN 4
+#define DUN_NUM_ATTR_FAX 7
+
+/* Number of protocol elements in protocol element list. */
+#define DUN_NUM_PROTO_ELEMS 2
+
+
+/* Global DUN/FAX control block structure
+*/
+#if DUN_DYNAMIC_MEMORY == FALSE
+tDUN_CB dun_cb;
+#endif
+
+/******************************************************************************
+**
+** Function dun_sdp_cback
+**
+** Description This is the SDP callback function used by DUN_FindService.
+** This function will be executed by SDP when the service
+** search is completed. If the search is successful, it
+** finds the first record in the database that matches the
+** UUID of the search. Then retrieves various parameters
+** from the record. When it is finished it calls the
+** application callback function.
+**
+** Returns Nothing.
+**
+******************************************************************************/
+static void dun_sdp_cback(UINT16 status)
+{
+ tSDP_DISC_REC *p_rec = NULL;
+ tSDP_DISC_ATTR *p_attr;
+ tSDP_PROTOCOL_ELEM pe;
+ UINT8 scn = 0;
+ UINT16 name_len = 0;
+ char *p_name = "";
+ UINT16 options = 0;
+ BOOLEAN found = FALSE;
+
+ DUN_TRACE_API1("dun_sdp_cback status: %d", status);
+
+ if (status == SDP_SUCCESS)
+ {
+ /* loop through all records we found */
+ do
+ {
+ /* get next record; if none found, we're done */
+ if ((p_rec = SDP_FindServiceInDb(dun_cb.find_cb.p_db,
+ dun_cb.find_cb.service_uuid, p_rec)) == NULL)
+ {
+ break;
+ }
+
+ /* get scn from proto desc list; if not found, go to next record */
+ if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe))
+ {
+ scn = (UINT8) pe.params[0];
+ }
+ else
+ {
+ continue;
+ }
+
+ /* get service name */
+ if ((p_attr = SDP_FindAttributeInRec(p_rec,
+ ATTR_ID_SERVICE_NAME)) != NULL)
+ {
+ p_name = (char *) p_attr->attr_value.v.array;
+ name_len = SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
+ }
+
+ /* get audio support */
+ if ((p_attr = SDP_FindAttributeInRec(p_rec,
+ ATTR_ID_AUDIO_FEEDBACK_SUPPORT)) != NULL)
+ {
+ options |= (p_attr->attr_value.v.u8) ? DUN_OPTIONS_AUDIO : 0;
+ }
+
+ /* get fax options */
+ if(dun_cb.find_cb.service_uuid == UUID_SERVCLASS_FAX)
+ {
+ if ((p_attr = SDP_FindAttributeInRec(p_rec,
+ ATTR_ID_FAX_CLASS_1_SUPPORT)) != NULL)
+ {
+ options |= (p_attr->attr_value.v.u8) ? DUN_OPTIONS_CLASS1 : 0;
+ }
+
+ if ((p_attr = SDP_FindAttributeInRec(p_rec,
+ ATTR_ID_FAX_CLASS_2_0_SUPPORT)) != NULL)
+ {
+ options |= (p_attr->attr_value.v.u8) ? DUN_OPTIONS_CLASS20 : 0;
+ }
+
+ if ((p_attr = SDP_FindAttributeInRec(p_rec,
+ ATTR_ID_FAX_CLASS_2_SUPPORT)) != NULL)
+ {
+ options |= (p_attr->attr_value.v.u8) ? DUN_OPTIONS_CLASS2 : 0;
+ }
+ }
+
+ /* we've got everything, we're done */
+ found = TRUE;
+ break;
+
+ } while (TRUE);
+ }
+
+ /* return info from sdp record in app callback function */
+ if (dun_cb.find_cb.p_cback != NULL)
+ {
+ (*dun_cb.find_cb.p_cback)(found, scn, p_name, name_len, options);
+ }
+
+ return;
+}
+
+/******************************************************************************
+**
+** Function DUN_Listen
+**
+** Description This function opens a DUN or Fax connection in server mode.
+** It configures the security settings for the connection and
+** opens an RFCOMM connection in server mode. It returns
+** the handle for the RFCOMM connection.
+**
+** Input Parameters:
+** service_uuid: Indicates DUN or Fax.
+**
+** p_service_name: A null-terminated character string
+** containing the service name. This is used for security.
+**
+** scn: The server channel number for the RFCOMM
+** connection.
+**
+** mtu: The MTU, or maximum data frame size, for the
+** RFCOMM connection.
+**
+** security_mask: Security configuration. See the BTM API.
+**
+** p_cback: RFCOMM port callback function. See the
+** RFCOMM API.
+**
+** Output Parameters:
+** p_handle: The handle for the RFCOMM connection.
+** This value is used in subsequent calls to the RFCOMM API.
+**
+** Returns DUN_SUCCESS if function execution succeeded,
+** DUN_FAIL if function execution failed.
+**
+******************************************************************************/
+UINT8 DUN_Listen(UINT16 service_uuid, char *p_service_name, UINT8 scn, UINT16 mtu,
+ UINT8 security_mask, UINT16 *p_handle, tPORT_CALLBACK *p_cback)
+{
+ BD_ADDR bd_addr = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+ UINT8 status = DUN_SUCCESS;
+ UINT8 service_id;
+
+ DUN_TRACE_API1("DUN_Listen uuid: %x", service_uuid);
+
+ switch (service_uuid)
+ {
+ case UUID_SERVCLASS_DIALUP_NETWORKING:
+ service_id = BTM_SEC_SERVICE_DUN;
+ break;
+
+ case UUID_SERVCLASS_FAX:
+ service_id = BTM_SEC_SERVICE_FAX;
+ break;
+
+ case UUID_SERVCLASS_SERIAL_PORT:
+ default:
+ service_id = BTM_SEC_SERVICE_SERIAL_PORT;
+ break;
+ }
+
+ /* set up security */
+ if (BTM_SetSecurityLevel(FALSE, (char *) p_service_name, service_id,
+ security_mask, BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM, scn) == FALSE)
+ {
+ status = DUN_FAIL;
+ }
+
+ /* open rfcomm server connection */
+ if (status == DUN_SUCCESS)
+ {
+ if (RFCOMM_CreateConnection(service_uuid, scn, TRUE, mtu, bd_addr,
+ p_handle, p_cback) != PORT_SUCCESS)
+ {
+ status = DUN_FAIL;
+ }
+ }
+
+ return status;
+}
+
+/******************************************************************************
+**
+** Function DUN_Connect
+**
+** Description This function opens a DUN or Fax client connection.
+** It configures the security settings for the connection
+** and opens an RFCOMM connection in server mode.
+** It returns the handle for the RFCOMM connection.
+**
+** Input Parameters:
+** service_uuid: Indicates DUN or Fax.
+**
+** bd_addr: BD address of the peer device.
+**
+** scn: The server channel number for the RFCOMM
+** connection.
+**
+** mtu: The MTU, or maximum data frame size, for the
+** RFCOMM connection.
+**
+** security_mask: Security configuration. See the BTM API.
+**
+** p_cback: RFCOMM port callback function. See the
+** RFCOMM API.
+**
+** Output Parameters:
+** p_handle: The handle for the RFCOMM connection.
+** This value is used in subsequent calls to the RFCOMM API.
+**
+** Returns DUN_SUCCESS if function execution succeeded,
+** DUN_FAIL if function execution failed.
+**
+******************************************************************************/
+UINT8 DUN_Connect(UINT16 service_uuid, BD_ADDR bd_addr, UINT8 scn, UINT16 mtu,
+ UINT8 security_mask, UINT16 *p_handle, tPORT_CALLBACK *p_cback)
+{
+ char name[] = ""; /* don't bother using a name for security */
+ UINT8 status = DUN_SUCCESS;
+ UINT8 service_id;
+
+ DUN_TRACE_API1("DUN_Connect uuid: %x", service_uuid);
+
+ switch (service_uuid)
+ {
+ case UUID_SERVCLASS_DIALUP_NETWORKING:
+ service_id = BTM_SEC_SERVICE_DUN;
+ break;
+
+ case UUID_SERVCLASS_FAX:
+ service_id = BTM_SEC_SERVICE_FAX;
+ break;
+
+ case UUID_SERVCLASS_SERIAL_PORT:
+ default:
+ service_id = BTM_SEC_SERVICE_SERIAL_PORT;
+ break;
+ }
+
+ /* set up security */
+ if(BTM_SetSecurityLevel(TRUE, name, service_id, security_mask,
+ BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM, scn) == FALSE)
+ {
+ status = DUN_FAIL;
+ }
+
+ /* open rfcomm client connection */
+ if (status == DUN_SUCCESS)
+ {
+ if (RFCOMM_CreateConnection(service_uuid, scn, FALSE, mtu, bd_addr,
+ p_handle, p_cback) != PORT_SUCCESS)
+ {
+ status = DUN_FAIL;
+ }
+ }
+
+ return status;
+}
+
+
+/******************************************************************************
+**
+** Function DUN_Close
+**
+** Description This function closes a DUN or Fax client connection
+** previously opened with DUN_Connect().
+**
+** Input Parameters:
+** handle: The handle for the RFCOMM connection
+** previously returned by DUN_Connect().
+**
+** Output Parameters:
+** None.
+**
+** Returns DUN_SUCCESS if function execution succeeded,
+** DUN_FAIL if function execution failed.
+**
+******************************************************************************/
+UINT8 DUN_Close(UINT16 handle)
+{
+ UINT8 status = DUN_SUCCESS;
+
+ DUN_TRACE_API0("DUN_close");
+
+ if (RFCOMM_RemoveConnection(handle) != PORT_SUCCESS)
+ {
+ status = DUN_FAIL;
+ }
+
+ return status;
+}
+
+
+/******************************************************************************
+**
+** Function DUN_Shutdown
+**
+** Description This function closes a DUN or Fax server connection
+** previously opened with DUN_Listen(). It is called if
+** the application wishes to close the DUN or Fax server
+** connection at any time.
+**
+** Input Parameters:
+** service_uuid: Indicates DUN or Fax.
+**
+** handle: The handle for the RFCOMM connection
+** previously returned by DUN_Connect().
+**
+** Output Parameters:
+** None.
+**
+** Returns DUN_SUCCESS if function execution succeeded,
+** DUN_FAIL if function execution failed.
+**
+******************************************************************************/
+UINT8 DUN_Shutdown(UINT16 handle)
+{
+ UINT8 status = DUN_SUCCESS;
+
+ DUN_TRACE_API0("DUN_Shutdown");
+
+ /* close rfcomm connection */
+ if (RFCOMM_RemoveServer(handle) != PORT_SUCCESS)
+ {
+ status = DUN_FAIL;
+ }
+
+ return status;
+}
+
+/******************************************************************************
+**
+** Function DUN_AddRecord
+**
+** Description This function is called by a server application to add
+** DUN or Fax information to an SDP record. Prior to
+** calling this function the application must call
+** SDP_CreateRecord() to create an SDP record.
+**
+** Input Parameters:
+** service_uuid: Indicates DUN or Fax.
+**
+** p_service_name: Pointer to a null-terminated character
+** string containing the service name.
+**
+** scn: The server channel number of the RFCOMM
+** connection.
+**
+** options: Profile support options.
+**
+** sdp_handle: SDP handle returned by SDP_CreateRecord().
+**
+** Output Parameters:
+** None.
+**
+** Returns DUN_SUCCESS if function execution succeeded,
+** DUN_FAIL if function execution failed.
+**
+******************************************************************************/
+UINT8 DUN_AddRecord(UINT16 service_uuid, char *p_service_name, UINT8 scn,
+ UINT16 options, UINT32 sdp_handle)
+{
+ tSDP_PROTOCOL_ELEM proto_elem_list[DUN_NUM_PROTO_ELEMS];
+ UINT8 audio;
+ UINT8 class1;
+ UINT8 class20;
+ UINT8 class2;
+ UINT16 browse_list[1];
+ BOOLEAN result = TRUE;
+
+ DUN_TRACE_API1("DUN_AddRecord uuid: %x", service_uuid);
+
+ memset((void*) proto_elem_list, 0 , DUN_NUM_PROTO_ELEMS*sizeof(tSDP_PROTOCOL_ELEM));
+
+ /* add the protocol element sequence */
+ proto_elem_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+ proto_elem_list[0].num_params = 0;
+ proto_elem_list[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
+ proto_elem_list[1].num_params = 1;
+ proto_elem_list[1].params[0] = scn;
+ result &= SDP_AddProtocolList(sdp_handle, DUN_NUM_PROTO_ELEMS, proto_elem_list);
+
+ /* add service class id list */
+ result &= SDP_AddServiceClassIdList(sdp_handle, 1, &service_uuid);
+
+ /* add service name */
+ if (p_service_name != NULL)
+ {
+ result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE,
+ (UINT32)(strlen(p_service_name)+1), (UINT8 *) p_service_name);
+ }
+
+ /* add audio feedback support */
+ if((service_uuid == UUID_SERVCLASS_FAX) ||
+ (service_uuid == UUID_SERVCLASS_DIALUP_NETWORKING))
+ {
+ audio = (options & DUN_OPTIONS_AUDIO) ? TRUE : FALSE;
+ result &= SDP_AddAttribute(sdp_handle, ATTR_ID_AUDIO_FEEDBACK_SUPPORT,
+ BOOLEAN_DESC_TYPE, 1, &audio);
+ }
+
+ /* add fax service class support */
+ if(service_uuid == UUID_SERVCLASS_FAX)
+ {
+ class1 = (options & DUN_OPTIONS_CLASS1) ? TRUE : FALSE;
+ result &= SDP_AddAttribute(sdp_handle, ATTR_ID_FAX_CLASS_1_SUPPORT,
+ BOOLEAN_DESC_TYPE, 1, &class1);
+
+ class20 = (options & DUN_OPTIONS_CLASS20) ? TRUE : FALSE;
+ result &= SDP_AddAttribute(sdp_handle, ATTR_ID_FAX_CLASS_2_0_SUPPORT,
+ BOOLEAN_DESC_TYPE, 1, &class20);
+
+ class2 = (options & DUN_OPTIONS_CLASS2) ? TRUE : FALSE;
+ result &= SDP_AddAttribute(sdp_handle, ATTR_ID_FAX_CLASS_2_SUPPORT,
+ BOOLEAN_DESC_TYPE, 1, &class2);
+ }
+
+ /* add browse group list */
+ browse_list[0] = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
+ result &= SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, browse_list);
+
+ /* add profile descriptor list */
+ if (service_uuid != UUID_SERVCLASS_SERIAL_PORT) /* BQB fix: BTA DG uses this for SPP */
+ result &= SDP_AddProfileDescriptorList(sdp_handle, service_uuid, 0x0100);
+
+ return (result ? DUN_SUCCESS : DUN_FAIL);
+}
+
+/******************************************************************************
+**
+** Function DUN_FindService
+**
+** Description This function is called by a client application to
+** perform service discovery and retrieve DUN or Fax SDP
+** record information from a server. Information is
+** returned for the first service record found on the
+** server that matches the service UUID. The callback
+** function will be executed when service discovery is
+** complete. There can only be one outstanding call to
+** DUN_FindService() at a time; the application must wait
+** for the callback before it makes another call to
+** the function.
+**
+** Input Parameters:
+** service_uuid: Indicates DUN or Fax.
+**
+** bd_addr: BD address of the peer device.
+**
+** p_db: Pointer to the discovery database.
+**
+** db_len: Length, in bytes, of the discovery database.
+**
+** p_cback: Pointer to the DUN_FindService()
+** callback function.
+**
+** Output Parameters:
+** None.
+**
+** Returns DUN_SUCCESS if function execution succeeded,
+** DUN_FAIL if function execution failed.
+**
+******************************************************************************/
+UINT8 DUN_FindService(UINT16 service_uuid, BD_ADDR bd_addr,
+ tSDP_DISCOVERY_DB *p_db, UINT32 db_len, tDUN_FIND_CBACK *p_cback)
+{
+ tSDP_UUID uuid_list;
+ UINT16 num_attr;
+ BOOLEAN result = TRUE;
+ UINT16 dun_attr_list[] = {ATTR_ID_SERVICE_CLASS_ID_LIST,
+ ATTR_ID_PROTOCOL_DESC_LIST,
+ ATTR_ID_SERVICE_NAME,
+ ATTR_ID_AUDIO_FEEDBACK_SUPPORT,
+ ATTR_ID_FAX_CLASS_1_SUPPORT,
+ ATTR_ID_FAX_CLASS_2_0_SUPPORT,
+ ATTR_ID_FAX_CLASS_2_SUPPORT};
+
+ DUN_TRACE_API1("DUN_FindService uuid: %x", service_uuid);
+
+ /* set up discovery database */
+ uuid_list.len = LEN_UUID_16;
+ uuid_list.uu.uuid16 = service_uuid;
+
+ num_attr = (service_uuid == UUID_SERVCLASS_FAX) ?
+ DUN_NUM_ATTR_FAX : DUN_NUM_ATTR_DUN;
+
+ result = SDP_InitDiscoveryDb(p_db, db_len, 1, &uuid_list, num_attr,
+ (UINT16 *) dun_attr_list);
+
+ if (result == TRUE)
+ {
+ /* store service_uuid and discovery db pointer */
+ dun_cb.find_cb.p_db = p_db;
+ dun_cb.find_cb.service_uuid = service_uuid;
+ dun_cb.find_cb.p_cback = p_cback;
+
+ /* perform service search */
+ result = SDP_ServiceSearchAttributeRequest(bd_addr, p_db, dun_sdp_cback);
+ }
+
+ return (result ? DUN_SUCCESS : DUN_FAIL);
+}
+
+/*******************************************************************************
+**
+** Function DUN_Init
+**
+** Description This function is called to initialize the control block
+** for this layer. It must be called before accessing any
+** other API functions for this layer. It is typically called
+** once during the start up of the stack.
+**
+** Returns void
+**
+*******************************************************************************/
+void DUN_Init (void)
+{
+ /* All fields are cleared; nonzero fields are reinitialized in appropriate function */
+ memset(&dun_cb, 0, sizeof(tDUN_CB));
+
+#if defined(DUN_INITIAL_TRACE_LEVEL)
+ dun_cb.trace_level = DUN_INITIAL_TRACE_LEVEL;
+#else
+ dun_cb.trace_level = BT_TRACE_LEVEL_NONE; /* No traces */
+#endif
+}
+
+/******************************************************************************
+**
+** Function DUN_SetTraceLevel
+**
+** Description Sets the trace level for DUN. If 0xff is passed, the
+** current trace level is returned.
+**
+** Input Parameters:
+** new_level: The level to set the DUN tracing to:
+** 0xff-returns the current setting.
+** 0-turns off tracing.
+** >= 1-Errors.
+** >= 2-Warnings.
+** >= 3-APIs.
+** >= 4-Events.
+** >= 5-Debug.
+**
+** Returns The new trace level or current trace level if
+** the input parameter is 0xff.
+**
+******************************************************************************/
+UINT8 DUN_SetTraceLevel (UINT8 new_level)
+{
+ if (new_level != 0xFF)
+ dun_cb.trace_level = new_level;
+
+ return (dun_cb.trace_level);
+}
diff --git a/stack/dun/dun_int.h b/stack/dun/dun_int.h
new file mode 100644
index 0000000..1e23bdc
--- /dev/null
+++ b/stack/dun/dun_int.h
@@ -0,0 +1,63 @@
+/*****************************************************************************
+**
+** Name: dun_int.h
+**
+** File: dun/fax type definitions
+**
+** Copyright (c) 2002-2004, WIDCOMM Inc., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef DUN_INT_H
+#define DUN_INT_H
+
+#include "dun_api.h"
+#include "sdp_api.h"
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+/*****************************************************************************
+** DUN Control Blocks
+******************************************************************************/
+/*****************************************************************************
+** Type definitions
+*****************************************************************************/
+/* Control block used by DUN_FindService(). */
+typedef struct
+{
+ tDUN_FIND_CBACK *p_cback; /* pointer to application callback */
+ tSDP_DISCOVERY_DB *p_db; /* pointer to discovery database */
+ UINT16 service_uuid; /* service UUID of search */
+} tDUN_FIND_CB;
+
+typedef struct
+{
+ tDUN_FIND_CB find_cb;
+ UINT8 trace_level;
+} tDUN_CB;
+
+/*****************************************************************************
+** External Definitions
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/*
+** Define prototypes for global data
+*/
+#if DUN_DYNAMIC_MEMORY == FALSE
+DUN_API extern tDUN_CB dun_cb;
+#else
+DUN_API extern tDUN_CB *dun_cb_ptr;
+#define dun_cb (*dun_cb_ptr)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* DUN_INT_H */
+
diff --git a/stack/gatt/att_protocol.c b/stack/gatt/att_protocol.c
new file mode 100644
index 0000000..f3c3a28
--- /dev/null
+++ b/stack/gatt/att_protocol.c
@@ -0,0 +1,617 @@
+/*****************************************************************************
+**
+** Name: att_protocl.c
+**
+** Description: this file contains ATT protocol functions
+**
+**
+** Copyright (c) 2008-2010, Broadcom Corp, All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+
+#include "bt_target.h"
+
+#if BLE_INCLUDED == TRUE
+
+#include "gatt_int.h"
+#include "l2c_api.h"
+
+#define GATT_HDR_FIND_TYPE_VALUE_LEN 21
+#define GATT_OP_CODE_SIZE 1
+/**********************************************************************
+** ATT protocl message building utility *
+***********************************************************************/
+/*******************************************************************************
+**
+** Function attp_build_mtu_exec_cmd
+**
+** Description Build a exchange MTU request
+**
+** Returns None.
+**
+*******************************************************************************/
+BT_HDR *attp_build_mtu_cmd(UINT8 op_code, UINT16 rx_mtu)
+{
+ BT_HDR *p_buf = NULL;
+ UINT8 *p;
+
+ if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + GATT_HDR_SIZE + L2CAP_MIN_OFFSET)) != NULL)
+ {
+ p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ UINT8_TO_STREAM (p, op_code);
+ UINT16_TO_STREAM (p, rx_mtu);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = GATT_HDR_SIZE; /* opcode + 2 bytes mtu */
+ }
+ return p_buf;
+}
+/*******************************************************************************
+**
+** Function attp_build_exec_write_cmd
+**
+** Description Build a execute write request or response.
+**
+** Returns None.
+**
+*******************************************************************************/
+BT_HDR *attp_build_exec_write_cmd (UINT8 op_code, UINT8 flag)
+{
+ BT_HDR *p_buf = NULL;
+ UINT8 *p;
+
+ if ((p_buf = (BT_HDR *)GKI_getbuf((UINT16)(sizeof(BT_HDR) + 10 + L2CAP_MIN_OFFSET))) != NULL)
+ {
+ p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = GATT_OP_CODE_SIZE;
+
+ UINT8_TO_STREAM (p, op_code);
+
+ if (op_code == GATT_REQ_EXEC_WRITE)
+ {
+ flag &= GATT_PREP_WRITE_EXEC;
+ UINT8_TO_STREAM (p, flag);
+ p_buf->len += 1;
+ }
+
+ }
+
+ return p_buf;
+}
+
+/*******************************************************************************
+**
+** Function attp_build_err_cmd
+**
+** Description Build a exchange MTU request
+**
+** Returns None.
+**
+*******************************************************************************/
+BT_HDR *attp_build_err_cmd(UINT8 cmd_code, UINT16 err_handle, UINT8 reason)
+{
+ BT_HDR *p_buf = NULL;
+ UINT8 *p;
+
+ if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + L2CAP_MIN_OFFSET + 5)) != NULL)
+ {
+ p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ UINT8_TO_STREAM (p, GATT_RSP_ERROR);
+ UINT8_TO_STREAM (p, cmd_code);
+ UINT16_TO_STREAM(p, err_handle);
+ UINT8_TO_STREAM (p, reason);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ /* GATT_HDR_SIZE (1B ERR_RSP op code+ 2B handle) + 1B cmd_op_code + 1B status */
+ p_buf->len = GATT_HDR_SIZE + 1 + 1;
+ }
+ return p_buf;
+}
+/*******************************************************************************
+**
+** Function attp_build_browse_cmd
+**
+** Description Build a read information request or read by type request
+**
+** Returns None.
+**
+*******************************************************************************/
+BT_HDR *attp_build_browse_cmd(UINT8 op_code, UINT16 s_hdl, UINT16 e_hdl, tBT_UUID uuid)
+{
+ BT_HDR *p_buf = NULL;
+ UINT8 *p;
+
+ if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + 8 + L2CAP_MIN_OFFSET)) != NULL)
+ {
+ p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+ /* Describe the built message location and size */
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = GATT_OP_CODE_SIZE + 4;
+
+ UINT8_TO_STREAM (p, op_code);
+ UINT16_TO_STREAM (p, s_hdl);
+ UINT16_TO_STREAM (p, e_hdl);
+ p_buf->len += gatt_build_uuid_to_stream(&p, uuid);
+ }
+
+ return p_buf;
+}
+/*******************************************************************************
+**
+** Function attp_build_read_handles_cmd
+**
+** Description Build a read by type and value request.
+**
+** Returns pointer to the command buffer.
+**
+*******************************************************************************/
+BT_HDR *attp_build_read_handles_cmd (UINT16 payload_size, tGATT_FIND_TYPE_VALUE *p_value_type)
+{
+ BT_HDR *p_buf = NULL;
+ UINT8 *p;
+ UINT16 len = p_value_type->value_len;
+
+ if ((p_buf = (BT_HDR *)GKI_getbuf((UINT16)(sizeof(BT_HDR) + payload_size + L2CAP_MIN_OFFSET))) != NULL)
+ {
+ p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = 5; /* opcode + s_handle + e_handle */
+
+ UINT8_TO_STREAM (p, GATT_REQ_FIND_TYPE_VALUE);
+ UINT16_TO_STREAM (p, p_value_type->s_handle);
+ UINT16_TO_STREAM (p, p_value_type->e_handle);
+
+ p_buf->len += gatt_build_uuid_to_stream(&p, p_value_type->uuid);
+
+ if (p_value_type->value_len + p_buf->len > payload_size )
+ len = payload_size - p_buf->len;
+
+ memcpy (p, p_value_type->value, len);
+ p_buf->len += len;
+ }
+
+ return p_buf;
+}
+/*******************************************************************************
+**
+** Function attp_build_read_multi_cmd
+**
+** Description Build a read multiple request
+**
+** Returns None.
+**
+*******************************************************************************/
+BT_HDR *attp_build_read_multi_cmd(UINT16 payload_size, UINT16 num_handle, UINT16 *p_handle)
+{
+ BT_HDR *p_buf = NULL;
+ UINT8 *p, i = 0;
+
+ if ((p_buf = (BT_HDR *)GKI_getbuf((UINT16)(sizeof(BT_HDR) + num_handle * 2 + 1 + L2CAP_MIN_OFFSET))) != NULL)
+ {
+ p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = 1;
+
+ UINT8_TO_STREAM (p, GATT_REQ_READ_MULTI);
+
+ for (i = 0; i < num_handle && p_buf->len + 2 <= payload_size; i ++)
+ {
+ UINT16_TO_STREAM (p, *(p_handle + i));
+ p_buf->len += 2;
+ }
+ }
+
+ return p_buf;
+}
+/*******************************************************************************
+**
+** Function attp_build_handle_cmd
+**
+** Description Build a read /read blob request
+**
+** Returns None.
+**
+*******************************************************************************/
+BT_HDR *attp_build_handle_cmd(UINT8 op_code, UINT16 handle, UINT16 offset)
+{
+ BT_HDR *p_buf = NULL;
+ UINT8 *p;
+
+ if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + 5 + L2CAP_MIN_OFFSET)) != NULL)
+ {
+ p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+
+ UINT8_TO_STREAM (p, op_code);
+ p_buf->len = 1;
+
+ UINT16_TO_STREAM (p, handle);
+ p_buf->len += 2;
+
+ if (op_code == GATT_REQ_READ_BLOB)
+ {
+ UINT16_TO_STREAM (p, offset);
+ p_buf->len += 2;
+ }
+
+ }
+
+ return p_buf;
+}
+/*******************************************************************************
+**
+** Function attp_build_opcode_cmd
+**
+** Description Build a request/response with opcode only.
+**
+** Returns None.
+**
+*******************************************************************************/
+BT_HDR *attp_build_opcode_cmd(UINT8 op_code)
+{
+ BT_HDR *p_buf = NULL;
+ UINT8 *p;
+
+ if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + 1 + L2CAP_MIN_OFFSET)) != NULL)
+ {
+ p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+ p_buf->offset = L2CAP_MIN_OFFSET;
+
+ UINT8_TO_STREAM (p, op_code);
+ p_buf->len = 1;
+ }
+
+ return p_buf;
+}
+/*******************************************************************************
+**
+** Function attp_build_value_cmd
+**
+** Description Build a attribute value request
+**
+** Returns None.
+**
+*******************************************************************************/
+BT_HDR *attp_build_value_cmd (UINT16 payload_size, UINT8 op_code, UINT16 handle,
+ UINT16 offset, UINT16 len, UINT8 *p_data)
+{
+ BT_HDR *p_buf = NULL;
+ UINT8 *p, *pp, pair_len, *p_pair_len;
+
+ if ((p_buf = (BT_HDR *)GKI_getbuf((UINT16)(sizeof(BT_HDR) + payload_size + L2CAP_MIN_OFFSET))) != NULL)
+ {
+ p = pp =(UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ UINT8_TO_STREAM (p, op_code);
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = 1;
+
+ if (op_code == GATT_RSP_READ_BY_TYPE)
+ {
+ p_pair_len = p;
+ pair_len = len + 2;
+ UINT8_TO_STREAM (p, pair_len);
+ p_buf->len += 1;
+ }
+ if (op_code != GATT_RSP_READ_BLOB && op_code != GATT_RSP_READ)
+ {
+ UINT16_TO_STREAM (p, handle);
+ p_buf->len += 2;
+ }
+
+ if (op_code == GATT_REQ_PREPARE_WRITE ||op_code == GATT_RSP_PREPARE_WRITE )
+ {
+ UINT16_TO_STREAM (p, offset);
+ p_buf->len += 2;
+ }
+
+ if (len > 0 && p_data != NULL)
+ {
+ /* ensure data not exceed MTU size */
+ if (payload_size - p_buf->len < len)
+ {
+ len = payload_size - p_buf->len;
+ /* update handle value pair length */
+ if (op_code == GATT_RSP_READ_BY_TYPE)
+ *p_pair_len = (len + 2);
+
+ GATT_TRACE_WARNING1("attribute value too long, to be truncated to %d", len);
+ }
+
+ ARRAY_TO_STREAM (p, p_data, len);
+ p_buf->len += len;
+ }
+ }
+ return p_buf;
+}
+
+/*******************************************************************************
+**
+** Function attp_send_msg_to_L2CAP
+**
+** Description Send message to L2CAP.
+**
+*******************************************************************************/
+BOOLEAN attp_send_msg_to_L2CAP(tGATT_TCB *p_tcb, BT_HDR *p_toL2CAP)
+{
+ UINT16 l2cap_ret;
+
+
+ if (p_tcb->att_lcid == L2CAP_ATT_CID)
+ l2cap_ret = L2CA_SendFixedChnlData (L2CAP_ATT_CID, p_tcb->peer_bda, p_toL2CAP);
+ else
+ l2cap_ret = (UINT16) L2CA_DataWrite (p_tcb->att_lcid, p_toL2CAP);
+
+ if (l2cap_ret == L2CAP_DW_FAILED)
+ {
+ GATT_TRACE_ERROR1("ATT failed to pass msg:0x%0x to L2CAP",
+ *((UINT8 *)(p_toL2CAP + 1) + p_toL2CAP->offset));
+ GKI_freebuf(p_toL2CAP);
+ return FALSE;
+ }
+ else
+ {
+ return TRUE;
+ }
+}
+
+/*******************************************************************************
+**
+** Function attp_build_sr_msg
+**
+** Description Build ATT Server PDUs.
+**
+*******************************************************************************/
+BT_HDR *attp_build_sr_msg(tGATT_TCB *p_tcb, UINT8 op_code, tGATT_SR_MSG *p_msg)
+{
+ BT_HDR *p_cmd = NULL;
+ UINT16 offset = 0;
+
+ switch (op_code)
+ {
+ case GATT_RSP_READ_BLOB:
+ GATT_TRACE_EVENT2 ("ATT_RSP_READ_BLOB: len = %d offset = %d", p_msg->attr_value.len, p_msg->attr_value.offset);
+ offset = p_msg->attr_value.offset;
+
+ case GATT_RSP_PREPARE_WRITE:
+ if (offset == 0)
+ offset = p_msg->attr_value.offset;
+
+ case GATT_RSP_READ_BY_TYPE:
+ case GATT_RSP_READ:
+ case GATT_HANDLE_VALUE_NOTIF:
+ case GATT_HANDLE_VALUE_IND:
+ p_cmd = attp_build_value_cmd(p_tcb->payload_size,
+ op_code,
+ p_msg->attr_value.handle,
+ offset,
+ p_msg->attr_value.len,
+ p_msg->attr_value.value);
+ break;
+
+ case GATT_RSP_WRITE:
+ p_cmd = attp_build_opcode_cmd(op_code);
+ break;
+
+ case GATT_RSP_ERROR:
+ p_cmd = attp_build_err_cmd(p_msg->error.cmd_code, p_msg->error.handle, p_msg->error.reason);
+ break;
+
+ case GATT_RSP_EXEC_WRITE:
+ p_cmd = attp_build_exec_write_cmd(op_code, 0);
+ break;
+
+ case GATT_RSP_MTU:
+ p_cmd = attp_build_mtu_cmd(op_code, p_msg->mtu);
+ break;
+
+ default:
+ GATT_TRACE_DEBUG1("attp_build_sr_msg: unknown op code = %d", op_code);
+ break;
+ }
+
+ if (!p_cmd)
+ GATT_TRACE_ERROR0("No resources");
+
+ return p_cmd;
+}
+
+/*******************************************************************************
+**
+** Function attp_send_sr_msg
+**
+** Description This function sends the server response or indication message
+** to client.
+**
+** Parameter p_tcb: pointer to the connecton control block.
+** p_msg: pointer to message parameters structure.
+**
+** Returns GATT_SUCCESS if sucessfully sent; otherwise error code.
+**
+**
+*******************************************************************************/
+tGATT_STATUS attp_send_sr_msg (tGATT_TCB *p_tcb, BT_HDR *p_msg)
+{
+ tGATT_STATUS cmd_sent = GATT_NO_RESOURCES;
+
+ if (p_tcb != NULL)
+ {
+ if (p_msg != NULL)
+ {
+ p_msg->offset = L2CAP_MIN_OFFSET;
+
+ if (attp_send_msg_to_L2CAP (p_tcb, p_msg))
+ cmd_sent = GATT_SUCCESS;
+ else
+ cmd_sent = GATT_INTERNAL_ERROR;
+ }
+ }
+ return cmd_sent;
+}
+
+/*******************************************************************************
+**
+** Function attp_cl_send_cmd
+**
+** Description Send a ATT command or enqueue it.
+**
+** Returns TRUE if command sent, otherwise FALSE.
+**
+*******************************************************************************/
+UINT8 attp_cl_send_cmd(tGATT_TCB *p_tcb, UINT16 clcb_idx, UINT8 cmd_code, BT_HDR *p_cmd)
+{
+ UINT8 att_ret = GATT_SUCCESS;
+
+ if (p_tcb != NULL)
+ {
+ cmd_code &= ~GATT_AUTH_SIGN_MASK;
+
+ if (p_tcb->pending_cl_req == p_tcb->next_slot_inq ||
+ cmd_code == GATT_HANDLE_VALUE_CONF)
+ {
+ /* no penindg request or value confirmation */
+ if (attp_send_msg_to_L2CAP(p_tcb, p_cmd))
+ {
+ /* do not enq cmd if handle value confirmation or set request */
+ if (cmd_code != GATT_HANDLE_VALUE_CONF && cmd_code != GATT_CMD_WRITE)
+ {
+ gatt_start_rsp_timer (p_tcb);
+ gatt_cmd_enq(p_tcb, clcb_idx, FALSE, cmd_code, NULL);
+ }
+ }
+ else
+ att_ret = GATT_INTERNAL_ERROR;
+ }
+ else
+ gatt_cmd_enq(p_tcb, clcb_idx, TRUE, cmd_code, p_cmd);
+ }
+ else
+ att_ret = GATT_ILLEGAL_PARAMETER;
+
+ return att_ret;
+}
+/*******************************************************************************
+**
+** Function attp_send_cl_msg
+**
+** Description This function sends the client request or confirmation message
+** to server.
+**
+** Parameter p_tcb: pointer to the connectino control block.
+** clcb_idx: clcb index
+** op_code: message op code.
+** p_msg: pointer to message parameters structure.
+**
+** Returns GATT_SUCCESS if sucessfully sent; otherwise error code.
+**
+**
+*******************************************************************************/
+tGATT_STATUS attp_send_cl_msg (tGATT_TCB *p_tcb, UINT16 clcb_idx, UINT8 op_code, tGATT_CL_MSG *p_msg)
+{
+ tGATT_STATUS status = GATT_NO_RESOURCES;
+ BT_HDR *p_cmd = NULL;
+ UINT16 offset = 0, handle;
+
+ if (p_tcb != NULL)
+ {
+ switch (op_code)
+ {
+ case GATT_REQ_MTU:
+ if (p_msg->mtu <= GATT_MAX_MTU_SIZE)
+ {
+ p_tcb->payload_size = p_msg->mtu;
+ p_cmd = attp_build_mtu_cmd(GATT_REQ_MTU, p_msg->mtu);
+ }
+ else
+ status = GATT_ILLEGAL_PARAMETER;
+ break;
+
+ case GATT_REQ_FIND_INFO:
+ case GATT_REQ_READ_BY_TYPE:
+ case GATT_REQ_READ_BY_GRP_TYPE:
+ if (GATT_HANDLE_IS_VALID (p_msg->browse.s_handle) &&
+ GATT_HANDLE_IS_VALID (p_msg->browse.e_handle) &&
+ p_msg->browse.s_handle <= p_msg->browse.e_handle)
+ {
+ p_cmd = attp_build_browse_cmd(op_code,
+ p_msg->browse.s_handle,
+ p_msg->browse.e_handle,
+ p_msg->browse.uuid);
+ }
+ else
+ status = GATT_ILLEGAL_PARAMETER;
+ break;
+
+ case GATT_REQ_READ_BLOB:
+ offset = p_msg->read_blob.offset;
+ /* fall through */
+ case GATT_REQ_READ:
+ handle = (op_code == GATT_REQ_READ) ? p_msg->handle: p_msg->read_blob.handle;
+ /* handle checking */
+ if (GATT_HANDLE_IS_VALID (handle))
+ {
+ p_cmd = attp_build_handle_cmd(op_code, handle, offset);
+ }
+ else
+ status = GATT_ILLEGAL_PARAMETER;
+ break;
+
+ case GATT_HANDLE_VALUE_CONF:
+ p_cmd = attp_build_opcode_cmd(op_code);
+ break;
+
+ case GATT_REQ_PREPARE_WRITE:
+ offset = p_msg->attr_value.offset;
+ /* fall through */
+ case GATT_REQ_WRITE:
+ case GATT_CMD_WRITE:
+ case GATT_SIGN_CMD_WRITE:
+ if (GATT_HANDLE_IS_VALID (p_msg->attr_value.handle))
+ {
+ p_cmd = attp_build_value_cmd (p_tcb->payload_size,
+ op_code, p_msg->attr_value.handle,
+ offset,
+ p_msg->attr_value.len,
+ p_msg->attr_value.value);
+ }
+ else
+ status = GATT_ILLEGAL_PARAMETER;
+ break;
+
+ case GATT_REQ_EXEC_WRITE:
+ p_cmd = attp_build_exec_write_cmd(op_code, p_msg->exec_write);
+ break;
+
+ case GATT_REQ_FIND_TYPE_VALUE:
+ p_cmd = attp_build_read_handles_cmd(p_tcb->payload_size, &p_msg->find_type_value);
+ break;
+
+ case GATT_REQ_READ_MULTI:
+ p_cmd = attp_build_read_multi_cmd(p_tcb->payload_size,
+ p_msg->read_multi.num_handles,
+ p_msg->read_multi.handles);
+ break;
+
+ default:
+ break;
+ }
+
+ if (p_cmd != NULL)
+ status = attp_cl_send_cmd(p_tcb, clcb_idx, op_code, p_cmd);
+
+ }
+ else
+ {
+ GATT_TRACE_ERROR0("Peer device not connected");
+ }
+
+ return status;
+}
+#endif
diff --git a/stack/gatt/gatt_api.c b/stack/gatt/gatt_api.c
new file mode 100644
index 0000000..c01d617
--- /dev/null
+++ b/stack/gatt/gatt_api.c
@@ -0,0 +1,1542 @@
+/*****************************************************************************
+**
+** Name: gatt_api.c
+**
+** Description: this file contains GATT interface functions
+**
+**
+** Copyright (c) 1999-2011, Broadcom Corp, All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+#include "bt_target.h"
+
+
+#if defined(BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE)
+
+#include "gki.h"
+#include <stdio.h>
+#include <string.h>
+#include "gatt_api.h"
+#include "gatt_int.h"
+#include "l2c_api.h"
+#include "btm_int.h"
+
+
+/*******************************************************************************
+**
+** Function GATT_SetTraceLevel
+**
+** Description This function sets the trace level. If called with
+** a value of 0xFF, it simply returns the current trace level.
+**
+** Input Parameters:
+** level: The level to set the GATT tracing to:
+** 0xff-returns the current setting.
+** 0-turns off tracing.
+** >= 1-Errors.
+** >= 2-Warnings.
+** >= 3-APIs.
+** >= 4-Events.
+** >= 5-Debug.
+**
+** Returns The new or current trace level
+**
+*******************************************************************************/
+UINT8 GATT_SetTraceLevel (UINT8 new_level)
+{
+ if (new_level != 0xFF)
+ gatt_cb.trace_level = new_level;
+
+ return(gatt_cb.trace_level);
+}
+
+/*****************************************************************************
+**
+** GATT SERVER API
+**
+******************************************************************************/
+/*******************************************************************************
+**
+** Function GATTS_AddHandleRange
+**
+** Description This function add the allocated handles range for the specifed
+** application UUID, service UUID and service instance
+**
+** Parameter p_hndl_range: pointer to allocated handles information
+**
+** Returns TRUE if handle range is added sucessfully; otherwise FALSE.
+**
+*******************************************************************************/
+
+BOOLEAN GATTS_AddHandleRange(tGATTS_HNDL_RANGE *p_hndl_range)
+{
+ tGATT_HDL_LIST_ELEM *p_buf;
+ BOOLEAN status= FALSE;
+
+ if ((p_buf = gatt_alloc_hdl_buffer()) != NULL)
+ {
+ p_buf->asgn_range = *p_hndl_range;
+ status = gatt_add_an_item_to_list(&gatt_cb.hdl_list_info, p_buf);
+ }
+ return status;
+}
+
+
+/*******************************************************************************
+**
+** Function GATTS_NVRegister
+**
+** Description Application manager calls this function to register for
+** NV save callback function. There can be one and only one
+** NV save callback function.
+**
+** Parameter p_cb_info : callback informaiton
+**
+** Returns TRUE if registered OK, else FALSE
+**
+*******************************************************************************/
+BOOLEAN GATTS_NVRegister (tGATT_APPL_INFO *p_cb_info)
+{
+ BOOLEAN status= FALSE;
+ if (p_cb_info)
+ {
+ gatt_cb.cb_info = *p_cb_info;
+ status = TRUE;
+ gatt_init_srv_chg();
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function GATTS_CreateService
+**
+** Description This function is called to reserve a block of handles for a service.
+**
+** *** It should be called only once per service instance ***
+**
+** Parameter gatt_if : application if
+** p_svc_uuid : service UUID
+** svc_inst : instance of the service inside the application
+** num_handles : number of handles needed by the service.
+** is_pri : is a primary service or not.
+**
+** Returns service handle if sucessful, otherwise 0.
+**
+*******************************************************************************/
+UINT16 GATTS_CreateService (tGATT_IF gatt_if, tBT_UUID *p_svc_uuid,
+ UINT16 svc_inst, UINT16 num_handles, BOOLEAN is_pri)
+{
+
+ tGATT_HDL_LIST_INFO *p_list_info= &gatt_cb.hdl_list_info;
+ tGATT_HDL_LIST_ELEM *p_list=NULL;
+ UINT16 s_hdl=0;
+ BOOLEAN save_hdl=FALSE;
+ tGATTS_PENDING_NEW_SRV_START *p_buf=NULL;
+ tGATT_REG *p_reg = gatt_get_regcb(gatt_if);
+ tBT_UUID *p_app_uuid128;
+
+
+ GATT_TRACE_API0 ("GATTS_CreateService" );
+
+ if (p_reg == NULL)
+ {
+ GATT_TRACE_ERROR1 ("Inavlid gatt_if=%d", gatt_if);
+ return(0);
+ }
+
+ p_app_uuid128 = &p_reg->app_uuid128;
+
+ if ((p_list = gatt_find_hdl_buffer_by_app_id(p_app_uuid128, p_svc_uuid, svc_inst)) != NULL)
+ {
+ s_hdl = p_list->asgn_range.s_handle;
+ GATT_TRACE_DEBUG0 ("Service already been created!!");
+ }
+ else
+ {
+ if ( (p_svc_uuid->len == LEN_UUID_16) && (p_svc_uuid->uu.uuid16 == UUID_SERVCLASS_GATT_SERVER))
+ {
+ s_hdl= gatt_cb.hdl_cfg.gatt_start_hdl;
+ }
+ else if ((p_svc_uuid->len == LEN_UUID_16) && (p_svc_uuid->uu.uuid16 == UUID_SERVCLASS_GAP_SERVER))
+ {
+ s_hdl= gatt_cb.hdl_cfg.gap_start_hdl;
+ }
+ else
+ {
+ p_list = p_list_info->p_first;
+
+ if (p_list)
+ {
+ s_hdl = p_list->asgn_range.e_handle + 1;
+ }
+
+ if (s_hdl < gatt_cb.hdl_cfg.app_start_hdl)
+ {
+
+ s_hdl= gatt_cb.hdl_cfg.app_start_hdl;
+ }
+ save_hdl = TRUE;
+ }
+
+ /* check for space */
+ if (num_handles > (0xFFFF - s_hdl + 1))
+ {
+ GATT_TRACE_ERROR2 ("GATTS_ReserveHandles: no handles, s_hdl: %u needed: %u", s_hdl, num_handles);
+ return(0);
+ }
+
+ if ( (p_list = gatt_alloc_hdl_buffer()) == NULL)
+ {
+ /* No free entry */
+ GATT_TRACE_ERROR0 ("GATTS_ReserveHandles: no free handle blocks");
+ return(0);
+ }
+
+ p_list->asgn_range.app_uuid128 = *p_app_uuid128;
+ p_list->asgn_range.svc_uuid = *p_svc_uuid;
+ p_list->asgn_range.svc_inst = svc_inst;
+ p_list->asgn_range.s_handle = s_hdl;
+ p_list->asgn_range.e_handle = s_hdl+num_handles-1;
+ p_list->asgn_range.is_primary = is_pri;
+
+ gatt_add_an_item_to_list(p_list_info, p_list);
+
+ if (save_hdl)
+ {
+ if (gatt_cb.cb_info.p_nv_save_callback)
+ (*gatt_cb.cb_info.p_nv_save_callback)(TRUE, &p_list->asgn_range);
+ /* add a pending new service change item to the list */
+ if ( (p_buf = gatt_add_pending_new_srv_start(&p_list->asgn_range)) == NULL)
+ {
+ /* No free entry */
+ GATT_TRACE_ERROR0 ("gatt_add_pending_new_srv_start: no free blocks");
+
+ if (p_list)
+ {
+ gatt_remove_an_item_from_list(p_list_info, p_list);
+ gatt_free_hdl_buffer(p_list);
+ }
+ return(0);
+ }
+
+ GATT_TRACE_DEBUG0 ("Add a new srv chg item");
+ }
+ }
+
+ if (!gatts_init_service_db(&p_list->svc_db, *p_svc_uuid, is_pri, s_hdl , num_handles))
+ {
+ GATT_TRACE_ERROR0 ("GATTS_ReserveHandles: service DB initialization failed");
+ if (p_list)
+ {
+ gatt_remove_an_item_from_list(p_list_info, p_list);
+ gatt_free_hdl_buffer(p_list);
+ }
+
+ if (p_buf)
+ GKI_freebuf (GKI_remove_from_queue (&gatt_cb.pending_new_srv_start_q, p_buf));
+ return(0);
+ }
+
+ GATT_TRACE_DEBUG6 ("GATTS_CreateService(success): handles needed:%u s_hdl=%u e_hdl=%u %s[%x] is_primary=%d",
+ num_handles, p_list->asgn_range.s_handle , p_list->asgn_range.e_handle,
+ ((p_list->asgn_range.svc_uuid.len == 2) ? "uuid16": "uuid128" ),
+ p_list->asgn_range.svc_uuid.uu.uuid16,
+ p_list->asgn_range.is_primary);
+
+ return(s_hdl);
+}
+
+/*******************************************************************************
+**
+** Function GATTS_AddIncludeService
+**
+** Description This function is called to add an included service.
+**
+** Parameter service_handle : To which service this included service is added to.
+** include_svc_handle : included service handle.
+**
+** Returns included service attribute handle. If 0, add included service
+** fail.
+**
+*******************************************************************************/
+UINT16 GATTS_AddIncludeService (UINT16 service_handle, UINT16 include_svc_handle)
+
+{
+ tGATT_HDL_LIST_ELEM *p_decl, *p_incl_decl;
+
+ if ((p_decl = gatt_find_hdl_buffer_by_handle(service_handle)) == NULL)
+ {
+ GATT_TRACE_DEBUG0("Service not created");
+ return 0;
+ }
+ if ((p_incl_decl = gatt_find_hdl_buffer_by_handle(include_svc_handle)) == NULL)
+ {
+ GATT_TRACE_DEBUG0("Included Service not created");
+ return 0;
+ }
+
+ return gatts_add_included_service(&p_decl->svc_db,
+ p_incl_decl->asgn_range.s_handle,
+ p_incl_decl->asgn_range.e_handle,
+ p_incl_decl->asgn_range.svc_uuid);
+}
+/*******************************************************************************
+**
+** Function GATTS_AddCharacteristic
+**
+** Description This function is called to add a characteristic into a service.
+** It will add a characteristic declaration and characteristic
+** value declaration into the service database identified by the
+** service handle.
+**
+** Parameter service_handle : To which service this included service is added to.
+** char_uuid : Characteristic UUID.
+** perm : Characteristic value declaration attribute permission.
+** property : Characteristic Properties
+**
+** Returns Characteristic value declaration attribute handle. 0 if failed.
+**
+*******************************************************************************/
+UINT16 GATTS_AddCharacteristic (UINT16 service_handle, tBT_UUID *p_char_uuid,
+ tGATT_PERM perm,tGATT_CHAR_PROP property)
+{
+ tGATT_HDL_LIST_ELEM *p_decl;
+
+ if ((p_decl = gatt_find_hdl_buffer_by_handle(service_handle)) == NULL)
+ {
+ GATT_TRACE_DEBUG0("Service not created");
+ return 0;
+ }
+ /* data validity checking */
+ if ( ((property & GATT_CHAR_PROP_BIT_AUTH) && !(perm & GATT_WRITE_SIGNED_PERM)) ||
+ ((perm & GATT_WRITE_SIGNED_PERM) && !(property & GATT_CHAR_PROP_BIT_AUTH)) )
+ {
+ GATT_TRACE_DEBUG2("Invalid configuration property=0x%x perm=0x%x ", property, perm);
+ return 0;
+ }
+
+ return gatts_add_characteristic(&p_decl->svc_db,
+ perm,
+ property,
+ p_char_uuid);
+}
+/*******************************************************************************
+**
+** Function GATTS_AddCharDescriptor
+**
+** Description This function is called to add a characteristic descriptor
+** into a service database. Add descriptor should follow add char
+** to which it belongs, and next add char should be done only
+** after all add descriptors for the previous char.
+**
+** Parameter service_handle : To which service this characteristic descriptor
+** is added to.
+** perm : Characteristic value declaration attribute
+** permission.
+** p_descr_uuid : Characteristic descriptor UUID
+**
+** Returns Characteristic descriptor attribute handle. 0 if add
+** characteristic descriptor failed.
+**
+*******************************************************************************/
+UINT16 GATTS_AddCharDescriptor (UINT16 service_handle,
+ tGATT_PERM perm,
+ tBT_UUID * p_descr_uuid)
+{
+ tGATT_HDL_LIST_ELEM *p_decl;
+
+ if ((p_decl = gatt_find_hdl_buffer_by_handle(service_handle)) == NULL)
+ {
+ GATT_TRACE_DEBUG0("Service not created");
+ return 0;
+ }
+ if (p_descr_uuid == NULL ||
+ (p_descr_uuid->len != LEN_UUID_128 && p_descr_uuid->len != LEN_UUID_16))
+ {
+ GATT_TRACE_DEBUG0("Illegal parameter");
+ return 0;
+ }
+
+ return gatts_add_char_descr(&p_decl->svc_db,
+ perm,
+ p_descr_uuid);
+
+}
+/*******************************************************************************
+**
+** Function GATTS_DeleteService
+**
+** Description This function is called to delete a service.
+**
+** Parameter gatt_if : application interface
+** p_svc_uuid : service UUID
+** svc_inst : instance of the service inside the application
+**
+** Returns TRUE if operation succeed, FALSE if handle block was not found.
+**
+*******************************************************************************/
+BOOLEAN GATTS_DeleteService (tGATT_IF gatt_if, tBT_UUID *p_svc_uuid, UINT16 svc_inst)
+{
+
+ tGATT_HDL_LIST_INFO *p_list_info= &gatt_cb.hdl_list_info;
+ tGATT_HDL_LIST_ELEM *p_list=NULL;
+ UINT8 i_sreg;
+ tGATTS_PENDING_NEW_SRV_START *p_buf;
+ tGATT_REG *p_reg = gatt_get_regcb(gatt_if);
+ tBT_UUID *p_app_uuid128;
+
+ GATT_TRACE_DEBUG0 ("GATTS_DeleteService");
+
+ if (p_reg == NULL)
+ {
+ GATT_TRACE_ERROR0 ("Applicaiton not foud");
+ return(FALSE);
+ }
+ p_app_uuid128 = &p_reg->app_uuid128;
+
+ if ((p_list = gatt_find_hdl_buffer_by_app_id(p_app_uuid128, p_svc_uuid, svc_inst)) == NULL)
+ {
+ GATT_TRACE_ERROR0 ("No Service found");
+ return(FALSE);
+ }
+
+ if ( (p_buf = gatt_sr_is_new_srv_chg(&p_list->asgn_range.app_uuid128,
+ &p_list->asgn_range.svc_uuid,
+ p_list->asgn_range.svc_inst)) != NULL)
+ {
+ GATT_TRACE_DEBUG0 ("Delete a new service changed item - the service has not yet started");
+ GKI_freebuf (GKI_remove_from_queue (&gatt_cb.pending_new_srv_start_q, p_buf));
+ }
+ else
+ {
+ gatt_proc_srv_chg();
+ }
+
+ if ((i_sreg = gatt_sr_find_i_rcb_by_app_id (p_app_uuid128,
+ p_svc_uuid,
+ svc_inst)) != GATT_MAX_SR_PROFILES)
+ {
+ GATTS_StopService(gatt_cb.sr_reg[i_sreg].s_hdl);
+ }
+
+ GATT_TRACE_DEBUG2 ("released handles s_hdl=%u e_hdl=%u",
+ p_list->asgn_range.s_handle , p_list->asgn_range.e_handle );
+
+ if ( (p_list->asgn_range.s_handle >= gatt_cb.hdl_cfg.app_start_hdl)
+ && gatt_cb.cb_info.p_nv_save_callback)
+ (*gatt_cb.cb_info.p_nv_save_callback)(FALSE, &p_list->asgn_range);
+
+ gatt_remove_an_item_from_list(p_list_info, p_list);
+ gatt_free_hdl_buffer(p_list);
+
+ return(TRUE);
+}
+
+/*******************************************************************************
+**
+** Function GATTS_StartService
+**
+** Description This function is called to start a service with GATT
+**
+** Parameter gatt_if : service handle.
+** p_cback : application service callback functions.
+** sup_transport : supported transport(s) for this primary service
+**
+** return GATT_SUCCESS if sucessfully started; otherwise error code.
+**
+*******************************************************************************/
+tGATT_STATUS GATTS_StartService (tGATT_IF gatt_if, UINT16 service_handle,
+ tGATT_TRANSPORT sup_transport)
+{
+ tGATT_SR_REG *p_sreg;
+ tGATT_HDL_LIST_ELEM *p_list=NULL;
+ UINT8 i_sreg;
+ tBT_UUID *p_uuid;
+ tGATT_REG *p_reg = gatt_get_regcb(gatt_if);
+
+ tGATTS_PENDING_NEW_SRV_START *p_buf;
+
+ GATT_TRACE_API0 ("GATTS_StartService");
+
+ if (p_reg == NULL)
+ {
+ /* Not found */
+ GATT_TRACE_ERROR0 ("Applicaiton not found ");
+ return GATT_NOT_FOUND;
+ }
+
+ if ((p_list = gatt_find_hdl_buffer_by_handle(service_handle)) == NULL)
+ {
+ /* Not found */
+ GATT_TRACE_ERROR0 ("no service found");
+ return GATT_NOT_FOUND;
+ }
+
+ if (gatt_sr_find_i_rcb_by_app_id (&p_list->asgn_range.app_uuid128,
+ &p_list->asgn_range.svc_uuid,
+ p_list->asgn_range.svc_inst) != GATT_MAX_SR_PROFILES)
+ {
+ GATT_TRACE_ERROR0 ("Duplicate Service start - Service already started");
+ return GATT_SERVICE_STARTED;
+ }
+
+ /*this is a new application servoce start */
+ if ((i_sreg = gatt_sr_alloc_rcb(p_list)) == GATT_MAX_SR_PROFILES)
+ {
+ GATT_TRACE_ERROR0 ("GATTS_StartService: no free server registration block");
+ return GATT_NO_RESOURCES;
+ }
+
+ p_sreg = &gatt_cb.sr_reg[i_sreg];
+ p_sreg->gatt_if = gatt_if;
+
+ switch (sup_transport)
+ {
+ case GATT_TRANSPORT_BR_EDR:
+ case GATT_TRANSPORT_LE_BR_EDR:
+ if (p_sreg->type == GATT_UUID_PRI_SERVICE)
+ {
+ p_uuid = gatts_get_service_uuid (p_sreg->p_db);
+
+ p_sreg->sdp_handle = gatt_add_sdp_record(p_uuid, p_sreg->s_hdl, p_sreg->e_hdl);
+ }
+ break;
+ default:
+ break;
+ }
+
+ gatts_update_srv_list_elem(i_sreg, p_sreg->s_hdl,
+ p_list->asgn_range.is_primary);
+
+ gatt_add_a_srv_to_list(&gatt_cb.srv_list_info, &gatt_cb.srv_list[i_sreg]);
+
+ GATT_TRACE_DEBUG1 ("allocated i_sreg=%d ",i_sreg);
+
+ GATT_TRACE_DEBUG5 ("s_hdl=%d e_hdl=%d type=0x%x svc_inst=%d sdp_hdl=0x%x",
+ p_sreg->s_hdl,p_sreg->e_hdl,
+ p_sreg->type, p_sreg->service_instance,
+ p_sreg->sdp_handle);
+
+
+ if ( (p_buf = gatt_sr_is_new_srv_chg(&p_list->asgn_range.app_uuid128,
+ &p_list->asgn_range.svc_uuid,
+ p_list->asgn_range.svc_inst)) != NULL)
+ {
+ gatt_proc_srv_chg();
+ /* remove the new service element after the srv changed processing is completed*/
+
+ GKI_freebuf (GKI_remove_from_queue (&gatt_cb.pending_new_srv_start_q, p_buf));
+ }
+ return GATT_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function GATTS_StopService
+**
+** Description This function is called to stop a service
+**
+** Parameter service_handle : this is the start handle of a service
+**
+** Returns None.
+**
+*******************************************************************************/
+void GATTS_StopService (UINT16 service_handle)
+{
+ UINT8 ii = gatt_sr_find_i_rcb_by_handle(service_handle);
+
+ GATT_TRACE_API1("GATTS_StopService %u", service_handle);
+
+ /* Index 0 is reserved for GATT, and is never stopped */
+ if ( (ii > 0) && (ii < GATT_MAX_SR_PROFILES) && (gatt_cb.sr_reg[ii].in_use) )
+ {
+ if (gatt_cb.sr_reg[ii].sdp_handle)
+ {
+ SDP_DeleteRecord(gatt_cb.sr_reg[ii].sdp_handle);
+ }
+ gatt_remove_a_srv_from_list(&gatt_cb.srv_list_info, &gatt_cb.srv_list[ii]);
+ gatt_cb.srv_list[ii].in_use = FALSE;
+ memset (&gatt_cb.sr_reg[ii], 0, sizeof(tGATT_SR_REG));
+ }
+ else
+ {
+ GATT_TRACE_ERROR1("GATTS_StopService service_handle: %u is not in use", service_handle);
+ }
+}
+/*******************************************************************************
+**
+** Function GATTs_HandleValueIndication
+**
+** Description This function sends a handle value indication to a client.
+**
+** Parameter conn_id: connection identifier.
+** attr_handle: Attribute handle of this handle value indication.
+** val_len: Length of the indicated attribute value.
+** p_val: Pointer to the indicated attribute value data.
+**
+** Returns GATT_SUCCESS if sucessfully sent or queued; otherwise error code.
+**
+*******************************************************************************/
+tGATT_STATUS GATTS_HandleValueIndication (UINT16 conn_id, UINT16 attr_handle, UINT16 val_len, UINT8 *p_val)
+{
+ tGATT_STATUS cmd_status = GATT_ILLEGAL_PARAMETER;
+
+ tGATT_VALUE indication;
+ BT_HDR *p_msg;
+ tGATT_VALUE *p_buf;
+ tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
+ UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id);
+ tGATT_REG *p_reg = gatt_get_regcb(gatt_if);
+ tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
+
+
+ GATT_TRACE_API0 ("GATTS_HandleValueIndication");
+ if ( (p_reg == NULL) || (p_tcb == NULL))
+ {
+ GATT_TRACE_ERROR1 ("GATTS_HandleValueIndication Unknown conn_id: %u ", conn_id);
+ return(tGATT_STATUS) GATT_INVALID_CONN_ID;
+ }
+ indication.conn_id = conn_id;
+ indication.handle = attr_handle;
+ indication.len = val_len;
+ memcpy (indication.value, p_val, val_len);
+ indication.auth_req = GATT_AUTH_REQ_NONE;
+
+ if (GATT_HANDLE_IS_VALID (attr_handle) )
+ {
+ if (GATT_HANDLE_IS_VALID(p_tcb->indicate_handle))
+ {
+ GATT_TRACE_DEBUG0 ("Add a pending indication");
+ if ((p_buf = gatt_add_pending_ind(p_tcb, &indication)) !=NULL)
+ {
+ cmd_status = GATT_SUCCESS;
+ }
+ else
+ {
+ cmd_status = GATT_NO_RESOURCES;
+ }
+ }
+ else
+ {
+
+ if ( (p_msg = attp_build_sr_msg (p_tcb, GATT_HANDLE_VALUE_IND, (tGATT_SR_MSG *)&indication)) != NULL)
+ {
+ cmd_status = attp_send_sr_msg (p_tcb, p_msg);
+
+ if (cmd_status == GATT_SUCCESS)
+ {
+ p_tcb->indicate_handle = indication.handle;
+ gatt_start_conf_timer(p_tcb);
+ }
+ }
+ }
+ }
+ return cmd_status;
+}
+
+/*******************************************************************************
+**
+** Function GATTS_HandleValueNotification
+**
+** Description This function sends a handle value notification to a client.
+**
+** Parameter conn_id: connection identifier.
+** attr_handle: Attribute handle of this handle value indication.
+** val_len: Length of the indicated attribute value.
+** p_val: Pointer to the indicated attribute value data.
+**
+** Returns GATT_SUCCESS if sucessfully sent; otherwise error code.
+**
+*******************************************************************************/
+tGATT_STATUS GATTS_HandleValueNotification (UINT16 conn_id, UINT16 attr_handle,
+ UINT16 val_len, UINT8 *p_val)
+{
+ tGATT_STATUS cmd_sent = GATT_ILLEGAL_PARAMETER;
+ BT_HDR *p_buf;
+ tGATT_VALUE notif;
+ tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
+ UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id);
+ tGATT_REG *p_reg = gatt_get_regcb(gatt_if);
+ tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
+
+ GATT_TRACE_API0 ("GATTS_HandleValueNotification");
+
+ if ( (p_reg == NULL) || (p_tcb == NULL))
+ {
+ GATT_TRACE_ERROR1 ("GATTS_HandleValueNotification Unknown conn_id: %u ", conn_id);
+ return(tGATT_STATUS) GATT_INVALID_CONN_ID;
+ }
+
+ if (GATT_HANDLE_IS_VALID (attr_handle))
+ {
+ notif.handle = attr_handle;
+ notif.len = val_len;
+ memcpy (notif.value, p_val, val_len);
+ notif.auth_req = GATT_AUTH_REQ_NONE;;
+
+ p_buf = attp_build_sr_msg (p_tcb, GATT_HANDLE_VALUE_NOTIF, (tGATT_SR_MSG *)&notif);
+ cmd_sent = attp_send_sr_msg (p_tcb, p_buf);
+ }
+ return cmd_sent;
+}
+
+/*******************************************************************************
+**
+** Function GATTS_SendRsp
+**
+** Description This function sends the server response to client.
+**
+** Parameter conn_id: connection identifier.
+** trans_id: transaction id
+** status: response status
+** p_msg: pointer to message parameters structure.
+**
+** Returns GATT_SUCCESS if sucessfully sent; otherwise error code.
+**
+*******************************************************************************/
+tGATT_STATUS GATTS_SendRsp (UINT16 conn_id, UINT32 trans_id,
+ tGATT_STATUS status, tGATTS_RSP *p_msg)
+{
+ tGATT_STATUS cmd_sent = GATT_ILLEGAL_PARAMETER;
+ tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
+ UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id);
+ tGATT_REG *p_reg = gatt_get_regcb(gatt_if);
+ tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
+
+ GATT_TRACE_API3 ("GATTS_SendRsp: conn_id: %u trans_id: %u Status: 0x%04x",
+ conn_id, trans_id, status);
+
+ if ( (p_reg == NULL) || (p_tcb == NULL))
+ {
+ GATT_TRACE_ERROR1 ("GATTS_SendRsp Unknown conn_id: %u ", conn_id);
+ return(tGATT_STATUS) GATT_INVALID_CONN_ID;
+ }
+
+ if (p_tcb->sr_cmd.trans_id != trans_id)
+ {
+ GATT_TRACE_ERROR2 ("GATTS_SendRsp conn_id: %u waiting for op_code = %02x",
+ conn_id, p_tcb->sr_cmd.op_code);
+
+ return(GATT_WRONG_STATE);
+ }
+ /* Process App response */
+ cmd_sent = gatt_sr_process_app_rsp (p_tcb, gatt_if, trans_id, p_tcb->sr_cmd.op_code, status, p_msg);
+
+ return cmd_sent;
+}
+
+/*******************************************************************************/
+/* GATT Profile Srvr Functions */
+/*******************************************************************************/
+
+/*******************************************************************************/
+/* */
+/* GATT CLIENT APIs */
+/* */
+/*******************************************************************************/
+
+
+/*******************************************************************************
+**
+** Function GATTC_ConfigureMTU
+**
+** Description This function is called to configure the ATT MTU size.
+**
+** Parameters conn_id: connection identifier.
+** mtu - attribute MTU size..
+**
+** Returns GATT_SUCCESS if command started successfully.
+**
+*******************************************************************************/
+tGATT_STATUS GATTC_ConfigureMTU (UINT16 conn_id, UINT16 mtu)
+{
+ UINT8 ret = GATT_NO_RESOURCES;
+ tGATT_IF gatt_if=GATT_GET_GATT_IF(conn_id);
+ UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id);
+ tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
+ tGATT_REG *p_reg = gatt_get_regcb(gatt_if);
+
+ tGATT_CLCB *p_clcb;
+
+ GATT_TRACE_API2 ("GATTC_ConfigureMTU conn_id=%d mtu=%d", conn_id, mtu );
+
+ // Validate that the link is BLE, not BR/EDR
+ // ????
+
+ if ( (p_tcb == NULL) || (p_reg==NULL) || (mtu < GATT_DEF_BLE_MTU_SIZE) || (mtu > GATT_MAX_MTU_SIZE))
+ {
+ return GATT_ILLEGAL_PARAMETER;
+ }
+
+ if (gatt_is_clcb_allocated(conn_id))
+ {
+ GATT_TRACE_ERROR1("GATTC_ConfigureMTU GATT_BUSY conn_id = %d", conn_id);
+ return GATT_BUSY;
+ }
+
+ if ((p_clcb = gatt_clcb_alloc(conn_id)) != NULL)
+ {
+ p_clcb->p_tcb->payload_size = mtu;
+ p_clcb->operation = GATTC_OPTYPE_CONFIG;
+
+ ret = attp_send_cl_msg (p_clcb->p_tcb, p_clcb->clcb_idx, GATT_REQ_MTU, (tGATT_CL_MSG *)&mtu);
+ }
+
+ return ret;
+}
+
+/*******************************************************************************
+**
+** Function GATTC_Discover
+**
+** Description This function is called to do a discovery procedure on ATT server.
+**
+** Parameters conn_id: connection identifier.
+** disc_type:discovery type.
+** p_param: parameters of discovery requirement.
+**
+** Returns GATT_SUCCESS if command received/sent successfully.
+**
+*******************************************************************************/
+tGATT_STATUS GATTC_Discover (UINT16 conn_id, tGATT_DISC_TYPE disc_type,
+ tGATT_DISC_PARAM *p_param)
+{
+ tGATT_STATUS status = GATT_SUCCESS;
+ tGATT_CLCB *p_clcb;
+ tGATT_IF gatt_if=GATT_GET_GATT_IF(conn_id);
+ UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id);
+ tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
+ tGATT_REG *p_reg = gatt_get_regcb(gatt_if);
+
+
+ GATT_TRACE_API2 ("GATTC_Discover conn_id=%d disc_type=%d",conn_id, disc_type);
+
+ if ( (p_tcb == NULL) || (p_reg==NULL) ||(p_param == NULL) ||
+ (disc_type >= GATT_DISC_MAX))
+ {
+ GATT_TRACE_ERROR2("GATTC_Discover Illegal param: disc_type %d conn_id = %d", disc_type, conn_id);
+ return GATT_ILLEGAL_PARAMETER;
+ }
+
+
+ if (gatt_is_clcb_allocated(conn_id))
+ {
+ GATT_TRACE_ERROR1("GATTC_Discover GATT_BUSY conn_id = %d", conn_id);
+ return GATT_BUSY;
+ }
+
+
+ if ((p_clcb = gatt_clcb_alloc(conn_id)) != NULL )
+ {
+ if (!GATT_HANDLE_IS_VALID(p_param->s_handle) ||
+ !GATT_HANDLE_IS_VALID(p_param->e_handle) ||
+ /* search by type does not have a valid UUID param */
+ (disc_type == GATT_DISC_SRVC_BY_UUID &&
+ p_param->service.len == 0))
+ {
+ return GATT_ILLEGAL_PARAMETER;
+ }
+
+ p_clcb->operation = GATTC_OPTYPE_DISCOVERY;
+ p_clcb->op_subtype = disc_type;
+ p_clcb->s_handle = p_param->s_handle;
+ p_clcb->e_handle = p_param->e_handle;
+ p_clcb->uuid = p_param->service;
+
+ gatt_act_discovery(p_clcb);
+ }
+ else
+ {
+ status = GATT_NO_RESOURCES;
+ }
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function GATTC_Read
+**
+** Description This function is called to read the value of an attribute from
+** the server.
+**
+** Parameters conn_id: connection identifier.
+** type - attribute read type.
+** p_read - read operation parameters.
+**
+** Returns GATT_SUCCESS if command started successfully.
+**
+*******************************************************************************/
+tGATT_STATUS GATTC_Read (UINT16 conn_id, tGATT_READ_TYPE type, tGATT_READ_PARAM *p_read)
+{
+ tGATT_STATUS status = GATT_SUCCESS;
+ tGATT_CLCB *p_clcb;
+ tGATT_READ_MULTI *p_read_multi;
+ tGATT_IF gatt_if=GATT_GET_GATT_IF(conn_id);
+ UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id);
+ tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
+ tGATT_REG *p_reg = gatt_get_regcb(gatt_if);
+
+
+ GATT_TRACE_API2 ("GATTC_Read conn_id=%d type=%d", conn_id, type);
+
+ if ( (p_tcb == NULL) || (p_reg==NULL) || (p_read == NULL) || ((type >= GATT_READ_MAX) || (type == 0)))
+ {
+ GATT_TRACE_ERROR2("GATT_Read Illegal param: conn_id %d, type 0%d,", conn_id, type);
+ return GATT_ILLEGAL_PARAMETER;
+ }
+
+ if (gatt_is_clcb_allocated(conn_id))
+ {
+ GATT_TRACE_ERROR1("GATTC_Read GATT_BUSY conn_id = %d", conn_id);
+ return GATT_BUSY;
+ }
+
+ if ( (p_clcb = gatt_clcb_alloc(conn_id)) != NULL )
+ {
+ p_clcb->operation = GATTC_OPTYPE_READ;
+ p_clcb->op_subtype = type;
+ p_clcb->auth_req = p_read->by_handle.auth_req;
+ p_clcb->counter = 0;
+
+ switch (type)
+ {
+ case GATT_READ_BY_TYPE:
+ case GATT_READ_CHAR_VALUE:
+ p_clcb->s_handle = p_read->service.s_handle;
+ p_clcb->e_handle = p_read->service.e_handle;
+ memcpy(&p_clcb->uuid, &p_read->service.uuid, sizeof(tBT_UUID));
+ break;
+ case GATT_READ_MULTIPLE:
+ p_clcb->s_handle = 0;
+ /* copy multiple handles in CB */
+ p_read_multi = (tGATT_READ_MULTI *)GKI_getbuf(sizeof(tGATT_READ_MULTI));
+ p_clcb->p_attr_buf = (UINT8*)p_read_multi;
+ memcpy (p_read_multi, &p_read->read_multiple, sizeof(tGATT_READ_MULTI));
+ case GATT_READ_BY_HANDLE:
+ case GATT_READ_PARTIAL:
+ memset(&p_clcb->uuid, 0, sizeof(tBT_UUID));
+ p_clcb->s_handle = p_read->by_handle.handle;
+
+ if (type == GATT_READ_PARTIAL)
+ {
+ p_clcb->counter = p_read->partial.offset;
+ }
+
+ break;
+ default:
+ break;
+ }
+ /* start security check */
+ if (gatt_security_check_start(p_clcb) == FALSE)
+ {
+ status = GATT_NO_RESOURCES;
+ gatt_clcb_dealloc(p_clcb);
+ }
+ }
+ else
+ {
+ status = GATT_NO_RESOURCES;
+ }
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function GATTC_Write
+**
+** Description This function is called to write the value of an attribute to
+** the server.
+**
+** Parameters conn_id: connection identifier.
+** type - attribute write type.
+** p_write - write operation parameters.
+**
+** Returns GATT_SUCCESS if command started successfully.
+**
+*******************************************************************************/
+tGATT_STATUS GATTC_Write (UINT16 conn_id, tGATT_WRITE_TYPE type, tGATT_VALUE *p_write)
+{
+ tGATT_STATUS status = GATT_SUCCESS;
+ tGATT_CLCB *p_clcb;
+ tGATT_VALUE *p;
+ tGATT_IF gatt_if=GATT_GET_GATT_IF(conn_id);
+ UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id);
+ tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
+ tGATT_REG *p_reg = gatt_get_regcb(gatt_if);
+
+ if ( (p_tcb == NULL) || (p_reg==NULL) || (p_write == NULL) ||
+ ((type != GATT_WRITE) && (type != GATT_WRITE_PREPARE) && (type != GATT_WRITE_NO_RSP)) )
+ {
+ GATT_TRACE_ERROR2("GATT_Write Illegal param: conn_id %d, type 0%d,", conn_id, type);
+ return GATT_ILLEGAL_PARAMETER;
+ }
+
+ if (gatt_is_clcb_allocated(conn_id))
+ {
+ GATT_TRACE_ERROR1("GATTC_Write GATT_BUSY conn_id = %d", conn_id);
+ return GATT_BUSY;
+ }
+
+ if ((p_clcb = gatt_clcb_alloc(conn_id)) != NULL )
+ {
+ p_clcb->operation = GATTC_OPTYPE_WRITE;
+ p_clcb->op_subtype = type;
+ p_clcb->auth_req = p_write->auth_req;
+
+ if (( p_clcb->p_attr_buf = (UINT8 *)GKI_getbuf((UINT16)sizeof(tGATT_VALUE))) != NULL)
+ {
+ memcpy(p_clcb->p_attr_buf, (void *)p_write, sizeof(tGATT_VALUE));
+
+ p = (tGATT_VALUE *)p_clcb->p_attr_buf;
+ if (type == GATT_WRITE_PREPARE)
+ {
+ p_clcb->start_offset = p_write->offset;
+ p->offset = 0;
+ }
+
+ if (gatt_security_check_start(p_clcb) == FALSE)
+ {
+ status = GATT_NO_RESOURCES;
+ }
+ }
+ else
+ {
+ status = GATT_NO_RESOURCES;
+ }
+
+ if (status == GATT_NO_RESOURCES)
+ gatt_clcb_dealloc(p_clcb);
+ }
+ else
+ {
+ status = GATT_NO_RESOURCES;
+ }
+ return status;
+}
+
+
+/*******************************************************************************
+**
+** Function GATTC_ExecuteWrite
+**
+** Description This function is called to send an Execute write request to
+** the server.
+**
+** Parameters conn_id: connection identifier.
+** is_execute - to execute or cancel the prepare write requet(s)
+**
+** Returns GATT_SUCCESS if command started successfully.
+**
+*******************************************************************************/
+tGATT_STATUS GATTC_ExecuteWrite (UINT16 conn_id, BOOLEAN is_execute)
+{
+ tGATT_STATUS status = GATT_SUCCESS;
+ tGATT_CLCB *p_clcb;
+ tGATT_EXEC_FLAG flag;
+ tGATT_IF gatt_if=GATT_GET_GATT_IF(conn_id);
+ UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id);
+ tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
+ tGATT_REG *p_reg = gatt_get_regcb(gatt_if);
+
+ GATT_TRACE_API2 ("GATTC_ExecuteWrite conn_id=%d is_execute=%d", conn_id, is_execute);
+
+ if ( (p_tcb == NULL) || (p_reg==NULL) )
+ {
+ GATT_TRACE_ERROR1("GATTC_ExecuteWrite Illegal param: conn_id %d", conn_id);
+ return GATT_ILLEGAL_PARAMETER;
+ }
+
+ if (gatt_is_clcb_allocated(conn_id))
+ {
+ GATT_TRACE_ERROR1("GATTC_Write GATT_BUSY conn_id = %d", conn_id);
+ return GATT_BUSY;
+ }
+
+ if ((p_clcb = gatt_clcb_alloc(conn_id)) != NULL)
+ {
+ p_clcb->operation = GATTC_OPTYPE_EXE_WRITE;
+ flag = is_execute ? GATT_PREP_WRITE_EXEC : GATT_PREP_WRITE_CANCEL;
+ gatt_send_queue_write_cancel (p_clcb->p_tcb, p_clcb, flag);
+ }
+ else
+ {
+ GATT_TRACE_ERROR1("Unable to allocate client CB for conn_id %d ", conn_id);
+ status = GATT_NO_RESOURCES;
+ }
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function GATTC_SendHandleValueConfirm
+**
+** Description This function is called to send a handle value confirmation
+** as response to a handle value notification from server.
+**
+** Parameters conn_id: connection identifier.
+** handle: the handle of the attribute confirmation.
+**
+** Returns GATT_SUCCESS if command started successfully.
+**
+*******************************************************************************/
+tGATT_STATUS GATTC_SendHandleValueConfirm (UINT16 conn_id, UINT16 handle)
+{
+ tGATT_STATUS ret = GATT_ILLEGAL_PARAMETER;
+ tGATT_TCB *p_tcb=gatt_get_tcb_by_idx(GATT_GET_TCB_IDX(conn_id));
+
+ GATT_TRACE_API2 ("GATTC_SendHandleValueConfirm conn_id=%d handle=0x%x", conn_id, handle);
+
+ if (p_tcb)
+ {
+ if (p_tcb->ind_count > 0 )
+ {
+ btu_stop_timer (&p_tcb->ind_ack_timer_ent);
+
+ GATT_TRACE_DEBUG1 ("notif_count=%d ", p_tcb->ind_count);
+ /* send confirmation now */
+ ret = attp_send_cl_msg(p_tcb, 0, GATT_HANDLE_VALUE_CONF, (tGATT_CL_MSG *)&handle);
+
+ p_tcb->ind_count = 0;
+
+ }
+ else
+ {
+ GATT_TRACE_DEBUG1 ("GATTC_SendHandleValueConfirm - conn_id: %u - ignored not waiting for indicaiton ack", conn_id);
+ ret = GATT_SUCCESS;
+ }
+ }
+ else
+ {
+ GATT_TRACE_ERROR1 ("GATTC_SendHandleValueConfirm - Unknown conn_id: %u", conn_id);
+ }
+ return ret;
+}
+
+
+/*******************************************************************************/
+/* */
+/* GATT APIs */
+/* */
+/*******************************************************************************/
+/*******************************************************************************
+**
+** Function GATT_SetIdleTimeout
+**
+** Description This function (common to both client and server) sets the idle
+** timeout for a tansport connection
+**
+** Parameter bd_addr: target device bd address.
+** idle_tout: timeout value in seconds.
+**
+** Returns void
+**
+*******************************************************************************/
+void GATT_SetIdleTimeout (BD_ADDR bd_addr, UINT16 idle_tout)
+{
+ tGATT_TCB *p_tcb;
+ BOOLEAN status = FALSE;
+
+ if ((p_tcb = gatt_find_tcb_by_addr (bd_addr)) != NULL)
+ {
+ if (p_tcb->att_lcid == L2CAP_ATT_CID)
+ {
+ status = L2CA_SetFixedChannelTout (bd_addr, L2CAP_ATT_CID, idle_tout);
+ }
+ else
+ {
+ status = L2CA_SetIdleTimeout (p_tcb->att_lcid, idle_tout, FALSE);
+ }
+ }
+
+ GATT_TRACE_API2 ("GATT_SetIdleTimeout idle_tout=%d status=%d(1-OK 0-not performed)",
+ idle_tout, status);
+}
+
+
+/*******************************************************************************
+**
+** Function GATT_Register
+**
+** Description This function is called to register an application
+** with GATT
+**
+** Parameter p_app_uuid128: Application UUID
+** p_cb_info: callback functions.
+**
+** Returns 0 for error, otherwise the index of the client registered with GATT
+**
+*******************************************************************************/
+tGATT_IF GATT_Register (tBT_UUID *p_app_uuid128, tGATT_CBACK *p_cb_info)
+{
+ tGATT_REG *p_reg;
+ UINT8 i_gatt_if=0;
+ tGATT_IF gatt_if=0;
+
+ GATT_TRACE_API0 ("GATT_Register");
+ gatt_dbg_display_uuid(*p_app_uuid128);
+
+ for (i_gatt_if = 0, p_reg = gatt_cb.cl_rcb; i_gatt_if < GATT_MAX_APPS; i_gatt_if++, p_reg++)
+ {
+ if (p_reg->in_use && !memcmp(p_app_uuid128->uu.uuid128, p_reg->app_uuid128.uu.uuid128, LEN_UUID_128))
+ {
+ GATT_TRACE_ERROR0("application already registered.");
+ return 0;
+ }
+ }
+
+ for (i_gatt_if = 0, p_reg = gatt_cb.cl_rcb; i_gatt_if < GATT_MAX_APPS; i_gatt_if++, p_reg++)
+ {
+ if (!p_reg->in_use)
+ {
+ memset(p_reg, 0 , sizeof(tGATT_REG));
+ i_gatt_if++; /* one based number */
+ p_reg->app_uuid128 = *p_app_uuid128;
+ gatt_if =
+ p_reg->gatt_if = (tGATT_IF)i_gatt_if;
+ p_reg->app_cb = *p_cb_info;
+ p_reg->in_use = TRUE;
+
+ break;
+ }
+ }
+ GATT_TRACE_API1 ("allocated gatt_if=%d", gatt_if);
+ return gatt_if;
+}
+
+
+/*******************************************************************************
+**
+** Function GATT_Deregister
+**
+** Description This function deregistered the application from GATT.
+**
+** Parameters gatt_if: applicaiton interface.
+**
+** Returns None.
+**
+*******************************************************************************/
+void GATT_Deregister (tGATT_IF gatt_if)
+{
+ tGATT_REG *p_reg = gatt_get_regcb(gatt_if);
+ tGATT_TCB *p_tcb;
+ tGATT_CLCB *p_clcb;
+ UINT8 i, ii, j;
+ tGATT_SR_REG *p_sreg;
+
+ GATT_TRACE_API1 ("GATT_Deregister gatt_if=%d", gatt_if);
+ /* Index 0 is GAP and is never deregistered */
+ if ( (gatt_if == 0) || (p_reg == NULL) )
+ {
+ GATT_TRACE_ERROR1 ("GATT_Deregister with invalid gatt_if: %u", gatt_if);
+ return;
+ }
+
+ /* stop all services */
+ /* todo an applcaiton can not be deregistered if its services is also used by other application
+ deregisteration need to bed performed in an orderly fashion
+ no check for now */
+
+ for (ii = 0, p_sreg = gatt_cb.sr_reg; ii < GATT_MAX_SR_PROFILES; ii++, p_sreg++)
+ {
+ if (p_sreg->in_use && (p_sreg->gatt_if == gatt_if))
+ {
+ GATTS_StopService(p_sreg->s_hdl);
+ }
+ }
+
+ /* free all services db buffers if owned by this application */
+ gatt_free_srvc_db_buffer_app_id(&p_reg->app_uuid128);
+
+ /* When an application deregisters, check remove the link associated with the app */
+
+ for (i=0, p_tcb = gatt_cb.tcb; i < GATT_MAX_PHY_CHANNEL; i++, p_tcb++)
+ {
+ if (p_tcb->in_use)
+ {
+ if (gatt_get_ch_state(p_tcb) != GATT_CH_CLOSE)
+ {
+ gatt_update_app_use_link_flag(gatt_if, p_tcb, FALSE, FALSE);
+ if (!gatt_num_apps_hold_link(p_tcb))
+ {
+ /* this will disconnect the link or cancel the pending connect request at lower layer*/
+ gatt_disconnect(p_tcb->peer_bda);
+ }
+ }
+
+ for (j = 0, p_clcb= &gatt_cb.clcb[j]; j < GATT_CL_MAX_LCB; j++, p_clcb++)
+ {
+ if (p_clcb->in_use &&
+ (p_clcb->p_reg->gatt_if == gatt_if) &&
+ (p_clcb->p_tcb->tcb_idx == p_tcb->tcb_idx))
+ {
+ gatt_clcb_dealloc (p_clcb);
+ break;
+ }
+ }
+ }
+ }
+
+ gatt_deregister_bgdev_list(gatt_if);
+ memset (p_reg, 0, sizeof(tGATT_REG));
+}
+
+
+/*******************************************************************************
+**
+** Function GATT_StartIf
+**
+** Description This function is called after registration to start receiving
+** callbacks for registered interface. Function may call back
+** with connection status and queued notifications
+**
+** Parameter gatt_if: applicaiton interface.
+**
+** Returns 0 for error, otherwise the index of the client registered with GATT
+**
+*******************************************************************************/
+void GATT_StartIf (tGATT_IF gatt_if)
+{
+ tGATT_REG *p_reg;
+ tGATT_TCB *p_tcb;
+ //tGATT_CLCB *p_clcb;
+ BD_ADDR bda;
+ UINT8 start_idx, found_idx;
+ UINT16 conn_id;
+
+ GATT_TRACE_API1 ("GATT_StartIf gatt_if=%d", gatt_if);
+ if ((p_reg = gatt_get_regcb(gatt_if)) != NULL)
+ {
+ p_reg = &gatt_cb.cl_rcb[gatt_if - 1];
+ start_idx = 0;
+ while (gatt_find_the_connected_bda(start_idx, bda, &found_idx))
+ {
+ p_tcb = gatt_find_tcb_by_addr(bda);
+ if (p_reg->app_cb.p_conn_cb)
+ {
+ conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, gatt_if);
+ (*p_reg->app_cb.p_conn_cb)(gatt_if, bda, conn_id, TRUE, 0);
+ }
+ start_idx = ++found_idx;
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function GATT_Connect
+**
+** Description This function initiate a connecttion to a ATT server.
+**
+** Parameters gatt_if: applicaiton interface
+** bd_addr: peer device address.
+** is_direct: is a direct conenection or a background auto connection
+**
+** Returns TRUE if connection started; FALSE if connection start failure.
+**
+*******************************************************************************/
+BOOLEAN GATT_Connect (tGATT_IF gatt_if, BD_ADDR bd_addr, BOOLEAN is_direct){
+ tGATT_REG *p_reg;
+ BOOLEAN status;
+
+ GATT_TRACE_API1 ("GATT_Connect gatt_if=%d", gatt_if);
+
+ /* Make sure app is registered */
+ if ((p_reg = gatt_get_regcb(gatt_if)) == NULL)
+ {
+ GATT_TRACE_ERROR1("GATT_Connect - gatt_if =%d is not registered", gatt_if);
+ return(FALSE);
+ }
+
+ if (is_direct)
+ status = gatt_act_connect (p_reg, bd_addr);
+ else
+ status = gatt_update_auto_connect_dev(gatt_if,TRUE, bd_addr);
+
+ return status;
+
+}
+
+/*******************************************************************************
+**
+** Function GATT_CancelConnect
+**
+** Description This function initiate a connecttion to a ATT server.
+**
+** Parameters gatt_if: client interface. If 0 used as unconditionally disconnect,
+** typically used for direct connection cancellation.
+** bd_addr: peer device address.
+**
+** Returns TRUE if connection started; FALSE if connection start failure.
+**
+*******************************************************************************/
+BOOLEAN GATT_CancelConnect (tGATT_IF gatt_if, BD_ADDR bd_addr, BOOLEAN is_direct){
+ tGATT_REG *p_reg;
+ tGATT_TCB *p_tcb;
+ BOOLEAN status = TRUE;
+ tGATT_IF temp_gatt_if;
+ UINT8 start_idx, found_idx;
+
+ GATT_TRACE_API1 ("GATT_CancelConnect gatt_if=%d", gatt_if);
+
+ if ((gatt_if != 0) && ((p_reg = gatt_get_regcb(gatt_if)) == NULL))
+ {
+ GATT_TRACE_ERROR1("GATT_CancelConnect - gatt_if =%d is not registered", gatt_if);
+ return(FALSE);
+ }
+
+ if (is_direct)
+ {
+ if (!gatt_if)
+ {
+ GATT_TRACE_DEBUG0("GATT_CancelConnect - unconditional");
+ start_idx = 0;
+ p_tcb = gatt_find_tcb_by_addr(bd_addr);
+ if (p_tcb && gatt_num_apps_hold_link(p_tcb))
+ {
+ while (status && gatt_find_app_hold_link(p_tcb, start_idx, &found_idx, &temp_gatt_if))
+ {
+ status = gatt_cancel_open(temp_gatt_if, bd_addr);
+ start_idx = ++found_idx;
+ }
+ }
+ else
+ {
+ GATT_TRACE_ERROR0("GATT_CancelConnect - no app found");
+ status = FALSE;
+ }
+ }
+ else
+ {
+ status = gatt_cancel_open(gatt_if, bd_addr);
+ }
+ }
+ else
+ {
+ if (!gatt_if)
+ {
+ if (gatt_get_num_apps_for_bg_dev(bd_addr))
+ {
+ while (gatt_find_app_for_bg_dev(bd_addr, &temp_gatt_if))
+ gatt_remove_bg_dev_for_app(temp_gatt_if, bd_addr);
+ }
+ else
+ {
+ GATT_TRACE_ERROR0("GATT_CancelConnect -no app associated with the bg device for unconditional removal");
+ status = FALSE;
+ }
+ }
+ else
+ {
+ status = gatt_remove_bg_dev_for_app(gatt_if, bd_addr);
+ }
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function GATT_Disconnect
+**
+** Description This function disconnect a logic channel.
+**
+** Parameters conn_id: connection identifier.
+**
+** Returns GATT_SUCCESS if disconnected.
+**
+*******************************************************************************/
+tGATT_STATUS GATT_Disconnect (UINT16 conn_id)
+{
+ tGATT_STATUS ret = GATT_ILLEGAL_PARAMETER;
+ tGATT_TCB *p_tcb=NULL;
+ tGATT_IF gatt_if=GATT_GET_GATT_IF(conn_id);
+ UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id);
+
+ GATT_TRACE_API1 ("GATT_Disconnect conn_id=%d ", conn_id);
+
+ p_tcb = gatt_get_tcb_by_idx(tcb_idx);
+
+ if (p_tcb)
+ {
+ gatt_update_app_use_link_flag(gatt_if, p_tcb, FALSE, FALSE);
+ if (!gatt_num_apps_hold_link(p_tcb))
+ {
+ gatt_disconnect(p_tcb->peer_bda);
+ }
+ ret = GATT_SUCCESS;
+ }
+ return ret;
+}
+
+
+/*******************************************************************************
+**
+** Function GATT_GetConnectionInfor
+**
+** Description This function use conn_id to find its associated BD address and applciation
+** interface
+**
+** Parameters conn_id: connection id (input)
+** p_gatt_if: applicaiton interface (output)
+** bd_addr: peer device address. (output)
+**
+** Returns TRUE the ligical link information is found for conn_id
+**
+*******************************************************************************/
+BOOLEAN GATT_GetConnectionInfor(UINT16 conn_id, tGATT_IF *p_gatt_if, BD_ADDR bd_addr)
+{
+
+ tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
+ tGATT_REG *p_reg = gatt_get_regcb(gatt_if);
+ UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id);
+ tGATT_TCB *p_tcb= gatt_get_tcb_by_idx(tcb_idx);
+ BOOLEAN status=FALSE;
+
+ GATT_TRACE_API1 ("GATT_GetConnectionInfor conn_id=%d", conn_id);
+
+ if (p_tcb && p_reg )
+ {
+ memcpy(bd_addr, p_tcb->peer_bda, BD_ADDR_LEN);
+ *p_gatt_if = gatt_if;
+ status = TRUE;
+ }
+ return status;
+}
+
+
+/*******************************************************************************
+**
+** Function GATT_GetConnIdIfConnected
+**
+** Description This function find the conn_id if the logical link for BD address
+** and applciation interface is connected
+**
+** Parameters gatt_if: applicaiton interface (input)
+** bd_addr: peer device address. (input)
+** p_conn_id: connection id (output)
+**
+** Returns TRUE the ligical link is connected
+**
+*******************************************************************************/
+BOOLEAN GATT_GetConnIdIfConnected(tGATT_IF gatt_if, BD_ADDR bd_addr, UINT16 *p_conn_id)
+{
+ tGATT_REG *p_reg = gatt_get_regcb(gatt_if);
+ tGATT_TCB *p_tcb= gatt_find_tcb_by_addr(bd_addr);
+ BOOLEAN status=FALSE;
+
+ if (p_reg && p_tcb && (gatt_get_ch_state(p_tcb) == GATT_CH_OPEN) )
+ {
+ *p_conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, gatt_if);
+ status = TRUE;
+ }
+
+ GATT_TRACE_API1 ("GATT_GetConnIdIfConnected status=%d", status);
+ return status;
+}
+
+#endif
+
+
diff --git a/stack/gatt/gatt_attr.c b/stack/gatt/gatt_attr.c
new file mode 100644
index 0000000..d8b417f
--- /dev/null
+++ b/stack/gatt/gatt_attr.c
@@ -0,0 +1,264 @@
+/*****************************************************************************
+**
+** Name: gatt_attr.c
+**
+** Description: this file contains the main GATT server attributes access
+** request handling functions.
+**
+** Copyright (c) 2008-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+
+#include "bt_target.h"
+
+#include "gatt_api.h"
+#include "gatt_int.h"
+
+#if BLE_INCLUDED == TRUE
+
+#define GATTP_MAX_NUM_INC_SVR 0
+#define GATTP_MAX_CHAR_NUM 2
+#define GATTP_MAX_ATTR_NUM (GATTP_MAX_CHAR_NUM * 2 + GATTP_MAX_NUM_INC_SVR + 1)
+#define GATTP_MAX_CHAR_VALUE_SIZE 50
+
+#ifndef GATTP_ATTR_DB_SIZE
+#define GATTP_ATTR_DB_SIZE GATT_DB_MEM_SIZE(GATTP_MAX_NUM_INC_SVR, GATTP_MAX_CHAR_NUM, GATTP_MAX_CHAR_VALUE_SIZE)
+#endif
+
+static void gatt_profile_request_cback (UINT16 conn_id, UINT32 trans_id, UINT8 op_code, tGATTS_DATA *p_data);
+static void gatt_profile_connect_cback (tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id, BOOLEAN connected, tGATT_DISCONN_REASON reason);
+
+static tGATT_CBACK gatt_profile_cback =
+{
+ gatt_profile_connect_cback,
+ NULL,
+ NULL,
+ NULL,
+ gatt_profile_request_cback
+} ;
+
+/*******************************************************************************
+**
+** Function gatt_profile_find_conn_id_by_bd_addr
+**
+** Description The function searches all LCB with macthing bd address
+**
+** Returns total number of clcb found.
+**
+*******************************************************************************/
+UINT16 gatt_profile_find_conn_id_by_bd_addr(BD_ADDR bda)
+{
+ UINT8 i_clcb;
+ tGATT_PROFILE_CLCB *p_clcb = NULL;
+
+ for (i_clcb = 0, p_clcb= gatt_cb.profile_clcb; i_clcb < GATT_MAX_APPS; i_clcb++, p_clcb++)
+ {
+ if (p_clcb->in_use && p_clcb->connected && !memcmp(p_clcb->bda, bda, BD_ADDR_LEN))
+ {
+ return p_clcb->conn_id;
+ }
+ }
+
+ return GATT_INVALID_CONN_ID;
+}
+
+/*******************************************************************************
+**
+** Function gatt_profile_find_clcb_by_bd_addr
+**
+** Description The function searches all LCBs with macthing bd address.
+**
+** Returns Pointer to the found link conenction control block.
+**
+*******************************************************************************/
+tGATT_PROFILE_CLCB *gatt_profile_find_clcb_by_bd_addr(BD_ADDR bda)
+{
+ UINT8 i_clcb;
+ tGATT_PROFILE_CLCB *p_clcb = NULL;
+
+ for (i_clcb = 0, p_clcb= gatt_cb.profile_clcb; i_clcb < GATT_MAX_APPS; i_clcb++, p_clcb++)
+ {
+ if (p_clcb->in_use && p_clcb->connected && !memcmp(p_clcb->bda, bda, BD_ADDR_LEN))
+ {
+ return p_clcb;
+ }
+ }
+
+ return p_clcb;
+}
+
+/*******************************************************************************
+**
+** Function gatt_profile_clcb_alloc
+**
+** Description The function allocates a GATT profile connection link control block
+**
+** Returns NULL if not found. Otherwise pointer to the connection link block.
+**
+*******************************************************************************/
+tGATT_PROFILE_CLCB *gatt_profile_clcb_alloc (UINT16 conn_id, BD_ADDR bda)
+{
+ UINT8 i_clcb = 0;
+ tGATT_PROFILE_CLCB *p_clcb = NULL;
+
+ for (i_clcb = 0, p_clcb= gatt_cb.profile_clcb; i_clcb < GATT_MAX_APPS; i_clcb++, p_clcb++)
+ {
+ if (!p_clcb->in_use)
+ {
+ p_clcb->in_use = TRUE;
+ p_clcb->conn_id = conn_id;
+ p_clcb->connected = TRUE;
+ memcpy (p_clcb->bda, bda, BD_ADDR_LEN);
+ break;
+ }
+ }
+ return p_clcb;
+}
+/*******************************************************************************
+**
+** Function gatt_profile_clcb_dealloc
+**
+** Description The function deallocates a GATT profile connection link control block
+**
+** Returns NTrue the deallocation is successful
+**
+*******************************************************************************/
+BOOLEAN gatt_profile_clcb_dealloc (UINT16 conn_id)
+{
+ UINT8 i_clcb = 0;
+ tGATT_PROFILE_CLCB *p_clcb = NULL;
+
+ for (i_clcb = 0, p_clcb= gatt_cb.profile_clcb; i_clcb < GATT_MAX_APPS; i_clcb++, p_clcb++)
+ {
+ if (p_clcb->in_use && p_clcb->connected && (p_clcb->conn_id == conn_id))
+ {
+ memset(p_clcb, 0, sizeof(tGATT_PROFILE_CLCB));
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+/*******************************************************************************
+**
+** Function gatt_profile_request_cback
+**
+** Description GATT profile attribute access request callback.
+**
+** Returns void.
+**
+*******************************************************************************/
+static void gatt_profile_request_cback (UINT16 conn_id, UINT32 trans_id, tGATTS_REQ_TYPE type,
+ tGATTS_DATA *p_data)
+{
+ UINT8 status = GATT_INVALID_PDU;
+ tGATTS_RSP rsp_msg ;
+ BOOLEAN ignore = FALSE;
+
+ memset(&rsp_msg, 0, sizeof(tGATTS_RSP));
+
+ switch (type)
+ {
+ case GATTS_REQ_TYPE_READ:
+ status = GATT_READ_NOT_PERMIT;
+ break;
+
+ case GATTS_REQ_TYPE_WRITE:
+ status = GATT_WRITE_NOT_PERMIT;
+ break;
+
+ case GATTS_REQ_TYPE_WRITE_EXEC:
+ //case GATT_CMD_WRITE:
+ ignore = TRUE;
+ GATT_TRACE_EVENT0("Ignore GATT_REQ_EXEC_WRITE/WRITE_CMD" );
+ break;
+
+ case GATTS_REQ_TYPE_MTU:
+ GATT_TRACE_EVENT1("Get MTU exchange new mtu size: %d", p_data->mtu);
+ ignore = TRUE;
+ break;
+
+ default:
+ GATT_TRACE_EVENT1("Unknown/unexpected LE GAP ATT request: 0x%02x", type);
+ break;
+ }
+
+ if (!ignore)
+ GATTS_SendRsp (conn_id, trans_id, status, &rsp_msg);
+
+}
+
+/*******************************************************************************
+**
+** Function gatt_profile_connect_cback
+**
+** Description Gatt profile connection callback.
+**
+** Returns void
+**
+*******************************************************************************/
+static void gatt_profile_connect_cback (tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id,
+ BOOLEAN connected, tGATT_DISCONN_REASON reason)
+{
+ GATT_TRACE_EVENT5 ("gatt_profile_connect_cback: from %08x%04x connected:%d conn_id=%d reason = 0x%04x",
+ (bda[0]<<24)+(bda[1]<<16)+(bda[2]<<8)+bda[3],
+ (bda[4]<<8)+bda[5], connected, conn_id, reason);
+
+ if (connected)
+ {
+ if (gatt_profile_clcb_alloc(conn_id, bda) == NULL)
+ {
+ GATT_TRACE_ERROR0 ("gatt_profile_connect_cback: no_resource");
+ return;
+ }
+ }
+ else
+ {
+ gatt_profile_clcb_dealloc(conn_id);
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function gatt_profile_db_init
+**
+** Description Initializa the GATT profile attribute database.
+**
+*******************************************************************************/
+void gatt_profile_db_init (void)
+{
+ tBT_UUID app_uuid = {LEN_UUID_128, {0}};
+ tBT_UUID uuid = {LEN_UUID_16, {UUID_SERVCLASS_GATT_SERVER}};
+ UINT16 service_handle = 0;
+ tGATT_STATUS status;
+
+ /* Fill our internal UUID with a fixed pattern 0x81 */
+ memset (&app_uuid.uu.uuid128, 0x81, LEN_UUID_128);
+
+
+ /* Create a GATT profile service */
+ gatt_cb.gatt_if = GATT_Register(&app_uuid, &gatt_profile_cback);
+ GATT_StartIf(gatt_cb.gatt_if);
+
+ service_handle = GATTS_CreateService (gatt_cb.gatt_if , &uuid, 0, GATTP_MAX_ATTR_NUM, TRUE);
+ /* add Service Changed characteristic
+ */
+ uuid.uu.uuid16 = gatt_cb.gattp_attr.uuid = GATT_UUID_GATT_SRV_CHGD;
+ gatt_cb.gattp_attr.service_change = 0;
+ gatt_cb.gattp_attr.handle =
+ gatt_cb.handle_of_h_r = GATTS_AddCharacteristic(service_handle, &uuid, 0, GATT_CHAR_PROP_BIT_INDICATE);
+
+ GATT_TRACE_DEBUG1 ("gatt_profile_db_init: handle of service changed%d",
+ gatt_cb.handle_of_h_r );
+
+ /* start service
+ */
+ status = GATTS_StartService (gatt_cb.gatt_if, service_handle, GATT_TRANSPORT_LE_BR_EDR);
+
+ GATT_TRACE_DEBUG2 ("gatt_profile_db_init: gatt_if=%d start status%d",
+ gatt_cb.gatt_if, status);
+}
+
+#endif /* BLE_INCLUDED */
diff --git a/stack/gatt/gatt_auth.c b/stack/gatt/gatt_auth.c
new file mode 100644
index 0000000..b7fa13f
--- /dev/null
+++ b/stack/gatt/gatt_auth.c
@@ -0,0 +1,435 @@
+/*****************************************************************************
+**
+** Name: gatt_auth.c
+**
+** Description: this file contains GATT authentication handling functions
+**
+**
+** Copyright (c) 1999-2011, Broadcom Corp, All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+#include "bt_target.h"
+
+#if BLE_INCLUDED == TRUE
+#include <string.h>
+#include "gki.h"
+
+#include "gatt_int.h"
+#include "gatt_api.h"
+#include "btm_int.h"
+
+/*******************************************************************************
+**
+** Function gatt_sign_data
+**
+** Description This function sign the data for write command.
+**
+** Returns TRUE if encrypted, otherwise FALSE.
+**
+*******************************************************************************/
+static BOOLEAN gatt_sign_data (tGATT_CLCB *p_clcb)
+{
+ tGATT_VALUE *p_attr = (tGATT_VALUE *)p_clcb->p_attr_buf;
+ UINT8 *p_data = NULL, *p;
+ UINT16 payload_size = p_clcb->p_tcb->payload_size;
+ BOOLEAN status = FALSE;
+ UINT8 *p_signature;
+
+ p_data = (UINT8 *)GKI_getbuf((UINT16)(p_attr->len + 3)); /* 3 = 2 byte handle + opcode */
+
+ if (p_data != NULL)
+ {
+ p = p_data;
+ UINT8_TO_STREAM(p, GATT_SIGN_CMD_WRITE);
+ UINT16_TO_STREAM(p, p_attr->handle);
+ ARRAY_TO_STREAM(p, p_attr->value, p_attr->len);
+
+ /* sign data length should be attribulte value length plus 2B handle + 1B op code */
+ if ((payload_size - GATT_AUTH_SIGN_LEN - 3) < p_attr->len)
+ p_attr->len = payload_size - GATT_AUTH_SIGN_LEN - 3;
+
+ p_signature = p_attr->value + p_attr->len;
+ if (BTM_BleDataSignature(p_clcb->p_tcb->peer_bda,
+ p_data,
+ (UINT16)(p_attr->len + 3), /* 3 = 2 byte handle + opcode */
+ p_signature))
+ {
+ p_attr->len += BTM_BLE_AUTH_SIGN_LEN;
+ gatt_set_ch_state(p_clcb->p_tcb, GATT_CH_OPEN);
+ gatt_act_write(p_clcb);
+ }
+ else
+ {
+ gatt_end_operation(p_clcb, GATT_INTERNAL_ERROR, NULL);
+ }
+
+ GKI_freebuf(p_data);
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function gatt_verify_signature
+**
+** Description This function start to verify the sign data when receiving
+** the data from peer device.
+**
+** Returns
+**
+*******************************************************************************/
+void gatt_verify_signature(tGATT_TCB *p_tcb, BT_HDR *p_buf)
+{
+ UINT16 cmd_len;
+ UINT8 op_code;
+ UINT8 *p, *p_orig = (UINT8 *)(p_buf + 1) + p_buf->offset;
+ UINT32 counter;
+
+ cmd_len = p_buf->len - GATT_AUTH_SIGN_LEN + 4;
+ p = p_orig + cmd_len - 4;
+ STREAM_TO_UINT32(counter, p);
+
+ if (BTM_BleVerifySignature(p_tcb->peer_bda, p_orig, cmd_len, counter, p))
+ {
+ STREAM_TO_UINT8(op_code, p_orig);
+ gatt_server_handle_client_req (p_tcb, op_code, (UINT16)(p_buf->len - 1), p_orig);
+ }
+ else
+ {
+ /* if this is a bad signature, assume from attacker, ignore it */
+ GATT_TRACE_ERROR0("Signature Verification Failed");
+ gatt_disconnect(p_tcb->peer_bda);
+ }
+
+ return;
+}
+/*******************************************************************************
+**
+** Function gatt_sec_check_complete
+**
+** Description security check complete and proceed to data sending action.
+**
+** Returns void.
+**
+*******************************************************************************/
+void gatt_sec_check_complete(BOOLEAN sec_check_ok, tGATT_CLCB *p_clcb)
+{
+ p_clcb->p_tcb->p_clcb = NULL;
+ gatt_set_sec_act(p_clcb->p_tcb, GATT_SEC_NONE);
+
+ if (!sec_check_ok)
+ {
+ gatt_end_operation(p_clcb, GATT_AUTH_FAIL, NULL);
+ }
+ else if (p_clcb->operation == GATTC_OPTYPE_WRITE)
+ {
+ gatt_act_write(p_clcb);
+ }
+ else if (p_clcb->operation == GATTC_OPTYPE_READ)
+ {
+ gatt_act_read(p_clcb, p_clcb->counter);
+ }
+}
+/*******************************************************************************
+**
+** Function gatt_enc_cmpl_cback
+**
+** Description link encryption complete callback.
+**
+** Returns
+**
+*******************************************************************************/
+void gatt_enc_cmpl_cback(BD_ADDR bd_addr, void *p_ref_data, tBTM_STATUS result)
+{
+ tGATT_TCB *p_tcb;
+ UINT8 sec_flag;
+ BOOLEAN status = FALSE;
+
+ GATT_TRACE_DEBUG0("gatt_enc_cmpl_cback");
+ if ((p_tcb = gatt_find_tcb_by_addr(bd_addr)) != NULL)
+ {
+ gatt_set_ch_state(p_tcb, GATT_CH_OPEN);
+
+ if (result == BTM_SUCCESS)
+ {
+ if (gatt_get_sec_act(p_tcb) == GATT_SEC_ENCRYPT_MITM )
+ {
+ BTM_GetSecurityFlags(bd_addr, &sec_flag);
+ if (sec_flag & sec_flag & BTM_SEC_FLAG_LKEY_AUTHED)
+ {
+ status = TRUE;
+ }
+ }
+ else
+ {
+ status = TRUE;
+ }
+ }
+ gatt_sec_check_complete(status , (tGATT_CLCB *)p_tcb->p_clcb);
+ }
+ else
+ {
+ GATT_TRACE_ERROR0("enc callback for unknown bd_addr");
+ }
+}
+
+/*******************************************************************************
+**
+** Function gatt_set_sec_act
+**
+** Description This function set the sec_act in clcb
+**
+** Returns none
+**
+*******************************************************************************/
+void gatt_set_sec_act(tGATT_TCB *p_tcb, tGATT_SEC_ACTION sec_act)
+{
+ if (p_tcb)
+ {
+ p_tcb->sec_act = sec_act;
+ }
+}
+/*******************************************************************************
+**
+** Function gatt_get_sec_act
+**
+** Description This function get the sec_act in clcb
+**
+** Returns none
+**
+*******************************************************************************/
+tGATT_SEC_ACTION gatt_get_sec_act(tGATT_TCB *p_tcb)
+{
+ tGATT_SEC_ACTION sec_act = GATT_SEC_NONE;
+ if (p_tcb)
+ {
+ sec_act = p_tcb->sec_act;
+ }
+ return sec_act;
+}
+/*******************************************************************************
+**
+** Function gatt_determine_sec_act
+**
+** Description This routine determine the security action based on auth_request and
+** current link status
+**
+** Returns tGATT_SEC_ACTION security action
+**
+*******************************************************************************/
+tGATT_SEC_ACTION gatt_determine_sec_act(tGATT_CLCB *p_clcb )
+{
+ tGATT_SEC_ACTION act = GATT_SEC_OK;
+ UINT8 sec_flag;
+ tGATT_TCB *p_tcb = p_clcb->p_tcb;
+ tGATT_AUTH_REQ auth_req = p_clcb->auth_req;
+
+ BOOLEAN is_link_encrypted= FALSE;
+ BOOLEAN is_le_link=FALSE;
+ BOOLEAN is_link_key_known=FALSE;
+ BOOLEAN is_key_mitm=FALSE;
+ UINT8 key_type;
+
+ if (auth_req == GATT_AUTH_REQ_NONE )
+ return act;
+
+ is_le_link = btm_ble_check_link_type(p_tcb->peer_bda);
+ BTM_GetSecurityFlags(p_tcb->peer_bda, &sec_flag);
+
+ if (sec_flag & BTM_SEC_FLAG_ENCRYPTED)
+ {
+ is_link_encrypted = TRUE;
+ }
+ if (sec_flag & BTM_SEC_FLAG_LKEY_KNOWN)
+ {
+ is_link_key_known = TRUE;
+ if (sec_flag & BTM_SEC_FLAG_LKEY_AUTHED)
+ {
+ is_key_mitm = TRUE;
+ }
+ }
+
+ /* first check link key upgrade required or not */
+ switch (auth_req)
+ {
+ case GATT_AUTH_REQ_MITM:
+ case GATT_AUTH_REQ_SIGNED_MITM:
+ if (!is_key_mitm)
+ act = GATT_SEC_ENCRYPT_MITM;
+ break;
+
+ case GATT_AUTH_REQ_NO_MITM:
+ case GATT_AUTH_REQ_SIGNED_NO_MITM:
+ if (!is_link_key_known)
+ act = GATT_SEC_ENCRYPT_NO_MITM;
+ break;
+ default:
+ break;
+ }
+
+ /* now check link needs to be encrypted or not if the link key upgrade is not required */
+ if (act == GATT_SEC_OK)
+ {
+ if (is_le_link &&
+ (p_clcb->operation == GATTC_OPTYPE_WRITE) &&
+ (p_clcb->op_subtype == GATT_WRITE_NO_RSP))
+ {
+ /* this is a write command request
+ check data signing required or not */
+ if (!is_link_encrypted)
+ {
+ btm_ble_get_enc_key_type(p_tcb->peer_bda, &key_type);
+
+ if ( (key_type & BTM_LE_KEY_LCSRK) &&
+ ((auth_req == GATT_AUTH_REQ_SIGNED_NO_MITM) ||
+ (auth_req == GATT_AUTH_REQ_SIGNED_MITM)))
+ {
+ act = GATT_SEC_SIGN_DATA;
+ }
+ else
+ {
+ act = GATT_SEC_ENCRYPT;
+ }
+ }
+ }
+ else
+ {
+ if (!is_link_encrypted)
+ {
+ act = GATT_SEC_ENCRYPT;
+ }
+ }
+
+ }
+
+ return act ;
+
+}
+
+
+
+/*******************************************************************************
+**
+** Function gatt_get_link_encrypt_status
+**
+** Description This routine get the encryption status of the specified link
+**
+**
+** Returns tGATT_STATUS link encryption status
+**
+*******************************************************************************/
+tGATT_STATUS gatt_get_link_encrypt_status(tGATT_TCB *p_tcb)
+{
+ tGATT_STATUS encrypt_status = GATT_NOT_ENCRYPTED;
+ UINT8 sec_flag=0;
+
+ BTM_GetSecurityFlags(p_tcb->peer_bda, &sec_flag);
+
+ if ((sec_flag & BTM_SEC_FLAG_ENCRYPTED) && (sec_flag & BTM_SEC_FLAG_LKEY_KNOWN))
+ {
+ encrypt_status = GATT_ENCRYPED_NO_MITM;
+ if (sec_flag & BTM_SEC_FLAG_LKEY_AUTHED)
+ encrypt_status = GATT_ENCRYPED_MITM;
+ }
+
+ GATT_TRACE_DEBUG1("gatt_get_link_encrypt_status status=0x%x",encrypt_status);
+ return encrypt_status ;
+}
+
+
+/*******************************************************************************
+**
+** Function gatt_convert_sec_action
+**
+** Description Convert GATT security action enum into equivalent BTM BLE security action enum
+**
+** Returns BOOLEAN TRUE - conversation is successful
+**
+*******************************************************************************/
+static BOOLEAN gatt_convert_sec_action(tGATT_SEC_ACTION gatt_sec_act, tBTM_BLE_SEC_ACT *p_btm_sec_act )
+{
+ BOOLEAN status = TRUE;
+ switch (gatt_sec_act)
+ {
+ case GATT_SEC_ENCRYPT:
+ *p_btm_sec_act = BTM_BLE_SEC_ENCRYPT;
+ break;
+ case GATT_SEC_ENCRYPT_NO_MITM:
+ *p_btm_sec_act = BTM_BLE_SEC_ENCRYPT_NO_MITM;
+ break;
+ case GATT_SEC_ENCRYPT_MITM:
+ *p_btm_sec_act = BTM_BLE_SEC_ENCRYPT_MITM;
+ break;
+ default:
+ status = FALSE;
+ break;
+ }
+
+ return status;
+}
+/*******************************************************************************
+**
+** Function gatt_check_enc_req
+**
+** Description check link security.
+**
+** Returns TRUE if encrypted, otherwise FALSE.
+**
+*******************************************************************************/
+BOOLEAN gatt_security_check_start(tGATT_CLCB *p_clcb)
+{
+ tGATT_TCB *p_tcb = p_clcb->p_tcb;
+ tGATT_SEC_ACTION gatt_sec_act;
+ tBTM_BLE_SEC_ACT btm_ble_sec_act;
+ BOOLEAN status = TRUE;
+ tBTM_STATUS btm_status;
+
+ if ( gatt_get_ch_state(p_tcb) == GATT_CH_OPEN)
+ {
+ gatt_sec_act = gatt_determine_sec_act(p_clcb);
+ gatt_set_sec_act(p_tcb, gatt_sec_act);
+ switch (gatt_sec_act )
+ {
+ case GATT_SEC_SIGN_DATA:
+ GATT_TRACE_DEBUG0("gatt_security_check_start: Do data signing");
+ gatt_set_ch_state(p_tcb, GATT_CH_W4_DATA_SIGN_COMP);
+ gatt_sign_data(p_clcb);
+ break;
+ case GATT_SEC_ENCRYPT:
+ case GATT_SEC_ENCRYPT_NO_MITM:
+ case GATT_SEC_ENCRYPT_MITM:
+ GATT_TRACE_DEBUG0("gatt_security_check_start: Encrypt now or key upgreade first");
+ gatt_convert_sec_action(p_tcb->sec_act, &btm_ble_sec_act);
+ gatt_set_ch_state(p_tcb, GATT_CH_W4_SEC_COMP);
+ p_tcb->p_clcb = p_clcb; /* keep the clcb pointer in CCB */
+ btm_status = BTM_SetEncryption(p_tcb->peer_bda, gatt_enc_cmpl_cback, &btm_ble_sec_act);
+ if ( (btm_status != BTM_SUCCESS) && (btm_status != BTM_CMD_STARTED))
+ {
+ GATT_TRACE_ERROR1("gatt_security_check_start BTM_SetEncryption failed btm_status=%d", btm_status);
+ p_tcb->p_clcb = NULL;
+ status = FALSE;
+ }
+ break;
+ default:
+ gatt_sec_check_complete(TRUE, p_clcb);
+ break;
+ }
+
+ if (status == FALSE)
+ {
+ gatt_set_sec_act(p_tcb, GATT_SEC_NONE);
+ gatt_set_ch_state(p_tcb, GATT_CH_OPEN);
+ }
+ }
+ else
+ {
+ GATT_TRACE_ERROR0("gatt_security_check_start channel not open");
+ status = FALSE;
+ }
+
+ return status;
+}
+
+
+#endif /* BLE_INCLUDED */
diff --git a/stack/gatt/gatt_cl.c b/stack/gatt/gatt_cl.c
new file mode 100644
index 0000000..9853694
--- /dev/null
+++ b/stack/gatt/gatt_cl.c
@@ -0,0 +1,1206 @@
+/*****************************************************************************
+**
+** Name: gatt_cl.c
+**
+** Description: this file contains the main GATT client functions
+**
+** Copyright (c) 1999-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+
+#include "bt_target.h"
+
+#if BLE_INCLUDED == TRUE
+
+#include <string.h>
+#include "gki.h"
+#include "gatt_int.h"
+
+#define GATT_WRITE_LONG_HDR_SIZE 5 /* 1 opcode + 2 handle + 2 offset */
+#define GATT_READ_CHAR_VALUE_HDL (GATT_READ_CHAR_VALUE | 0x80)
+#define GATT_READ_INC_SRV_UUID128 (GATT_DISC_INC_SRVC | 0x90)
+
+/********************************************************************************
+** G L O B A L G A T T D A T A *
+*********************************************************************************/
+void gatt_send_prepare_write(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb);
+
+UINT8 disc_type_to_att_opcode[GATT_DISC_MAX] =
+{
+ 0,
+ GATT_REQ_READ_BY_GRP_TYPE, /* GATT_DISC_SRVC_ALL = 1, */
+ GATT_REQ_FIND_TYPE_VALUE, /* GATT_DISC_SRVC_BY_UUID, */
+ GATT_REQ_READ_BY_TYPE, /* GATT_DISC_INC_SRVC, */
+ GATT_REQ_READ_BY_TYPE, /* GATT_DISC_CHAR, */
+ GATT_REQ_FIND_INFO /* GATT_DISC_CHAR_DSCPT, */
+};
+
+UINT16 disc_type_to_uuid[GATT_DISC_MAX] =
+{
+ 0, /* reserved */
+ GATT_UUID_PRI_SERVICE, /* <service> DISC_SRVC_ALL */
+ GATT_UUID_PRI_SERVICE, /* <service> for DISC_SERVC_BY_UUID */
+ GATT_UUID_INCLUDE_SERVICE, /* <include_service> for DISC_INC_SRVC */
+ GATT_UUID_CHAR_DECLARE, /* <characteristic> for DISC_CHAR */
+ 0 /* no type filtering for DISC_CHAR_DSCPT */
+};
+
+
+/*******************************************************************************
+**
+** Function gatt_act_discovery
+**
+** Description GATT discovery operation.
+**
+** Returns void.
+**
+*******************************************************************************/
+void gatt_act_discovery(tGATT_CLCB *p_clcb)
+{
+ UINT8 op_code = disc_type_to_att_opcode[p_clcb->op_subtype];
+ tGATT_CL_MSG cl_req;
+
+ if (p_clcb->s_handle <= p_clcb->e_handle && p_clcb->s_handle != 0)
+ {
+ memset(&cl_req, 0, sizeof(tGATT_CL_MSG));
+
+ cl_req.browse.s_handle = p_clcb->s_handle;
+ cl_req.browse.e_handle = p_clcb->e_handle;
+
+ if (disc_type_to_uuid[p_clcb->op_subtype] != 0)
+ {
+ cl_req.browse.uuid.len = 2;
+ cl_req.browse.uuid.uu.uuid16 = disc_type_to_uuid[p_clcb->op_subtype];
+ }
+
+ if (p_clcb->op_subtype == GATT_DISC_SRVC_BY_UUID) /* fill in the FindByTypeValue request info*/
+ {
+ cl_req.find_type_value.uuid.len = 2;
+ cl_req.find_type_value.uuid.uu.uuid16 = disc_type_to_uuid[p_clcb->op_subtype];
+ cl_req.find_type_value.s_handle = p_clcb->s_handle;
+ cl_req.find_type_value.e_handle = p_clcb->e_handle;
+ cl_req.find_type_value.value_len = p_clcb->uuid.len;
+ memcpy (cl_req.find_type_value.value, &p_clcb->uuid.uu, p_clcb->uuid.len);
+ }
+
+ if (attp_send_cl_msg(p_clcb->p_tcb, p_clcb->clcb_idx, op_code, &cl_req) != GATT_SUCCESS)
+ {
+ gatt_end_operation(p_clcb, GATT_ERROR, NULL);
+ }
+ }
+ else /* end of handle range */
+ gatt_end_operation(p_clcb, GATT_SUCCESS, NULL);
+}
+
+/*******************************************************************************
+**
+** Function gatt_act_read
+**
+** Description GATT read operation.
+**
+** Returns void.
+**
+*******************************************************************************/
+void gatt_act_read (tGATT_CLCB *p_clcb, UINT16 offset)
+{
+ tGATT_TCB *p_tcb = p_clcb->p_tcb;
+ UINT8 rt = GATT_INTERNAL_ERROR;
+ tGATT_CL_MSG msg;
+ UINT8 op_code = 0;
+
+ memset (&msg, 0, sizeof(tGATT_CL_MSG));
+
+ switch (p_clcb->op_subtype)
+ {
+ case GATT_READ_CHAR_VALUE:
+ case GATT_READ_BY_TYPE:
+ op_code = GATT_REQ_READ_BY_TYPE;
+ msg.browse.s_handle = p_clcb->s_handle;
+ msg.browse.e_handle = p_clcb->e_handle;
+ if (p_clcb->op_subtype == GATT_READ_BY_TYPE)
+ memcpy(&msg.browse.uuid, &p_clcb->uuid, sizeof(tBT_UUID));
+ else
+ {
+ msg.browse.uuid.len = LEN_UUID_16;
+ msg.browse.uuid.uu.uuid16 = GATT_UUID_CHAR_DECLARE;
+ }
+ break;
+
+ case GATT_READ_CHAR_VALUE_HDL:
+ case GATT_READ_BY_HANDLE:
+ if (!p_clcb->counter)
+ {
+ op_code = GATT_REQ_READ;
+ msg.handle = p_clcb->s_handle;
+ }
+ else
+ {
+ if (!p_clcb->first_read_blob_after_read)
+ p_clcb->first_read_blob_after_read = TRUE;
+ else
+ p_clcb->first_read_blob_after_read = FALSE;
+
+ GATT_TRACE_DEBUG1("gatt_act_read first_read_blob_after_read=%d",
+ p_clcb->first_read_blob_after_read);
+ op_code = GATT_REQ_READ_BLOB;
+ msg.read_blob.offset = offset;
+ msg.read_blob.handle = p_clcb->s_handle;
+ }
+ p_clcb->op_subtype &= ~ 0x80;
+ break;
+
+ case GATT_READ_PARTIAL:
+ op_code = GATT_REQ_READ_BLOB;
+ msg.read_blob.handle = p_clcb->s_handle;
+ msg.read_blob.offset = offset;
+ break;
+
+ case GATT_READ_MULTIPLE:
+ op_code = GATT_REQ_READ_MULTI;
+ memcpy (&msg.read_multi, p_clcb->p_attr_buf, sizeof(tGATT_READ_MULTI));
+ break;
+
+ case GATT_READ_INC_SRV_UUID128:
+ op_code = GATT_REQ_READ;
+ msg.handle = p_clcb->s_handle;
+ p_clcb->op_subtype &= ~ 0x90;
+ break;
+
+ default:
+ GATT_TRACE_ERROR1("Unknown read type: %d", p_clcb->op_subtype);
+ break;
+ }
+
+ if ( op_code == 0 ||
+ (rt = attp_send_cl_msg(p_tcb, p_clcb->clcb_idx, op_code, &msg)) != GATT_SUCCESS)
+ {
+ gatt_end_operation(p_clcb, rt, NULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function gatt_act_write
+**
+** Description GATT write operation.
+**
+** Returns void.
+**
+*******************************************************************************/
+void gatt_act_write (tGATT_CLCB *p_clcb)
+{
+ tGATT_TCB *p_tcb = p_clcb->p_tcb;
+ UINT8 rt = GATT_SUCCESS, op_code;
+ tGATT_VALUE *p_attr = (tGATT_VALUE *)p_clcb->p_attr_buf;
+
+ if (p_attr)
+ {
+ switch (p_clcb->op_subtype)
+ {
+ case GATT_WRITE_NO_RSP:
+ p_clcb->s_handle = p_attr->handle;
+ op_code = (p_tcb->sec_act & GATT_SEC_SIGN_DATA) ? GATT_SIGN_CMD_WRITE : GATT_CMD_WRITE;
+ rt = gatt_send_write_msg(p_tcb,
+ p_clcb->clcb_idx,
+ op_code,
+ p_attr->handle,
+ p_attr->len,
+ 0,
+ p_attr->value);
+ break;
+
+ case GATT_WRITE:
+ if (p_attr->len <= (p_tcb->payload_size - GATT_HDR_SIZE))
+ {
+ p_clcb->s_handle = p_attr->handle;
+
+ rt = gatt_send_write_msg(p_tcb,
+ p_clcb->clcb_idx,
+ GATT_REQ_WRITE,
+ p_attr->handle,
+ p_attr->len,
+ 0,
+ p_attr->value);
+ }
+ else /* prepare write for long attribute */
+ {
+ gatt_send_prepare_write(p_tcb, p_clcb);
+ }
+ break;
+
+ case GATT_WRITE_PREPARE:
+ gatt_send_prepare_write(p_tcb, p_clcb);
+ break;
+
+ default:
+ rt = GATT_INTERNAL_ERROR;
+ GATT_TRACE_ERROR1("Unknown write type: %d", p_clcb->op_subtype);
+ break;
+ }
+ }
+ else
+ rt = GATT_INTERNAL_ERROR;
+
+ if ((rt != GATT_SUCCESS && rt != GATT_CMD_STARTED)
+ || (rt != GATT_CMD_STARTED && p_clcb->op_subtype == GATT_WRITE_NO_RSP))
+ {
+ if (rt != GATT_SUCCESS)
+ {
+ GATT_TRACE_ERROR1("gatt_act_write() failed op_code=0x%x", op_code);
+ }
+ gatt_end_operation(p_clcb, rt, NULL);
+ }
+}
+/*******************************************************************************
+**
+** Function gatt_send_queue_write_cancel
+**
+** Description send queue write cancel
+**
+** Returns void.
+**
+*******************************************************************************/
+void gatt_send_queue_write_cancel (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, tGATT_EXEC_FLAG flag)
+{
+ UINT8 rt ;
+
+ GATT_TRACE_DEBUG0("gatt_send_queue_write_cancel ");
+
+ rt = attp_send_cl_msg(p_tcb, p_clcb->clcb_idx, GATT_REQ_EXEC_WRITE, (tGATT_CL_MSG *)&flag);
+
+ if (rt != GATT_SUCCESS)
+ {
+ gatt_end_operation(p_clcb, rt, NULL);
+ }
+}
+/*******************************************************************************
+**
+** Function gatt_check_write_long_terminate
+**
+** Description To terminate write long or not.
+**
+** Returns TRUE: write long is terminated; FALSE keep sending.
+**
+*******************************************************************************/
+BOOLEAN gatt_check_write_long_terminate(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, tGATT_VALUE *p_rsp_value)
+{
+ tGATT_VALUE *p_attr = (tGATT_VALUE *)p_clcb->p_attr_buf;
+ BOOLEAN exec = FALSE;
+ tGATT_EXEC_FLAG flag = GATT_PREP_WRITE_EXEC;
+
+ GATT_TRACE_DEBUG0("gatt_check_write_long_terminate ");
+ /* check the first write response status */
+ if (p_rsp_value != NULL)
+ {
+ if (p_rsp_value->handle != p_attr->handle ||
+ p_rsp_value->len != p_clcb->counter ||
+ memcmp(p_rsp_value->value, p_attr->value + p_attr->offset, p_rsp_value->len))
+ {
+ /* data does not match */
+ p_clcb->status = GATT_ERROR;
+ flag = GATT_PREP_WRITE_CANCEL;
+ exec = TRUE;
+ }
+ else /* response checking is good */
+ {
+ p_clcb->status = GATT_SUCCESS;
+ /* update write offset and check if end of attribute value */
+ if ((p_attr->offset += p_rsp_value->len) >= p_attr->len)
+ exec = TRUE;
+ }
+ }
+ if (exec)
+ {
+ gatt_send_queue_write_cancel (p_tcb, p_clcb, flag);
+ return TRUE;
+ }
+ return FALSE;
+}
+/*******************************************************************************
+**
+** Function gatt_send_prepare_write
+**
+** Description Send prepare write.
+**
+** Returns void.
+**
+*******************************************************************************/
+void gatt_send_prepare_write(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb)
+{
+ tGATT_VALUE *p_attr = (tGATT_VALUE *)p_clcb->p_attr_buf;
+ UINT16 to_send, offset;
+ UINT8 rt = GATT_SUCCESS;
+ UINT8 type = p_clcb->op_subtype;
+
+ GATT_TRACE_DEBUG1("gatt_send_prepare_write type=0x%x", type );
+ to_send = p_attr->len - p_attr->offset;
+
+ if (to_send > (p_tcb->payload_size - GATT_WRITE_LONG_HDR_SIZE)) /* 2 = UINT16 offset bytes */
+ to_send = p_tcb->payload_size - GATT_WRITE_LONG_HDR_SIZE;
+
+ p_clcb->s_handle = p_attr->handle;
+
+ offset = p_attr->offset;
+ if (type == GATT_WRITE_PREPARE)
+ {
+ offset += p_clcb->start_offset;
+ }
+
+ GATT_TRACE_DEBUG2("offset =0x%x len=%d", offset, to_send );
+
+ rt = gatt_send_write_msg(p_tcb,
+ p_clcb->clcb_idx,
+ GATT_REQ_PREPARE_WRITE,
+ p_attr->handle,
+ to_send, /* length */
+ offset, /* used as offset */
+ p_attr->value + p_attr->offset); /* data */
+
+ /* remember the write long attribute length */
+ p_clcb->counter = to_send;
+
+ if (rt != GATT_SUCCESS )
+ {
+ gatt_end_operation(p_clcb, rt, NULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function gatt_proc_disc_read_by_type_rsp
+**
+** Description This function process the read by type response and send another
+** request if needed.
+**
+** Returns void.
+**
+*******************************************************************************/
+void gatt_proc_disc_read_by_type_rsp(tGATT_CLCB *p_clcb, UINT16 len, UINT8 *p_data)
+{
+ /*
+ tGATT_TCB *p_tcb = p_clcb->p_tcb;
+ tGATT_DISCOVERY_DB *p_db = p_clcb->p_disc_db;
+ tGATT_DISC_REC *p_rec;
+ tGATT_STATUS status = GATT_INTERNAL_ERROR;
+
+
+ if ((p_rec = gatt_add_record(p_clcb->p_disc_db)) != NULL)
+ {
+ p_rec->handle = handle;
+ p_rec->type = p_db->uuid_filter;
+ p_rec->attr_len = len;
+
+ // copy the attibute value into DB
+ p_rec->p_value = p_db->p_free_mem;
+ memcpy(p_rec->p_value, p_value, len);
+ p_db->p_free_mem += len;
+ p_db->mem_free -= len;
+
+ if (handle < p_clcb->e_handle)
+ {
+ // send another request
+ if (gatt_act_send_browse(p_tcb, p_clcb->conn_id,
+ GATT_REQ_READ_BY_TYPE,
+ (UINT16)(handle + 1), // starting handle
+ p_clcb->e_handle, // end handle
+ p_clcb->p_disc_db->uuid_filter) // uuid filter /
+ == GATT_SUCCESS)
+ {
+ status = GATT_SUCCESS;
+ }
+ }
+ }
+ else
+ status = GATT_DB_FULL;
+
+ if (status != GATT_SUCCESS) // DB full
+ {
+ gatt_end_operation(p_clcb, status, NULL);
+ }*/
+}
+/*******************************************************************************
+**
+** Function gatt_process_find_type_value_rsp
+**
+** Description This function is called to handle find by type value response.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void gatt_process_find_type_value_rsp (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT16 len, UINT8 *p_data)
+{
+ tGATT_DISC_RES result;
+ tGATT_DISC_VALUE record_value;
+ UINT8 *p = p_data;
+
+ GATT_TRACE_DEBUG0("gatt_process_find_type_value_rsp ");
+ /* unexpected response */
+ if (p_clcb->operation != GATTC_OPTYPE_DISCOVERY || p_clcb->op_subtype != GATT_DISC_SRVC_BY_UUID)
+ return;
+
+ memset (&record_value, 0, sizeof(tGATT_DISC_VALUE));
+ result.type.len = 2;
+ result.type.uu.uuid16 = GATT_UUID_PRI_SERVICE;
+
+ /* returns a series of handle ranges */
+ while (len >= 4)
+ {
+ STREAM_TO_UINT16 (result.handle, p);
+ STREAM_TO_UINT16 (record_value.handle, p);
+ len -= 4;
+
+ memcpy (&result.value, &record_value, sizeof (result.value));;
+
+ if (p_clcb->p_reg->app_cb.p_disc_res_cb)
+ (*p_clcb->p_reg->app_cb.p_disc_res_cb)(p_clcb->conn_id, p_clcb->op_subtype, &result);
+ }
+
+ /* last handle + 1 */
+ p_clcb->s_handle = (record_value.handle == 0) ? 0 : (record_value.handle + 1);
+ /* initiate another request */
+ gatt_act_discovery(p_clcb) ;
+}
+/*******************************************************************************
+**
+** Function gatt_process_read_info_rsp
+**
+** Description This function is called to handle the read information
+** response.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void gatt_process_read_info_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op_code,
+ UINT16 len, UINT8 *p_data)
+{
+ tGATT_DISC_RES result;
+ UINT8 *p = p_data, uuid_len = 0, type;
+
+ /* unexpected response */
+ if (p_clcb->operation != GATTC_OPTYPE_DISCOVERY || p_clcb->op_subtype != GATT_DISC_CHAR_DSCPT)
+ return;
+
+ STREAM_TO_UINT8(type, p);
+ len -= 1;
+
+ if (type == GATT_INFO_TYPE_PAIR_16)
+ uuid_len = LEN_UUID_16;
+ else if (type == GATT_INFO_TYPE_PAIR_128)
+ uuid_len = LEN_UUID_128;
+
+ while (len >= uuid_len + 2)
+ {
+ STREAM_TO_UINT16 (result.handle, p);
+
+ if (uuid_len > 0)
+ {
+ if (!gatt_parse_uuid_from_cmd(&result.type, uuid_len, &p))
+ break;
+ }
+ else
+ memcpy (&result.type, &p_clcb->uuid, sizeof(tBT_UUID));
+
+ len -= (uuid_len + 2);
+
+ if (p_clcb->p_reg->app_cb.p_disc_res_cb)
+ (*p_clcb->p_reg->app_cb.p_disc_res_cb)(p_clcb->conn_id, p_clcb->op_subtype, &result);
+ }
+
+ p_clcb->s_handle = (result.handle == 0) ? 0 :(result.handle + 1);
+ /* initiate another request */
+ gatt_act_discovery(p_clcb) ;
+}
+/*******************************************************************************
+**
+** Function gatt_proc_disc_error_rsp
+**
+** Description This function process the read by type response and send another
+** request if needed.
+**
+** Returns void.
+**
+*******************************************************************************/
+void gatt_proc_disc_error_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 opcode,
+ UINT16 handle, UINT8 reason)
+{
+ tGATT_STATUS status = (tGATT_STATUS) reason;
+
+ GATT_TRACE_DEBUG2("gatt_proc_disc_error_rsp reason: %02x cmd_code %04x", reason, opcode);
+
+ switch (opcode)
+ {
+ case GATT_REQ_READ_BY_GRP_TYPE:
+ case GATT_REQ_FIND_TYPE_VALUE:
+ case GATT_REQ_READ_BY_TYPE:
+ case GATT_REQ_FIND_INFO:
+ if (reason == GATT_NOT_FOUND)
+ {
+ status = GATT_SUCCESS;
+ GATT_TRACE_DEBUG0("Discovery completed");
+ }
+ break;
+ default:
+ GATT_TRACE_ERROR1("Incorrect discovery opcode %04x", opcode);
+ break;
+ }
+
+ gatt_end_operation(p_clcb, status, NULL);
+}
+
+/*******************************************************************************
+**
+** Function gatt_process_error_rsp
+**
+** Description This function is called to handle the error response
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void gatt_process_error_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op_code,
+ UINT16 len, UINT8 *p_data)
+{
+ UINT8 opcode, reason, * p= p_data;
+ UINT16 handle;
+ tGATT_VALUE *p_attr = (tGATT_VALUE *)p_clcb->p_attr_buf;
+
+ GATT_TRACE_DEBUG0("gatt_process_error_rsp ");
+ STREAM_TO_UINT8(opcode, p);
+ STREAM_TO_UINT16(handle, p);
+ STREAM_TO_UINT8(reason, p);
+
+ if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY)
+ {
+ gatt_proc_disc_error_rsp(p_tcb, p_clcb, opcode, handle, reason);
+ }
+ else
+ {
+ if ( (p_clcb->operation == GATTC_OPTYPE_WRITE) &&
+ (p_clcb->op_subtype == GATT_WRITE) &&
+ (opcode == GATT_REQ_PREPARE_WRITE) &&
+ (p_attr) &&
+ (handle == p_attr->handle) )
+ {
+ p_clcb->status = reason;
+ gatt_send_queue_write_cancel(p_tcb, p_clcb, GATT_PREP_WRITE_CANCEL);
+ }
+ else if ((p_clcb->operation == GATTC_OPTYPE_READ) &&
+ ((p_clcb->op_subtype == GATT_READ_CHAR_VALUE_HDL) ||
+ (p_clcb->op_subtype == GATT_READ_BY_HANDLE)) &&
+ (opcode == GATT_REQ_READ_BLOB) &&
+ p_clcb->first_read_blob_after_read &&
+ (reason == GATT_NOT_LONG))
+ {
+ gatt_end_operation(p_clcb, GATT_SUCCESS, (void *)p_clcb->p_attr_buf);
+ }
+ else
+ gatt_end_operation(p_clcb, reason, NULL);
+ }
+}
+/*******************************************************************************
+**
+** Function gatt_process_prep_write_rsp
+**
+** Description This function is called to handle the read response
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void gatt_process_prep_write_rsp (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op_code,
+ UINT16 len, UINT8 *p_data)
+{
+ tGATT_VALUE value = {0};
+ UINT8 *p= p_data;
+
+ GATT_TRACE_ERROR2("value resp op_code = %s len = %d", gatt_dbg_op_name(op_code), len);
+
+ STREAM_TO_UINT16 (value.handle, p);
+ STREAM_TO_UINT16 (value.offset, p);
+
+ value.len = len - 4;
+
+ memcpy (value.value, p, value.len);
+
+ if (p_clcb->op_subtype == GATT_WRITE_PREPARE)
+ {
+ p_clcb->status = GATT_SUCCESS;
+ /* application should verify handle offset
+ and value are matched or not */
+
+ gatt_end_operation(p_clcb, p_clcb->status, &value);
+ }
+ else if (p_clcb->op_subtype == GATT_WRITE )
+ {
+ if (!gatt_check_write_long_terminate(p_tcb, p_clcb, &value))
+ gatt_send_prepare_write(p_tcb, p_clcb);
+ }
+
+}
+/*******************************************************************************
+**
+** Function gatt_process_notification
+**
+** Description This function is called to handle the handle value indication
+** or handle value notification.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void gatt_process_notification(tGATT_TCB *p_tcb, UINT8 op_code,
+ UINT16 len, UINT8 *p_data)
+{
+ tGATT_VALUE value = {0};
+ tGATT_REG *p_reg;
+ UINT16 conn_id;
+ tGATT_STATUS encrypt_status;
+ UINT8 *p= p_data, i,
+ event = (op_code == GATT_HANDLE_VALUE_NOTIF) ? GATTC_OPTYPE_NOTIFICATION : GATTC_OPTYPE_INDICATION;
+
+ GATT_TRACE_DEBUG0("gatt_process_notification ");
+
+ STREAM_TO_UINT16 (value.handle, p);
+ value.len = len - 2;
+ memcpy (value.value, p, value.len);
+
+ if (!GATT_HANDLE_IS_VALID(value.handle))
+ {
+ /* illegal handle, send ack now */
+ if (op_code == GATT_HANDLE_VALUE_IND)
+ attp_send_cl_msg(p_tcb, 0, GATT_HANDLE_VALUE_CONF, NULL);
+ return;
+ }
+
+ if (event == GATTC_OPTYPE_INDICATION)
+ {
+ if (p_tcb->ind_count)
+ {
+ /* this is an error case that receiving an indication but we
+ still has an indication not being acked yet.
+ For now, just log the error reset the counter.
+ Later we need to disconnect the link unconditionally.
+ */
+ GATT_TRACE_ERROR1("gatt_process_notification rcv Ind. but ind_count=%d (will reset ind_count)", p_tcb->ind_count);
+ }
+ p_tcb->ind_count = 0;
+ }
+
+ /* should notify all registered client with the handle value notificaion/indication
+ Note: need to do the indication count and start timer first then do callback
+ */
+
+ for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++)
+ {
+ if (p_reg->in_use && p_reg->app_cb.p_cmpl_cb && (event == GATTC_OPTYPE_INDICATION))
+ p_tcb->ind_count++;
+ }
+
+ if (event == GATTC_OPTYPE_INDICATION)
+ {
+ /* start a timer for app confirmation */
+ if (p_tcb->ind_count > 0)
+ gatt_start_ind_ack_timer(p_tcb);
+ else /* no app to indicate, or invalid handle */
+ attp_send_cl_msg(p_tcb, 0, GATT_HANDLE_VALUE_CONF, NULL);
+ }
+
+ for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++)
+ {
+ if (p_reg->in_use && p_reg->app_cb.p_cmpl_cb)
+ {
+ conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if);
+ encrypt_status = gatt_get_link_encrypt_status(p_tcb);
+ (*p_reg->app_cb.p_cmpl_cb) (conn_id, event, encrypt_status, (tGATT_CL_COMPLETE *)&value);
+ }
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function gatt_process_read_by_type_rsp
+**
+** Description This function is called to handle the read by type response.
+** read by type can be used for discovery, or read by type or
+** read characteristic value.
+**
+** Returns void
+**
+*******************************************************************************/
+void gatt_process_read_by_type_rsp (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op_code,
+ UINT16 len, UINT8 *p_data)
+{
+ tGATT_DISC_RES result;
+ tGATT_DISC_VALUE record_value;
+ UINT8 *p = p_data, value_len, handle_len = 2;
+ UINT16 handle = 0;
+
+ /* discovery procedure and no callback function registered */
+ if (((!p_clcb->p_reg) || (!p_clcb->p_reg->app_cb.p_disc_res_cb)) && (p_clcb->operation == GATTC_OPTYPE_DISCOVERY))
+ return;
+
+ STREAM_TO_UINT8(value_len, p);
+
+ if ((value_len > (p_tcb->payload_size - 2)) || (value_len > (len-1)) )
+ {
+ /* this is an error case that server's response containing a value length which is larger than MTU-2
+ or value_len > message total length -1 */
+ GATT_TRACE_ERROR4("gatt_process_read_by_type_rsp: Discard response op_code=%d vale_len=%d > (MTU-2=%d or msg_len-1=%d)",
+ op_code, value_len, (p_tcb->payload_size - 2), (len-1));
+ gatt_end_operation(p_clcb, GATT_ERROR, NULL);
+ return;
+ }
+
+ if (op_code == GATT_RSP_READ_BY_GRP_TYPE)
+ handle_len = 4;
+
+ value_len -= handle_len; /* substract the handle pairs bytes */
+ len -= 1;
+
+ while (len >= (handle_len + value_len))
+ {
+ STREAM_TO_UINT16(handle, p);
+
+ if (!GATT_HANDLE_IS_VALID(handle))
+ {
+ gatt_end_operation(p_clcb, GATT_INVALID_HANDLE, NULL);
+ return;
+ }
+
+ memset(&result, 0, sizeof(tGATT_DISC_RES));
+ memset(&record_value, 0, sizeof(tGATT_DISC_VALUE));
+
+ result.handle = handle;
+ result.type.len = 2;
+ result.type.uu.uuid16 = disc_type_to_uuid[p_clcb->op_subtype];
+
+ /* discover all services */
+ if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY &&
+ p_clcb->op_subtype == GATT_DISC_SRVC_ALL &&
+ op_code == GATT_RSP_READ_BY_GRP_TYPE)
+ {
+ STREAM_TO_UINT16(handle, p);
+
+ if (!GATT_HANDLE_IS_VALID(handle))
+ {
+ gatt_end_operation(p_clcb, GATT_INVALID_HANDLE, NULL);
+ return;
+ }
+ else
+ {
+ record_value.group_value.e_handle = handle;
+ if (!gatt_parse_uuid_from_cmd(&record_value.group_value.service_type, value_len, &p))
+ {
+ GATT_TRACE_ERROR0("discover all service response parsing failure");
+ break;
+ }
+ }
+ }
+ /* discover included service */
+ else if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY && p_clcb->op_subtype == GATT_DISC_INC_SRVC)
+ {
+ STREAM_TO_UINT16(record_value.incl_service.s_handle, p);
+ STREAM_TO_UINT16(record_value.incl_service.e_handle, p);
+
+ if (!GATT_HANDLE_IS_VALID(record_value.incl_service.s_handle) ||
+ !GATT_HANDLE_IS_VALID(record_value.incl_service.e_handle))
+ {
+ gatt_end_operation(p_clcb, GATT_INVALID_HANDLE, NULL);
+ return;
+ }
+
+ if(value_len == 6)
+ {
+ STREAM_TO_UINT16(record_value.incl_service.service_type.uu.uuid16, p);
+ record_value.incl_service.service_type.len = LEN_UUID_16;
+ }
+ else if (value_len == 4)
+ {
+ p_clcb->s_handle = record_value.incl_service.s_handle;
+ p_clcb->read_uuid128.wait_for_read_rsp = TRUE;
+ p_clcb->read_uuid128.next_disc_start_hdl = handle + 1;
+ memcpy(&p_clcb->read_uuid128.result, &result, sizeof(result));
+ memcpy(&p_clcb->read_uuid128.result.value, &record_value, sizeof (result.value));
+ p_clcb->op_subtype |= 0x90;
+ gatt_act_read(p_clcb, 0);
+ return;
+ }
+ else
+ {
+ GATT_TRACE_ERROR1("gatt_process_read_by_type_rsp INCL_SRVC failed with invalid data value_len=%d", value_len);
+ gatt_end_operation(p_clcb, GATT_INVALID_PDU, (void *)p);
+ return;
+ }
+ }
+ /* read by type */
+ else if (p_clcb->operation == GATTC_OPTYPE_READ && p_clcb->op_subtype == GATT_READ_BY_TYPE)
+ {
+ p_clcb->counter = len - 2;
+ p_clcb->s_handle = handle;
+ if ( p_clcb->counter == (p_clcb->p_tcb->payload_size -4))
+ {
+ p_clcb->op_subtype = GATT_READ_BY_HANDLE;
+ if (!p_clcb->p_attr_buf)
+ p_clcb->p_attr_buf = (UINT8 *)GKI_getbuf(GATT_MAX_ATTR_LEN);
+ if (p_clcb->p_attr_buf && p_clcb->counter <= GATT_MAX_ATTR_LEN)
+ {
+ memcpy(p_clcb->p_attr_buf, p, p_clcb->counter);
+ gatt_act_read(p_clcb, p_clcb->counter);
+ }
+ else
+ gatt_end_operation(p_clcb, GATT_INTERNAL_ERROR, (void *)p);
+ }
+ else
+ {
+ gatt_end_operation(p_clcb, GATT_SUCCESS, (void *)p);
+ }
+ return;
+ }
+ else /* discover characterisitic or read characteristic value */
+ {
+ STREAM_TO_UINT8 (record_value.dclr_value.char_prop, p);
+ STREAM_TO_UINT16(record_value.dclr_value.val_handle, p);
+ if (!GATT_HANDLE_IS_VALID(record_value.dclr_value.val_handle))
+ {
+ gatt_end_operation(p_clcb, GATT_INVALID_HANDLE, NULL);
+ return;
+ }
+ gatt_parse_uuid_from_cmd(&record_value.dclr_value.char_uuid, (UINT16)(value_len - 3), &p);
+
+ /* UUID not matching */
+ if (!gatt_uuid_compare(record_value.dclr_value.char_uuid, p_clcb->uuid))
+ {
+ len -= (value_len + 2);
+ continue; /* skip the result, and look for next one */
+ }
+ else if (p_clcb->operation == GATTC_OPTYPE_READ)
+ /* UUID match for read characteristic value */
+ {
+ /* only read the first matching UUID characteristic value, and
+ discard the rest results */
+ p_clcb->s_handle = record_value.dclr_value.val_handle;
+ p_clcb->op_subtype |= 0x80;
+ gatt_act_read(p_clcb, 0);
+ return;
+ }
+ }
+ len -= (value_len + handle_len);
+
+ /* result is (handle, 16bits UUID) pairs */
+ memcpy (&result.value, &record_value, sizeof (result.value));
+
+ /* send callback if is discover procedure */
+ if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY && p_clcb->p_reg->app_cb.p_disc_res_cb)
+ (*p_clcb->p_reg->app_cb.p_disc_res_cb)(p_clcb->conn_id, p_clcb->op_subtype, &result);
+ }
+
+ p_clcb->s_handle = (handle == 0) ? 0 : (handle + 1);
+
+ if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY)
+ {
+ /* initiate another request */
+ gatt_act_discovery(p_clcb) ;
+ }
+ else /* read characteristic value */
+ {
+ gatt_act_read(p_clcb, 0);
+ }
+}
+
+/*******************************************************************************
+**
+** Function gatt_process_read_rsp
+**
+** Description This function is called to handle the read BLOB response
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void gatt_process_read_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op_code,
+ UINT16 len, UINT8 *p_data)
+{
+ UINT16 offset = p_clcb->counter;
+ UINT8 * p= p_data;
+
+ if (p_clcb->operation == GATTC_OPTYPE_READ)
+ {
+ if (p_clcb->op_subtype != GATT_READ_BY_HANDLE)
+ {
+ p_clcb->counter = len;
+ gatt_end_operation(p_clcb, GATT_SUCCESS, (void *)p);
+ }
+ else
+ {
+
+ /* allocate GKI buffer holding up long attribute value */
+ if (!p_clcb->p_attr_buf)
+ p_clcb->p_attr_buf = (UINT8 *)GKI_getbuf(GATT_MAX_ATTR_LEN);
+
+ /* copy attrobute value into cb buffer */
+ if (p_clcb->p_attr_buf && offset < GATT_MAX_ATTR_LEN)
+ {
+ if ((len + offset) > GATT_MAX_ATTR_LEN)
+ len = GATT_MAX_ATTR_LEN - offset;
+
+ p_clcb->counter += len;
+
+ memcpy(p_clcb->p_attr_buf + offset, p, len);
+
+ /* send next request if needed */
+
+ if (len == (p_tcb->payload_size - 1) && /* full packet for read or read blob rsp */
+ len + offset < GATT_MAX_ATTR_LEN)
+ {
+ GATT_TRACE_DEBUG3("full pkt issue read blob for remianing bytes old offset=%d len=%d new offset=%d",
+ offset, len, p_clcb->counter);
+ gatt_act_read(p_clcb, p_clcb->counter);
+ }
+ else /* end of request, send callback */
+ {
+ gatt_end_operation(p_clcb, GATT_SUCCESS, (void *)p_clcb->p_attr_buf);
+ }
+ }
+ else /* exception, should not happen */
+ {
+ GATT_TRACE_ERROR2("attr offset = %d p_attr_buf = %d ", offset, p_clcb->p_attr_buf);
+ gatt_end_operation(p_clcb, GATT_NO_RESOURCES, (void *)p_clcb->p_attr_buf);
+ }
+ }
+ }
+ else
+ {
+ if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY &&
+ p_clcb->op_subtype == GATT_DISC_INC_SRVC &&
+ p_clcb->read_uuid128.wait_for_read_rsp )
+ {
+ p_clcb->s_handle = p_clcb->read_uuid128.next_disc_start_hdl;
+ p_clcb->read_uuid128.wait_for_read_rsp = FALSE;
+ if (len == LEN_UUID_128)
+ {
+
+ memcpy(p_clcb->read_uuid128.result.value.incl_service.service_type.uu.uuid128, p, len);
+ p_clcb->read_uuid128.result.value.incl_service.service_type.len = LEN_UUID_128;
+ if ( p_clcb->p_reg->app_cb.p_disc_res_cb)
+ (*p_clcb->p_reg->app_cb.p_disc_res_cb)(p_clcb->conn_id, p_clcb->op_subtype, &p_clcb->read_uuid128.result);
+ gatt_act_discovery(p_clcb) ;
+ }
+ else
+ {
+ gatt_end_operation(p_clcb, GATT_INVALID_PDU, (void *)p);
+ }
+ }
+ }
+
+}
+
+
+/*******************************************************************************
+**
+** Function gatt_process_handle_rsp
+**
+** Description This function is called to handle the write response
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void gatt_process_handle_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op_code, UINT16 len, UINT8 *p_data)
+{
+ UINT16 handle;
+ UINT8 * p= p_data;
+
+ STREAM_TO_UINT16(handle, p);
+ len -= 2;
+
+ if (op_code == GATT_RSP_WRITE)
+ gatt_end_operation(p_clcb, GATT_SUCCESS, NULL);
+}
+/*******************************************************************************
+**
+** Function gatt_process_mtu_rsp
+**
+** Description This function is called to process the configure MTU response.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void gatt_process_mtu_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT16 len, UINT8 *p_data)
+{
+ UINT16 mtu;
+
+ STREAM_TO_UINT16(mtu, p_data);
+
+ if (mtu < p_tcb->payload_size && mtu >= GATT_DEF_BLE_MTU_SIZE)
+ p_tcb->payload_size = mtu;
+
+ gatt_end_operation(p_clcb, p_clcb->status, NULL);
+}
+/*******************************************************************************
+**
+** Function gatt_cmd_to_rsp_code
+**
+** Description The function convert a ATT command op code into the corresponding
+** response code assume no error occurs.
+**
+** Returns response code.
+**
+*******************************************************************************/
+UINT8 gatt_cmd_to_rsp_code (UINT8 cmd_code)
+{
+ UINT8 rsp_code = 0;
+
+ if (cmd_code > 1 && cmd_code != GATT_CMD_WRITE)
+ {
+ rsp_code = cmd_code + 1;
+ }
+ return rsp_code;
+}
+/*******************************************************************************
+**
+** Function gatt_cl_send_next_cmd_inq
+**
+** Description Find next command in queue and sent to server
+**
+** Returns TRUE if command sent, otherwise FALSE.
+**
+*******************************************************************************/
+BOOLEAN gatt_cl_send_next_cmd_inq(tGATT_TCB *p_tcb)
+{
+ tGATT_CMD_Q *p_cmd = &p_tcb->cl_cmd_q[p_tcb->pending_cl_req];
+ BOOLEAN sent = FALSE;
+
+ while (!sent &&
+ p_tcb->pending_cl_req != p_tcb->next_slot_inq &&
+ p_cmd->to_send && p_cmd->p_cmd != NULL)
+ {
+ sent = attp_send_msg_to_L2CAP(p_tcb, p_cmd->p_cmd);
+
+ if (sent)
+ {
+ p_cmd->to_send = FALSE;
+ p_cmd->p_cmd = NULL;
+
+ gatt_start_rsp_timer (p_tcb);
+ }
+ else
+ {
+ GATT_TRACE_ERROR0("gatt_cl_send_next_cmd_inq: L2CAP sent error");
+
+ memset(p_cmd, 0, sizeof(tGATT_CMD_Q));
+ p_tcb->pending_cl_req ++;
+ p_cmd = &p_tcb->cl_cmd_q[p_tcb->pending_cl_req];
+ }
+ }
+ return sent;
+}
+
+/*******************************************************************************
+**
+** Function gatt_client_handle_server_rsp
+**
+** Description This function is called to handle the server response to
+** client.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void gatt_client_handle_server_rsp (tGATT_TCB *p_tcb, UINT8 op_code,
+ UINT16 len, UINT8 *p_data)
+{
+ tGATT_CLCB *p_clcb = NULL;
+ UINT8 rsp_code;
+
+ if (op_code != GATT_HANDLE_VALUE_IND && op_code != GATT_HANDLE_VALUE_NOTIF)
+ {
+ p_clcb = gatt_cmd_dequeue(p_tcb, &rsp_code);
+
+ rsp_code = gatt_cmd_to_rsp_code(rsp_code);
+
+ if (p_clcb == NULL || (rsp_code != op_code && op_code != GATT_RSP_ERROR))
+ {
+ GATT_TRACE_WARNING2 ("ATT - Ignore wrong response. Receives (%02x) \
+ Request(%02x) Ignored", op_code, rsp_code);
+
+ return;
+ }
+ else
+ btu_stop_timer (&p_tcb->rsp_timer_ent);
+ }
+ /* the size of the message may not be bigger than the local max PDU size*/
+ /* The message has to be smaller than the agreed MTU, len does not count op_code */
+ if (len >= p_tcb->payload_size)
+ {
+ GATT_TRACE_ERROR2("invalid response/indicate pkt size: %d, PDU size: %d", len + 1, p_tcb->payload_size);
+ if (op_code != GATT_HANDLE_VALUE_NOTIF &&
+ op_code != GATT_HANDLE_VALUE_IND)
+ gatt_end_operation(p_clcb, GATT_ERROR, NULL);
+ }
+ else
+ {
+ switch (op_code)
+ {
+ case GATT_RSP_ERROR:
+ gatt_process_error_rsp(p_tcb, p_clcb, op_code, len, p_data);
+ break;
+
+ case GATT_RSP_MTU: /* 2 bytes mtu */
+ gatt_process_mtu_rsp(p_tcb, p_clcb, len ,p_data);
+ break;
+
+ case GATT_RSP_FIND_INFO:
+ gatt_process_read_info_rsp(p_tcb, p_clcb, op_code, len, p_data);
+ break;
+
+ case GATT_RSP_READ_BY_TYPE:
+ case GATT_RSP_READ_BY_GRP_TYPE:
+ gatt_process_read_by_type_rsp(p_tcb, p_clcb, op_code, len, p_data);
+ break;
+
+ case GATT_RSP_READ:
+ case GATT_RSP_READ_BLOB:
+ case GATT_RSP_READ_MULTI:
+ gatt_process_read_rsp(p_tcb, p_clcb, op_code, len, p_data);
+ break;
+
+ case GATT_RSP_FIND_TYPE_VALUE: /* disc service with UUID */
+ gatt_process_find_type_value_rsp(p_tcb, p_clcb, len, p_data);
+ break;
+
+ case GATT_RSP_WRITE:
+ gatt_process_handle_rsp(p_tcb, p_clcb, op_code, len, p_data);
+ break;
+
+ case GATT_RSP_PREPARE_WRITE:
+ gatt_process_prep_write_rsp(p_tcb, p_clcb, op_code, len, p_data);
+ break;
+
+ case GATT_RSP_EXEC_WRITE:
+ gatt_end_operation(p_clcb, p_clcb->status, NULL);
+ break;
+
+ case GATT_HANDLE_VALUE_NOTIF:
+ case GATT_HANDLE_VALUE_IND:
+ gatt_process_notification(p_tcb, op_code, len, p_data);
+ break;
+
+ default:
+ GATT_TRACE_ERROR1("Unknown opcode = %d", op_code);
+ break;
+ }
+ }
+
+ if (op_code != GATT_HANDLE_VALUE_IND && op_code != GATT_HANDLE_VALUE_NOTIF)
+ {
+ gatt_cl_send_next_cmd_inq(p_tcb);
+ }
+
+ return;
+}
+
+#endif /* BLE_INCLUDED */
diff --git a/stack/gatt/gatt_db.c b/stack/gatt/gatt_db.c
new file mode 100644
index 0000000..68982bd
--- /dev/null
+++ b/stack/gatt/gatt_db.c
@@ -0,0 +1,1117 @@
+/*****************************************************************************
+**
+** Name: gatts_db.c
+**
+** Description: this file contains GATT database building and query
+** functions
+**
+** Copyright (c) 2009-2011, Broadcom Corp, All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+
+#include "bt_target.h"
+
+#if BLE_INCLUDED == TRUE
+
+#include "bt_trace.h"
+
+#include <stdio.h>
+#include <string.h>
+#include "gatt_int.h"
+#include "l2c_api.h"
+
+/********************************************************************************
+** L O C A L F U N C T I O N P R O T O T Y P E S *
+*********************************************************************************/
+static BOOLEAN allocate_svc_db_buf(tGATT_SVC_DB *p_db);
+static void *allocate_attr_in_db(tGATT_SVC_DB *p_db, UINT16 uuid16, UINT8 *p_uuid128, tGATT_PERM perm);
+static BOOLEAN deallocate_attr_in_db(tGATT_SVC_DB *p_db, void *p_attr);
+static BOOLEAN copy_extra_byte_in_db(tGATT_SVC_DB *p_db, void **p_dst, UINT16 len);
+
+static void gatts_db_add_service_declaration(tGATT_SVC_DB *p_db, tBT_UUID service, BOOLEAN is_pri);
+static tGATT_STATUS gatts_send_app_read_request(tGATT_TCB *p_tcb, UINT8 op_code,
+ UINT16 handle, UINT16 offset, UINT32 trans_id);
+
+/*******************************************************************************
+**
+** Function gatts_init_service_db
+**
+** Description This function initialize a memory space to be a service database.
+**
+** Parameter p_db: database pointer.
+** len: size of the memory space.
+**
+** Returns Status of te operation.
+**
+*******************************************************************************/
+BOOLEAN gatts_init_service_db (tGATT_SVC_DB *p_db, tBT_UUID service, BOOLEAN is_pri,
+ UINT16 s_hdl, UINT16 num_handle)
+{
+ if (!allocate_svc_db_buf(p_db))
+ {
+ GATT_TRACE_ERROR0("gatts_init_service_db failed, no resources");
+ return FALSE;
+ }
+
+ GATT_TRACE_DEBUG0("gatts_init_service_db");
+ GATT_TRACE_DEBUG2("s_hdl = %d num_handle = %d", s_hdl, num_handle );
+
+ /* update service database information */
+ p_db->next_handle = s_hdl;
+ p_db->end_handle = s_hdl + num_handle;
+
+ gatts_db_add_service_declaration(p_db, service, is_pri);
+
+ return TRUE;
+}
+
+/*******************************************************************************
+**
+** Function gatts_init_service_db
+**
+** Description This function initialize a memory space to be a service database.
+**
+** Parameter p_db: database pointer.
+** len: size of the memory space.
+**
+** Returns Status of te operation.
+**
+*******************************************************************************/
+tBT_UUID * gatts_get_service_uuid (tGATT_SVC_DB *p_db)
+{
+ if (!p_db || !p_db->p_attr_list)
+ {
+ GATT_TRACE_ERROR0("service DB empty");
+
+ return NULL;
+ }
+ else
+ {
+ return &((tGATT_ATTR16 *)p_db->p_attr_list)->p_value->uuid;
+ }
+}
+
+/*******************************************************************************
+**
+** Function gatts_check_attr_readability
+**
+** Description check attribute readability
+**
+** Returns status of operation.
+**
+*******************************************************************************/
+static tGATT_STATUS gatts_check_attr_readability(tGATT_ATTR16 *p_attr,
+ UINT16 offset,
+ BOOLEAN read_long,
+ tGATT_SEC_FLAG sec_flag,
+ UINT8 key_size)
+{
+ UINT16 min_key_size;
+ tGATT_PERM perm = p_attr->permission;
+
+ min_key_size = (((perm & GATT_ENCRYPT_KEY_SIZE_MASK) >> 12));
+ if (min_key_size != 0 )
+ {
+ min_key_size +=6;
+ }
+
+ if (!(perm & GATT_READ_ALLOWED))
+ {
+ GATT_TRACE_ERROR0( "GATT_READ_NOT_PERMIT");
+ return GATT_READ_NOT_PERMIT;
+ }
+
+ if ((perm & GATT_READ_AUTH_REQUIRED ) && !(sec_flag & GATT_SEC_FLAG_LKEY_UNAUTHED))
+ {
+ GATT_TRACE_ERROR0( "GATT_INSUF_AUTHENTICATION");
+ return GATT_INSUF_AUTHENTICATION;
+ }
+
+ if ((perm & GATT_READ_MITM_REQUIRED ) && !(sec_flag & GATT_SEC_FLAG_LKEY_AUTHED))
+ {
+ GATT_TRACE_ERROR0( "GATT_INSUF_AUTHENTICATION: MITM Required");
+ return GATT_INSUF_AUTHENTICATION;
+ }
+
+ if ((perm & GATT_READ_ENCRYPTED_REQUIRED ) && !(sec_flag & GATT_SEC_FLAG_ENCRYPTED))
+ {
+ GATT_TRACE_ERROR0( "GATT_INSUF_ENCRYPTION");
+ return GATT_INSUF_ENCRYPTION;
+ }
+
+ if ( (perm & GATT_READ_ENCRYPTED_REQUIRED) && (sec_flag & GATT_SEC_FLAG_ENCRYPTED) && (key_size < min_key_size))
+ {
+ GATT_TRACE_ERROR0( "GATT_INSUF_KEY_SIZE");
+ return GATT_INSUF_KEY_SIZE;
+ }
+
+
+ if (read_long)
+ {
+ switch (p_attr->uuid)
+ {
+ case GATT_UUID_PRI_SERVICE:
+ case GATT_UUID_SEC_SERVICE:
+ case GATT_UUID_CHAR_DECLARE:
+ case GATT_UUID_INCLUDE_SERVICE:
+ case GATT_UUID_CHAR_EXT_PROP:
+ case GATT_UUID_CHAR_CLIENT_CONFIG:
+ case GATT_UUID_CHAR_SRVR_CONFIG:
+ case GATT_UUID_CHAR_PRESENT_FORMAT:
+ GATT_TRACE_ERROR0("GATT_NOT_LONG");
+ return GATT_NOT_LONG;
+
+ default:
+ break;
+ }
+ }
+
+ return GATT_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function read_attr_value
+**
+** Description Utility function to read an attribute value.
+**
+** Parameter p_attr: pointer to the attribute to read.
+** offset: read offset.
+** p_value: output parameter to carry out the attribute value.
+** p_len: output parameter to carry out the attribute length.
+** read_long: this is a read blob request.
+** mtu: MTU
+** sec_flag: current link security status.
+** key_size: encryption key size.
+**
+** Returns status of operation.
+**
+*******************************************************************************/
+static tGATT_STATUS read_attr_value (void *p_attr,
+ UINT16 offset,
+ UINT8 **p_data,
+ BOOLEAN read_long,
+ UINT16 mtu,
+ UINT16 *p_len,
+ tGATT_SEC_FLAG sec_flag,
+ UINT8 key_size)
+{
+ UINT16 len = 0, uuid16 = 0;
+ UINT8 *p = *p_data;
+ tGATT_STATUS status;
+ UINT16 read_long_uuid=0;
+ tGATT_ATTR16 *p_attr16 = (tGATT_ATTR16 *)p_attr;
+
+ GATT_TRACE_DEBUG5("read_attr_value uuid=0x%04x perm=0x%0x sec_flag=0x%x offset=%d read_long=%d",
+ p_attr16->uuid,
+ p_attr16->permission,
+ sec_flag,
+ offset,
+ read_long);
+
+ status = gatts_check_attr_readability((tGATT_ATTR16 *)p_attr, offset, read_long, sec_flag, key_size);
+
+ if (p_attr16->uuid_type == GATT_ATTR_UUID_TYPE_16)
+ uuid16 = p_attr16->uuid;
+
+ if (status != GATT_SUCCESS)
+ return status;
+
+ status = GATT_NO_RESOURCES;
+
+ if (read_long &&
+ (uuid16 == GATT_UUID_CHAR_DESCRIPTION || uuid16 == GATT_UUID_CHAR_AGG_FORMAT))
+ {
+ read_long_uuid = p_attr16->uuid;
+ }
+
+ if (uuid16 == GATT_UUID_PRI_SERVICE || uuid16 == GATT_UUID_SEC_SERVICE)
+ {
+ len = p_attr16->p_value->uuid.len;
+ if (mtu >= p_attr16->p_value->uuid.len)
+ {
+ gatt_build_uuid_to_stream(&p, p_attr16->p_value->uuid);
+ status = GATT_SUCCESS;
+ }
+ }
+ else if (uuid16 == GATT_UUID_CHAR_DECLARE)
+ {
+ len = (((tGATT_ATTR16 *)(p_attr16->p_next))->uuid_type == GATT_ATTR_UUID_TYPE_16) ? 5 :19;
+
+ if (mtu >= len)
+ {
+ UINT8_TO_STREAM(p, p_attr16->p_value->char_decl.property);
+ UINT16_TO_STREAM(p, p_attr16->p_value->char_decl.char_val_handle);
+
+ if (((tGATT_ATTR16 *)(p_attr16->p_next))->uuid_type == GATT_ATTR_UUID_TYPE_16)
+ {
+ UINT16_TO_STREAM(p, ((tGATT_ATTR16 *)(p_attr16->p_next))->uuid);
+ }
+ else
+ {
+ ARRAY_TO_STREAM (p, ((tGATT_ATTR128 *)(p_attr16->p_next))->uuid, LEN_UUID_128);
+ }
+ status = GATT_SUCCESS;
+ }
+
+ }
+ else if (uuid16 == GATT_UUID_INCLUDE_SERVICE)
+ {
+ len = (p_attr16->p_value->incl_handle.service_type.len == 2) ? 6 : 4;
+ if (mtu >= len)
+ {
+ UINT16_TO_STREAM(p, p_attr16->p_value->incl_handle.s_handle);
+ UINT16_TO_STREAM(p, p_attr16->p_value->incl_handle.e_handle);
+
+ if (p_attr16->p_value->incl_handle.service_type.len == 2)
+ {
+ UINT16_TO_STREAM(p, p_attr16->p_value->incl_handle.service_type.uu.uuid16);
+ }
+ status = GATT_SUCCESS;
+ }
+ }
+ else /* characteristic description or characteristic value */
+ {
+ status = GATT_PENDING;
+ }
+
+ *p_len = len;
+ *p_data = p;
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function gatts_db_read_attr_value_by_type
+**
+** Description Query attribute value by attribute type.
+**
+** Parameter p_db: pointer to the attribute database.
+** p_rsp: Read By type response data.
+** s_handle: starting handle of the range we are looking for.
+** e_handle: ending handle of the range we are looking for.
+** type: Attribute type.
+** mtu: MTU.
+** sec_flag: current link security status.
+** key_size: encryption key size.
+**
+** Returns Status of the operation.
+**
+*******************************************************************************/
+tGATT_STATUS gatts_db_read_attr_value_by_type (tGATT_TCB *p_tcb,
+ tGATT_SVC_DB *p_db,
+ UINT8 op_code,
+ BT_HDR *p_rsp,
+ UINT16 s_handle,
+ UINT16 e_handle,
+ tBT_UUID type,
+ UINT16 *p_len,
+ tGATT_SEC_FLAG sec_flag,
+ UINT8 key_size,
+ UINT32 trans_id,
+ UINT16 *p_cur_handle)
+{
+ tGATT_STATUS status = GATT_NOT_FOUND;
+ tGATT_ATTR16 *p_attr;
+ UINT16 len = 0;
+ UINT8 *p = (UINT8 *)(p_rsp + 1) + p_rsp->len + L2CAP_MIN_OFFSET;
+ tBT_UUID attr_uuid;
+
+ if (p_db && p_db->p_attr_list)
+ {
+ p_attr = (tGATT_ATTR16 *)p_db->p_attr_list;
+
+ while (p_attr && p_attr->handle <= e_handle)
+ {
+ if (p_attr->uuid_type == GATT_ATTR_UUID_TYPE_16)
+ {
+ attr_uuid.len = LEN_UUID_16;
+ attr_uuid.uu.uuid16 = p_attr->uuid;
+ }
+ else
+ {
+ attr_uuid.len = LEN_UUID_128;
+ memcpy(attr_uuid.uu.uuid128, ((tGATT_ATTR128 *)p_attr)->uuid, LEN_UUID_128);
+ }
+
+ if (p_attr->handle >= s_handle && gatt_uuid_compare(type, attr_uuid))
+ {
+ if (*p_len <= 2)
+ {
+ status = GATT_NO_RESOURCES;
+ break;
+ }
+
+ UINT16_TO_STREAM (p, p_attr->handle);
+
+ status = read_attr_value ((void *)p_attr, 0, &p, FALSE, (UINT16)(*p_len -2), &len, sec_flag, key_size);
+
+ if (status == GATT_PENDING)
+ {
+ status = gatts_send_app_read_request(p_tcb, op_code, p_attr->handle, 0, trans_id);
+
+ /* one callback at a time */
+ break;
+ }
+ else if (status == GATT_SUCCESS)
+ {
+ if (p_rsp->offset == 0)
+ p_rsp->offset = len + 2;
+
+ if (p_rsp->offset == len + 2)
+ {
+ p_rsp->len += (len + 2);
+ *p_len -= (len + 2);
+ }
+ else
+ {
+ GATT_TRACE_ERROR0("format mismatch");
+ status = GATT_NO_RESOURCES;
+ break;
+ }
+ }
+ else
+ {
+ *p_cur_handle = p_attr->handle;
+ break;
+ }
+ }
+ p_attr = (tGATT_ATTR16 *)p_attr->p_next;
+ }
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function gatts_add_included_service
+**
+** Description This function adds an included service into a database.
+**
+** Parameter p_db: database pointer.
+** inc_srvc_type: included service type.
+**
+** Returns Status of the operation.
+**
+*******************************************************************************/
+UINT16 gatts_add_included_service (tGATT_SVC_DB *p_db, UINT16 s_handle, UINT16 e_handle,
+ tBT_UUID service)
+{
+ tGATT_ATTR16 *p_attr;
+
+ GATT_TRACE_DEBUG3("gatts_add_included_service: s_hdl = 0x%04x e_hdl = 0x%04x uuid = 0x%04x",
+ s_handle, e_handle, service.uu.uuid16);
+
+ if (service.len == 0 || s_handle == 0 || e_handle == 0)
+ {
+ GATT_TRACE_ERROR0("gatts_add_included_service Illegal Params.");
+ return 0;
+ }
+
+ if ((p_attr = (tGATT_ATTR16 *) allocate_attr_in_db(p_db, GATT_UUID_INCLUDE_SERVICE, NULL, GATT_PERM_READ)) != NULL)
+ {
+ if (copy_extra_byte_in_db(p_db, (void **)&p_attr->p_value, sizeof(tGATT_INCL_SRVC)))
+ {
+ p_attr->p_value->incl_handle.s_handle = s_handle;
+ p_attr->p_value->incl_handle.e_handle = e_handle;
+ memcpy(&p_attr->p_value->incl_handle.service_type, &service, sizeof(tBT_UUID));
+
+ return p_attr->handle;
+ }
+ else
+ {
+ deallocate_attr_in_db(p_db, p_attr);
+ }
+ }
+
+ return 0;
+}
+
+/*******************************************************************************
+**
+** Function gatts_add_characteristic
+**
+** Description This function add a characteristics and its descriptor into
+** a servce identified by the service database pointer.
+**
+** Parameter p_db: database pointer.
+** perm: permission (authentication and key size requirements)
+** property: property of the characteristic.
+** p_char: characteristic value information.
+**
+** Returns Status of te operation.
+**
+*******************************************************************************/
+UINT16 gatts_add_characteristic (tGATT_SVC_DB *p_db, tGATT_PERM perm,
+ tGATT_CHAR_PROP property,
+ tBT_UUID * p_char_uuid)
+{
+ tGATT_ATTR16 *p_char_decl, *p_char_val;
+ UINT16 uuid16 = (p_char_uuid->len == LEN_UUID_16) ? p_char_uuid->uu.uuid16 : 0;
+
+ GATT_TRACE_DEBUG2("gatts_add_characteristic perm=0x%0x property=0x%0x", perm, property);
+
+ if ((p_char_decl = (tGATT_ATTR16 *)allocate_attr_in_db(p_db, GATT_UUID_CHAR_DECLARE, NULL, GATT_PERM_READ)) != NULL)
+ {
+ if (!copy_extra_byte_in_db(p_db, (void **)&p_char_decl->p_value, sizeof(tGATT_CHAR_DECL)))
+ {
+ deallocate_attr_in_db(p_db, p_char_decl);
+ return 0;
+ }
+
+ p_char_val = (tGATT_ATTR16 *)allocate_attr_in_db(p_db, uuid16, p_char_uuid->uu.uuid128, perm);
+
+ if (p_char_val == NULL)
+ {
+ deallocate_attr_in_db(p_db, p_char_decl);
+ return 0;
+ }
+
+ p_char_decl->p_value->char_decl.property = property;
+ p_char_decl->p_value->char_decl.char_val_handle = p_char_val->handle;
+
+ p_char_val->p_value = NULL;
+
+ return p_char_val->handle;
+ }
+
+ return 0;
+}
+
+/*******************************************************************************
+**
+** Function gatt_convertchar_descr_type
+**
+** Description This function convert a char descript UUID into descriptor type.
+**
+** Returns descriptor type.
+**
+*******************************************************************************/
+UINT8 gatt_convertchar_descr_type(tBT_UUID *p_descr_uuid)
+{
+ tBT_UUID std_descr = {LEN_UUID_16, {GATT_UUID_CHAR_EXT_PROP}};
+
+ if (gatt_uuid_compare(std_descr, * p_descr_uuid))
+ return GATT_DESCR_EXT_DSCPTOR;
+
+ std_descr.uu.uuid16 ++;
+ if (gatt_uuid_compare(std_descr, * p_descr_uuid))
+ return GATT_DESCR_USER_DSCPTOR;
+
+ std_descr.uu.uuid16 ++;
+ if (gatt_uuid_compare(std_descr, * p_descr_uuid))
+ return GATT_DESCR_CLT_CONFIG;
+
+ std_descr.uu.uuid16 ++;
+ if (gatt_uuid_compare(std_descr, * p_descr_uuid))
+ return GATT_DESCR_SVR_CONFIG;
+
+ std_descr.uu.uuid16 ++;
+ if (gatt_uuid_compare(std_descr, * p_descr_uuid))
+ return GATT_DESCR_PRES_FORMAT;
+
+ std_descr.uu.uuid16 ++;
+ if (gatt_uuid_compare(std_descr, * p_descr_uuid))
+ return GATT_DESCR_AGGR_FORMAT;
+
+ std_descr.uu.uuid16 ++;
+ if (gatt_uuid_compare(std_descr, * p_descr_uuid))
+ return GATT_DESCR_VALID_RANGE;
+
+
+ return GATT_DESCR_UNKNOWN;
+}
+
+/*******************************************************************************
+**
+** Function gatts_add_char_descr
+**
+** Description This function add a characteristics descriptor.
+**
+** Parameter p_db: database pointer.
+** perm: characteristic descriptor permission type.
+** char_dscp_tpye: the characteristic descriptor masks.
+** p_dscp_params: characteristic descriptors values.
+**
+** Returns Status of the operation.
+**
+*******************************************************************************/
+UINT16 gatts_add_char_descr (tGATT_SVC_DB *p_db, tGATT_PERM perm,
+ tBT_UUID * p_descr_uuid)
+{
+ tGATT_ATTR16 *p_char_dscptr;
+ UINT16 uuid16 = (p_descr_uuid->len == LEN_UUID_16)? p_descr_uuid->uu.uuid16 : 0;
+
+ GATT_TRACE_DEBUG1("gatts_add_char_descr uuid=0x%04x", p_descr_uuid->uu.uuid16);
+
+ /* Add characteristic descriptors */
+ if ((p_char_dscptr = (tGATT_ATTR16 *)allocate_attr_in_db(p_db,
+ uuid16,
+ p_descr_uuid->uu.uuid128,
+ perm))
+ == NULL)
+ {
+ GATT_TRACE_DEBUG0("gatts_add_char_descr Fail for adding char descriptors.");
+ return 0;
+ }
+ else
+ {
+ return p_char_dscptr->handle;
+ }
+}
+
+/*******************************************************************************/
+/* Service Attribute Database Query Utility Functions */
+/*******************************************************************************/
+/*******************************************************************************
+**
+** Function gatts_read_attr_value_by_handle
+**
+** Description Query attribute value by attribute handle.
+**
+** Parameter p_db: pointer to the attribute database.
+** handle: Attribute handle to read.
+** offset: Read offset.
+** p_value: output parameter to carry out the attribute value.
+** p_len: output parameter as attribute length read.
+** read_long: this is a read blob request.
+** mtu: MTU.
+** sec_flag: current link security status.
+** key_size: encryption key size
+**
+** Returns Status of operation.
+**
+*******************************************************************************/
+tGATT_STATUS gatts_read_attr_value_by_handle(tGATT_TCB *p_tcb,
+ tGATT_SVC_DB *p_db,
+ UINT8 op_code,
+ UINT16 handle, UINT16 offset,
+ UINT8 *p_value, UINT16 *p_len,
+ UINT16 mtu,
+ tGATT_SEC_FLAG sec_flag,
+ UINT8 key_size,
+ UINT32 trans_id)
+{
+ tGATT_STATUS status = GATT_NOT_FOUND;
+ tGATT_ATTR16 *p_attr;
+ UINT8 *pp = p_value;
+
+ if (p_db && p_db->p_attr_list)
+ {
+ p_attr = (tGATT_ATTR16 *)p_db->p_attr_list;
+
+ while (p_attr && handle >= p_attr->handle)
+ {
+ if (p_attr->handle == handle)
+ {
+ status = read_attr_value (p_attr, offset, &pp,
+ (BOOLEAN)(op_code == GATT_REQ_READ_BLOB),
+ mtu, p_len, sec_flag, key_size);
+
+ if (status == GATT_PENDING)
+ {
+ status = gatts_send_app_read_request(p_tcb, op_code, p_attr->handle, offset, trans_id);
+ }
+ break;
+ }
+ p_attr = (tGATT_ATTR16 *)p_attr->p_next;
+ }
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function gatts_read_attr_perm_check
+**
+** Description Check attribute readability.
+**
+** Parameter p_db: pointer to the attribute database.
+** handle: Attribute handle to read.
+** offset: Read offset.
+** p_value: output parameter to carry out the attribute value.
+** p_len: output parameter as attribute length read.
+** read_long: this is a read blob request.
+** mtu: MTU.
+** sec_flag: current link security status.
+** key_size: encryption key size
+**
+** Returns Status of operation.
+**
+*******************************************************************************/
+tGATT_STATUS gatts_read_attr_perm_check(tGATT_SVC_DB *p_db,
+ BOOLEAN is_long,
+ UINT16 handle,
+ tGATT_SEC_FLAG sec_flag,
+ UINT8 key_size)
+{
+ tGATT_STATUS status = GATT_NOT_FOUND;
+ tGATT_ATTR16 *p_attr;
+
+ if (p_db && p_db->p_attr_list)
+ {
+ p_attr = (tGATT_ATTR16 *)p_db->p_attr_list;
+
+ while (p_attr && handle >= p_attr->handle)
+ {
+ if (p_attr->handle == handle)
+ {
+ status = gatts_check_attr_readability (p_attr, 0,
+ is_long,
+ sec_flag, key_size);
+ break;
+ }
+ p_attr = (tGATT_ATTR16 *) p_attr->p_next;
+ }
+ }
+
+ return status;
+}
+/*******************************************************************************
+**
+** Function gatts_write_attr_perm_check
+**
+** Description Write attribute value into database.
+**
+** Parameter p_db: pointer to the attribute database.
+** op_code:op code of this write.
+** handle: handle of the attribute to write.
+** offset: Write offset if write op code is write blob.
+** p_data: Attribute value to write.
+** len: attribute data length.
+** sec_flag: current link security status.
+** key_size: encryption key size
+**
+** Returns Status of the operation.
+**
+*******************************************************************************/
+tGATT_STATUS gatts_write_attr_perm_check (tGATT_SVC_DB *p_db, UINT8 op_code,
+ UINT16 handle, UINT16 offset, UINT8 *p_data,
+ UINT16 len, tGATT_SEC_FLAG sec_flag, UINT8 key_size)
+{
+ tGATT_STATUS status = GATT_NOT_FOUND;
+ tGATT_ATTR16 *p_attr;
+ UINT16 max_size = 0;
+ tGATT_PERM perm;
+ UINT16 min_key_size;
+
+ GATT_TRACE_DEBUG6( "gatts_write_attr_perm_check op_code=0x%0x handle=0x%04x offset=%d len=%d sec_flag=0x%0x key_size=%d",
+ op_code, handle, offset, len, sec_flag, key_size);
+
+ if (p_db != NULL)
+ {
+ p_attr = (tGATT_ATTR16 *) p_db->p_attr_list;
+
+ while (p_attr != NULL)
+ {
+ if (p_attr->handle == handle)
+ {
+ perm = p_attr->permission;
+ min_key_size = (((perm & GATT_ENCRYPT_KEY_SIZE_MASK) >> 12));
+ if (min_key_size != 0 )
+ {
+ min_key_size +=6;
+ }
+ GATT_TRACE_DEBUG2( "gatts_write_attr_perm_check p_attr->permission =0x%04x min_key_size==0x%04x",
+ p_attr->permission,
+ min_key_size);
+
+ if ((op_code == GATT_CMD_WRITE) && (perm & GATT_WRITE_SIGNED_PERM) )
+ {
+ /* use the rules for the mixed security see section 10.2.3*/
+ if (perm & GATT_PERM_WRITE_SIGNED)
+ {
+ perm = GATT_PERM_WRITE_ENCRYPTED;
+ }
+ else
+ {
+ perm = GATT_PERM_WRITE_ENC_MITM;
+ }
+ }
+
+ if ((op_code == GATT_SIGN_CMD_WRITE) && !(perm & GATT_WRITE_SIGNED_PERM))
+ {
+ status = GATT_WRITE_NOT_PERMIT;
+ GATT_TRACE_DEBUG0( "gatts_write_attr_perm_check - sign cmd write not allowed");
+ }
+ if ((op_code == GATT_SIGN_CMD_WRITE) && (sec_flag & GATT_SEC_FLAG_ENCRYPTED))
+ {
+ status = GATT_INVALID_PDU;
+ GATT_TRACE_ERROR0( "gatts_write_attr_perm_check - Error!! sign cmd write sent on a encypted link");
+ }
+ else if (!(perm & GATT_WRITE_ALLOWED))
+ {
+ status = GATT_WRITE_NOT_PERMIT;
+ GATT_TRACE_ERROR0( "gatts_write_attr_perm_check - GATT_WRITE_NOT_PERMIT");
+ }
+ else if ((perm & GATT_WRITE_AUTH_REQUIRED ) && !(sec_flag & GATT_SEC_FLAG_LKEY_UNAUTHED))
+ {
+ status = GATT_INSUF_AUTHENTICATION;
+ GATT_TRACE_ERROR0( "gatts_write_attr_perm_check - GATT_INSUF_AUTHENTICATION");
+ }
+ else if ((perm & GATT_WRITE_MITM_REQUIRED ) && !(sec_flag & GATT_SEC_FLAG_LKEY_AUTHED))
+ {
+ status = GATT_INSUF_AUTHENTICATION;
+ GATT_TRACE_ERROR0( "gatts_write_attr_perm_check - GATT_INSUF_AUTHENTICATION: MITM required");
+ }
+ else if ((perm & GATT_WRITE_ENCRYPTED_PERM ) && !(sec_flag & GATT_SEC_FLAG_ENCRYPTED))
+ {
+ status = GATT_INSUF_ENCRYPTION;
+ GATT_TRACE_ERROR0( "gatts_write_attr_perm_check - GATT_INSUF_ENCRYPTION");
+ }
+ else if ((perm & GATT_WRITE_ENCRYPTED_PERM ) && (sec_flag & GATT_SEC_FLAG_ENCRYPTED) && (key_size < min_key_size))
+ {
+ status = GATT_INSUF_KEY_SIZE;
+ GATT_TRACE_ERROR0( "gatts_write_attr_perm_check - GATT_INSUF_KEY_SIZE");
+ }
+ else /* writable: must be char value declaration or char descritpors */
+ {
+ if(p_attr->uuid_type == GATT_ATTR_UUID_TYPE_16)
+ {
+ switch (p_attr->uuid)
+ {
+ case GATT_UUID_CHAR_PRESENT_FORMAT:/* should be readable only */
+ case GATT_UUID_CHAR_EXT_PROP:/* should be readable only */
+ case GATT_UUID_CHAR_AGG_FORMAT: /* should be readable only */
+ case GATT_UUID_CHAR_VALID_RANGE:
+ status = GATT_WRITE_NOT_PERMIT;
+ break;
+
+ case GATT_UUID_CHAR_CLIENT_CONFIG:
+ case GATT_UUID_CHAR_SRVR_CONFIG:
+ max_size = 2;
+ case GATT_UUID_CHAR_DESCRIPTION:
+ default: /* any other must be character value declaration */
+ status = GATT_SUCCESS;
+ break;
+ }
+ }
+ else if (p_attr->uuid_type == GATT_ATTR_UUID_TYPE_128)
+ {
+ status = GATT_SUCCESS;
+ }
+ else
+ {
+ status = GATT_INVALID_PDU;
+ }
+
+ if (p_data == NULL && len > 0)
+ {
+ status = GATT_INVALID_PDU;
+ }
+ /* these attribute does not allow write blob */
+// btla-specific ++
+ else if ( (p_attr->uuid_type == GATT_ATTR_UUID_TYPE_16) &&
+ (p_attr->uuid == GATT_UUID_CHAR_CLIENT_CONFIG ||
+ p_attr->uuid == GATT_UUID_CHAR_SRVR_CONFIG) )
+// btla-specific --
+ {
+ if (op_code == GATT_REQ_PREPARE_WRITE && offset != 0) /* does not allow write blob */
+ {
+ status = GATT_NOT_LONG;
+ GATT_TRACE_ERROR0( "gatts_write_attr_perm_check - GATT_NOT_LONG");
+ }
+ else if (len != max_size) /* data does not match the required format */
+ {
+ status = GATT_INVALID_PDU;
+ GATT_TRACE_ERROR0( "gatts_write_attr_perm_check - GATT_INVALID_PDU");
+ }
+ else
+ {
+ status = GATT_SUCCESS;
+ }
+ }
+ }
+ break;
+ }
+ else
+ p_attr = (tGATT_ATTR16 *)p_attr->p_next;
+ }
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function allocate_attr_in_db
+**
+** Description Allocate a memory space for a new attribute, and link this
+** attribute into the database attribute list.
+**
+**
+** Parameter p_db : database pointer.
+** service : type of attribute to be added.
+**
+** Returns pointer to the newly allocated attribute.
+**
+*******************************************************************************/
+static void *allocate_attr_in_db(tGATT_SVC_DB *p_db, UINT16 uuid16, UINT8 *uuid128, tGATT_PERM perm)
+{
+ tGATT_ATTR16 *p_attr16 = NULL, *p_last;
+ tGATT_ATTR128 *p_attr128 = NULL;
+ UINT16 len = (uuid16 == 0) ? sizeof(tGATT_ATTR128): sizeof(tGATT_ATTR16);
+
+ GATT_TRACE_DEBUG1("allocate attr %d bytes ",len);
+
+ if (uuid16 == GATT_ILLEGAL_UUID && uuid128 == NULL)
+ {
+ GATT_TRACE_ERROR0("illegal UUID");
+ return NULL;
+ }
+
+ if (p_db->end_handle <= p_db->next_handle)
+ {
+ GATT_TRACE_DEBUG2("handle space full. handle_max = %d next_handle = %d",
+ p_db->end_handle, p_db->next_handle);
+ return NULL;
+ }
+
+ if (p_db->mem_free < len)
+ {
+ if (!allocate_svc_db_buf(p_db))
+ {
+ GATT_TRACE_ERROR0("allocate_attr_in_db failed, no resources");
+ return NULL;
+ }
+ }
+
+ p_attr16 = (tGATT_ATTR16 *) p_db->p_free_mem;
+ p_attr128 = (tGATT_ATTR128 *) p_db->p_free_mem;
+
+ memset(p_attr16, 0, len);
+
+ if (uuid16 != GATT_ILLEGAL_UUID)
+ {
+ p_attr16->uuid_type = GATT_ATTR_UUID_TYPE_16;
+ p_attr16->uuid = uuid16;
+ }
+ else
+ {
+ p_attr128->uuid_type = GATT_ATTR_UUID_TYPE_128;
+ memcpy(p_attr128->uuid, uuid128, LEN_UUID_128);
+ }
+
+ p_db->p_free_mem += len;
+ p_db->mem_free -= len;
+
+ p_attr16->handle = p_db->next_handle++;
+ p_attr16->permission = perm;
+ p_attr16->p_next = NULL;
+
+ /* link the attribute record into the end of DB */
+ if (p_db->p_attr_list == NULL)
+ p_db->p_attr_list = p_attr16;
+ else
+ {
+ p_last = (tGATT_ATTR16 *)p_db->p_attr_list;
+
+ while (p_last != NULL && p_last->p_next != NULL)
+ p_last = (tGATT_ATTR16 *)p_last->p_next;
+
+ p_last->p_next = p_attr16;
+ }
+
+ if (p_attr16->uuid_type == GATT_ATTR_UUID_TYPE_16)
+ {
+ GATT_TRACE_DEBUG3("=====> handle = [0x%04x] uuid = [0x%04x] perm=0x%02x ",
+ p_attr16->handle, p_attr16->uuid, p_attr16->permission);
+ }
+ else
+ {
+ GATT_TRACE_DEBUG4("=====> handle = [0x%04x] uuid128 = [0x%02x:0x%02x] perm=0x%02x ",
+ p_attr128->handle, p_attr128->uuid[0],p_attr128->uuid[1],
+ p_attr128->permission);
+ }
+ return(void *)p_attr16;
+}
+
+/*******************************************************************************
+**
+** Function deallocate_attr_in_db
+**
+** Description Free an attribute within the database.
+**
+** Parameter p_db: database pointer.
+** p_attr: pointer to the attribute record to be freed.
+**
+** Returns BOOLEAN: success
+**
+*******************************************************************************/
+static BOOLEAN deallocate_attr_in_db(tGATT_SVC_DB *p_db, void *p_attr)
+{
+ tGATT_ATTR16 *p_cur, *p_next;
+ BOOLEAN found = FALSE;
+
+ if (p_db->p_attr_list == NULL)
+ return found;
+
+ p_cur = (tGATT_ATTR16 *) p_db->p_attr_list;
+ p_next = (tGATT_ATTR16 *) p_cur->p_next;
+
+ for (; p_cur != NULL && p_next != NULL;
+ p_cur = p_next, p_next = (tGATT_ATTR16 *)p_next->p_next)
+ {
+ if (p_next == p_attr)
+ {
+ p_cur->p_next = p_next->p_next;
+ found = TRUE;
+ }
+ }
+ if (p_cur == p_attr && p_cur == p_db->p_attr_list)
+ {
+ p_db->p_attr_list = p_cur->p_next;
+ found = TRUE;
+ }
+ /* else attr not found */
+ if ( found)
+ p_db->next_handle --;
+
+ return found;
+}
+
+/*******************************************************************************
+**
+** Function copy_extra_byte_in_db
+**
+** Description Utility function to allocate extra bytes memory in DB and copy
+** the value from a source place.
+**
+**
+** Parameter p_db: database pointer.
+** p_dst: destination data pointer.
+** p_src: source data pointer.
+** len: data length to be copied.
+**
+** Returns None.
+**
+*******************************************************************************/
+static BOOLEAN copy_extra_byte_in_db(tGATT_SVC_DB *p_db, void **p_dst, UINT16 len)
+{
+ UINT8 *p = (UINT8 *)*p_dst;
+
+ if (p_db->mem_free < len)
+ {
+ if (!allocate_svc_db_buf(p_db))
+ {
+ GATT_TRACE_ERROR0("copy_extra_byte_in_db failed, no resources");
+ return FALSE;
+ }
+ }
+
+ p = p_db->p_free_mem;
+ p_db->p_free_mem += len;
+ p_db->mem_free -= len;
+ memset((void *)p, 0, len);
+ *p_dst = (void *)p;
+
+ return TRUE;
+}
+
+/*******************************************************************************
+**
+** Function allocate_svc_db_buf
+**
+** Description Utility function to allocate extra buffer for service database.
+**
+** Returns TRUE if allocation succeed, otherwise FALSE.
+**
+*******************************************************************************/
+static BOOLEAN allocate_svc_db_buf(tGATT_SVC_DB *p_db)
+{
+ BT_HDR *p_buf;
+
+ GATT_TRACE_DEBUG0("allocate_svc_db_buf allocating extra buffer");
+
+ if ((p_buf = (BT_HDR *)GKI_getpoolbuf(GATT_DB_POOL_ID)) == NULL)
+ {
+ GATT_TRACE_ERROR0("allocate_svc_db_buf failed, no resources");
+ return FALSE;
+ }
+
+ memset(p_buf, 0, GKI_get_buf_size(p_buf));
+ p_db->p_free_mem = (UINT8 *) p_buf;
+ p_db->mem_free = GKI_get_buf_size(p_buf);
+
+ GKI_enqueue(&p_db->svc_buffer, p_buf);
+
+ return TRUE;
+
+}
+
+/*******************************************************************************
+**
+** Function gatts_send_app_read_request
+**
+** Description Send application read request callback
+**
+** Returns status of operation.
+**
+*******************************************************************************/
+static tGATT_STATUS gatts_send_app_read_request(tGATT_TCB *p_tcb, UINT8 op_code,
+ UINT16 handle, UINT16 offset, UINT32 trans_id)
+{
+ tGATTS_DATA sr_data;
+ UINT8 i_rcb;
+ tGATT_SR_REG *p_sreg;
+ UINT16 conn_id;
+
+ i_rcb = gatt_sr_find_i_rcb_by_handle(handle);
+ p_sreg = &gatt_cb.sr_reg[i_rcb];
+ conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_sreg->gatt_if);
+
+ if (trans_id == 0)
+ {
+ trans_id = gatt_sr_enqueue_cmd(p_tcb, op_code, handle);
+ gatt_sr_update_cback_cnt(p_tcb, p_sreg->gatt_if, TRUE, TRUE);
+ }
+
+ if (trans_id != 0 )
+ {
+ memset(&sr_data, 0, sizeof(tGATTS_DATA));
+
+ sr_data.read_req.handle = handle;
+ sr_data.read_req.is_long = (BOOLEAN)(op_code == GATT_REQ_READ_BLOB);
+ sr_data.read_req.offset = offset;
+
+ gatt_sr_send_req_callback(conn_id,
+ trans_id, GATTS_REQ_TYPE_READ, &sr_data);
+ return(tGATT_STATUS) GATT_PENDING;
+ }
+ else
+ return(tGATT_STATUS) GATT_BUSY; /* max pending command, application error */
+
+}
+
+/*******************************************************************************
+**
+** Function gatts_db_add_service_declaration
+**
+** Description Update a service database service declaration record.
+**
+** Parameter p_db: database pointer.
+** service: UUID of the service.
+**
+** Returns void
+**
+*******************************************************************************/
+static void gatts_db_add_service_declaration(tGATT_SVC_DB *p_db, tBT_UUID service, BOOLEAN is_pri)
+{
+ tGATT_ATTR16 *p_attr;
+ UINT16 service_type = is_pri ? GATT_UUID_PRI_SERVICE: GATT_UUID_SEC_SERVICE;
+
+ GATT_TRACE_DEBUG0( "add_service_declaration");
+
+ /* add service declration record */
+ if ((p_attr = (tGATT_ATTR16 *)(allocate_attr_in_db(p_db, service_type, NULL, GATT_PERM_READ))) != NULL)
+ {
+ if (copy_extra_byte_in_db (p_db, (void **)&p_attr->p_value, sizeof(tBT_UUID)))
+ {
+ memcpy (&p_attr->p_value->uuid, &service, sizeof(tBT_UUID));
+ }
+ }
+}
+
+#endif /* BLE_INCLUDED */
diff --git a/stack/gatt/gatt_int.h b/stack/gatt/gatt_int.h
new file mode 100644
index 0000000..7c7fb89
--- /dev/null
+++ b/stack/gatt/gatt_int.h
@@ -0,0 +1,664 @@
+/****************************************************************************
+**
+** Name: gatt_int.h
+**
+** Function this file contains internally used GATT profile
+**
+** Copyright (c) 1999-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+******************************************************************************/
+
+#ifndef GATT_INT_H
+#define GATT_INT_H
+
+#include "bt_target.h"
+
+#if BLE_INCLUDED == TRUE
+
+
+#include "bt_trace.h"
+#include "gatt_api.h"
+#include "btm_ble_api.h"
+#include "btu.h"
+
+#include <string.h>
+
+
+#define GATT_CREATE_CONN_ID(tcb_idx, gatt_if) ((UINT16) ((((UINT8)(tcb_idx) ) << 8) | ((UINT8) (gatt_if))))
+#define GATT_GET_TCB_IDX(conn_id) ((UINT8) (((UINT16) (conn_id)) >> 8))
+#define GATT_GET_GATT_IF(conn_id) ((tGATT_IF)((UINT8) (conn_id)))
+
+#define GATT_GET_SR_REG_PTR(index) (&gatt_cb.sr_reg[(UINT8) (index)]);
+#define GATT_TRANS_ID_MAX 0x0fffffff /* 4 MSB is reserved */
+
+/* security action for GATT write and read request */
+#define GATT_SEC_NONE 0
+#define GATT_SEC_OK 1
+#define GATT_SEC_ENCRYPT 2 /* encrypt the link with current key */
+#define GATT_SEC_ENCRYPT_NO_MITM 3 /* unauthenticated encryption or better */
+#define GATT_SEC_ENCRYPT_MITM 4 /* authenticated encryption */
+#define GATT_SEC_SIGN_DATA 5 /* compute the signature for the write cmd */
+typedef UINT8 tGATT_SEC_ACTION;
+
+
+#define GATT_ATTR_OP_SPT_MTU (0x00000001 << 0)
+#define GATT_ATTR_OP_SPT_FIND_INFO (0x00000001 << 1)
+#define GATT_ATTR_OP_SPT_FIND_BY_TYPE (0x00000001 << 2)
+#define GATT_ATTR_OP_SPT_READ_BY_TYPE (0x00000001 << 3)
+#define GATT_ATTR_OP_SPT_READ (0x00000001 << 4)
+#define GATT_ATTR_OP_SPT_MULT_READ (0x00000001 << 5)
+#define GATT_ATTR_OP_SPT_READ_BLOB (0x00000001 << 6)
+#define GATT_ATTR_OP_SPT_READ_BY_GRP_TYPE (0x00000001 << 7)
+#define GATT_ATTR_OP_SPT_WRITE (0x00000001 << 8)
+#define GATT_ATTR_OP_SPT_WRITE_CMD (0x00000001 << 9)
+#define GATT_ATTR_OP_SPT_PREP_WRITE (0x00000001 << 10)
+#define GATT_ATTR_OP_SPT_EXE_WRITE (0x00000001 << 11)
+#define GATT_ATTR_OP_SPT_HDL_VALUE_CONF (0x00000001 << 12)
+#define GATT_ATTR_OP_SP_SIGN_WRITE (0x00000001 << 13)
+
+#define GATT_INDEX_INVALID 0xff
+
+#define GATT_PENDING_REQ_NONE 0
+
+
+#define GATT_WRITE_CMD_MASK 0xc0 /*0x1100-0000*/
+#define GATT_AUTH_SIGN_MASK 0x80 /*0x1000-0000*/
+#define GATT_AUTH_SIGN_LEN 12
+
+#define GATT_HDR_SIZE 3 /* 1B opcode + 2B handle */
+
+/* wait for ATT cmd response timeout value */
+#define GATT_WAIT_FOR_RSP_TOUT 30
+
+/* characteristic descriptor type */
+#define GATT_DESCR_EXT_DSCPTOR 1 /* Characteristic Extended Properties */
+#define GATT_DESCR_USER_DSCPTOR 2 /* Characteristic User Description */
+#define GATT_DESCR_CLT_CONFIG 3 /* Client Characteristic Configuration */
+#define GATT_DESCR_SVR_CONFIG 4 /* Server Characteristic Configuration */
+#define GATT_DESCR_PRES_FORMAT 5 /* Characteristic Presentation Format */
+#define GATT_DESCR_AGGR_FORMAT 6 /* Characteristic Aggregate Format */
+#define GATT_DESCR_VALID_RANGE 7 /* Characteristic Valid Range */
+#define GATT_DESCR_UNKNOWN 0xff
+
+#define GATT_SEC_FLAG_LKEY_UNAUTHED BTM_SEC_FLAG_LKEY_KNOWN
+#define GATT_SEC_FLAG_LKEY_AUTHED BTM_SEC_FLAG_LKEY_AUTHED
+#define GATT_SEC_FLAG_ENCRYPTED BTM_SEC_FLAG_ENCRYPTED
+typedef UINT8 tGATT_SEC_FLAG;
+
+/* Find Information Response Type
+*/
+#define GATT_INFO_TYPE_PAIR_16 0x01
+#define GATT_INFO_TYPE_PAIR_128 0x02
+
+/* GATT client FIND_TYPE_VALUE_Request data */
+typedef struct
+{
+ tBT_UUID uuid; /* type of attribute to be found */
+ UINT16 s_handle; /* starting handle */
+ UINT16 e_handle; /* ending handle */
+ UINT16 value_len; /* length of the attribute value */
+ UINT8 value[GATT_MAX_MTU_SIZE]; /* pointer to the attribute value to be found */
+} tGATT_FIND_TYPE_VALUE;
+
+/* client request message to ATT protocol
+*/
+typedef union
+{
+ tGATT_READ_BY_TYPE browse; /* read by type request */
+ tGATT_FIND_TYPE_VALUE find_type_value;/* find by type value */
+ tGATT_READ_MULTI read_multi; /* read multiple request */
+ tGATT_READ_PARTIAL read_blob; /* read blob */
+ tGATT_VALUE attr_value; /* write request */
+ /* prepare write */
+ /* write blob */
+ UINT16 handle; /* read, handle value confirmation */
+ UINT16 mtu;
+ tGATT_EXEC_FLAG exec_write; /* execute write */
+}tGATT_CL_MSG;
+
+/* error response strucutre */
+typedef struct
+{
+ UINT16 handle;
+ UINT8 cmd_code;
+ UINT8 reason;
+}tGATT_ERROR;
+
+/* server response message to ATT protocol
+*/
+typedef union
+{
+ /* data type member event */
+ tGATT_VALUE attr_value; /* READ, HANDLE_VALUE_IND, PREPARE_WRITE */
+ /* READ_BLOB, READ_BY_TYPE */
+ tGATT_ERROR error; /* ERROR_RSP */
+ UINT16 handle; /* WRITE, WRITE_BLOB */
+ UINT16 mtu; /* exchange MTU request */
+} tGATT_SR_MSG;
+
+/* Characteristic declaration attribute value
+*/
+typedef struct
+{
+ tGATT_CHAR_PROP property;
+ UINT16 char_val_handle;
+} tGATT_CHAR_DECL;
+
+/* attribute value maintained in the server database
+*/
+typedef union
+{
+ tBT_UUID uuid; /* service declaration */
+ tGATT_CHAR_DECL char_decl; /* characteristic declaration */
+ tGATT_INCL_SRVC incl_handle; /* included service */
+
+} tGATT_ATTR_VALUE;
+
+/* Attribute UUID type
+*/
+#define GATT_ATTR_UUID_TYPE_16 0
+#define GATT_ATTR_UUID_TYPE_128 1
+typedef UINT8 tGATT_ATTR_UUID_TYPE;
+
+/* 16 bits UUID Attribute in server database
+*/
+typedef struct
+{
+ void *p_next; /* pointer to the next attribute,
+ either tGATT_ATTR16 or tGATT_ATTR128 */
+ tGATT_ATTR_VALUE *p_value;
+ tGATT_ATTR_UUID_TYPE uuid_type;
+ tGATT_PERM permission;
+ UINT16 handle;
+ UINT16 uuid;
+} tGATT_ATTR16;
+
+/* 128 bits UUID Attribute in server database
+*/
+typedef struct
+{
+ void *p_next; /* pointer to the next attribute,
+ either tGATT_ATTR16 or tGATT_ATTR128 */
+ tGATT_ATTR_VALUE *p_value;
+ tGATT_ATTR_UUID_TYPE uuid_type;
+ tGATT_PERM permission;
+ UINT16 handle;
+ UINT8 uuid[LEN_UUID_128];
+} tGATT_ATTR128;
+
+/* Service Database definition
+*/
+typedef struct
+{
+ void *p_attr_list; /* pointer to the first attribute,
+ either tGATT_ATTR16 or tGATT_ATTR128 */
+ UINT8 *p_free_mem; /* Pointer to free memory */
+ BUFFER_Q svc_buffer; /* buffer queue used for service database */
+ UINT32 mem_free; /* Memory still available */
+ UINT16 end_handle; /* Last handle number */
+ UINT16 next_handle; /* Next usable handle value */
+} tGATT_SVC_DB;
+
+/* Data Structure used for GATT server */
+/* A GATT registration record consists of a handle, and 1 or more attributes */
+/* A service registration information record consists of beginning and ending */
+/* attribute handle, service UUID and a set of GATT server callback. */
+typedef struct
+{
+ tGATT_SVC_DB *p_db; /* pointer to the service database */
+ //tGATT_SR_CBACK sr_cb; /* server callback functions */
+ tBT_UUID app_uuid; /* applicatino UUID */
+ UINT32 sdp_handle; /* primamry service SDP handle */
+ UINT16 service_instance; /* service instance number */
+ UINT16 type; /* service type UUID, primary or secondary */
+ UINT16 s_hdl; /* service starting handle */
+ UINT16 e_hdl; /* service ending handle */
+ tGATT_IF gatt_if; /* this service is belong to which application */
+ BOOLEAN in_use;
+} tGATT_SR_REG;
+
+
+/* Data Structure used for GATT server */
+/* An GATT registration record consists of a handle, and 1 or more attributes */
+/* A service registration information record consists of beginning and ending */
+/* attribute handle, service UUID and a set of GATT server callback. */
+
+typedef struct
+{
+ tBT_UUID app_uuid128;
+ tGATT_CBACK app_cb;
+ tGATT_IF gatt_if; /* one based */
+ BOOLEAN in_use;
+} tGATT_REG;
+
+
+
+
+/* command queue for each connection */
+typedef struct
+{
+ BT_HDR *p_cmd;
+ UINT16 clcb_idx;
+ UINT8 op_code;
+ BOOLEAN to_send;
+}tGATT_CMD_Q;
+
+
+#if GATT_MAX_SR_PROFILES <= 8
+typedef UINT8 tGATT_APP_MASK;
+#elif GATT_MAX_SR_PROFILES <= 16
+typedef UINT16 tGATT_APP_MASK;
+#elif GATT_MAX_SR_PROFILES <= 32
+typedef UINT32 tGATT_APP_MASK;
+#endif
+
+/* command details for each connection */
+typedef struct
+{
+ BT_HDR *p_rsp_msg;
+ UINT32 trans_id;
+ tGATT_READ_MULTI multi_req;
+ BUFFER_Q multi_rsp_q;
+ UINT16 handle;
+ UINT8 op_code;
+ UINT8 status;
+ UINT8 cback_cnt[GATT_MAX_APPS];
+} tGATT_SR_CMD;
+
+#define GATT_CH_CLOSE 0
+#define GATT_CH_CLOSING 1
+#define GATT_CH_CONN 2
+#define GATT_CH_CFG 3
+#define GATT_CH_OPEN 4
+#define GATT_CH_W4_SEC_COMP 5
+#define GATT_CH_W4_DATA_SIGN_COMP 6
+
+typedef UINT8 tGATT_CH_STATE;
+
+#define GATT_GATT_START_HANDLE 1
+#define GATT_GAP_START_HANDLE 20
+#define GATT_APP_START_HANDLE 40
+
+typedef struct hdl_cfg
+{
+ UINT16 gatt_start_hdl;
+ UINT16 gap_start_hdl;
+ UINT16 app_start_hdl;
+}tGATT_HDL_CFG;
+
+typedef struct hdl_list_elem
+{
+ struct hdl_list_elem *p_next;
+ struct hdl_list_elem *p_prev;
+ tGATTS_HNDL_RANGE asgn_range; /* assigned handle range */
+ tGATT_SVC_DB svc_db;
+ BOOLEAN in_use;
+}tGATT_HDL_LIST_ELEM;
+
+typedef struct
+{
+ tGATT_HDL_LIST_ELEM *p_first;
+ tGATT_HDL_LIST_ELEM *p_last;
+ UINT16 count;
+}tGATT_HDL_LIST_INFO;
+
+
+typedef struct srv_list_elem
+{
+ struct srv_list_elem *p_next;
+ struct srv_list_elem *p_prev;
+ UINT16 s_hdl;
+ UINT8 i_sreg;
+ BOOLEAN in_use;
+ BOOLEAN is_primary;
+}tGATT_SRV_LIST_ELEM;
+
+
+typedef struct
+{
+ tGATT_SRV_LIST_ELEM *p_last_primary;
+ tGATT_SRV_LIST_ELEM *p_first;
+ tGATT_SRV_LIST_ELEM *p_last;
+ UINT16 count;
+}tGATT_SRV_LIST_INFO;
+
+typedef struct
+{
+ void *p_clcb; /* which clcb is doing encryption */
+ tGATT_SEC_ACTION sec_act;
+ BD_ADDR peer_bda;
+ UINT32 trans_id;
+
+ UINT16 att_lcid; /* L2CAP channel ID for ATT */
+ UINT16 payload_size;
+
+ tGATT_CH_STATE ch_state;
+ UINT8 ch_flags;
+
+ tGATT_IF app_hold_link[GATT_MAX_APPS];
+
+ /* server needs */
+ /* server response data */
+ tGATT_SR_CMD sr_cmd;
+ UINT16 indicate_handle;
+ BUFFER_Q pending_ind_q;
+
+ TIMER_LIST_ENT conf_timer_ent; /* peer confirm to indication timer */
+
+ UINT8 prep_cnt[GATT_MAX_APPS];
+ UINT8 ind_count;
+
+ tGATT_CMD_Q cl_cmd_q[GATT_CL_MAX_LCB];
+ TIMER_LIST_ENT rsp_timer_ent; /* peer response timer */
+ TIMER_LIST_ENT ind_ack_timer_ent; /* local app confirm to indication timer */
+ UINT8 pending_cl_req;
+ UINT8 next_slot_inq; /* index of next available slot in queue */
+
+ BOOLEAN in_use;
+ UINT8 tcb_idx;
+} tGATT_TCB;
+
+/* logic channel */
+typedef struct
+{
+ UINT16 next_disc_start_hdl; /* starting handle for the next inc srvv discovery */
+ tGATT_DISC_RES result;
+ BOOLEAN wait_for_read_rsp;
+} tGATT_READ_INC_UUID128;
+typedef struct
+{
+ tGATT_TCB *p_tcb; /* associated TCB of this CLCB */
+ tGATT_REG *p_reg; /* owner of this CLCB */
+ UINT8 sccb_idx;
+ UINT8 *p_attr_buf; /* attribute buffer for read multiple, prepare write */
+ tBT_UUID uuid;
+ UINT16 conn_id; /* connection handle */
+ UINT16 clcb_idx;
+ UINT16 s_handle; /* starting handle of the active request */
+ UINT16 e_handle; /* ending handle of the active request */
+ UINT16 counter; /* used as offset, attribute length, num of prepare write */
+ UINT16 start_offset;
+ tGATT_AUTH_REQ auth_req; /* authentication requirement */
+ UINT8 operation; /* one logic channel can have one operation active */
+ UINT8 op_subtype; /* operation subtype */
+ UINT8 status; /* operation status */
+ BOOLEAN first_read_blob_after_read;
+ tGATT_READ_INC_UUID128 read_uuid128;
+ BOOLEAN in_use;
+} tGATT_CLCB;
+
+#define GATT_SIGN_WRITE 1
+#define GATT_VERIFY_SIGN_DATA 2
+
+typedef struct
+{
+ BT_HDR hdr;
+ tGATT_CLCB *p_clcb;
+}tGATT_SIGN_WRITE_OP;
+
+typedef struct
+{
+ BT_HDR hdr;
+ tGATT_TCB *p_tcb;
+ BT_HDR *p_data;
+
+}tGATT_VERIFY_SIGN_OP;
+
+
+typedef struct
+{
+ UINT16 clcb_idx;
+ BOOLEAN in_use;
+} tGATT_SCCB;
+
+typedef struct
+{
+ UINT16 handle;
+ UINT16 uuid;
+ UINT32 service_change;
+}tGATT_SVC_CHG;
+
+typedef struct
+{
+ tGATT_IF gatt_if[GATT_MAX_APPS];
+ BD_ADDR remote_bda;
+ BOOLEAN in_use;
+}tGATT_BG_CONN_DEV;
+
+
+typedef struct
+{
+ UINT16 conn_id;
+ BOOLEAN in_use;
+ BOOLEAN connected;
+ BD_ADDR bda;
+}tGATT_PROFILE_CLCB;
+
+typedef struct
+{
+ tGATT_TCB tcb[GATT_MAX_PHY_CHANNEL];
+ BUFFER_Q sign_op_queue;
+
+ tGATT_SR_REG sr_reg[GATT_MAX_SR_PROFILES];
+ UINT16 next_handle; /* next available handle */
+ tGATT_SVC_CHG gattp_attr; /* GATT profile attribute service change */
+ tGATT_IF gatt_if;
+ tGATT_HDL_LIST_INFO hdl_list_info;
+ tGATT_HDL_LIST_ELEM hdl_list[GATT_MAX_SR_PROFILES];
+ tGATT_SRV_LIST_INFO srv_list_info;
+ tGATT_SRV_LIST_ELEM srv_list[GATT_MAX_SR_PROFILES];
+
+ BUFFER_Q srv_chg_clt_q; /* service change clients queue */
+ BUFFER_Q pending_new_srv_start_q; /* pending new service start queue */
+ tGATT_REG cl_rcb[GATT_MAX_APPS];
+ tGATT_CLCB clcb[GATT_CL_MAX_LCB]; /* connection link control block*/
+ tGATT_SCCB sccb[GATT_MAX_SCCB]; /* sign complete callback function GATT_MAX_SCCB <= GATT_CL_MAX_LCB */
+ UINT8 trace_level;
+ UINT16 def_mtu_size;
+
+#if GATT_CONFORMANCE_TESTING == TRUE
+ BOOLEAN enable_err_rsp;
+ UINT8 req_op_code;
+ UINT8 err_status;
+#endif
+
+ tGATT_PROFILE_CLCB profile_clcb[GATT_MAX_APPS];
+ UINT16 handle_of_h_r; /* Handle of the handles reused characteristic value */
+
+ tGATT_APPL_INFO cb_info;
+
+
+
+ tGATT_HDL_CFG hdl_cfg;
+ tGATT_BG_CONN_DEV bgconn_dev[GATT_MAX_BG_CONN_DEV];
+
+} tGATT_CB;
+
+
+#define GATT_SIZE_OF_SRV_CHG_HNDL_RANGE 4
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Global GATT data */
+#if GATT_DYNAMIC_MEMORY == FALSE
+GATT_API extern tGATT_CB gatt_cb;
+#else
+GATT_API extern tGATT_CB *gatt_cb_ptr;
+#define gatt_cb (*gatt_cb_ptr)
+#endif
+
+#if GATT_CONFORMANCE_TESTING == TRUE
+GATT_API extern void gatt_set_err_rsp(BOOLEAN enable, UINT8 req_op_code, UINT8 err_status);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+/* internal functions */
+extern void gatt_init (void);
+
+/* from gatt_main.c */
+extern BOOLEAN gatt_disconnect (BD_ADDR rem_bda);
+extern BOOLEAN gatt_act_connect (tGATT_REG *p_reg, BD_ADDR bd_addr);
+extern BOOLEAN gatt_connect (BD_ADDR rem_bda, tGATT_TCB *p_tcb);
+extern void gatt_data_process (tGATT_TCB *p_tcb, BT_HDR *p_buf);
+extern void gatt_update_app_use_link_flag ( tGATT_IF gatt_if, tGATT_TCB *p_tcb, BOOLEAN is_add, BOOLEAN check_acl_link);
+
+extern void gatt_profile_db_init(void);
+extern void gatt_set_ch_state(tGATT_TCB *p_tcb, tGATT_CH_STATE ch_state);
+extern tGATT_CH_STATE gatt_get_ch_state(tGATT_TCB *p_tcb);
+extern void gatt_init_srv_chg(void);
+extern void gatt_proc_srv_chg (void);
+extern void gatt_send_srv_chg_ind (BD_ADDR peer_bda);
+extern void gatt_chk_srv_chg(tGATTS_SRV_CHG *p_srv_chg_clt);
+extern void gatt_add_a_bonded_dev_for_srv_chg (BD_ADDR bda);
+
+/* from gatt_attr.c */
+extern UINT16 gatt_profile_find_conn_id_by_bd_addr(BD_ADDR bda);
+extern tGATT_PROFILE_CLCB *gatt_profile_find_clcb_by_bd_addr(BD_ADDR bda);
+extern BOOLEAN gatt_profile_clcb_dealloc (UINT16 conn_id);
+extern tGATT_PROFILE_CLCB *gatt_profile_clcb_alloc (UINT16 conn_id, BD_ADDR bda);
+
+
+/* Functions provided by att_protocol.c */
+extern tGATT_STATUS attp_send_cl_msg (tGATT_TCB *p_tcb, UINT16 clcb_idx, UINT8 op_code, tGATT_CL_MSG *p_msg);
+extern BT_HDR *attp_build_sr_msg(tGATT_TCB *p_tcb, UINT8 op_code, tGATT_SR_MSG *p_msg);
+extern tGATT_STATUS attp_send_sr_msg (tGATT_TCB *p_tcb, BT_HDR *p_msg);
+extern BOOLEAN attp_send_msg_to_L2CAP(tGATT_TCB *p_tcb, BT_HDR *p_toL2CAP);
+
+/* utility functions */
+extern UINT8 * gatt_dbg_op_name(UINT8 op_code);
+extern UINT32 gatt_add_sdp_record (tBT_UUID *p_uuid, UINT16 start_hdl, UINT16 end_hdl);
+extern BOOLEAN gatt_parse_uuid_from_cmd(tBT_UUID *p_uuid, UINT16 len, UINT8 **p_data);
+extern UINT8 gatt_build_uuid_to_stream(UINT8 **p_dst, tBT_UUID uuid);
+extern BOOLEAN gatt_uuid_compare(tBT_UUID src, tBT_UUID tar);
+extern void gatt_sr_get_sec_info(BD_ADDR rem_bda, BOOLEAN le_conn, UINT8 *p_sec_flag, UINT8 *p_key_size);
+extern void gatt_start_rsp_timer(tGATT_TCB *p_tcb);
+extern void gatt_start_conf_timer(tGATT_TCB *p_tcb);
+extern void gatt_rsp_timeout(TIMER_LIST_ENT *p_tle);
+extern void gatt_ind_ack_timeout(TIMER_LIST_ENT *p_tle);
+extern void gatt_start_ind_ack_timer(tGATT_TCB *p_tcb);
+extern tGATT_STATUS gatt_send_error_rsp(tGATT_TCB *p_tcb, UINT8 err_code, UINT8 op_code, UINT16 handle, BOOLEAN deq);
+extern void gatt_dbg_display_uuid(tBT_UUID bt_uuid);
+
+extern tGATTS_PENDING_NEW_SRV_START *gatt_sr_is_new_srv_chg(tBT_UUID *p_app_uuid128, tBT_UUID *p_svc_uuid, UINT16 svc_inst);
+
+extern BOOLEAN gatt_is_srv_chg_ind_pending (tGATT_TCB *p_tcb);
+extern tGATTS_SRV_CHG *gatt_is_bda_in_the_srv_chg_clt_list (BD_ADDR bda);
+
+extern BOOLEAN gatt_find_the_connected_bda(UINT8 start_idx, BD_ADDR bda, UINT8 *p_found_idx);
+extern void gatt_set_srv_chg(void);
+extern void gatt_delete_dev_from_srv_chg_clt_list(BD_ADDR bd_addr);
+extern tGATT_VALUE *gatt_add_pending_ind(tGATT_TCB *p_tcb, tGATT_VALUE *p_ind);
+extern tGATTS_PENDING_NEW_SRV_START *gatt_add_pending_new_srv_start( tGATTS_HNDL_RANGE *p_new_srv_start);
+extern void gatt_free_srvc_db_buffer_app_id(tBT_UUID *p_app_id);
+
+/* reserved handle list */
+extern tGATT_HDL_LIST_ELEM *gatt_find_hdl_buffer_by_app_id (tBT_UUID *p_app_uuid128, tBT_UUID *p_svc_uuid, UINT16 svc_inst);
+extern tGATT_HDL_LIST_ELEM *gatt_find_hdl_buffer_by_handle(UINT16 handle);
+extern tGATT_HDL_LIST_ELEM *gatt_alloc_hdl_buffer(void);
+extern void gatt_free_hdl_buffer(tGATT_HDL_LIST_ELEM *p);
+extern BOOLEAN gatt_is_last_attribute(tGATT_SRV_LIST_INFO *p_list, tGATT_SRV_LIST_ELEM *p_start, tBT_UUID value);
+extern void gatt_update_last_pri_srv_info(tGATT_SRV_LIST_INFO *p_list);
+extern BOOLEAN gatt_add_a_srv_to_list(tGATT_SRV_LIST_INFO *p_list, tGATT_SRV_LIST_ELEM *p_new);
+extern BOOLEAN gatt_remove_a_srv_from_list(tGATT_SRV_LIST_INFO *p_list, tGATT_SRV_LIST_ELEM *p_remove);
+extern BOOLEAN gatt_add_an_item_to_list(tGATT_HDL_LIST_INFO *p_list, tGATT_HDL_LIST_ELEM *p_new);
+extern BOOLEAN gatt_remove_an_item_from_list(tGATT_HDL_LIST_INFO *p_list, tGATT_HDL_LIST_ELEM *p_remove);
+extern tGATTS_SRV_CHG *gatt_add_srv_chg_clt(tGATTS_SRV_CHG *p_srv_chg);
+
+/* for background connection */
+extern BOOLEAN gatt_update_auto_connect_dev (tGATT_IF gatt_if, BOOLEAN add, BD_ADDR bd_addr);
+extern BOOLEAN gatt_add_bg_dev_list(tGATT_IF gatt_if, BD_ADDR bd_addr);
+extern BOOLEAN gatt_is_bg_dev_for_app(tGATT_BG_CONN_DEV *p_dev, tGATT_IF gatt_if);
+extern BOOLEAN gatt_remove_bg_dev_for_app(tGATT_IF gatt_if, BD_ADDR bd_addr);
+extern UINT8 gatt_get_num_apps_for_bg_dev(BD_ADDR bd_addr);
+extern BOOLEAN gatt_find_app_for_bg_dev(BD_ADDR bd_addr, tGATT_IF *p_gatt_if);
+extern BOOLEAN gatt_remove_bg_dev_from_list(tGATT_IF gatt_if, BD_ADDR bd_addr);
+extern tGATT_BG_CONN_DEV * gatt_find_bg_dev(BD_ADDR remote_bda);
+extern void gatt_deregister_bgdev_list(tGATT_IF gatt_if);
+extern void gatt_reset_bgdev_list(void);
+
+/* server function */
+extern UINT8 gatt_sr_find_i_rcb_by_handle(UINT16 handle);
+extern UINT8 gatt_sr_find_i_rcb_by_app_id(tBT_UUID *p_app_uuid128, tBT_UUID *p_svc_uuid, UINT16 svc_inst);
+extern UINT8 gatt_sr_alloc_rcb(tGATT_HDL_LIST_ELEM *p_list);
+extern tGATT_STATUS gatt_sr_process_app_rsp (tGATT_TCB *p_tcb, tGATT_IF gatt_if, UINT32 trans_id, UINT8 op_code, tGATT_STATUS status, tGATTS_RSP *p_msg);
+extern void gatt_server_handle_client_req (tGATT_TCB *p_tcb, UINT8 op_code,
+ UINT16 len, UINT8 *p_data);
+extern void gatt_sr_send_req_callback(UINT16 conn_id, UINT32 trans_id,
+ UINT8 op_code, tGATTS_DATA *p_req_data);
+extern UINT32 gatt_sr_enqueue_cmd (tGATT_TCB *p_tcb, UINT8 op_code, UINT16 handle);
+extern BOOLEAN gatt_cancel_open(tGATT_IF gatt_if, BD_ADDR bda);
+
+/* */
+
+extern tGATT_REG *gatt_get_regcb (tGATT_IF gatt_if);
+extern BOOLEAN gatt_is_clcb_allocated (UINT16 conn_id);
+extern tGATT_CLCB *gatt_clcb_alloc (UINT16 conn_id);
+extern void gatt_clcb_dealloc (tGATT_CLCB *p_clcb);
+
+extern void gatt_sr_copy_prep_cnt_to_cback_cnt(tGATT_TCB *p_tcb );
+extern BOOLEAN gatt_sr_is_cback_cnt_zero(tGATT_TCB *p_tcb );
+extern BOOLEAN gatt_sr_is_prep_cnt_zero(tGATT_TCB *p_tcb );
+extern void gatt_sr_reset_cback_cnt(tGATT_TCB *p_tcb );
+extern void gatt_sr_reset_prep_cnt(tGATT_TCB *p_tcb );
+extern void gatt_sr_update_cback_cnt(tGATT_TCB *p_tcb, tGATT_IF gatt_if, BOOLEAN is_inc, BOOLEAN is_reset_first);
+extern void gatt_sr_update_prep_cnt(tGATT_TCB *p_tcb, tGATT_IF gatt_if, BOOLEAN is_inc, BOOLEAN is_reset_first);
+
+extern BOOLEAN gatt_find_app_hold_link(tGATT_TCB *p_tcb, UINT8 start_idx, UINT8 *p_found_idx, tGATT_IF *p_gatt_if);
+extern UINT8 gatt_num_apps_hold_link(tGATT_TCB *p_tcb);
+extern UINT8 gatt_num_clcb_by_bd_addr(BD_ADDR bda);
+extern tGATT_TCB * gatt_find_tcb_by_cid(UINT16 lcid);
+extern tGATT_TCB * gatt_allocate_tcb_by_bdaddr(BD_ADDR bda);
+extern tGATT_TCB * gatt_get_tcb_by_idx(UINT8 tcb_idx);
+extern tGATT_TCB * gatt_find_tcb_by_addr(BD_ADDR bda);
+
+
+/* GATT client functions */
+extern void gatt_dequeue_sr_cmd (tGATT_TCB *p_tcb);
+extern UINT8 gatt_send_write_msg(tGATT_TCB *p_tcb, UINT16 clcb_idx, UINT8 op_code, UINT16 handle,
+ UINT16 len, UINT16 offset, UINT8 *p_data);
+extern void gatt_cleanup_upon_disc(BD_ADDR bda, UINT16 reason);
+extern void gatt_end_operation(tGATT_CLCB *p_clcb, tGATT_STATUS status, void *p_data);
+
+extern void gatt_act_discovery(tGATT_CLCB *p_clcb);
+extern void gatt_act_read(tGATT_CLCB *p_clcb, UINT16 offset);
+extern void gatt_act_write(tGATT_CLCB *p_clcb);
+extern UINT8 gatt_act_send_browse(tGATT_TCB *p_tcb, UINT16 index, UINT8 op, UINT16 s_handle, UINT16 e_handle,
+ tBT_UUID uuid);
+extern tGATT_CLCB *gatt_cmd_dequeue(tGATT_TCB *p_tcb, UINT8 *p_opcode);
+extern BOOLEAN gatt_cmd_enq(tGATT_TCB *p_tcb, UINT16 clcb_idx, BOOLEAN to_send, UINT8 op_code, BT_HDR *p_buf);
+extern void gatt_client_handle_server_rsp (tGATT_TCB *p_tcb, UINT8 op_code,
+ UINT16 len, UINT8 *p_data);
+extern void gatt_send_queue_write_cancel (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, tGATT_EXEC_FLAG flag);
+
+/* gatt_auth.c */
+extern BOOLEAN gatt_security_check_start(tGATT_CLCB *p_clcb);
+extern void gatt_verify_signature(tGATT_TCB *p_tcb, BT_HDR *p_buf);
+extern tGATT_SEC_ACTION gatt_determine_sec_act(tGATT_CLCB *p_clcb );
+extern tGATT_STATUS gatt_get_link_encrypt_status(tGATT_TCB *p_tcb);
+extern tGATT_SEC_ACTION gatt_get_sec_act(tGATT_TCB *p_tcb);
+extern void gatt_set_sec_act(tGATT_TCB *p_tcb, tGATT_SEC_ACTION sec_act);
+
+/* gatt_db.c */
+extern BOOLEAN gatts_init_service_db (tGATT_SVC_DB *p_db, tBT_UUID service, BOOLEAN is_pri, UINT16 s_hdl, UINT16 num_handle);
+extern UINT16 gatts_add_included_service (tGATT_SVC_DB *p_db, UINT16 s_handle, UINT16 e_handle, tBT_UUID service);
+extern UINT16 gatts_add_characteristic (tGATT_SVC_DB *p_db, tGATT_PERM perm, tGATT_CHAR_PROP property, tBT_UUID *p_char_uuid);
+extern UINT16 gatts_add_char_descr (tGATT_SVC_DB *p_db, tGATT_PERM perm, tBT_UUID *p_dscp_uuid);
+extern tGATT_STATUS gatts_db_read_attr_value_by_type (tGATT_TCB *p_tcb, tGATT_SVC_DB *p_db, UINT8 op_code, BT_HDR *p_rsp, UINT16 s_handle,
+ UINT16 e_handle, tBT_UUID type, UINT16 *p_len, tGATT_SEC_FLAG sec_flag, UINT8 key_size,UINT32 trans_id, UINT16 *p_cur_handle);
+extern tGATT_STATUS gatts_read_attr_value_by_handle(tGATT_TCB *p_tcb,tGATT_SVC_DB *p_db, UINT8 op_code, UINT16 handle, UINT16 offset,
+ UINT8 *p_value, UINT16 *p_len, UINT16 mtu,tGATT_SEC_FLAG sec_flag,UINT8 key_size,UINT32 trans_id);
+extern tGATT_STATUS gatts_write_attr_perm_check (tGATT_SVC_DB *p_db, UINT8 op_code,UINT16 handle, UINT16 offset, UINT8 *p_data,
+ UINT16 len, tGATT_SEC_FLAG sec_flag, UINT8 key_size);
+extern tGATT_STATUS gatts_read_attr_perm_check(tGATT_SVC_DB *p_db, BOOLEAN is_long, UINT16 handle, tGATT_SEC_FLAG sec_flag,UINT8 key_size);
+extern void gatts_update_srv_list_elem(UINT8 i_sreg, UINT16 handle, BOOLEAN is_primary);
+extern tBT_UUID * gatts_get_service_uuid (tGATT_SVC_DB *p_db);
+
+#endif
+
+#endif /* BLE_INCLUDED */
diff --git a/stack/gatt/gatt_main.c b/stack/gatt/gatt_main.c
new file mode 100644
index 0000000..396367a
--- /dev/null
+++ b/stack/gatt/gatt_main.c
@@ -0,0 +1,1101 @@
+/*****************************************************************************
+**
+** Name: gatt_main.c
+**
+** Description: this file contains the main ATT functions
+**
+** Copyright (c) 2008-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+
+#include "bt_target.h"
+
+#if BLE_INCLUDED == TRUE
+
+#include "gki.h"
+#include "gatt_int.h"
+#include "l2c_api.h"
+#include "btm_int.h"
+#include "btm_ble_int.h"
+
+/* Configuration flags. */
+#define GATT_L2C_CFG_IND_DONE (1<<0)
+#define GATT_L2C_CFG_CFM_DONE (1<<1)
+
+/********************************************************************************/
+/* L O C A L F U N C T I O N P R O T O T Y P E S */
+/********************************************************************************/
+static void gatt_le_connect_cback (BD_ADDR bd_addr, BOOLEAN connected, UINT16 reason);
+static void gatt_le_data_ind (BD_ADDR bd_addr, BT_HDR *p_buf);
+
+static void gatt_l2cif_connect_ind_cback (BD_ADDR bd_addr, UINT16 l2cap_cid, UINT16 psm, UINT8 l2cap_id);
+static void gatt_l2cif_connect_cfm_cback (UINT16 l2cap_cid, UINT16 result);
+static void gatt_l2cif_config_ind_cback (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg);
+static void gatt_l2cif_config_cfm_cback (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg);
+static void gatt_l2cif_disconnect_ind_cback (UINT16 l2cap_cid, BOOLEAN ack_needed);
+static void gatt_l2cif_disconnect_cfm_cback (UINT16 l2cap_cid, UINT16 result);
+static void gatt_l2cif_data_ind_cback (UINT16 l2cap_cid, BT_HDR *p_msg);
+static void gatt_send_conn_cback (BOOLEAN is_bg_conn, tGATT_TCB *p_tcb);
+
+static const tL2CAP_APPL_INFO dyn_info =
+{
+ gatt_l2cif_connect_ind_cback,
+ gatt_l2cif_connect_cfm_cback,
+ NULL,
+ gatt_l2cif_config_ind_cback,
+ gatt_l2cif_config_cfm_cback,
+ gatt_l2cif_disconnect_ind_cback,
+ gatt_l2cif_disconnect_cfm_cback,
+ NULL,
+ gatt_l2cif_data_ind_cback,
+ NULL
+} ;
+
+#if GATT_DYNAMIC_MEMORY == FALSE
+tGATT_CB gatt_cb;
+#endif
+
+/*******************************************************************************
+**
+** Function gatt_init
+**
+** Description This function is enable the GATT profile on the device.
+** It clears out the control blocks, and registers with L2CAP.
+**
+** Returns void
+**
+*******************************************************************************/
+void gatt_init (void)
+{
+ tL2CAP_FIXED_CHNL_REG fixed_reg;
+
+ GATT_TRACE_DEBUG0("gatt_init()");
+
+ memset (&gatt_cb, 0, sizeof(tGATT_CB));
+
+#if defined(GATT_INITIAL_TRACE_LEVEL)
+ gatt_cb.trace_level = GATT_INITIAL_TRACE_LEVEL;
+#else
+ gatt_cb.trace_level = BT_TRACE_LEVEL_NONE; /* No traces */
+#endif
+ gatt_cb.def_mtu_size = GATT_DEF_BLE_MTU_SIZE;
+ GKI_init_q (&gatt_cb.sign_op_queue);
+ /* First, register fixed L2CAP channel for ATT over BLE */
+ fixed_reg.fixed_chnl_opts.mode = L2CAP_FCR_BASIC_MODE;
+ fixed_reg.fixed_chnl_opts.max_transmit = 0xFF;
+ fixed_reg.fixed_chnl_opts.rtrans_tout = 2000;
+ fixed_reg.fixed_chnl_opts.mon_tout = 12000;
+ fixed_reg.fixed_chnl_opts.mps = 670;
+ fixed_reg.fixed_chnl_opts.tx_win_sz = 1;
+
+ fixed_reg.pL2CA_FixedConn_Cb = gatt_le_connect_cback;
+ fixed_reg.pL2CA_FixedData_Cb = gatt_le_data_ind;
+ fixed_reg.default_idle_tout = 0xffff; /* 0xffff default idle timeout */
+
+ L2CA_RegisterFixedChannel (L2CAP_ATT_CID, &fixed_reg);
+
+ /* Now, register with L2CAP for ATT PSM over BR/EDR */
+ if (!L2CA_Register (BT_PSM_ATT, (tL2CAP_APPL_INFO *) &dyn_info))
+ {
+ GATT_TRACE_ERROR0 ("ATT Dynamic Registration failed");
+ }
+
+ BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_ATT, BTM_SEC_NONE, BT_PSM_ATT, 0, 0);
+ BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_ATT, BTM_SEC_NONE, BT_PSM_ATT, 0, 0);
+
+ gatt_cb.hdl_cfg.gatt_start_hdl = GATT_GATT_START_HANDLE;
+ gatt_cb.hdl_cfg.gap_start_hdl = GATT_GAP_START_HANDLE;
+ gatt_cb.hdl_cfg.app_start_hdl = GATT_APP_START_HANDLE;
+ gatt_profile_db_init();
+
+}
+
+
+
+/*******************************************************************************
+**
+** Function gatt_connect
+**
+** Description This function is called to initiate a connection to a peer device.
+**
+** Parameter rem_bda: remote device address to connect to.
+**
+** Returns TRUE if connection is started, otherwise return FALSE.
+**
+*******************************************************************************/
+BOOLEAN gatt_connect (BD_ADDR rem_bda, tGATT_TCB *p_tcb)
+{
+ BOOLEAN gatt_ret = TRUE;
+ tBT_DEVICE_TYPE dev_type;
+ tBLE_ADDR_TYPE addr_type;
+
+ BTM_ReadDevInfo(rem_bda, &dev_type, &addr_type);
+
+ gatt_set_ch_state(p_tcb, GATT_CH_CONN);
+
+ if (dev_type == BT_DEVICE_TYPE_BLE)
+ {
+ p_tcb->att_lcid = L2CAP_ATT_CID;
+ gatt_ret = L2CA_ConnectFixedChnl (L2CAP_ATT_CID, rem_bda);
+ }
+ else
+ {
+ if ((p_tcb->att_lcid = L2CA_ConnectReq(BT_PSM_ATT, rem_bda)) == 0)
+ gatt_ret = FALSE;
+ }
+
+ return gatt_ret;
+}
+
+/*******************************************************************************
+**
+** Function gatt_disconnect
+**
+** Description This function is called to disconnect to an ATT device.
+**
+** Parameter rem_bda: remote device address to disconnect from.
+**
+** Returns TRUE: if connection found and to be disconnected; otherwise
+** return FALSE.
+**
+*******************************************************************************/
+BOOLEAN gatt_disconnect (BD_ADDR rem_bda)
+{
+ tGATT_TCB *p_tcb = gatt_find_tcb_by_addr(rem_bda);
+ BOOLEAN ret = FALSE;
+ tGATT_CH_STATE ch_state;
+ GATT_TRACE_DEBUG0 ("gatt_disconnect ");
+
+ if (p_tcb != NULL)
+ {
+ ret = TRUE;
+ if ( (ch_state = gatt_get_ch_state(p_tcb)) != GATT_CH_CLOSING )
+ {
+ if (p_tcb->att_lcid == L2CAP_ATT_CID)
+ {
+ if (ch_state == GATT_CH_OPEN)
+ /* only LCB exist between remote device and local */
+ ret = L2CA_RemoveFixedChnl (L2CAP_ATT_CID, rem_bda);
+ else
+ {
+ gatt_set_ch_state(p_tcb, GATT_CH_CLOSING);
+ ret = L2CA_CancelBleConnectReq (rem_bda);
+ }
+ }
+ else
+ {
+ ret = L2CA_DisconnectReq(p_tcb->att_lcid);
+ }
+ }
+ else
+ {
+ GATT_TRACE_DEBUG0 ("gatt_disconnect already in closing state");
+ }
+ }
+
+ return ret;
+}
+
+/*******************************************************************************
+**
+** Function gatt_update_app_hold_link_status
+**
+** Description Update the application use link status
+**
+** Returns void.
+**
+*******************************************************************************/
+void gatt_update_app_hold_link_status (tGATT_IF gatt_if, tGATT_TCB *p_tcb, BOOLEAN is_add)
+{
+ UINT8 i;
+ BOOLEAN found=FALSE;
+
+ if (p_tcb == NULL)
+ {
+ GATT_TRACE_ERROR0("gatt_update_app_hold_link_status p_tcb=NULL");
+ return;
+ }
+
+
+ for (i=0; i<GATT_MAX_APPS; i++)
+ {
+ if (p_tcb->app_hold_link[i] == gatt_if)
+ {
+ found = TRUE;
+ if (!is_add)
+ {
+ p_tcb->app_hold_link[i] = 0;
+ break;
+ }
+ }
+ }
+
+ if (!found && is_add)
+ {
+ for (i=0; i<GATT_MAX_APPS; i++)
+ {
+ if (p_tcb->app_hold_link[i] == 0)
+ {
+ p_tcb->app_hold_link[i] = gatt_if;
+ found = TRUE;
+ break;
+ }
+ }
+ }
+
+ GATT_TRACE_DEBUG4("gatt_update_app_hold_link_status found=%d[1-found] idx=%d gatt_if=%d is_add=%d", found, i, gatt_if, is_add);
+
+}
+
+/*******************************************************************************
+**
+** Function gatt_update_app_use_link_flag
+**
+** Description Update the application use link flag and optional to check the acl link
+** if the link is up then set the idle time out accordingly
+**
+** Returns void.
+**
+*******************************************************************************/
+void gatt_update_app_use_link_flag (tGATT_IF gatt_if, tGATT_TCB *p_tcb, BOOLEAN is_add, BOOLEAN check_acl_link)
+{
+ GATT_TRACE_DEBUG2("gatt_update_app_use_link_flag is_add=%d chk_link=%d",
+ is_add, check_acl_link);
+
+ gatt_update_app_hold_link_status(gatt_if, p_tcb, is_add);
+
+ if (check_acl_link &&
+ p_tcb &&
+ (BTM_GetHCIConnHandle(p_tcb->peer_bda) != GATT_INVALID_ACL_HANDLE))
+ {
+ if (is_add)
+ {
+ GATT_TRACE_DEBUG0("GATT disables link idle timer");
+ /* acl link is connected disable the idle timeout */
+ GATT_SetIdleTimeout(p_tcb->peer_bda, GATT_LINK_NO_IDLE_TIMEOUT);
+ }
+ else
+ {
+ if (!gatt_num_apps_hold_link(p_tcb))
+ {
+ /* acl link is connected but no application needs to use the link
+ so set the timeout value to GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP seconds */
+ GATT_TRACE_DEBUG1("GATT starts link idle timer =%d sec", GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP);
+ GATT_SetIdleTimeout(p_tcb->peer_bda, GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP);
+ }
+
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function gatt_act_connect
+**
+** Description GATT connection initiation.
+**
+** Returns void.
+**
+*******************************************************************************/
+BOOLEAN gatt_act_connect (tGATT_REG *p_reg, BD_ADDR bd_addr)
+{
+ BOOLEAN ret = FALSE;
+ tGATT_TCB *p_tcb;
+
+ GATT_TRACE_DEBUG0("gatt_act_connect");
+
+ if ((p_tcb = gatt_find_tcb_by_addr(bd_addr)) != NULL)
+ {
+ ret = TRUE;
+ if(gatt_get_ch_state(p_tcb) == GATT_CH_CLOSING )
+ {
+ /* need to complete the closing first */
+ ret = FALSE;
+ }
+ }
+ else
+ {
+ if ((p_tcb = gatt_allocate_tcb_by_bdaddr(bd_addr)) != NULL)
+ {
+ if (!gatt_connect(bd_addr, p_tcb))
+ {
+ GATT_TRACE_ERROR0("gatt_connect failed");
+ memset(p_tcb, 0, sizeof(tGATT_TCB));
+ }
+ else
+ ret = TRUE;
+ }
+ else
+ {
+ ret = 0;
+ GATT_TRACE_ERROR1("Max TCB for gatt_if [%d] reached.", p_reg->gatt_if);
+ }
+ }
+
+ if (ret)
+ {
+ gatt_update_app_use_link_flag(p_reg->gatt_if, p_tcb, TRUE, FALSE);
+ }
+
+ return ret;
+}
+
+/*******************************************************************************
+**
+** Function gatt_le_connect_cback
+**
+** Description This callback function is called by L2CAP to indicate that
+** the ATT fixed channel for LE is
+** connected (conn = TRUE)/disconnected (conn = FALSE).
+**
+*******************************************************************************/
+static void gatt_le_connect_cback (BD_ADDR bd_addr, BOOLEAN connected, UINT16 reason)
+{
+
+ tGATT_TCB *p_tcb = gatt_find_tcb_by_addr(bd_addr);
+
+ BOOLEAN check_srv_chg = FALSE;
+ tGATTS_SRV_CHG *p_srv_chg_clt=NULL;
+ BOOLEAN is_bg_conn = FALSE;
+
+
+ GATT_TRACE_DEBUG3 ("GATT ATT protocol channel with BDA: %08x%04x is %s",
+ (bd_addr[0]<<24)+(bd_addr[1]<<16)+(bd_addr[2]<<8)+bd_addr[3],
+ (bd_addr[4]<<8)+bd_addr[5], (connected) ? "connected" : "disconnected");
+
+
+ if ((p_srv_chg_clt = gatt_is_bda_in_the_srv_chg_clt_list(bd_addr)) != NULL)
+ {
+ check_srv_chg = TRUE;
+ }
+ else
+ {
+ if (btm_sec_is_a_bonded_dev(bd_addr))
+ gatt_add_a_bonded_dev_for_srv_chg(bd_addr);
+ }
+
+ if (connected)
+ {
+ GATT_TRACE_DEBUG1("connected is TRUE reason=%d",reason );
+ /* BR/EDR lik, ignore this callback */
+ if (reason == 0)
+ return;
+
+ /* do we have a channel initiating a connection? */
+ if (p_tcb)
+ {
+ if (check_srv_chg)
+ gatt_chk_srv_chg (p_srv_chg_clt);
+ /* we are initiating connection */
+ if ( gatt_get_ch_state(p_tcb) == GATT_CH_CONN)
+ {
+ /* send callback */
+ gatt_set_ch_state(p_tcb, GATT_CH_OPEN);
+ p_tcb->payload_size = GATT_DEF_BLE_MTU_SIZE;
+
+ gatt_send_conn_cback(FALSE, p_tcb);
+ }
+ else /* there was an exisiting link, ignore the callback */
+ {
+ GATT_TRACE_ERROR0("connection already up, ignore it");
+ return;
+ }
+ }
+ /* this is incoming connection or background connection callback */
+ else
+ {
+ if ((p_tcb = gatt_allocate_tcb_by_bdaddr(bd_addr)) != NULL)
+ {
+ p_tcb->att_lcid = L2CAP_ATT_CID;
+
+ gatt_set_ch_state(p_tcb, GATT_CH_OPEN);
+
+ p_tcb->payload_size = GATT_DEF_BLE_MTU_SIZE;
+ if (L2CA_GetBleConnRole(p_tcb->peer_bda)== HCI_ROLE_MASTER)
+ {
+ is_bg_conn = TRUE;
+ }
+ gatt_send_conn_cback (is_bg_conn, p_tcb);
+ if (check_srv_chg)
+ {
+ gatt_chk_srv_chg (p_srv_chg_clt);
+ }
+ }
+ else
+ {
+ GATT_TRACE_ERROR0("CCB max out, no rsources");
+ }
+ }
+ }
+ else
+ {
+ gatt_cleanup_upon_disc(bd_addr, reason);
+ GATT_TRACE_DEBUG0 ("ATT disconnected");
+ }
+}
+
+/*******************************************************************************
+**
+** Function gatt_le_data_ind
+**
+** Description This function is called when data is received from L2CAP.
+** if we are the originator of the connection, we are the ATT
+** client, and the received message is queued up for the client.
+**
+** If we are the destination of the connection, we are the ATT
+** server, so the message is passed to the server processing
+** function.
+**
+** Returns void
+**
+*******************************************************************************/
+static void gatt_le_data_ind (BD_ADDR bd_addr, BT_HDR *p_buf)
+{
+ tGATT_TCB *p_tcb;
+
+ /* Find CCB based on bd addr */
+ if ((p_tcb = gatt_find_tcb_by_addr (bd_addr)) != NULL &&
+ gatt_get_ch_state(p_tcb) >= GATT_CH_OPEN)
+ {
+ gatt_data_process(p_tcb, p_buf);
+ }
+ else
+ {
+ GKI_freebuf (p_buf);
+
+ if (p_tcb != NULL)
+ {
+ GATT_TRACE_WARNING1 ("ATT - Ignored L2CAP data while in state: %d",
+ gatt_get_ch_state(p_tcb));
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function gatt_l2cif_connect_ind
+**
+** Description This function handles an inbound connection indication
+** from L2CAP. This is the case where we are acting as a
+** server.
+**
+** Returns void
+**
+*******************************************************************************/
+static void gatt_l2cif_connect_ind_cback (BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id)
+{
+ /* do we already have a control channel for this peer? */
+ UINT8 result = L2CAP_CONN_OK;
+ tL2CAP_CFG_INFO cfg;
+ tGATT_TCB *p_tcb = gatt_find_tcb_by_addr(bd_addr);
+
+ GATT_TRACE_ERROR1("Connection indication cid = %d", lcid);
+ /* new connection ? */
+ if (p_tcb == NULL)
+ {
+ /* allocate tcb */
+ if ((p_tcb = gatt_allocate_tcb_by_bdaddr(bd_addr)) == NULL)
+ {
+ /* no tcb available, reject L2CAP connection */
+ result = L2CAP_CONN_NO_RESOURCES;
+ }
+ else
+ p_tcb->att_lcid = lcid;
+
+ }
+ else /* existing connection , reject it */
+ {
+ result = L2CAP_CONN_NO_RESOURCES;
+ }
+
+ /* Send L2CAP connect rsp */
+ L2CA_ConnectRsp(bd_addr, id, lcid, result, 0);
+
+ /* if result ok, proceed with connection */
+ if (result == L2CAP_CONN_OK)
+ {
+ /* transition to configuration state */
+ gatt_set_ch_state(p_tcb, GATT_CH_CFG);
+
+ /* Send L2CAP config req */
+ memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+ cfg.mtu_present = TRUE;
+ cfg.mtu = GATT_MAX_MTU_SIZE;
+
+ L2CA_ConfigReq(lcid, &cfg);
+ }
+}
+
+/*******************************************************************************
+**
+** Function gatt_l2c_connect_cfm_cback
+**
+** Description This is the L2CAP connect confirm callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void gatt_l2cif_connect_cfm_cback(UINT16 lcid, UINT16 result)
+{
+ tGATT_TCB *p_tcb;
+ tL2CAP_CFG_INFO cfg;
+
+ /* look up clcb for this channel */
+ if ((p_tcb = gatt_find_tcb_by_cid(lcid)) != NULL)
+ {
+ GATT_TRACE_DEBUG3("gatt_l2c_connect_cfm_cback result: %d ch_state: %d, lcid:0x%x", result, gatt_get_ch_state(p_tcb), p_tcb->att_lcid);
+
+ /* if in correct state */
+ if (gatt_get_ch_state(p_tcb) == GATT_CH_CONN)
+ {
+ /* if result successful */
+ if (result == L2CAP_CONN_OK)
+ {
+ /* set channel state */
+ gatt_set_ch_state(p_tcb, GATT_CH_CFG);
+
+ /* Send L2CAP config req */
+ memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+ cfg.mtu_present = TRUE;
+ cfg.mtu = GATT_MAX_MTU_SIZE;
+ L2CA_ConfigReq(lcid, &cfg);
+ }
+ /* else initiating connection failure */
+ else
+ {
+ gatt_cleanup_upon_disc(p_tcb->peer_bda, result);
+ }
+ }
+ else /* wrong state, disconnect it */
+ {
+ if (result == L2CAP_CONN_OK)
+ {
+ /* just in case the peer also accepts our connection - Send L2CAP disconnect req */
+ L2CA_DisconnectReq(lcid);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function gatt_l2cif_config_cfm_cback
+**
+** Description This is the L2CAP config confirm callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void gatt_l2cif_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
+{
+ tGATT_TCB *p_tcb;
+ tGATTS_SRV_CHG *p_srv_chg_clt=NULL;
+
+ /* look up clcb for this channel */
+ if ((p_tcb = gatt_find_tcb_by_cid(lcid)) != NULL)
+ {
+ /* if in correct state */
+ if ( gatt_get_ch_state(p_tcb) == GATT_CH_CFG)
+ {
+ /* if result successful */
+ if (p_cfg->result == L2CAP_CFG_OK)
+ {
+ /* update flags */
+ p_tcb->ch_flags |= GATT_L2C_CFG_CFM_DONE;
+
+ /* if configuration complete */
+ if (p_tcb->ch_flags & GATT_L2C_CFG_IND_DONE)
+ {
+ gatt_set_ch_state(p_tcb, GATT_CH_OPEN);
+
+ if ((p_srv_chg_clt = gatt_is_bda_in_the_srv_chg_clt_list(p_tcb->peer_bda)) != NULL)
+ {
+ gatt_chk_srv_chg(p_srv_chg_clt);
+ }
+ else
+ {
+ if (btm_sec_is_a_bonded_dev(p_tcb->peer_bda))
+ gatt_add_a_bonded_dev_for_srv_chg(p_tcb->peer_bda);
+ }
+
+ /* send callback */
+ gatt_send_conn_cback(FALSE, p_tcb);
+ }
+ }
+ /* else failure */
+ else
+ {
+ /* Send L2CAP disconnect req */
+ L2CA_DisconnectReq(lcid);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function gatt_l2cif_config_ind_cback
+**
+** Description This is the L2CAP config indication callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void gatt_l2cif_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
+{
+ tGATT_TCB *p_tcb;
+ tGATTS_SRV_CHG *p_srv_chg_clt=NULL;
+ /* look up clcb for this channel */
+ if ((p_tcb = gatt_find_tcb_by_cid(lcid)) != NULL)
+ {
+ /* GATT uses the smaller of our MTU and peer's MTU */
+ if ( (p_cfg->mtu_present) && (p_cfg->mtu < L2CAP_DEFAULT_MTU) )
+ p_tcb->payload_size = p_cfg->mtu;
+ else
+ p_tcb->payload_size = L2CAP_DEFAULT_MTU;
+
+ /* send L2CAP configure response */
+ memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO));
+ p_cfg->result = L2CAP_CFG_OK;
+ L2CA_ConfigRsp(lcid, p_cfg);
+
+ /* if first config ind */
+ if ((p_tcb->ch_flags & GATT_L2C_CFG_IND_DONE) == 0)
+ {
+ /* update flags */
+ p_tcb->ch_flags |= GATT_L2C_CFG_IND_DONE;
+
+ /* if configuration complete */
+ if (p_tcb->ch_flags & GATT_L2C_CFG_CFM_DONE)
+ {
+ gatt_set_ch_state(p_tcb, GATT_CH_OPEN);
+ if ((p_srv_chg_clt = gatt_is_bda_in_the_srv_chg_clt_list(p_tcb->peer_bda)) != NULL)
+ {
+ gatt_chk_srv_chg(p_srv_chg_clt);
+ }
+ else
+ {
+ if (btm_sec_is_a_bonded_dev(p_tcb->peer_bda))
+ gatt_add_a_bonded_dev_for_srv_chg(p_tcb->peer_bda);
+ }
+
+ /* send callback */
+ gatt_send_conn_cback(FALSE, p_tcb);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function gatt_l2cif_disconnect_ind_cback
+**
+** Description This is the L2CAP disconnect indication callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void gatt_l2cif_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed)
+{
+ tGATT_TCB *p_tcb;
+ UINT16 reason;
+
+ /* look up clcb for this channel */
+ if ((p_tcb = gatt_find_tcb_by_cid(lcid)) != NULL)
+ {
+ if (ack_needed)
+ {
+ /* send L2CAP disconnect response */
+ L2CA_DisconnectRsp(lcid);
+ }
+ if (btm_sec_is_a_bonded_dev(p_tcb->peer_bda))
+ gatt_add_a_bonded_dev_for_srv_chg(p_tcb->peer_bda);
+ /* if ACL link is still up, no reason is logged, l2cap is disconnect from peer */
+ if ((reason = L2CA_GetDisconnectReason(p_tcb->peer_bda)) == 0)
+ reason = GATT_CONN_TERMINATE_PEER_USER;
+
+ /* send disconnect callback */
+ gatt_cleanup_upon_disc(p_tcb->peer_bda, reason);
+ }
+}
+
+/*******************************************************************************
+**
+** Function gatt_l2cif_disconnect_cfm_cback
+**
+** Description This is the L2CAP disconnect confirm callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void gatt_l2cif_disconnect_cfm_cback(UINT16 lcid, UINT16 result)
+{
+ tGATT_TCB *p_tcb;
+ UINT16 reason;
+
+ /* look up clcb for this channel */
+ if ((p_tcb = gatt_find_tcb_by_cid(lcid)) != NULL)
+ {
+ if (btm_sec_is_a_bonded_dev(p_tcb->peer_bda))
+ gatt_add_a_bonded_dev_for_srv_chg(p_tcb->peer_bda);
+ /* send disconnect callback */
+ /* if ACL link is still up, no reason is logged, l2cap is disconnect from peer */
+ if ((reason = L2CA_GetDisconnectReason(p_tcb->peer_bda)) == 0)
+ reason = GATT_CONN_TERMINATE_LOCAL_HOST;
+
+ gatt_cleanup_upon_disc(p_tcb->peer_bda, reason);
+ }
+}
+
+/*******************************************************************************
+**
+** Function gatt_l2cif_data_ind_cback
+**
+** Description This is the L2CAP data indication callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void gatt_l2cif_data_ind_cback(UINT16 lcid, BT_HDR *p_buf)
+{
+ tGATT_TCB *p_tcb;
+
+ /* look up clcb for this channel */
+ if ((p_tcb = gatt_find_tcb_by_cid(lcid)) != NULL &&
+ gatt_get_ch_state(p_tcb) == GATT_CH_OPEN)
+ {
+ /* process the data */
+ gatt_data_process(p_tcb, p_buf);
+ }
+ else /* prevent buffer leak */
+ GKI_freebuf(p_buf);
+}
+
+/*******************************************************************************
+**
+** Function gatt_send_conn_cback
+**
+** Description Callback used to notify layer above about a connection.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void gatt_send_conn_cback(BOOLEAN is_bg_conn, tGATT_TCB *p_tcb)
+{
+ UINT8 i;
+ tGATT_REG *p_reg;
+ tGATT_BG_CONN_DEV *p_bg_dev=NULL;
+ UINT16 conn_id;
+
+ if (is_bg_conn)
+ p_bg_dev = gatt_find_bg_dev(p_tcb->peer_bda);
+
+ /* notifying all applications for the connection up event */
+ for (i = 0, p_reg = gatt_cb.cl_rcb ; i < GATT_MAX_APPS; i++, p_reg++)
+ {
+ if (p_reg->in_use)
+ {
+ if (p_bg_dev && gatt_is_bg_dev_for_app(p_bg_dev, p_reg->gatt_if))
+ gatt_update_app_use_link_flag(p_reg->gatt_if, p_tcb, TRUE, TRUE);
+
+ if (p_reg->app_cb.p_conn_cb)
+ {
+ conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if);
+ (*p_reg->app_cb.p_conn_cb)(p_reg->gatt_if, p_tcb->peer_bda, conn_id, TRUE, 0);
+ }
+ }
+ }
+
+
+ if (gatt_num_apps_hold_link(p_tcb))
+ {
+ /* disable idle timeout if one or more clients are holding the link disable the idle timer */
+ GATT_SetIdleTimeout(p_tcb->peer_bda, GATT_LINK_NO_IDLE_TIMEOUT);
+ }
+}
+
+/*******************************************************************************
+**
+** Function gatt_le_data_ind
+**
+** Description This function is called when data is received from L2CAP.
+** if we are the originator of the connection, we are the ATT
+** client, and the received message is queued up for the client.
+**
+** If we are the destination of the connection, we are the ATT
+** server, so the message is passed to the server processing
+** function.
+**
+** Returns void
+**
+*******************************************************************************/
+void gatt_data_process (tGATT_TCB *p_tcb, BT_HDR *p_buf)
+{
+ UINT8 *p = (UINT8 *)(p_buf + 1) + p_buf->offset;
+ UINT8 op_code, pseudo_op_code;
+ UINT16 msg_len;
+
+
+ if (p_buf->len > 0)
+ {
+ msg_len = p_buf->len - 1;
+ STREAM_TO_UINT8(op_code, p);
+
+ /* remove the two MSBs associated with sign write and write cmd */
+ pseudo_op_code = op_code & (~GATT_WRITE_CMD_MASK);
+
+ if (pseudo_op_code < GATT_OP_CODE_MAX)
+ {
+ if (op_code == GATT_SIGN_CMD_WRITE)
+ {
+ gatt_verify_signature(p_tcb, p_buf);
+ return;
+ }
+ else
+ {
+ /* message from client */
+ if ((op_code % 2) == 0)
+ gatt_server_handle_client_req (p_tcb, op_code, msg_len, p);
+ else
+ gatt_client_handle_server_rsp (p_tcb, op_code, msg_len, p);
+ }
+ }
+ else
+ {
+ GATT_TRACE_ERROR1 ("ATT - Rcvd L2CAP data, unknown cmd: 0x%x", op_code);
+ }
+ }
+ else
+ {
+ GATT_TRACE_ERROR0 ("invalid data length, ignore");
+ }
+
+ GKI_freebuf (p_buf);
+}
+
+/*******************************************************************************
+**
+** Function gatt_add_a_bonded_dev_for_srv_chg
+**
+** Description Add a bonded dev to the service changed client list
+**
+** Returns void
+**
+*******************************************************************************/
+void gatt_add_a_bonded_dev_for_srv_chg (BD_ADDR bda)
+{
+ tGATTS_SRV_CHG *p_buf;
+ tGATTS_SRV_CHG_REQ req;
+ tGATTS_SRV_CHG srv_chg_clt;
+
+ memcpy(srv_chg_clt.bda, bda, BD_ADDR_LEN);
+ srv_chg_clt.srv_changed = FALSE;
+ if ((p_buf = gatt_add_srv_chg_clt(&srv_chg_clt)) != NULL)
+ {
+ memcpy(req.srv_chg.bda, bda, BD_ADDR_LEN);
+ req.srv_chg.srv_changed = FALSE;
+ if (gatt_cb.cb_info.p_srv_chg_callback)
+ (*gatt_cb.cb_info.p_srv_chg_callback)(GATTS_SRV_CHG_CMD_ADD_CLIENT, &req, NULL);
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function gatt_send_srv_chg_ind
+**
+** Description This function is called to send a service chnaged indication to
+** the specified bd address
+**
+** Returns void
+**
+*******************************************************************************/
+void gatt_send_srv_chg_ind (BD_ADDR peer_bda)
+{
+ UINT8 handle_range[GATT_SIZE_OF_SRV_CHG_HNDL_RANGE];
+ UINT8 *p = handle_range;
+ UINT16 conn_id;
+
+ GATT_TRACE_DEBUG0("gatt_send_srv_chg_ind");
+
+ if (gatt_cb.handle_of_h_r)
+ {
+ if ((conn_id = gatt_profile_find_conn_id_by_bd_addr(peer_bda)) != GATT_INVALID_CONN_ID)
+ {
+ UINT16_TO_STREAM (p, 1);
+ UINT16_TO_STREAM (p, 0xFFFF);
+ GATTS_HandleValueIndication (conn_id,
+ gatt_cb.handle_of_h_r,
+ GATT_SIZE_OF_SRV_CHG_HNDL_RANGE,
+ handle_range);
+ }
+ else
+ {
+ GATT_TRACE_ERROR2("Unable to find conn_id for %08x%04x ",
+ (peer_bda[0]<<24)+(peer_bda[1]<<16)+(peer_bda[2]<<8)+peer_bda[3],
+ (peer_bda[4]<<8)+peer_bda[5] );
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function gatt_chk_srv_chg
+**
+** Description Check sending service chnaged Indication is required or not
+** if required then send the Indication
+**
+** Returns void
+**
+*******************************************************************************/
+void gatt_chk_srv_chg(tGATTS_SRV_CHG *p_srv_chg_clt)
+{
+ GATT_TRACE_DEBUG1("gatt_chk_srv_chg srv_changed=%d", p_srv_chg_clt->srv_changed );
+
+ if (p_srv_chg_clt->srv_changed)
+ {
+ gatt_send_srv_chg_ind(p_srv_chg_clt->bda);
+ }
+ else
+ {
+ GATT_TRACE_DEBUG0("No need to send srv chg ");
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function gatt_init_srv_chg
+**
+** Description This function is used to initialize the service changed
+** attribute value
+**
+** Returns void
+**
+*******************************************************************************/
+void gatt_init_srv_chg (void)
+{
+ tGATTS_SRV_CHG_REQ req;
+ tGATTS_SRV_CHG_RSP rsp;
+ BOOLEAN status;
+ UINT8 num_clients,i;
+ tGATTS_SRV_CHG srv_chg_clt;
+
+ GATT_TRACE_DEBUG0("gatt_init_srv_chg");
+ if (gatt_cb.cb_info.p_srv_chg_callback)
+ {
+ status = (*gatt_cb.cb_info.p_srv_chg_callback)(GATTS_SRV_CHG_CMD_READ_NUM_CLENTS, NULL, &rsp);
+
+ if (status && rsp.num_clients)
+ {
+ GATT_TRACE_DEBUG1("gatt_init_srv_chg num_srv_chg_clt_clients=%d", rsp.num_clients);
+ num_clients = rsp.num_clients;
+ i = 1; /* use one based index */
+ while ((i <= num_clients) && status)
+ {
+ req.client_read_index = i;
+ if ((status = (*gatt_cb.cb_info.p_srv_chg_callback)(GATTS_SRV_CHG_CMD_READ_CLENT, &req, &rsp)))
+ {
+ memcpy(&srv_chg_clt, &rsp.srv_chg ,sizeof(tGATTS_SRV_CHG));
+ if (gatt_add_srv_chg_clt(&srv_chg_clt) == NULL)
+ {
+ GATT_TRACE_ERROR0("Unable to add a service change client");
+ status = FALSE;
+ }
+ }
+ i++;
+ }
+ }
+ }
+ else
+ {
+ GATT_TRACE_DEBUG0("gatt_init_srv_chg callback not registered yet");
+ }
+}
+
+/*******************************************************************************
+**
+** Function gatt_proc_srv_chg
+**
+** Description This function is process the service changed request
+**
+** Returns void
+**
+*******************************************************************************/
+void gatt_proc_srv_chg (void)
+{
+ UINT8 start_idx, found_idx;
+ BD_ADDR bda;
+ BOOLEAN srv_chg_ind_pending=FALSE;
+ tGATT_TCB *p_tcb;
+
+ GATT_TRACE_DEBUG0 ("gatt_proc_srv_chg");
+
+ if (gatt_cb.cb_info.p_srv_chg_callback && gatt_cb.handle_of_h_r)
+ {
+ gatt_set_srv_chg();
+ start_idx =0;
+ while (gatt_find_the_connected_bda(start_idx, bda, &found_idx))
+ {
+ p_tcb = &gatt_cb.tcb[found_idx];;
+ srv_chg_ind_pending = gatt_is_srv_chg_ind_pending(p_tcb);
+
+ if (!srv_chg_ind_pending)
+ {
+ gatt_send_srv_chg_ind(bda);
+ }
+ else
+ {
+ GATT_TRACE_DEBUG0 ("discard srv chg - already has one in the queue");
+ }
+ start_idx = ++found_idx;
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function gatt_set_ch_state
+**
+** Description This function set the ch_state in tcb
+**
+** Returns none
+**
+*******************************************************************************/
+void gatt_set_ch_state(tGATT_TCB *p_tcb, tGATT_CH_STATE ch_state)
+{
+ if (p_tcb)
+ {
+ GATT_TRACE_DEBUG2 ("gatt_set_ch_state: old=%d new=%d", p_tcb->ch_state, ch_state);
+ p_tcb->ch_state = ch_state;
+ }
+}
+
+/*******************************************************************************
+**
+** Function gatt_get_ch_state
+**
+** Description This function get the ch_state in tcb
+**
+** Returns none
+**
+*******************************************************************************/
+tGATT_CH_STATE gatt_get_ch_state(tGATT_TCB *p_tcb)
+{
+ tGATT_CH_STATE ch_state = GATT_CH_CLOSE;
+ if (p_tcb)
+ {
+ GATT_TRACE_DEBUG1 ("gatt_get_ch_state: ch_state=%d", p_tcb->ch_state);
+ ch_state = p_tcb->ch_state;
+ }
+ return ch_state;
+}
+
+#endif /* BLE_INCLUDED */
diff --git a/stack/gatt/gatt_sr.c b/stack/gatt/gatt_sr.c
new file mode 100644
index 0000000..9da6c34
--- /dev/null
+++ b/stack/gatt/gatt_sr.c
@@ -0,0 +1,1472 @@
+/*****************************************************************************
+**
+** Name: gatt_sr.c
+**
+** Description: this file contains the GATT server functions
+**
+** Copyright (c) 2008-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+
+#include "bt_target.h"
+
+#if BLE_INCLUDED == TRUE
+#include <string.h>
+#include "gatt_int.h"
+#include "l2c_api.h"
+
+
+/*******************************************************************************
+**
+** Function gatt_sr_enqueue_cmd
+**
+** Description This function enqueue the request from client which needs a
+** application response, and update the transaction ID.
+**
+** Returns void
+**
+*******************************************************************************/
+UINT32 gatt_sr_enqueue_cmd (tGATT_TCB *p_tcb, UINT8 op_code, UINT16 handle)
+{
+ tGATT_SR_CMD *p_cmd = &p_tcb->sr_cmd;
+ UINT32 trans_id = 0;
+
+ if ( (p_cmd->op_code == 0) ||
+ (op_code == GATT_HANDLE_VALUE_CONF)) /* no pending request */
+ {
+ if (op_code == GATT_CMD_WRITE ||
+ op_code == GATT_SIGN_CMD_WRITE ||
+ op_code == GATT_REQ_MTU ||
+ op_code == GATT_HANDLE_VALUE_CONF)
+ {
+ trans_id = ++p_tcb->trans_id;
+ }
+ else
+ {
+ p_cmd->trans_id = ++p_tcb->trans_id;
+ p_cmd->op_code = op_code;
+ p_cmd->handle = handle;
+ p_cmd->status = GATT_NOT_FOUND;
+ p_tcb->trans_id %= GATT_TRANS_ID_MAX;
+ trans_id = p_cmd->trans_id;
+ }
+ }
+
+ return trans_id;
+}
+
+/*******************************************************************************
+**
+** Function gatt_sr_cmd_empty
+**
+** Description This function check the server command queue is empty or not.
+**
+** Returns TRUE if empty, FALSE if there is pending command.
+**
+*******************************************************************************/
+BOOLEAN gatt_sr_cmd_empty (tGATT_TCB *p_tcb)
+{
+ return(p_tcb->sr_cmd.op_code == 0);
+}
+
+/*******************************************************************************
+**
+** Function gatt_dequeue_sr_cmd
+**
+** Description This function dequeue the request from command queue.
+**
+** Returns void
+**
+*******************************************************************************/
+void gatt_dequeue_sr_cmd (tGATT_TCB *p_tcb)
+{
+ /* Double check in case any buffers are queued */
+ GATT_TRACE_DEBUG0("gatt_dequeue_sr_cmd" );
+ if (p_tcb->sr_cmd.p_rsp_msg)
+ {
+ GATT_TRACE_ERROR1("free p_tcb->sr_cmd.p_rsp_msg = %d", p_tcb->sr_cmd.p_rsp_msg);
+
+ GKI_freebuf (p_tcb->sr_cmd.p_rsp_msg);
+ }
+
+ while (p_tcb->sr_cmd.multi_rsp_q.p_first)
+ GKI_freebuf (GKI_dequeue (&p_tcb->sr_cmd.multi_rsp_q));
+ memset( &p_tcb->sr_cmd, 0, sizeof(tGATT_SR_CMD));
+}
+
+/*******************************************************************************
+**
+** Function process_read_multi_rsp
+**
+** Description This function check the read multiple response.
+**
+** Returns BOOLEAN if all replies have been received
+**
+*******************************************************************************/
+static BOOLEAN process_read_multi_rsp (tGATT_SR_CMD *p_cmd, tGATT_STATUS status,
+ tGATTS_RSP *p_msg, UINT16 mtu)
+{
+ tGATTS_RSP *p_rsp;
+ UINT16 ii, total_len, len;
+ BT_HDR *p_buf = (BT_HDR *)GKI_getbuf((UINT16)sizeof(tGATTS_RSP));
+ UINT8 *p;
+ BOOLEAN is_overflow = FALSE;
+
+ GATT_TRACE_DEBUG2 ("process_read_multi_rsp status=%d mtu=%d", status, mtu);
+
+ if (p_buf == NULL)
+ {
+ p_cmd->status = GATT_INSUF_RESOURCE;
+ return FALSE;
+ }
+
+ /* Enqueue the response */
+ memcpy((void *)p_buf, (const void *)p_msg, sizeof(tGATTS_RSP));
+ GKI_enqueue (&p_cmd->multi_rsp_q, p_buf);
+
+ p_cmd->status = status;
+ if (status == GATT_SUCCESS)
+ {
+ GATT_TRACE_DEBUG2 ("Multi read count=%d num_hdls=%d",
+ p_cmd->multi_rsp_q.count, p_cmd->multi_req.num_handles);
+ /* Wait till we get all the responses */
+ if (p_cmd->multi_rsp_q.count == p_cmd->multi_req.num_handles)
+ {
+ len = sizeof(BT_HDR) + L2CAP_MIN_OFFSET + mtu;
+ if ((p_buf = (BT_HDR *)GKI_getbuf(len)) == NULL)
+ {
+ p_cmd->status = GATT_INSUF_RESOURCE;
+ return(TRUE);
+ }
+
+ memset(p_buf, 0, len);
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p = (UINT8 *)(p_buf + 1) + p_buf->offset;
+
+ /* First byte in the response is the opcode */
+ *p++ = GATT_RSP_READ_MULTI;
+ p_buf->len = 1;
+
+ /* Now walk through the buffers puting the data into the response in order */
+ for (ii = 0; ii < p_cmd->multi_req.num_handles; ii++)
+ {
+ if (ii==0)
+ {
+ p_rsp = (tGATTS_RSP *)GKI_getfirst (&p_cmd->multi_rsp_q);
+ }
+ else
+ {
+ p_rsp = (tGATTS_RSP *)GKI_getnext (p_rsp);
+ }
+
+ if (p_rsp != NULL)
+ {
+
+ total_len = (p_buf->len + p_rsp->attr_value.len);
+
+ if (total_len > mtu)
+ {
+ /* just send the partial response for the overflow case */
+ len = p_rsp->attr_value.len - (total_len - mtu);
+ is_overflow = TRUE;
+ GATT_TRACE_DEBUG2 ("multi read overflow available len=%d val_len=%d", len, p_rsp->attr_value.len );
+ }
+ else
+ {
+ len = p_rsp->attr_value.len;
+ }
+
+ if (p_rsp->attr_value.handle == p_cmd->multi_req.handles[ii])
+ {
+ memcpy (p, p_rsp->attr_value.value, len);
+ if (!is_overflow)
+ p += len;
+ p_buf->len += len;
+ }
+ else
+ {
+ p_cmd->status = GATT_NOT_FOUND;
+ break;
+ }
+
+ if (is_overflow)
+ break;
+
+ }
+ else
+ {
+ p_cmd->status = GATT_NOT_FOUND;
+ break;
+ }
+
+ } /* loop through all handles*/
+
+
+ /* Sanity check on the buffer length */
+ if (p_buf->len == 0)
+ {
+ GATT_TRACE_ERROR0("process_read_multi_rsp - nothing found!!");
+ p_cmd->status = GATT_NOT_FOUND;
+ GKI_freebuf (p_buf);
+ GATT_TRACE_DEBUG0(" GKI_freebuf (p_buf)");
+ }
+ else if (p_cmd->p_rsp_msg != NULL)
+ {
+ GKI_freebuf (p_buf);
+ }
+ else
+ {
+ p_cmd->p_rsp_msg = p_buf;
+ }
+
+ return(TRUE);
+ }
+ }
+ else /* any handle read exception occurs, return error */
+ {
+ return(TRUE);
+ }
+
+ /* If here, still waiting */
+ return(FALSE);
+}
+
+/*******************************************************************************
+**
+** Function gatt_sr_process_app_rsp
+**
+** Description This function checks whether the response message from application
+** match any pending request or not.
+**
+** Returns void
+**
+*******************************************************************************/
+tGATT_STATUS gatt_sr_process_app_rsp (tGATT_TCB *p_tcb, tGATT_IF gatt_if,
+ UINT32 trans_id, UINT8 op_code,
+ tGATT_STATUS status, tGATTS_RSP *p_msg)
+{
+ tGATT_STATUS ret_code = GATT_SUCCESS;
+
+ GATT_TRACE_DEBUG1("gatt_sr_process_app_rsp gatt_if=%d", gatt_if);
+
+ gatt_sr_update_cback_cnt(p_tcb, gatt_if, FALSE, FALSE);
+
+ if (op_code == GATT_REQ_READ_MULTI)
+ {
+ /* If no error and still waiting, just return */
+ if (!process_read_multi_rsp (&p_tcb->sr_cmd, status, p_msg, p_tcb->payload_size))
+ return(GATT_SUCCESS);
+ }
+ else
+ {
+ if (op_code == GATT_REQ_PREPARE_WRITE && status == GATT_SUCCESS)
+ gatt_sr_update_prep_cnt(p_tcb, gatt_if, TRUE, FALSE);
+
+ if (op_code == GATT_REQ_EXEC_WRITE && status != GATT_SUCCESS)
+ gatt_sr_reset_cback_cnt(p_tcb);
+
+ p_tcb->sr_cmd.status = status;
+
+ if (gatt_sr_is_cback_cnt_zero(p_tcb)
+ && status == GATT_SUCCESS)
+ {
+ if (p_tcb->sr_cmd.p_rsp_msg == NULL)
+ {
+ p_tcb->sr_cmd.p_rsp_msg = attp_build_sr_msg (p_tcb, (UINT8)(op_code + 1), (tGATT_SR_MSG *)p_msg);
+ }
+ else
+ {
+ GATT_TRACE_ERROR0("Exception!!! already has respond message");
+ }
+ }
+ }
+ if (gatt_sr_is_cback_cnt_zero(p_tcb))
+ {
+ if ( (p_tcb->sr_cmd.status == GATT_SUCCESS) && (p_tcb->sr_cmd.p_rsp_msg) )
+ {
+ ret_code = attp_send_sr_msg (p_tcb, p_tcb->sr_cmd.p_rsp_msg);
+ p_tcb->sr_cmd.p_rsp_msg = NULL;
+ }
+ else
+ {
+ ret_code = gatt_send_error_rsp (p_tcb, status, op_code, p_tcb->sr_cmd.handle, FALSE);
+ }
+
+ gatt_dequeue_sr_cmd(p_tcb);
+ }
+
+ GATT_TRACE_DEBUG1("gatt_sr_process_app_rsp ret_code=%d", ret_code);
+
+ return ret_code;
+}
+
+/*******************************************************************************
+**
+** Function gatt_process_exec_write_req
+**
+** Description This function is called to process the execute write request
+** from client.
+**
+** Returns void
+**
+*******************************************************************************/
+void gatt_process_exec_write_req (tGATT_TCB *p_tcb, UINT8 op_code, UINT16 len, UINT8 *p_data)
+{
+ UINT8 *p = p_data, flag, i = 0;
+ UINT32 trans_id = 0;
+ BT_HDR *p_buf;
+ tGATT_IF gatt_if;
+ UINT16 conn_id;
+
+ STREAM_TO_UINT8(flag, p);
+
+ /* mask the flag */
+ flag &= GATT_PREP_WRITE_EXEC;
+
+
+ /* no prep write is queued */
+ if (!gatt_sr_is_prep_cnt_zero(p_tcb))
+ {
+ trans_id = gatt_sr_enqueue_cmd(p_tcb, op_code, 0);
+ gatt_sr_copy_prep_cnt_to_cback_cnt(p_tcb);
+
+ for (i=0; i<GATT_MAX_APPS; i++)
+ {
+ if (p_tcb->prep_cnt[i])
+ {
+ gatt_if = (tGATT_IF) (i+1);
+ conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, gatt_if);
+ gatt_sr_send_req_callback(conn_id,
+ trans_id,
+ GATTS_REQ_TYPE_WRITE_EXEC,
+ (tGATTS_DATA *)&flag);
+ p_tcb->prep_cnt[i]= 0;
+ }
+ }
+ }
+ else /* nothing needs to be executed , send response now */
+ {
+ GATT_TRACE_ERROR0("gatt_process_exec_write_req: no prepare write pending");
+
+ if ((p_buf = attp_build_sr_msg(p_tcb, GATT_RSP_EXEC_WRITE, NULL)) != NULL)
+ {
+ attp_send_sr_msg (p_tcb, p_buf);
+ }
+
+ }
+}
+
+/*******************************************************************************
+**
+** Function gatt_process_read_multi_req
+**
+** Description This function is called to process the read multiple request
+** from client.
+**
+** Returns void
+**
+*******************************************************************************/
+void gatt_process_read_multi_req (tGATT_TCB *p_tcb, UINT8 op_code, UINT16 len, UINT8 *p_data)
+{
+ UINT32 trans_id;
+ UINT16 handle, ll = len;
+ UINT8 *p = p_data, i_rcb;
+ tGATT_STATUS err = GATT_SUCCESS;
+ UINT8 sec_flag, key_size;
+ tGATTS_RSP *p_msg;
+
+ GATT_TRACE_DEBUG0("gatt_process_read_multi_req" );
+ p_tcb->sr_cmd.multi_req.num_handles = 0;
+
+ gatt_sr_get_sec_info(p_tcb->peer_bda,
+ (BOOLEAN)(p_tcb->att_lcid == L2CAP_ATT_CID),
+ &sec_flag,
+ &key_size);
+
+#if GATT_CONFORMANCE_TESTING == TRUE
+ if (gatt_cb.enable_err_rsp && gatt_cb.req_op_code == op_code)
+ {
+ GATT_TRACE_DEBUG1("Conformance tst: forced err rspvofr ReadMultiple: error status=%d", gatt_cb.err_status);
+
+ STREAM_TO_UINT16(handle, p);
+
+ gatt_send_error_rsp (p_tcb, gatt_cb.err_status, gatt_cb.req_op_code, handle, FALSE);
+
+ return;
+ }
+#endif
+
+ while (ll >= 2 && p_tcb->sr_cmd.multi_req.num_handles < GATT_MAX_READ_MULTI_HANDLES)
+ {
+ STREAM_TO_UINT16(handle, p);
+
+ if ((i_rcb = gatt_sr_find_i_rcb_by_handle(handle)) < GATT_MAX_SR_PROFILES)
+ {
+ p_tcb->sr_cmd.multi_req.handles[p_tcb->sr_cmd.multi_req.num_handles++] = handle;
+
+ /* check read permission */
+ if ((err = gatts_read_attr_perm_check( gatt_cb.sr_reg[i_rcb].p_db,
+ FALSE,
+ handle,
+ sec_flag,
+ key_size))
+ != GATT_SUCCESS)
+ {
+ GATT_TRACE_DEBUG1("read permission denied : 0x%02x", err);
+ break;
+ }
+ }
+ else
+ {
+ /* invalid handle */
+ err = GATT_INVALID_HANDLE;
+ break;
+ }
+ ll -= 2;
+ }
+
+ if (ll != 0)
+ {
+ GATT_TRACE_ERROR0("max attribute handle reached in ReadMultiple Request.");
+ }
+
+ if (p_tcb->sr_cmd.multi_req.num_handles == 0)
+ err = GATT_INVALID_HANDLE;
+
+ if (err == GATT_SUCCESS)
+ {
+ if ((trans_id = gatt_sr_enqueue_cmd (p_tcb, op_code, p_tcb->sr_cmd.multi_req.handles[0])) != 0)
+ {
+ gatt_sr_reset_cback_cnt(p_tcb); /* read multiple use multi_rsp_q's count*/
+
+ for (ll = 0; ll < p_tcb->sr_cmd.multi_req.num_handles; ll ++)
+ {
+ if ((p_msg = (tGATTS_RSP *)GKI_getbuf(sizeof(tGATTS_RSP))) != NULL)
+ {
+ memset(p_msg, 0, sizeof(tGATTS_RSP))
+ ;
+ handle = p_tcb->sr_cmd.multi_req.handles[ll];
+ i_rcb = gatt_sr_find_i_rcb_by_handle(handle);
+
+ p_msg->attr_value.handle = handle;
+ err = gatts_read_attr_value_by_handle(p_tcb,
+ gatt_cb.sr_reg[i_rcb].p_db,
+ op_code,
+ handle,
+ 0,
+ p_msg->attr_value.value,
+ &p_msg->attr_value.len,
+ GATT_MAX_ATTR_LEN,
+ sec_flag,
+ key_size,
+ trans_id);
+
+ if (err == GATT_SUCCESS)
+ {
+ gatt_sr_process_app_rsp(p_tcb, gatt_cb.sr_reg[i_rcb].gatt_if ,trans_id, op_code, GATT_SUCCESS, p_msg);
+ }
+ /* either not using or done using the buffer, release it now */
+ GKI_freebuf(p_msg);
+ }
+ else
+ {
+ err = GATT_NO_RESOURCES;
+ gatt_dequeue_sr_cmd(p_tcb);
+ break;
+ }
+ }
+ }
+ else
+ err = GATT_NO_RESOURCES;
+ }
+
+ /* in theroy BUSY is not possible(should already been checked), protected check */
+ if (err != GATT_SUCCESS && err != GATT_PENDING && err != GATT_BUSY)
+ gatt_send_error_rsp(p_tcb, err, op_code, handle, FALSE);
+}
+
+/*******************************************************************************
+**
+** Function gatt_build_primary_service_rsp
+**
+** Description Primamry service request processed internally. Theretically
+** only deal with ReadByTypeVAlue and ReadByGroupType.
+**
+** Returns void
+**
+*******************************************************************************/
+static tGATT_STATUS gatt_build_primary_service_rsp (BT_HDR *p_msg, tGATT_TCB *p_tcb,
+ UINT8 op_code, UINT16 s_hdl,
+ UINT16 e_hdl, UINT8 *p_data, tBT_UUID value)
+{
+ tGATT_STATUS status = GATT_NOT_FOUND;
+ UINT8 handle_len =4, *p ;
+ tGATT_SR_REG *p_rcb;
+ tGATT_SRV_LIST_INFO *p_list= &gatt_cb.srv_list_info;
+ tGATT_SRV_LIST_ELEM *p_srv=NULL;
+ tBT_UUID *p_uuid;
+
+ p = (UINT8 *)(p_msg + 1) + L2CAP_MIN_OFFSET;
+
+ p_srv = p_list->p_first;
+
+ while (p_srv)
+ {
+ p_rcb = GATT_GET_SR_REG_PTR(p_srv->i_sreg);
+
+ if (p_rcb->in_use &&
+ p_rcb->s_hdl >= s_hdl &&
+ p_rcb->s_hdl <= e_hdl &&
+ p_rcb->type == GATT_UUID_PRI_SERVICE)
+ {
+ p_uuid = gatts_get_service_uuid (p_rcb->p_db);
+
+ if (op_code == GATT_REQ_READ_BY_GRP_TYPE)
+ handle_len = 4 + p_uuid->len;
+
+ /* get the length byte in the repsonse */
+ if (p_msg->offset ==0)
+ {
+ *p ++ = op_code + 1;
+ p_msg->len ++;
+ p_msg->offset = handle_len;
+
+ if (op_code == GATT_REQ_READ_BY_GRP_TYPE)
+ {
+ *p ++ = (UINT8)p_msg->offset; /* length byte */
+ p_msg->len ++;
+ }
+ }
+
+ if (p_msg->len + p_msg->offset <= p_tcb->payload_size &&
+ handle_len == p_msg->offset)
+ {
+ if (op_code != GATT_REQ_FIND_TYPE_VALUE ||
+ gatt_uuid_compare(value, *p_uuid))
+ {
+ UINT16_TO_STREAM(p, p_rcb->s_hdl);
+
+ if (p_list->p_last_primary == p_srv &&
+ p_list->p_last_primary == p_list->p_last)
+ {
+ GATT_TRACE_DEBUG0("Use 0xFFFF for the last primary attribute");
+ UINT16_TO_STREAM(p, 0xFFFF); /* see GATT ERRATA 4065, 4063, ATT ERRATA 4062 */
+ }
+ else
+ {
+ UINT16_TO_STREAM(p, p_rcb->e_hdl);
+ }
+
+ if (op_code == GATT_REQ_READ_BY_GRP_TYPE)
+ gatt_build_uuid_to_stream(&p, *p_uuid);
+
+ status = GATT_SUCCESS;
+ p_msg->len += p_msg->offset;
+ }
+ }
+ else
+ break;
+ }
+ p_srv = p_srv->p_next;
+ }
+ p_msg->offset = L2CAP_MIN_OFFSET;
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function gatt_build_find_info_rsp
+**
+** Description fill the find information response information in the given
+** buffer.
+**
+** Returns TRUE: if data filled sucessfully.
+** FALSE: packet full, or format mismatch.
+**
+*******************************************************************************/
+static tGATT_STATUS gatt_build_find_info_rsp(tGATT_SR_REG *p_rcb, BT_HDR *p_msg, UINT16 *p_len,
+ UINT16 s_hdl, UINT16 e_hdl)
+{
+ tGATT_STATUS status = GATT_NOT_FOUND;
+ UINT8 *p;
+ UINT16 len = *p_len;
+ tGATT_ATTR16 *p_attr = NULL;
+ UINT8 info_pair_len[2] = {4, 18};
+
+ if (!p_rcb->p_db || !p_rcb->p_db->p_attr_list)
+ return status;
+
+ /* check the attribute database */
+ p_attr = (tGATT_ATTR16 *) p_rcb->p_db->p_attr_list;
+
+ p = (UINT8 *)(p_msg + 1) + L2CAP_MIN_OFFSET + p_msg->len;
+
+ while (p_attr)
+ {
+ if (p_attr->handle > e_hdl)
+ {
+ break;
+ }
+
+ if (p_attr->handle >= s_hdl)
+ {
+ if (p_msg->offset == 0)
+ p_msg->offset = (p_attr->uuid_type == GATT_ATTR_UUID_TYPE_128) ? GATT_INFO_TYPE_PAIR_128 : GATT_INFO_TYPE_PAIR_16;
+
+ if (len >= info_pair_len[p_msg->offset - 1])
+ {
+ if (p_msg->offset == GATT_INFO_TYPE_PAIR_16 && p_attr->uuid_type == GATT_ATTR_UUID_TYPE_16)
+ {
+ UINT16_TO_STREAM(p, p_attr->handle);
+ UINT16_TO_STREAM(p, p_attr->uuid);
+ }
+ else if (p_msg->offset == GATT_INFO_TYPE_PAIR_128 &&
+ p_attr->uuid_type == GATT_ATTR_UUID_TYPE_128 )
+ {
+ UINT16_TO_STREAM(p, p_attr->handle);
+ ARRAY_TO_STREAM (p, ((tGATT_ATTR128 *) p_attr)->uuid, LEN_UUID_128);
+ }
+ else
+ {
+ GATT_TRACE_ERROR0("format mismatch");
+ status = GATT_NO_RESOURCES;
+ break;
+ /* format mismatch */
+ }
+ p_msg->len += info_pair_len[p_msg->offset - 1];
+ len -= info_pair_len[p_msg->offset - 1];
+ status = GATT_SUCCESS;
+
+ }
+ else
+ {
+ status = GATT_NO_RESOURCES;
+ break;
+ }
+ }
+ p_attr = (tGATT_ATTR16 *)p_attr->p_next;
+ }
+
+ *p_len = len;
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function gatts_internal_read_by_type_req
+**
+** Description check to see if the ReadByType request can be handled internally.
+**
+** Returns void
+**
+*******************************************************************************/
+static tGATT_STATUS gatts_validate_packet_format(UINT8 op_code, UINT16 *p_len,
+ UINT8 **p_data, tBT_UUID *p_uuid_filter,
+ UINT16 *p_s_hdl, UINT16 *p_e_hdl)
+{
+ tGATT_STATUS reason = GATT_SUCCESS;
+ UINT16 uuid_len, s_hdl = 0, e_hdl = 0;
+ UINT16 len = *p_len;
+ UINT8 *p = *p_data;
+
+ if (len >= 4)
+ {
+ /* obtain starting handle, and ending handle */
+ STREAM_TO_UINT16(s_hdl, p);
+ STREAM_TO_UINT16(e_hdl, p);
+ len -= 4;
+
+ if (s_hdl > e_hdl || !GATT_HANDLE_IS_VALID(s_hdl) || !GATT_HANDLE_IS_VALID(e_hdl))
+ {
+ reason = GATT_INVALID_HANDLE;
+ }
+ /* for these PDUs, uuid filter must present */
+ else if (op_code == GATT_REQ_READ_BY_GRP_TYPE ||
+ op_code == GATT_REQ_FIND_TYPE_VALUE ||
+ op_code == GATT_REQ_READ_BY_TYPE)
+ {
+ if (len >= 2 && p_uuid_filter != NULL)
+ {
+ uuid_len = (op_code == GATT_REQ_FIND_TYPE_VALUE) ? 2 : len;
+
+ /* parse uuid now */
+ if (gatt_parse_uuid_from_cmd (p_uuid_filter, uuid_len, &p) == FALSE ||
+ p_uuid_filter->len == 0)
+ {
+ GATT_TRACE_DEBUG0("UUID filter does not exsit");
+ reason = GATT_INVALID_PDU;
+ }
+ else
+ len -= p_uuid_filter->len;
+ }
+ else
+ reason = GATT_INVALID_PDU;
+ }
+ }
+
+ *p_data = p;
+ *p_len = len;
+ *p_s_hdl = s_hdl;
+ *p_e_hdl = e_hdl;
+
+ return reason;
+}
+
+/*******************************************************************************
+**
+** Function gatts_process_primary_service_req
+**
+** Description process ReadByGroupType/ReadByTypeValue request, for discover
+** all primary services or discover primary service by UUID request.
+**
+** Returns void
+**
+*******************************************************************************/
+void gatts_process_primary_service_req(tGATT_TCB *p_tcb, UINT8 op_code, UINT16 len, UINT8 *p_data)
+{
+ UINT8 reason = GATT_INVALID_PDU;
+ UINT16 s_hdl = 0, e_hdl = 0;
+ tBT_UUID uuid, value, primary_service = {LEN_UUID_16, {GATT_UUID_PRI_SERVICE}};
+ BT_HDR *p_msg = NULL;
+ UINT16 msg_len = (UINT16)(sizeof(BT_HDR) + p_tcb->payload_size + L2CAP_MIN_OFFSET);
+
+ reason = gatts_validate_packet_format(op_code, &len, &p_data, &uuid, &s_hdl, &e_hdl);
+
+ if (reason == GATT_SUCCESS)
+ {
+ if (gatt_uuid_compare(uuid, primary_service))
+ {
+ if (op_code == GATT_REQ_FIND_TYPE_VALUE)
+ {
+ if (gatt_parse_uuid_from_cmd(&value, len, &p_data) == FALSE)
+ reason = GATT_INVALID_PDU;
+ }
+
+ if (reason == GATT_SUCCESS)
+ {
+ if ((p_msg = (BT_HDR *)GKI_getbuf(msg_len)) == NULL)
+ {
+ GATT_TRACE_ERROR0("gatts_process_primary_service_req failed. no resources.");
+ reason = GATT_NO_RESOURCES;
+ }
+ else
+ {
+ memset(p_msg, 0, msg_len);
+ reason = gatt_build_primary_service_rsp (p_msg, p_tcb, op_code, s_hdl, e_hdl, p_data, value);
+ }
+ }
+ }
+ else
+ {
+ if (op_code == GATT_REQ_READ_BY_GRP_TYPE)
+ {
+ reason = GATT_UNSUPPORT_GRP_TYPE;
+ GATT_TRACE_DEBUG1("unexpected ReadByGrpType Group: 0x%04x", uuid.uu.uuid16);
+ }
+ else
+ {
+ /* we do not support ReadByTypeValue with any non-primamry_service type */
+ reason = GATT_NOT_FOUND;
+ GATT_TRACE_DEBUG1("unexpected ReadByTypeValue type: 0x%04x", uuid.uu.uuid16);
+ }
+ }
+ }
+
+ if (reason != GATT_SUCCESS)
+ {
+ if (p_msg) GKI_freebuf(p_msg);
+ gatt_send_error_rsp (p_tcb, reason, op_code, s_hdl, FALSE);
+ }
+ else
+ attp_send_sr_msg(p_tcb, p_msg);
+
+}
+
+/*******************************************************************************
+**
+** Function gatts_process_find_info
+**
+** Description process find information request, for discover character
+** descriptors.
+**
+** Returns void
+**
+*******************************************************************************/
+static void gatts_process_find_info(tGATT_TCB *p_tcb, UINT8 op_code, UINT16 len, UINT8 *p_data)
+{
+ UINT8 reason = GATT_INVALID_PDU, *p;
+ UINT16 s_hdl = 0, e_hdl = 0, buf_len;
+ BT_HDR *p_msg = NULL;
+ tGATT_SR_REG *p_rcb;
+ tGATT_SRV_LIST_INFO *p_list= &gatt_cb.srv_list_info;
+ tGATT_SRV_LIST_ELEM *p_srv=NULL;
+
+ reason = gatts_validate_packet_format(op_code, &len, &p_data, NULL, &s_hdl, &e_hdl);
+
+ if (reason == GATT_SUCCESS)
+ {
+ buf_len = (UINT16)(sizeof(BT_HDR) + p_tcb->payload_size + L2CAP_MIN_OFFSET);
+
+ if ((p_msg = (BT_HDR *)GKI_getbuf(buf_len)) == NULL)
+ {
+ reason = GATT_NO_RESOURCES;
+ }
+ else
+ {
+ reason = GATT_NOT_FOUND;
+
+ memset(p_msg, 0, buf_len);
+ p = (UINT8 *)(p_msg + 1) + L2CAP_MIN_OFFSET;
+ *p ++ = op_code + 1;
+ p_msg->len = 2;
+
+ buf_len = p_tcb->payload_size - 2;
+
+ p_srv = p_list->p_first;
+
+ while (p_srv)
+ {
+ p_rcb = GATT_GET_SR_REG_PTR(p_srv->i_sreg);
+
+ if (p_rcb->in_use &&
+ !(p_rcb->s_hdl > e_hdl ||
+ p_rcb->e_hdl < s_hdl))
+ {
+ reason = gatt_build_find_info_rsp(p_rcb, p_msg, &buf_len, s_hdl, e_hdl);
+ if (reason == GATT_NO_RESOURCES)
+ {
+ reason = GATT_SUCCESS;
+ break;
+ }
+ }
+ p_srv = p_srv->p_next;
+ }
+ *p = (UINT8)p_msg->offset;
+
+ p_msg->offset = L2CAP_MIN_OFFSET;
+ }
+ }
+
+ if (reason != GATT_SUCCESS)
+ {
+ if (p_msg) GKI_freebuf(p_msg);
+ gatt_send_error_rsp (p_tcb, reason, op_code, s_hdl, FALSE);
+ }
+ else
+ attp_send_sr_msg(p_tcb, p_msg);
+
+}
+
+/*******************************************************************************
+**
+** Function gatts_process_mtu_req
+**
+** Description This function is called to process excahnge MTU request.
+** Only used on LE.
+**
+** Returns void
+**
+*******************************************************************************/
+static void gatts_process_mtu_req (tGATT_TCB *p_tcb, UINT16 len, UINT8 *p_data)
+{
+ UINT16 mtu = 0;
+ UINT8 *p = p_data, i;
+ BT_HDR *p_buf;
+ UINT16 conn_id;
+
+ STREAM_TO_UINT16 (mtu, p);
+
+ /* BR/EDR conenction, send error response */
+ if (p_tcb->att_lcid != L2CAP_ATT_CID)
+ {
+ gatt_send_error_rsp (p_tcb, GATT_REQ_NOT_SUPPORTED, GATT_REQ_MTU, 0, FALSE);
+ }
+ else
+ {
+ /* mtu must be greater than default MTU which is 23/48 */
+ if (mtu <= GATT_MAX_MTU_SIZE)
+ p_tcb->payload_size = mtu;
+ else
+ p_tcb->payload_size = GATT_MAX_MTU_SIZE;
+
+ if ((p_buf = attp_build_sr_msg(p_tcb, GATT_RSP_MTU, (tGATT_SR_MSG *) &p_tcb->payload_size)) != NULL)
+ {
+ attp_send_sr_msg (p_tcb, p_buf);
+
+ /* Notify all registered applicaiton with new MTU size. Us a transaction ID */
+ /* of 0, as no response is allowed from applcations */
+
+ for (i = 0; i < GATT_MAX_APPS; i ++)
+ {
+ if (gatt_cb.cl_rcb[i].in_use )
+ {
+ conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, gatt_cb.cl_rcb[i].gatt_if);
+ gatt_sr_send_req_callback(conn_id, 0, GATTS_REQ_TYPE_MTU,
+ (tGATTS_DATA *)&p_tcb->payload_size);
+ }
+ }
+
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function gatts_process_read_by_type_req
+**
+** Description process Read By type request.
+** This PDU can be used to perform:
+** - read characteristic value
+** - read characteristic descriptor value
+** - discover characteristic
+** - discover characteristic by UUID
+** - relationship discovery
+**
+** Returns void
+**
+*******************************************************************************/
+void gatts_process_read_by_type_req(tGATT_TCB *p_tcb, UINT8 op_code, UINT16 len, UINT8 *p_data)
+{
+ tBT_UUID uuid;
+ tGATT_SR_REG *p_rcb;
+ UINT16 msg_len = (UINT16)(sizeof(BT_HDR) + p_tcb->payload_size + L2CAP_MIN_OFFSET),
+ buf_len,
+ s_hdl, e_hdl, err_hdl = 0;
+ BT_HDR *p_msg = NULL;
+ tGATT_STATUS reason, ret;
+ UINT8 *p;
+ UINT8 sec_flag, key_size;
+ tGATT_SRV_LIST_INFO *p_list= &gatt_cb.srv_list_info;
+ tGATT_SRV_LIST_ELEM *p_srv=NULL;
+
+ reason = gatts_validate_packet_format(op_code, &len, &p_data, &uuid, &s_hdl, &e_hdl);
+
+#if GATT_CONFORMANCE_TESTING == TRUE
+ if (gatt_cb.enable_err_rsp && gatt_cb.req_op_code == op_code)
+ {
+ GATT_TRACE_DEBUG1("Conformance tst: forced err rsp for ReadByType: error status=%d", gatt_cb.err_status);
+
+ gatt_send_error_rsp (p_tcb, gatt_cb.err_status, gatt_cb.req_op_code, s_hdl, FALSE);
+
+ return;
+ }
+#endif
+
+ if (reason == GATT_SUCCESS)
+ {
+ if ((p_msg = (BT_HDR *)GKI_getbuf(msg_len)) == NULL)
+ {
+ GATT_TRACE_ERROR0("gatts_process_find_info failed. no resources.");
+
+ reason = GATT_NO_RESOURCES;
+ }
+ else
+ {
+ memset(p_msg, 0, msg_len);
+ p = (UINT8 *)(p_msg + 1) + L2CAP_MIN_OFFSET;
+
+ *p ++ = op_code + 1;
+ /* reserve length byte */
+ p_msg->len = 2;
+ buf_len = p_tcb->payload_size - 2;
+
+ reason = GATT_NOT_FOUND;
+
+ p_srv = p_list->p_first;
+
+ while (p_srv)
+ {
+ p_rcb = GATT_GET_SR_REG_PTR(p_srv->i_sreg);
+
+ if (p_rcb->in_use &&
+ !(p_rcb->s_hdl > e_hdl ||
+ p_rcb->e_hdl < s_hdl))
+ {
+ gatt_sr_get_sec_info(p_tcb->peer_bda,
+ (BOOLEAN)(p_tcb->att_lcid == L2CAP_ATT_CID),
+ &sec_flag,
+ &key_size);
+
+ ret = gatts_db_read_attr_value_by_type(p_tcb,
+ p_rcb->p_db,
+ op_code,
+ p_msg,
+ s_hdl,
+ e_hdl,
+ uuid,
+ &buf_len,
+ sec_flag,
+ key_size,
+ 0,
+ &err_hdl);
+ if (ret != GATT_NOT_FOUND)
+ {
+ reason = ret;
+
+ if (ret == GATT_NO_RESOURCES)
+ reason = GATT_SUCCESS;
+ }
+ if (ret != GATT_SUCCESS && ret != GATT_NOT_FOUND)
+ {
+ s_hdl = err_hdl;
+ break;
+ }
+ }
+ p_srv = p_srv->p_next;
+ }
+ *p = (UINT8)p_msg->offset;
+ p_msg->offset = L2CAP_MIN_OFFSET;
+ }
+ }
+ if (reason != GATT_SUCCESS)
+ {
+ if (p_msg) GKI_freebuf(p_msg);
+
+ /* in theroy BUSY is not possible(should already been checked), protected check */
+ if (reason != GATT_PENDING && reason != GATT_BUSY)
+ gatt_send_error_rsp (p_tcb, reason, op_code, s_hdl, FALSE);
+ }
+ else
+ attp_send_sr_msg(p_tcb, p_msg);
+
+}
+
+/*******************************************************************************
+**
+** Function gatts_process_write_req
+**
+** Description This function is called to process the write request
+** from client.
+**
+** Returns void
+**
+*******************************************************************************/
+void gatts_process_write_req (tGATT_TCB *p_tcb, UINT8 i_rcb, UINT16 handle,
+ UINT8 op_code, UINT16 len, UINT8 *p_data)
+{
+ tGATTS_DATA sr_data;
+ UINT32 trans_id;
+ tGATT_STATUS status;
+ UINT8 sec_flag, key_size, *p = p_data;
+ tGATT_SR_REG *p_sreg;
+ UINT16 conn_id;
+
+ memset(&sr_data, 0, sizeof(tGATTS_DATA));
+
+ switch (op_code)
+ {
+ case GATT_REQ_PREPARE_WRITE:
+ sr_data.write_req.is_prep = TRUE;
+ STREAM_TO_UINT16(sr_data.write_req.offset, p);
+ len -= 2;
+ /* fall through */
+ case GATT_SIGN_CMD_WRITE:
+ if (op_code == GATT_SIGN_CMD_WRITE)
+ {
+ GATT_TRACE_DEBUG0("Write CMD with data sigining" );
+ len -= GATT_AUTH_SIGN_LEN;
+ }
+ /* fall through */
+ case GATT_CMD_WRITE:
+ case GATT_REQ_WRITE:
+ if (op_code == GATT_REQ_WRITE || op_code == GATT_REQ_PREPARE_WRITE)
+ sr_data.write_req.need_rsp = TRUE;
+ sr_data.write_req.handle = handle;
+ sr_data.write_req.len = len;
+ memcpy (sr_data.write_req.value, p, len);
+ break;
+ }
+
+ gatt_sr_get_sec_info(p_tcb->peer_bda,
+ (BOOLEAN)(p_tcb->att_lcid == L2CAP_ATT_CID),
+ &sec_flag,
+ &key_size);
+
+ status = gatts_write_attr_perm_check (gatt_cb.sr_reg[i_rcb].p_db,
+ op_code,
+ handle,
+ sr_data.write_req.offset,
+ p,
+ len,
+ sec_flag,
+ key_size);
+
+ if (status == GATT_SUCCESS)
+ {
+ if ((trans_id = gatt_sr_enqueue_cmd(p_tcb, op_code, handle)) != 0)
+ {
+ p_sreg = &gatt_cb.sr_reg[i_rcb];
+ conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_sreg->gatt_if);
+ gatt_sr_send_req_callback(conn_id,
+ trans_id,
+ GATTS_REQ_TYPE_WRITE,
+ &sr_data);
+
+ status = GATT_PENDING;
+ }
+ else
+ {
+ GATT_TRACE_ERROR0("max pending command, send error");
+ status = GATT_BUSY; /* max pending command, application error */
+ }
+ }
+
+ /* in theroy BUSY is not possible(should already been checked), protected check */
+ if (status != GATT_PENDING && status != GATT_BUSY &&
+ (op_code == GATT_REQ_PREPARE_WRITE || op_code == GATT_REQ_WRITE))
+ {
+ gatt_send_error_rsp (p_tcb, status, op_code, handle, FALSE);
+ }
+ return;
+}
+
+/*******************************************************************************
+**
+** Function gatts_process_read_req
+**
+** Description This function is called to process the read request
+** from client.
+**
+** Returns void
+**
+*******************************************************************************/
+static void gatts_process_read_req(tGATT_TCB *p_tcb, tGATT_SR_REG *p_rcb, UINT8 op_code,
+ UINT16 handle, UINT16 len, UINT8 *p_data)
+{
+ UINT16 buf_len = (UINT16)(sizeof(BT_HDR) + p_tcb->payload_size + L2CAP_MIN_OFFSET);
+ tGATT_STATUS reason;
+ BT_HDR *p_msg = NULL;
+ UINT8 sec_flag, key_size, *p;
+ UINT16 offset = 0, value_len = 0;
+
+ if ((p_msg = (BT_HDR *)GKI_getbuf(buf_len)) == NULL)
+ {
+ GATT_TRACE_ERROR0("gatts_process_find_info failed. no resources.");
+
+ reason = GATT_NO_RESOURCES;
+ }
+ else
+ {
+ if (op_code == GATT_REQ_READ_BLOB)
+ STREAM_TO_UINT16(offset, p_data);
+
+ memset(p_msg, 0, buf_len);
+ p = (UINT8 *)(p_msg + 1) + L2CAP_MIN_OFFSET;
+ *p ++ = op_code + 1;
+ p_msg->len = 1;
+ buf_len = p_tcb->payload_size - 1;
+
+ gatt_sr_get_sec_info(p_tcb->peer_bda,
+ (BOOLEAN)(p_tcb->att_lcid == L2CAP_ATT_CID),
+ &sec_flag,
+ &key_size);
+
+ reason = gatts_read_attr_value_by_handle(p_tcb,
+ p_rcb->p_db,
+ op_code,
+ handle,
+ offset,
+ p,
+ &value_len,
+ buf_len,
+ sec_flag,
+ key_size,
+ 0);
+
+ p_msg->len += value_len;
+ }
+
+ if (reason != GATT_SUCCESS)
+ {
+ if (p_msg) GKI_freebuf(p_msg);
+
+ /* in theroy BUSY is not possible(should already been checked), protected check */
+ if (reason != GATT_PENDING && reason != GATT_BUSY)
+ gatt_send_error_rsp (p_tcb, reason, op_code, handle, FALSE);
+ }
+ else
+ attp_send_sr_msg(p_tcb, p_msg);
+
+}
+
+/*******************************************************************************
+**
+** Function gatts_process_attribute_req
+**
+** Description This function is called to process the per attribute handle request
+** from client.
+**
+** Returns void
+**
+*******************************************************************************/
+void gatts_process_attribute_req (tGATT_TCB *p_tcb, UINT8 op_code,
+ UINT16 len, UINT8 *p_data)
+{
+ UINT16 handle;
+ UINT8 *p = p_data, i;
+ tGATT_SR_REG *p_rcb = gatt_cb.sr_reg;
+ tGATT_STATUS status = GATT_INVALID_HANDLE;
+ tGATT_ATTR16 *p_attr;
+
+ STREAM_TO_UINT16(handle, p);
+ len -= 2;
+
+#if GATT_CONFORMANCE_TESTING == TRUE
+ if (gatt_cb.enable_err_rsp && gatt_cb.req_op_code == op_code)
+ {
+ GATT_TRACE_DEBUG1("Conformance tst: forced err rsp: error status=%d", gatt_cb.err_status);
+
+ gatt_send_error_rsp (p_tcb, gatt_cb.err_status, gatt_cb.req_op_code, handle, FALSE);
+
+ return;
+ }
+#endif
+
+ if (GATT_HANDLE_IS_VALID(handle))
+ {
+ for (i = 0; i < GATT_MAX_SR_PROFILES; i ++, p_rcb ++)
+ {
+ if (p_rcb->in_use && p_rcb->s_hdl <= handle && p_rcb->e_hdl >= handle)
+ {
+ p_attr = (tGATT_ATTR16 *)p_rcb->p_db->p_attr_list;
+
+ while (p_attr)
+ {
+ if (p_attr->handle == handle)
+ {
+ switch (op_code)
+ {
+ case GATT_REQ_READ: /* read char/char descriptor value */
+ case GATT_REQ_READ_BLOB:
+ gatts_process_read_req(p_tcb, p_rcb, op_code, handle, len, p);
+ break;
+
+ case GATT_REQ_WRITE: /* write char/char descriptor value */
+ case GATT_CMD_WRITE:
+ case GATT_SIGN_CMD_WRITE:
+ case GATT_REQ_PREPARE_WRITE:
+ gatts_process_write_req(p_tcb, i, handle, op_code, len, p);
+ break;
+ default:
+ break;
+ }
+ status = GATT_SUCCESS;
+ break;
+ }
+ p_attr = (tGATT_ATTR16 *)p_attr->p_next;
+ }
+ break;
+ }
+ }
+ }
+
+ if (status != GATT_SUCCESS && op_code != GATT_CMD_WRITE && op_code != GATT_SIGN_CMD_WRITE)
+ gatt_send_error_rsp (p_tcb, status, op_code, handle, FALSE);
+}
+
+/*******************************************************************************
+**
+** Function gatts_proc_srv_chg_ind_ack
+**
+** Description This function process the service changed indicaiton ACK
+**
+** Returns void
+**
+*******************************************************************************/
+static void gatts_proc_srv_chg_ind_ack(tGATT_TCB *p_tcb )
+{
+ tGATTS_SRV_CHG_REQ req;
+ tGATTS_SRV_CHG *p_buf = NULL;
+
+ GATT_TRACE_DEBUG0("gatts_proc_srv_chg_ind_ack");
+
+ if ((p_buf = gatt_is_bda_in_the_srv_chg_clt_list(p_tcb->peer_bda)) != NULL)
+ {
+ GATT_TRACE_DEBUG0("NV update set srv chg = FALSE");
+ p_buf->srv_changed = FALSE;
+ memcpy(&req.srv_chg, p_buf, sizeof(tGATTS_SRV_CHG));
+ if (gatt_cb.cb_info.p_srv_chg_callback)
+ (*gatt_cb.cb_info.p_srv_chg_callback)(GATTS_SRV_CHG_CMD_UPDATE_CLIENT,&req, NULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function gatts_chk_pending_ind
+**
+** Description This function check any pending indication needs to be sent if
+** there is a pending indication then sent the indication
+**
+** Returns void
+**
+*******************************************************************************/
+static void gatts_chk_pending_ind(tGATT_TCB *p_tcb )
+{
+ tGATT_VALUE *p_buf = (tGATT_VALUE *)GKI_getfirst(&p_tcb->pending_ind_q);
+ GATT_TRACE_DEBUG0("gatts_chk_pending_ind");
+
+ if (p_buf )
+ {
+ GATTS_HandleValueIndication (p_buf->conn_id,
+ p_buf->handle,
+ p_buf->len,
+ p_buf->value);
+ GKI_freebuf(GKI_remove_from_queue (&p_tcb->pending_ind_q, p_buf));
+ }
+}
+
+/*******************************************************************************
+**
+** Function gatts_proc_ind_ack
+**
+** Description This function process the Indication ack
+**
+** Returns TRUE continue to process the indication ack by the aaplication
+** if the ACk is not a Service Changed Indication Ack
+**
+*******************************************************************************/
+static BOOLEAN gatts_proc_ind_ack(tGATT_TCB *p_tcb, UINT16 ack_handle)
+{
+ BOOLEAN continue_processing = TRUE;
+
+ GATT_TRACE_DEBUG1 ("gatts_proc_ind_ack ack handle=%d", ack_handle);
+
+ if (ack_handle == gatt_cb.handle_of_h_r)
+ {
+ gatts_proc_srv_chg_ind_ack(p_tcb);
+ /* there is no need to inform the application since srv chg is handled internally by GATT */
+ continue_processing = FALSE;
+ }
+
+ gatts_chk_pending_ind(p_tcb);
+ return continue_processing;
+}
+
+/*******************************************************************************
+**
+** Function gatts_process_value_conf
+**
+** Description This function is called to process the handle value confirmation.
+**
+** Returns void
+**
+*******************************************************************************/
+void gatts_process_value_conf(tGATT_TCB *p_tcb, UINT8 op_code)
+{
+ UINT16 handle = p_tcb->indicate_handle;
+ UINT32 trans_id;
+ UINT8 i;
+ tGATT_SR_REG *p_rcb = gatt_cb.sr_reg;
+ BOOLEAN continue_processing;
+ UINT16 conn_id;
+
+ btu_stop_timer (&p_tcb->conf_timer_ent);
+ if (GATT_HANDLE_IS_VALID(handle))
+ {
+ p_tcb->indicate_handle = 0;
+ continue_processing = gatts_proc_ind_ack(p_tcb, handle);
+
+ if (continue_processing)
+ {
+ for (i = 0; i < GATT_MAX_SR_PROFILES; i ++, p_rcb ++)
+ {
+ if (p_rcb->in_use && p_rcb->s_hdl <= handle && p_rcb->e_hdl >= handle)
+ {
+ trans_id = gatt_sr_enqueue_cmd(p_tcb, op_code, handle);
+ conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_rcb->gatt_if);
+ gatt_sr_send_req_callback(conn_id,
+ trans_id, GATTS_REQ_TYPE_CONF, (tGATTS_DATA *)&handle);
+ }
+ }
+ }
+ }
+ else
+ {
+ GATT_TRACE_ERROR0("unexpected handle value confirmation");
+ }
+}
+
+/*******************************************************************************
+**
+** Function gatt_server_handle_client_req
+**
+** Description This function is called to handle the client requests to
+** server.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void gatt_server_handle_client_req (tGATT_TCB *p_tcb, UINT8 op_code,
+ UINT16 len, UINT8 *p_data)
+{
+ /* there is pending command, discard this one */
+ if (!gatt_sr_cmd_empty(p_tcb) && op_code != GATT_HANDLE_VALUE_CONF)
+ return;
+
+ /* the size of the message may not be bigger than the local max PDU size*/
+ /* The message has to be smaller than the agreed MTU, len does not include op code */
+ if (len >= p_tcb->payload_size)
+ {
+ GATT_TRACE_ERROR2("server receive invalid PDU size:%d pdu size:%d", len + 1, p_tcb->payload_size );
+ /* for invalid request expecting response, send it now */
+ if (op_code != GATT_CMD_WRITE &&
+ op_code != GATT_SIGN_CMD_WRITE &&
+ op_code != GATT_HANDLE_VALUE_CONF)
+ {
+ gatt_send_error_rsp (p_tcb, GATT_INVALID_PDU, op_code, 0, FALSE);
+ }
+ /* otherwise, ignore the pkt */
+ }
+ else
+ {
+ switch (op_code)
+ {
+ case GATT_REQ_READ_BY_GRP_TYPE: /* discover primary services */
+ case GATT_REQ_FIND_TYPE_VALUE: /* discover service by UUID */
+ gatts_process_primary_service_req (p_tcb, op_code, len, p_data);
+ break;
+
+ case GATT_REQ_FIND_INFO:/* discover char descrptor */
+ gatts_process_find_info(p_tcb, op_code, len, p_data);
+ break;
+
+ case GATT_REQ_READ_BY_TYPE: /* read characteristic value, char descriptor value */
+ /* discover characteristic, discover char by UUID */
+ gatts_process_read_by_type_req(p_tcb, op_code, len, p_data);
+ break;
+
+
+ case GATT_REQ_READ: /* read char/char descriptor value */
+ case GATT_REQ_READ_BLOB:
+ case GATT_REQ_WRITE: /* write char/char descriptor value */
+ case GATT_CMD_WRITE:
+ case GATT_SIGN_CMD_WRITE:
+ case GATT_REQ_PREPARE_WRITE:
+ gatts_process_attribute_req (p_tcb, op_code, len, p_data);
+ break;
+
+ case GATT_HANDLE_VALUE_CONF:
+ gatts_process_value_conf (p_tcb, op_code);
+ break;
+
+ case GATT_REQ_MTU:
+ gatts_process_mtu_req (p_tcb, len, p_data);
+ break;
+
+ case GATT_REQ_EXEC_WRITE:
+ gatt_process_exec_write_req (p_tcb, op_code, len, p_data);
+ break;
+
+ case GATT_REQ_READ_MULTI:
+ gatt_process_read_multi_req (p_tcb, op_code, len, p_data);
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+#endif /* BLE_INCLUDED */
diff --git a/stack/gatt/gatt_utils.c b/stack/gatt/gatt_utils.c
new file mode 100644
index 0000000..ca72f9d
--- /dev/null
+++ b/stack/gatt/gatt_utils.c
@@ -0,0 +1,2587 @@
+/*****************************************************************************
+**
+** Name: gatt_utils.c
+**
+** Description: this file contains GATT utility functions
+**
+**
+** Copyright (c) 2009-2011, Broadcom Corp, All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+#include "bt_target.h"
+
+#if BLE_INCLUDED == TRUE
+ #include <string.h>
+ #include "stdio.h"
+ #include "gki.h"
+
+ #include "l2cdefs.h"
+ #include "gatt_int.h"
+ #include "gatt_api.h"
+ #include "gattdefs.h"
+ #include "sdp_api.h"
+ #include "btm_int.h"
+/* check if [x, y] and [a, b] have overlapping range */
+ #define GATT_VALIDATE_HANDLE_RANGE(x, y, a, b) (y >= a && x <= b)
+
+ #define GATT_GET_NEXT_VALID_HANDLE(x) (((x)/10 + 1) * 10)
+
+const char * const op_code_name[] =
+{
+ "UNKNOWN",
+ "ATT_RSP_ERROR",
+ "ATT_REQ_MTU",
+ "ATT_RSP_MTU",
+ "ATT_REQ_READ_INFO",
+ "ATT_RSP_READ_INFO",
+ "ATT_REQ_FIND_TYPE_VALUE",
+ "ATT_RSP_FIND_TYPE_VALUE",
+ "ATT_REQ_READ_BY_TYPE",
+ "ATT_RSP_READ_BY_TYPE",
+ "ATT_REQ_READ",
+ "ATT_RSP_READ",
+ "ATT_REQ_READ_BLOB",
+ "ATT_RSP_READ_BLOB",
+ "GATT_REQ_READ_MULTI",
+ "GATT_RSP_READ_MULTI",
+ "GATT_REQ_READ_BY_GRP_TYPE",
+ "GATT_RSP_READ_BY_GRP_TYPE",
+ "ATT_REQ_WRITE",
+ "ATT_RSP_WRITE",
+ "ATT_CMD_WRITE",
+ "ATT_SIGN_CMD_WRITE",
+ "ATT_REQ_PREPARE_WRITE",
+ "ATT_RSP_PREPARE_WRITE",
+ "ATT_REQ_EXEC_WRITE",
+ "ATT_RSP_EXEC_WRITE",
+ "Reserved",
+ "ATT_HANDLE_VALUE_NOTIF",
+ "Reserved",
+ "ATT_HANDLE_VALUE_IND",
+ "ATT_HANDLE_VALUE_CONF",
+ "ATT_OP_CODE_MAX"
+};
+
+static const UINT8 base_uuid[LEN_UUID_128] = {0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+
+/*******************************************************************************
+**
+** Function gatt_free_pending_ind
+**
+** Description Free all pending indications
+**
+** Returns None
+**
+*******************************************************************************/
+void gatt_free_pending_ind(tGATT_TCB *p_tcb)
+{
+ GATT_TRACE_DEBUG0("gatt_free_pending_ind");
+ /* release all queued indications */
+ while (p_tcb->pending_ind_q.p_first)
+ GKI_freebuf (GKI_dequeue (&p_tcb->pending_ind_q));
+}
+
+/*******************************************************************************
+**
+** Function gatt_delete_dev_from_srv_chg_clt_list
+**
+** Description Delete a device from the service changed client lit
+**
+** Returns None
+**
+*******************************************************************************/
+void gatt_delete_dev_from_srv_chg_clt_list(BD_ADDR bd_addr)
+{
+ tGATTS_SRV_CHG *p_buf;
+ tGATTS_SRV_CHG_REQ req;
+
+ GATT_TRACE_DEBUG0 ("gatt_delete_dev_from_srv_chg_clt_list");
+ if ((p_buf = gatt_is_bda_in_the_srv_chg_clt_list(bd_addr)) != NULL)
+ {
+ if (gatt_cb.cb_info.p_srv_chg_callback)
+ {
+ /* delete from NV */
+ memcpy(req.srv_chg.bda, bd_addr, BD_ADDR_LEN);
+ (*gatt_cb.cb_info.p_srv_chg_callback)(GATTS_SRV_CHG_CMD_REMOVE_CLIENT,&req, NULL);
+ }
+ GKI_freebuf (GKI_remove_from_queue (&gatt_cb.srv_chg_clt_q, p_buf));
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function gatt_set_srv_chg
+**
+** Description Set the service changed flag to TRUE
+**
+** Returns None
+**
+*******************************************************************************/
+void gatt_set_srv_chg(void)
+{
+ tGATTS_SRV_CHG *p_buf = (tGATTS_SRV_CHG *)GKI_getfirst(&gatt_cb.srv_chg_clt_q);
+ tGATTS_SRV_CHG_REQ req;
+
+ GATT_TRACE_DEBUG0 ("gatt_set_srv_chg");
+ while (p_buf)
+ {
+ GATT_TRACE_DEBUG0 ("found a srv_chg clt");
+ if (!p_buf->srv_changed)
+ {
+ GATT_TRACE_DEBUG0 ("set srv_changed to TRUE");
+ p_buf->srv_changed= TRUE;
+ memcpy(&req.srv_chg, p_buf, sizeof(tGATTS_SRV_CHG));
+ if (gatt_cb.cb_info.p_srv_chg_callback)
+ (*gatt_cb.cb_info.p_srv_chg_callback)(GATTS_SRV_CHG_CMD_UPDATE_CLIENT,&req, NULL);
+ }
+ p_buf = (tGATTS_SRV_CHG *)GKI_getnext(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function gatt_sr_is_new_srv_chg
+**
+** Description Find the app id in on the new service changed list
+**
+** Returns Pointer to the found new service changed item othwerwise NULL
+**
+*******************************************************************************/
+tGATTS_PENDING_NEW_SRV_START *gatt_sr_is_new_srv_chg(tBT_UUID *p_app_uuid128, tBT_UUID *p_svc_uuid, UINT16 svc_inst)
+{
+ tGATTS_HNDL_RANGE *p;
+ tGATTS_PENDING_NEW_SRV_START *p_buf = (tGATTS_PENDING_NEW_SRV_START *)GKI_getfirst(&gatt_cb.pending_new_srv_start_q);
+
+ while (p_buf != NULL)
+ {
+ p = p_buf->p_new_srv_start;
+ if ( gatt_uuid_compare (*p_app_uuid128, p->app_uuid128)
+ && gatt_uuid_compare (*p_svc_uuid, p->svc_uuid)
+ && (svc_inst == p->svc_inst) )
+ {
+ GATT_TRACE_DEBUG0 ("gatt_sr_is_new_srv_chg: Yes");
+ break;
+ }
+ p_buf = (tGATTS_PENDING_NEW_SRV_START *)GKI_getnext(p_buf);
+ }
+
+ return p_buf;
+}
+
+
+/*******************************************************************************
+**
+** Function gatt_add_pending_ind
+**
+** Description Add a pending indication
+**
+** Returns Pointer to the current pending indication buffer, NULL no buffer available
+**
+*******************************************************************************/
+tGATT_VALUE *gatt_add_pending_ind(tGATT_TCB *p_tcb, tGATT_VALUE *p_ind)
+{
+ tGATT_VALUE *p_buf;
+ GATT_TRACE_DEBUG0 ("gatt_add_pending_ind");
+ if ((p_buf = (tGATT_VALUE *)GKI_getbuf((UINT16)sizeof(tGATT_VALUE))) != NULL)
+ {
+ GATT_TRACE_DEBUG0 ("enqueue a pending indication");
+ memcpy(p_buf, p_ind, sizeof(tGATT_VALUE));
+ GKI_enqueue (&p_tcb->pending_ind_q, p_buf);
+ }
+ return p_buf;
+}
+
+
+/*******************************************************************************
+**
+** Function gatt_add_pending_new_srv_start
+**
+** Description Add a pending new srv start to the new service start queue
+**
+** Returns Pointer to the new service start buffer, NULL no buffer available
+**
+*******************************************************************************/
+tGATTS_PENDING_NEW_SRV_START *gatt_add_pending_new_srv_start(tGATTS_HNDL_RANGE *p_new_srv_start)
+{
+ tGATTS_PENDING_NEW_SRV_START *p_buf;
+
+ GATT_TRACE_DEBUG0 ("gatt_add_pending_new_srv_start");
+ if ((p_buf = (tGATTS_PENDING_NEW_SRV_START *)GKI_getbuf((UINT16)sizeof(tGATTS_PENDING_NEW_SRV_START))) != NULL)
+ {
+ GATT_TRACE_DEBUG0 ("enqueue a new pending new srv start");
+ p_buf->p_new_srv_start = p_new_srv_start;
+ GKI_enqueue (&gatt_cb.pending_new_srv_start_q, p_buf);
+ }
+ return p_buf;
+}
+
+
+/*******************************************************************************
+**
+** Function gatt_add_srv_chg_clt
+**
+** Description Add a service chnage client to the service change client queue
+**
+** Returns Pointer to the service change client buffer; Null no buffer available
+**
+*******************************************************************************/
+tGATTS_SRV_CHG *gatt_add_srv_chg_clt(tGATTS_SRV_CHG *p_srv_chg)
+{
+ tGATTS_SRV_CHG *p_buf;
+ GATT_TRACE_DEBUG0 ("gatt_add_srv_chg_clt");
+ if ((p_buf = (tGATTS_SRV_CHG *)GKI_getbuf((UINT16)sizeof(tGATTS_SRV_CHG))) != NULL)
+ {
+ GATT_TRACE_DEBUG0 ("enqueue a srv chg client");
+ memcpy(p_buf, p_srv_chg, sizeof(tGATTS_SRV_CHG));
+ GKI_enqueue (&gatt_cb.srv_chg_clt_q, p_buf);
+ }
+
+ return p_buf;
+}
+
+
+/*******************************************************************************
+**
+** Function gatt_alloc_hdl_buffer
+**
+** Description Allocate a handle buufer
+**
+** Returns Pointer to the allocated buffer, NULL no buffer available
+**
+*******************************************************************************/
+tGATT_HDL_LIST_ELEM *gatt_alloc_hdl_buffer(void)
+{
+ UINT8 i;
+ tGATT_CB *p_cb = &gatt_cb;
+ tGATT_HDL_LIST_ELEM * p_elem= &p_cb->hdl_list[0];
+
+ for (i = 0; i < GATT_MAX_SR_PROFILES; i++, p_elem ++)
+ {
+ if (!p_cb->hdl_list[i].in_use)
+ {
+ memset(p_elem, 0, sizeof(tGATT_HDL_LIST_ELEM));
+ p_elem->in_use = TRUE;
+ return p_elem;
+ }
+ }
+
+ return NULL;
+}
+
+/*******************************************************************************
+**
+** Function gatt_find_hdl_buffer_by_handle
+**
+** Description Find handle range buffer by service handle.
+**
+** Returns Pointer to the buffer, NULL no buffer available
+**
+*******************************************************************************/
+tGATT_HDL_LIST_ELEM *gatt_find_hdl_buffer_by_handle(UINT16 handle)
+{
+ tGATT_HDL_LIST_INFO *p_list_info= &gatt_cb.hdl_list_info;
+ tGATT_HDL_LIST_ELEM *p_list = NULL;
+
+ p_list = p_list_info->p_first;
+
+ while (p_list != NULL)
+ {
+ if (p_list->in_use && p_list->asgn_range.s_handle == handle)
+ {
+ return(p_list);
+ }
+ p_list = p_list->p_next;
+ }
+ return NULL;
+}
+/*******************************************************************************
+**
+** Function gatt_find_hdl_buffer_by_app_id
+**
+** Description Find handle range buffer by app ID, service and service instance ID.
+**
+** Returns Pointer to the buffer, NULL no buffer available
+**
+*******************************************************************************/
+tGATT_HDL_LIST_ELEM *gatt_find_hdl_buffer_by_app_id (tBT_UUID *p_app_uuid128,
+ tBT_UUID *p_svc_uuid,
+ UINT16 svc_inst)
+{
+ tGATT_HDL_LIST_INFO *p_list_info= &gatt_cb.hdl_list_info;
+ tGATT_HDL_LIST_ELEM *p_list = NULL;
+
+ p_list = p_list_info->p_first;
+
+ while (p_list != NULL)
+ {
+ if ( gatt_uuid_compare (*p_app_uuid128, p_list->asgn_range.app_uuid128)
+ && gatt_uuid_compare (*p_svc_uuid, p_list->asgn_range.svc_uuid)
+ && (svc_inst == p_list->asgn_range.svc_inst) )
+ {
+ GATT_TRACE_DEBUG0 ("Already allocated handles for this service before!!");
+ return(p_list);
+ }
+ p_list = p_list->p_next;
+ }
+ return NULL;
+}
+/*******************************************************************************
+**
+** Function gatt_free_hdl_buffer
+**
+** Description free a handle buffer
+**
+** Returns None
+**
+*******************************************************************************/
+void gatt_free_hdl_buffer(tGATT_HDL_LIST_ELEM *p)
+{
+
+ if (p)
+ {
+ while (p->svc_db.svc_buffer.p_first)
+ GKI_freebuf (GKI_dequeue (&p->svc_db.svc_buffer));
+ memset(p, 0, sizeof(tGATT_HDL_LIST_ELEM));
+ }
+}
+/*******************************************************************************
+**
+** Function gatt_free_srvc_db_buffer_app_id
+**
+** Description free the service attribute database buffers by the owner of the
+** service app ID.
+**
+** Returns None
+**
+*******************************************************************************/
+void gatt_free_srvc_db_buffer_app_id(tBT_UUID *p_app_id)
+{
+ tGATT_HDL_LIST_ELEM *p_elem = &gatt_cb.hdl_list[0];
+ UINT8 i;
+
+ for (i = 0; i < GATT_MAX_SR_PROFILES; i ++, p_elem ++)
+ {
+ if (memcmp(p_app_id, &p_elem->asgn_range.app_uuid128, sizeof(tBT_UUID)) == 0)
+ {
+ while (p_elem->svc_db.svc_buffer.p_first)
+ GKI_freebuf (GKI_dequeue (&p_elem->svc_db.svc_buffer));
+
+ p_elem->svc_db.mem_free = 0;
+ p_elem->svc_db.p_attr_list = p_elem->svc_db.p_free_mem = NULL;
+ }
+ }
+}
+/*******************************************************************************
+**
+** Function gatt_is_last_attribute
+**
+** Description Check this is the last attribute of the specified value or not
+**
+** Returns TRUE - yes this is the last attribute
+**
+*******************************************************************************/
+BOOLEAN gatt_is_last_attribute(tGATT_SRV_LIST_INFO *p_list, tGATT_SRV_LIST_ELEM *p_start, tBT_UUID value)
+{
+ tGATT_SRV_LIST_ELEM *p_srv= p_start->p_next;
+ BOOLEAN is_last_attribute = TRUE;
+ tGATT_SR_REG *p_rcb = NULL;
+ tBT_UUID *p_svc_uuid;
+
+ p_list->p_last_primary = NULL;
+
+ while (p_srv)
+ {
+ p_rcb = GATT_GET_SR_REG_PTR(p_srv->i_sreg);
+
+ p_svc_uuid = gatts_get_service_uuid (p_rcb->p_db);
+
+ if (gatt_uuid_compare(value, *p_svc_uuid))
+ {
+ is_last_attribute = FALSE;
+ break;
+
+ }
+ p_srv = p_srv->p_next;
+ }
+
+ return is_last_attribute;
+
+}
+
+/*******************************************************************************
+**
+** Function gatt_update_last_pri_srv_info
+**
+** Description Update the the last primary info for the service list info
+**
+** Returns None
+**
+*******************************************************************************/
+void gatt_update_last_pri_srv_info(tGATT_SRV_LIST_INFO *p_list)
+{
+ tGATT_SRV_LIST_ELEM *p_srv= p_list->p_first;
+
+ p_list->p_last_primary = NULL;
+
+ while (p_srv)
+ {
+ if (p_srv->is_primary)
+ {
+ p_list->p_last_primary = p_srv;
+ }
+ p_srv = p_srv->p_next;
+ }
+
+}
+/*******************************************************************************
+**
+** Function gatts_update_srv_list_elem
+**
+** Description update an element in the service list.
+**
+** Returns None.
+**
+*******************************************************************************/
+void gatts_update_srv_list_elem(UINT8 i_sreg, UINT16 handle, BOOLEAN is_primary)
+{
+ gatt_cb.srv_list[i_sreg].in_use = TRUE;
+ gatt_cb.srv_list[i_sreg].i_sreg = i_sreg;
+ gatt_cb.srv_list[i_sreg].s_hdl = gatt_cb.sr_reg[i_sreg].s_hdl;
+ gatt_cb.srv_list[i_sreg].is_primary = is_primary;
+
+ return;
+}
+/*******************************************************************************
+**
+** Function gatt_add_a_srv_to_list
+**
+** Description add an service to the list in ascending
+** order of the start handle
+**
+** Returns BOOLEAN TRUE-if add is successful
+**
+*******************************************************************************/
+BOOLEAN gatt_add_a_srv_to_list(tGATT_SRV_LIST_INFO *p_list, tGATT_SRV_LIST_ELEM *p_new)
+{
+ tGATT_SRV_LIST_ELEM *p_old;
+
+ if (!p_new)
+ {
+ GATT_TRACE_DEBUG0("p_new==NULL");
+ return FALSE;
+ }
+
+ if (!p_list->p_first)
+ {
+ /* this is an empty list */
+ p_list->p_first =
+ p_list->p_last = p_new;
+ p_new->p_next =
+ p_new->p_prev = NULL;
+ }
+ else
+ {
+ p_old = p_list->p_first;
+ while (1)
+ {
+ if (p_old == NULL)
+ {
+ p_list->p_last->p_next = p_new;
+ p_new->p_prev = p_list->p_last;
+ p_new->p_next = NULL;
+ p_list->p_last = p_new;
+ break;
+ }
+ else
+ {
+ if (p_new->s_hdl < p_old->s_hdl)
+ {
+ /* if not the first in list */
+ if (p_old->p_prev != NULL)
+ p_old->p_prev->p_next = p_new;
+ else
+ p_list->p_first = p_new;
+
+ p_new->p_prev = p_old->p_prev;
+ p_new->p_next = p_old;
+ p_old->p_prev = p_new;
+ break;
+ }
+ }
+ p_old = p_old->p_next;
+ }
+ }
+ p_list->count++;
+
+ gatt_update_last_pri_srv_info(p_list);
+ return TRUE;
+
+}
+
+/*******************************************************************************
+**
+** Function gatt_remove_a_srv_from_list
+**
+** Description Remove a service from the list
+**
+** Returns BOOLEAN TRUE-if remove is successful
+**
+*******************************************************************************/
+BOOLEAN gatt_remove_a_srv_from_list(tGATT_SRV_LIST_INFO *p_list, tGATT_SRV_LIST_ELEM *p_remove)
+{
+ if (!p_remove || !p_list->p_first)
+ {
+ GATT_TRACE_DEBUG0("p_remove==NULL || p_list->p_first==NULL");
+ return FALSE;
+ }
+
+ if (p_remove->p_prev == NULL)
+ {
+ p_list->p_first = p_remove->p_next;
+ if (p_remove->p_next)
+ p_remove->p_next->p_prev = NULL;
+ }
+ else if (p_remove->p_next == NULL)
+ {
+ p_list->p_last = p_remove->p_prev;
+ p_remove->p_prev->p_next = NULL;
+ }
+ else
+ {
+ p_remove->p_next->p_prev = p_remove->p_prev;
+ p_remove->p_prev->p_next = p_remove->p_next;
+ }
+ p_list->count--;
+ gatt_update_last_pri_srv_info(p_list);
+ return TRUE;
+
+}
+
+/*******************************************************************************
+**
+** Function gatt_add_an_item_to_list
+**
+** Description add an service handle range to the list in decending
+** order of the start handle
+**
+** Returns BOOLEAN TRUE-if add is successful
+**
+*******************************************************************************/
+BOOLEAN gatt_add_an_item_to_list(tGATT_HDL_LIST_INFO *p_list, tGATT_HDL_LIST_ELEM *p_new)
+{
+ tGATT_HDL_LIST_ELEM *p_old;
+ if (!p_new)
+ {
+ GATT_TRACE_DEBUG0("p_new==NULL");
+ return FALSE;
+ }
+
+ if (!p_list->p_first)
+ {
+ /* this is an empty list */
+ p_list->p_first =
+ p_list->p_last = p_new;
+ p_new->p_next =
+ p_new->p_prev = NULL;
+ }
+ else
+ {
+ p_old = p_list->p_first;
+ while (1)
+ {
+ if (p_old == NULL)
+ {
+ p_list->p_last->p_next = p_new;
+ p_new->p_prev = p_list->p_last;
+ p_new->p_next = NULL;
+ p_list->p_last = p_new;
+
+ break;
+
+ }
+ else
+ {
+ if (p_new->asgn_range.s_handle > p_old->asgn_range.s_handle)
+ {
+ if (p_old == p_list->p_first)
+ p_list->p_first = p_new;
+
+ p_new->p_prev = p_old->p_prev;
+ p_new->p_next = p_old;
+
+
+ p_old->p_prev = p_new;
+ break;
+ }
+ }
+ p_old = p_old->p_next;
+ }
+ }
+ p_list->count++;
+ return TRUE;
+
+}
+
+/*******************************************************************************
+**
+** Function gatt_remove_an_item_from_list
+**
+** Description Remove an service handle range from the list
+**
+** Returns BOOLEAN TRUE-if remove is successful
+**
+*******************************************************************************/
+BOOLEAN gatt_remove_an_item_from_list(tGATT_HDL_LIST_INFO *p_list, tGATT_HDL_LIST_ELEM *p_remove)
+{
+ if (!p_remove || !p_list->p_first)
+ {
+ GATT_TRACE_DEBUG0("p_remove==NULL || p_list->p_first==NULL");
+ return FALSE;
+ }
+
+ if (p_remove->p_prev == NULL)
+ {
+ p_list->p_first = p_remove->p_next;
+ if (p_remove->p_next)
+ p_remove->p_next->p_prev = NULL;
+ }
+ else if (p_remove->p_next == NULL)
+ {
+ p_list->p_last = p_remove->p_prev;
+ p_remove->p_prev->p_next = NULL;
+ }
+ else
+ {
+ p_remove->p_next->p_prev = p_remove->p_prev;
+ p_remove->p_prev->p_next = p_remove->p_next;
+ }
+ p_list->count--;
+ return TRUE;
+
+}
+
+/*******************************************************************************
+**
+** Function gatt_find_the_connected_bda
+**
+** Description This function find the connected bda
+**
+** Returns TRUE if found
+**
+*******************************************************************************/
+BOOLEAN gatt_find_the_connected_bda(UINT8 start_idx, BD_ADDR bda, UINT8 *p_found_idx)
+{
+ UINT8 i;
+ BOOLEAN found = FALSE;
+ GATT_TRACE_DEBUG1("gatt_find_the_connected_bda start_idx=%d",start_idx);
+
+ for (i = start_idx ; i < GATT_MAX_PHY_CHANNEL; i ++)
+ {
+ if (gatt_cb.tcb[i].in_use)
+ {
+ memcpy( bda, gatt_cb.tcb[i].peer_bda, BD_ADDR_LEN);
+ *p_found_idx = i;
+ found = TRUE;
+ GATT_TRACE_DEBUG6("gatt_find_the_connected_bda bda :%02x-%02x-%02x-%02x-%02x-%02x",
+ bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
+ break;
+ }
+ }
+ GATT_TRACE_DEBUG2("gatt_find_the_connected_bda found=%d found_idx=%d", found, i);
+ return found;
+}
+
+
+
+/*******************************************************************************
+**
+** Function gatt_is_srv_chg_ind_pending
+**
+** Description Check whether a service chnaged is in the indication pending queue
+** or waiting for an Ack already
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+BOOLEAN gatt_is_srv_chg_ind_pending (tGATT_TCB *p_tcb)
+{
+ tGATT_VALUE *p_buf = (tGATT_VALUE *)GKI_getfirst(&p_tcb->pending_ind_q);
+ BOOLEAN srv_chg_ind_pending = FALSE;
+
+ GATT_TRACE_DEBUG1("gatt_is_srv_chg_ind_pending is_queue_empty=%d", GKI_queue_is_empty(&p_tcb->pending_ind_q) );
+
+ if (p_tcb->indicate_handle == gatt_cb.handle_of_h_r)
+ {
+ srv_chg_ind_pending = TRUE;
+ }
+ else
+ {
+ while (p_buf)
+ {
+ if (p_buf->handle == gatt_cb.handle_of_h_r)
+ {
+ srv_chg_ind_pending = TRUE;
+ break;
+ }
+ p_buf = (tGATT_VALUE *)GKI_getnext(p_buf);
+ }
+ }
+
+ GATT_TRACE_DEBUG1("srv_chg_ind_pending = %d", srv_chg_ind_pending);
+ return srv_chg_ind_pending;
+}
+
+
+/*******************************************************************************
+**
+** Function gatt_is_bda_in_the_srv_chg_clt_list
+**
+** Description This function check the specified bda is in the srv chg clinet list or not
+**
+** Returns pointer to the found elemenet otherwise NULL
+**
+*******************************************************************************/
+tGATTS_SRV_CHG *gatt_is_bda_in_the_srv_chg_clt_list (BD_ADDR bda)
+{
+ tGATTS_SRV_CHG *p_buf = (tGATTS_SRV_CHG *)GKI_getfirst(&gatt_cb.srv_chg_clt_q);
+
+ GATT_TRACE_DEBUG6("gatt_is_bda_in_the_srv_chg_clt_list :%02x-%02x-%02x-%02x-%02x-%02x",
+ bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
+
+ while (p_buf != NULL)
+ {
+ if (!memcmp( bda, p_buf->bda, BD_ADDR_LEN))
+ {
+ GATT_TRACE_DEBUG0("bda is in the srv chg clt list");
+ break;
+ }
+ p_buf = (tGATTS_SRV_CHG *)GKI_getnext(p_buf);
+ }
+
+ return p_buf;
+}
+
+
+/*******************************************************************************
+**
+** Function gatt_is_bda_connected
+**
+** Description
+**
+** Returns GATT_INDEX_INVALID if not found. Otherwise index to the tcb.
+**
+*******************************************************************************/
+BOOLEAN gatt_is_bda_connected(BD_ADDR bda)
+{
+ UINT8 i = 0;
+ BOOLEAN connected=FALSE;
+
+ for ( i=0; i < GATT_MAX_PHY_CHANNEL; i ++)
+ {
+ if (gatt_cb.tcb[i].in_use &&
+ !memcmp(gatt_cb.tcb[i].peer_bda, bda, BD_ADDR_LEN))
+ {
+ connected = TRUE;
+ break;
+ }
+ }
+ return connected;
+}
+
+/*******************************************************************************
+**
+** Function gatt_find_i_tcb_by_addr
+**
+** Description The function searches for an empty tcb entry, and return the index.
+**
+** Returns GATT_INDEX_INVALID if not found. Otherwise index to the tcb.
+**
+*******************************************************************************/
+UINT8 gatt_find_i_tcb_by_addr(BD_ADDR bda)
+{
+ UINT8 i = 0, j = GATT_INDEX_INVALID;
+
+ for ( ; i < GATT_MAX_PHY_CHANNEL; i ++)
+ {
+ if (!memcmp(gatt_cb.tcb[i].peer_bda, bda, BD_ADDR_LEN))
+ {
+ j = i;
+ break;
+ }
+ }
+ return j;
+}
+
+
+/*******************************************************************************
+**
+** Function gatt_get_tcb_by_idx
+**
+** Description The function get TCB using the TCB index
+**
+** Returns NULL if not found. Otherwise index to the tcb.
+**
+*******************************************************************************/
+tGATT_TCB * gatt_get_tcb_by_idx(UINT8 tcb_idx)
+{
+ tGATT_TCB *p_tcb = NULL;
+
+ if ( (tcb_idx < GATT_MAX_PHY_CHANNEL) && gatt_cb.tcb[tcb_idx].in_use)
+ p_tcb = &gatt_cb.tcb[tcb_idx];
+
+ return p_tcb;
+}
+
+/*******************************************************************************
+**
+** Function gatt_find_tcb_by_addr
+**
+** Description The function searches for an empty tcb entry, and return pointer.
+**
+** Returns NULL if not found. Otherwise index to the tcb.
+**
+*******************************************************************************/
+tGATT_TCB * gatt_find_tcb_by_addr(BD_ADDR bda)
+{
+ tGATT_TCB *p_tcb = NULL;
+ UINT8 i = 0;
+
+ if ((i = gatt_find_i_tcb_by_addr(bda)) != GATT_INDEX_INVALID)
+ p_tcb = &gatt_cb.tcb[i];
+
+ return p_tcb;
+}
+/*******************************************************************************
+**
+** Function gatt_find_i_tcb_free
+**
+** Description The function searches for an empty tcb entry, and return the index.
+**
+** Returns GATT_INDEX_INVALID if not found. Otherwise index to the tcb.
+**
+*******************************************************************************/
+UINT8 gatt_find_i_tcb_free(void)
+{
+ UINT8 i = 0, j = GATT_INDEX_INVALID;
+
+ for (i = 0; i < GATT_MAX_PHY_CHANNEL; i ++)
+ {
+ if (!gatt_cb.tcb[i].in_use)
+ {
+ j = i;
+ break;
+ }
+ }
+ return j;
+}
+/*******************************************************************************
+**
+** Function gatt_allocate_tcb_by_bdaddr
+**
+** Description The function locate or allocate new tcb entry for matching bda.
+**
+** Returns GATT_INDEX_INVALID if not found. Otherwise index to the tcb.
+**
+*******************************************************************************/
+tGATT_TCB * gatt_allocate_tcb_by_bdaddr(BD_ADDR bda)
+{
+ UINT8 i = 0;
+ BOOLEAN allocated = FALSE;
+ tGATT_TCB *p_tcb = NULL;
+
+ /* search for existing tcb with matching bda */
+ i = gatt_find_i_tcb_by_addr(bda);
+ /* find free tcb */
+ if (i == GATT_INDEX_INVALID)
+ {
+ i = gatt_find_i_tcb_free();
+ allocated = TRUE;
+ }
+ if (i != GATT_INDEX_INVALID)
+ {
+ p_tcb = &gatt_cb.tcb[i];
+
+ if (allocated)
+ {
+ memset(p_tcb, 0, sizeof(tGATT_TCB));
+ p_tcb->in_use = TRUE;
+ p_tcb->tcb_idx = i;
+ }
+ memcpy(p_tcb->peer_bda, bda, BD_ADDR_LEN);
+ }
+ return p_tcb;
+}
+
+/*******************************************************************************
+**
+** Function gatt_convert_uuid16_to_uuid128
+**
+** Description Convert a 16 bits UUID to be an standard 128 bits one.
+**
+** Returns TRUE if two uuid match; FALSE otherwise.
+**
+*******************************************************************************/
+void gatt_convert_uuid16_to_uuid128(UINT8 uuid_128[LEN_UUID_128], UINT16 uuid_16)
+{
+ UINT8 *p = &uuid_128[LEN_UUID_128 - 4];
+
+ memcpy (uuid_128, base_uuid, LEN_UUID_128);
+
+ UINT16_TO_STREAM(p, uuid_16);
+}
+
+/*******************************************************************************
+**
+** Function gatt_uuid_compare
+**
+** Description Compare two UUID to see if they are the same.
+**
+** Returns TRUE if two uuid match; FALSE otherwise.
+**
+*******************************************************************************/
+BOOLEAN gatt_uuid_compare (tBT_UUID src, tBT_UUID tar)
+{
+ UINT8 su[LEN_UUID_128], tu[LEN_UUID_128];
+ UINT8 *ps, *pt;
+
+ /* any of the UUID is unspecified */
+ if (src.len == 0 || tar.len == 0)
+ {
+ return TRUE;
+ }
+
+ /* If both are 16-bit, we can do a simple compare */
+ if (src.len == 2 && tar.len == 2)
+ {
+ return src.uu.uuid16 == tar.uu.uuid16;
+ }
+
+ /* One or both of the UUIDs is 128-bit */
+ if (src.len == LEN_UUID_16)
+ {
+ /* convert a 16 bits UUID to 128 bits value */
+ gatt_convert_uuid16_to_uuid128(su, src.uu.uuid16);
+ ps = su;
+ }
+ else
+ ps = src.uu.uuid128;
+
+ if (tar.len == LEN_UUID_16)
+ {
+ /* convert a 16 bits UUID to 128 bits value */
+ gatt_convert_uuid16_to_uuid128(tu, tar.uu.uuid16);
+ pt = tu;
+ }
+ else
+ pt = tar.uu.uuid128;
+
+ return(memcmp(ps, pt, LEN_UUID_128) == 0);
+}
+
+/*******************************************************************************
+**
+** Function gatt_build_uuid_to_stream
+**
+** Description Add UUID into stream.
+**
+** Returns UUID length.
+**
+*******************************************************************************/
+UINT8 gatt_build_uuid_to_stream(UINT8 **p_dst, tBT_UUID uuid)
+{
+ UINT8 *p = *p_dst;
+ UINT8 len = 0;
+
+ if (uuid.len == LEN_UUID_16)
+ {
+ UINT16_TO_STREAM (p, uuid.uu.uuid16);
+ len = LEN_UUID_16;
+ }
+ else if (uuid.len == LEN_UUID_128)
+ {
+ ARRAY_TO_STREAM (p, uuid.uu.uuid128, LEN_UUID_128);
+ len = LEN_UUID_128;
+ }
+
+ *p_dst = p;
+ return len;
+}
+
+/*******************************************************************************
+**
+** Function gatt_parse_uuid_from_cmd
+**
+** Description Convert a 128 bits UUID into a 16 bits UUID.
+**
+** Returns TRUE if command sent, otherwise FALSE.
+**
+*******************************************************************************/
+BOOLEAN gatt_parse_uuid_from_cmd(tBT_UUID *p_uuid_rec, UINT16 uuid_size, UINT8 **p_data)
+{
+ BOOLEAN is_base_uuid, ret = TRUE;
+ UINT8 xx;
+ UINT8 *p_uuid = *p_data;
+
+ memset(p_uuid_rec, 0, sizeof(tBT_UUID));
+
+ switch (uuid_size)
+ {
+ case LEN_UUID_16:
+ p_uuid_rec->len = uuid_size;
+ STREAM_TO_UINT16 (p_uuid_rec->uu.uuid16, p_uuid);
+ *p_data += LEN_UUID_16;
+ break;
+
+ case LEN_UUID_128:
+ /* See if we can compress his UUID down to 16 or 32bit UUIDs */
+ is_base_uuid = TRUE;
+ for (xx = 0; xx < LEN_UUID_128 - 4; xx++)
+ {
+ if (p_uuid[xx] != base_uuid[xx])
+ {
+ is_base_uuid = FALSE;
+ break;
+ }
+ }
+ if (is_base_uuid)
+ {
+ if ((p_uuid[LEN_UUID_128 - 1] == 0) && (p_uuid[LEN_UUID_128 - 2] == 0))
+ {
+ p_uuid += (LEN_UUID_128 - 4);
+ p_uuid_rec->len = LEN_UUID_16;
+ STREAM_TO_UINT16(p_uuid_rec->uu.uuid16, p_uuid);
+ }
+ else
+ is_base_uuid = FALSE;
+ }
+ if (!is_base_uuid)
+ {
+ p_uuid_rec->len = LEN_UUID_128;
+ memcpy(p_uuid_rec->uu.uuid128, p_uuid, LEN_UUID_128);
+ }
+ *p_data += LEN_UUID_128;
+ break;
+
+ case 0:
+ default:
+ if (uuid_size != 0) ret = FALSE;
+ GATT_TRACE_WARNING0("gatt_parse_uuid_from_cmd invalid uuid size");
+ break;
+ }
+
+ return( ret);
+}
+
+/*******************************************************************************
+**
+** Function gatt_start_rsp_timer
+**
+** Description Start a wait_for_response timer.
+**
+** Returns TRUE if command sent, otherwise FALSE.
+**
+*******************************************************************************/
+void gatt_start_rsp_timer(tGATT_TCB *p_tcb)
+{
+ p_tcb->rsp_timer_ent.param = (TIMER_PARAM_TYPE)p_tcb;
+ btu_start_timer (&p_tcb->rsp_timer_ent, BTU_TTYPE_ATT_WAIT_FOR_RSP,
+ GATT_WAIT_FOR_RSP_TOUT);
+}
+/*******************************************************************************
+**
+** Function gatt_start_conf_timer
+**
+** Description Start a wait_for_confirmation timer.
+**
+** Returns TRUE if command sent, otherwise FALSE.
+**
+*******************************************************************************/
+void gatt_start_conf_timer(tGATT_TCB *p_tcb)
+{
+ p_tcb->conf_timer_ent.param = (TIMER_PARAM_TYPE)p_tcb;
+ btu_start_timer (&p_tcb->conf_timer_ent, BTU_TTYPE_ATT_WAIT_FOR_RSP,
+ GATT_WAIT_FOR_RSP_TOUT);
+}
+/*******************************************************************************
+**
+** Function gatt_start_ind_ack_timer
+**
+** Description start the application ack timer
+**
+** Returns void
+**
+*******************************************************************************/
+void gatt_start_ind_ack_timer(tGATT_TCB *p_tcb)
+{
+ p_tcb->ind_ack_timer_ent.param = (TIMER_PARAM_TYPE)p_tcb;
+ /* start notification cache timer */
+ btu_start_timer (&p_tcb->ind_ack_timer_ent, BTU_TTYPE_ATT_WAIT_FOR_IND_ACK,
+ GATT_WAIT_FOR_RSP_TOUT);
+
+}
+/*******************************************************************************
+**
+** Function gatt_rsp_timeout
+**
+** Description Called when GATT wait for ATT command response timer expires
+**
+** Returns void
+**
+*******************************************************************************/
+void gatt_rsp_timeout(TIMER_LIST_ENT *p_tle)
+{
+ GATT_TRACE_WARNING0("gatt_rsp_timeout disconnecting...");
+ gatt_disconnect (((tGATT_TCB *)p_tle->param)->peer_bda);
+}
+
+/*******************************************************************************
+**
+** Function gatt_ind_ack_timeout
+**
+** Description Called when GATT wait for ATT handle confirmation timeout
+**
+** Returns void
+**
+*******************************************************************************/
+void gatt_ind_ack_timeout(TIMER_LIST_ENT *p_tle)
+{
+ tGATT_TCB * p_tcb = (tGATT_TCB *)p_tle->param;
+
+ GATT_TRACE_WARNING0("gatt_ind_ack_timeout send ack now");
+
+ if (p_tcb != NULL)
+ p_tcb->ind_count = 0;
+
+ attp_send_cl_msg(((tGATT_TCB *)p_tle->param), 0, GATT_HANDLE_VALUE_CONF, NULL);
+}
+/*******************************************************************************
+**
+** Function gatt_sr_find_i_rcb_by_handle
+**
+** Description The function searches for a service that owns a specific handle.
+**
+** Returns GATT_MAX_SR_PROFILES if not found. Otherwise index of th eservice.
+**
+*******************************************************************************/
+UINT8 gatt_sr_find_i_rcb_by_handle(UINT16 handle)
+{
+ UINT8 i_rcb = 0;
+
+ for ( ; i_rcb < GATT_MAX_SR_PROFILES; i_rcb++)
+ {
+ if (gatt_cb.sr_reg[i_rcb].in_use &&
+ gatt_cb.sr_reg[i_rcb].s_hdl <= handle &&
+ gatt_cb.sr_reg[i_rcb].e_hdl >= handle )
+ {
+ break;
+ }
+ }
+ return i_rcb;
+}
+
+/*******************************************************************************
+**
+** Function gatt_sr_find_i_rcb_by_handle
+**
+** Description The function searches for a service that owns a specific handle.
+**
+** Returns 0 if not found. Otherwise index of th eservice.
+**
+*******************************************************************************/
+UINT8 gatt_sr_find_i_rcb_by_app_id(tBT_UUID *p_app_uuid128, tBT_UUID *p_svc_uuid, UINT16 svc_inst)
+{
+ UINT8 i_rcb = 0;
+ tGATT_SR_REG *p_sreg;
+ tBT_UUID *p_this_uuid;
+
+ for (i_rcb = 0, p_sreg = gatt_cb.sr_reg; i_rcb < GATT_MAX_SR_PROFILES; i_rcb++, p_sreg++)
+ {
+ if ( p_sreg->in_use )
+ {
+ p_this_uuid = gatts_get_service_uuid (p_sreg->p_db);
+
+ if (p_this_uuid &&
+ gatt_uuid_compare (*p_app_uuid128, p_sreg->app_uuid ) &&
+ gatt_uuid_compare (*p_svc_uuid, *p_this_uuid) &&
+ (svc_inst == p_sreg->service_instance))
+ {
+ GATT_TRACE_ERROR0 ("Active Service Found ");
+ gatt_dbg_display_uuid(*p_svc_uuid);
+
+ break;
+ }
+ }
+ }
+ return i_rcb;
+}
+/*******************************************************************************
+**
+** Function gatt_sr_find_i_rcb_by_handle
+**
+** Description The function searches for a service that owns a specific handle.
+**
+** Returns 0 if not found. Otherwise index of th eservice.
+**
+*******************************************************************************/
+UINT8 gatt_sr_alloc_rcb(tGATT_HDL_LIST_ELEM *p_list )
+{
+ UINT8 ii = 0;
+ tGATT_SR_REG *p_sreg = NULL;
+
+ /*this is a new application servoce start */
+ for (ii = 0, p_sreg = gatt_cb.sr_reg; ii < GATT_MAX_SR_PROFILES; ii++, p_sreg++)
+ {
+ if (!p_sreg->in_use)
+ {
+ memset (p_sreg, 0, sizeof(tGATT_SR_REG));
+
+ p_sreg->in_use = TRUE;
+ memcpy (&p_sreg->app_uuid, &p_list->asgn_range.app_uuid128, sizeof(tBT_UUID));
+
+ p_sreg->service_instance = p_list->asgn_range.svc_inst;
+ p_sreg->type = p_list->asgn_range.is_primary ? GATT_UUID_PRI_SERVICE: GATT_UUID_SEC_SERVICE;
+ p_sreg->s_hdl = p_list->asgn_range.s_handle;
+ p_sreg->e_hdl = p_list->asgn_range.e_handle;
+ //p_sreg->sr_cb = *p_cback;
+ p_sreg->p_db = &p_list->svc_db;
+
+ GATT_TRACE_DEBUG1 ("total GKI buffer in db [%d]",p_sreg->p_db->svc_buffer.count);
+ break;
+ }
+ }
+
+ return ii;
+}
+/*******************************************************************************
+**
+** Function gatt_sr_get_sec_info
+**
+** Description Get the security flag and key size information for the peer
+** device.
+**
+** Returns void
+**
+*******************************************************************************/
+void gatt_sr_get_sec_info(BD_ADDR rem_bda, BOOLEAN le_conn, UINT8 *p_sec_flag, UINT8 *p_key_size)
+{
+ UINT8 sec_flag = 0;
+
+ BTM_GetSecurityFlags(rem_bda, &sec_flag);
+
+ sec_flag &= (GATT_SEC_FLAG_LKEY_UNAUTHED | GATT_SEC_FLAG_LKEY_AUTHED | GATT_SEC_FLAG_ENCRYPTED);
+
+ *p_key_size = btm_ble_read_sec_key_size(rem_bda);
+ *p_sec_flag = sec_flag;
+}
+/*******************************************************************************
+**
+** Function gatt_sr_send_req_callback
+**
+** Description
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void gatt_sr_send_req_callback(UINT16 conn_id,
+ UINT32 trans_id,
+ tGATTS_REQ_TYPE type, tGATTS_DATA *p_data)
+{
+ tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
+ tGATT_REG *p_reg = gatt_get_regcb(gatt_if);
+
+ if (!p_reg )
+ {
+ GATT_TRACE_ERROR0 ("p_reg not found discard request");
+ return;
+ }
+
+ if ( p_reg->in_use &&
+ p_reg->app_cb.p_req_cb)
+ {
+ (*p_reg->app_cb.p_req_cb)(conn_id, trans_id, type, p_data);
+ }
+ else
+ {
+ GATT_TRACE_WARNING1("Call back not found for application conn_id=%d", conn_id);
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function gatt_send_error_rsp
+**
+** Description This function sends an error response.
+**
+** Returns void
+**
+*******************************************************************************/
+tGATT_STATUS gatt_send_error_rsp (tGATT_TCB *p_tcb, UINT8 err_code, UINT8 op_code,
+ UINT16 handle, BOOLEAN deq)
+{
+ tGATT_ERROR error;
+ tGATT_STATUS status;
+ BT_HDR *p_buf;
+
+ error.cmd_code = op_code;
+ error.reason = err_code;
+ error.handle =handle;
+
+ if ((p_buf = attp_build_sr_msg(p_tcb, GATT_RSP_ERROR, (tGATT_SR_MSG *)&error)) != NULL)
+ {
+ status = attp_send_sr_msg (p_tcb, p_buf);
+ }
+ else
+ status = GATT_INSUF_RESOURCE;
+
+ if (deq)
+ gatt_dequeue_sr_cmd(p_tcb);
+
+ return status;
+}
+
+
+/*******************************************************************************
+**
+** Function gatt_add_sdp_record
+**
+** Description This function add a SDP record for a GATT primary service
+**
+** Returns 0 if error else sdp handle for the record.
+**
+*******************************************************************************/
+UINT32 gatt_add_sdp_record (tBT_UUID *p_uuid, UINT16 start_hdl, UINT16 end_hdl)
+{
+ tSDP_PROTOCOL_ELEM proto_elem_list[2];
+ UINT32 sdp_handle;
+ UINT16 list = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
+ UINT8 buff[60];
+ UINT8 *p = buff;
+
+ GATT_TRACE_DEBUG2("gatt_add_sdp_record s_hdl=0x%x s_hdl=0x%x",start_hdl, end_hdl);
+
+ if ((sdp_handle = SDP_CreateRecord()) == 0)
+ return 0;
+
+ switch (p_uuid->len)
+ {
+ case LEN_UUID_16:
+ SDP_AddServiceClassIdList(sdp_handle, 1, &p_uuid->uu.uuid16);
+ break;
+ case LEN_UUID_128:
+ UINT8_TO_BE_STREAM (p, (UUID_DESC_TYPE << 3) | SIZE_SIXTEEN_BYTES);
+ ARRAY_TO_BE_STREAM (p, p_uuid->uu.uuid128, LEN_UUID_128);
+ SDP_AddAttribute (sdp_handle, ATTR_ID_SERVICE_CLASS_ID_LIST, DATA_ELE_SEQ_DESC_TYPE,
+ (UINT32) (p - buff), buff);
+ break;
+
+ default:
+ GATT_TRACE_ERROR1("inavlid UUID len=%d", p_uuid->len);
+ SDP_DeleteRecord(sdp_handle);
+ return 0;
+ break;
+ }
+
+ /*** Fill out the protocol element sequence for SDP ***/
+ proto_elem_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+ proto_elem_list[0].num_params = 1;
+ proto_elem_list[0].params[0] = BT_PSM_ATT;
+ proto_elem_list[1].protocol_uuid = UUID_PROTOCOL_ATT;
+ proto_elem_list[1].num_params = 2;
+ proto_elem_list[1].params[0] = start_hdl;
+ proto_elem_list[1].params[1] = end_hdl;
+
+ SDP_AddProtocolList(sdp_handle, 2, proto_elem_list);
+
+ /* Make the service browseable */
+ SDP_AddUuidSequence (sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &list);
+
+ return(sdp_handle);
+}
+
+
+ #if GATT_CONFORMANCE_TESTING == TRUE
+/*******************************************************************************
+**
+** Function gatt_set_err_rsp
+**
+** Description This function is called to set the test confirm value
+**
+** Returns void
+**
+*******************************************************************************/
+void gatt_set_err_rsp(BOOLEAN enable, UINT8 req_op_code, UINT8 err_status)
+{
+ GATT_TRACE_DEBUG3("gatt_set_err_rsp enable=%d op_code=%d, err_status=%d", enable, req_op_code, err_status);
+ gatt_cb.enable_err_rsp = enable;
+ gatt_cb.req_op_code = req_op_code;
+ gatt_cb.err_status = err_status;
+}
+ #endif
+
+
+
+/*******************************************************************************
+**
+** Function gatt_get_regcb
+**
+** Description The function returns the registration control block.
+**
+** Returns pointer to the registration control block or NULL
+**
+*******************************************************************************/
+tGATT_REG *gatt_get_regcb (tGATT_IF gatt_if)
+{
+ UINT8 ii = (UINT8)gatt_if;
+ tGATT_REG *p_reg = NULL;
+
+ if (ii)
+ {
+ ii--; /* convert from one based to zero based */
+ p_reg = &gatt_cb.cl_rcb[ii];
+ if ( (ii < GATT_MAX_APPS) && (p_reg->in_use) )
+ return(p_reg);
+ }
+
+ return NULL;
+}
+
+
+/*******************************************************************************
+**
+** Function gatt_is_clcb_allocated
+**
+** Description The function check clcb for conn_id is allocated or not
+**
+** Returns True already allocated
+**
+*******************************************************************************/
+
+BOOLEAN gatt_is_clcb_allocated (UINT16 conn_id)
+{
+ UINT8 i = 0;
+ BOOLEAN is_allocated= FALSE;
+
+ for (i = 0; i < GATT_CL_MAX_LCB; i++)
+ {
+ if (gatt_cb.clcb[i].in_use && (gatt_cb.clcb[i].conn_id == conn_id))
+ {
+ is_allocated = TRUE;
+ break;
+ }
+ }
+
+ return is_allocated;
+}
+
+/*******************************************************************************
+**
+** Function gatt_clcb_alloc
+**
+** Description The function allocates a GATT connection link control block
+**
+** Returns NULL if not found. Otherwise pointer to the connection link block.
+**
+*******************************************************************************/
+tGATT_CLCB *gatt_clcb_alloc (UINT16 conn_id)
+{
+ UINT8 i = 0;
+ tGATT_CLCB *p_clcb = NULL;
+ tGATT_IF gatt_if=GATT_GET_GATT_IF(conn_id);
+ UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id);
+ tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
+ tGATT_REG *p_reg = gatt_get_regcb(gatt_if);
+
+ for (i = 0; i < GATT_CL_MAX_LCB; i++)
+ {
+ if (!gatt_cb.clcb[i].in_use)
+ {
+ p_clcb = &gatt_cb.clcb[i];
+
+ p_clcb->in_use = TRUE;
+ p_clcb->conn_id = conn_id;
+ p_clcb->clcb_idx = i;
+ p_clcb->p_reg = p_reg;
+ p_clcb->p_tcb = p_tcb;
+ break;
+ }
+ }
+ return p_clcb;
+}
+
+/*******************************************************************************
+**
+** Function gatt_clcb_dealloc
+**
+** Description The function de allocates a GATT connection link control block
+**
+** Returns None
+**
+*******************************************************************************/
+void gatt_clcb_dealloc (tGATT_CLCB *p_clcb)
+{
+ if (p_clcb && p_clcb->in_use)
+ {
+ memset(p_clcb, 0, sizeof(tGATT_CLCB));
+ }
+}
+
+
+
+/*******************************************************************************
+**
+** Function gatt_find_tcb_by_cid
+**
+** Description The function searches for an empty entry
+** in registration info table for GATT client
+**
+** Returns NULL if not found. Otherwise pointer to the rcb.
+**
+*******************************************************************************/
+tGATT_TCB * gatt_find_tcb_by_cid (UINT16 lcid)
+{
+ UINT16 xx = 0;
+ tGATT_TCB *p_tcb = NULL;
+
+ for (xx = 0; xx < GATT_MAX_PHY_CHANNEL; xx++)
+ {
+ if (gatt_cb.tcb[xx].in_use && gatt_cb.tcb[xx].att_lcid == lcid)
+ {
+ p_tcb = &gatt_cb.tcb[xx];
+ break;
+ }
+ }
+ return p_tcb;
+}
+
+
+/*******************************************************************************
+**
+** Function gatt_num_apps_hold_link
+**
+** Description The function find the number of applcaitions is holding the link
+**
+** Returns total number of applications holding this acl link.
+**
+*******************************************************************************/
+UINT8 gatt_num_apps_hold_link(tGATT_TCB *p_tcb)
+{
+ UINT8 i, num = 0;
+
+ for (i = 0; i < GATT_MAX_APPS; i ++)
+ {
+ if (p_tcb->app_hold_link[i])
+ num ++;
+ }
+
+ GATT_TRACE_DEBUG1("gatt_num_apps_hold_link num=%d", num);
+ return num;
+}
+
+
+/*******************************************************************************
+**
+** Function gatt_num_clcb_by_bd_addr
+**
+** Description The function searches all LCB with macthing bd address
+**
+** Returns total number of clcb found.
+**
+*******************************************************************************/
+UINT8 gatt_num_clcb_by_bd_addr(BD_ADDR bda)
+{
+ UINT8 i, num = 0;
+
+ for (i = 0; i < GATT_CL_MAX_LCB; i ++)
+ {
+ if (gatt_cb.clcb[i].in_use && memcmp(gatt_cb.clcb[i].p_tcb->peer_bda, bda, BD_ADDR_LEN) == 0)
+ num ++;
+ }
+ return num;
+}
+
+/*******************************************************************************
+**
+** Function gatt_sr_update_cback_cnt
+**
+** Description The function searches all LCB with macthing bd address
+**
+** Returns total number of clcb found.
+**
+*******************************************************************************/
+void gatt_sr_copy_prep_cnt_to_cback_cnt(tGATT_TCB *p_tcb )
+{
+ UINT8 i;
+
+ if (p_tcb)
+ {
+ for (i = 0; i < GATT_MAX_APPS; i ++)
+ {
+ if (p_tcb->prep_cnt[i])
+ {
+ p_tcb->sr_cmd.cback_cnt[i]=1;
+ }
+ }
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function gatt_sr_is_cback_cnt_zero
+**
+** Description The function searches all LCB with macthing bd address
+**
+** Returns True if thetotal application callback count is zero
+**
+*******************************************************************************/
+BOOLEAN gatt_sr_is_cback_cnt_zero(tGATT_TCB *p_tcb )
+{
+ BOOLEAN status = TRUE;
+ UINT8 i;
+
+ if (p_tcb)
+ {
+ for (i = 0; i < GATT_MAX_APPS; i ++)
+ {
+ if (p_tcb->sr_cmd.cback_cnt[i])
+ {
+ status = FALSE;
+ break;
+ }
+ }
+ }
+ else
+ {
+ status = FALSE;
+ }
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function gatt_sr_is_prep_cnt_zero
+**
+** Description Check the prepare write request count is zero or not
+**
+** Returns True no prepare write request
+**
+*******************************************************************************/
+BOOLEAN gatt_sr_is_prep_cnt_zero(tGATT_TCB *p_tcb)
+{
+ BOOLEAN status = TRUE;
+ UINT8 i;
+
+ if (p_tcb)
+ {
+ for (i = 0; i < GATT_MAX_APPS; i ++)
+ {
+ if (p_tcb->prep_cnt[i])
+ {
+ status = FALSE;
+ break;
+ }
+ }
+ }
+ else
+ {
+ status = FALSE;
+ }
+ return status;
+}
+
+
+/*******************************************************************************
+**
+** Function gatt_sr_reset_cback_cnt
+**
+** Description Reset the application callback count to zero
+**
+** Returns None
+**
+*******************************************************************************/
+void gatt_sr_reset_cback_cnt(tGATT_TCB *p_tcb )
+{
+ UINT8 i;
+
+ if (p_tcb)
+ {
+ for (i = 0; i < GATT_MAX_APPS; i ++)
+ {
+ p_tcb->sr_cmd.cback_cnt[i]=0;
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function gatt_sr_reset_prep_cnt
+**
+** Description Reset the prep write count to zero
+**
+** Returns None
+**
+*******************************************************************************/
+void gatt_sr_reset_prep_cnt(tGATT_TCB *p_tcb )
+{
+ UINT8 i;
+ if (p_tcb)
+ {
+ for (i = 0; i < GATT_MAX_APPS; i ++)
+ {
+ p_tcb->prep_cnt[i]=0;
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function gatt_sr_update_cback_cnt
+**
+** Description Update the teh applicaiton callback count
+**
+** Returns None
+**
+*******************************************************************************/
+void gatt_sr_update_cback_cnt(tGATT_TCB *p_tcb, tGATT_IF gatt_if, BOOLEAN is_inc, BOOLEAN is_reset_first)
+{
+
+ UINT8 idx = ((UINT8) gatt_if) - 1 ;
+
+ if (p_tcb)
+ {
+ if (is_reset_first)
+ {
+ gatt_sr_reset_cback_cnt(p_tcb);
+ }
+ if (is_inc)
+ {
+ p_tcb->sr_cmd.cback_cnt[idx]++;
+ }
+ else
+ {
+ if ( p_tcb->sr_cmd.cback_cnt[idx])
+ {
+ p_tcb->sr_cmd.cback_cnt[idx]--;
+ }
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function gatt_sr_update_prep_cnt
+**
+** Description Update the teh prepare write request count
+**
+** Returns None
+**
+*******************************************************************************/
+void gatt_sr_update_prep_cnt(tGATT_TCB *p_tcb, tGATT_IF gatt_if, BOOLEAN is_inc, BOOLEAN is_reset_first)
+{
+ UINT8 idx = ((UINT8) gatt_if) - 1 ;
+
+ GATT_TRACE_DEBUG4("gatt_sr_update_prep_cnt tcb idx=%d gatt_if=%d is_inc=%d is_reset_first=%d",
+ p_tcb->tcb_idx, gatt_if, is_inc, is_reset_first);
+
+ if (p_tcb)
+ {
+ if (is_reset_first)
+ {
+ gatt_sr_reset_prep_cnt(p_tcb);
+ }
+ if (is_inc)
+ {
+ p_tcb->prep_cnt[idx]++;
+ }
+ else
+ {
+ if (p_tcb->prep_cnt[idx])
+ {
+ p_tcb->prep_cnt[idx]--;
+ }
+ }
+ }
+}
+/*******************************************************************************
+**
+** Function gatt_cancel_open
+**
+** Description Cancel open request
+**
+** Returns Boolean
+**
+*******************************************************************************/
+BOOLEAN gatt_cancel_open(tGATT_IF gatt_if, BD_ADDR bda)
+{
+ tGATT_TCB *p_tcb=NULL;
+ BOOLEAN status= TRUE;
+
+ p_tcb = gatt_find_tcb_by_addr(bda);
+ if (p_tcb)
+ {
+ if (gatt_get_ch_state(p_tcb) == GATT_CH_OPEN)
+ {
+ GATT_TRACE_ERROR0("GATT_CancelConnect - link connected Too late to cancel");
+ status = FALSE;
+ }
+ else
+ {
+ gatt_update_app_use_link_flag(gatt_if, p_tcb, FALSE, FALSE);
+ if (!gatt_num_apps_hold_link(p_tcb))
+ {
+ gatt_disconnect(p_tcb->peer_bda);
+ }
+ }
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function gatt_find_app_hold_link
+**
+** Description find the applicaiton that is holding the specified link
+**
+** Returns Boolean
+**
+*******************************************************************************/
+BOOLEAN gatt_find_app_hold_link(tGATT_TCB *p_tcb, UINT8 start_idx, UINT8 *p_found_idx, tGATT_IF *p_gatt_if)
+{
+ UINT8 i;
+ BOOLEAN found= FALSE;
+
+ for (i = start_idx; i < GATT_MAX_APPS; i ++)
+ {
+ if (p_tcb->app_hold_link[i])
+ {
+ *p_gatt_if = gatt_cb.clcb[i].p_reg->gatt_if;
+ *p_found_idx = i;
+ found = TRUE;
+ break;
+ }
+ }
+ return found;
+}
+
+/*******************************************************************************
+**
+** Function gatt_cmd_enq
+**
+** Description Enqueue this command.
+**
+** Returns None.
+**
+*******************************************************************************/
+BOOLEAN gatt_cmd_enq(tGATT_TCB *p_tcb, UINT16 clcb_idx, BOOLEAN to_send, UINT8 op_code, BT_HDR *p_buf)
+{
+ tGATT_CMD_Q *p_cmd = &p_tcb->cl_cmd_q[p_tcb->next_slot_inq];
+
+ p_cmd->to_send = to_send; /* waiting to be sent */
+ p_cmd->op_code = op_code;
+ p_cmd->p_cmd = p_buf;
+ p_cmd->clcb_idx = clcb_idx;
+
+ if (!to_send)
+ {
+ p_tcb->pending_cl_req = p_tcb->next_slot_inq;
+ }
+
+ p_tcb->next_slot_inq ++;
+ p_tcb->next_slot_inq %= GATT_CL_MAX_LCB;
+
+ return TRUE;
+}
+
+/*******************************************************************************
+**
+** Function gatt_cmd_dequeue
+**
+** Description dequeue the command in the client CCB command queue.
+**
+** Returns total number of clcb found.
+**
+*******************************************************************************/
+tGATT_CLCB * gatt_cmd_dequeue(tGATT_TCB *p_tcb, UINT8 *p_op_code)
+{
+ tGATT_CMD_Q *p_cmd = &p_tcb->cl_cmd_q[p_tcb->pending_cl_req];
+ tGATT_CLCB *p_clcb = NULL;
+
+ if (p_tcb->pending_cl_req != p_tcb->next_slot_inq)
+ {
+ p_clcb = &gatt_cb.clcb[p_cmd->clcb_idx];
+
+ *p_op_code = p_cmd->op_code;
+
+ p_tcb->pending_cl_req ++;
+ p_tcb->pending_cl_req %= GATT_CL_MAX_LCB;
+ }
+
+ return p_clcb;
+}
+
+/*******************************************************************************
+**
+** Function gatt_send_write_msg
+**
+** Description This real function send out the ATT message for write.
+**
+** Returns status code
+**
+*******************************************************************************/
+UINT8 gatt_send_write_msg (tGATT_TCB *p_tcb, UINT16 clcb_idx, UINT8 op_code,
+ UINT16 handle, UINT16 len,
+ UINT16 offset, UINT8 *p_data)
+{
+ tGATT_CL_MSG msg;
+
+ msg.attr_value.handle = handle;
+ msg.attr_value.len = len;
+ msg.attr_value.offset = offset;
+
+ memcpy (msg.attr_value.value, p_data, len);
+
+ /* write by handle */
+ return attp_send_cl_msg(p_tcb, clcb_idx, op_code, &msg);
+}
+
+/*******************************************************************************
+**
+** Function gatt_act_send_browse
+**
+** Description This function ends a browse command request, including read
+** information request and read by type request.
+**
+** Returns status code
+**
+*******************************************************************************/
+UINT8 gatt_act_send_browse(tGATT_TCB *p_tcb, UINT16 index, UINT8 op, UINT16 s_handle,
+ UINT16 e_handle, tBT_UUID uuid)
+{
+ tGATT_CL_MSG msg;
+
+ msg.browse.s_handle = s_handle;
+ msg.browse.e_handle = e_handle;
+ memcpy(&msg.browse.uuid, &uuid, sizeof(tBT_UUID));
+
+ /* write by handle */
+ return attp_send_cl_msg(p_tcb, index, op, &msg);
+}
+
+/*******************************************************************************
+**
+** Function gatt_end_operation
+**
+** Description This function ends a discovery, send callback and finalize
+** some control value.
+**
+** Returns 16 bits uuid.
+**
+*******************************************************************************/
+void gatt_end_operation(tGATT_CLCB *p_clcb, tGATT_STATUS status, void *p_data)
+{
+ tGATT_CL_COMPLETE cb_data;
+ tGATT_CMPL_CBACK *p_cmpl_cb = (p_clcb->p_reg) ? p_clcb->p_reg->app_cb.p_cmpl_cb : NULL;
+ UINT8 op = p_clcb->operation, disc_type=GATT_DISC_MAX;
+ tGATT_DISC_CMPL_CB *p_disc_cmpl_cb = (p_clcb->p_reg) ? p_clcb->p_reg->app_cb.p_disc_cmpl_cb : NULL;
+ UINT16 conn_id;
+ UINT8 operation;
+
+ GATT_TRACE_DEBUG3 ("gatt_end_operation status=%d op=%d subtype=%d",
+ status, p_clcb->operation, p_clcb->op_subtype);
+
+ if (p_cmpl_cb != NULL && p_clcb->operation != 0)
+ {
+ if (p_clcb->operation == GATTC_OPTYPE_READ)
+ {
+ memset(&cb_data.att_value, 0, sizeof(tGATT_VALUE));
+ cb_data.att_value.handle = p_clcb->s_handle;
+ cb_data.att_value.len = p_clcb->counter;
+ if (p_data)
+ memcpy (cb_data.att_value.value, p_data, cb_data.att_value.len);
+ }
+
+ if (p_clcb->operation == GATTC_OPTYPE_WRITE)
+ {
+ memset(&cb_data.att_value, 0, sizeof(tGATT_VALUE));
+ cb_data.handle =
+ cb_data.att_value.handle = p_clcb->s_handle;
+ if (p_clcb->op_subtype == GATT_WRITE_PREPARE)
+ {
+ if (p_data)
+ {
+ cb_data.att_value = *((tGATT_VALUE *) p_data);
+ }
+ else
+ {
+ GATT_TRACE_DEBUG0("Rcv Prepare write rsp but no data");
+ }
+ }
+ }
+
+ if (p_clcb->operation == GATTC_OPTYPE_CONFIG)
+ cb_data.mtu = p_clcb->p_tcb->payload_size;
+
+ if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY)
+ {
+ disc_type = p_clcb->op_subtype;
+ }
+ }
+
+ if (p_clcb->p_attr_buf)
+ {
+ GKI_freebuf(p_clcb->p_attr_buf);
+ }
+
+ operation = p_clcb->operation;
+ conn_id = p_clcb->conn_id;
+
+ gatt_clcb_dealloc(p_clcb);
+
+ if (p_disc_cmpl_cb && (op == GATTC_OPTYPE_DISCOVERY))
+ (*p_disc_cmpl_cb)(conn_id, disc_type, status);
+ else if (p_cmpl_cb && op)
+ (*p_cmpl_cb)(conn_id, op, status, &cb_data);
+ else
+ GATT_TRACE_WARNING3 ("gatt_end_operation not sent out op=%d p_disc_cmpl_cb:%p p_cmpl_cb:%p",
+ operation, p_disc_cmpl_cb, p_cmpl_cb);
+}
+
+/*******************************************************************************
+**
+** Function gatt_cleanup_upon_disc
+**
+** Description This function cleans up the control blocks when L2CAP channel
+** disconnect.
+**
+** Returns 16 bits uuid.
+**
+*******************************************************************************/
+void gatt_cleanup_upon_disc(BD_ADDR bda, UINT16 reason)
+{
+ tGATT_TCB *p_tcb = NULL;
+ tGATT_CLCB *p_clcb;
+ UINT8 i;
+ UINT16 conn_id;
+ tGATT_REG *p_reg=NULL;
+
+
+ GATT_TRACE_DEBUG0 ("gatt_cleanup_upon_disc ");
+
+ if ((p_tcb = gatt_find_tcb_by_addr(bda)) != NULL)
+ {
+ GATT_TRACE_DEBUG0 ("found p_tcb ");
+ for (i = 0; i < GATT_CL_MAX_LCB; i ++)
+ {
+ p_clcb = &gatt_cb.clcb[i];
+ if (p_clcb->in_use && p_clcb->p_tcb == p_tcb)
+ {
+ GATT_TRACE_DEBUG2 ("found p_clcb conn_id=%d clcb_idx=%d", p_clcb->conn_id, p_clcb->clcb_idx);
+ if (p_clcb->operation != GATTC_OPTYPE_NONE)
+ gatt_end_operation(p_clcb, GATT_ERROR, NULL);
+
+ gatt_clcb_dealloc(p_clcb);
+
+ }
+ }
+
+ btu_stop_timer (&p_tcb->rsp_timer_ent);
+ btu_stop_timer (&p_tcb->ind_ack_timer_ent);
+ btu_stop_timer (&p_tcb->conf_timer_ent);
+ gatt_free_pending_ind(p_tcb);
+
+ for (i = 0; i < GATT_MAX_APPS; i ++)
+ {
+ p_reg = &gatt_cb.cl_rcb[i];
+ if (p_reg->in_use && p_reg->app_cb.p_conn_cb)
+ {
+ conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if);
+ GATT_TRACE_DEBUG3 ("found p_reg tcb_idx=%d gatt_if=%d conn_id=0x%x", p_tcb->tcb_idx, p_reg->gatt_if, conn_id);
+ (*p_reg->app_cb.p_conn_cb)(p_reg->gatt_if, bda, conn_id, FALSE, reason);
+ }
+ }
+ memset(p_tcb, 0, sizeof(tGATT_TCB));
+
+ }
+ GATT_TRACE_DEBUG0 ("exit gatt_cleanup_upon_disc ");
+}
+/*******************************************************************************
+**
+** Function gatt_dbg_req_op_name
+**
+** Description Get op code description name, for debug information.
+**
+** Returns UINT8 *: name of the operation.
+**
+*******************************************************************************/
+UINT8 * gatt_dbg_op_name(UINT8 op_code)
+{
+ UINT8 pseduo_op_code_idx = op_code & (~GATT_WRITE_CMD_MASK);
+
+ if (op_code == GATT_CMD_WRITE )
+ {
+ pseduo_op_code_idx = 0x14; /* just an index to op_code_name */
+
+ }
+
+ if (op_code == GATT_SIGN_CMD_WRITE)
+ {
+ pseduo_op_code_idx = 0x15; /* just an index to op_code_name */
+ }
+
+ if (pseduo_op_code_idx <= GATT_OP_CODE_MAX)
+ return(UINT8*) op_code_name[pseduo_op_code_idx];
+ else
+ return(UINT8 *)"Op Code Exceed Max";
+}
+
+/*******************************************************************************
+**
+** Function gatt_dbg_display_uuid
+**
+** Description Disaplay the UUID
+**
+** Returns None
+**
+*******************************************************************************/
+void gatt_dbg_display_uuid(tBT_UUID bt_uuid)
+{
+ char str_buf[50];
+ int x = 0;
+
+ if (bt_uuid.len == LEN_UUID_16)
+ {
+ sprintf(str_buf, "0x%04x", bt_uuid.uu.uuid16);
+ }
+ else if (bt_uuid.len == LEN_UUID_128)
+ {
+ x += sprintf(&str_buf[x], "0x%02x%02x%02x%02x%02x%02x%02x%02x",
+ bt_uuid.uu.uuid128[15], bt_uuid.uu.uuid128[14],
+ bt_uuid.uu.uuid128[13], bt_uuid.uu.uuid128[12],
+ bt_uuid.uu.uuid128[11], bt_uuid.uu.uuid128[10],
+ bt_uuid.uu.uuid128[9], bt_uuid.uu.uuid128[8]);
+ sprintf(&str_buf[x], "%02x%02x%02x%02x%02x%02x%02x%02x",
+ bt_uuid.uu.uuid128[7], bt_uuid.uu.uuid128[6],
+ bt_uuid.uu.uuid128[5], bt_uuid.uu.uuid128[4],
+ bt_uuid.uu.uuid128[3], bt_uuid.uu.uuid128[2],
+ bt_uuid.uu.uuid128[1], bt_uuid.uu.uuid128[0]);
+ }
+ else
+ BCM_STRNCPY_S(str_buf, sizeof(str_buf), "Unknown UUID 0", 15);
+
+ GATT_TRACE_DEBUG1 ("UUID=[%s]", str_buf);
+
+}
+
+
+/*******************************************************************************
+**
+** Function gatt_is_bg_dev_for_app
+**
+** Description find is this one of the background devices for the application
+**
+** Returns TRUE this is one of the background devices for the application
+**
+*******************************************************************************/
+BOOLEAN gatt_is_bg_dev_for_app(tGATT_BG_CONN_DEV *p_dev, tGATT_IF gatt_if)
+{
+ UINT8 i;
+
+ for (i = 0; i < GATT_MAX_APPS; i ++ )
+ {
+ if (p_dev->in_use && (p_dev->gatt_if[i] == gatt_if))
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+/*******************************************************************************
+**
+** Function gatt_find_bg_dev
+**
+** Description find background connection device from the list.
+**
+** Returns pointer to the device record
+**
+*******************************************************************************/
+tGATT_BG_CONN_DEV * gatt_find_bg_dev(BD_ADDR remote_bda)
+{
+ tGATT_BG_CONN_DEV *p_dev_list = &gatt_cb.bgconn_dev[0];
+ UINT8 i;
+
+ for (i = 0; i < GATT_MAX_BG_CONN_DEV; i ++, p_dev_list ++)
+ {
+ if (p_dev_list->in_use && !memcmp(p_dev_list->remote_bda, remote_bda, BD_ADDR_LEN))
+ {
+ return p_dev_list;
+ }
+ }
+ return NULL;
+}
+/*******************************************************************************
+**
+** Function gatt_alloc_bg_dev
+**
+** Description allocate a background connection device record
+**
+** Returns pointer to the device record
+**
+*******************************************************************************/
+tGATT_BG_CONN_DEV * gatt_alloc_bg_dev(BD_ADDR remote_bda)
+{
+ tGATT_BG_CONN_DEV *p_dev_list = &gatt_cb.bgconn_dev[0];
+ UINT8 i;
+
+ for (i = 0; i < GATT_MAX_BG_CONN_DEV; i ++, p_dev_list ++)
+ {
+ if (!p_dev_list->in_use)
+ {
+ p_dev_list->in_use = TRUE;
+ memcpy(p_dev_list->remote_bda, remote_bda, BD_ADDR_LEN);
+
+ return p_dev_list;
+ }
+ }
+ return NULL;
+}
+
+/*******************************************************************************
+**
+** Function gatt_add_bg_dev_list
+**
+** Description add/remove device from the back ground connection device list
+**
+** Returns pointer to the device record
+**
+*******************************************************************************/
+BOOLEAN gatt_add_bg_dev_list(tGATT_IF gatt_if, BD_ADDR bd_addr)
+{
+ tGATT_BG_CONN_DEV *p_dev = NULL;
+ UINT8 i;
+
+ if ((p_dev = gatt_find_bg_dev(bd_addr)) == NULL)
+ {
+ p_dev = gatt_alloc_bg_dev(bd_addr);
+ }
+
+ if (p_dev)
+ {
+ for (i = 0; i < GATT_MAX_APPS; i ++)
+ {
+ if (p_dev->gatt_if[i] == gatt_if)
+ {
+ GATT_TRACE_ERROR0("device already in list");
+ return FALSE;
+ }
+ else if (p_dev->gatt_if[i] == 0)
+ {
+ GATT_TRACE_DEBUG0("add device into list");
+ p_dev->gatt_if[i] = gatt_if;
+ return TRUE;
+ }
+ }
+ }
+
+ GATT_TRACE_ERROR0("no device record available");
+
+ return FALSE;
+}
+
+
+/*******************************************************************************
+**
+** Function gatt_remove_bg_dev_for_app
+**
+** Description Remove the application interface for the specified background device
+**
+** Returns Boolean
+**
+*******************************************************************************/
+BOOLEAN gatt_remove_bg_dev_for_app(tGATT_IF gatt_if, BD_ADDR bd_addr)
+{
+ tGATT_TCB *p_tcb = gatt_find_tcb_by_addr(bd_addr);
+ BOOLEAN status;
+
+ if (p_tcb)
+ gatt_update_app_use_link_flag(gatt_if, p_tcb, FALSE, FALSE);
+ status = gatt_update_auto_connect_dev(gatt_if, FALSE, bd_addr);
+ return status;
+}
+
+
+/*******************************************************************************
+**
+** Function gatt_get_num_apps_for_bg_dev
+**
+** Description Gte the number of applciations for the specified background device
+**
+** Returns UINT8 total number fo applications
+**
+*******************************************************************************/
+UINT8 gatt_get_num_apps_for_bg_dev(BD_ADDR bd_addr)
+{
+ tGATT_BG_CONN_DEV *p_dev = NULL;
+ UINT8 i;
+ UINT8 cnt = 0;
+
+ if ((p_dev = gatt_find_bg_dev(bd_addr)) != NULL)
+ {
+ for (i = 0; i < GATT_MAX_APPS; i ++)
+ {
+ if (p_dev->gatt_if[i])
+ cnt++;
+ }
+ }
+ return cnt;
+}
+
+/*******************************************************************************
+**
+** Function gatt_find_app_for_bg_dev
+**
+** Description find the application interface for the specified background device
+**
+** Returns Boolean
+**
+*******************************************************************************/
+BOOLEAN gatt_find_app_for_bg_dev(BD_ADDR bd_addr, tGATT_IF *p_gatt_if)
+{
+ tGATT_BG_CONN_DEV *p_dev = NULL;
+ UINT8 i;
+ BOOLEAN ret = FALSE;
+
+ if ((p_dev = gatt_find_bg_dev(bd_addr)) == NULL)
+ {
+ return ret;
+ }
+
+ for (i = 0; i < GATT_MAX_APPS; i ++)
+ {
+ if (p_dev->gatt_if[i] != 0 )
+ {
+ *p_gatt_if = p_dev->gatt_if[i];
+ ret = TRUE;
+ break;
+ }
+ }
+ return ret;
+}
+
+
+/*******************************************************************************
+**
+** Function gatt_remove_bg_dev_from_list
+**
+** Description add/remove device from the back ground connection device list
+**
+** Returns pointer to the device record
+**
+*******************************************************************************/
+BOOLEAN gatt_remove_bg_dev_from_list(tGATT_IF gatt_if, BD_ADDR bd_addr)
+{
+ tGATT_BG_CONN_DEV *p_dev = NULL;
+ UINT8 i, j;
+ BOOLEAN ret = FALSE;
+
+ if ((p_dev = gatt_find_bg_dev(bd_addr)) == NULL)
+ {
+ return ret;
+ }
+
+ for (i = 0; i < GATT_MAX_APPS && p_dev->gatt_if[i] > 0; i ++)
+ {
+ if (p_dev->gatt_if[i] == gatt_if)
+ {
+ p_dev->gatt_if[i] = 0;
+
+ for (j = i + 1; j < GATT_MAX_APPS; j ++)
+ p_dev->gatt_if[j - 1] = p_dev->gatt_if[j];
+
+ if (p_dev->gatt_if[0] == 0)
+ {
+ ret = BTM_BleUpdateBgConnDev(FALSE, p_dev->remote_bda);
+ memset(p_dev, 0, sizeof(tGATT_BG_CONN_DEV));
+ }
+ else
+ ret = TRUE;
+
+ break;
+ }
+ }
+
+ return ret;
+}
+/*******************************************************************************
+**
+** Function gatt_deregister_bgdev_list
+**
+** Description deregister all related back ground connetion device.
+**
+** Returns pointer to the device record
+**
+*******************************************************************************/
+void gatt_deregister_bgdev_list(tGATT_IF gatt_if)
+{
+ tGATT_BG_CONN_DEV *p_dev_list = &gatt_cb.bgconn_dev[0];
+ UINT8 i , j, k;
+
+ for (i = 0 ; i <GATT_MAX_BG_CONN_DEV; i ++, p_dev_list ++ )
+ {
+ if (p_dev_list->in_use)
+ {
+ for (j = 0; j < GATT_MAX_APPS; j ++)
+ {
+ if (p_dev_list->gatt_if[j] == 0)
+ break;
+ else if (p_dev_list->gatt_if[j] == gatt_if)
+ {
+ for (k = j + 1; k < GATT_MAX_APPS; k ++)
+ p_dev_list->gatt_if[k - 1] = p_dev_list->gatt_if[k];
+
+ if (p_dev_list->gatt_if[0] == 0)
+ {
+ BTM_BleUpdateBgConnDev(FALSE, p_dev_list->remote_bda);
+ memset(p_dev_list, 0, sizeof(tGATT_BG_CONN_DEV));
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function gatt_reset_bgdev_list
+**
+** Description reset bg device list
+**
+** Returns pointer to the device record
+**
+*******************************************************************************/
+void gatt_reset_bgdev_list(void)
+{
+ memset(&gatt_cb.bgconn_dev, 0 , sizeof(tGATT_BG_CONN_DEV)*GATT_MAX_BG_CONN_DEV);
+
+}
+/*******************************************************************************
+**
+** Function gatt_update_auto_connect_dev
+**
+** Description This function add or remove a device for background connection
+** procedure.
+**
+** Parameters gatt_if: Application ID.
+** add: add peer device
+** bd_addr: peer device address.
+**
+** Returns TRUE if connection started; FALSE if connection start failure.
+**
+*******************************************************************************/
+BOOLEAN gatt_update_auto_connect_dev (tGATT_IF gatt_if, BOOLEAN add, BD_ADDR bd_addr)
+{
+ BOOLEAN ret = FALSE, exist_dev = FALSE;
+ tGATT_REG *p_reg;
+ tGATT_TCB *p_tcb = gatt_find_tcb_by_addr(bd_addr);
+
+ GATT_TRACE_API0 ("gatt_update_auto_connect_dev ");
+ /* Make sure app is registered */
+ if ((p_reg = gatt_get_regcb(gatt_if)) == NULL)
+ {
+ GATT_TRACE_ERROR1("gatt_update_auto_connect_dev - gatt_if is not registered", gatt_if);
+ return(FALSE);
+ }
+
+ if (add)
+ {
+ /* new device */
+ if (gatt_find_bg_dev(bd_addr))
+ exist_dev = TRUE;
+
+ if (gatt_add_bg_dev_list(gatt_if, bd_addr))
+ {
+ if (!exist_dev)
+ {
+ ret = BTM_BleUpdateBgConnDev(TRUE, bd_addr);
+ }
+ else
+ ret = TRUE;
+
+ /* if a connected device, update the link holding number */
+ if (p_tcb != NULL)
+ gatt_update_app_use_link_flag(gatt_if, p_tcb, TRUE, TRUE);
+ }
+ }
+ else
+ {
+ ret = gatt_remove_bg_dev_from_list(gatt_if, bd_addr);
+ }
+ return ret;
+}
+
+
+
+/*******************************************************************************
+**
+** Function gatt_get_conn_id
+**
+** Description This function returns a connecttion handle to a ATT server
+** if the server is already connected
+**
+** Parameters gatt_if: client interface.
+** bd_addr: peer device address.
+**
+** Returns Connection handle or invalid handle value
+**
+*******************************************************************************/
+UINT16 gatt_get_conn_id (tGATT_IF gatt_if, BD_ADDR bd_addr)
+{
+ tGATT_REG *p_reg;
+ tGATT_CLCB *p_clcb;
+ tGATT_TCB *p_tcb;
+ UINT8 i;
+
+ GATT_TRACE_API1 ("GATTC_GetConnIfConnected gatt_if=%d", gatt_if);
+ /* Do we have a transport to the peer ? If not, we are not connected */
+ if ((p_tcb = gatt_find_tcb_by_addr(bd_addr)) == NULL)
+ {
+ GATT_TRACE_EVENT0 ("GATTC_GetConnIfConnected - no TCB found");
+ return(GATT_INVALID_CONN_ID);
+ }
+
+ /* Make sure app is registered */
+ if ((p_reg = gatt_get_regcb(gatt_if)) == NULL)
+ {
+ GATT_TRACE_ERROR1("GATTC_GetConnIfConnected - gatt_if is not registered", gatt_if);
+ return(GATT_INVALID_CONN_ID);
+ }
+
+ /* Now see if the app already has a client control block to that peer */
+ for (i = 0, p_clcb = gatt_cb.clcb; i < GATT_CL_MAX_LCB; i++, p_clcb++)
+ {
+ if ( p_clcb->in_use && (p_clcb->p_reg == p_reg) && (p_clcb->p_tcb == p_tcb) )
+ {
+ return(p_clcb->conn_id);
+ }
+ }
+
+ /* If here, failed to allocate a client control block */
+ GATT_TRACE_ERROR1 ("gatt_get_conn_id: not connected- gatt_if: %u", gatt_if);
+ return(GATT_INVALID_CONN_ID);
+}
+
+
+
+
+#endif
+
+
diff --git a/stack/goep/goep_fs.c b/stack/goep/goep_fs.c
new file mode 100644
index 0000000..4373341
--- /dev/null
+++ b/stack/goep/goep_fs.c
@@ -0,0 +1,149 @@
+/*****************************************************************************
+**
+** Name: goep_fs.c
+**
+** File: Implements the Object Interface for GOEP Profiles
+**
+** Copyright (c) 2000-2004, WIDCOMM Inc., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include <string.h>
+#include <ctype.h>
+#include <stdio.h>
+
+#include "gki.h"
+#include "btu.h"
+#include "goep_fs.h"
+
+/*****************************************************************************
+**
+** Function: GOEP_OpenRsp
+**
+** Purpose: Report the status of tGOEP_OPEN_CBACK callback function.
+**
+** Parameters: fd - File handle.
+** status - Status of the operation.
+** file_size - total number of bytes in this file.
+** event_id - event id as given in the tGOEP_OPEN_CBACK function.
+**
+** Returns: void
+**
+*****************************************************************************/
+void GOEP_OpenRsp (tGOEP_FD fd, tGOEP_STATUS status, UINT32 file_size,
+ UINT16 event_id)
+{
+ tGOEP_OPEN_RSP *p_evt_msg;
+ UINT16 size = sizeof(tGOEP_OPEN_RSP);
+
+ /* get an GKI buffer and send the event along with the event data to BTU task */
+ p_evt_msg = (tGOEP_OPEN_RSP *)GKI_getbuf(size);
+ if (p_evt_msg != NULL)
+ {
+ memset(&p_evt_msg->hdr, 0, sizeof(BT_HDR));
+ p_evt_msg->hdr.event = event_id;
+ p_evt_msg->fd = fd;
+ p_evt_msg->status = status;
+ p_evt_msg->file_size = file_size;
+
+ GKI_send_msg(BTU_TASK, BTU_HCI_RCV_MBOX, p_evt_msg);
+ }
+}
+
+/*****************************************************************************
+**
+** Function: GOEP_ReadRsp
+**
+** Purpose: Report the status of tGOEP_READ_CBACK callback function.
+**
+** Parameters: fd - File handle.
+** status - Status of the operation.
+** bytes_read - total number of bytes read from the file.
+** event_id - event id as given in the tGOEP_READ_CBACK function.
+**
+** Returns: void
+**
+*****************************************************************************/
+void GOEP_ReadRsp (tGOEP_FD fd, tGOEP_STATUS status, UINT16 bytes_read,
+ UINT16 event_id)
+{
+ tGOEP_READ_RSP *p_evt_msg;
+ UINT16 size = sizeof(tGOEP_READ_RSP);
+
+ /* get an GKI buffer and send the event along with the event data to BTU task */
+ p_evt_msg = (tGOEP_READ_RSP *)GKI_getbuf(size);
+ if (p_evt_msg != NULL)
+ {
+ memset(&p_evt_msg->hdr, 0, sizeof(BT_HDR));
+ p_evt_msg->hdr.event = event_id;
+ p_evt_msg->fd = fd;
+ p_evt_msg->status = status;
+ p_evt_msg->bytes_read = bytes_read;
+
+ GKI_send_msg(BTU_TASK, BTU_HCI_RCV_MBOX, p_evt_msg);
+ }
+}
+
+/*****************************************************************************
+**
+** Function: GOEP_WriteRsp
+**
+** Purpose: Report the status of tGOEP_WRITE_CBACK callback function.
+**
+** Parameters: fd - File handle.
+** status - Status of the operation.
+** event_id - event id as given in the tGOEP_WRITE_CBACK function.
+**
+** Returns: void
+**
+*****************************************************************************/
+void GOEP_WriteRsp (tGOEP_FD fd, tGOEP_STATUS status, UINT16 event_id)
+{
+ tGOEP_WRITE_RSP *p_evt_msg;
+ UINT16 size = sizeof(tGOEP_WRITE_RSP);
+
+ /* get an GKI buffer and send the event along with the event data to BTU task */
+ p_evt_msg = (tGOEP_WRITE_RSP *)GKI_getbuf(size);
+ if (p_evt_msg != NULL)
+ {
+ memset(&p_evt_msg->hdr, 0, sizeof(BT_HDR));
+ p_evt_msg->hdr.event = event_id;
+ p_evt_msg->fd = fd;
+ p_evt_msg->status = status;
+
+ GKI_send_msg(BTU_TASK, BTU_HCI_RCV_MBOX, p_evt_msg);
+ }
+}
+
+/*****************************************************************************
+**
+** Function: GOEP_DirentryRsp
+**
+** Purpose: Report the status of tGOEP_DIRENTRY_CBACK callback function.
+**
+** Parameters: status - GOEP_OK if p_entry points to a valid entry.
+** GOEP_EODIR if no more entries (p_entry is ignored).
+** GOEP_FAIL if any errors have occurred.
+** event_id - event id as given in the tGOEP_DIRENTRY_CBACK function.
+**
+** Returns: void
+**
+*****************************************************************************/
+void GOEP_DirentryRsp (tGOEP_STATUS status, UINT16 event_id)
+{
+ tGOEP_DIRENTRY_RSP *p_evt_msg;
+ UINT16 size = sizeof(tGOEP_DIRENTRY_RSP);
+
+ /* get an GKI buffer and send the event along with the event data to BTU task */
+ p_evt_msg = (tGOEP_DIRENTRY_RSP *)GKI_getbuf(size);
+ if (p_evt_msg != NULL)
+ {
+ memset(&p_evt_msg->hdr, 0, sizeof(BT_HDR));
+ p_evt_msg->hdr.event = event_id;
+ p_evt_msg->status = status;
+
+ GKI_send_msg(BTU_TASK, BTU_HCI_RCV_MBOX, p_evt_msg);
+ }
+}
+
diff --git a/stack/goep/goep_int.h b/stack/goep/goep_int.h
new file mode 100644
index 0000000..476d55a
--- /dev/null
+++ b/stack/goep/goep_int.h
@@ -0,0 +1,55 @@
+/*****************************************************************************
+**
+** Name: goep_int.h
+**
+** File: Generic Object Exchange Profile Internal Definitions
+**
+** Copyright (c) 2000-2004, WIDCOMM Inc., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef GOEP_INT_H
+#define GOEP_INT_H
+
+#include "bt_target.h"
+#include "goep_util.h"
+
+
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+#define GOEP_PROTOCOL_COUNT 3
+
+
+
+/*****************************************************************************
+** Main Control Block Structure
+*****************************************************************************/
+
+typedef struct
+{
+ UINT8 trace_level;
+} tGOEP_CB;
+
+/*****************************************************************************
+** Function Prototypes
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if GOEP_DYNAMIC_MEMORY == FALSE
+GOEP_API extern tGOEP_CB goep_cb;
+#else
+GOEP_API extern tGOEP_CB *goep_cb_ptr;
+#define goep_cb (*goep_cb_ptr)
+#endif
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GOEP_INT_H */
diff --git a/stack/goep/goep_trace.c b/stack/goep/goep_trace.c
new file mode 100644
index 0000000..137f2cd
--- /dev/null
+++ b/stack/goep/goep_trace.c
@@ -0,0 +1,35 @@
+/******************************************************************************
+**
+** Name: goep_trace.c
+**
+** Description: This file contains the debug display prototypes
+**
+** Copyright (c) 2000-2004, WIDCOMM Inc., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+******************************************************************************/
+#include "bt_target.h"
+
+#if (defined(GOEP_INCLUDED) && GOEP_INCLUDED == TRUE)
+
+#include "goep_int.h"
+
+#if (defined (BT_USE_TRACES) && BT_USE_TRACES == TRUE)
+
+
+char *GOEP_ErrorName (tGOEP_ERRORS error)
+{
+ switch (error)
+ {
+ case GOEP_SUCCESS: return "GOEP_SUCCESS (0x00)";
+ case GOEP_ERROR: return "GOEP_ERROR (0x01)";
+ case GOEP_RESOURCES: return "GOEP_RESOURCES (0x02)";
+ case GOEP_INVALID_PARAM: return "GOEP_INVALID_PARAM (0x03)";
+ default: return "UNKNOWN GOEP ERROR";
+ }
+}
+
+/* end if BT_TRACE_VERBOSE */
+#endif
+
+#endif /* GOEP_INCLUDED */
diff --git a/stack/goep/goep_util.c b/stack/goep/goep_util.c
new file mode 100644
index 0000000..099177a
--- /dev/null
+++ b/stack/goep/goep_util.c
@@ -0,0 +1,504 @@
+/*****************************************************************************
+**
+** Name: goep_util.c
+**
+** File: Implements the Utility API of the GOEP Profile
+**
+** Copyright (c) 2000-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include <string.h>
+
+#include "btm_api.h"
+#include "btu.h" /* BTU_HCI_RCV_MBOX */
+#include "goep_util.h"
+#include "goep_fs.h"
+#include "goep_int.h"
+#include "rfcdefs.h" /* BT_PSM_RFCOMM */
+#include "wcassert.h" /* WC_ASSERT() */
+#include "l2c_api.h" /* WC_ASSERT() */
+
+#if GOEP_DYNAMIC_MEMORY == FALSE
+tGOEP_CB goep_cb;
+#endif
+
+/*******************************************************************************
+**
+** Function GOEP_Init
+**
+** Description GOEP initialization
+**
+** Returns nothing
+**
+*******************************************************************************/
+void GOEP_Init(void)
+{
+ memset(&goep_cb, 0, sizeof(tGOEP_CB));
+
+#if defined(GOEP_INITIAL_TRACE_LEVEL)
+ goep_cb.trace_level = GOEP_INITIAL_TRACE_LEVEL;
+#else
+ goep_cb.trace_level = BT_TRACE_LEVEL_NONE; /* No traces */
+#endif
+
+}
+
+
+
+/*****************************************************************************
+**
+** Function: GOEP_SetSecurityLevel()
+**
+** Purpose: Register security & encryption level for GOEP server.
+** This is not to be used for the GOEP command server.
+**
+**
+** Parameters:
+** char *pName service name; Typically GOEP_DEFAULT_SERVICE_NAME
+** Not used if BTM_SEC_SERVICE_NAME_LEN is 0.
+** UINT8 level Security level; The mandatory GOEP security level
+** GOEP_DEFAULT_SECURITY, is or'd in.
+**
+**
+** Returns: (BOOLEAN) TRUE if OK
+** FALSE if a bad parameter
+**
+*****************************************************************************/
+BOOLEAN GOEP_SetSecurityLevel (BOOLEAN bOrig, char *pName, UINT32 service,
+ UINT8 level, UINT8 scn)
+{
+#if BTM_SEC_SERVICE_NAME_LEN > 0
+ char sec_name[BTM_SEC_SERVICE_NAME_LEN+1];
+#endif
+
+ /* Guarantee that there is a name */
+ if (!pName)
+ {
+ pName = "";
+ }
+
+#if BTM_SEC_SERVICE_NAME_LEN > 0
+ GOEP_TRACE_EVENT4("GOEP: Set Security Mode; name '%s'; service %d; level 0x%02x; scn %d",
+ pName, service, level, scn);
+
+ /* Guarantee that name is not too long */
+ if (strlen (pName) >= BTM_SEC_SERVICE_NAME_LEN)
+ {
+ BCM_STRNCPY_S(sec_name, sizeof(sec_name), pName, BTM_SEC_SERVICE_NAME_LEN);
+ sec_name[BTM_SEC_SERVICE_NAME_LEN] = '\0';
+ pName = sec_name;
+ }
+#else
+ GOEP_TRACE_EVENT3("GOEP: Set Security Mode: service id %d; level 0x%02x; scn %d",
+ service, level, scn);
+#endif
+
+ /* Register with Security Manager for the specific security level */
+ if (!BTM_SetSecurityLevel (bOrig, pName, (UINT8)service, level, BT_PSM_RFCOMM,
+ BTM_SEC_PROTO_RFCOMM, scn))
+ {
+ GOEP_TRACE_WARNING1("GOEP: Security Registration failed for %s", pName);
+ return (FALSE);
+ }
+
+ return (TRUE);
+}
+
+/*****************************************************************************
+**
+** Function: GOEP_SetTraceLevel
+**
+** Purpose: This function changes the trace level
+**
+** Returns: Nothing
+*****************************************************************************/
+void GOEP_SetTraceLevel(UINT8 level)
+{
+ goep_cb.trace_level = level;
+}
+
+/*******************************************************************************
+**
+** Function GOEP_FreeBuf
+**
+** Description free memory for specified packet
+**
+** Returns void
+**
+*******************************************************************************/
+void GOEP_FreeBuf (void **p_buf)
+{
+ if (p_buf && *p_buf)
+ {
+ GKI_freebuf(*p_buf);
+ *p_buf = NULL;
+ }
+}
+
+/*******************************************************************************
+**
+** Function GOEP_SendMsg
+**
+** Description send a message to BTU task
+**
+** Returns void
+**
+*******************************************************************************/
+void GOEP_SendMsg (void *p_msg)
+
+{
+ if(p_msg)
+ {
+ GKI_send_msg(BTU_TASK, BTU_HCI_RCV_MBOX, p_msg);
+ }
+}
+
+/*****************************************************************************
+**
+** Function: GOEP_Register()
+**
+** Purpose: Register an OBEX profile with SDP
+**
+** Parameters:
+**
+** char *p_name service name; optional (may be NULL)
+** UINT32 *phSDP handle to the created record; cannot be NULL
+** UINT8 scn scn desired for the service; must be > 0
+** UINT16 version version of the service; optional (may be 0)
+**
+** Returns: (tGOEP_ERRORS) GOEP_SUCCESS if ok; GOEP_ERROR on error
+**
+** Notes:
+**
+**
+** Preconditions:
+** - phSDP must be set (to return the SDP record handle)
+** - scn must be set
+**
+** Postconditions:
+** -
+**
+*****************************************************************************/
+tGOEP_ERRORS GOEP_Register (char *p_name,
+ UINT32 *phSDP,
+ UINT8 scn,
+ UINT8 num_srv_class,
+ UINT16 *p_service_class,
+ UINT16 profile_id,
+ UINT16 version)
+{
+ tGOEP_ERRORS status = GOEP_ERROR;
+ tSDP_PROTOCOL_ELEM protoList [GOEP_PROTOCOL_COUNT];
+ UINT16 browse;
+
+ /* GOEP_TRACE_EVENT4("GOEP: Register with SDP: name %s, scn %d, class %#x, version %d)",
+ p_name ? p_name : "NULL",
+ (UINT16)scn,
+ (UINT16)p_service_class[0],
+ version); */
+
+ /* parameter checking */
+ WC_ASSERT(phSDP);
+ WC_ASSERT(scn);
+
+ /* parameter checking */
+ if (!(phSDP && scn))
+ {
+ return (GOEP_INVALID_PARAM);
+ }
+
+ *phSDP = SDP_CreateRecord();
+ WC_ASSERT(*phSDP);
+ GOEP_TRACE_API2("GOEP: Register with SDP: scn %d, record:0x%08x", scn, *phSDP);
+
+ /* could a SDP handle be allocated? */
+ if (*phSDP == 0)
+ {
+ return (GOEP_RESOURCES);
+ }
+
+ /* add service class */
+ if (SDP_AddServiceClassIdList(*phSDP, num_srv_class, p_service_class))
+ {
+ /* add protocol list, including RFCOMM scn */
+ protoList[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+ protoList[0].num_params = 0;
+ protoList[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
+ protoList[1].num_params = 1;
+ protoList[1].params[0] = scn;
+ protoList[2].protocol_uuid = UUID_PROTOCOL_OBEX;
+ protoList[2].num_params = 0;
+
+/* coverity[uninit_use_in_call]
+FALSE-POSITIVE: coverity says
+Event uninit_use_in_call: Using uninitialized element of array "(protoList)->params" in call to function "SDP_AddProtocolList"
+Event uninit_use_in_call: Using uninitialized value "(protoList)->num_params" in call to function "SDP_AddProtocolList"
+Event uninit_use_in_call: Using uninitialized value "(protoList)->protocol_uuid" in call to function "SDP_AddProtocolList"
+SDP_AddProtocolList() uses (protoList)->params only when (protoList)->num_params is non-0
+*/
+ if (SDP_AddProtocolList(*phSDP, GOEP_PROTOCOL_COUNT, protoList))
+ {
+ /* optional: if name is not NULL, add a name entry */
+ if (p_name && p_name[0] )
+ {
+ SDP_AddAttribute(*phSDP,
+ (UINT16)ATTR_ID_SERVICE_NAME,
+ (UINT8)TEXT_STR_DESC_TYPE,
+ (UINT32)(strlen(p_name) + 1),
+ (UINT8 *)p_name);
+ } /* end of setting optional name */
+ /* Add in the Bluetooth Profile Descriptor List for IrMCSync [Sync s7.1.2] */
+ if (version)
+ {
+ SDP_AddProfileDescriptorList(*phSDP, profile_id, version);
+ } /* end of setting optional profile version */
+ status = GOEP_SUCCESS;
+ } /* end of setting mandatory protocol list */
+ } /* end of setting mandatory service class */
+
+ /* Make the service browseable */
+ browse = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
+ if (status == GOEP_SUCCESS && SDP_AddUuidSequence (*phSDP,
+ ATTR_ID_BROWSE_GROUP_LIST,
+ 1,
+ &browse) == FALSE)
+ {
+ status = GOEP_ERROR;
+ }
+
+ if (status != GOEP_SUCCESS)
+ {
+ SDP_DeleteRecord(*phSDP);
+ GOEP_TRACE_DEBUG1("GOEP_Register status: %d", status);
+ }
+ else
+ {
+ GOEP_TRACE_EVENT1("GOEP: Register with SDP returns handle 0x%08x", *phSDP);
+ }
+
+ return (status);
+}
+
+/*****************************************************************************
+**
+** Function: GOEP_Register2()
+**
+** Purpose: Register an OBEX 1.4 profile with SDP
+**
+** Parameters:
+**
+** char *p_name service name; optional (may be NULL)
+** UINT32 *phSDP handle to the created record; cannot be NULL
+** UINT8 scn scn desired for the service; must be > 0
+** UINT16 psm psm desired for the service; must be an legal L2CAP dynamic PSM
+** UINT16 version version of the service; optional (may be 0)
+**
+** Returns: (tGOEP_ERRORS) GOEP_SUCCESS if ok; GOEP_ERROR on error
+**
+** Notes:
+**
+**
+** Preconditions:
+** - phSDP must be set (to return the SDP record handle)
+** - psm must be set
+**
+** Postconditions:
+** -
+**
+*****************************************************************************/
+tGOEP_ERRORS GOEP_Register2 (char *p_name,
+ UINT32 *phSDP,
+ UINT16 psm,
+ UINT8 num_srv_class,
+ UINT16 *p_service_class,
+ UINT16 profile_id,
+ UINT16 version)
+{
+ tGOEP_ERRORS status = GOEP_ERROR;
+ tSDP_PROTOCOL_ELEM protoList [GOEP_PROTOCOL_COUNT];
+ UINT16 browse;
+ UINT16 num_elem;
+ UINT8 *p, array[3];
+
+ /* GOEP_TRACE_EVENT4("GOEP: Register2 with SDP: name %s, psm 0x%x, class %#x, version %d)",
+ p_name ? p_name : "NULL",
+ (UINT16)psm,
+ (UINT16)p_service_class[0],
+ version); */
+
+ /* parameter checking */
+ WC_ASSERT(phSDP);
+
+ /* parameter checking */
+ if (!(phSDP && L2C_IS_VALID_PSM(psm)))
+ {
+ return (GOEP_INVALID_PARAM);
+ }
+
+ *phSDP = SDP_CreateRecord();
+ WC_ASSERT(*phSDP);
+ GOEP_TRACE_API2("GOEP: Register with SDP(2): psm 0x%x, record:0x%08x", psm, *phSDP);
+
+ /* could a SDP handle be allocated? */
+ if (*phSDP == 0)
+ {
+ return (GOEP_RESOURCES);
+ }
+
+ /* add service class */
+ if (SDP_AddServiceClassIdList(*phSDP, num_srv_class, p_service_class))
+ {
+ /* add protocol list, including RFCOMM scn */
+ num_elem=0;
+ protoList[num_elem].protocol_uuid = UUID_PROTOCOL_L2CAP;
+ protoList[num_elem].num_params = 0;
+ num_elem++;
+ protoList[num_elem].protocol_uuid = UUID_PROTOCOL_OBEX;
+ protoList[num_elem].num_params = 0;
+ num_elem++;
+/* coverity[uninit_use_in_call]
+FALSE-POSITIVE: coverity says
+Event uninit_use_in_call: Using uninitialized element of array "(protoList)->params" in call to function "SDP_AddProtocolList"
+Event uninit_use_in_call: Using uninitialized value "(protoList)->num_params" in call to function "SDP_AddProtocolList"
+Event uninit_use_in_call: Using uninitialized value "(protoList)->protocol_uuid" in call to function "SDP_AddProtocolList"
+SDP_AddProtocolList() uses (protoList)->params only when (protoList)->num_params is non-0
+*/
+ if (SDP_AddProtocolList(*phSDP, num_elem, protoList))
+ {
+ p = array;
+ UINT16_TO_BE_STREAM (p, psm);
+ SDP_AddAttribute (*phSDP, ATTR_ID_OBX_OVR_L2CAP_PSM, UINT_DESC_TYPE, 2, array);
+
+ /* optional: if name is not NULL, add a name entry */
+ if (p_name && p_name[0] )
+ {
+ SDP_AddAttribute(*phSDP,
+ (UINT16)ATTR_ID_SERVICE_NAME,
+ (UINT8)TEXT_STR_DESC_TYPE,
+ (UINT32)(strlen(p_name) + 1),
+ (UINT8 *)p_name);
+ } /* end of setting optional name */
+ /* Add in the Bluetooth Profile Descriptor List for IrMCSync [Sync s7.1.2] */
+ if (version)
+ {
+ SDP_AddProfileDescriptorList(*phSDP, profile_id, version);
+ } /* end of setting optional profile version */
+ status = GOEP_SUCCESS;
+ } /* end of setting mandatory protocol list */
+ } /* end of setting mandatory service class */
+
+ /* Make the service browseable */
+ browse = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
+ if (status == GOEP_SUCCESS && SDP_AddUuidSequence (*phSDP,
+ ATTR_ID_BROWSE_GROUP_LIST,
+ 1,
+ &browse) == FALSE)
+ {
+ status = GOEP_ERROR;
+ }
+
+ if (status != GOEP_SUCCESS)
+ {
+ SDP_DeleteRecord(*phSDP);
+ GOEP_TRACE_DEBUG1("GOEP_Register status: %d", status);
+ }
+ else
+ {
+ GOEP_TRACE_EVENT1("GOEP: Register with SDP returns handle 0x%08x", *phSDP);
+ }
+
+
+ return (status);
+}
+
+/*****************************************************************************
+**
+** Function: GOEP_AddProtoLists()
+**
+** Purpose: Add the AdditionalProtocolDescriptorLists attribute
+** to a SDP record
+**
+** Parameters:
+**
+** UINT32 sdp_hdl the SDP record handle
+** UINT8 scn scn desired for the service; must be > 0
+**
+** Returns: (tGOEP_ERRORS) GOEP_SUCCESS if ok; GOEP_ERROR on error
+**
+** Notes:
+**
+**
+** Preconditions:
+** - sdp_hdl must be set (to the SDP record handle from GOEP_Register())
+** - scn must be set
+**
+** Postconditions:
+** -
+**
+*****************************************************************************/
+#if (BPP_INCLUDED == TRUE)
+tGOEP_ERRORS GOEP_AddProtoLists ( UINT32 sdp_hdl, UINT8 scn)
+{
+ tGOEP_ERRORS status = GOEP_ERROR;
+ tSDP_PROTO_LIST_ELEM proto_list_elem;
+ tSDP_PROTOCOL_ELEM *p_proto_list;
+
+ /*
+ GOEP_TRACE_EVENT4("GOEP: Register with SDP: name %s, scn %d, class %#x, version %d)",
+ p_name ? p_name : "NULL",
+ (UINT16)scn,
+ (UINT16)p_service_class[0],
+ version);
+ */
+
+ /* parameter checking */
+ WC_ASSERT(sdp_hdl);
+ WC_ASSERT(scn);
+
+ /* parameter checking */
+ if (!(sdp_hdl && scn))
+ {
+ return (GOEP_INVALID_PARAM);
+ }
+
+ proto_list_elem.num_elems = 0;
+ p_proto_list = &proto_list_elem.list_elem[proto_list_elem.num_elems++];
+ p_proto_list->num_params = 0;
+ p_proto_list->protocol_uuid = UUID_PROTOCOL_L2CAP;
+ p_proto_list = &proto_list_elem.list_elem[proto_list_elem.num_elems++];
+ p_proto_list->num_params = 1;
+ p_proto_list->params[0] = scn;
+ p_proto_list->protocol_uuid = UUID_PROTOCOL_RFCOMM;
+ p_proto_list = &proto_list_elem.list_elem[proto_list_elem.num_elems++];
+ p_proto_list->num_params = 0;
+ p_proto_list->protocol_uuid = UUID_PROTOCOL_OBEX;
+
+ /* add protocol list, including RFCOMM scn */
+ if(SDP_AddAdditionProtoLists( sdp_hdl, 1, &proto_list_elem))
+ status = GOEP_SUCCESS;
+
+ GOEP_TRACE_DEBUG1("GOEP_AddProtoLists status: %s", GOEP_ErrorName(status));
+
+ return (status);
+}
+#endif
+
+/*****************************************************************************
+**
+** Function: goep_dummy
+**
+** Purpose: This is to work around a GCC build linking problem
+**
+** Returns: none
+**
+*****************************************************************************/
+#if (RPC_INCLUDED == TRUE && RPC_TRACE_ONLY == TRUE && GOEP_FS_INCLUDED == TRUE)
+static void goep_dummy(void)
+{
+ GOEP_OpenRsp(0, 0, 0, 0);
+}
+#endif /* RPC stuff */
+
+
diff --git a/stack/hcic/hciblecmds.c b/stack/hcic/hciblecmds.c
new file mode 100644
index 0000000..d491ca4
--- /dev/null
+++ b/stack/hcic/hciblecmds.c
@@ -0,0 +1,739 @@
+/*****************************************************************************
+**
+** Name: hciblecmds.c
+**
+** Description: This file contains function of the HCIC unit to
+** format and send HCI commands.
+**
+**
+** Copyright (c) 1999-2008, Broadcom Corp., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+******************************************************************************/
+
+#include "bt_target.h"
+#include "gki.h"
+#include "hcidefs.h"
+#include "hcimsgs.h"
+#include "hcidefs.h"
+#include "btu.h"
+
+#include <stddef.h>
+#include <string.h>
+
+#if (defined BLE_INCLUDED) && (BLE_INCLUDED == TRUE)
+
+BOOLEAN btsnd_hcic_ble_reset(void)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_CMD)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_BLE_RESET);
+ UINT8_TO_STREAM (pp, 0);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+
+}
+
+BOOLEAN btsnd_hcic_ble_set_evt_mask (BT_EVENT_MASK event_mask)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_SET_EVENT_MASK)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_SET_EVENT_MASK;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_BLE_SET_EVENT_MASK);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_SET_EVENT_MASK);
+ ARRAY8_TO_STREAM (pp, event_mask);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+
+BOOLEAN btsnd_hcic_ble_read_buffer_size (void)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_CMD)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_BLE_READ_BUFFER_SIZE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_CMD);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_ble_read_local_spt_feat (void)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_CMD)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_BLE_READ_LOCAL_SPT_FEAT);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_CMD);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_ble_set_local_used_feat (UINT8 feat_set[8])
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_SET_USED_FEAT_CMD)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_SET_USED_FEAT_CMD;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_BLE_WRITE_LOCAL_SPT_FEAT);
+ ARRAY_TO_STREAM (pp, feat_set, HCIC_PARAM_SIZE_SET_USED_FEAT_CMD);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_ble_set_random_addr (BD_ADDR random_bda)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_WRITE_RANDOM_ADDR_CMD)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_RANDOM_ADDR_CMD;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_BLE_WRITE_RANDOM_ADDR);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_RANDOM_ADDR_CMD);
+
+ BDADDR_TO_STREAM (pp, random_bda);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_ble_write_adv_params (UINT16 adv_int_min, UINT16 adv_int_max,
+ UINT8 adv_type, UINT8 addr_type_own,
+ UINT8 addr_type_dir, BD_ADDR direct_bda,
+ UINT8 channel_map, UINT8 adv_filter_policy)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_BLE_WRITE_ADV_PARAMS)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_WRITE_ADV_PARAMS ;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_BLE_WRITE_ADV_PARAMS);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_WRITE_ADV_PARAMS );
+
+ UINT16_TO_STREAM (pp, adv_int_min);
+ UINT16_TO_STREAM (pp, adv_int_max);
+ UINT8_TO_STREAM (pp, adv_type);
+ UINT8_TO_STREAM (pp, addr_type_own);
+ UINT8_TO_STREAM (pp, addr_type_dir);
+ BDADDR_TO_STREAM (pp, direct_bda);
+ UINT8_TO_STREAM (pp, channel_map);
+ UINT8_TO_STREAM (pp, adv_filter_policy);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+BOOLEAN btsnd_hcic_ble_read_adv_chnl_tx_power (void)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_CMD)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_BLE_READ_ADV_CHNL_TX_POWER);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_CMD);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+
+}
+
+BOOLEAN btsnd_hcic_ble_set_adv_data (UINT8 data_len, UINT8 *p_data)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA + 1)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA + 1;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_BLE_WRITE_ADV_DATA);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA + 1);
+
+ memset(pp, 0, HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA);
+
+ if (p_data != NULL && data_len > 0)
+ {
+ if (data_len > HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA)
+ data_len = HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA;
+
+ UINT8_TO_STREAM (pp, data_len);
+
+ ARRAY_TO_STREAM (pp, p_data, data_len);
+ }
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+
+ return (TRUE);
+}
+BOOLEAN btsnd_hcic_ble_set_scan_rsp_data (UINT8 data_len, UINT8 *p_scan_rsp)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_BLE_WRITE_SCAN_RSP + 1)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_WRITE_SCAN_RSP + 1;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_BLE_WRITE_SCAN_RSP_DATA);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_WRITE_SCAN_RSP + 1);
+
+ memset(pp, 0, HCIC_PARAM_SIZE_BLE_WRITE_SCAN_RSP);
+
+ if (p_scan_rsp != NULL && data_len > 0)
+ {
+
+ if (data_len > HCIC_PARAM_SIZE_BLE_WRITE_SCAN_RSP )
+ data_len = HCIC_PARAM_SIZE_BLE_WRITE_SCAN_RSP;
+
+ UINT8_TO_STREAM (pp, data_len);
+
+ ARRAY_TO_STREAM (pp, p_scan_rsp, data_len);
+ }
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_ble_set_adv_enable (UINT8 adv_enable)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_WRITE_ADV_ENABLE)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_ADV_ENABLE;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_BLE_WRITE_ADV_ENABLE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_ADV_ENABLE);
+
+ UINT8_TO_STREAM (pp, adv_enable);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+BOOLEAN btsnd_hcic_ble_set_scan_params (UINT8 scan_type,
+ UINT16 scan_int, UINT16 scan_win,
+ UINT8 addr_type_own, UINT8 scan_filter_policy)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_BLE_WRITE_SCAN_PARAM)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_WRITE_SCAN_PARAM;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_BLE_WRITE_SCAN_PARAMS);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_WRITE_SCAN_PARAM);
+
+ UINT8_TO_STREAM (pp, scan_type);
+ UINT16_TO_STREAM (pp, scan_int);
+ UINT16_TO_STREAM (pp, scan_win);
+ UINT8_TO_STREAM (pp, addr_type_own);
+ UINT8_TO_STREAM (pp, scan_filter_policy);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_ble_set_scan_enable (UINT8 scan_enable, UINT8 duplicate)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_BLE_WRITE_SCAN_ENABLE)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_WRITE_SCAN_ENABLE;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_BLE_WRITE_SCAN_ENABLE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_WRITE_SCAN_ENABLE);
+
+ UINT8_TO_STREAM (pp, scan_enable);
+ UINT8_TO_STREAM (pp, duplicate);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+/* link layer connection management commands */
+BOOLEAN btsnd_hcic_ble_create_ll_conn (UINT16 scan_int, UINT16 scan_win,
+ UINT8 init_filter_policy,
+ UINT8 addr_type_peer, BD_ADDR bda_peer,
+ UINT8 addr_type_own,
+ UINT16 conn_int_min, UINT16 conn_int_max,
+ UINT16 conn_latency, UINT16 conn_timeout,
+ UINT16 min_ce_len, UINT16 max_ce_len)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_BLE_CREATE_LL_CONN)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_CREATE_LL_CONN;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_BLE_CREATE_LL_CONN);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_CREATE_LL_CONN);
+
+ UINT16_TO_STREAM (pp, scan_int);
+ UINT16_TO_STREAM (pp, scan_win);
+ UINT8_TO_STREAM (pp, init_filter_policy);
+
+ UINT8_TO_STREAM (pp, addr_type_peer);
+ BDADDR_TO_STREAM (pp, bda_peer);
+ UINT8_TO_STREAM (pp, addr_type_own);
+
+ UINT16_TO_STREAM (pp, conn_int_min);
+ UINT16_TO_STREAM (pp, conn_int_max);
+ UINT16_TO_STREAM (pp, conn_latency);
+ UINT16_TO_STREAM (pp, conn_timeout);
+
+ UINT16_TO_STREAM (pp, min_ce_len);
+ UINT16_TO_STREAM (pp, max_ce_len);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_ble_create_conn_cancel (void)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_BLE_CREATE_CONN_CANCEL)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_CREATE_CONN_CANCEL;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_BLE_CREATE_CONN_CANCEL);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_CREATE_CONN_CANCEL);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_ble_read_white_list_size (void)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_CMD)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_BLE_READ_WHITE_LIST_SIZE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_CMD);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_ble_clear_white_list (void)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_CLEAR_WHITE_LIST)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CLEAR_WHITE_LIST;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_BLE_CLEAR_WHITE_LIST);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_CLEAR_WHITE_LIST);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_ble_add_white_list (UINT8 addr_type, BD_ADDR bda)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_ADD_WHITE_LIST)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_ADD_WHITE_LIST;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_BLE_ADD_WHITE_LIST);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_ADD_WHITE_LIST);
+
+ UINT8_TO_STREAM (pp, addr_type);
+ BDADDR_TO_STREAM (pp, bda);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_ble_remove_from_white_list (UINT8 addr_type, BD_ADDR bda)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_REMOVE_WHITE_LIST)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_REMOVE_WHITE_LIST;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_BLE_REMOVE_WHITE_LIST);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_REMOVE_WHITE_LIST);
+
+ UINT8_TO_STREAM (pp, addr_type);
+ BDADDR_TO_STREAM (pp, bda);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_ble_upd_ll_conn_params (UINT16 handle,
+ UINT16 conn_int_min, UINT16 conn_int_max,
+ UINT16 conn_latency, UINT16 conn_timeout,
+ UINT16 min_ce_len, UINT16 max_ce_len)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_BLE_UPD_LL_CONN_PARAMS)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_UPD_LL_CONN_PARAMS;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_BLE_UPD_LL_CONN_PARAMS);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_UPD_LL_CONN_PARAMS);
+
+ UINT16_TO_STREAM (pp, handle);
+
+ UINT16_TO_STREAM (pp, conn_int_min);
+ UINT16_TO_STREAM (pp, conn_int_max);
+ UINT16_TO_STREAM (pp, conn_latency);
+ UINT16_TO_STREAM (pp, conn_timeout);
+ UINT16_TO_STREAM (pp, min_ce_len);
+ UINT16_TO_STREAM (pp, max_ce_len);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_ble_set_host_chnl_class (UINT8 chnl_map[HCIC_BLE_CHNL_MAP_SIZE])
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_SET_HOST_CHNL_CLASS)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_SET_HOST_CHNL_CLASS;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_BLE_SET_HOST_CHNL_CLASS);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_SET_HOST_CHNL_CLASS);
+
+ ARRAY_TO_STREAM (pp, chnl_map, HCIC_BLE_CHNL_MAP_SIZE);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_ble_read_chnl_map (UINT16 handle)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_CHNL_MAP)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CHNL_MAP;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_BLE_READ_CHNL_MAP);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_CHNL_MAP);
+
+ UINT16_TO_STREAM (pp, handle);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_ble_read_remote_feat (UINT16 handle)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_BLE_READ_REMOTE_FEAT)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_READ_REMOTE_FEAT;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_BLE_READ_REMOTE_FEAT);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_READ_REMOTE_FEAT);
+
+ UINT16_TO_STREAM (pp, handle);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+/* security management commands */
+BOOLEAN btsnd_hcic_ble_encrypt (UINT8 *key, UINT8 key_len,
+ UINT8 *plain_text, UINT8 pt_len,
+ void *p_cmd_cplt_cback)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(sizeof(BT_HDR) + sizeof (void *) +
+ HCIC_PARAM_SIZE_BLE_ENCRYPT)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_ENCRYPT;
+ p->offset = sizeof(void *);
+
+ *((void **)pp) = p_cmd_cplt_cback; /* Store command complete callback in buffer */
+ pp += sizeof(void *); /* Skip over callback pointer */
+
+
+ UINT16_TO_STREAM (pp, HCI_BLE_ENCRYPT);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_ENCRYPT);
+
+ memset(pp, 0, HCIC_PARAM_SIZE_BLE_ENCRYPT);
+
+ if (key_len > HCIC_BLE_ENCRYT_KEY_SIZE) key_len = HCIC_BLE_ENCRYT_KEY_SIZE;
+ if (pt_len > HCIC_BLE_ENCRYT_KEY_SIZE) pt_len = HCIC_BLE_ENCRYT_KEY_SIZE;
+
+ ARRAY_TO_STREAM (pp, key, key_len);
+ pp += (HCIC_BLE_ENCRYT_KEY_SIZE - key_len);
+ ARRAY_TO_STREAM (pp, plain_text, pt_len);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_ble_rand (void *p_cmd_cplt_cback)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(sizeof(BT_HDR) + sizeof (void *) +
+ HCIC_PARAM_SIZE_BLE_RAND)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_RAND;
+ p->offset = sizeof(void *);
+
+ *((void **)pp) = p_cmd_cplt_cback; /* Store command complete callback in buffer */
+ pp += sizeof(void *); /* Skip over callback pointer */
+
+ UINT16_TO_STREAM (pp, HCI_BLE_RAND);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_RAND);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_ble_start_enc (UINT16 handle, UINT8 rand[HCIC_BLE_RAND_DI_SIZE],
+ UINT16 ediv, UINT8 ltk[HCIC_BLE_ENCRYT_KEY_SIZE])
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_BLE_START_ENC)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_START_ENC;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_BLE_START_ENC);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_START_ENC);
+
+ UINT16_TO_STREAM (pp, handle);
+ ARRAY_TO_STREAM (pp, rand, HCIC_BLE_RAND_DI_SIZE);
+ UINT16_TO_STREAM (pp, ediv);
+ ARRAY_TO_STREAM (pp, ltk, HCIC_BLE_ENCRYT_KEY_SIZE);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_ble_ltk_req_reply (UINT16 handle, UINT8 ltk[HCIC_BLE_ENCRYT_KEY_SIZE])
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_LTK_REQ_REPLY)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_LTK_REQ_REPLY;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_BLE_LTK_REQ_REPLY);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_LTK_REQ_REPLY);
+
+ UINT16_TO_STREAM (pp, handle);
+ ARRAY_TO_STREAM (pp, ltk, HCIC_BLE_ENCRYT_KEY_SIZE);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_ble_ltk_req_neg_reply (UINT16 handle)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_LTK_REQ_NEG_REPLY)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_LTK_REQ_NEG_REPLY;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_BLE_LTK_REQ_NEG_REPLY);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_LTK_REQ_NEG_REPLY);
+
+ UINT16_TO_STREAM (pp, handle);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_ble_read_supported_states (void)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_CMD)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_BLE_READ_SUPPORTED_STATES);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_CMD);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+#endif
diff --git a/stack/hcic/hcicmds.c b/stack/hcic/hcicmds.c
new file mode 100644
index 0000000..edc98a2
--- /dev/null
+++ b/stack/hcic/hcicmds.c
@@ -0,0 +1,3349 @@
+/*****************************************************************************
+**
+** Name: hcicmds.c
+**
+** Description: This file contains function of the HCIC unit to
+** format and send HCI commands.
+**
+**
+** Copyright (c) 1999-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+******************************************************************************/
+
+#include "bt_target.h"
+#include "gki.h"
+#include "hcidefs.h"
+#include "hcimsgs.h"
+#include "hcidefs.h"
+#include "btu.h"
+
+#include <stddef.h>
+#include <string.h>
+
+#if defined (LMP_TEST)
+#include <script.h>
+#define btu_hcif_send_cmd(p1, p2) HCI_CMD_TO_LOWER((p2))
+#else
+#include "btm_int.h" /* Included for UIPC_* macro definitions */
+#endif
+
+BOOLEAN btsnd_hcic_inquiry(const LAP inq_lap, UINT8 duration, UINT8 response_cnt)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_INQUIRY)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_INQUIRY;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_INQUIRY);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_INQUIRY);
+
+ LAP_TO_STREAM (pp, inq_lap);
+ UINT8_TO_STREAM (pp, duration);
+ UINT8_TO_STREAM (pp, response_cnt);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_inq_cancel(void)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_INQ_CANCEL)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_INQ_CANCEL;
+ p->offset = 0;
+ UINT16_TO_STREAM (pp, HCI_INQUIRY_CANCEL);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_INQ_CANCEL);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_per_inq_mode (UINT16 max_period, UINT16 min_period,
+ const LAP inq_lap, UINT8 duration, UINT8 response_cnt)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_PER_INQ_MODE)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_PER_INQ_MODE;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_PERIODIC_INQUIRY_MODE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_PER_INQ_MODE);
+
+ UINT16_TO_STREAM (pp, max_period);
+ UINT16_TO_STREAM (pp, min_period);
+ LAP_TO_STREAM (pp, inq_lap);
+ UINT8_TO_STREAM (pp, duration);
+ UINT8_TO_STREAM (pp, response_cnt);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_exit_per_inq (void)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_EXIT_PER_INQ)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_EXIT_PER_INQ;
+ p->offset = 0;
+ UINT16_TO_STREAM (pp, HCI_EXIT_PERIODIC_INQUIRY_MODE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_EXIT_PER_INQ);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+
+BOOLEAN btsnd_hcic_create_conn(BD_ADDR dest, UINT16 packet_types,
+ UINT8 page_scan_rep_mode, UINT8 page_scan_mode,
+ UINT16 clock_offset, UINT8 allow_switch)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_CREATE_CONN)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+#ifndef BT_10A
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CREATE_CONN;
+#else
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CREATE_CONN - 1;
+#endif
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_CREATE_CONNECTION);
+#ifndef BT_10A
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_CREATE_CONN);
+#else
+ UINT8_TO_STREAM (pp, (HCIC_PARAM_SIZE_CREATE_CONN - 1));
+#endif
+ BDADDR_TO_STREAM (pp, dest);
+ UINT16_TO_STREAM (pp, packet_types);
+ UINT8_TO_STREAM (pp, page_scan_rep_mode);
+ UINT8_TO_STREAM (pp, page_scan_mode);
+ UINT16_TO_STREAM (pp, clock_offset);
+#if !defined (BT_10A)
+ UINT8_TO_STREAM (pp, allow_switch);
+#endif
+/* If calling from LMP_TEST or ScriptEngine, then send HCI command immediately */
+#if (!defined (LMP_TEST) && !defined(BTISE))
+ btm_acl_paging (p, dest);
+#else
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+#endif
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_disconnect (UINT16 handle, UINT8 reason)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_DISCONNECT)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_DISCONNECT;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_DISCONNECT);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_DISCONNECT);
+ UINT16_TO_STREAM (pp, handle);
+ UINT8_TO_STREAM (pp, reason);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+/* If calling from LMP_TEST or ScriptEngine, then send HCI command immediately */
+#if (!defined (LMP_TEST) && !defined(BTISE))
+// btla-specific ++
+ // btm_acl_set_discing(TRUE);
+// btla-specific --
+#endif
+ return (TRUE);
+}
+
+#if BTM_SCO_INCLUDED == TRUE
+BOOLEAN btsnd_hcic_add_SCO_conn (UINT16 handle, UINT16 packet_types)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_ADD_SCO_CONN)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_ADD_SCO_CONN;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_ADD_SCO_CONNECTION);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_ADD_SCO_CONN);
+
+ UINT16_TO_STREAM (pp, handle);
+ UINT16_TO_STREAM (pp, packet_types);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+#endif /* BTM_SCO_INCLUDED */
+
+BOOLEAN btsnd_hcic_create_conn_cancel(BD_ADDR dest)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_CREATE_CONN_CANCEL)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CREATE_CONN_CANCEL;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_CREATE_CONNECTION_CANCEL);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_CREATE_CONN_CANCEL);
+
+ BDADDR_TO_STREAM (pp, dest);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_accept_conn (BD_ADDR dest, UINT8 role)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_ACCEPT_CONN)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_ACCEPT_CONN;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_ACCEPT_CONNECTION_REQUEST);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_ACCEPT_CONN);
+ BDADDR_TO_STREAM (pp, dest);
+ UINT8_TO_STREAM (pp, role);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_reject_conn (BD_ADDR dest, UINT8 reason)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_REJECT_CONN)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_REJECT_CONN;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_REJECT_CONNECTION_REQUEST);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_REJECT_CONN);
+
+ BDADDR_TO_STREAM (pp, dest);
+ UINT8_TO_STREAM (pp, reason);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_link_key_req_reply (BD_ADDR bd_addr, LINK_KEY link_key)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_LINK_KEY_REQ_REPLY)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_LINK_KEY_REQ_REPLY;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_LINK_KEY_REQUEST_REPLY);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_LINK_KEY_REQ_REPLY);
+
+ BDADDR_TO_STREAM (pp, bd_addr);
+ ARRAY16_TO_STREAM (pp, link_key);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_link_key_neg_reply (BD_ADDR bd_addr)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_LINK_KEY_NEG_REPLY)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_LINK_KEY_NEG_REPLY;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_LINK_KEY_REQUEST_NEG_REPLY);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_LINK_KEY_NEG_REPLY);
+
+ BDADDR_TO_STREAM (pp, bd_addr);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_pin_code_req_reply (BD_ADDR bd_addr, UINT8 pin_code_len,
+ PIN_CODE pin_code)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+ int i;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_PIN_CODE_REQ_REPLY)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_PIN_CODE_REQ_REPLY;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_PIN_CODE_REQUEST_REPLY);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_PIN_CODE_REQ_REPLY);
+
+ BDADDR_TO_STREAM (pp, bd_addr);
+ UINT8_TO_STREAM (pp, pin_code_len);
+
+ for (i = 0; i < pin_code_len; i++)
+ *pp++ = *pin_code++;
+
+ for (; i < PIN_CODE_LEN; i++)
+ *pp++ = 0;
+
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_pin_code_neg_reply (BD_ADDR bd_addr)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_PIN_CODE_NEG_REPLY)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_PIN_CODE_NEG_REPLY;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_PIN_CODE_REQUEST_NEG_REPLY);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_PIN_CODE_NEG_REPLY);
+
+ BDADDR_TO_STREAM (pp, bd_addr);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_change_conn_type (UINT16 handle, UINT16 packet_types)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_CHANGE_CONN_TYPE)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CHANGE_CONN_TYPE;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_CHANGE_CONN_PACKET_TYPE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_CHANGE_CONN_TYPE);
+
+ UINT16_TO_STREAM (pp, handle);
+ UINT16_TO_STREAM (pp, packet_types);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_auth_request (UINT16 handle)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_CMD_HANDLE)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CMD_HANDLE;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_AUTHENTICATION_REQUESTED);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_CMD_HANDLE);
+
+ UINT16_TO_STREAM (pp, handle);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_set_conn_encrypt (UINT16 handle, BOOLEAN enable)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_SET_CONN_ENCRYPT)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_SET_CONN_ENCRYPT;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_SET_CONN_ENCRYPTION);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_SET_CONN_ENCRYPT);
+
+ UINT16_TO_STREAM (pp, handle);
+ UINT8_TO_STREAM (pp, enable);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_change_link_key (UINT16 handle)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_CMD_HANDLE)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CMD_HANDLE;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_CHANGE_CONN_LINK_KEY);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_CMD_HANDLE);
+
+ UINT16_TO_STREAM (pp, handle);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_master_link_key (BOOLEAN key_flag)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_MASTER_LINK_KEY)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_MASTER_LINK_KEY;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_MASTER_LINK_KEY);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_MASTER_LINK_KEY);
+
+ UINT8_TO_STREAM (pp, key_flag);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_rmt_name_req (BD_ADDR bd_addr, UINT8 page_scan_rep_mode,
+ UINT8 page_scan_mode, UINT16 clock_offset)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_RMT_NAME_REQ)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_RMT_NAME_REQ;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_RMT_NAME_REQUEST);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_RMT_NAME_REQ);
+
+ BDADDR_TO_STREAM (pp, bd_addr);
+ UINT8_TO_STREAM (pp, page_scan_rep_mode);
+ UINT8_TO_STREAM (pp, page_scan_mode);
+ UINT16_TO_STREAM (pp, clock_offset);
+
+/* If calling from LMP_TEST or ScriptEngine, then send HCI command immediately */
+#if (!defined (LMP_TEST) && !defined(BTISE))
+ btm_acl_paging (p, bd_addr);
+#else
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+#endif
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_rmt_name_req_cancel (BD_ADDR bd_addr)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_RMT_NAME_REQ_CANCEL)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_RMT_NAME_REQ_CANCEL;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_RMT_NAME_REQUEST_CANCEL);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_RMT_NAME_REQ_CANCEL);
+
+ BDADDR_TO_STREAM (pp, bd_addr);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_rmt_features_req (UINT16 handle)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_CMD_HANDLE)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CMD_HANDLE;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_READ_RMT_FEATURES);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_CMD_HANDLE);
+
+ UINT16_TO_STREAM (pp, handle);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_rmt_ext_features (UINT16 handle, UINT8 page_num)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_RMT_EXT_FEATURES)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_RMT_EXT_FEATURES;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_READ_RMT_EXT_FEATURES);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_RMT_EXT_FEATURES);
+
+ UINT16_TO_STREAM (pp, handle);
+ UINT8_TO_STREAM (pp, page_num);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_rmt_ver_req (UINT16 handle)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_CMD_HANDLE)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CMD_HANDLE;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_READ_RMT_VERSION_INFO);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_CMD_HANDLE);
+
+ UINT16_TO_STREAM (pp, handle);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_read_rmt_clk_offset (UINT16 handle)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_CMD_HANDLE)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CMD_HANDLE;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_READ_RMT_CLOCK_OFFSET);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_CMD_HANDLE);
+
+ UINT16_TO_STREAM (pp, handle);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_read_lmp_handle (UINT16 handle)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_CMD_HANDLE)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CMD_HANDLE;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_READ_LMP_HANDLE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_CMD_HANDLE);
+
+ UINT16_TO_STREAM (pp, handle);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_setup_esco_conn (UINT16 handle, UINT32 tx_bw,
+ UINT32 rx_bw, UINT16 max_latency, UINT16 voice,
+ UINT8 retrans_effort, UINT16 packet_types)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_SETUP_ESCO)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_SETUP_ESCO;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_SETUP_ESCO_CONNECTION);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_SETUP_ESCO);
+
+ UINT16_TO_STREAM (pp, handle);
+ UINT32_TO_STREAM (pp, tx_bw);
+ UINT32_TO_STREAM (pp, rx_bw);
+ UINT16_TO_STREAM (pp, max_latency);
+ UINT16_TO_STREAM (pp, voice);
+ UINT8_TO_STREAM (pp, retrans_effort);
+ UINT16_TO_STREAM (pp, packet_types);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_accept_esco_conn (BD_ADDR bd_addr, UINT32 tx_bw,
+ UINT32 rx_bw, UINT16 max_latency,
+ UINT16 content_fmt, UINT8 retrans_effort,
+ UINT16 packet_types)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_ACCEPT_ESCO)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_ACCEPT_ESCO;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_ACCEPT_ESCO_CONNECTION);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_ACCEPT_ESCO);
+
+ BDADDR_TO_STREAM (pp, bd_addr);
+ UINT32_TO_STREAM (pp, tx_bw);
+ UINT32_TO_STREAM (pp, rx_bw);
+ UINT16_TO_STREAM (pp, max_latency);
+ UINT16_TO_STREAM (pp, content_fmt);
+ UINT8_TO_STREAM (pp, retrans_effort);
+ UINT16_TO_STREAM (pp, packet_types);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_reject_esco_conn (BD_ADDR bd_addr, UINT8 reason)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_REJECT_ESCO)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_REJECT_ESCO;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_REJECT_ESCO_CONNECTION);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_REJECT_ESCO);
+
+ BDADDR_TO_STREAM (pp, bd_addr);
+ UINT8_TO_STREAM (pp, reason);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_hold_mode (UINT16 handle, UINT16 max_hold_period,
+ UINT16 min_hold_period)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_HOLD_MODE)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_HOLD_MODE;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_HOLD_MODE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_HOLD_MODE);
+
+ UINT16_TO_STREAM (pp, handle);
+ UINT16_TO_STREAM (pp, max_hold_period);
+ UINT16_TO_STREAM (pp, min_hold_period);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_sniff_mode (UINT16 handle, UINT16 max_sniff_period,
+ UINT16 min_sniff_period, UINT16 sniff_attempt,
+ UINT16 sniff_timeout)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_SNIFF_MODE)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_SNIFF_MODE;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_SNIFF_MODE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_SNIFF_MODE);
+
+ UINT16_TO_STREAM (pp, handle);
+ UINT16_TO_STREAM (pp, max_sniff_period);
+ UINT16_TO_STREAM (pp, min_sniff_period);
+ UINT16_TO_STREAM (pp, sniff_attempt);
+ UINT16_TO_STREAM (pp, sniff_timeout);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_exit_sniff_mode (UINT16 handle)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_CMD_HANDLE)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CMD_HANDLE;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_EXIT_SNIFF_MODE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_CMD_HANDLE);
+
+ UINT16_TO_STREAM (pp, handle);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return TRUE;
+}
+
+BOOLEAN btsnd_hcic_park_mode (UINT16 handle, UINT16 beacon_max_interval,
+ UINT16 beacon_min_interval)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_PARK_MODE)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_PARK_MODE;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_PARK_MODE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_PARK_MODE);
+
+ UINT16_TO_STREAM (pp, handle);
+ UINT16_TO_STREAM (pp, beacon_max_interval);
+ UINT16_TO_STREAM (pp, beacon_min_interval);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_exit_park_mode (UINT16 handle)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_CMD_HANDLE)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CMD_HANDLE;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_EXIT_PARK_MODE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_CMD_HANDLE);
+
+ UINT16_TO_STREAM (pp, handle);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return TRUE;
+}
+
+BOOLEAN btsnd_hcic_qos_setup (UINT16 handle, UINT8 flags, UINT8 service_type,
+ UINT32 token_rate, UINT32 peak, UINT32 latency,
+ UINT32 delay_var)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_QOS_SETUP)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_QOS_SETUP;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_QOS_SETUP);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_QOS_SETUP);
+
+ UINT16_TO_STREAM (pp, handle);
+ UINT8_TO_STREAM (pp, flags);
+ UINT8_TO_STREAM (pp, service_type);
+ UINT32_TO_STREAM (pp, token_rate);
+ UINT32_TO_STREAM (pp, peak);
+ UINT32_TO_STREAM (pp, latency);
+ UINT32_TO_STREAM (pp, delay_var);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_role_discovery (UINT16 handle)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_CMD_HANDLE)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CMD_HANDLE;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_ROLE_DISCOVERY);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_CMD_HANDLE);
+
+ UINT16_TO_STREAM (pp, handle);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_switch_role (BD_ADDR bd_addr, UINT8 role)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_SWITCH_ROLE)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_SWITCH_ROLE;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_SWITCH_ROLE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_SWITCH_ROLE);
+
+ BDADDR_TO_STREAM (pp, bd_addr);
+ UINT8_TO_STREAM (pp, role);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_read_policy_set (UINT16 handle)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_CMD_HANDLE)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CMD_HANDLE;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_READ_POLICY_SETTINGS);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_CMD_HANDLE);
+
+ UINT16_TO_STREAM (pp, handle);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_write_policy_set (UINT16 handle, UINT16 settings)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_WRITE_POLICY_SET)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_POLICY_SET;
+ p->offset = 0;
+ UINT16_TO_STREAM (pp, HCI_WRITE_POLICY_SETTINGS);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_POLICY_SET);
+
+ UINT16_TO_STREAM (pp, handle);
+ UINT16_TO_STREAM (pp, settings);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_read_def_policy_set (void)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_DEF_POLICY_SET)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_DEF_POLICY_SET;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_READ_DEF_POLICY_SETTINGS);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_DEF_POLICY_SET);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_write_def_policy_set (UINT16 settings)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_WRITE_DEF_POLICY_SET)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_DEF_POLICY_SET;
+ p->offset = 0;
+ UINT16_TO_STREAM (pp, HCI_WRITE_DEF_POLICY_SETTINGS);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_DEF_POLICY_SET);
+
+ UINT16_TO_STREAM (pp, settings);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_flow_specification(UINT16 handle, UINT8 flags, UINT8 flow_direct,
+ UINT8 service_type, UINT32 token_rate,
+ UINT32 token_bucket_size, UINT32 peak,
+ UINT32 latency)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_FLOW_SPEC)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_FLOW_SPEC;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_FLOW_SPECIFICATION);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_FLOW_SPEC);
+
+ UINT16_TO_STREAM (pp, handle);
+ UINT8_TO_STREAM (pp, flags);
+ UINT8_TO_STREAM (pp, flow_direct);
+ UINT8_TO_STREAM (pp, service_type);
+ UINT32_TO_STREAM (pp, token_rate);
+ UINT32_TO_STREAM (pp, token_bucket_size);
+ UINT32_TO_STREAM (pp, peak);
+ UINT32_TO_STREAM (pp, latency);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_set_event_mask(UINT8 local_controller_id, BT_EVENT_MASK event_mask)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_SET_EVENT_MASK)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_SET_EVENT_MASK;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_SET_EVENT_MASK);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_SET_EVENT_MASK);
+ ARRAY8_TO_STREAM (pp, event_mask);
+
+ btu_hcif_send_cmd (local_controller_id, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_set_event_mask_page_2 (UINT8 local_controller_id, BT_EVENT_MASK event_mask)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_SET_EVENT_MASK_PAGE_2)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_SET_EVENT_MASK_PAGE_2;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_SET_EVENT_MASK_PAGE_2);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_SET_EVENT_MASK_PAGE_2);
+ ARRAY8_TO_STREAM (pp, event_mask);
+
+ btu_hcif_send_cmd (local_controller_id, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_reset (UINT8 local_controller_id)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_RESET)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_RESET;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_RESET);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_RESET);
+
+ btu_hcif_send_cmd (local_controller_id, p);
+/* If calling from LMP_TEST or ScriptEngine, then send HCI command immediately */
+#if (!defined (LMP_TEST) && !defined(BTISE))
+ if (local_controller_id == LOCAL_BR_EDR_CONTROLLER_ID)
+ {
+ btm_acl_reset_paging ();
+ btm_acl_set_discing (FALSE);
+ }
+#endif
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_set_event_filter (UINT8 filt_type, UINT8 filt_cond_type,
+ UINT8 *filt_cond, UINT8 filt_cond_len)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ /* Use buffer large enough to hold all sizes in this command */
+ if ((p = HCI_GET_CMD_BUF(2 + filt_cond_len)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_SET_EVENT_FILTER);
+
+ if (filt_type)
+ {
+ p->len = (UINT16)(HCIC_PREAMBLE_SIZE + 2 + filt_cond_len);
+ UINT8_TO_STREAM (pp, (UINT8)(2 + filt_cond_len));
+
+ UINT8_TO_STREAM (pp, filt_type);
+ UINT8_TO_STREAM (pp, filt_cond_type);
+
+ if (filt_cond_type == HCI_FILTER_COND_DEVICE_CLASS)
+ {
+ DEVCLASS_TO_STREAM (pp, filt_cond);
+ filt_cond += DEV_CLASS_LEN;
+ DEVCLASS_TO_STREAM (pp, filt_cond);
+ filt_cond += DEV_CLASS_LEN;
+
+ filt_cond_len -= (2 * DEV_CLASS_LEN);
+ }
+ else if (filt_cond_type == HCI_FILTER_COND_BD_ADDR)
+ {
+ BDADDR_TO_STREAM (pp, filt_cond);
+ filt_cond += BD_ADDR_LEN;
+
+ filt_cond_len -= BD_ADDR_LEN;
+ }
+
+ if (filt_cond_len)
+ ARRAY_TO_STREAM (pp, filt_cond, filt_cond_len);
+ }
+ else
+ {
+ p->len = (UINT16)(HCIC_PREAMBLE_SIZE + 1);
+ UINT8_TO_STREAM (pp, 1);
+
+ UINT8_TO_STREAM (pp, filt_type);
+ }
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_flush (UINT8 local_controller_id, UINT16 handle)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_CMD_HANDLE)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CMD_HANDLE;
+ p->offset = 0;
+ UINT16_TO_STREAM (pp, HCI_FLUSH);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_CMD_HANDLE);
+
+ UINT16_TO_STREAM (pp, handle);
+
+ btu_hcif_send_cmd (local_controller_id, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_read_pin_type (void)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_CMD)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_READ_PIN_TYPE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_CMD);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_write_pin_type (UINT8 type)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_WRITE_PARAM1)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM1;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_WRITE_PIN_TYPE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_PARAM1);
+
+ UINT8_TO_STREAM (pp, type);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_new_unit_key (void)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_NEW_UNIT_KEY)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_NEW_UNIT_KEY;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_CREATE_NEW_UNIT_KEY);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_NEW_UNIT_KEY);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_read_stored_key (BD_ADDR bd_addr, BOOLEAN read_all_flag)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_STORED_KEY)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_STORED_KEY;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_READ_STORED_LINK_KEY);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_STORED_KEY);
+
+ BDADDR_TO_STREAM (pp, bd_addr);
+ UINT8_TO_STREAM (pp, read_all_flag);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_write_stored_key (UINT8 num_keys, BD_ADDR *bd_addr,
+ LINK_KEY *link_key)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+ int j;
+
+ if ((p = HCI_GET_CMD_BUF(1 + (num_keys * (BD_ADDR_LEN + LINK_KEY_LEN)))) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+
+ p->len = HCIC_PREAMBLE_SIZE + 1 + (num_keys * (BD_ADDR_LEN + LINK_KEY_LEN));
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_WRITE_STORED_LINK_KEY);
+ UINT8_TO_STREAM (pp, p->len - HCIC_PREAMBLE_SIZE);
+
+ if(num_keys > HCI_MAX_NUM_OF_LINK_KEYS_PER_CMMD)
+ num_keys = HCI_MAX_NUM_OF_LINK_KEYS_PER_CMMD;
+
+ UINT8_TO_STREAM (pp, num_keys);
+
+ for (j = 0; j < num_keys; j++)
+ {
+ BDADDR_TO_STREAM (pp, bd_addr[j]);
+ ARRAY16_TO_STREAM (pp, link_key[j]);
+ }
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_delete_stored_key (BD_ADDR bd_addr, BOOLEAN delete_all_flag)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_DELETE_STORED_KEY)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_DELETE_STORED_KEY;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_DELETE_STORED_LINK_KEY);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_DELETE_STORED_KEY);
+
+ BDADDR_TO_STREAM (pp, bd_addr);
+ UINT8_TO_STREAM (pp, delete_all_flag);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_change_name (BD_NAME name)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+ UINT16 len = strlen ((char *)name) + 1;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_CHANGE_NAME)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CHANGE_NAME;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_CHANGE_LOCAL_NAME);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_CHANGE_NAME);
+
+ ARRAY_TO_STREAM (pp, name, len);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_read_name (void)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_CMD)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_READ_LOCAL_NAME);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_CMD);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_read_conn_acc_tout (UINT8 local_controller_id)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_CMD)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_READ_CONN_ACCEPT_TOUT);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_CMD);
+
+ btu_hcif_send_cmd (local_controller_id, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_write_conn_acc_tout (UINT8 local_controller_id, UINT16 timeout)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_WRITE_PARAM2)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM2;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_WRITE_CONN_ACCEPT_TOUT);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_PARAM2);
+
+ UINT16_TO_STREAM (pp, timeout);
+
+ btu_hcif_send_cmd (local_controller_id, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_read_page_tout (void)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_CMD)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_READ_PAGE_TOUT);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_CMD);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_write_page_tout (UINT16 timeout)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_WRITE_PARAM2)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM2;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_WRITE_PAGE_TOUT);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_PARAM2);
+
+ UINT16_TO_STREAM (pp, timeout);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_read_scan_enable (void)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_CMD)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_READ_SCAN_ENABLE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_CMD);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_write_scan_enable (UINT8 flag)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_WRITE_PARAM1)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM1;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_WRITE_SCAN_ENABLE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_PARAM1);
+
+ UINT8_TO_STREAM (pp, flag);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_read_pagescan_cfg(void)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_CMD)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_READ_PAGESCAN_CFG);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_CMD);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_write_pagescan_cfg(UINT16 interval, UINT16 window)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_WRITE_PAGESCAN_CFG)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PAGESCAN_CFG;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_WRITE_PAGESCAN_CFG);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_PAGESCAN_CFG);
+
+ UINT16_TO_STREAM (pp, interval);
+ UINT16_TO_STREAM (pp, window);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_read_inqscan_cfg(void)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_CMD)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_READ_INQUIRYSCAN_CFG);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_CMD);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_write_inqscan_cfg(UINT16 interval, UINT16 window)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_WRITE_INQSCAN_CFG)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_INQSCAN_CFG;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_WRITE_INQUIRYSCAN_CFG);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_INQSCAN_CFG);
+
+ UINT16_TO_STREAM (pp, interval);
+ UINT16_TO_STREAM (pp, window);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_read_auth_enable (void)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_CMD)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_READ_AUTHENTICATION_ENABLE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_CMD);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_write_auth_enable (UINT8 flag)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_WRITE_PARAM1)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM1;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_WRITE_AUTHENTICATION_ENABLE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_PARAM1);
+
+ UINT8_TO_STREAM (pp, flag);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_read_encr_mode (void)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_CMD)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_READ_ENCRYPTION_MODE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_CMD);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_write_encr_mode (UINT8 mode)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_WRITE_PARAM1)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM1;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_WRITE_ENCRYPTION_MODE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_PARAM1);
+
+ UINT8_TO_STREAM (pp, mode);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_read_dev_class(void)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_CMD)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_READ_CLASS_OF_DEVICE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_CMD);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_write_dev_class(DEV_CLASS dev_class)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_WRITE_PARAM3)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM3;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_WRITE_CLASS_OF_DEVICE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_PARAM3);
+
+ DEVCLASS_TO_STREAM (pp, dev_class);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_read_voice_settings(void)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_CMD)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_READ_VOICE_SETTINGS);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_CMD);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_write_voice_settings(UINT16 flags)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_WRITE_PARAM2)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM2;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_WRITE_VOICE_SETTINGS);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_PARAM2);
+
+ UINT16_TO_STREAM (pp, flags);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_read_auto_flush_tout (UINT16 handle)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_CMD_HANDLE)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CMD_HANDLE;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_READ_AUTO_FLUSH_TOUT);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_CMD_HANDLE);
+
+ UINT16_TO_STREAM (pp, handle);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_write_auto_flush_tout (UINT16 handle, UINT16 tout)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_WRITE_AUTO_FLUSH_TOUT)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_AUTO_FLUSH_TOUT;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_WRITE_AUTO_FLUSH_TOUT);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_AUTO_FLUSH_TOUT);
+
+ UINT16_TO_STREAM (pp, handle);
+ UINT16_TO_STREAM (pp, tout);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_read_num_bcast_xmit (void)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_CMD)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_READ_NUM_BCAST_REXMITS);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_CMD);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_write_num_bcast_xmit (UINT8 num)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_WRITE_PARAM1)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM1;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_WRITE_NUM_BCAST_REXMITS);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_PARAM1);
+
+ UINT8_TO_STREAM (pp, num);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_read_hold_mode_act (void)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_CMD)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_READ_HOLD_MODE_ACTIVITY);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_CMD);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_write_hold_mode_act (UINT8 flags)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_WRITE_PARAM1)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM1;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_WRITE_HOLD_MODE_ACTIVITY);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_PARAM1);
+
+ UINT8_TO_STREAM (pp, flags);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_read_tx_power (UINT16 handle, UINT8 type)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_TX_POWER)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_TX_POWER;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_READ_TRANSMIT_POWER_LEVEL);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_TX_POWER);
+
+ UINT16_TO_STREAM (pp, handle);
+ UINT8_TO_STREAM (pp, type);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_read_sco_flow_enable (void)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_CMD)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_READ_SCO_FLOW_CTRL_ENABLE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_CMD);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_write_sco_flow_enable (UINT8 flag)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_WRITE_PARAM1)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM1;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_WRITE_SCO_FLOW_CTRL_ENABLE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_PARAM1);
+
+ UINT8_TO_STREAM (pp, flag);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_set_host_flow_ctrl (UINT8 value)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_WRITE_PARAM1)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM1;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_SET_HC_TO_HOST_FLOW_CTRL);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_PARAM1);
+
+ UINT8_TO_STREAM (pp, value);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_set_host_buf_size (UINT16 acl_len, UINT8 sco_len,
+ UINT16 acl_num, UINT16 sco_num)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_SET_HOST_BUF_SIZE)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_SET_HOST_BUF_SIZE;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_HOST_BUFFER_SIZE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_SET_HOST_BUF_SIZE);
+
+ UINT16_TO_STREAM (pp, acl_len);
+ UINT8_TO_STREAM (pp, sco_len);
+ UINT16_TO_STREAM (pp, acl_num);
+ UINT16_TO_STREAM (pp, sco_num);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_host_num_xmitted_pkts (UINT8 num_handles, UINT16 *handle,
+ UINT16 *num_pkts)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+ int j;
+
+ if ((p = HCI_GET_CMD_BUF(1 + (num_handles * 4))) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + 1 + (num_handles * 4);
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_HOST_NUM_PACKETS_DONE);
+ UINT8_TO_STREAM (pp, p->len - HCIC_PREAMBLE_SIZE);
+
+ UINT8_TO_STREAM (pp, num_handles);
+
+ for (j = 0; j < num_handles; j++)
+ {
+ UINT16_TO_STREAM (pp, handle[j]);
+ UINT16_TO_STREAM (pp, num_pkts[j]);
+ }
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_read_link_super_tout (UINT8 local_controller_id, UINT16 handle)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_CMD_HANDLE)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CMD_HANDLE;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_READ_LINK_SUPER_TOUT);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_CMD_HANDLE);
+
+ UINT16_TO_STREAM (pp, handle);
+
+ btu_hcif_send_cmd (local_controller_id, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_write_link_super_tout (UINT8 local_controller_id, UINT16 handle, UINT16 timeout)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_WRITE_LINK_SUPER_TOUT)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_LINK_SUPER_TOUT;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_WRITE_LINK_SUPER_TOUT);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_LINK_SUPER_TOUT);
+
+ UINT16_TO_STREAM (pp, handle);
+ UINT16_TO_STREAM (pp, timeout);
+
+ btu_hcif_send_cmd (local_controller_id, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_read_max_iac (void)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_CMD)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_READ_NUM_SUPPORTED_IAC);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_CMD);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_read_cur_iac_lap (void)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_CMD)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_READ_CURRENT_IAC_LAP);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_CMD);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_write_cur_iac_lap (UINT8 num_cur_iac, LAP * const iac_lap)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+ int i;
+
+ if ((p = HCI_GET_CMD_BUF(1 + (LAP_LEN * num_cur_iac))) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + 1 + (LAP_LEN * num_cur_iac);
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_WRITE_CURRENT_IAC_LAP);
+ UINT8_TO_STREAM (pp, p->len - HCIC_PREAMBLE_SIZE);
+
+ UINT8_TO_STREAM (pp, num_cur_iac);
+
+ for (i = 0; i < num_cur_iac; i++)
+ LAP_TO_STREAM (pp, iac_lap[i]);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_read_page_scan_per (void)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_CMD)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_READ_PAGESCAN_PERIOD_MODE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_CMD);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_write_page_scan_per (UINT8 mode)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_WRITE_PARAM1)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM1;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_WRITE_PAGESCAN_PERIOD_MODE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_PARAM1);
+
+ UINT8_TO_STREAM (pp, mode);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_read_page_scan_mode (void)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_CMD)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_READ_PAGESCAN_MODE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_CMD);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_write_page_scan_mode (UINT8 mode)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_WRITE_PARAM1)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM1;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_WRITE_PAGESCAN_MODE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_PARAM1);
+
+ UINT8_TO_STREAM (pp, mode);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+/******************************************
+** Lisbon Features
+*******************************************/
+#if BTM_SSR_INCLUDED == TRUE
+
+BOOLEAN btsnd_hcic_sniff_sub_rate(UINT16 handle, UINT16 max_lat,
+ UINT16 min_remote_lat, UINT16 min_local_lat)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_SNIFF_SUB_RATE)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_SNIFF_SUB_RATE;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_SNIFF_SUB_RATE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_SNIFF_SUB_RATE);
+
+ UINT16_TO_STREAM (pp, handle);
+ UINT16_TO_STREAM (pp, max_lat);
+ UINT16_TO_STREAM (pp, min_remote_lat);
+ UINT16_TO_STREAM (pp, min_local_lat);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+#endif /* BTM_SSR_INCLUDED */
+
+#if (BTM_EIR_SERVER_INCLUDED == TRUE)
+/**** Extended Inquiry Response Commands ****/
+BOOLEAN btsnd_hcic_read_ext_inquiry_response (void)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_CMD)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_READ_EXT_INQ_RESPONSE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_CMD);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+void btsnd_hcic_write_ext_inquiry_response (void *buffer, UINT8 fec_req)
+{
+ BT_HDR *p = (BT_HDR *)buffer;
+ UINT8 *pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_EXT_INQ_RESP;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_WRITE_EXT_INQ_RESPONSE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_EXT_INQ_RESP);
+
+ UINT8_TO_STREAM (pp, fec_req);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+#endif /* BTM_EIR_SERVER_INCLUDED == TRUE */
+
+/**** Simple Pairing Commands ****/
+BOOLEAN btsnd_hcic_write_simple_pairing_mode (UINT8 mode)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_W_SIMP_PAIR)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_W_SIMP_PAIR;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_WRITE_SIMPLE_PAIRING_MODE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_W_SIMP_PAIR);
+
+ UINT8_TO_STREAM (pp, mode);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_read_simple_pairing_mode (void)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_R_SIMP_PAIR)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_R_SIMP_PAIR;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_READ_SIMPLE_PAIRING_MODE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_R_SIMP_PAIR);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_write_simp_pair_debug_mode(UINT8 debug_mode)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_SIMP_PAIR_DBUG)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_SIMP_PAIR_DBUG;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_WRITE_SIMP_PAIR_DEBUG_MODE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_SIMP_PAIR_DBUG);
+
+ UINT8_TO_STREAM (pp, debug_mode);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_io_cap_req_reply (BD_ADDR bd_addr, UINT8 capability,
+ UINT8 oob_present, UINT8 auth_req)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_IO_CAP_RESP)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_IO_CAP_RESP;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_IO_CAPABILITY_RESPONSE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_IO_CAP_RESP);
+
+ BDADDR_TO_STREAM (pp, bd_addr);
+ UINT8_TO_STREAM (pp, capability);
+ UINT8_TO_STREAM (pp, oob_present);
+ UINT8_TO_STREAM (pp, auth_req);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_io_cap_req_neg_reply (BD_ADDR bd_addr, UINT8 err_code)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_IO_CAP_NEG_REPLY)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_IO_CAP_NEG_REPLY;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_IO_CAP_REQ_NEG_REPLY);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_IO_CAP_NEG_REPLY);
+
+ BDADDR_TO_STREAM (pp, bd_addr);
+ UINT8_TO_STREAM (pp, err_code);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_read_local_oob_data (void)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_R_LOCAL_OOB)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_R_LOCAL_OOB;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_READ_LOCAL_OOB_DATA);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_R_LOCAL_OOB);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_user_conf_reply (BD_ADDR bd_addr, BOOLEAN is_yes)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_UCONF_REPLY)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_UCONF_REPLY;
+ p->offset = 0;
+
+ if (!is_yes)
+ {
+ /* Negative reply */
+ UINT16_TO_STREAM (pp, HCI_USER_CONF_VALUE_NEG_REPLY);
+ }
+ else
+ {
+ /* Confirmation */
+ UINT16_TO_STREAM (pp, HCI_USER_CONF_REQUEST_REPLY);
+ }
+
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_UCONF_REPLY);
+
+ BDADDR_TO_STREAM (pp, bd_addr);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_user_passkey_reply (BD_ADDR bd_addr, UINT32 value)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_U_PKEY_REPLY)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_U_PKEY_REPLY;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_USER_PASSKEY_REQ_REPLY);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_U_PKEY_REPLY);
+
+ BDADDR_TO_STREAM (pp, bd_addr);
+ UINT32_TO_STREAM (pp, value);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_user_passkey_neg_reply (BD_ADDR bd_addr)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_U_PKEY_NEG_REPLY)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_U_PKEY_NEG_REPLY;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_USER_PASSKEY_REQ_NEG_REPLY);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_U_PKEY_NEG_REPLY);
+
+ BDADDR_TO_STREAM (pp, bd_addr);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_rem_oob_reply (BD_ADDR bd_addr, UINT8 *p_c, UINT8 *p_r)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_REM_OOB_REPLY)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_REM_OOB_REPLY;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_REM_OOB_DATA_REQ_REPLY);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_REM_OOB_REPLY);
+
+ BDADDR_TO_STREAM (pp, bd_addr);
+ ARRAY16_TO_STREAM (pp, p_c);
+ ARRAY16_TO_STREAM (pp, p_r);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_rem_oob_neg_reply (BD_ADDR bd_addr)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_REM_OOB_NEG_REPLY)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_REM_OOB_NEG_REPLY;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_REM_OOB_DATA_REQ_NEG_REPLY);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_REM_OOB_NEG_REPLY);
+
+ BDADDR_TO_STREAM (pp, bd_addr);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+
+BOOLEAN btsnd_hcic_read_inq_tx_power (void)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_R_TX_POWER)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_R_TX_POWER;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_READ_INQ_TX_POWER_LEVEL);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_R_TX_POWER);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_write_inq_tx_power (INT8 level)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_W_TX_POWER)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_W_TX_POWER;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_WRITE_INQ_TX_POWER_LEVEL);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_W_TX_POWER);
+
+ INT8_TO_STREAM (pp, level);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+#if 0 /* currently not been used */
+BOOLEAN btsnd_hcic_read_default_erroneous_data_rpt (void)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_R_ERR_DATA_RPT)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_R_ERR_DATA_RPT;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_READ_ERRONEOUS_DATA_RPT);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_R_ERR_DATA_RPT);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+#endif
+
+BOOLEAN btsnd_hcic_write_default_erroneous_data_rpt (UINT8 flag)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_W_ERR_DATA_RPT)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_W_ERR_DATA_RPT;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_WRITE_ERRONEOUS_DATA_RPT);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_W_ERR_DATA_RPT);
+
+ UINT8_TO_STREAM (pp, flag);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_send_keypress_notif (BD_ADDR bd_addr, UINT8 notif)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_SEND_KEYPRESS_NOTIF)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_SEND_KEYPRESS_NOTIF;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_SEND_KEYPRESS_NOTIF);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_SEND_KEYPRESS_NOTIF);
+
+ BDADDR_TO_STREAM (pp, bd_addr);
+ UINT8_TO_STREAM (pp, notif);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+/**** end of Simple Pairing Commands ****/
+
+#if L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE
+BOOLEAN btsnd_hcic_enhanced_flush (UINT16 handle, UINT8 packet_type)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_ENHANCED_FLUSH)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_ENHANCED_FLUSH;
+ p->offset = 0;
+ UINT16_TO_STREAM (pp, HCI_ENHANCED_FLUSH);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_ENHANCED_FLUSH);
+
+ UINT16_TO_STREAM (pp, handle);
+ UINT8_TO_STREAM (pp, packet_type);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+#endif
+
+
+BOOLEAN btsnd_hcic_refresh_encryption_key (UINT16 handle)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_CMD_HANDLE)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CMD_HANDLE;
+ p->offset = 0;
+ UINT16_TO_STREAM (pp, HCI_REFRESH_ENCRYPTION_KEY);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_CMD_HANDLE);
+
+ UINT16_TO_STREAM (pp, handle);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+/*************************
+** End of Lisbon Commands
+**************************/
+
+BOOLEAN btsnd_hcic_read_local_ver (UINT8 local_controller_id)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_CMD)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_READ_LOCAL_VERSION_INFO);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_CMD);
+
+ btu_hcif_send_cmd (local_controller_id, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_read_local_supported_cmds (UINT8 local_controller_id)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_CMD)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_READ_LOCAL_SUPPORTED_CMDS);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_CMD);
+
+ btu_hcif_send_cmd (local_controller_id, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_read_local_features (void)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_CMD)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_READ_LOCAL_FEATURES);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_CMD);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_read_local_ext_features (UINT8 page_num)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_LOCAL_EXT_FEATURES)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_LOCAL_EXT_FEATURES;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_READ_LOCAL_EXT_FEATURES);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_LOCAL_EXT_FEATURES);
+
+ UINT8_TO_STREAM (pp, page_num);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_read_buffer_size (void)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_CMD)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_READ_BUFFER_SIZE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_CMD);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_read_country_code (void)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_CMD)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_READ_COUNTRY_CODE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_CMD);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_read_bd_addr (void)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_CMD)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_READ_BD_ADDR);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_CMD);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_read_fail_contact_count (UINT8 local_controller_id, UINT16 handle)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_CMD_HANDLE)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CMD_HANDLE;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_READ_FAILED_CONTACT_COUNT);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_CMD_HANDLE);
+
+ UINT16_TO_STREAM (pp, handle);
+
+ btu_hcif_send_cmd (local_controller_id, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_reset_fail_contact_count (UINT8 local_controller_id, UINT16 handle)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_CMD_HANDLE)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CMD_HANDLE;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_RESET_FAILED_CONTACT_COUNT);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_CMD_HANDLE);
+
+ UINT16_TO_STREAM (pp, handle);
+
+ btu_hcif_send_cmd (local_controller_id, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_get_link_quality (UINT16 handle)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_CMD_HANDLE)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CMD_HANDLE;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_GET_LINK_QUALITY);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_CMD_HANDLE);
+
+ UINT16_TO_STREAM (pp, handle);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_read_rssi (UINT16 handle)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_CMD_HANDLE)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CMD_HANDLE;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_READ_RSSI);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_CMD_HANDLE);
+
+ UINT16_TO_STREAM (pp, handle);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_read_loopback_mode (void)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_CMD)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_READ_LOOPBACK_MODE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_CMD);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_write_loopback_mode (UINT8 mode)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_WRITE_PARAM1)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM1;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_WRITE_LOOPBACK_MODE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_PARAM1);
+
+ UINT8_TO_STREAM (pp, mode);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_enable_test_mode (void)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_CMD)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_ENABLE_DEV_UNDER_TEST_MODE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_CMD);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_write_afh_channel_assessment_mode (UINT8 mode)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_WRITE_PARAM1)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM1;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_WRITE_AFH_ASSESSMENT_MODE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_PARAM1);
+
+ UINT8_TO_STREAM (pp, mode);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_read_afh_channel_assessment_mode(void)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_CMD)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_READ_AFH_ASSESSMENT_MODE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_CMD);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_set_afh_channels (UINT8 first, UINT8 last)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+ UINT8 channels[10] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F};
+ int i;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_SET_AFH_CHANNELS)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_SET_AFH_CHANNELS;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_SET_AFH_CHANNELS);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_SET_AFH_CHANNELS);
+
+ /* Just make sure that caller did not exceed 79 Bluetooth channels */
+ if ((first <= last) && (last <= 78))
+ {
+ for (i = first; i <= last; i++)
+ {
+ int byte_offset = i / 8;
+ int bit_offset = i % 8;
+ channels[byte_offset] &= ~(1 << bit_offset);
+ }
+ }
+ for (i = 0; i < 10; i++)
+ *pp++ = channels[i];
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_set_afh_host_channel_class (UINT8 *p_afhchannelmap)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+ int i;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_SET_AFH_CHANNELS)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_SET_AFH_CHANNELS;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_SET_AFH_CHANNELS);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_SET_AFH_CHANNELS);
+
+ /* Copy and convert */
+ for (i = 0; i < 10; i++)
+ *pp++ = p_afhchannelmap[9-i];
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_read_afh_channel_map (UINT16 handle)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_CMD_HANDLE)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CMD_HANDLE;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_READ_AFH_CH_MAP);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_CMD_HANDLE);
+
+ UINT16_TO_STREAM (pp, handle);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_read_clock (UINT16 handle, UINT8 which_clock)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_CLOCK)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CLOCK;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_READ_CLOCK);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_CLOCK);
+
+ UINT16_TO_STREAM (pp, handle);
+ UINT8_TO_STREAM (pp, which_clock);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_read_inqscan_type(void)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_CMD)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_READ_INQSCAN_TYPE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_CMD);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_write_inqscan_type (UINT8 type)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_WRITE_PARAM1)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM1;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_WRITE_INQSCAN_TYPE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_PARAM1);
+
+ UINT8_TO_STREAM (pp, type);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_read_inquiry_mode (void)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_CMD)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_READ_INQUIRY_MODE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_CMD);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_write_inquiry_mode (UINT8 mode)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_WRITE_PARAM1)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM1;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_WRITE_INQUIRY_MODE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_PARAM1);
+
+ UINT8_TO_STREAM (pp, mode);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_read_pagescan_type (void)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_CMD)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_READ_PAGESCAN_TYPE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_CMD);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_write_pagescan_type (UINT8 type)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_WRITE_PARAM1)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM1;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_WRITE_PAGESCAN_TYPE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_PARAM1);
+
+ UINT8_TO_STREAM (pp, type);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+/* Must have room to store BT_HDR + max VSC length + callback pointer */
+#if !defined (LMP_TEST) && (HCI_CMD_POOL_BUF_SIZE < 268)
+#error "HCI_CMD_POOL_BUF_SIZE must be larger than 268"
+#endif
+
+void btsnd_hcic_vendor_spec_cmd (void *buffer, UINT16 opcode, UINT8 len,
+ UINT8 *p_data, void *p_cmd_cplt_cback)
+{
+ BT_HDR *p = (BT_HDR *)buffer;
+ UINT8 *pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + len;
+ p->offset = sizeof(void *);
+
+ *((void **)pp) = p_cmd_cplt_cback; /* Store command complete callback in buffer */
+ pp += sizeof(void *); /* Skip over callback pointer */
+
+ UINT16_TO_STREAM (pp, HCI_GRP_VENDOR_SPECIFIC | opcode);
+ UINT8_TO_STREAM (pp, len);
+ ARRAY_TO_STREAM (pp, p_data, len);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_data (BT_HDR *p_buf, UINT16 len, UINT16 handle, UINT8 boundary, UINT8 broadcast)
+{
+ UINT8 *p;
+
+ /* Higher layer should have left 4 bytes for us to fill the header */
+ p_buf->offset -= 4;
+ p_buf->len += 4;
+
+ /* Find the pointer to the beginning of the data */
+ p = (UINT8 *)(p_buf + 1) + p_buf->offset;
+
+ UINT16_TO_STREAM (p, handle | ((boundary & 3) << 12) | ((broadcast & 3) << 14));
+ UINT16_TO_STREAM (p, len);
+
+ HCI_ACL_DATA_TO_LOWER (p_buf);
+}
+
+BOOLEAN btsnd_hcic_nop (void)
+{
+ BT_HDR *p;
+ UINT8 *pp;
+
+ if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_CMD)) == NULL)
+ return (FALSE);
+
+ pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_COMMAND_NONE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_CMD);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
diff --git a/stack/hid/hid_conn.h b/stack/hid/hid_conn.h
new file mode 100644
index 0000000..41eeaaf
--- /dev/null
+++ b/stack/hid/hid_conn.h
@@ -0,0 +1,56 @@
+/****************************************************************************/
+/* */
+/* Name: hid_conn.h */
+/* */
+/* Function: this file contains HID connection internal definitions */
+/* */
+/* */
+/* Copyright (c) 2002-2004, WIDCOMM Inc., All Rights Reserved. */
+/* WIDCOMM Bluetooth Core. Proprietary and confidential. */
+/* */
+/****************************************************************************/
+#ifndef HID_CONN_H
+#define HID_CONN_H
+
+
+/* Define the HID Connection Block
+*/
+typedef struct hid_conn
+{
+#define HID_CONN_STATE_UNUSED (0)
+#define HID_CONN_STATE_CONNECTING_CTRL (1)
+#define HID_CONN_STATE_CONNECTING_INTR (2)
+#define HID_CONN_STATE_CONFIG (3)
+#define HID_CONN_STATE_CONNECTED (4)
+#define HID_CONN_STATE_DISCONNECTING (5)
+#define HID_CONN_STATE_SECURITY (6)
+
+ UINT8 conn_state;
+
+#define HID_CONN_FLAGS_IS_ORIG (0x01)
+#define HID_CONN_FLAGS_HIS_CTRL_CFG_DONE (0x02)
+#define HID_CONN_FLAGS_MY_CTRL_CFG_DONE (0x04)
+#define HID_CONN_FLAGS_HIS_INTR_CFG_DONE (0x08)
+#define HID_CONN_FLAGS_MY_INTR_CFG_DONE (0x10)
+#define HID_CONN_FLAGS_ALL_CONFIGURED (0x1E) /* All the config done */
+#define HID_CONN_FLAGS_CONGESTED (0x20)
+#define HID_CONN_FLAGS_INACTIVE (0x40)
+
+ UINT8 conn_flags;
+
+ UINT8 ctrl_id;
+ UINT16 ctrl_cid;
+ UINT16 intr_cid;
+ UINT16 rem_mtu_size;
+ UINT16 disc_reason; /* Reason for disconnecting (for HID_HDEV_EVT_CLOSE) */
+ TIMER_LIST_ENT timer_entry;
+
+} tHID_CONN;
+
+#define HID_SEC_CHN 1
+#define HID_NOSEC_CHN 2
+
+#define HIDD_SEC_CHN 3
+#define HIDD_NOSEC_CHN 4
+
+#endif
diff --git a/stack/hid/hidd_api.c b/stack/hid/hidd_api.c
new file mode 100644
index 0000000..7ee41ea
--- /dev/null
+++ b/stack/hid/hidd_api.c
@@ -0,0 +1,536 @@
+/*****************************************************************************/
+/* */
+/* Name: hidd_api.c */
+/* */
+/* Description: this file contains the Device HID API entry points */
+/* */
+/* */
+/* Copyright (c) 2002-2004, WIDCOMM Inc., All Rights Reserved. */
+/* WIDCOMM Bluetooth Core. Proprietary and confidential. */
+/*****************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "wcassert.h"
+
+#include "gki.h"
+#include "bt_types.h"
+#include "hiddefs.h"
+#include "hidd_api.h"
+#include "hidd_int.h"
+#include "btm_api.h"
+
+#include "hcimsgs.h"
+#include "btu.h"
+#include "sdpdefs.h"
+#include "sdp_api.h"
+
+static const UINT8 HidDevLangList[] = HID_DEV_LANGUAGELIST;
+
+#ifndef HID_DEV_BOOT_DEVICE
+#define HID_DEV_BOOT_DEVICE TRUE
+#endif
+
+
+/*******************************************************************************
+**
+** Function HID_DevSetSDPRecord
+**
+** Description This function should be called at startup to create the
+** device SDP record
+**
+** Returns 0 if error else sdp handle for the record.
+**
+*******************************************************************************/
+UINT32 HID_DevSetSDPRecord (tHID_DEV_SDP_INFO *p_sdp_info)
+{
+ UINT32 sdp_handle;
+ tSDP_PROTOCOL_ELEM protocol_list[2];
+ tSDP_PROTO_LIST_ELEM additional_list;
+ UINT16 u16;
+ UINT8 u8;
+ UINT8 *pRepDescriptor, *pd;
+ char buf[2];
+
+ if( p_sdp_info == NULL )
+ return (0);
+
+ /* Create an SDP record for the ctrl/data or notification channel */
+ if ((sdp_handle = SDP_CreateRecord()) == FALSE)
+ {
+ HIDD_TRACE_ERROR0 ("Could not create service record");
+ return (0);
+ }
+
+ /* Add the UUID to the Service Class ID List */
+ u16 = UUID_SERVCLASS_HUMAN_INTERFACE;
+ SDP_AddServiceClassIdList(sdp_handle, 1, &u16);
+
+ /* Build the protocol descriptor list */
+ protocol_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+ protocol_list[0].num_params = 1;
+ protocol_list[0].params[0] = HID_PSM_CONTROL;
+
+ protocol_list[1].num_params = 0;
+ protocol_list[1].protocol_uuid = UUID_PROTOCOL_HIDP;
+
+ SDP_AddProtocolList(sdp_handle, 2, protocol_list);
+
+ /* Language base */
+ SDP_AddLanguageBaseAttrIDList (sdp_handle, LANG_ID_CODE_ENGLISH, LANG_ID_CHAR_ENCODE_UTF8,
+ LANGUAGE_BASE_ID);
+
+ /* Add the Bluetooth Profile Descriptor List (profile version number) */
+ SDP_AddProfileDescriptorList(sdp_handle, UUID_SERVCLASS_HUMAN_INTERFACE, 0x0100);
+
+ /* Add the PSM of the interrupt channel to the Additional Protocol Descriptor List */
+ additional_list.num_elems = 2;
+ additional_list.list_elem[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+ additional_list.list_elem[0].num_params = 1;
+ additional_list.list_elem[0].params[0] = HID_PSM_INTERRUPT;
+ additional_list.list_elem[1].protocol_uuid = UUID_PROTOCOL_HIDP;
+ additional_list.list_elem[1].num_params = 0;
+
+ SDP_AddAdditionProtoLists (sdp_handle, 1, &additional_list);
+
+ if( p_sdp_info->svc_name[0] != '\0' )
+ SDP_AddAttribute (sdp_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE,
+ (UINT8)(strlen(p_sdp_info->svc_name)+1), (UINT8 *)p_sdp_info->svc_name);
+
+ if( p_sdp_info->svc_descr[0] != '\0' )
+ SDP_AddAttribute (sdp_handle, ATTR_ID_SERVICE_DESCRIPTION, TEXT_STR_DESC_TYPE,
+ (UINT8)(strlen(p_sdp_info->svc_descr)+1), (UINT8 *)p_sdp_info->svc_descr);
+
+ if( p_sdp_info->prov_name[0] != '\0' )
+ SDP_AddAttribute (sdp_handle, ATTR_ID_PROVIDER_NAME, TEXT_STR_DESC_TYPE,
+ (UINT8)(strlen(p_sdp_info->prov_name)+1), (UINT8 *)p_sdp_info->prov_name);
+
+ /* HID parser version */
+ UINT16_TO_BE_FIELD(buf,p_sdp_info->hpars_ver) ;
+ SDP_AddAttribute(sdp_handle, ATTR_ID_HID_PARSER_VERSION, UINT_DESC_TYPE, 2, (UINT8 *)buf);
+
+ /* HID subclass */
+ u8 = p_sdp_info->sub_class;
+ SDP_AddAttribute(sdp_handle, ATTR_ID_HID_DEVICE_SUBCLASS, UINT_DESC_TYPE, 1, &u8);
+
+ /* HID country code */
+ u8 = p_sdp_info->ctry_code;
+ SDP_AddAttribute(sdp_handle, ATTR_ID_HID_COUNTRY_CODE, UINT_DESC_TYPE, 1, &u8);
+
+ /* HID Virtual Cable */
+ u8 = HID_DEV_VIRTUAL_CABLE;
+ SDP_AddAttribute(sdp_handle, ATTR_ID_HID_VIRTUAL_CABLE, BOOLEAN_DESC_TYPE, 1, &u8);
+
+ /* HID reconnect initiate */
+ u8 = HID_DEV_RECONN_INITIATE;
+ SDP_AddAttribute(sdp_handle, ATTR_ID_HID_RECONNECT_INITIATE, BOOLEAN_DESC_TYPE, 1, &u8);
+
+ /* HID report descriptor */
+ if ( NULL != (pRepDescriptor = (UINT8 *)GKI_getbuf((UINT16)(p_sdp_info->dscp_info.dl_len + 8 ))) )
+ {
+ pd = pRepDescriptor;
+ *pd++ = (UINT8)((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
+ *pd++ = (UINT8)(p_sdp_info->dscp_info.dl_len + 4);
+ *pd++ = (UINT8)((UINT_DESC_TYPE << 3) | SIZE_ONE_BYTE);
+ *pd++ = (UINT8)(HID_SDP_DESCRIPTOR_REPORT);
+ *pd++ = (UINT8)((TEXT_STR_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
+ *pd++ = (UINT8)(p_sdp_info->dscp_info.dl_len);
+ memcpy (pd, p_sdp_info->dscp_info.dsc_list, p_sdp_info->dscp_info.dl_len);
+ pd += p_sdp_info->dscp_info.dl_len;
+
+ SDP_AddAttribute (sdp_handle, ATTR_ID_HID_DESCRIPTOR_LIST, DATA_ELE_SEQ_DESC_TYPE,
+ (UINT32)(pd - pRepDescriptor), pRepDescriptor);
+ GKI_freebuf( pRepDescriptor );
+ }
+ else
+ {
+ SDP_DeleteRecord( sdp_handle ); /* delete freshly allocated record */
+ HIDD_TRACE_ERROR1( "HID_DevSetSDPRecord(): SDP creation failed: no memory for rep dscr len: %d",
+ p_sdp_info->dscp_info.dl_len );
+ return 0;
+ }
+ /* HID language base list */
+ SDP_AddAttribute (sdp_handle, ATTR_ID_HID_LANGUAGE_ID_BASE, DATA_ELE_SEQ_DESC_TYPE,
+ sizeof (HidDevLangList), (UINT8 *)HidDevLangList);
+
+ /* HID SDP disable (i.e. SDP while Control and Interrupt are up) */
+#if (MAX_L2CAP_CHANNELS > 2)
+ u8 = 0;
+#else
+ u8 = 1;
+#endif
+ SDP_AddAttribute(sdp_handle, ATTR_ID_HID_SDP_DISABLE, BOOLEAN_DESC_TYPE, 1, &u8);
+
+#if defined(HID_DEV_BATTERY_POW)
+ /* HID battery power */
+ u8 = HID_DEV_BATTERY_POW;
+ SDP_AddAttribute(sdp_handle, ATTR_ID_HID_BATTERY_POWER, BOOLEAN_DESC_TYPE, 1, &u8);
+#endif
+
+#if defined(HID_DEV_REMOTE_WAKE)
+ /* HID remote wakeup capable */
+ u8 = HID_DEV_REMOTE_WAKE;
+ SDP_AddAttribute(sdp_handle, ATTR_ID_HID_REMOTE_WAKE, BOOLEAN_DESC_TYPE, 1, &u8);
+#endif
+
+ /* Link supervision timeout */
+ UINT16_TO_BE_FIELD(buf,HID_DEV_LINK_SUPERVISION_TO) ;
+ SDP_AddAttribute(sdp_handle, ATTR_ID_HID_LINK_SUPERVISION_TO, UINT_DESC_TYPE, 2, (UINT8 *)buf);
+
+ /* HID remote wakeup capable */
+ u8 = HID_DEV_NORMALLY_CONN;
+ SDP_AddAttribute(sdp_handle, ATTR_ID_HID_NORMALLY_CONNECTABLE, BOOLEAN_DESC_TYPE, 1, &u8);
+
+ /* HID BOOT Device */
+ u8 = HID_DEV_BOOT_DEVICE;
+ SDP_AddAttribute(sdp_handle, ATTR_ID_HID_BOOT_DEVICE, BOOLEAN_DESC_TYPE, 1, &u8);
+
+ u16 = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
+ SDP_AddUuidSequence (sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &u16);
+
+ /* SSR host max latency */
+ if (p_sdp_info->ssr_max_latency != HID_SSR_PARAM_INVALID)
+ {
+ UINT16_TO_BE_FIELD(buf,HID_DEV_LINK_SUPERVISION_TO) ;
+ SDP_AddAttribute(sdp_handle, ATTR_ID_HID_SSR_HOST_MAX_LAT, UINT_DESC_TYPE, 2, (UINT8 *)buf);
+ }
+
+ /* SSR host min timeout */
+ if (p_sdp_info->ssr_max_latency != HID_SSR_PARAM_INVALID)
+ {
+ UINT16_TO_BE_FIELD(buf,HID_DEV_LINK_SUPERVISION_TO) ;
+ SDP_AddAttribute(sdp_handle, ATTR_ID_HID_SSR_HOST_MIN_TOUT, UINT_DESC_TYPE, 2, (UINT8 *)buf);
+ }
+ return (sdp_handle);
+}
+
+/*******************************************************************************
+**
+** Function HID_DevInit
+**
+** Description This function initializes the control block and trace variable
+**
+** Returns void
+**
+*******************************************************************************/
+void HID_DevInit (void)
+{
+ memset(&hd_cb, 0, sizeof(tHIDDEV_CB));
+
+ /* Initialize control channel L2CAP configuration */
+ hd_cb.l2cap_ctrl_cfg.mtu_present = TRUE;
+ hd_cb.l2cap_ctrl_cfg.mtu = HID_DEV_MTU_SIZE;
+
+ /* Initialize interrupt channel L2CAP configuration */
+ hd_cb.l2cap_int_cfg.mtu_present = TRUE;
+ hd_cb.l2cap_int_cfg.mtu = HID_DEV_MTU_SIZE;
+
+ hd_cb.conn.timer_entry.param = (UINT32) hidd_proc_repage_timeout;
+#if defined(HID_INITIAL_TRACE_LEVEL)
+ hd_cb.trace_level = HID_INITIAL_TRACE_LEVEL;
+#else
+ hd_cb.trace_level = BT_TRACE_LEVEL_NONE;
+#endif
+}
+
+/*******************************************************************************
+**
+** Function HID_DevRegister
+**
+** Description This function must be called at startup so the device receive
+** HID related events and call other HID API Calls.
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+tHID_STATUS HID_DevRegister( tHID_DEV_REG_INFO *p_reg_info )
+{
+ tHID_STATUS st;
+ BD_ADDR bt_bd_any = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+ UINT16 conn_able;
+
+ if( p_reg_info == NULL ||
+ p_reg_info->app_cback == NULL )
+ return HID_ERR_INVALID_PARAM;
+
+ if( hd_cb.reg_flag )
+ return HID_ERR_ALREADY_REGISTERED;
+
+ /* Check if the host address is provided */
+ if( memcmp( p_reg_info->host_addr, bt_bd_any, BD_ADDR_LEN ) )
+ {
+ hd_cb.host_known = TRUE;
+ memcpy( hd_cb.host_addr, p_reg_info->host_addr, BD_ADDR_LEN );
+ hd_cb.dev_state = HID_DEV_ST_NO_CONN ;
+
+ /* When host address is provided, connectibility is determined by the
+ SDP attribute, otherwise device has to be connectable for initial
+ pairing process with the host */
+ conn_able = (UINT16) HID_DEV_NORMALLY_CONN;
+ }
+ else
+ {
+ hd_cb.host_known = FALSE;
+ conn_able = BTM_CONNECTABLE;
+ }
+
+ hd_cb.virtual_cable = HID_DEV_VIRTUAL_CABLE;
+
+ /* Copy QoS parameters if provided */
+ if( p_reg_info->qos_info )
+ {
+ memcpy( &(hd_cb.qos_info), p_reg_info->qos_info, sizeof( tHID_DEV_QOS_INFO ) );
+ hd_cb.use_qos_flg = TRUE;
+ }
+ else
+ {
+ hd_cb.use_qos_flg = FALSE;
+ }
+
+ hd_cb.callback = p_reg_info->app_cback ;
+
+ /* Register with L2CAP */
+ if( (st = hidd_conn_reg()) != HID_SUCCESS )
+ {
+ return st;
+ }
+
+#if (!defined(HID_DEV_SET_CONN_MODE) || HID_DEV_SET_CONN_MODE == TRUE)
+ if( BTM_SetConnectability (conn_able, HID_DEV_PAGE_SCAN_WIN, HID_DEV_PAGE_SCAN_INT) != BTM_SUCCESS )
+ return HID_ERR_SET_CONNABLE_FAIL ;
+#endif
+
+ hd_cb.reg_flag = TRUE;
+ hd_cb.unplug_on = FALSE;
+
+ HIDD_TRACE_DEBUG0 ("HID_DevRegister successful");
+ return HID_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function HID_DevDeregister
+**
+** Description This function may be used to remove HID service records and
+** deregister from L2CAP.
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+tHID_STATUS HID_DevDeregister( void )
+{
+ if( !hd_cb.reg_flag )
+ return HID_ERR_NOT_REGISTERED;
+
+ hidd_mgmt_process_evt( HID_API_DISCONNECT, NULL ) ; /* Disconnect first */
+ /* Deregister with L2CAP */
+ hidd_conn_dereg() ;
+ hd_cb.reg_flag = FALSE;
+ return HID_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function HID_DevConnect
+**
+** Description This function may be used to initiate a connection to the host..
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+tHID_STATUS HID_DevConnect( void )
+{
+ if( hd_cb.reg_flag == FALSE )
+ return HID_ERR_NOT_REGISTERED;
+
+ return hidd_mgmt_process_evt( HID_API_CONNECT, NULL ) ; /* This will initiate connection */
+}
+
+/*******************************************************************************
+**
+** Function HID_DevDisconnect
+**
+** Description This function may be used to disconnect from the host
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+tHID_STATUS HID_DevDisconnect( void )
+{
+ if( hd_cb.reg_flag == FALSE )
+ return HID_ERR_NOT_REGISTERED;
+
+ return hidd_mgmt_process_evt( HID_API_DISCONNECT, NULL ) ; /* This will initiate disconnection */
+}
+
+/*******************************************************************************
+**
+** Function HID_DevHandShake
+**
+** Description This function may be used to send HAND-SHAKE to host
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+tHID_STATUS HID_DevHandShake( UINT8 res_code )
+{
+ tHID_SND_DATA_PARAMS hsk_data;
+
+ if( hd_cb.reg_flag == FALSE )
+ return HID_ERR_NOT_REGISTERED;
+
+ hsk_data.trans_type = HID_TRANS_HANDSHAKE ;
+ hsk_data.ctrl_ch = TRUE ;
+ hsk_data.param = res_code;
+ hsk_data.buf = NULL;
+
+ return hidd_mgmt_process_evt( HID_API_SEND_DATA, &hsk_data ) ;
+}
+
+/*******************************************************************************
+**
+** Function HID_DevVirtualUnplug
+**
+** Description This function may be used to send VIRTUAL-UNPLUG to host
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+tHID_STATUS HID_DevVirtualUnplug ( void )
+{
+ tHID_STATUS st;
+
+ tHID_SND_DATA_PARAMS vup_data;
+
+ if( hd_cb.reg_flag == FALSE )
+ return HID_ERR_NOT_REGISTERED;
+
+ vup_data.trans_type = HID_TRANS_CONTROL ;
+ vup_data.ctrl_ch = TRUE ;
+ vup_data.param = HID_PAR_CONTROL_VIRTUAL_CABLE_UNPLUG;
+ vup_data.buf = NULL;
+
+ if( (st = hidd_mgmt_process_evt(HID_API_SEND_DATA, &vup_data)) == HID_SUCCESS )
+ {
+ hd_cb.unplug_on = TRUE;
+ }
+
+ return st;
+}
+
+/*******************************************************************************
+**
+** Function HID_DevSendData
+**
+** Description This function may be used to send input reports to host
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+tHID_STATUS HID_DevSendData ( BOOLEAN control_ch, UINT8 rep_type, BT_HDR *data_buf )
+{
+ tHID_SND_DATA_PARAMS snd_data;
+
+ WC_ASSERT(control_ch != TRUE && control_ch != FALSE);
+
+ if( hd_cb.reg_flag == FALSE )
+ return HID_ERR_NOT_REGISTERED;
+
+ snd_data.trans_type = HID_TRANS_DATA ;
+ snd_data.ctrl_ch = control_ch ;
+ snd_data.param = rep_type;
+ snd_data.buf = data_buf;
+
+ return hidd_mgmt_process_evt( HID_API_SEND_DATA, &snd_data ) ;
+}
+
+/*******************************************************************************
+**
+** Function HID_DevSetSecurityLevel
+**
+** Description This function set security level for the Hid Device service.
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+tHID_STATUS HID_DevSetSecurityLevel( char serv_name[], UINT8 sec_lvl )
+{
+ hd_cb.sec_mask = sec_lvl;
+
+ if (sec_lvl == 0)
+ {
+ if (!BTM_SetSecurityLevel (FALSE, serv_name, BTM_SEC_SERVICE_HID_NOSEC_CTRL,
+ BTM_SEC_NONE, HID_PSM_CONTROL, BTM_SEC_PROTO_HID , HIDD_NOSEC_CHN))
+ {
+ HIDD_TRACE_ERROR0 ("Security Registration 1 failed");
+ return (HID_ERR_NO_RESOURCES);
+ }
+ if (!BTM_SetSecurityLevel (TRUE, serv_name, BTM_SEC_SERVICE_HID_NOSEC_CTRL,
+ BTM_SEC_NONE, HID_PSM_CONTROL, BTM_SEC_PROTO_HID, HIDD_NOSEC_CHN))
+ {
+ HIDD_TRACE_ERROR0 ("Security Registration 2 failed");
+ return (HID_ERR_NO_RESOURCES);
+ }
+ }
+ else
+ {
+ /* Register with Security Manager for the specific security level */
+ if (!BTM_SetSecurityLevel (FALSE, serv_name, BTM_SEC_SERVICE_HID_SEC_CTRL,
+ sec_lvl, HID_PSM_CONTROL, BTM_SEC_PROTO_HID, HIDD_SEC_CHN))
+ {
+ HIDD_TRACE_ERROR0 ("Security Registration 3 failed");
+ return (HID_ERR_NO_RESOURCES);
+ }
+ if (!BTM_SetSecurityLevel (TRUE, serv_name, BTM_SEC_SERVICE_HID_SEC_CTRL,
+ sec_lvl, HID_PSM_CONTROL, BTM_SEC_PROTO_HID, HIDD_SEC_CHN))
+ {
+ HIDD_TRACE_ERROR0 ("Security Registration 4 failed");
+ return (HID_ERR_NO_RESOURCES);
+ }
+ }
+
+ /* Register with Security Manager for the specific security level for interupt channel*/
+ if (!BTM_SetSecurityLevel (TRUE, serv_name, BTM_SEC_SERVICE_HID_INTR,
+ BTM_SEC_NONE, HID_PSM_INTERRUPT, BTM_SEC_PROTO_HID, 0))
+ {
+ HIDD_TRACE_ERROR0 ("Security Registration 5 failed");
+ return (HID_ERR_NO_RESOURCES);
+ }
+
+ if (!BTM_SetSecurityLevel (FALSE, serv_name, BTM_SEC_SERVICE_HID_INTR,
+ BTM_SEC_NONE, HID_PSM_INTERRUPT, BTM_SEC_PROTO_HID, 0))
+ {
+ HIDD_TRACE_ERROR0 ("Security Registration 6 failed");
+ return (HID_ERR_NO_RESOURCES);
+ }
+
+ return HID_SUCCESS;
+}
+
+#if HID_DEV_PM_INCLUDED == TRUE
+/*******************************************************************************
+**
+** Function HID_DevSetPowerMgmtParams
+**
+** Description This function may be used to change power mgmt parameters.
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+tHID_STATUS HID_DevSetPowerMgmtParams( UINT8 conn_substate, tHID_DEV_PM_PWR_MD pm_params )
+{
+ if( conn_substate > HID_DEV_SUSP_CONN_ST )
+ return (HID_ERR_INVALID_PARAM);
+
+ memcpy( &hd_cb.pm_params[conn_substate], &pm_params, sizeof( tHID_DEV_PM_PWR_MD ) ) ;
+
+ /* Set the power mode to new parameters if currently in that state */
+ if( conn_substate == hd_cb.conn_substate )
+ hidd_pm_set_power_mode ( &(hd_cb.pm_params[conn_substate]) );
+
+ return (HID_SUCCESS);
+}
+
+#endif
+
diff --git a/stack/hid/hidd_conn.c b/stack/hid/hidd_conn.c
new file mode 100644
index 0000000..111dcb7
--- /dev/null
+++ b/stack/hid/hidd_conn.c
@@ -0,0 +1,970 @@
+/*****************************************************************************/
+/* */
+/* Name: hidd_conn.c */
+/* */
+/* Description: this file contains the connection interface functions */
+/* for device role */
+/* Copyright (c) 2002-2011, Broadcom Corp., All Rights Reserved. */
+/* Broadcom Bluetooth Core. Proprietary and confidential. */
+/* */
+/*****************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+
+#include "gki.h"
+#include "bt_types.h"
+
+#include "l2cdefs.h"
+#include "l2c_api.h"
+
+#include "btu.h"
+#include "btm_api.h"
+#include "btm_int.h"
+
+#include "hiddefs.h"
+
+#include "hidd_api.h"
+#include "hidd_int.h"
+
+/********************************************************************************/
+/* L O C A L F U N C T I O N P R O T O T Y P E S */
+/********************************************************************************/
+static void hidd_l2cif_connect_ind (BD_ADDR bd_addr, UINT16 l2cap_cid, UINT16 psm,
+ UINT8 l2cap_id);
+static void hidd_l2cif_connect_cfm (UINT16 l2cap_cid, UINT16 result);
+static void hidd_l2cif_config_ind (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg);
+static void hidd_l2cif_config_cfm (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg);
+static void hidd_l2cif_disconnect_ind (UINT16 l2cap_cid, BOOLEAN ack_needed);
+static void hidd_l2cif_data_ind (UINT16 l2cap_cid, BT_HDR *p_msg);
+static void hidd_l2cif_disconnect_cfm (UINT16 l2cap_cid, UINT16 result);
+static void hidd_l2cif_cong_ind (UINT16 l2cap_cid, BOOLEAN congested);
+
+static const tL2CAP_APPL_INFO reg_info =
+{
+ hidd_l2cif_connect_ind,
+ hidd_l2cif_connect_cfm,
+ NULL,
+ hidd_l2cif_config_ind,
+ hidd_l2cif_config_cfm,
+ hidd_l2cif_disconnect_ind,
+ hidd_l2cif_disconnect_cfm,
+ NULL,
+ hidd_l2cif_data_ind,
+ hidd_l2cif_cong_ind,
+ NULL /* tL2CA_TX_COMPLETE_CB */
+} ;
+
+
+/*******************************************************************************
+**
+** Function hidd_conn_reg
+**
+** Description This function registers with L2CAP.
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+tHID_STATUS hidd_conn_reg (void)
+{
+ /* Now, register with L2CAP for control and interrupt PSMs*/
+ if (!L2CA_Register (HID_PSM_CONTROL, (tL2CAP_APPL_INFO *) &reg_info))
+ {
+ HIDD_TRACE_ERROR0 ("HID Control Registration failed");
+ return( HID_ERR_L2CAP_FAILED );
+ }
+
+ if (!L2CA_Register (HID_PSM_INTERRUPT, (tL2CAP_APPL_INFO *) &reg_info))
+ {
+ L2CA_Deregister( HID_PSM_CONTROL ) ;
+ HIDD_TRACE_ERROR0 ("HID Interrupt Registration failed");
+ return( HID_ERR_L2CAP_FAILED );
+ }
+
+ /* Set up / initialize the l2cap configuration data */
+ hd_cb.l2cap_ctrl_cfg.flush_to_present = TRUE;
+ hd_cb.l2cap_ctrl_cfg.flush_to = HID_DEV_FLUSH_TO;
+ hd_cb.l2cap_int_cfg.flush_to_present = TRUE;
+ hd_cb.l2cap_int_cfg.flush_to = HID_DEV_FLUSH_TO;
+
+ if( hd_cb.use_qos_flg == TRUE )
+ {
+ memcpy( &(hd_cb.l2cap_ctrl_cfg.qos), &(hd_cb.qos_info.ctrl_ch), sizeof( FLOW_SPEC ) ) ;
+ hd_cb.l2cap_ctrl_cfg.qos_present = TRUE ;
+
+ memcpy( &(hd_cb.l2cap_int_cfg.qos), &(hd_cb.qos_info.int_ch), sizeof( FLOW_SPEC ) ) ;
+ hd_cb.l2cap_int_cfg.qos_present = TRUE ;
+ }
+ else
+ {
+ hd_cb.l2cap_ctrl_cfg.qos_present = FALSE ;
+ hd_cb.l2cap_int_cfg.qos_present = FALSE ;
+ }
+
+ hd_cb.conn.conn_state = HID_CONN_STATE_UNUSED ;
+
+ return( HID_SUCCESS );
+}
+
+/*******************************************************************************
+**
+** Function hidd_conn_dereg
+**
+** Description This function deregisters with L2CAP.
+**
+** Returns void
+**
+*******************************************************************************/
+void hidd_conn_dereg( void )
+{
+ L2CA_Deregister (HID_PSM_CONTROL);
+ L2CA_Deregister (HID_PSM_INTERRUPT);
+}
+
+/*******************************************************************************
+**
+** Function hid_conn_disconnect
+**
+** Description This function disconnects a connection.
+**
+** Returns TRUE if disconnect started, FALSE if already disconnected
+**
+*******************************************************************************/
+void hidd_conn_disconnect ()
+{
+ tHID_CONN *p_hcon = &hd_cb.conn;
+#if HID_DEV_PM_INCLUDED == TRUE
+ tHID_DEV_PM_PWR_MD act_pm = { 0, 0, 0, 0, HCI_MODE_ACTIVE } ;
+#endif
+
+ HIDD_TRACE_EVENT0 ("HID - disconnect");
+
+#if HID_DEV_PM_INCLUDED == TRUE
+ hidd_pm_stop(); /* This will stop the idle timer if running */
+
+ /* Need to go to to active mode to be able to send disconnect */
+ hidd_pm_set_power_mode( &act_pm );
+#endif
+
+ if ((p_hcon->ctrl_cid != 0) || (p_hcon->intr_cid != 0))
+ {
+ p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING;
+ /* Disconnect both control and interrupt channels */
+ if (p_hcon->intr_cid)
+ L2CA_DisconnectReq (p_hcon->intr_cid);
+
+ if (p_hcon->ctrl_cid)
+ L2CA_DisconnectReq (p_hcon->ctrl_cid);
+ }
+ else
+ {
+ p_hcon->conn_state = HID_CONN_STATE_UNUSED;
+ }
+}
+
+/*******************************************************************************
+**
+** Function hidd_conn_initiate
+**
+** Description This function is called by the management to create a connection.
+**
+** Returns void
+**
+*******************************************************************************/
+tHID_STATUS hidd_conn_initiate (void)
+{
+ tHID_CONN *p_hcon = &hd_cb.conn;
+ UINT8 service_id = BTM_SEC_SERVICE_HID_NOSEC_CTRL;
+ UINT32 mx_chan_id = HIDD_NOSEC_CHN;
+
+#if HID_DEV_NORMALLY_CONN == TRUE
+ if( p_hcon->conn_state != HID_CONN_STATE_UNUSED )
+ return HID_ERR_CONN_IN_PROCESS ;
+#endif
+
+ HIDD_TRACE_EVENT0 ("HID - Originate started");
+
+ p_hcon->ctrl_cid = 0;
+ p_hcon->intr_cid = 0;
+
+ /* We are the originator of this connection */
+ p_hcon->conn_flags = HID_CONN_FLAGS_IS_ORIG;
+ if(hd_cb.sec_mask)
+ {
+ service_id = BTM_SEC_SERVICE_HID_SEC_CTRL;
+ mx_chan_id = HIDD_SEC_CHN;
+ }
+ BTM_SetOutService (hd_cb.host_addr, service_id, mx_chan_id);
+
+ /* Check if L2CAP started the connection process */
+ if ((p_hcon->ctrl_cid = L2CA_ConnectReq (HID_PSM_CONTROL, hd_cb.host_addr)) == 0)
+ {
+ HIDD_TRACE_WARNING0 ("HID - Originate failed");
+ return (HID_ERR_L2CAP_FAILED);
+ }
+ else
+ {
+ /* Transition to the next appropriate state, waiting for connection confirm on control channel. */
+ p_hcon->conn_state = HID_CONN_STATE_CONNECTING_CTRL;
+
+ return (HID_SUCCESS);
+ }
+}
+
+/*******************************************************************************
+**
+** Function hidd_sec_check_complete_term
+**
+** Description HID device security check complete callback function.
+**
+** Returns When security check succeed, send L2Cap connect response with
+** OK code and send L2C configuration requret; otherwise send
+** L2C connection response with security block code.
+**
+**
+*******************************************************************************/
+void hidd_sec_check_complete_term (BD_ADDR bd_addr, void *p_ref_data, UINT8 res)
+{
+ tHID_CONN *p_hcon = &hd_cb.conn;
+
+ if( res == BTM_SUCCESS && p_hcon->conn_state == HID_CONN_STATE_SECURITY )
+ {
+ p_hcon->conn_state = HID_CONN_STATE_CONNECTING_INTR;
+
+ /* Send response to the L2CAP layer. */
+ L2CA_ConnectRsp (bd_addr, p_hcon->ctrl_id, p_hcon->ctrl_cid, L2CAP_CONN_OK, L2CAP_CONN_OK);
+
+ /* Send a Configuration Request. */
+ L2CA_ConfigReq (p_hcon->ctrl_cid, &hd_cb.l2cap_ctrl_cfg);
+
+ }
+ /* security check fail */
+ else if (res != BTM_SUCCESS)
+ {
+ L2CA_ConnectRsp (bd_addr, p_hcon->ctrl_id, p_hcon->ctrl_cid, L2CAP_CONN_SECURITY_BLOCK, L2CAP_CONN_OK);
+ p_hcon->conn_state = HID_CONN_STATE_UNUSED;
+ }
+}
+
+/*******************************************************************************
+**
+** Function hidd_l2cif_connect_ind
+**
+** Description This function handles an inbound connection indication
+** from L2CAP. This is the case where we are acting as a
+** server.
+**
+** Returns void
+**
+*******************************************************************************/
+static void hidd_l2cif_connect_ind (BD_ADDR bd_addr, UINT16 l2cap_cid, UINT16 psm, UINT8 l2cap_id)
+{
+ tHID_CONN *p_hcon = &hd_cb.conn;
+ BOOLEAN bAccept = TRUE;
+ tL2CAP_CFG_INFO *p_l2cfg = NULL;
+
+ HIDD_TRACE_EVENT2 ("HID - Rcvd L2CAP conn ind, PSM: 0x%04x CID 0x%x", psm, l2cap_cid);
+
+ /* If host address provided during registration does not match, reject connection */
+ if( hd_cb.virtual_cable && hd_cb.host_known &&
+ memcmp( hd_cb.host_addr, bd_addr, BD_ADDR_LEN) )
+ bAccept = FALSE;
+ else
+ {
+ /* Check we are in the correct state for this */
+ if (psm == HID_PSM_INTERRUPT)
+ {
+ if (p_hcon->ctrl_cid == 0)
+ {
+ HIDD_TRACE_WARNING0 ("HID - Rcvd INTR L2CAP conn ind, but no CTL channel");
+ bAccept = FALSE;
+ }
+ if (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR)
+ {
+ HIDD_TRACE_WARNING1 ("HID - Rcvd INTR L2CAP conn ind, wrong state: %d", p_hcon->conn_state);
+ bAccept = FALSE;
+ }
+ p_l2cfg = &hd_cb.l2cap_int_cfg;
+ }
+ else
+ {
+ if (p_hcon->conn_state != HID_CONN_STATE_UNUSED)
+ {
+ HIDD_TRACE_WARNING1 ("HID - Rcvd CTL L2CAP conn ind, wrong state: %d", p_hcon->conn_state);
+ bAccept = FALSE;
+ }
+ p_l2cfg = &hd_cb.l2cap_ctrl_cfg;
+ }
+ }
+
+ if (!bAccept)
+ {
+ L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_NO_RESOURCES, 0);
+ return;
+ }
+
+ if (psm == HID_PSM_CONTROL)
+ {
+ p_hcon->conn_flags = 0;
+ p_hcon->ctrl_cid = l2cap_cid;
+ p_hcon->ctrl_id = l2cap_id;
+
+ p_hcon->conn_state = HID_CONN_STATE_SECURITY;
+
+ if(btm_sec_mx_access_request (bd_addr, HID_PSM_CONTROL,
+ FALSE, BTM_SEC_PROTO_HID,
+ (hd_cb.sec_mask == 0) ? HIDD_NOSEC_CHN : HIDD_SEC_CHN,
+ &hidd_sec_check_complete_term, NULL) == BTM_CMD_STARTED)
+ {
+ L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_PENDING, L2CAP_CONN_OK);
+ }
+ return;
+ }
+ else
+ {
+ /* Transition to the next appropriate state, configuration */
+ p_hcon->conn_state = HID_CONN_STATE_CONFIG;
+ p_hcon->intr_cid = l2cap_cid;
+ }
+
+ /* Send response to the L2CAP layer. */
+ L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_OK, L2CAP_CONN_OK);
+
+ /* Send a Configuration Request. */
+ L2CA_ConfigReq (l2cap_cid, p_l2cfg);
+
+ memcpy( hd_cb.host_addr, bd_addr, BD_ADDR_LEN ) ;
+
+ HIDD_TRACE_EVENT2 ("HID - Rcvd L2CAP conn ind, sent config req, PSM: 0x%04x CID 0x%x", psm, l2cap_cid);
+}
+
+/*******************************************************************************
+**
+** Function hidd_sec_check_complete_orig
+**
+** Description This function checks to see if security procedures are being
+** carried out or not..
+**
+** Returns void
+**
+*******************************************************************************/
+void hidd_sec_check_complete_orig (BD_ADDR bd_addr, void *p_ref_data, UINT8 res)
+{
+ UINT32 reason;
+ tHID_CONN *p_hcon = &hd_cb.conn;
+
+ if( res == BTM_SUCCESS && p_hcon->conn_state == HID_CONN_STATE_SECURITY )
+ {
+ HIDD_TRACE_EVENT0 ("HID Device - Originator security pass.");
+
+ /* Send connect request for interrupt channel */
+ if ((p_hcon->intr_cid = L2CA_ConnectReq (HID_PSM_INTERRUPT, hd_cb.host_addr)) == 0)
+ {
+ HIDD_TRACE_WARNING0 ("HID - INTR Originate failed");
+ hidd_conn_disconnect();/* Disconnects the ctrl channel if setting of int chnl failed */
+ reason = HID_L2CAP_REQ_FAIL ;
+ hd_cb.conn_tries = HID_DEV_MAX_CONN_RETRY+1;
+ hidd_mgmt_process_evt( HOST_CONN_FAIL, &reason ) ;
+ return;
+ }
+ else
+ {
+ /* Transition to the next appropriate state, waiting for connection confirm on control channel. */
+ p_hcon->conn_state = HID_CONN_STATE_CONNECTING_INTR;
+ }
+ }
+
+ if( res != BTM_SUCCESS && p_hcon->conn_state == HID_CONN_STATE_SECURITY )
+ {
+ hidd_conn_disconnect();
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function hid_l2cif_connect_cfm
+**
+** Description This function handles the connect confirm events
+** from L2CAP. This is the case when we are acting as a
+** client and have sent a connect request.
+**
+** Returns void
+**
+*******************************************************************************/
+static void hidd_l2cif_connect_cfm (UINT16 l2cap_cid, UINT16 result)
+{
+ UINT32 reason;
+ tHID_CONN *p_hcon = &hd_cb.conn;
+ tL2CAP_CFG_INFO *p_l2cfg;
+
+ /* Verify we are in a state to accept this message */
+ if (((p_hcon->ctrl_cid != l2cap_cid) && (p_hcon->intr_cid != l2cap_cid))
+ || (!(p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG))
+ || ((l2cap_cid == p_hcon->ctrl_cid) && (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_CTRL))
+ || ((l2cap_cid == p_hcon->intr_cid) && (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR)))
+ {
+ HIDD_TRACE_WARNING1 ("HID - Rcvd unexpected conn cnf, CID 0x%x ", l2cap_cid);
+ return;
+ }
+
+ if (result != L2CAP_CONN_OK)
+ {
+ if (l2cap_cid == p_hcon->ctrl_cid)
+ p_hcon->ctrl_cid = 0;
+ else
+ p_hcon->intr_cid = 0;
+
+ reason = HID_L2CAP_CONN_FAIL | ((UINT32) result) ;
+ hidd_conn_disconnect(); /* Disconnects the ctrl channel if setting of int chnl failed */
+
+ /* If connection failed due to bad air link, retry... */
+ if (result != HCI_ERR_CONNECTION_TOUT && result != HCI_ERR_UNSPECIFIED
+ && result != HCI_ERR_PAGE_TIMEOUT)
+ hd_cb.conn_tries = HID_DEV_MAX_CONN_RETRY+1;
+ hidd_mgmt_process_evt( HOST_CONN_FAIL, &reason ) ;
+ return;
+ }
+
+ if (l2cap_cid == p_hcon->ctrl_cid)
+ {
+ /* let HID Device handle security itself */
+ p_hcon->conn_state = HID_CONN_STATE_SECURITY;
+
+ btm_sec_mx_access_request (hd_cb.host_addr, HID_PSM_CONTROL,
+ TRUE, BTM_SEC_PROTO_HID,
+ (hd_cb.sec_mask == 0) ? HIDD_NOSEC_CHN : HIDD_SEC_CHN,
+ &hidd_sec_check_complete_orig, NULL);
+
+ p_l2cfg = &hd_cb.l2cap_int_cfg;
+
+ }
+ else
+ {
+ p_hcon->conn_state = HID_CONN_STATE_CONFIG;
+ p_l2cfg = &hd_cb.l2cap_ctrl_cfg;
+ }
+
+ /* Send a Configuration Request. */
+ L2CA_ConfigReq (l2cap_cid, p_l2cfg);
+
+ HIDD_TRACE_EVENT1 ("HID - got CTRL conn cnf, sent cfg req, CID: 0x%x", l2cap_cid);
+ return;
+}
+
+/*******************************************************************************
+**
+** Function hidd_l2c_connected
+**
+** Description This function is called when both control and interrupt channels
+** have been created.
+**
+** Returns void
+**
+*******************************************************************************/
+void hidd_l2c_connected( tHID_CONN *p_hcon )
+{
+ p_hcon->conn_state = HID_CONN_STATE_CONNECTED;
+
+ /* Set HCI QoS */
+ if( hd_cb.use_qos_flg )
+ BTM_SetQoS( hd_cb.host_addr, &(hd_cb.qos_info.hci), NULL ) ;
+
+ hidd_mgmt_process_evt( HOST_CONN_OPEN, hd_cb.host_addr) ;
+#if HID_DEV_PM_INCLUDED == TRUE
+ hidd_pm_init();
+ hidd_pm_start(); /* This kicks in the idle timer */
+#endif
+}
+
+/*******************************************************************************
+**
+** Function hidd_l2cif_config_ind
+**
+** Description This function processes the L2CAP configuration indication
+** event.
+**
+** Returns void
+**
+*******************************************************************************/
+static void hidd_l2cif_config_ind (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg)
+{
+ tHID_CONN *p_hcon = &hd_cb.conn;
+
+ /* Find CCB based on CID */
+ if ((p_hcon->ctrl_cid != l2cap_cid) && (p_hcon->intr_cid != l2cap_cid))
+ {
+ HIDD_TRACE_WARNING1 ("HID - Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid);
+ return;
+ }
+
+ HIDD_TRACE_EVENT1 ("HID - Rcvd cfg ind, sent cfg cfm, CID: 0x%x", l2cap_cid);
+
+ /* Remember the remote MTU size */
+ if ((!p_cfg->mtu_present) || (p_cfg->mtu > HID_DEV_MTU_SIZE))
+ p_hcon->rem_mtu_size = HID_DEV_MTU_SIZE;
+ else
+ p_hcon->rem_mtu_size = p_cfg->mtu;
+
+ /* For now, always accept configuration from the other side */
+ p_cfg->flush_to_present = FALSE;
+ p_cfg->mtu_present = FALSE;
+ p_cfg->result = L2CAP_CFG_OK;
+
+ L2CA_ConfigRsp (l2cap_cid, p_cfg);
+
+ if (l2cap_cid == p_hcon->ctrl_cid)
+ p_hcon->conn_flags |= HID_CONN_FLAGS_HIS_CTRL_CFG_DONE;
+ else
+ p_hcon->conn_flags |= HID_CONN_FLAGS_HIS_INTR_CFG_DONE;
+
+ /* If all configuration is complete, change state and tell management we are up */
+ if (((p_hcon->conn_flags & HID_CONN_FLAGS_ALL_CONFIGURED) == HID_CONN_FLAGS_ALL_CONFIGURED)
+ && (p_hcon->conn_state == HID_CONN_STATE_CONFIG))
+ {
+ hidd_l2c_connected( p_hcon );
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function hid_l2cif_config_cfm
+**
+** Description This function processes the L2CAP configuration confirmation
+** event.
+**
+** Returns void
+**
+*******************************************************************************/
+static void hidd_l2cif_config_cfm (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg)
+{
+ UINT32 reason;
+ tHID_CONN *p_hcon = &hd_cb.conn;
+ tL2CAP_CFG_INFO * p_l2cfg = NULL;
+
+ HIDD_TRACE_EVENT2 ("HID - Rcvd cfg cfm, CID: 0x%x Result: %d", l2cap_cid, p_cfg->result);
+
+ /* Find CCB based on CID */
+ if ((p_hcon->ctrl_cid != l2cap_cid) && (p_hcon->intr_cid != l2cap_cid))
+ {
+ HIDD_TRACE_WARNING1 ("HID - Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid);
+ return;
+ }
+
+ /* config fail for unaccepted param, send reconfiguration */
+ if (p_cfg->result == L2CAP_CFG_UNACCEPTABLE_PARAMS)
+ {
+ /* remember the host prefered config param in control block */
+ p_l2cfg = (l2cap_cid == p_hcon->ctrl_cid)? &hd_cb.l2cap_ctrl_cfg : &hd_cb.l2cap_int_cfg ;
+ memcpy(p_l2cfg, p_cfg, sizeof(tL2CAP_CFG_INFO));
+
+ /* Send a second time configuration request. */
+ L2CA_ConfigReq (l2cap_cid, p_l2cfg);
+ return;
+ }
+ /* If configuration failed for other reason, disconnect the channel(s) */
+ else if (p_cfg->result != L2CAP_CFG_OK)
+ {
+ reason = HID_L2CAP_CFG_FAIL | ((UINT32) p_cfg->result) ;
+ hidd_conn_disconnect();
+ hd_cb.conn_tries = HID_DEV_MAX_CONN_RETRY+1;
+ hidd_mgmt_process_evt( HOST_CONN_FAIL, &reason ) ;
+ return;
+ }
+
+ if (l2cap_cid == p_hcon->ctrl_cid)
+ p_hcon->conn_flags |= HID_CONN_FLAGS_MY_CTRL_CFG_DONE;
+ else
+ p_hcon->conn_flags |= HID_CONN_FLAGS_MY_INTR_CFG_DONE;
+
+ /* If all configuration is complete, change state and tell management we are up */
+ if (((p_hcon->conn_flags & HID_CONN_FLAGS_ALL_CONFIGURED) == HID_CONN_FLAGS_ALL_CONFIGURED)
+ && (p_hcon->conn_state == HID_CONN_STATE_CONFIG))
+ {
+ hidd_l2c_connected( p_hcon );
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function hidd_l2cif_disconnect_ind
+**
+** Description This function handles a disconnect event from L2CAP. If
+** requested to, we ack the disconnect before dropping the CCB
+**
+** Returns void
+**
+*******************************************************************************/
+static void hidd_l2cif_disconnect_ind (UINT16 l2cap_cid, BOOLEAN ack_needed)
+{
+ tHID_CONN *p_hcon = &hd_cb.conn;
+ UINT16 disc_res = HCI_PENDING ;
+ UINT8 evt = HOST_CONN_CLOSE;
+
+ /* Find CCB based on CID */
+ if ((p_hcon->ctrl_cid != l2cap_cid) && (p_hcon->intr_cid != l2cap_cid))
+ {
+ HIDD_TRACE_WARNING1 ("HID - Rcvd L2CAP disc, unknown CID: 0x%x", l2cap_cid);
+ return;
+ }
+
+ if (ack_needed)
+ L2CA_DisconnectRsp (l2cap_cid);
+
+ HIDD_TRACE_EVENT1 ("HID - Rcvd L2CAP disc, CID: 0x%x", l2cap_cid);
+
+ p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING;
+
+ if (l2cap_cid == p_hcon->ctrl_cid)
+ p_hcon->ctrl_cid = 0;
+ else
+ p_hcon->intr_cid = 0;
+
+ if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0))
+ {
+ if (!ack_needed)
+ disc_res = btm_get_acl_disc_reason_code();
+ HIDD_TRACE_EVENT1 ("disc_res: 0x%x", disc_res);
+
+ if( disc_res == HCI_ERR_CONNECTION_TOUT || disc_res == HCI_ERR_UNSPECIFIED )
+ evt = HOST_CONN_LOST;
+
+ p_hcon->conn_state = HID_CONN_STATE_UNUSED;
+ hidd_mgmt_process_evt( evt, &disc_res ) ;
+#if HID_DEV_PM_INCLUDED == TRUE
+ hidd_pm_stop();
+#endif
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function hid_l2cif_disconnect_cfm
+**
+** Description This function handles a disconnect confirm event from L2CAP.
+**
+** Returns void
+**
+*******************************************************************************/
+static void hidd_l2cif_disconnect_cfm (UINT16 l2cap_cid, UINT16 result)
+{
+ UINT16 disc_res = HCI_SUCCESS;
+ tHID_CONN *p_hcon = &hd_cb.conn;
+
+ /* Find CCB based on CID */
+ if ((p_hcon->ctrl_cid != l2cap_cid) && (p_hcon->intr_cid != l2cap_cid))
+ {
+ HIDD_TRACE_WARNING1 ("HID - Rcvd L2CAP disc cfm, unknown CID: 0x%x", l2cap_cid);
+ return;
+ }
+
+ HIDD_TRACE_EVENT1 ("HID - Rcvd L2CAP disc cfm, CID: 0x%x", l2cap_cid);
+
+ if (l2cap_cid == p_hcon->ctrl_cid)
+ p_hcon->ctrl_cid = 0;
+ else
+ p_hcon->intr_cid = 0;
+
+ if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0))
+ {
+ p_hcon->conn_state = HID_CONN_STATE_UNUSED;
+ hidd_mgmt_process_evt( HOST_CONN_CLOSE, &disc_res ) ;
+#if HID_DEV_PM_INCLUDED == TRUE
+ hidd_pm_stop();
+#endif
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function hidd_l2cif_cong_ind
+**
+** Description This function handles a congestion status event from L2CAP.
+**
+** Returns void
+**
+*******************************************************************************/
+static void hidd_l2cif_cong_ind (UINT16 l2cap_cid, BOOLEAN congested)
+{
+ tHID_CONN *p_hcon = &hd_cb.conn;
+
+ /* Find CCB based on CID */
+ if ((p_hcon->ctrl_cid != l2cap_cid) && (p_hcon->intr_cid != l2cap_cid))
+ {
+ HIDD_TRACE_WARNING1 ("HID - Rcvd L2CAP congestion status, unknown CID: 0x%x", l2cap_cid);
+ return;
+ }
+
+ HIDD_TRACE_EVENT2 ("HID - Rcvd L2CAP congestion status, CID: 0x%x Cong: %d", l2cap_cid, congested);
+
+ if (congested)
+ p_hcon->conn_flags |= HID_CONN_FLAGS_CONGESTED;
+ else
+ {
+ p_hcon->conn_flags &= ~HID_CONN_FLAGS_CONGESTED;
+ }
+
+ hd_cb.callback( HID_DEV_EVT_L2CAP_CONGEST, (p_hcon->ctrl_cid == l2cap_cid), (tHID_DEV_CBACK_DATA*) &congested ) ;
+}
+
+
+/*******************************************************************************
+**
+** Function hid_l2cif_data_ind
+**
+** Description This function is called when data is received from L2CAP.
+** if we are the originator of the connection, we are the SDP
+** client, and the received message is queued up for the client.
+**
+** If we are the destination of the connection, we are the SDP
+** server, so the message is passed to the server processing
+** function.
+**
+** Returns void
+**
+*******************************************************************************/
+static void hidd_l2cif_data_ind (UINT16 l2cap_cid, BT_HDR *p_msg)
+{
+ tHID_CONN *p_hcon = &hd_cb.conn;
+ UINT8 *p_data = (UINT8 *)(p_msg + 1) + p_msg->offset;
+ UINT8 ttype, param, rep_type, idle_rate;
+ tHID_DEV_GET_REP_DATA get_rep;
+ BOOLEAN suspend = FALSE;
+
+ /* Find CCB based on CID */
+ if ((p_hcon->ctrl_cid != l2cap_cid) && (p_hcon->intr_cid != l2cap_cid))
+ {
+ HIDD_TRACE_WARNING1 ("HID - Rcvd L2CAP data, unknown CID: 0x%x", l2cap_cid);
+ GKI_freebuf (p_msg);
+ return;
+ }
+
+ ttype = HID_GET_TRANS_FROM_HDR(*p_data);
+ param = HID_GET_PARAM_FROM_HDR(*p_data);
+ rep_type = param & HID_PAR_REP_TYPE_MASK;
+ p_data++;
+
+ switch (ttype)
+ {
+ case HID_TRANS_CONTROL:
+ switch (param)
+ {
+ case HID_PAR_CONTROL_NOP:
+ case HID_PAR_CONTROL_HARD_RESET:
+ case HID_PAR_CONTROL_SOFT_RESET:
+ case HID_PAR_CONTROL_EXIT_SUSPEND:
+ break;
+
+ case HID_PAR_CONTROL_SUSPEND:
+ suspend = TRUE;
+#if HID_DEV_PM_INCLUDED == TRUE
+ hidd_pm_suspend_evt() ;
+#endif
+ break;
+
+ case HID_PAR_CONTROL_VIRTUAL_CABLE_UNPLUG:
+ hidd_mgmt_process_evt( HID_API_DISCONNECT, NULL ) ;
+ hd_cb.unplug_on = TRUE;
+ break;
+
+ default:
+ GKI_freebuf (p_msg);
+ HID_DevHandShake( HID_PAR_HANDSHAKE_RSP_ERR_INVALID_PARAM ) ;
+ return;
+ }
+ hd_cb.callback( HID_DEV_EVT_CONTROL, param, NULL ) ;
+ break;
+
+ case HID_TRANS_GET_REPORT:
+ if (param & HID_PAR_GET_REP_BUFSIZE_FOLLOWS)
+ {
+ STREAM_TO_UINT8 (get_rep.rep_id, p_data);
+ STREAM_TO_UINT16 (hd_cb.get_rep_buf_sz, p_data);
+ }
+ else
+ hd_cb.get_rep_buf_sz = 0;
+
+ get_rep.rep_type = param & HID_PAR_REP_TYPE_MASK;
+
+ hd_cb.callback( HID_DEV_EVT_GET_REPORT, param,
+ (tHID_DEV_CBACK_DATA*) &get_rep ) ;
+ break;
+
+ case HID_TRANS_SET_REPORT:
+ hd_cb.callback( HID_DEV_EVT_SET_REPORT, rep_type, (tHID_DEV_CBACK_DATA*) &p_msg ) ;
+ break;
+
+ case HID_TRANS_DATA:
+ hd_cb.callback( HID_DEV_EVT_DATA, rep_type, (tHID_DEV_CBACK_DATA*) &p_msg ) ;
+ break;
+
+ case HID_TRANS_DATAC:
+ hd_cb.callback( HID_DEV_EVT_DATC, rep_type, (tHID_DEV_CBACK_DATA*) &p_msg ) ;
+ break;
+
+ case HID_TRANS_GET_PROTOCOL:
+ /* Get current protocol */
+ hd_cb.callback( HID_DEV_EVT_GET_PROTO, 0, NULL ) ;
+ break;
+
+ case HID_TRANS_SET_PROTOCOL:
+ hd_cb.callback( HID_DEV_EVT_SET_PROTO, (UINT32) (param & HID_PAR_PROTOCOL_MASK), NULL ) ;
+ break;
+
+ /* for HID 1.0 device only */
+ case HID_TRANS_GET_IDLE:
+ hd_cb.callback( HID_DEV_EVT_GET_IDLE, 0, NULL ) ;
+ break;
+
+ /* for HID 1.0 device only */
+ case HID_TRANS_SET_IDLE:
+ STREAM_TO_UINT8 (idle_rate, p_data);
+ hd_cb.callback( HID_DEV_EVT_SET_IDLE, idle_rate, NULL ) ;
+ break;
+
+ default:
+ GKI_freebuf (p_msg);
+ HID_DevHandShake( HID_PAR_HANDSHAKE_RSP_ERR_UNSUPPORTED_REQ ) ;
+ return;
+ }
+
+#if HID_DEV_PM_INCLUDED == TRUE
+ if( !suspend )
+ hidd_pm_start();
+#endif
+
+ if( (ttype != HID_TRANS_SET_REPORT) && (ttype != HID_TRANS_DATA) && (ttype != HID_TRANS_DATAC) )
+ GKI_freebuf (p_msg);
+ /* Else application frees the buffer */
+}
+
+/*******************************************************************************
+**
+** Function hidd_conn_snd_data
+**
+** Description This function is called to send HID data.
+**
+** Returns void
+**
+*******************************************************************************/
+tHID_STATUS hidd_conn_snd_data (tHID_SND_DATA_PARAMS *p_data)
+{
+ tHID_CONN *p_hcon = &hd_cb.conn;
+ BT_HDR *p_buf;
+ UINT8 *p_out;
+ UINT16 bytes_copied;
+ BOOLEAN seg_req = FALSE;
+ UINT16 data_size;
+ UINT16 cid;
+ UINT8 pool_id;
+ UINT16 rem_mtu;
+
+#if HID_DEV_PM_INCLUDED == TRUE
+ hidd_pm_start();
+#endif
+
+ /* Safety check */
+ if (p_data)
+ {
+ pool_id = (p_data->ctrl_ch) ? HID_CONTROL_POOL_ID : HID_INTERRUPT_POOL_ID;
+ }
+ else
+ {
+ HIDD_TRACE_ERROR0 ("HID_ERR_INVALID_PARAM");
+ return HID_ERR_INVALID_PARAM;
+ }
+
+ if (p_hcon->conn_flags & HID_CONN_FLAGS_CONGESTED)
+ {
+ return( HID_ERR_CONGESTED );
+ }
+
+ if( (p_data->trans_type == HID_TRANS_DATA) && p_data->ctrl_ch && hd_cb.get_rep_buf_sz )
+ {
+ rem_mtu = hd_cb.get_rep_buf_sz;
+ hd_cb.get_rep_buf_sz = 0;
+ }
+ else
+ {
+ rem_mtu = p_hcon->rem_mtu_size;
+ }
+
+ do
+ {
+ /* If buf is null form the HID message with ttype and params alone */
+ if ( p_data->buf == NULL )
+ {
+ if((p_buf = (BT_HDR *)GKI_getpoolbuf (pool_id)) == NULL)
+ return (HID_ERR_NO_RESOURCES);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ seg_req = FALSE;
+ data_size = 0;
+ bytes_copied = 0;
+ }
+ /* Segmentation case */
+ else if ( (p_data->buf->len > (rem_mtu - 1)))
+ {
+ if((p_buf = (BT_HDR *)GKI_getpoolbuf (pool_id)) == NULL)
+ return (HID_ERR_NO_RESOURCES);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ seg_req = TRUE;
+ data_size = p_data->buf->len;
+ bytes_copied = rem_mtu - 1;
+ }
+ else /* NOTE: The initial buffer gets used last */
+ {
+ p_buf = p_data->buf ;
+ p_buf->offset -= 1;
+ seg_req = FALSE;
+ data_size = p_data->buf->len;
+ bytes_copied = p_data->buf->len;
+ }
+
+ p_out = (UINT8 *)(p_buf + 1) + p_buf->offset;
+ *p_out++ = HID_BUILD_HDR(p_data->trans_type, p_data->param);
+
+ if (seg_req)
+ {
+ memcpy (p_out, (((UINT8 *)(p_data->buf+1)) + p_data->buf->offset), bytes_copied);
+ p_data->buf->offset += bytes_copied;
+ p_data->buf->len -= bytes_copied;
+ }
+
+ p_buf->len = bytes_copied + 1;
+ data_size -= bytes_copied;
+
+ cid = (p_data->ctrl_ch ? p_hcon->ctrl_cid : p_hcon->intr_cid);
+ /* Send the buffer through L2CAP */
+ if ((p_hcon->conn_flags & HID_CONN_FLAGS_CONGESTED) || (!L2CA_DataWrite (cid, p_buf)))
+ {
+ return (HID_ERR_CONGESTED);
+ }
+
+ if (data_size)
+ p_data->trans_type = HID_TRANS_DATAC;
+
+ } while (data_size != 0);
+
+ if( bytes_copied == (rem_mtu - 1) )
+ {
+ tHID_SND_DATA_PARAMS datc;
+
+ datc.buf = NULL;
+ datc.ctrl_ch = p_data->ctrl_ch;
+ datc.param = p_data->param ;
+ datc.trans_type = HID_TRANS_DATAC ;
+
+ hidd_conn_snd_data( &datc ) ;
+ }
+
+ return (HID_SUCCESS);
+}
+
diff --git a/stack/hid/hidd_int.h b/stack/hid/hidd_int.h
new file mode 100644
index 0000000..58d7a83
--- /dev/null
+++ b/stack/hid/hidd_int.h
@@ -0,0 +1,136 @@
+/****************************************************************************/
+/* */
+/* Name: hidd_int.h */
+/* */
+/* Function: this file contains HID DEVICE internal definitions */
+/* */
+/* */
+/* Copyright (c) 2002-2004, WIDCOMM Inc., All Rights Reserved. */
+/* WIDCOMM Bluetooth Core. Proprietary and confidential. */
+/* */
+/****************************************************************************/
+
+#ifndef HIDD_INT_H
+#define HIDD_INT_H
+#include "hidd_api.h"
+#include "hid_conn.h"
+#include "l2c_api.h"
+
+/* Define the possible events of the HID Device state machine.
+*/
+enum
+{
+ HOST_CONN_OPEN,
+ HOST_CONN_CLOSE,
+ HOST_CONN_LOST,
+ HOST_CONN_FAIL,
+ HID_API_CONNECT,
+ HID_API_DISCONNECT,
+ HID_API_SEND_DATA
+};
+
+/* Define the possible states of the HID Device.
+*/
+enum
+{
+ HID_DEV_ST_NO_CONN,
+ HID_DEV_ST_CONNECTING,
+ HID_DEV_ST_CONNECTED,
+ HID_DEV_ST_DISC_ING
+};
+
+/* To remember the power mode and setting */
+typedef struct curr_pm_setting
+{
+ UINT8 mode;
+ UINT16 interval;
+} tHID_DEV_PM_CURR;
+
+/* Define the HID management control block.
+*/
+typedef struct hid_control_block
+{
+ BD_ADDR host_addr; /* BD-Addr of the host device */
+ BOOLEAN host_known; /* Mode */
+ BOOLEAN virtual_cable;/* If the device is to behave as virtual cable */
+ UINT8 dev_state; /* Device state if in HOST-KNOWN mode */
+ UINT8 conn_tries; /* Remembers to the number of connection attempts while CONNECTING */
+ UINT8 sec_mask;
+ UINT16 get_rep_buf_sz;
+ tHID_CONN conn; /* L2CAP channel info */
+
+#if HID_DEV_PM_INCLUDED == TRUE
+ TIMER_LIST_ENT idle_tle; /* Timer used for inactivity timing */
+ tHID_DEV_PM_PWR_MD pm_params[3]; /* Power management parameters for the three possible states */
+ tHID_DEV_PM_CURR curr_pm; /* Current power mode */
+ BOOLEAN pm_ctrl_busy;/* A power mode transition is going on */
+ UINT8 conn_substate;
+ tHID_DEV_PM_PWR_MD final_pm;/* To remember the power mode while a power mode change is ongoing */
+#endif
+
+ BOOLEAN use_qos_flg; /* Qos information provided by application or not */
+ BOOLEAN unplug_on; /* Virtual unplug has been sent or received */
+ tHID_DEV_QOS_INFO qos_info; /* Storage for QoS provided by application */
+
+ tHID_DEV_CALLBACK *callback; /* Application callbacks */
+ tL2CAP_CFG_INFO l2cap_ctrl_cfg; /* Configuration data for control channel */
+ tL2CAP_CFG_INFO l2cap_int_cfg; /* Configuration data for interrupt channel */
+ BOOLEAN reg_flag;
+ UINT8 trace_level;
+} tHIDDEV_CB;
+
+typedef struct snd_data_params
+{
+ BOOLEAN ctrl_ch; /* TRUE if control channel, FALSE if interrupt */
+ UINT8 trans_type; /* Transaction type */
+ UINT8 param; /* Second byte after trans type */
+ BT_HDR *buf ; /* Data that comes after param */
+} tHID_SND_DATA_PARAMS; /* Is defined for hidd_conn_snd_data */
+
+/* HID management function prototype
+*/
+typedef tHID_STATUS (tHIDD_MGMT_EVT_HDLR) (UINT8, void *);
+
+/* HID Globals
+*/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/******************************************************************************
+** Main Control Block
+*******************************************************************************/
+#if HID_DYNAMIC_MEMORY == FALSE
+HID_API extern tHIDDEV_CB hd_cb;
+#else
+HID_API extern tHIDDEV_CB *hidd_cb_ptr;
+#define hd_cb (*hidd_cb_ptr)
+#endif
+
+extern tHID_STATUS hidd_conn_reg (void);
+extern void hidd_conn_dereg( void );
+extern tHID_STATUS hidd_conn_initiate (void);
+extern void hidd_conn_disconnect (void);
+extern tHID_STATUS hidd_conn_snd_data (tHID_SND_DATA_PARAMS *p_data);
+
+extern tHID_STATUS hidd_mgmt_process_evt( UINT8 event, void *data );
+extern void hidd_proc_repage_timeout (TIMER_LIST_ENT *p_tle);
+
+#if HID_DEV_PM_INCLUDED == TRUE
+extern tHID_STATUS hidd_pm_start( void ) ;
+extern tHID_STATUS hidd_pm_stop( void );
+extern tHID_STATUS hidd_pm_activity_evt( void );
+extern tHID_STATUS hidd_pm_suspend_evt( void );
+extern tHID_STATUS hidd_pm_unsuspend_evt( void );
+extern void hidd_pm_init( void );
+extern BOOLEAN hidd_pm_set_power_mode( tHID_DEV_PM_PWR_MD *pm) ;
+
+extern void hidd_pm_proc_mode_change( UINT8 hci_status, UINT8 mode, UINT16 interval );
+#endif /* HID_DEV_PM_INCLUDED == TRUE */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/stack/hid/hidd_mgmt.c b/stack/hid/hidd_mgmt.c
new file mode 100644
index 0000000..819dd11
--- /dev/null
+++ b/stack/hid/hidd_mgmt.c
@@ -0,0 +1,287 @@
+/*****************************************************************************/
+/* */
+/* Name: hidd_mgmt.c */
+/* */
+/* Description: this file contains the HID Device Management logic */
+/* */
+/* NOTE: In the interest of keeping code small, there is an */
+/* inherent assumption that L2CAP always runs a timer, */
+/* and so the HID management never needs a timer on L2CAP */
+/* actions like connect and disconnect. */
+/* */
+/* */
+/* Copyright (c) 2002-2004, WIDCOMM Inc., All Rights Reserved. */
+/* WIDCOMM Bluetooth Core. Proprietary and confidential. */
+/*****************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "gki.h"
+#include "bt_types.h"
+#include "hidd_api.h"
+#include "hiddefs.h"
+#include "hidd_int.h"
+#include "btu.h"
+#include "btm_api.h"
+
+
+/********************************************************************************/
+/* L O C A L F U N C T I O N P R O T O T Y P E S */
+/********************************************************************************/
+static tHID_STATUS hidd_no_conn_proc_evt( UINT8 event, void *p_data );
+static tHID_STATUS hidd_connecting_proc_evt( UINT8 event, void *p_data );
+static tHID_STATUS hidd_connected_proc_evt( UINT8 event, void *p_data );
+static tHID_STATUS hidd_disc_ing_proc_evt( UINT8 event, void *p_data );
+
+
+/* State machine jump table.
+*/
+tHIDD_MGMT_EVT_HDLR * const hidd_sm_proc_evt[] =
+{
+ hidd_no_conn_proc_evt,
+ hidd_connecting_proc_evt,
+ hidd_connected_proc_evt,
+ hidd_disc_ing_proc_evt
+};
+
+/* Main HID control block */
+#if HID_DYNAMIC_MEMORY == FALSE
+tHIDDEV_CB hd_cb;
+#endif
+
+/*******************************************************************************
+**
+** Function hidd_mgmt_process_evt
+**
+** Description This function is called by other modules to report an event
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+tHID_STATUS hidd_mgmt_process_evt( UINT8 event, void *p_data )
+{
+ HIDD_TRACE_DEBUG3("hidd_mgmt_process_evt known: %d, s:%d, e:%d",
+ hd_cb.host_known, hd_cb.dev_state, event);
+ if( hd_cb.host_known )
+ {
+ return ((hidd_sm_proc_evt[hd_cb.dev_state]) (event, p_data)); /* Event is passed to main State Machine */
+ }
+
+ if( event == HOST_CONN_OPEN )
+ {
+ hd_cb.host_known = TRUE;
+ memcpy( hd_cb.host_addr, (BD_ADDR *) p_data, BD_ADDR_LEN ) ;
+ hd_cb.dev_state = HID_DEV_ST_CONNECTED ;
+ /* Call-Back the Application with this information */
+ hd_cb.callback(HID_DEV_EVT_OPEN, 0, (tHID_DEV_CBACK_DATA *) hd_cb.host_addr ) ;
+ return( HID_SUCCESS );
+ }
+
+ return( HID_ERR_HOST_UNKNOWN );
+}
+
+/*******************************************************************************
+**
+** Function hidd_no_conn_proc_evt
+**
+** Description NO-CONN state event handler.
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+static tHID_STATUS hidd_no_conn_proc_evt( UINT8 event, void *p_data )
+{
+ tHID_STATUS st = HID_SUCCESS;
+
+ switch( event )
+ {
+ case HOST_CONN_OPEN:
+ hd_cb.dev_state = HID_DEV_ST_CONNECTED ;
+ hd_cb.callback(HID_DEV_EVT_OPEN, 0, (tHID_DEV_CBACK_DATA *) hd_cb.host_addr ) ;
+ break;
+ case HID_API_CONNECT:
+ hd_cb.conn_tries = 1;
+ hd_cb.dev_state = HID_DEV_ST_CONNECTING ;
+ if( (st = hidd_conn_initiate()) != HID_SUCCESS )
+ {
+#if HID_DEV_MAX_CONN_RETRY > 0
+ btu_start_timer (&(hd_cb.conn.timer_entry), BTU_TTYPE_USER_FUNC, HID_DEV_REPAGE_WIN);
+ return HID_SUCCESS;
+#else
+ hd_cb.dev_state = HID_DEV_ST_NO_CONN ;
+#endif
+ }
+ break;
+ default:
+ st = HID_ERR_NO_CONNECTION;
+ }
+
+ return st;
+}
+
+/*******************************************************************************
+**
+** Function hidd_proc_repage_timeout
+**
+** Description function to handle timeout.
+**
+** Returns void
+**
+*******************************************************************************/
+void hidd_proc_repage_timeout (TIMER_LIST_ENT *p_tle)
+{
+ HIDD_TRACE_DEBUG0 ("hidd_proc_repage_timeout");
+ hd_cb.conn_tries++;
+ if( hidd_conn_initiate() != HID_SUCCESS )
+ {
+ if( hd_cb.conn_tries > HID_DEV_MAX_CONN_RETRY )
+ {
+ hd_cb.dev_state = HID_DEV_ST_NO_CONN ;
+ hd_cb.callback(HID_DEV_EVT_CLOSE, 0, NULL );
+ }
+ else
+ btu_start_timer (&(hd_cb.conn.timer_entry), BTU_TTYPE_USER_FUNC, HID_DEV_REPAGE_WIN);
+ }
+ else
+ hd_cb.callback( HID_DEV_EVT_RETRYING, hd_cb.conn_tries, NULL );
+}
+
+/*******************************************************************************
+**
+** Function hidd_connecting_proc_evt
+**
+** Description CONNECTING state event handler
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+static tHID_STATUS hidd_connecting_proc_evt( UINT8 event, void *p_data )
+{
+ switch( event )
+ {
+ case HOST_CONN_OPEN:
+ hd_cb.dev_state = HID_DEV_ST_CONNECTED ;
+ hd_cb.callback(HID_DEV_EVT_OPEN, 0, (tHID_DEV_CBACK_DATA *) hd_cb.host_addr ) ;
+ break;
+
+ case HOST_CONN_FAIL:
+ if( hd_cb.conn_tries > HID_DEV_MAX_CONN_RETRY )
+ {
+ UINT16 reason = *( (UINT16 *) p_data);
+
+ hd_cb.dev_state = HID_DEV_ST_NO_CONN;
+ hd_cb.callback(HID_DEV_EVT_CLOSE, reason, NULL );
+ }
+#if HID_DEV_MAX_CONN_RETRY > 0
+ else
+ {
+ btu_start_timer (&(hd_cb.conn.timer_entry), BTU_TTYPE_USER_FUNC, HID_DEV_REPAGE_WIN);
+ }
+#endif
+ break;
+
+ case HOST_CONN_CLOSE:
+ case HOST_CONN_LOST:
+ hd_cb.dev_state = HID_DEV_ST_NO_CONN;
+ hd_cb.callback(HID_DEV_EVT_CLOSE, *((UINT16 *) p_data), NULL );
+ break;
+
+ case HID_API_DISCONNECT:
+ hd_cb.dev_state = HID_DEV_ST_NO_CONN ;
+ btu_stop_timer (&(hd_cb.conn.timer_entry));
+ hidd_conn_disconnect();
+ break;
+
+ default:
+ return( HID_ERR_CONN_IN_PROCESS ) ;
+ }
+
+ return (HID_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function hidd_mgmt_conn_closed
+**
+** Description Called when l2cap channels have been released
+**
+** Returns void
+**
+*******************************************************************************/
+void hidd_mgmt_conn_closed( UINT16 reason )
+{
+ if( hd_cb.unplug_on )
+ {
+ hd_cb.host_known = FALSE; /* This allows the device to accept connection from other hosts */
+ }
+
+ hd_cb.dev_state = HID_DEV_ST_NO_CONN;
+ hd_cb.callback(HID_DEV_EVT_CLOSE, reason, NULL );
+}
+
+/*******************************************************************************
+**
+** Function hidd_connected_proc_evt
+**
+** Description CONNECTED state event handler
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+static tHID_STATUS hidd_connected_proc_evt( UINT8 event, void *p_data )
+{
+ switch( event )
+ {
+ case HOST_CONN_LOST:
+#if HID_DEV_RECONN_INITIATE == TRUE
+ hd_cb.dev_state = HID_DEV_ST_CONNECTING ;
+ hd_cb.conn_tries = 0;
+ btu_start_timer (&(hd_cb.conn.timer_entry), BTU_TTYPE_USER_FUNC, HID_DEV_REPAGE_WIN);
+#else
+ hidd_mgmt_conn_closed( *((UINT16 *) p_data) ) ;
+#endif
+ break;
+ case HOST_CONN_CLOSE:
+ hidd_mgmt_conn_closed( *((UINT16 *) p_data) ) ;
+ break;
+ case HID_API_DISCONNECT:
+ hd_cb.dev_state = HID_DEV_ST_DISC_ING ;
+ hidd_conn_disconnect();
+ break;
+ case HID_API_SEND_DATA: /*Send Input reports, handshake or virtual-unplug */
+ return hidd_conn_snd_data( (tHID_SND_DATA_PARAMS *) p_data );
+ default:
+ return( HID_ERR_ALREADY_CONN ) ;
+ }
+
+ return( HID_SUCCESS );
+}
+
+/*******************************************************************************
+**
+** Function hidd_disc_ing_proc_evt
+**
+** Description DISCONNECTING state event handler
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+static tHID_STATUS hidd_disc_ing_proc_evt( UINT8 event, void *p_data )
+{
+ switch( event )
+ {
+ case HOST_CONN_LOST:
+ case HOST_CONN_FAIL:
+ case HOST_CONN_CLOSE:
+ hidd_mgmt_conn_closed( *((UINT16 *) p_data) ) ;
+ break;
+ default:
+ return( HID_ERR_DISCONNECTING ) ;
+ }
+
+ return( HID_SUCCESS );
+}
+
+
diff --git a/stack/hid/hidd_pm.c b/stack/hid/hidd_pm.c
new file mode 100644
index 0000000..ff3cc22
--- /dev/null
+++ b/stack/hid/hidd_pm.c
@@ -0,0 +1,288 @@
+/*****************************************************************************/
+/* */
+/* Name: hidd_pm.c */
+/* */
+/* Description: this file contains the HID Device Power Management logic */
+/* */
+/* */
+/* Copyright (c) 2002-2004, WIDCOMM Inc., All Rights Reserved. */
+/* WIDCOMM Bluetooth Core. Proprietary and confidential. */
+/*****************************************************************************/
+
+
+#include "gki.h"
+#include "bt_types.h"
+#include "hiddefs.h"
+#include "btm_api.h"
+#include "string.h"
+
+#include "hiddefs.h"
+
+#include "hidd_api.h"
+#include "hidd_int.h"
+#include "btu.h"
+
+#if HID_DEV_PM_INCLUDED == TRUE
+
+/*******************************************************************************
+**
+** Function hidd_pm_init
+**
+** Description This function is called when connection is established. It
+** initializes the control block for power management.
+**
+** Returns void
+**
+*******************************************************************************/
+
+static const tHID_DEV_PM_PWR_MD pwr_modes[] =
+{
+ HID_DEV_BUSY_MODE_PARAMS,
+ HID_DEV_IDLE_MODE_PARAMS,
+ HID_DEV_SUSP_MODE_PARAMS
+};
+
+void hidd_pm_init( void )
+{
+ int i;
+
+ hd_cb.curr_pm.mode = HCI_MODE_ACTIVE ;
+ hd_cb.final_pm.mode = 0xff;
+
+ for( i=0; i<3; i++ )
+ memcpy( &hd_cb.pm_params[i], &pwr_modes[i], sizeof( tHID_DEV_PM_PWR_MD ) ) ;
+
+ hd_cb.pm_ctrl_busy = FALSE;
+}
+
+/*******************************************************************************
+**
+** Function hidd_pm_set_now
+**
+** Description This drives the BTM for power management settings.
+**
+** Returns TRUE if Success, FALSE otherwise
+**
+*******************************************************************************/
+BOOLEAN hidd_pm_set_now( tHID_DEV_PM_PWR_MD *p_req_mode)
+{
+ tHID_DEV_PM_PWR_MD act_pm = { 0, 0, 0, 0, HCI_MODE_ACTIVE } ;
+ UINT8 st = BTM_SUCCESS;
+
+ /* Do nothing if already in required state or already performing a pm function */
+ if( (hd_cb.pm_ctrl_busy) ||
+ ((p_req_mode->mode == hd_cb.curr_pm.mode) && ( (p_req_mode->mode == HCI_MODE_ACTIVE) ||
+ ((hd_cb.curr_pm.interval >= p_req_mode->min) && (hd_cb.curr_pm.interval <= p_req_mode->max)) )) )
+ {
+ hd_cb.final_pm.mode = 0xff;
+ return TRUE;
+ }
+
+ switch( p_req_mode->mode )
+ {
+ case HCI_MODE_ACTIVE:
+ if( hd_cb.curr_pm.mode == HCI_MODE_SNIFF )
+ {
+#if BTM_PWR_MGR_INCLUDED == TRUE
+ st = BTM_SetPowerMode (BTM_PM_SET_ONLY_ID, hd_cb.host_addr, (tBTM_PM_PWR_MD *) &act_pm);
+#else
+ st = BTM_CancelSniffMode (hd_cb.host_addr);
+#endif
+ hd_cb.pm_ctrl_busy = TRUE;
+ }
+ else if( hd_cb.curr_pm.mode == HCI_MODE_PARK )
+ {
+#if BTM_PWR_MGR_INCLUDED == TRUE
+ st = BTM_SetPowerMode (BTM_PM_SET_ONLY_ID, hd_cb.host_addr, (tBTM_PM_PWR_MD *) &act_pm);
+#else
+ st = BTM_CancelParkMode (hd_cb.host_addr);
+#endif
+ hd_cb.pm_ctrl_busy = TRUE;
+ }
+ break;
+
+ case HCI_MODE_SNIFF:
+ if( hd_cb.curr_pm.mode != HCI_MODE_ACTIVE ) /* Transition through active state required */
+ hidd_pm_set_now (&act_pm);
+ else
+ {
+#if BTM_PWR_MGR_INCLUDED == TRUE
+ st = BTM_SetPowerMode (BTM_PM_SET_ONLY_ID, hd_cb.host_addr, (tBTM_PM_PWR_MD *) p_req_mode);
+#else
+ st = BTM_SetSniffMode (hd_cb.host_addr, p_req_mode->min, p_req_mode->max, p_req_mode->attempt, p_req_mode->timeout);
+#endif
+ hd_cb.pm_ctrl_busy = TRUE;
+ }
+ break;
+
+ case HCI_MODE_PARK:
+ if( hd_cb.curr_pm.mode != HCI_MODE_ACTIVE ) /* Transition through active state required */
+ hidd_pm_set_now (&act_pm);
+ else
+ {
+#if BTM_PWR_MGR_INCLUDED == TRUE
+ st = BTM_SetPowerMode (BTM_PM_SET_ONLY_ID, hd_cb.host_addr, (tBTM_PM_PWR_MD *) p_req_mode);
+#else
+ st = BTM_SetParkMode (hd_cb.host_addr, p_req_mode->min, p_req_mode->max);
+#endif
+ hd_cb.pm_ctrl_busy = TRUE;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if( st == BTM_SUCCESS || st == BTM_CMD_STARTED )
+ return TRUE;
+ else
+ {
+ st += HCI_ERR_MAX_ERR ;
+ if( hd_cb.callback )
+ hd_cb.callback( HID_DEV_EVT_PM_FAILED, hd_cb.conn_substate, (tHID_DEV_CBACK_DATA *) &st ) ;
+ return FALSE;
+ }
+}
+
+/*******************************************************************************
+**
+** Function hidd_pm_set_power_mode
+**
+** Description This stores the power management setting and calls fn to set
+** the power.
+**
+** Returns TRUE if Success, FALSE otherwise
+**
+*******************************************************************************/
+BOOLEAN hidd_pm_set_power_mode( tHID_DEV_PM_PWR_MD *p_req_mode)
+{
+ memcpy( &hd_cb.final_pm, p_req_mode, sizeof( tHID_DEV_PM_PWR_MD ) ) ;
+ return hidd_pm_set_now( p_req_mode ) ;
+}
+
+
+/*******************************************************************************
+**
+** Function hidd_pm_proc_mode_change
+**
+** Description This is the callback function, when power mode changes.
+**
+** Returns void
+**
+*******************************************************************************/
+void hidd_pm_proc_mode_change( UINT8 hci_status, UINT8 mode, UINT16 interval )
+{
+ if (!hd_cb.reg_flag )
+ return;
+
+ hd_cb.pm_ctrl_busy = FALSE;
+
+ if( hci_status != HCI_SUCCESS )
+ {
+ if( hd_cb.callback )
+ hd_cb.callback( HID_DEV_EVT_PM_FAILED, hd_cb.conn_substate, (tHID_DEV_CBACK_DATA *) &hci_status ) ;
+ }
+ else
+ {
+ hd_cb.curr_pm.mode = mode;
+ hd_cb.curr_pm.interval = interval;
+
+ if( hd_cb.final_pm.mode != 0xff )
+ {
+ /* If we haven't reached the final power mode, set it now */
+ if( (hd_cb.final_pm.mode != hd_cb.curr_pm.mode) ||
+ ( (hd_cb.final_pm.mode != HCI_MODE_ACTIVE) &&
+ ((hd_cb.curr_pm.interval < hd_cb.final_pm.min) || (hd_cb.curr_pm.interval > hd_cb.final_pm.max))
+ ) )
+ {
+ hidd_pm_set_now( &(hd_cb.final_pm) ) ;
+ }
+ else
+ hd_cb.final_pm.mode = 0xff;
+ }
+ else
+ {
+ if( hd_cb.curr_pm.mode == HCI_MODE_ACTIVE )
+ hidd_pm_start();
+ }
+
+ if( hd_cb.callback )
+ hd_cb.callback( HID_DEV_EVT_MODE_CHG, mode, (tHID_DEV_CBACK_DATA *) &interval) ;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function hidd_pm_inact_timeout
+**
+** Description Called when idle timer expires.
+**
+** Returns void
+**
+*******************************************************************************/
+void hidd_pm_inact_timeout (TIMER_LIST_ENT *p_tle)
+{
+ hidd_pm_set_power_mode ( &(hd_cb.pm_params[HID_DEV_IDLE_CONN_ST]));
+ hd_cb.conn_substate = HID_DEV_IDLE_CONN_ST;
+}
+
+/*******************************************************************************
+**
+** Function hidd_pm_start
+**
+** Description Starts the power management function in a given state.
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+tHID_STATUS hidd_pm_start( void )
+{
+ hidd_pm_set_power_mode ( &(hd_cb.pm_params[HID_DEV_BUSY_CONN_ST]) );
+
+ hd_cb.conn_substate = HID_DEV_BUSY_CONN_ST;
+
+ hd_cb.idle_tle.param = (UINT32) hidd_pm_inact_timeout;
+ btu_start_timer (&hd_cb.idle_tle, BTU_TTYPE_USER_FUNC, HID_DEV_INACT_TIMEOUT);
+
+ return( HID_SUCCESS );
+}
+
+/*******************************************************************************
+**
+** Function hidd_pm_stop
+**
+** Description Stops the idle timer.
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+tHID_STATUS hidd_pm_stop( void )
+{
+ tHID_DEV_PM_PWR_MD p_md = { 0, 0, 0, 0, HCI_MODE_ACTIVE };
+
+ hidd_pm_set_power_mode( &p_md );
+ btu_stop_timer( &hd_cb.idle_tle ) ;
+ return( HID_SUCCESS );
+}
+
+
+/*******************************************************************************
+**
+** Function hidd_pm_suspend_evt
+**
+** Description Called when host suspends the device.
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+tHID_STATUS hidd_pm_suspend_evt( void )
+{
+ if( hd_cb.conn_substate == HID_DEV_BUSY_CONN_ST )
+ btu_stop_timer( &hd_cb.idle_tle ) ;
+
+ hidd_pm_set_power_mode ( &(hd_cb.pm_params[HID_DEV_SUSP_CONN_ST]) );
+ hd_cb.conn_substate = HID_DEV_SUSP_CONN_ST;
+ return( HID_SUCCESS );
+}
+#endif /* HID_DEV_PM_INCLUDED == TRUE */
diff --git a/stack/hid/hidh_api.c b/stack/hid/hidh_api.c
new file mode 100644
index 0000000..268b405
--- /dev/null
+++ b/stack/hid/hidh_api.c
@@ -0,0 +1,534 @@
+/*****************************************************************************/
+/* */
+/* Name: hidh_api.c */
+/* */
+/* Description: this file contains the HID HOST API entry points */
+/* */
+/* */
+/* */
+/* Copyright (c) 2002-2010, Broadcom Corp., All Rights Reserved. */
+/* Broadcom Bluetooth Core. Proprietary and confidential. */
+/*****************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "gki.h"
+#include "bt_types.h"
+#include "hiddefs.h"
+#include "hidh_api.h"
+#include "hidh_int.h"
+#include "btm_api.h"
+#include "btu.h"
+
+#if HID_DYNAMIC_MEMORY == FALSE
+tHID_HOST_CTB hh_cb;
+#endif
+
+static void hidh_search_callback (UINT16 sdp_result);
+
+/*******************************************************************************
+**
+** Function HID_HostGetSDPRecord
+**
+** Description This function reads the device SDP record
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+tHID_STATUS HID_HostGetSDPRecord ( BD_ADDR addr, tSDP_DISCOVERY_DB *p_db, UINT32 db_len,
+ tHID_HOST_SDP_CALLBACK *sdp_cback )
+{
+ tSDP_UUID uuid_list;
+
+ if( hh_cb.sdp_busy )
+ return HID_ERR_SDP_BUSY;
+
+ uuid_list.len = 2;
+ uuid_list.uu.uuid16 = UUID_SERVCLASS_HUMAN_INTERFACE;
+
+ hh_cb.p_sdp_db = p_db;
+ SDP_InitDiscoveryDb (p_db, db_len, 1, &uuid_list, 0, NULL);
+
+ if (SDP_ServiceSearchRequest (addr, p_db, hidh_search_callback))
+ {
+ hh_cb.sdp_cback = sdp_cback ;
+ hh_cb.sdp_busy = TRUE;
+ return HID_SUCCESS;
+ }
+ else
+ return HID_ERR_NO_RESOURCES;
+}
+
+void hidh_get_str_attr( tSDP_DISC_REC *p_rec, UINT16 attr_id, UINT16 max_len, char *str )
+{
+ tSDP_DISC_ATTR *p_attr;
+ UINT16 name_len;
+
+ if ((p_attr = SDP_FindAttributeInRec(p_rec, attr_id)) != NULL)
+ {
+ if((name_len = SDP_DISC_ATTR_LEN(p_attr->attr_len_type)) < max_len )
+ {
+ memcpy( str, (char *) p_attr->attr_value.v.array, name_len );
+ str[name_len] = '\0';
+ }
+ else
+ {
+ memcpy( str, (char *) p_attr->attr_value.v.array, max_len-1 );
+ str[max_len] = '\0';
+ }
+ }
+ else
+ str[0] = '\0';
+}
+
+
+static void hidh_search_callback (UINT16 sdp_result)
+{
+ tSDP_DISCOVERY_DB *p_db = hh_cb.p_sdp_db;
+ tSDP_DISC_REC *p_rec;
+ tSDP_DISC_ATTR *p_attr, *p_subattr1, *p_subattr2, *p_repdesc;
+ tBT_UUID hid_uuid;
+ tHID_DEV_SDP_INFO *p_nvi = &hh_cb.sdp_rec;
+ UINT16 attr_mask = 0;
+
+ hid_uuid.len = LEN_UUID_16;
+ hid_uuid.uu.uuid16 = UUID_SERVCLASS_HUMAN_INTERFACE;
+
+ hh_cb.sdp_busy = FALSE;
+
+ if (sdp_result != SDP_SUCCESS)
+ {
+ hh_cb.sdp_cback(sdp_result, 0, NULL);
+ return;
+ }
+
+ if ((p_rec = SDP_FindServiceUUIDInDb (p_db, &hid_uuid, NULL)) == NULL)
+ {
+ hh_cb.sdp_cback(HID_SDP_NO_SERV_UUID, 0, NULL);
+ return;
+ }
+
+ memset (&hh_cb.sdp_rec, 0, sizeof( tHID_DEV_SDP_INFO ));
+
+ /* First, verify the mandatory fields we care about */
+ if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_DESCRIPTOR_LIST)) == NULL)
+ || (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) != DATA_ELE_SEQ_DESC_TYPE)
+ || ((p_subattr1 = p_attr->attr_value.v.p_sub_attr) == NULL)
+ || (SDP_DISC_ATTR_TYPE(p_subattr1->attr_len_type) != DATA_ELE_SEQ_DESC_TYPE)
+ || ((p_subattr2 = p_subattr1->attr_value.v.p_sub_attr) == NULL)
+ || ((p_repdesc = p_subattr2->p_next_attr) == NULL)
+ || (SDP_DISC_ATTR_TYPE(p_repdesc->attr_len_type) != TEXT_STR_DESC_TYPE))
+ {
+ hh_cb.sdp_cback(HID_SDP_MANDATORY_MISSING, 0, NULL);
+ return;
+ }
+
+ if ((p_nvi->dscp_info.dl_len = SDP_DISC_ATTR_LEN(p_repdesc->attr_len_type)) != 0)
+ p_nvi->dscp_info.dsc_list = (UINT8 *) &p_repdesc->attr_value;
+
+ if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_VIRTUAL_CABLE)) != NULL) &&
+ (p_attr->attr_value.v.u8) )
+ {
+ attr_mask |= HID_VIRTUAL_CABLE;
+ }
+
+ if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_RECONNECT_INITIATE)) != NULL) &&
+ (p_attr->attr_value.v.u8) )
+ {
+ attr_mask |= HID_RECONN_INIT;
+ }
+
+ if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_NORMALLY_CONNECTABLE)) != NULL) &&
+ (p_attr->attr_value.v.u8) )
+ {
+ attr_mask |= HID_NORMALLY_CONNECTABLE;
+ }
+
+ if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_SDP_DISABLE)) != NULL)&&
+ (p_attr->attr_value.v.u8) )
+ {
+ attr_mask |= HID_SDP_DISABLE;
+ }
+
+ if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_BATTERY_POWER)) != NULL)&&
+ (p_attr->attr_value.v.u8) )
+ {
+ attr_mask |= HID_BATTERY_POWER;
+ }
+
+ if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_REMOTE_WAKE)) != NULL)&&
+ (p_attr->attr_value.v.u8) )
+ {
+ attr_mask |= HID_REMOTE_WAKE;
+ }
+
+ hidh_get_str_attr( p_rec, ATTR_ID_SERVICE_NAME, HID_MAX_SVC_NAME_LEN, p_nvi->svc_name );
+ hidh_get_str_attr( p_rec, ATTR_ID_SERVICE_DESCRIPTION, HID_MAX_SVC_DESCR_LEN, p_nvi->svc_descr );
+ hidh_get_str_attr( p_rec, ATTR_ID_PROVIDER_NAME, HID_MAX_PROV_NAME_LEN, p_nvi->prov_name );
+
+ if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_DEVICE_RELNUM)) != NULL))
+ {
+ p_nvi->rel_num = p_attr->attr_value.v.u16;
+ }
+
+ if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_COUNTRY_CODE)) != NULL))
+ {
+ p_nvi->ctry_code = p_attr->attr_value.v.u8;
+ }
+
+ if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_DEVICE_SUBCLASS)) != NULL))
+ {
+ p_nvi->sub_class = p_attr->attr_value.v.u8;
+ }
+
+ if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_PARSER_VERSION)) != NULL))
+ {
+ p_nvi->hpars_ver = p_attr->attr_value.v.u16;
+ }
+
+ if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_LINK_SUPERVISION_TO)) != NULL))
+ {
+ attr_mask |= HID_SUP_TOUT_AVLBL;
+ p_nvi->sup_timeout = p_attr->attr_value.v.u16;
+ }
+
+ if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_SSR_HOST_MAX_LAT)) != NULL))
+ {
+ attr_mask |= HID_SSR_MAX_LATENCY;
+ p_nvi->ssr_max_latency = p_attr->attr_value.v.u16;
+ }
+ else
+ p_nvi->ssr_max_latency = HID_SSR_PARAM_INVALID;
+
+ if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_SSR_HOST_MIN_TOUT)) != NULL))
+ {
+ attr_mask |= HID_SSR_MIN_TOUT;
+ p_nvi->ssr_min_tout = p_attr->attr_value.v.u16;
+ }
+ else
+ p_nvi->ssr_max_latency = HID_SSR_PARAM_INVALID;
+
+ hh_cb.sdp_rec.p_sdp_layer_rec = p_rec;
+ hh_cb.sdp_cback(SDP_SUCCESS, attr_mask, &hh_cb.sdp_rec);
+}
+
+
+/*******************************************************************************
+**
+** Function HID_HostInit
+**
+** Description This function initializes the control block and trace variable
+**
+** Returns void
+**
+*******************************************************************************/
+void HID_HostInit (void)
+{
+ memset(&hh_cb, 0, sizeof(tHID_HOST_CTB));
+
+#if defined(HID_INITIAL_TRACE_LEVEL)
+ hh_cb.trace_level = HID_INITIAL_TRACE_LEVEL;
+#else
+ hh_cb.trace_level = BT_TRACE_LEVEL_NONE;
+#endif
+}
+
+/*******************************************************************************
+**
+** Function HID_HostSetTraceLevel
+**
+** Description This function sets the trace level for HID Host. If called with
+** a value of 0xFF, it simply reads the current trace level.
+**
+** Returns the new (current) trace level
+**
+*******************************************************************************/
+UINT8 HID_HostSetTraceLevel (UINT8 new_level)
+{
+ if (new_level != 0xFF)
+ hh_cb.trace_level = new_level;
+
+ return (hh_cb.trace_level);
+}
+
+/*******************************************************************************
+**
+** Function HID_HostRegister
+**
+** Description This function registers HID-Host with lower layers
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+tHID_STATUS HID_HostRegister (tHID_HOST_DEV_CALLBACK *dev_cback)
+{
+ tHID_STATUS st;
+
+ if( hh_cb.reg_flag )
+ return HID_ERR_ALREADY_REGISTERED;
+
+ if( dev_cback == NULL )
+ return HID_ERR_INVALID_PARAM;
+
+ /* Register with L2CAP */
+ if( (st = hidh_conn_reg()) != HID_SUCCESS )
+ {
+ return st;
+ }
+
+ hh_cb.callback = dev_cback ;
+ hh_cb.reg_flag = TRUE;
+
+ return (HID_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function HID_HostDeregister
+**
+** Description This function is called when the host is about power down.
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+tHID_STATUS HID_HostDeregister(void)
+{
+ UINT8 i;
+
+ if( !hh_cb.reg_flag )
+ return (HID_ERR_NOT_REGISTERED);
+
+ for( i=0; i<HID_HOST_MAX_DEVICES; i++ )
+ {
+ HID_HostRemoveDev( i ) ;
+ }
+
+ hidh_conn_dereg();
+ hh_cb.reg_flag = FALSE;
+
+ return (HID_SUCCESS) ;
+}
+
+/*******************************************************************************
+**
+** Function HID_HostAddDev
+**
+** Description This is called so HID-host may manage this device.
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+tHID_STATUS HID_HostAddDev ( BD_ADDR addr, UINT16 attr_mask, UINT8 *handle )
+{
+ int i;
+ /* Find an entry for this device in hh_cb.devices array */
+
+ if( !hh_cb.reg_flag )
+ return (HID_ERR_NOT_REGISTERED);
+
+ for( i=0; i<HID_HOST_MAX_DEVICES; i++)
+ {
+ if((hh_cb.devices[i].in_use) &&
+ (!memcmp(addr, hh_cb.devices[i].addr, BD_ADDR_LEN)))
+ break;
+ }
+
+ if (i== HID_HOST_MAX_DEVICES )
+ {
+ for( i=0; i<HID_HOST_MAX_DEVICES; i++)
+ {
+ if( !hh_cb.devices[i].in_use)
+ break;
+ }
+ }
+
+ if( i==HID_HOST_MAX_DEVICES )
+ return HID_ERR_NO_RESOURCES;
+
+ if (!hh_cb.devices[i].in_use)
+ {
+ hh_cb.devices[i].in_use = TRUE;
+ memcpy( hh_cb.devices[i].addr, addr, sizeof( BD_ADDR ) ) ;
+ hh_cb.devices[i].state = HID_DEV_NO_CONN;
+ hh_cb.devices[i].conn_tries = 0 ;
+ }
+
+ hh_cb.devices[i].attr_mask = attr_mask;
+
+ *handle = i;
+
+ return (HID_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function HID_HostRemoveDev
+**
+** Description This removes the device from list devices that host has to manage.
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+tHID_STATUS HID_HostRemoveDev ( UINT8 dev_handle )
+{
+ if( !hh_cb.reg_flag )
+ return (HID_ERR_NOT_REGISTERED);
+
+ if( (dev_handle >= HID_HOST_MAX_DEVICES) || (!hh_cb.devices[dev_handle].in_use) )
+ return HID_ERR_INVALID_PARAM;
+
+ HID_HostCloseDev( dev_handle ) ;
+ hh_cb.devices[dev_handle].in_use = FALSE;
+ hh_cb.devices[dev_handle].conn.conn_state = HID_CONN_STATE_UNUSED;
+ hh_cb.devices[dev_handle].conn.ctrl_cid = hh_cb.devices[dev_handle].conn.intr_cid = 0;
+
+ return HID_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function HID_HostOpenDev
+**
+** Description This function is called when the user wants to initiate a
+** connection attempt to a device.
+**
+** Returns void
+**
+*******************************************************************************/
+tHID_STATUS HID_HostOpenDev ( UINT8 dev_handle )
+{
+ if( !hh_cb.reg_flag )
+ return (HID_ERR_NOT_REGISTERED);
+
+ if( (dev_handle >= HID_HOST_MAX_DEVICES) || (!hh_cb.devices[dev_handle].in_use) )
+ return HID_ERR_INVALID_PARAM;
+
+ if( hh_cb.devices[dev_handle].state != HID_DEV_NO_CONN )
+ return HID_ERR_ALREADY_CONN;
+
+ hh_cb.devices[dev_handle].conn_tries = 1;
+ return hidh_conn_initiate( dev_handle );
+}
+
+/*******************************************************************************
+**
+** Function HID_HostWriteDev
+**
+** Description This function is called when the host has a report to send.
+**
+** report_id: is only used on GET_REPORT transaction if is specified.
+** only valid when it's a non-zero value.
+**
+** Returns void
+**
+*******************************************************************************/
+tHID_STATUS HID_HostWriteDev( UINT8 dev_handle, UINT8 t_type,
+ UINT8 param, UINT16 data, UINT8 report_id, BT_HDR *pbuf )
+{
+ tHID_STATUS status = HID_SUCCESS;
+
+ if( !hh_cb.reg_flag )
+ {
+ HIDH_TRACE_ERROR0("HID_ERR_NOT_REGISTERED");
+ status = HID_ERR_NOT_REGISTERED;
+ }
+
+ if( (dev_handle >= HID_HOST_MAX_DEVICES) || (!hh_cb.devices[dev_handle].in_use) )
+ {
+ HIDH_TRACE_ERROR0("HID_ERR_INVALID_PARAM");
+ status = HID_ERR_INVALID_PARAM;
+ }
+
+ if( hh_cb.devices[dev_handle].state != HID_DEV_CONNECTED )
+ {
+ HIDH_TRACE_ERROR1("HID_ERR_NO_CONNECTION dev_handle %d", dev_handle);
+ status = HID_ERR_NO_CONNECTION;
+ }
+
+ if (status != HID_SUCCESS)
+ {
+ if (pbuf)
+ GKI_freebuf ((void *)pbuf);
+ }
+ else
+ status = hidh_conn_snd_data( dev_handle, t_type, param, data, report_id, pbuf ) ;
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function HID_HostCloseDev
+**
+** Description This function disconnects the device.
+**
+** Returns void
+**
+*******************************************************************************/
+tHID_STATUS HID_HostCloseDev( UINT8 dev_handle )
+{
+ if( !hh_cb.reg_flag )
+ return (HID_ERR_NOT_REGISTERED);
+
+ if( (dev_handle >= HID_HOST_MAX_DEVICES) || (!hh_cb.devices[dev_handle].in_use) )
+ return HID_ERR_INVALID_PARAM;
+
+ hh_cb.devices[dev_handle].conn_tries = HID_HOST_MAX_CONN_RETRY+1;
+ btu_stop_timer( &(hh_cb.devices[dev_handle].conn.timer_entry) ) ;
+
+ if( hh_cb.devices[dev_handle].state != HID_DEV_CONNECTED )
+ return HID_ERR_NO_CONNECTION;
+
+ hh_cb.devices[dev_handle].conn_tries = HID_HOST_MAX_CONN_RETRY+1;
+ return hidh_conn_disconnect( dev_handle );
+}
+
+tHID_STATUS HID_HostSetSecurityLevel( char serv_name[], UINT8 sec_lvl )
+{
+ if (!BTM_SetSecurityLevel (FALSE, serv_name, BTM_SEC_SERVICE_HID_SEC_CTRL,
+ sec_lvl, HID_PSM_CONTROL, BTM_SEC_PROTO_HID, HID_SEC_CHN))
+ {
+ HIDH_TRACE_ERROR0 ("Security Registration 1 failed");
+ return (HID_ERR_NO_RESOURCES);
+ }
+
+ if (!BTM_SetSecurityLevel (TRUE, serv_name, BTM_SEC_SERVICE_HID_SEC_CTRL,
+ sec_lvl, HID_PSM_CONTROL, BTM_SEC_PROTO_HID, HID_SEC_CHN))
+ {
+ HIDH_TRACE_ERROR0 ("Security Registration 2 failed");
+ return (HID_ERR_NO_RESOURCES);
+ }
+
+ if (!BTM_SetSecurityLevel (FALSE, serv_name, BTM_SEC_SERVICE_HID_NOSEC_CTRL,
+ BTM_SEC_NONE, HID_PSM_CONTROL, BTM_SEC_PROTO_HID, HID_NOSEC_CHN))
+ {
+ HIDH_TRACE_ERROR0 ("Security Registration 3 failed");
+ return (HID_ERR_NO_RESOURCES);
+ }
+
+ if (!BTM_SetSecurityLevel (TRUE, serv_name, BTM_SEC_SERVICE_HID_NOSEC_CTRL,
+ BTM_SEC_NONE, HID_PSM_CONTROL, BTM_SEC_PROTO_HID, HID_NOSEC_CHN))
+ {
+ HIDH_TRACE_ERROR0 ("Security Registration 4 failed");
+ return (HID_ERR_NO_RESOURCES);
+ }
+
+ if (!BTM_SetSecurityLevel (TRUE, serv_name, BTM_SEC_SERVICE_HID_INTR,
+ BTM_SEC_NONE, HID_PSM_INTERRUPT, BTM_SEC_PROTO_HID, 0))
+ {
+ HIDH_TRACE_ERROR0 ("Security Registration 5 failed");
+ return (HID_ERR_NO_RESOURCES);
+ }
+
+ if (!BTM_SetSecurityLevel (FALSE, serv_name, BTM_SEC_SERVICE_HID_INTR,
+ BTM_SEC_NONE, HID_PSM_INTERRUPT, BTM_SEC_PROTO_HID, 0))
+ {
+ HIDH_TRACE_ERROR0 ("Security Registration 6 failed");
+ return (HID_ERR_NO_RESOURCES);
+ }
+
+ return( HID_SUCCESS );
+}
diff --git a/stack/hid/hidh_conn.c b/stack/hid/hidh_conn.c
new file mode 100644
index 0000000..4744e10
--- /dev/null
+++ b/stack/hid/hidh_conn.c
@@ -0,0 +1,1021 @@
+/*****************************************************************************
+**
+** Name: hid_conn.c
+**
+** Description: this file contains the connection interface functions
+**
+**
+** Copyright (c) 2002-2010, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+******************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+
+#include "gki.h"
+#include "bt_types.h"
+
+#include "l2cdefs.h"
+#include "l2c_api.h"
+
+#include "btu.h"
+#include "btm_api.h"
+#include "btm_int.h"
+
+#include "hiddefs.h"
+
+#include "hidh_api.h"
+#include "hidh_int.h"
+
+static UINT8 find_conn_by_cid (UINT16 cid);
+static void hidh_conn_retry (UINT8 dhandle);
+
+/********************************************************************************/
+/* L O C A L F U N C T I O N P R O T O T Y P E S */
+/********************************************************************************/
+static void hidh_l2cif_connect_ind (BD_ADDR bd_addr, UINT16 l2cap_cid,
+ UINT16 psm, UINT8 l2cap_id);
+static void hidh_l2cif_connect_cfm (UINT16 l2cap_cid, UINT16 result);
+static void hidh_l2cif_config_ind (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg);
+static void hidh_l2cif_config_cfm (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg);
+static void hidh_l2cif_disconnect_ind (UINT16 l2cap_cid, BOOLEAN ack_needed);
+static void hidh_l2cif_data_ind (UINT16 l2cap_cid, BT_HDR *p_msg);
+static void hidh_l2cif_disconnect_cfm (UINT16 l2cap_cid, UINT16 result);
+static void hidh_l2cif_cong_ind (UINT16 l2cap_cid, BOOLEAN congested);
+
+static const tL2CAP_APPL_INFO hst_reg_info =
+{
+ hidh_l2cif_connect_ind,
+ hidh_l2cif_connect_cfm,
+ NULL,
+ hidh_l2cif_config_ind,
+ hidh_l2cif_config_cfm,
+ hidh_l2cif_disconnect_ind,
+ hidh_l2cif_disconnect_cfm,
+ NULL,
+ hidh_l2cif_data_ind,
+ hidh_l2cif_cong_ind,
+ NULL /* tL2CA_TX_COMPLETE_CB */
+};
+
+/*******************************************************************************
+**
+** Function hidh_l2cif_reg
+**
+** Description This function initializes the SDP unit.
+**
+** Returns void
+**
+*******************************************************************************/
+tHID_STATUS hidh_conn_reg (void)
+{
+ int xx;
+
+ /* Initialize the L2CAP configuration. We only care about MTU and flush */
+ memset(&hh_cb.l2cap_cfg, 0, sizeof(tL2CAP_CFG_INFO));
+
+ hh_cb.l2cap_cfg.mtu_present = TRUE;
+ hh_cb.l2cap_cfg.mtu = HID_HOST_MTU;
+ hh_cb.l2cap_cfg.flush_to_present = TRUE;
+ hh_cb.l2cap_cfg.flush_to = HID_HOST_FLUSH_TO;
+
+ /* Now, register with L2CAP */
+ if (!L2CA_Register (HID_PSM_CONTROL, (tL2CAP_APPL_INFO *) &hst_reg_info))
+ {
+ HIDH_TRACE_ERROR0 ("HID Control Registration failed");
+ return (HID_ERR_L2CAP_FAILED) ;
+ }
+ if (!L2CA_Register (HID_PSM_INTERRUPT, (tL2CAP_APPL_INFO *) &hst_reg_info))
+ {
+ L2CA_Deregister( HID_PSM_CONTROL ) ;
+ HIDH_TRACE_ERROR0 ("HID Interrupt Registration failed");
+ return (HID_ERR_L2CAP_FAILED) ;
+ }
+
+ for (xx = 0; xx < HID_HOST_MAX_DEVICES; xx++)
+ {
+ hh_cb.devices[xx].in_use = FALSE ;
+ hh_cb.devices[xx].conn.conn_state = HID_CONN_STATE_UNUSED;
+ }
+
+ return (HID_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function hidh_conn_disconnect
+**
+** Description This function disconnects a connection.
+**
+** Returns TRUE if disconnect started, FALSE if already disconnected
+**
+*******************************************************************************/
+tHID_STATUS hidh_conn_disconnect (UINT8 dhandle)
+{
+ tHID_CONN *p_hcon = &hh_cb.devices[dhandle].conn;
+
+ HIDH_TRACE_EVENT0 ("HID - disconnect");
+
+ if ((p_hcon->ctrl_cid != 0) || (p_hcon->intr_cid != 0))
+ {
+ p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING;
+
+ /* Disconnect both interrupt and control channels */
+ if (p_hcon->intr_cid)
+ L2CA_DisconnectReq (p_hcon->intr_cid);
+
+ if (p_hcon->ctrl_cid)
+ L2CA_DisconnectReq (p_hcon->ctrl_cid);
+ }
+ else
+ {
+ p_hcon->conn_state = HID_CONN_STATE_UNUSED;
+ }
+
+ return (HID_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function hidh_sec_check_complete_term
+**
+** Description HID security check complete callback function.
+**
+** Returns Send L2CA_ConnectRsp OK if secutiry check succeed; otherwise
+** send security block L2C connection response.
+**
+*******************************************************************************/
+void hidh_sec_check_complete_term (BD_ADDR bd_addr, void *p_ref_data, UINT8 res)
+{
+ tHID_HOST_DEV_CTB *p_dev= (tHID_HOST_DEV_CTB *) p_ref_data;
+
+ if( res == BTM_SUCCESS && p_dev->conn.conn_state == HID_CONN_STATE_SECURITY )
+ {
+ p_dev->conn.disc_reason = HID_SUCCESS; /* Authentication passed. Reset disc_reason (from HID_ERR_AUTH_FAILED) */
+
+ p_dev->conn.conn_state = HID_CONN_STATE_CONNECTING_INTR;
+
+ /* Send response to the L2CAP layer. */
+ L2CA_ConnectRsp (p_dev->addr, p_dev->conn.ctrl_id, p_dev->conn.ctrl_cid, L2CAP_CONN_OK, L2CAP_CONN_OK);
+
+ /* Send a Configuration Request. */
+ L2CA_ConfigReq (p_dev->conn.ctrl_cid, &hh_cb.l2cap_cfg);
+
+ }
+ /* security check fail */
+ else if (res != BTM_SUCCESS)
+ {
+ p_dev->conn.disc_reason = HID_ERR_AUTH_FAILED; /* Save reason for disconnecting */
+ p_dev->conn.conn_state = HID_CONN_STATE_UNUSED;
+ L2CA_ConnectRsp (p_dev->addr, p_dev->conn.ctrl_id, p_dev->conn.ctrl_cid, L2CAP_CONN_SECURITY_BLOCK, L2CAP_CONN_OK);
+ }
+}
+
+/*******************************************************************************
+**
+** Function hidh_l2cif_connect_ind
+**
+** Description This function handles an inbound connection indication
+** from L2CAP. This is the case where we are acting as a
+** server.
+**
+** Returns void
+**
+*******************************************************************************/
+static void hidh_l2cif_connect_ind (BD_ADDR bd_addr, UINT16 l2cap_cid, UINT16 psm, UINT8 l2cap_id)
+{
+ tHID_CONN *p_hcon;
+ BOOLEAN bAccept = TRUE;
+ int i;
+ tHID_HOST_DEV_CTB *p_dev;
+
+ HIDH_TRACE_EVENT2 ("HID - Rcvd L2CAP conn ind, PSM: 0x%04x CID 0x%x", psm, l2cap_cid);
+
+ for( i=0; i < HID_HOST_MAX_DEVICES; i++ )
+ {
+ if( hh_cb.devices[i].in_use && (!memcmp(bd_addr, hh_cb.devices[i].addr, sizeof(BD_ADDR))) )
+ break;
+ }
+
+ if (i >= HID_HOST_MAX_DEVICES)
+ {
+ L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_SECURITY_BLOCK, 0);
+ return;
+ }
+
+ p_hcon = &hh_cb.devices[i].conn;
+ p_dev = &hh_cb.devices[i];
+
+ /* Check we are in the correct state for this */
+ if (psm == HID_PSM_INTERRUPT)
+ {
+ if (p_hcon->ctrl_cid == 0)
+ {
+ HIDH_TRACE_WARNING0 ("HID - Rcvd INTR L2CAP conn ind, but no CTL channel");
+ bAccept = FALSE;
+ }
+ if (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR)
+ {
+ HIDH_TRACE_WARNING1 ("HID - Rcvd INTR L2CAP conn ind, wrong state: %d", p_hcon->conn_state);
+ bAccept = FALSE;
+ }
+ }
+ else /* CTRL channel */
+ {
+#if defined(HID_HOST_ACPT_NEW_CONN) && (HID_HOST_ACPT_NEW_CONN == TRUE)
+ p_hcon->ctrl_cid = p_hcon->intr_cid = 0;
+ p_hcon->conn_state = HID_CONN_STATE_UNUSED;
+#else
+ if (p_hcon->conn_state != HID_CONN_STATE_UNUSED)
+ {
+ HIDH_TRACE_WARNING1 ("HID - Rcvd CTL L2CAP conn ind, wrong state: %d", p_hcon->conn_state);
+ bAccept = FALSE;
+ }
+#endif
+ }
+
+ if (!bAccept)
+ {
+ L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_NO_RESOURCES, 0);
+ return;
+ }
+
+ if (psm == HID_PSM_CONTROL)
+ {
+ p_hcon->conn_flags = 0;
+ p_hcon->ctrl_cid = l2cap_cid;
+ p_hcon->ctrl_id = l2cap_id;
+ p_hcon->disc_reason = HID_L2CAP_CONN_FAIL; /* In case disconnection occurs before security is completed, then set CLOSE_EVT reason code to 'connection failure' */
+
+ p_hcon->conn_state = HID_CONN_STATE_SECURITY;
+ if(btm_sec_mx_access_request (p_dev->addr, HID_PSM_CONTROL,
+ FALSE, BTM_SEC_PROTO_HID,
+ (p_dev->attr_mask & HID_SEC_REQUIRED) ? HID_SEC_CHN : HID_NOSEC_CHN,
+ &hidh_sec_check_complete_term, p_dev) == BTM_CMD_STARTED)
+ {
+ L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_PENDING, L2CAP_CONN_OK);
+ }
+
+ return;
+ }
+
+ /* Transition to the next appropriate state, configuration */
+ p_hcon->conn_state = HID_CONN_STATE_CONFIG;
+ p_hcon->intr_cid = l2cap_cid;
+
+ /* Send response to the L2CAP layer. */
+ L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_OK, L2CAP_CONN_OK);
+
+ /* Send a Configuration Request. */
+ L2CA_ConfigReq (l2cap_cid, &hh_cb.l2cap_cfg);
+
+ HIDH_TRACE_EVENT2 ("HID - Rcvd L2CAP conn ind, sent config req, PSM: 0x%04x CID 0x%x", psm, l2cap_cid);
+}
+
+/*******************************************************************************
+**
+** Function hidh_proc_repage_timeout
+**
+** Description This function handles timeout (to page device).
+**
+** Returns void
+**
+*******************************************************************************/
+void hidh_proc_repage_timeout (TIMER_LIST_ENT *p_tle)
+{
+ hidh_conn_initiate( (UINT8) p_tle->param ) ;
+ hh_cb.devices[p_tle->param].conn_tries++;
+ hh_cb.callback( (UINT8) p_tle->param, HID_HDEV_EVT_RETRYING, hh_cb.devices[p_tle->param].conn_tries, NULL ) ;
+}
+
+/*******************************************************************************
+**
+** Function hidh_sec_check_complete_orig
+**
+** Description This function checks to see if security procedures are being
+** carried out or not..
+**
+** Returns void
+**
+*******************************************************************************/
+void hidh_sec_check_complete_orig (BD_ADDR bd_addr, void *p_ref_data, UINT8 res)
+{
+ tHID_HOST_DEV_CTB *p_dev = (tHID_HOST_DEV_CTB *) p_ref_data;
+ UINT8 dhandle;
+#if (HID_HOST_MAX_CONN_RETRY > 0)
+ UINT32 cb_res = HID_ERR_AUTH_FAILED;
+#endif
+ UINT32 reason;
+
+ dhandle = p_dev - &(hh_cb.devices[0]) ;
+ if( res == BTM_SUCCESS && p_dev->conn.conn_state == HID_CONN_STATE_SECURITY )
+ {
+ HIDH_TRACE_EVENT0 ("HID - Originator security pass.");
+ p_dev->conn.disc_reason = HID_SUCCESS; /* Authentication passed. Reset disc_reason (from HID_ERR_AUTH_FAILED) */
+
+ /* Check if L2CAP started the connection process for interrupt channel */
+ if ((p_dev->conn.intr_cid = L2CA_ConnectReq (HID_PSM_INTERRUPT, hh_cb.devices[dhandle].addr)) == 0)
+ {
+ HIDH_TRACE_WARNING0 ("HID - INTR Originate failed");
+ reason = HID_L2CAP_REQ_FAIL ;
+ hidh_conn_disconnect (dhandle);
+ hh_cb.callback( dhandle, HID_HDEV_EVT_CLOSE, reason, NULL ) ;
+ return;
+ }
+ else
+ {
+ /* Transition to the next appropriate state, waiting for connection confirm on control channel. */
+ p_dev->conn.conn_state = HID_CONN_STATE_CONNECTING_INTR;
+ }
+ }
+
+ if( res != BTM_SUCCESS && p_dev->conn.conn_state == HID_CONN_STATE_SECURITY )
+ {
+#if (HID_HOST_MAX_CONN_RETRY > 0)
+ if( res == BTM_DEVICE_TIMEOUT )
+ {
+ if( p_dev->conn_tries <= HID_HOST_MAX_CONN_RETRY )
+ {
+ hidh_conn_retry (dhandle);
+ return;
+ }
+ else
+ cb_res = HID_L2CAP_CONN_FAIL | HCI_ERR_PAGE_TIMEOUT ;
+ }
+#endif
+ p_dev->conn.disc_reason = HID_ERR_AUTH_FAILED; /* Save reason for disconnecting */
+ hidh_conn_disconnect(dhandle);
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function hidh_l2cif_connect_cfm
+**
+** Description This function handles the connect confirm events
+** from L2CAP. This is the case when we are acting as a
+** client and have sent a connect request.
+**
+** Returns void
+**
+*******************************************************************************/
+static void hidh_l2cif_connect_cfm (UINT16 l2cap_cid, UINT16 result)
+{
+ UINT8 dhandle;
+ tHID_CONN *p_hcon = NULL;
+ UINT32 reason;
+ tHID_HOST_DEV_CTB *p_dev = NULL;
+
+ /* Find CCB based on CID, and verify we are in a state to accept this message */
+ if( (dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES )
+ {
+ p_dev = &hh_cb.devices[dhandle];
+ p_hcon = &hh_cb.devices[dhandle].conn;
+ }
+
+ if ((p_hcon == NULL)
+ || (!(p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG))
+ || ((l2cap_cid == p_hcon->ctrl_cid) && (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_CTRL))
+ || ((l2cap_cid == p_hcon->intr_cid) && (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR)))
+ {
+ HIDH_TRACE_WARNING1 ("HID - Rcvd unexpected conn cnf, CID 0x%x ", l2cap_cid);
+ return;
+ }
+
+ if (result != L2CAP_CONN_OK)
+ {
+ if (l2cap_cid == p_hcon->ctrl_cid)
+ p_hcon->ctrl_cid = 0;
+ else
+ p_hcon->intr_cid = 0;
+
+ hidh_conn_disconnect(dhandle);
+
+#if (HID_HOST_MAX_CONN_RETRY > 0)
+ if( (hh_cb.devices[dhandle].conn_tries <= HID_HOST_MAX_CONN_RETRY) &&
+ (result == HCI_ERR_CONNECTION_TOUT || result == HCI_ERR_UNSPECIFIED ||
+ result == HCI_ERR_PAGE_TIMEOUT) )
+ {
+ hidh_conn_retry(dhandle);
+ }
+ else
+#endif
+ {
+ reason = HID_L2CAP_CONN_FAIL | (UINT32) result ;
+ hh_cb.callback( dhandle, HID_HDEV_EVT_CLOSE, reason, NULL ) ;
+ }
+ return;
+ }
+ /* receive Control Channel connect confirmation */
+ if (l2cap_cid == p_hcon->ctrl_cid)
+ {
+ /* check security requirement */
+ p_hcon->conn_state = HID_CONN_STATE_SECURITY;
+ p_hcon->disc_reason = HID_L2CAP_CONN_FAIL; /* In case disconnection occurs before security is completed, then set CLOSE_EVT reason code to "connection failure" */
+
+ btm_sec_mx_access_request (p_dev->addr, HID_PSM_CONTROL,
+ TRUE, BTM_SEC_PROTO_HID,
+ (p_dev->attr_mask & HID_SEC_REQUIRED) ? HID_SEC_CHN : HID_NOSEC_CHN,
+ &hidh_sec_check_complete_orig, p_dev);
+ }
+ else
+ {
+ p_hcon->conn_state = HID_CONN_STATE_CONFIG;
+ }
+
+ /* Send a Configuration Request. */
+ L2CA_ConfigReq (l2cap_cid, &hh_cb.l2cap_cfg);
+
+ HIDH_TRACE_EVENT1 ("HID - got CTRL conn cnf, sent cfg req, CID: 0x%x", l2cap_cid);
+ return;
+}
+
+/*******************************************************************************
+**
+** Function hidh_l2cif_config_ind
+**
+** Description This function processes the L2CAP configuration indication
+** event.
+**
+** Returns void
+**
+*******************************************************************************/
+static void hidh_l2cif_config_ind (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg)
+{
+ UINT8 dhandle;
+ tHID_CONN *p_hcon = NULL;
+ tHID_HOST_DEV_CTB *p_dev;
+
+ /* Find CCB based on CID */
+ if( (dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES )
+ {
+ p_dev = &hh_cb.devices[dhandle];
+ p_hcon = &hh_cb.devices[dhandle].conn;
+ }
+
+ if (p_hcon == NULL)
+ {
+ HIDH_TRACE_WARNING1 ("HID - Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid);
+ return;
+ }
+
+ HIDH_TRACE_EVENT1 ("HID - Rcvd cfg ind, sent cfg cfm, CID: 0x%x", l2cap_cid);
+
+ /* Remember the remote MTU size */
+ if ((!p_cfg->mtu_present) || (p_cfg->mtu > HID_HOST_MTU))
+ p_hcon->rem_mtu_size = HID_HOST_MTU;
+ else
+ p_hcon->rem_mtu_size = p_cfg->mtu;
+
+ /* For now, always accept configuration from the other side */
+ p_cfg->flush_to_present = FALSE;
+ p_cfg->mtu_present = FALSE;
+ p_cfg->result = L2CAP_CFG_OK;
+
+ L2CA_ConfigRsp (l2cap_cid, p_cfg);
+
+ if (l2cap_cid == p_hcon->ctrl_cid)
+ p_hcon->conn_flags |= HID_CONN_FLAGS_HIS_CTRL_CFG_DONE;
+ else
+ p_hcon->conn_flags |= HID_CONN_FLAGS_HIS_INTR_CFG_DONE;
+
+ /* If all configuration is complete, change state and tell management we are up */
+ if (((p_hcon->conn_flags & HID_CONN_FLAGS_ALL_CONFIGURED) == HID_CONN_FLAGS_ALL_CONFIGURED)
+ && (p_hcon->conn_state == HID_CONN_STATE_CONFIG))
+ {
+ p_hcon->conn_state = HID_CONN_STATE_CONNECTED;
+
+ hh_cb.devices[dhandle].state = HID_DEV_CONNECTED;
+ hh_cb.callback( dhandle, HID_HDEV_EVT_OPEN, 0, NULL ) ;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function hidh_l2cif_config_cfm
+**
+** Description This function processes the L2CAP configuration confirmation
+** event.
+**
+** Returns void
+**
+*******************************************************************************/
+static void hidh_l2cif_config_cfm (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg)
+{
+ UINT8 dhandle;
+ tHID_CONN *p_hcon = NULL;
+ UINT32 reason;
+
+ HIDH_TRACE_EVENT2 ("HID - Rcvd cfg cfm, CID: 0x%x Result: %d", l2cap_cid, p_cfg->result);
+
+ /* Find CCB based on CID */
+ if( (dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES )
+ p_hcon = &hh_cb.devices[dhandle].conn;
+
+ if (p_hcon == NULL)
+ {
+ HIDH_TRACE_WARNING1 ("HID - Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid);
+ return;
+ }
+
+ /* If configuration failed, disconnect the channel(s) */
+ if (p_cfg->result != L2CAP_CFG_OK)
+ {
+ hidh_conn_disconnect (dhandle);
+ reason = HID_L2CAP_CFG_FAIL | (UINT32) p_cfg->result ;
+ hh_cb.callback( dhandle, HID_HDEV_EVT_CLOSE, reason, NULL ) ;
+ return;
+ }
+
+ if (l2cap_cid == p_hcon->ctrl_cid)
+ p_hcon->conn_flags |= HID_CONN_FLAGS_MY_CTRL_CFG_DONE;
+ else
+ p_hcon->conn_flags |= HID_CONN_FLAGS_MY_INTR_CFG_DONE;
+
+ /* If all configuration is complete, change state and tell management we are up */
+ if (((p_hcon->conn_flags & HID_CONN_FLAGS_ALL_CONFIGURED) == HID_CONN_FLAGS_ALL_CONFIGURED)
+ && (p_hcon->conn_state == HID_CONN_STATE_CONFIG))
+ {
+ p_hcon->conn_state = HID_CONN_STATE_CONNECTED;
+
+ hh_cb.devices[dhandle].state = HID_DEV_CONNECTED;
+ hh_cb.callback( dhandle, HID_HDEV_EVT_OPEN, 0, NULL ) ;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function hidh_l2cif_disconnect_ind
+**
+** Description This function handles a disconnect event from L2CAP. If
+** requested to, we ack the disconnect before dropping the CCB
+**
+** Returns void
+**
+*******************************************************************************/
+static void hidh_l2cif_disconnect_ind (UINT16 l2cap_cid, BOOLEAN ack_needed)
+{
+ UINT8 dhandle;
+ tHID_CONN *p_hcon = NULL;
+ UINT16 disc_res = HCI_SUCCESS;
+ UINT16 hid_close_evt_reason;
+
+ /* Find CCB based on CID */
+ if( (dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES )
+ p_hcon = &hh_cb.devices[dhandle].conn;
+
+ if (p_hcon == NULL)
+ {
+ HIDH_TRACE_WARNING1 ("HID - Rcvd L2CAP disc, unknown CID: 0x%x", l2cap_cid);
+ return;
+ }
+
+ if (ack_needed)
+ L2CA_DisconnectRsp (l2cap_cid);
+
+ HIDH_TRACE_EVENT1 ("HID - Rcvd L2CAP disc, CID: 0x%x", l2cap_cid);
+
+ p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING;
+
+ if (l2cap_cid == p_hcon->ctrl_cid)
+ p_hcon->ctrl_cid = 0;
+ else
+ p_hcon->intr_cid = 0;
+
+ if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0))
+ {
+ hh_cb.devices[dhandle].state = HID_DEV_NO_CONN;
+ p_hcon->conn_state = HID_CONN_STATE_UNUSED;
+
+ if( !ack_needed )
+ disc_res = btm_get_acl_disc_reason_code();
+
+#if (HID_HOST_MAX_CONN_RETRY > 0)
+ if( (disc_res == HCI_ERR_CONNECTION_TOUT || disc_res == HCI_ERR_UNSPECIFIED) &&
+ (!(hh_cb.devices[dhandle].attr_mask & HID_RECONN_INIT)) &&
+ (hh_cb.devices[dhandle].attr_mask & HID_NORMALLY_CONNECTABLE))
+ {
+ hh_cb.devices[dhandle].conn_tries = 0;
+ hh_cb.devices[dhandle].conn.timer_entry.param = (UINT32) dhandle;
+ btu_start_timer (&(hh_cb.devices[dhandle].conn.timer_entry), BTU_TTYPE_HID_HOST_REPAGE_TO, HID_HOST_REPAGE_WIN);
+ }
+ else
+#endif
+ {
+ /* Set reason code for HID_HDEV_EVT_CLOSE */
+ hid_close_evt_reason = p_hcon->disc_reason;
+
+ /* If we got baseband sent HCI_DISCONNECT_COMPLETE_EVT due to security failure, then set reason to HID_ERR_AUTH_FAILED */
+ if ((disc_res == HCI_ERR_AUTH_FAILURE) ||
+ (disc_res == HCI_ERR_KEY_MISSING) ||
+ (disc_res == HCI_ERR_HOST_REJECT_SECURITY) ||
+ (disc_res == HCI_ERR_PAIRING_NOT_ALLOWED) ||
+ (disc_res == HCI_ERR_UNIT_KEY_USED) ||
+ (disc_res == HCI_ERR_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED) ||
+ (disc_res == HCI_ERR_ENCRY_MODE_NOT_ACCEPTABLE) ||
+ (disc_res == HCI_ERR_REPEATED_ATTEMPTS))
+ {
+ hid_close_evt_reason = HID_ERR_AUTH_FAILED;
+ }
+
+ hh_cb.callback( dhandle, HID_HDEV_EVT_CLOSE, hid_close_evt_reason, NULL ) ;
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function hidh_l2cif_disconnect_cfm
+**
+** Description This function handles a disconnect confirm event from L2CAP.
+**
+** Returns void
+**
+*******************************************************************************/
+static void hidh_l2cif_disconnect_cfm (UINT16 l2cap_cid, UINT16 result)
+{
+ UINT8 dhandle;
+ tHID_CONN *p_hcon = NULL;
+
+ /* Find CCB based on CID */
+ if( (dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES )
+ p_hcon = &hh_cb.devices[dhandle].conn;
+
+ if (p_hcon == NULL)
+ {
+ HIDH_TRACE_WARNING1 ("HID - Rcvd L2CAP disc cfm, unknown CID: 0x%x", l2cap_cid);
+ return;
+ }
+
+ HIDH_TRACE_EVENT1 ("HID - Rcvd L2CAP disc cfm, CID: 0x%x", l2cap_cid);
+
+ if (l2cap_cid == p_hcon->ctrl_cid)
+ p_hcon->ctrl_cid = 0;
+ else
+ p_hcon->intr_cid = 0;
+
+ if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0))
+ {
+ hh_cb.devices[dhandle].state = HID_DEV_NO_CONN;
+ p_hcon->conn_state = HID_CONN_STATE_UNUSED;
+ hh_cb.callback( dhandle, HID_HDEV_EVT_CLOSE, p_hcon->disc_reason, NULL ) ;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function hidh_l2cif_cong_ind
+**
+** Description This function handles a congestion status event from L2CAP.
+**
+** Returns void
+**
+*******************************************************************************/
+static void hidh_l2cif_cong_ind (UINT16 l2cap_cid, BOOLEAN congested)
+{
+ UINT8 dhandle;
+ tHID_CONN *p_hcon = NULL;
+
+ /* Find CCB based on CID */
+ if( (dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES )
+ p_hcon = &hh_cb.devices[dhandle].conn;
+
+ if (p_hcon == NULL)
+ {
+ HIDH_TRACE_WARNING1 ("HID - Rcvd L2CAP congestion status, unknown CID: 0x%x", l2cap_cid);
+ return;
+ }
+
+ HIDH_TRACE_EVENT2 ("HID - Rcvd L2CAP congestion status, CID: 0x%x Cong: %d", l2cap_cid, congested);
+
+ if (congested)
+ p_hcon->conn_flags |= HID_CONN_FLAGS_CONGESTED;
+ else
+ {
+ p_hcon->conn_flags &= ~HID_CONN_FLAGS_CONGESTED;
+
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function hidh_l2cif_data_ind
+**
+** Description This function is called when data is received from L2CAP.
+** if we are the originator of the connection, we are the SDP
+** client, and the received message is queued up for the client.
+**
+** If we are the destination of the connection, we are the SDP
+** server, so the message is passed to the server processing
+** function.
+**
+** Returns void
+**
+*******************************************************************************/
+static void hidh_l2cif_data_ind (UINT16 l2cap_cid, BT_HDR *p_msg)
+{
+ UINT8 *p_data = (UINT8 *)(p_msg + 1) + p_msg->offset;
+ UINT8 ttype, param, rep_type, evt;
+ UINT8 dhandle;
+ tHID_CONN *p_hcon = NULL;
+
+ HIDH_TRACE_DEBUG1 ("HID - hidh_l2cif_data_ind [l2cap_cid=0x%04x]", l2cap_cid);
+
+ /* Find CCB based on CID */
+ if ((dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES)
+ p_hcon = &hh_cb.devices[dhandle].conn;
+
+ if (p_hcon == NULL)
+ {
+ HIDH_TRACE_WARNING1 ("HID - Rcvd L2CAP data, unknown CID: 0x%x", l2cap_cid);
+ GKI_freebuf (p_msg);
+ return;
+ }
+
+
+ ttype = HID_GET_TRANS_FROM_HDR(*p_data);
+ param = HID_GET_PARAM_FROM_HDR(*p_data);
+ rep_type = param & HID_PAR_REP_TYPE_MASK;
+ p_data++;
+
+ /* Get rid of the data type */
+ p_msg->len--;
+ p_msg->offset++;
+
+ switch (ttype)
+ {
+ case HID_TRANS_HANDSHAKE:
+ hh_cb.callback(dhandle, HID_HDEV_EVT_HANDSHAKE, param, NULL);
+ GKI_freebuf (p_msg);
+ break;
+
+ case HID_TRANS_CONTROL:
+ switch (param)
+ {
+ case HID_PAR_CONTROL_VIRTUAL_CABLE_UNPLUG:
+ hidh_conn_disconnect( dhandle ) ;
+ /* Device is unplugging from us. Tell USB */
+ hh_cb.callback(dhandle, HID_HDEV_EVT_VC_UNPLUG, 0, NULL);
+ break;
+
+ default:
+ break;
+ }
+ GKI_freebuf (p_msg);
+ break;
+
+
+ case HID_TRANS_DATA:
+ evt = (hh_cb.devices[dhandle].conn.intr_cid == l2cap_cid) ?
+ HID_HDEV_EVT_INTR_DATA : HID_HDEV_EVT_CTRL_DATA;
+ hh_cb.callback(dhandle, evt, rep_type, p_msg);
+ break;
+
+ case HID_TRANS_DATAC:
+ evt = (hh_cb.devices[dhandle].conn.intr_cid == l2cap_cid) ?
+ HID_HDEV_EVT_INTR_DATC : HID_HDEV_EVT_CTRL_DATC;
+ hh_cb.callback(dhandle, evt, rep_type, p_msg);
+ break;
+
+ default:
+ GKI_freebuf (p_msg);
+ break;
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function hidh_conn_snd_data
+**
+** Description This function is sends out data.
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+tHID_STATUS hidh_conn_snd_data (UINT8 dhandle, UINT8 trans_type, UINT8 param,
+ UINT16 data, UINT8 report_id, BT_HDR *buf)
+{
+ tHID_CONN *p_hcon = &hh_cb.devices[dhandle].conn;
+ BT_HDR *p_buf;
+ UINT8 *p_out;
+ UINT16 bytes_copied;
+ BOOLEAN seg_req = FALSE;
+ UINT16 data_size;
+ UINT16 cid;
+ UINT8 pool_id;
+ UINT8 use_data = 0 ;
+ BOOLEAN blank_datc = FALSE;
+
+ if (p_hcon->conn_flags & HID_CONN_FLAGS_CONGESTED)
+ {
+ if (buf)
+ GKI_freebuf ((void *)buf);
+ return( HID_ERR_CONGESTED );
+ }
+
+ switch( trans_type )
+ {
+ case HID_TRANS_CONTROL:
+ case HID_TRANS_GET_REPORT:
+ case HID_TRANS_SET_REPORT:
+ case HID_TRANS_GET_PROTOCOL:
+ case HID_TRANS_SET_PROTOCOL:
+ case HID_TRANS_DATA:
+ cid = p_hcon->intr_cid;
+ pool_id = HID_INTERRUPT_POOL_ID;
+ break;
+ default:
+ return (HID_ERR_INVALID_PARAM) ;
+ }
+
+ if( (trans_type == HID_TRANS_GET_REPORT) && (param & 0x08) )
+ use_data = 2;
+
+ do
+ {
+ if ( buf == NULL || blank_datc )
+ {
+ if((p_buf = (BT_HDR *)GKI_getpoolbuf (pool_id)) == NULL)
+ return (HID_ERR_NO_RESOURCES);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ seg_req = FALSE;
+ data_size = 0;
+ bytes_copied = 0;
+ blank_datc = FALSE;
+ }
+ else if ( (buf->len > (p_hcon->rem_mtu_size - 1)))
+ {
+ if((p_buf = (BT_HDR *)GKI_getpoolbuf (pool_id)) == NULL)
+ return (HID_ERR_NO_RESOURCES);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ seg_req = TRUE;
+ data_size = buf->len;
+ bytes_copied = p_hcon->rem_mtu_size - 1;
+ }
+ else
+ {
+ p_buf = buf ;
+ p_buf->offset -= 1;
+ seg_req = FALSE;
+ data_size = buf->len;
+ bytes_copied = buf->len;
+ }
+
+ p_out = (UINT8 *)(p_buf + 1) + p_buf->offset;
+ *p_out++ = HID_BUILD_HDR(trans_type, param);
+
+ /* If report ID required for this device */
+ if( (trans_type == HID_TRANS_GET_REPORT) && (report_id != 0) )
+ {
+ *p_out = report_id;
+ data_size = bytes_copied = 1;
+ }
+
+
+ if (seg_req)
+ {
+ memcpy (p_out, (((UINT8 *)(buf+1)) + buf->offset), bytes_copied);
+ buf->offset += bytes_copied;
+ buf->len -= bytes_copied;
+ }
+ else if( use_data == 1)
+ {
+ *(p_out+bytes_copied) = data & 0xff;
+ }
+ else if( use_data == 2 )
+ {
+ *(p_out+bytes_copied) = data & 0xff;
+ *(p_out+bytes_copied+1) = (data >> 8) & 0xff ;
+ }
+
+ p_buf->len = bytes_copied + 1 + use_data;
+ data_size -= bytes_copied;
+
+ /* Send the buffer through L2CAP */
+ if ((p_hcon->conn_flags & HID_CONN_FLAGS_CONGESTED) || (!L2CA_DataWrite (cid, p_buf)))
+ return (HID_ERR_CONGESTED);
+
+ if (data_size)
+ trans_type = HID_TRANS_DATAC;
+ else if( bytes_copied == (p_hcon->rem_mtu_size - 1) )
+ {
+ trans_type = HID_TRANS_DATAC;
+ blank_datc = TRUE;
+ }
+
+ } while ((data_size != 0) || blank_datc ) ;
+
+ return (HID_SUCCESS);
+}
+/*******************************************************************************
+**
+** Function hidh_conn_initiate
+**
+** Description This function is called by the management to create a connection.
+**
+** Returns void
+**
+*******************************************************************************/
+tHID_STATUS hidh_conn_initiate (UINT8 dhandle)
+{
+ UINT8 service_id = BTM_SEC_SERVICE_HID_NOSEC_CTRL;
+ UINT32 mx_chan_id = HID_NOSEC_CHN;
+
+ tHID_HOST_DEV_CTB *p_dev = &hh_cb.devices[dhandle];
+
+ if( p_dev->conn.conn_state != HID_CONN_STATE_UNUSED )
+ return( HID_ERR_CONN_IN_PROCESS );
+
+ p_dev->conn.ctrl_cid = 0;
+ p_dev->conn.intr_cid = 0;
+ p_dev->conn.disc_reason = HID_L2CAP_CONN_FAIL; /* Reset initial reason for CLOSE_EVT: Connection Attempt was made but failed */
+
+ /* We are the originator of this connection */
+ p_dev->conn.conn_flags = HID_CONN_FLAGS_IS_ORIG;
+
+ if(p_dev->attr_mask & HID_SEC_REQUIRED)
+ {
+ service_id = BTM_SEC_SERVICE_HID_SEC_CTRL;
+ mx_chan_id = HID_SEC_CHN;
+ }
+ BTM_SetOutService (p_dev->addr, service_id, mx_chan_id);
+
+ /* Check if L2CAP started the connection process */
+ if ((p_dev->conn.ctrl_cid = L2CA_ConnectReq (HID_PSM_CONTROL, p_dev->addr)) == 0)
+ {
+ HIDH_TRACE_WARNING0 ("HID - Originate failed");
+ dhandle = (p_dev - &(hh_cb.devices[0]))/(sizeof( tHID_HOST_DEV_CTB )) ;
+ hh_cb.callback( dhandle, HID_HDEV_EVT_CLOSE, HID_ERR_L2CAP_FAILED, NULL ) ;
+ }
+ else
+ {
+ /* Transition to the next appropriate state, waiting for connection confirm on control channel. */
+ p_dev->conn.conn_state = HID_CONN_STATE_CONNECTING_CTRL;
+ }
+
+ return( HID_SUCCESS );
+}
+
+
+/*******************************************************************************
+**
+** Function find_conn_by_cid
+**
+** Description This function finds a connection control block based on CID
+**
+** Returns address of control block, or NULL if not found
+**
+*******************************************************************************/
+static UINT8 find_conn_by_cid (UINT16 cid)
+{
+ UINT8 xx;
+
+ for (xx = 0; xx < HID_HOST_MAX_DEVICES; xx++)
+ {
+ if ((hh_cb.devices[xx].in_use) && (hh_cb.devices[xx].conn.conn_state != HID_CONN_STATE_UNUSED)
+ && ((hh_cb.devices[xx].conn.ctrl_cid == cid) || (hh_cb.devices[xx].conn.intr_cid == cid)))
+ break;
+ }
+
+ return (xx);
+}
+
+void hidh_conn_dereg( void )
+{
+ L2CA_Deregister (HID_PSM_CONTROL);
+ L2CA_Deregister (HID_PSM_INTERRUPT);
+}
+
+/*******************************************************************************
+**
+** Function hidh_conn_retry
+**
+** Description This function is called to retry a failed connection.
+**
+** Returns void
+**
+*******************************************************************************/
+static void hidh_conn_retry( UINT8 dhandle )
+{
+ tHID_HOST_DEV_CTB *p_dev = &hh_cb.devices[dhandle];
+
+ p_dev->conn.conn_state = HID_CONN_STATE_UNUSED;
+ p_dev->conn.timer_entry.param = (UINT32) dhandle;
+#if (HID_HOST_REPAGE_WIN > 0)
+ btu_start_timer (&(p_dev->conn.timer_entry), BTU_TTYPE_HID_HOST_REPAGE_TO, HID_HOST_REPAGE_WIN);
+#else
+ hidh_proc_repage_timeout( &(p_dev->conn.timer_entry) );
+#endif
+}
diff --git a/stack/hid/hidh_int.h b/stack/hid/hidh_int.h
new file mode 100644
index 0000000..8e1a8a2
--- /dev/null
+++ b/stack/hid/hidh_int.h
@@ -0,0 +1,81 @@
+/****************************************************************************/
+/* */
+/* Name: hidh_int.h */
+/* */
+/* Function: this file contains HID HOST internal definitions */
+/* */
+/* Copyright (c) 2002-2004, WIDCOMM Inc., All Rights Reserved. */
+/* WIDCOMM Bluetooth Core. Proprietary and confidential. */
+/* */
+/****************************************************************************/
+
+#ifndef HIDH_INT_H
+#define HIDH_INT_H
+
+#include "hidh_api.h"
+#include "hid_conn.h"
+#include "l2c_api.h"
+
+enum {
+ HID_DEV_NO_CONN,
+ HID_DEV_CONNECTED
+};
+
+typedef struct per_device_ctb
+{
+ BOOLEAN in_use;
+ BD_ADDR addr; /* BD-Addr of the host device */
+ UINT16 attr_mask; /* 0x01- virtual_cable; 0x02- normally_connectable; 0x03- reconn_initiate;
+ 0x04- sdp_disable; */
+ UINT8 state; /* Device state if in HOST-KNOWN mode */
+ UINT8 conn_substate;
+ UINT8 conn_tries; /* Remembers to the number of connection attempts while CONNECTING */
+
+ tHID_CONN conn; /* L2CAP channel info */
+} tHID_HOST_DEV_CTB;
+
+typedef struct host_ctb
+{
+ tHID_HOST_DEV_CTB devices[HID_HOST_MAX_DEVICES];
+ tHID_HOST_DEV_CALLBACK *callback; /* Application callbacks */
+ tL2CAP_CFG_INFO l2cap_cfg;
+
+#define MAX_SERVICE_DB_SIZE 4000
+
+ BOOLEAN sdp_busy;
+ tHID_HOST_SDP_CALLBACK *sdp_cback;
+ tSDP_DISCOVERY_DB *p_sdp_db;
+ tHID_DEV_SDP_INFO sdp_rec;
+ BOOLEAN reg_flag;
+ UINT8 trace_level;
+} tHID_HOST_CTB;
+
+extern tHID_STATUS hidh_conn_snd_data(UINT8 dhandle, UINT8 trans_type, UINT8 param, \
+ UINT16 data,UINT8 rpt_id, BT_HDR *buf);
+extern tHID_STATUS hidh_conn_reg (void);
+extern void hidh_conn_dereg( void );
+extern tHID_STATUS hidh_conn_disconnect (UINT8 dhandle);
+extern tHID_STATUS hidh_conn_initiate (UINT8 dhandle);
+extern void hidh_proc_repage_timeout (TIMER_LIST_ENT *p_tle);
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/******************************************************************************
+** Main Control Block
+*******************************************************************************/
+#if HID_DYNAMIC_MEMORY == FALSE
+HID_API extern tHID_HOST_CTB hh_cb;
+#else
+HID_API extern tHID_HOST_CTB *hidh_cb_ptr;
+#define hh_cb (*hidh_cb_ptr)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/stack/include/a2d_api.h b/stack/include/a2d_api.h
new file mode 100644
index 0000000..6bb7f0b
--- /dev/null
+++ b/stack/include/a2d_api.h
@@ -0,0 +1,244 @@
+/*****************************************************************************
+**
+** Name: a2d_api.h
+**
+** Description:Interface to A2DP Application Programming Interface
+**
+** Copyright (c) 2000-2009, Broadcom Corp., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef A2D_API_H
+#define A2D_API_H
+#include "sdp_api.h"
+
+/*****************************************************************************
+** constants
+*****************************************************************************/
+
+/* Profile supported features */
+#define A2D_SUPF_PLAYER 0x0001
+#define A2D_SUPF_MIC 0x0002
+#define A2D_SUPF_TUNER 0x0004
+#define A2D_SUPF_MIXER 0x0008
+
+#define A2D_SUPF_HEADPHONE 0x0001
+#define A2D_SUPF_SPEAKER 0x0002
+#define A2D_SUPF_RECORDER 0x0004
+#define A2D_SUPF_AMP 0x0008
+
+/* AV Media Types */
+#define A2D_MEDIA_TYPE_AUDIO 0x00 /* audio media type + RFA */
+#define A2D_MEDIA_TYPE_VIDEO 0x10 /* video media type + RFA */
+#define A2D_MEDIA_TYPE_MULTI 0x20 /* multimedia media type + RFA */
+
+/* AV Media Codec Type (Audio Codec ID) */
+#define A2D_MEDIA_CT_SBC 0x00 /* SBC media codec type */
+#define A2D_MEDIA_CT_M12 0x01 /* MPEG-1, 2 Audio media codec type */
+#define A2D_MEDIA_CT_M24 0x02 /* MPEG-2, 4 AAC media codec type */
+#define A2D_MEDIA_CT_ATRAC 0x04 /* ATRAC family media codec type */
+
+#define A2D_SUCCESS 0 /* Success */
+#define A2D_FAIL 0x0A /* Failed */
+#define A2D_BUSY 0x0B /* A2D_FindService is already in progress */
+#define A2D_INVALID_PARAMS 0x0C /* bad parameters */
+#define A2D_WRONG_CODEC 0x0D /* wrong codec info */
+#define A2D_BAD_CODEC_TYPE 0xC1 /* Media Codec Type is not valid */
+#define A2D_NS_CODEC_TYPE 0xC2 /* Media Codec Type is not supported */
+#define A2D_BAD_SAMP_FREQ 0xC3 /* Sampling Frequency is not valid or multiple values have been selected */
+#define A2D_NS_SAMP_FREQ 0xC4 /* Sampling Frequency is not supported */
+#define A2D_BAD_CH_MODE 0xC5 /* Channel Mode is not valid or multiple values have been selected */
+#define A2D_NS_CH_MODE 0xC6 /* Channel Mode is not supported */
+#define A2D_BAD_SUBBANDS 0xC7 /* None or multiple values have been selected for Number of Subbands */
+#define A2D_NS_SUBBANDS 0xC8 /* Number of Subbands is not supported */
+#define A2D_BAD_ALLOC_MTHD 0xC9 /* None or multiple values have been selected for Allocation Method */
+#define A2D_NS_ALLOC_MTHD 0xCA /* Allocation Method is not supported */
+#define A2D_BAD_MIN_BITPOOL 0xCB /* Minimum Bitpool Value is not valid */
+#define A2D_NS_MIN_BITPOOL 0xCC /* Minimum Bitpool Value is not supported */
+#define A2D_BAD_MAX_BITPOOL 0xCD /* Maximum Bitpool Value is not valid */
+#define A2D_NS_MAX_BITPOOL 0xCE /* Maximum Bitpool Value is not supported */
+#define A2D_BAD_LAYER 0xCF /* None or multiple values have been selected for Layer */
+#define A2D_NS_LAYER 0xD0 /* Layer is not supported */
+#define A2D_NS_CRC 0xD1 /* CRC is not supported */
+#define A2D_NS_MPF 0xD2 /* MPF-2 is not supported */
+#define A2D_NS_VBR 0xD3 /* VBR is not supported */
+#define A2D_BAD_BIT_RATE 0xD4 /* None or multiple values have been selected for Bit Rate */
+#define A2D_NS_BIT_RATE 0xD5 /* Bit Rate is not supported */
+#define A2D_BAD_OBJ_TYPE 0xD6 /* Either 1) Object type is not valid (b3-b0) or 2) None or multiple values have been selected for Object Type */
+#define A2D_NS_OBJ_TYPE 0xD7 /* Object type is not supported */
+#define A2D_BAD_CHANNEL 0xD8 /* None or multiple values have been selected for Channels */
+#define A2D_NS_CHANNEL 0xD9 /* Channels is not supported */
+#define A2D_BAD_BLOCK_LEN 0xDD /* None or multiple values have been selected for Block Length */
+#define A2D_BAD_CP_TYPE 0xE0 /* The requested CP Type is not supported. */
+#define A2D_BAD_CP_FORMAT 0xE1 /* The format of Content Protection Service Capability/Content Protection Scheme Dependent Data is not correct. */
+
+typedef UINT8 tA2D_STATUS;
+
+/* the return values from A2D_BitsSet() */
+#define A2D_SET_ONE_BIT 1 /* one and only one bit is set */
+#define A2D_SET_ZERO_BIT 0 /* all bits clear */
+#define A2D_SET_MULTL_BIT 2 /* multiple bits are set */
+
+/*****************************************************************************
+** type definitions
+*****************************************************************************/
+
+/* This data type is used in A2D_FindService() to initialize the SDP database
+ * to hold the result service search. */
+typedef struct
+{
+ UINT32 db_len; /* Length, in bytes, of the discovery database */
+ UINT16 num_attr;/* The number of attributes in p_attrs */
+ tSDP_DISCOVERY_DB *p_db; /* Pointer to the discovery database */
+ UINT16 *p_attrs; /* The attributes filter. If NULL, A2DP API sets the attribute filter
+ * to be ATTR_ID_SERVICE_CLASS_ID_LIST, ATTR_ID_BT_PROFILE_DESC_LIST,
+ * ATTR_ID_SUPPORTED_FEATURES, ATTR_ID_SERVICE_NAME and ATTR_ID_PROVIDER_NAME.
+ * If not NULL, the input is taken as the filter. */
+} tA2D_SDP_DB_PARAMS;
+
+/* This data type is used in tA2D_FIND_CBACK to report the result of the SDP discovery process. */
+typedef struct
+{
+ UINT16 service_len; /* Length, in bytes, of the service name */
+ UINT16 provider_len; /* Length, in bytes, of the provider name */
+ char * p_service_name; /* Pointer the service name. This character string may not be null terminated.
+ * Use the service_len parameter to safely copy this string */
+ char * p_provider_name;/* Pointer the provider name. This character string may not be null terminated.
+ * Use the provider_len parameter to safely copy this string */
+ UINT16 features; /* Profile supported features */
+ UINT16 avdt_version; /* AVDTP protocol version */
+} tA2D_Service;
+
+/* This is the callback to notify the result of the SDP discovery process. */
+typedef void (tA2D_FIND_CBACK)(BOOLEAN found, tA2D_Service * p_service);
+
+
+/*****************************************************************************
+** external function declarations
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/******************************************************************************
+**
+** Function A2D_AddRecord
+**
+** Description This function is called by a server application to add
+** SRC or SNK information to an SDP record. Prior to
+** calling this function the application must call
+** SDP_CreateRecord() to create an SDP record.
+**
+** Input Parameters:
+** service_uuid: Indicates SRC or SNK.
+**
+** p_service_name: Pointer to a null-terminated character
+** string containing the service name.
+**
+** p_provider_name: Pointer to a null-terminated character
+** string containing the provider name.
+**
+** features: Profile supported features.
+**
+** sdp_handle: SDP handle returned by SDP_CreateRecord().
+**
+** Output Parameters:
+** None.
+**
+** Returns A2D_SUCCESS if function execution succeeded,
+** A2D_INVALID_PARAMS if bad parameters are given.
+** A2D_FAIL if function execution failed.
+**
+******************************************************************************/
+A2D_API extern tA2D_STATUS A2D_AddRecord(UINT16 service_uuid, char *p_service_name, char *p_provider_name,
+ UINT16 features, UINT32 sdp_handle);
+
+/******************************************************************************
+**
+** Function A2D_FindService
+**
+** Description This function is called by a client application to
+** perform service discovery and retrieve SRC or SNK SDP
+** record information from a server. Information is
+** returned for the first service record found on the
+** server that matches the service UUID. The callback
+** function will be executed when service discovery is
+** complete. There can only be one outstanding call to
+** A2D_FindService() at a time; the application must wait
+** for the callback before it makes another call to
+** the function.
+**
+** Input Parameters:
+** service_uuid: Indicates SRC or SNK.
+**
+** bd_addr: BD address of the peer device.
+**
+** p_db: Pointer to the information to initialize
+** the discovery database.
+**
+** p_cback: Pointer to the A2D_FindService()
+** callback function.
+**
+** Output Parameters:
+** None.
+**
+** Returns A2D_SUCCESS if function execution succeeded,
+** A2D_INVALID_PARAMS if bad parameters are given.
+** A2D_BUSY if discovery is already in progress.
+** A2D_FAIL if function execution failed.
+**
+******************************************************************************/
+A2D_API extern tA2D_STATUS A2D_FindService(UINT16 service_uuid, BD_ADDR bd_addr,
+ tA2D_SDP_DB_PARAMS *p_db, tA2D_FIND_CBACK *p_cback);
+
+/******************************************************************************
+**
+** Function A2D_SetTraceLevel
+**
+** Description Sets the trace level for A2D. If 0xff is passed, the
+** current trace level is returned.
+**
+** Input Parameters:
+** new_level: The level to set the A2D tracing to:
+** 0xff-returns the current setting.
+** 0-turns off tracing.
+** >= 1-Errors.
+** >= 2-Warnings.
+** >= 3-APIs.
+** >= 4-Events.
+** >= 5-Debug.
+**
+** Returns The new trace level or current trace level if
+** the input parameter is 0xff.
+**
+******************************************************************************/
+A2D_API extern UINT8 A2D_SetTraceLevel (UINT8 new_level);
+
+/******************************************************************************
+** Function A2D_BitsSet
+**
+** Description Check the given num for the number of bits set
+** Returns A2D_SET_ONE_BIT, if one and only one bit is set
+** A2D_SET_ZERO_BIT, if all bits clear
+** A2D_SET_MULTL_BIT, if multiple bits are set
+******************************************************************************/
+A2D_API extern UINT8 A2D_BitsSet(UINT8 num);
+
+#ifdef __cplusplus
+}
+#endif
+
+/*******************************************************************************
+**
+** Function A2D_Init
+**
+** Description This function is called at stack startup to allocate the
+** control block (if using dynamic memory), and initializes the
+** control block and tracing level.
+**
+** Returns void
+**
+*******************************************************************************/
+A2D_API extern void A2D_Init(void);
+
+#endif /* A2D_API_H */
diff --git a/stack/include/a2d_m12.h b/stack/include/a2d_m12.h
new file mode 100644
index 0000000..2cc5ef9
--- /dev/null
+++ b/stack/include/a2d_m12.h
@@ -0,0 +1,145 @@
+/*****************************************************************************
+**
+** Name: a2d_m12.h
+**
+** Description:Interface to MPEG-1, 2 Audio
+**
+** Copyright (c) 2000-2004, WIDCOMM Inc., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef A2D_M12_H
+#define A2D_M12_H
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+/* the length of the MPEG_1, 2 Audio Media Payload header. */
+#define A2D_M12_MPL_HDR_LEN 4
+
+/* the LOSC of MPEG_1, 2 Audio media codec capabilitiy */
+#define A2D_M12_INFO_LEN 6
+
+/* for Codec Specific Information Element */
+#define A2D_M12_IE_LAYER_MSK 0xE0 /* b7-b5 layer */
+#define A2D_M12_IE_LAYER1 0x80 /* b7: layer1 (mp1) */
+#define A2D_M12_IE_LAYER2 0x40 /* b6: layer2 (mp2) */
+#define A2D_M12_IE_LAYER3 0x20 /* b5: layer3 (mp3) */
+
+#define A2D_M12_IE_CRC_MSK 0x10 /* b4: CRC */
+
+#define A2D_M12_IE_CH_MD_MSK 0x0F /* b3-b0 channel mode */
+#define A2D_M12_IE_CH_MD_MONO 0x08 /* b3: mono */
+#define A2D_M12_IE_CH_MD_DUAL 0x04 /* b2: dual */
+#define A2D_M12_IE_CH_MD_STEREO 0x02 /* b1: stereo */
+#define A2D_M12_IE_CH_MD_JOINT 0x01 /* b0: joint stereo */
+
+#define A2D_M12_IE_MPF_MSK 0x40 /* b6: MPF */
+
+#define A2D_M12_IE_SAMP_FREQ_MSK 0x3F /* b5-b0 sampling frequency */
+#define A2D_M12_IE_SAMP_FREQ_16 0x20 /* b5:16 kHz */
+#define A2D_M12_IE_SAMP_FREQ_22 0x10 /* b4:22.05kHz */
+#define A2D_M12_IE_SAMP_FREQ_24 0x08 /* b3:24 kHz */
+#define A2D_M12_IE_SAMP_FREQ_32 0x04 /* b2:32 kHz */
+#define A2D_M12_IE_SAMP_FREQ_44 0x02 /* b1:44.1kHz */
+#define A2D_M12_IE_SAMP_FREQ_48 0x01 /* b0:48 kHz */
+
+#define A2D_M12_IE_VBR_MSK 0x80 /* b7: VBR */
+
+#define A2D_M12_IE_BITRATE_MSK 0x7FFF /* b6-b0 of octect 2, all of octect3*/
+#define A2D_M12_IE_BITRATE_0 0x0001 /* 0000 */
+#define A2D_M12_IE_BITRATE_1 0x0002 /* 0001 */
+#define A2D_M12_IE_BITRATE_2 0x0004 /* 0010 */
+#define A2D_M12_IE_BITRATE_3 0x0008 /* 0011 */
+#define A2D_M12_IE_BITRATE_4 0x0010 /* 0100 */
+#define A2D_M12_IE_BITRATE_5 0x0020 /* 0101 */
+#define A2D_M12_IE_BITRATE_6 0x0040 /* 0110 */
+#define A2D_M12_IE_BITRATE_7 0x0080 /* 0111 */
+#define A2D_M12_IE_BITRATE_8 0x0100 /* 1000 */
+#define A2D_M12_IE_BITRATE_9 0x0200 /* 1001 */
+#define A2D_M12_IE_BITRATE_10 0x0400 /* 1010 */
+#define A2D_M12_IE_BITRATE_11 0x0800 /* 1011 */
+#define A2D_M12_IE_BITRATE_12 0x1000 /* 1100 */
+#define A2D_M12_IE_BITRATE_13 0x2000 /* 1101 */
+#define A2D_M12_IE_BITRATE_14 0x4000 /* 1110 */
+
+#define A2D_BLD_M12_PML_HDR(p_dst,frag_offset) {UINT16_TO_BE_STREAM(p_dst, 0); \
+ UINT16_TO_BE_STREAM(p_dst, frag_offset); }
+
+#define A2D_PARS_M12_PML_HDR(p_src,frag_offset) {BE_STREAM_TO_UINT16(frag_offset, p_src); \
+ BE_STREAM_TO_UINT16(frag_offset, p_src); }
+
+
+/*****************************************************************************
+** Type Definitions
+*****************************************************************************/
+
+/* data type for the MPEG-1, 2 Audio Codec Information Element*/
+typedef struct
+{
+ UINT8 layer; /* layers */
+ BOOLEAN crc; /* Support of CRC protection or not */
+ UINT8 ch_mode; /* Channel mode */
+ UINT8 mpf; /* 1, if MPF-2 is supported. 0, otherwise */
+ UINT8 samp_freq; /* Sampling frequency */
+ BOOLEAN vbr; /* Variable Bit Rate */
+ UINT16 bitrate; /* Bit rate index */
+} tA2D_M12_CIE;
+
+/*****************************************************************************
+** External Function Declarations
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/******************************************************************************
+**
+** Function A2D_BldM12Info
+**
+** Description This function is called by an application to build
+** the MPEG-1, 2 Audio Media Codec Capabilities byte sequence
+** beginning from the LOSC octet.
+** Input Parameters:
+** media_type: Indicates Audio, or Multimedia.
+**
+** p_ie: The MPEG-1, 2 Audio Codec Information Element
+** information.
+**
+** Output Parameters:
+** p_result: the resulting codec info byte sequence.
+**
+** Returns A2D_SUCCESS if function execution succeeded.
+** Error status code, otherwise.
+******************************************************************************/
+A2D_API extern tA2D_STATUS A2D_BldM12Info(UINT8 media_type, tA2D_M12_CIE *p_ie,
+ UINT8 *p_result);
+
+/******************************************************************************
+**
+** Function A2D_ParsM12Info
+**
+** Description This function is called by an application to parse
+** the MPEG-1, 2 Audio Media Codec Capabilities byte sequence
+** beginning from the LOSC octet.
+** Input Parameters:
+** p_info: the byte sequence to parse.
+**
+** for_caps: TRUE, if the byte sequence is for get capabilities
+** response.
+**
+** Output Parameters:
+** p_ie: The MPEG-1, 2 Audio Codec Information Element
+** information.
+**
+** Returns A2D_SUCCESS if function execution succeeded.
+** Error status code, otherwise.
+******************************************************************************/
+A2D_API extern tA2D_STATUS A2D_ParsM12Info(tA2D_M12_CIE *p_ie, UINT8 *p_info,
+ BOOLEAN for_caps);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* A2D_M12_H */
diff --git a/stack/include/a2d_m24.h b/stack/include/a2d_m24.h
new file mode 100644
index 0000000..0417a57
--- /dev/null
+++ b/stack/include/a2d_m24.h
@@ -0,0 +1,122 @@
+/*****************************************************************************
+**
+** Name: a2d_m24.h
+**
+** Description:Interface to MPEG-2, 4 Aac
+**
+** Copyright (c) 2000-2004, WIDCOMM Inc., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef A2D_M24_H
+#define A2D_M24_H
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+/* the LOSC of MPEG_2, 4 AAC media codec capabilitiy */
+#define A2D_M24_INFO_LEN 8
+
+/* for Codec Specific Information Element */
+#define A2D_M24_IE_OBJ_MSK 0xF0 /* b7-b4 object type. b3-b0 is RFA,not used */
+#define A2D_M24_IE_OBJ_2LC 0x80 /* b7: MPEG-2 AAC LC */
+#define A2D_M24_IE_OBJ_4LC 0x40 /* b6: MPEG-4 AAC LC */
+#define A2D_M24_IE_OBJ_4LTP 0x20 /* b5: MPEG-4 AAC LTP */
+#define A2D_M24_IE_OBJ_4S 0x10 /* b4: MPEG-4 AAC scalable */
+
+#define A2D_M24_IE_SAMP_FREQ_MSK 0xFFF0 /* sampling frequency */
+#define A2D_M24_IE_SAMP_FREQ_8 0x8000 /* b7:8 kHz */
+#define A2D_M24_IE_SAMP_FREQ_11 0x4000 /* b6:11 kHz */
+#define A2D_M24_IE_SAMP_FREQ_12 0x2000 /* b5:12 kHz */
+#define A2D_M24_IE_SAMP_FREQ_16 0x1000 /* b4:16 kHz */
+#define A2D_M24_IE_SAMP_FREQ_22 0x0800 /* b3:22.05kHz */
+#define A2D_M24_IE_SAMP_FREQ_24 0x0400 /* b2:24 kHz */
+#define A2D_M24_IE_SAMP_FREQ_32 0x0200 /* b1:32 kHz */
+#define A2D_M24_IE_SAMP_FREQ_44 0x0100 /* b0:44.1kHz */
+#define A2D_M24_IE_SAMP_FREQ_48 0x0080 /* b7:48 kHz */
+#define A2D_M24_IE_SAMP_FREQ_64 0x0040 /* b6:64 kHz */
+#define A2D_M24_IE_SAMP_FREQ_88 0x0020 /* b5:88 kHz */
+#define A2D_M24_IE_SAMP_FREQ_96 0x0010 /* b4:96 kHz */
+
+#define A2D_M24_IE_CHNL_MSK 0x0C /* b3-b2 channels */
+#define A2D_M24_IE_CHNL_1 0x08 /* b3: 1 channel */
+#define A2D_M24_IE_CHNL_2 0x04 /* b2: 2 channels */
+
+#define A2D_M24_IE_VBR_MSK 0x80 /* b7: VBR */
+
+#define A2D_M24_IE_BITRATE3_MSK 0x7F0000 /* octect3*/
+#define A2D_M24_IE_BITRATE45_MSK 0x00FFFF /* octect4, 5*/
+#define A2D_M24_IE_BITRATE_MSK 0x7FFFFF /* b7-b0 of octect 3, all of octect4, 5*/
+
+
+/*****************************************************************************
+** Type Definitions
+*****************************************************************************/
+
+/* data type for the MPEG-2, 4 AAC Codec Information Element*/
+typedef struct
+{
+ UINT8 obj_type; /* Object type */
+ UINT16 samp_freq; /* Sampling frequency */
+ UINT8 chnl; /* Channel mode */
+ BOOLEAN vbr; /* Variable Bit Rate */
+ UINT32 bitrate; /* Bit rate index */
+} tA2D_M24_CIE;
+
+/*****************************************************************************
+** External Function Declarations
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/******************************************************************************
+**
+** Function A2D_BldM24Info
+**
+** Description This function is called by an application to build
+** the MPEG-2, 4 AAC Media Codec Capabilities byte sequence
+** beginning from the LOSC octet.
+** Input Parameters:
+** media_type: Indicates Audio, or Multimedia.
+**
+** p_ie: MPEG-2, 4 AAC Codec Information Element information.
+**
+** Output Parameters:
+** p_result: the resulting codec info byte sequence.
+**
+** Returns A2D_SUCCESS if function execution succeeded.
+** Error status code, otherwise.
+******************************************************************************/
+A2D_API extern tA2D_STATUS A2D_BldM24Info(UINT8 media_type, tA2D_M24_CIE *p_ie,
+ UINT8 *p_result);
+
+/******************************************************************************
+**
+** Function A2D_ParsM24Info
+**
+** Description This function is called by an application to parse
+** the MPEG-2, 4 AAC Media Codec Capabilities byte sequence
+** beginning from the LOSC octet.
+** Input Parameters:
+** p_info: the byte sequence to parse.
+**
+** for_caps: TRUE, if the byte sequence is for get
+** capabilities response.
+**
+** Output Parameters:
+** p_ie: MPEG-2, 4 AAC Codec Information Element information.
+**
+** Returns A2D_SUCCESS if function execution succeeded.
+** Error status code, otherwise.
+******************************************************************************/
+A2D_API extern tA2D_STATUS A2D_ParsM24Info(tA2D_M24_CIE *p_ie, UINT8 *p_info,
+ BOOLEAN for_caps);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* A2D_M24_H */
+
diff --git a/stack/include/a2d_sbc.h b/stack/include/a2d_sbc.h
new file mode 100644
index 0000000..a80639b
--- /dev/null
+++ b/stack/include/a2d_sbc.h
@@ -0,0 +1,199 @@
+/*****************************************************************************
+**
+** Name: a2d_sbc.h
+**
+** Description:Interface to low complexity subband codec (SBC)
+**
+** Copyright (c) 2000-2004, WIDCOMM Inc., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef A2D_SBC_H
+#define A2D_SBC_H
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+/* the length of the SBC Media Payload header. */
+#define A2D_SBC_MPL_HDR_LEN 1
+
+/* the LOSC of SBC media codec capabilitiy */
+#define A2D_SBC_INFO_LEN 6
+
+/* for Codec Specific Information Element */
+#define A2D_SBC_IE_SAMP_FREQ_MSK 0xF0 /* b7-b4 sampling frequency */
+#define A2D_SBC_IE_SAMP_FREQ_16 0x80 /* b7:16 kHz */
+#define A2D_SBC_IE_SAMP_FREQ_32 0x40 /* b6:32 kHz */
+#define A2D_SBC_IE_SAMP_FREQ_44 0x20 /* b5:44.1kHz */
+#define A2D_SBC_IE_SAMP_FREQ_48 0x10 /* b4:48 kHz */
+
+#define A2D_SBC_IE_CH_MD_MSK 0x0F /* b3-b0 channel mode */
+#define A2D_SBC_IE_CH_MD_MONO 0x08 /* b3: mono */
+#define A2D_SBC_IE_CH_MD_DUAL 0x04 /* b2: dual */
+#define A2D_SBC_IE_CH_MD_STEREO 0x02 /* b1: stereo */
+#define A2D_SBC_IE_CH_MD_JOINT 0x01 /* b0: joint stereo */
+
+#define A2D_SBC_IE_BLOCKS_MSK 0xF0 /* b7-b4 number of blocks */
+#define A2D_SBC_IE_BLOCKS_4 0x80 /* 4 blocks */
+#define A2D_SBC_IE_BLOCKS_8 0x40 /* 8 blocks */
+#define A2D_SBC_IE_BLOCKS_12 0x20 /* 12blocks */
+#define A2D_SBC_IE_BLOCKS_16 0x10 /* 16blocks */
+
+#define A2D_SBC_IE_SUBBAND_MSK 0x0C /* b3-b2 number of subbands */
+#define A2D_SBC_IE_SUBBAND_4 0x08 /* b3: 4 */
+#define A2D_SBC_IE_SUBBAND_8 0x04 /* b2: 8 */
+
+#define A2D_SBC_IE_ALLOC_MD_MSK 0x03 /* b1-b0 allocation mode */
+#define A2D_SBC_IE_ALLOC_MD_S 0x02 /* b1: SNR */
+#define A2D_SBC_IE_ALLOC_MD_L 0x01 /* b0: loundess */
+
+#define A2D_SBC_IE_MIN_BITPOOL 2
+#define A2D_SBC_IE_MAX_BITPOOL 250
+
+/* for media payload header */
+#define A2D_SBC_HDR_F_MSK 0x80
+#define A2D_SBC_HDR_S_MSK 0x40
+#define A2D_SBC_HDR_L_MSK 0x20
+#define A2D_SBC_HDR_NUM_MSK 0x0F
+
+/*****************************************************************************
+** Type Definitions
+*****************************************************************************/
+
+/* data type for the SBC Codec Information Element*/
+typedef struct
+{
+ UINT8 samp_freq; /* Sampling frequency */
+ UINT8 ch_mode; /* Channel mode */
+ UINT8 block_len; /* Block length */
+ UINT8 num_subbands; /* Number of subbands */
+ UINT8 alloc_mthd; /* Allocation method */
+ UINT8 max_bitpool; /* Maximum bitpool */
+ UINT8 min_bitpool; /* Minimum bitpool */
+} tA2D_SBC_CIE;
+
+
+/*****************************************************************************
+** External Function Declarations
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/******************************************************************************
+**
+** Function A2D_SbcChkFrInit
+**
+** Description check if need to init the descramble control block.
+**
+** Returns nothing.
+******************************************************************************/
+A2D_API extern void A2D_SbcChkFrInit(UINT8 *p_pkt);
+
+/******************************************************************************
+**
+** Function A2D_SbcDescramble
+**
+** Description descramble the packet.
+**
+** Returns nothing.
+******************************************************************************/
+A2D_API extern void A2D_SbcDescramble(UINT8 *p_pkt, UINT16 len);
+
+/******************************************************************************
+**
+** Function A2D_BldSbcInfo
+**
+** Description This function is called by an application to build
+** the SBC Media Codec Capabilities byte sequence
+** beginning from the LOSC octet.
+** Input Parameters:
+** media_type: Indicates Audio, or Multimedia.
+**
+** p_ie: The SBC Codec Information Element information.
+**
+** Output Parameters:
+** p_result: the resulting codec info byte sequence.
+**
+** Returns A2D_SUCCESS if function execution succeeded.
+** Error status code, otherwise.
+******************************************************************************/
+A2D_API extern tA2D_STATUS A2D_BldSbcInfo(UINT8 media_type, tA2D_SBC_CIE *p_ie,
+ UINT8 *p_result);
+
+/******************************************************************************
+**
+** Function A2D_ParsSbcInfo
+**
+** Description This function is called by an application to parse
+** the SBC Media Codec Capabilities byte sequence
+** beginning from the LOSC octet.
+** Input Parameters:
+** p_info: the byte sequence to parse.
+**
+** for_caps: TRUE, if the byte sequence is for get capabilities response.
+**
+** Output Parameters:
+** p_ie: The SBC Codec Information Element information.
+**
+** Returns A2D_SUCCESS if function execution succeeded.
+** Error status code, otherwise.
+******************************************************************************/
+A2D_API extern tA2D_STATUS A2D_ParsSbcInfo(tA2D_SBC_CIE *p_ie, UINT8 *p_info,
+ BOOLEAN for_caps);
+
+/******************************************************************************
+**
+** Function A2D_BldSbcMplHdr
+**
+** Description This function is called by an application to parse
+** the SBC Media Payload header.
+** Input Parameters:
+** frag: 1, if fragmented. 0, otherwise.
+**
+** start: 1, if the starting packet of a fragmented frame.
+**
+** last: 1, if the last packet of a fragmented frame.
+**
+** num: If frag is 1, this is the number of remaining fragments
+** (including this fragment) of this frame.
+** If frag is 0, this is the number of frames in this packet.
+**
+** Output Parameters:
+** p_dst: the resulting media payload header byte sequence.
+**
+** Returns void.
+******************************************************************************/
+A2D_API extern void A2D_BldSbcMplHdr(UINT8 *p_dst, BOOLEAN frag, BOOLEAN start,
+ BOOLEAN last, UINT8 num);
+
+/******************************************************************************
+**
+** Function A2D_ParsSbcMplHdr
+**
+** Description This function is called by an application to parse
+** the SBC Media Payload header.
+** Input Parameters:
+** p_src: the byte sequence to parse..
+**
+** Output Parameters:
+** frag: 1, if fragmented. 0, otherwise.
+**
+** start: 1, if the starting packet of a fragmented frame.
+**
+** last: 1, if the last packet of a fragmented frame.
+**
+** num: If frag is 1, this is the number of remaining fragments
+** (including this fragment) of this frame.
+** If frag is 0, this is the number of frames in this packet.
+**
+** Returns void.
+******************************************************************************/
+A2D_API extern void A2D_ParsSbcMplHdr(UINT8 *p_src, BOOLEAN *p_frag,
+ BOOLEAN *p_start, BOOLEAN *p_last,
+ UINT8 *p_num);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* A2D_SBC_H */
diff --git a/stack/include/avct_api.h b/stack/include/avct_api.h
new file mode 100644
index 0000000..b4e819b
--- /dev/null
+++ b/stack/include/avct_api.h
@@ -0,0 +1,266 @@
+/*****************************************************************************
+**
+** Name: avct_api.h
+**
+** Description: This interface file contains the interface to the Audio
+** Video Control Transport Protocol (AVCTP).
+**
+** Copyright (c) 2003-2008, WIDCOMM Inc., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef AVCT_API_H
+#define AVCT_API_H
+
+#include "bt_types.h"
+#include "bt_target.h"
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+/* API function return value result codes. */
+#define AVCT_SUCCESS 0 /* Function successful */
+#define AVCT_NO_RESOURCES 1 /* Not enough resources */
+#define AVCT_BAD_HANDLE 2 /* Bad handle */
+#define AVCT_PID_IN_USE 3 /* PID already in use */
+#define AVCT_NOT_OPEN 4 /* Connection not open */
+
+/* PSM for AVCT. */
+#define AVCT_PSM 0x0017
+#define AVCT_BR_PSM 0x001B
+
+/* Protocol revision numbers */
+#define AVCT_REV_1_0 0x0100
+#define AVCT_REV_1_2 0x0102
+#define AVCT_REV_1_3 0x0103
+
+/* the layer_specific settings */
+#define AVCT_DATA_CTRL 0x0001 /* for the control channel */
+#define AVCT_DATA_BROWSE 0x0002 /* for the browsing channel */
+#define AVCT_DATA_PARTIAL 0x0100 /* Only have room for a partial message */
+
+#define AVCT_MIN_CONTROL_MTU 48 /* Per the AVRC spec, minimum MTU for the control channel */
+#define AVCT_MIN_BROWSE_MTU 335 /* Per the AVRC spec, minimum MTU for the browsing channel */
+
+/* Message offset. The number of bytes needed by the protocol stack for the
+** protocol headers of an AVCTP message packet.
+*/
+#define AVCT_MSG_OFFSET 15
+#define AVCT_BROWSE_OFFSET 17 /* the default offset for browsing channel */
+
+/* Connection role. */
+#define AVCT_INT 0 /* Initiator connection */
+#define AVCT_ACP 1 /* Acceptor connection */
+
+/* Control role. */
+#define AVCT_TARGET 1 /* target */
+#define AVCT_CONTROL 2 /* controller */
+#define AVCT_PASSIVE 4 /* If conflict, allow the other side to succeed */
+
+/* Command/Response indicator. */
+#define AVCT_CMD 0 /* Command message */
+#define AVCT_RSP 2 /* Response message */
+#define AVCT_REJ 3 /* Message rejected */
+
+/* Control callback events. */
+#define AVCT_CONNECT_CFM_EVT 0 /* Connection confirm */
+#define AVCT_CONNECT_IND_EVT 1 /* Connection indication */
+#define AVCT_DISCONNECT_CFM_EVT 2 /* Disconnect confirm */
+#define AVCT_DISCONNECT_IND_EVT 3 /* Disconnect indication */
+#define AVCT_CONG_IND_EVT 4 /* Congestion indication */
+#define AVCT_UNCONG_IND_EVT 5 /* Uncongestion indication */
+#define AVCT_BROWSE_CONN_CFM_EVT 6 /* Browse Connection confirm */
+#define AVCT_BROWSE_CONN_IND_EVT 7 /* Browse Connection indication */
+#define AVCT_BROWSE_DISCONN_CFM_EVT 8 /* Browse Disconnect confirm */
+#define AVCT_BROWSE_DISCONN_IND_EVT 9 /* Browse Disconnect indication */
+#define AVCT_BROWSE_CONG_IND_EVT 10 /* Congestion indication */
+#define AVCT_BROWSE_UNCONG_IND_EVT 11 /* Uncongestion indication */
+
+
+/* General purpose failure result code for callback events. */
+#define AVCT_RESULT_FAIL 5
+
+/*****************************************************************************
+** Type Definitions
+*****************************************************************************/
+
+/* Control callback function. */
+typedef void (tAVCT_CTRL_CBACK)(UINT8 handle, UINT8 event, UINT16 result,
+ BD_ADDR peer_addr);
+
+/* Message callback function */
+/* p_pkt->layer_specific is AVCT_DATA_CTRL or AVCT_DATA_BROWSE */
+typedef void (tAVCT_MSG_CBACK)(UINT8 handle, UINT8 label, UINT8 cr,
+ BT_HDR *p_pkt);
+
+/* Structure used by AVCT_CreateConn. */
+typedef struct {
+ tAVCT_CTRL_CBACK *p_ctrl_cback; /* Control callback */
+ tAVCT_MSG_CBACK *p_msg_cback; /* Message callback */
+ UINT16 pid; /* Profile ID */
+ UINT8 role; /* Initiator/acceptor role */
+ UINT8 control; /* Control role (Control/Target) */
+} tAVCT_CC;
+
+/*****************************************************************************
+** External Function Declarations
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*******************************************************************************
+**
+** Function AVCT_Register
+**
+** Description This is the system level registration function for the
+** AVCTP protocol. This function initializes AVCTP and
+** prepares the protocol stack for its use. This function
+** must be called once by the system or platform using AVCTP
+** before the other functions of the API an be used.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+AVCT_API extern void AVCT_Register(UINT16 mtu, UINT16 mtu_br, UINT8 sec_mask);
+
+/*******************************************************************************
+**
+** Function AVCT_Deregister
+**
+** Description This function is called to deregister use AVCTP protocol.
+** It is called when AVCTP is no longer being used by any
+** application in the system. Before this function can be
+** called, all connections must be removed with
+** AVCT_RemoveConn().
+**
+**
+** Returns void
+**
+*******************************************************************************/
+AVCT_API extern void AVCT_Deregister(void);
+
+/*******************************************************************************
+**
+** Function AVCT_CreateConn
+**
+** Description Create an AVCTP connection. There are two types of
+** connections, initiator and acceptor, as determined by
+** the p_cc->role parameter. When this function is called to
+** create an initiator connection, an AVCTP connection to
+** the peer device is initiated if one does not already exist.
+** If an acceptor connection is created, the connection waits
+** passively for an incoming AVCTP connection from a peer device.
+**
+**
+** Returns AVCT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+AVCT_API extern UINT16 AVCT_CreateConn(UINT8 *p_handle, tAVCT_CC *p_cc,
+ BD_ADDR peer_addr);
+
+/*******************************************************************************
+**
+** Function AVCT_RemoveConn
+**
+** Description Remove an AVCTP connection. This function is called when
+** the application is no longer using a connection. If this
+** is the last connection to a peer the L2CAP channel for AVCTP
+** will be closed.
+**
+**
+** Returns AVCT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+AVCT_API extern UINT16 AVCT_RemoveConn(UINT8 handle);
+
+/*******************************************************************************
+**
+** Function AVCT_CreateBrowse
+**
+** Description Create an AVCTP connection. There are two types of
+** connections, initiator and acceptor, as determined by
+** the p_cc->role parameter. When this function is called to
+** create an initiator connection, an AVCTP connection to
+** the peer device is initiated if one does not already exist.
+** If an acceptor connection is created, the connection waits
+** passively for an incoming AVCTP connection from a peer device.
+**
+**
+** Returns AVCT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+AVCT_API extern UINT16 AVCT_CreateBrowse(UINT8 handle, UINT8 role);
+
+/*******************************************************************************
+**
+** Function AVCT_RemoveBrowse
+**
+** Description Remove an AVCTP connection. This function is called when
+** the application is no longer using a connection. If this
+** is the last connection to a peer the L2CAP channel for AVCTP
+** will be closed.
+**
+**
+** Returns AVCT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+AVCT_API extern UINT16 AVCT_RemoveBrowse(UINT8 handle);
+
+/*******************************************************************************
+**
+** Function AVCT_GetBrowseMtu
+**
+** Description Get the peer_mtu for the AVCTP Browse channel of the given
+** connection.
+**
+** Returns the peer browsing channel MTU.
+**
+*******************************************************************************/
+AVCT_API extern UINT16 AVCT_GetBrowseMtu (UINT8 handle);
+
+/*******************************************************************************
+**
+** Function AVCT_GetPeerMtu
+**
+** Description Get the peer_mtu for the AVCTP channel of the given
+** connection.
+**
+** Returns the peer MTU size.
+**
+*******************************************************************************/
+AVCT_API extern UINT16 AVCT_GetPeerMtu (UINT8 handle);
+
+/*******************************************************************************
+**
+** Function AVCT_MsgReq
+**
+** Description Send an AVCTP message to a peer device. In calling
+** AVCT_MsgReq(), the application should keep track of the
+** congestion state of AVCTP as communicated with events
+** AVCT_CONG_IND_EVT and AVCT_UNCONG_IND_EVT. If the
+** application calls AVCT_MsgReq() when AVCTP is congested
+** the message may be discarded. The application may make its
+** first call to AVCT_MsgReq() after it receives an
+** AVCT_CONNECT_CFM_EVT or AVCT_CONNECT_IND_EVT on control channel or
+** AVCT_BROWSE_CONN_CFM_EVT or AVCT_BROWSE_CONN_IND_EVT on browsing channel.
+**
+** p_msg->layer_specific must be set to
+** AVCT_DATA_CTRL for control channel traffic;
+** AVCT_DATA_BROWSE for for browse channel traffic.
+**
+** Returns AVCT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+AVCT_API extern UINT16 AVCT_MsgReq(UINT8 handle, UINT8 label, UINT8 cr, BT_HDR *p_msg);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* AVCT_API_H */
+
diff --git a/stack/include/avdt_api.h b/stack/include/avdt_api.h
new file mode 100644
index 0000000..317386e
--- /dev/null
+++ b/stack/include/avdt_api.h
@@ -0,0 +1,889 @@
+/*****************************************************************************
+**
+** Name: avdt_api.h
+**
+** Description: This interface file contains the interface to the Audio
+** Video Distribution Transport Protocol (AVDTP).
+**
+** Copyright (c) 2002-2009, Broadcom Corp., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef AVDT_API_H
+#define AVDT_API_H
+
+#include "bt_types.h"
+#include "bt_target.h"
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+#ifndef AVDT_VERSION
+#define AVDT_VERSION 0x0102
+#endif
+#define AVDT_VERSION_SYNC 0x0103
+
+/* API function return value result codes. */
+#define AVDT_SUCCESS 0 /* Function successful */
+#define AVDT_BAD_PARAMS 1 /* Invalid parameters */
+#define AVDT_NO_RESOURCES 2 /* Not enough resources */
+#define AVDT_BAD_HANDLE 3 /* Bad handle */
+#define AVDT_BUSY 4 /* A procedure is already in progress */
+#define AVDT_WRITE_FAIL 5 /* Write failed */
+
+/* The index to access the codec type in codec_info[]. */
+#define AVDT_CODEC_TYPE_INDEX 2
+
+/* The size in bytes of a Adaptation Layer header. */
+#define AVDT_AL_HDR_SIZE 3
+
+/* The size in bytes of a media packet header. */
+#define AVDT_MEDIA_HDR_SIZE 12
+
+/* AVDTP 7.5.3 Adaptation Layer Fragmentation
+ * original length of the un-fragmented transport packet should be specified by
+ * two bytes length field of Adaptation Layer Header */
+#define AVDT_MAX_MEDIA_SIZE (0xFFFF - AVDT_MEDIA_HDR_SIZE)
+
+/* The handle is used when reporting MULTI_AV specific events */
+#define AVDT_MULTI_AV_HANDLE 0xFF
+
+/* The number of bytes needed by the protocol stack for the protocol headers
+** of a media packet. This is the size of the media packet header, the
+** L2CAP packet header and HCI header.
+*/
+#define AVDT_MEDIA_OFFSET 23
+
+/* The marker bit is used by the application to mark significant events such
+** as frame boundaries in the data stream. This constant is used to check or
+** set the marker bit in the m_pt parameter of an AVDT_WriteReq()
+** or AVDT_DATA_IND_EVT.
+*/
+#define AVDT_MARKER_SET 0x80
+
+/* SEP Type. This indicates the stream endpoint type. */
+#define AVDT_TSEP_SRC 0 /* Source SEP */
+#define AVDT_TSEP_SNK 1 /* Sink SEP */
+
+/* initiator/acceptor role for adaption */
+#define AVDT_INT 0 /* initiator */
+#define AVDT_ACP 1 /* acceptor */
+
+/* Media Type. This indicates the media type of the stream endpoint. */
+#define AVDT_MEDIA_AUDIO 0 /* Audio SEP */
+#define AVDT_MEDIA_VIDEO 1 /* Video SEP */
+#define AVDT_MEDIA_MULTI 2 /* Multimedia SEP */
+
+/* for reporting packets */
+#define AVDT_RTCP_PT_SR 200 /* the packet type - SR (Sender Report) */
+#define AVDT_RTCP_PT_RR 201 /* the packet type - RR (Receiver Report) */
+#define AVDT_RTCP_PT_SDES 202 /* the packet type - SDES (Source Description) */
+typedef UINT8 AVDT_REPORT_TYPE;
+
+#define AVDT_RTCP_SDES_CNAME 1 /* SDES item CNAME */
+#ifndef AVDT_MAX_CNAME_SIZE
+#define AVDT_MAX_CNAME_SIZE 28
+#endif
+
+/* Protocol service capabilities. This indicates the protocol service
+** capabilities of a stream endpoint. This value is a mask.
+** Multiple values can be combined with a bitwise OR.
+*/
+#define AVDT_PSC_TRANS (1<<1) /* Media transport */
+#define AVDT_PSC_REPORT (1<<2) /* Reporting */
+#define AVDT_PSC_RECOV (1<<3) /* Recovery */
+#define AVDT_PSC_HDRCMP (1<<5) /* Header compression */
+#define AVDT_PSC_MUX (1<<6) /* Multiplexing */
+#define AVDT_PSC_DELAY_RPT (1<<8) /* Delay Report */
+
+/* Recovery type. This indicates the recovery type. */
+#define AVDT_RECOV_RFC2733 1 /* RFC2733 recovery */
+
+/* Header compression capabilities. This indicates the header compression
+** capabilities. This value is a mask. Multiple values can be combined
+** with a bitwise OR.
+*/
+#define AVDT_HDRCMP_MEDIA (1<<5) /* Available for media packets */
+#define AVDT_HDRCMP_RECOV (1<<6) /* Available for recovery packets */
+#define AVDT_HDRCMP_BACKCH (1<<7) /* Back channel supported */
+
+/* Multiplexing capabilities mask. */
+#define AVDT_MUX_FRAG (1<<7) /* Allow Adaptation Layer Fragmentation */
+
+/* Application service category. This indicates the application
+** service category.
+*/
+#define AVDT_ASC_PROTECT 4 /* Content protection */
+#define AVDT_ASC_CODEC 7 /* Codec */
+
+/* Error codes. The following are error codes defined in the AVDTP and GAVDP
+** specifications. These error codes communicate protocol errors between
+** AVDTP and the application. More detailed descriptions of the error codes
+** and their appropriate use can be found in the AVDTP and GAVDP specifications.
+** These error codes are unrelated to the result values returned by the
+** AVDTP API functions.
+*/
+#define AVDT_ERR_HEADER 0x01 /* Bad packet header format */
+#define AVDT_ERR_LENGTH 0x11 /* Bad packet length */
+#define AVDT_ERR_SEID 0x12 /* Invalid SEID */
+#define AVDT_ERR_IN_USE 0x13 /* The SEP is in use */
+#define AVDT_ERR_NOT_IN_USE 0x14 /* The SEP is not in use */
+#define AVDT_ERR_CATEGORY 0x17 /* Bad service category */
+#define AVDT_ERR_PAYLOAD 0x18 /* Bad payload format */
+#define AVDT_ERR_NSC 0x19 /* Requested command not supported */
+#define AVDT_ERR_INVALID_CAP 0x1A /* Reconfigure attempted invalid capabilities */
+#define AVDT_ERR_RECOV_TYPE 0x22 /* Requested recovery type not defined */
+#define AVDT_ERR_MEDIA_TRANS 0x23 /* Media transport capability not correct */
+#define AVDT_ERR_RECOV_FMT 0x25 /* Recovery service capability not correct */
+#define AVDT_ERR_ROHC_FMT 0x26 /* Header compression service capability not correct */
+#define AVDT_ERR_CP_FMT 0x27 /* Content protection service capability not correct */
+#define AVDT_ERR_MUX_FMT 0x28 /* Multiplexing service capability not correct */
+#define AVDT_ERR_UNSUP_CFG 0x29 /* Configuration not supported */
+#define AVDT_ERR_BAD_STATE 0x31 /* Message cannot be processed in this state */
+#define AVDT_ERR_REPORT_FMT 0x65 /* Report service capability not correct */
+#define AVDT_ERR_SERVICE 0x80 /* Invalid service category */
+#define AVDT_ERR_RESOURCE 0x81 /* Insufficient resources */
+#define AVDT_ERR_INVALID_MCT 0xC1 /* Invalid Media Codec Type */
+#define AVDT_ERR_UNSUP_MCT 0xC2 /* Unsupported Media Codec Type */
+#define AVDT_ERR_INVALID_LEVEL 0xC3 /* Invalid Level */
+#define AVDT_ERR_UNSUP_LEVEL 0xC4 /* Unsupported Level */
+#define AVDT_ERR_INVALID_CP 0xE0 /* Invalid Content Protection Type */
+#define AVDT_ERR_INVALID_FORMAT 0xE1 /* Invalid Content Protection format */
+
+/* Additional error codes. This indicates error codes used by AVDTP
+** in addition to the ones defined in the specifications.
+*/
+#define AVDT_ERR_CONNECT 0x07 /* Connection failed. */
+#define AVDT_ERR_TIMEOUT 0x08 /* Response timeout. */
+
+/* Control callback events. */
+#define AVDT_DISCOVER_CFM_EVT 0 /* Discover confirm */
+#define AVDT_GETCAP_CFM_EVT 1 /* Get capabilities confirm */
+#define AVDT_OPEN_CFM_EVT 2 /* Open confirm */
+#define AVDT_OPEN_IND_EVT 3 /* Open indication */
+#define AVDT_CONFIG_IND_EVT 4 /* Configuration indication */
+#define AVDT_START_CFM_EVT 5 /* Start confirm */
+#define AVDT_START_IND_EVT 6 /* Start indication */
+#define AVDT_SUSPEND_CFM_EVT 7 /* Suspend confirm */
+#define AVDT_SUSPEND_IND_EVT 8 /* Suspend indication */
+#define AVDT_CLOSE_CFM_EVT 9 /* Close confirm */
+#define AVDT_CLOSE_IND_EVT 10 /* Close indication */
+#define AVDT_RECONFIG_CFM_EVT 11 /* Reconfiguration confirm */
+#define AVDT_RECONFIG_IND_EVT 12 /* Reconfiguration indication */
+#define AVDT_SECURITY_CFM_EVT 13 /* Security confirm */
+#define AVDT_SECURITY_IND_EVT 14 /* Security indication */
+#define AVDT_WRITE_CFM_EVT 15 /* Write confirm */
+#define AVDT_CONNECT_IND_EVT 16 /* Signaling channel connected */
+#define AVDT_DISCONNECT_IND_EVT 17 /* Signaling channel disconnected */
+#define AVDT_REPORT_CONN_EVT 18 /* Reporting channel connected */
+#define AVDT_REPORT_DISCONN_EVT 19 /* Reporting channel disconnected */
+#define AVDT_DELAY_REPORT_EVT 20 /* Delay report received */
+#define AVDT_DELAY_REPORT_CFM_EVT 21 /* Delay report response received */
+
+#define AVDT_MAX_EVT (AVDT_DELAY_REPORT_CFM_EVT)
+
+/* PSM for AVDT */
+#define AVDT_PSM 0x0019
+
+/* Nonsupported protocol command messages. This value is used in tAVDT_CS */
+#define AVDT_NSC_SUSPEND 0x01 /* Suspend command not supported */
+#define AVDT_NSC_RECONFIG 0x02 /* Reconfigure command not supported */
+#define AVDT_NSC_SECURITY 0x04 /* Security command not supported */
+
+/*****************************************************************************
+** Type Definitions
+*****************************************************************************/
+
+typedef struct
+{
+ UINT32 ntp_sec; /* NTP time: seconds relative to 0h UTC on 1 January 1900 */
+ UINT32 ntp_frac; /* NTP time: the fractional part */
+ UINT32 rtp_time; /* timestamp in RTP header */
+ UINT32 pkt_count; /* sender's packet count: since starting transmission
+ * up until the time this SR packet was generated. */
+ UINT32 octet_count; /* sender's octet count: same comment */
+} tAVDT_SENDER_INFO;
+
+typedef struct
+{
+ UINT8 frag_lost; /* fraction lost since last RR */
+ UINT32 packet_lost; /* cumulative number of packets lost since the beginning */
+ UINT32 seq_num_rcvd; /* extended highest sequence number received */
+ UINT32 jitter; /* interarrival jitter */
+ UINT32 lsr; /* last SR timestamp */
+ UINT32 dlsr; /* delay since last SR */
+} tAVDT_REPORT_BLK;
+
+typedef union
+{
+ tAVDT_SENDER_INFO sr;
+ tAVDT_REPORT_BLK rr;
+ UINT8 cname[AVDT_MAX_CNAME_SIZE + 1];
+} tAVDT_REPORT_DATA;
+
+/* This structure contains parameters which are set at registration. */
+typedef struct {
+ UINT16 ctrl_mtu; /* L2CAP MTU of the AVDTP signaling channel */
+ UINT8 ret_tout; /* AVDTP signaling retransmission timeout */
+ UINT8 sig_tout; /* AVDTP signaling message timeout */
+ UINT8 idle_tout; /* AVDTP idle signaling channel timeout */
+ UINT8 sec_mask; /* Security mask for BTM_SetSecurityLevel() */
+} tAVDT_REG;
+
+/* This structure contains the SEP information. This information is
+** transferred during the discovery procedure.
+*/
+typedef struct {
+ BOOLEAN in_use; /* TRUE if stream is currently in use */
+ UINT8 seid; /* Stream endpoint identifier */
+ UINT8 media_type; /* Media type */
+ UINT8 tsep; /* SEP type */
+} tAVDT_SEP_INFO;
+
+/* This structure contains the SEP configuration. */
+typedef struct {
+ UINT8 codec_info[AVDT_CODEC_SIZE]; /* Codec capabilities array */
+ UINT8 protect_info[AVDT_PROTECT_SIZE]; /* Content protection capabilities */
+ UINT8 num_codec; /* Number of media codec information elements */
+ UINT8 num_protect; /* Number of content protection information elements */
+ UINT16 psc_mask; /* Protocol service capabilities mask */
+ UINT8 recov_type; /* Recovery type */
+ UINT8 recov_mrws; /* Maximum recovery window size */
+ UINT8 recov_mnmp; /* Recovery maximum number of media packets */
+ UINT8 hdrcmp_mask; /* Header compression capabilities */
+#if AVDT_MULTIPLEXING == TRUE
+ UINT8 mux_mask; /* Multiplexing capabilities. AVDT_MUX_XXX bits can be combined with a bitwise OR */
+ UINT8 mux_tsid_media; /* TSID for media transport session */
+ UINT8 mux_tcid_media; /* TCID for media transport session */
+ UINT8 mux_tsid_report; /* TSID for reporting transport session */
+ UINT8 mux_tcid_report; /* TCID for reporting transport session */
+ UINT8 mux_tsid_recov; /* TSID for recovery transport session */
+ UINT8 mux_tcid_recov; /* TCID for recovery transport session */
+#endif
+} tAVDT_CFG;
+
+/* Header structure for callback event parameters. */
+typedef struct {
+ UINT8 err_code; /* Zero if operation succeeded; nonzero if operation failed */
+ UINT8 err_param; /* Error parameter included for some events */
+ UINT8 label; /* Transaction label */
+ UINT8 seid; /* For internal use only */
+ UINT8 sig_id; /* For internal use only */
+ UINT8 ccb_idx; /* For internal use only */
+} tAVDT_EVT_HDR;
+
+/* This data structure is associated with the AVDT_GETCAP_CFM_EVT,
+** AVDT_RECONFIG_IND_EVT, and AVDT_RECONFIG_CFM_EVT.
+*/
+typedef struct {
+ tAVDT_EVT_HDR hdr; /* Event header */
+ tAVDT_CFG *p_cfg; /* Pointer to configuration for this SEP */
+} tAVDT_CONFIG;
+
+/* This data structure is associated with the AVDT_CONFIG_IND_EVT. */
+typedef struct {
+ tAVDT_EVT_HDR hdr; /* Event header */
+ tAVDT_CFG *p_cfg; /* Pointer to configuration for this SEP */
+ UINT8 int_seid; /* Stream endpoint ID of stream initiating the operation */
+} tAVDT_SETCONFIG;
+
+/* This data structure is associated with the AVDT_OPEN_IND_EVT and AVDT_OPEN_CFM_EVT. */
+typedef struct {
+ tAVDT_EVT_HDR hdr; /* Event header */
+ UINT16 peer_mtu; /* Transport channel L2CAP MTU of the peer */
+ UINT16 lcid; /* L2CAP LCID for media channel */
+} tAVDT_OPEN;
+
+/* This data structure is associated with the AVDT_SECURITY_IND_EVT
+** and AVDT_SECURITY_CFM_EVT.
+*/
+typedef struct {
+ tAVDT_EVT_HDR hdr; /* Event header */
+ UINT8 *p_data; /* Pointer to security data */
+ UINT16 len; /* Length in bytes of the security data */
+} tAVDT_SECURITY;
+
+/* This data structure is associated with the AVDT_DISCOVER_CFM_EVT. */
+typedef struct {
+ tAVDT_EVT_HDR hdr; /* Event header */
+ tAVDT_SEP_INFO *p_sep_info; /* Pointer to SEP information */
+ UINT8 num_seps; /* Number of stream endpoints */
+} tAVDT_DISCOVER;
+
+/* This data structure is associated with the AVDT_DELAY_REPORT_EVT. */
+typedef struct {
+ tAVDT_EVT_HDR hdr; /* Event header */
+ UINT16 delay; /* Delay value */
+} tAVDT_DELAY_RPT;
+
+/* Union of all control callback event data structures */
+typedef union {
+ tAVDT_EVT_HDR hdr;
+ tAVDT_DISCOVER discover_cfm;
+ tAVDT_CONFIG getcap_cfm;
+ tAVDT_OPEN open_cfm;
+ tAVDT_OPEN open_ind;
+ tAVDT_SETCONFIG config_ind;
+ tAVDT_EVT_HDR start_cfm;
+ tAVDT_EVT_HDR suspend_cfm;
+ tAVDT_EVT_HDR close_cfm;
+ tAVDT_CONFIG reconfig_cfm;
+ tAVDT_CONFIG reconfig_ind;
+ tAVDT_SECURITY security_cfm;
+ tAVDT_SECURITY security_ind;
+ tAVDT_EVT_HDR connect_ind;
+ tAVDT_EVT_HDR disconnect_ind;
+ tAVDT_EVT_HDR report_conn;
+ tAVDT_DELAY_RPT delay_rpt_cmd;
+} tAVDT_CTRL;
+
+/* This is the control callback function. This function passes control events
+** to the application. This function is required for all registered stream
+** endpoints and for the AVDT_DiscoverReq() and AVDT_GetCapReq() functions.
+**
+*/
+typedef void (tAVDT_CTRL_CBACK)(UINT8 handle, BD_ADDR bd_addr, UINT8 event,
+ tAVDT_CTRL *p_data);
+
+/* This is the data callback function. It is executed when AVDTP has a media
+** packet ready for the application. This function is required for SNK
+** endpoints and not applicable for SRC endpoints.
+*/
+typedef void (tAVDT_DATA_CBACK)(UINT8 handle, BT_HDR *p_pkt, UINT32 time_stamp,
+ UINT8 m_pt);
+
+#if AVDT_MULTIPLEXING == TRUE
+/* This is the second version of the data callback function. This version uses
+** application buffer assigned by AVDT_SetMediaBuf. Caller can assign different
+** buffer during callback or can leave the current buffer for further using.
+** This callback is called when AVDTP has a media packet ready for the application.
+** This function is required for SNK endpoints and not applicable for SRC endpoints.
+*/
+typedef void (tAVDT_MEDIA_CBACK)(UINT8 handle, UINT8 *p_payload, UINT32 payload_len,
+ UINT32 time_stamp, UINT16 seq_num, UINT8 m_pt, UINT8 marker);
+#endif
+
+#if AVDT_REPORTING == TRUE
+/* This is the report callback function. It is executed when AVDTP has a reporting
+** packet ready for the application. This function is required for streams
+** created with AVDT_PSC_REPORT.
+*/
+typedef void (tAVDT_REPORT_CBACK)(UINT8 handle, AVDT_REPORT_TYPE type,
+ tAVDT_REPORT_DATA *p_data);
+#endif
+
+typedef UINT16 (tAVDT_GETCAP_REQ) (BD_ADDR bd_addr, UINT8 seid, tAVDT_CFG *p_cfg, tAVDT_CTRL_CBACK *p_cback);
+
+/* This structure contains information required when a stream is created.
+** It is passed to the AVDT_CreateStream() function.
+*/
+typedef struct {
+ tAVDT_CFG cfg; /* SEP configuration */
+ tAVDT_CTRL_CBACK *p_ctrl_cback; /* Control callback function */
+ tAVDT_DATA_CBACK *p_data_cback; /* Data callback function */
+#if AVDT_MULTIPLEXING == TRUE
+ tAVDT_MEDIA_CBACK *p_media_cback; /* Media callback function. It will be called only if p_data_cback is NULL */
+#endif
+#if AVDT_REPORTING == TRUE
+ tAVDT_REPORT_CBACK *p_report_cback;/* Report callback function. */
+#endif
+ UINT16 mtu; /* The L2CAP MTU of the transport channel */
+ UINT16 flush_to; /* The L2CAP flush timeout of the transport channel */
+ UINT8 tsep; /* SEP type */
+ UINT8 media_type; /* Media type */
+ UINT16 nsc_mask; /* Nonsupported protocol command messages */
+} tAVDT_CS;
+
+
+/*****************************************************************************
+** External Function Declarations
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*******************************************************************************
+**
+** Function AVDT_Register
+**
+** Description This is the system level registration function for the
+** AVDTP protocol. This function initializes AVDTP and
+** prepares the protocol stack for its use. This function
+** must be called once by the system or platform using AVDTP
+** before the other functions of the API an be used.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+AVDT_API extern void AVDT_Register(tAVDT_REG *p_reg, tAVDT_CTRL_CBACK *p_cback);
+
+/*******************************************************************************
+**
+** Function AVDT_Deregister
+**
+** Description This function is called to deregister use AVDTP protocol.
+** It is called when AVDTP is no longer being used by any
+** application in the system. Before this function can be
+** called, all streams must be removed with AVDT_RemoveStream().
+**
+**
+** Returns void
+**
+*******************************************************************************/
+AVDT_API extern void AVDT_Deregister(void);
+
+/*******************************************************************************
+**
+** Function AVDT_CreateStream
+**
+** Description Create a stream endpoint. After a stream endpoint is
+** created an application can initiate a connection between
+** this endpoint and an endpoint on a peer device. In
+** addition, a peer device can discover, get the capabilities,
+** and connect to this endpoint.
+**
+**
+** Returns AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+AVDT_API extern UINT16 AVDT_CreateStream(UINT8 *p_handle, tAVDT_CS *p_cs);
+
+/*******************************************************************************
+**
+** Function AVDT_RemoveStream
+**
+** Description Remove a stream endpoint. This function is called when
+** the application is no longer using a stream endpoint.
+** If this function is called when the endpoint is connected
+** the connection is closed and then the stream endpoint
+** is removed.
+**
+**
+** Returns AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+AVDT_API extern UINT16 AVDT_RemoveStream(UINT8 handle);
+
+/*******************************************************************************
+**
+** Function AVDT_DiscoverReq
+**
+** Description This function initiates a connection to the AVDTP service
+** on the peer device, if not already present, and discovers
+** the stream endpoints on the peer device. (Please note
+** that AVDTP discovery is unrelated to SDP discovery).
+** This function can be called at any time regardless of whether
+** there is an AVDTP connection to the peer device.
+**
+** When discovery is complete, an AVDT_DISCOVER_CFM_EVT
+** is sent to the application via its callback function.
+** The application must not call AVDT_GetCapReq() or
+** AVDT_DiscoverReq() again to the same device until
+** discovery is complete.
+**
+** The memory addressed by sep_info is allocated by the
+** application. This memory is written to by AVDTP as part
+** of the discovery procedure. This memory must remain
+** accessible until the application receives the
+** AVDT_DISCOVER_CFM_EVT.
+**
+** Returns AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+AVDT_API extern UINT16 AVDT_DiscoverReq(BD_ADDR bd_addr, tAVDT_SEP_INFO *p_sep_info,
+ UINT8 max_seps, tAVDT_CTRL_CBACK *p_cback);
+
+
+/*******************************************************************************
+**
+** Function AVDT_GetCapReq
+**
+** Description This function initiates a connection to the AVDTP service
+** on the peer device, if not already present, and gets the
+** capabilities of a stream endpoint on the peer device.
+** This function can be called at any time regardless of
+** whether there is an AVDTP connection to the peer device.
+**
+** When the procedure is complete, an AVDT_GETCAP_CFM_EVT is
+** sent to the application via its callback function. The
+** application must not call AVDT_GetCapReq() or
+** AVDT_DiscoverReq() again until the procedure is complete.
+**
+** The memory pointed to by p_cfg is allocated by the
+** application. This memory is written to by AVDTP as part
+** of the get capabilities procedure. This memory must
+** remain accessible until the application receives
+** the AVDT_GETCAP_CFM_EVT.
+**
+** Returns AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+AVDT_API extern UINT16 AVDT_GetCapReq(BD_ADDR bd_addr, UINT8 seid, tAVDT_CFG *p_cfg,
+ tAVDT_CTRL_CBACK *p_cback);
+
+/*******************************************************************************
+**
+** Function AVDT_GetAllCapReq
+**
+** Description This function initiates a connection to the AVDTP service
+** on the peer device, if not already present, and gets the
+** capabilities of a stream endpoint on the peer device.
+** This function can be called at any time regardless of
+** whether there is an AVDTP connection to the peer device.
+**
+** When the procedure is complete, an AVDT_GETCAP_CFM_EVT is
+** sent to the application via its callback function. The
+** application must not call AVDT_GetCapReq() or
+** AVDT_DiscoverReq() again until the procedure is complete.
+**
+** The memory pointed to by p_cfg is allocated by the
+** application. This memory is written to by AVDTP as part
+** of the get capabilities procedure. This memory must
+** remain accessible until the application receives
+** the AVDT_GETCAP_CFM_EVT.
+**
+** Returns AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+AVDT_API extern UINT16 AVDT_GetAllCapReq(BD_ADDR bd_addr, UINT8 seid, tAVDT_CFG *p_cfg,
+ tAVDT_CTRL_CBACK *p_cback);
+
+/*******************************************************************************
+**
+** Function AVDT_DelayReport
+**
+** Description This functions sends a Delay Report to the peer device
+** that is associated with a particular SEID.
+** This function is called by SNK device.
+**
+** Returns AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+AVDT_API extern UINT16 AVDT_DelayReport(UINT8 handle, UINT8 seid, UINT16 delay);
+
+/*******************************************************************************
+**
+** Function AVDT_OpenReq
+**
+** Description This function initiates a connection to the AVDTP service
+** on the peer device, if not already present, and connects
+** to a stream endpoint on a peer device. When the connection
+** is completed, an AVDT_OPEN_CFM_EVT is sent to the
+** application via the control callback function for this handle.
+**
+** Returns AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+AVDT_API extern UINT16 AVDT_OpenReq(UINT8 handle, BD_ADDR bd_addr, UINT8 seid,
+ tAVDT_CFG *p_cfg);
+
+
+/*******************************************************************************
+**
+** Function AVDT_ConfigRsp
+**
+** Description Respond to a configure request from the peer device. This
+** function must be called if the application receives an
+** AVDT_CONFIG_IND_EVT through its control callback.
+**
+**
+** Returns AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+AVDT_API extern UINT16 AVDT_ConfigRsp(UINT8 handle, UINT8 label, UINT8 error_code,
+ UINT8 category);
+
+/*******************************************************************************
+**
+** Function AVDT_StartReq
+**
+** Description Start one or more stream endpoints. This initiates the
+** transfer of media packets for the streams. All stream
+** endpoints must previously be opened. When the streams
+** are started, an AVDT_START_CFM_EVT is sent to the
+** application via the control callback function for each stream.
+**
+**
+** Returns AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+AVDT_API extern UINT16 AVDT_StartReq(UINT8 *p_handles, UINT8 num_handles);
+
+/*******************************************************************************
+**
+** Function AVDT_SuspendReq
+**
+** Description Suspend one or more stream endpoints. This suspends the
+** transfer of media packets for the streams. All stream
+** endpoints must previously be open and started. When the
+** streams are suspended, an AVDT_SUSPEND_CFM_EVT is sent to
+** the application via the control callback function for
+** each stream.
+**
+**
+** Returns AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+AVDT_API extern UINT16 AVDT_SuspendReq(UINT8 *p_handles, UINT8 num_handles);
+
+/*******************************************************************************
+**
+** Function AVDT_CloseReq
+**
+** Description Close a stream endpoint. This stops the transfer of media
+** packets and closes the transport channel associated with
+** this stream endpoint. When the stream is closed, an
+** AVDT_CLOSE_CFM_EVT is sent to the application via the
+** control callback function for this handle.
+**
+**
+** Returns AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+AVDT_API extern UINT16 AVDT_CloseReq(UINT8 handle);
+
+/*******************************************************************************
+**
+** Function AVDT_ReconfigReq
+**
+** Description Reconfigure a stream endpoint. This allows the application
+** to change the codec or content protection capabilities of
+** a stream endpoint after it has been opened. This function
+** can only be called if the stream is opened but not started
+** or if the stream has been suspended. When the procedure
+** is completed, an AVDT_RECONFIG_CFM_EVT is sent to the
+** application via the control callback function for this handle.
+**
+**
+** Returns AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+AVDT_API extern UINT16 AVDT_ReconfigReq(UINT8 handle, tAVDT_CFG *p_cfg);
+
+/*******************************************************************************
+**
+** Function AVDT_ReconfigRsp
+**
+** Description Respond to a reconfigure request from the peer device.
+** This function must be called if the application receives
+** an AVDT_RECONFIG_IND_EVT through its control callback.
+**
+**
+** Returns AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+AVDT_API extern UINT16 AVDT_ReconfigRsp(UINT8 handle, UINT8 label, UINT8 error_code,
+ UINT8 category);
+
+/*******************************************************************************
+**
+** Function AVDT_SecurityReq
+**
+** Description Send a security request to the peer device. When the
+** security procedure is completed, an AVDT_SECURITY_CFM_EVT
+** is sent to the application via the control callback function
+** for this handle. (Please note that AVDTP security procedures
+** are unrelated to Bluetooth link level security.)
+**
+**
+** Returns AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+AVDT_API extern UINT16 AVDT_SecurityReq(UINT8 handle, UINT8 *p_data, UINT16 len);
+
+/*******************************************************************************
+**
+** Function AVDT_SecurityRsp
+**
+** Description Respond to a security request from the peer device.
+** This function must be called if the application receives
+** an AVDT_SECURITY_IND_EVT through its control callback.
+** (Please note that AVDTP security procedures are unrelated
+** to Bluetooth link level security.)
+**
+**
+** Returns AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+AVDT_API extern UINT16 AVDT_SecurityRsp(UINT8 handle, UINT8 label, UINT8 error_code,
+ UINT8 *p_data, UINT16 len);
+
+/*******************************************************************************
+**
+** Function AVDT_WriteReq
+**
+** Description Send a media packet to the peer device. The stream must
+** be started before this function is called. Also, this
+** function can only be called if the stream is a SRC.
+**
+** When AVDTP has sent the media packet and is ready for the
+** next packet, an AVDT_WRITE_CFM_EVT is sent to the
+** application via the control callback. The application must
+** wait for the AVDT_WRITE_CFM_EVT before it makes the next
+** call to AVDT_WriteReq(). If the applications calls
+** AVDT_WriteReq() before it receives the event the packet
+** will not be sent. The application may make its first call
+** to AVDT_WriteReq() after it receives an AVDT_START_CFM_EVT
+** or AVDT_START_IND_EVT.
+**
+** The application passes the packet using the BT_HDR structure.
+** This structure is described in section 2.1. The offset
+** field must be equal to or greater than AVDT_MEDIA_OFFSET.
+** This allows enough space in the buffer for the L2CAP and
+** AVDTP headers.
+**
+** The memory pointed to by p_pkt must be a GKI buffer
+** allocated by the application. This buffer will be freed
+** by the protocol stack; the application must not free
+** this buffer.
+**
+**
+** Returns AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+AVDT_API extern UINT16 AVDT_WriteReq(UINT8 handle, BT_HDR *p_pkt, UINT32 time_stamp,
+ UINT8 m_pt);
+
+/*******************************************************************************
+**
+** Function AVDT_ConnectReq
+**
+** Description This function initiates an AVDTP signaling connection
+** to the peer device. When the connection is completed, an
+** AVDT_CONNECT_IND_EVT is sent to the application via its
+** control callback function. If the connection attempt fails
+** an AVDT_DISCONNECT_IND_EVT is sent. The security mask
+** parameter overrides the outgoing security mask set in
+** AVDT_Register().
+**
+** Returns AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+AVDT_API extern UINT16 AVDT_ConnectReq(BD_ADDR bd_addr, UINT8 sec_mask,
+ tAVDT_CTRL_CBACK *p_cback);
+
+/*******************************************************************************
+**
+** Function AVDT_DisconnectReq
+**
+** Description This function disconnect an AVDTP signaling connection
+** to the peer device. When disconnected an
+** AVDT_DISCONNECT_IND_EVT is sent to the application via its
+** control callback function.
+**
+** Returns AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+AVDT_API extern UINT16 AVDT_DisconnectReq(BD_ADDR bd_addr, tAVDT_CTRL_CBACK *p_cback);
+
+/*******************************************************************************
+**
+** Function AVDT_GetL2CapChannel
+**
+** Description Get the L2CAP CID used by the handle.
+**
+** Returns CID if successful, otherwise 0.
+**
+*******************************************************************************/
+AVDT_API extern UINT16 AVDT_GetL2CapChannel(UINT8 handle);
+
+/*******************************************************************************
+**
+** Function AVDT_GetSignalChannel
+**
+** Description Get the L2CAP CID used by the signal channel of the given handle.
+**
+** Returns CID if successful, otherwise 0.
+**
+*******************************************************************************/
+AVDT_API extern UINT16 AVDT_GetSignalChannel(UINT8 handle, BD_ADDR bd_addr);
+
+/*******************************************************************************
+**
+** Function AVDT_WriteDataReq
+**
+** Description Send a media packet to the peer device. The stream must
+** be started before this function is called. Also, this
+** function can only be called if the stream is a SRC.
+**
+** When AVDTP has sent the media packet and is ready for the
+** next packet, an AVDT_WRITE_CFM_EVT is sent to the
+** application via the control callback. The application must
+** wait for the AVDT_WRITE_CFM_EVT before it makes the next
+** call to AVDT_WriteDataReq(). If the applications calls
+** AVDT_WriteDataReq() before it receives the event the packet
+** will not be sent. The application may make its first call
+** to AVDT_WriteDataReq() after it receives an
+** AVDT_START_CFM_EVT or AVDT_START_IND_EVT.
+**
+** Returns AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+AVDT_API extern UINT16 AVDT_WriteDataReq(UINT8 handle, UINT8 *p_data, UINT32 data_len,
+ UINT32 time_stamp, UINT8 m_pt, UINT8 marker);
+
+/*******************************************************************************
+**
+** Function AVDT_SetMediaBuf
+**
+** Description Assigns buffer for media packets or forbids using of assigned
+** buffer if argument p_buf is NULL. This function can only
+** be called if the stream is a SNK.
+**
+** AVDTP uses this buffer to reassemble fragmented media packets.
+** When AVDTP receives a complete media packet, it calls the
+** p_media_cback assigned by AVDT_CreateStream().
+** This function can be called during callback to assign a
+** different buffer for next media packet or can leave the current
+** buffer for next packet.
+**
+** Returns AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+AVDT_API extern UINT16 AVDT_SetMediaBuf(UINT8 handle, UINT8 *p_buf, UINT32 buf_len);
+
+/*******************************************************************************
+**
+** Function AVDT_SendReport
+**
+** Description
+**
+**
+**
+** Returns
+**
+*******************************************************************************/
+AVDT_API extern UINT16 AVDT_SendReport(UINT8 handle, AVDT_REPORT_TYPE type,
+ tAVDT_REPORT_DATA *p_data);
+
+/******************************************************************************
+**
+** Function AVDT_SetTraceLevel
+**
+** Description Sets the trace level for AVDT. If 0xff is passed, the
+** current trace level is returned.
+**
+** Input Parameters:
+** new_level: The level to set the AVDT tracing to:
+** 0xff-returns the current setting.
+** 0-turns off tracing.
+** >= 1-Errors.
+** >= 2-Warnings.
+** >= 3-APIs.
+** >= 4-Events.
+** >= 5-Debug.
+**
+** Returns The new trace level or current trace level if
+** the input parameter is 0xff.
+**
+******************************************************************************/
+AVDT_API extern UINT8 AVDT_SetTraceLevel (UINT8 new_level);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* AVDT_API_H */
diff --git a/stack/include/avdtc_api.h b/stack/include/avdtc_api.h
new file mode 100644
index 0000000..3b43221
--- /dev/null
+++ b/stack/include/avdtc_api.h
@@ -0,0 +1,219 @@
+/*****************************************************************************
+**
+** Name: avdt_capi.h
+**
+** Description: This interface file contains the interface AVDTP
+** conformance API. These additional API functions and
+** callback events are provided for conformance testing
+** purposes only. They are not intended to be used by
+** an application.
+**
+** Copyright (c) 2002-2009, Broadcom Corp., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef AVDT_CAPI_H
+#define AVDT_CAPI_H
+
+#include "avdt_api.h"
+
+/* start AVDTC events here to distinguish from AVDT events */
+#define AVDTC_EVT_BEGIN 0x80
+
+#define AVDTC_DISCOVER_IND_EVT (0 + AVDTC_EVT_BEGIN) /* Discover indication */
+#define AVDTC_GETCAP_IND_EVT (1 + AVDTC_EVT_BEGIN) /* Get capabilities indication */
+#define AVDTC_SETCONFIG_CFM_EVT (2 + AVDTC_EVT_BEGIN) /* Set configuration confirm */
+#define AVDTC_GETCONFIG_IND_EVT (3 + AVDTC_EVT_BEGIN) /* Get configuration indication */
+#define AVDTC_GETCONFIG_CFM_EVT (4 + AVDTC_EVT_BEGIN) /* Get configuration confirm */
+#define AVDTC_OPEN_IND_EVT (5 + AVDTC_EVT_BEGIN) /* Open indication */
+#define AVDTC_START_IND_EVT (6 + AVDTC_EVT_BEGIN) /* Start indication */
+#define AVDTC_CLOSE_IND_EVT (7 + AVDTC_EVT_BEGIN) /* Close indication */
+#define AVDTC_SUSPEND_IND_EVT (8 + AVDTC_EVT_BEGIN) /* Suspend indication */
+#define AVDTC_ABORT_IND_EVT (9 + AVDTC_EVT_BEGIN) /* Abort indication */
+#define AVDTC_ABORT_CFM_EVT (10 + AVDTC_EVT_BEGIN) /* Abort confirm */
+
+typedef struct {
+ tAVDT_EVT_HDR hdr; /* Event header */
+ UINT8 seid_list[AVDT_NUM_SEPS]; /* Array of SEID values */
+ UINT8 num_seps; /* Number of values in array */
+} tAVDT_MULTI;
+
+/* Union of all control callback event data structures */
+typedef union {
+ tAVDT_EVT_HDR hdr;
+ tAVDT_CONFIG getconfig_cfm;
+ tAVDT_MULTI start_ind;
+ tAVDT_MULTI suspend_ind;
+} tAVDTC_CTRL;
+
+typedef void tAVDTC_CTRL_CBACK(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDTC_CTRL *p_data);
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*******************************************************************************
+**
+** Function AVDTC_Init
+**
+** Description This function is called to begin using the conformance API.
+** It must be called after AVDT_Register() and before any
+** other API or conformance API functions are called.
+**
+** Returns void
+**
+*******************************************************************************/
+AVDT_API extern void AVDTC_Init(tAVDTC_CTRL_CBACK *p_cback);
+
+/*******************************************************************************
+**
+** Function AVDTC_DiscoverRsp
+**
+** Description Send a discover response.
+**
+** Returns void
+**
+*******************************************************************************/
+AVDT_API extern void AVDTC_DiscoverRsp(BD_ADDR bd_addr, UINT8 label,
+ tAVDT_SEP_INFO sep_info[], UINT8 num_seps);
+
+/*******************************************************************************
+**
+** Function AVDTC_GetCapRsp
+**
+** Description Send a get capabilities response.
+**
+** Returns void
+**
+*******************************************************************************/
+AVDT_API extern void AVDTC_GetCapRsp(BD_ADDR bd_addr, UINT8 label, tAVDT_CFG *p_cap);
+
+/*******************************************************************************
+**
+** Function AVDTC_GetAllCapRsp
+**
+** Description Send a get all capabilities response.
+**
+** Returns void
+**
+*******************************************************************************/
+AVDT_API extern void AVDTC_GetAllCapRsp(BD_ADDR bd_addr, UINT8 label, tAVDT_CFG *p_cap);
+
+/*******************************************************************************
+**
+** Function AVDTC_GetConfigReq
+**
+** Description Send a get configuration request.
+**
+** Returns void
+**
+*******************************************************************************/
+AVDT_API extern void AVDTC_GetConfigReq(UINT8 handle);
+
+/*******************************************************************************
+**
+** Function AVDTC_GetConfigRsp
+**
+** Description Send a get configuration response.
+**
+** Returns void
+**
+*******************************************************************************/
+AVDT_API extern void AVDTC_GetConfigRsp(UINT8 handle, UINT8 label, tAVDT_CFG *p_cfg);
+
+/*******************************************************************************
+**
+** Function AVDTC_OpenReq
+**
+** Description Send an open request.
+**
+** Returns void
+**
+*******************************************************************************/
+AVDT_API extern void AVDTC_OpenReq(UINT8 handle);
+
+/*******************************************************************************
+**
+** Function AVDTC_OpenRsp
+**
+** Description Send an open response.
+**
+** Returns void
+**
+*******************************************************************************/
+AVDT_API extern void AVDTC_OpenRsp(UINT8 handle, UINT8 label);
+
+/*******************************************************************************
+**
+** Function AVDTC_StartRsp
+**
+** Description Send a start response.
+**
+** Returns void
+**
+*******************************************************************************/
+AVDT_API extern void AVDTC_StartRsp(UINT8 *p_handles, UINT8 num_handles, UINT8 label);
+
+/*******************************************************************************
+**
+** Function AVDTC_CloseRsp
+**
+** Description Send a close response.
+**
+** Returns void
+**
+*******************************************************************************/
+AVDT_API extern void AVDTC_CloseRsp(UINT8 handle, UINT8 label);
+
+/*******************************************************************************
+**
+** Function AVDTC_SuspendRsp
+**
+** Description Send a suspend response.
+**
+** Returns void
+**
+*******************************************************************************/
+AVDT_API extern void AVDTC_SuspendRsp(UINT8 *p_handles, UINT8 num_handles, UINT8 label);
+
+/*******************************************************************************
+**
+** Function AVDTC_AbortReq
+**
+** Description Send an abort request.
+**
+** Returns void
+**
+*******************************************************************************/
+AVDT_API extern void AVDTC_AbortReq(UINT8 handle);
+
+/*******************************************************************************
+**
+** Function AVDTC_AbortRsp
+**
+** Description Send an abort response.
+**
+** Returns void
+**
+*******************************************************************************/
+AVDT_API extern void AVDTC_AbortRsp(UINT8 handle, UINT8 label);
+
+/*******************************************************************************
+**
+** Function AVDTC_Rej
+**
+** Description Send a reject message.
+**
+** Returns void
+**
+*******************************************************************************/
+AVDT_API extern void AVDTC_Rej(UINT8 handle, BD_ADDR bd_addr, UINT8 cmd, UINT8 label,
+ UINT8 err_code, UINT8 err_param);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVDT_CAPI_H */
+
diff --git a/stack/include/avrc_api.h b/stack/include/avrc_api.h
new file mode 100644
index 0000000..859c872
--- /dev/null
+++ b/stack/include/avrc_api.h
@@ -0,0 +1,621 @@
+/*****************************************************************************
+**
+** Name: avrc_api.h
+**
+** Description:Interface to AVRCP Application Programming Interface
+**
+** Copyright (c) 2006-2009, Broadcom Corp., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef AVRC_API_H
+#define AVRC_API_H
+
+#include "avct_api.h"
+#include "sdp_api.h"
+#include "avrc_defs.h"
+
+/*****************************************************************************
+** constants
+*****************************************************************************/
+
+/* API function return value result codes. */
+#define AVRC_SUCCESS AVCT_SUCCESS /* 0 Function successful */
+#define AVRC_NO_RESOURCES AVCT_NO_RESOURCES /* 1 Not enough resources */
+#define AVRC_BAD_HANDLE AVCT_BAD_HANDLE /* 2 Bad handle */
+#define AVRC_PID_IN_USE AVCT_PID_IN_USE /* 3 PID already in use */
+#define AVRC_NOT_OPEN AVCT_NOT_OPEN /* 4 Connection not open */
+#define AVRC_MSG_TOO_BIG 5 /* 5 the message length exceed the MTU of the browsing channel */
+#define AVRC_FAIL 0x10 /* 0x10 generic failure */
+#define AVRC_BAD_PARAM 0x11 /* 0x11 bad parameter */
+
+/* Control role - same as AVCT_TARGET/AVCT_CONTROL */
+#define AVRC_CT_TARGET 1 /* target */
+#define AVRC_CT_CONTROL 2 /* controller */
+#define AVRC_CT_PASSIVE 4 /* If conflict, allow the other side to succeed */
+
+/* Connection role */
+#define AVRC_CONN_INT AVCT_INT /* initiator */
+#define AVRC_CONN_ACP AVCT_ACP /* Acceptor */
+
+
+/* AVRC CTRL events */
+/* AVRC_OPEN_IND_EVT event is sent when the connection is successfully opened.
+ * This eventis sent in response to an AVRC_Open(). */
+#define AVRC_OPEN_IND_EVT 0
+
+/* AVRC_CLOSE_IND_EVT event is sent when a connection is closed.
+ * This event can result from a call to AVRC_Close() or when the peer closes
+ * the connection. It is also sent when a connection attempted through
+ * AVRC_Open() fails. */
+#define AVRC_CLOSE_IND_EVT 1
+
+/* AVRC_CONG_IND_EVT event indicates that AVCTP is congested and cannot send
+ * any more messages. */
+#define AVRC_CONG_IND_EVT 2
+
+/* AVRC_UNCONG_IND_EVT event indicates that AVCTP is uncongested and ready to
+ * send messages. */
+#define AVRC_UNCONG_IND_EVT 3
+
+ /* AVRC_BROWSE_OPEN_IND_EVT event is sent when the browse channel is successfully opened.
+ * This eventis sent in response to an AVRC_Open() or AVRC_OpenBrowse() . */
+#define AVRC_BROWSE_OPEN_IND_EVT 4
+
+/* AVRC_BROWSE_CLOSE_IND_EVT event is sent when a browse channel is closed.
+ * This event can result from a call to AVRC_Close(), AVRC_CloseBrowse() or when the peer closes
+ * the connection. It is also sent when a connection attempted through
+ * AVRC_OpenBrowse() fails. */
+#define AVRC_BROWSE_CLOSE_IND_EVT 5
+
+/* AVRC_BROWSE_CONG_IND_EVT event indicates that AVCTP browse channel is congested and cannot send
+ * any more messages. */
+#define AVRC_BROWSE_CONG_IND_EVT 6
+
+/* AVRC_BROWSE_UNCONG_IND_EVT event indicates that AVCTP browse channel is uncongested and ready to
+ * send messages. */
+#define AVRC_BROWSE_UNCONG_IND_EVT 7
+
+/* Supported categories */
+#define AVRC_SUPF_CT_CAT1 0x0001 /* Category 1 */
+#define AVRC_SUPF_CT_CAT2 0x0002 /* Category 2 */
+#define AVRC_SUPF_CT_CAT3 0x0004 /* Category 3 */
+#define AVRC_SUPF_CT_CAT4 0x0008 /* Category 4 */
+#define AVRC_SUPF_CT_BROWSE 0x0040 /* Browsing */
+
+#define AVRC_SUPF_TG_CAT1 0x0001 /* Category 1 */
+#define AVRC_SUPF_TG_CAT2 0x0002 /* Category 2 */
+#define AVRC_SUPF_TG_CAT3 0x0004 /* Category 3 */
+#define AVRC_SUPF_TG_CAT4 0x0008 /* Category 4 */
+#define AVRC_SUPF_TG_APP_SETTINGS 0x0010 /* Player Application Settings */
+#define AVRC_SUPF_TG_GROUP_NAVI 0x0020 /* Group Navigation */
+#define AVRC_SUPF_TG_BROWSE 0x0040 /* Browsing */
+#define AVRC_SUPF_TG_MULTI_PLAYER 0x0080 /* Muliple Media Player */
+
+#define AVRC_META_SUCCESS AVRC_SUCCESS
+#define AVRC_META_FAIL AVRC_FAIL
+#define AVRC_METADATA_CMD 0x0000
+#define AVRC_METADATA_RESP 0x0001
+
+
+
+/*****************************************************************************
+** data type definitions
+*****************************************************************************/
+
+/* This data type is used in AVRC_FindService() to initialize the SDP database
+ * to hold the result service search. */
+typedef struct
+{
+ UINT32 db_len; /* Length, in bytes, of the discovery database */
+ tSDP_DISCOVERY_DB *p_db; /* Pointer to the discovery database */
+ UINT16 num_attr;/* The number of attributes in p_attrs */
+ UINT16 *p_attrs; /* The attributes filter. If NULL, AVRCP API sets the attribute filter
+ * to be ATTR_ID_SERVICE_CLASS_ID_LIST, ATTR_ID_BT_PROFILE_DESC_LIST,
+ * ATTR_ID_SUPPORTED_FEATURES, ATTR_ID_SERVICE_NAME and ATTR_ID_PROVIDER_NAME.
+ * If not NULL, the input is taken as the filter. */
+} tAVRC_SDP_DB_PARAMS;
+
+/* This callback function returns service discovery information to the
+ * application after the AVRC_FindService() API function is called. The
+ * implementation of this callback function must copy the p_service_name
+ * and p_provider_name parameters passed to it as they are not guaranteed
+ * to remain after the callback function exits. */
+typedef void (tAVRC_FIND_CBACK) (UINT16 status);
+
+
+/* This is the control callback function. This function passes events
+ * listed in Table 20 to the application. */
+typedef void (tAVRC_CTRL_CBACK) (UINT8 handle, UINT8 event, UINT16 result,
+ BD_ADDR peer_addr);
+
+
+/* This is the message callback function. It is executed when AVCTP has
+ * a message packet ready for the application. The implementation of this
+ * callback function must copy the tAVRC_MSG structure passed to it as it
+ * is not guaranteed to remain after the callback function exits. */
+typedef void (tAVRC_MSG_CBACK) (UINT8 handle, UINT8 label, UINT8 opcode,
+ tAVRC_MSG *p_msg);
+
+typedef struct
+{
+ tAVRC_CTRL_CBACK *p_ctrl_cback; /* pointer to application control callback */
+ tAVRC_MSG_CBACK *p_msg_cback; /* pointer to application message callback */
+ UINT32 company_id; /* the company ID */
+ UINT8 conn; /* Connection role (Initiator/acceptor) */
+ UINT8 control; /* Control role (Control/Target) */
+} tAVRC_CONN_CB;
+
+
+
+/*****************************************************************************
+** external function declarations
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/******************************************************************************
+**
+** Function AVRC_AddRecord
+**
+** Description This function is called to build an AVRCP SDP record.
+** Prior to calling this function the application must
+** call SDP_CreateRecord() to create an SDP record.
+**
+** Input Parameters:
+** service_uuid: Indicates TG(UUID_SERVCLASS_AV_REM_CTRL_TARGET)
+** or CT(UUID_SERVCLASS_AV_REMOTE_CONTROL)
+**
+** p_service_name: Pointer to a null-terminated character
+** string containing the service name.
+** If service name is not used set this to NULL.
+**
+** p_provider_name: Pointer to a null-terminated character
+** string containing the provider name.
+** If provider name is not used set this to NULL.
+**
+** categories: Supported categories.
+**
+** sdp_handle: SDP handle returned by SDP_CreateRecord().
+**
+** Output Parameters:
+** None.
+**
+** Returns AVRC_SUCCESS if successful.
+** AVRC_NO_RESOURCES if not enough resources to build the SDP record.
+**
+******************************************************************************/
+AVRC_API extern UINT16 AVRC_AddRecord(UINT16 service_uuid, char *p_service_name,
+ char *p_provider_name, UINT16 categories, UINT32 sdp_handle);
+
+/******************************************************************************
+**
+** Function AVRC_FindService
+**
+** Description This function is called by the application to perform service
+** discovery and retrieve AVRCP SDP record information from a
+** peer device. Information is returned for the first service
+** record found on the server that matches the service UUID.
+** The callback function will be executed when service discovery
+** is complete. There can only be one outstanding call to
+** AVRC_FindService() at a time; the application must wait for
+** the callback before it makes another call to the function.
+** The application is responsible for allocating memory for the
+** discovery database. It is recommended that the size of the
+** discovery database be at least 300 bytes. The application
+** can deallocate the memory after the callback function has
+** executed.
+**
+** Input Parameters:
+** service_uuid: Indicates TG(UUID_SERVCLASS_AV_REM_CTRL_TARGET)
+** or CT(UUID_SERVCLASS_AV_REMOTE_CONTROL)
+**
+** bd_addr: BD address of the peer device.
+**
+** p_db: SDP discovery database parameters.
+**
+** p_cback: Pointer to the callback function.
+**
+** Output Parameters:
+** None.
+**
+** Returns AVRC_SUCCESS if successful.
+** AVRC_BAD_PARAMS if discovery database parameters are invalid.
+** AVRC_NO_RESOURCES if there are not enough resources to
+** perform the service search.
+**
+******************************************************************************/
+AVRC_API extern UINT16 AVRC_FindService(UINT16 service_uuid, BD_ADDR bd_addr,
+ tAVRC_SDP_DB_PARAMS *p_db, tAVRC_FIND_CBACK *p_cback);
+
+/******************************************************************************
+**
+** Function AVRC_Open
+**
+** Description This function is called to open a connection to AVCTP.
+** The connection can be either an initiator or acceptor, as
+** determined by the p_ccb->stream parameter.
+** The connection can be a target, a controller or for both role,
+** as determined by the p_ccb->control parameter.
+** By definition, a target connection is an acceptor connection
+** that waits for an incoming AVCTP connection from the peer.
+** The connection remains available to the application until
+** the application closes it by calling AVRC_Close(). The
+** application does not need to reopen the connection after an
+** AVRC_CLOSE_IND_EVT is received.
+**
+** Input Parameters:
+** p_ccb->company_id: Company Identifier.
+**
+** p_ccb->p_ctrl_cback: Pointer to control callback function.
+**
+** p_ccb->p_msg_cback: Pointer to message callback function.
+**
+** p_ccb->conn: AVCTP connection role. This is set to
+** AVCTP_INT for initiator connections and AVCTP_ACP
+** for acceptor connections.
+**
+** p_ccb->control: Control role. This is set to
+** AVRC_CT_TARGET for target connections, AVRC_CT_CONTROL
+** for control connections or (AVRC_CT_TARGET|AVRC_CT_CONTROL)
+** for connections that support both roles.
+**
+** peer_addr: BD address of peer device. This value is
+** only used for initiator connections; for acceptor
+** connections it can be set to NULL.
+**
+** Output Parameters:
+** p_handle: Pointer to handle. This parameter is only
+** valid if AVRC_SUCCESS is returned.
+**
+** Returns AVRC_SUCCESS if successful.
+** AVRC_NO_RESOURCES if there are not enough resources to open
+** the connection.
+**
+******************************************************************************/
+AVRC_API extern UINT16 AVRC_Open(UINT8 *p_handle, tAVRC_CONN_CB *p_ccb,
+ BD_ADDR_PTR peer_addr);
+
+/******************************************************************************
+**
+** Function AVRC_Close
+**
+** Description Close a connection opened with AVRC_Open().
+** This function is called when the
+** application is no longer using a connection.
+**
+** Input Parameters:
+** handle: Handle of this connection.
+**
+** Output Parameters:
+** None.
+**
+** Returns AVRC_SUCCESS if successful.
+** AVRC_BAD_HANDLE if handle is invalid.
+**
+******************************************************************************/
+AVRC_API extern UINT16 AVRC_Close(UINT8 handle);
+
+/******************************************************************************
+**
+** Function AVRC_OpenBrowse
+**
+** Description This function is called to open a browsing connection to AVCTP.
+** The connection can be either an initiator or acceptor, as
+** determined by the conn_role.
+** The handle is returned by a previous call to AVRC_Open.
+**
+** Returns AVRC_SUCCESS if successful.
+** AVRC_NO_RESOURCES if there are not enough resources to open
+** the connection.
+**
+******************************************************************************/
+AVRC_API extern UINT16 AVRC_OpenBrowse(UINT8 handle, UINT8 conn_role);
+
+/******************************************************************************
+**
+** Function AVRC_CloseBrowse
+**
+** Description Close a connection opened with AVRC_OpenBrowse().
+** This function is called when the
+** application is no longer using a connection.
+**
+** Returns AVRC_SUCCESS if successful.
+** AVRC_BAD_HANDLE if handle is invalid.
+**
+******************************************************************************/
+AVRC_API extern UINT16 AVRC_CloseBrowse(UINT8 handle);
+
+/******************************************************************************
+**
+** Function AVRC_MsgReq
+**
+** Description This function is used to send the AVRCP byte stream in p_pkt
+** down to AVCTP.
+**
+** It is expected that p_pkt->offset is at least AVCT_MSG_OFFSET
+** p_pkt->layer_specific is AVCT_DATA_CTRL or AVCT_DATA_BROWSE
+** p_pkt->event is AVRC_OP_VENDOR, AVRC_OP_PASS_THRU or AVRC_OP_BROWSING
+** The above BT_HDR settings are set by the AVRC_Bld* functions.
+**
+** Returns AVRC_SUCCESS if successful.
+** AVRC_BAD_HANDLE if handle is invalid.
+**
+******************************************************************************/
+AVRC_API extern UINT16 AVRC_MsgReq (UINT8 handle, UINT8 label, UINT8 ctype, BT_HDR *p_pkt);
+
+/******************************************************************************
+**
+** Function AVRC_UnitCmd
+**
+** Description Send a UNIT INFO command to the peer device. This
+** function can only be called for controller role connections.
+** Any response message from the peer is passed back through
+** the tAVRC_MSG_CBACK callback function.
+**
+** Input Parameters:
+** handle: Handle of this connection.
+**
+** label: Transaction label.
+**
+** Output Parameters:
+** None.
+**
+** Returns AVRC_SUCCESS if successful.
+** AVRC_BAD_HANDLE if handle is invalid.
+**
+******************************************************************************/
+AVRC_API extern UINT16 AVRC_UnitCmd(UINT8 handle, UINT8 label);
+
+/******************************************************************************
+**
+** Function AVRC_SubCmd
+**
+** Description Send a SUBUNIT INFO command to the peer device. This
+** function can only be called for controller role connections.
+** Any response message from the peer is passed back through
+** the tAVRC_MSG_CBACK callback function.
+**
+** Input Parameters:
+** handle: Handle of this connection.
+**
+** label: Transaction label.
+**
+** page: Specifies which part of the subunit type table
+** is requested. For AVRCP it is typically zero.
+** Value range is 0-7.
+**
+** Output Parameters:
+** None.
+**
+** Returns AVRC_SUCCESS if successful.
+** AVRC_BAD_HANDLE if handle is invalid.
+**
+******************************************************************************/
+AVRC_API extern UINT16 AVRC_SubCmd(UINT8 handle, UINT8 label, UINT8 page);
+
+
+/******************************************************************************
+**
+** Function AVRC_PassCmd
+**
+** Description Send a PASS THROUGH command to the peer device. This
+** function can only be called for controller role connections.
+** Any response message from the peer is passed back through
+** the tAVRC_MSG_CBACK callback function.
+**
+** Input Parameters:
+** handle: Handle of this connection.
+**
+** label: Transaction label.
+**
+** p_msg: Pointer to PASS THROUGH message structure.
+**
+** Output Parameters:
+** None.
+**
+** Returns AVRC_SUCCESS if successful.
+** AVRC_BAD_HANDLE if handle is invalid.
+**
+******************************************************************************/
+AVRC_API extern UINT16 AVRC_PassCmd(UINT8 handle, UINT8 label, tAVRC_MSG_PASS *p_msg);
+
+/******************************************************************************
+**
+** Function AVRC_PassRsp
+**
+** Description Send a PASS THROUGH response to the peer device. This
+** function can only be called for target role connections.
+** This function must be called when a PASS THROUGH command
+** message is received from the peer through the
+** tAVRC_MSG_CBACK callback function.
+**
+** Input Parameters:
+** handle: Handle of this connection.
+**
+** label: Transaction label. Must be the same value as
+** passed with the command message in the callback function.
+**
+** p_msg: Pointer to PASS THROUGH message structure.
+**
+** Output Parameters:
+** None.
+**
+** Returns AVRC_SUCCESS if successful.
+** AVRC_BAD_HANDLE if handle is invalid.
+**
+******************************************************************************/
+AVRC_API extern UINT16 AVRC_PassRsp(UINT8 handle, UINT8 label, tAVRC_MSG_PASS *p_msg);
+
+
+/******************************************************************************
+**
+** Function AVRC_VendorCmd
+**
+** Description Send a VENDOR DEPENDENT command to the peer device. This
+** function can only be called for controller role connections.
+** Any response message from the peer is passed back through
+** the tAVRC_MSG_CBACK callback function.
+**
+** Input Parameters:
+** handle: Handle of this connection.
+**
+** label: Transaction label.
+**
+** p_msg: Pointer to VENDOR DEPENDENT message structure.
+**
+** Output Parameters:
+** None.
+**
+** Returns AVRC_SUCCESS if successful.
+** AVRC_BAD_HANDLE if handle is invalid.
+**
+******************************************************************************/
+AVRC_API extern UINT16 AVRC_VendorCmd(UINT8 handle, UINT8 label, tAVRC_MSG_VENDOR *p_msg);
+
+
+/******************************************************************************
+**
+** Function AVRC_VendorRsp
+**
+** Description Send a VENDOR DEPENDENT response to the peer device. This
+** function can only be called for target role connections.
+** This function must be called when a VENDOR DEPENDENT
+** command message is received from the peer through the
+** tAVRC_MSG_CBACK callback function.
+**
+** Input Parameters:
+** handle: Handle of this connection.
+**
+** label: Transaction label. Must be the same value as
+** passed with the command message in the callback function.
+**
+** p_msg: Pointer to VENDOR DEPENDENT message structure.
+**
+** Output Parameters:
+** None.
+**
+** Returns AVRC_SUCCESS if successful.
+** AVRC_BAD_HANDLE if handle is invalid.
+**
+******************************************************************************/
+AVRC_API extern UINT16 AVRC_VendorRsp(UINT8 handle, UINT8 label, tAVRC_MSG_VENDOR *p_msg);
+
+
+/******************************************************************************
+**
+** Function AVRC_SetTraceLevel
+**
+** Description Sets the trace level for AVRC. If 0xff is passed, the
+** current trace level is returned.
+**
+** Input Parameters:
+** new_level: The level to set the AVRC tracing to:
+** 0xff-returns the current setting.
+** 0-turns off tracing.
+** >= 1-Errors.
+** >= 2-Warnings.
+** >= 3-APIs.
+** >= 4-Events.
+** >= 5-Debug.
+**
+** Returns The new trace level or current trace level if
+** the input parameter is 0xff.
+**
+******************************************************************************/
+AVRC_API extern UINT8 AVRC_SetTraceLevel (UINT8 new_level);
+
+/*******************************************************************************
+**
+** Function AVRC_Init
+**
+** Description This function is called at stack startup to allocate the
+** control block (if using dynamic memory), and initializes the
+** control block and tracing level.
+**
+** Returns void
+**
+*******************************************************************************/
+AVRC_API extern void AVRC_Init(void);
+
+/*******************************************************************************
+**
+** Function AVRC_ParsCommand
+**
+** Description This function is used to parse the received command.
+**
+** Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully.
+** Otherwise, the error code defined by AVRCP 1.4
+**
+*******************************************************************************/
+AVRC_API extern tAVRC_STS AVRC_ParsCommand (tAVRC_MSG *p_msg, tAVRC_COMMAND *p_result, UINT8 *p_buf, UINT16 buf_len);
+
+/*******************************************************************************
+**
+** Function AVRC_ParsResponse
+**
+** Description This function is used to parse the received response.
+**
+** Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully.
+** Otherwise, the error code defined by AVRCP 1.4
+**
+*******************************************************************************/
+AVRC_API extern tAVRC_STS AVRC_ParsResponse (tAVRC_MSG *p_msg, tAVRC_RESPONSE *p_result, UINT8 *p_buf, UINT16 buf_len);
+
+/*******************************************************************************
+**
+** Function AVRC_BldCommand
+**
+** Description This function builds the given AVRCP command to the given
+** GKI buffer
+**
+** Returns AVRC_STS_NO_ERROR, if the command is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+AVRC_API extern tAVRC_STS AVRC_BldCommand( tAVRC_COMMAND *p_cmd, BT_HDR **pp_pkt);
+
+/*******************************************************************************
+**
+** Function AVRC_BldResponse
+**
+** Description This function builds the given AVRCP response to the given
+** GKI buffer
+**
+** Returns AVRC_STS_NO_ERROR, if the response is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+AVRC_API extern tAVRC_STS AVRC_BldResponse( UINT8 handle, tAVRC_RESPONSE *p_rsp, BT_HDR **pp_pkt);
+
+/**************************************************************************
+**
+** Function AVRC_IsValidAvcType
+**
+** Description Check if correct AVC type is specified
+**
+** Returns returns TRUE if it is valid
+**
+**
+*******************************************************************************/
+AVRC_API extern BOOLEAN AVRC_IsValidAvcType(UINT8 pdu_id, UINT8 avc_type);
+
+/*******************************************************************************
+**
+** Function AVRC_IsValidPlayerAttr
+**
+** Description Check if the given attrib value is a valid one
+**
+**
+** Returns returns TRUE if it is valid
+**
+*******************************************************************************/
+AVRC_API extern BOOLEAN AVRC_IsValidPlayerAttr(UINT8 attr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVRC_API_H */
diff --git a/stack/include/avrc_defs.h b/stack/include/avrc_defs.h
new file mode 100644
index 0000000..188f5a4
--- /dev/null
+++ b/stack/include/avrc_defs.h
@@ -0,0 +1,1411 @@
+/*****************************************************************************
+**
+** Name: avrc_defs.h
+**
+** Description: AVRCP definition and data types
+**
+** Copyright (c) 2006-2008, Broadcom Corp., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef _AVRC_DEFS_H
+#define _AVRC_DEFS_H
+
+/*****************************************************************************
+** constants
+*****************************************************************************/
+
+/* Profile revision numbers */
+#define AVRC_REV_1_0 0x0100
+#define AVRC_REV_1_3 0x0103
+#define AVRC_REV_1_4 0x0104
+
+#define AVRC_PACKET_LEN 512 /* Per the spec, you must support 512 byte RC packets */
+
+#define AVRC_MIN_CONTROL_MTU 48 /* Per the spec, minimum MTU for the control channel */
+#define AVRC_MIN_BROWSE_MTU 335 /* Per the spec, minimum MTU for the browsing channel */
+
+#define AVRC_META_PDU_OFFSET 4
+#define AVRC_SUB_TYPE_LEN 4
+#define AVRC_UID_SIZE 8
+#define AVRC_FEATURE_MASK_SIZE 16
+
+/* command type codes */
+#define AVRC_CMD_CTRL 0 /* Instruct a target to perform an operation */
+#define AVRC_CMD_STATUS 1 /* Check a device’s current status */
+#define AVRC_CMD_SPEC_INQ 2 /* Check whether a target supports a particular
+ control command; all operands are included */
+#define AVRC_CMD_NOTIF 3 /* Used for receiving notification of a change in a device’s state */
+#define AVRC_CMD_GEN_INQ 4 /* Check whether a target supports a particular
+ control command; operands are not included */
+
+/* response type codes */
+#define AVRC_RSP_NOT_IMPL 8 /* The target does not implement the command specified
+ by the opcode and operand,
+ or doesn’t implement the specified subunit */
+#define AVRC_RSP_ACCEPT 9 /* The target executed or is executing the command */
+#define AVRC_RSP_REJ 10 /* The target implements the command specified by the
+ opcode but cannot respond because the current state
+ of the target doesn’t allow it */
+#define AVRC_RSP_IN_TRANS 11 /* The target implements the status command but it is
+ in a state of transition; the status command may
+ be retried at a future time */
+#define AVRC_RSP_IMPL_STBL 12 /* For specific inquiry or general inquiy commands,
+ the target implements the command; for status
+ commands, the target returns stable and includes
+ the status results */
+#define AVRC_RSP_CHANGED 13 /* The response frame contains a notification that the
+ target device’s state has changed */
+#define AVRC_RSP_INTERIM 15 /* For control commands, the target has accepted the
+ request but cannot return information within 100
+ milliseconds; for notify commands, the target accepted
+ the command, and will notify the controller of a change
+ of target state at a future time */
+
+/* subunit type */
+#define AVRC_SUB_MONITOR 0x00 /* Monitor */
+#define AVRC_SUB_AUDIO 0x01 /* Audio */
+#define AVRC_SUB_PRINTER 0x02 /* Printer */
+#define AVRC_SUB_DISC 0x03 /* Disc */
+#define AVRC_SUB_TAPE 0x04 /* Tape recorder/player */
+#define AVRC_SUB_TUNER 0x05 /* Tuner */
+#define AVRC_SUB_CA 0x06 /* CA */
+#define AVRC_SUB_CAMERA 0x07 /* Camera */
+#define AVRC_SUB_PANEL 0x09 /* Panel */
+#define AVRC_SUB_BB 0x0A /* Bulletin Board */
+#define AVRC_SUB_CAM_STOR 0x0B /* Camera Storage */
+#define AVRC_SUB_VENDOR 0x1C /* Vendor unique */
+#define AVRC_SUB_EXT 0x1E /* Subunit type extended to next byte */
+#define AVRC_SUB_UNIT 0x1F /* Unit */
+
+/* opcodes - defined by 1394ta */
+#define AVRC_OP_UNIT_INFO 0x30 /* Report unit information */
+#define AVRC_OP_SUB_INFO 0x31 /* Report subunit information */
+#define AVRC_OP_VENDOR 0x00 /* Vendor-dependent commands */
+#define AVRC_OP_PASS_THRU 0x7C /* panel subunit opcode */
+/* opcodes 80-9F and E0-FF are not used by 1394ta.Sneak one for the browsing channel */
+#define AVRC_OP_BROWSE 0xFF /* Browsing */
+#define AVRC_OP_INVALID 0xFE /* invalid one */
+
+/* Company ID's
+*/
+#define AVRC_CO_BLUETOOTH_SIG 0x00FFFFFF
+#define AVRC_CO_WIDCOMM 0x00000361
+#define AVRC_CO_BROADCOM 0x00001018
+#define AVRC_CO_METADATA 0x00001958 /* Unique COMPANY ID for Metadata messages */
+
+/* State flag for Passthrough commands
+*/
+#define AVRC_STATE_PRESS 0
+#define AVRC_STATE_RELEASE 1
+
+/* Operation ID list for Passthrough commands
+*/
+#define AVRC_ID_SELECT 0x00 /* select */
+#define AVRC_ID_UP 0x01 /* up */
+#define AVRC_ID_DOWN 0x02 /* down */
+#define AVRC_ID_LEFT 0x03 /* left */
+#define AVRC_ID_RIGHT 0x04 /* right */
+#define AVRC_ID_RIGHT_UP 0x05 /* right-up */
+#define AVRC_ID_RIGHT_DOWN 0x06 /* right-down */
+#define AVRC_ID_LEFT_UP 0x07 /* left-up */
+#define AVRC_ID_LEFT_DOWN 0x08 /* left-down */
+#define AVRC_ID_ROOT_MENU 0x09 /* root menu */
+#define AVRC_ID_SETUP_MENU 0x0A /* setup menu */
+#define AVRC_ID_CONT_MENU 0x0B /* contents menu */
+#define AVRC_ID_FAV_MENU 0x0C /* favorite menu */
+#define AVRC_ID_EXIT 0x0D /* exit */
+#define AVRC_ID_0 0x20 /* 0 */
+#define AVRC_ID_1 0x21 /* 1 */
+#define AVRC_ID_2 0x22 /* 2 */
+#define AVRC_ID_3 0x23 /* 3 */
+#define AVRC_ID_4 0x24 /* 4 */
+#define AVRC_ID_5 0x25 /* 5 */
+#define AVRC_ID_6 0x26 /* 6 */
+#define AVRC_ID_7 0x27 /* 7 */
+#define AVRC_ID_8 0x28 /* 8 */
+#define AVRC_ID_9 0x29 /* 9 */
+#define AVRC_ID_DOT 0x2A /* dot */
+#define AVRC_ID_ENTER 0x2B /* enter */
+#define AVRC_ID_CLEAR 0x2C /* clear */
+#define AVRC_ID_CHAN_UP 0x30 /* channel up */
+#define AVRC_ID_CHAN_DOWN 0x31 /* channel down */
+#define AVRC_ID_PREV_CHAN 0x32 /* previous channel */
+#define AVRC_ID_SOUND_SEL 0x33 /* sound select */
+#define AVRC_ID_INPUT_SEL 0x34 /* input select */
+#define AVRC_ID_DISP_INFO 0x35 /* display information */
+#define AVRC_ID_HELP 0x36 /* help */
+#define AVRC_ID_PAGE_UP 0x37 /* page up */
+#define AVRC_ID_PAGE_DOWN 0x38 /* page down */
+#define AVRC_ID_POWER 0x40 /* power */
+#define AVRC_ID_VOL_UP 0x41 /* volume up */
+#define AVRC_ID_VOL_DOWN 0x42 /* volume down */
+#define AVRC_ID_MUTE 0x43 /* mute */
+#define AVRC_ID_PLAY 0x44 /* play */
+#define AVRC_ID_STOP 0x45 /* stop */
+#define AVRC_ID_PAUSE 0x46 /* pause */
+#define AVRC_ID_RECORD 0x47 /* record */
+#define AVRC_ID_REWIND 0x48 /* rewind */
+#define AVRC_ID_FAST_FOR 0x49 /* fast forward */
+#define AVRC_ID_EJECT 0x4A /* eject */
+#define AVRC_ID_FORWARD 0x4B /* forward */
+#define AVRC_ID_BACKWARD 0x4C /* backward */
+#define AVRC_ID_ANGLE 0x50 /* angle */
+#define AVRC_ID_SUBPICT 0x51 /* subpicture */
+#define AVRC_ID_F1 0x71 /* F1 */
+#define AVRC_ID_F2 0x72 /* F2 */
+#define AVRC_ID_F3 0x73 /* F3 */
+#define AVRC_ID_F4 0x74 /* F4 */
+#define AVRC_ID_F5 0x75 /* F5 */
+#define AVRC_ID_VENDOR 0x7E /* vendor unique */
+#define AVRC_KEYPRESSED_RELEASE 0x80
+
+/*****************************************************************************
+** Metadata transfer definitions
+*****************************************************************************/
+
+/* Define the Metadata Packet types
+*/
+#define AVRC_PKT_SINGLE 0
+#define AVRC_PKT_START 1
+#define AVRC_PKT_CONTINUE 2
+#define AVRC_PKT_END 3
+#define AVRC_PKT_TYPE_MASK 3
+
+/* Define the PDUs carried in the vendor dependant data
+*/
+#define AVRC_PDU_GET_CAPABILITIES 0x10
+#define AVRC_PDU_LIST_PLAYER_APP_ATTR 0x11
+#define AVRC_PDU_LIST_PLAYER_APP_VALUES 0x12
+#define AVRC_PDU_GET_CUR_PLAYER_APP_VALUE 0x13
+#define AVRC_PDU_SET_PLAYER_APP_VALUE 0x14
+#define AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT 0x15
+#define AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT 0x16
+#define AVRC_PDU_INFORM_DISPLAY_CHARSET 0x17
+#define AVRC_PDU_INFORM_BATTERY_STAT_OF_CT 0x18
+#define AVRC_PDU_GET_ELEMENT_ATTR 0x20
+#define AVRC_PDU_GET_PLAY_STATUS 0x30
+#define AVRC_PDU_REGISTER_NOTIFICATION 0x31
+#define AVRC_PDU_REQUEST_CONTINUATION_RSP 0x40
+#define AVRC_PDU_ABORT_CONTINUATION_RSP 0x41
+/* added in 1.4 */
+#define AVRC_PDU_SET_ABSOLUTE_VOLUME 0x50
+#define AVRC_PDU_SET_ADDRESSED_PLAYER 0x60
+#define AVRC_PDU_SET_BROWSED_PLAYER 0x70
+#define AVRC_PDU_GET_FOLDER_ITEMS 0x71
+#define AVRC_PDU_CHANGE_PATH 0x72
+#define AVRC_PDU_GET_ITEM_ATTRIBUTES 0x73
+#define AVRC_PDU_PLAY_ITEM 0x74
+#define AVRC_PDU_SEARCH 0x80
+#define AVRC_PDU_ADD_TO_NOW_PLAYING 0x90
+#define AVRC_PDU_GENERAL_REJECT 0xA0
+
+/* Define the vendor unique id carried in the pass through data
+*/
+#define AVRC_PDU_NEXT_GROUP 0x00
+#define AVRC_PDU_PREV_GROUP 0x01
+/* the only pass through vendor unique commands defined by AVRC is the group navigation commands
+ * The len for vendor unique data is 5 */
+#define AVRC_PASS_THRU_GROUP_LEN 5
+
+
+/* 6.15.3 error status code for general reject */
+#define AVRC_STS_BAD_CMD 0x00 /* Invalid command, sent if TG received a PDU that it did not understand. */
+#define AVRC_STS_BAD_PARAM 0x01 /* Invalid parameter, sent if the TG received a PDU with a parameter ID that it did not understand. Sent if there is only one parameter ID in the PDU. */
+#define AVRC_STS_NOT_FOUND 0x02 /* Specified parameter not found., sent if the parameter ID is understood, but content is wrong or corrupted. */
+#define AVRC_STS_INTERNAL_ERR 0x03 /* Internal Error, sent if there are error conditions not covered by a more specific error code. */
+#define AVRC_STS_NO_ERROR 0x04 /* Operation completed without error. This is the status that should be returned if the operation was successful. */
+#define AVRC_STS_UID_CHANGED 0x05 /* UID Changed - The UIDs on the device have changed */
+/* #define AVRC_STS_GEN_ERROR 0x06 Unknown Error - this is changed to "reserved" */
+#define AVRC_STS_BAD_DIR 0x07 /* Invalid Direction - The Direction parameter is invalid - Change Path*/
+#define AVRC_STS_NOT_DIR 0x08 /* Not a Directory - The UID provided does not refer to a folder item Change Path*/
+#define AVRC_STS_NOT_EXIST 0x09 /* Does Not Exist - The UID provided does not refer to any item Change Path, PlayItem, AddToNowPlaying, GetItemAttributes*/
+#define AVRC_STS_BAD_SCOPE 0x0a /* Invalid Scope - The scope parameter is invalid GetFolderItems, PlayItem, AddToNowPlayer, GetItemAttributes, */
+#define AVRC_STS_BAD_RANGE 0x0b /* Range Out of Bounds - The start of range provided is not valid GetFolderItems*/
+#define AVRC_STS_UID_IS_DIR 0x0c /* UID is a Directory - The UID provided refers to a directory, which cannot be handled by this media player PlayItem, AddToNowPlaying */
+#define AVRC_STS_IN_USE 0x0d /* Media in Use - The media is not able to be used for this operation at this time PlayItem, AddToNowPlaying */
+#define AVRC_STS_NOW_LIST_FULL 0x0e /* Now Playing List Full - No more items can be added to the Now Playing List AddToNowPlaying*/
+#define AVRC_STS_SEARCH_NOT_SUP 0x0f /* Search Not Supported - The Browsed Media Player does not support search Search */
+#define AVRC_STS_SEARCH_BUSY 0x10 /* Search in Progress - A search operation is already in progress Search*/
+#define AVRC_STS_BAD_PLAYER_ID 0x11 /* Invalid Player Id - The specified Player Id does not refer to a valid player SetAddressedPlayer, SetBrowsedPlayer*/
+#define AVRC_STS_PLAYER_N_BR 0x12 /* Player Not Browsable - The Player Id supplied refers to a Media Player which does not support browsing. SetBrowsedPlayer */
+#define AVRC_STS_PLAYER_N_ADDR 0x13 /* Player Not Addressed. The Player Id supplied refers to a player which is not currently addressed, and the command is not able to be performed if the player is not set as addressed. Search, SetBrowsedPlayer*/
+#define AVRC_STS_BAD_SEARCH_RES 0x14 /* No valid Search Results - The Search result list does not contain valid entries, e.g. after being invalidated due to change of browsed player GetFolderItems */
+#define AVRC_STS_NO_AVAL_PLAYER 0x15 /* No available players ALL */
+#define AVRC_STS_ADDR_PLAYER_CHG 0x16 /* Addressed Player Changed - Register Notification */
+typedef UINT8 tAVRC_STS;
+
+
+/* Define the Capability IDs
+*/
+#define AVRC_CAP_COMPANY_ID 0x02
+#define AVRC_CAP_EVENTS_SUPPORTED 0x03
+#define AVRC_COMPANY_ID_LEN 3
+#define AVRC_CAPABILITY_OFFSET 2
+
+/* Define the Player Application Settings IDs
+*/
+#define AVRC_PLAYER_SETTING_EQUALIZER 0x01
+#define AVRC_PLAYER_SETTING_REPEAT 0x02
+#define AVRC_PLAYER_SETTING_SHUFFLE 0x03
+#define AVRC_PLAYER_SETTING_SCAN 0x04
+#define AVRC_PLAYER_SETTING_LOW_MENU_EXT 0x80
+#define AVRC_PLAYER_SETTING_HIGH_MENU_EXT 0xff
+
+/* Define the possible values of the Player Application Settings
+*/
+#define AVRC_PLAYER_VAL_OFF 0x01
+#define AVRC_PLAYER_VAL_ON 0x02
+#define AVRC_PLAYER_VAL_SINGLE_REPEAT 0x02
+#define AVRC_PLAYER_VAL_ALL_REPEAT 0x03
+#define AVRC_PLAYER_VAL_GROUP_REPEAT 0x04
+#define AVRC_PLAYER_VAL_ALL_SHUFFLE 0x02
+#define AVRC_PLAYER_VAL_GROUP_SHUFFLE 0x03
+#define AVRC_PLAYER_VAL_ALL_SCAN 0x02
+#define AVRC_PLAYER_VAL_GROUP_SCAN 0x03
+
+/* Define the possible values of Battery Status PDU
+*/
+#define AVRC_BATTERY_STATUS_NORMAL 0x00
+#define AVRC_BATTERY_STATUS_WARNING 0x01
+#define AVRC_BATTERY_STATUS_CRITICAL 0x02
+#define AVRC_BATTERY_STATUS_EXTERNAL 0x03
+#define AVRC_BATTERY_STATUS_FULL_CHARGE 0x04
+typedef UINT8 tAVRC_BATTERY_STATUS;
+
+/* Define character set */
+#define AVRC_CHAR_SET_SIZE 2
+
+/* Define the Media Attribute IDs
+*/
+#define AVRC_MEDIA_ATTR_ID_TITLE 0x00000001
+#define AVRC_MEDIA_ATTR_ID_ARTIST 0x00000002
+#define AVRC_MEDIA_ATTR_ID_ALBUM 0x00000003
+#define AVRC_MEDIA_ATTR_ID_TRACK_NUM 0x00000004
+#define AVRC_MEDIA_ATTR_ID_NUM_TRACKS 0x00000005
+#define AVRC_MEDIA_ATTR_ID_GENRE 0x00000006
+#define AVRC_MEDIA_ATTR_ID_PLAYING_TIME 0x00000007 /* in miliseconds */
+#define AVRC_MAX_NUM_MEDIA_ATTR_ID 7
+
+/* Define the possible values of play state
+*/
+#define AVRC_PLAYSTATE_RESP_MSG_SIZE 9
+#define AVRC_PLAYSTATE_STOPPED 0x00 /* Stopped */
+#define AVRC_PLAYSTATE_PLAYING 0x01 /* Playing */
+#define AVRC_PLAYSTATE_PAUSED 0x02 /* Paused */
+#define AVRC_PLAYSTATE_FWD_SEEK 0x03 /* Fwd Seek*/
+#define AVRC_PLAYSTATE_REV_SEEK 0x04 /* Rev Seek*/
+#define AVRC_PLAYSTATE_ERROR 0xFF /* Error */
+typedef UINT8 tAVRC_PLAYSTATE;
+
+/* Define the events that can be registered for notifications
+*/
+#define AVRC_EVT_PLAY_STATUS_CHANGE 0x01
+#define AVRC_EVT_TRACK_CHANGE 0x02
+#define AVRC_EVT_TRACK_REACHED_END 0x03
+#define AVRC_EVT_TRACK_REACHED_START 0x04
+#define AVRC_EVT_PLAY_POS_CHANGED 0x05
+#define AVRC_EVT_BATTERY_STATUS_CHANGE 0x06
+#define AVRC_EVT_SYSTEM_STATUS_CHANGE 0x07
+#define AVRC_EVT_APP_SETTING_CHANGE 0x08
+/* added in AVRCP 1.4 */
+#define AVRC_EVT_NOW_PLAYING_CHANGE 0x09
+#define AVRC_EVT_AVAL_PLAYERS_CHANGE 0x0a
+#define AVRC_EVT_ADDR_PLAYER_CHANGE 0x0b
+#define AVRC_EVT_UIDS_CHANGE 0x0c
+#define AVRC_EVT_VOLUME_CHANGE 0x0d
+
+/* the number of events that can be registered for notifications */
+#define AVRC_NUM_NOTIF_EVENTS 0x0d
+
+#define AVRC_EVT_MSG_LEN_1 0x01
+#define AVRC_EVT_MSG_LEN_2 0x02
+#define AVRC_EVT_MSG_LEN_5 0x05
+#define AVRC_EVT_MSG_LEN_9 0x09
+
+#define AVRC_MAX_VOLUME 0x7F
+
+/* Define the possible values of system status
+*/
+#define AVRC_SYSTEMSTATE_PWR_ON 0x00
+#define AVRC_SYSTEMSTATE_PWR_OFF 0x01
+#define AVRC_SYSTEMSTATE_PWR_UNPLUGGED 0x02
+typedef UINT8 tAVRC_SYSTEMSTATE;
+
+/* the frequently used character set ids */
+#define AVRC_CHARSET_ID_ASCII ((UINT16) 0x0003) /* ASCII */
+#define AVRC_CHARSET_ID_UTF8 ((UINT16) 0x006a) /* UTF-8 */
+#define AVRC_CHARSET_ID_UTF16 ((UINT16) 0x03f7) /* 1015 */
+#define AVRC_CHARSET_ID_UTF32 ((UINT16) 0x03f9) /* 1017 */
+
+/*****************************************************************************
+** Advanced Control
+*****************************************************************************/
+#define AVRC_ITEM_PLAYER 0x01
+#define AVRC_ITEM_FOLDER 0x02
+#define AVRC_ITEM_MEDIA 0x03
+
+#define AVRC_SCOPE_PLAYER_LIST 0x00 /* Media Player Item - Contains all available media players */
+#define AVRC_SCOPE_FILE_SYSTEM 0x01 /* Folder Item, Media Element Item
+ - The virtual filesystem containing the media content of the browsed player */
+#define AVRC_SCOPE_SEARCH 0x02 /* Media Element Item The results of a search operation on the browsed player */
+#define AVRC_SCOPE_NOW_PLAYING 0x03 /* Media Element Item The Now Playing list (or queue) of the addressed player */
+
+#define AVRC_FOLDER_ITEM_COUNT_NONE 0xFF
+
+/* folder type */
+#define AVRC_FOLDER_TYPE_MIXED 0x00
+#define AVRC_FOLDER_TYPE_TITLES 0x01
+#define AVRC_FOLDER_TYPE_ALNUMS 0x02
+#define AVRC_FOLDER_TYPE_ARTISTS 0x03
+#define AVRC_FOLDER_TYPE_GENRES 0x04
+#define AVRC_FOLDER_TYPE_PLAYLISTS 0x05
+#define AVRC_FOLDER_TYPE_YEARS 0x06
+
+/* major player type */
+#define AVRC_MJ_TYPE_AUDIO 0x01 /* Audio */
+#define AVRC_MJ_TYPE_VIDEO 0x02 /* Video */
+#define AVRC_MJ_TYPE_BC_AUDIO 0x04 /* Broadcasting Audio */
+#define AVRC_MJ_TYPE_BC_VIDEO 0x08 /* Broadcasting Video */
+#define AVRC_MJ_TYPE_INVALID 0xF0
+
+/* player sub type */
+#define AVRC_SUB_TYPE_NONE 0x00
+#define AVRC_SUB_TYPE_AUDIO_BOOK 0x01 /* Audio Book */
+#define AVRC_SUB_TYPE_PODCAST 0x02 /* Podcast */
+#define AVRC_SUB_TYPE_INVALID 0xFC
+
+/* media item - media type */
+#define AVRC_MEDIA_TYPE_AUDIO 0x00
+#define AVRC_MEDIA_TYPE_VIDEO 0x01
+
+#define AVRC_DIR_UP 0x00 /* Folder Up */
+#define AVRC_DIR_DOWN 0x01 /* Folder Down */
+
+#define AVRC_UID_SIZE 8
+typedef UINT8 tAVRC_UID[AVRC_UID_SIZE];
+
+/*****************************************************************************
+** player attribute - supported features
+*****************************************************************************/
+#define AVRC_PF_SELECT_BIT_NO 0
+#define AVRC_PF_SELECT_MASK 0x01
+#define AVRC_PF_SELECT_OFF 0
+#define AVRC_PF_SELECT_SUPPORTED(x) ((x)[AVRC_PF_SELECT_OFF] & AVRC_PF_SELECT_MASK)
+
+#define AVRC_PF_UP_BIT_NO 1
+#define AVRC_PF_UP_MASK 0x02
+#define AVRC_PF_UP_OFF 0
+#define AVRC_PF_UP_SUPPORTED(x) ((x)[AVRC_PF_UP_OFF] & AVRC_PF_UP_MASK)
+
+#define AVRC_PF_DOWN_BIT_NO 2
+#define AVRC_PF_DOWN_MASK 0x04
+#define AVRC_PF_DOWN_OFF 0
+#define AVRC_PF_DOWN_SUPPORTED(x) ((x)[AVRC_PF_DOWN_OFF] & AVRC_PF_DOWN_MASK)
+
+#define AVRC_PF_LEFT_BIT_NO 3
+#define AVRC_PF_LEFT_MASK 0x08
+#define AVRC_PF_LEFT_OFF 0
+#define AVRC_PF_LEFT_SUPPORTED(x) ((x)[AVRC_PF_LEFT_OFF] & AVRC_PF_LEFT_MASK)
+
+#define AVRC_PF_RIGHT_BIT_NO 4
+#define AVRC_PF_RIGHT_MASK 0x10
+#define AVRC_PF_RIGHT_OFF 0
+#define AVRC_PF_RIGHT_SUPPORTED(x) ((x)[AVRC_PF_RIGHT_OFF] & AVRC_PF_RIGHT_MASK)
+
+#define AVRC_PF_RIGHTUP_BIT_NO 5
+#define AVRC_PF_RIGHTUP_MASK 0x20
+#define AVRC_PF_RIGHTUP_OFF 0
+#define AVRC_PF_RIGHTUP_SUPPORTED(x) ((x)[AVRC_PF_RIGHTUP_OFF] & AVRC_PF_RIGHTUP_MASK)
+
+#define AVRC_PF_RIGHTDOWN_BIT_NO 6
+#define AVRC_PF_RIGHTDOWN_MASK 0x40
+#define AVRC_PF_RIGHTDOWN_OFF 0
+#define AVRC_PF_RIGHTDOWN_SUPPORTED(x) ((x)[AVRC_PF_RIGHTDOWN_OFF] & AVRC_PF_RIGHTDOWN_MASK)
+
+#define AVRC_PF_LEFTUP_BIT_NO 7
+#define AVRC_PF_LEFTUP_MASK 0x80
+#define AVRC_PF_LEFTUP_OFF 0
+#define AVRC_PF_LEFTUP_SUPPORTED(x) ((x)[AVRC_PF_LEFTUP_OFF] & AVRC_PF_LEFTUP_MASK)
+
+#define AVRC_PF_LEFTDOWN_BIT_NO 8
+#define AVRC_PF_LEFTDOWN_MASK 0x01
+#define AVRC_PF_LEFTDOWN_OFF 1
+#define AVRC_PF_LEFTDOWN_SUPPORTED(x) ((x)[AVRC_PF_LEFTDOWN_OFF] & AVRC_PF_LEFTDOWN_MASK)
+
+#define AVRC_PF_ROOT_MENU_BIT_NO 9
+#define AVRC_PF_ROOT_MENU_MASK 0x02
+#define AVRC_PF_ROOT_MENU_OFF 1
+#define AVRC_PF_ROOT_MENU_SUPPORTED(x) ((x)[AVRC_PF_ROOT_MENU_OFF] & AVRC_PF_ROOT_MENU_MASK)
+
+#define AVRC_PF_SETUP_MENU_BIT_NO 10
+#define AVRC_PF_SETUP_MENU_MASK 0x04
+#define AVRC_PF_SETUP_MENU_OFF 1
+#define AVRC_PF_SETUP_MENU_SUPPORTED(x) ((x)[AVRC_PF_SETUP_MENU_OFF] & AVRC_PF_SETUP_MENU_MASK)
+
+#define AVRC_PF_CONTENTS_MENU_BIT_NO 11
+#define AVRC_PF_CONTENTS_MENU_MASK 0x08
+#define AVRC_PF_CONTENTS_MENU_OFF 1
+#define AVRC_PF_CONTENTS_MENU_SUPPORTED(x) ((x)[AVRC_PF_CONTENTS_MENU_OFF] & AVRC_PF_CONTENTS_MENU_MASK)
+
+#define AVRC_PF_FAVORITE_MENU_BIT_NO 12
+#define AVRC_PF_FAVORITE_MENU_MASK 0x10
+#define AVRC_PF_FAVORITE_MENU_OFF 1
+#define AVRC_PF_FAVORITE_MENU_SUPPORTED(x) ((x)[AVRC_PF_FAVORITE_MENU_OFF] & AVRC_PF_FAVORITE_MENU_MASK)
+
+#define AVRC_PF_EXIT_BIT_NO 13
+#define AVRC_PF_EXIT_MASK 0x20
+#define AVRC_PF_EXIT_OFF 1
+#define AVRC_PF_EXIT_SUPPORTED(x) ((x)[AVRC_PF_EXIT_OFF] & AVRC_PF_EXIT_MASK)
+
+#define AVRC_PF_0_BIT_NO 14
+#define AVRC_PF_0_MASK 0x40
+#define AVRC_PF_0_OFF 1
+#define AVRC_PF_0_SUPPORTED(x) ((x)[AVRC_PF_0_OFF] & AVRC_PF_0_MASK)
+
+#define AVRC_PF_1_BIT_NO 15
+#define AVRC_PF_1_MASK 0x80
+#define AVRC_PF_1_OFF 1
+#define AVRC_PF_1_SUPPORTED(x) ((x)[AVRC_PF_1_OFF] & AVRC_PF_1_MASK)
+
+#define AVRC_PF_2_BIT_NO 16
+#define AVRC_PF_2_MASK 0x01
+#define AVRC_PF_2_OFF 2
+#define AVRC_PF_2_SUPPORTED(x) ((x)[AVRC_PF_2_OFF] & AVRC_PF_2_MASK)
+
+#define AVRC_PF_3_BIT_NO 17
+#define AVRC_PF_3_MASK 0x02
+#define AVRC_PF_3_OFF 2
+#define AVRC_PF_3_SUPPORTED(x) ((x)[AVRC_PF_3_OFF] & AVRC_PF_3_MASK)
+
+#define AVRC_PF_4_BIT_NO 18
+#define AVRC_PF_4_MASK 0x04
+#define AVRC_PF_4_OFF 2
+#define AVRC_PF_4_SUPPORTED(x) ((x)[AVRC_PF_4_OFF] & AVRC_PF_4_MASK)
+
+#define AVRC_PF_5_BIT_NO 19
+#define AVRC_PF_5_MASK 0x08
+#define AVRC_PF_5_OFF 2
+#define AVRC_PF_5_SUPPORTED(x) ((x)[AVRC_PF_5_OFF] & AVRC_PF_5_MASK)
+
+#define AVRC_PF_6_BIT_NO 20
+#define AVRC_PF_6_MASK 0x10
+#define AVRC_PF_6_OFF 2
+#define AVRC_PF_6_SUPPORTED(x) ((x)[AVRC_PF_6_OFF] & AVRC_PF_6_MASK)
+
+#define AVRC_PF_7_BIT_NO 21
+#define AVRC_PF_7_MASK 0x20
+#define AVRC_PF_7_OFF 2
+#define AVRC_PF_7_SUPPORTED(x) ((x)[AVRC_PF_7_OFF] & AVRC_PF_7_MASK)
+
+#define AVRC_PF_8_BIT_NO 22
+#define AVRC_PF_8_MASK 0x40
+#define AVRC_PF_8_OFF 2
+#define AVRC_PF_8_SUPPORTED(x) ((x)[AVRC_PF_8_OFF] & AVRC_PF_8_MASK)
+
+#define AVRC_PF_9_BIT_NO 23
+#define AVRC_PF_9_MASK 0x80
+#define AVRC_PF_9_OFF 2
+#define AVRC_PF_9_SUPPORTED(x) ((x)[AVRC_PF_9_OFF] & AVRC_PF_9_MASK)
+
+#define AVRC_PF_DOT_BIT_NO 24
+#define AVRC_PF_DOT_MASK 0x01
+#define AVRC_PF_DOT_OFF 3
+#define AVRC_PF_DOT_SUPPORTED(x) ((x)[AVRC_PF_DOT_OFF] & AVRC_PF_DOT_MASK)
+
+#define AVRC_PF_ENTER_BIT_NO 25
+#define AVRC_PF_ENTER_MASK 0x02
+#define AVRC_PF_ENTER_OFF 3
+#define AVRC_PF_ENTER_SUPPORTED(x) ((x)[AVRC_PF_ENTER_OFF] & AVRC_PF_ENTER_MASK)
+
+#define AVRC_PF_CLEAR_BIT_NO 26
+#define AVRC_PF_CLEAR_MASK 0x04
+#define AVRC_PF_CLEAR_OFF 3
+#define AVRC_PF_CLEAR_SUPPORTED(x) ((x)[AVRC_PF_CLEAR_OFF] & AVRC_PF_CLEAR_MASK)
+
+#define AVRC_PF_CHNL_UP_BIT_NO 27
+#define AVRC_PF_CHNL_UP_MASK 0x08
+#define AVRC_PF_CHNL_UP_OFF 3
+#define AVRC_PF_CHNL_UP_SUPPORTED(x) ((x)[AVRC_PF_CHNL_UP_OFF] & AVRC_PF_CHNL_UP_MASK)
+
+#define AVRC_PF_CHNL_DOWN_BIT_NO 28
+#define AVRC_PF_CHNL_DOWN_MASK 0x10
+#define AVRC_PF_CHNL_DOWN_OFF 3
+#define AVRC_PF_CHNL_DOWN_SUPPORTED(x) ((x)[AVRC_PF_CHNL_DOWN_OFF] & AVRC_PF_CHNL_DOWN_MASK)
+
+#define AVRC_PF_PREV_CHNL_BIT_NO 29
+#define AVRC_PF_PREV_CHNL_MASK 0x20
+#define AVRC_PF_PREV_CHNL_OFF 3
+#define AVRC_PF_PREV_CHNL_SUPPORTED(x) ((x)[AVRC_PF_PREV_CHNL_OFF] & AVRC_PF_PREV_CHNL_MASK)
+
+#define AVRC_PF_SOUND_SEL_BIT_NO 30
+#define AVRC_PF_SOUND_SEL_MASK 0x40
+#define AVRC_PF_SOUND_SEL_OFF 3
+#define AVRC_PF_SOUND_SEL_SUPPORTED(x) ((x)[AVRC_PF_SOUND_SEL_OFF] & AVRC_PF_SOUND_SEL_MASK)
+
+#define AVRC_PF_INPUT_SEL_BIT_NO 31
+#define AVRC_PF_INPUT_SEL_MASK 0x80
+#define AVRC_PF_INPUT_SEL_OFF 3
+#define AVRC_PF_INPUT_SEL_SUPPORTED(x) ((x)[AVRC_PF_INPUT_SEL_OFF] & AVRC_PF_INPUT_SEL_MASK)
+
+#define AVRC_PF_DISP_INFO_BIT_NO 32
+#define AVRC_PF_DISP_INFO_MASK 0x01
+#define AVRC_PF_DISP_INFO_OFF 4
+#define AVRC_PF_DISP_INFO_SUPPORTED(x) ((x)[AVRC_PF_DISP_INFO_OFF] & AVRC_PF_DISP_INFO_MASK)
+
+#define AVRC_PF_HELP_BIT_NO 33
+#define AVRC_PF_HELP_MASK 0x02
+#define AVRC_PF_HELP_OFF 4
+#define AVRC_PF_HELP_SUPPORTED(x) ((x)[AVRC_PF_HELP_OFF] & AVRC_PF_HELP_MASK)
+
+#define AVRC_PF_PAGE_UP_BIT_NO 34
+#define AVRC_PF_PAGE_UP_MASK 0x04
+#define AVRC_PF_PAGE_UP_OFF 4
+#define AVRC_PF_PAGE_UP_SUPPORTED(x) ((x)[AVRC_PF_PAGE_UP_OFF] & AVRC_PF_PAGE_UP_MASK)
+
+#define AVRC_PF_PAGE_DOWN_BIT_NO 35
+#define AVRC_PF_PAGE_DOWN_MASK 0x08
+#define AVRC_PF_PAGE_DOWN_OFF 4
+#define AVRC_PF_PAGE_DOWN_SUPPORTED(x) ((x)[AVRC_PF_PAGE_DOWN_OFF] & AVRC_PF_PAGE_DOWN_MASK)
+
+#define AVRC_PF_POWER_BIT_NO 36
+#define AVRC_PF_POWER_MASK 0x10
+#define AVRC_PF_POWER_OFF 4
+#define AVRC_PF_POWER_SUPPORTED(x) ((x)[AVRC_PF_POWER_OFF] & AVRC_PF_POWER_MASK)
+
+#define AVRC_PF_VOL_UP_BIT_NO 37
+#define AVRC_PF_VOL_UP_MASK 0x20
+#define AVRC_PF_VOL_UP_OFF 4
+#define AVRC_PF_VOL_UP_SUPPORTED(x) ((x)[AVRC_PF_VOL_UP_OFF] & AVRC_PF_VOL_UP_MASK)
+
+#define AVRC_PF_VOL_DOWN_BIT_NO 38
+#define AVRC_PF_VOL_DOWN_MASK 0x40
+#define AVRC_PF_VOL_DOWN_OFF 4
+#define AVRC_PF_VOL_DOWN_SUPPORTED(x) ((x)[AVRC_PF_VOL_DOWN_OFF] & AVRC_PF_VOL_DOWN_MASK)
+
+#define AVRC_PF_MUTE_BIT_NO 39
+#define AVRC_PF_MUTE_MASK 0x80
+#define AVRC_PF_MUTE_OFF 4
+#define AVRC_PF_MUTE_SUPPORTED(x) ((x)[AVRC_PF_MUTE_OFF] & AVRC_PF_MUTE_MASK)
+
+#define AVRC_PF_PLAY_BIT_NO 40
+#define AVRC_PF_PLAY_MASK 0x01
+#define AVRC_PF_PLAY_OFF 5
+#define AVRC_PF_PLAY_SUPPORTED(x) ((x)[AVRC_PF_PLAY_OFF] & AVRC_PF_PLAY_MASK)
+
+#define AVRC_PF_STOP_BIT_NO 41
+#define AVRC_PF_STOP_MASK 0x02
+#define AVRC_PF_STOP_OFF 5
+#define AVRC_PF_STOP_SUPPORTED(x) ((x)[AVRC_PF_STOP_OFF] & AVRC_PF_STOP_MASK)
+
+#define AVRC_PF_PAUSE_BIT_NO 42
+#define AVRC_PF_PAUSE_MASK 0x04
+#define AVRC_PF_PAUSE_OFF 5
+#define AVRC_PF_PAUSE_SUPPORTED(x) ((x)[AVRC_PF_PAUSE_OFF] & AVRC_PF_PAUSE_MASK)
+
+#define AVRC_PF_RECORD_BIT_NO 43
+#define AVRC_PF_RECORD_MASK 0x08
+#define AVRC_PF_RECORD_OFF 5
+#define AVRC_PF_RECORD_SUPPORTED(x) ((x)[AVRC_PF_RECORD_OFF] & AVRC_PF_RECORD_MASK)
+
+#define AVRC_PF_REWIND_BIT_NO 44
+#define AVRC_PF_REWIND_MASK 0x10
+#define AVRC_PF_REWIND_OFF 5
+#define AVRC_PF_REWIND_SUPPORTED(x) ((x)[AVRC_PF_REWIND_OFF] & AVRC_PF_REWIND_MASK)
+
+#define AVRC_PF_FAST_FWD_BIT_NO 45
+#define AVRC_PF_FAST_FWD_MASK 0x20
+#define AVRC_PF_FAST_FWD_OFF 5
+#define AVRC_PF_FAST_FWD_SUPPORTED(x) ((x)[AVRC_PF_FAST_FWD_OFF] & AVRC_PF_FAST_FWD_MASK)
+
+#define AVRC_PF_EJECT_BIT_NO 46
+#define AVRC_PF_EJECT_MASK 0x40
+#define AVRC_PF_EJECT_OFF 5
+#define AVRC_PF_EJECT_SUPPORTED(x) ((x)[AVRC_PF_EJECT_OFF] & AVRC_PF_EJECT_MASK)
+
+#define AVRC_PF_FORWARD_BIT_NO 47
+#define AVRC_PF_FORWARD_MASK 0x80
+#define AVRC_PF_FORWARD_OFF 5
+#define AVRC_PF_FORWARD_SUPPORTED(x) ((x)[AVRC_PF_FORWARD_OFF] & AVRC_PF_FORWARD_MASK)
+
+#define AVRC_PF_BACKWARD_BIT_NO 48
+#define AVRC_PF_BACKWARD_MASK 0x01
+#define AVRC_PF_BACKWARD_OFF 6
+#define AVRC_PF_BACKWARD_SUPPORTED(x) ((x)[AVRC_PF_BACKWARD_OFF] & AVRC_PF_BACKWARD_MASK)
+
+#define AVRC_PF_ANGLE_BIT_NO 49
+#define AVRC_PF_ANGLE_MASK 0x02
+#define AVRC_PF_ANGLE_OFF 6
+#define AVRC_PF_ANGLE_SUPPORTED(x) ((x)[AVRC_PF_ANGLE_OFF] & AVRC_PF_ANGLE_MASK)
+
+#define AVRC_PF_SUBPICTURE_BIT_NO 50
+#define AVRC_PF_SUBPICTURE_MASK 0x04
+#define AVRC_PF_SUBPICTURE_OFF 6
+#define AVRC_PF_SUBPICTURE_SUPPORTED(x) ((x)[AVRC_PF_SUBPICTURE_OFF] & AVRC_PF_SUBPICTURE_MASK)
+
+#define AVRC_PF_F1_BIT_NO 51
+#define AVRC_PF_F1_MASK 0x08
+#define AVRC_PF_F1_OFF 6
+#define AVRC_PF_F1_SUPPORTED(x) ((x)[AVRC_PF_F1_OFF] & AVRC_PF_F1_MASK)
+
+#define AVRC_PF_F2_BIT_NO 52
+#define AVRC_PF_F2_MASK 0x10
+#define AVRC_PF_F2_OFF 6
+#define AVRC_PF_F2_SUPPORTED(x) ((x)[AVRC_PF_F2_OFF] & AVRC_PF_F2_MASK)
+
+#define AVRC_PF_F3_BIT_NO 53
+#define AVRC_PF_F3_MASK 0x20
+#define AVRC_PF_F3_OFF 6
+#define AVRC_PF_F3_SUPPORTED(x) ((x)[AVRC_PF_F3_OFF] & AVRC_PF_F3_MASK)
+
+#define AVRC_PF_F4_BIT_NO 54
+#define AVRC_PF_F4_MASK 0x40
+#define AVRC_PF_F4_OFF 6
+#define AVRC_PF_F4_SUPPORTED(x) ((x)[AVRC_PF_F4_OFF] & AVRC_PF_F4_MASK)
+
+#define AVRC_PF_F5_BIT_NO 55
+#define AVRC_PF_F5_MASK 0x80
+#define AVRC_PF_F5_OFF 6
+#define AVRC_PF_F5_SUPPORTED(x) ((x)[AVRC_PF_F5_OFF] & AVRC_PF_F5_MASK)
+
+/* Vendor unique. This PASSTHROUGH command is supported. */
+#define AVRC_PF_VENDOR_BIT_NO 56
+#define AVRC_PF_VENDOR_MASK 0x01
+#define AVRC_PF_VENDOR_OFF 7
+#define AVRC_PF_VENDOR_SUPPORTED(x) ((x)[AVRC_PF_VENDOR_OFF] & AVRC_PF_VENDOR_MASK)
+
+/* Basic Group Navigation. This overrules the SDP entry as it is set per player.7 */
+#define AVRC_PF_GROUP_NAVI_BIT_NO 57
+#define AVRC_PF_GROUP_NAVI_MASK 0x02
+#define AVRC_PF_GROUP_NAVI_OFF 7
+#define AVRC_PF_GROUP_NAVI_SUPPORTED(x) ((x)[AVRC_PF_GROUP_NAVI_OFF] & AVRC_PF_GROUP_NAVI_MASK)
+
+/* Advanced Control Player. This bit is set if the player supports at least AVRCP 1.4. */
+#define AVRC_PF_ADV_CTRL_BIT_NO 58
+#define AVRC_PF_ADV_CTRL_MASK 0x04
+#define AVRC_PF_ADV_CTRL_OFF 7
+#define AVRC_PF_ADV_CTRL_SUPPORTED(x) ((x)[AVRC_PF_ADV_CTRL_OFF] & AVRC_PF_ADV_CTRL_MASK)
+
+/* Browsing. This bit is set if the player supports browsing. */
+#define AVRC_PF_BROWSE_BIT_NO 59
+#define AVRC_PF_BROWSE_MASK 0x08
+#define AVRC_PF_BROWSE_OFF 7
+#define AVRC_PF_BROWSE_SUPPORTED(x) ((x)[AVRC_PF_BROWSE_OFF] & AVRC_PF_BROWSE_MASK)
+
+/* Searching. This bit is set if the player supports searching. */
+#define AVRC_PF_SEARCH_BIT_NO 60
+#define AVRC_PF_SEARCH_MASK 0x10
+#define AVRC_PF_SEARCH_OFF 7
+#define AVRC_PF_SEARCH_SUPPORTED(x) ((x)[AVRC_PF_SEARCH_OFF] & AVRC_PF_SEARCH_MASK)
+
+/* AddToNowPlaying. This bit is set if the player supports the AddToNowPlaying command. */
+#define AVRC_PF_ADD2NOWPLAY_BIT_NO 61
+#define AVRC_PF_ADD2NOWPLAY_MASK 0x20
+#define AVRC_PF_ADD2NOWPLAY_OFF 7
+#define AVRC_PF_ADD2NOWPLAY_SUPPORTED(x) ((x)[AVRC_PF_ADD2NOWPLAY_OFF] & AVRC_PF_ADD2NOWPLAY_MASK)
+
+/* UIDs unique in player browse tree. This bit is set if the player is able to maintain unique UIDs across the player browse tree. */
+#define AVRC_PF_UID_UNIQUE_BIT_NO 62
+#define AVRC_PF_UID_UNIQUE_MASK 0x40
+#define AVRC_PF_UID_UNIQUE_OFF 7
+#define AVRC_PF_UID_UNIQUE_SUPPORTED(x) ((x)[AVRC_PF_UID_UNIQUE_OFF] & AVRC_PF_UID_UNIQUE_MASK)
+
+/* OnlyBrowsableWhenAddressed. This bit is set if the player is only able to be browsed when it is set as the Addressed Player. */
+#define AVRC_PF_BR_WH_ADDR_BIT_NO 63
+#define AVRC_PF_BR_WH_ADDR_MASK 0x80
+#define AVRC_PF_BR_WH_ADDR_OFF 7
+#define AVRC_PF_BR_WH_ADDR_SUPPORTED(x) ((x)[AVRC_PF_BR_WH_ADDR_OFF] & AVRC_PF_BR_WH_ADDR_MASK)
+
+/* OnlySearchableWhenAddressed. This bit is set if the player is only able to be searched when it is set as the Addressed player. */
+#define AVRC_PF_SEARCH_WH_ADDR_BIT_NO 64
+#define AVRC_PF_SEARCH_WH_ADDR_MASK 0x01
+#define AVRC_PF_SEARCH_WH_ADDR_OFF 8
+#define AVRC_PF_SEARCH_WH_ADDR_SUPPORTED(x) ((x)[AVRC_PF_SEARCH_WH_ADDR_OFF] & AVRC_PF_SEARCH_WH_ADDR_MASK)
+
+/* NowPlaying. This bit is set if the player supports the NowPlaying folder. Note that for all players that support browsing this bit shall be set */
+#define AVRC_PF_NOW_PLAY_BIT_NO 65
+#define AVRC_PF_NOW_PLAY_MASK 0x02
+#define AVRC_PF_NOW_PLAY_OFF 8
+#define AVRC_PF_NOW_PLAY_SUPPORTED(x) ((x)[AVRC_PF_NOW_PLAY_OFF] & AVRC_PF_NOW_PLAY_MASK)
+
+/* UIDPersistency. This bit is set if the Player is able to persist UID values between AVRCP Browse Reconnect */
+#define AVRC_PF_UID_PERSIST_BIT_NO 66
+#define AVRC_PF_UID_PERSIST_MASK 0x04
+#define AVRC_PF_UID_PERSIST_OFF 8
+#define AVRC_PF_UID_PERSIST_SUPPORTED(x) ((x)[AVRC_PF_UID_PERSIST_OFF] & AVRC_PF_UID_PERSIST_MASK)
+
+/*****************************************************************************
+** data type definitions
+*****************************************************************************/
+
+/*
+This structure contains the header parameters of an AV/C message.
+*/
+typedef struct
+{
+ UINT8 ctype; /* Command type. */
+ UINT8 subunit_type; /* Subunit type. */
+ UINT8 subunit_id; /* Subunit ID. This value is typically ignored in AVRCP,
+ * except for VENDOR DEPENDENT messages when the value is
+ * vendor-dependent. Value range is 0-7. */
+ UINT8 opcode; /* Op Code (passthrough, vendor, etc) */
+} tAVRC_HDR;
+
+/* This structure contains a UNIT INFO message. */
+typedef struct
+{
+ tAVRC_HDR hdr; /* Message header. */
+ UINT32 company_id; /* Company identifier. */
+ UINT8 unit_type; /* Unit type. Uses the same values as subunit type. */
+ UINT8 unit; /* This value is vendor dependent and typically zero. */
+} tAVRC_MSG_UNIT;
+
+/* This structure contains a SUBUNIT INFO message. */
+typedef struct
+{
+ tAVRC_HDR hdr; /* Message header. */
+ UINT8 subunit_type[AVRC_SUB_TYPE_LEN];
+ /* Array containing subunit type values. */
+ BOOLEAN panel; /* TRUE if the panel subunit type is in the
+ * subunit_type array, FALSE otherwise. */
+ UINT8 page; /* Specifies which part of the subunit type table is
+ * returned. For AVRCP it is typically zero.
+ * Value range is 0-7. */
+} tAVRC_MSG_SUB;
+
+/* This structure contains a VENDOR DEPENDENT message. */
+typedef struct
+{
+ tAVRC_HDR hdr; /* Message header. */
+ UINT32 company_id; /* Company identifier. */
+ UINT8 *p_vendor_data;/* Pointer to vendor dependent data. */
+ UINT16 vendor_len; /* Length in bytes of vendor dependent data. */
+} tAVRC_MSG_VENDOR;
+
+/* PASS THROUGH message structure */
+typedef struct
+{
+ tAVRC_HDR hdr; /* hdr.ctype Unused.
+ * hdr.subunit_type Unused.
+ * hdr.subunit_id Unused. */
+ UINT8 op_id; /* Operation ID. */
+ UINT8 state; /* Keypress state. */
+ UINT8 *p_pass_data;/* Pointer to data. This parameter is only valid
+ * when the op_id is AVRC_ID_VENDOR.*/
+ UINT8 pass_len; /* Length in bytes of data. This parameter is only
+ * valid when the op_id is AVRC_ID_VENDOR.*/
+} tAVRC_MSG_PASS;
+
+/* Command/Response indicator. */
+#define AVRC_CMD AVCT_CMD /* Command message */
+#define AVRC_RSP AVCT_RSP /* Response message */
+
+/* Browsing channel message structure */
+typedef struct
+{
+ tAVRC_HDR hdr; /* hdr.ctype AVRC_CMD or AVRC_RSP.
+ * hdr.subunit_type Unused.
+ * hdr.subunit_id Unused. */
+ UINT8 *p_browse_data; /* Pointer to data. */
+ UINT16 browse_len; /* Length in bytes of data. */
+ BT_HDR *p_browse_pkt; /* The GKI buffer received. Set to NULL, if the callback function wants to keep the buffer */
+} tAVRC_MSG_BROWSE;
+
+/* This is a union of all message type structures. */
+typedef union
+{
+ tAVRC_HDR hdr; /* Message header. */
+ tAVRC_MSG_UNIT unit; /* UNIT INFO message. */
+ tAVRC_MSG_SUB sub; /* SUBUNIT INFO message. */
+ tAVRC_MSG_VENDOR vendor; /* VENDOR DEPENDENT message. */
+ tAVRC_MSG_PASS pass; /* PASS THROUGH message. */
+ tAVRC_MSG_BROWSE browse; /* messages thru browsing channel */
+} tAVRC_MSG;
+
+/* macros */
+#define AVRC_IS_VALID_CAP_ID(a) (((a == AVRC_CAP_COMPANY_ID) || (a == AVRC_CAP_EVENTS_SUPPORTED)) ? TRUE : FALSE)
+
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
+#define AVRC_IS_VALID_EVENT_ID(a) (((a >= AVRC_EVT_PLAY_STATUS_CHANGE) && \
+ (a <= AVRC_EVT_VOLUME_CHANGE)) ? TRUE : FALSE)
+#else /* AVRCP 1.3 */
+#define AVRC_IS_VALID_EVENT_ID(a) (((a >= AVRC_EVT_PLAY_STATUS_CHANGE) && \
+ (a <= AVRC_EVT_APP_SETTING_CHANGE)) ? TRUE : FALSE)
+#endif
+
+#define AVRC_IS_VALID_ATTRIBUTE(a) (((((a > 0) && a <= AVRC_PLAYER_SETTING_SCAN)) || \
+ ((a >= AVRC_PLAYER_SETTING_LOW_MENU_EXT) && \
+ (a <= AVRC_PLAYER_SETTING_HIGH_MENU_EXT))) ? TRUE : FALSE)
+
+
+#define AVRC_IS_VALID_MEDIA_ATTRIBUTE(a) ((a >= AVRC_MEDIA_ATTR_ID_TITLE) && \
+ (a <= AVRC_MEDIA_ATTR_ID_PLAYING_TIME) ? TRUE : FALSE)
+
+#define AVRC_IS_VALID_BATTERY_STATUS(a) ((a <= AVRC_BATTERY_STATUS_FULL_CHARGE) ? TRUE : FALSE)
+
+#define AVRC_IS_VALID_SYSTEM_STATUS(a) ((a <= AVRC_SYSTEMSTATE_PWR_UNPLUGGED) ? TRUE : FALSE)
+
+#define AVRC_IS_VALID_GROUP(a) ((a <= AVRC_PDU_PREV_GROUP) ? TRUE : FALSE)
+
+/* Company ID is 24-bit integer We can not use the macros in bt_types.h */
+#define AVRC_CO_ID_TO_BE_STREAM(p, u32) {*(p)++ = (UINT8)((u32) >> 16); *(p)++ = (UINT8)((u32) >> 8); *(p)++ = (UINT8)(u32); }
+#define AVRC_BE_STREAM_TO_CO_ID(u32, p) {u32 = (((UINT32)(*((p) + 2))) + (((UINT32)(*((p) + 1))) << 8) + (((UINT32)(*(p))) << 16)); (p) += 3;}
+
+/*****************************************************************************
+** data type definitions
+*****************************************************************************/
+#define AVRC_MAX_APP_ATTR_SIZE 16
+#define AVRC_MAX_CHARSET_SIZE 16
+#define AVRC_MAX_ELEM_ATTR_SIZE 8
+
+
+/*****************************************************************************
+** Metadata transfer Building/Parsing definitions
+*****************************************************************************/
+
+typedef struct {
+ UINT16 charset_id;
+ UINT16 str_len;
+ UINT8 *p_str;
+} tAVRC_FULL_NAME;
+
+typedef struct {
+ UINT16 str_len;
+ UINT8 *p_str;
+} tAVRC_NAME;
+
+
+#ifndef AVRC_CAP_MAX_NUM_COMP_ID
+#define AVRC_CAP_MAX_NUM_COMP_ID 4
+#endif
+
+#ifndef AVRC_CAP_MAX_NUM_EVT_ID
+#define AVRC_CAP_MAX_NUM_EVT_ID 16
+#endif
+
+typedef union
+{
+ UINT32 company_id[AVRC_CAP_MAX_NUM_COMP_ID];
+ UINT8 event_id[AVRC_CAP_MAX_NUM_EVT_ID];
+} tAVRC_CAPS_PARAM;
+
+typedef struct
+{
+ UINT8 attr_id;
+ UINT8 attr_val;
+} tAVRC_APP_SETTING;
+
+typedef struct
+{
+ UINT8 attr_id;
+ UINT16 charset_id;
+ UINT8 str_len;
+ UINT8 *p_str;
+} tAVRC_APP_SETTING_TEXT;
+
+typedef UINT8 tAVRC_FEATURE_MASK[AVRC_FEATURE_MASK_SIZE];
+
+typedef struct
+{
+ UINT16 player_id; /* A unique identifier for this media player.*/
+ UINT8 major_type; /* Use AVRC_MJ_TYPE_AUDIO, AVRC_MJ_TYPE_VIDEO, AVRC_MJ_TYPE_BC_AUDIO, or AVRC_MJ_TYPE_BC_VIDEO.*/
+ UINT32 sub_type; /* Use AVRC_SUB_TYPE_NONE, AVRC_SUB_TYPE_AUDIO_BOOK, or AVRC_SUB_TYPE_PODCAST*/
+ UINT8 play_status; /* Use AVRC_PLAYSTATE_STOPPED, AVRC_PLAYSTATE_PLAYING, AVRC_PLAYSTATE_PAUSED, AVRC_PLAYSTATE_FWD_SEEK,
+ AVRC_PLAYSTATE_REV_SEEK, or AVRC_PLAYSTATE_ERROR*/
+ tAVRC_FEATURE_MASK features; /* Supported feature bit mask*/
+ tAVRC_FULL_NAME name; /* The player name, name length and character set id.*/
+} tAVRC_ITEM_PLAYER;
+
+typedef struct
+{
+ tAVRC_UID uid; /* The uid of this folder */
+ UINT8 type; /* Use AVRC_FOLDER_TYPE_MIXED, AVRC_FOLDER_TYPE_TITLES,
+ AVRC_FOLDER_TYPE_ALNUMS, AVRC_FOLDER_TYPE_ARTISTS, AVRC_FOLDER_TYPE_GENRES,
+ AVRC_FOLDER_TYPE_PLAYLISTS, or AVRC_FOLDER_TYPE_YEARS.*/
+ BOOLEAN playable; /* TRUE, if the folder can be played. */
+ tAVRC_FULL_NAME name; /* The folder name, name length and character set id. */
+} tAVRC_ITEM_FOLDER;
+
+typedef struct
+{
+ UINT32 attr_id; /* Use AVRC_MEDIA_ATTR_ID_TITLE, AVRC_MEDIA_ATTR_ID_ARTIST, AVRC_MEDIA_ATTR_ID_ALBUM,
+ AVRC_MEDIA_ATTR_ID_TRACK_NUM, AVRC_MEDIA_ATTR_ID_NUM_TRACKS,
+ AVRC_MEDIA_ATTR_ID_GENRE, AVRC_MEDIA_ATTR_ID_PLAYING_TIME */
+ tAVRC_FULL_NAME name; /* The attribute value, value length and character set id. */
+} tAVRC_ATTR_ENTRY;
+
+typedef struct
+{
+ tAVRC_UID uid; /* The uid of this media element item */
+ UINT8 type; /* Use AVRC_MEDIA_TYPE_AUDIO or AVRC_MEDIA_TYPE_VIDEO. */
+ tAVRC_FULL_NAME name; /* The media name, name length and character set id. */
+ UINT8 attr_count; /* The number of attributes in p_attr_list */
+ tAVRC_ATTR_ENTRY* p_attr_list; /* Attribute entry list. */
+} tAVRC_ITEM_MEDIA;
+
+typedef struct
+{
+ UINT8 item_type; /* AVRC_ITEM_PLAYER, AVRC_ITEM_FOLDER, or AVRC_ITEM_MEDIA */
+ union
+ {
+ tAVRC_ITEM_PLAYER player; /* The properties of a media player item.*/
+ tAVRC_ITEM_FOLDER folder; /* The properties of a folder item.*/
+ tAVRC_ITEM_MEDIA media; /* The properties of a media item.*/
+ } u;
+} tAVRC_ITEM;
+
+/* GetCapability */
+typedef struct
+{
+ UINT8 pdu;
+ tAVRC_STS status;
+ UINT8 opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+ UINT8 capability_id;
+} tAVRC_GET_CAPS_CMD;
+
+/* ListPlayerAppValues */
+typedef struct
+{
+ UINT8 pdu;
+ tAVRC_STS status;
+ UINT8 opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+ UINT8 attr_id;
+} tAVRC_LIST_APP_VALUES_CMD;
+
+/* GetCurAppValue */
+typedef struct
+{
+ UINT8 pdu;
+ tAVRC_STS status;
+ UINT8 opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+ UINT8 num_attr;
+ UINT8 attrs[AVRC_MAX_APP_ATTR_SIZE];
+} tAVRC_GET_CUR_APP_VALUE_CMD;
+
+/* SetAppValue */
+typedef struct
+{
+ UINT8 pdu;
+ tAVRC_STS status;
+ UINT8 opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+ UINT8 num_val;
+ tAVRC_APP_SETTING *p_vals;
+} tAVRC_SET_APP_VALUE_CMD;
+
+/* GetAppAttrTxt */
+typedef struct
+{
+ UINT8 pdu;
+ tAVRC_STS status;
+ UINT8 opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+ UINT8 num_attr;
+ UINT8 attrs[AVRC_MAX_APP_ATTR_SIZE];
+} tAVRC_GET_APP_ATTR_TXT_CMD;
+
+/* GetAppValueTxt */
+typedef struct
+{
+ UINT8 pdu;
+ tAVRC_STS status;
+ UINT8 opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+ UINT8 attr_id;
+ UINT8 num_val;
+ UINT8 vals[AVRC_MAX_APP_ATTR_SIZE];
+} tAVRC_GET_APP_VAL_TXT_CMD;
+
+/* InformCharset */
+typedef struct
+{
+ UINT8 pdu;
+ tAVRC_STS status;
+ UINT8 opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+ UINT8 num_id;
+ UINT16 charsets[AVRC_MAX_CHARSET_SIZE];
+} tAVRC_INFORM_CHARSET_CMD;
+
+/* InformBatteryStatus */
+typedef struct
+{
+ UINT8 pdu;
+ tAVRC_STS status;
+ UINT8 opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+ UINT8 battery_status;
+} tAVRC_BATTERY_STATUS_CMD;
+
+/* GetElemAttrs */
+typedef struct
+{
+ UINT8 pdu;
+ tAVRC_STS status;
+ UINT8 opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+ UINT8 num_attr;
+ UINT32 attrs[AVRC_MAX_ELEM_ATTR_SIZE];
+} tAVRC_GET_ELEM_ATTRS_CMD;
+
+/* RegNotify */
+typedef struct
+{
+ UINT8 pdu;
+ tAVRC_STS status;
+ UINT8 opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+ UINT8 event_id;
+ UINT32 param;
+} tAVRC_REG_NOTIF_CMD;
+
+/* SetAddrPlayer */
+typedef struct
+{
+ UINT8 pdu;
+ tAVRC_STS status;
+ UINT8 opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+ UINT16 player_id;
+} tAVRC_SET_ADDR_PLAYER_CMD;
+
+/* SetBrowsedPlayer */
+typedef struct
+{
+ UINT8 pdu;
+ tAVRC_STS status;
+ UINT8 opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+ UINT16 player_id;
+} tAVRC_SET_BR_PLAYER_CMD;
+
+/* SetAbsVolume */
+typedef struct
+{
+ UINT8 pdu;
+ tAVRC_STS status;
+ UINT8 opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+ UINT8 volume;
+} tAVRC_SET_VOLUME_CMD;
+
+/* GetFolderItems */
+typedef struct
+{
+ UINT8 pdu;
+ tAVRC_STS status;
+ UINT8 opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+ UINT8 scope;
+ UINT32 start_item;
+ UINT32 end_item;
+ UINT8 attr_count;
+ UINT32 *p_attr_list;
+} tAVRC_GET_ITEMS_CMD;
+
+/* ChangePath */
+typedef struct
+{
+ UINT8 pdu;
+ tAVRC_STS status;
+ UINT8 opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+ UINT16 uid_counter;
+ UINT8 direction;
+ tAVRC_UID folder_uid;
+} tAVRC_CHG_PATH_CMD;
+
+/* GetItemAttrs */
+typedef struct
+{
+ UINT8 pdu;
+ tAVRC_STS status;
+ UINT8 opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+ UINT8 scope;
+ tAVRC_UID uid;
+ UINT16 uid_counter;
+ UINT8 attr_count;
+ UINT32 *p_attr_list;
+} tAVRC_GET_ATTRS_CMD;
+
+/* Search */
+typedef struct
+{
+ UINT8 pdu;
+ tAVRC_STS status;
+ UINT8 opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+ tAVRC_FULL_NAME string;
+} tAVRC_SEARCH_CMD;
+
+/* PlayItem */
+typedef struct
+{
+ UINT8 pdu;
+ tAVRC_STS status;
+ UINT8 opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+ UINT8 scope;
+ tAVRC_UID uid;
+ UINT16 uid_counter;
+} tAVRC_PLAY_ITEM_CMD;
+
+/* AddToNowPlaying */
+typedef struct
+{
+ UINT8 pdu;
+ tAVRC_STS status;
+ UINT8 opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+ UINT8 scope;
+ tAVRC_UID uid;
+ UINT16 uid_counter;
+} tAVRC_ADD_TO_PLAY_CMD;
+
+typedef struct
+{
+ UINT8 pdu;
+ tAVRC_STS status;
+ UINT8 opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+} tAVRC_CMD;
+
+/* Continue and Abort */
+typedef struct
+{
+ UINT8 pdu;
+ tAVRC_STS status;
+ UINT8 opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+ UINT8 target_pdu;
+} tAVRC_NEXT_CMD;
+
+typedef union
+{
+ UINT8 pdu;
+ tAVRC_CMD cmd;
+ tAVRC_GET_CAPS_CMD get_caps; /* GetCapability */
+ tAVRC_CMD list_app_attr; /* ListPlayerAppAttr */
+ tAVRC_LIST_APP_VALUES_CMD list_app_values; /* ListPlayerAppValues */
+ tAVRC_GET_CUR_APP_VALUE_CMD get_cur_app_val; /* GetCurAppValue */
+ tAVRC_SET_APP_VALUE_CMD set_app_val; /* SetAppValue */
+ tAVRC_GET_APP_ATTR_TXT_CMD get_app_attr_txt; /* GetAppAttrTxt */
+ tAVRC_GET_APP_VAL_TXT_CMD get_app_val_txt; /* GetAppValueTxt */
+ tAVRC_INFORM_CHARSET_CMD inform_charset; /* InformCharset */
+ tAVRC_BATTERY_STATUS_CMD inform_battery_status; /* InformBatteryStatus */
+ tAVRC_GET_ELEM_ATTRS_CMD get_elem_attrs; /* GetElemAttrs */
+ tAVRC_CMD get_play_status; /* GetPlayStatus */
+ tAVRC_REG_NOTIF_CMD reg_notif; /* RegNotify */
+ tAVRC_NEXT_CMD continu; /* Continue */
+ tAVRC_NEXT_CMD abort; /* Abort */
+
+ tAVRC_SET_ADDR_PLAYER_CMD addr_player; /* SetAddrPlayer */
+ tAVRC_SET_VOLUME_CMD volume; /* SetAbsVolume */
+ tAVRC_SET_BR_PLAYER_CMD br_player; /* SetBrowsedPlayer */
+ tAVRC_GET_ITEMS_CMD get_items; /* GetFolderItems */
+ tAVRC_CHG_PATH_CMD chg_path; /* ChangePath */
+ tAVRC_GET_ATTRS_CMD get_attrs; /* GetItemAttrs */
+ tAVRC_SEARCH_CMD search; /* Search */
+ tAVRC_PLAY_ITEM_CMD play_item; /* PlayItem */
+ tAVRC_ADD_TO_PLAY_CMD add_to_play; /* AddToNowPlaying */
+} tAVRC_COMMAND;
+
+/* GetCapability */
+typedef struct
+{
+ UINT8 pdu;
+ tAVRC_STS status;
+ UINT8 opcode; /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse user. invalid one to generate according to pdu) */
+ UINT8 capability_id;
+ UINT8 count;
+ tAVRC_CAPS_PARAM param;
+} tAVRC_GET_CAPS_RSP;
+
+/* ListPlayerAppAttr */
+typedef struct
+{
+ UINT8 pdu;
+ tAVRC_STS status;
+ UINT8 opcode; /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse user. invalid one to generate according to pdu) */
+ UINT8 num_attr;
+ UINT8 attrs[AVRC_MAX_APP_ATTR_SIZE];
+} tAVRC_LIST_APP_ATTR_RSP;
+
+/* ListPlayerAppValues */
+typedef struct
+{
+ UINT8 pdu;
+ tAVRC_STS status;
+ UINT8 opcode; /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse user. invalid one to generate according to pdu) */
+ UINT8 num_val;
+ UINT8 vals[AVRC_MAX_APP_ATTR_SIZE];
+} tAVRC_LIST_APP_VALUES_RSP;
+
+/* GetCurAppValue */
+typedef struct
+{
+ UINT8 pdu;
+ tAVRC_STS status;
+ UINT8 opcode; /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse user. invalid one to generate according to pdu) */
+ UINT8 num_val;
+ tAVRC_APP_SETTING *p_vals;
+} tAVRC_GET_CUR_APP_VALUE_RSP;
+
+/* GetAppAttrTxt */
+typedef struct
+{
+ UINT8 pdu;
+ tAVRC_STS status;
+ UINT8 opcode; /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse user. invalid one to generate according to pdu) */
+ UINT8 num_attr;
+ tAVRC_APP_SETTING_TEXT *p_attrs;
+} tAVRC_GET_APP_ATTR_TXT_RSP;
+
+/* GetElemAttrs */
+typedef struct
+{
+ UINT8 pdu;
+ tAVRC_STS status;
+ UINT8 opcode; /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse user. invalid one to generate according to pdu) */
+ UINT8 num_attr;
+ tAVRC_ATTR_ENTRY *p_attrs;
+} tAVRC_GET_ELEM_ATTRS_RSP;
+
+/* GetPlayStatus */
+typedef struct
+{
+ UINT8 pdu;
+ tAVRC_STS status;
+ UINT8 opcode; /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse user. invalid one to generate according to pdu) */
+ UINT32 song_len;
+ UINT32 song_pos;
+ UINT8 play_status;
+} tAVRC_GET_PLAY_STATUS_RSP;
+
+/* notification event parameter for AddressedPlayer change */
+typedef struct
+{
+ UINT16 player_id;
+ UINT16 uid_counter;
+} tAVRC_ADDR_PLAYER_PARAM;
+
+#ifndef AVRC_MAX_APP_SETTINGS
+#define AVRC_MAX_APP_SETTINGS 8
+#endif
+
+/* notification event parameter for Player Application setting change */
+typedef struct
+{
+ UINT8 num_attr;
+ UINT8 attr_id[AVRC_MAX_APP_SETTINGS];
+ UINT8 attr_value[AVRC_MAX_APP_SETTINGS];
+} tAVRC_PLAYER_APP_PARAM;
+
+typedef union
+{
+ tAVRC_PLAYSTATE play_status;
+ tAVRC_UID track;
+ UINT32 play_pos;
+ tAVRC_BATTERY_STATUS battery_status;
+ tAVRC_SYSTEMSTATE system_status;
+ tAVRC_PLAYER_APP_PARAM player_setting;
+ tAVRC_ADDR_PLAYER_PARAM addr_player;
+ UINT16 uid_counter;
+ UINT8 volume;
+} tAVRC_NOTIF_RSP_PARAM;
+
+/* RegNotify */
+typedef struct
+{
+ UINT8 pdu;
+ tAVRC_STS status;
+ UINT8 opcode; /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse user. invalid one to generate according to pdu) */
+ UINT8 event_id;
+ tAVRC_NOTIF_RSP_PARAM param;
+} tAVRC_REG_NOTIF_RSP;
+
+/* SetAbsVolume */
+typedef struct
+{
+ UINT8 pdu;
+ tAVRC_STS status;
+ UINT8 opcode; /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse user. invalid one to generate according to pdu) */
+ UINT8 volume;
+} tAVRC_SET_VOLUME_RSP;
+
+/* SetBrowsedPlayer */
+typedef struct
+{
+ UINT8 pdu;
+ tAVRC_STS status;
+ UINT8 opcode; /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse user. invalid one to generate according to pdu) */
+ UINT16 uid_counter;
+ UINT32 num_items;
+ UINT16 charset_id;
+ UINT8 folder_depth;
+ tAVRC_NAME *p_folders;
+} tAVRC_SET_BR_PLAYER_RSP;
+
+/* GetFolderItems */
+typedef struct
+{
+ UINT8 pdu;
+ tAVRC_STS status;
+ UINT8 opcode; /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse user. invalid one to generate according to pdu) */
+ UINT16 uid_counter;
+ UINT16 item_count;
+ tAVRC_ITEM *p_item_list;
+} tAVRC_GET_ITEMS_RSP;
+
+/* ChangePath */
+typedef struct
+{
+ UINT8 pdu;
+ tAVRC_STS status;
+ UINT8 opcode; /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse user. invalid one to generate according to pdu) */
+ UINT32 num_items;
+} tAVRC_CHG_PATH_RSP;
+
+/* GetItemAttrs */
+typedef struct
+{
+ UINT8 pdu;
+ tAVRC_STS status;
+ UINT8 opcode; /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse user. invalid one to generate according to pdu) */
+ UINT8 attr_count;
+ tAVRC_ATTR_ENTRY *p_attr_list;
+} tAVRC_GET_ATTRS_RSP;
+
+/* Search */
+typedef struct
+{
+ UINT8 pdu;
+ tAVRC_STS status;
+ UINT8 opcode; /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse user. invalid one to generate according to pdu) */
+ UINT16 uid_counter;
+ UINT32 num_items;
+} tAVRC_SEARCH_RSP;
+
+
+typedef struct
+{
+ UINT8 pdu;
+ tAVRC_STS status;
+ UINT8 opcode; /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse user. invalid one to generate according to pdu) */
+} tAVRC_RSP;
+
+typedef union
+{
+ UINT8 pdu;
+ tAVRC_RSP rsp;
+ tAVRC_GET_CAPS_RSP get_caps; /* GetCapability */
+ tAVRC_LIST_APP_ATTR_RSP list_app_attr; /* ListPlayerAppAttr */
+ tAVRC_LIST_APP_VALUES_RSP list_app_values; /* ListPlayerAppValues */
+ tAVRC_GET_CUR_APP_VALUE_RSP get_cur_app_val; /* GetCurAppValue */
+ tAVRC_RSP set_app_val; /* SetAppValue */
+ tAVRC_GET_APP_ATTR_TXT_RSP get_app_attr_txt; /* GetAppAttrTxt */
+ tAVRC_GET_APP_ATTR_TXT_RSP get_app_val_txt; /* GetAppValueTxt */
+ tAVRC_RSP inform_charset; /* InformCharset */
+ tAVRC_RSP inform_battery_status; /* InformBatteryStatus */
+ tAVRC_GET_ELEM_ATTRS_RSP get_elem_attrs; /* GetElemAttrs */
+ tAVRC_GET_PLAY_STATUS_RSP get_play_status; /* GetPlayStatus */
+ tAVRC_REG_NOTIF_RSP reg_notif; /* RegNotify */
+ tAVRC_RSP continu; /* Continue */
+ tAVRC_RSP abort; /* Abort */
+
+ tAVRC_RSP addr_player; /* SetAddrPlayer */
+ tAVRC_SET_VOLUME_RSP volume; /* SetAbsVolume */
+ tAVRC_SET_BR_PLAYER_RSP br_player; /* SetBrowsedPlayer */
+ tAVRC_GET_ITEMS_RSP get_items; /* GetFolderItems */
+ tAVRC_CHG_PATH_RSP chg_path; /* ChangePath */
+ tAVRC_GET_ATTRS_RSP get_attrs; /* GetItemAttrs */
+ tAVRC_SEARCH_RSP search; /* Search */
+ tAVRC_RSP play_item; /* PlayItem */
+ tAVRC_RSP add_to_play; /* AddToNowPlaying */
+} tAVRC_RESPONSE;
+
+
+#endif
diff --git a/stack/include/bnep_api.h b/stack/include/bnep_api.h
new file mode 100644
index 0000000..4ac9abb
--- /dev/null
+++ b/stack/include/bnep_api.h
@@ -0,0 +1,463 @@
+/*****************************************************************************
+**
+** Name: bnep_api.h
+**
+** Description: This interface file contains the interface to the Bluetooth
+** Network Encapsilation Protocol (BNEP).
+**
+**
+** Copyright (c) 2001-2004, WIDCOMM Inc., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+#ifndef BNEP_API_H
+#define BNEP_API_H
+
+#include "l2c_api.h"
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+/* Define the minimum offset needed in a GKI buffer for
+** sending BNEP packets. Note, we are currently not sending
+** extension headers, but may in the future, so allow
+** space for them
+*/
+#define BNEP_MINIMUM_OFFSET (15 + L2CAP_MIN_OFFSET)
+#define BNEP_INVALID_HANDLE 0xFFFF
+
+/*****************************************************************************
+** Type Definitions
+*****************************************************************************/
+
+/* Define the result codes from BNEP
+*/
+enum
+{
+ BNEP_SUCCESS, /* Success */
+ BNEP_CONN_DISCONNECTED, /* Connection terminated */
+ BNEP_NO_RESOURCES, /* No resources */
+ BNEP_MTU_EXCEDED, /* Attempt to write long data */
+ BNEP_INVALID_OFFSET, /* Insufficient offset in GKI buffer */
+ BNEP_CONN_FAILED, /* Connection failed */
+ BNEP_CONN_FAILED_CFG, /* Connection failed cos of config */
+ BNEP_CONN_FAILED_SRC_UUID, /* Connection failed wrong source UUID */
+ BNEP_CONN_FAILED_DST_UUID, /* Connection failed wrong destination UUID */
+ BNEP_CONN_FAILED_UUID_SIZE, /* Connection failed wrong size UUID */
+ BNEP_Q_SIZE_EXCEEDED, /* Too many buffers to dest */
+ BNEP_TOO_MANY_FILTERS, /* Too many local filters specified */
+ BNEP_SET_FILTER_FAIL, /* Set Filter failed */
+ BNEP_WRONG_HANDLE, /* Wrong handle for the connection */
+ BNEP_WRONG_STATE, /* Connection is in wrong state */
+ BNEP_SECURITY_FAIL, /* Failed because of security */
+ BNEP_IGNORE_CMD, /* To ignore the rcvd command */
+ BNEP_TX_FLOW_ON, /* tx data flow enabled */
+ BNEP_TX_FLOW_OFF /* tx data flow disabled */
+
+}; typedef UINT8 tBNEP_RESULT;
+
+
+/***************************
+** Callback Functions
+****************************/
+
+/* Connection state change callback prototype. Parameters are
+** Connection handle
+** BD Address of remote
+** Connection state change result
+** BNEP_SUCCESS indicates connection is success
+** All values are used to indicate the reason for failure
+** Flag to indicate if it is just a role change
+*/
+typedef void (tBNEP_CONN_STATE_CB) (UINT16 handle,
+ BD_ADDR rem_bda,
+ tBNEP_RESULT result,
+ BOOLEAN is_role_change);
+
+
+
+
+/* Connection indication callback prototype. Parameters are
+** BD Address of remote, remote UUID and local UUID
+** and flag to indicate role change and handle to the connection
+** When BNEP calls this function profile should
+** use BNEP_ConnectResp call to accept or reject the request
+*/
+typedef void (tBNEP_CONNECT_IND_CB) (UINT16 handle,
+ BD_ADDR bd_addr,
+ tBT_UUID *remote_uuid,
+ tBT_UUID *local_uuid,
+ BOOLEAN is_role_change);
+
+
+
+/* Data buffer received indication callback prototype. Parameters are
+** Handle to the connection
+** Source BD/Ethernet Address
+** Dest BD/Ethernet address
+** Protocol
+** Pointer to the buffer
+** Flag to indicate whether extension headers to be forwarded are present
+*/
+typedef void (tBNEP_DATA_BUF_CB) (UINT16 handle,
+ UINT8 *src,
+ UINT8 *dst,
+ UINT16 protocol,
+ BT_HDR *p_buf,
+ BOOLEAN fw_ext_present);
+
+
+/* Data received indication callback prototype. Parameters are
+** Handle to the connection
+** Source BD/Ethernet Address
+** Dest BD/Ethernet address
+** Protocol
+** Pointer to the beginning of the data
+** Length of data
+** Flag to indicate whether extension headers to be forwarded are present
+*/
+typedef void (tBNEP_DATA_IND_CB) (UINT16 handle,
+ UINT8 *src,
+ UINT8 *dst,
+ UINT16 protocol,
+ UINT8 *p_data,
+ UINT16 len,
+ BOOLEAN fw_ext_present);
+
+/* Flow control callback for TX data. Parameters are
+** Handle to the connection
+** Event flow status
+*/
+typedef void (tBNEP_TX_DATA_FLOW_CB) (UINT16 handle,
+ tBNEP_RESULT event);
+
+/* Filters received indication callback prototype. Parameters are
+** Handle to the connection
+** TRUE if the cb is called for indication
+** Ignore this if it is indication, otherwise it is the result
+** for the filter set operation performed by the local
+** device
+** Number of protocol filters present
+** Pointer to the filters start. Filters are present in pairs
+** of start of the range and end of the range.
+** They will be present in big endian order. First
+** two bytes will be starting of the first range and
+** next two bytes will be ending of the range.
+*/
+typedef void (tBNEP_FILTER_IND_CB) (UINT16 handle,
+ BOOLEAN indication,
+ tBNEP_RESULT result,
+ UINT16 num_filters,
+ UINT8 *p_filters);
+
+
+
+/* Multicast Filters received indication callback prototype. Parameters are
+** Handle to the connection
+** TRUE if the cb is called for indication
+** Ignore this if it is indication, otherwise it is the result
+** for the filter set operation performed by the local
+** device
+** Number of multicast filters present
+** Pointer to the filters start. Filters are present in pairs
+** of start of the range and end of the range.
+** First six bytes will be starting of the first range and
+** next six bytes will be ending of the range.
+*/
+typedef void (tBNEP_MFILTER_IND_CB) (UINT16 handle,
+ BOOLEAN indication,
+ tBNEP_RESULT result,
+ UINT16 num_mfilters,
+ UINT8 *p_mfilters);
+
+/* This is the structure used by profile to register with BNEP */
+typedef struct
+{
+ tBNEP_CONNECT_IND_CB *p_conn_ind_cb; /* To indicate the conn request */
+ tBNEP_CONN_STATE_CB *p_conn_state_cb; /* To indicate conn state change */
+ tBNEP_DATA_IND_CB *p_data_ind_cb; /* To pass the data received */
+ tBNEP_DATA_BUF_CB *p_data_buf_cb; /* To pass the data buffer received */
+ tBNEP_TX_DATA_FLOW_CB *p_tx_data_flow_cb; /* data flow callback */
+ tBNEP_FILTER_IND_CB *p_filter_ind_cb; /* To indicate that peer set protocol filters */
+ tBNEP_MFILTER_IND_CB *p_mfilter_ind_cb; /* To indicate that peer set mcast filters */
+
+} tBNEP_REGISTER;
+
+
+
+/* This is the structure used by profile to get the status of BNEP */
+typedef struct
+{
+#define BNEP_STATUS_FAILE 0
+#define BNEP_STATUS_CONNECTED 1
+ UINT8 con_status;
+
+ UINT16 l2cap_cid;
+ BD_ADDR rem_bda;
+ UINT16 rem_mtu_size;
+ UINT16 xmit_q_depth;
+
+ UINT16 sent_num_filters;
+ UINT16 sent_mcast_filters;
+ UINT16 rcvd_num_filters;
+ UINT16 rcvd_mcast_filters;
+ tBT_UUID src_uuid;
+ tBT_UUID dst_uuid;
+
+} tBNEP_STATUS;
+
+
+
+/*****************************************************************************
+** External Function Declarations
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*******************************************************************************
+**
+** Function BNEP_Register
+**
+** Description This function is called by the upper layer to register
+** its callbacks with BNEP
+**
+** Parameters: p_reg_info - contains all callback function pointers
+**
+**
+** Returns BNEP_SUCCESS if registered successfully
+** BNEP_FAILURE if connection state callback is missing
+**
+*******************************************************************************/
+BNEP_API extern tBNEP_RESULT BNEP_Register (tBNEP_REGISTER *p_reg_info);
+
+/*******************************************************************************
+**
+** Function BNEP_Deregister
+**
+** Description This function is called by the upper layer to de-register
+** its callbacks.
+**
+** Parameters: void
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BNEP_API extern void BNEP_Deregister (void);
+
+
+/*******************************************************************************
+**
+** Function BNEP_Connect
+**
+** Description This function creates a BNEP connection to a remote
+** device.
+**
+** Parameters: p_rem_addr - BD_ADDR of the peer
+** src_uuid - source uuid for the connection
+** dst_uuid - destination uuid for the connection
+** p_handle - pointer to return the handle for the connection
+**
+** Returns BNEP_SUCCESS if connection started
+** BNEP_NO_RESOURCES if no resources
+**
+*******************************************************************************/
+BNEP_API extern tBNEP_RESULT BNEP_Connect (BD_ADDR p_rem_bda,
+ tBT_UUID *src_uuid,
+ tBT_UUID *dst_uuid,
+ UINT16 *p_handle);
+
+/*******************************************************************************
+**
+** Function BNEP_ConnectResp
+**
+** Description This function is called in responce to connection indication
+**
+**
+** Parameters: handle - handle given in the connection indication
+** resp - responce for the connection indication
+**
+** Returns BNEP_SUCCESS if connection started
+** BNEP_WRONG_HANDLE if the connection is not found
+** BNEP_WRONG_STATE if the responce is not expected
+**
+*******************************************************************************/
+BNEP_API extern tBNEP_RESULT BNEP_ConnectResp (UINT16 handle, tBNEP_RESULT resp);
+
+/*******************************************************************************
+**
+** Function BNEP_Disconnect
+**
+** Description This function is called to close the specified connection.
+**
+** Parameters: handle - handle of the connection
+**
+** Returns BNEP_SUCCESS if connection is disconnected
+** BNEP_WRONG_HANDLE if no connection is not found
+**
+*******************************************************************************/
+BNEP_API extern tBNEP_RESULT BNEP_Disconnect (UINT16 handle);
+
+/*******************************************************************************
+**
+** Function BNEP_WriteBuf
+**
+** Description This function sends data in a GKI buffer on BNEP connection
+**
+** Parameters: handle - handle of the connection to write
+** p_dest_addr - BD_ADDR/Ethernet addr of the destination
+** p_buf - pointer to address of buffer with data
+** protocol - protocol type of the packet
+** p_src_addr - (optional) BD_ADDR/ethernet address of the source
+** (should be NULL if it is local BD Addr)
+** fw_ext_present - forwarded extensions present
+**
+** Returns: BNEP_WRONG_HANDLE - if passed handle is not valid
+** BNEP_MTU_EXCEDED - If the data length is greater than MTU
+** BNEP_IGNORE_CMD - If the packet is filtered out
+** BNEP_Q_SIZE_EXCEEDED - If the Tx Q is full
+** BNEP_SUCCESS - If written successfully
+**
+*******************************************************************************/
+BNEP_API extern tBNEP_RESULT BNEP_WriteBuf (UINT16 handle,
+ UINT8 *p_dest_addr,
+ BT_HDR *p_buf,
+ UINT16 protocol,
+ UINT8 *p_src_addr,
+ BOOLEAN fw_ext_present);
+
+/*******************************************************************************
+**
+** Function BNEP_Write
+**
+** Description This function sends data over a BNEP connection
+**
+** Parameters: handle - handle of the connection to write
+** p_dest_addr - BD_ADDR/Ethernet addr of the destination
+** p_data - pointer to data start
+** protocol - protocol type of the packet
+** p_src_addr - (optional) BD_ADDR/ethernet address of the source
+** (should be NULL if it is local BD Addr)
+** fw_ext_present - forwarded extensions present
+**
+** Returns: BNEP_WRONG_HANDLE - if passed handle is not valid
+** BNEP_MTU_EXCEDED - If the data length is greater than MTU
+** BNEP_IGNORE_CMD - If the packet is filtered out
+** BNEP_Q_SIZE_EXCEEDED - If the Tx Q is full
+** BNEP_NO_RESOURCES - If not able to allocate a buffer
+** BNEP_SUCCESS - If written successfully
+**
+*******************************************************************************/
+BNEP_API extern tBNEP_RESULT BNEP_Write (UINT16 handle,
+ UINT8 *p_dest_addr,
+ UINT8 *p_data,
+ UINT16 len,
+ UINT16 protocol,
+ UINT8 *p_src_addr,
+ BOOLEAN fw_ext_present);
+
+/*******************************************************************************
+**
+** Function BNEP_SetProtocolFilters
+**
+** Description This function sets the protocol filters on peer device
+**
+** Parameters: handle - Handle for the connection
+** num_filters - total number of filter ranges
+** p_start_array - Array of beginings of all protocol ranges
+** p_end_array - Array of ends of all protocol ranges
+**
+** Returns BNEP_WRONG_HANDLE - if the connection handle is not valid
+** BNEP_SET_FILTER_FAIL - if the connection is in wrong state
+** BNEP_TOO_MANY_FILTERS - if too many filters
+** BNEP_SUCCESS - if request sent successfully
+**
+*******************************************************************************/
+BNEP_API extern tBNEP_RESULT BNEP_SetProtocolFilters (UINT16 handle,
+ UINT16 num_filters,
+ UINT16 *p_start_array,
+ UINT16 *p_end_array);
+
+/*******************************************************************************
+**
+** Function BNEP_SetMulticastFilters
+**
+** Description This function sets the filters for multicast addresses for BNEP.
+**
+** Parameters: handle - Handle for the connection
+** num_filters - total number of filter ranges
+** p_start_array - Pointer to sequence of beginings of all
+** multicast address ranges
+** p_end_array - Pointer to sequence of ends of all
+** multicast address ranges
+**
+** Returns BNEP_WRONG_HANDLE - if the connection handle is not valid
+** BNEP_SET_FILTER_FAIL - if the connection is in wrong state
+** BNEP_TOO_MANY_FILTERS - if too many filters
+** BNEP_SUCCESS - if request sent successfully
+**
+*******************************************************************************/
+BNEP_API extern tBNEP_RESULT BNEP_SetMulticastFilters (UINT16 handle,
+ UINT16 num_filters,
+ UINT8 *p_start_array,
+ UINT8 *p_end_array);
+
+/*******************************************************************************
+**
+** Function BNEP_GetMyBdAddr
+**
+** Description This function returns a pointer to the local device BD address.
+** If the BD address has not been read yet, it returns NULL.
+**
+** Returns the BD address
+**
+*******************************************************************************/
+BNEP_API extern UINT8 *BNEP_GetMyBdAddr (void);
+
+/*******************************************************************************
+**
+** Function BNEP_SetTraceLevel
+**
+** Description This function sets the trace level for BNEP. If called with
+** a value of 0xFF, it simply reads the current trace level.
+**
+** Returns the new (current) trace level
+**
+*******************************************************************************/
+BNEP_API extern UINT8 BNEP_SetTraceLevel (UINT8 new_level);
+
+/*******************************************************************************
+**
+** Function BNEP_Init
+**
+** Description This function initializes the BNEP unit. It should be called
+** before accessing any other APIs to initialize the control block
+**
+** Returns void
+**
+*******************************************************************************/
+BNEP_API extern void BNEP_Init (void);
+
+/*******************************************************************************
+**
+** Function BNEP_GetStatus
+**
+** Description This function gets the status information for BNEP connection
+**
+** Returns BNEP_SUCCESS - if the status is available
+** BNEP_NO_RESOURCES - if no structure is passed for output
+** BNEP_WRONG_HANDLE - if the handle is invalid
+** BNEP_WRONG_STATE - if not in connected state
+**
+*******************************************************************************/
+BNEP_API extern tBNEP_RESULT BNEP_GetStatus (UINT16 handle, tBNEP_STATUS *p_status);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
diff --git a/stack/include/bt_types.h b/stack/include/bt_types.h
new file mode 100644
index 0000000..801b153
--- /dev/null
+++ b/stack/include/bt_types.h
@@ -0,0 +1,684 @@
+/****************************************************************************
+**
+** Name bt_types.h
+**
+** Function this file contains definitions that are shared between
+** units in the Bluetooth system such as events.
+**
+** Copyright (c) 1999-2010, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+****************************************************************************/
+
+#ifndef BT_TYPES_H
+#define BT_TYPES_H
+
+#include "data_types.h"
+
+#ifdef _WIN32
+#ifdef BLUESTACK_TESTER
+ #include "bte_stack_entry.h"
+#endif
+#endif
+
+/* READ WELL !!
+**
+** This section defines global events. These are events that cross layers.
+** Any event that passes between layers MUST be one of these events. Tasks
+** can use their own events internally, but a FUNDAMENTAL design issue is
+** that global events MUST be one of these events defined below.
+**
+** The convention used is the the event name contains the layer that the
+** event is going to.
+*/
+#define BT_EVT_MASK 0xFF00
+#define BT_SUB_EVT_MASK 0x00FF
+ /* To Bluetooth Upper Layers */
+ /************************************/
+#define BT_EVT_TO_BTU_L2C_EVT 0x0900 /* L2CAP event */
+#define BT_EVT_TO_BTU_HCI_EVT 0x1000 /* HCI Event */
+#define BT_EVT_TO_BTU_HCI_BR_EDR_EVT (0x0000 | BT_EVT_TO_BTU_HCI_EVT) /* event from BR/EDR controller */
+#define BT_EVT_TO_BTU_HCI_AMP1_EVT (0x0001 | BT_EVT_TO_BTU_HCI_EVT) /* event from local AMP 1 controller */
+#define BT_EVT_TO_BTU_HCI_AMP2_EVT (0x0002 | BT_EVT_TO_BTU_HCI_EVT) /* event from local AMP 2 controller */
+#define BT_EVT_TO_BTU_HCI_AMP3_EVT (0x0003 | BT_EVT_TO_BTU_HCI_EVT) /* event from local AMP 3 controller */
+
+#define BT_EVT_TO_BTU_HCI_ACL 0x1100 /* ACL Data from HCI */
+#define BT_EVT_TO_BTU_HCI_SCO 0x1200 /* SCO Data from HCI */
+#define BT_EVT_TO_BTU_HCIT_ERR 0x1300 /* HCI Transport Error */
+
+#define BT_EVT_TO_BTU_SP_EVT 0x1400 /* Serial Port Event */
+#define BT_EVT_TO_BTU_SP_DATA 0x1500 /* Serial Port Data */
+
+#define BT_EVT_TO_BTU_HCI_CMD 0x1600 /* HCI command from upper layer */
+
+
+#define BT_EVT_TO_BTU_L2C_SEG_XMIT 0x1900 /* L2CAP segment(s) transmitted */
+
+#define BT_EVT_PROXY_INCOMING_MSG 0x1A00 /* BlueStackTester event: incoming message from target */
+
+#define BT_EVT_BTSIM 0x1B00 /* Insight BTSIM event */
+#define BT_EVT_BTISE 0x1C00 /* Insight Script Engine event */
+
+ /* To LM */
+ /************************************/
+#define BT_EVT_TO_LM_HCI_CMD 0x2000 /* HCI Command */
+#define BT_EVT_TO_LM_HCI_ACL 0x2100 /* HCI ACL Data */
+#define BT_EVT_TO_LM_HCI_SCO 0x2200 /* HCI SCO Data */
+#define BT_EVT_TO_LM_HCIT_ERR 0x2300 /* HCI Transport Error */
+#define BT_EVT_TO_LM_LC_EVT 0x2400 /* LC event */
+#define BT_EVT_TO_LM_LC_LMP 0x2500 /* LC Received LMP command frame */
+#define BT_EVT_TO_LM_LC_ACL 0x2600 /* LC Received ACL data */
+#define BT_EVT_TO_LM_LC_SCO 0x2700 /* LC Received SCO data (not used) */
+#define BT_EVT_TO_LM_LC_ACL_TX 0x2800 /* LMP data transmit complete */
+#define BT_EVT_TO_LM_LC_LMPC_TX 0x2900 /* LMP Command transmit complete */
+#define BT_EVT_TO_LM_LOCAL_ACL_LB 0x2a00 /* Data to be locally loopbacked */
+#define BT_EVT_TO_LM_HCI_ACL_ACK 0x2b00 /* HCI ACL Data ack (not used) */
+#define BT_EVT_TO_LM_DIAG 0x2c00 /* LM Diagnostics commands */
+
+
+#define BT_EVT_TO_BTM_CMDS 0x2f00
+#define BT_EVT_TO_BTM_PM_MDCHG_EVT (0x0001 | BT_EVT_TO_BTM_CMDS)
+
+#define BT_EVT_TO_TCS_CMDS 0x3000
+
+#define BT_EVT_TO_OBX_CL_MSG 0x3100
+#define BT_EVT_TO_OBX_SR_MSG 0x3200
+
+#define BT_EVT_TO_CTP_CMDS 0x3300
+
+/* Obex Over L2CAP */
+#define BT_EVT_TO_OBX_CL_L2C_MSG 0x3400
+#define BT_EVT_TO_OBX_SR_L2C_MSG 0x3500
+
+/* ftp events */
+#define BT_EVT_TO_FTP_SRVR_CMDS 0x3800
+#define BT_EVT_TO_FTP_CLNT_CMDS 0x3900
+
+#define BT_EVT_TO_BTU_SAP 0x3a00 /* SIM Access Profile events */
+
+/* opp events */
+#define BT_EVT_TO_OPP_SRVR_CMDS 0x3b00
+#define BT_EVT_TO_OPP_CLNT_CMDS 0x3c00
+
+/* gap events */
+#define BT_EVT_TO_GAP_MSG 0x3d00
+
+/* start timer */
+#define BT_EVT_TO_START_TIMER 0x3e00
+
+/* start quick timer */
+#define BT_EVT_TO_START_QUICK_TIMER 0x3f00
+
+
+/* for NFC */
+ /************************************/
+#define BT_EVT_TO_NFC_NCI 0x4000 /* NCI Command, Notification or Data*/
+#define BT_EVT_TO_NFC_INIT 0x4100 /* Initialization message */
+#define BT_EVT_TO_LLCP_ECHO 0x4200 /* LLCP Echo Service */
+#define BT_EVT_TO_LLCP_SOCKET 0x4300 /* LLCP over TCP/IP */
+#define BT_EVT_TO_NCI_LP 0x4400 /* Low power */
+#define BT_EVT_TO_NFC_ERR 0x4500 /* Error notification to NFC Task */
+
+#define BT_EVT_TO_NFCCSIM_NCI 0x4a00 /* events to NFCC simulation (NCI packets) */
+
+/* HCISU Events */
+
+#define BT_EVT_HCISU 0x5000
+
+// btla-specific ++
+#define BT_EVT_TO_HCISU_RECONFIG_EVT (0x0001 | BT_EVT_HCISU)
+#define BT_EVT_TO_HCISU_UPDATE_BAUDRATE_EVT (0x0002 | BT_EVT_HCISU)
+#define BT_EVT_TO_HCISU_LP_ENABLE_EVT (0x0003 | BT_EVT_HCISU)
+#define BT_EVT_TO_HCISU_LP_DISABLE_EVT (0x0004 | BT_EVT_HCISU)
+// btla-specific --
+#define BT_EVT_TO_HCISU_LP_APP_SLEEPING_EVT (0x0005 | BT_EVT_HCISU)
+#define BT_EVT_TO_HCISU_LP_ALLOW_BT_SLEEP_EVT (0x0006 | BT_EVT_HCISU)
+#define BT_EVT_TO_HCISU_LP_WAKEUP_HOST_EVT (0x0007 | BT_EVT_HCISU)
+#define BT_EVT_TO_HCISU_LP_RCV_H4IBSS_EVT (0x0008 | BT_EVT_HCISU)
+#define BT_EVT_TO_HCISU_H5_RESET_EVT (0x0009 | BT_EVT_HCISU)
+#define BT_EVT_HCISU_START_QUICK_TIMER (0x000a | BT_EVT_HCISU)
+
+#define BT_EVT_DATA_TO_AMP_1 0x5100
+#define BT_EVT_DATA_TO_AMP_15 0x5f00
+
+/* HSP Events */
+
+#define BT_EVT_BTU_HSP2 0x6000
+
+#define BT_EVT_TO_BTU_HSP2_EVT (0x0001 | BT_EVT_BTU_HSP2)
+
+/* BPP Events */
+#define BT_EVT_TO_BPP_PR_CMDS 0x6100 /* Printer Events */
+#define BT_EVT_TO_BPP_SND_CMDS 0x6200 /* BPP Sender Events */
+
+/* BIP Events */
+#define BT_EVT_TO_BIP_CMDS 0x6300
+
+/* HCRP Events */
+
+#define BT_EVT_BTU_HCRP 0x7000
+
+#define BT_EVT_TO_BTU_HCRP_EVT (0x0001 | BT_EVT_BTU_HCRP)
+#define BT_EVT_TO_BTU_HCRPM_EVT (0x0002 | BT_EVT_BTU_HCRP)
+
+
+#define BT_EVT_BTU_HFP 0x8000
+#define BT_EVT_TO_BTU_HFP_EVT (0x0001 | BT_EVT_BTU_HFP)
+
+#define BT_EVT_BTU_IPC_EVT 0x9000
+#define BT_EVT_BTU_IPC_LOGMSG_EVT (0x0000 | BT_EVT_BTU_IPC_EVT)
+#define BT_EVT_BTU_IPC_ACL_EVT (0x0001 | BT_EVT_BTU_IPC_EVT)
+#define BT_EVT_BTU_IPC_BTU_EVT (0x0002 | BT_EVT_BTU_IPC_EVT)
+#define BT_EVT_BTU_IPC_L2C_EVT (0x0003 | BT_EVT_BTU_IPC_EVT)
+#define BT_EVT_BTU_IPC_L2C_MSG_EVT (0x0004 | BT_EVT_BTU_IPC_EVT)
+#define BT_EVT_BTU_IPC_BTM_EVT (0x0005 | BT_EVT_BTU_IPC_EVT)
+#define BT_EVT_BTU_IPC_AVDT_EVT (0x0006 | BT_EVT_BTU_IPC_EVT)
+#define BT_EVT_BTU_IPC_SLIP_EVT (0x0007 | BT_EVT_BTU_IPC_EVT)
+#define BT_EVT_BTU_IPC_MGMT_EVT (0x0008 | BT_EVT_BTU_IPC_EVT)
+#define BT_EVT_BTU_IPC_BTTRC_EVT (0x0009 | BT_EVT_BTU_IPC_EVT)
+#define BT_EVT_BTU_IPC_BURST_EVT (0x000A | BT_EVT_BTU_IPC_EVT)
+
+
+/* BTIF Events */
+#define BT_EVT_BTIF 0xA000
+#define BT_EVT_CONTEXT_SWITCH_EVT (0x0001 | BT_EVT_BTIF)
+
+#define BT_EVT_TRIGGER_STACK_INIT EVENT_MASK(APPL_EVT_0)
+
+
+/* Define the header of each buffer used in the Bluetooth stack.
+*/
+typedef struct
+{
+ UINT16 event;
+ UINT16 len;
+ UINT16 offset;
+ UINT16 layer_specific;
+} BT_HDR;
+
+#define BT_HDR_SIZE (sizeof (BT_HDR))
+
+#define BT_PSM_SDP 0x0001
+#define BT_PSM_RFCOMM 0x0003
+#define BT_PSM_TCS 0x0005
+#define BT_PSM_CTP 0x0007
+#define BT_PSM_BNEP 0x000F
+#define BT_PSM_HIDC 0x0011
+#define BT_PSM_HIDI 0x0013
+#define BT_PSM_UPNP 0x0015
+#define BT_PSM_AVCTP 0x0017
+#define BT_PSM_AVDTP 0x0019
+#define BT_PSM_AVCTP_13 0x001B /* Advanced Control - Browsing */
+#define BT_PSM_UDI_CP 0x001D /* Unrestricted Digital Information Profile C-Plane */
+#define BT_PSM_ATT 0x001F /* Attribute Protocol */
+
+
+/* These macros extract the HCI opcodes from a buffer
+*/
+#define HCI_GET_CMD_HDR_OPCODE(p) (UINT16)((*((UINT8 *)((p) + 1) + p->offset) + \
+ (*((UINT8 *)((p) + 1) + p->offset + 1) << 8)))
+#define HCI_GET_CMD_HDR_PARAM_LEN(p) (UINT8) (*((UINT8 *)((p) + 1) + p->offset + 2))
+
+#define HCI_GET_EVT_HDR_OPCODE(p) (UINT8)(*((UINT8 *)((p) + 1) + p->offset))
+#define HCI_GET_EVT_HDR_PARAM_LEN(p) (UINT8) (*((UINT8 *)((p) + 1) + p->offset + 1))
+
+
+/********************************************************************************
+** Macros to get and put bytes to and from a stream (Little Endian format).
+*/
+#define UINT32_TO_STREAM(p, u32) {*(p)++ = (UINT8)(u32); *(p)++ = (UINT8)((u32) >> 8); *(p)++ = (UINT8)((u32) >> 16); *(p)++ = (UINT8)((u32) >> 24);}
+#define UINT24_TO_STREAM(p, u24) {*(p)++ = (UINT8)(u24); *(p)++ = (UINT8)((u24) >> 8); *(p)++ = (UINT8)((u24) >> 16);}
+#define UINT16_TO_STREAM(p, u16) {*(p)++ = (UINT8)(u16); *(p)++ = (UINT8)((u16) >> 8);}
+#define UINT8_TO_STREAM(p, u8) {*(p)++ = (UINT8)(u8);}
+#define INT8_TO_STREAM(p, u8) {*(p)++ = (INT8)(u8);}
+#define ARRAY32_TO_STREAM(p, a) {register int ijk; for (ijk = 0; ijk < 32; ijk++) *(p)++ = (UINT8) a[31 - ijk];}
+#define ARRAY16_TO_STREAM(p, a) {register int ijk; for (ijk = 0; ijk < 16; ijk++) *(p)++ = (UINT8) a[15 - ijk];}
+#define ARRAY8_TO_STREAM(p, a) {register int ijk; for (ijk = 0; ijk < 8; ijk++) *(p)++ = (UINT8) a[7 - ijk];}
+#define BDADDR_TO_STREAM(p, a) {register int ijk; for (ijk = 0; ijk < BD_ADDR_LEN; ijk++) *(p)++ = (UINT8) a[BD_ADDR_LEN - 1 - ijk];}
+#define LAP_TO_STREAM(p, a) {register int ijk; for (ijk = 0; ijk < LAP_LEN; ijk++) *(p)++ = (UINT8) a[LAP_LEN - 1 - ijk];}
+#define DEVCLASS_TO_STREAM(p, a) {register int ijk; for (ijk = 0; ijk < DEV_CLASS_LEN;ijk++) *(p)++ = (UINT8) a[DEV_CLASS_LEN - 1 - ijk];}
+#define ARRAY_TO_STREAM(p, a, len) {register int ijk; for (ijk = 0; ijk < len; ijk++) *(p)++ = (UINT8) a[ijk];}
+#define REVERSE_ARRAY_TO_STREAM(p, a, len) {register int ijk; for (ijk = 0; ijk < len; ijk++) *(p)++ = (UINT8) a[len - 1 - ijk];}
+
+#define STREAM_TO_UINT8(u8, p) {u8 = (UINT8)(*(p)); (p) += 1;}
+#define STREAM_TO_UINT16(u16, p) {u16 = ((UINT16)(*(p)) + (((UINT16)(*((p) + 1))) << 8)); (p) += 2;}
+#define STREAM_TO_UINT24(u32, p) {u32 = (((UINT32)(*(p))) + ((((UINT32)(*((p) + 1)))) << 8) + ((((UINT32)(*((p) + 2)))) << 16) ); (p) += 3;}
+#define STREAM_TO_UINT32(u32, p) {u32 = (((UINT32)(*(p))) + ((((UINT32)(*((p) + 1)))) << 8) + ((((UINT32)(*((p) + 2)))) << 16) + ((((UINT32)(*((p) + 3)))) << 24)); (p) += 4;}
+#define STREAM_TO_BDADDR(a, p) {register int ijk; register UINT8 *pbda = (UINT8 *)a + BD_ADDR_LEN - 1; for (ijk = 0; ijk < BD_ADDR_LEN; ijk++) *pbda-- = *p++;}
+#define STREAM_TO_ARRAY32(a, p) {register int ijk; register UINT8 *_pa = (UINT8 *)a + 31; for (ijk = 0; ijk < 32; ijk++) *_pa-- = *p++;}
+#define STREAM_TO_ARRAY16(a, p) {register int ijk; register UINT8 *_pa = (UINT8 *)a + 15; for (ijk = 0; ijk < 16; ijk++) *_pa-- = *p++;}
+#define STREAM_TO_ARRAY8(a, p) {register int ijk; register UINT8 *_pa = (UINT8 *)a + 7; for (ijk = 0; ijk < 8; ijk++) *_pa-- = *p++;}
+#define STREAM_TO_DEVCLASS(a, p) {register int ijk; register UINT8 *_pa = (UINT8 *)a + DEV_CLASS_LEN - 1; for (ijk = 0; ijk < DEV_CLASS_LEN; ijk++) *_pa-- = *p++;}
+#define STREAM_TO_LAP(a, p) {register int ijk; register UINT8 *plap = (UINT8 *)a + LAP_LEN - 1; for (ijk = 0; ijk < LAP_LEN; ijk++) *plap-- = *p++;}
+#define STREAM_TO_ARRAY(a, p, len) {register int ijk; for (ijk = 0; ijk < len; ijk++) ((UINT8 *) a)[ijk] = *p++;}
+#define REVERSE_STREAM_TO_ARRAY(a, p, len) {register int ijk; register UINT8 *_pa = (UINT8 *)a + len - 1; for (ijk = 0; ijk < len; ijk++) *_pa-- = *p++;}
+
+/********************************************************************************
+** Macros to get and put bytes to and from a field (Little Endian format).
+** These are the same as to stream, except the pointer is not incremented.
+*/
+#define UINT32_TO_FIELD(p, u32) {*(UINT8 *)(p) = (UINT8)(u32); *((UINT8 *)(p)+1) = (UINT8)((u32) >> 8); *((UINT8 *)(p)+2) = (UINT8)((u32) >> 16); *((UINT8 *)(p)+3) = (UINT8)((u32) >> 24);}
+#define UINT24_TO_FIELD(p, u24) {*(UINT8 *)(p) = (UINT8)(u24); *((UINT8 *)(p)+1) = (UINT8)((u24) >> 8); *((UINT8 *)(p)+2) = (UINT8)((u24) >> 16);}
+#define UINT16_TO_FIELD(p, u16) {*(UINT8 *)(p) = (UINT8)(u16); *((UINT8 *)(p)+1) = (UINT8)((u16) >> 8);}
+#define UINT8_TO_FIELD(p, u8) {*(UINT8 *)(p) = (UINT8)(u8);}
+
+
+/********************************************************************************
+** Macros to get and put bytes to and from a stream (Big Endian format)
+*/
+#define UINT32_TO_BE_STREAM(p, u32) {*(p)++ = (UINT8)((u32) >> 24); *(p)++ = (UINT8)((u32) >> 16); *(p)++ = (UINT8)((u32) >> 8); *(p)++ = (UINT8)(u32); }
+#define UINT24_TO_BE_STREAM(p, u24) {*(p)++ = (UINT8)((u24) >> 16); *(p)++ = (UINT8)((u24) >> 8); *(p)++ = (UINT8)(u24);}
+#define UINT16_TO_BE_STREAM(p, u16) {*(p)++ = (UINT8)((u16) >> 8); *(p)++ = (UINT8)(u16);}
+#define UINT8_TO_BE_STREAM(p, u8) {*(p)++ = (UINT8)(u8);}
+#define ARRAY_TO_BE_STREAM(p, a, len) {register int ijk; for (ijk = 0; ijk < len; ijk++) *(p)++ = (UINT8) a[ijk];}
+
+#define BE_STREAM_TO_UINT8(u8, p) {u8 = (UINT8)(*(p)); (p) += 1;}
+#define BE_STREAM_TO_UINT16(u16, p) {u16 = (UINT16)(((UINT16)(*(p)) << 8) + (UINT16)(*((p) + 1))); (p) += 2;}
+#define BE_STREAM_TO_UINT24(u32, p) {u32 = (((UINT32)(*((p) + 2))) + ((UINT32)(*((p) + 1)) << 8) + ((UINT32)(*(p)) << 16)); (p) += 3;}
+#define BE_STREAM_TO_UINT32(u32, p) {u32 = ((UINT32)(*((p) + 3)) + ((UINT32)(*((p) + 2)) << 8) + ((UINT32)(*((p) + 1)) << 16) + ((UINT32)(*(p)) << 24)); (p) += 4;}
+#define BE_STREAM_TO_ARRAY(p, a, len) {register int ijk; for (ijk = 0; ijk < len; ijk++) ((UINT8 *) a)[ijk] = *p++;}
+
+
+/********************************************************************************
+** Macros to get and put bytes to and from a field (Big Endian format).
+** These are the same as to stream, except the pointer is not incremented.
+*/
+#define UINT32_TO_BE_FIELD(p, u32) {*(UINT8 *)(p) = (UINT8)((u32) >> 24); *((UINT8 *)(p)+1) = (UINT8)((u32) >> 16); *((UINT8 *)(p)+2) = (UINT8)((u32) >> 8); *((UINT8 *)(p)+3) = (UINT8)(u32); }
+#define UINT24_TO_BE_FIELD(p, u24) {*(UINT8 *)(p) = (UINT8)((u24) >> 16); *((UINT8 *)(p)+1) = (UINT8)((u24) >> 8); *((UINT8 *)(p)+2) = (UINT8)(u24);}
+#define UINT16_TO_BE_FIELD(p, u16) {*(UINT8 *)(p) = (UINT8)((u16) >> 8); *((UINT8 *)(p)+1) = (UINT8)(u16);}
+#define UINT8_TO_BE_FIELD(p, u8) {*(UINT8 *)(p) = (UINT8)(u8);}
+
+
+/* Common Bluetooth field definitions */
+#define BD_ADDR_LEN 6 /* Device address length */
+typedef UINT8 BD_ADDR[BD_ADDR_LEN]; /* Device address */
+typedef UINT8 *BD_ADDR_PTR; /* Pointer to Device Address */
+
+#define AMP_KEY_TYPE_GAMP 0
+#define AMP_KEY_TYPE_WIFI 1
+#define AMP_KEY_TYPE_UWB 2
+typedef UINT8 tAMP_KEY_TYPE;
+
+#define BT_OCTET8_LEN 8
+typedef UINT8 BT_OCTET8[BT_OCTET8_LEN]; /* octet array: size 16 */
+
+#define LINK_KEY_LEN 16
+typedef UINT8 LINK_KEY[LINK_KEY_LEN]; /* Link Key */
+
+#define AMP_LINK_KEY_LEN 32
+typedef UINT8 AMP_LINK_KEY[AMP_LINK_KEY_LEN]; /* Dedicated AMP and GAMP Link Keys */
+
+#define BT_OCTET16_LEN 16
+typedef UINT8 BT_OCTET16[BT_OCTET16_LEN]; /* octet array: size 16 */
+
+#define PIN_CODE_LEN 16
+typedef UINT8 PIN_CODE[PIN_CODE_LEN]; /* Pin Code (upto 128 bits) MSB is 0 */
+typedef UINT8 *PIN_CODE_PTR; /* Pointer to Pin Code */
+
+#define DEV_CLASS_LEN 3
+typedef UINT8 DEV_CLASS[DEV_CLASS_LEN]; /* Device class */
+typedef UINT8 *DEV_CLASS_PTR; /* Pointer to Device class */
+
+#define EXT_INQ_RESP_LEN 3
+typedef UINT8 EXT_INQ_RESP[EXT_INQ_RESP_LEN];/* Extended Inquiry Response */
+typedef UINT8 *EXT_INQ_RESP_PTR; /* Pointer to Extended Inquiry Response */
+
+#define BD_NAME_LEN 248
+typedef UINT8 BD_NAME[BD_NAME_LEN]; /* Device name */
+typedef UINT8 *BD_NAME_PTR; /* Pointer to Device name */
+
+#define BD_FEATURES_LEN 8
+typedef UINT8 BD_FEATURES[BD_FEATURES_LEN]; /* LMP features supported by device */
+
+#define BT_EVENT_MASK_LEN 8
+typedef UINT8 BT_EVENT_MASK[BT_EVENT_MASK_LEN]; /* Event Mask */
+
+#define LAP_LEN 3
+typedef UINT8 LAP[LAP_LEN]; /* IAC as passed to Inquiry (LAP) */
+typedef UINT8 INQ_LAP[LAP_LEN]; /* IAC as passed to Inquiry (LAP) */
+
+#define RAND_NUM_LEN 16
+typedef UINT8 RAND_NUM[RAND_NUM_LEN];
+
+#define ACO_LEN 12
+typedef UINT8 ACO[ACO_LEN]; /* Authenticated ciphering offset */
+
+#define COF_LEN 12
+typedef UINT8 COF[COF_LEN]; /* ciphering offset number */
+
+typedef struct {
+ UINT8 qos_flags; /* TBD */
+ UINT8 service_type; /* see below */
+ UINT32 token_rate; /* bytes/second */
+ UINT32 token_bucket_size; /* bytes */
+ UINT32 peak_bandwidth; /* bytes/second */
+ UINT32 latency; /* microseconds */
+ UINT32 delay_variation; /* microseconds */
+} FLOW_SPEC;
+
+/* Values for service_type */
+#define NO_TRAFFIC 0
+#define BEST_EFFORT 1
+#define GUARANTEED 2
+
+/* Service class of the CoD */
+#define SERV_CLASS_NETWORKING (1 << 1)
+#define SERV_CLASS_RENDERING (1 << 2)
+#define SERV_CLASS_CAPTURING (1 << 3)
+#define SERV_CLASS_OBJECT_TRANSFER (1 << 4)
+#define SERV_CLASS_OBJECT_AUDIO (1 << 5)
+#define SERV_CLASS_OBJECT_TELEPHONY (1 << 6)
+#define SERV_CLASS_OBJECT_INFORMATION (1 << 7)
+
+/* Second byte */
+#define SERV_CLASS_LIMITED_DISC_MODE (0x20)
+
+/* Field size definitions. Note that byte lengths are rounded up. */
+#define ACCESS_CODE_BIT_LEN 72
+#define ACCESS_CODE_BYTE_LEN 9
+#define SHORTENED_ACCESS_CODE_BIT_LEN 68
+
+typedef UINT8 ACCESS_CODE[ACCESS_CODE_BYTE_LEN];
+
+#define SYNTH_TX 1 /* want synth code to TRANSMIT at this freq */
+#define SYNTH_RX 2 /* want synth code to RECEIVE at this freq */
+
+#define SYNC_REPS 1 /* repeats of sync word transmitted to start of burst */
+
+/* Bluetooth CLK27 */
+#define BT_CLK27 (2 << 26)
+
+/* Bluetooth CLK12 is 1.28 sec */
+#define BT_CLK12_TO_MS(x) ((x) * 1280)
+#define BT_MS_TO_CLK12(x) ((x) / 1280)
+#define BT_CLK12_TO_SLOTS(x) ((x) << 11)
+
+/* Bluetooth CLK is 0.625 msec */
+#define BT_CLK_TO_MS(x) (((x) * 5 + 3) / 8)
+#define BT_MS_TO_CLK(x) (((x) * 8 + 2) / 5)
+
+#define BT_CLK_TO_MICROSECS(x) (((x) * 5000 + 3) / 8)
+#define BT_MICROSECS_TO_CLK(x) (((x) * 8 + 2499) / 5000)
+
+/* Maximum UUID size - 16 bytes, and structure to hold any type of UUID. */
+#define MAX_UUID_SIZE 16
+typedef struct
+{
+#define LEN_UUID_16 2
+#define LEN_UUID_32 4
+#define LEN_UUID_128 16
+
+ UINT16 len;
+
+ union
+ {
+ UINT16 uuid16;
+ UINT32 uuid32;
+ UINT8 uuid128[MAX_UUID_SIZE];
+ } uu;
+
+} tBT_UUID;
+
+#define BT_EIR_FLAGS_TYPE 0x01
+#define BT_EIR_MORE_16BITS_UUID_TYPE 0x02
+#define BT_EIR_COMPLETE_16BITS_UUID_TYPE 0x03
+#define BT_EIR_MORE_32BITS_UUID_TYPE 0x04
+#define BT_EIR_COMPLETE_32BITS_UUID_TYPE 0x05
+#define BT_EIR_MORE_128BITS_UUID_TYPE 0x06
+#define BT_EIR_COMPLETE_128BITS_UUID_TYPE 0x07
+#define BT_EIR_SHORTENED_LOCAL_NAME_TYPE 0x08
+#define BT_EIR_COMPLETE_LOCAL_NAME_TYPE 0x09
+#define BT_EIR_TX_POWER_LEVEL_TYPE 0x0A
+#define BT_EIR_OOB_BD_ADDR_TYPE 0x0C
+#define BT_EIR_OOB_COD_TYPE 0x0D
+#define BT_EIR_OOB_SSP_HASH_C_TYPE 0x0E
+#define BT_EIR_OOB_SSP_RAND_R_TYPE 0x0F
+#define BT_EIR_MANUFACTURER_SPECIFIC_TYPE 0xFF
+
+#define BT_OOB_COD_SIZE 3
+#define BT_OOB_HASH_C_SIZE 16
+#define BT_OOB_RAND_R_SIZE 16
+
+/* Broadcom proprietary UUIDs and reserved PSMs
+**
+** The lowest 4 bytes byte of the UUID or GUID depends on the feature. Typically,
+** the value of those bytes will be the PSM or SCN, but it is up to the features.
+*/
+#define BRCM_PROPRIETARY_UUID_BASE 0xDA, 0x23, 0x41, 0x02, 0xA3, 0xBB, 0xC1, 0x71, 0xBA, 0x09, 0x6f, 0x21
+#define BRCM_PROPRIETARY_GUID_BASE 0xda23, 0x4102, 0xa3, 0xbb, 0xc1, 0x71, 0xba, 0x09, 0x6f, 0x21
+
+/* We will not allocate a PSM in the reserved range to 3rd party apps
+*/
+#define BRCM_RESERVED_PSM_START 0x5AE1
+#define BRCM_RESERVED_PSM_END 0x5AFF
+
+#define BRCM_UTILITY_SERVICE_PSM 0x5AE1
+#define BRCM_MATCHER_PSM 0x5AE3
+
+/* Connection statistics
+*/
+
+/* Structure to hold connection stats */
+#ifndef BT_CONN_STATS_DEFINED
+#define BT_CONN_STATS_DEFINED
+
+/* These bits are used in the bIsConnected field */
+#define BT_CONNECTED_USING_BREDR 1
+#define BT_CONNECTED_USING_AMP 2
+
+typedef struct
+{
+ UINT32 is_connected;
+ INT32 rssi;
+ UINT32 bytes_sent;
+ UINT32 bytes_rcvd;
+ UINT32 duration;
+} tBT_CONN_STATS;
+
+#endif
+
+
+/*****************************************************************************
+** Low Energy definitions
+**
+** Address types
+*/
+#define BLE_ADDR_PUBLIC 0x00
+#define BLE_ADDR_RANDOM 0x01
+#define BLE_ADDR_TYPE_MASK (BLE_ADDR_RANDOM | BLE_ADDR_PUBLIC)
+typedef UINT8 tBLE_ADDR_TYPE;
+
+#define BLE_ADDR_IS_STATIC(x) ((x[0] & 0xC0) == 0xC0)
+
+typedef struct
+{
+ tBLE_ADDR_TYPE type;
+ BD_ADDR bda;
+} tBLE_BD_ADDR;
+
+/* Device Types
+*/
+#define BT_DEVICE_TYPE_BREDR 0x01
+#define BT_DEVICE_TYPE_BLE 0x02
+#define BT_DEVICE_TYPE_DUMO 0x03
+typedef UINT8 tBT_DEVICE_TYPE;
+/*****************************************************************************/
+
+
+/* Define trace levels */
+#define BT_TRACE_LEVEL_NONE 0 /* No trace messages to be generated */
+#define BT_TRACE_LEVEL_ERROR 1 /* Error condition trace messages */
+#define BT_TRACE_LEVEL_WARNING 2 /* Warning condition trace messages */
+#define BT_TRACE_LEVEL_API 3 /* API traces */
+#define BT_TRACE_LEVEL_EVENT 4 /* Debug messages for events */
+#define BT_TRACE_LEVEL_DEBUG 5 /* Full debug messages */
+#define BT_TRACE_LEVEL_VERBOSE 6 /* Verbose debug messages */
+
+#define MAX_TRACE_LEVEL 6
+
+
+/* Define New Trace Type Definition */
+/* TRACE_CTRL_TYPE 0x^^000000*/
+#define TRACE_CTRL_MASK 0xff000000
+#define TRACE_GET_CTRL(x) ((((UINT32)(x)) & TRACE_CTRL_MASK) >> 24)
+
+#define TRACE_CTRL_GENERAL 0x00000000
+#define TRACE_CTRL_STR_RESOURCE 0x01000000
+#define TRACE_CTRL_SEQ_FLOW 0x02000000
+#define TRACE_CTRL_MAX_NUM 3
+
+/* LAYER SPECIFIC 0x00^^0000*/
+#define TRACE_LAYER_MASK 0x00ff0000
+#define TRACE_GET_LAYER(x) ((((UINT32)(x)) & TRACE_LAYER_MASK) >> 16)
+
+#define TRACE_LAYER_NONE 0x00000000
+#define TRACE_LAYER_USB 0x00010000
+#define TRACE_LAYER_SERIAL 0x00020000
+#define TRACE_LAYER_SOCKET 0x00030000
+#define TRACE_LAYER_RS232 0x00040000
+#define TRACE_LAYER_TRANS_MAX_NUM 5
+#define TRACE_LAYER_TRANS_ALL 0x007f0000
+#define TRACE_LAYER_LC 0x00050000
+#define TRACE_LAYER_LM 0x00060000
+#define TRACE_LAYER_HCI 0x00070000
+#define TRACE_LAYER_L2CAP 0x00080000
+#define TRACE_LAYER_RFCOMM 0x00090000
+#define TRACE_LAYER_SDP 0x000a0000
+#define TRACE_LAYER_TCS 0x000b0000
+#define TRACE_LAYER_OBEX 0x000c0000
+#define TRACE_LAYER_BTM 0x000d0000
+#define TRACE_LAYER_GAP 0x000e0000
+#define TRACE_LAYER_DUN 0x000f0000
+#define TRACE_LAYER_GOEP 0x00100000
+#define TRACE_LAYER_ICP 0x00110000
+#define TRACE_LAYER_HSP2 0x00120000
+#define TRACE_LAYER_SPP 0x00130000
+#define TRACE_LAYER_CTP 0x00140000
+#define TRACE_LAYER_BPP 0x00150000
+#define TRACE_LAYER_HCRP 0x00160000
+#define TRACE_LAYER_FTP 0x00170000
+#define TRACE_LAYER_OPP 0x00180000
+#define TRACE_LAYER_BTU 0x00190000
+#define TRACE_LAYER_GKI 0x001a0000
+#define TRACE_LAYER_BNEP 0x001b0000
+#define TRACE_LAYER_PAN 0x001c0000
+#define TRACE_LAYER_HFP 0x001d0000
+#define TRACE_LAYER_HID 0x001e0000
+#define TRACE_LAYER_BIP 0x001f0000
+#define TRACE_LAYER_AVP 0x00200000
+#define TRACE_LAYER_A2D 0x00210000
+#define TRACE_LAYER_SAP 0x00220000
+#define TRACE_LAYER_AMP 0x00230000
+#define TRACE_LAYER_MCA 0x00240000
+#define TRACE_LAYER_ATT 0x00250000
+#define TRACE_LAYER_SMP 0x00260000
+#define TRACE_LAYER_NFC 0x00270000
+#define TRACE_LAYER_NCI 0x00280000
+#define TRACE_LAYER_IDEP 0x00290000
+#define TRACE_LAYER_NDEP 0x002a0000
+#define TRACE_LAYER_LLCP 0x002b0000
+#define TRACE_LAYER_RW 0x002c0000
+#define TRACE_LAYER_CE 0x002d0000
+#define TRACE_LAYER_SNEP 0x002e0000
+#define TRACE_LAYER_NDEF 0x002f0000
+#define TRACE_LAYER_NFA 0x00300000
+
+#define TRACE_LAYER_MAX_NUM 0x0031
+
+
+/* TRACE_ORIGINATOR 0x0000^^00*/
+#define TRACE_ORG_MASK 0x0000ff00
+#define TRACE_GET_ORG(x) ((((UINT32)(x)) & TRACE_ORG_MASK) >> 8)
+
+#define TRACE_ORG_STACK 0x00000000
+#define TRACE_ORG_HCI_TRANS 0x00000100
+#define TRACE_ORG_PROTO_DISP 0x00000200
+#define TRACE_ORG_RPC 0x00000300
+#define TRACE_ORG_GKI 0x00000400
+#define TRACE_ORG_APPL 0x00000500
+#define TRACE_ORG_SCR_WRAPPER 0x00000600
+#define TRACE_ORG_SCR_ENGINE 0x00000700
+#define TRACE_ORG_USER_SCR 0x00000800
+#define TRACE_ORG_TESTER 0x00000900
+#define TRACE_ORG_MAX_NUM 10 /* 32-bit mask; must be < 32 */
+#define TRACE_LITE_ORG_MAX_NUM 6
+#define TRACE_ORG_ALL 0x03ff
+#define TRACE_ORG_RPC_TRANS 0x04
+
+#define TRACE_ORG_REG 0x00000909
+#define TRACE_ORG_REG_SUCCESS 0x0000090a
+
+/* TRACE_TYPE 0x000000^^*/
+#define TRACE_TYPE_MASK 0x000000ff
+#define TRACE_GET_TYPE(x) (((UINT32)(x)) & TRACE_TYPE_MASK)
+
+#define TRACE_TYPE_ERROR 0x00000000
+#define TRACE_TYPE_WARNING 0x00000001
+#define TRACE_TYPE_API 0x00000002
+#define TRACE_TYPE_EVENT 0x00000003
+#define TRACE_TYPE_DEBUG 0x00000004
+#define TRACE_TYPE_STACK_ONLY_MAX TRACE_TYPE_DEBUG
+#define TRACE_TYPE_TX 0x00000005
+#define TRACE_TYPE_RX 0x00000006
+#define TRACE_TYPE_DEBUG_ASSERT 0x00000007
+#define TRACE_TYPE_GENERIC 0x00000008
+#define TRACE_TYPE_REG 0x00000009
+#define TRACE_TYPE_REG_SUCCESS 0x0000000a
+#define TRACE_TYPE_CMD_TX 0x0000000b
+#define TRACE_TYPE_EVT_TX 0x0000000c
+#define TRACE_TYPE_ACL_TX 0x0000000d
+#define TRACE_TYPE_CMD_RX 0x0000000e
+#define TRACE_TYPE_EVT_RX 0x0000000f
+#define TRACE_TYPE_ACL_RX 0x00000010
+#define TRACE_TYPE_TARGET_TRACE 0x00000011
+#define TRACE_TYPE_SCO_TX 0x00000012
+#define TRACE_TYPE_SCO_RX 0x00000013
+
+
+#define TRACE_TYPE_MAX_NUM 20
+#define TRACE_TYPE_ALL 0xffff
+
+/* Define color for script type */
+#define SCR_COLOR_DEFAULT 0
+#define SCR_COLOR_TYPE_COMMENT 1
+#define SCR_COLOR_TYPE_COMMAND 2
+#define SCR_COLOR_TYPE_EVENT 3
+#define SCR_COLOR_TYPE_SELECT 4
+
+/* Define protocol trace flag values */
+#define SCR_PROTO_TRACE_HCI_SUMMARY 0x00000001
+#define SCR_PROTO_TRACE_HCI_DATA 0x00000002
+#define SCR_PROTO_TRACE_L2CAP 0x00000004
+#define SCR_PROTO_TRACE_RFCOMM 0x00000008
+#define SCR_PROTO_TRACE_SDP 0x00000010
+#define SCR_PROTO_TRACE_TCS 0x00000020
+#define SCR_PROTO_TRACE_OBEX 0x00000040
+#define SCR_PROTO_TRACE_OAPP 0x00000080 /* OBEX Application Profile */
+#define SCR_PROTO_TRACE_AMP 0x00000100
+#define SCR_PROTO_TRACE_BNEP 0x00000200
+#define SCR_PROTO_TRACE_AVP 0x00000400
+#define SCR_PROTO_TRACE_MCA 0x00000800
+#define SCR_PROTO_TRACE_ATT 0x00001000
+#define SCR_PROTO_TRACE_SMP 0x00002000
+#define SCR_PROTO_TRACE_NCI 0x00004000
+#define SCR_PROTO_TRACE_DEP 0x00008000
+#define SCR_PROTO_TRACE_LLCP 0x00010000
+#define SCR_PROTO_TRACE_NDEF 0x00020000
+#define SCR_PROTO_TRACE_TAGS 0x00040000
+#define SCR_PROTO_TRACE_ALL 0x0007ffff
+#define SCR_PROTO_TRACE_HCI_LOGGING_VSE 0x0800 /* Brcm vs event for logmsg and protocol traces */
+
+#define MAX_SCRIPT_TYPE 5
+
+#define TCS_PSM_INTERCOM 5
+#define TCS_PSM_CORDLESS 7
+#define BT_PSM_BNEP 0x000F
+/* Define PSMs HID uses */
+#define HID_PSM_CONTROL 0x0011
+#define HID_PSM_INTERRUPT 0x0013
+
+/* Define a function for logging */
+typedef void (BT_LOG_FUNC) (int trace_type, const char *fmt_str, ...);
+
+#endif
+
diff --git a/stack/include/btm_api.h b/stack/include/btm_api.h
new file mode 100644
index 0000000..20ae90c
--- /dev/null
+++ b/stack/include/btm_api.h
@@ -0,0 +1,4540 @@
+/*****************************************************************************
+**
+** Name: btm_api.h
+**
+** Description: This file contains the Bluetooth Manager (BTM) API function
+** external definitions.
+**
+** The BTM consists of several management entities:
+** 1. Device Control - controls the local device
+** 2. Device Discovery - manages inquiries, discover database
+** 3. ACL Channels - manages ACL connections
+** 4. SCO Channels - manages SCO connections
+** 5. Security - manages all security functionality
+** 6. Power Management - manages park, sniff, hold, etc. (optional)
+**
+** Copyright (c) 1999-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+#ifndef BTM_API_H
+#define BTM_API_H
+
+#include "bt_target.h"
+#include "sdp_api.h"
+#include "hcidefs.h"
+
+#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE
+#include "smp_api.h"
+#endif
+/*****************************************************************************
+** DEVICE CONTROL and COMMON
+*****************************************************************************/
+/*****************************
+** Device Control Constants
+******************************/
+/* Maximum number of bytes allowed for vendor specific command parameters */
+#define BTM_MAX_VENDOR_SPECIFIC_LEN HCI_COMMAND_SIZE
+
+/* BTM application return status codes */
+enum
+{
+ BTM_SUCCESS = 0, /* 0 Command succeeded */
+ BTM_CMD_STARTED, /* 1 Command started OK. */
+ BTM_BUSY, /* 2 Device busy with another command */
+ BTM_NO_RESOURCES, /* 3 No resources to issue command */
+ BTM_MODE_UNSUPPORTED, /* 4 Request for 1 or more unsupported modes */
+ BTM_ILLEGAL_VALUE, /* 5 Illegal parameter value */
+ BTM_WRONG_MODE, /* 6 Device in wrong mode for request */
+ BTM_UNKNOWN_ADDR, /* 7 Unknown remote BD address */
+ BTM_DEVICE_TIMEOUT, /* 8 Device timeout */
+ BTM_BAD_VALUE_RET, /* 9 A bad value was received from HCI */
+ BTM_ERR_PROCESSING, /* 10 Generic error */
+ BTM_NOT_AUTHORIZED, /* 11 Authorization failed */
+ BTM_DEV_RESET, /* 12 Device has been reset */
+ BTM_CMD_STORED, /* 13 request is stored in control block */
+ BTM_ILLEGAL_ACTION, /* 14 state machine gets illegal command */
+ BTM_DELAY_CHECK, /* 15 delay the check on encryption */
+ BTM_SCO_BAD_LENGTH, /* 16 Bad SCO over HCI data length */
+ BTM_SUCCESS_NO_SECURITY, /* 17 security passed, no security set */
+ BTM_FAILED_ON_SECURITY , /* 18 security failed */
+ BTM_REPEATED_ATTEMPTS /* 19 repeated attempts for LE security requests */
+};
+typedef UINT8 tBTM_STATUS;
+
+/*************************
+** Device Control Types
+**************************/
+#define BTM_DEVICE_ROLE_BR 0x01
+#define BTM_DEVICE_ROLE_DUAL 0x02
+#define BTM_MAX_DEVICE_ROLE BTM_DEVICE_ROLE_DUAL
+typedef UINT8 tBTM_DEVICE_ROLE;
+
+/* Device name of peer (may be truncated to save space in BTM database) */
+typedef UINT8 tBTM_BD_NAME[BTM_MAX_REM_BD_NAME_LEN + 1];
+
+/* Structure returned with local version information */
+typedef struct
+{
+ UINT8 hci_version;
+ UINT16 hci_revision;
+ UINT8 lmp_version;
+ UINT16 manufacturer;
+ UINT16 lmp_subversion;
+} tBTM_VERSION_INFO;
+
+/* Structure returned with Vendor Specific Command complete callback */
+typedef struct
+{
+ UINT16 opcode;
+ UINT16 param_len;
+ UINT8 *p_param_buf;
+} tBTM_VSC_CMPL;
+
+#define BTM_VSC_CMPL_DATA_SIZE (BTM_MAX_VENDOR_SPECIFIC_LEN + sizeof(tBTM_VSC_CMPL))
+/**************************************************
+** Device Control and General Callback Functions
+***************************************************/
+/* Callback function for when device status changes. Appl must poll for
+** what the new state is (BTM_IsDeviceUp). The event occurs whenever the stack
+** has detected that the controller status has changed. This asynchronous event
+** is enabled/disabled by calling BTM_RegisterForDeviceStatusNotif().
+*/
+enum
+{
+ BTM_DEV_STATUS_UP,
+ BTM_DEV_STATUS_DOWN,
+ BTM_DEV_STATUS_CMD_TOUT
+};
+
+typedef UINT8 tBTM_DEV_STATUS;
+
+
+typedef void (tBTM_DEV_STATUS_CB) (tBTM_DEV_STATUS status);
+
+
+/* Callback function for when a vendor specific event occurs. The length and
+** array of returned parameter bytes are included. This asynchronous event
+** is enabled/disabled by calling BTM_RegisterForVSEvents().
+*/
+typedef void (tBTM_VS_EVT_CB) (UINT8 len, UINT8 *p);
+
+
+/* General callback function for notifying an application that a synchronous
+** BTM function is complete. The pointer contains the address of any returned data.
+*/
+typedef void (tBTM_CMPL_CB) (void *p1);
+
+/* VSC callback function for notifying an application that a synchronous
+** BTM function is complete. The pointer contains the address of any returned data.
+*/
+typedef void (tBTM_VSC_CMPL_CB) (tBTM_VSC_CMPL *p1);
+
+/* Callback for apps to check connection and inquiry filters.
+** Parameters are the BD Address of remote and the Dev Class of remote.
+** If the app returns none zero, the connection or inquiry result will be dropped.
+*/
+typedef UINT8 (tBTM_FILTER_CB) (BD_ADDR bd_addr, DEV_CLASS dc);
+
+/*****************************************************************************
+** DEVICE DISCOVERY - Inquiry, Remote Name, Discovery, Class of Device
+*****************************************************************************/
+/*******************************
+** Device Discovery Constants
+********************************/
+/* Discoverable modes */
+#define BTM_NON_DISCOVERABLE 0
+#define BTM_LIMITED_DISCOVERABLE 1
+#define BTM_GENERAL_DISCOVERABLE 2
+#define BTM_DISCOVERABLE_MASK (BTM_LIMITED_DISCOVERABLE|BTM_GENERAL_DISCOVERABLE)
+#define BTM_MAX_DISCOVERABLE BTM_GENERAL_DISCOVERABLE
+/* high byte for BLE Discoverable modes */
+#define BTM_BLE_NON_DISCOVERABLE 0x0000
+#define BTM_BLE_LIMITED_DISCOVERABLE 0x0100
+#define BTM_BLE_GENERAL_DISCOVERABLE 0x0200
+#define BTM_BLE_MAX_DISCOVERABLE BTM_BLE_GENERAL_DISCOVERABLE
+#define BTM_BLE_DISCOVERABLE_MASK (BTM_BLE_NON_DISCOVERABLE|BTM_BLE_LIMITED_DISCOVERABLE|BTM_BLE_GENERAL_DISCOVERABLE)
+
+/* Connectable modes */
+#define BTM_NON_CONNECTABLE 0
+#define BTM_CONNECTABLE 1
+#define BTM_CONNECTABLE_MASK (BTM_NON_CONNECTABLE | BTM_CONNECTABLE)
+/* high byte for BLE Connectable modes */
+#define BTM_BLE_NON_CONNECTABLE 0x0000
+#define BTM_BLE_CONNECTABLE 0x0100
+#define BTM_BLE_MAX_CONNECTABLE BTM_BLE_CONNECTABLE
+#define BTM_BLE_CONNECTABLE_MASK (BTM_BLE_NON_CONNECTABLE | BTM_BLE_CONNECTABLE)
+
+/* Inquiry modes
+ * Note: These modes are associated with the inquiry active values (BTM_*ACTIVE) */
+#define BTM_GENERAL_INQUIRY 0
+#define BTM_LIMITED_INQUIRY 1
+#define BTM_BR_INQUIRY_MASK 0x0f
+/* high byte of inquiry mode for BLE inquiry mode */
+#define BTM_BLE_INQUIRY_NONE 0x00
+#define BTM_BLE_GENERAL_INQUIRY 0x10
+#define BTM_BLE_LIMITED_INQUIRY 0x20
+#define BTM_BLE_INQUIRY_MASK (BTM_BLE_GENERAL_INQUIRY|BTM_BLE_LIMITED_INQUIRY)
+
+/* BTM_IsInquiryActive return values (Bit Mask)
+ * Note: These bit masks are associated with the inquiry modes (BTM_*_INQUIRY) */
+#define BTM_INQUIRY_INACTIVE 0x0 /* no inquiry in progress */
+#define BTM_GENERAL_INQUIRY_ACTIVE 0x1 /* a general inquiry is in progress */
+#define BTM_LIMITED_INQUIRY_ACTIVE 0x2 /* a limited inquiry is in progress */
+#define BTM_PERIODIC_INQUIRY_ACTIVE 0x8 /* a periodic inquiry is active */
+#define BTM_SSP_INQUIRY_ACTIVE 0x4 /* SSP is active, so inquiry is disallowed (work around for FW bug) */
+
+/* Define scan types */
+#define BTM_SCAN_TYPE_STANDARD 0
+#define BTM_SCAN_TYPE_INTERLACED 1 /* 1.2 devices only */
+
+/* Define inquiry results mode */
+#define BTM_INQ_RESULT_STANDARD 0
+#define BTM_INQ_RESULT_WITH_RSSI 1
+#define BTM_INQ_RESULT_EXTENDED 2
+
+#define BTM_INQ_RES_IGNORE_RSSI 0x7f /* RSSI value not supplied (ignore it) */
+
+/* Inquiry Filter Condition types (see tBTM_INQ_PARMS) */
+#define BTM_CLR_INQUIRY_FILTER 0 /* Inquiry Filtering is turned off */
+#define BTM_FILTER_COND_DEVICE_CLASS HCI_FILTER_COND_DEVICE_CLASS /* Filter on device class */
+#define BTM_FILTER_COND_BD_ADDR HCI_FILTER_COND_BD_ADDR /* Filter on device addr */
+
+/* State of the remote name retrieval during inquiry operations.
+** Used in the tBTM_INQ_INFO structure, and returned in the
+** BTM_InqDbRead, BTM_InqDbFirst, and BTM_InqDbNext functions.
+** The name field is valid when the state returned is
+** BTM_INQ_RMT_NAME_DONE */
+#define BTM_INQ_RMT_NAME_EMPTY 0
+#define BTM_INQ_RMT_NAME_PENDING 1
+#define BTM_INQ_RMT_NAME_DONE 2
+#define BTM_INQ_RMT_NAME_FAILED 3
+
+/*********************************
+ *** Class of Device constants ***
+ *********************************/
+#define BTM_FORMAT_TYPE_1 0x00
+
+/****************************
+** minor device class field
+*****************************/
+
+/* 0x00 is used as unclassified for all minor device classes */
+#define BTM_COD_MINOR_UNCLASSIFIED 0x00
+
+/* minor device class field for Computer Major Class */
+/* #define BTM_COD_MINOR_UNCLASSIFIED 0x00 */
+#define BTM_COD_MINOR_DESKTOP_WORKSTATION 0x04
+#define BTM_COD_MINOR_SERVER_COMPUTER 0x08
+#define BTM_COD_MINOR_LAPTOP 0x0C
+#define BTM_COD_MINOR_HANDHELD_PC_PDA 0x10 /* clam shell */
+#define BTM_COD_MINOR_PALM_SIZE_PC_PDA 0x14
+#define BTM_COD_MINOR_WEARABLE_COMPUTER 0x18 /* watch sized */
+
+/* minor device class field for Phone Major Class */
+/* #define BTM_COD_MINOR_UNCLASSIFIED 0x00 */
+#define BTM_COD_MINOR_CELLULAR 0x04
+#define BTM_COD_MINOR_CORDLESS 0x08
+#define BTM_COD_MINOR_SMART_PHONE 0x0C
+#define BTM_COD_MINOR_WIRED_MDM_V_GTWY 0x10 /* wired modem or voice gatway */
+#define BTM_COD_MINOR_ISDN_ACCESS 0x14
+
+/* minor device class field for LAN Access Point Major Class */
+/* Load Factor Field bit 5-7 */
+#define BTM_COD_MINOR_FULLY_AVAILABLE 0x00
+#define BTM_COD_MINOR_1_17_UTILIZED 0x20
+#define BTM_COD_MINOR_17_33_UTILIZED 0x40
+#define BTM_COD_MINOR_33_50_UTILIZED 0x60
+#define BTM_COD_MINOR_50_67_UTILIZED 0x80
+#define BTM_COD_MINOR_67_83_UTILIZED 0xA0
+#define BTM_COD_MINOR_83_99_UTILIZED 0xC0
+#define BTM_COD_MINOR_NO_SERVICE_AVAILABLE 0xE0
+/* sub-Field bit 2-4 */
+/* #define BTM_COD_MINOR_UNCLASSIFIED 0x00 */
+
+/* minor device class field for Audio/Video Major Class */
+/* #define BTM_COD_MINOR_UNCLASSIFIED 0x00 */
+#define BTM_COD_MINOR_CONFM_HEADSET 0x04
+#define BTM_COD_MINOR_CONFM_HANDSFREE 0x08
+#define BTM_COD_MINOR_MICROPHONE 0x10
+#define BTM_COD_MINOR_LOUDSPEAKER 0x14
+#define BTM_COD_MINOR_HEADPHONES 0x18
+#define BTM_COD_MINOR_PORTABLE_AUDIO 0x1C
+#define BTM_COD_MINOR_CAR_AUDIO 0x20
+#define BTM_COD_MINOR_SET_TOP_BOX 0x24
+#define BTM_COD_MINOR_HIFI_AUDIO 0x28
+#define BTM_COD_MINOR_VCR 0x2C
+#define BTM_COD_MINOR_VIDEO_CAMERA 0x30
+#define BTM_COD_MINOR_CAMCORDER 0x34
+#define BTM_COD_MINOR_VIDEO_MONITOR 0x38
+#define BTM_COD_MINOR_VIDDISP_LDSPKR 0x3C
+#define BTM_COD_MINOR_VIDEO_CONFERENCING 0x40
+#define BTM_COD_MINOR_GAMING_TOY 0x48
+
+/* minor device class field for Peripheral Major Class */
+/* Bits 6-7 independently specify mouse, keyboard, or combo mouse/keyboard */
+#define BTM_COD_MINOR_KEYBOARD 0x40
+#define BTM_COD_MINOR_POINTING 0x80
+#define BTM_COD_MINOR_COMBO 0xC0
+/* Bits 2-5 OR'd with selection from bits 6-7 */
+/* #define BTM_COD_MINOR_UNCLASSIFIED 0x00 */
+#define BTM_COD_MINOR_JOYSTICK 0x04
+#define BTM_COD_MINOR_GAMEPAD 0x08
+#define BTM_COD_MINOR_REMOTE_CONTROL 0x0C
+#define BTM_COD_MINOR_SENSING_DEVICE 0x10
+#define BTM_COD_MINOR_DIGITIZING_TABLET 0x14
+#define BTM_COD_MINOR_CARD_READER 0x18 /* e.g. SIM card reader */
+#define BTM_COD_MINOR_DIGITAL_PAN 0x1C
+#define BTM_COD_MINOR_HAND_SCANNER 0x20
+#define BTM_COD_MINOR_HAND_GESTURAL_INPUT 0x24
+
+/* minor device class field for Imaging Major Class */
+/* Bits 5-7 independently specify display, camera, scanner, or printer */
+#define BTM_COD_MINOR_DISPLAY 0x10
+#define BTM_COD_MINOR_CAMERA 0x20
+#define BTM_COD_MINOR_SCANNER 0x40
+#define BTM_COD_MINOR_PRINTER 0x80
+/* Bits 2-3 Reserved */
+/* #define BTM_COD_MINOR_UNCLASSIFIED 0x00 */
+
+/* minor device class field for Wearable Major Class */
+/* Bits 2-7 meaningful */
+#define BTM_COD_MINOR_WRIST_WATCH 0x04
+#define BTM_COD_MINOR_PAGER 0x08
+#define BTM_COD_MINOR_JACKET 0x0C
+#define BTM_COD_MINOR_HELMET 0x10
+#define BTM_COD_MINOR_GLASSES 0x14
+
+/* minor device class field for Toy Major Class */
+/* Bits 2-7 meaningful */
+#define BTM_COD_MINOR_ROBOT 0x04
+#define BTM_COD_MINOR_VEHICLE 0x08
+#define BTM_COD_MINOR_DOLL_ACTION_FIGURE 0x0C
+#define BTM_COD_MINOR_CONTROLLER 0x10
+#define BTM_COD_MINOR_GAME 0x14
+
+/* minor device class field for Health Major Class */
+/* Bits 2-7 meaningful */
+#define BTM_COD_MINOR_BLOOD_MONITOR 0x04
+#define BTM_COD_MINOR_THERMOMETER 0x08
+#define BTM_COD_MINOR_WEIGHING_SCALE 0x0C
+#define BTM_COD_MINOR_GLUCOSE_METER 0x10
+#define BTM_COD_MINOR_PULSE_OXIMETER 0x14
+#define BTM_COD_MINOR_HEART_PULSE_MONITOR 0x18
+#define BTM_COD_MINOR_HEALTH_DATA_DISPLAY 0x1C
+#define BTM_COD_MINOR_STEP_COUNTER 0x20
+#define BTM_COD_MINOR_BODY_COM_ANALYZER 0x24
+#define BTM_COD_MINOR_PEAK_FLOW_MONITOR 0x28
+#define BTM_COD_MINOR_MEDICATION_MONITOR 0x2C
+#define BTM_COD_MINOR_KNEE_PROSTHESIS 0x30
+#define BTM_COD_MINOR_ANKLE_PROSTHESIS 0x34
+
+
+/***************************
+** major device class field
+****************************/
+#define BTM_COD_MAJOR_MISCELLANEOUS 0x00
+#define BTM_COD_MAJOR_COMPUTER 0x01
+#define BTM_COD_MAJOR_PHONE 0x02
+#define BTM_COD_MAJOR_LAN_ACCESS_PT 0x03
+#define BTM_COD_MAJOR_AUDIO 0x04
+#define BTM_COD_MAJOR_PERIPHERAL 0x05
+#define BTM_COD_MAJOR_IMAGING 0x06
+#define BTM_COD_MAJOR_WEARABLE 0x07
+#define BTM_COD_MAJOR_TOY 0x08
+#define BTM_COD_MAJOR_HEALTH 0x09
+#define BTM_COD_MAJOR_UNCLASSIFIED 0x1F
+
+/***************************
+** service class fields
+****************************/
+#define BTM_COD_SERVICE_LMTD_DISCOVER 0x0020
+#define BTM_COD_SERVICE_POSITIONING 0x0100
+#define BTM_COD_SERVICE_NETWORKING 0x0200
+#define BTM_COD_SERVICE_RENDERING 0x0400
+#define BTM_COD_SERVICE_CAPTURING 0x0800
+#define BTM_COD_SERVICE_OBJ_TRANSFER 0x1000
+#define BTM_COD_SERVICE_AUDIO 0x2000
+#define BTM_COD_SERVICE_TELEPHONY 0x4000
+#define BTM_COD_SERVICE_INFORMATION 0x8000
+
+/* class of device field macros */
+#define BTM_COD_FORMAT_TYPE(u8, pd) {u8 = pd[2]&0x03;}
+#define BTM_COD_MINOR_CLASS(u8, pd) {u8 = pd[2]&0xFC;}
+#define BTM_COD_MAJOR_CLASS(u8, pd) {u8 = pd[1]&0x1F;}
+#define BTM_COD_SERVICE_CLASS(u16, pd) {u16 = pd[0]; u16<<=8; u16 += pd[1]&0xE0;}
+
+/* to set the fields (assumes that format type is always 0) */
+#define FIELDS_TO_COD(pd, mn, mj, sv) {pd[2] = mn; pd[1] = \
+ mj+ ((sv)&BTM_COD_SERVICE_CLASS_LO_B); \
+ pd[0] = (sv) >> 8;}
+
+/* the COD masks */
+#define BTM_COD_FORMAT_TYPE_MASK 0x03
+#define BTM_COD_MINOR_CLASS_MASK 0xFC
+#define BTM_COD_MAJOR_CLASS_MASK 0x1F
+#define BTM_COD_SERVICE_CLASS_LO_B 0x00E0
+#define BTM_COD_SERVICE_CLASS_MASK 0xFFE0
+
+
+/* BTM service definitions
+** Used for storing EIR data to bit mask
+*/
+#ifndef BTM_EIR_UUID_LKUP_TBL
+enum
+{
+ BTM_EIR_UUID_SERVCLASS_SERVICE_DISCOVERY_SERVER,
+/* BTM_EIR_UUID_SERVCLASS_BROWSE_GROUP_DESCRIPTOR, */
+/* BTM_EIR_UUID_SERVCLASS_PUBLIC_BROWSE_GROUP, */
+ BTM_EIR_UUID_SERVCLASS_SERIAL_PORT,
+ BTM_EIR_UUID_SERVCLASS_LAN_ACCESS_USING_PPP,
+ BTM_EIR_UUID_SERVCLASS_DIALUP_NETWORKING,
+ BTM_EIR_UUID_SERVCLASS_IRMC_SYNC,
+ BTM_EIR_UUID_SERVCLASS_OBEX_OBJECT_PUSH,
+ BTM_EIR_UUID_SERVCLASS_OBEX_FILE_TRANSFER,
+ BTM_EIR_UUID_SERVCLASS_IRMC_SYNC_COMMAND,
+ BTM_EIR_UUID_SERVCLASS_HEADSET,
+ BTM_EIR_UUID_SERVCLASS_CORDLESS_TELEPHONY,
+ BTM_EIR_UUID_SERVCLASS_AUDIO_SOURCE,
+ BTM_EIR_UUID_SERVCLASS_AUDIO_SINK,
+ BTM_EIR_UUID_SERVCLASS_AV_REM_CTRL_TARGET,
+/* BTM_EIR_UUID_SERVCLASS_ADV_AUDIO_DISTRIBUTION, */
+ BTM_EIR_UUID_SERVCLASS_AV_REMOTE_CONTROL,
+/* BTM_EIR_UUID_SERVCLASS_VIDEO_CONFERENCING, */
+ BTM_EIR_UUID_SERVCLASS_INTERCOM,
+ BTM_EIR_UUID_SERVCLASS_FAX,
+ BTM_EIR_UUID_SERVCLASS_HEADSET_AUDIO_GATEWAY,
+/* BTM_EIR_UUID_SERVCLASS_WAP, */
+/* BTM_EIR_UUID_SERVCLASS_WAP_CLIENT, */
+ BTM_EIR_UUID_SERVCLASS_PANU,
+ BTM_EIR_UUID_SERVCLASS_NAP,
+ BTM_EIR_UUID_SERVCLASS_GN,
+ BTM_EIR_UUID_SERVCLASS_DIRECT_PRINTING,
+/* BTM_EIR_UUID_SERVCLASS_REFERENCE_PRINTING, */
+ BTM_EIR_UUID_SERVCLASS_IMAGING,
+ BTM_EIR_UUID_SERVCLASS_IMAGING_RESPONDER,
+ BTM_EIR_UUID_SERVCLASS_IMAGING_AUTO_ARCHIVE,
+ BTM_EIR_UUID_SERVCLASS_IMAGING_REF_OBJECTS,
+ BTM_EIR_UUID_SERVCLASS_HF_HANDSFREE,
+ BTM_EIR_UUID_SERVCLASS_AG_HANDSFREE,
+ BTM_EIR_UUID_SERVCLASS_DIR_PRT_REF_OBJ_SERVICE,
+/* BTM_EIR_UUID_SERVCLASS_REFLECTED_UI, */
+ BTM_EIR_UUID_SERVCLASS_BASIC_PRINTING,
+ BTM_EIR_UUID_SERVCLASS_PRINTING_STATUS,
+ BTM_EIR_UUID_SERVCLASS_HUMAN_INTERFACE,
+ BTM_EIR_UUID_SERVCLASS_CABLE_REPLACEMENT,
+ BTM_EIR_UUID_SERVCLASS_HCRP_PRINT,
+ BTM_EIR_UUID_SERVCLASS_HCRP_SCAN,
+/* BTM_EIR_UUID_SERVCLASS_COMMON_ISDN_ACCESS, */
+/* BTM_EIR_UUID_SERVCLASS_VIDEO_CONFERENCING_GW, */
+/* BTM_EIR_UUID_SERVCLASS_UDI_MT, */
+/* BTM_EIR_UUID_SERVCLASS_UDI_TA, */
+/* BTM_EIR_UUID_SERVCLASS_VCP, */
+ BTM_EIR_UUID_SERVCLASS_SAP,
+ BTM_EIR_UUID_SERVCLASS_PBAP_PCE,
+ BTM_EIR_UUID_SERVCLASS_PBAP_PSE,
+/* BTM_EIR_UUID_SERVCLASS_TE_PHONE_ACCESS, */
+/* BTM_EIR_UUID_SERVCLASS_ME_PHONE_ACCESS, */
+ BTM_EIR_UUID_SERVCLASS_PHONE_ACCESS,
+ BTM_EIR_UUID_SERVCLASS_HEADSET_HS,
+ BTM_EIR_UUID_SERVCLASS_PNP_INFORMATION,
+/* BTM_EIR_UUID_SERVCLASS_GENERIC_NETWORKING, */
+/* BTM_EIR_UUID_SERVCLASS_GENERIC_FILETRANSFER, */
+/* BTM_EIR_UUID_SERVCLASS_GENERIC_AUDIO, */
+/* BTM_EIR_UUID_SERVCLASS_GENERIC_TELEPHONY, */
+/* BTM_EIR_UUID_SERVCLASS_UPNP_SERVICE, */
+/* BTM_EIR_UUID_SERVCLASS_UPNP_IP_SERVICE, */
+/* BTM_EIR_UUID_SERVCLASS_ESDP_UPNP_IP_PAN, */
+/* BTM_EIR_UUID_SERVCLASS_ESDP_UPNP_IP_LAP, */
+/* BTM_EIR_UUID_SERVCLASS_ESDP_UPNP_IP_L2CAP, */
+ BTM_EIR_UUID_SERVCLASS_VIDEO_SOURCE,
+ BTM_EIR_UUID_SERVCLASS_VIDEO_SINK,
+/* BTM_EIR_UUID_SERVCLASS_VIDEO_DISTRIBUTION */
+/* BTM_EIR_UUID_SERVCLASS_HDP_PROFILE */
+ BTM_EIR_UUID_SERVCLASS_MESSAGE_ACCESS,
+ BTM_EIR_UUID_SERVCLASS_MESSAGE_NOTIFICATION,
+ BTM_EIR_UUID_SERVCLASS_HDP_SOURCE,
+ BTM_EIR_UUID_SERVCLASS_HDP_SINK,
+ BTM_EIR_MAX_SERVICES
+};
+#endif /* BTM_EIR_UUID_LKUP_TBL */
+
+/* search result in EIR of inquiry database */
+#define BTM_EIR_FOUND 0
+#define BTM_EIR_NOT_FOUND 1
+#define BTM_EIR_UNKNOWN 2
+
+typedef UINT8 tBTM_EIR_SEARCH_RESULT;
+
+#define BTM_EIR_FLAGS_TYPE HCI_EIR_FLAGS_TYPE /* 0x01 */
+#define BTM_EIR_MORE_16BITS_UUID_TYPE HCI_EIR_MORE_16BITS_UUID_TYPE /* 0x02 */
+#define BTM_EIR_COMPLETE_16BITS_UUID_TYPE HCI_EIR_COMPLETE_16BITS_UUID_TYPE /* 0x03 */
+#define BTM_EIR_MORE_32BITS_UUID_TYPE HCI_EIR_MORE_32BITS_UUID_TYPE /* 0x04 */
+#define BTM_EIR_COMPLETE_32BITS_UUID_TYPE HCI_EIR_COMPLETE_32BITS_UUID_TYPE /* 0x05 */
+#define BTM_EIR_MORE_128BITS_UUID_TYPE HCI_EIR_MORE_128BITS_UUID_TYPE /* 0x06 */
+#define BTM_EIR_COMPLETE_128BITS_UUID_TYPE HCI_EIR_COMPLETE_128BITS_UUID_TYPE /* 0x07 */
+#define BTM_EIR_SHORTENED_LOCAL_NAME_TYPE HCI_EIR_SHORTENED_LOCAL_NAME_TYPE /* 0x08 */
+#define BTM_EIR_COMPLETE_LOCAL_NAME_TYPE HCI_EIR_COMPLETE_LOCAL_NAME_TYPE /* 0x09 */
+#define BTM_EIR_TX_POWER_LEVEL_TYPE HCI_EIR_TX_POWER_LEVEL_TYPE /* 0x0A */
+#define BTM_EIR_MANUFACTURER_SPECIFIC_TYPE HCI_EIR_MANUFACTURER_SPECIFIC_TYPE /* 0xFF */
+
+/* the following EIR tags are defined to OOB, not regular EIR data */
+#define BTM_EIR_OOB_BD_ADDR_TYPE HCI_EIR_OOB_BD_ADDR_TYPE /* 6 bytes */
+#define BTM_EIR_OOB_COD_TYPE HCI_EIR_OOB_COD_TYPE /* 3 bytes */
+#define BTM_EIR_OOB_SSP_HASH_C_TYPE HCI_EIR_OOB_SSP_HASH_C_TYPE /* 16 bytes */
+#define BTM_EIR_OOB_SSP_RAND_R_TYPE HCI_EIR_OOB_SSP_RAND_R_TYPE /* 16 bytes */
+
+#define BTM_OOB_MANDATORY_SIZE 8 /* include 2 bytes length & 6 bytes bd_addr */
+#define BTM_OOB_DATA_LEN_SIZE 2
+#define BTM_OOB_BD_ADDR_SIZE 6
+#define BTM_OOB_COD_SIZE BT_OOB_COD_SIZE
+#define BTM_OOB_HASH_C_SIZE BT_OOB_HASH_C_SIZE
+#define BTM_OOB_RAND_R_SIZE BT_OOB_RAND_R_SIZE
+
+
+#if BLE_INCLUDED == TRUE
+#define BTM_BLE_SEC_NONE 0
+#define BTM_BLE_SEC_ENCRYPT 1 /* encrypt the link using current key */
+#define BTM_BLE_SEC_ENCRYPT_NO_MITM 2
+#define BTM_BLE_SEC_ENCRYPT_MITM 3
+typedef UINT8 tBTM_BLE_SEC_ACT;
+#endif
+/************************************************************************************************
+** BTM Services MACROS handle array of UINT32 bits for more than 32 services
+*************************************************************************************************/
+/* Determine the number of UINT32's necessary for services */
+#define BTM_EIR_ARRAY_BITS 32 /* Number of bits in each array element */
+#define BTM_EIR_SERVICE_ARRAY_SIZE (((UINT32)BTM_EIR_MAX_SERVICES / BTM_EIR_ARRAY_BITS) + \
+ (((UINT32)BTM_EIR_MAX_SERVICES % BTM_EIR_ARRAY_BITS) ? 1 : 0))
+
+/* MACRO to set the service bit mask in a bit stream */
+#define BTM_EIR_SET_SERVICE(p, service) (((UINT32 *)(p))[(((UINT32)(service)) / BTM_EIR_ARRAY_BITS)] |= \
+ ((UINT32)1 << (((UINT32)(service)) % BTM_EIR_ARRAY_BITS)))
+
+
+/* MACRO to clear the service bit mask in a bit stream */
+#define BTM_EIR_CLR_SERVICE(p, service) (((UINT32 *)(p))[(((UINT32)(service)) / BTM_EIR_ARRAY_BITS)] &= \
+ ~((UINT32)1 << (((UINT32)(service)) % BTM_EIR_ARRAY_BITS)))
+
+/* MACRO to check the service bit mask in a bit stream */
+#define BTM_EIR_HAS_SERVICE(p, service) ((((UINT32 *)(p))[(((UINT32)(service)) / BTM_EIR_ARRAY_BITS)] & \
+ ((UINT32)1 << (((UINT32)(service)) % BTM_EIR_ARRAY_BITS))) >> (((UINT32)(service)) % BTM_EIR_ARRAY_BITS))
+
+/* start of EIR in HCI buffer, 4 bytes = HCI Command(2) + Length(1) + FEC_Req(1) */
+#define BTM_HCI_EIR_OFFSET (BT_HDR_SIZE + 4)
+
+/***************************
+** Device Discovery Types
+****************************/
+/* Definitions of the parameters passed to BTM_StartInquiry and
+** BTM_SetPeriodicInquiryMode.
+*/
+typedef struct /* contains the two device class condition fields */
+{
+ DEV_CLASS dev_class;
+ DEV_CLASS dev_class_mask;
+} tBTM_COD_COND;
+
+
+typedef union /* contains the inquiry filter condition */
+{
+ BD_ADDR bdaddr_cond;
+ tBTM_COD_COND cod_cond;
+} tBTM_INQ_FILT_COND;
+
+
+typedef struct /* contains the parameters passed to the inquiry functions */
+{
+ UINT8 mode; /* general or limited */
+ UINT8 duration; /* duration of the inquiry (1.28 sec increments) */
+ UINT8 max_resps; /* maximum number of responses to return */
+ BOOLEAN report_dup; /* report duplicated inquiry response with higher RSSI value */
+ UINT8 filter_cond_type; /* new devices, BD ADDR, COD, or No filtering */
+ tBTM_INQ_FILT_COND filter_cond; /* filter value based on filter cond type */
+} tBTM_INQ_PARMS;
+
+#define BTM_INQ_RESULT_BR 0x01
+#define BTM_INQ_RESULT_BLE 0x02
+
+#if (BLE_INCLUDED == TRUE)
+#define BTM_BLE_EVT_CONN_ADV 0x00
+#define BTM_BLE_EVT_CONN_DIR_ADV 0x01
+#define BTM_BLE_EVT_DISC_ADV 0x02
+#define BTM_BLE_EVT_NON_CONN_ADV 0x03
+#define BTM_BLE_EVT_SCAN_RSP 0x04
+typedef UINT8 tBTM_BLE_EVT_TYPE;
+#endif
+
+/* These are the fields returned in each device's response to the inquiry. It
+** is returned in the results callback if registered.
+*/
+typedef struct
+{
+ UINT16 clock_offset;
+ BD_ADDR remote_bd_addr;
+ DEV_CLASS dev_class;
+ UINT8 page_scan_rep_mode;
+ UINT8 page_scan_per_mode;
+ UINT8 page_scan_mode;
+ INT8 rssi; /* Set to BTM_INQ_RES_IGNORE_RSSI if not valid */
+#if (BTM_EIR_CLIENT_INCLUDED == TRUE)
+ UINT32 eir_uuid[BTM_EIR_SERVICE_ARRAY_SIZE];
+ BOOLEAN eir_complete_list;
+#endif
+#if (BLE_INCLUDED == TRUE)
+ tBT_DEVICE_TYPE device_type;
+ UINT8 inq_result_type;
+ UINT8 ble_addr_type;
+ tBTM_BLE_EVT_TYPE ble_evt_type;
+ UINT8 flag;
+#endif
+} tBTM_INQ_RESULTS;
+
+
+/* This is the inquiry response information held in its database by BTM, and available
+** to applications via BTM_InqDbRead, BTM_InqDbFirst, and BTM_InqDbNext.
+*/
+typedef struct
+{
+ tBTM_INQ_RESULTS results;
+
+ BOOLEAN appl_knows_rem_name; /* set by application if it knows the remote name of the peer device.
+ This is later used by application to determine if remote name request is
+ required to be done. Having the flag here avoid duplicate store of inquiry results */
+
+
+#if (BTM_INQ_GET_REMOTE_NAME == TRUE || BLE_INCLUDED == TRUE)
+ UINT16 remote_name_len;
+ tBTM_BD_NAME remote_name;
+ UINT8 remote_name_state;
+ UINT8 remote_name_type;
+#endif
+
+} tBTM_INQ_INFO;
+
+
+/* Structure returned with inquiry complete callback */
+typedef struct
+{
+ tBTM_STATUS status;
+ UINT8 num_resp; /* Number of results from the current inquiry */
+} tBTM_INQUIRY_CMPL;
+
+
+/* Structure returned with remote name request */
+typedef struct
+{
+ UINT16 status;
+ UINT16 length;
+ BD_NAME remote_bd_name;
+} tBTM_REMOTE_DEV_NAME;
+
+typedef struct
+{
+ UINT8 pcm_intf_rate; /* PCM interface rate: 0: 128kbps, 1: 256 kbps;
+ 2:512 bps; 3: 1024kbps; 4: 2048kbps */
+ UINT8 frame_type; /* frame type: 0: short; 1: long */
+ UINT8 sync_mode; /* sync mode: 0: slave; 1: master */
+ UINT8 clock_mode; /* clock mode: 0: slave; 1: master */
+
+}tBTM_SCO_PCM_PARAM;
+
+/****************************************
+** Device Discovery Callback Functions
+*****************************************/
+/* Callback function for asynchronous notifications when the BTM inquiry DB
+** changes. First param is inquiry database, second is if added to or removed
+** from the inquiry database.
+*/
+typedef void (tBTM_INQ_DB_CHANGE_CB) (void *p1, BOOLEAN is_new);
+
+/* Callback function for notifications when the BTM gets inquiry response.
+** First param is inquiry results database, second is pointer of EIR.
+*/
+typedef void (tBTM_INQ_RESULTS_CB) (tBTM_INQ_RESULTS *p_inq_results, UINT8 *p_eir);
+
+/*****************************************************************************
+** ACL CHANNEL MANAGEMENT
+*****************************************************************************/
+/******************
+** ACL Constants
+*******************/
+
+/* ACL modes */
+#define BTM_ACL_MODE_NORMAL HCI_MODE_ACTIVE
+#define BTM_ACL_MODE_HOLD HCI_MODE_HOLD
+#define BTM_ACL_MODE_SNIFF HCI_MODE_SNIFF
+#define BTM_ACL_MODE_PARK HCI_MODE_PARK
+
+/* Returned with structure in role switch callback (tBTM_ROLE_SWITCH_CMPL) */
+#define BTM_ROLE_MASTER HCI_ROLE_MASTER
+#define BTM_ROLE_SLAVE HCI_ROLE_SLAVE
+#define BTM_ROLE_UNDEFINED 0xff /* undefined value (error status) */
+
+/* ACL Packet Types */
+#define BTM_ACL_PKT_TYPES_MASK_DM1 HCI_PKT_TYPES_MASK_DM1
+#define BTM_ACL_PKT_TYPES_MASK_DH1 HCI_PKT_TYPES_MASK_DH1
+#define BTM_ACL_PKT_TYPES_MASK_DM3 HCI_PKT_TYPES_MASK_DM3
+#define BTM_ACL_PKT_TYPES_MASK_DH3 HCI_PKT_TYPES_MASK_DH3
+#define BTM_ACL_PKT_TYPES_MASK_DM5 HCI_PKT_TYPES_MASK_DM5
+#define BTM_ACL_PKT_TYPES_MASK_DH5 HCI_PKT_TYPES_MASK_DH5
+#define BTM_ACL_PKT_TYPES_MASK_NO_2_DH1 HCI_PKT_TYPES_MASK_NO_2_DH1
+#define BTM_ACL_PKT_TYPES_MASK_NO_3_DH1 HCI_PKT_TYPES_MASK_NO_3_DH1
+#define BTM_ACL_PKT_TYPES_MASK_NO_2_DH3 HCI_PKT_TYPES_MASK_NO_2_DH3
+#define BTM_ACL_PKT_TYPES_MASK_NO_3_DH3 HCI_PKT_TYPES_MASK_NO_3_DH3
+#define BTM_ACL_PKT_TYPES_MASK_NO_2_DH5 HCI_PKT_TYPES_MASK_NO_2_DH5
+#define BTM_ACL_PKT_TYPES_MASK_NO_3_DH5 HCI_PKT_TYPES_MASK_NO_3_DH5
+
+/***************
+** ACL Types
+****************/
+
+/* Structure returned with link policy information (in tBTM_CMPL_CB callback function)
+** in response to BTM_ReadLinkPolicy call.
+*/
+typedef struct
+{
+ tBTM_STATUS status;
+ UINT8 hci_status;
+ BD_ADDR rem_bda;
+ UINT16 settings;
+} tBTM_LNK_POLICY_RESULTS;
+
+/* Structure returned with Role Switch information (in tBTM_CMPL_CB callback function)
+** in response to BTM_SwitchRole call.
+*/
+typedef struct
+{
+ UINT8 hci_status; /* HCI status returned with the event */
+ UINT8 role; /* BTM_ROLE_MASTER or BTM_ROLE_SLAVE */
+ BD_ADDR remote_bd_addr; /* Remote BD addr involved with the switch */
+} tBTM_ROLE_SWITCH_CMPL;
+
+
+/* Structure returned with Change Link Key information (in tBTM_CMPL_CB callback function)
+** in response to BTM_ChangeLinkKey call.
+*/
+typedef struct
+{
+ UINT8 hci_status; /* HCI status returned with the event */
+ BD_ADDR remote_bd_addr; /* Remote BD addr involved with the change link key */
+} tBTM_CHANGE_KEY_CMPL;
+
+
+/* Structure returned with QoS information (in tBTM_CMPL_CB callback function)
+** in response to BTM_SetQoS call.
+*/
+typedef struct
+{
+ FLOW_SPEC flow;
+ UINT16 handle;
+ UINT8 status;
+} tBTM_QOS_SETUP_CMPL;
+
+
+/* Structure returned with read RSSI event (in tBTM_CMPL_CB callback function)
+** in response to BTM_ReadRSSI call.
+*/
+typedef struct
+{
+ tBTM_STATUS status;
+ UINT8 hci_status;
+ INT8 rssi;
+ BD_ADDR rem_bda;
+} tBTM_RSSI_RESULTS;
+
+/* Structure returned with read current TX power event (in tBTM_CMPL_CB callback function)
+** in response to BTM_ReadTxPower call.
+*/
+typedef struct
+{
+ tBTM_STATUS status;
+ UINT8 hci_status;
+ INT8 tx_power;
+ BD_ADDR rem_bda;
+} tBTM_TX_POWER_RESULTS;
+
+/* Structure returned with read link quality event (in tBTM_CMPL_CB callback function)
+** in response to BTM_ReadLinkQuality call.
+*/
+typedef struct
+{
+ tBTM_STATUS status;
+ UINT8 hci_status;
+ UINT8 link_quality;
+ BD_ADDR rem_bda;
+} tBTM_LINK_QUALITY_RESULTS;
+
+/* Structure returned with read inq tx power quality event (in tBTM_CMPL_CB callback function)
+** in response to BTM_ReadInquiryRspTxPower call.
+*/
+typedef struct
+{
+ tBTM_STATUS status;
+ UINT8 hci_status;
+ INT8 tx_power;
+} tBTM_INQ_TXPWR_RESULTS;
+
+enum
+{
+ BTM_BL_CONN_EVT,
+ BTM_BL_DISCN_EVT,
+ BTM_BL_UPDATE_EVT,
+ BTM_BL_ROLE_CHG_EVT,
+ BTM_BL_COLLISION_EVT
+};
+typedef UINT8 tBTM_BL_EVENT;
+typedef UINT16 tBTM_BL_EVENT_MASK;
+
+#define BTM_BL_CONN_MASK 0x0001
+#define BTM_BL_DISCN_MASK 0x0002
+#define BTM_BL_UPDATE_MASK 0x0004
+#define BTM_BL_ROLE_CHG_MASK 0x0008
+
+/* the data type associated with BTM_BL_CONN_EVT */
+typedef struct
+{
+ tBTM_BL_EVENT event; /* The event reported. */
+ BD_ADDR_PTR p_bda; /* The address of the newly connected device */
+ DEV_CLASS_PTR p_dc; /* The device class */
+ BD_NAME_PTR p_bdn; /* The device name */
+ UINT8 *p_features; /* The remote device's supported features */
+} tBTM_BL_CONN_DATA;
+
+/* the data type associated with BTM_BL_DISCN_EVT */
+typedef struct
+{
+ tBTM_BL_EVENT event; /* The event reported. */
+ BD_ADDR_PTR p_bda; /* The address of the disconnected device */
+} tBTM_BL_DISCN_DATA;
+
+/* the data type associated with BTM_BL_UPDATE_EVT */
+typedef struct
+{
+ tBTM_BL_EVENT event; /* The event reported. */
+ UINT8 busy_level;/* when paging or inquiring, level is 10.
+ * Otherwise, the number of ACL links. */
+} tBTM_BL_UPDATE_DATA;
+
+/* the data type associated with BTM_BL_ROLE_CHG_EVT */
+typedef struct
+{
+ tBTM_BL_EVENT event; /* The event reported. */
+ BD_ADDR_PTR p_bda; /* The address of the peer connected device */
+ UINT8 new_role;
+ UINT8 hci_status; /* HCI status returned with the event */
+} tBTM_BL_ROLE_CHG_DATA;
+
+typedef union
+{
+ tBTM_BL_EVENT event; /* The event reported. */
+ tBTM_BL_CONN_DATA conn; /* The data associated with BTM_BL_CONN_EVT */
+ tBTM_BL_DISCN_DATA discn; /* The data associated with BTM_BL_DISCN_EVT */
+ tBTM_BL_UPDATE_DATA update; /* The data associated with BTM_BL_UPDATE_EVT */
+ tBTM_BL_ROLE_CHG_DATA role_chg;/*The data associated with BTM_BL_ROLE_CHG_EVT */
+} tBTM_BL_EVENT_DATA;
+
+/* Callback function for notifications when the BTM busy level
+** changes.
+*/
+typedef void (tBTM_BL_CHANGE_CB) (tBTM_BL_EVENT_DATA *p_data);
+
+/***************************
+** ACL Callback Functions
+****************************/
+/* Callback function for notifications when the BTM ACL connection DB
+** changes. First param is BD address, second is if added or removed.
+** Registered through BTM_AclRegisterForChanges call.
+*/
+typedef void (tBTM_ACL_DB_CHANGE_CB) (BD_ADDR p_bda, DEV_CLASS p_dc,
+ BD_NAME p_bdn, BD_FEATURES features,
+ BOOLEAN is_new);
+
+/*****************************************************************************
+** SCO CHANNEL MANAGEMENT
+*****************************************************************************/
+/******************
+** SCO Constants
+*******************/
+
+/* Define an invalid SCO index and an invalid HCI handle */
+#define BTM_INVALID_SCO_INDEX 0xFFFF
+#define BTM_INVALID_HCI_HANDLE 0xFFFF
+
+/* Define an invalid SCO disconnect reason */
+#define BTM_INVALID_SCO_DISC_REASON 0xFFFF
+
+/* Define SCO packet types used in APIs */
+#define BTM_SCO_PKT_TYPES_MASK_HV1 HCI_ESCO_PKT_TYPES_MASK_HV1
+#define BTM_SCO_PKT_TYPES_MASK_HV2 HCI_ESCO_PKT_TYPES_MASK_HV2
+#define BTM_SCO_PKT_TYPES_MASK_HV3 HCI_ESCO_PKT_TYPES_MASK_HV3
+#define BTM_SCO_PKT_TYPES_MASK_EV3 HCI_ESCO_PKT_TYPES_MASK_EV3
+#define BTM_SCO_PKT_TYPES_MASK_EV4 HCI_ESCO_PKT_TYPES_MASK_EV4
+#define BTM_SCO_PKT_TYPES_MASK_EV5 HCI_ESCO_PKT_TYPES_MASK_EV5
+#define BTM_SCO_PKT_TYPES_MASK_NO_2_EV3 HCI_ESCO_PKT_TYPES_MASK_NO_2_EV3
+#define BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 HCI_ESCO_PKT_TYPES_MASK_NO_3_EV3
+#define BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 HCI_ESCO_PKT_TYPES_MASK_NO_2_EV5
+#define BTM_SCO_PKT_TYPES_MASK_NO_3_EV5 HCI_ESCO_PKT_TYPES_MASK_NO_3_EV5
+
+#define BTM_SCO_LINK_ONLY_MASK (BTM_SCO_PKT_TYPES_MASK_HV1 | \
+ BTM_SCO_PKT_TYPES_MASK_HV2 | \
+ BTM_SCO_PKT_TYPES_MASK_HV3)
+
+#define BTM_ESCO_LINK_ONLY_MASK (BTM_SCO_PKT_TYPES_MASK_EV3 | \
+ BTM_SCO_PKT_TYPES_MASK_EV4 | \
+ BTM_SCO_PKT_TYPES_MASK_EV5)
+
+#define BTM_SCO_LINK_ALL_PKT_MASK (BTM_SCO_LINK_ONLY_MASK | \
+ BTM_ESCO_LINK_ONLY_MASK)
+
+#define BTM_VALID_SCO_ALL_PKT_TYPE HCI_VALID_SCO_ALL_PKT_TYPE
+
+/* Passed in BTM_CreateSco if the packet type parameter should be ignored */
+#define BTM_IGNORE_SCO_PKT_TYPE 0
+
+/***************
+** SCO Types
+****************/
+#define BTM_LINK_TYPE_SCO HCI_LINK_TYPE_SCO
+#define BTM_LINK_TYPE_ESCO HCI_LINK_TYPE_ESCO
+typedef UINT8 tBTM_SCO_TYPE;
+
+
+/*******************
+** SCO Routing Path
+********************/
+#define BTM_SCO_ROUTE_PCM HCI_BRCM_SCO_ROUTE_PCM
+#define BTM_SCO_ROUTE_HCI HCI_BRCM_SCO_ROUTE_HCI
+typedef UINT8 tBTM_SCO_ROUTE_TYPE;
+
+
+/*******************
+** SCO Codec Types
+********************/
+#define BTM_SCO_CODEC_NONE 0x0000
+#define BTM_SCO_CODEC_CVSD 0x0001
+#define BTM_SCO_CODEC_MSBC 0x0002
+typedef UINT16 tBTM_SCO_CODEC_TYPE;
+
+/*******************
+** SCO Voice Settings
+********************/
+#define BTM_VOICE_SETTING_CVSD ((UINT16) (HCI_INP_CODING_LINEAR | \
+ HCI_INP_DATA_FMT_2S_COMPLEMENT | \
+ HCI_INP_SAMPLE_SIZE_16BIT | \
+ HCI_AIR_CODING_FORMAT_CVSD))
+
+#define BTM_VOICE_SETTING_TRANS ((UINT16) (HCI_INP_CODING_LINEAR | \
+ HCI_INP_DATA_FMT_2S_COMPLEMENT | \
+ HCI_INP_SAMPLE_SIZE_16BIT | \
+ HCI_AIR_CODING_FORMAT_TRANSPNT))
+
+/*******************
+** SCO Data Status
+********************/
+enum
+{
+ BTM_SCO_DATA_CORRECT,
+ BTM_SCO_DATA_PAR_ERR,
+ BTM_SCO_DATA_NONE,
+ BTM_SCO_DATA_PAR_LOST
+};
+typedef UINT8 tBTM_SCO_DATA_FLAG;
+
+/***************************
+** SCO Callback Functions
+****************************/
+typedef void (tBTM_SCO_CB) (UINT16 sco_inx);
+typedef void (tBTM_SCO_DATA_CB) (UINT16 sco_inx, BT_HDR *p_data, tBTM_SCO_DATA_FLAG status);
+
+/******************
+** eSCO Constants
+*******************/
+#define BTM_64KBITS_RATE 0x00001f40 /* 64 kbits/sec data rate */
+
+/* Retransmission effort */
+#define BTM_ESCO_RETRANS_OFF 0
+#define BTM_ESCO_RETRANS_POWER 1
+#define BTM_ESCO_RETRANS_QUALITY 2
+#define BTM_ESCO_RETRANS_DONTCARE 0xff
+
+/* Max Latency Don't Care */
+#define BTM_ESCO_MAX_LAT_DONTCARE 0xffff
+
+/***************
+** eSCO Types
+****************/
+/* tBTM_ESCO_CBACK event types */
+#define BTM_ESCO_CHG_EVT 1
+#define BTM_ESCO_CONN_REQ_EVT 2
+typedef UINT8 tBTM_ESCO_EVT;
+
+/* Passed into BTM_SetEScoMode() */
+typedef struct
+{
+ UINT32 tx_bw;
+ UINT32 rx_bw;
+ UINT16 max_latency;
+ UINT16 voice_contfmt; /* Voice Settings or Content Format */
+ UINT16 packet_types;
+ UINT8 retrans_effort;
+} tBTM_ESCO_PARAMS;
+
+typedef struct
+{
+ UINT16 max_latency;
+ UINT16 packet_types;
+ UINT8 retrans_effort;
+} tBTM_CHG_ESCO_PARAMS;
+
+/* Returned by BTM_ReadEScoLinkParms() */
+typedef struct
+{
+ UINT16 rx_pkt_len;
+ UINT16 tx_pkt_len;
+ BD_ADDR bd_addr;
+ UINT8 link_type; /* BTM_LINK_TYPE_SCO or BTM_LINK_TYPE_ESCO */
+ UINT8 tx_interval;
+ UINT8 retrans_window;
+ UINT8 air_mode;
+} tBTM_ESCO_DATA;
+
+typedef struct
+{
+ UINT16 sco_inx;
+ UINT16 rx_pkt_len;
+ UINT16 tx_pkt_len;
+ BD_ADDR bd_addr;
+ UINT8 hci_status;
+ UINT8 tx_interval;
+ UINT8 retrans_window;
+} tBTM_CHG_ESCO_EVT_DATA;
+
+typedef struct
+{
+ UINT16 sco_inx;
+ BD_ADDR bd_addr;
+ DEV_CLASS dev_class;
+ tBTM_SCO_TYPE link_type;
+} tBTM_ESCO_CONN_REQ_EVT_DATA;
+
+typedef union
+{
+ tBTM_CHG_ESCO_EVT_DATA chg_evt;
+ tBTM_ESCO_CONN_REQ_EVT_DATA conn_evt;
+} tBTM_ESCO_EVT_DATA;
+
+/***************************
+** eSCO Callback Functions
+****************************/
+typedef void (tBTM_ESCO_CBACK) (tBTM_ESCO_EVT event, tBTM_ESCO_EVT_DATA *p_data);
+
+
+/*****************************************************************************
+** SECURITY MANAGEMENT
+*****************************************************************************/
+/*******************************
+** Security Manager Constants
+********************************/
+
+/* Security Mode (BTM_SetSecurityMode) */
+#define BTM_SEC_MODE_UNDEFINED 0
+#define BTM_SEC_MODE_NONE 1
+#define BTM_SEC_MODE_SERVICE 2
+#define BTM_SEC_MODE_LINK 3
+#define BTM_SEC_MODE_SP 4
+#define BTM_SEC_MODE_SP_DEBUG 5
+
+/* Security Service Levels [bit mask] (BTM_SetSecurityLevel)
+** Encryption should not be used without authentication
+*/
+#define BTM_SEC_NONE 0x0000 /* Nothing required */
+#define BTM_SEC_IN_AUTHORIZE 0x0001 /* Inbound call requires authorization */
+#define BTM_SEC_IN_AUTHENTICATE 0x0002 /* Inbound call requires authentication */
+#define BTM_SEC_IN_ENCRYPT 0x0004 /* Inbound call requires encryption */
+#define BTM_SEC_OUT_AUTHORIZE 0x0008 /* Outbound call requires authorization */
+#define BTM_SEC_OUT_AUTHENTICATE 0x0010 /* Outbound call requires authentication */
+#define BTM_SEC_OUT_ENCRYPT 0x0020 /* Outbound call requires encryption */
+#define BTM_SEC_BOND 0x0040 /* Bonding */
+#define BTM_SEC_BOND_CONN 0x0080 /* bond_created_connection */
+#define BTM_SEC_FORCE_MASTER 0x0100 /* Need to switch connection to be master */
+#define BTM_SEC_ATTEMPT_MASTER 0x0200 /* Try to switch connection to be master */
+#define BTM_SEC_FORCE_SLAVE 0x0400 /* Need to switch connection to be master */
+#define BTM_SEC_ATTEMPT_SLAVE 0x0800 /* Try to switch connection to be slave */
+#define BTM_SEC_IN_MITM 0x1000 /* inbound Do man in the middle protection */
+#define BTM_SEC_OUT_MITM 0x2000 /* outbound Do man in the middle protection */
+
+/* Security Flags [bit mask] (BTM_GetSecurityFlags)
+*/
+#define BTM_SEC_FLAG_AUTHORIZED 0x01
+#define BTM_SEC_FLAG_AUTHENTICATED 0x02
+#define BTM_SEC_FLAG_ENCRYPTED 0x04
+#define BTM_SEC_FLAG_LKEY_KNOWN 0x10
+#define BTM_SEC_FLAG_LKEY_AUTHED 0x20
+
+/* PIN types */
+#define BTM_PIN_TYPE_VARIABLE HCI_PIN_TYPE_VARIABLE
+#define BTM_PIN_TYPE_FIXED HCI_PIN_TYPE_FIXED
+
+/* Link Key types used to generate the new link key.
+** returned in link key notification callback function
+*/
+#define BTM_LKEY_TYPE_COMBINATION HCI_LKEY_TYPE_COMBINATION
+#define BTM_LKEY_TYPE_LOCAL_UNIT HCI_LKEY_TYPE_LOCAL_UNIT
+#define BTM_LKEY_TYPE_REMOTE_UNIT HCI_LKEY_TYPE_REMOTE_UNIT
+#define BTM_LKEY_TYPE_DEBUG_COMB HCI_LKEY_TYPE_DEBUG_COMB
+#define BTM_LKEY_TYPE_UNAUTH_COMB HCI_LKEY_TYPE_UNAUTH_COMB
+#define BTM_LKEY_TYPE_AUTH_COMB HCI_LKEY_TYPE_AUTH_COMB
+#define BTM_LKEY_TYPE_CHANGED_COMB HCI_LKEY_TYPE_CHANGED_COMB
+#define BTM_LKEY_TYPE_IGNORE 0xff /* used when event is response from
+ hci return link keys request */
+
+/* Protocol level security (BTM_SetSecurityLevel) */
+#define BTM_SEC_PROTO_L2CAP 0
+#define BTM_SEC_PROTO_SDP 1
+#define BTM_SEC_PROTO_TCS 2
+#define BTM_SEC_PROTO_RFCOMM 3
+#define BTM_SEC_PROTO_OBEX 4
+#define BTM_SEC_PROTO_BNEP 5
+#define BTM_SEC_PROTO_HID 6 /* HID */
+#define BTM_SEC_PROTO_AVDT 7
+#define BTM_SEC_PROTO_MCA 8
+
+/* Determine the number of UINT32's necessary for security services */
+#define BTM_SEC_ARRAY_BITS 32 /* Number of bits in each array element */
+#define BTM_SEC_SERVICE_ARRAY_SIZE (((UINT32)BTM_SEC_MAX_SERVICES / BTM_SEC_ARRAY_BITS) + \
+ (((UINT32)BTM_SEC_MAX_SERVICES % BTM_SEC_ARRAY_BITS) ? 1 : 0))
+
+/* Security service definitions (BTM_SetSecurityLevel)
+** Used for Authorization APIs
+*/
+#define BTM_SEC_SERVICE_SDP_SERVER 0
+#define BTM_SEC_SERVICE_SERIAL_PORT 1
+#define BTM_SEC_SERVICE_LAN_ACCESS 2
+#define BTM_SEC_SERVICE_DUN 3
+#define BTM_SEC_SERVICE_IRMC_SYNC 4
+#define BTM_SEC_SERVICE_IRMC_SYNC_CMD 5
+#define BTM_SEC_SERVICE_OBEX 6
+#define BTM_SEC_SERVICE_OBEX_FTP 7
+#define BTM_SEC_SERVICE_HEADSET 8
+#define BTM_SEC_SERVICE_CORDLESS 9
+#define BTM_SEC_SERVICE_INTERCOM 10
+#define BTM_SEC_SERVICE_FAX 11
+#define BTM_SEC_SERVICE_HEADSET_AG 12
+#define BTM_SEC_SERVICE_PNP_INFO 13
+#define BTM_SEC_SERVICE_GEN_NET 14
+#define BTM_SEC_SERVICE_GEN_FILE 15
+#define BTM_SEC_SERVICE_GEN_AUDIO 16
+#define BTM_SEC_SERVICE_GEN_TEL 17
+#define BTM_SEC_SERVICE_CTP_DATA 18
+#define BTM_SEC_SERVICE_HCRP_CTRL 19
+#define BTM_SEC_SERVICE_HCRP_DATA 20
+#define BTM_SEC_SERVICE_HCRP_NOTIF 21
+#define BTM_SEC_SERVICE_BPP_JOB 22
+#define BTM_SEC_SERVICE_BPP_STATUS 23
+#define BTM_SEC_SERVICE_BPP_REF 24
+#define BTM_SEC_SERVICE_BNEP_PANU 25
+#define BTM_SEC_SERVICE_BNEP_GN 26
+#define BTM_SEC_SERVICE_BNEP_NAP 27
+#define BTM_SEC_SERVICE_HF_HANDSFREE 28
+#define BTM_SEC_SERVICE_AG_HANDSFREE 29
+#define BTM_SEC_SERVICE_TE_PHONE_ACCESS 30
+#define BTM_SEC_SERVICE_ME_PHONE_ACCESS 31
+
+#define BTM_SEC_SERVICE_HID_SEC_CTRL 32
+#define BTM_SEC_SERVICE_HID_NOSEC_CTRL 33
+#define BTM_SEC_SERVICE_HID_INTR 34
+#define BTM_SEC_SERVICE_BIP 35
+#define BTM_SEC_SERVICE_BIP_REF 36
+#define BTM_SEC_SERVICE_AVDTP 37
+#define BTM_SEC_SERVICE_AVDTP_NOSEC 38
+#define BTM_SEC_SERVICE_AVCTP 39
+#define BTM_SEC_SERVICE_SAP 40
+#define BTM_SEC_SERVICE_PBAP 41
+#define BTM_SEC_SERVICE_RFC_MUX 42
+#define BTM_SEC_SERVICE_AVCTP_BROWSE 43
+#define BTM_SEC_SERVICE_MAP 44
+#define BTM_SEC_SERVICE_MAP_NOTIF 45
+#define BTM_SEC_SERVICE_MCAP_CTRL 46
+#define BTM_SEC_SERVICE_MCAP_DATA 47
+#define BTM_SEC_SERVICE_HDP_SNK 48
+#define BTM_SEC_SERVICE_HDP_SRC 49
+#define BTM_SEC_SERVICE_ATT 50
+
+/* Update these as services are added */
+#define BTM_SEC_SERVICE_FIRST_EMPTY 51
+
+#ifndef BTM_SEC_MAX_SERVICES
+#define BTM_SEC_MAX_SERVICES 65
+#endif
+
+/************************************************************************************************
+** Security Services MACROS handle array of UINT32 bits for more than 32 trusted services
+*************************************************************************************************/
+/* MACRO to set the security service bit mask in a bit stream */
+#define BTM_SEC_SET_SERVICE(p, service) (((UINT32 *)(p))[(((UINT32)(service)) / BTM_SEC_ARRAY_BITS)] |= \
+ ((UINT32)1 << (((UINT32)(service)) % BTM_SEC_ARRAY_BITS)))
+
+
+/* MACRO to clear the security service bit mask in a bit stream */
+#define BTM_SEC_CLR_SERVICE(p, service) (((UINT32 *)(p))[(((UINT32)(service)) / BTM_SEC_ARRAY_BITS)] &= \
+ ~((UINT32)1 << (((UINT32)(service)) % BTM_SEC_ARRAY_BITS)))
+
+/* MACRO to check the security service bit mask in a bit stream (Returns TRUE or FALSE) */
+#define BTM_SEC_IS_SERVICE_TRUSTED(p, service) (((((UINT32 *)(p))[(((UINT32)(service)) / BTM_SEC_ARRAY_BITS)]) & \
+ (UINT32)(((UINT32)1 << (((UINT32)(service)) % BTM_SEC_ARRAY_BITS)))) ? TRUE : FALSE)
+
+/* MACRO to copy two trusted device bitmask */
+#define BTM_SEC_COPY_TRUSTED_DEVICE(p_src, p_dst) {int trst; for (trst = 0; trst < BTM_SEC_SERVICE_ARRAY_SIZE; trst++) \
+ ((UINT32 *)(p_dst))[trst] = ((UINT32 *)(p_src))[trst];}
+
+/* MACRO to clear two trusted device bitmask */
+#define BTM_SEC_CLR_TRUSTED_DEVICE(p_dst) {int trst; for (trst = 0; trst < BTM_SEC_SERVICE_ARRAY_SIZE; trst++) \
+ ((UINT32 *)(p_dst))[trst] = 0;}
+
+/* Following bits can be provided by host in the trusted_mask array */
+/* 0..31 bits of mask[0] (Least Significant Word) */
+#define BTM_SEC_TRUST_SDP_SERVER (1 << BTM_SEC_SERVICE_SDP_SERVER)
+#define BTM_SEC_TRUST_SERIAL_PORT (1 << BTM_SEC_SERVICE_SERIAL_PORT)
+#define BTM_SEC_TRUST_LAN_ACCESS (1 << BTM_SEC_SERVICE_LAN_ACCESS)
+#define BTM_SEC_TRUST_DUN (1 << BTM_SEC_SERVICE_DUN)
+#define BTM_SEC_TRUST_IRMC_SYNC (1 << BTM_SEC_SERVICE_IRMC_SYNC)
+#define BTM_SEC_TRUST_IRMC_SYNC_CMD (1 << BTM_SEC_SERVICE_IRMC_SYNC_CMD)
+#define BTM_SEC_TRUST_OBEX (1 << BTM_SEC_SERVICE_OBEX)
+#define BTM_SEC_TRUST_OBEX_FTP (1 << BTM_SEC_SERVICE_OBEX_FTP)
+#define BTM_SEC_TRUST_HEADSET (1 << BTM_SEC_SERVICE_HEADSET)
+#define BTM_SEC_TRUST_CORDLESS (1 << BTM_SEC_SERVICE_CORDLESS)
+#define BTM_SEC_TRUST_INTERCOM (1 << BTM_SEC_SERVICE_INTERCOM)
+#define BTM_SEC_TRUST_FAX (1 << BTM_SEC_SERVICE_FAX)
+#define BTM_SEC_TRUST_HEADSET_AG (1 << BTM_SEC_SERVICE_HEADSET_AG)
+#define BTM_SEC_TRUST_PNP_INFO (1 << BTM_SEC_SERVICE_PNP_INFO)
+#define BTM_SEC_TRUST_GEN_NET (1 << BTM_SEC_SERVICE_GEN_NET)
+#define BTM_SEC_TRUST_GEN_FILE (1 << BTM_SEC_SERVICE_GEN_FILE)
+#define BTM_SEC_TRUST_GEN_AUDIO (1 << BTM_SEC_SERVICE_GEN_AUDIO)
+#define BTM_SEC_TRUST_GEN_TEL (1 << BTM_SEC_SERVICE_GEN_TEL)
+#define BTM_SEC_TRUST_CTP_DATA (1 << BTM_SEC_SERVICE_CTP_DATA)
+#define BTM_SEC_TRUST_HCRP_CTRL (1 << BTM_SEC_SERVICE_HCRP_CTRL)
+#define BTM_SEC_TRUST_HCRP_DATA (1 << BTM_SEC_SERVICE_HCRP_DATA)
+#define BTM_SEC_TRUST_HCRP_NOTIF (1 << BTM_SEC_SERVICE_HCRP_NOTIF)
+#define BTM_SEC_TRUST_BPP_JOB (1 << BTM_SEC_SERVICE_JOB)
+#define BTM_SEC_TRUST_BPP_STATUS (1 << BTM_SEC_SERVICE_STATUS)
+#define BTM_SEC_TRUST_BPP_REF (1 << BTM_SEC_SERVICE_REF)
+#define BTM_SEC_TRUST_BNEP_PANU (1 << BTM_SEC_SERVICE_BNEP_PANU)
+#define BTM_SEC_TRUST_BNEP_GN (1 << BTM_SEC_SERVICE_BNEP_GN)
+#define BTM_SEC_TRUST_BNEP_NAP (1 << BTM_SEC_SERVICE_BNEP_NAP)
+#define BTM_SEC_TRUST_HFP_HF (1 << BTM_SEC_SERVICE_HF_HANDSFREE)
+#define BTM_SEC_TRUST_HFP_AG (1 << BTM_SEC_SERVICE_AG_HANDSFREE)
+#define BTM_SEC_TRUST_TE_PHONE_ACCESS (1 << BTM_SEC_SERVICE_TE_PHONE_ACCESS)
+#define BTM_SEC_TRUST_ME_PHONE_ACCESS (1 << BTM_SEC_SERVICE_ME_PHONE_ACCESS)
+
+/* 0..31 bits of mask[1] (Most Significant Word) */
+#define BTM_SEC_TRUST_HID_CTRL (1 << (BTM_SEC_SERVICE_HID_SEC_CTRL - 32))
+#define BTM_SEC_TRUST_HID_NOSEC_CTRL (1 << (BTM_SEC_SERVICE_HID_NOSEC_CTRL - 32))
+#define BTM_SEC_TRUST_HID_INTR (1 << (BTM_SEC_SERVICE_HID_INTR - 32))
+#define BTM_SEC_TRUST_BIP (1 << (BTM_SEC_SERVICE_BIP - 32))
+#define BTM_SEC_TRUST_BIP_REF (1 << (BTM_SEC_SERVICE_BIP_REF - 32))
+#define BTM_SEC_TRUST_AVDTP (1 << (BTM_SEC_SERVICE_AVDTP - 32))
+#define BTM_SEC_TRUST_AVDTP_NOSEC (1 << (BTM_SEC_SERVICE_AVDTP_NOSEC - 32))
+#define BTM_SEC_TRUST_AVCTP (1 << (BTM_SEC_SERVICE_AVCTP - 32))
+#define BTM_SEC_TRUST_SAP (1 << (BTM_SEC_SERVICE_SAP - 32))
+#define BTM_SEC_TRUST_PBAP (1 << (BTM_SEC_SERVICE_PBAP - 32))
+#define BTM_SEC_TRUST_RFC_MUX (1 << (BTM_SEC_SERVICE_RFC_MUX - 32))
+#define BTM_SEC_TRUST_AVCTP_BROWSE (1 << (BTM_SEC_SERVICE_AVCTP_BROWSE - 32))
+#define BTM_SEC_TRUST_MAP (1 << (BTM_SEC_SERVICE_MAP - 32))
+#define BTM_SEC_TRUST_MAP_NOTIF (1 << (BTM_SEC_SERVICE_MAP_NOTIF - 32))
+#define BTM_SEC_TRUST_MCAP_CTRL (1 << (BTM_SEC_SERVICE_MCAP_CTRL - 32))
+#define BTM_SEC_TRUST_MCAP_DATA (1 << (BTM_SEC_SERVICE_MCAP_DATA - 32))
+#define BTM_SEC_TRUST_HDP_SNK (1 << (BTM_SEC_SERVICE_HDP_SNK - 32))
+#define BTM_SEC_TRUST_HDP_SRC (1 << (BTM_SEC_SERVICE_HDP_SRC - 32))
+
+#define BTM_SEC_TRUST_ALL 0xFFFFFFFF /* for each array element */
+
+/****************************************
+** Security Manager Callback Functions
+*****************************************/
+/* Authorize device for service. Parameters are
+** BD Address of remote
+** Device Class of remote
+** BD Name of remote
+** Service name
+** Service Id (NULL - unknown service or unused
+** [BTM_SEC_SERVICE_NAME_LEN set to 0])
+** Is originator of the connection
+** Result of the operation
+*/
+typedef UINT8 (tBTM_AUTHORIZE_CALLBACK) (BD_ADDR bd_addr, DEV_CLASS dev_class,
+ tBTM_BD_NAME bd_name, UINT8 *service_name,
+ UINT8 service_id, BOOLEAN is_originator);
+
+/* Get PIN for the connection. Parameters are
+** BD Address of remote
+** Device Class of remote
+** BD Name of remote
+*/
+typedef UINT8 (tBTM_PIN_CALLBACK) (BD_ADDR bd_addr, DEV_CLASS dev_class,
+ tBTM_BD_NAME bd_name);
+
+
+/* Get Link Key for the connection. Parameters are
+** BD Address of remote
+** Link Key
+*/
+typedef UINT8 (tBTM_LINK_KEY_REQ_CALLBACK) (BD_ADDR bd_addr, LINK_KEY key);
+
+/* New Link Key for the connection. Parameters are
+** BD Address of remote
+** Link Key
+** Key Type: Combination, Local Unit, or Remote Unit
+*/
+typedef UINT8 (tBTM_LINK_KEY_CALLBACK) (BD_ADDR bd_addr, DEV_CLASS dev_class,
+ tBTM_BD_NAME bd_name, UINT8 *key,
+ UINT8 key_type);
+
+
+/* Remote Name Resolved. Parameters are
+** BD Address of remote
+** BD Name of remote
+*/
+typedef void (tBTM_RMT_NAME_CALLBACK) (BD_ADDR bd_addr, DEV_CLASS dc,
+ tBTM_BD_NAME bd_name);
+
+
+/* Authentication complete for the connection. Parameters are
+** BD Address of remote
+** Device Class of remote
+** BD Name of remote
+**
+*/
+typedef UINT8 (tBTM_AUTH_COMPLETE_CALLBACK) (BD_ADDR bd_addr, DEV_CLASS dev_class,
+ tBTM_BD_NAME bd_name, int result);
+
+/* Operation abort. Called by the stack when link goes down during. Pin code
+** request or authorization. Parameters are
+** BD Address of remote
+**
+*/
+typedef UINT8 (tBTM_ABORT_CALLBACK) (BD_ADDR bd_addr, DEV_CLASS dev_class,
+ tBTM_BD_NAME bd_name);
+
+enum
+{
+ BTM_SP_IO_REQ_EVT, /* received IO_CAPABILITY_REQUEST event */
+ BTM_SP_IO_RSP_EVT, /* received IO_CAPABILITY_RESPONSE event */
+ BTM_SP_CFM_REQ_EVT, /* received USER_CONFIRMATION_REQUEST event */
+ BTM_SP_KEY_NOTIF_EVT, /* received USER_PASSKEY_NOTIFY event */
+ BTM_SP_KEY_REQ_EVT, /* received USER_PASSKEY_REQUEST event */
+ BTM_SP_KEYPRESS_EVT, /* received KEYPRESS_NOTIFY event */
+ BTM_SP_LOC_OOB_EVT, /* received result for READ_LOCAL_OOB_DATA command */
+ BTM_SP_RMT_OOB_EVT, /* received REMOTE_OOB_DATA_REQUEST event */
+ BTM_SP_COMPLT_EVT, /* received SIMPLE_PAIRING_COMPLETE event */
+ BTM_SP_UPGRADE_EVT /* check if the application wants to upgrade the link key */
+};
+typedef UINT8 tBTM_SP_EVT;
+
+#define BTM_IO_CAP_OUT 0 /* DisplayOnly */
+#define BTM_IO_CAP_IO 1 /* DisplayYesNo */
+#define BTM_IO_CAP_IN 2 /* KeyboardOnly */
+#define BTM_IO_CAP_NONE 3 /* NoInputNoOutput */
+#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE
+#define BTM_IO_CAP_KBDISP 4 /* Keyboard display */
+#define BTM_IO_CAP_MAX 5
+#else
+#define BTM_IO_CAP_MAX 4
+#endif
+
+typedef UINT8 tBTM_IO_CAP;
+
+#define BTM_MAX_PASSKEY_VAL (999999)
+#define BTM_MIN_PASSKEY_VAL (0)
+
+#define BTM_AUTH_SP_NO 0 /* MITM Protection Not Required - Single Profile/non-bonding
+ Numeric comparison with automatic accept allowed */
+#define BTM_AUTH_SP_YES 1 /* MITM Protection Required - Single Profile/non-bonding
+ Use IO Capabilities to determine authentication procedure */
+#define BTM_AUTH_AP_NO 2 /* MITM Protection Not Required - All Profiles/dedicated bonding
+ Numeric comparison with automatic accept allowed */
+#define BTM_AUTH_AP_YES 3 /* MITM Protection Required - All Profiles/dedicated bonding
+ Use IO Capabilities to determine authentication procedure */
+#define BTM_AUTH_SPGB_NO 4 /* MITM Protection Not Required - Single Profiles/general bonding
+ Numeric comparison with automatic accept allowed */
+#define BTM_AUTH_SPGB_YES 5 /* MITM Protection Required - Single Profiles/general bonding
+ Use IO Capabilities to determine authentication procedure */
+#define BTM_AUTH_DD_BOND 2 /* this bit is ORed to the BTM_AUTH_SP_* when IO exchange for dedicated bonding */
+#define BTM_AUTH_GB_BIT 4 /* the genernal bonding bit */
+#define BTM_AUTH_BONDS 6 /* the general/dedicated bonding bits */
+#define BTM_AUTH_YN_BIT 1 /* this is the Yes or No bit */
+
+typedef UINT8 tBTM_AUTH_REQ;
+
+enum
+{
+ BTM_OOB_NONE,
+ BTM_OOB_PRESENT
+#if BTM_OOB_INCLUDED == TRUE
+ ,BTM_OOB_UNKNOWN
+#endif
+};
+typedef UINT8 tBTM_OOB_DATA;
+
+/* data type for BTM_SP_IO_REQ_EVT */
+typedef struct
+{
+ BD_ADDR bd_addr; /* peer address */
+ tBTM_IO_CAP io_cap; /* local IO capabilities */
+ tBTM_OOB_DATA oob_data; /* OOB data present (locally) for the peer device */
+ tBTM_AUTH_REQ auth_req; /* Authentication required (for local device) */
+ BOOLEAN is_orig; /* TRUE, if local device initiated the SP process */
+} tBTM_SP_IO_REQ;
+
+/* data type for BTM_SP_IO_RSP_EVT */
+typedef struct
+{
+ BD_ADDR bd_addr; /* peer address */
+ tBTM_IO_CAP io_cap; /* peer IO capabilities */
+ tBTM_OOB_DATA oob_data; /* OOB data present at peer device for the local device */
+ tBTM_AUTH_REQ auth_req; /* Authentication required for peer device */
+} tBTM_SP_IO_RSP;
+
+/* data type for BTM_SP_CFM_REQ_EVT */
+typedef struct
+{
+ BD_ADDR bd_addr; /* peer address */
+ DEV_CLASS dev_class; /* peer CoD */
+ tBTM_BD_NAME bd_name; /* peer device name */
+ UINT32 num_val; /* the numeric value for comparison. If just_works, do not show this number to UI */
+ BOOLEAN just_works; /* TRUE, if "Just Works" association model */
+ tBTM_AUTH_REQ loc_auth_req; /* Authentication required for local device */
+ tBTM_AUTH_REQ rmt_auth_req; /* Authentication required for peer device */
+} tBTM_SP_CFM_REQ;
+
+/* data type for BTM_SP_KEY_REQ_EVT */
+typedef struct
+{
+ BD_ADDR bd_addr; /* peer address */
+ DEV_CLASS dev_class; /* peer CoD */
+ tBTM_BD_NAME bd_name; /* peer device name */
+} tBTM_SP_KEY_REQ;
+
+/* data type for BTM_SP_KEY_NOTIF_EVT */
+typedef struct
+{
+ BD_ADDR bd_addr; /* peer address */
+ DEV_CLASS dev_class; /* peer CoD */
+ tBTM_BD_NAME bd_name; /* peer device name */
+ UINT32 passkey; /* passkey */
+} tBTM_SP_KEY_NOTIF;
+
+enum
+{
+ BTM_SP_KEY_STARTED, /* passkey entry started */
+ BTM_SP_KEY_ENTERED, /* passkey digit entered */
+ BTM_SP_KEY_ERASED, /* passkey digit erased */
+ BTM_SP_KEY_CLEARED, /* passkey cleared */
+ BTM_SP_KEY_COMPLT /* passkey entry completed */
+};
+typedef UINT8 tBTM_SP_KEY_TYPE;
+
+/* data type for BTM_SP_KEYPRESS_EVT */
+typedef struct
+{
+ BD_ADDR bd_addr; /* peer address */
+ tBTM_SP_KEY_TYPE notif_type;
+} tBTM_SP_KEYPRESS;
+
+/* data type for BTM_SP_LOC_OOB_EVT */
+typedef struct
+{
+ tBTM_STATUS status; /* */
+ BT_OCTET16 c; /* Simple Pairing Hash C */
+ BT_OCTET16 r; /* Simple Pairing Randomnizer R */
+} tBTM_SP_LOC_OOB;
+
+/* data type for BTM_SP_RMT_OOB_EVT */
+typedef struct
+{
+ BD_ADDR bd_addr; /* peer address */
+ DEV_CLASS dev_class; /* peer CoD */
+ tBTM_BD_NAME bd_name; /* peer device name */
+} tBTM_SP_RMT_OOB;
+
+
+/* data type for BTM_SP_COMPLT_EVT */
+typedef struct
+{
+ BD_ADDR bd_addr; /* peer address */
+ DEV_CLASS dev_class; /* peer CoD */
+ tBTM_BD_NAME bd_name; /* peer device name */
+ tBTM_STATUS status; /* status of the simple pairing process */
+} tBTM_SP_COMPLT;
+
+/* data type for BTM_SP_UPGRADE_EVT */
+typedef struct
+{
+ BD_ADDR bd_addr; /* peer address */
+ BOOLEAN upgrade; /* TRUE, to upgrade the link key */
+} tBTM_SP_UPGRADE;
+
+typedef union
+{
+ tBTM_SP_IO_REQ io_req; /* BTM_SP_IO_REQ_EVT */
+ tBTM_SP_IO_RSP io_rsp; /* BTM_SP_IO_RSP_EVT */
+ tBTM_SP_CFM_REQ cfm_req; /* BTM_SP_CFM_REQ_EVT */
+ tBTM_SP_KEY_NOTIF key_notif; /* BTM_SP_KEY_NOTIF_EVT */
+ tBTM_SP_KEY_REQ key_req; /* BTM_SP_KEY_REQ_EVT */
+ tBTM_SP_KEYPRESS key_press; /* BTM_SP_KEYPRESS_EVT */
+ tBTM_SP_LOC_OOB loc_oob; /* BTM_SP_LOC_OOB_EVT */
+ tBTM_SP_RMT_OOB rmt_oob; /* BTM_SP_RMT_OOB_EVT */
+ tBTM_SP_COMPLT complt; /* BTM_SP_COMPLT_EVT */
+ tBTM_SP_UPGRADE upgrade; /* BTM_SP_UPGRADE_EVT */
+} tBTM_SP_EVT_DATA;
+
+/* Simple Pairing Events. Called by the stack when Simple Pairing related
+** events occur.
+*/
+typedef UINT8 (tBTM_SP_CALLBACK) (tBTM_SP_EVT event, tBTM_SP_EVT_DATA *p_data);
+
+
+typedef void (tBTM_MKEY_CALLBACK) (BD_ADDR bd_addr, UINT8 status, UINT8 key_flag) ;
+
+/* Encryption enabled/disabled complete: Optionally passed with BTM_SetEncryption.
+** Parameters are
+** BD Address of remote
+** optional data passed in by BTM_SetEncryption
+** tBTM_STATUS - result of the operation
+*/
+typedef void (tBTM_SEC_CBACK) (BD_ADDR bd_addr, void *p_ref_data, tBTM_STATUS result);
+
+/* Bond Cancel complete. Parameters are
+** Result of the cancel operation
+**
+*/
+typedef void (tBTM_BOND_CANCEL_CMPL_CALLBACK) (tBTM_STATUS result);
+
+/* LE related event and data structure
+*/
+enum
+{
+ BTM_LE_IO_REQ_EVT = 1, /* received IO_CAPABILITY_REQUEST event */
+ BTM_LE_SEC_REQUEST_EVT, /* security request event */
+ BTM_LE_KEY_NOTIF_EVT, /* received USER_PASSKEY_NOTIFY event */
+ BTM_LE_KEY_REQ_EVT, /* received USER_PASSKEY_REQUEST event */
+ BTM_LE_OOB_REQ_EVT, /* OOB data request event */
+ BTM_LE_COMPLT_EVT, /* received SIMPLE_PAIRING_COMPLETE event */
+ BTM_LE_KEY_EVT /* KEY update event */
+};
+typedef UINT8 tBTM_LE_EVT;
+
+#define BTM_LE_KEY_PENC SMP_SEC_KEY_TYPE_ENC /* encryption information of peer device */
+#define BTM_LE_KEY_PID SMP_SEC_KEY_TYPE_ID /* identity key of the peer device */
+#define BTM_LE_KEY_PCSRK SMP_SEC_KEY_TYPE_CSRK /* peer SRK */
+#define BTM_LE_KEY_LENC (SMP_SEC_KEY_TYPE_ENC << 3) /* master role security information:div */
+#define BTM_LE_KEY_LID (SMP_SEC_KEY_TYPE_ID << 3) /* master device ID key */
+#define BTM_LE_KEY_LCSRK (SMP_SEC_KEY_TYPE_CSRK << 3) /* local CSRK has been deliver to peer */
+typedef UINT8 tBTM_LE_KEY_TYPE;
+
+#define BTM_LE_AUTH_REQ_NO_BOND SMP_AUTH_NO_BOND /* 0 */
+#define BTM_LE_AUTH_REQ_BOND SMP_AUTH_GEN_BOND /* 1 << 0 */
+#define BTM_LE_AUTH_REQ_MITM SMP_AUTH_YN_BIT /* 1 << 2 */
+typedef UINT8 tBTM_LE_AUTH_REQ;
+
+#define BTM_LE_AUTH_REQ_MASK SMP_AUTH_MASK /* 0x03*/
+
+/* LE security level */
+#define BTM_LE_SEC_NONE SMP_SEC_NONE
+#define BTM_LE_SEC_UNAUTHENTICATE SMP_SEC_UNAUTHENTICATE
+#define BTM_LE_SEC_AUTHENTICATED SMP_SEC_AUTHENTICATED
+typedef UINT8 tBTM_LE_SEC;
+
+
+typedef struct
+{
+ tBTM_IO_CAP io_cap; /* local IO capabilities */
+ UINT8 oob_data; /* OOB data present (locally) for the peer device */
+ tBTM_LE_AUTH_REQ auth_req; /* Authentication request (for local device) contain bonding and MITM info */
+ UINT8 max_key_size; /* max encryption key size */
+ tBTM_LE_KEY_TYPE init_keys; /* keys to be distributed, bit mask */
+ tBTM_LE_KEY_TYPE resp_keys; /* keys to be distributed, bit mask */
+} tBTM_LE_IO_REQ;
+
+#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE
+/* data type for tBTM_LE_COMPLT */
+typedef struct
+{
+ UINT8 reason;
+ UINT8 sec_level;
+}tBTM_LE_COMPLT;
+#endif
+
+/* BLE encryption keys */
+typedef struct
+{
+ BT_OCTET16 ltk;
+ BT_OCTET8 rand;
+ UINT16 ediv;
+ UINT8 sec_level;
+ UINT8 key_size;
+}tBTM_LE_PENC_KEYS;
+
+/* BLE CSRK keys */
+typedef struct
+{
+ UINT32 counter;
+ BT_OCTET16 csrk;
+ UINT8 sec_level;
+}tBTM_LE_PCSRK_KEYS;
+
+/* BLE Encryption reproduction keys */
+typedef struct
+{
+ UINT16 div;
+ UINT8 key_size;
+ UINT8 sec_level;
+}tBTM_LE_LENC_KEYS;
+
+/* BLE SRK keys */
+typedef struct
+{
+ UINT32 counter;
+ UINT16 div;
+ UINT8 sec_level;
+
+}tBTM_LE_LCSRK_KEYS;
+
+
+typedef union
+{
+ tBTM_LE_PENC_KEYS penc_key; /* received peer encryption key */
+ tBTM_LE_PCSRK_KEYS pcsrk_key; /* received peer device SRK */
+ BT_OCTET16 pid_key; /* peer device ID key */
+ tBTM_LE_LENC_KEYS lenc_key; /* local encryption reproduction keys LTK = = d1(ER,DIV,0)*/
+ tBTM_LE_LCSRK_KEYS lcsrk_key; /* local device CSRK = d1(ER,DIV,1)*/
+}tBTM_LE_KEY_VALUE;
+
+typedef struct
+{
+ tBTM_LE_KEY_TYPE key_type;
+ tBTM_LE_KEY_VALUE *p_key_value;
+}tBTM_LE_KEY;
+
+typedef union
+{
+ tBTM_LE_IO_REQ io_req; /* BTM_LE_IO_REQ_EVT */
+ UINT32 key_notif; /* BTM_LE_KEY_NOTIF_EVT */
+ /* no callback dta for BTM_LE_KEY_REQ_EVT & BTM_LE_OOB_REQ_EVT */
+#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE
+ tBTM_LE_COMPLT complt; /* BTM_LE_COMPLT_EVT */
+#endif
+ tBTM_LE_KEY key;
+} tBTM_LE_EVT_DATA;
+
+/* Simple Pairing Events. Called by the stack when Simple Pairing related
+** events occur.
+*/
+typedef UINT8 (tBTM_LE_CALLBACK) (tBTM_LE_EVT event, BD_ADDR bda, tBTM_LE_EVT_DATA *p_data);
+
+#define BTM_BLE_KEY_TYPE_ID 1
+#define BTM_BLE_KEY_TYPE_ER 2
+#define BTM_BLE_KEY_TYPE_COUNTER 3 //tobe obsolete
+
+typedef struct
+{
+ BT_OCTET16 ir;
+ BT_OCTET16 irk;
+ BT_OCTET16 dhk;
+
+}tBTM_BLE_LOCAL_ID_KEYS;
+
+typedef union
+{
+ tBTM_BLE_LOCAL_ID_KEYS id_keys;
+ BT_OCTET16 er;
+}tBTM_BLE_LOCAL_KEYS;
+
+
+/* New LE identity key for local device.
+*/
+typedef void (tBTM_LE_KEY_CALLBACK) (UINT8 key_type, tBTM_BLE_LOCAL_KEYS *p_key);
+
+
+/***************************
+** Security Manager Types
+****************************/
+/* Structure that applications use to register with BTM_SecRegister */
+typedef struct
+{
+ tBTM_AUTHORIZE_CALLBACK *p_authorize_callback;
+ tBTM_PIN_CALLBACK *p_pin_callback;
+ tBTM_LINK_KEY_CALLBACK *p_link_key_callback;
+ tBTM_LINK_KEY_REQ_CALLBACK *p_link_key_req_callback;
+ tBTM_AUTH_COMPLETE_CALLBACK *p_auth_complete_callback;
+ tBTM_ABORT_CALLBACK *p_abort_callback;
+ tBTM_BOND_CANCEL_CMPL_CALLBACK *p_bond_cancel_cmpl_callback;
+ tBTM_SP_CALLBACK *p_sp_callback;
+#if BLE_INCLUDED == TRUE
+#if SMP_INCLUDED == TRUE
+ tBTM_LE_CALLBACK *p_le_callback;
+#endif
+ tBTM_LE_KEY_CALLBACK *p_le_key_callback;
+#endif
+} tBTM_APPL_INFO;
+
+/* Callback function for when a link supervision timeout event occurs.
+** This asynchronous event is enabled/disabled by calling BTM_RegForLstoEvt().
+*/
+typedef void (tBTM_LSTO_CBACK) (BD_ADDR remote_bda, UINT16 timeout);
+
+/*****************************************************************************
+** POWER MANAGEMENT
+*****************************************************************************/
+/****************************
+** Power Manager Constants
+*****************************/
+/* BTM Power manager status codes */
+enum
+{
+ BTM_PM_STS_ACTIVE = HCI_MODE_ACTIVE,
+ BTM_PM_STS_HOLD = HCI_MODE_HOLD,
+ BTM_PM_STS_SNIFF = HCI_MODE_SNIFF,
+ BTM_PM_STS_PARK = HCI_MODE_PARK,
+ BTM_PM_STS_SSR, /* report the SSR parameters in HCI_SNIFF_SUB_RATE_EVT */
+ BTM_PM_STS_PENDING, /* when waiting for status from controller */
+ BTM_PM_STS_ERROR /* when HCI command status returns error */
+};
+typedef UINT8 tBTM_PM_STATUS;
+
+/* BTM Power manager modes */
+enum
+{
+ BTM_PM_MD_ACTIVE = BTM_PM_STS_ACTIVE,
+ BTM_PM_MD_HOLD = BTM_PM_STS_HOLD,
+ BTM_PM_MD_SNIFF = BTM_PM_STS_SNIFF,
+ BTM_PM_MD_PARK = BTM_PM_STS_PARK,
+ BTM_PM_MD_FORCE = 0x10 /* OR this to force ACL link to a certain mode */
+};
+typedef UINT8 tBTM_PM_MODE;
+
+#define BTM_PM_SET_ONLY_ID 0x80
+
+/* Operation codes */
+#define BTM_PM_REG_SET 1 /* The module wants to set the desired power mode */
+#define BTM_PM_REG_NOTIF 2 /* The module wants to receive mode change event */
+#define BTM_PM_DEREG 4 /* The module does not want to involve with PM anymore */
+
+/************************
+** Power Manager Types
+*************************/
+typedef struct
+{
+ UINT16 max;
+ UINT16 min;
+ UINT16 attempt;
+ UINT16 timeout;
+ tBTM_PM_MODE mode;
+} tBTM_PM_PWR_MD;
+
+/*************************************
+** Power Manager Callback Functions
+**************************************/
+typedef void (tBTM_PM_STATUS_CBACK) (BD_ADDR p_bda, tBTM_PM_STATUS status,
+ UINT16 value, UINT8 hci_status);
+
+
+/************************
+** Stored Linkkey Types
+*************************/
+#define BTM_CB_EVT_RETURN_LINK_KEYS 1
+#define BTM_CB_EVT_READ_STORED_LINK_KEYS 2
+#define BTM_CB_EVT_WRITE_STORED_LINK_KEYS 3
+#define BTM_CB_EVT_DELETE_STORED_LINK_KEYS 4
+
+typedef struct
+{
+ UINT8 event;
+
+} tBTM_STORED_LINK_KEYS_EVT;
+
+
+typedef struct
+{
+ UINT8 event;
+ UINT8 num_keys;
+
+} tBTM_RETURN_LINK_KEYS_EVT;
+
+
+typedef struct
+{
+ BD_ADDR bd_addr;
+ LINK_KEY link_key;
+
+} tBTM_BD_ADDR_LINK_KEY_PAIR;
+
+
+typedef struct
+{
+ UINT8 event;
+ UINT8 status;
+ UINT16 max_keys;
+ UINT16 read_keys;
+
+} tBTM_READ_STORED_LINK_KEY_COMPLETE;
+
+
+typedef struct
+{
+ UINT8 event;
+ UINT8 status;
+ UINT8 num_keys;
+
+} tBTM_WRITE_STORED_LINK_KEY_COMPLETE;
+
+
+typedef struct
+{
+ UINT8 event;
+ UINT8 status;
+ UINT16 num_keys;
+
+} tBTM_DELETE_STORED_LINK_KEY_COMPLETE;
+
+
+/* These macros are defined to check the Broadcom features supported in controller
+ * (the return value for BTM_ReadBrcmFeatures() */
+/* multi-av */
+#define BTM_FEATURE_MULTI_AV_MASK 0x01
+#define BTM_FEATURE_MULTI_AV_OFF 0
+#define BTM_VSC_MULTI_AV_SUPPORTED(x) ((x)[BTM_FEATURE_MULTI_AV_OFF] & BTM_FEATURE_MULTI_AV_MASK)
+
+/* WBS SBC codec */
+#define BTM_FEATURE_WBS_SBC_MASK 0x02
+#define BTM_FEATURE_WBS_SBC_OFF 0
+#define BTM_VSC_WBS_SBC_SUPPORTED(x) ((x)[BTM_FEATURE_WBS_SBC_OFF] & BTM_FEATURE_WBS_SBC_MASK)
+
+/* Advanced Audio LC-PLC */
+#define BTM_FEATURE_AUDIO_LC_PLC_MASK 0x04
+#define BTM_FEATURE_AUDIO_LC_PLC_OFF 0
+#define BTM_VSC_AUDIO_LC_PLC_SUPPORTED(x) ((x)[BTM_FEATURE_AUDIO_LC_PLC_OFF] & BTM_FEATURE_AUDIO_LC_PLC_MASK)
+
+/* Light stack for audio routing in Controller */
+#define BTM_FEATURE_LIGHT_STACK_MASK 0x08
+#define BTM_FEATURE_LIGHT_STACK_OFF 0
+#define BTM_VSC_LIGHT_STACK_SUPPORTED(x) ((x)[BTM_FEATURE_LIGHT_STACK_OFF] & BTM_FEATURE_LIGHT_STACK_MASK)
+
+/* NFC support */
+#define BTM_FEATURE_NFC_MASK (HCI_BRCM_FEATURE_NFC_MASK) /* 0x10 */
+#define BTM_FEATURE_NFC_OFF (HCI_BRCM_FEATURE_NFC_OFF) /* 0 */
+#define BTM_VSC_NFC_SUPPORTED(x) ((x)[BTM_FEATURE_NFC_OFF] & BTM_FEATURE_NFC_MASK)
+
+
+/************************
+** Dual-Stack support
+*************************/
+/* BTM_SYNC_FAIL_EVT reason codes */
+#define BTM_SYNC_SUCCESS 0
+#define BTM_SYNC_FAIL_BTE_SWITCH_REJECTED 1
+#define BTM_SYNC_FAIL_TRANS_PAUSE 2
+#define BTM_SYNC_FAIL_CORE_SYNC 3
+#define BTM_SYNC_FAIL_BTA_SYNC 4
+#define BTM_SYNC_FAIL_TRANS_RESUME 5
+#define BTM_SYNC_FAIL_RESYNC 6
+#define BTM_SYNC_FAIL_ERROR 7
+#define BTM_SYNC_FAIL_UIPC_OPEN 8
+typedef UINT8 tBTM_SYNC_STATUS;
+
+/* Direction of sync (used by BTM_SyncStack) */
+#define BTM_SW_BB_TO_MM 0
+#define BTM_SW_TO_BB 1 /* Switch back to baseband stack (from either MM or BTC host) */
+#define BTM_SW_RESYNC 2
+#define BTM_SW_BB_TO_BTC 3 /* Switch from baseband stack to Bluetooth Controller Host stack */
+#define BTM_SW_MM_TO_BB 4
+#define BTM_SW_BTC_TO_BB 5
+typedef UINT8 tBTM_SW_DIR;
+
+/* Stack synchronization events (returned by tBTM_SYNC_STACK_CBACK callback) */
+#define BTM_SYNC_CPLT_EVT 0
+#define BTM_SYNC_BTA_EVT 1
+#define BTM_RESYNC_CPLT_EVT 2
+#define BTM_UIPC_OPENED_EVT 3
+#define BTM_UIPC_CLOSED_EVT 4
+typedef UINT8 tBTM_SYNC_STACK_EVT;
+
+/* Synchronization info from BTA/application that will be sent when calling BTE sync request functions */
+typedef struct
+{
+ tBTM_SW_DIR dir;
+ UINT16 lcid[BTM_SYNC_INFO_NUM_STR];
+ UINT8 avdt_handle[BTM_SYNC_INFO_NUM_STR];
+} tBTM_SYNC_INFO;
+
+/* Stack synchonization callback function
+** Parameters are
+** event: stack synchronization event
+** status: BTM_SUCCESS if event was successful
+*/
+typedef void (*tBTM_SYNC_STACK_CBACK)(tBTM_SYNC_STACK_EVT event, tBTM_SYNC_STATUS status);
+
+
+/* Sync complete callback function. Called by bte layers after synchronization is complete
+** so that BTM_SYNC can procede with the next step for switching stack to MM
+**
+** Parameters are
+** status: BTM_SUCCESS if synchronization was successful
+*/
+typedef void (*tBTM_SYNC_CPLT_CBACK)(tBTM_STATUS status);
+
+
+
+/* IPC event callback function. Called by BTM when an IPC event is received.
+** These events are currently sent to DM through the callback function.
+**
+** Parameters are
+** status: BTM_SUCCESS if synchronization was successful
+** p_data: Actual message in the IPC
+*/
+typedef void (tBTM_IPC_EVT_CBACK)(tBTM_STATUS status, BT_HDR *p_data);
+
+/* MIP evnets, callbacks */
+enum
+{
+ BTM_MIP_MODE_CHG_EVT,
+ BTM_MIP_DISCONNECT_EVT,
+ BTM_MIP_PKTS_COMPL_EVT,
+ BTM_MIP_RXDATA_EVT
+};
+typedef UINT8 tBTM_MIP_EVT;
+
+typedef struct
+{
+ tBTM_MIP_EVT event;
+ BD_ADDR bd_addr;
+ UINT16 mip_id;
+} tBTM_MIP_MODE_CHANGE;
+
+typedef struct
+{
+ tBTM_MIP_EVT event;
+ UINT16 mip_id;
+ UINT8 disc_reason;
+} tBTM_MIP_CONN_TIMEOUT;
+
+#define BTM_MIP_MAX_RX_LEN 17
+
+typedef struct
+{
+ tBTM_MIP_EVT event;
+ UINT16 mip_id;
+ UINT8 rx_len;
+ UINT8 rx_data[BTM_MIP_MAX_RX_LEN];
+} tBTM_MIP_RXDATA;
+
+typedef struct
+{
+ tBTM_MIP_EVT event;
+ BD_ADDR bd_addr;
+ UINT8 data[11]; /* data[0] shows Vender-specific device type */
+} tBTM_MIP_EIR_HANDSHAKE;
+
+typedef struct
+{
+ tBTM_MIP_EVT event;
+ UINT16 num_sent; /* Number of packets completed at the controller */
+} tBTM_MIP_PKTS_COMPL;
+
+typedef union
+{
+ tBTM_MIP_EVT event;
+ tBTM_MIP_MODE_CHANGE mod_chg;
+ tBTM_MIP_CONN_TIMEOUT conn_tmo;
+ tBTM_MIP_EIR_HANDSHAKE eir;
+ tBTM_MIP_PKTS_COMPL completed;
+ tBTM_MIP_RXDATA rxdata;
+} tBTM_MIP_EVENT_DATA;
+
+/* MIP event callback function */
+typedef void (tBTM_MIP_EVENTS_CB) (tBTM_MIP_EVT event, tBTM_MIP_EVENT_DATA data);
+
+/* MIP Device query callback function */
+typedef BOOLEAN (tBTM_MIP_QUERY_CB) (BD_ADDR dev_addr, UINT8 *p_mode, LINK_KEY link_key);
+
+/*****************************************************************************
+** EXTERNAL FUNCTION DECLARATIONS
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************
+** DEVICE CONTROL and COMMON FUNCTIONS
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function BTM_SetAfhChannels
+**
+** Description This function is called to disable channels
+**
+** Returns status
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_SetAfhChannels (UINT8 first, UINT8 last);
+
+/*******************************************************************************
+**
+** Function BTM_SetAfhChannelAssessment
+**
+** Description This function is called to set the channel assessment mode on or off
+**
+** Returns status
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_SetAfhChannelAssessment (BOOLEAN enable_or_disable);
+
+/*******************************************************************************
+**
+** Function BTM_DeviceReset
+**
+** Description This function is called to reset the controller.The Callback function
+** if provided is called when startup of the device has
+** completed.
+**
+** Returns void
+**
+*******************************************************************************/
+ BTM_API extern void BTM_DeviceReset (tBTM_CMPL_CB *p_cb);
+
+
+/*******************************************************************************
+**
+** Function BTM_IsDeviceUp
+**
+** Description This function is called to check if the device is up.
+**
+** Returns TRUE if device is up, else FALSE
+**
+*******************************************************************************/
+ BTM_API extern BOOLEAN BTM_IsDeviceUp (void);
+
+
+/*******************************************************************************
+**
+** Function BTM_SetLocalDeviceName
+**
+** Description This function is called to set the local device name.
+**
+** Returns BTM_CMD_STARTED if successful, otherwise an error
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_SetLocalDeviceName (char *p_name);
+
+/*******************************************************************************
+**
+** Function BTM_SetDeviceClass
+**
+** Description This function is called to set the local device class
+**
+** Returns BTM_SUCCESS if successful, otherwise an error
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_SetDeviceClass (DEV_CLASS dev_class);
+
+
+/*******************************************************************************
+**
+** Function BTM_ReadLocalDeviceName
+**
+** Description This function is called to read the local device name.
+**
+** Returns status of the operation
+** If success, BTM_SUCCESS is returned and p_name points stored
+** local device name
+** If BTM doesn't store local device name, BTM_NO_RESOURCES is
+** is returned and p_name is set to NULL
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_ReadLocalDeviceName (char **p_name);
+
+/*******************************************************************************
+**
+** Function BTM_ReadLocalDeviceNameFromController
+**
+** Description Get local device name from controller. Do not use cached
+** name (used to get chip-id prior to btm reset complete).
+**
+** Returns BTM_CMD_STARTED if successful, otherwise an error
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_ReadLocalDeviceNameFromController (tBTM_CMPL_CB *p_rln_cmpl_cback);
+
+/*******************************************************************************
+**
+** Function BTM_ReadLocalVersion
+**
+** Description This function is called to read the local device version
+**
+** Returns BTM_SUCCESS if successful, otherwise an error
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_ReadLocalVersion (tBTM_VERSION_INFO *p_vers);
+
+
+/*******************************************************************************
+**
+** Function BTM_ReadLocalDeviceAddr
+**
+** Description This function is called to read the local device address
+**
+** Returns BTM_SUCCESS
+** Callback returns the local device address
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_ReadLocalDeviceAddr (tBTM_CMPL_CB *p_cb);
+
+
+/*******************************************************************************
+**
+** Function BTM_GetLocalDeviceAddr
+**
+** Description This function is called to read the local device address
+**
+** Returns void
+** the local device address is copied into bd_addr
+**
+*******************************************************************************/
+ BTM_API extern void BTM_GetLocalDeviceAddr (BD_ADDR bd_addr);
+
+
+/*******************************************************************************
+**
+** Function BTM_ReadDeviceClass
+**
+** Description This function is called to read the local device class
+**
+** Returns pointer to the device class
+**
+*******************************************************************************/
+ BTM_API extern UINT8 *BTM_ReadDeviceClass (void);
+
+
+/*******************************************************************************
+**
+** Function BTM_ReadLocalFeatures
+**
+** Description This function is called to read the local features
+**
+** Returns pointer to the local features string
+**
+*******************************************************************************/
+ BTM_API extern UINT8 *BTM_ReadLocalFeatures (void);
+
+/*******************************************************************************
+**
+** Function BTM_ReadBrcmFeatures
+**
+** Description This function is called to read the Broadcom specific features
+**
+** Returns pointer to the Broadcom features string
+**
+*******************************************************************************/
+ BTM_API extern UINT8 *BTM_ReadBrcmFeatures (void);
+
+/*******************************************************************************
+**
+** Function BTM_RegisterForDeviceStatusNotif
+**
+** Description This function is called to register for device status
+** change notifications.
+**
+** Returns pointer to previous caller's callback function or NULL if first
+** registration.
+**
+*******************************************************************************/
+ BTM_API extern tBTM_DEV_STATUS_CB *BTM_RegisterForDeviceStatusNotif (tBTM_DEV_STATUS_CB *p_cb);
+
+
+/*******************************************************************************
+**
+** Function BTM_RegisterForVSEvents
+**
+** Description This function is called to register/deregister for vendor
+** specific HCI events.
+**
+** If is_register=TRUE, then the function will be registered;
+** if is_register=FALSE, then the function will be deregistered.
+**
+** Returns BTM_SUCCESS if successful,
+** BTM_BUSY if maximum number of callbacks have already been
+** registered.
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_RegisterForVSEvents (tBTM_VS_EVT_CB *p_cb, BOOLEAN is_register);
+
+
+/*******************************************************************************
+**
+** Function BTM_ContinueReset
+**
+** Description Instructs stack to continue its stack initialization after
+** an application has completed any vender specific commands
+** sent to the controller.
+**
+** Note: This function is only called if an application
+** initialization function has been inserted in the reset
+** sequence. (BTM_APP_DEV_INIT is defined with a function).
+**
+** Returns void
+**
+*******************************************************************************/
+ BTM_API extern void BTM_ContinueReset (void);
+
+
+/*******************************************************************************
+**
+** Function BTM_VendorSpecificCommand
+**
+** Description Send a vendor specific HCI command to the controller.
+**
+** Returns
+** BTM_SUCCESS Command sent. Does not expect command complete
+** event. (command cmpl callback param is NULL)
+** BTM_CMD_STARTED Command sent. Waiting for command cmpl event.
+** BTM_BUSY Command not sent. Waiting for cmd cmpl event for
+** prior command.
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_VendorSpecificCommand(UINT16 opcode,
+ UINT8 param_len,
+ UINT8 *p_param_buf,
+ tBTM_VSC_CMPL_CB *p_cb);
+
+
+/*******************************************************************************
+**
+** Function BTM_AllocateSCN
+**
+** Description Look through the Server Channel Numbers for a free one to be
+** used with an RFCOMM connection.
+**
+** Returns Allocated SCN number or 0 if none.
+**
+*******************************************************************************/
+ BTM_API extern UINT8 BTM_AllocateSCN(void);
+
+// btla-specific ++
+/*******************************************************************************
+**
+** Function BTM_TryAllocateSCN
+**
+** Description Try to allocate a fixed server channel
+**
+** Returns Returns TRUE if server channel was available
+**
+*******************************************************************************/
+BTM_API extern BOOLEAN BTM_TryAllocateSCN(UINT8 scn);
+// btla-specific --
+
+
+/*******************************************************************************
+**
+** Function BTM_FreeSCN
+**
+** Description Free the specified SCN.
+**
+** Returns TRUE if successful, FALSE if SCN is not in use or invalid
+**
+*******************************************************************************/
+ BTM_API extern BOOLEAN BTM_FreeSCN(UINT8 scn);
+
+
+/*******************************************************************************
+**
+** Function BTM_SetTraceLevel
+**
+** Description This function sets the trace level for BTM. If called with
+** a value of 0xFF, it simply returns the current trace level.
+**
+** Returns The new or current trace level
+**
+*******************************************************************************/
+ BTM_API extern UINT8 BTM_SetTraceLevel (UINT8 new_level);
+
+
+/*******************************************************************************
+**
+** Function BTM_WritePageTimeout
+**
+** Description Send HCI Wite Page Timeout.
+**
+** Returns
+** BTM_SUCCESS Command sent.
+** BTM_NO_RESOURCES If out of resources to send the command.
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_WritePageTimeout(UINT16 timeout);
+
+/*******************************************************************************
+**
+** Function BTM_WriteVoiceSettings
+**
+** Description Send HCI Write Voice Settings command.
+** See hcidefs.h for settings bitmask values.
+**
+** Returns
+** BTM_SUCCESS Command sent.
+** BTM_NO_RESOURCES If out of resources to send the command.
+**
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_WriteVoiceSettings(UINT16 settings);
+
+/*******************************************************************************
+**
+** Function BTM_EnableTestMode
+**
+** Description Send HCI the enable device under test command.
+**
+** Note: Controller can only be taken out of this mode by
+** resetting the controller.
+**
+** Returns
+** BTM_SUCCESS Command sent.
+** BTM_NO_RESOURCES If out of resources to send the command.
+**
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_EnableTestMode(void);
+
+
+/*****************************************************************************
+** DEVICE DISCOVERY FUNCTIONS - Inquiry, Remote Name, Discovery, Class of Device
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function BTM_SetDiscoverability
+**
+** Description This function is called to set the device into or out of
+** discoverable mode. Discoverable mode means inquiry
+** scans are enabled. If a value of '0' is entered for window or
+** interval, the default values are used.
+**
+** Returns BTM_SUCCESS if successful
+** BTM_BUSY if a setting of the filter is already in progress
+** BTM_NO_RESOURCES if couldn't get a memory pool buffer
+** BTM_ILLEGAL_VALUE if a bad parameter was detected
+** BTM_WRONG_MODE if the device is not up.
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_SetDiscoverability (UINT16 inq_mode, UINT16 window,
+ UINT16 interval);
+
+
+/*******************************************************************************
+**
+** Function BTM_ReadDiscoverability
+**
+** Description This function is called to read the current discoverability
+** mode of the device.
+**
+** Output Params: p_window - current inquiry scan duration
+** p_interval - current inquiry scan interval
+**
+** Returns BTM_NON_DISCOVERABLE, BTM_LIMITED_DISCOVERABLE, or
+** BTM_GENERAL_DISCOVERABLE
+**
+*******************************************************************************/
+ BTM_API extern UINT16 BTM_ReadDiscoverability (UINT16 *p_window,
+ UINT16 *p_interval);
+
+
+/*******************************************************************************
+**
+** Function BTM_SetPeriodicInquiryMode
+**
+** Description This function is called to set the device periodic inquiry mode.
+** If the duration is zero, the periodic inquiry mode is cancelled.
+**
+** Parameters: p_inqparms - pointer to the inquiry information
+** mode - GENERAL or LIMITED inquiry
+** duration - length in 1.28 sec intervals (If '0', the inquiry is CANCELLED)
+** max_resps - maximum amount of devices to search for before ending the inquiry
+** filter_cond_type - BTM_CLR_INQUIRY_FILTER, BTM_FILTER_COND_DEVICE_CLASS, or
+** BTM_FILTER_COND_BD_ADDR
+** filter_cond - value for the filter (based on filter_cond_type)
+**
+** max_delay - maximum amount of time between successive inquiries
+** min_delay - minimum amount of time between successive inquiries
+** p_results_cb - callback returning pointer to results (tBTM_INQ_RESULTS)
+**
+** Returns BTM_CMD_STARTED if successfully started
+** BTM_ILLEGAL_VALUE if a bad parameter is detected
+** BTM_NO_RESOURCES if could not allocate a message buffer
+** BTM_SUCCESS - if cancelling the periodic inquiry
+** BTM_BUSY - if an inquiry is already active
+** BTM_WRONG_MODE if the device is not up.
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_SetPeriodicInquiryMode (tBTM_INQ_PARMS *p_inqparms,
+ UINT16 max_delay, UINT16 min_delay,
+ tBTM_INQ_RESULTS_CB *p_results_cb);
+
+
+/*******************************************************************************
+**
+** Function BTM_StartInquiry
+**
+** Description This function is called to start an inquiry.
+**
+** Parameters: p_inqparms - pointer to the inquiry information
+** mode - GENERAL or LIMITED inquiry
+** duration - length in 1.28 sec intervals (If '0', the inquiry is CANCELLED)
+** max_resps - maximum amount of devices to search for before ending the inquiry
+** filter_cond_type - BTM_CLR_INQUIRY_FILTER, BTM_FILTER_COND_DEVICE_CLASS, or
+** BTM_FILTER_COND_BD_ADDR
+** filter_cond - value for the filter (based on filter_cond_type)
+**
+** p_results_cb - Pointer to the callback routine which gets called
+** upon receipt of an inquiry result. If this field is
+** NULL, the application is not notified.
+**
+** p_cmpl_cb - Pointer to the callback routine which gets called
+** upon completion. If this field is NULL, the
+** application is not notified when completed.
+** Returns tBTM_STATUS
+** BTM_CMD_STARTED if successfully initiated
+** BTM_BUSY if already in progress
+** BTM_ILLEGAL_VALUE if parameter(s) are out of range
+** BTM_NO_RESOURCES if could not allocate resources to start the command
+** BTM_WRONG_MODE if the device is not up.
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_StartInquiry (tBTM_INQ_PARMS *p_inqparms,
+ tBTM_INQ_RESULTS_CB *p_results_cb,
+ tBTM_CMPL_CB *p_cmpl_cb);
+
+
+/*******************************************************************************
+**
+** Function BTM_IsInquiryActive
+**
+** Description This function returns a bit mask of the current inquiry state
+**
+** Returns BTM_INQUIRY_INACTIVE if inactive (0)
+** BTM_LIMITED_INQUIRY_ACTIVE if a limted inquiry is active
+** BTM_GENERAL_INQUIRY_ACTIVE if a general inquiry is active
+** BTM_PERIODIC_INQUIRY_ACTIVE if a periodic inquiry is active
+**
+*******************************************************************************/
+ BTM_API extern UINT16 BTM_IsInquiryActive (void);
+
+
+/*******************************************************************************
+**
+** Function BTM_CancelInquiry
+**
+** Description This function cancels an inquiry if active
+**
+** Returns BTM_SUCCESS if successful
+** BTM_NO_RESOURCES if could not allocate a message buffer
+** BTM_WRONG_MODE if the device is not up.
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_CancelInquiry(void);
+
+
+/*******************************************************************************
+**
+** Function BTM_CancelPeriodicInquiry
+**
+** Description This function cancels a periodic inquiry
+**
+** Returns
+** BTM_NO_RESOURCES if could not allocate a message buffer
+** BTM_SUCCESS - if cancelling the periodic inquiry
+** BTM_WRONG_MODE if the device is not up.
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_CancelPeriodicInquiry(void);
+
+
+/*******************************************************************************
+**
+** Function BTM_SetInquiryFilterCallback
+**
+** Description Host can register to be asked whenever an inquiry result
+** is received. If host does not like the device no name
+** request is issued for the device
+**
+** Returns void
+**
+*******************************************************************************/
+ BTM_API extern void BTM_SetInquiryFilterCallback(tBTM_FILTER_CB *p_callback);
+
+
+/*******************************************************************************
+**
+** Function BTM_SetConnectability
+**
+** Description This function is called to set the device into or out of
+** connectable mode. Discoverable mode means page scans enabled.
+**
+** Returns BTM_SUCCESS if successful
+** BTM_ILLEGAL_VALUE if a bad parameter is detected
+** BTM_NO_RESOURCES if could not allocate a message buffer
+** BTM_WRONG_MODE if the device is not up.
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_SetConnectability (UINT16 page_mode, UINT16 window,
+ UINT16 interval);
+
+
+/*******************************************************************************
+**
+** Function BTM_ReadConnectability
+**
+** Description This function is called to read the current discoverability
+** mode of the device.
+** Output Params p_window - current page scan duration
+** p_interval - current time between page scans
+**
+** Returns BTM_NON_CONNECTABLE or BTM_CONNECTABLE
+**
+*******************************************************************************/
+ BTM_API extern UINT16 BTM_ReadConnectability (UINT16 *p_window, UINT16 *p_interval);
+
+
+/*******************************************************************************
+**
+** Function BTM_SetInquiryMode
+**
+** Description This function is called to set standard, with RSSI
+** mode or extended of the inquiry for local device.
+**
+** Input Params: BTM_INQ_RESULT_STANDARD, BTM_INQ_RESULT_WITH_RSSI or
+** BTM_INQ_RESULT_EXTENDED
+**
+** Returns BTM_SUCCESS if successful
+** BTM_NO_RESOURCES if couldn't get a memory pool buffer
+** BTM_ILLEGAL_VALUE if a bad parameter was detected
+** BTM_WRONG_MODE if the device is not up.
+**
+*******************************************************************************/
+ BT_API extern tBTM_STATUS BTM_SetInquiryMode (UINT8 mode);
+
+/*******************************************************************************
+**
+** Function BTM_SetInquiryScanType
+**
+** Description This function is called to set the iquiry scan-type to
+** standard or interlaced.
+**
+** Input Params: BTM_SCAN_TYPE_STANDARD or BTM_SCAN_TYPE_INTERLACED
+**
+** Returns BTM_SUCCESS if successful
+** BTM_MODE_UNSUPPORTED if not a 1.2 device
+** BTM_WRONG_MODE if the device is not up.
+**
+*******************************************************************************/
+ BT_API extern tBTM_STATUS BTM_SetInquiryScanType (UINT16 scan_type);
+
+/*******************************************************************************
+**
+** Function BTM_SetPageScanType
+**
+** Description This function is called to set the page scan-type to
+** standard or interlaced.
+**
+** Input Params: BTM_SCAN_TYPE_STANDARD or BTM_SCAN_TYPE_INTERLACED
+**
+** Returns BTM_SUCCESS if successful
+** BTM_MODE_UNSUPPORTED if not a 1.2 device
+** BTM_WRONG_MODE if the device is not up.
+**
+*******************************************************************************/
+
+ BT_API extern tBTM_STATUS BTM_SetPageScanType (UINT16 scan_type);
+
+/*******************************************************************************
+**
+** Function BTM_ReadRemoteDeviceName
+**
+** Description This function initiates a remote device HCI command to the
+** controller and calls the callback when the process has completed.
+**
+** Input Params: remote_bda - device address of name to retrieve
+** p_cb - callback function called when BTM_CMD_STARTED
+** is returned.
+** A pointer to tBTM_REMOTE_DEV_NAME is passed to the
+** callback.
+**
+** Returns
+** BTM_CMD_STARTED is returned if the request was successfully sent
+** to HCI.
+** BTM_BUSY if already in progress
+** BTM_UNKNOWN_ADDR if device address is bad
+** BTM_NO_RESOURCES if could not allocate resources to start the command
+** BTM_WRONG_MODE if the device is not up.
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_ReadRemoteDeviceName (BD_ADDR remote_bda,
+ tBTM_CMPL_CB *p_cb);
+
+
+/*******************************************************************************
+**
+** Function BTM_CancelRemoteDeviceName
+**
+** Description This function initiates the cancel request for the specified
+** remote device.
+**
+** Input Params: None
+**
+** Returns
+** BTM_CMD_STARTED is returned if the request was successfully sent
+** to HCI.
+** BTM_NO_RESOURCES if could not allocate resources to start the command
+** BTM_WRONG_MODE if there is not an active remote name request.
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_CancelRemoteDeviceName (void);
+
+/*******************************************************************************
+**
+** Function BTM_ReadRemoteVersion
+**
+** Description This function is called to read a remote device's version
+**
+** Returns BTM_SUCCESS if successful, otherwise an error
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_ReadRemoteVersion (BD_ADDR addr,
+ UINT8 *lmp_version,
+ UINT16 *manufacturer,
+ UINT16 *lmp_sub_version);
+
+/*******************************************************************************
+**
+** Function BTM_ReadRemoteFeatures
+**
+** Description This function is called to read a remote device's features
+**
+** Returns pointer to the features string
+**
+*******************************************************************************/
+ BTM_API extern UINT8 *BTM_ReadRemoteFeatures (BD_ADDR addr);
+
+/*******************************************************************************
+**
+** Function BTM_InqFirstResult
+**
+** Description This function looks through the inquiry database for the first
+** used entrysince the LAST inquiry. This is used in conjunction
+** with BTM_InqNext by applications as a way to walk through the
+** inquiry results database.
+**
+** Returns pointer to first in-use entry, or NULL if DB is empty
+**
+*******************************************************************************/
+ BTM_API extern tBTM_INQ_INFO *BTM_InqFirstResult (void);
+
+
+/*******************************************************************************
+**
+** Function BTM_InqNextResult
+**
+** Description This function looks through the inquiry database for the next
+** used entrysince the LAST inquiry. If the input parameter is NULL,
+** the first entry is returned.
+**
+** Returns pointer to next in-use entry, or NULL if no more found.
+**
+*******************************************************************************/
+ BTM_API extern tBTM_INQ_INFO *BTM_InqNextResult (tBTM_INQ_INFO *p_cur);
+
+
+/*******************************************************************************
+**
+** Function BTM_InqDbRead
+**
+** Description This function looks through the inquiry database for a match
+** based on Bluetooth Device Address. This is the application's
+** interface to get the inquiry details of a specific BD address.
+**
+** Returns pointer to entry, or NULL if not found
+**
+*******************************************************************************/
+ BTM_API extern tBTM_INQ_INFO *BTM_InqDbRead (BD_ADDR p_bda);
+
+
+/*******************************************************************************
+**
+** Function BTM_InqDbFirst
+**
+** Description This function looks through the inquiry database for the first
+** used entry, and returns that. This is used in conjunction with
+** BTM_InqDbNext by applications as a way to walk through the
+** inquiry database.
+**
+** Returns pointer to first in-use entry, or NULL if DB is empty
+**
+*******************************************************************************/
+ BTM_API extern tBTM_INQ_INFO *BTM_InqDbFirst (void);
+
+
+/*******************************************************************************
+**
+** Function BTM_InqDbNext
+**
+** Description This function looks through the inquiry database for the next
+** used entry, and returns that. If the input parameter is NULL,
+** the first entry is returned.
+**
+** Returns pointer to next in-use entry, or NULL if no more found.
+**
+*******************************************************************************/
+ BTM_API extern tBTM_INQ_INFO *BTM_InqDbNext (tBTM_INQ_INFO *p_cur);
+
+
+/*******************************************************************************
+**
+** Function BTM_ClearInqDb
+**
+** Description This function is called to clear out a device or all devices
+** from the inquiry database.
+**
+** Parameter p_bda - (input) BD_ADDR -> Address of device to clear
+** (NULL clears all entries)
+**
+** Returns BTM_BUSY if an inquiry, get remote name, or event filter
+** is active, otherwise BTM_SUCCESS
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_ClearInqDb (BD_ADDR p_bda);
+
+
+/*******************************************************************************
+**
+** Function BTM_ReadNumInqDbEntries
+**
+** Returns This function returns the number of entries in the inquiry database.
+**
+*******************************************************************************/
+ BTM_API extern UINT8 BTM_ReadNumInqDbEntries (void);
+
+
+/*******************************************************************************
+**
+** Function BTM_InquiryRegisterForChanges
+**
+** Description This function is called to register a callback for when the
+** inquiry database changes, i.e. new entry or entry deleted.
+**
+** Returns BTM_SUCCESS if successful, otherwise error code
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_InquiryRegisterForChanges (tBTM_INQ_DB_CHANGE_CB *p_cb);
+
+/*******************************************************************************
+**
+** Function BTM_ReadInquiryRspTxPower
+**
+** Description This command will read the inquiry Transmit Power level used
+** to transmit the FHS and EIR data packets.
+** This can be used directly in the Tx Power Level EIR data type.
+**
+** Returns BTM_SUCCESS if successful
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_ReadInquiryRspTxPower (tBTM_CMPL_CB *p_cb);
+
+/*******************************************************************************
+**
+** Function BTM_WriteInquiryTxPower
+**
+** Description This command is used to write the inquiry transmit power level
+** used to transmit the inquiry (ID) data packets. The Controller
+** should use the supported TX power level closest to the Tx_Power
+** parameter.
+**
+** Returns BTM_SUCCESS if successful
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_WriteInquiryTxPower (INT8 tx_power);
+
+/*******************************************************************************
+**
+** Function BTM_StartDiscovery
+**
+** Description This function is called by an application (or profile)
+** when it wants to trigger an service discovery using the
+** BTM's discovery database.
+**
+** Returns tBTM_STATUS
+** BTM_CMD_STARTED if the discovery was initiated
+** BTM_BUSY if one is already in progress
+** BTM_UNKNOWN_ADDR if no addresses are in the INQ DB
+** BTM_ERR_PROCESSING if err initiating the command
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_StartDiscovery (tBTM_CMPL_CB *p_cmpl_cb,
+ BD_ADDR_PTR p_rem_addr);
+
+
+/*******************************************************************************
+**
+** Function BTM_FindAttribute
+**
+** Description This function is called by an application (or profile)
+** when it wants to see if an attribute exists in the BTM
+** discovery database.
+**
+** Returns Pointer to matching record, or NULL
+**
+*******************************************************************************/
+ BTM_API extern tSDP_DISC_REC *BTM_FindAttribute (UINT16 attr_id,
+ tSDP_DISC_REC *p_start_rec);
+
+
+/*******************************************************************************
+**
+** Function BTM_FindService
+**
+** Description This function is called by an application (or profile)
+** when it wants to see if a service exists in the BTM
+** discovery database.
+**
+** Returns Pointer to matching record, or NULL
+**
+*******************************************************************************/
+ BTM_API extern tSDP_DISC_REC *BTM_FindService (UINT16 service_uuid,
+ tSDP_DISC_REC *p_start_rec);
+
+
+/*******************************************************************************
+**
+** Function BTM_SetDiscoveryParams
+**
+** Description This function is called to set the BTM default discovery parameters.
+** These UUID and attribute filters are used during the call to
+** BTM_StartDiscovery.
+**
+** Returns void
+**
+*******************************************************************************/
+ BTM_API extern void BTM_SetDiscoveryParams (UINT16 num_uuid, tSDP_UUID *p_uuid_list,
+ UINT16 num_attr, UINT16 *p_attr_list);
+
+
+/*****************************************************************************
+** ACL CHANNEL MANAGEMENT FUNCTIONS
+*****************************************************************************/
+/*******************************************************************************
+**
+** Function BTM_SetLinkPolicy
+**
+** Description Create and send HCI "Write Policy Set" command
+**
+** Returns BTM_CMD_STARTED if successfully initiated, otherwise error
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_SetLinkPolicy (BD_ADDR remote_bda,
+ UINT16 *settings);
+
+
+/*******************************************************************************
+**
+** Function BTM_ReadLinkPolicy
+**
+** Description This function is called to read the link policy settings.
+** The address of link policy results are returned in the callback.
+** (tBTM_LNK_POLICY_RESULTS)
+**
+** Returns BTM_CMD_STARTED if successfully initiated, otherwise error
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_ReadLinkPolicy (BD_ADDR remote_bda,
+ tBTM_CMPL_CB *p_cb);
+
+
+/*******************************************************************************
+**
+** Function BTM_SetDefaultLinkPolicy
+**
+** Description Set the default value for HCI "Write Policy Set" command
+** to use when an ACL link is created.
+**
+** Returns void
+**
+*******************************************************************************/
+ BTM_API extern void BTM_SetDefaultLinkPolicy (UINT16 settings);
+
+
+/*******************************************************************************
+**
+** Function BTM_SetDefaultLinkSuperTout
+**
+** Description Set the default value for HCI "Write Link Supervision Timeout"
+** command to use when an ACL link is created.
+**
+** Returns void
+**
+*******************************************************************************/
+ BTM_API extern void BTM_SetDefaultLinkSuperTout (UINT16 timeout);
+
+
+/*******************************************************************************
+**
+** Function BTM_SetLinkSuperTout
+**
+** Description Create and send HCI "Write Link Supervision Timeout" command
+**
+** Returns BTM_CMD_STARTED if successfully initiated, otherwise error
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_SetLinkSuperTout (BD_ADDR remote_bda,
+ UINT16 timeout);
+
+/*******************************************************************************
+**
+** Function BTM_RegForLstoEvt
+**
+** Description register for the HCI "Link Supervision Timeout Change" event
+**
+** Returns void
+**
+*******************************************************************************/
+ BTM_API extern void BTM_RegForLstoEvt (tBTM_LSTO_CBACK *p_cback);
+
+
+/* These next APIs are available if the power manager is not compiled in */
+#if BTM_PWR_MGR_INCLUDED == FALSE
+/*******************************************************************************
+**
+** Function BTM_SetHoldMode
+**
+** Description This function is called to set a connection into hold mode.
+** A check is made if the connection is in sniff or park mode,
+** and if yes, the hold mode is ignored.
+**
+** Returns BTM_CMD_STARTED if successfully initiated, otherwise error
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_SetHoldMode (BD_ADDR remote_bda, UINT16 min_interval,
+ UINT16 max_interval);
+
+
+/*******************************************************************************
+**
+** Function BTM_SetSniffMode
+**
+** Description This function is called to set a connection into sniff mode.
+** A check is made if the connection is already in sniff or park
+** mode, and if yes, the sniff mode is ignored.
+**
+** Returns BTM_CMD_STARTED if successfully initiated, otherwise error
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_SetSniffMode (BD_ADDR remote_bda, UINT16 min_period,
+ UINT16 max_period, UINT16 attempt,
+ UINT16 timeout);
+
+
+/*******************************************************************************
+**
+** Function BTM_CancelSniffMode
+**
+** Description This function is called to put a connection out of sniff mode.
+** A check is made if the connection is already in sniff mode,
+** and if not, the cancel sniff mode is ignored.
+**
+** Returns BTM_CMD_STARTED if successfully initiated, otherwise error
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_CancelSniffMode (BD_ADDR remote_bda);
+
+
+/*******************************************************************************
+**
+** Function BTM_SetParkMode
+**
+** Description This function is called to set a connection into park mode.
+** A check is made if the connection is already in sniff or park
+** mode, and if yes, the park mode is ignored.
+**
+** Returns BTM_CMD_STARTED if successfully initiated, otherwise error
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_SetParkMode (BD_ADDR remote_bda,
+ UINT16 beacon_min_period,
+ UINT16 beacon_max_period);
+
+
+/*******************************************************************************
+**
+** Function BTM_CancelParkMode
+**
+** Description This function is called to put a connection out of park mode.
+** A check is made if the connection is already in park mode,
+** and if not, the cancel sniff mode is ignored.
+**
+** Returns BTM_CMD_STARTED if successfully initiated, otherwise error
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_CancelParkMode (BD_ADDR remote_bda);
+
+
+/*******************************************************************************
+**
+** Function BTM_ReadAclMode
+**
+** Description This returns the current mode for a specific
+** ACL connection.
+**
+** Input Param remote_bda - device address of desired ACL connection
+**
+** Output Param p_mode - address where the current mode is copied into.
+** BTM_ACL_MODE_NORMAL
+** BTM_ACL_MODE_HOLD
+** BTM_ACL_MODE_SNIFF
+** BTM_ACL_MODE_PARK
+** (valid only if return code is BTM_SUCCESS)
+**
+** Returns BTM_SUCCESS if successful,
+** BTM_UNKNOWN_ADDR if bd addr is not active or bad
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_ReadAclMode (BD_ADDR remote_bda, UINT8 *p_mode);
+
+#endif /* if BTM_PWR_MGR_INCLUDED == FALSE */
+
+
+/*******************************************************************************
+**
+** Function BTM_SetPacketTypes
+**
+** Description This function is set the packet types used for a specific
+** ACL connection,
+**
+** Returns BTM_CMD_STARTED if successfully initiated, otherwise error
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_SetPacketTypes (BD_ADDR remote_bda, UINT16 pkt_types);
+
+
+/*******************************************************************************
+**
+** Function BTM_ReadPacketTypes
+**
+** Description This function is set the packet types used for the specified
+** ACL connection,
+**
+** Returns packet types supported for the connection, or 0 if no BD address
+**
+*******************************************************************************/
+ BTM_API extern UINT16 BTM_ReadPacketTypes (BD_ADDR remote_bda);
+
+
+/*******************************************************************************
+**
+** Function BTM_IsAclConnectionUp
+**
+** Description This function is called to check if an ACL connection exists
+** to a specific remote BD Address.
+**
+** Returns TRUE if connection is up, else FALSE.
+**
+*******************************************************************************/
+ BTM_API extern BOOLEAN BTM_IsAclConnectionUp (BD_ADDR remote_bda);
+
+
+/*******************************************************************************
+**
+** Function BTM_GetRole
+**
+** Description This function is called to get the role of the local device
+** for the ACL connection with the specified remote device
+**
+** Returns BTM_SUCCESS if connection exists.
+** BTM_UNKNOWN_ADDR if no active link with bd addr specified
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_GetRole (BD_ADDR remote_bd_addr, UINT8 *p_role);
+
+
+
+/*******************************************************************************
+**
+** Function BTM_SwitchRole
+**
+** Description This function is called to switch role between master and
+** slave. If role is already set it will do nothing. If the
+** command was initiated, the callback function is called upon
+** completion.
+**
+** Returns BTM_SUCCESS if already in specified role.
+** BTM_CMD_STARTED if command issued to controller.
+** BTM_NO_RESOURCES if couldn't allocate memory to issue command
+** BTM_UNKNOWN_ADDR if no active link with bd addr specified
+** BTM_MODE_UNSUPPORTED if local device does not support role switching
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_SwitchRole (BD_ADDR remote_bd_addr,
+ UINT8 new_role,
+ tBTM_CMPL_CB *p_cb);
+
+/*******************************************************************************
+**
+** Function BTM_ChangeLinkKey
+**
+** Description This function is called to change the link key of the
+** connection.
+**
+** Returns BTM_CMD_STARTED if command issued to controller.
+** BTM_NO_RESOURCES if couldn't allocate memory to issue command
+** BTM_UNKNOWN_ADDR if no active link with bd addr specified
+** BTM_BUSY if the previous command is not completed
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_ChangeLinkKey (BD_ADDR remote_bd_addr,
+ tBTM_CMPL_CB *p_cb);
+
+/*******************************************************************************
+**
+** Function BTM_ReadRSSI
+**
+** Description This function is called to read the link policy settings.
+** The address of link policy results are returned in the callback.
+** (tBTM_RSSI_RESULTS)
+**
+** Returns BTM_CMD_STARTED if command issued to controller.
+** BTM_NO_RESOURCES if couldn't allocate memory to issue command
+** BTM_UNKNOWN_ADDR if no active link with bd addr specified
+** BTM_BUSY if command is already in progress
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_ReadRSSI (BD_ADDR remote_bda, tBTM_CMPL_CB *p_cb);
+
+
+/*******************************************************************************
+**
+** Function BTM_ReadTxPower
+**
+** Description This function is called to read the current connection
+** TX power of the connection. The TX power level results
+** are returned in the callback.
+** (tBTM_RSSI_RESULTS)
+**
+** Returns BTM_CMD_STARTED if command issued to controller.
+** BTM_NO_RESOURCES if couldn't allocate memory to issue command
+** BTM_UNKNOWN_ADDR if no active link with bd addr specified
+** BTM_BUSY if command is already in progress
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_ReadTxPower (BD_ADDR remote_bda, tBTM_CMPL_CB *p_cb);
+
+/*******************************************************************************
+**
+** Function BTM_ReadLinkQuality
+**
+** Description This function is called to read the link quality.
+** The value of the link quality is returned in the callback.
+** (tBTM_LINK_QUALITY_RESULTS)
+**
+** Returns BTM_CMD_STARTED if command issued to controller.
+** BTM_NO_RESOURCES if couldn't allocate memory to issue command
+** BTM_UNKNOWN_ADDR if no active link with bd addr specified
+** BTM_BUSY if command is already in progress
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_ReadLinkQuality (BD_ADDR remote_bda, tBTM_CMPL_CB *p_cb);
+
+/*******************************************************************************
+**
+** Function BTM_RegBusyLevelNotif
+**
+** Description This function is called to register a callback to receive
+** busy level change events.
+**
+** Returns BTM_SUCCESS if successfully registered, otherwise error
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_RegBusyLevelNotif (tBTM_BL_CHANGE_CB *p_cb, UINT8 *p_level,
+ tBTM_BL_EVENT_MASK evt_mask);
+
+/*******************************************************************************
+**
+** Function BTM_AclRegisterForChanges
+**
+** Description This function is called to register a callback to receive
+** ACL database change events, i.e. new connection or removed.
+**
+** Returns BTM_SUCCESS if successfully initiated, otherwise error
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_AclRegisterForChanges (tBTM_ACL_DB_CHANGE_CB *p_cb);
+
+/*******************************************************************************
+**
+** Function BTM_GetNumAclLinks
+**
+** Description This function is called to count the number of
+** ACL links that are active.
+**
+** Returns UINT16 Number of active ACL links
+**
+*******************************************************************************/
+ BTM_API extern UINT16 BTM_GetNumAclLinks (void);
+
+
+/*******************************************************************************
+**
+** Function BTM_ReadClockOffset
+**
+** Description This returns the clock offset for a specific
+** ACL connection.
+**
+** Returns clock-offset or 0 if unknown
+**
+*******************************************************************************/
+ BTM_API extern UINT16 BTM_ReadClockOffset (BD_ADDR remote_bda);
+
+
+/*******************************************************************************
+**
+** Function BTM_SetQoS
+**
+** Description This function is called to setup QoS
+**
+** Returns BTM_CMD_STARTED if successfully initiated, otherwise error
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_SetQoS(BD_ADDR bd, FLOW_SPEC *p_flow,
+ tBTM_CMPL_CB *p_cb);
+
+
+/*****************************************************************************
+** (e)SCO CHANNEL MANAGEMENT FUNCTIONS
+*****************************************************************************/
+/*******************************************************************************
+**
+** Function BTM_CreateSco
+**
+** Description This function is called to create an SCO connection. If the
+** "is_orig" flag is TRUE, the connection will be originated,
+** otherwise BTM will wait for the other side to connect.
+**
+** Returns BTM_UNKNOWN_ADDR if the ACL connection is not up
+** BTM_BUSY if another SCO being set up to
+** the same BD address
+** BTM_NO_RESOURCES if the max SCO limit has been reached
+** BTM_CMD_STARTED if the connection establishment is started.
+** In this case, "*p_sco_inx" is filled in
+** with the sco index used for the connection.
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_CreateSco (BD_ADDR remote_bda, BOOLEAN is_orig,
+ UINT16 pkt_types, UINT16 *p_sco_inx,
+ tBTM_SCO_CB *p_conn_cb,
+ tBTM_SCO_CB *p_disc_cb);
+
+
+/*******************************************************************************
+**
+** Function BTM_RemoveSco
+**
+** Description This function is called to remove a specific SCO connection.
+**
+** Returns BTM_CMD_STARTED if successfully initiated, otherwise error
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_RemoveSco (UINT16 sco_inx);
+
+
+/*******************************************************************************
+**
+** Function BTM_SetScoPacketTypes
+**
+** Description This function is called to set the packet types used for
+** a specific SCO connection,
+**
+** Parameters pkt_types - One or more of the following
+** BTM_SCO_PKT_TYPES_MASK_HV1
+** BTM_SCO_PKT_TYPES_MASK_HV2
+** BTM_SCO_PKT_TYPES_MASK_HV3
+** BTM_SCO_PKT_TYPES_MASK_EV3
+** BTM_SCO_PKT_TYPES_MASK_EV4
+** BTM_SCO_PKT_TYPES_MASK_EV5
+**
+** BTM_SCO_LINK_ALL_MASK - enables all supported types
+**
+** Returns BTM_CMD_STARTED if successfully initiated, otherwise error
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_SetScoPacketTypes (UINT16 sco_inx, UINT16 pkt_types);
+
+
+/*******************************************************************************
+**
+** Function BTM_ReadScoPacketTypes
+**
+** Description This function is read the packet types used for a specific
+** SCO connection.
+**
+** Returns One or more of the following (bitmask)
+** BTM_SCO_PKT_TYPES_MASK_HV1
+** BTM_SCO_PKT_TYPES_MASK_HV2
+** BTM_SCO_PKT_TYPES_MASK_HV3
+** BTM_SCO_PKT_TYPES_MASK_EV3
+** BTM_SCO_PKT_TYPES_MASK_EV4
+** BTM_SCO_PKT_TYPES_MASK_EV5
+**
+** Returns packet types supported for the connection
+**
+*******************************************************************************/
+ BTM_API extern UINT16 BTM_ReadScoPacketTypes (UINT16 sco_inx);
+
+
+/*******************************************************************************
+**
+** Function BTM_ReadDeviceScoPacketTypes
+**
+** Description This function is read the SCO packet types that
+** the device supports.
+**
+** Returns packet types supported by the device.
+**
+*******************************************************************************/
+ BTM_API extern UINT16 BTM_ReadDeviceScoPacketTypes (void);
+
+
+/*******************************************************************************
+**
+** Function BTM_ReadScoHandle
+**
+** Description This function is used to read the HCI handle used for a specific
+** SCO connection,
+**
+** Returns handle for the connection, or 0xFFFF if invalid SCO index.
+**
+*******************************************************************************/
+ BTM_API extern UINT16 BTM_ReadScoHandle (UINT16 sco_inx);
+
+
+/*******************************************************************************
+**
+** Function BTM_ReadScoBdAddr
+**
+** Description This function is read the remote BD Address for a specific
+** SCO connection,
+**
+** Returns pointer to BD address or NULL if not known
+**
+*******************************************************************************/
+ BTM_API extern UINT8 *BTM_ReadScoBdAddr (UINT16 sco_inx);
+
+
+/*******************************************************************************
+**
+** Function BTM_ReadScoDiscReason
+**
+** Description This function is returns the reason why an (e)SCO connection
+** has been removed. It contains the value until read, or until
+** another (e)SCO connection has disconnected.
+**
+** Returns HCI reason or BTM_INVALID_SCO_DISC_REASON if not set.
+**
+*******************************************************************************/
+ BTM_API extern UINT16 BTM_ReadScoDiscReason (void);
+
+
+/*******************************************************************************
+**
+** Function BTM_SetEScoMode
+**
+** Description This function sets up the negotiated parameters for SCO or
+** eSCO, and sets as the default mode used for calls to
+** BTM_CreateSco. It can be called only when there are no
+** active (e)SCO links.
+**
+** Returns BTM_SUCCESS if the successful.
+** BTM_BUSY if there are one or more active (e)SCO links.
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_SetEScoMode (tBTM_SCO_TYPE sco_mode,
+ tBTM_ESCO_PARAMS *p_parms);
+
+/*******************************************************************************
+**
+** Function BTM_SetWBSCodec
+**
+** Description This function sends command to the controller to setup
+** WBS codec for the upcoming eSCO connection.
+**
+** Returns BTM_SUCCESS.
+**
+**
+*******************************************************************************/
+BTM_API extern tBTM_STATUS BTM_SetWBSCodec (tBTM_SCO_CODEC_TYPE codec_type);
+
+/*******************************************************************************
+**
+** Function BTM_RegForEScoEvts
+**
+** Description This function registers a SCO event callback with the
+** specified instance. It should be used to received
+** connection indication events and change of link parameter
+** events.
+**
+** Returns BTM_SUCCESS if the successful.
+** BTM_ILLEGAL_VALUE if there is an illegal sco_inx
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_RegForEScoEvts (UINT16 sco_inx,
+ tBTM_ESCO_CBACK *p_esco_cback);
+
+/*******************************************************************************
+**
+** Function BTM_ReadEScoLinkParms
+**
+** Description This function returns the current eSCO link parameters for
+** the specified handle. This can be called anytime a connection
+** is active, but is typically called after receiving the SCO
+** opened callback.
+**
+**
+** Returns BTM_SUCCESS if returned data is valid connection.
+** BTM_ILLEGAL_VALUE if no connection for specified sco_inx.
+** BTM_MODE_UNSUPPORTED if local controller does not support
+** 1.2 specification.
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_ReadEScoLinkParms (UINT16 sco_inx,
+ tBTM_ESCO_DATA *p_parms);
+
+/*******************************************************************************
+**
+** Function BTM_ChangeEScoLinkParms
+**
+** Description This function requests renegotiation of the parameters on
+** the current eSCO Link. If any of the changes are accepted
+** by the controllers, the BTM_ESCO_CHG_EVT event is sent in
+** the tBTM_ESCO_CBACK function with the current settings of
+** the link. The callback is registered through the call to
+** BTM_SetEScoMode.
+**
+**
+** Returns BTM_CMD_STARTED if command is successfully initiated.
+** BTM_ILLEGAL_VALUE if no connection for specified sco_inx.
+** BTM_NO_RESOURCES - not enough resources to initiate command.
+** BTM_MODE_UNSUPPORTED if local controller does not support
+** 1.2 specification.
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_ChangeEScoLinkParms (UINT16 sco_inx,
+ tBTM_CHG_ESCO_PARAMS *p_parms);
+
+/*******************************************************************************
+**
+** Function BTM_EScoConnRsp
+**
+** Description This function is called upon receipt of an (e)SCO connection
+** request event (BTM_ESCO_CONN_REQ_EVT) to accept or reject
+** the request. Parameters used to negotiate eSCO links.
+** If p_parms is NULL, then values set through BTM_SetEScoMode
+** are used.
+** If the link type of the incoming request is SCO, then only
+** the tx_bw, max_latency, content format, and packet_types are
+** valid. The hci_status parameter should be
+** ([0x0] to accept, [0x0d..0x0f] to reject)
+**
+**
+** Returns void
+**
+*******************************************************************************/
+ BTM_API extern void BTM_EScoConnRsp (UINT16 sco_inx, UINT8 hci_status,
+ tBTM_ESCO_PARAMS *p_parms);
+
+/*******************************************************************************
+**
+** Function BTM_GetNumScoLinks
+**
+** Description This function returns the number of active SCO links.
+**
+** Returns UINT8
+**
+*******************************************************************************/
+ BTM_API extern UINT8 BTM_GetNumScoLinks (void);
+
+/*****************************************************************************
+** SECURITY MANAGEMENT FUNCTIONS
+*****************************************************************************/
+/*******************************************************************************
+**
+** Function BTM_SecRegister
+**
+** Description Application manager calls this function to register for
+** security services. There can be one and only one application
+** saving link keys. BTM allows only first registration.
+**
+** Returns TRUE if registered OK, else FALSE
+**
+*******************************************************************************/
+ BTM_API extern BOOLEAN BTM_SecRegister (tBTM_APPL_INFO *p_cb_info);
+
+
+/*******************************************************************************
+**
+** Function BTM_SecRegisterLinkKeyNotificationCallback
+**
+** Description Profiles can register to be notified when a new Link Key
+** is generated per connection.
+**
+** Returns TRUE if registered OK, else FALSE
+**
+*******************************************************************************/
+ BTM_API extern BOOLEAN BTM_SecRegisterLinkKeyNotificationCallback (tBTM_LINK_KEY_CALLBACK *p_callback);
+
+
+/*******************************************************************************
+**
+** Function BTM_SecAddRmtNameNotifyCallback
+**
+** Description Profiles can register to be notified when name of the
+** remote device is resolved (up to BTM_SEC_MAX_RMT_NAME_CALLBACKS).
+**
+** Returns TRUE if registered OK, else FALSE
+**
+*******************************************************************************/
+ BTM_API extern BOOLEAN BTM_SecAddRmtNameNotifyCallback (tBTM_RMT_NAME_CALLBACK *p_callback);
+
+
+/*******************************************************************************
+**
+** Function BTM_SecDeleteRmtNameNotifyCallback
+**
+** Description A profile can deregister notification when a new Link Key
+** is generated per connection.
+**
+** Returns TRUE if OK, else FALSE
+**
+*******************************************************************************/
+ BTM_API extern BOOLEAN BTM_SecDeleteRmtNameNotifyCallback (tBTM_RMT_NAME_CALLBACK *p_callback);
+
+
+/*******************************************************************************
+**
+** Function BTM_SecSetConnectFilterCallback
+**
+** Description Host can register to be asked whenever an HCI connection
+** request is received. In the registered function host
+** suppose to check connectibility filters. Yes/No result
+** should be returned synchronously.
+**
+** Returns void
+**
+*******************************************************************************/
+ BTM_API extern void BTM_SecSetConnectFilterCallback (tBTM_FILTER_CB *p_callback);
+
+
+/*******************************************************************************
+**
+** Function BTM_GetSecurityMode
+**
+** Description Get security mode for the device
+**
+** Returns void
+**
+*******************************************************************************/
+ BTM_API extern UINT8 BTM_GetSecurityMode (void);
+
+
+/*******************************************************************************
+**
+** Function BTM_GetSecurityFlags
+**
+** Description Get security flags for the device
+**
+** Returns BOOLEAN TRUE or FALSE is device found
+**
+*******************************************************************************/
+ BTM_API extern BOOLEAN BTM_GetSecurityFlags (BD_ADDR bd_addr, UINT8 * p_sec_flags);
+
+/*******************************************************************************
+**
+** Function BTM_ReadTrustedMask
+**
+** Description Get trusted mask for the device
+**
+** Returns NULL, if the device record is not found.
+** otherwise, the trusted mask
+**
+*******************************************************************************/
+ BTM_API extern UINT32 * BTM_ReadTrustedMask (BD_ADDR bd_addr);
+
+
+/*******************************************************************************
+**
+** Function BTM_SetSecurityMode
+**
+** Description Set security mode for the device
+**
+** Returns void
+**
+*******************************************************************************/
+ BTM_API extern void BTM_SetSecurityMode (UINT8 sec_mode);
+
+
+/*******************************************************************************
+**
+** Function BTM_SetPinType
+**
+** Description Set PIN type for the device.
+**
+** Returns void
+**
+*******************************************************************************/
+ BTM_API extern void BTM_SetPinType (UINT8 pin_type, PIN_CODE pin_code, UINT8 pin_code_len);
+
+
+/*******************************************************************************
+**
+** Function BTM_SetPairableMode
+**
+** Description Enable or disable pairing
+**
+** Parameters allow_pairing - (TRUE or FALSE) whether or not the device
+** allows pairing.
+** connect_only_paired - (TRUE or FALSE) whether or not to
+** only allow paired devices to connect.
+**
+** Returns void
+**
+*******************************************************************************/
+ BTM_API extern void BTM_SetPairableMode (BOOLEAN allow_pairing, BOOLEAN connect_only_paired);
+
+/*******************************************************************************
+**
+** Function BTM_SetSecurityLevel
+**
+** Description Register service security level with Security Manager. Each
+** service must register its requirements regardless of the
+** security level that is used. This API is called once for originators
+** nad again for acceptors of connections.
+**
+** Returns TRUE if registered OK, else FALSE
+**
+*******************************************************************************/
+ BTM_API extern BOOLEAN BTM_SetSecurityLevel (BOOLEAN is_originator, char *p_name,
+ UINT8 service_id, UINT16 sec_level,
+ UINT16 psm, UINT32 mx_proto_id,
+ UINT32 mx_chan_id);
+
+/*******************************************************************************
+**
+** Function BTM_SetUCDSecurityLevel
+**
+** Description Register UCD service security level with Security Manager. Each
+** service must register its requirements regardless of the
+** security level that is used. This API is called once for originators
+** and again for acceptors of connections.
+**
+** Returns TRUE if registered OK, else FALSE
+**
+*******************************************************************************/
+ BTM_API extern BOOLEAN BTM_SetUCDSecurityLevel (BOOLEAN is_originator, char *p_name, UINT8 service_id,
+ UINT16 sec_level, UINT16 psm, UINT32 mx_proto_id,
+ UINT32 mx_chan_id);
+
+/*******************************************************************************
+**
+** Function BTM_SetOutService
+**
+** Description This function is called to set the service for
+** outgoing connection.
+**
+** Returns void
+**
+*******************************************************************************/
+ BTM_API extern void BTM_SetOutService(BD_ADDR bd_addr, UINT8 service_id, UINT32 mx_chan_id);
+
+/*******************************************************************************
+**
+** Function BTM_SecClrService
+**
+** Description Removes specified service record(s) from the security database.
+** All service records with the specified name are removed.
+** Typically used only by devices with limited RAM so that it can
+** reuse an old security service record.
+** records (except SDP).
+**
+** Returns Number of records that were freed.
+**
+*******************************************************************************/
+ BTM_API extern UINT8 BTM_SecClrService (UINT8 service_id);
+
+/*******************************************************************************
+**
+** Function BTM_SecClrUCDService
+**
+** Description
+**
+** Parameters Service ID - Id of the service to remove. ('0' removes all service
+** records.
+**
+** Returns Number of records that were freed.
+**
+*******************************************************************************/
+ BTM_API extern UINT8 BTM_SecClrUCDService (UINT8 service_id);
+
+/*******************************************************************************
+**
+** Function BTM_SecAddDevice
+**
+** Description Add/modify device. This function will be normally called
+** during host startup to restore all required information
+** stored in the NVRAM.
+** dev_class, bd_name, link_key, and features are NULL if unknown
+**
+** Returns TRUE if added OK, else FALSE
+**
+*******************************************************************************/
+ BTM_API extern BOOLEAN BTM_SecAddDevice (BD_ADDR bd_addr, DEV_CLASS dev_class,
+ BD_NAME bd_name, BD_FEATURES features,
+ UINT32 trusted_mask[], LINK_KEY link_key,
+ UINT8 key_type, tBTM_IO_CAP io_cap);
+
+
+/*******************************************************************************
+**
+** Function BTM_SecDeleteDevice
+**
+** Description Free resources associated with the device.
+**
+** Returns TRUE if rmoved OK, FALSE if not found
+**
+*******************************************************************************/
+ BTM_API extern BOOLEAN BTM_SecDeleteDevice (BD_ADDR bd_addr);
+
+
+/*******************************************************************************
+**
+** Function BTM_SecUseMasterLinkKey
+**
+** Description This function is called to tell master of the piconet to
+** switch to master link key
+**
+** Returns BTM_SUCCESS if command is successully initiated
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_SecUseMasterLinkKey (BOOLEAN use_master_key);
+
+
+/*******************************************************************************
+**
+** Function BTM_SetMasterKeyCompCback
+**
+** Description This function is called to register for the master key complete
+** status event.
+**
+** Parameters: mkey_cback - callback registered with the security manager
+**
+** Returns void
+**
+*******************************************************************************/
+ BTM_API extern void BTM_SetMasterKeyCompCback(tBTM_MKEY_CALLBACK *mkey_cback );
+
+
+/*******************************************************************************
+**
+** Function BTM_SecGetDeviceLinkKey
+**
+** Description This function is called to obtain link key for the device
+** it returns BTM_SUCCESS if link key is available, or
+** BTM_UNKNOWN_ADDR if Security Manager does not know about
+** the device or device record does not contain link key info
+**
+** Returns BTM_SUCCESS if successful, otherwise error code
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_SecGetDeviceLinkKey (BD_ADDR bd_addr,
+ LINK_KEY link_key);
+
+
+/*******************************************************************************
+**
+** Function BTM_PINCodeReply
+**
+** Description This function is called after Security Manager submitted
+** PIN code request to the UI.
+**
+** Parameters: bd_addr - Address of the device for which PIN was requested
+** res - result of the operation BTM_SUCCESS if success
+** pin_len - length in bytes of the PIN Code
+** p_pin - pointer to array with the PIN Code
+** trusted_mask - bitwise OR of trusted services (array of UINT32)
+**
+** Returns void
+**
+*******************************************************************************/
+ BTM_API extern void BTM_PINCodeReply (BD_ADDR bd_addr, UINT8 res, UINT8 pin_len,
+ UINT8 *p_pin, UINT32 trusted_mask[]);
+
+
+/*******************************************************************************
+**
+** Function BTM_DeviceAuthorized
+**
+** Description This function is called after Security Manager submitted
+** authorization request to the UI.
+**
+** Parameters: bd_addr - Address of the device for which PIN was requested
+** res - result of the operation BTM_SUCCESS if success
+**
+** Returns void
+**
+*******************************************************************************/
+ BTM_API extern void BTM_DeviceAuthorized (BD_ADDR bd_addr, UINT8 res,
+ UINT32 trusted_mask[]);
+
+
+/*******************************************************************************
+**
+** Function BTM_SecBond
+**
+** Description This function is called to perform bonding with peer device.
+**
+** Returns BTM_CMD_STARTED if successfully initiated, otherwise error
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_SecBond (BD_ADDR bd_addr, UINT8 pin_len, UINT8 *p_pin, UINT32 trusted_mask[]);
+
+/*******************************************************************************
+**
+** Function BTM_SecBondCancel
+**
+** Description This function is called to cancel ongoing bonding process
+** with peer device.
+**
+** Returns BTM_CMD_STARTED if successfully initiated, otherwise error
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_SecBondCancel (BD_ADDR bd_addr);
+
+/*******************************************************************************
+**
+** Function BTM_SetEncryption
+**
+** Description This function is called to ensure that connection is
+** encrypted. Should be called only on an open connection.
+** Typically only needed for connections that first want to
+** bring up unencrypted links, then later encrypt them.
+**
+** Parameters: bd_addr - Address of the peer device
+** p_callback - Pointer to callback function called if
+** this function returns PENDING after required
+** procedures are completed. Can be set to NULL
+** if status is not desired.
+** p_ref_data - pointer to any data the caller wishes to receive
+** in the callback function upon completion.
+* can be set to NULL if not used.
+**
+** Returns BTM_SUCCESS - already encrypted
+** BTM_PENDING - command will be returned in the callback
+** BTM_WRONG_MODE- connection not up.
+** BTM_BUSY - security procedures are currently active
+** BTM_MODE_UNSUPPORTED - if security manager not linked in.
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_SetEncryption (BD_ADDR bd_addr, tBTM_SEC_CBACK *p_callback,
+ void *p_ref_data);
+
+/*******************************************************************************
+**
+** Function BTM_ConfirmReqReply
+**
+** Description This function is called to confirm the numeric value for
+** Simple Pairing in response to BTM_SP_CFM_REQ_EVT
+**
+** Parameters: res - result of the operation BTM_SUCCESS if success
+** bd_addr - Address of the peer device
+**
+*******************************************************************************/
+ BTM_API extern void BTM_ConfirmReqReply(tBTM_STATUS res, BD_ADDR bd_addr);
+
+/*******************************************************************************
+**
+** Function BTM_PasskeyReqReply
+**
+** Description This function is called to provide the passkey for
+** Simple Pairing in response to BTM_SP_KEY_REQ_EVT
+**
+** Parameters: res - result of the operation BTM_SUCCESS if success
+** bd_addr - Address of the peer device
+** passkey - numeric value in the range of 0 - 999999(0xF423F).
+**
+*******************************************************************************/
+ BTM_API extern void BTM_PasskeyReqReply(tBTM_STATUS res, BD_ADDR bd_addr, UINT32 passkey);
+
+/*******************************************************************************
+**
+** Function BTM_SendKeypressNotif
+**
+** Description This function is used during the passkey entry model
+** by a device with KeyboardOnly IO capabilities
+** (very likely to be a HID Device).
+** It is called by a HID Device to inform the remote device when
+** a key has been entered or erased.
+**
+** Parameters: bd_addr - Address of the peer device
+** type - notification type
+**
+*******************************************************************************/
+ BTM_API extern void BTM_SendKeypressNotif(BD_ADDR bd_addr, tBTM_SP_KEY_TYPE type);
+
+/*******************************************************************************
+**
+** Function BTM_IoCapRsp
+**
+** Description This function is called in response to BTM_SP_IO_REQ_EVT
+** When the event data io_req.oob_data is set to BTM_OOB_UNKNOWN
+** by the tBTM_SP_CALLBACK implementation, this function is
+** called to provide the actual response
+**
+** Parameters: bd_addr - Address of the peer device
+** io_cap - The IO capability of local device.
+** oob - BTM_OOB_NONE or BTM_OOB_PRESENT.
+** auth_req- MITM protection required or not.
+**
+*******************************************************************************/
+ BTM_API extern void BTM_IoCapRsp(BD_ADDR bd_addr, tBTM_IO_CAP io_cap,
+ tBTM_OOB_DATA oob, tBTM_AUTH_REQ auth_req);
+
+/*******************************************************************************
+**
+** Function BTM_ReadLocalOobData
+**
+** Description This function is called to read the local OOB data from
+** LM
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_ReadLocalOobData(void);
+
+/*******************************************************************************
+**
+** Function BTM_RemoteOobDataReply
+**
+** Description This function is called to provide the remote OOB data for
+** Simple Pairing in response to BTM_SP_RMT_OOB_EVT
+**
+** Parameters: bd_addr - Address of the peer device
+** c - simple pairing Hash C.
+** r - simple pairing Randomizer C.
+**
+*******************************************************************************/
+ BTM_API extern void BTM_RemoteOobDataReply(tBTM_STATUS res, BD_ADDR bd_addr, BT_OCTET16 c, BT_OCTET16 r);
+
+/*******************************************************************************
+**
+** Function BTM_BuildOobData
+**
+** Description This function is called to build the OOB data payload to
+** be sent over OOB (non-Bluetooth) link
+**
+** Parameters: p_data - the location for OOB data
+** max_len - p_data size.
+** c - simple pairing Hash C.
+** r - simple pairing Randomizer C.
+** name_len- 0, local device name would not be included.
+** otherwise, the local device name is included for
+** up to this specified length
+**
+** Returns Number of bytes in p_data.
+**
+*******************************************************************************/
+ BTM_API extern UINT16 BTM_BuildOobData(UINT8 *p_data, UINT16 max_len, BT_OCTET16 c,
+ BT_OCTET16 r, UINT8 name_len);
+
+/*******************************************************************************
+**
+** Function BTM_ReadOobData
+**
+** Description This function is called to parse the OOB data payload
+** received over OOB (non-Bluetooth) link
+**
+** Parameters: p_data - the location for OOB data
+** eir_tag - The associated EIR tag to read the data.
+** *p_len(output) - the length of the data with the given tag.
+**
+** Returns the beginning of the data with the given tag.
+** NULL, if the tag is not found.
+**
+*******************************************************************************/
+ BTM_API extern UINT8 * BTM_ReadOobData(UINT8 *p_data, UINT8 eir_tag, UINT8 *p_len);
+
+/*******************************************************************************
+**
+** Function BTM_SecReadDevName
+**
+** Description Looks for the device name in the security database for the
+** specified BD address.
+**
+** Returns Pointer to the name or NULL
+**
+*******************************************************************************/
+ BTM_API extern char *BTM_SecReadDevName (BD_ADDR bd_addr);
+
+
+/*****************************************************************************
+** POWER MANAGEMENT FUNCTIONS
+*****************************************************************************/
+/*******************************************************************************
+**
+** Function BTM_PmRegister
+**
+** Description register or deregister with power manager
+**
+** Returns BTM_SUCCESS if successful,
+** BTM_NO_RESOURCES if no room to hold registration
+** BTM_ILLEGAL_VALUE
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_PmRegister (UINT8 mask, UINT8 *p_pm_id,
+ tBTM_PM_STATUS_CBACK *p_cb);
+
+
+/*******************************************************************************
+**
+** Function BTM_SetPowerMode
+**
+** Description store the mode in control block or
+** alter ACL connection behavior.
+**
+** Returns BTM_SUCCESS if successful,
+** BTM_UNKNOWN_ADDR if bd addr is not active or bad
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_SetPowerMode (UINT8 pm_id, BD_ADDR remote_bda,
+ tBTM_PM_PWR_MD *p_mode);
+
+
+/*******************************************************************************
+**
+** Function BTM_ReadPowerMode
+**
+** Description This returns the current mode for a specific
+** ACL connection.
+**
+** Input Param remote_bda - device address of desired ACL connection
+**
+** Output Param p_mode - address where the current mode is copied into.
+** BTM_ACL_MODE_NORMAL
+** BTM_ACL_MODE_HOLD
+** BTM_ACL_MODE_SNIFF
+** BTM_ACL_MODE_PARK
+** (valid only if return code is BTM_SUCCESS)
+**
+** Returns BTM_SUCCESS if successful,
+** BTM_UNKNOWN_ADDR if bd addr is not active or bad
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_ReadPowerMode (BD_ADDR remote_bda,
+ tBTM_PM_MODE *p_mode);
+
+/*******************************************************************************
+**
+** Function BTM_SetSsrParams
+**
+** Description This sends the given SSR parameters for the given ACL
+** connection if it is in ACTIVE mode.
+**
+** Input Param remote_bda - device address of desired ACL connection
+** max_lat - maximum latency (in 0.625ms)(0-0xFFFE)
+** min_rmt_to - minimum remote timeout
+** min_loc_to - minimum local timeout
+**
+**
+** Returns BTM_SUCCESS if the HCI command is issued successful,
+** BTM_UNKNOWN_ADDR if bd addr is not active or bad
+** BTM_CMD_STORED if the command is stored
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_SetSsrParams (BD_ADDR remote_bda, UINT16 max_lat,
+ UINT16 min_rmt_to, UINT16 min_loc_to);
+
+/*******************************************************************************
+**
+** Function BTM_IsPowerManagerOn
+**
+** Description This function is called to check if power manager is included.
+** in the BTE version.
+**
+** Returns TRUE if power manager is compiled in, otherwise FALSE.
+**
+*******************************************************************************/
+ BTM_API extern BOOLEAN BTM_IsPowerManagerOn (void);
+
+
+/*******************************************************************************
+**
+** Function BTM_GetHCIConnHandle
+**
+** Description This function is called to get the handle for an ACL connection
+** to a specific remote BD Address.
+**
+** Returns the handle of the connection, or 0xFFFF if none.
+**
+*******************************************************************************/
+ BTM_API extern UINT16 BTM_GetHCIConnHandle (BD_ADDR remote_bda);
+
+
+/*******************************************************************************
+**
+** Function BTM_ReadStoredLinkKey
+**
+** Description This function is called to obtain link key for the specified
+** device from the NVRAM storage attached to the Bluetooth
+** controller.
+**
+** Parameters: bd_addr - Address of the device
+** p_cb - Call back function to be called to return
+** the results
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_ReadStoredLinkKey (BD_ADDR bd_addr, tBTM_CMPL_CB *p_cb);
+
+
+/*******************************************************************************
+**
+** Function BTM_WriteStoredLinkKey
+**
+** Description This function is called to write link keys for the specified
+** device addresses to the NVRAM storage attached to the Bluetooth
+** controller.
+**
+** Parameters: num_keys - Number of link keys
+** bd_addr - Addresses of the devices
+** link_key - Link Keys to be stored
+** p_cb - Call back function to be called to return
+** the results
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_WriteStoredLinkKey (UINT8 num_keys,
+ BD_ADDR *bd_addr,
+ LINK_KEY *link_key,
+ tBTM_CMPL_CB *p_cb);
+
+
+/*******************************************************************************
+**
+** Function BTM_DeleteStoredLinkKey
+**
+** Description This function is called to delete link key for the specified
+** device addresses from the NVRAM storage attached to the Bluetooth
+** controller.
+**
+** Parameters: bd_addr - Addresses of the devices
+** p_cb - Call back function to be called to return
+** the results
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_DeleteStoredLinkKey(BD_ADDR bd_addr, tBTM_CMPL_CB *p_cb);
+
+/*******************************************************************************
+**
+** Function BTM_WriteEIR
+**
+** Description This function is called to write EIR data to controller.
+**
+** Parameters p_buff - allocated HCI command buffer including extended
+** inquriry response
+**
+** Returns BTM_SUCCESS - if successful
+** BTM_MODE_UNSUPPORTED - if local device cannot support it
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_WriteEIR( BT_HDR * p_buff );
+
+/*******************************************************************************
+**
+** Function BTM_CheckEirData
+**
+** Description This function is called to get EIR data from significant part.
+**
+** Parameters p_eir - pointer of EIR significant part
+** type - finding EIR data type
+** p_length - return the length of EIR data
+**
+** Returns pointer of EIR data
+**
+*******************************************************************************/
+ BTM_API extern UINT8 *BTM_CheckEirData( UINT8 *p_eir, UINT8 type, UINT8 *p_length );
+
+/*******************************************************************************
+**
+** Function BTM_HasEirService
+**
+** Description This function is called to know if UUID in bit map of UUID.
+**
+** Parameters p_eir_uuid - bit map of UUID list
+** uuid16 - UUID 16-bit
+**
+** Returns TRUE - if found
+** FALSE - if not found
+**
+*******************************************************************************/
+ BTM_API extern BOOLEAN BTM_HasEirService( UINT32 *p_eir_uuid, UINT16 uuid16 );
+
+/*******************************************************************************
+**
+** Function BTM_HasInquiryEirService
+**
+** Description This function is called to know if UUID in bit map of UUID list.
+**
+** Parameters p_results - inquiry results
+** uuid16 - UUID 16-bit
+**
+** Returns BTM_EIR_FOUND - if found
+** BTM_EIR_NOT_FOUND - if not found and it is complete list
+** BTM_EIR_UNKNOWN - if not found and it is not complete list
+**
+*******************************************************************************/
+ BTM_API extern tBTM_EIR_SEARCH_RESULT BTM_HasInquiryEirService( tBTM_INQ_RESULTS *p_results,
+ UINT16 uuid16 );
+
+/*******************************************************************************
+**
+** Function BTM_AddEirService
+**
+** Description This function is called to add a service in bit map of UUID list.
+**
+** Parameters p_eir_uuid - bit mask of UUID list for EIR
+** uuid16 - UUID 16-bit
+**
+** Returns None
+**
+*******************************************************************************/
+ BTM_API extern void BTM_AddEirService( UINT32 *p_eir_uuid, UINT16 uuid16 );
+
+/*******************************************************************************
+**
+** Function BTM_RemoveEirService
+**
+** Description This function is called to remove a service in bit map of UUID list.
+**
+** Parameters p_eir_uuid - bit mask of UUID list for EIR
+** uuid16 - UUID 16-bit
+**
+** Returns None
+**
+*******************************************************************************/
+ BTM_API extern void BTM_RemoveEirService( UINT32 *p_eir_uuid, UINT16 uuid16 );
+
+/*******************************************************************************
+**
+** Function BTM_GetEirSupportedServices
+**
+** Description This function is called to get UUID list from bit map of UUID list.
+**
+** Parameters p_eir_uuid - bit mask of UUID list for EIR
+** p - reference of current pointer of EIR
+** max_num_uuid16 - max number of UUID can be written in EIR
+** num_uuid16 - number of UUID have been written in EIR
+**
+** Returns BTM_EIR_MORE_16BITS_UUID_TYPE, if it has more than max
+** BTM_EIR_COMPLETE_16BITS_UUID_TYPE, otherwise
+**
+*******************************************************************************/
+ BTM_API extern UINT8 BTM_GetEirSupportedServices( UINT32 *p_eir_uuid, UINT8 **p,
+ UINT8 max_num_uuid16, UINT8 *p_num_uuid16);
+
+/*******************************************************************************
+**
+** Function BTM_GetEirUuidList
+**
+** Description This function parses EIR and returns UUID list.
+**
+** Parameters p_eir - EIR
+** uuid_size - LEN_UUID_16, LEN_UUID_32, LEN_UUID_128
+** p_num_uuid - return number of UUID in found list
+** p_uuid_list - return UUID 16-bit list
+** max_num_uuid - maximum number of UUID to be returned
+**
+** Returns 0 - if not found
+** BTM_EIR_COMPLETE_16BITS_UUID_TYPE
+** BTM_EIR_MORE_16BITS_UUID_TYPE
+** BTM_EIR_COMPLETE_32BITS_UUID_TYPE
+** BTM_EIR_MORE_32BITS_UUID_TYPE
+** BTM_EIR_COMPLETE_128BITS_UUID_TYPE
+** BTM_EIR_MORE_128BITS_UUID_TYPE
+**
+*******************************************************************************/
+ BTM_API extern UINT8 BTM_GetEirUuidList( UINT8 *p_eir, UINT8 uuid_size, UINT8 *p_num_uuid,
+ UINT8 *p_uuid_list, UINT8 max_num_uuid);
+
+/*******************************************************************************
+**
+** Function BTM_SyncStack
+**
+** Description For Dual-Stack support. Called to initiate switching to/from
+** main stack (running on phone baseband) to mm stack (light
+** stack running on multi-media chip)
+**
+** Parameters sync_dir: BTM_SW_BB_TO_MM: switch from BB to MM stack
+** BTM_SW_MM_TO_BB: switch from MM to BB stack
+** BTM_SW_RESYNC: resync MM and BB stacks
+**
+** p_sync_cback: callback function for event notification
+** Returns
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_SyncStack(tBTM_SW_DIR sync_dir, tBTM_SYNC_STACK_CBACK p_sync_cback);
+
+/*******************************************************************************
+**
+** Function BTM_SyncBtaRsp
+**
+** Description For Dual-Stack support. Called to indicate that upper layers
+** (e.g. BTA or application) have completed synchronizing bta/app
+** specific layers for switching.
+**
+** Called in response to 'BTM_SYNC_BTA_EVT'
+**
+** Parameters status: BTM_SUCESS: bta/app successfully synchronized
+** otherwise: sync was unsuccessfule. Abort switch.
+**
+** p_btm_sync_info: information from bta/app that will be needed
+** by BTE (avdt and l2cap) for switching.
+**
+** Returns void
+**
+*******************************************************************************/
+ BTM_API extern void BTM_SyncBtaRsp(tBTM_STATUS status, tBTM_SYNC_INFO *p_btm_sync_info);
+
+/*******************************************************************************
+**
+** Function BTM_OpenUIPC
+**
+** Description For Dual-Stack support. Called to open UIPC between
+** main stack (running on phone baseband) to embedded light stack
+** (running on Multimedia or Bluetooth Controller chip)
+**
+** Parameters sync_dir: BTM_SW_BB_TO_MM: switch from BB to MM stack
+** BTM_SW_BB_TO_BTC:switch from BB to BTC stack
+**
+** p_sync_callback: callback function for event notification
+** Returns
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_OpenUIPC(tBTM_SW_DIR sync_dir, tBTM_SYNC_STACK_CBACK p_sync_callback);
+
+/*******************************************************************************
+**
+** Function BTM_CloseUIPC
+**
+** Description For Dual-Stack support. Called to close UIPC between
+** main stack (running on phone baseband) to embedded light stack
+** (running on Multimedia or Bluetooth Controller chip)
+**
+** Parameters
+** p_sync_callback: callback function for event notification
+** Returns
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_CloseUIPC(tBTM_SYNC_STACK_CBACK p_sync_callback);
+
+/*******************************************************************************
+**
+** Function BTM_IpcSend
+**
+** Description For Dual-Stack support. Called to send ipc messages from
+** full stack to lite stack and vice-versa. This API is
+** typically called by bta layers e.g. bta_av.
+**
+**
+** Parameters len: Length of the buffer in the ipc message
+**
+** buffer: Pointer to the buffer to be passed in the IPC message
+**
+** Returns void
+**
+*******************************************************************************/
+ BTM_API extern void BTM_IpcSend(UINT16 len, UINT8* buffer);
+
+/*******************************************************************************
+**
+** Function BTM_IpcSendBuf
+**
+** Description For Dual-Stack support. Called to send ipc messages from
+** full stack to lite stack and vice-versa. This API is
+** typically called by bta layers e.g. bta_av_sync.
+**
+**
+** Parameters p_buf: Pointer to the buffer to be passed in the IPC message
+**
+** Returns void
+**
+*******************************************************************************/
+ BTM_API extern void BTM_IpcSendBuf(BT_HDR* p_buf);
+
+/*******************************************************************************
+**
+** Function BTM_RegIpcEvtHandler
+**
+** Description registers the DM provided handler for IPC events
+**
+**
+** Returns void
+**
+*******************************************************************************/
+ BTM_API extern void BTM_RegIpcEvtHandler(tBTM_IPC_EVT_CBACK *p_cback);
+
+/*******************************************************************************
+**
+** Function BTM_RegRTIpcEvtHandler
+**
+** Description registers the RT(Audio Routing) provided handler for IPC events
+**
+**
+** Returns void
+**
+*******************************************************************************/
+ BTM_API extern void BTM_RegRTIpcEvtHandler(tBTM_IPC_EVT_CBACK *p_cback);
+
+/*****************************************************************************
+** N2BT
+*****************************************************************************/
+
+/* Data callback for N2BT */
+ typedef void (tBTM_N2BT_DATA_CB) (BD_ADDR bd_addr, UINT16 handle, UINT8 *p_data, UINT16 datalen);
+
+/*******************************************************************************
+**
+** Function BTM_N2BtAcquire
+**
+** Description Put controller into acquisition mode
+**
+** Returns void
+**
+*******************************************************************************/
+ BTM_API extern void BTM_N2BtAcquire(BD_ADDR bd_addr, UINT16 timeout,
+ UINT8 freq, UINT8 src_addrlen, UINT8 sensor_flags,
+ UINT8 sensor_type, UINT8 sensor_clk_accuracy,
+ UINT16 add_rx_window, UINT16 init_crc,
+ UINT32 ac_low, UINT32 ac_high, UINT16 pkt_hdr,
+ UINT16 list_dur, UINT16 list_int,
+ UINT8 oor_missed_pkts, tBTM_VSC_CMPL_CB *p_cb,
+ tBTM_N2BT_DATA_CB *p_data_cback);
+
+/*******************************************************************************
+**
+** Function BTM_N2BtDisconnect
+**
+** Description Disconnects all N2BT devices
+**
+** Returns void
+**
+*******************************************************************************/
+ BTM_API extern void BTM_N2BtDisconnect(void);
+
+
+/*******************************************************************************
+**
+** Function BTM_ConfigI2SPCM
+**
+** Description This function sends VSC Write_I2SPCM_Interface_Param
+** as to the specified codec_type.
+**
+**
+** Parameter codec_type: codec_type to be used for sco connection.
+** role: master or slave role
+** sample_rate: sampling rate
+** clock_rate:clock rate 128K to 2048K
+**
+**
+** Returns BTM_SUCCESS if the successful.
+** BTM_ILLEGAL_VALUE: wrong codec type
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_ConfigI2SPCM (tBTM_SCO_CODEC_TYPE codec_type, UINT8 role, UINT8 sample_rate, UINT8 clock_rate);
+
+/*****************************************************************************
+** SCO OVER HCI
+*****************************************************************************/
+/*******************************************************************************
+**
+** Function BTM_ConfigScoPath
+**
+** Description This function enable/disable SCO over HCI and registers SCO
+** data callback if SCO over HCI is enabled.
+**
+** Parameter path: SCO or HCI
+** p_sco_data_cb: callback function or SCO data if path is set
+** to transport.
+** p_pcm_param: pointer to the PCM interface parameter. If a NULL
+** pointer is used, PCM parameter maintained in
+** the control block will be used; otherwise update
+** control block value.
+** err_data_rpt: Lisbon feature to enable the erronous data report
+** or not.
+**
+** Returns BTM_SUCCESS if the successful.
+** BTM_NO_RESOURCES: no rsource to start the command.
+** BTM_ILLEGAL_VALUE: invalid callback function pointer.
+** BTM_CMD_STARTED :Command sent. Waiting for command cmpl event.
+**
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_ConfigScoPath (tBTM_SCO_ROUTE_TYPE path,
+ tBTM_SCO_DATA_CB *p_sco_data_cb,
+ tBTM_SCO_PCM_PARAM *p_pcm_param,
+ BOOLEAN err_data_rpt);
+
+/*******************************************************************************
+**
+** Function BTM_WriteScoData
+**
+** Description This function write SCO data to a specified instance. The data
+** to be written p_buf needs to carry an offset of
+** HCI_SCO_PREAMBLE_SIZE bytes, and the data length can not
+** exceed BTM_SCO_DATA_SIZE_MAX bytes, whose default value is set
+** to 60 and is configurable. Data longer than the maximum bytes
+** will be truncated.
+**
+** Returns BTM_SUCCESS: data write is successful
+** BTM_ILLEGAL_VALUE: SCO data contains illegal offset value.
+** BTM_SCO_BAD_LENGTH: SCO data length exceeds the max SCO packet
+** size.
+** BTM_NO_RESOURCES: no resources.
+** BTM_UNKNOWN_ADDR: unknown SCO connection handle, or SCO is not
+** routed via HCI.
+**
+**
+*******************************************************************************/
+ BTM_API extern tBTM_STATUS BTM_WriteScoData (UINT16 sco_inx, BT_HDR *p_buf);
+
+/*******************************************************************************
+**
+** Function BTM_SetARCMode
+**
+** Description Send Audio Routing Control command.
+**
+** Returns void
+**
+*******************************************************************************/
+BTM_API extern void BTM_SetARCMode (UINT8 iface, UINT8 arc_mode, tBTM_VSC_CMPL_CB *p_arc_cb);
+
+
+/*******************************************************************************
+**
+** Function BTM_PCM2Setup_Write
+**
+** Description Send PCM2_Setup write command.
+**
+** Returns void
+**
+*******************************************************************************/
+BTM_API extern void BTM_PCM2Setup_Write (BOOLEAN clk_master, tBTM_VSC_CMPL_CB *p_arc_cb);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTM_API_H */
diff --git a/stack/include/btm_ble_api.h b/stack/include/btm_ble_api.h
new file mode 100644
index 0000000..4bcd797
--- /dev/null
+++ b/stack/include/btm_ble_api.h
@@ -0,0 +1,716 @@
+/*****************************************************************************
+**
+** Name: btm_ble_api.h
+**
+** Description: This file contains the Bluetooth Manager (BTM) API function
+** external definitions.
+**
+**
+** Copyright (c) 1999-2008, Broadcom Corp., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+#ifndef BTM_BLE_API_H
+#define BTM_BLE_API_H
+
+#include "btm_api.h"
+
+#define CHNL_MAP_LEN 5
+typedef UINT8 tBTM_BLE_CHNL_MAP[CHNL_MAP_LEN];
+
+#define BTM_BLE_SCAN_MODE_PASS 0
+#define BTM_BLE_SCAN_MODE_ACTI 1
+#define BTM_BLE_SCAN_MODE_NONE 0xff
+typedef UINT8 tBTM_BLE_SCAN_MODE;
+
+/* advertising channel map */
+#define BTM_BLE_ADV_CHNL_37 (0x01 << 0)
+#define BTM_BLE_ADV_CHNL_38 (0x01 << 1)
+#define BTM_BLE_ADV_CHNL_39 (0x01 << 2)
+typedef UINT8 tBTM_BLE_ADV_CHNL_MAP;
+
+/*d efault advertising channel map */
+#ifndef BTM_BLE_DEFAULT_ADV_CHNL_MAP
+#define BTM_BLE_DEFAULT_ADV_CHNL_MAP (BTM_BLE_ADV_CHNL_37| BTM_BLE_ADV_CHNL_38| BTM_BLE_ADV_CHNL_39)
+#endif
+
+/* advertising filter policy */
+#define AP_SCAN_CONN_ALL 0x00 /* default */
+#define AP_SCAN_WL_CONN_ALL 0x01
+#define AP_SCAN_ALL_CONN_WL 0x02
+#define AP_SCAN_CONN_WL 0x03
+#define AP_SCAN_CONN_POLICY_MAX 0x04
+typedef UINT8 tBTM_BLE_AFP;
+
+/* default advertising filter policy */
+#ifndef BTM_BLE_DEFAULT_AFP
+#define BTM_BLE_DEFAULT_AFP AP_SCAN_CONN_ALL
+#endif
+
+/* scanning filter policy */
+#define SP_ADV_ALL 0x00 /* accept adv pakt from all, directed adv pkt not directed to me is ignored */
+#define SP_ADV_WL 0x01 /* accept adv pakt from device in white list, directed adv pkt not directed to me is ignored */
+typedef UINT8 tBTM_BLE_SFP;
+
+#ifndef BTM_BLE_DEFAULT_SFP
+#define BTM_BLE_DEFAULT_SFP SP_ADV_ALL
+#endif
+
+/* adv parameter boundary values */
+#define BTM_BLE_ADV_INT_MIN 0x0020
+#define BTM_BLE_ADV_INT_MAX 0x4000
+
+/* connection parameter boundary value */
+#define BTM_BLE_SCAN_INT_MIN 0x0004
+#define BTM_BLE_SCAN_INT_MAX 0x4000
+#define BTM_BLE_SCAN_WIN_MIN 0x0004
+#define BTM_BLE_SCAN_WIN_MAX 0x4000
+#define BTM_BLE_CONN_INT_MIN 0x0006
+#define BTM_BLE_CONN_INT_MAX 0x0C80
+#define BTM_BLE_CONN_LATENCY_MAX 500
+#define BTM_BLE_CONN_SUP_TOUT_MIN 0x000A
+#define BTM_BLE_CONN_SUP_TOUT_MAX 0x0C80
+#define BTM_BLE_CONN_PARAM_UNDEF 0xffff /* use this value when a specific value not to be overwritten */
+
+/* default connection parameters if not configured, use GAP recommend value for auto/selective connection */
+/* default scan interval */
+#ifndef BTM_BLE_CONN_EST_SCAN_INT
+#define BTM_BLE_CONN_EST_SCAN_INT 96 /* 312.5 ms = 500 *0.625 */
+#endif
+/* default scan window for background connection, applicable for auto connection or selective conenction */
+#ifndef BTM_BLE_CONN_EST_SCAN_WIND
+#define BTM_BLE_CONN_EST_SCAN_WIND 48 /* 187.5 ms = 400 *0.625 */
+#endif
+
+/* default scan paramter used in reduced power cycle */
+#ifndef BTM_BLE_CONN_EST_SCAN_INT_LO
+#define BTM_BLE_CONN_EST_SCAN_INT_LO 2048 /* 1.28 s = 500 *0.625 */
+#endif
+#ifndef BTM_BLE_CONN_EST_SCAN_WIND_LO
+#define BTM_BLE_CONN_EST_SCAN_WIND_LO 18 /* 11.25 ms = 400 *0.625 */
+#endif
+
+/* default connection interval min */
+#ifndef BTM_BLE_CONN_INT_MIN_DEF
+#define BTM_BLE_CONN_INT_MIN_DEF 40 /* 50ms = 400 * 1.25 */
+#endif
+/* default connectino interval max */
+#ifndef BTM_BLE_CONN_INT_MAX_DEF
+#define BTM_BLE_CONN_INT_MAX_DEF 56 /* 70ms = 56 * 1.25 */
+#endif
+/* default slave latency */
+#ifndef BTM_BLE_CONN_SLAVE_LATENCY_DEF
+#define BTM_BLE_CONN_SLAVE_LATENCY_DEF 0 /* 0 */
+#endif
+/* default supervision timeout */
+#ifndef BTM_BLE_CONN_TIMEOUT_DEF
+#define BTM_BLE_CONN_TIMEOUT_DEF 2000
+#endif
+
+#define BTM_CMAC_TLEN_SIZE 8 /* 64 bits */
+#define BTM_BLE_AUTH_SIGN_LEN 12 /* BLE data signature length 8 Bytes + 4 bytes counter*/
+typedef UINT8 BLE_SIGNATURE[BTM_BLE_AUTH_SIGN_LEN]; /* Device address */
+
+/* Structure returned with Rand/Encrypt complete callback */
+typedef struct
+{
+ UINT8 status;
+ UINT8 param_len;
+ UINT16 opcode;
+ UINT8 param_buf[BT_OCTET16_LEN];
+} tBTM_RAND_ENC;
+
+/* General callback function for notifying an application that a synchronous
+** BTM function is complete. The pointer contains the address of any returned data.
+*/
+typedef void (tBTM_RAND_ENC_CB) (tBTM_RAND_ENC *p1);
+
+#define BTM_BLE_FILTER_TARGET_SCANNER 0x01
+#define BTM_BLE_FILTER_TARGET_ADVR 0x00
+
+#define BTM_BLE_POLICY_BLACK_ALL 0x00 /* relevant to both */
+#define BTM_BLE_POLICY_ALLOW_SCAN 0x01 /* relevant to advertiser */
+#define BTM_BLE_POLICY_ALLOW_CONN 0x02 /* relevant to advertiser */
+#define BTM_BLE_POLICY_WHITE_ALL 0x03 /* relevant to both */
+
+typedef struct
+{
+ UINT8 adv_int_min;
+ UINT8 adv_int_max;
+ tBTM_BLE_CHNL_MAP chnl_map;
+
+}tBTM_BLE_ADV_PARAMS;
+
+/* ADV data flag bit definition used for BTM_BLE_AD_TYPE_FLAG */
+#define BTM_BLE_LIMIT_DISC_FLAG (0x01 << 0)
+#define BTM_BLE_GEN_DISC_FLAG (0x01 << 1)
+#define BTM_BLE_BREDR_NOT_SPT (0x01 << 2)
+#define BTM_BLE_NON_LIMIT_DISC_FLAG (0x00 ) /* lowest bit unset */
+#define BTM_BLE_ADV_FLAG_MASK (BTM_BLE_LIMIT_DISC_FLAG | BTM_BLE_BREDR_NOT_SPT | BTM_BLE_GEN_DISC_FLAG)
+#define BTM_BLE_LIMIT_DISC_MASK (BTM_BLE_LIMIT_DISC_FLAG )
+
+#define BTM_BLE_AD_BIT_DEV_NAME (0x0001 << 0)
+#define BTM_BLE_AD_BIT_FLAGS (0x0001 << 1)
+#define BTM_BLE_AD_BIT_MANU (0x0001 << 2)
+#define BTM_BLE_AD_BIT_TX_PWR (0x0001 << 3)
+#define BTM_BLE_AD_BIT_ATTR (0x0001 << 4)
+#define BTM_BLE_AD_BIT_INT_RANGE (0x0001 << 5)
+#define BTM_BLE_AD_BIT_SERVICE (0x0001 << 6)
+#define BTM_BLE_AD_BIT_SERVICE_SOL (0x0001 << 7)
+#define BTM_BLE_AD_BIT_SERVICE_DATA (0x0001 << 8)
+#define BTM_BLE_AD_BIT_SIGN_DATA (0x0001 << 9)
+#define BTM_BLE_AD_BIT_PROPRIETARY (0x0001 << 15)
+
+typedef UINT16 tBTM_BLE_AD_MASK;
+
+#define BTM_BLE_AD_TYPE_FLAG 0x01
+#define BTM_BLE_AD_TYPE_SRV_PART 0x02
+#define BTM_BLE_AD_TYPE_SRV_CMPL 0x03
+#define BTM_BLE_AD_TYPE_NAME_SHORT 0x08
+#define BTM_BLE_AD_TYPE_NAME_CMPL 0x09
+#define BTM_BLE_AD_TYPE_TX_PWR 0x0A
+#define BTM_BLE_AD_TYPE_DEV_CLASS 0x0D
+#define BTM_BLE_AD_TYPE_ATTR 0x10
+#define BTM_BLE_AD_TYPE_MANU 0xff
+#define BTM_BLE_AD_TYPE_INT_RANGE 0x12
+#define BTM_BLE_AD_TYPE_SOL_SRV_UUID 0x14
+typedef UINT8 tBTM_BLE_AD_TYPE;
+
+/* slave preferred connection interval range */
+typedef struct
+{
+ UINT16 low;
+ UINT16 hi;
+
+}tBTM_BLE_INT_RANGE;
+
+/* Service tag supported in the device */
+typedef struct
+{
+ UINT8 num_service;
+ BOOLEAN list_cmpl;
+ UINT16 *p_uuid;
+}tBTM_BLE_SERVICE;
+
+/* attribute data */
+typedef struct
+{
+ UINT16 uuid;
+ UINT16 data_len;
+ UINT8 *p_data;
+}tBTM_BLE_ATTR;
+
+#ifndef BTM_BLE_NUM_AD_ATTR_MAX
+#define BTM_BLE_NUM_AD_ATTR_MAX 10
+#endif
+/* attribute list contained in adv data */
+typedef struct
+{
+ UINT8 num_attr;
+ tBTM_BLE_ATTR attr_list[BTM_BLE_NUM_AD_ATTR_MAX];
+}tBTM_BLE_ATTR_DATA;
+
+typedef struct
+{
+ UINT8 len;
+ UINT8 *p_val;
+}tBTM_BLE_MANU;
+
+typedef struct
+{
+ UINT8 adv_type;
+ UINT8 len;
+ UINT8 *p_val; /* number of len byte */
+}tBTM_BLE_PROP_ELEM;
+
+typedef struct
+{
+ UINT8 num_elem;
+ tBTM_BLE_PROP_ELEM *p_elem;
+}tBTM_BLE_PROPRIETARY;
+
+typedef struct
+{
+ tBTM_BLE_MANU manu; /* manufactuer data */
+ tBTM_BLE_INT_RANGE int_range; /* slave prefered conn interval range */
+ tBTM_BLE_SERVICE services; /* services */
+ tBTM_BLE_ATTR_DATA attr; /* attribute data */
+ UINT8 flag;
+ tBTM_BLE_PROPRIETARY *p_proprietary;
+}tBTM_BLE_ADV_DATA;
+
+/* These are the fields returned in each device adv packet. It
+** is returned in the results callback if registered.
+*/
+typedef struct
+{
+ UINT8 conn_mode;
+ tBTM_BLE_AD_MASK ad_mask; /* mask of the valid adv data field */
+ UINT8 flag;
+ UINT8 tx_power_level;
+ UINT8 remote_name_len;
+ UINT8 *p_remote_name;
+ tBTM_BLE_ATTR_DATA attr_data;
+ tBTM_BLE_SERVICE service;
+} tBTM_BLE_INQ_DATA;
+
+enum
+{
+ BTM_BLE_CONN_NONE,
+ BTM_BLE_CONN_AUTO,
+ BTM_BLE_CONN_SELECTIVE
+};
+typedef UINT8 tBTM_BLE_CONN_TYPE;
+
+typedef BOOLEAN (tBTM_BLE_SEL_CBACK)(BD_ADDR random_bda, UINT8 *p_remote_name);
+
+/* callback function for SMP signing algorithm, signed data in little endian order with tlen bits long */
+typedef void (tBTM_BLE_SIGN_CBACK)(void *p_ref_data, UINT8 *p_signing_data);
+typedef void (tBTM_BLE_VERIFY_CBACK)(void *p_ref_data, BOOLEAN match);
+/* random address set complete callback */
+typedef void (tBTM_BLE_RANDOM_SET_CBACK) (BD_ADDR random_bda);
+
+typedef void (tBTM_BLE_SCAN_REQ_CBACK)(BD_ADDR remote_bda, tBLE_ADDR_TYPE addr_type, UINT8 adv_evt);
+/*****************************************************************************
+** EXTERNAL FUNCTION DECLARATIONS
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*******************************************************************************
+**
+** Function BTM_SecAddBleDevice
+**
+** Description Add/modify device. This function will be normally called
+** during host startup to restore all required information
+** for a LE device stored in the NVRAM.
+**
+** Parameters: bd_addr - BD address of the peer
+** bd_name - Name of the peer device. NULL if unknown.
+** dev_type - Remote device's device type.
+** addr_type - LE device address type.
+**
+** Returns TRUE if added OK, else FALSE
+**
+*******************************************************************************/
+BTM_API extern BOOLEAN BTM_SecAddBleDevice (BD_ADDR bd_addr, BD_NAME bd_name,
+ tBT_DEVICE_TYPE dev_type, tBLE_ADDR_TYPE addr_type);
+
+/*******************************************************************************
+**
+** Function BTM_SecAddBleKey
+**
+** Description Add/modify LE device information. This function will be
+** normally called during host startup to restore all required
+** information stored in the NVRAM.
+**
+** Parameters: bd_addr - BD address of the peer
+** p_le_key - LE key values.
+** key_type - LE SMP key type.
+*
+** Returns TRUE if added OK, else FALSE
+**
+*******************************************************************************/
+BTM_API extern BOOLEAN BTM_SecAddBleKey (BD_ADDR bd_addr, tBTM_LE_KEY_VALUE *p_le_key,
+ tBTM_LE_KEY_TYPE key_type);
+
+/*******************************************************************************
+**
+** Function BTM_BleSetAdvParams
+**
+** Description This function is called to set advertising parameters.
+**
+** Parameters: None.
+**
+** Returns void
+**
+*******************************************************************************/
+BTM_API extern tBTM_STATUS BTM_BleSetAdvParams(UINT16 adv_int_min, UINT16 adv_int_max,
+ tBLE_BD_ADDR *p_dir_bda, tBTM_BLE_ADV_CHNL_MAP chnl_map);
+
+/*******************************************************************************
+**
+** Function BTM_BleWriteAdvData
+**
+** Description This function is called to write advertising data.
+**
+** Parameters: None.
+**
+** Returns void
+**
+*******************************************************************************/
+BTM_API extern tBTM_STATUS BTM_BleWriteAdvData(tBTM_BLE_AD_MASK data_mask,
+ tBTM_BLE_ADV_DATA *p_data);
+
+/*******************************************************************************
+**
+** Function BTM_BleSetAdvParams
+**
+** Description This function is called to set advertising parameters.
+**
+** Parameters adv_int_min: minimum advertising interval
+** adv_int_max: maximum advertising interval
+** p_dir_bda: connectable direct initiator's LE device address
+** chnl_map: advertising channel map.
+**
+** Returns void
+**
+*******************************************************************************/
+BTM_API extern void BTM_BleReadAdvParams (UINT16 *adv_int_min, UINT16 *adv_int_max,
+ tBLE_BD_ADDR *p_dir_bda, tBTM_BLE_ADV_CHNL_MAP *p_chnl_map);
+
+
+/*******************************************************************************
+**
+** Function BTM_BleSetScanParams
+**
+** Description This function is called to set Scan parameters.
+**
+** Parameters adv_int_min: minimum advertising interval
+** adv_int_max: maximum advertising interval
+** scan_type: scan mode.
+**
+** Returns void
+**
+*******************************************************************************/
+BTM_API extern void BTM_BleSetScanParams(UINT16 scan_interval, UINT16 scan_window,
+ tBTM_BLE_SCAN_MODE scan_type);
+
+/*******************************************************************************
+**
+** Function BTM_BleWriteScanRsp
+**
+** Description This function is called to write LE scan response.
+**
+** Parameters: p_scan_rsp: scan response.
+**
+** Returns status
+**
+*******************************************************************************/
+BTM_API extern tBTM_STATUS BTM_BleWriteScanRsp(tBTM_BLE_AD_MASK data_mask,
+ tBTM_BLE_ADV_DATA *p_data);
+
+/*******************************************************************************
+**
+** Function BTM_BleReset
+**
+** Description This function is called to reset ULP controller.
+**
+** Parameters None.
+**
+** Returns void
+**
+*******************************************************************************/
+BTM_API extern void BTM_BleReset(void);
+
+/*******************************************************************************
+**
+** Function BTM_BleObserve
+**
+** Description This procedure keep the device listening for advertising
+** events from a broadcast device.
+**
+** Parameters start: start or stop observe.
+**
+** Returns void
+**
+*******************************************************************************/
+BTM_API extern tBTM_STATUS BTM_BleObserve(BOOLEAN start, UINT8 duration,
+ tBTM_INQ_RESULTS_CB *p_results_cb, tBTM_CMPL_CB *p_cmpl_cb);
+
+
+/*******************************************************************************
+**
+** Function BTM_GetDeviceIDRoot
+**
+** Description This function is called to read the local device identity
+** root.
+**
+** Returns void
+** the local device ER is copied into er
+**
+*******************************************************************************/
+BTM_API extern void BTM_GetDeviceIDRoot (BT_OCTET16 ir);
+
+/*******************************************************************************
+**
+** Function BTM_GetDeviceEncRoot
+**
+** Description This function is called to read the local device encryption
+** root.
+**
+** Returns void
+** the local device ER is copied into er
+**
+*******************************************************************************/
+BTM_API extern void BTM_GetDeviceEncRoot (BT_OCTET16 er);
+
+/*******************************************************************************
+**
+** Function BTM_GetDeviceDHK
+**
+** Description This function is called to read the local device DHK.
+**
+** Returns void
+** the local device DHK is copied into dhk
+**
+*******************************************************************************/
+BTM_API extern void BTM_GetDeviceDHK (BT_OCTET16 dhk);
+
+/*******************************************************************************
+**
+** Function BTM_SecurityGrant
+**
+** Description This function is called to grant security process.
+**
+** Parameters bd_addr - peer device bd address.
+** res - result of the operation BTM_SUCCESS if success.
+** Otherwise, BTM_REPEATED_ATTEMPTS is too many attempts.
+**
+** Returns None
+**
+*******************************************************************************/
+BTM_API extern void BTM_SecurityGrant(BD_ADDR bd_addr, UINT8 res);
+
+/*******************************************************************************
+**
+** Function BTM_BlePasskeyReply
+**
+** Description This function is called after Security Manager submitted
+** passkey request to the application.
+**
+** Parameters: bd_addr - Address of the device for which passkey was requested
+** res - result of the operation SMP_SUCCESS if success
+** passkey - numeric value in the range of
+** BTM_MIN_PASSKEY_VAL(0) - BTM_MAX_PASSKEY_VAL(999999(0xF423F)).
+**
+*******************************************************************************/
+BTM_API extern void BTM_BlePasskeyReply (BD_ADDR bd_addr, UINT8 res, UINT32 passkey);
+
+/*******************************************************************************
+**
+** Function BTM_LeOobDataReply
+**
+** Description This function is called to provide the OOB data for
+** SMP in response to BTM_LE_OOB_REQ_EVT
+**
+** Parameters: bd_addr - Address of the peer device
+** res - result of the operation SMP_SUCCESS if success
+** p_data - simple pairing Randomizer C.
+**
+*******************************************************************************/
+BTM_API extern void BTM_BleOobDataReply(BD_ADDR bd_addr, UINT8 res, UINT8 len, UINT8 *p_data);
+
+
+/*******************************************************************************
+**
+** Function BTM_BleDataSignature
+**
+** Description This function is called to sign the data using AES128 CMAC
+** algorith.
+**
+** Parameter bd_addr: target device the data to be signed for.
+** p_text: singing data
+** len: length of the signing data
+** signature: output parameter where data signature is going to
+** be stored.
+**
+** Returns TRUE if signing sucessul, otherwise FALSE.
+**
+*******************************************************************************/
+BTM_API extern BOOLEAN BTM_BleDataSignature (BD_ADDR bd_addr, UINT8 *p_text, UINT16 len,
+ BLE_SIGNATURE signature);
+
+/*******************************************************************************
+**
+** Function BTM_BleVerifySignature
+**
+** Description This function is called to verify the data signature
+**
+** Parameter bd_addr: target device the data to be signed for.
+** p_orig: original data before signature.
+** len: length of the signing data
+** counter: counter used when doing data signing
+** p_comp: signature to be compared against.
+
+** Returns TRUE if signature verified correctly; otherwise FALSE.
+**
+*******************************************************************************/
+BTM_API extern BOOLEAN BTM_BleVerifySignature (BD_ADDR bd_addr, UINT8 *p_orig,
+ UINT16 len, UINT32 counter,
+ UINT8 *p_comp);
+
+/*******************************************************************************
+**
+** Function BTM_SetRandomAddr
+**
+** Description This function is called to set the local device random address
+** .
+**
+** Returns void
+**
+*******************************************************************************/
+BTM_API extern void BTM_SetRandomAddr (tBTM_BLE_RANDOM_SET_CBACK *p_cback);
+
+/*******************************************************************************
+**
+** Function BTM_ReadConnectionAddr
+**
+** Description This function is called to set the local device random address
+** .
+**
+** Returns void
+**
+*******************************************************************************/
+BTM_API extern void BTM_ReadConnectionAddr (BD_ADDR conn_addr);
+
+/*******************************************************************************
+**
+** Function BTM_BleLoadLocalKeys
+**
+** Description Local local identity key, encryption root or sign counter.
+**
+** Parameters: key_type: type of key, can be BTM_BLE_KEY_TYPE_ID, BTM_BLE_KEY_TYPE_ER
+** or BTM_BLE_KEY_TYPE_COUNTER.
+** p_key: pointer to the key.
+*
+** Returns non2.
+**
+*******************************************************************************/
+BTM_API extern void BTM_BleLoadLocalKeys(UINT8 key_type, tBTM_BLE_LOCAL_KEYS *p_key);
+
+
+/*******************************************************************************
+**
+** Function BTM_BleSetBgConnType
+**
+** Description This function is called to set BLE background connection
+** procedure type. It can be auto connection, or selective connection.
+**
+** Parameters conn_type: it can be auto connection, or selective connection.
+** p_select_cback: callback function when selective connection procedure
+** is being used.
+**
+** Returns void
+**
+*******************************************************************************/
+BTM_API extern BOOLEAN BTM_BleSetBgConnType(tBTM_BLE_CONN_TYPE conn_type,
+ tBTM_BLE_SEL_CBACK *p_select_cback);
+
+/*******************************************************************************
+**
+** Function BTM_BleUpdateBgConnDev
+**
+** Description This function is called to add or remove a device into/from
+** background connection procedure. The background connection
+* procedure is decided by the background connection type, it can be
+* auto connection, or selective connection.
+**
+** Parameters add_remove: TRUE to add; FALSE to remove.
+** remote_bda: device address to add/remove.
+**
+** Returns void
+**
+*******************************************************************************/
+BTM_API extern BOOLEAN BTM_BleUpdateBgConnDev(BOOLEAN add_remove, BD_ADDR remote_bda);
+
+
+/********************************************************
+**
+** Function BTM_BleSetPrefConnParams
+**
+** Description Set a peripheral's preferred connection parameters. When
+** any of the value does not want to be updated while others
+** do, use BTM_BLE_CONN_PARAM_UNDEF for the ones want to
+** leave untouched.
+**
+** Parameters: bd_addr - BD address of the peripheral
+** min_conn_int - minimum preferred connection interval
+** max_conn_int - maximum preferred connection interval
+** slave_latency - preferred slave latency
+** supervision_tout - preferred supervision timeout
+**
+** Returns void
+**
+*******************************************************************************/
+BTM_API extern void BTM_BleSetPrefConnParams (BD_ADDR bd_addr,
+ UINT16 min_conn_int, UINT16 max_conn_int,
+ UINT16 slave_latency, UINT16 supervision_tout);
+
+/******************************************************************************
+**
+** Function BTM_BleSetConnScanParams
+**
+** Description Set scan parameters used in BLE connection request
+**
+** Parameters: scan_interval - scan interval
+** scan_window - scan window
+**
+** Returns void
+**
+*******************************************************************************/
+BTM_API extern void BTM_BleSetConnScanParams (UINT16 scan_interval, UINT16 scan_window);
+
+/*******************************************************************************
+**
+** Function BTM_CheckAdvData
+**
+** Description This function is called to get ADV data for a specific type.
+**
+** Parameters p_adv - pointer of ADV data
+** type - finding ADV data type
+** p_length - return the length of ADV data not including type
+**
+** Returns pointer of ADV data
+**
+*******************************************************************************/
+BTM_API extern UINT8 *BTM_CheckAdvData( UINT8 *p_adv, UINT8 type, UINT8 *p_length);
+
+/*******************************************************************************
+**
+** Function BTM_ReadDevInfo
+**
+** Description This function is called to read the device/address type
+** of BD address.
+**
+** Parameter remote_bda: remote device address
+** p_dev_type: output parameter to read the device type.
+** p_addr_type: output parameter to read the address type.
+**
+*******************************************************************************/
+BTM_API extern void BTM_ReadDevInfo (BD_ADDR remote_bda, tBT_DEVICE_TYPE *p_dev_type,
+ tBLE_ADDR_TYPE *p_addr_type);
+
+/*******************************************************************************
+**
+** Function BTM_BleBroadcast
+**
+** Description This function is to start or stop broadcasting.
+**
+** Parameters start: start or stop broadcasting.
+**
+** Returns status.
+**
+*******************************************************************************/
+BTM_API extern tBTM_STATUS BTM_BleBroadcast(BOOLEAN start);
+
+/*******************************************************************************
+**
+** Function BTM_RegisterScanReqEvt
+**
+** Description This function is called to register a scan request callback
+** on the advertiser.
+**
+** Parameters p_scan_req_cback: scan request callback. If NULL, remove the
+** registration.
+**
+** Returns void
+**
+*******************************************************************************/
+BTM_API extern void BTM_RegisterScanReqEvt(tBTM_BLE_SCAN_REQ_CBACK *p_scan_req_cback);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/stack/include/btu.h b/stack/include/btu.h
new file mode 100644
index 0000000..c47839e
--- /dev/null
+++ b/stack/include/btu.h
@@ -0,0 +1,297 @@
+/*****************************************************************************/
+/* */
+/* Name: btu.h */
+/* */
+/* Description: this file contains the main Bluetooth Upper Layer */
+/* definitions. The Widcomm implementations of L2CAP */
+/* RFCOMM, SDP and the BTIf run as one GKI task. The */
+/* btu_task switches between them. */
+/* */
+/* Copyright (c) 1999-2011, Broadcom Corp., All Rights Reserved. */
+/* Broadcom Bluetooth Core. Proprietary and confidential. */
+/*****************************************************************************/
+#ifndef BTU_H
+#define BTU_H
+
+#include "bt_target.h"
+#include "gki.h"
+
+/* Define the BTU mailbox usage
+*/
+#define BTU_HCI_RCV_MBOX TASK_MBOX_0 /* Messages from HCI */
+#define BTU_BTIF_MBOX TASK_MBOX_1 /* Messages to BTIF */
+
+
+/* callbacks
+*/
+typedef void (*tBTU_TIMER_CALLBACK)(TIMER_LIST_ENT *p_tle);
+typedef void (*tBTU_EVENT_CALLBACK)(BT_HDR *p_hdr);
+
+
+/* Define the timer types maintained by BTU
+*/
+#define BTU_TTYPE_BTM_DEV_CTL 1
+#define BTU_TTYPE_L2CAP_LINK 2
+#define BTU_TTYPE_L2CAP_CHNL 3
+#define BTU_TTYPE_L2CAP_HOLD 4
+#define BTU_TTYPE_SDP 5
+#define BTU_TTYPE_BTM_SCO 6
+#define BTU_TTYPE_BTM_ACL 9
+#define BTU_TTYPE_BTM_RMT_NAME 10
+#define BTU_TTYPE_RFCOMM_MFC 11
+#define BTU_TTYPE_RFCOMM_PORT 12
+#define BTU_TTYPE_TCS_L2CAP 13
+#define BTU_TTYPE_TCS_CALL 14
+#define BTU_TTYPE_TCS_WUG 15
+#define BTU_TTYPE_AUTO_SYNC 16
+#define BTU_TTYPE_CTP_RECON 17
+#define BTU_TTYPE_CTP_T100 18
+#define BTU_TTYPE_CTP_GUARD 19
+#define BTU_TTYPE_CTP_DETACH 20
+
+#define BTU_TTYPE_SPP_CONN_RETRY 21
+#define BTU_TTYPE_USER_FUNC 22
+
+#define BTU_TTYPE_FTP_DISC 25
+#define BTU_TTYPE_OPP_DISC 26
+
+#define BTU_TTYPE_CTP_TL_DISCVY 28
+#define BTU_TTYPE_IPFRAG_TIMER 29
+#define BTU_TTYPE_HSP2_AT_CMD_TO 30
+#define BTU_TTYPE_HSP2_REPEAT_RING 31
+
+#define BTU_TTYPE_CTP_GW_INIT 32
+#define BTU_TTYPE_CTP_GW_CONN 33
+#define BTU_TTYPE_CTP_GW_IDLE 35
+
+#define BTU_TTYPE_ICP_L2CAP 36
+#define BTU_TTYPE_ICP_T100 37
+
+#define BTU_TTYPE_HSP2_WAIT_OK 38
+
+/* HCRP Timers */
+#define BTU_TTYPE_HCRP_NOTIF_REG 39
+#define BTU_TTYPE_HCRP_PROTO_RSP 40
+#define BTU_TTYPE_HCRP_CR_GRANT 41
+#define BTU_TTYPE_HCRP_CR_CHECK 42
+#define BTU_TTYPE_HCRP_W4_CLOSE 43
+
+/* HCRPM Timers */
+#define BTU_TTYPE_HCRPM_NOTIF_REG 44
+#define BTU_TTYPE_HCRPM_NOTIF_KEEP 45
+#define BTU_TTYPE_HCRPM_API_RSP 46
+#define BTU_TTYPE_HCRPM_W4_OPEN 47
+#define BTU_TTYPE_HCRPM_W4_CLOSE 48
+
+/* BNEP Timers */
+#define BTU_TTYPE_BNEP 50
+
+/* OBX */
+#define BTU_TTYPE_OBX_CLIENT_TO 51
+#define BTU_TTYPE_OBX_SERVER_TO 52
+#define BTU_TTYPE_OBX_SVR_SESS_TO 53
+
+
+#define BTU_TTYPE_HSP2_SDP_FAIL_TO 55
+#define BTU_TTYPE_HSP2_SDP_RTRY_TO 56
+
+/* BTU internal */
+/* unused 60 */
+
+#define BTU_TTYPE_AVDT_CCB_RET 61
+#define BTU_TTYPE_AVDT_CCB_RSP 62
+#define BTU_TTYPE_AVDT_CCB_IDLE 63
+#define BTU_TTYPE_AVDT_SCB_TC 64
+
+#define BTU_TTYPE_HID_DEV_REPAGE_TO 65
+#define BTU_TTYPE_HID_HOST_REPAGE_TO 66
+
+#define BTU_TTYPE_HSP2_DELAY_CKPD_RCV 67
+
+#define BTU_TTYPE_SAP_TO 68
+
+/* BPP Timer */
+#define BTU_TTYPE_BPP_REF_CHNL 72
+
+/* LP HC idle Timer */
+#define BTU_TTYPE_LP_HC_IDLE_TO 74
+
+/* Patch RAM Timer */
+#define BTU_TTYPE_PATCHRAM_TO 75
+
+/* eL2CAP Info Request and other proto cmds timer */
+#define BTU_TTYPE_L2CAP_FCR_ACK 78
+#define BTU_TTYPE_L2CAP_INFO 79
+
+/* BTU internal for BR/EDR and AMP HCI command timeout (reserve up to 3 AMP controller) */
+#define BTU_TTYPE_BTU_CMD_CMPL 80
+#define BTU_TTYPE_BTU_AMP1_CMD_CMPL 81
+#define BTU_TTYPE_BTU_AMP2_CMD_CMPL 82
+#define BTU_TTYPE_BTU_AMP3_CMD_CMPL 83
+
+#define BTU_TTYPE_MCA_CCB_RSP 98
+
+/* BTU internal timer for BLE activity */
+#define BTU_TTYPE_BLE_INQUIRY 99
+#define BTU_TTYPE_BLE_GAP_LIM_DISC 100
+#define BTU_TTYPE_ATT_WAIT_FOR_RSP 101
+#define BTU_TTYPE_SMP_PAIRING_CMD 102
+#define BTU_TTYPE_BLE_RANDOM_ADDR 103
+#define BTU_TTYPE_ATT_WAIT_FOR_APP_RSP 104
+#define BTU_TTYPE_ATT_WAIT_FOR_IND_ACK 105
+#define BTU_TTYPE_BLE_SCAN_PARAM_IDLE 106
+
+/* Define the BTU_TASK APPL events
+*/
+#if (defined(NFC_SHARED_TRANSPORT_ENABLED) && (NFC_SHARED_TRANSPORT_ENABLED==TRUE))
+#define BTU_NFC_AVAILABLE_EVT EVENT_MASK(APPL_EVT_0) /* Notifies BTU task that NFC is available (used for shared NFC+BT transport) */
+#endif
+
+/* This is the inquiry response information held by BTU, and available
+** to applications.
+*/
+typedef struct
+{
+ BD_ADDR remote_bd_addr;
+ UINT8 page_scan_rep_mode;
+ UINT8 page_scan_per_mode;
+ UINT8 page_scan_mode;
+ DEV_CLASS dev_class;
+ UINT16 clock_offset;
+} tBTU_INQ_INFO;
+
+
+
+#define BTU_MAX_REG_TIMER (2) /* max # timer callbacks which may register */
+#define BTU_MAX_REG_EVENT (6) /* max # event callbacks which may register */
+#define BTU_DEFAULT_DATA_SIZE (0x2a0)
+
+#if (BLE_INCLUDED == TRUE)
+#define BTU_DEFAULT_BLE_DATA_SIZE (27)
+#endif
+
+/* structure to hold registered timers */
+typedef struct
+{
+ TIMER_LIST_ENT *p_tle; /* timer entry */
+ tBTU_TIMER_CALLBACK timer_cb; /* callback triggered when timer expires */
+} tBTU_TIMER_REG;
+
+/* structure to hold registered event callbacks */
+typedef struct
+{
+ UINT16 event_range; /* start of event range */
+ tBTU_EVENT_CALLBACK event_cb; /* callback triggered when event is in range */
+} tBTU_EVENT_REG;
+
+#define NFC_MAX_LOCAL_CTRLS 0
+
+/* the index to BTU command queue array */
+#define NFC_CONTROLLER_ID (1)
+#define BTU_MAX_LOCAL_CTRLS (1 + NFC_MAX_LOCAL_CTRLS) /* only BR/EDR */
+
+/* AMP HCI control block */
+typedef struct
+{
+ BUFFER_Q cmd_xmit_q;
+ BUFFER_Q cmd_cmpl_q;
+ UINT16 cmd_window;
+ TIMER_LIST_ENT cmd_cmpl_timer; /* Command complete timer */
+#if (defined(BTU_CMD_CMPL_TOUT_DOUBLE_CHECK) && BTU_CMD_CMPL_TOUT_DOUBLE_CHECK == TRUE)
+ BOOLEAN checked_hcisu;
+#endif
+} tHCI_CMD_CB;
+
+/* Define structure holding BTU variables
+*/
+typedef struct
+{
+ tBTU_TIMER_REG timer_reg[BTU_MAX_REG_TIMER];
+ tBTU_EVENT_REG event_reg[BTU_MAX_REG_EVENT];
+
+ TIMER_LIST_Q quick_timer_queue; /* Timer queue for transport level (100/10 msec)*/
+ TIMER_LIST_Q timer_queue; /* Timer queue for normal BTU task (1 second) */
+
+ TIMER_LIST_ENT cmd_cmpl_timer; /* Command complete timer */
+
+ UINT16 hcit_acl_data_size; /* Max ACL data size across HCI transport */
+ UINT16 hcit_acl_pkt_size; /* Max ACL packet size across HCI transport */
+ /* (this is data size plus 4 bytes overhead) */
+
+#if BLE_INCLUDED == TRUE
+ UINT16 hcit_ble_acl_data_size; /* Max BLE ACL data size across HCI transport */
+ UINT16 hcit_ble_acl_pkt_size; /* Max BLE ACL packet size across HCI transport */
+ /* (this is data size plus 4 bytes overhead) */
+#endif
+
+ BOOLEAN reset_complete; /* TRUE after first ack from device received */
+ UINT8 trace_level; /* Trace level for HCI layer */
+
+ tHCI_CMD_CB hci_cmd_cb[BTU_MAX_LOCAL_CTRLS]; /* including BR/EDR */
+} tBTU_CB;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Global BTU data */
+#if BTU_DYNAMIC_MEMORY == FALSE
+BTU_API extern tBTU_CB btu_cb;
+#else
+BTU_API extern tBTU_CB *btu_cb_ptr;
+#define btu_cb (*btu_cb_ptr)
+#endif
+
+BTU_API extern const BD_ADDR BT_BD_ANY;
+
+/* Functions provided by btu_task.c
+************************************
+*/
+BTU_API extern void btu_start_timer (TIMER_LIST_ENT *p_tle, UINT16 type, UINT32 timeout);
+BTU_API extern void btu_stop_timer (TIMER_LIST_ENT *p_tle);
+BTU_API extern void btu_register_timer (TIMER_LIST_ENT *p_tle, UINT16 type, UINT32 timeout, tBTU_TIMER_CALLBACK timer_cb);
+BTU_API extern void btu_deregister_timer(TIMER_LIST_ENT *p_tle);
+BTU_API extern UINT32 btu_remaining_time (TIMER_LIST_ENT *p_tle);
+
+
+BTU_API extern void btu_register_event_range (UINT16 range, tBTU_EVENT_CALLBACK event_cb);
+BTU_API extern void btu_deregister_event_range (UINT16 range);
+BTU_API extern void btu_uipc_rx_cback(BT_HDR *p_msg);
+
+BTU_API extern void btu_hcif_flush_cmd_queue(void);
+/*
+** Quick Timer
+*/
+#if defined(QUICK_TIMER_TICKS_PER_SEC) && (QUICK_TIMER_TICKS_PER_SEC > 0)
+#define QUICK_TIMER_TICKS (GKI_SECS_TO_TICKS (1)/QUICK_TIMER_TICKS_PER_SEC)
+BTU_API extern void btu_start_quick_timer (TIMER_LIST_ENT *p_tle, UINT16 type, UINT32 timeout);
+BTU_API extern void btu_stop_quick_timer (TIMER_LIST_ENT *p_tle);
+BTU_API extern void btu_process_quick_timer_evt (void);
+BTU_API extern void process_quick_timer_evt (TIMER_LIST_Q *p_tlq);
+#endif
+
+#if (defined(HCILP_INCLUDED) && HCILP_INCLUDED == TRUE)
+BTU_API extern void btu_check_bt_sleep (void);
+#endif
+
+/* Functions provided by btu_hcif.c
+************************************
+*/
+BTU_API extern void btu_hcif_process_event (UINT8 controller_id, BT_HDR *p_buf);
+BTU_API extern void btu_hcif_send_cmd (UINT8 controller_id, BT_HDR *p_msg);
+BTU_API extern void btu_hcif_send_host_rdy_for_data(void);
+BTU_API extern void btu_hcif_cmd_timeout (UINT8 controller_id);
+
+/* Functions provided by btu_core.c
+************************************
+*/
+BTU_API extern void btu_init_core(void);
+BTU_API extern void BTE_Init(void);
+BTU_API extern UINT16 BTU_AclPktSize(void);
+BTU_API extern UINT16 BTU_BleAclPktSize(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/stack/include/dun_api.h b/stack/include/dun_api.h
new file mode 100644
index 0000000..2b3679f
--- /dev/null
+++ b/stack/include/dun_api.h
@@ -0,0 +1,201 @@
+/************************************************************************************
+**
+** Name: dun_api.h
+**
+** Description: this file contains the DUN API declaration
+**
+**
+** Copyright (c) 1999-2004, WIDCOMM Inc., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+*************************************************************************************/
+#ifndef DUN_API_H
+#define DUN_API_H
+
+#include "bt_target.h"
+#include "btm_api.h"
+#include "sdp_api.h"
+#include "port_api.h"
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+/* API function return values */
+#define DUN_SUCCESS 0
+#define DUN_FAIL 1
+
+/* Values for the options parameter. It is an integer bit mask that
+** contains information used in the DUN or Fax SDP record. These values
+** can be or'ed together to indicate more than one option. Fax class options
+** are not allowed for the DUN profile.
+*/
+#define DUN_OPTIONS_AUDIO (1<<0) /* Audio feedback supported */
+#define DUN_OPTIONS_CLASS1 (1<<1) /* Fax class 1 supported */
+#define DUN_OPTIONS_CLASS20 (1<<2) /* Fax class 2.0 supported */
+#define DUN_OPTIONS_CLASS2 (1<<3) /* Fax class 2 supported */
+
+/*****************************************************************************
+** Type definitions
+*****************************************************************************/
+
+/* This callback function returns service discovery information to the
+** application after the DUN_FindService() API function is called. The
+** implementation of this callback function must copy the p_name parameter
+** passed to it as it is not guaranteed to remain after the callback
+** function exits.
+*/
+typedef void (tDUN_FIND_CBACK)(BOOLEAN found, UINT8 scn, char* p_name,
+ UINT16 name_len, UINT16 options);
+
+
+/*****************************************************************************
+** External Function Declarations
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/******************************************************************************
+**
+** Function DUN_Listen
+**
+** Description This function opens a DUN or Fax connection in server mode.
+** It configures the security settings for the connection,
+** opens an RFCOMM connection in server mode, and sets the
+** class of device as required by the profile. It returns
+** the handle for the RFCOMM connection.
+**
+** Returns DUN_SUCCESS if function execution succeeded,
+** DUN_FAIL if function execution failed.
+**
+******************************************************************************/
+DUN_API extern UINT8 DUN_Listen(UINT16 service_uuid, char *p_service_name,
+ UINT8 scn, UINT16 mtu, UINT8 security_mask,
+ UINT16 *p_handle, tPORT_CALLBACK *p_cback);
+
+/******************************************************************************
+**
+** Function DUN_Connect
+**
+** Description This function opens a DUN or Fax client connection.
+** It configures the security settings for the connection
+** and opens an RFCOMM connection in server mode.
+** It returns the handle for the RFCOMM connection.
+**
+** Returns DUN_SUCCESS if function execution succeeded,
+** DUN_FAIL if function execution failed.
+**
+******************************************************************************/
+DUN_API extern UINT8 DUN_Connect(UINT16 service_uuid, BD_ADDR bd_addr, UINT8 scn,
+ UINT16 mtu, UINT8 security_mask, UINT16 *p_handle,
+ tPORT_CALLBACK *p_cback);
+
+/******************************************************************************
+**
+** Function DUN_Close
+**
+** Description This function closes a DUN or Fax client connection
+** previously opened with DUN_Connect().
+**
+** Returns DUN_SUCCESS if function execution succeeded,
+** DUN_FAIL if function execution failed.
+**
+******************************************************************************/
+DUN_API extern UINT8 DUN_Close(UINT16 handle);
+
+/******************************************************************************
+**
+** Function DUN_Shutdown
+**
+** Description This function closes a DUN or Fax server connection
+** previously opened with DUN_Listen(). It is called if
+** the application wishes to close the DUN or Fax server
+** connection at any time.
+**
+** Returns DUN_SUCCESS if function execution succeeded,
+** DUN_FAIL if function execution failed.
+**
+******************************************************************************/
+DUN_API extern UINT8 DUN_Shutdown(UINT16 handle);
+
+/******************************************************************************
+**
+** Function DUN_AddRecord
+**
+** Description This function is called by a server application to add
+** DUN or Fax information to an SDP record. Prior to
+** calling this function the application must call
+** SDP_CreateRecord() to create an SDP record.
+**
+** Returns DUN_SUCCESS if function execution succeeded,
+** DUN_FAIL if function execution failed.
+**
+******************************************************************************/
+DUN_API extern UINT8 DUN_AddRecord(UINT16 service_uuid, char *p_service_name,
+ UINT8 scn, UINT16 options, UINT32 sdp_handle);
+
+/******************************************************************************
+**
+** Function DUN_FindService
+**
+** Description This function is called by a client application to
+** perform service discovery and retrieve DUN or Fax SDP
+** record information from a server. Information is
+** returned for the first service record found on the
+** server that matches the service UUID. The callback
+** function will be executed when service discovery is
+** complete. There can only be one outstanding call to
+** DUN_FindService() at a time; the application must wait
+** for the callback before it makes another call to
+** the function.
+**
+** Returns DUN_SUCCESS if function execution succeeded,
+** DUN_FAIL if function execution failed.
+**
+******************************************************************************/
+DUN_API extern UINT8 DUN_FindService(UINT16 service_uuid, BD_ADDR bd_addr,
+ tSDP_DISCOVERY_DB *p_db, UINT32 db_len,
+ tDUN_FIND_CBACK *p_cback);
+
+/******************************************************************************
+**
+** Function DUN_SetTraceLevel
+**
+** Description Sets the trace level for DUN. If 0xff is passed, the
+** current trace level is returned.
+**
+** Input Parameters:
+** new_level: The level to set the DUN tracing to:
+** 0xff-returns the current setting.
+** 0-turns off tracing.
+** >= 1-Errors.
+** >= 2-Warnings.
+** >= 3-APIs.
+** >= 4-Events.
+** >= 5-Debug.
+**
+** Returns The new trace level or current trace level if
+** the input parameter is 0xff.
+**
+******************************************************************************/
+DUN_API extern UINT8 DUN_SetTraceLevel (UINT8 new_level);
+
+/*******************************************************************************
+**
+** Function DUN_Init
+**
+** Description This function is called before accessing the DUN APIs in order
+** to initialize the control block.
+**
+** Returns void
+**
+*******************************************************************************/
+DUN_API extern void DUN_Init(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* DUN_API_H */
+
diff --git a/stack/include/dyn_mem.h b/stack/include/dyn_mem.h
new file mode 100644
index 0000000..58d4579
--- /dev/null
+++ b/stack/include/dyn_mem.h
@@ -0,0 +1,182 @@
+/****************************************************************************
+**
+** Name: dyn_mem.h
+**
+** Function this file contains definitions used to determine if a component
+** uses static or dynamic memory for its control blocks.
+**
+**
+** Copyright (c) 2002-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef DYN_MEM_H
+#define DYN_MEM_H
+
+/****************************************************************************
+** Define memory usage for GKI (if not defined in buildcfg.h)
+** The default for GKI is to use static memory allocation for its control
+** block.
+*/
+#ifndef GKI_DYNAMIC_MEMORY
+#define GKI_DYNAMIC_MEMORY FALSE
+#endif
+
+/****************************************************************************
+** Define memory usage for each CORE component (if not defined in buildcfg.h)
+** The default for each component is to use static memory allocations.
+*/
+#ifndef BTU_DYNAMIC_MEMORY
+#define BTU_DYNAMIC_MEMORY FALSE
+#endif
+
+#ifndef BTM_DYNAMIC_MEMORY
+#define BTM_DYNAMIC_MEMORY FALSE
+#endif
+
+#ifndef SDP_DYNAMIC_MEMORY
+#define SDP_DYNAMIC_MEMORY FALSE
+#endif
+
+#ifndef L2C_DYNAMIC_MEMORY
+#define L2C_DYNAMIC_MEMORY FALSE
+#endif
+
+#ifndef RFC_DYNAMIC_MEMORY
+#define RFC_DYNAMIC_MEMORY FALSE
+#endif
+
+#ifndef TCS_DYNAMIC_MEMORY
+#define TCS_DYNAMIC_MEMORY FALSE
+#endif
+
+#ifndef OBX_DYNAMIC_MEMORY
+#define OBX_DYNAMIC_MEMORY FALSE
+#endif
+
+#ifndef BNEP_DYNAMIC_MEMORY
+#define BNEP_DYNAMIC_MEMORY FALSE
+#endif
+
+#ifndef AVDT_DYNAMIC_MEMORY
+#define AVDT_DYNAMIC_MEMORY FALSE
+#endif
+
+#ifndef AVCT_DYNAMIC_MEMORY
+#define AVCT_DYNAMIC_MEMORY FALSE
+#endif
+
+#ifndef MCA_DYNAMIC_MEMORY
+#define MCA_DYNAMIC_MEMORY FALSE
+#endif
+
+#ifndef GATT_DYNAMIC_MEMORY
+#define GATT_DYNAMIC_MEMORY FALSE
+#endif
+
+#ifndef SMP_DYNAMIC_MEMORY
+#define SMP_DYNAMIC_MEMORY FALSE
+#endif
+
+/****************************************************************************
+** Define memory usage for each PROFILE component (if not defined in buildcfg.h)
+** The default for each component is to use static memory allocations.
+*/
+#ifndef A2D_DYNAMIC_MEMORY
+#define A2D_DYNAMIC_MEMORY FALSE
+#endif
+
+#ifndef VDP_DYNAMIC_MEMORY
+#define VDP_DYNAMIC_MEMORY FALSE
+#endif
+
+#ifndef AVRC_DYNAMIC_MEMORY
+#define AVRC_DYNAMIC_MEMORY FALSE
+#endif
+
+#ifndef BIP_DYNAMIC_MEMORY
+#define BIP_DYNAMIC_MEMORY FALSE
+#endif
+
+#ifndef BPP_DYNAMIC_MEMORY
+#define BPP_DYNAMIC_MEMORY FALSE
+#endif
+
+#ifndef CTP_DYNAMIC_MEMORY
+#define CTP_DYNAMIC_MEMORY FALSE
+#endif
+
+#ifndef DUN_DYNAMIC_MEMORY
+#define DUN_DYNAMIC_MEMORY FALSE
+#endif
+
+#ifndef FTP_DYNAMIC_MEMORY
+#define FTP_DYNAMIC_MEMORY FALSE
+#endif
+
+#ifndef GAP_DYNAMIC_MEMORY
+#define GAP_DYNAMIC_MEMORY FALSE
+#endif
+
+#ifndef GOEP_DYNAMIC_MEMORY
+#define GOEP_DYNAMIC_MEMORY FALSE
+#endif
+
+#ifndef HCRP_DYNAMIC_MEMORY
+#define HCRP_DYNAMIC_MEMORY FALSE
+#endif
+
+#ifndef HFP_DYNAMIC_MEMORY
+#define HFP_DYNAMIC_MEMORY FALSE
+#endif
+
+#ifndef HID_DYNAMIC_MEMORY
+#define HID_DYNAMIC_MEMORY FALSE
+#endif
+
+#ifndef HSP2_DYNAMIC_MEMORY
+#define HSP2_DYNAMIC_MEMORY FALSE
+#endif
+
+#ifndef ICP_DYNAMIC_MEMORY
+#define ICP_DYNAMIC_MEMORY FALSE
+#endif
+
+#ifndef OPP_DYNAMIC_MEMORY
+#define OPP_DYNAMIC_MEMORY FALSE
+#endif
+
+#ifndef PAN_DYNAMIC_MEMORY
+#define PAN_DYNAMIC_MEMORY FALSE
+#endif
+
+#ifndef SPP_DYNAMIC_MEMORY
+#define SPP_DYNAMIC_MEMORY FALSE
+#endif
+
+#ifndef SLIP_DYNAMIC_MEMORY
+#define SLIP_DYNAMIC_MEMORY FALSE
+#endif
+
+#ifndef LLCP_DYNAMIC_MEMORY
+#define LLCP_DYNAMIC_MEMORY FALSE
+#endif
+
+/****************************************************************************
+** Define memory usage for BTA (if not defined in buildcfg.h)
+** The default for each component is to use static memory allocations.
+*/
+#ifndef BTA_DYNAMIC_MEMORY
+#define BTA_DYNAMIC_MEMORY FALSE
+#endif
+
+/****************************************************************************
+** Define memory usage for BT Trace (if not defined in buildcfg.h)
+** The default is to use static memory allocations.
+*/
+#ifndef BTTRC_DYNAMIC_MEMORY
+#define BTTRC_DYNAMIC_MEMORY FALSE
+#endif
+
+#endif /* #ifdef DYN_MEM_H */
+
diff --git a/stack/include/gatt_api.h b/stack/include/gatt_api.h
new file mode 100644
index 0000000..1c64d1b
--- /dev/null
+++ b/stack/include/gatt_api.h
@@ -0,0 +1,1121 @@
+/****************************************************************************
+**
+** Name: gatt_api.h
+** Function this file contains the definitions for the GATT API
+**
+**
+** Copyright (c) 1999-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+******************************************************************************/
+#ifndef GATT_API_H
+#define GATT_API_H
+
+#include "bt_target.h"
+#include "gattdefs.h"
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+/* Success code and error codes */
+#define GATT_SUCCESS 0x0000
+#define GATT_INVALID_HANDLE 0x0001
+#define GATT_READ_NOT_PERMIT 0x0002
+#define GATT_WRITE_NOT_PERMIT 0x0003
+#define GATT_INVALID_PDU 0x0004
+#define GATT_INSUF_AUTHENTICATION 0x0005
+#define GATT_REQ_NOT_SUPPORTED 0x0006
+#define GATT_INVALID_OFFSET 0x0007
+#define GATT_INSUF_AUTHORIZATION 0x0008
+#define GATT_PREPARE_Q_FULL 0x0009
+#define GATT_NOT_FOUND 0x000a
+#define GATT_NOT_LONG 0x000b
+#define GATT_INSUF_KEY_SIZE 0x000c
+#define GATT_INVALID_ATTR_LEN 0x000d
+#define GATT_ERR_UNLIKELY 0x000e
+#define GATT_INSUF_ENCRYPTION 0x000f
+#define GATT_UNSUPPORT_GRP_TYPE 0x0010
+#define GATT_INSUF_RESOURCE 0x0011
+
+
+#define GATT_ILLEGAL_PARAMETER 0x0087
+#define GATT_NO_RESOURCES 0x0080
+#define GATT_INTERNAL_ERROR 0x0081
+#define GATT_WRONG_STATE 0x0082
+#define GATT_DB_FULL 0x0083
+#define GATT_BUSY 0x0084
+#define GATT_ERROR 0x0085
+#define GATT_CMD_STARTED 0x0086
+#define GATT_PENDING 0x0088
+#define GATT_AUTH_FAIL 0x0089
+#define GATT_MORE 0x008a
+#define GATT_INVALID_CFG 0x008b
+#define GATT_SERVICE_STARTED 0x008c
+#define GATT_ENCRYPED_MITM GATT_SUCCESS
+#define GATT_ENCRYPED_NO_MITM 0x008d
+#define GATT_NOT_ENCRYPTED 0x008e
+
+
+typedef UINT8 tGATT_STATUS;
+
+
+#define GATT_RSP_ERROR 0x01
+#define GATT_REQ_MTU 0x02
+#define GATT_RSP_MTU 0x03
+#define GATT_REQ_FIND_INFO 0x04
+#define GATT_RSP_FIND_INFO 0x05
+#define GATT_REQ_FIND_TYPE_VALUE 0x06
+#define GATT_RSP_FIND_TYPE_VALUE 0x07
+#define GATT_REQ_READ_BY_TYPE 0x08
+#define GATT_RSP_READ_BY_TYPE 0x09
+#define GATT_REQ_READ 0x0A
+#define GATT_RSP_READ 0x0B
+#define GATT_REQ_READ_BLOB 0x0C
+#define GATT_RSP_READ_BLOB 0x0D
+#define GATT_REQ_READ_MULTI 0x0E
+#define GATT_RSP_READ_MULTI 0x0F
+#define GATT_REQ_READ_BY_GRP_TYPE 0x10
+#define GATT_RSP_READ_BY_GRP_TYPE 0x11
+#define GATT_REQ_WRITE 0x12 /* 0001-0010 (write)*/
+#define GATT_RSP_WRITE 0x13
+#define GATT_CMD_WRITE 0x52 /* changed in V4.0 01001-0010(write cmd)*/
+#define GATT_REQ_PREPARE_WRITE 0x16
+#define GATT_RSP_PREPARE_WRITE 0x17
+#define GATT_REQ_EXEC_WRITE 0x18
+#define GATT_RSP_EXEC_WRITE 0x19
+#define GATT_HANDLE_VALUE_NOTIF 0x1B
+#define GATT_HANDLE_VALUE_IND 0x1D
+#define GATT_HANDLE_VALUE_CONF 0x1E
+#define GATT_SIGN_CMD_WRITE 0xD2 /* changed in V4.0 1101-0010 (signed write) see write cmd above*/
+#define GATT_OP_CODE_MAX GATT_HANDLE_VALUE_CONF + 1 /* 0x1E = 30 + 1 = 31*/
+
+
+#define GATT_HANDLE_IS_VALID(x) ((x) != 0)
+
+#define GATT_CONN_UNKNOWN 0
+#define GATT_CONN_NO_RESOURCES L2CAP_CONN_NO_RESOURCES /* connection fail for l2cap resource failure */
+#define GATT_CONN_TIMEOUT HCI_ERR_CONNECTION_TOUT /* 0x08 connection timeout */
+#define GATT_CONN_TERMINATE_PEER_USER HCI_ERR_PEER_USER /* 0x13 connection terminate by peer user */
+#define GATT_CONN_TERMINATE_LOCAL_HOST HCI_ERR_CONN_CAUSE_LOCAL_HOST /* 0x16 connectionterminated by local host */
+#define GATT_CONN_FAIL_ESTABLISH HCI_ERR_CONN_FAILED_ESTABLISHMENT/* 0x03E connection fail to establish */
+#define GATT_CONN_LMP_TIMEOUT HCI_ERR_LMP_RESPONSE_TIMEOUT /* 0x22 connection fail for LMP response tout */
+#define GATT_CONN_CANCEL L2CAP_CONN_CANCEL /* 0x0100 L2CAP connection cancelled */
+typedef UINT16 tGATT_DISCONN_REASON;
+
+/* MAX GATT MTU size
+*/
+#ifndef GATT_MAX_MTU_SIZE
+ #define GATT_MAX_MTU_SIZE 517
+#endif
+
+/* max legth of an attribute value
+*/
+#ifndef GATT_MAX_ATTR_LEN
+ #define GATT_MAX_ATTR_LEN 600
+#endif
+
+/* default GATT MTU size over LE link
+*/
+#define GATT_DEF_BLE_MTU_SIZE 23
+
+/* invalid connection ID
+*/
+#define GATT_INVALID_CONN_ID 0xFFFF
+
+#ifndef GATT_CL_MAX_LCB
+ #define GATT_CL_MAX_LCB 22
+#endif
+
+#ifndef GATT_MAX_SCCB
+ #define GATT_MAX_SCCB 10
+#endif
+
+
+
+/* GATT notification caching timer, default to be three seconds
+*/
+#ifndef GATTC_NOTIF_TIMEOUT
+ #define GATTC_NOTIF_TIMEOUT 3
+#endif
+
+/*****************************************************************************
+** GATT Structure Definition
+*****************************************************************************/
+
+/* Attribute permissions
+*/
+#define GATT_PERM_READ (1 << 0) /* bit 0 */
+#define GATT_PERM_READ_ENCRYPTED (1 << 1) /* bit 1 */
+#define GATT_PERM_READ_ENC_MITM (1 << 2) /* bit 2 */
+#define GATT_PERM_WRITE (1 << 4) /* bit 4 */
+#define GATT_PERM_WRITE_ENCRYPTED (1 << 5) /* bit 5 */
+#define GATT_PERM_WRITE_ENC_MITM (1 << 6) /* bit 6 */
+#define GATT_PERM_WRITE_SIGNED (1 << 7) /* bit 7 */
+#define GATT_PERM_WRITE_SIGNED_MITM (1 << 8) /* bit 8 */
+typedef UINT16 tGATT_PERM;
+
+#define GATT_ENCRYPT_KEY_SIZE_MASK (0xF000) /* the MS nibble of tGATT_PERM; key size 7=0; size 16=9 */
+
+#define GATT_READ_ALLOWED (GATT_PERM_READ | GATT_PERM_READ_ENCRYPTED | GATT_PERM_READ_ENC_MITM)
+#define GATT_READ_AUTH_REQUIRED (GATT_PERM_READ_ENC_MITM)
+#define GATT_READ_MITM_REQUIRED (GATT_PERM_READ_ENC_MITM)
+#define GATT_READ_ENCRYPTED_REQUIRED (GATT_PERM_READ_ENCRYPTED | GATT_PERM_READ_ENC_MITM)
+
+
+#define GATT_WRITE_ALLOWED (GATT_PERM_WRITE | GATT_PERM_WRITE_ENCRYPTED | GATT_PERM_WRITE_ENC_MITM | \
+ GATT_PERM_WRITE_SIGNED | GATT_PERM_WRITE_SIGNED_MITM)
+
+#define GATT_WRITE_AUTH_REQUIRED (GATT_PERM_WRITE_ENCRYPTED | GATT_PERM_WRITE_SIGNED)
+
+#define GATT_WRITE_MITM_REQUIRED (GATT_PERM_WRITE_ENC_MITM | GATT_PERM_WRITE_SIGNED_MITM)
+
+#define GATT_WRITE_ENCRYPTED_PERM (GATT_PERM_WRITE_ENCRYPTED | GATT_PERM_WRITE_ENC_MITM)
+
+#define GATT_WRITE_SIGNED_PERM (GATT_PERM_WRITE_SIGNED | GATT_PERM_WRITE_SIGNED_MITM)
+
+
+/* Characteristic properties
+*/
+#define GATT_CHAR_PROP_BIT_BROADCAST (1 << 0)
+#define GATT_CHAR_PROP_BIT_READ (1 << 1)
+#define GATT_CHAR_PROP_BIT_WRITE_NR (1 << 2)
+#define GATT_CHAR_PROP_BIT_WRITE (1 << 3)
+#define GATT_CHAR_PROP_BIT_NOTIFY (1 << 4)
+#define GATT_CHAR_PROP_BIT_INDICATE (1 << 5)
+#define GATT_CHAR_PROP_BIT_AUTH (1 << 6)
+#define GATT_CHAR_PROP_BIT_EXT_PROP (1 << 7)
+typedef UINT8 tGATT_CHAR_PROP;
+
+
+/* Format of the value of a characteristic. enumeration type
+*/
+enum
+{
+ GATT_FORMAT_RES, /* rfu */
+ GATT_FORMAT_BOOL, /* 0x01 boolean */
+ GATT_FORMAT_2BITS, /* 0x02 2 bit */
+ GATT_FORMAT_NIBBLE, /* 0x03 nibble */
+ GATT_FORMAT_UINT8, /* 0x04 uint8 */
+ GATT_FORMAT_UINT12, /* 0x05 uint12 */
+ GATT_FORMAT_UINT16, /* 0x06 uint16 */
+ GATT_FORMAT_UINT24, /* 0x07 uint24 */
+ GATT_FORMAT_UINT32, /* 0x08 uint32 */
+ GATT_FORMAT_UINT48, /* 0x09 uint48 */
+ GATT_FORMAT_UINT64, /* 0x0a uint64 */
+ GATT_FORMAT_UINT128, /* 0x0B uint128 */
+ GATT_FORMAT_SINT8, /* 0x0C signed 8 bit integer */
+ GATT_FORMAT_SINT12, /* 0x0D signed 12 bit integer */
+ GATT_FORMAT_SINT16, /* 0x0E signed 16 bit integer */
+ GATT_FORMAT_SINT24, /* 0x0F signed 24 bit integer */
+ GATT_FORMAT_SINT32, /* 0x10 signed 32 bit integer */
+ GATT_FORMAT_SINT48, /* 0x11 signed 48 bit integer */
+ GATT_FORMAT_SINT64, /* 0x12 signed 64 bit integer */
+ GATT_FORMAT_SINT128, /* 0x13 signed 128 bit integer */
+ GATT_FORMAT_FLOAT32, /* 0x14 float 32 */
+ GATT_FORMAT_FLOAT64, /* 0x15 float 64*/
+ GATT_FORMAT_SFLOAT, /* 0x16 IEEE-11073 16 bit SFLOAT */
+ GATT_FORMAT_FLOAT, /* 0x17 IEEE-11073 32 bit SFLOAT */
+ GATT_FORMAT_DUINT16, /* 0x18 IEEE-20601 format */
+ GATT_FORMAT_UTF8S, /* 0x19 UTF-8 string */
+ GATT_FORMAT_UTF16S, /* 0x1a UTF-16 string */
+ GATT_FORMAT_STRUCT, /* 0x1b Opaque structure*/
+ GATT_FORMAT_MAX /* 0x1c or above reserved */
+};
+typedef UINT8 tGATT_FORMAT;
+
+/* Characteristic Presentation Format Descriptor value
+*/
+typedef struct
+{
+ UINT16 unit; /* as UUIUD defined by SIG */
+ UINT16 descr; /* as UUID as defined by SIG */
+ tGATT_FORMAT format;
+ INT8 exp;
+ UINT8 name_spc; /* The name space of the description */
+} tGATT_CHAR_PRES;
+
+#define GATT_VALID_RANGE_MAX_SIZE 16
+typedef struct
+{
+ UINT8 format;
+ UINT16 len;
+ UINT8 lower_range[GATT_VALID_RANGE_MAX_SIZE]; /* in little endian format */
+ UINT8 upper_range[GATT_VALID_RANGE_MAX_SIZE];
+} tGATT_VALID_RANGE;
+
+/* Characteristic Aggregate Format attribute value
+*/
+#define GATT_AGGR_HANDLE_NUM_MAX 10
+typedef struct
+{
+ UINT8 num_handle;
+ UINT16 handle_list[GATT_AGGR_HANDLE_NUM_MAX];
+} tGATT_CHAR_AGGRE;
+
+/* Characteristic descriptor: Extended Properties value
+*/
+#define GATT_CHAR_BIT_REL_WRITE 0x0001 /* permits reliable writes of the Characteristic Value */
+#define GATT_CHAR_BIT_WRITE_AUX 0x0002 /* permits writes to the characteristic descriptor */
+
+
+/* characteristic descriptor: client configuration value
+*/
+#define GATT_CLT_CONFIG_NONE 0x0000
+#define GATT_CLT_CONFIG_NOTIFICATION 0x0001
+#define GATT_CLT_CONFIG_INDICATION 0x0002
+typedef UINT16 tGATT_CLT_CHAR_CONFIG;
+
+
+/* characteristic descriptor: server configuration value
+*/
+#define GATT_SVR_CONFIG_NONE 0x0000
+#define GATT_SVR_CONFIG_BROADCAST 0x0001
+typedef UINT16 tGATT_SVR_CHAR_CONFIG;
+
+/* Characteristic descriptor: Extended Properties value
+*/
+#define GATT_CHAR_BIT_REL_WRITE 0x0001 /* permits reliable writes of the Characteristic Value */
+#define GATT_CHAR_BIT_WRITE_AUX 0x0002 /* permits writes to the characteristic descriptor */
+
+/* authentication requirement
+*/
+#define GATT_AUTH_REQ_NONE 0
+#define GATT_AUTH_REQ_NO_MITM 1 /* unauthenticated encryption */
+#define GATT_AUTH_REQ_MITM 2 /* authenticated encryption */
+#define GATT_AUTH_REQ_SIGNED_NO_MITM 3
+#define GATT_AUTH_REQ_SIGNED_MITM 4
+typedef UINT8 tGATT_AUTH_REQ;
+
+/* Attribute Value structure
+*/
+typedef struct
+{
+ UINT16 conn_id;
+ UINT16 handle; /* attribute handle */
+ UINT16 offset; /* attribute value offset, if no offfset is needed for the command, ignore it */
+ UINT16 len; /* length of attribute value */
+ tGATT_AUTH_REQ auth_req; /* authentication request */
+ UINT8 value[GATT_MAX_ATTR_LEN]; /* the actual attribute value */
+} tGATT_VALUE;
+
+/* Union of the event data which is used in the server respond API to carry the server response information
+*/
+typedef union
+{
+ /* data type member event */
+ tGATT_VALUE attr_value; /* READ, HANDLE_VALUE_IND, PREPARE_WRITE */
+ /* READ_BLOB, READ_BY_TYPE */
+ UINT16 handle; /* WRITE, WRITE_BLOB */
+
+} tGATTS_RSP;
+
+/* Transports for the primary service */
+enum
+{
+ GATT_TRANSPORT_LE,
+ GATT_TRANSPORT_BR_EDR,
+ GATT_TRANSPORT_LE_BR_EDR
+};
+typedef UINT8 tGATT_TRANSPORT;
+
+#define GATT_PREP_WRITE_CANCEL 0x00
+#define GATT_PREP_WRITE_EXEC 0x01
+typedef UINT8 tGATT_EXEC_FLAG;
+
+/* read request always based on UUID */
+typedef struct
+{
+ UINT16 handle;
+ UINT16 offset;
+ BOOLEAN is_long;
+} tGATT_READ_REQ;
+
+/* write request data */
+typedef struct
+{
+ UINT16 handle; /* attribute handle */
+ UINT16 offset; /* attribute value offset, if no offfset is needed for the command, ignore it */
+ UINT16 len; /* length of attribute value */
+ UINT8 value[GATT_MAX_ATTR_LEN]; /* the actual attribute value */
+ BOOLEAN need_rsp; /* need write response */
+ BOOLEAN is_prep; /* is prepare write */
+} tGATT_WRITE_REQ;
+
+/* callback data for server access request from client */
+typedef union
+{
+ tGATT_READ_REQ read_req; /* read request, read by Type, read blob */
+
+ tGATT_WRITE_REQ write_req; /* write */
+ /* prepare write */
+ /* write blob */
+ UINT16 handle; /* handle value confirmation */
+ UINT16 mtu; /* MTU exchange request */
+ tGATT_EXEC_FLAG exec_write; /* execute write */
+} tGATTS_DATA;
+
+typedef UINT8 tGATT_SERV_IF; /* GATT Service Interface */
+
+enum
+{
+ GATTS_REQ_TYPE_READ = 1, /* Attribute read request */
+ GATTS_REQ_TYPE_WRITE, /* Attribute write request */
+ GATTS_REQ_TYPE_WRITE_EXEC, /* Execute write */
+ GATTS_REQ_TYPE_MTU, /* MTU exchange information */
+ GATTS_REQ_TYPE_CONF /* handle value confirmation */
+};
+typedef UINT8 tGATTS_REQ_TYPE;
+
+
+
+/* Client Used Data Structure
+*/
+/* definition of different discovery types */
+enum
+{
+ GATT_DISC_SRVC_ALL = 1, /* discover all services */
+ GATT_DISC_SRVC_BY_UUID, /* discover service of a special type */
+ GATT_DISC_INC_SRVC, /* discover the included service within a service */
+ GATT_DISC_CHAR, /* discover characteristics of a service with/without type requirement */
+ GATT_DISC_CHAR_DSCPT, /* discover characteristic descriptors of a character */
+ GATT_DISC_MAX /* maximnun discover type */
+};
+typedef UINT8 tGATT_DISC_TYPE;
+
+/* Discover parameters of different discovery types
+*/
+typedef struct
+{
+ tBT_UUID service;
+ UINT16 s_handle;
+ UINT16 e_handle;
+}tGATT_DISC_PARAM;
+
+/* GATT read type enumeration
+*/
+enum
+{
+ GATT_READ_BY_TYPE = 1,
+ GATT_READ_BY_HANDLE,
+ GATT_READ_MULTIPLE,
+ GATT_READ_CHAR_VALUE,
+ GATT_READ_PARTIAL,
+ GATT_READ_MAX
+};
+typedef UINT8 tGATT_READ_TYPE;
+
+/* Read By Type Request (GATT_READ_BY_TYPE) Data
+*/
+typedef struct
+{
+ tGATT_AUTH_REQ auth_req;
+ UINT16 s_handle;
+ UINT16 e_handle;
+ tBT_UUID uuid;
+} tGATT_READ_BY_TYPE;
+
+/* GATT_READ_MULTIPLE request data
+*/
+#define GATT_MAX_READ_MULTI_HANDLES 10 /* Max attributes to read in one request */
+typedef struct
+{
+ tGATT_AUTH_REQ auth_req;
+ UINT16 num_handles; /* number of handles to read */
+ UINT16 handles[GATT_MAX_READ_MULTI_HANDLES]; /* handles list to be read */
+} tGATT_READ_MULTI;
+
+/* Read By Handle Request (GATT_READ_BY_HANDLE) data */
+typedef struct
+{
+ tGATT_AUTH_REQ auth_req;
+ UINT16 handle;
+} tGATT_READ_BY_HANDLE;
+
+/* READ_BT_HANDLE_Request data */
+typedef struct
+{
+ tGATT_AUTH_REQ auth_req;
+ UINT16 handle;
+ UINT16 offset;
+} tGATT_READ_PARTIAL;
+
+/* Read Request Data
+*/
+typedef union
+{
+ tGATT_READ_BY_TYPE service;
+ tGATT_READ_BY_TYPE char_type; /* characterisitc type */
+ tGATT_READ_MULTI read_multiple;
+ tGATT_READ_BY_HANDLE by_handle;
+ tGATT_READ_PARTIAL partial;
+} tGATT_READ_PARAM;
+
+/* GATT write type enumeration */
+enum
+{
+ GATT_WRITE_NO_RSP = 1,
+ GATT_WRITE ,
+ GATT_WRITE_PREPARE
+};
+typedef UINT8 tGATT_WRITE_TYPE;
+
+/* Client Operation Complete Callback Data
+*/
+typedef union
+{
+ tGATT_VALUE att_value;
+ UINT16 mtu;
+ UINT16 handle;
+} tGATT_CL_COMPLETE;
+
+/* GATT client operation type, used in client callback function
+*/
+#define GATTC_OPTYPE_NONE 0
+#define GATTC_OPTYPE_DISCOVERY 1
+#define GATTC_OPTYPE_READ 2
+#define GATTC_OPTYPE_WRITE 3
+#define GATTC_OPTYPE_EXE_WRITE 4
+#define GATTC_OPTYPE_CONFIG 5
+#define GATTC_OPTYPE_NOTIFICATION 6
+#define GATTC_OPTYPE_INDICATION 7
+typedef UINT8 tGATTC_OPTYPE;
+
+/* characteristic declaration
+*/
+typedef struct
+{
+ tGATT_CHAR_PROP char_prop; /* characterisitc properties */
+ UINT16 val_handle; /* characteristic value attribute handle */
+ tBT_UUID char_uuid; /* characteristic UUID type */
+} tGATT_CHAR_DCLR_VAL;
+
+/* primary service group data
+*/
+typedef struct
+{
+ UINT16 e_handle; /* ending handle of the group */
+ tBT_UUID service_type; /* group type */
+} tGATT_GROUP_VALUE;
+
+
+/* included service attribute value
+*/
+typedef struct
+{
+ tBT_UUID service_type; /* included service UUID */
+ UINT16 s_handle; /* starting handle */
+ UINT16 e_handle; /* ending handle */
+} tGATT_INCL_SRVC;
+
+typedef union
+{
+ tGATT_INCL_SRVC incl_service; /* include service value */
+ tGATT_GROUP_VALUE group_value; /* Service UUID type.
+ This field is used with GATT_DISC_SRVC_ALL
+ type of discovery result callback. */
+
+ UINT16 handle; /* When used with GATT_DISC_SRVC_BY_UUID type
+ discovery result, it is the ending handle of a
+ known service to be discovered. When used with
+ GATT_DISC_INC_SRVC type discovery result,
+ it is the included service starting handle.*/
+
+ tGATT_CHAR_DCLR_VAL dclr_value; /* Characteristic declaration value.
+ This field is used with GATT_DISC_CHAR type discovery.*/
+} tGATT_DISC_VALUE;
+
+/* discover result record
+*/
+typedef struct
+{
+ tBT_UUID type;
+ UINT16 handle;
+ tGATT_DISC_VALUE value;
+} tGATT_DISC_RES;
+
+
+typedef UINT8 tGATT_IF;
+#define GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP 0 /* start a idle timer for this duration when no application
+ need to use the link */
+
+#define GATT_LINK_NO_IDLE_TIMEOUT 0xFFFF
+
+#define GATT_INVALID_ACL_HANDLE 0xFFFF
+/* discover result callback function */
+typedef void (tGATT_DISC_RES_CB) (UINT16 conn_id, tGATT_DISC_TYPE disc_type, tGATT_DISC_RES *p_data);
+
+/* discover complete callback function */
+typedef void (tGATT_DISC_CMPL_CB) (UINT16 conn_id, tGATT_DISC_TYPE disc_type, tGATT_STATUS status);
+
+/* Define a callback function for when read/write/disc/config operation is completed. */
+typedef void (tGATT_CMPL_CBACK) (UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS status, tGATT_CL_COMPLETE *p_data);
+
+/* Define a callback function when an initialized connection is established. */
+typedef void (tGATT_CONN_CBACK) (tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id, BOOLEAN connected, tGATT_DISCONN_REASON reason);
+
+/* attribute request callback for ATT server */
+typedef void (tGATT_REQ_CBACK )(UINT16 conn_id, UINT32 trans_id, tGATTS_REQ_TYPE type, tGATTS_DATA *p_data);
+
+
+
+
+/* Define the structure that applications use to register with
+** GATT. This structure includes callback functions. All functions
+** MUST be provided.
+*/
+typedef struct
+{
+ tGATT_CONN_CBACK *p_conn_cb;
+ tGATT_CMPL_CBACK *p_cmpl_cb;
+ tGATT_DISC_RES_CB *p_disc_res_cb;
+ tGATT_DISC_CMPL_CB *p_disc_cmpl_cb;
+ tGATT_REQ_CBACK *p_req_cb;
+} tGATT_CBACK;
+
+/*********************** Start Handle Management Definitions **********************
+*/
+
+
+typedef struct
+{
+ tBT_UUID app_uuid128;
+ tBT_UUID svc_uuid;
+ UINT16 svc_inst;
+ UINT16 s_handle;
+ UINT16 e_handle;
+ BOOLEAN is_primary; /* primary service or secondary */
+} tGATTS_HNDL_RANGE;
+
+
+
+#define GATTS_SRV_CHG_CMD_ADD_CLIENT 1
+#define GATTS_SRV_CHG_CMD_UPDATE_CLIENT 2
+#define GATTS_SRV_CHG_CMD_REMOVE_CLIENT 3
+#define GATTS_SRV_CHG_CMD_READ_NUM_CLENTS 4
+#define GATTS_SRV_CHG_CMD_READ_CLENT 5
+typedef UINT8 tGATTS_SRV_CHG_CMD;
+
+typedef struct
+{
+ BD_ADDR bda;
+ BOOLEAN srv_changed;
+} tGATTS_SRV_CHG;
+
+
+typedef union
+{
+ tGATTS_SRV_CHG srv_chg;
+ UINT8 client_read_index; /* only used for sequential reading client srv chg info */
+} tGATTS_SRV_CHG_REQ;
+
+typedef union
+{
+ tGATTS_SRV_CHG srv_chg;
+ UINT8 num_clients;
+} tGATTS_SRV_CHG_RSP;
+
+
+
+typedef struct
+{
+ tGATTS_HNDL_RANGE *p_new_srv_start;
+} tGATTS_PENDING_NEW_SRV_START;
+
+/* Attibute server handle ranges NV storage callback functions
+*/
+typedef void (tGATTS_NV_SAVE_CBACK)(BOOLEAN is_saved, tGATTS_HNDL_RANGE *p_hndl_range);
+typedef BOOLEAN (tGATTS_NV_SRV_CHG_CBACK)(tGATTS_SRV_CHG_CMD cmd, tGATTS_SRV_CHG_REQ *p_req, tGATTS_SRV_CHG_RSP *p_rsp);
+
+typedef struct
+{
+ tGATTS_NV_SAVE_CBACK *p_nv_save_callback;
+ tGATTS_NV_SRV_CHG_CBACK *p_srv_chg_callback;
+} tGATT_APPL_INFO;
+
+/*
+*********************** End Handle Management Definitions **********************/
+
+/*****************************************************************************
+** External Function Declarations
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*******************************************************************************
+**
+** Function GATT_SetTraceLevel
+**
+** Description This function sets the trace level. If called with
+** a value of 0xFF, it simply returns the current trace level.
+**
+** Returns The new or current trace level
+**
+*******************************************************************************/
+ GATT_API extern UINT8 GATT_SetTraceLevel (UINT8 new_level);
+
+
+/*******************************************************************************/
+/* GATT Profile API Functions */
+/*******************************************************************************/
+/* GATT Profile Server Functions */
+/*******************************************************************************/
+/*******************************************************************************
+**
+** Function GATTS_AddHandleRange
+**
+** Description This function add the allocated handles range for the specifed
+** application UUID, service UUID and service instance
+**
+** Parameter p_hndl_range: pointer to allocated handles information
+**
+** Returns TRUE if handle range is added sucessfully; otherwise FALSE.
+**
+*******************************************************************************/
+
+ GATT_API extern BOOLEAN GATTS_AddHandleRange(tGATTS_HNDL_RANGE *p_hndl_range);
+
+/*******************************************************************************
+**
+** Function GATTS_NVRegister
+**
+** Description Application manager calls this function to register for
+** NV save callback function. There can be one and only one
+** NV save callback function.
+**
+** Parameter p_cb_info : callback informaiton
+**
+** Returns TRUE if registered OK, else FALSE
+**
+*******************************************************************************/
+ GATT_API extern BOOLEAN GATTS_NVRegister (tGATT_APPL_INFO *p_cb_info);
+
+
+/*******************************************************************************
+**
+** Function GATTS_CreateService
+**
+** Description This function is called to reserve a block of handles for a service.
+**
+** *** It should be called only once per service instance ***
+**
+** Parameter gatt_if : application if
+** p_svc_uuid : service UUID
+** svc_inst : instance of the service inside the application
+** num_handles : number of handles needed by the service.
+** is_pri : is a primary service or not.
+**
+** Returns service handle if sucessful, otherwise 0.
+**
+*******************************************************************************/
+ GATT_API extern UINT16 GATTS_CreateService (tGATT_IF gatt_if, tBT_UUID *p_svc_uuid,
+ UINT16 svc_inst, UINT16 num_handles, BOOLEAN is_pri);
+
+
+/*******************************************************************************
+**
+** Function GATTS_AddIncludeService
+**
+** Description This function is called to add an included service.
+**
+** Parameter service_handle : To which service this included service is added to.
+** include_svc_handle : included service handle.
+**
+** Returns included service attribute handle. If 0, add included service
+** fail.
+**
+*******************************************************************************/
+ GATT_API extern UINT16 GATTS_AddIncludeService (UINT16 service_handle,
+ UINT16 include_svc_handle);
+
+
+/*******************************************************************************
+**
+** Function GATTS_AddCharacteristic
+**
+** Description This function is called to add a characteristic into a service.
+** It will add a characteristic declaration and characteristic
+** value declaration into the service database identified by the
+** service handle.
+**
+** Parameter service_handle : To which service this included service is added to.
+** char_uuid : Characteristic UUID.
+** perm : Characteristic value declaration attribute permission.
+** property : Characteristic Properties
+**
+** Returns Characteristic value declaration attribute handle. 0 if add
+** characteristic failed.
+**
+*******************************************************************************/
+ GATT_API extern UINT16 GATTS_AddCharacteristic (UINT16 service_handle, tBT_UUID *char_uuid,
+ tGATT_PERM perm,tGATT_CHAR_PROP property);
+
+/*******************************************************************************
+**
+** Function GATTS_AddCharDescriptor
+**
+** Description This function is called to add a characteristic descriptor
+** into a service database. Add descriptor should follow add char
+** to which it belongs, and next add char should be done only
+** after all add descriptors for the previous char.
+**
+** Parameter service_handle : To which service this characteristic descriptor
+** is added to.
+** perm : Characteristic value declaration attribute
+** permission.
+** p_descr_uuid : Characteristic descriptor UUID.
+**
+** Returns Characteristic descriptor attribute handle. 0 if add
+** characteristic descriptor failed.
+**
+*******************************************************************************/
+ GATT_API extern UINT16 GATTS_AddCharDescriptor (UINT16 service_handle, tGATT_PERM perm,
+ tBT_UUID * p_descr_uuid);
+
+/*******************************************************************************
+**
+** Function GATTS_DeleteService
+**
+** Description This function is called to delete a service.
+**
+** Parameter gatt_if : application interface
+** p_svc_uuid : service UUID
+** svc_inst : instance of the service inside the application
+**
+** Returns TRUE if operation succeed, FALSE if handle block was not found.
+**
+*******************************************************************************/
+ GATT_API extern BOOLEAN GATTS_DeleteService (tGATT_IF gatt_if, tBT_UUID *p_svc_uuid, UINT16 svc_inst);
+
+/*******************************************************************************
+**
+** Function GATTS_StartService
+**
+** Description This function is called to start a service with GATT
+**
+** Parameter gatt_if : service handle.
+** p_cback : application service callback functions.
+** sup_transport : supported transport(s) for this primary service
+**
+** return GATT_SUCCESS if sucessfully started; otherwise error code.
+**
+*******************************************************************************/
+ GATT_API extern tGATT_STATUS GATTS_StartService (tGATT_IF gatt_if, UINT16 service_handle,
+ tGATT_TRANSPORT sup_transport);
+
+
+/*******************************************************************************
+**
+** Function GATTS_StopService
+**
+** Description This function is called to stop a service
+**
+** Parameter service_handle : this is the start handle of a service
+**
+** Returns None.
+**
+*******************************************************************************/
+ GATT_API extern void GATTS_StopService (UINT16 service_handle);
+
+
+/*******************************************************************************
+**
+** Function GATTs_HandleValueIndication
+**
+** Description This function sends a handle value indication to a client.
+**
+** Parameter conn_id: connection identifier.
+** attr_handle: Attribute handle of this handle value indication.
+** val_len: Length of the indicated attribute value.
+** p_val: Pointer to the indicated attribute value data.
+**
+** Returns GATT_SUCCESS if sucessfully sent or queued; otherwise error code.
+**
+*******************************************************************************/
+ GATT_API extern tGATT_STATUS GATTS_HandleValueIndication (UINT16 conn_id,
+ UINT16 attr_handle,
+ UINT16 val_len, UINT8 *p_val);
+
+/*******************************************************************************
+**
+** Function GATTS_HandleValueNotification
+**
+** Description This function sends a handle value notification to a client.
+**
+** Parameter conn_id: connection identifier.
+** attr_handle: Attribute handle of this handle value indication.
+** val_len: Length of the indicated attribute value.
+** p_val: Pointer to the indicated attribute value data.
+**
+** Returns GATT_SUCCESS if sucessfully sent; otherwise error code.
+**
+*******************************************************************************/
+ GATT_API extern tGATT_STATUS GATTS_HandleValueNotification (UINT16 conn_id, UINT16 attr_handle,
+ UINT16 val_len, UINT8 *p_val);
+
+
+/*******************************************************************************
+**
+** Function GATTS_SendRsp
+**
+** Description This function sends the server response to client.
+**
+** Parameter conn_id: connection identifier.
+** trans_id: transaction id
+** status: response status
+** p_msg: pointer to message parameters structure.
+**
+** Returns GATT_SUCCESS if sucessfully sent; otherwise error code.
+**
+*******************************************************************************/
+ GATT_API extern tGATT_STATUS GATTS_SendRsp (UINT16 conn_id, UINT32 trans_id,
+ tGATT_STATUS status, tGATTS_RSP *p_msg);
+
+
+/*******************************************************************************/
+/* GATT Profile Client Functions */
+/*******************************************************************************/
+
+/*******************************************************************************
+**
+** Function GATTC_ConfigureMTU
+**
+** Description This function is called to configure the ATT MTU size for
+** a connection on an LE transport.
+**
+** Parameters conn_id: connection identifier.
+** mtu - attribute MTU size..
+**
+** Returns GATT_SUCCESS if command started successfully.
+**
+*******************************************************************************/
+ GATT_API extern tGATT_STATUS GATTC_ConfigureMTU (UINT16 conn_id, UINT16 mtu);
+
+/*******************************************************************************
+**
+** Function GATTC_Discover
+**
+** Description This function is called to do a discovery procedure on ATT server.
+**
+** Parameters conn_id: connection identifier.
+** disc_type:discovery type.
+** p_param: parameters of discovery requirement.
+**
+** Returns GATT_SUCCESS if command received/sent successfully.
+**
+*******************************************************************************/
+ GATT_API extern tGATT_STATUS GATTC_Discover (UINT16 conn_id,
+ tGATT_DISC_TYPE disc_type,
+ tGATT_DISC_PARAM *p_param );
+/*******************************************************************************
+**
+** Function GATTC_Read
+**
+** Description This function is called to read the value of an attribute from
+** the server.
+**
+** Parameters conn_id: connection identifier.
+** type - attribute read type.
+** p_read - read operation parameters.
+**
+** Returns GATT_SUCCESS if command started successfully.
+**
+*******************************************************************************/
+ GATT_API extern tGATT_STATUS GATTC_Read (UINT16 conn_id, tGATT_READ_TYPE type,
+ tGATT_READ_PARAM *p_read);
+
+/*******************************************************************************
+**
+** Function GATTC_Write
+**
+** Description This function is called to read the value of an attribute from
+** the server.
+**
+** Parameters conn_id: connection identifier.
+** type - attribute write type.
+** p_write - write operation parameters.
+**
+** Returns GATT_SUCCESS if command started successfully.
+**
+*******************************************************************************/
+ GATT_API extern tGATT_STATUS GATTC_Write (UINT16 conn_id, tGATT_WRITE_TYPE type,
+ tGATT_VALUE *p_write);
+
+
+/*******************************************************************************
+**
+** Function GATTC_ExecuteWrite
+**
+** Description This function is called to send an Execute write request to
+** the server.
+**
+** Parameters conn_id: connection identifier.
+** is_execute - to execute or cancel the prepare write requet(s)
+**
+** Returns GATT_SUCCESS if command started successfully.
+**
+*******************************************************************************/
+ GATT_API extern tGATT_STATUS GATTC_ExecuteWrite (UINT16 conn_id, BOOLEAN is_execute);
+
+/*******************************************************************************
+**
+** Function GATTC_SendHandleValueConfirm
+**
+** Description This function is called to send a handle value confirmation
+** as response to a handle value notification from server.
+**
+** Parameters conn_id: connection identifier.
+** handle: the handle of the attribute confirmation.
+**
+** Returns GATT_SUCCESS if command started successfully.
+**
+*******************************************************************************/
+ GATT_API extern tGATT_STATUS GATTC_SendHandleValueConfirm (UINT16 conn_id, UINT16 handle);
+
+
+/*******************************************************************************
+**
+** Function GATT_SetIdleTimeout
+**
+** Description This function (common to both client and server) sets the idle
+** timeout for a tansport connection
+**
+** Parameter bd_addr: target device bd address.
+** idle_tout: timeout value in seconds.
+**
+** Returns void
+**
+*******************************************************************************/
+ GATT_API extern void GATT_SetIdleTimeout (BD_ADDR bd_addr, UINT16 idle_tout);
+
+
+/*******************************************************************************
+**
+** Function GATT_Register
+**
+** Description This function is called to register an application
+** with GATT
+**
+** Parameter p_app_uuid128: Application UUID
+** p_cb_info: callback functions.
+**
+** Returns 0 for error, otherwise the index of the client registered with GATT
+**
+*******************************************************************************/
+ GATT_API extern tGATT_IF GATT_Register (tBT_UUID *p_app_uuid128, tGATT_CBACK *p_cb_info);
+
+/*******************************************************************************
+**
+** Function GATT_Deregister
+**
+** Description This function deregistered the application from GATT.
+**
+** Parameters gatt_if: applicaiton interface.
+**
+** Returns None.
+**
+*******************************************************************************/
+ GATT_API extern void GATT_Deregister (tGATT_IF gatt_if);
+
+/*******************************************************************************
+**
+** Function GATT_StartIf
+**
+** Description This function is called after registration to start receiving
+** callbacks for registered interface. Function may call back
+** with connection status and queued notifications
+**
+** Parameter gatt_if: applicaiton interface.
+**
+** Returns None
+**
+*******************************************************************************/
+ GATT_API extern void GATT_StartIf (tGATT_IF gatt_if);
+
+/*******************************************************************************
+**
+** Function GATT_Connect
+**
+** Description This function initiate a connecttion to a ATT server.
+**
+** Parameters gatt_if: applicaiton interface
+** bd_addr: peer device address.
+** is_direct: is a direct conenection or a background auto connection
+**
+** Returns TRUE if connection started; FALSE if connection start failure.
+**
+*******************************************************************************/
+ GATT_API extern BOOLEAN GATT_Connect (tGATT_IF gatt_if, BD_ADDR bd_addr, BOOLEAN is_direct);
+
+
+/*******************************************************************************
+**
+** Function GATT_CancelConnect
+**
+** Description This function initiate a cancel connecttion to a ATT server.
+**
+** Parameters gatt_if: client interface. If 0 used as unconditionally disconnect,
+** typically used for direct connection cancellation.
+** bd_addr: peer device address.
+** is_direct: is a direct conenection or a background auto connection
+**
+** Returns TRUE if connection started; FALSE if connection start failure.
+**
+*******************************************************************************/
+ GATT_API extern BOOLEAN GATT_CancelConnect (tGATT_IF gatt_if, BD_ADDR bd_addr, BOOLEAN is_direct);
+
+/*******************************************************************************
+**
+** Function GATT_Disconnect
+**
+** Description This function disconnect a logic channel.
+**
+** Parameters conn_id: connection identifier.
+**
+** Returns GATT_SUCCESS if disconnected.
+**
+*******************************************************************************/
+ GATT_API extern tGATT_STATUS GATT_Disconnect (UINT16 conn_id);
+
+
+
+/*******************************************************************************
+**
+** Function GATT_GetConnectionInfor
+**
+** Description This function use conn_id to find its associated BD address and applciation
+** interface
+**
+** Parameters conn_id: connection id (input)
+** p_gatt_if: applicaiton interface (output)
+** bd_addr: peer device address. (output)
+**
+** Returns TRUE the ligical link information is found for conn_id
+**
+*******************************************************************************/
+ GATT_API extern BOOLEAN GATT_GetConnectionInfor(UINT16 conn_id, tGATT_IF *p_gatt_if, BD_ADDR bd_addr);
+
+
+/*******************************************************************************
+**
+** Function GATT_GetConnIdIfConnected
+**
+** Description This function find the conn_id if the logical link for BD address
+** and applciation interface is connected
+**
+** Parameters gatt_if: applicaiton interface (input)
+** bd_addr: peer device address. (input)
+** p_conn_id: connection id (output)
+**
+** Returns TRUE the ligical link is connected
+**
+*******************************************************************************/
+ GATT_API extern BOOLEAN GATT_GetConnIdIfConnected(tGATT_IF gatt_if, BD_ADDR bd_addr, UINT16 *p_conn_id);
+
+#ifdef __cplusplus
+
+}
+#endif
+
+#endif /* GATT_API_H */
diff --git a/stack/include/gattdefs.h b/stack/include/gattdefs.h
new file mode 100644
index 0000000..def3270
--- /dev/null
+++ b/stack/include/gattdefs.h
@@ -0,0 +1,96 @@
+/****************************************************************************/
+/* */
+/* Name: gattdefs.h */
+/* */
+/* Function this file contains internally used ATT definitions */
+/* */
+/* Copyright (c) 1999-2010, Broadcom Corp., All Rights Reserved. */
+/* WIDCOMM Bluetooth Core. Proprietary and confidential. */
+/* */
+/*****************************************************************************/
+
+#ifndef _GATTDEFS_H
+#define _GATTDEFS_H
+
+#define GATT_ILLEGAL_UUID 0
+
+/* GATT attribute types
+*/
+#define GATT_UUID_PRI_SERVICE 0x2800
+#define GATT_UUID_SEC_SERVICE 0x2801
+#define GATT_UUID_INCLUDE_SERVICE 0x2802
+#define GATT_UUID_CHAR_DECLARE 0x2803 /* Characteristic Declaration*/
+
+#define GATT_UUID_CHAR_EXT_PROP 0x2900 /* Characteristic Extended Properties */
+#define GATT_UUID_CHAR_DESCRIPTION 0x2901 /* Characteristic User Description*/
+#define GATT_UUID_CHAR_CLIENT_CONFIG 0x2902 /* Client Characteristic Configuration */
+#define GATT_UUID_CHAR_SRVR_CONFIG 0x2903 /* Server Characteristic Configuration */
+#define GATT_UUID_CHAR_PRESENT_FORMAT 0x2904 /* Characteristic Presentation Format*/
+#define GATT_UUID_CHAR_AGG_FORMAT 0x2905 /* Characteristic Aggregate Format*/
+#define GATT_UUID_CHAR_VALID_RANGE 0x2906 /* Characteristic Valid Range */
+#define GATT_UUID_EXT_RPT_REF_DESCR 0x2907
+#define GATT_UUID_RPT_REF_DESCR 0x2908
+
+
+/* GAP Profile Attributes
+*/
+#define GATT_UUID_GAP_DEVICE_NAME 0x2A00
+#define GATT_UUID_GAP_ICON 0x2A01
+#define GATT_UUID_GAP_PRIVACY_FLAG 0x2A02
+#define GATT_UUID_GAP_RECONN_ADDR 0x2A03
+#define GATT_UUID_GAP_PREF_CONN_PARAM 0x2A04
+
+/* Attribute Profile Attribute UUID */
+#define GATT_UUID_GATT_SRV_CHGD 0x2A05
+/* Attribute Protocol Test */
+
+/* Link Loss Service */
+#define GATT_UUID_ALERT_LEVEL 0x2A06 /* Alert Level */
+#define GATT_UUID_TX_POWER_LEVEL 0x2A07 /* TX power level */
+
+/* Time Profile */
+/* Current Time Service */
+#define GATT_UUID_CURRENT_TIME 0x2A2B /* Current Time */
+#define GATT_UUID_LOCAL_TIME_INFO 0x2A0F /* Local time info */
+#define GATT_UUID_REF_TIME_INFO 0x2A14 /* reference time information */
+
+/* NwA Profile */
+#define GATT_UUID_NW_STATUS 0x2A18 /* network availability status */
+#define GATT_UUID_NW_TRIGGER 0x2A1A /* Network availability trigger */
+
+/* phone alert */
+#define GATT_UUID_ALERT_STATUS 0x2A40 /* alert status */
+#define GATT_UUID_RINGER_CP 0x2A42 /* ringer control point */
+#define GATT_UUID_RINGER_SETTING 0x2A41 /* ringer setting */
+
+/* Glucose Service */
+#define GATT_UUID_GM_MEASUREMENT 0x2A18
+#define GATT_UUID_GM_CONTEXT 0x2A34
+#define GATT_UUID_GM_CONTROL_POINT 0x2A52
+#define GATT_UUID_GM_FEATURE 0x2A51
+
+/* device infor characteristic */
+#define GATT_UUID_SYSTEM_ID 0x2A23
+#define GATT_UUID_MODEL_NUMBER_STR 0x2A24
+#define GATT_UUID_SERIAL_NUMBER_STR 0x2A25
+#define GATT_UUID_FW_VERSION_STR 0x2A26
+#define GATT_UUID_HW_VERSION_STR 0x2A27
+#define GATT_UUID_SW_VERSION_STR 0x2A28
+#define GATT_UUID_MANU_NAME 0x2A29
+#define GATT_UUID_IEEE_DATA 0x2A2A
+#define GATT_UUID_PNP_ID 0x2A50
+
+/* HID characteristics */
+#define GATT_UUID_HID_INFORMATION 0x2A4A
+#define GATT_UUID_HID_REPORT_MAP 0x2A4B
+#define GATT_UUID_HID_CONTROL_POINT 0x2A4C
+#define GATT_UUID_HID_REPORT 0x2A4D
+#define GATT_UUID_HID_PROTO_MODE 0x2A4E
+#define GATT_UUID_HID_BT_KB_INPUT 0x2A22
+#define GATT_UUID_HID_BT_KB_OUTPUT 0x2A32
+#define GATT_UUID_HID_BT_MOUSE_INPUT 0x2A33
+
+/* Battery Service char */
+#define GATT_UUID_BATTERY_LEVEL 0x2A19
+
+#endif
diff --git a/stack/include/goep_fs.h b/stack/include/goep_fs.h
new file mode 100644
index 0000000..095449a
--- /dev/null
+++ b/stack/include/goep_fs.h
@@ -0,0 +1,386 @@
+/*****************************************************************************
+**
+** Name: goep_fs.h
+**
+** File: Object Storage API
+**
+** Copyright (c) 2000-2009, Broadcom Corp., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef GOEP_FS_H
+#define GOEP_FS_H
+
+#include "bt_target.h"
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+/* Flags passed to the open function (tGOEP_OPEN_CBACK)
+** Values are OR'd together. (First 3 are
+** mutually exclusive.
+*/
+#define GOEP_O_RDONLY 0x0000
+#define GOEP_O_WRONLY 0x0001
+#define GOEP_O_RDWR 0x0002
+
+#define GOEP_O_CREAT 0x0100
+#define GOEP_O_EXCL 0x0200
+#define GOEP_O_TRUNC 0x1000
+
+
+#define GOEP_LEN_UNKNOWN 0xFFFFFFFF
+#define GOEP_INVALID_FD (-1)
+
+/* Values passed to the access function (tGOEP_ACCESS_CBACK)
+*/
+#define GOEP_ACC_EXIST 0x0
+#define GOEP_ACC_READ 0x4
+#define GOEP_ACC_RDWR 0x6
+
+/* Constants used in directory listing structure */
+#define GOEP_A_RDONLY 0x1
+#define GOEP_A_DIR 0x2 /* Entry is a sub directory */
+
+#define GOEP_CTIME_LEN 17 /* Creation time "yyyymmddTHHMMSSZ" */
+
+/*****************************************************************************
+** Seek Constants
+*****************************************************************************/
+/* Origin for the seek function (tGOEP_SEEK_CBACK) */
+#define GOEP_SEEK_SET 0
+#define GOEP_SEEK_CUR 1
+#define GOEP_SEEK_END 2
+
+
+
+/*****************************************************************************
+** Typedefs
+*****************************************************************************/
+typedef INT32 tGOEP_FD;
+
+enum
+{
+ GOEP_OK,
+ GOEP_FAIL,
+ GOEP_EACCES,
+ GOEP_ENOTEMPTY,
+ GOEP_EOF,
+ GOEP_EODIR,
+ GOEP_ENOSPACE,
+ GOEP_EIS_DIR,
+ GOEP_RESUME,
+ GOEP_NONE
+};
+typedef UINT16 tGOEP_STATUS;
+
+/* Structure passed in Directory Entry Callback to be filled in */
+typedef struct
+{
+ UINT32 refdata; /* holder for OS specific data used to get next entry */
+ UINT32 filesize;
+ char crtime[GOEP_CTIME_LEN]; /* "yyyymmddTHHMMSSZ", or "" if none */
+ char *p_name; /* Contains the addr of memory to copy name into */
+ UINT8 mode; /* GOEP_A_RDONLY and/or GOEP_A_DIR */
+} tGOEP_DIRENTRY;
+
+
+/*****************************************************************************
+** Typedefs for messages from response functions
+*****************************************************************************/
+typedef struct
+{
+ BT_HDR hdr;
+ tGOEP_FD fd;
+ tGOEP_STATUS status;
+ UINT32 file_size;
+} tGOEP_OPEN_RSP;
+
+typedef struct
+{
+ BT_HDR hdr;
+ tGOEP_FD fd;
+ tGOEP_STATUS status;
+ UINT16 bytes_read;
+} tGOEP_READ_RSP;
+
+typedef struct
+{
+ BT_HDR hdr;
+ tGOEP_FD fd;
+ tGOEP_STATUS status;
+} tGOEP_WRITE_RSP;
+
+typedef struct
+{
+ BT_HDR hdr;
+ tGOEP_STATUS status;
+} tGOEP_DIRENTRY_RSP;
+
+/*****************************************************************************
+** Object Store Interface
+*****************************************************************************/
+/*******************************************************************************
+**
+** Callback Function: tGOEP_OPEN_CBACK
+**
+** Description This function is executed by OBX profiles to open
+** a file for reading or writing.
+**
+** Parameters p_path - Fully qualified path and file name.
+** flags - permissions and mode (see constants above)
+** size - size of file to put (0 if unavailable or not applicable)
+** event_id - code that must be passed to the call-in function.
+**
+** Returns void
+**
+** Note: Upon completion of the request, a file descriptor (tGOEP_FD),
+** file size (UINT32), and an status code (tGOEP_STATUS)
+** are returned in GOEP_OpenRsp().
+**
+*******************************************************************************/
+typedef void (tGOEP_OPEN_CBACK) (const UINT8 *p_name, UINT16 flags, UINT32 size,
+ UINT16 event_id, UINT8 app_id);
+
+/*******************************************************************************
+**
+** Callback Function: tGOEP_CLOSE_CBACK
+**
+** Description This function is executed by OBX profiles when the file descriptor
+** is no longer in use.
+**
+** Returns void
+**
+*******************************************************************************/
+typedef void (tGOEP_CLOSE_CBACK) (tGOEP_FD fd, UINT8 app_id);
+
+/*******************************************************************************
+**
+** Callback Function: tGOEP_READ_CBACK
+**
+** Description This function is executed by OBX profiles to read in data from the
+** previously opened file.
+**
+** Returns void
+**
+** Note: Upon completion of the request, GOEP_ReadRsp() is
+** called with the buffer of data, along with the number
+** of bytes read into the buffer, and a status. The
+** call-in function should only be called when ALL requested
+** bytes have been read, the end of file has been detected,
+** or an error has occurred.
+**
+*******************************************************************************/
+typedef void (tGOEP_READ_CBACK) (tGOEP_FD fd, void *p_data, INT16 size,
+ UINT16 event_id, UINT8 app_id);
+
+/*******************************************************************************
+**
+** Callback Function: tGOEP_WRITE_CBACK
+**
+** Description This function is executed by OBX profiles to write the data to the
+** previously opened file.
+**
+** Returns void
+**
+** Note: Upon completion of the request, GOEP_WriteRsp() is
+** called with the file descriptor and the status. The
+** call-in function should only be called when ALL requested
+** bytes have been written, or an error has been detected,
+**
+*******************************************************************************/
+typedef void (tGOEP_WRITE_CBACK) (tGOEP_FD fd, const void *p_data, INT16 size,
+ UINT16 event_id, UINT8 app_id);
+
+/*******************************************************************************
+**
+** Callback Function: tGOEP_SEEK_CBACK
+**
+** Description This function is executed by OBX profiles to Move a file pointer
+** of a previously opened file to the specified location for the
+** next read or write operation.
+**
+** Returns void
+**
+*******************************************************************************/
+typedef void (tGOEP_SEEK_CBACK) (tGOEP_FD fd, INT32 offset, INT16 origin, UINT8 app_id);
+
+
+/*******************************************************************************
+**
+** Callback Function: tGOEP_DIRENTRY_CBACK
+**
+** Description This function is called to retrieve a directory entry for the
+** specified path. The first/next directory should be filled
+** into the location specified by p_entry.
+**
+** Parameters p_path - directory to search (Fully qualified path)
+** first_item - TRUE if first search, FALSE if next search
+** (p_cur contains previous)
+** p_entry (input/output) - Points to last entry data (valid when
+** first_item is FALSE)
+** event_id - event that must be passed into the call-in function.
+**
+** Returns void
+**
+** Note: Upon completion of the request, GOEP_DirentryRsp() is
+** filled in entry and the status.
+** GOEP_OK is returned when p_entry is valid,
+** GOEP_EODIR is returned when no more entries [finished]
+** GOEP_FAIL is returned if an error occurred
+**
+*******************************************************************************/
+typedef void (tGOEP_DIRENTRY_CBACK) (const char *p_path, BOOLEAN first_item,
+ tGOEP_DIRENTRY *p_entry, UINT16 event_id,
+ UINT8 app_id);
+
+/*******************************************************************************
+**
+** Callback Function: tGOEP_ACCESS_CBACK
+**
+** Description This function is called to check the existence of a file or
+** directory.
+**
+** Returns (tGOEP_STATUS) status of the call.
+** [GOEP_OK if it exists]
+** [GOEP_EACCES if permissions are wrong]
+** [GOEP_FAIL if it does not exist]
+**
+*******************************************************************************/
+typedef tGOEP_STATUS (tGOEP_ACCESS_CBACK) (const char *p_path, UINT16 mode,
+ BOOLEAN *p_is_dir, UINT8 app_id);
+
+/*******************************************************************************
+**
+** Callback Function: tGOEP_MKDIR_CBACK
+**
+** Description This function is called to create a directory with
+** the pathname given by path. The pathname is a null terminated
+** string. All components of the path must already exist.
+**
+** Parameters p_path - (input) name of directory to create (fully qualified path).
+**
+** Returns (tGOEP_STATUS) status of the call.
+** [GOEP_OK if successful]
+** [GOEP_FAIL if unsuccessful]
+**
+*******************************************************************************/
+typedef tGOEP_STATUS (tGOEP_MKDIR_CBACK) (const char *p_path, UINT8 app_id);
+
+/*******************************************************************************
+**
+** Callback Function: tGOEP_RMDIR_CBACK
+**
+** Description This function is called to remove a directory whose
+** name is given by path. The directory must be empty.
+**
+** Parameters p_path - (input) name of directory to remove (fully qualified path).
+**
+** Returns (tGOEP_STATUS) status of the call.
+** [GOEP_OK if successful]
+** [GOEP_EACCES if read-only]
+** [GOEP_ENOTEMPTY if directory is not empty]
+** [GOEP_FAIL otherwise]
+**
+*******************************************************************************/
+typedef tGOEP_STATUS (tGOEP_RMDIR_CBACK) (const char *p_path, UINT8 app_id);
+
+/*******************************************************************************
+**
+** Callback Function: tGOEP_UNLINK_CBACK
+**
+** Description This function is called to remove a directory whose
+** name is given by path. The directory must be empty.
+**
+** Parameters p_path - (input) name of file to remove (fully qualified path).
+**
+** Returns (tGOEP_STATUS) status of the call.
+** [GOEP_OK if successful]
+** [GOEP_EACCES if read-only]
+** [GOEP_FAIL otherwise]
+**
+*******************************************************************************/
+typedef tGOEP_STATUS (tGOEP_UNLINK_CBACK) (const char *p_path, UINT8 app_id);
+
+
+/*****************************************************************************
+** Prototypes
+*****************************************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************
+**
+** Function: GOEP_OpenRsp
+**
+** Purpose: Report the status of tGOEP_OPEN_CBACK callback function.
+**
+** Parameters: fd - File handle.
+** status - Status of the operation.
+** file_size - total number of bytes in this file.
+** event_id - event id as given in the tGOEP_OPEN_CBACK function.
+**
+** Returns: void
+**
+*****************************************************************************/
+GOEP_API extern void GOEP_OpenRsp (tGOEP_FD fd, tGOEP_STATUS status,
+ UINT32 file_size, UINT16 event_id);
+
+/*****************************************************************************
+**
+** Function: GOEP_ReadRsp
+**
+** Purpose: Report the status of tGOEP_READ_CBACK callback function.
+**
+** Parameters: fd - File handle.
+** status - Status of the operation.
+** bytes_read - total number of bytes read from the file.
+** event_id - event id as given in the tGOEP_READ_CBACK function.
+**
+** Returns: void
+**
+*****************************************************************************/
+GOEP_API extern void GOEP_ReadRsp (tGOEP_FD fd, tGOEP_STATUS status,
+ UINT16 bytes_read, UINT16 event_id);
+
+/*****************************************************************************
+**
+** Function: GOEP_WriteRsp
+**
+** Purpose: Report the status of tGOEP_WRITE_CBACK callback function.
+**
+** Parameters: fd - File handle.
+** status - Status of the operation.
+** event_id - event id as given in the tGOEP_WRITE_CBACK function.
+**
+** Returns: void
+**
+*****************************************************************************/
+GOEP_API extern void GOEP_WriteRsp (tGOEP_FD fd, tGOEP_STATUS status, UINT16 event_id);
+
+/*******************************************************************************
+**
+** Function GOEP_DirentryRsp
+**
+** Description This function is called in response to the
+** tGOEP_DIRENTRY_CBACK function with a filled in directory listing
+** entry.
+**
+** Parameters status - GOEP_OK if p_entry points to a valid entry.
+** GOEP_EODIR if no more entries (p_entry is ignored).
+** GOEP_FAIL if any errors have occurred.
+** event_id - event id as given in the tGOEP_DIRENTRY_CBACK function.
+**
+** Returns void
+**
+*******************************************************************************/
+GOEP_API extern void GOEP_DirentryRsp(tGOEP_STATUS status, UINT16 event_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GOEP_FS_H */
diff --git a/stack/include/goep_util.h b/stack/include/goep_util.h
new file mode 100644
index 0000000..8bfe4af
--- /dev/null
+++ b/stack/include/goep_util.h
@@ -0,0 +1,265 @@
+/*****************************************************************************
+**
+** Name: goep_util.h
+**
+** File: Generic Object Exchange Profile utility API
+**
+** Copyright (c) 2000-2008, Broadcom Corp., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef GOEP_UTIL_H
+#define GOEP_UTIL_H
+
+#include "bt_target.h"
+#include "sdp_api.h" /* for tSDP_DISC_REC */
+
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+#define GOEP_ENHANCED_VERSION 0x0102
+#define GOEP_LEGACY_VERSION 0x0100
+
+
+/*****************************************************************************
+** Type Definitions
+*****************************************************************************/
+
+/*** Define goep error codes ***/
+enum
+{
+ GOEP_SUCCESS = 0, /* success */
+ GOEP_ERROR, /* general failure */
+ GOEP_RESOURCES, /* resources not available */
+ GOEP_INVALID_PARAM /* bad parameter(s) */
+} ;
+typedef UINT8 tGOEP_ERRORS;
+
+
+
+
+
+/*****************************************************************************
+** External Function Declarations
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*** GOEP utility functions ***/
+/*****************************************************************************
+**
+** Function GOEP_SetSecurityLevel()
+**
+** Description Register security & encryption level for GOEP server.
+** This is not to be used for the GOEP command server.
+**
+** Returns TRUE if OK, FALSE if a bad parameter
+**
+*****************************************************************************/
+GOEP_API extern BOOLEAN GOEP_SetSecurityLevel (BOOLEAN b_orig,
+ char *p_sz_name,
+ UINT32 service,
+ UINT8 sec,
+ UINT8 scn);
+
+/*****************************************************************************
+**
+** Function GOEP_SetTraceLevel
+**
+** Description This function changes the trace level (debugging levels)
+**
+** Returns void
+**
+*****************************************************************************/
+GOEP_API extern void GOEP_SetTraceLevel(UINT8 level);
+
+/*******************************************************************************
+**
+** Function GOEP_FreeBuf
+**
+** Description free memory for specified packet
+**
+** Returns void
+**
+*******************************************************************************/
+GOEP_API extern void GOEP_FreeBuf (void **p_buf);
+
+/*******************************************************************************
+**
+** Function GOEP_SendMsg
+**
+** Description send a message to BTU task
+**
+** Returns void
+**
+*******************************************************************************/
+GOEP_API extern void GOEP_SendMsg (void *p_msg);
+
+/*******************************************************************************
+**
+** Function GOEP_Init
+**
+** Description This function is called once at stack startup to allocate
+** (if using dynamic memory) and initialize the
+** control block, and initializes the
+** debug tracing level.
+**
+** Returns void
+**
+*******************************************************************************/
+GOEP_API extern void GOEP_Init(void);
+
+
+
+/*** GOEP Service functions ***/
+
+
+/*****************************************************************************
+**
+** Function: GOEP_Register()
+**
+** Purpose: Register an OBEX profile with SDP
+**
+** Parameters:
+**
+** char *p_name service name; optional (may be NULL)
+** UINT32 *phSDP handle to the created record; cannot be NULL
+** UINT8 scn scn desired for the service; must be > 0
+** UINT16 version version of the service; optional (may be 0)
+**
+** Returns: (tGOEP_ERRORS) GOEP_SUCCESS if ok; GOEP_ERROR on error
+**
+** Notes:
+**
+**
+** Preconditions:
+** - phSDP must be set (to return the SDP record handle)
+** - scn must be set
+**
+** Postconditions:
+** -
+**
+*****************************************************************************/
+GOEP_API extern tGOEP_ERRORS GOEP_Register (char *p_name,
+ UINT32 *p_sdp_handle,
+ UINT8 scn,
+ UINT8 num_srv_class,
+ UINT16 *p_service_class,
+ UINT16 profile_id,
+ UINT16 version);
+/*****************************************************************************
+**
+** Function: GOEP_Register2()
+**
+** Purpose: Register an OBEX 1.5 profile with SDP
+**
+** Parameters:
+**
+** char *p_name service name; optional (may be NULL)
+** UINT32 *phSDP handle to the created record; cannot be NULL
+** UINT16 psm psm desired for the service; must be an legal L2CAP dynamic PSM
+** UINT16 version version of the service; optional (may be 0)
+**
+** Returns: (tGOEP_ERRORS) GOEP_SUCCESS if ok; GOEP_ERROR on error
+**
+** Notes:
+**
+**
+** Preconditions:
+** - phSDP must be set (to return the SDP record handle)
+** - psm must be set
+**
+** Postconditions:
+** -
+**
+*****************************************************************************/
+GOEP_API extern tGOEP_ERRORS GOEP_Register2 (char *p_name,
+ UINT32 *phSDP,
+ UINT16 psm,
+ UINT8 num_srv_class,
+ UINT16 *p_service_class,
+ UINT16 profile_id,
+ UINT16 version);
+
+/*****************************************************************************
+**
+** Function: GOEP_AddProtoLists()
+**
+** Purpose: Add the AdditionalProtocolDescriptorLists attribute
+** to a SDP record
+**
+** Parameters:
+**
+** UINT32 sdp_hdl the SDP record handle
+** UINT8 scn scn desired for the service; must be > 0
+**
+** Returns: (tGOEP_ERRORS) GOEP_SUCCESS if ok; GOEP_ERROR on error
+**
+** Notes:
+**
+**
+** Preconditions:
+** - sdp_hdl must be set (to the SDP record handle from GOEP_Register())
+** - scn must be set
+**
+** Postconditions:
+** -
+**
+*****************************************************************************/
+GOEP_API extern tGOEP_ERRORS GOEP_AddProtoLists ( UINT32 sdp_hdl, UINT8 scn);
+
+
+
+/*** Debug Tracing support ***/
+#if BT_USE_TRACES == TRUE
+
+GOEP_API extern char *GOEP_ErrorName (tGOEP_ERRORS error);
+GOEP_API extern void GOEP_TraceSupportedDataTypes(UINT8 data_types, UINT8 *p_data_types);
+#else
+#ifndef BTE_SIM_APP
+/* define these trace functions out */
+#define GOEP_CodeName(_x) ""
+#define GOEP_ErrorName(_x) ""
+#endif
+#define GOEP_TraceSupportedDataTypes(x, y)
+#endif /* end if BT_TRACE_PROTOCOL */
+
+
+/*****************************************************************************
+**
+** Design notes:
+**
+** The responsibilities handle by this module include:
+**
+** a) Function signatures which assure the proper header fields are
+** set for the GOEP connection establishment, GOEP put, and GOEP get.
+** Required fields / headers are filled in through the API function
+** parameters. Extensions beyond the required fields / headers
+** must be set through the tOBEX_HEADERS *p_headers parameter.
+**
+** b) Debug error checking for required fields and prohibited fields
+** for the GOEP connection establishment, GOEP put, and GOEP get.
+** With debugging on, non-optional headers set in the p_headers
+** parameter will generate a Widcomm assertion error.
+**
+** c) Does NOT include checks of any kind on the contents of the
+** authentication or authentication response headers. In fact,
+** the logic for encoding, decoding, validating, and calculating
+** authentication data is outside the scope of GOEP and OBEX.
+** Refer to IrOBEX v1.2 sections 2.2.13, 2.2.14, and 3.5.
+**
+** d) Does NOT include checks of any kind on the contents of the
+** data (body headers) sent or received.
+**
+**
+*****************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GOEP_UTIL_H */
diff --git a/stack/include/hcidefs.h b/stack/include/hcidefs.h
new file mode 100644
index 0000000..f70f100
--- /dev/null
+++ b/stack/include/hcidefs.h
@@ -0,0 +1,2220 @@
+/*****************************************************************************
+**
+** Name hcidefs.h
+**
+** Function this file contains Host Controller Interface definitions
+**
+** Copyright (c) 1999-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+******************************************************************************/
+
+#ifndef HCIDEFS_H
+#define HCIDEFS_H
+
+#ifdef BRCM_VS
+#include "brcm_vs_include.h"
+#endif
+
+#define HCI_PROTO_VERSION 0x01 /* Version for BT spec 1.1 */
+#define HCI_PROTO_VERSION_1_2 0x02 /* Version for BT spec 1.2 */
+#define HCI_PROTO_VERSION_2_0 0x03 /* Version for BT spec 2.0 */
+#define HCI_PROTO_VERSION_2_1 0x04 /* Version for BT spec 2.1 [Lisbon] */
+#define HCI_PROTO_VERSION_3_0 0x05 /* Version for BT spec 3.0 */
+#define HCI_PROTO_REVISION 0x000C /* Current implementation version */
+/*
+** Definitions for HCI groups
+*/
+#define HCI_GRP_LINK_CONTROL_CMDS (0x01 << 10) /* 0x0400 */
+#define HCI_GRP_LINK_POLICY_CMDS (0x02 << 10) /* 0x0800 */
+#define HCI_GRP_HOST_CONT_BASEBAND_CMDS (0x03 << 10) /* 0x0C00 */
+#define HCI_GRP_INFORMATIONAL_PARAMS (0x04 << 10) /* 0x1000 */
+#define HCI_GRP_STATUS_PARAMS (0x05 << 10) /* 0x1400 */
+#define HCI_GRP_TESTING_CMDS (0x06 << 10) /* 0x1800 */
+
+#define HCI_GRP_VENDOR_SPECIFIC (0x3F << 10) /* 0xFC00 */
+
+/* Group occupies high 6 bits of the HCI command rest is opcode itself */
+#define HCI_OGF(p) (UINT8)((0xFC00 & (p)) >> 10)
+#define HCI_OCF(p) ( 0x3FF & (p))
+
+/*
+** Defentions for Link Control Commands
+*/
+/* Following opcode is used only in command complete event for flow control */
+#define HCI_COMMAND_NONE 0x0000
+
+/* Commands of HCI_GRP_LINK_CONTROL_CMDS group */
+#define HCI_INQUIRY (0x0001 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_INQUIRY_CANCEL (0x0002 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_PERIODIC_INQUIRY_MODE (0x0003 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_EXIT_PERIODIC_INQUIRY_MODE (0x0004 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_CREATE_CONNECTION (0x0005 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_DISCONNECT (0x0006 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_ADD_SCO_CONNECTION (0x0007 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_CREATE_CONNECTION_CANCEL (0x0008 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_ACCEPT_CONNECTION_REQUEST (0x0009 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_REJECT_CONNECTION_REQUEST (0x000A | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_LINK_KEY_REQUEST_REPLY (0x000B | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_LINK_KEY_REQUEST_NEG_REPLY (0x000C | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_PIN_CODE_REQUEST_REPLY (0x000D | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_PIN_CODE_REQUEST_NEG_REPLY (0x000E | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_CHANGE_CONN_PACKET_TYPE (0x000F | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_AUTHENTICATION_REQUESTED (0x0011 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_SET_CONN_ENCRYPTION (0x0013 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_CHANGE_CONN_LINK_KEY (0x0015 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_MASTER_LINK_KEY (0x0017 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_RMT_NAME_REQUEST (0x0019 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_RMT_NAME_REQUEST_CANCEL (0x001A | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_READ_RMT_FEATURES (0x001B | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_READ_RMT_EXT_FEATURES (0x001C | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_READ_RMT_VERSION_INFO (0x001D | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_READ_RMT_CLOCK_OFFSET (0x001F | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_READ_LMP_HANDLE (0x0020 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_SETUP_ESCO_CONNECTION (0x0028 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_ACCEPT_ESCO_CONNECTION (0x0029 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_REJECT_ESCO_CONNECTION (0x002A | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_IO_CAPABILITY_RESPONSE (0x002B | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_USER_CONF_REQUEST_REPLY (0x002C | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_USER_CONF_VALUE_NEG_REPLY (0x002D | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_USER_PASSKEY_REQ_REPLY (0x002E | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_USER_PASSKEY_REQ_NEG_REPLY (0x002F | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_REM_OOB_DATA_REQ_REPLY (0x0030 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_REM_OOB_DATA_REQ_NEG_REPLY (0x0033 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_IO_CAP_REQ_NEG_REPLY (0x0034 | HCI_GRP_LINK_CONTROL_CMDS)
+
+/* AMP HCI */
+#define HCI_CREATE_PHYSICAL_LINK (0x0035 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_ACCEPT_PHYSICAL_LINK (0x0036 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_DISCONNECT_PHYSICAL_LINK (0x0037 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_CREATE_LOGICAL_LINK (0x0038 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_ACCEPT_LOGICAL_LINK (0x0039 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_DISCONNECT_LOGICAL_LINK (0x003A | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_LOGICAL_LINK_CANCEL (0x003B | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_FLOW_SPEC_MODIFY (0x003C | HCI_GRP_LINK_CONTROL_CMDS)
+
+#define HCI_LINK_CTRL_CMDS_FIRST HCI_INQUIRY
+#define HCI_LINK_CTRL_CMDS_LAST HCI_FLOW_SPEC_MODIFY
+
+/* Commands of HCI_GRP_LINK_POLICY_CMDS */
+#define HCI_HOLD_MODE (0x0001 | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_SNIFF_MODE (0x0003 | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_EXIT_SNIFF_MODE (0x0004 | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_PARK_MODE (0x0005 | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_EXIT_PARK_MODE (0x0006 | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_QOS_SETUP (0x0007 | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_ROLE_DISCOVERY (0x0009 | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_SWITCH_ROLE (0x000B | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_READ_POLICY_SETTINGS (0x000C | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_WRITE_POLICY_SETTINGS (0x000D | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_READ_DEF_POLICY_SETTINGS (0x000E | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_WRITE_DEF_POLICY_SETTINGS (0x000F | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_FLOW_SPECIFICATION (0x0010 | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_SNIFF_SUB_RATE (0x0011 | HCI_GRP_LINK_POLICY_CMDS)
+
+#define HCI_LINK_POLICY_CMDS_FIRST HCI_HOLD_MODE
+#define HCI_LINK_POLICY_CMDS_LAST HCI_SNIFF_SUB_RATE
+
+
+/* Commands of HCI_GRP_HOST_CONT_BASEBAND_CMDS */
+#define HCI_SET_EVENT_MASK (0x0001 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_RESET (0x0003 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_SET_EVENT_FILTER (0x0005 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_FLUSH (0x0008 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_PIN_TYPE (0x0009 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_PIN_TYPE (0x000A | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_CREATE_NEW_UNIT_KEY (0x000B | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_STORED_LINK_KEY (0x000D | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_STORED_LINK_KEY (0x0011 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_DELETE_STORED_LINK_KEY (0x0012 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_CHANGE_LOCAL_NAME (0x0013 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_LOCAL_NAME (0x0014 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_CONN_ACCEPT_TOUT (0x0015 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_CONN_ACCEPT_TOUT (0x0016 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_PAGE_TOUT (0x0017 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_PAGE_TOUT (0x0018 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_SCAN_ENABLE (0x0019 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_SCAN_ENABLE (0x001A | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_PAGESCAN_CFG (0x001B | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_PAGESCAN_CFG (0x001C | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_INQUIRYSCAN_CFG (0x001D | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_INQUIRYSCAN_CFG (0x001E | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_AUTHENTICATION_ENABLE (0x001F | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_AUTHENTICATION_ENABLE (0x0020 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_ENCRYPTION_MODE (0x0021 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_ENCRYPTION_MODE (0x0022 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_CLASS_OF_DEVICE (0x0023 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_CLASS_OF_DEVICE (0x0024 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_VOICE_SETTINGS (0x0025 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_VOICE_SETTINGS (0x0026 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_AUTO_FLUSH_TOUT (0x0027 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_AUTO_FLUSH_TOUT (0x0028 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_NUM_BCAST_REXMITS (0x0029 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_NUM_BCAST_REXMITS (0x002A | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_HOLD_MODE_ACTIVITY (0x002B | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_HOLD_MODE_ACTIVITY (0x002C | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_TRANSMIT_POWER_LEVEL (0x002D | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_SCO_FLOW_CTRL_ENABLE (0x002E | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_SCO_FLOW_CTRL_ENABLE (0x002F | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_SET_HC_TO_HOST_FLOW_CTRL (0x0031 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_HOST_BUFFER_SIZE (0x0033 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_HOST_NUM_PACKETS_DONE (0x0035 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_LINK_SUPER_TOUT (0x0036 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_LINK_SUPER_TOUT (0x0037 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_NUM_SUPPORTED_IAC (0x0038 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_CURRENT_IAC_LAP (0x0039 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_CURRENT_IAC_LAP (0x003A | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_PAGESCAN_PERIOD_MODE (0x003B | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_PAGESCAN_PERIOD_MODE (0x003C | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_PAGESCAN_MODE (0x003D | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_PAGESCAN_MODE (0x003E | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_SET_AFH_CHANNELS (0x003F | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+
+#define HCI_READ_INQSCAN_TYPE (0x0042 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_INQSCAN_TYPE (0x0043 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_INQUIRY_MODE (0x0044 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_INQUIRY_MODE (0x0045 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_PAGESCAN_TYPE (0x0046 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_PAGESCAN_TYPE (0x0047 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_AFH_ASSESSMENT_MODE (0x0048 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_AFH_ASSESSMENT_MODE (0x0049 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_EXT_INQ_RESPONSE (0x0051 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_EXT_INQ_RESPONSE (0x0052 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_REFRESH_ENCRYPTION_KEY (0x0053 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_SIMPLE_PAIRING_MODE (0x0055 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_SIMPLE_PAIRING_MODE (0x0056 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_LOCAL_OOB_DATA (0x0057 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_INQ_TX_POWER_LEVEL (0x0058 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_INQ_TX_POWER_LEVEL (0x0059 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_ERRONEOUS_DATA_RPT (0x005A | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_ERRONEOUS_DATA_RPT (0x005B | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_ENHANCED_FLUSH (0x005F | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_SEND_KEYPRESS_NOTIF (0x0060 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+
+
+/* AMP HCI */
+#define HCI_READ_LOGICAL_LINK_ACCEPT_TIMEOUT (0x0061 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_LOGICAL_LINK_ACCEPT_TIMEOUT (0x0062 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_SET_EVENT_MASK_PAGE_2 (0x0063 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_LOCATION_DATA (0x0064 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_LOCATION_DATA (0x0065 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_FLOW_CONTROL_MODE (0x0066 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_FLOW_CONTROL_MODE (0x0067 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_BE_FLUSH_TOUT (0x0069 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_BE_FLUSH_TOUT (0x006A | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_SHORT_RANGE_MODE (0x006B | HCI_GRP_HOST_CONT_BASEBAND_CMDS) /* 802.11 only */
+
+#define HCI_CONT_BASEBAND_CMDS_FIRST HCI_SET_EVENT_MASK
+#define HCI_CONT_BASEBAND_CMDS_LAST HCI_SHORT_RANGE_MODE
+
+
+/* Commands of HCI_GRP_INFORMATIONAL_PARAMS group */
+#define HCI_READ_LOCAL_VERSION_INFO (0x0001 | HCI_GRP_INFORMATIONAL_PARAMS)
+#define HCI_READ_LOCAL_SUPPORTED_CMDS (0x0002 | HCI_GRP_INFORMATIONAL_PARAMS)
+#define HCI_READ_LOCAL_FEATURES (0x0003 | HCI_GRP_INFORMATIONAL_PARAMS)
+#define HCI_READ_LOCAL_EXT_FEATURES (0x0004 | HCI_GRP_INFORMATIONAL_PARAMS)
+#define HCI_READ_BUFFER_SIZE (0x0005 | HCI_GRP_INFORMATIONAL_PARAMS)
+#define HCI_READ_COUNTRY_CODE (0x0007 | HCI_GRP_INFORMATIONAL_PARAMS)
+#define HCI_READ_BD_ADDR (0x0009 | HCI_GRP_INFORMATIONAL_PARAMS)
+#define HCI_READ_DATA_BLOCK_SIZE (0x000A | HCI_GRP_INFORMATIONAL_PARAMS)
+
+#define HCI_INFORMATIONAL_CMDS_FIRST HCI_READ_LOCAL_VERSION_INFO
+#define HCI_INFORMATIONAL_CMDS_LAST HCI_READ_BD_ADDR
+
+
+/* Commands of HCI_GRP_STATUS_PARAMS group */
+#define HCI_READ_FAILED_CONTACT_COUNT (0x0001 | HCI_GRP_STATUS_PARAMS)
+#define HCI_RESET_FAILED_CONTACT_COUNT (0x0002 | HCI_GRP_STATUS_PARAMS)
+#define HCI_GET_LINK_QUALITY (0x0003 | HCI_GRP_STATUS_PARAMS)
+#define HCI_READ_RSSI (0x0005 | HCI_GRP_STATUS_PARAMS)
+#define HCI_READ_AFH_CH_MAP (0x0006 | HCI_GRP_STATUS_PARAMS)
+#define HCI_READ_CLOCK (0x0007 | HCI_GRP_STATUS_PARAMS)
+#define HCI_READ_ENCR_KEY_SIZE (0x0008 | HCI_GRP_STATUS_PARAMS)
+
+/* AMP HCI */
+#define HCI_READ_LOCAL_AMP_INFO (0x0009 | HCI_GRP_STATUS_PARAMS)
+#define HCI_READ_LOCAL_AMP_ASSOC (0x000A | HCI_GRP_STATUS_PARAMS)
+#define HCI_WRITE_REMOTE_AMP_ASSOC (0x000B | HCI_GRP_STATUS_PARAMS)
+
+#define HCI_STATUS_PARAMS_CMDS_FIRST HCI_READ_FAILED_CONTACT_COUNT
+#define HCI_STATUS_PARAMS_CMDS_LAST HCI_WRITE_REMOTE_AMP_ASSOC
+
+/* Commands of HCI_GRP_TESTING_CMDS group */
+#define HCI_READ_LOOPBACK_MODE (0x0001 | HCI_GRP_TESTING_CMDS)
+#define HCI_WRITE_LOOPBACK_MODE (0x0002 | HCI_GRP_TESTING_CMDS)
+#define HCI_ENABLE_DEV_UNDER_TEST_MODE (0x0003 | HCI_GRP_TESTING_CMDS)
+#define HCI_WRITE_SIMP_PAIR_DEBUG_MODE (0x0004 | HCI_GRP_TESTING_CMDS)
+
+/* AMP HCI */
+#define HCI_ENABLE_AMP_RCVR_REPORTS (0x0007 | HCI_GRP_TESTING_CMDS)
+#define HCI_AMP_TEST_END (0x0008 | HCI_GRP_TESTING_CMDS)
+#define HCI_AMP_TEST (0x0009 | HCI_GRP_TESTING_CMDS)
+
+#define HCI_TESTING_CMDS_FIRST HCI_READ_LOOPBACK_MODE
+#define HCI_TESTING_CMDS_LAST HCI_AMP_TEST
+
+#define HCI_VENDOR_CMDS_FIRST 0x0001
+#define HCI_VENDOR_CMDS_LAST 0xFFFF
+#define HCI_VSC_MULTI_AV_HANDLE 0x0AAA
+#define HCI_VSC_BURST_MODE_HANDLE 0x0BBB
+
+/* BLE HCI */
+#define HCI_GRP_BLE_CMDS (0x08 << 10)
+/* Commands of BLE Controller setup and configuration */
+#define HCI_BLE_SET_EVENT_MASK (0x0001 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_BUFFER_SIZE (0x0002 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_LOCAL_SPT_FEAT (0x0003 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_WRITE_LOCAL_SPT_FEAT (0x0004 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_WRITE_RANDOM_ADDR (0x0005 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_WRITE_ADV_PARAMS (0x0006 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_ADV_CHNL_TX_POWER (0x0007 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_WRITE_ADV_DATA (0x0008 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_WRITE_SCAN_RSP_DATA (0x0009 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_WRITE_ADV_ENABLE (0x000A | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_WRITE_SCAN_PARAMS (0x000B | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_WRITE_SCAN_ENABLE (0x000C | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_CREATE_LL_CONN (0x000D | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_CREATE_CONN_CANCEL (0x000E | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_WHITE_LIST_SIZE (0x000F | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_CLEAR_WHITE_LIST (0x0010 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_ADD_WHITE_LIST (0x0011 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_REMOVE_WHITE_LIST (0x0012 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_UPD_LL_CONN_PARAMS (0x0013 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_SET_HOST_CHNL_CLASS (0x0014 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_CHNL_MAP (0x0015 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_REMOTE_FEAT (0x0016 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_ENCRYPT (0x0017 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_RAND (0x0018 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_START_ENC (0x0019 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_LTK_REQ_REPLY (0x001A | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_LTK_REQ_NEG_REPLY (0x001B | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_SUPPORTED_STATES (0x001C | HCI_GRP_BLE_CMDS)
+
+#define HCI_BLE_RESET (0x0020 | HCI_GRP_BLE_CMDS)
+
+/* LE supported states definition */
+#define HCI_LE_ADV_STATE 0x00000001
+#define HCI_LE_SCAN_STATE 0x00000002
+#define HCI_LE_INIT_STATE 0x00000004
+#define HCI_LE_CONN_SL_STATE 0x00000008
+#define HCI_LE_ADV_SCAN_STATE 0x00000010
+#define HCI_LE_ADV_INIT_STATE 0x00000020
+#define HCI_LE_ADV_MA_STATE 0x00000040
+#define HCI_LE_ADV_SL_STATE 0x00000080
+#define HCI_LE_SCAN_INIT_STATE 0x00000100
+#define HCI_LE_SCAN_MA_STATE 0x00000200
+#define HCI_LE_SCAN_SL_STATE 0x00000400
+#define HCI_LE_INIT_MA_STATE 0x00000800
+
+/*
+** Definitions for HCI Events
+*/
+#define HCI_INQUIRY_COMP_EVT 0x01
+#define HCI_INQUIRY_RESULT_EVT 0x02
+#define HCI_CONNECTION_COMP_EVT 0x03
+#define HCI_CONNECTION_REQUEST_EVT 0x04
+#define HCI_DISCONNECTION_COMP_EVT 0x05
+#define HCI_AUTHENTICATION_COMP_EVT 0x06
+#define HCI_RMT_NAME_REQUEST_COMP_EVT 0x07
+#define HCI_ENCRYPTION_CHANGE_EVT 0x08
+#define HCI_CHANGE_CONN_LINK_KEY_EVT 0x09
+#define HCI_MASTER_LINK_KEY_COMP_EVT 0x0A
+#define HCI_READ_RMT_FEATURES_COMP_EVT 0x0B
+#define HCI_READ_RMT_VERSION_COMP_EVT 0x0C
+#define HCI_QOS_SETUP_COMP_EVT 0x0D
+#define HCI_COMMAND_COMPLETE_EVT 0x0E
+#define HCI_COMMAND_STATUS_EVT 0x0F
+#define HCI_HARDWARE_ERROR_EVT 0x10
+#define HCI_FLUSH_OCCURED_EVT 0x11
+#define HCI_ROLE_CHANGE_EVT 0x12
+#define HCI_NUM_COMPL_DATA_PKTS_EVT 0x13
+#define HCI_MODE_CHANGE_EVT 0x14
+#define HCI_RETURN_LINK_KEYS_EVT 0x15
+#define HCI_PIN_CODE_REQUEST_EVT 0x16
+#define HCI_LINK_KEY_REQUEST_EVT 0x17
+#define HCI_LINK_KEY_NOTIFICATION_EVT 0x18
+#define HCI_LOOPBACK_COMMAND_EVT 0x19
+#define HCI_DATA_BUF_OVERFLOW_EVT 0x1A
+#define HCI_MAX_SLOTS_CHANGED_EVT 0x1B
+#define HCI_READ_CLOCK_OFF_COMP_EVT 0x1C
+#define HCI_CONN_PKT_TYPE_CHANGE_EVT 0x1D
+#define HCI_QOS_VIOLATION_EVT 0x1E
+#define HCI_PAGE_SCAN_MODE_CHANGE_EVT 0x1F
+#define HCI_PAGE_SCAN_REP_MODE_CHNG_EVT 0x20
+#define HCI_FLOW_SPECIFICATION_COMP_EVT 0x21
+#define HCI_INQUIRY_RSSI_RESULT_EVT 0x22
+#define HCI_READ_RMT_EXT_FEATURES_COMP_EVT 0x23
+#define HCI_ESCO_CONNECTION_COMP_EVT 0x2C
+#define HCI_ESCO_CONNECTION_CHANGED_EVT 0x2D
+#define HCI_SNIFF_SUB_RATE_EVT 0x2E
+#define HCI_EXTENDED_INQUIRY_RESULT_EVT 0x2F
+#define HCI_ENCRYPTION_KEY_REFRESH_COMP_EVT 0x30
+#define HCI_IO_CAPABILITY_REQUEST_EVT 0x31
+#define HCI_IO_CAPABILITY_RESPONSE_EVT 0x32
+#define HCI_USER_CONFIRMATION_REQUEST_EVT 0x33
+#define HCI_USER_PASSKEY_REQUEST_EVT 0x34
+#define HCI_REMOTE_OOB_DATA_REQUEST_EVT 0x35
+#define HCI_SIMPLE_PAIRING_COMPLETE_EVT 0x36
+#define HCI_LINK_SUPER_TOUT_CHANGED_EVT 0x38
+#define HCI_ENHANCED_FLUSH_COMPLETE_EVT 0x39
+#define HCI_USER_PASSKEY_NOTIFY_EVT 0x3B
+#define HCI_KEYPRESS_NOTIFY_EVT 0x3C
+#define HCI_RMT_HOST_SUP_FEAT_NOTIFY_EVT 0x3D
+
+/*#define HCI_GENERIC_AMP_LINK_KEY_NOTIF_EVT 0x3E Removed from spec */
+#define HCI_PHYSICAL_LINK_COMP_EVT 0x40
+#define HCI_CHANNEL_SELECTED_EVT 0x41
+#define HCI_DISC_PHYSICAL_LINK_COMP_EVT 0x42
+#define HCI_PHY_LINK_LOSS_EARLY_WARNING_EVT 0x43
+#define HCI_PHY_LINK_RECOVERY_EVT 0x44
+#define HCI_LOGICAL_LINK_COMP_EVT 0x45
+#define HCI_DISC_LOGICAL_LINK_COMP_EVT 0x46
+#define HCI_FLOW_SPEC_MODIFY_COMP_EVT 0x47
+#define HCI_NUM_COMPL_DATA_BLOCKS_EVT 0x48
+#define HCI_SHORT_RANGE_MODE_COMPLETE_EVT 0x4C
+#define HCI_AMP_STATUS_CHANGE_EVT 0x4D
+
+/* ULP HCI Event */
+#define HCI_BLE_EVENT 0x03E
+/* ULP Event sub code */
+#define HCI_BLE_CONN_COMPLETE_EVT 0x01
+#define HCI_BLE_ADV_PKT_RPT_EVT 0x02
+#define HCI_BLE_LL_CONN_PARAM_UPD_EVT 0x03
+#define HCI_BLE_READ_REMOTE_FEAT_CMPL_EVT 0x04
+#define HCI_BLE_LTK_REQ_EVT 0x05
+
+#define HCI_EVENT_RSP_FIRST HCI_INQUIRY_COMP_EVT
+#define HCI_EVENT_RSP_LAST HCI_AMP_STATUS_CHANGE_EVT
+
+#define HCI_VENDOR_SPECIFIC_EVT 0xFF /* Vendor specific events */
+#define HCI_NAP_TRACE_EVT 0xFF /* was define 0xFE, 0xFD, change to 0xFF
+ because conflict w/ TCI_EVT and per
+ specification compliant */
+
+
+
+/*
+** Defentions for HCI Error Codes that are past in the events
+*/
+#define HCI_SUCCESS 0x00
+#define HCI_PENDING 0x00
+#define HCI_ERR_ILLEGAL_COMMAND 0x01
+#define HCI_ERR_NO_CONNECTION 0x02
+#define HCI_ERR_HW_FAILURE 0x03
+#define HCI_ERR_PAGE_TIMEOUT 0x04
+#define HCI_ERR_AUTH_FAILURE 0x05
+#define HCI_ERR_KEY_MISSING 0x06
+#define HCI_ERR_MEMORY_FULL 0x07
+#define HCI_ERR_CONNECTION_TOUT 0x08
+#define HCI_ERR_MAX_NUM_OF_CONNECTIONS 0x09
+#define HCI_ERR_MAX_NUM_OF_SCOS 0x0A
+#define HCI_ERR_CONNECTION_EXISTS 0x0B
+#define HCI_ERR_COMMAND_DISALLOWED 0x0C
+#define HCI_ERR_HOST_REJECT_RESOURCES 0x0D
+#define HCI_ERR_HOST_REJECT_SECURITY 0x0E
+#define HCI_ERR_HOST_REJECT_DEVICE 0x0F
+#define HCI_ERR_HOST_TIMEOUT 0x10
+#define HCI_ERR_UNSUPPORTED_VALUE 0x11
+#define HCI_ERR_ILLEGAL_PARAMETER_FMT 0x12
+#define HCI_ERR_PEER_USER 0x13
+#define HCI_ERR_PEER_LOW_RESOURCES 0x14
+#define HCI_ERR_PEER_POWER_OFF 0x15
+#define HCI_ERR_CONN_CAUSE_LOCAL_HOST 0x16
+#define HCI_ERR_REPEATED_ATTEMPTS 0x17
+#define HCI_ERR_PAIRING_NOT_ALLOWED 0x18
+#define HCI_ERR_UNKNOWN_LMP_PDU 0x19
+#define HCI_ERR_UNSUPPORTED_REM_FEATURE 0x1A
+#define HCI_ERR_SCO_OFFSET_REJECTED 0x1B
+#define HCI_ERR_SCO_INTERVAL_REJECTED 0x1C
+#define HCI_ERR_SCO_AIR_MODE 0x1D
+#define HCI_ERR_INVALID_LMP_PARAM 0x1E
+#define HCI_ERR_UNSPECIFIED 0x1F
+#define HCI_ERR_UNSUPPORTED_LMP_FEATURE 0x20
+#define HCI_ERR_ROLE_CHANGE_NOT_ALLOWED 0x21
+#define HCI_ERR_LMP_RESPONSE_TIMEOUT 0x22
+#define HCI_ERR_LMP_ERR_TRANS_COLLISION 0x23
+#define HCI_ERR_LMP_PDU_NOT_ALLOWED 0x24
+#define HCI_ERR_ENCRY_MODE_NOT_ACCEPTABLE 0x25
+#define HCI_ERR_UNIT_KEY_USED 0x26
+#define HCI_ERR_QOS_NOT_SUPPORTED 0x27
+#define HCI_ERR_INSTANT_PASSED 0x28
+#define HCI_ERR_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED 0x29
+#define HCI_ERR_DIFF_TRANSACTION_COLLISION 0x2A
+#define HCI_ERR_UNDEFINED_0x2B 0x2B
+#define HCI_ERR_QOS_UNACCEPTABLE_PARAM 0x2C
+#define HCI_ERR_QOS_REJECTED 0x2D
+#define HCI_ERR_CHAN_CLASSIF_NOT_SUPPORTED 0x2E
+#define HCI_ERR_INSUFFCIENT_SECURITY 0x2F
+#define HCI_ERR_PARAM_OUT_OF_RANGE 0x30
+#define HCI_ERR_UNDEFINED_0x31 0x31
+#define HCI_ERR_ROLE_SWITCH_PENDING 0x32
+#define HCI_ERR_UNDEFINED_0x33 0x33
+#define HCI_ERR_RESERVED_SLOT_VIOLATION 0x34
+#define HCI_ERR_ROLE_SWITCH_FAILED 0x35
+#define HCI_ERR_INQ_RSP_DATA_TOO_LARGE 0x36
+#define HCI_ERR_SIMPLE_PAIRING_NOT_SUPPORTED 0x37
+#define HCI_ERR_HOST_BUSY_PAIRING 0x38
+#define HCI_ERR_REJ_NO_SUITABLE_CHANNEL 0x39
+#define HCI_ERR_CONTROLLER_BUSY 0x3A
+#define HCI_ERR_UNACCEPT_CONN_INTERVAL 0x3B
+#define HCI_ERR_DIRECTED_ADVERTISING_TIMEOUT 0x3C
+#define HCI_ERR_CONN_TOUT_DUE_TO_MIC_FAILURE 0x3D
+#define HCI_ERR_CONN_FAILED_ESTABLISHMENT 0x3E
+#define HCI_ERR_MAC_CONNECTION_FAILED 0x3F
+
+#define HCI_ERR_MAX_ERR 0x40
+
+#define HCI_HINT_TO_RECREATE_AMP_PHYS_LINK 0xFF
+
+/*
+** Definitions for HCI enable event
+*/
+#define HCI_INQUIRY_COMPLETE_EV(p) (*((UINT32 *)(p)) & 0x00000001)
+#define HCI_INQUIRY_RESULT_EV(p) (*((UINT32 *)(p)) & 0x00000002)
+#define HCI_CONNECTION_COMPLETE_EV(p) (*((UINT32 *)(p)) & 0x00000004)
+#define HCI_CONNECTION_REQUEST_EV(p) (*((UINT32 *)(p)) & 0x00000008)
+#define HCI_DISCONNECTION_COMPLETE_EV(p) (*((UINT32 *)(p)) & 0x00000010)
+#define HCI_AUTHENTICATION_COMPLETE_EV(p) (*((UINT32 *)(p)) & 0x00000020)
+#define HCI_RMT_NAME_REQUEST_COMPL_EV(p) (*((UINT32 *)(p)) & 0x00000040)
+#define HCI_CHANGE_CONN_ENCRPT_ENABLE_EV(p) (*((UINT32 *)(p)) & 0x00000080)
+#define HCI_CHANGE_CONN_LINK_KEY_EV(p) (*((UINT32 *)(p)) & 0x00000100)
+#define HCI_MASTER_LINK_KEY_COMPLETE_EV(p) (*((UINT32 *)(p)) & 0x00000200)
+#define HCI_READ_RMT_FEATURES_COMPL_EV(p) (*((UINT32 *)(p)) & 0x00000400)
+#define HCI_READ_RMT_VERSION_COMPL_EV(p) (*((UINT32 *)(p)) & 0x00000800)
+#define HCI_QOS_SETUP_COMPLETE_EV(p) (*((UINT32 *)(p)) & 0x00001000)
+#define HCI_COMMAND_COMPLETE_EV(p) (*((UINT32 *)(p)) & 0x00002000)
+#define HCI_COMMAND_STATUS_EV(p) (*((UINT32 *)(p)) & 0x00004000)
+#define HCI_HARDWARE_ERROR_EV(p) (*((UINT32 *)(p)) & 0x00008000)
+#define HCI_FLASH_OCCURED_EV(p) (*((UINT32 *)(p)) & 0x00010000)
+#define HCI_ROLE_CHANGE_EV(p) (*((UINT32 *)(p)) & 0x00020000)
+#define HCI_NUM_COMPLETED_PKTS_EV(p) (*((UINT32 *)(p)) & 0x00040000)
+#define HCI_MODE_CHANGE_EV(p) (*((UINT32 *)(p)) & 0x00080000)
+#define HCI_RETURN_LINK_KEYS_EV(p) (*((UINT32 *)(p)) & 0x00100000)
+#define HCI_PIN_CODE_REQUEST_EV(p) (*((UINT32 *)(p)) & 0x00200000)
+#define HCI_LINK_KEY_REQUEST_EV(p) (*((UINT32 *)(p)) & 0x00400000)
+#define HCI_LINK_KEY_NOTIFICATION_EV(p) (*((UINT32 *)(p)) & 0x00800000)
+#define HCI_LOOPBACK_COMMAND_EV(p) (*((UINT32 *)(p)) & 0x01000000)
+#define HCI_DATA_BUF_OVERFLOW_EV(p) (*((UINT32 *)(p)) & 0x02000000)
+#define HCI_MAX_SLOTS_CHANGE_EV(p) (*((UINT32 *)(p)) & 0x04000000)
+#define HCI_READ_CLOCK_OFFSET_COMP_EV(p) (*((UINT32 *)(p)) & 0x08000000)
+#define HCI_CONN_PKT_TYPE_CHANGED_EV(p) (*((UINT32 *)(p)) & 0x10000000)
+#define HCI_QOS_VIOLATION_EV(p) (*((UINT32 *)(p)) & 0x20000000)
+#define HCI_PAGE_SCAN_MODE_CHANGED_EV(p) (*((UINT32 *)(p)) & 0x40000000)
+#define HCI_PAGE_SCAN_REP_MODE_CHNG_EV(p) (*((UINT32 *)(p)) & 0x80000000)
+
+/* the default event mask for 2.1+EDR (Lisbon) does not include Lisbon events */
+#define HCI_DEFAULT_EVENT_MASK_0 0xFFFFFFFF
+#define HCI_DEFAULT_EVENT_MASK_1 0x00001FFF
+
+/* the event mask for 2.0 + EDR and later (includes Lisbon events) */
+#define HCI_LISBON_EVENT_MASK_0 0xFFFFFFFF
+#define HCI_LISBON_EVENT_MASK_1 0x1DBFFFFF
+#define HCI_LISBON_EVENT_MASK "\x0D\xBF\xFF\xFF\xFF\xFF\xFF\xFF"
+#define HCI_LISBON_EVENT_MASK_EXT "\x1D\xBF\xFF\xFF\xFF\xFF\xFF\xFF"
+#define HCI_DUMO_EVENT_MASK_EXT "\x3D\xBF\xFF\xFF\xFF\xFF\xFF\xFF"
+/* 0x00001FFF FFFFFFFF Default - no Lisbon events
+ 0x00000800 00000000 Synchronous Connection Complete Event
+ 0x00001000 00000000 Synchronous Connection Changed Event
+ 0x00002000 00000000 Sniff Subrate Event
+ 0x00004000 00000000 Extended Inquiry Result Event
+ 0x00008000 00000000 Encryption Key Refresh Complete Event
+ 0x00010000 00000000 IO Capability Request Event
+ 0x00020000 00000000 IO Capability Response Event
+ 0x00040000 00000000 User Confirmation Request Event
+ 0x00080000 00000000 User Passkey Request Event
+ 0x00100000 00000000 Remote OOB Data Request Event
+ 0x00200000 00000000 Simple Pairing Complete Event
+ 0x00400000 00000000 Generic AMP Link Key Notification Event
+ 0x00800000 00000000 Link Supervision Timeout Changed Event
+ 0x01000000 00000000 Enhanced Flush Complete Event
+ 0x04000000 00000000 User Passkey Notification Event
+ 0x08000000 00000000 Keypress Notification Event
+ 0x10000000 00000000 Remote Host Supported Features Notification Event
+ 0x20000000 00000000 LE Meta Event
+ */
+
+
+/* the event mask for AMP controllers */
+#define HCI_AMP_EVENT_MASK_3_0 "\x00\x00\x00\x00\x00\x00\x3F\xFF"
+
+/* 0x0000000000000000 No events specified (default)
+ 0x0000000000000001 Physical Link Complete Event
+ 0x0000000000000002 Channel Selected Event
+ 0x0000000000000004 Disconnection Physical Link Event
+ 0x0000000000000008 Physical Link Loss Early Warning Event
+ 0x0000000000000010 Physical Link Recovery Event
+ 0x0000000000000020 Logical Link Complete Event
+ 0x0000000000000040 Disconnection Logical Link Complete Event
+ 0x0000000000000080 Flow Spec Modify Complete Event
+ 0x0000000000000100 Number of Completed Data Blocks Event
+ 0x0000000000000200 AMP Start Test Event
+ 0x0000000000000400 AMP Test End Event
+ 0x0000000000000800 AMP Receiver Report Event
+ 0x0000000000001000 Short Range Mode Change Complete Event
+ 0x0000000000002000 AMP Status Change Event
+*/
+
+
+/*
+** Definitions for packet type masks (BT1.2 and BT2.0 definitions)
+*/
+#define HCI_PKT_TYPES_MASK_NO_2_DH1 0x0002
+#define HCI_PKT_TYPES_MASK_NO_3_DH1 0x0004
+#define HCI_PKT_TYPES_MASK_DM1 0x0008
+#define HCI_PKT_TYPES_MASK_DH1 0x0010
+#define HCI_PKT_TYPES_MASK_HV1 0x0020
+#define HCI_PKT_TYPES_MASK_HV2 0x0040
+#define HCI_PKT_TYPES_MASK_HV3 0x0080
+#define HCI_PKT_TYPES_MASK_NO_2_DH3 0x0100
+#define HCI_PKT_TYPES_MASK_NO_3_DH3 0x0200
+#define HCI_PKT_TYPES_MASK_DM3 0x0400
+#define HCI_PKT_TYPES_MASK_DH3 0x0800
+#define HCI_PKT_TYPES_MASK_NO_2_DH5 0x1000
+#define HCI_PKT_TYPES_MASK_NO_3_DH5 0x2000
+#define HCI_PKT_TYPES_MASK_DM5 0x4000
+#define HCI_PKT_TYPES_MASK_DH5 0x8000
+
+/* Packet type should be one of valid but at least one should be specified */
+#define HCI_VALID_SCO_PKT_TYPE(t) (((((t) & ~(HCI_PKT_TYPES_MASK_HV1 \
+ | HCI_PKT_TYPES_MASK_HV2 \
+ | HCI_PKT_TYPES_MASK_HV3)) == 0)) \
+ && ((t) != 0))
+
+
+
+
+
+/* Packet type should not be invalid and at least one should be specified */
+#define HCI_VALID_ACL_PKT_TYPE(t) (((((t) & ~(HCI_PKT_TYPES_MASK_DM1 \
+ | HCI_PKT_TYPES_MASK_DH1 \
+ | HCI_PKT_TYPES_MASK_DM3 \
+ | HCI_PKT_TYPES_MASK_DH3 \
+ | HCI_PKT_TYPES_MASK_DM5 \
+ | HCI_PKT_TYPES_MASK_DH5 \
+ | HCI_PKT_TYPES_MASK_NO_2_DH1 \
+ | HCI_PKT_TYPES_MASK_NO_3_DH1 \
+ | HCI_PKT_TYPES_MASK_NO_2_DH3 \
+ | HCI_PKT_TYPES_MASK_NO_3_DH3 \
+ | HCI_PKT_TYPES_MASK_NO_2_DH5 \
+ | HCI_PKT_TYPES_MASK_NO_3_DH5 )) == 0)) \
+ && (((t) & (HCI_PKT_TYPES_MASK_DM1 \
+ | HCI_PKT_TYPES_MASK_DH1 \
+ | HCI_PKT_TYPES_MASK_DM3 \
+ | HCI_PKT_TYPES_MASK_DH3 \
+ | HCI_PKT_TYPES_MASK_DM5 \
+ | HCI_PKT_TYPES_MASK_DH5)) != 0))
+
+/*
+** Definitions for eSCO packet type masks (BT1.2 and BT2.0 definitions)
+*/
+#define HCI_ESCO_PKT_TYPES_MASK_HV1 0x0001
+#define HCI_ESCO_PKT_TYPES_MASK_HV2 0x0002
+#define HCI_ESCO_PKT_TYPES_MASK_HV3 0x0004
+#define HCI_ESCO_PKT_TYPES_MASK_EV3 0x0008
+#define HCI_ESCO_PKT_TYPES_MASK_EV4 0x0010
+#define HCI_ESCO_PKT_TYPES_MASK_EV5 0x0020
+#define HCI_ESCO_PKT_TYPES_MASK_NO_2_EV3 0x0040
+#define HCI_ESCO_PKT_TYPES_MASK_NO_3_EV3 0x0080
+#define HCI_ESCO_PKT_TYPES_MASK_NO_2_EV5 0x0100
+#define HCI_ESCO_PKT_TYPES_MASK_NO_3_EV5 0x0200
+
+/* Packet type should be one of valid but at least one should be specified for 1.2 */
+#define HCI_VALID_ESCO_PKT_TYPE(t) (((((t) & ~(HCI_ESCO_PKT_TYPES_MASK_EV3 \
+ | HCI_ESCO_PKT_TYPES_MASK_EV4 \
+ | HCI_ESCO_PKT_TYPES_MASK_EV5)) == 0)) \
+ && ((t) != 0))/* Packet type should be one of valid but at least one should be specified */
+
+#define HCI_VALID_ESCO_SCOPKT_TYPE(t) (((((t) & ~(HCI_ESCO_PKT_TYPES_MASK_HV1 \
+ | HCI_ESCO_PKT_TYPES_MASK_HV2 \
+ | HCI_ESCO_PKT_TYPES_MASK_HV3)) == 0)) \
+ && ((t) != 0))
+
+#define HCI_VALID_SCO_ALL_PKT_TYPE(t) (((((t) & ~(HCI_ESCO_PKT_TYPES_MASK_HV1 \
+ | HCI_ESCO_PKT_TYPES_MASK_HV2 \
+ | HCI_ESCO_PKT_TYPES_MASK_HV3 \
+ | HCI_ESCO_PKT_TYPES_MASK_EV3 \
+ | HCI_ESCO_PKT_TYPES_MASK_EV4 \
+ | HCI_ESCO_PKT_TYPES_MASK_EV5)) == 0)) \
+ && ((t) != 0))
+
+/*
+** Define parameters to allow role switch during create connection
+*/
+#define HCI_CR_CONN_NOT_ALLOW_SWITCH 0x00
+#define HCI_CR_CONN_ALLOW_SWITCH 0x01
+
+/*
+** Hold Mode command destination
+*/
+#define HOLD_MODE_DEST_LOCAL_DEVICE 0x00
+#define HOLD_MODE_DEST_RMT_DEVICE 0x01
+
+/*
+** Definitions for different HCI parameters
+*/
+#define HCI_PER_INQ_MIN_MAX_PERIOD 0x0003
+#define HCI_PER_INQ_MAX_MAX_PERIOD 0xFFFF
+#define HCI_PER_INQ_MIN_MIN_PERIOD 0x0002
+#define HCI_PER_INQ_MAX_MIN_PERIOD 0xFFFE
+
+#define HCI_MAX_INQUIRY_LENGTH 0x30
+
+#define HCI_MIN_INQ_LAP 0x9E8B00
+#define HCI_MAX_INQ_LAP 0x9E8B3F
+
+/* HCI role defenitions */
+#define HCI_ROLE_MASTER 0x00
+#define HCI_ROLE_SLAVE 0x01
+#define HCI_ROLE_UNKNOWN 0xff
+
+/* HCI mode defenitions */
+#define HCI_MODE_ACTIVE 0x00
+#define HCI_MODE_HOLD 0x01
+#define HCI_MODE_SNIFF 0x02
+#define HCI_MODE_PARK 0x03
+
+/* HCI Flow Control Mode defenitions */
+#define HCI_PACKET_BASED_FC_MODE 0x00
+#define HCI_BLOCK_BASED_FC_MODE 0x01
+
+/* Define Packet types as requested by the Host */
+#define HCI_ACL_PKT_TYPE_NONE 0x0000
+#define HCI_ACL_PKT_TYPE_DM1 0x0008
+#define HCI_ACL_PKT_TYPE_DH1 0x0010
+#define HCI_ACL_PKT_TYPE_AUX1 0x0200
+#define HCI_ACL_PKT_TYPE_DM3 0x0400
+#define HCI_ACL_PKT_TYPE_DH3 0x0800
+#define HCI_ACL_PKT_TYPE_DM5 0x4000
+#define HCI_ACL_PKT_TYPE_DH5 0x8000
+
+/* Define key type in the Master Link Key command */
+#define HCI_USE_SEMI_PERMANENT_KEY 0x00
+#define HCI_USE_TEMPORARY_KEY 0x01
+
+/* Page scan period modes */
+#define HCI_PAGE_SCAN_REP_MODE_R0 0x00
+#define HCI_PAGE_SCAN_REP_MODE_R1 0x01
+#define HCI_PAGE_SCAN_REP_MODE_R2 0x02
+
+/* Define limits for page scan repetition modes */
+#define HCI_PAGE_SCAN_R1_LIMIT 0x0800
+#define HCI_PAGE_SCAN_R2_LIMIT 0x1000
+
+/* Page scan period modes */
+#define HCI_PAGE_SCAN_PER_MODE_P0 0x00
+#define HCI_PAGE_SCAN_PER_MODE_P1 0x01
+#define HCI_PAGE_SCAN_PER_MODE_P2 0x02
+
+/* Page scan modes */
+#define HCI_MANDATARY_PAGE_SCAN_MODE 0x00
+#define HCI_OPTIONAL_PAGE_SCAN_MODE1 0x01
+#define HCI_OPTIONAL_PAGE_SCAN_MODE2 0x02
+#define HCI_OPTIONAL_PAGE_SCAN_MODE3 0x03
+
+/* Page and inquiry scan types */
+#define HCI_SCAN_TYPE_STANDARD 0x00
+#define HCI_SCAN_TYPE_INTERLACED 0x01 /* 1.2 devices or later */
+#define HCI_DEF_SCAN_TYPE HCI_SCAN_TYPE_STANDARD
+
+/* Definitions for quality of service service types */
+#define HCI_SERVICE_NO_TRAFFIC 0x00
+#define HCI_SERVICE_BEST_EFFORT 0x01
+#define HCI_SERVICE_GUARANTEED 0x02
+
+#define HCI_QOS_LATENCY_DO_NOT_CARE 0xFFFFFFFF
+#define HCI_QOS_DELAY_DO_NOT_CARE 0xFFFFFFFF
+
+/* Definitions for Flow Specification */
+#define HCI_FLOW_SPEC_LATENCY_DO_NOT_CARE 0xFFFFFFFF
+
+/* Definitions for AFH Channel Map */
+#define HCI_AFH_CHANNEL_MAP_LEN 10
+
+/* Definitions for Extended Inquiry Response */
+#define HCI_EXT_INQ_RESPONSE_LEN 240
+#define HCI_EIR_FLAGS_TYPE BT_EIR_FLAGS_TYPE
+#define HCI_EIR_MORE_16BITS_UUID_TYPE BT_EIR_MORE_16BITS_UUID_TYPE
+#define HCI_EIR_COMPLETE_16BITS_UUID_TYPE BT_EIR_COMPLETE_16BITS_UUID_TYPE
+#define HCI_EIR_MORE_32BITS_UUID_TYPE BT_EIR_MORE_32BITS_UUID_TYPE
+#define HCI_EIR_COMPLETE_32BITS_UUID_TYPE BT_EIR_COMPLETE_32BITS_UUID_TYPE
+#define HCI_EIR_MORE_128BITS_UUID_TYPE BT_EIR_MORE_128BITS_UUID_TYPE
+#define HCI_EIR_COMPLETE_128BITS_UUID_TYPE BT_EIR_COMPLETE_128BITS_UUID_TYPE
+#define HCI_EIR_SHORTENED_LOCAL_NAME_TYPE BT_EIR_SHORTENED_LOCAL_NAME_TYPE
+#define HCI_EIR_COMPLETE_LOCAL_NAME_TYPE BT_EIR_COMPLETE_LOCAL_NAME_TYPE
+#define HCI_EIR_TX_POWER_LEVEL_TYPE BT_EIR_TX_POWER_LEVEL_TYPE
+#define HCI_EIR_MANUFACTURER_SPECIFIC_TYPE BT_EIR_MANUFACTURER_SPECIFIC_TYPE
+#define HCI_EIR_OOB_BD_ADDR_TYPE BT_EIR_OOB_BD_ADDR_TYPE
+#define HCI_EIR_OOB_COD_TYPE BT_EIR_OOB_COD_TYPE
+#define HCI_EIR_OOB_SSP_HASH_C_TYPE BT_EIR_OOB_SSP_HASH_C_TYPE
+#define HCI_EIR_OOB_SSP_RAND_R_TYPE BT_EIR_OOB_SSP_RAND_R_TYPE
+
+/* Definitions for Write Simple Pairing Mode */
+#define HCI_SP_MODE_UNDEFINED 0x00
+#define HCI_SP_MODE_ENABLED 0x01
+
+/* Definitions for Write Simple Pairing Debug Mode */
+#define HCI_SPD_MODE_DISABLED 0x00
+#define HCI_SPD_MODE_ENABLED 0x01
+
+/* Definitions for IO Capability Response/Command */
+#define HCI_IO_CAP_DISPLAY_ONLY 0x00
+#define HCI_IO_CAP_DISPLAY_YESNO 0x01
+#define HCI_IO_CAP_KEYBOARD_ONLY 0x02
+#define HCI_IO_CAP_NO_IO 0x03
+
+#define HCI_OOB_AUTH_DATA_NOT_PRESENT 0x00
+#define HCI_OOB_REM_AUTH_DATA_PRESENT 0x01
+
+#define HCI_MITM_PROTECT_NOT_REQUIRED 0x00
+#define HCI_MITM_PROTECT_REQUIRED 0x01
+
+
+/* Policy settings status */
+#define HCI_DISABLE_ALL_LM_MODES 0x0000
+#define HCI_ENABLE_MASTER_SLAVE_SWITCH 0x0001
+#define HCI_ENABLE_HOLD_MODE 0x0002
+#define HCI_ENABLE_SNIFF_MODE 0x0004
+#define HCI_ENABLE_PARK_MODE 0x0008
+
+/* By default allow switch, because host can not allow that */
+/* that until he created the connection */
+#define HCI_DEFAULT_POLICY_SETTINGS HCI_DISABLE_ALL_LM_MODES
+
+/* Filters that are sent in set filter command */
+#define HCI_FILTER_TYPE_CLEAR_ALL 0x00
+#define HCI_FILTER_INQUIRY_RESULT 0x01
+#define HCI_FILTER_CONNECTION_SETUP 0x02
+
+#define HCI_FILTER_COND_NEW_DEVICE 0x00
+#define HCI_FILTER_COND_DEVICE_CLASS 0x01
+#define HCI_FILTER_COND_BD_ADDR 0x02
+
+#define HCI_DO_NOT_AUTO_ACCEPT_CONNECT 1
+#define HCI_DO_AUTO_ACCEPT_CONNECT 2 /* role switch disabled */
+#define HCI_DO_AUTO_ACCEPT_CONNECT_RS 3 /* role switch enabled (1.1 errata 1115) */
+
+/* Auto accept flags */
+#define HCI_AUTO_ACCEPT_OFF 0x00
+#define HCI_AUTO_ACCEPT_ACL_CONNECTIONS 0x01
+#define HCI_AUTO_ACCEPT_SCO_CONNECTIONS 0x02
+
+/* PIN type */
+#define HCI_PIN_TYPE_VARIABLE 0
+#define HCI_PIN_TYPE_FIXED 1
+
+/* Loopback Modes */
+#define HCI_LOOPBACK_MODE_DISABLED 0
+#define HCI_LOOPBACK_MODE_LOCAL 1
+#define HCI_LOOPBACK_MODE_REMOTE 2
+
+#define SLOTS_PER_10MS 16 /* 0.625 ms slots in a 10 ms tick */
+
+/* Maximum connection accept timeout in 0.625msec */
+#define HCI_MAX_CONN_ACCEPT_TOUT 0xB540 /* 29 sec */
+#define HCI_DEF_CONN_ACCEPT_TOUT 0x1F40 /* 5 sec */
+
+/* Page timeout is used in LC only and LC is counting down slots not using OS */
+#define HCI_DEFAULT_PAGE_TOUT 0x2000 /* 5.12 sec (in slots) */
+
+/* Scan enable flags */
+#define HCI_NO_SCAN_ENABLED 0x00
+#define HCI_INQUIRY_SCAN_ENABLED 0x01
+#define HCI_PAGE_SCAN_ENABLED 0x02
+
+/* Pagescan timer definitions in 0.625 ms */
+#define HCI_MIN_PAGESCAN_INTERVAL 0x12 /* 11.25 ms */
+#define HCI_MAX_PAGESCAN_INTERVAL 0x1000 /* 2.56 sec */
+#define HCI_DEF_PAGESCAN_INTERVAL 0x0800 /* 1.28 sec */
+
+/* Parameter for pagescan window is passed to LC and is kept in slots */
+#define HCI_MIN_PAGESCAN_WINDOW 0x11 /* 10.625 ms */
+#define HCI_MAX_PAGESCAN_WINDOW 0x1000 /* 2.56 sec */
+#define HCI_DEF_PAGESCAN_WINDOW 0x12 /* 11.25 ms */
+
+/* Inquiryscan timer definitions in 0.625 ms */
+#define HCI_MIN_INQUIRYSCAN_INTERVAL 0x12 /* 11.25 ms */
+#define HCI_MAX_INQUIRYSCAN_INTERVAL 0x1000 /* 2.56 sec */
+#define HCI_DEF_INQUIRYSCAN_INTERVAL 0x1000 /* 2.56 sec */
+
+/* Parameter for inquiryscan window is passed to LC and is kept in slots */
+#define HCI_MIN_INQUIRYSCAN_WINDOW 0x11 /* 10.625 ms */
+#define HCI_MAX_INQUIRYSCAN_WINDOW 0x1000 /* 2.56 sec */
+#define HCI_DEF_INQUIRYSCAN_WINDOW 0x12 /* 11.25 ms */
+
+/* Encryption modes */
+#define HCI_ENCRYPT_MODE_DISABLED 0x00
+#define HCI_ENCRYPT_MODE_POINT_TO_POINT 0x01
+#define HCI_ENCRYPT_MODE_ALL 0x02
+
+/* Voice settings */
+#define HCI_INP_CODING_LINEAR 0x0000 /* 0000000000 */
+#define HCI_INP_CODING_U_LAW 0x0100 /* 0100000000 */
+#define HCI_INP_CODING_A_LAW 0x0200 /* 1000000000 */
+#define HCI_INP_CODING_MASK 0x0300 /* 1100000000 */
+
+#define HCI_INP_DATA_FMT_1S_COMPLEMENT 0x0000 /* 0000000000 */
+#define HCI_INP_DATA_FMT_2S_COMPLEMENT 0x0040 /* 0001000000 */
+#define HCI_INP_DATA_FMT_SIGN_MAGNITUDE 0x0080 /* 0010000000 */
+#define HCI_INP_DATA_FMT_UNSIGNED 0x00c0 /* 0011000000 */
+#define HCI_INP_DATA_FMT_MASK 0x00c0 /* 0011000000 */
+
+#define HCI_INP_SAMPLE_SIZE_8BIT 0x0000 /* 0000000000 */
+#define HCI_INP_SAMPLE_SIZE_16BIT 0x0020 /* 0000100000 */
+#define HCI_INP_SAMPLE_SIZE_MASK 0x0020 /* 0000100000 */
+
+#define HCI_INP_LINEAR_PCM_BIT_POS_MASK 0x001c /* 0000011100 */
+#define HCI_INP_LINEAR_PCM_BIT_POS_OFFS 2
+
+#define HCI_AIR_CODING_FORMAT_CVSD 0x0000 /* 0000000000 */
+#define HCI_AIR_CODING_FORMAT_U_LAW 0x0001 /* 0000000001 */
+#define HCI_AIR_CODING_FORMAT_A_LAW 0x0002 /* 0000000010 */
+#define HCI_AIR_CODING_FORMAT_TRANSPNT 0x0003 /* 0000000011 */
+#define HCI_AIR_CODING_FORMAT_MASK 0x0003 /* 0000000011 */
+
+/* default 0001100000 */
+#define HCI_DEFAULT_VOICE_SETTINGS (HCI_INP_CODING_LINEAR \
+ | HCI_INP_DATA_FMT_2S_COMPLEMENT \
+ | HCI_INP_SAMPLE_SIZE_16BIT \
+ | HCI_AIR_CODING_FORMAT_CVSD)
+
+#define HCI_CVSD_SUPPORTED(x) (((x) & HCI_AIR_CODING_FORMAT_MASK) == HCI_AIR_CODING_FORMAT_CVSD)
+#define HCI_U_LAW_SUPPORTED(x) (((x) & HCI_AIR_CODING_FORMAT_MASK) == HCI_AIR_CODING_FORMAT_U_LAW)
+#define HCI_A_LAW_SUPPORTED(x) (((x) & HCI_AIR_CODING_FORMAT_MASK) == HCI_AIR_CODING_FORMAT_A_LAW)
+#define HCI_TRANSPNT_SUPPORTED(x) (((x) & HCI_AIR_CODING_FORMAT_MASK) == HCI_AIR_CODING_FORMAT_TRANSPNT)
+
+/* Retransmit timer definitions in 0.625 */
+#define HCI_MAX_AUTO_FLUSH_TOUT 0x07FF
+#define HCI_DEFAULT_AUTO_FLUSH_TOUT 0 /* No auto flush */
+
+/* Broadcast retransmitions */
+#define HCI_DEFAULT_NUM_BCAST_RETRAN 1
+
+/* Define broadcast data types as passed in the hci data packet */
+#define HCI_DATA_POINT_TO_POINT 0x00
+#define HCI_DATA_ACTIVE_BCAST 0x01
+#define HCI_DATA_PICONET_BCAST 0x02
+
+/* Hold mode activity */
+#define HCI_MAINTAIN_CUR_POWER_STATE 0x00
+#define HCI_SUSPEND_PAGE_SCAN 0x01
+#define HCI_SUSPEND_INQUIRY_SCAN 0x02
+#define HCI_SUSPEND_PERIODIC_INQUIRIES 0x04
+
+/* Default Link Supervision timeoout */
+#define HCI_DEFAULT_INACT_TOUT 0x7D00 /* BR/EDR (20 seconds) */
+#define HCI_DEFAULT_AMP_INACT_TOUT 0x3E80 /* AMP (10 seconds) */
+
+/* Read transmit power level parameter */
+#define HCI_READ_CURRENT 0x00
+#define HCI_READ_MAXIMUM 0x01
+
+/* Link types for connection complete event */
+#define HCI_LINK_TYPE_SCO 0x00
+#define HCI_LINK_TYPE_ACL 0x01
+#define HCI_LINK_TYPE_ESCO 0x02
+
+/* Link Key Notification Event (Key Type) definitions */
+#define HCI_LKEY_TYPE_COMBINATION 0x00
+#define HCI_LKEY_TYPE_LOCAL_UNIT 0x01
+#define HCI_LKEY_TYPE_REMOTE_UNIT 0x02
+#define HCI_LKEY_TYPE_DEBUG_COMB 0x03
+#define HCI_LKEY_TYPE_UNAUTH_COMB 0x04
+#define HCI_LKEY_TYPE_AUTH_COMB 0x05
+#define HCI_LKEY_TYPE_CHANGED_COMB 0x06
+
+/* Internal definitions - not used over HCI */
+#define HCI_LKEY_TYPE_AMP_WIFI 0x80
+#define HCI_LKEY_TYPE_AMP_UWB 0x81
+#define HCI_LKEY_TYPE_UNKNOWN 0xff
+
+/* Read Local Version HCI Version return values (Command Complete Event) */
+#define HCI_VERSION_1_0B 0x00
+#define HCI_VERSION_1_1 0x01
+
+/* Define an invalid value for a handle */
+#define HCI_INVALID_HANDLE 0xFFFF
+
+/* Define max ammount of data in the HCI command */
+#define HCI_COMMAND_SIZE 255
+
+/* Define the preamble length for all HCI Commands.
+** This is 2-bytes for opcode and 1 byte for length
+*/
+#define HCIC_PREAMBLE_SIZE 3
+
+/* Define the preamble length for all HCI Events
+** This is 1-byte for opcode and 1 byte for length
+*/
+#define HCIE_PREAMBLE_SIZE 2
+#define HCI_SCO_PREAMBLE_SIZE 3
+#define HCI_DATA_PREAMBLE_SIZE 4
+
+/* local Bluetooth controller id for AMP HCI */
+#define LOCAL_BR_EDR_CONTROLLER_ID 0
+
+/* controller id types for AMP HCI */
+#define HCI_CONTROLLER_TYPE_BR_EDR 0
+#define HCI_CONTROLLER_TYPE_802_11 1
+#define HCI_CONTROLLER_TYPE_ECMA 2
+#define HCI_MAX_CONTROLLER_TYPES 3
+
+
+
+
+/* AMP Controller Status codes
+*/
+#define HCI_AMP_CTRLR_PHYSICALLY_DOWN 0
+#define HCI_AMP_CTRLR_USABLE_BY_BT 1
+#define HCI_AMP_CTRLR_UNUSABLE_FOR_BT 2
+#define HCI_AMP_CTRLR_LOW_CAP_FOR_BT 3
+#define HCI_AMP_CTRLR_MED_CAP_FOR_BT 4
+#define HCI_AMP_CTRLR_HIGH_CAP_FOR_BT 5
+#define HCI_AMP_CTRLR_FULL_CAP_FOR_BT 6
+
+#define HCI_MAX_AMP_STATUS_TYPES 7
+
+
+/* Define the extended flow specification fields used by AMP */
+typedef struct
+{
+ UINT8 id;
+ UINT8 stype;
+ UINT16 max_sdu_size;
+ UINT32 sdu_inter_time;
+ UINT32 access_latency;
+ UINT32 flush_timeout;
+} tHCI_EXT_FLOW_SPEC;
+
+
+/* HCI message type definitions (for H4 messages) */
+#define HCIT_TYPE_COMMAND 1
+#define HCIT_TYPE_ACL_DATA 2
+#define HCIT_TYPE_SCO_DATA 3
+#define HCIT_TYPE_EVENT 4
+#define HCIT_TYPE_LM_DIAG 7
+#define HCIT_TYPE_NFC 16
+
+#define HCIT_LM_DIAG_LENGTH 63
+
+/* Define values for LMP Test Control parameters
+** Test Scenario, Hopping Mode, Power Control Mode
+*/
+#define LMP_TESTCTL_TESTSC_PAUSE 0
+#define LMP_TESTCTL_TESTSC_TXTEST_0 1
+#define LMP_TESTCTL_TESTSC_TXTEST_1 2
+#define LMP_TESTCTL_TESTSC_TXTEST_1010 3
+#define LMP_TESTCTL_TESTSC_PSRND_BITSEQ 4
+#define LMP_TESTCTL_TESTSC_CLOSEDLB_ACL 5
+#define LMP_TESTCTL_TESTSC_CLOSEDLB_SCO 6
+#define LMP_TESTCTL_TESTSC_ACL_NOWHIT 7
+#define LMP_TESTCTL_TESTSC_SCO_NOWHIT 8
+#define LMP_TESTCTL_TESTSC_TXTEST_11110000 9
+#define LMP_TESTCTL_TESTSC_EXITTESTMODE 255
+
+#define LMP_TESTCTL_HOPMOD_RXTX1FREQ 0
+#define LMP_TESTCTL_HOPMOD_HOP_EURUSA 1
+#define LMP_TESTCTL_HOPMOD_HOP_JAPAN 2
+#define LMP_TESTCTL_HOPMOD_HOP_FRANCE 3
+#define LMP_TESTCTL_HOPMOD_HOP_SPAIN 4
+#define LMP_TESTCTL_HOPMOD_REDUCED_HOP 5
+
+#define LMP_TESTCTL_POWCTL_FIXEDTX_OP 0
+#define LMP_TESTCTL_POWCTL_ADAPTIVE 1
+
+
+/*
+** Define company IDs (from Bluetooth Assigned Numbers v1.1, section 2.2)
+*/
+#define LMP_COMPID_ERICSSON 0
+#define LMP_COMPID_NOKIA 1
+#define LMP_COMPID_INTEL 2
+#define LMP_COMPID_IBM 3
+#define LMP_COMPID_TOSHIBA 4
+#define LMP_COMPID_3COM 5
+#define LMP_COMPID_MICROSOFT 6
+#define LMP_COMPID_LUCENT 7
+#define LMP_COMPID_MOTOROLA 8
+#define LMP_COMPID_INFINEON 9
+#define LMP_COMPID_CSR 10
+#define LMP_COMPID_SILICON_WAVE 11
+#define LMP_COMPID_DIGIANSWER 12
+#define LMP_COMPID_TEXAS_INSTRUMENTS 13
+#define LMP_COMPID_PARTHUS 14
+#define LMP_COMPID_BROADCOM 15
+#define LMP_COMPID_MITEL_SEMI 16
+#define LMP_COMPID_WIDCOMM 17
+#define LMP_COMPID_ZEEVO 18
+#define LMP_COMPID_ATMEL 19
+#define LMP_COMPID_MITSUBISHI 20
+#define LMP_COMPID_RTX_TELECOM 21
+#define LMP_COMPID_KC_TECH 22
+#define LMP_COMPID_NEWLOGIC 23
+#define LMP_COMPID_TRANSILICA 24
+#define LMP_COMPID_ROHDE_SCHWARZ 25
+#define LMP_COMPID_TTPCOM 26
+#define LMP_COMPID_SIGNIA 27
+#define LMP_COMPID_CONEXANT 28
+#define LMP_COMPID_QUALCOMM 29
+#define LMP_COMPID_INVENTEL 30
+#define LMP_COMPID_AVM 31
+#define LMP_COMPID_BANDSPEED 32
+#define LMP_COMPID_MANSELLA 33
+#define LMP_COMPID_NEC_CORP 34
+#define LMP_COMPID_WAVEPLUS 35
+#define LMP_COMPID_ALCATEL 36
+#define LMP_COMPID_PHILIPS 37
+#define LMP_COMPID_C_TECHNOLOGIES 38
+#define LMP_COMPID_OPEN_INTERFACE 39
+#define LMP_COMPID_RF_MICRO 40
+#define LMP_COMPID_HITACHI 41
+#define LMP_COMPID_SYMBOL_TECH 42
+#define LMP_COMPID_TENOVIS 43
+#define LMP_COMPID_MACRONIX 44
+#define LMP_COMPID_GCT_SEMI 45
+#define LMP_COMPID_NORWOOD_SYSTEMS 46
+#define LMP_COMPID_MEWTEL_TECH 47
+#define LMP_COMPID_STM 48
+#define LMP_COMPID_SYNOPSYS 49
+#define LMP_COMPID_RED_M_LTD 50
+#define LMP_COMPID_COMMIL_LTD 51
+#define LMP_COMPID_CATC 52
+#define LMP_COMPID_ECLIPSE 53
+#define LMP_COMPID_RENESAS_TECH 54
+#define LMP_COMPID_MOBILIAN_CORP 55
+#define LMP_COMPID_TERAX 56
+#define LMP_COMPID_ISSC 57
+#define LMP_COMPID_MATSUSHITA 58
+#define LMP_COMPID_GENNUM_CORP 59
+#define LMP_COMPID_RESEARCH_IN_MOTION 60
+#define LMP_COMPID_IPEXTREME 61
+#define LMP_COMPID_SYSTEMS_AND_CHIPS 62
+#define LMP_COMPID_BLUETOOTH_SIG 63
+#define LMP_COMPID_SEIKO_EPSON_CORP 64
+#define LMP_COMPID_ISS_TAIWAN 65
+#define LMP_COMPID_CONWISE_TECHNOLOGIES 66
+#define LMP_COMPID_PARROT_SA 67
+#define LMP_COMPID_SOCKET_COMM 68
+#define LMP_COMPID_ALTHEROS 69
+#define LMP_COMPID_MEDIATEK 70
+#define LMP_COMPID_BLUEGIGA 71
+#define LMP_COMPID_MARVELL 72
+#define LMP_COMPID_3DSP_CORP 73
+#define LMP_COMPID_ACCEL_SEMICONDUCTOR 74
+#define LMP_COMPID_CONTINENTAL_AUTO 75
+#define LMP_COMPID_APPLE 76
+#define LMP_COMPID_STACCATO 77
+#define LMP_COMPID_AVAGO_TECHNOLOGIES 78
+#define LMP_COMPID_APT_LTD 79
+#define LMP_COMPID_SIRF_TECHNOLOGY 80
+#define LMP_COMPID_TZERO_TECHNOLOGY 81
+#define LMP_COMPID_J_AND_M_CORP 82
+#define LMP_COMPID_FREE_2_MOVE 83
+#define LMP_COMPID_3DIJOY_CORP 84
+#define LMP_COMPID_PLANTRONICS 85
+#define LMP_COMPID_SONY_ERICSSON_MOBILE 86
+#define LMP_COMPID_HARMON_INTL_IND 87
+#define LMP_COMPID_VIZIO 88
+#define LMP_COMPID_NORDIC SEMI 89
+#define LMP_COMPID_EM MICRO 90
+#define LMP_COMPID_RALINK TECH 91
+#define LMP_COMPID_BELKIN INC 92
+#define LMP_COMPID_REALTEK SEMI 93
+#define LMP_COMPID_STONESTREET ONE 94
+#define LMP_COMPID_WICENTRIC 95
+#define LMP_COMPID_RIVIERAWAVES 96
+#define LMP_COMPID_RDA MICRO 97
+#define LMP_COMPID_GIBSON GUITARS 98
+#define LMP_COMPID_MICOMMAND INC 99
+#define LMP_COMPID_BAND XI 100
+#define LMP_COMPID_HP COMPANY 101
+#define LMP_COMPID_9SOLUTIONS OY 102
+#define LMP_COMPID_GN NETCOM 103
+#define LMP_COMPID_GENERAL MOTORS 104
+#define LMP_COMPID_AD ENGINEERING 105
+#define LMP_COMPID_MINDTREE LTD 106
+#define LMP_COMPID_POLAR ELECTRO 107
+#define LMP_COMPID_BEAUTIFUL ENTERPRISE 108
+#define LMP_COMPID_BRIARTEK 109
+#define LMP_COMPID_SUMMIT DATA COMM 110
+#define LMP_COMPID_SOUND ID 111
+#define LMP_COMPID_MONSTER LLC 112
+#define LMP_COMPID_CONNECTBLU 113
+#define LMP_COMPID_MAX_ID 114 /* this is a place holder */
+#define LMP_COMPID_INTERNAL 65535
+
+#define MAX_LMP_COMPID (LMP_COMPID_MAX_ID)
+/*
+** Define the packet types in the packet header, and a couple extra
+*/
+#define PKT_TYPE_NULL 0x00
+#define PKT_TYPE_POLL 0x01
+#define PKT_TYPE_FHS 0x02
+#define PKT_TYPE_DM1 0x03
+
+#define PKT_TYPE_DH1 0x04
+#define PKT_TYPE_HV1 0x05
+#define PKT_TYPE_HV2 0x06
+#define PKT_TYPE_HV3 0x07
+#define PKT_TYPE_DV 0x08
+#define PKT_TYPE_AUX1 0x09
+
+#define PKT_TYPE_DM3 0x0a
+#define PKT_TYPE_DH3 0x0b
+
+#define PKT_TYPE_DM5 0x0e
+#define PKT_TYPE_DH5 0x0f
+
+
+#define PKT_TYPE_ID 0x10 /* Internally used packet types */
+#define PKT_TYPE_BAD 0x11
+#define PKT_TYPE_NONE 0x12
+
+/*
+** Define packet size
+*/
+#define HCI_DM1_PACKET_SIZE 17
+#define HCI_DH1_PACKET_SIZE 27
+#define HCI_DM3_PACKET_SIZE 121
+#define HCI_DH3_PACKET_SIZE 183
+#define HCI_DM5_PACKET_SIZE 224
+#define HCI_DH5_PACKET_SIZE 339
+#define HCI_AUX1_PACKET_SIZE 29
+#define HCI_HV1_PACKET_SIZE 10
+#define HCI_HV2_PACKET_SIZE 20
+#define HCI_HV3_PACKET_SIZE 30
+#define HCI_DV_PACKET_SIZE 9
+#define HCI_EDR2_DH1_PACKET_SIZE 54
+#define HCI_EDR2_DH3_PACKET_SIZE 367
+#define HCI_EDR2_DH5_PACKET_SIZE 679
+#define HCI_EDR3_DH1_PACKET_SIZE 83
+#define HCI_EDR3_DH3_PACKET_SIZE 552
+#define HCI_EDR3_DH5_PACKET_SIZE 1021
+
+/*
+** Features encoding - page 0
+*/
+#define HCI_NUM_FEATURE_BYTES 8
+#define HCI_FEATURES_KNOWN(x) ((x[0] | x[1] | x[2] | x[3] | x[4] | x[5] | x[6] | x[7]) != 0)
+
+#define HCI_FEATURE_3_SLOT_PACKETS_MASK 0x01
+#define HCI_FEATURE_3_SLOT_PACKETS_OFF 0
+#define HCI_3_SLOT_PACKETS_SUPPORTED(x) ((x)[HCI_FEATURE_3_SLOT_PACKETS_OFF] & HCI_FEATURE_3_SLOT_PACKETS_MASK)
+
+#define HCI_FEATURE_5_SLOT_PACKETS_MASK 0x02
+#define HCI_FEATURE_5_SLOT_PACKETS_OFF 0
+#define HCI_5_SLOT_PACKETS_SUPPORTED(x) ((x)[HCI_FEATURE_5_SLOT_PACKETS_OFF] & HCI_FEATURE_5_SLOT_PACKETS_MASK)
+
+#define HCI_FEATURE_ENCRYPTION_MASK 0x04
+#define HCI_FEATURE_ENCRYPTION_OFF 0
+#define HCI_ENCRYPTION_SUPPORTED(x) ((x)[HCI_FEATURE_ENCRYPTION_OFF] & HCI_FEATURE_ENCRYPTION_MASK)
+
+#define HCI_FEATURE_SLOT_OFFSET_MASK 0x08
+#define HCI_FEATURE_SLOT_OFFSET_OFF 0
+#define HCI_SLOT_OFFSET_SUPPORTED(x) ((x)[HCI_FEATURE_SLOT_OFFSET_OFF] & HCI_FEATURE_SLOT_OFFSET_MASK)
+
+#define HCI_FEATURE_TIMING_ACC_MASK 0x10
+#define HCI_FEATURE_TIMING_ACC_OFF 0
+#define HCI_TIMING_ACC_SUPPORTED(x) ((x)[HCI_FEATURE_TIMING_ACC_OFF] & HCI_FEATURE_TIMING_ACC_MASK)
+
+#define HCI_FEATURE_SWITCH_MASK 0x20
+#define HCI_FEATURE_SWITCH_OFF 0
+#define HCI_SWITCH_SUPPORTED(x) ((x)[HCI_FEATURE_SWITCH_OFF] & HCI_FEATURE_SWITCH_MASK)
+
+#define HCI_FEATURE_HOLD_MODE_MASK 0x40
+#define HCI_FEATURE_HOLD_MODE_OFF 0
+#define HCI_HOLD_MODE_SUPPORTED(x) ((x)[HCI_FEATURE_HOLD_MODE_OFF] & HCI_FEATURE_HOLD_MODE_MASK)
+
+#define HCI_FEATURE_SNIFF_MODE_MASK 0x80
+#define HCI_FEATURE_SNIFF_MODE_OFF 0
+#define HCI_SNIFF_MODE_SUPPORTED(x) ((x)[HCI_FEATURE_SNIFF_MODE_OFF] & HCI_FEATURE_SNIFF_MODE_MASK)
+
+#define HCI_FEATURE_PARK_MODE_MASK 0x01
+#define HCI_FEATURE_PARK_MODE_OFF 1
+#define HCI_PARK_MODE_SUPPORTED(x) ((x)[HCI_FEATURE_PARK_MODE_OFF] & HCI_FEATURE_PARK_MODE_MASK)
+
+#define HCI_FEATURE_RSSI_MASK 0x02
+#define HCI_FEATURE_RSSI_OFF 1
+#define HCI_RSSI_SUPPORTED(x) ((x)[HCI_FEATURE_RSSI_OFF] & HCI_FEATURE_RSSI_MASK)
+
+#define HCI_FEATURE_CQM_DATA_RATE_MASK 0x04
+#define HCI_FEATURE_CQM_DATA_RATE_OFF 1
+#define HCI_CQM_DATA_RATE_SUPPORTED(x) ((x)[HCI_FEATURE_CQM_DATA_RATE_OFF] & HCI_FEATURE_CQM_DATA_RATE_MASK)
+
+#define HCI_FEATURE_SCO_LINK_MASK 0x08
+#define HCI_FEATURE_SCO_LINK_OFF 1
+#define HCI_SCO_LINK_SUPPORTED(x) ((x)[HCI_FEATURE_SCO_LINK_OFF] & HCI_FEATURE_SCO_LINK_MASK)
+
+#define HCI_FEATURE_HV2_PACKETS_MASK 0x10
+#define HCI_FEATURE_HV2_PACKETS_OFF 1
+#define HCI_HV2_PACKETS_SUPPORTED(x) ((x)[HCI_FEATURE_HV2_PACKETS_OFF] & HCI_FEATURE_HV2_PACKETS_MASK)
+
+#define HCI_FEATURE_HV3_PACKETS_MASK 0x20
+#define HCI_FEATURE_HV3_PACKETS_OFF 1
+#define HCI_HV3_PACKETS_SUPPORTED(x) ((x)[HCI_FEATURE_HV3_PACKETS_OFF] & HCI_FEATURE_HV3_PACKETS_MASK)
+
+#define HCI_FEATURE_U_LAW_MASK 0x40
+#define HCI_FEATURE_U_LAW_OFF 1
+#define HCI_LMP_U_LAW_SUPPORTED(x) ((x)[HCI_FEATURE_U_LAW_OFF] & HCI_FEATURE_U_LAW_MASK)
+
+#define HCI_FEATURE_A_LAW_MASK 0x80
+#define HCI_FEATURE_A_LAW_OFF 1
+#define HCI_LMP_A_LAW_SUPPORTED(x) ((x)[HCI_FEATURE_A_LAW_OFF] & HCI_FEATURE_A_LAW_MASK)
+
+#define HCI_FEATURE_CVSD_MASK 0x01
+#define HCI_FEATURE_CVSD_OFF 2
+#define HCI_LMP_CVSD_SUPPORTED(x) ((x)[HCI_FEATURE_CVSD_OFF] & HCI_FEATURE_CVSD_MASK)
+
+#define HCI_FEATURE_PAGING_SCHEME_MASK 0x02
+#define HCI_FEATURE_PAGING_SCHEME_OFF 2
+#define HCI_PAGING_SCHEME_SUPPORTED(x) ((x)[HCI_FEATURE_PAGING_SCHEME_OFF] & HCI_FEATURE_PAGING_SCHEME_MASK)
+
+#define HCI_FEATURE_POWER_CTRL_MASK 0x04
+#define HCI_FEATURE_POWER_CTRL_OFF 2
+#define HCI_POWER_CTRL_SUPPORTED(x) ((x)[HCI_FEATURE_POWER_CTRL_OFF] & HCI_FEATURE_POWER_CTRL_MASK)
+
+#define HCI_FEATURE_TRANSPNT_MASK 0x08
+#define HCI_FEATURE_TRANSPNT_OFF 2
+#define HCI_LMP_TRANSPNT_SUPPORTED(x) ((x)[HCI_FEATURE_TRANSPNT_OFF] & HCI_FEATURE_TRANSPNT_MASK)
+
+#define HCI_FEATURE_FLOW_CTRL_LAG_MASK 0x70
+#define HCI_FEATURE_FLOW_CTRL_LAG_OFF 2
+#define HCI_FLOW_CTRL_LAG_VALUE(x) (((x)[HCI_FEATURE_FLOW_CTRL_LAG_OFF] & HCI_FEATURE_FLOW_CTRL_LAG_MASK) >> 4)
+
+#define HCI_FEATURE_BROADCAST_ENC_MASK 0x80
+#define HCI_FEATURE_BROADCAST_ENC_OFF 2
+#define HCI_LMP_BCAST_ENC_SUPPORTED(x) ((x)[HCI_FEATURE_BROADCAST_ENC_OFF] & HCI_FEATURE_BROADCAST_ENC_MASK)
+
+#define HCI_FEATURE_SCATTER_MODE_MASK 0x01
+#define HCI_FEATURE_SCATTER_MODE_OFF 3
+#define HCI_LMP_SCATTER_MODE_SUPPORTED(x) ((x)[HCI_FEATURE_SCATTER_MODE_OFF] & HCI_FEATURE_SCATTER_MODE_MASK)
+
+#define HCI_FEATURE_EDR_ACL_2MPS_MASK 0x02
+#define HCI_FEATURE_EDR_ACL_2MPS_OFF 3
+#define HCI_EDR_ACL_2MPS_SUPPORTED(x) ((x)[HCI_FEATURE_EDR_ACL_2MPS_OFF] & HCI_FEATURE_EDR_ACL_2MPS_MASK)
+
+#define HCI_FEATURE_EDR_ACL_3MPS_MASK 0x04
+#define HCI_FEATURE_EDR_ACL_3MPS_OFF 3
+#define HCI_EDR_ACL_3MPS_SUPPORTED(x) ((x)[HCI_FEATURE_EDR_ACL_3MPS_OFF] & HCI_FEATURE_EDR_ACL_3MPS_MASK)
+
+#define HCI_FEATURE_ENHANCED_INQ_MASK 0x08
+#define HCI_FEATURE_ENHANCED_INQ_OFF 3
+#define HCI_ENHANCED_INQ_SUPPORTED(x) ((x)[HCI_FEATURE_ENHANCED_INQ_OFF] & HCI_FEATURE_ENHANCED_INQ_MASK)
+
+#define HCI_FEATURE_INTERLACED_INQ_SCAN_MASK 0x10
+#define HCI_FEATURE_INTERLACED_INQ_SCAN_OFF 3
+#define HCI_LMP_INTERLACED_INQ_SCAN_SUPPORTED(x) ((x)[HCI_FEATURE_INTERLACED_INQ_SCAN_OFF] & HCI_FEATURE_INTERLACED_INQ_SCAN_MASK)
+
+#define HCI_FEATURE_INTERLACED_PAGE_SCAN_MASK 0x20
+#define HCI_FEATURE_INTERLACED_PAGE_SCAN_OFF 3
+#define HCI_LMP_INTERLACED_PAGE_SCAN_SUPPORTED(x) ((x)[HCI_FEATURE_INTERLACED_PAGE_SCAN_OFF] & HCI_FEATURE_INTERLACED_PAGE_SCAN_MASK)
+
+#define HCI_FEATURE_INQ_RSSI_MASK 0x40
+#define HCI_FEATURE_INQ_RSSI_OFF 3
+#define HCI_LMP_INQ_RSSI_SUPPORTED(x) ((x)[HCI_FEATURE_INQ_RSSI_OFF] & HCI_FEATURE_INQ_RSSI_MASK)
+
+#define HCI_FEATURE_ESCO_EV3_MASK 0x80
+#define HCI_FEATURE_ESCO_EV3_OFF 3
+#define HCI_ESCO_EV3_SUPPORTED(x) ((x)[HCI_FEATURE_ESCO_EV3_OFF] & HCI_FEATURE_ESCO_EV3_MASK)
+
+#define HCI_FEATURE_ESCO_EV4_MASK 0x01
+#define HCI_FEATURE_ESCO_EV4_OFF 4
+#define HCI_ESCO_EV4_SUPPORTED(x) ((x)[HCI_FEATURE_ESCO_EV4_OFF] & HCI_FEATURE_ESCO_EV4_MASK)
+
+#define HCI_FEATURE_ESCO_EV5_MASK 0x02
+#define HCI_FEATURE_ESCO_EV5_OFF 4
+#define HCI_ESCO_EV5_SUPPORTED(x) ((x)[HCI_FEATURE_ESCO_EV5_OFF] & HCI_FEATURE_ESCO_EV5_MASK)
+
+#define HCI_FEATURE_ABSENCE_MASKS_MASK 0x04
+#define HCI_FEATURE_ABSENCE_MASKS_OFF 4
+#define HCI_LMP_ABSENCE_MASKS_SUPPORTED(x) ((x)[HCI_FEATURE_ABSENCE_MASKS_OFF] & HCI_FEATURE_ABSENCE_MASKS_MASK)
+
+#define HCI_FEATURE_AFH_CAP_SLAVE_MASK 0x08
+#define HCI_FEATURE_AFH_CAP_SLAVE_OFF 4
+#define HCI_LMP_AFH_CAP_SLAVE_SUPPORTED(x) ((x)[HCI_FEATURE_AFH_CAP_SLAVE_OFF] & HCI_FEATURE_AFH_CAP_SLAVE_MASK)
+
+#define HCI_FEATURE_AFH_CLASS_SLAVE_MASK 0x10
+#define HCI_FEATURE_AFH_CLASS_SLAVE_OFF 4
+#define HCI_LMP_AFH_CLASS_SLAVE_SUPPORTED(x) ((x)[HCI_FEATURE_AFH_CLASS_SLAVE_OFF] & HCI_FEATURE_AFH_CLASS_SLAVE_MASK)
+
+#define HCI_FEATURE_ALIAS_AUTH_MASK 0x20
+#define HCI_FEATURE_ALIAS_AUTH_OFF 4
+#define HCI_LMP_ALIAS_AUTH_SUPPORTED(x) ((x)[HCI_FEATURE_ALIAS_AUTH_OFF] & HCI_FEATURE_ALIAS_AUTH_MASK)
+
+#define HCI_FEATURE_ANON_MODE_MASK 0x40
+#define HCI_FEATURE_ANON_MODE_OFF 4
+#define HCI_LMP_ANON_MODE_SUPPORTED(x) ((x)[HCI_FEATURE_ANON_MODE_OFF] & HCI_FEATURE_ANON_MODE_MASK)
+
+#define HCI_FEATURE_3_SLOT_EDR_ACL_MASK 0x80
+#define HCI_FEATURE_3_SLOT_EDR_ACL_OFF 4
+#define HCI_3_SLOT_EDR_ACL_SUPPORTED(x) ((x)[HCI_FEATURE_3_SLOT_EDR_ACL_OFF] & HCI_FEATURE_3_SLOT_EDR_ACL_MASK)
+
+#define HCI_FEATURE_5_SLOT_EDR_ACL_MASK 0x01
+#define HCI_FEATURE_5_SLOT_EDR_ACL_OFF 5
+#define HCI_5_SLOT_EDR_ACL_SUPPORTED(x) ((x)[HCI_FEATURE_5_SLOT_EDR_ACL_OFF] & HCI_FEATURE_5_SLOT_EDR_ACL_MASK)
+
+#define HCI_FEATURE_SNIFF_SUB_RATE_MASK 0x02
+#define HCI_FEATURE_SNIFF_SUB_RATE_OFF 5
+#define HCI_SNIFF_SUB_RATE_SUPPORTED(x) ((x)[HCI_FEATURE_SNIFF_SUB_RATE_OFF] & HCI_FEATURE_SNIFF_SUB_RATE_MASK)
+
+#define HCI_FEATURE_ATOMIC_ENCRYPT_MASK 0x04
+#define HCI_FEATURE_ATOMIC_ENCRYPT_OFF 5
+#define HCI_ATOMIC_ENCRYPT_SUPPORTED(x) ((x)[HCI_FEATURE_ATOMIC_ENCRYPT_OFF] & HCI_FEATURE_ATOMIC_ENCRYPT_MASK)
+
+#define HCI_FEATURE_AFH_CAP_MASTR_MASK 0x08
+#define HCI_FEATURE_AFH_CAP_MASTR_OFF 5
+#define HCI_LMP_AFH_CAP_MASTR_SUPPORTED(x) ((x)[HCI_FEATURE_AFH_CAP_MASTR_OFF] & HCI_FEATURE_AFH_CAP_MASTR_MASK)
+
+#define HCI_FEATURE_AFH_CLASS_MASTR_MASK 0x10
+#define HCI_FEATURE_AFH_CLASS_MASTR_OFF 5
+#define HCI_LMP_AFH_CLASS_MASTR_SUPPORTED(x) ((x)[HCI_FEATURE_AFH_CLASS_MASTR_OFF] & HCI_FEATURE_AFH_CLASS_MASTR_MASK)
+
+#define HCI_FEATURE_EDR_ESCO_2MPS_MASK 0x20
+#define HCI_FEATURE_EDR_ESCO_2MPS_OFF 5
+#define HCI_EDR_ESCO_2MPS_SUPPORTED(x) ((x)[HCI_FEATURE_EDR_ESCO_2MPS_OFF] & HCI_FEATURE_EDR_ESCO_2MPS_MASK)
+
+#define HCI_FEATURE_EDR_ESCO_3MPS_MASK 0x40
+#define HCI_FEATURE_EDR_ESCO_3MPS_OFF 5
+#define HCI_EDR_ESCO_3MPS_SUPPORTED(x) ((x)[HCI_FEATURE_EDR_ESCO_3MPS_OFF] & HCI_FEATURE_EDR_ESCO_3MPS_MASK)
+
+#define HCI_FEATURE_3_SLOT_EDR_ESCO_MASK 0x80
+#define HCI_FEATURE_3_SLOT_EDR_ESCO_OFF 5
+#define HCI_3_SLOT_EDR_ESCO_SUPPORTED(x) ((x)[HCI_FEATURE_3_SLOT_EDR_ESCO_OFF] & HCI_FEATURE_3_SLOT_EDR_ESCO_MASK)
+
+#define HCI_FEATURE_EXT_INQ_RSP_MASK 0x01
+#define HCI_FEATURE_EXT_INQ_RSP_OFF 6
+#define HCI_EXT_INQ_RSP_SUPPORTED(x) ((x)[HCI_FEATURE_EXT_INQ_RSP_OFF] & HCI_FEATURE_EXT_INQ_RSP_MASK)
+
+#define HCI_FEATURE_ANUM_PIN_AWARE_MASK 0x02
+#define HCI_FEATURE_ANUM_PIN_AWARE_OFF 6
+#define HCI_ANUM_PIN_AWARE_SUPPORTED(x) ((x)[HCI_FEATURE_ANUM_PIN_AWARE_OFF] & HCI_FEATURE_ANUM_PIN_AWARE_MASK)
+
+#define HCI_FEATURE_ANUM_PIN_CAP_MASK 0x04
+#define HCI_FEATURE_ANUM_PIN_CAP_OFF 6
+#define HCI_ANUM_PIN_CAP_SUPPORTED(x) ((x)[HCI_FEATURE_ANUM_PIN_CAP_OFF] & HCI_FEATURE_ANUM_PIN_CAP_MASK)
+
+#define HCI_FEATURE_SIMPLE_PAIRING_MASK 0x08
+#define HCI_FEATURE_SIMPLE_PAIRING_OFF 6
+#define HCI_SIMPLE_PAIRING_SUPPORTED(x) ((x)[HCI_FEATURE_SIMPLE_PAIRING_OFF] & HCI_FEATURE_SIMPLE_PAIRING_MASK)
+
+#define HCI_FEATURE_ENCAP_PDU_MASK 0x10
+#define HCI_FEATURE_ENCAP_PDU_OFF 6
+#define HCI_ENCAP_PDU_SUPPORTED(x) ((x)[HCI_FEATURE_ENCAP_PDU_OFF] & HCI_FEATURE_ENCAP_PDU_MASK)
+
+#define HCI_FEATURE_ERROR_DATA_MASK 0x20
+#define HCI_FEATURE_ERROR_DATA_OFF 6
+#define HCI_ERROR_DATA_SUPPORTED(x) ((x)[HCI_FEATURE_ERROR_DATA_OFF] & HCI_FEATURE_ERROR_DATA_MASK)
+
+#define HCI_FEATURE_NON_FLUSHABLE_PB_MASK 0x40
+#define HCI_FEATURE_NON_FLUSHABLE_PB_OFF 6
+
+// btla-specific ++
+#ifdef ANDROID_APP_INCLUDED
+/* This feature is causing frequent link drops when doing call switch with certain av/hfp headsets */
+#define HCI_NON_FLUSHABLE_PB_SUPPORTED(x) (0)//((x)[HCI_FEATURE_NON_FLUSHABLE_PB_OFF] & HCI_FEATURE_NON_FLUSHABLE_PB_MASK)
+#else
+#define HCI_NON_FLUSHABLE_PB_SUPPORTED(x) ((x)[HCI_FEATURE_NON_FLUSHABLE_PB_OFF] & HCI_FEATURE_NON_FLUSHABLE_PB_MASK)
+#endif
+// btla-specific --
+
+#define HCI_FEATURE_LINK_SUP_TO_EVT_MASK 0x01
+#define HCI_FEATURE_LINK_SUP_TO_EVT_OFF 7
+#define HCI_LINK_SUP_TO_EVT_SUPPORTED(x) ((x)[HCI_FEATURE_LINK_SUP_TO_EVT_OFF] & HCI_FEATURE_LINK_SUP_TO_EVT_MASK)
+
+#define HCI_FEATURE_INQ_RESP_TX_MASK 0x02
+#define HCI_FEATURE_INQ_RESP_TX_OFF 7
+#define HCI_INQ_RESP_TX_SUPPORTED(x) ((x)[HCI_FEATURE_INQ_RESP_TX_OFF] & HCI_FEATURE_INQ_RESP_TX_MASK)
+
+#define HCI_FEATURE_EXTENDED_MASK 0x80
+#define HCI_FEATURE_EXTENDED_OFF 7
+#define HCI_LMP_EXTENDED_SUPPORTED(x) ((x)[HCI_FEATURE_EXTENDED_OFF] & HCI_FEATURE_EXTENDED_MASK)
+
+/*
+** Features encoding - page 1
+*/
+#define HCI_EXT_FEATURE_SSP_HOST_MASK 0x01
+#define HCI_EXT_FEATURE_SSP_HOST_OFF 0
+#define HCI_SSP_HOST_SUPPORTED(x) ((x)[HCI_EXT_FEATURE_SSP_HOST_OFF] & HCI_EXT_FEATURE_SSP_HOST_MASK)
+
+/*
+** Local Supported Commands encoding
+*/
+#define HCI_NUM_SUPP_COMMANDS_BYTES 64
+
+#define HCI_SUPP_COMMANDS_INQUIRY_MASK 0x01
+#define HCI_SUPP_COMMANDS_INQUIRY_OFF 0
+#define HCI_INQUIRY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_INQUIRY_OFF] & HCI_SUPP_COMMANDS_INQUIRY_MASK)
+
+#define HCI_SUPP_COMMANDS_INQUIRY_CANCEL_MASK 0x02
+#define HCI_SUPP_COMMANDS_INQUIRY_CANCEL_OFF 0
+#define HCI_INQUIRY_CANCEL_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_INQUIRY_CANCEL_OFF] & HCI_SUPP_COMMANDS_INQUIRY_CANCEL_MASK)
+
+#define HCI_SUPP_COMMANDS_PERIODIC_INQUIRY_MASK 0x04
+#define HCI_SUPP_COMMANDS_PERIODIC_INQUIRY_OFF 0
+#define HCI_PERIODIC_INQUIRY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_PERIODIC_INQUIRY_OFF] & HCI_SUPP_COMMANDS_PERIODIC_INQUIRY_MASK)
+
+#define HCI_SUPP_COMMANDS_EXIT_PERIODIC_INQUIRY_MASK 0x08
+#define HCI_SUPP_COMMANDS_EXIT_PERIODIC_INQUIRY_OFF 0
+#define HCI_EXIT_PERIODIC_INQUIRY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_EXIT_PERIODIC_INQUIRY_OFF] & HCI_SUPP_COMMANDS_EXIT_PERIODIC_INQUIRY_MASK)
+
+#define HCI_SUPP_COMMANDS_CREATE_CONN_MASK 0x10
+#define HCI_SUPP_COMMANDS_CREATE_CONN_OFF 0
+#define HCI_CREATE_CONN_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_CREATE_CONN_OFF] & HCI_SUPP_COMMANDS_CREATE_CONN_MASK)
+
+#define HCI_SUPP_COMMANDS_DISCONNECT_MASK 0x20
+#define HCI_SUPP_COMMANDS_DISCONNECT_OFF 0
+#define HCI_DISCONNECT_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_DISCONNECT_OFF] & HCI_SUPP_COMMANDS_DISCONNECT_MASK)
+
+#define HCI_SUPP_COMMANDS_ADD_SCO_CONN_MASK 0x40
+#define HCI_SUPP_COMMANDS_ADD_SCO_CONN_OFF 0
+#define HCI_ADD_SCO_CONN_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_ADD_SCO_CONN_OFF] & HCI_SUPP_COMMANDS_ADD_SCO_CONN_MASK)
+
+#define HCI_SUPP_COMMANDS_CANCEL_CREATE_CONN_MASK 0x80
+#define HCI_SUPP_COMMANDS_CANCEL_CREATE_CONN_OFF 0
+#define HCI_CANCEL_CREATE_CONN_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_CANCEL_CREATE_CONN_OFF] & HCI_SUPP_COMMANDS_CANCEL_CREATE_CONN_MASK)
+
+#define HCI_SUPP_COMMANDS_ACCEPT_CONN_REQUEST_MASK 0x01
+#define HCI_SUPP_COMMANDS_ACCEPT_CONN_REQUEST_OFF 1
+#define HCI_ACCEPT_CONN_REQUEST_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_ACCEPT_CONN_REQUEST_OFF] & HCI_SUPP_COMMANDS_ACCEPT_CONN_REQUEST_MASK)
+
+#define HCI_SUPP_COMMANDS_REJECT_CONN_REQUEST_MASK 0x02
+#define HCI_SUPP_COMMANDS_REJECT_CONN_REQUEST_OFF 1
+#define HCI_REJECT_CONN_REQUEST_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_REJECT_CONN_REQUEST_OFF] & HCI_SUPP_COMMANDS_REJECT_CONN_REQUEST_MASK)
+
+#define HCI_SUPP_COMMANDS_LINK_KEY_REQUEST_REPLY_MASK 0x04
+#define HCI_SUPP_COMMANDS_LINK_KEY_REQUEST_REPLY_OFF 1
+#define HCI_LINK_KEY_REQUEST_REPLY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_LINK_KEY_REQUEST_REPLY_OFF] & HCI_SUPP_COMMANDS_LINK_KEY_REQUEST_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_LINK_KEY_REQUEST_NEG_REPLY_MASK 0x08
+#define HCI_SUPP_COMMANDS_LINK_KEY_REQUEST_NEG_REPLY_OFF 1
+#define HCI_LINK_KEY_REQUEST_NEG_REPLY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_LINK_KEY_REQUEST_NEG_REPLY_OFF] & HCI_SUPP_COMMANDS_LINK_KEY_REQUEST_NEG_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_PIN_CODE_REQUEST_REPLY_MASK 0x10
+#define HCI_SUPP_COMMANDS_PIN_CODE_REQUEST_REPLY_OFF 1
+#define HCI_PIN_CODE_REQUEST_REPLY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_PIN_CODE_REQUEST_REPLY_OFF] & HCI_SUPP_COMMANDS_PIN_CODE_REQUEST_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_PIN_CODE_REQUEST_NEG_REPLY_MASK 0x20
+#define HCI_SUPP_COMMANDS_PIN_CODE_REQUEST_NEG_REPLY_OFF 1
+#define HCI_PIN_CODE_REQUEST_NEG_REPLY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_PIN_CODE_REQUEST_NEG_REPLY_OFF] & HCI_SUPP_COMMANDS_PIN_CODE_REQUEST_NEG_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_CHANGE_CONN_PKT_TYPE_MASK 0x40
+#define HCI_SUPP_COMMANDS_CHANGE_CONN_PKT_TYPE_OFF 1
+#define HCI_CHANGE_CONN_PKT_TYPE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_CHANGE_CONN_PKT_TYPE_OFF] & HCI_SUPP_COMMANDS_CHANGE_CONN_PKT_TYPE_MASK)
+
+#define HCI_SUPP_COMMANDS_AUTH_REQUEST_MASK 0x80
+#define HCI_SUPP_COMMANDS_AUTH_REQUEST_OFF 1
+#define HCI_AUTH_REQUEST_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_AUTH_REQUEST_OFF] & HCI_SUPP_COMMANDS_AUTH_REQUEST_MASK)
+
+#define HCI_SUPP_COMMANDS_SET_CONN_ENCRYPTION_MASK 0x01
+#define HCI_SUPP_COMMANDS_SET_CONN_ENCRYPTION_OFF 2
+#define HCI_SET_CONN_ENCRYPTION_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SET_CONN_ENCRYPTION_OFF] & HCI_SUPP_COMMANDS_SET_CONN_ENCRYPTION_MASK)
+
+#define HCI_SUPP_COMMANDS_CHANGE_CONN_LINK_KEY_MASK 0x02
+#define HCI_SUPP_COMMANDS_CHANGE_CONN_LINK_KEY_OFF 2
+#define HCI_CHANGE_CONN_LINK_KEY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_CHANGE_CONN_LINK_KEY_OFF] & HCI_SUPP_COMMANDS_CHANGE_CONN_LINK_KEY_MASK)
+
+#define HCI_SUPP_COMMANDS_MASTER_LINK_KEY_MASK 0x04
+#define HCI_SUPP_COMMANDS_MASTER_LINK_KEY_OFF 2
+#define HCI_MASTER_LINK_KEY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_MASTER_LINK_KEY_OFF] & HCI_SUPP_COMMANDS_MASTER_LINK_KEY_MASK)
+
+#define HCI_SUPP_COMMANDS_REMOTE_NAME_REQUEST_MASK 0x08
+#define HCI_SUPP_COMMANDS_REMOTE_NAME_REQUEST_OFF 2
+#define HCI_REMOTE_NAME_REQUEST_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_REMOTE_NAME_REQUEST_OFF] & HCI_SUPP_COMMANDS_REMOTE_NAME_REQUEST_MASK)
+
+#define HCI_SUPP_COMMANDS_CANCEL_REMOTE_NAME_REQUEST_MASK 0x10
+#define HCI_SUPP_COMMANDS_CANCEL_REMOTE_NAME_REQUEST_OFF 2
+#define HCI_CANCEL_REMOTE_NAME_REQUEST_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_CANCEL_REMOTE_NAME_REQUEST_OFF] & HCI_SUPP_COMMANDS_CANCEL_REMOTE_NAME_REQUEST_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_REMOTE_SUPP_FEATURES_MASK 0x20
+#define HCI_SUPP_COMMANDS_READ_REMOTE_SUPP_FEATURES_OFF 2
+#define HCI_READ_REMOTE_SUPP_FEATURES_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_REMOTE_SUPP_FEATURES_OFF] & HCI_SUPP_COMMANDS_READ_REMOTE_SUPP_FEATURES_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_REMOTE_EXT_FEATURES_MASK 0x40
+#define HCI_SUPP_COMMANDS_READ_REMOTE_EXT_FEATURES_OFF 2
+#define HCI_READ_REMOTE_EXT_FEATURES_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_REMOTE_EXT_FEATURES_OFF] & HCI_SUPP_COMMANDS_READ_REMOTE_EXT_FEATURES_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_REMOTE_VER_INFO_MASK 0x80
+#define HCI_SUPP_COMMANDS_READ_REMOTE_VER_INFO_OFF 2
+#define HCI_READ_REMOTE_VER_INFO_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_REMOTE_VER_INFO_OFF] & HCI_SUPP_COMMANDS_READ_REMOTE_VER_INFO_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_CLOCK_OFFSET_MASK 0x01
+#define HCI_SUPP_COMMANDS_READ_CLOCK_OFFSET_OFF 3
+#define HCI_READ_CLOCK_OFFSET_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_CLOCK_OFFSET_OFF] & HCI_SUPP_COMMANDS_READ_CLOCK_OFFSET_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LMP_HANDLE_MASK 0x02
+#define HCI_SUPP_COMMANDS_READ_LMP_HANDLE_OFF 3
+#define HCI_READ_LMP_HANDLE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_LMP_HANDLE_OFF] & HCI_SUPP_COMMANDS_READ_LMP_HANDLE_MASK)
+
+#define HCI_SUPP_COMMANDS_HOLD_MODE_CMD_MASK 0x02
+#define HCI_SUPP_COMMANDS_HOLD_MODE_CMD_OFF 4
+#define HCI_HOLD_MODE_CMD_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_HOLD_MODE_CMD_OFF] & HCI_SUPP_COMMANDS_HOLD_MODE_CMD_MASK)
+
+#define HCI_SUPP_COMMANDS_SNIFF_MODE_CMD_MASK 0x04
+#define HCI_SUPP_COMMANDS_SNIFF_MODE_CMD_OFF 4
+#define HCI_SNIFF_MODE_CMD_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SNIFF_MODE_CMD_OFF] & HCI_SUPP_COMMANDS_SNIFF_MODE_CMD_MASK)
+
+#define HCI_SUPP_COMMANDS_EXIT_SNIFF_MODE_MASK 0x08
+#define HCI_SUPP_COMMANDS_EXIT_SNIFF_MODE_OFF 4
+#define HCI_EXIT_SNIFF_MODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_EXIT_SNIFF_MODE_OFF] & HCI_SUPP_COMMANDS_EXIT_SNIFF_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_PARK_STATE_MASK 0x10
+#define HCI_SUPP_COMMANDS_PARK_STATE_OFF 4
+#define HCI_PARK_STATE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_PARK_STATE_OFF] & HCI_SUPP_COMMANDS_PARK_STATE_MASK)
+
+#define HCI_SUPP_COMMANDS_EXIT_PARK_STATE_MASK 0x20
+#define HCI_SUPP_COMMANDS_EXIT_PARK_STATE_OFF 4
+#define HCI_EXIT_PARK_STATE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_EXIT_PARK_STATE_OFF] & HCI_SUPP_COMMANDS_EXIT_PARK_STATE_MASK)
+
+#define HCI_SUPP_COMMANDS_QOS_SETUP_MASK 0x40
+#define HCI_SUPP_COMMANDS_QOS_SETUP_OFF 4
+#define HCI_QOS_SETUP_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_QOS_SETUP_OFF] & HCI_SUPP_COMMANDS_QOS_SETUP_MASK)
+
+#define HCI_SUPP_COMMANDS_ROLE_DISCOVERY_MASK 0x80
+#define HCI_SUPP_COMMANDS_ROLE_DISCOVERY_OFF 4
+#define HCI_ROLE_DISCOVERY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_ROLE_DISCOVERY_OFF] & HCI_SUPP_COMMANDS_ROLE_DISCOVERY_MASK)
+
+#define HCI_SUPP_COMMANDS_SWITCH_ROLE_MASK 0x01
+#define HCI_SUPP_COMMANDS_SWITCH_ROLE_OFF 5
+#define HCI_SWITCH_ROLE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SWITCH_ROLE_OFF] & HCI_SUPP_COMMANDS_SWITCH_ROLE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LINK_POLICY_SET_MASK 0x02
+#define HCI_SUPP_COMMANDS_READ_LINK_POLICY_SET_OFF 5
+#define HCI_READ_LINK_POLICY_SET_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_LINK_POLICY_SET_OFF] & HCI_SUPP_COMMANDS_READ_LINK_POLICY_SET_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_LINK_POLICY_SET_MASK 0x04
+#define HCI_SUPP_COMMANDS_WRITE_LINK_POLICY_SET_OFF 5
+#define HCI_WRITE_LINK_POLICY_SET_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_LINK_POLICY_SET_OFF] & HCI_SUPP_COMMANDS_WRITE_LINK_POLICY_SET_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_DEF_LINK_POLICY_SET_MASK 0x08
+#define HCI_SUPP_COMMANDS_READ_DEF_LINK_POLICY_SET_OFF 5
+#define HCI_READ_DEF_LINK_POLICY_SET_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_DEF_LINK_POLICY_SET_OFF] & HCI_SUPP_COMMANDS_READ_DEF_LINK_POLICY_SET_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_DEF_LINK_POLICY_SET_MASK 0x10
+#define HCI_SUPP_COMMANDS_WRITE_DEF_LINK_POLICY_SET_OFF 5
+#define HCI_WRITE_DEF_LINK_POLICY_SET_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_DEF_LINK_POLICY_SET_OFF] & HCI_SUPP_COMMANDS_WRITE_DEF_LINK_POLICY_SET_MASK)
+
+#define HCI_SUPP_COMMANDS_FLOW_SPECIFICATION_MASK 0x20
+#define HCI_SUPP_COMMANDS_FLOW_SPECIFICATION_OFF 5
+#define HCI_FLOW_SPECIFICATION_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_FLOW_SPECIFICATION_OFF] & HCI_SUPP_COMMANDS_FLOW_SPECIFICATION_MASK)
+
+#define HCI_SUPP_COMMANDS_SET_EVENT_MASK_MASK 0x40
+#define HCI_SUPP_COMMANDS_SET_EVENT_MASK_OFF 5
+#define HCI_SET_EVENT_MASK_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SET_EVENT_MASK_OFF] & HCI_SUPP_COMMANDS_SET_EVENT_MASK_MASK)
+
+#define HCI_SUPP_COMMANDS_RESET_MASK 0x80
+#define HCI_SUPP_COMMANDS_RESET_OFF 5
+#define HCI_RESET_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_RESET_OFF] & HCI_SUPP_COMMANDS_RESET_MASK)
+
+#define HCI_SUPP_COMMANDS_SET_EVENT_FILTER_MASK 0x01
+#define HCI_SUPP_COMMANDS_SET_EVENT_FILTER_OFF 6
+#define HCI_SET_EVENT_FILTER_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SET_EVENT_FILTER_OFF] & HCI_SUPP_COMMANDS_SET_EVENT_FILTER_MASK)
+
+#define HCI_SUPP_COMMANDS_FLUSH_MASK 0x02
+#define HCI_SUPP_COMMANDS_FLUSH_OFF 6
+#define HCI_FLUSH_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_FLUSH_OFF] & HCI_SUPP_COMMANDS_FLUSH_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_PIN_TYPE_MASK 0x04
+#define HCI_SUPP_COMMANDS_READ_PIN_TYPE_OFF 6
+#define HCI_READ_PIN_TYPE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_PIN_TYPE_OFF] & HCI_SUPP_COMMANDS_READ_PIN_TYPE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_PIN_TYPE_MASK 0x08
+#define HCI_SUPP_COMMANDS_WRITE_PIN_TYPE_OFF 6
+#define HCI_WRITE_PIN_TYPE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_PIN_TYPE_OFF] & HCI_SUPP_COMMANDS_WRITE_PIN_TYPE_MASK)
+
+#define HCI_SUPP_COMMANDS_CREATE_NEW_UNIT_KEY_MASK 0x10
+#define HCI_SUPP_COMMANDS_CREATE_NEW_UNIT_KEY_OFF 6
+#define HCI_CREATE_NEW_UNIT_KEY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_CREATE_NEW_UNIT_KEY_OFF] & HCI_SUPP_COMMANDS_CREATE_NEW_UNIT_KEY_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_STORED_LINK_KEY_MASK 0x20
+#define HCI_SUPP_COMMANDS_READ_STORED_LINK_KEY_OFF 6
+#define HCI_READ_STORED_LINK_KEY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_STORED_LINK_KEY_OFF] & HCI_SUPP_COMMANDS_READ_STORED_LINK_KEY_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_STORED_LINK_KEY_MASK 0x40
+#define HCI_SUPP_COMMANDS_WRITE_STORED_LINK_KEY_OFF 6
+#define HCI_WRITE_STORED_LINK_KEY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_STORED_LINK_KEY_OFF] & HCI_SUPP_COMMANDS_WRITE_STORED_LINK_KEY_MASK)
+
+#define HCI_SUPP_COMMANDS_DELETE_STORED_LINK_KEY_MASK 0x80
+#define HCI_SUPP_COMMANDS_DELETE_STORED_LINK_KEY_OFF 6
+#define HCI_DELETE_STORED_LINK_KEY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_DELETE_STORED_LINK_KEY_OFF] & HCI_SUPP_COMMANDS_DELETE_STORED_LINK_KEY_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_LOCAL_NAME_MASK 0x01
+#define HCI_SUPP_COMMANDS_WRITE_LOCAL_NAME_OFF 7
+#define HCI_WRITE_LOCAL_NAME_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_LOCAL_NAME_OFF] & HCI_SUPP_COMMANDS_WRITE_LOCAL_NAME_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOCAL_NAME_MASK 0x02
+#define HCI_SUPP_COMMANDS_READ_LOCAL_NAME_OFF 7
+#define HCI_READ_LOCAL_NAME_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_NAME_OFF] & HCI_SUPP_COMMANDS_READ_LOCAL_NAME_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_CONN_ACCEPT_TOUT_MASK 0x04
+#define HCI_SUPP_COMMANDS_READ_CONN_ACCEPT_TOUT_OFF 7
+#define HCI_READ_CONN_ACCEPT_TOUT_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_CONN_ACCEPT_TOUT_OFF] & HCI_SUPP_COMMANDS_READ_CONN_ACCEPT_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_CONN_ACCEPT_TOUT_MASK 0x08
+#define HCI_SUPP_COMMANDS_WRITE_CONN_ACCEPT_TOUT_OFF 7
+#define HCI_WRITE_CONN_ACCEPT_TOUT_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_CONN_ACCEPT_TOUT_OFF] & HCI_SUPP_COMMANDS_WRITE_CONN_ACCEPT_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_PAGE_TOUT_MASK 0x10
+#define HCI_SUPP_COMMANDS_READ_PAGE_TOUT_OFF 7
+#define HCI_READ_PAGE_TOUT_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_PAGE_TOUT_OFF] & HCI_SUPP_COMMANDS_READ_PAGE_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_PAGE_TOUT_MASK 0x20
+#define HCI_SUPP_COMMANDS_WRITE_PAGE_TOUT_OFF 7
+#define HCI_WRITE_PAGE_TOUT_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_PAGE_TOUT_OFF] & HCI_SUPP_COMMANDS_WRITE_PAGE_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_SCAN_ENABLE_MASK 0x40
+#define HCI_SUPP_COMMANDS_READ_SCAN_ENABLE_OFF 7
+#define HCI_READ_SCAN_ENABLE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_SCAN_ENABLE_OFF] & HCI_SUPP_COMMANDS_READ_SCAN_ENABLE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_SCAN_ENABLE_MASK 0x80
+#define HCI_SUPP_COMMANDS_WRITE_SCAN_ENABLE_OFF 7
+#define HCI_WRITE_SCAN_ENABLE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_SCAN_ENABLE_OFF] & HCI_SUPP_COMMANDS_WRITE_SCAN_ENABLE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_PAGE_SCAN_ACTIVITY_MASK 0x01
+#define HCI_SUPP_COMMANDS_READ_PAGE_SCAN_ACTIVITY_OFF 8
+#define HCI_READ_PAGE_SCAN_ACTIVITY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_PAGE_SCAN_ACTIVITY_OFF] & HCI_SUPP_COMMANDS_READ_PAGE_SCAN_ACTIVITY_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_ACTIVITY_MASK 0x02
+#define HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_ACTIVITY_OFF 8
+#define HCI_WRITE_PAGE_SCAN_ACTIVITY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_ACTIVITY_OFF] & HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_ACTIVITY_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_INQURIY_SCAN_ACTIVITY_MASK 0x04
+#define HCI_SUPP_COMMANDS_READ_INQURIY_SCAN_ACTIVITY_OFF 8
+#define HCI_READ_INQURIY_SCAN_ACTIVITY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_INQURIY_SCAN_ACTIVITY_OFF] & HCI_SUPP_COMMANDS_READ_INQURIY_SCAN_ACTIVITY_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_INQURIY_SCAN_ACTIVITY_MASK 0x08
+#define HCI_SUPP_COMMANDS_WRITE_INQURIY_SCAN_ACTIVITY_OFF 8
+#define HCI_WRITE_INQURIY_SCAN_ACTIVITY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_INQURIY_SCAN_ACTIVITY_OFF] & HCI_SUPP_COMMANDS_WRITE_INQURIY_SCAN_ACTIVITY_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_AUTH_ENABLE_MASK 0x10
+#define HCI_SUPP_COMMANDS_READ_AUTH_ENABLE_OFF 8
+#define HCI_READ_AUTH_ENABLE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_AUTH_ENABLE_OFF] & HCI_SUPP_COMMANDS_READ_AUTH_ENABLE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_AUTH_ENABLE_MASK 0x20
+#define HCI_SUPP_COMMANDS_WRITE_AUTH_ENABLE_OFF 8
+#define HCI_WRITE_AUTH_ENABLE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_AUTH_ENABLE_OFF] & HCI_SUPP_COMMANDS_WRITE_AUTH_ENABLE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_ENCRYPT_ENABLE_MASK 0x40
+#define HCI_SUPP_COMMANDS_READ_ENCRYPT_ENABLE_OFF 8
+#define HCI_READ_ENCRYPT_ENABLE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_ENCRYPT_ENABLE_OFF] & HCI_SUPP_COMMANDS_READ_ENCRYPT_ENABLE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_ENCRYPT_ENABLE_MASK 0x80
+#define HCI_SUPP_COMMANDS_WRITE_ENCRYPT_ENABLE_OFF 8
+#define HCI_WRITE_ENCRYPT_ENABLE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_ENCRYPT_ENABLE_OFF] & HCI_SUPP_COMMANDS_WRITE_ENCRYPT_ENABLE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_CLASS_DEVICE_MASK 0x01
+#define HCI_SUPP_COMMANDS_READ_CLASS_DEVICE_OFF 9
+#define HCI_READ_CLASS_DEVICE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_CLASS_DEVICE_OFF] & HCI_SUPP_COMMANDS_READ_CLASS_DEVICE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_CLASS_DEVICE_MASK 0x02
+#define HCI_SUPP_COMMANDS_WRITE_CLASS_DEVICE_OFF 9
+#define HCI_WRITE_CLASS_DEVICE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_CLASS_DEVICE_OFF] & HCI_SUPP_COMMANDS_WRITE_CLASS_DEVICE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_VOICE_SETTING_MASK 0x04
+#define HCI_SUPP_COMMANDS_READ_VOICE_SETTING_OFF 9
+#define HCI_READ_VOICE_SETTING_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_VOICE_SETTING_OFF] & HCI_SUPP_COMMANDS_READ_VOICE_SETTING_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_VOICE_SETTING_MASK 0x08
+#define HCI_SUPP_COMMANDS_WRITE_VOICE_SETTING_OFF 9
+#define HCI_WRITE_VOICE_SETTING_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_VOICE_SETTING_OFF] & HCI_SUPP_COMMANDS_WRITE_VOICE_SETTING_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_AUTO_FLUSH_TOUT_MASK 0x10
+#define HCI_SUPP_COMMANDS_READ_AUTO_FLUSH_TOUT_OFF 9
+#define HCI_READ_AUTO_FLUSH_TOUT_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_AUTO_FLUSH_TOUT_OFF] & HCI_SUPP_COMMANDS_READ_AUTO_FLUSH_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_AUTO_FLUSH_TOUT_MASK 0x20
+#define HCI_SUPP_COMMANDS_WRITE_AUTO_FLUSH_TOUT_OFF 9
+#define HCI_WRITE_AUTO_FLUSH_TOUT_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_AUTO_FLUSH_TOUT_OFF] & HCI_SUPP_COMMANDS_WRITE_AUTO_FLUSH_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_NUM_BROAD_RETRANS_MASK 0x40
+#define HCI_SUPP_COMMANDS_READ_NUM_BROAD_RETRANS_OFF 9
+#define HCI_READ_NUM_BROAD_RETRANS_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_NUM_BROAD_RETRANS_OFF] & HCI_SUPP_COMMANDS_READ_NUM_BROAD_RETRANS_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_NUM_BROAD_RETRANS_MASK 0x80
+#define HCI_SUPP_COMMANDS_WRITE_NUM_BROAD_RETRANS_OFF 9
+#define HCI_WRITE_NUM_BROAD_RETRANS_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_NUM_BROAD_RETRANS_OFF] & HCI_SUPP_COMMANDS_WRITE_NUM_BROAD_RETRANS_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_HOLD_MODE_ACTIVITY_MASK 0x01
+#define HCI_SUPP_COMMANDS_READ_HOLD_MODE_ACTIVITY_OFF 10
+#define HCI_READ_HOLD_MODE_ACTIVITY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_HOLD_MODE_ACTIVITY_OFF] & HCI_SUPP_COMMANDS_READ_HOLD_MODE_ACTIVITY_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_HOLD_MODE_ACTIVITY_MASK 0x02
+#define HCI_SUPP_COMMANDS_WRITE_HOLD_MODE_ACTIVITY_OFF 10
+#define HCI_WRITE_HOLD_MODE_ACTIVITY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_HOLD_MODE_ACTIVITY_OFF] & HCI_SUPP_COMMANDS_WRITE_HOLD_MODE_ACTIVITY_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_TRANS_PWR_LEVEL_MASK 0x04
+#define HCI_SUPP_COMMANDS_READ_TRANS_PWR_LEVEL_OFF 10
+#define HCI_READ_TRANS_PWR_LEVEL_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_TRANS_PWR_LEVEL_OFF] & HCI_SUPP_COMMANDS_READ_TRANS_PWR_LEVEL_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_SYNCH_FLOW_CTRL_ENABLE_MASK 0x08
+#define HCI_SUPP_COMMANDS_READ_SYNCH_FLOW_CTRL_ENABLE_OFF 10
+#define HCI_READ_SYNCH_FLOW_CTRL_ENABLE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_SYNCH_FLOW_CTRL_ENABLE_OFF] & HCI_SUPP_COMMANDS_READ_SYNCH_FLOW_CTRL_ENABLE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_SYNCH_FLOW_CTRL_ENABLE_MASK 0x10
+#define HCI_SUPP_COMMANDS_WRITE_SYNCH_FLOW_CTRL_ENABLE_OFF 10
+#define HCI_WRITE_SYNCH_FLOW_CTRL_ENABLE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_SYNCH_FLOW_CTRL_ENABLE_OFF] & HCI_SUPP_COMMANDS_WRITE_SYNCH_FLOW_CTRL_ENABLE_MASK)
+
+#define HCI_SUPP_COMMANDS_SET_HOST_CTRLR_TO_HOST_FC_MASK 0x20
+#define HCI_SUPP_COMMANDS_SET_HOST_CTRLR_TO_HOST_FC_OFF 10
+#define HCI_SET_HOST_CTRLR_TO_HOST_FC_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SET_HOST_CTRLR_TO_HOST_FC_OFF] & HCI_SUPP_COMMANDS_SET_HOST_CTRLR_TO_HOST_FC_MASK)
+
+#define HCI_SUPP_COMMANDS_HOST_BUFFER_SIZE_MASK 0x40
+#define HCI_SUPP_COMMANDS_HOST_BUFFER_SIZE_OFF 10
+#define HCI_HOST_BUFFER_SIZE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_HOST_BUFFER_SIZE_OFF] & HCI_SUPP_COMMANDS_HOST_BUFFER_SIZE_MASK)
+
+#define HCI_SUPP_COMMANDS_HOST_NUM_COMPLETED_PKTS_MASK 0x80
+#define HCI_SUPP_COMMANDS_HOST_NUM_COMPLETED_PKTS_OFF 10
+#define HCI_HOST_NUM_COMPLETED_PKTS_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_HOST_NUM_COMPLETED_PKTS_OFF] & HCI_SUPP_COMMANDS_HOST_NUM_COMPLETED_PKTS_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LINK_SUP_TOUT_MASK 0x01
+#define HCI_SUPP_COMMANDS_READ_LINK_SUP_TOUT_OFF 11
+#define HCI_READ_LINK_SUP_TOUT_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_LINK_SUP_TOUT_OFF] & HCI_SUPP_COMMANDS_READ_LINK_SUP_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_LINK_SUP_TOUT_MASK 0x02
+#define HCI_SUPP_COMMANDS_WRITE_LINK_SUP_TOUT_OFF 11
+#define HCI_WRITE_LINK_SUP_TOUT_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_LINK_SUP_TOUT_OFF] & HCI_SUPP_COMMANDS_WRITE_LINK_SUP_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_NUM_SUPP_IAC_MASK 0x04
+#define HCI_SUPP_COMMANDS_READ_NUM_SUPP_IAC_OFF 11
+#define HCI_READ_NUM_SUPP_IAC_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_NUM_SUPP_IAC_OFF] & HCI_SUPP_COMMANDS_READ_NUM_SUPP_IAC_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_CURRENT_IAC_LAP_MASK 0x08
+#define HCI_SUPP_COMMANDS_READ_CURRENT_IAC_LAP_OFF 11
+#define HCI_READ_CURRENT_IAC_LAP_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_CURRENT_IAC_LAP_OFF] & HCI_SUPP_COMMANDS_READ_CURRENT_IAC_LAP_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_CURRENT_IAC_LAP_MASK 0x10
+#define HCI_SUPP_COMMANDS_WRITE_CURRENT_IAC_LAP_OFF 11
+#define HCI_WRITE_CURRENT_IAC_LAP_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_CURRENT_IAC_LAP_OFF] & HCI_SUPP_COMMANDS_WRITE_CURRENT_IAC_LAP_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_PAGE_SCAN_PER_MODE_MASK 0x20
+#define HCI_SUPP_COMMANDS_READ_PAGE_SCAN_PER_MODE_OFF 11
+#define HCI_READ_PAGE_SCAN_PER_MODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_PAGE_SCAN_PER_MODE_OFF] & HCI_SUPP_COMMANDS_READ_PAGE_SCAN_PER_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_PER_MODE_MASK 0x40
+#define HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_PER_MODE_OFF 11
+#define HCI_WRITE_PAGE_SCAN_PER_MODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_PER_MODE_OFF] & HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_PER_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_PAGE_SCAN_MODE_MASK 0x80
+#define HCI_SUPP_COMMANDS_READ_PAGE_SCAN_MODE_OFF 11
+#define HCI_READ_PAGE_SCAN_MODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_PAGE_SCAN_MODE_OFF] & HCI_SUPP_COMMANDS_READ_PAGE_SCAN_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_MODE_MASK 0x01
+#define HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_MODE_OFF 12
+#define HCI_WRITE_PAGE_SCAN_MODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_MODE_OFF] & HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_SET_AFH_CHNL_CLASS_MASK 0x02
+#define HCI_SUPP_COMMANDS_SET_AFH_CHNL_CLASS_OFF 12
+#define HCI_SET_AFH_CHNL_CLASS_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SET_AFH_CHNL_CLASS_OFF] & HCI_SUPP_COMMANDS_SET_AFH_CHNL_CLASS_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_INQUIRY_SCAN_TYPE_MASK 0x10
+#define HCI_SUPP_COMMANDS_READ_INQUIRY_SCAN_TYPE_OFF 12
+#define HCI_READ_INQUIRY_SCAN_TYPE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_INQUIRY_SCAN_TYPE_OFF] & HCI_SUPP_COMMANDS_READ_INQUIRY_SCAN_TYPE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_INQUIRY_SCAN_TYPE_MASK 0x20
+#define HCI_SUPP_COMMANDS_WRITE_INQUIRY_SCAN_TYPE_OFF 12
+#define HCI_WRITE_INQUIRY_SCAN_TYPE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_INQUIRY_SCAN_TYPE_OFF] & HCI_SUPP_COMMANDS_WRITE_INQUIRY_SCAN_TYPE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_INQUIRY_MODE_MASK 0x40
+#define HCI_SUPP_COMMANDS_READ_INQUIRY_MODE_OFF 12
+#define HCI_READ_INQUIRY_MODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_INQUIRY_MODE_OFF] & HCI_SUPP_COMMANDS_READ_INQUIRY_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_INQUIRY_MODE_MASK 0x80
+#define HCI_SUPP_COMMANDS_WRITE_INQUIRY_MODE_OFF 12
+#define HCI_WRITE_INQUIRY_MODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_INQUIRY_MODE_OFF] & HCI_SUPP_COMMANDS_WRITE_INQUIRY_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_PAGE_SCAN_TYPE_MASK 0x01
+#define HCI_SUPP_COMMANDS_READ_PAGE_SCAN_TYPE_OFF 13
+#define HCI_READ_PAGE_SCAN_TYPE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_PAGE_SCAN_TYPE_OFF] & HCI_SUPP_COMMANDS_READ_PAGE_SCAN_TYPE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_TYPE_MASK 0x02
+#define HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_TYPE_OFF 13
+#define HCI_WRITE_PAGE_SCAN_TYPE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_TYPE_OFF] & HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_TYPE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_AFH_CHNL_ASSESS_MODE_MASK 0x04
+#define HCI_SUPP_COMMANDS_READ_AFH_CHNL_ASSESS_MODE_OFF 13
+#define HCI_READ_AFH_CHNL_ASSESS_MODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_AFH_CHNL_ASSESS_MODE_OFF] & HCI_SUPP_COMMANDS_READ_AFH_CHNL_ASSESS_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_AFH_CHNL_ASSESS_MODE_MASK 0x08
+#define HCI_SUPP_COMMANDS_WRITE_AFH_CHNL_ASSESS_MODE_OFF 13
+#define HCI_WRITE_AFH_CHNL_ASSESS_MODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_AFH_CHNL_ASSESS_MODE_OFF] & HCI_SUPP_COMMANDS_WRITE_AFH_CHNL_ASSESS_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOCAL_VER_INFO_MASK 0x08
+#define HCI_SUPP_COMMANDS_READ_LOCAL_VER_INFO_OFF 14
+#define HCI_READ_LOCAL_VER_INFO_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_VER_INFO_OFF] & HCI_SUPP_COMMANDS_READ_LOCAL_VER_INFO_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOCAL_SUP_CMDS_MASK 0x10
+#define HCI_SUPP_COMMANDS_READ_LOCAL_SUP_CMDS_OFF 14
+#define HCI_READ_LOCAL_SUP_CMDS_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_SUP_CMDS_OFF] & HCI_SUPP_COMMANDS_READ_LOCAL_SUP_CMDS_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOCAL_SUPP_FEATURES_MASK 0x20
+#define HCI_SUPP_COMMANDS_READ_LOCAL_SUPP_FEATURES_OFF 14
+#define HCI_READ_LOCAL_SUPP_FEATURES_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_SUPP_FEATURES_OFF] & HCI_SUPP_COMMANDS_READ_LOCAL_SUPP_FEATURES_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOCAL_EXT_FEATURES_MASK 0x40
+#define HCI_SUPP_COMMANDS_READ_LOCAL_EXT_FEATURES_OFF 14
+#define HCI_READ_LOCAL_EXT_FEATURES_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_EXT_FEATURES_OFF] & HCI_SUPP_COMMANDS_READ_LOCAL_EXT_FEATURES_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_BUFFER_SIZE_MASK 0x80
+#define HCI_SUPP_COMMANDS_READ_BUFFER_SIZE_OFF 14
+#define HCI_READ_BUFFER_SIZE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_BUFFER_SIZE_OFF] & HCI_SUPP_COMMANDS_READ_BUFFER_SIZE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_COUNTRY_CODE_MASK 0x01
+#define HCI_SUPP_COMMANDS_READ_COUNTRY_CODE_OFF 15
+#define HCI_READ_COUNTRY_CODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_COUNTRY_CODE_OFF] & HCI_SUPP_COMMANDS_READ_COUNTRY_CODE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_BD_ADDR_MASK 0x02
+#define HCI_SUPP_COMMANDS_READ_BD_ADDR_OFF 15
+#define HCI_READ_BD_ADDR_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_BD_ADDR_OFF] & HCI_SUPP_COMMANDS_READ_BD_ADDR_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_FAIL_CONTACT_CNTR_MASK 0x04
+#define HCI_SUPP_COMMANDS_READ_FAIL_CONTACT_CNTR_OFF 15
+#define HCI_READ_FAIL_CONTACT_CNTR_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_FAIL_CONTACT_CNTR_OFF] & HCI_SUPP_COMMANDS_READ_FAIL_CONTACT_CNTR_MASK)
+
+#define HCI_SUPP_COMMANDS_RESET_FAIL_CONTACT_CNTR_MASK 0x08
+#define HCI_SUPP_COMMANDS_RESET_FAIL_CONTACT_CNTR_OFF 15
+#define HCI_RESET_FAIL_CONTACT_CNTR_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_RESET_FAIL_CONTACT_CNTR_OFF] & HCI_SUPP_COMMANDS_RESET_FAIL_CONTACT_CNTR_MASK)
+
+#define HCI_SUPP_COMMANDS_GET_LINK_QUALITY_MASK 0x10
+#define HCI_SUPP_COMMANDS_GET_LINK_QUALITY_OFF 15
+#define HCI_GET_LINK_QUALITY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_GET_LINK_QUALITY_OFF] & HCI_SUPP_COMMANDS_GET_LINK_QUALITY_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_RSSI_MASK 0x20
+#define HCI_SUPP_COMMANDS_READ_RSSI_OFF 15
+#define HCI_READ_RSSI_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_RSSI_OFF] & HCI_SUPP_COMMANDS_READ_RSSI_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_AFH_CH_MAP_MASK 0x40
+#define HCI_SUPP_COMMANDS_READ_AFH_CH_MAP_OFF 15
+#define HCI_READ_AFH_CH_MAP_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_AFH_CH_MAP_OFF] & HCI_SUPP_COMMANDS_READ_AFH_CH_MAP_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_BD_CLOCK_MASK 0x80
+#define HCI_SUPP_COMMANDS_READ_BD_CLOCK_OFF 15
+#define HCI_READ_BD_CLOCK_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_BD_CLOCK_OFF] & HCI_SUPP_COMMANDS_READ_BD_CLOCK_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOOPBACK_MODE_MASK 0x01
+#define HCI_SUPP_COMMANDS_READ_LOOPBACK_MODE_OFF 16
+#define HCI_READ_LOOPBACK_MODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_LOOPBACK_MODE_OFF] & HCI_SUPP_COMMANDS_READ_LOOPBACK_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_LOOPBACK_MODE_MASK 0x02
+#define HCI_SUPP_COMMANDS_WRITE_LOOPBACK_MODE_OFF 16
+#define HCI_WRITE_LOOPBACK_MODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_LOOPBACK_MODE_OFF] & HCI_SUPP_COMMANDS_WRITE_LOOPBACK_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_ENABLE_DEV_UNDER_TEST_MASK 0x04
+#define HCI_SUPP_COMMANDS_ENABLE_DEV_UNDER_TEST_OFF 16
+#define HCI_ENABLE_DEV_UNDER_TEST_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_ENABLE_DEV_UNDER_TEST_OFF] & HCI_SUPP_COMMANDS_ENABLE_DEV_UNDER_TEST_MASK)
+
+#define HCI_SUPP_COMMANDS_SETUP_SYNCH_CONN_MASK 0x08
+#define HCI_SUPP_COMMANDS_SETUP_SYNCH_CONN_OFF 16
+#define HCI_SETUP_SYNCH_CONN_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SETUP_SYNCH_CONN_OFF] & HCI_SUPP_COMMANDS_SETUP_SYNCH_CONN_MASK)
+
+#define HCI_SUPP_COMMANDS_ACCEPT_SYNCH_CONN_MASK 0x10
+#define HCI_SUPP_COMMANDS_ACCEPT_SYNCH_CONN_OFF 16
+#define HCI_ACCEPT_SYNCH_CONN_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_ACCEPT_SYNCH_CONN_OFF] & HCI_SUPP_COMMANDS_ACCEPT_SYNCH_CONN_MASK)
+
+#define HCI_SUPP_COMMANDS_REJECT_SYNCH_CONN_MASK 0x20
+#define HCI_SUPP_COMMANDS_REJECT_SYNCH_CONN_OFF 16
+#define HCI_REJECT_SYNCH_CONN_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_REJECT_SYNCH_CONN_OFF] & HCI_SUPP_COMMANDS_REJECT_SYNCH_CONN_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_EXT_INQUIRY_RESP_MASK 0x01
+#define HCI_SUPP_COMMANDS_READ_EXT_INQUIRY_RESP_OFF 17
+#define HCI_READ_EXT_INQUIRY_RESP_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_EXT_INQUIRY_RESP_OFF] & HCI_SUPP_COMMANDS_READ_EXT_INQUIRY_RESP_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_EXT_INQUIRY_RESP_MASK 0x02
+#define HCI_SUPP_COMMANDS_WRITE_EXT_INQUIRY_RESP_OFF 17
+#define HCI_WRITE_EXT_INQUIRY_RESP_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_EXT_INQUIRY_RESP_OFF] & HCI_SUPP_COMMANDS_WRITE_EXT_INQUIRY_RESP_MASK)
+
+#define HCI_SUPP_COMMANDS_REFRESH_ENCRYPTION_KEY_MASK 0x04
+#define HCI_SUPP_COMMANDS_REFRESH_ENCRYPTION_KEY_OFF 17
+#define HCI_REFRESH_ENCRYPTION_KEY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_REFRESH_ENCRYPTION_KEY_OFF] & HCI_SUPP_COMMANDS_REFRESH_ENCRYPTION_KEY_MASK)
+
+/* Octet 17, bit 3 is reserved */
+
+#define HCI_SUPP_COMMANDS_SNIFF_SUB_RATE_MASK 0x10
+#define HCI_SUPP_COMMANDS_SNIFF_SUB_RATE_OFF 17
+#define HCI_SNIFF_SUB_RATE_CMD_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SNIFF_SUB_RATE_OFF] & HCI_SUPP_COMMANDS_SNIFF_SUB_RATE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_SIMPLE_PAIRING_MODE_MASK 0x20
+#define HCI_SUPP_COMMANDS_READ_SIMPLE_PAIRING_MODE_OFF 17
+#define HCI_READ_SIMPLE_PAIRING_MODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_SIMPLE_PAIRING_MODE_OFF] & HCI_SUPP_COMMANDS_READ_SIMPLE_PAIRING_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_SIMPLE_PAIRING_MODE_MASK 0x40
+#define HCI_SUPP_COMMANDS_WRITE_SIMPLE_PAIRING_MODE_OFF 17
+#define HCI_WRITE_SIMPLE_PAIRING_MODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_SIMPLE_PAIRING_MODE_OFF] & HCI_SUPP_COMMANDS_WRITE_SIMPLE_PAIRING_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOCAL_OOB_DATA_MASK 0x80
+#define HCI_SUPP_COMMANDS_READ_LOCAL_OOB_DATA_OFF 17
+#define HCI_READ_LOCAL_OOB_DATA_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_OOB_DATA_OFF] & HCI_SUPP_COMMANDS_READ_LOCAL_OOB_DATA_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_INQUIRY_RESPONSE_TX_POWER_MASK 0x01
+#define HCI_SUPP_COMMANDS_READ_INQUIRY_RESPONSE_TX_POWER_OFF 18
+#define HCI_READ_INQUIRY_RESPONSE_TX_POWER_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_INQUIRY_RESPONSE_TX_POWER_OFF] & HCI_SUPP_COMMANDS_READ_INQUIRY_RESPONSE_TX_POWER_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_INQUIRY_RESPONSE_TX_POWER_MASK 0x02
+#define HCI_SUPP_COMMANDS_WRITE_INQUIRY_RESPONSE_TX_POWER_OFF 18
+#define HCI_WRITE_INQUIRY_RESPONSE_TX_POWER_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_INQUIRY_RESPONSE_TX_POWER_OFF] & HCI_SUPP_COMMANDS_WRITE_INQUIRY_RESPONSE_TX_POWER_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_DEFAULT_ERRONEOUS_DATA_REPORTING_MASK 0x04
+#define HCI_SUPP_COMMANDS_READ_DEFAULT_ERRONEOUS_DATA_REPORTING_OFF 18
+#define HCI_READ_DEFAULT_ERRONEOUS_DATA_REPORTING_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_DEFAULT_ERRONEOUS_DATA_REPORTING_OFF] & HCI_SUPP_COMMANDS_READ_DEFAULT_ERRONEOUS_DATA_REPORTING_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_DEFAULT_ERRONEOUS_DATA_REPORTING_MASK 0x08
+#define HCI_SUPP_COMMANDS_WRITE_DEFAULT_ERRONEOUS_DATA_REPORTING_OFF 18
+#define HCI_WRITE_DEFAULT_ERRONEOUS_DATA_REPORTING_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_DEFAULT_ERRONEOUS_DATA_REPORTING_OFF] & HCI_SUPP_COMMANDS_WRITE_DEFAULT_ERRONEOUS_DATA_REPORTING_MASK)
+
+#define HCI_SUPP_COMMANDS_IO_CAPABILITY_RESPONSE_MASK 0x80
+#define HCI_SUPP_COMMANDS_IO_CAPABILITY_RESPONSE_OFF 18
+#define HCI_IO_CAPABILITY_RESPONSE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_IO_CAPABILITY_RESPONSE_OFF] & HCI_SUPP_COMMANDS_IO_CAPABILITY_RESPONSE_MASK)
+
+#define HCI_SUPP_COMMANDS_USER_CONFIRMATION_REQUEST_REPLY_MASK 0x01
+#define HCI_SUPP_COMMANDS_USER_CONFIRMATION_REQUEST_REPLY_OFF 19
+#define HCI_USER_CONFIRMATION_REQUEST_REPLY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_USER_CONFIRMATION_REQUEST_REPLY_OFF] & HCI_SUPP_COMMANDS_USER_CONFIRMATION_REQUEST_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_USER_CONFIRMATION_REQUEST_NEG_REPLY_MASK 0x02
+#define HCI_SUPP_COMMANDS_USER_CONFIRMATION_REQUEST_NEG_REPLY_OFF 19
+#define HCI_USER_CONFIRMATION_REQUEST_NEG_REPLY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_USER_CONFIRMATION_REQUEST_NEG_REPLY_OFF] & HCI_SUPP_COMMANDS_USER_CONFIRMATION_REQUEST_NEG_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_USER_PASSKEY_REQUEST_REPLY_MASK 0x04
+#define HCI_SUPP_COMMANDS_USER_PASSKEY_REQUEST_REPLY_OFF 19
+#define HCI_USER_PASSKEY_REQUEST_REPLY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_USER_PASSKEY_REQUEST_REPLY_OFF] & HCI_SUPP_COMMANDS_USER_PASSKEY_REQUEST_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_USER_PASSKEY_REQUEST_NEG_REPLY_MASK 0x08
+#define HCI_SUPP_COMMANDS_USER_PASSKEY_REQUEST_NEG_REPLY_OFF 19
+#define HCI_USER_PASSKEY_REQUEST_NEG_REPLY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_USER_PASSKEY_REQUEST_NEG_REPLY_OFF] & HCI_SUPP_COMMANDS_USER_PASSKEY_REQUEST_NEG_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_REMOTE_OOB_DATA_REQUEST_REPLY_MASK 0x10
+#define HCI_SUPP_COMMANDS_REMOTE_OOB_DATA_REQUEST_REPLY_OFF 19
+#define HCI_REMOTE_OOB_DATA_REQUEST_REPLY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_REMOTE_OOB_DATA_REQUEST_REPLY_OFF] & HCI_SUPP_COMMANDS_REMOTE_OOB_DATA_REQUEST_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_SIMPLE_PAIRING_DBG_MODE_MASK 0x20
+#define HCI_SUPP_COMMANDS_WRITE_SIMPLE_PAIRING_DBG_MODE_OFF 19
+#define HCI_WRITE_SIMPLE_PAIRING_DBG_MODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_SIMPLE_PAIRING_DBG_MODE_OFF] & HCI_SUPP_COMMANDS_WRITE_SIMPLE_PAIRING_DBG_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_ENHANCED_FLUSH_MASK 0x40
+#define HCI_SUPP_COMMANDS_ENHANCED_FLUSH_OFF 19
+#define HCI_ENHANCED_FLUSH_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_ENHANCED_FLUSH_OFF] & HCI_SUPP_COMMANDS_ENHANCED_FLUSH_MASK)
+
+#define HCI_SUPP_COMMANDS_REMOTE_OOB_DATA_REQUEST_NEG_REPLY_MASK 0x80
+#define HCI_SUPP_COMMANDS_REMOTE_OOB_DATA_REQUEST_NEG_REPLY_OFF 19
+#define HCI_REMOTE_OOB_DATA_REQUEST_NEG_REPLY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_REMOTE_OOB_DATA_REQUEST_NEG_REPLY_OFF] & HCI_SUPP_COMMANDS_REMOTE_OOB_DATA_REQUEST_NEG_REPLY_MASK)
+
+/* Supported Commands (Byte 20) */
+#define HCI_SUPP_COMMANDS_SEND_KEYPRESS_NOTIF_MASK 0x04
+#define HCI_SUPP_COMMANDS_SEND_KEYPRESS_NOTIF_OFF 20
+#define HCI_SEND_NOTIF_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SEND_KEYPRESS_NOTIF_OFF] & HCI_SUPP_COMMANDS_SEND_KEYPRESS_NOTIF_MASK)
+
+#define HCI_SUPP_COMMANDS_IO_CAP_REQ_NEG_REPLY_MASK 0x08
+#define HCI_SUPP_COMMANDS_IO_CAP_REQ_NEG_REPLY_OFF 20
+#define HCI_IO_CAP_REQ_NEG_REPLY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_IO_CAP_REQ_NEG_REPLY_OFF] & HCI_SUPP_COMMANDS_IO_CAP_REQ_NEG_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_ENCR_KEY_SIZE_MASK 0x10
+#define HCI_SUPP_COMMANDS_READ_ENCR_KEY_SIZE_OFF 20
+#define HCI_READ_ENCR_KEY_SIZE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_ENCR_KEY_SIZE_OFF] & HCI_SUPP_COMMANDS_READ_ENCR_KEY_SIZE_MASK)
+
+/* Supported Commands (Byte 21) */
+#define HCI_SUPP_COMMANDS_CREATE_PHYSICAL_LINK_MASK 0x01
+#define HCI_SUPP_COMMANDS_CREATE_PHYSICAL_LINK_OFF 21
+#define HCI_CREATE_PHYSICAL_LINK_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_CREATE_PHYSICAL_LINK_OFF] & HCI_SUPP_COMMANDS_CREATE_PHYSICAL_LINK_MASK)
+
+#define HCI_SUPP_COMMANDS_ACCEPT_PHYSICAL_LINK_MASK 0x02
+#define HCI_SUPP_COMMANDS_ACCEPT_PHYSICAL_LINK_OFF 21
+#define HCI_ACCEPT_PHYSICAL_LINK_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_ACCEPT_PHYSICAL_LINK_OFF] & HCI_SUPP_COMMANDS_ACCEPT_PHYSICAL_LINK_MASK)
+
+#define HCI_SUPP_COMMANDS_DISCONNECT_PHYSICAL_LINK_MASK 0x04
+#define HCI_SUPP_COMMANDS_DISCONNECT_PHYSICAL_LINK_OFF 21
+#define HCI_DISCONNECT_PHYSICAL_LINK_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_DISCONNECT_PHYSICAL_LINK_OFF] & HCI_SUPP_COMMANDS_DISCONNECT_PHYSICAL_LINK_MASK)
+
+#define HCI_SUPP_COMMANDS_CREATE_LOGICAL_LINK_MASK 0x08
+#define HCI_SUPP_COMMANDS_CREATE_LOGICAL_LINK_OFF 21
+#define HCI_CREATE_LOGICAL_LINK_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_CREATE_LOGICAL_LINK_OFF] & HCI_SUPP_COMMANDS_CREATE_LOGICAL_LINK_MASK)
+
+#define HCI_SUPP_COMMANDS_ACCEPT_LOGICAL_LINK_MASK 0x10
+#define HCI_SUPP_COMMANDS_ACCEPT_LOGICAL_LINK_OFF 21
+#define HCI_ACCEPT_LOGICAL_LINK_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_ACCEPT_LOGICAL_LINK_OFF] & HCI_SUPP_COMMANDS_ACCEPT_LOGICAL_LINK_MASK)
+
+#define HCI_SUPP_COMMANDS_DISCONNECT_LOGICAL_LINK_MASK 0x20
+#define HCI_SUPP_COMMANDS_DISCONNECT_LOGICAL_LINK_OFF 21
+#define HCI_DISCONNECT_LOGICAL_LINK_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_DISCONNECT_LOGICAL_LINK_OFF] & HCI_SUPP_COMMANDS_DISCONNECT_LOGICAL_LINK_MASK)
+
+#define HCI_SUPP_COMMANDS_LOGICAL_LINK_CANCEL_MASK 0x40
+#define HCI_SUPP_COMMANDS_LOGICAL_LINK_CANCEL_OFF 21
+#define HCI_LOGICAL_LINK_CANCEL_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_LOGICAL_LINK_CANCEL_OFF] & HCI_SUPP_COMMANDS_LOGICAL_LINK_CANCEL_MASK)
+
+#define HCI_SUPP_COMMANDS_FLOW_SPEC_MODIFY_MASK 0x80
+#define HCI_SUPP_COMMANDS_FLOW_SPEC_MODIFY_OFF 21
+#define HCI_FLOW_SPEC_MODIFY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_FLOW_SPEC_MODIFY_OFF] & HCI_SUPP_COMMANDS_FLOW_SPEC_MODIFY_MASK)
+
+/* Supported Commands (Byte 22) */
+#define HCI_SUPP_COMMANDS_READ_LOGICAL_LINK_ACCEPT_TIMEOUT_MASK 0x01
+#define HCI_SUPP_COMMANDS_READ_LOGICAL_LINK_ACCEPT_TIMEOUT_OFF 22
+#define HCI_READ_LOGICAL_LINK_ACCEPT_TIMEOUT_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_LOGICAL_LINK_ACCEPT_TIMEOUT_OFF] & HCI_SUPP_COMMANDS_READ_LOGICAL_LINK_ACCEPT_TIMEOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_LOGICAL_LINK_ACCEPT_TIMEOUT_MASK 0x02
+#define HCI_SUPP_COMMANDS_WRITE_LOGICAL_LINK_ACCEPT_TIMEOUT_OFF 22
+#define HCI_WRITE_LOGICAL_LINK_ACCEPT_TIMEOUT_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_LOGICAL_LINK_ACCEPT_TIMEOUT_OFF] & HCI_SUPP_COMMANDS_WRITE_LOGICAL_LINK_ACCEPT_TIMEOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_SET_EVENT_MASK_PAGE_2_MASK 0x04
+#define HCI_SUPP_COMMANDS_SET_EVENT_MASK_PAGE_2_OFF 22
+#define HCI_SET_EVENT_MASK_PAGE_2_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SET_EVENT_MASK_PAGE_2_OFF] & HCI_SUPP_COMMANDS_SET_EVENT_MASK_PAGE_2_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOCATION_DATA_MASK 0x08
+#define HCI_SUPP_COMMANDS_READ_LOCATION_DATA_OFF 22
+#define HCI_READ_LOCATION_DATA_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_LOCATION_DATA_OFF] & HCI_SUPP_COMMANDS_READ_LOCATION_DATA_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_LOCATION_DATA_MASK 0x10
+#define HCI_SUPP_COMMANDS_WRITE_LOCATION_DATA_OFF 22
+#define HCI_WRITE_LOCATION_DATA_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_LOCATION_DATA_OFF] & HCI_SUPP_COMMANDS_WRITE_LOCATION_DATA_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOCAL_AMP_INFO_MASK 0x20
+#define HCI_SUPP_COMMANDS_READ_LOCAL_AMP_INFO_OFF 22
+#define HCI_READ_LOCAL_AMP_INFO_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_AMP_INFO_OFF] & HCI_SUPP_COMMANDS_READ_LOCAL_AMP_INFO_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOCAL_AMP_ASSOC_MASK 0x40
+#define HCI_SUPP_COMMANDS_READ_LOCAL_AMP_ASSOC_OFF 22
+#define HCI_READ_LOCAL_AMP_ASSOC_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_AMP_ASSOC_OFF] & HCI_SUPP_COMMANDS_READ_LOCAL_AMP_ASSOC_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_REMOTE_AMP_ASSOC_MASK 0x80
+#define HCI_SUPP_COMMANDS_WRITE_REMOTE_AMP_ASSOC_OFF 22
+#define HCI_WRITE_REMOTE_AMP_ASSOC_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_REMOTE_AMP_ASSOC_OFF] & HCI_SUPP_COMMANDS_WRITE_REMOTE_AMP_ASSOC_MASK)
+
+/* Supported Commands (Byte 23) */
+#define HCI_SUPP_COMMANDS_READ_FLOW_CONTROL_MODE_MASK 0x01
+#define HCI_SUPP_COMMANDS_READ_FLOW_CONTROL_MODE_OFF 23
+#define HCI_READ_FLOW_CONTROL_MODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_FLOW_CONTROL_MODE_OFF] & HCI_SUPP_COMMANDS_READ_FLOW_CONTROL_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_FLOW_CONTROL_MODE_MASK 0x02
+#define HCI_SUPP_COMMANDS_WRITE_FLOW_CONTROL_MODE_OFF 23
+#define HCI_WRITE_FLOW_CONTROL_MODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_FLOW_CONTROL_MODE_OFF] & HCI_SUPP_COMMANDS_WRITE_FLOW_CONTROL_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_DATA_BLOCK_SIZE_MASK 0x04
+#define HCI_SUPP_COMMANDS_READ_DATA_BLOCK_SIZE_OFF 23
+#define HCI_READ_DATA_BLOCK_SIZE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_DATA_BLOCK_SIZE_OFF] & HCI_SUPP_COMMANDS_READ_DATA_BLOCK_SIZE_MASK)
+
+#define HCI_SUPP_COMMANDS_ENABLE_AMP_RCVR_REPORTS_MASK 0x20
+#define HCI_SUPP_COMMANDS_ENABLE_AMP_RCVR_REPORTS_OFF 23
+#define HCI_ENABLE_AMP_RCVR_REPORTS_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_ENABLE_AMP_RCVR_REPORTS_OFF] & HCI_SUPP_COMMANDS_ENABLE_AMP_RCVR_REPORTS_MASK)
+
+#define HCI_SUPP_COMMANDS_AMP_TEST_END_MASK 0x40
+#define HCI_SUPP_COMMANDS_AMP_TEST_END_OFF 23
+#define HCI_AMP_TEST_END_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_AMP_TEST_END_OFF] & HCI_SUPP_COMMANDS_AMP_TEST_END_MASK)
+
+#define HCI_SUPP_COMMANDS_AMP_TEST_MASK 0x80
+#define HCI_SUPP_COMMANDS_AMP_TEST_OFF 23
+#define HCI_AMP_TEST_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_AMP_TEST_OFF] & HCI_SUPP_COMMANDS_AMP_TEST_MASK)
+
+/* Supported Commands (Byte 24) */
+#define HCI_SUPP_COMMANDS_READ_TRANSMIT_POWER_LEVEL_MASK 0x01
+#define HCI_SUPP_COMMANDS_READ_TRANSMIT_POWER_LEVEL_OFF 24
+#define HCI_READ_TRANSMIT_POWER_LEVEL_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_TRANSMIT_POWER_LEVEL_OFF] & HCI_SUPP_COMMANDS_READ_TRANSMIT_POWER_LEVEL_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_BE_FLUSH_TOUT_MASK 0x04
+#define HCI_SUPP_COMMANDS_READ_BE_FLUSH_TOUT_OFF 24
+#define HCI_READ_BE_FLUSH_TOUT_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_BE_FLUSH_TOUT_OFF] & HCI_SUPP_COMMANDS_READ_BE_FLUSH_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_BE_FLUSH_TOUT_MASK 0x08
+#define HCI_SUPP_COMMANDS_WRITE_BE_FLUSH_TOUT_OFF 24
+#define HCI_WRITE_BE_FLUSH_TOUT_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_BE_FLUSH_TOUT_OFF] & HCI_SUPP_COMMANDS_WRITE_BE_FLUSH_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_SHORT_RANGE_MODE_MASK 0x10
+#define HCI_SUPP_COMMANDS_SHORT_RANGE_MODE_OFF 24
+#define HCI_SHORT_RANGE_MODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SHORT_RANGE_MODE_OFF] & HCI_SUPP_COMMANDS_SHORT_RANGE_MODE_MASK)
+
+/* LE commands TBD
+** Supported Commands (Byte 24 continued)
+** Supported Commands (Byte 25)
+** Supported Commands (Byte 26)
+** Supported Commands (Byte 27)
+** Supported Commands (Byte 28)
+*/
+
+/*
+Commands of HCI_GRP_VENDOR_SPECIFIC group for WIDCOMM SW LM Simulator
+*/
+#ifdef _WIDCOMM
+
+#define HCI_SET_HCI_TRACE (0x0001 | HCI_GRP_VENDOR_SPECIFIC)
+#define HCI_SET_LM_TRACE (0x0002 | HCI_GRP_VENDOR_SPECIFIC)
+#define HCI_WRITE_COUNTRY_CODE (0x0004 | HCI_GRP_VENDOR_SPECIFIC)
+#define HCI_READ_LM_HISTORY (0x0005 | HCI_GRP_VENDOR_SPECIFIC)
+#define HCI_WRITE_BD_ADDR (0x0006 | HCI_GRP_VENDOR_SPECIFIC)
+#define HCI_DISABLE_ENCRYPTION (0x0007 | HCI_GRP_VENDOR_SPECIFIC)
+#define HCI_DISABLE_AUTHENTICATION (0x0008 | HCI_GRP_VENDOR_SPECIFIC)
+#define HCI_GENERIC_LC_CMD (0x000A | HCI_GRP_VENDOR_SPECIFIC)
+#define HCI_INCR_POWER (0x000B | HCI_GRP_VENDOR_SPECIFIC)
+#define HCI_DECR_POWER (0x000C | HCI_GRP_VENDOR_SPECIFIC)
+
+/* Definitions for the local transactions */
+#define LM_DISCONNECT (0x00D0 | HCI_GRP_VENDOR_SPECIFIC)
+#define LM_AUTHENTICATION_REQUESTED (0x00D1 | HCI_GRP_VENDOR_SPECIFIC)
+#define LM_SET_CONN_ENCRYPTION (0x00D2 | HCI_GRP_VENDOR_SPECIFIC)
+#define LM_START_ENCRYPT_KEY_SIZE (0x00D3 | HCI_GRP_VENDOR_SPECIFIC)
+#define LM_START_ENCRYPTION (0x00D4 | HCI_GRP_VENDOR_SPECIFIC)
+#define LM_STOP_ENCRYPTION (0x00D5 | HCI_GRP_VENDOR_SPECIFIC)
+#define LM_CHANGE_CONN_PACKET_TYPE (0x00D6 | HCI_GRP_VENDOR_SPECIFIC)
+#define LM_RMT_NAME_REQUEST (0x00D7 | HCI_GRP_VENDOR_SPECIFIC)
+#define LM_READ_RMT_FEATURES (0x00D8 | HCI_GRP_VENDOR_SPECIFIC)
+#define LM_READ_RMT_VERSION_INFO (0x00D9 | HCI_GRP_VENDOR_SPECIFIC)
+#define LM_READ_RMT_TIMING_INFO (0x00DA | HCI_GRP_VENDOR_SPECIFIC)
+#define LM_READ_RMT_CLOCK_OFFSET (0x00DB | HCI_GRP_VENDOR_SPECIFIC)
+#define LM_HOLD_MODE (0x00DC | HCI_GRP_VENDOR_SPECIFIC)
+#define LM_EXIT_PARK_MODE (0x00DD | HCI_GRP_VENDOR_SPECIFIC)
+
+#define LM_SCO_LINK_REQUEST (0x00E0 | HCI_GRP_VENDOR_SPECIFIC)
+#define LM_SCO_CHANGE (0x00E4 | HCI_GRP_VENDOR_SPECIFIC)
+#define LM_SCO_REMOVE (0x00E8 | HCI_GRP_VENDOR_SPECIFIC)
+#define LM_MAX_SLOTS (0x00F1 | HCI_GRP_VENDOR_SPECIFIC)
+#define LM_MAX_SLOTS_REQUEST (0x00F2 | HCI_GRP_VENDOR_SPECIFIC)
+
+#ifdef INCLUDE_OPTIONAL_PAGING_SCHEME
+#define LM_OPTIONAL_PAGE_REQUEST (0x00F3 | HCI_GRP_VENDOR_SPECIFIC)
+#define LM_OPTIONAL_PAGESCAN_REQUEST (0x00F4 | HCI_GRP_VENDOR_SPECIFIC)
+#endif
+
+#define LM_SETUP_COMPLETE (0x00FF | HCI_GRP_VENDOR_SPECIFIC)
+
+#define LM_HIST_SEND_LMP_FRAME (0x0100 | HCI_GRP_VENDOR_SPECIFIC)
+#define LM_HIST_RECV_LMP_FRAME (0x0101 | HCI_GRP_VENDOR_SPECIFIC)
+#define LM_HIST_HCIT_ERROR (0x0102 | HCI_GRP_VENDOR_SPECIFIC)
+#define LM_HIST_PER_INQ_TOUT (0x0103 | HCI_GRP_VENDOR_SPECIFIC)
+#define LM_HIST_INQ_SCAN_TOUT (0x0104 | HCI_GRP_VENDOR_SPECIFIC)
+#define LM_HIST_PAGE_SCAN_TOUT (0x0105 | HCI_GRP_VENDOR_SPECIFIC)
+#define LM_HIST_RESET_TOUT (0x0106 | HCI_GRP_VENDOR_SPECIFIC)
+#define LM_HIST_MANDAT_PSCAN_TOUT (0x0107 | HCI_GRP_VENDOR_SPECIFIC)
+#define LM_HIST_ACL_START_TRANS (0x0108 | HCI_GRP_VENDOR_SPECIFIC)
+#define LM_HIST_ACL_HOST_REPLY (0x0109 | HCI_GRP_VENDOR_SPECIFIC)
+#define LM_HIST_ACL_TIMEOUT (0x010A | HCI_GRP_VENDOR_SPECIFIC)
+#define LM_HIST_ACL_TX_COMP (0x010B | HCI_GRP_VENDOR_SPECIFIC)
+#define LM_HIST_ACL_HCID_SUSPENDED (0x010C | HCI_GRP_VENDOR_SPECIFIC)
+#define LM_HIST_ACL_FAILED (0x010D | HCI_GRP_VENDOR_SPECIFIC)
+#define LM_HIST_HCI_COMMAND (0x010E | HCI_GRP_VENDOR_SPECIFIC)
+
+#define LM_HIST_HCI_EVENT (0x010F | HCI_GRP_VENDOR_SPECIFIC)
+#define LM_HIST_HCI_UPDATA (0x0110 | HCI_GRP_VENDOR_SPECIFIC)
+#define LM_HIST_HCI_DNDATA (0x0111 | HCI_GRP_VENDOR_SPECIFIC)
+
+#define HCI_ENTER_TEST_MODE (0x0300 | HCI_GRP_VENDOR_SPECIFIC)
+#define HCI_LMP_TEST_CNTRL (0x0301 | HCI_GRP_VENDOR_SPECIFIC)
+#define HCI_DEBUG_LC_CMD_MIN (0x0300 | HCI_GRP_VENDOR_SPECIFIC)
+#define HCI_DEBUG_LC_CMD_MAX (0x03FF | HCI_GRP_VENDOR_SPECIFIC)
+#define HCI_DEBUG_LC_COMMAND HCI_DEBUG_LC_CMD_MAX
+
+#endif
+
+
+/* AMP VSE events
+*/
+#define AMP_VSE_CHANSPEC_CHAN_MASK 0x00ff
+
+#define AMP_VSE_CHANSPEC_CTL_SB_MASK 0x0300
+#define AMP_VSE_CHANSPEC_CTL_SB_LOWER 0x0100
+#define AMP_VSE_CHANSPEC_CTL_SB_UPPER 0x0200
+#define AMP_VSE_CHANSPEC_CTL_SB_NONE 0x0300
+
+#define AMP_VSE_CHANSPEC_BW_MASK 0x0C00
+#define AMP_VSE_CHANSPEC_BW_10 0x0400
+#define AMP_VSE_CHANSPEC_BW_20 0x0800
+#define AMP_VSE_CHANSPEC_BW_40 0x0C00
+
+#define AMP_VSE_CHANSPEC_BAND_MASK 0xf000
+#define AMP_VSE_CHANSPEC_BAND_5G 0x1000
+#define AMP_VSE_CHANSPEC_BAND_2G 0x2000
+
+
+#endif
+
diff --git a/stack/include/hcimsgs.h b/stack/include/hcimsgs.h
new file mode 100644
index 0000000..5cfdcc2
--- /dev/null
+++ b/stack/include/hcimsgs.h
@@ -0,0 +1,1325 @@
+/*****************************************************************************
+**
+** Name hcimsgs.h
+**
+** Function this file defines Host Controller Interface messages
+**
+**
+** Copyright (c) 1999-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+******************************************************************************/
+
+#ifndef HCIMSGS_H
+#define HCIMSGS_H
+
+#include "bt_target.h"
+#include "hcidefs.h"
+#include "bt_types.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Message by message.... */
+
+#define HCIC_GET_UINT8(p, off) (UINT8)(*((UINT8 *)((p) + 1) + p->offset + 3 + (off)))
+
+#define HCIC_GET_UINT16(p, off) (UINT16)((*((UINT8 *)((p) + 1) + p->offset + 3 + (off)) + \
+ (*((UINT8 *)((p) + 1) + p->offset + 3 + (off) + 1) << 8)))
+
+#define HCIC_GET_UINT32(p, off) (UINT32)((*((UINT8 *)((p) + 1) + p->offset + 3 + (off)) + \
+ (*((UINT8 *)((p) + 1) + p->offset + 3 + (off) + 1) << 8) + \
+ (*((UINT8 *)((p) + 1) + p->offset + 3 + (off) + 2) << 16) + \
+ (*((UINT8 *)((p) + 1) + p->offset + 3 + (off) + 3) << 24)))
+
+#define HCIC_GET_ARRAY(p, off, x, len) \
+{ \
+ UINT8 *qq = ((UINT8 *)((p) + 1) + p->offset + 3 + (off)); UINT8 *rr = (UINT8 *)x; \
+ int ii; for (ii = 0; ii < len; ii++) *rr++ = *qq++; \
+}
+
+#define HCIC_GET_ARRAY16(p, off, x) \
+{ \
+ UINT8 *qq = ((UINT8 *)((p) + 1) + p->offset + 3 + (off)); UINT8 *rr = (UINT8 *)x + 15; \
+ int ii; for (ii = 0; ii < 16; ii++) *rr-- = *qq++; \
+}
+
+#define HCIC_GET_BDADDR(p, off, x) \
+{ \
+ UINT8 *qq = ((UINT8 *)((p) + 1) + p->offset + 3 + (off)); UINT8 *rr = (UINT8 *)x + BD_ADDR_LEN - 1; \
+ int ii; for (ii = 0; ii < BD_ADDR_LEN; ii++) *rr-- = *qq++; \
+}
+
+#define HCIC_GET_DEVCLASS(p, off, x) \
+{ \
+ UINT8 *qq = ((UINT8 *)((p) + 1) + p->offset + 3 + (off)); UINT8 *rr = (UINT8 *)x + DEV_CLASS_LEN - 1; \
+ int ii; for (ii = 0; ii < DEV_CLASS_LEN; ii++) *rr-- = *qq++; \
+}
+
+#define HCIC_GET_LAP(p, off, x) \
+{ \
+ UINT8 *qq = ((UINT8 *)((p) + 1) + p->offset + 3 + (off)); UINT8 *rr = (UINT8 *)x + LAP_LEN - 1; \
+ int ii; for (ii = 0; ii < LAP_LEN; ii++) *rr-- = *qq++; \
+}
+
+#define HCIC_GET_POINTER(p, off) ((UINT8 *)((p) + 1) + p->offset + 3 + (off))
+
+
+HCI_API extern BOOLEAN btsnd_hcic_inquiry(const LAP inq_lap, UINT8 duration,
+ UINT8 response_cnt);
+
+#define HCIC_PARAM_SIZE_INQUIRY 5
+
+
+#define HCIC_INQ_INQ_LAP_OFF 0
+#define HCIC_INQ_DUR_OFF 3
+#define HCIC_INQ_RSP_CNT_OFF 4
+ /* Inquiry */
+
+ /* Inquiry Cancel */
+HCI_API extern BOOLEAN btsnd_hcic_inq_cancel(void);
+
+#define HCIC_PARAM_SIZE_INQ_CANCEL 0
+
+ /* Periodic Inquiry Mode */
+HCI_API extern BOOLEAN btsnd_hcic_per_inq_mode(UINT16 max_period, UINT16 min_period,
+ const LAP inq_lap, UINT8 duration,
+ UINT8 response_cnt);
+
+#define HCIC_PARAM_SIZE_PER_INQ_MODE 9
+
+#define HCI_PER_INQ_MAX_INTRVL_OFF 0
+#define HCI_PER_INQ_MIN_INTRVL_OFF 2
+#define HCI_PER_INQ_INQ_LAP_OFF 4
+#define HCI_PER_INQ_DURATION_OFF 7
+#define HCI_PER_INQ_RSP_CNT_OFF 8
+ /* Periodic Inquiry Mode */
+
+ /* Exit Periodic Inquiry Mode */
+HCI_API extern BOOLEAN btsnd_hcic_exit_per_inq(void);
+
+#define HCIC_PARAM_SIZE_EXIT_PER_INQ 0
+ /* Create Connection */
+HCI_API extern BOOLEAN btsnd_hcic_create_conn(BD_ADDR dest, UINT16 packet_types,
+ UINT8 page_scan_rep_mode,
+ UINT8 page_scan_mode,
+ UINT16 clock_offset,
+ UINT8 allow_switch);
+
+#define HCIC_PARAM_SIZE_CREATE_CONN 13
+
+#define HCIC_CR_CONN_BD_ADDR_OFF 0
+#define HCIC_CR_CONN_PKT_TYPES_OFF 6
+#define HCIC_CR_CONN_REP_MODE_OFF 8
+#define HCIC_CR_CONN_PAGE_SCAN_MODE_OFF 9
+#define HCIC_CR_CONN_CLK_OFF_OFF 10
+#define HCIC_CR_CONN_ALLOW_SWITCH_OFF 12
+ /* Create Connection */
+
+ /* Disconnect */
+HCI_API extern BOOLEAN btsnd_hcic_disconnect(UINT16 handle, UINT8 reason);
+
+#define HCIC_PARAM_SIZE_DISCONNECT 3
+
+#define HCI_DISC_HANDLE_OFF 0
+#define HCI_DISC_REASON_OFF 2
+ /* Disconnect */
+
+#if BTM_SCO_INCLUDED == TRUE
+ /* Add SCO Connection */
+HCI_API extern BOOLEAN btsnd_hcic_add_SCO_conn (UINT16 handle, UINT16 packet_types);
+#endif /* BTM_SCO_INCLUDED */
+
+#define HCIC_PARAM_SIZE_ADD_SCO_CONN 4
+
+#define HCI_ADD_SCO_HANDLE_OFF 0
+#define HCI_ADD_SCO_PACKET_TYPES_OFF 2
+ /* Add SCO Connection */
+
+ /* Create Connection Cancel */
+HCI_API extern BOOLEAN btsnd_hcic_create_conn_cancel(BD_ADDR dest);
+
+#define HCIC_PARAM_SIZE_CREATE_CONN_CANCEL 6
+
+#define HCIC_CR_CONN_CANCEL_BD_ADDR_OFF 0
+ /* Create Connection Cancel */
+
+ /* Accept Connection Request */
+HCI_API extern BOOLEAN btsnd_hcic_accept_conn (BD_ADDR bd_addr, UINT8 role);
+
+#define HCIC_PARAM_SIZE_ACCEPT_CONN 7
+
+#define HCI_ACC_CONN_BD_ADDR_OFF 0
+#define HCI_ACC_CONN_ROLE_OFF 6
+ /* Accept Connection Request */
+
+ /* Reject Connection Request */
+HCI_API extern BOOLEAN btsnd_hcic_reject_conn (BD_ADDR bd_addr, UINT8 reason);
+
+#define HCIC_PARAM_SIZE_REJECT_CONN 7
+
+#define HCI_REJ_CONN_BD_ADDR_OFF 0
+#define HCI_REJ_CONN_REASON_OFF 6
+ /* Reject Connection Request */
+
+ /* Link Key Request Reply */
+HCI_API extern BOOLEAN btsnd_hcic_link_key_req_reply (BD_ADDR bd_addr,
+ LINK_KEY link_key);
+
+#define HCIC_PARAM_SIZE_LINK_KEY_REQ_REPLY 22
+
+#define HCI_LINK_KEY_REPLY_BD_ADDR_OFF 0
+#define HCI_LINK_KEY_REPLY_LINK_KEY_OFF 6
+ /* Link Key Request Reply */
+
+ /* Link Key Request Neg Reply */
+HCI_API extern BOOLEAN btsnd_hcic_link_key_neg_reply (BD_ADDR bd_addr);
+
+#define HCIC_PARAM_SIZE_LINK_KEY_NEG_REPLY 6
+
+#define HCI_LINK_KEY_NEG_REP_BD_ADR_OFF 0
+ /* Link Key Request Neg Reply */
+
+ /* PIN Code Request Reply */
+HCI_API extern BOOLEAN btsnd_hcic_pin_code_req_reply (BD_ADDR bd_addr,
+ UINT8 pin_code_len,
+ PIN_CODE pin_code);
+
+#define HCIC_PARAM_SIZE_PIN_CODE_REQ_REPLY 23
+
+#define HCI_PIN_CODE_REPLY_BD_ADDR_OFF 0
+#define HCI_PIN_CODE_REPLY_PIN_LEN_OFF 6
+#define HCI_PIN_CODE_REPLY_PIN_CODE_OFF 7
+ /* PIN Code Request Reply */
+
+ /* Link Key Request Neg Reply */
+HCI_API extern BOOLEAN btsnd_hcic_pin_code_neg_reply (BD_ADDR bd_addr);
+
+#define HCIC_PARAM_SIZE_PIN_CODE_NEG_REPLY 6
+
+#define HCI_PIN_CODE_NEG_REP_BD_ADR_OFF 0
+ /* Link Key Request Neg Reply */
+
+ /* Change Connection Type */
+HCI_API extern BOOLEAN btsnd_hcic_change_conn_type (UINT16 handle, UINT16 packet_types);
+
+#define HCIC_PARAM_SIZE_CHANGE_CONN_TYPE 4
+
+#define HCI_CHNG_PKT_TYPE_HANDLE_OFF 0
+#define HCI_CHNG_PKT_TYPE_PKT_TYPE_OFF 2
+ /* Change Connection Type */
+
+#define HCIC_PARAM_SIZE_CMD_HANDLE 2
+
+#define HCI_CMD_HANDLE_HANDLE_OFF 0
+
+HCI_API extern BOOLEAN btsnd_hcic_auth_request (UINT16 handle); /* Authentication Request */
+
+ /* Set Connection Encryption */
+HCI_API extern BOOLEAN btsnd_hcic_set_conn_encrypt (UINT16 handle, BOOLEAN enable);
+#define HCIC_PARAM_SIZE_SET_CONN_ENCRYPT 3
+
+
+#define HCI_SET_ENCRYPT_HANDLE_OFF 0
+#define HCI_SET_ENCRYPT_ENABLE_OFF 2
+ /* Set Connection Encryption */
+
+HCI_API extern BOOLEAN btsnd_hcic_change_link_key (UINT16 handle); /* Change Connection Link Key */
+
+ /* Master Link Key */
+HCI_API extern BOOLEAN btsnd_hcic_master_link_key (BOOLEAN key_flag);
+
+#define HCIC_PARAM_SIZE_MASTER_LINK_KEY 1
+
+#define HCI_MASTER_KEY_FLAG_OFF 0
+ /* Master Link Key */
+
+ /* Remote Name Request */
+HCI_API extern BOOLEAN btsnd_hcic_rmt_name_req (BD_ADDR bd_addr,
+ UINT8 page_scan_rep_mode,
+ UINT8 page_scan_mode,
+ UINT16 clock_offset);
+
+#define HCIC_PARAM_SIZE_RMT_NAME_REQ 10
+
+#define HCI_RMT_NAME_BD_ADDR_OFF 0
+#define HCI_RMT_NAME_REP_MODE_OFF 6
+#define HCI_RMT_NAME_PAGE_SCAN_MODE_OFF 7
+#define HCI_RMT_NAME_CLK_OFF_OFF 8
+ /* Remote Name Request */
+
+ /* Remote Name Request Cancel */
+HCI_API extern BOOLEAN btsnd_hcic_rmt_name_req_cancel(BD_ADDR bd_addr);
+
+#define HCIC_PARAM_SIZE_RMT_NAME_REQ_CANCEL 6
+
+#define HCI_RMT_NAME_CANCEL_BD_ADDR_OFF 0
+ /* Remote Name Request Cancel */
+
+HCI_API extern BOOLEAN btsnd_hcic_rmt_features_req(UINT16 handle); /* Remote Features Request */
+
+ /* Remote Extended Features */
+HCI_API extern BOOLEAN btsnd_hcic_rmt_ext_features(UINT16 handle, UINT8 page_num);
+
+#define HCIC_PARAM_SIZE_RMT_EXT_FEATURES 3
+
+#define HCI_RMT_EXT_FEATURES_HANDLE_OFF 0
+#define HCI_RMT_EXT_FEATURES_PAGE_NUM_OFF 2
+ /* Remote Extended Features */
+
+
+ /* Local Extended Features */
+HCI_API extern BOOLEAN btsnd_hcic_read_local_ext_features (UINT8 page_num);
+
+#define HCIC_PARAM_SIZE_LOCAL_EXT_FEATURES 1
+
+#define HCI_LOCAL_EXT_FEATURES_PAGE_NUM_OFF 0
+ /* Local Extended Features */
+
+
+HCI_API extern BOOLEAN btsnd_hcic_rmt_ver_req(UINT16 handle); /* Remote Version Info Request */
+HCI_API extern BOOLEAN btsnd_hcic_read_rmt_clk_offset(UINT16 handle); /* Remote Clock Offset */
+HCI_API extern BOOLEAN btsnd_hcic_read_lmp_handle(UINT16 handle); /* Remote LMP Handle */
+
+HCI_API extern BOOLEAN btsnd_hcic_setup_esco_conn (UINT16 handle,
+ UINT32 tx_bw, UINT32 rx_bw,
+ UINT16 max_latency, UINT16 voice,
+ UINT8 retrans_effort,
+ UINT16 packet_types);
+#define HCIC_PARAM_SIZE_SETUP_ESCO 17
+
+#define HCI_SETUP_ESCO_HANDLE_OFF 0
+#define HCI_SETUP_ESCO_TX_BW_OFF 2
+#define HCI_SETUP_ESCO_RX_BW_OFF 6
+#define HCI_SETUP_ESCO_MAX_LAT_OFF 10
+#define HCI_SETUP_ESCO_VOICE_OFF 12
+#define HCI_SETUP_ESCO_RETRAN_EFF_OFF 14
+#define HCI_SETUP_ESCO_PKT_TYPES_OFF 15
+
+
+HCI_API extern BOOLEAN btsnd_hcic_accept_esco_conn (BD_ADDR bd_addr,
+ UINT32 tx_bw, UINT32 rx_bw,
+ UINT16 max_latency,
+ UINT16 content_fmt,
+ UINT8 retrans_effort,
+ UINT16 packet_types);
+#define HCIC_PARAM_SIZE_ACCEPT_ESCO 21
+
+#define HCI_ACCEPT_ESCO_BDADDR_OFF 0
+#define HCI_ACCEPT_ESCO_TX_BW_OFF 6
+#define HCI_ACCEPT_ESCO_RX_BW_OFF 10
+#define HCI_ACCEPT_ESCO_MAX_LAT_OFF 14
+#define HCI_ACCEPT_ESCO_VOICE_OFF 16
+#define HCI_ACCEPT_ESCO_RETRAN_EFF_OFF 18
+#define HCI_ACCEPT_ESCO_PKT_TYPES_OFF 19
+
+
+HCI_API extern BOOLEAN btsnd_hcic_reject_esco_conn (BD_ADDR bd_addr, UINT8 reason);
+#define HCIC_PARAM_SIZE_REJECT_ESCO 7
+
+#define HCI_REJECT_ESCO_BDADDR_OFF 0
+#define HCI_REJECT_ESCO_REASON_OFF 6
+
+/* Hold Mode */
+HCI_API extern BOOLEAN btsnd_hcic_hold_mode(UINT16 handle, UINT16 max_hold_period,
+ UINT16 min_hold_period);
+
+#define HCIC_PARAM_SIZE_HOLD_MODE 6
+
+#define HCI_HOLD_MODE_HANDLE_OFF 0
+#define HCI_HOLD_MODE_MAX_PER_OFF 2
+#define HCI_HOLD_MODE_MIN_PER_OFF 4
+ /* Hold Mode */
+
+ /* Sniff Mode */
+HCI_API extern BOOLEAN btsnd_hcic_sniff_mode(UINT16 handle,
+ UINT16 max_sniff_period,
+ UINT16 min_sniff_period,
+ UINT16 sniff_attempt,
+ UINT16 sniff_timeout);
+
+#define HCIC_PARAM_SIZE_SNIFF_MODE 10
+
+
+#define HCI_SNIFF_MODE_HANDLE_OFF 0
+#define HCI_SNIFF_MODE_MAX_PER_OFF 2
+#define HCI_SNIFF_MODE_MIN_PER_OFF 4
+#define HCI_SNIFF_MODE_ATTEMPT_OFF 6
+#define HCI_SNIFF_MODE_TIMEOUT_OFF 8
+ /* Sniff Mode */
+
+HCI_API extern BOOLEAN btsnd_hcic_exit_sniff_mode(UINT16 handle); /* Exit Sniff Mode */
+
+ /* Park Mode */
+HCI_API extern BOOLEAN btsnd_hcic_park_mode (UINT16 handle,
+ UINT16 beacon_max_interval,
+ UINT16 beacon_min_interval);
+
+#define HCIC_PARAM_SIZE_PARK_MODE 6
+
+#define HCI_PARK_MODE_HANDLE_OFF 0
+#define HCI_PARK_MODE_MAX_PER_OFF 2
+#define HCI_PARK_MODE_MIN_PER_OFF 4
+ /* Park Mode */
+
+HCI_API extern BOOLEAN btsnd_hcic_exit_park_mode(UINT16 handle); /* Exit Park Mode */
+
+ /* QoS Setup */
+HCI_API extern BOOLEAN btsnd_hcic_qos_setup (UINT16 handle, UINT8 flags,
+ UINT8 service_type,
+ UINT32 token_rate, UINT32 peak,
+ UINT32 latency, UINT32 delay_var);
+
+#define HCIC_PARAM_SIZE_QOS_SETUP 20
+
+#define HCI_QOS_HANDLE_OFF 0
+#define HCI_QOS_FLAGS_OFF 2
+#define HCI_QOS_SERVICE_TYPE_OFF 3
+#define HCI_QOS_TOKEN_RATE_OFF 4
+#define HCI_QOS_PEAK_BANDWIDTH_OFF 8
+#define HCI_QOS_LATENCY_OFF 12
+#define HCI_QOS_DELAY_VAR_OFF 16
+ /* QoS Setup */
+
+HCI_API extern BOOLEAN btsnd_hcic_role_discovery (UINT16 handle); /* Role Discovery */
+
+ /* Switch Role Request */
+HCI_API extern BOOLEAN btsnd_hcic_switch_role (BD_ADDR bd_addr, UINT8 role);
+
+#define HCIC_PARAM_SIZE_SWITCH_ROLE 7
+
+#define HCI_SWITCH_BD_ADDR_OFF 0
+#define HCI_SWITCH_ROLE_OFF 6
+ /* Switch Role Request */
+
+HCI_API extern BOOLEAN btsnd_hcic_read_policy_set(UINT16 handle); /* Read Policy Settings */
+
+ /* Write Policy Settings */
+HCI_API extern BOOLEAN btsnd_hcic_write_policy_set(UINT16 handle, UINT16 settings);
+
+#define HCIC_PARAM_SIZE_WRITE_POLICY_SET 4
+
+#define HCI_WRITE_POLICY_HANDLE_OFF 0
+#define HCI_WRITE_POLICY_SETTINGS_OFF 2
+ /* Write Policy Settings */
+
+ /* Read Default Policy Settings */
+HCI_API extern BOOLEAN btsnd_hcic_read_def_policy_set(void);
+
+#define HCIC_PARAM_SIZE_READ_DEF_POLICY_SET 0
+ /* Read Default Policy Settings */
+
+ /* Write Default Policy Settings */
+HCI_API extern BOOLEAN btsnd_hcic_write_def_policy_set(UINT16 settings);
+
+#define HCIC_PARAM_SIZE_WRITE_DEF_POLICY_SET 2
+
+#define HCI_WRITE_DEF_POLICY_SETTINGS_OFF 0
+ /* Write Default Policy Settings */
+
+ /* Flow Specification */
+HCI_API extern BOOLEAN btsnd_hcic_flow_specification(UINT16 handle, UINT8 flags,
+ UINT8 flow_direct,
+ UINT8 service_type,
+ UINT32 token_rate,
+ UINT32 token_bucket_size,
+ UINT32 peak, UINT32 latency);
+
+#define HCIC_PARAM_SIZE_FLOW_SPEC 21
+
+#define HCI_FLOW_SPEC_HANDLE_OFF 0
+#define HCI_FLOW_SPEC_FLAGS_OFF 2
+#define HCI_FLOW_SPEC_FLOW_DIRECT_OFF 3
+#define HCI_FLOW_SPEC_SERVICE_TYPE_OFF 4
+#define HCI_FLOW_SPEC_TOKEN_RATE_OFF 5
+#define HCI_FLOW_SPEC_TOKEN_BUCKET_SIZE_OFF 9
+#define HCI_FLOW_SPEC_PEAK_BANDWIDTH_OFF 13
+#define HCI_FLOW_SPEC_LATENCY_OFF 17
+ /* Flow Specification */
+
+/******************************************
+** Lisbon Features
+*******************************************/
+#if BTM_SSR_INCLUDED == TRUE
+ /* Sniff Subrating */
+HCI_API extern BOOLEAN btsnd_hcic_sniff_sub_rate(UINT16 handle, UINT16 max_lat,
+ UINT16 min_remote_lat,
+ UINT16 min_local_lat);
+
+#define HCIC_PARAM_SIZE_SNIFF_SUB_RATE 8
+
+#define HCI_SNIFF_SUB_RATE_HANDLE_OFF 0
+#define HCI_SNIFF_SUB_RATE_MAX_LAT_OFF 2
+#define HCI_SNIFF_SUB_RATE_MIN_REM_LAT_OFF 4
+#define HCI_SNIFF_SUB_RATE_MIN_LOC_LAT_OFF 6
+ /* Sniff Subrating */
+
+#else /* BTM_SSR_INCLUDED == FALSE */
+
+#define btsnd_hcic_sniff_sub_rate(handle, max_lat, min_remote_lat, min_local_lat) FALSE
+
+#endif /* BTM_SSR_INCLUDED */
+
+ /* Extended Inquiry Response */
+#if (BTM_EIR_SERVER_INCLUDED == TRUE)
+HCI_API extern void btsnd_hcic_write_ext_inquiry_response(void *buffer, UINT8 fec_req);
+
+#define HCIC_PARAM_SIZE_EXT_INQ_RESP 241
+
+#define HCIC_EXT_INQ_RESP_FEC_OFF 0
+#define HCIC_EXT_INQ_RESP_RESPONSE 1
+
+HCI_API extern BOOLEAN btsnd_hcic_read_ext_inquiry_response(void); /* Read Extended Inquiry Response */
+#else
+#define btsnd_hcic_write_ext_inquiry_response(buffer, fec_req)
+#define btsnd_hcic_read_ext_inquiry_response() FALSE
+#endif
+ /* Write Simple Pairing Mode */
+/**** Simple Pairing Commands ****/
+HCI_API extern BOOLEAN btsnd_hcic_write_simple_pairing_mode(UINT8 mode);
+
+#define HCIC_PARAM_SIZE_W_SIMP_PAIR 1
+
+#define HCIC_WRITE_SP_MODE_OFF 0
+
+
+HCI_API extern BOOLEAN btsnd_hcic_read_simple_pairing_mode (void);
+
+#define HCIC_PARAM_SIZE_R_SIMP_PAIR 0
+
+ /* Write Simple Pairing Debug Mode */
+HCI_API extern BOOLEAN btsnd_hcic_write_simp_pair_debug_mode(UINT8 debug_mode);
+
+#define HCIC_PARAM_SIZE_SIMP_PAIR_DBUG 1
+
+#define HCIC_WRITE_SP_DBUG_MODE_OFF 0
+
+ /* IO Capabilities Response */
+HCI_API extern BOOLEAN btsnd_hcic_io_cap_req_reply (BD_ADDR bd_addr, UINT8 capability,
+ UINT8 oob_present, UINT8 auth_req);
+
+#define HCIC_PARAM_SIZE_IO_CAP_RESP 9
+
+#define HCI_IO_CAP_BD_ADDR_OFF 0
+#define HCI_IO_CAPABILITY_OFF 6
+#define HCI_IO_CAP_OOB_DATA_OFF 7
+#define HCI_IO_CAP_AUTH_REQ_OFF 8
+
+ /* IO Capabilities Req Neg Reply */
+HCI_API extern BOOLEAN btsnd_hcic_io_cap_req_neg_reply (BD_ADDR bd_addr, UINT8 err_code);
+
+#define HCIC_PARAM_SIZE_IO_CAP_NEG_REPLY 7
+
+#define HCI_IO_CAP_NR_BD_ADDR_OFF 0
+#define HCI_IO_CAP_NR_ERR_CODE 6
+
+ /* Read Local OOB Data */
+HCI_API extern BOOLEAN btsnd_hcic_read_local_oob_data (void);
+
+#define HCIC_PARAM_SIZE_R_LOCAL_OOB 0
+
+
+HCI_API extern BOOLEAN btsnd_hcic_user_conf_reply (BD_ADDR bd_addr, BOOLEAN is_yes);
+
+#define HCIC_PARAM_SIZE_UCONF_REPLY 6
+
+#define HCI_USER_CONF_BD_ADDR_OFF 0
+
+
+HCI_API extern BOOLEAN btsnd_hcic_user_passkey_reply (BD_ADDR bd_addr, UINT32 value);
+
+#define HCIC_PARAM_SIZE_U_PKEY_REPLY 10
+
+#define HCI_USER_PASSKEY_BD_ADDR_OFF 0
+#define HCI_USER_PASSKEY_VALUE_OFF 6
+
+
+HCI_API extern BOOLEAN btsnd_hcic_user_passkey_neg_reply (BD_ADDR bd_addr);
+
+#define HCIC_PARAM_SIZE_U_PKEY_NEG_REPLY 6
+
+#define HCI_USER_PASSKEY_NEG_BD_ADDR_OFF 0
+
+ /* Remote OOB Data Request Reply */
+HCI_API extern BOOLEAN btsnd_hcic_rem_oob_reply (BD_ADDR bd_addr, UINT8 *p_c,
+ UINT8 *p_r);
+
+#define HCIC_PARAM_SIZE_REM_OOB_REPLY 38
+
+#define HCI_REM_OOB_DATA_BD_ADDR_OFF 0
+#define HCI_REM_OOB_DATA_C_OFF 6
+#define HCI_REM_OOB_DATA_R_OFF 22
+
+ /* Remote OOB Data Request Negative Reply */
+HCI_API extern BOOLEAN btsnd_hcic_rem_oob_neg_reply (BD_ADDR bd_addr);
+
+#define HCIC_PARAM_SIZE_REM_OOB_NEG_REPLY 6
+
+#define HCI_REM_OOB_DATA_NEG_BD_ADDR_OFF 0
+
+ /* Read Tx Power Level */
+HCI_API extern BOOLEAN btsnd_hcic_read_inq_tx_power (void);
+
+#define HCIC_PARAM_SIZE_R_TX_POWER 0
+
+ /* Write Tx Power Level */
+HCI_API extern BOOLEAN btsnd_hcic_write_inq_tx_power (INT8 level);
+
+#define HCIC_PARAM_SIZE_W_TX_POWER 1
+
+#define HCIC_WRITE_TX_POWER_LEVEL_OFF 0
+ /* Read Default Erroneous Data Reporting */
+HCI_API extern BOOLEAN btsnd_hcic_read_default_erroneous_data_rpt (void);
+
+#define HCIC_PARAM_SIZE_R_ERR_DATA_RPT 0
+
+ /* Write Default Erroneous Data Reporting */
+HCI_API extern BOOLEAN btsnd_hcic_write_default_erroneous_data_rpt (UINT8 level);
+
+#define HCIC_PARAM_SIZE_W_ERR_DATA_RPT 1
+
+#define HCIC_WRITE_ERR_DATA_RPT_OFF 0
+
+
+#if L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE
+HCI_API extern BOOLEAN btsnd_hcic_enhanced_flush (UINT16 handle, UINT8 packet_type);
+
+#define HCIC_PARAM_SIZE_ENHANCED_FLUSH 3
+#endif
+
+
+HCI_API extern BOOLEAN btsnd_hcic_send_keypress_notif (BD_ADDR bd_addr, UINT8 notif);
+
+#define HCIC_PARAM_SIZE_SEND_KEYPRESS_NOTIF 7
+
+#define HCI_SEND_KEYPRESS_NOTIF_BD_ADDR_OFF 0
+#define HCI_SEND_KEYPRESS_NOTIF_NOTIF_OFF 6
+
+
+HCI_API extern BOOLEAN btsnd_hcic_refresh_encryption_key(UINT16 handle); /* Refresh Encryption Key */
+
+/**** end of Simple Pairing Commands ****/
+
+
+HCI_API extern BOOLEAN btsnd_hcic_set_event_mask(UINT8 local_controller_id, BT_EVENT_MASK evt_mask);
+
+#define HCIC_PARAM_SIZE_SET_EVENT_MASK 8
+#define HCI_EVENT_MASK_MASK_OFF 0
+ /* Set Event Mask */
+
+ /* Reset */
+HCI_API extern BOOLEAN btsnd_hcic_set_event_mask_page_2 (UINT8 local_controller_id,
+ BT_EVENT_MASK event_mask);
+
+#define HCIC_PARAM_SIZE_SET_EVENT_MASK_PAGE_2 8
+#define HCI_EVENT_MASK_MASK_OFF 0
+ /* Set Event Mask Page 2 */
+
+ /* Reset */
+HCI_API extern BOOLEAN btsnd_hcic_reset(UINT8 local_controller_id);
+
+#define HCIC_PARAM_SIZE_RESET 0
+ /* Reset */
+
+ /* Store Current Settings */
+#define MAX_FILT_COND (sizeof (BD_ADDR) + 1)
+
+HCI_API extern BOOLEAN btsnd_hcic_set_event_filter(UINT8 filt_type,
+ UINT8 filt_cond_type,
+ UINT8 *filt_cond,
+ UINT8 filt_cond_len);
+
+#define HCIC_PARAM_SIZE_SET_EVT_FILTER 9
+
+#define HCI_FILT_COND_FILT_TYPE_OFF 0
+#define HCI_FILT_COND_COND_TYPE_OFF 1
+#define HCI_FILT_COND_FILT_OFF 2
+ /* Set Event Filter */
+
+HCI_API extern BOOLEAN btsnd_hcic_flush(UINT8 local_controller_id, UINT16 handle); /* Flush */
+
+ /* Create New Unit Type */
+HCI_API extern BOOLEAN btsnd_hcic_new_unit_key(void);
+
+#define HCIC_PARAM_SIZE_NEW_UNIT_KEY 0
+ /* Create New Unit Type */
+
+ /* Read Stored Key */
+HCI_API extern BOOLEAN btsnd_hcic_read_stored_key (BD_ADDR bd_addr,
+ BOOLEAN read_all_flag);
+
+#define HCIC_PARAM_SIZE_READ_STORED_KEY 7
+
+#define HCI_READ_KEY_BD_ADDR_OFF 0
+#define HCI_READ_KEY_ALL_FLAG_OFF 6
+ /* Read Stored Key */
+
+#define MAX_WRITE_KEYS 10
+ /* Write Stored Key */
+HCI_API extern BOOLEAN btsnd_hcic_write_stored_key (UINT8 num_keys, BD_ADDR *bd_addr,
+ LINK_KEY *link_key);
+
+#define HCIC_PARAM_SIZE_WRITE_STORED_KEY sizeof(btmsg_hcic_write_stored_key_t)
+
+#define HCI_WRITE_KEY_NUM_KEYS_OFF 0
+#define HCI_WRITE_KEY_BD_ADDR_OFF 1
+#define HCI_WRITE_KEY_KEY_OFF 7
+/* only 0x0b keys cab be sent in one HCI command */
+#define HCI_MAX_NUM_OF_LINK_KEYS_PER_CMMD 0x0b
+ /* Write Stored Key */
+
+ /* Delete Stored Key */
+HCI_API extern BOOLEAN btsnd_hcic_delete_stored_key (BD_ADDR bd_addr, BOOLEAN delete_all_flag);
+
+#define HCIC_PARAM_SIZE_DELETE_STORED_KEY 7
+
+#define HCI_DELETE_KEY_BD_ADDR_OFF 0
+#define HCI_DELETE_KEY_ALL_FLAG_OFF 6
+ /* Delete Stored Key */
+
+ /* Change Local Name */
+HCI_API extern BOOLEAN btsnd_hcic_change_name(BD_NAME name);
+
+#define HCIC_PARAM_SIZE_CHANGE_NAME BD_NAME_LEN
+
+#define HCI_CHANGE_NAME_NAME_OFF 0
+ /* Change Local Name */
+
+
+#define HCIC_PARAM_SIZE_READ_CMD 0
+
+#define HCIC_PARAM_SIZE_WRITE_PARAM1 1
+
+#define HCIC_WRITE_PARAM1_PARAM_OFF 0
+
+#define HCIC_PARAM_SIZE_WRITE_PARAM2 2
+
+#define HCIC_WRITE_PARAM2_PARAM_OFF 0
+
+#define HCIC_PARAM_SIZE_WRITE_PARAM3 3
+
+#define HCIC_WRITE_PARAM3_PARAM_OFF 0
+
+#define HCIC_PARAM_SIZE_SET_AFH_CHANNELS 10
+
+HCI_API extern BOOLEAN btsnd_hcic_read_pin_type(void); /* Read PIN Type */
+HCI_API extern BOOLEAN btsnd_hcic_write_pin_type(UINT8 type); /* Write PIN Type */
+HCI_API extern BOOLEAN btsnd_hcic_read_auto_accept(void); /* Read Auto Accept */
+HCI_API extern BOOLEAN btsnd_hcic_write_auto_accept(UINT8 flag); /* Write Auto Accept */
+HCI_API extern BOOLEAN btsnd_hcic_read_name (void); /* Read Local Name */
+HCI_API extern BOOLEAN btsnd_hcic_read_conn_acc_tout(UINT8 local_controller_id); /* Read Connection Accept Timout */
+HCI_API extern BOOLEAN btsnd_hcic_write_conn_acc_tout(UINT8 local_controller_id, UINT16 tout); /* Write Connection Accept Timout */
+HCI_API extern BOOLEAN btsnd_hcic_read_page_tout(void); /* Read Page Timout */
+HCI_API extern BOOLEAN btsnd_hcic_write_page_tout(UINT16 timeout); /* Write Page Timout */
+HCI_API extern BOOLEAN btsnd_hcic_read_scan_enable(void); /* Read Scan Enable */
+HCI_API extern BOOLEAN btsnd_hcic_write_scan_enable(UINT8 flag); /* Write Scan Enable */
+HCI_API extern BOOLEAN btsnd_hcic_read_pagescan_cfg(void); /* Read Page Scan Activity */
+
+HCI_API extern BOOLEAN btsnd_hcic_write_pagescan_cfg(UINT16 interval,
+ UINT16 window); /* Write Page Scan Activity */
+
+#define HCIC_PARAM_SIZE_WRITE_PAGESCAN_CFG 4
+
+#define HCI_SCAN_CFG_INTERVAL_OFF 0
+#define HCI_SCAN_CFG_WINDOW_OFF 2
+ /* Write Page Scan Activity */
+
+HCI_API extern BOOLEAN btsnd_hcic_read_inqscan_cfg(void); /* Read Inquiry Scan Activity */
+
+ /* Write Inquiry Scan Activity */
+HCI_API extern BOOLEAN btsnd_hcic_write_inqscan_cfg(UINT16 interval, UINT16 window);
+
+#define HCIC_PARAM_SIZE_WRITE_INQSCAN_CFG 4
+
+#define HCI_SCAN_CFG_INTERVAL_OFF 0
+#define HCI_SCAN_CFG_WINDOW_OFF 2
+ /* Write Inquiry Scan Activity */
+
+HCI_API extern BOOLEAN btsnd_hcic_read_auth_enable(void); /* Read Authentication Enable */
+HCI_API extern BOOLEAN btsnd_hcic_write_auth_enable(UINT8 flag); /* Write Authentication Enable */
+HCI_API extern BOOLEAN btsnd_hcic_read_encr_mode (void); /* Read encryption mode */
+HCI_API extern BOOLEAN btsnd_hcic_write_encr_mode (UINT8 mode); /* Write encryption mode */
+HCI_API extern BOOLEAN btsnd_hcic_read_dev_class(void); /* Read Class of Device */
+HCI_API extern BOOLEAN btsnd_hcic_write_dev_class(DEV_CLASS dev); /* Write Class of Device */
+HCI_API extern BOOLEAN btsnd_hcic_read_voice_settings(void); /* Read Voice Settings */
+HCI_API extern BOOLEAN btsnd_hcic_write_voice_settings(UINT16 flags); /* Write Voice Settings */
+
+/* Host Controller to Host flow control */
+#define HCI_HOST_FLOW_CTRL_OFF 0
+#define HCI_HOST_FLOW_CTRL_ACL_ON 1
+#define HCI_HOST_FLOW_CTRL_SCO_ON 2
+#define HCI_HOST_FLOW_CTRL_BOTH_ON 3
+
+HCI_API extern BOOLEAN btsnd_hcic_set_host_flow_ctrl (UINT8 value); /* Enable/disable flow control toward host */
+
+
+HCI_API extern BOOLEAN btsnd_hcic_read_auto_flush_tout(UINT16 handle); /* Read Retransmit Timout */
+
+HCI_API extern BOOLEAN btsnd_hcic_write_auto_flush_tout(UINT16 handle,
+ UINT16 timeout); /* Write Retransmit Timout */
+
+#define HCIC_PARAM_SIZE_WRITE_AUTO_FLUSH_TOUT 4
+
+#define HCI_FLUSH_TOUT_HANDLE_OFF 0
+#define HCI_FLUSH_TOUT_TOUT_OFF 2
+
+HCI_API extern BOOLEAN btsnd_hcic_read_num_bcast_xmit(void); /* Read Num Broadcast Retransmits */
+HCI_API extern BOOLEAN btsnd_hcic_write_num_bcast_xmit(UINT8 num); /* Write Num Broadcast Retransmits */
+HCI_API extern BOOLEAN btsnd_hcic_read_hold_mode_act(void); /* Read Hold Mode Activity */
+HCI_API extern BOOLEAN btsnd_hcic_write_hold_mode_act(UINT8 flags); /* Write Hold Mode Activity */
+
+HCI_API extern BOOLEAN btsnd_hcic_read_tx_power(UINT16 handle, UINT8 type); /* Read Tx Power */
+
+#define HCIC_PARAM_SIZE_READ_TX_POWER 3
+
+#define HCI_READ_TX_POWER_HANDLE_OFF 0
+#define HCI_READ_TX_POWER_TYPE_OFF 2
+
+/* Read transmit power level parameter */
+#define HCI_READ_CURRENT 0x00
+#define HCI_READ_MAXIMUM 0x01
+
+HCI_API extern BOOLEAN btsnd_hcic_read_sco_flow_enable(void); /* Read Authentication Enable */
+HCI_API extern BOOLEAN btsnd_hcic_write_sco_flow_enable(UINT8 flag); /* Write Authentication Enable */
+
+ /* Set Host Buffer Size */
+HCI_API extern BOOLEAN btsnd_hcic_set_host_buf_size (UINT16 acl_len,
+ UINT8 sco_len,
+ UINT16 acl_num,
+ UINT16 sco_num);
+
+#define HCIC_PARAM_SIZE_SET_HOST_BUF_SIZE 7
+
+#define HCI_HOST_BUF_SIZE_ACL_LEN_OFF 0
+#define HCI_HOST_BUF_SIZE_SCO_LEN_OFF 2
+#define HCI_HOST_BUF_SIZE_ACL_NUM_OFF 3
+#define HCI_HOST_BUF_SIZE_SCO_NUM_OFF 5
+
+
+HCI_API extern BOOLEAN btsnd_hcic_host_num_xmitted_pkts (UINT8 num_handles,
+ UINT16 *handle,
+ UINT16 *num_pkts); /* Set Host Buffer Size */
+
+#define HCIC_PARAM_SIZE_NUM_PKTS_DONE_SIZE sizeof(btmsg_hcic_num_pkts_done_t)
+
+#define MAX_DATA_HANDLES 10
+
+#define HCI_PKTS_DONE_NUM_HANDLES_OFF 0
+#define HCI_PKTS_DONE_HANDLE_OFF 1
+#define HCI_PKTS_DONE_NUM_PKTS_OFF 3
+
+HCI_API extern BOOLEAN btsnd_hcic_read_link_super_tout(UINT8 local_controller_id, UINT16 handle); /* Read Link Supervision Timeout */
+
+ /* Write Link Supervision Timeout */
+HCI_API extern BOOLEAN btsnd_hcic_write_link_super_tout(UINT8 local_controller_id, UINT16 handle, UINT16 timeout);
+
+#define HCIC_PARAM_SIZE_WRITE_LINK_SUPER_TOUT 4
+
+#define HCI_LINK_SUPER_TOUT_HANDLE_OFF 0
+#define HCI_LINK_SUPER_TOUT_TOUT_OFF 2
+ /* Write Link Supervision Timeout */
+
+HCI_API extern BOOLEAN btsnd_hcic_read_max_iac (void); /* Read Num Supported IAC */
+HCI_API extern BOOLEAN btsnd_hcic_read_cur_iac_lap (void); /* Read Current IAC LAP */
+
+HCI_API extern BOOLEAN btsnd_hcic_write_cur_iac_lap (UINT8 num_cur_iac,
+ LAP * const iac_lap); /* Write Current IAC LAP */
+
+#define MAX_IAC_LAPS 0x40
+
+#define HCI_WRITE_IAC_LAP_NUM_OFF 0
+#define HCI_WRITE_IAC_LAP_LAP_OFF 1
+ /* Write Current IAC LAP */
+
+ /* Read Clock */
+HCI_API extern BOOLEAN btsnd_hcic_read_clock (UINT16 handle, UINT8 which_clock);
+
+#define HCIC_PARAM_SIZE_READ_CLOCK 3
+
+#define HCI_READ_CLOCK_HANDLE_OFF 0
+#define HCI_READ_CLOCK_WHICH_CLOCK 2
+ /* Read Clock */
+
+#ifdef TESTER_ENABLE
+
+#define HCIC_PARAM_SIZE_ENTER_TEST_MODE 2
+
+#define HCI_ENTER_TEST_HANDLE_OFF 0
+
+#define HCIC_PARAM_SIZE_TEST_CNTRL 10
+#define HCI_TEST_CNTRL_HANDLE_OFF 0
+#define HCI_TEST_CNTRL_SCENARIO_OFF 2
+#define HCI_TEST_CNTRL_HOPPINGMODE_OFF 3
+#define HCI_TEST_CNTRL_TX_FREQ_OFF 4
+#define HCI_TEST_CNTRL_RX_FREQ_OFF 5
+#define HCI_TEST_CNTRL_PWR_CNTRL_MODE_OFF 6
+#define HCI_TEST_CNTRL_POLL_PERIOD_OFF 7
+#define HCI_TEST_CNTRL_PKT_TYPE_OFF 8
+#define HCI_TEST_CNTRL_LENGTH_OFF 9
+
+#endif
+
+HCI_API extern BOOLEAN btsnd_hcic_read_page_scan_per (void); /* Read Page Scan Period Mode */
+HCI_API extern BOOLEAN btsnd_hcic_write_page_scan_per (UINT8 mode); /* Write Page Scan Period Mode */
+HCI_API extern BOOLEAN btsnd_hcic_read_page_scan_mode (void); /* Read Page Scan Mode */
+HCI_API extern BOOLEAN btsnd_hcic_write_page_scan_mode (UINT8 mode); /* Write Page Scan Mode */
+HCI_API extern BOOLEAN btsnd_hcic_read_local_ver (UINT8 local_controller_id); /* Read Local Version Info */
+HCI_API extern BOOLEAN btsnd_hcic_read_local_supported_cmds (UINT8 local_controller_id); /* Read Local Supported Commands */
+HCI_API extern BOOLEAN btsnd_hcic_read_local_features (void); /* Read Local Supported Features */
+HCI_API extern BOOLEAN btsnd_hcic_read_buffer_size (void); /* Read Local buffer sizes */
+HCI_API extern BOOLEAN btsnd_hcic_read_country_code (void); /* Read Country Code */
+HCI_API extern BOOLEAN btsnd_hcic_read_bd_addr (void); /* Read Local BD_ADDR */
+HCI_API extern BOOLEAN btsnd_hcic_read_fail_contact_count (UINT8 local_controller_id, UINT16 handle); /* Read Failed Contact Counter */
+HCI_API extern BOOLEAN btsnd_hcic_reset_fail_contact_count (UINT8 local_controller_id, UINT16 handle);/* Reset Failed Contact Counter */
+HCI_API extern BOOLEAN btsnd_hcic_get_link_quality (UINT16 handle); /* Get Link Quality */
+HCI_API extern BOOLEAN btsnd_hcic_read_rssi (UINT16 handle); /* Read RSSI */
+HCI_API extern BOOLEAN btsnd_hcic_read_loopback_mode (void); /* Read Loopback Mode */
+HCI_API extern BOOLEAN btsnd_hcic_write_loopback_mode (UINT8 mode); /* Write Loopback Mode */
+HCI_API extern BOOLEAN btsnd_hcic_enable_test_mode (void); /* Enable Device Under Test Mode */
+HCI_API extern BOOLEAN btsnd_hcic_write_pagescan_type(UINT8 type); /* Write Page Scan Type */
+HCI_API extern BOOLEAN btsnd_hcic_read_pagescan_type(void); /* Read Page Scan Type */
+HCI_API extern BOOLEAN btsnd_hcic_write_inqscan_type(UINT8 type); /* Write Inquiry Scan Type */
+HCI_API extern BOOLEAN btsnd_hcic_read_inqscan_type(void); /* Read Inquiry Scan Type */
+HCI_API extern BOOLEAN btsnd_hcic_write_inquiry_mode(UINT8 type); /* Write Inquiry Mode */
+HCI_API extern BOOLEAN btsnd_hcic_read_inquiry_mode(void); /* Read Inquiry Mode */
+HCI_API extern BOOLEAN btsnd_hcic_set_afh_channels (UINT8 first, UINT8 last);
+HCI_API extern BOOLEAN btsnd_hcic_write_afh_channel_assessment_mode (UINT8 mode);
+HCI_API extern BOOLEAN btsnd_hcic_set_afh_host_channel_class (UINT8 *p_afhchannelmap);
+HCI_API extern BOOLEAN btsnd_hcic_read_afh_channel_assessment_mode(void);
+HCI_API extern BOOLEAN btsnd_hcic_read_afh_channel_map (UINT16 handle);
+HCI_API extern BOOLEAN btsnd_hcic_nop(void); /* NOP */
+
+ /* Send HCI Data */
+HCI_API extern void btsnd_hcic_data (BT_HDR *p_buf, UINT16 len, UINT16 handle, UINT8 boundary, UINT8 broadcast);
+
+#define HCI_DATA_HANDLE_MASK 0x0FFF
+
+#define HCID_GET_HANDLE_EVENT(p) (UINT16)((*((UINT8 *)((p) + 1) + p->offset) + \
+ (*((UINT8 *)((p) + 1) + p->offset + 1) << 8)))
+
+#define HCID_GET_HANDLE(u16) (UINT16)((u16) & HCI_DATA_HANDLE_MASK)
+
+#define HCI_DATA_EVENT_MASK 3
+#define HCI_DATA_EVENT_OFFSET 12
+#define HCID_GET_EVENT(u16) (UINT8)(((u16) >> HCI_DATA_EVENT_OFFSET) & HCI_DATA_EVENT_MASK)
+
+#define HCI_DATA_BCAST_MASK 3
+#define HCI_DATA_BCAST_OFFSET 10
+#define HCID_GET_BCAST(u16) (UINT8)(((u16) >> HCI_DATA_BCAST_OFFSET) & HCI_DATA_BCAST_MASK)
+
+#define HCID_GET_ACL_LEN(p) (UINT16)((*((UINT8 *)((p) + 1) + p->offset + 2) + \
+ (*((UINT8 *)((p) + 1) + p->offset + 3) << 8)))
+
+#define HCID_HEADER_SIZE 4
+ /* Send HCI Data */
+
+#define HCID_GET_SCO_LEN(p) (*((UINT8 *)((p) + 1) + p->offset + 2))
+
+HCI_API extern void btsnd_hcic_vendor_spec_cmd (
+ void *buffer, UINT16 opcode,
+ UINT8 len, UINT8 *p_data,
+ void *p_cmd_cplt_cback);
+
+
+/*********************************************************************************
+** **
+** H C I E V E N T S **
+** **
+*********************************************************************************/
+
+/* Inquiry Complete Event */
+HCI_API extern void btsnd_hcie_inq_comp(void *buffer, UINT8 status);
+
+#define HCIE_PARAM_SIZE_INQ_COMP 1
+
+/* Inquiry Response Event */
+HCI_API extern void btsnd_hcie_inq_res(void *buffer, UINT8 num_resp, UINT8 **bd_addr,
+ UINT8 *page_scan_rep_mode, UINT8 *page_scan_per_mode,
+ UINT8 *page_scan_mode, UINT8 **dev_class,
+ UINT16 *clock_offset);
+
+/* Connection Complete Event */
+HCI_API extern void btsnd_hcie_connection_comp(void *buffer, UINT8 status, UINT16 handle,
+ BD_ADDR bd_addr, UINT8 link_type, UINT8 encr_mode);
+
+#define HCIE_PARAM_SIZE_CONNECTION_COMP 11
+
+
+#define HCI_LINK_TYPE_SCO 0x00
+#define HCI_LINK_TYPE_ACL 0x01
+
+#define HCI_ENCRYPT_MODE_DISABLED 0x00
+#define HCI_ENCRYPT_MODE_POINT_TO_POINT 0x01
+#define HCI_ENCRYPT_MODE_ALL 0x02
+
+
+/* Connection Request Event */
+HCI_API extern void btsnd_hcie_connection_req(void *buffer, BD_ADDR bd_addr, DEV_CLASS dev_class, UINT8 link_type);
+
+#define HCIE_PARAM_SIZE_CONNECTION_REQ 10
+
+#define HCI_LINK_TYPE_SCO 0x00
+#define HCI_LINK_TYPE_ACL 0x01
+
+
+/* Disonnection Complete Event */
+HCI_API extern void btsnd_hcie_disc_comp(void *buffer, UINT8 status, UINT16 handle, UINT8 reason);
+
+#define HCIE_PARAM_SIZE_DISC_COMP 4
+
+
+/* Authentication Complete Event */
+HCI_API extern void btsnd_hcie_auth_comp (void *buffer, UINT8 status, UINT16 handle);
+
+#define HCIE_PARAM_SIZE_AUTH_COMP 3
+
+
+/* Remote Name Request Complete Event */
+HCI_API extern void btsnd_hcie_rmt_name_req_comp(void *buffer, UINT8 status, BD_ADDR bd_addr, BD_NAME name);
+
+#define HCIE_PARAM_SIZE_RMT_NAME_REQ_COMP (1 + BD_ADDR_LEN + BD_NAME_LEN)
+
+
+/* Encryption Change Event */
+HCI_API extern void btsnd_hcie_encryption_change (void *buffer, UINT8 status, UINT16 handle, BOOLEAN enable);
+
+#define HCIE_PARAM_SIZE_ENCR_CHANGE 4
+
+
+/* Connection Link Key Change Event */
+HCI_API extern void btsnd_hcie_conn_link_key_change (void *buffer, UINT8 status, UINT16 handle);
+
+#define HCIE_PARAM_SIZE_LINK_KEY_CHANGE 3
+
+
+/* Encryption Key Refresh Complete Event */
+HCI_API extern void btsnd_hcie_encrypt_key_refresh (void *buffer, UINT8 status, UINT16 handle);
+
+#define HCIE_PARAM_SIZE_ENCRYPT_KEY_REFRESH 3
+
+
+/* Master Link Key Complete Event */
+HCI_API extern void btsnd_hcie_master_link_key (void *buffer, UINT8 status, UINT16 handle, UINT8 flag);
+
+#define HCIE_PARAM_SIZE_MASTER_LINK_KEY 4
+
+
+/* Read Remote Supported Features Complete Event */
+HCI_API extern void btsnd_hcie_read_rmt_features (void *buffer, UINT8 status, UINT16 handle, UINT8 *features);
+
+#define LMP_FEATURES_SIZE 8
+#define HCIE_PARAM_SIZE_READ_RMT_FEATURES 11
+
+
+/* Read Remote Extended Features Complete Event */
+HCI_API extern void btsnd_hcie_read_rmt_ext_features (void *buffer, UINT8 status, UINT16 handle, UINT8 page_num,
+ UINT8 max_page_num, UINT8 *features);
+
+#define EXT_LMP_FEATURES_SIZE 8
+#define HCIE_PARAM_SIZE_READ_RMT_EXT_FEATURES 13
+
+
+/* Read Remote Version Complete Event */
+HCI_API extern void btsnd_hcie_read_rmt_version (void *buffer, UINT8 status, UINT16 handle, UINT8 version,
+ UINT16 comp_name, UINT16 sub_version);
+
+#define HCIE_PARAM_SIZE_READ_RMT_VERSION 8
+
+
+/* QOS setup complete */
+HCI_API extern void btsnd_hcie_qos_setup_compl (void *buffer, UINT8 status, UINT16 handle, UINT8 flags,
+ UINT8 service_type, UINT32 token_rate, UINT32 peak,
+ UINT32 latency, UINT32 delay_var);
+
+#define HCIE_PARAM_SIZE_QOS_SETUP_COMP 21
+
+
+/* Flow Specification complete */
+HCI_API extern void btsnd_hcie_flow_spec_compl (void *buffer, UINT8 status, UINT16 handle, UINT8 flags,
+ UINT8 flow_direction, UINT8 service_type, UINT32 token_rate, UINT32 token_bucket_size,
+ UINT32 peak, UINT32 latency);
+
+#define HCIE_PARAM_SIZE_FLOW_SPEC_COMP 22
+
+
+/* Command Complete Event */
+HCI_API extern void btsnd_hcie_cmd_comp(void *buffer, UINT8 max_host_cmds, UINT16 opcode, UINT8 status);
+
+#define HCIE_PARAM_SIZE_CMD_COMP 4
+
+
+/* Command Complete with pre-filled in parameters */
+HCI_API extern void btsnd_hcie_cmd_comp_params (void *buffer, UINT8 max_host_cmds, UINT16 cmd_opcode, UINT8 status);
+
+#define HCI_CMD_COMPL_PARAM_OFFSET 4
+
+
+/* Command Complete Event with 1-byte param */
+HCI_API extern void btsnd_hcie_cmd_comp_param1(void *buffer, UINT8 max_host_cmds, UINT16 opcode,
+ UINT8 status, UINT8 param1);
+
+#define HCIE_PARAM_SIZE_CMD_COMP_PARAM1 5
+
+/* Command Complete Event with 2-byte param */
+HCI_API extern void btsnd_hcie_cmd_comp_param2(void *buffer, UINT8 max_host_cmds, UINT16 opcode,
+ UINT8 status, UINT16 param2);
+
+#define HCIE_PARAM_SIZE_CMD_COMP_PARAM2 6
+
+
+/* Command Complete Event with BD-addr as param */
+HCI_API extern void btsnd_hcie_cmd_comp_bd_addr(void *buffer, UINT8 max_host_cmds, UINT16 opcode,
+ UINT8 status, BD_ADDR bd_addr);
+
+#define HCIE_PARAM_SIZE_CMD_COMP_BD_ADDR 10
+
+
+/* Command Pending Event */
+HCI_API extern void btsnd_hcie_cmd_status (void *buffer, UINT8 status, UINT8 max_host_cmds, UINT16 opcode);
+
+#define HCIE_PARAM_SIZE_CMD_STATUS 4
+
+
+/* HW failure Event */
+HCI_API extern void btsnd_hcie_hw_failure (void *buffer, UINT8 code);
+
+#define HCIE_PARAM_SIZE_HW_FAILURE 1
+
+
+/* Flush Occured Event */
+HCI_API extern void btsnd_hcie_flush_occured (void *buffer, UINT16 handle);
+
+#define HCIE_PARAM_SIZE_FLUSH_OCCURED 2
+
+
+/* Role Changed Event */
+HCI_API extern void btsnd_hcie_role_change (void *buffer, UINT8 status, BD_ADDR bd_addr, UINT8 role);
+
+#define HCIE_PARAM_SIZE_ROLE_CHANGE 8
+
+
+/* Ready for Data Packets Event */
+HCI_API extern void btsnd_hcie_num_compl_pkts (void *buffer, UINT8 num_handles, UINT16 *p_handle, UINT16 *num_pkts);
+
+#define MAX_DATA_HANDLES 10
+
+
+/* Mode Change Event */
+HCI_API extern void btsnd_hcie_mode_change (void *buffer, UINT8 status, UINT16 handle,
+ UINT8 mode, UINT16 interval);
+
+#define HCIE_PARAM_SIZE_MODE_CHANGE 6
+#define MAX_DATA_HANDLES 10
+
+
+
+/* Return Link Keys Event */
+HCI_API extern void btsnd_hcie_return_link_keys (void *buffer, UINT8 num_keys, BD_ADDR *bd_addr, LINK_KEY *link_key);
+
+/* This should not be more than 0x0b */
+#define MAX_LINK_KEYS 10
+
+
+
+/* PIN Code Request Event */
+HCI_API extern void btsnd_hcie_pin_code_req (void *buffer, BD_ADDR bd_addr);
+
+#define HCIE_PARAM_SIZE_PIN_CODE_REQ 6
+
+
+
+/* Link Key Request Event */
+HCI_API extern void btsnd_hcie_link_key_req (void *buffer, BD_ADDR bd_addr);
+
+#define HCIE_PARAM_SIZE_LINK_KEY_REQ 6
+
+
+
+/* Link Key Notification Event */
+HCI_API extern void btsnd_hcie_link_key_notify (void *buffer, BD_ADDR bd_addr, LINK_KEY link_key, UINT8 key_type);
+
+#define HCIE_PARAM_SIZE_LINK_KEY_NOTIFY 23
+
+
+
+/* Loopback Command Event */
+HCI_API extern void btsnd_hcie_loopback_command (void *buffer, UINT8 data_len, UINT8 *data);
+
+#define HCIE_PARAM_SIZE_LOOPBACK_COMMAND sizeof(btmsg_hcie_loopback_cmd_t)
+
+
+
+/* Data Buffer Overflow Event */
+HCI_API extern void btsnd_hcie_data_buf_overflow (void *buffer, UINT8 link_type);
+
+#define HCIE_PARAM_SIZE_DATA_BUF_OVERFLOW 1
+
+
+
+/* Max Slots Change Event */
+HCI_API extern void btsnd_hcie_max_slots_change(void *buffer, UINT16 handle, UINT8 max_slots);
+
+#define HCIE_PARAM_SIZE_MAX_SLOTS_CHANGE 3
+
+
+/* Read Clock Offset Complet Event */
+HCI_API extern void btsnd_hcie_read_clock_off_comp(void *buffer, UINT8 status, UINT16 handle,
+ UINT16 clock_offset);
+
+#define HCIE_PARAM_SIZE_READ_CLOCK_OFF_COMP 5
+
+
+
+/* Connection Packet Type Change Event */
+HCI_API extern void btsnd_hcie_pkt_type_change (void *buffer, UINT8 status, UINT16 handle, UINT16 pkt_type);
+
+#define HCIE_PARAM_SIZE_PKT_TYPE_CHANGE 5
+
+
+
+/* QOS violation Event */
+HCI_API extern void btsnd_hcie_qos_violation (void *buffer, UINT16 handle);
+
+#define HCIE_PARAM_SIZE_QOS_VIOLATION 2
+
+
+
+/* Page Scan Mode Change Event */
+HCI_API extern void btsnd_hcie_pagescan_mode_chng (void *buffer, BD_ADDR bd_addr, UINT8 mode);
+
+#define HCIE_PARAM_SIZE_PAGE_SCAN_MODE_CHNG 7
+
+
+/* Page Scan Repetition Mode Change Event */
+HCI_API extern void btsnd_hcie_pagescan_rep_mode_chng (void *buffer, BD_ADDR bd_addr, UINT8 mode);
+
+#define HCIE_PARAM_SIZE_PAGE_SCAN_REP_MODE_CHNG 7
+
+
+/* Sniff Sub Rate Event */
+HCI_API extern void btsnd_hcie_sniff_sub_rate(void *buffer, UINT8 status, UINT16 handle, UINT16 max_tx_lat, UINT16 max_rx_lat,
+ UINT16 min_remote_timeout, UINT16 min_local_timeout);
+
+#define HCIE_PARAM_SIZE_SNIFF_SUB_RATE 11
+
+
+
+/* Extended Inquiry Result Event */
+HCI_API extern void btsnd_hcie_ext_inquiry_result(void *buffer, UINT8 num_resp, UINT8 **bd_addr,
+ UINT8 *page_scan_rep_mode, UINT8 *reserved,
+ UINT8 **dev_class, UINT16 *clock_offset, UINT8 *rssi, UINT8 *p_data);
+
+
+#if (BLE_INCLUDED == TRUE)
+/********************************************************************************
+** BLE Commands
+** Note: "local_controller_id" is for transport, not counted in HCI message size
+*********************************************************************************/
+#define HCIC_PARAM_SIZE_SET_USED_FEAT_CMD 8
+#define HCIC_PARAM_SIZE_WRITE_RANDOM_ADDR_CMD 6
+#define HCIC_PARAM_SIZE_BLE_WRITE_ADV_PARAMS 15
+#define HCIC_PARAM_SIZE_BLE_WRITE_SCAN_RSP 31
+#define HCIC_PARAM_SIZE_WRITE_ADV_ENABLE 1
+#define HCIC_PARAM_SIZE_BLE_WRITE_SCAN_PARAM 7
+#define HCIC_PARAM_SIZE_BLE_WRITE_SCAN_ENABLE 2
+#define HCIC_PARAM_SIZE_BLE_CREATE_LL_CONN 25
+#define HCIC_PARAM_SIZE_BLE_CREATE_CONN_CANCEL 0
+#define HCIC_PARAM_SIZE_CLEAR_WHITE_LIST 0
+#define HCIC_PARAM_SIZE_ADD_WHITE_LIST 7
+#define HCIC_PARAM_SIZE_REMOVE_WHITE_LIST 7
+#define HCIC_PARAM_SIZE_BLE_UPD_LL_CONN_PARAMS 14
+#define HCIC_PARAM_SIZE_SET_HOST_CHNL_CLASS 5
+#define HCIC_PARAM_SIZE_READ_CHNL_MAP 2
+#define HCIC_PARAM_SIZE_BLE_READ_REMOTE_FEAT 2
+#define HCIC_PARAM_SIZE_BLE_ENCRYPT 32
+#define HCIC_PARAM_SIZE_BLE_RAND 0
+
+#define HCIC_BLE_RAND_DI_SIZE 8
+#define HCIC_BLE_ENCRYT_KEY_SIZE 16
+#define HCIC_PARAM_SIZE_BLE_START_ENC (4 + HCIC_BLE_RAND_DI_SIZE + HCIC_BLE_ENCRYT_KEY_SIZE)
+#define HCIC_PARAM_SIZE_LTK_REQ_REPLY (2 + HCIC_BLE_ENCRYT_KEY_SIZE)
+#define HCIC_PARAM_SIZE_LTK_REQ_NEG_REPLY 2
+#define HCIC_BLE_CHNL_MAP_SIZE 5
+#define HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA 31
+
+/* ULP HCI command */
+HCI_API extern BOOLEAN btsnd_hcic_ble_reset(void);
+
+HCI_API extern BOOLEAN btsnd_hcic_ble_set_evt_mask (BT_EVENT_MASK event_mask);
+
+HCI_API extern BOOLEAN btsnd_hcic_ble_read_buffer_size (void);
+
+HCI_API extern BOOLEAN btsnd_hcic_ble_read_local_spt_feat (void);
+
+HCI_API extern BOOLEAN btsnd_hcic_ble_set_local_used_feat (UINT8 feat_set[8]);
+
+HCI_API extern BOOLEAN btsnd_hcic_ble_set_random_addr (BD_ADDR random_addr);
+
+HCI_API extern BOOLEAN btsnd_hcic_ble_write_adv_params (UINT16 adv_int_min, UINT16 adv_int_max,
+ UINT8 adv_type, UINT8 addr_type_own,
+ UINT8 addr_type_dir, BD_ADDR direct_bda,
+ UINT8 channel_map, UINT8 adv_filter_policy);
+
+HCI_API extern BOOLEAN btsnd_hcic_ble_read_adv_chnl_tx_power (void);
+
+HCI_API extern BOOLEAN btsnd_hcic_ble_set_adv_data (UINT8 data_len, UINT8 *p_data);
+
+HCI_API extern BOOLEAN btsnd_hcic_ble_set_scan_rsp_data (UINT8 data_len, UINT8 *p_scan_rsp);
+
+HCI_API extern BOOLEAN btsnd_hcic_ble_set_adv_enable (UINT8 adv_enable);
+
+HCI_API extern BOOLEAN btsnd_hcic_ble_set_scan_params (UINT8 scan_type,
+ UINT16 scan_int, UINT16 scan_win,
+ UINT8 addr_type, UINT8 scan_filter_policy);
+
+HCI_API extern BOOLEAN btsnd_hcic_ble_set_scan_enable (UINT8 scan_enable, UINT8 duplicate);
+
+HCI_API extern BOOLEAN btsnd_hcic_ble_create_ll_conn (UINT16 scan_int, UINT16 scan_win,
+ UINT8 init_filter_policy, UINT8 addr_type_peer, BD_ADDR bda_peer, UINT8 addr_type_own,
+ UINT16 conn_int_min, UINT16 conn_int_max, UINT16 conn_latency, UINT16 conn_timeout,
+ UINT16 min_ce_len, UINT16 max_ce_len);
+
+HCI_API extern BOOLEAN btsnd_hcic_ble_create_conn_cancel (void);
+
+HCI_API extern BOOLEAN btsnd_hcic_ble_read_white_list_size (void);
+
+HCI_API extern BOOLEAN btsnd_hcic_ble_clear_white_list (void);
+
+HCI_API extern BOOLEAN btsnd_hcic_ble_add_white_list (UINT8 addr_type, BD_ADDR bda);
+
+HCI_API extern BOOLEAN btsnd_hcic_ble_remove_from_white_list (UINT8 addr_type, BD_ADDR bda);
+
+HCI_API extern BOOLEAN btsnd_hcic_ble_upd_ll_conn_params (UINT16 handle, UINT16 conn_int_min, UINT16 conn_int_max,
+ UINT16 conn_latency, UINT16 conn_timeout, UINT16 min_len, UINT16 max_len);
+
+HCI_API extern BOOLEAN btsnd_hcic_ble_set_host_chnl_class (UINT8 chnl_map[HCIC_BLE_CHNL_MAP_SIZE]);
+
+HCI_API extern BOOLEAN btsnd_hcic_ble_read_chnl_map (UINT16 handle);
+
+HCI_API extern BOOLEAN btsnd_hcic_ble_read_remote_feat ( UINT16 handle);
+
+HCI_API extern BOOLEAN btsnd_hcic_ble_encrypt (UINT8* key, UINT8 key_len, UINT8* plain_text, UINT8 pt_len, void *p_cmd_cplt_cback);
+
+HCI_API extern BOOLEAN btsnd_hcic_ble_rand (void *p_cmd_cplt_cback);
+
+HCI_API extern BOOLEAN btsnd_hcic_ble_start_enc ( UINT16 handle,
+ UINT8 rand[HCIC_BLE_RAND_DI_SIZE],
+ UINT16 ediv, UINT8 ltk[HCIC_BLE_ENCRYT_KEY_SIZE]);
+
+HCI_API extern BOOLEAN btsnd_hcic_ble_ltk_req_reply (UINT16 handle, UINT8 ltk[HCIC_BLE_ENCRYT_KEY_SIZE]);
+
+HCI_API extern BOOLEAN btsnd_hcic_ble_ltk_req_neg_reply (UINT16 handle);
+
+HCI_API extern BOOLEAN btsnd_hcic_ble_read_supported_states (void);
+
+
+#endif /* BLE_INCLUDED */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/stack/include/hidd_api.h b/stack/include/hidd_api.h
new file mode 100644
index 0000000..180dc3e
--- /dev/null
+++ b/stack/include/hidd_api.h
@@ -0,0 +1,241 @@
+/****************************************************************************
+**
+** Name: hidd_api.h
+**
+** Function: this file contains HID DEVICE side API definitions
+**
+**
+** Copyright (c) 2002-2004, WIDCOMM Inc., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef HIDD_API_H
+#define HIDD_API_H
+
+#include "hiddefs.h"
+
+
+/*****************************************************************************
+** Type Definitions
+*****************************************************************************/
+
+/* Define the structures that the HID Device function should use to register
+** callbacks with HID.
+*/
+
+typedef struct
+{
+ FLOW_SPEC ctrl_ch;
+ FLOW_SPEC int_ch;
+ FLOW_SPEC hci;
+} tHID_DEV_QOS_INFO;
+
+typedef struct rep_data
+{
+ UINT8 rep_type;
+ UINT8 rep_id;
+} tHID_DEV_GET_REP_DATA;
+
+/* HID-Device Callback Events
+*/
+enum
+{
+ HID_DEV_EVT_OPEN, /*Connected to host with Interrupt and Control Data = 1 if Virtual Cable
+ Channels in OPEN state. pdata = Host BD-Addr.*/
+
+ HID_DEV_EVT_CLOSE, /*Connection with host is closed. Data=Reason Code. */
+ HID_DEV_EVT_RETRYING, /*Lost connection is being re-connected. Data=Retrial number */
+ HID_DEV_EVT_MODE_CHG, /*Device changed power mode. Data=new power mode */
+ HID_DEV_EVT_PM_FAILED,
+ HID_DEV_EVT_CONTROL, /*Host sent HID_CONTROL Data=Control Operation */
+ HID_DEV_EVT_GET_REPORT,/*Host sent GET_REPORT Data=Length pdata=structure
+ having details of get-report.*/
+ HID_DEV_EVT_SET_REPORT,/*Host sent SET_REPORT Data=Length pdata=details.*/
+ HID_DEV_EVT_GET_PROTO, /*Host sent GET_PROTOCOL Data=NA*/
+ HID_DEV_EVT_SET_PROTO, /*Host sent SET_PROTOCOL Data=1 for Report, 0 for Boot*/
+ HID_DEV_EVT_GET_IDLE, /*Host sent GET_IDLE Data=NA */
+ HID_DEV_EVT_SET_IDLE, /*Host sent SET_IDLE Data=Idle Rate */
+ HID_DEV_EVT_DATA,
+ HID_DEV_EVT_DATC,
+
+ HID_DEV_EVT_L2CAP_CONGEST /* L2CAP channel congested */
+};
+
+/* Define the possible states of the HID Device power manager.
+*/
+enum
+{
+ HID_DEV_BUSY_CONN_ST,
+ HID_DEV_IDLE_CONN_ST,
+ HID_DEV_SUSP_CONN_ST
+};
+
+typedef union {
+ BD_ADDR host_bdaddr;
+ BT_HDR *buffer;
+ tHID_DEV_GET_REP_DATA get_rep;
+ UINT8 pm_err_code;
+ UINT16 pm_interval;
+} tHID_DEV_CBACK_DATA;
+
+typedef void (tHID_DEV_CALLBACK) (UINT8 event, /* Event from HID-DEVICE. */
+ UINT32 data, /* Integer data corresponding to the event. */
+ tHID_DEV_CBACK_DATA *pdata ); /* Pointer data corresponding to the event.*/
+
+typedef struct
+{
+ BD_ADDR host_addr;/* Host BD-ADDR */
+ tHID_DEV_QOS_INFO *qos_info; /* This info is used only if HID_DEV_USE_GLB_QOS is set to FALSE.*/
+ tHID_DEV_CALLBACK *app_cback;
+} tHID_DEV_REG_INFO;
+
+typedef struct pwr_md
+{
+ UINT16 max;
+ UINT16 min;
+ UINT16 attempt;
+ UINT16 timeout;
+ UINT8 mode;
+} tHID_DEV_PM_PWR_MD;
+
+
+/*****************************************************************************
+** External Function Declarations
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*******************************************************************************
+**
+** Function HID_DevSetSDPRecord
+**
+** Description This function should be called at startup to create the
+** device SDP record
+**
+** Returns 0 if error else sdp handle for the record.
+**
+*******************************************************************************/
+HID_API extern UINT32 HID_DevSetSDPRecord (tHID_DEV_SDP_INFO *p_sdp_info);
+
+/*******************************************************************************
+**
+** Function HID_DevRegister
+**
+** Description This function must be called at startup so the device receive
+** HID related events and call other HID API Calls.
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+HID_API extern tHID_STATUS HID_DevRegister(tHID_DEV_REG_INFO *pHID_DEVRegInfo );
+
+/*******************************************************************************
+**
+** Function HID_DevDeregister
+**
+** Description This function may be used to remove HID service records and
+** deregister from L2CAP.
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+HID_API extern tHID_STATUS HID_DevDeregister(void);
+
+/*******************************************************************************
+**
+** Function HID_DevConnect
+**
+** Description This function may be used to initiate a connection to the host..
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+HID_API extern tHID_STATUS HID_DevConnect(void);
+
+/*******************************************************************************
+**
+** Function HID_DevDisconnect
+**
+** Description This function may be used to disconnect from the host.
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+HID_API extern tHID_STATUS HID_DevDisconnect(void);
+
+/*******************************************************************************
+**
+** Function HID_DevHandShake
+**
+** Description This function may be used to send HAND-SHAKE to host.
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+HID_API extern tHID_STATUS HID_DevHandShake(UINT8 res_code );
+
+/*******************************************************************************
+**
+** Function HID_DevVirtualUnplug
+**
+** Description This function may be used to send VIRTUAL-UNPLUG to host.
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+HID_API extern tHID_STATUS HID_DevVirtualUnplug (void);
+
+/*******************************************************************************
+**
+** Function HID_DevSendData
+**
+** Description This function may be used to send input reports to host.
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+HID_API extern tHID_STATUS HID_DevSendData (BOOLEAN control_ch, UINT8 rep_type,
+ BT_HDR *data_buf );
+
+/*******************************************************************************
+**
+** Function HID_DevSetPowerMgmtParams
+**
+** Description This function may be used to change power mgmt parameters.
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+HID_API extern tHID_STATUS HID_DevSetPowerMgmtParams(UINT8 conn_substate,
+ tHID_DEV_PM_PWR_MD pm_params );
+
+/*******************************************************************************
+**
+** Function HID_DevInit
+**
+** Description This function initializes the control block and trace variable
+**
+** Returns void
+**
+*******************************************************************************/
+HID_API extern void HID_DevInit(void);
+
+/*******************************************************************************
+**
+** Function HID_DevSetSecurityLevel
+**
+** Description This function set security level for the Hid Device service.
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+HID_API extern tHID_STATUS HID_DevSetSecurityLevel( char serv_name[], UINT8 sec_lvl );
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HIDD_API_H */
diff --git a/stack/include/hiddefs.h b/stack/include/hiddefs.h
new file mode 100644
index 0000000..7d8e75a
--- /dev/null
+++ b/stack/include/hiddefs.h
@@ -0,0 +1,146 @@
+/****************************************************************************/
+/* */
+/* Name: hiddefs.h */
+/* */
+/* Function: this file contains HID protocol definitions */
+/* */
+/* */
+/* Copyright (c) 2002-2004, WIDCOMM Inc., All Rights Reserved. */
+/* WIDCOMM Bluetooth Core. Proprietary and confidential. */
+/* */
+/****************************************************************************/
+
+#ifndef HIDDEFS_H
+#define HIDDEFS_H
+
+#include "sdp_api.h"
+/*
+** tHID_STATUS: HID result codes, returned by HID and device and host functions.
+*/
+enum
+{
+ HID_SUCCESS,
+ HID_ERR_NOT_REGISTERED,
+ HID_ERR_ALREADY_REGISTERED,
+ HID_ERR_NO_RESOURCES,
+ HID_ERR_NO_CONNECTION,
+ HID_ERR_INVALID_PARAM,
+ HID_ERR_UNSUPPORTED,
+ HID_ERR_UNKNOWN_COMMAND,
+ HID_ERR_CONGESTED,
+ HID_ERR_CONN_IN_PROCESS,
+ HID_ERR_ALREADY_CONN,
+ HID_ERR_DISCONNECTING,
+ HID_ERR_SET_CONNABLE_FAIL,
+ /* Device specific error codes */
+ HID_ERR_HOST_UNKNOWN,
+ HID_ERR_L2CAP_FAILED,
+ HID_ERR_AUTH_FAILED,
+ HID_ERR_SDP_BUSY,
+
+ HID_ERR_INVALID = 0xFF
+};
+
+typedef UINT8 tHID_STATUS;
+
+#define HID_L2CAP_CONN_FAIL (0x0100) /* Connection Attempt was made but failed */
+#define HID_L2CAP_REQ_FAIL (0x0200) /* L2CAP_ConnectReq API failed */
+#define HID_L2CAP_CFG_FAIL (0x0400) /* L2CAP Configuration was rejected by peer */
+
+
+
+/* Define the HID transaction types
+*/
+#define HID_TRANS_HANDSHAKE (0)
+#define HID_TRANS_CONTROL (1)
+#define HID_TRANS_GET_REPORT (4)
+#define HID_TRANS_SET_REPORT (5)
+#define HID_TRANS_GET_PROTOCOL (6)
+#define HID_TRANS_SET_PROTOCOL (7)
+#define HID_TRANS_GET_IDLE (8)
+#define HID_TRANS_SET_IDLE (9)
+#define HID_TRANS_DATA (10)
+#define HID_TRANS_DATAC (11)
+
+#define HID_GET_TRANS_FROM_HDR(x) ((x >> 4) & 0x0f)
+#define HID_GET_PARAM_FROM_HDR(x) (x & 0x0f)
+#define HID_BUILD_HDR(t,p) (UINT8)((t << 4) | (p & 0x0f))
+
+
+/* Parameters for Handshake
+*/
+#define HID_PAR_HANDSHAKE_RSP_SUCCESS (0)
+#define HID_PAR_HANDSHAKE_RSP_NOT_READY (1)
+#define HID_PAR_HANDSHAKE_RSP_ERR_INVALID_REP_ID (2)
+#define HID_PAR_HANDSHAKE_RSP_ERR_UNSUPPORTED_REQ (3)
+#define HID_PAR_HANDSHAKE_RSP_ERR_INVALID_PARAM (4)
+#define HID_PAR_HANDSHAKE_RSP_ERR_UNKNOWN (14)
+#define HID_PAR_HANDSHAKE_RSP_ERR_FATAL (15)
+
+
+/* Parameters for Control
+*/
+#define HID_PAR_CONTROL_NOP (0)
+#define HID_PAR_CONTROL_HARD_RESET (1)
+#define HID_PAR_CONTROL_SOFT_RESET (2)
+#define HID_PAR_CONTROL_SUSPEND (3)
+#define HID_PAR_CONTROL_EXIT_SUSPEND (4)
+#define HID_PAR_CONTROL_VIRTUAL_CABLE_UNPLUG (5)
+
+
+/* Different report types in get, set, data
+*/
+#define HID_PAR_REP_TYPE_MASK (0x03)
+#define HID_PAR_REP_TYPE_OTHER (0x00)
+#define HID_PAR_REP_TYPE_INPUT (0x01)
+#define HID_PAR_REP_TYPE_OUTPUT (0x02)
+#define HID_PAR_REP_TYPE_FEATURE (0x03)
+
+/* Parameters for Get Report
+*/
+
+/* Buffer size in two bytes after Report ID */
+#define HID_PAR_GET_REP_BUFSIZE_FOLLOWS (0x08)
+
+
+/* Parameters for Protocol Type
+*/
+#define HID_PAR_PROTOCOL_MASK (0x01)
+#define HID_PAR_PROTOCOL_REPORT (0x01)
+#define HID_PAR_PROTOCOL_BOOT_MODE (0x00)
+
+#define HID_PAR_REP_TYPE_MASK (0x03)
+
+/* Descriptor types in the SDP record
+*/
+#define HID_SDP_DESCRIPTOR_REPORT (0x22)
+#define HID_SDP_DESCRIPTOR_PHYSICAL (0x23)
+
+typedef struct desc_info
+{
+ UINT16 dl_len;
+ UINT8 *dsc_list;
+} tHID_DEV_DSCP_INFO;
+
+#define HID_SSR_PARAM_INVALID 0xffff
+
+typedef struct sdp_info
+{
+ char svc_name[HID_MAX_SVC_NAME_LEN]; /*Service Name */
+ char svc_descr[HID_MAX_SVC_DESCR_LEN]; /*Service Description*/
+ char prov_name[HID_MAX_PROV_NAME_LEN]; /*Provider Name.*/
+ UINT16 rel_num; /*Release Number */
+ UINT16 hpars_ver; /*HID Parser Version.*/
+ UINT16 ssr_max_latency; /* HIDSSRHostMaxLatency value, if HID_SSR_PARAM_INVALID not used*/
+ UINT16 ssr_min_tout; /* HIDSSRHostMinTimeout value, if HID_SSR_PARAM_INVALID not used* */
+ UINT8 sub_class; /*Device Subclass.*/
+ UINT8 ctry_code; /*Country Code.*/
+ UINT16 sup_timeout;/* Supervisory Timeout */
+
+ tHID_DEV_DSCP_INFO dscp_info; /* Descriptor list and Report list to be set in the SDP record.
+ This parameter is used if HID_DEV_USE_GLB_SDP_REC is set to FALSE.*/
+ tSDP_DISC_REC *p_sdp_layer_rec;
+} tHID_DEV_SDP_INFO;
+
+#endif
+
diff --git a/stack/include/hidh_api.h b/stack/include/hidh_api.h
new file mode 100644
index 0000000..bc3f8c8
--- /dev/null
+++ b/stack/include/hidh_api.h
@@ -0,0 +1,215 @@
+/****************************************************************************
+**
+** Name: hidh_api.h
+**
+** Function: this file contains HID HOST side API definitions
+**
+** Copyright (c) 2002-2004, WIDCOMM Inc., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef HIDH_API_H
+#define HIDH_API_H
+
+#include "hiddefs.h"
+#include "sdp_api.h"
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+enum {
+ HID_SDP_NO_SERV_UUID = (SDP_ILLEGAL_PARAMETER+1),
+ HID_SDP_MANDATORY_MISSING
+};
+
+/* Attributes mask values to be used in HID_HostAddDev API */
+#define HID_VIRTUAL_CABLE 0x0001
+#define HID_NORMALLY_CONNECTABLE 0x0002
+#define HID_RECONN_INIT 0x0004
+#define HID_SDP_DISABLE 0x0008
+#define HID_BATTERY_POWER 0x0010
+#define HID_REMOTE_WAKE 0x0020
+#define HID_SUP_TOUT_AVLBL 0x0040
+#define HID_SSR_MAX_LATENCY 0x0080
+#define HID_SSR_MIN_TOUT 0x0100
+
+#define HID_SEC_REQUIRED 0x8000
+
+
+/*****************************************************************************
+** Type Definitions
+*****************************************************************************/
+
+typedef void (tHID_HOST_SDP_CALLBACK) (UINT16 result, UINT16 attr_mask,
+ tHID_DEV_SDP_INFO *sdp_rec );
+
+/* HID-HOST returns the events in the following table to the application via tHID_HOST_DEV_CALLBACK
+HID_HDEV_EVT_OPEN Connected to device with Interrupt and Control Channels in OPEN state.
+ Data = NA
+HID_HDEV_EVT_CLOSE Connection with device is closed. Data=reason code.
+HID_HDEV_EVT_RETRYING Lost connection is being re-connected.
+ Data=Retrial number
+HID_HDEV_EVT_IN_REPORT Device sent an input report Data=Report Type pdata= pointer to BT_HDR
+ (GKI buffer having report data.)
+HID_HDEV_EVT_HANDSHAKE Device sent SET_REPORT Data=Result-code pdata=NA.
+HID_HDEV_EVT_VC_UNPLUG Device sent Virtual Unplug Data=NA. pdata=NA.
+*/
+
+enum
+{
+ HID_HDEV_EVT_OPEN,
+ HID_HDEV_EVT_CLOSE,
+ HID_HDEV_EVT_RETRYING,
+ HID_HDEV_EVT_INTR_DATA,
+ HID_HDEV_EVT_INTR_DATC,
+ HID_HDEV_EVT_CTRL_DATA,
+ HID_HDEV_EVT_CTRL_DATC,
+ HID_HDEV_EVT_HANDSHAKE,
+ HID_HDEV_EVT_VC_UNPLUG
+};
+typedef void (tHID_HOST_DEV_CALLBACK) (UINT8 dev_handle,
+ UINT8 event, /* Event from HID-DEVICE. */
+ UINT32 data, /* Integer data corresponding to the event.*/
+ BT_HDR *p_buf ); /* Pointer data corresponding to the event. */
+
+
+/*****************************************************************************
+** External Function Declarations
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*******************************************************************************
+**
+** Function HID_HostGetSDPRecord
+**
+** Description This function reads the device SDP record.
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+HID_API extern tHID_STATUS HID_HostGetSDPRecord (BD_ADDR addr,
+ tSDP_DISCOVERY_DB *p_db,
+ UINT32 db_len,
+ tHID_HOST_SDP_CALLBACK *sdp_cback );
+
+/*******************************************************************************
+**
+** Function HID_HostRegister
+**
+** Description This function registers HID-Host with lower layers.
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+HID_API extern tHID_STATUS HID_HostRegister (tHID_HOST_DEV_CALLBACK *dev_cback);
+
+/*******************************************************************************
+**
+** Function HID_HostDeregister
+**
+** Description This function is called when the host is about power down.
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+HID_API extern tHID_STATUS HID_HostDeregister(void);
+
+/*******************************************************************************
+**
+** Function HID_HostAddDev
+**
+** Description This is called so HID-host may manage this device.
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+HID_API extern tHID_STATUS HID_HostAddDev (BD_ADDR addr, UINT16 attr_mask,
+ UINT8 *handle );
+
+/*******************************************************************************
+**
+** Function HID_HostRemoveDev
+**
+** Description This removes the device from list devices that host has to manage.
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+HID_API extern tHID_STATUS HID_HostRemoveDev (UINT8 dev_handle );
+
+/*******************************************************************************
+**
+** Function HID_HostOpenDev
+**
+** Description This function is called when the user wants to initiate a
+** connection attempt to a device.
+**
+** Returns void
+**
+*******************************************************************************/
+HID_API extern tHID_STATUS HID_HostOpenDev (UINT8 dev_handle );
+
+/*******************************************************************************
+**
+** Function HID_HostWriteDev
+**
+** Description This function is called when the host has a report to send.
+**
+** Returns void
+**
+*******************************************************************************/
+HID_API extern tHID_STATUS HID_HostWriteDev(UINT8 dev_handle, UINT8 t_type,
+ UINT8 param, UINT16 data,
+ UINT8 report_id, BT_HDR *pbuf);
+
+/*******************************************************************************
+**
+** Function HID_HostCloseDev
+**
+** Description This function disconnects the device.
+**
+** Returns void
+**
+*******************************************************************************/
+HID_API extern tHID_STATUS HID_HostCloseDev(UINT8 dev_handle );
+
+/*******************************************************************************
+** Function HID_HostInit
+**
+** Description This function initializes the control block and trace variable
+**
+** Returns void
+*******************************************************************************/
+HID_API extern void HID_HostInit(void);
+
+/*******************************************************************************
+** Function HID_HostSetSecurityLevel
+**
+** Description This function sets the security level for the devices which
+** are marked by application as requiring security
+**
+** Returns tHID_STATUS
+*******************************************************************************/
+HID_API extern tHID_STATUS HID_HostSetSecurityLevel( char serv_name[], UINT8 sec_lvl );
+
+/*******************************************************************************
+**
+** Function HID_HostSetTraceLevel
+**
+** Description This function sets the trace level for HID Host. If called with
+** a value of 0xFF, it simply reads the current trace level.
+**
+** Returns the new (current) trace level
+**
+*******************************************************************************/
+HID_API extern UINT8 HID_HostSetTraceLevel (UINT8 new_level);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HIDH_API_H */
diff --git a/stack/include/l2c_api.h b/stack/include/l2c_api.h
new file mode 100644
index 0000000..fbd45d8
--- /dev/null
+++ b/stack/include/l2c_api.h
@@ -0,0 +1,1173 @@
+/*****************************************************************************
+**
+** Name: l2c_api.h
+**
+** Description: this file contains the L2CAP API definitions
+**
+**
+**
+** Copyright (c) 1999-2009, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+#ifndef L2C_API_H
+#define L2C_API_H
+
+#include "bt_target.h"
+#include "l2cdefs.h"
+#include "hcidefs.h"
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+/* Define the minimum offset that L2CAP needs in a buffer. This is made up of
+** HCI type(1), len(2), handle(2), L2CAP len(2) and CID(2) => 9
+*/
+#define L2CAP_MIN_OFFSET 13 /* plus control(2), SDU length(2) */
+
+/* Minimum offset for broadcast needs another two bytes for the PSM */
+#define L2CAP_BCST_MIN_OFFSET 11
+
+/* ping result codes */
+#define L2CAP_PING_RESULT_OK 0 /* Ping reply received OK */
+#define L2CAP_PING_RESULT_NO_LINK 1 /* Link could not be setup */
+#define L2CAP_PING_RESULT_NO_RESP 2 /* Remote L2CAP did not reply */
+
+/* result code for L2CA_DataWrite() */
+#define L2CAP_DW_FAILED FALSE
+#define L2CAP_DW_SUCCESS TRUE
+#define L2CAP_DW_CONGESTED 2
+
+/* Values for priority parameter to L2CA_SetAclPriority */
+#define L2CAP_PRIORITY_NORMAL 0
+#define L2CAP_PRIORITY_HIGH 1
+
+/* Values for priority parameter to L2CA_SetTxPriority */
+#define L2CAP_CHNL_PRIORITY_HIGH 0
+#define L2CAP_CHNL_PRIORITY_MEDIUM 1
+#define L2CAP_CHNL_PRIORITY_LOW 2
+
+typedef UINT8 tL2CAP_CHNL_PRIORITY;
+
+/* Values for Tx/Rx data rate parameter to L2CA_SetChnlDataRate */
+#define L2CAP_CHNL_DATA_RATE_HIGH 3
+#define L2CAP_CHNL_DATA_RATE_MEDIUM 2
+#define L2CAP_CHNL_DATA_RATE_LOW 1
+#define L2CAP_CHNL_DATA_RATE_NO_TRAFFIC 0
+
+typedef UINT8 tL2CAP_CHNL_DATA_RATE;
+
+/* Data Packet Flags (bits 2-15 are reserved) */
+/* layer specific 14-15 bits are used for FCR SAR */
+#define L2CAP_FLUSHABLE_MASK 0x0003
+#define L2CAP_FLUSHABLE_CH_BASED 0x0000
+#define L2CAP_FLUSHABLE_PKT 0x0001
+#define L2CAP_NON_FLUSHABLE_PKT 0x0002
+
+
+/* L2CA_FlushChannel num_to_flush definitions */
+#define L2CAP_FLUSH_CHANS_ALL 0xffff
+#define L2CAP_FLUSH_CHANS_GET 0x0000
+
+
+/* special CID for Multi-AV for reporting congestion */
+#define L2CAP_MULTI_AV_CID 0
+
+/* length of the HCI header block */
+/* HCI header(4) + SNK count(1) + FCR bits(1) + AV data length(2) */
+#define L2CAP_MULTI_AV_HCI_HDR_LEN 8
+
+/* length of padding for 4 bytes align */
+#define L2CAP_MULTI_AV_PADDING_LEN 2
+
+/* length of the HCI header block with padding for FCR */
+/* HCI header(4) + SNK count(1) + FCR bits(1) + AV data length(2) + padding(2) */
+#define L2CAP_MULTI_AV_HCI_HDR_LEN_WITH_PADDING 10
+
+/* length of the L2CAP header block */
+/* HCI header(4) + L2CAP header(4) + padding(4) or control word(2) + FCS(2) */
+#define L2CAP_MULTI_AV_L2C_HDR_LEN 12
+
+/* definition used for L2CA_SetDesireRole */
+#define L2CAP_ROLE_SLAVE HCI_ROLE_SLAVE
+#define L2CAP_ROLE_MASTER HCI_ROLE_MASTER
+#define L2CAP_ROLE_ALLOW_SWITCH 0x80 /* set this bit to allow switch at create conn */
+#define L2CAP_ROLE_DISALLOW_SWITCH 0x40 /* set this bit to disallow switch at create conn */
+#define L2CAP_ROLE_CHECK_SWITCH 0xC0
+
+
+/* Values for 'allowed_modes' field passed in structure tL2CAP_ERTM_INFO
+*/
+#define L2CAP_FCR_CHAN_OPT_BASIC (1 << L2CAP_FCR_BASIC_MODE)
+#define L2CAP_FCR_CHAN_OPT_ERTM (1 << L2CAP_FCR_ERTM_MODE)
+#define L2CAP_FCR_CHAN_OPT_STREAM (1 << L2CAP_FCR_STREAM_MODE)
+
+#define L2CAP_FCR_CHAN_OPT_ALL_MASK (L2CAP_FCR_CHAN_OPT_BASIC | L2CAP_FCR_CHAN_OPT_ERTM | L2CAP_FCR_CHAN_OPT_STREAM)
+
+/* Validity check for PSM. PSM values must be odd. Also, all PSM values must
+** be assigned such that the least significant bit of the most sigificant
+** octet equals zero.
+*/
+#define L2C_INVALID_PSM(psm) (((psm) & 0x0101) != 0x0001)
+#define L2C_IS_VALID_PSM(psm) (((psm) & 0x0101) == 0x0001)
+
+#if (BLE_INCLUDED == TRUE)
+#define L2CAP_LE_INT_MIN 0x0006
+#define L2CAP_LE_INT_MAX 0x0C80
+#define L2CAP_LE_LATENCY_MAX 500
+#define L2CAP_LE_TIMEOUT_MIN 0x000a
+#define L2CAP_LE_TIMEOUT_MAX 0x0C80
+#define L2CAP_LE_TIMEOUT_DEFAULT 0x07D0
+#endif
+
+
+/*****************************************************************************
+** Type Definitions
+*****************************************************************************/
+
+typedef struct
+{
+#define L2CAP_FCR_BASIC_MODE 0x00
+#define L2CAP_FCR_ERTM_MODE 0x03
+#define L2CAP_FCR_STREAM_MODE 0x04
+
+ UINT8 mode;
+
+ UINT8 tx_win_sz;
+ UINT8 max_transmit;
+ UINT16 rtrans_tout;
+ UINT16 mon_tout;
+ UINT16 mps;
+} tL2CAP_FCR_OPTS;
+
+/* Define a structure to hold the configuration parameters. Since the
+** parameters are optional, for each parameter there is a boolean to
+** use to signify its presence or absence.
+*/
+typedef struct
+{
+ UINT16 result; /* Only used in confirm messages */
+ BOOLEAN mtu_present;
+ UINT16 mtu;
+ BOOLEAN qos_present;
+ FLOW_SPEC qos;
+ BOOLEAN flush_to_present;
+ UINT16 flush_to;
+ BOOLEAN fcr_present;
+ tL2CAP_FCR_OPTS fcr;
+ BOOLEAN fcs_present; /* Optionally bypasses FCS checks */
+ UINT8 fcs; /* '0' if desire is to bypass FCS, otherwise '1' */
+ BOOLEAN ext_flow_spec_present;
+ tHCI_EXT_FLOW_SPEC ext_flow_spec;
+ UINT16 flags; /* bit 0: 0-no continuation, 1-continuation */
+} tL2CAP_CFG_INFO;
+
+/* L2CAP channel configured field bitmap */
+#define L2CAP_CH_CFG_MASK_MTU 0x0001
+#define L2CAP_CH_CFG_MASK_QOS 0x0002
+#define L2CAP_CH_CFG_MASK_FLUSH_TO 0x0004
+#define L2CAP_CH_CFG_MASK_FCR 0x0008
+#define L2CAP_CH_CFG_MASK_FCS 0x0010
+#define L2CAP_CH_CFG_MASK_EXT_FLOW_SPEC 0x0020
+
+typedef UINT16 tL2CAP_CH_CFG_BITS;
+
+/*********************************
+** Callback Functions Prototypes
+**********************************/
+
+/* Connection indication callback prototype. Parameters are
+** BD Address of remote
+** Local CID assigned to the connection
+** PSM that the remote wants to connect to
+** Identifier that the remote sent
+*/
+typedef void (tL2CA_CONNECT_IND_CB) (BD_ADDR, UINT16, UINT16, UINT8);
+
+
+/* Connection confirmation callback prototype. Parameters are
+** Local CID
+** Result - 0 = connected, non-zero means failure reason
+*/
+typedef void (tL2CA_CONNECT_CFM_CB) (UINT16, UINT16);
+
+
+/* Connection pending callback prototype. Parameters are
+** Local CID
+*/
+typedef void (tL2CA_CONNECT_PND_CB) (UINT16);
+
+
+/* Configuration indication callback prototype. Parameters are
+** Local CID assigned to the connection
+** Pointer to configuration info
+*/
+typedef void (tL2CA_CONFIG_IND_CB) (UINT16, tL2CAP_CFG_INFO *);
+
+
+/* Configuration confirm callback prototype. Parameters are
+** Local CID assigned to the connection
+** Pointer to configuration info
+*/
+typedef void (tL2CA_CONFIG_CFM_CB) (UINT16, tL2CAP_CFG_INFO *);
+
+
+/* Disconnect indication callback prototype. Parameters are
+** Local CID
+** Boolean whether upper layer should ack this
+*/
+typedef void (tL2CA_DISCONNECT_IND_CB) (UINT16, BOOLEAN);
+
+
+/* Disconnect confirm callback prototype. Parameters are
+** Local CID
+** Result
+*/
+typedef void (tL2CA_DISCONNECT_CFM_CB) (UINT16, UINT16);
+
+
+/* QOS Violation indication callback prototype. Parameters are
+** BD Address of violating device
+*/
+typedef void (tL2CA_QOS_VIOLATION_IND_CB) (BD_ADDR);
+
+
+/* Data received indication callback prototype. Parameters are
+** Local CID
+** Address of buffer
+*/
+typedef void (tL2CA_DATA_IND_CB) (UINT16, BT_HDR *);
+
+
+/* Echo response callback prototype. Note that this is not included in the
+** registration information, but is passed to L2CAP as part of the API to
+** actually send an echo request. Parameters are
+** Result
+*/
+typedef void (tL2CA_ECHO_RSP_CB) (UINT16);
+
+
+/* Callback function prototype to pass broadcom specific echo response */
+/* to the upper layer */
+typedef void (tL2CA_ECHO_DATA_CB) (BD_ADDR, UINT16, UINT8 *);
+
+
+/* Congestion status callback protype. This callback is optional. If
+** an application tries to send data when the transmit queue is full,
+** the data will anyways be dropped. The parameter is:
+** Local CID
+** TRUE if congested, FALSE if uncongested
+*/
+typedef void (tL2CA_CONGESTION_STATUS_CB) (UINT16, BOOLEAN);
+
+/* Callback prototype for number of packets completed events.
+** This callback notifies the application when Number of Completed Packets
+** event has been received.
+** This callback is originally designed for 3DG devices.
+** The parameter is:
+** peer BD_ADDR
+*/
+typedef void (tL2CA_NOCP_CB) (BD_ADDR);
+
+/* Transmit complete callback protype. This callback is optional. If
+** set, L2CAP will call it when packets are sent or flushed. If the
+** count is 0xFFFF, it means all packets are sent for that CID (eRTM
+** mode only). The parameters are:
+** Local CID
+** Number of SDUs sent or dropped
+*/
+typedef void (tL2CA_TX_COMPLETE_CB) (UINT16, UINT16);
+
+/* Define the structure that applications use to register with
+** L2CAP. This structure includes callback functions. All functions
+** MUST be provided, with the exception of the "connect pending"
+** callback and "congestion status" callback.
+*/
+typedef struct
+{
+ tL2CA_CONNECT_IND_CB *pL2CA_ConnectInd_Cb;
+ tL2CA_CONNECT_CFM_CB *pL2CA_ConnectCfm_Cb;
+ tL2CA_CONNECT_PND_CB *pL2CA_ConnectPnd_Cb;
+ tL2CA_CONFIG_IND_CB *pL2CA_ConfigInd_Cb;
+ tL2CA_CONFIG_CFM_CB *pL2CA_ConfigCfm_Cb;
+ tL2CA_DISCONNECT_IND_CB *pL2CA_DisconnectInd_Cb;
+ tL2CA_DISCONNECT_CFM_CB *pL2CA_DisconnectCfm_Cb;
+ tL2CA_QOS_VIOLATION_IND_CB *pL2CA_QoSViolationInd_Cb;
+ tL2CA_DATA_IND_CB *pL2CA_DataInd_Cb;
+ tL2CA_CONGESTION_STATUS_CB *pL2CA_CongestionStatus_Cb;
+ tL2CA_TX_COMPLETE_CB *pL2CA_TxComplete_Cb;
+
+} tL2CAP_APPL_INFO;
+
+/* Define the structure that applications use to create or accept
+** connections with enhanced retransmission mode.
+*/
+typedef struct
+{
+ UINT8 preferred_mode;
+ UINT8 allowed_modes;
+ UINT8 user_rx_pool_id;
+ UINT8 user_tx_pool_id;
+ UINT8 fcr_rx_pool_id;
+ UINT8 fcr_tx_pool_id;
+
+} tL2CAP_ERTM_INFO;
+
+#define L2CA_REGISTER(a,b,c) L2CA_Register(a,(tL2CAP_APPL_INFO *)b)
+#define L2CA_DEREGISTER(a) L2CA_Deregister(a)
+#define L2CA_CONNECT_REQ(a,b,c,d) L2CA_ErtmConnectReq(a,b,c)
+#define L2CA_CONNECT_RSP(a,b,c,d,e,f,g) L2CA_ErtmConnectRsp(a,b,c,d,e,f)
+#define L2CA_CONFIG_REQ(a,b) L2CA_ConfigReq(a,b)
+#define L2CA_CONFIG_RSP(a,b) L2CA_ConfigRsp(a,b)
+#define L2CA_DISCONNECT_REQ(a) L2CA_DisconnectReq(a)
+#define L2CA_DISCONNECT_RSP(a) L2CA_DisconnectRsp(a)
+#define L2CA_DATA_WRITE(a, b) L2CA_DataWrite(a, b)
+
+/*****************************************************************************
+** External Function Declarations
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*******************************************************************************
+**
+** Function L2CA_Register
+**
+** Description Other layers call this function to register for L2CAP
+** services.
+**
+** Returns PSM to use or zero if error. Typically, the PSM returned
+** is the same as was passed in, but for an outgoing-only
+** connection to a dynamic PSM, a "virtual" PSM is returned
+** and should be used in the calls to L2CA_ConnectReq() and
+** BTM_SetSecurityLevel().
+**
+*******************************************************************************/
+L2C_API extern UINT16 L2CA_Register (UINT16 psm, tL2CAP_APPL_INFO *p_cb_info);
+
+/*******************************************************************************
+**
+** Function L2CA_Deregister
+**
+** Description Other layers call this function to deregister for L2CAP
+** services.
+**
+** Returns void
+**
+*******************************************************************************/
+L2C_API extern void L2CA_Deregister (UINT16 psm);
+
+/*******************************************************************************
+**
+** Function L2CA_AllocatePSM
+**
+** Description Other layers call this function to find an unused PSM for L2CAP
+** services.
+**
+** Returns PSM to use.
+**
+*******************************************************************************/
+L2C_API extern UINT16 L2CA_AllocatePSM(void);
+
+/*******************************************************************************
+**
+** Function L2CA_ConnectReq
+**
+** Description Higher layers call this function to create an L2CAP connection.
+** Note that the connection is not established at this time, but
+** connection establishment gets started. The callback function
+** will be invoked when connection establishes or fails.
+**
+** Returns the CID of the connection, or 0 if it failed to start
+**
+*******************************************************************************/
+L2C_API extern UINT16 L2CA_ConnectReq (UINT16 psm, BD_ADDR p_bd_addr);
+
+/*******************************************************************************
+**
+** Function L2CA_ConnectRsp
+**
+** Description Higher layers call this function to accept an incoming
+** L2CAP connection, for which they had gotten an connect
+** indication callback.
+**
+** Returns TRUE for success, FALSE for failure
+**
+*******************************************************************************/
+L2C_API extern BOOLEAN L2CA_ConnectRsp (BD_ADDR p_bd_addr, UINT8 id, UINT16 lcid,
+ UINT16 result, UINT16 status);
+
+/*******************************************************************************
+**
+** Function L2CA_ErtmConnectReq
+**
+** Description Higher layers call this function to create an L2CAP connection
+** that needs to use Enhanced Retransmission Mode.
+** Note that the connection is not established at this time, but
+** connection establishment gets started. The callback function
+** will be invoked when connection establishes or fails.
+**
+** Returns the CID of the connection, or 0 if it failed to start
+**
+*******************************************************************************/
+L2C_API extern UINT16 L2CA_ErtmConnectReq (UINT16 psm, BD_ADDR p_bd_addr,
+ tL2CAP_ERTM_INFO *p_ertm_info);
+
+/*******************************************************************************
+**
+** Function L2CA_ErtmConnectRsp
+**
+** Description Higher layers call this function to accept an incoming
+** L2CAP connection, for which they had gotten an connect
+** indication callback, and for which the higher layer wants
+** to use Enhanced Retransmission Mode.
+**
+** Returns TRUE for success, FALSE for failure
+**
+*******************************************************************************/
+L2C_API extern BOOLEAN L2CA_ErtmConnectRsp (BD_ADDR p_bd_addr, UINT8 id, UINT16 lcid,
+ UINT16 result, UINT16 status,
+ tL2CAP_ERTM_INFO *p_ertm_info);
+
+/*******************************************************************************
+**
+** Function L2CA_ConfigReq
+**
+** Description Higher layers call this function to send configuration.
+**
+** Returns TRUE if configuration sent, else FALSE
+**
+*******************************************************************************/
+L2C_API extern BOOLEAN L2CA_ConfigReq (UINT16 cid, tL2CAP_CFG_INFO *p_cfg);
+
+/*******************************************************************************
+**
+** Function L2CA_ConfigRsp
+**
+** Description Higher layers call this function to send a configuration
+** response.
+**
+** Returns TRUE if configuration response sent, else FALSE
+**
+*******************************************************************************/
+L2C_API extern BOOLEAN L2CA_ConfigRsp (UINT16 cid, tL2CAP_CFG_INFO *p_cfg);
+
+/*******************************************************************************
+**
+** Function L2CA_DisconnectReq
+**
+** Description Higher layers call this function to disconnect a channel.
+**
+** Returns TRUE if disconnect sent, else FALSE
+**
+*******************************************************************************/
+L2C_API extern BOOLEAN L2CA_DisconnectReq (UINT16 cid);
+
+/*******************************************************************************
+**
+** Function L2CA_DisconnectRsp
+**
+** Description Higher layers call this function to acknowledge the
+** disconnection of a channel.
+**
+** Returns void
+**
+*******************************************************************************/
+L2C_API extern BOOLEAN L2CA_DisconnectRsp (UINT16 cid);
+
+/*******************************************************************************
+**
+** Function L2CA_DataWrite
+**
+** Description Higher layers call this function to write data.
+**
+** Returns L2CAP_DW_SUCCESS, if data accepted, else FALSE
+** L2CAP_DW_CONGESTED, if data accepted and the channel is congested
+** L2CAP_DW_FAILED, if error
+**
+*******************************************************************************/
+L2C_API extern UINT8 L2CA_DataWrite (UINT16 cid, BT_HDR *p_data);
+
+/*******************************************************************************
+**
+** Function L2CA_Ping
+**
+** Description Higher layers call this function to send an echo request.
+**
+** Returns TRUE if echo request sent, else FALSE.
+**
+*******************************************************************************/
+L2C_API extern BOOLEAN L2CA_Ping (BD_ADDR p_bd_addr, tL2CA_ECHO_RSP_CB *p_cb);
+
+/*******************************************************************************
+**
+** Function L2CA_Echo
+**
+** Description Higher layers call this function to send an echo request
+** with application-specific data.
+**
+** Returns TRUE if echo request sent, else FALSE.
+**
+*******************************************************************************/
+L2C_API extern BOOLEAN L2CA_Echo (BD_ADDR p_bd_addr, BT_HDR *p_data, tL2CA_ECHO_DATA_CB *p_callback);
+
+/*******************************************************************************
+**
+** Function L2CA_SetIdleTimeout
+**
+** Description Higher layers call this function to set the idle timeout for
+** a connection, or for all future connections. The "idle timeout"
+** is the amount of time that a connection can remain up with
+** no L2CAP channels on it. A timeout of zero means that the
+** connection will be torn down immediately when the last channel
+** is removed. A timeout of 0xFFFF means no timeout. Values are
+** in seconds.
+**
+** Returns TRUE if command succeeded, FALSE if failed
+**
+*******************************************************************************/
+L2C_API extern BOOLEAN L2CA_SetIdleTimeout (UINT16 cid, UINT16 timeout,
+ BOOLEAN is_global);
+
+/*******************************************************************************
+**
+** Function L2CA_SetIdleTimeoutByBdAddr
+**
+** Description Higher layers call this function to set the idle timeout for
+** a connection. The "idle timeout" is the amount of time that
+** a connection can remain up with no L2CAP channels on it.
+** A timeout of zero means that the connection will be torn
+** down immediately when the last channel is removed.
+** A timeout of 0xFFFF means no timeout. Values are in seconds.
+** A bd_addr is the remote BD address. If bd_addr = BT_BD_ANY,
+** then the idle timeouts for all active l2cap links will be
+** changed.
+**
+** Returns TRUE if command succeeded, FALSE if failed
+**
+** NOTE This timeout applies to all logical channels active on the
+** ACL link.
+*******************************************************************************/
+L2C_API extern BOOLEAN L2CA_SetIdleTimeoutByBdAddr(BD_ADDR bd_addr, UINT16 timeout);
+
+/*******************************************************************************
+**
+** Function L2CA_SetTraceLevel
+**
+** Description This function sets the trace level for L2CAP. If called with
+** a value of 0xFF, it simply reads the current trace level.
+**
+** Returns the new (current) trace level
+**
+*******************************************************************************/
+L2C_API extern UINT8 L2CA_SetTraceLevel (UINT8 trace_level);
+
+/*******************************************************************************
+**
+** Function L2CA_SetDesireRole
+**
+** Description This function sets the desire role for L2CAP.
+** If the new role is L2CAP_ROLE_ALLOW_SWITCH, allow switch on
+** HciCreateConnection.
+** If the new role is L2CAP_ROLE_DISALLOW_SWITCH, do not allow switch on
+** HciCreateConnection.
+**
+** If the new role is a valid role (HCI_ROLE_MASTER or HCI_ROLE_SLAVE),
+** the desire role is set to the new value. Otherwise, it is not changed.
+**
+** Returns the new (current) role
+**
+*******************************************************************************/
+L2C_API extern UINT8 L2CA_SetDesireRole (UINT8 new_role);
+
+/*******************************************************************************
+**
+** Function L2CA_LocalLoopbackReq
+**
+** Description This function sets up a CID for local loopback
+**
+** Returns CID of 0 if none.
+**
+*******************************************************************************/
+L2C_API extern UINT16 L2CA_LocalLoopbackReq (UINT16 psm, UINT16 handle, BD_ADDR p_bd_addr);
+
+/*******************************************************************************
+**
+** Function L2CA_FlushChannel
+**
+** Description This function flushes none, some or all buffers queued up
+** for xmission for a particular CID. If called with
+** L2CAP_FLUSH_CHANS_GET (0), it simply returns the number
+** of buffers queued for that CID L2CAP_FLUSH_CHANS_ALL (0xffff)
+** flushes all buffers. All other values specifies the maximum
+** buffers to flush.
+**
+** Returns Number of buffers left queued for that CID
+**
+*******************************************************************************/
+L2C_API extern UINT16 L2CA_FlushChannel (UINT16 lcid, UINT16 num_to_flush);
+
+
+/*******************************************************************************
+**
+** Function L2CA_SetAclPriority
+**
+** Description Sets the transmission priority for an ACL channel.
+** (For initial implementation only two values are valid.
+** L2CAP_PRIORITY_NORMAL and L2CAP_PRIORITY_HIGH).
+**
+** Returns TRUE if a valid channel, else FALSE
+**
+*******************************************************************************/
+L2C_API extern BOOLEAN L2CA_SetAclPriority (BD_ADDR bd_addr, UINT8 priority);
+
+/*******************************************************************************
+**
+** Function L2CA_FlowControl
+**
+** Description Higher layers call this function to flow control a channel.
+**
+** data_enabled - TRUE data flows, FALSE data is stopped
+**
+** Returns TRUE if valid channel, else FALSE
+**
+*******************************************************************************/
+L2C_API extern BOOLEAN L2CA_FlowControl (UINT16 cid, BOOLEAN data_enabled);
+
+/*******************************************************************************
+**
+** Function L2CA_SendTestSFrame
+**
+** Description Higher layers call this function to send a test S-frame.
+**
+** Returns TRUE if valid Channel, else FALSE
+**
+*******************************************************************************/
+L2C_API extern BOOLEAN L2CA_SendTestSFrame (UINT16 cid, BOOLEAN rr_or_rej,
+ UINT8 back_track);
+
+/*******************************************************************************
+**
+** Function L2CA_SetTxPriority
+**
+** Description Sets the transmission priority for a channel. (FCR Mode)
+**
+** Returns TRUE if a valid channel, else FALSE
+**
+*******************************************************************************/
+L2C_API extern BOOLEAN L2CA_SetTxPriority (UINT16 cid, tL2CAP_CHNL_PRIORITY priority);
+
+/*******************************************************************************
+**
+** Function L2CA_RegForNoCPEvt
+**
+** Description Register callback for Number of Completed Packets event.
+**
+** Input Param p_cb - callback for Number of completed packets event
+** p_bda - BT address of remote device
+**
+** Returns
+**
+*******************************************************************************/
+L2C_API extern BOOLEAN L2CA_RegForNoCPEvt(tL2CA_NOCP_CB *p_cb, BD_ADDR p_bda);
+
+/*******************************************************************************
+**
+** Function L2CA_SetChnlDataRate
+**
+** Description Sets the tx/rx data rate for a channel.
+**
+** Returns TRUE if a valid channel, else FALSE
+**
+*******************************************************************************/
+L2C_API extern BOOLEAN L2CA_SetChnlDataRate (UINT16 cid, tL2CAP_CHNL_DATA_RATE tx, tL2CAP_CHNL_DATA_RATE rx);
+
+typedef void (tL2CA_RESERVE_CMPL_CBACK) (void);
+
+/*******************************************************************************
+**
+** Function L2CA_SetFlushTimeout
+**
+** Description This function set the automatic flush time out in Baseband
+** for ACL-U packets.
+** BdAddr : the remote BD address of ACL link. If it is BT_DB_ANY
+** then the flush time out will be applied to all ACL link.
+** FlushTimeout: flush time out in ms
+** 0x0000 : No automatic flush
+** L2CAP_NO_RETRANSMISSION : No retransmission
+** 0x0002 - 0xFFFE : flush time out, if (flush_tout*8)+3/5)
+** <= HCI_MAX_AUTO_FLUSH_TOUT (in 625us slot).
+** Otherwise, return FALSE.
+** L2CAP_NO_AUTOMATIC_FLUSH : No automatic flush
+**
+** Returns TRUE if command succeeded, FALSE if failed
+**
+** NOTE This flush timeout applies to all logical channels active on the
+** ACL link.
+*******************************************************************************/
+L2C_API extern BOOLEAN L2CA_SetFlushTimeout (BD_ADDR bd_addr, UINT16 flush_tout);
+
+/*******************************************************************************
+**
+** Function L2CA_DataWriteEx
+**
+** Description Higher layers call this function to write data with extended
+** flags.
+** flags : L2CAP_FLUSHABLE_CH_BASED
+** L2CAP_FLUSHABLE_PKT
+** L2CAP_NON_FLUSHABLE_PKT
+**
+** Returns L2CAP_DW_SUCCESS, if data accepted, else FALSE
+** L2CAP_DW_CONGESTED, if data accepted and the channel is congested
+** L2CAP_DW_FAILED, if error
+**
+*******************************************************************************/
+L2C_API extern UINT8 L2CA_DataWriteEx (UINT16 cid, BT_HDR *p_data, UINT16 flags);
+
+/*******************************************************************************
+**
+** Function L2CA_SetChnlFlushability
+**
+** Description Higher layers call this function to set a channels
+** flushability flags
+**
+** Returns TRUE if CID found, else FALSE
+**
+*******************************************************************************/
+L2C_API extern BOOLEAN L2CA_SetChnlFlushability (UINT16 cid, BOOLEAN is_flushable);
+
+/*******************************************************************************
+**
+** Function L2CA_GetPeerFeatures
+**
+** Description Get a peers features and fixed channel map
+**
+** Parameters: BD address of the peer
+** Pointers to features and channel mask storage area
+**
+** Return value: TRUE if peer is connected
+**
+*******************************************************************************/
+L2C_API extern BOOLEAN L2CA_GetPeerFeatures (BD_ADDR bd_addr, UINT32 *p_ext_feat, UINT8 *p_chnl_mask);
+
+/*******************************************************************************
+**
+** Function L2CA_GetBDAddrbyHandle
+**
+** Description Get BD address for the given HCI handle
+**
+** Parameters: HCI handle
+** BD address of the peer
+**
+** Return value: TRUE if found lcb for the given handle, FALSE otherwise
+**
+*******************************************************************************/
+L2C_API extern BOOLEAN L2CA_GetBDAddrbyHandle (UINT16 handle, BD_ADDR bd_addr);
+
+/*******************************************************************************
+**
+** Function L2CA_GetChnlFcrMode
+**
+** Description Get the channel FCR mode
+**
+** Parameters: Local CID
+**
+** Return value: Channel mode
+**
+*******************************************************************************/
+L2C_API extern UINT8 L2CA_GetChnlFcrMode (UINT16 lcid);
+
+
+/*******************************************************************************
+**
+** UCD callback prototypes
+**
+*******************************************************************************/
+
+/* UCD discovery. Parameters are
+** BD Address of remote
+** Data Type
+** Data
+*/
+#define L2CAP_UCD_INFO_TYPE_RECEPTION 0x01
+#define L2CAP_UCD_INFO_TYPE_MTU 0x02
+
+typedef void (tL2CA_UCD_DISCOVER_CB) (BD_ADDR, UINT8, UINT32);
+
+/* UCD data received. Parameters are
+** BD Address of remote
+** Pointer to buffer with data
+*/
+typedef void (tL2CA_UCD_DATA_CB) (BD_ADDR, BT_HDR *);
+
+/* Congestion status callback protype. This callback is optional. If
+** an application tries to send data when the transmit queue is full,
+** the data will anyways be dropped. The parameter is:
+** remote BD_ADDR
+** TRUE if congested, FALSE if uncongested
+*/
+typedef void (tL2CA_UCD_CONGESTION_STATUS_CB) (BD_ADDR, BOOLEAN);
+
+/* UCD registration info (the callback addresses and PSM)
+*/
+typedef struct
+{
+ tL2CA_UCD_DISCOVER_CB *pL2CA_UCD_Discover_Cb;
+ tL2CA_UCD_DATA_CB *pL2CA_UCD_Data_Cb;
+ tL2CA_UCD_CONGESTION_STATUS_CB *pL2CA_UCD_Congestion_Status_Cb;
+} tL2CAP_UCD_CB_INFO;
+
+/*******************************************************************************
+**
+** Function L2CA_UcdRegister
+**
+** Description Register PSM on UCD.
+**
+** Parameters: tL2CAP_UCD_CB_INFO
+**
+** Return value: TRUE if successs
+**
+*******************************************************************************/
+L2C_API extern BOOLEAN L2CA_UcdRegister ( UINT16 psm, tL2CAP_UCD_CB_INFO *p_cb_info );
+
+/*******************************************************************************
+**
+** Function L2CA_UcdDeregister
+**
+** Description Deregister PSM on UCD.
+**
+** Parameters: PSM
+**
+** Return value: TRUE if successs
+**
+*******************************************************************************/
+L2C_API extern BOOLEAN L2CA_UcdDeregister ( UINT16 psm );
+
+/*******************************************************************************
+**
+** Function L2CA_UcdDiscover
+**
+** Description Discover UCD of remote device.
+**
+** Parameters: PSM
+** BD_ADDR of remote device
+** info_type : L2CAP_UCD_INFO_TYPE_RECEPTION
+** L2CAP_UCD_INFO_TYPE_MTU
+**
+**
+** Return value: TRUE if successs
+**
+*******************************************************************************/
+L2C_API extern BOOLEAN L2CA_UcdDiscover ( UINT16 psm, BD_ADDR rem_bda, UINT8 info_type );
+
+/*******************************************************************************
+**
+** Function L2CA_UcdDataWrite
+**
+** Description Send UCD to remote device
+**
+** Parameters: PSM
+** BD Address of remote
+** Pointer to buffer of type BT_HDR
+** flags : L2CAP_FLUSHABLE_CH_BASED
+** L2CAP_FLUSHABLE_PKT
+** L2CAP_NON_FLUSHABLE_PKT
+**
+** Return value L2CAP_DW_SUCCESS, if data accepted
+** L2CAP_DW_FAILED, if error
+**
+*******************************************************************************/
+L2C_API extern UINT16 L2CA_UcdDataWrite (UINT16 psm, BD_ADDR rem_bda, BT_HDR *p_buf, UINT16 flags);
+
+/*******************************************************************************
+**
+** Function L2CA_UcdSetIdleTimeout
+**
+** Description Set UCD Idle timeout.
+**
+** Parameters: BD Addr
+** Timeout in second
+**
+** Return value: TRUE if successs
+**
+*******************************************************************************/
+L2C_API extern BOOLEAN L2CA_UcdSetIdleTimeout ( BD_ADDR rem_bda, UINT16 timeout );
+
+/*******************************************************************************
+**
+** Function L2CA_UCDSetTxPriority
+**
+** Description Sets the transmission priority for a connectionless channel.
+**
+** Returns TRUE if a valid channel, else FALSE
+**
+*******************************************************************************/
+L2C_API extern BOOLEAN L2CA_UCDSetTxPriority ( BD_ADDR rem_bda, tL2CAP_CHNL_PRIORITY priority );
+
+
+/*******************************************************************************
+**
+** Fixed Channel callback prototypes
+**
+*******************************************************************************/
+
+/* Fixed channel connected and disconnected. Parameters are
+** BD Address of remote
+** TRUE if channel is connected, FALSE if disconnected
+** Reason for connection failure
+*/
+typedef void (tL2CA_FIXED_CHNL_CB) (BD_ADDR, BOOLEAN, UINT16);
+
+/* Signalling data received. Parameters are
+** BD Address of remote
+** Pointer to buffer with data
+*/
+typedef void (tL2CA_FIXED_DATA_CB) (BD_ADDR, BT_HDR *);
+
+/* Fixed channel registration info (the callback addresses and channel config)
+*/
+typedef struct
+{
+ tL2CA_FIXED_CHNL_CB *pL2CA_FixedConn_Cb;
+ tL2CA_FIXED_DATA_CB *pL2CA_FixedData_Cb;
+ tL2CAP_FCR_OPTS fixed_chnl_opts;
+
+ UINT16 default_idle_tout;
+} tL2CAP_FIXED_CHNL_REG;
+
+
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+/*******************************************************************************
+**
+** Function L2CA_RegisterFixedChannel
+**
+** Description Register a fixed channel.
+**
+** Parameters: Fixed Channel #
+** Channel Callbacks and config
+**
+** Return value: TRUE if registered OK
+**
+*******************************************************************************/
+L2C_API extern BOOLEAN L2CA_RegisterFixedChannel (UINT16 fixed_cid, tL2CAP_FIXED_CHNL_REG *p_freg);
+
+/*******************************************************************************
+**
+** Function L2CA_ConnectFixedChnl
+**
+** Description Connect an fixed signalling channel to a remote device.
+**
+** Parameters: Fixed CID
+** BD Address of remote
+**
+** Return value: TRUE if connection started
+**
+*******************************************************************************/
+L2C_API extern BOOLEAN L2CA_ConnectFixedChnl (UINT16 fixed_cid, BD_ADDR bd_addr);
+
+/*******************************************************************************
+**
+** Function L2CA_SendFixedChnlData
+**
+** Description Write data on a fixed signalling channel.
+**
+** Parameters: Fixed CID
+** BD Address of remote
+** Pointer to buffer of type BT_HDR
+**
+** Return value L2CAP_DW_SUCCESS, if data accepted
+** L2CAP_DW_FAILED, if error
+**
+*******************************************************************************/
+L2C_API extern UINT16 L2CA_SendFixedChnlData (UINT16 fixed_cid, BD_ADDR rem_bda, BT_HDR *p_buf);
+
+/*******************************************************************************
+**
+** Function L2CA_RemoveFixedChnl
+**
+** Description Remove a fixed channel to a remote device.
+**
+** Parameters: Fixed CID
+** BD Address of remote
+** Idle timeout to use (or 0xFFFF if don't care)
+**
+** Return value: TRUE if channel removed
+**
+*******************************************************************************/
+L2C_API extern BOOLEAN L2CA_RemoveFixedChnl (UINT16 fixed_cid, BD_ADDR rem_bda);
+
+/*******************************************************************************
+**
+** Function L2CA_SetFixedChannelTout
+**
+** Description Higher layers call this function to set the idle timeout for
+** a fixed channel. The "idle timeout" is the amount of time that
+** a connection can remain up with no L2CAP channels on it.
+** A timeout of zero means that the connection will be torn
+** down immediately when the last channel is removed.
+** A timeout of 0xFFFF means no timeout. Values are in seconds.
+** A bd_addr is the remote BD address. If bd_addr = BT_BD_ANY,
+** then the idle timeouts for all active l2cap links will be
+** changed.
+**
+** Returns TRUE if command succeeded, FALSE if failed
+**
+*******************************************************************************/
+L2C_API extern BOOLEAN L2CA_SetFixedChannelTout (BD_ADDR rem_bda, UINT16 fixed_cid, UINT16 idle_tout);
+
+#endif /* (L2CAP_NUM_FIXED_CHNLS > 0) */
+
+/*******************************************************************************
+**
+** Function L2CA_GetCurrentConfig
+**
+** Description This function returns configurations of L2CAP channel
+** pp_our_cfg : pointer of our saved configuration options
+** p_our_cfg_bits : valid config in bitmap
+** pp_peer_cfg: pointer of peer's saved configuration options
+** p_peer_cfg_bits : valid config in bitmap
+**
+** Returns TRUE if successful
+**
+*******************************************************************************/
+L2C_API extern BOOLEAN L2CA_GetCurrentConfig (UINT16 lcid,
+ tL2CAP_CFG_INFO **pp_our_cfg, tL2CAP_CH_CFG_BITS *p_our_cfg_bits,
+ tL2CAP_CFG_INFO **pp_peer_cfg, tL2CAP_CH_CFG_BITS *p_peer_cfg_bits);
+
+#if (L2CAP_CORRUPT_ERTM_PKTS == TRUE)
+/*******************************************************************************
+**
+** Function L2CA_SetupErtmTest
+**
+** Description This function is used for testing purposes only.
+** It corrupts or drops one or more packets used with ERTM channels.
+**
+** Parameters
+** cid - channel ID (0 uses RFCOMM PSM's CID)
+**
+** type - type of test to run (L2CAP_FCR_TTYPE_CORR_IFRAMES
+** L2CAP_FCR_TTYPE_CORR_SFRAME
+** L2CAP_FCR_TTYPE_STOP_TEST
+** L2CAP_FCR_TTYPE_GET_CID - returns rfcomm cid only)
+**
+** is_rx - TRUE to corrupt Rx packet, FALSE for Tx packet)
+**
+** freq - L2CAP_FCR_FREQ_RANDOM (turns on random corruptions/drops)
+** L2CAP_FCR_FREQ_NORMAL (turns on test with "count" corruptions/drops)
+**
+** count - number of packets in a row to drop or corrupt
+**
+** Returns CID of channel running test
+**
+*******************************************************************************/
+L2C_API extern UINT16 L2CA_SetupErtmTest (UINT16 cid, UINT8 type, BOOLEAN is_rx, UINT8 freq, UINT16 count);
+
+/*******************************************************************************
+**
+** Function L2CA_SendPolledSFrame
+**
+** Description This function is used for testing purposes only.
+** It Sends a Polled RR or RNR to the peer
+**
+** Parameters
+** cid - channel ID
+**
+** sup_type - (L2CAP_FCR_SUP_RR or L2CAP_FCR_SUP_RNR)
+**
+** Returns void
+**
+*******************************************************************************/
+L2C_API extern void L2CA_SendPolledSFrame (UINT16 cid, UINT16 sup_type);
+
+/*******************************************************************************
+**
+** Function L2CA_BypassSFrame
+**
+** Description This function is used for testing purposes only.
+** It skips sending 'count' S-Frames.
+**
+** Parameters
+** cid - channel ID
+**
+** count - Number of S-Frames to skip sending
+**
+** Returns void
+**
+*******************************************************************************/
+L2C_API extern void L2CA_BypassSFrame (UINT16 cid, UINT8 count);
+
+#endif /* (L2CAP_CORRUPT_ERTM_PKTS == TRUE) */
+
+
+#if (BLE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function L2CA_CancelBleConnectReq
+**
+** Description Cancel a pending connection attempt to a BLE device.
+**
+** Parameters: BD Address of remote
+**
+** Return value: TRUE if connection was cancelled
+**
+*******************************************************************************/
+L2C_API extern BOOLEAN L2CA_CancelBleConnectReq (BD_ADDR rem_bda);
+
+/*******************************************************************************
+**
+** Function L2CA_UpdateBleConnParams
+**
+** Description Update BLE connection parameters.
+**
+** Parameters: BD Address of remote
+**
+** Return value: TRUE if update started
+**
+*******************************************************************************/
+L2C_API extern BOOLEAN L2CA_UpdateBleConnParams (BD_ADDR rem_bdRa, UINT16 min_int, UINT16 max_int, UINT16 latency, UINT16 timeout);
+
+/*******************************************************************************
+**
+** Function L2CA_EnableUpdateBleConnParams
+**
+** Description Update BLE connection parameters.
+**
+** Parameters: BD Address of remote
+** enable flag
+**
+** Return value: TRUE if update started
+**
+*******************************************************************************/
+L2C_API extern BOOLEAN L2CA_EnableUpdateBleConnParams (BD_ADDR rem_bda, BOOLEAN enable);
+
+/*******************************************************************************
+**
+** Function L2CA_GetBleConnRole
+**
+** Description This function returns the connection role.
+**
+** Returns link role.
+**
+*******************************************************************************/
+L2C_API extern UINT8 L2CA_GetBleConnRole (BD_ADDR bd_addr);
+
+/*******************************************************************************
+**
+** Function L2CA_GetDisconnectReason
+**
+** Description This function returns the disconnect reason code.
+**
+** Returns disconnect reason
+**
+*******************************************************************************/
+L2C_API extern UINT16 L2CA_GetDisconnectReason (BD_ADDR remote_bda);
+
+#endif /* (BLE_INCLUDED == TRUE) */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* L2C_API_H */
diff --git a/stack/include/l2cdefs.h b/stack/include/l2cdefs.h
new file mode 100644
index 0000000..b2740cd
--- /dev/null
+++ b/stack/include/l2cdefs.h
@@ -0,0 +1,304 @@
+/****************************************************************************
+**
+** Name: l2cdefs.h
+**
+** Function: This file contains L2CAP protocol definitions
+**
+**
+**
+** Copyright (c) 1999-2009, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#ifndef L2CDEFS_H
+#define L2CDEFS_H
+
+/* L2CAP command codes
+*/
+#define L2CAP_CMD_REJECT 0x01
+#define L2CAP_CMD_CONN_REQ 0x02
+#define L2CAP_CMD_CONN_RSP 0x03
+#define L2CAP_CMD_CONFIG_REQ 0x04
+#define L2CAP_CMD_CONFIG_RSP 0x05
+#define L2CAP_CMD_DISC_REQ 0x06
+#define L2CAP_CMD_DISC_RSP 0x07
+#define L2CAP_CMD_ECHO_REQ 0x08
+#define L2CAP_CMD_ECHO_RSP 0x09
+#define L2CAP_CMD_INFO_REQ 0x0A
+#define L2CAP_CMD_INFO_RSP 0x0B
+#define L2CAP_CMD_AMP_CONN_REQ 0x0C
+#define L2CAP_CMD_AMP_CONN_RSP 0x0D
+#define L2CAP_CMD_AMP_MOVE_REQ 0x0E
+#define L2CAP_CMD_AMP_MOVE_RSP 0x0F
+#define L2CAP_CMD_AMP_MOVE_CFM 0x10
+#define L2CAP_CMD_AMP_MOVE_CFM_RSP 0x11
+#define L2CAP_CMD_BLE_UPDATE_REQ 0x12
+#define L2CAP_CMD_BLE_UPDATE_RSP 0x13
+
+
+/* Define some packet and header lengths
+*/
+#define L2CAP_PKT_OVERHEAD 4 /* Length and CID */
+#define L2CAP_CMD_OVERHEAD 4 /* Cmd code, Id and length */
+#define L2CAP_CMD_REJECT_LEN 2 /* Reason (data is optional) */
+#define L2CAP_CONN_REQ_LEN 4 /* PSM and source CID */
+#define L2CAP_CONN_RSP_LEN 8 /* Dest CID, source CID, reason, status */
+#define L2CAP_CONFIG_REQ_LEN 4 /* Dest CID, flags (data is optional) */
+#define L2CAP_CONFIG_RSP_LEN 6 /* Dest CID, flags, result,data optional*/
+#define L2CAP_DISC_REQ_LEN 4 /* Dest CID, source CID */
+#define L2CAP_DISC_RSP_LEN 4 /* Dest CID, source CID */
+#define L2CAP_ECHO_REQ_LEN 0 /* Data is optional */
+#define L2CAP_ECHO_RSP_LEN 0 /* Data is optional */
+#define L2CAP_INFO_REQ_LEN 2 /* Info type */
+#define L2CAP_INFO_RSP_LEN 4 /* Info type, result (data is optional) */
+#define L2CAP_BCST_OVERHEAD 2 /* Additional broadcast packet overhead */
+#define L2CAP_UCD_OVERHEAD 2 /* Additional connectionless packet overhead */
+
+#define L2CAP_AMP_CONN_REQ_LEN 5 /* PSM, CID, and remote controller ID */
+#define L2CAP_AMP_MOVE_REQ_LEN 3 /* CID and remote controller ID */
+#define L2CAP_AMP_MOVE_RSP_LEN 4 /* CID and result */
+#define L2CAP_AMP_MOVE_CFM_LEN 4 /* CID and result */
+#define L2CAP_AMP_MOVE_CFM_RSP_LEN 2 /* CID */
+
+#define L2CAP_CMD_BLE_UPD_REQ_LEN 8 /* Min and max interval, latency, tout */
+#define L2CAP_CMD_BLE_UPD_RSP_LEN 2 /* Result */
+
+
+/* Define the packet boundary flags
+*/
+#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
+#define L2CAP_PKT_START_FLUSHABLE 2
+#define L2CAP_PKT_START_NON_FLUSHABLE 0
+#endif
+#define L2CAP_COMPLETE_AMP_PKT 3 /* complete L2CAP packet on AMP HCI */
+#define L2CAP_PKT_START 2
+#define L2CAP_PKT_CONTINUE 1
+#define L2CAP_MASK_FLAG 0x0FFF
+#define L2CAP_PKT_TYPE_SHIFT 12
+#define L2CAP_PKT_TYPE_MASK 3
+
+
+/* Define the L2CAP connection result codes
+*/
+#define L2CAP_CONN_OK 0
+#define L2CAP_CONN_PENDING 1
+#define L2CAP_CONN_NO_PSM 2
+#define L2CAP_CONN_SECURITY_BLOCK 3
+#define L2CAP_CONN_NO_RESOURCES 4
+#define L2CAP_CONN_BAD_CTLR_ID 5 /* AMP related */
+#define L2CAP_CONN_TIMEOUT 0xEEEE
+#define L2CAP_CONN_AMP_FAILED 254
+#define L2CAP_CONN_NO_LINK 255 /* Add a couple of our own for internal use */
+#define L2CAP_CONN_CANCEL 256 /* L2CAP connection cancelled */
+
+
+/* Define L2CAP Move Channel Response result codes
+*/
+#define L2CAP_MOVE_OK 0
+#define L2CAP_MOVE_PENDING 1
+#define L2CAP_MOVE_CTRL_ID_NOT_SUPPORT 2
+#define L2CAP_MOVE_SAME_CTRLR_ID 3
+#define L2CAP_MOVE_CONFIG_NOT_SUPPORTED 4
+#define L2CAP_MOVE_CHAN_COLLISION 5
+#define L2CAP_MOVE_NOT_ALLOWED 6
+
+
+/* Define L2CAP Move Channel Confirmation result codes
+*/
+#define L2CAP_MOVE_CFM_OK 0
+#define L2CAP_MOVE_CFM_REFUSED 1
+
+
+/* Define the L2CAP command reject reason codes
+*/
+#define L2CAP_CMD_REJ_NOT_UNDERSTOOD 0
+#define L2CAP_CMD_REJ_MTU_EXCEEDED 1
+#define L2CAP_CMD_REJ_INVALID_CID 2
+
+
+/* L2CAP Predefined CIDs (0x0004-0x003E Reserved)
+*/
+#define L2CAP_SIGNALLING_CID 1
+#define L2CAP_CONNECTIONLESS_CID 2
+#define L2CAP_AMP_CID 3
+#define L2CAP_ATT_CID 4
+#define L2CAP_BLE_SIGNALLING_CID 5
+#define L2CAP_SMP_CID 6
+#define L2CAP_AMP_TEST_CID 0x003F
+#define L2CAP_BASE_APPL_CID 0x0040
+
+/* Fixed Channels mask bits
+*/
+#define L2CAP_FIXED_CHNL_SIG_BIT (1 << L2CAP_SIGNALLING_CID) /* Signal Channel Supported (Mandatory) */
+#define L2CAP_FIXED_CHNL_CNCTLESS_BIT (1 << L2CAP_CONNECTIONLESS_CID) /* Connectionless Reception */
+#define L2CAP_FIXED_CHNL_AMP_BIT (1 << L2CAP_AMP_CID) /* AMP Manager Supported */
+#define L2CAP_FIXED_CHNL_ATT_BIT (1 << L2CAP_ATT_CID) /* Attribute protocol Supported */
+#define L2CAP_FIXED_CHNL_BLE_SIG_BIT (1 << L2CAP_BLE_SIGNALLING_CID) /* BLE Signalling Supported */
+#define L2CAP_FIXED_CHNL_SMP_BIT (1 << L2CAP_SMP_CID) /* BLE Security Manager Supported */
+
+
+
+/* Define the L2CAP configuration result codes
+*/
+#define L2CAP_CFG_OK 0
+#define L2CAP_CFG_UNACCEPTABLE_PARAMS 1
+#define L2CAP_CFG_FAILED_NO_REASON 2
+#define L2CAP_CFG_UNKNOWN_OPTIONS 3
+#define L2CAP_CFG_PENDING 4
+#define L2CAP_CFG_FLOW_SPEC_REJECTED 5
+
+
+/* Define the L2CAP configuration option types
+*/
+#define L2CAP_CFG_TYPE_MTU 0x01
+#define L2CAP_CFG_TYPE_FLUSH_TOUT 0x02
+#define L2CAP_CFG_TYPE_QOS 0x03
+#define L2CAP_CFG_TYPE_FCR 0x04
+#define L2CAP_CFG_TYPE_FCS 0x05
+#define L2CAP_CFG_TYPE_EXT_FLOW 0x06
+#define L2CAP_CFG_TYPE_EXT_WIN_SIZE 0x07
+
+#define L2CAP_CFG_MTU_OPTION_LEN 2 /* MTU option length */
+#define L2CAP_CFG_FLUSH_OPTION_LEN 2 /* Flush option len */
+#define L2CAP_CFG_QOS_OPTION_LEN 22 /* QOS option length */
+#define L2CAP_CFG_FCR_OPTION_LEN 9 /* FCR option length */
+#define L2CAP_CFG_FCS_OPTION_LEN 1 /* FCR option length */
+#define L2CAP_CFG_EXT_FLOW_OPTION_LEN 16 /* Extended Flow Spec */
+#define L2CAP_CFG_EXT_WIN_SIZE_LEN 2 /* Ext window size length */
+#define L2CAP_CFG_OPTION_OVERHEAD 2 /* Type and length */
+
+/* Configuration Cmd/Rsp Flags mask
+*/
+#define L2CAP_CFG_FLAGS_MASK_CONT 0x0001 /* Flags mask: Continuation */
+
+/* FCS Check Option values
+*/
+#define L2CAP_CFG_FCS_BYPASS 0 /* Bypass the FCS in streaming or ERTM modes */
+#define L2CAP_CFG_FCS_USE 1 /* Use the FCS in streaming or ERTM modes [default] */
+
+/* Default values for configuration
+*/
+#define L2CAP_NO_AUTOMATIC_FLUSH 0xFFFF
+#define L2CAP_NO_RETRANSMISSION 0x0001
+
+#define L2CAP_DEFAULT_MTU (672)
+#define L2CAP_DEFAULT_FLUSH_TO L2CAP_NO_AUTOMATIC_FLUSH
+#define L2CAP_DEFAULT_SERV_TYPE 1
+#define L2CAP_DEFAULT_TOKEN_RATE 0
+#define L2CAP_DEFAULT_BUCKET_SIZE 0
+#define L2CAP_DEFAULT_PEAK_BANDWIDTH 0
+#define L2CAP_DEFAULT_LATENCY 0xFFFFFFFF
+#define L2CAP_DEFAULT_DELAY 0xFFFFFFFF
+#define L2CAP_DEFAULT_FCS L2CAP_CFG_FCS_USE
+
+
+/* Define the L2CAP disconnect result codes
+*/
+#define L2CAP_DISC_OK 0
+#define L2CAP_DISC_TIMEOUT 0xEEEE
+
+/* Define the L2CAP info resp result codes
+*/
+#define L2CAP_INFO_RESP_RESULT_SUCCESS 0
+#define L2CAP_INFO_RESP_RESULT_NOT_SUPPORTED 1
+
+/* Define the info-type fields of information request & response
+*/
+#define L2CAP_CONNLESS_MTU_INFO_TYPE 0x0001
+#define L2CAP_EXTENDED_FEATURES_INFO_TYPE 0x0002 /* Used in Information Req/Response */
+#define L2CAP_FIXED_CHANNELS_INFO_TYPE 0x0003 /* Used in AMP */
+
+#define L2CAP_CONNLESS_MTU_INFO_SIZE 2 /* Connectionless MTU size */
+#define L2CAP_EXTENDED_FEATURES_ARRAY_SIZE 4 /* Extended features array size */
+#define L2CAP_FIXED_CHNL_ARRAY_SIZE 8 /* Fixed channel array size */
+
+/* Extended features mask bits
+*/
+#define L2CAP_EXTFEA_RTRANS 0x00000001 /* Retransmission Mode (Not Supported) */
+#define L2CAP_EXTFEA_FC 0x00000002 /* Flow Control Mode (Not Supported) */
+#define L2CAP_EXTFEA_QOS 0x00000004
+#define L2CAP_EXTFEA_ENH_RETRANS 0x00000008 /* Enhanced retransmission mode */
+#define L2CAP_EXTFEA_STREAM_MODE 0x00000010 /* Streaming Mode */
+#define L2CAP_EXTFEA_NO_CRC 0x00000020 /* Optional FCS (if set No FCS desired) */
+#define L2CAP_EXTFEA_EXT_FLOW_SPEC 0x00000040 /* Extended flow spec */
+#define L2CAP_EXTFEA_FIXED_CHNLS 0x00000080 /* Fixed channels */
+#define L2CAP_EXTFEA_EXT_WINDOW 0x00000100 /* Extended Window Size */
+#define L2CAP_EXTFEA_UCD_RECEPTION 0x00000200 /* Unicast Connectionless Data Reception */
+
+/* Mask for locally supported features used in Information Response (default to none) */
+#ifndef L2CAP_EXTFEA_SUPPORTED_MASK
+#define L2CAP_EXTFEA_SUPPORTED_MASK 0
+#endif
+
+/* Mask for LE supported features used in Information Response (default to none) */
+#ifndef L2CAP_BLE_EXTFEA_MASK
+#define L2CAP_BLE_EXTFEA_MASK 0
+#endif
+
+/* Define a value that tells L2CAP to use the default HCI ACL buffer pool */
+#define L2CAP_DEFAULT_ERM_POOL_ID 0xFF
+/* Define a value that tells L2CAP to use the default MPS */
+#define L2CAP_DEFAULT_ERM_MPS 0x0000
+
+#define L2CAP_FCR_OVERHEAD 2 /* Control word */
+#define L2CAP_FCS_LEN 2 /* FCS takes 2 bytes */
+#define L2CAP_SDU_LEN_OVERHEAD 2 /* SDU length field is 2 bytes */
+#define L2CAP_SDU_LEN_OFFSET 2 /* SDU length offset is 2 bytes */
+#define L2CAP_EXT_CONTROL_OVERHEAD 4 /* Extended Control Field */
+#define L2CAP_MAX_HEADER_FCS (L2CAP_PKT_OVERHEAD + L2CAP_EXT_CONTROL_OVERHEAD + L2CAP_SDU_LEN_OVERHEAD + L2CAP_FCS_LEN)
+ /* length(2), channel(2), control(4), SDU length(2) FCS(2) */
+/* Part of L2CAP_MIN_OFFSET that is not part of L2CAP
+*/
+#define L2CAP_OFFSET_WO_L2HDR (L2CAP_MIN_OFFSET-(L2CAP_PKT_OVERHEAD+L2CAP_FCR_OVERHEAD))
+
+/* SAR bits in the control word
+*/
+#define L2CAP_FCR_UNSEG_SDU 0x0000 /* Control word to begin with for unsegmented PDU*/
+#define L2CAP_FCR_START_SDU 0x4000 /* ...for Starting PDU of a semented SDU */
+#define L2CAP_FCR_END_SDU 0x8000 /* ...for ending PDU of a segmented SDU */
+#define L2CAP_FCR_CONT_SDU 0xc000 /* ...for continuation PDU of a segmented SDU */
+
+/* Supervisory frame types
+*/
+#define L2CAP_FCR_SUP_RR 0x0000 /* Supervisory frame - RR */
+#define L2CAP_FCR_SUP_REJ 0x0001 /* Supervisory frame - REJ */
+#define L2CAP_FCR_SUP_RNR 0x0002 /* Supervisory frame - RNR */
+#define L2CAP_FCR_SUP_SREJ 0x0003 /* Supervisory frame - SREJ */
+
+#define L2CAP_FCR_SAR_BITS 0xC000 /* Mask to get the SAR bits from control word */
+#define L2CAP_FCR_SAR_BITS_SHIFT 14 /* Bits to shift right to get the SAR bits from ctrl-word */
+
+#define L2CAP_FCR_S_FRAME_BIT 0x0001 /* Mask to check if a PDU is S-frame */
+#define L2CAP_FCR_REQ_SEQ_BITS 0x3F00 /* Mask to get the req-seq from control word */
+#define L2CAP_FCR_REQ_SEQ_BITS_SHIFT 8 /* Bits to shift right to get the req-seq from ctrl-word */
+#define L2CAP_FCR_TX_SEQ_BITS 0x007E /* Mask on get the tx-seq from control word */
+#define L2CAP_FCR_TX_SEQ_BITS_SHIFT 1 /* Bits to shift right to get the tx-seq from ctrl-word */
+
+#define L2CAP_FCR_F_BIT 0x0080 /* F-bit in the control word (Sup and I frames) */
+#define L2CAP_FCR_P_BIT 0x0010 /* P-bit in the control word (Sup frames only) */
+
+#define L2CAP_FCR_F_BIT_SHIFT 7
+#define L2CAP_FCR_P_BIT_SHIFT 4
+
+#define L2CAP_FCR_SEG_BITS 0xC000 /* Mask to get the segmentation bits from ctrl-word */
+#define L2CAP_FCR_SUP_SHIFT 2 /* Bits to shift right to get the S-bits from ctrl-word */
+#define L2CAP_FCR_SUP_BITS 0x000C /* Mask to get the supervisory bits from ctrl-word */
+
+#define L2CAP_FCR_INIT_CRC 0 /* Initial state of the CRC register */
+#define L2CAP_FCR_SEQ_MODULO 0x3F /* Mask for sequence numbers (range 0 - 63) */
+
+/*************************************************************************************************
+** The following definitions are only used for internal testing of ERTM at the application level
+*************************************************************************************************/
+/* L2CA_SetupErtmTest() corruption test types */
+#define L2CAP_FCR_TTYPE_CORR_IFRAME 0 /* Corrupt one or more I-frames, based on count */
+#define L2CAP_FCR_TTYPE_CORR_SFRAME 1 /* Corrupt an S-frame, (acknowledgement) */
+#define L2CAP_FCR_TTYPE_STOP_TEST 2 /* Used when turning off a test */
+#define L2CAP_FCR_TTYPE_GET_CID 3 /* Returns RFCOMM cid when '0' is passed in cid argument */
+
+/* L2CA_SetupErtmTest() Freq */
+#define L2CAP_FCR_FREQ_NORMAL 0 /* A single test is run */
+#define L2CAP_FCR_FREQ_RANDOM 1 /* Randomly loses or corrupts a packet */
+
+#endif
diff --git a/stack/include/mca_api.h b/stack/include/mca_api.h
new file mode 100644
index 0000000..4ac2c89
--- /dev/null
+++ b/stack/include/mca_api.h
@@ -0,0 +1,482 @@
+/*****************************************************************************
+**
+** Name: mca_api.h
+**
+** Description: This interface file contains the interface to the
+** Multi-Channel Adaptation Protocol (MCAP).
+**
+** Copyright (c) 2009-2009, Broadcom Corp., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef MCA_API_H
+#define MCA_API_H
+
+#include "bt_target.h"
+#include "l2c_api.h"
+
+/* move the following to bt_target.h or other place later */
+#define MCA_NUM_TC_TBL ((MCA_NUM_REGS)*(MCA_NUM_LINKS)*(MCA_NUM_MDLS+1))
+#define MCA_NUM_CCBS ((MCA_NUM_REGS)*(MCA_NUM_LINKS)) /* Number of control channel control blocks */
+#define MCA_NUM_DCBS ((MCA_NUM_REGS)*(MCA_NUM_LINKS)*(MCA_NUM_MDLS)) /* Number of data channel control blocks */
+
+
+/*****************************************************************************
+** constants
+*****************************************************************************/
+/* API function return value result codes. */
+#define MCA_SUCCESS 0 /* Function successful */
+#define MCA_BAD_PARAMS 1 /* Invalid parameters */
+#define MCA_NO_RESOURCES 2 /* Not enough resources */
+#define MCA_BAD_HANDLE 3 /* Bad handle */
+#define MCA_BUSY 4 /* A procedure is already in progress */
+#define MCA_WRITE_FAIL 5 /* Write failed */
+#define MCA_BAD_MDL_ID 6 /* MDL ID is not valid for the current API */
+typedef UINT8 tMCA_RESULT;
+
+/* MDEP data type. */
+#define MCA_TDEP_ECHO 0 /* MDEP for echo test */
+#define MCA_TDEP_DATA 1 /* MDEP for normal data */
+
+/* Control callback events. */
+#define MCA_ERROR_RSP_EVT 0 /* error response */
+#define MCA_CREATE_IND_EVT 1 /* create mdl indication */
+#define MCA_CREATE_CFM_EVT 2 /* create mdl confirm */
+#define MCA_RECONNECT_IND_EVT 3 /* reconnect mdl indication */
+#define MCA_RECONNECT_CFM_EVT 4 /* reconnect mdl confirm */
+#define MCA_ABORT_IND_EVT 5 /* abort mdl indication */
+#define MCA_ABORT_CFM_EVT 6 /* abort mdl confirm */
+#define MCA_DELETE_IND_EVT 7 /* delete mdl indication */
+#define MCA_DELETE_CFM_EVT 8 /* delete mdl confirm */
+
+#define MCA_SYNC_CAP_IND_EVT 0x11 /* request sync capabilities & requirements */
+#define MCA_SYNC_CAP_CFM_EVT 0x12 /* indicate completion */
+#define MCA_SYNC_SET_IND_EVT 0x13 /* request to set the time-stamp clock */
+#define MCA_SYNC_SET_CFM_EVT 0x14 /* indicate completion */
+#define MCA_SYNC_INFO_IND_EVT 0x15 /* update of the actual time-stamp clock instant from the sync slave */
+
+#define MCA_CONNECT_IND_EVT 0x20 /* Control channel connected */
+#define MCA_DISCONNECT_IND_EVT 0x21 /* Control channel disconnected */
+#define MCA_OPEN_IND_EVT 0x22 /* Data channel open indication */
+#define MCA_OPEN_CFM_EVT 0x23 /* Data channel open confirm */
+#define MCA_CLOSE_IND_EVT 0x24 /* Data channel close indication */
+#define MCA_CLOSE_CFM_EVT 0x25 /* Data channel close confirm */
+#define MCA_CONG_CHG_EVT 0x26 /* congestion change event */
+#define MCA_RSP_TOUT_IND_EVT 0x27 /* Control channel message response timeout */
+/*****************************************************************************
+** Type Definitions
+*****************************************************************************/
+typedef UINT8 tMCA_HANDLE; /* the handle for registration. 1 based index to rcb */
+typedef UINT8 tMCA_CL; /* the handle for a control channel; reported at MCA_CONNECT_IND_EVT */
+typedef UINT8 tMCA_DEP; /* the handle for MCA_CreateDep. This is also the local mdep_id */
+typedef UINT16 tMCA_DL; /* the handle for the data channel. This is reported at MCA_OPEN_CFM_EVT or MCA_OPEN_IND_EVT */
+
+/* This is the data callback function. It is executed when MCAP has a data
+** packet ready for the application.
+*/
+typedef void (tMCA_DATA_CBACK)(tMCA_DL mdl, BT_HDR *p_pkt);
+
+
+/* This structure contains parameters which are set at registration. */
+typedef struct {
+ UINT32 rsp_tout; /* MCAP signaling response timeout */
+ UINT16 ctrl_psm; /* L2CAP PSM for the MCAP control channel */
+ UINT16 data_psm; /* L2CAP PSM for the MCAP data channel */
+ UINT16 sec_mask; /* Security mask for BTM_SetSecurityLevel() */
+} tMCA_REG;
+
+/* This structure contains parameters to create a MDEP. */
+typedef struct {
+ UINT8 type; /* MCA_TDEP_DATA, or MCA_TDEP_ECHO. a regiatration may have only one MCA_TDEP_ECHO MDEP */
+ UINT8 max_mdl; /* The maximum number of MDLs for this MDEP (max is MCA_NUM_MDLS) */
+ tMCA_DATA_CBACK *p_data_cback; /* Data callback function */
+} tMCA_CS;
+
+#define MCA_FCS_NONE 0 /* fcs_present=FALSE */
+#define MCA_FCS_BYPASS 0x10 /* fcs_present=TRUE, fcs=L2CAP_CFG_FCS_BYPASS */
+#define MCA_FCS_USE 0x11 /* fcs_present=TRUE, fcs=L2CAP_CFG_FCS_USE */
+#define MCA_FCS_PRESNT_MASK 0x10 /* fcs_present=TRUE */
+#define MCA_FCS_USE_MASK 0x01 /* mask for fcs */
+typedef UINT8 tMCA_FCS_OPT;
+
+/* This structure contains L2CAP configuration parameters for the channel. */
+typedef struct {
+ tL2CAP_FCR_OPTS fcr_opt;
+ UINT8 user_rx_pool_id;
+ UINT8 user_tx_pool_id;
+ UINT8 fcr_rx_pool_id;
+ UINT8 fcr_tx_pool_id;
+ tMCA_FCS_OPT fcs;
+ UINT16 data_mtu; /* L2CAP MTU of the MCAP data channel */
+} tMCA_CHNL_CFG;
+
+
+/* Header structure for callback event parameters. */
+typedef struct {
+ UINT16 mdl_id; /* The associated MDL ID */
+ UINT8 op_code; /* The op (request/response) code */
+} tMCA_EVT_HDR;
+
+/* Response Header structure for callback event parameters. */
+typedef struct {
+ UINT16 mdl_id; /* The associated MDL ID */
+ UINT8 op_code; /* The op (request/response) code */
+ UINT8 rsp_code; /* The response code */
+} tMCA_RSP_EVT;
+
+/* This data structure is associated with the MCA_CREATE_IND_EVT. */
+typedef struct {
+ UINT16 mdl_id; /* The associated MDL ID */
+ UINT8 op_code; /* The op (request/response) code */
+ UINT8 dep_id; /* MDEP ID */
+ UINT8 cfg; /* The configuration to negotiate */
+} tMCA_CREATE_IND;
+
+/* This data structure is associated with the MCA_CREATE_CFM_EVT. */
+typedef struct {
+ UINT16 mdl_id; /* The associated MDL ID */
+ UINT8 op_code; /* The op (request/response) code */
+ UINT8 rsp_code; /* The response code. */
+ UINT8 cfg; /* The configuration to negotiate */
+} tMCA_CREATE_CFM;
+
+/* This data structure is associated with MCA_CONNECT_IND_EVT. */
+typedef struct {
+ BD_ADDR bd_addr; /* The peer address */
+ UINT16 mtu; /* peer mtu */
+} tMCA_CONNECT_IND;
+
+/* This data structure is associated with MCA_DISCONNECT_IND_EVT. */
+typedef struct {
+ BD_ADDR bd_addr; /* The peer address */
+ UINT16 reason; /* disconnect reason given by L2CAP */
+} tMCA_DISCONNECT_IND;
+
+/* This data structure is associated with MCA_OPEN_IND_EVT, and MCA_OPEN_CFM_EVT. */
+typedef struct {
+ UINT16 mdl_id; /* The associated MDL ID */
+ tMCA_DL mdl; /* The handle for the data channel */
+ UINT16 mtu; /* peer mtu */
+} tMCA_DL_OPEN;
+
+/* This data structure is associated with MCA_CLOSE_IND_EVT and MCA_CLOSE_CFM_EVT. */
+typedef struct {
+ UINT16 mdl_id; /* The associated MDL ID */
+ tMCA_DL mdl; /* The handle for the data channel */
+ UINT16 reason; /* disconnect reason given by L2CAP */
+} tMCA_DL_CLOSE;
+
+/* This data structure is associated with MCA_CONG_CHG_EVT. */
+typedef struct {
+ UINT16 mdl_id; /* N/A - This is a place holder */
+ tMCA_DL mdl; /* The handle for the data channel */
+ BOOLEAN cong; /* TRUE, if the channel is congested */
+} tMCA_CONG_CHG;
+
+/* Union of all control callback event data structures */
+typedef union {
+ tMCA_EVT_HDR hdr;
+ tMCA_RSP_EVT rsp;
+ tMCA_CREATE_IND create_ind;
+ tMCA_CREATE_CFM create_cfm;
+ tMCA_EVT_HDR reconnect_ind;
+ tMCA_RSP_EVT reconnect_cfm;
+ tMCA_EVT_HDR abort_ind;
+ tMCA_RSP_EVT abort_cfm;
+ tMCA_EVT_HDR delete_ind;
+ tMCA_RSP_EVT delete_cfm;
+ tMCA_CONNECT_IND connect_ind;
+ tMCA_DISCONNECT_IND disconnect_ind;
+ tMCA_DL_OPEN open_ind;
+ tMCA_DL_OPEN open_cfm;
+ tMCA_DL_CLOSE close_ind;
+ tMCA_DL_CLOSE close_cfm;
+ tMCA_CONG_CHG cong_chg;
+} tMCA_CTRL;
+
+/* This is the control callback function. This function passes control events
+** to the application.
+*/
+typedef void (tMCA_CTRL_CBACK)(tMCA_HANDLE handle, tMCA_CL mcl, UINT8 event,
+ tMCA_CTRL *p_data);
+
+
+/*******************************************************************************
+**
+** Function MCA_Init
+**
+** Description Initialize MCAP internal control blocks.
+** This function is called at stack start up.
+**
+** Returns void
+**
+*******************************************************************************/
+MCA_API extern void MCA_Init(void);
+
+/*******************************************************************************
+**
+** Function MCA_SetTraceLevel
+**
+** Description This function sets the debug trace level for MCA.
+** If 0xff is passed, the current trace level is returned.
+**
+** Input Parameters:
+** level: The level to set the MCA tracing to:
+** 0xff-returns the current setting.
+** 0-turns off tracing.
+** >= 1-Errors.
+** >= 2-Warnings.
+** >= 3-APIs.
+** >= 4-Events.
+** >= 5-Debug.
+**
+** Returns The new trace level or current trace level if
+** the input parameter is 0xff.
+**
+*******************************************************************************/
+MCA_API extern UINT8 MCA_SetTraceLevel (UINT8 level);
+
+/*******************************************************************************
+**
+** Function MCA_Register
+**
+** Description This function registers an MCAP implementation.
+** It is assumed that the control channel PSM and data channel
+** PSM are not used by any other instances of the stack.
+** If the given p_reg->ctrl_psm is 0, this handle is INT only.
+**
+** Returns 0, if failed. Otherwise, the MCA handle.
+**
+*******************************************************************************/
+MCA_API extern tMCA_HANDLE MCA_Register(tMCA_REG *p_reg, tMCA_CTRL_CBACK *p_cback);
+
+/*******************************************************************************
+**
+** Function MCA_Deregister
+**
+** Description This function is called to deregister an MCAP implementation.
+** Before this function can be called, all control and data
+** channels must be removed with MCA_DisconnectReq and MCA_CloseReq.
+**
+** Returns void
+**
+*******************************************************************************/
+MCA_API extern void MCA_Deregister(tMCA_HANDLE handle);
+
+/*******************************************************************************
+**
+** Function MCA_CreateDep
+**
+** Description Create a data endpoint. If the MDEP is created successfully,
+** the MDEP ID is returned in *p_dep. After a data endpoint is
+** created, an application can initiate a connection between this
+** endpoint and an endpoint on a peer device.
+**
+** Returns MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+MCA_API extern tMCA_RESULT MCA_CreateDep(tMCA_HANDLE handle, tMCA_DEP *p_dep, tMCA_CS *p_cs);
+
+/*******************************************************************************
+**
+** Function MCA_DeleteDep
+**
+** Description Delete a data endpoint. This function is called when
+** the implementation is no longer using a data endpoint.
+** If this function is called when the endpoint is connected
+** the connection is closed and the data endpoint
+** is removed.
+**
+** Returns MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+MCA_API extern tMCA_RESULT MCA_DeleteDep(tMCA_HANDLE handle, tMCA_DEP dep);
+
+/*******************************************************************************
+**
+** Function MCA_ConnectReq
+**
+** Description This function initiates an MCAP control channel connection
+** to the peer device. When the connection is completed, an
+** MCA_CONNECT_IND_EVT is reported to the application via its
+** control callback function.
+** This control channel is identified by tMCA_CL.
+** If the connection attempt fails, an MCA_DISCONNECT_IND_EVT is
+** reported. The security mask parameter overrides the outgoing
+** security mask set in MCA_Register().
+**
+** Returns MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+MCA_API extern tMCA_RESULT MCA_ConnectReq(tMCA_HANDLE handle, BD_ADDR bd_addr,
+ UINT16 ctrl_psm,
+ UINT16 sec_mask);
+
+/*******************************************************************************
+**
+** Function MCA_DisconnectReq
+**
+** Description This function disconnect an MCAP control channel
+** to the peer device.
+** If associated data channel exists, they are disconnected.
+** When the MCL is disconnected an MCA_DISCONNECT_IND_EVT is
+** reported to the application via its control callback function.
+**
+** Returns MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+MCA_API extern tMCA_RESULT MCA_DisconnectReq(tMCA_CL mcl);
+
+/*******************************************************************************
+**
+** Function MCA_CreateMdl
+**
+** Description This function sends a CREATE_MDL request to the peer device.
+** When the response is received, a MCA_CREATE_CFM_EVT is reported
+** with the given MDL ID.
+** If the response is successful, a data channel is open
+** with the given p_chnl_cfg
+** When the data channel is open successfully, a MCA_OPEN_CFM_EVT
+** is reported. This data channel is identified as tMCA_DL.
+**
+** Returns MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+MCA_API extern tMCA_RESULT MCA_CreateMdl(tMCA_CL mcl, tMCA_DEP dep, UINT16 data_psm,
+ UINT16 mdl_id, UINT8 peer_dep_id,
+ UINT8 cfg, const tMCA_CHNL_CFG *p_chnl_cfg);
+
+/*******************************************************************************
+**
+** Function MCA_CreateMdlRsp
+**
+** Description This function sends a CREATE_MDL response to the peer device
+** in response to a received MCA_CREATE_IND_EVT.
+** If the rsp_code is successful, a data channel is open
+** with the given p_chnl_cfg
+** When the data channel is open successfully, a MCA_OPEN_IND_EVT
+** is reported. This data channel is identified as tMCA_DL.
+**
+** Returns MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+MCA_API extern tMCA_RESULT MCA_CreateMdlRsp(tMCA_CL mcl, tMCA_DEP dep,
+ UINT16 mdl_id, UINT8 cfg, UINT8 rsp_code,
+ const tMCA_CHNL_CFG *p_chnl_cfg);
+
+/*******************************************************************************
+**
+** Function MCA_CloseReq
+**
+** Description Close a data channel. When the channel is closed, an
+** MCA_CLOSE_CFM_EVT is sent to the application via the
+** control callback function for this handle.
+**
+** Returns MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+MCA_API extern tMCA_RESULT MCA_CloseReq(tMCA_DL mdl);
+
+/*******************************************************************************
+**
+** Function MCA_ReconnectMdl
+**
+** Description This function sends a RECONNECT_MDL request to the peer device.
+** When the response is received, a MCA_RECONNECT_CFM_EVT is reported.
+** If the response is successful, a data channel is open.
+** When the data channel is open successfully, a MCA_OPEN_CFM_EVT
+** is reported.
+**
+** Returns MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+MCA_API extern tMCA_RESULT MCA_ReconnectMdl(tMCA_CL mcl, tMCA_DEP dep, UINT16 data_psm,
+ UINT16 mdl_id, const tMCA_CHNL_CFG *p_chnl_cfg);
+
+/*******************************************************************************
+**
+** Function MCA_ReconnectMdlRsp
+**
+** Description This function sends a RECONNECT_MDL response to the peer device
+** in response to a MCA_RECONNECT_IND_EVT event.
+** If the response is successful, a data channel is open.
+** When the data channel is open successfully, a MCA_OPEN_IND_EVT
+** is reported.
+**
+** Returns MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+MCA_API extern tMCA_RESULT MCA_ReconnectMdlRsp(tMCA_CL mcl, tMCA_DEP dep,
+ UINT16 mdl_id, UINT8 rsp_code,
+ const tMCA_CHNL_CFG *p_chnl_cfg);
+
+/*******************************************************************************
+**
+** Function MCA_DataChnlCfg
+**
+** Description This function initiates a data channel connection toward the
+** connected peer device.
+** When the data channel is open successfully, a MCA_OPEN_CFM_EVT
+** is reported. This data channel is identified as tMCA_DL.
+**
+** Returns MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+MCA_API extern tMCA_RESULT MCA_DataChnlCfg(tMCA_CL mcl, const tMCA_CHNL_CFG *p_chnl_cfg);
+
+/*******************************************************************************
+**
+** Function MCA_Abort
+**
+** Description This function sends a ABORT_MDL request to the peer device.
+** When the response is received, a MCA_ABORT_CFM_EVT is reported.
+**
+** Returns MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+MCA_API extern tMCA_RESULT MCA_Abort(tMCA_CL mcl);
+
+/*******************************************************************************
+**
+** Function MCA_Delete
+**
+** Description This function sends a DELETE_MDL request to the peer device.
+** When the response is received, a MCA_DELETE_CFM_EVT is reported.
+**
+** Returns MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+MCA_API extern tMCA_RESULT MCA_Delete(tMCA_CL mcl, UINT16 mdl_id);
+
+/*******************************************************************************
+**
+** Function MCA_WriteReq
+**
+** Description Send a data packet to the peer device.
+**
+** The application passes the packet using the BT_HDR structure.
+** The offset field must be equal to or greater than L2CAP_MIN_OFFSET.
+** This allows enough space in the buffer for the L2CAP header.
+**
+** The memory pointed to by p_pkt must be a GKI buffer
+** allocated by the application. This buffer will be freed
+** by the protocol stack; the application must not free
+** this buffer.
+**
+** Returns MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+MCA_API extern tMCA_RESULT MCA_WriteReq(tMCA_DL mdl, BT_HDR *p_pkt);
+
+/*******************************************************************************
+**
+** Function MCA_GetL2CapChannel
+**
+** Description Get the L2CAP CID used by the given data channel handle.
+**
+** Returns L2CAP channel ID if successful, otherwise 0.
+**
+*******************************************************************************/
+MCA_API extern UINT16 MCA_GetL2CapChannel (tMCA_DL mdl);
+
+#endif /* MCA_API_H */
diff --git a/stack/include/mca_defs.h b/stack/include/mca_defs.h
new file mode 100644
index 0000000..aebf315
--- /dev/null
+++ b/stack/include/mca_defs.h
@@ -0,0 +1,75 @@
+/*****************************************************************************
+**
+** Name: mca_defs.h
+**
+** Description: This contains constants definitions and other information
+** from the MCAP specification.
+**
+**
+** Copyright (c) 2009-2009, Broadcom Corp., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef MCA_DEFS_H
+#define MCA_DEFS_H
+
+/*****************************************************************************
+** constants
+*****************************************************************************/
+#define MCA_MIN_MTU 48
+
+/* standard op codes */
+#define MCA_OP_ERROR_RSP 0x00 /* invalid opcode response */
+#define MCA_OP_MDL_CREATE_REQ 0x01 /* create an MDL, wait for an associated data channel connection */
+#define MCA_OP_MDL_CREATE_RSP 0x02 /* response to above request */
+#define MCA_OP_MDL_RECONNECT_REQ 0x03 /* req to prepare to rvc a data channel conn associated with a prev MDL */
+#define MCA_OP_MDL_RECONNECT_RSP 0x04 /* response to above request */
+#define MCA_OP_MDL_ABORT_REQ 0x05 /* stop waiting for a data channel connection */
+#define MCA_OP_MDL_ABORT_RSP 0x06 /* response to above request */
+#define MCA_OP_MDL_DELETE_REQ 0x07 /* delete an MDL */
+#define MCA_OP_MDL_DELETE_RSP 0x08 /* response to above request */
+#define MCA_NUM_STANDARD_OPCODE (1+MCA_OP_MDL_DELETE_RSP)
+
+/* clock synchronization op codes */
+#define MCA_OP_SYNC_CAP_REQ 0x11 /* request sync capabilities & requirements */
+#define MCA_OP_SYNC_CAP_RSP 0x12 /* indicate completion */
+#define MCA_OP_SYNC_SET_REQ 0x13 /* request to set the time-stamp clock */
+#define MCA_OP_SYNC_SET_RSP 0x14 /* indicate completion */
+#define MCA_OP_SYNC_INFO_IND 0x15 /* update of the actual time-stamp clock instant from the sync slave */
+
+#define MCA_FIRST_SYNC_OP MCA_OP_SYNC_CAP_REQ
+#define MCA_LAST_SYNC_OP MCA_OP_SYNC_INFO_IND
+
+/* response code */
+#define MCA_RSP_SUCCESS 0x00 /* The corresponding request was received and processed successfully. */
+#define MCA_RSP_BAD_OPCODE 0x01 /* The Op Code received is not valid (i.e. neither a Standard Op Code nor a Clock Synchronization Protocol Op Code). */
+#define MCA_RSP_BAD_PARAM 0x02 /* One or more of the values in the received request is invalid. */
+/* MCA_RSP_BAD_PARAM shall be used when:
+- The request length is invalid
+- Some of the parameters have invalid values and none of the other defined Response Codes are more appropriate.
+*/
+#define MCA_RSP_BAD_MDEP 0x03 /* The MDEP ID referenced does not exist on this device. */
+#define MCA_RSP_MDEP_BUSY 0x04 /* The requested MDEP currently has as many active MDLs as it can manage simultaneously. */
+#define MCA_RSP_BAD_MDL 0x05 /* The MDL ID referenced is invalid. */
+/* MCA_RSP_BAD_MDL shall be used when:
+- A reserved or invalid value for MDL ID was used.
+- The MDL ID referenced is not available (was never created, has been deleted, or was otherwise lost),
+- The MDL ID referenced in the Abort request is not the same value that was used to initiate the PENDING state
+*/
+#define MCA_RSP_MDL_BUSY 0x06 /* The device is temporarily unable to complete the request. This is intended for reasons not related to the physical sensor (e.g. communication resources unavailable). */
+#define MCA_RSP_BAD_OP 0x07 /* The received request is invalid in the current state. */
+/* MCA_RSP_BAD_OP is used when
+- Abort request was received while not in the PENDING state.
+- Create, Reconnect, or Delete request was received while in the PENDING state.
+- A response is received when a request is expected
+*/
+#define MCA_RSP_NO_RESOURCE 0x08 /* The device is temporarily unable to complete the request. This is intended for reasons relating to the physical sensor (e.g. hardware fault, low battery), or when processing resources are temporarily committed to other processes. */
+#define MCA_RSP_ERROR 0x09 /* An internal error other than those listed in this table was encountered while processing the request. */
+#define MCA_RSP_NO_SUPPORT 0x0A /* The Op Code that was used in this request is not supported. */
+#define MCA_RSP_CFG_REJ 0x0B /* A configuration required by a MD_CREATE_MDL or MD_RECONNECT_MDL operation has been rejected. */
+
+#define MCA_MAX_MDEP_ID 0x7F /* the valid range for MDEP ID is 1-0x7F */
+#define MCA_IS_VALID_MDL_ID(xxx) (((xxx)>0) && ((xxx)<=0xFEFF))
+#define MCA_ALL_MDL_ID 0xFFFF
+
+#endif /* MCA_DEFS_H */
diff --git a/stack/include/obx_api.h b/stack/include/obx_api.h
new file mode 100644
index 0000000..ab6cae6
--- /dev/null
+++ b/stack/include/obx_api.h
@@ -0,0 +1,1697 @@
+/*****************************************************************************
+**
+** Name: obx_api.h
+**
+** File: Object Exchange Protocol Application Programming Interface
+**
+** Copyright (c) 2003-2009, Broadcom Corp., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef OBX_API_H
+#define OBX_API_H
+#include "bt_target.h"
+#include "bt_types.h"
+#include "l2c_api.h"
+
+/* 18 is 7/OBX_CONN_HDRS_OFFSET + 5/conn id, 2/ssn, 2/srm 2/srm_param */
+#define OBX_HDR_OFFSET (18 + L2CAP_MIN_OFFSET)
+#define OBX_MAX_TRIPLET 3
+
+#define OBX_MIN_MTU 255 /* per IrOBEX spec */
+#define OBX_MAX_MTU (OBX_LRG_DATA_POOL_SIZE - BT_HDR_SIZE - OBX_HDR_OFFSET)
+
+#define OBX_CONN_ID_SIZE 4
+#define OBX_PKT_LEN_SIZE 2
+
+#define OBX_CONN_HDRS_OFFSET 7
+#define OBX_SESS_HDRS_OFFSET 3
+#define OBX_DISCON_HDRS_OFFSET 3
+#define OBX_PUT_HDRS_OFFSET 3
+#define OBX_GET_HDRS_OFFSET 3
+#define OBX_SETPATH_REQ_HDRS_OFFSET 5
+#define OBX_ABORT_HDRS_OFFSET 3
+#define OBX_ACTION_HDRS_OFFSET 3
+#define OBX_RESPONSE_HDRS_OFFSET 3
+
+/* this is not needed if OBX_HDR_OFFSET is 18+ */
+#define OBX_MAX_CONN_HDR_EXTRA 8 /* 5/conn id, 2/ssn, 2/srm 2/srm_param - (5/setpath + 5/conn_id - 7/conn) */
+
+/* offset for header functions to access fields */
+#define OBX_CONNECT_MTU_OFFSET 5
+#define OBX_SETPATH_FLAG_OFFSET 3
+
+#define OBX_MAX_NUM_AUTH_TRIPLET 3
+#define OBX_UNICODE_SIZE 2 /* sizeof(UINT16) */
+
+#define OBX_INVALID_HDR_LEN 0xFFFF
+
+#define OBX_MIN_NONCE_SIZE 4 /* fixed size per IrOBEX spec */
+#define OBX_NONCE_SIZE 16 /* fixed size per IrOBEX spec */
+#define OBX_DIGEST_SIZE 16 /* fixed size per IrOBEX spec */
+#define OBX_MAX_AUTH_KEY_SIZE 16
+#define OBX_MAX_AUTH_USER_SIZE 20
+#define OBX_SESSION_ID_SIZE 16 /* fixed size per IrOBEX spec */
+#define OBX_SESSION_INFO_SIZE 32 /* OBX_SESSION_ID_SIZE + 4(local nonce) + 4 (connection id) + 4 (timeout) + 2(mtu) + 1(state) + 1(srm) */
+#define OBX_SESSION_INFO_NONCE_IDX 16 /* The index to the (local nonce) in session info */
+#define OBX_SESSION_INFO_ID_IDX 20 /* The index to the (connection id) in session info */
+#define OBX_SESSION_INFO_TO_IDX 24 /* The index to the (timeout) in session info */
+#define OBX_SESSION_INFO_MTU_IDX 28 /* The index to peer MTU in session info */
+#define OBX_SESSION_INFO_ST_IDX 30 /* The index to sr/cl state in session info */
+#define OBX_SESSION_INFO_SRM_IDX 31 /* The index to srm in session info */
+#define OBX_TIMEOUT_SIZE 4
+
+/* handle related definitions */
+#define OBX_SESS_SHIFT 8
+#define OBX_ENC_SESS_HANDLE(oh, os) (((os)<<OBX_SESS_SHIFT)|(oh))
+#define OBX_HANDLE_MASK 0xFF
+#define OBX_SESS_MASK 0x7F00
+#define OBX_DEC_HANDLE(os) ((os) & OBX_HANDLE_MASK)
+#define OBX_DEC_SESS_IND(os) ((os & OBX_SESS_MASK)>>OBX_SESS_SHIFT)
+
+/* Return values for API functions */
+enum
+{
+ OBX_SUCCESS, /* Status is successful. */
+ OBX_BAD_PARAMS, /* Bad parameter(s). */
+ OBX_NO_RESOURCES, /* No resources (GKI buffers, control block) */
+ OBX_BAD_HANDLE /* The OBEX handle is not valid. */
+};
+typedef UINT8 tOBX_STATUS;
+
+
+typedef UINT16 tOBX_HANDLE;
+
+#define OBX_HANDLE_NULL 0
+
+enum
+{
+ OBX_PT_PUT, /* Regular Put request */
+ OBX_PT_DELETE, /* Delete request - a Put request with NO Body or End-of-Body header. */
+ OBX_PT_CREATE /* Create-Empty request - a Put request with an empty End-of-Body header. */
+};
+typedef UINT8 tOBX_PUT_TYPE;
+
+/* SetPath Request Flags - the following definitions can be ORed if both flags are wanted */
+#define OBX_SPF_BACKUP 0x01 /* Backup a level before applying name(equivalent to ../) */
+#define OBX_SPF_NO_CREATE 0x02 /* Don't create directory if it does not exist, return an error instead. */
+typedef UINT8 tOBX_SETPATH_FLAG;
+
+/* Authentication Challenge Options */
+#define OBX_AO_NONE 0x00 /* If this is used in OBX_StartServer and the authenticate
+ * flag is TRUE, the optional Challenge Information (tag 0x01)
+ * will not be sent. */
+#define OBX_AO_USR_ID 0x01 /* Set this bit to make the client respond with the user ID. */
+typedef UINT8 tOBX_AUTH_OPT;
+
+/* CHARSET definition for Authentication Challenge Realm */
+#define OBX_RCS_ASCII 0x00 /* ASCII */
+#define OBX_RCS_8859_1 0x01 /* ISO-8859-1 */
+#define OBX_RCS_8859_2 0x02 /* ISO-8859-2 */
+#define OBX_RCS_8859_3 0x03 /* ISO-8859-3 */
+#define OBX_RCS_8859_4 0x04 /* ISO-8859-4 */
+#define OBX_RCS_8859_5 0x05 /* ISO-8859-5 */
+#define OBX_RCS_8859_6 0x06 /* ISO-8859-6 */
+#define OBX_RCS_8859_7 0x07 /* ISO-8859-7 */
+#define OBX_RCS_8859_8 0x08 /* ISO-8859-8 */
+#define OBX_RCS_8859_9 0x09 /* ISO-8859-9 */
+#define OBX_RCS_UNICODE 0xFF /* Unicode */
+typedef UINT8 tOBX_CHARSET;
+
+typedef struct
+{
+ UINT8 ssn; /* session sequence number */
+ BOOLEAN final; /* TRUE, if this is the final packet of this PUT transaction. */
+ tOBX_PUT_TYPE type; /* The type of PUT request. */
+} tOBX_PUT_EVT;
+
+typedef struct
+{
+ UINT8 ssn; /* session sequence number */
+ BOOLEAN final; /* TRUE, if this is the final packet of this GET transaction. */
+} tOBX_GET_EVT;
+
+typedef struct
+{
+ UINT8 ssn; /* session sequence number */
+ BD_ADDR peer_addr; /* The peer Bluetooth Address. */
+ UINT16 mtu; /* The peer MTU. This element is associated with OBX_CONNECT_REQ_EVT and OBX_CONNECT_RSP_EVT. */
+ tOBX_HANDLE handle; /* the OBX handle returned by OBX_StartServer(), OBX_CreateSession() and OBX_ConnectReq() */
+ BOOLEAN no_rsp; /* TRUE, when the event is generated as a part of RESUME SESSION */
+} tOBX_CONN_EVT;
+
+/* Session Opcode Definitions: */
+#define OBX_SESS_OP_CREATE 0x00 /* Create Session */
+#define OBX_SESS_OP_CLOSE 0x01 /* Close Session */
+#define OBX_SESS_OP_SUSPEND 0x02 /* Suspend Session */
+#define OBX_SESS_OP_RESUME 0x03 /* Resume Session */
+#define OBX_SESS_OP_SET_TIME 0x04 /* Set Timeout */
+#define OBX_SESS_OP_TRANSPORT 0xFF /* transport dropped */
+typedef UINT8 tOBX_SESS_OP;
+
+/* Session States Definitions for external use: */
+enum
+{
+ OBX_SESS_NONE, /* 0x00 session is not engaged/closed */
+ OBX_SESS_ACTIVE, /* 0x01 session is active. */
+ OBX_SESS_SUSPENDED, /* 0x02 session is suspended. */
+ OBX_SESS_EXT_MAX
+};
+typedef UINT8 tOBX_SESS_ST;
+
+
+typedef struct
+{
+ UINT8 ssn; /* session sequence number */
+ tOBX_SESS_OP sess_op; /* the session op code */
+ tOBX_SESS_ST sess_st; /* the session state */
+ BD_ADDR peer_addr; /* The peer Bluetooth Address. */
+ UINT8 *p_sess_info; /* The session ID and the local nonce for a reliable session, a reference to the location in OBEX control block or NULL */
+ UINT32 timeout; /* The number of seconds remaining in suspend. 0xffff if infinite. */
+ UINT32 obj_offset; /* The object offset for resume session. */
+ UINT8 nssn; /* tne next session sequence number the server expects */
+} tOBX_SESS_EVT;
+
+#define OBX_ACT_COPY 0x00 /* Copy object */
+#define OBX_ACT_MOVE 0x01 /* Move/rename object */
+#define OBX_ACT_PERMISSION 0x02 /* Set object permission */
+typedef UINT8 tOBX_ACTION;
+
+typedef struct
+{
+ UINT8 ssn; /* session sequence number */
+ tOBX_ACTION action; /* The action opcode. */
+} tOBX_ACT_EVT;
+
+typedef struct
+{
+ UINT8 ssn; /* session sequence number */
+ tOBX_SETPATH_FLAG flag; /* The set path flags. */
+} tOBX_SETPATH_EVT;
+
+/* permission flags */
+#define OBX_PERMISSION_READ 0x01
+#define OBX_PERMISSION_WRITE 0x02
+#define OBX_PERMISSION_DELETE 0x04
+#define OBX_PERMISSION_MODIFY 0x80
+
+typedef union
+{
+ UINT8 ssn; /* session sequence number */
+ tOBX_CONN_EVT conn; /* This element is associated with OBX_CONNECT_REQ_EVT and OBX_CONNECT_RSP_EVT. */
+ tOBX_SESS_EVT sess; /* This element is associated with OBX_SESSION_RSP_EVT and OBX_SESSION_REQ_EVT. */
+ tOBX_PUT_EVT put; /* This element is associated with OBX_PUT_REQ_EVT. */
+ tOBX_SETPATH_EVT sp; /* This element is associated with OBX_SETPATH_REQ_EVT. */
+ tOBX_ACT_EVT action; /* This element is associated with OBX_ACTION_REQ_EVT */
+ tOBX_GET_EVT get; /* This element is associated with OBX_GET_REQ_EVT. TRUE, if this is the final packet that contains the OBEX headers for this GET request. */
+} tOBX_EVT_PARAM;
+
+
+enum
+{
+ OBX_NULL_EVT,
+ /* server events */
+ OBX_CONNECT_REQ_EVT, /* param = packet MTU */
+ OBX_SESSION_REQ_EVT, /* A Crease Session or Resume Session request is received by the server. Call OBX_SessionRsp(). */
+ OBX_DISCONNECT_REQ_EVT,
+ OBX_PUT_REQ_EVT, /* could have param indicate delete or create? */
+ OBX_GET_REQ_EVT,
+ OBX_SETPATH_REQ_EVT, /* param = flags */
+ OBX_ABORT_REQ_EVT,
+ OBX_ACTION_REQ_EVT, /* An Action request is received by the server. Call OBX_ActionRsp(). */
+
+ /* client events */
+ OBX_CONNECT_RSP_EVT, /* param = packet MTU */
+ OBX_SESSION_RSP_EVT, /* A response for Create Session or Resume Session is received by the client. The client needs to remember the session id. The session id is to be used in calling OBX_ResumeSession, if the current session is terminated prematurely. */
+ OBX_DISCONNECT_RSP_EVT,
+ OBX_PUT_RSP_EVT,
+ OBX_GET_RSP_EVT,
+ OBX_SETPATH_RSP_EVT,
+ OBX_ABORT_RSP_EVT,
+ OBX_ACTION_RSP_EVT, /* An Action response is received by the client. */
+
+ /* common events */
+ OBX_SESSION_INFO_EVT, /* the session information event to resume the session. */
+ OBX_CLOSE_IND_EVT, /* when transport goes down; p_pkt = NULL; no response needed */
+ OBX_TIMEOUT_EVT, /* param = tOBX_EVENT */
+ OBX_PASSWORD_EVT
+};
+typedef UINT8 tOBX_EVENT;
+
+/* this is used by the protocol display function only*/
+enum
+{
+ OBX_NULL_DISP,
+ /* server events */
+ OBX_CONNECT_REQ_DISP,
+ OBX_SESSION_REQ_DISP,
+ OBX_DISCONNECT_REQ_DISP,
+ OBX_PUT_REQ_DISP,
+ OBX_GET_REQ_DISP,
+ OBX_SETPATH_REQ_DISP,
+ OBX_ABORT_REQ_DISP,
+ OBX_ACTION_REQ_DISP,
+ /* client events */
+ OBX_CONNECT_RSP_DISP,
+ OBX_SESSION_RSP_DISP,
+ OBX_DISCONNECT_RSP_DISP,
+ OBX_PUT_RSP_DISP,
+ OBX_GET_RSP_DISP,
+ OBX_SETPATH_RSP_DISP,
+ OBX_ABORT_RSP_DISP,
+ OBX_ACTION_RSP_DISP,
+ /* common events */
+ OBX_CLOSE_IND_DISP,
+ OBX_TIMEOUT_DISP,
+ OBX_PASSWORD_DISP
+};
+#define OBX_DISP_IS_RECV 0x80
+#define OBX_DISP_TYPE_MASK 0x7F
+
+#define OBX_MAX_EVT OBX_PASSWORD_EVT
+#define OBX_MAX_OFFSET_IND OBX_ABORT_RSP_EVT /* This is used to access obx_hdr_start_offset */
+
+/*
+** Define Miscellaneous Constants
+*/
+#define OBX_VERSION 0x10 /* Version 1.0 */
+#define OBX_CONN_FLAGS 0 /* Connect flags per IrOBEX spec */
+#define OBX_SETPATH_CONST 0 /* SetPath Request constants per IrOBEX spec */
+#define OBX_INVALID_CONN_ID 0xFFFFFFFF /* invalid connection ID per IrOBEX spec */
+#define OBX_INFINITE_TIMEOUT 0xFFFFFFFF
+
+/* Header Identifier Data Type Constants */
+#define OBX_HI_TYPE_MASK 0xC0 /* This mask get the encoding (data type) of the header ID. */
+#define OBX_HI_ID_MASK 0x3F /* This mask gets the meaning of the header ID. */
+#define OBX_HI_TYPE_UNIC 0x00 /* Null terminated Unicode text */
+#define OBX_HI_TYPE_ARRAY 0x40 /* Unstructured octet array (byte sequence) */
+#define OBX_HI_TYPE_BYTE 0x80 /* 8-bit integer */
+#define OBX_HI_TYPE_INT 0xC0 /* 32-bit integer */
+
+/*
+** Define OBEX Header Identifiers
+*/
+#define OBX_HI_NULL 0
+#define OBX_HI_COUNT 0xC0
+#define OBX_HI_NAME 0x01
+#define OBX_HI_TYPE 0x42
+#define OBX_HI_LENGTH 0xC3
+#define OBX_HI_TIME 0x44
+#define OBX_HI_DESCRIPTION 0x05
+#define OBX_HI_TARGET 0x46
+#define OBX_HI_HTTP 0x47
+#define OBX_HI_BODY 0x48
+#define OBX_HI_BODY_END 0x49
+#define OBX_HI_WHO 0x4A
+#define OBX_HI_CONN_ID 0xCB
+#define OBX_HI_APP_PARMS 0x4C
+#define OBX_HI_CHALLENGE 0x4D
+#define OBX_HI_AUTH_RSP 0x4E
+#define OBX_HI_CREATOR_ID 0xCF
+#define OBX_HI_WAN_UUID 0x50
+#define OBX_HI_OBJ_CLASS 0x51
+#define OBX_HI_SESSION_PARAM 0x52
+#define OBX_HI_SESSION_SN 0x93
+#define OBX_HI_ACTION_ID 0x94
+#define OBX_HI_DEST_NAME 0x15
+#define OBX_HI_PERMISSION 0xD6
+#define OBX_HI_SRM 0x97
+#define OBX_HI_SRM_PARAM 0x98
+#define OBX_HI_LO_USER 0x30
+#define OBX_HI_HI_USER 0x3F
+
+/* Obex Header Values for the SRM header */
+#define OBX_HV_SRM_DISABLE 0x00 /* SRM header value - disable */
+#define OBX_HV_SRM_ENABLE 0x01 /* SRM header value - enable */
+#define OBX_HV_SRM_IND 0x02 /* SRM header value - indicate support */
+
+/* Obex Header Values for the SRM Parameter header */
+#define OBX_HV_SRM_PARAM_MORE 0x00 /* SRM Param header value - request additional packet */
+#define OBX_HV_SRM_PARAM_WAIT 0x01 /* SRM Param header value - wait for next req/rsp */
+#define OBX_HV_SRM_PARAM_COMBO 0x02 /* SRM Param header value - next and wait */
+
+#define OBX_TAG_SESS_PARAM_ADDR 0x00
+#define OBX_TAG_SESS_PARAM_NONCE 0x01
+#define OBX_TAG_SESS_PARAM_SESS_ID 0x02
+#define OBX_TAG_SESS_PARAM_NSEQNUM 0x03
+#define OBX_TAG_SESS_PARAM_TOUT 0x04
+#define OBX_TAG_SESS_PARAM_SESS_OP 0x05
+#define OBX_TAG_SESS_PARAM_OBJ_OFF 0x06
+#define OBX_MAX_SESS_PARAM_TRIP 7 /* max number of TLV for session operations */
+
+#define OBX_LEN_SESS_PARAM_SESS_OP 1
+#define OBX_LEN_SESS_PARAM_OBJ_OFF 4 /* this value varies, so it needs to be verified on the receiving side */
+
+/*
+** Define OBEX Request Codes
+*/
+#define OBX_REQ_CONNECT 0x00 /* need to set final bit */
+#define OBX_REQ_DISCONNECT 0x01 /* need to set final bit */
+#define OBX_REQ_PUT 0x02
+#define OBX_REQ_GET 0x03
+#define OBX_REQ_SETPATH 0x05 /* need to set final bit */
+#define OBX_REQ_ACTION 0x06
+#define OBX_REQ_SESSION 0x07 /* need to set final bit */
+#define OBX_REQ_ABORT 0x7F /* need to set final bit */
+#define OBX_FINAL 0x80
+
+/* OBEX response code as defined in IrOBEX spec. version 1.2 */
+#define OBX_RSP_DEFAULT 0x00
+#define OBX_RSP_FAILED 0x08 /* OBEX failed - not from spec */
+#define OBX_RSP_CONTINUE 0x10 /* Continue */
+#define OBX_RSP_OK 0x20 /* OK, Success */
+#define OBX_RSP_CREATED 0x21 /* Created */
+#define OBX_RSP_ACCEPTED 0x22 /* Accepted */
+#define OBX_RSP_NON_AUTH_INFO 0x23 /* Non-Authoritative Information */
+#define OBX_RSP_NO_CONTENT 0x24 /* No Content */
+#define OBX_RSP_RESET_CONTENT 0x25 /* Reset Content */
+#define OBX_RSP_PART_CONTENT 0x26 /* Partial Content */
+#define OBX_RSP_MULTI_CHOICES 0x30 /* Multiple Choices */
+#define OBX_RSP_MVD_PERM 0x31 /* Moved Permanently */
+#define OBX_RSP_MVD_TEMP 0x32 /* Moved temporarily */
+#define OBX_RSP_SEE_OTHER 0x33 /* See Other */
+#define OBX_RSP_NOT_MODIFIED 0x34 /* Not modified */
+#define OBX_RSP_USE_PROXY 0x35 /* Use Proxy */
+#define OBX_RSP_BAD_REQUEST 0x40 /* Bad Request - server couldn't understand request */
+#define OBX_RSP_UNAUTHORIZED 0x41 /* Unauthorized */
+#define OBX_RSP_PAYMENT_REQD 0x42 /* Payment required */
+#define OBX_RSP_FORBIDDEN 0x43 /* Forbidden - operation is understood but refused */
+#define OBX_RSP_NOT_FOUND 0x44 /* Not Found */
+#define OBX_RSP_NOT_ALLOWED 0x45 /* Method not allowed */
+#define OBX_RSP_NOT_ACCEPTABLE 0x46 /* Not Acceptable */
+#define OBX_RSP_PROXY_AUTH_REQD 0x47 /* Proxy Authentication required */
+#define OBX_RSP_REQUEST_TIMEOUT 0x48 /* Request Time Out */
+#define OBX_RSP_CONFLICT 0x49 /* Conflict */
+#define OBX_RSP_GONE 0x4A /* Gone */
+#define OBX_RSP_LENGTH_REQD 0x4B /* Length Required */
+#define OBX_RSP_PRECONDTN_FAILED 0x4C /* Precondition failed */
+#define OBX_RSP_REQ_ENT_2_LARGE 0x4D /* Requested entity too large */
+#define OBX_RSP_REQ_URL_2_LARGE 0x4E /* Request URL too large */
+#define OBX_RSP_UNSUPTD_TYPE 0x4F /* Unsupported media type */
+#define OBX_RSP_INTRNL_SRVR_ERR 0x50 /* Internal Server Error */
+#define OBX_RSP_NOT_IMPLEMENTED 0x51 /* Not Implemented */
+#define OBX_RSP_BAD_GATEWAY 0x52 /* Bad Gateway */
+#define OBX_RSP_SERVICE_UNAVL 0x53 /* Service Unavailable */
+#define OBX_RSP_GATEWAY_TIMEOUT 0x54 /* Gateway Timeout */
+#define OBX_RSP_HTTP_VER_NOT_SUPTD 0x55 /* HTTP version not supported */
+#define OBX_RSP_DATABASE_FULL 0x60 /* Database Full */
+#define OBX_RSP_DATABASE_LOCKED 0x61 /* Database Locked */
+
+#define OBX_MAX_OK_RSP OBX_RSP_PART_CONTENT
+
+typedef UINT8 tOBX_RSP_CODE;
+
+/* tags for authentication triplet */
+#define OBX_NONCE_CHLNG_TAG 0
+#define OBX_OPTIONS_CHLNG_TAG 1
+#define OBX_REALM_CHLNG_TAG 2
+
+#define OBX_DIGEST_RSP_TAG 0
+#define OBX_USERID_RSP_TAG 1
+#define OBX_NONCE_RSP_TAG 2
+
+typedef struct
+{
+ UINT8 tag;
+ UINT8 len;
+ UINT8 *p_array;
+} tOBX_TRIPLET;
+
+/* Server Callback type: */
+typedef void (tOBX_SR_CBACK) (tOBX_HANDLE shandle, tOBX_EVENT event, tOBX_EVT_PARAM param, BT_HDR *p_pkt);
+/* Client Callback type: */
+typedef void (tOBX_CL_CBACK) (tOBX_HANDLE handle, tOBX_EVENT event, UINT8 rsp_code, tOBX_EVT_PARAM param, BT_HDR *p_pkt);
+
+
+typedef struct
+{
+ UINT16 len; /* Length of target header. */
+ UINT8 target[OBX_MAX_TARGET_LEN]; /* The byte sequence that describes the target header. */
+} tOBX_TARGET;
+
+
+typedef struct
+{
+ tOBX_TARGET *p_target;
+ tOBX_SR_CBACK *p_cback;
+ UINT16 mtu;
+ UINT8 scn; /* The RFCOMM SCN number that this server listens for incoming requests. 0, if do not wish to listen to connection from RFCOMM. */
+ BOOLEAN authenticate;
+ UINT8 auth_option;
+ UINT8 realm_charset;
+ UINT8 *p_realm;
+ UINT8 realm_len;
+ UINT8 max_sessions;
+ BOOLEAN get_nonf; /* report GET non-final request event. If FALSE, GET response is sent automatically */
+ UINT16 psm; /* The L2CAP PSM number that this server listens for incoming requests. 0, if do not wish to listen to connection from L2CAP. */
+ UINT32 nonce; /* This is converted to UINT8[16] internally before adding to the OBEX header. This value is copied to the server control block and is increased after each use. 0, if only legacy OBEX (unreliable) session is desired. */
+ BOOLEAN srm; /* TRUE, to support single response mode. */
+ UINT8 max_suspend; /* Max number of suspended session. must be less than OBX_MAX_SUSPEND_SESSIONS. ignored, if nonce is 0 */
+} tOBX_StartParams;
+
+
+
+
+
+/*****************************************************************************
+** External Function Declarations
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*******************************************************************************
+**
+** Function OBX_Init
+**
+** Description This function is called to initialize the control block for this
+** layer. It must be called before accessing any other of its API
+** functions. It is typically called once during the start up of
+** the stack.
+**
+** Returns void.
+**
+*******************************************************************************/
+OBX_API extern void OBX_Init(void);
+
+/*******************************************************************************
+**
+** Function OBX_SetTraceLevel
+**
+** Description This function sets the debug trace level for OBX.
+** If 0xff is passed, the current trace level is returned.
+**
+** Input Parameters:
+** level: The level to set the OBX tracing to:
+** 0xff-returns the current setting.
+** 0-turns off tracing.
+** >= 1-Errors.
+** >= 2-Warnings.
+** >= 3-APIs.
+** >= 4-Events.
+** >= 5-Debug.
+**
+** Returns The new trace level or current trace level if
+** the input parameter is 0xff.
+**
+*******************************************************************************/
+OBX_API extern UINT8 OBX_SetTraceLevel (UINT8 level);
+
+/*******************************************************************************
+** Function OBX_HandleToMtu
+**
+** Description Given an OBEX handle, return the associated peer MTU.
+**
+** Returns MTU.
+**
+*******************************************************************************/
+OBX_API extern UINT16 OBX_HandleToMtu(tOBX_HANDLE handle);
+
+/* Server API's: */
+/*******************************************************************************
+**
+** Function OBX_StartServer
+**
+** Description This function is to register a server entity to OBEX.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_NO_RESOURCES, if OBX does not have resources.
+**
+*******************************************************************************/
+OBX_API extern tOBX_STATUS OBX_StartServer(tOBX_StartParams *p_params, tOBX_HANDLE *p_handle);
+
+/*******************************************************************************
+**
+** Function OBX_StopServer
+**
+** Description This function is to stop this OBEX server from receiving any
+** more incoming requests.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_BAD_HANDLE, if the handle is not valid.
+**
+*******************************************************************************/
+OBX_API extern tOBX_STATUS OBX_StopServer(tOBX_HANDLE handle);
+
+/*******************************************************************************
+**
+** Function OBX_AddSuspendedSession
+**
+** Description This function is to add the session information for a previously
+** suspended reliable session to the server control block
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_BAD_HANDLE, if the handle is not valid.
+**
+*******************************************************************************/
+OBX_API extern tOBX_STATUS OBX_AddSuspendedSession(tOBX_HANDLE shandle, BD_ADDR peer_addr, UINT8 *p_sess_info,
+ UINT32 timeout, UINT8 ssn, UINT32 offset);
+
+/*******************************************************************************
+**
+** Function OBX_ConnectRsp
+**
+** Description This function is called to send the response to a Connect
+** Request from an OBEX client.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_BAD_HANDLE, if the handle is not valid.
+**
+*******************************************************************************/
+OBX_API extern tOBX_STATUS OBX_ConnectRsp(tOBX_HANDLE shandle, UINT8 rsp_code, BT_HDR *p_pkt);
+
+/*******************************************************************************
+**
+** Function OBX_SessionRsp
+**
+** Description This function is called to respond to a request to create a reliable session.
+**
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_BAD_HANDLE, if the handle is not valid.
+**
+*******************************************************************************/
+OBX_API extern tOBX_STATUS OBX_SessionRsp(tOBX_HANDLE shandle, UINT8 rsp_code,
+ UINT8 ssn, UINT32 offset, BT_HDR *p_pkt);
+
+/*******************************************************************************
+**
+** Function OBX_SetPathRsp
+**
+** Description This function is called to send the response to a Set Path
+** Request from an OBEX client.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_BAD_HANDLE, if the handle is not valid.
+**
+*******************************************************************************/
+OBX_API extern tOBX_STATUS OBX_SetPathRsp(tOBX_HANDLE shandle, UINT8 rsp_code, BT_HDR *p_pkt);
+
+/*******************************************************************************
+**
+** Function OBX_PutRsp
+**
+** Description This function is called to send the response to a Put
+** Request from an OBEX client.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_BAD_HANDLE, if the handle is not valid.
+**
+*******************************************************************************/
+OBX_API extern tOBX_STATUS OBX_PutRsp(tOBX_HANDLE shandle, UINT8 rsp_code, BT_HDR *p_pkt);
+
+/*******************************************************************************
+**
+** Function OBX_GetRsp
+**
+** Description This function is called to send the response to a Get
+** Request from an OBEX client.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_BAD_HANDLE, if the handle is not valid.
+**
+*******************************************************************************/
+OBX_API extern tOBX_STATUS OBX_GetRsp(tOBX_HANDLE shandle, UINT8 rsp_code, BT_HDR *p_pkt);
+
+/*******************************************************************************
+**
+** Function OBX_AbortRsp
+**
+** Description This function is called to send the response to an Abort
+** Request from an OBEX client.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_BAD_HANDLE, if the handle is not valid.
+**
+*******************************************************************************/
+OBX_API extern tOBX_STATUS OBX_AbortRsp(tOBX_HANDLE shandle, UINT8 rsp_code, BT_HDR *p_pkt);
+
+/*******************************************************************************
+**
+** Function OBX_ActionRsp
+**
+** Description This function is called to respond to an Action command Request
+** from an OBEX client.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_BAD_HANDLE, if the handle is not valid.
+**
+*******************************************************************************/
+OBX_API extern tOBX_STATUS OBX_ActionRsp(tOBX_HANDLE shandle, UINT8 rsp_code, BT_HDR *p_pkt);
+
+/*******************************************************************************
+**
+** Function OBX_DisconnectRsp
+**
+** Description This function is called to send the response to a Disconnect
+** Request from an OBEX client.
+** This function can also be used to force close the transport
+** to a connected client.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_BAD_HANDLE, if the handle is not valid.
+**
+*******************************************************************************/
+OBX_API extern tOBX_STATUS OBX_DisconnectRsp(tOBX_HANDLE shandle, UINT8 rsp_code, BT_HDR *p_pkt);
+
+/*******************************************************************************
+**
+** Function OBX_Password
+**
+** Description This function is called to respond to an OBX_PASSWORD_EVT event.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_NO_RESOURCES, if OBX does not resources
+**
+*******************************************************************************/
+OBX_API extern tOBX_STATUS OBX_Password(tOBX_HANDLE shandle, UINT8 *p_password, UINT8 password_len,
+ UINT8 *p_userid, UINT8 userid_len);
+
+/*******************************************************************************
+**
+** Function OBX_GetPeerAddr
+**
+** Description This function is called to learn the Bluetooth address of the
+** connected device.
+**
+** Returns L2CAP channel ID.
+**
+*******************************************************************************/
+OBX_API extern UINT16 OBX_GetPeerAddr(tOBX_HANDLE shandle, BD_ADDR bd_addr);
+
+/*******************************************************************************
+**
+** Function OBX_GetPortHandle
+**
+** Description This function is called to get the RFCOMM port handle for the obex connection.
+**
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_NO_RESOURCES, if no existing connection.
+** OBX_BAD_HANDLE, if the handle is not valid.
+**
+*******************************************************************************/
+OBX_API extern tOBX_STATUS OBX_GetPortHandle(tOBX_HANDLE handle, UINT16 *port_handle);
+
+/* Client API's: */
+/*******************************************************************************
+**
+** Function OBX_ConnectReq
+**
+** Description This function registers a client entity to OBEX and sends a
+** CONNECT request to the server specified by the API parameters.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_NO_RESOURCES, if OBX does not resources
+**
+*******************************************************************************/
+OBX_API extern tOBX_STATUS OBX_ConnectReq(BD_ADDR bd_addr, UINT8 scn, UINT16 mtu,
+ tOBX_CL_CBACK *p_cback, tOBX_HANDLE *p_handle, BT_HDR *p_pkt);
+
+/*******************************************************************************
+**
+** Function OBX_AllocSession
+**
+** Description This function registers a client entity to OBEX.
+** If p_session_id is not NULL, it tries to find an suspended session
+** with matching session_id.
+** If scn is not 0, it allocates a control block for this new session.
+** Otherwise, it allocates a control block for the given PSM.
+** The associated virtual PSM assigned by L2CAP is returned in p_psm
+** The allocated OBEX handle is returned in p_handle.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_NO_RESOURCES, if OBX does not resources
+**
+*******************************************************************************/
+OBX_API extern tOBX_STATUS OBX_AllocSession (UINT8 *p_session_info, UINT8 scn, UINT16 *p_psm,
+ tOBX_CL_CBACK *p_cback, tOBX_HANDLE *p_handle);
+
+/*******************************************************************************
+**
+** Function OBX_CreateSession
+**
+** Description This function registers a client entity to OBEX.
+** It may send a CreateSession request and wait for CreateSession response.
+** It sends a CONNECT request to the server specified by the API parameters.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_NO_RESOURCES, if OBX does not resources
+**
+*******************************************************************************/
+OBX_API extern tOBX_STATUS OBX_CreateSession (BD_ADDR bd_addr, UINT16 mtu, BOOLEAN srm, UINT32 nonce,
+ tOBX_HANDLE handle, BT_HDR *p_pkt);
+
+/*******************************************************************************
+**
+** Function OBX_ResumeSession
+**
+** Description This function registers a client entity to OBEX and resumes
+** a previously interrupted reliable session.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_NO_RESOURCES, if OBX does not resources
+**
+*******************************************************************************/
+OBX_API extern tOBX_STATUS OBX_ResumeSession (BD_ADDR bd_addr, UINT8 ssn, UINT32 offset, tOBX_HANDLE handle);
+
+/*******************************************************************************
+**
+** Function OBX_SessionReq
+**
+** Description This function is used to Suspend, Resume, or Close a session.
+** For Resume: this function registers a client entity to OBEX and resumes
+** a previously interrupted reliable session.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_NO_RESOURCES, if OBX does not resources
+**
+*******************************************************************************/
+OBX_API extern tOBX_STATUS OBX_SessionReq (tOBX_HANDLE handle, tOBX_SESS_OP opcode, UINT32 timeout);
+
+/*******************************************************************************
+**
+** Function OBX_SetPathReq
+**
+** Description This function sends a Set Path request to the connected server.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_BAD_HANDLE, if the handle is not valid.
+**
+*******************************************************************************/
+OBX_API extern tOBX_STATUS OBX_SetPathReq(tOBX_HANDLE handle, UINT8 flags, BT_HDR *p_pkt);
+
+/*******************************************************************************
+**
+** Function OBX_PutReq
+**
+** Description This function sends a Put request to the connected server.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_BAD_HANDLE, if the handle is not valid.
+**
+*******************************************************************************/
+OBX_API extern tOBX_STATUS OBX_PutReq(tOBX_HANDLE handle, BOOLEAN final, BT_HDR *p_pkt);
+
+/*******************************************************************************
+**
+** Function OBX_GetReq
+**
+** Description This function sends a Get request to the connected server.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_BAD_HANDLE, if the handle is not valid.
+**
+*******************************************************************************/
+OBX_API extern tOBX_STATUS OBX_GetReq(tOBX_HANDLE handle, BOOLEAN final, BT_HDR *p_pkt);
+
+/*******************************************************************************
+**
+** Function OBX_AbortReq
+**
+** Description This function sends an Abort request to the connected server.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_BAD_HANDLE, if the handle is not valid.
+**
+*******************************************************************************/
+OBX_API extern tOBX_STATUS OBX_AbortReq(tOBX_HANDLE handle, BT_HDR *p_pkt);
+
+/*******************************************************************************
+**
+** Function OBX_DisconnectReq
+**
+** Description This function sends a Disconnect request to the connected server.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_BAD_HANDLE, if the handle is not valid.
+**
+*******************************************************************************/
+OBX_API extern tOBX_STATUS OBX_DisconnectReq(tOBX_HANDLE handle, BT_HDR *p_pkt);
+
+/*******************************************************************************
+**
+** Function OBX_ActionReq
+**
+** Description This function sends a Action request to the connected server.
+** The Name Header and DestName Header must be in p_pkt for
+** the Copy and Move Object action.
+** The Name header and Permission Header must be in p_pkt for
+** the Set Object Permission action.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_BAD_HANDLE, if the handle is not valid.
+**
+*******************************************************************************/
+OBX_API extern tOBX_STATUS OBX_ActionReq(tOBX_HANDLE handle, tOBX_ACTION action_id, BT_HDR *p_pkt);
+
+/*******************************************************************************
+**
+** Function OBX_AuthResponse
+**
+** Description This function is called to respond to an OBX_PASSWORD_EVT event.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_NO_RESOURCES, if OBX does not resources
+**
+*******************************************************************************/
+OBX_API extern tOBX_STATUS OBX_AuthResponse(tOBX_HANDLE handle,
+ UINT8 *p_password, UINT8 password_len,
+ UINT8 *p_userid, UINT8 userid_len,
+ BOOLEAN authenticate);
+
+
+/*******************************************************************************
+**
+** Function OBX_HdrInit
+**
+** Description This function is called to initialize an OBEX packet. This
+** function takes a GKI buffer and sets the offset in BT_HDR as
+** OBEX_HDR_OFFSET, the len as 0. The layer_specific is set to the
+** length still available. This function compares the given
+** (pkt_size - sizeof(BT_HDR)) with the peer MTU to get the lesser
+** of the two and set the layer_specific to
+** (lesser_size - OBEX_HDR_OFFSET).
+** If composing a header for the CONNECT request (there is no
+** client handle yet), use OBX_HANDLE_NULL as the handle.
+**
+** Returns BT_HDR *.
+**
+*******************************************************************************/
+OBX_API extern BT_HDR * OBX_HdrInit(tOBX_HANDLE handle, UINT16 pkt_size);
+
+/*******************************************************************************
+**
+** Function OBX_AddNameHdr
+**
+** Description This function is called to add an OBEX Name header
+** to an OBEX packet.
+**
+** Returns TRUE, if the header is added successfully.
+** FALSE, if the operation failed. p_pkt is not altered.
+**
+*******************************************************************************/
+OBX_API extern BOOLEAN OBX_AddNameHdr(BT_HDR *p_pkt, UINT16 *p_name, UINT16 len);
+
+/*******************************************************************************
+**
+** Function OBX_CharToWchar
+**
+** Description This function is called to convert ASCII to Unicode (UINT16).
+**
+** Returns the length.
+**
+*******************************************************************************/
+OBX_API extern UINT16 OBX_CharToWchar (UINT16 *w_str, char* a_str, UINT16 w_size);
+
+/*******************************************************************************
+**
+** Function OBX_AddAsciiNameHdr
+**
+** Description This function is called to add an OBEX Name header
+** to an OBEX packet.
+**
+** Returns TRUE, if the header is added successfully.
+** FALSE, if the operation failed. p_pkt is not altered.
+**
+*******************************************************************************/
+OBX_API extern BOOLEAN OBX_AddAsciiNameHdr(BT_HDR *p_pkt, char *p_name);
+
+/*******************************************************************************
+**
+** Function OBX_AddTypeHdr
+**
+** Description This function is called to add an OBEX Type header
+** to an OBEX packet.
+**
+** Returns TRUE, if the header is added successfully.
+** FALSE, if the operation failed. p_pkt is not altered.
+**
+*******************************************************************************/
+OBX_API extern BOOLEAN OBX_AddTypeHdr(BT_HDR *p_pkt, char *p_type);
+
+/*******************************************************************************
+**
+** Function OBX_AddLengthHdr
+**
+** Description This function is called to add an OBEX Length header to an OBEX
+** packet. The Length header describes the total length in bytes of
+** the object.
+**
+** Returns TRUE, if the header is added successfully.
+** FALSE, if the operation failed. p_pkt is not altered.
+**
+*******************************************************************************/
+OBX_API extern BOOLEAN OBX_AddLengthHdr(BT_HDR *p_pkt, UINT32 len);
+
+/*******************************************************************************
+**
+** Function OBX_AddTimeHdr
+**
+** Description This function is called to add an OBEX Time header
+** to an OBEX packet.
+**
+** Returns TRUE, if the header is added successfully.
+** FALSE, if the operation failed. p_pkt is not altered.
+**
+*******************************************************************************/
+OBX_API extern BOOLEAN OBX_AddTimeHdr(BT_HDR *p_pkt, char *p_time);
+
+/*******************************************************************************
+**
+** Function OBX_AddDescrHdr
+**
+** Description This function is called to add an OBEX Description header
+** to an OBEX packet.
+**
+** Returns TRUE, if the header is added successfully.
+** FALSE, if the operation failed. p_pkt is not altered.
+**
+*******************************************************************************/
+OBX_API extern BOOLEAN OBX_AddDescrHdr(BT_HDR *p_pkt, UINT16 *p_descr, UINT16 len);
+
+/*******************************************************************************
+**
+** Function OBX_AddAsciiDescrHdr
+**
+** Description This function is called to add an OBEX Description header
+** to an OBEX packet.
+**
+** Returns TRUE, if the header is added successfully.
+** FALSE, if the operation failed. p_pkt is not altered.
+**
+*******************************************************************************/
+OBX_API extern BOOLEAN OBX_AddAsciiDescrHdr(BT_HDR *p_pkt, char *p_descr);
+
+/*******************************************************************************
+**
+** Function OBX_AddTargetHdr
+**
+** Description This function is called to add an OBEX Target header to an OBEX
+** packet. This header is most commonly used in Connect packets.
+**
+** NOTE: The target header must be the first header in an OBEX message.
+**
+** Returns TRUE, if the header is added successfully.
+** FALSE, if the operation failed. p_pkt is not altered.
+**
+*******************************************************************************/
+OBX_API extern BOOLEAN OBX_AddTargetHdr(BT_HDR *p_pkt, UINT8 *p_target, UINT16 len);
+
+/*******************************************************************************
+**
+** Function OBX_AddHttpHdr
+**
+** Description This function is called to add an OBEX HTTP header
+** to an OBEX packet.
+**
+** Returns TRUE, if the header is added successfully.
+** FALSE, if the operation failed. p_pkt is not altered.
+**
+*******************************************************************************/
+OBX_API extern BOOLEAN OBX_AddHttpHdr(BT_HDR *p_pkt, UINT8 *p_http, UINT16 len);
+
+/*******************************************************************************
+**
+** Function OBX_AddBodyHdr
+**
+** Description This function is called to add an OBEX body header
+** to an OBEX packet.
+**
+** NOTE: The body header must be the last header in an OBEX message.
+**
+** Returns TRUE, if the header is added successfully.
+** FALSE, if the operation failed. p_pkt is not altered.
+**
+*******************************************************************************/
+OBX_API extern BOOLEAN OBX_AddBodyHdr(BT_HDR *p_pkt, UINT8 *p_body, UINT16 len, BOOLEAN end);
+
+/* Alternate Body header functions: for non-blocking scenario */
+/*******************************************************************************
+**
+** Function OBX_AddBodyStart
+**
+** Description This function is called to get the address to the beginning of
+** the byte sequence for an OBEX body header in an OBEX packet.
+**
+** Returns The address to add body content.
+**
+*******************************************************************************/
+OBX_API extern UINT8 *OBX_AddBodyStart(BT_HDR *p_pkt, UINT16 *p_len);
+
+/*******************************************************************************
+**
+** Function OBX_AddBodyEnd
+**
+** Description This function is called to add the HI and the length of HV of an
+** OBEX body header to an OBEX packet. If end is TRUE, HI is
+** OBX_HI_BODY_END. If FALSE, HI is OBX_HI_BODY. It is assumed that
+** the actual value of the body has been copied into the OBEX packet.
+**
+** Returns void
+**
+*******************************************************************************/
+OBX_API extern void OBX_AddBodyEnd(BT_HDR *p_pkt, UINT8 *p, UINT16 len, BOOLEAN end);
+
+/*******************************************************************************
+**
+** Function OBX_AddWhoHdr
+**
+** Description This function is called to add an OBEX Who header to an OBEX
+** packet.
+**
+** Note: Who header is typically used in an OBEX CONNECT response packet
+** to indicate the UUID of the service that has accepted the
+** directed connection. If the server calls OBX_StartServer() with
+** specified target header, this OBEX implementation automatically
+** adds this WHO header to the CONNECT response packet. If
+** OBX_StartServer() is called with target header length as 0, the
+** OBEX API user is responsible to add the WHO header.
+**
+** Returns TRUE, if the header is added successfully.
+** FALSE, if the operation failed. p_pkt is not altered.
+**
+*******************************************************************************/
+OBX_API extern BOOLEAN OBX_AddWhoHdr(BT_HDR *p_pkt, UINT8 *p_who, UINT16 len);
+
+/*******************************************************************************
+**
+** Function OBX_AddAppParamHdr
+**
+** Description This function is called to add an OBEX Application Parameter
+** header to an OBEX packet. This header is used by the application
+** layer above OBEX to convey application specific information.
+**
+** Returns TRUE, if the header is added successfully.
+** FALSE, if the operation failed. p_pkt is not altered.
+**
+*******************************************************************************/
+OBX_API extern BOOLEAN OBX_AddAppParamHdr(BT_HDR *p_pkt, tOBX_TRIPLET *p_triplet, UINT8 num);
+
+/*******************************************************************************
+**
+** Function OBX_AddDestNameHdr
+**
+** Description This function is called to add an OBEX DestName header
+** to an OBEX packet.
+**
+** Returns TRUE, if the header is added successfully.
+** FALSE, if the operation failed. p_pkt is not altered.
+**
+*******************************************************************************/
+OBX_API extern BOOLEAN OBX_AddDestNameHdr(BT_HDR *p_pkt, UINT16 *p_dest, UINT16 len);
+
+/*******************************************************************************
+**
+** Function OBX_AddAsciiDestNameHdr
+**
+** Description This function is called to add an OBEX DestName header
+** to an OBEX packet.
+**
+** Returns TRUE, if the header is added successfully.
+** FALSE, if the operation failed. p_pkt is not altered.
+**
+*******************************************************************************/
+OBX_API extern BOOLEAN OBX_AddAsciiDestNameHdr(BT_HDR *p_pkt, char *p_descr);
+
+/*******************************************************************************
+**
+** Function OBX_AddPermissionHdr
+**
+** Description This function is called to add an OBEX Permission header to an OBEX
+** packet.
+** bit 0 is set for read permission
+** bit 1 is set for write permission
+** bit 2 is set for delete permission
+** bit 7 is set for modify permission
+**
+** Returns TRUE, if the header is added successfully.
+** FALSE, if the operation failed. p_pkt is not altered.
+**
+*******************************************************************************/
+OBX_API extern BOOLEAN OBX_AddPermissionHdr(BT_HDR *p_pkt, UINT8 user, UINT8 group, UINT8 other);
+
+/*******************************************************************************
+**
+** Function OBX_Add1ByteHdr
+**
+** Description This function is called to add a header with type as UINT8
+** to an OBEX packet.
+**
+** Returns TRUE, if the header is added successfully.
+** FALSE, if the operation failed. p_pkt is not altered.
+**
+*******************************************************************************/
+OBX_API extern BOOLEAN OBX_Add1ByteHdr(BT_HDR *p_pkt, UINT8 id, UINT8 data);
+
+/*******************************************************************************
+**
+** Function OBX_Add4ByteHdr
+**
+** Description This function is called to add a header with type as UINT32
+** to an OBEX packet.
+**
+** Returns TRUE, if the header is added successfully.
+** FALSE, if the operation failed. p_pkt is not altered.
+**
+*******************************************************************************/
+OBX_API extern BOOLEAN OBX_Add4ByteHdr(BT_HDR *p_pkt, UINT8 id, UINT32 data);
+
+/*******************************************************************************
+**
+** Function OBX_AddByteStrStart
+**
+** Description This function is called to get the address to the beginning of
+** the byte sequence for an OBEX header in an OBEX packet.
+**
+** Returns The address to add the byte sequence.
+**
+*******************************************************************************/
+OBX_API extern UINT8 *OBX_AddByteStrStart(BT_HDR *p_pkt, UINT16 *p_len);
+
+/*******************************************************************************
+**
+** Function OBX_AddByteStrHdr
+**
+** Description This function is called to add a header with type as byte sequence
+** to an OBEX packet.
+**
+** Returns TRUE, if the header is added successfully.
+** FALSE, if the operation failed. p_pkt is not altered.
+**
+*******************************************************************************/
+OBX_API extern BOOLEAN OBX_AddByteStrHdr(BT_HDR *p_pkt, UINT8 id, UINT8 *p_data, UINT16 len);
+
+/*******************************************************************************
+**
+** Function OBX_AddUnicodeHdr
+**
+** Description This function is called to add a header with type as Unicode string
+** to an OBEX packet.
+**
+** Returns TRUE, if the header is added successfully.
+** FALSE, if the operation failed. p_pkt is not altered.
+**
+*******************************************************************************/
+OBX_API extern BOOLEAN OBX_AddUnicodeHdr(BT_HDR *p_pkt, UINT8 id, UINT16 *p_data, UINT16 len);
+
+/*******************************************************************************
+**
+** Function OBX_AddTriplet
+**
+** Description This function is called to add a header with type as byte sequence
+** to an OBEX packet.
+**
+** Note: The byte sequence uses a Tag-Length-Value encoding scheme
+** These headers include: Application Parameters header
+** Authenticate Challenge header
+** Authenticate Response header
+**
+** Returns TRUE, if the header is added successfully.
+** FALSE, if the operation failed. p_pkt is not altered.
+**
+*******************************************************************************/
+OBX_API extern BOOLEAN OBX_AddTriplet(BT_HDR *p_pkt, UINT8 id, tOBX_TRIPLET *p_triplet, UINT8 num);
+
+/*******************************************************************************
+**
+** Function OBX_CheckHdr
+**
+** Description This function is called to check if the given OBEX packet
+** contains the specified header.
+**
+** Returns NULL, if the header is not in the OBEX packet.
+** The pointer to the specified header beginning from HI.
+**
+*******************************************************************************/
+OBX_API extern UINT8 * OBX_CheckHdr(BT_HDR *p_pkt, UINT8 id);
+
+/*******************************************************************************
+**
+** Function OBX_ReadNumHdrs
+**
+** Description This function is called to check the number of headers in the
+** given OBEX packet
+**
+** Returns number of headers.
+**
+*******************************************************************************/
+OBX_API extern UINT8 OBX_ReadNumHdrs(BT_HDR *p_pkt, UINT8 *p_num_body);
+
+/*******************************************************************************
+**
+** Function OBX_ReadHdrLen
+**
+** Description This function is called to check the length of the specified
+** header in the given OBEX packet.
+**
+** Returns OBX_INVALID_HDR_LEN, if the header is not in the OBEX packet.
+** Otherwise the actual length of the header.
+**
+*******************************************************************************/
+OBX_API extern UINT16 OBX_ReadHdrLen(BT_HDR *p_pkt, UINT8 id);
+
+/*******************************************************************************
+**
+** Function OBX_ReadNameHdr
+**
+** Description This function is called to get the Name Header in the given
+** OBEX packet.
+**
+** Returns TRUE, if the header is in the OBEX packet.
+** FALSE, otherwise.
+**
+*******************************************************************************/
+OBX_API extern BOOLEAN OBX_ReadNameHdr(BT_HDR *p_pkt, UINT16 *p_name, UINT16 *p_len);
+
+/*******************************************************************************
+**
+** Function OBX_WcharToChar
+**
+** Description This function is called to convert Unicode (UINT16) to ASCII.
+**
+** Returns void.
+**
+*******************************************************************************/
+OBX_API extern void OBX_WcharToChar (char *a_str, UINT16* w_str, UINT16 a_size) ;
+
+/*******************************************************************************
+**
+** Function OBX_ReadAsciiNameHdr
+**
+** Description This function is called to get the Name Header in the given
+** OBEX packet. If Name header exists in the given OBEX packet,
+** it is converted to ASCII format and copied into p_name.
+**
+** Returns TRUE, if the header is in the OBEX packet.
+** FALSE, otherwise.
+**
+*******************************************************************************/
+OBX_API extern BOOLEAN OBX_ReadAsciiNameHdr(BT_HDR *p_pkt, char *p_name, UINT16 max_len);
+
+/*******************************************************************************
+**
+** Function OBX_ReadTypeHdr
+**
+** Description This function is called to get the Type Header in the given
+** OBEX packet.
+**
+** Returns TRUE, if the header is in the OBEX packet.
+** FALSE, otherwise.
+**
+*******************************************************************************/
+OBX_API extern BOOLEAN OBX_ReadTypeHdr(BT_HDR *p_pkt, UINT8 **p_type, UINT16 *p_len);
+
+/*******************************************************************************
+**
+** Function OBX_ReadLengthHdr
+**
+** Description This function is called to get the Length Header in the given
+** OBEX packet.
+**
+** Returns TRUE, if the header is in the OBEX packet.
+** FALSE, otherwise.
+**
+*******************************************************************************/
+OBX_API extern BOOLEAN OBX_ReadLengthHdr(BT_HDR *p_pkt, UINT32 *p_len);
+
+/*******************************************************************************
+**
+** Function OBX_ReadTimeHdr
+**
+** Description This function is called to get the Time Header in the given
+** OBEX packet.
+**
+** Returns TRUE, if the header is in the OBEX packet.
+** FALSE, otherwise.
+**
+*******************************************************************************/
+OBX_API extern BOOLEAN OBX_ReadTimeHdr(BT_HDR *p_pkt, UINT8 **p_time, UINT16 *p_len);
+
+/*******************************************************************************
+**
+** Function OBX_ReadDescrHdr
+**
+** Description This function is called to get the Description Header in the
+** given OBEX packet.
+**
+** Returns TRUE, if the header is in the OBEX packet.
+** FALSE, otherwise.
+**
+*******************************************************************************/
+OBX_API extern BOOLEAN OBX_ReadDescrHdr(BT_HDR *p_pkt, UINT16 *p_descr, UINT16 *p_len);
+
+/*******************************************************************************
+**
+** Function OBX_ReadDestNameHdr
+**
+** Description This function is called to get the DestName Header in the
+** given OBEX packet.
+**
+** Returns TRUE, if the header is in the OBEX packet.
+** FALSE, otherwise.
+**
+*******************************************************************************/
+OBX_API extern BOOLEAN OBX_ReadDestNameHdr(BT_HDR *p_pkt, UINT16 *p_dest, UINT16 *p_len);
+
+/*******************************************************************************
+**
+** Function OBX_ReadAsciiDescrHdr
+**
+** Description This function is called to get the Description Header in the
+** given OBEX packet. If Description header exists in the given
+** OBEX packet, it is converted to ASCII format and copied into
+** p_descr.
+**
+** Returns TRUE, if the header is in the OBEX packet.
+** FALSE, otherwise.
+**
+*******************************************************************************/
+OBX_API extern BOOLEAN OBX_ReadAsciiDescrHdr(BT_HDR *p_pkt, char *p_descr, UINT16 max_len);
+
+/*******************************************************************************
+**
+** Function OBX_ReadAsciiDestNameHdr
+**
+** Description This function is called to get the DestName Header in the
+** given OBEX packet. If DestName header exists in the given
+** OBEX packet, it is converted to ASCII format and copied into
+** p_descr.
+**
+** Returns TRUE, if the header is in the OBEX packet.
+** FALSE, otherwise.
+**
+*******************************************************************************/
+OBX_API extern BOOLEAN OBX_ReadAsciiDestNameHdr(BT_HDR *p_pkt, char *p_dest, UINT16 max_len);
+
+/*******************************************************************************
+**
+** Function OBX_ReadTargetHdr
+**
+** Description This function is called to get the Target Header in the
+** given OBEX packet.
+**
+** Returns TRUE, if the header is in the OBEX packet.
+** FALSE, otherwise.
+**
+*******************************************************************************/
+OBX_API extern BOOLEAN OBX_ReadTargetHdr(BT_HDR *p_pkt, UINT8 **p_target, UINT16 *p_len, UINT8 next);
+
+/*******************************************************************************
+**
+** Function OBX_ReadHttpHdr
+**
+** Description This function is called to get the HTTP Header in the
+** given OBEX packet.
+**
+** Returns TRUE, if the header is in the OBEX packet.
+** FALSE, otherwise.
+**
+*******************************************************************************/
+OBX_API extern BOOLEAN OBX_ReadHttpHdr(BT_HDR *p_pkt, UINT8 **p_http, UINT16 *p_len, UINT8 next);
+
+/*******************************************************************************
+**
+** Function OBX_ReadBodyHdr
+**
+** Description This function is called to get the Body Header in the
+** given OBEX packet.
+**
+** Returns 1, if a single header is in the OBEX packet.
+** 2, if a end of body header is in the OBEX packet.
+** 0, (FALSE) otherwise.
+**
+*******************************************************************************/
+OBX_API extern UINT8 OBX_ReadBodyHdr(BT_HDR *p_pkt, UINT8 **p_body, UINT16 *p_len, BOOLEAN *p_end);
+
+/*******************************************************************************
+**
+** Function OBX_ReadWhoHdr
+**
+** Description This function is called to get the Who Header in the
+** given OBEX packet.
+**
+** Returns TRUE, if the header is in the OBEX packet.
+** FALSE, otherwise.
+**
+*******************************************************************************/
+OBX_API extern BOOLEAN OBX_ReadWhoHdr(BT_HDR *p_pkt, UINT8 **p_who, UINT16 *p_len);
+
+/*******************************************************************************
+**
+** Function OBX_ReadAppParamHdr
+**
+** Description This function is called to get the Application Parameter Header
+** in the given OBEX packet.
+**
+** Returns TRUE, if the header is in the OBEX packet.
+** FALSE, otherwise.
+**
+*******************************************************************************/
+OBX_API extern BOOLEAN OBX_ReadAppParamHdr(BT_HDR *p_pkt, UINT8 *p_tag, UINT8 **p_app_param, UINT8 *p_len, UINT8 next);
+
+/*******************************************************************************
+**
+** Function OBX_ReadPermissionHdr
+**
+** Description This function is called to get the Application Parameter Header
+** in the given OBEX packet.
+**
+** Returns TRUE, if the header is in the OBEX packet.
+** FALSE, otherwise.
+**
+*******************************************************************************/
+OBX_API extern BOOLEAN OBX_ReadPermissionHdr(BT_HDR *p_pkt, UINT8 *p_user, UINT8 *p_group, UINT8 *p_other);
+
+/*******************************************************************************
+**
+** Function OBX_Read1ByteHdr
+**
+** Description This function is called to get the UINT8 HV of the given HI
+** in the given OBEX packet.
+**
+** Returns TRUE, if the header is in the OBEX packet.
+** FALSE, otherwise.
+**
+*******************************************************************************/
+OBX_API extern BOOLEAN OBX_Read1ByteHdr(BT_HDR *p_pkt, UINT8 id, UINT8 *p_data);
+
+/*******************************************************************************
+**
+** Function OBX_Read4ByteHdr
+**
+** Description This function is called to get the UINT32 HV of the given HI
+** in the given OBEX packet.
+**
+** Returns TRUE, if the header is in the OBEX packet.
+** FALSE, otherwise.
+**
+*******************************************************************************/
+OBX_API extern BOOLEAN OBX_Read4ByteHdr(BT_HDR *p_pkt, UINT8 id, UINT32 *p_data);
+
+/*******************************************************************************
+**
+** Function OBX_ReadByteStrHdr
+**
+** Description This function is called to get the byte sequence HV of the given
+** HI in the given OBEX packet.
+**
+** Returns TRUE, if the header is in the OBEX packet.
+** FALSE, otherwise.
+**
+*******************************************************************************/
+OBX_API extern BOOLEAN OBX_ReadByteStrHdr(BT_HDR *p_pkt, UINT8 id, UINT8 **p_data, UINT16 *p_len, UINT8 next);
+
+/*******************************************************************************
+**
+** Function OBX_ReadUnicodeHdr
+**
+** Description This function is called to get the Unicode HV of the given
+** HI in the given OBEX packet.
+**
+** Returns TRUE, if the header is in the OBEX packet.
+** FALSE, otherwise.
+**
+*******************************************************************************/
+OBX_API extern BOOLEAN OBX_ReadUnicodeHdr(BT_HDR *p_pkt, UINT8 id, UINT16 *p_data, UINT16 *p_len);
+
+/*******************************************************************************
+**
+** Function OBX_ReadTriplet
+**
+** Description This function is called to get the Triplet HV of the given
+** HI in the given OBEX packet.
+**
+** Returns TRUE, if the header is in the OBEX packet.
+** FALSE, otherwise.
+**
+*******************************************************************************/
+OBX_API extern BOOLEAN OBX_ReadTriplet(BT_HDR *p_pkt, UINT8 id, tOBX_TRIPLET *p_triplet, UINT8 *p_num);
+
+/*******************************************************************************
+**
+** Function OBX_ReadActionIdHdr
+**
+** Description This function is called to get the HV of the Action ID header
+** in the given OBEX packet.
+**
+** Returns TRUE, if the header is in the OBEX packet.
+** FALSE, otherwise.
+**
+*******************************************************************************/
+OBX_API extern BOOLEAN OBX_ReadActionIdHdr(BT_HDR *p_pkt, UINT8 *p_data);
+
+/*******************************************************************************
+**
+** Function OBX_ReadChallenge
+**
+** Description This function is called to read the Realm and options of the
+** Authentication Challenge Header in the given OBEX packet.
+**
+** Returns TRUE, if the header is in the OBEX packet.
+** FALSE, otherwise.
+**
+*******************************************************************************/
+OBX_API extern BOOLEAN OBX_ReadChallenge(BT_HDR *p_pkt, tOBX_CHARSET *p_charset,
+ UINT8 **p_realm, UINT8 *p_len,
+ tOBX_AUTH_OPT *p_option);
+
+/*******************************************************************************
+**
+** Function OBX_ReadAuthParams
+**
+** Description This function is called to read the User ID of the
+** Authentication Response Header in the given OBEX packet.
+**
+** Returns TRUE, if the header is in the OBEX packet.
+** FALSE, otherwise.
+**
+*******************************************************************************/
+OBX_API extern BOOLEAN OBX_ReadAuthParams(BT_HDR *p_pkt, UINT8 **p_userid, UINT8 *p_len,
+ BOOLEAN *is_challenged, tOBX_AUTH_OPT *p_option);
+
+
+/*******************************************************************************
+**
+** Function utfc_16_to_8
+**
+** Description Convert a UTF-16 array to a null-terminated UTF-8 string.
+** Illegal characters are skipped.
+**
+** Returns Length of UTF-8 string in bytes.
+**
+*******************************************************************************/
+OBX_API extern UINT16 utfc_16_to_8(UINT8 *p_utf8, UINT16 utf8_len, UINT16 *p_utf16, UINT16 utf16_len);
+
+/*******************************************************************************
+**
+** Function utfc_8_to_16
+**
+** Description Convert a null-terminated UTF-8 string to a UTF-16 array.
+** Illegal characters are skipped.
+**
+** Returns Length of UTF-16 array.
+**
+*******************************************************************************/
+OBX_API extern UINT16 utfc_8_to_16(UINT16 *p_utf16, UINT16 utf16_len, UINT8 *p_utf8);
+
+/*******************************************************************************
+**
+** Function OBX_AddUtf8NameHdr
+**
+** Description This function is called to add an OBEX Name header
+** to an OBEX packet.
+**
+** Returns TRUE, if the header is added successfully.
+** FALSE, if the operation failed. p_pkt is not altered.
+**
+*******************************************************************************/
+OBX_API extern BOOLEAN OBX_AddUtf8NameHdr(BT_HDR *p_pkt, UINT8 *p_name);
+
+/*******************************************************************************
+**
+** Function OBX_AddUtf8DescrHdr
+**
+** Description This function is called to add an OBEX Description header
+** to an OBEX packet.
+**
+** Returns TRUE, if the header is added successfully.
+** FALSE, if the operation failed. p_pkt is not altered.
+**
+*******************************************************************************/
+OBX_API extern BOOLEAN OBX_AddUtf8DescrHdr(BT_HDR *p_pkt, UINT8 *p_descr);
+
+/*******************************************************************************
+**
+** Function OBX_AddUtf8DestNameHdr
+**
+** Description This function is called to add an OBEX DestName header
+** to an OBEX packet.
+**
+** Returns TRUE, if the header is added successfully.
+** FALSE, if the operation failed. p_pkt is not altered.
+**
+*******************************************************************************/
+OBX_API extern BOOLEAN OBX_AddUtf8DestNameHdr(BT_HDR *p_pkt, UINT8 *p_dest);
+
+/*******************************************************************************
+**
+** Function OBX_ReadUtf8NameHdr
+**
+** Description This function is called to get the Name Header in the given
+** OBEX packet. If Name header exists in the given OBEX packet,
+** it is converted to UTF8 format and copied into p_name.
+**
+** Returns TRUE, if the header is in the OBEX packet.
+** FALSE, otherwise.
+**
+*******************************************************************************/
+OBX_API extern BOOLEAN OBX_ReadUtf8NameHdr(BT_HDR *p_pkt, UINT8 *p_name, UINT16 max_len);
+
+/*******************************************************************************
+**
+** Function OBX_ReadUtf8DescrHdr
+**
+** Description This function is called to get the Description Header in the
+** given OBEX packet. If Description header exists in the given
+** OBEX packet, it is converted to UTF8 format and copied into
+** p_descr.
+**
+** Returns TRUE, if the header is in the OBEX packet.
+** FALSE, otherwise.
+**
+*******************************************************************************/
+OBX_API extern BOOLEAN OBX_ReadUtf8DescrHdr(BT_HDR *p_pkt, UINT8 *p_descr, UINT16 max_len);
+
+/*******************************************************************************
+**
+** Function OBX_ReadUtf8DestNameHdr
+**
+** Description This function is called to get the DestName Header in the
+** given OBEX packet.
+**
+** Returns TRUE, if the header is in the OBEX packet.
+** FALSE, otherwise.
+**
+*******************************************************************************/
+OBX_API extern BOOLEAN OBX_ReadUtf8DestNameHdr(BT_HDR *p_pkt, UINT8 *p_dest, UINT16 max_len);
+
+/*******************************************************************************
+**
+** Function OBX_VerifyResponse
+**
+** Description This function is called by the client to verify the challenge
+** response.
+**
+** Returns TRUE, if successful.
+** FALSE, if authentication failed
+**
+*******************************************************************************/
+OBX_API extern BOOLEAN OBX_VerifyResponse(UINT32 nonce_u32, UINT8 *p_password, UINT8 password_len, UINT8 *p_response);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* OBX_API_H */
diff --git a/stack/include/pan_api.h b/stack/include/pan_api.h
new file mode 100644
index 0000000..9af03de
--- /dev/null
+++ b/stack/include/pan_api.h
@@ -0,0 +1,446 @@
+/*****************************************************************************
+**
+** Name: pan_api.h
+**
+** Description: this file contains the PAN API definitions
+**
+**
+** Copyright (c) 2001-2004, WIDCOMM Inc., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+#ifndef PAN_API_H
+#define PAN_API_H
+
+#include "bnep_api.h"
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+/* Define the minimum offset needed in a GKI buffer for
+** sending PAN packets. Note, we are currently not sending
+** extension headers, but may in the future, so allow
+** space for them
+*/
+#define PAN_MINIMUM_OFFSET BNEP_MINIMUM_OFFSET
+
+
+/*
+** The handle is passed from BNEP to PAN. The same handle is used
+** between PAN and application as well
+*/
+#define PAN_INVALID_HANDLE BNEP_INVALID_HANDLE
+
+/* Bit map for PAN roles */
+#define PAN_ROLE_CLIENT 0x01 /* PANU role */
+#define PAN_ROLE_GN_SERVER 0x02 /* GN role */
+#define PAN_ROLE_NAP_SERVER 0x04 /* NAP role */
+
+/* Bitmap to indicate the usage of the Data */
+#define PAN_DATA_TO_HOST 0x01
+#define PAN_DATA_TO_LAN 0x02
+
+
+/*****************************************************************************
+** Type Definitions
+*****************************************************************************/
+
+/* Define the result codes from PAN */
+enum
+{
+ PAN_SUCCESS, /* Success */
+ PAN_DISCONNECTED = BNEP_CONN_DISCONNECTED, /* Connection terminated */
+ PAN_CONN_FAILED = BNEP_CONN_FAILED, /* Connection failed */
+ PAN_NO_RESOURCES = BNEP_NO_RESOURCES, /* No resources */
+ PAN_MTU_EXCEDED = BNEP_MTU_EXCEDED, /* Attempt to write long data */
+ PAN_INVALID_OFFSET = BNEP_INVALID_OFFSET, /* Insufficient offset in GKI buffer */
+ PAN_CONN_FAILED_CFG = BNEP_CONN_FAILED_CFG, /* Connection failed cos of config */
+ PAN_INVALID_SRC_ROLE = BNEP_CONN_FAILED_SRC_UUID, /* Connection failed wrong source UUID */
+ PAN_INVALID_DST_ROLE = BNEP_CONN_FAILED_DST_UUID, /* Connection failed wrong destination UUID */
+ PAN_CONN_FAILED_UUID_SIZE = BNEP_CONN_FAILED_UUID_SIZE, /* Connection failed wrong size UUID */
+ PAN_Q_SIZE_EXCEEDED = BNEP_Q_SIZE_EXCEEDED, /* Too many buffers to dest */
+ PAN_TOO_MANY_FILTERS = BNEP_TOO_MANY_FILTERS, /* Too many local filters specified */
+ PAN_SET_FILTER_FAIL = BNEP_SET_FILTER_FAIL, /* Set Filter failed */
+ PAN_WRONG_HANDLE = BNEP_WRONG_HANDLE, /* Wrong handle for the connection */
+ PAN_WRONG_STATE = BNEP_WRONG_STATE, /* Connection is in wrong state */
+ PAN_SECURITY_FAIL = BNEP_SECURITY_FAIL, /* Failed because of security */
+ PAN_IGNORE_CMD = BNEP_IGNORE_CMD, /* To ignore the rcvd command */
+ PAN_TX_FLOW_ON = BNEP_TX_FLOW_ON, /* tx data flow enabled */
+ PAN_TX_FLOW_OFF = BNEP_TX_FLOW_OFF, /* tx data flow disabled */
+ PAN_FAILURE /* Failure */
+
+};
+typedef UINT8 tPAN_RESULT;
+
+
+/*****************************************************************
+** Callback Function Prototypes
+*****************************************************************/
+
+/* This is call back function used to report connection status
+** to the application. The second parameter TRUE means
+** to create the bridge and FALSE means to remove it.
+*/
+typedef void (tPAN_CONN_STATE_CB) (UINT16 handle, BD_ADDR bd_addr, tPAN_RESULT state, BOOLEAN is_role_change,
+ UINT8 src_role, UINT8 dst_role);
+
+
+/* This is call back function used to create bridge for the
+** Connected device. The parameter "state" indicates
+** whether to create the bridge or remove it. TRUE means
+** to create the bridge and FALSE means to remove it.
+*/
+typedef void (tPAN_BRIDGE_REQ_CB) (BD_ADDR bd_addr, BOOLEAN state);
+
+
+/* Data received indication callback prototype. Parameters are
+** Source BD/Ethernet Address
+** Dest BD/Ethernet address
+** Protocol
+** Address of buffer (or data if non-GKI)
+** Length of data (non-GKI)
+** ext is flag to indicate whether it has aby extension headers
+** Flag used to indicate to forward on LAN
+** FALSE - Use it for internal stack
+** TRUE - Send it across the ethernet as well
+*/
+typedef void (tPAN_DATA_IND_CB) (UINT16 handle,
+ BD_ADDR src,
+ BD_ADDR dst,
+ UINT16 protocol,
+ UINT8 *p_data,
+ UINT16 len,
+ BOOLEAN ext,
+ BOOLEAN forward);
+
+
+/* Data buffer received indication callback prototype. Parameters are
+** Source BD/Ethernet Address
+** Dest BD/Ethernet address
+** Protocol
+** pointer to the data buffer
+** ext is flag to indicate whether it has aby extension headers
+** Flag used to indicate to forward on LAN
+** FALSE - Use it for internal stack
+** TRUE - Send it across the ethernet as well
+*/
+typedef void (tPAN_DATA_BUF_IND_CB) (UINT16 handle,
+ BD_ADDR src,
+ BD_ADDR dst,
+ UINT16 protocol,
+ BT_HDR *p_buf,
+ BOOLEAN ext,
+ BOOLEAN forward);
+
+
+/* Flow control callback for TX data. Parameters are
+** Handle to the connection
+** Event flow status
+*/
+typedef void (tPAN_TX_DATA_FLOW_CB) (UINT16 handle,
+ tPAN_RESULT event);
+
+/* Filters received indication callback prototype. Parameters are
+** Handle to the connection
+** TRUE if the cb is called for indication
+** Ignore this if it is indication, otherwise it is the result
+** for the filter set operation performed by the local
+** device
+** Number of protocol filters present
+** Pointer to the filters start. Filters are present in pairs
+** of start of the range and end of the range.
+** They will be present in big endian order. First
+** two bytes will be starting of the first range and
+** next two bytes will be ending of the range.
+*/
+typedef void (tPAN_FILTER_IND_CB) (UINT16 handle,
+ BOOLEAN indication,
+ tBNEP_RESULT result,
+ UINT16 num_filters,
+ UINT8 *p_filters);
+
+
+
+/* Multicast Filters received indication callback prototype. Parameters are
+** Handle to the connection
+** TRUE if the cb is called for indication
+** Ignore this if it is indication, otherwise it is the result
+** for the filter set operation performed by the local
+** device
+** Number of multicast filters present
+** Pointer to the filters start. Filters are present in pairs
+** of start of the range and end of the range.
+** First six bytes will be starting of the first range and
+** next six bytes will be ending of the range.
+*/
+typedef void (tPAN_MFILTER_IND_CB) (UINT16 handle,
+ BOOLEAN indication,
+ tBNEP_RESULT result,
+ UINT16 num_mfilters,
+ UINT8 *p_mfilters);
+
+
+
+
+/* This structure is used to register with PAN profile
+** It is passed as a parameter to PAN_Register call.
+*/
+typedef struct
+{
+ tPAN_CONN_STATE_CB *pan_conn_state_cb; /* Connection state callback */
+ tPAN_BRIDGE_REQ_CB *pan_bridge_req_cb; /* Bridge request callback */
+ tPAN_DATA_IND_CB *pan_data_ind_cb; /* Data indication callback */
+ tPAN_DATA_BUF_IND_CB *pan_data_buf_ind_cb; /* Data buffer indication callback */
+ tPAN_FILTER_IND_CB *pan_pfilt_ind_cb; /* protocol filter indication callback */
+ tPAN_MFILTER_IND_CB *pan_mfilt_ind_cb; /* multicast filter indication callback */
+ tPAN_TX_DATA_FLOW_CB *pan_tx_data_flow_cb; /* data flow callback */
+ char *user_service_name; /* Service name for PANU role */
+ char *gn_service_name; /* Service name for GN role */
+ char *nap_service_name; /* Service name for NAP role */
+
+} tPAN_REGISTER;
+
+
+/*****************************************************************************
+** External Function Declarations
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*******************************************************************************
+**
+** Function PAN_Register
+**
+** Description This function is called by the application to register
+** its callbacks with PAN profile. The application then
+** should set the PAN role explicitly.
+**
+** Parameters: p_register - contains all callback function pointers
+**
+**
+** Returns none
+**
+*******************************************************************************/
+PAN_API extern void PAN_Register (tPAN_REGISTER *p_register);
+
+
+/*******************************************************************************
+**
+** Function PAN_Deregister
+**
+** Description This function is called by the application to de-register
+** its callbacks with PAN profile. This will make the PAN to
+** become inactive. This will deregister PAN services from SDP
+** and close all active connections
+**
+** Returns none
+**
+*******************************************************************************/
+PAN_API extern void PAN_Deregister (void);
+
+/*******************************************************************************
+**
+** Function PAN_SetRole
+**
+** Description This function is called by the application to set the PAN
+** profile role. This should be called after PAN_Register.
+** This can be called any time to change the PAN role
+**
+** Parameters: role - is bit map of roles to be active
+** PAN_ROLE_CLIENT is for PANU role
+** PAN_ROLE_GN_SERVER is for GN role
+** PAN_ROLE_NAP_SERVER is for NAP role
+** sec_mask - Security mask for different roles
+** It is array of UINT8. The byte represent the
+** security for roles PANU, GN and NAP in order
+** p_user_name - Service name for PANU role
+** p_gn_name - Service name for GN role
+** p_nap_name - Service name for NAP role
+** Can be NULL if user wants it to be default
+**
+** Returns PAN_SUCCESS - if the role is set successfully
+** PAN_FAILURE - if the role is not valid
+**
+*******************************************************************************/
+PAN_API extern tPAN_RESULT PAN_SetRole (UINT8 role,
+ UINT8 *sec_mask,
+ char *p_user_name,
+ char *p_gn_name,
+ char *p_nap_name);
+
+/*******************************************************************************
+**
+** Function PAN_Connect
+**
+** Description This function is called by the application to initiate a
+** connection to the remote device
+**
+** Parameters: rem_bda - BD Addr of the remote device
+** src_role - Role of the local device for the connection
+** dst_role - Role of the remote device for the connection
+** PAN_ROLE_CLIENT is for PANU role
+** PAN_ROLE_GN_SERVER is for GN role
+** PAN_ROLE_NAP_SERVER is for NAP role
+** *handle - Pointer for returning Handle to the connection
+**
+** Returns PAN_SUCCESS - if the connection is initiated successfully
+** PAN_NO_RESOURCES - resources are not sufficent
+** PAN_FAILURE - if the connection cannot be initiated
+** this can be because of the combination of
+** src and dst roles may not be valid or
+** allowed at that point of time
+**
+*******************************************************************************/
+PAN_API extern tPAN_RESULT PAN_Connect (BD_ADDR rem_bda, UINT8 src_role, UINT8 dst_role, UINT16 *handle);
+
+/*******************************************************************************
+**
+** Function PAN_Disconnect
+**
+** Description This is used to disconnect the connection
+**
+** Parameters: handle - handle for the connection
+**
+** Returns PAN_SUCCESS - if the connection is closed successfully
+** PAN_FAILURE - if the connection is not found or
+** there is an error in disconnecting
+**
+*******************************************************************************/
+PAN_API extern tPAN_RESULT PAN_Disconnect (UINT16 handle);
+
+/*******************************************************************************
+**
+** Function PAN_Write
+**
+** Description This sends data over the PAN connections. If this is called
+** on GN or NAP side and the packet is multicast or broadcast
+** it will be sent on all the links. Otherwise the correct link
+** is found based on the destination address and forwarded on it
+** If the return value is not PAN_SUCCESS the application should
+** take care of releasing the message buffer
+**
+** Parameters: dst - MAC or BD Addr of the destination device
+** src - MAC or BD Addr of the source who sent this packet
+** protocol - protocol of the ethernet packet like IP or ARP
+** p_data - pointer to the data
+** len - length of the data
+** ext - to indicate that extension headers present
+**
+** Returns PAN_SUCCESS - if the data is sent successfully
+** PAN_FAILURE - if the connection is not found or
+** there is an error in sending data
+**
+*******************************************************************************/
+PAN_API extern tPAN_RESULT PAN_Write (UINT16 handle,
+ BD_ADDR dst,
+ BD_ADDR src,
+ UINT16 protocol,
+ UINT8 *p_data,
+ UINT16 len,
+ BOOLEAN ext);
+
+/*******************************************************************************
+**
+** Function PAN_WriteBuf
+**
+** Description This sends data over the PAN connections. If this is called
+** on GN or NAP side and the packet is multicast or broadcast
+** it will be sent on all the links. Otherwise the correct link
+** is found based on the destination address and forwarded on it
+** If the return value is not PAN_SUCCESS the application should
+** take care of releasing the message buffer
+**
+** Parameters: dst - MAC or BD Addr of the destination device
+** src - MAC or BD Addr of the source who sent this packet
+** protocol - protocol of the ethernet packet like IP or ARP
+** p_buf - pointer to the data buffer
+** ext - to indicate that extension headers present
+**
+** Returns PAN_SUCCESS - if the data is sent successfully
+** PAN_FAILURE - if the connection is not found or
+** there is an error in sending data
+**
+*******************************************************************************/
+PAN_API extern tPAN_RESULT PAN_WriteBuf (UINT16 handle,
+ BD_ADDR dst,
+ BD_ADDR src,
+ UINT16 protocol,
+ BT_HDR *p_buf,
+ BOOLEAN ext);
+
+/*******************************************************************************
+**
+** Function PAN_SetProtocolFilters
+**
+** Description This function is used to set protocol filters on the peer
+**
+** Parameters: handle - handle for the connection
+** num_filters - number of protocol filter ranges
+** start - array of starting protocol numbers
+** end - array of ending protocol numbers
+**
+**
+** Returns PAN_SUCCESS if protocol filters are set successfully
+** PAN_FAILURE if connection not found or error in setting
+**
+*******************************************************************************/
+PAN_API extern tPAN_RESULT PAN_SetProtocolFilters (UINT16 handle,
+ UINT16 num_filters,
+ UINT16 *p_start_array,
+ UINT16 *p_end_array);
+
+/*******************************************************************************
+**
+** Function PAN_SetMulticastFilters
+**
+** Description This function is used to set multicast filters on the peer
+**
+** Parameters: handle - handle for the connection
+** num_filters - number of multicast filter ranges
+** p_start_array - Pointer to sequence of beginings of all
+** multicast address ranges
+** p_end_array - Pointer to sequence of ends of all
+** multicast address ranges
+**
+**
+** Returns PAN_SUCCESS if multicast filters are set successfully
+** PAN_FAILURE if connection not found or error in setting
+**
+*******************************************************************************/
+PAN_API extern tBNEP_RESULT PAN_SetMulticastFilters (UINT16 handle,
+ UINT16 num_mcast_filters,
+ UINT8 *p_start_array,
+ UINT8 *p_end_array);
+
+/*******************************************************************************
+**
+** Function PAN_SetTraceLevel
+**
+** Description This function sets the trace level for PAN. If called with
+** a value of 0xFF, it simply reads the current trace level.
+**
+** Returns the new (current) trace level
+**
+*******************************************************************************/
+PAN_API extern UINT8 PAN_SetTraceLevel (UINT8 new_level);
+
+/*******************************************************************************
+**
+** Function PAN_Init
+**
+** Description This function initializes the PAN unit. It should be called
+** before accessing any other APIs to initialize the control
+** block.
+**
+** Returns void
+**
+*******************************************************************************/
+PAN_API extern void PAN_Init (void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PAN_API_H */
diff --git a/stack/include/port_api.h b/stack/include/port_api.h
new file mode 100644
index 0000000..26e0299
--- /dev/null
+++ b/stack/include/port_api.h
@@ -0,0 +1,605 @@
+/*****************************************************************************
+**
+** Name: port_api.h
+**
+** Description: this file contains the PORT API definitions
+**
+**
+** Copyright (c) 1999-2008, Broadcom Corp., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+#ifndef PORT_API_H
+#define PORT_API_H
+
+#include "bt_target.h"
+
+/*****************************************************************************
+** Constants and Types
+*****************************************************************************/
+
+/*
+** Define port settings structure send from the application in the
+** set settings request, or to the application in the set settings indication.
+*/
+typedef struct
+{
+
+#define PORT_BAUD_RATE_2400 0x00
+#define PORT_BAUD_RATE_4800 0x01
+#define PORT_BAUD_RATE_7200 0x02
+#define PORT_BAUD_RATE_9600 0x03
+#define PORT_BAUD_RATE_19200 0x04
+#define PORT_BAUD_RATE_38400 0x05
+#define PORT_BAUD_RATE_57600 0x06
+#define PORT_BAUD_RATE_115200 0x07
+#define PORT_BAUD_RATE_230400 0x08
+
+ UINT8 baud_rate;
+
+#define PORT_5_BITS 0x00
+#define PORT_6_BITS 0x01
+#define PORT_7_BITS 0x02
+#define PORT_8_BITS 0x03
+
+ UINT8 byte_size;
+
+#define PORT_ONESTOPBIT 0x00
+#define PORT_ONE5STOPBITS 0x01
+ UINT8 stop_bits;
+
+#define PORT_PARITY_NO 0x00
+#define PORT_PARITY_YES 0x01
+ UINT8 parity;
+
+#define PORT_ODD_PARITY 0x00
+#define PORT_EVEN_PARITY 0x01
+#define PORT_MARK_PARITY 0x02
+#define PORT_SPACE_PARITY 0x03
+
+ UINT8 parity_type;
+
+#define PORT_FC_OFF 0x00
+#define PORT_FC_XONXOFF_ON_INPUT 0x01
+#define PORT_FC_XONXOFF_ON_OUTPUT 0x02
+#define PORT_FC_CTS_ON_INPUT 0x04
+#define PORT_FC_CTS_ON_OUTPUT 0x08
+#define PORT_FC_DSR_ON_INPUT 0x10
+#define PORT_FC_DSR_ON_OUTPUT 0x20
+
+ UINT8 fc_type;
+
+ UINT8 rx_char1;
+
+#define PORT_XON_DC1 0x11
+ UINT8 xon_char;
+
+#define PORT_XOFF_DC3 0x13
+ UINT8 xoff_char;
+
+} tPORT_STATE;
+
+
+/*
+** Define the callback function prototypes. Parameters are specific
+** to each event and are described bellow
+*/
+typedef int (tPORT_DATA_CALLBACK) (UINT16 port_handle, void *p_data, UINT16 len);
+typedef void (tPORT_CALLBACK) (UINT32 code, UINT16 port_handle);
+
+/*
+** Define events that registered application can receive in the callback
+*/
+
+#define PORT_EV_RXCHAR 0x00000001 /* Any Character received */
+#define PORT_EV_RXFLAG 0x00000002 /* Received certain character */
+#define PORT_EV_TXEMPTY 0x00000004 /* Transmitt Queue Empty */
+#define PORT_EV_CTS 0x00000008 /* CTS changed state */
+#define PORT_EV_DSR 0x00000010 /* DSR changed state */
+#define PORT_EV_RLSD 0x00000020 /* RLSD changed state */
+#define PORT_EV_BREAK 0x00000040 /* BREAK received */
+#define PORT_EV_ERR 0x00000080 /* Line status error occurred */
+#define PORT_EV_RING 0x00000100 /* Ring signal detected */
+#define PORT_EV_CTSS 0x00000400 /* CTS state */
+#define PORT_EV_DSRS 0x00000800 /* DSR state */
+#define PORT_EV_RLSDS 0x00001000 /* RLSD state */
+#define PORT_EV_OVERRUN 0x00002000 /* receiver buffer overrun */
+#define PORT_EV_TXCHAR 0x00004000 /* Any character transmitted */
+
+#define PORT_EV_CONNECTED 0x00000200 /* RFCOMM connection established */
+#define PORT_EV_CONNECT_ERR 0x00008000 /* Was not able to establish connection */
+ /* or disconnected */
+#define PORT_EV_FC 0x00010000 /* data flow enabled flag changed by remote */
+#define PORT_EV_FCS 0x00020000 /* data flow enable status true = enabled */
+
+/*
+** To register for events application should provide bitmask with
+** corresponding bit set
+*/
+
+#define PORT_MASK_ALL (PORT_EV_RXCHAR | PORT_EV_TXEMPTY | PORT_EV_CTS | \
+ PORT_EV_DSR | PORT_EV_RLSD | PORT_EV_BREAK | \
+ PORT_EV_ERR | PORT_EV_RING | PORT_EV_CONNECT_ERR | \
+ PORT_EV_DSRS | PORT_EV_CTSS | PORT_EV_RLSDS | \
+ PORT_EV_RXFLAG | PORT_EV_TXCHAR | PORT_EV_OVERRUN | \
+ PORT_EV_FC | PORT_EV_FCS | PORT_EV_CONNECTED)
+
+
+/*
+** Define port result codes
+*/
+#define PORT_SUCCESS 0
+
+#define PORT_ERR_BASE 0
+
+#define PORT_UNKNOWN_ERROR (PORT_ERR_BASE + 1)
+#define PORT_ALREADY_OPENED (PORT_ERR_BASE + 2)
+#define PORT_CMD_PENDING (PORT_ERR_BASE + 3)
+#define PORT_APP_NOT_REGISTERED (PORT_ERR_BASE + 4)
+#define PORT_NO_MEM (PORT_ERR_BASE + 5)
+#define PORT_NO_RESOURCES (PORT_ERR_BASE + 6)
+#define PORT_BAD_BD_ADDR (PORT_ERR_BASE + 7)
+#define PORT_BAD_HANDLE (PORT_ERR_BASE + 9)
+#define PORT_NOT_OPENED (PORT_ERR_BASE + 10)
+#define PORT_LINE_ERR (PORT_ERR_BASE + 11)
+#define PORT_START_FAILED (PORT_ERR_BASE + 12)
+#define PORT_PAR_NEG_FAILED (PORT_ERR_BASE + 13)
+#define PORT_PORT_NEG_FAILED (PORT_ERR_BASE + 14)
+#define PORT_SEC_FAILED (PORT_ERR_BASE + 15)
+#define PORT_PEER_CONNECTION_FAILED (PORT_ERR_BASE + 16)
+#define PORT_PEER_FAILED (PORT_ERR_BASE + 17)
+#define PORT_PEER_TIMEOUT (PORT_ERR_BASE + 18)
+#define PORT_CLOSED (PORT_ERR_BASE + 19)
+#define PORT_TX_FULL (PORT_ERR_BASE + 20)
+#define PORT_LOCAL_CLOSED (PORT_ERR_BASE + 21)
+#define PORT_LOCAL_TIMEOUT (PORT_ERR_BASE + 22)
+#define PORT_TX_QUEUE_DISABLED (PORT_ERR_BASE + 23)
+#define PORT_PAGE_TIMEOUT (PORT_ERR_BASE + 24)
+#define PORT_INVALID_SCN (PORT_ERR_BASE + 25)
+
+
+/*****************************************************************************
+** External Function Declarations
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*******************************************************************************
+**
+** Function RFCOMM_CreateConnection
+**
+** Description RFCOMM_CreateConnection function is used from the application
+** to establish serial port connection to the peer device,
+** or allow RFCOMM to accept a connection from the peer
+** application.
+**
+** Parameters: scn - Service Channel Number as registered with
+** the SDP (server) or obtained using SDP from
+** the peer device (client).
+** is_server - TRUE if requesting application is a server
+** mtu - Maximum frame size the application can accept
+** bd_addr - BD_ADDR of the peer (client)
+** mask - specifies events to be enabled. A value
+** of zero disables all events.
+** p_handle - OUT pointer to the handle.
+** p_mgmt_cb - pointer to callback function to receive
+** connection up/down events.
+** Notes:
+**
+** Server can call this function with the same scn parameter multiple times if
+** it is ready to accept multiple simulteneous connections.
+**
+** DLCI for the connection is (scn * 2 + 1) if client originates connection on
+** existing none initiator multiplexer channel. Otherwise it is (scn * 2).
+** For the server DLCI can be changed later if client will be calling it using
+** (scn * 2 + 1) dlci.
+**
+*******************************************************************************/
+RFC_API extern int RFCOMM_CreateConnection (UINT16 uuid, UINT8 scn,
+ BOOLEAN is_server, UINT16 mtu,
+ BD_ADDR bd_addr, UINT16 *p_handle,
+ tPORT_CALLBACK *p_mgmt_cb);
+
+
+/*******************************************************************************
+**
+** Function RFCOMM_RemoveConnection
+**
+** Description This function is called to close the specified connection.
+**
+** Parameters: handle - Handle of the port returned in the Open
+**
+*******************************************************************************/
+RFC_API extern int RFCOMM_RemoveConnection (UINT16 handle);
+
+
+/*******************************************************************************
+**
+** Function RFCOMM_RemoveServer
+**
+** Description This function is called to close the server port.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+**
+*******************************************************************************/
+RFC_API extern int RFCOMM_RemoveServer (UINT16 handle);
+
+
+/*******************************************************************************
+**
+** Function PORT_SetEventCallback
+**
+** Description Set event callback the specified connection.
+**
+** Parameters: handle - Handle of the port returned in the Open
+** p_callback - address of the callback function which should
+** be called from the RFCOMM when an event
+** specified in the mask occurs.
+**
+*******************************************************************************/
+RFC_API extern int PORT_SetEventCallback (UINT16 port_handle,
+ tPORT_CALLBACK *p_port_cb);
+
+
+/*******************************************************************************
+**
+** Function PORT_SetEventCallback
+**
+** Description Set event data callback the specified connection.
+**
+** Parameters: handle - Handle of the port returned in the Open
+** p_callback - address of the callback function which should
+** be called from the RFCOMM when a data
+** packet is received.
+**
+*******************************************************************************/
+RFC_API extern int PORT_SetDataCallback (UINT16 port_handle,
+ tPORT_DATA_CALLBACK *p_cb);
+
+
+/*******************************************************************************
+**
+** Function PORT_SetEventMask
+**
+** Description This function is called to close the specified connection.
+**
+** Parameters: handle - Handle of the port returned in the Open
+** mask - specifies events to be enabled. A value
+** of zero disables all events.
+**
+*******************************************************************************/
+RFC_API extern int PORT_SetEventMask (UINT16 port_handle, UINT32 mask);
+
+
+/*******************************************************************************
+**
+** Function PORT_CheckConnection
+**
+** Description This function returns PORT_SUCCESS if connection referenced
+** by handle is up and running
+**
+** Parameters: handle - Handle of the port returned in the Open
+** bd_addr - OUT bd_addr of the peer
+** p_lcid - OUT L2CAP's LCID
+**
+*******************************************************************************/
+RFC_API extern int PORT_CheckConnection (UINT16 handle, BD_ADDR bd_addr,
+ UINT16 *p_lcid);
+
+/*******************************************************************************
+**
+** Function PORT_IsOpening
+**
+** Description This function returns TRUE if there is any RFCOMM connection
+** opening in process.
+**
+** Parameters: TRUE if any connection opening is found
+** bd_addr - bd_addr of the peer
+**
+*******************************************************************************/
+RFC_API extern BOOLEAN PORT_IsOpening (BD_ADDR bd_addr);
+
+/*******************************************************************************
+**
+** Function PORT_SetState
+**
+** Description This function configures connection according to the
+** specifications in the tPORT_STATE structure.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** p_settings - Pointer to a tPORT_STATE structure containing
+** configuration information for the connection.
+**
+*******************************************************************************/
+RFC_API extern int PORT_SetState (UINT16 handle, tPORT_STATE *p_settings);
+
+/*******************************************************************************
+**
+** Function PORT_GetRxQueueCnt
+**
+** Description This function return number of buffers on the rx queue.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** p_rx_queue_count - Pointer to return queue count in.
+**
+*******************************************************************************/
+RFC_API extern int PORT_GetRxQueueCnt (UINT16 handle, UINT16 *p_rx_queue_count);
+
+/*******************************************************************************
+**
+** Function PORT_GetState
+**
+** Description This function is called to fill tPORT_STATE structure
+** with the current control settings for the port
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** p_settings - Pointer to a tPORT_STATE structure in which
+** configuration information is returned.
+**
+*******************************************************************************/
+RFC_API extern int PORT_GetState (UINT16 handle, tPORT_STATE *p_settings);
+
+
+/*******************************************************************************
+**
+** Function PORT_Control
+**
+** Description This function directs a specified connection to pass control
+** control information to the peer device.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** signal - specify the function to be passed
+**
+*******************************************************************************/
+#define PORT_SET_DTRDSR 0x01
+#define PORT_CLR_DTRDSR 0x02
+#define PORT_SET_CTSRTS 0x03
+#define PORT_CLR_CTSRTS 0x04
+#define PORT_SET_RI 0x05 /* DCE only */
+#define PORT_CLR_RI 0x06 /* DCE only */
+#define PORT_SET_DCD 0x07 /* DCE only */
+#define PORT_CLR_DCD 0x08 /* DCE only */
+#define PORT_BREAK 0x09 /* Break event */
+
+RFC_API extern int PORT_Control (UINT16 handle, UINT8 signal);
+
+
+/*******************************************************************************
+**
+** Function PORT_FlowControl
+**
+** Description This function directs a specified connection to pass
+** flow control message to the peer device. Enable flag passed
+** shows if port can accept more data.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** enable - enables data flow
+**
+*******************************************************************************/
+RFC_API extern int PORT_FlowControl (UINT16 handle, BOOLEAN enable);
+
+
+/*******************************************************************************
+**
+** Function PORT_GetModemStatus
+**
+** Description This function retrieves modem control signals. Normally
+** application will call this function after a callback
+** function is called with notification that one of signals
+** has been changed.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** callback.
+** p_signal - specify the pointer to control signals info
+**
+*******************************************************************************/
+#define PORT_DTRDSR_ON 0x01
+#define PORT_CTSRTS_ON 0x02
+#define PORT_RING_ON 0x04
+#define PORT_DCD_ON 0x08
+
+/*
+** Define default initial local modem signals state set after connection established
+*/
+#define PORT_OBEX_DEFAULT_SIGNAL_STATE (PORT_DTRDSR_ON | PORT_CTSRTS_ON | PORT_DCD_ON)
+#define PORT_SPP_DEFAULT_SIGNAL_STATE (PORT_DTRDSR_ON | PORT_CTSRTS_ON | PORT_DCD_ON)
+#define PORT_PPP_DEFAULT_SIGNAL_STATE (PORT_DTRDSR_ON | PORT_CTSRTS_ON | PORT_DCD_ON)
+#define PORT_DUN_DEFAULT_SIGNAL_STATE (PORT_DTRDSR_ON | PORT_CTSRTS_ON)
+
+RFC_API extern int PORT_GetModemStatus (UINT16 handle, UINT8 *p_control_signal);
+
+
+/*******************************************************************************
+**
+** Function PORT_ClearError
+**
+** Description This function retreives information about a communications
+** error and reports current status of a connection. The
+** function should be called when an error occures to clear
+** the connection error flag and to enable additional read
+** and write operations.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** p_errors - pointer of the variable to receive error codes
+** p_status - pointer to the tPORT_STATUS structur to receive
+** connection status
+**
+*******************************************************************************/
+
+#define PORT_ERR_BREAK 0x01 /* Break condition occured on the peer device */
+#define PORT_ERR_OVERRUN 0x02 /* Overrun is reported by peer device */
+#define PORT_ERR_FRAME 0x04 /* Framing error reported by peer device */
+#define PORT_ERR_RXOVER 0x08 /* Input queue overflow occured */
+#define PORT_ERR_TXFULL 0x10 /* Output queue overflow occured */
+
+typedef struct
+{
+#define PORT_FLAG_CTS_HOLD 0x01 /* Tx is waiting for CTS signal */
+#define PORT_FLAG_DSR_HOLD 0x02 /* Tx is waiting for DSR signal */
+#define PORT_FLAG_RLSD_HOLD 0x04 /* Tx is waiting for RLSD signal */
+
+ UINT16 flags;
+ UINT16 in_queue_size; /* Number of bytes in the input queue */
+ UINT16 out_queue_size; /* Number of bytes in the output queue */
+ UINT16 mtu_size; /* peer MTU size */
+} tPORT_STATUS;
+
+
+RFC_API extern int PORT_ClearError (UINT16 handle, UINT16 *p_errors,
+ tPORT_STATUS *p_status);
+
+
+/*******************************************************************************
+**
+** Function PORT_SendError
+**
+** Description This function send a communications error to the peer device
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** errors - receive error codes
+**
+*******************************************************************************/
+RFC_API extern int PORT_SendError (UINT16 handle, UINT8 errors);
+
+
+/*******************************************************************************
+**
+** Function PORT_GetQueueStatus
+**
+** Description This function reports current status of a connection.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** p_status - pointer to the tPORT_STATUS structur to receive
+** connection status
+**
+*******************************************************************************/
+RFC_API extern int PORT_GetQueueStatus (UINT16 handle, tPORT_STATUS *p_status);
+
+
+/*******************************************************************************
+**
+** Function PORT_Purge
+**
+** Description This function discards all the data from the output or
+** input queues of the specified connection.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** purge_flags - specify the action to take.
+**
+*******************************************************************************/
+#define PORT_PURGE_TXCLEAR 0x01
+#define PORT_PURGE_RXCLEAR 0x02
+
+RFC_API extern int PORT_Purge (UINT16 handle, UINT8 purge_flags);
+
+
+/*******************************************************************************
+**
+** Function PORT_Read
+**
+** Description This function returns the pointer to the buffer received
+** from the peer device. Normally application will call this
+** function after receiving PORT_EVT_RXCHAR event.
+** Application calling this function is responsible to free
+** buffer returned.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** callback.
+** pp_buf - pointer to address of buffer with data,
+**
+*******************************************************************************/
+RFC_API extern int PORT_Read (UINT16 handle, BT_HDR **pp_buf);
+
+
+/*******************************************************************************
+**
+** Function PORT_ReadData
+**
+** Description Normally application will call this function after receiving
+** PORT_EVT_RXCHAR event.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** callback.
+** p_data - Data area
+** max_len - Byte count requested
+** p_len - Byte count received
+**
+*******************************************************************************/
+RFC_API extern int PORT_ReadData (UINT16 handle, char *p_data, UINT16 max_len,
+ UINT16 *p_len);
+
+
+/*******************************************************************************
+**
+** Function PORT_Write
+**
+** Description This function to send BT buffer to the peer device.
+** Application should not free the buffer.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** p_buf - pointer to the buffer with data,
+**
+*******************************************************************************/
+RFC_API extern int PORT_Write (UINT16 handle, BT_HDR *p_buf);
+
+
+/*******************************************************************************
+**
+** Function PORT_WriteData
+**
+** Description This function is called from the legacy application to
+** send data.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** p_data - Data area
+** max_len - Byte count to write
+** p_len - Bytes written
+**
+*******************************************************************************/
+RFC_API extern int PORT_WriteData (UINT16 handle, char *p_data, UINT16 max_len,
+ UINT16 *p_len);
+
+
+/*******************************************************************************
+**
+** Function PORT_Test
+**
+** Description Application can call this function to send RFCOMM Test frame
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** p_data - Data area
+** max_len - Byte count requested
+**
+*******************************************************************************/
+RFC_API extern int PORT_Test (UINT16 handle, UINT8 *p_data, UINT16 len);
+
+
+/*******************************************************************************
+**
+** Function RFCOMM_Init
+**
+** Description This function is called to initialize RFCOMM layer
+**
+*******************************************************************************/
+RFC_API extern void RFCOMM_Init (void);
+
+
+/*******************************************************************************
+**
+** Function PORT_SetTraceLevel
+**
+** Description This function sets the trace level for RFCOMM. If called with
+** a value of 0xFF, it simply reads the current trace level.
+**
+** Returns the new (current) trace level
+**
+*******************************************************************************/
+RFC_API extern UINT8 PORT_SetTraceLevel (UINT8 new_level);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PORT_API_H */
diff --git a/stack/include/port_ext.h b/stack/include/port_ext.h
new file mode 100644
index 0000000..37497d8
--- /dev/null
+++ b/stack/include/port_ext.h
@@ -0,0 +1,19 @@
+/*****************************************************************************/
+/* */
+/* Name: port_ext.h */
+/* */
+/* Description: This file contains external definitions of Port Emulation */
+/* entity unit */
+/* */
+/* */
+/* Copyright (c) 1999-2004, WIDCOMM Inc., All Rights Reserved. */
+/* WIDCOMM Bluetooth Core. Proprietary and confidential. */
+/*****************************************************************************/
+#ifndef PORTEXT_H
+#define PORTEXT_H
+
+#include "gki.h"
+
+/* Port emulation entity Entry Points */
+extern void rfcomm_process_timeout (TIMER_LIST_ENT *p_tle);
+#endif
diff --git a/stack/include/rfcdefs.h b/stack/include/rfcdefs.h
new file mode 100644
index 0000000..4dacda1
--- /dev/null
+++ b/stack/include/rfcdefs.h
@@ -0,0 +1,236 @@
+/****************************************************************************/
+/* */
+/* Name rfcdefs.h */
+/* */
+/* Function this file contains definitions for the RFCOMM protocol */
+/* */
+/* */
+/* Copyright (c) 1999-2008, Broadcom Corp., All Rights Reserved. */
+/* Broadcom Bluetooth Core. Proprietary and confidential. */
+/* */
+/****************************************************************************/
+
+#ifndef RFCDEFS_H
+#define RFCDEFS_H
+
+#define PORT_MAX_RFC_PORTS 31
+
+/*
+** If nothing is negotiated MTU should be 127
+*/
+#define RFCOMM_DEFAULT_MTU 127
+
+/*
+** Define used by RFCOMM TS frame types
+*/
+#define RFCOMM_SABME 0x2F
+#define RFCOMM_UA 0x63
+#define RFCOMM_DM 0x0F
+#define RFCOMM_DISC 0x43
+#define RFCOMM_UIH 0xEF
+
+/*
+** Defenitions for the TS control frames
+*/
+#define RFCOMM_CTRL_FRAME_LEN 3
+#define RFCOMM_MIN_OFFSET 5 /* ctrl 2 , len 1 or 2 bytes, credit 1 byte */
+#define RFCOMM_DATA_OVERHEAD (RFCOMM_MIN_OFFSET + 1) /* add 1 for checksum */
+
+#define RFCOMM_EA 1
+#define RFCOMM_EA_MASK 0x01
+#define RFCOMM_CR_MASK 0x02
+#define RFCOMM_SHIFT_CR 1
+#define RFCOMM_SHIFT_DLCI 2
+#define RFCOMM_SHIFT_DLCI2 6
+#define RFCOMM_PF 0x10
+#define RFCOMM_PF_MASK 0x10
+#define RFCOMM_PF_OFFSET 4
+#define RFCOMM_SHIFT_LENGTH1 1
+#define RFCOMM_SHIFT_LENGTH2 7
+#define RFCOMM_SHIFT_MX_CTRL_TYPE 2
+
+#define RFCOMM_INITIATOR_CMD 1
+#define RFCOMM_INITIATOR_RSP 0
+#define RFCOMM_RESPONDER_CMD 0
+#define RFCOMM_RESPONDER_RSP 1
+
+#define RFCOMM_PARSE_CTRL_FIELD(ea, cr, dlci, p_data) \
+{ \
+ ea = *p_data & RFCOMM_EA; \
+ cr = (*p_data & RFCOMM_CR_MASK) >> RFCOMM_SHIFT_CR; \
+ dlci = *p_data++ >> RFCOMM_SHIFT_DLCI; \
+ if (!ea) dlci += *p_data++ << RFCOMM_SHIFT_DLCI2; \
+}
+
+#define RFCOMM_FORMAT_CTRL_FIELD(p_data, ea, cr, dlci) \
+ *p_data++ = ea | cr | (dlci << RFCOMM_SHIFT_DLCI)
+
+#define RFCOMM_PARSE_TYPE_FIELD(type, pf, p_data) \
+{ \
+ type = *p_data & ~RFCOMM_PF_MASK; \
+ pf = (*p_data++ & RFCOMM_PF_MASK) >> RFCOMM_PF_OFFSET;\
+}
+
+#define RFCOMM_FORMAT_TYPE_FIELD(p_data, type, pf) \
+ *p_data++ = (type | (pf << RFCOMM_PF_OFFSET)) \
+{ \
+ type = *p_data & ~RFCOMM_PF_MASK; \
+ pf = (*p_data++ & RFCOMM_PF_MASK) >> RFCOMM_PF_OFFSET;\
+}
+
+#define RFCOMM_PARSE_LEN_FIELD(ea, length, p_data) \
+{ \
+ ea = (*p_data & RFCOMM_EA); \
+ length = (*p_data++ >> RFCOMM_SHIFT_LENGTH1); \
+ if (!ea) length += (*p_data++ << RFCOMM_SHIFT_LENGTH2); \
+}
+
+#define RFCOMM_FRAME_IS_CMD(initiator, cr) \
+ (( (initiator) && !(cr)) || (!(initiator) && (cr)))
+
+#define RFCOMM_FRAME_IS_RSP(initiator, cr) \
+ (( (initiator) && (cr)) || (!(initiator) && !(cr)))
+
+#define RFCOMM_CR(initiator, is_command) \
+ (( ( (initiator) && (is_command)) \
+ || (!(initiator) && !(is_command))) << 1)
+
+#define RFCOMM_I_CR(is_command) ((is_command) ? 0x02 : 0x00)
+
+#define RFCOMM_MAX_DLCI 61
+
+#define RFCOMM_VALID_DLCI(dlci) \
+ (((dlci) == 0) || (((dlci) >= 2) && ((dlci) <= RFCOMM_MAX_DLCI)))
+
+
+/* Port Negotiation (PN) */
+#define RFCOMM_PN_DLCI_MASK 0x3F
+
+#define RFCOMM_PN_FRAM_TYPE_UIH 0x00
+#define RFCOMM_PN_FRAME_TYPE_MASK 0x0F
+
+#define RFCOMM_PN_CONV_LAYER_MASK 0xF0
+#define RFCOMM_PN_CONV_LAYER_TYPE_1 0
+#define RFCOMM_PN_CONV_LAYER_CBFC_I 0xF0
+#define RFCOMM_PN_CONV_LAYER_CBFC_R 0xE0
+
+#define RFCOMM_PN_PRIORITY_MASK 0x3F
+#define RFCOMM_PN_PRIORITY_0 0
+
+#define RFCOMM_PN_K_MASK 0x07
+
+#define RFCOMM_T1_DSEC 0 /* None negotiable in RFCOMM */
+#define RFCOMM_N2 0 /* Number of retransmissions */
+#define RFCOMM_K 0 /* Window size */
+#define RFCOMM_K_MAX 7 /* Max value of K for credit based flow control */
+
+#define RFCOMM_MSC_FC 0x02 /* Flow control*/
+#define RFCOMM_MSC_RTC 0x04 /* Ready to communicate*/
+#define RFCOMM_MSC_RTR 0x08 /* Ready to receive*/
+#define RFCOMM_MSC_IC 0x40 /* Incomming call indicator*/
+#define RFCOMM_MSC_DV 0x80 /* Data Valid*/
+
+#define RFCOMM_MSC_SHIFT_BREAK 4
+#define RFCOMM_MSC_BREAK_MASK 0xF0
+#define RFCOMM_MSC_BREAK_PRESENT_MASK 0x02
+
+#define RFCOMM_BAUD_RATE_2400 0x00
+#define RFCOMM_BAUD_RATE_4800 0x01
+#define RFCOMM_BAUD_RATE_7200 0x02
+#define RFCOMM_BAUD_RATE_9600 0x03
+#define RFCOMM_BAUD_RATE_19200 0x04
+#define RFCOMM_BAUD_RATE_38400 0x05
+#define RFCOMM_BAUD_RATE_57600 0x06
+#define RFCOMM_BAUD_RATE_115200 0x07
+#define RFCOMM_BAUD_RATE_230400 0x08
+
+#define RFCOMM_5_BITS 0x00
+#define RFCOMM_6_BITS 0x01
+#define RFCOMM_7_BITS 0x02
+#define RFCOMM_8_BITS 0x03
+
+#define RFCOMM_RPN_BITS_MASK 0x03
+#define RFCOMM_RPN_BITS_SHIFT 0
+
+#define RFCOMM_ONESTOPBIT 0x00
+#define RFCOMM_ONE5STOPBITS 0x01
+
+#define RFCOMM_RPN_STOP_BITS_MASK 0x01
+#define RFCOMM_RPN_STOP_BITS_SHIFT 2
+
+#define RFCOMM_PARITY_NO 0x00
+#define RFCOMM_PARITY_YES 0x01
+#define RFCOMM_RPN_PARITY_MASK 0x01
+#define RFCOMM_RPN_PARITY_SHIFT 3
+
+#define RFCOMM_ODD_PARITY 0x00
+#define RFCOMM_EVEN_PARITY 0x01
+#define RFCOMM_MARK_PARITY 0x02
+#define RFCOMM_SPACE_PARITY 0x03
+
+#define RFCOMM_RPN_PARITY_TYPE_MASK 0x03
+#define RFCOMM_RPN_PARITY_TYPE_SHIFT 4
+
+#define RFCOMM_FC_OFF 0x00
+#define RFCOMM_FC_XONXOFF_ON_INPUT 0x01
+#define RFCOMM_FC_XONXOFF_ON_OUTPUT 0x02
+#define RFCOMM_FC_RTR_ON_INPUT 0x04
+#define RFCOMM_FC_RTR_ON_OUTPUT 0x08
+#define RFCOMM_FC_RTC_ON_INPUT 0x10
+#define RFCOMM_FC_RTC_ON_OUTPUT 0x20
+#define RFCOMM_FC_MASK 0x3F
+
+#define RFCOMM_RPN_PM_BIT_RATE 0x0001
+#define RFCOMM_RPN_PM_DATA_BITS 0x0002
+#define RFCOMM_RPN_PM_STOP_BITS 0x0004
+#define RFCOMM_RPN_PM_PARITY 0x0008
+#define RFCOMM_RPN_PM_PARITY_TYPE 0x0010
+#define RFCOMM_RPN_PM_XON_CHAR 0x0020
+#define RFCOMM_RPN_PM_XOFF_CHAR 0x0040
+#define RFCOMM_RPN_PM_XONXOFF_ON_INPUT 0x0100
+#define RFCOMM_RPN_PM_XONXOFF_ON_OUTPUT 0x0200
+#define RFCOMM_RPN_PM_RTR_ON_INPUT 0x0400
+#define RFCOMM_RPN_PM_RTR_ON_OUTPUT 0x0800
+#define RFCOMM_RPN_PM_RTC_ON_INPUT 0x1000
+#define RFCOMM_RPN_PM_RTC_ON_OUTPUT 0x2000
+#define RFCOMM_RPN_PM_MASK 0x3F7F
+
+#define RFCOMM_RLS_ERROR 0x01
+#define RFCOMM_RLS_OVERRUN 0x02
+#define RFCOMM_RLS_PARITY 0x04
+#define RFCOMM_RLS_FRAMING 0x08
+
+/* Multiplexor channel uses DLCI 0 */
+#define RFCOMM_MX_DLCI 0
+
+/*
+** Define RFCOMM Multiplexer message types
+*/
+#define RFCOMM_MX_PN 0x80
+#define RFCOMM_MX_PN_LEN 8
+
+#define RFCOMM_MX_CLD 0xC0
+#define RFCOMM_MX_CLD_LEN 0
+
+#define RFCOMM_MX_TEST 0x20
+
+#define RFCOMM_MX_FCON 0xA0
+#define RFCOMM_MX_FCON_LEN 0
+
+#define RFCOMM_MX_FCOFF 0x60
+#define RFCOMM_MX_FCOFF_LEN 0
+
+#define RFCOMM_MX_MSC 0xE0
+#define RFCOMM_MX_MSC_LEN_NO_BREAK 2
+#define RFCOMM_MX_MSC_LEN_WITH_BREAK 3
+
+#define RFCOMM_MX_NSC 0x10
+#define RFCOMM_MX_NSC_LEN 1
+
+#define RFCOMM_MX_RPN 0x90
+#define RFCOMM_MX_RPN_REQ_LEN 1
+#define RFCOMM_MX_RPN_LEN 8
+
+#define RFCOMM_MX_RLS 0x50
+#define RFCOMM_MX_RLS_LEN 2
+#endif
diff --git a/stack/include/sdp_api.h b/stack/include/sdp_api.h
new file mode 100644
index 0000000..00de801
--- /dev/null
+++ b/stack/include/sdp_api.h
@@ -0,0 +1,702 @@
+/****************************************************************************
+**
+** Name: sdp_api.h
+** Function this file contains the definitions for the SDP API
+**
+**
+** Copyright (c) 1999-2009, Broadcom Corp., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+******************************************************************************/
+#ifndef SDP_API_H
+#define SDP_API_H
+
+#include "bt_target.h"
+#include "sdpdefs.h"
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+/* Success code and error codes */
+#define SDP_SUCCESS 0x0000
+#define SDP_INVALID_VERSION 0x0001
+#define SDP_INVALID_SERV_REC_HDL 0x0002
+#define SDP_INVALID_REQ_SYNTAX 0x0003
+#define SDP_INVALID_PDU_SIZE 0x0004
+#define SDP_INVALID_CONT_STATE 0x0005
+#define SDP_NO_RESOURCES 0x0006
+#define SDP_DI_REG_FAILED 0x0007
+#define SDP_DI_DISC_FAILED 0x0008
+#define SDP_NO_DI_RECORD_FOUND 0x0009
+#define SDP_ERR_ATTR_NOT_PRESENT 0x000A
+#define SDP_ILLEGAL_PARAMETER 0x000B
+
+#define SDP_NO_RECS_MATCH 0xFFF0
+#define SDP_CONN_FAILED 0xFFF1
+#define SDP_CFG_FAILED 0xFFF2
+#define SDP_GENERIC_ERROR 0xFFF3
+#define SDP_DB_FULL 0xFFF4
+#define SDP_INVALID_PDU 0xFFF5
+#define SDP_SECURITY_ERR 0xFFF6
+#define SDP_CONN_REJECTED 0xFFF7
+#define SDP_CANCEL 0xFFF8
+
+/* these result codes are used only when SDP_FOR_JV_INCLUDED==TRUE */
+#define SDP_EVT_OPEN 0x00F0 /* connected */
+#define SDP_EVT_DATA_IND 0x00F1 /* data ind */
+#define SDP_EVT_CLOSE 0x00F2 /* disconnected */
+
+/* Define the PSM that SDP uses */
+#define SDP_PSM 0x0001
+
+/* Legacy #define to avoid code changes - SDP UUID is same as BT UUID */
+#define tSDP_UUID tBT_UUID
+
+/* Masks for attr_value field of tSDP_DISC_ATTR */
+#define SDP_DISC_ATTR_LEN_MASK 0x0FFF
+#define SDP_DISC_ATTR_TYPE(len_type) (len_type >> 12)
+#define SDP_DISC_ATTR_LEN(len_type) (len_type & SDP_DISC_ATTR_LEN_MASK)
+
+/* Maximum number of protocol list items (list_elem in tSDP_PROTOCOL_ELEM) */
+#define SDP_MAX_LIST_ELEMS 3
+
+
+/*****************************************************************************
+** Type Definitions
+*****************************************************************************/
+
+/* Define a callback function for when discovery is complete. */
+typedef void (tSDP_DISC_CMPL_CB) (UINT16 result);
+
+typedef struct
+{
+ BD_ADDR peer_addr;
+ UINT16 peer_mtu;
+} tSDP_DR_OPEN;
+
+typedef struct
+{
+ UINT8 *p_data;
+ UINT16 data_len;
+} tSDP_DR_DATA;
+
+typedef union
+{
+ tSDP_DR_OPEN open;
+ tSDP_DR_DATA data;
+} tSDP_DATA;
+
+/* Define a callback function for when discovery result is received. */
+typedef void (tSDP_DISC_RES_CB) (UINT16 event, tSDP_DATA *p_data);
+
+/* Define a structure to hold the discovered service information. */
+typedef struct
+{
+ union
+ {
+ UINT8 u8; /* 8-bit integer */
+ UINT16 u16; /* 16-bit integer */
+ UINT32 u32; /* 32-bit integer */
+ UINT8 array[4]; /* Variable length field */
+ struct t_sdp_disc_attr *p_sub_attr; /* Addr of first sub-attr (list)*/
+ } v;
+
+} tSDP_DISC_ATVAL;
+
+typedef struct t_sdp_disc_attr
+{
+ struct t_sdp_disc_attr *p_next_attr; /* Addr of next linked attr */
+ UINT16 attr_id; /* Attribute ID */
+ UINT16 attr_len_type; /* Length and type fields */
+ tSDP_DISC_ATVAL attr_value; /* Variable length entry data */
+} tSDP_DISC_ATTR;
+
+typedef struct t_sdp_disc_rec
+{
+ tSDP_DISC_ATTR *p_first_attr; /* First attribute of record */
+ struct t_sdp_disc_rec *p_next_rec; /* Addr of next linked record */
+ UINT32 time_read; /* The time the record was read */
+ BD_ADDR remote_bd_addr; /* Remote BD address */
+} tSDP_DISC_REC;
+
+typedef struct
+{
+ UINT32 mem_size; /* Memory size of the DB */
+ UINT32 mem_free; /* Memory still available */
+ tSDP_DISC_REC *p_first_rec; /* Addr of first record in DB */
+ UINT16 num_uuid_filters; /* Number of UUIds to filter */
+ tSDP_UUID uuid_filters[SDP_MAX_UUID_FILTERS]; /* UUIDs to filter */
+ UINT16 num_attr_filters; /* Number of attribute filters */
+ UINT16 attr_filters[SDP_MAX_ATTR_FILTERS]; /* Attributes to filter */
+ UINT8 *p_free_mem; /* Pointer to free memory */
+#if (SDP_RAW_DATA_INCLUDED == TRUE)
+ UINT8 *raw_data; /* Received record from server. allocated/released by client */
+ UINT32 raw_size; /* size of raw_data */
+ UINT32 raw_used; /* length of raw_data used */
+#endif
+}tSDP_DISCOVERY_DB;
+
+/* This structure is used to add protocol lists and find protocol elements */
+typedef struct
+{
+ UINT16 protocol_uuid;
+ UINT16 num_params;
+ UINT16 params[SDP_MAX_PROTOCOL_PARAMS];
+} tSDP_PROTOCOL_ELEM;
+
+typedef struct
+{
+ UINT16 num_elems;
+ tSDP_PROTOCOL_ELEM list_elem[SDP_MAX_LIST_ELEMS];
+} tSDP_PROTO_LIST_ELEM;
+
+/* Device Identification (DI) data structure
+*/
+/* Used to set the DI record */
+typedef struct t_sdp_di_record
+{
+ UINT16 vendor;
+ UINT16 vendor_id_source;
+ UINT16 product;
+ UINT16 version;
+ BOOLEAN primary_record;
+ char client_executable_url[SDP_MAX_ATTR_LEN]; /* optional */
+ char service_description[SDP_MAX_ATTR_LEN]; /* optional */
+ char documentation_url[SDP_MAX_ATTR_LEN]; /* optional */
+}tSDP_DI_RECORD;
+
+/* Used to get the DI record */
+typedef struct t_sdp_di_get_record
+{
+ UINT16 spec_id;
+ tSDP_DI_RECORD rec;
+}tSDP_DI_GET_RECORD;
+
+
+/*****************************************************************************
+** External Function Declarations
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* API into the SDP layer for service discovery. */
+
+/*******************************************************************************
+**
+** Function SDP_InitDiscoveryDb
+**
+** Description This function is called to initialize a discovery database.
+**
+** Returns TRUE if successful, FALSE if one or more parameters are bad
+**
+*******************************************************************************/
+SDP_API extern BOOLEAN SDP_InitDiscoveryDb (tSDP_DISCOVERY_DB *p_db, UINT32 len,
+ UINT16 num_uuid,
+ tSDP_UUID *p_uuid_list,
+ UINT16 num_attr,
+ UINT16 *p_attr_list);
+
+/*******************************************************************************
+**
+** Function SDP_CancelServiceSearch
+**
+** Description This function cancels an active query to an SDP server.
+**
+** Returns TRUE if discovery cancelled, FALSE if a matching activity is not found.
+**
+*******************************************************************************/
+SDP_API extern BOOLEAN SDP_CancelServiceSearch (tSDP_DISCOVERY_DB *p_db);
+
+/*******************************************************************************
+**
+** Function SDP_ServiceSearchRequest
+**
+** Description This function queries an SDP server for information.
+**
+** Returns TRUE if discovery started, FALSE if failed.
+**
+*******************************************************************************/
+SDP_API extern BOOLEAN SDP_ServiceSearchRequest (UINT8 *p_bd_addr,
+ tSDP_DISCOVERY_DB *p_db,
+ tSDP_DISC_CMPL_CB *p_cb);
+
+
+/*******************************************************************************
+**
+** Function SDP_ServiceSearchAttributeRequest
+**
+** Description This function queries an SDP server for information.
+**
+** The difference between this API function and the function
+** SDP_ServiceSearchRequest is that this one does a
+** combined ServiceSearchAttributeRequest SDP function.
+**
+** Returns TRUE if discovery started, FALSE if failed.
+**
+*******************************************************************************/
+SDP_API extern BOOLEAN SDP_ServiceSearchAttributeRequest (UINT8 *p_bd_addr,
+ tSDP_DISCOVERY_DB *p_db,
+ tSDP_DISC_CMPL_CB *p_cb);
+
+
+/* API of utilities to find data in the local discovery database */
+
+/*******************************************************************************
+**
+** Function SDP_FindAttributeInDb
+**
+** Description This function queries an SDP database for a specific attribute.
+** If the p_start_rec pointer is NULL, it looks from the beginning
+** of the database, else it continues from the next record after
+** p_start_rec.
+**
+** Returns Pointer to matching record, or NULL
+**
+*******************************************************************************/
+SDP_API extern tSDP_DISC_REC *SDP_FindAttributeInDb (tSDP_DISCOVERY_DB *p_db,
+ UINT16 attr_id,
+ tSDP_DISC_REC *p_start_rec);
+
+
+/*******************************************************************************
+**
+** Function SDP_FindAttributeInRec
+**
+** Description This function searches an SDP discovery record for a
+** specific attribute.
+**
+** Returns Pointer to matching attribute entry, or NULL
+**
+*******************************************************************************/
+SDP_API extern tSDP_DISC_ATTR *SDP_FindAttributeInRec (tSDP_DISC_REC *p_rec,
+ UINT16 attr_id);
+
+
+/*******************************************************************************
+**
+** Function SDP_FindServiceInDb
+**
+** Description This function queries an SDP database for a specific service.
+** If the p_start_rec pointer is NULL, it looks from the beginning
+** of the database, else it continues from the next record after
+** p_start_rec.
+**
+** Returns Pointer to record containing service class, or NULL
+**
+*******************************************************************************/
+SDP_API extern tSDP_DISC_REC *SDP_FindServiceInDb (tSDP_DISCOVERY_DB *p_db,
+ UINT16 service_uuid,
+ tSDP_DISC_REC *p_start_rec);
+
+
+/*******************************************************************************
+**
+** Function SDP_FindServiceUUIDInDb
+**
+** Description This function queries an SDP database for a specific service.
+** If the p_start_rec pointer is NULL, it looks from the beginning
+** of the database, else it continues from the next record after
+** p_start_rec.
+**
+** NOTE the only difference between this function and the previous
+** function "SDP_FindServiceInDb()" is that this function takes
+** a tBT_UUID input.
+**
+** Returns Pointer to record containing service class, or NULL
+**
+*******************************************************************************/
+SDP_API extern tSDP_DISC_REC *SDP_FindServiceUUIDInDb (tSDP_DISCOVERY_DB *p_db,
+ tBT_UUID *p_uuid,
+ tSDP_DISC_REC *p_start_rec);
+
+
+/*******************************************************************************
+**
+** Function SDP_FindProtocolListElemInRec
+**
+** Description This function looks at a specific discovery record for a
+** protocol list element.
+**
+** Returns TRUE if found, FALSE if not
+** If found, the passed protocol list element is filled in.
+**
+*******************************************************************************/
+SDP_API extern BOOLEAN SDP_FindProtocolListElemInRec (tSDP_DISC_REC *p_rec,
+ UINT16 layer_uuid,
+ tSDP_PROTOCOL_ELEM *p_elem);
+
+
+/*******************************************************************************
+**
+** Function SDP_FindAddProtoListsElemInRec
+**
+** Description This function looks at a specific discovery record for a
+** protocol list element.
+**
+** Returns TRUE if found, FALSE if not
+** If found, the passed protocol list element is filled in.
+**
+*******************************************************************************/
+SDP_API extern BOOLEAN SDP_FindAddProtoListsElemInRec (tSDP_DISC_REC *p_rec,
+ UINT16 layer_uuid,
+ tSDP_PROTOCOL_ELEM *p_elem);
+
+
+/*******************************************************************************
+**
+** Function SDP_FindProfileVersionInRec
+**
+** Description This function looks at a specific discovery record for the
+** Profile list descriptor, and pulls out the version number.
+** The version number consists of an 8-bit major version and
+** an 8-bit minor version.
+**
+** Returns TRUE if found, FALSE if not
+** If found, the major and minor version numbers that were passed
+** in are filled in.
+**
+*******************************************************************************/
+SDP_API extern BOOLEAN SDP_FindProfileVersionInRec (tSDP_DISC_REC *p_rec,
+ UINT16 profile_uuid,
+ UINT16 *p_version);
+
+
+/* API into SDP for local service database updates */
+
+/*******************************************************************************
+**
+** Function SDP_CreateRecord
+**
+** Description This function is called to create a record in the database.
+** This would be through the SDP database maintenance API. The
+** record is created empty, teh application should then call
+** "add_attribute" to add the record's attributes.
+**
+** Returns Record handle if OK, else 0.
+**
+*******************************************************************************/
+SDP_API extern UINT32 SDP_CreateRecord (void);
+
+
+/*******************************************************************************
+**
+** Function SDP_DeleteRecord
+**
+** Description This function is called to add a record (or all records)
+** from the database. This would be through the SDP database
+** maintenance API.
+**
+** If a record handle of 0 is passed, all records are deleted.
+**
+** Returns TRUE if succeeded, else FALSE
+**
+*******************************************************************************/
+SDP_API extern BOOLEAN SDP_DeleteRecord (UINT32 handle);
+
+
+/*******************************************************************************
+**
+** Function SDP_ReadRecord
+**
+** Description This function is called to get the raw data of the record
+** with the given handle from the database.
+**
+** Returns -1, if the record is not found.
+** Otherwise, the offset (0 or 1) to start of data in p_data.
+**
+** The size of data copied into p_data is in *p_data_len.
+**
+*******************************************************************************/
+SDP_API extern INT32 SDP_ReadRecord(UINT32 handle, UINT8 *p_data, INT32 *p_data_len);
+
+/*******************************************************************************
+**
+** Function SDP_AddAttribute
+**
+** Description This function is called to add an attribute to a record.
+** This would be through the SDP database maintenance API.
+** If the attribute already exists in the record, it is replaced
+** with the new value.
+**
+** NOTE Attribute values must be passed as a Big Endian stream.
+**
+** Returns TRUE if added OK, else FALSE
+**
+*******************************************************************************/
+SDP_API extern BOOLEAN SDP_AddAttribute (UINT32 handle, UINT16 attr_id,
+ UINT8 attr_type, UINT32 attr_len,
+ UINT8 *p_val);
+
+
+/*******************************************************************************
+**
+** Function SDP_AddSequence
+**
+** Description This function is called to add a sequence to a record.
+** This would be through the SDP database maintenance API.
+** If the sequence already exists in the record, it is replaced
+** with the new sequence.
+**
+** NOTE Element values must be passed as a Big Endian stream.
+**
+** Returns TRUE if added OK, else FALSE
+**
+*******************************************************************************/
+SDP_API extern BOOLEAN SDP_AddSequence (UINT32 handle, UINT16 attr_id,
+ UINT16 num_elem, UINT8 type[],
+ UINT8 len[], UINT8 *p_val[]);
+
+
+/*******************************************************************************
+**
+** Function SDP_AddUuidSequence
+**
+** Description This function is called to add a UUID sequence to a record.
+** This would be through the SDP database maintenance API.
+** If the sequence already exists in the record, it is replaced
+** with the new sequence.
+**
+** Returns TRUE if added OK, else FALSE
+**
+*******************************************************************************/
+SDP_API extern BOOLEAN SDP_AddUuidSequence (UINT32 handle, UINT16 attr_id,
+ UINT16 num_uuids, UINT16 *p_uuids);
+
+
+/*******************************************************************************
+**
+** Function SDP_AddProtocolList
+**
+** Description This function is called to add a protocol descriptor list to
+** a record. This would be through the SDP database maintenance API.
+** If the protocol list already exists in the record, it is replaced
+** with the new list.
+**
+** Returns TRUE if added OK, else FALSE
+**
+*******************************************************************************/
+SDP_API extern BOOLEAN SDP_AddProtocolList (UINT32 handle, UINT16 num_elem,
+ tSDP_PROTOCOL_ELEM *p_elem_list);
+
+
+/*******************************************************************************
+**
+** Function SDP_AddAdditionProtoLists
+**
+** Description This function is called to add a protocol descriptor list to
+** a record. This would be through the SDP database maintenance API.
+** If the protocol list already exists in the record, it is replaced
+** with the new list.
+**
+** Returns TRUE if added OK, else FALSE
+**
+*******************************************************************************/
+SDP_API extern BOOLEAN SDP_AddAdditionProtoLists (UINT32 handle, UINT16 num_elem,
+ tSDP_PROTO_LIST_ELEM *p_proto_list);
+
+
+/*******************************************************************************
+**
+** Function SDP_AddProfileDescriptorList
+**
+** Description This function is called to add a profile descriptor list to
+** a record. This would be through the SDP database maintenance API.
+** If the version already exists in the record, it is replaced
+** with the new one.
+**
+** Returns TRUE if added OK, else FALSE
+**
+*******************************************************************************/
+SDP_API extern BOOLEAN SDP_AddProfileDescriptorList (UINT32 handle,
+ UINT16 profile_uuid,
+ UINT16 version);
+
+
+/*******************************************************************************
+**
+** Function SDP_AddLanguageBaseAttrIDList
+**
+** Description This function is called to add a language base attr list to
+** a record. This would be through the SDP database maintenance API.
+** If the version already exists in the record, it is replaced
+** with the new one.
+**
+** Returns TRUE if added OK, else FALSE
+**
+*******************************************************************************/
+SDP_API extern BOOLEAN SDP_AddLanguageBaseAttrIDList (UINT32 handle,
+ UINT16 lang, UINT16 char_enc,
+ UINT16 base_id);
+
+
+/*******************************************************************************
+**
+** Function SDP_AddServiceClassIdList
+**
+** Description This function is called to add a service list to a record.
+** This would be through the SDP database maintenance API.
+** If the service list already exists in the record, it is replaced
+** with the new list.
+**
+** Returns TRUE if added OK, else FALSE
+**
+*******************************************************************************/
+SDP_API extern BOOLEAN SDP_AddServiceClassIdList (UINT32 handle,
+ UINT16 num_services,
+ UINT16 *p_service_uuids);
+
+
+/*******************************************************************************
+**
+** Function SDP_DeleteAttribute
+**
+** Description This function is called to delete an attribute from a record.
+** This would be through the SDP database maintenance API.
+**
+** Returns TRUE if deleted OK, else FALSE if not found
+**
+*******************************************************************************/
+SDP_API extern BOOLEAN SDP_DeleteAttribute (UINT32 handle, UINT16 attr_id);
+
+
+/* Device Identification APIs */
+
+/*******************************************************************************
+**
+** Function SDP_SetLocalDiRecord
+**
+** Description This function adds a DI record to the local SDP database.
+**
+** Returns Returns SDP_SUCCESS if record added successfully, else error
+**
+*******************************************************************************/
+SDP_API extern UINT16 SDP_SetLocalDiRecord (tSDP_DI_RECORD *device_info,
+ UINT32 *p_handle);
+
+/*******************************************************************************
+**
+** Function SDP_GetLocalDiRecord
+**
+** Description This function adds a DI record to the local SDP database.
+**
+** Fills in the device information of the record
+** p_handle - if p_handle == NULL, the primary record is returned
+**
+** Returns Returns SDP_SUCCESS if record exists, else error
+**
+*******************************************************************************/
+SDP_API extern UINT16 SDP_GetLocalDiRecord(tSDP_DI_GET_RECORD *p_device_info,
+ UINT32 *p_handle );
+
+/*******************************************************************************
+**
+** Function SDP_DiDiscover
+**
+** Description This function queries a remote device for DI information.
+**
+** Returns SDP_SUCCESS if query started successfully, else error
+**
+*******************************************************************************/
+SDP_API extern UINT16 SDP_DiDiscover (BD_ADDR remote_device,
+ tSDP_DISCOVERY_DB *p_db, UINT32 len,
+ tSDP_DISC_CMPL_CB *p_cb);
+
+
+/*******************************************************************************
+**
+** Function SDP_GetNumDiRecords
+**
+** Description Searches specified database for DI records
+**
+** Returns number of DI records found
+**
+*******************************************************************************/
+SDP_API extern UINT8 SDP_GetNumDiRecords (tSDP_DISCOVERY_DB *p_db);
+
+
+/*******************************************************************************
+**
+** Function SDP_GetDiRecord
+**
+** Description This function retrieves a remote device's DI record from
+** the specified database.
+**
+** Returns SDP_SUCCESS if record retrieved, else error
+**
+*******************************************************************************/
+SDP_API extern UINT16 SDP_GetDiRecord (UINT8 getRecordIndex,
+ tSDP_DI_GET_RECORD *device_info,
+ tSDP_DISCOVERY_DB *p_db);
+
+
+/*******************************************************************************
+**
+** Function SDP_SetTraceLevel
+**
+** Description This function sets the trace level for SDP. If called with
+** a value of 0xFF, it simply reads the current trace level.
+**
+** Returns the new (current) trace level
+**
+*******************************************************************************/
+SDP_API extern UINT8 SDP_SetTraceLevel (UINT8 new_level);
+
+/*******************************************************************************
+**
+** Function SDP_ConnOpen
+**
+** Description This function creates a connection to the SDP server on the
+** given device.
+**
+** Returns 0, if failed to initiate connection. Otherwise, the handle.
+**
+*******************************************************************************/
+SDP_API UINT32 SDP_ConnOpen (UINT8 *p_bd_addr, tSDP_DISC_RES_CB *p_rcb,
+ tSDP_DISC_CMPL_CB *p_cb);
+
+/*******************************************************************************
+**
+** Function SDP_WriteData
+**
+** Description This function sends data to the connected SDP server.
+**
+** Returns TRUE if data is sent, FALSE if failed.
+**
+*******************************************************************************/
+SDP_API BOOLEAN SDP_WriteData (UINT32 handle, BT_HDR *p_msg);
+
+/*******************************************************************************
+**
+** Function SDP_ConnClose
+**
+** Description This function is called to close a SDP connection.
+**
+** Parameters: handle - Handle of the connection returned by SDP_ConnOpen
+**
+** Returns TRUE if connection is closed, FALSE if failed to find the handle.
+**
+*******************************************************************************/
+SDP_API BOOLEAN SDP_ConnClose (UINT32 handle);
+
+/*******************************************************************************
+**
+** Function SDP_FindServiceUUIDInRec
+**
+** Description This function is called to read the service UUID within a record
+** if there is any.
+**
+** Parameters: p_rec - pointer to a SDP record.
+**
+** Returns TRUE if found, otherwise FALSE.
+**
+*******************************************************************************/
+SDP_API BOOLEAN SDP_FindServiceUUIDInRec(tSDP_DISC_REC *p_rec, tBT_UUID *p_uuid);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SDP_API_H */
diff --git a/stack/include/sdpdefs.h b/stack/include/sdpdefs.h
new file mode 100644
index 0000000..6ef2972
--- /dev/null
+++ b/stack/include/sdpdefs.h
@@ -0,0 +1,305 @@
+/****************************************************************************/
+/* */
+/* Name: sdp_defs.h */
+/* */
+/* Function this file contains the definitions for the SDP API */
+/* */
+/* Copyright (c) 1999-2009, Broadcom Corp, All Rights Reserved. */
+/* Broadcom Bluetooth Core. Proprietary and confidential. */
+/* */
+/*****************************************************************************/
+#ifndef SDP_DEFS_H
+#define SDP_DEFS_H
+
+/* Define the service attribute IDs.
+*/
+#define ATTR_ID_SERVICE_RECORD_HDL 0x0000
+#define ATTR_ID_SERVICE_CLASS_ID_LIST 0x0001
+#define ATTR_ID_SERVICE_RECORD_STATE 0x0002
+#define ATTR_ID_SERVICE_ID 0x0003
+#define ATTR_ID_PROTOCOL_DESC_LIST 0x0004
+#define ATTR_ID_BROWSE_GROUP_LIST 0x0005
+#define ATTR_ID_LANGUAGE_BASE_ATTR_ID_LIST 0x0006
+#define ATTR_ID_SERVICE_INFO_TIME_TO_LIVE 0x0007
+#define ATTR_ID_SERVICE_AVAILABILITY 0x0008
+#define ATTR_ID_BT_PROFILE_DESC_LIST 0x0009
+#define ATTR_ID_DOCUMENTATION_URL 0x000A
+#define ATTR_ID_CLIENT_EXE_URL 0x000B
+#define ATTR_ID_ICON_URL 0x000C
+#define ATTR_ID_ADDITION_PROTO_DESC_LISTS 0x000D
+
+#define LANGUAGE_BASE_ID 0x0100
+#define ATTR_ID_SERVICE_NAME LANGUAGE_BASE_ID + 0x0000
+#define ATTR_ID_SERVICE_DESCRIPTION LANGUAGE_BASE_ID + 0x0001
+#define ATTR_ID_PROVIDER_NAME LANGUAGE_BASE_ID + 0x0002
+
+/* Device Identification (DI)
+*/
+#define ATTR_ID_SPECIFICATION_ID 0x0200
+#define ATTR_ID_VENDOR_ID 0x0201
+#define ATTR_ID_PRODUCT_ID 0x0202
+#define ATTR_ID_PRODUCT_VERSION 0x0203
+#define ATTR_ID_PRIMARY_RECORD 0x0204
+#define ATTR_ID_VENDOR_ID_SOURCE 0x0205
+
+#define BLUETOOTH_DI_SPECIFICATION 0x0103 /* 1.3 */
+#define DI_VENDOR_ID_DEFAULT 0xFFFF
+#define DI_VENDOR_ID_SOURCE_BTSIG 0x0001
+#define DI_VENDOR_ID_SOURCE_USBIF 0x0002
+
+
+#define ATTR_ID_IP_SUBNET 0x0200 /* PAN Profile (***) */
+#define ATTR_ID_VERSION_NUMBER_LIST 0x0200
+#define ATTR_ID_GROUP_ID 0x0200
+#define ATTR_ID_SERVICE_DATABASE_STATE 0x0201
+#define ATTR_ID_SERVICE_VERSION 0x0300
+#define ATTR_ID_HCRP_1284ID 0x0300
+
+#define ATTR_ID_SUPPORTED_DATA_STORES 0x0301
+#define ATTR_ID_NETWORK 0x0301
+#define ATTR_ID_EXTERNAL_NETWORK 0x0301
+#define ATTR_ID_FAX_CLASS_1_SUPPORT 0x0302
+#define ATTR_ID_REMOTE_AUDIO_VOLUME_CONTROL 0x0302
+#define ATTR_ID_DEVICE_NAME 0x0302
+#define ATTR_ID_SUPPORTED_FORMATS_LIST 0x0303
+#define ATTR_ID_FAX_CLASS_2_0_SUPPORT 0x0303
+#define ATTR_ID_FAX_CLASS_2_SUPPORT 0x0304
+#define ATTR_ID_FRIENDLY_NAME 0x0304
+#define ATTR_ID_AUDIO_FEEDBACK_SUPPORT 0x0305
+#define ATTR_ID_NETWORK_ADDRESS 0x0306
+#define ATTR_ID_DEVICE_LOCATION 0x0306
+#define ATTR_ID_WAP_GATEWAY 0x0307
+#define ATTR_ID_HOME_PAGE_URL 0x0308
+#define ATTR_ID_WAP_STACK_TYPE 0x0309
+#define ATTR_ID_IMG_SUPPORTED_CAPABILITIES 0x0310 /* Imaging Profile */
+#define ATTR_ID_SUPPORTED_FEATURES 0x0311 /* HFP, BIP */
+#define ATTR_ID_IMG_SUPPORTED_FUNCTIONS 0x0312 /* Imaging Profile */
+#define ATTR_ID_IMG_TOT_DATA_CAPABILITY 0x0313 /* Imaging Profile */
+#define ATTR_ID_SUPPORTED_REPOSITORIES 0x0314 /* Phone book access Profile */
+#define ATTR_ID_MAS_INSTANCE_ID 0x0315 /* MAP profile */
+#define ATTR_ID_SUPPORTED_MSG_TYPE 0x0316 /* MAP profile */
+
+/* These values are for the BPP profile */
+#define ATTR_ID_DOCUMENT_FORMATS_SUPPORTED 0x0350
+#define ATTR_ID_CHARACTER_REPERTOIRES_SUPPORTED 0x0352
+#define ATTR_ID_XHTML_IMAGE_FORMATS_SUPPORTED 0x0354
+#define ATTR_ID_COLOR_SUPPORTED 0x0356
+#define ATTR_ID_1284ID 0x0358
+#define ATTR_ID_PRINTER_NAME 0x035A
+#define ATTR_ID_PRINTER_LOCATION 0x035C
+#define ATTR_ID_DUPLEX_SUPPORTED 0x035E
+#define ATTR_ID_MEDIA_TYPES_SUPPORTED 0x0360
+#define ATTR_ID_MAX_MEDIA_WIDTH 0x0362
+#define ATTR_ID_MAX_MEDIA_LENGTH 0x0364
+#define ATTR_ID_ENHANCED_LAYOUT_SUPPORTED 0x0366
+#define ATTR_ID_RUI_FORMATS_SUPPORTED 0x0368
+#define ATTR_ID_RUI_REF_PRINTING_SUPPORTED 0x0370 /* Boolean */
+#define ATTR_ID_RUI_DIRECT_PRINTING_SUPPORTED 0x0372 /* Boolean */
+#define ATTR_ID_REF_PRINTING_TOP_URL 0x0374
+#define ATTR_ID_DIRECT_PRINTING_TOP_URL 0x0376
+#define ATTR_ID_PRINTER_ADMIN_RUI_TOP_URL 0x0378
+#define ATTR_ID_BPP_DEVICE_NAME 0x037A
+
+/* These values are for the PAN profile */
+#define ATTR_ID_SECURITY_DESCRIPTION 0x030A
+#define ATTR_ID_NET_ACCESS_TYPE 0x030B
+#define ATTR_ID_MAX_NET_ACCESS_RATE 0x030C
+#define ATTR_ID_IPV4_SUBNET 0x030D
+#define ATTR_ID_IPV6_SUBNET 0x030E
+#define ATTR_ID_PAN_SECURITY 0x0400
+
+/* These values are for HID profile */
+#define ATTR_ID_HID_DEVICE_RELNUM 0x0200
+#define ATTR_ID_HID_PARSER_VERSION 0x0201
+#define ATTR_ID_HID_DEVICE_SUBCLASS 0x0202
+#define ATTR_ID_HID_COUNTRY_CODE 0x0203
+#define ATTR_ID_HID_VIRTUAL_CABLE 0x0204
+#define ATTR_ID_HID_RECONNECT_INITIATE 0x0205
+#define ATTR_ID_HID_DESCRIPTOR_LIST 0x0206
+#define ATTR_ID_HID_LANGUAGE_ID_BASE 0x0207
+#define ATTR_ID_HID_SDP_DISABLE 0x0208
+#define ATTR_ID_HID_BATTERY_POWER 0x0209
+#define ATTR_ID_HID_REMOTE_WAKE 0x020A
+#define ATTR_ID_HID_PROFILE_VERSION 0x020B
+#define ATTR_ID_HID_LINK_SUPERVISION_TO 0x020C
+#define ATTR_ID_HID_NORMALLY_CONNECTABLE 0x020D
+#define ATTR_ID_HID_BOOT_DEVICE 0x020E
+#define ATTR_ID_HID_SSR_HOST_MAX_LAT 0x020F
+#define ATTR_ID_HID_SSR_HOST_MIN_TOUT 0x0210
+
+/* These values are for the HDP profile */
+#define ATTR_ID_HDP_SUP_FEAT_LIST 0x0200 /* Supported features list */
+#define ATTR_ID_HDP_DATA_EXCH_SPEC 0x0301 /* Data exchange specification */
+#define ATTR_ID_HDP_MCAP_SUP_PROC 0x0302 /* MCAP supported procedures */
+
+/* a temporary value for IOP */
+#ifndef ATTR_ID_OBX_OVR_L2CAP_PSM
+#define ATTR_ID_OBX_OVR_L2CAP_PSM 0x0200
+#endif
+
+
+/* Define common 16-bit protocol UUIDs
+*/
+#define UUID_PROTOCOL_SDP 0x0001
+#define UUID_PROTOCOL_UDP 0x0002
+#define UUID_PROTOCOL_RFCOMM 0x0003
+#define UUID_PROTOCOL_TCP 0x0004
+#define UUID_PROTOCOL_TCS_BIN 0x0005
+#define UUID_PROTOCOL_TCS_AT 0x0006
+#define UUID_PROTOCOL_OBEX 0x0008
+#define UUID_PROTOCOL_IP 0x0009
+#define UUID_PROTOCOL_FTP 0x000A
+#define UUID_PROTOCOL_HTTP 0x000C
+#define UUID_PROTOCOL_WSP 0x000E
+#define UUID_PROTOCOL_BNEP 0x000F
+#define UUID_PROTOCOL_UPNP 0x0010
+#define UUID_PROTOCOL_HIDP 0x0011
+#define UUID_PROTOCOL_HCRP_CTRL 0x0012
+#define UUID_PROTOCOL_HCRP_DATA 0x0014
+#define UUID_PROTOCOL_HCRP_NOTIF 0x0016
+#define UUID_PROTOCOL_AVCTP 0x0017
+#define UUID_PROTOCOL_AVDTP 0x0019
+#define UUID_PROTOCOL_CMTP 0x001B
+#define UUID_PROTOCOL_UDI 0x001D
+#define UUID_PROTOCOL_MCAP_CTRL 0x001E
+#define UUID_PROTOCOL_MCAP_DATA 0x001F
+#define UUID_PROTOCOL_L2CAP 0x0100
+#define UUID_PROTOCOL_ATT 0x0007
+
+/* Define common 16-bit service class UUIDs
+*/
+#define UUID_SERVCLASS_SERVICE_DISCOVERY_SERVER 0X1000
+#define UUID_SERVCLASS_BROWSE_GROUP_DESCRIPTOR 0X1001
+#define UUID_SERVCLASS_PUBLIC_BROWSE_GROUP 0X1002
+#define UUID_SERVCLASS_SERIAL_PORT 0X1101
+#define UUID_SERVCLASS_LAN_ACCESS_USING_PPP 0X1102
+#define UUID_SERVCLASS_DIALUP_NETWORKING 0X1103
+#define UUID_SERVCLASS_IRMC_SYNC 0X1104
+#define UUID_SERVCLASS_OBEX_OBJECT_PUSH 0X1105
+#define UUID_SERVCLASS_OBEX_FILE_TRANSFER 0X1106
+#define UUID_SERVCLASS_IRMC_SYNC_COMMAND 0X1107
+#define UUID_SERVCLASS_HEADSET 0X1108
+#define UUID_SERVCLASS_CORDLESS_TELEPHONY 0X1109
+#define UUID_SERVCLASS_AUDIO_SOURCE 0X110A
+#define UUID_SERVCLASS_AUDIO_SINK 0X110B
+#define UUID_SERVCLASS_AV_REM_CTRL_TARGET 0X110C /* Audio/Video Control profile */
+#define UUID_SERVCLASS_ADV_AUDIO_DISTRIBUTION 0X110D /* Advanced Audio Distribution profile */
+#define UUID_SERVCLASS_AV_REMOTE_CONTROL 0X110E /* Audio/Video Control profile */
+#define UUID_SERVCLASS_AV_REM_CTRL_CONTROL 0X110F /* Audio/Video Control profile */
+#define UUID_SERVCLASS_INTERCOM 0X1110
+#define UUID_SERVCLASS_FAX 0X1111
+#define UUID_SERVCLASS_HEADSET_AUDIO_GATEWAY 0X1112
+#define UUID_SERVCLASS_WAP 0X1113
+#define UUID_SERVCLASS_WAP_CLIENT 0X1114
+#define UUID_SERVCLASS_PANU 0X1115 /* PAN profile */
+#define UUID_SERVCLASS_NAP 0X1116 /* PAN profile */
+#define UUID_SERVCLASS_GN 0X1117 /* PAN profile */
+#define UUID_SERVCLASS_DIRECT_PRINTING 0X1118 /* BPP profile */
+#define UUID_SERVCLASS_REFERENCE_PRINTING 0X1119 /* BPP profile */
+#define UUID_SERVCLASS_IMAGING 0X111A /* Imaging profile */
+#define UUID_SERVCLASS_IMAGING_RESPONDER 0X111B /* Imaging profile */
+#define UUID_SERVCLASS_IMAGING_AUTO_ARCHIVE 0X111C /* Imaging profile */
+#define UUID_SERVCLASS_IMAGING_REF_OBJECTS 0X111D /* Imaging profile */
+#define UUID_SERVCLASS_HF_HANDSFREE 0X111E /* Handsfree profile */
+#define UUID_SERVCLASS_AG_HANDSFREE 0X111F /* Handsfree profile */
+#define UUID_SERVCLASS_DIR_PRT_REF_OBJ_SERVICE 0X1120 /* BPP profile */
+#define UUID_SERVCLASS_REFLECTED_UI 0X1121 /* BPP profile */
+#define UUID_SERVCLASS_BASIC_PRINTING 0X1122 /* BPP profile */
+#define UUID_SERVCLASS_PRINTING_STATUS 0X1123 /* BPP profile */
+#define UUID_SERVCLASS_HUMAN_INTERFACE 0X1124 /* HID profile */
+#define UUID_SERVCLASS_CABLE_REPLACEMENT 0X1125 /* HCRP profile */
+#define UUID_SERVCLASS_HCRP_PRINT 0X1126 /* HCRP profile */
+#define UUID_SERVCLASS_HCRP_SCAN 0X1127 /* HCRP profile */
+#define UUID_SERVCLASS_COMMON_ISDN_ACCESS 0X1128 /* CAPI Message Transport Protocol*/
+#define UUID_SERVCLASS_VIDEO_CONFERENCING_GW 0X1129 /* Video Conferencing profile */
+#define UUID_SERVCLASS_UDI_MT 0X112A /* Unrestricted Digital Information profile */
+#define UUID_SERVCLASS_UDI_TA 0X112B /* Unrestricted Digital Information profile */
+#define UUID_SERVCLASS_VCP 0X112C /* Video Conferencing profile */
+#define UUID_SERVCLASS_SAP 0X112D /* SIM Access profile */
+#define UUID_SERVCLASS_PBAP_PCE 0X112E /* Phonebook Access - PCE */
+#define UUID_SERVCLASS_PBAP_PSE 0X112F /* Phonebook Access - PSE */
+#define UUID_SERVCLASS_PHONE_ACCESS 0x1130
+#define UUID_SERVCLASS_HEADSET_HS 0x1131 /* Headset - HS, from HSP v1.2 */
+#define UUID_SERVCLASS_PNP_INFORMATION 0X1200 /* Device Identification */
+#define UUID_SERVCLASS_GENERIC_NETWORKING 0X1201
+#define UUID_SERVCLASS_GENERIC_FILETRANSFER 0X1202
+#define UUID_SERVCLASS_GENERIC_AUDIO 0X1203
+#define UUID_SERVCLASS_GENERIC_TELEPHONY 0X1204
+#define UUID_SERVCLASS_UPNP_SERVICE 0X1205 /* UPNP_Service [ESDP] */
+#define UUID_SERVCLASS_UPNP_IP_SERVICE 0X1206 /* UPNP_IP_Service [ESDP] */
+#define UUID_SERVCLASS_ESDP_UPNP_IP_PAN 0X1300 /* UPNP_IP_PAN [ESDP] */
+#define UUID_SERVCLASS_ESDP_UPNP_IP_LAP 0X1301 /* UPNP_IP_LAP [ESDP] */
+#define UUID_SERVCLASS_ESDP_UPNP_IP_L2CAP 0X1302 /* UPNP_L2CAP [ESDP] */
+#define UUID_SERVCLASS_VIDEO_SOURCE 0X1303 /* Video Distribution Profile (VDP) */
+#define UUID_SERVCLASS_VIDEO_SINK 0X1304 /* Video Distribution Profile (VDP) */
+#define UUID_SERVCLASS_VIDEO_DISTRIBUTION 0X1305 /* Video Distribution Profile (VDP) */
+#define UUID_SERVCLASS_HDP_PROFILE 0X1400 /* Health Device profile (HDP) */
+#define UUID_SERVCLASS_HDP_SOURCE 0X1401 /* Health Device profile (HDP) */
+#define UUID_SERVCLASS_HDP_SINK 0X1402 /* Health Device profile (HDP) */
+#define UUID_SERVCLASS_MAP_PROFILE 0X1134 /* MAP profile UUID */
+#define UUID_SERVCLASS_MESSAGE_ACCESS 0X1132 /* Message Access Service UUID */
+#define UUID_SERVCLASS_MESSAGE_NOTIFICATION 0X1133 /* Message Notification Service UUID */
+
+#define UUID_SERVCLASS_GAP_SERVER 0x1800
+#define UUID_SERVCLASS_GATT_SERVER 0x1801
+#define UUID_SERVCLASS_IMMEDIATE_ALERT 0x1802 /* immediate alert */
+#define UUID_SERVCLASS_LINKLOSS 0x1803 /* Link Loss Alert */
+#define UUID_SERVCLASS_TX_POWER 0x1804 /* TX power */
+#define UUID_SERVCLASS_CURRENT_TIME 0x1805 /* Link Loss Alert */
+#define UUID_SERVCLASS_DST_CHG 0x1806 /* DST Time change */
+#define UUID_SERVCLASS_REF_TIME_UPD 0x1807 /* reference time update */
+#define UUID_SERVCLASS_DEVICE_INFO 0x180A /* device info service */
+#define UUID_SERVCLASS_NWA 0x180B /* Network availability */
+#define UUID_SERVCLASS_PHALERT 0x180C /* phone alert service */
+#define UUID_SERVCLASS_GLUCOSE 0xC000 /* Glucose Meter Service */
+#define UUID_SERVCLASS_TEST_SERVER 0x9000 /* Test Group UUID */
+
+#if (BTM_WBS_INCLUDED == TRUE )
+#define UUID_CODEC_CVSD 0x0001 /* CVSD */
+#define UUID_CODEC_MSBC 0x0002 /* mSBC */
+#endif
+
+/* Define all the 'Descriptor Type' values.
+*/
+#define NULL_DESC_TYPE 0
+#define UINT_DESC_TYPE 1
+#define TWO_COMP_INT_DESC_TYPE 2
+#define UUID_DESC_TYPE 3
+#define TEXT_STR_DESC_TYPE 4
+#define BOOLEAN_DESC_TYPE 5
+#define DATA_ELE_SEQ_DESC_TYPE 6
+#define DATA_ELE_ALT_DESC_TYPE 7
+#define URL_DESC_TYPE 8
+
+/* Define all the "Descriptor Size" values.
+*/
+#define SIZE_ONE_BYTE 0
+#define SIZE_TWO_BYTES 1
+#define SIZE_FOUR_BYTES 2
+#define SIZE_EIGHT_BYTES 3
+#define SIZE_SIXTEEN_BYTES 4
+#define SIZE_IN_NEXT_BYTE 5
+#define SIZE_IN_NEXT_WORD 6
+#define SIZE_IN_NEXT_LONG 7
+
+/* Language Encoding Constants */
+#define LANG_ID_CODE_ENGLISH ((UINT16) 0x656e) /* "en" */
+#define LANG_ID_CHAR_ENCODE_UTF8 ((UINT16) 0x006a) /* UTF-8 */
+
+/* Constants used for display purposes only. These define ovelapping attribute values */
+#define ATTR_ID_VERS_OR_GRP_OR_DRELNUM_OR_IPSUB_OR_SPECID 0x0200
+#define ATTR_ID_VEND_ID_OR_SERVICE_DB_STATE_OR_PARSE_VER 0x0201
+#define ATTR_ID_PROD_ID_OR_HID_DEV_SUBCLASS 0x0202
+#define ATTR_ID_PROD_VER_OR_HID_COUNTRY_CODE 0x0203
+#define ATTR_ID_PRIMARY_REC_OR_HID_VIRTUAL_CABLE 0x0204
+#define ATTR_ID_DI_VENDOR_ID_SOURCE_OR_HID_INIT_RECONNECT 0x0205
+#define ATTR_ID_SERV_VERS_OR_1284ID 0x0300
+#define ATTR_ID_DATA_STORES_OR_NETWORK 0x0301
+#define ATTR_ID_FAX_1_OR_AUD_VOL_OR_DEV_NAME 0x0302
+#define ATTR_ID_FORMATS_OR_FAX_2_0 0x0303
+#define ATTR_ID_FAX_CLASS_2_OR_FRIENDLY_NAME 0x0304
+#define ATTR_ID_NETADDRESS_OR_DEVLOCATION 0x0306
+
+#endif
+
+
diff --git a/stack/include/smp_api.h b/stack/include/smp_api.h
new file mode 100644
index 0000000..f04ff92
--- /dev/null
+++ b/stack/include/smp_api.h
@@ -0,0 +1,292 @@
+/*****************************************************************************
+**
+** Name: smp_api.h
+**
+** Description: This file contains the SMP API function
+** external definitions.
+**
+** The SMP consists of several management entities:
+** 1. Address & Identity Privacy
+** 2. Authentication
+** 3. Encryption
+**
+** Copyright (c) 1999-2008, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+#ifndef SMP_API_H
+#define SMP_API_H
+
+#include "bt_target.h"
+
+#define SMP_PIN_CODE_LEN_MAX PIN_CODE_LEN
+#define SMP_PIN_CODE_LEN_MIN 6
+
+/* SMP event type */
+#define SMP_IO_CAP_REQ_EVT 1 /* IO capability request event */
+#define SMP_SEC_REQUEST_EVT 2 /* SMP pairing request */
+#define SMP_PASSKEY_NOTIF_EVT 3 /* passkey notification event */
+#define SMP_PASSKEY_REQ_EVT 4 /* passkey request event */
+#define SMP_OOB_REQ_EVT 5 /* OOB request event */
+#define SMP_COMPLT_EVT 6 /* SMP complete event */
+typedef UINT8 tSMP_EVT;
+
+
+/* pairing failure reason code */
+#define SMP_PASSKEY_ENTRY_FAIL 0x01
+#define SMP_OOB_FAIL 0x02
+#define SMP_PAIR_AUTH_FAIL 0x03
+#define SMP_CONFIRM_VALUE_ERR 0x04
+#define SMP_PAIR_NOT_SUPPORT 0x05
+#define SMP_ENC_KEY_SIZE 0x06
+#define SMP_INVALID_CMD 0x07
+#define SMP_PAIR_FAIL_UNKNOWN 0x08
+#define SMP_REPEATED_ATTEMPTS 0x09
+#define SMP_PAIR_FAILURE_MAX SMP_REPEATED_ATTEMPTS
+/* self defined error code */
+#define SMP_PAIR_INTERNAL_ERR 0x0A
+#define SMP_UNKNOWN_IO_CAP 0x0B /* unknown IO capability, unable to decide associatino model */
+#define SMP_INIT_FAIL 0x0C
+#define SMP_CONFIRM_FAIL 0x0D
+#define SMP_BUSY 0x0E
+#define SMP_ENC_FAIL 0x0F
+#define SMP_STARTED 0x10
+#define SMP_RSP_TIMEOUT 0x11
+#define SMP_DIV_NOT_AVAIL 0x12
+#define SMP_FAIL 0x13 /* unspecified failed reason */
+#define SMP_SUCCESS 0
+
+typedef UINT8 tSMP_STATUS;
+
+
+/* Device IO capability */
+#define SMP_IO_CAP_OUT BTM_IO_CAP_OUT /* DisplayOnly */
+#define SMP_IO_CAP_IO BTM_IO_CAP_IO /* DisplayYesNo */
+#define SMP_IO_CAP_IN BTM_IO_CAP_IN /* KeyboardOnly */
+#define SMP_IO_CAP_NONE BTM_IO_CAP_NONE /* NoInputNoOutput */
+#define SMP_IO_CAP_KBDISP BTM_IO_CAP_KBDISP /* Keyboard Display */
+#define SMP_IO_CAP_MAX BTM_IO_CAP_MAX
+typedef UINT8 tSMP_IO_CAP;
+
+#ifndef SMP_DEFAULT_IO_CAPS
+ #define SMP_DEFAULT_IO_CAPS SMP_IO_CAP_KBDISP
+#endif
+
+/* OOB data present or not */
+enum
+{
+ SMP_OOB_NONE,
+ SMP_OOB_PRESENT,
+ SMP_OOB_UNKNOWN
+};
+typedef UINT8 tSMP_OOB_FLAG;
+
+#define SMP_AUTH_NO_BOND 0x00
+#define SMP_AUTH_GEN_BOND 0x01 //todo sdh change GEN_BOND to BOND
+
+/* SMP Authentication requirement */
+#define SMP_AUTH_YN_BIT (1 << 2)
+#define SMP_AUTH_MASK (SMP_AUTH_GEN_BOND|SMP_AUTH_YN_BIT)
+
+
+#define SMP_AUTH_BOND SMP_AUTH_GEN_BOND
+
+#define SMP_AUTH_NB_ENC_ONLY 0x00 //(SMP_AUTH_MASK | BTM_AUTH_SP_NO) /* no MITM, No Bonding, Encryptino only */
+#define SMP_AUTH_NB_IOCAP (SMP_AUTH_NO_BOND | SMP_AUTH_YN_BIT) /* MITM, No Bonding, Use IO Capability
+ to detrermine authenticaion procedure */
+#define SMP_AUTH_GB_ENC_ONLY (SMP_AUTH_GEN_BOND ) /* no MITM, General Bonding, Encryptino only */
+#define SMP_AUTH_GB_IOCAP (SMP_AUTH_GEN_BOND | SMP_AUTH_YN_BIT) /* MITM, General Bonding, Use IO Capability
+ to detrermine authenticaion procedure */
+typedef UINT8 tSMP_AUTH_REQ;
+
+#define SMP_SEC_NONE 0
+#define SMP_SEC_UNAUTHENTICATE (1 << 0)
+#define SMP_SEC_AUTHENTICATED (1 << 2)
+typedef UINT8 tSMP_SEC_LEVEL;
+
+/* SMP key types */
+#define SMP_SEC_KEY_TYPE_ENC (1 << 0) /* encryption key */
+#define SMP_SEC_KEY_TYPE_ID (1 << 1) /* identity key */
+#define SMP_SEC_KEY_TYPE_CSRK (1 << 2) /* slave CSRK */
+typedef UINT8 tSMP_KEYS;
+
+/* default security key distribution value */
+#define SMP_SEC_DEFAULT_KEY (SMP_SEC_KEY_TYPE_ENC | SMP_SEC_KEY_TYPE_ID | SMP_SEC_KEY_TYPE_CSRK)
+
+/* data type for BTM_SP_IO_REQ_EVT */
+typedef struct
+{
+ tSMP_IO_CAP io_cap; /* local IO capabilities */
+ tSMP_OOB_FLAG oob_data; /* OOB data present (locally) for the peer device */
+ tSMP_AUTH_REQ auth_req; /* Authentication required (for local device) */
+ UINT8 max_key_size; /* max encryption key size */
+ tSMP_KEYS init_keys; /* initiator keys to be distributed */
+ tSMP_KEYS resp_keys; /* responder keys */
+} tSMP_IO_REQ;
+
+typedef struct
+{
+ UINT8 reason;
+ UINT8 sec_level;
+ BOOLEAN is_pair_cancel;
+} tSMP_CMPL;
+
+typedef union
+{
+ UINT32 passkey;
+ tSMP_IO_REQ io_req; /* IO request */
+ tSMP_CMPL cmplt;
+
+}tSMP_EVT_DATA;
+
+
+/* AES Encryption output */
+typedef struct
+{
+ UINT8 status;
+ UINT8 param_len;
+ UINT16 opcode;
+ UINT8 param_buf[BT_OCTET16_LEN];
+} tSMP_ENC;
+
+/* Simple Pairing Events. Called by the stack when Simple Pairing related
+** events occur.
+*/
+typedef UINT8 (tSMP_CALLBACK) (tSMP_EVT event, BD_ADDR bd_addr, tSMP_EVT_DATA *p_data);
+
+/* callback function for CMAC algorithm
+*/
+typedef void (tCMAC_CMPL_CBACK)(UINT8 *p_mac, UINT16 tlen, UINT32 sign_counter);
+
+/*****************************************************************************
+** External Function Declarations
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* API of SMP */
+
+/*******************************************************************************
+**
+** Function SMP_Init
+**
+** Description This function initializes the SMP unit.
+**
+** Returns void
+**
+*******************************************************************************/
+ SMP_API extern void SMP_Init(void);
+
+/*******************************************************************************
+**
+** Function SMP_SetTraceLevel
+**
+** Description This function sets the trace level for SMP. If called with
+** a value of 0xFF, it simply returns the current trace level.
+**
+** Returns The new or current trace level
+**
+*******************************************************************************/
+ SMP_API extern UINT8 SMP_SetTraceLevel (UINT8 new_level);
+
+/*******************************************************************************
+**
+** Function SMP_Register
+**
+** Description This function register for the SMP service callback.
+**
+** Returns void
+**
+*******************************************************************************/
+ SMP_API extern BOOLEAN SMP_Register (tSMP_CALLBACK *p_cback);
+
+/*******************************************************************************
+**
+** Function SMP_Pair
+**
+** Description This function is called to start a SMP pairing.
+**
+** Returns SMP_STARTED if bond started, else otherwise exception.
+**
+*******************************************************************************/
+ SMP_API extern tSMP_STATUS SMP_Pair (BD_ADDR bd_addr);
+/*******************************************************************************
+**
+** Function SMP_PairCancel
+**
+** Description This function is called to cancel a SMP pairing.
+**
+** Returns TRUE - pairing cancelled
+**
+*******************************************************************************/
+ SMP_API extern BOOLEAN SMP_PairCancel (BD_ADDR bd_addr);
+
+/*******************************************************************************
+**
+** Function SMP_SecurityGrant
+**
+** Description This function is called to grant security process.
+**
+** Parameters bd_addr - peer device bd address.
+** res - result of the operation SMP_SUCCESS if success.
+** Otherwise, SMP_REPEATED_ATTEMPTS is too many attempts.
+**
+** Returns None
+**
+*******************************************************************************/
+ SMP_API extern void SMP_SecurityGrant(BD_ADDR bd_addr, UINT8 res);
+
+/*******************************************************************************
+**
+** Function SMP_PasskeyReply
+**
+** Description This function is called after Security Manager submitted
+** Passkey request to the application.
+**
+** Parameters: bd_addr - Address of the device for which PIN was requested
+** res - result of the operation BTM_SUCCESS if success
+** passkey - numeric value in the range of
+** BTM_MIN_PASSKEY_VAL(0) - BTM_MAX_PASSKEY_VAL(999999(0xF423F)).
+**
+*******************************************************************************/
+ SMP_API extern void SMP_PasskeyReply (BD_ADDR bd_addr, UINT8 res, UINT32 passkey);
+
+/*******************************************************************************
+**
+** Function SMP_OobDataReply
+**
+** Description This function is called to provide the OOB data for
+** Simple Pairing in response to BTM_SP_RMT_OOB_EVT
+**
+** Parameters: bd_addr - Address of the peer device
+** res - result of the operation SMP_SUCCESS if success
+** p_data - simple pairing Randomizer C.
+**
+*******************************************************************************/
+ SMP_API extern void SMP_OobDataReply(BD_ADDR bd_addr, tSMP_STATUS res, UINT8 len,
+ UINT8 *p_data);
+
+/*******************************************************************************
+**
+** Function SMP_Encrypt
+**
+** Description This function is called to encrypt the data with the specified
+** key
+**
+** Parameters: key - Pointer to key key[0] conatins the MSB
+** key_len - key length
+** plain_text - Pointer to data to be encrypted
+** plain_text[0] conatins the MSB
+** pt_len - plain text length
+** p_out - pointer to the encrypted outputs
+**
+** Returns Boolean - TRUE: encryption is successful
+*******************************************************************************/
+ SMP_API extern BOOLEAN SMP_Encrypt (UINT8 *key, UINT8 key_len,
+ UINT8 *plain_text, UINT8 pt_len,
+ tSMP_ENC *p_out);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* SMP_API_H */
diff --git a/stack/include/uipc_msg.h b/stack/include/uipc_msg.h
new file mode 100644
index 0000000..0091687
--- /dev/null
+++ b/stack/include/uipc_msg.h
@@ -0,0 +1,869 @@
+/*****************************************************************************/
+/* */
+/* Name: uipc_sync.h */
+/* */
+/* Description: this file contains sync message over UIPC */
+/* */
+/* Copyright (c) 1999-2007, Broadcom Corp., All Rights Reserved. */
+/* WIDCOMM Bluetooth Core. Proprietary and confidential. */
+/*****************************************************************************/
+#ifndef UIPC_MSG_H
+#define UIPC_MSG_H
+
+#include "bt_types.h"
+
+/****************************************************************************/
+/* UIPC version number: 1.0 */
+/****************************************************************************/
+#define UIPC_VERSION_MAJOR 0x0001
+#define UIPC_VERSION_MINOR 0x0000
+
+
+/********************************
+
+ UIPC Management Messages
+
+********************************/
+
+/* tUIPC_STATUS codes*/
+enum
+{
+ UIPC_STATUS_SUCCESS,
+ UIPC_STATUS_FAIL
+};
+typedef UINT8 tUIPC_STATUS;
+
+/* op_code */
+#define UIPC_OPEN_REQ 0x00
+#define UIPC_OPEN_RSP 0x01
+#define UIPC_CLOSE_REQ 0x02
+#define UIPC_CLOSE_RSP 0x03
+
+/* Structure of UIPC_OPEN_REQ message */
+typedef struct
+{
+ UINT8 opcode; /* UIPC_OPEN_REQ */
+} tUIPC_OPEN_REQ;
+#define UIPC_OPEN_REQ_MSGLEN (1)
+
+/* Structure of UIPC_OPEN_RSP message */
+typedef struct
+{
+ UINT8 opcode; /* UIPC_OPEN_RESP */
+ tUIPC_STATUS status; /* UIPC_STATUS */
+ UINT16 version_major; /* UIPC_VERSION_MAJOR */
+ UINT16 version_minor; /* UIPC_VERSION_MINOR */
+ UINT8 num_streams; /* Number of simultaneous streams supported by the light stack */
+} tUIPC_OPEN_RSP;
+#define UIPC_OPEN_RSP_MSGLEN (7)
+
+/* Structure of UIPC_CLOSE_REQ message */
+typedef struct t_uipc_close_req
+{
+ UINT8 opcode; /* UIPC_CLOSE_REQ */
+} tUIPC_CLOSE_REQ;
+#define UIPC_CLOSE_REQ_MSGLEN (1)
+
+/* Structure of UIPC_CLOSE_RSP message, only for BTC, full stack may ignore it */
+typedef struct t_uipc_close_rsp
+{
+ UINT8 opcode; /* UIPC_CLOSE_RSP */
+} tUIPC_CLOSE_RSP;
+#define UIPC_CLOSE_RSP_MSGLEN (1)
+
+/* UIPC management message structures */
+typedef union
+{
+ UINT8 opcode;
+ tUIPC_OPEN_REQ open_req;
+ tUIPC_OPEN_RSP open_resp;
+ tUIPC_CLOSE_REQ close_req;
+} tUIPC_MSG;
+
+#define UIPC_MGMT_MSG_MAXLEN (sizeof(tUIPC_MSG))
+
+#define IPC_LOG_MSG_LEN 100
+typedef struct t_uipc_log_msg
+{
+ UINT32 trace_set_mask;
+ UINT8 msg[IPC_LOG_MSG_LEN];
+} tUIPC_LOG_MSG;
+#define UIPC_LOG_MSGLEN (IPC_LOG_MSG_LEN + 4)
+
+/********************************
+
+ H5 Sync Message
+
+********************************/
+
+/* op_code */
+#define SLIP_SYNC_TO_LITE_REQ 0
+#define SLIP_SYNC_TO_LITE_RESP 1
+#define SLIP_SYNC_TO_FULL_REQ 2
+#define SLIP_SYNC_TO_FULL_RESP 3
+#define SLIP_SYNC_NOTIFY 4
+
+/* status */
+#define SLIP_SYNC_SUCCESS 0
+#define SLIP_SYNC_FAILURE 1
+
+typedef struct
+{
+ UINT8 op_code;
+ UINT8 status;
+ UINT16 acl_pkt_size;
+ UINT8 state;
+ UINT8 lp_state; /* Low Power state */
+ UINT8 next_seqno; /* next send seq */
+ UINT8 ack; /* next ack seq, expected seq from peer */
+ UINT8 sent_ack; /* last sent ack */
+ UINT8 sliding_window_size;/* window size */
+ BOOLEAN oof_flow_control; /* Out of Frame SW Flow Control */
+ BOOLEAN data_integrity_type;/* Level of Data Integrity Check */
+ UINT8 rx_state; /* rx state for incoming packet processing */
+} tSLIP_SYNC_INFO;
+
+/********************************
+
+ L2CAP Sync Message
+
+********************************/
+
+/* op_code */
+#define L2C_SYNC_TO_LITE_REQ 0
+#define L2C_SYNC_TO_LITE_RESP 1
+#define L2C_REMOVE_TO_LITE_REQ 2
+#define L2C_REMOVE_TO_LITE_RESP 3
+#define L2C_FLUSH_TO_FULL_IND 4
+
+/* status */
+#define L2C_SYNC_SUCCESS 0
+#define L2C_SYNC_FAILURE 1
+
+typedef struct t_l2c_stream_info
+{
+ UINT16 local_cid; /* Local CID */
+ UINT16 remote_cid; /* Remote CID */
+ UINT16 out_mtu; /* Max MTU we will send */
+ UINT16 handle; /* The handle used with LM */
+ UINT16 link_xmit_quota; /* Num outstanding pkts allowed */
+ BOOLEAN is_flushable; /* TRUE if flushable channel */
+} tL2C_STREAM_INFO;
+
+typedef struct t_l2c_sync_to_lite_req
+{
+ UINT8 op_code; /* L2C_SYNC_TO_LITE_REQ */
+ UINT16 light_xmit_quota; /* Total quota for light stack */
+ UINT16 acl_data_size; /* Max ACL data size across HCI transport */
+ UINT16 non_flushable_pbf; /* L2CAP_PKT_START_NON_FLUSHABLE if controller supports */
+ /* Otherwise, L2CAP_PKT_START */
+ UINT8 multi_av_data_cong_start; /* Multi-AV queue size to start congestion */
+ UINT8 multi_av_data_cong_end; /* Multi-AV queue size to end congestion */
+ UINT8 multi_av_data_cong_discard; /* Multi-AV queue size to discard */
+ UINT8 num_stream;
+ tL2C_STREAM_INFO stream[BTM_SYNC_INFO_NUM_STR];
+} tL2C_SYNC_TO_LITE_REQ;
+
+typedef struct t_l2c_sync_to_lite_resp_stream
+{
+ UINT16 lcid;
+ UINT8 status;
+} tL2C_SYNC_TO_LITE_RESP_STREAM;
+
+typedef struct t_l2c_sync_to_lite_resp
+{
+ UINT8 op_code; /* L2C_SYNC_TO_LITE_RESP */
+ UINT16 light_xmit_unacked; /* unacked packet more than quota in light stack */
+ UINT8 num_stream;
+ tL2C_SYNC_TO_LITE_RESP_STREAM stream[BTM_SYNC_INFO_NUM_STR];
+} tL2C_SYNC_TO_LITE_RESP;
+
+typedef struct t_l2c_remove_to_lite_req
+{
+ UINT8 op_code; /* L2C_REMOVE_TO_LITE_REQ */
+ UINT16 light_xmit_quota; /* Total quota for light stack */
+ UINT8 num_stream;
+ UINT16 lcid[BTM_SYNC_INFO_NUM_STR];
+} tL2C_REMOVE_TO_LITE_REQ;
+
+typedef tL2C_SYNC_TO_LITE_RESP tL2C_REMOVE_TO_LITE_RESP;
+typedef tL2C_REMOVE_TO_LITE_REQ tL2C_FLUSH_TO_FULL_IND;
+
+typedef union t_l2c_sync_msg
+{
+ UINT8 op_code;
+ tL2C_SYNC_TO_LITE_REQ sync_req;
+ tL2C_SYNC_TO_LITE_RESP sync_resp;
+ tL2C_REMOVE_TO_LITE_REQ remove_req;
+ tL2C_REMOVE_TO_LITE_RESP remove_resp;
+ tL2C_FLUSH_TO_FULL_IND flush_ind;
+} tL2C_SYNC_MSG;
+
+/********************************
+
+ AVDTP Sync Message
+
+********************************/
+
+/* op_code */
+#define AVDT_SYNC_TO_LITE_REQ 0
+#define AVDT_SYNC_TO_LITE_RESP 1
+#define AVDT_RESYNC_TO_LITE_REQ 2
+#define AVDT_RESYNC_TO_LITE_RESP 3
+#define AVDT_SYNC_TO_FULL_REQ 4
+#define AVDT_SYNC_TO_FULL_RESP 5
+#define AVDT_REMOVE_TO_LITE_REQ 6
+#define AVDT_REMOVE_TO_LITE_RESP 7
+#define AVDT_SYNC_TO_BTC_LITE_REQ 8
+#define AVDT_SYNC_TO_BTC_LITE_RESP 9
+
+/* status */
+#define AVDT_SYNC_SUCCESS 0
+#define AVDT_SYNC_FAILURE 1
+
+typedef struct
+{
+ UINT16 lcid;
+ UINT32 ssrc;
+} tAVDT_SYNC_TO_BTC_LITE_REQ_STREAM;
+
+typedef struct
+{
+ UINT8 opcode; /* AVDT_SYNC_TO_BTC_LITE_REQ */
+ UINT8 num_stream;
+ tAVDT_SYNC_TO_BTC_LITE_REQ_STREAM stream[BTM_SYNC_INFO_NUM_STR];
+} tAVDT_SYNC_TO_BTC_LITE_REQ;
+
+typedef struct
+{
+ UINT8 opcode; /* AVDT_SYNC_TO_BTC_LITE_RESP */
+ UINT8 status;
+} tAVDT_SYNC_TO_BTC_LITE_RESP;
+
+typedef struct t_avdt_scb_sync_info
+{
+ UINT8 handle; /* SCB handle */
+ BD_ADDR peer_addr; /* BD address of peer */
+ UINT16 local_cid; /* Local CID */
+ UINT16 peer_mtu; /* L2CAP mtu of the peer device */
+ UINT8 mux_tsid_media; /* TSID for media transport session */
+ UINT16 media_seq; /* media packet sequence number */
+} tAVDT_SCB_SYNC_INFO;
+
+typedef struct t_avdt_sync_info
+{
+ UINT8 op_code;
+ UINT8 status;
+
+ tAVDT_SCB_SYNC_INFO scb_info[BTM_SYNC_INFO_NUM_STR];
+
+} tAVDT_SYNC_INFO;
+
+typedef union t_avdt_sync_msg
+{
+ UINT8 op_code;
+ tAVDT_SYNC_INFO sync_info;
+ tAVDT_SYNC_TO_BTC_LITE_REQ btc_sync_req;
+ tAVDT_SYNC_TO_BTC_LITE_RESP btc_sync_resp;
+} tAVDT_SYNC_MSG;
+
+/********************************
+
+ BTA AV Sync Message
+
+********************************/
+
+/* op_code for MM light stack */
+#define BTA_AV_SYNC_TO_LITE_REQ 0
+#define BTA_AV_SYNC_TO_LITE_RESP 1
+#define BTA_AV_STR_START_TO_LITE_REQ 2
+#define BTA_AV_STR_START_TO_LITE_RESP 3
+#define BTA_AV_STR_STOP_TO_LITE_REQ 4
+#define BTA_AV_STR_STOP_TO_LITE_RESP 5
+#define BTA_AV_STR_CLEANUP_TO_LITE_REQ 6
+#define BTA_AV_STR_CLEANUP_TO_LITE_RESP 7
+#define BTA_AV_STR_SUSPEND_TO_LITE_REQ 8
+#define BTA_AV_STR_SUSPEND_TO_LITE_RESP 9
+#define BTA_AV_SYNC_ERROR_RESP 10
+
+/* op_code for BTC light stack */
+#define A2DP_START_REQ 11
+#define A2DP_START_RESP 12
+#define A2DP_STOP_REQ 13
+#define A2DP_STOP_RESP 14
+#define A2DP_CLEANUP_REQ 15
+#define A2DP_CLEANUP_RESP 16
+#define A2DP_SUSPEND_REQ 17
+#define A2DP_SUSPEND_RESP 18
+
+#define A2DP_JITTER_DONE_IND 41 /* For BTSNK */
+
+#define AUDIO_CODEC_CONFIG_REQ 19
+#define AUDIO_CODEC_CONFIG_RESP 20
+#define AUDIO_CODEC_SET_BITRATE_REQ 21
+#define AUDIO_CODEC_FLUSH_REQ 22
+#define AUDIO_ROUTE_CONFIG_REQ 23
+#define AUDIO_ROUTE_CONFIG_RESP 24
+#define AUDIO_MIX_CONFIG_REQ 25
+#define AUDIO_MIX_CONFIG_RESP 26
+#define AUDIO_BURST_FRAMES_IND 27
+#define AUDIO_BURST_END_IND 28
+#define AUDIO_EQ_MODE_CONFIG_REQ 29
+#define AUDIO_SCALE_CONFIG_REQ 30
+
+/* For TIVO, only applicable for I2S -> DAC */
+#define AUDIO_SUB_ROUTE_REQ 51
+#define AUDIO_SUB_ROUTE_RESP 52
+
+typedef struct
+{
+ UINT8 opcode; /* A2DP_START_REQ */
+ UINT16 lcid;
+ UINT16 curr_mtu;
+}tA2DP_START_REQ;
+
+typedef struct
+{
+ UINT8 opcode; /* A2DP_STOP_REQ */
+ UINT16 lcid;
+}tA2DP_STOP_REQ;
+
+typedef struct
+{
+ UINT8 opcode; /* A2DP_SUSPEND_REQ */
+ UINT16 lcid;
+}tA2DP_SUSPEND_REQ;
+
+typedef struct
+{
+ UINT8 opcode; /* A2DP_CLEANUP_REQ */
+ UINT16 lcid;
+ UINT16 curr_mtu;
+} tA2DP_CLEANUP_REQ;
+
+typedef struct
+{
+ UINT8 opcode; /* A2DP_START_RESP, A2DP_STOP_RESP, A2DP_CLEANUP_RESP, A2DP_SUSPEND_RESP */
+ UINT16 lcid;
+}tA2DP_GENERIC_RESP;
+
+#define AUDIO_CODEC_NONE 0x0000
+#define AUDIO_CODEC_SBC_ENC 0x0001
+#define AUDIO_CODEC_SBC_DEC 0x0002
+#define AUDIO_CODEC_MP3_ENC 0x0004
+#define AUDIO_CODEC_MP3_DEC 0x0008
+#define AUDIO_CODEC_AAC_ENC 0x0010
+#define AUDIO_CODEC_AAC_DEC 0x0020
+#define AUDIO_CODEC_AAC_PLUS_ENC 0x0040
+#define AUDIO_CODEC_AAC_PLUS_DEC 0x0080
+#define AUDIO_CODEC_MP2_ENC 0x0100
+#define AUDIO_CODEC_MP2_DEC 0x0200
+#define AUDIO_CODEC_MP2_5_ENC 0x0400
+#define AUDIO_CODEC_MP2_5_DEC 0x0800
+
+typedef UINT16 tAUDIO_CODEC_TYPE;
+
+/* SBC CODEC Parameters */
+
+#define CODEC_INFO_SBC_SF_16K 0x00
+#define CODEC_INFO_SBC_SF_32K 0x01
+#define CODEC_INFO_SBC_SF_44K 0x02
+#define CODEC_INFO_SBC_SF_48K 0x03
+
+#define CODEC_INFO_SBC_BLOCK_4 0x00
+#define CODEC_INFO_SBC_BLOCK_8 0x01
+#define CODEC_INFO_SBC_BLOCK_12 0x02
+#define CODEC_INFO_SBC_BLOCK_16 0x03
+
+#define CODEC_INFO_SBC_CH_MONO 0x00
+#define CODEC_INFO_SBC_CH_DUAL 0x01
+#define CODEC_INFO_SBC_CH_STEREO 0x02
+#define CODEC_INFO_SBC_CH_JS 0x03
+
+#define CODEC_INFO_SBC_ALLOC_LOUDNESS 0x00
+#define CODEC_INFO_SBC_ALLOC_SNR 0x01
+
+#define CODEC_INFO_SBC_SUBBAND_4 0x00
+#define CODEC_INFO_SBC_SUBBAND_8 0x01
+
+/* MPEG audio version ID */
+#define CODEC_INFO_MP25_ID 0x00
+#define CODEC_INFO_RESERVE 0x01
+#define CODEC_INFO_MP2_ID 0x02
+#define CODEC_INFO_MP3_ID 0x03
+
+#define CODEC_INFO_MP3_PROTECTION_ON 0x00
+#define CODEC_INFO_MP3_PROTECTION_OFF 0x01
+
+#define CODEC_INFO_MP3_BR_IDX_FREE 0x00
+#define CODEC_INFO_MP3_BR_IDX_32K 0x01
+#define CODEC_INFO_MP3_BR_IDX_40K 0x02
+#define CODEC_INFO_MP3_BR_IDX_48K 0x03
+#define CODEC_INFO_MP3_BR_IDX_56K 0x04
+#define CODEC_INFO_MP3_BR_IDX_64K 0x05
+#define CODEC_INFO_MP3_BR_IDX_80K 0x06
+#define CODEC_INFO_MP3_BR_IDX_96K 0x07
+#define CODEC_INFO_MP3_BR_IDX_112K 0x08
+#define CODEC_INFO_MP3_BR_IDX_128K 0x09
+#define CODEC_INFO_MP3_BR_IDX_160K 0x0A
+#define CODEC_INFO_MP3_BR_IDX_192K 0x0B
+#define CODEC_INFO_MP3_BR_IDX_224K 0x0C
+#define CODEC_INFO_MP3_BR_IDX_256K 0x0D
+#define CODEC_INFO_MP3_BR_IDX_320K 0x0E
+
+#define CODEC_INFO_MP3_SF_44K 0x00
+#define CODEC_INFO_MP3_SF_48K 0x01
+#define CODEC_INFO_MP3_SF_32K 0x02
+
+#define CODEC_INFO_MP3_MODE_STEREO 0x00
+#define CODEC_INFO_MP3_MODE_JS 0x01
+#define CODEC_INFO_MP3_MODE_DUAL 0x02
+#define CODEC_INFO_MP3_MODE_SINGLE 0x03
+
+/* layer 3, type of joint stereo coding method (intensity and ms) */
+#define CODEC_INFO_MP3_MODE_EXT_OFF_OFF 0x00
+#define CODEC_INFO_MP3_MODE_EXT_ON_OFF 0x01
+#define CODEC_INFO_MP3_MODE_EXT_OFF_ON 0x02
+#define CODEC_INFO_MP3_MODE_EXT_ON_ON 0x03
+
+
+#define CODEC_INFO_MP2_PROTECTION_ON 0x00
+#define CODEC_INFO_MP2_PROTECTION_OFF 0x01
+
+#define CODEC_INFO_MP2_BR_IDX_FREE 0x00
+#define CODEC_INFO_MP2_BR_IDX_8K 0x01
+#define CODEC_INFO_MP2_BR_IDX_16K 0x02
+#define CODEC_INFO_MP2_BR_IDX_24K 0x03
+#define CODEC_INFO_MP2_BR_IDX_32K 0x04
+#define CODEC_INFO_MP2_BR_IDX_40K 0x05
+#define CODEC_INFO_MP2_BR_IDX_48K 0x06
+#define CODEC_INFO_MP2_BR_IDX_56K 0x07
+#define CODEC_INFO_MP2_BR_IDX_64K 0x08
+#define CODEC_INFO_MP2_BR_IDX_80K 0x09
+#define CODEC_INFO_MP2_BR_IDX_96K 0x0A
+#define CODEC_INFO_MP2_BR_IDX_112K 0x0B
+#define CODEC_INFO_MP2_BR_IDX_128K 0x0C
+#define CODEC_INFO_MP2_BR_IDX_144K 0x0D
+#define CODEC_INFO_MP2_BR_IDX_160K 0x0E
+
+#define CODEC_INFO_MP2_SF_22K 0x00
+#define CODEC_INFO_MP2_SF_24K 0x01
+#define CODEC_INFO_MP2_SF_16K 0x02
+
+#define CODEC_INFO_MP2_MODE_STEREO 0x00
+#define CODEC_INFO_MP2_MODE_JS 0x01
+#define CODEC_INFO_MP2_MODE_DUAL 0x02
+#define CODEC_INFO_MP2_MODE_SINGLE 0x03
+
+/* layer 3, type of joint stereo coding method (intensity and ms) */
+#define CODEC_INFO_MP2_MODE_EXT_OFF_OFF 0x00
+#define CODEC_INFO_MP2_MODE_EXT_ON_OFF 0x01
+#define CODEC_INFO_MP2_MODE_EXT_OFF_ON 0x02
+#define CODEC_INFO_MP2_MODE_EXT_ON_ON 0x03
+
+#define CODEC_INFO_MP2_SAMPLE_PER_FRAME 576
+
+/* mpeg 2.5 layer 3 decoder */
+
+#define CODEC_INFO_MP25_PROTECTION_ON 0x00
+#define CODEC_INFO_MP25_PROTECTION_OFF 0x01
+
+#define CODEC_INFO_MP25_BR_IDX_FREE 0x00
+#define CODEC_INFO_MP25_BR_IDX_8K 0x01
+#define CODEC_INFO_MP25_BR_IDX_16K 0x02
+#define CODEC_INFO_MP25_BR_IDX_24K 0x03
+#define CODEC_INFO_MP25_BR_IDX_32K 0x04
+#define CODEC_INFO_MP25_BR_IDX_40K 0x05
+#define CODEC_INFO_MP25_BR_IDX_48K 0x06
+#define CODEC_INFO_MP25_BR_IDX_56K 0x07
+#define CODEC_INFO_MP25_BR_IDX_64K 0x08
+#define CODEC_INFO_MP25_BR_IDX_80K 0x09
+#define CODEC_INFO_MP25_BR_IDX_96K 0x0A
+#define CODEC_INFO_MP25_BR_IDX_112K 0x0B
+#define CODEC_INFO_MP25_BR_IDX_128K 0x0C
+#define CODEC_INFO_MP25_BR_IDX_144K 0x0D
+#define CODEC_INFO_MP25_BR_IDX_160K 0x0E
+
+#define CODEC_INFO_MP25_SF_11K 0x00
+#define CODEC_INFO_MP25_SF_12K 0x01
+#define CODEC_INFO_MP25_SF_8K 0x02
+
+#define CODEC_INFO_MP25_MODE_STEREO 0x00
+#define CODEC_INFO_MP25_MODE_JS 0x01
+#define CODEC_INFO_MP25_MODE_DUAL 0x02
+#define CODEC_INFO_MP25_MODE_SINGLE 0x03
+
+/* layer 3, type of joint stereo coding method (intensity and ms) */
+#define CODEC_INFO_MP25_MODE_EXT_OFF_OFF 0x00
+#define CODEC_INFO_MP25_MODE_EXT_ON_OFF 0x01
+#define CODEC_INFO_MP25_MODE_EXT_OFF_ON 0x02
+#define CODEC_INFO_MP25_MODE_EXT_ON_ON 0x03
+
+#define CODEC_INFO_MP25_SAMPLE_PER_FRAME 576
+
+/* AAC/AAC+ CODEC Parameters */
+#define CODEC_INFO_AAC_SF_IDX_96K 0x0
+#define CODEC_INFO_AAC_SF_IDX_88K 0x1
+#define CODEC_INFO_AAC_SF_IDX_64K 0x2
+#define CODEC_INFO_AAC_SF_IDX_48K 0x3
+#define CODEC_INFO_AAC_SF_IDX_44K 0x4
+#define CODEC_INFO_AAC_SF_IDX_32K 0x5
+#define CODEC_INFO_AAC_SF_IDX_24K 0x6
+#define CODEC_INFO_AAC_SF_IDX_22K 0x7
+#define CODEC_INFO_AAC_SF_IDX_16K 0x8
+#define CODEC_INFO_AAC_SF_IDX_12K 0x9
+#define CODEC_INFO_AAC_SF_IDX_11K 0xA
+#define CODEC_INFO_AAC_SF_IDX_08K 0xB
+#define CODEC_INFO_AAC_SF_IDX_RESERVE 0xC
+
+#define CODEC_INFO_AAC_BR_RATE_48K 288000
+#define CODEC_INFO_AAC_BR_RATE_44K 264600
+#define CODEC_INFO_AAC_BR_RATE_32K 192000
+
+
+#define CODEC_INFO_AAC_1_CH 1 /*center front speaker */
+#define CODEC_INFO_AAC_2_CH 2 /*left, right front speaker */
+#define CODEC_INFO_AAC_3_CH 3 /*center front speaker, left right front speaker */
+#define CODEC_INFO_AAC_4_CH 4 /*center/rear front speaker, left/right front speaker */
+#define CODEC_INFO_AAC_5_CH 5 /*center, left, right front speaker, left/right surround */
+#define CODEC_INFO_AAC_6_CH 6 /*center, left, right front speaker, left/right surround, LFE */
+#define CODEC_INFO_AAC_7_CH 7 /*(left, right)center/left,right front speaker, left/right surround, LFE */
+
+
+typedef struct
+{
+ UINT8 sampling_freq;
+ UINT8 channel_mode;
+ UINT8 block_length;
+ UINT8 num_subbands;
+ UINT8 alloc_method;
+ UINT8 bitpool_size; /* 2 - 250 */
+} tCODEC_INFO_SBC;
+
+typedef struct
+{
+ UINT8 ch_mode;
+ UINT8 sampling_freq;
+ UINT8 bitrate_index; /* 0 - 14 */
+} tCODEC_INFO_MP3;
+
+typedef struct
+{
+ UINT8 ch_mode;
+ UINT8 sampling_freq;
+ UINT8 bitrate_index; /* 0 - 14 */
+} tCODEC_INFO_MP2;
+
+
+typedef struct
+{
+ UINT8 ch_mode;
+ UINT8 sampling_freq;
+ UINT8 bitrate_index; /* 0 - 14 */
+} tCODEC_INFO_MP2_5;
+
+typedef struct
+{
+ UINT16 sampling_freq;
+ UINT8 channel_mode; /* 0x02:mono, 0x01:dual */
+ UINT32 bitrate; /* 0 - 320K */
+ UINT32 sbr_profile; /* 1: ON, 0: OFF */
+} tCODEC_INFO_AAC;
+
+typedef union
+{
+ tCODEC_INFO_SBC sbc;
+ tCODEC_INFO_MP3 mp3;
+ tCODEC_INFO_MP2 mp2;
+ tCODEC_INFO_MP2_5 mp2_5;
+ tCODEC_INFO_AAC aac;
+} tCODEC_INFO;
+
+typedef struct
+{
+ UINT8 opcode; /* AUDIO_CODEC_CONFIG_REQ */
+ tAUDIO_CODEC_TYPE codec_type;
+ tCODEC_INFO codec_info;
+} tAUDIO_CODEC_CONFIG_REQ;
+
+#define AUDIO_CONFIG_SUCCESS 0x00
+#define AUDIO_CONFIG_NOT_SUPPORTED 0x01
+#define AUDIO_CONFIG_FAIL_OUT_OF_MEMORY 0x02
+#define AUDIO_CONFIG_FAIL_CODEC_USED 0x03
+#define AUDIO_CONFIG_FAIL_ROUTE 0x04
+typedef UINT8 tAUDIO_CONFIG_STATUS;
+
+typedef struct
+{
+ UINT8 opcode; /* AUDIO_CODEC_CONFIG_RESP */
+ tAUDIO_CONFIG_STATUS status;
+} tAUDIO_CODEC_CONFIG_RESP;
+
+typedef struct
+{
+ UINT8 opcode; /* AUDIO_CODEC_SET_BITRATE_REQ */
+ tAUDIO_CODEC_TYPE codec_type;
+ union
+ {
+ UINT8 sbc;
+ UINT8 mp3;
+ UINT32 aac;
+ } codec_bitrate;
+} tAUDIO_CODEC_SET_BITRATE_REQ;
+
+#define AUDIO_ROUTE_SRC_FMRX 0x00
+#define AUDIO_ROUTE_SRC_I2S 0x01
+#define AUDIO_ROUTE_SRC_ADC 0x02
+#define AUDIO_ROUTE_SRC_HOST 0x03
+#define AUDIO_ROUTE_SRC_PTU 0x04
+#define AUDIO_ROUTE_SRC_BTSNK 0x05
+#define AUDIO_ROUTE_SRC_NONE 0x80
+#define MAX_AUDIO_ROUTE_SRC 6
+typedef UINT8 tAUDIO_ROUTE_SRC;
+
+#define AUDIO_ROUTE_MIX_NONE 0x00
+#define AUDIO_ROUTE_MIX_HOST 0x01
+#define AUDIO_ROUTE_MIX_PCM 0x02
+#define AUDIO_ROUTE_MIX_CHIRP 0x03
+#define AUDIO_ROUTE_MIX_I2S 0x04
+#define AUDIO_ROUTE_MIX_ADC 0x05
+#define AUDIO_ROUTE_MIX_RESERVED 0x06
+#define MAX_AUDIO_ROUTE_MIX 7
+typedef UINT8 tAUDIO_ROUTE_MIX;
+
+#define AUDIO_ROUTE_OUT_NONE 0x0000
+#define AUDIO_ROUTE_OUT_BTA2DP 0x0001
+#define AUDIO_ROUTE_OUT_FMTX 0x0002
+#define AUDIO_ROUTE_OUT_BTSCO 0x0004
+#define AUDIO_ROUTE_OUT_HOST 0x0008
+#define AUDIO_ROUTE_OUT_DAC 0x0010
+#define AUDIO_ROUTE_OUT_I2S 0x0020
+#define AUDIO_ROUTE_OUT_BTA2DP_DAC 0x0040
+#define AUDIO_ROUTE_OUT_BTA2DP_I2S 0x0080
+#define AUDIO_ROUTE_OUT_BTSCO_DAC 0x0100
+#define AUDIO_ROUTE_OUT_BTSCO_I2S 0x0200
+#define AUDIO_ROUTE_OUT_HOST_BTA2DP 0x0400
+#define AUDIO_ROUTE_OUT_HOST_BTSCO 0x0800
+#define AUDIO_ROUTE_OUT_HOST_DAC 0x1000
+#define AUDIO_ROUTE_OUT_HOST_I2S 0x2000
+#define AUDIO_ROUTE_OUT_DAC_I2S 0x4000
+#define AUDIO_ROUTE_OUT_RESERVED_2 0x8000
+
+#define MAX_AUDIO_SINGLE_ROUTE_OUT 6
+#define MAX_AUDIO_MULTI_ROUTE_OUT 16
+typedef UINT16 tAUDIO_MULTI_ROUTE_OUT;
+typedef UINT8 tAUDIO_ROUTE_OUT;
+
+#define AUDIO_ROUTE_SF_8K 0x00
+#define AUDIO_ROUTE_SF_16K 0x01
+#define AUDIO_ROUTE_SF_32K 0x02
+#define AUDIO_ROUTE_SF_44_1K 0x03
+#define AUDIO_ROUTE_SF_48K 0x04
+#define AUDIO_ROUTE_SF_11K 0x05
+#define AUDIO_ROUTE_SF_12K 0x06
+#define AUDIO_ROUTE_SF_22K 0x07
+#define AUDIO_ROUTE_SF_24K 0x08
+#define AUDIO_ROUTE_SF_NA 0xFF
+typedef UINT8 tAUDIO_ROUTE_SF;
+
+#define AUDIO_ROUTE_EQ_BASS_BOOST 0x00
+#define AUDIO_ROUTE_EQ_CLASSIC 0x01
+#define AUDIO_ROUTE_EQ_JAZZ 0x02
+#define AUDIO_ROUTE_EQ_LIVE 0x03
+#define AUDIO_ROUTE_EQ_NORMAL 0x04
+#define AUDIO_ROUTE_EQ_ROCK 0x05
+#define AUDIO_ROUTE_EQ_BYPASS 0x06
+
+#define AUDIO_ROUTE_DIGITAL_VOLUME_CONTROL 0x07
+
+#define AUDIO_ROUTE_EQ_CONFIG_GAIN 0xFF /* Custion Gain Config */
+typedef UINT8 tAUDIO_ROUTE_EQ;
+
+typedef struct
+{
+ UINT8 opcode; /* AUDIO_ROUTE_CONFIG_REQ */
+ tAUDIO_ROUTE_SRC src;
+ tAUDIO_ROUTE_SF src_sf;
+ tAUDIO_ROUTE_OUT out;
+ tAUDIO_ROUTE_SF out_codec_sf;
+ tAUDIO_ROUTE_SF out_i2s_sf;
+ tAUDIO_ROUTE_EQ eq_mode;
+} tAUDIO_ROUTE_CONFIG_REQ;
+
+typedef struct
+{
+ UINT8 opcode; /* AUDIO_ROUTE_CONFIG_RESP */
+ tAUDIO_CONFIG_STATUS status;
+} tAUDIO_ROUTE_CONFIG_RESP;
+
+typedef struct
+{
+ UINT16 amp[2]; /* left/right 15 bit amplitude value */
+ UINT16 tone[2]; /* left/right 12 bit frequency 0 - 4096Hz */
+ UINT16 mark[2]; /* left/right 16 bit mark time 0 - 65535ms */
+ UINT16 space[2]; /* left/right 16 bit space time 0 - 65535ms */
+} tCHIRP_CONFIG;
+
+typedef struct
+{
+ UINT8 pri_l; /* Primary Left scale : 0 ~ 255 */
+ UINT8 mix_l; /* Mixing Left scale : 0 ~ 255 */
+ UINT8 pri_r; /* Primary Right scale : 0 ~ 255 */
+ UINT8 mix_r; /* Mixing Right scale : 0 ~ 255 */
+} tMIX_SCALE_CONFIG;
+
+/* For custon equalizer gain configuration */
+typedef struct
+{
+ UINT32 audio_l_g0; /* IIR biquad filter left ch gain 0 */
+ UINT32 audio_l_g1; /* IIR biquad filter left ch gain 1 */
+ UINT32 audio_l_g2; /* IIR biquad filter left ch gain 2 */
+ UINT32 audio_l_g3; /* IIR biquad filter left ch gain 3 */
+ UINT32 audio_l_g4; /* IIR biquad filter left ch gain 4 */
+ UINT32 audio_l_gl; /* IIR biquad filter left ch global gain */
+ UINT32 audio_r_g0; /* IIR biquad filter left ch gain 0 */
+ UINT32 audio_r_g1; /* IIR biquad filter left ch gain 1 */
+ UINT32 audio_r_g2; /* IIR biquad filter left ch gain 2 */
+ UINT32 audio_r_g3; /* IIR biquad filter left ch gain 3 */
+ UINT32 audio_r_g4; /* IIR biquad filter left ch gain 4 */
+ UINT32 audio_r_gl; /* IIR biquad filter left ch global gain */
+} tEQ_GAIN_CONFIG;
+
+typedef struct
+{
+ UINT8 opcode; /* AUDIO_MIX_CONFIG_REQ */
+ tAUDIO_ROUTE_MIX mix_src;
+ tAUDIO_ROUTE_SF mix_src_sf;
+ tMIX_SCALE_CONFIG mix_scale;
+ tCHIRP_CONFIG chirp_config;
+} tAUDIO_MIX_CONFIG_REQ;
+
+typedef struct
+{
+ UINT8 opcode; /* AUDIO_MIX_CONFIG_RESP */
+ tAUDIO_CONFIG_STATUS status;
+} tAUDIO_MIX_CONFIG_RESP;
+
+
+typedef struct
+{
+ UINT8 opcode; /* AUDIO_BURST_FRAMES_IND */
+ UINT32 burst_size; /* in bytes */
+} tAUDIO_BURST_FRAMES_IND;
+
+typedef struct
+{
+ UINT8 opcode; /* AUDIO_BURST_END_IND */
+} tAUDIO_BURST_END_IND;
+
+typedef struct
+{
+ UINT8 opcode; /* AUDIO_CODEC_FLUSH_REQ */
+} tAUDIO_CODEC_FLUSH_REQ;
+
+typedef struct
+{
+ UINT8 opcode; /* AUDIO_EQ_MODE_CONFIG_REQ */
+ tAUDIO_ROUTE_EQ eq_mode;
+ tEQ_GAIN_CONFIG filter_gain; /* Valid only when eq_mode is 0xFF */
+} tAUDIO_EQ_MODE_CONFIG_REQ;
+
+typedef struct
+{
+ UINT8 opcode; /* AUDIO_SCALE_CONFIG_REQ */
+ tMIX_SCALE_CONFIG mix_scale;
+} tAUDIO_SCALE_CONFIG_REQ;
+
+typedef UINT8 tBTA_AV_DUAL_STACK_EVT;
+
+typedef struct
+{
+ UINT8 avdt_handle; /* AVDTP handle */
+ UINT8 chnl; /* the channel: audio/video */
+ UINT8 codec_type; /* codec type */
+ BOOLEAN cong; /* TRUE if AVDTP congested */
+ UINT8 hdi; /* the index to SCB[] */
+ UINT8 hndl; /* the handle: ((hdi + 1)|chnl) */
+ UINT8 l2c_bufs; /* the number of buffers queued to L2CAP */
+ UINT16 l2c_cid; /* L2CAP channel ID */
+ BD_ADDR peer_addr; /* peer BD address */
+}tBTA_AV_SYNC_INFO;
+
+typedef struct
+{
+ tBTA_AV_DUAL_STACK_EVT event;
+ tBTA_AV_SYNC_INFO sync_info;
+ UINT16 curr_mtu; /* common mtu shared by all active streams */
+ UINT8 multi_av_supported; /* Whether multi-av is supported */
+}tBTA_AV_SYNC_INFO_REQ; /* SYNC_TO_LITE_REQ */
+
+/* Dual stack stream events */
+typedef struct
+{
+ tBTA_AV_DUAL_STACK_EVT event;
+ UINT8 scb_idx;
+}tBTA_AV_SCB_EVT;
+
+/* data type for the Audio Codec Information*/
+typedef struct
+{
+ UINT16 bit_rate; /* SBC encoder bit rate in kbps */
+ UINT16 bit_rate_busy; /* SBC encoder bit rate in kbps */
+ UINT16 bit_rate_swampd; /* SBC encoder bit rate in kbps */
+ UINT8 busy_level; /* Busy level indicating the bit-rate to be used */
+ UINT8 codec_info[AVDT_CODEC_SIZE];
+ UINT8 codec_type; /* Codec type */
+} tBTA_AV_AUDIO_CODEC_SYNC_INFO;
+
+/* Dual stack stream events */
+typedef struct
+{
+ tBTA_AV_DUAL_STACK_EVT event;
+ UINT8 scb_idx;
+ UINT8 audio_open_cnt;
+ tBTA_AV_AUDIO_CODEC_SYNC_INFO p_codec_cfg;
+ UINT8 start_stop_flag;
+}tBTA_AV_SCB_REQ;
+
+typedef struct
+{
+ tBTA_AV_DUAL_STACK_EVT event;
+ UINT8 scb_idx;
+ UINT8 audio_open_cnt;
+ UINT16 curr_mtu; /* common mtu shared by all active streams */
+}tBTA_AV_SCB_CLEANUP_REQ;
+
+/* Add request/response structures if needed ...
+typedef struct
+{
+ event;
+ data;
+}tBTA_AV_SYNC_*_REQ/RESP;
+*/
+
+typedef union
+{
+ /* MM light stack */
+ tBTA_AV_DUAL_STACK_EVT event;
+ tBTA_AV_SYNC_INFO_REQ sync_info_req;
+ tBTA_AV_SCB_EVT scb_evt;
+ tBTA_AV_SCB_REQ scb_req;
+ tBTA_AV_SCB_CLEANUP_REQ scb_cleanup_req;
+
+ /* BTC light stack */
+ UINT8 opcode;
+ tA2DP_START_REQ btc_start_req;
+ tA2DP_STOP_REQ btc_stop_req;
+ tA2DP_CLEANUP_REQ btc_cleanup_req;
+ tA2DP_SUSPEND_REQ btc_suspend_req;
+
+ tAUDIO_CODEC_CONFIG_REQ codec_config_req;
+ tAUDIO_CODEC_SET_BITRATE_REQ codec_bitrate_req;
+ tAUDIO_CODEC_FLUSH_REQ codec_flush_req;
+ tAUDIO_ROUTE_CONFIG_REQ route_config_req;
+ tAUDIO_MIX_CONFIG_REQ mix_config_req;
+ tAUDIO_EQ_MODE_CONFIG_REQ eq_mode_req;
+ tAUDIO_SCALE_CONFIG_REQ scale_config_req;
+}tBTA_DUAL_STACK_MSG;
+
+#endif /* UIPC_MSG_H */
diff --git a/stack/include/utfc.h b/stack/include/utfc.h
new file mode 100644
index 0000000..4460b8f
--- /dev/null
+++ b/stack/include/utfc.h
@@ -0,0 +1,48 @@
+/*****************************************************************************
+**
+** Name: utfc.h
+**
+** Description: UTF conversion utilities.
+**
+** Copyright (c) 2003-2004, WIDCOMM Inc., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef UTFC_H
+#define UTFC_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*******************************************************************************
+**
+** Function utfc_16_to_8
+**
+** Description Convert a UTF-16 array to a null-terminated UTF-8 string.
+** Illegal characters are skipped.
+**
+** Returns Length of UTF-8 string in bytes.
+**
+*******************************************************************************/
+extern UINT16 utfc_16_to_8(UINT8 *p_utf8, UINT16 utf8_len, UINT16 *p_utf16, UINT16 utf16_len);
+
+/*******************************************************************************
+**
+** Function utfc_8_to_16
+**
+** Description Convert a null-terminated UTF-8 string to a UTF-16 array.
+** Illegal characters are skipped. The UTF-16 array is
+** appended with a zero (null) character.
+**
+** Returns Length of UTF-16 array including null character.
+**
+*******************************************************************************/
+extern UINT16 utfc_8_to_16(UINT16 *p_utf16, UINT16 utf16_len, UINT8 *p_utf8);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* UTFC_H */
diff --git a/stack/include/wbt_api.h b/stack/include/wbt_api.h
new file mode 100644
index 0000000..be94e56
--- /dev/null
+++ b/stack/include/wbt_api.h
@@ -0,0 +1,58 @@
+/*****************************************************************************
+**
+** Name: wbt_api.h
+**
+** Description: This file contains definitions and constants used by the
+** Broadcom Bluetooth Extensions API software.
+**
+** Copyright (c) 2003-2005, Broadcom Corp., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef WBT_API_H
+#define WBT_API_H
+
+#include "bt_target.h"
+
+/*****************************************************************************
+** Constants and Types
+*****************************************************************************/
+
+/**************************
+* SDP Attribute IDs *
+***************************/
+#define ATTR_ID_EXT_BRCM_VERSION 0x8001 /* UINT16 (0xmmnn - major, minor [0x0001]) mandatory */
+#define ATTR_ID_EXT_PIN_CODE 0x8002 /* UINT32 4 - digit pin */
+
+/**************************
+* SDP Attribute ID Values *
+***************************/
+/* Version Attribute Value */
+#define BRCM_EXT_VERSION 0x0001 /* UINT16 (0xmmnn - major, minor [0x0001]) mandatory */
+
+/* Pin Code Attribute Value */
+#define BRCM_EXT_PIN_CODE 0x00000000 /* UINT32 ('0000') */
+
+/*****************************************************************************
+** External Function Declarations
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+BT_API extern BOOLEAN WBT_ExtCreateRecord(void);
+
+/*** Features ***/
+BT_API extern BOOLEAN WBT_ExtAddPinCode(void);
+
+
+BT_API extern UINT32 wbt_sdp_show_ext(UINT8 scn, char *service_name,
+ UINT8 pin_code_ext,
+ UINT8 active_sync_ext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* WBT_API_H */
diff --git a/stack/include/wcassert.h b/stack/include/wcassert.h
new file mode 100644
index 0000000..459081f
--- /dev/null
+++ b/stack/include/wcassert.h
@@ -0,0 +1,66 @@
+#ifndef WC_ASSERT_H
+#define WC_ASSERT_H
+/*******************************************************************************
+**
+** File Name: wcassert.h
+**
+** Purpose: Defines the macro WC_ASSERT(), which is used during
+** development / debugging to do precondition and postcondition
+** checks for routines.
+**
+** The macros are enabled when _DEBUG is defined.
+** Note:
+** None.
+**
+** Revision History:
+** 10/23/99 Stephen Lee Create
+**
+** Copyright (c) 1999-2004 WIDCOMM Inc., All Rights Reserved.
+**
+*******************************************************************************/
+
+
+#ifdef _DEBUG
+
+#include "bt_target.h"
+
+
+
+/* debug settings*/
+#ifndef WC_DEBUG_LEVEL
+#define WC_DEBUG_LEVEL 0
+#endif
+
+#if WC_DEBUG_LEVEL == 0
+
+#include "stdio.h" /* for printf()*/
+
+#ifdef __cplusplus
+extern "C" wc_assert(char *message, char *file, UINT32 line);
+#else
+void wc_assert(char *message, char *file, UINT32 line);
+#endif
+
+#define WC_ASSERT(_x) if ( !(_x) ) wc_assert("ASSERT at %s line %d\n", __FILE__, __LINE__);
+#define WC_ASSERT_ALWAYS() wc_assert("ASSERT! at %s line %d\n", __FILE__, __LINE__);
+
+#elif WC_DEBUG_LEVEL == 1
+
+#include "assert.h"
+
+#define WC_ASSERT(_x) assert(_x);
+#define WC_ASSERT_ALWAYS() assert(0);
+#endif /* WC_DEBUG_LEVEL*/
+
+#else /* _DEBUG*/
+
+#ifndef WC_ASSERT
+#define WC_ASSERT(_x) ;
+#endif
+
+#ifndef WC_ASSERT_ALWAYS
+#define WC_ASSERT_ALWAYS() ;
+#endif
+
+#endif /* _DEBUG*/
+#endif /* WC_ASSERT_H*/
diff --git a/stack/include/xml_bld_api.h b/stack/include/xml_bld_api.h
new file mode 100644
index 0000000..2d788e0
--- /dev/null
+++ b/stack/include/xml_bld_api.h
@@ -0,0 +1,113 @@
+/*****************************************************************************
+**
+** Name: xml_bld_api.h
+**
+** File: XML Builder API
+**
+**
+** Copyright (c) 2000-2004, WIDCOMM Inc., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef XML_BLD_API_H
+#define XML_BLD_API_H
+
+#include "data_types.h"
+
+
+/*****************************************************************************
+** Type Definitions
+*****************************************************************************/
+
+enum
+{
+ XML_BLD_SUCCESS,
+ XML_BLD_ERROR
+};
+typedef UINT16 tXML_BLD_RESULT;
+
+
+enum
+{
+ XML_ATTR_CONT = FALSE, /* not the end of attribute list. add quote(') */
+ XML_ATTR_LAST = TRUE, /* the last one of the attribute list. add quote('), greater_than(>), and line_feed(\n) */
+ XML_ATTR_ETAG = 2 /* the end of the element. add quote('), end_mark(/), greater_than(>), and line_feed(\n) */
+};
+typedef UINT8 tXML_ATTR_END;
+
+
+/*****************************************************************************
+** External Function Declarations
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+
+/*****************************************************************************
+**
+** Function: XML_BufAddTag
+**
+** Purpose: Write a start or end tag and optional prefix.
+**
+** Parameters:
+** UINT8 **pp_buf reference to the storage to hold the XML object
+** GOEP_WriteStore.
+** const UINT8* prefix tag prefix (namespace)
+** const UINT8* tag tag name
+** BOOLEAN start_tag TRUE = start tag, FALSE = end tag
+** BOOLEAN has_attr TRUE if the tag contains attributes
+**
+** Returns: XML_BLD_SUCCESS if success
+**
+*****************************************************************************/
+tXML_BLD_RESULT XML_BufAddTag (UINT8 **pp_buf,
+ const UINT8 *prefix,
+ const UINT8 *tag,
+ BOOLEAN start_tag,
+ BOOLEAN has_attr);
+
+
+/*****************************************************************************
+**
+** Function: XML_BufAddAttribute
+**
+** Purpose: Write an attribute and optional prefix.
+**
+** Parameters:
+** UINT8 **pp_buf reference to the storage to hold the XML object
+** const UINT8* prefix attribute prefix (namespace)
+** const UINT8* attr_name attribute name
+** const UINT8* attr_value attribute value
+**
+** Returns: XML_BLD_SUCCESS if success
+**
+*****************************************************************************/
+tXML_BLD_RESULT XML_BufAddAttribute (UINT8 **pp_buf,
+ const UINT8 *prefix,
+ const UINT8 *attr_name,
+ const UINT8 *attr_value,
+ tXML_ATTR_END last_attr);
+
+/*****************************************************************************
+**
+** Function: XML_BufAddCharData
+**
+** Purpose: Write the element content.
+**
+** Parameters:
+** UINT8 **pp_buf reference to the storage to hold the XML object
+** const UINT8* content element content
+**
+** Returns: XML_BLD_SUCCESS if success
+**
+*****************************************************************************/
+tXML_BLD_RESULT XML_BufAddCharData (UINT8 **pp_buf, const UINT8 *charData);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ifndef XML_BLD_API_H */
diff --git a/stack/include/xml_erp_api.h b/stack/include/xml_erp_api.h
new file mode 100644
index 0000000..fa2b33a
--- /dev/null
+++ b/stack/include/xml_erp_api.h
@@ -0,0 +1,145 @@
+/******************************************************************************
+ **
+ ** Name: xml_erp_api.h
+ ** $Id:
+ **
+ ** Description: This module contains xml parser of MAP event report
+ **
+ ** Copyright (c) 2004-2005, Broadcom Corporation, All Rights Reserved.
+ ** WIDCOMM Bluetooth Core. Proprietary and confidential.
+ ******************************************************************************/
+
+#ifndef XML_ERP_API_H
+#define XML_ERP_API_H
+
+#include "bt_target.h"
+#include "gki.h"
+#include "xml_pars_api.h"
+
+
+#ifndef XML_EVT_RPT_CARRY_OVER_LEN
+#define XML_EVT_RPT_CARRY_OVER_LEN 512 /* number of bytes we can store in case we did not yet find the > */
+#endif
+
+/**********************************************************************************/
+
+typedef struct
+{
+ UINT16 type_len;
+ UINT16 handle_len;
+ UINT16 folder_len;
+ UINT16 old_folder_len;
+ UINT16 msg_type_len;
+ UINT8 *type;
+ UINT8 *handle;
+ UINT8 *folder;
+ UINT8 *old_folder;
+ UINT8 *msg_type;
+} tXML_EVT_RPT_ENTRY;
+
+/**********************************************************************************/
+
+enum
+{
+ XML_EVT_RPT_OK, /* parsing is ok, operation is ok */
+ XML_EVT_RPT_PENDING, /* parsing is ok but not enough data */
+ XML_EVT_RPT_END_LIST, /* found </MAP-event-report> */
+ XML_EVT_RPT_OUT_FULL, /* output buffer full /MAP-event-report not reached! data is dumped */
+ XML_EVT_RPT_ERROR, /* some parsing error occured */
+ XML_EVT_RPT_NO_RES, /* ran out of resources (memory) */
+ XML_EVT_RPT_DST_NO_RES /* ran out of destination data buffer */
+} ;
+typedef UINT8 tXML_EVT_RPT_RES;
+
+
+typedef struct
+{
+ tXML_EVT_RPT_ENTRY *p_entry; /* point to parser_cb->ilist.evt_rpt */
+ tXML_PROP *p_prop; /* GKI_BUF3_SIZE */
+
+ tXML_PROP *offset_prop; /* current filling property */
+ UINT16 prop_num; /* number of properties left to be filled in */
+
+ INT16 current_entry;
+ INT16 max_name_len; /* maximum length of name length of entry
+ XML parser limits to 196 bytes i think. */
+ UINT16 max_entry;
+ BOOLEAN ended;
+ UINT16 prop_index;
+ UINT16 max_num_prop;
+ UINT8 obj; /* the XML object - (tFTC_XML_OBJ + 1)*/
+} tXML_EVT_RPT_STATE;
+
+typedef struct
+{
+ tXML_MUL_STATE xml;
+ tXML_EVT_RPT_STATE xml_user_data;
+} tXML_EVT_RPT_PARSER;
+
+/* only this value is of significance, if not ok frame is dropped by parser */
+#define XML_EVT_RPT_ENTRY_OK 0
+
+typedef UINT8 tXML_EVT_RPT_STATUS;
+
+
+typedef struct
+{
+ UINT8 *data;
+ UINT16 len;
+ BOOLEAN final; /* If TRUE, entry is last of the series */
+ tXML_EVT_RPT_STATUS status; /* Fields are valid when status is BTA_FTC_OK */
+} tXML_EVT_RPT_LIST; /* clone of tBTA_FTC_LIST */
+
+
+/**************************************************************************************
+** Function XML_EvtRptInit
+**
+** Description Initialize xml parser state machine.
+**
+** Parameters p_xml_state: address of parser structure, allocate an additional space
+** of size XML_EVT_RPT_CARRY_OVER_LEN right after p_xml_state
+** to hold carry over data.
+** p_entry : points start of output directory entry. caller needs do free this memory
+** max_entry : max is 16 bit integer value which is the maximum number of folder entries.
+
+**
+** Returns void
+**************************************************************************************/
+MCE_API void XML_EvtRptInit( tXML_EVT_RPT_PARSER *p_xml_state,
+ tXML_EVT_RPT_ENTRY *p_entry,
+ const UINT16 max_entry );
+
+
+/**************************************************************************************
+** Function XML_EvtRptParse
+**
+** Description This function is called to parse the xml data received from OBEX
+** into folder entries associated with properties value. It can also be
+** used as clean up function to delete left over data from previous parse.
+** This clean up function is typically used when application runs out of
+** resource and decides to discard extra xml data received.
+**
+** Parameters p_xml_state: pointer to a xml parser initialized by XML_FolderInit().
+** xml_data: valid pointer to OBEX list data in xml format.
+** xml_len: length of the package, must be non-zero value.
+** dst_data: valid pointer to the buffer for holding converted folder entry name.
+** When dst_data is NULL, clean up all remaining data in the parser.
+** dst_len: length of the dst_data buffer, its carry out value is the number
+** of bytes of available buffer remains.
+** num_entries: current number of entries, in the end it is the total number of entries
+**
+** Returns tXML_EVT_RPT_RES (see xml_flp.h)
+** XML_PENDING: parsing not completed
+** XML_END_LIST: found /folder-listing but no final flag detected
+** XML_EVT_RPT_OUT_FULL: reached max_entry -> do not call parser anymore!!! dump data
+** XML_EVT_RPT_DST_NO_RES : run out of dst buffer resource while
+** some xml data still remains.
+
+**************************************************************************************/
+MCE_API extern tXML_EVT_RPT_RES XML_EvtRptParse( tXML_EVT_RPT_PARSER *p_xml_state,
+ UINT8 *xml_data, UINT16 xml_len,
+ UINT8 *dst_data, UINT16 *dst_len,
+ UINT16 *num_entries );
+
+
+#endif
diff --git a/stack/include/xml_flp_api.h b/stack/include/xml_flp_api.h
new file mode 100644
index 0000000..fddb839
--- /dev/null
+++ b/stack/include/xml_flp_api.h
@@ -0,0 +1,162 @@
+/******************************************************************************
+ **
+ ** Name: xml_flp.h
+ ** $Id: xml_flp.h,v 1.2 2004/11/15 14:07:47 rlenden Exp
+ **
+ ** Description: This module contains xml parser of obex folder listing
+ **
+ ** Copyright (c) 2004-2005, Broadcom Corporation, All Rights Reserved.
+ ** WIDCOMM Bluetooth Core. Proprietary and confidential.
+ ******************************************************************************/
+
+#ifndef XML_FLP_H
+#define XML_FLP_H
+
+#include "bt_target.h"
+#include "gki.h"
+#include "xml_pars_api.h"
+
+/**********************************************************************************/
+#ifndef XML_OBX_FOLDER
+#define XML_OBX_FOLDER 0
+#endif
+#ifndef XML_OBX_FILE
+#define XML_OBX_FILE 1
+#endif
+
+#define XML_PERM_READ_B 0x01
+#define XML_PERM_WRITE_B 0x02
+#define XML_PERM_DELETE_B 0x04
+
+typedef UINT8 XML_PERM_MASK ;
+
+#ifndef XML_OBX_FILE_MAX
+#define XML_OBX_FILE_MAX 100
+#endif
+
+#ifndef XML_FOLDER_CARRY_OVER_LEN
+#define XML_FOLDER_CARRY_OVER_LEN 512 /* number of bytes we can store in case we did not yet find the > */
+#endif
+
+
+#ifndef XML_PARENT_FOLDER
+#define XML_PARENT_FOLDER ".." /* <parent-folder/> is represented as .. */
+#endif
+
+
+typedef struct
+{
+
+ UINT8 *data;
+ UINT32 size; /* size of file or folder in bytes */
+ UINT16 len;
+ UINT8 type;
+ XML_PERM_MASK user_perm;
+} tXML_FOLDER_ENTRY;
+
+/**********************************************************************************/
+
+typedef enum
+{
+ XML_FOLDER_OK, /* parsing is ok, operation is ok */
+ XML_FOLDER_PENDING, /* parsing is ok but not enough data */
+ XML_FOLDER_END_LIST, /* found </folder-listing> */
+ XML_FOLDER_OUT_FULL, /* output buffer full /folder-listing not reached! data is dumped */
+ XML_FOLDER_ERROR, /* some parsing error occured */
+ XML_FOLDER_NO_RES, /* ran out of resources (memory) */
+ XML_FOLDER_DST_NO_RES /* ran out of destination data buffer */
+} txml_folder_res;
+typedef UINT8 tXML_FOLDER_RES;
+
+
+typedef struct
+{
+ tXML_FOLDER_ENTRY *p_entry;
+ tXML_PROP *p_prop;
+
+ tXML_PROP *offset_prop; /* current filling property */
+ UINT16 prop_num; /* number of properties left to be filled in */
+
+ INT16 current_entry;
+ INT16 max_name_len; /* maximum length of name length of entry
+ XML parser limits to 196 bytes i think. */
+ UINT16 max_entry;
+ BOOLEAN ended;
+ UINT16 prop_index;
+ UINT16 max_num_prop;
+ UINT8 obj; /* the XML object - (tFTC_XML_OBJ + 1)*/
+} tXML_FOLDER_STATE;
+
+typedef struct
+{
+ tXML_MUL_STATE xml;
+ tXML_FOLDER_STATE xml_user_data;
+} tXML_FOLDER_PARSER;
+
+/* only this value is of significance, if not ok frame is dropped by parser */
+#define XML_FOLDER_ENTRY_OK 0
+
+typedef UINT8 tXML_FOLDER_STATUS;
+
+
+typedef struct
+{
+ UINT8 *data;
+ UINT16 len;
+ BOOLEAN final; /* If TRUE, entry is last of the series */
+ tXML_FOLDER_STATUS status; /* Fields are valid when status is BTA_FTC_OK */
+} tXML_FOLDER_LIST; /* clone of tBTA_FTC_LIST */
+
+
+/**************************************************************************************
+** Function XML_FolderInit
+**
+** Description Initialize xml parser state machine.
+**
+** Parameters p_xml_state: address of parser structure, allocate an additional space
+** of size XML_FOLDER_CARRY_OVER_LEN right after p_xml_state
+** to hold carry over data.
+** p_entry : points start of output directory entry. caller needs do free this memory
+** max_entry : max is 16 bit integer value which is the maximum number of folder entries.
+
+**
+** Returns void
+**************************************************************************************/
+FTP_API void XML_FolderInit( tXML_FOLDER_PARSER *p_xml_state,
+ tXML_FOLDER_ENTRY *p_entry,
+ const UINT16 max_entry );
+
+
+/**************************************************************************************
+** Function XML_FolderParse
+**
+** Description This function is called to parse the xml data received from OBEX
+** into folder entries associated with properties value. It can also be
+** used as clean up function to delete left over data from previous parse.
+** This clean up function is typically used when application runs out of
+** resource and decides to discard extra xml data received.
+**
+** Parameters p_xml_state: pointer to a xml parser initialized by XML_FolderInit().
+** xml_data: valid pointer to OBEX list data in xml format.
+** xml_len: length of the package, must be non-zero value.
+** dst_data: valid pointer to the buffer for holding converted folder entry name.
+** When dst_data is NULL, clean up all remaining data in the parser.
+** dst_len: length of the dst_data buffer, its carry out value is the number
+** of bytes of available buffer remains.
+** num_entries: current number of entries, in the end it is the total number of entries
+**
+** Returns tXML_FOLDER_RES (see xml_flp.h)
+** XML_PENDING: parsing not completed
+** XML_END_LIST: found /folder-listing but no final flag detected
+** XML_FOLDER_OUT_FULL: reached max_entry -> do not call parser anymore!!! dump data
+** XML_FOLDER_DST_NO_RES : run out of dst buffer resource while
+** some xml data still remains.
+
+**************************************************************************************/
+FTP_API extern tXML_FOLDER_RES XML_FolderParse( tXML_FOLDER_PARSER *p_xml_state,
+ UINT8 *xml_data, UINT16 xml_len,
+ UINT8 *dst_data, UINT16 *dst_len,
+ UINT16 *num_entries );
+
+
+#endif
diff --git a/stack/include/xml_mlp_api.h b/stack/include/xml_mlp_api.h
new file mode 100644
index 0000000..eabbfbd
--- /dev/null
+++ b/stack/include/xml_mlp_api.h
@@ -0,0 +1,169 @@
+/******************************************************************************
+ **
+ ** Name: xml_mlp_api.h
+ ** $Id:
+ **
+ ** Description: This module contains xml parser of MAP message list object
+ **
+ ** Copyright (c) 2004-2005, Broadcom Corporation, All Rights Reserved.
+ ** WIDCOMM Bluetooth Core. Proprietary and confidential.
+ ******************************************************************************/
+
+#ifndef XML_MLP_API_H
+#define XML_MLP_API_H
+
+#include "bt_target.h"
+#include "gki.h"
+#include "xml_pars_api.h"
+
+
+#ifndef XML_ML_CARRY_OVER_LEN
+#define XML_ML_CARRY_OVER_LEN 512 /* number of bytes we can store in case we did not yet find the > */
+#endif
+
+/**********************************************************************************/
+
+typedef struct
+{
+ UINT16 msg_handle_len;
+ UINT16 subject_len;
+ UINT16 datetime_len;
+ UINT16 sender_name_len;
+ UINT16 sender_addressing_len;
+ UINT16 replyto_addressing_len;
+ UINT16 recipient_name_len;
+ UINT16 recipient_addressing_len;
+ UINT16 type_len;
+ UINT16 org_msg_size_len;
+ UINT16 text_len;
+ UINT16 reception_status_len;
+ UINT16 attachment_size_len;
+ UINT16 priority_status_len;
+ UINT16 read_len;
+ UINT16 sent_len;
+ UINT16 is_protected_len;
+ UINT8 *msg_handle;
+ UINT8 *subject;
+ UINT8 *datetime;
+ UINT8 *sender_name;
+ UINT8 *sender_addressing;
+ UINT8 *replyto_addressing;
+ UINT8 *recipient_name;
+ UINT8 *recipient_addressing;
+ UINT8 *type;
+ UINT8 *org_msg_size;
+ UINT8 *text;
+ UINT8 *reception_status;
+ UINT8 *attachment_size;
+ UINT8 *priority_status;
+ UINT8 *read;
+ UINT8 *sent;
+ UINT8 *is_protected;
+} tXML_ML_ENTRY;
+
+/**********************************************************************************/
+
+enum
+{
+ XML_ML_OK, /* parsing is ok, operation is ok */
+ XML_ML_PENDING, /* parsing is ok but not enough data */
+ XML_ML_END_LIST, /* found </MAP-msg-listing> */
+ XML_ML_OUT_FULL, /* output buffer full /MAP-msg-listing not reached! data is dumped */
+ XML_ML_ERROR, /* some parsing error occured */
+ XML_ML_NO_RES, /* ran out of resources (memory) */
+ XML_ML_DST_NO_RES /* ran out of destination data buffer */
+};
+typedef UINT8 tXML_ML_RES;
+
+
+typedef struct
+{
+ tXML_ML_ENTRY *p_entry; /* point to parser_cb->mlist.evt_rpt */
+ tXML_PROP *p_prop; /* GKI_BUF3_SIZE */
+
+ tXML_PROP *offset_prop; /* current filling property */
+ UINT16 prop_num; /* number of properties left to be filled in */
+
+ INT16 current_entry;
+ INT16 max_name_len; /* maximum length of name length of entry
+ XML parser limits to 196 bytes i think. */
+ UINT16 max_entry;
+ BOOLEAN ended;
+ UINT16 prop_index;
+ UINT16 max_num_prop;
+ UINT8 obj; /* the XML object - (tFTC_XML_OBJ + 1)*/
+} tXML_ML_STATE;
+
+typedef struct
+{
+ tXML_MUL_STATE xml;
+ tXML_ML_STATE xml_user_data;
+} tXML_ML_PARSER;
+
+/* only this value is of significance, if not ok frame is dropped by parser */
+#define XML_ML_ENTRY_OK 0
+
+typedef UINT8 tXML_ML_STATUS;
+
+
+typedef struct
+{
+ UINT8 *data;
+ UINT16 len;
+ BOOLEAN final; /* If TRUE, entry is last of the series */
+ tXML_ML_STATUS status; /* Fields are valid when status is BTA_FTC_OK */
+} tXML_ML_LIST; /* clone of tBTA_FTC_LIST */
+
+
+/**************************************************************************************
+** Function XML_MlInit
+**
+** Description Initialize xml parser state machine.
+**
+** Parameters p_xml_state: address of parser structure, allocate an additional space
+** of size XML_ML_CARRY_OVER_LEN right after p_xml_state
+** to hold carry over data.
+** p_entry : points start of output directory entry. caller needs do free this memory
+** max_entry : max is 16 bit integer value which is the maximum number of folder entries.
+
+**
+** Returns void
+**************************************************************************************/
+MCE_API void XML_MlInit( tXML_ML_PARSER *p_xml_state,
+ tXML_ML_ENTRY *p_entry,
+ const UINT16 max_entry );
+
+
+/**************************************************************************************
+** Function XML_MLParse
+**
+** Description This function is called to parse the xml data received from OBEX
+** into folder entries associated with properties value. It can also be
+** used as clean up function to delete left over data from previous parse.
+** This clean up function is typically used when application runs out of
+** resource and decides to discard extra xml data received.
+**
+** Parameters p_xml_state: pointer to a xml parser initialized by XML_FolderInit().
+** xml_data: valid pointer to OBEX list data in xml format.
+** xml_len: length of the package, must be non-zero value.
+** dst_data: valid pointer to the buffer for holding converted folder entry name.
+** When dst_data is NULL, clean up all remaining data in the parser.
+** dst_len: length of the dst_data buffer, its carry out value is the number
+** of bytes of available buffer remains.
+** num_entries: current number of entries, in the end it is the total number of entries
+**
+** Returns tXML_ML_RES (see xml_flp.h)
+** XML_PENDING: parsing not completed
+** XML_END_LIST: found /folder-listing but no final flag detected
+** XML_ML_OUT_FULL: reached max_entry -> do not call parser anymore!!! dump data
+** XML_ML_DST_NO_RES : run out of dst buffer resource while
+** some xml data still remains.
+
+**************************************************************************************/
+MCE_API extern tXML_ML_RES XML_MlParse( tXML_ML_PARSER *p_xml_state,
+ UINT8 *xml_data, UINT16 xml_len,
+ UINT8 *dst_data, UINT16 *dst_len,
+ UINT16 *num_entries );
+
+
+#endif
diff --git a/stack/include/xml_pars_api.h b/stack/include/xml_pars_api.h
new file mode 100644
index 0000000..d29645a
--- /dev/null
+++ b/stack/include/xml_pars_api.h
@@ -0,0 +1,358 @@
+/*****************************************************************************
+**
+** Name: xml_pars_api.h
+**
+** File: XML Parser
+**
+** Copyright (c) 2000-2004, WIDCOMM Inc., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef XML_PARS_API_H
+#define XML_PARS_API_H
+
+#include "data_types.h"
+
+#define XML_STACK_SIZE 7
+
+#ifndef XML_UI_ENTRY_MAX_NAME_LEN
+#define XML_UI_ENTRY_MAX_NAME_LEN 256
+#endif
+
+/*****************************************************************************
+** Type Definitions
+*****************************************************************************/
+
+/* Definition of XML events */
+enum
+{
+ XML_XMLDECL,
+ XML_TAG, /* 1 For STag (Start Tag) and EmptyElemTag */
+ XML_TAG_END, /* 2 When STag or EmptyElemTag ends */
+ XML_ATTRIBUTE, /* 3 */
+ XML_CHARDATA, /* 4 */
+ XML_ETAG, /* 5 For End Tag */
+ XML_PARTIAL, /* 6 notify XML user that the parse does not end properly */
+ XML_COPY, /* 7 notify XML user to copy till end of a token */
+ XML_QUERY, /* 8 query if the XML object has ended */
+ XML_TOP /* 9 */
+};
+typedef UINT16 tXML_EVENT;
+#define XML_LAST_XE XML_ETAG
+
+enum
+{
+ XML_SUCCESS,
+ XML_WARNING,
+ XML_OBJ_ST_EMPTY,
+ XML_NO_MEM, /* no p_last_bfr, and the tXML_MUL_STATE is not in init */
+ XML_NO_PROP, /* run out of tXML_PROP */
+ XML_ERR, /* generic error */
+ XML_NO_END /* to be continued */
+};
+typedef UINT16 tXML_RESULT;
+
+/* Definitions of different event data */
+typedef struct
+{
+ UINT8 *p_version;
+ UINT8 *p_enc_name;
+ BOOLEAN *p_standalone; /* NULL if no standalone decl was found */
+} tXML_DECL;
+
+
+
+/* for parser that expand multi-sessions */
+/* tag stack */
+typedef struct
+{
+ UINT8 stack[XML_STACK_SIZE];
+ UINT8 top;
+ tXML_EVENT event; /* last XML event */
+} tXML_STACK;
+
+typedef struct
+{
+ UINT8 *p;
+ UINT16 len;
+} tXML_STR;
+
+typedef struct
+{
+ tXML_STACK stack;
+ tXML_STR prefix;
+ tXML_STR name;
+ UINT8 *p_last_stm;
+} tXML_MTAG;
+
+typedef struct
+{
+ tXML_STACK stack;
+ BOOLEAN end; /* true if end of EmptyElemTag */
+ /* false if end of STag */
+} tXML_MTAG_END;
+
+
+
+typedef struct
+{
+ tXML_STACK stack;
+ tXML_STR prefix;
+ tXML_STR name;
+ tXML_STR value;
+} tXML_MATTR;
+
+
+/* There may be several XML_CHARDATA events dispatched for one CHARDATA
+** string in the XML document. In each XML_CHARDATA only a segment of the
+** total string is provided. For the last segement the field last is true.
+*/
+typedef struct
+{
+ tXML_STACK stack;
+ tXML_STR value;
+ BOOLEAN last;
+} tXML_MCH_DATA;
+
+
+typedef struct
+{
+ tXML_STACK stack;
+ tXML_STR prefix;
+ tXML_STR name;
+} tXML_METAG;
+
+typedef struct
+{
+ tXML_STACK stack;
+ UINT8 *p_begin;
+ tXML_STR last;
+} tXML_MCOPY;
+
+typedef struct
+{
+ tXML_STACK stack;
+ tXML_RESULT parse;
+ UINT8 *p_keep;
+} tXML_MPART;
+
+typedef union
+{
+ tXML_STACK stack;
+ tXML_DECL decl;
+ tXML_MTAG tag;
+ tXML_MTAG_END empty_elem;
+ tXML_MATTR attr;
+ tXML_MCH_DATA ch_data;
+ tXML_METAG etag;
+ tXML_MCOPY copy;
+ tXML_MPART part;
+} tXML_MEVT_DATA;
+
+typedef struct
+{
+ UINT8 *p_data; /* Pointer to property data. */
+ UINT16 len; /* Length of data. */
+ UINT8 prefix; /* Property prefix. */
+ UINT8 name; /* Property name. */
+ UINT8 level; /* 0 as top level */
+} tXML_PROP;
+
+/* Definitions of different error actions.
+** At present there is only one.
+*/
+enum
+{
+ XML_NEXT_TAG /* tries to find beginning of next tag */
+};
+typedef UINT16 tXML_ERR_ACTION;
+
+
+
+enum
+{
+ XML_STS_INIT,
+ XML_STS_1STM, /* got the first < */
+ XML_STS_1TAG, /* got the first tag element */
+ XML_STS_DONE
+};
+typedef UINT8 tXML_STATUS;
+
+typedef struct
+{
+ UINT8 *p_hdr; /* the beginning of GKI buffer */
+ UINT8 *p_begin;/* the beginning of XML data */
+ UINT8 *p_end; /* the end of XML data */
+} tXML_OS;
+
+
+/*****************************************************************************
+**
+** Callback tXML_CBACK
+**
+** Description
+** Called repeatedly from the XML parser for each XML construct parsed.
+** The parsed XML construct is reported as an XML event in the event
+** in-parameter. The parser provides event data specific for each event
+** in the callback through the p_event_data param which should be casted
+** to the proper type by the user implemented tXML_CBACK function.
+** The p_event_data should be casted to a pointer of a type with the same
+** name as the event but prefixed with t. For example when the event is
+** XML_TAG, p_event_data should be casted to tXML_TAG*. Alternatively,
+** p_event_data can be casted to a tEVENT_DATA* (pointer to union) type
+** for all events. The memory behind the p_event_data is provided by the
+** parser and is only valid during the callback, i.e. the memory is not
+** valid after the callback. No pointer inside the event structures may
+** be NULL unless explicitly stated so above for some specific event.
+** The p_usr_data parameter is the same p_usr_data pointer the
+** API user passed in the XML_Parse. It is only declared as a mean for
+** the API user to pass any user data to its callback function.
+**
+**
+** Parameters
+** event (in) : the XML event or XML contruct just parsed,
+** p_event_data (in) : data, i.e. names values etc, found in the XML
+** construct. The data is specific for the XML
+** construct and should be casted to the
+** proper type as descibed above. May not be NULL.
+** p_usr_data (in) : Same p_usr_data as passed in XML_Parse.
+**
+** Returns
+** TRUE : if parsing should continue
+** FALSE : if parsing should stop
+**
+*****************************************************************************/
+
+typedef BOOLEAN (*tXML_CBACK)(tXML_EVENT event, void *p_event_data,
+ void *p_usr_data);
+
+typedef struct
+{
+
+ UINT8 p[512];
+ UINT16 len;
+} tXML_STR_PARTIAL;
+
+typedef struct
+{
+ tXML_STR_PARTIAL last_bfr;
+ UINT16 used_last_bfr;
+ tXML_MEVT_DATA event_data;
+}
+tXML_PARTIAL;
+
+/* tXML_STATE stores state during the XML_Parse call not between
+** XML_Parse calls. It is used in most static functions in this file
+** and passed in as first parameter to these.
+*/
+typedef struct
+{
+ /* input from XML_Parse caller */
+ tXML_OS xml_os;
+ UINT8 *p_cur;
+ tXML_CBACK cback;
+ void *p_usr_data;
+ tXML_MEVT_DATA event_data;
+
+ /* handling of data buffers for prefix, name and value */
+ UINT8 *p_data_bfr;
+ UINT8 *p_last_stm; /* last '<' */
+ UINT8 *p_copy;
+ tXML_STR last_bfr;
+ tXML_STR value;
+ tXML_STR prefix;
+ tXML_STR name;
+
+ /* token and result handling */
+ INT16 curr_res;
+ tXML_RESULT pars_res;
+ UINT8 next_token;
+ BOOLEAN skip_next_nl;
+
+ UINT16 used_last_bfr; /* the actual data size in p_last_bfr */
+ tXML_STATUS status;
+
+ /* structure used to store partial data */
+ tXML_PARTIAL partial_st;
+} tXML_MUL_STATE;
+
+/*****************************************************************************
+** External Function Declarations
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*****************************************************************************
+**
+** Function XML_Parse
+**
+** Description
+** Parses an XML message/document in utf8. The message is read from
+** an object store which must have been initialised and an object
+** (file) must have been opened so the parser can start directly with
+** reading the first byte using the GOEP_Read function and passing
+** the h_obj_store in-param.
+** The parser will call the xml_cback callback for each basic
+** XML-construct parsed. If the parser encounters an error it will
+** try to act according to the err_action in-param and report any
+** errors through the err_handle. The parser is non-validating.
+**
+** Parameters
+** h_obj_store (in) : a handle to an opened object (file) in
+** the Object Store. The object must be
+** ready for reading.
+** xml_cback (in) : the user provided function to call back
+** for each XML-construct (XML event) parsed.
+** err_action (in) : the action the parser will try if it finds
+** an error.
+** err_handle (in) : a handle to some error recording object to
+** which the parser may report errors. This is
+** a place holder to connect any type of error
+** recording object.
+** p_usr_data (in) : any user data that will be passed on
+** unchanged to the callback function.
+**
+** Returns
+** 0 if the parsing was successfull without errors
+** non-zero error or warning code otherwise
+**
+*****************************************************************************/
+
+tXML_RESULT XML_Parse(tXML_OS *p_os, tXML_CBACK xml_cback,
+ tXML_ERR_ACTION err_action, UINT32 err_handle,
+ void *p_usr_data);
+
+/*****************************************************************************
+**
+** Function XML_MulParse
+**
+** Description Initialize XML parser state machine.
+**
+** Parameters
+** p_st (in) : xml state machine.
+** p_os (in) : xml data storage
+**
+*****************************************************************************/
+tXML_RESULT XML_MulParse(tXML_MUL_STATE *p_st, tXML_OS *p_os);
+
+/*****************************************************************************
+**
+** Function XML_InitPars
+**
+** Description Initialize XML parser state machine.
+**
+** Parameters
+** p_st (in) : xml state machine.
+** xml_cback (in) : the user provided function to call back
+** p_usr_data : user defined data.
+**
+*****************************************************************************/
+void XML_InitPars(tXML_MUL_STATE *p_st, tXML_CBACK xml_cback, void *p_usr_data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ifndef XML_PARS_API_H */
diff --git a/stack/include/xml_vlist_api.h b/stack/include/xml_vlist_api.h
new file mode 100644
index 0000000..362432a
--- /dev/null
+++ b/stack/include/xml_vlist_api.h
@@ -0,0 +1,136 @@
+/******************************************************************************
+ **
+ ** Name: xml_vlist_api.h
+ **
+ ** Description: This module contains xml parser of obex vcard listing
+ **
+ ** Copyright (c) 2004-2005, Broadcom Corporation, All Rights Reserved.
+ ** WIDCOMM Bluetooth Core. Proprietary and confidential.
+ ******************************************************************************/
+
+#ifndef XML_VLIST_API_H
+#define XML_VLIST_API_H
+
+#include "bt_target.h"
+#include "gki.h"
+#include "xml_pars_api.h"
+
+/**********************************************************************************/
+#ifndef XML_VLIST_CARRY_OVER_LEN
+#define XML_VLIST_CARRY_OVER_LEN 512 /* number of bytes we can store in case we did not yet find the > */
+#endif
+
+typedef struct
+{
+ UINT16 handle_len;
+ UINT8 *handle;
+ UINT16 name_len;
+ UINT8 *name;
+} tXML_VLIST_ENTRY;
+
+/**********************************************************************************/
+
+typedef enum
+{
+ XML_VLIST_OK, /* parsing is ok, operation is ok */
+ XML_VLIST_PENDING, /* parsing is ok but not enough data */
+ XML_VLIST_END_LIST, /* found </vCard-listing> */
+ XML_VLIST_OUT_FULL, /* output buffer full /vCard-listing not reached! data is dumped */
+ XML_VLIST_ERROR, /* some parsing error occured */
+ XML_VLIST_NO_RES, /* ran out of resources (memory) */
+ XML_VLIST_DST_NO_RES /* ran out of destination data buffer */
+} txml_vlist_res;
+typedef UINT8 tXML_VLIST_RES;
+
+
+typedef struct
+{
+ tXML_VLIST_ENTRY *p_entry;
+ tXML_PROP *p_prop;
+
+ tXML_PROP *offset_prop; /* current filling property */
+ UINT16 prop_num; /* number of properties left to be filled in */
+
+ INT16 current_entry;
+ INT16 max_name_len; /* maximum length of name length of entry
+ XML parser limits to 64 bytes i think. */
+ UINT16 max_entry;
+ BOOLEAN ended;
+ UINT16 prop_index;
+ UINT16 max_num_prop;
+ UINT8 obj; /* the XML object */
+} tXML_VLIST_STATE;
+
+typedef struct
+{
+ tXML_MUL_STATE xml;
+ tXML_VLIST_STATE xml_user_data;
+} tXML_VLIST_PARSER;
+
+/* only this value is of significance, if not ok frame is dropped by parser */
+#define XML_VLIST_ENTRY_OK 0
+
+typedef UINT8 tXML_VLIST_STATUS;
+
+
+typedef struct
+{
+ UINT8 *data;
+ UINT16 len;
+ BOOLEAN final; /* If TRUE, entry is last of the series */
+ tXML_VLIST_STATUS status; /* Fields are valid when status is BTA_FTC_OK */
+} tXML_VLIST_LIST; /* clone of tBTA_FTC_LIST */
+
+
+/**************************************************************************************
+** Function XML_VlistInit
+**
+** Description Initialize xml parser state machine.
+**
+** Parameters p_xml_state: address of parser structure, allocate an additional space
+** of size XML_VLIST_CARRY_OVER_LEN right after p_xml_state
+** to hold carry over data.
+** p_entry : points start of output vlist entry. caller needs do free this memory
+** max_entry : max is 16 bit integer value which is the maximum number of vlist entries.
+
+**
+** Returns void
+**************************************************************************************/
+BT_API void XML_VlistInit(tXML_VLIST_PARSER *p_xml_state,
+ tXML_VLIST_ENTRY *p_entry,
+ const UINT16 max_entry );
+
+
+/**************************************************************************************
+** Function XML_VlistParse
+**
+** Description This function is called to parse the xml data received from OBEX
+** into vlist entries associated with properties value. It can also be
+** used as clean up function to delete left over data from previous parse.
+** This clean up function is typically used when application runs out of
+** resource and decides to discard extra xml data received.
+**
+** Parameters p_xml_state: pointer to a xml parser initialized by XML_VlistInit().
+** xml_data: valid pointer to OBEX list data in xml format.
+** xml_len: length of the package, must be non-zero value.
+** dst_data: valid pointer to the buffer for holding converted vlist entry name and handle.
+** When dst_data is NULL, clean up all remaining data in the parser.
+** dst_len: length of the dst_data buffer, its carry out value is the number
+** of bytes of available buffer remains.
+** num_entries: current number of entries, in the end it is the total number of entries
+**
+** Returns tXML_VLIST_RES (see xml_vlist_api.h)
+** XML_PENDING: parsing not completed
+** XML_END_LIST: found /vCard-listing but no final flag detected
+** XML_VLIST_OUT_FULL: reached max_entry -> do not call parser anymore!!! dump data
+** XML_VLIST_DST_NO_RES : run out of dst buffer resource while
+** some xml data still remains.
+
+**************************************************************************************/
+BT_API extern tXML_VLIST_RES XML_VlistParse( tXML_VLIST_PARSER *p_xml_state,
+ UINT8 *xml_data, UINT16 xml_len,
+ UINT8 *dst_data, UINT16 *dst_len,
+ UINT16 *num_entries );
+
+
+#endif
diff --git a/stack/l2cap/l2c_api.c b/stack/l2cap/l2c_api.c
new file mode 100644
index 0000000..476ded1
--- /dev/null
+++ b/stack/l2cap/l2c_api.c
@@ -0,0 +1,1800 @@
+/*****************************************************************************
+**
+** Name: l2c_api.c
+**
+** Description: This file contains the L2CAP API code
+**
+**
+**
+** Copyright (c) 1999-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "gki.h"
+#include "bt_types.h"
+#include "hcidefs.h"
+#include "hcimsgs.h"
+#include "l2cdefs.h"
+#include "l2c_int.h"
+#include "btu.h"
+#include "btm_api.h"
+
+/*******************************************************************************
+**
+** Function L2CA_Register
+**
+** Description Other layers call this function to register for L2CAP
+** services.
+**
+** Returns PSM to use or zero if error. Typically, the PSM returned
+** is the same as was passed in, but for an outgoing-only
+** connection to a dynamic PSM, a "virtual" PSM is returned
+** and should be used in the calls to L2CA_ConnectReq(),
+** L2CA_ErtmConnectReq() and L2CA_Deregister()
+**
+*******************************************************************************/
+UINT16 L2CA_Register (UINT16 psm, tL2CAP_APPL_INFO *p_cb_info)
+{
+ tL2C_RCB *p_rcb;
+ UINT16 vpsm = psm;
+
+ L2CAP_TRACE_API1 ("L2CAP - L2CA_Register() called for PSM: 0x%04x", psm);
+
+ /* Verify that the required callback info has been filled in
+ ** Note: Connection callbacks are required but not checked
+ ** for here because it is possible to be only a client
+ ** or only a server.
+ */
+ if ((!p_cb_info->pL2CA_ConfigCfm_Cb)
+ || (!p_cb_info->pL2CA_ConfigInd_Cb)
+ || (!p_cb_info->pL2CA_DataInd_Cb)
+ || (!p_cb_info->pL2CA_DisconnectInd_Cb))
+ {
+ L2CAP_TRACE_ERROR1 ("L2CAP - no cb registering PSM: 0x%04x", psm);
+ return (0);
+ }
+
+ /* Verify PSM is valid */
+ if (L2C_INVALID_PSM(psm))
+ {
+ L2CAP_TRACE_ERROR1 ("L2CAP - invalid PSM value, PSM: 0x%04x", psm);
+ return (0);
+ }
+
+ /* Check if this is a registration for an outgoing-only connection to */
+ /* a dynamic PSM. If so, allocate a "virtual" PSM for the app to use. */
+ if ( (psm >= 0x1001) && (p_cb_info->pL2CA_ConnectInd_Cb == NULL) )
+ {
+ for (vpsm = 0x1002; vpsm < 0x8000; vpsm += 2)
+ {
+ if ((p_rcb = l2cu_find_rcb_by_psm (vpsm)) == NULL)
+ break;
+ }
+
+ L2CAP_TRACE_API2 ("L2CA_Register - Real PSM: 0x%04x Virtual PSM: 0x%04x", psm, vpsm);
+ }
+
+ /* If registration block already there, just overwrite it */
+ if ((p_rcb = l2cu_find_rcb_by_psm (vpsm)) == NULL)
+ {
+ if ((p_rcb = l2cu_allocate_rcb (vpsm)) == NULL)
+ {
+ L2CAP_TRACE_WARNING2 ("L2CAP - no RCB available, PSM: 0x%04x vPSM: 0x%04x", psm, vpsm);
+ return (0);
+ }
+ }
+
+ p_rcb->api = *p_cb_info;
+ p_rcb->real_psm = psm;
+
+ return (vpsm);
+}
+
+
+
+/*******************************************************************************
+**
+** Function L2CA_Deregister
+**
+** Description Other layers call this function to de-register for L2CAP
+** services.
+**
+** Returns void
+**
+*******************************************************************************/
+void L2CA_Deregister (UINT16 psm)
+{
+ tL2C_RCB *p_rcb;
+ tL2C_CCB *p_ccb;
+ tL2C_LCB *p_lcb;
+ int ii;
+
+ L2CAP_TRACE_API1 ("L2CAP - L2CA_Deregister() called for PSM: 0x%04x", psm);
+
+ if ((p_rcb = l2cu_find_rcb_by_psm (psm)) != NULL)
+ {
+ p_lcb = &l2cb.lcb_pool[0];
+ for (ii = 0; ii < MAX_L2CAP_LINKS; ii++, p_lcb++)
+ {
+ if (p_lcb->in_use)
+ {
+ if (((p_ccb = p_lcb->ccb_queue.p_first_ccb) == NULL)
+ || (p_lcb->link_state == LST_DISCONNECTING))
+ continue;
+
+ if ((p_ccb->in_use) &&
+ ((p_ccb->chnl_state == CST_W4_L2CAP_DISCONNECT_RSP) ||
+ (p_ccb->chnl_state == CST_W4_L2CA_DISCONNECT_RSP)))
+ continue;
+
+ if (p_ccb->p_rcb == p_rcb)
+ l2c_csm_execute (p_ccb, L2CEVT_L2CA_DISCONNECT_REQ, NULL);
+ }
+ }
+ l2cu_release_rcb (p_rcb);
+ }
+ else
+ {
+ L2CAP_TRACE_WARNING1 ("L2CAP - PSM: 0x%04x not found for deregistration", psm);
+ }
+}
+
+/*******************************************************************************
+**
+** Function L2CA_AllocatePSM
+**
+** Description Other layers call this function to find an unused PSM for L2CAP
+** services.
+**
+** Returns PSM to use.
+**
+*******************************************************************************/
+UINT16 L2CA_AllocatePSM(void)
+{
+ BOOLEAN done = FALSE;
+ UINT16 psm = l2cb.dyn_psm;
+
+ L2CAP_TRACE_API0( "L2CA_AllocatePSM");
+ while (!done)
+ {
+ psm += 2;
+ if (psm > 0xfeff)
+ {
+ psm = 0x1001;
+ }
+ else if (psm & 0x0100)
+ {
+ /* the upper byte must be even */
+ psm += 0x0100;
+ }
+
+ /* if psm is in range of reserved BRCM Aware features */
+ if ((BRCM_RESERVED_PSM_START <= psm)&&(psm <= BRCM_RESERVED_PSM_END))
+ continue;
+
+ /* make sure the newlly allocated psm is not used right now */
+ if ((l2cu_find_rcb_by_psm (psm)) == NULL)
+ done = TRUE;
+ }
+ l2cb.dyn_psm = psm;
+
+ return(psm);
+}
+
+/*******************************************************************************
+**
+** Function L2CA_ConnectReq
+**
+** Description Higher layers call this function to create an L2CAP connection.
+** Note that the connection is not established at this time, but
+** connection establishment gets started. The callback function
+** will be invoked when connection establishes or fails.
+**
+** Returns the CID of the connection, or 0 if it failed to start
+**
+*******************************************************************************/
+UINT16 L2CA_ConnectReq (UINT16 psm, BD_ADDR p_bd_addr)
+{
+ return L2CA_ErtmConnectReq (psm, p_bd_addr, NULL);
+}
+
+/*******************************************************************************
+**
+** Function L2CA_ErtmConnectReq
+**
+** Description Higher layers call this function to create an L2CAP connection.
+** Note that the connection is not established at this time, but
+** connection establishment gets started. The callback function
+** will be invoked when connection establishes or fails.
+**
+** Returns the CID of the connection, or 0 if it failed to start
+**
+*******************************************************************************/
+UINT16 L2CA_ErtmConnectReq (UINT16 psm, BD_ADDR p_bd_addr, tL2CAP_ERTM_INFO *p_ertm_info)
+{
+ tL2C_LCB *p_lcb;
+ tL2C_CCB *p_ccb;
+ tL2C_RCB *p_rcb;
+
+ L2CAP_TRACE_API6 ("L2CA_ErtmConnectReq() PSM: 0x%04x BDA: %08x%04x p_ertm_info: 0x%08x allowed:0x%x preferred:%d", psm,
+ (p_bd_addr[0]<<24)+(p_bd_addr[1]<<16)+(p_bd_addr[2]<<8)+p_bd_addr[3],
+ (p_bd_addr[4]<<8)+p_bd_addr[5], p_ertm_info,
+ (p_ertm_info) ? p_ertm_info->allowed_modes : 0, (p_ertm_info) ? p_ertm_info->preferred_mode : 0);
+
+ /* Fail if we have not established communications with the controller */
+ if (!BTM_IsDeviceUp())
+ {
+ L2CAP_TRACE_WARNING0 ("L2CAP connect req - BTU not ready");
+ return (0);
+ }
+ /* Fail if the PSM is not registered */
+ if ((p_rcb = l2cu_find_rcb_by_psm (psm)) == NULL)
+ {
+ L2CAP_TRACE_WARNING1 ("L2CAP - no RCB for L2CA_conn_req, PSM: 0x%04x", psm);
+ return (0);
+ }
+
+ /* First, see if we already have a link to the remote */
+ if ((p_lcb = l2cu_find_lcb_by_bd_addr (p_bd_addr)) == NULL)
+ {
+ /* No link. Get an LCB and start link establishment */
+ if ( ((p_lcb = l2cu_allocate_lcb (p_bd_addr, FALSE)) == NULL)
+ || (l2cu_create_conn(p_lcb) == FALSE) )
+ {
+ L2CAP_TRACE_WARNING2 ("L2CAP - conn not started for PSM: 0x%04x p_lcb: 0x%08x", psm, p_lcb);
+ return (0);
+ }
+ }
+
+ /* Allocate a channel control block */
+ if ((p_ccb = l2cu_allocate_ccb (p_lcb, 0)) == NULL)
+ {
+ L2CAP_TRACE_WARNING1 ("L2CAP - no CCB for L2CA_conn_req, PSM: 0x%04x", psm);
+ return (0);
+ }
+
+ /* Save registration info */
+ p_ccb->p_rcb = p_rcb;
+
+ if (p_ertm_info)
+ {
+ p_ccb->ertm_info = *p_ertm_info;
+
+ /* Replace default indicators with the actual default pool */
+ if (p_ccb->ertm_info.fcr_rx_pool_id == L2CAP_DEFAULT_ERM_POOL_ID)
+ p_ccb->ertm_info.fcr_rx_pool_id = L2CAP_FCR_RX_POOL_ID;
+
+ if (p_ccb->ertm_info.fcr_tx_pool_id == L2CAP_DEFAULT_ERM_POOL_ID)
+ p_ccb->ertm_info.fcr_tx_pool_id = L2CAP_FCR_TX_POOL_ID;
+
+ if (p_ccb->ertm_info.user_rx_pool_id == L2CAP_DEFAULT_ERM_POOL_ID)
+ p_ccb->ertm_info.user_rx_pool_id = HCI_ACL_POOL_ID;
+
+ if (p_ccb->ertm_info.user_tx_pool_id == L2CAP_DEFAULT_ERM_POOL_ID)
+ p_ccb->ertm_info.user_tx_pool_id = HCI_ACL_POOL_ID;
+
+ p_ccb->max_rx_mtu = GKI_get_pool_bufsize (p_ertm_info->user_rx_pool_id) - (L2CAP_MIN_OFFSET + L2CAP_SDU_LEN_OFFSET + L2CAP_FCS_LEN);
+ }
+
+ /* If link is up, start the L2CAP connection */
+ if (p_lcb->link_state == LST_CONNECTED)
+ {
+ l2c_csm_execute (p_ccb, L2CEVT_L2CA_CONNECT_REQ, NULL);
+ }
+
+ /* If link is disconnecting, save link info to retry after disconnect
+ * Possible Race condition when a reconnect occurs
+ * on the channel during a disconnect of link. This
+ * ccb will be automatically retried after link disconnect
+ * arrives
+ */
+ else if (p_lcb->link_state == LST_DISCONNECTING)
+ {
+ L2CAP_TRACE_DEBUG0 ("L2CAP API - link disconnecting: RETRY LATER");
+
+ /* Save ccb so it can be started after disconnect is finished */
+ p_lcb->p_pending_ccb = p_ccb;
+ }
+
+ L2CAP_TRACE_API2 ("L2CAP - L2CA_conn_req(psm: 0x%04x) returned CID: 0x%04x", psm, p_ccb->local_cid);
+
+ /* Return the local CID as our handle */
+ return (p_ccb->local_cid);
+}
+
+
+/*******************************************************************************
+**
+** Function L2CA_ConnectRsp
+**
+** Description Higher layers call this function to accept an incoming
+** L2CAP connection, for which they had gotten an connect
+** indication callback.
+**
+** Returns TRUE for success, FALSE for failure
+**
+*******************************************************************************/
+BOOLEAN L2CA_ConnectRsp (BD_ADDR p_bd_addr, UINT8 id, UINT16 lcid, UINT16 result, UINT16 status)
+{
+ return L2CA_ErtmConnectRsp (p_bd_addr, id, lcid, result, status, NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function L2CA_ErtmConnectRsp
+**
+** Description Higher layers call this function to accept an incoming
+** L2CAP connection, for which they had gotten an connect
+** indication callback.
+**
+** Returns TRUE for success, FALSE for failure
+**
+*******************************************************************************/
+BOOLEAN L2CA_ErtmConnectRsp (BD_ADDR p_bd_addr, UINT8 id, UINT16 lcid, UINT16 result,
+ UINT16 status, tL2CAP_ERTM_INFO *p_ertm_info)
+{
+ tL2C_LCB *p_lcb;
+ tL2C_CCB *p_ccb;
+
+ L2CAP_TRACE_API6 ("L2CA_ErtmConnectRsp() CID: 0x%04x Result: %d Status: %d BDA: %08x%04x p_ertm_info:0x%08x",
+ lcid, result, status,
+ (p_bd_addr[0]<<24)+(p_bd_addr[1]<<16)+(p_bd_addr[2]<<8)+p_bd_addr[3],
+ (p_bd_addr[4]<<8)+p_bd_addr[5], p_ertm_info);
+
+ /* First, find the link control block */
+ if ((p_lcb = l2cu_find_lcb_by_bd_addr (p_bd_addr)) == NULL)
+ {
+ /* No link. Get an LCB and start link establishment */
+ L2CAP_TRACE_WARNING0 ("L2CAP - no LCB for L2CA_conn_rsp");
+ return (FALSE);
+ }
+
+ /* Now, find the channel control block */
+ if ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, lcid)) == NULL)
+ {
+ L2CAP_TRACE_WARNING0 ("L2CAP - no CCB for L2CA_conn_rsp");
+ return (FALSE);
+ }
+
+ /* The IDs must match */
+ if (p_ccb->remote_id != id)
+ {
+ L2CAP_TRACE_WARNING2 ("L2CAP - bad id in L2CA_conn_rsp. Exp: %d Got: %d", p_ccb->remote_id, id);
+ return (FALSE);
+ }
+
+ if (p_ertm_info)
+ {
+ p_ccb->ertm_info = *p_ertm_info;
+
+ /* Replace default indicators with the actual default pool */
+ if (p_ccb->ertm_info.fcr_rx_pool_id == L2CAP_DEFAULT_ERM_POOL_ID)
+ p_ccb->ertm_info.fcr_rx_pool_id = L2CAP_FCR_RX_POOL_ID;
+
+ if (p_ccb->ertm_info.fcr_tx_pool_id == L2CAP_DEFAULT_ERM_POOL_ID)
+ p_ccb->ertm_info.fcr_tx_pool_id = L2CAP_FCR_TX_POOL_ID;
+
+ if (p_ccb->ertm_info.user_rx_pool_id == L2CAP_DEFAULT_ERM_POOL_ID)
+ p_ccb->ertm_info.user_rx_pool_id = HCI_ACL_POOL_ID;
+
+ if (p_ccb->ertm_info.user_tx_pool_id == L2CAP_DEFAULT_ERM_POOL_ID)
+ p_ccb->ertm_info.user_tx_pool_id = HCI_ACL_POOL_ID;
+
+ p_ccb->max_rx_mtu = GKI_get_pool_bufsize (p_ertm_info->user_rx_pool_id) - (L2CAP_MIN_OFFSET + L2CAP_SDU_LEN_OFFSET + L2CAP_FCS_LEN);
+ }
+
+ if (result == L2CAP_CONN_OK)
+ {
+ l2c_csm_execute (p_ccb, L2CEVT_L2CA_CONNECT_RSP, NULL);
+ }
+ else
+ {
+ tL2C_CONN_INFO conn_info;
+
+ conn_info.l2cap_result = result;
+ conn_info.l2cap_status = status;
+
+ if (result == L2CAP_CONN_PENDING)
+ l2c_csm_execute (p_ccb, L2CEVT_L2CA_CONNECT_RSP, &conn_info);
+ else
+ l2c_csm_execute (p_ccb, L2CEVT_L2CA_CONNECT_RSP_NEG, &conn_info);
+ }
+
+ return (TRUE);
+}
+
+
+/*******************************************************************************
+**
+** Function L2CA_ConfigReq
+**
+** Description Higher layers call this function to send configuration.
+**
+** Note: The FCR options of p_cfg are not used.
+**
+** Returns TRUE if configuration sent, else FALSE
+**
+*******************************************************************************/
+BOOLEAN L2CA_ConfigReq (UINT16 cid, tL2CAP_CFG_INFO *p_cfg)
+{
+ tL2C_CCB *p_ccb;
+
+ L2CAP_TRACE_API5 ("L2CA_ConfigReq() CID 0x%04x: fcr_present:%d (mode %d) mtu_present:%d (%d)",
+ cid, p_cfg->fcr_present, p_cfg->fcr.mode, p_cfg->mtu_present, p_cfg->mtu);
+
+ /* Find the channel control block. We don't know the link it is on. */
+ if ((p_ccb = l2cu_find_ccb_by_cid (NULL, cid)) == NULL)
+ {
+ L2CAP_TRACE_WARNING1 ("L2CAP - no CCB for L2CA_cfg_req, CID: %d", cid);
+ return (FALSE);
+ }
+
+ /* We need to have at least one mode type common with the peer */
+ if (!l2c_fcr_adj_our_req_options(p_ccb, p_cfg))
+ return (FALSE);
+
+ /* Don't adjust FCR options if not used */
+ if ((!p_cfg->fcr_present)||(p_cfg->fcr.mode == L2CAP_FCR_BASIC_MODE))
+ {
+ /* FCR and FCS options are not used in basic mode */
+ p_cfg->fcs_present = FALSE;
+ p_cfg->ext_flow_spec_present = FALSE;
+
+ if ( (p_cfg->mtu_present) && (p_cfg->mtu > L2CAP_MTU_SIZE) )
+ {
+ L2CAP_TRACE_WARNING1 ("L2CAP - adjust MTU: %u too large", p_cfg->mtu);
+ p_cfg->mtu = L2CAP_MTU_SIZE;
+ }
+ }
+
+ /* Save the adjusted configuration in case it needs to be used for renegotiation */
+ p_ccb->our_cfg = *p_cfg;
+
+ l2c_csm_execute (p_ccb, L2CEVT_L2CA_CONFIG_REQ, p_cfg);
+
+ return (TRUE);
+}
+
+
+/*******************************************************************************
+**
+** Function L2CA_ConfigRsp
+**
+** Description Higher layers call this function to send a configuration
+** response.
+**
+** Returns TRUE if configuration response sent, else FALSE
+**
+*******************************************************************************/
+BOOLEAN L2CA_ConfigRsp (UINT16 cid, tL2CAP_CFG_INFO *p_cfg)
+{
+ tL2C_CCB *p_ccb;
+
+ L2CAP_TRACE_API6 ("L2CA_ConfigRsp() CID: 0x%04x Result: %d MTU present:%d Flush TO:%d FCR:%d FCS:%d",
+ cid, p_cfg->result, p_cfg->mtu_present, p_cfg->flush_to_present, p_cfg->fcr_present, p_cfg->fcs_present);
+
+ /* Find the channel control block. We don't know the link it is on. */
+ if ((p_ccb = l2cu_find_ccb_by_cid (NULL, cid)) == NULL)
+ {
+ L2CAP_TRACE_WARNING1 ("L2CAP - no CCB for L2CA_cfg_rsp, CID: %d", cid);
+ return (FALSE);
+ }
+
+ if ( (p_cfg->result == L2CAP_CFG_OK) || (p_cfg->result == L2CAP_CFG_PENDING) )
+ l2c_csm_execute (p_ccb, L2CEVT_L2CA_CONFIG_RSP, p_cfg);
+ else
+ {
+ p_cfg->fcr_present = FALSE; /* FCR options already negotiated before this point */
+
+ /* Clear out any cached options that are being returned as an error (excluding FCR) */
+ if (p_cfg->mtu_present)
+ p_ccb->peer_cfg.mtu_present = FALSE;
+ if (p_cfg->flush_to_present)
+ p_ccb->peer_cfg.flush_to_present = FALSE;
+ if (p_cfg->qos_present)
+ p_ccb->peer_cfg.qos_present = FALSE;
+
+ l2c_csm_execute (p_ccb, L2CEVT_L2CA_CONFIG_RSP_NEG, p_cfg);
+ }
+
+ return (TRUE);
+}
+
+
+/*******************************************************************************
+**
+** Function L2CA_DisconnectReq
+**
+** Description Higher layers call this function to disconnect a channel.
+**
+** Returns TRUE if disconnect sent, else FALSE
+**
+*******************************************************************************/
+BOOLEAN L2CA_DisconnectReq (UINT16 cid)
+{
+ tL2C_CCB *p_ccb;
+
+ L2CAP_TRACE_API1 ("L2CA_DisconnectReq() CID: 0x%04x", cid);
+
+ /* Find the channel control block. We don't know the link it is on. */
+ if ((p_ccb = l2cu_find_ccb_by_cid (NULL, cid)) == NULL)
+ {
+ L2CAP_TRACE_WARNING1 ("L2CAP - no CCB for L2CA_disc_req, CID: %d", cid);
+ return (FALSE);
+ }
+
+ l2c_csm_execute (p_ccb, L2CEVT_L2CA_DISCONNECT_REQ, NULL);
+
+ return (TRUE);
+}
+
+/*******************************************************************************
+**
+** Function L2CA_DisconnectRsp
+**
+** Description Higher layers call this function to acknowledge the
+** disconnection of a channel.
+**
+** Returns void
+**
+*******************************************************************************/
+BOOLEAN L2CA_DisconnectRsp (UINT16 cid)
+{
+ tL2C_CCB *p_ccb;
+
+ L2CAP_TRACE_API1 ("L2CA_DisconnectRsp() CID: 0x%04x", cid);
+
+ /* Find the channel control block. We don't know the link it is on. */
+ if ((p_ccb = l2cu_find_ccb_by_cid (NULL, cid)) == NULL)
+ {
+ L2CAP_TRACE_WARNING1 ("L2CAP - no CCB for L2CA_disc_rsp, CID: %d", cid);
+ return (FALSE);
+ }
+
+ l2c_csm_execute (p_ccb, L2CEVT_L2CA_DISCONNECT_RSP, NULL);
+
+ return (TRUE);
+}
+
+/*******************************************************************************
+**
+** Function L2CA_Ping
+**
+** Description Higher layers call this function to send an echo request.
+**
+** Returns TRUE if echo request sent, else FALSE.
+**
+*******************************************************************************/
+BOOLEAN L2CA_Ping (BD_ADDR p_bd_addr, tL2CA_ECHO_RSP_CB *p_callback)
+{
+ tL2C_LCB *p_lcb;
+
+ L2CAP_TRACE_API6 ("L2CA_Ping() BDA: %02x-%02x-%02x-%02x-%02x-%02x",
+ p_bd_addr[0], p_bd_addr[1], p_bd_addr[2], p_bd_addr[3], p_bd_addr[4], p_bd_addr[5]);
+
+ /* Fail if we have not established communications with the controller */
+ if (!BTM_IsDeviceUp())
+ return (FALSE);
+
+ /* First, see if we already have a link to the remote */
+ if ((p_lcb = l2cu_find_lcb_by_bd_addr (p_bd_addr)) == NULL)
+ {
+ /* No link. Get an LCB and start link establishment */
+ if ((p_lcb = l2cu_allocate_lcb (p_bd_addr, FALSE)) == NULL)
+ {
+ L2CAP_TRACE_WARNING0 ("L2CAP - no LCB for L2CA_ping");
+ return (FALSE);
+ }
+ if (l2cu_create_conn(p_lcb) == FALSE)
+ {
+ return (FALSE);
+ }
+
+ p_lcb->p_echo_rsp_cb = p_callback;
+
+ return (TRUE);
+ }
+
+ /* We only allow 1 ping outstanding at a time */
+ if (p_lcb->p_echo_rsp_cb != NULL)
+ {
+ L2CAP_TRACE_WARNING0 ("L2CAP - rejected second L2CA_ping");
+ return (FALSE);
+ }
+
+ /* Have a link control block. If link is disconnecting, tell user to retry later */
+ if (p_lcb->link_state == LST_DISCONNECTING)
+ {
+ L2CAP_TRACE_WARNING0 ("L2CAP - L2CA_ping rejected - link disconnecting");
+ return (FALSE);
+ }
+
+ /* Save address of callback */
+ p_lcb->p_echo_rsp_cb = p_callback;
+
+ if (p_lcb->link_state == LST_CONNECTED)
+ {
+ l2cu_adj_id(p_lcb, L2CAP_ADJ_BRCM_ID); /* Make sure not using Broadcom ID */
+ l2cu_send_peer_echo_req (p_lcb, NULL, 0);
+ btu_start_timer (&p_lcb->timer_entry, BTU_TTYPE_L2CAP_LINK, L2CAP_ECHO_RSP_TOUT);
+ }
+
+ return (TRUE);
+}
+
+/*******************************************************************************
+**
+** Function L2CA_Echo
+**
+** Description Higher layers call this function to send an echo request
+** with application-specific data.
+**
+** Returns TRUE if echo request sent, else FALSE.
+**
+*******************************************************************************/
+BOOLEAN L2CA_Echo (BD_ADDR p_bd_addr, BT_HDR *p_data, tL2CA_ECHO_DATA_CB *p_callback)
+{
+ tL2C_LCB *p_lcb;
+ UINT8 *pp;
+
+ L2CAP_TRACE_API2 ("L2CA_Echo() BDA: %08X%04X",
+ ((p_bd_addr[0] << 24) + (p_bd_addr[1] << 16) + (p_bd_addr[2] << 8) + (p_bd_addr[3])),
+ ((p_bd_addr[4] << 8) + (p_bd_addr[5])));
+
+ /* Fail if we have not established communications with the controller */
+ if (!BTM_IsDeviceUp())
+ return (FALSE);
+
+ if ((memcmp(BT_BD_ANY, p_bd_addr, BD_ADDR_LEN) == 0) && (p_data == NULL))
+ {
+ /* Only register callback without sending message. */
+ l2cb.p_echo_data_cb = p_callback;
+ return TRUE;
+ }
+
+ /* We assume the upper layer will call this function only when the link is established. */
+ if ((p_lcb = l2cu_find_lcb_by_bd_addr (p_bd_addr)) == NULL)
+ {
+ L2CAP_TRACE_ERROR0 ("L2CA_Echo ERROR : link not established");
+ return FALSE;
+ }
+
+ if (p_lcb->link_state != LST_CONNECTED)
+ {
+ L2CAP_TRACE_ERROR0 ("L2CA_Echo ERROR : link is not connected");
+ return FALSE;
+ }
+
+ /* Save address of callback */
+ l2cb.p_echo_data_cb = p_callback;
+
+ /* Set the pointer to the beginning of the data */
+ pp = (UINT8 *)(p_data + 1) + p_data->offset;
+ l2cu_adj_id(p_lcb, L2CAP_ADJ_BRCM_ID); /* Make sure not using Broadcom ID */
+ l2cu_send_peer_echo_req (p_lcb, pp, p_data->len);
+
+ return (TRUE);
+
+}
+
+/*******************************************************************************
+**
+** Function L2CA_SetIdleTimeout
+**
+** Description Higher layers call this function to set the idle timeout for
+** a connection, or for all future connections. The "idle timeout"
+** is the amount of time that a connection can remain up with
+** no L2CAP channels on it. A timeout of zero means that the
+** connection will be torn down immediately when the last channel
+** is removed. A timeout of 0xFFFF means no timeout. Values are
+** in seconds.
+**
+** Returns TRUE if command succeeded, FALSE if failed
+**
+** NOTE This timeout takes effect after at least 1 channel has been
+** established and removed. L2CAP maintains its own timer from
+** whan a connection is established till the first channel is
+** set up.
+*******************************************************************************/
+BOOLEAN L2CA_SetIdleTimeout (UINT16 cid, UINT16 timeout, BOOLEAN is_global)
+{
+ tL2C_CCB *p_ccb;
+ tL2C_LCB *p_lcb;
+
+ if (is_global)
+ {
+ l2cb.idle_timeout = timeout;
+ }
+ else
+ {
+ /* Find the channel control block. We don't know the link it is on. */
+ if ((p_ccb = l2cu_find_ccb_by_cid (NULL, cid)) == NULL)
+ {
+ L2CAP_TRACE_WARNING1 ("L2CAP - no CCB for L2CA_SetIdleTimeout, CID: %d", cid);
+ return (FALSE);
+ }
+
+ p_lcb = p_ccb->p_lcb;
+
+ if ((p_lcb) && (p_lcb->in_use) && (p_lcb->link_state == LST_CONNECTED))
+ p_lcb->idle_timeout = timeout;
+ else
+ return (FALSE);
+ }
+
+ return (TRUE);
+}
+
+/*******************************************************************************
+**
+** Function L2CA_SetIdleTimeoutByBdAddr
+**
+** Description Higher layers call this function to set the idle timeout for
+** a connection. The "idle timeout" is the amount of time that
+** a connection can remain up with no L2CAP channels on it.
+** A timeout of zero means that the connection will be torn
+** down immediately when the last channel is removed.
+** A timeout of 0xFFFF means no timeout. Values are in seconds.
+** A bd_addr is the remote BD address. If bd_addr = BT_BD_ANY,
+** then the idle timeouts for all active l2cap links will be
+** changed.
+**
+** Returns TRUE if command succeeded, FALSE if failed
+**
+** NOTE This timeout applies to all logical channels active on the
+** ACL link.
+*******************************************************************************/
+BOOLEAN L2CA_SetIdleTimeoutByBdAddr(BD_ADDR bd_addr, UINT16 timeout)
+{
+ tL2C_LCB *p_lcb;
+
+ if (memcmp (BT_BD_ANY, bd_addr, BD_ADDR_LEN))
+ {
+ p_lcb = l2cu_find_lcb_by_bd_addr( bd_addr );
+ if ((p_lcb) && (p_lcb->in_use) && (p_lcb->link_state == LST_CONNECTED))
+ p_lcb->idle_timeout = timeout;
+ else
+ return (FALSE);
+ }
+ else
+ {
+ int xx;
+ tL2C_LCB *p_lcb = &l2cb.lcb_pool[0];
+
+ for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_lcb++)
+ {
+ if ((p_lcb->in_use) && (p_lcb->link_state == LST_CONNECTED))
+ {
+ p_lcb->idle_timeout = timeout;
+ }
+ }
+ }
+
+ return (TRUE);
+}
+
+/*******************************************************************************
+**
+** Function L2CA_SetTraceLevel
+**
+** Description This function sets the trace level for L2CAP. If called with
+** a value of 0xFF, it simply reads the current trace level.
+**
+** Returns the new (current) trace level
+**
+*******************************************************************************/
+UINT8 L2CA_SetTraceLevel (UINT8 new_level)
+{
+ if (new_level != 0xFF)
+ l2cb.l2cap_trace_level = new_level;
+
+ return (l2cb.l2cap_trace_level);
+}
+
+
+/*******************************************************************************
+**
+** Function L2CA_SetDesireRole
+**
+** Description This function sets the desire role for L2CAP.
+** If the new role is L2CAP_ROLE_ALLOW_SWITCH, allow switch on
+** HciCreateConnection.
+** If the new role is L2CAP_ROLE_DISALLOW_SWITCH, do not allow switch on
+** HciCreateConnection.
+**
+** If the new role is a valid role (HCI_ROLE_MASTER or HCI_ROLE_SLAVE),
+** the desire role is set to the new value. Otherwise, it is not changed.
+**
+** Returns the new (current) role
+**
+*******************************************************************************/
+UINT8 L2CA_SetDesireRole (UINT8 new_role)
+{
+ L2CAP_TRACE_API2 ("L2CA_SetDesireRole() new:x%x, disallow_switch:%d",
+ new_role, l2cb.disallow_switch);
+
+ if (L2CAP_ROLE_CHECK_SWITCH != (L2CAP_ROLE_CHECK_SWITCH & new_role))
+ {
+ /* do not process the allow_switch when both bits are set */
+ if (new_role & L2CAP_ROLE_ALLOW_SWITCH)
+ {
+ l2cb.disallow_switch = FALSE;
+ }
+ if (new_role & L2CAP_ROLE_DISALLOW_SWITCH)
+ {
+ l2cb.disallow_switch = TRUE;
+ }
+ }
+
+ if (new_role == HCI_ROLE_MASTER || new_role == HCI_ROLE_SLAVE)
+ l2cb.desire_role = new_role;
+
+ return (l2cb.desire_role);
+}
+
+/*******************************************************************************
+**
+** Function L2CA_LocalLoopbackReq
+**
+** Description This function sets up a CID for local loopback
+**
+** Returns CID of 0 if none.
+**
+*******************************************************************************/
+UINT16 L2CA_LocalLoopbackReq (UINT16 psm, UINT16 handle, BD_ADDR p_bd_addr)
+{
+ tL2C_LCB *p_lcb;
+ tL2C_CCB *p_ccb;
+ tL2C_RCB *p_rcb;
+
+ L2CAP_TRACE_API2 ("L2CA_LocalLoopbackReq() PSM: %d Handle: 0x%04x", psm, handle);
+
+ /* Fail if we have not established communications with the controller */
+ if (!BTM_IsDeviceUp())
+ {
+ L2CAP_TRACE_WARNING0 ("L2CAP loop req - BTU not ready");
+ return (0);
+ }
+
+ /* Fail if the PSM is not registered */
+ if ((p_rcb = l2cu_find_rcb_by_psm (psm)) == NULL)
+ {
+ L2CAP_TRACE_WARNING1 ("L2CAP - no RCB for L2CA_conn_req, PSM: %d", psm);
+ return (0);
+ }
+
+ if ((p_lcb = l2cu_allocate_lcb (p_bd_addr, FALSE)) == NULL)
+ {
+ L2CAP_TRACE_WARNING0 ("L2CAP - no LCB for L2CA_conn_req");
+ return (0);
+ }
+
+ p_lcb->link_state = LST_CONNECTED;
+ p_lcb->handle = handle;
+
+ /* Allocate a channel control block */
+ if ((p_ccb = l2cu_allocate_ccb (p_lcb, 0)) == NULL)
+ {
+ L2CAP_TRACE_WARNING0 ("L2CAP - no CCB for L2CA_conn_req");
+ return (0);
+ }
+
+ /* Save registration info */
+ p_ccb->p_rcb = p_rcb;
+ p_ccb->chnl_state = CST_OPEN;
+ p_ccb->remote_cid = p_ccb->local_cid;
+ p_ccb->config_done = CFG_DONE_MASK;
+
+ /* Return the local CID as our handle */
+ return (p_ccb->local_cid);
+}
+
+/*******************************************************************************
+**
+** Function L2CA_SetAclPriority
+**
+** Description Sets the transmission priority for a channel.
+** (For initial implementation only two values are valid.
+** L2CAP_PRIORITY_NORMAL and L2CAP_PRIORITY_HIGH).
+**
+** Returns TRUE if a valid channel, else FALSE
+**
+*******************************************************************************/
+BOOLEAN L2CA_SetAclPriority (BD_ADDR bd_addr, UINT8 priority)
+{
+ L2CAP_TRACE_API6 ("L2CA_SetAclPriority() bdaddr: %02x%02x%02x%02x%04x, priority:%d",
+ bd_addr[0], bd_addr[1], bd_addr[2],
+ bd_addr[3], (bd_addr[4] << 8) + bd_addr[5], priority);
+
+ return (l2cu_set_acl_priority(bd_addr, priority, FALSE));
+}
+
+/*******************************************************************************
+**
+** Function L2CA_FlowControl
+**
+** Description Higher layers call this function to flow control a channel.
+**
+** data_enabled - TRUE data flows, FALSE data is stopped
+**
+** Returns TRUE if valid channel, else FALSE
+**
+*******************************************************************************/
+BOOLEAN L2CA_FlowControl (UINT16 cid, BOOLEAN data_enabled)
+{
+ tL2C_CCB *p_ccb;
+ BOOLEAN on_off = !data_enabled;
+
+ L2CAP_TRACE_API2 ("L2CA_FlowControl(%d) CID: 0x%04x", on_off, cid);
+
+ /* Find the channel control block. We don't know the link it is on. */
+ if ((p_ccb = l2cu_find_ccb_by_cid (NULL, cid)) == NULL)
+ {
+ L2CAP_TRACE_WARNING2 ("L2CAP - no CCB for L2CA_FlowControl, CID: 0x%04x data_enabled: %d", cid, data_enabled);
+ return (FALSE);
+ }
+
+ if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_ERTM_MODE)
+ {
+ L2CAP_TRACE_EVENT1 ("L2CA_FlowControl() invalid mode:%d", p_ccb->peer_cfg.fcr.mode);
+ return (FALSE);
+ }
+ if (p_ccb->fcrb.local_busy != on_off)
+ {
+ p_ccb->fcrb.local_busy = on_off;
+
+ if ( (p_ccb->chnl_state == CST_OPEN) && (!p_ccb->fcrb.wait_ack) )
+ {
+ if (on_off)
+ l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RNR, 0);
+ else
+ l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RR, L2CAP_FCR_P_BIT);
+ }
+ }
+
+ return (TRUE);
+}
+
+/*******************************************************************************
+**
+** Function L2CA_SendTestSFrame
+**
+** Description Higher layers call this function to send a test S-frame.
+**
+** Returns TRUE if valid Channel, else FALSE
+**
+*******************************************************************************/
+BOOLEAN L2CA_SendTestSFrame (UINT16 cid, UINT8 sup_type, UINT8 back_track)
+{
+ tL2C_CCB *p_ccb;
+
+ L2CAP_TRACE_API3 ("L2CA_SendTestSFrame() CID: 0x%04x Type: 0x%02x back_track: %u", cid, sup_type, back_track);
+
+ /* Find the channel control block. We don't know the link it is on. */
+ if ((p_ccb = l2cu_find_ccb_by_cid (NULL, cid)) == NULL)
+ {
+ L2CAP_TRACE_WARNING1 ("L2CAP - no CCB for L2CA_SendTestSFrame, CID: %d", cid);
+ return (FALSE);
+ }
+
+ if ( (p_ccb->chnl_state != CST_OPEN) || (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_ERTM_MODE) )
+ return (FALSE);
+
+ p_ccb->fcrb.next_seq_expected -= back_track;
+
+ l2c_fcr_send_S_frame (p_ccb, (UINT16)(sup_type & 3), (UINT16)(sup_type & (L2CAP_FCR_P_BIT | L2CAP_FCR_F_BIT)));
+
+ return (TRUE);
+}
+
+
+/*******************************************************************************
+**
+** Function L2CA_SetTxPriority
+**
+** Description Sets the transmission priority for a channel.
+**
+** Returns TRUE if a valid channel, else FALSE
+**
+*******************************************************************************/
+BOOLEAN L2CA_SetTxPriority (UINT16 cid, tL2CAP_CHNL_PRIORITY priority)
+{
+ tL2C_CCB *p_ccb;
+
+ L2CAP_TRACE_API2 ("L2CA_SetTxPriority() CID: 0x%04x, priority:%d", cid, priority);
+
+ /* Find the channel control block. We don't know the link it is on. */
+ if ((p_ccb = l2cu_find_ccb_by_cid (NULL, cid)) == NULL)
+ {
+ L2CAP_TRACE_WARNING1 ("L2CAP - no CCB for L2CA_SetTxPriority, CID: %d", cid);
+ return (FALSE);
+ }
+
+ /* it will update the order of CCB in LCB by priority and update round robin service variables */
+ l2cu_change_pri_ccb (p_ccb, priority);
+
+ return (TRUE);
+}
+
+/*******************************************************************************
+**
+** Function L2CA_SetChnlDataRate
+**
+** Description Sets the tx/rx data rate for a channel.
+**
+** Returns TRUE if a valid channel, else FALSE
+**
+*******************************************************************************/
+BOOLEAN L2CA_SetChnlDataRate (UINT16 cid, tL2CAP_CHNL_DATA_RATE tx, tL2CAP_CHNL_DATA_RATE rx)
+{
+ tL2C_CCB *p_ccb;
+
+ L2CAP_TRACE_API3 ("L2CA_SetChnlDataRate() CID: 0x%04x, tx:%d, rx:%d", cid, tx, rx);
+
+ /* Find the channel control block. We don't know the link it is on. */
+ if ((p_ccb = l2cu_find_ccb_by_cid (NULL, cid)) == NULL)
+ {
+ L2CAP_TRACE_WARNING1 ("L2CAP - no CCB for L2CA_SetChnlDataRate, CID: %d", cid);
+ return (FALSE);
+ }
+
+ p_ccb->tx_data_rate = tx;
+ p_ccb->rx_data_rate = rx;
+
+ /* Adjust channel buffer allocation */
+ l2c_link_adjust_chnl_allocation ();
+
+ return(TRUE);
+}
+
+/*******************************************************************************
+**
+** Function L2CA_SetFlushTimeout
+**
+** Description This function set the automatic flush time out in Baseband
+** for ACL-U packets.
+** BdAddr : the remote BD address of ACL link. If it is BT_DB_ANY
+** then the flush time out will be applied to all ACL link.
+** FlushTimeout: flush time out in ms
+** 0x0000 : No automatic flush
+** L2CAP_NO_RETRANSMISSION : No retransmission
+** 0x0002 - 0xFFFE : flush time out, if (flush_tout*8)+3/5)
+** <= HCI_MAX_AUTO_FLUSH_TOUT (in 625us slot).
+** Otherwise, return FALSE.
+** L2CAP_NO_AUTOMATIC_FLUSH : No automatic flush
+**
+** Returns TRUE if command succeeded, FALSE if failed
+**
+** NOTE This flush timeout applies to all logical channels active on the
+** ACL link.
+*******************************************************************************/
+BOOLEAN L2CA_SetFlushTimeout (BD_ADDR bd_addr, UINT16 flush_tout)
+{
+ tL2C_LCB *p_lcb;
+ UINT16 hci_flush_to;
+ UINT32 temp;
+
+ /* no automatic flush (infinite timeout) */
+ if (flush_tout == 0x0000)
+ {
+ hci_flush_to = flush_tout;
+ flush_tout = L2CAP_NO_AUTOMATIC_FLUSH;
+ }
+ /* no retransmission */
+ else if (flush_tout == L2CAP_NO_RETRANSMISSION)
+ {
+ /* not mandatory range for controller */
+ /* Packet is flushed before getting any ACK/NACK */
+ /* To do this, flush timeout should be 1 baseband slot */
+ hci_flush_to = flush_tout;
+ }
+ /* no automatic flush (infinite timeout) */
+ else if (flush_tout == L2CAP_NO_AUTOMATIC_FLUSH)
+ {
+ hci_flush_to = 0x0000;
+ }
+ else
+ {
+ /* convert L2CAP flush_to to 0.625 ms units, with round */
+ temp = (((UINT32)flush_tout * 8) + 3) / 5;
+
+ /* if L2CAP flush_to within range of HCI, set HCI flush timeout */
+ if (temp > HCI_MAX_AUTO_FLUSH_TOUT)
+ {
+ L2CAP_TRACE_WARNING1("WARNING L2CA_SetFlushTimeout timeout(0x%x) is out of range", flush_tout);
+ return FALSE;
+ }
+ else
+ {
+ hci_flush_to = (UINT16)temp;
+ }
+ }
+
+ if (memcmp (BT_BD_ANY, bd_addr, BD_ADDR_LEN))
+ {
+ p_lcb = l2cu_find_lcb_by_bd_addr (bd_addr);
+
+ if ((p_lcb) && (p_lcb->in_use) && (p_lcb->link_state == LST_CONNECTED))
+ {
+ if (p_lcb->link_flush_tout != flush_tout)
+ {
+ p_lcb->link_flush_tout = flush_tout;
+
+ L2CAP_TRACE_API4 ("L2CA_SetFlushTimeout 0x%04x ms for bd_addr [...;%02x%02x%02x]",
+ flush_tout, bd_addr[3], bd_addr[4], bd_addr[5]);
+
+ if (!btsnd_hcic_write_auto_flush_tout (p_lcb->handle, hci_flush_to))
+ return (FALSE);
+ }
+ }
+ else
+ {
+ L2CAP_TRACE_WARNING3 ("WARNING L2CA_SetFlushTimeout No lcb for bd_addr [...;%02x%02x%02x]",
+ bd_addr[3], bd_addr[4], bd_addr[5]);
+ return (FALSE);
+ }
+ }
+ else
+ {
+ int xx;
+ p_lcb = &l2cb.lcb_pool[0];
+
+ for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_lcb++)
+ {
+ if ((p_lcb->in_use) && (p_lcb->link_state == LST_CONNECTED))
+ {
+ if (p_lcb->link_flush_tout != flush_tout)
+ {
+ p_lcb->link_flush_tout = flush_tout;
+
+ L2CAP_TRACE_API4 ("L2CA_SetFlushTimeout 0x%04x ms for bd_addr [...;%02x%02x%02x]",
+ flush_tout, p_lcb->remote_bd_addr[3],
+ p_lcb->remote_bd_addr[4], p_lcb->remote_bd_addr[5]);
+
+ if (!btsnd_hcic_write_auto_flush_tout(p_lcb->handle, hci_flush_to))
+ return (FALSE);
+ }
+ }
+ }
+ }
+
+ return (TRUE);
+}
+
+/*******************************************************************************
+**
+** Function L2CA_GetPeerFeatures
+**
+** Description Get a peers features and fixed channel map
+**
+** Parameters: BD address of the peer
+** Pointers to features and channel mask storage area
+**
+** Return value: TRUE if peer is connected
+**
+*******************************************************************************/
+BOOLEAN L2CA_GetPeerFeatures (BD_ADDR bd_addr, UINT32 *p_ext_feat, UINT8 *p_chnl_mask)
+{
+ tL2C_LCB *p_lcb;
+
+ /* We must already have a link to the remote */
+ if ((p_lcb = l2cu_find_lcb_by_bd_addr (bd_addr)) == NULL)
+ {
+ L2CAP_TRACE_WARNING2 ("L2CA_GetPeerFeatures() No BDA: %08x%04x",
+ (bd_addr[0]<<24)+(bd_addr[1]<<16)+(bd_addr[2]<<8)+bd_addr[3],
+ (bd_addr[4]<<8)+bd_addr[5]);
+ return (FALSE);
+ }
+
+ L2CAP_TRACE_API4 ("L2CA_GetPeerFeatures() BDA: %08x%04x ExtFea: 0x%08x Chnl_Mask[0]: 0x%02x",
+ (bd_addr[0]<<24)+(bd_addr[1]<<16)+(bd_addr[2]<<8)+bd_addr[3],
+ (bd_addr[4]<<8)+bd_addr[5], p_lcb->peer_ext_fea, p_lcb->peer_chnl_mask[0]);
+
+ *p_ext_feat = p_lcb->peer_ext_fea;
+
+ memcpy (p_chnl_mask, p_lcb->peer_chnl_mask, L2CAP_FIXED_CHNL_ARRAY_SIZE);
+
+ return (TRUE);
+}
+
+/*******************************************************************************
+**
+** Function L2CA_GetBDAddrbyHandle
+**
+** Description Get BD address for the given HCI handle
+**
+** Parameters: HCI handle
+** BD address of the peer
+**
+** Return value: TRUE if found lcb for the given handle, FALSE otherwise
+**
+*******************************************************************************/
+BOOLEAN L2CA_GetBDAddrbyHandle (UINT16 handle, BD_ADDR bd_addr)
+{
+ tL2C_LCB *p_lcb = NULL;
+ BOOLEAN found_dev = FALSE;
+
+ p_lcb = l2cu_find_lcb_by_handle (handle);
+ if (p_lcb)
+ {
+ found_dev = TRUE;
+ memcpy (bd_addr, p_lcb->remote_bd_addr, BD_ADDR_LEN);
+ }
+
+ return found_dev;
+}
+
+/*******************************************************************************
+**
+** Function L2CA_GetChnlFcrMode
+**
+** Description Get the channel FCR mode
+**
+** Parameters: Local CID
+**
+** Return value: Channel mode
+**
+*******************************************************************************/
+UINT8 L2CA_GetChnlFcrMode (UINT16 lcid)
+{
+ tL2C_CCB *p_ccb = l2cu_find_ccb_by_cid (NULL, lcid);
+
+ if (p_ccb)
+ {
+ L2CAP_TRACE_API1 ("L2CA_GetChnlFcrMode() returns mode %d", p_ccb->peer_cfg.fcr.mode);
+ return (p_ccb->peer_cfg.fcr.mode);
+ }
+
+ L2CAP_TRACE_API0 ("L2CA_GetChnlFcrMode() returns mode L2CAP_FCR_BASIC_MODE");
+ return (L2CAP_FCR_BASIC_MODE);
+}
+
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+/*******************************************************************************
+**
+** Function L2CA_RegisterFixedChannel
+**
+** Description Register a fixed channel.
+**
+** Parameters: Fixed Channel #
+** Channel Callbacks and config
+**
+** Return value: -
+**
+*******************************************************************************/
+BOOLEAN L2CA_RegisterFixedChannel (UINT16 fixed_cid, tL2CAP_FIXED_CHNL_REG *p_freg)
+{
+ if ( (fixed_cid < L2CAP_FIRST_FIXED_CHNL) || (fixed_cid > L2CAP_LAST_FIXED_CHNL) )
+ {
+ L2CAP_TRACE_ERROR1 ("L2CA_RegisterFixedChannel() Invalid CID: 0x%04x", fixed_cid);
+
+ return (FALSE);
+ }
+
+ l2cb.fixed_reg[fixed_cid - L2CAP_FIRST_FIXED_CHNL] = *p_freg;
+ return (TRUE);
+}
+
+/*******************************************************************************
+**
+** Function L2CA_ConnectFixedChnl
+**
+** Description Connect an fixed signalling channel to a remote device.
+**
+** Parameters: Fixed CID
+** BD Address of remote
+**
+** Return value: TRUE if connection started
+**
+*******************************************************************************/
+BOOLEAN L2CA_ConnectFixedChnl (UINT16 fixed_cid, BD_ADDR rem_bda)
+{
+ tL2C_LCB *p_lcb;
+#if BLE_INCLUDED == TRUE
+ UINT16 reason;
+#endif
+
+ L2CAP_TRACE_API3 ("L2CA_ConnectFixedChnl() CID: 0x%04x BDA: %08x%04x", fixed_cid,
+ (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3], (rem_bda[4]<<8)+rem_bda[5]);
+
+ /* Check CID is valid and registered */
+ if ( (fixed_cid < L2CAP_FIRST_FIXED_CHNL) || (fixed_cid > L2CAP_LAST_FIXED_CHNL)
+ || (l2cb.fixed_reg[fixed_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb == NULL) )
+ {
+ L2CAP_TRACE_ERROR1 ("L2CA_ConnectFixedChnl() Invalid CID: 0x%04x", fixed_cid);
+ return (FALSE);
+ }
+
+ /* Fail if BT is not yet up */
+ if (!BTM_IsDeviceUp())
+ {
+ L2CAP_TRACE_WARNING1 ("L2CA_ConnectFixedChnl(0x%04x) - BTU not ready", fixed_cid);
+ return (FALSE);
+ }
+
+ /* If we already have a link to the remote, check if it supports that CID */
+ if ((p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda)) != NULL)
+ {
+ if (!(p_lcb->peer_chnl_mask[0] & (1 << fixed_cid)))
+ {
+ L2CAP_TRACE_EVENT3 ("L2CA_ConnectFixedChnl() CID: 0x%04x BDA: %08x%04x not supported", fixed_cid,
+ (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3], (rem_bda[4]<<8)+rem_bda[5]);
+ return (FALSE);
+ }
+ /* Get a CCB and link the lcb to it */
+ if (!l2cu_initialize_fixed_ccb (p_lcb, fixed_cid, &l2cb.fixed_reg[fixed_cid - L2CAP_FIRST_FIXED_CHNL].fixed_chnl_opts))
+ {
+ L2CAP_TRACE_WARNING1 ("L2CA_ConnectFixedChnl(0x%04x) - LCB but no CCB", fixed_cid);
+ return (FALSE);
+ }
+#if BLE_INCLUDED == TRUE
+ reason = (p_lcb->is_ble_link) ? 1: 0;
+ (*l2cb.fixed_reg[fixed_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedConn_Cb)(p_lcb->remote_bd_addr, TRUE, reason);
+#else
+ (*l2cb.fixed_reg[fixed_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedConn_Cb)(p_lcb->remote_bd_addr, TRUE, 0);
+#endif
+ return (TRUE);
+ }
+
+ /* No link. Get an LCB and start link establishment */
+ if ((p_lcb = l2cu_allocate_lcb (rem_bda, FALSE)) == NULL)
+ {
+ L2CAP_TRACE_WARNING1 ("L2CA_ConnectFixedChnl(0x%04x) - no LCB", fixed_cid);
+ return (FALSE);
+ }
+
+ /* Get a CCB and link the lcb to it */
+ if (!l2cu_initialize_fixed_ccb (p_lcb, fixed_cid, &l2cb.fixed_reg[fixed_cid - L2CAP_FIRST_FIXED_CHNL].fixed_chnl_opts))
+ {
+ p_lcb->disc_reason = L2CAP_CONN_NO_RESOURCES;
+ L2CAP_TRACE_WARNING1 ("L2CA_ConnectFixedChnl(0x%04x) - no CCB", fixed_cid);
+ l2cu_release_lcb (p_lcb);
+ return (FALSE);
+ }
+
+ return (l2cu_create_conn(p_lcb));
+}
+
+/*******************************************************************************
+**
+** Function L2CA_SendFixedChnlData
+**
+** Description Write data on a fixed channel.
+**
+** Parameters: Fixed CID
+** BD Address of remote
+** Pointer to buffer of type BT_HDR
+**
+** Return value L2CAP_DW_SUCCESS, if data accepted
+** L2CAP_DW_FAILED, if error
+**
+*******************************************************************************/
+UINT16 L2CA_SendFixedChnlData (UINT16 fixed_cid, BD_ADDR rem_bda, BT_HDR *p_buf)
+{
+ tL2C_LCB *p_lcb;
+
+ L2CAP_TRACE_API3 ("L2CA_SendFixedChnlData() CID: 0x%04x BDA: %08x%04x", fixed_cid,
+ (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3], (rem_bda[4]<<8)+rem_bda[5]);
+
+ /* Check CID is valid and registered */
+ if ( (fixed_cid < L2CAP_FIRST_FIXED_CHNL) || (fixed_cid > L2CAP_LAST_FIXED_CHNL)
+ || (l2cb.fixed_reg[fixed_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb == NULL) )
+ {
+ L2CAP_TRACE_ERROR1 ("L2CA_SendFixedChnlData() Invalid CID: 0x%04x", fixed_cid);
+ return (L2CAP_DW_FAILED);
+ }
+
+ /* Fail if BT is not yet up */
+ if (!BTM_IsDeviceUp())
+ {
+ L2CAP_TRACE_WARNING1 ("L2CA_SendFixedChnlData(0x%04x) - BTU not ready", fixed_cid);
+ return (L2CAP_DW_FAILED);
+ }
+
+ /* We need to have a link up */
+ if ((p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda)) == NULL)
+ {
+ L2CAP_TRACE_WARNING1 ("L2CA_SendFixedChnlData(0x%04x) - no LCB", fixed_cid);
+ return (L2CAP_DW_FAILED);
+ }
+
+ if ((p_lcb->peer_chnl_mask[0] & (1 << fixed_cid)) == 0)
+ {
+ L2CAP_TRACE_WARNING1 ("L2CA_SendFixedChnlData() - peer does not support fixed chnl: 0x%04x", fixed_cid);
+ return (L2CAP_DW_FAILED);
+ }
+
+ p_buf->event = 0;
+ p_buf->layer_specific = L2CAP_FLUSHABLE_CH_BASED;
+
+ if (!p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL])
+ {
+ if (!l2cu_initialize_fixed_ccb (p_lcb, fixed_cid, &l2cb.fixed_reg[fixed_cid - L2CAP_FIRST_FIXED_CHNL].fixed_chnl_opts))
+ {
+ L2CAP_TRACE_WARNING1 ("L2CA_SendFixedChnlData() - no CCB for chnl: 0x%4x", fixed_cid);
+ return (L2CAP_DW_FAILED);
+ }
+ }
+
+ l2c_enqueue_peer_data (p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL], p_buf);
+
+ l2c_link_check_send_pkts (p_lcb, NULL, NULL);
+
+ /* If there is no dynamic CCB on the link, restart the idle timer each time something is sent */
+ if (p_lcb->in_use && p_lcb->link_state == LST_CONNECTED && !p_lcb->ccb_queue.p_first_ccb)
+ {
+ l2cu_no_dynamic_ccbs (p_lcb);
+ }
+
+ return (L2CAP_DW_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function L2CA_RemoveFixedChnl
+**
+** Description Remove a fixed channel to a remote device.
+**
+** Parameters: Fixed CID
+** BD Address of remote
+** Idle timeout to use (or 0xFFFF if don't care)
+**
+** Return value: TRUE if channel removed
+**
+*******************************************************************************/
+BOOLEAN L2CA_RemoveFixedChnl (UINT16 fixed_cid, BD_ADDR rem_bda)
+{
+ tL2C_LCB *p_lcb;
+ tL2C_CCB *p_ccb;
+
+ /* Check CID is valid and registered */
+ if ( (fixed_cid < L2CAP_FIRST_FIXED_CHNL) || (fixed_cid > L2CAP_LAST_FIXED_CHNL)
+ || (l2cb.fixed_reg[fixed_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb == NULL) )
+ {
+ L2CAP_TRACE_ERROR1 ("L2CA_RemoveFixedChnl() Invalid CID: 0x%04x", fixed_cid);
+ return (FALSE);
+ }
+
+ /* Is a fixed channel connected to the remote BDA ?*/
+ p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda);
+ if ( ((p_lcb) == NULL) || (!p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL]) )
+ {
+ L2CAP_TRACE_WARNING3 ("L2CA_RemoveFixedChnl() CID: 0x%04x BDA: %08x%04x not connected", fixed_cid,
+ (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3], (rem_bda[4]<<8)+rem_bda[5]);
+ return (FALSE);
+ }
+
+ L2CAP_TRACE_API3 ("L2CA_RemoveFixedChnl() CID: 0x%04x BDA: %08x%04x", fixed_cid,
+ (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3], (rem_bda[4]<<8)+rem_bda[5]);
+
+ /* Release the CCB, starting an inactivity timeout on the LCB if no other CCBs exist */
+ p_ccb = p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL];
+
+ p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL] = NULL;
+ p_lcb->disc_reason = HCI_ERR_CONN_CAUSE_LOCAL_HOST;
+ l2cu_release_ccb (p_ccb);
+
+ return (TRUE);
+}
+
+/*******************************************************************************
+**
+** Function L2CA_SetFixedChannelTout
+**
+** Description Higher layers call this function to set the idle timeout for
+** a fixed channel. The "idle timeout" is the amount of time that
+** a connection can remain up with no L2CAP channels on it.
+** A timeout of zero means that the connection will be torn
+** down immediately when the last channel is removed.
+** A timeout of 0xFFFF means no timeout. Values are in seconds.
+** A bd_addr is the remote BD address. If bd_addr = BT_BD_ANY,
+** then the idle timeouts for all active l2cap links will be
+** changed.
+**
+** Returns TRUE if command succeeded, FALSE if failed
+**
+*******************************************************************************/
+BOOLEAN L2CA_SetFixedChannelTout (BD_ADDR rem_bda, UINT16 fixed_cid, UINT16 idle_tout)
+{
+ tL2C_LCB *p_lcb;
+
+ /* Is a fixed channel connected to the remote BDA ?*/
+ p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda);
+ if ( ((p_lcb) == NULL) || (!p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL]) )
+ {
+ L2CAP_TRACE_WARNING3 ("L2CA_SetFixedChannelTout() CID: 0x%04x BDA: %08x%04x not connected", fixed_cid,
+ (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3], (rem_bda[4]<<8)+rem_bda[5]);
+ return (FALSE);
+ }
+
+ p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL]->fixed_chnl_idle_tout = idle_tout;
+
+ if (p_lcb->in_use && p_lcb->link_state == LST_CONNECTED && !p_lcb->ccb_queue.p_first_ccb)
+ {
+ /* If there are no dynamic CCBs, (re)start the idle timer in case we changed it */
+ l2cu_no_dynamic_ccbs (p_lcb);
+ }
+
+ return (TRUE);
+}
+
+#endif /* #if (L2CAP_NUM_FIXED_CHNLS > 0) */
+
+/*******************************************************************************
+**
+** Function L2CA_GetCurrentConfig
+**
+** Description This function returns configurations of L2CAP channel
+** pp_our_cfg : pointer of our saved configuration options
+** p_our_cfg_bits : valid config in bitmap
+** pp_peer_cfg: pointer of peer's saved configuration options
+** p_peer_cfg_bits : valid config in bitmap
+**
+** Returns TRUE if successful
+**
+*******************************************************************************/
+BOOLEAN L2CA_GetCurrentConfig (UINT16 lcid,
+ tL2CAP_CFG_INFO **pp_our_cfg, tL2CAP_CH_CFG_BITS *p_our_cfg_bits,
+ tL2CAP_CFG_INFO **pp_peer_cfg, tL2CAP_CH_CFG_BITS *p_peer_cfg_bits)
+{
+ tL2C_CCB *p_ccb;
+
+ L2CAP_TRACE_API1 ("L2CA_GetCurrentConfig() CID: 0x%04x", lcid);
+
+ p_ccb = l2cu_find_ccb_by_cid(NULL, lcid);
+
+ if (p_ccb)
+ {
+ *pp_our_cfg = &(p_ccb->our_cfg);
+
+ /* convert valid config items into bitmap */
+ *p_our_cfg_bits = 0;
+ if (p_ccb->our_cfg.mtu_present)
+ *p_our_cfg_bits |= L2CAP_CH_CFG_MASK_MTU;
+ if (p_ccb->our_cfg.qos_present)
+ *p_our_cfg_bits |= L2CAP_CH_CFG_MASK_QOS;
+ if (p_ccb->our_cfg.flush_to_present)
+ *p_our_cfg_bits |= L2CAP_CH_CFG_MASK_FLUSH_TO;
+ if (p_ccb->our_cfg.fcr_present)
+ *p_our_cfg_bits |= L2CAP_CH_CFG_MASK_FCR;
+ if (p_ccb->our_cfg.fcs_present)
+ *p_our_cfg_bits |= L2CAP_CH_CFG_MASK_FCS;
+ if (p_ccb->our_cfg.ext_flow_spec_present)
+ *p_our_cfg_bits |= L2CAP_CH_CFG_MASK_EXT_FLOW_SPEC;
+
+ *pp_peer_cfg = &(p_ccb->peer_cfg);
+ *p_peer_cfg_bits = p_ccb->peer_cfg_bits;
+
+ return TRUE;
+ }
+ else
+ {
+ L2CAP_TRACE_ERROR1 ("No CCB for CID:0x%04x", lcid);
+ return FALSE;
+ }
+}
+
+/*******************************************************************************
+**
+** Function L2CA_RegForNoCPEvt
+**
+** Description Register callback for Number of Completed Packets event.
+**
+** Input Param p_cb - callback for Number of completed packets event
+** p_bda - BT address of remote device
+**
+** Returns TRUE if registered OK, else FALSE
+**
+*******************************************************************************/
+BOOLEAN L2CA_RegForNoCPEvt(tL2CA_NOCP_CB *p_cb, BD_ADDR p_bda)
+{
+ tL2C_LCB *p_lcb;
+
+ /* Find the link that is associated with this remote bdaddr */
+ p_lcb = l2cu_find_lcb_by_bd_addr (p_bda);
+
+ /* If no link for this handle, nothing to do. */
+ if (!p_lcb)
+ return FALSE;
+
+ p_lcb->p_nocp_cb = p_cb;
+
+ return TRUE;
+}
+
+/*******************************************************************************
+**
+** Function L2CA_DataWrite
+**
+** Description Higher layers call this function to write data.
+**
+** Returns L2CAP_DW_SUCCESS, if data accepted, else FALSE
+** L2CAP_DW_CONGESTED, if data accepted and the channel is congested
+** L2CAP_DW_FAILED, if error
+**
+*******************************************************************************/
+UINT8 L2CA_DataWrite (UINT16 cid, BT_HDR *p_data)
+{
+ L2CAP_TRACE_API2 ("L2CA_DataWrite() CID: 0x%04x Len: %d", cid, p_data->len);
+ return l2c_data_write (cid, p_data, L2CAP_FLUSHABLE_CH_BASED);
+}
+
+/*******************************************************************************
+**
+** Function L2CA_SetChnlFlushability
+**
+** Description Higher layers call this function to set a channels
+** flushability flags
+**
+** Returns TRUE if CID found, else FALSE
+**
+*******************************************************************************/
+BOOLEAN L2CA_SetChnlFlushability (UINT16 cid, BOOLEAN is_flushable)
+{
+#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
+
+ tL2C_CCB *p_ccb;
+
+ /* Find the channel control block. We don't know the link it is on. */
+ if ((p_ccb = l2cu_find_ccb_by_cid (NULL, cid)) == NULL)
+ {
+ L2CAP_TRACE_WARNING1 ("L2CAP - no CCB for L2CA_SetChnlFlushability, CID: %d", cid);
+ return (FALSE);
+ }
+
+ p_ccb->is_flushable = is_flushable;
+
+ L2CAP_TRACE_API2 ("L2CA_SetChnlFlushability() CID: 0x%04x is_flushable: %d", cid, is_flushable);
+
+#endif
+
+ return (TRUE);
+}
+
+/*******************************************************************************
+**
+** Function L2CA_DataWriteEx
+**
+** Description Higher layers call this function to write data with extended
+** flags.
+** flags : L2CAP_FLUSHABLE_CH_BASED
+** L2CAP_FLUSHABLE_PKT
+** L2CAP_NON_FLUSHABLE_PKT
+**
+** Returns L2CAP_DW_SUCCESS, if data accepted, else FALSE
+** L2CAP_DW_CONGESTED, if data accepted and the channel is congested
+** L2CAP_DW_FAILED, if error
+**
+*******************************************************************************/
+UINT8 L2CA_DataWriteEx (UINT16 cid, BT_HDR *p_data, UINT16 flags)
+{
+ L2CAP_TRACE_API3 ("L2CA_DataWriteEx() CID: 0x%04x Len: %d Flags:0x%04X",
+ cid, p_data->len, flags);
+ return l2c_data_write (cid, p_data, flags);
+}
+
+/*******************************************************************************
+**
+** Function L2CA_FlushChannel
+**
+** Description This function flushes none, some or all buffers queued up
+** for xmission for a particular CID. If called with
+** L2CAP_FLUSH_CHANS_GET (0), it simply returns the number
+** of buffers queued for that CID L2CAP_FLUSH_CHANS_ALL (0xffff)
+** flushes all buffers. All other values specifies the maximum
+** buffers to flush.
+**
+** Returns Number of buffers left queued for that CID
+**
+*******************************************************************************/
+UINT16 L2CA_FlushChannel (UINT16 lcid, UINT16 num_to_flush)
+{
+ tL2C_CCB *p_ccb;
+ tL2C_LCB *p_lcb;
+ UINT16 num_left = 0,
+ num_flushed1 = 0,
+ num_flushed2 = 0;
+ BT_HDR *p_buf1, *p_buf;
+
+ p_ccb = l2cu_find_ccb_by_cid(NULL, lcid);
+
+ if ( !p_ccb || ((p_lcb = p_ccb->p_lcb) == NULL) )
+ {
+ L2CAP_TRACE_WARNING1 ("L2CA_FlushChannel() abnormally returning 0 CID: 0x%04x", lcid);
+ return (0);
+ }
+
+ if (num_to_flush != L2CAP_FLUSH_CHANS_GET)
+ {
+ L2CAP_TRACE_API4 ("L2CA_FlushChannel (FLUSH) CID: 0x%04x NumToFlush: %d QC: %u pFirst: 0x%08x",
+ lcid, num_to_flush, p_ccb->xmit_hold_q.count, p_ccb->xmit_hold_q.p_first);
+ }
+ else
+ {
+ L2CAP_TRACE_API1 ("L2CA_FlushChannel (QUERY) CID: 0x%04x", lcid);
+ }
+
+ /* Cannot flush eRTM buffers once they have a sequence number */
+ if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_ERTM_MODE)
+ {
+#if L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE
+ if (num_to_flush != L2CAP_FLUSH_CHANS_GET)
+ {
+ /* If the controller supports enhanced flush, flush the data queued at the controller */
+ if ( (HCI_NON_FLUSHABLE_PB_SUPPORTED(BTM_ReadLocalFeatures ()))
+ && (BTM_GetNumScoLinks() == 0) )
+ {
+ if ( l2cb.is_flush_active == FALSE )
+ {
+ l2cb.is_flush_active = TRUE;
+
+ /* The only packet type defined - 0 - Automatically-Flushable Only */
+ btsnd_hcic_enhanced_flush (p_lcb->handle, 0);
+ }
+ }
+ }
+#endif
+
+ p_buf = (BT_HDR *)p_lcb->link_xmit_data_q.p_first;
+
+ /* First flush the number we are asked to flush */
+ while ((p_buf != NULL) && (num_to_flush != 0))
+ {
+ /* Do not flush other CIDs or partial segments */
+ if ( (p_buf->layer_specific == 0) && (p_buf->event == lcid) )
+ {
+ p_buf1 = p_buf;
+ p_buf = (BT_HDR *)GKI_getnext (p_buf);
+ num_to_flush--;
+ num_flushed1++;
+
+ GKI_remove_from_queue (&p_lcb->link_xmit_data_q, p_buf1);
+ GKI_freebuf (p_buf1);
+ }
+ else
+ p_buf = (BT_HDR *)GKI_getnext (p_buf);
+ }
+ }
+
+ /* If needed, flush buffers in the CCB xmit hold queue */
+ while ( (num_to_flush != 0) && (p_ccb->xmit_hold_q.count != 0) )
+ {
+ p_buf = (BT_HDR *)GKI_dequeue (&p_ccb->xmit_hold_q);
+ if (p_buf)
+ GKI_freebuf (p_buf);
+ num_to_flush--;
+ num_flushed2++;
+ }
+
+ /* If app needs to track all packets, call him */
+ if ( (p_ccb->p_rcb) && (p_ccb->p_rcb->api.pL2CA_TxComplete_Cb) && (num_flushed2) )
+ (*p_ccb->p_rcb->api.pL2CA_TxComplete_Cb)(p_ccb->local_cid, num_flushed2);
+
+ /* Now count how many are left */
+ p_buf = (BT_HDR *)p_lcb->link_xmit_data_q.p_first;
+
+ while (p_buf != NULL)
+ {
+ if (p_buf->event == lcid)
+ num_left++;
+
+ p_buf = (BT_HDR *)GKI_getnext (p_buf);
+ }
+
+ /* Add in the number in the CCB xmit queue */
+ num_left += p_ccb->xmit_hold_q.count;
+
+ /* Return the local number of buffers left for the CID */
+ L2CAP_TRACE_DEBUG3 ("L2CA_FlushChannel() flushed: %u + %u, num_left: %u", num_flushed1, num_flushed2, num_left);
+
+ /* If we were congested, and now we are not, tell the app */
+ l2cu_check_channel_congestion (p_ccb);
+
+ return (num_left);
+}
+
diff --git a/stack/l2cap/l2c_ble.c b/stack/l2cap/l2c_ble.c
new file mode 100644
index 0000000..8c69dee
--- /dev/null
+++ b/stack/l2cap/l2c_ble.c
@@ -0,0 +1,585 @@
+/*****************************************************************************
+**
+** Name: l2c_ble.c
+**
+** Description: this file contains functions relating to BLE management.
+**
+**
+** Copyright (c) 2009-2012, Broadcom Corp, All Rights Reserved.
+******************************************************************************/
+
+#include <string.h>
+#include "bt_target.h"
+#include "l2cdefs.h"
+#include "l2c_int.h"
+#include "btu.h"
+#include "btm_int.h"
+#include "hcimsgs.h"
+
+#if (BLE_INCLUDED == TRUE)
+
+/*******************************************************************************
+**
+** Function L2CA_CancelBleConnectReq
+**
+** Description Cancel a pending connection attempt to a BLE device.
+**
+** Parameters: BD Address of remote
+**
+** Return value: TRUE if connection was cancelled
+**
+*******************************************************************************/
+BOOLEAN L2CA_CancelBleConnectReq (BD_ADDR rem_bda)
+{
+ tL2C_LCB *p_lcb;
+
+ /* There can be only one BLE connection request outstanding at a time */
+ if (!l2cb.is_ble_connecting)
+ {
+ L2CAP_TRACE_WARNING0 ("L2CA_CancelBleConnectReq - no connection pending");
+ return(FALSE);
+ }
+
+ if (memcmp (rem_bda, l2cb.ble_connecting_bda, BD_ADDR_LEN))
+ {
+ L2CAP_TRACE_WARNING4 ("L2CA_CancelBleConnectReq - different BDA Connecting: %08x%04x Cancel: %08x%04x",
+ (l2cb.ble_connecting_bda[0]<<24)+(l2cb.ble_connecting_bda[1]<<16)+(l2cb.ble_connecting_bda[2]<<8)+l2cb.ble_connecting_bda[3],
+ (l2cb.ble_connecting_bda[4]<<8)+l2cb.ble_connecting_bda[5],
+ (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3], (rem_bda[4]<<8)+rem_bda[5]);
+
+ return(FALSE);
+ }
+
+ if (btsnd_hcic_ble_create_conn_cancel())
+ {
+
+ if ((p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda)) != NULL)
+ {
+ p_lcb->disc_reason = L2CAP_CONN_CANCEL;
+ l2cu_release_lcb (p_lcb);
+ }
+
+ l2cb.is_ble_connecting = FALSE;
+ btm_ble_update_bg_state();
+ btm_ble_resume_bg_conn(NULL, TRUE);
+
+ return(TRUE);
+ }
+ else
+ return(FALSE);
+}
+
+
+/*******************************************************************************
+**
+** Function L2CA_UpdateBleConnParams
+**
+** Description Update BLE connection parameters.
+**
+** Parameters: BD Address of remote
+**
+** Return value: TRUE if update started
+**
+*******************************************************************************/
+BOOLEAN L2CA_UpdateBleConnParams (BD_ADDR rem_bda, UINT16 min_int, UINT16 max_int, UINT16 latency, UINT16 timeout)
+{
+ tL2C_LCB *p_lcb;
+
+ /* See if we have a link control block for the remote device */
+ p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda);
+
+ /* If we don't have one, create one and accept the connection. */
+ if (!p_lcb)
+ {
+ L2CAP_TRACE_WARNING2 ("L2CA_UpdateBleConnParams - unknown BD_ADDR %08x%04x",
+ (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3], (rem_bda[4]<<8)+rem_bda[5]);
+ return(FALSE);
+ }
+
+ if (!p_lcb->is_ble_link)
+ {
+ L2CAP_TRACE_WARNING2 ("L2CA_UpdateBleConnParams - BD_ADDR %08x%04x not LE",
+ (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3], (rem_bda[4]<<8)+rem_bda[5]);
+ return(FALSE);
+ }
+
+ if (p_lcb->link_role == HCI_ROLE_MASTER)
+ btsnd_hcic_ble_upd_ll_conn_params (p_lcb->handle, min_int, max_int, latency, timeout, 0, 0);
+ else
+ l2cu_send_peer_ble_par_req (p_lcb, min_int, max_int, latency, timeout);
+
+ return(TRUE);
+}
+
+
+/*******************************************************************************
+**
+** Function L2CA_EnableUpdateBleConnParams
+**
+** Description Enable or disable update based on the request from the peer
+**
+** Parameters: BD Address of remote
+**
+** Return value: TRUE if update started
+**
+*******************************************************************************/
+BOOLEAN L2CA_EnableUpdateBleConnParams (BD_ADDR rem_bda, BOOLEAN enable)
+{
+ tL2C_LCB *p_lcb;
+
+ /* See if we have a link control block for the remote device */
+ p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda);
+
+ /* If we don't have one, create one and accept the connection. */
+ if (!p_lcb)
+ {
+ L2CAP_TRACE_WARNING2 ("L2CA_EnableUpdateBleConnParams - unknown BD_ADDR %08x%04x",
+ (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3], (rem_bda[4]<<8)+rem_bda[5]);
+ return (FALSE);
+ }
+
+ L2CAP_TRACE_API4 ("L2CA_EnableUpdateBleConnParams - BD_ADDR %08x%04x enable %d current upd state %d",
+ (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3], (rem_bda[4]<<8)+rem_bda[5], enable, p_lcb->upd_disabled);
+
+ if (!p_lcb->is_ble_link || (p_lcb->link_role != HCI_ROLE_MASTER))
+ {
+ L2CAP_TRACE_WARNING3 ("L2CA_EnableUpdateBleConnParams - BD_ADDR %08x%04x not LE or not master %d",
+ (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3], (rem_bda[4]<<8)+rem_bda[5], p_lcb->link_role);
+ return (FALSE);
+ }
+
+ if (enable)
+ {
+ /* application allows to do update, if we were delaying one do it now, otherwise
+ just mark lcb that updates are enabled */
+ if (p_lcb->upd_disabled == UPD_PENDING)
+ {
+ btsnd_hcic_ble_upd_ll_conn_params (p_lcb->handle, p_lcb->min_interval, p_lcb->max_interval,
+ p_lcb->latency, p_lcb->timeout, 0, 0);
+ p_lcb->upd_disabled = UPD_UPDATED;
+ }
+ else
+ {
+ p_lcb->upd_disabled = UPD_ENABLED;
+ }
+ }
+ else
+ {
+ /* application requests to disable parameters update. If parameters are already updated, lets set them
+ up to what has been requested during connection establishement */
+ if (p_lcb->upd_disabled == UPD_UPDATED)
+ {
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_or_alloc_dev (rem_bda);
+
+ btsnd_hcic_ble_upd_ll_conn_params (p_lcb->handle,
+ (UINT16)((p_dev_rec->conn_params.min_conn_int != BTM_BLE_CONN_PARAM_UNDEF) ? p_dev_rec->conn_params.min_conn_int : L2CAP_LE_INT_MIN),
+ (UINT16)((p_dev_rec->conn_params.max_conn_int != BTM_BLE_CONN_PARAM_UNDEF) ? p_dev_rec->conn_params.max_conn_int : L2CAP_LE_INT_MAX),
+ (UINT16)((p_dev_rec->conn_params.slave_latency != BTM_BLE_CONN_PARAM_UNDEF) ? p_dev_rec->conn_params.slave_latency : 0),
+ (UINT16) ((p_dev_rec->conn_params.supervision_tout != BTM_BLE_CONN_PARAM_UNDEF) ? p_dev_rec->conn_params.supervision_tout : L2CAP_LE_TIMEOUT_MAX),
+ 0, 0);
+ }
+ p_lcb->upd_disabled = UPD_DISABLED;
+ }
+
+ return (TRUE);
+}
+
+/*******************************************************************************
+**
+** Function L2CA_GetBleConnRole
+**
+** Description This function returns the connection role.
+**
+** Returns link role.
+**
+*******************************************************************************/
+UINT8 L2CA_GetBleConnRole (BD_ADDR bd_addr)
+{
+ UINT8 role = HCI_ROLE_UNKNOWN;
+
+ tL2C_LCB *p_lcb;
+
+ if ((p_lcb = l2cu_find_lcb_by_bd_addr (bd_addr)) != NULL)
+ role = p_lcb->link_role;
+
+ return role;
+}
+/*******************************************************************************
+**
+** Function L2CA_GetDisconnectReason
+**
+** Description This function returns the disconnect reason code.
+**
+** Returns disconnect reason
+**
+*******************************************************************************/
+UINT16 L2CA_GetDisconnectReason (BD_ADDR remote_bda)
+{
+ tL2C_LCB *p_lcb;
+ UINT16 reason = 0;
+
+ if ((p_lcb = l2cu_find_lcb_by_bd_addr (remote_bda)) != NULL)
+ reason = p_lcb->disc_reason;
+
+ L2CAP_TRACE_DEBUG1 ("L2CA_GetDisconnectReason=%d ",reason);
+
+ return reason;
+}
+
+/*******************************************************************************
+**
+** Function l2cble_scanner_conn_comp
+**
+** Description This function is called when an HCI Connection Complete
+** event is received while we are a scanner (so we are master).
+**
+** Returns void
+**
+*******************************************************************************/
+void l2cble_scanner_conn_comp (UINT16 handle, BD_ADDR bda, tBLE_ADDR_TYPE type, UINT16 conn_interval, UINT16 conn_latency, UINT16 conn_timeout)
+{
+ tL2C_LCB *p_lcb;
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_or_alloc_dev (bda);
+
+ L2CAP_TRACE_DEBUG5 ("l2cble_scanner_conn_comp: HANDLE=%d addr_type=%d conn_interval=%d slave_latency=%d supervision_tout=%d",
+ handle, type, conn_interval, conn_latency, conn_timeout);
+
+ l2cb.is_ble_connecting = FALSE;
+
+ p_dev_rec->device_type = BT_DEVICE_TYPE_BLE;
+ p_dev_rec->ble.ble_addr_type = type;
+
+ /* See if we have a link control block for the remote device */
+ p_lcb = l2cu_find_lcb_by_bd_addr (bda);
+
+ /* If we don't have one, create one. this is auto connection complete. */
+ if (!p_lcb)
+ {
+ p_lcb = l2cu_allocate_lcb (bda, FALSE);
+ if (!p_lcb)
+ {
+ btm_sec_disconnect (handle, HCI_ERR_NO_CONNECTION);
+ L2CAP_TRACE_ERROR0 ("l2cble_scanner_conn_comp - failed to allocate LCB");
+ return;
+ }
+ else
+ {
+ if (!l2cu_initialize_fixed_ccb (p_lcb, L2CAP_ATT_CID, &l2cb.fixed_reg[L2CAP_ATT_CID - L2CAP_FIRST_FIXED_CHNL].fixed_chnl_opts))
+ {
+ btm_sec_disconnect (handle, HCI_ERR_NO_CONNECTION);
+ L2CAP_TRACE_WARNING0 ("l2cble_scanner_conn_comp - LCB but no CCB");
+ return ;
+ }
+ }
+ }
+ else if (p_lcb->link_state != LST_CONNECTING)
+ {
+ L2CAP_TRACE_ERROR1 ("L2CAP got BLE scanner conn_comp in bad state: %d", p_lcb->link_state);
+ return;
+ }
+ btu_stop_timer(&p_lcb->timer_entry);
+
+ /* Save the handle */
+ p_lcb->handle = handle;
+
+ /* Connected OK. Change state to connected, we were scanning so we are master */
+ p_lcb->link_state = LST_CONNECTED;
+ p_lcb->link_role = HCI_ROLE_MASTER;
+ p_lcb->is_ble_link = TRUE;
+
+ /* If there are any preferred connection parameters, set them now */
+ if ( (p_dev_rec->conn_params.min_conn_int >= L2CAP_LE_INT_MIN ) &&
+ (p_dev_rec->conn_params.min_conn_int <= L2CAP_LE_INT_MAX ) &&
+ (p_dev_rec->conn_params.max_conn_int >= L2CAP_LE_INT_MIN ) &&
+ (p_dev_rec->conn_params.max_conn_int <= L2CAP_LE_INT_MAX ) &&
+ (p_dev_rec->conn_params.slave_latency <= L2CAP_LE_LATENCY_MAX ) &&
+ (p_dev_rec->conn_params.supervision_tout >= L2CAP_LE_TIMEOUT_MIN) &&
+ (p_dev_rec->conn_params.supervision_tout <= L2CAP_LE_TIMEOUT_MAX) &&
+ ((conn_interval < p_dev_rec->conn_params.min_conn_int &&
+ p_dev_rec->conn_params.min_conn_int != BTM_BLE_CONN_PARAM_UNDEF) ||
+ (conn_interval > p_dev_rec->conn_params.max_conn_int) ||
+ (conn_latency > p_dev_rec->conn_params.slave_latency) ||
+ (conn_timeout > p_dev_rec->conn_params.supervision_tout)))
+ {
+ L2CAP_TRACE_ERROR5 ("upd_ll_conn_params: HANDLE=%d min_conn_int=%d max_conn_int=%d slave_latency=%d supervision_tout=%d",
+ handle, p_dev_rec->conn_params.min_conn_int, p_dev_rec->conn_params.max_conn_int,
+ p_dev_rec->conn_params.slave_latency, p_dev_rec->conn_params.supervision_tout);
+
+ btsnd_hcic_ble_upd_ll_conn_params (handle,
+ p_dev_rec->conn_params.min_conn_int,
+ p_dev_rec->conn_params.max_conn_int,
+ p_dev_rec->conn_params.slave_latency,
+ p_dev_rec->conn_params.supervision_tout,
+ 0, 0);
+ }
+
+ /* Tell BTM Acl management about the link */
+ btm_acl_created (bda, NULL, p_dev_rec->sec_bd_name, handle, p_lcb->link_role, TRUE);
+
+ if (p_lcb->p_echo_rsp_cb)
+ {
+ L2CAP_TRACE_ERROR0 ("l2cu_send_peer_echo_req");
+ l2cu_send_peer_echo_req (p_lcb, NULL, 0);
+ }
+
+ p_lcb->peer_chnl_mask[0] = L2CAP_FIXED_CHNL_ATT_BIT | L2CAP_FIXED_CHNL_BLE_SIG_BIT | L2CAP_FIXED_CHNL_SMP_BIT;
+
+ l2cu_process_fixed_chnl_resp (p_lcb);
+}
+
+
+/*******************************************************************************
+**
+** Function l2cble_advertiser_conn_comp
+**
+** Description This function is called when an HCI Connection Complete
+** event is received while we are an advertiser (so we are slave).
+**
+** Returns void
+**
+*******************************************************************************/
+void l2cble_advertiser_conn_comp (UINT16 handle, BD_ADDR bda, tBLE_ADDR_TYPE type,
+ UINT16 conn_interval, UINT16 conn_latency, UINT16 conn_timeout)
+{
+ tL2C_LCB *p_lcb;
+ tBTM_SEC_DEV_REC *p_dev_rec;
+
+ /* See if we have a link control block for the remote device */
+ p_lcb = l2cu_find_lcb_by_bd_addr (bda);
+
+ /* If we don't have one, create one and accept the connection. */
+ if (!p_lcb)
+ {
+ p_lcb = l2cu_allocate_lcb (bda, FALSE);
+ if (!p_lcb)
+ {
+ btm_sec_disconnect (handle, HCI_ERR_NO_CONNECTION);
+ L2CAP_TRACE_ERROR0 ("l2cble_advertiser_conn_comp - failed to allocate LCB");
+ return;
+ }
+ else
+ {
+ if (!l2cu_initialize_fixed_ccb (p_lcb, L2CAP_ATT_CID, &l2cb.fixed_reg[L2CAP_ATT_CID - L2CAP_FIRST_FIXED_CHNL].fixed_chnl_opts))
+ {
+ btm_sec_disconnect (handle, HCI_ERR_NO_CONNECTION);
+ L2CAP_TRACE_WARNING0 ("l2cble_scanner_conn_comp - LCB but no CCB");
+ return ;
+ }
+ }
+ }
+
+ /* Save the handle */
+ p_lcb->handle = handle;
+
+ /* Connected OK. Change state to connected, we were advertising, so we are slave */
+ p_lcb->link_state = LST_CONNECTED;
+ p_lcb->link_role = HCI_ROLE_SLAVE;
+ p_lcb->is_ble_link = TRUE;
+
+ /* Tell BTM Acl management about the link */
+ p_dev_rec = btm_find_or_alloc_dev (bda);
+
+ p_dev_rec->device_type = BT_DEVICE_TYPE_BLE;
+ p_dev_rec->ble.ble_addr_type = type;
+
+ btm_acl_created (bda, NULL, p_dev_rec->sec_bd_name, handle, p_lcb->link_role, TRUE);
+
+ p_lcb->peer_chnl_mask[0] = L2CAP_FIXED_CHNL_ATT_BIT | L2CAP_FIXED_CHNL_BLE_SIG_BIT | L2CAP_FIXED_CHNL_SMP_BIT;
+
+ l2cu_process_fixed_chnl_resp (p_lcb);
+}
+
+/*******************************************************************************
+**
+** Function l2cble_conn_comp
+**
+** Description This function is called when an HCI Connection Complete
+** event is received.
+**
+** Returns void
+**
+*******************************************************************************/
+void l2cble_conn_comp(UINT16 handle, UINT8 role, BD_ADDR bda, tBLE_ADDR_TYPE type,
+ UINT16 conn_interval, UINT16 conn_latency, UINT16 conn_timeout)
+{
+ if (role == HCI_ROLE_MASTER)
+ {
+ l2cble_scanner_conn_comp(handle, bda, type, conn_interval, conn_latency, conn_timeout);
+ }
+ else
+ {
+ l2cble_advertiser_conn_comp(handle, bda, type, conn_interval, conn_latency, conn_timeout);
+ }
+}
+/*******************************************************************************
+**
+** Function l2cble_process_sig_cmd
+**
+** Description This function is called when a signalling packet is received
+** on the BLE signalling CID
+**
+** Returns void
+**
+*******************************************************************************/
+void l2cble_process_sig_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
+{
+ UINT8 *p_pkt_end;
+ UINT8 cmd_code, id;
+ UINT16 cmd_len, rej_reason;
+ UINT16 result;
+ UINT16 min_interval, max_interval, latency, timeout;
+
+ p_pkt_end = p + pkt_len;
+
+ STREAM_TO_UINT8 (cmd_code, p);
+ STREAM_TO_UINT8 (id, p);
+ STREAM_TO_UINT16 (cmd_len, p);
+
+ /* Check command length does not exceed packet length */
+ if ((p + cmd_len) > p_pkt_end)
+ {
+ L2CAP_TRACE_WARNING3 ("L2CAP - LE - format error, pkt_len: %d cmd_len: %d code: %d", pkt_len, cmd_len, cmd_code);
+ return;
+ }
+
+ switch (cmd_code)
+ {
+ case L2CAP_CMD_REJECT:
+ case L2CAP_CMD_ECHO_RSP:
+ case L2CAP_CMD_INFO_RSP:
+ STREAM_TO_UINT16 (rej_reason, p);
+ break;
+ case L2CAP_CMD_ECHO_REQ:
+ case L2CAP_CMD_INFO_REQ:
+ l2cu_send_peer_cmd_reject (p_lcb, L2CAP_CMD_REJ_NOT_UNDERSTOOD, id, 0, 0);
+ break;
+
+ case L2CAP_CMD_BLE_UPDATE_REQ:
+ STREAM_TO_UINT16 (min_interval, p); /* 0x0006 - 0x0C80 */
+ STREAM_TO_UINT16 (max_interval, p); /* 0x0006 - 0x0C80 */
+ STREAM_TO_UINT16 (latency, p); /* 0x0000 - 0x03E8 */
+ STREAM_TO_UINT16 (timeout, p); /* 0x000A - 0x0C80 */
+ /* If we are a master, the slave wants to update the parameters */
+ if (p_lcb->link_role == HCI_ROLE_MASTER)
+ {
+ if (min_interval < L2CAP_LE_INT_MIN || min_interval > L2CAP_LE_INT_MAX ||
+ max_interval < L2CAP_LE_INT_MIN || max_interval > L2CAP_LE_INT_MAX ||
+ latency > L2CAP_LE_LATENCY_MAX ||
+ /*(timeout >= max_interval && latency > (timeout * 10/(max_interval * 1.25) - 1)) ||*/
+ timeout < L2CAP_LE_TIMEOUT_MIN || timeout > L2CAP_LE_TIMEOUT_MAX ||
+ max_interval < min_interval)
+ {
+ result = L2CAP_CFG_UNACCEPTABLE_PARAMS;
+ }
+ else
+ {
+
+ l2cu_send_peer_ble_par_rsp (p_lcb, L2CAP_CFG_OK, id);
+
+ p_lcb->min_interval = min_interval;
+ p_lcb->max_interval = max_interval;
+ p_lcb->latency = latency;
+ p_lcb->timeout = timeout;
+
+ if (p_lcb->upd_disabled == UPD_ENABLED)
+ {
+ btsnd_hcic_ble_upd_ll_conn_params (p_lcb->handle, min_interval, max_interval,
+ latency, timeout, 0, 0);
+ p_lcb->upd_disabled = UPD_UPDATED;
+ }
+ else
+ {
+ L2CAP_TRACE_EVENT0 ("L2CAP - LE - update currently disabled");
+ p_lcb->upd_disabled = UPD_PENDING;
+ }
+ }
+ }
+ else
+ l2cu_send_peer_cmd_reject (p_lcb, L2CAP_CMD_REJ_NOT_UNDERSTOOD, id, 0, 0);
+ break;
+
+ case L2CAP_CMD_BLE_UPDATE_RSP:
+ STREAM_TO_UINT16 (result, p);
+ break;
+
+ default:
+ L2CAP_TRACE_WARNING1 ("L2CAP - LE - unknown cmd code: %d", cmd_code);
+ l2cu_send_peer_cmd_reject (p_lcb, L2CAP_CMD_REJ_NOT_UNDERSTOOD, id, 0, 0);
+ return;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function l2cble_create_conn
+**
+** Description This function initiates an acl connection via HCI
+**
+** Returns TRUE if successful, FALSE if connection not started.
+**
+*******************************************************************************/
+BOOLEAN l2cble_create_conn (tL2C_LCB *p_lcb)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_or_alloc_dev (p_lcb->remote_bd_addr);
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+ UINT16 scan_int, scan_win;
+
+ /* There can be only one BLE connection request outstanding at a time */
+ if (l2cb.is_ble_connecting)
+ {
+ L2CAP_TRACE_WARNING0 ("L2CAP - LE - cannot start new connection, already connecting");
+ return(FALSE);
+ }
+
+ p_lcb->link_state = LST_CONNECTING;
+ l2cb.is_ble_connecting = TRUE;
+
+ memcpy (l2cb.ble_connecting_bda, p_lcb->remote_bd_addr, BD_ADDR_LEN);
+ btm_ble_suspend_bg_conn();
+
+ scan_int = (p_cb->scan_int == BTM_BLE_CONN_PARAM_UNDEF) ? L2CAP_LE_INT_MIN : p_cb->scan_int;
+ scan_win = (p_cb->scan_win == BTM_BLE_CONN_PARAM_UNDEF) ? L2CAP_LE_INT_MIN : p_cb->scan_win;
+
+ if (!btsnd_hcic_ble_create_ll_conn (scan_int,/* UINT16 scan_int */
+ scan_win, /* UINT16 scan_win */
+ FALSE, /* UINT8 white_list */
+ p_lcb->ble_addr_type, /* UINT8 addr_type_peer */
+ p_lcb->remote_bd_addr, /* BD_ADDR bda_peer */
+ BLE_ADDR_PUBLIC, /* UINT8 addr_type_own */
+ (UINT16) ((p_dev_rec->conn_params.min_conn_int != BTM_BLE_CONN_PARAM_UNDEF) ? p_dev_rec->conn_params.min_conn_int : L2CAP_LE_INT_MIN), /* UINT16 conn_int_min */
+ (UINT16) ((p_dev_rec->conn_params.max_conn_int != BTM_BLE_CONN_PARAM_UNDEF) ? p_dev_rec->conn_params.max_conn_int : L2CAP_LE_INT_MIN), /* UINT16 conn_int_max */
+ (UINT16) ((p_dev_rec->conn_params.slave_latency != BTM_BLE_CONN_PARAM_UNDEF) ? p_dev_rec->conn_params.slave_latency : 0), /* UINT16 conn_latency */
+ (UINT16) ((p_dev_rec->conn_params.supervision_tout != BTM_BLE_CONN_PARAM_UNDEF) ? p_dev_rec->conn_params.supervision_tout : L2CAP_LE_TIMEOUT_MAX), /* UINT16 conn_timeout */
+ 0, /* UINT16 min_len */
+ 0)) /* UINT16 max_len */
+ {
+ /* No buffer for connection request ? */
+ l2cb.is_ble_connecting = FALSE;
+ p_lcb->disc_reason = L2CAP_CONN_NO_RESOURCES;
+ l2cu_release_lcb (p_lcb);
+ return(FALSE);
+ }
+ else
+ btu_start_timer (&p_lcb->timer_entry, BTU_TTYPE_L2CAP_LINK, L2CAP_BLE_LINK_CONNECT_TOUT);
+
+ return(TRUE);
+}
+
+/*******************************************************************************
+**
+** Function l2c_link_processs_ble_num_bufs
+**
+** Description This function is called when a "controller buffer size"
+** event is first received from the controller. It updates
+** the L2CAP values.
+**
+** Returns void
+**
+*******************************************************************************/
+void l2c_link_processs_ble_num_bufs (UINT16 num_lm_ble_bufs)
+{
+ l2cb.num_lm_ble_bufs = l2cb.controller_le_xmit_window = num_lm_ble_bufs;
+}
+
+#endif /* (BLE_INCLUDED == TRUE) */
diff --git a/stack/l2cap/l2c_csm.c b/stack/l2cap/l2c_csm.c
new file mode 100644
index 0000000..216f45b
--- /dev/null
+++ b/stack/l2cap/l2c_csm.c
@@ -0,0 +1,1321 @@
+/*****************************************************************************
+**
+** Name: l2c_csm.c
+**
+** Description: This file contains the L2CAP channel state machine
+**
+**
+**
+** Copyright (c) 1999-2011, Broadcom Corp, All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "bt_target.h"
+#include "gki.h"
+#include "hcidefs.h"
+#include "hcimsgs.h"
+#include "l2cdefs.h"
+#include "l2c_int.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "hcimsgs.h"
+
+/********************************************************************************/
+/* L O C A L F U N C T I O N P R O T O T Y P E S */
+/********************************************************************************/
+static void l2c_csm_closed (tL2C_CCB *p_ccb, UINT16 event, void *p_data);
+static void l2c_csm_orig_w4_sec_comp (tL2C_CCB *p_ccb, UINT16 event, void *p_data);
+static void l2c_csm_term_w4_sec_comp (tL2C_CCB *p_ccb, UINT16 event, void *p_data);
+static void l2c_csm_w4_l2cap_connect_rsp (tL2C_CCB *p_ccb, UINT16 event, void *p_data);
+static void l2c_csm_w4_l2ca_connect_rsp (tL2C_CCB *p_ccb, UINT16 event, void *p_data);
+static void l2c_csm_config (tL2C_CCB *p_ccb, UINT16 event, void *p_data);
+static void l2c_csm_open (tL2C_CCB *p_ccb, UINT16 event, void *p_data);
+static void l2c_csm_w4_l2cap_disconnect_rsp (tL2C_CCB *p_ccb, UINT16 event, void *p_data);
+static void l2c_csm_w4_l2ca_disconnect_rsp (tL2C_CCB *p_ccb, UINT16 event, void *p_data);
+
+#if (BT_TRACE_VERBOSE == TRUE)
+static char *l2c_csm_get_event_name (UINT16 event);
+#endif
+
+/*******************************************************************************
+**
+** Function l2c_csm_execute
+**
+** Description This function executes the state machine.
+**
+** Returns void
+**
+*******************************************************************************/
+void l2c_csm_execute (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
+{
+ switch (p_ccb->chnl_state)
+ {
+ case CST_CLOSED:
+ l2c_csm_closed (p_ccb, event, p_data);
+ break;
+
+ case CST_ORIG_W4_SEC_COMP:
+ l2c_csm_orig_w4_sec_comp (p_ccb, event, p_data);
+ break;
+
+ case CST_TERM_W4_SEC_COMP:
+ l2c_csm_term_w4_sec_comp (p_ccb, event, p_data);
+ break;
+
+ case CST_W4_L2CAP_CONNECT_RSP:
+ l2c_csm_w4_l2cap_connect_rsp (p_ccb, event, p_data);
+ break;
+
+ case CST_W4_L2CA_CONNECT_RSP:
+ l2c_csm_w4_l2ca_connect_rsp (p_ccb, event, p_data);
+ break;
+
+ case CST_CONFIG:
+ l2c_csm_config (p_ccb, event, p_data);
+ break;
+
+ case CST_OPEN:
+ l2c_csm_open (p_ccb, event, p_data);
+ break;
+
+ case CST_W4_L2CAP_DISCONNECT_RSP:
+ l2c_csm_w4_l2cap_disconnect_rsp (p_ccb, event, p_data);
+ break;
+
+ case CST_W4_L2CA_DISCONNECT_RSP:
+ l2c_csm_w4_l2ca_disconnect_rsp (p_ccb, event, p_data);
+ break;
+
+ default:
+ break;
+ }
+}
+
+/*******************************************************************************
+**
+** Function l2c_csm_closed
+**
+** Description This function handles events when the channel is in
+** CLOSED state. This state exists only when the link is
+** being initially established.
+**
+** Returns void
+**
+*******************************************************************************/
+static void l2c_csm_closed (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
+{
+ tL2C_CONN_INFO *p_ci = (tL2C_CONN_INFO *)p_data;
+ UINT16 local_cid = p_ccb->local_cid;
+ tL2CA_DISCONNECT_IND_CB *disconnect_ind;
+ tL2CA_CONNECT_CFM_CB *connect_cfm;
+
+ if (p_ccb->p_rcb == NULL)
+ {
+#if (BT_TRACE_VERBOSE == TRUE)
+ L2CAP_TRACE_ERROR2 ("L2CAP - LCID: 0x%04x st: CLOSED evt: %s p_rcb == NULL", p_ccb->local_cid, l2c_csm_get_event_name (event));
+#else
+ L2CAP_TRACE_ERROR2 ("L2CAP - LCID: 0x%04x st: CLOSED evt: 0x%04x p_rcb == NULL", p_ccb->local_cid, event);
+#endif
+ return;
+ }
+
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ if ( local_cid == L2CAP_CONNECTIONLESS_CID )
+ {
+ /* check if this event can be processed by UCD */
+ if ( l2c_ucd_process_event (p_ccb, event, p_data) )
+ {
+ /* The event is processed by UCD state machine */
+ return;
+ }
+ }
+#endif
+
+ disconnect_ind = p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb;
+ connect_cfm = p_ccb->p_rcb->api.pL2CA_ConnectCfm_Cb;
+
+#if (BT_TRACE_VERBOSE == TRUE)
+ L2CAP_TRACE_EVENT2 ("L2CAP - LCID: 0x%04x st: CLOSED evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event));
+#else
+ L2CAP_TRACE_EVENT1 ("L2CAP - st: CLOSED evt: %d", event);
+#endif
+
+ switch (event)
+ {
+ case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */
+ L2CAP_TRACE_API1 ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed", p_ccb->local_cid);
+ l2cu_release_ccb (p_ccb);
+ (*disconnect_ind)(local_cid, FALSE);
+ break;
+
+ case L2CEVT_LP_CONNECT_CFM: /* Link came up */
+ p_ccb->chnl_state = CST_ORIG_W4_SEC_COMP;
+ btm_sec_l2cap_access_req (p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm,
+ p_ccb->p_lcb->handle, TRUE, &l2c_link_sec_comp, p_ccb);
+ break;
+
+ case L2CEVT_LP_CONNECT_CFM_NEG: /* Link failed */
+ /* Disconnect unless ACL collision and upper layer wants to handle it */
+ if (p_ci->status != HCI_ERR_CONNECTION_EXISTS
+ || !btm_acl_notif_conn_collision(p_ccb->p_lcb->remote_bd_addr))
+ {
+ L2CAP_TRACE_API2 ("L2CAP - Calling ConnectCfm_Cb(), CID: 0x%04x Status: %d", p_ccb->local_cid, p_ci->status);
+ l2cu_release_ccb (p_ccb);
+ (*connect_cfm)(local_cid, p_ci->status);
+ }
+ break;
+
+ case L2CEVT_L2CA_CONNECT_REQ: /* API connect request */
+ /* Cancel sniff mode if needed */
+#if BTM_PWR_MGR_INCLUDED == TRUE
+ {
+ tBTM_PM_PWR_MD settings;
+// btla-specific ++
+ memset((void*)&settings, 0, sizeof(settings));
+// btla-specific --
+ settings.mode = BTM_PM_MD_ACTIVE;
+/* COVERITY
+Event uninit_use_in_call: Using uninitialized value "settings" (field "settings".timeout uninitialized) in call to function "BTM_SetPowerMode" [details]
+Event uninit_use_in_call: Using uninitialized value "settings.max" in call to function "BTM_SetPowerMode" [details]
+Event uninit_use_in_call: Using uninitialized value "settings.min" in call to function "BTM_SetPowerMode"
+// FALSE-POSITIVE error from Coverity test-tool. Please do NOT remove following comment.
+// coverity[uninit_use_in_call] False-positive: setting the mode to BTM_PM_MD_ACTIVE only uses settings.mode the other data members of tBTM_PM_PWR_MD are ignored
+*/
+ BTM_SetPowerMode (BTM_PM_SET_ONLY_ID, p_ccb->p_lcb->remote_bd_addr, &settings);
+ }
+#else
+ BTM_CancelSniffMode (p_ccb->p_lcb->remote_bd_addr);
+#endif
+
+ /* If sec access does not result in started SEC_COM or COMP_NEG are already processed */
+ if (btm_sec_l2cap_access_req (p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm,
+ p_ccb->p_lcb->handle, TRUE, &l2c_link_sec_comp, p_ccb) == BTM_CMD_STARTED)
+ p_ccb->chnl_state = CST_ORIG_W4_SEC_COMP;
+ break;
+
+ case L2CEVT_SEC_COMP:
+ p_ccb->chnl_state = CST_W4_L2CAP_CONNECT_RSP;
+
+ /* Wait for the info resp in this state before sending connect req (if needed) */
+ if (!p_ccb->p_lcb->w4_info_rsp)
+ {
+ /* Need to have at least one compatible channel to continue */
+ if (!l2c_fcr_chk_chan_modes(p_ccb))
+ {
+ l2cu_release_ccb (p_ccb);
+ (*p_ccb->p_rcb->api.pL2CA_ConnectCfm_Cb)(local_cid, L2CAP_CONN_NO_LINK);
+ }
+ else
+ {
+ l2cu_send_peer_connect_req (p_ccb);
+ btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CONNECT_TOUT);
+ }
+ }
+ break;
+
+ case L2CEVT_SEC_COMP_NEG: /* something is really bad with security */
+ L2CAP_TRACE_API2 ("L2CAP - Calling ConnectCfm_Cb(), CID: 0x%04x Status: %d", p_ccb->local_cid, L2CAP_CONN_TIMEOUT);
+ l2cu_release_ccb (p_ccb);
+ (*connect_cfm)(local_cid, L2CAP_CONN_SECURITY_BLOCK);
+ break;
+
+ case L2CEVT_L2CAP_CONNECT_REQ: /* Peer connect request */
+ /* stop link timer to avoid race condition between A2MP, Security, and L2CAP */
+ btu_stop_timer (&p_ccb->p_lcb->timer_entry);
+
+ /* Cancel sniff mode if needed */
+#if BTM_PWR_MGR_INCLUDED == TRUE
+ {
+ tBTM_PM_PWR_MD settings;
+// btla-specific ++
+ memset((void*)&settings, 0, sizeof(settings));
+// btla-specific --
+ settings.mode = BTM_PM_MD_ACTIVE;
+/* COVERITY
+Event uninit_use_in_call: Using uninitialized value "settings" (field "settings".timeout uninitialized) in call to function "BTM_SetPowerMode" [details]
+Event uninit_use_in_call: Using uninitialized value "settings.max" in call to function "BTM_SetPowerMode" [details]
+Event uninit_use_in_call: Using uninitialized value "settings.min" in call to function "BTM_SetPowerMode"
+// FALSE-POSITIVE error from Coverity test-tool. Please do NOT remove following comment.
+// coverity[uninit_use_in_call] False-positive: setting the mode to BTM_PM_MD_ACTIVE only uses settings.mode the other data members of tBTM_PM_PWR_MD are ignored
+*/
+ BTM_SetPowerMode (BTM_PM_SET_ONLY_ID, p_ccb->p_lcb->remote_bd_addr, &settings);
+ }
+#else
+ BTM_CancelSniffMode (p_ccb->p_lcb->remote_bd_addr);
+#endif
+
+ p_ccb->chnl_state = CST_TERM_W4_SEC_COMP;
+ if (btm_sec_l2cap_access_req (p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm,
+ p_ccb->p_lcb->handle, FALSE, &l2c_link_sec_comp, p_ccb) == BTM_CMD_STARTED)
+ {
+ /* started the security process, tell the peer to set a longer timer */
+ l2cu_send_peer_connect_rsp(p_ccb, L2CAP_CONN_PENDING, 0);
+ }
+ break;
+
+ case L2CEVT_TIMEOUT:
+ L2CAP_TRACE_API2 ("L2CAP - Calling ConnectCfm_Cb(), CID: 0x%04x Status: %d", p_ccb->local_cid, L2CAP_CONN_TIMEOUT);
+ l2cu_release_ccb (p_ccb);
+ (*connect_cfm)(local_cid, L2CAP_CONN_TIMEOUT);
+ break;
+
+ case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
+ case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
+ GKI_freebuf (p_data);
+ break;
+
+ case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper wants to disconnect */
+ l2cu_release_ccb (p_ccb);
+ break;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function l2c_csm_orig_w4_sec_comp
+**
+** Description This function handles events when the channel is in
+** CST_ORIG_W4_SEC_COMP state.
+**
+** Returns void
+**
+*******************************************************************************/
+static void l2c_csm_orig_w4_sec_comp (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
+{
+ tL2CA_DISCONNECT_IND_CB *disconnect_ind = p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb;
+ tL2CA_CONNECT_CFM_CB *connect_cfm = p_ccb->p_rcb->api.pL2CA_ConnectCfm_Cb;
+ UINT16 local_cid = p_ccb->local_cid;
+
+#if (BT_TRACE_VERBOSE == TRUE)
+ L2CAP_TRACE_EVENT2 ("L2CAP - LCID: 0x%04x st: ORIG_W4_SEC_COMP evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event));
+#else
+ L2CAP_TRACE_EVENT1 ("L2CAP - st: ORIG_W4_SEC_COMP evt: %d", event);
+#endif
+
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ if ( local_cid == L2CAP_CONNECTIONLESS_CID )
+ {
+ /* check if this event can be processed by UCD */
+ if ( l2c_ucd_process_event (p_ccb, event, p_data) )
+ {
+ /* The event is processed by UCD state machine */
+ return;
+ }
+ }
+#endif
+
+ switch (event)
+ {
+ case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */
+ L2CAP_TRACE_API1 ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed", p_ccb->local_cid);
+ l2cu_release_ccb (p_ccb);
+ (*disconnect_ind)(local_cid, FALSE);
+ break;
+
+ case L2CEVT_SEC_RE_SEND_CMD: /* BTM has enough info to proceed */
+ case L2CEVT_LP_CONNECT_CFM: /* Link came up */
+ btm_sec_l2cap_access_req (p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm,
+ p_ccb->p_lcb->handle, TRUE, &l2c_link_sec_comp, p_ccb);
+ break;
+
+ case L2CEVT_SEC_COMP: /* Security completed success */
+ /* Wait for the info resp in this state before sending connect req (if needed) */
+ p_ccb->chnl_state = CST_W4_L2CAP_CONNECT_RSP;
+ if (!p_ccb->p_lcb->w4_info_rsp)
+ {
+ /* Need to have at least one compatible channel to continue */
+ if (!l2c_fcr_chk_chan_modes(p_ccb))
+ {
+ l2cu_release_ccb (p_ccb);
+ (*connect_cfm)(local_cid, L2CAP_CONN_NO_LINK);
+ }
+ else
+ {
+ btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CONNECT_TOUT);
+ l2cu_send_peer_connect_req (p_ccb); /* Start Connection */
+ }
+ }
+ break;
+
+ case L2CEVT_SEC_COMP_NEG:
+ L2CAP_TRACE_API2 ("L2CAP - Calling ConnectCfm_Cb(), CID: 0x%04x Status: %d", p_ccb->local_cid, HCI_ERR_AUTH_FAILURE);
+
+ /* If last channel immediately disconnect the ACL for better security.
+ Also prevents a race condition between BTM and L2CAP */
+ if ( (p_ccb == p_ccb->p_lcb->ccb_queue.p_first_ccb) && (p_ccb == p_ccb->p_lcb->ccb_queue.p_last_ccb) )
+ {
+ p_ccb->p_lcb->idle_timeout = 0;
+ }
+
+ l2cu_release_ccb (p_ccb);
+ (*connect_cfm)(local_cid, HCI_ERR_AUTH_FAILURE);
+ break;
+
+ case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
+ case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
+ GKI_freebuf (p_data);
+ break;
+
+ case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper wants to disconnect */
+ /* Tell security manager to abort */
+ btm_sec_abort_access_req (p_ccb->p_lcb->remote_bd_addr);
+
+ l2cu_release_ccb (p_ccb);
+ break;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function l2c_csm_term_w4_sec_comp
+**
+** Description This function handles events when the channel is in
+** CST_TERM_W4_SEC_COMP state.
+**
+** Returns void
+**
+*******************************************************************************/
+static void l2c_csm_term_w4_sec_comp (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
+{
+#if (BT_TRACE_VERBOSE == TRUE)
+ L2CAP_TRACE_EVENT2 ("L2CAP - LCID: 0x%04x st: TERM_W4_SEC_COMP evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event));
+#else
+ L2CAP_TRACE_EVENT1 ("L2CAP - st: TERM_W4_SEC_COMP evt: %d", event);
+#endif
+
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ if ( p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID )
+ {
+ /* check if this event can be processed by UCD */
+ if ( l2c_ucd_process_event (p_ccb, event, p_data) )
+ {
+ /* The event is processed by UCD state machine */
+ return;
+ }
+ }
+#endif
+
+ switch (event)
+ {
+ case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */
+ /* Tell security manager to abort */
+ btm_sec_abort_access_req (p_ccb->p_lcb->remote_bd_addr);
+
+ l2cu_release_ccb (p_ccb);
+ break;
+
+ case L2CEVT_SEC_COMP:
+ p_ccb->chnl_state = CST_W4_L2CA_CONNECT_RSP;
+
+ /* Wait for the info resp in next state before sending connect ind (if needed) */
+ if (!p_ccb->p_lcb->w4_info_rsp)
+ {
+ /* Don't need to get info from peer or already retrieved so continue */
+ btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CONNECT_TOUT);
+ L2CAP_TRACE_API1 ("L2CAP - Calling Connect_Ind_Cb(), CID: 0x%04x", p_ccb->local_cid);
+
+ (*p_ccb->p_rcb->api.pL2CA_ConnectInd_Cb) (p_ccb->p_lcb->remote_bd_addr, p_ccb->local_cid,
+ p_ccb->p_rcb->psm, p_ccb->remote_id);
+ }
+ else
+ {
+ /*
+ ** L2CAP Connect Response will be sent out by 3 sec timer expiration
+ ** because Bluesoleil doesn't respond to L2CAP Information Request.
+ ** Bluesoleil seems to disconnect ACL link as failure case, because
+ ** it takes too long (4~7secs) to get response.
+ ** product version : Bluesoleil 2.1.1.0 EDR Release 060123
+ ** stack version : 05.04.11.20060119
+ */
+
+ /* Waiting for the info resp, tell the peer to set a longer timer */
+ l2cu_send_peer_connect_rsp(p_ccb, L2CAP_CONN_PENDING, 0);
+ }
+ break;
+
+ case L2CEVT_SEC_COMP_NEG:
+ if (((tL2C_CONN_INFO *)p_data)->status == BTM_DELAY_CHECK)
+ {
+ /* start a timer - encryption change not received before L2CAP connect req */
+ btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_DELAY_CHECK_SM4);
+ }
+ else
+ {
+ l2cu_send_peer_connect_rsp (p_ccb, L2CAP_CONN_SECURITY_BLOCK, 0);
+ l2cu_release_ccb (p_ccb);
+ }
+ break;
+
+ case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
+ case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
+ GKI_freebuf (p_data);
+ break;
+
+ case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper wants to disconnect */
+ l2cu_release_ccb (p_ccb);
+ break;
+
+ case L2CEVT_L2CAP_DISCONNECT_REQ: /* Peer disconnected request */
+ l2cu_send_peer_disc_rsp (p_ccb->p_lcb, p_ccb->remote_id, p_ccb->local_cid, p_ccb->remote_cid);
+
+ /* Tell security manager to abort */
+ btm_sec_abort_access_req (p_ccb->p_lcb->remote_bd_addr);
+
+ l2cu_release_ccb (p_ccb);
+ break;
+
+ case L2CEVT_TIMEOUT:
+ /* SM4 related. */
+ if (!btsnd_hcic_disconnect (p_ccb->p_lcb->handle, HCI_ERR_AUTH_FAILURE))
+ {
+ L2CAP_TRACE_API1 ("L2CAP - Calling btsnd_hcic_disconnect for handle %i failed", p_ccb->p_lcb->handle);
+ btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, 1);
+ }
+ break;
+
+ case L2CEVT_SEC_RE_SEND_CMD: /* BTM has enough info to proceed */
+ btm_sec_l2cap_access_req (p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm,
+ p_ccb->p_lcb->handle, FALSE, &l2c_link_sec_comp, p_ccb);
+ break;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function l2c_csm_w4_l2cap_connect_rsp
+**
+** Description This function handles events when the channel is in
+** CST_W4_L2CAP_CONNECT_RSP state.
+**
+** Returns void
+**
+*******************************************************************************/
+static void l2c_csm_w4_l2cap_connect_rsp (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
+{
+ tL2C_CONN_INFO *p_ci = (tL2C_CONN_INFO *)p_data;
+ tL2CA_DISCONNECT_IND_CB *disconnect_ind = p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb;
+ tL2CA_CONNECT_CFM_CB *connect_cfm = p_ccb->p_rcb->api.pL2CA_ConnectCfm_Cb;
+ UINT16 local_cid = p_ccb->local_cid;
+
+#if (BT_TRACE_VERBOSE == TRUE)
+ L2CAP_TRACE_EVENT2 ("L2CAP - LCID: 0x%04x st: W4_L2CAP_CON_RSP evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event));
+#else
+ L2CAP_TRACE_EVENT1 ("L2CAP - st: W4_L2CAP_CON_RSP evt: %d", event);
+#endif
+
+ switch (event)
+ {
+ case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */
+ /* Send disc indication unless peer to peer race condition AND normal disconnect */
+ /* *((UINT8 *)p_data) != HCI_ERR_PEER_USER happens when peer device try to disconnect for normal reason */
+ p_ccb->chnl_state = CST_CLOSED;
+ if ((p_ccb->flags & CCB_FLAG_NO_RETRY) || !p_data || (*((UINT8 *)p_data) != HCI_ERR_PEER_USER))
+ {
+ L2CAP_TRACE_API1 ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed",
+ p_ccb->local_cid);
+ l2cu_release_ccb (p_ccb);
+ (*disconnect_ind)(local_cid, FALSE);
+ }
+ p_ccb->flags |= CCB_FLAG_NO_RETRY;
+ break;
+
+ case L2CEVT_L2CAP_CONNECT_RSP: /* Got peer connect confirm */
+ p_ccb->remote_cid = p_ci->remote_cid;
+ p_ccb->chnl_state = CST_CONFIG;
+ btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CFG_TIMEOUT);
+ L2CAP_TRACE_API1 ("L2CAP - Calling Connect_Cfm_Cb(), CID: 0x%04x, Success", p_ccb->local_cid);
+
+ (*p_ccb->p_rcb->api.pL2CA_ConnectCfm_Cb)(local_cid, L2CAP_CONN_OK);
+ break;
+
+ case L2CEVT_L2CAP_CONNECT_RSP_PND: /* Got peer connect pending */
+ p_ccb->remote_cid = p_ci->remote_cid;
+ btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CONNECT_TOUT_EXT);
+ if (p_ccb->p_rcb->api.pL2CA_ConnectPnd_Cb)
+ {
+ L2CAP_TRACE_API1 ("L2CAP - Calling Connect_Pnd_Cb(), CID: 0x%04x", p_ccb->local_cid);
+ (*p_ccb->p_rcb->api.pL2CA_ConnectPnd_Cb)(p_ccb->local_cid);
+ }
+ break;
+
+ case L2CEVT_L2CAP_CONNECT_RSP_NEG: /* Peer rejected connection */
+ L2CAP_TRACE_API2 ("L2CAP - Calling Connect_Cfm_Cb(), CID: 0x%04x, Failure Code: %d", p_ccb->local_cid, p_ci->l2cap_result);
+ l2cu_release_ccb (p_ccb);
+ (*connect_cfm)(local_cid, p_ci->l2cap_result);
+ break;
+
+ case L2CEVT_TIMEOUT:
+ L2CAP_TRACE_API1 ("L2CAP - Calling Connect_Cfm_Cb(), CID: 0x%04x, Timeout", p_ccb->local_cid);
+ l2cu_release_ccb (p_ccb);
+ (*connect_cfm)(local_cid, L2CAP_CONN_TIMEOUT);
+ break;
+
+ case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper wants to disconnect */
+ /* If we know peer CID from connect pending, we can send disconnect */
+ if (p_ccb->remote_cid != 0)
+ {
+ l2cu_send_peer_disc_req (p_ccb);
+ p_ccb->chnl_state = CST_W4_L2CAP_DISCONNECT_RSP;
+ btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_DISCONNECT_TOUT);
+ }
+ else
+ l2cu_release_ccb (p_ccb);
+ break;
+
+ case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
+ case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
+ GKI_freebuf (p_data);
+ break;
+
+ case L2CEVT_L2CAP_INFO_RSP:
+ /* Need to have at least one compatible channel to continue */
+ if (!l2c_fcr_chk_chan_modes(p_ccb))
+ {
+ l2cu_release_ccb (p_ccb);
+ (*connect_cfm)(local_cid, L2CAP_CONN_NO_LINK);
+ }
+ else
+ {
+ /* We have feature info, so now send peer connect request */
+ btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CONNECT_TOUT);
+ l2cu_send_peer_connect_req (p_ccb); /* Start Connection */
+ }
+ break;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function l2c_csm_w4_l2ca_connect_rsp
+**
+** Description This function handles events when the channel is in
+** CST_W4_L2CA_CONNECT_RSP state.
+**
+** Returns void
+**
+*******************************************************************************/
+static void l2c_csm_w4_l2ca_connect_rsp (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
+{
+ tL2C_CONN_INFO *p_ci;
+ tL2CA_DISCONNECT_IND_CB *disconnect_ind = p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb;
+ UINT16 local_cid = p_ccb->local_cid;
+
+#if (BT_TRACE_VERBOSE == TRUE)
+ L2CAP_TRACE_EVENT2 ("L2CAP - LCID: 0x%04x st: W4_L2CA_CON_RSP evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event));
+#else
+ L2CAP_TRACE_EVENT1 ("L2CAP - st: W4_L2CA_CON_RSP evt: %d", event);
+#endif
+
+ switch (event)
+ {
+ case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */
+ L2CAP_TRACE_API1 ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed", p_ccb->local_cid);
+ l2cu_release_ccb (p_ccb);
+ (*disconnect_ind)(local_cid, FALSE);
+ break;
+
+ case L2CEVT_L2CA_CONNECT_RSP:
+ p_ci = (tL2C_CONN_INFO *)p_data;
+
+ /* Result should be OK or PENDING */
+ if ((!p_ci) || (p_ci->l2cap_result == L2CAP_CONN_OK))
+ {
+ l2cu_send_peer_connect_rsp (p_ccb, L2CAP_CONN_OK, 0);
+ p_ccb->chnl_state = CST_CONFIG;
+ btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CFG_TIMEOUT);
+ }
+ else
+ {
+ /* If pending, stay in same state and start extended timer */
+ l2cu_send_peer_connect_rsp (p_ccb, p_ci->l2cap_result, p_ci->l2cap_status);
+ btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CONNECT_TOUT_EXT);
+ }
+ break;
+
+ case L2CEVT_L2CA_CONNECT_RSP_NEG:
+ p_ci = (tL2C_CONN_INFO *)p_data;
+ l2cu_send_peer_connect_rsp (p_ccb, p_ci->l2cap_result, p_ci->l2cap_status);
+ l2cu_release_ccb (p_ccb);
+ break;
+
+ case L2CEVT_TIMEOUT:
+ l2cu_send_peer_connect_rsp (p_ccb, L2CAP_CONN_NO_PSM, 0);
+ L2CAP_TRACE_API1 ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed", p_ccb->local_cid);
+ l2cu_release_ccb (p_ccb);
+ (*disconnect_ind)(local_cid, FALSE);
+ break;
+
+ case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
+ case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
+ GKI_freebuf (p_data);
+ break;
+
+ case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper wants to disconnect */
+ l2cu_send_peer_disc_req (p_ccb);
+ p_ccb->chnl_state = CST_W4_L2CAP_DISCONNECT_RSP;
+ btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_DISCONNECT_TOUT);
+ break;
+
+ case L2CEVT_L2CAP_INFO_RSP:
+ /* We have feature info, so now give the upper layer connect IND */
+ btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CONNECT_TOUT);
+ L2CAP_TRACE_API1 ("L2CAP - Calling Connect_Ind_Cb(), CID: 0x%04x", p_ccb->local_cid);
+
+ (*p_ccb->p_rcb->api.pL2CA_ConnectInd_Cb) (p_ccb->p_lcb->remote_bd_addr,
+ p_ccb->local_cid,
+ p_ccb->p_rcb->psm,
+ p_ccb->remote_id);
+ break;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function l2c_csm_config
+**
+** Description This function handles events when the channel is in
+** CONFIG state.
+**
+** Returns void
+**
+*******************************************************************************/
+static void l2c_csm_config (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
+{
+ tL2CAP_CFG_INFO *p_cfg = (tL2CAP_CFG_INFO *)p_data;
+ tL2CA_DISCONNECT_IND_CB *disconnect_ind = p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb;
+ UINT16 local_cid = p_ccb->local_cid;
+ UINT8 cfg_result;
+
+#if (BT_TRACE_VERBOSE == TRUE)
+ L2CAP_TRACE_EVENT2 ("L2CAP - LCID: 0x%04x st: CONFIG evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event));
+#else
+ L2CAP_TRACE_EVENT1 ("L2CAP - st: CONFIG evt: %d", event);
+#endif
+
+ switch (event)
+ {
+ case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */
+ L2CAP_TRACE_API1 ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed", p_ccb->local_cid);
+ l2cu_release_ccb (p_ccb);
+ (*disconnect_ind)(local_cid, FALSE);
+ break;
+
+ case L2CEVT_L2CAP_CONFIG_REQ: /* Peer config request */
+
+ if ((cfg_result = l2cu_process_peer_cfg_req (p_ccb, p_cfg)) == L2CAP_PEER_CFG_OK)
+ {
+ L2CAP_TRACE_EVENT2 ("L2CAP - Calling Config_Req_Cb(), CID: 0x%04x, C-bit %d",
+ p_ccb->local_cid, (p_cfg->flags & L2CAP_CFG_FLAGS_MASK_CONT));
+ (*p_ccb->p_rcb->api.pL2CA_ConfigInd_Cb)(p_ccb->local_cid, p_cfg);
+ }
+ else if (cfg_result == L2CAP_PEER_CFG_DISCONNECT)
+ {
+ /* Disconnect if channels are incompatible */
+ L2CAP_TRACE_EVENT0 ("L2CAP - incompatible configurations disconnect");
+ l2cu_disconnect_chnl (p_ccb);
+ }
+ else /* Return error to peer so he can renegotiate if possible */
+ {
+ L2CAP_TRACE_EVENT0 ("L2CAP - incompatible configurations trying reconfig");
+ l2cu_send_peer_config_rsp (p_ccb, p_cfg);
+ }
+ break;
+
+ case L2CEVT_L2CAP_CONFIG_RSP: /* Peer config response */
+ l2cu_process_peer_cfg_rsp (p_ccb, p_cfg);
+
+ if (p_cfg->result != L2CAP_CFG_PENDING)
+ {
+ /* TBD: When config options grow beyong minimum MTU (48 bytes)
+ * logic needs to be added to handle responses with
+ * continuation bit set in flags field.
+ * 1. Send additional config request out until C-bit is cleared in response
+ */
+ p_ccb->config_done |= OB_CFG_DONE;
+
+ if (p_ccb->config_done & IB_CFG_DONE)
+ {
+ /* Verify two sides are in compatible modes before continuing */
+ if (p_ccb->our_cfg.fcr.mode != p_ccb->peer_cfg.fcr.mode)
+ {
+ l2cu_send_peer_disc_req (p_ccb);
+ L2CAP_TRACE_WARNING1 ("L2CAP - Calling Disconnect_Ind_Cb(Incompatible CFG), CID: 0x%04x No Conf Needed", p_ccb->local_cid);
+ l2cu_release_ccb (p_ccb);
+ (*disconnect_ind)(local_cid, FALSE);
+ break;
+ }
+
+ p_ccb->config_done |= RECONFIG_FLAG;
+ p_ccb->chnl_state = CST_OPEN;
+ l2c_link_adjust_chnl_allocation ();
+ btu_stop_timer (&p_ccb->timer_entry);
+
+ /* If using eRTM and waiting for an ACK, restart the ACK timer */
+ if (p_ccb->fcrb.wait_ack)
+ l2c_fcr_start_timer(p_ccb);
+
+ /*
+ ** check p_ccb->our_cfg.fcr.mon_tout and p_ccb->our_cfg.fcr.rtrans_tout
+ ** we may set them to zero when sending config request during renegotiation
+ */
+ if ((p_ccb->our_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE)
+ &&((p_ccb->our_cfg.fcr.mon_tout == 0)||(p_ccb->our_cfg.fcr.rtrans_tout)))
+ {
+ l2c_fcr_adj_monitor_retran_timeout (p_ccb);
+ }
+
+#if (L2CAP_ERTM_STATS == TRUE)
+ p_ccb->fcrb.connect_tick_count = GKI_get_os_tick_count();
+#endif
+ /* See if we can forward anything on the hold queue */
+ if (p_ccb->xmit_hold_q.count)
+ {
+ l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, NULL);
+ }
+ }
+ }
+
+ L2CAP_TRACE_API1 ("L2CAP - Calling Config_Rsp_Cb(), CID: 0x%04x", p_ccb->local_cid);
+ (*p_ccb->p_rcb->api.pL2CA_ConfigCfm_Cb)(p_ccb->local_cid, p_cfg);
+ break;
+
+ case L2CEVT_L2CAP_CONFIG_RSP_NEG: /* Peer config error rsp */
+ /* Disable the Timer */
+ btu_stop_timer (&p_ccb->timer_entry);
+
+ /* If failure was channel mode try to renegotiate */
+ if (l2c_fcr_renegotiate_chan(p_ccb, p_cfg) == FALSE)
+ {
+ L2CAP_TRACE_API2 ("L2CAP - Calling Config_Rsp_Cb(), CID: 0x%04x, Failure: %d", p_ccb->local_cid, p_cfg->result);
+ (*p_ccb->p_rcb->api.pL2CA_ConfigCfm_Cb)(p_ccb->local_cid, p_cfg);
+ }
+ break;
+
+ case L2CEVT_L2CAP_DISCONNECT_REQ: /* Peer disconnected request */
+ btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_DISCONNECT_TOUT);
+ p_ccb->chnl_state = CST_W4_L2CA_DISCONNECT_RSP;
+ L2CAP_TRACE_API1 ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x Conf Needed", p_ccb->local_cid);
+ (*p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb)(p_ccb->local_cid, TRUE);
+ break;
+
+ case L2CEVT_L2CA_CONFIG_REQ: /* Upper layer config req */
+ l2cu_process_our_cfg_req (p_ccb, p_cfg);
+ l2cu_send_peer_config_req (p_ccb, p_cfg);
+ btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CFG_TIMEOUT);
+ break;
+
+ case L2CEVT_L2CA_CONFIG_RSP: /* Upper layer config rsp */
+ l2cu_process_our_cfg_rsp (p_ccb, p_cfg);
+
+ /* Not finished if continuation flag is set */
+ if ( (p_cfg->flags & L2CAP_CFG_FLAGS_MASK_CONT) || (p_cfg->result == L2CAP_CFG_PENDING) )
+ {
+ /* Send intermediate response; remain in cfg state */
+ l2cu_send_peer_config_rsp (p_ccb, p_cfg);
+ break;
+ }
+
+ /* Local config done; clear cached configuration in case reconfig takes place later */
+ p_ccb->peer_cfg.mtu_present = FALSE;
+ p_ccb->peer_cfg.flush_to_present = FALSE;
+ p_ccb->peer_cfg.qos_present = FALSE;
+
+ p_ccb->config_done |= IB_CFG_DONE;
+
+ if (p_ccb->config_done & OB_CFG_DONE)
+ {
+ /* Verify two sides are in compatible modes before continuing */
+ if (p_ccb->our_cfg.fcr.mode != p_ccb->peer_cfg.fcr.mode)
+ {
+ l2cu_send_peer_disc_req (p_ccb);
+ L2CAP_TRACE_WARNING1 ("L2CAP - Calling Disconnect_Ind_Cb(Incompatible CFG), CID: 0x%04x No Conf Needed", p_ccb->local_cid);
+ l2cu_release_ccb (p_ccb);
+ (*disconnect_ind)(local_cid, FALSE);
+ break;
+ }
+
+ p_ccb->config_done |= RECONFIG_FLAG;
+ p_ccb->chnl_state = CST_OPEN;
+ l2c_link_adjust_chnl_allocation ();
+ btu_stop_timer (&p_ccb->timer_entry);
+ }
+
+ l2cu_send_peer_config_rsp (p_ccb, p_cfg);
+
+ /* If using eRTM and waiting for an ACK, restart the ACK timer */
+ if (p_ccb->fcrb.wait_ack)
+ l2c_fcr_start_timer(p_ccb);
+
+#if (L2CAP_ERTM_STATS == TRUE)
+ p_ccb->fcrb.connect_tick_count = GKI_get_os_tick_count();
+#endif
+
+ /* See if we can forward anything on the hold queue */
+ if ( (p_ccb->chnl_state == CST_OPEN) && (p_ccb->xmit_hold_q.count) )
+ {
+ l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, NULL);
+ }
+ break;
+
+ case L2CEVT_L2CA_CONFIG_RSP_NEG: /* Upper layer config reject */
+ l2cu_send_peer_config_rsp (p_ccb, p_cfg);
+ btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CFG_TIMEOUT);
+ break;
+
+ case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper wants to disconnect */
+ l2cu_send_peer_disc_req (p_ccb);
+ p_ccb->chnl_state = CST_W4_L2CAP_DISCONNECT_RSP;
+ btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_DISCONNECT_TOUT);
+ break;
+
+ case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
+ L2CAP_TRACE_API1 ("L2CAP - Calling DataInd_Cb(), CID: 0x%04x", p_ccb->local_cid);
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+ if (p_ccb->local_cid < L2CAP_BASE_APPL_CID)
+ {
+ if (l2cb.fixed_reg[p_ccb->local_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb)
+ (*l2cb.fixed_reg[p_ccb->local_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb)(p_ccb->p_lcb->remote_bd_addr,(BT_HDR *)p_data);
+ else
+ GKI_freebuf (p_data);
+
+ break;
+ }
+#endif
+ (*p_ccb->p_rcb->api.pL2CA_DataInd_Cb)(p_ccb->local_cid, (BT_HDR *)p_data);
+ break;
+
+ case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
+ if (p_ccb->config_done & OB_CFG_DONE)
+ l2c_enqueue_peer_data (p_ccb, (BT_HDR *)p_data);
+ else
+ GKI_freebuf (p_data);
+ break;
+
+ case L2CEVT_TIMEOUT:
+ l2cu_send_peer_disc_req (p_ccb);
+ L2CAP_TRACE_API1 ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed", p_ccb->local_cid);
+ l2cu_release_ccb (p_ccb);
+ (*disconnect_ind)(local_cid, FALSE);
+ break;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function l2c_csm_open
+**
+** Description This function handles events when the channel is in
+** OPEN state.
+**
+** Returns void
+**
+*******************************************************************************/
+static void l2c_csm_open (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
+{
+ UINT16 local_cid = p_ccb->local_cid;
+ tL2CAP_CFG_INFO *p_cfg;
+ tL2C_CHNL_STATE tempstate;
+ UINT8 tempcfgdone;
+ UINT8 cfg_result;
+
+#if (BT_TRACE_VERBOSE == TRUE)
+ L2CAP_TRACE_EVENT2 ("L2CAP - LCID: 0x%04x st: OPEN evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event));
+#else
+ L2CAP_TRACE_EVENT1 ("L2CAP - st: OPEN evt: %d", event);
+#endif
+
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ if ( local_cid == L2CAP_CONNECTIONLESS_CID )
+ {
+ /* check if this event can be processed by UCD */
+ if ( l2c_ucd_process_event (p_ccb, event, p_data) )
+ {
+ /* The event is processed by UCD state machine */
+ return;
+ }
+ }
+#endif
+
+ switch (event)
+ {
+ case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */
+ L2CAP_TRACE_API1 ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed", p_ccb->local_cid);
+ l2cu_release_ccb (p_ccb);
+ if (p_ccb->p_rcb)
+ (*p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb)(local_cid, FALSE);
+ break;
+
+ case L2CEVT_LP_QOS_VIOLATION_IND: /* QOS violation */
+ /* Tell upper layer. If service guaranteed, then clear the channel */
+ if (p_ccb->p_rcb->api.pL2CA_QoSViolationInd_Cb)
+ (*p_ccb->p_rcb->api.pL2CA_QoSViolationInd_Cb)(p_ccb->p_lcb->remote_bd_addr);
+ break;
+
+ case L2CEVT_L2CAP_CONFIG_REQ: /* Peer config request */
+ p_cfg = (tL2CAP_CFG_INFO *)p_data;
+
+ tempstate = p_ccb->chnl_state;
+ tempcfgdone = p_ccb->config_done;
+ p_ccb->chnl_state = CST_CONFIG;
+ p_ccb->config_done &= ~CFG_DONE_MASK;
+
+ btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CFG_TIMEOUT);
+
+ if ((cfg_result = l2cu_process_peer_cfg_req (p_ccb, p_cfg)) == L2CAP_PEER_CFG_OK)
+ {
+ (*p_ccb->p_rcb->api.pL2CA_ConfigInd_Cb)(p_ccb->local_cid, p_cfg);
+ }
+
+ /* Error in config parameters: reset state and config flag */
+ else if (cfg_result == L2CAP_PEER_CFG_UNACCEPTABLE)
+ {
+ btu_stop_timer(&p_ccb->timer_entry);
+ p_ccb->chnl_state = tempstate;
+ p_ccb->config_done = tempcfgdone;
+ l2cu_send_peer_config_rsp (p_ccb, p_cfg);
+ }
+ else /* L2CAP_PEER_CFG_DISCONNECT */
+ {
+ /* Disconnect if channels are incompatible
+ * Note this should not occur if reconfigure
+ * since this should have never passed original config.
+ */
+ l2cu_disconnect_chnl (p_ccb);
+ }
+ break;
+
+ case L2CEVT_L2CAP_DISCONNECT_REQ: /* Peer disconnected request */
+// btla-specific ++
+ /* Make sure we are not in sniff mode */
+#if BTM_PWR_MGR_INCLUDED == TRUE
+ {
+ tBTM_PM_PWR_MD settings;
+ settings.mode = BTM_PM_MD_ACTIVE;
+ BTM_SetPowerMode (BTM_PM_SET_ONLY_ID, p_ccb->p_lcb->remote_bd_addr, &settings);
+ }
+#else
+ BTM_CancelSniffMode (p_ccb->p_lcb->remote_bd_addr);
+#endif
+// btla-specific --
+
+ p_ccb->chnl_state = CST_W4_L2CA_DISCONNECT_RSP;
+ btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_DISCONNECT_TOUT);
+ L2CAP_TRACE_API1 ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x Conf Needed", p_ccb->local_cid);
+ (*p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb)(p_ccb->local_cid, TRUE);
+ break;
+
+ case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
+ (*p_ccb->p_rcb->api.pL2CA_DataInd_Cb)(p_ccb->local_cid, (BT_HDR *)p_data);
+ break;
+
+ case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper wants to disconnect */
+ /* Make sure we are not in sniff mode */
+#if BTM_PWR_MGR_INCLUDED == TRUE
+ {
+ tBTM_PM_PWR_MD settings;
+ settings.mode = BTM_PM_MD_ACTIVE;
+ BTM_SetPowerMode (BTM_PM_SET_ONLY_ID, p_ccb->p_lcb->remote_bd_addr, &settings);
+ }
+#else
+ BTM_CancelSniffMode (p_ccb->p_lcb->remote_bd_addr);
+#endif
+
+ l2cu_send_peer_disc_req (p_ccb);
+ p_ccb->chnl_state = CST_W4_L2CAP_DISCONNECT_RSP;
+ btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_DISCONNECT_TOUT);
+ break;
+
+ case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
+ l2c_enqueue_peer_data (p_ccb, (BT_HDR *)p_data);
+ l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, NULL);
+ break;
+
+ case L2CEVT_L2CA_CONFIG_REQ: /* Upper layer config req */
+ p_ccb->chnl_state = CST_CONFIG;
+ p_ccb->config_done &= ~CFG_DONE_MASK;
+ l2cu_process_our_cfg_req (p_ccb, (tL2CAP_CFG_INFO *)p_data);
+ l2cu_send_peer_config_req (p_ccb, (tL2CAP_CFG_INFO *)p_data);
+ btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CFG_TIMEOUT);
+ break;
+
+ case L2CEVT_TIMEOUT:
+ /* Process the monitor/retransmission time-outs in flow control/retrans mode */
+ if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE)
+ l2c_fcr_proc_tout (p_ccb);
+ break;
+
+ case L2CEVT_ACK_TIMEOUT:
+ l2c_fcr_proc_ack_tout (p_ccb);
+ break;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function l2c_csm_w4_l2cap_disconnect_rsp
+**
+** Description This function handles events when the channel is in
+** CST_W4_L2CAP_DISCONNECT_RSP state.
+**
+** Returns void
+**
+*******************************************************************************/
+static void l2c_csm_w4_l2cap_disconnect_rsp (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
+{
+ tL2CA_DISCONNECT_CFM_CB *disconnect_cfm = p_ccb->p_rcb->api.pL2CA_DisconnectCfm_Cb;
+ UINT16 local_cid = p_ccb->local_cid;
+
+#if (BT_TRACE_VERBOSE == TRUE)
+ L2CAP_TRACE_EVENT2 ("L2CAP - LCID: 0x%04x st: W4_L2CAP_DISC_RSP evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event));
+#else
+ L2CAP_TRACE_EVENT1 ("L2CAP - st: W4_L2CAP_DISC_RSP evt: %d", event);
+#endif
+
+ switch (event)
+ {
+ case L2CEVT_L2CAP_DISCONNECT_RSP: /* Peer disconnect response */
+ l2cu_release_ccb (p_ccb);
+ if (disconnect_cfm)
+ {
+ L2CAP_TRACE_API1 ("L2CAP - Calling DisconnectCfm_Cb(), CID: 0x%04x", local_cid);
+ (*disconnect_cfm)(local_cid, L2CAP_DISC_OK);
+ }
+ break;
+
+ case L2CEVT_L2CAP_DISCONNECT_REQ: /* Peer disconnect request */
+ l2cu_send_peer_disc_rsp (p_ccb->p_lcb, p_ccb->remote_id, p_ccb->local_cid, p_ccb->remote_cid);
+ l2cu_release_ccb (p_ccb);
+ if (disconnect_cfm)
+ {
+ L2CAP_TRACE_API1 ("L2CAP - Calling DisconnectCfm_Cb(), CID: 0x%04x", local_cid);
+ (*disconnect_cfm)(local_cid, L2CAP_DISC_OK);
+ }
+ break;
+
+ case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */
+ case L2CEVT_TIMEOUT: /* Timeout */
+ l2cu_release_ccb (p_ccb);
+ if (disconnect_cfm)
+ {
+ L2CAP_TRACE_API1 ("L2CAP - Calling DisconnectCfm_Cb(), CID: 0x%04x", local_cid);
+ (*disconnect_cfm)(local_cid, L2CAP_DISC_TIMEOUT);
+ }
+ break;
+
+ case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
+ case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
+ GKI_freebuf (p_data);
+ break;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function l2c_csm_w4_l2ca_disconnect_rsp
+**
+** Description This function handles events when the channel is in
+** CST_W4_L2CA_DISCONNECT_RSP state.
+**
+** Returns void
+**
+*******************************************************************************/
+static void l2c_csm_w4_l2ca_disconnect_rsp (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
+{
+ tL2CA_DISCONNECT_IND_CB *disconnect_ind = p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb;
+ UINT16 local_cid = p_ccb->local_cid;
+
+#if (BT_TRACE_VERBOSE == TRUE)
+ L2CAP_TRACE_EVENT2 ("L2CAP - LCID: 0x%04x st: W4_L2CA_DISC_RSP evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event));
+#else
+ L2CAP_TRACE_EVENT1 ("L2CAP - st: W4_L2CA_DISC_RSP evt: %d", event);
+#endif
+
+ switch (event)
+ {
+ case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */
+ L2CAP_TRACE_API1 ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed", p_ccb->local_cid);
+ l2cu_release_ccb (p_ccb);
+ (*disconnect_ind)(local_cid, FALSE);
+ break;
+
+ case L2CEVT_TIMEOUT:
+ l2cu_send_peer_disc_rsp (p_ccb->p_lcb, p_ccb->remote_id, p_ccb->local_cid, p_ccb->remote_cid);
+ L2CAP_TRACE_API1 ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed", p_ccb->local_cid);
+ l2cu_release_ccb (p_ccb);
+ (*disconnect_ind)(local_cid, FALSE);
+ break;
+
+ case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper disconnect request */
+ case L2CEVT_L2CA_DISCONNECT_RSP: /* Upper disconnect response */
+ l2cu_send_peer_disc_rsp (p_ccb->p_lcb, p_ccb->remote_id, p_ccb->local_cid, p_ccb->remote_cid);
+ l2cu_release_ccb (p_ccb);
+ break;
+
+ case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
+ case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
+ GKI_freebuf (p_data);
+ break;
+ }
+}
+
+
+#if (BT_TRACE_VERBOSE == TRUE)
+/*******************************************************************************
+**
+** Function l2c_csm_get_event_name
+**
+** Description This function returns the event name.
+**
+** NOTE conditionally compiled to save memory.
+**
+** Returns pointer to the name
+**
+*******************************************************************************/
+static char *l2c_csm_get_event_name (UINT16 event)
+{
+ switch (event)
+ {
+ case L2CEVT_LP_CONNECT_CFM: /* Lower layer connect confirm */
+ return ("LOWER_LAYER_CONNECT_CFM");
+ case L2CEVT_LP_CONNECT_CFM_NEG: /* Lower layer connect confirm (failed) */
+ return ("LOWER_LAYER_CONNECT_CFM_NEG");
+ case L2CEVT_LP_CONNECT_IND: /* Lower layer connect indication */
+ return ("LOWER_LAYER_CONNECT_IND");
+ case L2CEVT_LP_DISCONNECT_IND: /* Lower layer disconnect indication */
+ return ("LOWER_LAYER_DISCONNECT_IND");
+ case L2CEVT_LP_QOS_CFM: /* Lower layer QOS confirmation */
+ return ("LOWER_LAYER_QOS_CFM");
+ case L2CEVT_LP_QOS_CFM_NEG: /* Lower layer QOS confirmation (failed)*/
+ return ("LOWER_LAYER_QOS_CFM_NEG");
+ case L2CEVT_LP_QOS_VIOLATION_IND: /* Lower layer QOS violation indication */
+ return ("LOWER_LAYER_QOS_VIOLATION_IND");
+
+ case L2CEVT_SEC_COMP: /* Security cleared successfully */
+ return ("SECURITY_COMPLETE");
+ case L2CEVT_SEC_COMP_NEG: /* Security procedure failed */
+ return ("SECURITY_COMPLETE_NEG");
+
+ case L2CEVT_L2CAP_CONNECT_REQ: /* Peer connection request */
+ return ("PEER_CONNECT_REQ");
+ case L2CEVT_L2CAP_CONNECT_RSP: /* Peer connection response */
+ return ("PEER_CONNECT_RSP");
+ case L2CEVT_L2CAP_CONNECT_RSP_PND: /* Peer connection response pending */
+ return ("PEER_CONNECT_RSP_PND");
+ case L2CEVT_L2CAP_CONNECT_RSP_NEG: /* Peer connection response (failed) */
+ return ("PEER_CONNECT_RSP_NEG");
+ case L2CEVT_L2CAP_CONFIG_REQ: /* Peer configuration request */
+ return ("PEER_CONFIG_REQ");
+ case L2CEVT_L2CAP_CONFIG_RSP: /* Peer configuration response */
+ return ("PEER_CONFIG_RSP");
+ case L2CEVT_L2CAP_CONFIG_RSP_NEG: /* Peer configuration response (failed) */
+ return ("PEER_CONFIG_RSP_NEG");
+ case L2CEVT_L2CAP_DISCONNECT_REQ: /* Peer disconnect request */
+ return ("PEER_DISCONNECT_REQ");
+ case L2CEVT_L2CAP_DISCONNECT_RSP: /* Peer disconnect response */
+ return ("PEER_DISCONNECT_RSP");
+ case L2CEVT_L2CAP_DATA: /* Peer data */
+ return ("PEER_DATA");
+
+ case L2CEVT_L2CA_CONNECT_REQ: /* Upper layer connect request */
+ return ("UPPER_LAYER_CONNECT_REQ");
+ case L2CEVT_L2CA_CONNECT_RSP: /* Upper layer connect response */
+ return ("UPPER_LAYER_CONNECT_RSP");
+ case L2CEVT_L2CA_CONNECT_RSP_NEG: /* Upper layer connect response (failed)*/
+ return ("UPPER_LAYER_CONNECT_RSP_NEG");
+ case L2CEVT_L2CA_CONFIG_REQ: /* Upper layer config request */
+ return ("UPPER_LAYER_CONFIG_REQ");
+ case L2CEVT_L2CA_CONFIG_RSP: /* Upper layer config response */
+ return ("UPPER_LAYER_CONFIG_RSP");
+ case L2CEVT_L2CA_CONFIG_RSP_NEG: /* Upper layer config response (failed) */
+ return ("UPPER_LAYER_CONFIG_RSP_NEG");
+ case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper layer disconnect request */
+ return ("UPPER_LAYER_DISCONNECT_REQ");
+ case L2CEVT_L2CA_DISCONNECT_RSP: /* Upper layer disconnect response */
+ return ("UPPER_LAYER_DISCONNECT_RSP");
+ case L2CEVT_L2CA_DATA_READ: /* Upper layer data read */
+ return ("UPPER_LAYER_DATA_READ");
+ case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data write */
+ return ("UPPER_LAYER_DATA_WRITE");
+ case L2CEVT_TIMEOUT: /* Timeout */
+ return ("TIMEOUT");
+ case L2CEVT_SEC_RE_SEND_CMD:
+ return ("SEC_RE_SEND_CMD");
+ case L2CEVT_L2CAP_INFO_RSP: /* Peer information response */
+ return ("L2CEVT_L2CAP_INFO_RSP");
+ case L2CEVT_ACK_TIMEOUT:
+ return ("L2CEVT_ACK_TIMEOUT");
+
+ default:
+ return ("???? UNKNOWN EVENT");
+ }
+}
+#endif /* (BT_TRACE_VERBOSE == TRUE) */
+
+
+/*******************************************************************************
+**
+** Function l2c_enqueue_peer_data
+**
+** Description Enqueues data destined for the peer in the ccb. Handles
+** FCR segmentation and checks for congestion.
+**
+** Returns void
+**
+*******************************************************************************/
+void l2c_enqueue_peer_data (tL2C_CCB *p_ccb, BT_HDR *p_buf)
+{
+ UINT8 *p;
+
+ if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE)
+ {
+ p_buf->event = 0;
+ }
+ else
+ {
+ /* Save the channel ID for faster counting */
+ p_buf->event = p_ccb->local_cid;
+
+ /* Step back to add the L2CAP header */
+ p_buf->offset -= L2CAP_PKT_OVERHEAD;
+ p_buf->len += L2CAP_PKT_OVERHEAD;
+
+ /* Set the pointer to the beginning of the data */
+ p = (UINT8 *)(p_buf + 1) + p_buf->offset;
+
+ /* Now the L2CAP header */
+ UINT16_TO_STREAM (p, p_buf->len - L2CAP_PKT_OVERHEAD);
+ UINT16_TO_STREAM (p, p_ccb->remote_cid);
+ }
+
+ GKI_enqueue (&p_ccb->xmit_hold_q, p_buf);
+
+ l2cu_check_channel_congestion (p_ccb);
+
+#if (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE)
+ /* if new packet is higher priority than serving ccb and it is not overrun */
+ if (( p_ccb->p_lcb->rr_pri > p_ccb->ccb_priority )
+ &&( p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].quota > 0))
+ {
+ /* send out higher priority packet */
+ p_ccb->p_lcb->rr_pri = p_ccb->ccb_priority;
+ }
+#endif
+
+ /* if we are doing a round robin scheduling, set the flag */
+ if (p_ccb->p_lcb->link_xmit_quota == 0)
+ l2cb.check_round_robin = TRUE;
+}
+
+
diff --git a/stack/l2cap/l2c_fcr.c b/stack/l2cap/l2c_fcr.c
new file mode 100644
index 0000000..25a9b3f
--- /dev/null
+++ b/stack/l2cap/l2c_fcr.c
@@ -0,0 +1,2697 @@
+/*****************************************************************************
+**
+** Name: l2c_fcr.c
+**
+** Description: This file contains the L2CAP 1.2 Flow Control and
+** retransmissions functions
+**
+**
+**
+** Copyright (c) 2004-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "gki.h"
+#include "bt_types.h"
+#include "hcimsgs.h"
+#include "l2cdefs.h"
+#include "l2c_int.h"
+#include "l2c_api.h"
+#include "btu.h"
+#include "btm_api.h"
+#include "btm_int.h"
+
+
+/* Flag passed to retransmit_i_frames() when all packets should be retransmitted */
+#define L2C_FCR_RETX_ALL_PKTS 0xFF
+
+#if BT_TRACE_VERBOSE == TRUE
+static char *SAR_types[] = { "Unsegmented", "Start", "End", "Continuation" };
+static char *SUP_types[] = { "RR", "REJ", "RNR", "SREJ" };
+#endif
+
+/* Look-up table for the CRC calculation */
+static const unsigned short crctab[256] = {
+ 0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241,
+ 0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440,
+ 0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40,
+ 0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841,
+ 0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40,
+ 0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41,
+ 0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,
+ 0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040,
+ 0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,
+ 0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441,
+ 0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41,
+ 0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840,
+ 0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41,
+ 0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
+ 0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640,
+ 0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041,
+ 0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240,
+ 0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
+ 0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41,
+ 0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840,
+ 0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,
+ 0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40,
+ 0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640,
+ 0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041,
+ 0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241,
+ 0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440,
+ 0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,
+ 0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
+ 0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40,
+ 0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41,
+ 0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641,
+ 0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040,
+};
+
+
+/*******************************************************************************
+** Static local functions
+*/
+static BOOLEAN process_reqseq (tL2C_CCB *p_ccb, UINT16 ctrl_word);
+static void process_s_frame (tL2C_CCB *p_ccb, BT_HDR *p_buf, UINT16 ctrl_word);
+static void process_i_frame (tL2C_CCB *p_ccb, BT_HDR *p_buf, UINT16 ctrl_word, BOOLEAN delay_ack);
+static BOOLEAN retransmit_i_frames (tL2C_CCB *p_ccb, UINT8 tx_seq);
+static void prepare_I_frame (tL2C_CCB *p_ccb, BT_HDR *p_buf, BOOLEAN is_retransmission);
+static void process_stream_frame (tL2C_CCB *p_ccb, BT_HDR *p_buf);
+static BOOLEAN do_sar_reassembly (tL2C_CCB *p_ccb, BT_HDR *p_buf, UINT16 ctrl_word);
+
+#if L2CAP_CORRUPT_ERTM_PKTS == TRUE
+static BOOLEAN l2c_corrupt_the_fcr_packet (tL2C_CCB *p_ccb, BT_HDR *p_buf,
+ BOOLEAN is_rx, UINT16 ctrl_word);
+static BOOLEAN l2c_bypass_sframe_packet (tL2C_CCB *p_ccb);
+#endif
+
+#if (L2CAP_ERTM_STATS == TRUE)
+static void l2c_fcr_collect_ack_delay (tL2C_CCB *p_ccb, UINT8 num_bufs_acked);
+#endif
+
+/*******************************************************************************
+**
+** Function l2c_fcr_updcrc
+**
+** Description This function computes the CRC using the look-up table.
+**
+** Returns CRC
+**
+*******************************************************************************/
+unsigned short l2c_fcr_updcrc(unsigned short icrc, unsigned char *icp, int icnt)
+{
+ register unsigned short crc = icrc;
+ register unsigned char *cp = icp;
+ register int cnt = icnt;
+
+ while (cnt--)
+ {
+ crc = ((crc >> 8) & 0xff) ^ crctab[(crc & 0xff) ^ *cp++];
+ }
+
+ return(crc);
+}
+
+
+/*******************************************************************************
+**
+** Function l2c_fcr_tx_get_fcs
+**
+** Description This function computes the CRC for a frame to be TXed.
+**
+** Returns CRC
+**
+*******************************************************************************/
+UINT16 l2c_fcr_tx_get_fcs (BT_HDR *p_buf)
+{
+ UINT8 *p = ((UINT8 *) (p_buf + 1)) + p_buf->offset;
+
+ return (l2c_fcr_updcrc (L2CAP_FCR_INIT_CRC, p, p_buf->len));
+}
+
+/*******************************************************************************
+**
+** Function l2c_fcr_rx_get_fcs
+**
+** Description This function computes the CRC for a received frame.
+**
+** Returns CRC
+**
+*******************************************************************************/
+UINT16 l2c_fcr_rx_get_fcs (BT_HDR *p_buf)
+{
+ UINT8 *p = ((UINT8 *) (p_buf + 1)) + p_buf->offset;
+
+ /* offset points past the L2CAP header, but the CRC check includes it */
+ p -= L2CAP_PKT_OVERHEAD;
+
+ return (l2c_fcr_updcrc (L2CAP_FCR_INIT_CRC, p, p_buf->len + L2CAP_PKT_OVERHEAD));
+}
+
+/*******************************************************************************
+**
+** Function l2c_fcr_start_timer
+**
+** Description This function starts the (monitor or retransmission) timer.
+**
+** Returns -
+**
+*******************************************************************************/
+void l2c_fcr_start_timer (tL2C_CCB *p_ccb)
+{
+ UINT32 tout;
+
+ /* The timers which are in milliseconds */
+ if (p_ccb->fcrb.wait_ack)
+ {
+ tout = (UINT32)p_ccb->our_cfg.fcr.mon_tout;
+ }
+ else
+ {
+ tout = (UINT32)p_ccb->our_cfg.fcr.rtrans_tout;
+ }
+/*
+ L2CAP_TRACE_DEBUG4 ("l2c_fcr_start_timer Tout: %u Already Running: %u wait_ack: %u ack_q_count: %u",
+ tout, p_ccb->timer_entry.in_use, p_ccb->fcrb.wait_ack, p_ccb->fcrb.waiting_for_ack_q.count);
+*/
+ /* Only start a timer that was not started */
+ if (p_ccb->fcrb.mon_retrans_timer.in_use == 0)
+ btu_start_quick_timer (&p_ccb->fcrb.mon_retrans_timer, BTU_TTYPE_L2CAP_CHNL, tout*QUICK_TIMER_TICKS_PER_SEC/1000);
+}
+
+/*******************************************************************************
+**
+** Function l2c_fcr_stop_timer
+**
+** Description This function stops the (monitor or transmission) timer.
+**
+** Returns -
+**
+*******************************************************************************/
+void l2c_fcr_stop_timer (tL2C_CCB *p_ccb)
+{
+ if (p_ccb->fcrb.mon_retrans_timer.in_use)
+ {
+/*
+ L2CAP_TRACE_DEBUG2 ("l2c_fcr_stop_timer wait_ack: %u ack_q_count: %u",
+ p_ccb->fcrb.wait_ack, p_ccb->fcrb.waiting_for_ack_q.count);
+*/
+ btu_stop_quick_timer (&p_ccb->fcrb.mon_retrans_timer);
+ }
+}
+
+/*******************************************************************************
+**
+** Function l2c_fcr_cleanup
+**
+** Description This function cleans up the variable used for flow-control/retrans.
+**
+** Returns -
+**
+*******************************************************************************/
+void l2c_fcr_cleanup (tL2C_CCB *p_ccb)
+{
+ tL2C_FCRB *p_fcrb = &p_ccb->fcrb;
+
+ l2c_fcr_stop_timer (p_ccb);
+
+ if (p_fcrb->p_rx_sdu)
+ GKI_freebuf (p_fcrb->p_rx_sdu);
+
+ while (p_fcrb->waiting_for_ack_q.p_first)
+ GKI_freebuf (GKI_dequeue (&p_fcrb->waiting_for_ack_q));
+
+ while (p_fcrb->srej_rcv_hold_q.p_first)
+ GKI_freebuf (GKI_dequeue (&p_fcrb->srej_rcv_hold_q));
+
+ while (p_fcrb->retrans_q.p_first)
+ GKI_freebuf (GKI_dequeue (&p_fcrb->retrans_q));
+
+ btu_stop_quick_timer (&p_fcrb->ack_timer);
+ btu_stop_quick_timer (&p_ccb->fcrb.mon_retrans_timer);
+
+#if (L2CAP_ERTM_STATS == TRUE)
+ if ( (p_ccb->local_cid >= L2CAP_BASE_APPL_CID) && (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) )
+ {
+ UINT32 dur = GKI_get_os_tick_count() - p_ccb->fcrb.connect_tick_count;
+ char *p_str = (char *)GKI_getbuf(120);
+ UINT16 i;
+ UINT32 throughput_avg, ack_delay_avg, ack_q_count_avg;
+
+ dur = GKI_OS_TICKS_TO_MS(dur);
+ BT_TRACE_2(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI , TRACE_TYPE_GENERIC,
+ "--- L2CAP ERTM Stats for CID: 0x%04x Duration: %08ums", p_ccb->local_cid, dur);
+ BT_TRACE_4(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI , TRACE_TYPE_GENERIC,
+ "Retransmissions:%08u Times Flow Controlled:%08u Retrans Touts:%08u Ack Touts:%08u",
+ p_ccb->fcrb.pkts_retransmitted, p_ccb->fcrb.xmit_window_closed, p_ccb->fcrb.retrans_touts, p_ccb->fcrb.xmit_ack_touts);
+ BT_TRACE_1(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI , TRACE_TYPE_GENERIC,
+ "Times there is less than 2 packets in controller when flow controlled:%08u", p_ccb->fcrb.controller_idle);
+ BT_TRACE_2(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI , TRACE_TYPE_GENERIC,
+ "max_held_acks:%08u, in_cfg.fcr.tx_win_sz:%08u", p_ccb->fcrb.max_held_acks, p_ccb->peer_cfg.fcr.tx_win_sz );
+ if (p_str)
+ {
+ sprintf(p_str, "Sent Pkts:%08u Bytes:%10u(%06u/sec) RR:%08u REJ:%08u RNR:%08u SREJ:%08u",
+ p_ccb->fcrb.ertm_pkt_counts[0], p_ccb->fcrb.ertm_byte_counts[0],
+ (dur >= 10 ? (p_ccb->fcrb.ertm_byte_counts[0] * 100) / (dur / 10) : 0),
+ p_ccb->fcrb.s_frames_sent[0], p_ccb->fcrb.s_frames_sent[1], p_ccb->fcrb.s_frames_sent[2], p_ccb->fcrb.s_frames_sent[3]);
+
+ BT_TRACE_1(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI , TRACE_TYPE_GENERIC, "%s", p_str);
+
+ sprintf(p_str, "Rcvd Pkts:%08u Bytes:%10u(%06u/sec) RR:%08u REJ:%08u RNR:%08u SREJ:%08u",
+ p_ccb->fcrb.ertm_pkt_counts[1], p_ccb->fcrb.ertm_byte_counts[1],
+ (dur >= 10 ? (p_ccb->fcrb.ertm_byte_counts[1] * 100) / (dur / 10) : 0),
+ p_ccb->fcrb.s_frames_rcvd[0], p_ccb->fcrb.s_frames_rcvd[1], p_ccb->fcrb.s_frames_rcvd[2], p_ccb->fcrb.s_frames_rcvd[3]);
+
+ BT_TRACE_1(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI , TRACE_TYPE_GENERIC, "%s", p_str);
+
+ throughput_avg = 0;
+ ack_delay_avg = 0;
+ ack_q_count_avg = 0;
+
+ for (i = 0; i < L2CAP_ERTM_STATS_NUM_AVG; i++ )
+ {
+ if (i == p_ccb->fcrb.ack_delay_avg_index )
+ {
+ BT_TRACE_1(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI , TRACE_TYPE_GENERIC,
+ "[%02u] collecting data ...", i );
+ continue;
+ }
+
+ sprintf(p_str, "[%02u] throughput: %5u, ack_delay avg:%3u, min:%3u, max:%3u, ack_q_count avg:%3u, min:%3u, max:%3u",
+ i, p_ccb->fcrb.throughput[i],
+ p_ccb->fcrb.ack_delay_avg[i], p_ccb->fcrb.ack_delay_min[i], p_ccb->fcrb.ack_delay_max[i],
+ p_ccb->fcrb.ack_q_count_avg[i], p_ccb->fcrb.ack_q_count_min[i], p_ccb->fcrb.ack_q_count_max[i] );
+
+ BT_TRACE_1(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI , TRACE_TYPE_GENERIC, "%s", p_str);
+
+ throughput_avg += p_ccb->fcrb.throughput[i];
+ ack_delay_avg += p_ccb->fcrb.ack_delay_avg[i];
+ ack_q_count_avg += p_ccb->fcrb.ack_q_count_avg[i];
+ }
+
+ throughput_avg /= (L2CAP_ERTM_STATS_NUM_AVG - 1);
+ ack_delay_avg /= (L2CAP_ERTM_STATS_NUM_AVG - 1);
+ ack_q_count_avg /= (L2CAP_ERTM_STATS_NUM_AVG - 1);
+
+ BT_TRACE_3(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI , TRACE_TYPE_GENERIC,
+ "throughput_avg: %8u (kbytes/sec), ack_delay_avg: %8u ms, ack_q_count_avg: %8u",
+ throughput_avg, ack_delay_avg, ack_q_count_avg );
+
+ GKI_freebuf(p_str);
+ }
+
+ BT_TRACE_0(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI , TRACE_TYPE_GENERIC,
+ "---");
+ }
+#endif
+
+ memset (p_fcrb, 0, sizeof (tL2C_FCRB));
+}
+
+/*******************************************************************************
+**
+** Function l2c_fcr_clone_buf
+**
+** Description This function allocates and copies requested part of a buffer
+** at a new-offset.
+**
+** Returns pointer to new buffer
+**
+*******************************************************************************/
+BT_HDR *l2c_fcr_clone_buf (BT_HDR *p_buf, UINT16 new_offset, UINT16 no_of_bytes, UINT8 pool)
+{
+ BT_HDR *p_buf2;
+
+ /* If using the common pool, should be at least 10% free. */
+ if ( (pool == HCI_ACL_POOL_ID) && (GKI_poolutilization (pool) > 90) )
+ {
+ L2CAP_TRACE_ERROR1 ("L2CAP - failed to clone buffer on HCI_ACL_POOL_ID Utilization: %u", GKI_poolutilization(pool));
+ return (NULL);
+ }
+
+ if ((p_buf2 = (BT_HDR *)GKI_getpoolbuf(pool)) != NULL)
+ {
+ UINT16 pool_buf_size = GKI_get_pool_bufsize (pool);
+
+ /* Make sure buffer fits into buffer pool */
+ if ((no_of_bytes + sizeof(BT_HDR) + new_offset) > pool_buf_size)
+ {
+ L2CAP_TRACE_ERROR5("##### l2c_fcr_clone_buf (NumBytes %d) -> Exceeds poolsize %d [bytes %d + BT_HDR %d + offset %d]",
+ (no_of_bytes + sizeof(BT_HDR) + new_offset),
+ pool_buf_size, no_of_bytes, sizeof(BT_HDR),
+ new_offset);
+
+ GKI_freebuf(p_buf2);
+ return (NULL);
+ }
+
+ p_buf2->offset = new_offset;
+ p_buf2->len = no_of_bytes;
+
+ memcpy (((UINT8 *)(p_buf2 + 1)) + p_buf2->offset,
+ ((UINT8 *)(p_buf + 1)) + p_buf->offset,
+ no_of_bytes);
+ }
+ else
+ {
+ L2CAP_TRACE_ERROR2 ("L2CAP - failed to clone buffer, Pool: %u Count: %u", pool, GKI_poolfreecount(pool));
+ }
+
+ return (p_buf2);
+}
+
+/*******************************************************************************
+**
+** Function l2c_fcr_is_flow_controlled
+**
+** Description This function checks if the CCB is flow controlled by peer.
+**
+** Returns The control word
+**
+*******************************************************************************/
+BOOLEAN l2c_fcr_is_flow_controlled (tL2C_CCB *p_ccb)
+{
+ if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE)
+ {
+ /* Check if remote side flowed us off or the transmit window is full */
+ if ( (p_ccb->fcrb.remote_busy == TRUE)
+ || (p_ccb->fcrb.waiting_for_ack_q.count >= p_ccb->peer_cfg.fcr.tx_win_sz) )
+ {
+#if (L2CAP_ERTM_STATS == TRUE)
+ if (p_ccb->xmit_hold_q.count != 0)
+ {
+ p_ccb->fcrb.xmit_window_closed++;
+
+ if ((p_ccb->p_lcb->sent_not_acked < 2)&&(l2cb.controller_xmit_window > 0))
+ p_ccb->fcrb.controller_idle++;
+ }
+#endif
+ return (TRUE);
+ }
+ }
+ return (FALSE);
+}
+
+/*******************************************************************************
+**
+** Function prepare_I_frame
+**
+** Description This function sets the FCR variables in an I-frame that is
+** about to be sent to HCI for transmission. This may be the
+** first time the I-frame is sent, or a retransmission
+**
+** Returns -
+**
+*******************************************************************************/
+static void prepare_I_frame (tL2C_CCB *p_ccb, BT_HDR *p_buf, BOOLEAN is_retransmission)
+{
+ tL2C_FCRB *p_fcrb = &p_ccb->fcrb;
+ UINT8 *p;
+ UINT16 fcs;
+ UINT16 ctrl_word;
+ BOOLEAN set_f_bit = p_fcrb->send_f_rsp;
+
+ p_fcrb->send_f_rsp = FALSE;
+
+ if (is_retransmission)
+ {
+ /* Get the old control word and clear out the old req_seq and F bits */
+ p = ((UINT8 *) (p_buf+1)) + p_buf->offset + L2CAP_PKT_OVERHEAD;
+
+ STREAM_TO_UINT16 (ctrl_word, p);
+
+ ctrl_word &= ~(L2CAP_FCR_REQ_SEQ_BITS + L2CAP_FCR_F_BIT);
+ }
+ else
+ {
+ ctrl_word = p_buf->layer_specific & L2CAP_FCR_SEG_BITS; /* SAR bits */
+ ctrl_word |= (p_fcrb->next_tx_seq << L2CAP_FCR_TX_SEQ_BITS_SHIFT); /* Tx Seq */
+
+ p_fcrb->next_tx_seq = (p_fcrb->next_tx_seq + 1) & L2CAP_FCR_SEQ_MODULO;
+ }
+
+ /* Set the F-bit and reqseq only if using re-transmission mode */
+ if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE)
+ {
+ if (set_f_bit)
+ ctrl_word |= L2CAP_FCR_F_BIT;
+
+ ctrl_word |= (p_fcrb->next_seq_expected) << L2CAP_FCR_REQ_SEQ_BITS_SHIFT;
+
+ p_fcrb->last_ack_sent = p_ccb->fcrb.next_seq_expected;
+
+ if (p_ccb->fcrb.ack_timer.in_use)
+ btu_stop_quick_timer (&p_ccb->fcrb.ack_timer);
+ }
+
+ /* Set the control word */
+ p = ((UINT8 *) (p_buf+1)) + p_buf->offset + L2CAP_PKT_OVERHEAD;
+
+ UINT16_TO_STREAM (p, ctrl_word);
+
+ /* Compute the FCS and add to the end of the buffer if not bypassed */
+ if (p_ccb->bypass_fcs != L2CAP_BYPASS_FCS)
+ {
+ /* length field in l2cap header has to include FCS length */
+ p = ((UINT8 *) (p_buf+1)) + p_buf->offset;
+ UINT16_TO_STREAM (p, p_buf->len + L2CAP_FCS_LEN - L2CAP_PKT_OVERHEAD);
+
+ /* Calculate the FCS */
+ fcs = l2c_fcr_tx_get_fcs(p_buf);
+
+ /* Point to the end of the buffer and put the FCS there */
+ p = ((UINT8 *) (p_buf+1)) + p_buf->offset + p_buf->len;
+
+ UINT16_TO_STREAM (p, fcs);
+
+ p_buf->len += L2CAP_FCS_LEN;
+ }
+
+#if BT_TRACE_VERBOSE == TRUE
+ if (is_retransmission)
+ {
+ L2CAP_TRACE_EVENT6 ("L2CAP eRTM ReTx I-frame CID: 0x%04x Len: %u SAR: %s TxSeq: %u ReqSeq: %u F: %u",
+ p_ccb->local_cid, p_buf->len,
+ SAR_types[(ctrl_word & L2CAP_FCR_SAR_BITS) >> L2CAP_FCR_SAR_BITS_SHIFT],
+ (ctrl_word & L2CAP_FCR_TX_SEQ_BITS) >> L2CAP_FCR_TX_SEQ_BITS_SHIFT,
+ (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT,
+ (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT);
+ }
+ else
+ {
+ L2CAP_TRACE_EVENT6 ("L2CAP eRTM Tx I-frame CID: 0x%04x Len: %u SAR: %-12s TxSeq: %u ReqSeq: %u F: %u",
+ p_ccb->local_cid, p_buf->len,
+ SAR_types[(ctrl_word & L2CAP_FCR_SAR_BITS) >> L2CAP_FCR_SAR_BITS_SHIFT],
+ (ctrl_word & L2CAP_FCR_TX_SEQ_BITS) >> L2CAP_FCR_TX_SEQ_BITS_SHIFT,
+ (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT,
+ (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT);
+ }
+#endif
+
+ /* Start the retransmission timer if not already running */
+ if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE)
+ l2c_fcr_start_timer (p_ccb);
+}
+
+/*******************************************************************************
+**
+** Function l2c_fcr_send_S_frame
+**
+** Description This function formats and sends an S-frame for transmission.
+**
+** Returns -
+**
+*******************************************************************************/
+void l2c_fcr_send_S_frame (tL2C_CCB *p_ccb, UINT16 function_code, UINT16 pf_bit)
+{
+ BT_HDR *p_buf;
+ UINT8 *p;
+ UINT16 ctrl_word;
+ UINT16 fcs;
+
+#if L2CAP_CORRUPT_ERTM_PKTS == TRUE
+ /* Only used for conformance testing */
+ if (l2c_bypass_sframe_packet (p_ccb))
+ return;
+#endif
+
+ if ((!p_ccb->in_use) || (p_ccb->chnl_state != CST_OPEN))
+ return;
+
+#if (L2CAP_ERTM_STATS == TRUE)
+ p_ccb->fcrb.s_frames_sent[function_code]++;
+#endif
+
+ if (pf_bit == L2CAP_FCR_P_BIT)
+ {
+ p_ccb->fcrb.wait_ack = TRUE;
+
+ l2c_fcr_stop_timer (p_ccb); /* Restart the monitor timer */
+ l2c_fcr_start_timer (p_ccb);
+ }
+
+ /* Create the control word to use */
+ ctrl_word = (function_code << L2CAP_FCR_SUP_SHIFT) | L2CAP_FCR_S_FRAME_BIT;
+ ctrl_word |= (p_ccb->fcrb.next_seq_expected << L2CAP_FCR_REQ_SEQ_BITS_SHIFT);
+ ctrl_word |= pf_bit;
+
+ if ((p_buf = (BT_HDR *)GKI_getpoolbuf (L2CAP_CMD_POOL_ID)) != NULL)
+ {
+ p_buf->offset = HCI_DATA_PREAMBLE_SIZE;
+ p_buf->len = L2CAP_PKT_OVERHEAD + L2CAP_FCR_OVERHEAD;
+
+ /* Set the pointer to the beginning of the data */
+ p = (UINT8 *)(p_buf + 1) + p_buf->offset;
+
+ /* Put in the L2CAP header */
+ UINT16_TO_STREAM (p, L2CAP_FCR_OVERHEAD + L2CAP_FCS_LEN);
+ UINT16_TO_STREAM (p, p_ccb->remote_cid);
+ UINT16_TO_STREAM (p, ctrl_word);
+
+ /* Compute the FCS and add to the end of the buffer if not bypassed */
+ if (p_ccb->bypass_fcs != L2CAP_BYPASS_FCS)
+ {
+ fcs = l2c_fcr_tx_get_fcs (p_buf);
+
+ UINT16_TO_STREAM (p, fcs);
+ p_buf->len += L2CAP_FCS_LEN;
+ }
+ else /* rewrite the length without FCS length */
+ {
+ p -= 6;
+ UINT16_TO_STREAM (p, L2CAP_FCR_OVERHEAD);
+ }
+
+#if L2CAP_CORRUPT_ERTM_PKTS == TRUE
+ /* Get out if packet was dropped */
+ if (l2c_corrupt_the_fcr_packet (p_ccb, p_buf, FALSE, ctrl_word))
+ return;
+#endif
+ /* Now, the HCI transport header */
+ p_buf->layer_specific = L2CAP_NON_FLUSHABLE_PKT;
+ l2cu_set_acl_hci_header (p_buf, p_ccb);
+
+#if BT_TRACE_VERBOSE == TRUE
+ if ((((ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT) == 1)
+ || (((ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT) == 3))
+ {
+ L2CAP_TRACE_WARNING6 ("L2CAP eRTM Tx S-frame CID: 0x%04x ctrlword: 0x%04x Type: %s ReqSeq: %u P: %u F: %u",
+ p_ccb->local_cid, ctrl_word,
+ SUP_types[(ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT],
+ (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT,
+ (ctrl_word & L2CAP_FCR_P_BIT) >> L2CAP_FCR_P_BIT_SHIFT,
+ (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT);
+ L2CAP_TRACE_WARNING1 (" Buf Len: %u", p_buf->len);
+ }
+ else
+ {
+ L2CAP_TRACE_EVENT6 ("L2CAP eRTM Tx S-frame CID: 0x%04x ctrlword: 0x%04x Type: %s ReqSeq: %u P: %u F: %u",
+ p_ccb->local_cid, ctrl_word,
+ SUP_types[(ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT],
+ (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT,
+ (ctrl_word & L2CAP_FCR_P_BIT) >> L2CAP_FCR_P_BIT_SHIFT,
+ (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT);
+ L2CAP_TRACE_EVENT1 (" Buf Len: %u", p_buf->len);
+ }
+#endif /* BT_TRACE_VERBOSE */
+
+ l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, p_buf);
+
+ p_ccb->fcrb.last_ack_sent = p_ccb->fcrb.next_seq_expected;
+
+ if (p_ccb->fcrb.ack_timer.in_use)
+ btu_stop_quick_timer (&p_ccb->fcrb.ack_timer);
+ }
+ else
+ {
+ L2CAP_TRACE_ERROR2 ("l2c_fcr_send_S_frame(No Resources) cid 0x%04x, Type: 0x%4x",
+ p_ccb->local_cid, function_code);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function l2c_fcr_proc_pdu
+**
+** Description This function is the entry point for processing of a
+** received PDU when in flow control and/or retransmission modes.
+**
+** Returns -
+**
+*******************************************************************************/
+void l2c_fcr_proc_pdu (tL2C_CCB *p_ccb, BT_HDR *p_buf)
+{
+ UINT8 *p;
+ UINT16 fcs;
+ UINT16 min_pdu_len;
+ UINT16 ctrl_word;
+
+ /* Check the length */
+ min_pdu_len = (p_ccb->bypass_fcs == L2CAP_BYPASS_FCS) ?
+ (UINT16)L2CAP_FCR_OVERHEAD : (UINT16)(L2CAP_FCS_LEN + L2CAP_FCR_OVERHEAD);
+
+ if (p_buf->len < min_pdu_len)
+ {
+ L2CAP_TRACE_WARNING2 ("Rx L2CAP PDU: CID: 0x%04x Len too short: %u", p_ccb->local_cid, p_buf->len);
+ GKI_freebuf (p_buf);
+ return;
+ }
+
+ if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_STREAM_MODE)
+ {
+ process_stream_frame (p_ccb, p_buf);
+ return;
+ }
+
+#if BT_TRACE_VERBOSE == TRUE
+ /* Get the control word */
+ p = ((UINT8 *)(p_buf+1)) + p_buf->offset;
+ STREAM_TO_UINT16 (ctrl_word, p);
+
+ if (ctrl_word & L2CAP_FCR_S_FRAME_BIT)
+ {
+ if ((((ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT) == 1)
+ || (((ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT) == 3))
+ {
+ /* REJ or SREJ */
+ L2CAP_TRACE_WARNING6 ("L2CAP eRTM Rx S-frame: cid: 0x%04x Len: %u Type: %s ReqSeq: %u P: %u F: %u",
+ p_ccb->local_cid, p_buf->len,
+ SUP_types[(ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT],
+ (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT,
+ (ctrl_word & L2CAP_FCR_P_BIT) >> L2CAP_FCR_P_BIT_SHIFT,
+ (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT);
+ }
+ else
+ {
+ L2CAP_TRACE_EVENT6 ("L2CAP eRTM Rx S-frame: cid: 0x%04x Len: %u Type: %s ReqSeq: %u P: %u F: %u",
+ p_ccb->local_cid, p_buf->len,
+ SUP_types[(ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT],
+ (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT,
+ (ctrl_word & L2CAP_FCR_P_BIT) >> L2CAP_FCR_P_BIT_SHIFT,
+ (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT);
+ }
+ }
+ else
+ {
+ L2CAP_TRACE_EVENT6 ("L2CAP eRTM Rx I-frame: cid: 0x%04x Len: %u SAR: %-12s TxSeq: %u ReqSeq: %u F: %u",
+ p_ccb->local_cid, p_buf->len,
+ SAR_types[(ctrl_word & L2CAP_FCR_SAR_BITS) >> L2CAP_FCR_SAR_BITS_SHIFT],
+ (ctrl_word & L2CAP_FCR_TX_SEQ_BITS) >> L2CAP_FCR_TX_SEQ_BITS_SHIFT,
+ (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT,
+ (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT);
+ }
+
+ L2CAP_TRACE_EVENT6 (" eRTM Rx Nxt_tx_seq %u, Lst_rx_ack %u, Nxt_seq_exp %u, Lst_ack_snt %u, wt_q.cnt %u, tries %u",
+ p_ccb->fcrb.next_tx_seq, p_ccb->fcrb.last_rx_ack, p_ccb->fcrb.next_seq_expected,
+ p_ccb->fcrb.last_ack_sent, p_ccb->fcrb.waiting_for_ack_q.count, p_ccb->fcrb.num_tries);
+
+#endif /* BT_TRACE_VERBOSE */
+
+#if L2CAP_CORRUPT_ERTM_PKTS == TRUE
+ p = ((UINT8 *)(p_buf+1)) + p_buf->offset;
+ STREAM_TO_UINT16 (ctrl_word, p);
+
+ /* Get out if packet was dropped */
+ if (l2c_corrupt_the_fcr_packet (p_ccb, p_buf, TRUE, ctrl_word))
+ return;
+#endif /* L2CAP_CORRUPT_ERTM_PKTS */
+
+ /* Verify FCS if using */
+ if (p_ccb->bypass_fcs != L2CAP_BYPASS_FCS)
+ {
+ p = ((UINT8 *)(p_buf+1)) + p_buf->offset + p_buf->len - L2CAP_FCS_LEN;
+
+ /* Extract and drop the FCS from the packet */
+ STREAM_TO_UINT16 (fcs, p);
+ p_buf->len -= L2CAP_FCS_LEN;
+
+ if (l2c_fcr_rx_get_fcs(p_buf) != fcs)
+ {
+ L2CAP_TRACE_WARNING1 ("Rx L2CAP PDU: CID: 0x%04x BAD FCS", p_ccb->local_cid);
+ GKI_freebuf(p_buf);
+ return;
+ }
+ }
+
+ /* Get the control word */
+ p = ((UINT8 *)(p_buf+1)) + p_buf->offset;
+
+ STREAM_TO_UINT16 (ctrl_word, p);
+
+ p_buf->len -= L2CAP_FCR_OVERHEAD;
+ p_buf->offset += L2CAP_FCR_OVERHEAD;
+
+ /* If we had a poll bit outstanding, check if we got a final response */
+ if (p_ccb->fcrb.wait_ack)
+ {
+ /* If final bit not set, ignore the frame unless it is a polled S-frame */
+ if ( !(ctrl_word & L2CAP_FCR_F_BIT) )
+ {
+ if ( (ctrl_word & L2CAP_FCR_P_BIT) && (ctrl_word & L2CAP_FCR_S_FRAME_BIT) )
+ {
+ if (p_ccb->fcrb.srej_sent)
+ l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_SREJ, L2CAP_FCR_F_BIT);
+ else if (p_ccb->fcrb.local_busy)
+ l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RNR, L2CAP_FCR_F_BIT);
+ else
+ l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RR, L2CAP_FCR_F_BIT);
+
+ /* Got a poll while in wait_ack state, so re-start our timer with 1-second */
+ /* This is a small optimization... the monitor timer is 12 secs, but we saw */
+ /* that if the other side sends us a poll when we are waiting for a final, */
+ /* then it speeds up recovery significantly if we poll him back soon after his poll. */
+ btu_start_quick_timer (&p_ccb->fcrb.mon_retrans_timer, BTU_TTYPE_L2CAP_CHNL, QUICK_TIMER_TICKS_PER_SEC);
+ }
+ GKI_freebuf (p_buf);
+ return;
+ }
+
+ p_ccb->fcrb.wait_ack = FALSE;
+
+ /* P and F are mutually exclusive */
+ if (ctrl_word & L2CAP_FCR_S_FRAME_BIT)
+ ctrl_word &= ~L2CAP_FCR_P_BIT;
+
+ if (p_ccb->fcrb.waiting_for_ack_q.count == 0)
+ p_ccb->fcrb.num_tries = 0;
+
+ l2c_fcr_stop_timer (p_ccb);
+ }
+ else
+ {
+ /* Otherwise, ensure the final bit is ignored */
+ ctrl_word &= ~L2CAP_FCR_F_BIT;
+ }
+
+ /* Process receive sequence number */
+ if (!process_reqseq (p_ccb, ctrl_word))
+ {
+ GKI_freebuf (p_buf);
+ return;
+ }
+
+ /* Process based on whether it is an S-frame or an I-frame */
+ if (ctrl_word & L2CAP_FCR_S_FRAME_BIT)
+ process_s_frame (p_ccb, p_buf, ctrl_word);
+ else
+ process_i_frame (p_ccb, p_buf, ctrl_word, FALSE);
+
+ /* Return if the channel got disconnected by a bad packet or max retransmissions */
+ if ( (!p_ccb->in_use) || (p_ccb->chnl_state != CST_OPEN) )
+ return;
+
+ /* If we have some buffers held while doing SREJ, and SREJ has cleared, process them now */
+ if ( (!p_ccb->fcrb.local_busy) && (!p_ccb->fcrb.srej_sent) && (p_ccb->fcrb.srej_rcv_hold_q.count > 0) )
+ {
+ BUFFER_Q temp_q = p_ccb->fcrb.srej_rcv_hold_q;
+
+ GKI_init_q (&p_ccb->fcrb.srej_rcv_hold_q);
+
+ while ((p_buf = (BT_HDR *)GKI_dequeue (&temp_q)) != NULL)
+ {
+ if (p_ccb->in_use && (p_ccb->chnl_state == CST_OPEN))
+ {
+ /* Get the control word */
+ p = ((UINT8 *)(p_buf+1)) + p_buf->offset - L2CAP_FCR_OVERHEAD;
+
+ STREAM_TO_UINT16 (ctrl_word, p);
+
+ L2CAP_TRACE_DEBUG3 ("l2c_fcr_proc_pdu() CID: 0x%04x Process Buffer from SREJ_Hold_Q TxSeq: %u Expected_Seq: %u",
+ p_ccb->local_cid, (ctrl_word & L2CAP_FCR_TX_SEQ_BITS) >> L2CAP_FCR_TX_SEQ_BITS_SHIFT,
+ p_ccb->fcrb.next_seq_expected);
+
+ /* Process the SREJ held I-frame, but do not send an RR for each individual frame */
+ process_i_frame (p_ccb, p_buf, ctrl_word, TRUE);
+ }
+ else
+ GKI_freebuf (p_buf);
+
+ /* If more frames were lost during SREJ, send a REJ */
+ if (p_ccb->fcrb.rej_after_srej)
+ {
+ p_ccb->fcrb.rej_after_srej = FALSE;
+ p_ccb->fcrb.rej_sent = TRUE;
+
+ l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_REJ, 0);
+ }
+ }
+
+ /* Now, if needed, send one RR for the whole held queue */
+ if ( (!p_ccb->fcrb.local_busy) && (!p_ccb->fcrb.rej_sent) && (!p_ccb->fcrb.srej_sent)
+ && (p_ccb->fcrb.next_seq_expected != p_ccb->fcrb.last_ack_sent) )
+ l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RR, 0);
+ else
+ {
+ L2CAP_TRACE_DEBUG6 ("l2c_fcr_proc_pdu() not sending RR CID: 0x%04x local_busy:%d rej_sent:%d srej_sent:%d Expected_Seq:%u Last_Ack:%u",
+ p_ccb->local_cid, p_ccb->fcrb.local_busy, p_ccb->fcrb.rej_sent, p_ccb->fcrb.srej_sent, p_ccb->fcrb.next_seq_expected,
+ p_ccb->fcrb.last_ack_sent);
+ }
+ }
+
+ /* If a window has opened, check if we can send any more packets */
+ if ( (p_ccb->fcrb.retrans_q.count || p_ccb->xmit_hold_q.count)
+ && (p_ccb->fcrb.wait_ack == FALSE)
+ && (l2c_fcr_is_flow_controlled (p_ccb) == FALSE) )
+ {
+ l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, NULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function l2c_fcr_proc_tout
+**
+** Description Handle a timeout. We should be in error recovery state.
+**
+** Returns -
+**
+*******************************************************************************/
+void l2c_fcr_proc_tout (tL2C_CCB *p_ccb)
+{
+ L2CAP_TRACE_DEBUG5 ("l2c_fcr_proc_tout: CID: 0x%04x num_tries: %u (max: %u) wait_ack: %u ack_q_count: %u",
+ p_ccb->local_cid, p_ccb->fcrb.num_tries, p_ccb->peer_cfg.fcr.max_transmit,
+ p_ccb->fcrb.wait_ack, p_ccb->fcrb.waiting_for_ack_q.count);
+
+#if (L2CAP_ERTM_STATS == TRUE)
+ p_ccb->fcrb.retrans_touts++;
+#endif
+
+ if ( (p_ccb->peer_cfg.fcr.max_transmit != 0) && (++p_ccb->fcrb.num_tries > p_ccb->peer_cfg.fcr.max_transmit) )
+ {
+ l2cu_disconnect_chnl (p_ccb);
+ }
+ else
+ {
+ if (!p_ccb->fcrb.srej_sent && !p_ccb->fcrb.rej_sent)
+ {
+ if (p_ccb->fcrb.local_busy)
+ l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RNR, L2CAP_FCR_P_BIT);
+ else
+ l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RR, L2CAP_FCR_P_BIT);
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function l2c_fcr_proc_ack_tout
+**
+** Description Send RR/RNR if we have not acked I frame
+**
+** Returns -
+**
+*******************************************************************************/
+void l2c_fcr_proc_ack_tout (tL2C_CCB *p_ccb)
+{
+ L2CAP_TRACE_DEBUG5 ("l2c_fcr_proc_ack_tout: CID: 0x%04x State: %u Wack:%u Rq:%d Acked:%d", p_ccb->local_cid,
+ p_ccb->chnl_state, p_ccb->fcrb.wait_ack, p_ccb->fcrb.next_seq_expected, p_ccb->fcrb.last_ack_sent);
+
+ if ( (p_ccb->chnl_state == CST_OPEN) && (!p_ccb->fcrb.wait_ack)
+ && (p_ccb->fcrb.last_ack_sent != p_ccb->fcrb.next_seq_expected) )
+ {
+#if (L2CAP_ERTM_STATS == TRUE)
+ p_ccb->fcrb.xmit_ack_touts++;
+#endif
+ if (p_ccb->fcrb.local_busy)
+ l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RNR, 0);
+ else
+ l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RR, 0);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function process_reqseq
+**
+** Description Handle receive sequence number
+**
+** Returns -
+**
+*******************************************************************************/
+static BOOLEAN process_reqseq (tL2C_CCB *p_ccb, UINT16 ctrl_word)
+{
+ tL2C_FCRB *p_fcrb = &p_ccb->fcrb;
+ UINT8 req_seq, num_bufs_acked, xx;
+ UINT16 ls;
+ UINT16 full_sdus_xmitted;
+
+ /* Receive sequence number does not ack anything for SREJ with P-bit set to zero */
+ if ( (ctrl_word & L2CAP_FCR_S_FRAME_BIT)
+ && ((ctrl_word & L2CAP_FCR_SUP_BITS) == (L2CAP_FCR_SUP_SREJ << L2CAP_FCR_SUP_SHIFT))
+ && ((ctrl_word & L2CAP_FCR_P_BIT) == 0) )
+ {
+ /* If anything still waiting for ack, restart the timer if it was stopped */
+ if (p_fcrb->waiting_for_ack_q.count)
+ l2c_fcr_start_timer (p_ccb);
+
+ return (TRUE);
+ }
+
+ /* Extract the receive sequence number from the control word */
+ req_seq = (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT;
+
+ num_bufs_acked = (req_seq - p_fcrb->last_rx_ack) & L2CAP_FCR_SEQ_MODULO;
+
+ /* Verify the request sequence is in range before proceeding */
+ if (num_bufs_acked > p_fcrb->waiting_for_ack_q.count)
+ {
+ /* The channel is closed if ReqSeq is not in range */
+ L2CAP_TRACE_WARNING4 ("L2CAP eRTM Frame BAD Req_Seq - ctrl_word: 0x%04x req_seq 0x%02x last_rx_ack: 0x%02x QCount: %u",
+ ctrl_word, req_seq, p_fcrb->last_rx_ack, p_fcrb->waiting_for_ack_q.count);
+
+ l2cu_disconnect_chnl (p_ccb);
+ return (FALSE);
+ }
+
+/*
+ L2CAP_TRACE_DEBUG3 ("L2CAP process_reqseq 0x%02x last_rx_ack: 0x%02x QCount: %u",
+ req_seq, p_fcrb->last_rx_ack, p_fcrb->waiting_for_ack_q.count);
+*/
+ p_fcrb->last_rx_ack = req_seq;
+
+ /* Now we can release all acknowledged frames, and restart the retransmission timer if needed */
+ if (num_bufs_acked != 0)
+ {
+ p_fcrb->num_tries = 0;
+ full_sdus_xmitted = 0;
+
+#if (L2CAP_ERTM_STATS == TRUE)
+ l2c_fcr_collect_ack_delay (p_ccb, num_bufs_acked);
+#endif
+
+ for (xx = 0; xx < num_bufs_acked; xx++)
+ {
+ ls = ((BT_HDR *)(p_fcrb->waiting_for_ack_q.p_first))->layer_specific & L2CAP_FCR_SAR_BITS;
+
+ if ( (ls == L2CAP_FCR_UNSEG_SDU) || (ls == L2CAP_FCR_END_SDU) )
+ full_sdus_xmitted++;
+
+ GKI_freebuf (GKI_dequeue (&p_fcrb->waiting_for_ack_q));
+ }
+
+ /* If we are still in a wait_ack state, do not mess with the timer */
+ if (!p_ccb->fcrb.wait_ack)
+ l2c_fcr_stop_timer (p_ccb);
+
+ /* Check if we need to call the "packet_sent" callback */
+ if ( (p_ccb->p_rcb) && (p_ccb->p_rcb->api.pL2CA_TxComplete_Cb) && (full_sdus_xmitted) )
+ {
+ /* Special case for eRTM, if all packets sent, send 0xFFFF */
+ if ( (p_fcrb->waiting_for_ack_q.count == 0) && (p_ccb->xmit_hold_q.count == 0) )
+ full_sdus_xmitted = 0xFFFF;
+
+ (*p_ccb->p_rcb->api.pL2CA_TxComplete_Cb)(p_ccb->local_cid, full_sdus_xmitted);
+ }
+ }
+
+ /* If anything still waiting for ack, restart the timer if it was stopped */
+ if (p_fcrb->waiting_for_ack_q.count)
+ l2c_fcr_start_timer (p_ccb);
+
+ return (TRUE);
+}
+
+
+/*******************************************************************************
+**
+** Function process_s_frame
+**
+** Description Process an S frame
+**
+** Returns -
+**
+*******************************************************************************/
+static void process_s_frame (tL2C_CCB *p_ccb, BT_HDR *p_buf, UINT16 ctrl_word)
+{
+ tL2C_FCRB *p_fcrb = &p_ccb->fcrb;
+ UINT16 s_frame_type = (ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT;
+ BOOLEAN remote_was_busy;
+ BOOLEAN all_ok = TRUE;
+
+ if (p_buf->len != 0)
+ {
+ L2CAP_TRACE_WARNING1 ("Incorrect S-frame Length (%d)", p_buf->len);
+ }
+
+ L2CAP_TRACE_DEBUG2 ("process_s_frame ctrl_word 0x%04x fcrb_remote_busy:%d", ctrl_word, p_fcrb->remote_busy);
+
+#if (L2CAP_ERTM_STATS == TRUE)
+ p_ccb->fcrb.s_frames_rcvd[s_frame_type]++;
+#endif
+
+ if (ctrl_word & L2CAP_FCR_P_BIT)
+ {
+ p_fcrb->rej_sent = FALSE; /* After checkpoint, we can send anoher REJ */
+ p_fcrb->send_f_rsp = TRUE; /* Set a flag in case an I-frame is pending */
+ }
+
+ switch (s_frame_type)
+ {
+ case L2CAP_FCR_SUP_RR:
+ remote_was_busy = p_fcrb->remote_busy;
+ p_fcrb->remote_busy = FALSE;
+
+ if ( (ctrl_word & L2CAP_FCR_F_BIT) || (remote_was_busy) )
+ all_ok = retransmit_i_frames (p_ccb, L2C_FCR_RETX_ALL_PKTS);
+ break;
+
+ case L2CAP_FCR_SUP_REJ:
+ p_fcrb->remote_busy = FALSE;
+ all_ok = retransmit_i_frames (p_ccb, L2C_FCR_RETX_ALL_PKTS);
+ break;
+
+ case L2CAP_FCR_SUP_RNR:
+ p_fcrb->remote_busy = TRUE;
+ l2c_fcr_stop_timer (p_ccb);
+ break;
+
+ case L2CAP_FCR_SUP_SREJ:
+ p_fcrb->remote_busy = FALSE;
+ all_ok = retransmit_i_frames (p_ccb, (UINT8)((ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT));
+ break;
+ }
+
+ if (all_ok)
+ {
+ /* If polled, we need to respond with F-bit. Note, we may have sent a I-frame with the F-bit */
+ if (p_fcrb->send_f_rsp)
+ {
+ if (p_fcrb->srej_sent)
+ l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_SREJ, L2CAP_FCR_F_BIT);
+ else if (p_fcrb->local_busy)
+ l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RNR, L2CAP_FCR_F_BIT);
+ else
+ l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RR, L2CAP_FCR_F_BIT);
+
+ p_fcrb->send_f_rsp = FALSE;
+ }
+ }
+ else
+ {
+ L2CAP_TRACE_DEBUG0 ("process_s_frame hit_max_retries");
+ }
+
+ GKI_freebuf (p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function process_i_frame
+**
+** Description Process an I frame
+**
+** Returns -
+**
+*******************************************************************************/
+static void process_i_frame (tL2C_CCB *p_ccb, BT_HDR *p_buf, UINT16 ctrl_word, BOOLEAN delay_ack)
+{
+ tL2C_FCRB *p_fcrb = &p_ccb->fcrb;
+ UINT8 tx_seq, num_lost, num_to_ack, next_srej;
+
+ /* If we were doing checkpoint recovery, first retransmit all unacked I-frames */
+ if (ctrl_word & L2CAP_FCR_F_BIT)
+ {
+ if (!retransmit_i_frames (p_ccb, L2C_FCR_RETX_ALL_PKTS))
+ {
+ GKI_freebuf(p_buf);
+ return;
+ }
+ }
+
+#if (L2CAP_ERTM_STATS == TRUE)
+ p_ccb->fcrb.ertm_pkt_counts[1]++;
+ p_ccb->fcrb.ertm_byte_counts[1] += p_buf->len;
+#endif
+
+ /* Extract the sequence number */
+ tx_seq = (ctrl_word & L2CAP_FCR_TX_SEQ_BITS) >> L2CAP_FCR_TX_SEQ_BITS_SHIFT;
+
+ /* If we have flow controlled the peer, ignore any bad I-frames from him */
+ if ( (tx_seq != p_fcrb->next_seq_expected) && (p_fcrb->local_busy) )
+ {
+ L2CAP_TRACE_WARNING1 ("Dropping bad I-Frame since we flowed off, tx_seq:%u", tx_seq);
+ l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RNR, 0);
+ GKI_freebuf(p_buf);
+ return;
+ }
+
+ /* If there are no free buffers in the user Rx queue, drop the */
+ /* received buffer now before we update any sequence numbers */
+ if (GKI_poolfreecount (p_ccb->ertm_info.user_rx_pool_id) == 0)
+ {
+ L2CAP_TRACE_WARNING4 ("L2CAP CID: 0x%04x Dropping I-Frame seq: %u User RX Pool: %u (Size: %u) has no free buffers!!",
+ p_ccb->local_cid, tx_seq, p_ccb->ertm_info.user_rx_pool_id,
+ GKI_poolcount (p_ccb->ertm_info.user_rx_pool_id));
+ GKI_freebuf(p_buf);
+ return;
+ }
+
+ /* Check if tx-sequence is the expected one */
+ if (tx_seq != p_fcrb->next_seq_expected)
+ {
+ num_lost = (tx_seq - p_fcrb->next_seq_expected) & L2CAP_FCR_SEQ_MODULO;
+
+ /* Is the frame a duplicate ? If so, just drop it */
+ if (num_lost >= p_ccb->our_cfg.fcr.tx_win_sz)
+ {
+ /* Duplicate - simply drop it */
+ L2CAP_TRACE_WARNING2 ("process_i_frame() Dropping Duplicate Frame tx_seq:%u ExpectedTxSeq %u", tx_seq, p_fcrb->next_seq_expected);
+ GKI_freebuf(p_buf);
+ }
+ else
+ {
+ L2CAP_TRACE_WARNING6 ("process_i_frame() CID: 0x%04x Lost: %u tx_seq:%u ExpTxSeq %u Rej: %u SRej: %u",
+ p_ccb->local_cid, num_lost, tx_seq, p_fcrb->next_seq_expected, p_fcrb->rej_sent, p_fcrb->srej_sent);
+
+ if (p_fcrb->srej_sent)
+ {
+ /* If SREJ sent, save the frame for later processing as long as it is in sequence */
+ next_srej = (((BT_HDR *)p_fcrb->srej_rcv_hold_q.p_last)->layer_specific + 1) & L2CAP_FCR_SEQ_MODULO;
+
+ if ( (tx_seq == next_srej) && (p_fcrb->srej_rcv_hold_q.count < p_ccb->our_cfg.fcr.tx_win_sz) )
+ {
+ /* If user gave us a pool for held rx buffers, use that */
+ if (p_ccb->ertm_info.fcr_rx_pool_id != HCI_ACL_POOL_ID)
+ {
+ BT_HDR *p_buf2;
+
+ /* Adjust offset and len so that control word is copied */
+ p_buf->offset -= L2CAP_FCR_OVERHEAD;
+ p_buf->len += L2CAP_FCR_OVERHEAD;
+
+ p_buf2 = l2c_fcr_clone_buf (p_buf, p_buf->offset, p_buf->len, p_ccb->ertm_info.fcr_rx_pool_id);
+
+ if (p_buf2)
+ {
+ GKI_freebuf (p_buf);
+ p_buf = p_buf2;
+ }
+ p_buf->offset += L2CAP_FCR_OVERHEAD;
+ p_buf->len -= L2CAP_FCR_OVERHEAD;
+ }
+ L2CAP_TRACE_DEBUG4 ("process_i_frame() Lost: %u tx_seq:%u ExpTxSeq %u Rej: %u SRej1",
+ num_lost, tx_seq, p_fcrb->next_seq_expected, p_fcrb->rej_sent);
+
+ p_buf->layer_specific = tx_seq;
+ GKI_enqueue (&p_fcrb->srej_rcv_hold_q, p_buf);
+ }
+ else
+ {
+ L2CAP_TRACE_WARNING4 ("process_i_frame() CID: 0x%04x frame dropped in Srej Sent next_srej:%u hold_q.count:%u win_sz:%u",
+ p_ccb->local_cid, next_srej, p_fcrb->srej_rcv_hold_q.count, p_ccb->our_cfg.fcr.tx_win_sz);
+
+ p_fcrb->rej_after_srej = TRUE;
+ GKI_freebuf (p_buf);
+ }
+ }
+ else if (p_fcrb->rej_sent)
+ {
+ L2CAP_TRACE_WARNING5 ("process_i_frame() CID: 0x%04x Lost: %u tx_seq:%u ExpTxSeq %u Rej: 1 SRej: %u",
+ p_ccb->local_cid, num_lost, tx_seq, p_fcrb->next_seq_expected, p_fcrb->srej_sent);
+
+ /* If REJ sent, just drop the frame */
+ GKI_freebuf (p_buf);
+ }
+ else
+ {
+ L2CAP_TRACE_DEBUG4 ("process_i_frame() CID: 0x%04x tx_seq:%u ExpTxSeq %u Rej: %u",
+ p_ccb->local_cid, tx_seq, p_fcrb->next_seq_expected, p_fcrb->rej_sent);
+
+ /* If only one lost, we will send SREJ, otherwise we will send REJ */
+ if (num_lost > 1)
+ {
+ GKI_freebuf (p_buf);
+ p_fcrb->rej_sent = TRUE;
+ l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_REJ, 0);
+ }
+ else
+ {
+ if (p_fcrb->srej_rcv_hold_q.count != 0)
+ {
+ L2CAP_TRACE_ERROR3 ("process_i_frame() CID: 0x%04x sending SREJ tx_seq:%d hold_q.count:%u",
+ p_ccb->local_cid, tx_seq, p_fcrb->srej_rcv_hold_q.count);
+ }
+ p_buf->layer_specific = tx_seq;
+ GKI_enqueue (&p_fcrb->srej_rcv_hold_q, p_buf);
+ p_fcrb->srej_sent = TRUE;
+ l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_SREJ, 0);
+ }
+ btu_stop_quick_timer (&p_ccb->fcrb.ack_timer);
+ }
+ }
+ return;
+ }
+
+ /* Seq number is the next expected. Clear possible reject exception in case it occured */
+ p_fcrb->rej_sent = p_fcrb->srej_sent = FALSE;
+
+ /* Adjust the next_seq, so that if the upper layer sends more data in the callback
+ context, the received frame is acked by an I-frame. */
+ p_fcrb->next_seq_expected = (tx_seq + 1) & L2CAP_FCR_SEQ_MODULO;
+
+ /* If any SAR problem in eRTM mode, spec says disconnect. */
+ if (!do_sar_reassembly (p_ccb, p_buf, ctrl_word))
+ {
+ L2CAP_TRACE_WARNING1 ("process_i_frame() CID: 0x%04x reassembly failed", p_ccb->local_cid);
+ l2cu_disconnect_chnl (p_ccb);
+ return;
+ }
+
+ /* RR optimization - if peer can still send us more, then start an ACK timer */
+ num_to_ack = (p_fcrb->next_seq_expected - p_fcrb->last_ack_sent) & L2CAP_FCR_SEQ_MODULO;
+
+ if ( (num_to_ack < p_ccb->fcrb.max_held_acks) && (!p_fcrb->local_busy) )
+ delay_ack = TRUE;
+
+ /* We should neve never ack frame if we are not in OPEN state */
+ if ((num_to_ack != 0) && p_ccb->in_use && (p_ccb->chnl_state == CST_OPEN))
+ {
+ /* If no frames are awaiting transmission or are held, send an RR or RNR S-frame for ack */
+ if (delay_ack)
+ {
+ /* If it is the first I frame we did not ack, start ack timer */
+ if (!p_ccb->fcrb.ack_timer.in_use)
+ {
+ btu_start_quick_timer (&p_ccb->fcrb.ack_timer, BTU_TTYPE_L2CAP_FCR_ACK,
+ (L2CAP_FCR_ACK_TOUT*QUICK_TIMER_TICKS_PER_SEC)/1000);
+ }
+ }
+ else if ( ((p_ccb->xmit_hold_q.count == 0) || (l2c_fcr_is_flow_controlled (p_ccb)))
+ && (p_ccb->fcrb.srej_rcv_hold_q.count == 0) )
+ {
+ if (p_fcrb->local_busy)
+ l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RNR, 0);
+ else
+ l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RR, 0);
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function process_stream_frame
+**
+** Description This function processes frames in streaming mode
+**
+** Returns -
+**
+*******************************************************************************/
+static void process_stream_frame (tL2C_CCB *p_ccb, BT_HDR *p_buf)
+{
+ UINT16 ctrl_word;
+ UINT16 fcs;
+ UINT8 *p;
+ UINT8 tx_seq;
+
+ /* Verify FCS if using */
+ if (p_ccb->bypass_fcs != L2CAP_BYPASS_FCS)
+ {
+ p = ((UINT8 *)(p_buf+1)) + p_buf->offset + p_buf->len - L2CAP_FCS_LEN;
+
+ /* Extract and drop the FCS from the packet */
+ STREAM_TO_UINT16 (fcs, p);
+ p_buf->len -= L2CAP_FCS_LEN;
+
+ if (l2c_fcr_rx_get_fcs(p_buf) != fcs)
+ {
+ L2CAP_TRACE_WARNING1 ("Rx L2CAP PDU: CID: 0x%04x BAD FCS", p_ccb->local_cid);
+ GKI_freebuf(p_buf);
+ return;
+ }
+ }
+
+ /* Get the control word */
+ p = ((UINT8 *)(p_buf+1)) + p_buf->offset;
+
+ STREAM_TO_UINT16 (ctrl_word, p);
+
+ p_buf->len -= L2CAP_FCR_OVERHEAD;
+ p_buf->offset += L2CAP_FCR_OVERHEAD;
+
+ /* Make sure it is an I-frame */
+ if (ctrl_word & L2CAP_FCR_S_FRAME_BIT)
+ {
+ L2CAP_TRACE_WARNING2 ("Rx L2CAP PDU: CID: 0x%04x BAD S-frame in streaming mode ctrl_word: 0x%04x", p_ccb->local_cid, ctrl_word);
+ GKI_freebuf (p_buf);
+ return;
+ }
+
+#if BT_TRACE_VERBOSE == TRUE
+ L2CAP_TRACE_EVENT6 ("L2CAP eRTM Rx I-frame: cid: 0x%04x Len: %u SAR: %-12s TxSeq: %u ReqSeq: %u F: %u",
+ p_ccb->local_cid, p_buf->len,
+ SAR_types[(ctrl_word & L2CAP_FCR_SAR_BITS) >> L2CAP_FCR_SAR_BITS_SHIFT],
+ (ctrl_word & L2CAP_FCR_TX_SEQ_BITS) >> L2CAP_FCR_TX_SEQ_BITS_SHIFT,
+ (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT,
+ (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT);
+#endif
+
+ /* Extract the sequence number */
+ tx_seq = (ctrl_word & L2CAP_FCR_TX_SEQ_BITS) >> L2CAP_FCR_TX_SEQ_BITS_SHIFT;
+
+ /* Check if tx-sequence is the expected one */
+ if (tx_seq != p_ccb->fcrb.next_seq_expected)
+ {
+ L2CAP_TRACE_WARNING4 ("Rx L2CAP PDU: CID: 0x%04x Lost frames Exp: %u Got: %u p_rx_sdu: 0x%08x",
+ p_ccb->local_cid, p_ccb->fcrb.next_seq_expected, tx_seq, p_ccb->fcrb.p_rx_sdu);
+
+ /* Lost one or more packets, so flush the SAR queue */
+ if (p_ccb->fcrb.p_rx_sdu != NULL)
+ {
+ GKI_freebuf (p_ccb->fcrb.p_rx_sdu);
+ p_ccb->fcrb.p_rx_sdu = NULL;
+ }
+ }
+
+ p_ccb->fcrb.next_seq_expected = (tx_seq + 1) & L2CAP_FCR_SEQ_MODULO;
+
+ if (!do_sar_reassembly (p_ccb, p_buf, ctrl_word))
+ {
+ /* Some sort of SAR error, so flush the SAR queue */
+ if (p_ccb->fcrb.p_rx_sdu != NULL)
+ {
+ GKI_freebuf (p_ccb->fcrb.p_rx_sdu);
+ p_ccb->fcrb.p_rx_sdu = NULL;
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function do_sar_reassembly
+**
+** Description Process SAR bits and re-assemble frame
+**
+** Returns TRUE if all OK, else FALSE
+**
+*******************************************************************************/
+static BOOLEAN do_sar_reassembly (tL2C_CCB *p_ccb, BT_HDR *p_buf, UINT16 ctrl_word)
+{
+ tL2C_FCRB *p_fcrb = &p_ccb->fcrb;
+ UINT16 sar_type = ctrl_word & L2CAP_FCR_SEG_BITS;
+ BOOLEAN packet_ok = TRUE;
+ UINT8 *p;
+
+ /* Check if the SAR state is correct */
+ if ((sar_type == L2CAP_FCR_UNSEG_SDU) || (sar_type == L2CAP_FCR_START_SDU))
+ {
+ if (p_fcrb->p_rx_sdu != NULL)
+ {
+ L2CAP_TRACE_WARNING2 ("SAR - got unexpected unsegmented or start SDU Expected len: %u Got so far: %u",
+ p_fcrb->rx_sdu_len, p_fcrb->p_rx_sdu->len);
+
+ packet_ok = FALSE;
+ }
+ /* Check the length of the packet */
+ if ( (sar_type == L2CAP_FCR_START_SDU) && (p_buf->len < L2CAP_SDU_LEN_OVERHEAD) )
+ {
+ L2CAP_TRACE_WARNING1 ("SAR start packet too short: %u", p_buf->len);
+ packet_ok = FALSE;
+ }
+ }
+ else
+ {
+ if (p_fcrb->p_rx_sdu == NULL)
+ {
+ L2CAP_TRACE_WARNING0 ("SAR - got unexpected cont or end SDU");
+ packet_ok = FALSE;
+ }
+ }
+
+ if ( (packet_ok) && (sar_type != L2CAP_FCR_UNSEG_SDU) )
+ {
+ p = ((UINT8 *)(p_buf + 1)) + p_buf->offset;
+
+ /* For start SDU packet, extract the SDU length */
+ if (sar_type == L2CAP_FCR_START_SDU)
+ {
+ /* Get the SDU length */
+ STREAM_TO_UINT16 (p_fcrb->rx_sdu_len, p);
+ p_buf->offset += 2;
+ p_buf->len -= 2;
+
+ if (p_fcrb->rx_sdu_len > p_ccb->max_rx_mtu)
+ {
+ L2CAP_TRACE_WARNING2 ("SAR - SDU len: %u larger than MTU: %u", p_fcrb->rx_sdu_len, p_fcrb->rx_sdu_len);
+ packet_ok = FALSE;
+ }
+ else if ((p_fcrb->p_rx_sdu = (BT_HDR *)GKI_getpoolbuf (p_ccb->ertm_info.user_rx_pool_id)) == NULL)
+ {
+ L2CAP_TRACE_ERROR1 ("SAR - no buffer for SDU start user_rx_pool_id:%d", p_ccb->ertm_info.user_rx_pool_id);
+ packet_ok = FALSE;
+ }
+ else
+ {
+ p_fcrb->p_rx_sdu->offset = 4; /* this is the minimal offset required by OBX to process incoming packets */
+ p_fcrb->p_rx_sdu->len = 0;
+ }
+ }
+
+ if (packet_ok)
+ {
+ if ((p_fcrb->p_rx_sdu->len + p_buf->len) > p_fcrb->rx_sdu_len)
+ {
+ L2CAP_TRACE_ERROR4 ("SAR - SDU len exceeded Type: %u Lengths: %u %u %u",
+ sar_type, p_fcrb->p_rx_sdu->len, p_buf->len, p_fcrb->rx_sdu_len);
+ packet_ok = FALSE;
+ }
+ else if ( (sar_type == L2CAP_FCR_END_SDU) && ((p_fcrb->p_rx_sdu->len + p_buf->len) != p_fcrb->rx_sdu_len) )
+ {
+ L2CAP_TRACE_WARNING3 ("SAR - SDU end rcvd but SDU incomplete: %u %u %u",
+ p_fcrb->p_rx_sdu->len, p_buf->len, p_fcrb->rx_sdu_len);
+ packet_ok = FALSE;
+ }
+ else
+ {
+ memcpy (((UINT8 *) (p_fcrb->p_rx_sdu + 1)) + p_fcrb->p_rx_sdu->offset + p_fcrb->p_rx_sdu->len, p, p_buf->len);
+
+ p_fcrb->p_rx_sdu->len += p_buf->len;
+
+ GKI_freebuf (p_buf);
+ p_buf = NULL;
+
+ if (sar_type == L2CAP_FCR_END_SDU)
+ {
+ p_buf = p_fcrb->p_rx_sdu;
+ p_fcrb->p_rx_sdu = NULL;
+ }
+ }
+ }
+ }
+
+ if (packet_ok == FALSE)
+ {
+ GKI_freebuf (p_buf);
+ }
+ else if (p_buf != NULL)
+ {
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+ if (p_ccb->local_cid < L2CAP_BASE_APPL_CID)
+ (*l2cb.fixed_reg[p_ccb->local_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb)(p_ccb->p_lcb->remote_bd_addr, p_buf);
+ else
+#endif
+ l2c_csm_execute (p_ccb, L2CEVT_L2CAP_DATA, p_buf);
+ }
+
+ return (packet_ok);
+}
+
+
+/*******************************************************************************
+**
+** Function retransmit_i_frames
+**
+** Description This function retransmits i-frames awaiting acks.
+**
+** Returns BOOLEAN - TRUE if retransmitted
+**
+*******************************************************************************/
+static BOOLEAN retransmit_i_frames (tL2C_CCB *p_ccb, UINT8 tx_seq)
+{
+ BT_HDR *p_buf, *p_buf2;
+ UINT8 *p;
+ UINT8 buf_seq;
+ UINT16 ctrl_word;
+
+ if ( (p_ccb->fcrb.waiting_for_ack_q.p_first)
+ && (p_ccb->peer_cfg.fcr.max_transmit != 0)
+ && (p_ccb->fcrb.num_tries >= p_ccb->peer_cfg.fcr.max_transmit) )
+ {
+ L2CAP_TRACE_EVENT5 ("Max Tries Exceeded: (last_acq: %d CID: 0x%04x num_tries: %u (max: %u) ack_q_count: %u",
+ p_ccb->fcrb.last_rx_ack, p_ccb->local_cid, p_ccb->fcrb.num_tries, p_ccb->peer_cfg.fcr.max_transmit,
+ p_ccb->fcrb.waiting_for_ack_q.count);
+
+ l2cu_disconnect_chnl (p_ccb);
+ return (FALSE);
+ }
+
+ /* tx_seq indicates whether to retransmit a specific sequence or all (if == L2C_FCR_RETX_ALL_PKTS) */
+ if (tx_seq != L2C_FCR_RETX_ALL_PKTS)
+ {
+ /* If sending only one, the sequence number tells us which one. Look for it.
+ */
+ for (p_buf = (BT_HDR *)p_ccb->fcrb.waiting_for_ack_q.p_first; p_buf; p_buf = (BT_HDR *)GKI_getnext (p_buf))
+ {
+ /* Get the old control word */
+ p = ((UINT8 *) (p_buf+1)) + p_buf->offset + L2CAP_PKT_OVERHEAD;
+
+ STREAM_TO_UINT16 (ctrl_word, p);
+
+ buf_seq = (ctrl_word & L2CAP_FCR_TX_SEQ_BITS) >> L2CAP_FCR_TX_SEQ_BITS_SHIFT;
+
+ L2CAP_TRACE_DEBUG2 ("retransmit_i_frames() cur seq: %u looking for: %u", buf_seq, tx_seq);
+
+ if (tx_seq == buf_seq)
+ break;
+ }
+
+ if (!p_buf)
+ {
+ L2CAP_TRACE_ERROR2 ("retransmit_i_frames() UNKNOWN seq: %u q_count: %u", tx_seq, p_ccb->fcrb.waiting_for_ack_q.count);
+ return (TRUE);
+ }
+ }
+ else
+ {
+ /* Retransmitting everything. Flush buffers we already put in the link xmit queue.
+ */
+ p_buf = (BT_HDR *)p_ccb->p_lcb->link_xmit_data_q.p_first;
+
+ while (p_buf != NULL)
+ {
+ /* Do not flush other CIDs or partial segments */
+ if ( (p_buf->layer_specific == 0) && (p_buf->event == p_ccb->local_cid) )
+ {
+ p_buf2 = p_buf;
+ p_buf = (BT_HDR *)GKI_getnext (p_buf);
+
+ GKI_remove_from_queue (&p_ccb->p_lcb->link_xmit_data_q, p_buf2);
+ GKI_freebuf (p_buf2);
+ }
+ else
+ p_buf = (BT_HDR *)GKI_getnext (p_buf);
+ }
+
+ /* Also flush our retransmission queue */
+ while (p_ccb->fcrb.retrans_q.p_first)
+ GKI_freebuf (GKI_dequeue (&p_ccb->fcrb.retrans_q));
+
+ p_buf = (BT_HDR *)p_ccb->fcrb.waiting_for_ack_q.p_first;
+ }
+
+ while (p_buf != NULL)
+ {
+ p_buf2 = l2c_fcr_clone_buf (p_buf, p_buf->offset, p_buf->len, p_ccb->ertm_info.fcr_tx_pool_id);
+
+ if (p_buf2)
+ {
+ p_buf2->layer_specific = p_buf->layer_specific;
+
+ GKI_enqueue (&p_ccb->fcrb.retrans_q, p_buf2);
+ }
+
+ if ( (tx_seq != L2C_FCR_RETX_ALL_PKTS) || (p_buf2 == NULL) )
+ break;
+ else
+ p_buf = (BT_HDR *)GKI_getnext (p_buf);
+ }
+
+ l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, NULL);
+
+ if (p_ccb->fcrb.waiting_for_ack_q.count)
+ {
+ p_ccb->fcrb.num_tries++;
+ l2c_fcr_start_timer (p_ccb);
+ }
+
+ return (TRUE);
+}
+
+
+/*******************************************************************************
+**
+** Function l2c_fcr_get_next_xmit_sdu_seg
+**
+** Description Get the next SDU segment to transmit.
+**
+** Returns pointer to buffer with segment or NULL
+**
+*******************************************************************************/
+BT_HDR *l2c_fcr_get_next_xmit_sdu_seg (tL2C_CCB *p_ccb, UINT16 max_packet_length)
+{
+ BOOLEAN first_seg = FALSE, /* The segment is the first part of data */
+ mid_seg = FALSE, /* The segment is the middle part of data */
+ last_seg = FALSE; /* The segment is the last part of data */
+ UINT16 sdu_len;
+ BT_HDR *p_buf, *p_xmit;
+ UINT8 *p;
+ UINT16 max_pdu = p_ccb->tx_mps /* Needed? - L2CAP_MAX_HEADER_FCS*/;
+
+ /* If there is anything in the retransmit queue, that goes first
+ */
+ if (p_ccb->fcrb.retrans_q.p_first)
+ {
+ p_buf = (BT_HDR *)GKI_dequeue (&p_ccb->fcrb.retrans_q);
+
+ /* Update Rx Seq and FCS if we acked some packets while this one was queued */
+ prepare_I_frame (p_ccb, p_buf, TRUE);
+
+ p_buf->event = p_ccb->local_cid;
+
+#if L2CAP_CORRUPT_ERTM_PKTS == TRUE
+ /* Use sdu_len to hold the control word */
+ p = ((UINT8 *) (p_buf+1)) + p_buf->offset + L2CAP_PKT_OVERHEAD;
+ STREAM_TO_UINT16 (sdu_len, p);
+
+ /* Get out if packet was dropped; just pretend it went out */
+ if (l2c_corrupt_the_fcr_packet (p_ccb, p_buf, FALSE, sdu_len))
+ return (NULL);
+#endif /* L2CAP_CORRUPT_ERTM_PKTS */
+
+#if (L2CAP_ERTM_STATS == TRUE)
+ p_ccb->fcrb.pkts_retransmitted++;
+ p_ccb->fcrb.ertm_pkt_counts[0]++;
+ p_ccb->fcrb.ertm_byte_counts[0] += (p_buf->len - 8);
+#endif
+ return (p_buf);
+ }
+
+ /* For BD/EDR controller, max_packet_length is set to 0 */
+ /* For AMP controller, max_packet_length is set by available blocks */
+ if ( (max_packet_length > L2CAP_MAX_HEADER_FCS)
+ && (max_pdu + L2CAP_MAX_HEADER_FCS > max_packet_length) )
+ {
+ max_pdu = max_packet_length - L2CAP_MAX_HEADER_FCS;
+ }
+
+ p_buf = (BT_HDR *)p_ccb->xmit_hold_q.p_first;
+
+ /* If there is more data than the MPS, it requires segmentation */
+ if (p_buf->len > max_pdu)
+ {
+ /* We are using the "event" field to tell is if we already started segmentation */
+ if (p_buf->event == 0)
+ {
+ first_seg = TRUE;
+ sdu_len = p_buf->len;
+ }
+ else
+ mid_seg = TRUE;
+
+ /* Get a new buffer and copy the data that can be sent in a PDU */
+ p_xmit = l2c_fcr_clone_buf (p_buf, L2CAP_MIN_OFFSET + L2CAP_SDU_LEN_OFFSET,
+ max_pdu, p_ccb->ertm_info.fcr_tx_pool_id);
+
+ if (p_xmit != NULL)
+ {
+ p_buf->event = p_ccb->local_cid;
+ p_xmit->event = p_ccb->local_cid;
+
+ p_buf->len -= max_pdu;
+ p_buf->offset += max_pdu;
+
+ /* copy PBF setting */
+ p_xmit->layer_specific = p_buf->layer_specific;
+ }
+ else /* Should never happen if the application has configured buffers correctly */
+ {
+ L2CAP_TRACE_ERROR1 ("L2CAP - cannot get buffer, for segmentation, pool: %u", p_ccb->ertm_info.fcr_tx_pool_id);
+ return (NULL);
+ }
+ }
+ else /* Use the original buffer if no segmentation, or the last segment */
+ {
+ p_xmit = (BT_HDR *)GKI_dequeue (&p_ccb->xmit_hold_q);
+
+ if (p_xmit->event != 0)
+ last_seg = TRUE;
+
+ p_xmit->event = p_ccb->local_cid;
+ }
+
+ /* Step back to add the L2CAP headers */
+ p_xmit->offset -= (L2CAP_PKT_OVERHEAD + L2CAP_FCR_OVERHEAD);
+ p_xmit->len += L2CAP_PKT_OVERHEAD + L2CAP_FCR_OVERHEAD;
+
+ if (first_seg)
+ {
+ p_xmit->offset -= L2CAP_SDU_LEN_OVERHEAD;
+ p_xmit->len += L2CAP_SDU_LEN_OVERHEAD;
+ }
+
+ /* Set the pointer to the beginning of the data */
+ p = (UINT8 *)(p_xmit + 1) + p_xmit->offset;
+
+ /* Now the L2CAP header */
+
+ /* Note: if FCS has to be included then the length is recalculated later */
+ UINT16_TO_STREAM (p, p_xmit->len - L2CAP_PKT_OVERHEAD);
+
+ UINT16_TO_STREAM (p, p_ccb->remote_cid);
+
+ if (first_seg)
+ {
+ /* Skip control word and add SDU length */
+ p += 2;
+ UINT16_TO_STREAM (p, sdu_len);
+
+ /* We will store the SAR type in layer-specific */
+ /* layer_specific is shared with flushable flag(bits 0-1), don't clear it */
+ p_xmit->layer_specific |= L2CAP_FCR_START_SDU;
+
+ first_seg = FALSE;
+ }
+ else if (mid_seg)
+ p_xmit->layer_specific |= L2CAP_FCR_CONT_SDU;
+ else if (last_seg)
+ p_xmit->layer_specific |= L2CAP_FCR_END_SDU;
+ else
+ p_xmit->layer_specific |= L2CAP_FCR_UNSEG_SDU;
+
+ prepare_I_frame (p_ccb, p_xmit, FALSE);
+
+ if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE)
+ {
+ BT_HDR *p_wack = l2c_fcr_clone_buf (p_xmit, HCI_DATA_PREAMBLE_SIZE, p_xmit->len, p_ccb->ertm_info.fcr_tx_pool_id);
+
+ if (!p_wack)
+ {
+ L2CAP_TRACE_ERROR3 ("L2CAP - no buffer for xmit cloning, CID: 0x%04x Pool: %u Count: %u",
+ p_ccb->local_cid, p_ccb->ertm_info.fcr_tx_pool_id, GKI_poolfreecount(p_ccb->ertm_info.fcr_tx_pool_id));
+
+ /* We will not save the FCS in case we reconfigure and change options */
+ if (p_ccb->bypass_fcs != L2CAP_BYPASS_FCS)
+ p_xmit->len -= L2CAP_FCS_LEN;
+
+ /* Pretend we sent it and it got lost */
+ GKI_enqueue (&p_ccb->fcrb.waiting_for_ack_q, p_xmit);
+ return (NULL);
+ }
+ else
+ {
+#if (L2CAP_ERTM_STATS == TRUE)
+ /* set timestamp at the end of tx I-frame to get acking delay */
+ p = ((UINT8 *) (p_wack+1)) + p_wack->offset + p_wack->len;
+ UINT32_TO_STREAM (p, GKI_get_os_tick_count());
+#endif
+ /* We will not save the FCS in case we reconfigure and change options */
+ if (p_ccb->bypass_fcs != L2CAP_BYPASS_FCS)
+ p_wack->len -= L2CAP_FCS_LEN;
+
+ p_wack->layer_specific = p_xmit->layer_specific;
+ GKI_enqueue (&p_ccb->fcrb.waiting_for_ack_q, p_wack);
+ }
+
+#if L2CAP_CORRUPT_ERTM_PKTS == TRUE
+ {
+ UINT16 ctrl_word;
+ p = ((UINT8 *) (p_xmit+1)) + p_xmit->offset + L2CAP_PKT_OVERHEAD;
+ STREAM_TO_UINT16 (ctrl_word, p);
+
+ /* Get out if packet was dropped; pretend it was sent */
+ if (l2c_corrupt_the_fcr_packet (p_ccb, p_xmit, FALSE, ctrl_word))
+ return (NULL);
+ }
+#endif
+#if (L2CAP_ERTM_STATS == TRUE)
+ p_ccb->fcrb.ertm_pkt_counts[0]++;
+ p_ccb->fcrb.ertm_byte_counts[0] += (p_xmit->len - 8);
+#endif
+
+ }
+
+ return (p_xmit);
+}
+
+
+/*******************************************************************************
+** Configuration negotiation functions
+**
+** The following functions are used in negotiating channel modes during
+** configuration
+********************************************************************************/
+
+/*******************************************************************************
+**
+** Function l2c_fcr_chk_chan_modes
+**
+** Description Validates and adjusts if necessary, the FCR options
+** based on remote EXT features.
+**
+** Note: This assumes peer EXT Features have been received.
+** Basic mode is used if FCR Options have not been received
+**
+** Returns UINT8 - nonzero if can continue, '0' if no compatible channels
+**
+*******************************************************************************/
+UINT8 l2c_fcr_chk_chan_modes (tL2C_CCB *p_ccb)
+{
+ /* Remove nonbasic options that the peer does not support */
+ if (!(p_ccb->p_lcb->peer_ext_fea & L2CAP_EXTFEA_ENH_RETRANS))
+ p_ccb->ertm_info.allowed_modes &= ~L2CAP_FCR_CHAN_OPT_ERTM;
+
+ if (!(p_ccb->p_lcb->peer_ext_fea & L2CAP_EXTFEA_STREAM_MODE))
+ p_ccb->ertm_info.allowed_modes &= ~L2CAP_FCR_CHAN_OPT_STREAM;
+
+ /* At least one type needs to be set (Basic, ERTM, STM) to continue */
+ if (!p_ccb->ertm_info.allowed_modes)
+ {
+ L2CAP_TRACE_WARNING0 ("L2CAP - Peer does not support our desired channel types");
+ }
+
+ return (p_ccb->ertm_info.allowed_modes);
+}
+
+/*******************************************************************************
+**
+** Function l2c_fcr_adj_our_req_options
+**
+** Description Validates and sets up the FCR options passed in from
+** L2CA_ConfigReq based on remote device's features.
+**
+** Returns TRUE if no errors, Otherwise FALSE
+**
+*******************************************************************************/
+BOOLEAN l2c_fcr_adj_our_req_options (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg)
+{
+ tL2CAP_FCR_OPTS *p_fcr = &p_cfg->fcr;
+
+ if (p_fcr->mode != p_ccb->ertm_info.preferred_mode)
+ {
+ L2CAP_TRACE_WARNING2 ("l2c_fcr_adj_our_req_options - preferred_mode (%d), does not match mode (%d)",
+ p_ccb->ertm_info.preferred_mode, p_fcr->mode);
+
+ /* The preferred mode is passed in through tL2CAP_ERTM_INFO, so override this one */
+ p_fcr->mode = p_ccb->ertm_info.preferred_mode;
+ }
+
+ /* If upper layer did not request eRTM mode, BASIC must be used */
+ if (p_ccb->ertm_info.allowed_modes == L2CAP_FCR_CHAN_OPT_BASIC)
+ {
+ if (p_cfg->fcr_present && p_fcr->mode != L2CAP_FCR_BASIC_MODE)
+ {
+ L2CAP_TRACE_WARNING1 ("l2c_fcr_adj_our_req_options (mode %d): ERROR: No FCR options set using BASIC mode", p_fcr->mode);
+ }
+ p_fcr->mode = L2CAP_FCR_BASIC_MODE;
+ }
+
+ /* Process the FCR options if initial channel bring-up (not a reconfig request)
+ ** Determine initial channel mode to try based on our options and remote's features
+ */
+ if (p_cfg->fcr_present && !(p_ccb->config_done & RECONFIG_FLAG))
+ {
+ /* We need to have at least one mode type common with the peer */
+ if (!l2c_fcr_chk_chan_modes(p_ccb))
+ {
+ /* Two channels have incompatible supported types */
+ l2cu_disconnect_chnl (p_ccb);
+ return (FALSE);
+ }
+
+ /* Basic is the only common channel mode between the two devices */
+ else if (p_ccb->ertm_info.allowed_modes == L2CAP_FCR_CHAN_OPT_BASIC)
+ {
+ /* We only want to try Basic, so bypass sending the FCR options entirely */
+ p_cfg->fcr_present = FALSE;
+ p_cfg->fcs_present = FALSE; /* Illegal to use FCS option in basic mode */
+ p_cfg->ext_flow_spec_present = FALSE; /* Illegal to use extended flow spec in basic mode */
+ }
+
+ /* We have at least one non-basic mode available
+ * Override mode from available mode options based on preference, if needed
+ */
+ else
+ {
+ /* If peer does not support STREAMING, try ERTM */
+ if (p_fcr->mode == L2CAP_FCR_STREAM_MODE && !(p_ccb->ertm_info.allowed_modes & L2CAP_FCR_CHAN_OPT_STREAM))
+ {
+ L2CAP_TRACE_DEBUG0 ("L2C CFG: mode is STREAM, but peer does not support; Try ERTM");
+ p_fcr->mode = L2CAP_FCR_ERTM_MODE;
+ }
+
+ /* If peer does not support ERTM, try BASIC (will support this if made it here in the code) */
+ if (p_fcr->mode == L2CAP_FCR_ERTM_MODE && !(p_ccb->ertm_info.allowed_modes & L2CAP_FCR_CHAN_OPT_ERTM))
+ {
+ L2CAP_TRACE_DEBUG0 ("L2C CFG: mode is ERTM, but peer does not support; Try BASIC");
+ p_fcr->mode = L2CAP_FCR_BASIC_MODE;
+ }
+ }
+
+ if (p_fcr->mode != L2CAP_FCR_BASIC_MODE)
+ {
+ /* MTU must be smaller than buffer size */
+ if ( (p_cfg->mtu_present) && (p_cfg->mtu > p_ccb->max_rx_mtu) )
+ {
+ L2CAP_TRACE_WARNING2 ("L2CAP - MTU: %u larger than buf size: %u", p_cfg->mtu, p_ccb->max_rx_mtu);
+ return (FALSE);
+ }
+
+ /* application want to use the default MPS */
+ if (p_fcr->mps == L2CAP_DEFAULT_ERM_MPS)
+ {
+ p_fcr->mps = L2CAP_MPS_OVER_BR_EDR;
+ }
+ /* MPS must be less than MTU */
+ else if (p_fcr->mps > p_ccb->max_rx_mtu)
+ {
+ L2CAP_TRACE_WARNING2 ("L2CAP - MPS %u invalid MTU: %u", p_fcr->mps, p_ccb->max_rx_mtu);
+ return (FALSE);
+ }
+
+ /* We always initially read into the HCI buffer pool, so make sure it fits */
+ if (p_fcr->mps > (L2CAP_MTU_SIZE - L2CAP_MAX_HEADER_FCS))
+ p_fcr->mps = L2CAP_MTU_SIZE - L2CAP_MAX_HEADER_FCS;
+ }
+ else
+ {
+ p_cfg->fcs_present = FALSE; /* Illegal to use FCS option in basic mode */
+ p_cfg->ext_flow_spec_present = FALSE; /* Illegal to use extended flow spec in basic mode */
+ }
+
+ p_ccb->our_cfg.fcr = *p_fcr;
+ }
+ else /* Not sure how to send a reconfiguration(??) should fcr be included? */
+ {
+ p_ccb->our_cfg.fcr_present = FALSE;
+ }
+
+ return (TRUE);
+}
+
+
+/*******************************************************************************
+**
+** Function l2c_fcr_adj_monitor_retran_timeout
+**
+** Description Overrides monitor/retrans timer value based on controller
+**
+** Returns None
+**
+*******************************************************************************/
+void l2c_fcr_adj_monitor_retran_timeout (tL2C_CCB *p_ccb)
+{
+ /* adjust our monitor/retran timeout */
+ if (p_ccb->out_cfg_fcr_present)
+ {
+ /*
+ ** if we requestd ERTM or accepted ERTM
+ ** We may accept ERTM even if we didn't request ERTM, in case of requesting STREAM
+ */
+ if ((p_ccb->our_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE)
+ ||(p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE))
+ {
+ /* upper layer setting is ignored */
+ p_ccb->our_cfg.fcr.mon_tout = L2CAP_MIN_MONITOR_TOUT;
+ p_ccb->our_cfg.fcr.rtrans_tout = L2CAP_MIN_RETRANS_TOUT;
+ }
+ else
+ {
+ p_ccb->our_cfg.fcr.mon_tout = 0;
+ p_ccb->our_cfg.fcr.rtrans_tout = 0;
+ }
+
+ L2CAP_TRACE_DEBUG2 ("l2c_fcr_adj_monitor_retran_timeout: mon_tout:%d, rtrans_tout:%d",
+ p_ccb->our_cfg.fcr.mon_tout, p_ccb->our_cfg.fcr.rtrans_tout);
+ }
+}
+/*******************************************************************************
+**
+** Function l2c_fcr_adj_our_rsp_options
+**
+** Description Overrides any neccesary FCR options passed in from
+** L2CA_ConfigRsp based on our FCR options.
+** Only makes adjustments if channel is in ERTM mode.
+**
+** Returns None
+**
+*******************************************************************************/
+void l2c_fcr_adj_our_rsp_options (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg)
+{
+ /* adjust our monitor/retran timeout */
+ l2c_fcr_adj_monitor_retran_timeout(p_ccb);
+
+ p_cfg->fcr_present = p_ccb->out_cfg_fcr_present;
+
+ if (p_cfg->fcr_present)
+ {
+// btla-specific ++
+ /* Temporary - until a better algorithm is implemented */
+ /* If peer's tx_wnd_sz requires too many buffers for us to support, then adjust it. For now, respond with our own tx_wnd_sz. */
+ /* Note: peer is not guaranteed to obey our adjustment */
+ if (p_ccb->peer_cfg.fcr.tx_win_sz > p_ccb->our_cfg.fcr.tx_win_sz)
+ {
+ L2CAP_TRACE_DEBUG3 ("%s: adjusting requested tx_win_sz from %i to %i", __FUNCTION__, p_ccb->peer_cfg.fcr.tx_win_sz, p_ccb->our_cfg.fcr.tx_win_sz);
+ p_ccb->peer_cfg.fcr.tx_win_sz = p_ccb->our_cfg.fcr.tx_win_sz;
+ }
+// btla-specific --
+
+ p_cfg->fcr.mode = p_ccb->peer_cfg.fcr.mode;
+ p_cfg->fcr.tx_win_sz = p_ccb->peer_cfg.fcr.tx_win_sz;
+ p_cfg->fcr.max_transmit = p_ccb->peer_cfg.fcr.max_transmit;
+ p_cfg->fcr.mps = p_ccb->peer_cfg.fcr.mps;
+ p_cfg->fcr.rtrans_tout = p_ccb->our_cfg.fcr.rtrans_tout;
+ p_cfg->fcr.mon_tout = p_ccb->our_cfg.fcr.mon_tout;
+ }
+}
+
+/*******************************************************************************
+**
+** Function l2c_fcr_renegotiate_chan
+**
+** Description Called upon unsuccessful peer response to config request.
+** If the error is because of the channel mode, it will try
+** to resend using another supported optional channel.
+**
+** Returns TRUE if resent configuration, False if channel matches or
+** cannot match.
+**
+*******************************************************************************/
+BOOLEAN l2c_fcr_renegotiate_chan(tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg)
+{
+ UINT8 peer_mode = p_ccb->our_cfg.fcr.mode;
+ BOOLEAN can_renegotiate;
+
+ /* Skip if this is a reconfiguration from OPEN STATE or if FCR is not returned */
+ if (!p_cfg->fcr_present || (p_ccb->config_done & RECONFIG_FLAG))
+ return (FALSE);
+
+ /* Only retry if there are more channel options to try */
+ if (p_cfg->result == L2CAP_CFG_UNACCEPTABLE_PARAMS)
+ {
+ peer_mode = (p_cfg->fcr_present) ? p_cfg->fcr.mode : L2CAP_FCR_BASIC_MODE;
+
+ if (p_ccb->our_cfg.fcr.mode != peer_mode)
+ {
+
+ if ((--p_ccb->fcr_cfg_tries) == 0)
+ {
+ p_cfg->result = L2CAP_CFG_FAILED_NO_REASON;
+ L2CAP_TRACE_WARNING0 ("l2c_fcr_renegotiate_chan (Max retries exceeded)");
+ }
+
+ can_renegotiate = FALSE;
+
+ /* Try another supported mode if available based on our last attempted channel */
+ switch (p_ccb->our_cfg.fcr.mode)
+ {
+ /* Our Streaming mode request was unnacceptable; try ERTM or Basic */
+ case L2CAP_FCR_STREAM_MODE:
+ /* Peer wants ERTM and we support it */
+ if ( (peer_mode == L2CAP_FCR_ERTM_MODE) && (p_ccb->ertm_info.allowed_modes & L2CAP_FCR_CHAN_OPT_ERTM) )
+ {
+ L2CAP_TRACE_DEBUG0 ("l2c_fcr_renegotiate_chan(Trying ERTM)");
+ p_ccb->our_cfg.fcr.mode = L2CAP_FCR_ERTM_MODE;
+ can_renegotiate = TRUE;
+ }
+ else /* Falls through */
+
+ case L2CAP_FCR_ERTM_MODE:
+ {
+ /* We can try basic for any other peer mode if we support it */
+ if (p_ccb->ertm_info.allowed_modes & L2CAP_FCR_CHAN_OPT_BASIC)
+ {
+ L2CAP_TRACE_DEBUG0 ("l2c_fcr_renegotiate_chan(Trying Basic)");
+ can_renegotiate = TRUE;
+ p_ccb->our_cfg.fcr.mode = L2CAP_FCR_BASIC_MODE;
+ }
+ }
+ break;
+
+ default:
+ /* All other scenarios cannot be renegotiated */
+ break;
+ }
+
+ if (can_renegotiate)
+ {
+ p_ccb->our_cfg.fcr_present = TRUE;
+
+ if (p_ccb->our_cfg.fcr.mode == L2CAP_FCR_BASIC_MODE)
+ {
+ p_ccb->our_cfg.fcs_present = FALSE;
+ p_ccb->our_cfg.ext_flow_spec_present = FALSE;
+
+ /* Basic Mode uses ACL Data Pool, make sure the MTU fits */
+ if ( (p_cfg->mtu_present) && (p_cfg->mtu > L2CAP_MTU_SIZE) )
+ {
+ L2CAP_TRACE_WARNING1 ("L2CAP - adjust MTU: %u too large", p_cfg->mtu);
+ p_cfg->mtu = L2CAP_MTU_SIZE;
+ }
+ }
+
+ l2cu_process_our_cfg_req (p_ccb, &p_ccb->our_cfg);
+ l2cu_send_peer_config_req (p_ccb, &p_ccb->our_cfg);
+ btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CFG_TIMEOUT);
+ return (TRUE);
+ }
+ }
+ }
+
+ /* Disconnect if the channels do not match */
+ if (p_ccb->our_cfg.fcr.mode != peer_mode)
+ {
+ L2CAP_TRACE_WARNING2 ("L2C CFG: Channels incompatible (local %d, peer %d)",
+ p_ccb->our_cfg.fcr.mode, peer_mode);
+ l2cu_disconnect_chnl (p_ccb);
+ }
+
+ return (FALSE);
+}
+
+
+/*******************************************************************************
+**
+** Function l2c_fcr_process_peer_cfg_req
+**
+** Description This function is called to process the FCR options passed
+** in the peer's configuration request.
+**
+** Returns UINT8 - L2CAP_PEER_CFG_OK, L2CAP_PEER_CFG_UNACCEPTABLE,
+** or L2CAP_PEER_CFG_DISCONNECT.
+**
+*******************************************************************************/
+UINT8 l2c_fcr_process_peer_cfg_req(tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg)
+{
+ UINT16 max_retrans_size;
+ UINT8 fcr_ok = L2CAP_PEER_CFG_OK;
+
+ p_ccb->p_lcb->w4_info_rsp = FALSE; /* Handles T61x SonyEricsson Bug in Info Request */
+
+ L2CAP_TRACE_EVENT5 ("l2c_fcr_process_peer_cfg_req() CFG fcr_present:%d fcr.mode:%d CCB FCR mode:%d preferred: %u allowed:%u",
+ p_cfg->fcr_present, p_cfg->fcr.mode, p_ccb->our_cfg.fcr.mode, p_ccb->ertm_info.preferred_mode,
+ p_ccb->ertm_info.allowed_modes);
+
+ /* If Peer wants basic, we are done (accept it or disconnect) */
+ if (p_cfg->fcr.mode == L2CAP_FCR_BASIC_MODE)
+ {
+ /* If we do not allow basic, disconnect */
+ if ( !(p_ccb->ertm_info.allowed_modes & L2CAP_FCR_CHAN_OPT_BASIC) )
+ fcr_ok = L2CAP_PEER_CFG_DISCONNECT;
+ }
+
+ /* Need to negotiate if our modes are not the same */
+ else if (p_cfg->fcr.mode != p_ccb->ertm_info.preferred_mode)
+ {
+ /* If peer wants a mode that we don't support then retry our mode (ex. rtx/flc), OR
+ ** If we want ERTM and they wanted streaming retry our mode.
+ ** Note: If we have already determined they support our mode previously
+ ** from their EXF mask.
+ */
+ if ( (((1 << p_cfg->fcr.mode) & L2CAP_FCR_CHAN_OPT_ALL_MASK) == 0)
+ || (p_ccb->ertm_info.preferred_mode == L2CAP_FCR_ERTM_MODE) )
+ {
+ p_cfg->fcr.mode = p_ccb->our_cfg.fcr.mode;
+ p_cfg->fcr.tx_win_sz = p_ccb->our_cfg.fcr.tx_win_sz;
+ p_cfg->fcr.max_transmit = p_ccb->our_cfg.fcr.max_transmit;
+ fcr_ok = L2CAP_PEER_CFG_UNACCEPTABLE;
+ }
+
+ /* If we wanted basic, then try to renegotiate it */
+ else if (p_ccb->ertm_info.preferred_mode == L2CAP_FCR_BASIC_MODE)
+ {
+ p_cfg->fcr.mode = L2CAP_FCR_BASIC_MODE;
+ p_cfg->fcr.max_transmit = p_cfg->fcr.tx_win_sz = 0;
+ p_cfg->fcr.rtrans_tout = p_cfg->fcr.mon_tout = p_cfg->fcr.mps = 0;
+ p_ccb->our_cfg.fcr.rtrans_tout = p_ccb->our_cfg.fcr.mon_tout = p_ccb->our_cfg.fcr.mps = 0;
+ fcr_ok = L2CAP_PEER_CFG_UNACCEPTABLE;
+ }
+
+ /* Only other valid case is if they want ERTM and we wanted STM which should be
+ accepted if we support it; otherwise the channel should be disconnected */
+ else if ( (p_cfg->fcr.mode != L2CAP_FCR_ERTM_MODE)
+ || !(p_ccb->ertm_info.allowed_modes & L2CAP_FCR_CHAN_OPT_ERTM) )
+ {
+ fcr_ok = L2CAP_PEER_CFG_DISCONNECT;
+ }
+ }
+
+ /* Configuration for FCR channels so make any adjustments and fwd to upper layer */
+ if (fcr_ok == L2CAP_PEER_CFG_OK)
+ {
+ /* by default don't need to send params in the response */
+ p_ccb->out_cfg_fcr_present = FALSE;
+
+ /* Make any needed adjustments for the response to the peer */
+ if (p_cfg->fcr_present && p_cfg->fcr.mode != L2CAP_FCR_BASIC_MODE)
+ {
+ /* Peer desires to bypass FCS check, and streaming or ERTM mode */
+ if (p_cfg->fcs_present)
+ {
+ p_ccb->peer_cfg.fcs = p_cfg->fcs;
+ p_ccb->peer_cfg_bits |= L2CAP_CH_CFG_MASK_FCS;
+ if( p_cfg->fcs == L2CAP_CFG_FCS_BYPASS)
+ p_ccb->bypass_fcs |= L2CAP_CFG_FCS_PEER;
+ }
+
+ max_retrans_size = GKI_get_pool_bufsize (p_ccb->ertm_info.fcr_tx_pool_id) - sizeof(BT_HDR)
+ - L2CAP_MIN_OFFSET - L2CAP_SDU_LEN_OFFSET - L2CAP_FCS_LEN;
+
+ /* Ensure the MPS is not bigger than the MTU */
+ if ( (p_cfg->fcr.mps == 0) || (p_cfg->fcr.mps > p_ccb->peer_cfg.mtu) )
+ {
+ p_cfg->fcr.mps = p_ccb->peer_cfg.mtu;
+ p_ccb->out_cfg_fcr_present = TRUE;
+ }
+
+ /* Ensure the MPS is not bigger than our retransmission buffer */
+ if (p_cfg->fcr.mps > max_retrans_size)
+ {
+ L2CAP_TRACE_DEBUG2("CFG: Overriding MPS to %d (orig %d)", max_retrans_size, p_cfg->fcr.mps);
+
+ p_cfg->fcr.mps = max_retrans_size;
+ p_ccb->out_cfg_fcr_present = TRUE;
+ }
+
+ if (p_cfg->fcr.mode == L2CAP_FCR_ERTM_MODE)
+ {
+ /* Always respond with FCR ERTM parameters */
+ p_ccb->out_cfg_fcr_present = TRUE;
+ }
+ }
+
+ /* Everything ok, so save the peer's adjusted fcr options */
+ p_ccb->peer_cfg.fcr = p_cfg->fcr;
+
+ if (p_cfg->fcr_present)
+ p_ccb->peer_cfg_bits |= L2CAP_CH_CFG_MASK_FCR;
+ }
+ else if (fcr_ok == L2CAP_PEER_CFG_UNACCEPTABLE)
+ {
+ /* Allow peer only one retry for mode */
+ if (p_ccb->peer_cfg_already_rejected)
+ fcr_ok = L2CAP_PEER_CFG_DISCONNECT;
+ else
+ p_ccb->peer_cfg_already_rejected = TRUE;
+ }
+
+ return (fcr_ok);
+}
+
+
+#if L2CAP_CORRUPT_ERTM_PKTS == TRUE
+/*******************************************************************************
+** Functions used for testing ERTM mode
+*/
+/* If FALSE, will also corrupt cid, length, control word, etc. */
+#ifndef L2CAP_CORR_FCS_ONLY
+#define L2CAP_CORR_FCS_ONLY TRUE
+#endif
+
+#define L2C_DISP_FRAME_SIZE 16
+/*******************************************************************************
+**
+** Function l2c_corrupt_the_fcr_packet
+**
+** Description This function is used for testing purposes only.
+** It systematically or randomly corrupts packets used with
+** ERTM channels.
+**
+** Returns BOOLEAN TRUE if packet was dropped,
+** FALSE if fcs corrupted or no corruption
+**
+*******************************************************************************/
+static BOOLEAN l2c_corrupt_the_fcr_packet (tL2C_CCB *p_ccb, BT_HDR *p_buf,
+ BOOLEAN is_rx, UINT16 ctrl_word)
+{
+ tL2C_FCR_TEST_CFG *p_cfg;
+ UINT32 tc;
+ UINT8 *p;
+ UINT32 xx;
+ char buf[L2C_DISP_FRAME_SIZE];
+
+ if (!p_ccb || !p_ccb->fcrb.test_cb.cfg.in_use)
+ return FALSE;
+
+ /* Prepare bad FCS */
+ p = ((UINT8 *) (p_buf + 1)) + p_buf->offset;
+ tc = GKI_get_os_tick_count();
+ tc ^= p[p_buf->len - 1];
+ xx = tc % 47;
+
+ p_cfg = &p_ccb->fcrb.test_cb.cfg;
+#if 0
+ L2CAP_TRACE_DEBUG4 ("testcfg: type: %d, freq: %d (NRM-0, RDM-1), is_rx: %d, count: %d",
+ p_cfg->type, p_cfg->freq, p_cfg->is_rx, p_cfg->count);
+#endif
+ /* If not time to corrupt get out */
+ if (p_cfg->freq == L2CAP_FCR_FREQ_RANDOM)
+ {
+ if (xx != 0)
+ return FALSE;
+ }
+ else /* check test criteria before corrupting */
+ {
+ if ( (p_cfg->count == 0)
+ || (p_cfg->is_rx != is_rx)
+ || ((UINT8)(ctrl_word & L2CAP_FCR_S_FRAME_BIT) != p_cfg->type) )
+ {
+ return FALSE;
+ }
+
+ /* Turn off if done */
+ if (--(p_cfg->count) == 0)
+ {
+ p_ccb->fcrb.test_cb.cfg.in_use = FALSE;
+ }
+ }
+
+#if L2CAP_CORR_FCS_ONLY == TRUE
+ /* Corrupt the FCS check */
+ p[p_buf->len - 1] = p[p_buf->len - 2] = 0;
+#else
+ /* If made it this far packet needs to be corrupted */
+ xx = tc % p_buf->len;
+
+ /* Make sure the value was changed */
+ if (p[xx + 1] == 0)
+ p[xx + 1] = 0x5A;
+
+ p[xx] = p[xx] ^ p[xx + 1];
+
+#if 1 /* Enable if not wishing to corrupting frame type */
+ {
+ UINT8 *p_temp = ((UINT8 *) (p_buf + 1)) + p_buf->offset;
+ p_temp += L2CAP_PKT_OVERHEAD;
+ if ((UINT16)((*p_temp) & 0x01) != (ctrl_word & 0x0001))
+ {
+ (*p_temp) |= (UINT8)(ctrl_word & 0x0001);
+ }
+ }
+#endif
+#endif
+
+ if (is_rx)
+ {
+ if (ctrl_word & L2CAP_FCR_S_FRAME_BIT)
+ BCM_STRCPY_S(buf, L2C_DISP_FRAME_SIZE, "Rx S-Frame");
+ else
+ BCM_STRCPY_S(buf, L2C_DISP_FRAME_SIZE, "Rx I-Frame");
+ }
+ else
+ {
+ if (ctrl_word & L2CAP_FCR_S_FRAME_BIT)
+ BCM_STRCPY_S(buf, L2C_DISP_FRAME_SIZE, "Tx S-Frame");
+ else
+ BCM_STRCPY_S(buf, L2C_DISP_FRAME_SIZE, "Tx I-Frame");
+ }
+
+ /* Lastly, just drop packet if FCS is not being used or if Tx */
+ if (!is_rx || p_ccb->bypass_fcs == L2CAP_BYPASS_FCS)
+ {
+ L2CAP_TRACE_ERROR6 ("-=-=-=-=-=-=-=- Dropping %s packet (0x%04x) tc: %u Buf Len: %u xx: %u count: %d",
+ buf, (UINT32)p_buf, tc, p_buf->len, xx, p_cfg->count);
+ GKI_freebuf(p_buf);
+ return TRUE;
+ }
+ else
+ {
+ L2CAP_TRACE_ERROR6 ("-=-=-=-=-=-=-=- Corrupting %s packet (0x%04x) tc: %u Buf Len: %u xx: %u count: %d",
+ buf, (UINT32)p_buf, tc, p_buf->len, xx, p_cfg->count);
+ }
+
+ return FALSE;
+}
+
+
+/*******************************************************************************
+**
+** Function L2CA_SetupErtmTest
+**
+** Description This function is used for testing purposes only.
+** It corrupts or drops one or more packets used with ERTM channels.
+**
+** Parameters
+** cid - channel ID (0 uses RFCOMM PSM's CID)
+**
+** type - type of test to run (L2CAP_FCR_TTYPE_CORR_IFRAMES
+** L2CAP_FCR_TTYPE_CORR_SFRAME
+** L2CAP_FCR_TTYPE_STOP_TEST
+** L2CAP_FCR_TTYPE_GET_CID - returns rfcomm cid only)
+**
+** is_rx - TRUE to corrupt Rx packet, FALSE for Tx packet)
+**
+** freq - L2CAP_FCR_FREQ_RANDOM (turns on random corruptions/drops)
+** L2CAP_FCR_FREQ_NORMAL (turns on test with "count" corruptions/drops)
+**
+** count - number of packets in a row to drop or corrupt
+**
+** Returns CID of channel running test
+**
+*******************************************************************************/
+UINT16 L2CA_SetupErtmTest (UINT16 cid, UINT8 type, BOOLEAN is_rx, UINT8 freq, UINT16 count)
+{
+ tL2C_CCB *p_ccb = NULL;
+ tL2C_CCB *p_temp_ccb;
+ tL2C_FCR_TEST_CB *p_test_cb;
+ UINT16 xx;
+
+ /* If '0' tests run on top of RFCOMM CID if active */
+ if (cid == 0)
+ {
+ p_temp_ccb = l2cb.ccb_pool;
+ for (xx = 0; xx < MAX_L2CAP_CHANNELS; xx++, p_temp_ccb++)
+ {
+ /* Fixed channels don't have p_rcb's */
+ if (p_temp_ccb->in_use && p_temp_ccb->p_rcb && p_temp_ccb->p_rcb->psm == BT_PSM_RFCOMM)
+ {
+ p_ccb = p_temp_ccb;
+ cid = L2CAP_BASE_APPL_CID + xx;
+ break;
+ }
+ }
+ }
+ else
+ p_ccb = l2cu_find_ccb_by_cid (NULL, cid);
+
+ if (!p_ccb || type == L2CAP_FCR_TTYPE_GET_CID)
+ {
+ if (type == L2CAP_FCR_TTYPE_GET_CID)
+ {
+ L2CAP_TRACE_API1 ("L2CA_SetupErtmTest (GET_CID): cid = 0x%04x", cid);
+ }
+ return (cid);
+ }
+
+ p_test_cb = &p_ccb->fcrb.test_cb;
+
+ /* Turn off the current test */
+ if (type == L2CAP_FCR_TTYPE_STOP_TEST)
+ {
+ if (p_test_cb->cfg.in_use)
+ {
+ L2CAP_TRACE_ERROR1 ("L2CA_SetupErtmTest (OFF): cid 0x%04x", cid);
+ }
+ p_test_cb->cfg.in_use = FALSE;
+ p_test_cb->cfg.count = 0;
+ }
+
+ /* Process the new request */
+ else if (!p_test_cb->cfg.in_use)
+ {
+ /* count must be positive unless random is used */
+ if (!count && freq != L2CAP_FCR_FREQ_RANDOM)
+ {
+ L2CAP_TRACE_ERROR1 ("L2CA_SetupErtmTest (FAIL): Count = 0, freq = %d", freq);
+ return (cid);
+ }
+
+ L2CAP_TRACE_ERROR5 ("L2CA_SetupErtmTest (START): cid 0x%04x, type %d, is_rx %d, freq %d, count %d",
+ cid, type, is_rx, freq, count);
+
+ p_test_cb->cfg.in_use = TRUE;
+ p_test_cb->cfg.freq = freq;
+ p_test_cb->cfg.type = type;
+ p_test_cb->cfg.is_rx = is_rx;
+ p_test_cb->cfg.count = count;
+ }
+ else /* Test already in progress so ignore */
+ {
+ L2CAP_TRACE_ERROR5 ("L2CA_SetupErtmTest (ignoring): cid 0x%04x, type %d, is_rx %d, freq %d, count %d",
+ cid, type, is_rx, freq, count);
+ }
+
+ return (cid);
+}
+
+
+/*******************************************************************************
+** The following routines are only used in conjunction with Conformance testing
+********************************************************************************/
+
+/*******************************************************************************
+**
+** Function L2CA_SendPolledSFrame
+**
+** Description This function is used for testing purposes only.
+** It Sends a Polled RR or RNR to the peer
+**
+** Parameters
+** cid - channel ID
+**
+** sup_type - (L2CAP_FCR_SUP_RR or L2CAP_FCR_SUP_RNR)
+**
+** Returns void
+**
+*******************************************************************************/
+void L2CA_SendPolledSFrame (UINT16 cid, UINT16 sup_type)
+{
+ tL2C_CCB *p_ccb = l2cu_find_ccb_by_cid (NULL, cid);
+
+ if (p_ccb && (sup_type == L2CAP_FCR_SUP_RR || sup_type == L2CAP_FCR_SUP_RNR))
+ {
+ l2c_fcr_send_S_frame (p_ccb, sup_type, L2CAP_FCR_P_BIT);
+ }
+ else
+ {
+ L2CAP_TRACE_ERROR2 ("L2CA_SendPolledSFrame(ERROR): sup_type %u, p_ccb 0x%07x",
+ sup_type, (UINT32)p_ccb);
+ }
+}
+
+/*******************************************************************************
+**
+** Function l2c_bypass_sframe_packet
+**
+** Description This function is used for testing purposes only.
+** It returns TRUE if S-Frame should be bypassed.
+**
+** Returns void
+**
+*******************************************************************************/
+static BOOLEAN l2c_bypass_sframe_packet (tL2C_CCB *p_ccb)
+{
+ if (p_ccb && p_ccb->fcrb.test_cb.cfm.in_use)
+ {
+ if (p_ccb->fcrb.test_cb.cfm.skip_sframe_count > 0)
+ {
+ L2CAP_TRACE_ERROR1 ("l2c_bypass_sframe_packet (count %d)",
+ p_ccb->fcrb.test_cb.cfm.skip_sframe_count);
+
+ if (--p_ccb->fcrb.test_cb.cfm.skip_sframe_count == 0)
+ p_ccb->fcrb.test_cb.cfm.in_use = FALSE;
+
+ /* Bypass sending S-Frame */
+ return TRUE;
+ }
+ else
+ p_ccb->fcrb.test_cb.cfm.in_use = FALSE;
+ }
+
+ return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function L2CA_BypassSFrame
+**
+** Description This function is used for testing purposes only.
+** It skips sending 'count' S-Frames.
+**
+** Parameters
+** cid - channel ID
+**
+** count - Number of S-Frames to skip sending
+**
+** Returns void
+**
+*******************************************************************************/
+void L2CA_BypassSFrame (UINT16 cid, UINT8 count)
+{
+ tL2C_CCB *p_ccb = l2cu_find_ccb_by_cid (NULL, cid);
+ tL2C_FCR_CFM_TEST_CB *p_test_cb;
+
+ if (!p_ccb)
+ {
+ L2CAP_TRACE_WARNING1 ("L2CA_BypassSFrame(ERROR): no p_ccb (0x%07x)", (UINT32)p_ccb);
+ return;
+ }
+
+ p_test_cb = &p_ccb->fcrb.test_cb.cfm;
+
+ /* Initiate test if not active */
+ if (!p_test_cb->in_use)
+ {
+ p_test_cb->in_use = TRUE;
+ p_test_cb->skip_sframe_count = count;
+ }
+ else
+ {
+ L2CAP_TRACE_WARNING0 ("L2CA_BypassSFrame(ERROR): already in use (ignoring...)");
+ }
+}
+
+#endif /* L2CAP_CORRUPT_ERTM_PKTS == TRUE */
+
+#if (L2CAP_ERTM_STATS == TRUE)
+/*******************************************************************************
+**
+** Function l2c_fcr_collect_ack_delay
+**
+** Description collect throughput, delay, queue size of waiting ack
+**
+** Parameters
+** tL2C_CCB
+**
+** Returns void
+**
+*******************************************************************************/
+static void l2c_fcr_collect_ack_delay (tL2C_CCB *p_ccb, UINT8 num_bufs_acked)
+{
+ UINT32 index;
+ BT_HDR *p_buf;
+ UINT8 *p;
+ UINT32 timestamp, delay;
+ UINT8 xx;
+ UINT8 str[120];
+
+ index = p_ccb->fcrb.ack_delay_avg_index;
+
+ /* update sum, max and min of waiting for ack queue size */
+ p_ccb->fcrb.ack_q_count_avg[index] += p_ccb->fcrb.waiting_for_ack_q.count;
+
+ if ( p_ccb->fcrb.waiting_for_ack_q.count > p_ccb->fcrb.ack_q_count_max[index] )
+ p_ccb->fcrb.ack_q_count_max[index] = p_ccb->fcrb.waiting_for_ack_q.count;
+
+ if ( p_ccb->fcrb.waiting_for_ack_q.count < p_ccb->fcrb.ack_q_count_min[index] )
+ p_ccb->fcrb.ack_q_count_min[index] = p_ccb->fcrb.waiting_for_ack_q.count;
+
+ /* update sum, max and min of round trip delay of acking */
+ p_buf = (BT_HDR *)(p_ccb->fcrb.waiting_for_ack_q.p_first);
+ for (xx = 0; (xx < num_bufs_acked)&&(p_buf); xx++)
+ {
+ /* adding up length of acked I-frames to get throughput */
+ p_ccb->fcrb.throughput[index] += p_buf->len - 8;
+
+ if ( xx == num_bufs_acked - 1 )
+ {
+ /* get timestamp from tx I-frame that receiver is acking */
+ p = ((UINT8 *) (p_buf+1)) + p_buf->offset + p_buf->len;
+ if (p_ccb->bypass_fcs != L2CAP_BYPASS_FCS)
+ {
+ p += L2CAP_FCS_LEN;
+ }
+
+ STREAM_TO_UINT32 (timestamp, p);
+ delay = GKI_get_os_tick_count() - timestamp;
+
+ p_ccb->fcrb.ack_delay_avg[index] += delay;
+ if ( delay > p_ccb->fcrb.ack_delay_max[index] )
+ p_ccb->fcrb.ack_delay_max[index] = delay;
+ if ( delay < p_ccb->fcrb.ack_delay_min[index] )
+ p_ccb->fcrb.ack_delay_min[index] = delay;
+ }
+
+ p_buf = GKI_getnext(p_buf);
+ }
+
+ p_ccb->fcrb.ack_delay_avg_count++;
+
+ /* calculate average and initialize next avg, min and max */
+ if (p_ccb->fcrb.ack_delay_avg_count > L2CAP_ERTM_STATS_AVG_NUM_SAMPLES)
+ {
+ p_ccb->fcrb.ack_delay_avg_count = 0;
+
+ p_ccb->fcrb.ack_q_count_avg[index] /= L2CAP_ERTM_STATS_AVG_NUM_SAMPLES;
+ p_ccb->fcrb.ack_delay_avg[index] /= L2CAP_ERTM_STATS_AVG_NUM_SAMPLES;
+
+ /* calculate throughput */
+ timestamp = GKI_get_os_tick_count();
+ if (timestamp - p_ccb->fcrb.throughput_start > 0 )
+ p_ccb->fcrb.throughput[index] /= (timestamp - p_ccb->fcrb.throughput_start);
+
+ p_ccb->fcrb.throughput_start = timestamp;
+
+ sprintf(str, "[%02u] throughput: %5u, ack_delay avg:%3u, min:%3u, max:%3u, ack_q_count avg:%3u, min:%3u, max:%3u",
+ index, p_ccb->fcrb.throughput[index],
+ p_ccb->fcrb.ack_delay_avg[index], p_ccb->fcrb.ack_delay_min[index], p_ccb->fcrb.ack_delay_max[index],
+ p_ccb->fcrb.ack_q_count_avg[index], p_ccb->fcrb.ack_q_count_min[index], p_ccb->fcrb.ack_q_count_max[index] );
+
+ BT_TRACE_1(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI , TRACE_TYPE_GENERIC, "%s", str);
+
+ index = (index + 1) % L2CAP_ERTM_STATS_NUM_AVG;
+ p_ccb->fcrb.ack_delay_avg_index = index;
+
+ p_ccb->fcrb.ack_q_count_max[index] = 0;
+ p_ccb->fcrb.ack_q_count_min[index] = 0xFFFFFFFF;
+ p_ccb->fcrb.ack_q_count_avg[index] = 0;
+
+
+ p_ccb->fcrb.ack_delay_max[index] = 0;
+ p_ccb->fcrb.ack_delay_min[index] = 0xFFFFFFFF;
+ p_ccb->fcrb.ack_delay_avg[index] = 0;
+
+ p_ccb->fcrb.throughput[index] = 0;
+ }
+}
+#endif
+
+
+
diff --git a/stack/l2cap/l2c_int.h b/stack/l2cap/l2c_int.h
new file mode 100644
index 0000000..6dd93b0
--- /dev/null
+++ b/stack/l2cap/l2c_int.h
@@ -0,0 +1,757 @@
+/*****************************************************************************
+**
+** Name: l2c_int.h
+**
+** Description: This file contains L2CAP internal definitions
+**
+** Copyright (c) 1999-2012, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+#ifndef L2C_INT_H
+#define L2C_INT_H
+
+#include "l2c_api.h"
+#include "l2cdefs.h"
+#include "gki.h"
+#include "btm_api.h"
+
+#define L2CAP_MIN_MTU 48 /* Minimum acceptable MTU is 48 bytes */
+
+/* Timeouts. Since L2CAP works off a 1-second list, all are in seconds.
+*/
+#define L2CAP_LINK_ROLE_SWITCH_TOUT 10 /* 10 seconds */
+#define L2CAP_LINK_CONNECT_TOUT 60 /* 30 seconds */
+#define L2CAP_LINK_CONNECT_TOUT_EXT 120 /* 120 seconds */
+#define L2CAP_ECHO_RSP_TOUT 30 /* 30 seconds */
+#define L2CAP_LINK_FLOW_CONTROL_TOUT 2 /* 2 seconds */
+#define L2CAP_LINK_DISCONNECT_TOUT 30 /* 30 seconds */
+
+#ifndef L2CAP_CHNL_CONNECT_TOUT /* BSA needs to override for internal project needs */
+#define L2CAP_CHNL_CONNECT_TOUT 60 /* 60 seconds */
+#endif
+
+#define L2CAP_CHNL_CONNECT_TOUT_EXT 120 /* 120 seconds */
+#define L2CAP_CHNL_CFG_TIMEOUT 30 /* 30 seconds */
+#define L2CAP_CHNL_DISCONNECT_TOUT 10 /* 10 seconds */
+#define L2CAP_DELAY_CHECK_SM4 2 /* 2 seconds */
+#define L2CAP_WAIT_INFO_RSP_TOUT 3 /* 3 seconds */
+#define L2CAP_WAIT_UNPARK_TOUT 2 /* 2 seconds */
+#define L2CAP_LINK_INFO_RESP_TOUT 2 /* 2 seconds */
+#define L2CAP_BLE_LINK_CONNECT_TOUT 30 /* 30 seconds */
+
+/* quick timer uses millisecond unit */
+#define L2CAP_DEFAULT_RETRANS_TOUT 2000 /* 2000 milliseconds */
+#define L2CAP_DEFAULT_MONITOR_TOUT 12000 /* 12000 milliseconds */
+#define L2CAP_FCR_ACK_TOUT 200 /* 200 milliseconds */
+
+/* Define the possible L2CAP channel states. The names of
+** the states may seem a bit strange, but they are taken from
+** the Bluetooth specification.
+*/
+typedef enum
+{
+ CST_CLOSED, /* Channel is in clodes state */
+ CST_ORIG_W4_SEC_COMP, /* Originator waits security clearence */
+ CST_TERM_W4_SEC_COMP, /* Acceptor waits security clearence */
+ CST_W4_L2CAP_CONNECT_RSP, /* Waiting for peer conenct response */
+ CST_W4_L2CA_CONNECT_RSP, /* Waiting for upper layer connect rsp */
+ CST_CONFIG, /* Negotiating configuration */
+ CST_OPEN, /* Data transfer state */
+ CST_W4_L2CAP_DISCONNECT_RSP, /* Waiting for peer disconnect rsp */
+ CST_W4_L2CA_DISCONNECT_RSP /* Waiting for upper layer disc rsp */
+} tL2C_CHNL_STATE;
+
+/* Define the possible L2CAP link states
+*/
+typedef enum
+{
+ LST_DISCONNECTED,
+ LST_CONNECT_HOLDING,
+ LST_CONNECTING_WAIT_SWITCH,
+ LST_CONNECTING,
+ LST_CONNECTED,
+ LST_DISCONNECTING
+} tL2C_LINK_STATE;
+
+
+
+/* Define input events to the L2CAP link and channel state machines. The names
+** of the events may seem a bit strange, but they are taken from
+** the Bluetooth specification.
+*/
+#define L2CEVT_LP_CONNECT_CFM 0 /* Lower layer connect confirm */
+#define L2CEVT_LP_CONNECT_CFM_NEG 1 /* Lower layer connect confirm (failed) */
+#define L2CEVT_LP_CONNECT_IND 2 /* Lower layer connect indication */
+#define L2CEVT_LP_DISCONNECT_IND 3 /* Lower layer disconnect indication */
+#define L2CEVT_LP_QOS_CFM 4 /* Lower layer QOS confirmation */
+#define L2CEVT_LP_QOS_CFM_NEG 5 /* Lower layer QOS confirmation (failed)*/
+#define L2CEVT_LP_QOS_VIOLATION_IND 6 /* Lower layer QOS violation indication */
+
+#define L2CEVT_SEC_COMP 7 /* Security cleared successfully */
+#define L2CEVT_SEC_COMP_NEG 8 /* Security procedure failed */
+
+#define L2CEVT_L2CAP_CONNECT_REQ 10 /* Peer connection request */
+#define L2CEVT_L2CAP_CONNECT_RSP 11 /* Peer connection response */
+#define L2CEVT_L2CAP_CONNECT_RSP_PND 12 /* Peer connection response pending */
+#define L2CEVT_L2CAP_CONNECT_RSP_NEG 13 /* Peer connection response (failed) */
+#define L2CEVT_L2CAP_CONFIG_REQ 14 /* Peer configuration request */
+#define L2CEVT_L2CAP_CONFIG_RSP 15 /* Peer configuration response */
+#define L2CEVT_L2CAP_CONFIG_RSP_NEG 16 /* Peer configuration response (failed) */
+#define L2CEVT_L2CAP_DISCONNECT_REQ 17 /* Peer disconnect request */
+#define L2CEVT_L2CAP_DISCONNECT_RSP 18 /* Peer disconnect response */
+#define L2CEVT_L2CAP_INFO_RSP 19 /* Peer information response */
+#define L2CEVT_L2CAP_DATA 20 /* Peer data */
+
+#define L2CEVT_L2CA_CONNECT_REQ 21 /* Upper layer connect request */
+#define L2CEVT_L2CA_CONNECT_RSP 22 /* Upper layer connect response */
+#define L2CEVT_L2CA_CONNECT_RSP_NEG 23 /* Upper layer connect response (failed)*/
+#define L2CEVT_L2CA_CONFIG_REQ 24 /* Upper layer config request */
+#define L2CEVT_L2CA_CONFIG_RSP 25 /* Upper layer config response */
+#define L2CEVT_L2CA_CONFIG_RSP_NEG 26 /* Upper layer config response (failed) */
+#define L2CEVT_L2CA_DISCONNECT_REQ 27 /* Upper layer disconnect request */
+#define L2CEVT_L2CA_DISCONNECT_RSP 28 /* Upper layer disconnect response */
+#define L2CEVT_L2CA_DATA_READ 29 /* Upper layer data read */
+#define L2CEVT_L2CA_DATA_WRITE 30 /* Upper layer data write */
+#define L2CEVT_L2CA_FLUSH_REQ 31 /* Upper layer flush */
+
+#define L2CEVT_TIMEOUT 32 /* Timeout */
+#define L2CEVT_SEC_RE_SEND_CMD 33 /* btm_sec has enough info to proceed */
+
+#define L2CEVT_ACK_TIMEOUT 34 /* RR delay timeout */
+
+
+/* Bitmask to skip over Broadcom feature reserved (ID) to avoid sending two
+ successive ID values, '0' id only or both */
+#define L2CAP_ADJ_BRCM_ID 0x1
+#define L2CAP_ADJ_ZERO_ID 0x2
+#define L2CAP_ADJ_ID 0x3
+
+/* Return values for l2cu_process_peer_cfg_req() */
+#define L2CAP_PEER_CFG_UNACCEPTABLE 0
+#define L2CAP_PEER_CFG_OK 1
+#define L2CAP_PEER_CFG_DISCONNECT 2
+
+/* eL2CAP option constants */
+#define L2CAP_MIN_RETRANS_TOUT 2000 /* Min retransmission timeout if no flush timeout or PBF */
+#define L2CAP_MIN_MONITOR_TOUT 12000 /* Min monitor timeout if no flush timeout or PBF */
+
+#define L2CAP_MAX_FCR_CFG_TRIES 2 /* Config attempts before disconnecting */
+
+/* Only compiled in when in test mode. Production devices must not include
+*/
+#if L2CAP_CORRUPT_ERTM_PKTS == TRUE
+
+/* These are used for conformance and corruption testing only */
+typedef struct
+{
+ BOOLEAN in_use; /* TRUE if test in progress */
+ UINT8 type; /* Type of test to run or turns off random test */
+ UINT8 freq; /* One-shot or random */
+ BOOLEAN is_rx; /* TRUE if incoming packets */
+ UINT16 count; /* How many I-frames to drop in a row; used only with one-shot tests */
+} tL2C_FCR_TEST_CFG;
+
+typedef struct
+{
+ BOOLEAN in_use; /* TRUE if test in progress */
+ UINT8 skip_sframe_count; /* Number of S-Frames to skip sending */
+} tL2C_FCR_CFM_TEST_CB;
+
+typedef struct
+{
+ tL2C_FCR_TEST_CFG cfg; /* Current corruption test configuration */
+ tL2C_FCR_CFM_TEST_CB cfm; /* Conformance test structure */
+} tL2C_FCR_TEST_CB;
+
+#endif /* L2CAP_CORRUPT_ERTM_PKTS == TRUE */
+
+typedef struct
+{
+ UINT8 next_tx_seq; /* Next sequence number to be Tx'ed */
+ UINT8 last_rx_ack; /* Last sequence number ack'ed by the peer */
+ UINT8 next_seq_expected; /* Next peer sequence number expected */
+ UINT8 last_ack_sent; /* Last peer sequence number ack'ed */
+ UINT8 num_tries; /* Number of retries to send a packet */
+ UINT8 max_held_acks; /* Max acks we can hold before sending */
+
+ BOOLEAN remote_busy; /* TRUE if peer has flowed us off */
+ BOOLEAN local_busy; /* TRUE if we have flowed off the peer */
+
+ BOOLEAN rej_sent; /* Reject was sent */
+ BOOLEAN srej_sent; /* Selective Reject was sent */
+ BOOLEAN wait_ack; /* Transmitter is waiting ack (poll sent) */
+ BOOLEAN rej_after_srej; /* Send a REJ when SREJ clears */
+
+ BOOLEAN send_f_rsp; /* We need to send an F-bit response */
+
+ UINT16 rx_sdu_len; /* Length of the SDU being received */
+ BT_HDR *p_rx_sdu; /* Buffer holding the SDU being received */
+ BUFFER_Q waiting_for_ack_q; /* Buffers sent and waiting for peer to ack */
+ BUFFER_Q srej_rcv_hold_q; /* Buffers rcvd but held pending SREJ rsp */
+ BUFFER_Q retrans_q; /* Buffers being retransmitted */
+
+ TIMER_LIST_ENT ack_timer; /* Timer delaying RR */
+ TIMER_LIST_ENT mon_retrans_timer; /* Timer Monitor or Retransmission */
+
+#if (L2CAP_ERTM_STATS == TRUE)
+ UINT32 connect_tick_count; /* Time channel was established */
+ UINT32 ertm_pkt_counts[2]; /* Packets sent and received */
+ UINT32 ertm_byte_counts[2]; /* Bytes sent and received */
+ UINT32 s_frames_sent[4]; /* S-frames sent (RR, REJ, RNR, SREJ) */
+ UINT32 s_frames_rcvd[4]; /* S-frames rcvd (RR, REJ, RNR, SREJ) */
+ UINT32 xmit_window_closed; /* # of times the xmit window was closed */
+ UINT32 controller_idle; /* # of times less than 2 packets in controller */
+ /* when the xmit window was closed */
+ UINT32 pkts_retransmitted; /* # of packets that were retransmitted */
+ UINT32 retrans_touts; /* # of retransmission timouts */
+ UINT32 xmit_ack_touts; /* # of xmit ack timouts */
+
+#define L2CAP_ERTM_STATS_NUM_AVG 10
+#define L2CAP_ERTM_STATS_AVG_NUM_SAMPLES 100
+ UINT32 ack_delay_avg_count;
+ UINT32 ack_delay_avg_index;
+ UINT32 throughput_start;
+ UINT32 throughput[L2CAP_ERTM_STATS_NUM_AVG];
+ UINT32 ack_delay_avg[L2CAP_ERTM_STATS_NUM_AVG];
+ UINT32 ack_delay_min[L2CAP_ERTM_STATS_NUM_AVG];
+ UINT32 ack_delay_max[L2CAP_ERTM_STATS_NUM_AVG];
+ UINT32 ack_q_count_avg[L2CAP_ERTM_STATS_NUM_AVG];
+ UINT32 ack_q_count_min[L2CAP_ERTM_STATS_NUM_AVG];
+ UINT32 ack_q_count_max[L2CAP_ERTM_STATS_NUM_AVG];
+#endif
+
+#if L2CAP_CORRUPT_ERTM_PKTS == TRUE
+ tL2C_FCR_TEST_CB test_cb; /* Used for SVT and UPF testing */
+#endif
+
+} tL2C_FCRB;
+
+
+/* Define a registration control block. Every application (e.g. RFCOMM, SDP,
+** TCS etc) that registers with L2CAP is assigned one of these.
+*/
+#if (L2CAP_UCD_INCLUDED == TRUE)
+#define L2C_UCD_RCB_ID 0x00
+#define L2C_UCD_STATE_UNUSED 0x00
+#define L2C_UCD_STATE_W4_DATA 0x01
+#define L2C_UCD_STATE_W4_RECEPTION 0x02
+#define L2C_UCD_STATE_W4_MTU 0x04
+
+typedef struct
+{
+ UINT8 state;
+ tL2CAP_UCD_CB_INFO cb_info;
+} tL2C_UCD_REG;
+#endif
+
+typedef struct
+{
+ BOOLEAN in_use;
+ UINT16 psm;
+ UINT16 real_psm; /* This may be a dummy RCB for an o/b connection but */
+ /* this is the real PSM that we need to connect to */
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ tL2C_UCD_REG ucd;
+#endif
+
+ tL2CAP_APPL_INFO api;
+} tL2C_RCB;
+
+
+/* Define a channel control block (CCB). There may be many channel control blocks
+** between the same two Bluetooth devices (i.e. on the same link).
+** Each CCB has unique local and remote CIDs. All channel control blocks on
+** the same physical link and are chained together.
+*/
+typedef struct t_l2c_ccb
+{
+ BOOLEAN in_use; /* TRUE when in use, FALSE when not */
+ tL2C_CHNL_STATE chnl_state; /* Channel state */
+
+ struct t_l2c_ccb *p_next_ccb; /* Next CCB in the chain */
+ struct t_l2c_ccb *p_prev_ccb; /* Previous CCB in the chain */
+ struct t_l2c_linkcb *p_lcb; /* Link this CCB is assigned to */
+
+ UINT16 local_cid; /* Local CID */
+ UINT16 remote_cid; /* Remote CID */
+
+ TIMER_LIST_ENT timer_entry; /* CCB Timer List Entry */
+
+ tL2C_RCB *p_rcb; /* Registration CB for this Channel */
+
+#define IB_CFG_DONE 0x01
+#define OB_CFG_DONE 0x02
+#define RECONFIG_FLAG 0x04 /* True after initial configuration */
+#define CFG_DONE_MASK (IB_CFG_DONE | OB_CFG_DONE)
+
+ UINT8 config_done; /* Configuration flag word */
+ UINT8 local_id; /* Transaction ID for local trans */
+ UINT8 remote_id; /* Transaction ID for local */
+
+#define CCB_FLAG_NO_RETRY 0x01 /* no more retry */
+#define CCB_FLAG_SENT_PENDING 0x02 /* already sent pending response */
+ UINT8 flags;
+
+ tL2CAP_CFG_INFO our_cfg; /* Our saved configuration options */
+ tL2CAP_CH_CFG_BITS peer_cfg_bits; /* Store what peer wants to configure */
+ tL2CAP_CFG_INFO peer_cfg; /* Peer's saved configuration options */
+
+ BUFFER_Q xmit_hold_q; /* Transmit data hold queue */
+
+ BOOLEAN cong_sent; /* Set when congested status sent */
+ UINT16 buff_quota; /* Buffer quota before sending congestion */
+
+ tL2CAP_CHNL_PRIORITY ccb_priority; /* Channel priority */
+ tL2CAP_CHNL_DATA_RATE tx_data_rate; /* Channel Tx data rate */
+ tL2CAP_CHNL_DATA_RATE rx_data_rate; /* Channel Rx data rate */
+
+ /* Fields used for eL2CAP */
+ tL2CAP_ERTM_INFO ertm_info;
+ tL2C_FCRB fcrb;
+ UINT16 tx_mps; /* TX MPS adjusted based on current controller */
+ UINT16 max_rx_mtu;
+ UINT8 fcr_cfg_tries; /* Max number of negotiation attempts */
+ BOOLEAN peer_cfg_already_rejected; /* If mode rejected once, set to TRUE */
+ BOOLEAN out_cfg_fcr_present; /* TRUE if cfg response shoulkd include fcr options */
+
+#define L2CAP_CFG_FCS_OUR 0x01 /* Our desired config FCS option */
+#define L2CAP_CFG_FCS_PEER 0x02 /* Peer's desired config FCS option */
+#define L2CAP_BYPASS_FCS (L2CAP_CFG_FCS_OUR | L2CAP_CFG_FCS_PEER)
+ UINT8 bypass_fcs;
+
+#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
+ BOOLEAN is_flushable; /* TRUE if channel is flushable */
+#endif
+
+#if (L2CAP_NUM_FIXED_CHNLS > 0) || (L2CAP_UCD_INCLUDED == TRUE)
+ UINT16 fixed_chnl_idle_tout; /* Idle timeout to use for the fixed channel */
+#endif
+
+} tL2C_CCB;
+
+/***********************************************************************
+** Define a queue of linked CCBs.
+*/
+typedef struct
+{
+ tL2C_CCB *p_first_ccb; /* The first channel in this queue */
+ tL2C_CCB *p_last_ccb; /* The last channel in this queue */
+} tL2C_CCB_Q;
+
+#if (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE)
+
+/* Round-Robin service for the same priority channels */
+#define L2CAP_NUM_CHNL_PRIORITY 3 /* Total number of priority group (high, medium, low)*/
+#define L2CAP_CHNL_PRIORITY_WEIGHT 5 /* weight per priority for burst transmission quota */
+#define L2CAP_GET_PRIORITY_QUOTA(pri) ((L2CAP_NUM_CHNL_PRIORITY - (pri)) * L2CAP_CHNL_PRIORITY_WEIGHT)
+
+/* CCBs within the same LCB are served in round robin with priority */
+/* It will make sure that low priority channel (for example, HF signaling on RFCOMM) */
+/* can be sent to headset even if higher priority channel (for example, AV media channel) */
+/* is congested. */
+
+typedef struct
+{
+ tL2C_CCB *p_serve_ccb; /* current serving ccb within priority group */
+ tL2C_CCB *p_first_ccb; /* first ccb of priority group */
+ UINT8 num_ccb; /* number of channels in priority group */
+ UINT8 quota; /* burst transmission quota */
+} tL2C_RR_SERV;
+
+#endif /* (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE) */
+
+/* Define a link control block. There is one link control block between
+** this device and any other device (i.e. BD ADDR).
+*/
+typedef struct t_l2c_linkcb
+{
+ BOOLEAN in_use; /* TRUE when in use, FALSE when not */
+ tL2C_LINK_STATE link_state;
+
+ TIMER_LIST_ENT timer_entry; /* Timer list entry for timeout evt */
+ UINT16 handle; /* The handle used with LM */
+
+ tL2C_CCB_Q ccb_queue; /* Queue of CCBs on this LCB */
+
+ tL2C_CCB *p_pending_ccb; /* ccb of waiting channel during link disconnect */
+ TIMER_LIST_ENT info_timer_entry; /* Timer entry for info resp timeout evt */
+ BD_ADDR remote_bd_addr; /* The BD address of the remote */
+
+ UINT8 link_role; /* Master or slave */
+ UINT8 id;
+ tL2CA_ECHO_RSP_CB *p_echo_rsp_cb; /* Echo response callback */
+ UINT16 idle_timeout; /* Idle timeout */
+ BOOLEAN is_bonding; /* True - link active only for bonding */
+
+ UINT16 link_flush_tout; /* Flush timeout used */
+
+ UINT16 link_xmit_quota; /* Num outstanding pkts allowed */
+ UINT16 sent_not_acked; /* Num packets sent but not acked */
+
+ BOOLEAN partial_segment_being_sent; /* Set TRUE when a partial segment */
+ /* is being sent. */
+ BOOLEAN w4_info_rsp; /* TRUE when info request is active */
+ UINT8 info_rx_bits; /* set 1 if received info type */
+ UINT32 peer_ext_fea; /* Peer's extended features mask */
+ BUFFER_Q link_xmit_data_q; /* Transmit data buffer queue */
+
+ UINT8 peer_chnl_mask[L2CAP_FIXED_CHNL_ARRAY_SIZE];
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ UINT16 ucd_mtu; /* peer MTU on UCD */
+ BUFFER_Q ucd_out_sec_pending_q; /* Security pending outgoing UCD packet */
+ BUFFER_Q ucd_in_sec_pending_q; /* Security pending incoming UCD packet */
+#endif
+
+#if (L2CAP_HOST_FLOW_CTRL == TRUE)
+ UINT16 link_pkts_unacked; /* Packets received but not acked */
+ UINT16 link_ack_thresh; /* Threshold at which to ack pkts */
+#endif
+
+ BT_HDR *p_hcit_rcv_acl; /* Current HCIT ACL buf being rcvd */
+ UINT16 idle_timeout_sv; /* Save current Idle timeout */
+ UINT8 acl_priority; /* L2C_PRIORITY_NORMAL or L2C_PRIORITY_HIGH */
+ tL2CA_NOCP_CB *p_nocp_cb; /* Num Cmpl pkts callback */
+
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+ tL2C_CCB *p_fixed_ccbs[L2CAP_NUM_FIXED_CHNLS];
+ UINT16 disc_reason;
+#endif
+
+#if (BLE_INCLUDED == TRUE)
+ BOOLEAN is_ble_link;
+ tBLE_ADDR_TYPE ble_addr_type;
+
+#define UPD_ENABLED 0 /* If peer requests update, we will change params */
+#define UPD_DISABLED 1 /* application requested not to update */
+#define UPD_PENDING 2 /* while updates are disabled, peer requested new parameters */
+#define UPD_UPDATED 3 /* peer updated connection parameters */
+ UINT8 upd_disabled;
+
+ UINT16 min_interval; /* parameters as requested by peripheral */
+ UINT16 max_interval;
+ UINT16 latency;
+ UINT16 timeout;
+
+#endif
+
+#if (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE)
+ /* each priority group is limited burst transmission */
+ /* round robin service for the same priority channels */
+ tL2C_RR_SERV rr_serv[L2CAP_NUM_CHNL_PRIORITY];
+ UINT8 rr_pri; /* current serving priority group */
+#endif
+
+} tL2C_LCB;
+
+/* Define the L2CAP control structure
+*/
+typedef struct
+{
+ UINT8 l2cap_trace_level;
+ UINT16 controller_xmit_window; /* Total ACL window for all links */
+
+ UINT16 round_robin_quota; /* Round-robin link quota */
+ UINT16 round_robin_unacked; /* Round-robin unacked */
+ BOOLEAN check_round_robin; /* Do a round robin check */
+
+ BOOLEAN is_cong_cback_context;
+
+ tL2C_LCB lcb_pool[MAX_L2CAP_LINKS]; /* Link Control Block pool */
+ tL2C_CCB ccb_pool[MAX_L2CAP_CHANNELS]; /* Channel Control Block pool */
+ tL2C_RCB rcb_pool[MAX_L2CAP_CLIENTS]; /* Registration info pool */
+
+ tL2C_CCB *p_free_ccb_first; /* Pointer to first free CCB */
+ tL2C_CCB *p_free_ccb_last; /* Pointer to last free CCB */
+
+ UINT8 desire_role; /* desire to be master/slave when accepting a connection */
+ BOOLEAN disallow_switch; /* FALSE, to allow switch at create conn */
+ UINT16 num_lm_acl_bufs; /* # of ACL buffers on controller */
+ UINT16 idle_timeout; /* Idle timeout */
+
+ BUFFER_Q rcv_hold_q; /* Recv pending queue */
+ TIMER_LIST_ENT rcv_hold_tle; /* Timer list entry for rcv hold */
+
+ tL2C_LCB *p_cur_hcit_lcb; /* Current HCI Transport buffer */
+ UINT16 num_links_active; /* Number of links active */
+
+#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
+ UINT16 non_flushable_pbf; /* L2CAP_PKT_START_NON_FLUSHABLE if controller supports */
+ /* Otherwise, L2CAP_PKT_START */
+ BOOLEAN is_flush_active; /* TRUE if an HCI_Enhanced_Flush has been sent */
+#endif
+
+#if L2CAP_CONFORMANCE_TESTING == TRUE
+ UINT32 test_info_resp; /* Conformance testing needs a dynamic response */
+#endif
+
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+ tL2CAP_FIXED_CHNL_REG fixed_reg[L2CAP_NUM_FIXED_CHNLS]; /* Reg info for fixed channels */
+#endif
+
+#if (BLE_INCLUDED == TRUE)
+ BOOLEAN is_ble_connecting;
+ BD_ADDR ble_connecting_bda;
+ UINT16 controller_le_xmit_window; /* Total ACL window for all links */
+ UINT16 num_lm_ble_bufs; /* # of ACL buffers on controller */
+#endif
+
+ tL2CA_ECHO_DATA_CB *p_echo_data_cb; /* Echo data callback */
+
+#if (defined(L2CAP_HIGH_PRI_CHAN_QUOTA_IS_CONFIGURABLE) && (L2CAP_HIGH_PRI_CHAN_QUOTA_IS_CONFIGURABLE == TRUE))
+ UINT16 high_pri_min_xmit_quota; /* Minimum number of ACL credit for high priority link */
+#endif /* (L2CAP_HIGH_PRI_CHAN_QUOTA_IS_CONFIGURABLE == TRUE) */
+
+ UINT16 dyn_psm;
+} tL2C_CB;
+
+
+
+/* Define a structure that contains the information about a connection.
+** This structure is used to pass between functions, and not all the
+** fields will always be filled in.
+*/
+typedef struct
+{
+ BD_ADDR bd_addr; /* Remote BD address */
+ UINT8 status; /* Connection status */
+ UINT16 psm; /* PSM of the connection */
+ UINT16 l2cap_result; /* L2CAP result */
+ UINT16 l2cap_status; /* L2CAP status */
+ UINT16 remote_cid; /* Remote CID */
+} tL2C_CONN_INFO;
+
+
+typedef void (tL2C_FCR_MGMT_EVT_HDLR) (UINT8, tL2C_CCB *);
+
+/* The offset in a buffer that L2CAP will use when building commands.
+*/
+#define L2CAP_SEND_CMD_OFFSET 0
+
+
+/* Number of ACL buffers to use for high priority channel
+*/
+#if (!defined(L2CAP_HIGH_PRI_CHAN_QUOTA_IS_CONFIGURABLE) || (L2CAP_HIGH_PRI_CHAN_QUOTA_IS_CONFIGURABLE == FALSE))
+#define L2CAP_HIGH_PRI_MIN_XMIT_QUOTA_A (L2CAP_HIGH_PRI_MIN_XMIT_QUOTA)
+#else
+#define L2CAP_HIGH_PRI_MIN_XMIT_QUOTA_A (l2cb.high_pri_min_xmit_quota)
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* L2CAP global data
+************************************
+*/
+#if (!defined L2C_DYNAMIC_MEMORY) || (L2C_DYNAMIC_MEMORY == FALSE)
+L2C_API extern tL2C_CB l2cb;
+#else
+L2C_API extern tL2C_CB *l2c_cb_ptr;
+#define l2cb (*l2c_cb_ptr)
+#endif
+
+
+/* Functions provided by l2c_main.c
+************************************
+*/
+extern void l2c_init (void);
+extern void l2c_process_timeout (TIMER_LIST_ENT *p_tle);
+extern UINT8 l2c_data_write (UINT16 cid, BT_HDR *p_data, UINT16 flag);
+extern void l2c_rcv_acl_data (BT_HDR *p_msg);
+extern void l2c_process_held_packets (BOOLEAN timed_out);
+
+/* Functions provided by l2c_utils.c
+************************************
+*/
+extern tL2C_LCB *l2cu_allocate_lcb (BD_ADDR p_bd_addr, BOOLEAN is_bonding);
+extern BOOLEAN l2cu_start_post_bond_timer (UINT16 handle);
+extern void l2cu_release_lcb (tL2C_LCB *p_lcb);
+extern tL2C_LCB *l2cu_find_lcb_by_bd_addr (BD_ADDR p_bd_addr);
+extern tL2C_LCB *l2cu_find_lcb_by_handle (UINT16 handle);
+extern void l2cu_update_lcb_4_bonding (BD_ADDR p_bd_addr, BOOLEAN is_bonding);
+
+extern UINT8 l2cu_get_conn_role (tL2C_LCB *p_this_lcb);
+extern BOOLEAN l2cu_set_acl_priority (BD_ADDR bd_addr, UINT8 priority, BOOLEAN reset_after_rs);
+
+extern void l2cu_enqueue_ccb (tL2C_CCB *p_ccb);
+extern void l2cu_dequeue_ccb (tL2C_CCB *p_ccb);
+extern void l2cu_change_pri_ccb (tL2C_CCB *p_ccb, tL2CAP_CHNL_PRIORITY priority);
+
+extern tL2C_CCB *l2cu_allocate_ccb (tL2C_LCB *p_lcb, UINT16 cid);
+extern void l2cu_release_ccb (tL2C_CCB *p_ccb);
+extern tL2C_CCB *l2cu_find_ccb_by_cid (tL2C_LCB *p_lcb, UINT16 local_cid);
+extern tL2C_CCB *l2cu_find_ccb_by_remote_cid (tL2C_LCB *p_lcb, UINT16 remote_cid);
+extern void l2cu_adj_id (tL2C_LCB *p_lcb, UINT8 adj_mask);
+
+extern void l2cu_send_peer_cmd_reject (tL2C_LCB *p_lcb, UINT16 reason,
+ UINT8 rem_id,UINT16 p1, UINT16 p2);
+extern void l2cu_send_peer_connect_req (tL2C_CCB *p_ccb);
+extern void l2cu_send_peer_connect_rsp (tL2C_CCB *p_ccb, UINT16 result, UINT16 status);
+extern void l2cu_send_peer_config_req (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg);
+extern void l2cu_send_peer_config_rsp (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg);
+extern void l2cu_send_peer_config_rej (tL2C_CCB *p_ccb, UINT8 *p_data, UINT16 data_len, UINT16 rej_len);
+extern void l2cu_send_peer_disc_req (tL2C_CCB *p_ccb);
+extern void l2cu_send_peer_disc_rsp (tL2C_LCB *p_lcb, UINT8 remote_id, UINT16 local_cid, UINT16 remote_cid);
+extern void l2cu_send_peer_echo_req (tL2C_LCB *p_lcb, UINT8 *p_data, UINT16 data_len);
+extern void l2cu_send_peer_echo_rsp (tL2C_LCB *p_lcb, UINT8 id, UINT8 *p_data, UINT16 data_len);
+extern void l2cu_send_peer_info_rsp (tL2C_LCB *p_lcb, UINT8 id, UINT16 info_type);
+extern void l2cu_reject_connection (tL2C_LCB *p_lcb, UINT16 remote_cid, UINT8 rem_id, UINT16 result);
+extern void l2cu_send_peer_info_req (tL2C_LCB *p_lcb, UINT16 info_type);
+extern void l2cu_set_acl_hci_header (BT_HDR *p_buf, tL2C_CCB *p_ccb);
+extern void l2cu_check_channel_congestion (tL2C_CCB *p_ccb);
+extern void l2cu_disconnect_chnl (tL2C_CCB *p_ccb);
+
+#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
+extern void l2cu_set_non_flushable_pbf(BOOLEAN);
+#endif
+
+#if (BLE_INCLUDED == TRUE)
+extern void l2cu_send_peer_ble_par_req (tL2C_LCB *p_lcb, UINT16 min_int, UINT16 max_int, UINT16 latency, UINT16 timeout);
+extern void l2cu_send_peer_ble_par_rsp (tL2C_LCB *p_lcb, UINT16 reason, UINT8 rem_id);
+#endif
+
+extern BOOLEAN l2cu_initialize_fixed_ccb (tL2C_LCB *p_lcb, UINT16 fixed_cid, tL2CAP_FCR_OPTS *p_fcr);
+extern void l2cu_no_dynamic_ccbs (tL2C_LCB *p_lcb);
+extern void l2cu_process_fixed_chnl_resp (tL2C_LCB *p_lcb);
+
+/* Functions provided by l2c_ucd.c
+************************************
+*/
+#if (L2CAP_UCD_INCLUDED == TRUE)
+void l2c_ucd_delete_sec_pending_q(tL2C_LCB *p_lcb);
+void l2c_ucd_enqueue_pending_out_sec_q(tL2C_CCB *p_ccb, void *p_data);
+BOOLEAN l2c_ucd_check_pending_info_req(tL2C_CCB *p_ccb);
+BOOLEAN l2c_ucd_check_pending_out_sec_q(tL2C_CCB *p_ccb);
+void l2c_ucd_send_pending_out_sec_q(tL2C_CCB *p_ccb);
+void l2c_ucd_discard_pending_out_sec_q(tL2C_CCB *p_ccb);
+BOOLEAN l2c_ucd_check_pending_in_sec_q(tL2C_CCB *p_ccb);
+void l2c_ucd_send_pending_in_sec_q(tL2C_CCB *p_ccb);
+void l2c_ucd_discard_pending_in_sec_q(tL2C_CCB *p_ccb);
+BOOLEAN l2c_ucd_check_rx_pkts(tL2C_LCB *p_lcb, BT_HDR *p_msg);
+BOOLEAN l2c_ucd_process_event(tL2C_CCB *p_ccb, UINT16 event, void *p_data);
+#endif
+
+#if (BLE_INCLUDED == TRUE)
+extern void l2cu_send_peer_ble_par_req (tL2C_LCB *p_lcb, UINT16 min_int, UINT16 max_int, UINT16 latency, UINT16 timeout);
+extern void l2cu_send_peer_ble_par_rsp (tL2C_LCB *p_lcb, UINT16 reason, UINT8 rem_id);
+#endif
+
+extern BOOLEAN l2cu_initialize_fixed_ccb (tL2C_LCB *p_lcb, UINT16 fixed_cid, tL2CAP_FCR_OPTS *p_fcr);
+extern void l2cu_no_dynamic_ccbs (tL2C_LCB *p_lcb);
+extern void l2cu_process_fixed_chnl_resp (tL2C_LCB *p_lcb);
+
+
+/* Functions provided for Broadcom Aware
+****************************************
+*/
+extern BOOLEAN l2cu_check_feature_req (tL2C_LCB *p_lcb, UINT8 id, UINT8 *p_data, UINT16 data_len);
+extern void l2cu_check_feature_rsp (tL2C_LCB *p_lcb, UINT8 id, UINT8 *p_data, UINT16 data_len);
+extern void l2cu_send_feature_req (tL2C_CCB *p_ccb);
+
+extern tL2C_RCB *l2cu_allocate_rcb (UINT16 psm);
+extern tL2C_RCB *l2cu_find_rcb_by_psm (UINT16 psm);
+extern void l2cu_release_rcb (tL2C_RCB *p_rcb);
+
+extern UINT8 l2cu_process_peer_cfg_req (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg);
+extern void l2cu_process_peer_cfg_rsp (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg);
+extern void l2cu_process_our_cfg_req (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg);
+extern void l2cu_process_our_cfg_rsp (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg);
+
+extern void l2cu_device_reset (void);
+extern tL2C_LCB *l2cu_find_lcb_by_state (tL2C_LINK_STATE state);
+extern BOOLEAN l2cu_lcb_disconnecting (void);
+
+extern BOOLEAN l2cu_create_conn (tL2C_LCB *p_lcb);
+extern BOOLEAN l2cu_create_conn_after_switch (tL2C_LCB *p_lcb);
+extern BT_HDR *l2cu_get_next_buffer_to_send (tL2C_LCB *p_lcb);
+extern void l2cu_resubmit_pending_sec_req (BD_ADDR p_bda);
+extern void l2cu_initialize_amp_ccb (tL2C_LCB *p_lcb);
+extern void l2cu_adjust_out_mps (tL2C_CCB *p_ccb);
+
+/* Functions provided by l2c_link.c
+************************************
+*/
+extern BOOLEAN l2c_link_hci_conn_req (BD_ADDR bd_addr);
+extern BOOLEAN l2c_link_hci_conn_comp (UINT8 status, UINT16 handle, BD_ADDR p_bda);
+extern BOOLEAN l2c_link_hci_disc_comp (UINT16 handle, UINT8 reason);
+extern BOOLEAN l2c_link_hci_qos_violation (UINT16 handle);
+extern void l2c_link_timeout (tL2C_LCB *p_lcb);
+extern void l2c_info_timeout (tL2C_LCB *p_lcb);
+extern void l2c_link_check_send_pkts (tL2C_LCB *p_lcb, tL2C_CCB *p_ccb, BT_HDR *p_buf);
+extern void l2c_link_adjust_allocation (void);
+extern void l2c_link_process_num_completed_pkts (UINT8 *p);
+extern void l2c_link_process_num_completed_blocks (UINT8 controller_id, UINT8 *p, UINT16 evt_len);
+extern void l2c_link_processs_num_bufs (UINT16 num_lm_acl_bufs);
+extern UINT8 l2c_link_pkts_rcvd (UINT16 *num_pkts, UINT16 *handles);
+extern void l2c_link_role_changed (BD_ADDR bd_addr, UINT8 new_role, UINT8 hci_status);
+extern void l2c_link_sec_comp (BD_ADDR p_bda, void *p_ref_data, UINT8 status);
+extern void l2c_link_segments_xmitted (BT_HDR *p_msg);
+extern void l2c_pin_code_request (BD_ADDR bd_addr);
+extern void l2c_link_adjust_chnl_allocation (void);
+
+#if (BLE_INCLUDED == TRUE)
+extern void l2c_link_processs_ble_num_bufs (UINT16 num_lm_acl_bufs);
+#endif
+
+#if ((BTM_PWR_MGR_INCLUDED == TRUE) && L2CAP_WAKE_PARKED_LINK == TRUE)
+extern BOOLEAN l2c_link_check_power_mode ( tL2C_LCB *p_lcb );
+#define L2C_LINK_CHECK_POWER_MODE(x) l2c_link_check_power_mode ((x))
+#else
+#define L2C_LINK_CHECK_POWER_MODE(x) (FALSE)
+#endif
+
+#if L2CAP_CONFORMANCE_TESTING == TRUE
+/* Used only for conformance testing */
+L2C_API extern void l2cu_set_info_rsp_mask (UINT32 mask);
+#endif
+
+/* Functions provided by l2c_csm.c
+************************************
+*/
+extern void l2c_csm_execute (tL2C_CCB *p_ccb, UINT16 event, void *p_data);
+
+L2C_API extern BT_HDR *l2cap_link_chk_pkt_start(BT_HDR *); /* Called at start of rcv to check L2CAP segmentation */
+L2C_API extern BOOLEAN l2cap_link_chk_pkt_end (void); /* Called at end of rcv to check L2CAP segmentation */
+
+L2C_API extern void l2c_enqueue_peer_data (tL2C_CCB *p_ccb, BT_HDR *p_buf);
+
+
+/* Functions provided by l2c_fcr.c
+************************************
+*/
+extern void l2c_fcr_cleanup (tL2C_CCB *p_ccb);
+extern void l2c_fcr_proc_pdu (tL2C_CCB *p_ccb, BT_HDR *p_buf);
+extern void l2c_fcr_proc_tout (tL2C_CCB *p_ccb);
+extern void l2c_fcr_proc_ack_tout (tL2C_CCB *p_ccb);
+extern void l2c_fcr_send_S_frame (tL2C_CCB *p_ccb, UINT16 function_code, UINT16 pf_bit);
+extern BT_HDR *l2c_fcr_clone_buf (BT_HDR *p_buf, UINT16 new_offset, UINT16 no_of_bytes, UINT8 pool);
+extern BOOLEAN l2c_fcr_is_flow_controlled (tL2C_CCB *p_ccb);
+extern BT_HDR *l2c_fcr_get_next_xmit_sdu_seg (tL2C_CCB *p_ccb, UINT16 max_packet_length);
+extern void l2c_fcr_start_timer (tL2C_CCB *p_ccb);
+
+/* Configuration negotiation */
+extern UINT8 l2c_fcr_chk_chan_modes (tL2C_CCB *p_ccb);
+extern BOOLEAN l2c_fcr_adj_our_req_options (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg);
+extern void l2c_fcr_adj_our_rsp_options (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_peer_cfg);
+extern BOOLEAN l2c_fcr_renegotiate_chan(tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg);
+extern UINT8 l2c_fcr_process_peer_cfg_req(tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg);
+extern void l2c_fcr_adj_monitor_retran_timeout (tL2C_CCB *p_ccb);
+extern void l2c_fcr_stop_timer (tL2C_CCB *p_ccb);
+
+/* Functions provided by l2c_ble.c
+************************************
+*/
+#if (BLE_INCLUDED == TRUE)
+extern BOOLEAN l2cble_create_conn (tL2C_LCB *p_lcb);
+extern void l2cble_process_sig_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len);
+extern void l2cble_conn_comp (UINT16 handle, UINT8 role, BD_ADDR bda, tBLE_ADDR_TYPE type,
+ UINT16 conn_interval, UINT16 conn_latency, UINT16 conn_timeout);
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/stack/l2cap/l2c_link.c b/stack/l2cap/l2c_link.c
new file mode 100644
index 0000000..d0899aa
--- /dev/null
+++ b/stack/l2cap/l2c_link.c
@@ -0,0 +1,1703 @@
+/*****************************************************************************
+**
+** Name: l2c_link.c
+**
+** Description: this file contains the functions relating to link
+** management. A "link" is a connection between this device
+** and another device. Only ACL links are managed.
+**
+**
+** Copyright (c) 1999-2011, Broadcom Corp, All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "gki.h"
+#include "bt_types.h"
+#include "hcimsgs.h"
+#include "l2cdefs.h"
+#include "l2c_int.h"
+#include "l2c_api.h"
+#include "btu.h"
+#include "btm_api.h"
+#include "btm_int.h"
+
+static BOOLEAN l2c_link_send_to_lower (tL2C_LCB *p_lcb, BT_HDR *p_buf);
+
+#define L2C_LINK_SEND_ACL_DATA(x) HCI_ACL_DATA_TO_LOWER((x))
+
+#if (BLE_INCLUDED == TRUE)
+#define L2C_LINK_SEND_BLE_ACL_DATA(x) HCI_BLE_ACL_DATA_TO_LOWER((x))
+#endif
+
+/*******************************************************************************
+**
+** Function l2c_link_hci_conn_req
+**
+** Description This function is called when an HCI Connection Request
+** event is received.
+**
+** Returns TRUE, if accept conn
+**
+*******************************************************************************/
+BOOLEAN l2c_link_hci_conn_req (BD_ADDR bd_addr)
+{
+ tL2C_LCB *p_lcb;
+ tL2C_LCB *p_lcb_cur;
+ int xx;
+ BOOLEAN no_links;
+
+ /* See if we have a link control block for the remote device */
+ p_lcb = l2cu_find_lcb_by_bd_addr (bd_addr);
+
+ /* If we don't have one, create one and accept the connection. */
+ if (!p_lcb)
+ {
+ p_lcb = l2cu_allocate_lcb (bd_addr, FALSE);
+ if (!p_lcb)
+ {
+ btsnd_hcic_reject_conn (bd_addr, HCI_ERR_HOST_REJECT_RESOURCES);
+ L2CAP_TRACE_ERROR0 ("L2CAP failed to allocate LCB");
+ return FALSE;
+ }
+
+ no_links = TRUE;
+
+ /* If we already have connection, accept as a master */
+ for (xx = 0, p_lcb_cur = &l2cb.lcb_pool[0]; xx < MAX_L2CAP_LINKS; xx++, p_lcb_cur++)
+ {
+ if (p_lcb_cur == p_lcb)
+ continue;
+
+ if (p_lcb_cur->in_use)
+ {
+ no_links = FALSE;
+ p_lcb->link_role = HCI_ROLE_MASTER;
+ break;
+ }
+ }
+
+ if (no_links)
+ {
+ if (!btm_dev_support_switch (bd_addr))
+ p_lcb->link_role = HCI_ROLE_SLAVE;
+ else
+ p_lcb->link_role = l2cu_get_conn_role(p_lcb);
+ }
+
+ /* Tell the other side we accept the connection */
+ btsnd_hcic_accept_conn (bd_addr, p_lcb->link_role);
+
+ p_lcb->link_state = LST_CONNECTING;
+
+ /* Start a timer waiting for connect complete */
+ btu_start_timer (&p_lcb->timer_entry, BTU_TTYPE_L2CAP_LINK, L2CAP_LINK_CONNECT_TOUT);
+ return (TRUE);
+ }
+
+ /* We already had a link control block to the guy. Check what state it is in */
+ if ((p_lcb->link_state == LST_CONNECTING) || (p_lcb->link_state == LST_CONNECT_HOLDING))
+ {
+ /* Connection collision. Accept the connection anyways. */
+
+ if (!btm_dev_support_switch (bd_addr))
+ p_lcb->link_role = HCI_ROLE_SLAVE;
+ else
+ p_lcb->link_role = l2cu_get_conn_role(p_lcb);
+
+ btsnd_hcic_accept_conn (bd_addr, p_lcb->link_role);
+
+ p_lcb->link_state = LST_CONNECTING;
+ return (TRUE);
+ }
+ else if (p_lcb->link_state == LST_DISCONNECTING)
+ {
+ /* In disconnecting state, reject the connection. */
+ btsnd_hcic_reject_conn (bd_addr, HCI_ERR_HOST_REJECT_DEVICE);
+ }
+ else
+ {
+ L2CAP_TRACE_ERROR0 ("L2CAP got conn_req while connected");
+ }
+ return (FALSE);
+}
+
+/*******************************************************************************
+**
+** Function l2c_link_hci_conn_comp
+**
+** Description This function is called when an HCI Connection Complete
+** event is received.
+**
+** Returns void
+**
+*******************************************************************************/
+BOOLEAN l2c_link_hci_conn_comp (UINT8 status, UINT16 handle, BD_ADDR p_bda)
+{
+ tL2C_CONN_INFO ci;
+ tL2C_LCB *p_lcb;
+ tL2C_CCB *p_ccb;
+ tBTM_SEC_DEV_REC *p_dev_info = NULL;
+
+#if (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE)
+ btm_acl_update_busy_level (BTM_BLI_PAGE_DONE_EVT);
+#endif
+
+ /* Save the parameters */
+ ci.status = status;
+ memcpy (ci.bd_addr, p_bda, BD_ADDR_LEN);
+
+ /* See if we have a link control block for the remote device */
+ p_lcb = l2cu_find_lcb_by_bd_addr (ci.bd_addr);
+
+ /* If we don't have one, this is an error */
+ if (!p_lcb)
+ {
+ L2CAP_TRACE_WARNING0 ("L2CAP got conn_comp for unknown BD_ADDR");
+ return (FALSE);
+ }
+
+ if (p_lcb->link_state != LST_CONNECTING)
+ {
+ L2CAP_TRACE_ERROR2 ("L2CAP got conn_comp in bad state: %d status: 0x%d", p_lcb->link_state, status);
+
+ if (status != HCI_SUCCESS)
+ l2c_link_hci_disc_comp (p_lcb->handle, status);
+
+ return (FALSE);
+ }
+
+ /* Save the handle */
+ p_lcb->handle = handle;
+
+ if (ci.status == HCI_SUCCESS)
+ {
+ /* Connected OK. Change state to connected */
+ p_lcb->link_state = LST_CONNECTED;
+
+ /* Get the peer information if the l2cap flow-control/rtrans is supported */
+ l2cu_send_peer_info_req (p_lcb, L2CAP_EXTENDED_FEATURES_INFO_TYPE);
+
+ /* Tell BTM Acl management about the link */
+ if ((p_dev_info = btm_find_dev (p_bda)) != NULL)
+ btm_acl_created (ci.bd_addr, p_dev_info->dev_class,
+ p_dev_info->sec_bd_name, handle,
+ p_lcb->link_role, FALSE);
+ else
+ btm_acl_created (ci.bd_addr, NULL, NULL, handle, p_lcb->link_role, FALSE);
+
+ /* If dedicated bonding do not process any further */
+ if (p_lcb->is_bonding)
+ {
+ if (l2cu_start_post_bond_timer(handle))
+ return (TRUE);
+ }
+
+ /* Update the timeouts in the hold queue */
+ l2c_process_held_packets(FALSE);
+
+ btu_stop_timer (&p_lcb->timer_entry);
+
+ /* For all channels, send the event through their FSMs */
+ for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; p_ccb = p_ccb->p_next_ccb)
+ {
+ l2c_csm_execute (p_ccb, L2CEVT_LP_CONNECT_CFM, &ci);
+ }
+
+ if (p_lcb->p_echo_rsp_cb)
+ {
+ l2cu_send_peer_echo_req (p_lcb, NULL, 0);
+ btu_start_timer (&p_lcb->timer_entry, BTU_TTYPE_L2CAP_LINK, L2CAP_ECHO_RSP_TOUT);
+ }
+ else if (!p_lcb->ccb_queue.p_first_ccb)
+ {
+ btu_start_timer (&p_lcb->timer_entry, BTU_TTYPE_L2CAP_LINK, L2CAP_LINK_STARTUP_TOUT);
+ }
+ }
+ /* Max number of acl connections. */
+ /* If there's an lcb disconnecting set this one to holding */
+ else if ((ci.status == HCI_ERR_MAX_NUM_OF_CONNECTIONS) && l2cu_lcb_disconnecting())
+ {
+ p_lcb->link_state = LST_CONNECT_HOLDING;
+ p_lcb->handle = HCI_INVALID_HANDLE;
+ }
+ else
+ {
+ /* Just in case app decides to try again in the callback context */
+ p_lcb->link_state = LST_DISCONNECTING;
+
+ /* Connection failed. For all channels, send the event through */
+ /* their FSMs. The CCBs should remove themselves from the LCB */
+ for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; )
+ {
+ tL2C_CCB *pn = p_ccb->p_next_ccb;
+
+ l2c_csm_execute (p_ccb, L2CEVT_LP_CONNECT_CFM_NEG, &ci);
+
+ p_ccb = pn;
+ }
+
+ p_lcb->disc_reason = status;
+ /* Release the LCB */
+ if (p_lcb->ccb_queue.p_first_ccb == NULL)
+ l2cu_release_lcb (p_lcb);
+ else /* there are any CCBs remaining */
+ {
+ if (ci.status == HCI_ERR_CONNECTION_EXISTS)
+ {
+ /* we are in collision situation, wait for connecttion request from controller */
+ p_lcb->link_state = LST_CONNECTING;
+ }
+ else
+ {
+ l2cu_create_conn(p_lcb);
+ }
+ }
+ }
+ return (TRUE);
+}
+
+
+/*******************************************************************************
+**
+** Function l2c_link_sec_comp
+**
+** Description This function is called when required security procedures
+** are completed.
+**
+** Returns void
+**
+*******************************************************************************/
+void l2c_link_sec_comp (BD_ADDR p_bda, void *p_ref_data, UINT8 status)
+{
+ tL2C_CONN_INFO ci;
+ tL2C_LCB *p_lcb;
+ tL2C_CCB *p_ccb;
+ tL2C_CCB *p_next_ccb;
+ UINT8 event;
+
+ L2CAP_TRACE_DEBUG2 ("l2c_link_sec_comp: %d, 0x%x", status, p_ref_data);
+
+ if (status == BTM_SUCCESS_NO_SECURITY)
+ status = BTM_SUCCESS;
+
+ /* Save the parameters */
+ ci.status = status;
+ memcpy (ci.bd_addr, p_bda, BD_ADDR_LEN);
+
+ p_lcb = l2cu_find_lcb_by_bd_addr (p_bda);
+
+ /* If we don't have one, this is an error */
+ if (!p_lcb)
+ {
+ L2CAP_TRACE_WARNING0 ("L2CAP got sec_comp for unknown BD_ADDR");
+ return;
+ }
+
+ /* Match p_ccb with p_ref_data returned by sec manager */
+ for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; p_ccb = p_next_ccb)
+ {
+ p_next_ccb = p_ccb->p_next_ccb;
+
+ if (p_ccb == p_ref_data)
+ {
+ switch(status)
+ {
+ case BTM_SUCCESS:
+ L2CAP_TRACE_DEBUG1 ("ccb timer ticks: %u", p_ccb->timer_entry.ticks);
+ event = L2CEVT_SEC_COMP;
+ break;
+
+ case BTM_DELAY_CHECK:
+ /* start a timer - encryption change not received before L2CAP connect req */
+ btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_DELAY_CHECK_SM4);
+ return;
+
+ default:
+ event = L2CEVT_SEC_COMP_NEG;
+ }
+ l2c_csm_execute (p_ccb, event, &ci);
+ break;
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function l2c_link_hci_disc_comp
+**
+** Description This function is called when an HCI Disconnect Complete
+** event is received.
+**
+** Returns TRUE if the link is known about, else FALSE
+**
+*******************************************************************************/
+BOOLEAN l2c_link_hci_disc_comp (UINT16 handle, UINT8 reason)
+{
+ tL2C_LCB *p_lcb;
+ tL2C_CCB *p_ccb;
+ BOOLEAN status = TRUE;
+ BOOLEAN lcb_is_free = TRUE;
+
+ /* See if we have a link control block for the connection */
+ p_lcb = l2cu_find_lcb_by_handle (handle);
+
+ /* If we don't have one, maybe an SCO link. Send to MM */
+ if (!p_lcb)
+ {
+ status = FALSE;
+ }
+ else
+ {
+ /* There can be a case when we rejected PIN code authentication */
+ /* otherwise save a new reason */
+ if (btm_cb.acl_disc_reason != HCI_ERR_HOST_REJECT_SECURITY)
+ btm_cb.acl_disc_reason = reason;
+
+ p_lcb->disc_reason = btm_cb.acl_disc_reason;
+
+ /* Just in case app decides to try again in the callback context */
+ p_lcb->link_state = LST_DISCONNECTING;
+
+ /* Link is disconnected. For all channels, send the event through */
+ /* their FSMs. The CCBs should remove themselves from the LCB */
+ for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; )
+ {
+ tL2C_CCB *pn = p_ccb->p_next_ccb;
+
+ /* Keep connect pending control block (if exists)
+ * Possible Race condition when a reconnect occurs
+ * on the channel during a disconnect of link. This
+ * ccb will be automatically retried after link disconnect
+ * arrives
+ */
+ if (p_ccb != p_lcb->p_pending_ccb)
+ {
+ l2c_csm_execute (p_ccb, L2CEVT_LP_DISCONNECT_IND, &reason);
+ }
+ p_ccb = pn;
+ }
+
+#if BTM_SCO_INCLUDED == TRUE
+ /* Tell SCO management to drop any SCOs on this ACL */
+ btm_sco_acl_removed (p_lcb->remote_bd_addr);
+#endif
+
+ /* If waiting for disconnect and reconnect is pending start the reconnect now
+ race condition where layer above issued connect request on link that was
+ disconnecting
+ */
+ if (p_lcb->ccb_queue.p_first_ccb != NULL)
+ {
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+ /* If we are going to re-use the LCB without dropping it, release all fixed channels here */
+ int xx;
+
+ for (xx = 0; xx < L2CAP_NUM_FIXED_CHNLS; xx++)
+ {
+ if (p_lcb->p_fixed_ccbs[xx])
+ {
+ (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(p_lcb->remote_bd_addr, FALSE, p_lcb->disc_reason);
+ l2cu_release_ccb (p_lcb->p_fixed_ccbs[xx]);
+
+ p_lcb->p_fixed_ccbs[xx] = NULL;
+ }
+ }
+#endif
+ L2CAP_TRACE_DEBUG0("l2c_link_hci_disc_comp: Restarting pending ACL request");
+
+ if (l2cu_create_conn(p_lcb))
+ lcb_is_free = FALSE; /* still using this lcb */
+ }
+
+ p_lcb->p_pending_ccb = NULL;
+
+ /* Release the LCB */
+ if (lcb_is_free)
+ l2cu_release_lcb (p_lcb);
+ }
+
+ /* Now that we have a free acl connection, see if any lcbs are pending */
+ if (lcb_is_free && ((p_lcb = l2cu_find_lcb_by_state(LST_CONNECT_HOLDING)) != NULL))
+ {
+ /* we found one-- create a connection */
+ l2cu_create_conn(p_lcb);
+ }
+
+ return status;
+}
+
+
+/*******************************************************************************
+**
+** Function l2c_link_hci_qos_violation
+**
+** Description This function is called when an HCI QOS Violation
+** event is received.
+**
+** Returns TRUE if the link is known about, else FALSE
+**
+*******************************************************************************/
+BOOLEAN l2c_link_hci_qos_violation (UINT16 handle)
+{
+ tL2C_LCB *p_lcb;
+ tL2C_CCB *p_ccb;
+
+ /* See if we have a link control block for the connection */
+ p_lcb = l2cu_find_lcb_by_handle (handle);
+
+ /* If we don't have one, maybe an SCO link. */
+ if (!p_lcb)
+ return (FALSE);
+
+ /* For all channels, tell the upper layer about it */
+ for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; p_ccb = p_ccb->p_next_ccb)
+ {
+ if (p_ccb->p_rcb->api.pL2CA_QoSViolationInd_Cb)
+ l2c_csm_execute (p_ccb, L2CEVT_LP_QOS_VIOLATION_IND, NULL);
+ }
+
+ return (TRUE);
+}
+
+
+
+/*******************************************************************************
+**
+** Function l2c_link_timeout
+**
+** Description This function is called when a link timer expires
+**
+** Returns void
+**
+*******************************************************************************/
+void l2c_link_timeout (tL2C_LCB *p_lcb)
+{
+ tL2C_CCB *p_ccb;
+ UINT16 timeout;
+ tBTM_STATUS rc;
+
+ L2CAP_TRACE_EVENT3 ("L2CAP - l2c_link_timeout() link state %d first CCB %p is_bonding:%d",
+ p_lcb->link_state, p_lcb->ccb_queue.p_first_ccb, p_lcb->is_bonding);
+
+ /* If link was connecting or disconnecting, clear all channels and drop the LCB */
+ if ((p_lcb->link_state == LST_CONNECTING_WAIT_SWITCH) ||
+ (p_lcb->link_state == LST_CONNECTING) ||
+ (p_lcb->link_state == LST_CONNECT_HOLDING) ||
+ (p_lcb->link_state == LST_DISCONNECTING))
+ {
+ p_lcb->p_pending_ccb = NULL;
+
+ /* For all channels, send a disconnect indication event through */
+ /* their FSMs. The CCBs should remove themselves from the LCB */
+ for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; )
+ {
+ tL2C_CCB *pn = p_ccb->p_next_ccb;
+
+ l2c_csm_execute (p_ccb, L2CEVT_LP_DISCONNECT_IND, NULL);
+
+ p_ccb = pn;
+ }
+#if (BLE_INCLUDED == TRUE)
+ if (p_lcb->link_state == LST_CONNECTING &&
+ l2cb.is_ble_connecting == TRUE)
+ {
+ L2CA_CancelBleConnectReq(l2cb.ble_connecting_bda);
+ }
+#endif
+ /* Release the LCB */
+ l2cu_release_lcb (p_lcb);
+ }
+
+ /* If link is connected, check for inactivity timeout */
+ if (p_lcb->link_state == LST_CONNECTED)
+ {
+ /* Check for ping outstanding */
+ if (p_lcb->p_echo_rsp_cb)
+ {
+ tL2CA_ECHO_RSP_CB *p_cb = p_lcb->p_echo_rsp_cb;
+
+ /* Zero out the callback in case app immediately calls us again */
+ p_lcb->p_echo_rsp_cb = NULL;
+
+ (*p_cb) (L2CAP_PING_RESULT_NO_RESP);
+
+ L2CAP_TRACE_WARNING0 ("L2CAP - ping timeout");
+
+ /* For all channels, send a disconnect indication event through */
+ /* their FSMs. The CCBs should remove themselves from the LCB */
+ for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; )
+ {
+ tL2C_CCB *pn = p_ccb->p_next_ccb;
+
+ l2c_csm_execute (p_ccb, L2CEVT_LP_DISCONNECT_IND, NULL);
+
+ p_ccb = pn;
+ }
+ }
+
+ /* If no channels in use, drop the link. */
+ if (!p_lcb->ccb_queue.p_first_ccb)
+ {
+ rc = btm_sec_disconnect (p_lcb->handle, HCI_ERR_PEER_USER);
+
+ if (rc == BTM_CMD_STORED)
+ {
+ /* Security Manager will take care of disconnecting, state will be updated at that time */
+ timeout = 0xFFFF;
+ }
+ else if (rc == BTM_CMD_STARTED)
+ {
+ p_lcb->link_state = LST_DISCONNECTING;
+ timeout = L2CAP_LINK_DISCONNECT_TOUT;
+ }
+ else if (rc == BTM_SUCCESS)
+ {
+ /* BTM SEC will make sure that link is release (probably after pairing is done) */
+ p_lcb->link_state = LST_DISCONNECTING;
+ timeout = 0xFFFF;
+ }
+ else if (rc == BTM_BUSY)
+ {
+ /* BTM is still executing security process. Let lcb stay as connected */
+ timeout = 0xFFFF;
+ }
+ else if ((p_lcb->is_bonding)
+ && (btsnd_hcic_disconnect (p_lcb->handle, HCI_ERR_PEER_USER)))
+ {
+ p_lcb->link_state = LST_DISCONNECTING;
+ timeout = L2CAP_LINK_DISCONNECT_TOUT;
+ }
+ else
+ {
+ /* probably no buffer to send disconnect */
+ timeout = BT_1SEC_TIMEOUT;
+ }
+
+ if (timeout != 0xFFFF)
+ {
+ btu_start_timer (&p_lcb->timer_entry, BTU_TTYPE_L2CAP_LINK, timeout);
+ }
+ }
+ else
+ {
+ /* Check in case we were flow controlled */
+ l2c_link_check_send_pkts (p_lcb, NULL, NULL);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function l2c_info_timeout
+**
+** Description This function is called when an info request times out
+**
+** Returns void
+**
+*******************************************************************************/
+void l2c_info_timeout (tL2C_LCB *p_lcb)
+{
+ tL2C_CCB *p_ccb;
+ tL2C_CONN_INFO ci;
+
+ /* If we timed out waiting for info response, just continue using basic if allowed */
+ if (p_lcb->w4_info_rsp)
+ {
+ /* If waiting for security complete, restart the info response timer */
+ for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; p_ccb = p_ccb->p_next_ccb)
+ {
+ if ( (p_ccb->chnl_state == CST_ORIG_W4_SEC_COMP) || (p_ccb->chnl_state == CST_TERM_W4_SEC_COMP) )
+ {
+ btu_start_timer (&p_lcb->info_timer_entry, BTU_TTYPE_L2CAP_INFO, L2CAP_WAIT_INFO_RSP_TOUT);
+ return;
+ }
+ }
+
+ p_lcb->w4_info_rsp = FALSE;
+
+ /* If link is in process of being brought up */
+ if ((p_lcb->link_state != LST_DISCONNECTED) &&
+ (p_lcb->link_state != LST_DISCONNECTING))
+ {
+ /* Notify active channels that peer info is finished */
+ if (p_lcb->ccb_queue.p_first_ccb)
+ {
+ ci.status = HCI_SUCCESS;
+ memcpy (ci.bd_addr, p_lcb->remote_bd_addr, sizeof(BD_ADDR));
+
+ for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; p_ccb = p_ccb->p_next_ccb)
+ {
+ l2c_csm_execute (p_ccb, L2CEVT_L2CAP_INFO_RSP, &ci);
+ }
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function l2c_link_adjust_allocation
+**
+** Description This function is called when a link is created or removed
+** to calculate the amount of packets each link may send to
+** the HCI without an ack coming back.
+**
+** Currently, this is a simple allocation, dividing the
+** number of Controller Packets by the number of links. In
+** the future, QOS configuration should be examined.
+**
+** Returns void
+**
+*******************************************************************************/
+void l2c_link_adjust_allocation (void)
+{
+ UINT16 qq, yy, qq_remainder;
+ tL2C_LCB *p_lcb;
+ UINT16 hi_quota, low_quota;
+ UINT16 num_lowpri_links = 0;
+ UINT16 num_hipri_links = 0;
+ UINT16 controller_xmit_quota = l2cb.num_lm_acl_bufs;
+ UINT16 high_pri_link_quota = L2CAP_HIGH_PRI_MIN_XMIT_QUOTA_A;
+
+ /* If no links active, nothing to do. */
+ if (l2cb.num_links_active == 0)
+ {
+ l2cb.round_robin_quota = l2cb.round_robin_unacked = 0;
+ return;
+ }
+
+ /* First, count the links */
+ for (yy = 0, p_lcb = &l2cb.lcb_pool[0]; yy < MAX_L2CAP_LINKS; yy++, p_lcb++)
+ {
+ if (p_lcb->in_use)
+ {
+ if (p_lcb->acl_priority == L2CAP_PRIORITY_HIGH)
+ num_hipri_links++;
+ else
+ num_lowpri_links++;
+ }
+ }
+
+ /* now adjust high priority link quota */
+ low_quota = num_lowpri_links ? 1 : 0;
+ while ( (num_hipri_links * high_pri_link_quota + low_quota) > controller_xmit_quota )
+ high_pri_link_quota--;
+
+ /* Work out the xmit quota and buffer quota high and low priorities */
+ hi_quota = num_hipri_links * high_pri_link_quota;
+ low_quota = (hi_quota < controller_xmit_quota) ? controller_xmit_quota - hi_quota : 1;
+
+ /* Work out and save the HCI xmit quota for each low priority link */
+
+ /* If each low priority link cannot have at least one buffer */
+ if (num_lowpri_links > low_quota)
+ {
+ l2cb.round_robin_quota = low_quota;
+ qq = qq_remainder = 0;
+ }
+ /* If each low priority link can have at least one buffer */
+ else if (num_lowpri_links > 0)
+ {
+ l2cb.round_robin_quota = 0;
+ l2cb.round_robin_unacked = 0;
+ qq = low_quota / num_lowpri_links;
+ qq_remainder = low_quota % num_lowpri_links;
+ }
+ /* If no low priority link */
+ else
+ {
+ l2cb.round_robin_quota = 0;
+ l2cb.round_robin_unacked = 0;
+ qq = qq_remainder = 0;
+ }
+
+ L2CAP_TRACE_EVENT5 ("l2c_link_adjust_allocation num_hipri: %u num_lowpri: %u low_quota: %u round_robin_quota: %u qq: %u",
+ num_hipri_links, num_lowpri_links, low_quota,
+ l2cb.round_robin_quota, qq);
+
+ /* Now, assign the quotas to each link */
+ for (yy = 0, p_lcb = &l2cb.lcb_pool[0]; yy < MAX_L2CAP_LINKS; yy++, p_lcb++)
+ {
+ if (p_lcb->in_use)
+ {
+ if (p_lcb->acl_priority == L2CAP_PRIORITY_HIGH)
+ {
+ p_lcb->link_xmit_quota = high_pri_link_quota;
+ }
+ else
+ {
+ /* Safety check in case we switched to round-robin with something outstanding */
+ /* if sent_not_acked is added into round_robin_unacked then don't add it again */
+ /* l2cap keeps updating sent_not_acked for exiting from round robin */
+ if (( p_lcb->link_xmit_quota > 0 )&&( qq == 0 ))
+ l2cb.round_robin_unacked += p_lcb->sent_not_acked;
+
+ p_lcb->link_xmit_quota = qq;
+ if (qq_remainder > 0)
+ {
+ p_lcb->link_xmit_quota++;
+ qq_remainder--;
+ }
+ }
+
+#if L2CAP_HOST_FLOW_CTRL
+ p_lcb->link_ack_thresh = L2CAP_HOST_FC_ACL_BUFS / l2cb.num_links_active;
+#endif
+ L2CAP_TRACE_EVENT3 ("l2c_link_adjust_allocation LCB %d Priority: %d XmitQuota: %d",
+ yy, p_lcb->acl_priority, p_lcb->link_xmit_quota);
+
+ L2CAP_TRACE_EVENT2 (" SentNotAcked: %d RRUnacked: %d",
+ p_lcb->sent_not_acked, l2cb.round_robin_unacked);
+
+ /* There is a special case where we have readjusted the link quotas and */
+ /* this link may have sent anything but some other link sent packets so */
+ /* so we may need a timer to kick off this link's transmissions. */
+ if ( (p_lcb->link_state == LST_CONNECTED)
+ && (p_lcb->link_xmit_data_q.count)
+ && (p_lcb->sent_not_acked < p_lcb->link_xmit_quota) )
+ btu_start_timer (&p_lcb->timer_entry, BTU_TTYPE_L2CAP_LINK, L2CAP_LINK_FLOW_CONTROL_TOUT);
+ }
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function l2c_link_adjust_chnl_allocation
+**
+** Description This function is called to calculate the amount of packets each
+** non-F&EC channel may have outstanding.
+**
+** Currently, this is a simple allocation, dividing the number
+** of packets allocated to the link by the number of channels. In
+** the future, QOS configuration should be examined.
+**
+** Returns void
+**
+*******************************************************************************/
+void l2c_link_adjust_chnl_allocation (void)
+{
+ tL2C_CCB *p_ccb;
+ UINT8 xx;
+
+ UINT16 weighted_chnls[GKI_NUM_TOTAL_BUF_POOLS];
+ UINT16 quota_per_weighted_chnls[GKI_NUM_TOTAL_BUF_POOLS];
+ UINT16 reserved_buff[GKI_NUM_TOTAL_BUF_POOLS];
+
+ L2CAP_TRACE_DEBUG0 ("l2c_link_adjust_chnl_allocation");
+
+ /* initialize variables */
+ for (xx = 0; xx < GKI_NUM_TOTAL_BUF_POOLS; xx++ )
+ {
+ weighted_chnls[xx] = 0;
+ reserved_buff[xx] = 0;
+ }
+
+ /* add up all of tx and rx data rate requirement */
+ /* channel required higher data rate will get more buffer quota */
+ for (xx = 0; xx < MAX_L2CAP_CHANNELS; xx++)
+ {
+ p_ccb = l2cb.ccb_pool + xx;
+
+ if (!p_ccb->in_use)
+ continue;
+
+ if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE)
+ {
+ weighted_chnls[p_ccb->ertm_info.user_tx_pool_id] += p_ccb->tx_data_rate;
+ weighted_chnls[p_ccb->ertm_info.user_rx_pool_id] += p_ccb->rx_data_rate;
+
+ if (p_ccb->ertm_info.fcr_tx_pool_id == HCI_ACL_POOL_ID)
+ {
+ /* reserve buffers only for wait_for_ack_q to maximize throughput */
+ /* retrans_q will work based on buffer status */
+ reserved_buff[HCI_ACL_POOL_ID] += p_ccb->peer_cfg.fcr.tx_win_sz;
+ }
+
+ if (p_ccb->ertm_info.fcr_rx_pool_id == HCI_ACL_POOL_ID)
+ {
+ /* reserve buffers for srej_rcv_hold_q */
+ reserved_buff[HCI_ACL_POOL_ID] += p_ccb->peer_cfg.fcr.tx_win_sz;
+ }
+ }
+ else
+ {
+ /* low data rate is 1, medium is 2, high is 3 and no traffic is 0 */
+ weighted_chnls[HCI_ACL_POOL_ID] += p_ccb->tx_data_rate + p_ccb->rx_data_rate;
+ }
+ }
+
+
+ /* get unit quota per pool */
+ for (xx = 0; xx < GKI_NUM_TOTAL_BUF_POOLS; xx++ )
+ {
+ if ( weighted_chnls[xx] > 0 )
+ {
+ if (GKI_poolcount(xx) > reserved_buff[xx])
+ quota_per_weighted_chnls[xx] = ((GKI_poolcount(xx) - reserved_buff[xx])/weighted_chnls[xx]) + 1;
+ else
+ quota_per_weighted_chnls[xx] = 1;
+
+ L2CAP_TRACE_DEBUG5 ("POOL ID:%d, GKI_poolcount = %d, reserved_buff = %d, weighted_chnls = %d, quota_per_weighted_chnls = %d",
+ xx, GKI_poolcount(xx), reserved_buff[xx], weighted_chnls[xx], quota_per_weighted_chnls[xx] );
+ }
+ else
+ quota_per_weighted_chnls[xx] = 0;
+ }
+
+
+ /* assign buffer quota to each channel based on its data rate requirement */
+ for (xx = 0; xx < MAX_L2CAP_CHANNELS; xx++)
+ {
+ p_ccb = l2cb.ccb_pool + xx;
+
+ if (!p_ccb->in_use)
+ continue;
+
+ if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE)
+ {
+ p_ccb->buff_quota = quota_per_weighted_chnls[p_ccb->ertm_info.user_tx_pool_id] * p_ccb->tx_data_rate;
+
+ L2CAP_TRACE_EVENT6 ("CID:0x%04x FCR Mode:%u UserTxPool:%u Priority:%u TxDataRate:%u Quota:%u",
+ p_ccb->local_cid, p_ccb->peer_cfg.fcr.mode, p_ccb->ertm_info.user_tx_pool_id,
+ p_ccb->ccb_priority, p_ccb->tx_data_rate, p_ccb->buff_quota);
+
+ }
+ else
+ {
+ p_ccb->buff_quota = quota_per_weighted_chnls[HCI_ACL_POOL_ID] * p_ccb->tx_data_rate;
+
+ L2CAP_TRACE_EVENT4 ("CID:0x%04x Priority:%u TxDataRate:%u Quota:%u",
+ p_ccb->local_cid,
+ p_ccb->ccb_priority, p_ccb->tx_data_rate, p_ccb->buff_quota);
+ }
+
+ /* quota may be change so check congestion */
+ l2cu_check_channel_congestion (p_ccb);
+ }
+}
+
+/*******************************************************************************
+**
+** Function l2c_link_processs_num_bufs
+**
+** Description This function is called when a "controller buffer size"
+** event is first received from the controller. It updates
+** the L2CAP values.
+**
+** Returns void
+**
+*******************************************************************************/
+void l2c_link_processs_num_bufs (UINT16 num_lm_acl_bufs)
+{
+ l2cb.num_lm_acl_bufs = l2cb.controller_xmit_window = num_lm_acl_bufs;
+
+}
+
+/*******************************************************************************
+**
+** Function l2c_link_pkts_rcvd
+**
+** Description This function is called from the HCI transport when it is time
+** tto send a "Host ready for packets" command. This is only when
+** host to controller flow control is used. If fills in the arrays
+** of numbers of packets and handles.
+**
+** Returns count of number of entries filled in
+**
+*******************************************************************************/
+UINT8 l2c_link_pkts_rcvd (UINT16 *num_pkts, UINT16 *handles)
+{
+ UINT8 num_found = 0;
+
+#if (L2CAP_HOST_FLOW_CTRL == TRUE)
+
+ int xx;
+ tL2C_LCB *p_lcb = &l2cb.lcb_pool[0];
+
+ for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_lcb++)
+ {
+ if ((p_lcb->in_use) && (p_lcb->link_pkts_unacked))
+ {
+ num_pkts[num_found] = p_lcb->link_pkts_unacked;
+ handles[num_found] = p_lcb->handle;
+ p_lcb->link_pkts_unacked = 0;
+ num_found++;
+ }
+ }
+
+#endif
+
+ return (num_found);
+}
+
+/*******************************************************************************
+**
+** Function l2c_link_role_changed
+**
+** Description This function is called whan a link's master/slave role change
+** event is received. It simply updates the link control block.
+**
+** Returns void
+**
+*******************************************************************************/
+void l2c_link_role_changed (BD_ADDR bd_addr, UINT8 new_role, UINT8 hci_status)
+{
+ tL2C_LCB *p_lcb;
+ int xx;
+
+ /* Make sure not called from HCI Command Status (bd_addr and new_role are invalid) */
+ if (bd_addr)
+ {
+ /* If here came form hci role change event */
+ p_lcb = l2cu_find_lcb_by_bd_addr (bd_addr);
+ if (p_lcb)
+ {
+ p_lcb->link_role = new_role;
+
+ /* Reset high priority link if needed */
+ if (hci_status == HCI_SUCCESS)
+ l2cu_set_acl_priority(bd_addr, p_lcb->acl_priority, TRUE);
+ }
+ }
+
+ /* Check if any LCB was waiting for switch to be completed */
+ for (xx = 0, p_lcb = &l2cb.lcb_pool[0]; xx < MAX_L2CAP_LINKS; xx++, p_lcb++)
+ {
+ if ((p_lcb->in_use) && (p_lcb->link_state == LST_CONNECTING_WAIT_SWITCH))
+ {
+ l2cu_create_conn_after_switch (p_lcb);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function l2c_pin_code_request
+**
+** Description This function is called whan a pin-code request is received
+** on a connection. If there are no channels active yet on the
+** link, it extends the link first connection timer. Make sure
+** that inactivity timer is not extended if PIN code happens
+** to be after last ccb released.
+**
+** Returns void
+**
+*******************************************************************************/
+void l2c_pin_code_request (BD_ADDR bd_addr)
+{
+ tL2C_LCB *p_lcb = l2cu_find_lcb_by_bd_addr (bd_addr);
+
+ if ( (p_lcb) && (!p_lcb->ccb_queue.p_first_ccb) )
+ {
+ btu_start_timer (&p_lcb->timer_entry, BTU_TTYPE_L2CAP_LINK, L2CAP_LINK_CONNECT_TOUT_EXT);
+ }
+}
+
+#if ((BTM_PWR_MGR_INCLUDED == TRUE) && L2CAP_WAKE_PARKED_LINK == TRUE)
+/*******************************************************************************
+**
+** Function l2c_link_check_power_mode
+**
+** Description This function is called to check power mode.
+**
+** Returns TRUE if link is going to be active from park
+** FALSE if nothing to send or not in park mode
+**
+*******************************************************************************/
+BOOLEAN l2c_link_check_power_mode (tL2C_LCB *p_lcb)
+{
+ tBTM_PM_MODE mode;
+ tBTM_PM_PWR_MD pm;
+ tL2C_CCB *p_ccb;
+ BOOLEAN need_to_active = FALSE;
+
+ /*
+ * We only switch park to active only if we have unsent packets
+ */
+ if ( p_lcb->link_xmit_data_q.count == 0 )
+ {
+ for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; p_ccb = p_ccb->p_next_ccb)
+ {
+ if (p_ccb->xmit_hold_q.count != 0)
+ {
+ need_to_active = TRUE;
+ break;
+ }
+ }
+ }
+ else
+ need_to_active = TRUE;
+
+ /* if we have packets to send */
+ if ( need_to_active )
+ {
+ /* check power mode */
+ if (BTM_ReadPowerMode(p_lcb->remote_bd_addr, &mode) == BTM_SUCCESS)
+ {
+ if ( mode == BTM_PM_MD_PARK )
+ {
+ L2CAP_TRACE_DEBUG1 ("LCB(0x%x) is in park mode", p_lcb->handle);
+/* Coverity:
+// FALSE-POSITIVE error from Coverity test tool. Please do NOT remove following comment.
+// coverity[uninit_use_in_call] False-positive: setting the mode to BTM_PM_MD_ACTIVE only uses settings.mode
+ the other data members of tBTM_PM_PWR_MD are ignored
+*/
+ memset((void*)&pm, 0, sizeof(pm));
+ pm.mode = BTM_PM_MD_ACTIVE;
+ BTM_SetPowerMode(BTM_PM_SET_ONLY_ID, p_lcb->remote_bd_addr, &pm);
+ btu_start_timer (&p_lcb->timer_entry,
+ BTU_TTYPE_L2CAP_LINK, L2CAP_WAIT_UNPARK_TOUT);
+ return TRUE;
+ }
+ else if ( mode == BTM_PM_STS_PENDING )
+ {
+ L2CAP_TRACE_DEBUG1 ("LCB(0x%x) is in PM pending state", p_lcb->handle);
+
+ btu_start_timer (&p_lcb->timer_entry,
+ BTU_TTYPE_L2CAP_LINK, L2CAP_WAIT_UNPARK_TOUT);
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+#endif /* ((BTM_PWR_MGR_INCLUDED == TRUE) && L2CAP_WAKE_PARKED_LINK == TRUE) */
+
+/*******************************************************************************
+**
+** Function l2c_link_check_send_pkts
+**
+** Description This function is called to check if it can send packets
+** to the Host Controller. It may be passed the address of
+** a packet to send.
+**
+** Returns void
+**
+*******************************************************************************/
+void l2c_link_check_send_pkts (tL2C_LCB *p_lcb, tL2C_CCB *p_ccb, BT_HDR *p_buf)
+{
+ int xx;
+ BOOLEAN single_write = FALSE;
+
+ /* Save the channel ID for faster counting */
+ if (p_buf)
+ {
+ if (p_ccb != NULL)
+ {
+ p_buf->event = p_ccb->local_cid;
+ single_write = TRUE;
+ }
+ else
+ p_buf->event = 0;
+
+ p_buf->layer_specific = 0;
+ GKI_enqueue (&p_lcb->link_xmit_data_q, p_buf);
+
+ if (p_lcb->link_xmit_quota == 0)
+ l2cb.check_round_robin = TRUE;
+ }
+
+ /* If this is called from uncongested callback context break recursive calling.
+ ** This LCB will be served when receiving number of completed packet event.
+ */
+ if (l2cb.is_cong_cback_context)
+ return;
+
+ /* If we are in a scenario where there are not enough buffers for each link to
+ ** have at least 1, then do a round-robin for all the LCBs
+ */
+ if ( (p_lcb == NULL) || (p_lcb->link_xmit_quota == 0) )
+ {
+ if (p_lcb == NULL)
+ p_lcb = l2cb.lcb_pool;
+ else if (!single_write)
+ p_lcb++;
+
+ /* Loop through, starting at the next */
+ for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_lcb++)
+ {
+ /* If controller window is full, nothing to do */
+ if ( (l2cb.controller_xmit_window == 0
+#if (BLE_INCLUDED == TRUE)
+ && !p_lcb->is_ble_link
+#endif
+ )
+#if (BLE_INCLUDED == TRUE)
+ || (p_lcb->is_ble_link && l2cb.controller_le_xmit_window == 0 )
+#endif
+ || (l2cb.round_robin_unacked >= l2cb.round_robin_quota) )
+ break;
+
+ /* Check for wraparound */
+ if (p_lcb == &l2cb.lcb_pool[MAX_L2CAP_LINKS])
+ p_lcb = &l2cb.lcb_pool[0];
+
+ if ( (!p_lcb->in_use)
+ || (p_lcb->partial_segment_being_sent)
+ || (p_lcb->link_state != LST_CONNECTED)
+ || (p_lcb->link_xmit_quota != 0)
+ || (L2C_LINK_CHECK_POWER_MODE (p_lcb)) )
+ continue;
+
+ /* See if we can send anything from the Link Queue */
+ if ((p_buf = (BT_HDR *)GKI_dequeue (&p_lcb->link_xmit_data_q)) != NULL)
+ {
+ l2c_link_send_to_lower (p_lcb, p_buf);
+ }
+ else if (single_write)
+ {
+ /* If only doing one write, break out */
+ break;
+ }
+ /* If nothing on the link queue, check the channel queue */
+ else if ((p_buf = l2cu_get_next_buffer_to_send (p_lcb)) != NULL)
+ {
+ l2c_link_send_to_lower (p_lcb, p_buf);
+ }
+ }
+
+ /* If we finished without using up our quota, no need for a safety check */
+#if (BLE_INCLUDED == TRUE)
+ if ( ((l2cb.controller_xmit_window > 0 && !p_lcb->is_ble_link) ||
+ (l2cb.controller_le_xmit_window > 0 && p_lcb->is_ble_link))
+ && (l2cb.round_robin_unacked < l2cb.round_robin_quota) )
+#else
+ if ( (l2cb.controller_xmit_window > 0)
+ && (l2cb.round_robin_unacked < l2cb.round_robin_quota) )
+
+#endif
+ l2cb.check_round_robin = FALSE;
+ }
+ else /* if this is not round-robin service */
+ {
+ /* If a partial segment is being sent, can't send anything else */
+ if ( (p_lcb->partial_segment_being_sent)
+ || (p_lcb->link_state != LST_CONNECTED)
+ || (L2C_LINK_CHECK_POWER_MODE (p_lcb)) )
+ return;
+
+ /* See if we can send anything from the link queue */
+#if (BLE_INCLUDED == TRUE)
+ while ( ((l2cb.controller_xmit_window != 0 && !p_lcb->is_ble_link) ||
+ (l2cb.controller_le_xmit_window != 0 && p_lcb->is_ble_link))
+ && (p_lcb->sent_not_acked < p_lcb->link_xmit_quota))
+#else
+ while ( (l2cb.controller_xmit_window != 0)
+ && (p_lcb->sent_not_acked < p_lcb->link_xmit_quota))
+#endif
+ {
+ if ((p_buf = (BT_HDR *)GKI_dequeue (&p_lcb->link_xmit_data_q)) == NULL)
+ break;
+
+ if (!l2c_link_send_to_lower (p_lcb, p_buf))
+ break;
+ }
+
+ if (!single_write)
+ {
+ /* See if we can send anything for any channel */
+#if (BLE_INCLUDED == TRUE)
+ while ( ((l2cb.controller_xmit_window != 0 && !p_lcb->is_ble_link) ||
+ (l2cb.controller_le_xmit_window != 0 && p_lcb->is_ble_link))
+ && (p_lcb->sent_not_acked < p_lcb->link_xmit_quota))
+#else
+ while ((l2cb.controller_xmit_window != 0) && (p_lcb->sent_not_acked < p_lcb->link_xmit_quota))
+#endif
+ {
+ if ((p_buf = l2cu_get_next_buffer_to_send (p_lcb)) == NULL)
+ break;
+
+ if (!l2c_link_send_to_lower (p_lcb, p_buf))
+ break;
+ }
+ }
+
+ /* There is a special case where we have readjusted the link quotas and */
+ /* this link may have sent anything but some other link sent packets so */
+ /* so we may need a timer to kick off this link's transmissions. */
+ if ( (p_lcb->link_xmit_data_q.count) && (p_lcb->sent_not_acked < p_lcb->link_xmit_quota) )
+ btu_start_timer (&p_lcb->timer_entry, BTU_TTYPE_L2CAP_LINK, L2CAP_LINK_FLOW_CONTROL_TOUT);
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function l2c_link_send_to_lower
+**
+** Description This function queues the buffer for HCI transmission
+**
+** Returns TRUE for success, FALSE for fail
+**
+*******************************************************************************/
+static BOOLEAN l2c_link_send_to_lower (tL2C_LCB *p_lcb, BT_HDR *p_buf)
+{
+ UINT16 num_segs;
+ UINT16 xmit_window, acl_data_size;
+
+#if (BLE_INCLUDED == TRUE)
+ if ((!p_lcb->is_ble_link && (p_buf->len <= btu_cb.hcit_acl_pkt_size)) ||
+ (p_lcb->is_ble_link && (p_buf->len <= btu_cb.hcit_ble_acl_pkt_size)))
+#else
+ if (p_buf->len <= btu_cb.hcit_acl_pkt_size)
+#endif
+ {
+ if (p_lcb->link_xmit_quota == 0)
+ l2cb.round_robin_unacked++;
+
+ p_lcb->sent_not_acked++;
+ p_buf->layer_specific = 0;
+
+#if (BLE_INCLUDED == TRUE)
+ if (p_lcb->is_ble_link)
+ {
+ l2cb.controller_le_xmit_window--;
+ L2C_LINK_SEND_BLE_ACL_DATA (p_buf);
+ }
+ else
+#endif
+ {
+ l2cb.controller_xmit_window--;
+ L2C_LINK_SEND_ACL_DATA (p_buf);
+ }
+ }
+ else
+ {
+#if BLE_INCLUDED == TRUE
+ if (p_lcb->is_ble_link)
+ {
+ acl_data_size = btu_cb.hcit_ble_acl_data_size;
+ xmit_window = l2cb.controller_le_xmit_window;
+
+ }
+ else
+#endif
+ {
+ acl_data_size = btu_cb.hcit_acl_data_size;
+ xmit_window = l2cb.controller_xmit_window;
+ }
+ num_segs = (p_buf->len - HCI_DATA_PREAMBLE_SIZE + acl_data_size - 1) / acl_data_size;
+
+
+ /* If doing round-robin, then only 1 segment each time */
+ if (p_lcb->link_xmit_quota == 0)
+ {
+ num_segs = 1;
+ p_lcb->partial_segment_being_sent = TRUE;
+ }
+ else
+ {
+ /* Multi-segment packet. Make sure it can fit */
+ if (num_segs > xmit_window)
+ {
+ num_segs = xmit_window;
+ p_lcb->partial_segment_being_sent = TRUE;
+ }
+
+ if (num_segs > (p_lcb->link_xmit_quota - p_lcb->sent_not_acked))
+ {
+ num_segs = (p_lcb->link_xmit_quota - p_lcb->sent_not_acked);
+ p_lcb->partial_segment_being_sent = TRUE;
+ }
+ }
+
+ p_buf->layer_specific = num_segs;
+#if BLE_INCLUDED == TRUE
+ if (p_lcb->is_ble_link)
+ {
+ l2cb.controller_le_xmit_window -= num_segs;
+
+ }
+ else
+#endif
+ l2cb.controller_xmit_window -= num_segs;
+
+ if (p_lcb->link_xmit_quota == 0)
+ l2cb.round_robin_unacked += num_segs;
+
+ p_lcb->sent_not_acked += num_segs;
+#if BLE_INCLUDED == TRUE
+ if (p_lcb->is_ble_link)
+ {
+ L2C_LINK_SEND_BLE_ACL_DATA(p_buf);
+ }
+ else
+#endif
+ {
+ L2C_LINK_SEND_ACL_DATA (p_buf);
+ }
+ }
+
+#if (L2CAP_HCI_FLOW_CONTROL_DEBUG == TRUE)
+#if (BLE_INCLUDED == TRUE)
+ if (p_lcb->is_ble_link)
+ {
+ L2CAP_TRACE_DEBUG6 ("TotalWin=%d,Hndl=0x%x,Quota=%d,Unack=%d,RRQuota=%d,RRUnack=%d",
+ l2cb.controller_le_xmit_window,
+ p_lcb->handle,
+ p_lcb->link_xmit_quota, p_lcb->sent_not_acked,
+ l2cb.round_robin_quota, l2cb.round_robin_unacked);
+ }
+ else
+#endif
+ {
+ L2CAP_TRACE_DEBUG6 ("TotalWin=%d,Hndl=0x%x,Quota=%d,Unack=%d,RRQuota=%d,RRUnack=%d",
+ l2cb.controller_xmit_window,
+ p_lcb->handle,
+ p_lcb->link_xmit_quota, p_lcb->sent_not_acked,
+ l2cb.round_robin_quota, l2cb.round_robin_unacked);
+ }
+#endif
+
+ return TRUE;
+}
+
+/*******************************************************************************
+**
+** Function l2c_link_process_num_completed_pkts
+**
+** Description This function is called when a "number-of-completed-packets"
+** event is received from the controller. It updates all the
+** LCB transmit counts.
+**
+** Returns void
+**
+*******************************************************************************/
+void l2c_link_process_num_completed_pkts (UINT8 *p)
+{
+ UINT8 num_handles, xx;
+ UINT16 handle;
+ UINT16 num_sent;
+ tL2C_LCB *p_lcb;
+
+ STREAM_TO_UINT8 (num_handles, p);
+
+ for (xx = 0; xx < num_handles; xx++)
+ {
+ STREAM_TO_UINT16 (handle, p);
+ STREAM_TO_UINT16 (num_sent, p);
+
+ p_lcb = l2cu_find_lcb_by_handle (handle);
+
+ /* Callback for number of completed packet event */
+ /* Originally designed for [3DSG] */
+ if((p_lcb != NULL) && (p_lcb->p_nocp_cb))
+ {
+ L2CAP_TRACE_DEBUG0 ("L2CAP - calling NoCP callback");
+ (*p_lcb->p_nocp_cb)(p_lcb->remote_bd_addr);
+ }
+
+#if (BLE_INCLUDED == TRUE)
+ if (p_lcb && p_lcb->is_ble_link)
+ l2cb.controller_le_xmit_window += num_sent;
+ else
+#endif
+ {
+
+ /* Maintain the total window to the controller */
+ l2cb.controller_xmit_window += num_sent;
+ }
+
+ if (p_lcb)
+ {
+ /* If doing round-robin, adjust communal counts */
+ if (p_lcb->link_xmit_quota == 0)
+ {
+ /* Don't go negative */
+ if (l2cb.round_robin_unacked > num_sent)
+ l2cb.round_robin_unacked -= num_sent;
+ else
+ l2cb.round_robin_unacked = 0;
+ }
+
+ /* Don't go negative */
+ if (p_lcb->sent_not_acked > num_sent)
+ p_lcb->sent_not_acked -= num_sent;
+ else
+ p_lcb->sent_not_acked = 0;
+
+ l2c_link_check_send_pkts (p_lcb, NULL, NULL);
+
+ /* If we were doing round-robin for low priority links, check 'em */
+ if ( (p_lcb->acl_priority == L2CAP_PRIORITY_HIGH)
+ && (l2cb.check_round_robin)
+ && (l2cb.round_robin_unacked < l2cb.round_robin_quota) )
+ {
+ l2c_link_check_send_pkts (NULL, NULL, NULL);
+ }
+ }
+
+#if (L2CAP_HCI_FLOW_CONTROL_DEBUG == TRUE)
+ if (p_lcb)
+ {
+#if (BLE_INCLUDED == TRUE)
+ if (p_lcb->is_ble_link)
+ {
+ L2CAP_TRACE_DEBUG5 ("TotalWin=%d,LinkUnack(0x%x)=%d,RRCheck=%d,RRUnack=%d",
+ l2cb.controller_le_xmit_window,
+ p_lcb->handle, p_lcb->sent_not_acked,
+ l2cb.check_round_robin, l2cb.round_robin_unacked);
+ }
+ else
+#endif
+ {
+ L2CAP_TRACE_DEBUG5 ("TotalWin=%d,LinkUnack(0x%x)=%d,RRCheck=%d,RRUnack=%d",
+ l2cb.controller_xmit_window,
+ p_lcb->handle, p_lcb->sent_not_acked,
+ l2cb.check_round_robin, l2cb.round_robin_unacked);
+
+ }
+ }
+ else
+ {
+#if (BLE_INCLUDED == TRUE)
+ L2CAP_TRACE_DEBUG5 ("TotalWin=%d LE_Win: %d, Handle=0x%x, RRCheck=%d, RRUnack=%d",
+ l2cb.controller_xmit_window,
+ l2cb.controller_le_xmit_window,
+ handle,
+ l2cb.check_round_robin, l2cb.round_robin_unacked);
+#else
+ L2CAP_TRACE_DEBUG4 ("TotalWin=%d Handle=0x%x RRCheck=%d RRUnack=%d",
+ l2cb.controller_xmit_window,
+ handle,
+ l2cb.check_round_robin, l2cb.round_robin_unacked);
+#endif
+ }
+#endif
+ }
+
+#if (defined(HCILP_INCLUDED) && HCILP_INCLUDED == TRUE)
+ /* only full stack can enable sleep mode */
+ btu_check_bt_sleep ();
+#endif
+}
+
+/*******************************************************************************
+**
+** Function l2cap_link_chk_pkt_start
+**
+** Description This function is called from the HCI transport when the first
+** 4 bytes of an HCI ACL packet have been received. It checks if the
+** packet is the next segment of a fragmented L2CAP message. If it
+** is, and the length is OK, it returns the address of the
+** starting L2CAP message segment buffer.
+**
+** Returns the address of the receive buffer HCIT should use
+** (CR419: Modified to return NULL in case of error.)
+**
+** NOTE This assumes that the L2CAP MTU size is less than the size
+** of an HCI ACL buffer, so the maximum L2CAP message will fit
+** into one buffer.
+**
+*******************************************************************************/
+BT_HDR *l2cap_link_chk_pkt_start (BT_HDR *p_cur_buf)
+{
+ UINT8 *p;
+ UINT16 handle;
+ UINT16 hci_len;
+ UINT16 pkt_type;
+ tL2C_LCB *p_lcb;
+ BT_HDR * p_return_buf; /* CR419: To avoid returning from too many places */
+
+
+ if (p_cur_buf)
+ {
+ p = (UINT8 *)(p_cur_buf + 1) + p_cur_buf->offset;
+ }
+ else
+ {
+ return (NULL);
+ }
+
+ /* L2CAP expects all rcvd packets to have a layer-specific value of 0 */
+ p_cur_buf->layer_specific = 0;
+
+ STREAM_TO_UINT16 (handle, p);
+ STREAM_TO_UINT16 (hci_len, p);
+
+ pkt_type = HCID_GET_EVENT (handle);
+ handle = HCID_GET_HANDLE (handle);
+
+ l2cb.p_cur_hcit_lcb = NULL;
+
+ /* Find the link that is associated with this handle */
+ p_lcb = l2cu_find_lcb_by_handle (handle);
+
+ /* If no link for this handle, nothing to do. */
+ if (!p_lcb)
+ return (p_cur_buf) ;
+
+ if (pkt_type == L2CAP_PKT_START) /*** START PACKET ***/
+ {
+ /* Start of packet. If we were in the middle of receiving */
+ /* a packet, it is incomplete. Drop it. */
+ if (p_lcb->p_hcit_rcv_acl)
+ {
+ L2CAP_TRACE_WARNING0 ("L2CAP - dropping incomplete pkt");
+ GKI_freebuf (p_lcb->p_hcit_rcv_acl);
+ p_lcb->p_hcit_rcv_acl = NULL;
+ }
+
+ /* Save the active buffer address in the LCB */
+ if ((p_return_buf = p_cur_buf) != NULL)
+ {
+ p_lcb->p_hcit_rcv_acl = p_return_buf;
+ l2cb.p_cur_hcit_lcb = p_lcb;
+ }
+ }
+ else /*** CONTINUATION PACKET ***/
+ {
+ /* Packet continuation. Check if we were expecting it */
+ if (p_lcb->p_hcit_rcv_acl)
+ {
+ UINT16 total_len;
+ BT_HDR *p_base_buf = p_lcb->p_hcit_rcv_acl;
+ UINT8 *p_f = (UINT8 *)(p_base_buf + 1) + p_base_buf->offset + 2;
+
+ STREAM_TO_UINT16 (total_len, p_f);
+
+ /* We were expecting the CONTINUATION packet. If length fits, it can go in the */
+ /* current buffer. */
+ if ((total_len + hci_len) <= (L2CAP_MTU_SIZE + HCI_DATA_PREAMBLE_SIZE))
+ {
+ /* GKI_freebuf (p_cur_buf); CR419:Do not free it yet */
+ p_return_buf = p_lcb->p_hcit_rcv_acl; /* CR419: return base buffer */
+ l2cb.p_cur_hcit_lcb = p_lcb;
+
+ if ((p_cur_buf->len > HCI_DATA_PREAMBLE_SIZE))
+ {
+ UINT8 * p = (UINT8 *)(p_cur_buf + 1)
+ + p_cur_buf->offset
+ + HCI_DATA_PREAMBLE_SIZE;
+ UINT8 * p1 = (UINT8 *)(p_return_buf + 1)
+ + p_return_buf->offset
+ + p_return_buf->len;
+
+ /* Copy data from new buffer into base buffer then update the data */
+ /* count in the base buffer accordingly. */
+ memcpy (p1, p, p_cur_buf->len - HCI_DATA_PREAMBLE_SIZE);
+ p_return_buf->len += (p_cur_buf->len - HCI_DATA_PREAMBLE_SIZE);
+ }
+
+ GKI_freebuf (p_cur_buf);
+ p_cur_buf = NULL;
+
+ /* Update HCI header of first segment (base buffer) with new length */
+ total_len += hci_len;
+ p_f = (UINT8 *)(p_base_buf + 1) + p_base_buf->offset + 2;
+ UINT16_TO_STREAM (p_f, total_len);
+ }
+ else
+ {
+ /* Packet too long. Drop the base packet */
+ L2CAP_TRACE_WARNING3 ("L2CAP - dropping too long pkt BufLen: %d total_len: %d hci_len: %d",
+ p_lcb->p_hcit_rcv_acl->len, total_len, hci_len);
+
+ GKI_freebuf (p_lcb->p_hcit_rcv_acl);
+ p_lcb->p_hcit_rcv_acl = NULL;
+ p_return_buf = NULL ; /* Can't hold onto it any more */
+ }
+ }
+ else /*** NEITHER START OR CONTINUATION PACKET ***/
+ {
+ p_return_buf = NULL ;
+ }
+ }
+
+ if (p_return_buf == NULL) /* if error is indicated.. */
+ {
+ if (p_cur_buf != NULL) /* ..drop input buffer */
+ GKI_freebuf(p_cur_buf); /* (if present) */
+ }
+
+ return (p_return_buf);
+}
+
+/*******************************************************************************
+**
+** Function l2cap_link_chk_pkt_end
+**
+** Description This function is called from the HCI transport when the last
+** byte of an HCI ACL packet has been received. It checks if the
+** L2CAP message is complete, i.e. no more continuation packets
+** are expected.
+**
+** Returns TRUE if message complete, FALSE if continuation expected
+**
+*******************************************************************************/
+BOOLEAN l2cap_link_chk_pkt_end (void)
+{
+ UINT8 *p;
+ BT_HDR *p_buf;
+ UINT16 l2cap_len;
+ tL2C_LCB *p_lcb;
+
+ /* If link or buffer pointer not set up, let main line handle it */
+ if (((p_lcb = l2cb.p_cur_hcit_lcb) == NULL) || ((p_buf = p_lcb->p_hcit_rcv_acl) == NULL))
+ return (TRUE);
+
+ /* Point to the L2CAP length */
+ p = (UINT8 *)(p_buf + 1) + p_buf->offset + HCI_DATA_PREAMBLE_SIZE;
+
+ STREAM_TO_UINT16 (l2cap_len, p);
+
+ /* If the L2CAP length has not been reached, tell HCIT not to send this buffer to BTU */
+ if (l2cap_len > (p_buf->len - (HCI_DATA_PREAMBLE_SIZE + L2CAP_PKT_OVERHEAD)))
+ {
+ return (FALSE);
+ }
+ else
+ {
+ p_lcb->p_hcit_rcv_acl = NULL;
+ return (TRUE);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function l2c_link_segments_xmitted
+**
+** Description This function is called from the HCI Interface when an ACL
+** data packet segment is transmitted.
+**
+** Returns void
+**
+*******************************************************************************/
+void l2c_link_segments_xmitted (BT_HDR *p_msg)
+{
+ UINT8 *p = (UINT8 *)(p_msg + 1) + p_msg->offset;
+ UINT16 handle;
+ tL2C_LCB *p_lcb;
+
+ /* Extract the handle */
+ STREAM_TO_UINT16 (handle, p);
+ handle = HCID_GET_HANDLE (handle);
+
+ /* Find the LCB based on the handle */
+ if ((p_lcb = l2cu_find_lcb_by_handle (handle)) == NULL)
+ {
+ L2CAP_TRACE_WARNING1 ("L2CAP - rcvd segment complete, unknown handle: %d", handle);
+ GKI_freebuf (p_msg);
+ return;
+ }
+
+ if (p_lcb->link_state == LST_CONNECTED)
+ {
+ /* Enqueue the buffer to the head of the transmit queue, and see */
+ /* if we can transmit anything more. */
+ GKI_enqueue_head (&p_lcb->link_xmit_data_q, p_msg);
+
+ p_lcb->partial_segment_being_sent = FALSE;
+
+ l2c_link_check_send_pkts (p_lcb, NULL, NULL);
+ }
+ else
+ GKI_freebuf (p_msg);
+}
diff --git a/stack/l2cap/l2c_main.c b/stack/l2cap/l2c_main.c
new file mode 100644
index 0000000..17b9df1
--- /dev/null
+++ b/stack/l2cap/l2c_main.c
@@ -0,0 +1,979 @@
+/*****************************************************************************
+**
+** Name: l2c_main.c
+**
+** Description: This file contains the main L2CAP entry points
+**
+**
+**
+** Copyright (c) 1999-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+
+#include "bt_target.h"
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "gki.h"
+#include "hcimsgs.h"
+#include "l2cdefs.h"
+#include "l2c_int.h"
+#include "l2c_api.h"
+#include "btu.h"
+#include "btm_int.h"
+
+/********************************************************************************/
+/* L O C A L F U N C T I O N P R O T O T Y P E S */
+/********************************************************************************/
+static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len);
+
+/********************************************************************************/
+/* G L O B A L L 2 C A P D A T A */
+/********************************************************************************/
+#if L2C_DYNAMIC_MEMORY == FALSE
+tL2C_CB l2cb;
+#endif
+
+/* Temporary - until l2cap implements group management */
+#if (TCS_BCST_SETUP_INCLUDED == TRUE && TCS_INCLUDED == TRUE)
+extern void tcs_proc_bcst_msg( BD_ADDR addr, BT_HDR *p_msg ) ;
+
+/*******************************************************************************
+**
+** Function l2c_bcst_msg
+**
+** Description
+**
+** Returns void
+**
+*******************************************************************************/
+void l2c_bcst_msg( BT_HDR *p_buf, UINT16 psm )
+{
+ UINT8 *p;
+
+ /* Ensure we have enough space in the buffer for the L2CAP and HCI headers */
+ if (p_buf->offset < L2CAP_BCST_MIN_OFFSET)
+ {
+ L2CAP_TRACE_ERROR1 ("L2CAP - cannot send buffer, offset: %d", p_buf->offset);
+ GKI_freebuf (p_buf);
+ return;
+ }
+
+ /* Step back some bytes to add the headers */
+ p_buf->offset -= (HCI_DATA_PREAMBLE_SIZE + L2CAP_PKT_OVERHEAD + L2CAP_BCST_OVERHEAD);
+ p_buf->len += L2CAP_PKT_OVERHEAD + L2CAP_BCST_OVERHEAD;
+
+ /* Set the pointer to the beginning of the data */
+ p = (UINT8 *)(p_buf + 1) + p_buf->offset;
+
+ /* First, the HCI transport header */
+ UINT16_TO_STREAM (p, 0x0050 | (L2CAP_PKT_START << 12) | (2 << 14));
+
+ /* The HCI transport will segment the buffers. */
+ if (p_buf->len > btu_cb.hcit_acl_data_size)
+ {
+ UINT16_TO_STREAM (p, btu_cb.hcit_acl_data_size);
+ }
+ else
+ {
+ UINT16_TO_STREAM (p, p_buf->len);
+ }
+
+ /* Now the L2CAP header */
+ UINT16_TO_STREAM (p, p_buf->len - L2CAP_PKT_OVERHEAD);
+ UINT16_TO_STREAM (p, L2CAP_CONNECTIONLESS_CID);
+ UINT16_TO_STREAM (p, psm);
+
+ p_buf->len += HCI_DATA_PREAMBLE_SIZE;
+
+ if (p_buf->len <= btu_cb.hcit_acl_pkt_size)
+ {
+ HCI_ACL_DATA_TO_LOWER (p_buf);
+ }
+}
+#endif
+
+/*******************************************************************************
+**
+** Function l2c_rcv_acl_data
+**
+** Description This function is called from the HCI Interface when an ACL
+** data packet is received.
+**
+** Returns void
+**
+*******************************************************************************/
+void l2c_rcv_acl_data (BT_HDR *p_msg)
+{
+ UINT8 *p = (UINT8 *)(p_msg + 1) + p_msg->offset;
+ UINT16 handle, hci_len;
+ UINT8 pkt_type;
+ tL2C_LCB *p_lcb;
+ tL2C_CCB *p_ccb = NULL;
+ UINT16 l2cap_len, rcv_cid, psm;
+
+ /* Extract the handle */
+ STREAM_TO_UINT16 (handle, p);
+ pkt_type = HCID_GET_EVENT (handle);
+ handle = HCID_GET_HANDLE (handle);
+
+ /* Since the HCI Transport is putting segmented packets back together, we */
+ /* should never get a valid packet with the type set to "continuation" */
+ if (pkt_type != L2CAP_PKT_CONTINUE)
+ {
+ /* Find the LCB based on the handle */
+ if ((p_lcb = l2cu_find_lcb_by_handle (handle)) == NULL)
+ {
+ UINT8 cmd_code;
+
+ /* There is a slight possibility (specifically with USB) that we get an */
+ /* L2CAP connection request before we get the HCI connection complete. */
+ /* So for these types of messages, hold them for up to 2 seconds. */
+ STREAM_TO_UINT16 (hci_len, p);
+ STREAM_TO_UINT16 (l2cap_len, p);
+ STREAM_TO_UINT16 (rcv_cid, p);
+ STREAM_TO_UINT8 (cmd_code, p);
+
+ if ((p_msg->layer_specific == 0) && (rcv_cid == L2CAP_SIGNALLING_CID)
+ && (cmd_code == L2CAP_CMD_INFO_REQ || cmd_code == L2CAP_CMD_CONN_REQ))
+ {
+ L2CAP_TRACE_WARNING5 ("L2CAP - holding ACL for unknown handle:%d ls:%d cid:%d opcode:%d cur count:%d",
+ handle, p_msg->layer_specific, rcv_cid, cmd_code,
+ l2cb.rcv_hold_q.count);
+ p_msg->layer_specific = 2;
+ GKI_enqueue (&l2cb.rcv_hold_q, p_msg);
+
+ if (l2cb.rcv_hold_q.count == 1)
+ btu_start_timer (&l2cb.rcv_hold_tle, BTU_TTYPE_L2CAP_HOLD, BT_1SEC_TIMEOUT);
+
+ return;
+ }
+ else
+ {
+ L2CAP_TRACE_ERROR5 ("L2CAP - rcvd ACL for unknown handle:%d ls:%d cid:%d opcode:%d cur count:%d",
+ handle, p_msg->layer_specific, rcv_cid, cmd_code, l2cb.rcv_hold_q.count);
+ }
+ GKI_freebuf (p_msg);
+ return;
+ }
+ }
+ else
+ {
+ L2CAP_TRACE_WARNING1 ("L2CAP - expected pkt start or complete, got: %d", pkt_type);
+ GKI_freebuf (p_msg);
+ return;
+ }
+
+ /* Extract the length and update the buffer header */
+ STREAM_TO_UINT16 (hci_len, p);
+ p_msg->offset += 4;
+
+#if (L2CAP_HOST_FLOW_CTRL == TRUE)
+ /* Send ack if we hit the threshold */
+ if (++p_lcb->link_pkts_unacked >= p_lcb->link_ack_thresh)
+ btu_hcif_send_host_rdy_for_data();
+#endif
+
+ /* Extract the length and CID */
+ STREAM_TO_UINT16 (l2cap_len, p);
+ STREAM_TO_UINT16 (rcv_cid, p);
+
+ /* Find the CCB for this CID */
+ if (rcv_cid >= L2CAP_BASE_APPL_CID)
+ {
+ if ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, rcv_cid)) == NULL)
+ {
+ L2CAP_TRACE_WARNING1 ("L2CAP - unknown CID: 0x%04x", rcv_cid);
+ GKI_freebuf (p_msg);
+ return;
+ }
+ }
+
+ if (hci_len >= L2CAP_PKT_OVERHEAD) /* Must receive at least the L2CAP length and CID.*/
+ {
+ p_msg->len = hci_len - L2CAP_PKT_OVERHEAD;
+ p_msg->offset += L2CAP_PKT_OVERHEAD;
+ }
+ else
+ {
+ L2CAP_TRACE_WARNING0 ("L2CAP - got incorrect hci header" );
+ GKI_freebuf (p_msg);
+ return;
+ }
+
+ if (l2cap_len != p_msg->len)
+ {
+ L2CAP_TRACE_WARNING2 ("L2CAP - bad length in pkt. Exp: %d Act: %d",
+ l2cap_len, p_msg->len);
+
+ GKI_freebuf (p_msg);
+ return;
+ }
+
+ /* Send the data through the channel state machine */
+ if (rcv_cid == L2CAP_SIGNALLING_CID)
+ {
+ process_l2cap_cmd (p_lcb, p, l2cap_len);
+ GKI_freebuf (p_msg);
+ }
+ else if (rcv_cid == L2CAP_CONNECTIONLESS_CID)
+ {
+ /* process_connectionless_data (p_lcb); */
+ STREAM_TO_UINT16 (psm, p);
+ L2CAP_TRACE_DEBUG1( "GOT CONNECTIONLESS DATA PSM:%d", psm ) ;
+#if (TCS_BCST_SETUP_INCLUDED == TRUE && TCS_INCLUDED == TRUE)
+ if (psm == TCS_PSM_INTERCOM || psm == TCS_PSM_CORDLESS)
+ {
+ p_msg->offset += L2CAP_BCST_OVERHEAD;
+ p_msg->len -= L2CAP_BCST_OVERHEAD;
+ tcs_proc_bcst_msg( p_lcb->remote_bd_addr, p_msg ) ;
+ GKI_freebuf (p_msg);
+ }
+ else
+#endif
+
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ /* if it is not broadcast, check UCD registration */
+ if ( l2c_ucd_check_rx_pkts( p_lcb, p_msg ) )
+ {
+ /* nothing to do */
+ }
+ else
+#endif
+ GKI_freebuf (p_msg);
+ }
+#if (BLE_INCLUDED == TRUE)
+ else if (rcv_cid == L2CAP_BLE_SIGNALLING_CID)
+ {
+ l2cble_process_sig_cmd (p_lcb, p, l2cap_len);
+ GKI_freebuf (p_msg);
+ }
+#endif
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+ else if ((rcv_cid >= L2CAP_FIRST_FIXED_CHNL) && (rcv_cid <= L2CAP_LAST_FIXED_CHNL) &&
+ (l2cb.fixed_reg[rcv_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb != NULL) )
+ {
+ /* If no CCB for this channel, allocate one */
+ if (l2cu_initialize_fixed_ccb (p_lcb, rcv_cid, &l2cb.fixed_reg[rcv_cid - L2CAP_FIRST_FIXED_CHNL].fixed_chnl_opts))
+ {
+ p_ccb = p_lcb->p_fixed_ccbs[rcv_cid - L2CAP_FIRST_FIXED_CHNL];
+
+ if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE)
+ l2c_fcr_proc_pdu (p_ccb, p_msg);
+ else
+ (*l2cb.fixed_reg[rcv_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb)(p_lcb->remote_bd_addr, p_msg);
+ }
+ else
+ GKI_freebuf (p_msg);
+ }
+#endif
+
+ else
+ {
+ if (p_ccb == NULL)
+ GKI_freebuf (p_msg);
+ else
+ {
+ /* Basic mode packets go straight to the state machine */
+ if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_BASIC_MODE)
+ l2c_csm_execute (p_ccb, L2CEVT_L2CAP_DATA, p_msg);
+ else
+ {
+ /* eRTM or streaming mode, so we need to validate states first */
+ if ((p_ccb->chnl_state == CST_OPEN) || (p_ccb->chnl_state == CST_CONFIG))
+ l2c_fcr_proc_pdu (p_ccb, p_msg);
+ else
+ GKI_freebuf (p_msg);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function process_l2cap_cmd
+**
+** Description This function is called when a packet is received on the
+** L2CAP signalling CID
+**
+** Returns void
+**
+*******************************************************************************/
+static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
+{
+ UINT8 *p_pkt_end, *p_next_cmd, *p_cfg_end, *p_cfg_start;
+ UINT8 cmd_code, cfg_code, cfg_len, id;
+ tL2C_CONN_INFO con_info;
+ tL2CAP_CFG_INFO cfg_info;
+ UINT16 rej_reason, rej_mtu, lcid, rcid, info_type;
+ tL2C_CCB *p_ccb;
+ tL2C_RCB *p_rcb;
+ BOOLEAN cfg_rej;
+ UINT16 cfg_rej_len, cmd_len;
+ UINT16 result;
+ tL2C_CONN_INFO ci;
+
+#if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE)
+ /* if l2cap command received in CID 1 on top of an LE link, ignore this command */
+ if (p_lcb->is_ble_link)
+ return;
+#endif
+ p_next_cmd = p;
+ p_pkt_end = p + pkt_len;
+
+ memset (&cfg_info, 0, sizeof(cfg_info));
+
+ /* An L2CAP packet may contain multiple commands */
+ while (TRUE)
+ {
+ /* Smallest command is 4 bytes */
+ if ((p = p_next_cmd) > (p_pkt_end - 4))
+ break;
+
+ STREAM_TO_UINT8 (cmd_code, p);
+ STREAM_TO_UINT8 (id, p);
+ STREAM_TO_UINT16 (cmd_len, p);
+
+ /* Check command length does not exceed packet length */
+ if ((p_next_cmd = p + cmd_len) > p_pkt_end)
+ {
+ L2CAP_TRACE_WARNING3 ("Command len bad pkt_len: %d cmd_len: %d code: %d",
+ pkt_len, cmd_len, cmd_code);
+ break;
+ }
+
+ switch (cmd_code)
+ {
+ case L2CAP_CMD_REJECT:
+ STREAM_TO_UINT16 (rej_reason, p);
+ if (rej_reason == L2CAP_CMD_REJ_MTU_EXCEEDED)
+ {
+ STREAM_TO_UINT16 (rej_mtu, p);
+ /* What to do with the MTU reject ? We have negotiated an MTU. For now */
+ /* we will ignore it and let a higher protocol timeout take care of it */
+
+ L2CAP_TRACE_WARNING2 ("L2CAP - MTU rej Handle: %d MTU: %d", p_lcb->handle, rej_mtu);
+ }
+ if (rej_reason == L2CAP_CMD_REJ_INVALID_CID)
+ {
+ STREAM_TO_UINT16 (rcid, p);
+ STREAM_TO_UINT16 (lcid, p);
+
+ L2CAP_TRACE_WARNING2 ("L2CAP - rej with CID invalid, LCID: 0x%04x RCID: 0x%04x", lcid, rcid);
+
+ /* Remote CID invalid. Treat as a disconnect */
+ if (((p_ccb = l2cu_find_ccb_by_cid (p_lcb, lcid)) != NULL)
+ && (p_ccb->remote_cid == rcid))
+ {
+ /* Fake link disconnect - no reply is generated */
+ l2c_csm_execute (p_ccb, L2CEVT_LP_DISCONNECT_IND, NULL);
+ }
+ }
+
+ /* SonyEricsson Info request Bug workaround (Continue connection) */
+ else if (rej_reason == L2CAP_CMD_REJ_NOT_UNDERSTOOD && p_lcb->w4_info_rsp)
+ {
+ btu_stop_timer (&p_lcb->info_timer_entry);
+
+ p_lcb->w4_info_rsp = FALSE;
+ ci.status = HCI_SUCCESS;
+ memcpy (ci.bd_addr, p_lcb->remote_bd_addr, sizeof(BD_ADDR));
+
+ /* For all channels, send the event through their FSMs */
+ for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; p_ccb = p_ccb->p_next_ccb)
+ {
+ l2c_csm_execute (p_ccb, L2CEVT_L2CAP_INFO_RSP, &ci);
+ }
+ }
+ break;
+
+ case L2CAP_CMD_CONN_REQ:
+ STREAM_TO_UINT16 (con_info.psm, p);
+ STREAM_TO_UINT16 (rcid, p);
+ if ((p_rcb = l2cu_find_rcb_by_psm (con_info.psm)) == NULL)
+ {
+ L2CAP_TRACE_WARNING1 ("L2CAP - rcvd conn req for unknown PSM: %d", con_info.psm);
+ l2cu_reject_connection (p_lcb, rcid, id, L2CAP_CONN_NO_PSM);
+ break;
+ }
+ else
+ {
+ if (!p_rcb->api.pL2CA_ConnectInd_Cb)
+ {
+ L2CAP_TRACE_WARNING1 ("L2CAP - rcvd conn req for outgoing-only connection PSM: %d", con_info.psm);
+ l2cu_reject_connection (p_lcb, rcid, id, L2CAP_CONN_NO_PSM);
+ break;
+ }
+ }
+ if ((p_ccb = l2cu_allocate_ccb (p_lcb, 0)) == NULL)
+ {
+ L2CAP_TRACE_ERROR0 ("L2CAP - unable to allocate CCB");
+ l2cu_reject_connection (p_lcb, rcid, id, L2CAP_CONN_NO_RESOURCES);
+ break;
+ }
+ p_ccb->remote_id = id;
+ p_ccb->p_rcb = p_rcb;
+ p_ccb->remote_cid = rcid;
+
+ l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_REQ, &con_info);
+ break;
+
+ case L2CAP_CMD_CONN_RSP:
+ STREAM_TO_UINT16 (con_info.remote_cid, p);
+ STREAM_TO_UINT16 (lcid, p);
+ STREAM_TO_UINT16 (con_info.l2cap_result, p);
+ STREAM_TO_UINT16 (con_info.l2cap_status, p);
+
+ if ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, lcid)) == NULL)
+ {
+ L2CAP_TRACE_WARNING2 ("L2CAP - no CCB for conn rsp, LCID: %d RCID: %d",
+ lcid, con_info.remote_cid);
+ break;
+ }
+ if (p_ccb->local_id != id)
+ {
+ L2CAP_TRACE_WARNING2 ("L2CAP - con rsp - bad ID. Exp: %d Got: %d",
+ p_ccb->local_id, id);
+ break;
+ }
+
+ if (con_info.l2cap_result == L2CAP_CONN_OK)
+ l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_RSP, &con_info);
+ else if (con_info.l2cap_result == L2CAP_CONN_PENDING)
+ l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_RSP_PND, &con_info);
+ else
+ l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_RSP_NEG, &con_info);
+
+ break;
+
+ case L2CAP_CMD_CONFIG_REQ:
+ p_cfg_end = p + cmd_len;
+ cfg_rej = FALSE;
+ cfg_rej_len = 0;
+
+ STREAM_TO_UINT16 (lcid, p);
+ STREAM_TO_UINT16 (cfg_info.flags, p);
+
+ p_cfg_start = p;
+
+ cfg_info.flush_to_present = cfg_info.mtu_present = cfg_info.qos_present =
+ cfg_info.fcr_present = cfg_info.fcs_present = FALSE;
+
+ while (p < p_cfg_end)
+ {
+ STREAM_TO_UINT8 (cfg_code, p);
+ STREAM_TO_UINT8 (cfg_len, p);
+
+ switch (cfg_code & 0x7F)
+ {
+ case L2CAP_CFG_TYPE_MTU:
+ cfg_info.mtu_present = TRUE;
+ STREAM_TO_UINT16 (cfg_info.mtu, p);
+ break;
+
+ case L2CAP_CFG_TYPE_FLUSH_TOUT:
+ cfg_info.flush_to_present = TRUE;
+ STREAM_TO_UINT16 (cfg_info.flush_to, p);
+ break;
+
+ case L2CAP_CFG_TYPE_QOS:
+ cfg_info.qos_present = TRUE;
+ STREAM_TO_UINT8 (cfg_info.qos.qos_flags, p);
+ STREAM_TO_UINT8 (cfg_info.qos.service_type, p);
+ STREAM_TO_UINT32 (cfg_info.qos.token_rate, p);
+ STREAM_TO_UINT32 (cfg_info.qos.token_bucket_size, p);
+ STREAM_TO_UINT32 (cfg_info.qos.peak_bandwidth, p);
+ STREAM_TO_UINT32 (cfg_info.qos.latency, p);
+ STREAM_TO_UINT32 (cfg_info.qos.delay_variation, p);
+ break;
+
+ case L2CAP_CFG_TYPE_FCR:
+ cfg_info.fcr_present = TRUE;
+ STREAM_TO_UINT8 (cfg_info.fcr.mode, p);
+ STREAM_TO_UINT8 (cfg_info.fcr.tx_win_sz, p);
+ STREAM_TO_UINT8 (cfg_info.fcr.max_transmit, p);
+ STREAM_TO_UINT16 (cfg_info.fcr.rtrans_tout, p);
+ STREAM_TO_UINT16 (cfg_info.fcr.mon_tout, p);
+ STREAM_TO_UINT16 (cfg_info.fcr.mps, p);
+ break;
+
+ case L2CAP_CFG_TYPE_FCS:
+ cfg_info.fcs_present = TRUE;
+ STREAM_TO_UINT8 (cfg_info.fcs, p);
+ break;
+
+ case L2CAP_CFG_TYPE_EXT_FLOW:
+ cfg_info.ext_flow_spec_present = TRUE;
+ STREAM_TO_UINT8 (cfg_info.ext_flow_spec.id, p);
+ STREAM_TO_UINT8 (cfg_info.ext_flow_spec.stype, p);
+ STREAM_TO_UINT16 (cfg_info.ext_flow_spec.max_sdu_size, p);
+ STREAM_TO_UINT32 (cfg_info.ext_flow_spec.sdu_inter_time, p);
+ STREAM_TO_UINT32 (cfg_info.ext_flow_spec.access_latency, p);
+ STREAM_TO_UINT32 (cfg_info.ext_flow_spec.flush_timeout, p);
+ break;
+
+ default:
+ /* sanity check option length */
+ if ((cfg_len + L2CAP_CFG_OPTION_OVERHEAD) <= cmd_len)
+ {
+ p += cfg_len;
+ if ((cfg_code & 0x80) == 0)
+ {
+ cfg_rej_len += cfg_len + L2CAP_CFG_OPTION_OVERHEAD;
+ cfg_rej = TRUE;
+ }
+ }
+ /* bad length; force loop exit */
+ else
+ {
+ p = p_cfg_end;
+ cfg_rej = TRUE;
+ }
+ break;
+ }
+ }
+
+ if ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, lcid)) != NULL)
+ {
+ p_ccb->remote_id = id;
+ if (cfg_rej)
+ {
+ l2cu_send_peer_config_rej (p_ccb, p_cfg_start, (UINT16) (cmd_len - L2CAP_CONFIG_REQ_LEN), cfg_rej_len);
+ }
+ else
+ {
+ l2c_csm_execute (p_ccb, L2CEVT_L2CAP_CONFIG_REQ, &cfg_info);
+ }
+ }
+ else
+ {
+ /* updated spec says send command reject on invalid cid */
+ l2cu_send_peer_cmd_reject (p_lcb, L2CAP_CMD_REJ_INVALID_CID, id, 0, 0);
+ }
+ break;
+
+ case L2CAP_CMD_CONFIG_RSP:
+ p_cfg_end = p + cmd_len;
+ STREAM_TO_UINT16 (lcid, p);
+ STREAM_TO_UINT16 (cfg_info.flags, p);
+ STREAM_TO_UINT16 (cfg_info.result, p);
+
+ cfg_info.flush_to_present = cfg_info.mtu_present = cfg_info.qos_present =
+ cfg_info.fcr_present = cfg_info.fcs_present = FALSE;
+
+ while (p < p_cfg_end)
+ {
+ STREAM_TO_UINT8 (cfg_code, p);
+ STREAM_TO_UINT8 (cfg_len, p);
+
+ switch (cfg_code & 0x7F)
+ {
+ case L2CAP_CFG_TYPE_MTU:
+ cfg_info.mtu_present = TRUE;
+ STREAM_TO_UINT16 (cfg_info.mtu, p);
+ break;
+
+ case L2CAP_CFG_TYPE_FLUSH_TOUT:
+ cfg_info.flush_to_present = TRUE;
+ STREAM_TO_UINT16 (cfg_info.flush_to, p);
+ break;
+
+ case L2CAP_CFG_TYPE_QOS:
+ cfg_info.qos_present = TRUE;
+ STREAM_TO_UINT8 (cfg_info.qos.qos_flags, p);
+ STREAM_TO_UINT8 (cfg_info.qos.service_type, p);
+ STREAM_TO_UINT32 (cfg_info.qos.token_rate, p);
+ STREAM_TO_UINT32 (cfg_info.qos.token_bucket_size, p);
+ STREAM_TO_UINT32 (cfg_info.qos.peak_bandwidth, p);
+ STREAM_TO_UINT32 (cfg_info.qos.latency, p);
+ STREAM_TO_UINT32 (cfg_info.qos.delay_variation, p);
+ break;
+
+ case L2CAP_CFG_TYPE_FCR:
+ cfg_info.fcr_present = TRUE;
+ STREAM_TO_UINT8 (cfg_info.fcr.mode, p);
+ STREAM_TO_UINT8 (cfg_info.fcr.tx_win_sz, p);
+ STREAM_TO_UINT8 (cfg_info.fcr.max_transmit, p);
+ STREAM_TO_UINT16 (cfg_info.fcr.rtrans_tout, p);
+ STREAM_TO_UINT16 (cfg_info.fcr.mon_tout, p);
+ STREAM_TO_UINT16 (cfg_info.fcr.mps, p);
+ break;
+
+ case L2CAP_CFG_TYPE_FCS:
+ cfg_info.fcs_present = TRUE;
+ STREAM_TO_UINT8 (cfg_info.fcs, p);
+ break;
+
+ case L2CAP_CFG_TYPE_EXT_FLOW:
+ cfg_info.ext_flow_spec_present = TRUE;
+ STREAM_TO_UINT8 (cfg_info.ext_flow_spec.id, p);
+ STREAM_TO_UINT8 (cfg_info.ext_flow_spec.stype, p);
+ STREAM_TO_UINT16 (cfg_info.ext_flow_spec.max_sdu_size, p);
+ STREAM_TO_UINT32 (cfg_info.ext_flow_spec.sdu_inter_time, p);
+ STREAM_TO_UINT32 (cfg_info.ext_flow_spec.access_latency, p);
+ STREAM_TO_UINT32 (cfg_info.ext_flow_spec.flush_timeout, p);
+ break;
+ }
+ }
+
+ if ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, lcid)) != NULL)
+ {
+ if (p_ccb->local_id != id)
+ {
+ L2CAP_TRACE_WARNING2 ("L2CAP - cfg rsp - bad ID. Exp: %d Got: %d",
+ p_ccb->local_id, id);
+ break;
+ }
+ if ( (cfg_info.result == L2CAP_CFG_OK) || (cfg_info.result == L2CAP_CFG_PENDING) )
+ l2c_csm_execute (p_ccb, L2CEVT_L2CAP_CONFIG_RSP, &cfg_info);
+ else
+ l2c_csm_execute (p_ccb, L2CEVT_L2CAP_CONFIG_RSP_NEG, &cfg_info);
+ }
+ else
+ {
+ L2CAP_TRACE_WARNING1 ("L2CAP - rcvd cfg rsp for unknown CID: 0x%04x", lcid);
+ }
+ break;
+
+
+ case L2CAP_CMD_DISC_REQ:
+ STREAM_TO_UINT16 (lcid, p);
+ STREAM_TO_UINT16 (rcid, p);
+
+ if ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, lcid)) != NULL)
+ {
+ if (p_ccb->remote_cid == rcid)
+ {
+ p_ccb->remote_id = id;
+ l2c_csm_execute (p_ccb, L2CEVT_L2CAP_DISCONNECT_REQ, &con_info);
+ }
+ }
+ else
+ l2cu_send_peer_disc_rsp (p_lcb, id, lcid, rcid);
+
+ break;
+
+ case L2CAP_CMD_DISC_RSP:
+ STREAM_TO_UINT16 (rcid, p);
+ STREAM_TO_UINT16 (lcid, p);
+
+ if ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, lcid)) != NULL)
+ {
+ if ((p_ccb->remote_cid == rcid) && (p_ccb->local_id == id))
+ {
+ l2c_csm_execute (p_ccb, L2CEVT_L2CAP_DISCONNECT_RSP, &con_info);
+ }
+ }
+ break;
+
+ case L2CAP_CMD_ECHO_REQ:
+
+#if (L2CAP_ENHANCED_FEATURES != 0)
+ if (!l2cu_check_feature_req (p_lcb, id, p, cmd_len))
+ {
+ if (cmd_len < (btu_cb.hcit_acl_pkt_size - L2CAP_PKT_OVERHEAD
+ - L2CAP_CMD_OVERHEAD
+ - L2CAP_ECHO_RSP_LEN
+ - HCI_DATA_PREAMBLE_SIZE))
+ {
+ l2cu_send_peer_echo_rsp (p_lcb, id, p, cmd_len);
+ }
+ else
+ {
+ l2cu_send_peer_echo_rsp (p_lcb, id, NULL, 0);
+ }
+ }
+#else
+ l2cu_send_peer_echo_rsp (p_lcb, id, NULL, 0);
+#endif
+ break;
+
+ case L2CAP_CMD_ECHO_RSP:
+#if (L2CAP_ENHANCED_FEATURES != 0)
+ l2cu_check_feature_rsp (p_lcb, id, p, cmd_len);
+#endif
+ if (p_lcb->p_echo_rsp_cb)
+ {
+ tL2CA_ECHO_RSP_CB *p_cb = p_lcb->p_echo_rsp_cb;
+
+ /* Zero out the callback in case app immediately calls us again */
+ p_lcb->p_echo_rsp_cb = NULL;
+
+ (*p_cb) (L2CAP_PING_RESULT_OK);
+ }
+ break;
+
+ case L2CAP_CMD_INFO_REQ:
+ STREAM_TO_UINT16 (info_type, p);
+ l2cu_send_peer_info_rsp (p_lcb, id, info_type);
+ break;
+
+ case L2CAP_CMD_INFO_RSP:
+ /* Stop the link connect timer if sent before L2CAP connection is up */
+ if (p_lcb->w4_info_rsp)
+ {
+ btu_stop_timer (&p_lcb->info_timer_entry);
+ p_lcb->w4_info_rsp = FALSE;
+ }
+
+ STREAM_TO_UINT16 (info_type, p);
+ STREAM_TO_UINT16 (result, p);
+
+ p_lcb->info_rx_bits |= (1 << info_type);
+
+ if ( (info_type == L2CAP_EXTENDED_FEATURES_INFO_TYPE)
+ && (result == L2CAP_INFO_RESP_RESULT_SUCCESS) )
+ {
+ STREAM_TO_UINT32( p_lcb->peer_ext_fea, p );
+
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+ if (p_lcb->peer_ext_fea & L2CAP_EXTFEA_FIXED_CHNLS)
+ {
+ l2cu_send_peer_info_req (p_lcb, L2CAP_FIXED_CHANNELS_INFO_TYPE);
+ break;
+ }
+ else
+ {
+ l2cu_process_fixed_chnl_resp (p_lcb);
+ }
+#endif
+ }
+
+
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+ if (info_type == L2CAP_FIXED_CHANNELS_INFO_TYPE)
+ {
+ if (result == L2CAP_INFO_RESP_RESULT_SUCCESS)
+ {
+ memcpy (p_lcb->peer_chnl_mask, p, L2CAP_FIXED_CHNL_ARRAY_SIZE);
+ }
+
+ l2cu_process_fixed_chnl_resp (p_lcb);
+ }
+#endif
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ else if (info_type == L2CAP_CONNLESS_MTU_INFO_TYPE)
+ {
+ if (result == L2CAP_INFO_RESP_RESULT_SUCCESS)
+ {
+ STREAM_TO_UINT16 (p_lcb->ucd_mtu, p);
+ }
+ }
+#endif
+
+ ci.status = HCI_SUCCESS;
+ memcpy (ci.bd_addr, p_lcb->remote_bd_addr, sizeof(BD_ADDR));
+ for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; p_ccb = p_ccb->p_next_ccb)
+ {
+ l2c_csm_execute (p_ccb, L2CEVT_L2CAP_INFO_RSP, &ci);
+ }
+ break;
+
+ default:
+ L2CAP_TRACE_WARNING1 ("L2CAP - bad cmd code: %d", cmd_code);
+ l2cu_send_peer_cmd_reject (p_lcb, L2CAP_CMD_REJ_NOT_UNDERSTOOD, id, 0, 0);
+ return;
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function l2c_process_held_packets
+**
+** Description This function processes any L2CAP packets that arrived before
+** the HCI connection complete arrived. It is a work around for
+** badly behaved controllers.
+**
+** Returns void
+**
+*******************************************************************************/
+void l2c_process_held_packets (BOOLEAN timed_out)
+{
+ BT_HDR *p_buf, *p_buf1;
+ BUFFER_Q *p_rcv_hold_q = &l2cb.rcv_hold_q;
+
+ if (!p_rcv_hold_q->count)
+ return;
+
+ if (!timed_out)
+ {
+ btu_stop_timer(&l2cb.rcv_hold_tle);
+ L2CAP_TRACE_WARNING0("L2CAP HOLD CONTINUE");
+ }
+ else
+ {
+ L2CAP_TRACE_WARNING0("L2CAP HOLD TIMEOUT");
+ }
+
+ /* Update the timeouts in the hold queue */
+ for (p_buf = (BT_HDR *)GKI_getfirst (p_rcv_hold_q); p_buf; p_buf = p_buf1)
+ {
+ p_buf1 = (BT_HDR *)GKI_getnext (p_buf);
+ if (!timed_out || (!p_buf->layer_specific) || (--p_buf->layer_specific == 0))
+ {
+ GKI_remove_from_queue (p_rcv_hold_q, p_buf);
+ p_buf->layer_specific = 0xFFFF;
+ l2c_rcv_acl_data (p_buf);
+ }
+ }
+
+ /* If anyone still in the queue, restart the timeout */
+ if (p_rcv_hold_q->count)
+ btu_start_timer (&l2cb.rcv_hold_tle, BTU_TTYPE_L2CAP_HOLD, BT_1SEC_TIMEOUT);
+}
+
+
+/*******************************************************************************
+**
+** Function l2c_init
+**
+** Description This function is called once at startup to initialize
+** all the L2CAP structures
+**
+** Returns void
+**
+*******************************************************************************/
+void l2c_init (void)
+{
+ INT16 xx;
+
+ memset (&l2cb, 0, sizeof (tL2C_CB));
+ /* the psm is increased by 2 before being used */
+ l2cb.dyn_psm = 0xFFF;
+
+ /* Put all the channel control blocks on the free queue */
+ for (xx = 0; xx < MAX_L2CAP_CHANNELS - 1; xx++)
+ {
+ l2cb.ccb_pool[xx].p_next_ccb = &l2cb.ccb_pool[xx + 1];
+ }
+
+#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
+ /* it will be set to L2CAP_PKT_START_NON_FLUSHABLE if controller supports */
+ l2cb.non_flushable_pbf = L2CAP_PKT_START << L2CAP_PKT_TYPE_SHIFT;
+#endif
+
+
+ l2cb.p_free_ccb_first = &l2cb.ccb_pool[0];
+ l2cb.p_free_ccb_last = &l2cb.ccb_pool[MAX_L2CAP_CHANNELS - 1];
+
+#ifdef L2CAP_DESIRED_LINK_ROLE
+ l2cb.desire_role = L2CAP_DESIRED_LINK_ROLE;
+#else
+ l2cb.desire_role = HCI_ROLE_SLAVE;
+#endif
+
+ /* Set the default idle timeout */
+ l2cb.idle_timeout = L2CAP_LINK_INACTIVITY_TOUT;
+
+#if defined(L2CAP_INITIAL_TRACE_LEVEL)
+ l2cb.l2cap_trace_level = L2CAP_INITIAL_TRACE_LEVEL;
+#else
+ l2cb.l2cap_trace_level = BT_TRACE_LEVEL_NONE; /* No traces */
+#endif
+
+#if L2CAP_CONFORMANCE_TESTING == TRUE
+ /* Conformance testing needs a dynamic response */
+ l2cb.test_info_resp = L2CAP_EXTFEA_SUPPORTED_MASK;
+#endif
+
+ /* Number of ACL buffers to use for high priority channel */
+#if (defined(L2CAP_HIGH_PRI_CHAN_QUOTA_IS_CONFIGURABLE) && (L2CAP_HIGH_PRI_CHAN_QUOTA_IS_CONFIGURABLE == TRUE))
+ l2cb.high_pri_min_xmit_quota = L2CAP_HIGH_PRI_MIN_XMIT_QUOTA;
+#endif
+
+}
+
+/*******************************************************************************
+**
+** Function l2c_process_timeout
+**
+** Description This function is called when an L2CAP-related timeout occurs
+**
+** Returns void
+**
+*******************************************************************************/
+void l2c_process_timeout (TIMER_LIST_ENT *p_tle)
+{
+ /* What type of timeout ? */
+ switch (p_tle->event)
+ {
+ case BTU_TTYPE_L2CAP_LINK:
+ l2c_link_timeout ((tL2C_LCB *)p_tle->param);
+ break;
+
+ case BTU_TTYPE_L2CAP_CHNL:
+ l2c_csm_execute (((tL2C_CCB *)p_tle->param), L2CEVT_TIMEOUT, NULL);
+ break;
+
+ case BTU_TTYPE_L2CAP_FCR_ACK:
+ l2c_csm_execute (((tL2C_CCB *)p_tle->param), L2CEVT_ACK_TIMEOUT, NULL);
+ break;
+
+ case BTU_TTYPE_L2CAP_HOLD:
+ /* Update the timeouts in the hold queue */
+ l2c_process_held_packets(TRUE);
+ break;
+
+ case BTU_TTYPE_L2CAP_INFO:
+ l2c_info_timeout((tL2C_LCB *)p_tle->param);
+ break;
+
+ }
+}
+
+/*******************************************************************************
+**
+** Function l2c_data_write
+**
+** Description API functions call this function to write data.
+**
+** Returns L2CAP_DW_SUCCESS, if data accepted, else FALSE
+** L2CAP_DW_CONGESTED, if data accepted and the channel is congested
+** L2CAP_DW_FAILED, if error
+**
+*******************************************************************************/
+UINT8 l2c_data_write (UINT16 cid, BT_HDR *p_data, UINT16 flags)
+{
+ tL2C_CCB *p_ccb;
+
+ /* Find the channel control block. We don't know the link it is on. */
+ if ((p_ccb = l2cu_find_ccb_by_cid (NULL, cid)) == NULL)
+ {
+ L2CAP_TRACE_WARNING1 ("L2CAP - no CCB for L2CA_DataWrite, CID: %d", cid);
+ GKI_freebuf (p_data);
+ return (L2CAP_DW_FAILED);
+ }
+
+#ifndef TESTER /* Tester may send any amount of data. otherwise sending message
+ bigger than mtu size of peer is a violation of protocol */
+ if (p_data->len > p_ccb->peer_cfg.mtu)
+ {
+ L2CAP_TRACE_WARNING1 ("L2CAP - CID: 0x%04x cannot send message bigger than peer's mtu size", cid);
+ GKI_freebuf (p_data);
+ return (L2CAP_DW_FAILED);
+ }
+#endif
+
+ /* channel based, packet based flushable or non-flushable */
+ p_data->layer_specific = flags;
+
+ /* If already congested, do not accept any more packets */
+ if (p_ccb->cong_sent)
+ {
+ L2CAP_TRACE_ERROR3 ("L2CAP - CID: 0x%04x cannot send, already congested xmit_hold_q.count: %u buff_quota: %u",
+ p_ccb->local_cid, p_ccb->xmit_hold_q.count, p_ccb->buff_quota);
+
+ GKI_freebuf (p_data);
+ return (L2CAP_DW_FAILED);
+ }
+
+ l2c_csm_execute (p_ccb, L2CEVT_L2CA_DATA_WRITE, p_data);
+
+ if (p_ccb->cong_sent)
+ return (L2CAP_DW_CONGESTED);
+
+ return (L2CAP_DW_SUCCESS);
+}
+
diff --git a/stack/l2cap/l2c_ucd.c b/stack/l2cap/l2c_ucd.c
new file mode 100644
index 0000000..375988e
--- /dev/null
+++ b/stack/l2cap/l2c_ucd.c
@@ -0,0 +1,1158 @@
+/*****************************************************************************
+**
+** Name: l2c_ucd.c
+**
+** Description: This file contains the L2CAP UCD code
+**
+**
+**
+** Copyright (c) 1999-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "gki.h"
+#include "bt_types.h"
+#include "hcidefs.h"
+#include "hcimsgs.h"
+#include "l2cdefs.h"
+#include "l2c_int.h"
+#include "btu.h"
+#include "btm_api.h"
+#include "btm_int.h"
+
+#if (L2CAP_UCD_INCLUDED == TRUE)
+static BOOLEAN l2c_ucd_connect ( BD_ADDR rem_bda );
+
+/*******************************************************************************
+**
+** Function l2c_ucd_discover_cback
+**
+** Description UCD Discover callback
+**
+** Returns void
+**
+*******************************************************************************/
+static void l2c_ucd_discover_cback (BD_ADDR rem_bda, UINT8 info_type, UINT32 data)
+{
+ tL2C_RCB *p_rcb = &l2cb.rcb_pool[0];
+ UINT16 xx;
+
+ L2CAP_TRACE_DEBUG0 ("L2CAP - l2c_ucd_discover_cback");
+
+ for (xx = 0; xx < MAX_L2CAP_CLIENTS; xx++, p_rcb++)
+ {
+ if (p_rcb->in_use)
+ {
+ /* if this application is waiting UCD reception info */
+ if (( info_type == L2CAP_UCD_INFO_TYPE_RECEPTION )
+ && ( p_rcb->ucd.state & L2C_UCD_STATE_W4_RECEPTION ))
+ {
+ p_rcb->ucd.cb_info.pL2CA_UCD_Discover_Cb (rem_bda, info_type, data);
+ p_rcb->ucd.state &= ~(L2C_UCD_STATE_W4_RECEPTION);
+ }
+
+ /* if this application is waiting UCD MTU info */
+ if (( info_type == L2CAP_UCD_INFO_TYPE_MTU )
+ && ( p_rcb->ucd.state & L2C_UCD_STATE_W4_MTU ))
+ {
+ p_rcb->ucd.cb_info.pL2CA_UCD_Discover_Cb (rem_bda, info_type, data);
+ p_rcb->ucd.state &= ~(L2C_UCD_STATE_W4_MTU);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function l2c_ucd_data_ind_cback
+**
+** Description UCD Data callback
+**
+** Returns void
+**
+*******************************************************************************/
+static void l2c_ucd_data_ind_cback (BD_ADDR rem_bda, BT_HDR *p_buf)
+{
+ UINT8 *p;
+ UINT16 psm;
+ tL2C_RCB *p_rcb;
+
+ L2CAP_TRACE_DEBUG0 ("L2CAP - l2c_ucd_data_ind_cback");
+
+ p = (UINT8 *)(p_buf + 1) + p_buf->offset;
+ STREAM_TO_UINT16(psm, p)
+
+ p_buf->offset += L2CAP_UCD_OVERHEAD;
+ p_buf->len -= L2CAP_UCD_OVERHEAD;
+
+ if ((p_rcb = l2cu_find_rcb_by_psm (psm)) == NULL)
+ {
+ L2CAP_TRACE_ERROR1 ("L2CAP - no RCB for l2c_ucd_data_ind_cback, PSM: 0x%04x", psm);
+ GKI_freebuf (p_buf);
+ }
+ else
+ {
+ p_rcb->ucd.cb_info.pL2CA_UCD_Data_Cb(rem_bda, p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function l2c_ucd_congestion_status_cback
+**
+** Description UCD Congestion Status callback
+**
+** Returns void
+**
+*******************************************************************************/
+static void l2c_ucd_congestion_status_cback (BD_ADDR rem_bda, BOOLEAN is_congested)
+{
+ tL2C_RCB *p_rcb = &l2cb.rcb_pool[0];
+ UINT16 xx;
+
+ L2CAP_TRACE_DEBUG0 ("L2CAP - l2c_ucd_congestion_status_cback");
+
+ for (xx = 0; xx < MAX_L2CAP_CLIENTS; xx++, p_rcb++)
+ {
+ if (( p_rcb->in_use )
+ &&( p_rcb->ucd.state != L2C_UCD_STATE_UNUSED ))
+ {
+ if ( p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb )
+ {
+ L2CAP_TRACE_DEBUG4 ("L2CAP - Calling UCDCongestionStatus_Cb (%d), PSM=0x%04x, BDA: %08x%04x,",
+ is_congested, p_rcb->psm,
+ (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3],
+ (rem_bda[4]<<8)+rem_bda[5]);
+
+ p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb ( rem_bda, is_congested );
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function l2c_ucd_disconnect_ind_cback
+**
+** Description UCD disconnect callback (This prevent to access null pointer)
+**
+** Returns void
+**
+*******************************************************************************/
+static void l2c_ucd_disconnect_ind_cback (UINT16 cid, BOOLEAN result)
+{
+ /* do nothing */
+}
+
+/*******************************************************************************
+**
+** Function l2c_ucd_config_ind_cback
+**
+** Description UCD config callback (This prevent to access null pointer)
+**
+** Returns void
+**
+*******************************************************************************/
+static void l2c_ucd_config_ind_cback (UINT16 cid, tL2CAP_CFG_INFO *p_cfg)
+{
+ /* do nothing */
+}
+
+/*******************************************************************************
+**
+** Function l2c_ucd_config_cfm_cback
+**
+** Description UCD config callback (This prevent to access null pointer)
+**
+** Returns void
+**
+*******************************************************************************/
+static void l2c_ucd_config_cfm_cback (UINT16 cid, tL2CAP_CFG_INFO *p_cfg)
+{
+ /* do nothing */
+}
+
+/*******************************************************************************
+**
+** Function L2CA_UcdRegister
+**
+** Description Register PSM on UCD.
+**
+** Parameters: tL2CAP_UCD_CB_INFO
+**
+** Return value: TRUE if successs
+**
+*******************************************************************************/
+BOOLEAN L2CA_UcdRegister ( UINT16 psm, tL2CAP_UCD_CB_INFO *p_cb_info )
+{
+ tL2C_RCB *p_rcb;
+
+ L2CAP_TRACE_API1 ("L2CA_UcdRegister() PSM: 0x%04x", psm);
+
+ if ((!p_cb_info->pL2CA_UCD_Discover_Cb)
+ || (!p_cb_info->pL2CA_UCD_Data_Cb))
+ {
+ L2CAP_TRACE_ERROR1 ("L2CAP - no callback registering PSM(0x%04x) on UCD", psm);
+ return (FALSE);
+ }
+
+ if ((p_rcb = l2cu_find_rcb_by_psm (psm)) == NULL)
+ {
+ L2CAP_TRACE_ERROR1 ("L2CAP - no RCB for L2CA_UcdRegister, PSM: 0x%04x", psm);
+ return (FALSE);
+ }
+
+ p_rcb->ucd.state = L2C_UCD_STATE_W4_DATA;
+ p_rcb->ucd.cb_info = *p_cb_info;
+
+ /* check if master rcb is created for UCD */
+ if ((p_rcb = l2cu_find_rcb_by_psm (L2C_UCD_RCB_ID)) == NULL)
+ {
+ if ((p_rcb = l2cu_allocate_rcb (L2C_UCD_RCB_ID)) == NULL)
+ {
+ L2CAP_TRACE_ERROR0 ("L2CAP - no RCB available for L2CA_UcdRegister");
+ return (FALSE);
+ }
+ else
+ {
+ /* these callback functions will forward data to each UCD application */
+ p_rcb->ucd.cb_info.pL2CA_UCD_Discover_Cb = l2c_ucd_discover_cback;
+ p_rcb->ucd.cb_info.pL2CA_UCD_Data_Cb = l2c_ucd_data_ind_cback;
+ p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb = l2c_ucd_congestion_status_cback;
+
+ memset (&p_rcb->api, 0, sizeof(tL2CAP_APPL_INFO));
+ p_rcb->api.pL2CA_DisconnectInd_Cb = l2c_ucd_disconnect_ind_cback;
+
+ /* This will make L2CAP check UCD congestion callback */
+ p_rcb->api.pL2CA_CongestionStatus_Cb = NULL;
+
+ /* do nothing but prevent crash */
+ p_rcb->api.pL2CA_ConfigInd_Cb = l2c_ucd_config_ind_cback;
+ p_rcb->api.pL2CA_ConfigCfm_Cb = l2c_ucd_config_cfm_cback;
+ }
+ }
+
+ return (TRUE);
+}
+
+/*******************************************************************************
+**
+** Function L2CA_UcdDeregister
+**
+** Description Deregister PSM on UCD.
+**
+** Parameters: PSM
+**
+** Return value: TRUE if successs
+**
+*******************************************************************************/
+BOOLEAN L2CA_UcdDeregister ( UINT16 psm )
+{
+ tL2C_CCB *p_ccb;
+ tL2C_RCB *p_rcb;
+ UINT16 xx;
+
+ L2CAP_TRACE_API1 ("L2CA_UcdDeregister() PSM: 0x%04x", psm);
+
+ if ((p_rcb = l2cu_find_rcb_by_psm (psm)) == NULL)
+ {
+ L2CAP_TRACE_ERROR1 ("L2CAP - no RCB for L2CA_UcdDeregister, PSM: 0x%04x", psm);
+ return (FALSE);
+ }
+
+ p_rcb->ucd.state = L2C_UCD_STATE_UNUSED;
+
+ /* check this was the last UCD registration */
+ p_rcb = &l2cb.rcb_pool[0];
+
+ for (xx = 0; xx < MAX_L2CAP_CLIENTS; xx++, p_rcb++)
+ {
+ if ((p_rcb->in_use) && (p_rcb->ucd.state != L2C_UCD_STATE_UNUSED))
+ return (TRUE);
+ }
+
+ /* delete master rcb for UCD */
+ if ((p_rcb = l2cu_find_rcb_by_psm (L2C_UCD_RCB_ID)) != NULL)
+ {
+ l2cu_release_rcb (p_rcb);
+ }
+
+ /* delete CCB for UCD */
+ p_ccb = l2cb.ccb_pool;
+ for ( xx = 0; xx < MAX_L2CAP_CHANNELS; xx++ )
+ {
+ if (( p_ccb->in_use )
+ &&( p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID ))
+ {
+ l2cu_release_ccb (p_ccb);
+ }
+ p_ccb++;
+ }
+
+ return (TRUE);
+}
+
+/*******************************************************************************
+**
+** Function L2CA_UcdDiscover
+**
+** Description Discover UCD of remote device.
+**
+** Parameters: PSM
+** BD_ADDR of remote device
+** info_type : L2CAP_UCD_INFO_TYPE_RECEPTION
+** L2CAP_UCD_INFO_TYPE_MTU
+**
+**
+** Return value: TRUE if successs
+**
+*******************************************************************************/
+BOOLEAN L2CA_UcdDiscover ( UINT16 psm, BD_ADDR rem_bda, UINT8 info_type )
+{
+ tL2C_LCB *p_lcb;
+ tL2C_CCB *p_ccb;
+ tL2C_RCB *p_rcb;
+
+ L2CAP_TRACE_API4 ("L2CA_UcdDiscover() PSM: 0x%04x BDA: %08x%04x, InfoType=0x%02x", psm,
+ (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3],
+ (rem_bda[4]<<8)+rem_bda[5], info_type);
+
+ /* Fail if the PSM is not registered */
+ if (((p_rcb = l2cu_find_rcb_by_psm (psm)) == NULL)
+ ||( p_rcb->ucd.state == L2C_UCD_STATE_UNUSED ))
+ {
+ L2CAP_TRACE_WARNING1 ("L2CAP - no RCB for L2CA_UcdDiscover, PSM: 0x%04x", psm);
+ return (FALSE);
+ }
+
+ /* First, see if we already have a link to the remote */
+ /* then find the channel control block for UCD. */
+ if (((p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda)) == NULL)
+ ||((p_ccb = l2cu_find_ccb_by_cid (p_lcb, L2CAP_CONNECTIONLESS_CID)) == NULL))
+ {
+ if ( l2c_ucd_connect (rem_bda) == FALSE )
+ {
+ return (FALSE);
+ }
+ }
+
+ /* set waiting flags in rcb */
+
+ if ( info_type & L2CAP_UCD_INFO_TYPE_RECEPTION )
+ p_rcb->ucd.state |= L2C_UCD_STATE_W4_RECEPTION;
+
+ if ( info_type & L2CAP_UCD_INFO_TYPE_MTU )
+ p_rcb->ucd.state |= L2C_UCD_STATE_W4_MTU;
+
+ /* if link is already established */
+ if ((p_lcb)&&(p_lcb->link_state == LST_CONNECTED))
+ {
+ if (!p_ccb)
+ {
+ p_ccb = l2cu_find_ccb_by_cid (p_lcb, L2CAP_CONNECTIONLESS_CID);
+ }
+ l2c_ucd_check_pending_info_req(p_ccb);
+ }
+ return (TRUE);
+}
+
+/*******************************************************************************
+**
+** Function L2CA_UcdDataWrite
+**
+** Description Send UCD to remote device
+**
+** Parameters: PSM
+** BD Address of remote
+** Pointer to buffer of type BT_HDR
+** flags : L2CAP_FLUSHABLE_CH_BASED
+** L2CAP_FLUSHABLE_PKT
+** L2CAP_NON_FLUSHABLE_PKT
+**
+** Return value L2CAP_DW_SUCCESS, if data accepted
+** L2CAP_DW_FAILED, if error
+**
+*******************************************************************************/
+UINT16 L2CA_UcdDataWrite (UINT16 psm, BD_ADDR rem_bda, BT_HDR *p_buf, UINT16 flags)
+{
+ tL2C_LCB *p_lcb;
+ tL2C_CCB *p_ccb;
+ tL2C_RCB *p_rcb;
+ UINT8 *p;
+
+ L2CAP_TRACE_API3 ("L2CA_UcdDataWrite() PSM: 0x%04x BDA: %08x%04x", psm,
+ (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3],
+ (rem_bda[4]<<8)+rem_bda[5]);
+
+ /* Fail if the PSM is not registered */
+ if (((p_rcb = l2cu_find_rcb_by_psm (psm)) == NULL)
+ ||( p_rcb->ucd.state == L2C_UCD_STATE_UNUSED ))
+ {
+ L2CAP_TRACE_WARNING1 ("L2CAP - no RCB for L2CA_UcdDataWrite, PSM: 0x%04x", psm);
+ GKI_freebuf (p_buf);
+ return (L2CAP_DW_FAILED);
+ }
+
+ /* First, see if we already have a link to the remote */
+ /* then find the channel control block for UCD */
+ if (((p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda)) == NULL)
+ ||((p_ccb = l2cu_find_ccb_by_cid (p_lcb, L2CAP_CONNECTIONLESS_CID)) == NULL))
+ {
+ if ( l2c_ucd_connect (rem_bda) == FALSE )
+ {
+ GKI_freebuf (p_buf);
+ return (L2CAP_DW_FAILED);
+ }
+
+ /* If we still don't have lcb and ccb after connect attempt, then can't proceed */
+ if (((p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda)) == NULL)
+ || ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, L2CAP_CONNECTIONLESS_CID)) == NULL))
+ {
+ GKI_freebuf (p_buf);
+ return (L2CAP_DW_FAILED);
+ }
+ }
+
+ /* write PSM */
+ p_buf->offset -= L2CAP_UCD_OVERHEAD;
+ p_buf->len += L2CAP_UCD_OVERHEAD;
+ p = (UINT8 *)(p_buf + 1) + p_buf->offset;
+
+ UINT16_TO_STREAM (p, psm);
+
+ /* UCD MTU check */
+ if ((p_lcb->ucd_mtu) && (p_buf->len > p_lcb->ucd_mtu))
+ {
+ L2CAP_TRACE_WARNING1 ("L2CAP - Handle: 0x%04x UCD bigger than peer's UCD mtu size cannot be sent", p_lcb->handle);
+ GKI_freebuf (p_buf);
+ return (L2CAP_DW_FAILED);
+ }
+
+ /* If already congested, do not accept any more packets */
+ if (p_ccb->cong_sent)
+ {
+ L2CAP_TRACE_ERROR3 ("L2CAP - Handle: 0x%04x UCD cannot be sent, already congested count: %u buff_quota: %u",
+ p_lcb->handle,
+ (p_ccb->xmit_hold_q.count + p_lcb->ucd_out_sec_pending_q.count),
+ p_ccb->buff_quota);
+
+ GKI_freebuf (p_buf);
+ return (L2CAP_DW_FAILED);
+ }
+
+ /* channel based, packet based flushable or non-flushable */
+ p_buf->layer_specific = flags;
+
+ l2c_csm_execute (p_ccb, L2CEVT_L2CA_DATA_WRITE, p_buf);
+
+ if (p_ccb->cong_sent)
+ return (L2CAP_DW_CONGESTED);
+ else
+ return (L2CAP_DW_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function L2CA_UcdSetIdleTimeout
+**
+** Description Set UCD Idle timeout.
+**
+** Parameters: BD Addr
+** Timeout in second
+**
+** Return value: TRUE if successs
+**
+*******************************************************************************/
+BOOLEAN L2CA_UcdSetIdleTimeout ( BD_ADDR rem_bda, UINT16 timeout )
+{
+ tL2C_LCB *p_lcb;
+ tL2C_CCB *p_ccb;
+
+ L2CAP_TRACE_API3 ("L2CA_UcdSetIdleTimeout() Timeout: 0x%04x BDA: %08x%04x", timeout,
+ (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3],
+ (rem_bda[4]<<8)+rem_bda[5]);
+
+ /* First, see if we already have a link to the remote */
+ /* then find the channel control block. */
+ if (((p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda)) == NULL)
+ ||((p_ccb = l2cu_find_ccb_by_cid (p_lcb, L2CAP_CONNECTIONLESS_CID)) == NULL))
+ {
+ L2CAP_TRACE_WARNING0 ("L2CAP - no UCD channel");
+ return (FALSE);
+ }
+ else
+ {
+ p_ccb->fixed_chnl_idle_tout = timeout;
+ return (TRUE);
+ }
+}
+
+/*******************************************************************************
+**
+** Function L2CA_UCDSetTxPriority
+**
+** Description Sets the transmission priority for a connectionless channel.
+**
+** Returns TRUE if a valid channel, else FALSE
+**
+*******************************************************************************/
+BOOLEAN L2CA_UCDSetTxPriority ( BD_ADDR rem_bda, tL2CAP_CHNL_PRIORITY priority )
+{
+ tL2C_LCB *p_lcb;
+ tL2C_CCB *p_ccb;
+
+ L2CAP_TRACE_API3 ("L2CA_UCDSetTxPriority() priority: 0x%02x BDA: %08x%04x", priority,
+ (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3],
+ (rem_bda[4]<<8)+rem_bda[5]);
+
+ if ((p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda)) == NULL)
+ {
+ L2CAP_TRACE_WARNING0 ("L2CAP - no LCB for L2CA_UCDSetTxPriority");
+ return (FALSE);
+ }
+
+ /* Find the channel control block */
+ if ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, L2CAP_CONNECTIONLESS_CID)) == NULL)
+ {
+ L2CAP_TRACE_WARNING0 ("L2CAP - no CCB for L2CA_UCDSetTxPriority");
+ return (FALSE);
+ }
+
+ /* it will update the order of CCB in LCB by priority and update round robin service variables */
+ l2cu_change_pri_ccb (p_ccb, priority);
+
+ return (TRUE);
+}
+
+/*******************************************************************************
+**
+** Function l2c_ucd_connect
+**
+** Description Connect UCD to remote device.
+**
+** Parameters: BD_ADDR of remote device
+**
+** Return value: TRUE if successs
+**
+*******************************************************************************/
+static BOOLEAN l2c_ucd_connect ( BD_ADDR rem_bda )
+{
+ tL2C_LCB *p_lcb;
+ tL2C_CCB *p_ccb;
+ tL2C_RCB *p_rcb;
+
+ L2CAP_TRACE_DEBUG2 ("l2c_ucd_connect() BDA: %08x%04x",
+ (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3],
+ (rem_bda[4]<<8)+rem_bda[5]);
+
+ /* Fail if we have not established communications with the controller */
+ if (!BTM_IsDeviceUp())
+ {
+ L2CAP_TRACE_WARNING0 ("l2c_ucd_connect - BTU not ready");
+ return (FALSE);
+ }
+
+ /* First, see if we already have a link to the remote */
+ if ((p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda)) == NULL)
+ {
+ /* No link. Get an LCB and start link establishment */
+ if ( ((p_lcb = l2cu_allocate_lcb (rem_bda, FALSE)) == NULL)
+ || (l2cu_create_conn(p_lcb) == FALSE) )
+ {
+ L2CAP_TRACE_WARNING0 ("L2CAP - conn not started l2c_ucd_connect");
+ return (FALSE);
+ }
+ }
+ else if ( p_lcb->info_rx_bits & (1 << L2CAP_EXTENDED_FEATURES_INFO_TYPE) )
+ {
+ if (!(p_lcb->peer_ext_fea & L2CAP_EXTFEA_UCD_RECEPTION))
+ {
+ L2CAP_TRACE_WARNING0 ("L2CAP - UCD is not supported by peer, l2c_ucd_connect");
+ return (FALSE);
+ }
+ }
+
+ /* Find the channel control block. */
+ if ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, L2CAP_CONNECTIONLESS_CID)) == NULL)
+ {
+ /* Allocate a channel control block */
+ if ((p_ccb = l2cu_allocate_ccb (p_lcb, 0)) == NULL)
+ {
+ L2CAP_TRACE_WARNING0 ("L2CAP - no CCB for l2c_ucd_connect");
+ return (FALSE);
+ }
+ else
+ {
+ /* Set CID for the connection */
+ p_ccb->local_cid = L2CAP_CONNECTIONLESS_CID;
+ p_ccb->remote_cid = L2CAP_CONNECTIONLESS_CID;
+
+ /* Set the default idle timeout value to use */
+ p_ccb->fixed_chnl_idle_tout = L2CAP_UCD_IDLE_TIMEOUT;
+
+ /* Set the default channel priority value to use */
+ l2cu_change_pri_ccb (p_ccb, L2CAP_UCD_CH_PRIORITY);
+
+ if ((p_rcb = l2cu_find_rcb_by_psm (L2C_UCD_RCB_ID)) == NULL)
+ {
+ L2CAP_TRACE_WARNING0 ("L2CAP - no UCD registered, l2c_ucd_connect");
+ return (FALSE);
+ }
+ /* Save UCD registration info */
+ p_ccb->p_rcb = p_rcb;
+
+ /* There is no configuration, so if the link is up, the channel is up */
+ if (p_lcb->link_state == LST_CONNECTED)
+ {
+ p_ccb->chnl_state = CST_OPEN;
+ }
+ }
+ }
+
+ return (TRUE);
+}
+
+/*******************************************************************************
+**
+** Function l2c_ucd_delete_sec_pending_q
+**
+** Description discard all of UCD packets in security pending queue
+**
+** Returns None
+**
+*******************************************************************************/
+void l2c_ucd_delete_sec_pending_q(tL2C_LCB *p_lcb)
+{
+ /* clean up any security pending UCD */
+ while (p_lcb->ucd_out_sec_pending_q.p_first)
+ GKI_freebuf (GKI_dequeue (&p_lcb->ucd_out_sec_pending_q));
+
+ while (p_lcb->ucd_in_sec_pending_q.p_first)
+ GKI_freebuf (GKI_dequeue (&p_lcb->ucd_in_sec_pending_q));
+}
+
+/*******************************************************************************
+**
+** Function l2c_ucd_check_pending_info_req
+**
+** Description check if any application is waiting for UCD information
+**
+** Return TRUE if any pending UCD info request
+**
+*******************************************************************************/
+BOOLEAN l2c_ucd_check_pending_info_req(tL2C_CCB *p_ccb)
+{
+ tL2C_RCB *p_rcb = &l2cb.rcb_pool[0];
+ UINT16 xx;
+ BOOLEAN pending = FALSE;
+
+ if (p_ccb == NULL)
+ {
+ L2CAP_TRACE_ERROR0 ("L2CAP - NULL p_ccb in l2c_ucd_check_pending_info_req");
+ return (FALSE);
+ }
+
+ for (xx = 0; xx < MAX_L2CAP_CLIENTS; xx++, p_rcb++)
+ {
+ if (p_rcb->in_use)
+ {
+ /* if application is waiting UCD reception info */
+ if (p_rcb->ucd.state & L2C_UCD_STATE_W4_RECEPTION)
+ {
+ /* if this information is available */
+ if ( p_ccb->p_lcb->info_rx_bits & (1 << L2CAP_EXTENDED_FEATURES_INFO_TYPE) )
+ {
+ if (!(p_ccb->p_lcb->peer_ext_fea & L2CAP_EXTFEA_UCD_RECEPTION))
+ {
+ L2CAP_TRACE_WARNING0 ("L2CAP - UCD is not supported by peer, l2c_ucd_check_pending_info_req");
+
+ l2c_ucd_delete_sec_pending_q(p_ccb->p_lcb);
+ l2cu_release_ccb (p_ccb);
+ }
+
+ p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Discover_Cb (p_ccb->p_lcb->remote_bd_addr,
+ L2CAP_UCD_INFO_TYPE_RECEPTION,
+ p_ccb->p_lcb->peer_ext_fea & L2CAP_EXTFEA_UCD_RECEPTION);
+ }
+ else
+ {
+ pending = TRUE;
+ if (p_ccb->p_lcb->w4_info_rsp == FALSE)
+ {
+ l2cu_send_peer_info_req (p_ccb->p_lcb, L2CAP_EXTENDED_FEATURES_INFO_TYPE);
+ }
+ }
+ }
+
+ /* if application is waiting for UCD MTU */
+ if (p_rcb->ucd.state & L2C_UCD_STATE_W4_MTU)
+ {
+ /* if this information is available */
+ if ( p_ccb->p_lcb->info_rx_bits & (1 << L2CAP_CONNLESS_MTU_INFO_TYPE))
+ {
+ p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Discover_Cb (p_ccb->p_lcb->remote_bd_addr,
+ L2CAP_UCD_INFO_TYPE_MTU,
+ p_ccb->p_lcb->ucd_mtu);
+ }
+ else
+ {
+ pending = TRUE;
+ if (p_ccb->p_lcb->w4_info_rsp == FALSE)
+ {
+ l2cu_send_peer_info_req (p_ccb->p_lcb, L2CAP_CONNLESS_MTU_INFO_TYPE);
+ }
+ }
+ }
+ }
+ }
+ return (pending);
+}
+
+/*******************************************************************************
+**
+** Function l2c_ucd_enqueue_pending_out_sec_q
+**
+** Description enqueue outgoing UCD packet into security pending queue
+** and check congestion
+**
+** Return None
+**
+*******************************************************************************/
+void l2c_ucd_enqueue_pending_out_sec_q(tL2C_CCB *p_ccb, void *p_data)
+{
+ GKI_enqueue (&p_ccb->p_lcb->ucd_out_sec_pending_q, p_data);
+ l2cu_check_channel_congestion (p_ccb);
+}
+
+/*******************************************************************************
+**
+** Function l2c_ucd_check_pending_out_sec_q
+**
+** Description check outgoing security
+**
+** Return TRUE if any UCD packet for security
+**
+*******************************************************************************/
+BOOLEAN l2c_ucd_check_pending_out_sec_q(tL2C_CCB *p_ccb)
+{
+ UINT8 *p;
+ UINT16 psm;
+ BT_HDR *p_buf;
+
+ if ( p_ccb->p_lcb->ucd_out_sec_pending_q.count )
+ {
+ p_buf = (BT_HDR*)(p_ccb->p_lcb->ucd_out_sec_pending_q.p_first);
+ p = (UINT8 *)(p_buf + 1) + p_buf->offset;
+ STREAM_TO_UINT16(psm, p)
+
+ p_ccb->chnl_state = CST_ORIG_W4_SEC_COMP;
+ btm_sec_l2cap_access_req (p_ccb->p_lcb->remote_bd_addr, psm,
+ p_ccb->p_lcb->handle, CONNLESS_ORIG, &l2c_link_sec_comp, p_ccb);
+
+ return (TRUE);
+ }
+ return (FALSE);
+}
+
+/*******************************************************************************
+**
+** Function l2c_ucd_send_pending_out_sec_q
+**
+** Description dequeue UCD packet from security pending queue and
+** enqueue it into CCB
+**
+** Return None
+**
+*******************************************************************************/
+void l2c_ucd_send_pending_out_sec_q(tL2C_CCB *p_ccb)
+{
+ BT_HDR *p_buf;
+
+ if ( p_ccb->p_lcb->ucd_out_sec_pending_q.count )
+ {
+ p_buf = (BT_HDR*)GKI_dequeue (&p_ccb->p_lcb->ucd_out_sec_pending_q);
+
+ l2c_enqueue_peer_data (p_ccb, (BT_HDR *)p_buf);
+ l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, NULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function l2c_ucd_discard_pending_out_sec_q
+**
+** Description dequeue UCD packet from security pending queue and
+** discard it.
+**
+** Return None
+**
+*******************************************************************************/
+void l2c_ucd_discard_pending_out_sec_q(tL2C_CCB *p_ccb)
+{
+ BT_HDR *p_buf;
+
+ p_buf = (BT_HDR*)GKI_dequeue (&p_ccb->p_lcb->ucd_out_sec_pending_q);
+
+ /* we may need to report to application */
+
+ if (p_buf)
+ {
+ GKI_freebuf (p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function l2c_ucd_check_pending_in_sec_q
+**
+** Description check incoming security
+**
+** Return TRUE if any UCD packet for security
+**
+*******************************************************************************/
+BOOLEAN l2c_ucd_check_pending_in_sec_q(tL2C_CCB *p_ccb)
+{
+ UINT8 *p;
+ UINT16 psm;
+ BT_HDR *p_buf;
+
+ if ( p_ccb->p_lcb->ucd_in_sec_pending_q.count )
+ {
+ p_buf = (BT_HDR*)(p_ccb->p_lcb->ucd_in_sec_pending_q.p_first);
+ p = (UINT8 *)(p_buf + 1) + p_buf->offset;
+ STREAM_TO_UINT16(psm, p)
+
+ p_ccb->chnl_state = CST_TERM_W4_SEC_COMP;
+ btm_sec_l2cap_access_req (p_ccb->p_lcb->remote_bd_addr, psm,
+ p_ccb->p_lcb->handle, CONNLESS_TERM, &l2c_link_sec_comp, p_ccb);
+
+ return (TRUE);
+ }
+ return (FALSE);
+}
+
+/*******************************************************************************
+**
+** Function l2c_ucd_send_pending_in_sec_q
+**
+** Description dequeue UCD packet from security pending queue and
+** send it to application
+**
+** Return None
+**
+*******************************************************************************/
+void l2c_ucd_send_pending_in_sec_q(tL2C_CCB *p_ccb)
+{
+ BT_HDR *p_buf;
+
+ if ( p_ccb->p_lcb->ucd_in_sec_pending_q.count )
+ {
+ p_buf = (BT_HDR*)GKI_dequeue (&p_ccb->p_lcb->ucd_in_sec_pending_q);
+
+ p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Data_Cb(p_ccb->p_lcb->remote_bd_addr, (BT_HDR *)p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function l2c_ucd_discard_pending_in_sec_q
+**
+** Description dequeue UCD packet from security pending queue and
+** discard it.
+**
+** Return None
+**
+*******************************************************************************/
+void l2c_ucd_discard_pending_in_sec_q(tL2C_CCB *p_ccb)
+{
+ BT_HDR *p_buf;
+
+ p_buf = (BT_HDR*)GKI_dequeue (&p_ccb->p_lcb->ucd_in_sec_pending_q);
+
+ if (p_buf)
+ {
+ GKI_freebuf (p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function l2c_ucd_check_rx_pkts
+**
+** Description Check if UCD reception is registered.
+** Process received UCD packet if application is expecting.
+**
+** Return TRUE if UCD reception is registered
+**
+*******************************************************************************/
+BOOLEAN l2c_ucd_check_rx_pkts(tL2C_LCB *p_lcb, BT_HDR *p_msg)
+{
+ tL2C_CCB *p_ccb;
+ tL2C_RCB *p_rcb;
+
+ if (((p_ccb = l2cu_find_ccb_by_cid (p_lcb, L2CAP_CONNECTIONLESS_CID)) != NULL)
+ ||((p_rcb = l2cu_find_rcb_by_psm (L2C_UCD_RCB_ID)) != NULL))
+ {
+ if (p_ccb == NULL)
+ {
+ /* Allocate a channel control block */
+ if ((p_ccb = l2cu_allocate_ccb (p_lcb, 0)) == NULL)
+ {
+ L2CAP_TRACE_WARNING0 ("L2CAP - no CCB for UCD reception");
+ GKI_freebuf (p_msg);
+ return TRUE;
+ }
+ else
+ {
+ /* Set CID for the connection */
+ p_ccb->local_cid = L2CAP_CONNECTIONLESS_CID;
+ p_ccb->remote_cid = L2CAP_CONNECTIONLESS_CID;
+
+ /* Set the default idle timeout value to use */
+ p_ccb->fixed_chnl_idle_tout = L2CAP_UCD_IDLE_TIMEOUT;
+
+ /* Set the default channel priority value to use */
+ l2cu_change_pri_ccb (p_ccb, L2CAP_UCD_CH_PRIORITY);
+
+ /* Save registration info */
+ p_ccb->p_rcb = p_rcb;
+
+ p_ccb->chnl_state = CST_OPEN;
+ }
+ }
+ l2c_csm_execute(p_ccb, L2CEVT_L2CAP_DATA, p_msg);
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function l2c_ucd_process_event
+**
+** Description This is called from main state machine when LCID is connectionless
+** Process the event if it is for UCD.
+**
+** Return TRUE if the event is consumed by UCD
+** FALSE if the event needs to be processed by main state machine
+**
+*******************************************************************************/
+BOOLEAN l2c_ucd_process_event(tL2C_CCB *p_ccb, UINT16 event, void *p_data)
+{
+ /* if the event is not processed by this function, this variable will be set to FALSE */
+ BOOLEAN done = TRUE;
+
+ switch (p_ccb->chnl_state)
+ {
+ case CST_CLOSED:
+ switch (event)
+ {
+ case L2CEVT_LP_CONNECT_CFM: /* Link came up */
+ /* check if waiting for UCD info */
+ if (!l2c_ucd_check_pending_info_req (p_ccb))
+ {
+ /* check if any outgoing UCD packet is waiting security check */
+ if (!l2c_ucd_check_pending_out_sec_q(p_ccb))
+ {
+ p_ccb->chnl_state = CST_OPEN;
+ }
+ }
+ break;
+
+ case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
+ GKI_enqueue (&p_ccb->p_lcb->ucd_in_sec_pending_q, p_data);
+ break;
+
+ case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
+ l2c_ucd_enqueue_pending_out_sec_q(p_ccb, p_data);
+ break;
+
+ case L2CEVT_L2CAP_INFO_RSP:
+ /* check if waiting for UCD info */
+ if (!l2c_ucd_check_pending_info_req (p_ccb))
+ {
+ /* check if any outgoing UCD packet is waiting security check */
+ if (!l2c_ucd_check_pending_out_sec_q(p_ccb))
+ {
+ p_ccb->chnl_state = CST_OPEN;
+ }
+ }
+ break;
+
+ default:
+ done = FALSE; /* main state machine continues to process event */
+ break;
+ }
+ break;
+
+ case CST_ORIG_W4_SEC_COMP:
+ switch (event)
+ {
+ case L2CEVT_SEC_RE_SEND_CMD: /* BTM has enough info to proceed */
+ /* check if any outgoing UCD packet is waiting security check */
+ if (!l2c_ucd_check_pending_out_sec_q(p_ccb))
+ {
+ p_ccb->chnl_state = CST_OPEN;
+ }
+ break;
+
+ case L2CEVT_SEC_COMP: /* Security completed success */
+ p_ccb->chnl_state = CST_OPEN;
+ l2c_ucd_send_pending_out_sec_q(p_ccb);
+
+ if ( p_ccb->p_lcb->ucd_out_sec_pending_q.count )
+ {
+ /* start a timer to send next UCD packet in OPEN state */
+ /* it will prevent stack overflow */
+ btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, 0);
+ }
+ else
+ {
+ /* start a timer for idle timeout of UCD */
+ btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, p_ccb->fixed_chnl_idle_tout);
+ }
+ break;
+
+ case L2CEVT_SEC_COMP_NEG:
+ p_ccb->chnl_state = CST_OPEN;
+ l2c_ucd_discard_pending_out_sec_q(p_ccb);
+
+ /* start a timer for idle timeout of UCD */
+ btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, p_ccb->fixed_chnl_idle_tout);
+ break;
+
+ case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
+ l2c_ucd_enqueue_pending_out_sec_q(p_ccb, p_data);
+ break;
+
+ case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
+ GKI_enqueue (&p_ccb->p_lcb->ucd_in_sec_pending_q, p_data);
+ break;
+
+ case L2CEVT_L2CAP_INFO_RSP:
+ /* check if waiting for UCD info */
+ l2c_ucd_check_pending_info_req (p_ccb);
+ break;
+
+ default:
+ done = FALSE; /* main state machine continues to process event */
+ break;
+ }
+ break;
+
+
+ case CST_TERM_W4_SEC_COMP:
+ switch (event)
+ {
+ case L2CEVT_SEC_COMP:
+ p_ccb->chnl_state = CST_OPEN;
+ l2c_ucd_send_pending_in_sec_q (p_ccb);
+
+ if ( p_ccb->p_lcb->ucd_in_sec_pending_q.count )
+ {
+ /* start a timer to check next UCD packet in OPEN state */
+ /* it will prevent stack overflow */
+ btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, 0);
+ }
+ else
+ {
+ /* start a timer for idle timeout of UCD */
+ btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, p_ccb->fixed_chnl_idle_tout);
+ }
+ break;
+
+ case L2CEVT_SEC_COMP_NEG:
+ if (((tL2C_CONN_INFO *)p_data)->status == BTM_DELAY_CHECK)
+ {
+ done = FALSE;
+ break;
+ }
+ p_ccb->chnl_state = CST_OPEN;
+ l2c_ucd_discard_pending_in_sec_q (p_ccb);
+
+ /* start a timer for idle timeout of UCD */
+ btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, p_ccb->fixed_chnl_idle_tout);
+ break;
+
+ case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
+ l2c_ucd_enqueue_pending_out_sec_q(p_ccb, p_data);
+ break;
+
+ case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
+ GKI_enqueue (&p_ccb->p_lcb->ucd_in_sec_pending_q, p_data);
+ break;
+
+ case L2CEVT_SEC_RE_SEND_CMD: /* BTM has enough info to proceed */
+ /* check if any incoming UCD packet is waiting security check */
+ if (!l2c_ucd_check_pending_in_sec_q(p_ccb))
+ {
+ p_ccb->chnl_state = CST_OPEN;
+ }
+ break;
+
+ case L2CEVT_L2CAP_INFO_RSP:
+ /* check if waiting for UCD info */
+ l2c_ucd_check_pending_info_req (p_ccb);
+ break;
+
+ default:
+ done = FALSE; /* main state machine continues to process event */
+ break;
+ }
+ break;
+
+ case CST_OPEN:
+ switch (event)
+ {
+ case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
+ /* stop idle timer of UCD */
+ btu_stop_timer (&p_ccb->timer_entry);
+
+ GKI_enqueue (&p_ccb->p_lcb->ucd_in_sec_pending_q, p_data);
+ l2c_ucd_check_pending_in_sec_q (p_ccb);
+ break;
+
+ case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
+ /* stop idle timer of UCD */
+ btu_stop_timer (&p_ccb->timer_entry);
+
+ l2c_ucd_enqueue_pending_out_sec_q(p_ccb, p_data);
+
+ /* coverity[check_return] */ /* coverity[unchecked_value] */
+ /* success changes state, failure stays in current state */
+ l2c_ucd_check_pending_out_sec_q (p_ccb);
+ break;
+
+ case L2CEVT_TIMEOUT:
+ /* check if any UCD packet is waiting security check */
+ if ((!l2c_ucd_check_pending_in_sec_q(p_ccb))
+ &&(!l2c_ucd_check_pending_out_sec_q(p_ccb)))
+ {
+ l2cu_release_ccb (p_ccb);
+ }
+ break;
+
+ case L2CEVT_L2CAP_INFO_RSP:
+ /* check if waiting for UCD info */
+ l2c_ucd_check_pending_info_req (p_ccb);
+ break;
+
+ default:
+ done = FALSE; /* main state machine continues to process event */
+ break;
+ }
+ break;
+
+ default:
+ done = FALSE; /* main state machine continues to process event */
+ break;
+ }
+
+ return done;
+}
+#endif /* (L2CAP_UCD_INCLUDED == TRUE) */
diff --git a/stack/l2cap/l2c_utils.c b/stack/l2cap/l2c_utils.c
new file mode 100644
index 0000000..0c1fb60
--- /dev/null
+++ b/stack/l2cap/l2c_utils.c
@@ -0,0 +1,3397 @@
+/*****************************************************************************
+**
+** Name: l2c_utils.c
+**
+**
+** Description: This file contains L2CAP utility functions
+**
+**
+**
+** Copyright (c) 1999-2012, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "gki.h"
+#include "bt_types.h"
+#include "hcimsgs.h"
+#include "l2cdefs.h"
+#include "l2c_int.h"
+#include "hcidefs.h"
+#include "btu.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "hcidefs.h"
+
+/*******************************************************************************
+**
+** Function l2cu_allocate_lcb
+**
+** Description Look for an unused LCB
+**
+** Returns LCB address or NULL if none found
+**
+*******************************************************************************/
+tL2C_LCB *l2cu_allocate_lcb (BD_ADDR p_bd_addr, BOOLEAN is_bonding)
+{
+ int xx;
+ tL2C_LCB *p_lcb = &l2cb.lcb_pool[0];
+
+ for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_lcb++)
+ {
+ if (!p_lcb->in_use)
+ {
+ memset (p_lcb, 0, sizeof (tL2C_LCB));
+
+ memcpy (p_lcb->remote_bd_addr, p_bd_addr, BD_ADDR_LEN);
+
+ p_lcb->in_use = TRUE;
+ p_lcb->link_state = LST_DISCONNECTED;
+ p_lcb->handle = HCI_INVALID_HANDLE;
+ p_lcb->link_flush_tout = 0xFFFF;
+ p_lcb->timer_entry.param = (TIMER_PARAM_TYPE)p_lcb;
+ p_lcb->info_timer_entry.param = (TIMER_PARAM_TYPE)p_lcb;
+ p_lcb->idle_timeout = l2cb.idle_timeout;
+ p_lcb->id = 1; /* spec does not allow '0' */
+ p_lcb->is_bonding = is_bonding;
+
+ l2cb.num_links_active++;
+
+ l2c_link_adjust_allocation();
+ return (p_lcb);
+ }
+ }
+
+ /* If here, no free LCB found */
+ return (NULL);
+}
+
+/*******************************************************************************
+**
+** Function l2cu_update_lcb_4_bonding
+**
+** Description Mark the lcb for bonding. Used when bonding takes place on
+** an existing ACL connection. (Pre-Lisbon devices)
+**
+** Returns Nothing
+**
+*******************************************************************************/
+void l2cu_update_lcb_4_bonding (BD_ADDR p_bd_addr, BOOLEAN is_bonding)
+{
+ tL2C_LCB *p_lcb = l2cu_find_lcb_by_bd_addr (p_bd_addr);
+
+ if (p_lcb)
+ {
+ L2CAP_TRACE_DEBUG3 ("l2cu_update_lcb_4_bonding BDA: %08x%04x is_bonding: %d",
+ (p_bd_addr[0]<<24)+(p_bd_addr[1]<<16)+(p_bd_addr[2]<<8)+p_bd_addr[3],
+ (p_bd_addr[4]<<8)+p_bd_addr[5], is_bonding);
+ p_lcb->is_bonding = is_bonding;
+ }
+}
+
+/*******************************************************************************
+**
+** Function l2cu_release_lcb
+**
+** Description Release an LCB. All timers will be stopped, channels
+** dropped, buffers returned etc.
+**
+** Returns void
+**
+*******************************************************************************/
+void l2cu_release_lcb (tL2C_LCB *p_lcb)
+{
+ tL2C_CCB *p_ccb;
+
+ p_lcb->in_use = FALSE;
+ p_lcb->is_bonding = FALSE;
+
+ /* Stop timers */
+ btu_stop_timer (&p_lcb->timer_entry);
+ btu_stop_timer (&p_lcb->info_timer_entry);
+
+ /* Release any unfinished L2CAP packet on this link */
+ if (p_lcb->p_hcit_rcv_acl)
+ {
+ GKI_freebuf(p_lcb->p_hcit_rcv_acl);
+ p_lcb->p_hcit_rcv_acl = NULL;
+ }
+
+#if BTM_SCO_INCLUDED == TRUE
+ /* Release all SCO links */
+ btm_remove_sco_links(p_lcb->remote_bd_addr);
+#endif
+
+#if (BLE_INCLUDED == TRUE)
+ p_lcb->is_ble_link = FALSE;
+ l2cb.is_ble_connecting = FALSE;
+#endif
+
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+ {
+ int xx;
+
+ for (xx = 0; xx < L2CAP_NUM_FIXED_CHNLS; xx++)
+ {
+ if (p_lcb->p_fixed_ccbs[xx])
+ {
+ l2cu_release_ccb (p_lcb->p_fixed_ccbs[xx]);
+ p_lcb->p_fixed_ccbs[xx] = NULL;
+ (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(p_lcb->remote_bd_addr, FALSE, p_lcb->disc_reason);
+ }
+ else if ( (p_lcb->peer_chnl_mask[0] & (1 << (xx + L2CAP_FIRST_FIXED_CHNL)))
+ && (l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb != NULL) )
+ (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(p_lcb->remote_bd_addr, FALSE, p_lcb->disc_reason);
+ }
+ }
+#endif
+
+ /* Ensure no CCBs left on this LCB */
+ for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; p_ccb = p_lcb->ccb_queue.p_first_ccb)
+ {
+ l2cu_release_ccb (p_ccb);
+ }
+
+ /* Tell BTM Acl management the link was removed */
+ if ((p_lcb->link_state == LST_CONNECTED) || (p_lcb->link_state == LST_DISCONNECTING))
+ btm_acl_removed (p_lcb->remote_bd_addr);
+
+ /* Release any held buffers */
+ while (p_lcb->link_xmit_data_q.p_first)
+ GKI_freebuf (GKI_dequeue (&p_lcb->link_xmit_data_q));
+
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ /* clean up any security pending UCD */
+ l2c_ucd_delete_sec_pending_q(p_lcb);
+#endif
+
+ /* Re-adjust flow control windows make sure it does not go negative */
+ if (l2cb.num_links_active >= 1)
+ l2cb.num_links_active--;
+
+ l2c_link_adjust_allocation();
+
+ /* Check for ping outstanding */
+ if (p_lcb->p_echo_rsp_cb)
+ {
+ tL2CA_ECHO_RSP_CB *p_cb = p_lcb->p_echo_rsp_cb;
+
+ /* Zero out the callback in case app immediately calls us again */
+ p_lcb->p_echo_rsp_cb = NULL;
+
+ (*p_cb) (L2CAP_PING_RESULT_NO_LINK);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function l2cu_find_lcb_by_bd_addr
+**
+** Description Look through all active LCBs for a match based on the
+** remote BD address.
+**
+** Returns pointer to matched LCB, or NULL if no match
+**
+*******************************************************************************/
+tL2C_LCB *l2cu_find_lcb_by_bd_addr (BD_ADDR p_bd_addr)
+{
+ int xx;
+ tL2C_LCB *p_lcb = &l2cb.lcb_pool[0];
+
+ for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_lcb++)
+ {
+ if ((p_lcb->in_use) && (!memcmp (p_lcb->remote_bd_addr, p_bd_addr, BD_ADDR_LEN)))
+ {
+ return (p_lcb);
+ }
+ }
+
+ /* If here, no match found */
+ return (NULL);
+}
+
+/*******************************************************************************
+**
+** Function l2cu_get_conn_role
+**
+** Description Determine the desired role (master or slave) of a link.
+** If already got a slave link, this one must be a master. If
+** already got at least 1 link where we are the master, make this
+** also a master.
+**
+** Returns HCI_ROLE_MASTER or HCI_ROLE_SLAVE
+**
+*******************************************************************************/
+UINT8 l2cu_get_conn_role (tL2C_LCB *p_this_lcb)
+{
+ return l2cb.desire_role;
+}
+
+/*******************************************************************************
+**
+** Function l2cu_build_header
+**
+** Description Builds the L2CAP command packet header
+**
+** Returns Pointer to allocated packet or NULL if no resources
+**
+*******************************************************************************/
+BT_HDR *l2cu_build_header (tL2C_LCB *p_lcb, UINT16 len, UINT8 cmd, UINT8 id)
+{
+ BT_HDR *p_buf = (BT_HDR *)GKI_getpoolbuf (L2CAP_CMD_POOL_ID);
+ UINT8 *p;
+
+ if (!p_buf)
+ {
+ L2CAP_TRACE_ERROR0 ("l2cu_build_header - no buffer");
+ return (NULL);
+ }
+
+ p_buf->offset = L2CAP_SEND_CMD_OFFSET;
+ p_buf->len = len + HCI_DATA_PREAMBLE_SIZE + L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+ p = (UINT8 *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET;
+
+ /* Put in HCI header - handle + pkt boundary */
+#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
+ UINT16_TO_STREAM (p, p_lcb->handle | l2cb.non_flushable_pbf);
+#else
+ UINT16_TO_STREAM (p, (p_lcb->handle | (L2CAP_PKT_START << L2CAP_PKT_TYPE_SHIFT)));
+#endif
+
+ UINT16_TO_STREAM (p, len + L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD);
+ UINT16_TO_STREAM (p, len + L2CAP_CMD_OVERHEAD);
+
+#if (BLE_INCLUDED == TRUE)
+ if (p_lcb->is_ble_link)
+ {
+ UINT16_TO_STREAM (p, L2CAP_BLE_SIGNALLING_CID);
+ }
+ else
+#endif
+ {
+ UINT16_TO_STREAM (p, L2CAP_SIGNALLING_CID);
+ }
+
+ /* Put in L2CAP command header */
+ UINT8_TO_STREAM (p, cmd);
+ UINT8_TO_STREAM (p, id);
+ UINT16_TO_STREAM (p, len);
+
+ return (p_buf);
+}
+
+/*******************************************************************************
+**
+** Function l2cu_adj_id
+**
+** Description Checks for valid ID based on specified mask
+** and adjusts the id if invalid.
+**
+** Returns void
+**
+*******************************************************************************/
+void l2cu_adj_id (tL2C_LCB *p_lcb, UINT8 adj_mask)
+{
+#if (L2CAP_ENHANCED_FEATURES != 0)
+ if ((adj_mask & L2CAP_ADJ_BRCM_ID) && p_lcb->id == L2CAP_FEATURE_REQ_ID)
+ {
+ p_lcb->id++;
+ }
+#endif
+
+ if ((adj_mask & L2CAP_ADJ_ZERO_ID) && !p_lcb->id)
+ {
+ p_lcb->id++;
+ }
+}
+
+/*******************************************************************************
+**
+** Function l2cu_send_peer_cmd_reject
+**
+** Description Build and send an L2CAP "command reject" message
+** to the peer.
+**
+** Returns void
+**
+*******************************************************************************/
+void l2cu_send_peer_cmd_reject (tL2C_LCB *p_lcb, UINT16 reason, UINT8 rem_id,
+ UINT16 p1, UINT16 p2)
+{
+ UINT16 param_len;
+ BT_HDR *p_buf;
+ UINT8 *p;
+
+ /* Put in L2CAP packet header */
+ if (reason == L2CAP_CMD_REJ_MTU_EXCEEDED)
+ param_len = 2;
+ else if (reason == L2CAP_CMD_REJ_INVALID_CID)
+ param_len = 4;
+ else
+ param_len = 0;
+
+ if ((p_buf = l2cu_build_header (p_lcb, (UINT16) (L2CAP_CMD_REJECT_LEN + param_len), L2CAP_CMD_REJECT, rem_id)) == NULL )
+ {
+ L2CAP_TRACE_WARNING0 ("L2CAP - no buffer cmd_rej");
+ return;
+ }
+
+ p = (UINT8 *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE +
+ L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+ UINT16_TO_STREAM (p, reason);
+
+ if (param_len >= 2)
+ UINT16_TO_STREAM (p, p1);
+
+ if (param_len >= 4)
+ UINT16_TO_STREAM (p, p2);
+
+ l2c_link_check_send_pkts (p_lcb, NULL, p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function l2cu_send_peer_connect_req
+**
+** Description Build and send an L2CAP "connection request" message
+** to the peer.
+**
+** Returns void
+**
+*******************************************************************************/
+void l2cu_send_peer_connect_req (tL2C_CCB *p_ccb)
+{
+ BT_HDR *p_buf;
+ UINT8 *p;
+
+ /* Create an identifier for this packet */
+ p_ccb->p_lcb->id++;
+ l2cu_adj_id(p_ccb->p_lcb, L2CAP_ADJ_ID);
+
+ p_ccb->local_id = p_ccb->p_lcb->id;
+
+ if ((p_buf = l2cu_build_header (p_ccb->p_lcb, L2CAP_CONN_REQ_LEN, L2CAP_CMD_CONN_REQ,
+ p_ccb->local_id)) == NULL)
+ {
+ L2CAP_TRACE_WARNING0 ("L2CAP - no buffer for conn_req");
+ return;
+ }
+
+ p = (UINT8 *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET+HCI_DATA_PREAMBLE_SIZE +
+ L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+ UINT16_TO_STREAM (p, p_ccb->p_rcb->real_psm);
+ UINT16_TO_STREAM (p, p_ccb->local_cid);
+
+ l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function l2cu_send_peer_connect_rsp
+**
+** Description Build and send an L2CAP "connection response" message
+** to the peer.
+**
+** Returns void
+**
+*******************************************************************************/
+void l2cu_send_peer_connect_rsp (tL2C_CCB *p_ccb, UINT16 result, UINT16 status)
+{
+ BT_HDR *p_buf;
+ UINT8 *p;
+
+ if (result == L2CAP_CONN_PENDING)
+ {
+ /* if we already sent pending response */
+ if (p_ccb->flags & CCB_FLAG_SENT_PENDING)
+ return;
+ else
+ p_ccb->flags |= CCB_FLAG_SENT_PENDING;
+ }
+
+ if ((p_buf=l2cu_build_header(p_ccb->p_lcb, L2CAP_CONN_RSP_LEN, L2CAP_CMD_CONN_RSP, p_ccb->remote_id)) == NULL)
+ {
+ L2CAP_TRACE_WARNING0 ("L2CAP - no buffer for conn_rsp");
+ return;
+ }
+
+ p = (UINT8 *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET+HCI_DATA_PREAMBLE_SIZE +
+ L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+ UINT16_TO_STREAM (p, p_ccb->local_cid);
+ UINT16_TO_STREAM (p, p_ccb->remote_cid);
+ UINT16_TO_STREAM (p, result);
+ UINT16_TO_STREAM (p, status);
+
+ l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function l2cu_reject_connection
+**
+** Description Build and send an L2CAP "connection response neg" message
+** to the peer. This function is called when there is no peer
+** CCB (non-existant PSM or no resources).
+**
+** Returns void
+**
+*******************************************************************************/
+void l2cu_reject_connection (tL2C_LCB *p_lcb, UINT16 remote_cid, UINT8 rem_id, UINT16 result)
+{
+ BT_HDR *p_buf;
+ UINT8 *p;
+
+ if ((p_buf = l2cu_build_header(p_lcb, L2CAP_CONN_RSP_LEN, L2CAP_CMD_CONN_RSP, rem_id)) == NULL )
+ {
+ L2CAP_TRACE_WARNING0 ("L2CAP - no buffer for conn_req");
+ return;
+ }
+
+ p = (UINT8 *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET+HCI_DATA_PREAMBLE_SIZE + L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+ UINT16_TO_STREAM (p, 0); /* Local CID of 0 */
+ UINT16_TO_STREAM (p, remote_cid);
+ UINT16_TO_STREAM (p, result);
+ UINT16_TO_STREAM (p, 0); /* Status of 0 */
+
+ l2c_link_check_send_pkts (p_lcb, NULL, p_buf);
+}
+
+/*******************************************************************************
+**
+** Function l2cu_send_peer_config_req
+**
+** Description Build and send an L2CAP "configuration request" message
+** to the peer.
+**
+** Returns void
+**
+*******************************************************************************/
+void l2cu_send_peer_config_req (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg)
+{
+ BT_HDR *p_buf;
+ UINT16 cfg_len=0;
+ UINT8 *p;
+
+ /* Create an identifier for this packet */
+ p_ccb->p_lcb->id++;
+ l2cu_adj_id(p_ccb->p_lcb, L2CAP_ADJ_ID);
+
+ p_ccb->local_id = p_ccb->p_lcb->id;
+
+ if (p_cfg->mtu_present)
+ cfg_len += L2CAP_CFG_MTU_OPTION_LEN + L2CAP_CFG_OPTION_OVERHEAD;
+ if (p_cfg->flush_to_present)
+ cfg_len += L2CAP_CFG_FLUSH_OPTION_LEN + L2CAP_CFG_OPTION_OVERHEAD;
+ if (p_cfg->qos_present)
+ cfg_len += L2CAP_CFG_QOS_OPTION_LEN + L2CAP_CFG_OPTION_OVERHEAD;
+ if (p_cfg->fcr_present)
+ cfg_len += L2CAP_CFG_FCR_OPTION_LEN + L2CAP_CFG_OPTION_OVERHEAD;
+ if (p_cfg->fcs_present)
+ cfg_len += L2CAP_CFG_FCS_OPTION_LEN + L2CAP_CFG_OPTION_OVERHEAD;
+ if (p_cfg->ext_flow_spec_present)
+ cfg_len += L2CAP_CFG_EXT_FLOW_OPTION_LEN + L2CAP_CFG_OPTION_OVERHEAD;
+
+ if ((p_buf = l2cu_build_header (p_ccb->p_lcb, (UINT16) (L2CAP_CONFIG_REQ_LEN + cfg_len),
+ L2CAP_CMD_CONFIG_REQ, p_ccb->local_id)) == NULL )
+ {
+ L2CAP_TRACE_WARNING0 ("L2CAP - no buffer for conn_req");
+ return;
+ }
+
+ p = (UINT8 *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE +
+ L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+ UINT16_TO_STREAM (p, p_ccb->remote_cid);
+ UINT16_TO_STREAM (p, p_cfg->flags); /* Flags (continuation) */
+
+ /* Now, put the options */
+ if (p_cfg->mtu_present)
+ {
+ UINT8_TO_STREAM (p, L2CAP_CFG_TYPE_MTU);
+ UINT8_TO_STREAM (p, L2CAP_CFG_MTU_OPTION_LEN);
+ UINT16_TO_STREAM (p, p_cfg->mtu);
+ }
+ if (p_cfg->flush_to_present)
+ {
+ UINT8_TO_STREAM (p, L2CAP_CFG_TYPE_FLUSH_TOUT);
+ UINT8_TO_STREAM (p, L2CAP_CFG_FLUSH_OPTION_LEN);
+ UINT16_TO_STREAM (p, p_cfg->flush_to);
+ }
+ if (p_cfg->qos_present)
+ {
+ UINT8_TO_STREAM (p, L2CAP_CFG_TYPE_QOS);
+ UINT8_TO_STREAM (p, L2CAP_CFG_QOS_OPTION_LEN);
+ UINT8_TO_STREAM (p, p_cfg->qos.qos_flags);
+ UINT8_TO_STREAM (p, p_cfg->qos.service_type);
+ UINT32_TO_STREAM (p, p_cfg->qos.token_rate);
+ UINT32_TO_STREAM (p, p_cfg->qos.token_bucket_size);
+ UINT32_TO_STREAM (p, p_cfg->qos.peak_bandwidth);
+ UINT32_TO_STREAM (p, p_cfg->qos.latency);
+ UINT32_TO_STREAM (p, p_cfg->qos.delay_variation);
+ }
+ if (p_cfg->fcr_present)
+ {
+ UINT8_TO_STREAM (p, L2CAP_CFG_TYPE_FCR);
+ UINT8_TO_STREAM (p, L2CAP_CFG_FCR_OPTION_LEN);
+ UINT8_TO_STREAM (p, p_cfg->fcr.mode);
+ UINT8_TO_STREAM (p, p_cfg->fcr.tx_win_sz);
+ UINT8_TO_STREAM (p, p_cfg->fcr.max_transmit);
+ UINT16_TO_STREAM (p, p_cfg->fcr.rtrans_tout);
+ UINT16_TO_STREAM (p, p_cfg->fcr.mon_tout);
+ UINT16_TO_STREAM (p, p_cfg->fcr.mps);
+ }
+
+ if (p_cfg->fcs_present)
+ {
+ UINT8_TO_STREAM (p, L2CAP_CFG_TYPE_FCS);
+ UINT8_TO_STREAM (p, L2CAP_CFG_FCS_OPTION_LEN);
+ UINT8_TO_STREAM (p, p_cfg->fcs);
+ }
+
+ if (p_cfg->ext_flow_spec_present)
+ {
+ UINT8_TO_STREAM (p, L2CAP_CFG_TYPE_EXT_FLOW);
+ UINT8_TO_STREAM (p, L2CAP_CFG_EXT_FLOW_OPTION_LEN);
+ UINT8_TO_STREAM (p, p_cfg->ext_flow_spec.id);
+ UINT8_TO_STREAM (p, p_cfg->ext_flow_spec.stype);
+ UINT16_TO_STREAM (p, p_cfg->ext_flow_spec.max_sdu_size);
+ UINT32_TO_STREAM (p, p_cfg->ext_flow_spec.sdu_inter_time);
+ UINT32_TO_STREAM (p, p_cfg->ext_flow_spec.access_latency);
+ UINT32_TO_STREAM (p, p_cfg->ext_flow_spec.flush_timeout);
+ }
+
+ l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, p_buf);
+}
+
+/*******************************************************************************
+**
+** Function l2cu_send_peer_config_rsp
+**
+** Description Build and send an L2CAP "configuration response" message
+** to the peer.
+**
+** Returns void
+**
+*******************************************************************************/
+void l2cu_send_peer_config_rsp (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg)
+{
+ BT_HDR *p_buf;
+ UINT16 cfg_len = 0;
+ UINT8 *p;
+
+ /* Create an identifier for this packet */
+ if (p_cfg->mtu_present)
+ cfg_len += L2CAP_CFG_MTU_OPTION_LEN + L2CAP_CFG_OPTION_OVERHEAD;
+ if (p_cfg->flush_to_present)
+ cfg_len += L2CAP_CFG_FLUSH_OPTION_LEN + L2CAP_CFG_OPTION_OVERHEAD;
+ if (p_cfg->qos_present)
+ cfg_len += L2CAP_CFG_QOS_OPTION_LEN + L2CAP_CFG_OPTION_OVERHEAD;
+ if (p_cfg->fcr_present)
+ cfg_len += L2CAP_CFG_FCR_OPTION_LEN + L2CAP_CFG_OPTION_OVERHEAD;
+ if (p_cfg->ext_flow_spec_present)
+ cfg_len += L2CAP_CFG_EXT_FLOW_OPTION_LEN + L2CAP_CFG_OPTION_OVERHEAD;
+
+ if ((p_buf = l2cu_build_header (p_ccb->p_lcb, (UINT16)(L2CAP_CONFIG_RSP_LEN + cfg_len),
+ L2CAP_CMD_CONFIG_RSP, p_ccb->remote_id)) == NULL )
+ {
+ L2CAP_TRACE_WARNING0 ("L2CAP - no buffer for conn_req");
+ return;
+ }
+
+ p = (UINT8 *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET+HCI_DATA_PREAMBLE_SIZE + L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+ UINT16_TO_STREAM (p, p_ccb->remote_cid);
+ UINT16_TO_STREAM (p, p_cfg->flags); /* Flags (continuation) Must match request */
+ UINT16_TO_STREAM (p, p_cfg->result);
+
+ /* Now, put the options */
+ if (p_cfg->mtu_present)
+ {
+ UINT8_TO_STREAM (p, L2CAP_CFG_TYPE_MTU);
+ UINT8_TO_STREAM (p, L2CAP_CFG_MTU_OPTION_LEN);
+ UINT16_TO_STREAM (p, p_cfg->mtu);
+ }
+ if (p_cfg->flush_to_present)
+ {
+ UINT8_TO_STREAM (p, L2CAP_CFG_TYPE_FLUSH_TOUT);
+ UINT8_TO_STREAM (p, L2CAP_CFG_FLUSH_OPTION_LEN);
+ UINT16_TO_STREAM (p, p_cfg->flush_to);
+ }
+ if (p_cfg->qos_present)
+ {
+ UINT8_TO_STREAM (p, L2CAP_CFG_TYPE_QOS);
+ UINT8_TO_STREAM (p, L2CAP_CFG_QOS_OPTION_LEN);
+ UINT8_TO_STREAM (p, p_cfg->qos.qos_flags);
+ UINT8_TO_STREAM (p, p_cfg->qos.service_type);
+ UINT32_TO_STREAM (p, p_cfg->qos.token_rate);
+ UINT32_TO_STREAM (p, p_cfg->qos.token_bucket_size);
+ UINT32_TO_STREAM (p, p_cfg->qos.peak_bandwidth);
+ UINT32_TO_STREAM (p, p_cfg->qos.latency);
+ UINT32_TO_STREAM (p, p_cfg->qos.delay_variation);
+ }
+ if (p_cfg->fcr_present)
+ {
+ UINT8_TO_STREAM (p, L2CAP_CFG_TYPE_FCR);
+ UINT8_TO_STREAM (p, L2CAP_CFG_FCR_OPTION_LEN);
+ UINT8_TO_STREAM (p, p_cfg->fcr.mode);
+ UINT8_TO_STREAM (p, p_cfg->fcr.tx_win_sz);
+ UINT8_TO_STREAM (p, p_cfg->fcr.max_transmit);
+ UINT16_TO_STREAM (p, p_ccb->our_cfg.fcr.rtrans_tout);
+ UINT16_TO_STREAM (p, p_ccb->our_cfg.fcr.mon_tout);
+ UINT16_TO_STREAM (p, p_cfg->fcr.mps);
+ }
+
+ if (p_cfg->ext_flow_spec_present)
+ {
+ UINT8_TO_STREAM (p, L2CAP_CFG_TYPE_EXT_FLOW);
+ UINT8_TO_STREAM (p, L2CAP_CFG_EXT_FLOW_OPTION_LEN);
+ UINT8_TO_STREAM (p, p_cfg->ext_flow_spec.id);
+ UINT8_TO_STREAM (p, p_cfg->ext_flow_spec.stype);
+ UINT16_TO_STREAM (p, p_cfg->ext_flow_spec.max_sdu_size);
+ UINT32_TO_STREAM (p, p_cfg->ext_flow_spec.sdu_inter_time);
+ UINT32_TO_STREAM (p, p_cfg->ext_flow_spec.access_latency);
+ UINT32_TO_STREAM (p, p_cfg->ext_flow_spec.flush_timeout);
+ }
+
+ l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, p_buf);
+}
+
+/*******************************************************************************
+**
+** Function l2cu_send_peer_config_rej
+**
+** Description Build and send an L2CAP "configuration reject" message
+** to the peer.
+**
+** Returns void
+**
+*******************************************************************************/
+void l2cu_send_peer_config_rej (tL2C_CCB *p_ccb, UINT8 *p_data, UINT16 data_len, UINT16 rej_len)
+{
+ BT_HDR *p_buf = (BT_HDR *)GKI_getpoolbuf (L2CAP_CMD_POOL_ID);
+ UINT16 len, cfg_len;
+ UINT8 *p, *p_hci_len, *p_data_end;
+ UINT8 cfg_code;
+
+ if (!p_buf)
+ {
+ L2CAP_TRACE_ERROR0 ("L2CAP - no buffer for cfg_rej");
+ return;
+ }
+
+ p_buf->offset = L2CAP_SEND_CMD_OFFSET;
+ p = (UINT8 *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET;
+
+ /* Put in HCI header - handle + pkt boundary */
+#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
+ if (HCI_NON_FLUSHABLE_PB_SUPPORTED(BTM_ReadLocalFeatures ()))
+ {
+ UINT16_TO_STREAM (p, (p_ccb->p_lcb->handle | (L2CAP_PKT_START_NON_FLUSHABLE << L2CAP_PKT_TYPE_SHIFT)));
+ }
+ else
+#endif
+ {
+ UINT16_TO_STREAM (p, (p_ccb->p_lcb->handle | (L2CAP_PKT_START << L2CAP_PKT_TYPE_SHIFT)));
+ }
+
+ /* Remember the HCI header length position, and save space for it */
+ p_hci_len = p;
+ p += 2;
+
+ /* Put in L2CAP packet header */
+ UINT16_TO_STREAM (p, L2CAP_CMD_OVERHEAD + L2CAP_CONFIG_RSP_LEN + rej_len);
+ UINT16_TO_STREAM (p, L2CAP_SIGNALLING_CID);
+
+ /* Put in L2CAP command header */
+ UINT8_TO_STREAM (p, L2CAP_CMD_CONFIG_RSP);
+ UINT8_TO_STREAM (p, p_ccb->remote_id);
+
+ UINT16_TO_STREAM (p, L2CAP_CONFIG_RSP_LEN + rej_len);
+
+ UINT16_TO_STREAM (p, p_ccb->remote_cid);
+ UINT16_TO_STREAM (p, 0); /* Flags = 0 (no continuation) */
+ UINT16_TO_STREAM (p, L2CAP_CFG_UNKNOWN_OPTIONS);
+
+ /* Now, put the rejected options */
+ p_data_end = p_data + data_len;
+ while (p_data < p_data_end)
+ {
+ cfg_code = *p_data;
+ cfg_len = *(p_data + 1);
+
+ switch (cfg_code & 0x7F)
+ {
+ /* skip known options */
+ case L2CAP_CFG_TYPE_MTU:
+ case L2CAP_CFG_TYPE_FLUSH_TOUT:
+ case L2CAP_CFG_TYPE_QOS:
+ p_data += cfg_len + L2CAP_CFG_OPTION_OVERHEAD;
+ break;
+
+ /* unknown options; copy into rsp if not hints */
+ default:
+ /* sanity check option length */
+ if ((cfg_len + L2CAP_CFG_OPTION_OVERHEAD) <= data_len)
+ {
+ if ((cfg_code & 0x80) == 0)
+ {
+ memcpy(p, p_data, cfg_len + L2CAP_CFG_OPTION_OVERHEAD);
+ p += cfg_len + L2CAP_CFG_OPTION_OVERHEAD;
+ }
+ p_data += cfg_len + L2CAP_CFG_OPTION_OVERHEAD;
+ }
+ /* bad length; force loop exit */
+ else
+ {
+ p_data = p_data_end;
+ }
+ break;
+ }
+ }
+
+ len = (UINT16) (p - p_hci_len - 2);
+ UINT16_TO_STREAM (p_hci_len, len);
+
+ p_buf->len = len + 4;
+
+ l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, p_buf);
+}
+
+/*******************************************************************************
+**
+** Function l2cu_send_peer_disc_req
+**
+** Description Build and send an L2CAP "disconnect request" message
+** to the peer.
+**
+** Returns void
+**
+*******************************************************************************/
+void l2cu_send_peer_disc_req (tL2C_CCB *p_ccb)
+{
+ BT_HDR *p_buf, *p_buf2;
+ UINT8 *p;
+
+ /* Create an identifier for this packet */
+ p_ccb->p_lcb->id++;
+ l2cu_adj_id(p_ccb->p_lcb, L2CAP_ADJ_ID);
+
+ p_ccb->local_id = p_ccb->p_lcb->id;
+
+ if ((p_buf = l2cu_build_header(p_ccb->p_lcb, L2CAP_DISC_REQ_LEN, L2CAP_CMD_DISC_REQ, p_ccb->local_id)) == NULL)
+ {
+ L2CAP_TRACE_WARNING0 ("L2CAP - no buffer for disc_req");
+ return;
+ }
+
+ p = (UINT8 *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE + L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+ UINT16_TO_STREAM (p, p_ccb->remote_cid);
+ UINT16_TO_STREAM (p, p_ccb->local_cid);
+
+ /* Move all queued data packets to the LCB. In FCR mode, assume the higher
+ layer checks that all buffers are sent before disconnecting.
+ */
+ if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_BASIC_MODE)
+ {
+ while (p_ccb->xmit_hold_q.p_first)
+ {
+ p_buf2 = (BT_HDR *)GKI_dequeue (&p_ccb->xmit_hold_q);
+ l2cu_set_acl_hci_header (p_buf2, p_ccb);
+ l2c_link_check_send_pkts (p_ccb->p_lcb, p_ccb, p_buf2);
+ }
+ }
+
+ l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function l2cu_send_peer_disc_rsp
+**
+** Description Build and send an L2CAP "disconnect response" message
+** to the peer.
+**
+** This function is passed the parameters for the disconnect
+** response instead of the CCB address, as it may be called
+** to send a disconnect response when there is no CCB.
+**
+** Returns void
+**
+*******************************************************************************/
+void l2cu_send_peer_disc_rsp (tL2C_LCB *p_lcb, UINT8 remote_id, UINT16 local_cid,
+ UINT16 remote_cid)
+{
+ BT_HDR *p_buf;
+ UINT8 *p;
+
+ if ((p_buf=l2cu_build_header(p_lcb, L2CAP_DISC_RSP_LEN, L2CAP_CMD_DISC_RSP, remote_id)) == NULL)
+ {
+ L2CAP_TRACE_WARNING0 ("L2CAP - no buffer for disc_rsp");
+ return;
+ }
+
+ p = (UINT8 *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE + L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+ UINT16_TO_STREAM (p, local_cid);
+ UINT16_TO_STREAM (p, remote_cid);
+
+ l2c_link_check_send_pkts (p_lcb, NULL, p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function l2cu_send_peer_echo_req
+**
+** Description Build and send an L2CAP "echo request" message
+** to the peer. Note that we do not currently allow
+** data in the echo request.
+**
+** Returns void
+**
+*******************************************************************************/
+void l2cu_send_peer_echo_req (tL2C_LCB *p_lcb, UINT8 *p_data, UINT16 data_len)
+{
+ BT_HDR *p_buf;
+ UINT8 *p;
+
+ p_lcb->id++;
+ l2cu_adj_id(p_lcb, L2CAP_ADJ_ZERO_ID); /* check for wrap to '0' */
+
+ if ((p_buf = l2cu_build_header(p_lcb, (UINT16) (L2CAP_ECHO_REQ_LEN + data_len), L2CAP_CMD_ECHO_REQ, p_lcb->id)) == NULL)
+ {
+ L2CAP_TRACE_WARNING0 ("L2CAP - no buffer for echo_req");
+ return;
+ }
+
+ p = (UINT8 *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE + L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+ if (data_len)
+ {
+ ARRAY_TO_STREAM (p, p_data, data_len);
+ }
+
+ l2c_link_check_send_pkts (p_lcb, NULL, p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function l2cu_send_peer_echo_rsp
+**
+** Description Build and send an L2CAP "echo response" message
+** to the peer.
+**
+** Returns void
+**
+*******************************************************************************/
+void l2cu_send_peer_echo_rsp (tL2C_LCB *p_lcb, UINT8 id, UINT8 *p_data, UINT16 data_len)
+{
+ BT_HDR *p_buf;
+ UINT8 *p;
+ UINT16 maxlen;
+
+ /* Don't return data if it does not fit in ACL and L2CAP MTU */
+ maxlen = (GKI_get_pool_bufsize(L2CAP_CMD_POOL_ID) > btu_cb.hcit_acl_pkt_size) ?
+ btu_cb.hcit_acl_data_size : (UINT16)GKI_get_pool_bufsize(L2CAP_CMD_POOL_ID);
+ maxlen -= (UINT16)(BT_HDR_SIZE + HCI_DATA_PREAMBLE_SIZE + L2CAP_PKT_OVERHEAD +
+ L2CAP_CMD_OVERHEAD + L2CAP_ECHO_RSP_LEN);
+
+ if (data_len > maxlen)
+ data_len = 0;
+
+ if ((p_buf = l2cu_build_header (p_lcb, (UINT16)(L2CAP_ECHO_RSP_LEN + data_len), L2CAP_CMD_ECHO_RSP, id)) == NULL)
+ {
+ L2CAP_TRACE_WARNING0 ("L2CAP - no buffer for echo_rsp");
+ return;
+ }
+
+ p = (UINT8 *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE +
+ L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+ if (data_len)
+ {
+ ARRAY_TO_STREAM (p, p_data, data_len);
+ }
+
+ l2c_link_check_send_pkts (p_lcb, NULL, p_buf);
+}
+
+/*******************************************************************************
+**
+** Function l2cu_send_peer_info_req
+**
+** Description Build and send an L2CAP "info request" message
+** to the peer.
+** Returns void
+**
+*******************************************************************************/
+void l2cu_send_peer_info_req (tL2C_LCB *p_lcb, UINT16 info_type)
+{
+ BT_HDR *p_buf;
+ UINT8 *p;
+
+ /* check for wrap and/or BRCM ID */
+ p_lcb->id++;
+ l2cu_adj_id(p_lcb, L2CAP_ADJ_ID);
+
+ if ((p_buf = l2cu_build_header(p_lcb, 2, L2CAP_CMD_INFO_REQ, p_lcb->id)) == NULL)
+ {
+ L2CAP_TRACE_WARNING0 ("L2CAP - no buffer for info_req");
+ return;
+ }
+
+ L2CAP_TRACE_EVENT1 ("l2cu_send_peer_info_req: type 0x%04x", info_type);
+
+ p = (UINT8 *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET+HCI_DATA_PREAMBLE_SIZE +
+ L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+ UINT16_TO_STREAM (p, info_type);
+
+ p_lcb->w4_info_rsp = TRUE;
+ btu_start_timer (&p_lcb->info_timer_entry, BTU_TTYPE_L2CAP_INFO, L2CAP_WAIT_INFO_RSP_TOUT);
+
+ l2c_link_check_send_pkts (p_lcb, NULL, p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function l2cu_send_peer_info_rsp
+**
+** Description Build and send an L2CAP "info response" message
+** to the peer.
+**
+** Returns void
+**
+*******************************************************************************/
+void l2cu_send_peer_info_rsp (tL2C_LCB *p_lcb, UINT8 remote_id, UINT16 info_type)
+{
+ BT_HDR *p_buf;
+ UINT8 *p;
+ UINT16 len = L2CAP_INFO_RSP_LEN;
+
+#if (L2CAP_CONFORMANCE_TESTING == TRUE)
+ if ((info_type == L2CAP_EXTENDED_FEATURES_INFO_TYPE)
+ && (l2cb.test_info_resp & (L2CAP_EXTFEA_ENH_RETRANS | L2CAP_EXTFEA_STREAM_MODE |
+ L2CAP_EXTFEA_NO_CRC | L2CAP_EXTFEA_EXT_FLOW_SPEC |
+ L2CAP_EXTFEA_FIXED_CHNLS | L2CAP_EXTFEA_EXT_WINDOW |
+ L2CAP_EXTFEA_UCD_RECEPTION )) )
+#else
+ if ((info_type == L2CAP_EXTENDED_FEATURES_INFO_TYPE)
+ && (L2CAP_EXTFEA_SUPPORTED_MASK & (L2CAP_EXTFEA_ENH_RETRANS | L2CAP_EXTFEA_STREAM_MODE |
+ L2CAP_EXTFEA_NO_CRC |L2CAP_EXTFEA_FIXED_CHNLS |
+ L2CAP_EXTFEA_UCD_RECEPTION )) )
+#endif
+ {
+ len += L2CAP_EXTENDED_FEATURES_ARRAY_SIZE;
+ }
+ else if (info_type == L2CAP_FIXED_CHANNELS_INFO_TYPE)
+ {
+ len += L2CAP_FIXED_CHNL_ARRAY_SIZE;
+ }
+ else if (info_type == L2CAP_CONNLESS_MTU_INFO_TYPE)
+ {
+ len += L2CAP_CONNLESS_MTU_INFO_SIZE;
+ }
+
+ if ((p_buf = l2cu_build_header(p_lcb, len, L2CAP_CMD_INFO_RSP, remote_id)) == NULL)
+ {
+ L2CAP_TRACE_WARNING0 ("L2CAP - no buffer for info_rsp");
+ return;
+ }
+
+ p = (UINT8 *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE +
+ L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+ UINT16_TO_STREAM (p, info_type);
+
+#if (L2CAP_CONFORMANCE_TESTING == TRUE)
+ if ((info_type == L2CAP_EXTENDED_FEATURES_INFO_TYPE)
+ && (l2cb.test_info_resp & ( L2CAP_EXTFEA_ENH_RETRANS | L2CAP_EXTFEA_STREAM_MODE
+ | L2CAP_EXTFEA_UCD_RECEPTION )) )
+#else
+ if ((info_type == L2CAP_EXTENDED_FEATURES_INFO_TYPE)
+ && (L2CAP_EXTFEA_SUPPORTED_MASK & ( L2CAP_EXTFEA_ENH_RETRANS | L2CAP_EXTFEA_STREAM_MODE
+ | L2CAP_EXTFEA_UCD_RECEPTION )) )
+#endif
+ {
+ UINT16_TO_STREAM (p, L2CAP_INFO_RESP_RESULT_SUCCESS);
+#if (BLE_INCLUDED == TRUE)
+ if (p_lcb->is_ble_link)
+ {
+ /* optional data are not added for now */
+ UINT32_TO_STREAM (p, L2CAP_BLE_EXTFEA_MASK);
+ }
+ else
+#endif
+ {
+#if L2CAP_CONFORMANCE_TESTING == TRUE
+ UINT32_TO_STREAM (p, l2cb.test_info_resp);
+#else
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+ UINT32_TO_STREAM (p, L2CAP_EXTFEA_SUPPORTED_MASK | L2CAP_EXTFEA_FIXED_CHNLS);
+#else
+ UINT32_TO_STREAM (p, L2CAP_EXTFEA_SUPPORTED_MASK);
+#endif
+#endif
+ }
+ }
+ else if (info_type == L2CAP_FIXED_CHANNELS_INFO_TYPE)
+ {
+ UINT16_TO_STREAM (p, L2CAP_INFO_RESP_RESULT_SUCCESS);
+ memset (p, 0, L2CAP_FIXED_CHNL_ARRAY_SIZE);
+
+ p[0] = L2CAP_FIXED_CHNL_SIG_BIT;
+
+ if ( L2CAP_EXTFEA_SUPPORTED_MASK & L2CAP_EXTFEA_UCD_RECEPTION )
+ p[0] |= L2CAP_FIXED_CHNL_CNCTLESS_BIT;
+
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+ {
+ int xx;
+
+ for (xx = 0; xx < L2CAP_NUM_FIXED_CHNLS; xx++)
+ if (l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb != NULL)
+ p[0] |= 1 << (xx + L2CAP_FIRST_FIXED_CHNL);
+ }
+#endif
+ }
+ else if (info_type == L2CAP_CONNLESS_MTU_INFO_TYPE)
+ {
+ UINT16_TO_STREAM (p, L2CAP_INFO_RESP_RESULT_SUCCESS);
+ UINT16_TO_STREAM (p, L2CAP_UCD_MTU);
+ }
+ else
+ {
+ UINT16_TO_STREAM (p, L2CAP_INFO_RESP_RESULT_NOT_SUPPORTED); /* 'not supported' */
+ }
+
+ l2c_link_check_send_pkts (p_lcb, NULL, p_buf);
+}
+
+/******************************************************************************
+**
+** Function l2cu_enqueue_ccb
+**
+** Description queue CCB by priority. The first CCB is highest priority and
+** is served at first. The CCB is queued to an LLCB or an LCB.
+**
+** Returns None
+**
+*******************************************************************************/
+void l2cu_enqueue_ccb (tL2C_CCB *p_ccb)
+{
+ tL2C_CCB *p_ccb1;
+ tL2C_CCB_Q *p_q = NULL;
+
+ /* Find out which queue the channel is on
+ */
+ if (p_ccb->p_lcb != NULL)
+ p_q = &p_ccb->p_lcb->ccb_queue;
+
+ if ( (!p_ccb->in_use) || (p_q == NULL) )
+ {
+ L2CAP_TRACE_ERROR3 ("l2cu_enqueue_ccb CID: 0x%04x ERROR in_use: %u p_lcb: 0x%08x",
+ p_ccb->local_cid, p_ccb->in_use, p_ccb->p_lcb);
+ return;
+ }
+
+ L2CAP_TRACE_DEBUG2 ("l2cu_enqueue_ccb CID: 0x%04x priority: %d",
+ p_ccb->local_cid, p_ccb->ccb_priority);
+
+ /* If the queue is empty, we go at the front */
+ if (!p_q->p_first_ccb)
+ {
+ p_q->p_first_ccb = p_q->p_last_ccb = p_ccb;
+ p_ccb->p_next_ccb = p_ccb->p_prev_ccb = NULL;
+ }
+ else
+ {
+ p_ccb1 = p_q->p_first_ccb;
+
+ while (p_ccb1 != NULL)
+ {
+ /* Insert new ccb at the end of the same priority. Lower number, higher priority */
+ if (p_ccb->ccb_priority < p_ccb1->ccb_priority)
+ {
+ /* Are we at the head of the queue ? */
+ if (p_ccb1 == p_q->p_first_ccb)
+ p_q->p_first_ccb = p_ccb;
+ else
+ p_ccb1->p_prev_ccb->p_next_ccb = p_ccb;
+
+ p_ccb->p_next_ccb = p_ccb1;
+ p_ccb->p_prev_ccb = p_ccb1->p_prev_ccb;
+ p_ccb1->p_prev_ccb = p_ccb;
+ break;
+ }
+
+ p_ccb1 = p_ccb1->p_next_ccb;
+ }
+
+ /* If we are lower then anyone in the list, we go at the end */
+ if (!p_ccb1)
+ {
+ /* add new ccb at the end of the list */
+ p_q->p_last_ccb->p_next_ccb = p_ccb;
+
+ p_ccb->p_next_ccb = NULL;
+ p_ccb->p_prev_ccb = p_q->p_last_ccb;
+ p_q->p_last_ccb = p_ccb;
+ }
+ }
+
+#if (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE)
+ /* Adding CCB into round robin service table of its LCB */
+ if (p_ccb->p_lcb != NULL)
+ {
+ /* if this is the first channel in this priority group */
+ if (p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].num_ccb == 0 )
+ {
+ /* Set the first channel to this CCB */
+ p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_first_ccb = p_ccb;
+ /* Set the next serving channel in this group to this CCB */
+ p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_serve_ccb = p_ccb;
+ /* Initialize quota of this priority group based on its priority */
+ p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].quota = L2CAP_GET_PRIORITY_QUOTA(p_ccb->ccb_priority);
+ }
+ /* increase number of channels in this group */
+ p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].num_ccb++;
+ }
+#endif
+
+}
+
+/******************************************************************************
+**
+** Function l2cu_dequeue_ccb
+**
+** Description dequeue CCB from a queue
+**
+** Returns -
+**
+*******************************************************************************/
+void l2cu_dequeue_ccb (tL2C_CCB *p_ccb)
+{
+ tL2C_CCB_Q *p_q = NULL;
+
+ L2CAP_TRACE_DEBUG1 ("l2cu_dequeue_ccb CID: 0x%04x", p_ccb->local_cid);
+
+ /* Find out which queue the channel is on
+ */
+ if (p_ccb->p_lcb != NULL)
+ p_q = &p_ccb->p_lcb->ccb_queue;
+
+ if ( (!p_ccb->in_use) || (p_q == NULL) || (p_q->p_first_ccb == NULL) )
+ {
+ L2CAP_TRACE_ERROR5 ("l2cu_dequeue_ccb CID: 0x%04x ERROR in_use: %u p_lcb: 0x%08x p_q: 0x%08x p_q->p_first_ccb: 0x%08x",
+ p_ccb->local_cid, p_ccb->in_use, p_ccb->p_lcb, p_q, p_q ? p_q->p_first_ccb : 0);
+ return;
+ }
+
+#if (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE)
+ /* Removing CCB from round robin service table of its LCB */
+ if (p_ccb->p_lcb != NULL)
+ {
+ /* decrease number of channels in this priority group */
+ p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].num_ccb--;
+
+ /* if it was the last channel in the priority group */
+ if (p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].num_ccb == 0 )
+ {
+ p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_first_ccb = NULL;
+ p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_serve_ccb = NULL;
+ }
+ else
+ {
+ /* if it is the first channel of this group */
+ if ( p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_first_ccb == p_ccb )
+ {
+ p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_first_ccb = p_ccb->p_next_ccb;
+ }
+ /* if it is the next serving channel of this group */
+ if ( p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_serve_ccb == p_ccb )
+ {
+ /* simply, start serving from the first channel */
+ p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_serve_ccb
+ = p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_first_ccb;
+ }
+ }
+ }
+#endif
+
+ if (p_ccb == p_q->p_first_ccb)
+ {
+ /* We are removing the first in a queue */
+ p_q->p_first_ccb = p_ccb->p_next_ccb;
+
+ if (p_q->p_first_ccb)
+ p_q->p_first_ccb->p_prev_ccb = NULL;
+ else
+ p_q->p_last_ccb = NULL;
+ }
+ else if (p_ccb == p_q->p_last_ccb)
+ {
+ /* We are removing the last in a queue */
+ p_q->p_last_ccb = p_ccb->p_prev_ccb;
+ p_q->p_last_ccb->p_next_ccb = NULL;
+ }
+ else
+ {
+ /* In the middle of a chain. */
+ p_ccb->p_prev_ccb->p_next_ccb = p_ccb->p_next_ccb;
+ p_ccb->p_next_ccb->p_prev_ccb = p_ccb->p_prev_ccb;
+ }
+
+ p_ccb->p_next_ccb = p_ccb->p_prev_ccb = NULL;
+}
+
+/******************************************************************************
+**
+** Function l2cu_change_pri_ccb
+**
+** Description
+**
+** Returns -
+**
+*******************************************************************************/
+void l2cu_change_pri_ccb (tL2C_CCB *p_ccb, tL2CAP_CHNL_PRIORITY priority)
+{
+ if (p_ccb->ccb_priority != priority)
+ {
+ /* If CCB is not the only guy on the queue */
+ if ( (p_ccb->p_next_ccb != NULL) || (p_ccb->p_prev_ccb != NULL) )
+ {
+ L2CAP_TRACE_DEBUG0 ("Update CCB list in logical link");
+
+ /* Remove CCB from queue and re-queue it at new priority */
+ l2cu_dequeue_ccb (p_ccb);
+
+ p_ccb->ccb_priority = priority;
+ l2cu_enqueue_ccb (p_ccb);
+ }
+#if (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE)
+ else
+ {
+ /* If CCB is the only guy on the queue, no need to re-enqueue */
+ /* update only round robin service data */
+ p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].num_ccb = 0;
+ p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_first_ccb = NULL;
+ p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_serve_ccb = NULL;
+
+ p_ccb->ccb_priority = priority;
+
+ p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_first_ccb = p_ccb;
+ p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_serve_ccb = p_ccb;
+ p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].quota = L2CAP_GET_PRIORITY_QUOTA(p_ccb->ccb_priority);
+ p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].num_ccb = 1;
+ }
+#endif
+ }
+}
+
+/*******************************************************************************
+**
+** Function l2cu_allocate_ccb
+**
+** Description This function allocates a Channel Control Block and
+** attaches it to a link control block. The local CID
+** is also assigned.
+**
+** Returns pointer to CCB, or NULL if none
+**
+*******************************************************************************/
+tL2C_CCB *l2cu_allocate_ccb (tL2C_LCB *p_lcb, UINT16 cid)
+{
+ tL2C_CCB *p_ccb;
+ tL2C_CCB *p_prev;
+
+ L2CAP_TRACE_DEBUG1 ("l2cu_allocate_ccb: cid 0x%04x", cid);
+
+ if (!l2cb.p_free_ccb_first)
+ return (NULL);
+
+ /* If a CID was passed in, use that, else take the first free one */
+ if (cid == 0)
+ {
+ p_ccb = l2cb.p_free_ccb_first;
+ l2cb.p_free_ccb_first = p_ccb->p_next_ccb;
+ }
+ else
+ {
+ p_prev = NULL;
+
+ p_ccb = &l2cb.ccb_pool[cid - L2CAP_BASE_APPL_CID];
+
+ if (p_ccb == l2cb.p_free_ccb_first)
+ l2cb.p_free_ccb_first = p_ccb->p_next_ccb;
+ else
+ {
+ for (p_prev = l2cb.p_free_ccb_first; p_prev != NULL; p_prev = p_prev->p_next_ccb)
+ {
+ if (p_prev->p_next_ccb == p_ccb)
+ {
+ p_prev->p_next_ccb = p_ccb->p_next_ccb;
+
+ if (p_ccb == l2cb.p_free_ccb_last)
+ l2cb.p_free_ccb_last = p_prev;
+
+ break;
+ }
+ }
+ if (p_prev == NULL)
+ {
+ L2CAP_TRACE_ERROR1 ("l2cu_allocate_ccb: could not find CCB for CID 0x%04x in the free list", cid);
+ return NULL;
+ }
+ }
+ }
+
+ p_ccb->p_next_ccb = p_ccb->p_prev_ccb = NULL;
+
+ p_ccb->in_use = TRUE;
+
+ /* Get a CID for the connection */
+ p_ccb->local_cid = L2CAP_BASE_APPL_CID + (UINT16)(p_ccb - l2cb.ccb_pool);
+
+ p_ccb->p_lcb = p_lcb;
+ p_ccb->p_rcb = NULL;
+
+ /* Set priority then insert ccb into LCB queue (if we have an LCB) */
+ p_ccb->ccb_priority = L2CAP_CHNL_PRIORITY_LOW;
+
+ if (p_lcb)
+ l2cu_enqueue_ccb (p_ccb);
+
+ /* clear what peer wants to configure */
+ p_ccb->peer_cfg_bits = 0;
+
+ /* Put in default values for configuration */
+ memset (&p_ccb->our_cfg, 0, sizeof(tL2CAP_CFG_INFO));
+ memset (&p_ccb->peer_cfg, 0, sizeof(tL2CAP_CFG_INFO));
+
+ /* Put in default values for local/peer configurations */
+ p_ccb->our_cfg.flush_to = p_ccb->peer_cfg.flush_to = L2CAP_DEFAULT_FLUSH_TO;
+ p_ccb->our_cfg.mtu = p_ccb->peer_cfg.mtu = L2CAP_DEFAULT_MTU;
+ p_ccb->our_cfg.qos.service_type = p_ccb->peer_cfg.qos.service_type = L2CAP_DEFAULT_SERV_TYPE;
+ p_ccb->our_cfg.qos.token_rate = p_ccb->peer_cfg.qos.token_rate = L2CAP_DEFAULT_TOKEN_RATE;
+ p_ccb->our_cfg.qos.token_bucket_size = p_ccb->peer_cfg.qos.token_bucket_size = L2CAP_DEFAULT_BUCKET_SIZE;
+ p_ccb->our_cfg.qos.peak_bandwidth = p_ccb->peer_cfg.qos.peak_bandwidth = L2CAP_DEFAULT_PEAK_BANDWIDTH;
+ p_ccb->our_cfg.qos.latency = p_ccb->peer_cfg.qos.latency = L2CAP_DEFAULT_LATENCY;
+ p_ccb->our_cfg.qos.delay_variation = p_ccb->peer_cfg.qos.delay_variation = L2CAP_DEFAULT_DELAY;
+
+ p_ccb->bypass_fcs = 0;
+ memset (&p_ccb->ertm_info, 0, sizeof(tL2CAP_ERTM_INFO));
+ p_ccb->peer_cfg_already_rejected = FALSE;
+ p_ccb->fcr_cfg_tries = L2CAP_MAX_FCR_CFG_TRIES;
+ p_ccb->fcrb.ack_timer.param = (TIMER_PARAM_TYPE)p_ccb;
+
+ /* if timer is running, remove it from timer list */
+ if (p_ccb->fcrb.ack_timer.in_use)
+ btu_stop_quick_timer (&p_ccb->fcrb.ack_timer);
+
+ p_ccb->fcrb.mon_retrans_timer.param = (TIMER_PARAM_TYPE)p_ccb;
+
+// btla-specific ++
+ /* CSP408639 Fix: When L2CAP send amp move channel request or receive
+ * L2CEVT_AMP_MOVE_REQ do following sequence. Send channel move
+ * request -> Stop retrans/monitor timer -> Change channel state to CST_AMP_MOVING. */
+ if (p_ccb->fcrb.mon_retrans_timer.in_use)
+ btu_stop_quick_timer (&p_ccb->fcrb.mon_retrans_timer);
+// btla-specific --
+
+ l2c_fcr_stop_timer (p_ccb);
+
+ p_ccb->ertm_info.preferred_mode = L2CAP_FCR_BASIC_MODE; /* Default mode for channel is basic mode */
+ p_ccb->ertm_info.allowed_modes = L2CAP_FCR_CHAN_OPT_BASIC; /* Default mode for channel is basic mode */
+ p_ccb->ertm_info.fcr_rx_pool_id = L2CAP_FCR_RX_POOL_ID;
+ p_ccb->ertm_info.fcr_tx_pool_id = L2CAP_FCR_TX_POOL_ID;
+ p_ccb->ertm_info.user_rx_pool_id = HCI_ACL_POOL_ID;
+ p_ccb->ertm_info.user_tx_pool_id = HCI_ACL_POOL_ID;
+ p_ccb->max_rx_mtu = L2CAP_MTU_SIZE;
+ p_ccb->tx_mps = GKI_get_pool_bufsize(HCI_ACL_POOL_ID) - 32;
+
+ GKI_init_q (&p_ccb->xmit_hold_q);
+
+ p_ccb->cong_sent = FALSE;
+ p_ccb->buff_quota = 2; /* This gets set after config */
+
+ /* If CCB was reserved Config_Done can already have some value */
+ if (cid == 0)
+ p_ccb->config_done = 0;
+ else
+ {
+ L2CAP_TRACE_DEBUG2 ("l2cu_allocate_ccb: cid 0x%04x config_done:0x%x", cid, p_ccb->config_done);
+ }
+
+ p_ccb->chnl_state = CST_CLOSED;
+ p_ccb->flags = 0;
+ p_ccb->tx_data_rate = L2CAP_CHNL_DATA_RATE_LOW;
+ p_ccb->rx_data_rate = L2CAP_CHNL_DATA_RATE_LOW;
+
+#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
+ p_ccb->is_flushable = FALSE;
+#endif
+
+ p_ccb->timer_entry.param = (TIMER_PARAM_TYPE)p_ccb;
+ p_ccb->timer_entry.in_use = 0;
+
+ l2c_link_adjust_chnl_allocation ();
+
+ return (p_ccb);
+}
+
+/*******************************************************************************
+**
+** Function l2cu_start_post_bond_timer
+**
+** Description This function starts the ACL Link inactivity timer after
+** dedicated bonding
+** This timer can be longer than the normal link inactivity
+** timer for some platforms.
+**
+** Returns BOOLEAN - TRUE if idle timer started or disconnect initiated
+** FALSE if there's one or more pending CCB's exist
+**
+*******************************************************************************/
+BOOLEAN l2cu_start_post_bond_timer (UINT16 handle)
+{
+ UINT16 timeout;
+ tL2C_LCB *p_lcb = l2cu_find_lcb_by_handle(handle);
+
+ if (!p_lcb)
+ return (TRUE);
+
+ p_lcb->is_bonding = FALSE;
+
+ /* Only start timer if no control blocks allocated */
+ if (p_lcb->ccb_queue.p_first_ccb != NULL)
+ return (FALSE);
+
+ /* If no channels on the connection, start idle timeout */
+ if ( (p_lcb->link_state == LST_CONNECTED) || (p_lcb->link_state == LST_CONNECTING) || (p_lcb->link_state == LST_DISCONNECTING) )
+ {
+ if (p_lcb->idle_timeout == 0)
+ {
+ if (btsnd_hcic_disconnect (p_lcb->handle, HCI_ERR_PEER_USER))
+ {
+ p_lcb->link_state = LST_DISCONNECTING;
+ timeout = L2CAP_LINK_DISCONNECT_TOUT;
+ }
+ else
+ timeout = BT_1SEC_TIMEOUT;
+ }
+ else
+ {
+ timeout = L2CAP_BONDING_TIMEOUT;
+ }
+
+ if (timeout != 0xFFFF)
+ btu_start_timer (&p_lcb->timer_entry, BTU_TTYPE_L2CAP_LINK, timeout);
+
+ return (TRUE);
+ }
+
+ return (FALSE);
+}
+
+/*******************************************************************************
+**
+** Function l2cu_release_ccb
+**
+** Description This function releases a Channel Control Block. The timer
+** is stopped, any attached buffers freed, and the CCB is removed
+** from the link control block.
+**
+** Returns void
+**
+*******************************************************************************/
+void l2cu_release_ccb (tL2C_CCB *p_ccb)
+{
+ tL2C_LCB *p_lcb = p_ccb->p_lcb;
+ tL2C_RCB *p_rcb = p_ccb->p_rcb;
+
+ L2CAP_TRACE_DEBUG2 ("l2cu_release_ccb: cid 0x%04x in_use: %u", p_ccb->local_cid, p_ccb->in_use);
+
+ /* If already released, could be race condition */
+ if (!p_ccb->in_use)
+ return;
+
+ if (p_rcb && (p_rcb->psm != p_rcb->real_psm))
+ {
+ btm_sec_clr_service_by_psm(p_rcb->psm);
+ }
+ /* Stop the timer */
+ btu_stop_timer (&p_ccb->timer_entry);
+
+ while (p_ccb->xmit_hold_q.p_first)
+ GKI_freebuf (GKI_dequeue (&p_ccb->xmit_hold_q));
+
+ l2c_fcr_cleanup (p_ccb);
+
+ /* Channel may not be assigned to any LCB if it was just pre-reserved */
+ if ( (p_lcb) &&
+ ( (p_ccb->local_cid >= L2CAP_BASE_APPL_CID)
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ ||(p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID)
+#endif
+ )
+ )
+ {
+ l2cu_dequeue_ccb (p_ccb);
+
+ /* Delink the CCB from the LCB */
+ p_ccb->p_lcb = NULL;
+ }
+
+ /* Put the CCB back on the free pool */
+ if (!l2cb.p_free_ccb_first)
+ {
+ l2cb.p_free_ccb_first = p_ccb;
+ l2cb.p_free_ccb_last = p_ccb;
+ p_ccb->p_next_ccb = NULL;
+ p_ccb->p_prev_ccb = NULL;
+ }
+ else
+ {
+ p_ccb->p_next_ccb = NULL;
+ p_ccb->p_prev_ccb = l2cb.p_free_ccb_last;
+ l2cb.p_free_ccb_last->p_next_ccb = p_ccb;
+ l2cb.p_free_ccb_last = p_ccb;
+ }
+
+ /* Flag as not in use */
+ p_ccb->in_use = FALSE;
+
+ /* If no channels on the connection, start idle timeout */
+ if ((p_lcb) && p_lcb->in_use && (p_lcb->link_state == LST_CONNECTED))
+ {
+ if (!p_lcb->ccb_queue.p_first_ccb)
+ {
+ l2cu_no_dynamic_ccbs (p_lcb);
+ }
+ else
+ {
+ /* Link is still active, adjust channel quotas. */
+ l2c_link_adjust_chnl_allocation ();
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function l2cu_find_ccb_by_remote_cid
+**
+** Description Look through all active CCBs on a link for a match based
+** on the remote CID.
+**
+** Returns pointer to matched CCB, or NULL if no match
+**
+*******************************************************************************/
+tL2C_CCB *l2cu_find_ccb_by_remote_cid (tL2C_LCB *p_lcb, UINT16 remote_cid)
+{
+ tL2C_CCB *p_ccb;
+
+ /* If LCB is NULL, look through all active links */
+ if (!p_lcb)
+ {
+ return NULL;
+ }
+ else
+ {
+ for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; p_ccb = p_ccb->p_next_ccb)
+ if ((p_ccb->in_use) && (p_ccb->remote_cid == remote_cid))
+ return (p_ccb);
+ }
+
+ /* If here, no match found */
+ return (NULL);
+}
+
+/*******************************************************************************
+**
+** Function l2cu_allocate_rcb
+**
+** Description Look through the Registration Control Blocks for a free
+** one.
+**
+** Returns Pointer to the RCB or NULL if not found
+**
+*******************************************************************************/
+tL2C_RCB *l2cu_allocate_rcb (UINT16 psm)
+{
+ tL2C_RCB *p_rcb = &l2cb.rcb_pool[0];
+ UINT16 xx;
+
+ for (xx = 0; xx < MAX_L2CAP_CLIENTS; xx++, p_rcb++)
+ {
+ if (!p_rcb->in_use)
+ {
+ p_rcb->in_use = TRUE;
+ p_rcb->psm = psm;
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ p_rcb->ucd.state = L2C_UCD_STATE_UNUSED;
+#endif
+ return (p_rcb);
+ }
+ }
+
+ /* If here, no free RCB found */
+ return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function l2cu_release_rcb
+**
+** Description Mark an RCB as no longet in use
+**
+** Returns void
+**
+*******************************************************************************/
+void l2cu_release_rcb (tL2C_RCB *p_rcb)
+{
+ p_rcb->in_use = FALSE;
+ p_rcb->psm = 0;
+}
+
+
+/*******************************************************************************
+**
+** Function l2cu_disconnect_chnl
+**
+** Description Disconnect a channel. Typically, this is due to either
+** receiving a bad configuration, bad packet or max_retries expiring.
+**
+*******************************************************************************/
+void l2cu_disconnect_chnl (tL2C_CCB *p_ccb)
+{
+ UINT16 local_cid = p_ccb->local_cid;
+
+ if (local_cid >= L2CAP_BASE_APPL_CID)
+ {
+ tL2CA_DISCONNECT_IND_CB *p_disc_cb = p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb;
+
+ L2CAP_TRACE_WARNING1 ("L2CAP - disconnect_chnl CID: 0x%04x", local_cid);
+
+ l2cu_send_peer_disc_req (p_ccb);
+
+ l2cu_release_ccb (p_ccb);
+
+ (*p_disc_cb)(local_cid, FALSE);
+ }
+ else
+ {
+ /* failure on the AMP channel, probably need to disconnect ACL */
+ L2CAP_TRACE_ERROR1 ("L2CAP - disconnect_chnl CID: 0x%04x Ignored", local_cid);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function l2cu_find_rcb_by_psm
+**
+** Description Look through the Registration Control Blocks to see if
+** anyone registered to handle the PSM in question
+**
+** Returns Pointer to the RCB or NULL if not found
+**
+*******************************************************************************/
+tL2C_RCB *l2cu_find_rcb_by_psm (UINT16 psm)
+{
+ tL2C_RCB *p_rcb = &l2cb.rcb_pool[0];
+ UINT16 xx;
+
+ for (xx = 0; xx < MAX_L2CAP_CLIENTS; xx++, p_rcb++)
+ {
+ if ((p_rcb->in_use) && (p_rcb->psm == psm))
+ return (p_rcb);
+ }
+
+ /* If here, no match found */
+ return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function l2cu_process_peer_cfg_req
+**
+** Description This function is called when the peer sends us a "config request"
+** message. It extracts the configuration of interest and saves
+** it in the CCB.
+**
+** Note: Negotiation of the FCR channel type is handled internally,
+** all others are passed to the upper layer.
+**
+** Returns UINT8 - L2CAP_PEER_CFG_OK if passed to upper layer,
+** L2CAP_PEER_CFG_UNACCEPTABLE if automatically responded to
+** because parameters are unnacceptable from a specification
+** point of view.
+** L2CAP_PEER_CFG_DISCONNECT if no compatible channel modes
+** between the two devices, and shall be closed.
+**
+*******************************************************************************/
+UINT8 l2cu_process_peer_cfg_req (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg)
+{
+ BOOLEAN mtu_ok = TRUE;
+ BOOLEAN qos_type_ok = TRUE;
+ BOOLEAN flush_to_ok = TRUE;
+ BOOLEAN fcr_ok = TRUE;
+ UINT8 fcr_status;
+
+ /* Ignore FCR parameters for basic mode */
+ if (!p_cfg->fcr_present)
+ p_cfg->fcr.mode = L2CAP_FCR_BASIC_MODE;
+
+ /* Save the MTU that our peer can receive */
+ if (p_cfg->mtu_present)
+ {
+ /* Make sure MTU is at least the minimum */
+ if (p_cfg->mtu >= L2CAP_MIN_MTU)
+ {
+ /* In basic mode, limit the MTU to our buffer size */
+ if ( (p_cfg->fcr_present == FALSE) && (p_cfg->mtu > L2CAP_MTU_SIZE) )
+ p_cfg->mtu = L2CAP_MTU_SIZE;
+
+ /* Save the accepted value in case of renegotiation */
+ p_ccb->peer_cfg.mtu = p_cfg->mtu;
+ p_ccb->peer_cfg.mtu_present = TRUE;
+ p_ccb->peer_cfg_bits |= L2CAP_CH_CFG_MASK_MTU;
+ }
+ else /* Illegal MTU value */
+ {
+ p_cfg->mtu = L2CAP_MIN_MTU;
+ mtu_ok = FALSE;
+ }
+ }
+ /* Reload mtu from a previously accepted config request */
+ else if (p_ccb->peer_cfg.mtu_present)
+ {
+ p_cfg->mtu_present = TRUE;
+ p_cfg->mtu = p_ccb->peer_cfg.mtu;
+ }
+
+ /* Verify that the flush timeout is a valid value (0 is illegal) */
+ if (p_cfg->flush_to_present)
+ {
+ if (!p_cfg->flush_to)
+ {
+ p_cfg->flush_to = 0xFFFF; /* Infinite retransmissions (spec default) */
+ flush_to_ok = FALSE;
+ }
+ else /* Save the accepted value in case of renegotiation */
+ {
+ p_ccb->peer_cfg.flush_to_present = TRUE;
+ p_ccb->peer_cfg.flush_to = p_cfg->flush_to;
+ p_ccb->peer_cfg_bits |= L2CAP_CH_CFG_MASK_FLUSH_TO;
+ }
+ }
+ /* Reload flush_to from a previously accepted config request */
+ else if (p_ccb->peer_cfg.flush_to_present)
+ {
+ p_cfg->flush_to_present = TRUE;
+ p_cfg->flush_to = p_ccb->peer_cfg.flush_to;
+ }
+
+ /* Save the QOS settings the the peer is using */
+ if (p_cfg->qos_present)
+ {
+ /* Make sure service type is not a reserved value; otherwise let upper
+ layer decide if acceptable
+ */
+ if (p_cfg->qos.service_type <= GUARANTEED)
+ {
+ p_ccb->peer_cfg.qos = p_cfg->qos;
+ p_ccb->peer_cfg.qos_present = TRUE;
+ p_ccb->peer_cfg_bits |= L2CAP_CH_CFG_MASK_QOS;
+ }
+ else /* Illegal service type value */
+ {
+ p_cfg->qos.service_type = BEST_EFFORT;
+ qos_type_ok = FALSE;
+ }
+ }
+ /* Reload QOS from a previously accepted config request */
+ else if (p_ccb->peer_cfg.qos_present)
+ {
+ p_cfg->qos_present = TRUE;
+ p_cfg->qos = p_ccb->peer_cfg.qos;
+ }
+
+ if ((fcr_status = l2c_fcr_process_peer_cfg_req (p_ccb, p_cfg)) == L2CAP_PEER_CFG_DISCONNECT)
+ {
+ /* Notify caller to disconnect the channel (incompatible modes) */
+ p_cfg->result = L2CAP_CFG_FAILED_NO_REASON;
+ p_cfg->mtu_present = p_cfg->qos_present = p_cfg->flush_to_present = 0;
+
+ return (L2CAP_PEER_CFG_DISCONNECT);
+ }
+
+ fcr_ok = (fcr_status == L2CAP_PEER_CFG_OK);
+
+ /* Return any unacceptable parameters */
+ if (mtu_ok && flush_to_ok && qos_type_ok && fcr_ok)
+ {
+ l2cu_adjust_out_mps (p_ccb);
+ return (L2CAP_PEER_CFG_OK);
+ }
+ else
+ {
+ p_cfg->result = L2CAP_CFG_UNACCEPTABLE_PARAMS;
+
+ if (mtu_ok)
+ p_cfg->mtu_present = FALSE;
+ if (flush_to_ok)
+ p_cfg->flush_to_present = FALSE;
+ if (qos_type_ok)
+ p_cfg->qos_present = FALSE;
+ if (fcr_ok)
+ p_cfg->fcr_present = FALSE;
+
+ return (L2CAP_PEER_CFG_UNACCEPTABLE);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function l2cu_process_peer_cfg_rsp
+**
+** Description This function is called when the peer sends us a "config response"
+** message. It extracts the configuration of interest and saves
+** it in the CCB.
+**
+** Returns void
+**
+*******************************************************************************/
+void l2cu_process_peer_cfg_rsp (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg)
+{
+ /* If we wanted QoS and the peer sends us a positive response with QoS, use his values */
+ if ( (p_cfg->qos_present) && (p_ccb->our_cfg.qos_present) )
+ p_ccb->our_cfg.qos = p_cfg->qos;
+
+ if (p_cfg->fcr_present)
+ {
+ /* Save the retransmission and monitor timeout values */
+ if (p_cfg->fcr.mode == L2CAP_FCR_ERTM_MODE)
+ {
+ p_ccb->peer_cfg.fcr.rtrans_tout = p_cfg->fcr.rtrans_tout;
+ p_ccb->peer_cfg.fcr.mon_tout = p_cfg->fcr.mon_tout;
+ }
+
+ /* Calculate the max number of packets for which we can delay sending an ack */
+ if (p_cfg->fcr.tx_win_sz < p_ccb->our_cfg.fcr.tx_win_sz)
+ p_ccb->fcrb.max_held_acks = p_cfg->fcr.tx_win_sz / 3;
+ else
+ p_ccb->fcrb.max_held_acks = p_ccb->our_cfg.fcr.tx_win_sz / 3;
+
+ L2CAP_TRACE_DEBUG3 ("l2cu_process_peer_cfg_rsp(): peer tx_win_sz: %d, our tx_win_sz: %d, max_held_acks: %d",
+ p_cfg->fcr.tx_win_sz, p_ccb->our_cfg.fcr.tx_win_sz, p_ccb->fcrb.max_held_acks);
+ }
+}
+
+/*******************************************************************************
+**
+** Function l2cu_process_our_cfg_req
+**
+** Description This function is called when we send a "config request"
+** message. It extracts the configuration of interest and saves
+** it in the CCB.
+**
+** Returns void
+**
+*******************************************************************************/
+void l2cu_process_our_cfg_req (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg)
+{
+ tL2C_LCB *p_lcb;
+ UINT16 hci_flush_to;
+
+ /* Save the QOS settings we are using for transmit */
+ if (p_cfg->qos_present)
+ {
+ p_ccb->our_cfg.qos_present = TRUE;
+ p_ccb->our_cfg.qos = p_cfg->qos;
+ }
+
+ if (p_cfg->fcr_present)
+ {
+ /* Override FCR options if attempting streaming or basic */
+ if (p_cfg->fcr.mode == L2CAP_FCR_BASIC_MODE)
+ memset(&p_cfg->fcr, 0, sizeof(tL2CAP_FCR_OPTS));
+ else
+ {
+ /* On BR/EDR, timer values are zero in config request */
+ /* On class 2 AMP, timer value in config request shall be non-0 processing time */
+ /* timer value in config response shall be greater than received processing time */
+ p_cfg->fcr.mon_tout = p_cfg->fcr.rtrans_tout = 0;
+
+ if (p_cfg->fcr.mode == L2CAP_FCR_STREAM_MODE)
+ p_cfg->fcr.max_transmit = p_cfg->fcr.tx_win_sz = 0;
+ }
+
+ /* Set the threshold to send acks (may be updated in the cfg response) */
+ p_ccb->fcrb.max_held_acks = p_cfg->fcr.tx_win_sz / 3;
+
+ /* Include FCS option only if peer can handle it */
+ if (p_ccb->p_lcb->peer_ext_fea & L2CAP_EXTFEA_NO_CRC)
+ {
+ /* FCS check can be bypassed if peer also desires to bypass */
+ if (p_cfg->fcs_present && p_cfg->fcs == L2CAP_CFG_FCS_BYPASS)
+ p_ccb->bypass_fcs |= L2CAP_CFG_FCS_OUR;
+ }
+ else
+ p_cfg->fcs_present = FALSE;
+ }
+ else
+ {
+ p_cfg->fcr.mode = L2CAP_FCR_BASIC_MODE;
+ }
+
+ p_ccb->our_cfg.fcr.mode = p_cfg->fcr.mode;
+ p_ccb->our_cfg.fcr_present = p_cfg->fcr_present;
+
+ /* Check the flush timeout. If it is lower than the current one used */
+ /* then we need to adjust the flush timeout sent to the controller */
+ if (p_cfg->flush_to_present)
+ {
+ if ((p_cfg->flush_to == 0)||(p_cfg->flush_to == L2CAP_NO_AUTOMATIC_FLUSH))
+ {
+ /* don't send invalid flush timeout */
+ /* SPEC: The sender of the Request shall specify its flush timeout value */
+ /* if it differs from the default value of 0xFFFF */
+ p_cfg->flush_to_present = FALSE;
+ }
+ else
+ {
+ p_ccb->our_cfg.flush_to = p_cfg->flush_to;
+ p_lcb = p_ccb->p_lcb;
+
+ if (p_cfg->flush_to < p_lcb->link_flush_tout)
+ {
+ p_lcb->link_flush_tout = p_cfg->flush_to;
+
+ /* If the timeout is within range of HCI, set the flush timeout */
+ if (p_cfg->flush_to <= ((HCI_MAX_AUTO_FLUSH_TOUT * 5) / 8))
+ {
+ /* Convert flush timeout to 0.625 ms units, with round */
+ hci_flush_to = ((p_cfg->flush_to * 8) + 3) / 5;
+ btsnd_hcic_write_auto_flush_tout (p_lcb->handle, hci_flush_to);
+ }
+ }
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function l2cu_process_our_cfg_rsp
+**
+** Description This function is called when we send the peer a "config response"
+** message. It extracts the configuration of interest and saves
+** it in the CCB.
+**
+** Returns void
+**
+*******************************************************************************/
+void l2cu_process_our_cfg_rsp (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg)
+{
+ /* If peer wants QoS, we are allowed to change the values in a positive response */
+ if ( (p_cfg->qos_present) && (p_ccb->peer_cfg.qos_present) )
+ p_ccb->peer_cfg.qos = p_cfg->qos;
+ else
+ p_cfg->qos_present = FALSE;
+
+ l2c_fcr_adj_our_rsp_options (p_ccb, p_cfg);
+}
+
+
+/*******************************************************************************
+**
+** Function l2cu_device_reset
+**
+** Description This function is called when reset of the device is
+** completed. For all active connection simulate HCI_DISC
+**
+** Returns void
+**
+*******************************************************************************/
+void l2cu_device_reset (void)
+{
+ int xx;
+ tL2C_LCB *p_lcb = &l2cb.lcb_pool[0];
+
+ for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_lcb++)
+ {
+ if ((p_lcb->in_use) && (p_lcb->handle != HCI_INVALID_HANDLE))
+ {
+ l2c_link_hci_disc_comp (p_lcb->handle, (UINT8) -1);
+ }
+ }
+}
+
+#if (TCS_WUG_MEMBER_INCLUDED == TRUE && TCS_INCLUDED == TRUE)
+extern UINT16 tcs_wug_get_clk_offset( BD_ADDR addr ) ;
+#endif
+
+/*******************************************************************************
+**
+** Function l2cu_create_conn
+**
+** Description This function initiates an acl connection via HCI
+**
+** Returns TRUE if successful, FALSE if gki get buffer fails.
+**
+*******************************************************************************/
+BOOLEAN l2cu_create_conn (tL2C_LCB *p_lcb)
+{
+ int xx;
+ tL2C_LCB *p_lcb_cur = &l2cb.lcb_pool[0];
+#if BTM_SCO_INCLUDED == TRUE
+ BOOLEAN is_sco_active;
+#endif
+
+#if (BLE_INCLUDED == TRUE)
+ tBT_DEVICE_TYPE dev_type;
+ tBLE_ADDR_TYPE addr_type;
+
+ BTM_ReadDevInfo(p_lcb->remote_bd_addr, &dev_type, &addr_type);
+
+ if (dev_type == BT_DEVICE_TYPE_BLE)
+ {
+ p_lcb->ble_addr_type = addr_type;
+ p_lcb->is_ble_link = TRUE;
+
+ return (l2cble_create_conn(p_lcb));
+ }
+#endif
+
+ /* If there is a connection where we perform as a slave, try to switch roles
+ for this connection */
+ for (xx = 0, p_lcb_cur = &l2cb.lcb_pool[0]; xx < MAX_L2CAP_LINKS; xx++, p_lcb_cur++)
+ {
+ if (p_lcb_cur == p_lcb)
+ continue;
+
+ if ((p_lcb_cur->in_use) && (p_lcb_cur->link_role == HCI_ROLE_SLAVE))
+ {
+
+#if BTM_SCO_INCLUDED == TRUE
+ /* The LMP_switch_req shall be sent only if the ACL logical transport
+ is in active mode, when encryption is disabled, and all synchronous
+ logical transports on the same physical link are disabled." */
+
+ /* Check if there is any SCO Active on this BD Address */
+ is_sco_active = btm_is_sco_active_by_bdaddr(p_lcb_cur->remote_bd_addr);
+
+ L2CAP_TRACE_API1 ("l2cu_create_conn - btm_is_sco_active_by_bdaddr() is_sco_active = %s", \
+ (is_sco_active == TRUE) ? "TRUE":"FALSE");
+
+ if (is_sco_active == TRUE)
+ continue; /* No Master Slave switch not allowed when SCO Active */
+#endif
+
+ if (HCI_SWITCH_SUPPORTED(btm_cb.devcb.local_features))
+ {
+ /* mark this lcb waiting for switch to be completed and
+ start switch on the other one */
+ p_lcb->link_state = LST_CONNECTING_WAIT_SWITCH;
+ p_lcb->link_role = HCI_ROLE_MASTER;
+
+ if (BTM_SwitchRole (p_lcb_cur->remote_bd_addr, HCI_ROLE_MASTER, NULL) == BTM_CMD_STARTED)
+ {
+ btu_start_timer (&p_lcb->timer_entry, BTU_TTYPE_L2CAP_LINK, L2CAP_LINK_ROLE_SWITCH_TOUT);
+ return (TRUE);
+ }
+ }
+ }
+ }
+
+ p_lcb->link_state = LST_CONNECTING;
+
+ return (l2cu_create_conn_after_switch (p_lcb));
+}
+
+/*******************************************************************************
+**
+** Function l2cu_get_num_hi_priority
+**
+** Description Gets the number of high priority channels.
+**
+** Returns
+**
+*******************************************************************************/
+UINT8 l2cu_get_num_hi_priority (void)
+{
+ UINT8 no_hi = 0;
+ int xx;
+ tL2C_LCB *p_lcb = &l2cb.lcb_pool[0];
+
+ for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_lcb++)
+ {
+ if ((p_lcb->in_use) && (p_lcb->acl_priority == L2CAP_PRIORITY_HIGH))
+ {
+ no_hi++;
+ }
+ }
+ return no_hi;
+}
+
+
+/*******************************************************************************
+**
+** Function l2cu_create_conn_after_switch
+**
+** Description This function initiates an acl connection via HCI
+** If switch required to create connection it is already done.
+**
+** Returns TRUE if successful, FALSE if gki get buffer fails.
+**
+*******************************************************************************/
+
+BOOLEAN l2cu_create_conn_after_switch (tL2C_LCB *p_lcb)
+{
+ UINT8 allow_switch = HCI_CR_CONN_ALLOW_SWITCH;
+ tBTM_INQ_INFO *p_inq_info;
+ UINT8 page_scan_rep_mode;
+ UINT8 page_scan_mode;
+ UINT16 clock_offset;
+ UINT8 *p_features;
+ UINT16 num_acl = BTM_GetNumAclLinks();
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (p_lcb->remote_bd_addr);
+ UINT8 no_hi_prio_chs = l2cu_get_num_hi_priority();
+
+ p_features = BTM_ReadLocalFeatures();
+
+ L2CAP_TRACE_DEBUG4 ("l2cu_create_conn_after_switch :%d num_acl:%d no_hi: %d is_bonding:%d",
+ l2cb.disallow_switch, num_acl, no_hi_prio_chs, p_lcb->is_bonding);
+ /* FW team says that we can participant in 4 piconets
+ * typically 3 piconet + 1 for scanning.
+ * We can enhance the code to count the number of piconets later. */
+ if ( ((!l2cb.disallow_switch && (num_acl < 3)) || (p_lcb->is_bonding && (no_hi_prio_chs==0)))
+ && HCI_SWITCH_SUPPORTED(p_features))
+ allow_switch = HCI_CR_CONN_ALLOW_SWITCH;
+ else
+ allow_switch = HCI_CR_CONN_NOT_ALLOW_SWITCH;
+
+ p_lcb->link_state = LST_CONNECTING;
+
+
+#if (TCS_WUG_MEMBER_INCLUDED == TRUE && TCS_INCLUDED == TRUE)
+ if ( (clock_offset = tcs_wug_get_clk_offset( p_lcb->remote_bd_addr )) != 0 )
+ {
+ page_scan_rep_mode = HCI_PAGE_SCAN_REP_MODE_R0;
+ page_scan_mode = HCI_MANDATARY_PAGE_SCAN_MODE;
+ }
+ else
+ {
+#endif
+
+ /* Check with the BT manager if details about remote device are known */
+ if ((p_inq_info = BTM_InqDbRead(p_lcb->remote_bd_addr)) != NULL)
+ {
+ page_scan_rep_mode = p_inq_info->results.page_scan_rep_mode;
+ page_scan_mode = p_inq_info->results.page_scan_mode;
+ clock_offset = (UINT16)(p_inq_info->results.clock_offset);
+ }
+ else
+ {
+ /* No info known. Use default settings */
+ page_scan_rep_mode = HCI_PAGE_SCAN_REP_MODE_R1;
+ page_scan_mode = HCI_MANDATARY_PAGE_SCAN_MODE;
+
+ clock_offset = (p_dev_rec) ? p_dev_rec->clock_offset : 0;
+ }
+#if (TCS_WUG_MEMBER_INCLUDED == TRUE && TCS_INCLUDED == TRUE)
+ }
+#endif
+
+ if (!btsnd_hcic_create_conn (p_lcb->remote_bd_addr,
+ HCI_PKT_TYPES_MASK_DM1 + HCI_PKT_TYPES_MASK_DH1,
+ page_scan_rep_mode,
+ page_scan_mode,
+ clock_offset,
+ allow_switch))
+
+ {
+ L2CAP_TRACE_ERROR0 ("L2CAP - no buffer for l2cu_create_conn");
+ l2cu_release_lcb (p_lcb);
+ return (FALSE);
+ }
+
+#if (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE)
+ btm_acl_update_busy_level (BTM_BLI_PAGE_EVT);
+#endif
+
+ btu_start_timer (&p_lcb->timer_entry, BTU_TTYPE_L2CAP_LINK,
+ L2CAP_LINK_CONNECT_TOUT);
+
+ return (TRUE);
+}
+
+
+/*******************************************************************************
+**
+** Function l2cu_find_lcb_by_state
+**
+** Description Look through all active LCBs for a match based on the
+** LCB state.
+**
+** Returns pointer to first matched LCB, or NULL if no match
+**
+*******************************************************************************/
+tL2C_LCB *l2cu_find_lcb_by_state (tL2C_LINK_STATE state)
+{
+ UINT16 i;
+ tL2C_LCB *p_lcb = &l2cb.lcb_pool[0];
+
+ for (i = 0; i < MAX_L2CAP_LINKS; i++, p_lcb++)
+ {
+ if ((p_lcb->in_use) && (p_lcb->link_state == state))
+ {
+ return (p_lcb);
+ }
+ }
+
+ /* If here, no match found */
+ return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function l2cu_lcb_disconnecting
+**
+** Description On each active lcb, check if the lcb is in disconnecting
+** state, or if there are no ccb's on the lcb (implying
+ idle timeout is running), or if last ccb on the link
+ is in disconnecting state.
+**
+** Returns TRUE if any of above conditions met, FALSE otherwise
+**
+*******************************************************************************/
+BOOLEAN l2cu_lcb_disconnecting (void)
+{
+ tL2C_LCB *p_lcb;
+ tL2C_CCB *p_ccb;
+ UINT16 i;
+ BOOLEAN status = FALSE;
+
+ p_lcb = &l2cb.lcb_pool[0];
+
+ for (i = 0; i < MAX_L2CAP_LINKS; i++, p_lcb++)
+ {
+ if (p_lcb->in_use)
+ {
+ /* no ccbs on lcb, or lcb is in disconnecting state */
+ if ((!p_lcb->ccb_queue.p_first_ccb) || (p_lcb->link_state == LST_DISCONNECTING))
+ {
+ status = TRUE;
+ break;
+ }
+ /* only one ccb left on lcb */
+ else if (p_lcb->ccb_queue.p_first_ccb == p_lcb->ccb_queue.p_last_ccb)
+ {
+ p_ccb = p_lcb->ccb_queue.p_first_ccb;
+
+ if ((p_ccb->in_use) &&
+ ((p_ccb->chnl_state == CST_W4_L2CAP_DISCONNECT_RSP) ||
+ (p_ccb->chnl_state == CST_W4_L2CA_DISCONNECT_RSP)))
+ {
+ status = TRUE;
+ break;
+ }
+ }
+ }
+ }
+ return status;
+}
+
+
+/*******************************************************************************
+**
+** Function l2cu_set_acl_priority
+**
+** Description Sets the transmission priority for a channel.
+** (For initial implementation only two values are valid.
+** L2CAP_PRIORITY_NORMAL and L2CAP_PRIORITY_HIGH).
+**
+** Returns TRUE if a valid channel, else FALSE
+**
+*******************************************************************************/
+BOOLEAN l2cu_set_acl_priority (BD_ADDR bd_addr, UINT8 priority, BOOLEAN reset_after_rs)
+{
+ tL2C_LCB *p_lcb;
+#ifdef BRCM_VS
+ UINT8 *pp;
+ UINT8 command[HCI_BRCM_ACL_PRIORITY_PARAM_SIZE];
+ UINT8 vs_param;
+#endif
+
+ /* Find the link control block for the acl channel */
+ if ((p_lcb = l2cu_find_lcb_by_bd_addr(bd_addr)) == NULL)
+ {
+ L2CAP_TRACE_WARNING0 ("L2CAP - no LCB for L2CA_SetAclPriority");
+ return (FALSE);
+ }
+
+#ifdef BRCM_VS
+ if (BTM_IS_BRCM_CONTROLLER())
+ {
+ /* Called from above L2CAP through API; send VSC if changed */
+ if ((!reset_after_rs && (priority != p_lcb->acl_priority)) ||
+
+ /* Called because of a master/slave role switch; if high resend VSC */
+ ( reset_after_rs && p_lcb->acl_priority == L2CAP_PRIORITY_HIGH))
+ {
+ pp = command;
+
+ vs_param = (priority == L2CAP_PRIORITY_HIGH) ? HCI_BRCM_ACL_PRIORITY_HIGH : HCI_BRCM_ACL_PRIORITY_LOW;
+
+ UINT16_TO_STREAM (pp, p_lcb->handle);
+ UINT8_TO_STREAM (pp, vs_param);
+
+ BTM_VendorSpecificCommand (HCI_BRCM_SET_ACL_PRIORITY, HCI_BRCM_ACL_PRIORITY_PARAM_SIZE, command, NULL);
+
+ /* Adjust lmp buffer allocation for this channel if priority changed */
+ if (p_lcb->acl_priority != priority)
+ {
+ p_lcb->acl_priority = priority;
+ l2c_link_adjust_allocation();
+ }
+ }
+ }
+#endif
+ return(TRUE);
+}
+
+#if (L2CAP_ENHANCED_FEATURES != 0)
+/*******************************************************************************
+**
+** Function l2cu_send_feature_req
+**
+** Description Called at connection establishment by the originator
+** of the connection to send an L2CAP Echo request message
+** to the peer to determine if he supports Widcomm proprietary
+** features.
+**
+** Returns void
+**
+*******************************************************************************/
+void l2cu_send_feature_req (tL2C_CCB *p_ccb)
+{
+ UINT8 saved_id;
+ UINT8 buff[100], *p = buff;
+
+ UINT8_TO_STREAM (p, 'R');
+ UINT8_TO_STREAM (p, 'Q');
+
+ UINT8_TO_STREAM (p, 'r');
+ UINT8_TO_STREAM (p, 'q');
+
+ /* save current ID to be restored after feature request */
+ saved_id = p_ccb->p_lcb->id;
+
+ /* Set appropriate ID */
+ p_ccb->p_lcb->id = L2CAP_FEATURE_REQ_ID - 1;
+
+ l2cu_send_peer_echo_req (p_ccb->p_lcb, buff, (UINT16)(p - buff));
+
+ /* packet has been built so we can restore the control block id */
+ p_ccb->p_lcb->id = saved_id;
+}
+
+
+
+/*******************************************************************************
+**
+** Function l2cu_check_feature_req
+**
+** Description Called when an echo request is received to check if the
+** other side is doing a proprietary feature request. If so,
+** extract the values and reply with a features response.
+**
+** Returns void
+**
+*******************************************************************************/
+BOOLEAN l2cu_check_feature_req (tL2C_LCB *p_lcb, UINT8 id, UINT8 *p_data, UINT16 data_len)
+{
+ UINT8 buff[100];
+ UINT8 *p_out = buff;
+ UINT8 *p_end = p_data + data_len - 2;
+ UINT8 pe_type, pe_len;
+
+ if ((data_len <= 4)
+ || (p_data[0] != 'R')
+ || (p_data[1] != 'Q')
+ || (p_data[data_len - 2] != 'r')
+ || (p_data[data_len - 1] != 'q')
+ || (id != L2CAP_FEATURE_REQ_ID))
+ return (FALSE);
+
+ /* Skip leading frame characters */
+ p_data += 2;
+
+ UINT8_TO_STREAM (p_out, 'R');
+ UINT8_TO_STREAM (p_out, 'S');
+
+ while (p_data < p_end)
+ {
+ pe_type = *p_data++;
+ pe_len = *p_data++;
+
+ switch (pe_type)
+ {
+ default:
+ p_data += pe_len;
+ break;
+ }
+ }
+
+ /* Sanity check - we should not overrun the input */
+ if (p_data != p_end)
+ {
+ L2CAP_TRACE_ERROR0 ("L2CAP - badly formatted feature req");
+ return (FALSE);
+ }
+
+ UINT8_TO_STREAM (p_out, 'r');
+ UINT8_TO_STREAM (p_out, 's');
+
+ l2cu_send_peer_echo_rsp (p_lcb, L2CAP_FEATURE_RSP_ID, buff, (UINT16)(p_out - buff));
+
+ return (TRUE);
+}
+
+/*******************************************************************************
+**
+** Function l2cu_check_feature_rsp
+**
+** Description Called when an echo response is received to check if the
+** other side is suports proprietary feature(s). If so,
+** extract the values.
+**
+** Returns void
+**
+*******************************************************************************/
+void l2cu_check_feature_rsp (tL2C_LCB *p_lcb, UINT8 id, UINT8 *p_data, UINT16 data_len)
+{
+ UINT8 *p_end = p_data + data_len - 2;
+
+ if ((data_len <= 4)
+ || (p_data[0] != 'R')
+ || (p_data[1] != 'S')
+ || (p_data[data_len - 2] != 'r')
+ || (p_data[data_len - 1] != 's')
+ || (id != L2CAP_FEATURE_RSP_ID))
+ {
+ return;
+ }
+
+ /* Skip leading frame characters */
+ p_data += 2;
+
+ while (p_data < p_end)
+ {
+ UINT8 pe_id = *p_data++;
+ UINT8 pe_len = *p_data++;
+
+ switch (pe_id)
+ {
+ default:
+ p_data += pe_len;
+ break;
+ }
+ }
+
+ /* Sanity check - we should not overrun the input */
+ if (p_data != p_end)
+ {
+ L2CAP_TRACE_ERROR0 ("L2CAP - badly formatted feature rsp");
+ }
+}
+#endif /* L2CAP_ENHANCED_FEATURES != 0 */
+
+#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
+/******************************************************************************
+**
+** Function l2cu_set_non_flushable_pbf
+**
+** Description set L2CAP_PKT_START_NON_FLUSHABLE if controller supoorts
+**
+** Returns void
+**
+*******************************************************************************/
+void l2cu_set_non_flushable_pbf (BOOLEAN is_supported)
+{
+ if (is_supported)
+ l2cb.non_flushable_pbf = (L2CAP_PKT_START_NON_FLUSHABLE << L2CAP_PKT_TYPE_SHIFT);
+ else
+ l2cb.non_flushable_pbf = (L2CAP_PKT_START << L2CAP_PKT_TYPE_SHIFT);
+}
+#endif
+
+/*******************************************************************************
+**
+** Function l2cu_resubmit_pending_sec_req
+**
+** Description This function is called when required security procedures
+** are completed and any pending requests can be re-submitted.
+**
+** Returns void
+**
+*******************************************************************************/
+void l2cu_resubmit_pending_sec_req (BD_ADDR p_bda)
+{
+ tL2C_LCB *p_lcb;
+ tL2C_CCB *p_ccb;
+ tL2C_CCB *p_next_ccb;
+ int xx;
+
+ L2CAP_TRACE_DEBUG1 ("l2cu_resubmit_pending_sec_req p_bda: 0x%08x", p_bda);
+
+ /* If we are called with a BDA, only resubmit for that BDA */
+ if (p_bda)
+ {
+ p_lcb = l2cu_find_lcb_by_bd_addr (p_bda);
+
+ /* If we don't have one, this is an error */
+ if (p_lcb)
+ {
+ /* For all channels, send the event through their FSMs */
+ for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; p_ccb = p_next_ccb)
+ {
+ p_next_ccb = p_ccb->p_next_ccb;
+ l2c_csm_execute (p_ccb, L2CEVT_SEC_RE_SEND_CMD, NULL);
+ }
+ }
+ else
+ {
+ L2CAP_TRACE_WARNING0 ("l2cu_resubmit_pending_sec_req - unknown BD_ADDR");
+ }
+ }
+ else
+ {
+ /* No BDA pasesed in, so check all links */
+ for (xx = 0, p_lcb = &l2cb.lcb_pool[0]; xx < MAX_L2CAP_LINKS; xx++, p_lcb++)
+ {
+ if (p_lcb->in_use)
+ {
+ /* For all channels, send the event through their FSMs */
+ for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; p_ccb = p_next_ccb)
+ {
+ p_next_ccb = p_ccb->p_next_ccb;
+ l2c_csm_execute (p_ccb, L2CEVT_SEC_RE_SEND_CMD, NULL);
+ }
+ }
+ }
+ }
+}
+
+#if L2CAP_CONFORMANCE_TESTING == TRUE
+/*******************************************************************************
+**
+** Function l2cu_set_info_rsp_mask
+**
+** Description This function allows the script wrapper to change the
+** info resp mask for conformance testing.
+**
+** Returns pointer to CCB, or NULL if none
+**
+*******************************************************************************/
+void l2cu_set_info_rsp_mask (UINT32 mask)
+{
+ l2cb.test_info_resp = mask;
+}
+#endif /* L2CAP_CONFORMANCE_TESTING */
+
+/*******************************************************************************
+**
+** Function l2cu_adjust_out_mps
+**
+** Description Sets our MPS based on current controller capabilities
+**
+** Returns void
+**
+*******************************************************************************/
+void l2cu_adjust_out_mps (tL2C_CCB *p_ccb)
+{
+ UINT16 packet_size;
+
+ /* on the tx side MTU is selected based on packet size of the controller */
+ packet_size = btm_get_max_packet_size (p_ccb->p_lcb->remote_bd_addr);
+
+ if (packet_size <= (L2CAP_PKT_OVERHEAD + L2CAP_FCR_OVERHEAD + L2CAP_SDU_LEN_OVERHEAD + L2CAP_FCS_LEN))
+ {
+ /* something is very wrong */
+ L2CAP_TRACE_ERROR2 ("l2cu_adjust_out_mps bad packet size: %u will use MPS: %u", packet_size, p_ccb->peer_cfg.fcr.mps);
+ p_ccb->tx_mps = p_ccb->peer_cfg.fcr.mps;
+ }
+ else
+ {
+ packet_size -= (L2CAP_PKT_OVERHEAD + L2CAP_FCR_OVERHEAD + L2CAP_SDU_LEN_OVERHEAD + L2CAP_FCS_LEN);
+
+ /* We try to negotiate MTU that each packet can be split into whole
+ number of max packets. For example if link is 1.2 max packet size is 339 bytes.
+ At first calculate how many whole packets it is. MAX L2CAP is 1691 + 4 overhead.
+ 1695, that will be 5 Dh5 packets. Now maximum L2CAP packet is
+ 5 * 339 = 1695. Minus 4 bytes L2CAP header 1691.
+
+ For EDR 2.0 packet size is 1027. So we better send RFCOMM packet as 1 3DH5 packet
+ 1 * 1027 = 1027. Minus 4 bytes L2CAP header 1023. */
+ if (p_ccb->peer_cfg.fcr.mps >= packet_size)
+ p_ccb->tx_mps = p_ccb->peer_cfg.fcr.mps / packet_size * packet_size;
+ else
+ p_ccb->tx_mps = p_ccb->peer_cfg.fcr.mps;
+
+ L2CAP_TRACE_DEBUG3 ("l2cu_adjust_out_mps use %d Based on peer_cfg.fcr.mps: %u packet_size: %u",
+ p_ccb->tx_mps, p_ccb->peer_cfg.fcr.mps, packet_size);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function l2cu_initialize_fixed_ccb
+**
+** Description Initialize a fixed channel's CCB
+**
+** Returns TRUE or FALSE
+**
+*******************************************************************************/
+BOOLEAN l2cu_initialize_fixed_ccb (tL2C_LCB *p_lcb, UINT16 fixed_cid, tL2CAP_FCR_OPTS *p_fcr)
+{
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+ tL2C_CCB *p_ccb;
+
+ /* If we already have a CCB, then simply return */
+ if (p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL] != NULL)
+ return (TRUE);
+
+ if ((p_ccb = l2cu_allocate_ccb (NULL, 0)) == NULL)
+ return (FALSE);
+
+ /* Set CID for the connection */
+ p_ccb->local_cid = fixed_cid;
+ p_ccb->remote_cid = fixed_cid;
+
+ GKI_init_q (&p_ccb->xmit_hold_q);
+
+ p_ccb->is_flushable = FALSE;
+
+ p_ccb->timer_entry.param = (TIMER_PARAM_TYPE)p_ccb;
+
+
+ if (p_fcr)
+ {
+ /* Set the FCR parameters. For now, we will use default pools */
+ p_ccb->our_cfg.fcr = p_ccb->peer_cfg.fcr = *p_fcr;
+
+ p_ccb->ertm_info.fcr_rx_pool_id = HCI_ACL_POOL_ID;
+ p_ccb->ertm_info.fcr_tx_pool_id = HCI_ACL_POOL_ID;
+ p_ccb->ertm_info.user_rx_pool_id = HCI_ACL_POOL_ID;
+ p_ccb->ertm_info.user_tx_pool_id = HCI_ACL_POOL_ID;
+
+ p_ccb->fcrb.max_held_acks = p_fcr->tx_win_sz / 3;
+ }
+
+ /* Link ccb to lcb and lcb to ccb */
+ p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL] = p_ccb;
+ p_ccb->p_lcb = p_lcb;
+
+ /* There is no configuration, so if the link is up, the channel is up */
+ if (p_lcb->link_state == LST_CONNECTED)
+ p_ccb->chnl_state = CST_OPEN;
+
+ /* Set the default idle timeout value to use */
+ p_ccb->fixed_chnl_idle_tout = l2cb.fixed_reg[fixed_cid - L2CAP_FIRST_FIXED_CHNL].default_idle_tout;
+#endif
+ return (TRUE);
+}
+
+/*******************************************************************************
+**
+** Function l2cu_no_dynamic_ccbs
+**
+** Description Handles the case when there are no more dynamic CCBs. If there
+** are any fixed CCBs, start the longest of the fixed CCB timeouts,
+** otherwise start the default link idle timeout or disconnect.
+**
+** Returns void
+**
+*******************************************************************************/
+void l2cu_no_dynamic_ccbs (tL2C_LCB *p_lcb)
+{
+ tBTM_STATUS rc;
+ UINT16 timeout = p_lcb->idle_timeout;
+
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+ int xx;
+
+ for (xx = 0; xx < L2CAP_NUM_FIXED_CHNLS; xx++)
+ {
+ if ( (p_lcb->p_fixed_ccbs[xx] != NULL) && (p_lcb->p_fixed_ccbs[xx]->fixed_chnl_idle_tout > timeout) )
+ timeout = p_lcb->p_fixed_ccbs[xx]->fixed_chnl_idle_tout;
+ }
+#endif
+
+ /* If the link is pairing, do not mess with the timeouts */
+ if (p_lcb->is_bonding)
+ return;
+
+ if (timeout == 0)
+ {
+ L2CAP_TRACE_DEBUG0 ("l2cu_no_dynamic_ccbs() IDLE timer 0, disconnecting link");
+
+ rc = btm_sec_disconnect (p_lcb->handle, HCI_ERR_PEER_USER);
+ if (rc == BTM_CMD_STARTED)
+ {
+ p_lcb->link_state = LST_DISCONNECTING;
+ timeout = L2CAP_LINK_DISCONNECT_TOUT;
+ }
+ else if (rc == BTM_SUCCESS)
+ {
+ /* BTM SEC will make sure that link is release (probably after pairing is done) */
+ p_lcb->link_state = LST_DISCONNECTING;
+ timeout = 0xFFFF;
+ }
+ else if ( (p_lcb->is_bonding)
+ && (btsnd_hcic_disconnect (p_lcb->handle, HCI_ERR_PEER_USER)) )
+ {
+ p_lcb->link_state = LST_DISCONNECTING;
+ timeout = L2CAP_LINK_DISCONNECT_TOUT;
+ }
+ else
+ {
+ /* probably no buffer to send disconnect */
+ timeout = BT_1SEC_TIMEOUT;
+ }
+ }
+
+ if (timeout != 0xFFFF)
+ {
+ L2CAP_TRACE_DEBUG1 ("l2cu_no_dynamic_ccbs() starting IDLE timeout: %d", timeout);
+ btu_start_timer (&p_lcb->timer_entry, BTU_TTYPE_L2CAP_LINK, timeout);
+ }
+ else
+ {
+ btu_stop_timer(&p_lcb->timer_entry);
+ }
+}
+
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+/*******************************************************************************
+**
+** Function l2cu_process_fixed_chnl_resp
+**
+** Description handle a fixed channel response (or lack thereof)
+** if the link failed, or a fixed channel response was
+** not received, the bitfield is all zeros.
+**
+*******************************************************************************/
+void l2cu_process_fixed_chnl_resp (tL2C_LCB *p_lcb)
+{
+ int xx;
+#if BLE_INCLUDED == TRUE
+ UINT16 reason = (p_lcb->is_ble_link ) ? 1 : 0;
+#else
+ UINT16 reason =0;
+#endif
+
+ /* Tell all registered fixed channels about the connection */
+ for (xx = 0; xx < L2CAP_NUM_FIXED_CHNLS; xx++)
+ {
+ if (l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb != NULL)
+ {
+ if (p_lcb->peer_chnl_mask[0] & (1 << (xx + L2CAP_FIRST_FIXED_CHNL)))
+ {
+ if (p_lcb->p_fixed_ccbs[xx])
+ p_lcb->p_fixed_ccbs[xx]->chnl_state = CST_OPEN;
+
+ (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(p_lcb->remote_bd_addr, TRUE, reason);
+ }
+ else if (p_lcb->p_fixed_ccbs[xx])
+ {
+ (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(p_lcb->remote_bd_addr, FALSE, p_lcb->disc_reason);
+ l2cu_release_ccb (p_lcb->p_fixed_ccbs[xx]);
+ p_lcb->p_fixed_ccbs[xx] = NULL;
+ }
+ }
+ }
+}
+#endif
+
+#if (BLE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function l2cu_send_peer_ble_par_req
+**
+** Description Build and send a BLE parameter update request message
+** to the peer.
+**
+** Returns void
+**
+*******************************************************************************/
+void l2cu_send_peer_ble_par_req (tL2C_LCB *p_lcb, UINT16 min_int, UINT16 max_int, UINT16 latency, UINT16 timeout)
+{
+ BT_HDR *p_buf;
+ UINT8 *p;
+
+ /* Create an identifier for this packet */
+ p_lcb->id++;
+ l2cu_adj_id (p_lcb, L2CAP_ADJ_ID);
+
+ if ((p_buf = l2cu_build_header (p_lcb, L2CAP_CMD_BLE_UPD_REQ_LEN, L2CAP_CMD_BLE_UPDATE_REQ, p_lcb->id)) == NULL )
+ {
+ L2CAP_TRACE_WARNING0 ("l2cu_send_peer_ble_par_req - no buffer");
+ return;
+ }
+
+ p = (UINT8 *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE +
+ L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+ UINT16_TO_STREAM (p, min_int);
+ UINT16_TO_STREAM (p, max_int);
+ UINT16_TO_STREAM (p, latency);
+ UINT16_TO_STREAM (p, timeout);
+
+ l2c_link_check_send_pkts (p_lcb, NULL, p_buf);
+}
+
+/*******************************************************************************
+**
+** Function l2cu_send_peer_ble_par_rsp
+**
+** Description Build and send a BLE parameter update response message
+** to the peer.
+**
+** Returns void
+**
+*******************************************************************************/
+void l2cu_send_peer_ble_par_rsp (tL2C_LCB *p_lcb, UINT16 reason, UINT8 rem_id)
+{
+ BT_HDR *p_buf;
+ UINT8 *p;
+
+ if ((p_buf = l2cu_build_header (p_lcb, L2CAP_CMD_BLE_UPD_RSP_LEN, L2CAP_CMD_BLE_UPDATE_RSP, rem_id)) == NULL )
+ {
+ L2CAP_TRACE_WARNING0 ("l2cu_send_peer_ble_par_rsp - no buffer");
+ return;
+ }
+
+ p = (UINT8 *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE +
+ L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+ UINT16_TO_STREAM (p, reason);
+
+ l2c_link_check_send_pkts (p_lcb, NULL, p_buf);
+}
+
+#endif /* BLE_INCLUDED == TRUE */
+
+
+/*******************************************************************************
+** Functions used by both Full and Light Stack
+********************************************************************************/
+
+/*******************************************************************************
+**
+** Function l2cu_find_lcb_by_handle
+**
+** Description Look through all active LCBs for a match based on the
+** HCI handle.
+**
+** Returns pointer to matched LCB, or NULL if no match
+**
+*******************************************************************************/
+tL2C_LCB *l2cu_find_lcb_by_handle (UINT16 handle)
+{
+ int xx;
+ tL2C_LCB *p_lcb = &l2cb.lcb_pool[0];
+
+ for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_lcb++)
+ {
+ if ((p_lcb->in_use) && (p_lcb->handle == handle))
+ {
+ return (p_lcb);
+ }
+ }
+
+ /* If here, no match found */
+ return (NULL);
+}
+
+/*******************************************************************************
+**
+** Function l2cu_find_ccb_by_cid
+**
+** Description Look through all active CCBs on a link for a match based
+** on the local CID. If passed the link pointer is NULL, all
+** active links are searched.
+**
+** Returns pointer to matched CCB, or NULL if no match
+**
+*******************************************************************************/
+tL2C_CCB *l2cu_find_ccb_by_cid (tL2C_LCB *p_lcb, UINT16 local_cid)
+{
+ tL2C_CCB *p_ccb = NULL;
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ UINT8 xx;
+#endif
+
+ if (local_cid >= L2CAP_BASE_APPL_CID)
+ {
+ /* find the associated CCB by "index" */
+ local_cid -= L2CAP_BASE_APPL_CID;
+
+ if (local_cid >= MAX_L2CAP_CHANNELS)
+ return NULL;
+
+ p_ccb = l2cb.ccb_pool + local_cid;
+
+ /* make sure the CCB is in use */
+ if (!p_ccb->in_use)
+ {
+ p_ccb = NULL;
+ }
+ /* make sure it's for the same LCB */
+ else if (p_lcb && p_lcb != p_ccb->p_lcb)
+ {
+ p_ccb = NULL;
+ }
+ }
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ else
+ {
+ /* searching fixed channel */
+ p_ccb = l2cb.ccb_pool;
+ for ( xx = 0; xx < MAX_L2CAP_CHANNELS; xx++ )
+ {
+ if ((p_ccb->local_cid == local_cid)
+ &&(p_ccb->in_use)
+ &&(p_lcb == p_ccb->p_lcb))
+ break;
+ else
+ p_ccb++;
+ }
+ if ( xx >= MAX_L2CAP_CHANNELS )
+ return NULL;
+ }
+#endif
+
+ return (p_ccb);
+}
+
+#if (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE)
+
+/******************************************************************************
+**
+** Function l2cu_get_next_channel_in_rr
+**
+** Description get the next channel to send on a link. It also adjusts the
+** CCB queue to do a basic priority and round-robin scheduling.
+**
+** Returns pointer to CCB or NULL
+**
+*******************************************************************************/
+static tL2C_CCB *l2cu_get_next_channel_in_rr(tL2C_LCB *p_lcb)
+{
+ tL2C_CCB *p_serve_ccb = NULL;
+ tL2C_CCB *p_ccb;
+
+ int i, j;
+
+ /* scan all of priority until finding a channel to serve */
+ for ( i = 0; (i < L2CAP_NUM_CHNL_PRIORITY)&&(!p_serve_ccb); i++ )
+ {
+ /* scan all channel within serving priority group until finding a channel to serve */
+ for ( j = 0; (j < p_lcb->rr_serv[p_lcb->rr_pri].num_ccb)&&(!p_serve_ccb); j++)
+ {
+ /* scaning from next serving channel */
+ p_ccb = p_lcb->rr_serv[p_lcb->rr_pri].p_serve_ccb;
+
+ if (!p_ccb)
+ {
+ L2CAP_TRACE_ERROR1("p_serve_ccb is NULL, rr_pri=%d", p_lcb->rr_pri);
+ return NULL;
+ }
+
+ L2CAP_TRACE_DEBUG3("RR scan pri=%d, lcid=0x%04x, q_cout=%d",
+ p_ccb->ccb_priority, p_ccb->local_cid, p_ccb->xmit_hold_q.count );
+
+ /* store the next serving channel */
+ /* this channel is the last channel of its priority group */
+ if (( p_ccb->p_next_ccb == NULL )
+ ||( p_ccb->p_next_ccb->ccb_priority != p_ccb->ccb_priority ))
+ {
+ /* next serving channel is set to the first channel in the group */
+ p_lcb->rr_serv[p_lcb->rr_pri].p_serve_ccb = p_lcb->rr_serv[p_lcb->rr_pri].p_first_ccb;
+ }
+ else
+ {
+ /* next serving channel is set to the next channel in the group */
+ p_lcb->rr_serv[p_lcb->rr_pri].p_serve_ccb = p_ccb->p_next_ccb;
+ }
+
+ if (p_ccb->chnl_state != CST_OPEN)
+ continue;
+
+ /* eL2CAP option in use */
+ if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE)
+ {
+ if (p_ccb->fcrb.wait_ack || p_ccb->fcrb.remote_busy)
+ continue;
+
+ if ( p_ccb->fcrb.retrans_q.count == 0 )
+ {
+ if ( p_ccb->xmit_hold_q.count == 0 )
+ continue;
+
+ /* If using the common pool, should be at least 10% free. */
+ if ( (p_ccb->ertm_info.fcr_tx_pool_id == HCI_ACL_POOL_ID) && (GKI_poolutilization (HCI_ACL_POOL_ID) > 90) )
+ continue;
+
+ /* If in eRTM mode, check for window closure */
+ if ( (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) && (l2c_fcr_is_flow_controlled (p_ccb)) )
+ continue;
+ }
+ }
+ else
+ {
+ if (p_ccb->xmit_hold_q.count == 0)
+ continue;
+ }
+
+ /* found a channel to serve */
+ p_serve_ccb = p_ccb;
+ /* decrease quota of its priority group */
+ p_lcb->rr_serv[p_lcb->rr_pri].quota--;
+ }
+
+ /* if there is no more quota of the priority group or no channel to have data to send */
+ if ((p_lcb->rr_serv[p_lcb->rr_pri].quota == 0)||(!p_serve_ccb))
+ {
+ /* serve next priority group */
+ p_lcb->rr_pri = (p_lcb->rr_pri + 1) % L2CAP_NUM_CHNL_PRIORITY;
+ /* initialize its quota */
+ p_lcb->rr_serv[p_lcb->rr_pri].quota = L2CAP_GET_PRIORITY_QUOTA(p_lcb->rr_pri);
+ }
+ }
+
+ if (p_serve_ccb)
+ {
+ L2CAP_TRACE_DEBUG3("RR service pri=%d, quota=%d, lcid=0x%04x",
+ p_serve_ccb->ccb_priority,
+ p_lcb->rr_serv[p_serve_ccb->ccb_priority].quota,
+ p_serve_ccb->local_cid );
+ }
+
+ return p_serve_ccb;
+}
+
+#else /* (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE) */
+
+/******************************************************************************
+**
+** Function l2cu_get_next_channel
+**
+** Description get the next channel to send on a link bassed on priority
+** scheduling.
+**
+** Returns pointer to CCB or NULL
+**
+*******************************************************************************/
+static tL2C_CCB *l2cu_get_next_channel(tL2C_LCB *p_lcb)
+{
+ tL2C_CCB *p_ccb;
+
+ /* Get the first CCB with data to send.
+ */
+ for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; p_ccb = p_ccb->p_next_ccb)
+ {
+ if (p_ccb->chnl_state != CST_OPEN)
+ continue;
+
+ if (p_ccb->fcrb.wait_ack || p_ccb->fcrb.remote_busy)
+ continue;
+
+ if (p_ccb->fcrb.retrans_q.count != 0)
+ return p_ccb;
+
+ if (p_ccb->xmit_hold_q.count == 0)
+ continue;
+
+ /* If using the common pool, should be at least 10% free. */
+ if ( (p_ccb->ertm_info.fcr_tx_pool_id == HCI_ACL_POOL_ID) && (GKI_poolutilization (HCI_ACL_POOL_ID) > 90) )
+ continue;
+
+ /* If in eRTM mode, check for window closure */
+ if ( (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) && (l2c_fcr_is_flow_controlled (p_ccb)) )
+ continue;
+
+ /* If here, we found someone */
+ return p_ccb;
+ }
+
+ return NULL;
+}
+#endif /* (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE) */
+
+/******************************************************************************
+**
+** Function l2cu_get_next_buffer_to_send
+**
+** Description get the next buffer to send on a link. It also adjusts the
+** CCB queue to do a basic priority and round-robin scheduling.
+**
+** Returns pointer to buffer or NULL
+**
+*******************************************************************************/
+BT_HDR *l2cu_get_next_buffer_to_send (tL2C_LCB *p_lcb)
+{
+ tL2C_CCB *p_ccb;
+ BT_HDR *p_buf;
+
+ /* Highest priority are fixed channels */
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+ int xx;
+
+ for (xx = 0; xx < L2CAP_NUM_FIXED_CHNLS; xx++)
+ {
+ if ((p_ccb = p_lcb->p_fixed_ccbs[xx]) == NULL)
+ continue;
+
+ /* eL2CAP option in use */
+ if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE)
+ {
+ if (p_ccb->fcrb.wait_ack || p_ccb->fcrb.remote_busy)
+ continue;
+
+ /* No more checks needed if sending from the reatransmit queue */
+ if (p_ccb->fcrb.retrans_q.count == 0)
+ {
+ if (p_ccb->xmit_hold_q.count == 0)
+ continue;
+
+ /* If using the common pool, should be at least 10% free. */
+ if ( (p_ccb->ertm_info.fcr_tx_pool_id == HCI_ACL_POOL_ID) && (GKI_poolutilization (HCI_ACL_POOL_ID) > 90) )
+ continue;
+
+ /* If in eRTM mode, check for window closure */
+ if ( (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) && (l2c_fcr_is_flow_controlled (p_ccb)) )
+ continue;
+ }
+
+ if ((p_buf = l2c_fcr_get_next_xmit_sdu_seg(p_ccb, 0)) != NULL)
+ {
+ l2cu_set_acl_hci_header (p_buf, p_ccb);
+ return (p_buf);
+ }
+ }
+ else
+ {
+ if (p_ccb->xmit_hold_q.count != 0)
+ {
+ p_buf = (BT_HDR *)GKI_dequeue (&p_ccb->xmit_hold_q);
+ l2cu_set_acl_hci_header (p_buf, p_ccb);
+ return (p_buf);
+ }
+ }
+ }
+#endif
+
+#if (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE)
+ /* get next serving channel in round-robin */
+ p_ccb = l2cu_get_next_channel_in_rr( p_lcb );
+#else
+ p_ccb = l2cu_get_next_channel( p_lcb );
+#endif
+
+ /* Return if no buffer */
+ if (p_ccb == NULL)
+ return (NULL);
+
+ if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE)
+ {
+ if ((p_buf = l2c_fcr_get_next_xmit_sdu_seg(p_ccb, 0)) == NULL)
+ return (NULL);
+ }
+ else
+ {
+ p_buf = (BT_HDR *)GKI_dequeue (&p_ccb->xmit_hold_q);
+ }
+
+ if ( p_ccb->p_rcb && p_ccb->p_rcb->api.pL2CA_TxComplete_Cb && (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_ERTM_MODE) )
+ (*p_ccb->p_rcb->api.pL2CA_TxComplete_Cb)(p_ccb->local_cid, 1);
+
+
+ l2cu_check_channel_congestion (p_ccb);
+
+ l2cu_set_acl_hci_header (p_buf, p_ccb);
+
+ return (p_buf);
+}
+
+/******************************************************************************
+**
+** Function l2cu_set_acl_hci_header
+**
+** Description Set HCI handle for ACL packet
+**
+** Returns None
+**
+*******************************************************************************/
+void l2cu_set_acl_hci_header (BT_HDR *p_buf, tL2C_CCB *p_ccb)
+{
+ UINT8 *p;
+
+ /* Set the pointer to the beginning of the data minus 4 bytes for the packet header */
+ p = (UINT8 *)(p_buf + 1) + p_buf->offset - HCI_DATA_PREAMBLE_SIZE;
+
+#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
+ if ( (((p_buf->layer_specific & L2CAP_FLUSHABLE_MASK) == L2CAP_FLUSHABLE_CH_BASED) && (p_ccb->is_flushable))
+ || ((p_buf->layer_specific & L2CAP_FLUSHABLE_MASK) == L2CAP_FLUSHABLE_PKT) )
+ {
+ UINT16_TO_STREAM (p, p_ccb->p_lcb->handle | (L2CAP_PKT_START << L2CAP_PKT_TYPE_SHIFT));
+ }
+ else
+ {
+ UINT16_TO_STREAM (p, p_ccb->p_lcb->handle | l2cb.non_flushable_pbf);
+ }
+#else
+ UINT16_TO_STREAM (p, p_ccb->p_lcb->handle | (L2CAP_PKT_START << L2CAP_PKT_TYPE_SHIFT));
+#endif
+#if (BLE_INCLUDED == TRUE)
+ if (p_ccb->p_lcb->is_ble_link)
+ {
+ /* The HCI transport will segment the buffers. */
+ if (p_buf->len > btu_cb.hcit_ble_acl_data_size)
+ {
+ UINT16_TO_STREAM (p, btu_cb.hcit_ble_acl_data_size);
+ }
+ else
+ {
+ UINT16_TO_STREAM (p, p_buf->len);
+ }
+ } /* (BLE_INCLUDED == TRUE) */
+ else
+#endif
+ {
+
+ /* The HCI transport will segment the buffers. */
+ if (p_buf->len > btu_cb.hcit_acl_data_size)
+ {
+ UINT16_TO_STREAM (p, btu_cb.hcit_acl_data_size);
+ }
+ else
+ {
+ UINT16_TO_STREAM (p, p_buf->len);
+ }
+ }
+ p_buf->offset -= HCI_DATA_PREAMBLE_SIZE;
+ p_buf->len += HCI_DATA_PREAMBLE_SIZE;
+}
+
+/******************************************************************************
+**
+** Function l2cu_check_channel_congestion
+**
+** Description check if any change in congestion status
+**
+** Returns None
+**
+*******************************************************************************/
+void l2cu_check_channel_congestion (tL2C_CCB *p_ccb)
+{
+ UINT16 q_count = p_ccb->xmit_hold_q.count;
+
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ if ( p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID )
+ {
+ q_count += p_ccb->p_lcb->ucd_out_sec_pending_q.count;
+ }
+#endif
+
+ /* If the CCB queue limit is subject to a quota, check for congestion */
+
+ /* if this channel has outgoing traffic */
+ if ((p_ccb->p_rcb)&&(p_ccb->buff_quota != 0))
+ {
+ /* If this channel was congested */
+ if ( p_ccb->cong_sent )
+ {
+ /* If the channel is not congested now, tell the app */
+ if (q_count <= (p_ccb->buff_quota / 2))
+ {
+ p_ccb->cong_sent = FALSE;
+ if (p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb)
+ {
+ L2CAP_TRACE_DEBUG3 ("L2CAP - Calling CongestionStatus_Cb (FALSE), CID: 0x%04x xmit_hold_q.count: %u buff_quota: %u",
+ p_ccb->local_cid, q_count, p_ccb->buff_quota);
+
+ /* Prevent recursive calling */
+ l2cb.is_cong_cback_context = TRUE;
+ (*p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb)(p_ccb->local_cid, FALSE);
+ l2cb.is_cong_cback_context = FALSE;
+ }
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ else if ( p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID )
+ {
+ if ( p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb )
+ {
+ L2CAP_TRACE_DEBUG3 ("L2CAP - Calling UCD CongestionStatus_Cb (FALSE), SecPendingQ:%u,XmitQ:%u,Quota:%u",
+ p_ccb->p_lcb->ucd_out_sec_pending_q.count,
+ p_ccb->xmit_hold_q.count, p_ccb->buff_quota);
+ p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb( p_ccb->p_lcb->remote_bd_addr, FALSE );
+ }
+ }
+#endif
+ }
+ }
+ else
+ {
+ /* If this channel was not congested but it is congested now, tell the app */
+ if (q_count > p_ccb->buff_quota)
+ {
+ p_ccb->cong_sent = TRUE;
+ if (p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb)
+ {
+ L2CAP_TRACE_DEBUG3 ("L2CAP - Calling CongestionStatus_Cb (TRUE),CID:0x%04x,XmitQ:%u,Quota:%u",
+ p_ccb->local_cid, q_count, p_ccb->buff_quota);
+
+ (*p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb)(p_ccb->local_cid, TRUE);
+ }
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ else if ( p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID )
+ {
+ if ( p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb )
+ {
+ L2CAP_TRACE_DEBUG3 ("L2CAP - Calling UCD CongestionStatus_Cb (TRUE), SecPendingQ:%u,XmitQ:%u,Quota:%u",
+ p_ccb->p_lcb->ucd_out_sec_pending_q.count,
+ p_ccb->xmit_hold_q.count, p_ccb->buff_quota);
+ p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb( p_ccb->p_lcb->remote_bd_addr, TRUE );
+ }
+ }
+#endif
+ }
+ }
+ }
+}
+
diff --git a/stack/mcap/mca_api.c b/stack/mcap/mca_api.c
new file mode 100644
index 0000000..c4cf7a3
--- /dev/null
+++ b/stack/mcap/mca_api.c
@@ -0,0 +1,912 @@
+/*****************************************************************************
+**
+** Name: mca_api.c
+**
+** Description: This is the API implementation file for the
+** Multi-Channel Adaptation Protocol (MCAP).
+**
+** Copyright (c) 2009-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include <string.h>
+
+#include "bt_target.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "mca_api.h"
+#include "mca_defs.h"
+#include "mca_int.h"
+
+#include "wcassert.h"
+#include "btu.h"
+
+
+/*******************************************************************************
+**
+** Function mca_process_timeout
+**
+** Description This function is called by BTU when an MCA timer
+** expires.
+**
+** This function is for use internal to the stack only.
+**
+** Returns void
+**
+*******************************************************************************/
+void mca_process_timeout(TIMER_LIST_ENT *p_tle)
+{
+ if(p_tle->event == BTU_TTYPE_MCA_CCB_RSP)
+ {
+ p_tle->event = 0;
+ mca_ccb_event ((tMCA_CCB *) p_tle->param, MCA_CCB_RSP_TOUT_EVT, NULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function MCA_Init
+**
+** Description Initialize MCAP main control block.
+** This function is called at stack start up.
+**
+** Returns void
+**
+*******************************************************************************/
+void MCA_Init(void)
+{
+ memset(&mca_cb, 0, sizeof(tMCA_CB));
+
+#if defined(MCA_INITIAL_TRACE_LEVEL)
+ mca_cb.trace_level = MCA_INITIAL_TRACE_LEVEL;
+#else
+ mca_cb.trace_level = BT_TRACE_LEVEL_NONE;
+#endif
+}
+
+/*******************************************************************************
+**
+** Function MCA_SetTraceLevel
+**
+** Description This function sets the debug trace level for MCA.
+** If 0xff is passed, the current trace level is returned.
+**
+** Input Parameters:
+** level: The level to set the MCA tracing to:
+** 0xff-returns the current setting.
+** 0-turns off tracing.
+** >= 1-Errors.
+** >= 2-Warnings.
+** >= 3-APIs.
+** >= 4-Events.
+** >= 5-Debug.
+**
+** Returns The new trace level or current trace level if
+** the input parameter is 0xff.
+**
+*******************************************************************************/
+UINT8 MCA_SetTraceLevel (UINT8 level)
+{
+ if (level != 0xFF)
+ mca_cb.trace_level = level;
+
+ return (mca_cb.trace_level);
+}
+
+/*******************************************************************************
+**
+** Function MCA_Register
+**
+** Description This function registers an MCAP implementation.
+** It is assumed that the control channel PSM and data channel
+** PSM are not used by any other instances of the stack.
+** If the given p_reg->ctrl_psm is 0, this handle is INT only.
+**
+** Returns 0, if failed. Otherwise, the MCA handle.
+**
+*******************************************************************************/
+tMCA_HANDLE MCA_Register(tMCA_REG *p_reg, tMCA_CTRL_CBACK *p_cback)
+{
+ tMCA_RCB *p_rcb;
+ tMCA_HANDLE handle = 0;
+ tL2CAP_APPL_INFO l2c_cacp_appl;
+ tL2CAP_APPL_INFO l2c_dacp_appl;
+
+ WC_ASSERT(p_reg != NULL );
+ WC_ASSERT(p_cback != NULL );
+
+ MCA_TRACE_API2 ("MCA_Register: ctrl_psm:0x%x, data_psm:0x%x", p_reg->ctrl_psm, p_reg->data_psm);
+
+ if ( (p_rcb = mca_rcb_alloc (p_reg)) != NULL)
+ {
+ if (p_reg->ctrl_psm)
+ {
+ if (L2C_INVALID_PSM(p_reg->ctrl_psm) || L2C_INVALID_PSM(p_reg->data_psm))
+ {
+ MCA_TRACE_ERROR0 ("INVALID_PSM");
+ return 0;
+ }
+
+ l2c_cacp_appl = *(tL2CAP_APPL_INFO *)&mca_l2c_int_appl;
+ l2c_cacp_appl.pL2CA_ConnectCfm_Cb = NULL;
+ l2c_dacp_appl = *(tL2CAP_APPL_INFO *)&l2c_cacp_appl;
+ l2c_cacp_appl.pL2CA_ConnectInd_Cb = mca_l2c_cconn_ind_cback;
+ l2c_dacp_appl.pL2CA_ConnectInd_Cb = mca_l2c_dconn_ind_cback;
+ if (L2CA_Register(p_reg->ctrl_psm, (tL2CAP_APPL_INFO *) &l2c_cacp_appl) &&
+ L2CA_Register(p_reg->data_psm, (tL2CAP_APPL_INFO *) &l2c_dacp_appl))
+ {
+ /* set security level */
+ BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_MCAP_CTRL, p_reg->sec_mask,
+ p_reg->ctrl_psm, BTM_SEC_PROTO_MCA, MCA_CTRL_TCID);
+
+ /* in theory, we do not need this one for data_psm
+ * If we don't, L2CAP rejects with security block (3),
+ * which is different reject code from what MCAP spec suggests.
+ * we set this one, so mca_l2c_dconn_ind_cback can reject /w no resources (4) */
+ BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_MCAP_DATA, p_reg->sec_mask,
+ p_reg->data_psm, BTM_SEC_PROTO_MCA, MCA_CTRL_TCID);
+ }
+ else
+ {
+ MCA_TRACE_ERROR0 ("Failed to register to L2CAP");
+ return 0;
+ }
+ }
+ else
+ p_rcb->reg.data_psm = 0;
+ handle = mca_rcb_to_handle (p_rcb);
+ p_rcb->p_cback = p_cback;
+ p_rcb->reg.rsp_tout = p_reg->rsp_tout;
+ }
+ return handle;
+}
+
+
+/*******************************************************************************
+**
+** Function MCA_Deregister
+**
+** Description This function is called to deregister an MCAP implementation.
+** Before this function can be called, all control and data
+** channels must be removed with MCA_DisconnectReq and MCA_CloseReq.
+**
+** Returns void
+**
+*******************************************************************************/
+void MCA_Deregister(tMCA_HANDLE handle)
+{
+ tMCA_RCB *p_rcb = mca_rcb_by_handle(handle);
+
+ MCA_TRACE_API1 ("MCA_Deregister: %d", handle);
+ if (p_rcb && p_rcb->reg.ctrl_psm)
+ {
+ L2CA_Deregister(p_rcb->reg.ctrl_psm);
+ L2CA_Deregister(p_rcb->reg.data_psm);
+ btm_sec_clr_service_by_psm (p_rcb->reg.ctrl_psm);
+ btm_sec_clr_service_by_psm (p_rcb->reg.data_psm);
+ }
+ mca_rcb_dealloc(handle);
+}
+
+
+/*******************************************************************************
+**
+** Function MCA_CreateDep
+**
+** Description Create a data endpoint. If the MDEP is created successfully,
+** the MDEP ID is returned in *p_dep. After a data endpoint is
+** created, an application can initiate a connection between this
+** endpoint and an endpoint on a peer device.
+**
+** Returns MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+tMCA_RESULT MCA_CreateDep(tMCA_HANDLE handle, tMCA_DEP *p_dep, tMCA_CS *p_cs)
+{
+ tMCA_RESULT result = MCA_BAD_HANDLE;
+ int i;
+ tMCA_RCB *p_rcb = mca_rcb_by_handle(handle);
+ tMCA_CS *p_depcs;
+
+ WC_ASSERT(p_dep != NULL );
+ WC_ASSERT(p_cs != NULL );
+ WC_ASSERT(p_cs->p_data_cback != NULL );
+
+ MCA_TRACE_API1 ("MCA_CreateDep: %d", handle);
+ if (p_rcb)
+ {
+ if (p_cs->max_mdl > MCA_NUM_MDLS)
+ {
+ MCA_TRACE_ERROR1 ("max_mdl: %d is too big", p_cs->max_mdl );
+ result = MCA_BAD_PARAMS;
+ }
+ else
+ {
+ p_depcs = p_rcb->dep;
+ if (p_cs->type == MCA_TDEP_ECHO)
+ {
+ if (p_depcs->p_data_cback)
+ {
+ MCA_TRACE_ERROR0 ("Already has ECHO MDEP");
+ return MCA_NO_RESOURCES;
+ }
+ memcpy (p_depcs, p_cs, sizeof (tMCA_CS));
+ *p_dep = 0;
+ result = MCA_SUCCESS;
+ }
+ else
+ {
+ result = MCA_NO_RESOURCES;
+ /* non-echo MDEP starts from 1 */
+ p_depcs++;
+ for (i=1; i<MCA_NUM_DEPS; i++, p_depcs++)
+ {
+ if (p_depcs->p_data_cback == NULL)
+ {
+ memcpy (p_depcs, p_cs, sizeof (tMCA_CS));
+ /* internally use type as the mdep id */
+ p_depcs->type = i;
+ *p_dep = i;
+ result = MCA_SUCCESS;
+ break;
+ }
+ }
+ }
+ }
+ }
+ return result;
+}
+
+
+/*******************************************************************************
+**
+** Function MCA_DeleteDep
+**
+** Description Delete a data endpoint. This function is called when
+** the implementation is no longer using a data endpoint.
+** If this function is called when the endpoint is connected
+** the connection is closed and the data endpoint
+** is removed.
+**
+** Returns MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+tMCA_RESULT MCA_DeleteDep(tMCA_HANDLE handle, tMCA_DEP dep)
+{
+ tMCA_RESULT result = MCA_BAD_HANDLE;
+ tMCA_RCB *p_rcb = mca_rcb_by_handle(handle);
+ tMCA_DCB *p_dcb;
+ int i, max;
+ tMCA_CS *p_depcs;
+
+ MCA_TRACE_API2 ("MCA_DeleteDep: %d dep:%d", handle, dep);
+ if (p_rcb)
+ {
+ if (dep < MCA_NUM_DEPS && p_rcb->dep[dep].p_data_cback)
+ {
+ result = MCA_SUCCESS;
+ p_rcb->dep[dep].p_data_cback = NULL;
+ p_depcs = &(p_rcb->dep[dep]);
+ i = handle - 1;
+ max = MCA_NUM_MDLS*MCA_NUM_LINKS;
+ p_dcb = &mca_cb.dcb[i*max];
+ /* make sure no MDL exists for this MDEP */
+ for (i=0; i<max; i++, p_dcb++)
+ {
+ if (p_dcb->state && p_dcb->p_cs == p_depcs)
+ {
+ mca_dcb_event(p_dcb, MCA_DCB_API_CLOSE_EVT, NULL);
+ }
+ }
+ }
+ }
+ return result;
+}
+
+/*******************************************************************************
+**
+** Function MCA_ConnectReq
+**
+** Description This function initiates an MCAP control channel connection
+** to the peer device. When the connection is completed, an
+** MCA_CONNECT_IND_EVT is reported to the application via its
+** control callback function.
+** This control channel is identified by the tMCA_CL.
+** If the connection attempt fails, an MCA_DISCONNECT_IND_EVT is
+** reported. The security mask parameter overrides the outgoing
+** security mask set in MCA_Register().
+**
+** Returns MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+tMCA_RESULT MCA_ConnectReq(tMCA_HANDLE handle, BD_ADDR bd_addr,
+ UINT16 ctrl_psm, UINT16 sec_mask)
+{
+ tMCA_RESULT result = MCA_BAD_HANDLE;
+ tMCA_CCB *p_ccb;
+ tMCA_TC_TBL *p_tbl;
+
+ MCA_TRACE_API2 ("MCA_ConnectReq: %d psm:0x%x", handle, ctrl_psm);
+ if ((p_ccb = mca_ccb_by_bd(handle, bd_addr)) == NULL)
+ p_ccb = mca_ccb_alloc(handle, bd_addr);
+ else
+ {
+ MCA_TRACE_ERROR0 ("control channel already exists");
+ return MCA_BUSY;
+ }
+
+ if (p_ccb)
+ {
+ p_ccb->ctrl_vpsm = L2CA_Register (ctrl_psm, (tL2CAP_APPL_INFO *)&mca_l2c_int_appl);
+ result = MCA_NO_RESOURCES;
+ if (p_ccb->ctrl_vpsm)
+ {
+ BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_MCAP_CTRL, sec_mask,
+ p_ccb->ctrl_vpsm, BTM_SEC_PROTO_MCA, MCA_CTRL_TCID);
+ p_ccb->lcid = mca_l2c_open_req(bd_addr, p_ccb->ctrl_vpsm, NULL);
+ if (p_ccb->lcid)
+ {
+ p_tbl = mca_tc_tbl_calloc(p_ccb);
+ if (p_tbl)
+ {
+ p_tbl->state = MCA_TC_ST_CONN;
+ p_ccb->sec_mask = sec_mask;
+ result = MCA_SUCCESS;
+ }
+ }
+ }
+ if (result != MCA_SUCCESS)
+ mca_ccb_dealloc (p_ccb, NULL);
+ }
+ return result;
+}
+
+
+/*******************************************************************************
+**
+** Function MCA_DisconnectReq
+**
+** Description This function disconnect an MCAP control channel
+** to the peer device.
+** If associated data channel exists, they are disconnected.
+** When the MCL is disconnected an MCA_DISCONNECT_IND_EVT is
+** reported to the application via its control callback function.
+**
+** Returns MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+tMCA_RESULT MCA_DisconnectReq(tMCA_CL mcl)
+{
+ tMCA_RESULT result = MCA_BAD_HANDLE;
+ tMCA_CCB *p_ccb = mca_ccb_by_hdl(mcl);
+
+ MCA_TRACE_API1 ("MCA_DisconnectReq: %d ", mcl);
+ if (p_ccb)
+ {
+ result = MCA_SUCCESS;
+ mca_ccb_event (p_ccb, MCA_CCB_API_DISCONNECT_EVT, NULL);
+ }
+ return result;
+}
+
+
+/*******************************************************************************
+**
+** Function MCA_CreateMdl
+**
+** Description This function sends a CREATE_MDL request to the peer device.
+** When the response is received, a MCA_CREATE_CFM_EVT is reported
+** with the given MDL ID.
+** If the response is successful, a data channel is open
+** with the given p_chnl_cfg
+** If p_chnl_cfg is NULL, the data channel is not initiated until
+** MCA_DataChnlCfg is called to provide the p_chnl_cfg.
+** When the data channel is open successfully, a MCA_OPEN_CFM_EVT
+** is reported. This data channel is identified as tMCA_DL.
+**
+** Returns MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+tMCA_RESULT MCA_CreateMdl(tMCA_CL mcl, tMCA_DEP dep, UINT16 data_psm,
+ UINT16 mdl_id, UINT8 peer_dep_id,
+ UINT8 cfg, const tMCA_CHNL_CFG *p_chnl_cfg)
+{
+ tMCA_RESULT result = MCA_BAD_HANDLE;
+ tMCA_CCB *p_ccb = mca_ccb_by_hdl(mcl);
+ tMCA_CCB_MSG *p_evt_data;
+ tMCA_DCB *p_dcb;
+
+ MCA_TRACE_API4 ("MCA_CreateMdl: %d dep=%d mdl_id=%d peer_dep_id=%d", mcl, dep, mdl_id, peer_dep_id);
+ if (p_ccb)
+ {
+ if (p_ccb->p_tx_req || p_ccb->p_rx_msg || p_ccb->cong)
+ {
+ MCA_TRACE_ERROR0 ("pending req");
+ return MCA_BUSY;
+ }
+
+ if ((peer_dep_id > MCA_MAX_MDEP_ID) || (!MCA_IS_VALID_MDL_ID(mdl_id)))
+ {
+ MCA_TRACE_ERROR2 ("bad peer dep id:%d or bad mdl id: %d ", peer_dep_id, mdl_id);
+ return MCA_BAD_PARAMS;
+ }
+
+ if (mca_ccb_uses_mdl_id(p_ccb, mdl_id))
+ {
+ MCA_TRACE_ERROR1 ("mdl id: %d is used in the control link", mdl_id);
+ return MCA_BAD_MDL_ID;
+ }
+
+ p_dcb = mca_dcb_alloc(p_ccb, dep);
+ result = MCA_NO_RESOURCES;
+ if (p_dcb)
+ {
+ /* save the info required by dcb connection */
+ p_dcb->p_chnl_cfg = p_chnl_cfg;
+ p_dcb->mdl_id = mdl_id;
+ p_evt_data = (tMCA_CCB_MSG *)GKI_getbuf (sizeof(tMCA_CCB_MSG));
+ if (p_evt_data)
+ {
+ if (!p_ccb->data_vpsm)
+ p_ccb->data_vpsm = L2CA_Register (data_psm, (tL2CAP_APPL_INFO *)&mca_l2c_int_appl);
+ if (p_ccb->data_vpsm)
+ {
+ p_evt_data->dcb_idx = mca_dcb_to_hdl (p_dcb);
+ p_evt_data->mdep_id = peer_dep_id;
+ p_evt_data->mdl_id = mdl_id;
+ p_evt_data->param = cfg;
+ p_evt_data->op_code = MCA_OP_MDL_CREATE_REQ;
+ p_evt_data->hdr.event = MCA_CCB_API_REQ_EVT;
+ p_evt_data->hdr.layer_specific = FALSE;
+ mca_ccb_event(p_ccb, MCA_CCB_API_REQ_EVT, (tMCA_CCB_EVT *)p_evt_data);
+ return MCA_SUCCESS;
+ }
+ else
+ GKI_freebuf (p_evt_data);
+ }
+ mca_dcb_dealloc(p_dcb, NULL);
+ }
+ }
+ return result;
+}
+
+
+/*******************************************************************************
+**
+** Function MCA_CreateMdlRsp
+**
+** Description This function sends a CREATE_MDL response to the peer device
+** in response to a received MCA_CREATE_IND_EVT.
+** If the rsp_code is successful, a data channel is open
+** with the given p_chnl_cfg
+** When the data channel is open successfully, a MCA_OPEN_IND_EVT
+** is reported. This data channel is identified as tMCA_DL.
+**
+** Returns MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+tMCA_RESULT MCA_CreateMdlRsp(tMCA_CL mcl, tMCA_DEP dep,
+ UINT16 mdl_id, UINT8 cfg, UINT8 rsp_code,
+ const tMCA_CHNL_CFG *p_chnl_cfg)
+{
+ tMCA_RESULT result = MCA_BAD_HANDLE;
+ tMCA_CCB *p_ccb = mca_ccb_by_hdl(mcl);
+ tMCA_CCB_MSG evt_data;
+ tMCA_DCB *p_dcb;
+
+ MCA_TRACE_API5 ("MCA_CreateMdlRsp: %d dep=%d mdl_id=%d cfg=%d rsp_code=%d", mcl, dep, mdl_id, cfg, rsp_code);
+ WC_ASSERT(p_chnl_cfg != NULL );
+ if (p_ccb)
+ {
+ if (p_ccb->cong)
+ {
+ MCA_TRACE_ERROR0 ("congested");
+ return MCA_BUSY;
+ }
+ if (p_ccb->p_rx_msg && (p_ccb->p_rx_msg->mdep_id == dep )
+ && (p_ccb->p_rx_msg->mdl_id == mdl_id) && (p_ccb->p_rx_msg->op_code == MCA_OP_MDL_CREATE_REQ))
+ {
+ result = MCA_SUCCESS;
+ evt_data.dcb_idx = 0;
+ if (rsp_code == MCA_RSP_SUCCESS)
+ {
+ p_dcb = mca_dcb_alloc(p_ccb, dep);
+ if (p_dcb)
+ {
+ evt_data.dcb_idx = mca_dcb_to_hdl(p_dcb);
+ p_dcb->p_chnl_cfg = p_chnl_cfg;
+ p_dcb->mdl_id = mdl_id;
+ }
+ else
+ {
+ rsp_code = MCA_RSP_MDEP_BUSY;
+ result = MCA_NO_RESOURCES;
+ }
+ }
+
+ if (result == MCA_SUCCESS)
+ {
+ evt_data.mdl_id = mdl_id;
+ evt_data.param = cfg;
+ evt_data.rsp_code = rsp_code;
+ evt_data.op_code = MCA_OP_MDL_CREATE_RSP;
+ mca_ccb_event(p_ccb, MCA_CCB_API_RSP_EVT, (tMCA_CCB_EVT *)&evt_data);
+ }
+ }
+ else
+ {
+ MCA_TRACE_ERROR0 ("The given MCL is not expecting a MCA_CreateMdlRsp with the given parameters" );
+ result = MCA_BAD_PARAMS;
+ }
+ }
+ return result;
+}
+
+/*******************************************************************************
+**
+** Function MCA_CloseReq
+**
+** Description Close a data channel. When the channel is closed, an
+** MCA_CLOSE_CFM_EVT is sent to the application via the
+** control callback function for this handle.
+**
+** Returns MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+tMCA_RESULT MCA_CloseReq(tMCA_DL mdl)
+{
+ tMCA_RESULT result = MCA_BAD_HANDLE;
+ tMCA_DCB *p_dcb = mca_dcb_by_hdl(mdl);
+
+ MCA_TRACE_API1 ("MCA_CloseReq: %d ", mdl);
+ if (p_dcb)
+ {
+ result = MCA_SUCCESS;
+ mca_dcb_event(p_dcb, MCA_DCB_API_CLOSE_EVT, NULL);
+ }
+ return result;
+}
+
+
+/*******************************************************************************
+**
+** Function MCA_ReconnectMdl
+**
+** Description This function sends a RECONNECT_MDL request to the peer device.
+** When the response is received, a MCA_RECONNECT_CFM_EVT is reported.
+** If p_chnl_cfg is NULL, the data channel is not initiated until
+** MCA_DataChnlCfg is called to provide the p_chnl_cfg.
+** If the response is successful, a data channel is open.
+** When the data channel is open successfully, a MCA_OPEN_CFM_EVT
+** is reported.
+**
+** Returns MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+tMCA_RESULT MCA_ReconnectMdl(tMCA_CL mcl, tMCA_DEP dep, UINT16 data_psm,
+ UINT16 mdl_id, const tMCA_CHNL_CFG *p_chnl_cfg)
+{
+ tMCA_RESULT result = MCA_BAD_HANDLE;
+ tMCA_CCB *p_ccb = mca_ccb_by_hdl(mcl);
+ tMCA_CCB_MSG *p_evt_data;
+ tMCA_DCB *p_dcb;
+
+ MCA_TRACE_API1 ("MCA_ReconnectMdl: %d ", mcl);
+ WC_ASSERT(p_chnl_cfg != NULL );
+ if (p_ccb)
+ {
+ if (p_ccb->p_tx_req || p_ccb->p_rx_msg || p_ccb->cong)
+ {
+ MCA_TRACE_ERROR0 ("pending req");
+ return MCA_BUSY;
+ }
+
+ if (!MCA_IS_VALID_MDL_ID(mdl_id))
+ {
+ MCA_TRACE_ERROR1 ("bad mdl id: %d ", mdl_id);
+ return MCA_BAD_PARAMS;
+ }
+
+ if (mca_ccb_uses_mdl_id(p_ccb, mdl_id))
+ {
+ MCA_TRACE_ERROR1 ("mdl id: %d is used in the control link", mdl_id);
+ return MCA_BAD_MDL_ID;
+ }
+
+ p_dcb = mca_dcb_alloc(p_ccb, dep);
+ result = MCA_NO_RESOURCES;
+ if (p_dcb)
+ {
+ p_dcb->p_chnl_cfg = p_chnl_cfg;
+ p_dcb->mdl_id = mdl_id;
+ p_evt_data = (tMCA_CCB_MSG *)GKI_getbuf (sizeof(tMCA_CCB_MSG));
+ if (p_evt_data)
+ {
+ if (!p_ccb->data_vpsm)
+ p_ccb->data_vpsm = L2CA_Register (data_psm, (tL2CAP_APPL_INFO *)&mca_l2c_int_appl);
+ p_evt_data->dcb_idx = mca_dcb_to_hdl(p_dcb);
+ p_evt_data->mdl_id = mdl_id;
+ p_evt_data->op_code = MCA_OP_MDL_RECONNECT_REQ;
+ p_evt_data->hdr.event = MCA_CCB_API_REQ_EVT;
+ mca_ccb_event(p_ccb, MCA_CCB_API_REQ_EVT, (tMCA_CCB_EVT *)p_evt_data);
+ return MCA_SUCCESS;
+ }
+ mca_dcb_dealloc(p_dcb, NULL);
+ }
+ }
+ return result;
+}
+
+
+/*******************************************************************************
+**
+** Function MCA_ReconnectMdlRsp
+**
+** Description This function sends a RECONNECT_MDL response to the peer device
+** in response to a MCA_RECONNECT_IND_EVT event.
+** If the response is successful, a data channel is open.
+** When the data channel is open successfully, a MCA_OPEN_IND_EVT
+** is reported.
+**
+** Returns MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+tMCA_RESULT MCA_ReconnectMdlRsp(tMCA_CL mcl, tMCA_DEP dep,
+ UINT16 mdl_id, UINT8 rsp_code,
+ const tMCA_CHNL_CFG *p_chnl_cfg)
+{
+ tMCA_RESULT result = MCA_BAD_HANDLE;
+ tMCA_CCB *p_ccb = mca_ccb_by_hdl(mcl);
+ tMCA_CCB_MSG evt_data;
+ tMCA_DCB *p_dcb;
+
+ MCA_TRACE_API1 ("MCA_ReconnectMdlRsp: %d ", mcl);
+ WC_ASSERT(p_chnl_cfg != NULL );
+ if (p_ccb)
+ {
+ if (p_ccb->cong)
+ {
+ MCA_TRACE_ERROR0 ("congested");
+ return MCA_BUSY;
+ }
+ if (p_ccb->p_rx_msg && (p_ccb->p_rx_msg->mdl_id == mdl_id) &&
+ (p_ccb->p_rx_msg->op_code == MCA_OP_MDL_RECONNECT_REQ))
+ {
+ result = MCA_SUCCESS;
+ evt_data.dcb_idx = 0;
+ if (rsp_code == MCA_RSP_SUCCESS)
+ {
+ p_dcb = mca_dcb_alloc(p_ccb, dep);
+ if (p_dcb)
+ {
+ evt_data.dcb_idx = mca_dcb_to_hdl(p_dcb);
+ p_dcb->p_chnl_cfg = p_chnl_cfg;
+ p_dcb->mdl_id = mdl_id;
+ }
+ else
+ {
+ MCA_TRACE_ERROR0 ("Out of MDL for this MDEP");
+ rsp_code = MCA_RSP_MDEP_BUSY;
+ result = MCA_NO_RESOURCES;
+ }
+ }
+
+ evt_data.mdl_id = mdl_id;
+ evt_data.rsp_code = rsp_code;
+ evt_data.op_code = MCA_OP_MDL_RECONNECT_RSP;
+ mca_ccb_event(p_ccb, MCA_CCB_API_RSP_EVT, (tMCA_CCB_EVT *)&evt_data);
+ }
+ else
+ {
+ MCA_TRACE_ERROR0 ("The given MCL is not expecting a MCA_ReconnectMdlRsp with the given parameters" );
+ result = MCA_BAD_PARAMS;
+ }
+ }
+ return result;
+}
+
+
+/*******************************************************************************
+**
+** Function MCA_DataChnlCfg
+**
+** Description This function initiates a data channel connection toward the
+** connected peer device.
+** When the data channel is open successfully, a MCA_OPEN_CFM_EVT
+** is reported. This data channel is identified as tMCA_DL.
+**
+** Returns MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+tMCA_RESULT MCA_DataChnlCfg(tMCA_CL mcl, const tMCA_CHNL_CFG *p_chnl_cfg)
+{
+ tMCA_RESULT result = MCA_BAD_HANDLE;
+ tMCA_CCB *p_ccb = mca_ccb_by_hdl(mcl);
+ tMCA_DCB *p_dcb;
+ tMCA_TC_TBL *p_tbl;
+
+ MCA_TRACE_API1 ("MCA_DataChnlCfg: %d ", mcl);
+ WC_ASSERT(p_chnl_cfg != NULL );
+ if (p_ccb)
+ {
+ result = MCA_NO_RESOURCES;
+ if ((p_ccb->p_tx_req == NULL) || (p_ccb->status != MCA_CCB_STAT_PENDING) ||
+ ((p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx)) == NULL))
+ {
+ MCA_TRACE_ERROR1 ("The given MCL is not expecting this API:%d", p_ccb->status);
+ return result;
+ }
+
+ p_dcb->p_chnl_cfg = p_chnl_cfg;
+ BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_MCAP_DATA, p_ccb->sec_mask,
+ p_ccb->data_vpsm, BTM_SEC_PROTO_MCA, p_ccb->p_tx_req->dcb_idx);
+ p_dcb->lcid = mca_l2c_open_req(p_ccb->peer_addr, p_ccb->data_vpsm, p_dcb->p_chnl_cfg);
+ if (p_dcb->lcid)
+ {
+ p_tbl = mca_tc_tbl_dalloc(p_dcb);
+ if (p_tbl)
+ {
+ p_tbl->state = MCA_TC_ST_CONN;
+ result = MCA_SUCCESS;
+ }
+ }
+ }
+ return result;
+}
+
+
+/*******************************************************************************
+**
+** Function MCA_Abort
+**
+** Description This function sends a ABORT_MDL request to the peer device.
+** When the response is received, a MCA_ABORT_CFM_EVT is reported.
+**
+** Returns MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+tMCA_RESULT MCA_Abort(tMCA_CL mcl)
+{
+ tMCA_RESULT result = MCA_BAD_HANDLE;
+ tMCA_CCB *p_ccb = mca_ccb_by_hdl(mcl);
+ tMCA_CCB_MSG *p_evt_data;
+ tMCA_DCB *p_dcb;
+
+ MCA_TRACE_API1 ("MCA_Abort: %d", mcl);
+ if (p_ccb)
+ {
+ result = MCA_NO_RESOURCES;
+ /* verify that we are waiting for data channel to come up with the given mdl */
+ if ((p_ccb->p_tx_req == NULL) || (p_ccb->status != MCA_CCB_STAT_PENDING) ||
+ ((p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx)) == NULL))
+ {
+ MCA_TRACE_ERROR1 ("The given MCL is not expecting this API:%d", p_ccb->status);
+ return result;
+ }
+
+ if (p_ccb->cong)
+ {
+ MCA_TRACE_ERROR0 ("congested");
+ return MCA_BUSY;
+ }
+
+ result = MCA_NO_RESOURCES;
+ p_evt_data = (tMCA_CCB_MSG *)GKI_getbuf (sizeof(tMCA_CCB_MSG));
+ if (p_evt_data)
+ {
+ result = MCA_SUCCESS;
+ p_evt_data->op_code = MCA_OP_MDL_ABORT_REQ;
+ p_evt_data->hdr.event = MCA_CCB_API_REQ_EVT;
+ mca_ccb_event(p_ccb, MCA_CCB_API_REQ_EVT, (tMCA_CCB_EVT *)p_evt_data);
+ }
+
+ }
+ return result;
+}
+
+
+/*******************************************************************************
+**
+** Function MCA_Delete
+**
+** Description This function sends a DELETE_MDL request to the peer device.
+** When the response is received, a MCA_DELETE_CFM_EVT is reported.
+**
+** Returns MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+tMCA_RESULT MCA_Delete(tMCA_CL mcl, UINT16 mdl_id)
+{
+ tMCA_RESULT result = MCA_BAD_HANDLE;
+ tMCA_CCB *p_ccb = mca_ccb_by_hdl(mcl);
+ tMCA_CCB_MSG *p_evt_data;
+
+ MCA_TRACE_API1 ("MCA_Delete: %d ", mcl);
+ if (p_ccb)
+ {
+ if (p_ccb->cong)
+ {
+ MCA_TRACE_ERROR0 ("congested");
+ return MCA_BUSY;
+ }
+ if (!MCA_IS_VALID_MDL_ID(mdl_id) && (mdl_id != MCA_ALL_MDL_ID))
+ {
+ MCA_TRACE_ERROR1 ("bad mdl id: %d ", mdl_id);
+ return MCA_BAD_PARAMS;
+ }
+ p_evt_data = (tMCA_CCB_MSG *)GKI_getbuf (sizeof(tMCA_CCB_MSG));
+ if (p_evt_data)
+ {
+ result = MCA_SUCCESS;
+ p_evt_data->mdl_id = mdl_id;
+ p_evt_data->op_code = MCA_OP_MDL_DELETE_REQ;
+ p_evt_data->hdr.event = MCA_CCB_API_REQ_EVT;
+ mca_ccb_event(p_ccb, MCA_CCB_API_REQ_EVT, (tMCA_CCB_EVT *)p_evt_data);
+ }
+ else
+ result = MCA_NO_RESOURCES;
+ }
+ return result;
+}
+
+/*******************************************************************************
+**
+** Function MCA_WriteReq
+**
+** Description Send a data packet to the peer device.
+**
+** The application passes the packet using the BT_HDR structure.
+** The offset field must be equal to or greater than L2CAP_MIN_OFFSET.
+** This allows enough space in the buffer for the L2CAP header.
+**
+** The memory pointed to by p_pkt must be a GKI buffer
+** allocated by the application. This buffer will be freed
+** by the protocol stack; the application must not free
+** this buffer.
+**
+** Returns MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+tMCA_RESULT MCA_WriteReq(tMCA_DL mdl, BT_HDR *p_pkt)
+{
+ tMCA_RESULT result = MCA_BAD_HANDLE;
+ tMCA_DCB *p_dcb = mca_dcb_by_hdl(mdl);
+ tMCA_DCB_EVT evt_data;
+
+ MCA_TRACE_API1 ("MCA_WriteReq: %d ", mdl);
+ if (p_dcb)
+ {
+ if (p_dcb->cong)
+ {
+ result = MCA_BUSY;
+ }
+ else
+ {
+ evt_data.p_pkt = p_pkt;
+ result = MCA_SUCCESS;
+ mca_dcb_event(p_dcb, MCA_DCB_API_WRITE_EVT, &evt_data);
+ }
+ }
+ return result;
+}
+
+/*******************************************************************************
+**
+** Function MCA_GetL2CapChannel
+**
+** Description Get the L2CAP CID used by the given data channel handle.
+**
+** Returns L2CAP channel ID if successful, otherwise 0.
+**
+*******************************************************************************/
+UINT16 MCA_GetL2CapChannel (tMCA_DL mdl)
+{
+ UINT16 lcid = 0;
+ tMCA_DCB *p_dcb = mca_dcb_by_hdl(mdl);
+
+ MCA_TRACE_API1 ("MCA_GetL2CapChannel: %d ", mdl);
+ if (p_dcb)
+ lcid = p_dcb->lcid;
+ return lcid;
+}
+
diff --git a/stack/mcap/mca_cact.c b/stack/mcap/mca_cact.c
new file mode 100644
index 0000000..d074172
--- /dev/null
+++ b/stack/mcap/mca_cact.c
@@ -0,0 +1,567 @@
+/*****************************************************************************
+**
+** Name: mca_cact.c
+**
+** Description: This is the implementation file for the MCAP
+** Control Channel Action Functions.
+**
+** Copyright (c) 2009-2009, Broadcom Corp., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include <string.h>
+#include "bt_target.h"
+#include "gki.h"
+#include "btm_api.h"
+#include "mca_api.h"
+#include "mca_defs.h"
+#include "mca_int.h"
+
+
+#include "btu.h"
+/*****************************************************************************
+** constants
+*****************************************************************************/
+/*******************************************************************************
+**
+** Function mca_ccb_rsp_tout
+**
+** Description This function processes the response timeout.
+**
+** Returns void.
+**
+*******************************************************************************/
+void mca_ccb_rsp_tout(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
+{
+ tMCA_CTRL evt_data;
+ mca_ccb_report_event(p_ccb, MCA_RSP_TOUT_IND_EVT, &evt_data);
+}
+
+/*******************************************************************************
+**
+** Function mca_ccb_report_event
+**
+** Description This function reports the given event.
+**
+** Returns void.
+**
+*******************************************************************************/
+void mca_ccb_report_event(tMCA_CCB *p_ccb, UINT8 event, tMCA_CTRL *p_data)
+{
+ if (p_ccb && p_ccb->p_rcb && p_ccb->p_rcb->p_cback)
+ (*p_ccb->p_rcb->p_cback)(mca_rcb_to_handle(p_ccb->p_rcb), mca_ccb_to_hdl(p_ccb), event, p_data);
+}
+
+/*******************************************************************************
+**
+** Function mca_ccb_free_msg
+**
+** Description This function frees the received message.
+**
+** Returns void.
+**
+*******************************************************************************/
+void mca_ccb_free_msg(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
+{
+ GKI_freebuf (p_data);
+}
+
+/*******************************************************************************
+**
+** Function mca_ccb_snd_req
+**
+** Description This function builds a request and sends it to the peer.
+**
+** Returns void.
+**
+*******************************************************************************/
+void mca_ccb_snd_req(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
+{
+ tMCA_CCB_MSG *p_msg = (tMCA_CCB_MSG *)p_data;
+ BT_HDR *p_pkt;
+ UINT8 *p, *p_start;
+ BOOLEAN is_abort = FALSE;
+ tMCA_DCB *p_dcb;
+
+ MCA_TRACE_DEBUG2 ("mca_ccb_snd_req cong=%d req=%d", p_ccb->cong, p_msg->op_code);
+ /* check for abort request */
+ if ((p_ccb->status == MCA_CCB_STAT_PENDING) && (p_msg->op_code == MCA_OP_MDL_ABORT_REQ))
+ {
+ p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx);
+ /* the Abort API does not have the associated mdl_id.
+ * Get the mdl_id in dcb to compose the request */
+ p_msg->mdl_id = p_dcb->mdl_id;
+ mca_dcb_event(p_dcb, MCA_DCB_API_CLOSE_EVT, NULL);
+ mca_free_buf ((void **)&p_ccb->p_tx_req);
+ p_ccb->status = MCA_CCB_STAT_NORM;
+ is_abort = TRUE;
+ }
+
+ /* no pending outgoing messages or it's an abort request for a pending data channel */
+ if ((!p_ccb->p_tx_req) || is_abort)
+ {
+ p_ccb->p_tx_req = p_msg;
+ if (!p_ccb->cong)
+ {
+ p_pkt = (BT_HDR *)GKI_getbuf (MCA_CTRL_MTU);
+ if (p_pkt)
+ {
+ p_pkt->offset = L2CAP_MIN_OFFSET;
+ p = p_start = (UINT8*)(p_pkt + 1) + L2CAP_MIN_OFFSET;
+ *p++ = p_msg->op_code;
+ UINT16_TO_BE_STREAM (p, p_msg->mdl_id);
+ if (p_msg->op_code == MCA_OP_MDL_CREATE_REQ)
+ {
+ *p++ = p_msg->mdep_id;
+ *p++ = p_msg->param;
+ }
+ p_msg->hdr.layer_specific = TRUE; /* mark this message as sent */
+ p_pkt->len = p - p_start;
+ L2CA_DataWrite (p_ccb->lcid, p_pkt);
+ p_ccb->timer_entry.param = (TIMER_PARAM_TYPE) p_ccb;
+ btu_start_timer(&p_ccb->timer_entry, BTU_TTYPE_MCA_CCB_RSP, p_ccb->p_rcb->reg.rsp_tout);
+ }
+ }
+ /* else the L2CAP channel is congested. keep the message to be sent later */
+ }
+ else
+ {
+ MCA_TRACE_WARNING0 ("dropping api req");
+ GKI_freebuf (p_data);
+ }
+}
+
+/*******************************************************************************
+**
+** Function mca_ccb_snd_rsp
+**
+** Description This function builds a response and sends it to
+** the peer.
+**
+** Returns void.
+**
+*******************************************************************************/
+void mca_ccb_snd_rsp(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
+{
+ tMCA_CCB_MSG *p_msg = (tMCA_CCB_MSG *)p_data;
+ BT_HDR *p_pkt;
+ UINT8 *p, *p_start;
+ BOOLEAN chk_mdl = FALSE;
+ tMCA_DCB *p_dcb;
+
+ MCA_TRACE_DEBUG2 ("mca_ccb_snd_rsp cong=%d req=%d", p_ccb->cong, p_msg->op_code);
+ /* assume that API functions verified the parameters */
+ p_pkt = (BT_HDR *)GKI_getbuf (MCA_CTRL_MTU);
+ if (p_pkt)
+ {
+ p_pkt->offset = L2CAP_MIN_OFFSET;
+ p = p_start = (UINT8*)(p_pkt + 1) + L2CAP_MIN_OFFSET;
+ *p++ = p_msg->op_code;
+ *p++ = p_msg->rsp_code;
+ UINT16_TO_BE_STREAM (p, p_msg->mdl_id);
+ if (p_msg->op_code == MCA_OP_MDL_CREATE_RSP)
+ {
+ *p++ = p_msg->param;
+ chk_mdl = TRUE;
+ }
+ else if (p_msg->op_code == MCA_OP_MDL_RECONNECT_RSP)
+ chk_mdl = TRUE;
+
+ if (chk_mdl && p_msg->rsp_code == MCA_RSP_SUCCESS)
+ {
+ p_dcb = mca_dcb_by_hdl(p_msg->dcb_idx);
+ BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_MCAP_DATA, p_ccb->sec_mask,
+ p_ccb->p_rcb->reg.data_psm, BTM_SEC_PROTO_MCA, p_msg->dcb_idx);
+ p_ccb->status = MCA_CCB_STAT_PENDING;
+ /* set p_tx_req to block API_REQ/API_RSP before DL is up */
+ mca_free_buf ((void **)&p_ccb->p_tx_req);
+ p_ccb->p_tx_req = p_ccb->p_rx_msg;
+ p_ccb->p_rx_msg = NULL;
+ p_ccb->p_tx_req->dcb_idx = p_msg->dcb_idx;
+ }
+ mca_free_buf ((void **)&p_ccb->p_rx_msg);
+ p_pkt->len = p - p_start;
+ L2CA_DataWrite (p_ccb->lcid, p_pkt);
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function mca_ccb_do_disconn
+**
+** Description This function closes a control channel.
+**
+** Returns void.
+**
+*******************************************************************************/
+void mca_ccb_do_disconn (tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
+{
+ mca_dcb_close_by_mdl_id (p_ccb, MCA_ALL_MDL_ID);
+ L2CA_DisconnectReq(p_ccb->lcid);
+}
+
+/*******************************************************************************
+**
+** Function mca_ccb_cong
+**
+** Description This function sets the congestion state for the CCB.
+**
+** Returns void.
+**
+*******************************************************************************/
+void mca_ccb_cong(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
+{
+ MCA_TRACE_DEBUG2 ("mca_ccb_cong cong=%d/%d", p_ccb->cong, p_data->llcong);
+ p_ccb->cong = p_data->llcong;
+ if (!p_ccb->cong)
+ {
+ /* if there's a held packet, send it now */
+ if (p_ccb->p_tx_req && !p_ccb->p_tx_req->hdr.layer_specific)
+ {
+ p_data = (tMCA_CCB_EVT *)p_ccb->p_tx_req;
+ p_ccb->p_tx_req = NULL;
+ mca_ccb_snd_req (p_ccb, p_data);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function mca_ccb_hdl_req
+**
+** Description This function is called when a MCAP request is received from
+** the peer. It calls the application callback function to
+** report the event.
+**
+** Returns void.
+**
+*******************************************************************************/
+void mca_ccb_hdl_req(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
+{
+ BT_HDR *p_pkt = &p_data->hdr;
+ BT_HDR *p_buf;
+ UINT8 *p, *p_start;
+ tMCA_DCB *p_dcb;
+ tMCA_CTRL evt_data;
+ tMCA_CCB_MSG *p_rx_msg = NULL;
+ UINT8 reject_code = MCA_RSP_NO_RESOURCE;
+ BOOLEAN send_rsp = FALSE;
+ BOOLEAN check_req = FALSE;
+ UINT8 reject_opcode;
+
+ MCA_TRACE_DEBUG1 ("mca_ccb_hdl_req status:%d", p_ccb->status);
+ p_rx_msg = (tMCA_CCB_MSG *)p_pkt;
+ p = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ evt_data.hdr.op_code = *p++;
+ BE_STREAM_TO_UINT16 (evt_data.hdr.mdl_id, p);
+ reject_opcode = evt_data.hdr.op_code+1;
+
+ MCA_TRACE_DEBUG1 ("received mdl id: %d ", evt_data.hdr.mdl_id);
+ if (p_ccb->status == MCA_CCB_STAT_PENDING)
+ {
+ MCA_TRACE_DEBUG0 ("received req inpending state");
+ /* allow abort in pending state */
+ if ((p_ccb->status == MCA_CCB_STAT_PENDING) && (evt_data.hdr.op_code == MCA_OP_MDL_ABORT_REQ))
+ {
+ reject_code = MCA_RSP_SUCCESS;
+ send_rsp = TRUE;
+ /* clear the pending status */
+ p_ccb->status = MCA_CCB_STAT_NORM;
+ if (p_ccb->p_tx_req && ((p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx))!= NULL))
+ {
+ mca_dcb_dealloc (p_dcb, NULL);
+ mca_free_buf ((void **)&p_ccb->p_tx_req);
+ }
+ }
+ else
+ reject_code = MCA_RSP_BAD_OP;
+ }
+ else if (p_ccb->p_rx_msg)
+ {
+ MCA_TRACE_DEBUG0 ("still handling prev req");
+ /* still holding previous message, reject this new one ?? */
+
+ }
+ else if (p_ccb->p_tx_req)
+ {
+ MCA_TRACE_DEBUG1 ("still waiting for a response ctrl_vpsm:0x%x", p_ccb->ctrl_vpsm);
+ /* sent a request; waiting for response */
+ if (p_ccb->ctrl_vpsm == 0)
+ {
+ MCA_TRACE_DEBUG0 ("local is ACP. accept the cmd from INT");
+ /* local is acceptor, need to handle the request */
+ check_req = TRUE;
+ reject_code = MCA_RSP_SUCCESS;
+ /* drop the previous request */
+ if ((p_ccb->p_tx_req->op_code == MCA_OP_MDL_CREATE_REQ) &&
+ ((p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx)) != NULL))
+ {
+ mca_dcb_dealloc(p_dcb, NULL);
+ }
+ mca_free_buf ((void **)&p_ccb->p_tx_req);
+ mca_stop_timer(p_ccb);
+ }
+ else
+ {
+ /* local is initiator, ignore the req */
+ GKI_freebuf (p_pkt);
+ return;
+ }
+ }
+ else if (p_pkt->layer_specific != MCA_RSP_SUCCESS)
+ {
+
+ reject_code = (UINT8)p_pkt->layer_specific;
+ if (((evt_data.hdr.op_code >= MCA_NUM_STANDARD_OPCODE) &&
+ (evt_data.hdr.op_code < MCA_FIRST_SYNC_OP)) ||
+ (evt_data.hdr.op_code > MCA_LAST_SYNC_OP))
+ {
+ /* invalid op code */
+ reject_opcode = MCA_OP_ERROR_RSP;
+ evt_data.hdr.mdl_id = 0;
+ }
+ }
+ else
+ {
+ check_req = TRUE;
+ reject_code = MCA_RSP_SUCCESS;
+ }
+
+ if (check_req)
+ {
+ if (reject_code == MCA_RSP_SUCCESS)
+ {
+ reject_code = MCA_RSP_BAD_MDL;
+ if (MCA_IS_VALID_MDL_ID(evt_data.hdr.mdl_id) ||
+ ((evt_data.hdr.mdl_id == MCA_ALL_MDL_ID) && (evt_data.hdr.op_code == MCA_OP_MDL_DELETE_REQ)))
+ {
+ reject_code = MCA_RSP_SUCCESS;
+ /* mdl_id is valid according to the spec */
+ switch (evt_data.hdr.op_code)
+ {
+ case MCA_OP_MDL_CREATE_REQ:
+ evt_data.create_ind.dep_id = *p++;
+ evt_data.create_ind.cfg = *p++;
+ p_rx_msg->mdep_id = evt_data.create_ind.dep_id;
+ if (!mca_is_valid_dep_id(p_ccb->p_rcb, p_rx_msg->mdep_id))
+ {
+ MCA_TRACE_ERROR0 ("not a valid local mdep id");
+ reject_code = MCA_RSP_BAD_MDEP;
+ }
+ else if (mca_ccb_uses_mdl_id(p_ccb, evt_data.hdr.mdl_id))
+ {
+ MCA_TRACE_DEBUG0 ("the mdl_id is currently used in the CL(create)");
+ mca_dcb_close_by_mdl_id(p_ccb, evt_data.hdr.mdl_id);
+ }
+ else
+ {
+ /* check if this dep still have MDL available */
+ if (mca_dep_free_mdl(p_ccb, evt_data.create_ind.dep_id) == 0)
+ {
+ MCA_TRACE_ERROR0 ("the mdep is currently using max_mdl");
+ reject_code = MCA_RSP_MDEP_BUSY;
+ }
+ }
+ break;
+
+ case MCA_OP_MDL_RECONNECT_REQ:
+ if (mca_ccb_uses_mdl_id(p_ccb, evt_data.hdr.mdl_id))
+ {
+ MCA_TRACE_ERROR0 ("the mdl_id is currently used in the CL(reconn)");
+ reject_code = MCA_RSP_MDL_BUSY;
+ }
+ break;
+
+ case MCA_OP_MDL_ABORT_REQ:
+ reject_code = MCA_RSP_BAD_OP;
+ break;
+
+ case MCA_OP_MDL_DELETE_REQ:
+ /* delete the associated mdl */
+ mca_dcb_close_by_mdl_id(p_ccb, evt_data.hdr.mdl_id);
+ send_rsp = TRUE;
+ break;
+ }
+ }
+ }
+ }
+
+ if (((reject_code != MCA_RSP_SUCCESS) && (evt_data.hdr.op_code != MCA_OP_SYNC_INFO_IND))
+ || send_rsp)
+ {
+ p_buf = (BT_HDR *)GKI_getbuf (MCA_CTRL_MTU);
+ if (p_buf)
+ {
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p = p_start = (UINT8*)(p_buf + 1) + L2CAP_MIN_OFFSET;
+ *p++ = reject_opcode;
+ *p++ = reject_code;
+ UINT16_TO_BE_STREAM (p, evt_data.hdr.mdl_id);
+ /*
+ if (((*p_start) == MCA_OP_MDL_CREATE_RSP) && (reject_code == MCA_RSP_SUCCESS))
+ {
+ *p++ = evt_data.create_ind.cfg;
+ }
+ */
+
+ p_buf->len = p - p_start;
+ L2CA_DataWrite (p_ccb->lcid, p_buf);
+ }
+ }
+
+ if (reject_code == MCA_RSP_SUCCESS)
+ {
+ /* use the received GKI buffer to store information to double check response API */
+ p_rx_msg->op_code = evt_data.hdr.op_code;
+ p_rx_msg->mdl_id = evt_data.hdr.mdl_id;
+ p_ccb->p_rx_msg = p_rx_msg;
+ if (send_rsp)
+ {
+ GKI_freebuf (p_pkt);
+ p_ccb->p_rx_msg = NULL;
+ }
+ mca_ccb_report_event(p_ccb, evt_data.hdr.op_code, &evt_data);
+ }
+ else
+ GKI_freebuf (p_pkt);
+}
+
+/*******************************************************************************
+**
+** Function mca_ccb_hdl_rsp
+**
+** Description This function is called when a MCAP response is received from
+** the peer. It calls the application callback function with
+** the results.
+**
+** Returns void.
+**
+*******************************************************************************/
+void mca_ccb_hdl_rsp(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
+{
+ BT_HDR *p_pkt = &p_data->hdr;
+ UINT8 *p;
+ tMCA_CTRL evt_data;
+ BOOLEAN chk_mdl = FALSE;
+ tMCA_DCB *p_dcb;
+ tMCA_RESULT result = MCA_BAD_HANDLE;
+ tMCA_TC_TBL *p_tbl;
+
+ if (p_ccb->p_tx_req)
+ {
+ /* verify that the received response matches the sent request */
+ p = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ evt_data.hdr.op_code = *p++;
+ if ((evt_data.hdr.op_code == 0) ||
+ ((p_ccb->p_tx_req->op_code + 1) == evt_data.hdr.op_code))
+ {
+ evt_data.rsp.rsp_code = *p++;
+ mca_stop_timer(p_ccb);
+ BE_STREAM_TO_UINT16 (evt_data.hdr.mdl_id, p);
+ if (evt_data.hdr.op_code == MCA_OP_MDL_CREATE_RSP)
+ {
+ evt_data.create_cfm.cfg = *p++;
+ chk_mdl = TRUE;
+ }
+ else if (evt_data.hdr.op_code == MCA_OP_MDL_RECONNECT_RSP)
+ chk_mdl = TRUE;
+
+ if (chk_mdl)
+ {
+ p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx);
+ if (evt_data.rsp.rsp_code == MCA_RSP_SUCCESS)
+ {
+ if (evt_data.hdr.mdl_id != p_dcb->mdl_id)
+ {
+ MCA_TRACE_ERROR2 ("peer's mdl_id=%d != our mdl_id=%d", evt_data.hdr.mdl_id, p_dcb->mdl_id);
+ /* change the response code to be an error */
+ if (evt_data.rsp.rsp_code == MCA_RSP_SUCCESS)
+ {
+ evt_data.rsp.rsp_code = MCA_RSP_BAD_MDL;
+ /* send Abort */
+ p_ccb->status = MCA_CCB_STAT_PENDING;
+ MCA_Abort(mca_ccb_to_hdl(p_ccb));
+ }
+ }
+ else if (p_dcb->p_chnl_cfg)
+ {
+ /* the data channel configuration is known. Proceed with data channel initiation */
+ BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_MCAP_DATA, p_ccb->sec_mask,
+ p_ccb->data_vpsm, BTM_SEC_PROTO_MCA, p_ccb->p_tx_req->dcb_idx);
+ p_dcb->lcid = mca_l2c_open_req(p_ccb->peer_addr, p_ccb->data_vpsm, p_dcb->p_chnl_cfg);
+ if (p_dcb->lcid)
+ {
+ p_tbl = mca_tc_tbl_dalloc(p_dcb);
+ if (p_tbl)
+ {
+ p_tbl->state = MCA_TC_ST_CONN;
+ p_ccb->status = MCA_CCB_STAT_PENDING;
+ result = MCA_SUCCESS;
+ }
+ }
+ }
+ else
+ {
+ /* mark this MCL as pending and wait for MCA_DataChnlCfg */
+ p_ccb->status = MCA_CCB_STAT_PENDING;
+ result = MCA_SUCCESS;
+ }
+ }
+
+ if (result != MCA_SUCCESS && p_dcb)
+ {
+ mca_dcb_dealloc(p_dcb, NULL);
+ }
+ } /* end of chk_mdl */
+
+ if (p_ccb->status != MCA_CCB_STAT_PENDING)
+ mca_free_buf ((void **)&p_ccb->p_tx_req);
+ mca_ccb_report_event(p_ccb, evt_data.hdr.op_code, &evt_data);
+ }
+ /* else a bad response is received */
+ }
+ else
+ {
+ /* not expecting any response. drop it */
+ MCA_TRACE_WARNING0 ("dropping received rsp (not expecting a response)");
+ }
+ GKI_freebuf (p_data);
+}
+
+/*******************************************************************************
+**
+** Function mca_ccb_ll_open
+**
+** Description This function is called to report MCA_CONNECT_IND_EVT event.
+** It also clears the congestion flag (ccb.cong).
+**
+** Returns void.
+**
+*******************************************************************************/
+void mca_ccb_ll_open (tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
+{
+ tMCA_CTRL evt_data;
+ p_ccb->cong = FALSE;
+ evt_data.connect_ind.mtu = p_data->open.peer_mtu;
+ memcpy (evt_data.connect_ind.bd_addr, p_ccb->peer_addr, BD_ADDR_LEN);
+ mca_ccb_report_event (p_ccb, MCA_CONNECT_IND_EVT, &evt_data);
+}
+
+/*******************************************************************************
+**
+** Function mca_ccb_dl_open
+**
+** Description This function is called when data channel is open.
+** It clears p_tx_req to allow other message exchage on this CL.
+**
+** Returns void.
+**
+*******************************************************************************/
+void mca_ccb_dl_open (tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
+{
+ mca_free_buf ((void **)&p_ccb->p_tx_req);
+ mca_free_buf ((void **)&p_ccb->p_rx_msg);
+ p_ccb->status = MCA_CCB_STAT_NORM;
+}
+
diff --git a/stack/mcap/mca_csm.c b/stack/mcap/mca_csm.c
new file mode 100644
index 0000000..411ee6a
--- /dev/null
+++ b/stack/mcap/mca_csm.c
@@ -0,0 +1,372 @@
+/*****************************************************************************
+**
+** Name: mca_csm.c
+**
+** Description: This is the implementation file for the MCAP
+** Control channel state machine.
+**
+** Copyright (c) 2009-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include <string.h>
+
+#include "bt_target.h"
+#include "mca_api.h"
+#include "mca_defs.h"
+#include "mca_int.h"
+#include "btu.h"
+
+/*****************************************************************************
+** data channel state machine constants and types
+*****************************************************************************/
+enum
+{
+ MCA_CCB_FREE_MSG,
+ MCA_CCB_SND_REQ,
+ MCA_CCB_SND_RSP,
+ MCA_CCB_DO_DISCONN,
+ MCA_CCB_CONG,
+ MCA_CCB_HDL_REQ,
+ MCA_CCB_HDL_RSP,
+ MCA_CCB_LL_OPEN,
+ MCA_CCB_DL_OPEN,
+ MCA_CCB_DEALLOC,
+ MCA_CCB_RSP_TOUT,
+ MCA_CCB_NUM_ACTIONS
+};
+#define MCA_CCB_IGNORE MCA_CCB_NUM_ACTIONS
+
+/* action function list */
+const tMCA_CCB_ACTION mca_ccb_action[] = {
+ mca_ccb_free_msg,
+ mca_ccb_snd_req,
+ mca_ccb_snd_rsp,
+ mca_ccb_do_disconn,
+ mca_ccb_cong,
+ mca_ccb_hdl_req,
+ mca_ccb_hdl_rsp,
+ mca_ccb_ll_open,
+ mca_ccb_dl_open,
+ mca_ccb_dealloc,
+ mca_ccb_rsp_tout,
+};
+
+/* state table information */
+#define MCA_CCB_ACTIONS 1 /* number of actions */
+#define MCA_CCB_ACT_COL 0 /* position of action function */
+#define MCA_CCB_NEXT_STATE 1 /* position of next state */
+#define MCA_CCB_NUM_COLS 2 /* number of columns in state tables */
+
+/* state table for opening state */
+const UINT8 mca_ccb_st_opening[][MCA_CCB_NUM_COLS] = {
+/* Event Action Next State */
+/* MCA_CCB_API_CONNECT_EVT */ {MCA_CCB_IGNORE, MCA_CCB_OPENING_ST},
+/* MCA_CCB_API_DISCONNECT_EVT */ {MCA_CCB_DO_DISCONN, MCA_CCB_CLOSING_ST},
+/* MCA_CCB_API_REQ_EVT */ {MCA_CCB_FREE_MSG, MCA_CCB_OPENING_ST},
+/* MCA_CCB_API_RSP_EVT */ {MCA_CCB_IGNORE, MCA_CCB_OPENING_ST},
+/* MCA_CCB_MSG_REQ_EVT */ {MCA_CCB_FREE_MSG, MCA_CCB_OPENING_ST},
+/* MCA_CCB_MSG_RSP_EVT */ {MCA_CCB_FREE_MSG, MCA_CCB_OPENING_ST},
+/* MCA_CCB_DL_OPEN_EVT */ {MCA_CCB_IGNORE, MCA_CCB_OPENING_ST},
+/* MCA_CCB_LL_OPEN_EVT */ {MCA_CCB_LL_OPEN, MCA_CCB_OPEN_ST},
+/* MCA_CCB_LL_CLOSE_EVT */ {MCA_CCB_DEALLOC, MCA_CCB_NULL_ST},
+/* MCA_CCB_LL_CONG_EVT */ {MCA_CCB_CONG, MCA_CCB_OPENING_ST},
+/* MCA_CCB_RSP_TOUT_EVT */ {MCA_CCB_IGNORE, MCA_CCB_OPENING_ST}
+};
+
+/* state table for open state */
+const UINT8 mca_ccb_st_open[][MCA_CCB_NUM_COLS] = {
+/* Event Action Next State */
+/* MCA_CCB_API_CONNECT_EVT */ {MCA_CCB_IGNORE, MCA_CCB_OPEN_ST},
+/* MCA_CCB_API_DISCONNECT_EVT */ {MCA_CCB_DO_DISCONN, MCA_CCB_CLOSING_ST},
+/* MCA_CCB_API_REQ_EVT */ {MCA_CCB_SND_REQ, MCA_CCB_OPEN_ST},
+/* MCA_CCB_API_RSP_EVT */ {MCA_CCB_SND_RSP, MCA_CCB_OPEN_ST},
+/* MCA_CCB_MSG_REQ_EVT */ {MCA_CCB_HDL_REQ, MCA_CCB_OPEN_ST},
+/* MCA_CCB_MSG_RSP_EVT */ {MCA_CCB_HDL_RSP, MCA_CCB_OPEN_ST},
+/* MCA_CCB_DL_OPEN_EVT */ {MCA_CCB_DL_OPEN, MCA_CCB_OPEN_ST},
+/* MCA_CCB_LL_OPEN_EVT */ {MCA_CCB_IGNORE, MCA_CCB_OPEN_ST},
+/* MCA_CCB_LL_CLOSE_EVT */ {MCA_CCB_DEALLOC, MCA_CCB_NULL_ST},
+/* MCA_CCB_LL_CONG_EVT */ {MCA_CCB_CONG, MCA_CCB_OPEN_ST},
+/* MCA_CCB_RSP_TOUT_EVT */ {MCA_CCB_RSP_TOUT, MCA_CCB_OPEN_ST}
+};
+
+/* state table for closing state */
+const UINT8 mca_ccb_st_closing[][MCA_CCB_NUM_COLS] = {
+/* Event Action Next State */
+/* MCA_CCB_API_CONNECT_EVT */ {MCA_CCB_IGNORE, MCA_CCB_CLOSING_ST},
+/* MCA_CCB_API_DISCONNECT_EVT */ {MCA_CCB_IGNORE, MCA_CCB_CLOSING_ST},
+/* MCA_CCB_API_REQ_EVT */ {MCA_CCB_FREE_MSG, MCA_CCB_CLOSING_ST},
+/* MCA_CCB_API_RSP_EVT */ {MCA_CCB_IGNORE, MCA_CCB_CLOSING_ST},
+/* MCA_CCB_MSG_REQ_EVT */ {MCA_CCB_FREE_MSG, MCA_CCB_CLOSING_ST},
+/* MCA_CCB_MSG_RSP_EVT */ {MCA_CCB_FREE_MSG, MCA_CCB_CLOSING_ST},
+/* MCA_CCB_DL_OPEN_EVT */ {MCA_CCB_IGNORE, MCA_CCB_CLOSING_ST},
+/* MCA_CCB_LL_OPEN_EVT */ {MCA_CCB_IGNORE, MCA_CCB_CLOSING_ST},
+/* MCA_CCB_LL_CLOSE_EVT */ {MCA_CCB_DEALLOC, MCA_CCB_NULL_ST},
+/* MCA_CCB_LL_CONG_EVT */ {MCA_CCB_IGNORE, MCA_CCB_CLOSING_ST},
+/* MCA_CCB_RSP_TOUT_EVT */ {MCA_CCB_IGNORE, MCA_CCB_CLOSING_ST}
+};
+
+/* type for state table */
+typedef const UINT8 (*tMCA_CCB_ST_TBL)[MCA_CCB_NUM_COLS];
+
+/* state table */
+const tMCA_CCB_ST_TBL mca_ccb_st_tbl[] = {
+ mca_ccb_st_opening,
+ mca_ccb_st_open,
+ mca_ccb_st_closing
+};
+
+#if (BT_TRACE_VERBOSE == TRUE)
+/* verbose event strings for trace */
+static const char * const mca_ccb_evt_str[] = {
+ "API_CONNECT_EVT",
+ "API_DISCONNECT_EVT",
+ "API_REQ_EVT",
+ "API_RSP_EVT",
+ "MSG_REQ_EVT",
+ "MSG_RSP_EVT",
+ "DL_OPEN_EVT",
+ "LL_OPEN_EVT",
+ "LL_CLOSE_EVT",
+ "LL_CONG_EVT",
+ "RSP_TOUT_EVT"
+};
+/* verbose state strings for trace */
+static const char * const mca_ccb_st_str[] = {
+ "NULL_ST",
+ "OPENING_ST",
+ "OPEN_ST",
+ "CLOSING_ST"
+};
+#endif
+
+/*******************************************************************************
+**
+** Function mca_stop_timer
+**
+** Description This function is stop a MCAP timer
+**
+** This function is for use internal to MCAP only.
+**
+** Returns void
+**
+*******************************************************************************/
+void mca_stop_timer(tMCA_CCB *p_ccb)
+{
+ if (p_ccb->timer_entry.event == BTU_TTYPE_MCA_CCB_RSP)
+ {
+ btu_stop_timer(&p_ccb->timer_entry);
+ p_ccb->timer_entry.event = 0;
+ }
+}
+
+/*******************************************************************************
+**
+** Function mca_ccb_event
+**
+** Description This function is the CCB state machine main function.
+** It uses the state and action function tables to execute
+** action functions.
+**
+** Returns void.
+**
+*******************************************************************************/
+void mca_ccb_event(tMCA_CCB *p_ccb, UINT8 event, tMCA_CCB_EVT *p_data)
+{
+ tMCA_CCB_ST_TBL state_table;
+ UINT8 action;
+
+#if (BT_TRACE_VERBOSE == TRUE)
+ MCA_TRACE_EVENT3("CCB ccb=%d event=%s state=%s", mca_ccb_to_hdl(p_ccb), mca_ccb_evt_str[event], mca_ccb_st_str[p_ccb->state]);
+#else
+ MCA_TRACE_EVENT3("CCB ccb=%d event=%d state=%d", mca_ccb_to_hdl(p_ccb), event, p_ccb->state);
+#endif
+
+ /* look up the state table for the current state */
+ state_table = mca_ccb_st_tbl[p_ccb->state - 1];
+
+ /* set next state */
+ p_ccb->state = state_table[event][MCA_CCB_NEXT_STATE];
+
+ /* execute action functions */
+ if ((action = state_table[event][MCA_CCB_ACT_COL]) != MCA_CCB_IGNORE)
+ {
+ (*mca_ccb_action[action])(p_ccb, p_data);
+ }
+}
+
+/*******************************************************************************
+**
+** Function mca_ccb_by_bd
+**
+** Description This function looks up the CCB based on the BD address.
+** It returns a pointer to the CCB.
+** If no CCB is found it returns NULL.
+**
+** Returns void.
+**
+*******************************************************************************/
+tMCA_CCB *mca_ccb_by_bd(tMCA_HANDLE handle, BD_ADDR bd_addr)
+{
+ tMCA_CCB *p_ccb = NULL;
+ tMCA_RCB *p_rcb = mca_rcb_by_handle(handle);
+ tMCA_CCB *p_ccb_tmp;
+ int i;
+
+ if (p_rcb)
+ {
+ i = handle-1;
+ p_ccb_tmp = &mca_cb.ccb[i*MCA_NUM_LINKS];
+ for (i=0; i<MCA_NUM_LINKS; i++, p_ccb_tmp++)
+ {
+ if (p_ccb_tmp->state != MCA_CCB_NULL_ST && memcmp(p_ccb_tmp->peer_addr, bd_addr, BD_ADDR_LEN) == 0)
+ {
+ p_ccb = p_ccb_tmp;
+ break;
+ }
+ }
+ }
+ return p_ccb;
+}
+
+/*******************************************************************************
+**
+** Function mca_ccb_alloc
+**
+** Description This function allocates a CCB and copies the BD address to
+** the CCB. It returns a pointer to the CCB. If no CCB can
+** be allocated it returns NULL.
+**
+** Returns void.
+**
+*******************************************************************************/
+tMCA_CCB *mca_ccb_alloc(tMCA_HANDLE handle, BD_ADDR bd_addr)
+{
+ tMCA_CCB *p_ccb = NULL;
+ tMCA_RCB *p_rcb = mca_rcb_by_handle(handle);
+ tMCA_CCB *p_ccb_tmp;
+ int i;
+
+ MCA_TRACE_DEBUG1("mca_ccb_alloc handle:0x%x", handle);
+ if (p_rcb)
+ {
+ i = handle-1;
+ p_ccb_tmp = &mca_cb.ccb[i*MCA_NUM_LINKS];
+ for (i=0; i<MCA_NUM_LINKS; i++, p_ccb_tmp++)
+ {
+ if (p_ccb_tmp->state == MCA_CCB_NULL_ST)
+ {
+ p_ccb_tmp->p_rcb = p_rcb;
+ p_ccb_tmp->state = MCA_CCB_OPENING_ST;
+ p_ccb_tmp->cong = TRUE;
+ memcpy(p_ccb_tmp->peer_addr, bd_addr, BD_ADDR_LEN);
+ p_ccb = p_ccb_tmp;
+ break;
+ }
+ }
+ }
+ return p_ccb;
+}
+
+
+/*******************************************************************************
+**
+** Function mca_ccb_dealloc
+**
+** Description This function deallocates a CCB.
+**
+** Returns void.
+**
+*******************************************************************************/
+void mca_ccb_dealloc(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
+{
+ tMCA_CTRL evt_data;
+
+ MCA_TRACE_DEBUG1("mca_ccb_dealloc ctrl_vpsm:0x%x", p_ccb->ctrl_vpsm);
+ mca_dcb_close_by_mdl_id (p_ccb, MCA_ALL_MDL_ID);
+ if (p_ccb->ctrl_vpsm)
+ {
+ L2CA_Deregister (p_ccb->ctrl_vpsm);
+ }
+ if (p_ccb->data_vpsm)
+ {
+ L2CA_Deregister (p_ccb->data_vpsm);
+ }
+ mca_free_buf ((void **)&p_ccb->p_rx_msg);
+ mca_free_buf ((void **)&p_ccb->p_tx_req);
+ mca_stop_timer(p_ccb);
+
+ if (p_data)
+ {
+ /* non-NULL -> an action function -> report disconnect event */
+ memcpy (evt_data.disconnect_ind.bd_addr, p_ccb->peer_addr, BD_ADDR_LEN);
+ evt_data.disconnect_ind.reason = p_data->close.reason;
+ mca_ccb_report_event(p_ccb, MCA_DISCONNECT_IND_EVT, &evt_data);
+ }
+ mca_free_tc_tbl_by_lcid (p_ccb->lcid);
+ memset (p_ccb, 0, sizeof (tMCA_CCB));
+}
+
+/*******************************************************************************
+**
+** Function mca_ccb_to_hdl
+**
+** Description This function converts a pointer to a CCB to a tMCA_CL
+** and returns the value.
+**
+** Returns void.
+**
+*******************************************************************************/
+tMCA_CL mca_ccb_to_hdl(tMCA_CCB *p_ccb)
+{
+ return (UINT8) (p_ccb - mca_cb.ccb + 1);
+}
+
+/*******************************************************************************
+**
+** Function mca_ccb_by_hdl
+**
+** Description This function converts an index value to a CCB. It returns
+** a pointer to the CCB. If no valid CCB matches the index it
+** returns NULL.
+**
+** Returns void.
+**
+*******************************************************************************/
+tMCA_CCB *mca_ccb_by_hdl(tMCA_CL mcl)
+{
+ tMCA_CCB * p_ccb = NULL;
+ if (mcl && mcl <= MCA_NUM_CCBS && mca_cb.ccb[mcl-1].state)
+ p_ccb = &mca_cb.ccb[mcl-1];
+ return p_ccb;
+}
+
+
+/*******************************************************************************
+**
+** Function mca_ccb_uses_mdl_id
+**
+** Description This function checkes if a given mdl_id is in use.
+**
+** Returns TRUE, if the given mdl_id is currently used in the MCL.
+**
+*******************************************************************************/
+BOOLEAN mca_ccb_uses_mdl_id(tMCA_CCB *p_ccb, UINT16 mdl_id)
+{
+ BOOLEAN uses = FALSE;
+ tMCA_DCB *p_dcb;
+ int i;
+
+ i = mca_ccb_to_hdl(p_ccb)-1;
+ p_dcb = &mca_cb.dcb[i*MCA_NUM_MDLS];
+ for (i=0; i<MCA_NUM_MDLS; i++, p_dcb++)
+ {
+ if (p_dcb->state != MCA_DCB_NULL_ST && p_dcb->mdl_id == mdl_id)
+ {
+ uses = TRUE;
+ break;
+ }
+ }
+
+ return uses;
+}
diff --git a/stack/mcap/mca_dact.c b/stack/mcap/mca_dact.c
new file mode 100644
index 0000000..5ace8fa
--- /dev/null
+++ b/stack/mcap/mca_dact.c
@@ -0,0 +1,149 @@
+/*****************************************************************************
+**
+** Name: mca_dact.c
+**
+** Description: This is the implementation file for the MCAP
+** Data Channel Action Functions.
+**
+** Copyright (c) 2009-2009, Broadcom Corp., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include "bt_target.h"
+#include "gki.h"
+#include "mca_api.h"
+#include "mca_int.h"
+
+/*******************************************************************************
+**
+** Function mca_dcb_report_cong
+**
+** Description This function is called to report the congestion flag.
+**
+** Returns void.
+**
+*******************************************************************************/
+void mca_dcb_report_cong (tMCA_DCB *p_dcb)
+{
+ tMCA_CTRL evt_data;
+
+ evt_data.cong_chg.cong = p_dcb->cong;
+ evt_data.cong_chg.mdl = mca_dcb_to_hdl(p_dcb);
+ evt_data.cong_chg.mdl_id = p_dcb->mdl_id;
+ mca_ccb_report_event (p_dcb->p_ccb, MCA_CONG_CHG_EVT, &evt_data);
+}
+
+/*******************************************************************************
+**
+** Function mca_dcb_tc_open
+**
+** Description This function is called to report MCA_OPEN_IND_EVT or
+** MCA_OPEN_CFM_EVT event.
+** It also clears the congestion flag (dcb.cong).
+**
+** Returns void.
+**
+*******************************************************************************/
+void mca_dcb_tc_open (tMCA_DCB *p_dcb, tMCA_DCB_EVT *p_data)
+{
+ tMCA_CTRL evt_data;
+ tMCA_CCB *p_ccb = p_dcb->p_ccb;
+ UINT8 event = MCA_OPEN_IND_EVT;
+
+ if (p_data->open.param == MCA_INT)
+ event = MCA_OPEN_CFM_EVT;
+ p_dcb->cong = FALSE;
+ evt_data.open_cfm.mtu = p_data->open.peer_mtu;
+ evt_data.open_cfm.mdl_id = p_dcb->mdl_id;
+ evt_data.open_cfm.mdl = mca_dcb_to_hdl(p_dcb);
+ mca_ccb_event (p_ccb, MCA_CCB_DL_OPEN_EVT, NULL);
+ mca_ccb_report_event (p_ccb, event, &evt_data);
+}
+
+/*******************************************************************************
+**
+** Function mca_dcb_cong
+**
+** Description This function sets the congestion state for the DCB.
+**
+** Returns void.
+**
+*******************************************************************************/
+void mca_dcb_cong (tMCA_DCB *p_dcb, tMCA_DCB_EVT *p_data)
+{
+ p_dcb->cong = p_data->llcong;
+ mca_dcb_report_cong(p_dcb);
+}
+
+/*******************************************************************************
+**
+** Function mca_dcb_free_data
+**
+** Description This function frees the received message.
+**
+** Returns void.
+**
+*******************************************************************************/
+void mca_dcb_free_data (tMCA_DCB *p_dcb, tMCA_DCB_EVT *p_data)
+{
+ GKI_freebuf (p_data);
+}
+
+/*******************************************************************************
+**
+** Function mca_dcb_do_disconn
+**
+** Description This function closes a data channel.
+**
+** Returns void.
+**
+*******************************************************************************/
+void mca_dcb_do_disconn (tMCA_DCB *p_dcb, tMCA_DCB_EVT *p_data)
+{
+ tMCA_CLOSE close;
+ if ((p_dcb->lcid == 0) || (L2CA_DisconnectReq(p_dcb->lcid) == FALSE))
+ {
+ close.param = MCA_INT;
+ close.reason = L2CAP_DISC_OK;
+ close.lcid = 0;
+ mca_dcb_event(p_dcb, MCA_DCB_TC_CLOSE_EVT, (tMCA_DCB_EVT *) &close);
+ }
+}
+
+/*******************************************************************************
+**
+** Function mca_dcb_snd_data
+**
+** Description This function sends the data from application to the peer device.
+**
+** Returns void.
+**
+*******************************************************************************/
+void mca_dcb_snd_data (tMCA_DCB *p_dcb, tMCA_DCB_EVT *p_data)
+{
+ UINT8 status;
+
+ /* do not need to check cong, because API already checked the status */
+ status = L2CA_DataWrite (p_dcb->lcid, p_data->p_pkt);
+ if (status == L2CAP_DW_CONGESTED)
+ {
+ p_dcb->cong = TRUE;
+ mca_dcb_report_cong(p_dcb);
+ }
+}
+
+/*******************************************************************************
+**
+** Function mca_dcb_hdl_data
+**
+** Description This function reports the received data through the data
+** callback function.
+**
+** Returns void.
+**
+*******************************************************************************/
+void mca_dcb_hdl_data (tMCA_DCB *p_dcb, tMCA_DCB_EVT *p_data)
+{
+ (*p_dcb->p_cs->p_data_cback) (mca_dcb_to_hdl(p_dcb), (BT_HDR *)p_data);
+}
+
diff --git a/stack/mcap/mca_dsm.c b/stack/mcap/mca_dsm.c
new file mode 100644
index 0000000..e6139a3
--- /dev/null
+++ b/stack/mcap/mca_dsm.c
@@ -0,0 +1,334 @@
+/*****************************************************************************
+**
+** Name: mca_dsm.c
+**
+** Description: This is the implementation file for the MCAP
+** Data chahnel state machine.
+**
+** Copyright (c) 2009-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include <string.h>
+
+#include "bt_target.h"
+#include "mca_api.h"
+#include "mca_defs.h"
+#include "mca_int.h"
+
+/*****************************************************************************
+** data channel state machine constants and types
+*****************************************************************************/
+enum
+{
+ MCA_DCB_TC_OPEN,
+ MCA_DCB_CONG,
+ MCA_DCB_FREE_DATA,
+ MCA_DCB_DEALLOC,
+ MCA_DCB_DO_DISCONN,
+ MCA_DCB_SND_DATA,
+ MCA_DCB_HDL_DATA,
+ MCA_DCB_NUM_ACTIONS
+};
+#define MCA_DCB_IGNORE MCA_DCB_NUM_ACTIONS
+
+/* action function list */
+const tMCA_DCB_ACTION mca_dcb_action[] = {
+ mca_dcb_tc_open,
+ mca_dcb_cong,
+ mca_dcb_free_data,
+ mca_dcb_dealloc,
+ mca_dcb_do_disconn,
+ mca_dcb_snd_data,
+ mca_dcb_hdl_data
+};
+
+/* state table information */
+#define MCA_DCB_ACTIONS 1 /* number of actions */
+#define MCA_DCB_ACT_COL 0 /* position of action function */
+#define MCA_DCB_NEXT_STATE 1 /* position of next state */
+#define MCA_DCB_NUM_COLS 2 /* number of columns in state tables */
+
+/* state table for opening state */
+const UINT8 mca_dcb_st_opening[][MCA_DCB_NUM_COLS] = {
+/* Event Action Next State */
+/* MCA_DCB_API_CLOSE_EVT */ {MCA_DCB_DO_DISCONN, MCA_DCB_CLOSING_ST},
+/* MCA_DCB_API_WRITE_EVT */ {MCA_DCB_IGNORE, MCA_DCB_OPENING_ST},
+/* MCA_DCB_TC_OPEN_EVT */ {MCA_DCB_TC_OPEN, MCA_DCB_OPEN_ST},
+/* MCA_DCB_TC_CLOSE_EVT */ {MCA_DCB_DEALLOC, MCA_DCB_NULL_ST},
+/* MCA_DCB_TC_CONG_EVT */ {MCA_DCB_CONG, MCA_DCB_OPENING_ST},
+/* MCA_DCB_TC_DATA_EVT */ {MCA_DCB_FREE_DATA, MCA_DCB_OPENING_ST}
+};
+
+/* state table for open state */
+const UINT8 mca_dcb_st_open[][MCA_DCB_NUM_COLS] = {
+/* Event Action Next State */
+/* MCA_DCB_API_CLOSE_EVT */ {MCA_DCB_DO_DISCONN, MCA_DCB_CLOSING_ST},
+/* MCA_DCB_API_WRITE_EVT */ {MCA_DCB_SND_DATA, MCA_DCB_OPEN_ST},
+/* MCA_DCB_TC_OPEN_EVT */ {MCA_DCB_IGNORE, MCA_DCB_OPEN_ST},
+/* MCA_DCB_TC_CLOSE_EVT */ {MCA_DCB_DEALLOC, MCA_DCB_NULL_ST},
+/* MCA_DCB_TC_CONG_EVT */ {MCA_DCB_CONG, MCA_DCB_OPEN_ST},
+/* MCA_DCB_TC_DATA_EVT */ {MCA_DCB_HDL_DATA, MCA_DCB_OPEN_ST}
+};
+
+/* state table for closing state */
+const UINT8 mca_dcb_st_closing[][MCA_DCB_NUM_COLS] = {
+/* Event Action Next State */
+/* MCA_DCB_API_CLOSE_EVT */ {MCA_DCB_IGNORE, MCA_DCB_CLOSING_ST},
+/* MCA_DCB_API_WRITE_EVT */ {MCA_DCB_IGNORE, MCA_DCB_CLOSING_ST},
+/* MCA_DCB_TC_OPEN_EVT */ {MCA_DCB_TC_OPEN, MCA_DCB_OPEN_ST},
+/* MCA_DCB_TC_CLOSE_EVT */ {MCA_DCB_DEALLOC, MCA_DCB_NULL_ST},
+/* MCA_DCB_TC_CONG_EVT */ {MCA_DCB_IGNORE, MCA_DCB_CLOSING_ST},
+/* MCA_DCB_TC_DATA_EVT */ {MCA_DCB_FREE_DATA, MCA_DCB_CLOSING_ST}
+};
+
+/* type for state table */
+typedef const UINT8 (*tMCA_DCB_ST_TBL)[MCA_DCB_NUM_COLS];
+
+/* state table */
+const tMCA_DCB_ST_TBL mca_dcb_st_tbl[] = {
+ mca_dcb_st_opening,
+ mca_dcb_st_open,
+ mca_dcb_st_closing
+};
+
+#if (BT_TRACE_VERBOSE == TRUE)
+/* verbose event strings for trace */
+const char * const mca_dcb_evt_str[] = {
+ "API_CLOSE_EVT",
+ "API_WRITE_EVT",
+ "TC_OPEN_EVT",
+ "TC_CLOSE_EVT",
+ "TC_CONG_EVT",
+ "TC_DATA_EVT"
+};
+/* verbose state strings for trace */
+const char * const mca_dcb_st_str[] = {
+ "NULL_ST",
+ "OPENING_ST",
+ "OPEN_ST",
+ "CLOSING_ST"
+};
+#endif
+
+/*******************************************************************************
+**
+** Function mca_dcb_event
+**
+** Description This function is the DCB state machine main function.
+** It uses the state and action function tables to execute
+** action functions.
+**
+** Returns void.
+**
+*******************************************************************************/
+void mca_dcb_event(tMCA_DCB *p_dcb, UINT8 event, tMCA_DCB_EVT *p_data)
+{
+ tMCA_DCB_ST_TBL state_table;
+ UINT8 action;
+
+ if (p_dcb == NULL)
+ return;
+#if (BT_TRACE_VERBOSE == TRUE)
+ MCA_TRACE_EVENT3("DCB dcb=%d event=%s state=%s", mca_dcb_to_hdl(p_dcb), mca_dcb_evt_str[event], mca_dcb_st_str[p_dcb->state]);
+#else
+ MCA_TRACE_EVENT3("DCB dcb=%d event=%d state=%d", mca_dcb_to_hdl(p_dcb), event, p_dcb->state);
+#endif
+
+ /* look up the state table for the current state */
+ state_table = mca_dcb_st_tbl[p_dcb->state - 1];
+
+ /* set next state */
+ p_dcb->state = state_table[event][MCA_DCB_NEXT_STATE];
+
+ /* execute action functions */
+ if ((action = state_table[event][MCA_DCB_ACT_COL]) != MCA_DCB_IGNORE)
+ {
+ (*mca_dcb_action[action])(p_dcb, p_data);
+ }
+}
+
+/*******************************************************************************
+**
+** Function mca_dcb_alloc
+**
+** Description This function is called to allocate an DCB.
+** It initializes the DCB with the data passed to the function.
+**
+** Returns tMCA_DCB *
+**
+*******************************************************************************/
+tMCA_DCB *mca_dcb_alloc(tMCA_CCB*p_ccb, tMCA_DEP dep)
+{
+ tMCA_DCB *p_dcb = NULL, *p_dcb_tmp;
+ tMCA_RCB *p_rcb = p_ccb->p_rcb;
+ tMCA_CS *p_cs;
+ int i, max;
+
+ if (dep < MCA_NUM_DEPS)
+ {
+ p_cs = &p_rcb->dep[dep];
+ i = mca_ccb_to_hdl(p_ccb)-1;
+ p_dcb_tmp = &mca_cb.dcb[i*MCA_NUM_MDLS];
+ /* make sure p_cs->max_mdl is smaller than MCA_NUM_MDLS at MCA_CreateDep */
+ max = p_cs->max_mdl;
+ for (i=0; i<max; i++, p_dcb_tmp++)
+ {
+ if (p_dcb_tmp->state == MCA_DCB_NULL_ST)
+ {
+ p_dcb_tmp->p_ccb = p_ccb;
+ p_dcb_tmp->state = MCA_DCB_OPENING_ST;
+ p_dcb_tmp->cong = TRUE;
+ p_dcb_tmp->p_cs = p_cs;
+ p_dcb = p_dcb_tmp;
+ break;
+ }
+ }
+ }
+ return p_dcb;
+}
+
+/*******************************************************************************
+**
+** Function mca_dep_free_mdl
+**
+** Description This function is called to check the number of free mdl for
+** the given dep.
+**
+** Returns the number of free mdl for the given dep
+**
+*******************************************************************************/
+UINT8 mca_dep_free_mdl(tMCA_CCB *p_ccb, tMCA_DEP dep)
+{
+ tMCA_DCB *p_dcb;
+ tMCA_RCB *p_rcb = p_ccb->p_rcb;
+ tMCA_CS *p_cs;
+ int i, max;
+ UINT8 count = 0;
+ UINT8 left;
+
+ if (dep < MCA_NUM_DEPS)
+ {
+ p_cs = &p_rcb->dep[dep];
+ i = mca_ccb_to_hdl(p_ccb)-1;
+ p_dcb = &mca_cb.dcb[i * MCA_NUM_MDLS];
+ /* make sure p_cs->max_mdl is smaller than MCA_NUM_MDLS at MCA_CreateDep */
+ max = p_cs->max_mdl;
+ for (i=0; i<max; i++, p_dcb++)
+ {
+ if ((p_dcb->state != MCA_DCB_NULL_ST) && (p_dcb->p_cs == p_cs))
+ {
+ count++;
+ break;
+ }
+ }
+ }
+ else
+ {
+ max = 0;
+ MCA_TRACE_WARNING0("Invalid Dep ID");
+ }
+ left = max - count;
+ return left;
+}
+
+/*******************************************************************************
+**
+** Function mca_dcb_dealloc
+**
+** Description This function deallocates an DCB.
+**
+** Returns void.
+**
+*******************************************************************************/
+void mca_dcb_dealloc(tMCA_DCB *p_dcb, tMCA_DCB_EVT *p_data)
+{
+ tMCA_CCB *p_ccb = p_dcb->p_ccb;
+ UINT8 event = MCA_CLOSE_IND_EVT;
+ tMCA_CTRL evt_data;
+
+ MCA_TRACE_DEBUG0("mca_dcb_dealloc");
+ mca_free_buf ((void **)&p_dcb->p_data);
+ if (p_data)
+ {
+ /* non-NULL -> an action function -> report disconnect event */
+ evt_data.close_cfm.mdl = mca_dcb_to_hdl(p_dcb);
+ evt_data.close_cfm.reason = p_data->close.reason;
+ evt_data.close_cfm.mdl_id = p_dcb->mdl_id;
+ if (p_data->close.param == MCA_INT)
+ event = MCA_CLOSE_CFM_EVT;
+ if (p_data->close.lcid)
+ mca_ccb_report_event(p_ccb, event, &evt_data);
+ }
+ mca_free_tc_tbl_by_lcid (p_dcb->lcid);
+ memset (p_dcb, 0, sizeof (tMCA_DCB));
+}
+
+/*******************************************************************************
+**
+** Function mca_dcb_to_hdl
+**
+** Description This function converts a pointer to an DCB to a handle (tMCA_DL).
+** It returns the handle.
+**
+** Returns tMCA_DL.
+**
+*******************************************************************************/
+tMCA_DL mca_dcb_to_hdl(tMCA_DCB *p_dcb)
+{
+ return (UINT8) (p_dcb - mca_cb.dcb + 1);
+}
+
+/*******************************************************************************
+**
+** Function mca_dcb_by_hdl
+**
+** Description This function finds the DCB for a handle (tMCA_DL).
+** It returns a pointer to the DCB.
+** If no DCB matches the handle it returns NULL.
+**
+** Returns tMCA_DCB *
+**
+*******************************************************************************/
+tMCA_DCB *mca_dcb_by_hdl(tMCA_DL hdl)
+{
+ tMCA_DCB * p_dcb = NULL;
+ if (hdl && hdl <= MCA_NUM_DCBS && mca_cb.dcb[hdl-1].state)
+ p_dcb = &mca_cb.dcb[hdl-1];
+ return p_dcb;
+}
+
+/*******************************************************************************
+**
+** Function mca_dcb_close_by_mdl_id
+**
+** Description This function finds the DCB for a mdl_id and
+** disconnect the mdl
+**
+** Returns void
+**
+*******************************************************************************/
+void mca_dcb_close_by_mdl_id(tMCA_CCB*p_ccb, UINT16 mdl_id)
+{
+ tMCA_DCB *p_dcb;
+ int i;
+
+ MCA_TRACE_DEBUG1("mca_dcb_close_by_mdl_id mdl_id=%d", mdl_id);
+ i = mca_ccb_to_hdl(p_ccb)-1;
+ p_dcb = &mca_cb.dcb[i*MCA_NUM_MDLS];
+ for (i=0; i<MCA_NUM_MDLS; i++, p_dcb++)
+ {
+ if (p_dcb->state)
+ {
+ if (p_dcb->mdl_id == mdl_id)
+ {
+ mca_dcb_event(p_dcb, MCA_DCB_API_CLOSE_EVT, NULL);
+ break;
+ }
+ else if (mdl_id == MCA_ALL_MDL_ID)
+ {
+ mca_dcb_event(p_dcb, MCA_DCB_API_CLOSE_EVT, NULL);
+ }
+ }
+ }
+}
diff --git a/stack/mcap/mca_int.h b/stack/mcap/mca_int.h
new file mode 100644
index 0000000..f248dbe
--- /dev/null
+++ b/stack/mcap/mca_int.h
@@ -0,0 +1,343 @@
+/*****************************************************************************
+**
+** Name: mca_int.h
+**
+** Description: This file contains interfaces which are internal to MCAP.
+**
+** Copyright (c) 2009-2010, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef MCA_INT_H
+#define MCA_INT_H
+#include "gki.h"
+#include "mca_api.h"
+
+/*****************************************************************************
+** constants
+*****************************************************************************/
+
+/* INT initiates the L2CAP channel */
+#define MCA_ACP 0
+#define MCA_INT 1
+
+/*****************************************************************************
+** Type Definitions
+*****************************************************************************/
+
+/* Header structure for api/received request/response. */
+typedef struct {
+ BT_HDR hdr; /* layer specific information */
+ UINT8 op_code; /* the request/response opcode */
+ UINT8 rsp_code; /* valid only if op_code is a response */
+ UINT16 mdl_id; /* the MDL ID associated with this request/response */
+ UINT8 param; /* other parameter */
+ UINT8 mdep_id; /* the MDEP ID associated with this request/response */
+ /* tMCA_HANDLE rcb_idx; For internal use only */
+ /* tMCA_CL ccb_idx; For internal use only */
+ tMCA_DL dcb_idx; /* For internal use only */
+} tMCA_CCB_MSG;
+
+/* This data structure is associated with the AVDT_OPEN_IND_EVT and AVDT_OPEN_CFM_EVT. */
+typedef struct {
+ BT_HDR hdr; /* Event header */
+ UINT16 peer_mtu; /* Transport channel L2CAP MTU of the peer */
+ UINT16 lcid; /* L2CAP LCID */
+ UINT8 param;
+} tMCA_OPEN;
+
+typedef struct {
+ UINT16 reason; /* disconnect reason from L2CAP */
+ UINT8 param; /* MCA_INT or MCA_ACP */
+ UINT16 lcid; /* L2CAP LCID */
+} tMCA_CLOSE;
+
+/* Header structure for state machine event parameters. */
+typedef union {
+ BT_HDR hdr; /* layer specific information */
+ tMCA_CCB_MSG api;
+ BOOLEAN llcong;
+ UINT8 param;
+ tMCA_OPEN open;
+ tMCA_CLOSE close;
+} tMCA_CCB_EVT;
+
+/* control channel states */
+enum
+{
+ MCA_CCB_NULL_ST, /* not allocated */
+ MCA_CCB_OPENING_ST,
+ MCA_CCB_OPEN_ST, /* open */
+ MCA_CCB_CLOSING_ST, /* disconnecting */
+ MCA_CCB_MAX_ST
+};
+typedef UINT8 tMCA_CCB_STATE;
+
+/* control channel events */
+enum
+{
+ MCA_CCB_API_CONNECT_EVT, /* application initiates a connect request. */
+ MCA_CCB_API_DISCONNECT_EVT, /* application initiates a disconnect request. */
+ MCA_CCB_API_REQ_EVT, /* application initiates a request. The request may be create_mdl, delete_mdl, reconnect_mdl or abort_mdl. */
+ MCA_CCB_API_RSP_EVT, /* application initiates a create_mdl or reconnect_mdl response. */
+ MCA_CCB_MSG_REQ_EVT, /* a create_mdl, delete_mdl, reconnect_mdl or abort_mdl request message is received from the peer. */
+ MCA_CCB_MSG_RSP_EVT, /* Response received event. This event is sent whenever a response message is received for an outstanding request message. */
+ MCA_CCB_DL_OPEN_EVT, /* data channel open. */
+ MCA_CCB_LL_OPEN_EVT, /* Lower layer open. This event is sent when the lower layer channel is open. */
+ MCA_CCB_LL_CLOSE_EVT, /* Lower layer close. This event is sent when the lower layer channel is closed. */
+ MCA_CCB_LL_CONG_EVT, /* Lower layer congestion. This event is sent when the lower layer is congested. */
+ MCA_CCB_RSP_TOUT_EVT /* time out for waiting the message response on the control channel */
+};
+
+/* Header structure for callback event parameters. */
+typedef union {
+ tMCA_OPEN open;
+ tMCA_CLOSE close;
+ BT_HDR hdr; /* layer specific information */
+ BT_HDR *p_pkt;
+ BOOLEAN llcong;
+ UINT16 mdl_id; /* the MDL ID associated with this request/response */
+ /* tMCA_HANDLE rcb_idx; For internal use only */
+ /* tMCA_CL ccb_idx; For internal use only */
+ /* tMCA_DL dcb_idx; For internal use only */
+} tMCA_DCB_EVT;
+
+/* data channel states */
+enum
+{
+ MCA_DCB_NULL_ST, /* not allocated */
+ MCA_DCB_OPENING_ST, /* create/reconnect sequence is successful, waiting for data channel connection */
+ MCA_DCB_OPEN_ST, /* open */
+ MCA_DCB_CLOSING_ST, /* disconnecting */
+ MCA_DCB_MAX_ST
+};
+typedef UINT8 tMCA_DCB_STATE;
+
+/* data channel events */
+enum
+{
+ MCA_DCB_API_CLOSE_EVT, /* This event is sent when the application wants to disconnect the data channel.*/
+ MCA_DCB_API_WRITE_EVT, /* This event is sent when the application wants to send a data packet to the peer.*/
+ MCA_DCB_TC_OPEN_EVT, /* Transport Channel open. This event is sent when the channel is open.*/
+ MCA_DCB_TC_CLOSE_EVT, /* Transport Channel close.*/
+ MCA_DCB_TC_CONG_EVT, /* Transport Channel congestion status.*/
+ MCA_DCB_TC_DATA_EVT /* This event is sent when a data packet is received from the peer.*/
+};
+
+
+
+
+/* "states" used in transport channel table */
+#define MCA_TC_ST_UNUSED 0 /* Unused - unallocated */
+#define MCA_TC_ST_IDLE 1 /* No connection */
+#define MCA_TC_ST_ACP 2 /* Waiting to accept a connection */
+#define MCA_TC_ST_INT 3 /* Initiating a connection */
+#define MCA_TC_ST_CONN 4 /* Waiting for connection confirm */
+#define MCA_TC_ST_CFG 5 /* Waiting for configuration complete */
+#define MCA_TC_ST_OPEN 6 /* Channel opened */
+#define MCA_TC_ST_SEC_INT 7 /* Security process as INT */
+#define MCA_TC_ST_SEC_ACP 8 /* Security process as ACP */
+
+/* Configuration flags. tMCA_TC_TBL.cfg_flags */
+#define MCA_L2C_CFG_IND_DONE (1<<0)
+#define MCA_L2C_CFG_CFM_DONE (1<<1)
+#define MCA_L2C_CFG_CONN_INT (1<<2)
+#define MCA_L2C_CFG_CONN_ACP (1<<3)
+#define MCA_L2C_CFG_DISCN_INT (1<<4)
+#define MCA_L2C_CFG_DISCN_ACP (1<<5)
+
+
+#define MCA_CTRL_TCID 0 /* to identify control channel by tMCA_TC_TBL.tcid */
+
+/* transport channel table */
+typedef struct {
+ UINT16 peer_mtu; /* L2CAP mtu of the peer device */
+ UINT16 my_mtu; /* Our MTU for this channel */
+ UINT16 lcid; /* L2CAP LCID */
+ UINT8 tcid; /* transport channel id (0, for control channel. (MDEP ID + 1) for data channel) */
+ tMCA_DL cb_idx; /* 1-based index to ccb or dcb */
+ UINT8 state; /* transport channel state */
+ UINT8 cfg_flags; /* L2CAP configuration flags */
+ UINT8 id; /* L2CAP id sent by peer device (need this to handle security pending) */
+} tMCA_TC_TBL;
+
+/* transport control block */
+typedef struct {
+ tMCA_TC_TBL tc_tbl[MCA_NUM_TC_TBL];
+ UINT8 lcid_tbl[MAX_L2CAP_CHANNELS]; /* map LCID to tc_tbl index */
+} tMCA_TC;
+
+/* registration control block */
+typedef struct {
+ tMCA_REG reg; /* the parameter at register */
+ tMCA_CS dep[MCA_NUM_DEPS]; /* the registration info for each MDEP */
+ tMCA_CTRL_CBACK *p_cback; /* control callback function */
+} tMCA_RCB;
+
+enum
+{
+ MCA_CCB_STAT_NORM, /* normal operation (based on ccb state) */
+ MCA_CCB_STAT_PENDING, /* waiting for data channel */
+ MCA_CCB_STAT_RECONN, /* reinitiate connection after transitioning from CLOSING to IDLE state */
+ MCA_CCB_STAT_DISC /* MCA_DisconnectReq or MCA_Deregister is called. waiting for all associated CL and DL to detach */
+};
+typedef UINT8 tMCA_CCB_STAT;
+
+/* control channel control block */
+/* the ccbs association with the rcbs
+ * ccb[0] ...ccb[MCA_NUM_LINKS*1-1] -> rcb[0]
+ * ccb[MCA_NUM_LINKS*1]...ccb[MCA_NUM_LINKS*2-1] -> rcb[1]
+ * ccb[MCA_NUM_LINKS*2]...ccb[MCA_NUM_LINKS*3-1] -> rcb[2]
+ */
+typedef struct {
+ tMCA_RCB *p_rcb; /* the associated registration control block */
+ TIMER_LIST_ENT timer_entry; /* CCB timer list entry */
+ tMCA_CCB_MSG *p_tx_req; /* Current request being sent/awaiting response */
+ tMCA_CCB_MSG *p_rx_msg; /* Current message received/being processed */
+ BD_ADDR peer_addr; /* BD address of peer */
+ UINT16 sec_mask; /* Security mask for connections as initiator */
+ UINT16 ctrl_vpsm; /* The virtual PSM that peer is listening for control channel */
+ UINT16 data_vpsm; /* The virtual PSM that peer is listening for data channel. */
+ UINT16 lcid; /* L2CAP lcid for this control channel */
+ UINT8 state; /* The CCB state machine state */
+ BOOLEAN cong; /* Whether control channel is congested */
+ tMCA_CCB_STAT status; /* see tMCA_CCB_STAT */
+} tMCA_CCB;
+typedef void (*tMCA_CCB_ACTION)(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data);
+
+enum
+{
+ MCA_DCB_STAT_NORM, /* normal operation (based on dcb state) */
+ MCA_DCB_STAT_DEL, /* MCA_Delete is called. waiting for the DL to detach */
+ MCA_DCB_STAT_DISC /* MCA_CloseReq is called. waiting for the DL to detach */
+};
+typedef UINT8 tMCA_DCB_STAT;
+
+/* data channel control block */
+/* the dcbs association with the ccbs
+ * dcb[0] ...dcb[MCA_NUM_MDLS*1-1] -> ccb[0]
+ * dcb[MCA_NUM_MDLS*1]...dcb[MCA_NUM_MDLS*2-1] -> ccb[1]
+ * dcb[MCA_NUM_MDLS*2]...dcb[MCA_NUM_MDLS*3-1] -> ccb[2]
+ *
+ * the dcbs association with the rcbs
+ * dcb[0] ...dcb[MCA_NUM_MDLS*1*MCA_NUM_LINKS*1-1] -> rcb[0]
+ * dcb[MCA_NUM_MDLS*1*MCA_NUM_LINKS*1]...dcb[MCA_NUM_MDLS*2*MCA_NUM_LINKS*2-1] -> rcb[1]
+ * dcb[MCA_NUM_MDLS*2*MCA_NUM_LINKS*2]...dcb[MCA_NUM_MDLS*3*MCA_NUM_LINKS*3-1] -> rcb[2]
+ */
+typedef struct {
+ tMCA_CCB *p_ccb; /* the associated control control block */
+ BT_HDR *p_data; /* data packet held due to L2CAP channel congestion */
+ tMCA_CS *p_cs; /* the associated MDEP info. p_cs->type is the mdep id(internal use) */
+ const tMCA_CHNL_CFG *p_chnl_cfg; /* cfg params for L2CAP channel */
+ UINT16 mdl_id; /* the MDL ID for this data channel */
+ UINT16 lcid; /* L2CAP lcid */
+ UINT8 state; /* The DCB state machine state */
+ BOOLEAN cong; /* Whether data channel is congested */
+ tMCA_DCB_STAT status; /* see tMCA_DCB_STAT */
+} tMCA_DCB;
+
+typedef void (*tMCA_DCB_ACTION)(tMCA_DCB *p_ccb, tMCA_DCB_EVT *p_data);
+
+/* Control block for MCA */
+typedef struct {
+ tMCA_RCB rcb[MCA_NUM_REGS]; /* registration control block */
+ tMCA_CCB ccb[MCA_NUM_CCBS]; /* control channel control blocks */
+ tMCA_DCB dcb[MCA_NUM_DCBS]; /* data channel control blocks */
+ tMCA_TC tc; /* transport control block */
+ UINT8 trace_level; /* trace level */
+} tMCA_CB;
+
+/* csm functions */
+extern void mca_ccb_event(tMCA_CCB *p_ccb, UINT8 event, tMCA_CCB_EVT *p_data);
+extern tMCA_CCB *mca_ccb_by_bd(tMCA_HANDLE handle, BD_ADDR bd_addr);
+extern tMCA_CCB *mca_ccb_alloc(tMCA_HANDLE handle, BD_ADDR bd_addr);
+extern void mca_ccb_rsp_tout(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data);
+extern void mca_ccb_dealloc(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data);
+extern tMCA_CL mca_ccb_to_hdl(tMCA_CCB *p_ccb);
+extern tMCA_CCB *mca_ccb_by_hdl(tMCA_CL mcl);
+extern BOOLEAN mca_ccb_uses_mdl_id(tMCA_CCB *p_ccb, UINT16 mdl_id);
+
+/* cact functions */
+extern void mca_ccb_report_event(tMCA_CCB *p_ccb, UINT8 event, tMCA_CTRL *p_data);
+extern void mca_ccb_free_msg(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data);
+extern void mca_ccb_snd_req(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data);
+extern void mca_ccb_snd_rsp(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data);
+extern void mca_ccb_do_disconn (tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data);
+extern void mca_ccb_cong(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data);
+extern void mca_ccb_hdl_req(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data);
+extern void mca_ccb_hdl_rsp(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data);
+extern void mca_ccb_ll_open (tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data);
+extern void mca_ccb_dl_open (tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data);
+
+/* dsm functions */
+extern void mca_dcb_event(tMCA_DCB *p_dcb, UINT8 event, tMCA_DCB_EVT *p_data);
+extern tMCA_DCB *mca_dcb_alloc(tMCA_CCB*p_ccb, tMCA_DEP dep);
+extern UINT8 mca_dep_free_mdl(tMCA_CCB*p_ccb, tMCA_DEP dep);
+extern void mca_dcb_dealloc(tMCA_DCB *p_dcb, tMCA_DCB_EVT *p_data);
+extern tMCA_DL mca_dcb_to_hdl(tMCA_DCB *p_dcb);
+extern tMCA_DCB *mca_dcb_by_hdl(tMCA_DL hdl);
+extern void mca_dcb_close_by_mdl_id(tMCA_CCB*p_ccb, UINT16 mdl_id);
+
+/* dact functions */
+extern void mca_dcb_tc_open (tMCA_DCB *p_dcb, tMCA_DCB_EVT *p_data);
+extern void mca_dcb_cong (tMCA_DCB *p_dcb, tMCA_DCB_EVT *p_data);
+extern void mca_dcb_free_data (tMCA_DCB *p_dcb, tMCA_DCB_EVT *p_data);
+extern void mca_dcb_do_disconn (tMCA_DCB *p_dcb, tMCA_DCB_EVT *p_data);
+extern void mca_dcb_snd_data (tMCA_DCB *p_dcb, tMCA_DCB_EVT *p_data);
+extern void mca_dcb_hdl_data (tMCA_DCB *p_dcb, tMCA_DCB_EVT *p_data);
+
+
+/* main/utils functions */
+extern tMCA_HANDLE mca_handle_by_cpsm(UINT16 psm);
+extern tMCA_HANDLE mca_handle_by_dpsm(UINT16 psm);
+extern tMCA_TC_TBL * mca_tc_tbl_calloc(tMCA_CCB *p_ccb);
+extern tMCA_TC_TBL * mca_tc_tbl_dalloc(tMCA_DCB *p_dcb);
+extern tMCA_TC_TBL * mca_tc_tbl_by_lcid(UINT16 lcid);
+extern void mca_free_tc_tbl_by_lcid(UINT16 lcid);
+extern void mca_set_cfg_by_tbl(tL2CAP_CFG_INFO *p_cfg, tMCA_TC_TBL *p_tbl);
+extern void mca_tc_close_ind(tMCA_TC_TBL *p_tbl, UINT16 reason);
+extern void mca_tc_open_ind(tMCA_TC_TBL *p_tbl);
+extern void mca_tc_cong_ind(tMCA_TC_TBL *p_tbl, BOOLEAN is_congested);
+extern void mca_tc_data_ind(tMCA_TC_TBL *p_tbl, BT_HDR *p_buf);
+extern tMCA_RCB * mca_rcb_alloc(tMCA_REG *p_reg);
+extern void mca_rcb_dealloc(tMCA_HANDLE handle);
+extern tMCA_HANDLE mca_rcb_to_handle(tMCA_RCB *p_rcb);
+extern tMCA_RCB *mca_rcb_by_handle(tMCA_HANDLE handle);
+extern BOOLEAN mca_is_valid_dep_id(tMCA_RCB *p_rcb, tMCA_DEP dep);
+extern void mca_free_buf(void **p_buf);
+extern void mca_process_timeout(TIMER_LIST_ENT *p_tle);
+extern void mca_stop_timer(tMCA_CCB *p_ccb);
+
+/* l2c functions */
+extern void mca_l2c_cconn_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id);
+extern void mca_l2c_dconn_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id);
+extern UINT16 mca_l2c_open_req(BD_ADDR bd_addr, UINT16 PSM, const tMCA_CHNL_CFG *p_chnl_cfg);
+
+/*****************************************************************************
+** global data
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/******************************************************************************
+** Main Control Block
+*******************************************************************************/
+#if MCA_DYNAMIC_MEMORY == FALSE
+MCA_API extern tMCA_CB mca_cb;
+#else
+MCA_API extern tMCA_CB *mca_cb_ptr;
+#define mca_cb (*mca_cb_ptr)
+#endif
+
+/* L2CAP callback registration structure */
+extern const tL2CAP_APPL_INFO mca_l2c_int_appl;
+extern const tL2CAP_FCR_OPTS mca_l2c_fcr_opts_def;
+extern const UINT8 mca_std_msg_len[];
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MCA_INT_H */
diff --git a/stack/mcap/mca_l2c.c b/stack/mcap/mca_l2c.c
new file mode 100644
index 0000000..a776568
--- /dev/null
+++ b/stack/mcap/mca_l2c.c
@@ -0,0 +1,577 @@
+/*****************************************************************************
+**
+** Name: mca_l2c.c
+**
+** Description: This is the implementation file for the MCAP
+** at L2CAP Interface.
+**
+** Copyright (c) 2009-2009, Broadcom Corp., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include <string.h>
+
+#include "bt_target.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "mca_api.h"
+#include "mca_defs.h"
+#include "mca_int.h"
+
+/* callback function declarations */
+void mca_l2c_cconn_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id);
+void mca_l2c_dconn_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id);
+void mca_l2c_connect_cfm_cback(UINT16 lcid, UINT16 result);
+void mca_l2c_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg);
+void mca_l2c_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg);
+void mca_l2c_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed);
+void mca_l2c_disconnect_cfm_cback(UINT16 lcid, UINT16 result);
+void mca_l2c_congestion_ind_cback(UINT16 lcid, BOOLEAN is_congested);
+void mca_l2c_data_ind_cback(UINT16 lcid, BT_HDR *p_buf);
+
+/* L2CAP callback function structure */
+const tL2CAP_APPL_INFO mca_l2c_int_appl = {
+ NULL,
+ mca_l2c_connect_cfm_cback,
+ NULL,
+ mca_l2c_config_ind_cback,
+ mca_l2c_config_cfm_cback,
+ mca_l2c_disconnect_ind_cback,
+ mca_l2c_disconnect_cfm_cback,
+ NULL,
+ mca_l2c_data_ind_cback,
+ mca_l2c_congestion_ind_cback
+};
+
+/* Control channel eL2CAP default options */
+const tL2CAP_FCR_OPTS mca_l2c_fcr_opts_def = {
+ L2CAP_FCR_ERTM_MODE, /* Mandatory for MCAP */
+ MCA_FCR_OPT_TX_WINDOW_SIZE, /* Tx window size */
+ MCA_FCR_OPT_MAX_TX_B4_DISCNT, /* Maximum transmissions before disconnecting */
+ MCA_FCR_OPT_RETX_TOUT, /* Retransmission timeout (2 secs) */
+ MCA_FCR_OPT_MONITOR_TOUT, /* Monitor timeout (12 secs) */
+ MCA_FCR_OPT_MPS_SIZE /* MPS segment size */
+};
+
+
+/*******************************************************************************
+**
+** Function mca_sec_check_complete_term
+**
+** Description The function called when Security Manager finishes
+** verification of the service side connection
+**
+** Returns void
+**
+*******************************************************************************/
+static void mca_sec_check_complete_term (BD_ADDR bd_addr, void *p_ref_data, UINT8 res)
+{
+ tMCA_TC_TBL *p_tbl = (tMCA_TC_TBL *)p_ref_data;
+ tL2CAP_CFG_INFO cfg;
+ tL2CAP_ERTM_INFO ertm_info;
+
+ MCA_TRACE_DEBUG1("mca_sec_check_complete_term res: %d", res);
+
+ if ( res == BTM_SUCCESS )
+ {
+ MCA_TRACE_DEBUG2 ("lcid:x%x id:x%x", p_tbl->lcid, p_tbl->id);
+ /* Set the FCR options: control channel mandates ERTM */
+ ertm_info.preferred_mode = mca_l2c_fcr_opts_def.mode;
+ ertm_info.allowed_modes = L2CAP_FCR_CHAN_OPT_ERTM;
+ ertm_info.user_rx_pool_id = MCA_USER_RX_POOL_ID;
+ ertm_info.user_tx_pool_id = MCA_USER_TX_POOL_ID;
+ ertm_info.fcr_rx_pool_id = MCA_FCR_RX_POOL_ID;
+ ertm_info.fcr_tx_pool_id = MCA_FCR_TX_POOL_ID;
+ /* Send response to the L2CAP layer. */
+ L2CA_ErtmConnectRsp (bd_addr, p_tbl->id, p_tbl->lcid, L2CAP_CONN_OK, L2CAP_CONN_OK, &ertm_info);
+
+ /* transition to configuration state */
+ p_tbl->state = MCA_TC_ST_CFG;
+
+ /* Send L2CAP config req */
+ mca_set_cfg_by_tbl (&cfg, p_tbl);
+ L2CA_ConfigReq(p_tbl->lcid, &cfg);
+ }
+ else
+ {
+ L2CA_ConnectRsp (bd_addr, p_tbl->id, p_tbl->lcid, L2CAP_CONN_SECURITY_BLOCK, L2CAP_CONN_OK);
+ mca_tc_close_ind(p_tbl, L2CAP_CONN_SECURITY_BLOCK);
+ }
+}
+
+/*******************************************************************************
+**
+** Function mca_sec_check_complete_orig
+**
+** Description The function called when Security Manager finishes
+** verification of the service side connection
+**
+** Returns void
+**
+*******************************************************************************/
+static void mca_sec_check_complete_orig (BD_ADDR bd_addr, void *p_ref_data, UINT8 res)
+{
+ tMCA_TC_TBL *p_tbl = (tMCA_TC_TBL *)p_ref_data;
+ tL2CAP_CFG_INFO cfg;
+
+ MCA_TRACE_DEBUG1("mca_sec_check_complete_orig res: %d", res);
+
+ if ( res == BTM_SUCCESS )
+ {
+ /* set channel state */
+ p_tbl->state = MCA_TC_ST_CFG;
+
+ /* Send L2CAP config req */
+ mca_set_cfg_by_tbl (&cfg, p_tbl);
+ L2CA_ConfigReq(p_tbl->lcid, &cfg);
+ }
+ else
+ {
+ L2CA_DisconnectReq (p_tbl->lcid);
+ mca_tc_close_ind(p_tbl, L2CAP_CONN_SECURITY_BLOCK);
+ }
+}
+/*******************************************************************************
+**
+** Function mca_l2c_cconn_ind_cback
+**
+** Description This is the L2CAP connect indication callback function.
+**
+** Returns void
+**
+*******************************************************************************/
+void mca_l2c_cconn_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id)
+{
+ tMCA_HANDLE handle = mca_handle_by_cpsm(psm);
+ tMCA_CCB *p_ccb;
+ tMCA_TC_TBL *p_tbl = NULL;
+ UINT16 result = L2CAP_CONN_NO_RESOURCES;
+ tBTM_STATUS rc;
+ tL2CAP_ERTM_INFO ertm_info, *p_ertm_info = NULL;
+ tL2CAP_CFG_INFO cfg;
+
+ MCA_TRACE_EVENT3 ("mca_l2c_cconn_ind_cback: lcid:x%x psm:x%x id:x%x", lcid, psm, id);
+
+ /* do we already have a control channel for this peer? */
+ if ((p_ccb = mca_ccb_by_bd(handle, bd_addr)) == NULL)
+ {
+ /* no, allocate ccb */
+ if ((p_ccb = mca_ccb_alloc(handle, bd_addr)) != NULL)
+ {
+ /* allocate and set up entry */
+ p_ccb->lcid = lcid;
+ p_tbl = mca_tc_tbl_calloc(p_ccb);
+ p_tbl->id = id;
+ p_tbl->cfg_flags= MCA_L2C_CFG_CONN_ACP;
+ /* proceed with connection */
+ /* Check the security */
+ rc = btm_sec_mx_access_request (bd_addr, psm, FALSE, BTM_SEC_PROTO_MCA, 0,
+ &mca_sec_check_complete_term, p_tbl);
+ if (rc == BTM_CMD_STARTED)
+ {
+ /* Set the FCR options: control channel mandates ERTM */
+ ertm_info.preferred_mode = mca_l2c_fcr_opts_def.mode;
+ ertm_info.allowed_modes = L2CAP_FCR_CHAN_OPT_ERTM;
+ ertm_info.user_rx_pool_id = MCA_USER_RX_POOL_ID;
+ ertm_info.user_tx_pool_id = MCA_USER_TX_POOL_ID;
+ ertm_info.fcr_rx_pool_id = MCA_FCR_RX_POOL_ID;
+ ertm_info.fcr_tx_pool_id = MCA_FCR_TX_POOL_ID;
+ p_ertm_info = &ertm_info;
+ result = L2CAP_CONN_PENDING;
+ }
+ else
+ result = L2CAP_CONN_OK;
+ }
+
+ /* deal with simultaneous control channel connect case */
+ }
+ /* else reject their connection */
+
+ if (!p_tbl || (p_tbl->state != MCA_TC_ST_CFG))
+ {
+ /* Send L2CAP connect rsp */
+ L2CA_ErtmConnectRsp (bd_addr, id, lcid, result, L2CAP_CONN_OK, p_ertm_info);
+
+ /* if result ok, proceed with connection and send L2CAP
+ config req */
+ if (result == L2CAP_CONN_OK)
+ {
+ /* set channel state */
+ p_tbl->state = MCA_TC_ST_CFG;
+
+ /* Send L2CAP config req */
+ mca_set_cfg_by_tbl (&cfg, p_tbl);
+ L2CA_ConfigReq(p_tbl->lcid, &cfg);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function mca_l2c_dconn_ind_cback
+**
+** Description This is the L2CAP connect indication callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void mca_l2c_dconn_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id)
+{
+ tMCA_HANDLE handle = mca_handle_by_dpsm(psm);
+ tMCA_CCB *p_ccb;
+ tMCA_DCB *p_dcb;
+ tMCA_TC_TBL *p_tbl = NULL;
+ UINT16 result;
+ tL2CAP_CFG_INFO cfg;
+ tL2CAP_ERTM_INFO *p_ertm_info = NULL, ertm_info;
+ const tMCA_CHNL_CFG *p_chnl_cfg;
+
+ MCA_TRACE_EVENT2 ("mca_l2c_dconn_ind_cback: lcid:x%x psm:x%x ", lcid, psm);
+
+ if (((p_ccb = mca_ccb_by_bd(handle, bd_addr)) != NULL) && /* find the CCB */
+ (p_ccb->status == MCA_CCB_STAT_PENDING) && /* this CCB is expecting a MDL */
+ (p_ccb->p_tx_req && (p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx)) != NULL))
+ {
+ /* found the associated dcb in listening mode */
+ /* proceed with connection */
+ p_dcb->lcid = lcid;
+ p_tbl = mca_tc_tbl_dalloc(p_dcb);
+ p_tbl->id = id;
+ p_tbl->cfg_flags= MCA_L2C_CFG_CONN_ACP;
+ p_chnl_cfg = p_dcb->p_chnl_cfg;
+ /* assume that control channel has verified the security requirement */
+ /* Set the FCR options: control channel mandates ERTM */
+ ertm_info.preferred_mode = p_chnl_cfg->fcr_opt.mode;
+ ertm_info.allowed_modes = (1 << p_chnl_cfg->fcr_opt.mode);
+ ertm_info.user_rx_pool_id = p_chnl_cfg->user_rx_pool_id;
+ ertm_info.user_tx_pool_id = p_chnl_cfg->user_tx_pool_id;
+ ertm_info.fcr_rx_pool_id = p_chnl_cfg->fcr_rx_pool_id;
+ ertm_info.fcr_tx_pool_id = p_chnl_cfg->fcr_tx_pool_id;
+ p_ertm_info = &ertm_info;
+ result = L2CAP_CONN_OK;
+ }
+ else
+ {
+ /* else we're not listening for traffic channel; reject
+ * (this error code is specified by MCAP spec) */
+ result = L2CAP_CONN_NO_RESOURCES;
+ }
+
+ /* Send L2CAP connect rsp */
+ L2CA_ErtmConnectRsp (bd_addr, id, lcid, result, result, p_ertm_info);
+
+ /* if result ok, proceed with connection */
+ if (result == L2CAP_CONN_OK)
+ {
+ /* transition to configuration state */
+ p_tbl->state = MCA_TC_ST_CFG;
+
+ /* Send L2CAP config req */
+ mca_set_cfg_by_tbl (&cfg, p_tbl);
+ L2CA_ConfigReq(lcid, &cfg);
+ }
+}
+
+/*******************************************************************************
+**
+** Function mca_l2c_connect_cfm_cback
+**
+** Description This is the L2CAP connect confirm callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void mca_l2c_connect_cfm_cback(UINT16 lcid, UINT16 result)
+{
+ tMCA_TC_TBL *p_tbl;
+ tL2CAP_CFG_INFO cfg;
+ tMCA_CCB *p_ccb;
+
+ MCA_TRACE_DEBUG2("mca_l2c_connect_cfm_cback lcid: x%x, result: %d",
+ lcid, result);
+ /* look up info for this channel */
+ if ((p_tbl = mca_tc_tbl_by_lcid(lcid)) != NULL)
+ {
+ MCA_TRACE_DEBUG2("p_tbl state: %d, tcid: %d", p_tbl->state, p_tbl->tcid);
+ /* if in correct state */
+ if (p_tbl->state == MCA_TC_ST_CONN)
+ {
+ /* if result successful */
+ if (result == L2CAP_CONN_OK)
+ {
+ if (p_tbl->tcid != 0)
+ {
+ /* set channel state */
+ p_tbl->state = MCA_TC_ST_CFG;
+
+ /* Send L2CAP config req */
+ mca_set_cfg_by_tbl (&cfg, p_tbl);
+ L2CA_ConfigReq(lcid, &cfg);
+ }
+ else
+ {
+ p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx);
+ if (p_ccb == NULL)
+ {
+ result = L2CAP_CONN_NO_RESOURCES;
+ }
+ else
+ {
+ /* set channel state */
+ p_tbl->state = MCA_TC_ST_SEC_INT;
+ p_tbl->lcid = lcid;
+ p_tbl->cfg_flags= MCA_L2C_CFG_CONN_INT;
+
+ /* Check the security */
+ btm_sec_mx_access_request (p_ccb->peer_addr, p_ccb->ctrl_vpsm,
+ TRUE, BTM_SEC_PROTO_MCA,
+ p_tbl->tcid,
+ &mca_sec_check_complete_orig, p_tbl);
+ }
+ }
+ }
+
+ /* failure; notify adaption that channel closed */
+ if (result != L2CAP_CONN_OK)
+ {
+ p_tbl->cfg_flags |= MCA_L2C_CFG_DISCN_INT;
+ mca_tc_close_ind(p_tbl, result);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function mca_l2c_config_cfm_cback
+**
+** Description This is the L2CAP config confirm callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void mca_l2c_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
+{
+ tMCA_TC_TBL *p_tbl;
+
+ /* look up info for this channel */
+ if ((p_tbl = mca_tc_tbl_by_lcid(lcid)) != NULL)
+ {
+ /* if in correct state */
+ if (p_tbl->state == MCA_TC_ST_CFG)
+ {
+ /* if result successful */
+ if (p_cfg->result == L2CAP_CONN_OK)
+ {
+ /* update cfg_flags */
+ p_tbl->cfg_flags |= MCA_L2C_CFG_CFM_DONE;
+
+ /* if configuration complete */
+ if (p_tbl->cfg_flags & MCA_L2C_CFG_IND_DONE)
+ {
+ mca_tc_open_ind(p_tbl);
+ }
+ }
+ /* else failure */
+ else
+ {
+ /* Send L2CAP disconnect req */
+ L2CA_DisconnectReq(lcid);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function mca_l2c_config_ind_cback
+**
+** Description This is the L2CAP config indication callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void mca_l2c_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
+{
+ tMCA_TC_TBL *p_tbl;
+ UINT16 result = L2CAP_CFG_OK;
+
+ /* look up info for this channel */
+ if ((p_tbl = mca_tc_tbl_by_lcid(lcid)) != NULL)
+ {
+ /* store the mtu in tbl */
+ if (p_cfg->mtu_present)
+ {
+ p_tbl->peer_mtu = p_cfg->mtu;
+ if (p_tbl->peer_mtu < MCA_MIN_MTU)
+ {
+ result = L2CAP_CFG_UNACCEPTABLE_PARAMS;
+ }
+ }
+ else
+ {
+ p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
+ }
+ MCA_TRACE_DEBUG3("peer_mtu: %d, lcid: x%x mtu_present:%d",p_tbl->peer_mtu, lcid, p_cfg->mtu_present);
+
+ /* send L2CAP configure response */
+ memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO));
+ p_cfg->result = result;
+ L2CA_ConfigRsp(lcid, p_cfg);
+
+ /* if first config ind */
+ if ((p_tbl->cfg_flags & MCA_L2C_CFG_IND_DONE) == 0)
+ {
+ /* update cfg_flags */
+ p_tbl->cfg_flags |= MCA_L2C_CFG_IND_DONE;
+
+ /* if configuration complete */
+ if (p_tbl->cfg_flags & MCA_L2C_CFG_CFM_DONE)
+ {
+ mca_tc_open_ind(p_tbl);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function mca_l2c_disconnect_ind_cback
+**
+** Description This is the L2CAP disconnect indication callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void mca_l2c_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed)
+{
+ tMCA_TC_TBL *p_tbl;
+ UINT16 reason = L2CAP_DISC_TIMEOUT;
+
+ MCA_TRACE_DEBUG2("mca_l2c_disconnect_ind_cback lcid: %d, ack_needed: %d",
+ lcid, ack_needed);
+ /* look up info for this channel */
+ if ((p_tbl = mca_tc_tbl_by_lcid(lcid)) != NULL)
+ {
+ if (ack_needed)
+ {
+ /* send L2CAP disconnect response */
+ L2CA_DisconnectRsp(lcid);
+ }
+
+ p_tbl->cfg_flags = MCA_L2C_CFG_DISCN_ACP;
+ if (ack_needed)
+ reason = L2CAP_DISC_OK;
+ mca_tc_close_ind(p_tbl, reason);
+ }
+}
+
+/*******************************************************************************
+**
+** Function mca_l2c_disconnect_cfm_cback
+**
+** Description This is the L2CAP disconnect confirm callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void mca_l2c_disconnect_cfm_cback(UINT16 lcid, UINT16 result)
+{
+ tMCA_TC_TBL *p_tbl;
+
+ MCA_TRACE_DEBUG2("mca_l2c_disconnect_cfm_cback lcid: x%x, result: %d",
+ lcid, result);
+ /* look up info for this channel */
+ if ((p_tbl = mca_tc_tbl_by_lcid(lcid)) != NULL)
+ {
+ p_tbl->cfg_flags = MCA_L2C_CFG_DISCN_INT;
+ mca_tc_close_ind(p_tbl, result);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function mca_l2c_congestion_ind_cback
+**
+** Description This is the L2CAP congestion indication callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void mca_l2c_congestion_ind_cback(UINT16 lcid, BOOLEAN is_congested)
+{
+ tMCA_TC_TBL *p_tbl;
+
+ /* look up info for this channel */
+ if ((p_tbl = mca_tc_tbl_by_lcid(lcid)) != NULL)
+ {
+ mca_tc_cong_ind(p_tbl, is_congested);
+ }
+}
+
+/*******************************************************************************
+**
+** Function mca_l2c_data_ind_cback
+**
+** Description This is the L2CAP data indication callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void mca_l2c_data_ind_cback(UINT16 lcid, BT_HDR *p_buf)
+{
+ tMCA_TC_TBL *p_tbl;
+
+ /* look up info for this channel */
+ if ((p_tbl = mca_tc_tbl_by_lcid(lcid)) != NULL)
+ {
+ mca_tc_data_ind(p_tbl, p_buf);
+ }
+ else /* prevent buffer leak */
+ GKI_freebuf(p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function mca_l2c_open_req
+**
+** Description This function calls L2CA_ConnectReq() to initiate a L2CAP channel.
+**
+** Returns void.
+**
+*******************************************************************************/
+UINT16 mca_l2c_open_req(BD_ADDR bd_addr, UINT16 psm, const tMCA_CHNL_CFG *p_chnl_cfg)
+{
+ tL2CAP_ERTM_INFO ertm_info;
+
+ if (p_chnl_cfg)
+ {
+ ertm_info.preferred_mode = p_chnl_cfg->fcr_opt.mode;
+ ertm_info.allowed_modes = (1 << p_chnl_cfg->fcr_opt.mode);
+ ertm_info.user_rx_pool_id = p_chnl_cfg->user_rx_pool_id;
+ ertm_info.user_tx_pool_id = p_chnl_cfg->user_tx_pool_id;
+ ertm_info.fcr_rx_pool_id = p_chnl_cfg->fcr_rx_pool_id;
+ ertm_info.fcr_tx_pool_id = p_chnl_cfg->fcr_tx_pool_id;
+ }
+ else
+ {
+ ertm_info.preferred_mode = mca_l2c_fcr_opts_def.mode;
+ ertm_info.allowed_modes = L2CAP_FCR_CHAN_OPT_ERTM;
+ ertm_info.user_rx_pool_id = MCA_USER_RX_POOL_ID;
+ ertm_info.user_tx_pool_id = MCA_USER_TX_POOL_ID;
+ ertm_info.fcr_rx_pool_id = MCA_FCR_RX_POOL_ID;
+ ertm_info.fcr_tx_pool_id = MCA_FCR_TX_POOL_ID;
+ }
+ return L2CA_ErtmConnectReq (psm, bd_addr, &ertm_info);
+}
+
diff --git a/stack/mcap/mca_main.c b/stack/mcap/mca_main.c
new file mode 100644
index 0000000..bc6118c
--- /dev/null
+++ b/stack/mcap/mca_main.c
@@ -0,0 +1,630 @@
+/*****************************************************************************
+**
+** Name: mca_main.c
+**
+** Description: This is the implementation file for the MCAP
+** Main Control Block and Utility functions.
+**
+** Copyright (c) 2009-2009, Broadcom Corp., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include <string.h>
+
+#include "bt_target.h"
+#include "gki.h"
+#include "mca_api.h"
+#include "mca_defs.h"
+#include "mca_int.h"
+#include "wcassert.h"
+#include "l2c_api.h"
+
+/* Main Control block for MCA */
+#if MCA_DYNAMIC_MEMORY == FALSE
+tMCA_CB mca_cb;
+#endif
+
+/*****************************************************************************
+** constants
+*****************************************************************************/
+
+/* table of standard opcode message size */
+const UINT8 mca_std_msg_len[MCA_NUM_STANDARD_OPCODE] = {
+ 4, /* MCA_OP_ERROR_RSP */
+ 5, /* MCA_OP_MDL_CREATE_REQ */
+ 5, /* MCA_OP_MDL_CREATE_RSP */
+ 3, /* MCA_OP_MDL_RECONNECT_REQ */
+ 4, /* MCA_OP_MDL_RECONNECT_RSP */
+ 3, /* MCA_OP_MDL_ABORT_REQ */
+ 4, /* MCA_OP_MDL_ABORT_RSP */
+ 3, /* MCA_OP_MDL_DELETE_REQ */
+ 4 /* MCA_OP_MDL_DELETE_RSP */
+};
+
+
+/*******************************************************************************
+**
+** Function mca_handle_by_cpsm
+**
+** Description This function returns the handle for the given control
+** channel PSM. 0, if not found.
+**
+** Returns the MCA handle.
+**
+*******************************************************************************/
+tMCA_HANDLE mca_handle_by_cpsm(UINT16 psm)
+{
+ int i;
+ tMCA_HANDLE handle = 0;
+ tMCA_RCB *p_rcb = &mca_cb.rcb[0];
+
+ for (i=0; i<MCA_NUM_REGS; i++, p_rcb++)
+ {
+ if (p_rcb->p_cback && p_rcb->reg.ctrl_psm == psm)
+ {
+ handle = i+1;
+ break;
+ }
+ }
+ return handle;
+}
+
+/*******************************************************************************
+**
+** Function mca_handle_by_dpsm
+**
+** Description This function returns the handle for the given data
+** channel PSM. 0, if not found.
+**
+** Returns the MCA handle.
+**
+*******************************************************************************/
+tMCA_HANDLE mca_handle_by_dpsm(UINT16 psm)
+{
+ int i;
+ tMCA_HANDLE handle = 0;
+ tMCA_RCB *p_rcb = &mca_cb.rcb[0];
+
+ for (i=0; i<MCA_NUM_REGS; i++, p_rcb++)
+ {
+ if (p_rcb->p_cback && p_rcb->reg.data_psm == psm)
+ {
+ handle = i+1;
+ break;
+ }
+ }
+ return handle;
+}
+
+/*******************************************************************************
+**
+** Function mca_tc_tbl_calloc
+**
+** Description This function allocates a transport table for the given
+** control channel.
+**
+** Returns The tranport table.
+**
+*******************************************************************************/
+tMCA_TC_TBL * mca_tc_tbl_calloc(tMCA_CCB *p_ccb)
+{
+ tMCA_TC_TBL *p_tbl = mca_cb.tc.tc_tbl;
+ int i;
+
+ /* find next free entry in tc table */
+ for (i = 0; i < MCA_NUM_TC_TBL; i++, p_tbl++)
+ {
+ if (p_tbl->state == MCA_TC_ST_UNUSED)
+ {
+ break;
+ }
+ }
+
+ /* sanity check */
+ WC_ASSERT(i != MCA_NUM_TC_TBL);
+
+ /* initialize entry */
+ p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
+ p_tbl->cfg_flags= 0;
+ p_tbl->cb_idx = mca_ccb_to_hdl(p_ccb);
+ p_tbl->tcid = MCA_CTRL_TCID;
+ p_tbl->my_mtu = MCA_CTRL_MTU;
+ p_tbl->state = MCA_TC_ST_IDLE;
+ p_tbl->lcid = p_ccb->lcid;
+ mca_cb.tc.lcid_tbl[p_ccb->lcid - L2CAP_BASE_APPL_CID] = i;
+ MCA_TRACE_DEBUG1("mca_tc_tbl_calloc cb_idx: %d", p_tbl->cb_idx);
+
+ return p_tbl;
+}
+
+/*******************************************************************************
+**
+** Function mca_tc_tbl_dalloc
+**
+** Description This function allocates a transport table for the given
+** data channel.
+**
+** Returns The tranport table.
+**
+*******************************************************************************/
+tMCA_TC_TBL * mca_tc_tbl_dalloc(tMCA_DCB *p_dcb)
+{
+ tMCA_TC_TBL *p_tbl = mca_cb.tc.tc_tbl;
+ int i;
+
+ /* find next free entry in tc table */
+ for (i = 0; i < MCA_NUM_TC_TBL; i++, p_tbl++)
+ {
+ if (p_tbl->state == MCA_TC_ST_UNUSED)
+ {
+ break;
+ }
+ }
+
+ /* sanity check */
+ WC_ASSERT(i != MCA_NUM_TC_TBL);
+
+ /* initialize entry */
+ p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
+ p_tbl->cfg_flags= 0;
+ p_tbl->cb_idx = mca_dcb_to_hdl(p_dcb);
+ p_tbl->tcid = p_dcb->p_cs->type + 1;
+ p_tbl->my_mtu = p_dcb->p_chnl_cfg->data_mtu;
+ p_tbl->state = MCA_TC_ST_IDLE;
+ p_tbl->lcid = p_dcb->lcid;
+ mca_cb.tc.lcid_tbl[p_dcb->lcid - L2CAP_BASE_APPL_CID] = i;
+ MCA_TRACE_DEBUG2("mca_tc_tbl_dalloc tcid: %d, cb_idx: %d", p_tbl->tcid, p_tbl->cb_idx);
+
+ return p_tbl;
+}
+
+/*******************************************************************************
+**
+** Function mca_tc_tbl_by_lcid
+**
+** Description Find the transport channel table entry by LCID.
+**
+**
+** Returns The tranport table.
+**
+*******************************************************************************/
+tMCA_TC_TBL *mca_tc_tbl_by_lcid(UINT16 lcid)
+{
+ UINT8 idx;
+
+ if (lcid)
+ {
+ idx = mca_cb.tc.lcid_tbl[lcid - L2CAP_BASE_APPL_CID];
+
+ if (idx < MCA_NUM_TC_TBL)
+ {
+ return &mca_cb.tc.tc_tbl[idx];
+ }
+ }
+ return NULL;
+}
+
+/*******************************************************************************
+**
+** Function mca_free_tc_tbl_by_lcid
+**
+** Description Find the transport table entry by LCID
+** and free the tc_tbl
+**
+** Returns void.
+**
+*******************************************************************************/
+void mca_free_tc_tbl_by_lcid(UINT16 lcid)
+{
+ UINT8 idx;
+
+ if (lcid)
+ {
+ idx = mca_cb.tc.lcid_tbl[lcid - L2CAP_BASE_APPL_CID];
+
+ if (idx < MCA_NUM_TC_TBL)
+ {
+ mca_cb.tc.tc_tbl[idx].state = MCA_TC_ST_UNUSED;
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function mca_set_cfg_by_tbl
+**
+** Description Set the L2CAP configuration information
+**
+** Returns none.
+**
+*******************************************************************************/
+void mca_set_cfg_by_tbl(tL2CAP_CFG_INFO *p_cfg, tMCA_TC_TBL *p_tbl)
+{
+ tMCA_DCB *p_dcb;
+ const tL2CAP_FCR_OPTS *p_opt;
+ tMCA_FCS_OPT fcs = MCA_FCS_NONE;
+
+ if (p_tbl->tcid == MCA_CTRL_TCID)
+ {
+ p_opt = &mca_l2c_fcr_opts_def;
+ }
+ else
+ {
+ p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx);
+ p_opt = &p_dcb->p_chnl_cfg->fcr_opt;
+ fcs = p_dcb->p_chnl_cfg->fcs;
+ }
+ memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO));
+ p_cfg->mtu_present = TRUE;
+ p_cfg->mtu = p_tbl->my_mtu;
+ p_cfg->fcr_present = TRUE;
+ memcpy(&p_cfg->fcr, p_opt, sizeof (tL2CAP_FCR_OPTS));
+ if (fcs & MCA_FCS_PRESNT_MASK)
+ {
+ p_cfg->fcs_present = TRUE;
+ p_cfg->fcs = (fcs & MCA_FCS_USE_MASK);
+ }
+}
+
+/*******************************************************************************
+**
+** Function mca_tc_close_ind
+**
+** Description This function is called by the L2CAP interface when the
+** L2CAP channel is closed. It looks up the CCB or DCB for
+** the channel and sends it a close event. The reason
+** parameter is the same value passed by the L2CAP
+** callback function.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void mca_tc_close_ind(tMCA_TC_TBL *p_tbl, UINT16 reason)
+{
+ tMCA_CCB *p_ccb;
+ tMCA_DCB *p_dcb;
+ tMCA_CLOSE close;
+
+ close.param = MCA_ACP;
+ close.reason = reason;
+ close.lcid = p_tbl->lcid;
+
+ MCA_TRACE_DEBUG3("mca_tc_close_ind tcid: %d, cb_idx:%d, old: %d",
+ p_tbl->tcid, p_tbl->cb_idx, p_tbl->state);
+
+ /* Check if the transport channel is in use */
+ if (p_tbl->state == MCA_TC_ST_UNUSED)
+ return;
+
+ /* clear mca_tc_tbl entry */
+ if (p_tbl->cfg_flags&MCA_L2C_CFG_DISCN_INT)
+ close.param = MCA_INT;
+ p_tbl->cfg_flags = 0;
+ p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
+
+ /* if control channel, notify ccb that channel close */
+ if (p_tbl->tcid == MCA_CTRL_TCID)
+ {
+ p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx);
+ mca_ccb_event(p_ccb, MCA_CCB_LL_CLOSE_EVT, (tMCA_CCB_EVT *)&close);
+ }
+ /* notify dcb that channel close */
+ else
+ {
+ /* look up dcb */
+ p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx);
+ if (p_dcb != NULL)
+ {
+ mca_dcb_event(p_dcb, MCA_DCB_TC_CLOSE_EVT, (tMCA_DCB_EVT *) &close);
+ }
+ }
+ p_tbl->state = MCA_TC_ST_UNUSED;
+}
+
+/*******************************************************************************
+**
+** Function mca_tc_open_ind
+**
+** Description This function is called by the L2CAP interface when
+** the L2CAP channel is opened. It looks up the CCB or DCB
+** for the channel and sends it an open event.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void mca_tc_open_ind(tMCA_TC_TBL *p_tbl)
+{
+ tMCA_CCB *p_ccb;
+ tMCA_DCB *p_dcb;
+ tMCA_OPEN open;
+
+ MCA_TRACE_DEBUG2("mca_tc_open_ind tcid: %d, cb_idx: %d", p_tbl->tcid, p_tbl->cb_idx);
+ p_tbl->state = MCA_TC_ST_OPEN;
+
+ open.peer_mtu = p_tbl->peer_mtu;
+ open.lcid = p_tbl->lcid;
+ /* use param to indicate the role of connection.
+ * MCA_ACP, if ACP */
+ open.param = MCA_INT;
+ if (p_tbl->cfg_flags & MCA_L2C_CFG_CONN_ACP)
+ {
+ open.param = MCA_ACP;
+ }
+
+ /* if control channel, notify ccb that channel open */
+ if (p_tbl->tcid == MCA_CTRL_TCID)
+ {
+ p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx);
+
+ mca_ccb_event(p_ccb, MCA_CCB_LL_OPEN_EVT, (tMCA_CCB_EVT *)&open);
+ }
+ /* must be data channel, notify dcb that channel open */
+ else
+ {
+ /* look up dcb */
+ p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx);
+
+ /* put lcid in event data */
+ if (p_dcb != NULL)
+ {
+ mca_dcb_event(p_dcb, MCA_DCB_TC_OPEN_EVT, (tMCA_DCB_EVT *) &open);
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function mca_tc_cong_ind
+**
+** Description This function is called by the L2CAP interface layer when
+** L2CAP calls the congestion callback. It looks up the CCB
+** or DCB for the channel and sends it a congestion event.
+** The is_congested parameter is the same value passed by
+** the L2CAP callback function.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void mca_tc_cong_ind(tMCA_TC_TBL *p_tbl, BOOLEAN is_congested)
+{
+ tMCA_CCB *p_ccb;
+ tMCA_DCB *p_dcb;
+
+ MCA_TRACE_DEBUG2("mca_tc_cong_ind tcid: %d, cb_idx: %d", p_tbl->tcid, p_tbl->cb_idx);
+ /* if control channel, notify ccb of congestion */
+ if (p_tbl->tcid == MCA_CTRL_TCID)
+ {
+ p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx);
+ mca_ccb_event(p_ccb, MCA_CCB_LL_CONG_EVT, (tMCA_CCB_EVT *) &is_congested);
+ }
+ /* notify dcb that channel open */
+ else
+ {
+ /* look up dcb by cb_idx */
+ p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx);
+ if (p_dcb != NULL)
+ {
+ mca_dcb_event(p_dcb, MCA_DCB_TC_CONG_EVT, (tMCA_DCB_EVT *) &is_congested);
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function mca_tc_data_ind
+**
+** Description This function is called by the L2CAP interface layer when
+** incoming data is received from L2CAP. It looks up the CCB
+** or DCB for the channel and routes the data accordingly.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void mca_tc_data_ind(tMCA_TC_TBL *p_tbl, BT_HDR *p_buf)
+{
+ tMCA_CCB *p_ccb;
+ tMCA_DCB *p_dcb;
+ UINT8 event = MCA_CCB_MSG_RSP_EVT;
+ UINT8 *p;
+ UINT8 rej_rsp_code = MCA_RSP_SUCCESS;
+
+ MCA_TRACE_DEBUG2("mca_tc_data_ind tcid: %d, cb_idx: %d", p_tbl->tcid, p_tbl->cb_idx);
+
+
+ /* if control channel, handle control message */
+ if (p_tbl->tcid == MCA_CTRL_TCID)
+ {
+ p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx);
+ if (p_ccb)
+ {
+ p = (UINT8*)(p_buf+1) + p_buf->offset;
+ /* all the request opcode has bit 0 set. response code has bit 0 clear */
+ if ((*p) & 0x01)
+ event = MCA_CCB_MSG_REQ_EVT;
+
+ if (*p < MCA_NUM_STANDARD_OPCODE)
+ {
+ if (p_buf->len != mca_std_msg_len[*p])
+ {
+ MCA_TRACE_ERROR3 ("opcode: %d required len:%d, got len:%d", *p, mca_std_msg_len[*p], p_buf->len);
+ rej_rsp_code = MCA_RSP_BAD_PARAM;
+ }
+ }
+ else if ((*p >= MCA_FIRST_SYNC_OP) && (*p <= MCA_LAST_SYNC_OP))
+ {
+ MCA_TRACE_ERROR2 ("unsupported SYNC opcode: %d len:%d", *p, p_buf->len);
+ /* reject unsupported request */
+ rej_rsp_code = MCA_RSP_NO_SUPPORT;
+ }
+ else
+ {
+ MCA_TRACE_ERROR2 ("bad opcode: %d len:%d", *p, p_buf->len);
+ /* reject unsupported request */
+ rej_rsp_code = MCA_RSP_BAD_OPCODE;
+ }
+
+ p_buf->layer_specific = rej_rsp_code;
+ /* forward the request/response to state machine */
+ mca_ccb_event(p_ccb, event, (tMCA_CCB_EVT *) p_buf);
+ } /* got a valid ccb */
+ else
+ GKI_freebuf(p_buf);
+ }
+ /* else send event to dcb */
+ else
+ {
+ p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx);
+ if (p_dcb != NULL)
+ {
+ mca_dcb_event(p_dcb, MCA_DCB_TC_DATA_EVT, (tMCA_DCB_EVT *) p_buf);
+ }
+ else
+ GKI_freebuf(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function mca_rcb_alloc
+**
+** Description This function allocates a registration control block.
+** If no free RCB is available, it returns NULL.
+**
+** Returns tMCA_RCB *
+**
+*******************************************************************************/
+tMCA_RCB * mca_rcb_alloc(tMCA_REG *p_reg)
+{
+ int i;
+ tMCA_RCB *p_rcb = NULL;
+
+ for (i=0; i<MCA_NUM_REGS; i++)
+ {
+ if (mca_cb.rcb[i].p_cback == NULL)
+ {
+ p_rcb = &mca_cb.rcb[i];
+ memcpy (&p_rcb->reg, p_reg, sizeof(tMCA_REG));
+ break;
+ }
+ }
+ return p_rcb;
+}
+
+/*******************************************************************************
+**
+** Function mca_rcb_dealloc
+**
+** Description This function deallocates the RCB with the given handle.
+**
+** Returns void.
+**
+*******************************************************************************/
+void mca_rcb_dealloc(tMCA_HANDLE handle)
+{
+ int i;
+ BOOLEAN done = TRUE;
+ tMCA_RCB *p_rcb;
+ tMCA_CCB *p_ccb;
+
+ if (handle && (handle<=MCA_NUM_REGS))
+ {
+ handle--;
+ p_rcb = &mca_cb.rcb[handle];
+ if (p_rcb->p_cback)
+ {
+ p_ccb = &mca_cb.ccb[handle*MCA_NUM_LINKS];
+ /* check if all associated CCB are disconnected */
+ for (i=0; i<MCA_NUM_LINKS; i++, p_ccb++)
+ {
+ if (p_ccb->p_rcb)
+ {
+ done = FALSE;
+ mca_ccb_event (p_ccb, MCA_CCB_API_DISCONNECT_EVT, NULL);
+ }
+ }
+
+ if (done)
+ {
+ memset (p_rcb, 0, sizeof(tMCA_RCB));
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function mca_rcb_to_handle
+**
+** Description This function converts a pointer to an RCB to
+** a handle (tMCA_HANDLE). It returns the handle.
+**
+** Returns void.
+**
+*******************************************************************************/
+tMCA_HANDLE mca_rcb_to_handle(tMCA_RCB *p_rcb)
+{
+ return(UINT8) (p_rcb - mca_cb.rcb + 1);
+}
+
+/*******************************************************************************
+**
+** Function mca_rcb_by_handle
+**
+** Description This function finds the RCB for a handle (tMCA_HANDLE).
+** It returns a pointer to the RCB. If no RCB matches the
+** handle it returns NULL.
+**
+** Returns tMCA_RCB *
+**
+*******************************************************************************/
+tMCA_RCB *mca_rcb_by_handle(tMCA_HANDLE handle)
+{
+ tMCA_RCB *p_rcb = NULL;
+
+ if (handle && (handle<=MCA_NUM_REGS) && mca_cb.rcb[handle-1].p_cback)
+ {
+ p_rcb = &mca_cb.rcb[handle-1];
+ }
+ return p_rcb;
+}
+
+/*******************************************************************************
+**
+** Function mca_is_valid_dep_id
+**
+** Description This function checks if the given dep_id is valid.
+**
+** Returns TRUE, if this is a valid local dep_id
+**
+*******************************************************************************/
+BOOLEAN mca_is_valid_dep_id(tMCA_RCB *p_rcb, tMCA_DEP dep)
+{
+ BOOLEAN valid = FALSE;
+ if (dep < MCA_NUM_DEPS && p_rcb->dep[dep].p_data_cback)
+ {
+ valid = TRUE;
+ }
+ return valid;
+}
+
+/*******************************************************************************
+**
+** Function mca_free_buf
+**
+** Description free memory for specified GKI packet
+**
+** Returns void
+**
+*******************************************************************************/
+void mca_free_buf (void **p_buf)
+{
+ if (p_buf && *p_buf)
+ {
+ GKI_freebuf(*p_buf);
+ *p_buf = NULL;
+ }
+}
diff --git a/stack/obx/hdrs/obx_dauth.c b/stack/obx/hdrs/obx_dauth.c
new file mode 100644
index 0000000..91d4bd7
--- /dev/null
+++ b/stack/obx/hdrs/obx_dauth.c
@@ -0,0 +1,149 @@
+/*****************************************************************************
+**
+** Name: obx_dauth.c
+**
+** File: OBEX Authentication related functions
+**
+** Copyright (c) 2003-2008, WIDCOMM Inc., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include <string.h>
+#include "bt_target.h"
+#include "obx_api.h"
+
+
+
+
+
+#if (OBX_CLIENT_INCLUDED == TRUE)
+
+/*******************************************************************************
+**
+** Function OBX_ReadChallenge
+**
+** Description This function is called by the client to read the Realm and
+** options of the Authentication Challenge Header in the
+** given OBEX packet ( from an OBX_PASSWORD_EVT event).
+**
+** Returns TRUE, if the header is in the OBEX packet.
+** FALSE, otherwise.
+**
+*******************************************************************************/
+BOOLEAN OBX_ReadChallenge(BT_HDR *p_pkt, tOBX_CHARSET *p_charset,
+ UINT8 **p_realm, UINT8 *p_len,
+ tOBX_AUTH_OPT *p_option)
+{
+ BOOLEAN status;
+ tOBX_TRIPLET triplet[OBX_MAX_NUM_AUTH_TRIPLET];
+ UINT8 num_trip = OBX_MAX_NUM_AUTH_TRIPLET;
+ UINT8 xx;
+
+ /* The coverity complaints on this function is not correct.
+ * The value in triplet[] is set/initialized by OBX_ReadTriplet if it returns TRUE.
+ * leave this unnecessary memset here */
+ memset( triplet, 0, sizeof(triplet ));
+
+ *p_len = 0;
+ *p_option = OBX_AO_NONE;
+ *p_realm = NULL;
+ *p_charset = OBX_RCS_ASCII; /* 0 */
+ status = OBX_ReadTriplet(p_pkt, OBX_HI_CHALLENGE, triplet, &num_trip);
+ if(status)
+ {
+ for(xx=0; xx<num_trip; xx++)
+ {
+ switch(triplet[xx].tag)
+ {
+ case OBX_OPTIONS_CHLNG_TAG:
+ *p_option = triplet[xx].p_array[0];
+ break;
+ case OBX_REALM_CHLNG_TAG:
+ *p_charset = triplet[xx].p_array[0];
+ *p_len = triplet[xx].len - 1;
+ *p_realm = &(triplet[xx].p_array[1]);
+ break;
+ /* The user does not need to know the nonce value
+ case OBX_NONCE_CHLNG_TAG:
+ break;
+ */
+ }
+ }
+ }
+
+ return status;
+}
+#endif
+
+
+
+#if (OBX_SERVER_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function OBX_ReadAuthParams
+**
+** Description This function is called by the server to read the User ID of
+** the Authentication Response Header in the given OBEX packet
+** ( from an OBX_PASSWORD_EVT event).
+** This function also
+** checks if the authentication challenge header exists and
+** checks the authentication challenge options.
+**
+** Returns TRUE, if the header is in the OBEX packet.
+** FALSE, otherwise.
+**
+*******************************************************************************/
+BOOLEAN OBX_ReadAuthParams(BT_HDR *p_pkt, UINT8 **p_userid, UINT8 *p_len,
+ BOOLEAN *is_challenged, tOBX_AUTH_OPT *p_option)
+{
+ BOOLEAN status;
+ tOBX_TRIPLET triplet[OBX_MAX_NUM_AUTH_TRIPLET];
+ UINT8 num_trip = OBX_MAX_NUM_AUTH_TRIPLET;
+ UINT8 xx;
+
+ /* The coverity complaints on this function is not correct.
+ * The value in triplet[] is set/initialized by OBX_ReadTriplet if it returns TRUE.
+ * leave this unnecessary memset here */
+ memset( triplet, 0, sizeof(triplet ));
+
+ *p_userid = NULL;
+ *p_len = 0;
+ *is_challenged = FALSE;
+ *p_option = OBX_AO_NONE;
+ status = OBX_ReadTriplet(p_pkt, OBX_HI_AUTH_RSP, triplet, &num_trip);
+ if(status)
+ {
+ /* found authentication response, but we do not know if it has user id.
+ * assume no user id */
+ *p_len = 0;
+ for(xx=0; xx<num_trip; xx++)
+ {
+ if(triplet[xx].tag == OBX_USERID_RSP_TAG)
+ {
+ *p_len = triplet[xx].len;
+ *p_userid = triplet[xx].p_array;
+ break;
+ }
+ }
+
+ /* read the authentication challenge header,
+ * only if the authentication response header exists */
+ if( OBX_ReadTriplet(p_pkt, OBX_HI_CHALLENGE, triplet, &num_trip) == TRUE)
+ {
+ *is_challenged = TRUE;
+ for(xx=0; xx<num_trip; xx++)
+ {
+ if(triplet[xx].tag == OBX_OPTIONS_CHLNG_TAG)
+ {
+ *p_option = triplet[xx].p_array[0];
+ break;
+ }
+ }
+ }
+ }
+ return status;
+}
+#endif
+
+
+
diff --git a/stack/obx/hdrs/obx_dbtp.c b/stack/obx/hdrs/obx_dbtp.c
new file mode 100644
index 0000000..fbf473d
--- /dev/null
+++ b/stack/obx/hdrs/obx_dbtp.c
@@ -0,0 +1,189 @@
+/*****************************************************************************
+**
+** Name: obx_dbtp.c
+**
+** File: OBEX Headers Decode Utility functions
+** - for current Bluetooth profiles
+**
+** Copyright (c) 2003-2008, WIDCOMM Inc., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include <string.h>
+#include "bt_target.h"
+#include "obx_api.h"
+#include "obx_int.h"
+
+
+
+
+/*******************************************************************************
+**
+** Function OBX_ReadTypeHdr
+**
+** Description This function is called to get the Type Header in the given
+** OBEX packet.
+**
+** Returns TRUE, if the header is in the OBEX packet.
+** FALSE, otherwise.
+**
+*******************************************************************************/
+BOOLEAN OBX_ReadTypeHdr(BT_HDR *p_pkt, UINT8 **p_type, UINT16 *p_len)
+{
+ return OBX_ReadByteStrHdr(p_pkt, OBX_HI_TYPE, p_type, p_len, 0);
+}
+
+/*******************************************************************************
+**
+** Function OBX_ReadLengthHdr
+**
+** Description This function is called to get the Length Header in the given
+** OBEX packet.
+**
+** Returns TRUE, if the header is in the OBEX packet.
+** FALSE, otherwise.
+**
+*******************************************************************************/
+BOOLEAN OBX_ReadLengthHdr(BT_HDR *p_pkt, UINT32 *p_len)
+{
+ return OBX_Read4ByteHdr(p_pkt, OBX_HI_LENGTH, p_len);
+}
+
+/*******************************************************************************
+**
+** Function OBX_ReadTargetHdr
+**
+** Description This function is called to get the Target Header in the
+** given OBEX packet.
+**
+** Returns TRUE, if the header is in the OBEX packet.
+** FALSE, otherwise.
+**
+*******************************************************************************/
+BOOLEAN OBX_ReadTargetHdr(BT_HDR *p_pkt, UINT8 **p_target, UINT16 *p_len, UINT8 next)
+{
+ return OBX_ReadByteStrHdr(p_pkt, OBX_HI_TARGET, p_target, p_len, next);
+}
+
+/*******************************************************************************
+**
+** Function OBX_ReadBodyHdr
+**
+** Description This function is called to get the Body Header in the
+** given OBEX packet.
+**
+** Returns 1, if a single header is in the OBEX packet.
+** 2, if a end of body header is in the OBEX packet.
+** 0, (FALSE) otherwise.
+**
+*******************************************************************************/
+UINT8 OBX_ReadBodyHdr(BT_HDR *p_pkt, UINT8 **p_body, UINT16 *p_len, BOOLEAN *p_end)
+{
+ BOOLEAN status;
+ UINT8 *p_body2;
+ UINT16 len2;
+ UINT8 num;
+
+ *p_end = FALSE;
+ num = OBX_ReadByteStrHdr(p_pkt, OBX_HI_BODY, p_body, p_len, 0);
+ status = OBX_ReadByteStrHdr(p_pkt, OBX_HI_BODY_END, &p_body2, &len2, 0);
+ if(num == FALSE && status == TRUE)
+ {
+ *p_body = p_body2;
+ *p_len = len2;
+ *p_end = TRUE;
+ }
+ num += status;
+
+ return num;
+}
+
+/*******************************************************************************
+**
+** Function OBX_ReadWhoHdr
+**
+** Description This function is called to get the Who Header in the
+** given OBEX packet.
+**
+** Returns TRUE, if the header is in the OBEX packet.
+** FALSE, otherwise.
+**
+*******************************************************************************/
+BOOLEAN OBX_ReadWhoHdr(BT_HDR *p_pkt, UINT8 **p_who, UINT16 *p_len)
+{
+ return OBX_ReadByteStrHdr(p_pkt, OBX_HI_WHO, p_who, p_len, 0);
+}
+
+/*******************************************************************************
+**
+** Function OBX_ReadAppParamHdr
+**
+** Description This function is called to get the Application Parameter Header
+** in the given OBEX packet.
+**
+** Returns TRUE, if the header is in the OBEX packet.
+** FALSE, otherwise.
+**
+*******************************************************************************/
+BOOLEAN OBX_ReadAppParamHdr(BT_HDR *p_pkt, UINT8 *p_tag, UINT8 **p_app_param, UINT8 *p_len, UINT8 next)
+{
+ BOOLEAN status;
+ tOBX_TRIPLET triplet[OBX_MAX_TRIPLET];
+ UINT8 num = OBX_MAX_TRIPLET;
+
+ /* The coverity complaints on this function is not correct.
+ * The value in triplet[] is set/initialized by OBX_ReadTriplet if it returns TRUE.
+ * leave this unnecessary memset here */
+ memset( triplet, 0, sizeof(triplet ));
+
+ status = OBX_ReadTriplet(p_pkt, OBX_HI_APP_PARMS, triplet, &num);
+ if(status == TRUE)
+ {
+ if(next >= num)
+ {
+ status = FALSE;
+ }
+ else
+ {
+ *p_tag = triplet[next].tag;
+ *p_app_param = triplet[next].p_array;
+ *p_len = triplet[next].len;
+ OBX_TRACE_DEBUG3( "OBX_ReadAppParamHdr: next: %d, tag: %x, len: %d",
+ next, *p_tag, *p_len);
+ }
+ }
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function OBX_ReadPermissionHdr
+**
+** Description This function is called to get the Application Parameter Header
+** in the given OBEX packet.
+**
+** Returns TRUE, if the header is in the OBEX packet.
+** FALSE, otherwise.
+**
+*******************************************************************************/
+BOOLEAN OBX_ReadPermissionHdr(BT_HDR *p_pkt, UINT8 *p_user, UINT8 *p_group, UINT8 *p_other)
+{
+ UINT32 permission;
+ BOOLEAN status = FALSE;
+
+ if (OBX_Read4ByteHdr(p_pkt, OBX_HI_PERMISSION, &permission))
+ {
+ *p_other = (permission & 0xFF);
+ permission >>= 8;
+ *p_group = (permission & 0xFF);
+ permission >>= 8;
+ *p_user = (permission & 0xFF);
+ status = TRUE;
+ }
+
+ return status;
+}
+
+
+
+
diff --git a/stack/obx/hdrs/obx_dopt.c b/stack/obx/hdrs/obx_dopt.c
new file mode 100644
index 0000000..e3d0d27
--- /dev/null
+++ b/stack/obx/hdrs/obx_dopt.c
@@ -0,0 +1,52 @@
+/*****************************************************************************
+**
+** Name: obx_dopt.c
+**
+** File: OBEX Headers Decode Utility functions
+** - optional functions
+**
+** Copyright (c) 2003-2004, WIDCOMM Inc., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include "bt_target.h"
+#include "obx_api.h"
+
+
+
+
+
+
+/*******************************************************************************
+**
+** Function OBX_ReadTimeHdr
+**
+** Description This function is called to get the Time Header in the given
+** OBEX packet.
+**
+** Returns TRUE, if the header is in the OBEX packet.
+** FALSE, otherwise.
+**
+*******************************************************************************/
+BOOLEAN OBX_ReadTimeHdr(BT_HDR *p_pkt, UINT8 **p_time, UINT16 *p_len)
+{
+ return OBX_ReadByteStrHdr(p_pkt, OBX_HI_TIME, p_time, p_len, 0);
+}
+
+
+/*******************************************************************************
+**
+** Function OBX_ReadHttpHdr
+**
+** Description This function is called to get the HTTP Header in the
+** given OBEX packet.
+**
+** Returns TRUE, if the header is in the OBEX packet.
+** FALSE, otherwise.
+**
+*******************************************************************************/
+BOOLEAN OBX_ReadHttpHdr(BT_HDR *p_pkt, UINT8 **p_http, UINT16 *p_len, UINT8 next)
+{
+ return OBX_ReadByteStrHdr(p_pkt, OBX_HI_HTTP, p_http, p_len, next);
+}
+
diff --git a/stack/obx/hdrs/obx_dunic.c b/stack/obx/hdrs/obx_dunic.c
new file mode 100644
index 0000000..c8f6b12
--- /dev/null
+++ b/stack/obx/hdrs/obx_dunic.c
@@ -0,0 +1,64 @@
+/*****************************************************************************
+**
+** Name: obx_dunic.c
+**
+** File: OBEX Headers Decode Utility functions
+** - Unicode functions
+**
+** Copyright (c) 2003-2004, WIDCOMM Inc., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include "bt_target.h"
+#include "obx_api.h"
+
+
+
+
+/*******************************************************************************
+**
+** Function OBX_ReadNameHdr
+**
+** Description This function is called to get the Name Header in the given
+** OBEX packet.
+**
+** Returns TRUE, if the header is in the OBEX packet.
+** FALSE, otherwise.
+**
+*******************************************************************************/
+BOOLEAN OBX_ReadNameHdr(BT_HDR *p_pkt, UINT16 *p_name, UINT16 *p_len)
+{
+ return OBX_ReadUnicodeHdr(p_pkt, OBX_HI_NAME, p_name, p_len);
+}
+
+/*******************************************************************************
+**
+** Function OBX_ReadDescrHdr
+**
+** Description This function is called to get the Description Header in the
+** given OBEX packet.
+**
+** Returns TRUE, if the header is in the OBEX packet.
+** FALSE, otherwise.
+**
+*******************************************************************************/
+BOOLEAN OBX_ReadDescrHdr(BT_HDR *p_pkt, UINT16 *p_descr, UINT16 *p_len)
+{
+ return OBX_ReadUnicodeHdr(p_pkt, OBX_HI_DESCRIPTION, p_descr, p_len);
+}
+
+/*******************************************************************************
+**
+** Function OBX_ReadDestNameHdr
+**
+** Description This function is called to get the DestName Header in the
+** given OBEX packet.
+**
+** Returns TRUE, if the header is in the OBEX packet.
+** FALSE, otherwise.
+**
+*******************************************************************************/
+BOOLEAN OBX_ReadDestNameHdr(BT_HDR *p_pkt, UINT16 *p_dest, UINT16 *p_len)
+{
+ return OBX_ReadUnicodeHdr(p_pkt, OBX_HI_DEST_NAME, p_dest, p_len);
+}
diff --git a/stack/obx/hdrs/obx_dutf.c b/stack/obx/hdrs/obx_dutf.c
new file mode 100644
index 0000000..a800428
--- /dev/null
+++ b/stack/obx/hdrs/obx_dutf.c
@@ -0,0 +1,91 @@
+/*****************************************************************************
+**
+** Name: obx_dutf.c
+**
+** File: OBEX Headers Decode Utility functions
+** - Unicode conversion functions
+**
+** Copyright (c) 2003-2009, Broadcom Corp., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include "bt_target.h"
+#include "gki.h"
+#include "obx_api.h"
+
+
+/*******************************************************************************
+**
+** Function OBX_ReadUtf8NameHdr
+**
+** Description This function is called to get the Name Header in the given
+** OBEX packet. If Name header exists in the given OBEX packet,
+** it is converted to UTF8 format and copied into p_name.
+**
+** Returns TRUE, if the header is in the OBEX packet.
+** FALSE, otherwise.
+**
+*******************************************************************************/
+BOOLEAN OBX_ReadUtf8NameHdr(BT_HDR *p_pkt, UINT8 *p_name, UINT16 max_len)
+{
+ BOOLEAN status;
+ UINT16 *p_unicode = (UINT16 *)GKI_getbuf((UINT16)((max_len + 1) * 2));
+ UINT16 len = max_len;
+
+ status = OBX_ReadUnicodeHdr(p_pkt, OBX_HI_NAME, p_unicode, &len);
+ utfc_16_to_8(p_name, max_len, p_unicode, len);
+ GKI_freebuf(p_unicode);
+ return status;
+}
+
+
+
+/*******************************************************************************
+**
+** Function OBX_ReadUtf8DescrHdr
+**
+** Description This function is called to get the Description Header in the
+** given OBEX packet. If Description header exists in the given
+** OBEX packet, it is converted to UTF8 format and copied into
+** p_descr.
+**
+** Returns TRUE, if the header is in the OBEX packet.
+** FALSE, otherwise.
+**
+*******************************************************************************/
+BOOLEAN OBX_ReadUtf8DescrHdr(BT_HDR *p_pkt, UINT8 *p_descr, UINT16 max_len)
+{
+ BOOLEAN status;
+ UINT16 *p_unicode = (UINT16 *)GKI_getbuf((UINT16)((max_len + 1) * 2));
+ UINT16 len = max_len;
+
+ status = OBX_ReadUnicodeHdr(p_pkt, OBX_HI_DESCRIPTION, p_unicode, &len);
+ utfc_16_to_8(p_descr, max_len, p_unicode, len);
+ GKI_freebuf(p_unicode);
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function OBX_ReadUtf8DestNameHdr
+**
+** Description This function is called to get the DestName Header in the
+** given OBEX packet.
+**
+** Returns TRUE, if the header is in the OBEX packet.
+** FALSE, otherwise.
+**
+*******************************************************************************/
+BOOLEAN OBX_ReadUtf8DestNameHdr(BT_HDR *p_pkt, UINT8 *p_dest, UINT16 max_len)
+{
+ BOOLEAN status;
+ UINT16 *p_unicode = (UINT16 *)GKI_getbuf((UINT16)((max_len + 1) * 2));
+ UINT16 len = max_len;
+
+ status = OBX_ReadUnicodeHdr(p_pkt, OBX_HI_DEST_NAME, p_unicode, &len);
+ utfc_16_to_8(p_dest, max_len, p_unicode, len);
+ GKI_freebuf(p_unicode);
+ return status;
+}
+
+
diff --git a/stack/obx/hdrs/obx_dwchar.c b/stack/obx/hdrs/obx_dwchar.c
new file mode 100644
index 0000000..2aa5ebd
--- /dev/null
+++ b/stack/obx/hdrs/obx_dwchar.c
@@ -0,0 +1,91 @@
+/*****************************************************************************
+**
+** Name: obx_dwchar.c
+**
+** File: OBEX Headers Decode Utility functions
+** - Unicode conversion functions
+**
+** Copyright (c) 2003-2004, WIDCOMM Inc., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include "bt_target.h"
+#include "gki.h"
+#include "obx_api.h"
+
+
+/*******************************************************************************
+**
+** Function OBX_ReadAsciiNameHdr
+**
+** Description This function is called to get the Name Header in the given
+** OBEX packet. If Name header exists in the given OBEX packet,
+** it is converted to ASCII format and copied into p_name.
+**
+** Returns TRUE, if the header is in the OBEX packet.
+** FALSE, otherwise.
+**
+*******************************************************************************/
+BOOLEAN OBX_ReadAsciiNameHdr(BT_HDR *p_pkt, char *p_name, UINT16 max_len)
+{
+ BOOLEAN status;
+ UINT16 *p_unicode = (UINT16 *)GKI_getbuf((UINT16)((max_len + 1) * 2));
+ UINT16 len = max_len;
+
+ status = OBX_ReadUnicodeHdr(p_pkt, OBX_HI_NAME, p_unicode, &len);
+ OBX_WcharToChar(p_name, p_unicode, max_len);
+ GKI_freebuf(p_unicode);
+ return status;
+}
+
+
+
+/*******************************************************************************
+**
+** Function OBX_ReadAsciiDescrHdr
+**
+** Description This function is called to get the Description Header in the
+** given OBEX packet. If Description header exists in the given
+** OBEX packet, it is converted to ASCII format and copied into
+** p_descr.
+**
+** Returns TRUE, if the header is in the OBEX packet.
+** FALSE, otherwise.
+**
+*******************************************************************************/
+BOOLEAN OBX_ReadAsciiDescrHdr(BT_HDR *p_pkt, char *p_descr, UINT16 max_len)
+{
+ BOOLEAN status;
+ UINT16 *p_unicode = (UINT16 *)GKI_getbuf((UINT16)((max_len + 1) * 2));
+ UINT16 len = max_len;
+
+ status = OBX_ReadUnicodeHdr(p_pkt, OBX_HI_DESCRIPTION, p_unicode, &len);
+ OBX_WcharToChar(p_descr, p_unicode, max_len);
+ GKI_freebuf(p_unicode);
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function OBX_ReadAsciiDestNameHdr
+**
+** Description This function is called to get the DestName Header in the
+** given OBEX packet. If DestName header exists in the given
+** OBEX packet, it is converted to ASCII format and copied into
+** p_descr.
+**
+** Returns TRUE, if the header is in the OBEX packet.
+** FALSE, otherwise.
+**
+*******************************************************************************/
+BOOLEAN OBX_ReadAsciiDestNameHdr(BT_HDR *p_pkt, char *p_dest, UINT16 max_len)
+{
+ BOOLEAN status;
+ UINT16 *p_unicode = (UINT16 *)GKI_getbuf((UINT16)((max_len + 1) * 2));
+ UINT16 len = max_len;
+
+ status = OBX_ReadUnicodeHdr(p_pkt, OBX_HI_DEST_NAME, p_unicode, &len);
+ OBX_WcharToChar(p_dest, p_unicode, max_len);
+ GKI_freebuf(p_unicode);
+ return status;
+}
diff --git a/stack/obx/hdrs/obx_ebtp.c b/stack/obx/hdrs/obx_ebtp.c
new file mode 100644
index 0000000..93dd988
--- /dev/null
+++ b/stack/obx/hdrs/obx_ebtp.c
@@ -0,0 +1,177 @@
+/*****************************************************************************
+**
+** Name: obx_ebtp.c
+**
+** File: OBEX Headers Encode Utility functions
+** - for current Bluetooth profiles
+**
+** Copyright (c) 2003-2004, WIDCOMM Inc., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include <string.h>
+
+#include "bt_target.h"
+#include "obx_api.h"
+
+
+
+/*******************************************************************************
+**
+** Function OBX_AddTypeHdr
+**
+** Description This function is called to add an OBEX Type header
+** to an OBEX packet.
+**
+** Returns TRUE, if the header is added successfully.
+** FALSE, if the operation failed. p_pkt is not altered.
+**
+*******************************************************************************/
+BOOLEAN OBX_AddTypeHdr(BT_HDR *p_pkt, char *p_type)
+{
+ return OBX_AddByteStrHdr(p_pkt, OBX_HI_TYPE, (UINT8*)p_type, (UINT16)(strlen(p_type)+1));
+}
+
+/*******************************************************************************
+**
+** Function OBX_AddLengthHdr
+**
+** Description This function is called to add an OBEX Length header to an OBEX
+** packet. The Length header describes the total length in bytes of
+** the object.
+**
+** Returns TRUE, if the header is added successfully.
+** FALSE, if the operation failed. p_pkt is not altered.
+**
+*******************************************************************************/
+BOOLEAN OBX_AddLengthHdr(BT_HDR *p_pkt, UINT32 len)
+{
+ return OBX_Add4ByteHdr(p_pkt, OBX_HI_LENGTH, len);
+}
+
+/*******************************************************************************
+**
+** Function OBX_AddTargetHdr
+**
+** Description This function is called to add an OBEX Target header to an OBEX
+** packet. This header is most commonly used in Connect packets.
+**
+** NOTE: The target header must be the first header in an OBEX message.
+**
+** Returns TRUE, if the header is added successfully.
+** FALSE, if the operation failed. p_pkt is not altered.
+**
+*******************************************************************************/
+BOOLEAN OBX_AddTargetHdr(BT_HDR *p_pkt, UINT8 *p_target, UINT16 len)
+{
+ BOOLEAN add = FALSE;
+ UINT8 *p;
+
+ if (p_pkt->len == 0)
+ {
+ add = TRUE;
+ }
+ else if (p_pkt->len == 2)
+ {
+ p = (UINT8 *)(p_pkt+1)+p_pkt->offset;
+ if ((*p) == OBX_HI_SESSION_SN)
+ add = TRUE;
+
+ }
+ /* allow SSN to preceed target header */
+ if (add)
+ return OBX_AddByteStrHdr(p_pkt, OBX_HI_TARGET, p_target, len);
+ else
+ {
+ BT_ERROR_TRACE_1(TRACE_LAYER_OBEX, "Target header must be the first:%d", p_pkt->len) ;
+ return FALSE;
+ }
+}
+
+/*******************************************************************************
+**
+** Function OBX_AddBodyHdr
+**
+** Description This function is called to add an OBEX body header
+** to an OBEX packet.
+**
+** NOTE: The body header must be the last header in an OBEX message.
+**
+** Returns TRUE, if the header is added successfully.
+** FALSE, if the operation failed. p_pkt is not altered.
+**
+*******************************************************************************/
+BOOLEAN OBX_AddBodyHdr(BT_HDR *p_pkt, UINT8 *p_body, UINT16 len, BOOLEAN end)
+{
+ UINT8 id = (end)?OBX_HI_BODY_END:OBX_HI_BODY;
+ return OBX_AddByteStrHdr(p_pkt, id, p_body, len);
+}
+
+
+/*******************************************************************************
+**
+** Function OBX_AddWhoHdr
+**
+** Description This function is called to add an OBEX Who header to an OBEX
+** packet.
+**
+** Note: Who header is typically used in an OBEX CONNECT response packet
+** to indicate the UUID of the service that has accepted the
+** directed connection. If the server calls OBX_StartServer() with
+** specified target header, this OBEX implementation automatically
+** adds this WHO header to the CONNECT response packet. If
+** OBX_StartServer() is called with target header length as 0, the
+** OBEX API user is responsible to add the WHO header.
+**
+** Returns TRUE, if the header is added successfully.
+** FALSE, if the operation failed. p_pkt is not altered.
+**
+*******************************************************************************/
+BOOLEAN OBX_AddWhoHdr(BT_HDR *p_pkt, UINT8 *p_who, UINT16 len)
+{
+ return OBX_AddByteStrHdr(p_pkt, OBX_HI_WHO, p_who, len);
+}
+
+/*******************************************************************************
+**
+** Function OBX_AddAppParamHdr
+**
+** Description This function is called to add an OBEX Application Parameter
+** header to an OBEX packet. This header is used by the application
+** layer above OBEX to convey application specific information.
+**
+** Returns TRUE, if the header is added successfully.
+** FALSE, if the operation failed. p_pkt is not altered.
+**
+*******************************************************************************/
+BOOLEAN OBX_AddAppParamHdr(BT_HDR *p_pkt, tOBX_TRIPLET *p_triplet, UINT8 num)
+{
+ return OBX_AddTriplet(p_pkt, OBX_HI_APP_PARMS, p_triplet, num);
+}
+
+/*******************************************************************************
+**
+** Function OBX_AddPermissionHdr
+**
+** Description This function is called to add an OBEX Permission header to an OBEX
+** packet.
+** bit 0 is set for read permission
+** bit 1 is set for write permission
+** bit 2 is set for delete permission
+** bit 7 is set for modify permission
+**
+** Returns TRUE, if the header is added successfully.
+** FALSE, if the operation failed. p_pkt is not altered.
+**
+*******************************************************************************/
+BOOLEAN OBX_AddPermissionHdr(BT_HDR *p_pkt, UINT8 user, UINT8 group, UINT8 other)
+{
+ UINT32 permission = user;
+ permission <<= 8;
+ permission |= group;
+ permission <<= 8;
+ permission |= other;
+ return OBX_Add4ByteHdr(p_pkt, OBX_HI_PERMISSION, permission);
+}
+
+
diff --git a/stack/obx/hdrs/obx_eopt.c b/stack/obx/hdrs/obx_eopt.c
new file mode 100644
index 0000000..e0b0487
--- /dev/null
+++ b/stack/obx/hdrs/obx_eopt.c
@@ -0,0 +1,51 @@
+/*****************************************************************************
+**
+** Name: obx_eopt.c
+**
+** File: OBEX Headers Encode Utility functions
+** - optional functions
+**
+** Copyright (c) 2003-2004, WIDCOMM Inc., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include <string.h>
+#include "bt_target.h"
+#include "obx_api.h"
+
+
+
+/*******************************************************************************
+**
+** Function OBX_AddTimeHdr
+**
+** Description This function is called to add an OBEX Time header
+** to an OBEX packet.
+**
+** Returns TRUE, if the header is added successfully.
+** FALSE, if the operation failed. p_pkt is not altered.
+**
+*******************************************************************************/
+BOOLEAN OBX_AddTimeHdr(BT_HDR *p_pkt, char *p_time)
+{
+ return OBX_AddByteStrHdr(p_pkt, OBX_HI_TIME, (UINT8 *)p_time, (UINT16)strlen(p_time));
+}
+
+
+/*******************************************************************************
+**
+** Function OBX_AddHttpHdr
+**
+** Description This function is called to add an OBEX HTTP header
+** to an OBEX packet.
+**
+** Returns TRUE, if the header is added successfully.
+** FALSE, if the operation failed. p_pkt is not altered.
+**
+*******************************************************************************/
+BOOLEAN OBX_AddHttpHdr(BT_HDR *p_pkt, UINT8 *p_http, UINT16 len)
+{
+ return OBX_AddByteStrHdr(p_pkt, OBX_HI_HTTP, p_http, len);
+}
+
+
diff --git a/stack/obx/hdrs/obx_eunic.c b/stack/obx/hdrs/obx_eunic.c
new file mode 100644
index 0000000..6b5cb29
--- /dev/null
+++ b/stack/obx/hdrs/obx_eunic.c
@@ -0,0 +1,64 @@
+/*****************************************************************************
+**
+** Name: obx_eunic.c
+**
+** File: OBEX Headers Encode Utility functions
+** - Unicode functions
+**
+** Copyright (c) 2003-2004, WIDCOMM Inc., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include "bt_target.h"
+#include "obx_api.h"
+
+
+/*******************************************************************************
+**
+** Function OBX_AddNameHdr
+**
+** Description This function is called to add an OBEX Name header
+** to an OBEX packet.
+**
+** Returns TRUE, if the header is added successfully.
+** FALSE, if the operation failed. p_pkt is not altered.
+**
+*******************************************************************************/
+BOOLEAN OBX_AddNameHdr(BT_HDR *p_pkt, UINT16 *p_name, UINT16 len)
+{
+ return OBX_AddUnicodeHdr(p_pkt, OBX_HI_NAME, p_name, len);
+}
+
+/*******************************************************************************
+**
+** Function OBX_AddDescrHdr
+**
+** Description This function is called to add an OBEX Description header
+** to an OBEX packet.
+**
+** Returns TRUE, if the header is added successfully.
+** FALSE, if the operation failed. p_pkt is not altered.
+**
+*******************************************************************************/
+BOOLEAN OBX_AddDescrHdr(BT_HDR *p_pkt, UINT16 *p_descr, UINT16 len)
+{
+ return OBX_AddUnicodeHdr(p_pkt, OBX_HI_DESCRIPTION, p_descr, len);
+}
+
+/*******************************************************************************
+**
+** Function OBX_AddDestNameHdr
+**
+** Description This function is called to add an OBEX DestName header
+** to an OBEX packet.
+**
+** Returns TRUE, if the header is added successfully.
+** FALSE, if the operation failed. p_pkt is not altered.
+**
+*******************************************************************************/
+BOOLEAN OBX_AddDestNameHdr(BT_HDR *p_pkt, UINT16 *p_dest, UINT16 len)
+{
+ return OBX_AddUnicodeHdr(p_pkt, OBX_HI_DEST_NAME, p_dest, len);
+}
+
+
diff --git a/stack/obx/hdrs/obx_eutf.c b/stack/obx/hdrs/obx_eutf.c
new file mode 100644
index 0000000..b298500
--- /dev/null
+++ b/stack/obx/hdrs/obx_eutf.c
@@ -0,0 +1,111 @@
+/*****************************************************************************
+**
+** Name: obx_eutf.c
+**
+** File: OBEX Headers Encode Utility functions
+** - Unicode conversion functions
+**
+** Copyright (c) 2003-2005, WIDCOMM Inc., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include <string.h>
+#include "bt_target.h"
+#include "gki.h"
+#include "obx_api.h"
+
+
+/*******************************************************************************
+**
+** Function OBX_AddUtf8NameHdr
+**
+** Description This function is called to add an OBEX Name header
+** to an OBEX packet.
+**
+** Returns TRUE, if the header is added successfully.
+** FALSE, if the operation failed. p_pkt is not altered.
+**
+*******************************************************************************/
+BOOLEAN OBX_AddUtf8NameHdr(BT_HDR *p_pkt, UINT8 *p_name)
+{
+ BOOLEAN status = FALSE;
+ UINT16 utf16_len = 0;
+ UINT16 *p_utf16 = NULL;
+
+ if (p_name)
+ {
+ utf16_len = strlen((char *)p_name) * 2 + 2;
+ p_utf16 = (UINT16 *)GKI_getbuf(utf16_len);
+ }
+
+ if (p_utf16)
+ utf16_len = utfc_8_to_16(p_utf16, utf16_len, p_name);
+ else
+ utf16_len = 0;
+
+ status = OBX_AddUnicodeHdr(p_pkt, OBX_HI_NAME, p_utf16, utf16_len);
+
+ if (p_utf16)
+ GKI_freebuf(p_utf16);
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function OBX_AddUtf8DescrHdr
+**
+** Description This function is called to add an OBEX Description header
+** to an OBEX packet.
+**
+** Returns TRUE, if the header is added successfully.
+** FALSE, if the operation failed. p_pkt is not altered.
+**
+*******************************************************************************/
+BOOLEAN OBX_AddUtf8DescrHdr(BT_HDR *p_pkt, UINT8 *p_descr)
+{
+ BOOLEAN status = FALSE;
+ UINT16 utf16_len;
+ UINT16 *p_utf16;
+
+ utf16_len = strlen((char *)p_descr) * 2 + 2;
+ p_utf16 = (UINT16 *)GKI_getbuf(utf16_len);
+ if(p_utf16)
+ {
+ utf16_len = utfc_8_to_16(p_utf16, utf16_len, p_descr);
+ status = OBX_AddUnicodeHdr(p_pkt, OBX_HI_DESCRIPTION, p_utf16, utf16_len);
+ GKI_freebuf(p_utf16);
+ }
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function OBX_AddUtf8DestNameHdr
+**
+** Description This function is called to add an OBEX DestName header
+** to an OBEX packet.
+**
+** Returns TRUE, if the header is added successfully.
+** FALSE, if the operation failed. p_pkt is not altered.
+**
+*******************************************************************************/
+BOOLEAN OBX_AddUtf8DestNameHdr(BT_HDR *p_pkt, UINT8 *p_dest)
+{
+ BOOLEAN status = FALSE;
+ UINT16 utf16_len;
+ UINT16 *p_utf16;
+
+ utf16_len = strlen((char *)p_dest) * 2 + 2;
+ p_utf16 = (UINT16 *)GKI_getbuf(utf16_len);
+ if(p_utf16)
+ {
+ utf16_len = utfc_8_to_16(p_utf16, utf16_len, p_dest);
+ status = OBX_AddUnicodeHdr(p_pkt, OBX_HI_DEST_NAME, p_utf16, utf16_len);
+ GKI_freebuf(p_utf16);
+ }
+ return status;
+}
+
+
+
diff --git a/stack/obx/hdrs/obx_ewchar.c b/stack/obx/hdrs/obx_ewchar.c
new file mode 100644
index 0000000..2025baa
--- /dev/null
+++ b/stack/obx/hdrs/obx_ewchar.c
@@ -0,0 +1,100 @@
+/*****************************************************************************
+**
+** Name: obx_ewchar.c
+**
+** File: OBEX Headers Encode Utility functions
+** - Unicode conversion functions
+**
+** Copyright (c) 2003-2005, WIDCOMM Inc., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include <string.h>
+#include "bt_target.h"
+#include "gki.h"
+#include "obx_api.h"
+
+/*******************************************************************************
+**
+** Function OBX_AddAsciiNameHdr
+**
+** Description This function is called to add an OBEX Name header
+** to an OBEX packet.
+**
+** Returns TRUE, if the header is added successfully.
+** FALSE, if the operation failed. p_pkt is not altered.
+**
+*******************************************************************************/
+BOOLEAN OBX_AddAsciiNameHdr(BT_HDR *p_pkt, char *p_name)
+{
+ BOOLEAN status;
+ UINT16 len = 0;
+ UINT16 *p_unicode = NULL;
+
+ if(p_name)
+ {
+ len = strlen(p_name) + 1;
+ p_unicode = (UINT16 *)GKI_getbuf((UINT16)(len*2));
+ }
+
+ if(p_unicode)
+ len = OBX_CharToWchar(p_unicode, p_name, len);
+ else
+ len = 0;
+
+ status = OBX_AddUnicodeHdr(p_pkt, OBX_HI_NAME, p_unicode, len);
+
+ if(p_unicode)
+ GKI_freebuf(p_unicode);
+ return status;
+}
+
+
+/*******************************************************************************
+**
+** Function OBX_AddAsciiDescrHdr
+**
+** Description This function is called to add an OBEX Description header
+** to an OBEX packet.
+**
+** Returns TRUE, if the header is added successfully.
+** FALSE, if the operation failed. p_pkt is not altered.
+**
+*******************************************************************************/
+BOOLEAN OBX_AddAsciiDescrHdr(BT_HDR *p_pkt, char *p_descr)
+{
+ BOOLEAN status;
+ UINT16 len = strlen(p_descr) + 1;
+ UINT16 *p_unicode = (UINT16 *)GKI_getbuf((UINT16)(len*2));
+
+ len = OBX_CharToWchar(p_unicode, p_descr, len);
+ status = OBX_AddUnicodeHdr(p_pkt, OBX_HI_DESCRIPTION, p_unicode, len);
+ GKI_freebuf(p_unicode);
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function OBX_AddAsciiDestNameHdr
+**
+** Description This function is called to add an OBEX DestName header
+** to an OBEX packet.
+**
+** Returns TRUE, if the header is added successfully.
+** FALSE, if the operation failed. p_pkt is not altered.
+**
+*******************************************************************************/
+BOOLEAN OBX_AddAsciiDestNameHdr(BT_HDR *p_pkt, char *p_dest)
+{
+ BOOLEAN status;
+ UINT16 len = strlen(p_dest) + 1;
+ UINT16 *p_unicode = (UINT16 *)GKI_getbuf((UINT16)(len*2));
+
+ len = OBX_CharToWchar(p_unicode, p_dest, len);
+ status = OBX_AddUnicodeHdr(p_pkt, OBX_HI_DEST_NAME, p_unicode, len);
+ GKI_freebuf(p_unicode);
+ return status;
+}
+
+
+
diff --git a/stack/obx/hdrs/obx_gen.c b/stack/obx/hdrs/obx_gen.c
new file mode 100644
index 0000000..9b25e04
--- /dev/null
+++ b/stack/obx/hdrs/obx_gen.c
@@ -0,0 +1,896 @@
+/*****************************************************************************
+**
+** Name: obx_gen.c
+**
+** File: OBEX Headers Utility functions
+** - common/generic functions
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include <string.h>
+
+#include "bt_target.h"
+#include "wcassert.h"
+#include "obx_api.h"
+#include "gki.h"
+#include "obx_int.h"
+
+const UINT8 obx_hdr_start_offset[] =
+{
+ OBX_CONN_HDRS_OFFSET, /* OBX_CONNECT_REQ_EVT */
+ OBX_SESS_HDRS_OFFSET, /* OBX_SESSION_REQ_EVT */
+ OBX_DISCON_HDRS_OFFSET, /* OBX_DISCONNECT_REQ_EVT */
+ OBX_PUT_HDRS_OFFSET, /* OBX_PUT_REQ_EVT */
+ OBX_GET_HDRS_OFFSET, /* OBX_GET_REQ_EVT */
+ OBX_SETPATH_REQ_HDRS_OFFSET,/* OBX_SETPATH_REQ_EVT */
+ OBX_ABORT_HDRS_OFFSET, /* OBX_ABORT_REQ_EVT */
+ OBX_ACTION_HDRS_OFFSET, /* OBX_ACTION_REQ_EVT */
+ OBX_CONN_HDRS_OFFSET, /* OBX_CONNECT_RSP_EVT */
+ OBX_RESPONSE_HDRS_OFFSET, /* OBX_SESSION_RSP_EVT */
+ OBX_RESPONSE_HDRS_OFFSET, /* OBX_DISCONNECT_RSP_EVT */
+ OBX_RESPONSE_HDRS_OFFSET, /* OBX_PUT_RSP_EVT */
+ OBX_RESPONSE_HDRS_OFFSET, /* OBX_GET_RSP_EVT */
+ OBX_RESPONSE_HDRS_OFFSET, /* OBX_SETPATH_RSP_EVT */
+ OBX_RESPONSE_HDRS_OFFSET, /* OBX_ABORT_RSP_EVT */
+ OBX_RESPONSE_HDRS_OFFSET /* OBX_ACTION_RSP_EVT */
+};
+
+/*******************************************************************************
+**
+** Function obx_access_rsp_code
+**
+** Description This function is used to read/change response code
+**
+** Returns void.
+**
+*******************************************************************************/
+void obx_access_rsp_code(BT_HDR *p_pkt, UINT8 *p_rsp_code)
+{
+ UINT8 *p = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ if(*p_rsp_code == OBX_RSP_DEFAULT)
+ *p_rsp_code = *p;
+ else
+ *p = *p_rsp_code;
+}
+
+/*******************************************************************************
+**
+** Function obx_adjust_packet_len
+**
+** Description Adjust the packet length in the OBEX packet
+**
+** Returns void.
+**
+*******************************************************************************/
+void obx_adjust_packet_len(BT_HDR *p_pkt)
+{
+ UINT8 *p = (UINT8 *)(p_pkt + 1) + p_pkt->offset + 1;
+ UINT16_TO_BE_STREAM(p, p_pkt->len);
+}
+
+/*******************************************************************************
+**
+** Function obx_read_header_len
+**
+** Description ph is the beginning of an OBEX header
+**
+** Returns total length of the header
+**
+*******************************************************************************/
+UINT16 obx_read_header_len(UINT8 *ph)
+{
+ UINT16 len = 0;
+
+ /*
+ OBX_TRACE_DEBUG1( "obx_read_header_len: 0x%x", *ph);
+ */
+ switch(*ph&OBX_HI_TYPE_MASK)
+ {
+ case OBX_HI_TYPE_BYTE:
+ len = 2;
+ break;
+ case OBX_HI_TYPE_INT:
+ len = 5;
+ break;
+ case OBX_HI_TYPE_ARRAY:
+ case OBX_HI_TYPE_UNIC:
+ ph++;
+ BE_STREAM_TO_UINT16(len, ph);
+ break;
+ }
+ /*
+ OBX_TRACE_DEBUG1( "len:%d", len);
+ */
+ return len;
+}
+
+/*******************************************************************************
+**
+** Function obx_dup_pkt
+**
+** Description This function duplicate the OBEX message
+**
+** Returns BT_HDR *.
+**
+*******************************************************************************/
+BT_HDR * obx_dup_pkt(BT_HDR *p_pkt)
+{
+ BT_HDR *p_new;
+ UINT16 size = p_pkt->len + p_pkt->offset + BT_HDR_SIZE;
+
+ if (size < GKI_MAX_BUF_SIZE)
+ {
+ /* Use the largest general pool to allow challenge tags appendage */
+ p_new = (BT_HDR *)GKI_getbuf(GKI_MAX_BUF_SIZE);
+ }
+ else
+ {
+ p_new = (BT_HDR *) GKI_getpoolbuf(OBX_LRG_DATA_POOL_ID);
+ }
+
+ if (p_new)
+ memcpy(p_new, p_pkt, size );
+
+ return p_new;
+}
+
+
+/*******************************************************************************
+**
+** Function OBX_HdrInit
+**
+** Description This function is called to initialize an OBEX packet. This
+** function takes a GKI buffer and sets the offset in BT_HDR as
+** OBX_HDR_OFFSET, the len as 0. The layer_specific is set to the
+** length still available. This function compares the given
+** (pkt_size - BT_HDR_SIZE) with the peer MTU to get the lesser
+** of the two and set the layer_specific to
+** (lesser_size - OBX_HDR_OFFSET).
+** If composing a header for the CONNECT request (there is no
+** client handle yet), use OBX_HANDLE_NULL as the handle.
+**
+** If the pkt_size is larger than the largest public pool size,
+** GKI_MAX_BUF_SIZE, then an attempt to grab a buffer from the reserved OBX
+** data pool will be made.
+** Returns BT_HDR *.
+**
+*******************************************************************************/
+BT_HDR *OBX_HdrInit(tOBX_HANDLE handle, UINT16 pkt_size)
+{
+ UINT16 mtu = OBX_HandleToMtu(handle);
+ BT_HDR *p_pkt = NULL;
+ UINT16 buf_size;
+#if (BT_USE_TRACES == TRUE)
+ UINT16 req_size = pkt_size;
+#endif
+
+ WC_ASSERT(pkt_size > (BT_HDR_SIZE + OBX_HDR_OFFSET));
+
+ pkt_size -= BT_HDR_SIZE;
+ if(pkt_size > mtu )
+ pkt_size = mtu;
+ pkt_size += (BT_HDR_SIZE + OBX_HDR_OFFSET);
+
+ OBX_TRACE_DEBUG4( "OBX_HdrInit: checking req_size %d, pkt_size:%d, max:%d, offset:%d",
+ req_size, pkt_size, GKI_MAX_BUF_SIZE, OBX_HDR_OFFSET);
+ /* See if packet will fit in regular public pool */
+ if ((pkt_size) < GKI_MAX_BUF_SIZE)
+ {
+ p_pkt = (BT_HDR *) GKI_getbuf(pkt_size);
+ }
+ else /* Must use the reserved OBX buffer pool */
+ {
+ p_pkt = (BT_HDR *) GKI_getpoolbuf(OBX_LRG_DATA_POOL_ID);
+ if (!p_pkt)
+ {
+ OBX_TRACE_DEBUG1( "Out of Large buffers. Trying pkt_size:%d", GKI_MAX_BUF_SIZE);
+ p_pkt = (BT_HDR *) GKI_getbuf(GKI_MAX_BUF_SIZE);
+ }
+ }
+
+ if(p_pkt)
+ {
+ buf_size = GKI_get_buf_size(p_pkt);
+ buf_size -= BT_HDR_SIZE;
+ if(buf_size > mtu)
+ buf_size = mtu;
+
+ OBX_TRACE_DEBUG4( "OBX_HdrInit: req_size %d, pkt_size = %d, gki_size %d, buf_size %d",
+ req_size, pkt_size, GKI_get_buf_size(p_pkt), buf_size);
+
+ p_pkt->offset = OBX_HDR_OFFSET;
+ p_pkt->len = 0;
+ p_pkt->event = 0;
+
+ /* layer specific contains remaining space in packet */
+ p_pkt->layer_specific = buf_size - OBX_HDR_OFFSET ;
+ p_pkt->layer_specific -= 2;
+
+ OBX_TRACE_DEBUG2( "buf size: %d, ls:%d", buf_size, p_pkt->layer_specific);
+ }
+ else
+ {
+ OBX_TRACE_ERROR1("OBX_HdrInit: No buffers for size (%d)", pkt_size);
+ }
+
+ return p_pkt;
+}
+
+
+/*******************************************************************************
+**
+** Function OBX_Add1ByteHdr
+**
+** Description This function is called to add a header with type as UINT8
+** to an OBEX packet.
+**
+** Returns TRUE, if the header is added successfully.
+** FALSE, if the operation failed. p_pkt is not altered.
+**
+*******************************************************************************/
+BOOLEAN OBX_Add1ByteHdr(BT_HDR *p_pkt, UINT8 id, UINT8 data)
+{
+ UINT8 *p;
+ BOOLEAN status = FALSE;
+ UINT16 size = 2; /* total length added by this header - 1/hi & 1/hv */
+
+ if(p_pkt)
+ {
+ p = (UINT8 *)(p_pkt+1)+p_pkt->offset+p_pkt->len;
+ /* verify that the HI is of correct type and the remaining length in the packet is good */
+ if( ((id & OBX_HI_TYPE_MASK) == OBX_HI_TYPE_BYTE) && (p_pkt->layer_specific >= size) )
+ {
+ *p++ = id;
+ *p++ = data;
+
+ p_pkt->len += size;
+ p_pkt->layer_specific -= size;
+ status = TRUE;
+ }
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function OBX_Add4ByteHdr
+**
+** Description This function is called to add a header with type as UINT32
+** to an OBEX packet.
+**
+** Returns TRUE, if the header is added successfully.
+** FALSE, if the operation failed. p_pkt is not altered.
+**
+*******************************************************************************/
+BOOLEAN OBX_Add4ByteHdr(BT_HDR *p_pkt, UINT8 id, UINT32 data)
+{
+ UINT8 *p;
+ BOOLEAN status = FALSE;
+ UINT16 size = 5; /* total length added by this header - 1/hi & 4/hv */
+
+ if(p_pkt)
+ {
+ p = (UINT8 *)(p_pkt+1)+p_pkt->offset+p_pkt->len;
+ /* verify that the HI is of correct type and the remaining length in the packet is good */
+ if( ((id & OBX_HI_TYPE_MASK) == OBX_HI_TYPE_INT) && (p_pkt->layer_specific >= size) )
+ {
+ *p++ = id;
+ UINT32_TO_BE_STREAM(p, data);
+
+ p_pkt->len += size;
+ p_pkt->layer_specific -= size;
+ status = TRUE;
+ }
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function OBX_AddByteStrStart
+**
+** Description This function is called to get the address to the beginning of
+** the byte sequence for an OBEX header in an OBEX packet.
+**
+** Returns The address to add the byte sequence.
+**
+*******************************************************************************/
+UINT8 *OBX_AddByteStrStart(BT_HDR *p_pkt, UINT16 *p_len)
+{
+ UINT8 *p = (UINT8 *)(p_pkt + 1) + p_pkt->offset + p_pkt->len + 3;
+
+ WC_ASSERT(p_len);
+
+ if(*p_len > (p_pkt->layer_specific - 3) || *p_len == 0)
+ *p_len = p_pkt->layer_specific - 3;
+ return p;
+}
+
+/*******************************************************************************
+**
+** Function OBX_AddByteStrHdr
+**
+** Description This function is called to add a header with type as byte sequence
+** to an OBEX packet.
+**
+** Returns TRUE, if the header is added successfully.
+** FALSE, if the operation failed. p_pkt is not altered.
+**
+*******************************************************************************/
+BOOLEAN OBX_AddByteStrHdr(BT_HDR *p_pkt, UINT8 id, UINT8 *p_data, UINT16 len)
+{
+ UINT8 *p;
+ BOOLEAN status = FALSE;
+ UINT16 size = (len+3); /* total length added by this header - 1/hi & len+2/hv */
+
+ if(p_pkt)
+ {
+ p = (UINT8 *)(p_pkt+1)+p_pkt->offset+p_pkt->len;
+ /* verify that the HI is of correct type and the remaining length in the packet is good */
+ if( ((id & OBX_HI_TYPE_MASK) == OBX_HI_TYPE_ARRAY) && (p_pkt->layer_specific >= size) )
+ {
+ *p++ = id;
+ UINT16_TO_BE_STREAM(p, size);
+ if(p_data)
+ memcpy(p, p_data, len);
+
+ p_pkt->len += size;
+ p_pkt->layer_specific -= size;
+ status = TRUE;
+ }
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function OBX_AddUnicodeHdr
+**
+** Description This function is called to add a header with type as Unicode string
+** to an OBEX packet.
+**
+** Returns TRUE, if the header is added successfully.
+** FALSE, if the operation failed. p_pkt is not altered.
+**
+*******************************************************************************/
+BOOLEAN OBX_AddUnicodeHdr(BT_HDR *p_pkt, UINT8 id, UINT16 *p_data, UINT16 len)
+{
+ UINT8 *p;
+ BOOLEAN status = FALSE;
+ UINT16 size, xx;
+
+ if(p_pkt)
+ {
+ p = (UINT8 *)(p_pkt+1)+p_pkt->offset+p_pkt->len;
+ size = (len*OBX_UNICODE_SIZE + 3); /* total length added by this header - 1/hi & len*OBX_UNICODE_SIZE+2/hv */
+ OBX_TRACE_DEBUG4( "OBX_AddUnicodeHdr len: %d, size: %d, left: %d, id: 0x%x",
+ len, size, p_pkt->layer_specific, id );
+
+ /* verify that the HI is of correct type and the remaining length in the packet is good */
+ if( ((id & OBX_HI_TYPE_MASK) == OBX_HI_TYPE_UNIC) && (p_pkt->layer_specific >= size) )
+ {
+ *p++ = id;
+ UINT16_TO_BE_STREAM(p, size);
+ for(xx=0; xx<len; xx++)
+ {
+ UINT16_TO_BE_STREAM(p, *p_data);
+ p_data++;
+ }
+
+ p_pkt->len += size;
+ p_pkt->layer_specific -= size;
+ status = TRUE;
+ }
+ }
+
+ return status;
+}
+
+/* Alternate Body header functions: for non-blocking scenario */
+/*******************************************************************************
+**
+** Function OBX_AddBodyStart
+**
+** Description This function is called to get the address to the beginning of
+** the byte sequence for an OBEX body header in an OBEX packet.
+**
+** Returns The address to add body content.
+**
+*******************************************************************************/
+UINT8 *OBX_AddBodyStart(BT_HDR *p_pkt, UINT16 *p_len)
+{
+ UINT8 *p = (UINT8 *)(p_pkt + 1) + p_pkt->offset + p_pkt->len + 3;
+
+ WC_ASSERT(p_len);
+
+ if(*p_len > (p_pkt->layer_specific - 3) || *p_len == 0)
+ *p_len = p_pkt->layer_specific - 3;
+ return p;
+}
+
+/*******************************************************************************
+**
+** Function OBX_AddBodyEnd
+**
+** Description This function is called to add the HI and the length of HV of an
+** OBEX body header to an OBEX packet. If end is TRUE, HI is
+** OBX_HI_BODY_END. If FALSE, HI is OBX_HI_BODY. It is assumed that
+** the actual value of the body has been copied into the OBEX packet.
+**
+** Returns void
+**
+*******************************************************************************/
+void OBX_AddBodyEnd(BT_HDR *p_pkt, UINT8 *p, UINT16 len, BOOLEAN end)
+{
+ UINT8 id = (end)?OBX_HI_BODY_END:OBX_HI_BODY;
+ UINT8 *pb = (UINT8 *)(p_pkt + 1) + p_pkt->offset + p_pkt->len;
+ *pb++ = id;
+ len += 3; /* 1/hi, 2/hv_len */
+ UINT16_TO_BE_STREAM(pb, len);
+ p_pkt->layer_specific -= len;
+ p_pkt->len += len;
+}
+
+/*******************************************************************************
+**
+** Function OBX_AddTriplet
+**
+** Description This function is called to add a header with type as byte sequence
+** to an OBEX packet.
+**
+** Note: The byte sequence uses a Tag-Length-Value encoding scheme
+** These headers include: Application Parameters header
+** Authenticate Challenge header
+** Authenticate Response header
+**
+** Returns TRUE, if the header is added successfully.
+** FALSE, if the operation failed. p_pkt is not altered.
+**
+*******************************************************************************/
+BOOLEAN OBX_AddTriplet(BT_HDR *p_pkt, UINT8 id, tOBX_TRIPLET *p_triplet, UINT8 num)
+{
+ UINT8 *p = (UINT8 *)(p_pkt+1)+p_pkt->offset+p_pkt->len;
+ BOOLEAN status = FALSE;
+ UINT16 size = 3;/* 1/hi & len+2/hv */
+ UINT8 xx;
+
+ /* calculate the total length added by this header */
+ for(xx=0; xx< num; xx++)
+ size += (p_triplet[xx].len + 2);
+
+ /* verify that the HI is of correct type and the remaining length in the packet is good */
+ if( ((id & OBX_HI_TYPE_MASK) == OBX_HI_TYPE_ARRAY) && (p_pkt->layer_specific >= size) )
+ {
+ *p++ = id;
+ UINT16_TO_BE_STREAM(p, size);
+ for(xx=0; xx< num; xx++)
+ {
+ *p++ = p_triplet[xx].tag;
+ *p++ = p_triplet[xx].len;
+ memcpy(p, p_triplet[xx].p_array, p_triplet[xx].len);
+ p += p_triplet[xx].len;
+ }
+ p_pkt->len += size;
+ p_pkt->layer_specific -= size;
+ status = TRUE;
+ }
+
+ return status;
+}
+
+
+/*******************************************************************************
+**
+** Function OBX_CheckNext
+**
+** Description This function is called to check if the given OBEX packet
+** contains the specified header.
+**
+** Returns NULL, if the header is not in the OBEX packet.
+** The pointer to the specified header beginning from HI.
+**
+*******************************************************************************/
+UINT8 * OBX_CheckNext(BT_HDR *p_pkt, UINT8 *p_start, UINT8 id)
+{
+ UINT8 *p;
+ UINT8 *p_res = NULL;
+ UINT16 len, start, skip;
+ int remain;
+
+ if(p_pkt != NULL && p_start != NULL)
+ {
+ p = (UINT8 *)(p_pkt+1)+p_pkt->offset;
+ if(p_pkt->event <= OBX_MAX_OFFSET_IND)
+ {
+ start = obx_hdr_start_offset[p_pkt->event-1];
+ p++;
+ BE_STREAM_TO_UINT16(len, p);
+ remain = len - start;
+ p = p - 3 + start;
+
+ while(remain >0)
+ {
+ if(*p != id || p < p_start)
+ {
+ skip = obx_read_header_len(p);
+ p += skip;
+ /* Just in case this is a bad packet, make sure that remain is >= 0 */
+ if(skip && (remain > skip))
+ remain -= skip;
+ else
+ remain = 0;
+ }
+ else
+ {
+ p_res = p;
+ break;
+ }
+ }
+ }
+ }
+
+ if (p_pkt)
+ {
+ OBX_TRACE_DEBUG2( "OBX_CheckNext: remain: %d len:%d", remain, p_pkt->len);
+ }
+
+ return p_res;
+}
+
+
+/*******************************************************************************
+**
+** Function OBX_CheckHdr
+**
+** Description This function is called to check if the given OBEX packet
+** contains the specified header.
+**
+** Returns NULL, if the header is not in the OBEX packet.
+** The pointer to the specified header beginning from HI.
+**
+*******************************************************************************/
+UINT8 * OBX_CheckHdr(BT_HDR *p_pkt, UINT8 id)
+{
+ UINT8 *p;
+ UINT8 *p_res = NULL;
+ UINT16 len, start, skip;
+ int remain;
+
+ if(p_pkt != NULL)
+ {
+ p = (UINT8 *)(p_pkt+1)+p_pkt->offset;
+ if(p_pkt->event <= OBX_MAX_OFFSET_IND)
+ {
+ start = obx_hdr_start_offset[p_pkt->event-1];
+ p++;
+ BE_STREAM_TO_UINT16(len, p);
+ remain = len - start;
+ p = p - 3 + start;
+
+ while(remain >0)
+ {
+ if(*p != id)
+ {
+ skip = obx_read_header_len(p);
+ p += skip;
+ /* Just in case this is a bad packet, make sure that remain is >= 0 */
+ if(skip && (remain > skip))
+ remain -= skip;
+ else
+ remain = 0;
+ }
+ else
+ {
+ p_res = p;
+ break;
+ }
+ }
+ }
+ }
+
+ return p_res;
+}
+
+/*******************************************************************************
+**
+** Function OBX_ReadNumHdrs
+**
+** Description This function is called to check the number of headers in the
+** given OBEX packet
+**
+** Returns number of headers.
+**
+*******************************************************************************/
+UINT8 OBX_ReadNumHdrs(BT_HDR *p_pkt, UINT8 *p_num_body)
+{
+ UINT8 num_hdrs = 0, num_body = 0;
+ UINT8 *p;
+ UINT16 len, start, skip;
+ int remain = 0;
+
+ if(p_pkt != NULL)
+ {
+ p = (UINT8 *)(p_pkt+1)+p_pkt->offset;
+ if(p_pkt->event == 0)
+ {
+ /* GKI buffer just went through OBX_HdrInit; not processed by the state machine yet */
+ remain = len = p_pkt->len;
+ }
+ else if(p_pkt->event <= OBX_MAX_OFFSET_IND)
+ {
+ start = obx_hdr_start_offset[p_pkt->event-1];
+ p++;
+ BE_STREAM_TO_UINT16(len, p);
+ remain = len - start;
+ p = p - 3 + start;
+ }
+
+ while(remain >0)
+ {
+ num_hdrs++;
+ if(*p == OBX_HI_BODY || *p == OBX_HI_BODY_END)
+ num_body++;
+
+ skip = obx_read_header_len(p);
+ p += skip;
+ /* Just in case this is a bad packet, make sure that remain is >= 0 */
+ if(skip && (remain > skip))
+ remain -= skip;
+ else
+ remain = 0;
+
+ }
+ }
+ if (p_num_body)
+ *p_num_body = num_body;
+ return num_hdrs;
+}
+
+/*******************************************************************************
+**
+** Function OBX_ReadHdrLen
+**
+** Description This function is called to check the length of the specified
+** header in the given OBEX packet.
+**
+** Returns OBX_INVALID_HDR_LEN, if the header is not in the OBEX packet.
+** Otherwise the actual length of the header.
+**
+*******************************************************************************/
+UINT16 OBX_ReadHdrLen(BT_HDR *p_pkt, UINT8 id)
+{
+ UINT8 *p;
+ UINT16 len = OBX_INVALID_HDR_LEN;
+
+ if( (p = OBX_CheckHdr(p_pkt, id)) != NULL)
+ len = obx_read_header_len(p);
+
+ return len;
+}
+
+/*******************************************************************************
+**
+** Function OBX_Read1ByteHdr
+**
+** Description This function is called to get the UINT8 HV of the given HI
+** in the given OBEX packet.
+**
+** Returns TRUE, if the header is in the OBEX packet.
+** FALSE, otherwise.
+**
+*******************************************************************************/
+BOOLEAN OBX_Read1ByteHdr(BT_HDR *p_pkt, UINT8 id, UINT8 *p_data)
+{
+ BOOLEAN status = FALSE;
+ UINT8 *p_start = OBX_CheckHdr(p_pkt, id);
+
+ if(p_start)
+ {
+ *p_data = *(++p_start);
+ status = TRUE;
+ }
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function OBX_Read4ByteHdr
+**
+** Description This function is called to get the UINT32 HV of the given HI
+** in the given OBEX packet.
+**
+** Returns TRUE, if the header is in the OBEX packet.
+** FALSE, otherwise.
+**
+*******************************************************************************/
+BOOLEAN OBX_Read4ByteHdr(BT_HDR *p_pkt, UINT8 id, UINT32 *p_data)
+{
+ BOOLEAN status = FALSE;
+ UINT8 *p_start = OBX_CheckHdr(p_pkt, id);
+
+ if(p_start)
+ {
+ p_start++;
+ BE_STREAM_TO_UINT32(*p_data, p_start);
+ status = TRUE;
+ }
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function OBX_ReadByteStrHdr
+**
+** Description This function is called to get the byte sequence HV of the given
+** HI in the given OBEX packet.
+**
+** Returns TRUE, if the header is in the OBEX packet.
+** FALSE, otherwise.
+**
+*******************************************************************************/
+BOOLEAN OBX_ReadByteStrHdr(BT_HDR *p_pkt, UINT8 id, UINT8 **p_data, UINT16 *p_len, UINT8 next)
+{
+ BOOLEAN status = FALSE;
+ UINT8 *p_start = OBX_CheckHdr(p_pkt, id);
+
+ if(p_start)
+ {
+ next += 1;
+ while(next && (id == *p_start++))
+ {
+ next--;
+ BE_STREAM_TO_UINT16(*p_len, p_start);
+ if(next == 0)
+ {
+ status = TRUE;
+ *p_len -= 3; /* get rid of hi and hv_len */
+ *p_data = p_start;
+ }
+ else
+ p_start = p_start + *p_len - 3;
+ }
+ }
+ else
+ {
+ *p_len = 0;
+ }
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function OBX_ReadUnicodeHdr
+**
+** Description This function is called to get the Unicode HV of the given
+** HI in the given OBEX packet.
+**
+** Returns TRUE, if the header is in the OBEX packet.
+** FALSE, otherwise.
+**
+*******************************************************************************/
+BOOLEAN OBX_ReadUnicodeHdr(BT_HDR *p_pkt, UINT8 id, UINT16 *p_data, UINT16 *p_len)
+{
+ BOOLEAN status = FALSE;
+ UINT16 len, xx, max_len;
+ UINT8 *p_start = OBX_CheckHdr(p_pkt, id);
+
+ if(p_start)
+ {
+ max_len = *p_len;
+ p_start++; /* 1/hi*/
+ BE_STREAM_TO_UINT16(len, p_start);
+ len -= 3; /* 1/hi, 2/hv_len */
+ len /= OBX_UNICODE_SIZE; /* size in UINT16 */
+ /* only conver the provided size */
+ if( len > max_len)
+ len = max_len;
+ for(xx=0; xx<len; xx++)
+ {
+ BE_STREAM_TO_UINT16(*p_data, p_start);
+ p_data++;
+ }
+ *p_len = len;
+ status = TRUE;
+ max_len -= len;
+ while ( (p_start = OBX_CheckNext(p_pkt, p_start, id)) != NULL && (max_len > 0))
+ {
+ p_start++; /* 1/hi*/
+ BE_STREAM_TO_UINT16(len, p_start);
+ len -= 3; /* 1/hi, 2/hv_len */
+ len /= OBX_UNICODE_SIZE; /* size in UINT16 */
+ /* only conver the provided size */
+ if( len > max_len)
+ len = max_len;
+ for(xx=0; xx<len; xx++)
+ {
+ BE_STREAM_TO_UINT16(*p_data, p_start);
+ p_data++;
+ }
+ *p_len += len;
+ max_len -= len;
+ }
+ }
+ else
+ {
+ *p_len = 0;
+ }
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function OBX_ReadTriplet
+**
+** Description This function is called to get the Triplet HV of the given
+** HI in the given OBEX packet.
+**
+** Returns TRUE, if the header is in the OBEX packet.
+** FALSE, otherwise.
+**
+*******************************************************************************/
+BOOLEAN OBX_ReadTriplet(BT_HDR *p_pkt, UINT8 id, tOBX_TRIPLET *p_triplet, UINT8 *p_num)
+{
+ BOOLEAN status = FALSE;
+ UINT8 *p_start = OBX_CheckHdr(p_pkt, id);
+ UINT16 len;
+ UINT8 count = 0;
+
+ if(p_start)
+ {
+ p_start++; /* 1/hi*/
+ BE_STREAM_TO_UINT16(len, p_start);
+ len -= 3; /* 1/hi, 2/hv_len */
+ while(len && *p_num > count)
+ {
+ p_triplet[count].tag = *p_start++;
+ p_triplet[count].len = *p_start++;
+ OBX_TRACE_DEBUG3( "OBX_ReadTriplet: count: %d, tag: %x, len: %d",
+ count, p_triplet[count].tag, p_triplet[count].len);
+ p_triplet[count].p_array = p_start;
+ p_start += p_triplet[count].len;
+ if(len > (p_triplet[count].len + 2) )
+ len -= (p_triplet[count].len + 2);
+ else
+ len = 0;
+ count++;
+ }
+ status = TRUE;
+ }
+ *p_num = count;
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function OBX_ReadActionIdHdr
+**
+** Description This function is called to get the HV of the Action ID header
+** in the given OBEX packet.
+**
+** Returns TRUE, if the header is in the OBEX packet.
+** FALSE, otherwise.
+**
+*******************************************************************************/
+BOOLEAN OBX_ReadActionIdHdr(BT_HDR *p_pkt, UINT8 *p_data)
+{
+ BOOLEAN status = FALSE;
+ UINT8 *p_start = OBX_CheckHdr(p_pkt, OBX_HI_ACTION_ID);
+
+ if(p_start)
+ {
+ p_start++;
+ /* check for valid values: 0-2 */
+ /* do not allow 0x80 - 0xFF (vendor extention) for now. */
+ if (*p_start <= OBX_ACT_PERMISSION)
+ {
+ *p_data = *(p_start);
+ status = TRUE;
+ }
+ }
+ return status;
+}
diff --git a/stack/obx/hdrs/obx_wchar.c b/stack/obx/hdrs/obx_wchar.c
new file mode 100644
index 0000000..5364210
--- /dev/null
+++ b/stack/obx/hdrs/obx_wchar.c
@@ -0,0 +1,84 @@
+/*****************************************************************************
+**
+** Name: obx_wchar.c
+**
+** File: OBEX Headers Encode conversion Utility functions
+**
+** Copyright (c) 2003-2004, WIDCOMM Inc., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include "bt_target.h"
+#include "gki.h"
+#include "obx_api.h"
+
+/*******************************************************************************
+**
+** Function OBX_CharToWchar
+**
+** Description This function is called to convert ASCII to Unicode (UINT16).
+**
+** Returns the length.
+**
+*******************************************************************************/
+UINT16 OBX_CharToWchar (UINT16 *w_str, char* a_str, UINT16 w_size)
+{
+ UINT16 result = 0;
+ int size = w_size;
+
+ if (a_str == NULL || w_str == NULL)
+ return 0;
+
+ while (size > 0 && *a_str != '\0')
+ {
+ w_str[result++] = (UINT16) *a_str;
+ a_str++;
+ size--;
+ }
+
+ if (size > 0)
+ {
+ w_str[result] = 0;
+ }
+
+ return (result+1);
+}
+
+/*******************************************************************************
+**
+** Function OBX_WcharToChar
+**
+** Description This function is called to convert Unicode (UINT16) to ASCII.
+**
+** Returns void.
+**
+*******************************************************************************/
+void OBX_WcharToChar (char *a_str, UINT16* w_str, UINT16 a_size)
+{
+ UINT16 result = 0;
+ int size = a_size;
+
+ if (w_str == NULL || a_str == NULL)
+ return;
+
+ while (size > 0 && *w_str != 0)
+ {
+ if ((*w_str & ~0xff) != 0)
+ {
+ result = 0;
+ break;
+ }
+
+ a_str[result++] = (char) *w_str;
+ ++(w_str);
+ --size;
+ }
+
+ if(size)
+ a_str[result] = 0;
+
+ return;
+
+
+}
+
diff --git a/stack/obx/hdrs/utfc.c b/stack/obx/hdrs/utfc.c
new file mode 100644
index 0000000..d59733d
--- /dev/null
+++ b/stack/obx/hdrs/utfc.c
@@ -0,0 +1,245 @@
+/*****************************************************************************
+**
+** Name: utfc.c
+**
+** Description: UTF conversion utilities.
+**
+** Copyright (c) 2003-2004, WIDCOMM Inc., All Rights Reserved.
+**
+*****************************************************************************/
+
+#include <string.h>
+#include "bt_target.h"
+#include "utfc.h"
+
+/* Based on code from Unicode, Inc:
+ *
+ * Copyright 2001-2003 Unicode, Inc.
+ *
+ * Limitations on Rights to Redistribute This Code
+ *
+ * Unicode, Inc. hereby grants the right to freely use the information
+ * supplied in this file in the creation of products supporting the
+ * Unicode Standard, and to make copies of this file in any form
+ * for internal or external distribution as long as this notice
+ * remains attached.
+ */
+
+/*******************************************************************************
+** Constants
+*******************************************************************************/
+
+#define UTFC_8_MASK 0xBF
+#define UTFC_8_MARK 0x80
+
+#define UTFC_SUR_HIGH_START 0xD800
+#define UTFC_SUR_HIGH_END 0xDBFF
+#define UTFC_SUR_LOW_START 0xDC00
+#define UTFC_SUR_LOW_END 0xDFFF
+
+/* Lookup table for length of UTF-8 byte sequence based on upper four bits
+** of first byte. Illegal values give length zero.
+*/
+static const UINT8 utfc_8_seq_len[] = {1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 2, 2, 3, 4};
+
+/* Magic values subtracted from a buffer value during UTF-8 conversion.
+** This table contains as many values as there might be trailing bytes
+** in a UTF-8 sequence.
+**/
+static const UINT32 utfc_8_offset[] = {0x00000000, 0x00003080,
+ 0x000E2080, 0x03C82080};
+
+static const UINT8 utfc_8_first_byte[] = {0x00, 0x00, 0xC0, 0xE0, 0xF0};
+
+/*******************************************************************************
+**
+** Function utfc_16_to_8
+**
+** Description Convert a UTF-16 array to a null-terminated UTF-8 string.
+** Illegal characters are skipped.
+**
+** Returns Length of UTF-8 string in bytes.
+**
+*******************************************************************************/
+UINT16 utfc_16_to_8(UINT8 *p_utf8, UINT16 utf8_len, UINT16 *p_utf16, UINT16 utf16_len)
+{
+ UINT32 ch, ch2;
+ UINT16 len = 0;
+ UINT8 seq_len;
+
+ /* sanity check destination buffer len */
+ if (utf8_len == 0)
+ {
+ /* set null */
+ *p_utf8 = 0;
+ return len;
+ }
+
+ /* save space for null */
+ utf8_len--;
+
+ while (utf16_len-- > 0)
+ {
+ ch = (UINT32) *p_utf16++;
+
+ /* if we have a surrogate pair, convert to UTF-32 first */
+ if (ch >= UTFC_SUR_HIGH_START && ch <= UTFC_SUR_HIGH_END)
+ {
+ /* if not enough characters we're done */
+ if (utf16_len == 0)
+ {
+ break;
+ }
+
+ /* get next character */
+ ch2 = *p_utf16++;
+ utf16_len--;
+
+ /* if it's a low surrogate, convert to UTF-32 */
+ if (ch2 >= UTFC_SUR_LOW_START && ch2 <= UTFC_SUR_LOW_END)
+ {
+ ch = ((ch - UTFC_SUR_HIGH_START) << 10) +
+ (ch2 - UTFC_SUR_LOW_START) + 0x00010000;
+ }
+ else
+ {
+ /* illegal UTF-16 sequence, skip it */
+ continue;
+ }
+ }
+
+ /* Figure out how many bytes the result will require */
+ if (ch < 0x00000080)
+ seq_len = 1;
+ else if (ch < 0x00000800)
+ seq_len = 2;
+ else if (ch < 0x00010000)
+ seq_len = 3;
+ else
+ seq_len = 4;
+
+ /* if sequence doesn't fit we're done */
+ if (utf8_len < len + seq_len)
+ {
+ break;
+ }
+
+ /* build UTF-8 sequence */
+ switch (seq_len)
+ { /* note: everything falls through. */
+ case 4: p_utf8[3] = (UINT8) ((ch | UTFC_8_MARK) & UTFC_8_MASK); ch >>= 6;
+ case 3: p_utf8[2] = (UINT8) ((ch | UTFC_8_MARK) & UTFC_8_MASK); ch >>= 6;
+ case 2: p_utf8[1] = (UINT8) ((ch | UTFC_8_MARK) & UTFC_8_MASK); ch >>= 6;
+ case 1: p_utf8[0] = (UINT8) (ch | utfc_8_first_byte[seq_len]);
+ }
+
+ /* converted value is a null we're done */
+ if (*p_utf8 == 0)
+ {
+ break;
+ }
+
+ p_utf8 += seq_len;
+ len += seq_len;
+ }
+
+ /* set null */
+ *p_utf8 = 0;
+
+ return len;
+}
+
+/*******************************************************************************
+**
+** Function utfc_8_to_16
+**
+** Description Convert a null-terminated UTF-8 string to a UTF-16 array.
+** Illegal characters are skipped. The UTF-16 array is
+** appended with a zero (null) character.
+**
+** Returns Length of UTF-16 array including null character.
+**
+*******************************************************************************/
+UINT16 utfc_8_to_16(UINT16 *p_utf16, UINT16 utf16_len, UINT8 *p_utf8)
+{
+ UINT32 ch;
+ UINT8 *p_end;
+ UINT16 *p;
+ UINT8 seq_len;
+
+ /* sanity check destination buffer len */
+ if (utf16_len == 0)
+ {
+ *p_utf16 = 0;
+ return 0;
+ }
+
+ /* save space for null */
+ utf16_len--;
+
+ p = p_utf16;
+ p_end = (UINT8 *) p_utf8 + strlen((char *) p_utf8);
+
+ while (*p_utf8)
+ {
+ /* get sequence length; skip if illegal */
+ if ((seq_len = utfc_8_seq_len[*p_utf8 >> 4]) == 0)
+ {
+ p_utf8++;
+ continue;
+ }
+
+ /* make sure sequence doesn't extend past end of UTF-8 buffer */
+ if (p_utf8 + seq_len > p_end)
+ {
+ break;
+ }
+
+ /* construct UTF-32 character from sequence */
+ ch = 0;
+ switch (seq_len)
+ { /* note: everything falls through. */
+ case 4: ch += *p_utf8++; ch <<= 6;
+ case 3: ch += *p_utf8++; ch <<= 6;
+ case 2: ch += *p_utf8++; ch <<= 6;
+ case 1: ch += *p_utf8++;
+ }
+ ch -= utfc_8_offset[seq_len - 1];
+
+ if (ch <= 0x0000FFFF)
+ {
+ /* UTF-16 surrogate values are illegal in UTF-32 */
+ if (ch >= UTFC_SUR_HIGH_START && ch <= UTFC_SUR_LOW_END)
+ {
+ continue;
+ }
+
+ /* make sure fits */
+ if (p - p_utf16 == utf16_len)
+ {
+ break;
+ }
+
+ *p++ = (UINT16) ch;
+ }
+ else if (ch < 0x0010FFFF)
+ {
+ /* make sure fits */
+ if ((p - p_utf16) == (utf16_len - 1))
+ {
+ break;
+ }
+
+ ch -= 0x00010000;
+ *p++ = (UINT16) ((ch >> 10) + UTFC_SUR_HIGH_START);
+ *p++ = (UINT16) ((ch & 0x000003FF) + UTFC_SUR_LOW_START);
+ }
+ }
+
+ /* set null */
+ *p++ = 0;
+
+ return (UINT16) (p - p_utf16);
+}
+
diff --git a/stack/obx/obx_cact.c b/stack/obx/obx_cact.c
new file mode 100644
index 0000000..62998bd
--- /dev/null
+++ b/stack/obx/obx_cact.c
@@ -0,0 +1,1103 @@
+/*****************************************************************************
+**
+** Name: obx_cact.c
+**
+** File: OBEX Client State Machine Action Functions
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include <string.h>
+#include "bt_target.h"
+#include "obx_int.h"
+#include "btm_api.h"
+
+const tOBX_EVENT obx_cl_state_2_event_map[] =
+{
+ OBX_DISCONNECT_RSP_EVT, /* OBX_CS_NOT_CONNECTED */
+ OBX_SESSION_RSP_EVT, /* OBX_CS_SESSION_REQ_SENT */
+ OBX_CONNECT_RSP_EVT, /* OBX_CS_CONNECT_REQ_SENT */
+ OBX_NULL_EVT, /* OBX_CS_UNAUTH */
+ OBX_ABORT_RSP_EVT, /* OBX_CS_CONNECTED */
+ OBX_DISCONNECT_RSP_EVT, /* OBX_CS_DISCNT_REQ_SENT */
+ OBX_NULL_EVT, /* OBX_CS_OP_UNAUTH */
+ OBX_SETPATH_RSP_EVT, /* OBX_CS_SETPATH_REQ_SENT */
+ OBX_ACTION_RSP_EVT, /* OBX_CS_ACTION_REQ_SENT */
+ OBX_ABORT_RSP_EVT, /* OBX_CS_ABORT_REQ_SENT */
+ OBX_PUT_RSP_EVT, /* OBX_CS_PUT_REQ_SENT */
+ OBX_GET_RSP_EVT, /* OBX_CS_GET_REQ_SENT */
+ OBX_PUT_RSP_EVT, /* OBX_CS_PUT_TRANSACTION */
+ OBX_GET_RSP_EVT, /* OBX_CS_GET_TRANSACTION */
+ OBX_PUT_RSP_EVT, /* OBX_CS_PUT_SRM */
+ OBX_GET_RSP_EVT /* OBX_CS_GET_SRM */
+};
+
+/*******************************************************************************
+** Function obx_ca_close_sess_req
+** Description send close session request
+*******************************************************************************/
+BT_HDR * obx_ca_close_sess_req(tOBX_CL_CB *p_cb)
+{
+ BT_HDR *p_req;
+ UINT8 *p;
+ UINT8 num_trip = 0;
+ tOBX_TRIPLET triplet[4];
+ UINT8 data[2];
+
+ p_req = OBX_HdrInit(OBX_HANDLE_NULL, OBX_MIN_MTU);
+ p = (UINT8 *) (p_req + 1) + p_req->offset;
+ /* Session request packet always has the final bit set */
+ *p++ = (OBX_REQ_SESSION | OBX_FINAL);
+ p_req->len = 3;
+ p = data;
+
+ /* add session opcode */
+ triplet[num_trip].tag = OBX_TAG_SESS_PARAM_SESS_OP;
+ triplet[num_trip].len = OBX_LEN_SESS_PARAM_SESS_OP;
+ triplet[num_trip].p_array = p;
+ *p = OBX_SESS_OP_CLOSE;
+ p += OBX_LEN_SESS_PARAM_SESS_OP;
+ num_trip++;
+
+ /* add session id */
+ triplet[num_trip].tag = OBX_TAG_SESS_PARAM_SESS_ID;
+ triplet[num_trip].len = OBX_SESSION_ID_SIZE;
+ triplet[num_trip].p_array = p_cb->sess_info;
+ num_trip++;
+
+ OBX_AddTriplet(p_req, OBX_HI_SESSION_PARAM, triplet, num_trip);
+ /* adjust the packet len */
+ p = (UINT8 *) (p_req + 1) + p_req->offset + 1;
+ UINT16_TO_BE_STREAM(p, p_req->len);
+ p_req->event = OBX_SESSION_REQ_EVT;
+ p_cb->sess_st = OBX_SESS_CLOSE;
+ OBX_TRACE_DEBUG2("obx_ca_close_sess_req shandle:0x%x, sess_st:%d", p_cb->ll_cb.comm.handle, p_cb->sess_st);
+ return p_req;
+}
+
+/*******************************************************************************
+** Function obx_ca_connect_req
+** Description send connect request
+*******************************************************************************/
+void obx_ca_connect_req(tOBX_CL_CB *p_cb, BT_HDR *p_pkt)
+{
+ UINT8 msg[OBX_HDR_OFFSET + OBX_MAX_CONN_HDR_EXTRA];
+ UINT8 *p = msg;
+
+ /* Connect request packet always has the final bit set */
+ *p++ = (OBX_REQ_CONNECT | OBX_FINAL);
+ p += OBX_PKT_LEN_SIZE;
+
+ *p++ = OBX_VERSION;
+ *p++ = OBX_CONN_FLAGS;
+ UINT16_TO_BE_STREAM(p, p_cb->ll_cb.port.rx_mtu);
+
+ /* add session sequence number, if session is active */
+ if (p_cb->sess_st == OBX_SESS_ACTIVE)
+ {
+ *p++ = OBX_HI_SESSION_SN;
+ *p++ = p_cb->ssn;
+ }
+ if (p_cb->srm)
+ {
+ p_cb->srm = OBX_SRM_ENABLE;
+ }
+
+ /* IrOBEX spec forbids connection ID in Connect Request */
+ p_pkt = obx_cl_prepend_msg(p_cb, p_pkt, msg, (UINT16)(p - msg) );
+
+ p_pkt->event = OBX_CONNECT_REQ_EVT;
+ obx_csm_event(p_cb, OBX_CONNECT_REQ_CEVT, p_pkt);
+}
+
+/*******************************************************************************
+** Function obx_ca_state
+** Description change state
+*******************************************************************************/
+tOBX_CL_STATE obx_ca_state(tOBX_CL_CB *p_cb, BT_HDR *p_pkt)
+{
+ /* p_pkt should be NULL here */
+ return p_cb->next_state;
+}
+
+/*******************************************************************************
+** Function obx_ca_start_timer
+** Description start timer
+*******************************************************************************/
+tOBX_CL_STATE obx_ca_start_timer(tOBX_CL_CB *p_cb, BT_HDR *p_pkt)
+{
+ if (p_pkt)
+ GKI_freebuf(p_pkt);
+ obx_start_timer(&p_cb->ll_cb.comm);
+ return OBX_CS_NULL;
+}
+
+/*******************************************************************************
+** Function obx_ca_connect_ok
+** Description process the connect OK response from server
+*******************************************************************************/
+tOBX_CL_STATE obx_ca_connect_ok(tOBX_CL_CB *p_cb, BT_HDR *p_pkt)
+{
+ UINT8 *p;
+ tOBX_EVT_PARAM param; /* The event parameter. */
+
+ if (p_cb->sess_st == OBX_SESS_ACTIVE)
+ {
+ /* reliable session was established - need to report the session event first */
+ p = &p_cb->sess_info[OBX_SESSION_INFO_ID_IDX];
+ UINT32_TO_BE_STREAM(p, p_cb->conn_id);
+ param.sess.p_sess_info= p_cb->sess_info;
+ param.sess.sess_st = p_cb->sess_st;
+ param.sess.nssn = p_cb->ssn;
+ param.sess.obj_offset = 0;
+ p = &p_cb->sess_info[OBX_SESSION_INFO_MTU_IDX];
+ UINT16_TO_BE_STREAM(p, p_cb->param.conn.mtu);
+ param.sess.sess_op = OBX_SESS_OP_CREATE;
+ (*p_cb->p_cback)(p_cb->ll_cb.comm.handle, OBX_SESSION_RSP_EVT, p_cb->rsp_code, param, NULL);
+ }
+ return obx_ca_notify(p_cb, p_pkt);
+}
+
+/*******************************************************************************
+** Function obx_ca_session_ok
+** Description process the session OK response from server
+*******************************************************************************/
+tOBX_CL_STATE obx_ca_session_ok(tOBX_CL_CB *p_cb, BT_HDR *p_pkt)
+{
+ tOBX_TRIPLET triplet[OBX_MAX_SESS_PARAM_TRIP];
+ UINT8 num = OBX_MAX_SESS_PARAM_TRIP;
+ UINT8 *p_nonce = NULL, *p_addr = NULL, *p_sess_id = NULL;
+ UINT8 *p, *p_cl_nonce;
+ UINT8 ind, nonce_len = 0;
+ UINT8 ind_sess_id;
+ BD_ADDR cl_addr;
+ tOBX_STATUS status = OBX_SUCCESS;
+ UINT8 nssn;
+#if (BT_USE_TRACES == TRUE)
+ tOBX_SESS_ST old_sess_st = p_cb->sess_st;
+#endif
+ tOBX_SESS_OP sess_op = OBX_SESS_OP_SET_TIME;
+ tOBX_CL_STATE new_state = OBX_CS_NULL;
+ tOBX_CL_EVENT sm_evt = OBX_BAD_SM_EVT;
+ UINT32 obj_offset = p_cb->param.sess.obj_offset;
+ UINT32 timeout = p_cb->param.sess.timeout;
+ tOBX_EVT_PARAM param; /* The event parameter. */
+ UINT8 dropped = 0;
+
+ OBX_TRACE_DEBUG4("obx_ca_session_ok sess_st: %d ssn:%d obj_offset:%d prev_state:%d", p_cb->sess_st, p_cb->ssn, obj_offset, p_cb->prev_state);
+ OBX_ReadTriplet(p_pkt, OBX_HI_SESSION_PARAM, triplet, &num);
+ obx_read_timeout (triplet, num, &timeout, &p_cb->sess_info[OBX_SESSION_INFO_TO_IDX]);
+ p_cb->param.sess.timeout = timeout;
+ if (p_cb->sess_st == OBX_SESS_SUSPEND)
+ {
+ p_cb->sess_st = OBX_SESS_SUSPENDED;
+ sess_op = OBX_SESS_OP_SUSPEND;
+ p_cb->sess_info[OBX_SESSION_INFO_SRM_IDX] = p_cb->srm;
+ nssn = p_cb->ssn;
+ /* send a tx_empty event to close port */
+ sm_evt = OBX_TX_EMPTY_CEVT;
+ OBX_TRACE_DEBUG2("suspend saved st:%d, srm:0x%x", p_cb->sess_info[OBX_SESSION_INFO_ST_IDX], p_cb->sess_info[OBX_SESSION_INFO_SRM_IDX]);
+ }
+ else if (p_cb->sess_st == OBX_SESS_CLOSE)
+ {
+ sess_op = OBX_SESS_OP_CLOSE;
+ p_cb->sess_st = OBX_SESS_NONE;
+ /* send a tx_empty event to close port */
+ sm_evt = OBX_TX_EMPTY_CEVT;
+ }
+ else if (num)
+ {
+ ind_sess_id = obx_read_triplet(triplet, num, OBX_TAG_SESS_PARAM_SESS_ID);
+ if ((ind_sess_id != num) && (triplet[ind_sess_id].len == OBX_SESSION_ID_SIZE))
+ {
+ p_sess_id = triplet[ind_sess_id].p_array;
+ }
+ switch (p_cb->sess_st)
+ {
+ case OBX_SESS_CREATE:
+ sess_op = OBX_SESS_OP_CREATE;
+ status = OBX_BAD_PARAMS;
+ ind = obx_read_triplet(triplet, num, OBX_TAG_SESS_PARAM_ADDR);
+ if ((ind != num) && (triplet[ind].len == BD_ADDR_LEN))
+ {
+ p_addr = triplet[ind].p_array;
+ }
+ ind = obx_read_triplet(triplet, num, OBX_TAG_SESS_PARAM_NONCE);
+ if ((ind != num) && (triplet[ind].len >= OBX_MIN_NONCE_SIZE) && (triplet[ind].len <= OBX_NONCE_SIZE))
+ {
+ p_nonce = triplet[ind].p_array;
+ nonce_len = triplet[ind].len;
+ }
+
+ if (p_nonce && p_addr && p_sess_id)
+ {
+ OBX_TRACE_DEBUG0("verify session id");
+ BTM_GetLocalDeviceAddr (cl_addr);
+ p_cl_nonce = &p_cb->sess_info[OBX_SESSION_ID_SIZE];
+ p = p_cl_nonce;
+ UINT32_TO_BE_STREAM(p, p_cb->nonce);
+ /* calculate client copy of session id */
+ obx_session_id (p_cb->sess_info, cl_addr, p_cl_nonce, OBX_LOCAL_NONCE_SIZE, p_addr, p_nonce, nonce_len);
+ obxu_dump_hex (p_cb->sess_info, "cl sess id", OBX_SESSION_ID_SIZE);
+ obxu_dump_hex (p_sess_id, "sr sess id", OBX_SESSION_ID_SIZE);
+ /* verify that the server copy is the same */
+ if (memcmp (p_sess_id, p_cb->sess_info, OBX_SESSION_ID_SIZE) == 0)
+ {
+ p_cb->sess_st = OBX_SESS_ACTIVE;
+ p_cb->ssn = 0;
+ /* do we want a timer here */
+ status = OBX_SUCCESS;
+ OBX_TRACE_DEBUG0("freeing received packet");
+ GKI_freebuf (p_pkt) ;
+ p_pkt = p_cb->p_next_req;
+ p_cb->p_next_req = NULL;
+ obx_ca_connect_req (p_cb, p_pkt);
+ /*
+ p_cb->param.sess.p_sess_info= p_cb->sess_info;
+ p_cb->param.sess.sess_st = p_cb->sess_st;
+ p_cb->param.sess.nssn = p_cb->ssn;
+ p_cb->param.sess.sess_op = sess_op;
+ (*p_cb->p_cback)(p_cb->ll_cb.comm.handle, OBX_SESSION_RSP_EVT, p_cb->rsp_code, p_cb->param, NULL);
+ */
+ return new_state;
+ }
+ }
+ break;
+
+ case OBX_SESS_RESUME:
+ status = OBX_BAD_PARAMS;
+ dropped = p_cb->sess_info[OBX_SESSION_INFO_ST_IDX] & OBX_CL_STATE_DROP;
+ ind = obx_read_triplet(triplet, num, OBX_TAG_SESS_PARAM_NSEQNUM);
+ if ((ind == num) || (triplet[ind].len != 1))
+ {
+ OBX_TRACE_ERROR0("RESUME:do not have valid NSSN tag");
+ break;
+ }
+
+ nssn = *(triplet[ind].p_array);
+ /* if SRM is enaged; make sure object offset TAG exists */
+ if ((p_cb->sess_info[OBX_SESSION_INFO_SRM_IDX] & OBX_SRM_ENGAGE) != 0)
+ {
+ obj_offset = obx_read_obj_offset(triplet, num);
+ OBX_TRACE_DEBUG2("RESUME:SRM is engaged and object offset:0x%x (0x%x)",
+ obj_offset, p_cb->param.sess.obj_offset);
+
+ /* client always takes the offset and ssn from the response since adjustment was done at server side */
+ p_cb->param.sess.obj_offset = obj_offset;
+ p_cb->ssn = nssn;
+ status = OBX_SUCCESS;
+ }
+ /* otherwise make sure NSSN from server is OK */
+ else if (nssn == p_cb->ssn)
+ {
+ OBX_TRACE_DEBUG0("RESUME:nssn matches expected ssn");
+ status = OBX_SUCCESS;
+ }
+ else if (dropped != 0)
+ {
+ OBX_TRACE_DEBUG2("RESUME:link drop suspend nssn:%d cb ssn:%d", nssn, p_cb->ssn);
+ if ((UINT8)(nssn+1) == p_cb->ssn)
+ {
+ OBX_TRACE_DEBUG0("RESUME:nssn matches expected(ssn-1)");
+ p_cb->ssn -= 1;
+ status = OBX_SUCCESS;
+ }
+ else if (nssn == (UINT8)(p_cb->ssn+1))
+ {
+ OBX_TRACE_DEBUG0("RESUME:nssn matches expected(ssn+1)");
+ nssn -= 1;
+ status = OBX_SUCCESS;
+ }
+ }
+ else
+ {
+ OBX_TRACE_ERROR2("RESUME:bad NSSN:%d (%d)", nssn, p_cb->ssn);
+ break;
+ }
+ p_cb->sess_st = OBX_SESS_ACTIVE;
+ sess_op = OBX_SESS_OP_RESUME;
+ OBX_TRACE_DEBUG2("RESUME:info new_state:0x%x, srm:0x%x", p_cb->sess_info[OBX_SESSION_INFO_ST_IDX], p_cb->sess_info[OBX_SESSION_INFO_SRM_IDX]);
+ p_cb->srm = p_cb->sess_info[OBX_SESSION_INFO_SRM_IDX];
+ p_cb->sess_info[OBX_SESSION_INFO_ST_IDX] &= ~OBX_CL_STATE_DROP;
+ if (p_cb->srm & OBX_SRM_ENGAGE)
+ {
+ new_state = p_cb->sess_info[OBX_SESSION_INFO_ST_IDX];
+ if (new_state == OBX_CS_GET_SRM)
+ {
+ p_cb->srm |= OBX_SRM_WAIT_UL;
+ /* Adjust snn in the control block since it is off by one with nssn in resume request */
+ p_cb->ssn--;
+ }
+ }
+ else
+ {
+ new_state = OBX_CS_CONNECTED;
+ p_cb->srmp |= OBX_SRMP_SESS_FST;
+ }
+ OBX_TRACE_DEBUG2("RESUME:new_state:%d, srm:0x%x", new_state, p_cb->srm);
+ break;
+
+ default:
+ status = OBX_BAD_PARAMS;
+ }
+ }
+ else
+ {
+ status = OBX_BAD_PARAMS;
+ }
+ OBX_TRACE_DEBUG5("obx_ca_session_ok prev:%d, sess_st:%d->%d obj_offset:%d status:%d", p_cb->prev_state, old_sess_st, p_cb->sess_st, obj_offset, status);
+
+ if (sess_op == OBX_SESS_OP_SET_TIME)
+ new_state = p_cb->prev_state;
+
+ if (status != OBX_SUCCESS)
+ {
+ if (p_cb->sess_st == OBX_SESS_CLOSE)
+ p_cb->sess_st = OBX_SESS_NONE;
+ obx_csm_event(p_cb, OBX_TIMEOUT_CEVT, NULL);
+ return OBX_CS_NULL;
+ }
+ p_cb->param.sess.p_sess_info= p_cb->sess_info;
+ p_cb->param.sess.sess_st = p_cb->sess_st;
+ p_cb->param.sess.nssn = nssn;
+ p_cb->param.sess.ssn = nssn;
+ p_cb->param.sess.sess_op = sess_op;
+ p_cb->param.sess.obj_offset = obj_offset;
+ p_cb->param.sess.timeout = timeout;
+ (*p_cb->p_cback)(p_cb->ll_cb.comm.handle, OBX_SESSION_RSP_EVT, p_cb->rsp_code, p_cb->param, NULL);
+
+ if ((sess_op == OBX_SESS_OP_RESUME) && (p_cb->sess_st == OBX_SESS_ACTIVE))
+ {
+ param.conn.ssn = p_cb->ssn;
+ memcpy (param.conn.peer_addr, p_cb->peer_addr, BD_ADDR_LEN);
+ p = &p_cb->sess_info[OBX_SESSION_INFO_MTU_IDX];
+ BE_STREAM_TO_UINT16(param.conn.mtu, p);
+ p_cb->ll_cb.comm.tx_mtu = param.conn.mtu;
+ param.conn.handle = p_cb->ll_cb.comm.handle;
+ OBX_TRACE_DEBUG1("RESUME: tx_mtu: %d", p_cb->ll_cb.comm.tx_mtu);
+ /* report OBX_CONNECT_RSP_EVT to let the client know the MTU */
+ (*p_cb->p_cback)(p_cb->ll_cb.comm.handle, OBX_CONNECT_RSP_EVT, OBX_RSP_OK, param, NULL);
+ sm_evt = OBX_STATE_CEVT;
+ p_cb->next_state = OBX_CS_CONNECTED;
+ }
+
+ if (sm_evt != OBX_BAD_SM_EVT)
+ {
+ /* send an event to csm */
+ obx_csm_event(p_cb, sm_evt, NULL);
+ }
+ return new_state;
+}
+
+/*******************************************************************************
+** Function obx_ca_session_cont
+** Description process the continue response from server for SRM after
+** a suspend session request is sent
+*******************************************************************************/
+tOBX_CL_STATE obx_ca_session_cont(tOBX_CL_CB *p_cb, BT_HDR *p_pkt)
+{
+ BOOLEAN free = TRUE;
+
+ OBX_TRACE_DEBUG3("obx_ca_session_cont sess_st:%d prev_state:%d, srm:0x%x", p_cb->sess_st, p_cb->prev_state, p_cb->srm);
+ if (p_cb->sess_st == OBX_SESS_SUSPEND)
+ {
+ if (p_cb->prev_state == OBX_CS_GET_SRM)
+ {
+ if ((p_cb->srm & OBX_SRM_WAIT_UL) == 0)
+ {
+ p_cb->srm |= OBX_SRM_WAIT_UL;
+ p_cb->api_evt = OBX_GET_RSP_EVT;
+ }
+ else
+ {
+ GKI_enqueue_head (&p_cb->ll_cb.comm.rx_q, p_pkt);
+ OBX_TRACE_DEBUG1("obx_ca_session_cont rx_q.count:%d", p_cb->ll_cb.comm.rx_q.count);
+ }
+ free = FALSE;
+ }
+ else if (p_cb->prev_state == OBX_CS_GET_REQ_SENT)
+ {
+ p_cb->api_evt = OBX_GET_RSP_EVT;
+ free = FALSE;
+ }
+
+ }
+ if (free && p_pkt)
+ GKI_freebuf(p_pkt);
+ OBX_TRACE_DEBUG1("obx_ca_session_cont srm: 0x%x(e)", p_cb->srm );
+ return OBX_CS_NULL;
+}
+
+/*******************************************************************************
+** Function obx_ca_session_get
+** Description process the get req api for SRM after
+** a suspend session request is sent (to clean out the received buffers)
+*******************************************************************************/
+tOBX_CL_STATE obx_ca_session_get(tOBX_CL_CB *p_cb, BT_HDR *p_pkt)
+{
+ OBX_TRACE_DEBUG3("obx_ca_session_get sess_st:%d prev_state: %d, srm:0x%x", p_cb->sess_st, p_cb->prev_state, p_cb->srm );
+ if (p_cb->sess_st == OBX_SESS_SUSPEND && p_cb->prev_state == OBX_CS_GET_SRM)
+ return obx_ca_srm_get_req(p_cb, p_pkt);
+ return OBX_CS_NULL;
+}
+
+/*******************************************************************************
+** Function obx_ca_session_fail
+** Description process the session failed response from server
+*******************************************************************************/
+tOBX_CL_STATE obx_ca_session_fail(tOBX_CL_CB *p_cb, BT_HDR *p_pkt)
+{
+ tOBX_SESS_ST old_sess_st = p_cb->sess_st;
+
+ p_cb->sess_st = OBX_SESS_NONE;
+ OBX_TRACE_DEBUG2("obx_ca_session_fail, sess_st:%d->%d", old_sess_st, p_cb->sess_st);
+ if (old_sess_st == OBX_SESS_CREATE && p_cb->rsp_code != OBX_RSP_OK)
+ {
+ /* peer device does not support session. Continue with regular session */
+ /* report session failure */
+ (*p_cb->p_cback)(p_cb->ll_cb.comm.handle, OBX_SESSION_RSP_EVT, p_cb->rsp_code, p_cb->param, NULL);
+ OBX_TRACE_DEBUG0("freeing received packet");
+ if (p_pkt)
+ GKI_freebuf (p_pkt) ;
+ p_pkt = p_cb->p_next_req;
+ p_cb->p_next_req = NULL;
+ obx_ca_connect_req (p_cb, p_pkt);
+ }
+ else
+ {
+ (*p_cb->p_cback)(p_cb->ll_cb.comm.handle, OBX_SESSION_RSP_EVT, OBX_RSP_FAILED, p_cb->param, NULL);
+ obx_ca_close_port (p_cb, p_pkt);
+ }
+ return OBX_CS_NULL;
+}
+
+/*******************************************************************************
+** Function obx_ca_abort
+** Description process the abort request in connected state
+*******************************************************************************/
+tOBX_CL_STATE obx_ca_abort(tOBX_CL_CB *p_cb, BT_HDR *p_pkt)
+{
+ OBX_TRACE_DEBUG2("obx_ca_abort srm:0x%x srmp:0x%x", p_cb->srm, p_cb->srmp);
+ if ( p_cb->srmp & OBX_SRMP_SESS_FST)
+ {
+ /* the first request after a session is resume.
+ * We may need to abort the previous request */
+ if (p_cb->sess_info[OBX_SESSION_INFO_ST_IDX] != OBX_CS_CONNECTED)
+ {
+ /* set the state here, just in case the result of obx_ca_snd_req is partial_sent */
+ p_cb->state = OBX_CS_ABORT_REQ_SENT;
+ obx_ca_snd_req(p_cb, p_pkt);
+ return OBX_CS_NULL;
+ }
+ p_cb->srmp &= ~OBX_SRMP_SESS_FST;
+ }
+ obx_ca_notify (p_cb, p_pkt);
+ return OBX_CS_NULL;
+}
+
+/*******************************************************************************
+** Function obx_ca_snd_put_req
+** Description send put request in connected state
+*******************************************************************************/
+tOBX_CL_STATE obx_ca_snd_put_req(tOBX_CL_CB *p_cb, BT_HDR *p_pkt)
+{
+ tOBX_SR_STATE state = OBX_CS_NULL;
+
+ OBX_TRACE_DEBUG1("obx_ca_snd_put_req, srm:0x%x", p_cb->srm);
+ state = obx_ca_snd_req (p_cb, p_pkt);
+ if (p_cb->srm & OBX_SRM_ENGAGE)
+ {
+ if (state == OBX_CS_PARTIAL_SENT)
+ {
+ p_cb->next_state = OBX_CS_PUT_SRM;
+ }
+ else
+ {
+ p_cb->state = OBX_CS_PUT_SRM;
+ if ((p_cb->srm & OBX_SRM_WAIT) == 0)
+ {
+ p_cb->rsp_code = OBX_RSP_CONTINUE;
+ p_cb->param.put.final = FALSE;
+ p_cb->param.put.type = OBX_PT_PUT;
+ p_cb->param.put.ssn = 0;
+ state = obx_ca_notify (p_cb, NULL);
+ }
+ }
+ }
+ return state;
+}
+
+/*******************************************************************************
+** Function obx_ca_snd_get_req
+** Description send get request in connected state
+*******************************************************************************/
+tOBX_CL_STATE obx_ca_snd_get_req(tOBX_CL_CB *p_cb, BT_HDR *p_pkt)
+{
+ tOBX_SR_STATE state;
+
+ OBX_TRACE_DEBUG1("obx_ca_snd_get_req srm:0x%x", p_cb->srm );
+ state = obx_ca_snd_req (p_cb, p_pkt);
+ OBX_TRACE_DEBUG1("srm:0x%x", p_cb->srm );
+ if (p_cb->srm & OBX_SRM_ENABLE)
+ {
+ if (state == OBX_CS_PARTIAL_SENT)
+ {
+ p_cb->next_state = OBX_CS_GET_SRM;
+ }
+ else
+ state = OBX_CS_GET_SRM;
+ p_cb->srm &= ~OBX_SRM_WAIT_UL;
+ }
+ OBX_TRACE_DEBUG1("srm:0x%x", p_cb->srm );
+ return state;
+}
+
+/*******************************************************************************
+** Function obx_ca_srm_snd_req
+** Description send Abort or Disconnect request
+*******************************************************************************/
+tOBX_CL_STATE obx_ca_srm_snd_req(tOBX_CL_CB *p_cb, BT_HDR *p_pkt)
+{
+ tOBX_SR_STATE state;
+ tOBX_COMM_CB *p_comm = &p_cb->ll_cb.comm;
+
+ OBX_TRACE_DEBUG2("obx_ca_srm_snd_req rx_q.count: %d, srm:0x%x", p_comm->rx_q.count, p_cb->srm );
+ p_cb->srm &= ~OBX_SRM_WAIT_UL;
+ state = obx_ca_snd_req (p_cb, p_pkt);
+ if ((p_pkt = (BT_HDR *)GKI_dequeue (&p_comm->rx_q)) != NULL)
+ {
+ GKI_freebuf(p_pkt);
+ }
+ OBX_TRACE_DEBUG2(" rx_q.count: %d, srm:0x%x", p_comm->rx_q.count, p_cb->srm );
+ return state;
+}
+
+/*******************************************************************************
+** Function obx_ca_srm_put_req
+** Description send a PUT request when SRM is engaged
+*******************************************************************************/
+tOBX_CL_STATE obx_ca_srm_put_req(tOBX_CL_CB *p_cb, BT_HDR *p_pkt)
+{
+ tOBX_SR_STATE state;
+
+ OBX_TRACE_DEBUG1("obx_ca_srm_put_req srm:0x%x", p_cb->srm );
+ state = obx_ca_snd_req (p_cb, p_pkt);
+ OBX_TRACE_DEBUG4("obx_ca_srm_put_req state:%d srm:0x%x, final:%d rsp_code:0x%x", state, p_cb->srm, p_cb->final, p_cb->rsp_code );
+ if (state != OBX_CS_PARTIAL_SENT && p_cb->final != TRUE && (p_cb->srm & OBX_SRM_WAIT) == 0)
+ {
+ p_cb->rsp_code = OBX_RSP_CONTINUE;
+ state = obx_ca_notify (p_cb, NULL);
+ }
+ return state;
+}
+
+/*******************************************************************************
+** Function obx_ca_srm_get_req
+** Description send a GET request when SRM is engaged
+*******************************************************************************/
+tOBX_CL_STATE obx_ca_srm_get_req(tOBX_CL_CB *p_cb, BT_HDR *p_pkt)
+{
+ tOBX_SR_STATE state = OBX_CS_NULL;
+ tOBX_COMM_CB *p_comm = &p_cb->ll_cb.comm;
+
+ OBX_TRACE_DEBUG3("obx_ca_srm_get_req rx_q.count: %d, srm:0x%x", p_cb->sess_st, p_comm->rx_q.count, p_cb->srm );
+
+ obx_start_timer(&p_cb->ll_cb.comm);
+ p_cb->srm &= ~OBX_SRM_WAIT_UL;
+ if (p_cb->sess_st == OBX_SESS_ACTIVE)
+ {
+ p_cb->ssn++;
+ }
+ if (p_pkt)
+ GKI_freebuf(p_pkt);
+
+ if ((p_pkt = (BT_HDR *)GKI_dequeue (&p_comm->rx_q)) != NULL)
+ {
+ if (state != OBX_CS_NULL)
+ {
+ p_cb->prev_state = p_cb->state;
+ p_cb->state = state;
+ state = OBX_CS_NULL;
+ }
+ obx_cl_proc_pkt (p_cb, p_pkt);
+ obx_flow_control(p_comm);
+ OBX_TRACE_DEBUG1("obx_ca_srm_get_req rx_q.count: %d", p_cb->ll_cb.comm.rx_q.count );
+ }
+ OBX_TRACE_DEBUG1("obx_ca_srm_get_req srm:0x%x", p_cb->srm );
+
+ return state;
+}
+
+/*******************************************************************************
+** Function obx_ca_srm_put_notify
+** Description Notify the OBX user OBX_PUT_RSP_EVT (OBX is ready for next req)
+*******************************************************************************/
+tOBX_CL_STATE obx_ca_srm_put_notify(tOBX_CL_CB *p_cb, BT_HDR *p_pkt)
+{
+ tOBX_SR_STATE state;
+
+ OBX_TRACE_DEBUG2("obx_ca_srm_put_notify srm: 0x%x, srmp: 0x%x", p_cb->srm, p_cb->srmp );
+
+ state = obx_ca_notify (p_cb, p_pkt);
+ return state;
+}
+
+/*******************************************************************************
+** Function obx_ca_srm_get_notify
+** Description Notify the OBX user OBX_GET_RSP_EVT (OBX is ready for next req)
+*******************************************************************************/
+tOBX_CL_STATE obx_ca_srm_get_notify(tOBX_CL_CB *p_cb, BT_HDR *p_pkt)
+{
+ tOBX_SR_STATE state = OBX_CS_NULL;
+
+ OBX_TRACE_DEBUG1("obx_ca_srm_get_notify srm: 0x%x", p_cb->srm );
+ /* do not allow SRMP for now */
+ p_cb->srm &= ~OBX_SRM_WAIT;
+
+ if (p_cb->srm & OBX_SRM_ENGAGE)
+ {
+ if ((p_cb->srm & OBX_SRM_WAIT_UL) == 0)
+ {
+ p_cb->srm |= OBX_SRM_WAIT_UL;
+ state = obx_ca_notify (p_cb, p_pkt);
+ }
+ else
+ {
+ GKI_enqueue_head (&p_cb->ll_cb.comm.rx_q, p_pkt);
+ OBX_TRACE_DEBUG1("obx_ca_srm_get_notify rx_q.count:%d", p_cb->ll_cb.comm.rx_q.count);
+ }
+ }
+ else
+ {
+ state = obx_ca_notify (p_cb, p_pkt);
+ if (state == OBX_CS_GET_SRM || state == OBX_CS_NULL)
+ state = OBX_CS_GET_TRANSACTION;
+ }
+ OBX_TRACE_DEBUG2("obx_ca_srm_get_notify srm: 0x%x(e) state:%s", p_cb->srm, obx_sr_get_state_name(state) );
+ return state;
+}
+
+/*******************************************************************************
+** Function obx_ca_save_rsp
+** Description save response in control block
+*******************************************************************************/
+tOBX_CL_STATE obx_ca_save_rsp(tOBX_CL_CB *p_cb, BT_HDR *p_pkt)
+{
+ GKI_enqueue (&p_cb->ll_cb.comm.rx_q, p_pkt);
+ return OBX_CS_NULL;
+}
+
+/*******************************************************************************
+** Function obx_ca_save_req
+** Description save request in control block
+*******************************************************************************/
+tOBX_CL_STATE obx_ca_save_req(tOBX_CL_CB *p_cb, BT_HDR *p_pkt)
+{
+ if (p_cb->p_next_req)
+ {
+ /* this probably would not happen */
+ /* this action only occurs when we are flow controlled by the peer
+ * and the client wants to abort the operation */
+ /* Just in case that the user keeps calling abort request.... */
+ OBX_TRACE_WARNING1("free next req: 0x%x", p_cb->p_next_req );
+ GKI_freebuf(p_cb->p_next_req);
+ }
+
+ p_cb->p_next_req = p_pkt;
+
+ return OBX_CS_NULL;
+}
+
+
+/*******************************************************************************
+** Function obx_ca_snd_req
+** Description If (p_pkt), call p_send_fn() to send the message to the peer.
+** Start timer. Return NULL state.If data is partially sent, return
+** PART state.
+*******************************************************************************/
+tOBX_CL_STATE obx_ca_snd_req(tOBX_CL_CB *p_cb, BT_HDR *p_pkt)
+{
+ tOBX_SR_STATE state = OBX_CS_NULL;
+ UINT8 rsp_code = OBX_RSP_DEFAULT;
+
+ obx_access_rsp_code(p_pkt, &rsp_code);
+ p_cb->final = (rsp_code&OBX_FINAL) ? TRUE : FALSE;
+ OBX_TRACE_DEBUG2("obx_ca_snd_req rsp_code: 0x%x final:%d", rsp_code, p_cb->final );
+
+ /* save a copy of the request sent to the server */
+ /* In case that we are challenged by the server,
+ * we can send the same request with authentication response again */
+ if (p_cb->p_saved_req)
+ GKI_freebuf(p_cb->p_saved_req);
+
+ p_cb->p_saved_req = obx_dup_pkt(p_pkt);
+
+ OBX_TRACE_DEBUG3( "event p_saved_req:%d, pkt:%d, final: %d", p_cb->p_saved_req->event, p_pkt->event,p_cb->final);
+
+ p_cb->ll_cb.comm.p_txmsg = p_pkt;
+ /* debug: obxu_dump_hex ((UINT8 *)(p_pkt + 1) + p_pkt->offset, "conn req", p_pkt->len); */
+
+ p_cb->srmp &= ~OBX_SRMP_SESS_FST;
+ if (p_cb->sess_st == OBX_SESS_ACTIVE)
+ {
+ p_cb->ssn++;
+ }
+
+ if (p_cb->ll_cb.comm.p_send_fn(&p_cb->ll_cb) == FALSE)
+ {
+ p_cb->next_state = p_cb->state;
+ state = OBX_CS_PARTIAL_SENT;
+ }
+
+ return state;
+}
+
+/*******************************************************************************
+** Function obx_ca_close_port
+** Description Close the transport. Return NULL state.
+*******************************************************************************/
+tOBX_CL_STATE obx_ca_close_port(tOBX_CL_CB *p_cb, BT_HDR *p_pkt)
+{
+ if (p_pkt)
+ GKI_freebuf(p_pkt);
+ p_cb->ll_cb.comm.p_close_fn(p_cb->ll_cb.comm.id);
+ return OBX_CS_NULL;
+}
+
+/*******************************************************************************
+** Function obx_ca_snd_part
+** Description Call p_send_fn() to send the left-over OBEX message to the peer.
+** Start timer. If all the data is sent, call obx_csm_event() with
+** STATE event to next_state in the port control block.
+** If (p_next_req), call obx_csm_event() to process the saved request.
+** Return NULL state.
+*******************************************************************************/
+tOBX_CL_STATE obx_ca_snd_part(tOBX_CL_CB *p_cb, BT_HDR *p_pkt)
+{
+ tOBX_CL_STATE state = OBX_CS_NULL;
+
+ OBX_TRACE_DEBUG1("obx_ca_snd_part sess_st:%d", p_cb->sess_st);
+
+ /* p_pkt should be NULL here */
+ if (p_cb->ll_cb.comm.p_send_fn(&p_cb->ll_cb) == TRUE)
+ {
+ /* data is all sent. change state to the appropriate state */
+ obx_csm_event(p_cb, OBX_STATE_CEVT, NULL);
+ if (p_cb->p_next_req && (p_cb->sess_st != OBX_SESS_CREATE))
+ {
+ /* abort request was issued - send it now */
+ p_pkt = p_cb->p_next_req;
+ p_cb->p_next_req = NULL;
+ obx_csm_event(p_cb, (tOBX_CL_EVENT)(p_pkt->event-1), p_pkt);
+ }
+
+ OBX_TRACE_DEBUG2("obx_ca_snd_part state:%d, srm:0x%x", p_cb->state, p_cb->srm);
+ if ((p_pkt = (BT_HDR *)GKI_dequeue (&p_cb->ll_cb.comm.rx_q)) != NULL)
+ {
+ obx_cl_proc_pkt (p_cb, p_pkt);
+ }
+ else if (p_cb->state == OBX_CS_PUT_SRM)
+ {
+ if (((p_cb->srm & OBX_SRM_WAIT) == 0) && (p_cb->final != TRUE))
+ {
+ state = obx_ca_notify (p_cb, NULL);
+ }
+ }
+ }
+ return state;
+}
+
+/*******************************************************************************
+** Function obx_ca_connect_error
+** Description Call callback function with OBX_CLOSE_IND_EVT. Free the client
+** control block. Return NULL state.
+*******************************************************************************/
+tOBX_CL_STATE obx_ca_connect_error(tOBX_CL_CB *p_cb, BT_HDR *p_pkt)
+{
+ tOBX_CL_CBACK *p_cback = p_cb->p_cback;
+ tOBX_HANDLE handle = p_cb->ll_cb.comm.handle;
+ tOBX_EVT_PARAM param = p_cb->param;
+ tOBX_SR_STATE save_state;
+
+ if (p_cb->sess_st == OBX_SESS_ACTIVE)
+ {
+ /* The transport is interrupted while a reliable session is active:
+ * report a suspend event fot application to save the information in NV.
+ * The only time this is called is for port close evt /w next state as not_connected
+ * we need to use prev_state as the potential state to resume session
+ */
+ save_state = p_cb->prev_state;
+ if (save_state == OBX_CS_PARTIAL_SENT)
+ save_state = p_cb->next_state;
+ /* marks link drop suspend only when SRM is not engaged */
+ if ((p_cb->srm & OBX_SRM_ENGAGE) == 0)
+ save_state |= OBX_CL_STATE_DROP;
+ else if (save_state == OBX_CS_GET_SRM)
+ p_cb->srm &= ~OBX_SRM_WAIT_UL;
+ p_cb->sess_info[OBX_SESSION_INFO_ST_IDX] = save_state;
+ OBX_TRACE_DEBUG2("obx_ca_connect_error saved state:0x%x, srm:0x%x", save_state, p_cb->srm);
+ p_cb->sess_info[OBX_SESSION_INFO_SRM_IDX] = p_cb->srm;
+ param.sess.p_sess_info = p_cb->sess_info;
+ param.sess.sess_op = OBX_SESS_OP_TRANSPORT;
+ param.sess.sess_st = p_cb->sess_st;
+ param.sess.nssn = p_cb->ssn;
+ param.sess.ssn = p_cb->ssn;
+ param.sess.obj_offset = 0;
+ param.sess.timeout = OBX_SESS_TIMEOUT_VALUE;
+ memcpy(param.sess.peer_addr, p_cb->peer_addr, BD_ADDR_LEN);
+ p_cb->sess_st = OBX_SESS_NONE;
+ (*p_cback)(handle, OBX_SESSION_INFO_EVT, OBX_RSP_OK, param, NULL);
+ }
+
+ obx_cl_free_cb(p_cb);
+ (*p_cback)(handle, OBX_CLOSE_IND_EVT, OBX_RSP_DEFAULT, param, p_pkt);
+ return OBX_CS_NULL;
+}
+
+/*******************************************************************************
+** Function obx_ca_connect_fail
+** Description If the response code is OBX_RSP_UNAUTHORIZED, save the OBEX
+** message in the client control block and call callback function
+** with OBX_PASSWORD_EVT. Return NULL state.Otherwise, call
+** obx_csm_event() with OBX_DISCNT_REQ_CEVT. (We do not need to
+** send disconnect request to the server, since we are not
+** connected yet). Return NULL state.
+*******************************************************************************/
+tOBX_CL_STATE obx_ca_connect_fail(tOBX_CL_CB *p_cb, BT_HDR *p_pkt)
+{
+ tOBX_SR_STATE state = OBX_CS_NULL;
+
+ if ( p_cb->rsp_code == OBX_RSP_UNAUTHORIZED &&
+ OBX_CheckHdr(p_pkt, OBX_HI_CHALLENGE) != NULL)
+ {
+ p_cb->api_evt = OBX_PASSWORD_EVT;
+ p_cb->p_auth = obx_dup_pkt(p_pkt);
+ }
+ else
+ {
+ /* Connect Request is rejected for reasons other than authentication
+ * or if the client challenges the server, but the server does nt return good digest
+ * - notify the user of the failure and .. */
+ (*p_cb->p_cback)(p_cb->ll_cb.comm.handle, OBX_CONNECT_RSP_EVT, p_cb->rsp_code, p_cb->param, p_pkt);
+ p_cb->api_evt = OBX_NULL_EVT;
+ /* and close the RFCOMM port */
+ obx_csm_event(p_cb, OBX_DISCNT_REQ_CEVT, NULL);
+ }
+ return state;
+}
+
+/*******************************************************************************
+** Function obx_ca_discnt_req
+** Description OBX_DISCNT_REQ_CEVT event is received in OBX_CS_CONNECT_REQ_SENT
+** state. In case that the server fails the authentication, client
+** needs to send Disconnect Req. Otherwise, just close port.
+*******************************************************************************/
+tOBX_CL_STATE obx_ca_discnt_req(tOBX_CL_CB *p_cb, BT_HDR *p_pkt)
+{
+ tOBX_CL_STATE state = OBX_CS_NOT_CONNECTED;
+ UINT8 msg[OBX_HDR_OFFSET];
+ UINT8 *p = msg;
+
+ if (p_cb->wait_auth == OBX_WAIT_AUTH_FAIL)
+ {
+ /* server thinks the connection is up.
+ * client needs to send disconnect req */
+ state = OBX_CS_DISCNT_REQ_SENT;
+ /* Disconnect request always has the final bit set */
+ *p++ = (OBX_REQ_DISCONNECT|OBX_FINAL);
+ p += OBX_PKT_LEN_SIZE;
+
+ /* add session sequence number, if session is active */
+ if (p_cb->sess_st == OBX_SESS_ACTIVE)
+ {
+ *p++ = OBX_HI_SESSION_SN;
+ *p++ = p_cb->ssn;
+ }
+
+ /* add connection ID, if needed */
+ if (p_cb->conn_id != OBX_INVALID_CONN_ID)
+ {
+ *p++ = OBX_HI_CONN_ID;
+ UINT32_TO_BE_STREAM(p, p_cb->conn_id);
+ }
+
+ p_pkt = obx_cl_prepend_msg(p_cb, NULL, msg, (UINT16)(p - msg) );
+ obx_ca_snd_req(p_cb, p_pkt);
+ }
+ else
+ {
+ /* connection is not officially up yet.
+ * just close the port */
+ obx_ca_close_port(p_cb, p_pkt);
+ }
+ p_cb->wait_auth = FALSE;
+
+ return state;
+}
+
+/*******************************************************************************
+** Function obx_ca_notify
+** Description Use api_evt or look up the event according to the state. Fill
+** the event parameter. Call callback function with the event.
+** Return NULL state.
+*******************************************************************************/
+tOBX_CL_STATE obx_ca_notify(tOBX_CL_CB *p_cb, BT_HDR *p_pkt)
+{
+ tOBX_SR_STATE state = OBX_CS_CONNECTED;
+ tOBX_EVENT event = obx_cl_state_2_event_map[p_cb->state - 1];
+ BOOLEAN notify = FALSE;
+ tOBX_CL_EVENT sm_evt = OBX_BAD_SM_EVT;
+ BT_HDR *p_req = NULL;
+
+ OBX_TRACE_DEBUG6( "obx_ca_notify state: %s, prev_state: %s, rsp:0x%x, sess_st:%d, event:%d srm:0x%x",
+ obx_cl_get_state_name( p_cb->state ), obx_cl_get_state_name(p_cb->prev_state), p_cb->rsp_code, p_cb->sess_st, event, p_cb->srm);
+ OBX_TRACE_DEBUG2( "ssn:0x%x/0x%x", p_cb->ssn, p_cb->param.ssn);
+
+ if ( (p_cb->final == TRUE && p_cb->rsp_code == OBX_RSP_CONTINUE && p_cb->state == OBX_CS_PUT_TRANSACTION) ||
+ (p_cb->final == FALSE && p_cb->rsp_code != OBX_RSP_CONTINUE) )
+ {
+ /* final bit on the request mismatch the responde code --- Error!! */
+ OBX_TRACE_ERROR2( "final:%d on the request mismatch the responde code:0x%x",
+ p_cb->final, p_cb->rsp_code) ;
+ /* change the state to not connected state */
+ p_cb->next_state = OBX_CS_NOT_CONNECTED;
+ obx_csm_event(p_cb, OBX_STATE_CEVT, NULL);
+ notify = TRUE;
+ /* send a tx_empty event to close port */
+ sm_evt = OBX_TX_EMPTY_CEVT;
+ }
+
+ else if (event != OBX_NULL_EVT)
+ {
+ switch (p_cb->state)
+ {
+ case OBX_CS_PUT_TRANSACTION:
+ case OBX_CS_GET_TRANSACTION:
+ case OBX_CS_PUT_REQ_SENT:
+ case OBX_CS_GET_REQ_SENT:
+ case OBX_CS_PUT_SRM:
+ case OBX_CS_GET_SRM:
+ if (p_cb->rsp_code == OBX_RSP_CONTINUE )
+ {
+ /* notify the event in this function. the new state stays the same */
+ notify = TRUE;
+
+ if (p_cb->srm & OBX_SRM_ENGAGE)
+ {
+ if (p_cb->state == OBX_CS_PUT_TRANSACTION)
+ {
+ p_cb->state = OBX_CS_PUT_SRM;
+ }
+ else if (p_cb->state == OBX_CS_GET_TRANSACTION)
+ {
+ p_cb->state = OBX_CS_GET_SRM;
+ }
+ else if (p_cb->state == OBX_CS_PUT_SRM && p_pkt && (p_cb->srm & OBX_SRM_WAIT) == 0)
+ {
+ OBX_TRACE_ERROR0 ("unexpected PUT response. disconnect now!!");
+ notify = FALSE;
+ event = OBX_NULL_EVT;
+ obx_ca_close_port(p_cb, p_pkt);
+ }
+ /* clear the wait bit here to avoid the link being disconnected by accident */
+ p_cb->srm &= ~OBX_SRM_WAIT;
+ if (p_cb->srmp)
+ {
+ p_cb->srmp = 0;
+ p_cb->srm |= OBX_SRM_WAIT;
+ }
+ }
+ }
+ /* else let obx_csm_event notify the event. the new state is OBX_CS_CONNECTED */
+ else
+ {
+ /* dis-engage SRM */
+ p_cb->srm &= OBX_SRM_ENABLE;
+ OBX_TRACE_DEBUG1( "disengage srm:0x%x", p_cb->srm);
+ }
+ break;
+
+ case OBX_CS_NOT_CONNECTED:
+ if (p_cb->sess_st == OBX_SESS_ACTIVE && p_cb->prev_state == OBX_CS_DISCNT_REQ_SENT)
+ {
+ p_req = obx_ca_close_sess_req (p_cb);
+ sm_evt = OBX_SESSION_REQ_CEVT;
+ state = OBX_CS_NULL;
+ }
+ else
+ {
+ notify = TRUE;
+ /* send a tx_empty event to close port */
+ sm_evt = OBX_TX_EMPTY_CEVT;
+ }
+ break;
+
+ case OBX_CS_CONNECT_REQ_SENT:
+ if (p_cb->rsp_code == OBX_RSP_FAILED)
+ {
+ /* client challenged the server and the server does not return a good digest */
+ notify = TRUE;
+ /* send a disconnect req event to close port */
+ sm_evt = OBX_DISCNT_REQ_CEVT;
+ }
+ break;
+
+ case OBX_CS_ABORT_REQ_SENT:
+ p_cb->srm &= OBX_SRM_ENABLE;
+ OBX_TRACE_DEBUG1( "(ab) disengage srm:0x%x", p_cb->srm);
+ break;
+ }
+ }
+
+ if (notify == TRUE )
+ {
+ (*p_cb->p_cback)(p_cb->ll_cb.comm.handle, event, p_cb->rsp_code, p_cb->param, p_pkt);
+ event = OBX_NULL_EVT;
+ }
+
+ if (sm_evt != OBX_BAD_SM_EVT)
+ {
+ /* send an event to csm */
+ obx_csm_event(p_cb, sm_evt, p_req);
+ }
+
+ p_cb->api_evt = event;
+ if (event == OBX_NULL_EVT)
+ {
+ state = OBX_CS_NULL;
+ }
+ else
+ {
+ p_cb->ssn = p_cb->param.ssn;
+ OBX_TRACE_DEBUG1( "ssn:0x%x", p_cb->ssn);
+ }
+
+ return state;
+}
+
+/*******************************************************************************
+** Function obx_ca_fail_rsp
+** Description Save the OBEX message in control block.If the response code is
+** OBX_RSP_UNAUTHORIZED, set api_evt to OBX_PASSWORD_EVT. Return
+** OP_UNAUTH state.Otherwise, set api_evt according to the
+** event/state table. Return CONN state.
+*******************************************************************************/
+tOBX_CL_STATE obx_ca_fail_rsp(tOBX_CL_CB *p_cb, BT_HDR *p_pkt)
+{
+ tOBX_SR_STATE state = OBX_CS_CONNECTED;
+
+ p_cb->srm &= OBX_SRM_ENABLE;
+
+ if ( p_cb->rsp_code == OBX_RSP_UNAUTHORIZED &&
+ OBX_CheckHdr(p_pkt, OBX_HI_CHALLENGE) != NULL)
+ {
+ state = OBX_CS_OP_UNAUTH;
+ p_cb->api_evt = OBX_PASSWORD_EVT;
+ p_cb->p_auth = obx_dup_pkt(p_pkt);
+ }
+ else
+ p_cb->api_evt = obx_cl_state_2_event_map[p_cb->state - 1];
+
+ return state;
+}
diff --git a/stack/obx/obx_capi.c b/stack/obx/obx_capi.c
new file mode 100644
index 0000000..ea34aa1
--- /dev/null
+++ b/stack/obx/obx_capi.c
@@ -0,0 +1,855 @@
+/*****************************************************************************
+**
+** Name: obx_capi.c
+**
+** File: OBEX Client Application Programming Interface functions
+**
+** Copyright (c) 2003-2010, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include "bt_target.h"
+#include "wcassert.h"
+#include "obx_int.h"
+#include "port_api.h"
+#include "l2c_api.h"
+#include "btm_api.h"
+
+/*******************************************************************************
+**
+** Function OBX_ConnectReq
+**
+** Description This function registers a client entity to OBEX and sends a
+** CONNECT request to the server specified by the API parameters.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_NO_RESOURCES, if OBX does not resources
+**
+*******************************************************************************/
+tOBX_STATUS OBX_ConnectReq(BD_ADDR bd_addr, UINT8 scn, UINT16 mtu,
+ tOBX_CL_CBACK *p_cback, tOBX_HANDLE *p_handle, BT_HDR *p_pkt)
+{
+ tOBX_STATUS status = OBX_NO_RESOURCES;
+ UINT8 msg[OBX_HDR_OFFSET + OBX_MAX_CONN_HDR_EXTRA];
+ UINT8 *p = msg;
+ tOBX_CL_CB *p_cb;
+
+ WC_ASSERT(p_handle);
+
+ p_cb = obx_cl_get_cb(*p_handle);
+ if (p_cb == NULL)
+ p_cb = obx_cl_alloc_cb();
+
+ if (p_cb)
+ {
+ if (p_cb->ll_cb.port.port_handle == 0)
+ {
+ WC_ASSERT(p_cback);
+ /* port is not open yet- open one
+ * this is the first CONNECT request */
+ p_cb->ll_cb.comm.rx_mtu = mtu;
+ p_cb->p_cback = p_cback;
+ p_cb->state = OBX_CS_NOT_CONNECTED;
+ status = obx_open_port(&p_cb->ll_cb.port, bd_addr, scn);
+ *p_handle = p_cb->ll_cb.port.handle;
+ }
+ else
+ {
+ /* when called by other OBX functions */
+ status = OBX_SUCCESS;
+ }
+
+ if (status == OBX_SUCCESS)
+ {
+ /* Connect request packet always has the final bit set */
+ *p++ = (OBX_REQ_CONNECT | OBX_FINAL);
+ p += OBX_PKT_LEN_SIZE;
+
+ *p++ = OBX_VERSION;
+ *p++ = OBX_CONN_FLAGS;
+ UINT16_TO_BE_STREAM(p, p_cb->ll_cb.port.rx_mtu);
+ /* IrOBEX spec forbids connection ID in Connect Request */
+ p_pkt = obx_cl_prepend_msg(p_cb, p_pkt, msg, (UINT16)(p - msg) );
+
+ p_pkt->event = OBX_CONNECT_REQ_EVT;
+ obx_csm_event(p_cb, OBX_CONNECT_REQ_CEVT, p_pkt);
+ }
+ else
+ {
+ OBX_TRACE_ERROR1("Error opening port for scn: %d", scn);
+ obx_cl_free_cb(p_cb);
+ }
+ }
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function OBX_AllocSession
+**
+** Description This function registers a client entity to OBEX.
+** If p_session_info is not NULL, it tries to find an suspended session
+** with matching session_info.
+** If scn is not 0, it allocates a control block for this new session.
+** Otherwise, it allocates a control block for the given PSM.
+** The associated virtual PSM assigned by L2CAP is returned in p_psm
+** The allocated OBEX handle is returned in p_handle.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_NO_RESOURCES, if OBX does not resources
+**
+*******************************************************************************/
+tOBX_STATUS OBX_AllocSession (UINT8 *p_session_info, UINT8 scn, UINT16 *p_psm,
+ tOBX_CL_CBACK *p_cback, tOBX_HANDLE *p_handle)
+{
+ tOBX_STATUS status = OBX_NO_RESOURCES;
+ tOBX_CL_CB *p_cb;
+
+ WC_ASSERT(p_handle);
+ WC_ASSERT(p_cback);
+
+ OBX_TRACE_API2("OBX_AllocSession scn: %d, psm:0x%x", scn, *p_psm);
+
+ if (p_session_info)
+ {
+ p_cb = obx_cl_get_suspended_cb(p_handle, p_session_info);
+ if (p_cb)
+ {
+ p_cb->srm = p_cb->sess_info[OBX_SESSION_INFO_SRM_IDX];
+ status = OBX_SUCCESS;
+ }
+ }
+ else
+ {
+ p_cb = obx_cl_get_cb(*p_handle);
+ if (p_cb == NULL)
+ p_cb = obx_cl_alloc_cb();
+
+
+ }
+
+ if (p_cb)
+ {
+ p_cb->rsp_code = 0;
+ p_cb->psm = 0;
+
+ if (p_cb->sess_st != OBX_SESS_SUSPENDED)
+ p_cb->sess_st = OBX_SESS_NONE;
+
+ if (p_psm && L2C_IS_VALID_PSM(*p_psm))
+ {
+ obx_register_l2c(p_cb, *p_psm);
+ /* obx_register_l2c puts the virtual psm in p_cb->psm */
+ if (p_cb->psm)
+ {
+ *p_psm = p_cb->psm;
+ status = OBX_SUCCESS;
+ }
+ }
+
+ /* check SCN only when a virtual PSM is not allocated */
+ if (!p_cb->psm)
+ {
+ if (scn)
+ {
+ /* borrow this data member temporarily */
+ p_cb->rsp_code = scn;
+ status = OBX_SUCCESS;
+ }
+ }
+ }
+
+ if (status != OBX_SUCCESS)
+ {
+ obx_cl_free_cb(p_cb);
+ p_cb = NULL;
+ }
+
+ if (p_cb)
+ {
+ *p_handle = p_cb->ll_cb.comm.handle;
+ p_cb->p_cback = p_cback;
+ p_cb->state = OBX_CS_NOT_CONNECTED;
+ }
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function OBX_CreateSession
+**
+** Description This function registers a client entity to OBEX.
+** It may send a CreateSession request and wait for CreateSession response.
+** It sends a CONNECT request to the server specified by the API parameters.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_NO_RESOURCES, if OBX does not resources
+**
+*******************************************************************************/
+tOBX_STATUS OBX_CreateSession (BD_ADDR bd_addr, UINT16 mtu, BOOLEAN srm, UINT32 nonce,
+ tOBX_HANDLE handle, BT_HDR *p_pkt)
+{
+ tOBX_STATUS status = OBX_NO_RESOURCES;
+ tOBX_CL_CB *p_cb;
+ UINT8 *p;
+ UINT8 *pn;
+ BT_HDR *p_req;
+ UINT8 data[20];
+ tOBX_TRIPLET triplet[4];
+ UINT8 num_trip = 0;
+
+ OBX_TRACE_API1("OBX_CreateSession handle: 0x%x", handle);
+ p_cb = obx_cl_get_cb(handle);
+
+ if (p_cb)
+ {
+ if (p_cb->state != OBX_CS_NOT_CONNECTED || p_cb->sess_st != OBX_SESS_NONE)
+ {
+ OBX_TRACE_ERROR2("bad state: %d, or sess_st:%d", p_cb->state, p_cb->sess_st);
+ return status;
+ }
+
+ if (p_cb->ll_cb.comm.id == 0)
+ {
+ p_cb->ll_cb.comm.rx_mtu = mtu;
+
+ OBX_TRACE_DEBUG2("scn: %d, psm:0x%x", p_cb->rsp_code, p_cb->psm);
+
+ if (p_cb->psm)
+ {
+ /* L2CAP channel is not open yet- open one
+ * this is the first CONNECT request */
+ status = obx_open_l2c(p_cb, bd_addr);
+ }
+ else if (p_cb->rsp_code) /* p_cb->rsp_code is used as the scn */
+ {
+ /* port is not open yet- open one
+ * this is the first CONNECT request */
+ status = obx_open_port(&p_cb->ll_cb.port, bd_addr, p_cb->rsp_code);
+ }
+ }
+ else
+ {
+ /* when called by other OBX functions */
+ status = OBX_SUCCESS;
+ }
+
+ if (status == OBX_SUCCESS)
+ {
+ /* OBEX 1.5 */
+ p_cb->srm = OBX_SRM_NO;
+ if (srm)
+ p_cb->srm = OBX_SRM_ENABLE;
+ p_cb->nonce = nonce;
+ p_cb->sess_st = OBX_SESS_NONE;
+ if (nonce)
+ {
+ if ( (p_req = OBX_HdrInit(handle, OBX_MIN_MTU)) != NULL)
+ {
+ p = (UINT8 *) (p_req + 1) + p_req->offset;
+ /* Session request packet always has the final bit set */
+ *p++ = (OBX_REQ_SESSION | OBX_FINAL);
+ p_req->len = 3;
+ p = data;
+ /* add session opcode */
+ triplet[num_trip].tag = OBX_TAG_SESS_PARAM_SESS_OP;
+ triplet[num_trip].len = OBX_LEN_SESS_PARAM_SESS_OP;
+ triplet[num_trip].p_array = p;
+ *p = OBX_SESS_OP_CREATE;
+ p += OBX_LEN_SESS_PARAM_SESS_OP;
+ num_trip++;
+
+ /* add device addr */
+ triplet[num_trip].tag = OBX_TAG_SESS_PARAM_ADDR;
+ triplet[num_trip].len = BD_ADDR_LEN;
+ triplet[num_trip].p_array = p;
+ BTM_GetLocalDeviceAddr (p);
+ p += BD_ADDR_LEN;
+ num_trip++;
+
+ /* add nonce 4 - 16 bytes */
+ triplet[num_trip].tag = OBX_TAG_SESS_PARAM_NONCE;
+ triplet[num_trip].len = OBX_LOCAL_NONCE_SIZE;
+ pn = &p_cb->sess_info[OBX_SESSION_ID_SIZE];
+ triplet[num_trip].p_array = pn;
+ UINT32_TO_BE_STREAM(pn, nonce);
+ num_trip++;
+
+ /* add timeout */
+ triplet[num_trip].p_array = p;
+ if (obx_add_timeout (&triplet[num_trip], obx_cb.sess_tout_val, &p_cb->param.sess))
+ {
+ num_trip ++;
+ p = &p_cb->sess_info[OBX_SESSION_INFO_TO_IDX];
+ UINT32_TO_BE_STREAM(p, obx_cb.sess_tout_val);
+ p_cb->param.sess.timeout = obx_cb.sess_tout_val;
+ }
+
+ OBX_AddTriplet(p_req, OBX_HI_SESSION_PARAM, triplet, num_trip);
+ if (p_pkt)
+ {
+ /* assume that these headers are to be added to the connect req */
+ p_cb->p_next_req = p_pkt;
+ }
+ /* adjust the packet len */
+ p = (UINT8 *) (p_req + 1) + p_req->offset + 1;
+ UINT16_TO_BE_STREAM(p, p_req->len);
+ p_req->event = OBX_SESSION_REQ_EVT;
+ p_cb->sess_st = OBX_SESS_CREATE;
+ obx_csm_event(p_cb, OBX_SESSION_REQ_CEVT, p_req);
+ }
+ else
+ status = OBX_NO_RESOURCES;
+ }
+ else /* legacy */
+ {
+ obx_ca_connect_req (p_cb, p_pkt);
+ }
+ }
+ if (status != OBX_SUCCESS)
+ {
+ obx_cl_free_cb(p_cb);
+ }
+ }
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function OBX_ResumeSession
+**
+** Description This function registers a client entity to OBEX and resumes
+** a previously interrupted reliable session.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_NO_RESOURCES, if OBX does not resources
+**
+*******************************************************************************/
+tOBX_STATUS OBX_ResumeSession (BD_ADDR bd_addr, UINT8 ssn, UINT32 offset, tOBX_HANDLE handle)
+{
+ tOBX_STATUS status = OBX_NO_RESOURCES;
+ UINT8 *p;
+ tOBX_CL_CB *p_cb;
+ BT_HDR *p_req;
+ tOBX_TRIPLET triplet[6];
+ UINT8 data[13];
+ UINT8 num_trip = 0;
+ UINT8 *pn;
+
+ OBX_TRACE_API3("OBX_ResumeSession handle: 0x%x ssn:%d offset:%d", handle, ssn, offset);
+ p_cb = obx_cl_get_cb(handle);
+
+ if (p_cb)
+ {
+ OBX_TRACE_DEBUG3("OBX_ResumeSession, sess_st:%d srm:0x%x, saved state:0x%x", p_cb->sess_st,
+ p_cb->sess_info[OBX_SESSION_INFO_SRM_IDX], p_cb->sess_info[OBX_SESSION_INFO_SRM_IDX]);
+ if (p_cb->sess_st == OBX_SESS_SUSPENDED)
+ {
+ if ((p_req = OBX_HdrInit(OBX_HANDLE_NULL, OBX_MIN_MTU)) != NULL)
+ {
+ p = (UINT8 *) (p_req + 1) + p_req->offset;
+ /* Session request packet always has the final bit set */
+ *p++ = (OBX_REQ_SESSION | OBX_FINAL);
+ p_req->len = 3;
+
+ /* add session opcode */
+ p = data;
+ triplet[num_trip].tag = OBX_TAG_SESS_PARAM_SESS_OP;
+ triplet[num_trip].len = OBX_LEN_SESS_PARAM_SESS_OP;
+ triplet[num_trip].p_array = p;
+ *p = OBX_SESS_OP_RESUME;
+ p += OBX_LEN_SESS_PARAM_SESS_OP;
+ num_trip++;
+
+ /* add device addr */
+ triplet[num_trip].tag = OBX_TAG_SESS_PARAM_ADDR;
+ triplet[num_trip].len = BD_ADDR_LEN;
+ triplet[num_trip].p_array = p;
+ BTM_GetLocalDeviceAddr (p);
+ p += BD_ADDR_LEN;
+ num_trip++;
+
+ /* add nonce 4 - 16 bytes */
+ triplet[num_trip].tag = OBX_TAG_SESS_PARAM_NONCE;
+ triplet[num_trip].len = OBX_LOCAL_NONCE_SIZE;
+ pn = &p_cb->sess_info[OBX_SESSION_ID_SIZE];
+ triplet[num_trip].p_array = pn;
+ num_trip++;
+
+ /* add session id */
+ triplet[num_trip].tag = OBX_TAG_SESS_PARAM_SESS_ID;
+ triplet[num_trip].len = OBX_SESSION_ID_SIZE;
+ triplet[num_trip].p_array = p_cb->sess_info;
+ num_trip++;
+
+ if (p_cb->sess_info[OBX_SESSION_INFO_SRM_IDX] & OBX_SRM_ENGAGE)
+ {
+ /* add ssn */
+ triplet[num_trip].tag = OBX_TAG_SESS_PARAM_NSEQNUM;
+ triplet[num_trip].len = 1;
+ triplet[num_trip].p_array = p;
+ *p++ = ssn;
+ num_trip++;
+
+ if (offset)
+ {
+ /* add object offset */
+ p_cb->param.sess.obj_offset = offset;
+ triplet[num_trip].tag = OBX_TAG_SESS_PARAM_OBJ_OFF;
+ triplet[num_trip].len = OBX_LEN_SESS_PARAM_OBJ_OFF;
+ triplet[num_trip].p_array = p;
+ UINT32_TO_BE_STREAM(p, offset);
+ num_trip++;
+ }
+ }
+
+ p_cb->sess_st = OBX_SESS_RESUME;
+ OBX_AddTriplet(p_req, OBX_HI_SESSION_PARAM, triplet, num_trip);
+ /* adjust the packet len */
+ p = (UINT8 *) (p_req + 1) + p_req->offset + 1;
+ UINT16_TO_BE_STREAM(p, p_req->len);
+ p_req->event = OBX_SESSION_REQ_EVT;
+ status = OBX_SUCCESS;
+
+ if (p_cb->ll_cb.comm.id == 0 || p_cb->ll_cb.comm.p_send_fn == 0)
+ {
+ /* the transport is closed. open it again */
+ OBX_TRACE_DEBUG2("scn: %d, psm:0x%x", p_cb->rsp_code, p_cb->psm);
+ p_cb->ll_cb.comm.rx_mtu = OBX_MAX_MTU;
+
+ if (p_cb->psm)
+ {
+ /* L2CAP channel is not open yet- open one
+ * this is the first CONNECT request */
+ status = obx_open_l2c(p_cb, bd_addr);
+ }
+ else if (p_cb->rsp_code) /* p_cb->rsp_code is used as the scn */
+ {
+ /* port is not open yet- open one
+ * this is the first CONNECT request */
+ status = obx_open_port(&p_cb->ll_cb.port, bd_addr, p_cb->rsp_code);
+ }
+ }
+
+ if (status == OBX_SUCCESS)
+ {
+ pn = &p_cb->sess_info[OBX_SESSION_INFO_ID_IDX];
+ BE_STREAM_TO_UINT32(p_cb->conn_id, pn);
+ p_cb->ssn = ssn;
+ p_cb->param.sess.ssn = ssn;
+ obx_csm_event(p_cb, OBX_SESSION_REQ_CEVT, p_req);
+ }
+ }
+ }
+ else
+ {
+ OBX_TRACE_ERROR1("Handle is not in a right state: %d for RESUME", p_cb->sess_st);
+ status = OBX_BAD_HANDLE;
+ }
+ }
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function OBX_SessionReq
+**
+** Description This function is used to Suspend/Close a session or update the
+** timeout value of the session.
+** If timeout is 0, OBX_SESS_TIMEOUT_VALUE is the value used
+** THe timeout value is not added for the CloseSession request
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_NO_RESOURCES, if OBX does not resources
+**
+*******************************************************************************/
+tOBX_STATUS OBX_SessionReq (tOBX_HANDLE handle, tOBX_SESS_OP opcode, UINT32 timeout)
+{
+ tOBX_STATUS status = OBX_NO_RESOURCES;
+ UINT8 *p;
+ tOBX_CL_CB *p_cb;
+ BT_HDR *p_req;
+ tOBX_TRIPLET triplet[3];
+ UINT8 data[12];
+ UINT8 num_trip = 0;
+ tOBX_SESS_ST old_sess_st;
+
+ p_cb = obx_cl_get_cb(handle);
+
+ if (p_cb)
+ {
+ OBX_TRACE_API2("OBX_SessionReq st:%d opcode:%d", p_cb->sess_st, opcode);
+ old_sess_st = p_cb->sess_st;
+ if ((p_req = OBX_HdrInit(OBX_HANDLE_NULL, OBX_MIN_MTU)) != NULL)
+ {
+ status = OBX_SUCCESS;
+ p = (UINT8 *) (p_req + 1) + p_req->offset;
+ /* Session request packet always has the final bit set */
+ *p++ = (OBX_REQ_SESSION | OBX_FINAL);
+ p_req->len = 3;
+
+ /* add session opcode */
+ p = data;
+ triplet[num_trip].tag = OBX_TAG_SESS_PARAM_SESS_OP;
+ triplet[num_trip].len = OBX_LEN_SESS_PARAM_SESS_OP;
+ triplet[num_trip].p_array = p;
+ *p = opcode;
+ p += OBX_LEN_SESS_PARAM_SESS_OP;
+ num_trip++;
+ if (timeout == 0)
+ {
+ timeout = obx_cb.sess_tout_val;
+ if (p_cb->srm & OBX_SRM_ENABLE)
+ timeout += obx_cb.sess_tout_val;
+ }
+ triplet[num_trip].p_array = p;
+ switch (opcode)
+ {
+ case OBX_SESS_OP_CLOSE:
+ /* do not need any other session parameters */
+ if (p_cb->sess_st != OBX_SESS_NONE)
+ p_cb->sess_st = OBX_SESS_CLOSE;
+ else
+ {
+ OBX_TRACE_ERROR1("Handle is not in a right state: %d for CLOSE", p_cb->sess_st);
+ status = OBX_BAD_HANDLE;
+ }
+ break;
+
+ case OBX_SESS_OP_SUSPEND:
+ /* do not need any other session parameters */
+ if (p_cb->sess_st == OBX_SESS_ACTIVE)
+ {
+ /* add timeout value */
+ num_trip += obx_add_timeout (&triplet[num_trip], timeout, &p_cb->param.sess);
+ p_cb->sess_st = OBX_SESS_SUSPEND;
+ }
+ else
+ {
+ OBX_TRACE_ERROR1("Handle is not in a right state: %d for SUSPEND", p_cb->sess_st);
+ status = OBX_BAD_HANDLE;
+ }
+ break;
+
+ case OBX_SESS_OP_SET_TIME:
+ if (p_cb->sess_st == OBX_SESS_ACTIVE)
+ {
+ /* add timeout value */
+ num_trip += obx_add_timeout (&triplet[num_trip], timeout, &p_cb->param.sess);
+ p_cb->sess_st = OBX_SESS_TIMEOUT;
+ }
+ else
+ {
+ OBX_TRACE_ERROR1("Handle is not in a right state: %d for SET_TIME", p_cb->sess_st);
+ status = OBX_BAD_HANDLE;
+ }
+ break;
+ default:
+ OBX_TRACE_ERROR1("bad session opcode :%d", opcode);
+ status = OBX_BAD_PARAMS;
+ }
+
+ OBX_TRACE_DEBUG4("OBX_SessionReq, sess_st:%d->%d opcode:%d status:%d", old_sess_st, p_cb->sess_st, opcode, status);
+ if (status != OBX_SUCCESS)
+ GKI_freebuf (p_req);
+ else
+ {
+ OBX_AddTriplet(p_req, OBX_HI_SESSION_PARAM, triplet, num_trip);
+ if (p_cb->sess_st == OBX_SESS_SUSPEND)
+ {
+ p_cb->sess_info[OBX_SESSION_INFO_ST_IDX] = p_cb->state;
+ if (p_cb->state == OBX_CS_PARTIAL_SENT)
+ p_cb->sess_info[OBX_SESSION_INFO_ST_IDX] = p_cb->prev_state;
+ p_cb->sess_info[OBX_SESSION_INFO_SRM_IDX] = p_cb->srm;
+ OBX_TRACE_DEBUG2("suspend saved st:%d, srm:0x%x", p_cb->sess_info[OBX_SESSION_INFO_ST_IDX], p_cb->sess_info[OBX_SESSION_INFO_SRM_IDX]);
+ }
+ /* adjust the packet len */
+ p = (UINT8 *) (p_req + 1) + p_req->offset + 1;
+ UINT16_TO_BE_STREAM(p, p_req->len);
+ p_req->event = OBX_SESSION_REQ_EVT;
+ obx_csm_event(p_cb, OBX_SESSION_REQ_CEVT, p_req);
+ }
+ }
+ }
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function OBX_GetPortHandle
+**
+** Description This function is called to get RFCOMM port handle for the obex connection.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_NO_RESOURCES, if no existing connection.
+** OBX_BAD_HANDLE, if the handle is not valid.
+**
+*******************************************************************************/
+tOBX_STATUS OBX_GetPortHandle(tOBX_HANDLE handle, UINT16 *port_handle)
+{
+ BD_ADDR bd_addr;
+ UINT16 lcid;
+ tOBX_STATUS status = OBX_SUCCESS;
+ tOBX_CL_CB *p_cb = obx_cl_get_cb(handle);
+
+ if (p_cb)
+ {
+ if (PORT_CheckConnection(p_cb->ll_cb.port.port_handle, bd_addr, &lcid) != PORT_SUCCESS)
+ {
+ status = OBX_NO_RESOURCES;
+ }
+ else
+ {
+ *port_handle = p_cb->ll_cb.port.port_handle;
+ }
+ }
+ else
+ status = OBX_BAD_HANDLE;
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function OBX_SetPathReq
+**
+** Description This function sends a Set Path request to the connected server.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_BAD_HANDLE, if the handle is not valid.
+**
+*******************************************************************************/
+tOBX_STATUS OBX_SetPathReq(tOBX_HANDLE handle, UINT8 flags, BT_HDR *p_pkt)
+{
+ tOBX_CL_CB *p_cb = obx_cl_get_cb(handle);
+ tOBX_STATUS status = OBX_BAD_HANDLE;
+ UINT8 msg[OBX_HDR_OFFSET];
+ UINT8 *p = msg;
+ UINT8 good_flags = (OBX_SPF_BACKUP | OBX_SPF_NO_CREATE);
+
+ if (p_cb)
+ {
+ /* SetPath request packet always has the final bit set */
+ *p++ = (OBX_REQ_SETPATH | OBX_FINAL);
+ p += OBX_PKT_LEN_SIZE;
+ *p++ = (flags & good_flags); /* send only good flags */
+ *p++ = OBX_SETPATH_CONST;
+
+ /* add session sequence number, if session is active */
+ if (p_cb->sess_st == OBX_SESS_ACTIVE)
+ {
+ *p++ = OBX_HI_SESSION_SN;
+ *p++ = p_cb->ssn;
+ }
+
+ /* add connection ID, if needed */
+ if (p_cb->conn_id != OBX_INVALID_CONN_ID)
+ {
+ *p++ = OBX_HI_CONN_ID;
+ UINT32_TO_BE_STREAM(p, p_cb->conn_id);
+ }
+ p_pkt = obx_cl_prepend_msg(p_cb, p_pkt, msg, (UINT16)(p - msg) );
+ p_pkt->event = OBX_SETPATH_REQ_EVT;
+ obx_csm_event(p_cb, OBX_SETPATH_REQ_CEVT, p_pkt);
+ status = OBX_SUCCESS;
+ }
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function obx_prepend_req_msg
+**
+** Description This function is called to add request code and connection ID
+** to the given OBEX message
+** Returns void
+**
+*******************************************************************************/
+tOBX_STATUS obx_prepend_req_msg(tOBX_HANDLE handle, tOBX_CL_EVENT event, UINT8 req_code, BT_HDR *p_pkt)
+{
+ tOBX_STATUS status = OBX_SUCCESS;
+ tOBX_CL_CB *p_cb = obx_cl_get_cb(handle);
+ UINT8 msg[OBX_HDR_OFFSET];
+ UINT8 *p = msg;
+ UINT8 srm = 0;
+ UINT8 num_hdrs, num_body;
+
+ if (p_cb)
+ {
+ *p++ = req_code;
+ p += OBX_PKT_LEN_SIZE;
+
+ /* add session sequence number, if session is active */
+ if (p_cb->sess_st == OBX_SESS_ACTIVE)
+ {
+ *p++ = OBX_HI_SESSION_SN;
+ *p++ = p_cb->ssn;
+ }
+
+ req_code &= ~OBX_FINAL;
+
+ /* add connection ID, if needed */
+ if ((p_cb->conn_id != OBX_INVALID_CONN_ID) &&
+ /* always use connection ID in CONNECTED state or being challenged on operation */
+ ((p_cb->state == OBX_CS_CONNECTED) || (p_cb->state == OBX_CS_OP_UNAUTH) ||
+ /* always use connection ID for abort and disconnect. they may be out of sequence */
+ (req_code == OBX_REQ_ABORT) || (req_code == OBX_REQ_DISCONNECT)))
+ {
+ *p++ = OBX_HI_CONN_ID;
+ UINT32_TO_BE_STREAM(p, p_cb->conn_id);
+ }
+
+ /* add SRM header, if SRM is enabled */
+ if (p_cb->srm & OBX_SRM_ENABLE)
+ {
+ if (p_cb->state == OBX_CS_CONNECTED)
+ {
+ if(event == OBX_PUT_REQ_CEVT)
+ {
+ num_hdrs = OBX_ReadNumHdrs(p_pkt, &num_body);
+ OBX_TRACE_DEBUG2("num_hdrs:%d num_body:%d", num_hdrs, num_body);
+ if (num_hdrs == num_body)
+ {
+ OBX_TRACE_DEBUG0("it is left-over, drop it");
+ if (p_pkt)
+ GKI_freebuf (p_pkt);
+ return OBX_BAD_PARAMS;
+ }
+ srm = OBX_SRM_REQING | OBX_SRM_WAIT;
+ }
+ else if (event == OBX_GET_REQ_CEVT)
+ {
+ srm = OBX_SRM_REQING;
+ }
+
+ OBX_TRACE_DEBUG2("cb srm: 0x%x/0x%x", p_cb->srm, srm );
+ if (srm)
+ {
+ p_cb->srm |= srm;
+ *p++ = OBX_HI_SRM;
+ *p++ = OBX_HV_SRM_ENABLE;
+ }
+ }
+ }
+
+ p_pkt = obx_cl_prepend_msg(p_cb, p_pkt, msg, (UINT16)(p - msg) );
+ p_pkt->event = obx_sm_evt_to_api_evt[event];
+ obx_csm_event(p_cb, event, p_pkt);
+ }
+ else
+ status = OBX_BAD_HANDLE;
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function OBX_PutReq
+**
+** Description This function sends a Put request to the connected server.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_BAD_HANDLE, if the handle is not valid.
+**
+*******************************************************************************/
+tOBX_STATUS OBX_PutReq(tOBX_HANDLE handle, BOOLEAN final, BT_HDR *p_pkt)
+{
+ UINT8 req_code = OBX_REQ_PUT;
+ if (final)
+ req_code |= OBX_FINAL;
+ return obx_prepend_req_msg(handle, OBX_PUT_REQ_CEVT, req_code, p_pkt);
+
+}
+
+
+/*******************************************************************************
+**
+** Function OBX_GetReq
+**
+** Description This function sends a Get request to the connected server.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_BAD_HANDLE, if the handle is not valid.
+**
+*******************************************************************************/
+tOBX_STATUS OBX_GetReq(tOBX_HANDLE handle, BOOLEAN final, BT_HDR *p_pkt)
+{
+ UINT8 req_code = OBX_REQ_GET;
+ OBX_TRACE_API1("OBX_GetReq final: 0x%x", final );
+ if (final)
+ req_code |= OBX_FINAL;
+ return obx_prepend_req_msg(handle, OBX_GET_REQ_CEVT, req_code, p_pkt);
+}
+
+
+/*******************************************************************************
+**
+** Function OBX_AbortReq
+**
+** Description This function sends an Abort request to the connected server.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_BAD_HANDLE, if the handle is not valid.
+**
+*******************************************************************************/
+tOBX_STATUS OBX_AbortReq(tOBX_HANDLE handle, BT_HDR *p_pkt)
+{
+ /* Disconnect request always has the final bit set */
+ UINT8 req_code = (OBX_REQ_ABORT|OBX_FINAL);
+ return obx_prepend_req_msg(handle, OBX_ABORT_REQ_CEVT, req_code, p_pkt);
+}
+
+
+/*******************************************************************************
+**
+** Function OBX_DisconnectReq
+**
+** Description This function sends a Disconnect request to the connected server.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_BAD_HANDLE, if the handle is not valid.
+**
+*******************************************************************************/
+tOBX_STATUS OBX_DisconnectReq(tOBX_HANDLE handle, BT_HDR *p_pkt)
+{
+ /* Disconnect request always has the final bit set */
+ UINT8 req_code = (OBX_REQ_DISCONNECT|OBX_FINAL);
+ return obx_prepend_req_msg(handle, OBX_DISCNT_REQ_CEVT, req_code, p_pkt);
+}
+
+/*******************************************************************************
+**
+** Function OBX_ActionReq
+**
+** Description This function sends a Action request to the connected server.
+** The Name Header and DestName Header must be in p_pkt for
+** the Copy and Move Object action.
+** The Name header and Permission Header must be in p_pkt for
+** the Set Object Permission action.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_BAD_HANDLE, if the handle is not valid.
+**
+*******************************************************************************/
+tOBX_STATUS OBX_ActionReq(tOBX_HANDLE handle, tOBX_ACTION action_id, BT_HDR *p_pkt)
+{
+ /* Disconnect request always has the final bit set */
+ UINT8 req_code = (OBX_REQ_ACTION|OBX_FINAL);
+ UINT8 *p;
+
+ if (p_pkt == NULL)
+ {
+ OBX_TRACE_ERROR0("OBX_ActionReq must include Name & DestName Header for Copy/Move action" );
+ OBX_TRACE_ERROR0("OBX_ActionReq must include Name & Permission Header for Set Object Permission action" );
+ return OBX_BAD_PARAMS;
+ }
+
+ /* add the Action ID header before the other headers */
+ p_pkt->offset -= 2;
+ p_pkt->len += 2;
+ p = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ *p++ = OBX_HI_ACTION_ID;
+ *p++ = action_id;
+
+ return obx_prepend_req_msg(handle, OBX_ACTION_REQ_CEVT, req_code, p_pkt);
+}
diff --git a/stack/obx/obx_csm.c b/stack/obx/obx_csm.c
new file mode 100644
index 0000000..25447df
--- /dev/null
+++ b/stack/obx/obx_csm.c
@@ -0,0 +1,365 @@
+/*****************************************************************************
+**
+** Name: obx_csm.c
+**
+** File: OBEX Client State Machine and Control Block Access Functions
+**
+** Copyright (c) 2003-2009, Broadcom Corp., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include <string.h>
+#include "bt_target.h"
+#include "btu.h" /* for timer */
+#include "obx_int.h"
+
+/* OBEX Client Action Functions Enums (must match obx_cl_action [below] */
+enum
+{
+ OBX_CA_SND_REQ,
+ OBX_CA_NOTIFY,
+ OBX_CA_CONNECT_ERROR,
+ OBX_CA_STATE,
+ OBX_CA_CLOSE_PORT,
+ OBX_CA_CONNECT_FAIL,
+ OBX_CA_DISCNT_REQ,
+ OBX_CA_START_TIMER,
+ OBX_CA_FAIL_RSP,
+ OBX_CA_SND_PART,
+ OBX_CA_CONNECT_OK,
+ OBX_CA_SESSION_OK,
+ OBX_CA_SESSION_CONT,
+ OBX_CA_SESSION_GET,
+ OBX_CA_SESSION_FAIL,
+ OBX_CA_ABORT,
+ OBX_CA_SND_PUT_REQ,
+ OBX_CA_SND_GET_REQ,
+ OBX_CA_SRM_SND_REQ,
+ OBX_CA_SRM_PUT_REQ,
+ OBX_CA_SRM_GET_REQ,
+ OBX_CA_SRM_PUT_NOTIFY,
+ OBX_CA_SRM_GET_NOTIFY,
+ OBX_CA_SAVE_RSP,
+ OBX_CA_SAVE_REQ
+};
+
+/* OBEX Client Action Functions */
+static const tOBX_CL_ACT obx_cl_action[] =
+{
+ obx_ca_snd_req,
+ obx_ca_notify,
+ obx_ca_connect_error,
+ obx_ca_state,
+ obx_ca_close_port,
+ obx_ca_connect_fail,
+ obx_ca_discnt_req,
+ obx_ca_start_timer,
+ obx_ca_fail_rsp,
+ obx_ca_snd_part,
+ obx_ca_connect_ok,
+ obx_ca_session_ok,
+ obx_ca_session_cont,
+ obx_ca_session_get,
+ obx_ca_session_fail,
+ obx_ca_abort,
+ obx_ca_snd_put_req,
+ obx_ca_snd_get_req,
+ obx_ca_srm_snd_req,
+ obx_ca_srm_put_req,
+ obx_ca_srm_get_req,
+ obx_ca_srm_put_notify,
+ obx_ca_srm_get_notify,
+ obx_ca_save_rsp,
+ obx_ca_save_req
+};
+
+/************ OBX Client FSM State/Event Indirection Table **************/
+/* obx_csm_event() first looks at obx_csm_entry_map[][] to get an entry of the event of a particular state
+ * 0 means the event in the current state is ignored.
+ * a number with 0x80 bit set, use obx_cl_all_table[][] as the "state table".
+ * other numbers, look up obx_cl_main_state_table[] for the state table of current state.
+ *
+ * once the state table is determined,
+ * look up the "action" column to find the associated action function
+ * and the "next state" column to find the "next state" candidate.
+ *
+ * The actual next state could be either the state in the "next state" column
+ * or the state returned from the action function.
+ */
+static const UINT8 obx_csm_entry_map[][OBX_CS_MAX-1] =
+{
+/* state name: NtCon SesRs ConRs UnAut Conn DscRs OpUna StpRs ActRs AbtRs PutRs GetRs Put Get PutS GetS Part */
+/* CONN_R */{ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+/* SESS_R */{ 2, 0, 0, 0, 5, 0, 0, 0, 0, 0, 2, 2, 2, 2, 5, 5, 1 },
+/* DISCNT_R */{ 0, 0x87, 2, 0x87, 0x81, 0x87, 0x87, 0x81, 0x81, 0x81, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87 },
+/* PUT_R */{ 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0 },
+/* GET_R */{ 0, 3, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0 },
+/* SETPATH_R*/{ 0, 0, 0, 0, 3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+/* ACT_R */{ 0, 0, 0, 0, 6, 0, 5, 0, 0, 0, 0x82, 0x82, 0x82, 0x82, 3, 3, 1 },
+/* ABORT_R */{ 0, 0, 0, 0, 4, 0, 4, 0, 0, 0, 0x82, 0x82, 0x82, 0x82, 3, 3, 1 },
+/* OK_C */{ 0, 1, 3, 0, 0, 1, 0, 0x83, 0x83, 0x83, 0x83, 0x83, 0, 0, 0x83, 0x83, 3 },
+/* CONT_C */{ 0, 2, 0, 0, 0, 2, 0, 0, 0, 1, 1, 1, 0, 0, 4, 4, 3 },
+/* FAIL_C */{ 0, 4, 1, 0, 0, 0x87, 0, 0x86, 0x86, 2, 0x86, 0x86, 0, 0, 0x86, 0x86, 3 },
+/* PORT_CLS */{ 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84 },
+/* TX_EMPTY */{ 0x87, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+/* FCS_SET */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 },
+/* STATE */{ 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85 },
+/* TIMEOUT */{ 3, 2, 0x87, 0, 0, 0x87, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+};
+
+static const UINT8 obx_cl_all_table[][OBX_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* DISCNT_R */{OBX_CA_SND_REQ, OBX_CS_DISCNT_REQ_SENT },
+/* ABORT_R */{OBX_CA_SND_REQ, OBX_CS_ABORT_REQ_SENT },
+/* OK_C */{OBX_CA_NOTIFY, OBX_CS_NULL },
+/* PORT_CLS */{OBX_CA_CONNECT_ERROR, OBX_CS_NOT_CONNECTED },
+/* STATE */{OBX_CA_STATE, OBX_CS_NULL },
+/* FAIL_C */{OBX_CA_FAIL_RSP, OBX_CS_NULL },
+/* end */{OBX_CA_CLOSE_PORT, OBX_CS_NOT_CONNECTED }
+};
+
+static const UINT8 obx_cl_not_conn_table[][OBX_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* CONN_R */{OBX_CA_SND_REQ, OBX_CS_CONNECT_REQ_SENT },
+/* SESS_R */{OBX_CA_SND_REQ, OBX_CS_SESSION_REQ_SENT },
+/* TIMEOUT */{OBX_CA_SESSION_FAIL, OBX_CS_NOT_CONNECTED }
+};
+
+static const UINT8 obx_cl_sess_rs_table[][OBX_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* OK_C */{OBX_CA_SESSION_OK, OBX_CS_NOT_CONNECTED },
+/* CONT_C */{OBX_CA_SESSION_CONT, OBX_CS_SESSION_REQ_SENT },
+/* GET_R */{OBX_CA_SESSION_GET, OBX_CS_SESSION_REQ_SENT },
+/* FAIL_C */{OBX_CA_SESSION_FAIL, OBX_CS_NOT_CONNECTED }
+};
+
+static const UINT8 obx_cl_conn_rs_table[][OBX_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* FAIL_C */{OBX_CA_CONNECT_FAIL, OBX_CS_UNAUTH },
+/* DISCNT_R */{OBX_CA_DISCNT_REQ, OBX_CS_NULL },
+/* OK_C */{OBX_CA_CONNECT_OK, OBX_CS_NULL }
+};
+
+static const UINT8 obx_cl_unauth_table[][OBX_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* CONN_R */{OBX_CA_SND_REQ, OBX_CS_CONNECT_REQ_SENT }
+};
+
+static const UINT8 obx_cl_conn_table[][OBX_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* PUT_R */{OBX_CA_SND_PUT_REQ, OBX_CS_PUT_REQ_SENT },
+/* GET_R */{OBX_CA_SND_GET_REQ, OBX_CS_GET_REQ_SENT },
+/* SETPATH_R*/{OBX_CA_SND_REQ, OBX_CS_SETPATH_REQ_SENT },
+/* ABORT_R */{OBX_CA_ABORT, OBX_CS_CONNECTED },
+/* SESS_R */{OBX_CA_SND_REQ, OBX_CS_SESSION_REQ_SENT },
+/* ACT_R */{OBX_CA_SND_REQ, OBX_CS_ACTION_REQ_SENT }
+};
+
+static const UINT8 obx_cl_discnt_rs_table[][OBX_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* OK_C */{OBX_CA_NOTIFY, OBX_CS_NOT_CONNECTED }, /* and close port */
+/* CONT_C */{OBX_CA_START_TIMER, OBX_CS_DISCNT_REQ_SENT }
+};
+
+static const UINT8 obx_cl_op_unauth_table[][OBX_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* PUT_R */{OBX_CA_SND_REQ, OBX_CS_PUT_REQ_SENT },
+/* GET_R */{OBX_CA_SND_REQ, OBX_CS_GET_REQ_SENT },
+/* SETPATH_R*/{OBX_CA_SND_REQ, OBX_CS_SETPATH_REQ_SENT },
+/* ABORT_R */{OBX_SM_NO_ACTION, OBX_CS_CONNECTED },
+/* ACT_R */{OBX_CA_SND_REQ, OBX_CS_ACTION_REQ_SENT }
+};
+
+/* static const UINT8 obx_cl_setpath_rs_table[][OBX_SM_NUM_COLS] = { */
+/* Event Action Next State */
+/* DISCNT_R {OBX_CA_SND_REQ, OBX_CS_DISCNT_REQ_SENT },*/
+/* OK_C {OBX_CA_NOTIFY, OBX_CS_NULL },*/
+/* FAIL_C {OBX_CA_FAIL_RSP, OBX_CS_NULL },*/
+/* PORT_CLS {OBX_CA_CONNECT_ERROR, OBX_CS_NOT_CONNECTED },*/
+/* STATE {OBX_CA_STATE, OBX_CS_NULL },*/
+/* }; */
+
+static const UINT8 obx_cl_abort_rs_table[][OBX_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* CONT_C */{OBX_CA_START_TIMER, OBX_CS_ABORT_REQ_SENT },
+/* FAIL_C */{OBX_CA_NOTIFY, OBX_CS_CONNECTED }
+};
+
+static const UINT8 obx_cl_put_rs_table[][OBX_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* CONT_C */{OBX_CA_NOTIFY, OBX_CS_PUT_TRANSACTION },
+/* SESS_R */{OBX_CA_SND_REQ, OBX_CS_SESSION_REQ_SENT }
+};
+
+static const UINT8 obx_cl_get_rs_table[][OBX_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* CONT_C */{OBX_CA_NOTIFY, OBX_CS_GET_TRANSACTION },
+/* SESS_R */{OBX_CA_SND_REQ, OBX_CS_SESSION_REQ_SENT }
+};
+
+static const UINT8 obx_cl_put_table[][OBX_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* PUT_R */{OBX_CA_SND_REQ, OBX_CS_PUT_REQ_SENT },
+/* SESS_R */{OBX_CA_SND_REQ, OBX_CS_SESSION_REQ_SENT }
+};
+
+static const UINT8 obx_cl_get_table[][OBX_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* GET_R */{OBX_CA_SND_REQ, OBX_CS_GET_REQ_SENT },
+/* SESS_R */{OBX_CA_SND_REQ, OBX_CS_SESSION_REQ_SENT }
+};
+
+static const UINT8 obx_cl_put_s_table[][OBX_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* DISCNT_R */{OBX_CA_SRM_SND_REQ, OBX_CS_DISCNT_REQ_SENT },
+/* PUT_R */{OBX_CA_SRM_PUT_REQ, OBX_CS_PUT_SRM },
+/* ABORT_R */{OBX_CA_SRM_SND_REQ, OBX_CS_ABORT_REQ_SENT },
+/* CONT_C */{OBX_CA_SRM_PUT_NOTIFY, OBX_CS_PUT_SRM },
+/* SESS_R */{OBX_CA_SND_REQ, OBX_CS_SESSION_REQ_SENT }
+};
+
+static const UINT8 obx_cl_get_s_table[][OBX_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* DISCNT_R */{OBX_CA_SRM_SND_REQ, OBX_CS_DISCNT_REQ_SENT },
+/* GET_R */{OBX_CA_SRM_GET_REQ, OBX_CS_GET_SRM },
+/* ABORT_R */{OBX_CA_SRM_SND_REQ, OBX_CS_ABORT_REQ_SENT },
+/* CONT_C */{OBX_CA_SRM_GET_NOTIFY, OBX_CS_GET_SRM },
+/* SESS_R */{OBX_CA_SND_REQ, OBX_CS_SESSION_REQ_SENT }
+};
+
+static const UINT8 obx_cl_part_table[][OBX_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* ABORT_R */{OBX_CA_SAVE_REQ, OBX_CS_PARTIAL_SENT },
+/* FCS_SET */{OBX_CA_SND_PART, OBX_CS_NULL },
+/* FAIL_C */{OBX_CA_SAVE_RSP, OBX_CS_NULL }
+};
+
+static const tOBX_SM_TBL obx_cl_main_state_table[] = {
+ obx_cl_not_conn_table,
+ obx_cl_sess_rs_table,
+ obx_cl_conn_rs_table,
+ obx_cl_unauth_table,
+ obx_cl_conn_table,
+ obx_cl_discnt_rs_table,
+ obx_cl_op_unauth_table,
+ NULL, /* obx_cl_setpath_rs_table */
+ NULL, /* obx_cl_action_rs_table */
+ obx_cl_abort_rs_table,
+ obx_cl_put_rs_table,
+ obx_cl_get_rs_table,
+ obx_cl_put_table,
+ obx_cl_get_table,
+ obx_cl_put_s_table,
+ obx_cl_get_s_table,
+ obx_cl_part_table
+};
+
+/*******************************************************************************
+**
+** Function obx_csm_event
+**
+** Description Handle events to the client state machine. It looks up the entry
+** in the obx_csm_entry_map array. If it is a valid entry, it gets
+** the state table. Set the next state, if not NULL state.Execute
+** the action function according to the state table. If the state
+** returned by action function is not NULL state, adjust the new
+** state to the returned state.If (api_evt != MAX), call callback
+** function.
+**
+** Returns void.
+**
+*******************************************************************************/
+void obx_csm_event(tOBX_CL_CB *p_cb, tOBX_CL_EVENT event, BT_HDR *p_msg)
+{
+ UINT8 curr_state = p_cb->state;
+ tOBX_SM_TBL state_table = NULL;
+ UINT8 action, entry;
+ tOBX_CL_STATE act_state = OBX_CS_NULL;
+ UINT8 prev_state = OBX_CS_NULL;
+
+ if( curr_state == OBX_CS_NULL || curr_state >= OBX_CS_MAX)
+ {
+ OBX_TRACE_WARNING1( "Invalid state: %d", curr_state) ;
+ if(p_msg)
+ GKI_freebuf(p_msg);
+ return;
+ }
+ OBX_TRACE_DEBUG4( "Client Handle 0x%x, State: %s, event: %s srm:0x%x",
+ p_cb->ll_cb.comm.handle, obx_cl_get_state_name( p_cb->state ), obx_cl_get_event_name(event), p_cb->srm ) ;
+ OBX_TRACE_DEBUG1("obx_csm_event csm offset:%d", p_cb->param.sess.obj_offset);
+
+ /* look up the state table for the current state */
+ /* lookup entry /w event & curr_state */
+ /* If entry is ignore, return.
+ * Otherwise, get state table (according to curr_state or all_state) */
+ if( (entry = obx_csm_entry_map[event][curr_state-1]) != OBX_SM_IGNORE )
+ {
+ if(entry&OBX_SM_ALL)
+ {
+ entry &= OBX_SM_ENTRY_MASK;
+ state_table = obx_cl_all_table;
+ }
+ else
+ state_table = obx_cl_main_state_table[curr_state-1];
+ }
+
+ if( entry == OBX_SM_IGNORE || state_table == NULL)
+ {
+ OBX_TRACE_WARNING4( "Ignore event %s(%d) in state %s(%d)",
+ obx_cl_get_event_name(event), event, obx_cl_get_state_name(curr_state), curr_state );
+ if(p_msg)
+ GKI_freebuf(p_msg);
+ return;
+ }
+
+ /* Get possible next state from state table. */
+ if( state_table[entry-1][OBX_SME_NEXT_STATE] != OBX_CS_NULL )
+ {
+ prev_state = p_cb->state;
+ p_cb->state = state_table[entry-1][OBX_SME_NEXT_STATE];
+ if (prev_state != p_cb->state)
+ {
+ p_cb->prev_state = prev_state;
+ OBX_TRACE_DEBUG1( "saved state1:%s", obx_cl_get_state_name(p_cb->prev_state));
+ }
+ }
+ OBX_TRACE_DEBUG1( "possible new state = %s", obx_cl_get_state_name( p_cb->state ) ) ;
+
+ /* If action is not ignore, clear param, exec action and get next state.
+ * The action function may set the Param for cback.
+ * Depending on param, call cback or free buffer. */
+ /* execute action */
+ action = state_table[entry-1][OBX_SME_ACTION];
+ if (action != OBX_SM_NO_ACTION)
+ {
+ act_state = (*obx_cl_action[action])(p_cb, p_msg);
+ }
+
+ /* adjust next state, if it needs to use the new state returned from action function */
+ if( act_state != OBX_CS_NULL)
+ {
+ prev_state = p_cb->state;
+ p_cb->state = act_state;
+ OBX_TRACE_DEBUG1( "new state = %s (action)", obx_cl_get_state_name( p_cb->state )) ;
+ if (prev_state != p_cb->state)
+ {
+ p_cb->prev_state = prev_state;
+ OBX_TRACE_DEBUG1( "saved state2:%s", obx_cl_get_state_name(p_cb->prev_state));
+ }
+ }
+
+ if(p_cb->api_evt)
+ {
+ (p_cb->p_cback) (p_cb->ll_cb.comm.handle, p_cb->api_evt, p_cb->rsp_code, p_cb->param, p_msg);
+ p_cb->api_evt = OBX_NULL_EVT;
+ p_cb->rsp_code = 0;
+ memset(&p_cb->param, 0, sizeof (p_cb->param) );
+ }
+ else if(action == OBX_SM_NO_ACTION && p_msg)
+ GKI_freebuf(p_msg);
+ OBX_TRACE_DEBUG1("after csm offset:%d", p_cb->param.sess.obj_offset);
+
+ OBX_TRACE_DEBUG2( "result state = %s/%d", obx_cl_get_state_name( p_cb->state ), p_cb->state ) ;
+}
+
+
diff --git a/stack/obx/obx_int.h b/stack/obx/obx_int.h
new file mode 100644
index 0000000..8d4a7f6
--- /dev/null
+++ b/stack/obx/obx_int.h
@@ -0,0 +1,602 @@
+/*****************************************************************************
+**
+** Name: obx_int.h
+**
+** File: OBEX Internal header file
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#ifndef OBX_INT_H
+#define OBX_INT_H
+
+#include "bt_target.h"
+#include "obx_api.h"
+#include "gki.h"
+
+#define OBX_DEFAULT_TARGET_LEN 0xFF
+#define OBX_INITIAL_CONN_ID 0x1
+
+/* the rules for OBX handles: (some of the definitions are in obx_api.h)
+ *
+ * tOBX_HANDLE is UINT16
+ * It was UINT8, the support for multiple clients on the same SCN for MAP is required
+ *
+ * LSB (0x00FF) is the same as the old definition.
+ * The 0x80 bit (OBX_CL_HANDLE_MASK) is set for client connections.
+ * The 0x40 bit (OBX_HANDLE_RX_MTU_MASK) is used internally for RFCOMM to allocate a buffer to receive data
+ *
+ * The MSB (0xFF00) is used for enhancements add for BTE release 3.15
+ * This byte is the session index; used for server only.
+ */
+
+#define OBX_CL_HANDLE_MASK 0x80
+#define OBX_CL_CB_IND_MASK 0x007F
+#define OBX_HANDLE_RX_MTU_MASK 0x40
+#define OBX_LOCAL_NONCE_SIZE OBX_MIN_NONCE_SIZE /* 4 - 16 per IrOBEX spec. local nonce is always 4 */
+
+#define OBX_MAX_EVT_MAP_NUM (OBX_ABORT_REQ_SEVT+1)
+
+#define OBX_PORT_EVENT_MASK (PORT_EV_RXCHAR | PORT_EV_TXEMPTY | \
+ PORT_EV_FC | PORT_EV_FCS)
+
+#define OBX_BAD_SM_EVT 0xFF
+
+/* for wait_auth flag */
+#define OBX_WAIT_AUTH_FAIL 2
+
+enum
+{
+ OBX_CS_NULL, /* 0 0 */
+ OBX_CS_NOT_CONNECTED, /* 1 1 */
+ OBX_CS_SESSION_REQ_SENT, /* 2 */
+ OBX_CS_CONNECT_REQ_SENT, /* 3 2 */
+ OBX_CS_UNAUTH, /* 4 3 */
+ OBX_CS_CONNECTED, /* 5 4 */
+ OBX_CS_DISCNT_REQ_SENT, /* 6 5 */
+ OBX_CS_OP_UNAUTH, /* 7 6 */
+ OBX_CS_SETPATH_REQ_SENT, /* 8 7 */
+ OBX_CS_ACTION_REQ_SENT, /* 9 */
+ OBX_CS_ABORT_REQ_SENT, /*10 8 */
+ OBX_CS_PUT_REQ_SENT, /*11 9 */
+ OBX_CS_GET_REQ_SENT, /*12 10 */
+ OBX_CS_PUT_TRANSACTION, /*13 11 */
+ OBX_CS_GET_TRANSACTION, /*14 12 */
+ OBX_CS_PUT_SRM, /*15 */
+ OBX_CS_GET_SRM, /*16 */
+ OBX_CS_PARTIAL_SENT, /*17 13 */
+ OBX_CS_MAX
+};
+
+typedef UINT8 tOBX_CL_STATE;
+#define OBX_CL_STATE_DROP 0x80 /* this is used only in session_info[] to mark link drop suspend*/
+
+enum
+{
+ OBX_CONNECT_REQ_CEVT, /* API call to send a CONNECT request. */
+ OBX_SESSION_REQ_CEVT, /* API call to send a SESSION request. */
+ OBX_DISCNT_REQ_CEVT, /* API call to send a DISCONNECT request. */
+ OBX_PUT_REQ_CEVT, /* API call to send a PUT request. */
+ OBX_GET_REQ_CEVT, /* API call to send a GET request.*/
+ OBX_SETPATH_REQ_CEVT, /* API call to send a SETPATH request. */
+ OBX_ACTION_REQ_CEVT, /* API call to send an ACTION request. */
+ OBX_ABORT_REQ_CEVT, /* API call to send an ABORT request. */
+ OBX_OK_CFM_CEVT, /* Received success response from server. */
+ OBX_CONT_CFM_CEVT, /* Received continue response from server. */
+ OBX_FAIL_CFM_CEVT, /* Received failure response from server. */
+ OBX_PORT_CLOSE_CEVT, /* Transport is closed. */
+ OBX_TX_EMPTY_CEVT, /* Transmit Queue Empty */
+ OBX_FCS_SET_CEVT, /* Data flow enable */
+ OBX_STATE_CEVT, /* Change state. */
+ OBX_TIMEOUT_CEVT, /* Timeout occurred. */
+ OBX_MAX_CEVT
+};
+typedef UINT8 tOBX_CL_EVENT;
+
+#define OBX_MAX_API_CEVT OBX_ABORT_REQ_CEVT
+
+enum
+{
+ OBX_CONNECT_REQ_SEVT, /* 1 1 Received CONNECT request from client. */
+ OBX_SESSION_REQ_SEVT, /* 2 Received SESSION request from client. */
+ OBX_DISCNT_REQ_SEVT, /* 3 2 Received DISCONNECT request from client. */
+ OBX_PUT_REQ_SEVT, /* 4 3 Received PUT request from client. */
+ OBX_GET_REQ_SEVT, /* 5 4 Received GET request from client. */
+ OBX_SETPATH_REQ_SEVT, /* 6 5 Received SETPATH request from client. */
+ OBX_ACTION_REQ_SEVT, /* 7 Received ACTION request from client. */
+ OBX_ABORT_REQ_SEVT, /* 8 6 Received ABORT request from client. */
+ OBX_CONNECT_CFM_SEVT, /* 9 7 API call to send a CONNECT response. */
+ OBX_SESSION_CFM_SEVT, /*10 API call to send a SESSION response. */
+ OBX_DISCNT_CFM_SEVT, /*11 8 API call to send a DISCONNECT response or close the connection to the client. */
+ OBX_PUT_CFM_SEVT, /*12 9 API call to send a PUT response. */
+ OBX_GET_CFM_SEVT, /*13 10 API call to send a GET response. */
+ OBX_SETPATH_CFM_SEVT, /*14 11 API call to send a SETPATH response. */
+ OBX_ACTION_CFM_SEVT, /*15 API call to send an ACTION response. */
+ OBX_ABORT_CFM_SEVT, /*16 12 API call to send an ABORT response. */
+ OBX_PORT_CLOSE_SEVT, /*17 13 Transport is closed. */
+ OBX_FCS_SET_SEVT, /*18 14 Data flow enable */
+ OBX_STATE_SEVT, /*19 15 Change state. */
+ OBX_TIMEOUT_SEVT, /*20 16 Timeout has occurred. */
+ OBX_BAD_REQ_SEVT, /*21 17 Received a bad request from client. */
+ OBX_TX_EMPTY_SEVT, /*22 18 Transmit Queue Empty */
+ OBX_MAX_SEVT
+};
+typedef UINT8 tOBX_SR_EVENT;
+
+#define OBX_SEVT_DIFF_REQ_CFM (OBX_CONNECT_CFM_SEVT - OBX_CONNECT_REQ_SEVT) /* the index difference between *REQ_SEVT and *CFM_SEVT */
+#define OBX_SEVT_MAX_REQ OBX_ACTION_REQ_SEVT /* last *REQ_SEVT */
+
+enum
+{
+ OBX_SS_NULL, /* 0 0 */
+ OBX_SS_NOT_CONNECTED, /* 1 1 */
+ OBX_SS_SESS_INDICATED, /* 2 */
+ OBX_SS_CONN_INDICATED, /* 3 2 */
+ OBX_SS_WAIT_AUTH, /* 4 3 */
+ OBX_SS_AUTH_INDICATED, /* 5 4 */
+ OBX_SS_CONNECTED, /* 6 5 */
+ OBX_SS_DISCNT_INDICATED, /* 7 6 */
+ OBX_SS_SETPATH_INDICATED, /* 8 7 */
+ OBX_SS_ACTION_INDICATED, /* 9 */
+ OBX_SS_ABORT_INDICATED, /*10 8 */
+ OBX_SS_PUT_INDICATED, /*11 9 */
+ OBX_SS_GET_INDICATED, /*12 10 */
+ OBX_SS_PUT_TRANSACTION, /*13 11 */
+ OBX_SS_GET_TRANSACTION, /*14 12 */
+ OBX_SS_PUT_SRM, /*15 */
+ OBX_SS_GET_SRM, /*16 */
+ OBX_SS_PARTIAL_SENT, /*17 13 */
+ OBX_SS_WAIT_CLOSE, /*18 14 */
+ OBX_SS_MAX
+};
+typedef UINT8 tOBX_SR_STATE;
+
+typedef UINT8 tOBX_STATE; /* this must be the same type as tOBX_SR_STATE and tOBX_CL_STATE */
+
+typedef struct
+{
+ UINT16 pkt_len;/* the packet length */
+ UINT8 code; /* the response/request code with the final bit */
+ UINT8 sm_evt; /* The state machine event*/
+} tOBX_RX_HDR;
+
+typedef void (tOBX_CLOSE_FN) (UINT16);
+typedef BOOLEAN (tOBX_SEND_FN) (void *p_cb);
+typedef UINT8 (*tOBX_VERIFY_OPCODE)(UINT8 opcode, tOBX_RX_HDR *p_rxh);
+
+#define OBX_SRM_NO 0x00 /* SRM is not enabled and not engaged */
+#define OBX_SRM_ENABLE 0x01 /* SRM is enabled. */
+#define OBX_SRM_PARAM_AL 0x02 /* SRMP is allowed only in the beginning of a transaction */
+#define OBX_SRM_REQING 0x04 /* requesting/requested to enable SRM. */
+#define OBX_SRM_ABORT 0x08 /* (server) abort/reject at SRM GET/PUT rsp API*/
+#define OBX_SRM_ENGAGE 0x10 /* SRM is engaged. */
+#define OBX_SRM_NEXT 0x20 /* peer is ready for next packet. */
+#define OBX_SRM_WAIT 0x40 /* wait for peer. */
+#define OBX_SRM_WAIT_UL 0x80 /* wait for upper layer. */
+typedef UINT8 tOBX_SRM;
+
+#define OBX_SRMP_WAIT 0x40 /* wait for peer */
+#define OBX_SRMP_NONF 0x80 /* handle GET non-final (used by server only) */
+#define OBX_SRMP_NONF_EVT 0x20 /* report GET non-final req event (used by server only) */
+#define OBX_SRMP_SESS_FST 0x01 /* mark the session resume. The SSN on first req might not match */
+typedef UINT8 tOBX_SRMP;
+
+/* continue to define tOBX_SESS_ST for internal use */
+enum
+{
+ OBX_SESS_TIMEOUT = OBX_SESS_EXT_MAX, /* 0x03 session is requested/set timeout. */
+ OBX_SESS_CREATE, /* 0x04 session is requested/create. */
+ OBX_SESS_SUSPEND, /* 0x05 session is requested/suspend. */
+ OBX_SESS_RESUME, /* 0x06 session is requested/resume. */
+ OBX_SESS_CLOSE, /* 0x07 session is requested/close. */
+ OBX_SESS_SUSPENDING /* 0x08 session is requested/suspend: server has not reported the suspend event */
+};
+#define OBX_SESS_DROP (0x80|OBX_SESS_SUSPENDED) /* the session as suspended by link drop */
+
+/* port control block */
+typedef struct
+{
+ tOBX_HANDLE handle; /* The handle of the client or session handle for server */
+ UINT16 port_handle; /* Port handle of connection */
+ UINT16 tx_mtu; /* The MTU of the connected peer */
+ UINT16 rx_mtu; /* The MTU of this instance */
+ TIMER_LIST_ENT tle; /* This session's Timer List Entry */
+ tOBX_CLOSE_FN *p_close_fn; /* the close connection function */
+ tOBX_SEND_FN *p_send_fn; /* the send message function */
+ BT_HDR *p_txmsg; /* The message to send to peer */
+ BUFFER_Q rx_q; /* received data buffer queue */
+ BOOLEAN stopped; /* TRUE, if flow control the peer (stop peer from sending more data). */
+ BT_HDR *p_rxmsg; /* The message received from peer */
+} tOBX_PORT_CB;
+
+typedef struct
+{
+ tOBX_PORT_CB *p_pcb; /* the port control block */
+ UINT32 code; /* the event code from RFCOMM */
+} tOBX_PORT_EVT;
+
+/* l2cap control block */
+typedef struct
+{
+ tOBX_HANDLE handle; /* The handle of the client or session handle for server */
+ UINT16 lcid; /* l2cap lcid of connection */
+ UINT16 tx_mtu; /* The MTU of the connected peer */
+ UINT16 rx_mtu; /* The MTU of this instance */
+ TIMER_LIST_ENT tle; /* This session's Timer List Entry */
+ tOBX_CLOSE_FN *p_close_fn; /* the close connection function */
+ tOBX_SEND_FN *p_send_fn; /* the send message function */
+ BT_HDR *p_txmsg; /* The message to send to peer */
+ BUFFER_Q rx_q; /* received data buffer queue */
+ BOOLEAN stopped; /* TRUE, if flow control the peer (stop peer from sending more data). */
+ UINT8 ch_state; /* L2CAP channel state */
+ UINT8 ch_flags; /* L2CAP configuration flags */
+ BOOLEAN cong; /* TRUE, if L2CAP is congested. */
+} tOBX_L2C_CB;
+
+enum
+{
+ OBX_L2C_EVT_CONG,
+ OBX_L2C_EVT_CLOSE,
+ OBX_L2C_EVT_CONN_IND,
+ OBX_L2C_EVT_DATA_IND,
+ OBX_L2C_EVT_RESUME
+};
+typedef UINT8 tOBX_L2C_EVT;
+
+typedef struct
+{
+ BD_ADDR bd_addr;
+ UINT16 lcid;
+ UINT16 psm;
+ UINT8 id;
+} tOBX_L2C_IND;
+
+typedef union
+{
+ tOBX_L2C_IND conn_ind;
+ BOOLEAN is_cong;
+ BT_HDR *p_pkt;
+ UINT8 any;
+ BD_ADDR remote_addr;
+} tOBX_L2C_EVT_PARAM;
+
+typedef struct
+{
+ tOBX_L2C_CB *p_l2cb; /* the L2CAP control block */
+ tOBX_L2C_EVT_PARAM param;
+ tOBX_L2C_EVT l2c_evt; /* the event code from L2CAP */
+} tOBX_L2C_EVT_MSG;
+
+/* common of port & l2cap control block */
+typedef struct
+{
+ tOBX_HANDLE handle; /* The handle of the client or session handle for server */
+ UINT16 id; /* l2cap lcid or port handle */
+ UINT16 tx_mtu; /* The MTU of the connected peer */
+ UINT16 rx_mtu; /* The MTU of this instance */
+ TIMER_LIST_ENT tle; /* This session's Timer List Entry */
+ tOBX_CLOSE_FN *p_close_fn; /* the close connection function */
+ tOBX_SEND_FN *p_send_fn; /* the send message function */
+ BT_HDR *p_txmsg; /* The message to send to peer */
+ BUFFER_Q rx_q; /* received data buffer queue */
+ BOOLEAN stopped; /* TRUE, if flow control the peer (stop peer from sending more data). */
+} tOBX_COMM_CB;
+
+/* lower layer control block */
+typedef union
+{
+ tOBX_PORT_CB port;
+ tOBX_L2C_CB l2c;
+ tOBX_COMM_CB comm;
+} tOBX_LL_CB;
+
+/* client control block */
+typedef struct
+{
+ tOBX_CL_CBACK *p_cback; /* Application callback function to receive events */
+ BT_HDR *p_next_req; /* This is used when the session is flow controlled by peer
+ * and a DISCONNECT or ABORT request is sent.*/
+ BT_HDR *p_saved_req; /* Client saves a copy of the request sent to the server
+ * Just in case the operation is challenged by the server */
+ BT_HDR *p_auth; /* The request-digest string, if challenging the server.
+ * The received OBEX packet, if waiting for password */
+ tOBX_LL_CB ll_cb; /* lower layer control block for this client */
+ UINT32 conn_id; /* Connection ID for this connection */
+ UINT32 nonce; /* This is converted to UINT8[16] internally before adding to the OBEX header. This value is copied to the server control block and is increased after each use. 0, if only legacy OBEX (unreliable) session is desired. */
+ BD_ADDR peer_addr; /* peer address */
+ tOBX_EVT_PARAM param; /* The event parameter. */
+ UINT8 sess_info[OBX_SESSION_INFO_SIZE]; /* session id + local nonce */
+ tOBX_EVENT api_evt; /* Set the API event, if need to notify user outside of action function. */
+ tOBX_CL_STATE state; /* The current state */
+ tOBX_STATE next_state; /* Use by PART state to return to regular states */
+ tOBX_CL_STATE prev_state; /* The previous state */
+ UINT16 psm; /* L2CAP virtual psm */
+ tOBX_SRM srm; /* Single Response Mode */
+ tOBX_SRMP srmp; /* Single Response Mode Parameter */
+ UINT8 ssn; /* Session Sequence number */
+ tOBX_SESS_ST sess_st; /* Session state */
+ UINT8 rsp_code; /* The response code of the response packet */
+ BOOLEAN final; /* The final bit status of last request */
+ BOOLEAN wait_auth; /* TRUE, if challenges the server and is waiting for the response */
+} tOBX_CL_CB;
+
+/* Authentication Control block */
+typedef struct
+{
+ UINT32 nonce; /* Timestamp used as nonce */
+ tOBX_AUTH_OPT auth_option; /* Authentication option */
+ UINT8 realm_len; /* The length of p_realm */
+ UINT8 realm[1]; /* The realm of this server. Charset is the first byte */
+} tOBX_AUTH_PARAMS;
+
+/* suspend control block */
+typedef struct
+{
+ TIMER_LIST_ENT stle; /* The timer for suspended session timeout */
+ BD_ADDR peer_addr; /* peer address */
+ UINT8 sess_info[OBX_SESSION_INFO_SIZE]; /* session id + local nonce + conn id + state + srm */
+ UINT32 offset; /* the file offset */
+ tOBX_SR_STATE state; /* The current state */
+ UINT8 ssn; /* the last ssn */
+} tOBX_SPND_CB;
+
+/* server control block */
+typedef struct
+{
+ tOBX_SR_CBACK *p_cback; /* Application callback function to receive events */
+ tOBX_TARGET target; /* target header of this server */
+ tOBX_AUTH_PARAMS *p_auth; /* A GKI buffer that holds the authentication related parameters */
+ UINT8 sess[OBX_MAX_SR_SESSION]; /* index + 1 of sr_sess[]. 0, if not used. */
+ tOBX_SPND_CB *p_suspend; /* the information for suspended sessions (GKI buffer) */
+ UINT32 nonce; /* This is converted to UINT8[16] internally before adding to the OBEX header. This value is copied to the server control block and is increased after each use. 0, if only legacy OBEX (unreliable) session is desired. */
+ UINT16 psm; /* PSM for this server */
+ UINT8 max_suspend; /* the max number of tOBX_SPD_CB[] in p_suspend. must be less than OBX_MAX_SUSPEND_SESSIONS */
+ UINT8 scn; /* SCN for this server */
+ UINT8 num_sess; /* Max number of session control blocks used by this server*/
+} tOBX_SR_CB;
+
+/* server session control block */
+typedef struct
+{
+ BT_HDR *p_saved_msg; /* This is a message saved for authentication or GetReq-non-final */
+ BT_HDR *p_next_req; /* This is a message saved for flow control reasons */
+ tOBX_LL_CB ll_cb; /* lower layer control block for this session */
+ UINT32 conn_id; /* Connection ID for this connection */
+ BD_ADDR peer_addr; /* peer address */
+ UINT8 sess_info[OBX_SESSION_INFO_SIZE]; /* session id + local nonce */
+ tOBX_SR_STATE state; /* The current state */
+ tOBX_SR_STATE prev_state; /* The previous state */
+ tOBX_STATE next_state; /* Use by PART state to return to regular states */
+ tOBX_HANDLE handle; /* The obx handle for server */
+ tOBX_EVENT api_evt; /* The event to notify the API user. */
+ tOBX_EVT_PARAM param; /* The event parameter. */
+ tOBX_SRMP srmp; /* Single Response Mode Parameter */
+ tOBX_SRM srm; /* Single Response Mode */
+ tOBX_SESS_ST sess_st; /* Session state */
+ UINT8 ssn; /* Next Session Sequence number */
+ UINT8 cur_op; /* The op code for the current transaction (keep this for Abort reasons) */
+ /* set to the current OP (non-abort) in rfc.c, set it to abort when a response is sent */
+} tOBX_SR_SESS_CB;
+
+typedef struct
+{
+#if (OBX_SERVER_INCLUDED == TRUE)
+ tOBX_SR_CB server[OBX_NUM_SERVERS];/* The server control blocks */
+ UINT32 next_cid; /* Next OBEX connection ID for server */
+ tOBX_SR_SESS_CB sr_sess[OBX_NUM_SR_SESSIONS];
+ tOBX_L2C_CB sr_l2cb; /* for obx_l2c_connect_ind_cback */
+#endif
+
+#if (OBX_CLIENT_INCLUDED == TRUE)
+ tOBX_CL_CB client[OBX_NUM_CLIENTS];/* The client control blocks */
+ tOBX_PORT_CB *p_temp_pcb; /* Valid only during client RFCOMM_CreateConnection call */
+ UINT8 next_ind; /* The index to the next client control block */
+#endif
+
+ tOBX_HANDLE hdl_map[MAX_RFC_PORTS]; /* index of this array is the port_handle,
+ * the value is the OBX handle */
+ UINT16 l2c_map[MAX_L2CAP_CHANNELS]; /* index of this array is (lcid - L2CAP_BASE_APPL_CID) */
+ UINT32 timeout_val; /* The timeout value to wait for activity from peer */
+ UINT32 sess_tout_val; /* The timeout value for reliable sessions to remain in suspend */
+ UINT8 trace_level; /* The default trace level */
+ UINT8 num_client; /* Number of client control blocks */
+ UINT8 num_server; /* Number of server control blocks */
+ UINT8 num_sr_sess; /* Number of server session control blocks */
+ UINT8 max_rx_qcount; /* Max Number of rx_q count */
+} tOBX_CB;
+
+/*****************************************************************************
+** Definition for State Machine
+*****************************************************************************/
+
+/* Client Action functions are of this type */
+typedef tOBX_CL_STATE (*tOBX_CL_ACT)(tOBX_CL_CB *p_cb, BT_HDR *p_pkt);
+
+/* Server Action functions are of this type */
+typedef tOBX_SR_STATE (*tOBX_SR_ACT)(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt);
+
+#define OBX_SM_IGNORE 0
+#define OBX_SM_NO_ACTION 0xFF
+#define OBX_SM_ALL 0x80 /* for events like close confirm, abort request, close request where event handling is the same for most of the states */
+#define OBX_SM_ENTRY_MASK 0x7F /* state machine entry mask */
+
+#define OBX_SME_ACTION 0
+#define OBX_SME_NEXT_STATE 1
+#define OBX_SM_NUM_COLS 2
+
+typedef const UINT8 (*tOBX_SM_TBL)[OBX_SM_NUM_COLS];
+
+/*****************************************************************************
+** External global data
+*****************************************************************************/
+#if OBX_DYNAMIC_MEMORY == FALSE
+OBX_API extern tOBX_CB obx_cb;
+#else
+OBX_API extern tOBX_CB *obx_cb_ptr;
+#define obx_cb (*obx_cb_ptr)
+#endif
+extern const tOBX_EVENT obx_sm_evt_to_api_evt[];
+extern const UINT8 obx_hdr_start_offset[];
+/*****************************************************************************
+** External Function Declarations
+*****************************************************************************/
+/* from obx_main.c */
+
+#if (defined (BT_USE_TRACES) && BT_USE_TRACES == TRUE && OBX_CLIENT_INCLUDED == TRUE)
+extern const char * obx_cl_get_state_name(tOBX_CL_STATE state);
+extern const char * obx_cl_get_event_name(tOBX_CL_EVENT event);
+#else
+#define obx_cl_get_state_name(state_num) ""
+#define obx_cl_get_event_name(event_num) ""
+#endif
+
+#if (defined (BT_USE_TRACES) && BT_USE_TRACES == TRUE && OBX_SERVER_INCLUDED == TRUE)
+extern const char * obx_sr_get_state_name(tOBX_SR_STATE state);
+extern const char * obx_sr_get_event_name(tOBX_SR_EVENT event);
+#else
+#define obx_sr_get_state_name(state_num) ""
+#define obx_sr_get_event_name(event_num) ""
+#endif
+/* client functions in obx_main.c */
+extern void obx_cl_timeout(TIMER_LIST_ENT *p_tle);
+extern tOBX_CL_CB * obx_cl_alloc_cb(void);
+extern tOBX_CL_CB * obx_cl_get_cb(tOBX_HANDLE handle);
+extern tOBX_CL_CB * obx_cl_get_suspended_cb(tOBX_HANDLE *p_handle, UINT8 *p_session_info);
+extern void obx_cl_free_cb(tOBX_CL_CB * p_cb);
+
+/* server functions in obx_main.c */
+extern tOBX_SPND_CB * obx_find_suspended_session (tOBX_SR_SESS_CB *p_scb, tOBX_TRIPLET *p_triplet, UINT8 num);
+extern void obx_l2c_snd_evt (tOBX_L2C_CB *p_l2cb, tOBX_L2C_EVT_PARAM param, tOBX_L2C_EVT l2c_evt);
+extern void obx_sr_timeout(TIMER_LIST_ENT *p_tle);
+extern void obx_sr_sess_timeout(TIMER_LIST_ENT *p_tle);
+extern tOBX_HANDLE obx_sr_alloc_cb(tOBX_StartParams *p_params);
+extern tOBX_SR_CB * obx_sr_get_cb(tOBX_HANDLE handle);
+extern tOBX_SR_SESS_CB * obx_sr_get_scb(tOBX_HANDLE handle);
+extern void obx_sr_free_cb(tOBX_HANDLE handle);
+extern void obx_sr_free_scb(tOBX_SR_SESS_CB *p_scb);
+extern UINT32 obx_sr_get_next_conn_id(void);
+/* common functions in obx_main.c */
+extern tOBX_PORT_CB * obx_port_handle_2cb(UINT16 port_handle);
+extern void obx_start_timer(tOBX_COMM_CB *p_pcb);
+extern void obx_stop_timer(TIMER_LIST_ENT *p_tle);
+
+/* from obx_rfc.c */
+extern void obx_cl_proc_evt(tOBX_PORT_EVT *p_evt);
+extern BT_HDR * obx_build_dummy_rsp(tOBX_SR_SESS_CB *p_scb, UINT8 rsp_code);
+extern void obx_sr_proc_evt(tOBX_PORT_EVT *p_evt);
+extern BOOLEAN obx_rfc_snd_msg(tOBX_PORT_CB *p_pcb);
+extern tOBX_STATUS obx_open_port(tOBX_PORT_CB *p_pcb, const BD_ADDR bd_addr, UINT8 scn);
+extern void obx_add_port(tOBX_HANDLE obx_handle);
+extern void obx_close_port(UINT16 port_handle);
+
+/* from obx_capi.c */
+extern tOBX_STATUS obx_prepend_req_msg(tOBX_HANDLE handle, tOBX_CL_EVENT event, UINT8 req_code, BT_HDR *p_pkt);
+
+/* from obx_csm.c */
+extern void obx_csm_event(tOBX_CL_CB *p_cb, tOBX_EVENT event, BT_HDR *p_msg);
+
+/* from obx_cact.c */
+extern void obx_ca_connect_req(tOBX_CL_CB *p_cb, BT_HDR *p_pkt);
+extern tOBX_CL_STATE obx_ca_snd_req(tOBX_CL_CB *p_cb, BT_HDR *p_pkt);
+extern tOBX_CL_STATE obx_ca_close_port(tOBX_CL_CB *p_cb, BT_HDR *p_pkt);
+extern tOBX_CL_STATE obx_ca_snd_part(tOBX_CL_CB *p_cb, BT_HDR *p_pkt);
+extern tOBX_CL_STATE obx_ca_connect_error(tOBX_CL_CB *p_cb, BT_HDR *p_pkt);
+extern tOBX_CL_STATE obx_ca_connect_fail(tOBX_CL_CB *p_cb, BT_HDR *p_pkt);
+extern tOBX_CL_STATE obx_ca_discnt_req(tOBX_CL_CB *p_cb, BT_HDR *p_pkt);
+extern tOBX_CL_STATE obx_ca_notify(tOBX_CL_CB *p_cb, BT_HDR *p_pkt);
+extern tOBX_CL_STATE obx_ca_fail_rsp(tOBX_CL_CB *p_cb, BT_HDR *p_pkt);
+extern tOBX_CL_STATE obx_ca_state(tOBX_CL_CB *p_cb, BT_HDR *p_pkt);
+extern tOBX_CL_STATE obx_ca_start_timer(tOBX_CL_CB *p_cb, BT_HDR *p_pkt);
+extern tOBX_CL_STATE obx_ca_connect_ok(tOBX_CL_CB *p_cb, BT_HDR *p_pkt);
+extern tOBX_CL_STATE obx_ca_session_ok(tOBX_CL_CB *p_cb, BT_HDR *p_pkt);
+extern tOBX_CL_STATE obx_ca_session_cont(tOBX_CL_CB *p_cb, BT_HDR *p_pkt);
+extern tOBX_CL_STATE obx_ca_session_get(tOBX_CL_CB *p_cb, BT_HDR *p_pkt);
+extern tOBX_CL_STATE obx_ca_session_fail(tOBX_CL_CB *p_cb, BT_HDR *p_pkt);
+extern tOBX_CL_STATE obx_ca_abort(tOBX_CL_CB *p_cb, BT_HDR *p_pkt);
+extern tOBX_CL_STATE obx_ca_snd_put_req(tOBX_CL_CB *p_cb, BT_HDR *p_pkt);
+extern tOBX_CL_STATE obx_ca_snd_get_req(tOBX_CL_CB *p_cb, BT_HDR *p_pkt);
+extern tOBX_CL_STATE obx_ca_srm_snd_req(tOBX_CL_CB *p_cb, BT_HDR *p_pkt);
+extern tOBX_CL_STATE obx_ca_srm_put_req(tOBX_CL_CB *p_cb, BT_HDR *p_pkt);
+extern tOBX_CL_STATE obx_ca_srm_get_req(tOBX_CL_CB *p_cb, BT_HDR *p_pkt);
+extern tOBX_CL_STATE obx_ca_srm_put_notify(tOBX_CL_CB *p_cb, BT_HDR *p_pkt);
+extern tOBX_CL_STATE obx_ca_srm_get_notify(tOBX_CL_CB *p_cb, BT_HDR *p_pkt);
+extern tOBX_CL_STATE obx_ca_save_rsp(tOBX_CL_CB *p_cb, BT_HDR *p_pkt);
+extern tOBX_CL_STATE obx_ca_save_req(tOBX_CL_CB *p_cb, BT_HDR *p_pkt);
+
+/* from obx_ssm.c */
+extern void obx_ssm_event(tOBX_SR_SESS_CB *p_scb, tOBX_SR_EVENT event, BT_HDR *p_msg);
+
+/* from obx_sapi.c */
+extern tOBX_STATUS obx_prepend_rsp_msg(tOBX_HANDLE shandle, tOBX_SR_EVENT event, UINT8 rsp_code, BT_HDR *p_pkt);
+
+/* from obx_sact.c */
+extern tOBX_SR_STATE obx_sa_snd_rsp(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt);
+extern tOBX_SR_STATE obx_sa_snd_part(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt);
+extern tOBX_SR_STATE obx_sa_abort_rsp(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt);
+extern tOBX_SR_STATE obx_sa_op_rsp(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt);
+extern BT_HDR * obx_conn_rsp(tOBX_SR_CB *p_cb, tOBX_SR_SESS_CB *p_scb, UINT8 rsp_code, BT_HDR *p_pkt);
+extern tOBX_SR_STATE obx_sa_connect_ind(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt);
+extern tOBX_SR_STATE obx_sa_wc_conn_ind(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt);
+extern tOBX_SR_STATE obx_sa_auth_ind(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt);
+extern tOBX_SR_STATE obx_sa_connect_rsp(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt);
+extern tOBX_SR_STATE obx_sa_connection_error(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt);
+extern tOBX_SR_STATE obx_sa_close_port(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt);
+extern tOBX_SR_STATE obx_sa_clean_port(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt);
+extern tOBX_SR_STATE obx_sa_state(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt);
+extern tOBX_SR_STATE obx_sa_nc_to(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt);
+extern tOBX_SR_STATE obx_sa_save_req(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt);
+extern tOBX_SR_STATE obx_sa_rej_req(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt);
+extern tOBX_SR_STATE obx_sa_session_ind(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt);
+extern tOBX_SR_STATE obx_sa_sess_conn_ind(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt);
+extern tOBX_SR_STATE obx_sa_wc_sess_ind(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt);
+extern tOBX_SR_STATE obx_sa_session_rsp(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt);
+extern tOBX_SR_STATE obx_sa_put_ind(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt);
+extern tOBX_SR_STATE obx_sa_get_ind(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt);
+extern tOBX_SR_STATE obx_sa_get_req(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt);
+extern tOBX_SR_STATE obx_sa_srm_put_req(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt);
+extern tOBX_SR_STATE obx_sa_srm_put_rsp(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt);
+extern tOBX_SR_STATE obx_sa_srm_get_fcs(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt);
+extern tOBX_SR_STATE obx_sa_srm_get_rsp(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt);
+extern tOBX_SR_STATE obx_sa_srm_get_req(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt);
+
+/* from obx_gen.c */
+extern void obx_access_rsp_code(BT_HDR *p_pkt, UINT8 *p_rsp_code);
+extern void obx_adjust_packet_len(BT_HDR *p_pkt);
+extern UINT16 obx_read_header_len(UINT8 *ph);
+extern BT_HDR * obx_dup_pkt(BT_HDR *p_pkt);
+
+/* from obx_md5 */
+extern BT_HDR * obx_unauthorize_rsp(tOBX_SR_CB *p_cb, tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt);
+extern void obx_session_id(UINT8 *p_sess_id, UINT8 *p_cl_addr, UINT8 * p_cl_nonce, int cl_nonce_len,
+ UINT8 *p_sr_addr, UINT8 * p_sr_nonce, int sr_nonce_len);
+
+/* from obx_l2c.c */
+extern void obx_register_l2c(tOBX_CL_CB *p_cl_cb, UINT16 psm);
+extern tOBX_STATUS obx_open_l2c(tOBX_CL_CB *p_cl_cb, const BD_ADDR bd_addr);
+extern tOBX_STATUS obx_l2c_sr_register (tOBX_SR_CB *p_cb);
+extern void obx_close_l2c(UINT16 lcid);
+extern BOOLEAN obx_l2c_snd_msg(tOBX_L2C_CB *p_l2cb);
+extern void obx_sr_proc_l2c_evt (tOBX_L2C_EVT_MSG *p_msg);
+extern void obx_cl_proc_l2c_evt (tOBX_L2C_EVT_MSG *p_msg);
+
+/* from obx_utils.c */
+extern UINT8 obx_verify_response(UINT8 opcode, tOBX_RX_HDR *p_rxh);
+extern UINT8 obx_verify_request(UINT8 opcode, tOBX_RX_HDR *p_rxh);
+extern BOOLEAN obx_sr_proc_pkt (tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt);
+extern void obx_cl_proc_pkt (tOBX_CL_CB *p_cb, BT_HDR *p_pkt);
+extern void obx_free_buf(tOBX_LL_CB *p_ll_cb);
+extern UINT8 obx_add_timeout (tOBX_TRIPLET *p_trip, UINT32 timeout, tOBX_SESS_EVT *p_param);
+extern void obx_read_timeout (tOBX_TRIPLET *p_trip, UINT8 num, UINT32 *p_timeout, UINT8 *p_toa);
+#if (BT_USE_TRACES == TRUE)
+extern void obxu_dump_hex (UINT8 *p, char *p_title, UINT16 len);
+#else
+#define obxu_dump_hex(p, p_title, len)
+#endif
+extern BT_HDR * obx_sr_prepend_msg(BT_HDR *p_pkt, UINT8 * p_data, UINT16 data_len);
+extern BT_HDR * obx_cl_prepend_msg(tOBX_CL_CB *p_cb, BT_HDR *p_pkt, UINT8 * p_data, UINT16 data_len);
+extern void obx_flow_control(tOBX_COMM_CB *p_comm);
+extern UINT8 obx_read_triplet(tOBX_TRIPLET *p_trip, UINT8 num_trip, UINT8 tag);
+extern UINT32 obx_read_obj_offset(tOBX_TRIPLET *p_trip, UINT8 num_trip);
+
+#endif /* OBX_INT_H */
diff --git a/stack/obx/obx_l2c.c b/stack/obx/obx_l2c.c
new file mode 100644
index 0000000..51226d9
--- /dev/null
+++ b/stack/obx/obx_l2c.c
@@ -0,0 +1,1031 @@
+/*****************************************************************************
+**
+** Name: obx_l2c.c
+**
+** Description: This OBX module interfaces to L2CAP
+**
+** Copyright (c) 2008-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include <string.h>
+#include "wcassert.h"
+#include "data_types.h"
+#include "bt_target.h"
+#include "obx_api.h"
+#include "obx_int.h"
+#include "l2c_api.h"
+#include "l2cdefs.h"
+#include "port_api.h"
+#include "btu.h"
+#include "btm_int.h"
+
+/* Configuration flags. */
+#define OBX_L2C_CFG_IND_DONE 0x01
+#define OBX_L2C_CFG_CFM_DONE 0x02
+#define OBX_L2C_SECURITY_DONE 0x04
+#define OBX_L2C_CONN_RQS_DONE 0x07
+
+/* "states" used for L2CAP channel */
+#define OBX_CH_IDLE 0 /* No connection */
+#define OBX_CH_CONN 1 /* Waiting for connection confirm */
+#define OBX_CH_CFG 2 /* Waiting for configuration complete */
+#define OBX_CH_OPEN 3 /* Channel opened */
+
+/* callback function declarations */
+void obx_l2c_connect_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id);
+void obx_l2c_connect_cfm_cback(UINT16 lcid, UINT16 result);
+void obx_l2c_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg);
+void obx_l2c_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg);
+void obx_l2c_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed);
+void obx_l2c_disconnect_cfm_cback(UINT16 lcid, UINT16 result);
+void obx_l2c_data_ind_cback(UINT16 lcid, BT_HDR *p_buf);
+void obx_l2c_congestion_ind_cback(UINT16 lcid, BOOLEAN is_congested);
+tOBX_SR_SESS_CB * obx_lcb_2_sr_sess_cb(tOBX_L2C_CB *p_lcb);
+
+#if (OBX_SERVER_INCLUDED == TRUE)
+/* L2CAP callback function structure for server */
+const tL2CAP_APPL_INFO obx_l2c_sr_appl = {
+ obx_l2c_connect_ind_cback, /* tL2CA_CONNECT_IND_CB */
+ NULL, /* tL2CA_CONNECT_CFM_CB */
+ NULL, /* tL2CA_CONNECT_PND_CB */
+ obx_l2c_config_ind_cback, /* tL2CA_CONFIG_IND_CB */
+ obx_l2c_config_cfm_cback, /* tL2CA_CONFIG_CFM_CB */
+ obx_l2c_disconnect_ind_cback, /* tL2CA_DISCONNECT_IND_CB */
+ obx_l2c_disconnect_cfm_cback, /* tL2CA_DISCONNECT_CFM_CB */
+ NULL, /* tL2CA_QOS_VIOLATION_IND_CB */
+ obx_l2c_data_ind_cback, /* tL2CA_DATA_IND_CB */
+ obx_l2c_congestion_ind_cback, /* tL2CA_CONGESTION_STATUS_CB */
+ NULL /* tL2CA_TX_COMPLETE_CB */
+};
+#endif
+
+#if (OBX_CLIENT_INCLUDED == TRUE)
+/* L2CAP callback function structure for client */
+const tL2CAP_APPL_INFO obx_l2c_cl_appl = {
+ NULL, /* tL2CA_CONNECT_IND_CB */
+ obx_l2c_connect_cfm_cback, /* tL2CA_CONNECT_CFM_CB */
+ NULL, /* tL2CA_CONNECT_PND_CB */
+ obx_l2c_config_ind_cback, /* tL2CA_CONFIG_IND_CB */
+ obx_l2c_config_cfm_cback, /* tL2CA_CONFIG_CFM_CB */
+ obx_l2c_disconnect_ind_cback, /* tL2CA_DISCONNECT_IND_CB */
+ obx_l2c_disconnect_cfm_cback, /* tL2CA_DISCONNECT_CFM_CB */
+ NULL, /* tL2CA_QOS_VIOLATION_IND_CB */
+ obx_l2c_data_ind_cback, /* tL2CA_DATA_IND_CB */
+ obx_l2c_congestion_ind_cback, /* tL2CA_CONGESTION_STATUS_CB */
+ NULL /* tL2CA_TX_COMPLETE_CB */
+};
+#endif
+
+/* OBX eL2CAP default options */
+const tL2CAP_FCR_OPTS obx_l2c_fcr_opts_def = {
+ L2CAP_FCR_ERTM_MODE, /* Mandatory for Obex over L2CAP */
+ OBX_FCR_OPT_TX_WINDOW_SIZE_BR_EDR, /* Tx window size over Bluetooth */
+ OBX_FCR_OPT_MAX_TX_B4_DISCNT, /* Maximum transmissions before disconnecting */
+ OBX_FCR_OPT_RETX_TOUT, /* Retransmission timeout (2 secs) */
+ OBX_FCR_OPT_MONITOR_TOUT, /* Monitor timeout (12 secs) */
+ L2CAP_DEFAULT_ERM_MPS /* MPS segment size */
+};
+
+/*******************************************************************************
+** Function obx_l2c_snd_evt
+** Description Sends an L2CAP event to OBX through the BTU task.
+*******************************************************************************/
+void obx_l2c_snd_evt (tOBX_L2C_CB *p_l2cb, tOBX_L2C_EVT_PARAM param, tOBX_L2C_EVT l2c_evt)
+{
+ BT_HDR *p_msg;
+ tOBX_L2C_EVT_MSG *p_evt;
+ UINT16 event;
+
+ if (!p_l2cb)
+ return;
+
+ p_msg = (BT_HDR*)GKI_getbuf(BT_HDR_SIZE + sizeof(tOBX_PORT_EVT));
+ WC_ASSERT(p_msg);
+
+ if (p_l2cb->handle & OBX_CL_HANDLE_MASK)
+ event = BT_EVT_TO_OBX_CL_L2C_MSG;
+ else
+ event = BT_EVT_TO_OBX_SR_L2C_MSG;
+
+ p_msg->event = event;
+ p_msg->len = sizeof(tOBX_L2C_EVT_MSG);
+ p_msg->offset = 0;
+ p_evt = (tOBX_L2C_EVT_MSG *)(p_msg + 1);
+ p_evt->l2c_evt = l2c_evt;
+ p_evt->p_l2cb = p_l2cb;
+ p_evt->param = param;
+
+ GKI_send_msg(BTU_TASK, BTU_HCI_RCV_MBOX, p_msg);
+}
+
+#if (OBX_SERVER_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function obx_sr_scb_by_psm
+**
+** Description Find the server session control block for L2CAP.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+tOBX_SR_SESS_CB * obx_sr_scb_by_psm (UINT16 psm)
+{
+ UINT32 xx, yy;
+ tOBX_SR_CB *p_cb;
+ tOBX_SR_SESS_CB *p_scb = NULL, *p_scbt;
+ UINT16 port_handle;
+
+ for (xx=0; xx<obx_cb.num_server; xx++)
+ {
+ if (obx_cb.server[xx].psm == psm)
+ {
+ p_cb = &obx_cb.server[xx];
+ /* find one that has not allocated a RFCOMM port */
+ for (yy=0; yy<p_cb->num_sess; yy++)
+ {
+ p_scbt = &obx_cb.sr_sess[p_cb->sess[yy]-1];
+ if (p_scbt->ll_cb.comm.id == 0)
+ {
+ p_scb = p_scbt;
+ p_scb->ll_cb.l2c.p_close_fn = obx_close_l2c;
+ p_scb->ll_cb.l2c.p_send_fn = (tOBX_SEND_FN *)obx_l2c_snd_msg;
+ break;
+ }
+ }
+
+ if (p_scb == NULL)
+ {
+ /* check if an RFCOMM port can be freed */
+ for (yy=0; yy<p_cb->num_sess; yy++)
+ {
+ p_scbt = &obx_cb.sr_sess[p_cb->sess[yy]-1];
+ if (p_scbt->ll_cb.comm.p_send_fn == (tOBX_SEND_FN *)obx_rfc_snd_msg && p_scbt->state == OBX_SS_NOT_CONNECTED)
+ {
+ port_handle = p_scbt->ll_cb.port.port_handle;
+ p_scbt->ll_cb.port.port_handle = 0;
+ p_scb = p_scbt;
+ p_scb->ll_cb.l2c.p_close_fn = obx_close_l2c;
+ p_scb->ll_cb.l2c.p_send_fn = (tOBX_SEND_FN *)obx_l2c_snd_msg;
+ obx_close_port(port_handle);
+ RFCOMM_RemoveServer(port_handle);
+ obx_sr_free_scb(p_scbt);
+ break;
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ return p_scb;
+}
+
+/*******************************************************************************
+**
+** Function obx_sr_proc_l2c_evt
+**
+** Description This is called to process BT_EVT_TO_OBX_SR_L2C_MSG
+** Process server events from L2CAP. Get the associated server control
+** block. If this is a request packet, stop timer. Find the
+** associated API event and save it in server control block
+** (api_evt). Fill the event parameter (param).
+** Call obx_ssm_event() with the associated events.If the associated
+** control block is not found (maybe the target header does not
+** match) or busy, compose a service unavailable response and call
+** obx_l2c_snd_msg().
+** Returns void
+**
+*******************************************************************************/
+void obx_sr_proc_l2c_evt (tOBX_L2C_EVT_MSG *p_msg)
+{
+ tOBX_SR_SESS_CB *p_scb = NULL;
+ tOBX_L2C_CB *p_lcb;
+ BT_HDR *p_pkt=NULL;
+ tOBX_RX_HDR *p_rxh;
+ UINT8 opcode;
+ tOBX_L2C_IND *p_ind;
+ tL2CAP_CFG_INFO cfg;
+ UINT16 result = L2CAP_CONN_NO_RESOURCES;
+#if (BT_USE_TRACES == TRUE)
+ UINT16 len;
+#endif
+ tL2CAP_ERTM_INFO ertm_info;
+ tBT_UUID bt_uuid = {2, {UUID_PROTOCOL_OBEX}};
+ tOBX_EVT_PARAM param;
+ tOBX_SR_CB *p_cb;
+
+ if (p_msg == NULL || p_msg->p_l2cb == NULL)
+ return;
+
+ if (p_msg->l2c_evt == OBX_L2C_EVT_CONN_IND)
+ {
+ memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+ cfg.mtu_present = TRUE;
+
+ p_ind = &p_msg->param.conn_ind;
+ if ((p_scb = obx_sr_scb_by_psm(p_ind->psm)) != NULL)
+ {
+ memcpy(p_scb->param.conn.peer_addr, p_ind->bd_addr, BD_ADDR_LEN);
+ memcpy(p_scb->peer_addr, p_ind->bd_addr, BD_ADDR_LEN);
+ result = L2CAP_CONN_OK;
+ p_lcb = &p_scb->ll_cb.l2c;
+ cfg.mtu = p_lcb->rx_mtu;
+
+ cfg.fcr_present = TRUE;
+ cfg.fcr = obx_l2c_fcr_opts_def;
+ }
+ /* else no control channel yet, reject */
+
+ /* Set the FCR options: */
+ ertm_info.preferred_mode = obx_l2c_fcr_opts_def.mode;
+ ertm_info.allowed_modes = L2CAP_FCR_CHAN_OPT_ERTM;
+ ertm_info.user_rx_pool_id = OBX_USER_RX_POOL_ID;
+ ertm_info.user_tx_pool_id = OBX_USER_TX_POOL_ID;
+ ertm_info.fcr_rx_pool_id = OBX_FCR_RX_POOL_ID;
+ ertm_info.fcr_tx_pool_id = OBX_FCR_TX_POOL_ID;
+
+ /* Send L2CAP connect rsp */
+ L2CA_CONNECT_RSP(p_ind->bd_addr, p_ind->id, p_ind->lcid, result, 0, &ertm_info, &bt_uuid);
+
+ /* if result ok, proceed with connection */
+ if (result == L2CAP_CONN_OK)
+ {
+ /* store LCID */
+ p_lcb->lcid = p_ind->lcid;
+ obx_cb.l2c_map[p_ind->lcid - L2CAP_BASE_APPL_CID] = p_lcb->handle;
+ OBX_TRACE_DEBUG2("l2c_map[%d]=0x%x",p_ind->lcid - L2CAP_BASE_APPL_CID, p_lcb->handle );
+
+ /* transition to configuration state */
+ p_lcb->ch_state = OBX_CH_CFG;
+ p_lcb->ch_flags = OBX_L2C_SECURITY_DONE;
+
+ /* Send L2CAP config req */
+ L2CA_CONFIG_REQ(p_ind->lcid, &cfg);
+ }
+ return;
+ }
+
+ p_lcb = p_msg->p_l2cb;
+ p_scb = obx_lcb_2_sr_sess_cb(p_lcb);
+ if (p_scb == NULL)
+ return;
+
+ switch (p_msg->l2c_evt)
+ {
+ case OBX_L2C_EVT_RESUME:
+ p_cb = &obx_cb.server[p_scb->handle - 1];
+ param.ssn = p_scb->ssn;
+ (p_cb->p_cback) (p_scb->ll_cb.comm.handle, OBX_GET_REQ_EVT, param, p_pkt);
+ break;
+
+ case OBX_L2C_EVT_CONG:
+ p_lcb->cong = p_msg->param.is_cong;
+ obx_ssm_event (p_scb, OBX_FCS_SET_SEVT, NULL);
+ break;
+
+ case OBX_L2C_EVT_CLOSE:
+ obx_ssm_event (p_scb, OBX_PORT_CLOSE_SEVT, NULL);
+ break;
+
+ case OBX_L2C_EVT_DATA_IND:
+ p_pkt = p_msg->param.p_pkt;
+ OBX_TRACE_DEBUG2("obx_sr_proc_l2c_evt len:%d, offset:%d", p_pkt->len, p_pkt->offset );
+#if (BT_USE_TRACES == TRUE)
+ len = p_pkt->len;
+ if (len > 0x20)
+ len = 0x20;
+ obxu_dump_hex ((UINT8 *)(p_pkt + 1) + p_pkt->offset, "rsp evt", len);
+#endif
+ p_rxh = (tOBX_RX_HDR *)(p_pkt + 1);
+ opcode = *((UINT8 *)(p_pkt + 1) + p_pkt->offset);
+ memset(p_rxh, 0, sizeof(tOBX_RX_HDR));
+ if (obx_verify_request (opcode, p_rxh) == OBX_BAD_SM_EVT)
+ {
+ OBX_TRACE_ERROR1("bad opcode:0x%x disconnect now", opcode );
+ GKI_freebuf(p_pkt);
+ /* coverity [overrun-call] */
+ obx_ssm_event(p_scb, OBX_TX_EMPTY_SEVT, NULL);
+ return;
+ }
+ p_pkt->event = obx_sm_evt_to_api_evt[p_rxh->sm_evt];
+ p_pkt->layer_specific = GKI_get_buf_size(p_pkt) - BT_HDR_SIZE - p_pkt->offset - p_pkt->len;
+ OBX_TRACE_DEBUG3("opcode:0x%x event:%d sm_evt:%d", opcode, p_pkt->event, p_rxh->sm_evt );
+ if (p_pkt->event != OBX_BAD_SM_EVT)
+ {
+ if (GKI_queue_is_empty(&p_lcb->rx_q) && (p_scb->srm & OBX_SRM_WAIT_UL) == 0)
+ {
+ obx_sr_proc_pkt (p_scb, p_pkt);
+ }
+ else
+ {
+ GKI_enqueue (&p_lcb->rx_q, p_pkt);
+ if (p_lcb->rx_q.count > obx_cb.max_rx_qcount)
+ {
+ p_lcb->stopped = TRUE;
+ L2CA_FlowControl(p_lcb->lcid, FALSE);
+ }
+ OBX_TRACE_DEBUG4 ("obx_sr_proc_l2c_evt stopped:%d state:%d rx_q.count:%d, srm:0x%x",
+ p_lcb->stopped, p_scb->state, p_lcb->rx_q.count, p_scb->srm );
+ }
+ }
+ else
+ {
+ OBX_TRACE_ERROR0("bad SM event" );
+ }
+ break;
+ }
+}
+
+/*******************************************************************************
+**
+** Function obx_l2c_sr_register
+**
+** Description register the PSM to L2CAP.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+tOBX_STATUS obx_l2c_sr_register (tOBX_SR_CB *p_cb)
+{
+ tOBX_STATUS status = OBX_NO_RESOURCES;
+
+ if (L2CA_REGISTER (p_cb->psm, &obx_l2c_sr_appl, AMP_AUTOSWITCH_ALLOWED|AMP_USE_AMP_IF_POSSIBLE))
+ {
+ status = OBX_SUCCESS;
+ }
+ return status;
+}
+#endif
+
+#if (OBX_SERVER_INCLUDED == TRUE)
+
+/*******************************************************************************
+**
+** Function obx_lcb_2_sr_sess_cb
+**
+** Description Find the client control block for the given l2cap session.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+tOBX_SR_SESS_CB * obx_lcb_2_sr_sess_cb(tOBX_L2C_CB *p_lcb)
+{
+ UINT32 xx, yy;
+ tOBX_SR_CB *p_cb;
+ tOBX_SR_SESS_CB *p_scb = NULL;
+
+ for (xx=0; xx<obx_cb.num_server; xx++)
+ {
+ if (obx_cb.server[xx].num_sess)
+ {
+ p_cb = &obx_cb.server[xx];
+ for (yy=0; yy<p_cb->num_sess; yy++)
+ {
+ if (&(obx_cb.sr_sess[p_cb->sess[yy]-1].ll_cb.l2c) == p_lcb)
+ {
+ p_scb = &(obx_cb.sr_sess[p_cb->sess[yy]-1]);
+ break;
+ }
+ }
+
+ if (p_scb)
+ break;
+ }
+ }
+ return p_scb;
+}
+#endif
+
+#if (OBX_CLIENT_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function obx_lcb_2_clcb
+**
+** Description Find the client control block for the given l2cap session.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+tOBX_CL_CB * obx_lcb_2_clcb(tOBX_L2C_CB *p_lcb)
+{
+ UINT32 xx;
+ tOBX_CL_CB *p_cl_cb = NULL;
+
+ for (xx=0; xx<obx_cb.num_client; xx++)
+ {
+ if (&obx_cb.client[xx].ll_cb.l2c == p_lcb)
+ {
+ p_cl_cb = &obx_cb.client[xx];
+ break;
+ }
+ }
+ return p_cl_cb;
+}
+#endif
+
+/*******************************************************************************
+**
+** Function obx_lcid_2lcb
+**
+** Description Given a lcid, return the associated client or server
+** control block.
+**
+** Returns
+**
+*******************************************************************************/
+tOBX_L2C_CB * obx_lcid_2lcb(UINT16 lcid)
+{
+ tOBX_L2C_CB *p_lcb = NULL;
+ tOBX_HANDLE obx_handle = 0;
+#if (OBX_SERVER_INCLUDED == TRUE)
+ tOBX_SR_CB *p_cb;
+#endif
+ tOBX_HANDLE obx_mskd_handle;
+
+ /* this function is called by obx_rfc_cback() only.
+ * assume that port_handle is within range */
+ obx_handle = obx_cb.l2c_map[lcid-L2CAP_BASE_APPL_CID];
+ obx_mskd_handle = obx_handle&OBX_HANDLE_MASK;
+ OBX_TRACE_DEBUG3("obx_lcid_2lcb lcid:0x%x obx_handle:0x%x obx_mskd_handle:0x%x",
+ lcid, obx_handle, obx_mskd_handle);
+
+ if (obx_handle > 0)
+ {
+ if (obx_mskd_handle & OBX_CL_HANDLE_MASK)
+ {
+#if (OBX_CLIENT_INCLUDED == TRUE)
+ obx_mskd_handle &= ~OBX_CL_HANDLE_MASK;
+ p_lcb = &obx_cb.client[obx_mskd_handle - 1].ll_cb.l2c;
+#endif /* OBX_CLIENT_INCLUDED */
+ }
+ else if (obx_mskd_handle < OBX_NUM_SERVERS)
+ {
+#if (OBX_SERVER_INCLUDED == TRUE)
+ p_cb = &obx_cb.server[obx_mskd_handle - 1];
+ p_lcb = &obx_cb.sr_sess[p_cb->sess[OBX_DEC_SESS_IND(obx_handle)]-1].ll_cb.l2c;
+ OBX_TRACE_DEBUG3("p_lcb lcid:0x%x sess_ind:%d, sr_sess[%d]",
+ p_lcb->lcid, OBX_DEC_SESS_IND(obx_handle), p_cb->sess[OBX_DEC_SESS_IND(obx_handle)]-1);
+#endif /* OBX_SERVER_INCLUDED */
+ }
+ }
+
+ return p_lcb;
+}
+
+/*******************************************************************************
+**
+** Function obx_l2c_checks_ch_flags
+**
+** Description This function processes the L2CAP configuration indication
+** event.
+**
+** Returns void
+**
+*******************************************************************************/
+static void obx_l2c_checks_ch_flags (tOBX_L2C_CB *p_lcb)
+{
+ tOBX_L2C_EVT_PARAM evt_param;
+
+ OBX_TRACE_DEBUG1 ("obx_l2c_checks_ch_flags ch_flags:0x%x ", p_lcb->ch_flags);
+ /* if all the required ch_flags are set, report the OPEN event now */
+ if ((p_lcb->ch_flags & OBX_L2C_CONN_RQS_DONE) == OBX_L2C_CONN_RQS_DONE)
+ {
+ p_lcb->ch_state = OBX_CH_OPEN;
+ obx_start_timer((tOBX_COMM_CB *)p_lcb);
+ evt_param.is_cong = FALSE;
+ obx_l2c_snd_evt (p_lcb, evt_param, OBX_L2C_EVT_CONG);
+ }
+}
+
+/*******************************************************************************
+**
+** Function obx_l2c_connect_ind_cback
+**
+** Description This is the L2CAP connect indication callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+#if (OBX_SERVER_INCLUDED == TRUE)
+void obx_l2c_connect_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id)
+{
+ tOBX_L2C_EVT_PARAM evt_param;
+
+ obx_cb.sr_l2cb.handle = 0; /* to mark as server event */
+ memcpy( evt_param.conn_ind.bd_addr, bd_addr, BD_ADDR_LEN);
+ evt_param.conn_ind.lcid = lcid;
+ evt_param.conn_ind.psm = psm;
+ evt_param.conn_ind.id = id;
+ obx_l2c_snd_evt (&obx_cb.sr_l2cb, evt_param, OBX_L2C_EVT_CONN_IND);
+}
+#endif /* OBX_SERVER_INCLUDED */
+
+#if (OBX_CLIENT_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function obx_cl_proc_l2c_evt
+**
+** Description This is called to process BT_EVT_TO_OBX_CL_L2C_MSG
+** Process client events from L2CAP. Get the associated client control
+** block. If this is a response packet, stop timer. Call
+** obx_csm_event() with event OK_CFM, FAIL_CFM or CONT_CFM.
+** Returns void
+**
+*******************************************************************************/
+void obx_cl_proc_l2c_evt (tOBX_L2C_EVT_MSG *p_msg)
+{
+ tOBX_CL_CB *p_cl_cb = NULL;
+ tOBX_L2C_CB *p_l2cb;
+ BT_HDR *p_pkt;
+ tOBX_RX_HDR *p_rxh;
+ UINT8 opcode;
+
+ if (p_msg == NULL || p_msg->p_l2cb == NULL)
+ return;
+
+ p_l2cb = p_msg->p_l2cb;
+ p_cl_cb = obx_lcb_2_clcb(p_l2cb);
+ if (p_cl_cb == NULL)
+ return;
+
+ switch (p_msg->l2c_evt)
+ {
+ case OBX_L2C_EVT_CONG:
+ p_msg->p_l2cb->cong = p_msg->param.is_cong;
+ obx_csm_event (p_cl_cb, OBX_FCS_SET_CEVT, NULL);
+ break;
+
+ case OBX_L2C_EVT_CLOSE:
+ obx_csm_event (p_cl_cb, OBX_PORT_CLOSE_CEVT, NULL);
+ break;
+
+ case OBX_L2C_EVT_DATA_IND:
+ p_pkt = p_msg->param.p_pkt;
+ p_rxh = (tOBX_RX_HDR *)(p_pkt + 1);
+ opcode = *((UINT8 *)(p_pkt + 1) + p_pkt->offset);
+ memset(p_rxh, 0, sizeof(tOBX_RX_HDR));
+ obx_verify_response (opcode, p_rxh);
+
+ OBX_TRACE_DEBUG4 ("obx_cl_proc_l2c_evt event:0x%x/0x%x state:%d srm:0x%x", p_pkt->event, p_rxh->sm_evt, p_cl_cb->state, p_cl_cb->srm );
+ if (p_rxh->sm_evt != OBX_BAD_SM_EVT)
+ {
+ if (GKI_queue_is_empty(&p_l2cb->rx_q) && (p_cl_cb->srm & OBX_SRM_WAIT_UL) == 0)
+ {
+ obx_cl_proc_pkt (p_cl_cb, p_pkt);
+ }
+ else
+ {
+ GKI_enqueue (&p_l2cb->rx_q, p_pkt);
+ if (p_l2cb->rx_q.count > obx_cb.max_rx_qcount)
+ {
+ p_l2cb->stopped = TRUE;
+ L2CA_FlowControl(p_l2cb->lcid, FALSE);
+ }
+ OBX_TRACE_DEBUG3 ("obx_cl_proc_l2c_evt rx_q.count:%d, stopped:%d state:%d", p_l2cb->rx_q.count, p_l2cb->stopped, p_cl_cb->state );
+ }
+ }
+ else
+ {
+ OBX_TRACE_ERROR0("bad SM event" );
+ }
+ break;
+
+ }
+}
+
+/*******************************************************************************
+**
+** Function obx_l2c_sec_check_complete
+**
+** Description The function called when Security Manager finishes
+** verification of the service side connection
+**
+** Returns void
+**
+*******************************************************************************/
+static void obx_l2c_sec_check_complete (BD_ADDR bd_addr, void *p_ref_data, UINT8 res)
+{
+ tOBX_L2C_CB *p_lcb = (tOBX_L2C_CB *)p_ref_data;
+
+ OBX_TRACE_DEBUG3 ("obx_l2c_sec_check_complete ch_state:%d, ch_flags:0x%x, status:%d",
+ p_lcb->ch_state, p_lcb->ch_flags, res);
+ if (p_lcb->ch_state == OBX_CH_IDLE)
+ return;
+
+ if (res == BTM_SUCCESS)
+ {
+ p_lcb->ch_flags |= OBX_L2C_SECURITY_DONE;
+ obx_l2c_checks_ch_flags (p_lcb);
+ }
+ else
+ {
+ /* security failed - disconnect the channel */
+ L2CA_DISCONNECT_REQ (p_lcb->lcid);
+ }
+}
+
+/*******************************************************************************
+**
+** Function obx_l2c_connect_cfm_cback
+**
+** Description This is the L2CAP connect confirm callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void obx_l2c_connect_cfm_cback(UINT16 lcid, UINT16 result)
+{
+ tOBX_L2C_CB *p_lcb;
+ tL2CAP_CFG_INFO cfg;
+ tOBX_L2C_EVT_PARAM evt_param;
+ tOBX_CL_CB *p_cl_cb = NULL;
+
+ /* look up lcb for this channel */
+ if ((p_lcb = obx_lcid_2lcb(lcid)) != NULL)
+ {
+ OBX_TRACE_DEBUG1("obx_l2c_connect_cfm_cback ch_state:%d", p_lcb->ch_state);
+ /* if in correct state */
+ if (p_lcb->ch_state == OBX_CH_CONN)
+ {
+ /* if result successful */
+ if (result == L2CAP_CONN_OK)
+ {
+ /* set channel state */
+ p_lcb->ch_state = OBX_CH_CFG;
+
+ p_cl_cb = obx_lcb_2_clcb(p_lcb);
+ btm_sec_mx_access_request (p_cl_cb->peer_addr, p_cl_cb->psm, TRUE,
+ 0, 0, &obx_l2c_sec_check_complete, p_lcb);
+
+ /* Send L2CAP config req */
+ memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+
+ cfg.mtu_present = TRUE;
+ cfg.mtu = p_lcb->rx_mtu;
+
+ cfg.fcr_present = TRUE;
+ cfg.fcr = obx_l2c_fcr_opts_def;
+
+ L2CA_CONFIG_REQ(lcid, &cfg);
+ }
+ /* else failure */
+ else
+ {
+ evt_param.any = 0;
+ obx_l2c_snd_evt (p_lcb, evt_param, OBX_L2C_EVT_CLOSE);
+ }
+ }
+ }
+}
+#endif /* OBX_CLIENT_INCLUDED */
+
+
+/*******************************************************************************
+**
+** Function obx_l2c_config_cfm_cback
+**
+** Description This is the L2CAP config confirm callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void obx_l2c_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
+{
+ tOBX_L2C_CB *p_lcb;
+
+ /* look up lcb for this channel */
+ if ((p_lcb = obx_lcid_2lcb(lcid)) != NULL)
+ {
+ /* if in correct state */
+ if (p_lcb->ch_state == OBX_CH_CFG)
+ {
+ /* if result successful */
+ if (p_cfg->result == L2CAP_CFG_OK)
+ {
+ /* update flags */
+ p_lcb->ch_flags |= OBX_L2C_CFG_CFM_DONE;
+
+ /* if configuration complete */
+ obx_l2c_checks_ch_flags(p_lcb);
+ }
+ /* else failure */
+ else
+ {
+ /* store result value
+ p_lcb->ch_result = p_cfg->result; */
+
+ /* Send L2CAP disconnect req */
+ L2CA_DISCONNECT_REQ(lcid);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function obx_l2c_config_ind_cback
+**
+** Description This is the L2CAP config indication callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void obx_l2c_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
+{
+ tOBX_L2C_CB *p_lcb;
+ UINT16 max_mtu = OBX_MAX_MTU;
+
+ /* Don't include QoS nor flush timeout in the response since we
+ currently always accept these values. Note: fcr_present is left
+ untouched since l2cap negotiates this internally
+ */
+ p_cfg->flush_to_present = FALSE;
+ p_cfg->qos_present = FALSE;
+
+ /* look up lcb for this channel */
+ if ((p_lcb = obx_lcid_2lcb(lcid)) != NULL)
+ {
+ /* store the mtu in tbl */
+ if (p_cfg->mtu_present)
+ {
+ p_lcb->tx_mtu = p_cfg->mtu;
+ }
+ else
+ {
+ p_lcb->tx_mtu = L2CAP_DEFAULT_MTU;
+ }
+
+ if (p_lcb->tx_mtu > max_mtu)
+ {
+ p_lcb->tx_mtu = p_cfg->mtu = max_mtu;
+
+ /* Must tell the peer what the adjusted value is */
+ p_cfg->mtu_present = TRUE;
+ }
+ else /* Don't include in the response */
+ p_cfg->mtu_present = FALSE;
+ OBX_TRACE_DEBUG2 ("obx_l2c_config_ind_cback tx_mtu:%d use:%d", p_lcb->tx_mtu, max_mtu);
+
+ p_cfg->result = L2CAP_CFG_OK;
+
+ /* send L2CAP configure response */
+ L2CA_CONFIG_RSP(lcid, p_cfg);
+
+ if (p_cfg->result != L2CAP_CFG_OK)
+ {
+ return;
+ }
+
+ /* if first config ind */
+ if ((p_lcb->ch_flags & OBX_L2C_CFG_IND_DONE) == 0)
+ {
+ /* update flags */
+ p_lcb->ch_flags |= OBX_L2C_CFG_IND_DONE;
+
+ /* if configuration complete */
+ obx_l2c_checks_ch_flags(p_lcb);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function obx_l2c_disconnect_ind_cback
+**
+** Description This is the L2CAP disconnect indication callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void obx_l2c_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed)
+{
+ tOBX_L2C_CB *p_lcb;
+ tOBX_L2C_EVT_PARAM evt_param;
+
+ /* look up lcb for this channel */
+ if ((p_lcb = obx_lcid_2lcb(lcid)) != NULL)
+ {
+ if (ack_needed)
+ {
+ /* send L2CAP disconnect response */
+ L2CA_DISCONNECT_RSP(lcid);
+ }
+
+ evt_param.any = 0;
+ obx_l2c_snd_evt (p_lcb, evt_param, OBX_L2C_EVT_CLOSE);
+ }
+}
+
+/*******************************************************************************
+**
+** Function obx_l2c_disconnect_cfm_cback
+**
+** Description This is the L2CAP disconnect confirm callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void obx_l2c_disconnect_cfm_cback(UINT16 lcid, UINT16 result)
+{
+ tOBX_L2C_CB *p_lcb;
+ tOBX_L2C_EVT_PARAM evt_param;
+
+ /* look up lcb for this channel */
+ if ((p_lcb = obx_lcid_2lcb(lcid)) != NULL)
+ {
+ evt_param.any = 0;
+ obx_l2c_snd_evt (p_lcb, evt_param, OBX_L2C_EVT_CLOSE);
+ }
+}
+
+/*******************************************************************************
+**
+** Function obx_l2c_data_ind_cback
+**
+** Description This is the L2CAP data indication callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void obx_l2c_data_ind_cback(UINT16 lcid, BT_HDR *p_buf)
+{
+ tOBX_L2C_CB *p_lcb;
+ tOBX_L2C_EVT_PARAM evt_param;
+#if (BT_USE_TRACES == TRUE)
+ UINT16 len;
+#endif
+
+ /* look up lcb for this channel */
+ if ((p_lcb = obx_lcid_2lcb(lcid)) != NULL)
+ {
+ evt_param.p_pkt = p_buf;
+ OBX_TRACE_DEBUG3("obx_l2c_data_ind_cback 0x%x, len:%d, offset:%d", p_buf, p_buf->len, p_buf->offset );
+#if (BT_USE_TRACES == TRUE)
+ len = p_buf->len;
+ if (len > 0x20)
+ len = 0x20;
+ obxu_dump_hex ((UINT8 *)(p_buf + 1) + p_buf->offset, "rsp cback", len);
+#endif
+ obx_l2c_snd_evt (p_lcb, evt_param, OBX_L2C_EVT_DATA_IND);
+ }
+ else /* prevent buffer leak */
+ GKI_freebuf(p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function obx_l2c_congestion_ind_cback
+**
+** Description This is the L2CAP congestion indication callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void obx_l2c_congestion_ind_cback(UINT16 lcid, BOOLEAN is_congested)
+{
+ tOBX_L2C_CB *p_lcb;
+ tOBX_L2C_EVT_PARAM evt_param;
+
+ OBX_TRACE_DEBUG2("obx_l2c_congestion_ind_cback lcid:%d, is_congested:%d",lcid, is_congested );
+ /* look up lcb for this channel */
+ if ((p_lcb = obx_lcid_2lcb(lcid)) != NULL)
+ {
+ evt_param.is_cong = is_congested;
+ obx_l2c_snd_evt (p_lcb, evt_param, OBX_L2C_EVT_CONG);
+ }
+}
+
+#if (OBX_CLIENT_INCLUDED == TRUE)
+/*******************************************************************************
+** Function obx_register_l2c
+** Description Call L2CA_Register() to get virtual psm.
+** Returns
+*******************************************************************************/
+void obx_register_l2c(tOBX_CL_CB *p_cl_cb, UINT16 psm)
+{
+ p_cl_cb->psm = L2CA_REGISTER (psm, &obx_l2c_cl_appl, AMP_AUTOSWITCH_ALLOWED|AMP_USE_AMP_IF_POSSIBLE);
+}
+
+/*******************************************************************************
+** Function obx_open_l2c
+** Description Call L2CA_Register() & L2CA_ConnectReq() to get lcid.
+** Returns port handle
+*******************************************************************************/
+tOBX_STATUS obx_open_l2c(tOBX_CL_CB *p_cl_cb, const BD_ADDR bd_addr)
+{
+ tOBX_L2C_CB *p_l2cb = &p_cl_cb->ll_cb.l2c;
+ tOBX_STATUS status = OBX_NO_RESOURCES; /* successful */
+ UINT16 max_mtu = OBX_MAX_MTU;
+ tL2CAP_CFG_INFO cfg;
+ tL2CAP_ERTM_INFO ertm_info;
+ tBT_UUID bt_uuid = {2, {UUID_PROTOCOL_OBEX}};
+
+ OBX_TRACE_DEBUG2("obx_open_l2c rxmtu:%d, cbmtu:%d", p_l2cb->rx_mtu, max_mtu );
+
+ /* clear buffers from previous connection */
+ obx_free_buf(&p_cl_cb->ll_cb);
+
+ /* make sure the MTU is in registered range */
+ if (p_l2cb->rx_mtu > max_mtu)
+ p_l2cb->rx_mtu = max_mtu;
+ if (p_l2cb->rx_mtu < OBX_MIN_MTU)
+ p_l2cb->rx_mtu = OBX_MIN_MTU;
+
+ if (p_cl_cb->psm)
+ {
+ memcpy (p_cl_cb->peer_addr, bd_addr, BD_ADDR_LEN);
+
+ /* Set the FCR options: */
+ ertm_info.preferred_mode = obx_l2c_fcr_opts_def.mode;
+ ertm_info.allowed_modes = L2CAP_FCR_CHAN_OPT_ERTM;
+ ertm_info.user_rx_pool_id = OBX_USER_RX_POOL_ID;
+ ertm_info.user_tx_pool_id = OBX_USER_TX_POOL_ID;
+ ertm_info.fcr_rx_pool_id = OBX_FCR_RX_POOL_ID;
+ ertm_info.fcr_tx_pool_id = OBX_FCR_TX_POOL_ID;
+
+ p_l2cb->lcid = L2CA_CONNECT_REQ (p_cl_cb->psm, (BD_ADDR_PTR)bd_addr, &ertm_info, &bt_uuid);
+ if (p_l2cb->lcid)
+ {
+ p_l2cb->ch_state = OBX_CH_CONN;
+ p_l2cb->ch_flags = 0;
+ p_l2cb->cong = TRUE;
+ memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+ cfg.fcr_present = TRUE;
+ cfg.fcr = obx_l2c_fcr_opts_def;
+ status = OBX_SUCCESS;
+ }
+ }
+
+ OBX_TRACE_DEBUG3("obx_open_l2c rxmtu:%d, lcid:%d, l2c.handle:0x%x",
+ p_l2cb->rx_mtu, p_l2cb->lcid, p_l2cb->handle );
+
+ if (status == OBX_SUCCESS)
+ {
+ obx_cb.l2c_map[p_l2cb->lcid - L2CAP_BASE_APPL_CID] = p_l2cb->handle;
+ p_l2cb->p_send_fn = (tOBX_SEND_FN *)obx_l2c_snd_msg;
+ p_l2cb->p_close_fn = obx_close_l2c;
+ }
+ else
+ {
+ status = OBX_NO_RESOURCES;
+ }
+
+ return status;
+}
+#endif
+
+/*******************************************************************************
+**
+** Function obx_close_l2c
+** Description Clear the port event mask and callback. Close the port.
+** Returns void
+*******************************************************************************/
+void obx_close_l2c(UINT16 lcid)
+{
+ L2CA_DISCONNECT_REQ (lcid);
+}
+
+/*******************************************************************************
+** Function obx_l2c_snd_msg
+** Description Call PORT_WriteData() to send an OBEX message to peer. If
+** all data is sent, free the GKI buffer that holds
+** the OBEX message. If only portion of data is
+** sent, adjust the BT_HDR for PART state.
+** Returns TRUE if all data is sent
+*******************************************************************************/
+BOOLEAN obx_l2c_snd_msg(tOBX_L2C_CB *p_l2cb)
+{
+ BOOLEAN sent = FALSE;
+
+ if (!p_l2cb->cong)
+ {
+ OBX_TRACE_DEBUG2("obx_l2c_snd_msg len:%d, offset:0x%x", p_l2cb->p_txmsg->len, p_l2cb->p_txmsg->offset);
+
+ obx_stop_timer(&p_l2cb->tle);
+ if (L2CA_DATA_WRITE (p_l2cb->lcid, p_l2cb->p_txmsg) == L2CAP_DW_CONGESTED)
+ {
+ OBX_TRACE_DEBUG0("obx_l2c_snd_msg congested");
+ p_l2cb->cong = TRUE;
+ }
+ obx_start_timer ((tOBX_COMM_CB *)p_l2cb);
+ p_l2cb->p_txmsg = NULL;
+ sent = TRUE;
+ }
+
+ return sent;
+}
diff --git a/stack/obx/obx_main.c b/stack/obx/obx_main.c
new file mode 100644
index 0000000..7dc7c97
--- /dev/null
+++ b/stack/obx/obx_main.c
@@ -0,0 +1,946 @@
+/*****************************************************************************
+**
+** Name: obx_main.c
+**
+** File: OBEX common API and interface to other Bluetooth modules
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include <string.h>
+
+#include "bt_target.h"
+#include "obx_int.h"
+#include "btu.h" /* for timer */
+#include "l2c_api.h"
+#include "l2cdefs.h"
+
+#if (defined (BT_USE_TRACES) && BT_USE_TRACES == TRUE)
+const char * const obx_cl_state_name [] =
+{
+ "NULL",
+ "NOT_CONN",
+ "SESS_RS",
+ "CONN_RS",
+ "UNAUTH",
+ "CONN",
+ "DISCNT_RS",
+ "OP_UNAUTH",
+ "SETPATH_RS",
+ "ACT_RS",
+ "ABORT_RS",
+ "PUT_RS",
+ "GET_RS",
+ "PUT",
+ "GET",
+ "PUT_S",
+ "GET_S",
+ "PART",
+ "Unknown"
+};
+
+const char * const obx_cl_event_name [] =
+{
+ "CONN_R",
+ "SESS_R",
+ "DISCNT_R",
+ "PUT_R",
+ "GET_R",
+ "SETPATH_R",
+ "ACT_R",
+ "ABORT_R",
+ "OK_C",
+ "CONT_C",
+ "FAIL_C",
+ "PORT_CLS",
+ "TX_EMPTY",
+ "FCS_SET",
+ "STATE",
+ "TIMEOUT",
+ "Unknown"
+};
+
+const char * const obx_sr_state_name [] =
+{
+ "NULL",
+ "NOT_CONN",
+ "SESS_I",
+ "CONN_I",
+ "WAIT_AUTH",
+ "AUTH_I",
+ "CONN",
+ "DISCNT_I",
+ "SETPATH_I",
+ "ACT_I",
+ "ABORT_I",
+ "PUT_I",
+ "GET_I",
+ "PUT",
+ "GET",
+ "PUT_S",
+ "GET_S",
+ "PART",
+ "WAIT_CLS",
+ "Unknown"
+};
+
+const char * const obx_sr_event_name [] =
+{
+ "CONN_R",
+ "SESS_R",
+ "DISCNT_R",
+ "PUT_R",
+ "GET_R",
+ "SETPATH_R",
+ "ACT_R",
+ "ABORT_R",
+ "CONN_C",
+ "SESS_C",
+ "DISCNT_C",
+ "PUT_C",
+ "GET_C",
+ "SETPATH_C",
+ "ACT_C",
+ "ABORT_C",
+ "PORT_CLS",
+ "FCS_SET",
+ "STATE",
+ "TIMEOUT",
+ "BAD_REQ",
+ "TX_EMPTY",
+ "Unknown"
+};
+#endif
+
+#if OBX_DYNAMIC_MEMORY == FALSE
+OBX_API tOBX_CB obx_cb;
+#endif
+
+
+#if (defined (BT_USE_TRACES) && BT_USE_TRACES == TRUE)
+#if (OBX_CLIENT_INCLUDED == TRUE)
+/*******************************************************************************
+** Function obx_cl_get_state_name
+** Returns The client state name.
+*******************************************************************************/
+const char *obx_cl_get_state_name(tOBX_CL_STATE state)
+{
+ const char * p_str = obx_cl_state_name[OBX_CS_MAX];
+ if (state < OBX_CS_MAX)
+ {
+ p_str = obx_cl_state_name[state];
+ }
+ return p_str;
+}
+
+/*******************************************************************************
+** Function obx_cl_get_event_name
+** Returns The client event name.
+*******************************************************************************/
+const char *obx_cl_get_event_name(tOBX_CL_EVENT event)
+{
+ const char * p_str = obx_cl_event_name[OBX_MAX_CEVT];
+ if (event < OBX_MAX_CEVT)
+ {
+ p_str = obx_cl_event_name[event];
+ }
+ return p_str;
+}
+#endif
+
+#if (OBX_SERVER_INCLUDED == TRUE)
+/*******************************************************************************
+** Function obx_sr_get_state_name
+** Returns The server state name.
+*******************************************************************************/
+const char *obx_sr_get_state_name(tOBX_SR_STATE state)
+{
+ const char * p_str = obx_sr_state_name[OBX_SS_MAX];
+ if (state < OBX_SS_MAX)
+ {
+ p_str = obx_sr_state_name[state];
+ }
+ return p_str;
+}
+
+/*******************************************************************************
+** Function obx_sr_get_event_name
+** Returns The server event name.
+*******************************************************************************/
+const char *obx_sr_get_event_name(tOBX_SR_EVENT event)
+{
+ const char * p_str = obx_sr_event_name[OBX_MAX_SEVT];
+ if (event < OBX_MAX_SEVT)
+ {
+ p_str = obx_sr_event_name[event];
+ }
+ return p_str;
+}
+#endif
+#endif
+
+/*******************************************************************************
+** Function obx_start_timer
+** Description start BTU timer.
+*******************************************************************************/
+void obx_start_timer(tOBX_COMM_CB *p_pcb)
+{
+ UINT16 type = 0;
+ UINT32 timeout = obx_cb.timeout_val;
+
+ if (timeout)
+ {
+ if (p_pcb->handle & OBX_CL_HANDLE_MASK)
+ {
+ if (p_pcb->p_txmsg && p_pcb->p_txmsg->event == OBX_DISCONNECT_REQ_EVT)
+ {
+ timeout = OBX_DISC_TOUT_VALUE;
+ }
+ type = BTU_TTYPE_OBX_CLIENT_TO;
+ }
+ else
+ {
+ if (p_pcb->p_txmsg && p_pcb->p_txmsg->event == (OBX_DISCNT_CFM_SEVT + 1))
+ {
+ timeout = OBX_DISC_TOUT_VALUE;
+ }
+ type = BTU_TTYPE_OBX_SERVER_TO;
+ }
+ btu_start_timer(&p_pcb->tle, type, timeout);
+ }
+ OBX_TRACE_DEBUG3("obx_start_timer type: %d, val:%d, p_tle:0x%x", type, timeout, &p_pcb->tle);
+}
+
+/*******************************************************************************
+** Function obx_stop_timer
+** Description Stop BTU timer
+*******************************************************************************/
+void obx_stop_timer(TIMER_LIST_ENT *p_tle)
+{
+ btu_stop_timer(p_tle);
+ OBX_TRACE_DEBUG1("obx_stop_timer p_tle:0x%x", p_tle);
+}
+
+#if (OBX_CLIENT_INCLUDED == TRUE)
+/*******************************************************************************
+** Function obx_cl_timeout
+** Description Get client control block from timer param. Start BTU timer again.
+** Call application callback routine with OBX_TIMEOUT_EVT event.
+*******************************************************************************/
+void obx_cl_timeout(TIMER_LIST_ENT *p_tle)
+{
+ tOBX_CL_CB *p_cb = (tOBX_CL_CB *) p_tle->param;
+ tOBX_EVT_PARAM evtp;
+ tOBX_HANDLE handle = p_cb->ll_cb.comm.handle;
+ tOBX_CL_CBACK *p_cback = p_cb->p_cback;
+
+ memset(&evtp, 0, sizeof(tOBX_EVT_PARAM));
+ if (obx_cb.timeout_val)
+ btu_start_timer(p_tle, BTU_TTYPE_OBX_CLIENT_TO, obx_cb.timeout_val);
+ obx_csm_event(p_cb, OBX_TIMEOUT_CEVT, NULL);
+ (*p_cback) (handle, OBX_TIMEOUT_EVT, OBX_RSP_DEFAULT, evtp, NULL);
+}
+
+/*******************************************************************************
+**
+** Function obx_cl_alloc_cb
+**
+** Description allocate a client control block.
+**
+*******************************************************************************/
+tOBX_CL_CB *obx_cl_alloc_cb(void)
+{
+ int xx, yy;
+ tOBX_CL_CB *p_cb = NULL;
+
+ /* allocate a client control block */
+ for (xx=0, yy=obx_cb.next_ind; xx<obx_cb.num_client; xx++, yy++)
+ {
+ if (yy >= obx_cb.num_client)
+ yy = 0;
+ p_cb = &obx_cb.client[yy];
+
+ if (p_cb->ll_cb.comm.handle == OBX_HANDLE_NULL)
+ {
+ p_cb->ll_cb.comm.handle = OBX_CL_HANDLE_MASK | (yy + 1);
+ obx_cb.next_ind = yy+1; /* it will be adjusted, so we do not need to check the range now */
+ OBX_TRACE_DEBUG3("obx_cl_alloc_cb obx handle:0x%x, yy:%d, next: %d",
+ p_cb->ll_cb.comm.handle, yy, obx_cb.next_ind);
+ p_cb->ll_cb.comm.tx_mtu = 0;
+ p_cb->conn_id = OBX_INVALID_CONN_ID;
+
+ p_cb->ll_cb.comm.tle.param = (UINT32)p_cb;
+ p_cb->psm = 0;
+ p_cb->srm = 0;
+ break;
+ }
+ }
+
+ if (xx == obx_cb.num_client)
+ p_cb = NULL;
+ return p_cb;
+}
+
+/*******************************************************************************
+**
+** Function obx_cl_get_cb
+**
+** Description Returns the pointer to the client control block with given handle.
+**
+*******************************************************************************/
+tOBX_CL_CB *obx_cl_get_cb(tOBX_HANDLE handle)
+{
+ tOBX_CL_CB *p_cb = NULL;
+ UINT8 ind = (handle & OBX_CL_CB_IND_MASK);
+
+ if (handle & OBX_CL_HANDLE_MASK)
+ {
+ if (ind <= obx_cb.num_client && ind > 0)
+ {
+ if (obx_cb.client[--ind].ll_cb.comm.handle == handle)
+ p_cb = &obx_cb.client[ind];
+ }
+ }
+
+ return p_cb;
+}
+
+/*******************************************************************************
+**
+** Function obx_cl_get_suspended_cb
+**
+** Description Returns the pointer to the client control block with given handle.
+**
+*******************************************************************************/
+tOBX_CL_CB *obx_cl_get_suspended_cb(tOBX_HANDLE *p_handle, UINT8 *p_session_info)
+{
+ tOBX_HANDLE handle = *p_handle;
+ tOBX_CL_CB *p_cb = NULL;
+ tOBX_CL_CB *p_ccb = NULL;
+ UINT8 ind = (handle & OBX_CL_CB_IND_MASK);
+
+ OBX_TRACE_DEBUG1("obx_cl_get_suspended_cb handle: 0x%x", handle);
+ if (handle & OBX_CL_HANDLE_MASK)
+ {
+ if (ind <= obx_cb.num_client && ind > 0)
+ {
+ if (obx_cb.client[--ind].ll_cb.comm.handle == handle)
+ {
+ p_ccb = &obx_cb.client[ind];
+ if (p_ccb->sess_st == OBX_SESS_SUSPENDED &&
+ ((p_session_info == p_ccb->sess_info) || (memcmp(p_session_info, p_ccb->sess_info, OBX_SESSION_INFO_SIZE) == 0)))
+ {
+ OBX_TRACE_DEBUG0("found a suspended session");
+ p_cb = p_ccb;
+ }
+ }
+ }
+ }
+ if (p_cb == NULL) /* if the handle is NULL, assume the system was power cycled. attempt to allocate a control block */
+ {
+ p_cb = obx_cl_alloc_cb();
+ if (p_cb)
+ {
+ *p_handle = p_cb->ll_cb.comm.handle;
+ p_cb->sess_st = OBX_SESS_SUSPENDED;
+ memcpy(p_cb->sess_info, p_session_info, OBX_SESSION_INFO_SIZE);
+ OBX_TRACE_DEBUG1("allocated a suspended session handle: 0x%x", *p_handle);
+ }
+ }
+
+ return p_cb;
+}
+
+/*******************************************************************************
+**
+** Function obx_cl_free_cb
+**
+** Description Free the given client control block.
+**
+** Returns void
+**
+*******************************************************************************/
+void obx_cl_free_cb(tOBX_CL_CB * p_cb)
+{
+ if (p_cb)
+ {
+ OBX_TRACE_DEBUG2("obx_cl_free_cb id: %d, sess_st:%d", p_cb->ll_cb.comm.id, p_cb->sess_st);
+
+ if (p_cb->ll_cb.comm.id>0)
+ {
+ if (p_cb->ll_cb.comm.p_send_fn == (tOBX_SEND_FN *)obx_rfc_snd_msg)
+ obx_cb.hdl_map[p_cb->ll_cb.port.port_handle - 1] = 0;
+ else
+ obx_cb.l2c_map[p_cb->ll_cb.l2c.lcid - L2CAP_BASE_APPL_CID] = 0;
+ }
+
+ /* make sure the GKI buffers are freed */
+ if (p_cb->p_next_req)
+ GKI_freebuf(p_cb->p_next_req);
+
+ if (p_cb->p_saved_req)
+ GKI_freebuf(p_cb->p_saved_req);
+
+ if (p_cb->p_auth)
+ GKI_freebuf(p_cb->p_auth);
+
+ obx_free_buf (&p_cb->ll_cb);
+
+ if (p_cb->psm)
+ L2CA_DEREGISTER (p_cb->psm);
+
+ /* make sure the timer is stopped */
+ btu_stop_timer(&p_cb->ll_cb.comm.tle);
+
+ memset(p_cb, 0, sizeof(tOBX_CL_CB) );
+ }
+}
+#endif /* OBX_CLIENT_INCLUDED */
+
+#if (OBX_SERVER_INCLUDED == TRUE)
+/*******************************************************************************
+** Function obx_find_suspended_session
+** Description if p_triplet is NULL,
+** check if there's still room for a reliable session
+** else check if the given session is still in the suspended list
+*******************************************************************************/
+tOBX_SPND_CB *obx_find_suspended_session (tOBX_SR_SESS_CB *p_scb, tOBX_TRIPLET *p_triplet, UINT8 num)
+{
+ UINT8 ind;
+ BOOLEAN found = FALSE;
+ BOOLEAN infinite = FALSE;
+ UINT8 *p, xx;
+ tOBX_SR_CB *p_cb = obx_sr_get_cb(p_scb->handle);
+ tOBX_SPND_CB *p_spndcb, *p_ret = NULL;
+
+ OBX_TRACE_DEBUG0("obx_find_suspended_session ");
+ if (p_triplet == NULL)
+ {
+ if (p_cb->p_suspend)
+ {
+ for (xx=0, p_spndcb=p_cb->p_suspend; xx<p_cb->max_suspend; xx++, p_spndcb++)
+ {
+ if ((p_spndcb->state == OBX_SS_NULL) || (memcmp(p_spndcb->peer_addr, p_scb->peer_addr, BD_ADDR_LEN)==0))
+ {
+ OBX_TRACE_DEBUG3("[%d] state: %d, BDA: %08x", xx, p_spndcb->state,
+ (p_spndcb->peer_addr[2]<<24)+(p_spndcb->peer_addr[3]<<16)+(p_spndcb->peer_addr[4]<<8)+p_spndcb->peer_addr[5]);
+ /* this entry is not used yet or overwriting the entry with the same address */
+ found = TRUE;
+ break;
+ }
+ else if (p_spndcb->stle.param == 0)
+ {
+ infinite = TRUE;
+ }
+ }
+ OBX_TRACE_DEBUG2("found: %d infinite:%d", found, infinite);
+ if (found == FALSE)
+ found = infinite;
+ }
+ else if (p_cb->max_suspend > 0)
+ {
+ found = TRUE;
+ }
+ p_ret = (tOBX_SPND_CB *)p_scb;
+ }
+ else if (p_cb->p_suspend)
+ {
+ ind = obx_read_triplet(p_triplet, num, OBX_TAG_SESS_PARAM_SESS_ID);
+ if (ind < num && p_triplet[ind].len == OBX_SESSION_ID_SIZE)
+ {
+ p = p_triplet[ind].p_array;
+ for (xx=0, p_spndcb=p_cb->p_suspend; xx<p_cb->max_suspend; xx++, p_spndcb++)
+ {
+ OBX_TRACE_DEBUG5("[%d] state: %d/%d, ssn:%d offset:x%x", xx, p_spndcb->state,
+ p_spndcb->sess_info[OBX_SESSION_INFO_ST_IDX], p_spndcb->ssn, p_spndcb->offset);
+ if ((p_spndcb->state != OBX_SS_NULL) &&
+ (memcmp (p, p_spndcb->sess_info, OBX_SESSION_ID_SIZE) == 0))
+ {
+ obxu_dump_hex (p_spndcb->sess_info, "sess info", OBX_SESSION_INFO_SIZE);
+ /* prepare p_scb to the proper state for resume */
+ p_ret = p_spndcb;
+ break;
+ }
+ }
+ }
+ }
+ return p_ret;
+}
+
+/*******************************************************************************
+** Function obx_sr_sess_timeout
+** Description Get suspended session control block from timer param.
+** mark the suspended session as NULL
+*******************************************************************************/
+void obx_sr_sess_timeout(TIMER_LIST_ENT *p_tle)
+{
+ tOBX_SPND_CB *p_spndcb = (tOBX_SPND_CB *) p_tle->param;
+
+ OBX_TRACE_DEBUG0("obx_sr_sess_timeout");
+ p_spndcb->state = OBX_SS_NULL;
+}
+
+/*******************************************************************************
+** Function obx_sr_timeout
+** Description Get server control block from timer param. Start BTU timer again.
+** Call application callback routine with OBX_TIMEOUT_EVT event.
+*******************************************************************************/
+void obx_sr_timeout(TIMER_LIST_ENT *p_tle)
+{
+ tOBX_SR_SESS_CB *p_scb = (tOBX_SR_SESS_CB *) p_tle->param;
+ tOBX_EVT_PARAM evtp;
+ tOBX_HANDLE handle = p_scb->ll_cb.comm.handle;
+ tOBX_SR_CBACK *p_cback;
+ tOBX_SR_CB *p_cb;
+
+ memset(&evtp, 0, sizeof(tOBX_EVT_PARAM));
+ if (obx_cb.timeout_val)
+ btu_start_timer(p_tle, BTU_TTYPE_OBX_SERVER_TO, obx_cb.timeout_val);
+ p_cb = &obx_cb.server[p_scb->handle - 1];
+ p_cback = p_cb->p_cback;
+ obx_ssm_event(p_scb, OBX_TIMEOUT_SEVT, NULL);
+ (*p_cback) (handle, OBX_TIMEOUT_EVT, evtp, NULL);
+}
+
+/*******************************************************************************
+**
+** Function obx_sr_alloc_cb
+**
+** Description allocate a server control block.
+**
+*******************************************************************************/
+tOBX_HANDLE obx_sr_alloc_cb(tOBX_StartParams *p_params)
+{
+ int xx, yy, zz;
+ tOBX_SR_CB *p_cb = &obx_cb.server[0];
+ tOBX_SR_SESS_CB *p_scb = &obx_cb.sr_sess[0];
+ tOBX_HANDLE obx_handle = OBX_HANDLE_NULL;
+
+ OBX_TRACE_DEBUG1("obx_sr_alloc_cb num sess: %d", p_params->max_sessions);
+ /* allocate a server control block */
+ for (xx=0; xx<obx_cb.num_server; xx++, p_cb++)
+ {
+ if (p_cb->scn == 0 && p_cb->psm == 0)
+ {
+ obx_handle = xx + 1;
+ p_cb->scn = p_params->scn;
+ p_cb->psm = p_params->psm;
+ break;
+ }
+ }
+
+ if (xx != obx_cb.num_server)
+ {
+ /* allocate session control blocks */
+ zz = 0;
+ for (yy=0; yy<obx_cb.num_sr_sess && zz < p_params->max_sessions; yy++, p_scb++)
+ {
+ if (p_scb->ll_cb.comm.handle == OBX_HANDLE_NULL)
+ {
+ p_scb->handle = obx_handle;
+ if (p_params->get_nonf)
+ p_scb->srmp = OBX_SRMP_NONF_EVT;
+ p_cb->sess[zz] = yy + 1;
+ p_scb->srm = p_params->srm;
+ p_scb->ll_cb.comm.handle = OBX_ENC_SESS_HANDLE((obx_handle), zz);
+ p_scb->ll_cb.comm.tx_mtu = 0;
+ p_scb->ll_cb.comm.tle.param = (UINT32)p_scb;
+ OBX_TRACE_DEBUG2("[%d]: 0x%x", zz, p_scb->ll_cb.comm.handle);
+ zz++;
+ }
+ }
+
+ if (zz == p_params->max_sessions && L2C_IS_VALID_PSM(p_params->psm))
+ {
+ if (obx_l2c_sr_register(p_cb) != OBX_SUCCESS)
+ {
+ OBX_TRACE_ERROR0("Cannot register to L2CAP");
+ zz = 0; /* let it fail */
+ }
+ }
+
+ if (zz != p_params->max_sessions)
+ {
+ OBX_TRACE_ERROR0("not enough resources: release the allocated ones");
+ p_cb->scn = 0;
+ p_cb->psm = 0;
+ obx_handle = OBX_HANDLE_NULL;
+ p_scb = &obx_cb.sr_sess[0];
+ for (yy=0; yy<obx_cb.num_sr_sess; yy++, p_scb++)
+ {
+ if (p_scb->handle == obx_handle)
+ {
+ p_scb->ll_cb.comm.handle = OBX_HANDLE_NULL;
+ }
+ }
+ }
+ else
+ {
+ p_cb->num_sess = p_params->max_sessions;
+ p_cb->nonce = p_params->nonce;
+ p_cb->max_suspend = p_params->max_suspend;
+ if (p_cb->nonce && (p_cb->max_suspend == 0))
+ p_cb->max_suspend = 1;
+ if (p_cb->max_suspend > OBX_MAX_SUSPEND_SESSIONS)
+ p_cb->max_suspend = OBX_MAX_SUSPEND_SESSIONS;
+ if ((p_cb->max_suspend * sizeof (tOBX_SPND_CB)) > GKI_MAX_BUF_SIZE)
+ {
+ OBX_TRACE_ERROR1("OBX_MAX_SUSPEND_SESSIONS:%d is too big", OBX_MAX_SUSPEND_SESSIONS);
+ }
+ }
+ }
+ return obx_handle;
+}
+
+/*******************************************************************************
+**
+** Function obx_sr_get_cb
+**
+** Description Returns the pointer to the server control block with given handle.
+**
+*******************************************************************************/
+tOBX_SR_CB * obx_sr_get_cb(tOBX_HANDLE handle)
+{
+ tOBX_SR_CB *p_cb = NULL;
+ tOBX_HANDLE obx_handle = OBX_DEC_HANDLE(handle);
+
+ /* check range */
+ if (obx_handle <= obx_cb.num_server && obx_handle > 0 && obx_cb.server[obx_handle-1].p_cback)
+ {
+ p_cb = &obx_cb.server[obx_handle-1];
+ }
+
+ return p_cb;
+}
+
+/*******************************************************************************
+**
+** Function obx_sr_get_scb
+**
+** Description Returns the pointer to the server control block with given handle.
+**
+*******************************************************************************/
+tOBX_SR_SESS_CB * obx_sr_get_scb(tOBX_HANDLE handle)
+{
+ tOBX_SR_CB *p_cb;
+ tOBX_SR_SESS_CB *p_scb = NULL;
+ tOBX_HANDLE obx_handle;
+ UINT16 sess_ind;
+
+ /* check range */
+ obx_handle = OBX_DEC_HANDLE(handle) - 1;
+ if (obx_handle < obx_cb.num_server)
+ {
+ /* make sure the handle is a valid one */
+ p_cb = &obx_cb.server[obx_handle];
+ sess_ind = OBX_DEC_SESS_IND(handle);
+ if ((sess_ind < p_cb->num_sess))
+ {
+ if ((obx_cb.sr_sess[p_cb->sess[sess_ind]-1].ll_cb.comm.handle) == handle)
+ p_scb = &obx_cb.sr_sess[p_cb->sess[sess_ind]-1];
+ }
+ }
+
+ return p_scb;
+}
+
+/*******************************************************************************
+**
+** Function obx_sr_free_cb
+**
+** Description Free the given server control block.
+**
+** Returns void
+**
+*******************************************************************************/
+void obx_sr_free_cb(tOBX_HANDLE handle)
+{
+ tOBX_SR_CB * p_cb = obx_sr_get_cb(handle);
+ tOBX_SR_SESS_CB *p_scb;
+ int yy;
+
+ OBX_TRACE_DEBUG1("obx_sr_free_cb handle:0x%x", handle);
+ /* check range */
+ if (p_cb)
+ {
+ p_scb = &obx_cb.sr_sess[0];
+ for (yy=0; yy<obx_cb.num_sr_sess; yy++, p_scb++)
+ {
+ if (OBX_DEC_HANDLE(p_scb->handle) == OBX_DEC_HANDLE(handle))
+ {
+ obx_sr_free_scb(p_scb);
+ if (p_scb->ll_cb.comm.id>0)
+ {
+ if (p_scb->ll_cb.comm.p_send_fn == (tOBX_SEND_FN *)obx_rfc_snd_msg)
+ obx_cb.hdl_map[p_scb->ll_cb.port.port_handle - 1] = 0;
+ else
+ obx_cb.l2c_map[p_scb->ll_cb.l2c.lcid - L2CAP_BASE_APPL_CID] = 0;
+ }
+ memset(p_scb, 0, sizeof(tOBX_SR_SESS_CB) );
+ }
+ }
+
+ if (p_cb->p_auth)
+ {
+ GKI_freebuf(p_cb->p_auth);
+ p_cb->p_auth = 0;
+ }
+
+ memset(p_cb, 0, sizeof(tOBX_SR_CB) );
+ }
+}
+
+/*******************************************************************************
+**
+** Function obx_sr_free_scb
+**
+** Description Free the given server session control block.
+**
+** Returns void
+**
+*******************************************************************************/
+void obx_sr_free_scb(tOBX_SR_SESS_CB *p_scb)
+{
+ OBX_TRACE_DEBUG2("obx_sr_free_scb shandle:0x%x, sess_st:%d", p_scb->ll_cb.comm.handle, p_scb->sess_st);
+
+ /* make sure the GKI buffers are freed */
+ if (p_scb->p_saved_msg)
+ {
+ GKI_freebuf(p_scb->p_saved_msg);
+ p_scb->p_saved_msg = 0;
+ }
+
+ if (p_scb->p_next_req)
+ {
+ GKI_freebuf(p_scb->p_next_req);
+ p_scb->p_next_req = 0;
+ }
+ obx_free_buf (&p_scb->ll_cb);
+
+ /* make sure the timer is stopped */
+ btu_stop_timer(&p_scb->ll_cb.comm.tle);
+}
+
+/*******************************************************************************
+**
+** Function obx_sr_get_next_conn_id
+**
+** Description assigns the next available connection id. It will avoid using
+** active conn id instances as well so that we can work with the
+** IVT stack bugs.
+**
+*******************************************************************************/
+UINT32 obx_sr_get_next_conn_id(void)
+{
+#if (OBX_CLIENT_INCLUDED == TRUE)
+ tOBX_CL_CB *p_ccb;
+ int xx;
+ BOOLEAN done;
+
+ /* Make sure no client instances are using the value */
+ do
+ {
+ obx_cb.next_cid++;
+
+ /* Increment the value and make sure it is legal */
+ if (obx_cb.next_cid == OBX_INVALID_CONN_ID)
+ obx_cb.next_cid = OBX_INITIAL_CONN_ID;
+
+ done = TRUE;
+ for (xx=0, p_ccb = &obx_cb.client[0]; xx < obx_cb.num_client; xx++, p_ccb++)
+ {
+ /* If the handle is in use and same as proposed conn_id, increment and restart */
+ if (p_ccb->ll_cb.comm.handle != OBX_HANDLE_NULL && p_ccb->conn_id == obx_cb.next_cid)
+ {
+ OBX_TRACE_WARNING1(" **** OBX CONN_ID Collision (0x%08x) trying another...", obx_cb.next_cid);
+ done = FALSE;
+ break;
+ }
+ }
+ } while (!done);
+
+#else /* Client code is not compiled in */
+
+ obx_cb.next_cid++;
+
+ /* Increment the value and make sure it is legal */
+ if (obx_cb.next_cid == OBX_INVALID_CONN_ID)
+ obx_cb.next_cid = OBX_INITIAL_CONN_ID;
+#endif
+
+ return obx_cb.next_cid;
+}
+
+#endif /* OBX_SERVER_INCLUDED */
+
+/*******************************************************************************
+**
+** Function obx_port_handle_2cb
+**
+** Description Given a port handle, return the associated client or server
+** control block.
+**
+** Returns
+**
+*******************************************************************************/
+tOBX_PORT_CB * obx_port_handle_2cb(UINT16 port_handle)
+{
+ tOBX_PORT_CB *p_pcb = NULL;
+ tOBX_HANDLE obx_handle = 0;
+#if (OBX_SERVER_INCLUDED == TRUE)
+ tOBX_SR_CB *p_cb;
+#endif
+
+ /* this function is called by obx_rfc_cback() only.
+ * assume that port_handle is within range */
+ obx_handle = obx_cb.hdl_map[port_handle-1];
+ OBX_TRACE_DEBUG2("obx_port_handle_2cb port_handle:%d obx_handle:0x%x", port_handle, obx_handle);
+
+ if (obx_handle > 0)
+ {
+ if (obx_handle & OBX_CL_HANDLE_MASK)
+ {
+#if (OBX_CLIENT_INCLUDED == TRUE)
+ obx_handle &= OBX_CL_CB_IND_MASK;
+ p_pcb = &obx_cb.client[obx_handle - 1].ll_cb.port;
+#endif /* OBX_CLIENT_INCLUDED */
+ }
+ else
+ {
+#if (OBX_SERVER_INCLUDED == TRUE)
+ p_cb = &obx_cb.server[OBX_DEC_HANDLE(obx_handle) - 1];
+ p_pcb = &obx_cb.sr_sess[p_cb->sess[OBX_DEC_SESS_IND(obx_handle)]-1].ll_cb.port;
+ OBX_TRACE_DEBUG1("p_pcb port_handle:%d", p_pcb->port_handle);
+#endif /* OBX_SERVER_INCLUDED */
+ }
+ }
+
+ return p_pcb;
+}
+
+
+
+/*******************************************************************************
+**
+** Function OBX_Init
+**
+** Description This function is called to initialize the control block for this
+** layer. It must be called before accessing any other of its API
+** functions. It is typically called once during the start up of
+** the stack.
+**
+** Returns void.
+**
+*******************************************************************************/
+void OBX_Init(void)
+{
+ memset(&obx_cb, 0, sizeof(tOBX_CB));
+
+#if defined(OBX_INITIAL_TRACE_LEVEL)
+ obx_cb.trace_level = OBX_INITIAL_TRACE_LEVEL;
+#else
+ obx_cb.trace_level = BT_TRACE_LEVEL_NONE; /* No traces */
+#endif
+
+#if (OBX_CLIENT_INCLUDED == TRUE)
+ obx_cb.next_ind = 0;
+ obx_cb.num_client = OBX_NUM_CLIENTS;
+#endif
+
+#if (OBX_SERVER_INCLUDED == TRUE)
+ obx_cb.num_server = OBX_NUM_SERVERS;
+ obx_cb.num_sr_sess = OBX_NUM_SR_SESSIONS;
+ obx_cb.next_cid = OBX_INITIAL_CONN_ID;
+#endif
+ obx_cb.timeout_val = OBX_TIMEOUT_VALUE;
+ obx_cb.sess_tout_val= OBX_SESS_TIMEOUT_VALUE;
+ obx_cb.max_rx_qcount= OBX_MAX_RX_QUEUE_COUNT;
+}
+
+/*******************************************************************************
+**
+** Function OBX_SetTraceLevel
+**
+** Description This function sets the debug trace level for OBX.
+** If 0xff is passed, the current trace level is returned.
+**
+** Input Parameters:
+** level: The level to set the OBX tracing to:
+** 0xff-returns the current setting.
+** 0-turns off tracing.
+** >= 1-Errors.
+** >= 2-Warnings.
+** >= 3-APIs.
+** >= 4-Events.
+** >= 5-Debug.
+**
+** Returns The new trace level or current trace level if
+** the input parameter is 0xff.
+**
+*******************************************************************************/
+UINT8 OBX_SetTraceLevel (UINT8 level)
+{
+ if (level != 0xFF)
+ obx_cb.trace_level = level;
+
+ return (obx_cb.trace_level);
+}
+
+/*******************************************************************************
+** Function OBX_HandleToMtu
+**
+** Description Given an OBEX handle, return the associated peer MTU.
+**
+** Returns MTU.
+**
+*******************************************************************************/
+UINT16 OBX_HandleToMtu(tOBX_HANDLE handle)
+{
+ UINT16 mtu = OBX_MIN_MTU;
+ BOOLEAN rx = (handle & OBX_HANDLE_RX_MTU_MASK);
+#if (OBX_CLIENT_INCLUDED == TRUE)
+ int xx;
+#endif
+#if (OBX_SERVER_INCLUDED == TRUE)
+ tOBX_SR_SESS_CB *p_scb;
+#endif
+
+ handle &= ~OBX_HANDLE_RX_MTU_MASK;
+
+ if (handle != OBX_HANDLE_NULL)
+ {
+ if (handle & OBX_CL_HANDLE_MASK)
+ {
+#if (OBX_CLIENT_INCLUDED == TRUE)
+ /* a client handle */
+ for (xx=0; xx<obx_cb.num_client; xx++)
+ {
+ if (handle == obx_cb.client[xx].ll_cb.comm.handle)
+ {
+ mtu = (rx) ? obx_cb.client[xx].ll_cb.comm.rx_mtu : obx_cb.client[xx].ll_cb.comm.tx_mtu;
+ break;
+ }
+ }
+#endif
+ }
+ else
+ {
+#if (OBX_SERVER_INCLUDED == TRUE)
+ /* a server handle */
+ p_scb = obx_sr_get_scb(handle);
+ /* make sure the handle is a valid one */
+ if (p_scb && p_scb->ll_cb.comm.handle != OBX_HANDLE_NULL)
+ {
+ mtu = (rx) ? p_scb->ll_cb.comm.rx_mtu : p_scb->ll_cb.comm.tx_mtu;
+ }
+#endif
+ }
+ }
+
+ if (mtu < OBX_MIN_MTU)
+ mtu = OBX_MIN_MTU;
+ OBX_TRACE_DEBUG3("OBX_HandleToMtu handle: 0x%x, rx:%x, mtu:%d", handle, rx, mtu);
+ return mtu;
+}
+
diff --git a/stack/obx/obx_md5.c b/stack/obx/obx_md5.c
new file mode 100644
index 0000000..6e0d6ea
--- /dev/null
+++ b/stack/obx/obx_md5.c
@@ -0,0 +1,1050 @@
+/*****************************************************************************
+**
+** Name: obx_md5.c
+**
+** File: OBEX Authentication related functions
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include <stdio.h>
+#include <string.h>
+
+#include "bt_target.h"
+#include "btu.h"
+#include "obx_int.h"
+#include "wcassert.h"
+
+
+
+/*
+* This code implements the MD5 message-digest algorithm.
+* The algorithm is due to Ron Rivest. This code was
+* written by Colin Plumb in 1993, no copyright is claimed.
+* This code is in the public domain; do with it what you wish.
+*
+* Equivalent code is available from RSA Data Security, Inc.
+* This code has been tested against that, and is equivalent,
+* except that you don't need to include two pages of legalese
+* with every copy.
+*
+* To compute the message digest of a chunk of bytes, declare an
+* MD5Context structure, pass it to MD5Init, call MD5Update as
+* needed on buffers full of bytes, and then call MD5Final, which
+* will fill a supplied 16-byte array with the digest.
+*/
+typedef UINT32 word32;
+typedef UINT8 byte;
+struct xMD5Context {
+ word32 buf[4];
+ word32 bytes[2];
+ word32 in[16];
+};
+
+static void obx_md5_transform(word32 buf[4], word32 const in[16]);
+
+/*
+* Shuffle the bytes into little-endian order within words, as per the
+* MD5 spec. Note: this code works regardless of the byte order.
+*/
+static void obx_byte_swap(word32 *buf, unsigned words)
+{
+ byte *p = (byte *)buf;
+ do {
+ *buf++ = (word32)((unsigned)p[3] << 8 | p[2]) << 16
+ | (word32)((unsigned)p[1] << 8 | p[0]);
+ p += 4;
+ } while (--words);
+}
+
+/*
+* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
+* initialization constants.
+*/
+static void obx_md5_init(struct xMD5Context *ctx)
+{
+ ctx->buf[0] = 0x67452301;
+ ctx->buf[1] = 0xefcdab89;
+ ctx->buf[2] = 0x98badcfe;
+ ctx->buf[3] = 0x10325476;
+ ctx->bytes[0] = 0;
+ ctx->bytes[1] = 0;
+}
+
+/*
+* Update context to reflect the concatenation of another buffer full
+* of bytes.
+*/
+static void obx_md5_update(struct xMD5Context *ctx, byte const *buf, int len)
+{
+ word32 t;
+ /* Update byte count */
+ t = ctx->bytes[0];
+ if ((ctx->bytes[0] = t + len) < t)
+ ctx->bytes[1]++; /* Carry from low to high */
+ t = 64 - (t & 0x3f); /* Space avail in ctx->in (at least 1) */
+ if ((unsigned)t > (unsigned)len)
+ {
+ memcpy ((byte *)ctx->in + 64 - (unsigned)t, buf, len);
+ return;
+ }
+ /* First chunk is an odd size */
+ memcpy (ctx->in + (64 - (unsigned)t), buf, (unsigned)t);
+ obx_byte_swap(ctx->in, 16);
+ obx_md5_transform(ctx->buf, ctx->in);
+ buf += (unsigned)t;
+ len -= (unsigned)t;
+ /* Process data in 64-byte chunks */
+ while (len >= 64)
+ {
+ /* coverity[access_dbuff_const] */
+ memcpy (ctx->in, buf, 64);
+ obx_byte_swap(ctx->in, 16);
+ obx_md5_transform(ctx->buf, ctx->in);
+ buf += 64;
+ len -= 64;
+ }
+ /* Handle any remaining bytes of data. */
+ memcpy (ctx->in, buf, len);
+}
+
+/*
+* Final wrapup - pad to 64-byte boundary with the bit pattern
+* 1 0* (64-bit count of bits processed, MSB-first)
+*/
+static void obx_md5_final(byte digest[16], struct xMD5Context *ctx)
+{
+ int count = (int)(ctx->bytes[0] & 0x3f); /* Bytes in ctx->in */
+ byte *p = (byte *)ctx->in + count; /* First unused byte */
+ /* Set the first char of padding to 0x80. There is always room.*/
+ *p++ = 0x80;
+ /* Bytes of padding needed to make 56 bytes (-8..55) */
+ count = 56 - 1 - count;
+ if (count < 0) /* Padding forces an extra block */
+ {
+ memset (p, 0, count+8);
+ obx_byte_swap(ctx->in, 16);
+ obx_md5_transform(ctx->buf, ctx->in);
+ p = (byte *)ctx->in;
+ count = 56;
+ }
+ memset (p, 0, count+8);
+ obx_byte_swap(ctx->in, 14);
+ /* Append length in bits and transform */
+ ctx->in[14] = ctx->bytes[0] << 3;
+ ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29;
+ obx_md5_transform(ctx->buf, ctx->in);
+ obx_byte_swap(ctx->buf, 4);
+ memcpy (digest, ctx->buf, 16);
+ memset (ctx, 0, sizeof(ctx));
+}
+
+/* The four core functions - F1 is optimized somewhat */
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f,w,x,y,z,in,s) \
+(w += f(x,y,z) + in, w = (w<<s | w>>(32-s)) + x)
+
+/*
+* The core of the MD5 algorithm, this alters an existing MD5 hash to
+* reflect the addition of 16 longwords of new data. MD5Update blocks
+* the data and converts bytes into longwords for this routine.
+*/
+static const word32 obx_md5_f1 [] =
+{
+ 0xd76aa478,
+ 0xe8c7b756,
+ 0x242070db,
+ 0xc1bdceee,
+
+ 0xf57c0faf,
+ 0x4787c62a,
+ 0xa8304613,
+ 0xfd469501,
+
+ 0x698098d8,
+ 0x8b44f7af,
+ 0xffff5bb1,
+ 0x895cd7be,
+
+ 0x6b901122,
+ 0xfd987193,
+ 0xa679438e,
+ 0x49b40821
+};
+
+static const word32 obx_md5_f2 [] =
+{
+ 0xf61e2562,
+ 0xc040b340,
+ 0x265e5a51,
+ 0xe9b6c7aa,
+
+ 0xd62f105d,
+ 0x02441453,
+ 0xd8a1e681,
+ 0xe7d3fbc8,
+
+ 0x21e1cde6,
+ 0xc33707d6,
+ 0xf4d50d87,
+ 0x455a14ed,
+
+ 0xa9e3e905,
+ 0xfcefa3f8,
+ 0x676f02d9,
+ 0x8d2a4c8a
+};
+
+static const word32 obx_md5_f3 [] =
+{
+ 0xfffa3942,
+ 0x8771f681,
+ 0x6d9d6122,
+ 0xfde5380c,
+
+ 0xa4beea44,
+ 0x4bdecfa9,
+ 0xf6bb4b60,
+ 0xbebfbc70,
+
+ 0x289b7ec6,
+ 0xeaa127fa,
+ 0xd4ef3085,
+ 0x04881d05,
+
+ 0xd9d4d039,
+ 0xe6db99e5,
+ 0x1fa27cf8,
+ 0xc4ac5665
+};
+
+static const word32 obx_md5_f4 [] =
+{
+ 0xf4292244,
+ 0x432aff97,
+ 0xab9423a7,
+ 0xfc93a039,
+
+ 0x655b59c3,
+ 0x8f0ccc92,
+ 0xffeff47d,
+ 0x85845dd1,
+
+ 0x6fa87e4f,
+ 0xfe2ce6e0,
+ 0xa3014314,
+ 0x4e0811a1,
+
+ 0xf7537e82,
+ 0xbd3af235,
+ 0x2ad7d2bb,
+ 0xeb86d391
+};
+
+static const UINT8 obx_md5_a [] =
+{
+ 1,
+ 2,
+ 3,
+ 0,
+ 1,
+ 2,
+ 3
+};
+
+static const word32 obx_md5_var1 [] =
+{
+ 7,
+ 12,
+ 17,
+ 22
+};
+
+static const word32 obx_md5_var2 [] =
+{
+ 5,
+ 9,
+ 14,
+ 20
+};
+
+static const word32 obx_md5_var3 [] =
+{
+ 4,
+ 11,
+ 16,
+ 23
+};
+
+static const word32 obx_md5_var4 [] =
+{
+ 6,
+ 10,
+ 15,
+ 21
+};
+
+static void obx_md5_transform(word32 buf[4], word32 const in[16])
+{
+ int xx, yy, zz, i, j, k;
+ word32 a[4];
+
+ a[0] = buf[0];
+ a[1] = buf[1];
+ a[2] = buf[2];
+ a[3] = buf[3];
+
+ yy = 0;
+ for(xx=0; xx<4; xx++)
+ {
+ j = 3;
+ for(i=0; i < 4; i++)
+ {
+ k = j--;
+ /*
+ OBX_TRACE_DEBUG4( "f1 a: %d, yy: %d, inc: 0x%x, var: %d",
+ obx_md5_a[k], yy, obx_md5_f1[yy], obx_md5_var1[i]);
+ */
+ MD5STEP(F1, a[obx_md5_a[k]], a[obx_md5_a[k+1]], a[obx_md5_a[k+2]], a[obx_md5_a[k+3]],
+ in[yy] + obx_md5_f1[yy], obx_md5_var1[i]);
+ yy++;
+ }
+ }
+
+ yy = 1;
+ zz = 0;
+ for(xx=0; xx<4; xx++)
+ {
+ j = 3;
+ for(i=0; i < 4; i++)
+ {
+ k = j--;
+ /*
+ OBX_TRACE_DEBUG4( "f2 a: %d, yy: %d, inc: 0x%x, var: %d",
+ obx_md5_a[k], yy, obx_md5_f2[zz], obx_md5_var2[i]);
+ */
+ MD5STEP(F2, a[obx_md5_a[k]], a[obx_md5_a[k+1]], a[obx_md5_a[k+2]], a[obx_md5_a[k+3]],
+ in[yy] + obx_md5_f2[zz++], obx_md5_var2[i]);
+ yy += 5;
+ yy %= 16;
+ }
+ }
+
+ yy = 5;
+ zz = 0;
+ for(xx=0; xx<4; xx++)
+ {
+ j = 3;
+ for(i=0; i < 4; i++)
+ {
+ k = j--;
+ /*
+ OBX_TRACE_DEBUG4( "f3 a: %d, yy: %d, inc: 0x%x, var: %d",
+ obx_md5_a[k], yy, obx_md5_f3[zz], obx_md5_var3[i]);
+ */
+ MD5STEP(F3, a[obx_md5_a[k]], a[obx_md5_a[k+1]], a[obx_md5_a[k+2]], a[obx_md5_a[k+3]],
+ in[yy] + obx_md5_f3[zz++], obx_md5_var3[i]);
+ yy += 3;
+ yy %= 16;
+ }
+ }
+
+
+ yy = 0;
+ zz = 0;
+ for(xx=0; xx<4; xx++)
+ {
+ j = 3;
+ for(i=0; i < 4; i++)
+ {
+ k = j--;
+ /*
+ OBX_TRACE_DEBUG4( "f4 a: %d, yy: %d, inc: 0x%x, var: %d",
+ obx_md5_a[k], yy, obx_md5_f4[zz], obx_md5_var4[i]);
+ */
+ MD5STEP(F4, a[obx_md5_a[k]], a[obx_md5_a[k+1]], a[obx_md5_a[k+2]], a[obx_md5_a[k+3]],
+ in[yy] + obx_md5_f4[zz++], obx_md5_var4[i]);
+ yy += 7;
+ yy %= 16;
+ }
+ }
+
+ buf[0] += a[0];
+ buf[1] += a[1];
+ buf[2] += a[2];
+ buf[3] += a[3];
+}
+
+/*******************************************************************************
+**
+** Function OBX_MD5
+**
+** Description This function is called to run the MD5 algorithm.
+**
+** Returns void
+**
+*******************************************************************************/
+static void OBX_MD5(void *digest, UINT8 *nonce, UINT8 * password, int password_len)
+{
+ struct xMD5Context context;
+ UINT8 before[OBX_NONCE_SIZE + OBX_MAX_AUTH_KEY_SIZE + 4];
+
+ memcpy(before, nonce, OBX_NONCE_SIZE);
+ before[OBX_NONCE_SIZE] = ':';
+ memcpy(before + OBX_NONCE_SIZE + 1, password, password_len);
+ /*
+ scru_dump_hex (before, "before", OBX_NONCE_SIZE + 1 + password_len, TRACE_LAYER_OBEX, TRACE_TYPE_GENERIC);
+ */
+
+ obx_md5_init(&context);
+/* coverity[overrun-buffer-val] */
+/*
+FALSE-POSITIVE: coverity says "Overrun of static array "before" of size 36 bytes by passing it as an argument to a function which indexes it at byte position 63"
+obx_md5_update() only goes into that condition when (len >= 64). In this case, len is (OBX_NONCE_SIZE + 1 + password_len) which is less than or equal to 33.
+password_len is less than or equal to OBX_MAX_AUTH_KEY_SIZE. The size of before[] is more than enough */
+ obx_md5_update(&context, (byte const *)before, OBX_NONCE_SIZE + 1 + password_len);
+ obx_md5_final((byte *)digest, &context);
+ /*
+ scru_dump_hex (digest, "after", 16, TRACE_LAYER_OBEX, TRACE_TYPE_GENERIC);
+ */
+}
+
+/*******************************************************************************
+**
+** Function obx_session_id
+**
+** Description This function is called to run the MD5 algorithm to create a
+** session id.
+**
+** Returns void
+**
+*******************************************************************************/
+void obx_session_id(UINT8 *p_sess_id, UINT8 *p_cl_addr, UINT8 * p_cl_nonce, int cl_nonce_len,
+ UINT8 *p_sr_addr, UINT8 * p_sr_nonce, int sr_nonce_len)
+{
+ struct xMD5Context context;
+ UINT8 before[(OBX_NONCE_SIZE + BD_ADDR_LEN) * 2 + 4];
+ UINT8 *p = before;
+ UINT8 len;
+
+ memcpy(p, p_cl_addr, BD_ADDR_LEN);
+ p += BD_ADDR_LEN;
+ memcpy(p, p_cl_nonce, cl_nonce_len);
+ p += cl_nonce_len;
+ memcpy(p, p_sr_addr, BD_ADDR_LEN);
+ p += BD_ADDR_LEN;
+ memcpy(p, p_sr_nonce, sr_nonce_len);
+ p += sr_nonce_len;
+ /*
+ scru_dump_hex (before, "before", OBX_NONCE_SIZE + 1 + password_len, TRACE_LAYER_OBEX, TRACE_TYPE_GENERIC);
+ */
+
+ len = BD_ADDR_LEN + cl_nonce_len + BD_ADDR_LEN + sr_nonce_len;
+ obx_md5_init(&context);
+/* coverity [overrun-buffer-val] */
+/* Overrun of static array "before" of size 48 bytes by passing it as an argument to a function which indexes it at byte position 63*/
+/* FALSE-POSITIVE: obx_md5_update() only goes into that condition when (len >= 64). In this case, len is (OBX_NONCE_SIZE + 1 + password_len) which is less than or equal to 33.
+password_len is less than or equal to OBX_MAX_AUTH_KEY_SIZE. The size of before[] is more than enough */
+ obx_md5_update(&context, (byte const *)before, len);
+ obx_md5_final((byte *)p_sess_id, &context);
+ /*
+ scru_dump_hex (p_sess_id, "after", 16, TRACE_LAYER_OBEX, TRACE_TYPE_GENERIC);
+ */
+}
+
+#if (OBX_SERVER_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function obx_copy_and_rm_auth_hdrs
+**
+** Description This function is used to copy the given OBEX packet to a new packet
+** with the authentication headers removed.
+**
+** Returns tOBX_STATUS
+**
+*******************************************************************************/
+tOBX_STATUS obx_copy_and_rm_auth_hdrs(BT_HDR *p_pkt, BT_HDR *p_new, UINT8 * p_hi)
+{
+ tOBX_STATUS status = OBX_SUCCESS;
+ UINT8 *pn, *po, *p_nlen = NULL;
+ int hsize, nsize;
+ UINT16 nlen, olen;
+ UINT8 size;
+ int xx;
+
+ WC_ASSERT(p_new);
+
+
+ po = (UINT8 *)(p_pkt + 1) + p_pkt->offset + 1;
+ BE_STREAM_TO_UINT16(olen, po);
+ OBX_TRACE_DEBUG3( "obx_copy_and_rm_auth_hdrs event: %d, new len:%d, olen:%d",
+ p_pkt->event, p_new->len, olen);
+
+ po = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ if(p_new->len == 0)
+ {
+ p_new->offset = p_pkt->offset;
+ p_nlen = (UINT8 *)(p_new + 1) + p_new->offset + 1;
+ }
+ pn = (UINT8 *)(p_new + 1) + p_new->offset;
+
+ /* Get the number of bytes before headers start */
+ size = obx_hdr_start_offset[p_pkt->event - 1];
+ if(p_new->len)
+ {
+ /* for OBX_AuthResponse
+ * - do not need to copy the stuff before headers
+ * there's already some header, skip them */
+ pn += p_new->len;
+ nlen = p_new->len;
+ }
+ else
+ {
+ /* for obx_unauthorize_rsp
+ * - needs to copy the stuff before headers */
+ memcpy(pn, po, size);
+ pn += size;
+ nlen = size;
+ }
+ po += size;
+
+ olen -= size;
+ while(olen)
+ {
+ OBX_TRACE_DEBUG1( "olen:%d", olen);
+ hsize = (int)obx_read_header_len(po);
+ if(olen > hsize)
+ olen -= hsize;
+ else
+ olen = 0;
+
+ xx = 0;
+ nsize = hsize;
+ while(p_hi[xx] != OBX_HI_NULL)
+ {
+ /*
+ OBX_TRACE_DEBUG2( "po:0x%x, hix:0x%x", *po, p_hi[xx]);
+ */
+ if(*po == p_hi[xx++])
+ {
+ nsize = 0;
+ break;
+ }
+ }
+ OBX_TRACE_DEBUG2( "hsize:%d, nsize:%d", hsize, nsize);
+ if(nsize)
+ {
+ /* skip auth challenge and auth response */
+ if((nlen+hsize) < p_pkt->layer_specific)
+ {
+ /* copy other headers */
+ memcpy(pn, po, hsize);
+ pn += hsize;
+ nlen += hsize;
+ }
+ else
+ {
+ OBX_TRACE_WARNING1( "obx_copy_and_rm_auth_hdrs Not enough room: %d", olen);
+ /* no more room in the new packet */
+ status = OBX_NO_RESOURCES;
+ break;
+ }
+ }
+ po += hsize;
+ }
+
+ if(status == OBX_SUCCESS)
+ {
+ if(p_nlen)
+ {
+ UINT16_TO_BE_STREAM(p_nlen, nlen);
+ }
+ p_new->len = nlen;
+ p_new->layer_specific = GKI_get_buf_size(p_new) - BT_HDR_SIZE - p_new->offset;
+ p_new->event = p_pkt->event;
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function obx_unauthorize_rsp
+**
+** Description This function is used to add authentication challenge triplet
+**
+** Returns void.
+** Note: this function assumes that all data can fit in the MTU
+*******************************************************************************/
+BT_HDR * obx_unauthorize_rsp(tOBX_SR_CB *p_cb, tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt)
+{
+ UINT8 *p;
+ UINT8 nonce[OBX_NONCE_SIZE+2];
+ UINT8 option[2];
+ UINT8 *p_target = NULL;
+ tOBX_TRIPLET triplet[OBX_MAX_NUM_AUTH_TRIPLET];
+ UINT8 num_trip = 0;
+ BT_HDR *p_old;
+ UINT8 hi[] = {OBX_HI_CHALLENGE, OBX_HI_AUTH_RSP, OBX_HI_NULL};
+
+ OBX_TRACE_DEBUG1( "obx_unauthorize_rsp: %d", p_cb->target.len);
+ if(OBX_CheckHdr(p_pkt, OBX_HI_CHALLENGE) || OBX_CheckHdr(p_pkt, OBX_HI_AUTH_RSP))
+ {
+ p_old = p_pkt;
+ p_pkt = OBX_HdrInit(p_scb->ll_cb.comm.handle, (UINT16)(p_old->len + BT_HDR_SIZE + p_old->offset));
+ obx_copy_and_rm_auth_hdrs(p_old, p_pkt, hi);
+ GKI_freebuf(p_old);
+ }
+
+ if(p_cb->target.len)
+ {
+ /* There must be the target header, change it to be WHO header */
+ if( (p_target = OBX_CheckHdr(p_pkt, OBX_HI_TARGET)) != NULL)
+ {
+ *p_target = OBX_HI_WHO;
+ }
+ }
+ OBX_TRACE_DEBUG1( "p_target: %x", p_target);
+
+ if(p_cb->p_auth)
+ {
+ /* server registers for authentication */
+ /* prepare the triplet byte sequence */
+ /* add nonce: tag, length, value */
+ p_cb->p_auth->nonce = GKI_get_tick_count();
+ sprintf ((char *)nonce, "%016lu", p_cb->p_auth->nonce);
+
+ num_trip = 0;
+ triplet[num_trip].tag = OBX_NONCE_CHLNG_TAG;
+ triplet[num_trip].len = OBX_NONCE_SIZE;
+ triplet[num_trip].p_array = nonce;
+ num_trip++;
+
+ if(p_cb->p_auth->auth_option)
+ {
+ /* add option */
+ triplet[num_trip].tag = OBX_OPTIONS_CHLNG_TAG;
+ triplet[num_trip].len = 1;
+ option[0] = p_cb->p_auth->auth_option;
+ triplet[num_trip].p_array = option;
+ num_trip++;
+ }
+ if(p_cb->p_auth->realm_len)
+ {
+ /* add realm */
+ triplet[num_trip].tag = OBX_REALM_CHLNG_TAG;
+ triplet[num_trip].len = p_cb->p_auth->realm_len+1;
+ triplet[num_trip].p_array = p_cb->p_auth->realm;
+ num_trip++;
+ }
+
+ /* add the sequence to header */
+ OBX_AddTriplet(p_pkt, OBX_HI_CHALLENGE, triplet, num_trip);
+ }
+
+ p = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ /* change the opcode to unauthorized response */
+ *p++ = OBX_RSP_UNAUTHORIZED | OBX_FINAL;
+ /* adjust the packet len */
+ UINT16_TO_BE_STREAM(p, p_pkt->len);
+
+ /* add session sequence number, if session is active */
+ if ((p_scb->sess_st == OBX_SESS_ACTIVE) && ((p_target = OBX_CheckHdr(p_pkt, OBX_HI_SESSION_SN)) != NULL))
+ {
+ p_target++;
+ (*p_target)++;
+ }
+
+ p_pkt->event = OBX_CONNECT_RSP_EVT;
+
+ return p_pkt;
+}
+
+/*******************************************************************************
+**
+** Function OBX_Password
+**
+** Description This function is called by the server to respond to an
+** OBX_PASSWORD_EVT event.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_NO_RESOURCES, if OBX does not resources
+**
+*******************************************************************************/
+tOBX_STATUS OBX_Password(tOBX_HANDLE shandle, UINT8 *p_password, UINT8 password_len,
+ UINT8 *p_userid, UINT8 userid_len)
+{
+ tOBX_STATUS status = OBX_SUCCESS;
+ BT_HDR *p_pkt;
+ BT_HDR *p_rsp;
+ UINT8 temp_digest[OBX_DIGEST_SIZE];
+ UINT8 nonce[OBX_NONCE_SIZE + 1];
+ BOOLEAN pass = FALSE;
+ BOOLEAN digest_done = FALSE;
+ BOOLEAN option_userid = FALSE;
+ tOBX_TRIPLET triplet[OBX_MAX_NUM_AUTH_TRIPLET];
+ UINT8 num_trip = OBX_MAX_NUM_AUTH_TRIPLET;
+ UINT8 xx;
+ UINT8 *p_target;
+ UINT16 tlen;
+ tOBX_SR_SESS_CB *p_scb = obx_sr_get_scb(shandle);
+ tOBX_SR_CB *p_cb = obx_sr_get_cb(shandle);
+ UINT8 *p;
+ tOBX_EVT_PARAM param; /* The event parameter. */
+
+ WC_ASSERT(password_len < OBX_MAX_AUTH_KEY_SIZE);
+
+ if(p_scb == NULL || p_scb->p_saved_msg == NULL)
+ return OBX_NO_RESOURCES;
+
+ /* The coverity complaints on this function is not correct.
+ * The value in triplet[] is set/initialized by OBX_ReadTriplet if num_trip returns TRUE.
+ * leave this unnecessary memset here */
+ memset(triplet,0,sizeof(triplet));
+
+ p_pkt = p_scb->p_saved_msg;
+
+ if(p_cb->p_auth == NULL)
+ {
+ pass = TRUE;
+ }
+ else if(OBX_ReadTriplet(p_pkt, OBX_HI_AUTH_RSP, triplet, &num_trip) == TRUE)
+ {
+ if(p_password && password_len )
+ {
+ /* if given password, verify it */
+ for(xx=0; xx<num_trip; xx++)
+ {
+ if(triplet[xx].tag == OBX_DIGEST_RSP_TAG)
+ {
+ sprintf((char *)nonce, "%016lu", p_cb->p_auth->nonce);
+ OBX_MD5 (temp_digest, nonce, p_password, password_len);
+ if (memcmp (temp_digest, triplet[xx].p_array, OBX_DIGEST_SIZE) == 0)
+ pass = TRUE;
+ break;
+ }
+ }
+ }
+ }
+
+ /* check if challenged by client */
+ num_trip = OBX_MAX_NUM_AUTH_TRIPLET;
+ if(pass == TRUE && OBX_ReadTriplet(p_pkt, OBX_HI_CHALLENGE, triplet, &num_trip) == TRUE)
+ {
+ /* Make sure password was passed in and not empty */
+ if (p_password && password_len )
+ {
+ for(xx=0; xx<num_trip; xx++)
+ {
+ if(triplet[xx].tag == OBX_NONCE_CHLNG_TAG)
+ {
+ /* nonce tag is mandatory */
+ OBX_MD5 (temp_digest, triplet[xx].p_array, p_password, password_len);
+ digest_done = TRUE;
+ }
+ else if(triplet[xx].tag == OBX_OPTIONS_CHLNG_TAG)
+ {
+ /* user ID bit is set */
+ if(OBX_AO_USR_ID & triplet[xx].p_array[0])
+ option_userid = TRUE;
+ }
+ }
+
+ if (option_userid && (userid_len == 0 || p_userid == NULL) )
+ {
+ status = OBX_BAD_PARAMS;
+ }
+ }
+ }
+
+ if(status == OBX_SUCCESS)
+ {
+ p_scb->p_saved_msg = NULL;
+ if(pass == TRUE)
+ {
+ p_rsp = OBX_HdrInit(shandle, OBX_MIN_MTU);
+
+ /* add the authentication response if been challenged */
+ if(digest_done)
+ {
+ num_trip = 1;
+ triplet[0].tag = OBX_DIGEST_RSP_TAG;
+ triplet[0].len = OBX_DIGEST_SIZE;
+ triplet[0].p_array = temp_digest;
+ if(option_userid)
+ {
+ num_trip++;
+ triplet[1].tag = OBX_USERID_RSP_TAG;
+ triplet[1].len = userid_len;
+ triplet[1].p_array = p_userid;
+ }
+ OBX_AddTriplet(p_rsp, OBX_HI_AUTH_RSP, triplet, num_trip);
+ }
+
+ if( p_cb->target.len == OBX_DEFAULT_TARGET_LEN &&
+ OBX_ReadTargetHdr(p_pkt, &p_target, &tlen, 0) == TRUE)
+ {
+ /* API user is supposed to handle WHO header
+ * for this special case, we add it for the API user */
+ OBX_AddWhoHdr(p_rsp, p_target, tlen);
+ }
+
+ /* use OBX_ConnectRsp to fill the common data */
+ status = OBX_ConnectRsp(shandle, OBX_RSP_OK, p_rsp);
+ if(status == OBX_SUCCESS)
+ {
+ /* If authentication is successful, need to update session info */
+ p = &p_scb->sess_info[OBX_SESSION_INFO_ID_IDX];
+ UINT32_TO_BE_STREAM(p, p_scb->conn_id);
+ param.sess.p_sess_info = p_scb->sess_info;
+ param.sess.sess_op = OBX_SESS_OP_CREATE;
+ param.sess.sess_st = p_scb->sess_st;
+ param.sess.nssn = p_scb->param.ssn;
+ param.sess.ssn = p_scb->param.ssn;
+ param.sess.obj_offset = 0;
+ p = &p_scb->sess_info[OBX_SESSION_INFO_MTU_IDX];
+ UINT16_TO_BE_STREAM(p, p_scb->param.conn.mtu);
+ memcpy(param.sess.peer_addr, p_scb->peer_addr, BD_ADDR_LEN);
+ (*p_cb->p_cback)(p_scb->ll_cb.comm.handle, OBX_SESSION_REQ_EVT, param, p_pkt);
+ (*p_cb->p_cback)(p_scb->ll_cb.comm.handle, OBX_CONNECT_REQ_EVT, p_scb->param, p_pkt);
+ }
+ else
+ GKI_freebuf(p_pkt);
+ }
+ else
+ {
+ /* server can not find the password, send unauthorized response */
+ p_pkt = obx_unauthorize_rsp(p_cb, p_scb, p_pkt);
+ obx_ssm_event(p_scb, OBX_CONNECT_CFM_SEVT, p_pkt);
+ }
+ }
+ /*
+ else p_scb->p_saved_msg is still valid.
+ */
+
+ return status;
+}
+#endif
+
+
+#if (OBX_CLIENT_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function OBX_AuthResponse
+**
+** Description This function is called by the client to respond to an
+** OBX_PASSWORD_EVT event.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_NO_RESOURCES, if OBX does not resources
+**
+*******************************************************************************/
+tOBX_STATUS OBX_AuthResponse(tOBX_HANDLE handle,
+ UINT8 *p_password, UINT8 password_len,
+ UINT8 *p_userid, UINT8 userid_len,
+ BOOLEAN authenticate)
+{
+ tOBX_CL_CB *p_cb = obx_cl_get_cb(handle);
+ tOBX_STATUS status = OBX_NO_RESOURCES;
+ BT_HDR *p_pkt;
+ BT_HDR *p_saved_req;
+ UINT8 num_trip, flags = 0;
+ UINT16 nlen, xx;
+ UINT8 temp_digest[OBX_DIGEST_SIZE];
+ UINT8 nonce[OBX_NONCE_SIZE + 1];
+ BOOLEAN digest_done = FALSE;
+ BOOLEAN option_userid = FALSE;
+ UINT8 rsp_code;
+ BOOLEAN final;
+ UINT8 *p_target;
+ tOBX_TRIPLET triplet[OBX_MAX_NUM_AUTH_TRIPLET];
+ UINT8 hi[] = {OBX_HI_CONN_ID, OBX_HI_TARGET, OBX_HI_CHALLENGE, OBX_HI_AUTH_RSP,
+ OBX_HI_SESSION_SN, /* prevent SSN from being copied */
+ OBX_HI_NULL};
+ WC_ASSERT(password_len < OBX_MAX_AUTH_KEY_SIZE);
+ WC_ASSERT(p_password);
+
+ if(p_cb == NULL || p_cb->p_auth == NULL || p_cb->p_saved_req == NULL)
+ return OBX_NO_RESOURCES;
+
+ p_saved_req = p_cb->p_saved_req;
+ p_pkt = OBX_HdrInit(handle, GKI_MAX_BUF_SIZE); /* make sure added length will fit */
+ WC_ASSERT(p_pkt);
+ OBX_TRACE_DEBUG2("OBX_AuthResponse p_saved_req:%d, p_saved_req->len %d ",
+ p_saved_req->event, p_saved_req->len);
+
+ /* if the save_req contains SSN, add it now */
+ if ((p_target = OBX_CheckHdr(p_saved_req, OBX_HI_SESSION_SN)) != NULL)
+ {
+ p_target++;
+ OBX_Add1ByteHdr(p_pkt, OBX_HI_SESSION_SN, (UINT8)((*p_target) + 1));
+ }
+
+ /* The coverity complaints on this function is not correct.
+ * The value in triplet[] is set/initialized by OBX_ReadTriplet if num_trip returns TRUE.
+ * leave this unnecessary memset here */
+ memset(triplet,0,sizeof(triplet));
+
+ /* if target header exists in the original request
+ * and the Connection ID has not been assigned yet,
+ * copy the target header over */
+ if(OBX_ReadTargetHdr(p_saved_req, &p_target, &nlen, 0) == TRUE)
+ {
+ OBX_AddTargetHdr(p_pkt, p_target, nlen);
+ }
+
+ /* read the challenge from received packet */
+ num_trip = OBX_MAX_NUM_AUTH_TRIPLET;
+ if(OBX_ReadTriplet(p_cb->p_auth, OBX_HI_CHALLENGE, triplet, &num_trip) == TRUE)
+ {
+ status = OBX_SUCCESS;
+ for(xx=0; xx<num_trip; xx++)
+ {
+ if(triplet[xx].tag == OBX_NONCE_CHLNG_TAG)
+ {
+ /* nonce tag is mandatory */
+ OBX_MD5 (temp_digest, triplet[xx].p_array, p_password, password_len);
+ digest_done = TRUE;
+ }
+ else if(triplet[xx].tag == OBX_OPTIONS_CHLNG_TAG)
+ {
+ /* user ID bit is set */
+ if(OBX_AO_USR_ID & triplet[xx].p_array[0])
+ option_userid = TRUE;
+ }
+ }
+
+ if(option_userid && (userid_len == 0 || p_userid == NULL) )
+ {
+ status = OBX_BAD_PARAMS;
+ }
+ OBX_TRACE_DEBUG2( "num_trip:%d, option_userid:%d", num_trip, option_userid);
+
+ if(digest_done && status == OBX_SUCCESS)
+ {
+ /* Compose and add the authentication Response header */
+ num_trip = 1;
+ triplet[0].tag = OBX_DIGEST_RSP_TAG;
+ triplet[0].len = OBX_DIGEST_SIZE;
+ triplet[0].p_array = temp_digest;
+ if(option_userid)
+ {
+ /* add user id */
+ num_trip++;
+ triplet[1].tag = OBX_USERID_RSP_TAG;
+ triplet[1].len = userid_len;
+ triplet[1].p_array = p_userid;
+ }
+ OBX_AddTriplet(p_pkt, OBX_HI_AUTH_RSP, triplet, num_trip);
+
+ /* if we want to authenticate the server, add the challenge header here */
+ /* Note: we only do it for the CONNECT request */
+ if(authenticate && p_saved_req->event == OBX_CONNECT_REQ_EVT)
+ {
+ /* Indicate in the control block to verify the response */
+ p_cb->wait_auth = TRUE;
+
+ /* add the challenge nonce */
+ num_trip = 1;
+ triplet[0].tag = OBX_NONCE_CHLNG_TAG;
+ triplet[0].len = OBX_NONCE_SIZE;
+ triplet[0].p_array = nonce;
+ sprintf ((char *)nonce, "%016lu", GKI_get_tick_count());
+ OBX_AddTriplet(p_pkt, OBX_HI_CHALLENGE, triplet, num_trip);
+ OBX_MD5 ((UINT8 *)(p_cb->p_auth), nonce, p_password, password_len);
+ }
+
+ /* copy non-(target, conn_id, authentication) headers from p_saved_req. */
+ status = obx_copy_and_rm_auth_hdrs(p_saved_req, p_pkt, hi);
+ OBX_TRACE_DEBUG4( "status:%d, save:%d, pkt:%d, off:%d",
+ status, p_saved_req->event, p_pkt->event, p_pkt->offset);
+
+ if(status == OBX_SUCCESS)
+ {
+ /* get the final from the saved request */
+ rsp_code = OBX_RSP_DEFAULT;
+ obx_access_rsp_code(p_saved_req, &rsp_code);
+ final = (rsp_code & OBX_FINAL) ? TRUE : FALSE;
+ OBX_TRACE_DEBUG1( "saved final:%d", final);
+
+ /* call the associated API function to send the request again */
+ switch(p_pkt->event)
+ {
+ case OBX_CONNECT_REQ_EVT:
+ status = OBX_ConnectReq((BD_ADDR_PTR)BT_BD_ANY, 0, 0, NULL, &p_cb->ll_cb.comm.handle, p_pkt);
+ break;
+ case OBX_PUT_REQ_EVT:
+ status = OBX_PutReq(handle, final, p_pkt);
+ break;
+ case OBX_GET_REQ_EVT:
+ status = OBX_GetReq(handle, final, p_pkt);
+ break;
+ case OBX_SETPATH_REQ_EVT:
+ /* get the flags from old request - if SetPath */
+ flags = *((UINT8 *)(p_saved_req + 1) + p_saved_req->offset + 3);
+ status = OBX_SetPathReq(handle, flags, p_pkt);
+ break;
+ default:
+ /* it does not make sense to authenticate on Abort and Disconnect */
+ OBX_TRACE_WARNING1( "Authenticate on bad request: %d", p_pkt->event);
+ status = OBX_NO_RESOURCES;
+ } /* switch (event) */
+ }
+ } /* digest done */
+ } /* challenge heaer exists */
+
+ if(status != OBX_SUCCESS)
+ {
+ GKI_freebuf(p_pkt);
+ }
+
+ if(p_cb->wait_auth == FALSE)
+ {
+ GKI_freebuf(p_cb->p_auth);
+ p_cb->p_auth = NULL;
+ }
+ return status;
+}
+
+#if (OBX_MD5_TEST_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function OBX_VerifyResponse
+**
+** Description This function is called by the client to verify the challenge
+** response.
+**
+** Returns TRUE, if successful.
+** FALSE, if authentication failed
+**
+*******************************************************************************/
+BOOLEAN OBX_VerifyResponse(UINT32 nonce_u32, UINT8 *p_password, UINT8 password_len, UINT8 *p_response)
+{
+ BOOLEAN status = FALSE;
+ UINT8 nonce[OBX_NONCE_SIZE + 1];
+ UINT8 temp_digest[OBX_DIGEST_SIZE];
+
+ OBX_TRACE_API0( "OBX_VerifyResponse");
+ if (p_password && password_len)
+ {
+ sprintf((char *)nonce, "%016lu", nonce_u32);
+ OBX_MD5 (temp_digest, nonce, p_password, password_len);
+ if (memcmp (temp_digest, p_response, OBX_DIGEST_SIZE) == 0)
+ status = TRUE;
+ }
+ return status;
+}
+#endif /* OBX_MD5_TEST_INCLUDED */
+
+
+#endif
+
+
+
diff --git a/stack/obx/obx_rfc.c b/stack/obx/obx_rfc.c
new file mode 100644
index 0000000..b02fbef
--- /dev/null
+++ b/stack/obx/obx_rfc.c
@@ -0,0 +1,613 @@
+/*****************************************************************************
+**
+** Name: obx_rfc.c
+**
+** File: OBEX interface to the RFCOMM module
+**
+** Copyright (c) 2003-2008, Broadcom Corp., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include <string.h>
+#include "wcassert.h"
+
+#include "bt_target.h"
+#include "obx_int.h"
+
+#include "port_api.h"
+#include "sdpdefs.h"
+#include "btu.h"
+
+/*******************************************************************************
+** Function obx_rfc_snd_evt
+** Description Sends an rfcomm event to OBX through the BTU task.
+*******************************************************************************/
+static void obx_rfc_snd_evt (tOBX_PORT_CB *p_pcb, UINT32 code)
+{
+ BT_HDR *p_msg;
+ tOBX_PORT_EVT *p_evt;
+ UINT16 event;
+
+ if (!p_pcb)
+ return;
+
+ p_msg = (BT_HDR*)GKI_getbuf(BT_HDR_SIZE + sizeof(tOBX_PORT_EVT));
+ WC_ASSERT(p_msg);
+
+ if (p_pcb->handle & OBX_CL_HANDLE_MASK)
+ event = BT_EVT_TO_OBX_CL_MSG;
+ else
+ event = BT_EVT_TO_OBX_SR_MSG;
+
+ p_msg->event = event;
+ p_msg->len = sizeof(tOBX_PORT_EVT);
+ p_msg->offset = 0;
+ p_evt = (tOBX_PORT_EVT *)(p_msg + 1);
+ p_evt->code = code;
+ p_evt->p_pcb = p_pcb;
+
+ GKI_send_msg(BTU_TASK, BTU_HCI_RCV_MBOX, p_msg);
+}
+
+/*******************************************************************************
+** Function obx_rfc_cback
+** Description find the port control block and post an event to BTU task.
+** NOTE: This callback does not handle connect up/down events.
+** obx_rfc_mgmt_cback is used for these events.
+*******************************************************************************/
+static void obx_rfc_cback (UINT32 code, UINT16 port_handle)
+{
+ tOBX_PORT_CB *p_pcb = obx_port_handle_2cb(port_handle);
+
+ if (p_pcb)
+ {
+ obx_rfc_snd_evt (p_pcb, code);
+ }
+ else
+ {
+ OBX_TRACE_WARNING0("Can not find control block");
+ }
+}
+
+/*******************************************************************************
+** Function obx_rfc_mgmt_cback
+** Callback registered with the PORT entity's Management Callback so that OBX
+** can be notified when the connection has come up or gone down.
+********************************************************************************/
+void obx_rfc_mgmt_cback(UINT32 port_status, UINT16 port_handle)
+{
+ tOBX_PORT_CB *p_pcb = obx_port_handle_2cb(port_handle);
+ UINT32 code;
+
+#if (OBX_CLIENT_INCLUDED == TRUE)
+ if (!p_pcb && port_status != PORT_SUCCESS)
+ {
+ /* See if error called within RFCOMM_CreateConnection */
+ if (obx_cb.p_temp_pcb)
+ {
+ p_pcb = obx_cb.p_temp_pcb;
+ obx_cb.p_temp_pcb = NULL;
+ }
+ }
+#endif
+
+ if (p_pcb)
+ {
+ code = (port_status == PORT_SUCCESS) ? PORT_EV_CONNECTED : PORT_EV_CONNECT_ERR;
+ obx_rfc_snd_evt (p_pcb, code);
+ }
+ else
+ {
+ OBX_TRACE_WARNING0("mgmt cback: Can not find control block");
+ }
+}
+
+
+/*******************************************************************************
+** Function obx_read_data
+** Description This functions reads data from FRCOMM. Return a message if the
+** whole packet is read.
+** The following defines how BT_HDR is used in this function
+** event: response or request event code
+** len: the length read so far.
+** offset: offset to the beginning of the actual data.
+** layer_specific: left
+*******************************************************************************/
+static BT_HDR * obx_read_data (tOBX_PORT_CB *p_pcb, tOBX_VERIFY_OPCODE p_verify_opcode)
+{
+ BT_HDR *p_ret = NULL;
+ UINT8 *p;
+ UINT16 ask_len;
+ UINT16 got_len;
+ int rc;
+ tOBX_RX_HDR *p_rxh;
+ tOBX_SR_SESS_CB *p_scb;
+ UINT8 opcode;
+ UINT16 pkt_len;
+ BOOLEAN failed = FALSE;
+
+ OBX_TRACE_DEBUG1("obx_read_data port_handle:%d", p_pcb->port_handle );
+ for (;;)
+ {
+ if (p_pcb->p_rxmsg == NULL)
+ {
+ p_pcb->p_rxmsg = OBX_HdrInit((tOBX_HANDLE)(p_pcb->handle|OBX_HANDLE_RX_MTU_MASK),
+ OBX_LRG_DATA_POOL_SIZE);
+ memset((p_pcb->p_rxmsg + 1), 0, sizeof(tOBX_RX_HDR));
+ }
+ /* we use this header to keep the status of this packet (instead of in control block) */
+ p_rxh = (tOBX_RX_HDR *)(p_pcb->p_rxmsg + 1);
+
+ ask_len = 0;
+ if (p_rxh->code == 0)
+ {
+ if (p_pcb->p_rxmsg->len == 0) /* we need this if statement in case of "throw away" */
+ ask_len = 1;
+ }
+ else if (p_pcb->p_rxmsg->len < (OBX_PKT_LEN_SIZE + 1) )
+ {
+ /* if we do not know the packet len yet, read from port */
+ ask_len = OBX_PKT_LEN_SIZE + 1 - p_pcb->p_rxmsg->len;
+ }
+ else
+ {
+ /* we already know the packet len.
+ * determine how many more bytes we need for this packet */
+ ask_len = p_rxh->pkt_len - p_pcb->p_rxmsg->len;
+ }
+
+ /* the position of next byte to read */
+ p = (UINT8 *)(p_pcb->p_rxmsg + 1) + p_pcb->p_rxmsg->offset + p_pcb->p_rxmsg->len;
+
+ if (ask_len)
+ {
+ rc = PORT_ReadData( p_pcb->port_handle, (char*)p, ask_len, &got_len);
+ if (rc != PORT_SUCCESS)
+ {
+ OBX_TRACE_WARNING2("Error %d returned from PORT_Read_Data, len:%d", rc, got_len);
+ }
+
+ OBX_TRACE_DEBUG2("ask_len: %d, got_len:%d", ask_len, got_len );
+ if (got_len == 0)
+ {
+ /* If we tried to read but did not get anything, */
+ /* there is nothing more to read at this time */
+ break;
+ }
+ p_pcb->p_rxmsg->len += got_len;
+ p_pcb->p_rxmsg->layer_specific -= got_len;
+ }
+
+ /* process the response/opcode, if not yet */
+ if (p_rxh->code == 0 && p_pcb->p_rxmsg->len)
+ {
+ opcode = *((UINT8 *)(p_pcb->p_rxmsg + 1) + p_pcb->p_rxmsg->offset);
+ if ( (p_verify_opcode)(opcode, p_rxh) == OBX_BAD_SM_EVT)
+ {
+ OBX_TRACE_WARNING1("bad opcode:0x%x - Disconnecting", opcode );
+ /* received data with bad length. */
+
+ /*bad length disconnect */
+ failed = TRUE;
+ break;
+ }
+ continue;
+ }
+
+ /* process the packet len */
+ if (p_rxh->pkt_len == 0 && p_pcb->p_rxmsg->len >= (OBX_PKT_LEN_SIZE + 1) )
+ {
+ p = (UINT8 *)(p_pcb->p_rxmsg + 1) + p_pcb->p_rxmsg->offset + 1;
+ BE_STREAM_TO_UINT16(pkt_len, p);
+
+ if ( (pkt_len > p_pcb->rx_mtu) ||
+ (pkt_len < 3) ||
+ (pkt_len == 4) )
+ {
+ /* received data with bad length. */
+ OBX_TRACE_WARNING2("Received bad packet len -Disconnecting: %d RX MTU: %x",
+ pkt_len, p_pcb->rx_mtu);
+ /*bad length disconnect */
+ failed = TRUE;
+ break;
+ }
+ else
+ {
+ /* keep the packet len in the header */
+ p_rxh->pkt_len = pkt_len;
+ }
+ continue;
+ }
+
+ if (p_pcb->p_rxmsg->len == p_rxh->pkt_len)
+ {
+ /* received a whole packet */
+ OBX_TRACE_DEBUG1("got a packet. opcode:0x%x", p_rxh->code );
+ p_ret = p_pcb->p_rxmsg;
+ p_pcb->p_rxmsg = NULL;
+ break;
+ }
+
+ }
+
+ if (failed)
+ {
+ if (p_pcb->handle & OBX_CL_HANDLE_MASK)
+ {
+ obx_close_port(p_pcb->port_handle);
+ }
+ else
+ {
+ if ((p_scb = obx_sr_get_scb(p_pcb->handle)) != NULL)
+ obx_ssm_event(p_scb, OBX_PORT_CLOSE_SEVT, NULL);
+
+ }
+ p_ret = NULL;
+ }
+
+ return p_ret;
+}
+
+
+#if (OBX_CLIENT_INCLUDED == TRUE)
+/*******************************************************************************
+** Function obx_cl_proc_evt
+** Description This is called to process BT_EVT_TO_OBX_CL_MSG
+** Process events from RFCOMM. Get the associated client control
+** block. If this is a response packet, stop timer. Call
+** obx_csm_event() with event OK_CFM, FAIL_CFM or CONT_CFM.
+*******************************************************************************/
+void obx_cl_proc_evt(tOBX_PORT_EVT *p_evt)
+{
+ tOBX_PORT_CB *p_pcb = p_evt->p_pcb;
+ tOBX_CL_CB *p_cb = obx_cl_get_cb(p_pcb->handle);
+ BT_HDR *p_pkt;
+
+ if (p_cb == NULL)
+ {
+ /* probably already close the port and deregistered from OBX */
+ OBX_TRACE_ERROR1("Could not find control block for handle: 0x%x", p_pcb->handle);
+ return;
+ }
+
+ if (p_evt->code & PORT_EV_CONNECT_ERR)
+ {
+ obx_csm_event(p_cb, OBX_PORT_CLOSE_CEVT, NULL);
+ return;
+ } /* PORT_EV_CONNECT_ERR */
+
+ if (p_evt->code & PORT_EV_TXEMPTY)
+ {
+ obx_csm_event(p_cb, OBX_TX_EMPTY_CEVT, NULL);
+ } /* PORT_EV_TXEMPTY */
+
+ if (p_evt->code & PORT_EV_RXCHAR)
+ {
+ while( (p_pkt = obx_read_data(p_pcb, obx_verify_response)) != NULL )
+ {
+ if (GKI_queue_is_empty(&p_pcb->rx_q))
+ {
+ if (p_pkt->event != OBX_BAD_SM_EVT)
+ {
+ obx_cl_proc_pkt (p_cb, p_pkt);
+ }
+ else
+ {
+ OBX_TRACE_ERROR0("bad SM event" );
+ }
+ }
+ else if (p_pkt->event != OBX_BAD_SM_EVT)
+ {
+ GKI_enqueue (&p_pcb->rx_q, p_pkt);
+ if (p_pcb->rx_q.count > obx_cb.max_rx_qcount)
+ {
+ p_pcb->stopped = TRUE;
+ PORT_FlowControl(p_pcb->port_handle, FALSE);
+ }
+ }
+ } /* while received a packet */
+ } /* PORT_EV_RXCHAR */
+
+ if (p_evt->code & PORT_EV_FC)
+ {
+ if (p_evt->code & PORT_EV_FCS)
+ {
+ OBX_TRACE_EVENT0("cl flow control event - FCS SET ----" );
+ obx_csm_event(p_cb, OBX_FCS_SET_CEVT, NULL);
+ }
+ } /* PORT_EV_FC */
+}
+#endif
+
+#if (OBX_SERVER_INCLUDED == TRUE)
+/*******************************************************************************
+** Function obx_build_dummy_rsp
+** Description make up a dummy response if the app does not call response API
+** yet and AbortRsp is called
+*******************************************************************************/
+BT_HDR * obx_build_dummy_rsp(tOBX_SR_SESS_CB *p_scb, UINT8 rsp_code)
+{
+ BT_HDR *p_pkt;
+ UINT8 *p;
+ UINT16 size = 3;
+
+ p_pkt = OBX_HdrInit(p_scb->ll_cb.comm.handle, OBX_CMD_POOL_SIZE);
+ p = (UINT8 *)(p_pkt+1)+p_pkt->offset+p_pkt->len;
+ *p++ = (rsp_code|OBX_FINAL);
+ if (p_scb->conn_id)
+ {
+ size += 5;
+ UINT16_TO_BE_STREAM(p, size);
+ *p++ = OBX_HI_CONN_ID;
+ UINT32_TO_BE_STREAM(p, p_scb->conn_id);
+ }
+ else
+ {
+ UINT16_TO_BE_STREAM(p, size);
+ }
+ p_pkt->len = size;
+ p_pkt->event = OBX_PUT_RSP_EVT; /* or OBX_GET_RSP_EVT: for tracing purposes */
+ return p_pkt;
+}
+
+/*******************************************************************************
+** Function obx_add_port
+** Description check if this server has aother un-used port to open
+**
+**
+** Returns void
+*******************************************************************************/
+void obx_add_port(tOBX_HANDLE obx_handle)
+{
+ tOBX_SR_CB * p_cb = obx_sr_get_cb(obx_handle);
+ tOBX_SR_SESS_CB *p_scb, *p_scb0;
+ int xx;
+ tOBX_STATUS status = OBX_NO_RESOURCES;
+ BOOLEAN found;
+
+ OBX_TRACE_DEBUG1("obx_add_port handle:0x%x", obx_handle );
+ if (p_cb && p_cb->scn)
+ {
+ OBX_TRACE_DEBUG2("num_sess:%d scn:%d", p_cb->num_sess, p_cb->scn );
+ p_scb0 = &obx_cb.sr_sess[p_cb->sess[0]-1];
+ found = FALSE;
+ /* find an RFCOMM port that is not connected yet */
+ for (xx=0; xx < p_cb->num_sess && p_cb->sess[xx]; xx++)
+ {
+ p_scb = &obx_cb.sr_sess[p_cb->sess[xx]-1];
+ OBX_TRACE_DEBUG3("[%d] id:0x%x, state:%d", xx, p_scb->ll_cb.comm.id, p_scb->state );
+
+ if (p_scb->ll_cb.comm.p_send_fn == (tOBX_SEND_FN *)obx_rfc_snd_msg
+ && p_scb->state == OBX_SS_NOT_CONNECTED)
+ {
+ found = TRUE;
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ for (xx=0; xx < p_cb->num_sess && p_cb->sess[xx]; xx++)
+ {
+ p_scb = &obx_cb.sr_sess[p_cb->sess[xx]-1];
+ OBX_TRACE_DEBUG2("[%d] port_handle:%d", xx, p_scb->ll_cb.port.port_handle );
+ if (!p_scb->ll_cb.comm.id)
+ {
+ status = obx_open_port(&p_scb->ll_cb.port, BT_BD_ANY, p_cb->scn);
+ if (status == OBX_SUCCESS)
+ {
+ p_scb->ll_cb.port.rx_mtu= p_scb0->ll_cb.port.rx_mtu;
+ p_scb->state = OBX_SS_NOT_CONNECTED;
+ }
+ break;
+ }
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+** Function obx_sr_proc_evt
+** Description This is called to process BT_EVT_TO_OBX_SR_MSG
+** Process events from RFCOMM. Get the associated server control
+** block. If this is a request packet, stop timer. Find the
+** associated API event and save it in server control block
+** (api_evt). Fill the event parameter (param).
+** Call obx_ssm_event() with the associated events.If the associated
+** control block is not found (maybe the target header does not
+** match) or busy, compose a service unavailable response and call
+** obx_rfc_snd_msg().
+*******************************************************************************/
+void obx_sr_proc_evt(tOBX_PORT_EVT *p_evt)
+{
+ tOBX_SR_SESS_CB *p_scb;
+ BT_HDR *p_pkt;
+ tOBX_RX_HDR *p_rxh;
+ tOBX_PORT_CB *p_pcb = p_evt->p_pcb;
+
+
+ OBX_TRACE_DEBUG2("obx_sr_proc_evt handle: 0x%x, port_handle:%d", p_evt->p_pcb->handle, p_evt->p_pcb->port_handle);
+ if (p_pcb->handle == 0 || p_pcb->p_send_fn != (tOBX_SEND_FN*)obx_rfc_snd_msg)
+ return;
+
+ if ((p_scb = obx_sr_get_scb(p_pcb->handle)) == NULL)
+ {
+ /* probably already close the port and deregistered from OBX */
+ OBX_TRACE_ERROR1("Could not find control block for handle: 0x%x", p_pcb->handle);
+ return;
+ }
+
+ if (p_evt->code & PORT_EV_CONNECTED)
+ {
+ p_scb->ll_cb.port.tx_mtu = OBX_MIN_MTU;
+ obx_start_timer(&p_scb->ll_cb.comm);
+ /* Get the Bd_Addr */
+ PORT_CheckConnection (p_scb->ll_cb.port.port_handle,
+ p_scb->param.conn.peer_addr,
+ NULL);
+ memcpy(p_scb->peer_addr, p_scb->param.conn.peer_addr, BD_ADDR_LEN);
+ }
+
+ if (p_evt->code & PORT_EV_CONNECT_ERR)
+ {
+ obx_ssm_event(p_scb, OBX_PORT_CLOSE_SEVT, NULL);
+ return;
+ } /* PORT_EV_CONNECT_ERR */
+
+ if (p_evt->code & PORT_EV_RXCHAR)
+ {
+ while( (p_pkt = obx_read_data(p_pcb, obx_verify_request)) != NULL)
+ {
+ p_rxh = (tOBX_RX_HDR *)(p_pkt + 1);
+ p_pkt->event = obx_sm_evt_to_api_evt[p_rxh->sm_evt];
+ if (GKI_queue_is_empty(&p_pcb->rx_q))
+ {
+ if (p_pkt->event != OBX_BAD_SM_EVT)
+ {
+ obx_sr_proc_pkt (p_scb, p_pkt);
+ }
+ else
+ {
+ OBX_TRACE_ERROR0("bad SM event" );
+ }
+ }
+ else
+ {
+ GKI_enqueue (&p_pcb->rx_q, p_pkt);
+ if (p_pcb->rx_q.count > obx_cb.max_rx_qcount)
+ {
+ p_pcb->stopped = TRUE;
+ PORT_FlowControl(p_pcb->port_handle, FALSE);
+ }
+ }
+ } /* while a packet */
+ } /* PORT_EV_RXCHAR */
+
+ /* The server does not need to handle this event
+ */
+ if (p_evt->code & PORT_EV_TXEMPTY)
+ {
+ obx_ssm_event(p_scb, OBX_TX_EMPTY_SEVT, NULL);
+ }
+
+ if (p_evt->code & PORT_EV_FC)
+ {
+ if (p_evt->code & PORT_EV_FCS)
+ {
+ OBX_TRACE_EVENT0("sr flow control event - FCS SET ----" );
+ obx_ssm_event(p_scb, OBX_FCS_SET_SEVT, NULL);
+ }
+ } /* PORT_EV_FC */
+}
+#endif /* OBX_SERVER_INCLUDED */
+
+/*******************************************************************************
+** Function obx_open_port
+** Description Call RFCOMM_CreateConnection() to get port_handle.
+** Call PORT_SetEventCallback() with given callback.
+** Call PORT_SetEventMask() with given event mask. Return port handle.
+** Returns port handle
+*******************************************************************************/
+tOBX_STATUS obx_open_port(tOBX_PORT_CB *p_pcb, const BD_ADDR bd_addr, UINT8 scn)
+{
+ tOBX_STATUS status = OBX_SUCCESS; /* successful */
+ UINT16 port_rc;
+ BOOLEAN is_server = (p_pcb->handle & OBX_CL_HANDLE_MASK)?FALSE:TRUE;
+ UINT16 max_mtu = OBX_MAX_MTU;
+
+ OBX_TRACE_DEBUG2("obx_open_port rxmtu:%d, cbmtu:%d", p_pcb->rx_mtu, max_mtu );
+
+ /* clear buffers from previous connection */
+ obx_free_buf ((tOBX_LL_CB*)p_pcb);
+
+ /* make sure the MTU is in registered range */
+ if (p_pcb->rx_mtu > max_mtu)
+ p_pcb->rx_mtu = max_mtu;
+ if (p_pcb->rx_mtu < OBX_MIN_MTU)
+ p_pcb->rx_mtu = OBX_MIN_MTU;
+
+#if (OBX_CLIENT_INCLUDED == TRUE)
+ /* There's a remote chance that an error can occur in L2CAP before the handle
+ * before the handle can be assigned (server side only). We will save the
+ * client control block while the handle is not known */
+ if (!is_server)
+ {
+ obx_cb.p_temp_pcb = p_pcb;
+ }
+#endif
+
+ port_rc = RFCOMM_CreateConnection ( UUID_PROTOCOL_OBEX, scn,
+ is_server, (UINT16)(p_pcb->rx_mtu+1), (BD_ADDR_PTR)bd_addr,
+ &p_pcb->port_handle, obx_rfc_mgmt_cback);
+
+ OBX_TRACE_DEBUG3("obx_open_port rxmtu:%d, port_handle:%d, port.handle:0x%x",
+ p_pcb->rx_mtu, p_pcb->port_handle, p_pcb->handle );
+
+#if (OBX_CLIENT_INCLUDED == TRUE)
+ if (!is_server)
+ {
+ obx_cb.p_temp_pcb = NULL;
+ }
+#endif
+
+ if (port_rc == PORT_SUCCESS)
+ {
+ obx_cb.hdl_map[p_pcb->port_handle - 1] = p_pcb->handle;
+ PORT_SetEventCallback (p_pcb->port_handle, obx_rfc_cback);
+ PORT_SetEventMask (p_pcb->port_handle, OBX_PORT_EVENT_MASK);
+ p_pcb->p_send_fn = (tOBX_SEND_FN *)obx_rfc_snd_msg;
+ p_pcb->p_close_fn = obx_close_port;
+ }
+ else
+ {
+ status = OBX_NO_RESOURCES;
+ }
+
+ return status;
+}
+
+
+/*******************************************************************************
+** Function obx_close_port
+** Description Clear the port event mask and callback. Close the port.
+** Returns void
+*******************************************************************************/
+void obx_close_port(UINT16 port_handle)
+{
+ RFCOMM_RemoveConnection(port_handle);
+}
+
+/*******************************************************************************
+** Function obx_rfc_snd_msg
+** Description Call PORT_WriteData() to send an OBEX message to peer. If
+** all data is sent, free the GKI buffer that holds
+** the OBEX message. If only portion of data is
+** sent, adjust the BT_HDR for PART state.
+** Returns TRUE if all data is sent
+*******************************************************************************/
+BOOLEAN obx_rfc_snd_msg(tOBX_PORT_CB *p_pcb)
+{
+ BOOLEAN status = FALSE;
+ UINT16 bytes_written = 0;
+
+ obx_stop_timer(&p_pcb->tle);
+ PORT_WriteData(p_pcb->port_handle, ((char*)(p_pcb->p_txmsg + 1)) + p_pcb->p_txmsg->offset,
+ p_pcb->p_txmsg->len, &bytes_written);
+
+ obx_start_timer ((tOBX_COMM_CB *)p_pcb);
+
+ if (bytes_written == p_pcb->p_txmsg->len)
+ {
+ GKI_freebuf(p_pcb->p_txmsg);
+ p_pcb->p_txmsg = NULL;
+ status = TRUE;
+ }
+ else
+ {
+ /* packet not completely written to RFCOMM */
+ p_pcb->p_txmsg->offset += bytes_written;
+ p_pcb->p_txmsg->len -= bytes_written;
+ }
+
+ return status;
+}
diff --git a/stack/obx/obx_sact.c b/stack/obx/obx_sact.c
new file mode 100644
index 0000000..1602752
--- /dev/null
+++ b/stack/obx/obx_sact.c
@@ -0,0 +1,1519 @@
+/*****************************************************************************
+**
+** Name: obx_sact.c
+**
+** File: OBEX Server State Machine Action Functions
+**
+** Copyright (c) 2003-2012, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include <string.h>
+#include <bt_target.h>
+
+#include "btu.h"
+#include "obx_int.h"
+#include "btm_api.h"
+
+/*******************************************************************************
+** Function obx_sa_snd_rsp
+** Description Call p_send_fn() to send the OBEX message to the peer.
+** Start timer. Return NULL state.If data is partially sent, set
+** next_state in port control block. Return PART state.
+*******************************************************************************/
+tOBX_SR_STATE obx_sa_snd_rsp(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt)
+{
+ tOBX_SR_STATE state = p_scb->state;
+ UINT8 rsp_code = OBX_RSP_DEFAULT;
+ tOBX_SR_CB *p_cb;
+ BOOLEAN not_cong = TRUE;
+
+ obx_access_rsp_code(p_pkt, &rsp_code);
+ p_scb->cur_op = OBX_REQ_ABORT;
+
+
+ p_scb->ll_cb.comm.p_txmsg = p_pkt;
+ rsp_code &= ~OBX_FINAL;
+ /* Get and Put operation may need to adjust the state*/
+ if (rsp_code != OBX_RSP_CONTINUE )
+ {
+ if (p_scb->state == OBX_SS_GET_TRANSACTION ||
+ p_scb->state == OBX_SS_PUT_SRM ||
+ p_scb->state == OBX_SS_GET_SRM ||
+ p_scb->state == OBX_SS_PUT_TRANSACTION)
+ {
+ state = OBX_SS_CONNECTED;
+ /* the SRM bits can not be cleared here, if aborting */
+ if ((p_scb->srm &OBX_SRM_ABORT) == 0)
+ p_scb->srm &= OBX_SRM_ENABLE;
+ }
+ }
+
+ OBX_TRACE_DEBUG2("obx_sa_snd_rsp sess_st:%d, event:%d", p_scb->sess_st, p_pkt->event);
+ if ((p_scb->sess_st == OBX_SESS_ACTIVE) && (p_pkt->event != (OBX_SESSION_CFM_SEVT + 1)))
+ {
+ p_scb->ssn++;
+ }
+
+ if (p_scb->ll_cb.comm.p_send_fn(&p_scb->ll_cb) == FALSE)
+ {
+ p_scb->next_state = state;
+ state = OBX_SS_PARTIAL_SENT;
+ }
+ else if (p_scb->state == OBX_SS_GET_SRM)
+ {
+ if (((p_scb->srmp & OBX_SRMP_WAIT) == 0) && (rsp_code == OBX_RSP_CONTINUE))
+ {
+ if (p_scb->ll_cb.comm.p_send_fn == (tOBX_SEND_FN *)obx_l2c_snd_msg)
+ {
+ OBX_TRACE_DEBUG1("obx_sa_snd_rsp cong:%d", p_scb->ll_cb.l2c.cong);
+ if (p_scb->ll_cb.l2c.cong)
+ {
+ not_cong = FALSE;
+ }
+ }
+
+ /* do not need to wait
+ - fake a get request event, so the profile would issue another GET response */
+ if (not_cong)
+ {
+ p_cb = obx_sr_get_cb(p_scb->handle);
+ (p_cb->p_cback) (p_scb->ll_cb.comm.handle, OBX_GET_REQ_EVT, p_scb->param, NULL);
+ }
+ }
+ p_scb->srmp &= ~OBX_SRMP_WAIT;
+ }
+ else if (p_scb->sess_st == OBX_SESS_SUSPENDING)
+ {
+ p_scb->ssn++;
+ p_scb->param.sess.ssn = p_scb->ssn;
+ p_scb->param.sess.nssn = p_scb->ssn;
+ p_scb->sess_st = OBX_SESS_SUSPEND;
+ p_scb->sess_info[OBX_SESSION_INFO_ST_IDX] = p_scb->state;
+ state = OBX_SS_SESS_INDICATED;
+ p_scb->api_evt = OBX_SESSION_REQ_EVT;
+ }
+
+ return state;
+}
+
+/*******************************************************************************
+** Function obx_sa_snd_part
+** Description Call p_send_fn() to send the left-over OBEX message to the
+** peer. Start timer. If all the data is sent, call obx_ssm_event()
+** with STATE event to next_state in the port control block.
+** If (p_saved), call obx_ssm_event() to process the saved request.
+*******************************************************************************/
+tOBX_SR_STATE obx_sa_snd_part(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt)
+{
+ tOBX_SR_STATE state = OBX_SS_NULL;
+ UINT8 rsp_code = OBX_RSP_DEFAULT;
+ tOBX_SR_CB *p_cb;
+
+ obx_access_rsp_code(p_scb->ll_cb.comm.p_txmsg , &rsp_code);
+ if (p_scb->ll_cb.comm.p_send_fn(&p_scb->ll_cb) == TRUE)
+ {
+ obx_ssm_event(p_scb, OBX_STATE_SEVT, NULL);
+ if (p_scb->p_next_req)
+ {
+ p_pkt = p_scb->p_next_req;
+ obx_access_rsp_code(p_pkt , &rsp_code);
+ p_scb->p_next_req = NULL;
+ p_scb->api_evt = (tOBX_EVENT)p_pkt->event;
+ obx_ssm_event(p_scb, (tOBX_SR_EVENT)(p_pkt->event-1), p_pkt);
+ }
+
+ OBX_TRACE_DEBUG3("obx_sa_snd_part state:%d, srm:0x%x, rsp_code:0x%x", p_scb->state, p_scb->srm, rsp_code);
+ if (p_scb->state == OBX_SS_GET_SRM)
+ {
+ rsp_code &= ~OBX_FINAL;
+ if (((p_scb->srm & OBX_SRM_WAIT) == 0) && (rsp_code == OBX_RSP_CONTINUE))
+ {
+ /* do not need to wait
+ - fake a get request event, so the profile would issue another GET response */
+ p_cb = obx_sr_get_cb(p_scb->handle);
+ (p_cb->p_cback) (p_scb->ll_cb.comm.handle, OBX_GET_REQ_EVT, p_scb->param, NULL);
+ }
+ }
+ }
+ return state;
+}
+
+/*******************************************************************************
+** Function obx_sa_abort_rsp
+** Description Send an abort response.
+** If Put/Get response has not been sent yet,
+** send it before the abort response.
+*******************************************************************************/
+tOBX_SR_STATE obx_sa_abort_rsp(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt)
+{
+ tOBX_SR_STATE state = OBX_SS_NULL;
+ BT_HDR *p_dummy;
+ UINT8 rsp_code = OBX_RSP_CONTINUE;
+
+ if (p_scb->cur_op != OBX_REQ_ABORT && ((p_scb->srm & OBX_SRM_ENGAGE) == 0))
+ {
+ /* if we have not respond to an op yet, send a dummy response */
+ if (p_scb->cur_op == (rsp_code|OBX_REQ_PUT) )
+ rsp_code = OBX_RSP_INTRNL_SRVR_ERR;
+ p_dummy = obx_build_dummy_rsp(p_scb, rsp_code);
+ obx_sa_snd_rsp(p_scb, p_dummy);
+ }
+
+ /* clear the SRM bits; leave only the enabled bit */
+ p_scb->srm &= OBX_SRM_ENABLE;
+ state = obx_sa_snd_rsp(p_scb, p_pkt);
+ return state;
+}
+
+/*******************************************************************************
+** Function obx_sa_op_rsp
+** Description Send response for Put/Get when Abort request is already received
+*******************************************************************************/
+tOBX_SR_STATE obx_sa_op_rsp(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt)
+{
+ tOBX_SR_STATE state = OBX_SS_NULL;
+ if (p_scb->cur_op != OBX_REQ_ABORT)
+ state = obx_sa_snd_rsp(p_scb, p_pkt);
+#if (BT_USE_TRACES == TRUE)
+ else
+ OBX_TRACE_WARNING0("OBX is not waiting for a rsp API!!");
+#endif
+ return state;
+}
+
+/*******************************************************************************
+** Function obx_verify_target
+** Description Verify that target header or connection ID is correct.
+** Make sure that they do not both exist
+*******************************************************************************/
+static UINT8 obx_verify_target(tOBX_SR_CB *p_cb, tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt)
+{
+ UINT16 len = 0;
+ UINT8 rsp_code = OBX_RSP_SERVICE_UNAVL;
+ UINT32 conn_id = 0;
+ UINT8 *p_target = NULL;
+
+ OBX_Read4ByteHdr(p_pkt, OBX_HI_CONN_ID, &conn_id);
+/* Coverity:
+Event unchecked_value: Return value of "OBX_ReadTargetHdr" is not checked
+Coverity: FALSE-POSITIVE error from Coverity tool. Please do NOT remove following comment. */
+/* coverity[unchecked_value] False-positive: If target headser does not exist,
+ p_target would remain the default value/NULL and len would be set to 0.
+ There's no need to check the return value of OBX_ReadTargetHdr
+*/
+ OBX_ReadTargetHdr(p_pkt, &p_target, &len, 0);
+
+ if (p_cb->target.len)
+ {
+ /* directed connection: make sure the connection ID matches */
+ if ( conn_id && conn_id == p_scb->conn_id )
+ rsp_code = OBX_RSP_OK;
+
+ if (p_cb->target.len == OBX_DEFAULT_TARGET_LEN)
+ {
+ /* the user verify target (cases like BIP that has multiple targets) */
+ rsp_code = OBX_RSP_OK;
+ }
+ else if ( len == p_cb->target.len && p_target &&
+ memcmp(p_cb->target.target, p_target, p_cb->target.len) == 0)
+ {
+ rsp_code = OBX_RSP_OK;
+ }
+ }
+ else
+ {
+ /* no target - request to inbox, like OPP */
+ if (conn_id == 0 && len == 0)
+ {
+ if (p_scb->ll_cb.comm.tx_mtu < OBX_MIN_MTU)
+ rsp_code = OBX_RSP_FORBIDDEN;
+ else
+ rsp_code = OBX_RSP_OK;
+ }
+ }
+
+ /* target header and connection ID are not supposed to exist in the same packet*/
+ if (conn_id != 0 && p_target != NULL)
+ rsp_code = OBX_RSP_BAD_REQUEST;
+
+ OBX_TRACE_DEBUG3("obx_verify_target rsp: %x, id:%x, code:%x",
+ rsp_code, conn_id, ((tOBX_RX_HDR *)(p_pkt + 1))->code);
+ if (rsp_code != OBX_RSP_OK)
+ p_pkt->event = OBX_CONNECT_RSP_EVT;
+ return rsp_code;
+}
+
+/*******************************************************************************
+** Function obx_conn_rsp
+** Description Called by OBX_ConnectRsp() and obx_sa_connect_ind() to compose
+** a connect response packet.
+*******************************************************************************/
+BT_HDR * obx_conn_rsp(tOBX_SR_CB *p_cb, tOBX_SR_SESS_CB *p_scb, UINT8 rsp_code, BT_HDR *p_pkt)
+{
+ UINT8 msg[OBX_HDR_OFFSET + OBX_MAX_CONN_HDR_EXTRA];
+ UINT8 *p = msg;
+
+ /* response packets always have the final bit set */
+ *p++ = (rsp_code | OBX_FINAL);
+ p += OBX_PKT_LEN_SIZE;
+
+ *p++ = OBX_VERSION;
+ *p++ = OBX_CONN_FLAGS;
+ UINT16_TO_BE_STREAM(p, p_scb->ll_cb.comm.rx_mtu);
+
+ /* add session sequence number, if session is active */
+ if (p_scb->sess_st == OBX_SESS_ACTIVE)
+ {
+ *p++ = OBX_HI_SESSION_SN;
+ *p++ = (p_scb->ssn+1);
+ }
+
+ if (p_scb->conn_id && rsp_code == OBX_RSP_OK)
+ {
+ *p++ = OBX_HI_CONN_ID;
+ UINT32_TO_BE_STREAM(p, p_scb->conn_id);
+ }
+
+ p_pkt = obx_sr_prepend_msg(p_pkt, msg, (UINT16)(p - msg) );
+
+ /* If the target is registered to server and the WHO headers not in the packet
+ * add WHO header here */
+ p_pkt->event = OBX_CONNECT_RSP_EVT;
+ if (p_cb->target.len && p_cb->target.len != OBX_DEFAULT_TARGET_LEN &&
+ OBX_CheckHdr(p_pkt, OBX_HI_WHO) == NULL)
+ {
+ OBX_AddByteStrHdr(p_pkt, OBX_HI_WHO, p_cb->target.target, p_cb->target.len);
+ /* adjust the packet len */
+ obx_adjust_packet_len(p_pkt);
+ }
+ return p_pkt;
+}
+
+/*******************************************************************************
+** Function obx_sa_wc_conn_ind
+** Description Connect Req is received when waiting for the port to close
+** Call callback with OBX_CLOSE_IND_EVT to clean up the profiles
+** then call obx_sa_connect_ind to process the connect req.
+*******************************************************************************/
+tOBX_SR_STATE obx_sa_wc_conn_ind(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt)
+{
+ tOBX_EVT_PARAM param;
+ tOBX_SR_CB *p_cb = obx_sr_get_cb(p_scb->handle);
+
+ obx_stop_timer(&p_scb->ll_cb.comm.tle);
+ memset(&param, 0, sizeof(tOBX_EVT_PARAM));
+ if (p_cb && p_cb->p_cback)
+ (*p_cb->p_cback)(p_scb->ll_cb.comm.handle, OBX_CLOSE_IND_EVT, param, NULL);
+ obx_sa_connect_ind(p_scb, p_pkt);
+ return OBX_SS_NULL;
+}
+
+/*******************************************************************************
+** Function obx_sa_connect_ind
+** Description Save peer MTU in the server control block.If the server does not
+** register authentication, call callback with OBX_CONNECT_REQ_EVT
+** and the MTU from the request message. Return NULL state.
+** If authenticate, compose an unauthorized response, and call
+** obx_sa_snd_rsp() to send it to the client. Return WAIT_AUTH state.
+*******************************************************************************/
+tOBX_SR_STATE obx_sa_connect_ind(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt)
+{
+ tOBX_SR_STATE state = OBX_SS_NULL;
+ UINT8 rsp_code = OBX_RSP_SERVICE_UNAVL;
+ tOBX_SR_CB *p_cb = obx_sr_get_cb(p_scb->handle);
+ UINT8 *p;
+ tOBX_EVT_PARAM param; /* The event parameter. */
+
+ /* clear the SRM bits; leave only the enabled bit */
+ p_scb->srm &= OBX_SRM_ENABLE;
+
+ OBX_TRACE_DEBUG0("obx_sa_connect_ind");
+ p_scb->api_evt = OBX_NULL_EVT;
+
+ /* verify that the connect request is OK */
+ rsp_code = obx_verify_target(p_cb, p_scb, p_pkt);
+ if (rsp_code == OBX_RSP_OK)
+ {
+ if (p_cb->target.len && p_scb->conn_id == 0)
+ {
+ /* if Connection ID is used for this connection and none assigned yet,
+ * - assign one */
+ p_scb->conn_id = obx_sr_get_next_conn_id();
+ OBX_TRACE_DEBUG1(" **** obx_sr_get_next_conn_id (0x%08x)", p_scb->conn_id);
+ }
+
+ /* tx_mtu is processed in obx_sr_proc_evt() */
+ if (p_cb->p_auth)
+ {
+ /* If client challenge us first, and the server registers for authentication:
+ * remove the authentication headers and challenge it back */
+ /* send unauthorize response */
+ p_pkt = obx_unauthorize_rsp(p_cb, p_scb, p_pkt);
+ state = OBX_SS_WAIT_AUTH;
+ }
+ else
+ {
+ if (OBX_CheckHdr(p_pkt, OBX_HI_CHALLENGE) != NULL)
+ {
+ /* If client challenge us first, and the server does not register for authentication:
+ * report the challenge */
+ p_scb->p_saved_msg = obx_dup_pkt(p_pkt);
+ state = OBX_SS_AUTH_INDICATED;
+ p_scb->api_evt = OBX_PASSWORD_EVT;
+ }
+ else
+ {
+ if (p_scb->sess_st == OBX_SESS_ACTIVE)
+ {
+ p = &p_scb->sess_info[OBX_SESSION_INFO_ID_IDX];
+ UINT32_TO_BE_STREAM(p, p_scb->conn_id);
+ param.sess.p_sess_info = p_scb->sess_info;
+ param.sess.sess_op = OBX_SESS_OP_CREATE;
+ param.sess.sess_st = p_scb->sess_st;
+ param.sess.nssn = p_scb->param.ssn;
+ param.sess.ssn = p_scb->param.ssn;
+ param.sess.obj_offset = 0;
+ p = &p_scb->sess_info[OBX_SESSION_INFO_MTU_IDX];
+ UINT16_TO_BE_STREAM(p, p_scb->param.conn.mtu);
+ memcpy(param.sess.peer_addr, p_scb->peer_addr, BD_ADDR_LEN);
+ (*p_cb->p_cback)(p_scb->ll_cb.comm.handle, OBX_SESSION_REQ_EVT, param, NULL);
+ }
+ (*p_cb->p_cback)(p_scb->ll_cb.comm.handle, OBX_CONNECT_REQ_EVT, p_scb->param, p_pkt);
+ }
+ }
+ }
+ else
+ {
+ /* bad target or connection ID - reject the request */
+ rsp_code |= OBX_FINAL;
+ obx_access_rsp_code(p_pkt, &rsp_code);
+ state = OBX_SS_NOT_CONNECTED;
+ }
+
+ if (state != OBX_SS_NULL && state != OBX_SS_AUTH_INDICATED)
+ {
+ /* each port has its own credit.
+ * It's very unlikely that we can be flow controlled here */
+ obx_sa_snd_rsp(p_scb, p_pkt);
+ }
+
+ return state;
+}
+
+/*******************************************************************************
+** Function obx_sa_auth_ind
+** Description Save peer MTU and the OBEX message in the server control block.
+** Call callback function with OBX_PASSWORD_EVT.
+** Note: This action function is only valid when MD5 is included
+** Leave this as a stub function to avoid altering the state machine
+*******************************************************************************/
+tOBX_SR_STATE obx_sa_auth_ind(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt)
+{
+ tOBX_SR_STATE state = OBX_SS_NULL;
+ UINT8 rsp_code;
+ tOBX_SR_CB *p_cb = obx_sr_get_cb(p_scb->handle);
+
+ p_scb->api_evt = OBX_NULL_EVT;
+ rsp_code = obx_verify_target(p_cb, p_scb, p_pkt);
+
+ if (rsp_code == OBX_RSP_OK)
+ {
+ /* tx_mtu is processed in obx_sr_proc_evt() */
+ if (OBX_CheckHdr(p_pkt, OBX_HI_AUTH_RSP) == NULL)
+ {
+ /* we are expecting authentication response in this state.
+ * if none is received, reject the request */
+ p_pkt = obx_unauthorize_rsp(p_cb, p_scb, p_pkt);
+ state = OBX_SS_NOT_CONNECTED;
+ }
+ else
+ {
+ /* the client sends authentication response.
+ * save a copy in the control block. Verify it when OBX_Password() is issued */
+ p_scb->p_saved_msg = obx_dup_pkt(p_pkt);
+ (*p_cb->p_cback)(p_scb->ll_cb.comm.handle, OBX_PASSWORD_EVT, p_scb->param, p_pkt);
+ }
+ }
+ else
+ {
+ /* bad target or connection ID - reject the request */
+ rsp_code |= OBX_FINAL;
+ obx_access_rsp_code(p_pkt, &rsp_code);
+ state = OBX_SS_NOT_CONNECTED;
+ }
+
+ if (state != OBX_SS_NULL)
+ {
+ /* each port has its own credit.
+ * It's very unlikely that we can be flow controlled here */
+ obx_sa_snd_rsp(p_scb, p_pkt);
+ }
+
+ return state;
+}
+
+/*******************************************************************************
+** Function obx_sa_connect_rsp
+** Description obx_sa_snd_rsp().If(p_saved), free the OBEX message.If OK
+** response, return NULL state.If unauthorized response, return
+** WAIT_AUTH state.If other fail response, return NOT_CONN state.
+*******************************************************************************/
+tOBX_SR_STATE obx_sa_connect_rsp(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt)
+{
+ UINT8 rsp_code = OBX_RSP_DEFAULT;
+ tOBX_SR_STATE state = p_scb->state;
+
+ obx_access_rsp_code(p_pkt, &rsp_code);
+
+ if (p_scb->p_saved_msg)
+ {
+ GKI_freebuf(p_scb->p_saved_msg);
+ p_scb->p_saved_msg = NULL;
+ }
+
+ if ( rsp_code == (OBX_RSP_UNAUTHORIZED | OBX_FINAL) &&
+ OBX_CheckHdr(p_pkt, OBX_HI_CHALLENGE) != NULL)
+ {
+ state = OBX_SS_WAIT_AUTH;
+ }
+ else if (rsp_code != (OBX_RSP_OK | OBX_FINAL) )
+ state = OBX_SS_NOT_CONNECTED;
+
+ /* each port has its own credit.
+ * It's very unlikely that we can be flow controlled here */
+ obx_sa_snd_rsp(p_scb, p_pkt);
+
+ return state;
+}
+
+/*******************************************************************************
+** Function obx_sa_connection_error
+** Description Stop timer. Reopen transport. Call callback function with
+** OBX_CLOSE_IND_EVT.
+*******************************************************************************/
+tOBX_SR_STATE obx_sa_connection_error(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt)
+{
+ tOBX_EVT_PARAM param;
+ tOBX_SR_CB *p_cb = obx_sr_get_cb(p_scb->handle);
+ tOBX_SR_CBACK *p_cback = NULL;
+ tOBX_SR_STATE save_state;
+
+ OBX_TRACE_DEBUG4("obx_sa_connection_error tx_mtu: %d, sess_st:%d state:%d, prev_state:%d",
+ p_scb->ll_cb.comm.tx_mtu, p_scb->sess_st, p_scb->state, p_scb->prev_state);
+
+ if (p_cb)
+ {
+ p_cback = p_cb->p_cback;
+ memset(&param, 0, sizeof(tOBX_EVT_PARAM));
+ }
+
+ /* clear buffers from previous connection */
+ obx_free_buf (&p_scb->ll_cb);
+
+ if (p_scb->sess_st == OBX_SESS_ACTIVE)
+ {
+ /* The transport is interrupted while a reliable session is active:
+ * report a suspend event fot application to save the information in NV */
+ save_state = p_scb->prev_state;
+ p_scb->sess_info[OBX_SESSION_INFO_SRM_IDX] = p_scb->srm;
+ param.sess.p_sess_info = p_scb->sess_info;
+ param.sess.sess_op = OBX_SESS_OP_TRANSPORT;
+ param.sess.sess_st = p_scb->sess_st;
+ param.sess.nssn = p_scb->ssn;
+ param.sess.ssn = p_scb->ssn;
+ param.sess.obj_offset = 0;
+ param.sess.timeout = OBX_SESS_TIMEOUT_VALUE;
+ if (save_state == OBX_SS_PARTIAL_SENT)
+ save_state = p_scb->next_state;
+
+ if ((p_scb->srm & OBX_SRM_ENGAGE) == 0)
+ {
+ /* SRM is not engaged.
+ * When the session is resume, client needs to send the request first,
+ * the save ssm state may need to be adjusted */
+ if (save_state == OBX_SS_PUT_INDICATED)
+ {
+ save_state = OBX_SS_PUT_TRANSACTION;
+ }
+ else if (save_state == OBX_SS_GET_INDICATED)
+ {
+ save_state = OBX_SS_GET_TRANSACTION;
+ }
+ }
+ p_scb->sess_info[OBX_SESSION_INFO_ST_IDX] = save_state;
+ OBX_TRACE_DEBUG2("saved state:0x%x, srm:0x%x", save_state, p_scb->sess_info[OBX_SESSION_INFO_SRM_IDX]);
+ memcpy(param.sess.peer_addr, p_scb->peer_addr, BD_ADDR_LEN);
+ p_scb->sess_st = OBX_SESS_NONE;
+ if (p_cback)
+ (*p_cback)(p_scb->ll_cb.comm.handle, OBX_SESSION_INFO_EVT, param, NULL);
+ }
+ else if (p_scb->sess_st == OBX_SESS_CLOSE || p_scb->state == OBX_SS_NOT_CONNECTED)
+ p_scb->sess_st = OBX_SESS_NONE;
+
+ if (p_scb->ll_cb.comm.tx_mtu != 0)
+ {
+ p_scb->ll_cb.comm.tx_mtu = 0;
+ obx_stop_timer(&p_scb->ll_cb.comm.tle);
+ p_scb->conn_id = 0;
+ if (p_cback)
+ (*p_cback)(p_scb->ll_cb.comm.handle, OBX_CLOSE_IND_EVT, param, p_pkt);
+ }
+
+ if (p_scb->ll_cb.comm.p_send_fn == (tOBX_SEND_FN *)obx_l2c_snd_msg)
+ {
+ p_scb->ll_cb.comm.id = 0; /* mark this port unused. */
+ p_scb->srm &= OBX_SRM_ENABLE;
+ obx_add_port (p_scb->handle);
+ }
+
+ return OBX_SS_NULL;
+}
+
+/*******************************************************************************
+** Function obx_sa_close_port
+** Description Close transport. Start timer.
+*******************************************************************************/
+tOBX_SR_STATE obx_sa_close_port(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt)
+{
+ if (p_pkt)
+ GKI_freebuf(p_pkt);
+ p_scb->ll_cb.comm.p_close_fn(p_scb->ll_cb.comm.id);
+ obx_sr_free_scb(p_scb);
+ obx_start_timer(&p_scb->ll_cb.comm);
+ return OBX_SS_NULL;
+}
+
+/*******************************************************************************
+** Function obx_sa_clean_port
+** Description Close transport and clean up api_evt if illegal obex message is
+** received.
+*******************************************************************************/
+tOBX_SR_STATE obx_sa_clean_port(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt)
+{
+ p_scb->api_evt = OBX_NULL_EVT;
+ return obx_sa_close_port(p_scb, p_pkt);
+}
+/*******************************************************************************
+** Function obx_sa_state
+** Description change state
+*******************************************************************************/
+tOBX_SR_STATE obx_sa_state(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt)
+{
+ return p_scb->next_state;
+}
+
+/*******************************************************************************
+** Function obx_sa_nc_to
+** Description Timer expires in not_conn state
+** if there is existing connections -> disconnect
+*******************************************************************************/
+tOBX_SR_STATE obx_sa_nc_to(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt)
+{
+ BD_ADDR bd_addr;
+
+ obx_stop_timer(&p_scb->ll_cb.comm.tle);
+ /* if there is existing connections -> disconnect */
+ if (OBX_GetPeerAddr(p_scb->ll_cb.comm.handle, bd_addr) != 0)
+ {
+ p_scb->ll_cb.comm.p_close_fn(p_scb->ll_cb.comm.id);
+ p_scb->conn_id = 0;
+ /* wait for the conn err event to re-open the port */
+ }
+ return OBX_SS_NULL;
+}
+
+/*******************************************************************************
+** Function obx_sa_save_req
+** Description When a request received from peer in PART state,
+** save the request for later processing
+*******************************************************************************/
+tOBX_SR_STATE obx_sa_save_req(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt)
+{
+ if (p_scb->p_next_req)
+ {
+ GKI_freebuf(p_scb->p_next_req);
+ }
+ p_scb->p_next_req = p_pkt;
+ p_scb->api_evt = OBX_NULL_EVT;
+ return OBX_SS_NULL;
+}
+
+/*******************************************************************************
+** Function obx_sa_rej_req
+** Description Send bad request response when request comes in bad state
+*******************************************************************************/
+tOBX_SR_STATE obx_sa_rej_req(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt)
+{
+ UINT8 msg[OBX_HDR_OFFSET];
+ UINT8 *p = msg;
+
+ OBX_TRACE_DEBUG0( "obx_sa_rej_req" ) ;
+ if (p_pkt)
+ GKI_freebuf(p_pkt);
+
+ /* response packets always have the final bit set */
+ *p++ = (OBX_RSP_SERVICE_UNAVL | OBX_FINAL);
+ p += OBX_PKT_LEN_SIZE;
+
+ /* add session sequence number, if session is active */
+ if (p_scb->sess_st == OBX_SESS_ACTIVE)
+ {
+ *p++ = OBX_HI_SESSION_SN;
+ *p++ = (p_scb->ssn+1);
+ }
+
+ /* add connection ID, if needed */
+ if (p_scb->conn_id)
+ {
+ *p++ = OBX_HI_CONN_ID;
+ UINT32_TO_BE_STREAM(p, p_scb->conn_id);
+ }
+
+ p_pkt = obx_sr_prepend_msg(NULL, msg, (UINT16)(p - msg) );
+ p_pkt->event = OBX_PUT_RSP_EVT; /* any response */
+ p_scb->api_evt = OBX_NULL_EVT;
+
+ return obx_sa_snd_rsp(p_scb, p_pkt);
+}
+
+/*******************************************************************************
+** Function obx_sa_get_ind
+** Description received a GET request from the client. Check if SRM is engaged.
+*******************************************************************************/
+tOBX_SR_STATE obx_sa_get_ind(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt)
+{
+ tOBX_SR_STATE state = OBX_SS_NULL;
+
+ if ((p_scb->srm & OBX_SRM_REQING) && (p_scb->srm & OBX_SRM_ENABLE))
+ {
+ state = OBX_CS_GET_SRM;
+ }
+
+ /* the GET request does not set the final bit.
+ * Save this request, send response automatically and do not report the event */
+ if ((!p_scb->param.get.final) && ((p_scb->srmp & OBX_SRMP_NONF_EVT) == 0))
+ {
+ p_scb->srmp |= OBX_SRMP_NONF;
+ if (p_scb->p_saved_msg)
+ GKI_freebuf(p_scb->p_saved_msg);
+ p_scb->p_saved_msg = p_pkt;
+ p_scb->api_evt = OBX_NULL_EVT;
+ OBX_GetRsp(p_scb->ll_cb.comm.handle, OBX_RSP_CONTINUE, NULL);
+ }
+ return state;
+}
+
+/*******************************************************************************
+** Function obx_merge_get_req
+** Description merge the given 2 GET request packets and return the merged result
+*******************************************************************************/
+BT_HDR * obx_merge_get_req(BT_HDR *p_pkt1, BT_HDR *p_pkt2)
+{
+ BT_HDR *p_ret = p_pkt1;
+ UINT16 size, need;
+ UINT8 *p1, *p2;
+ UINT8 *p, pre_size = OBX_GET_HDRS_OFFSET;
+
+ /* skip the connection ID header */
+ p = (UINT8 *)(p_pkt2 + 1) + p_pkt2->offset;
+ if (*p == OBX_HI_CONN_ID)
+ pre_size += 5;
+
+ need = p_pkt1->len + p_pkt2->len;
+ if ((p_pkt2->len == pre_size) || (need >= OBX_LRG_DATA_POOL_SIZE))
+ {
+ GKI_freebuf (p_pkt2);
+ return p_pkt1;
+ }
+
+ /* get rid of the GET request header - opcode(1) + packet len(2) (and maybe connection ID) before merging */
+ p_pkt2->len -= pre_size;
+ p_pkt2->offset += pre_size;
+ size = GKI_get_buf_size(p_pkt1);
+
+ if (size < need)
+ {
+ /* the original p_pkt1 is too small.
+ * Allocate a bigger GKI buffer, p_ret, and copy p_pkt1 into p_ret */
+ if (need < GKI_MAX_BUF_SIZE)
+ {
+ /* Use the largest general pool to allow challenge tags appendage */
+ p_ret = (BT_HDR *)GKI_getbuf(GKI_MAX_BUF_SIZE);
+ }
+ else
+ {
+ p_ret = (BT_HDR *) GKI_getpoolbuf(OBX_LRG_DATA_POOL_ID);
+ }
+ memcpy (p_ret, p_pkt1, sizeof (BT_HDR));
+ p_ret->offset = 0;
+ p1 = (UINT8 *)(p_ret + 1);
+ p2 = (UINT8 *)(p_pkt1 + 1) + p_pkt1->offset;
+ memcpy (p1, p2, p_pkt1->len);
+ GKI_freebuf (p_pkt1);
+ }
+
+ /* adjust the actualy packet length to reflect the combined packet and copy p_pkt2 into p_ret */
+ p1 = (UINT8 *)(p_ret + 1) + p_ret->offset + 1;
+ size = p_ret->len + p_pkt2->len;
+ UINT16_TO_BE_STREAM(p1, size);
+ p1 = (UINT8 *)(p_ret + 1) + p_ret->offset + p_ret->len;
+ p2 = (UINT8 *)(p_pkt2 + 1) + p_pkt2->offset;
+ p_ret->len = size;
+ memcpy (p1, p2, p_pkt2->len);
+ GKI_freebuf (p_pkt2);
+
+ return p_ret;
+}
+
+/*******************************************************************************
+** Function obx_sa_get_req
+** Description
+*******************************************************************************/
+tOBX_SR_STATE obx_sa_get_req(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt)
+{
+ tOBX_SR_STATE state = OBX_SS_NULL;
+ tOBX_SR_CB *p_cb;
+
+ OBX_TRACE_DEBUG2("obx_sa_get_req srmp:0x%x final:%d", p_scb->srmp, p_scb->param.get.final);
+ if (p_scb->srmp & OBX_SRMP_NONF)
+ {
+ /* the GET request does not set the final bit yet.
+ * merge this request, send response automatically and do not report the event */
+ if (!p_scb->param.get.final)
+ {
+ p_scb->p_saved_msg = obx_merge_get_req(p_scb->p_saved_msg, p_pkt);
+ p_scb->api_evt = OBX_NULL_EVT;
+ OBX_GetRsp(p_scb->ll_cb.comm.handle, OBX_RSP_CONTINUE, NULL);
+ }
+ else
+ {
+ p_scb->srmp &= ~OBX_SRMP_NONF;
+ p_pkt = obx_merge_get_req(p_scb->p_saved_msg, p_pkt);
+ p_scb->p_saved_msg = NULL;
+ p_scb->api_evt = OBX_NULL_EVT;
+ p_cb = &obx_cb.server[p_scb->handle - 1];
+ (p_cb->p_cback) (p_scb->ll_cb.comm.handle, OBX_GET_REQ_EVT, p_scb->param, p_pkt);
+ memset(&p_scb->param, 0, sizeof (p_scb->param) );
+ }
+ }
+
+ return state;
+}
+
+/*******************************************************************************
+** Function obx_sa_make_sess_id
+** Description compute the session id
+*******************************************************************************/
+static tOBX_STATUS obx_sa_make_sess_id (tOBX_SR_SESS_CB *p_scb, UINT8 *p_sess_info,
+ tOBX_TRIPLET *p_triplet, UINT8 num_triplet)
+{
+ UINT8 data[10];
+ UINT8 ind;
+ UINT8 *p;
+
+ /* check the device address session parameter */
+ ind = obx_read_triplet(p_triplet, num_triplet, OBX_TAG_SESS_PARAM_ADDR);
+ OBX_TRACE_DEBUG2("addr ind:%d, num:%d", ind, num_triplet);
+ if (ind == num_triplet || p_triplet[ind].len != BD_ADDR_LEN)
+ {
+ OBX_TRACE_ERROR0("No Device Addr parameter");
+ return OBX_BAD_PARAMS;
+ }
+
+ if (memcmp (p_scb->peer_addr, p_triplet[ind].p_array, BD_ADDR_LEN) != 0)
+ {
+ OBX_TRACE_ERROR0("Bad Device Addr parameter");
+ return OBX_BAD_PARAMS;
+ }
+
+ /* check the nonce session parameter */
+ ind = obx_read_triplet(p_triplet, num_triplet, OBX_TAG_SESS_PARAM_NONCE);
+ OBX_TRACE_DEBUG2("nonce ind:%d, num:%d", ind, num_triplet);
+ if (ind == num_triplet || (p_triplet[ind].len < OBX_MIN_NONCE_SIZE) || (p_triplet[ind].len > OBX_NONCE_SIZE))
+ {
+ OBX_TRACE_ERROR0("No Nonce parameter");
+ return OBX_BAD_PARAMS;
+ }
+ p = data;
+ BTM_GetLocalDeviceAddr (p);
+
+ /* compute the session ID */
+ obx_session_id (p_sess_info, p_scb->peer_addr, p_triplet[ind].p_array, p_triplet[ind].len,
+ data, &p_scb->sess_info[OBX_SESSION_ID_SIZE], OBX_LOCAL_NONCE_SIZE);
+
+ return OBX_SUCCESS;
+}
+
+/*******************************************************************************
+** Function obx_sa_session_ind
+** Description process session request from client
+** when the session request is received is not OBX_SS_NOT_CONNECTED
+*******************************************************************************/
+tOBX_SR_STATE obx_sa_session_ind(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt)
+{
+ tOBX_TRIPLET triplet[OBX_MAX_SESS_PARAM_TRIP];
+ UINT8 num = OBX_MAX_SESS_PARAM_TRIP, ind;
+ UINT8 *p;
+ tOBX_SR_CB *p_cb = obx_sr_get_cb(p_scb->handle);
+ UINT8 rsp_code = OBX_RSP_FORBIDDEN;
+ BOOLEAN now = FALSE;
+#if (BT_USE_TRACES == TRUE)
+ tOBX_SESS_ST old_sess_st = p_scb->sess_st;
+#endif
+ tOBX_EVENT old_api_evt;
+ UINT32 obj_offset = 0;
+ UINT8 ind_to;
+ UINT32 timeout = OBX_INFINITE_TIMEOUT;
+ tOBX_SR_STATE state = OBX_SS_NULL;
+
+ OBX_TRACE_DEBUG0("obx_sa_session_ind");
+ OBX_ReadTriplet(p_pkt, OBX_HI_SESSION_PARAM, triplet, &num);
+ if (p_cb->nonce == 0)
+ {
+ OBX_TRACE_ERROR0("reliable session is not supported by this server");
+ /* do not report the session_req_evt */
+ p_scb->api_evt = OBX_NULL_EVT;
+ obx_prepend_rsp_msg(p_scb->handle, OBX_SESSION_CFM_SEVT, OBX_RSP_NOT_IMPLEMENTED, NULL);
+ return OBX_SS_NULL;
+ }
+ else if (num)
+ {
+ ind = obx_read_triplet(triplet, num, OBX_TAG_SESS_PARAM_SESS_OP);
+ OBX_TRACE_DEBUG2("sess_op ind:%d, num:%d", ind, num);
+ if ((ind != num) && (triplet[ind].len == OBX_LEN_SESS_PARAM_SESS_OP))
+ {
+ p = triplet[ind].p_array;
+ p_scb->param.sess.sess_op = *p;
+ OBX_TRACE_DEBUG1("sess_op :%d", *p);
+ switch (*p)
+ {
+ case OBX_SESS_OP_CREATE:
+ /* do not report the API event */
+ p_scb->api_evt = OBX_NULL_EVT;
+ /* the session is already active; reject with Service Unavailable */
+ rsp_code = OBX_RSP_SERVICE_UNAVL;
+ break;
+
+ case OBX_SESS_OP_CLOSE:
+ /* verify that the session ID matches an existing one. Otherwise, FORBIDDEN */
+ if (p_scb->sess_st != OBX_SESS_NONE)
+ {
+ ind = obx_read_triplet(triplet, num, OBX_TAG_SESS_PARAM_SESS_ID);
+ if (ind == num || triplet[ind].len != OBX_SESSION_ID_SIZE)
+ break;
+ if (memcmp (p_scb->sess_info, triplet[ind].p_array, OBX_SESSION_ID_SIZE) != 0)
+ {
+ /* bad session id */
+ break;
+ }
+ /* must be closing a good session 0 send the response now */
+ now = TRUE;
+ rsp_code = OBX_RSP_OK;
+ p_scb->sess_st = OBX_SESS_CLOSE;
+ }
+ break;
+
+ case OBX_SESS_OP_SUSPEND:
+ /* verify that a session is active. Otherwise, FORBIDDEN */
+ if (p_scb->sess_st == OBX_SESS_ACTIVE)
+ {
+ rsp_code = OBX_RSP_OK;
+ p_scb->sess_st = OBX_SESS_SUSPEND;
+ p_scb->sess_info[OBX_SESSION_INFO_ST_IDX] = p_scb->prev_state;
+ p_scb->sess_info[OBX_SESSION_INFO_SRM_IDX] = p_scb->srm;
+ /* save the session state in a GKI buffer on OBX_SessionRsp */
+ if (p_scb->prev_state == OBX_SS_PUT_INDICATED || p_scb->prev_state == OBX_SS_GET_INDICATED)
+ {
+ /* out of sequence suspend:
+ * report the suspend event when the PutRsp or GetRsp is called
+ * this would allow server to resume the session in the right state */
+ p_scb->api_evt = OBX_NULL_EVT;
+ p_scb->sess_st = OBX_SESS_SUSPENDING;
+ state = p_scb->prev_state;
+ }
+ }
+ break;
+
+ case OBX_SESS_OP_RESUME:
+ rsp_code = OBX_RSP_SERVICE_UNAVL;
+ /* do not report the API event */
+ p_scb->api_evt = OBX_NULL_EVT;
+ break;
+
+ case OBX_SESS_OP_SET_TIME:
+ /* respond SET_TIME right away */
+ now = TRUE;
+
+ if (p_scb->sess_st == OBX_SESS_NONE)
+ {
+ rsp_code = OBX_RSP_FORBIDDEN;
+ }
+ break;
+ }
+ }
+ }
+ OBX_TRACE_DEBUG6("obx_sa_session_ind tx_mtu: %d, sess_st:%d->%d, rsp_code:0x%x, now:%d pstate:%d",
+ p_scb->ll_cb.comm.tx_mtu, old_sess_st, p_scb->sess_st, rsp_code, now, p_scb->prev_state);
+
+ if (rsp_code == OBX_RSP_OK)
+ {
+ obx_read_timeout (triplet, num, &timeout, &p_scb->sess_info[OBX_SESSION_INFO_TO_IDX]);
+ }
+
+ if ((rsp_code != OBX_RSP_OK) || now)
+ {
+ /* hold the original api_evt temporarily, so it's not reported at this obx_ssm_event */
+ old_api_evt = p_scb->api_evt;
+ p_scb->api_evt = OBX_NULL_EVT;
+ /* send the response now */
+ obx_prepend_rsp_msg(p_scb->handle, OBX_SESSION_CFM_SEVT, rsp_code, NULL);
+ /* restore the api event */
+ p_scb->api_evt = old_api_evt;
+ }
+ else
+ {
+ ind_to = obx_read_triplet(triplet, num, OBX_TAG_SESS_PARAM_SESS_OP);
+ if ((ind_to != num) && (triplet[ind_to].len == OBX_TIMEOUT_SIZE))
+ {
+ p = triplet[ind_to].p_array;
+ BE_STREAM_TO_UINT32(timeout, p);
+ }
+ p_scb->param.sess.p_sess_info = p_scb->sess_info;
+ p_scb->param.sess.sess_st = p_scb->sess_st;
+ p_scb->param.sess.ssn = p_scb->ssn;
+ p_scb->param.sess.obj_offset = obj_offset;
+ p_scb->param.sess.timeout = timeout;
+ memcpy(p_scb->param.sess.peer_addr , p_scb->peer_addr, BD_ADDR_LEN);
+
+ }
+ return state;
+}
+
+/*******************************************************************************
+** Function obx_sa_sess_conn_ind
+** Description process session request from client
+** when the session request is received in OBX_SS_NOT_CONNECTED
+*******************************************************************************/
+tOBX_SR_STATE obx_sa_sess_conn_ind(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt)
+{
+ UINT8 sess_info[OBX_SESSION_INFO_SIZE]; /* session id + local nonce */
+ tOBX_TRIPLET triplet[OBX_MAX_SESS_PARAM_TRIP];
+ UINT8 num = OBX_MAX_SESS_PARAM_TRIP, ind;
+ UINT8 *p;
+ tOBX_SR_CB *p_cb = obx_sr_get_cb(p_scb->handle);
+ UINT8 rsp_code = OBX_RSP_FORBIDDEN;
+ BOOLEAN now = FALSE;
+#if (BT_USE_TRACES == TRUE)
+ tOBX_SESS_ST old_sess_st = p_scb->sess_st;
+#endif
+ tOBX_SESS_OP sess_op = OBX_SESS_OP_CREATE;
+ tOBX_EVENT old_api_evt;
+ UINT32 obj_offset = 0;/* to report in evt param */
+ UINT8 op_ssn;
+ UINT8 num_trip = 0;
+ BT_HDR *p_rsp = NULL;
+ UINT8 data[12];
+ UINT8 ind_to;
+ UINT32 timeout = OBX_INFINITE_TIMEOUT;
+ UINT32 offset = 0; /* if non-0, add to triplet on resume */
+ tOBX_SPND_CB *p_spndcb;
+ tOBX_EVT_PARAM param; /* The event parameter. */
+
+ OBX_TRACE_DEBUG0("obx_sa_sess_conn_ind");
+ OBX_ReadTriplet(p_pkt, OBX_HI_SESSION_PARAM, triplet, &num);
+ if (p_cb->nonce == 0)
+ {
+ OBX_TRACE_ERROR0("reliable session is not supported by this server");
+ /* do not report the session_req_evt */
+ p_scb->api_evt = OBX_NULL_EVT;
+ obx_prepend_rsp_msg(p_scb->handle, OBX_SESSION_CFM_SEVT, OBX_RSP_NOT_IMPLEMENTED, NULL);
+ return OBX_SS_NULL;
+ }
+ else if (num)
+ {
+ ind = obx_read_triplet(triplet, num, OBX_TAG_SESS_PARAM_SESS_OP);
+ OBX_TRACE_DEBUG2("sess_op ind:%d, num:%d", ind, num);
+ if ((ind != num) && (triplet[ind].len == OBX_LEN_SESS_PARAM_SESS_OP))
+ {
+ p = triplet[ind].p_array;
+ p_scb->param.sess.sess_op = sess_op = *p;
+ OBX_TRACE_DEBUG1("sess_op :%d", *p);
+ switch (*p)
+ {
+ case OBX_SESS_OP_CREATE:
+ /* do not report the API event */
+ p_scb->api_evt = OBX_NULL_EVT;
+
+ if (p_scb->sess_st == OBX_SESS_ACTIVE)
+ {
+ /* the session is already active; reject with OBX_RSP_FORBIDDEN */
+ break;
+ }
+
+ /* check if we still have room for one more session */
+ if (obx_find_suspended_session (p_scb, NULL, 0) == NULL)
+ {
+ rsp_code = OBX_RSP_DATABASE_FULL;
+ break;
+ }
+
+ p = &p_scb->sess_info[OBX_SESSION_INFO_NONCE_IDX];
+ UINT32_TO_BE_STREAM(p, p_cb->nonce);
+ p_cb->nonce++;
+ /* make sure it's not 0 (which means reliable session is disabled) */
+ if (!p_cb->nonce)
+ p_cb->nonce++;
+
+ if (obx_sa_make_sess_id (p_scb, p_scb->sess_info, triplet, num) == OBX_SUCCESS)
+ {
+ rsp_code = OBX_RSP_OK;
+ p_scb->ssn = 0;
+ p_scb->sess_st = OBX_SESS_CREATE;
+ }
+ break;
+
+ case OBX_SESS_OP_RESUME:
+ /* verify that a previously interrupted session exists with the same session parameters.
+ Otherwise, OBX_RSP_SERVICE_UNAVL.
+ */
+ p_spndcb = obx_find_suspended_session (p_scb, triplet, num);
+ if (p_spndcb)
+ {
+ op_ssn = p_spndcb->ssn;
+ memcpy (p_scb->sess_info, p_spndcb->sess_info, OBX_SESSION_INFO_SIZE);
+ if (obx_sa_make_sess_id (p_scb, sess_info, triplet, num) == OBX_SUCCESS &&
+ memcmp (sess_info, p_scb->sess_info, OBX_SESSION_ID_SIZE) == 0)
+ {
+ /* clear the suspend cb info */
+ p_spndcb->state = OBX_SS_NULL;
+ if (p_spndcb->stle.param)
+ {
+ btu_stop_timer (&p_spndcb->stle);
+ p_spndcb->stle.param = 0;
+ }
+ rsp_code = OBX_RSP_OK;
+ p_scb->sess_st = OBX_SESS_RESUME;
+ p_scb->srmp |= OBX_SRMP_SESS_FST;
+ ind = obx_read_triplet(triplet, num, OBX_TAG_SESS_PARAM_NSEQNUM);
+ if (ind != num)
+ {
+ /* ssn exists - must be immediate suspend */
+ p = triplet[ind].p_array;
+ op_ssn = *p;
+ obj_offset = obx_read_obj_offset(triplet, num);
+ }
+ }
+ obxu_dump_hex (p_scb->sess_info, "sess info", OBX_SESSION_INFO_SIZE);
+ OBX_TRACE_DEBUG4("p_spndcb->offset: 0x%x srm:x%x op_ssn %d ssn %d", p_spndcb->offset, p_scb->sess_info[OBX_SESSION_INFO_SRM_IDX],op_ssn,p_scb->ssn);
+
+ if (p_scb->sess_info[OBX_SESSION_INFO_SRM_IDX] & OBX_SRM_ENGAGE)
+ {
+ /*
+ If offset in the request is smaller which only happens when it is a get operation, then client's offset and ssn matters.
+ So server's offset and ssn should be set to the client's ones.
+ If offset in the request is greater which only happens when it is a put operation, then server's offset and ssn matters.
+ So server keeps its offset(do nothing) and ssn and send it back to client in the resume reponse.
+ If offset are equal, either side's offset & ssn is fine, we choose to use the one in the reqeust
+ */
+
+ offset = p_spndcb->offset;
+ if (obj_offset && (obj_offset <= offset))
+ {
+ offset = obj_offset;
+ p_scb->ssn = op_ssn;
+ /* Adjust ssn in the next continue to be the same as nssn in the resume request */
+ if (p_scb->sess_info[OBX_SESSION_INFO_ST_IDX] ==OBX_CS_GET_SRM)
+ p_scb->ssn--;
+
+
+ }
+
+ }
+ /* SRM is not enabled */
+ else
+ {
+ p_scb->ssn = op_ssn;
+ }
+
+ OBX_TRACE_DEBUG4("offset: 0x%x ssn:%d obj_offset:0x%x srm:0x%x", offset, p_scb->ssn, obj_offset, p_scb->sess_info[OBX_SESSION_INFO_SRM_IDX]);
+ }
+
+
+ if (rsp_code != OBX_RSP_OK)
+ {
+ rsp_code = OBX_RSP_SERVICE_UNAVL;
+ }
+ /* do not report the API event for RESUME.
+ * if OBX_RSP_OK, the event is reported in this function.
+ * p_rsp is used to call obx_ssm_event, and can not be reported to cback */
+ p_scb->api_evt = OBX_NULL_EVT;
+ break;
+ }
+ }
+ }
+ else
+ {
+ /* do not have session parameters - bad req do not report the API event */
+ p_scb->api_evt = OBX_NULL_EVT;
+ rsp_code = OBX_RSP_BAD_REQUEST;
+ }
+ OBX_TRACE_DEBUG5("obx_sa_sess_conn_ind tx_mtu: %d, sess_st:%d->%d, rsp_code:0x%x, now:%d",
+ p_scb->ll_cb.comm.tx_mtu, old_sess_st, p_scb->sess_st, rsp_code, now);
+
+ if (rsp_code == OBX_RSP_OK)
+ {
+ /* send the session response now.
+ * do not report OBX_SESSION_REQ_EVT until connect indication,
+ * so connection id can be reported at the same time in sess_info */
+ if ( (p_rsp = OBX_HdrInit(p_scb->handle, OBX_MIN_MTU))== NULL)
+ {
+ rsp_code = OBX_RSP_INTRNL_SRVR_ERR;
+ }
+ else
+ {
+ obx_read_timeout (triplet, num, &timeout, &p_scb->sess_info[OBX_SESSION_INFO_TO_IDX]);
+
+ p = (UINT8 *) (p_rsp + 1) + p_rsp->offset;
+ /* response packet always has the final bit set */
+ *p++ = (OBX_RSP_OK | OBX_FINAL);
+ p_rsp->len = 3;
+ p = data;
+
+ /* add address */
+ triplet[num_trip].tag = OBX_TAG_SESS_PARAM_ADDR;
+ triplet[num_trip].len = BD_ADDR_LEN;
+ triplet[num_trip].p_array = p;
+ BTM_GetLocalDeviceAddr (p);
+ p += BD_ADDR_LEN;
+ num_trip++;
+
+ /* add nonce 4 - 16 bytes */
+ triplet[num_trip].tag = OBX_TAG_SESS_PARAM_NONCE;
+ triplet[num_trip].len = OBX_LOCAL_NONCE_SIZE;
+ triplet[num_trip].p_array = &p_scb->sess_info[OBX_SESSION_INFO_NONCE_IDX];
+ num_trip++;
+
+ /* add session id */
+ triplet[num_trip].tag = OBX_TAG_SESS_PARAM_SESS_ID;
+ triplet[num_trip].len = OBX_SESSION_ID_SIZE;
+ triplet[num_trip].p_array = p_scb->sess_info;
+ num_trip++;
+
+ if (sess_op == OBX_SESS_OP_RESUME)
+ {
+ /* add session id */
+ triplet[num_trip].tag = OBX_TAG_SESS_PARAM_NSEQNUM;
+ triplet[num_trip].len = 1;
+ triplet[num_trip].p_array = p;
+ /* Adjust ssn in the resume response to be the same as nssn in the resume request */
+ if (p_scb->sess_info[OBX_SESSION_INFO_ST_IDX] == OBX_CS_GET_SRM)
+ *p++ = p_scb->ssn+1;
+ else
+ *p++ = p_scb->ssn;
+ num_trip++;
+ if (offset)
+ {
+ triplet[num_trip].tag = OBX_TAG_SESS_PARAM_OBJ_OFF;
+ triplet[num_trip].len = OBX_LEN_SESS_PARAM_OBJ_OFF;
+ triplet[num_trip].p_array = p;
+ UINT32_TO_BE_STREAM(p, offset);
+ num_trip++;
+ obj_offset = offset;
+ }
+ }
+
+ /* add timeout */
+ if (timeout != OBX_INFINITE_TIMEOUT && obx_cb.sess_tout_val != OBX_INFINITE_TIMEOUT && (obx_cb.sess_tout_val > timeout))
+ {
+ timeout = obx_cb.sess_tout_val;
+ triplet[num_trip].p_array = p;
+ num_trip += obx_add_timeout (&triplet[num_trip], obx_cb.sess_tout_val, &p_scb->param.sess);
+ p = &p_scb->sess_info[OBX_SESSION_INFO_TO_IDX];
+ UINT32_TO_BE_STREAM(p, timeout);
+ }
+ OBX_AddTriplet(p_rsp, OBX_HI_SESSION_PARAM, triplet, num_trip);
+
+ /* adjust the packet len */
+ p = (UINT8 *) (p_rsp + 1) + p_rsp->offset + 1;
+ UINT16_TO_BE_STREAM(p, p_rsp->len);
+ p_rsp->event = OBX_SESSION_CFM_SEVT + 1;
+ p_scb->sess_st = OBX_SESS_ACTIVE;
+ p_scb->param.sess.p_sess_info = p_scb->sess_info;
+ p_scb->param.sess.sess_st = p_scb->sess_st;
+ p_scb->param.sess.ssn = p_scb->ssn;
+ p_scb->param.sess.nssn = p_scb->ssn;
+ p_scb->param.sess.obj_offset = obj_offset;
+ p_scb->param.sess.timeout = timeout;
+ memcpy(p_scb->param.sess.peer_addr , p_scb->peer_addr, BD_ADDR_LEN);
+ obx_ssm_event(p_scb, OBX_SESSION_CFM_SEVT, p_rsp);
+
+ if (sess_op == OBX_SESS_OP_RESUME)
+ {
+ (*p_cb->p_cback)(p_scb->ll_cb.comm.handle, OBX_SESSION_REQ_EVT, p_scb->param, NULL);
+ memset(&p_scb->param, 0, sizeof (p_scb->param) );
+ param.conn.ssn = p_scb->ssn;
+ memcpy (param.conn.peer_addr, p_scb->peer_addr, BD_ADDR_LEN);
+ p = &p_scb->sess_info[OBX_SESSION_INFO_MTU_IDX];
+ BE_STREAM_TO_UINT16(param.conn.mtu, p);
+ p_scb->ll_cb.comm.tx_mtu = param.conn.mtu;
+ param.conn.handle = p_scb->ll_cb.comm.handle;
+ OBX_TRACE_DEBUG1("RESUME tx_mtu: %d", p_scb->ll_cb.comm.tx_mtu);
+ /* report OBX_CONNECT_REQ_EVT to let the client know the MTU */
+ (*p_cb->p_cback)(p_scb->ll_cb.comm.handle, OBX_CONNECT_REQ_EVT, param, NULL);
+ }
+ }
+ }
+
+ if ((rsp_code != OBX_RSP_OK) || now)
+ {
+ /* hold the original api_evt temporarily, so it's not reported at this obx_ssm_event */
+ old_api_evt = p_scb->api_evt;
+ p_scb->api_evt = OBX_NULL_EVT;
+ /* send the response now */
+ obx_prepend_rsp_msg(p_scb->handle, OBX_DISCNT_CFM_SEVT, rsp_code, NULL);
+ /* restore the api event */
+ p_scb->api_evt = old_api_evt;
+ }
+ else
+ {
+ ind_to = obx_read_triplet(triplet, num, OBX_TAG_SESS_PARAM_SESS_OP);
+ if ((ind_to != num) && (triplet[ind_to].len == OBX_TIMEOUT_SIZE))
+ {
+ p = triplet[ind_to].p_array;
+ BE_STREAM_TO_UINT32(timeout, p);
+ }
+ p_scb->param.sess.p_sess_info = p_scb->sess_info;
+ p_scb->param.sess.sess_st = p_scb->sess_st;
+ p_scb->param.sess.ssn = p_scb->ssn;
+ p_scb->param.sess.nssn = p_scb->ssn;
+ p_scb->param.sess.obj_offset = obj_offset;
+ p_scb->param.sess.timeout = timeout;
+ memcpy(p_scb->param.sess.peer_addr , p_scb->peer_addr, BD_ADDR_LEN);
+
+ }
+ return OBX_SS_NULL;
+}
+
+/*******************************************************************************
+** Function obx_sa_wc_sess_ind
+** Description process session request from client
+** when the session request is received in OBX_SS_WAIT_CLOSE
+*******************************************************************************/
+tOBX_SR_STATE obx_sa_wc_sess_ind(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt)
+{
+ tOBX_EVT_PARAM param;
+ tOBX_SR_CB *p_cb = obx_sr_get_cb(p_scb->handle);
+
+ OBX_TRACE_DEBUG1("obx_sa_wc_sess_ind sess_st:%d", p_scb->sess_st);
+ if (p_scb->sess_st == OBX_SESS_ACTIVE)
+ {
+ /* processing CloseSession */
+ obx_sa_session_ind(p_scb, p_pkt);
+ }
+ else
+ {
+ /* probably CreateSession */
+ obx_sa_sess_conn_ind(p_scb, p_pkt);
+ OBX_TRACE_DEBUG1("obx_sa_wc_sess_ind (after obx_sa_sess_conn_ind) sess_st:%d", p_scb->sess_st);
+ if (p_scb->sess_st == OBX_SESS_ACTIVE)
+ {
+ /* after session command and still is Active
+ * a session must have been created during Wait_close state.
+ * need to report a OBX_CLOSE_IND_EVT to clean up the profiles */
+ memset(&param, 0, sizeof(tOBX_EVT_PARAM));
+ if (p_cb && p_cb->p_cback)
+ (*p_cb->p_cback)(p_scb->ll_cb.comm.handle, OBX_CLOSE_IND_EVT, param, NULL);
+ }
+ }
+ return OBX_SS_NULL;
+}
+
+/*******************************************************************************
+** Function obx_sa_session_rsp
+** Description process Session response API.
+*******************************************************************************/
+tOBX_SR_STATE obx_sa_session_rsp(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt)
+{
+ tOBX_SR_STATE new_state = OBX_SS_NULL;
+ UINT8 *p;
+ tOBX_L2C_CB *p_lcb;
+ tOBX_L2C_EVT_PARAM evt_param;
+
+ OBX_TRACE_DEBUG1("obx_sa_session_rsp pstate:%d", p_scb->prev_state);
+ new_state = obx_sa_snd_rsp(p_scb, p_pkt);
+ OBX_TRACE_DEBUG2("sess_st: %d op:%d", p_scb->sess_st, p_scb->param.sess.sess_op);
+ if (p_scb->sess_st == OBX_SESS_ACTIVE && p_scb->param.sess.sess_op == OBX_SESS_OP_RESUME)
+ {
+ p_scb->srm = p_scb->sess_info[OBX_SESSION_INFO_SRM_IDX];
+ new_state = p_scb->sess_info[OBX_SESSION_INFO_ST_IDX];
+ p = &p_scb->sess_info[OBX_SESSION_INFO_ID_IDX];
+ BE_STREAM_TO_UINT32(p_scb->conn_id, p);
+ OBX_TRACE_DEBUG3("new_state; %d Connection ID: 0x%x, srm:0x%x", new_state, p_scb->conn_id, p_scb->srm);
+ if ((p_scb->srm & OBX_SRM_ENGAGE) && (new_state == OBX_SS_GET_SRM))
+ {
+ p_lcb = &p_scb->ll_cb.l2c;
+ evt_param.any = 0;
+ obx_l2c_snd_evt (p_lcb, evt_param, OBX_L2C_EVT_RESUME);
+ }
+ /* report OBX_CONNECT_REQ_EVT in obx_sa_sess_conn_ind()
+ if (new_state == OBX_SS_CONNECTED)
+ {
+ } */
+ }
+ else if (p_scb->sess_st == OBX_SESS_CLOSE)
+ {
+ new_state = OBX_SS_WAIT_CLOSE;
+ }
+
+ return new_state;
+}
+
+/*******************************************************************************
+** Function obx_sa_put_ind
+** Description received a PUT request from the client. Check if SRM is engaged.
+*******************************************************************************/
+tOBX_SR_STATE obx_sa_put_ind(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt)
+{
+ tOBX_SR_STATE state = OBX_SS_NULL;
+ if ((p_scb->srm & OBX_SRM_REQING) && (p_scb->srm & OBX_SRM_ENABLE))
+ {
+ state = OBX_CS_PUT_SRM;
+ }
+ return state;
+}
+
+/*******************************************************************************
+** Function obx_sa_srm_put_req
+** Description received a PUT request from the client when SRM is engaged.
+*******************************************************************************/
+tOBX_SR_STATE obx_sa_srm_put_req(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt)
+{
+ if (!p_scb->param.put.final)
+ p_scb->srm |= OBX_SRM_WAIT_UL;
+ return OBX_SS_NULL;
+}
+
+/*******************************************************************************
+** Function obx_sa_srm_put_rsp
+** Description process PUT response API function.
+** report PUT request event, if any is queued
+*******************************************************************************/
+tOBX_SR_STATE obx_sa_srm_put_rsp(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt)
+{
+ tOBX_SR_STATE state = OBX_SS_NULL;
+ tOBX_COMM_CB *p_comm = &p_scb->ll_cb.comm;
+ UINT8 rsp_code = OBX_RSP_DEFAULT;
+ BOOLEAN ret = TRUE;
+
+ obx_access_rsp_code(p_pkt, &rsp_code);
+ rsp_code &= ~OBX_FINAL;
+ if (rsp_code != OBX_RSP_CONTINUE )
+ {
+ p_scb->srm |= OBX_SRM_NEXT;
+ if (rsp_code != OBX_RSP_OK)
+ p_scb->srm |= OBX_SRM_ABORT;
+ }
+
+ p_scb->srm &= ~OBX_SRM_WAIT_UL;
+ OBX_TRACE_DEBUG2("obx_sa_srm_put_rsp srm:0x%x rsp_code:0x%x", p_scb->srm, rsp_code);
+ if (p_scb->srm & OBX_SRM_NEXT)
+ {
+ p_scb->srm &= ~OBX_SRM_NEXT;
+ state = obx_sa_snd_rsp (p_scb, p_pkt);
+ }
+ else
+ {
+ if (p_scb->sess_st == OBX_SESS_ACTIVE)
+ {
+ p_scb->ssn++;
+ }
+ obx_start_timer(&p_scb->ll_cb.comm);
+ if (p_pkt)
+ GKI_freebuf(p_pkt);
+ }
+ OBX_TRACE_DEBUG1("obx_sa_srm_put_rsp srm:0x%x", p_scb->srm);
+
+ while (ret && (p_pkt = (BT_HDR *)GKI_dequeue (&p_comm->rx_q)) != NULL)
+ {
+ if (state != OBX_SS_NULL)
+ {
+ p_scb->state = state;
+ state = OBX_SS_NULL;
+ }
+ ret = obx_sr_proc_pkt (p_scb, p_pkt);
+ if ((p_scb->srm & OBX_SRM_ABORT) == 0)
+ ret = FALSE;
+ obx_flow_control(p_comm);
+ OBX_TRACE_DEBUG3("obx_sa_srm_put_rsp rx_q.count: %d srm:0x%x, ret:%d", p_comm->rx_q.count, p_scb->srm, ret );
+ }
+
+ return state;
+}
+
+/*******************************************************************************
+** Function obx_sa_srm_get_fcs
+** Description Process L2CAP congestion event
+*******************************************************************************/
+tOBX_SR_STATE obx_sa_srm_get_fcs(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt)
+{
+ BOOLEAN not_cong = TRUE;
+ if (p_scb->ll_cb.comm.p_send_fn == (tOBX_SEND_FN *)obx_l2c_snd_msg)
+ {
+ OBX_TRACE_DEBUG1("obx_sa_srm_get_fcs cong:%d", p_scb->ll_cb.l2c.cong);
+ if (p_scb->ll_cb.l2c.cong)
+ not_cong = FALSE;
+ }
+ if (not_cong)
+ p_scb->api_evt = OBX_GET_REQ_EVT;
+ return OBX_SS_NULL;
+}
+
+/*******************************************************************************
+** Function obx_sa_srm_get_rsp
+** Description send GET response to client
+*******************************************************************************/
+tOBX_SR_STATE obx_sa_srm_get_rsp(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt)
+{
+ tOBX_SR_STATE state;
+ OBX_TRACE_DEBUG1("obx_sa_srm_get_rsp srm:0x%x", p_scb->srm);
+ state = obx_sa_snd_rsp(p_scb, p_pkt);
+ return state;
+}
+
+
+
+/*******************************************************************************
+** Function obx_sa_srm_get_req
+** Description process GET request from client
+*******************************************************************************/
+tOBX_SR_STATE obx_sa_srm_get_req(tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt)
+{
+ tOBX_SR_STATE state = OBX_SS_NULL;
+ tOBX_SR_CB *p_cb;
+
+ OBX_TRACE_DEBUG3("obx_sa_srm_get_req srm:0x%x srmp:0x%x final:%d", p_scb->srm, p_scb->srmp, p_scb->param.get.final);
+ if (p_scb->srmp & OBX_SRMP_NONF)
+ {
+ /* the GET request does not set the final bit yet.
+ * merge this request, send response automatically and do not report the event */
+ if (!p_scb->param.get.final)
+ {
+ p_scb->p_saved_msg = obx_merge_get_req(p_scb->p_saved_msg, p_pkt);
+ p_scb->api_evt = OBX_NULL_EVT;
+ }
+ else
+ {
+ p_scb->srmp &= ~OBX_SRMP_NONF;
+ p_pkt = obx_merge_get_req(p_scb->p_saved_msg, p_pkt);
+ p_scb->p_saved_msg = NULL;
+ p_scb->api_evt = OBX_NULL_EVT;
+ p_cb = &obx_cb.server[p_scb->handle - 1];
+ (p_cb->p_cback) (p_scb->ll_cb.comm.handle, OBX_GET_REQ_EVT, p_scb->param, p_pkt);
+ memset(&p_scb->param, 0, sizeof (p_scb->param) );
+ }
+ }
+
+ return state;
+}
+
diff --git a/stack/obx/obx_sapi.c b/stack/obx/obx_sapi.c
new file mode 100644
index 0000000..7815947
--- /dev/null
+++ b/stack/obx/obx_sapi.c
@@ -0,0 +1,591 @@
+/*****************************************************************************
+**
+** Name: obx_sapi.c
+**
+** File: OBEX Server Application Programming Interface functions
+**
+** Copyright (c) 2003-2009, Broadcom Corp., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include <string.h>
+
+#include "bt_target.h"
+
+#if defined(OBX_INCLUDED) && (OBX_INCLUDED == TRUE)
+
+#include "wcassert.h"
+#include "btu.h"
+#include "port_api.h"
+#include "obx_int.h"
+#include "l2c_api.h"
+#include "btm_api.h"
+
+/*******************************************************************************
+**
+** Function OBX_StartServer
+**
+** Description This function is to register a server entity to OBEX.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_NO_RESOURCES, if OBX does not have resources.
+**
+*******************************************************************************/
+tOBX_STATUS OBX_StartServer(tOBX_StartParams *p_params, tOBX_HANDLE *p_handle)
+{
+ tOBX_SR_CB *p_cb = NULL;
+ tOBX_STATUS status = OBX_NO_RESOURCES;
+// btla-specific ++
+ tOBX_SR_SESS_CB *p_scb = NULL;
+// btla-specific --
+ tOBX_HANDLE obx_handle;
+ UINT8 size;
+
+ WC_ASSERT(p_params);
+ WC_ASSERT(p_params->p_cback);
+ WC_ASSERT(p_handle);
+
+ if (p_params->max_sessions > OBX_MAX_SR_SESSION)
+ {
+ OBX_TRACE_ERROR2("OBX_StartServer bad max_sessions:%d (1-%d)",
+ p_params->max_sessions, OBX_MAX_SR_SESSION);
+ return OBX_BAD_PARAMS;
+ }
+
+ if (p_params->scn == 0 && L2C_INVALID_PSM(p_params->psm))
+ {
+ OBX_TRACE_ERROR2("OBX_StartServer bad scn:%d and psm:0x%x", p_params->scn, p_params->psm);
+ return OBX_BAD_PARAMS;
+ }
+
+ if (p_params->max_sessions == 0)
+ p_params->max_sessions = 1;
+
+ /* allocate a server control block */
+ obx_handle = obx_sr_alloc_cb(p_params);
+ if (obx_handle)
+ p_cb = &obx_cb.server[obx_handle-1];
+
+ if (p_cb != NULL)
+ {
+ p_scb = &obx_cb.sr_sess[p_cb->sess[0]-1];
+ p_scb->ll_cb.port.rx_mtu = p_params->mtu;
+ if (p_cb->scn)
+ {
+ /* open an RFCOMM port to listen for incoming messages */
+ /* allocate the port for the first session now. The others will be allocated when needed */
+ status = obx_open_port(&p_scb->ll_cb.port, BT_BD_ANY, p_cb->scn);
+ }
+ else
+ {
+ status = OBX_SUCCESS;
+ }
+
+ if (status == OBX_SUCCESS)
+ {
+ /* If authentication is needed for this server, save the parameters in control block */
+ if (p_params->authenticate)
+ {
+ p_cb->p_auth = (tOBX_AUTH_PARAMS *)GKI_getbuf(sizeof(tOBX_AUTH_PARAMS)+OBX_MAX_REALM_LEN+1);
+ if (p_cb->p_auth)
+ {
+ p_cb->p_auth->auth_option = p_params->auth_option;
+ /* adjust realm len, if the given realm is too big */
+ size = (p_params->realm_len>OBX_MAX_REALM_LEN) ? OBX_MAX_REALM_LEN : p_params->realm_len;
+ p_cb->p_auth->realm_len = size;
+ p_cb->p_auth->realm[0] = p_params->realm_charset;
+ if (p_params->realm_len && p_params->p_realm)
+ memcpy(&p_cb->p_auth->realm[1], p_params->p_realm, size);
+ }
+ else
+ status = OBX_NO_RESOURCES;
+ }
+ }
+
+ if (status == OBX_SUCCESS)
+ {
+ /* if everything is OK, save the other parameters for this server */
+ memset(p_cb->target.target, 0, OBX_MAX_TARGET_LEN);
+ if (p_params->p_target)
+ {
+ if (p_params->p_target->len)
+ {
+ /* OBX handles who, connection ID headers */
+ p_cb->target.len = p_params->p_target->len;
+ memcpy(p_cb->target.target, p_params->p_target->target, p_params->p_target->len);
+ }
+ else
+ {
+ /* the regular default server */
+ /* the user handles target, who headers.
+ * OBX handles connection ID header */
+ p_cb->target.len = OBX_DEFAULT_TARGET_LEN;
+ }
+ }
+ else
+ {
+ /* the one and only default server */
+ /* no target, who, connection id headers for this case */
+ p_cb->target.len = 0;
+ }
+
+// btla-specific ++
+ if (p_scb)
+ {
+ OBX_TRACE_DEBUG3("OBX_StartServer target len:%d, authenticate:%d handle:0x%x",
+ p_cb->target.len, p_params->authenticate, p_scb->ll_cb.port.handle);
+ p_cb->p_cback = p_params->p_cback;
+ p_scb->state = OBX_SS_NOT_CONNECTED;
+
+ /* give the handle to application */
+ *p_handle = p_scb->ll_cb.port.handle;
+ }
+// btla-specific --
+ }
+ else
+ {
+ /* otherwise, free the control block */
+ obx_sr_free_cb(obx_handle);
+ }
+ }
+
+ return status;
+}
+
+
+/*******************************************************************************
+**
+** Function OBX_StopServer
+**
+** Description This function is to stop this OBEX server from receiving any
+** more incoming requests.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_BAD_HANDLE, if the handle is not valid.
+**
+*******************************************************************************/
+tOBX_STATUS OBX_StopServer(tOBX_HANDLE handle)
+{
+ tOBX_STATUS status = OBX_SUCCESS;
+ tOBX_SR_CB *p_cb = obx_sr_get_cb(handle);
+ tOBX_SR_SESS_CB *p_scb;
+ int xx;
+ tOBX_SPND_CB *p_spndcb;
+
+ if (p_cb)
+ {
+ /* Process suspended session if necessary */
+ if (p_cb->p_suspend)
+ {
+ for (xx=0, p_spndcb=p_cb->p_suspend; xx<p_cb->max_suspend; xx++, p_spndcb++)
+ {
+ if (p_spndcb->state)
+ {
+ btu_stop_timer (&p_spndcb->stle);
+ }
+ }
+ GKI_freebuf (p_cb->p_suspend);
+ }
+
+ for (xx=0; xx < p_cb->num_sess && p_cb->sess[xx]; xx ++)
+ {
+ p_scb = &obx_cb.sr_sess[p_cb->sess[xx]-1];
+ if (p_scb->ll_cb.comm.id)
+ {
+ OBX_DisconnectRsp(handle, OBX_RSP_SERVICE_UNAVL, NULL);
+ if (p_scb->ll_cb.comm.p_send_fn == (tOBX_SEND_FN *)obx_rfc_snd_msg)
+ RFCOMM_RemoveServer(p_scb->ll_cb.port.port_handle);
+ }
+ }
+
+ if (p_cb->psm)
+ L2CA_DEREGISTER (p_cb->psm);
+
+ obx_sr_free_cb (handle);
+ }
+ else
+ status = OBX_BAD_HANDLE;
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function OBX_AddSuspendedSession
+**
+** Description This function is to add the session information for a previously
+** suspended reliable session to the server control block
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_BAD_HANDLE, if the handle is not valid.
+**
+*******************************************************************************/
+tOBX_STATUS OBX_AddSuspendedSession(tOBX_HANDLE shandle, BD_ADDR peer_addr, UINT8 *p_sess_info,
+ UINT32 timeout, UINT8 ssn, UINT32 offset)
+{
+ tOBX_STATUS status = OBX_SUCCESS;
+ tOBX_SR_CB *p_cb = obx_sr_get_cb(shandle);
+ UINT16 size;
+ UINT8 xx;
+ tOBX_SPND_CB *p_spndcb;
+ INT32 ticks = 0x7FFFFFFF, remain_ticks;
+ BOOLEAN added = FALSE;
+ UINT8 saved_xx = 0;
+
+ OBX_TRACE_DEBUG2("OBX_AddSuspendedSession BDA: %06x%06x",
+ (peer_addr[0]<<16)+(peer_addr[1]<<8)+peer_addr[2],
+ (peer_addr[3]<<16)+(peer_addr[4]<<8)+peer_addr[5]);
+ if (p_cb && p_sess_info && p_cb->max_suspend)
+ {
+ if (p_cb->p_suspend == NULL)
+ {
+ size = p_cb->max_suspend * sizeof (tOBX_SPND_CB);
+ p_cb->p_suspend = (tOBX_SPND_CB *)GKI_getbuf( size);
+ memset (p_cb->p_suspend, 0, size);
+ }
+
+ if (p_cb->p_suspend)
+ {
+ for (xx=0, p_spndcb=p_cb->p_suspend; xx<p_cb->max_suspend; xx++, p_spndcb++)
+ {
+ OBX_TRACE_DEBUG4("[%d] state: %d, ssn:%d BDA: %08x", xx, p_spndcb->state, p_spndcb->ssn,
+ (p_spndcb->peer_addr[2]<<24)+(p_spndcb->peer_addr[3]<<16)+(p_spndcb->peer_addr[4]<<8)+p_spndcb->peer_addr[5]);
+ if (p_spndcb->state == OBX_SS_NULL || memcmp(p_spndcb->peer_addr, peer_addr, BD_ADDR_LEN) == 0)
+ {
+ added = TRUE;
+ break;
+ }
+ else if (p_spndcb->state != OBX_SS_NULL && ticks)
+ {
+ if (p_spndcb->stle.param == 0)
+ {
+ /* this entry has infinite timeout; just use it */
+ ticks = 0;
+ saved_xx = xx;
+ OBX_TRACE_DEBUG1("[%d] infinite timeout", xx );
+ }
+ /* find the entry the expires in the shortest time */
+ else
+ {
+ remain_ticks = btu_remaining_time(&p_spndcb->stle);
+ OBX_TRACE_DEBUG2("[%d] remain_ticks: %d", xx, remain_ticks );
+ if (remain_ticks < ticks)
+ {
+ ticks = remain_ticks;
+ saved_xx = xx;
+ }
+ }
+ }
+ }
+
+ if (!added)
+ {
+ /* if cannot use an empty/or reuse an existing entry, use the one expires soon */
+ added = TRUE;
+ xx = saved_xx; /* this is for debug trace; don't optimize */
+ p_spndcb = &p_cb->p_suspend[xx];
+ OBX_TRACE_DEBUG1("reuse entry [%d]", xx );
+ }
+
+ if (added)
+ {
+ memcpy (p_spndcb->sess_info, p_sess_info, OBX_SESSION_INFO_SIZE);
+ p_spndcb->state = p_sess_info[OBX_SESSION_INFO_ST_IDX];
+ p_spndcb->ssn = ssn;
+ p_spndcb->offset = offset;
+ OBX_TRACE_DEBUG6("[%d] timeout: %d state:%d ssn:%d offset:%d, BDA: %08x",
+ xx, timeout, p_spndcb->state, ssn, offset,
+ (peer_addr[2]<<24)+(peer_addr[3]<<16)+(peer_addr[4]<<8)+peer_addr[5]);
+ memcpy(p_spndcb->peer_addr, peer_addr, BD_ADDR_LEN);
+ if (timeout != OBX_INFINITE_TIMEOUT)
+ {
+ p_spndcb->stle.param = (UINT32)p_spndcb;
+ btu_start_timer(&p_spndcb->stle, BTU_TTYPE_OBX_SVR_SESS_TO, timeout);
+ OBX_TRACE_DEBUG2("timeout: %d ticks:%d", timeout, p_spndcb->stle.ticks);
+ }
+ else
+ p_spndcb->stle.param = 0;
+ }
+ }
+ }
+ else
+ status = OBX_BAD_HANDLE;
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function OBX_ConnectRsp
+**
+** Description This function is called to send the response to a Connect
+** Request from an OBEX client.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_BAD_HANDLE, if the handle is not valid.
+**
+*******************************************************************************/
+tOBX_STATUS OBX_ConnectRsp(tOBX_HANDLE shandle, UINT8 rsp_code, BT_HDR *p_pkt)
+{
+ tOBX_STATUS status = OBX_SUCCESS;
+ tOBX_SR_SESS_CB *p_scb = obx_sr_get_scb(shandle);
+ tOBX_SR_CB *p_cb = obx_sr_get_cb(shandle);
+
+ if (p_scb)
+ {
+ p_pkt = obx_conn_rsp(p_cb, p_scb, rsp_code, p_pkt);
+
+ obx_ssm_event(p_scb, OBX_CONNECT_CFM_SEVT, p_pkt);
+ }
+ else
+ {
+ OBX_TRACE_DEBUG1("OBX_ConnectRsp Bad Handle: 0x%x", shandle);
+ status = OBX_BAD_HANDLE;
+ }
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function OBX_SessionRsp
+**
+** Description This function is called to respond to a request to create a reliable session.
+**
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_BAD_HANDLE, if the handle is not valid.
+**
+*******************************************************************************/
+tOBX_STATUS OBX_SessionRsp(tOBX_HANDLE shandle, UINT8 rsp_code, UINT8 ssn, UINT32 offset, BT_HDR *p_pkt)
+{
+ tOBX_STATUS status = OBX_SUCCESS;
+ tOBX_SR_SESS_CB *p_scb = obx_sr_get_scb(shandle);
+ UINT8 *p;
+ BT_HDR *p_rsp = NULL;
+ tOBX_TRIPLET triplet[5];
+ UINT8 data[12];
+ UINT8 num_trip = 0;
+ UINT32 timeout;
+ tOBX_SESS_ST old_sess_st;
+
+ OBX_TRACE_API0("OBX_SessionRsp");
+ if (p_scb)
+ {
+ old_sess_st = p_scb->sess_st;
+ p_rsp = OBX_HdrInit(p_scb->handle, OBX_MIN_MTU);
+ if (p_rsp)
+ {
+ p = (UINT8 *) (p_rsp + 1) + p_rsp->offset;
+ /* response packet always has the final bit set */
+ *p++ = (rsp_code | OBX_FINAL);
+ p_rsp->len = 3;
+ p = data;
+ if (rsp_code == OBX_RSP_OK)
+ {
+ switch (p_scb->sess_st)
+ {
+ case OBX_SESS_CREATE:
+ case OBX_SESS_RESUME:
+ GKI_freebuf (p_rsp);
+ if (p_pkt)
+ GKI_freebuf (p_pkt);
+ OBX_TRACE_DEBUG0("OBX_SessionRsp do not need to be called for CREATE and RESUME");
+ return OBX_SUCCESS;
+ case OBX_SESS_SUSPEND:
+ p_scb->sess_st = OBX_SESS_SUSPENDED;
+ p = &p_scb->sess_info[OBX_SESSION_INFO_TO_IDX];
+ BE_STREAM_TO_UINT32(timeout, p);
+ OBX_AddSuspendedSession(p_scb->handle, p_scb->peer_addr, p_scb->sess_info, timeout, ssn, offset);
+ break;
+ case OBX_SESS_CLOSE:
+ p_scb->sess_st = OBX_SESS_NONE;
+ break;
+ }
+
+ if (num_trip)
+ OBX_AddTriplet(p_rsp, OBX_HI_SESSION_PARAM, triplet, num_trip);
+ if (p_pkt)
+ {
+ p = (UINT8 *) (p_rsp + 1) + p_rsp->offset + p_rsp->len;
+ memcpy (p, ((UINT8 *) (p_pkt + 1) + p_pkt->offset), p_pkt->len);
+ p_rsp->len += p_pkt->len;
+ }
+ }
+ p = (UINT8 *) (p_rsp + 1) + p_rsp->offset + 1;
+ UINT16_TO_BE_STREAM(p, p_rsp->len);
+
+ p_rsp->event = OBX_SESSION_CFM_SEVT + 1;
+ }
+ OBX_TRACE_DEBUG3("Rsp sess_st:%d->%d status:%d", old_sess_st, p_scb->sess_st, status);
+
+ obx_ssm_event(p_scb, OBX_SESSION_CFM_SEVT, p_rsp);
+ /* clear the "previous" session state as required by earlier comment */
+ p_scb->param.sess.sess_st = 0;
+ }
+ else
+ status = OBX_BAD_HANDLE;
+
+ if (p_pkt)
+ {
+ GKI_freebuf (p_pkt);
+ }
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function obx_prepend_rsp_msg
+**
+** Description This function is called to add response code and connection ID
+** to the given OBEX message
+** Returns OBX_SUCCESS, if successful.
+** OBX_BAD_HANDLE, if the handle is not valid.
+**
+*******************************************************************************/
+tOBX_STATUS obx_prepend_rsp_msg(tOBX_HANDLE shandle, tOBX_SR_EVENT event, UINT8 rsp_code, BT_HDR *p_pkt)
+{
+ tOBX_STATUS status = OBX_SUCCESS;
+ tOBX_SR_SESS_CB *p_scb = obx_sr_get_scb(shandle);
+ UINT8 msg[OBX_HDR_OFFSET];
+ UINT8 *p = msg;
+
+ if (p_scb)
+ {
+ /* response packets always have the final bit set */
+ *p++ = (rsp_code | OBX_FINAL);
+ p += OBX_PKT_LEN_SIZE;
+
+ /* add session sequence number, if session is active */
+ if (p_scb->sess_st == OBX_SESS_ACTIVE || p_scb->sess_st == OBX_SESS_SUSPENDING)
+ {
+ *p++ = OBX_HI_SESSION_SN;
+ *p++ = (p_scb->ssn+1);
+ }
+
+ if (event == OBX_DISCNT_CFM_SEVT)
+ p_scb->conn_id = 0;
+
+ if (p_scb->srm & OBX_SRM_REQING)
+ {
+ p_scb->srm &= ~OBX_SRM_REQING;
+ if (rsp_code == OBX_RSP_CONTINUE)
+ {
+ p_scb->srm |= OBX_SRM_ENGAGE;
+ *p++ = OBX_HI_SRM;
+ *p++ = OBX_HV_SRM_ENABLE;
+
+ if (event == OBX_PUT_CFM_SEVT)
+ p_scb->srm |= OBX_SRM_NEXT;
+ }
+ }
+
+ p_pkt = obx_sr_prepend_msg(p_pkt, msg, (UINT16)(p - msg) );
+ /* this event code needs to be set up properly for flow control reasons */
+ p_pkt->event = event+1;
+ obx_ssm_event(p_scb, event, p_pkt);
+ }
+ else
+ status = OBX_BAD_HANDLE;
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function OBX_SetPathRsp
+**
+** Description This function is called to send the response to a Set Path
+** Request from an OBEX client.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_BAD_HANDLE, if the handle is not valid.
+**
+*******************************************************************************/
+tOBX_STATUS OBX_SetPathRsp(tOBX_HANDLE shandle, UINT8 rsp_code, BT_HDR *p_pkt)
+{
+ return obx_prepend_rsp_msg(shandle, OBX_SETPATH_CFM_SEVT, rsp_code, p_pkt);
+}
+
+
+/*******************************************************************************
+**
+** Function OBX_PutRsp
+**
+** Description This function is called to send the response to a Put
+** Request from an OBEX client.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_BAD_HANDLE, if the handle is not valid.
+**
+*******************************************************************************/
+tOBX_STATUS OBX_PutRsp(tOBX_HANDLE shandle, UINT8 rsp_code, BT_HDR *p_pkt)
+{
+ return obx_prepend_rsp_msg(shandle, OBX_PUT_CFM_SEVT, rsp_code, p_pkt);
+}
+
+
+/*******************************************************************************
+**
+** Function OBX_GetRsp
+**
+** Description This function is called to send the response to a Get
+** Request from an OBEX client.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_BAD_HANDLE, if the handle is not valid.
+**
+*******************************************************************************/
+tOBX_STATUS OBX_GetRsp(tOBX_HANDLE shandle, UINT8 rsp_code, BT_HDR *p_pkt)
+{
+ return obx_prepend_rsp_msg(shandle, OBX_GET_CFM_SEVT, rsp_code, p_pkt);
+}
+
+
+/*******************************************************************************
+**
+** Function OBX_AbortRsp
+**
+** Description This function is called to send the response to an Abort
+** Request from an OBEX client.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_BAD_HANDLE, if the handle is not valid.
+**
+*******************************************************************************/
+tOBX_STATUS OBX_AbortRsp(tOBX_HANDLE shandle, UINT8 rsp_code, BT_HDR *p_pkt)
+{
+ return obx_prepend_rsp_msg(shandle, OBX_ABORT_CFM_SEVT, rsp_code, p_pkt);
+}
+
+/*******************************************************************************
+**
+** Function OBX_ActionRsp
+**
+** Description This function is called to respond to an Action command Request
+** from an OBEX client.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_BAD_HANDLE, if the handle is not valid.
+**
+*******************************************************************************/
+tOBX_STATUS OBX_ActionRsp(tOBX_HANDLE shandle, UINT8 rsp_code, BT_HDR *p_pkt)
+{
+ return obx_prepend_rsp_msg(shandle, OBX_ACTION_CFM_SEVT, rsp_code, p_pkt);
+}
+
+/*******************************************************************************
+**
+** Function OBX_DisconnectRsp
+**
+** Description This function is called to send the response to a Disconnect
+** Request from an OBEX client.
+** This function can also be used to force close the transport
+** to a connected client.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_BAD_HANDLE, if the handle is not valid.
+**
+*******************************************************************************/
+tOBX_STATUS OBX_DisconnectRsp(tOBX_HANDLE shandle, UINT8 rsp_code, BT_HDR *p_pkt)
+{
+ return obx_prepend_rsp_msg(shandle, OBX_DISCNT_CFM_SEVT, rsp_code, p_pkt);
+}
+#endif
diff --git a/stack/obx/obx_ssm.c b/stack/obx/obx_ssm.c
new file mode 100644
index 0000000..2e06404
--- /dev/null
+++ b/stack/obx/obx_ssm.c
@@ -0,0 +1,365 @@
+/*****************************************************************************
+**
+** Name: obx_ssm.c
+**
+** File: OBEX Server State Machine and Control Block Access Functions
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include <string.h>
+
+#include "btu.h" /* for timer */
+#include "obx_int.h"
+
+/* OBEX Server Action Functions Enums (must match obx_sr_action [below] */
+enum
+{
+ OBX_SA_CLOSE_PORT,
+ OBX_SA_CONNECTION_ERROR,
+ OBX_SA_STATE,
+ OBX_SA_CONNECT_IND,
+ OBX_SA_WC_CONN_IND,
+ OBX_SA_NC_TO,
+ OBX_SA_CONNECT_RSP,
+ OBX_SA_AUTH_IND,
+ OBX_SA_SND_RSP,
+ OBX_SA_SAVE_REQ,
+ OBX_SA_SND_PART,
+ OBX_SA_REJ_REQ,
+ OBX_SA_ABORT_RSP,
+ OBX_SA_OP_RSP,
+ OBX_SA_GET_IND,
+ OBX_SA_GET_REQ,
+ OBX_SA_SESSION_IND,
+ OBX_SA_SESS_CONN_IND,
+ OBX_SA_WC_SESS_IND,
+ OBX_SA_SESSION_RSP,
+ OBX_SA_PUT_IND,
+ OBX_SA_SRM_PUT_REQ,
+ OBX_SA_SRM_PUT_RSP,
+ OBX_SA_SRM_GET_FCS,
+ OBX_SA_SRM_GET_RSP,
+ OBX_SA_SRM_GET_REQ,
+ OBX_SA_CLEAN_PORT
+};
+
+/* OBEX Server Action Functions */
+static const tOBX_SR_ACT obx_sr_action[] =
+{
+ obx_sa_close_port,
+ obx_sa_connection_error,
+ obx_sa_state,
+ obx_sa_connect_ind,
+ obx_sa_wc_conn_ind,
+ obx_sa_nc_to,
+ obx_sa_connect_rsp,
+ obx_sa_auth_ind,
+ obx_sa_snd_rsp,
+ obx_sa_save_req,
+ obx_sa_snd_part,
+ obx_sa_rej_req,
+ obx_sa_abort_rsp,
+ obx_sa_op_rsp,
+ obx_sa_get_ind,
+ obx_sa_get_req,
+ obx_sa_session_ind,
+ obx_sa_sess_conn_ind,
+ obx_sa_wc_sess_ind,
+ obx_sa_session_rsp,
+ obx_sa_put_ind,
+ obx_sa_srm_put_req,
+ obx_sa_srm_put_rsp,
+ obx_sa_srm_get_fcs,
+ obx_sa_srm_get_rsp,
+ obx_sa_srm_get_req,
+ obx_sa_clean_port
+};
+
+/************ OBX Server FSM State/Event Indirection Table **************/
+/* obx_ssm_event() first looks at obx_ssm_entry_map[][] to get an entry of the event of a particular state
+ * 0 means the event in the current state is ignored.
+ * a number with 0x80 bit set, use obx_sr_all_table[][] as the "state table".
+ * other numbers, look up obx_sr_main_state_table[] for the state table of current state.
+ *
+ * once the state table is determined,
+ * look up the "action" column to find the associated action function
+ * and the "next state" column to find the "next state" candidate.
+ *
+ * The actual next state could be either the state in the "next state" column
+ * or the state returned from the action function.
+ */
+static const UINT8 obx_ssm_entry_map[][OBX_SS_MAX-1] =
+{
+/* state name: NtCon SesIn CntIn WtAut AutIn Conn DscIn StpIn ActIn AbtIn PutIn GetIn Put Get PutS GetS Part WtCls */
+/* CONN_R */{ 1, 0x82, 0x82, 1, 0x82, 0x86, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82 ,1 },
+/* SESS_R */{ 3, 0x82, 0x82, 0x82, 0x82, 0x88, 3, 0x85, 0x85, 0x85, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 1 ,3 },
+/* DISCNT_R */{ 0x86, 0x82, 0x82, 0x82, 0x82, 0x85, 0x82, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 1 ,0x86 },
+/* PUT_R */{ 0x86, 0x82, 0x82, 0x82, 0x82, 1, 0x87, 0x87, 0x87, 0x82, 0x87, 0x87, 1, 0x82, 1, 0x82, 0x82 ,0x86 },
+/* GET_R */{ 0x86, 0x82, 0x82, 0x82, 0x82, 2, 0x87, 0x87, 0x87, 0x82, 0x87, 0x87, 0x82, 1, 0x82, 1, 0x82 ,0x86 },
+/* SETPATH_R*/{ 0x86, 0x82, 0x82, 0x82, 0x82, 3, 0x87, 0x87, 0x87, 0x82, 0x87, 0x87, 0x82, 0x82, 0x82, 0x82, 0x82 ,0x86 },
+/* ACTION_R */{ 0x86, 0x82, 0x82, 0x82, 0x82, 4, 0x87, 0x87, 0x87, 0x82, 0x87, 0x87, 0x82, 0x82, 0x82, 0x82, 0x82 ,0x86 },
+/* ABORT_R */{ 0x86, 0x82, 0x82, 0x82, 0x82, 0x86, 0x82, 0x82, 0x82, 0x82, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 1 ,0x86 },
+/* CONN_C */{ 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ,0 },
+/* SESS_C */{ 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ,0 },
+/* DISCNT_C */{ 0, 0x82, 0x82, 0x82, 0x82, 0x82, 1, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82 ,0 },
+/* PUT_C */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 2, 0, 0 ,0 },
+/* GET_C */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 2, 0 ,0 },
+/* SETPATH_C*/{ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 ,0 },
+/* ACTION_C */{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 ,0 },
+/* ABORT_C */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0 ,0 },
+/* PORT_CLS */{ 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83 ,0x83 },
+/* FCS_SET */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2 ,0 },
+/* STATE */{ 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84 ,0x84 },
+/* TIMEOUT */{ 2, 0, 0, 2, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ,2 },
+/* BAD_REQ */{ 0x86, 0x82, 0x82, 0x82, 0x82, 0x86, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82 ,0x86 },
+/* TX_EMPTY */{ 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ,0 }
+};
+
+static const UINT8 obx_sr_all_table[][OBX_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* ABORT_R */{OBX_SM_NO_ACTION, OBX_SS_ABORT_INDICATED },
+/* misc */{OBX_SA_CLOSE_PORT, OBX_SS_NOT_CONNECTED },
+/* PORT_CLS */{OBX_SA_CONNECTION_ERROR, OBX_SS_NOT_CONNECTED },
+/* STATE */{OBX_SA_STATE, OBX_SS_NULL },
+/* DISCNT_R */{OBX_SM_NO_ACTION, OBX_SS_DISCNT_INDICATED },
+/* misc */{OBX_SA_REJ_REQ, OBX_SS_NULL },
+/* illegalop*/{OBX_SA_CLEAN_PORT, OBX_SS_NOT_CONNECTED },
+/* SESS_R */{OBX_SA_SESSION_IND, OBX_SS_SESS_INDICATED }
+};
+
+static const UINT8 obx_sr_not_conn_table[][OBX_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* CONN_R */{OBX_SA_CONNECT_IND, OBX_SS_CONN_INDICATED },
+/* TIMEOUT */{OBX_SA_NC_TO, OBX_SS_NOT_CONNECTED},
+/* SESS_R */{OBX_SA_SESS_CONN_IND, OBX_SS_SESS_INDICATED }
+};
+
+static const UINT8 obx_sr_connect_ind_table[][OBX_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* CONN_C */{OBX_SA_CONNECT_RSP, OBX_SS_CONNECTED }
+};
+
+static const UINT8 obx_sr_session_ind_table[][OBX_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* SESS_R */{OBX_SA_SESSION_RSP, OBX_SS_NOT_CONNECTED }
+};
+
+static const UINT8 obx_sr_wait_auth_table[][OBX_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* CONN_R */{OBX_SA_AUTH_IND, OBX_SS_AUTH_INDICATED },
+/* TIMEOUT */{OBX_SA_CLOSE_PORT, OBX_SS_NOT_CONNECTED}
+};
+
+static const UINT8 obx_sr_conn_table[][OBX_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* PUT_R */{OBX_SA_PUT_IND, OBX_SS_PUT_INDICATED },
+/* GET_R */{OBX_SA_GET_IND, OBX_SS_GET_INDICATED },
+/* SETPATH_R*/{OBX_SM_NO_ACTION, OBX_SS_SETPATH_INDICATED },
+/* ACTION_R */{OBX_SM_NO_ACTION, OBX_SS_ACTION_INDICATED }
+};
+
+static const UINT8 obx_sr_disconnect_ind_table[][OBX_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* DISCNT_C */{OBX_SA_SND_RSP, OBX_SS_WAIT_CLOSE },
+/* TIMEOUT */{OBX_SA_CLOSE_PORT, OBX_SS_NOT_CONNECTED},
+/* SESS_R */{OBX_SA_SESSION_IND, OBX_SS_DISCNT_INDICATED}
+};
+
+static const UINT8 obx_sr_setpath_ind_table[][OBX_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* SETPATH_C*/{OBX_SA_SND_RSP, OBX_SS_CONNECTED }
+};
+
+static const UINT8 obx_sr_abort_ind_table[][OBX_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* GET/PUT_C*/{OBX_SA_OP_RSP, OBX_SS_ABORT_INDICATED },
+/* ABORT_C */{OBX_SA_ABORT_RSP, OBX_SS_CONNECTED }
+};
+
+static const UINT8 obx_sr_put_ind_table[][OBX_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* PUT_C */{OBX_SA_SND_RSP, OBX_SS_PUT_TRANSACTION }
+};
+
+static const UINT8 obx_sr_get_ind_table[][OBX_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* GET_C */{OBX_SA_SND_RSP, OBX_SS_GET_TRANSACTION }
+};
+
+static const UINT8 obx_sr_put_table[][OBX_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* PUT_R */{OBX_SM_NO_ACTION, OBX_SS_PUT_INDICATED }
+};
+
+static const UINT8 obx_sr_get_table[][OBX_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* GET_R */{OBX_SA_GET_REQ, OBX_SS_GET_INDICATED }
+};
+
+static const UINT8 obx_sr_put_s_table[][OBX_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* PUT_R */{OBX_SA_SRM_PUT_REQ, OBX_SS_PUT_SRM },
+/* PUT_C */{OBX_SA_SRM_PUT_RSP, OBX_SS_PUT_SRM }
+};
+
+static const UINT8 obx_sr_get_s_table[][OBX_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* GET_R */{OBX_SA_SRM_GET_REQ, OBX_SS_GET_SRM },
+/* GET_C */{OBX_SA_SRM_GET_RSP, OBX_SS_GET_SRM },
+/* FCS_SET */{OBX_SA_SRM_GET_FCS, OBX_SS_GET_SRM }
+};
+
+static const UINT8 obx_sr_part_table[][OBX_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* ABORT_R */{OBX_SA_SAVE_REQ, OBX_SS_NULL },/* and DISCNT_R */
+/* FCS_SET */{OBX_SA_SND_PART, OBX_SS_NULL }
+};
+
+static const UINT8 obx_sr_wait_close_table[][OBX_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* CONN_R */{OBX_SA_WC_CONN_IND, OBX_SS_CONN_INDICATED },
+/* TIMEOUT */{OBX_SA_NC_TO, OBX_SS_NOT_CONNECTED},
+/* SESS_R */{OBX_SA_WC_SESS_IND, OBX_SS_SESS_INDICATED }
+};
+
+static const tOBX_SM_TBL obx_sr_main_state_table[] = {
+ obx_sr_not_conn_table,
+ obx_sr_session_ind_table,
+ obx_sr_connect_ind_table,
+ obx_sr_wait_auth_table,
+ obx_sr_connect_ind_table, /* same table for auth ind */
+ obx_sr_conn_table,
+ obx_sr_disconnect_ind_table,
+ obx_sr_setpath_ind_table,
+ obx_sr_setpath_ind_table, /* same action table for action_ind */
+ obx_sr_abort_ind_table,
+ obx_sr_put_ind_table,
+ obx_sr_get_ind_table,
+ obx_sr_put_table,
+ obx_sr_get_table,
+ obx_sr_put_s_table,
+ obx_sr_get_s_table,
+ obx_sr_part_table,
+ obx_sr_wait_close_table
+};
+
+/*******************************************************************************
+**
+** Function obx_ssm_event
+**
+** Description Handle events to the server state machine. It looks up the entry
+** in the obx_ssm_entry_map array. If it is a valid entry, it gets
+** the state table.Set the next state, if not NULL state.Execute
+** the action function according to the state table. If the state
+** returned by action function is not NULL state, adjust the new
+** state to the returned state.If (api_evt != MAX), call callback
+** function.
+**
+** Returns void.
+**
+*******************************************************************************/
+void obx_ssm_event(tOBX_SR_SESS_CB *p_scb, tOBX_SR_EVENT event, BT_HDR *p_msg)
+{
+ UINT8 curr_state = p_scb->state;
+ tOBX_SM_TBL state_table;
+ UINT8 action, entry;
+ tOBX_SR_STATE act_state = OBX_SS_NULL;
+ UINT8 *p_data;
+ UINT16 len;
+ BT_HDR *p_dummy;
+ tOBX_EVENT api_evt;
+ tOBX_SR_CB *p_cb;
+#if 0
+ UINT8 srm;
+#endif
+
+ if( curr_state == OBX_SS_NULL || curr_state >= OBX_SS_MAX)
+ {
+ OBX_TRACE_WARNING1( "Invalid state: %d", curr_state) ;
+ if(p_msg)
+ GKI_freebuf(p_msg);
+ return;
+ }
+
+ OBX_TRACE_DEBUG6( "For Server SHandle 0x%x, State: %s, Event: %s/%d srm:0x%x ssn:%d",
+ p_scb->ll_cb.comm.handle, obx_sr_get_state_name( p_scb->state ),
+ obx_sr_get_event_name(event), event, p_scb->srm, p_scb->ssn ) ;
+
+ /* look up the state table for the current state */
+ /* lookup entry /w event & curr_state */
+ /* If entry is ignore, return.
+ * Otherwise, get state table (according to curr_state or all_state) */
+ /* coverity [index_parm] */
+ if( (entry = obx_ssm_entry_map[event][curr_state-1]) != OBX_SM_IGNORE )
+ {
+ if(entry&OBX_SM_ALL)
+ {
+ entry &= OBX_SM_ENTRY_MASK;
+ state_table = obx_sr_all_table;
+ }
+ else
+ state_table = obx_sr_main_state_table[curr_state-1];
+ }
+ else
+ {
+ OBX_TRACE_WARNING2( "Ignore event %d in state %d", event, curr_state );
+ if(p_msg)
+ GKI_freebuf(p_msg);
+ return;
+ }
+
+ /* Get possible next state from state table. */
+ if( state_table[entry-1][OBX_SME_NEXT_STATE] != OBX_CS_NULL )
+ p_scb->state = state_table[entry-1][OBX_SME_NEXT_STATE];
+ p_scb->prev_state = curr_state;
+ OBX_TRACE_DEBUG3( "possible new state = %s/%s/%d",
+ obx_sr_get_state_name(p_scb->state), obx_sr_get_state_name( p_scb->prev_state ), p_scb->prev_state) ;
+
+ /* If action is not ignore, clear param, exec action and get next state.
+ * The action function may set the Param for cback.
+ * Depending on param, call cback or free buffer. */
+ /* execute action */
+ action = state_table[entry-1][OBX_SME_ACTION];
+ if (action != OBX_SM_NO_ACTION)
+ {
+ act_state = (*obx_sr_action[action])(p_scb, p_msg);
+ }
+
+ /* adjust next state, if it needs to use the new state returned from action function */
+ if( act_state != OBX_CS_NULL)
+ {
+ p_scb->state = act_state;
+ OBX_TRACE_DEBUG1( "new state = %s (action)", obx_sr_get_state_name( p_scb->state ) ) ;
+ }
+
+ if(p_scb->api_evt)
+ {
+ api_evt = p_scb->api_evt;
+ p_scb->api_evt = OBX_NULL_EVT;
+ /* we do not want the operation to be challenged by the client */
+ if( event <= OBX_SEVT_MAX_REQ && event != OBX_CONNECT_REQ_SEVT &&
+ OBX_ReadByteStrHdr(p_msg, OBX_HI_CHALLENGE, &p_data, &len, 0) == TRUE)
+ {
+ /* send bad request response */
+ p_dummy = obx_build_dummy_rsp(p_scb, OBX_RSP_BAD_REQUEST);
+ event += OBX_SEVT_DIFF_REQ_CFM;
+ obx_ssm_event(p_scb, event, p_dummy);
+ GKI_freebuf(p_msg);
+ }
+ else
+ {
+ p_cb = &obx_cb.server[p_scb->handle - 1];
+ (p_cb->p_cback) (p_scb->ll_cb.comm.handle, api_evt, p_scb->param, p_msg);
+ }
+ memset(&p_scb->param, 0, sizeof (p_scb->param) );
+ }
+ else if(action == OBX_SM_NO_ACTION && p_msg)
+ GKI_freebuf(p_msg);
+
+
+ OBX_TRACE_DEBUG2( "result state = %s ssn:%d", obx_sr_get_state_name( p_scb->state ), p_scb->ssn ) ;
+}
+
+
diff --git a/stack/obx/obx_utils.c b/stack/obx/obx_utils.c
new file mode 100644
index 0000000..785df18
--- /dev/null
+++ b/stack/obx/obx_utils.c
@@ -0,0 +1,979 @@
+/*****************************************************************************
+**
+** Name: obx_utils.c
+**
+** File: OBEX common utility functions
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include <string.h>
+#include <stdio.h>
+#include "wcassert.h"
+
+
+#include "bt_target.h"
+#include "obx_int.h"
+#include "port_api.h"
+#include "sdpdefs.h"
+#include "l2c_api.h"
+
+const tOBX_EVENT obx_sm_evt_to_api_evt[OBX_MAX_EVT_MAP_NUM] =
+{
+ OBX_CONNECT_REQ_EVT,
+ OBX_SESSION_REQ_EVT, /* A Crease Session or Resume Session request is received by the server. Call OBX_SessionRsp(). */
+ OBX_DISCONNECT_REQ_EVT,
+ OBX_PUT_REQ_EVT,
+ OBX_GET_REQ_EVT,
+ OBX_SETPATH_REQ_EVT,
+ OBX_ACTION_REQ_EVT, /* An Action request is received by the server. Call OBX_ActionRsp(). */
+ OBX_ABORT_REQ_EVT
+};
+
+
+const UINT8 obx_rsp_code[] =
+{
+ OBX_RSP_CONTINUE, /* 0x10 Continue */
+ OBX_RSP_OK, /* 0x20 OK, Success */
+ OBX_RSP_CREATED, /* 0x21 Created */
+ OBX_RSP_ACCEPTED, /* 0x22 Accepted */
+ OBX_RSP_NON_AUTH_INFO, /* 0x23 Non-Authoritative Information */
+ OBX_RSP_NO_CONTENT, /* 0x24 No Content */
+ OBX_RSP_RESET_CONTENT, /* 0x25 Reset Content */
+ OBX_RSP_PART_CONTENT, /* 0x26 Partial Content */
+ OBX_RSP_MULTI_CHOICES, /* 0x30 Multiple Choices */
+ OBX_RSP_MVD_PERM, /* 0x31 Moved Permanently */
+ OBX_RSP_MVD_TEMP, /* 0x32 Moved temporarily */
+ OBX_RSP_SEE_OTHER, /* 0x33 See Other */
+ OBX_RSP_NOT_MODIFIED, /* 0x34 Not modified */
+ OBX_RSP_USE_PROXY, /* 0x35 Use Proxy */
+ OBX_RSP_BAD_REQUEST, /* 0x40 Bad Request - server couldn't understand request */
+ OBX_RSP_UNAUTHORIZED, /* 0x41 Unauthorized */
+ OBX_RSP_PAYMENT_REQD, /* 0x42 Payment required */
+ OBX_RSP_FORBIDDEN, /* 0x43 Forbidden - operation is understood but refused */
+ OBX_RSP_NOT_FOUND, /* 0x44 Not Found */
+ OBX_RSP_NOT_ALLOWED, /* 0x45 Method not allowed */
+ OBX_RSP_NOT_ACCEPTABLE, /* 0x46 Not Acceptable */
+ OBX_RSP_PROXY_AUTH_REQD, /* 0x47 Proxy Authentication required */
+ OBX_RSP_REQUEST_TIMEOUT, /* 0x48 Request Time Out */
+ OBX_RSP_CONFLICT, /* 0x49 Conflict */
+ OBX_RSP_GONE, /* 0x4A Gone */
+ OBX_RSP_LENGTH_REQD, /* 0x4B Length Required */
+ OBX_RSP_PRECONDTN_FAILED, /* 0x4C Precondition failed */
+ OBX_RSP_REQ_ENT_2_LARGE, /* 0x4D Requested entity too large */
+ OBX_RSP_REQ_URL_2_LARGE, /* 0x4E Request URL too large */
+ OBX_RSP_UNSUPTD_TYPE, /* 0x4F Unsupported media type */
+ OBX_RSP_INTRNL_SRVR_ERR, /* 0x50 Internal Server Error */
+ OBX_RSP_NOT_IMPLEMENTED, /* 0x51 Not Implemented */
+ OBX_RSP_BAD_GATEWAY, /* 0x52 Bad Gateway */
+ OBX_RSP_SERVICE_UNAVL, /* 0x53 Service Unavailable */
+ OBX_RSP_GATEWAY_TIMEOUT, /* 0x54 Gateway Timeout */
+ OBX_RSP_HTTP_VER_NOT_SUPTD, /* 0x55 HTTP version not supported */
+ OBX_RSP_DATABASE_FULL, /* 0x60 Database Full */
+ OBX_RSP_DATABASE_LOCKED, /* 0x61 Database Locked */
+ OBX_RSP_DEFAULT
+};
+
+static void obx_read_mtu(BT_HDR *p_pkt, tOBX_HANDLE handle, tOBX_CONN_EVT *p_evt);
+
+/*******************************************************************************
+** Function obx_read_srm
+** Description read the SRM and SRM_PARAM headers from the packet received from
+** peer and set the control block data member accordingly
+** Return UINT8
+*******************************************************************************/
+UINT8 obx_read_srm (tOBX_SRM *p_srm, BOOLEAN is_client, BT_HDR *p_pkt)
+{
+ UINT8 srm, srmp = 0, ret_srmp=0;
+ UINT8 old_srm = *p_srm;
+ BOOLEAN allowed = FALSE, clear = TRUE;
+
+ OBX_TRACE_DEBUG1("obx_read_srm srm:0x%x", *p_srm );
+ if (*p_srm)
+ {
+ /* if the SRM enable request is not granted in the next packet, the request is not valid any more
+ * clear the requesting flag */
+ *p_srm &= ~OBX_SRM_REQING;
+
+ if (OBX_Read1ByteHdr(p_pkt, OBX_HI_SRM, &srm))
+ {
+ if (srm == OBX_HV_SRM_ENABLE)
+ {
+ if (is_client)
+ {
+ if (old_srm & OBX_SRM_REQING)
+ {
+ *p_srm |= OBX_SRM_ENGAGE;
+ allowed = TRUE;
+ }
+ }
+ else /* is server */
+ {
+ *p_srm |= OBX_SRM_REQING;
+ allowed = TRUE;
+ }
+ }
+ OBX_TRACE_DEBUG3("SRM :0x%x srm:0x%x old_srm:0x%x", srm, *p_srm, old_srm );
+ }
+
+ if (!allowed)
+ allowed = old_srm & OBX_SRM_PARAM_AL;
+
+ if (OBX_Read1ByteHdr(p_pkt, OBX_HI_SRM_PARAM, &srmp))
+ {
+ if ((srmp == OBX_HV_SRM_PARAM_WAIT) && allowed)
+ {
+ ret_srmp = OBX_SRMP_WAIT;
+ *p_srm |= OBX_SRM_PARAM_AL;
+ clear = FALSE;
+ }
+ }
+ OBX_TRACE_DEBUG4("SRM_PARAM :0x%x srm:0x%x allowed:%d clear:%d", srmp, *p_srm, allowed, clear );
+
+ /* once the SRMP header is not used, it should be ignored for the rest of the transaction */
+ if (clear)
+ *p_srm &= ~OBX_SRM_PARAM_AL;
+ }
+
+ return ret_srmp;
+}
+
+/*******************************************************************************
+** Function obx_add_timeout
+** Description add the timeout triplet
+**
+** Return UINT8
+*******************************************************************************/
+UINT8 obx_add_timeout (tOBX_TRIPLET *p_trip, UINT32 timeout, tOBX_SESS_EVT *p_param)
+{
+ UINT8 *p;
+ UINT8 ret = 0;
+
+ if (timeout != OBX_INFINITE_TIMEOUT)
+ {
+ p_trip->tag = OBX_TAG_SESS_PARAM_TOUT;
+ p_trip->len = OBX_TIMEOUT_SIZE;
+ p = p_trip->p_array;
+ UINT32_TO_BE_STREAM(p, timeout);
+ ret = 1;
+ }
+ p_param->timeout = timeout;
+ return ret;
+}
+
+/*******************************************************************************
+** Function obx_read_timeout
+** Description add the timeout triplet
+**
+** Return void
+*******************************************************************************/
+void obx_read_timeout (tOBX_TRIPLET *p_trip, UINT8 num, UINT32 *p_timeout, UINT8 *p_toa)
+{
+ UINT8 ind;
+ UINT8 *p;
+ UINT32 tmp;
+
+ p = p_toa;
+ BE_STREAM_TO_UINT32(tmp, p);
+ OBX_TRACE_DEBUG2("obx_read_timeout %d/%d", *p_timeout, tmp);
+ if (*p_timeout == 0)
+ *p_timeout = tmp;
+ ind = obx_read_triplet(p_trip, num, OBX_TAG_SESS_PARAM_TOUT);
+ if ((ind != num) && (p_trip[ind].len == OBX_TIMEOUT_SIZE))
+ {
+ p = p_trip[ind].p_array;
+ BE_STREAM_TO_UINT32(tmp, p);
+ if (tmp < (*p_timeout))
+ {
+ (*p_timeout) = tmp;
+ OBX_TRACE_DEBUG1("new timeout %d", tmp);
+ }
+ }
+ UINT32_TO_BE_STREAM(p_toa, (*p_timeout));
+}
+
+#if (OBX_CLIENT_INCLUDED == TRUE)
+/*******************************************************************************
+** Function obx_verify_response
+** Description
+** Return OBX_BAD_SM_EVT, if bad.
+*******************************************************************************/
+UINT8 obx_verify_response(UINT8 opcode, tOBX_RX_HDR *p_rxh)
+{
+ UINT8 final = (opcode & OBX_FINAL) ? TRUE : FALSE;
+ int xx = 0;
+ UINT8 res_code = opcode & ~OBX_FINAL;
+
+ p_rxh->sm_evt = OBX_BAD_SM_EVT;
+
+ /* response packet must have the final bit set */
+ if (final == TRUE)
+ {
+ if (res_code == OBX_RSP_CONTINUE)
+ {
+ p_rxh->sm_evt = OBX_CONT_CFM_CEVT;
+ }
+ else
+ {
+ /* figure out the kind of response, Continue, OK, or Error */
+ while(obx_rsp_code[xx] != OBX_RSP_DEFAULT)
+ {
+ if (obx_rsp_code[xx] == res_code)
+ break;
+ xx++;
+ }
+
+ if (obx_rsp_code[xx] != OBX_RSP_DEFAULT)
+ {
+ if (obx_rsp_code[xx] <= OBX_MAX_OK_RSP)
+ p_rxh->sm_evt = OBX_OK_CFM_CEVT;
+ else
+ p_rxh->sm_evt = OBX_FAIL_CFM_CEVT;
+ }
+ /* else bad response code */
+ }
+ if (p_rxh->sm_evt != OBX_BAD_SM_EVT)
+ {
+ p_rxh->code = opcode;
+ }
+ }
+ /*
+ else final bit not set in response packet -> bad response code
+ */
+
+ return p_rxh->sm_evt;
+}
+
+/*******************************************************************************
+**
+** Function obx_cl_proc_pkt
+**
+** Description process a packet received from the connected server
+** verify that the response is valid
+** fill in event parameters
+** call csm to process the event
+**
+** Returns void
+**
+*******************************************************************************/
+void obx_cl_proc_pkt (tOBX_CL_CB *p_cb, BT_HDR *p_pkt)
+{
+ tOBX_RX_HDR *p_rxh;
+ UINT32 conn_id;
+ BOOLEAN pass = FALSE;
+ UINT8 xx;
+ tOBX_TRIPLET triplet[OBX_MAX_NUM_AUTH_TRIPLET];
+ UINT8 num_trip = OBX_MAX_NUM_AUTH_TRIPLET;
+ tOBX_CL_EVENT sm_evt;
+ UINT8 ssn;
+
+ OBX_TRACE_DEBUG3("obx_cl_proc_pkt 0x%x srm:0x%x, sess_st:%d", p_pkt, p_cb->srm, p_cb->sess_st);
+ OBX_TRACE_DEBUG1("csm offset:%d", p_cb->param.sess.obj_offset);
+
+ p_rxh = (tOBX_RX_HDR *)(p_pkt + 1);
+ p_cb->rsp_code = p_rxh->code & ~OBX_FINAL;
+
+ p_pkt->event = OBX_PUT_RSP_EVT; /* any response */
+ /* setup callback event param
+ memset(&p_cb->param, 0, sizeof(tOBX_EVT_PARAM)); */
+
+ if (p_cb->state == OBX_CS_CONNECT_REQ_SENT )
+ {
+ /* when a response packet is received in conn_rs state,
+ * it must be a connect response packet */
+ p_pkt->event = OBX_CONNECT_RSP_EVT;
+ p_cb->param.conn.handle = p_cb->ll_cb.port.handle;
+ obx_read_mtu(p_pkt, p_cb->ll_cb.port.handle, &(p_cb->param.conn));
+ p_cb->ll_cb.port.tx_mtu = p_cb->param.conn.mtu;
+
+ /* save Connection ID */
+ if (OBX_Read4ByteHdr(p_pkt, OBX_HI_CONN_ID, &conn_id) == TRUE)
+ p_cb->conn_id = conn_id;
+ OBX_TRACE_DEBUG1("Connection ID: 0x%x", p_cb->conn_id );
+ }
+
+ if (p_cb->sess_st == OBX_SESS_ACTIVE)
+ {
+ /* verify the session sequence number */
+ if (OBX_Read1ByteHdr (p_pkt, OBX_HI_SESSION_SN, &ssn))
+ {
+ OBX_TRACE_DEBUG1("ssn:%d", ssn);
+ p_cb->param.ssn = ssn;
+ }
+ }
+
+ sm_evt = p_rxh->sm_evt;
+
+ if (p_cb->wait_auth == TRUE)
+ {
+ /* this can only happen for CONNECT */
+ if (p_cb->rsp_code == OBX_RSP_OK)
+ {
+ /* successful according to server */
+ /* verify the digest */
+ p_cb->wait_auth = FALSE;
+ /* The coverity complaints on this function is not correct.
+ * The value in triplet[] is set/initialized by OBX_ReadTriplet if num_trip returns TRUE.
+ * leave this unnecessary memset here */
+ memset(triplet,0,sizeof(triplet));
+ if (OBX_ReadTriplet(p_pkt, OBX_HI_AUTH_RSP, triplet, &num_trip))
+ {
+ for (xx=0; xx<num_trip; xx++)
+ {
+ if (triplet[xx].tag == OBX_DIGEST_RSP_TAG)
+ {
+ if (memcmp (p_cb->p_auth, triplet[xx].p_array, OBX_DIGEST_SIZE) == 0)
+ pass = TRUE;
+ break;
+ }
+ }
+ }
+ if (pass == FALSE)
+ {
+ OBX_TRACE_ERROR0("Failed - server does not provide good digest" );
+ p_cb->wait_auth = OBX_WAIT_AUTH_FAIL;
+ p_cb->rsp_code = OBX_RSP_FAILED;
+ }
+ }
+ }
+ if (p_cb->p_auth)
+ GKI_freebuf(p_cb->p_auth);
+ p_cb->p_auth = NULL;
+
+ p_cb->srmp = obx_read_srm (&p_cb->srm, TRUE, p_pkt);
+ obx_csm_event(p_cb, sm_evt, p_pkt);
+}
+
+/*******************************************************************************
+**
+** Function obx_cl_prepend_msg
+**
+** Description This function is used by API functions to add the data in the
+** reserved space in the OBEX packet
+**
+** Returns void.
+**
+*******************************************************************************/
+BT_HDR * obx_cl_prepend_msg(tOBX_CL_CB *p_cb, BT_HDR *p_pkt, UINT8 * p_data, UINT16 data_len)
+{
+ UINT8 *p;
+ UINT16 len;
+
+ if (p_pkt == NULL)
+ {
+ p_pkt = OBX_HdrInit(OBX_HANDLE_NULL, OBX_MIN_MTU);
+ len = data_len;
+ }
+ else
+ {
+ len = p_pkt->len + data_len;
+ }
+
+ WC_ASSERT(p_pkt->offset >= data_len);
+ p = (UINT8 *)(p_pkt + 1) + p_pkt->offset - data_len;
+ memcpy(p, p_data, data_len);
+ p++;
+ /* adjust the packet len */
+ UINT16_TO_BE_STREAM(p, len);
+ p_pkt->len += data_len;
+ p_pkt->offset -= data_len;
+ p_pkt->layer_specific -= data_len;
+
+ return p_pkt;
+}
+#endif /* OBX_CLIENT_INCLUDED */
+
+#if (OBX_SERVER_INCLUDED == TRUE)
+/*******************************************************************************
+** Function obx_verify_request
+** Description
+** Return OBX_BAD_SM_EVT, if bad.
+*******************************************************************************/
+UINT8 obx_verify_request(UINT8 opcode, tOBX_RX_HDR *p_rxh)
+{
+ UINT8 final = (opcode & OBX_FINAL) ? TRUE : FALSE;
+ UINT8 req_code = opcode & ~OBX_FINAL;
+ p_rxh->sm_evt = OBX_BAD_SM_EVT;
+
+ OBX_TRACE_DEBUG2("obx_verify_request opcode 0x%x: final:%d", opcode, final);
+ switch (req_code)
+ {
+ case OBX_REQ_CONNECT:
+ /* this request must have the final bit set */
+ if (final == TRUE)
+ p_rxh->sm_evt = OBX_CONNECT_REQ_SEVT;
+ break;
+
+ case OBX_REQ_SESSION:
+ /* this request must have the final bit set */
+ if (final == TRUE)
+ p_rxh->sm_evt = OBX_SESSION_REQ_SEVT;
+ break;
+
+ case OBX_REQ_ACTION:
+ /* this request must have the final bit set */
+ if (final == TRUE)
+ p_rxh->sm_evt = OBX_ACTION_REQ_SEVT;
+ break;
+
+ case OBX_REQ_DISCONNECT:
+ /* this request must have the final bit set */
+ if (final == TRUE)
+ p_rxh->sm_evt = OBX_DISCNT_REQ_SEVT;
+ break;
+
+ case OBX_REQ_PUT:
+ p_rxh->sm_evt = OBX_PUT_REQ_SEVT;
+ break;
+
+ case OBX_REQ_GET:
+ p_rxh->sm_evt = OBX_GET_REQ_SEVT;
+ break;
+
+ case OBX_REQ_SETPATH:
+ /* this request must have the final bit set */
+ if (final == TRUE)
+ p_rxh->sm_evt = OBX_SETPATH_REQ_SEVT;
+ break;
+
+ case OBX_REQ_ABORT:
+ /* this request must have the final bit set */
+ if (final == TRUE)
+ p_rxh->sm_evt = OBX_ABORT_REQ_SEVT;
+ break;
+ }
+
+ if (p_rxh->sm_evt != OBX_BAD_SM_EVT)
+ {
+ p_rxh->code = opcode;
+ }
+ return p_rxh->sm_evt;
+}
+
+/*******************************************************************************
+**
+** Function obx_is_get_or_put_cont
+**
+** Returns TRUE, if it's a GET/PUT continuing continuing
+** TRUE, if it's an ABORT
+**
+*******************************************************************************/
+BOOLEAN obx_is_get_or_put_cont (tOBX_SR_SESS_CB *p_scb, UINT8 req_code)
+{
+ BOOLEAN is_cont = FALSE;
+
+ if (req_code == OBX_REQ_ABORT)
+ {
+ is_cont = TRUE;
+ }
+ else if (req_code == OBX_REQ_PUT)
+ {
+ if (p_scb->state == OBX_SS_PUT_TRANSACTION || p_scb->state == OBX_SS_PUT_SRM)
+ {
+ is_cont = TRUE;
+ }
+ }
+ else if (req_code == OBX_REQ_GET)
+ {
+ if (p_scb->state == OBX_SS_GET_TRANSACTION || p_scb->state == OBX_SS_GET_SRM)
+ {
+ is_cont = TRUE;
+ }
+ }
+
+ return is_cont;
+}
+
+/*******************************************************************************
+**
+** Function obx_sr_proc_pkt
+**
+** Description process a packet received from the connected client
+** verify that the request is valid
+** fill in event parameters
+** call ssm to process the event
+**
+** Returns TRUE, if abort
+**
+*******************************************************************************/
+BOOLEAN obx_sr_proc_pkt (tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt)
+{
+ tOBX_RX_HDR *p_rxh;
+ UINT8 *p_body;
+ UINT16 len;
+ BOOLEAN end;
+ UINT32 conn_id = 0;
+ UINT8 req_code;
+ BOOLEAN final;
+ UINT8 ssn, tmp_ssn;
+ UINT8 num_hdrs, num_body, num_ssn;
+ UINT8 rsp_code = OBX_RSP_OK;
+ UINT8 num_id;
+ BOOLEAN chk_add = FALSE;
+
+ p_rxh = (tOBX_RX_HDR *)(p_pkt + 1);
+ final = (p_rxh->code & OBX_FINAL) ? TRUE : FALSE;
+ req_code = p_rxh->code & ~OBX_FINAL;
+ p_scb->api_evt = (UINT8)p_pkt->event;
+ memset(&p_scb->param, 0, sizeof(tOBX_EVT_PARAM));
+ p_scb->param.get.final = final;
+
+ num_id = OBX_Read4ByteHdr (p_pkt, OBX_HI_CONN_ID, &conn_id);
+
+ OBX_TRACE_DEBUG6("obx_sr_proc_pkt 0x%x srm:0x%x sess_st:%d req_code:0x%x, sm_evt:%d ssn:%d",
+ p_pkt, p_scb->srm, p_scb->sess_st, req_code, p_rxh->sm_evt, p_scb->ssn);
+
+ num_ssn = OBX_Read1ByteHdr (p_pkt, OBX_HI_SESSION_SN, &ssn);
+ if (p_scb->srm & OBX_SRM_ABORT)
+ {
+ /* OBX_SRM_ABORT bit is set by server only when PUT req /w SRM is rejected before transaction actually ends
+ * this means we need to ignore follow packets until the next transaction starts */
+ if (req_code == OBX_REQ_PUT)
+ {
+ /* check if this is the put for the previous transaction */
+ num_hdrs = OBX_ReadNumHdrs(p_pkt, &num_body);
+ OBX_TRACE_DEBUG4("num_hdrs:%d num_body:%d num_id:%d num_ssn:%d", num_hdrs, num_body, num_id, num_ssn);
+ num_body += num_ssn;
+ num_body += num_id;
+ if (num_hdrs <= num_body)
+ {
+ p_scb->ssn = ssn+1;
+ /* it is left-over, drop it. */
+ if (p_pkt)
+ GKI_freebuf (p_pkt);
+ p_scb->api_evt = OBX_NULL_EVT;
+ return TRUE;
+ }
+ }
+ /* clear the SRM bits; leave only the enabled bit */
+ p_scb->srm &= OBX_SRM_ENABLE;
+ }
+
+ if ((p_scb->sess_st == OBX_SESS_ACTIVE) && (req_code != OBX_REQ_SESSION) && (req_code != OBX_REQ_ABORT))
+ {
+ rsp_code = OBX_RSP_BAD_REQUEST;
+ /* verify the session sequence number */
+ if (num_ssn)
+ {
+ OBX_TRACE_DEBUG2("ssn pkt/cb=%d/%d", ssn, p_scb->ssn);
+ if (ssn == p_scb->ssn)
+ {
+ p_scb->param.ssn = p_scb->ssn;
+ rsp_code = OBX_RSP_OK;
+ }
+ else if (p_scb->srmp & OBX_SRMP_SESS_FST)
+ {
+ tmp_ssn = ssn+1;
+ if (tmp_ssn == p_scb->ssn)
+ {
+ p_scb->param.ssn = ssn;
+ p_scb->ssn = ssn;
+ rsp_code = OBX_RSP_OK;
+ }
+ }
+ }
+ p_scb->srmp &= ~OBX_SRMP_SESS_FST;
+ }
+
+ /* fill event parameter */
+ if (req_code == OBX_REQ_CONNECT)
+ {
+ p_scb->param.conn.handle = p_scb->handle;
+ obx_read_mtu(p_pkt, p_scb->ll_cb.comm.handle, &(p_scb->param.conn));
+
+ p_scb->ll_cb.port.tx_mtu = p_scb->param.conn.mtu;
+ /* verify the target header and connection ID
+ * in obx_sa_connect_ind() for OBX_SS_NOT_CONNECTED */
+ /* verify the connection ID in obx_sa_auth_ind() for OBX_SS_WAIT_AUTH */
+ chk_add = TRUE;
+ }
+ else if (req_code == OBX_REQ_SESSION)
+ {
+ /* do nothing */
+ if (conn_id != 0)
+ {
+ OBX_TRACE_ERROR1("Session command should not use Connection ID: 0x%x", conn_id);
+ p_rxh->sm_evt = OBX_BAD_REQ_SEVT;
+ }
+ }
+ else
+ {
+ OBX_TRACE_DEBUG3("Connection ID: 0x%x/0x%x state:%d", p_scb->conn_id, conn_id, p_scb->state );
+ /* verify the connection ID */
+ if ( (conn_id == p_scb->conn_id) ||
+ (conn_id == 0 && p_scb->conn_id != 0 && obx_is_get_or_put_cont(p_scb, req_code)))
+ {
+ /* match: both non-exist or both exist and equal */
+ /* connection ID header does not exist, but control block uses connection ID,
+ * if this is continuation packets for PUT and GET, it's OK */
+ if (req_code == OBX_REQ_PUT)
+ {
+ p_scb->param.put.final = final;
+
+ /* determine the PUT type */
+ p_scb->param.put.type = OBX_PT_PUT;
+ if (p_scb->state == OBX_SS_CONNECTED && final == TRUE)
+ {
+ if (OBX_ReadBodyHdr(p_pkt, &p_body, &len, &end) == FALSE)
+ {
+ /* final is set, no BODY or End-of-Body
+ * -> Delete request */
+ p_scb->param.put.type = OBX_PT_DELETE;
+ }
+ else if (end == TRUE && len == 0)
+ {
+ /* an empty End-of-Body header
+ * -> Create-Empty request */
+ p_scb->param.put.type = OBX_PT_CREATE;
+ }
+ }
+ OBX_TRACE_EVENT1("Put request type: %d", p_scb->param.put.type);
+ }
+ else if (req_code == OBX_REQ_SETPATH)
+ {
+ p_scb->param.sp.flag = *((UINT8 *)(p_pkt + 1) + p_pkt->offset + OBX_SETPATH_FLAG_OFFSET);
+ }
+ }
+ else
+ {
+ /* does not have good connection ID */
+ p_rxh->sm_evt = OBX_BAD_REQ_SEVT;
+ p_scb->api_evt = OBX_NULL_EVT;
+ }
+ }
+
+ /* process the SRM header */
+ p_scb->srmp |= obx_read_srm (&p_scb->srm, FALSE, p_pkt);
+
+ if (p_rxh->sm_evt != OBX_BAD_REQ_SEVT && req_code != OBX_REQ_ABORT)
+ {
+ p_scb->cur_op = req_code;
+ if (final)
+ p_scb->cur_op |= OBX_FINAL;
+ }
+
+ if (rsp_code != OBX_RSP_OK)
+ {
+ p_rxh->sm_evt = OBX_BAD_REQ_SEVT;
+ }
+
+ OBX_TRACE_DEBUG2("rsp_code:0x%x, sm_evt:%d", rsp_code, p_rxh->sm_evt);
+
+ obx_ssm_event(p_scb, p_rxh->sm_evt, p_pkt);
+ if (chk_add)
+ {
+ if (p_scb->ll_cb.comm.p_send_fn == (tOBX_SEND_FN *)obx_rfc_snd_msg)
+ obx_add_port(p_scb->handle);
+ }
+ return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function obx_sr_prepend_msg
+**
+** Description This function is used by API functions to add the data in the
+** reserved space in the OBEX packet
+**
+** Returns void.
+**
+*******************************************************************************/
+BT_HDR * obx_sr_prepend_msg(BT_HDR *p_pkt, UINT8 * p_data, UINT16 data_len)
+{
+ UINT8 *p;
+ UINT16 len;
+
+ if (p_pkt == NULL)
+ {
+ p_pkt = OBX_HdrInit(OBX_HANDLE_NULL, OBX_MIN_MTU);
+ len = data_len;
+ }
+ else
+ {
+ len = p_pkt->len + data_len;
+ }
+
+ WC_ASSERT(p_pkt->offset >= data_len);
+ p = (UINT8 *)(p_pkt + 1) + p_pkt->offset - data_len;
+ memcpy(p, p_data, data_len);
+ p++;
+ /* adjust the packet len */
+ UINT16_TO_BE_STREAM(p, len);
+ p_pkt->len += data_len;
+ p_pkt->offset -= data_len;
+ p_pkt->layer_specific -= data_len;
+
+ return p_pkt;
+}
+#endif /* OBX_SERVER_INCLUDED */
+
+/*******************************************************************************
+**
+** Function obx_read_mtu
+**
+** Description This function is used to access the MTU in CONNECT packets
+**
+** Returns void.
+**
+*******************************************************************************/
+void obx_read_mtu(BT_HDR *p_pkt, tOBX_HANDLE handle, tOBX_CONN_EVT *p_evt)
+{
+ UINT8 *p = (UINT8 *)(p_pkt + 1) + p_pkt->offset + OBX_CONNECT_MTU_OFFSET;
+
+ BE_STREAM_TO_UINT16(p_evt->mtu, p);
+ if (p_evt->mtu > OBX_MAX_MTU)
+ p_evt->mtu = OBX_MAX_MTU;
+ if (p_evt->mtu == 0)
+ p_evt->mtu = OBX_MIN_MTU;
+
+ /* Get the Bd_Addr */
+ OBX_GetPeerAddr (handle, p_evt->peer_addr);
+}
+
+/*******************************************************************************
+**
+** Function obx_free_buf
+**
+** Description This function is used to free the GKI buffers of the given
+** lower layer control block
+**
+** Returns void.
+**
+*******************************************************************************/
+void obx_free_buf(tOBX_LL_CB *p_ll_cb)
+{
+ void *p_pkt;
+
+
+ if (p_ll_cb->comm.p_send_fn == (tOBX_SEND_FN *)obx_rfc_snd_msg)
+ {
+ if (p_ll_cb->port.p_rxmsg)
+ {
+ OBX_TRACE_WARNING0("obx_free_buf release p_rxmsg");
+ GKI_freebuf(p_ll_cb->port.p_rxmsg);
+ p_ll_cb->port.p_rxmsg = 0;
+ }
+ }
+
+ if (!GKI_queue_is_empty(&p_ll_cb->comm.rx_q))
+ {
+ while((p_pkt = GKI_dequeue (&p_ll_cb->comm.rx_q)) != NULL)
+ {
+ OBX_TRACE_WARNING0("obx_free_buf release rx_q");
+ GKI_freebuf(p_pkt);
+ }
+ }
+
+ if (p_ll_cb->comm.p_txmsg)
+ {
+ OBX_TRACE_WARNING0("obx_free_buf release p_txmsg");
+ GKI_freebuf(p_ll_cb->comm.p_txmsg);
+ p_ll_cb->comm.p_txmsg = 0;
+ }
+}
+
+/*******************************************************************************
+**
+** Function obx_flow_control
+**
+** Description If we had flowed control the peer, enable the data path now
+**
+** Returns void.
+**
+*******************************************************************************/
+void obx_flow_control(tOBX_COMM_CB *p_comm)
+{
+ OBX_TRACE_DEBUG1 ("obx_flow_control stopped:%d", p_comm->stopped );
+ if (p_comm->stopped)
+ {
+ if (p_comm->p_send_fn == (tOBX_SEND_FN *)obx_rfc_snd_msg)
+ {
+ PORT_FlowControl(p_comm->id, TRUE);
+ }
+ else
+ {
+ L2CA_FlowControl(p_comm->id, TRUE);
+ }
+ p_comm->stopped = FALSE;
+ }
+}
+
+/*****************************************************************************
+* Function: obx_read_triplet
+* Purpose: Read the application parameters with the given tag
+*****************************************************************************/
+UINT8 obx_read_triplet(tOBX_TRIPLET *p_trip, UINT8 num_trip, UINT8 tag)
+{
+ UINT8 xx = 0;
+
+ for (xx=0; xx<num_trip; xx++, p_trip++)
+ {
+ if (p_trip->tag == tag)
+ {
+ break;
+ }
+ }
+
+ return xx;
+}
+/*****************************************************************************
+* Function: obx_read_obj_offset
+* Purpose: Read the application parameters with the object offset tag
+*****************************************************************************/
+UINT32 obx_read_obj_offset(tOBX_TRIPLET *p_trip, UINT8 num_trip)
+{
+ UINT32 obj_offset = 0;
+ UINT8 ind;
+ UINT8 *p = NULL, *pe;
+ UINT8 extra = 0, xx;
+
+ ind = obx_read_triplet(p_trip, num_trip, OBX_TAG_SESS_PARAM_OBJ_OFF);
+ if (ind != num_trip)
+ {
+ if (p_trip[ind].len == 4)
+ {
+ p = p_trip[ind].p_array;
+ }
+ else if (p_trip[ind].len > 4)
+ {
+ extra = p_trip[ind].len - 4;
+ }
+
+ if (extra)
+ {
+ /* the TLV is bigger than 4 bytes
+ * if the MSBs are all 0, we can still handle it with UINT32 */
+ pe = p_trip[ind].p_array;
+ for (xx=0; xx<extra; xx++)
+ {
+ if (*pe == 0)
+ pe++;
+ else
+ break;
+ }
+ if (xx == extra)
+ p = pe;
+ }
+
+ if (p)
+ BE_STREAM_TO_UINT32(obj_offset, p);
+ }
+
+ return obj_offset;
+}
+
+/*******************************************************************************
+**
+** Function obxu_dump_hex
+**
+** Description This function dumps hex data
+**
+*/
+#if (BT_USE_TRACES == TRUE)
+void obxu_dump_hex (UINT8 *p, char *p_title, UINT16 len)
+{
+ UINT16 xx, yy;
+ char buff1[100], buff2[20];
+
+ if (p_title)
+ OBX_TRACE_DEBUG1 ("%s:", p_title);
+
+ memset (buff2, ' ', 16);
+ buff2[16] = 0;
+
+ yy = sprintf (buff1, "%04x: ", 0);
+ for (xx = 0; xx < len; xx++)
+ {
+ if ( (xx) && ((xx & 15) == 0) )
+ {
+ OBX_TRACE_DEBUG2 (" %s %s", buff1, buff2);
+ yy = sprintf(buff1, "%04x: ", xx);
+ memset (buff2, ' ', 16);
+ }
+ yy += sprintf (&buff1[yy], "%02x ", *p);
+
+ if ((*p >= ' ') && (*p <= 'z'))
+ buff2[xx & 15] = *p;
+ else
+ buff2[xx & 15] = '.';
+
+ p++;
+ }
+
+ /* Pad out the remainder */
+ for ( ; ; xx++)
+ {
+ if ((xx & 15) == 0)
+ {
+ OBX_TRACE_DEBUG2 (" %s %s", buff1, buff2);
+ break;
+ }
+ yy += sprintf (&buff1[yy], " ");
+ }
+
+}
+#endif
+
+/*******************************************************************************
+**
+** Function OBX_GetPeerAddr
+**
+** Description This function is called to learn the Bluetooth address of the
+** connected device.
+**
+** Returns L2CAP channel ID.
+**
+*******************************************************************************/
+UINT16 OBX_GetPeerAddr(tOBX_HANDLE shandle, BD_ADDR bd_addr)
+{
+ UINT16 lcid = 0;
+#if (OBX_SERVER_INCLUDED == TRUE)
+ tOBX_SR_SESS_CB *p_scb;
+#endif
+#if (OBX_CLIENT_INCLUDED == TRUE)
+ tOBX_CL_CB *p_cb;
+
+ if (shandle & OBX_CL_HANDLE_MASK)
+ {
+ p_cb = obx_cl_get_cb(shandle);
+ if (p_cb)
+ {
+ if (p_cb->ll_cb.comm.p_send_fn == (tOBX_SEND_FN *)obx_rfc_snd_msg)
+ {
+ PORT_CheckConnection(p_cb->ll_cb.port.port_handle, p_cb->peer_addr, &lcid);
+ memcpy (bd_addr, p_cb->peer_addr, BD_ADDR_LEN);
+ lcid = p_cb->ll_cb.comm.id;
+ }
+ else if (p_cb->ll_cb.comm.id)
+ {
+ /* GetPeerAddr for l2c */
+ memcpy (bd_addr, p_cb->peer_addr, BD_ADDR_LEN);
+ lcid = p_cb->ll_cb.comm.id;
+ }
+ }
+ }
+#endif
+
+#if (OBX_SERVER_INCLUDED == TRUE)
+ if ((shandle & OBX_CL_HANDLE_MASK) == 0)
+ {
+ p_scb = obx_sr_get_scb(shandle);
+ if (p_scb)
+ {
+ if (p_scb->ll_cb.comm.p_send_fn == (tOBX_SEND_FN *)obx_rfc_snd_msg)
+ {
+ PORT_CheckConnection(p_scb->ll_cb.port.port_handle, bd_addr, &lcid);
+ }
+ else if (p_scb->ll_cb.comm.id)
+ {
+ /* GetPeerAddr for l2c */
+ memcpy (bd_addr, p_scb->peer_addr, BD_ADDR_LEN);
+ lcid = p_scb->ll_cb.comm.id;
+ }
+ }
+ }
+#endif
+
+ return lcid;
+}
diff --git a/stack/pan/pan_api.c b/stack/pan/pan_api.c
new file mode 100644
index 0000000..3cc6dec
--- /dev/null
+++ b/stack/pan/pan_api.c
@@ -0,0 +1,840 @@
+/****************************************************************************/
+/* */
+/* Name: pan_api.c */
+/* */
+/* Function: this file contains main functions to support PAN profile */
+/* commands and events. */
+/* */
+/* Copyright (c) 1999-2011, Broadcom Corp., All Rights Reserved. */
+/* Broadcom Bluetooth Core. Proprietary and confidential. */
+/* */
+/****************************************************************************/
+
+#include <string.h>
+#include "gki.h"
+#include "bt_types.h"
+#include "bnep_api.h"
+#include "pan_api.h"
+#include "pan_int.h"
+#include "sdp_api.h"
+#include "sdpdefs.h"
+#include "l2c_api.h"
+#include "hcidefs.h"
+#include "btm_api.h"
+
+
+/*******************************************************************************
+**
+** Function PAN_Register
+**
+** Description This function is called by the application to register
+** its callbacks with PAN profile. The application then
+** should set the PAN role explicitly.
+**
+** Parameters: p_register - contains all callback function pointers
+**
+**
+** Returns none
+**
+*******************************************************************************/
+void PAN_Register (tPAN_REGISTER *p_register)
+{
+ BTM_SetDiscoverability (BTM_GENERAL_DISCOVERABLE, 0, 0);
+ BTM_SetConnectability (BTM_CONNECTABLE, 0, 0);
+
+ pan_register_with_bnep ();
+
+ if (!p_register)
+ return;
+
+ pan_cb.pan_conn_state_cb = p_register->pan_conn_state_cb;
+ pan_cb.pan_bridge_req_cb = p_register->pan_bridge_req_cb;
+ pan_cb.pan_data_buf_ind_cb = p_register->pan_data_buf_ind_cb;
+ pan_cb.pan_data_ind_cb = p_register->pan_data_ind_cb;
+ pan_cb.pan_pfilt_ind_cb = p_register->pan_pfilt_ind_cb;
+ pan_cb.pan_mfilt_ind_cb = p_register->pan_mfilt_ind_cb;
+ pan_cb.pan_tx_data_flow_cb = p_register->pan_tx_data_flow_cb;
+
+ return;
+}
+
+
+
+/*******************************************************************************
+**
+** Function PAN_Deregister
+**
+** Description This function is called by the application to de-register
+** its callbacks with PAN profile. This will make the PAN to
+** become inactive. This will deregister PAN services from SDP
+** and close all active connections
+**
+** Parameters: none
+**
+**
+** Returns none
+**
+*******************************************************************************/
+void PAN_Deregister (void)
+{
+ pan_cb.pan_bridge_req_cb = NULL;
+ pan_cb.pan_data_buf_ind_cb = NULL;
+ pan_cb.pan_data_ind_cb = NULL;
+ pan_cb.pan_conn_state_cb = NULL;
+ pan_cb.pan_pfilt_ind_cb = NULL;
+ pan_cb.pan_mfilt_ind_cb = NULL;
+
+ PAN_SetRole (PAN_ROLE_INACTIVE, NULL, NULL, NULL, NULL);
+ BNEP_Deregister ();
+
+ return;
+}
+
+
+
+
+/*******************************************************************************
+**
+** Function PAN_SetRole
+**
+** Description This function is called by the application to set the PAN
+** profile role. This should be called after PAN_Register.
+** This can be called any time to change the PAN role
+**
+** Parameters: role - is bit map of roles to be active
+** PAN_ROLE_CLIENT is for PANU role
+** PAN_ROLE_GN_SERVER is for GN role
+** PAN_ROLE_NAP_SERVER is for NAP role
+** sec_mask - Security mask for different roles
+** It is array of UINT8. The byte represent the
+** security for roles PANU, GN and NAP in order
+** p_user_name - Service name for PANU role
+** p_gn_name - Service name for GN role
+** p_nap_name - Service name for NAP role
+** Can be NULL if user wants it to be default
+**
+** Returns PAN_SUCCESS - if the role is set successfully
+** PAN_FAILURE - if the role is not valid
+**
+*******************************************************************************/
+tPAN_RESULT PAN_SetRole (UINT8 role,
+ UINT8 *sec_mask,
+ char *p_user_name,
+ char *p_gn_name,
+ char *p_nap_name)
+{
+ char *p_desc;
+ UINT8 security[3] = {PAN_PANU_SECURITY_LEVEL,
+ PAN_GN_SECURITY_LEVEL,
+ PAN_NAP_SECURITY_LEVEL};
+ UINT8 *p_sec;
+
+ /* If the role is not a valid combination reject it */
+ if ((!(role & (PAN_ROLE_CLIENT | PAN_ROLE_GN_SERVER | PAN_ROLE_NAP_SERVER))) &&
+ role != PAN_ROLE_INACTIVE)
+ {
+ PAN_TRACE_ERROR1 ("PAN role %d is invalid", role);
+ return PAN_FAILURE;
+ }
+
+ /* If the current active role is same as the role being set do nothing */
+ if (pan_cb.role == role)
+ {
+ PAN_TRACE_EVENT1 ("PAN role already was set to: %d", role);
+ return PAN_SUCCESS;
+ }
+
+ if (!sec_mask)
+ p_sec = security;
+ else
+ p_sec = sec_mask;
+
+ /* Register all the roles with SDP */
+ PAN_TRACE_API1 ("PAN_SetRole() called with role 0x%x", role);
+#if (defined (PAN_SUPPORTS_ROLE_NAP) && PAN_SUPPORTS_ROLE_NAP == TRUE)
+ /* Check the service name */
+ if ((p_nap_name == NULL) || (*p_nap_name == 0))
+ p_nap_name = PAN_NAP_DEFAULT_SERVICE_NAME;
+
+ if (role & PAN_ROLE_NAP_SERVER)
+ {
+ /* Registering for NAP service with SDP */
+ p_desc = PAN_NAP_DEFAULT_DESCRIPTION;
+
+ if (pan_cb.pan_nap_sdp_handle != 0)
+ SDP_DeleteRecord (pan_cb.pan_nap_sdp_handle);
+
+ pan_cb.pan_nap_sdp_handle = pan_register_with_sdp (UUID_SERVCLASS_NAP, p_sec[2], p_nap_name, p_desc);
+// btla-specific ++
+ bta_sys_add_uuid(UUID_SERVCLASS_NAP);
+// btla-specific --
+ }
+ /* If the NAP role is already active and now being cleared delete the record */
+ else if (pan_cb.role & PAN_ROLE_NAP_SERVER)
+ {
+ if (pan_cb.pan_nap_sdp_handle != 0)
+ {
+ SDP_DeleteRecord (pan_cb.pan_nap_sdp_handle);
+ pan_cb.pan_nap_sdp_handle = 0;
+// btla-specific ++
+ bta_sys_remove_uuid(UUID_SERVCLASS_NAP);
+// btla-specific --
+ }
+ }
+#endif
+
+#if (defined (PAN_SUPPORTS_ROLE_GN) && PAN_SUPPORTS_ROLE_GN == TRUE)
+ /* Check the service name */
+ if ((p_gn_name == NULL) || (*p_gn_name == 0))
+ p_gn_name = PAN_GN_DEFAULT_SERVICE_NAME;
+
+ if (role & PAN_ROLE_GN_SERVER)
+ {
+ /* Registering for GN service with SDP */
+ p_desc = PAN_GN_DEFAULT_DESCRIPTION;
+
+ if (pan_cb.pan_gn_sdp_handle != 0)
+ SDP_DeleteRecord (pan_cb.pan_gn_sdp_handle);
+
+ pan_cb.pan_gn_sdp_handle = pan_register_with_sdp (UUID_SERVCLASS_GN, p_sec[1], p_gn_name, p_desc);
+// btla-specific ++
+ bta_sys_add_uuid(UUID_SERVCLASS_GN);
+// btla-specific --
+ }
+ /* If the GN role is already active and now being cleared delete the record */
+ else if (pan_cb.role & PAN_ROLE_GN_SERVER)
+ {
+ if (pan_cb.pan_gn_sdp_handle != 0)
+ {
+ SDP_DeleteRecord (pan_cb.pan_gn_sdp_handle);
+ pan_cb.pan_gn_sdp_handle = 0;
+// btla-specific ++
+ bta_sys_remove_uuid(UUID_SERVCLASS_GN);
+// btla-specific --
+ }
+ }
+#endif
+
+#if (defined (PAN_SUPPORTS_ROLE_PANU) && PAN_SUPPORTS_ROLE_PANU == TRUE)
+ /* Check the service name */
+ if ((p_user_name == NULL) || (*p_user_name == 0))
+ p_user_name = PAN_PANU_DEFAULT_SERVICE_NAME;
+
+ if (role & PAN_ROLE_CLIENT)
+ {
+ /* Registering for PANU service with SDP */
+ p_desc = PAN_PANU_DEFAULT_DESCRIPTION;
+ if (pan_cb.pan_user_sdp_handle != 0)
+ SDP_DeleteRecord (pan_cb.pan_user_sdp_handle);
+
+ pan_cb.pan_user_sdp_handle = pan_register_with_sdp (UUID_SERVCLASS_PANU, p_sec[0], p_user_name, p_desc);
+// btla-specific ++
+ bta_sys_add_uuid(UUID_SERVCLASS_PANU);
+// btla-specific --
+ }
+ /* If the PANU role is already active and now being cleared delete the record */
+ else if (pan_cb.role & PAN_ROLE_CLIENT)
+ {
+ if (pan_cb.pan_user_sdp_handle != 0)
+ {
+ SDP_DeleteRecord (pan_cb.pan_user_sdp_handle);
+ pan_cb.pan_user_sdp_handle = 0;
+// btla-specific ++
+ bta_sys_remove_uuid(UUID_SERVCLASS_PANU);
+// btla-specific --
+ }
+ }
+#endif
+
+ /* Check if it is a shutdown request */
+ if (role == PAN_ROLE_INACTIVE)
+ pan_close_all_connections ();
+
+ pan_cb.role = role;
+ PAN_TRACE_EVENT1 ("PAN role set to: %d", role);
+ return PAN_SUCCESS;
+}
+
+
+
+/*******************************************************************************
+**
+** Function PAN_Connect
+**
+** Description This function is called by the application to initiate a
+** connection to the remote device
+**
+** Parameters: rem_bda - BD Addr of the remote device
+** src_role - Role of the local device for the connection
+** dst_role - Role of the remote device for the connection
+** PAN_ROLE_CLIENT is for PANU role
+** PAN_ROLE_GN_SERVER is for GN role
+** PAN_ROLE_NAP_SERVER is for NAP role
+** *handle - Pointer for returning Handle to the connection
+**
+** Returns PAN_SUCCESS - if the connection is initiated successfully
+** PAN_NO_RESOURCES - resources are not sufficent
+** PAN_FAILURE - if the connection cannot be initiated
+** this can be because of the combination of
+** src and dst roles may not be valid or
+** allowed at that point of time
+**
+*******************************************************************************/
+tPAN_RESULT PAN_Connect (BD_ADDR rem_bda, UINT8 src_role, UINT8 dst_role, UINT16 *handle)
+{
+ tPAN_CONN *pcb;
+ tBNEP_RESULT result;
+ tBT_UUID src_uuid, dst_uuid;
+ UINT8 service_id;
+ UINT32 mx_chan_id;
+
+ /*
+ ** Initialize the handle so that in case of failure return values
+ ** the profile will not get confused
+ */
+ *handle = BNEP_INVALID_HANDLE;
+
+ /* Check if PAN is active or not */
+ if (!(pan_cb.role & src_role))
+ {
+ PAN_TRACE_ERROR1 ("PAN is not active for the role %d", src_role);
+ return PAN_FAILURE;
+ }
+
+ /* Validate the parameters before proceeding */
+ if ((src_role != PAN_ROLE_CLIENT && src_role != PAN_ROLE_GN_SERVER && src_role != PAN_ROLE_NAP_SERVER) ||
+ (dst_role != PAN_ROLE_CLIENT && dst_role != PAN_ROLE_GN_SERVER && dst_role != PAN_ROLE_NAP_SERVER))
+ {
+ PAN_TRACE_ERROR2 ("Either source %d or destination role %d is invalid", src_role, dst_role);
+ return PAN_FAILURE;
+ }
+
+ /* Check if connection exists for this remote device */
+ pcb = pan_get_pcb_by_addr (rem_bda);
+
+ /* If we are PANU for this role validate destination role */
+ if (src_role == PAN_ROLE_CLIENT)
+ {
+ if ((pan_cb.num_conns > 1) || (pan_cb.num_conns && (!pcb)))
+ {
+ /*
+ ** If the request is not for existing connection reject it
+ ** because if there is already a connection we cannot accept
+ ** another connection in PANU role
+ */
+ PAN_TRACE_ERROR0 ("Cannot make PANU connections when there are more than one connection");
+ return PAN_INVALID_SRC_ROLE;
+ }
+
+ src_uuid.uu.uuid16 = UUID_SERVCLASS_PANU;
+ if (dst_role == PAN_ROLE_CLIENT)
+ {
+ service_id = BTM_SEC_SERVICE_BNEP_PANU;
+ dst_uuid.uu.uuid16 = UUID_SERVCLASS_PANU;
+ }
+ else if (dst_role == PAN_ROLE_GN_SERVER)
+ {
+ service_id = BTM_SEC_SERVICE_BNEP_GN;
+ dst_uuid.uu.uuid16 = UUID_SERVCLASS_GN;
+ }
+ else
+ {
+ service_id = BTM_SEC_SERVICE_BNEP_NAP;
+ dst_uuid.uu.uuid16 = UUID_SERVCLASS_NAP;
+ }
+ mx_chan_id = dst_uuid.uu.uuid16;
+ }
+ /* If destination is PANU role validate source role */
+ else if (dst_role == PAN_ROLE_CLIENT)
+ {
+ if (pan_cb.num_conns && pan_cb.active_role == PAN_ROLE_CLIENT && !pcb)
+ {
+ PAN_TRACE_ERROR0 ("Device already have a connection in PANU role");
+ return PAN_INVALID_SRC_ROLE;
+ }
+
+ dst_uuid.uu.uuid16 = UUID_SERVCLASS_PANU;
+ if (src_role == PAN_ROLE_GN_SERVER)
+ {
+ service_id = BTM_SEC_SERVICE_BNEP_GN;
+ src_uuid.uu.uuid16 = UUID_SERVCLASS_GN;
+ }
+ else
+ {
+ service_id = BTM_SEC_SERVICE_BNEP_NAP;
+ src_uuid.uu.uuid16 = UUID_SERVCLASS_NAP;
+ }
+ mx_chan_id = src_uuid.uu.uuid16;
+ }
+ /* The role combination is not valid */
+ else
+ {
+ PAN_TRACE_ERROR2 ("Source %d and Destination roles %d are not valid combination",
+ src_role, dst_role);
+ return PAN_FAILURE;
+ }
+
+ /* Allocate control block and initiate connection */
+ if (!pcb)
+ pcb = pan_allocate_pcb (rem_bda, BNEP_INVALID_HANDLE);
+ if (!pcb)
+ {
+ PAN_TRACE_ERROR0 ("PAN Connection failed because of no resources");
+ return PAN_NO_RESOURCES;
+ }
+ BTM_SetOutService(rem_bda, BTM_SEC_SERVICE_BNEP_PANU, mx_chan_id);
+
+ PAN_TRACE_API6 ("PAN_Connect() for BD Addr %x.%x.%x.%x.%x.%x",
+ rem_bda[0], rem_bda[1], rem_bda[2], rem_bda[3], rem_bda[4], rem_bda[5]);
+ if (pcb->con_state == PAN_STATE_IDLE)
+ {
+ pan_cb.num_conns++;
+ }
+ else if (pcb->con_state == PAN_STATE_CONNECTED)
+ {
+ pcb->con_flags |= PAN_FLAGS_CONN_COMPLETED;
+ }
+ else
+ /* PAN connection is still in progress */
+ return PAN_WRONG_STATE;
+
+ pcb->con_state = PAN_STATE_CONN_START;
+ pcb->prv_src_uuid = pcb->src_uuid;
+ pcb->prv_dst_uuid = pcb->dst_uuid;
+
+ pcb->src_uuid = src_uuid.uu.uuid16;
+ pcb->dst_uuid = dst_uuid.uu.uuid16;
+
+ src_uuid.len = 2;
+ dst_uuid.len = 2;
+
+ result = BNEP_Connect (rem_bda, &src_uuid, &dst_uuid, &(pcb->handle));
+ if (result != BNEP_SUCCESS)
+ {
+ pan_release_pcb (pcb);
+ return result;
+ }
+
+ PAN_TRACE_DEBUG1 ("PAN_Connect() current active role set to %d", src_role);
+ pan_cb.prv_active_role = pan_cb.active_role;
+ pan_cb.active_role = src_role;
+ *handle = pcb->handle;
+ return PAN_SUCCESS;
+}
+
+
+
+
+/*******************************************************************************
+**
+** Function PAN_Disconnect
+**
+** Description This is used to disconnect the connection
+**
+** Parameters: handle - handle for the connection
+**
+** Returns PAN_SUCCESS - if the connection is closed successfully
+** PAN_FAILURE - if the connection is not found or
+** there is an error in disconnecting
+**
+*******************************************************************************/
+tPAN_RESULT PAN_Disconnect (UINT16 handle)
+{
+ tPAN_CONN *pcb;
+ tBNEP_RESULT result;
+
+ /* Check if the connection exists */
+ pcb = pan_get_pcb_by_handle (handle);
+ if(!pcb)
+ {
+ PAN_TRACE_ERROR1 ("PAN connection not found for the handle %d", handle);
+ return PAN_FAILURE;
+ }
+
+ result = BNEP_Disconnect (pcb->handle);
+ if (pcb->con_state == PAN_STATE_CONNECTED)
+ pan_cb.num_conns--;
+
+ if (pan_cb.pan_bridge_req_cb && pcb->src_uuid == UUID_SERVCLASS_NAP)
+ (*pan_cb.pan_bridge_req_cb) (pcb->rem_bda, FALSE);
+
+ pan_release_pcb (pcb);
+
+ if (result != BNEP_SUCCESS)
+ {
+ PAN_TRACE_EVENT0 ("Error in closing PAN connection");
+ return PAN_FAILURE;
+ }
+
+ PAN_TRACE_EVENT0 ("PAN connection closed");
+ return PAN_SUCCESS;
+}
+
+
+/*******************************************************************************
+**
+** Function PAN_Write
+**
+** Description This sends data over the PAN connections. If this is called
+** on GN or NAP side and the packet is multicast or broadcast
+** it will be sent on all the links. Otherwise the correct link
+** is found based on the destination address and forwarded on it
+** If the return value is not PAN_SUCCESS the application should
+** take care of releasing the message buffer
+**
+** Parameters: handle - handle for the connection
+** dst - MAC or BD Addr of the destination device
+** src - MAC or BD Addr of the source who sent this packet
+** protocol - protocol of the ethernet packet like IP or ARP
+** p_data - pointer to the data
+** len - length of the data
+** ext - to indicate that extension headers present
+**
+** Returns PAN_SUCCESS - if the data is sent successfully
+** PAN_FAILURE - if the connection is not found or
+** there is an error in sending data
+**
+*******************************************************************************/
+tPAN_RESULT PAN_Write (UINT16 handle, BD_ADDR dst, BD_ADDR src, UINT16 protocol, UINT8 *p_data, UINT16 len, BOOLEAN ext)
+{
+ tPAN_CONN *pcb;
+ UINT16 i;
+ tBNEP_RESULT result;
+
+ if (pan_cb.role == PAN_ROLE_INACTIVE || (!(pan_cb.num_conns)))
+ {
+ PAN_TRACE_ERROR0 ("PAN is not active Data write failed");
+ return PAN_FAILURE;
+ }
+
+ /* Check if it is broadcast or multicast packet */
+ if (dst[0] & 0x01)
+ {
+ for (i=0; i<MAX_PAN_CONNS; i++)
+ {
+ if (pan_cb.pcb[i].con_state == PAN_STATE_CONNECTED)
+ BNEP_Write (pan_cb.pcb[i].handle, dst, p_data, len, protocol, src, ext);
+ }
+
+ return PAN_SUCCESS;
+ }
+
+ if (pan_cb.active_role == PAN_ROLE_CLIENT)
+ {
+ /* Data write is on PANU connection */
+ for (i=0; i<MAX_PAN_CONNS; i++)
+ {
+ if (pan_cb.pcb[i].con_state == PAN_STATE_CONNECTED &&
+ pan_cb.pcb[i].src_uuid == UUID_SERVCLASS_PANU)
+ break;
+ }
+
+ if (i == MAX_PAN_CONNS)
+ {
+ PAN_TRACE_ERROR0 ("PAN Don't have any user connections");
+ return PAN_FAILURE;
+ }
+
+ result = BNEP_Write (pan_cb.pcb[i].handle, dst, p_data, len, protocol, src, ext);
+ if (result == BNEP_IGNORE_CMD)
+ {
+ PAN_TRACE_DEBUG0 ("PAN ignored data for PANU connection");
+ return result;
+ }
+ else if (result != BNEP_SUCCESS)
+ {
+ PAN_TRACE_ERROR0 ("PAN failed to write data for the PANU connection");
+ return result;
+ }
+
+ PAN_TRACE_DEBUG0 ("PAN successfully wrote data for the PANU connection");
+ return PAN_SUCCESS;
+ }
+
+ pcb = pan_get_pcb_by_handle (handle);
+ if (!pcb)
+ {
+ PAN_TRACE_ERROR0 ("PAN Data write for wrong addr");
+ return PAN_FAILURE;
+ }
+
+ if (pcb->con_state != PAN_STATE_CONNECTED)
+ {
+ PAN_TRACE_ERROR0 ("PAN Data write when conn is not active");
+ return PAN_FAILURE;
+ }
+
+ result = BNEP_Write (pcb->handle, dst, p_data, len, protocol, src, ext);
+ if (result == BNEP_IGNORE_CMD)
+ {
+ PAN_TRACE_DEBUG0 ("PAN ignored data write to PANU");
+ return result;
+ }
+ else if (result != BNEP_SUCCESS)
+ {
+ PAN_TRACE_ERROR0 ("PAN failed to send data to the PANU");
+ return result;
+ }
+
+ PAN_TRACE_DEBUG0 ("PAN successfully sent data to the PANU");
+ return PAN_SUCCESS;
+}
+
+
+/*******************************************************************************
+**
+** Function PAN_WriteBuf
+**
+** Description This sends data over the PAN connections. If this is called
+** on GN or NAP side and the packet is multicast or broadcast
+** it will be sent on all the links. Otherwise the correct link
+** is found based on the destination address and forwarded on it
+** If the return value is not PAN_SUCCESS the application should
+** take care of releasing the message buffer
+**
+** Parameters: handle - handle for the connection
+** dst - MAC or BD Addr of the destination device
+** src - MAC or BD Addr of the source who sent this packet
+** protocol - protocol of the ethernet packet like IP or ARP
+** p_buf - pointer to the data buffer
+** ext - to indicate that extension headers present
+**
+** Returns PAN_SUCCESS - if the data is sent successfully
+** PAN_FAILURE - if the connection is not found or
+** there is an error in sending data
+**
+*******************************************************************************/
+tPAN_RESULT PAN_WriteBuf (UINT16 handle, BD_ADDR dst, BD_ADDR src, UINT16 protocol, BT_HDR *p_buf, BOOLEAN ext)
+{
+ tPAN_CONN *pcb;
+ UINT16 i;
+ tBNEP_RESULT result;
+
+ /* Check if it is broadcast or multicast packet */
+ if (dst[0] & 0x01)
+ {
+ UINT8 *p_data;
+ UINT16 len;
+
+ p_data = (UINT8 *)(p_buf + 1) + p_buf->offset;
+ len = p_buf->len;
+ PAN_Write (handle, dst, src, protocol, p_data, len, ext);
+ GKI_freebuf (p_buf);
+ return PAN_SUCCESS;
+ }
+
+ if (pan_cb.role == PAN_ROLE_INACTIVE || (!(pan_cb.num_conns)))
+ {
+ PAN_TRACE_ERROR0 ("PAN is not active Data write failed");
+ GKI_freebuf (p_buf);
+ return PAN_FAILURE;
+ }
+
+ /* Check if the data write is on PANU side */
+ if (pan_cb.active_role == PAN_ROLE_CLIENT)
+ {
+ /* Data write is on PANU connection */
+ for (i=0; i<MAX_PAN_CONNS; i++)
+ {
+ if (pan_cb.pcb[i].con_state == PAN_STATE_CONNECTED &&
+ pan_cb.pcb[i].src_uuid == UUID_SERVCLASS_PANU)
+ break;
+ }
+
+ if (i == MAX_PAN_CONNS)
+ {
+ PAN_TRACE_ERROR0 ("PAN Don't have any user connections");
+ GKI_freebuf (p_buf);
+ return PAN_FAILURE;
+ }
+
+ result = BNEP_WriteBuf (pan_cb.pcb[i].handle, dst, p_buf, protocol, src, ext);
+ if (result == BNEP_IGNORE_CMD)
+ {
+ PAN_TRACE_DEBUG0 ("PAN ignored data write for PANU connection");
+ return result;
+ }
+ else if (result != BNEP_SUCCESS)
+ {
+ PAN_TRACE_ERROR0 ("PAN failed to write data for the PANU connection");
+ return result;
+ }
+
+ PAN_TRACE_DEBUG0 ("PAN successfully wrote data for the PANU connection");
+ return PAN_SUCCESS;
+ }
+
+ /* findout to which connection the data is meant for */
+ pcb = pan_get_pcb_by_handle (handle);
+ if (!pcb)
+ {
+ PAN_TRACE_ERROR0 ("PAN Buf write for wrong handle");
+ GKI_freebuf (p_buf);
+ return PAN_FAILURE;
+ }
+
+ if (pcb->con_state != PAN_STATE_CONNECTED)
+ {
+ PAN_TRACE_ERROR0 ("PAN Buf write when conn is not active");
+ GKI_freebuf (p_buf);
+ return PAN_FAILURE;
+ }
+
+ result = BNEP_WriteBuf (pcb->handle, dst, p_buf, protocol, src, ext);
+ if (result == BNEP_IGNORE_CMD)
+ {
+ PAN_TRACE_DEBUG0 ("PAN ignored data buf write to PANU");
+ return result;
+ }
+ else if (result != BNEP_SUCCESS)
+ {
+ PAN_TRACE_ERROR0 ("PAN failed to send data buf to the PANU");
+ return result;
+ }
+
+ PAN_TRACE_DEBUG0 ("PAN successfully sent data buf to the PANU");
+ return PAN_SUCCESS;
+}
+
+
+/*******************************************************************************
+**
+** Function PAN_SetProtocolFilters
+**
+** Description This function is used to set protocol filters on the peer
+**
+** Parameters: handle - handle for the connection
+** num_filters - number of protocol filter ranges
+** start - array of starting protocol numbers
+** end - array of ending protocol numbers
+**
+**
+** Returns PAN_SUCCESS if protocol filters are set successfully
+** PAN_FAILURE if connection not found or error in setting
+**
+*******************************************************************************/
+tPAN_RESULT PAN_SetProtocolFilters (UINT16 handle,
+ UINT16 num_filters,
+ UINT16 *p_start_array,
+ UINT16 *p_end_array)
+{
+#if (defined (BNEP_SUPPORTS_PROT_FILTERS) && BNEP_SUPPORTS_PROT_FILTERS == TRUE)
+ tPAN_CONN *pcb;
+ tPAN_RESULT result;
+
+ /* Check if the connection exists */
+ pcb = pan_get_pcb_by_handle (handle);
+ if(!pcb)
+ {
+ PAN_TRACE_ERROR1 ("PAN connection not found for the handle %d", handle);
+ return PAN_FAILURE;
+ }
+
+ result = BNEP_SetProtocolFilters (pcb->handle, num_filters, p_start_array, p_end_array);
+ if (result != BNEP_SUCCESS)
+ {
+ PAN_TRACE_ERROR1 ("PAN failed to set protocol filters for handle %d", handle);
+ return result;
+ }
+
+ PAN_TRACE_API1 ("PAN successfully sent protocol filters for handle %d", handle);
+ return PAN_SUCCESS;
+#else
+ return PAN_FAILURE;
+#endif
+}
+
+
+
+/*******************************************************************************
+**
+** Function PAN_SetMulticastFilters
+**
+** Description This function is used to set multicast filters on the peer
+**
+** Parameters: handle - handle for the connection
+** num_filters - number of multicast filter ranges
+** start - array of starting multicast filter addresses
+** end - array of ending multicast filter addresses
+**
+**
+** Returns PAN_SUCCESS if multicast filters are set successfully
+** PAN_FAILURE if connection not found or error in setting
+**
+*******************************************************************************/
+tBNEP_RESULT PAN_SetMulticastFilters (UINT16 handle,
+ UINT16 num_mcast_filters,
+ UINT8 *p_start_array,
+ UINT8 *p_end_array)
+{
+#if (defined (BNEP_SUPPORTS_MULTI_FILTERS) && BNEP_SUPPORTS_MULTI_FILTERS == TRUE)
+ tPAN_CONN *pcb;
+ tPAN_RESULT result;
+
+ /* Check if the connection exists */
+ pcb = pan_get_pcb_by_handle (handle);
+ if(!pcb)
+ {
+ PAN_TRACE_ERROR1 ("PAN connection not found for the handle %d", handle);
+ return PAN_FAILURE;
+ }
+
+ result = BNEP_SetMulticastFilters (pcb->handle,
+ num_mcast_filters, p_start_array, p_end_array);
+ if (result != BNEP_SUCCESS)
+ {
+ PAN_TRACE_ERROR1 ("PAN failed to set multicast filters for handle %d", handle);
+ return result;
+ }
+
+ PAN_TRACE_API1 ("PAN successfully sent multicast filters for handle %d", handle);
+ return PAN_SUCCESS;
+#else
+ return PAN_FAILURE;
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function PAN_SetTraceLevel
+**
+** Description This function sets the trace level for PAN. If called with
+** a value of 0xFF, it simply reads the current trace level.
+**
+** Returns the new (current) trace level
+**
+*******************************************************************************/
+UINT8 PAN_SetTraceLevel (UINT8 new_level)
+{
+ if (new_level != 0xFF)
+ pan_cb.trace_level = new_level;
+ else
+ pan_dump_status ();
+
+ return (pan_cb.trace_level);
+}
+
+/*******************************************************************************
+**
+** Function PAN_Init
+**
+** Description This function initializes the PAN module variables
+**
+** Parameters: none
+**
+** Returns none
+**
+*******************************************************************************/
+void PAN_Init (void)
+{
+ memset (&pan_cb, 0, sizeof (tPAN_CB));
+
+#if defined(PAN_INITIAL_TRACE_LEVEL)
+ pan_cb.trace_level = PAN_INITIAL_TRACE_LEVEL;
+#else
+ pan_cb.trace_level = BT_TRACE_LEVEL_NONE; /* No traces */
+#endif
+}
+
+
diff --git a/stack/pan/pan_int.h b/stack/pan/pan_int.h
new file mode 100644
index 0000000..3c24d08
--- /dev/null
+++ b/stack/pan/pan_int.h
@@ -0,0 +1,145 @@
+/****************************************************************************/
+/* */
+/* Name: pan_int.h */
+/* */
+/* Function this file contains internally used PAN definitions */
+/* */
+/* */
+/* Copyright (c) 2001-2004, WIDCOMM Inc., All Rights Reserved. */
+/* WIDCOMM Bluetooth Core. Proprietary and confidential. */
+/* */
+/****************************************************************************/
+#ifndef PAN_INT_H
+#define PAN_INT_H
+
+#include "pan_api.h"
+
+/*
+** This role is used to shutdown the profile. Used internally
+** Applications should call PAN_Deregister to shutdown the profile
+*/
+#define PAN_ROLE_INACTIVE 0
+
+/* Protocols supported by the host internal stack, are registered with SDP */
+#define PAN_PROTOCOL_IP 0x0800
+#define PAN_PROTOCOL_ARP 0x0806
+
+#define PAN_PROFILE_VERSION 0x0100 /* Version 1.00 */
+
+/* Define the PAN Connection Control Block
+*/
+typedef struct
+{
+#define PAN_STATE_IDLE 0
+#define PAN_STATE_CONN_START 1
+#define PAN_STATE_CONNECTED 2
+ UINT8 con_state;
+
+#define PAN_FLAGS_CONN_COMPLETED 0x01
+ UINT8 con_flags;
+
+ UINT16 handle;
+ BD_ADDR rem_bda;
+
+ UINT16 bad_pkts_rcvd;
+ UINT16 src_uuid;
+ UINT16 dst_uuid;
+ UINT16 prv_src_uuid;
+ UINT16 prv_dst_uuid;
+ UINT16 ip_addr_known;
+ UINT32 ip_addr;
+
+} tPAN_CONN;
+
+
+/* The main PAN control block
+*/
+typedef struct
+{
+ UINT8 role;
+ UINT8 active_role;
+ UINT8 prv_active_role;
+ tPAN_CONN pcb[MAX_PAN_CONNS];
+
+ tPAN_CONN_STATE_CB *pan_conn_state_cb; /* Connection state callback */
+ tPAN_BRIDGE_REQ_CB *pan_bridge_req_cb;
+ tPAN_DATA_IND_CB *pan_data_ind_cb;
+ tPAN_DATA_BUF_IND_CB *pan_data_buf_ind_cb;
+ tPAN_FILTER_IND_CB *pan_pfilt_ind_cb; /* protocol filter indication callback */
+ tPAN_MFILTER_IND_CB *pan_mfilt_ind_cb; /* multicast filter indication callback */
+ tPAN_TX_DATA_FLOW_CB *pan_tx_data_flow_cb;
+
+ BD_ADDR my_bda; /* BD Address of this device */
+ char *user_service_name;
+ char *gn_service_name;
+ char *nap_service_name;
+ UINT32 pan_user_sdp_handle;
+ UINT32 pan_gn_sdp_handle;
+ UINT32 pan_nap_sdp_handle;
+ UINT8 num_conns;
+ UINT8 trace_level;
+} tPAN_CB;
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Global PAN data
+*/
+#if PAN_DYNAMIC_MEMORY == FALSE
+PAN_API extern tPAN_CB pan_cb;
+#else
+PAN_API extern tPAN_CB *pan_cb_ptr;
+#define pan_cb (*pan_cb_ptr)
+#endif
+
+/*******************************************************************************/
+extern void pan_register_with_bnep (void);
+extern void pan_conn_ind_cb (UINT16 handle,
+ BD_ADDR p_bda,
+ tBT_UUID *remote_uuid,
+ tBT_UUID *local_uuid,
+ BOOLEAN is_role_change);
+extern void pan_connect_state_cb (UINT16 handle, BD_ADDR rem_bda, tBNEP_RESULT result, BOOLEAN is_role_change);
+extern void pan_data_ind_cb (UINT16 handle,
+ UINT8 *src,
+ UINT8 *dst,
+ UINT16 protocol,
+ UINT8 *p_data,
+ UINT16 len,
+ BOOLEAN fw_ext_present);
+extern void pan_data_buf_ind_cb (UINT16 handle,
+ UINT8 *src,
+ UINT8 *dst,
+ UINT16 protocol,
+ BT_HDR *p_buf,
+ BOOLEAN ext);
+extern void pan_tx_data_flow_cb (UINT16 handle,
+ tBNEP_RESULT event);
+void pan_proto_filt_ind_cb (UINT16 handle,
+ BOOLEAN indication,
+ tBNEP_RESULT result,
+ UINT16 num_filters,
+ UINT8 *p_filters);
+void pan_mcast_filt_ind_cb (UINT16 handle,
+ BOOLEAN indication,
+ tBNEP_RESULT result,
+ UINT16 num_filters,
+ UINT8 *p_filters);
+extern UINT32 pan_register_with_sdp (UINT16 uuid, UINT8 sec_mask, char *p_name, char *p_desc);
+extern tPAN_CONN *pan_allocate_pcb (BD_ADDR p_bda, UINT16 handle);
+extern tPAN_CONN *pan_get_pcb_by_handle (UINT16 handle);
+extern tPAN_CONN *pan_get_pcb_by_addr (BD_ADDR p_bda);
+extern void pan_close_all_connections (void);
+extern void pan_release_pcb (tPAN_CONN *p_pcb);
+extern void pan_dump_status (void);
+
+/********************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/stack/pan/pan_main.c b/stack/pan/pan_main.c
new file mode 100644
index 0000000..36d7a8c
--- /dev/null
+++ b/stack/pan/pan_main.c
@@ -0,0 +1,717 @@
+/****************************************************************************/
+/* */
+/* Name: pan_main.c */
+/* */
+/* Function: this file contains main functions to support PAN profile */
+/* commands and events. */
+/* */
+/* Copyright (c) 1999-2004, WIDCOMM Inc., All Rights Reserved. */
+/* WIDCOMM Bluetooth Core. Proprietary and confidential. */
+/* */
+/****************************************************************************/
+
+#include <string.h>
+#include "gki.h"
+#include "bt_types.h"
+#include "bnep_api.h"
+#include "pan_api.h"
+#include "pan_int.h"
+#include "sdp_api.h"
+#include "sdpdefs.h"
+#include "l2c_api.h"
+#include "hcidefs.h"
+
+
+#if PAN_DYNAMIC_MEMORY == FALSE
+tPAN_CB pan_cb;
+#endif
+
+#define UUID_CONSTANT_PART 12
+UINT8 constant_pan_uuid[UUID_CONSTANT_PART] = {0, 0, 0x10, 0, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb};
+
+
+/*******************************************************************************
+**
+** Function pan_register_with_bnep
+**
+** Description This function registers PAN profile with BNEP
+**
+** Parameters: none
+**
+** Returns none
+**
+*******************************************************************************/
+void pan_register_with_bnep (void)
+{
+ tBNEP_REGISTER reg_info;
+
+ memset (&reg_info, 0, sizeof (tBNEP_REGISTER));
+
+ reg_info.p_conn_ind_cb = pan_conn_ind_cb;
+ reg_info.p_conn_state_cb = pan_connect_state_cb;
+ reg_info.p_data_buf_cb = pan_data_buf_ind_cb;
+ reg_info.p_data_ind_cb = NULL;
+ reg_info.p_tx_data_flow_cb = pan_tx_data_flow_cb;
+ reg_info.p_filter_ind_cb = pan_proto_filt_ind_cb;
+ reg_info.p_mfilter_ind_cb = pan_mcast_filt_ind_cb;
+
+ BNEP_Register (&reg_info);
+}
+
+
+/*******************************************************************************
+**
+** Function pan_conn_ind_cb
+**
+** Description This function is registered with BNEP as connection indication
+** callback. BNEP will call this when there is connection
+** request from the peer. PAN should call BNEP_ConnectResp to
+** indicate whether to accept the connection or reject
+**
+** Parameters: handle - handle for the connection
+** p_bda - BD Addr of the peer requesting the connection
+** remote_uuid - UUID of the source role (peer device role)
+** local_uuid - UUID of the destination role (local device role)
+** is_role_change - Flag to indicate that it is a role change
+**
+** Returns none
+**
+*******************************************************************************/
+void pan_conn_ind_cb (UINT16 handle,
+ BD_ADDR p_bda,
+ tBT_UUID *remote_uuid,
+ tBT_UUID *local_uuid,
+ BOOLEAN is_role_change)
+{
+ tPAN_CONN *pcb;
+ UINT8 req_role;
+ BOOLEAN wrong_uuid;
+
+ /*
+ ** If we are in GN or NAP role and have one or more
+ ** active connections and the received connection is
+ ** for user role reject it.
+ ** If we are in user role with one connection active
+ ** reject the connection.
+ ** Allocate PCB and store the parameters
+ ** Make bridge request to the host system if connection
+ ** is for NAP
+ */
+ wrong_uuid = FALSE;
+#if (defined (BNEP_SUPPORTS_ALL_UUID_LENGTHS) && BNEP_SUPPORTS_ALL_UUID_LENGTHS == TRUE)
+ if (remote_uuid->len == 16)
+ {
+ /*
+ ** If the UUID is 16 bytes forst two bytes should be zeros
+ ** and last 12 bytes should match the spec defined constant value
+ */
+ if (memcmp (constant_pan_uuid, remote_uuid->uu.uuid128 + 4, UUID_CONSTANT_PART))
+ wrong_uuid = TRUE;
+
+ if (remote_uuid->uu.uuid128[0] || remote_uuid->uu.uuid128[1])
+ wrong_uuid = TRUE;
+
+ /* Extract the 16 bit equivalent of the UUID */
+ remote_uuid->uu.uuid16 = (UINT16)((remote_uuid->uu.uuid128[2] << 8) | remote_uuid->uu.uuid128[3]);
+ remote_uuid->len = 2;
+ }
+ if (remote_uuid->len == 4)
+ {
+ /* First two bytes should be zeros */
+ if (remote_uuid->uu.uuid32 & 0xFFFF0000)
+ wrong_uuid = TRUE;
+
+ remote_uuid->uu.uuid16 = (UINT16)remote_uuid->uu.uuid32;
+ remote_uuid->len = 2;
+ }
+
+ if (wrong_uuid)
+ {
+ PAN_TRACE_ERROR0 ("PAN Connection failed because of wrong remote UUID ");
+ BNEP_ConnectResp (handle, BNEP_CONN_FAILED_SRC_UUID);
+ return;
+ }
+
+ wrong_uuid = FALSE;
+ if (local_uuid->len == 16)
+ {
+ /*
+ ** If the UUID is 16 bytes forst two bytes should be zeros
+ ** and last 12 bytes should match the spec defined constant value
+ */
+ if (memcmp (constant_pan_uuid, local_uuid->uu.uuid128 + 4, UUID_CONSTANT_PART))
+ wrong_uuid = TRUE;
+
+ if (local_uuid->uu.uuid128[0] || local_uuid->uu.uuid128[1])
+ wrong_uuid = TRUE;
+
+ /* Extract the 16 bit equivalent of the UUID */
+ local_uuid->uu.uuid16 = (UINT16)((local_uuid->uu.uuid128[2] << 8) | local_uuid->uu.uuid128[3]);
+ local_uuid->len = 2;
+ }
+ if (local_uuid->len == 4)
+ {
+ /* First two bytes should be zeros */
+ if (local_uuid->uu.uuid32 & 0xFFFF0000)
+ wrong_uuid = TRUE;
+
+ local_uuid->uu.uuid16 = (UINT16)local_uuid->uu.uuid32;
+ local_uuid->len = 2;
+ }
+
+ if (wrong_uuid)
+ {
+ PAN_TRACE_ERROR0 ("PAN Connection failed because of wrong local UUID ");
+ BNEP_ConnectResp (handle, BNEP_CONN_FAILED_DST_UUID);
+ return;
+ }
+
+ PAN_TRACE_EVENT5 ("pan_conn_ind_cb - for handle %d, current role %d, dst uuid 0x%x, src uuid 0x%x, role change %s",
+ handle, pan_cb.role, local_uuid->uu.uuid16, remote_uuid->uu.uuid16, is_role_change?"YES":"NO");
+ /* The acceptable UUID size is only 2 */
+ if (remote_uuid->len != 2)
+ {
+ PAN_TRACE_ERROR1 ("PAN Connection failed because of wrong UUID size %d", remote_uuid->len);
+ BNEP_ConnectResp (handle, BNEP_CONN_FAILED_UUID_SIZE);
+ return;
+ }
+#endif
+
+ /* Check if the source UUID is a valid one */
+ if (remote_uuid->uu.uuid16 != UUID_SERVCLASS_PANU &&
+ remote_uuid->uu.uuid16 != UUID_SERVCLASS_NAP &&
+ remote_uuid->uu.uuid16 != UUID_SERVCLASS_GN)
+ {
+ PAN_TRACE_ERROR1 ("Src UUID 0x%x is not valid", remote_uuid->uu.uuid16);
+ BNEP_ConnectResp (handle, BNEP_CONN_FAILED_SRC_UUID);
+ return;
+ }
+
+ /* Check if the destination UUID is a valid one */
+ if (local_uuid->uu.uuid16 != UUID_SERVCLASS_PANU &&
+ local_uuid->uu.uuid16 != UUID_SERVCLASS_NAP &&
+ local_uuid->uu.uuid16 != UUID_SERVCLASS_GN)
+ {
+ PAN_TRACE_ERROR1 ("Dst UUID 0x%x is not valid", remote_uuid->uu.uuid16);
+ BNEP_ConnectResp (handle, BNEP_CONN_FAILED_DST_UUID);
+ return;
+ }
+
+ /* Check if currently we support the destination role requested */
+ if (((!(pan_cb.role & UUID_SERVCLASS_PANU))
+ && local_uuid->uu.uuid16 == UUID_SERVCLASS_PANU) ||
+ ((!(pan_cb.role & UUID_SERVCLASS_GN))
+ && local_uuid->uu.uuid16 == UUID_SERVCLASS_GN) ||
+ ((!(pan_cb.role & UUID_SERVCLASS_NAP))
+ && local_uuid->uu.uuid16 == UUID_SERVCLASS_NAP))
+ {
+ PAN_TRACE_ERROR1 ("PAN Connection failed because of unsupported destination UUID 0x%x", local_uuid->uu.uuid16);
+ BNEP_ConnectResp (handle, BNEP_CONN_FAILED_DST_UUID);
+ return;
+ }
+
+ /* Requested destination role is */
+ if (local_uuid->uu.uuid16 == UUID_SERVCLASS_PANU)
+ req_role = PAN_ROLE_CLIENT;
+ else if (local_uuid->uu.uuid16 == UUID_SERVCLASS_GN)
+ req_role = PAN_ROLE_GN_SERVER;
+ else
+ req_role = PAN_ROLE_NAP_SERVER;
+
+ /* If the connection indication is for the existing connection
+ ** Check if the new destination role is acceptable
+ */
+ pcb = pan_get_pcb_by_handle (handle);
+ if (pcb)
+ {
+ if (pan_cb.num_conns > 1 && local_uuid->uu.uuid16 == UUID_SERVCLASS_PANU)
+ {
+ /* There are connections other than this one
+ ** so we cann't accept PANU role. Reject
+ */
+ PAN_TRACE_ERROR0 ("Dst UUID should be either GN or NAP only because there are other connections");
+ BNEP_ConnectResp (handle, BNEP_CONN_FAILED_DST_UUID);
+ return;
+ }
+
+ /* If it is already in connected state check for bridging status */
+ if (pcb->con_state == PAN_STATE_CONNECTED)
+ {
+ PAN_TRACE_EVENT2 ("PAN Role changing New Src 0x%x Dst 0x%x",
+ remote_uuid->uu.uuid16, local_uuid->uu.uuid16);
+
+ pcb->prv_src_uuid = pcb->src_uuid;
+ pcb->prv_dst_uuid = pcb->dst_uuid;
+
+ if (pcb->src_uuid == UUID_SERVCLASS_NAP &&
+ local_uuid->uu.uuid16 != UUID_SERVCLASS_NAP)
+ {
+ /* Remove bridging */
+ if (pan_cb.pan_bridge_req_cb)
+ (*pan_cb.pan_bridge_req_cb) (pcb->rem_bda, FALSE);
+ }
+ }
+ /* Set the latest active PAN role */
+ pan_cb.active_role = req_role;
+ pcb->src_uuid = local_uuid->uu.uuid16;
+ pcb->dst_uuid = remote_uuid->uu.uuid16;
+ BNEP_ConnectResp (handle, BNEP_SUCCESS);
+ return;
+ }
+ else
+ {
+ /* If this a new connection and destination is PANU role and
+ ** we already have a connection then reject the request.
+ ** If we have a connection in PANU role then reject it
+ */
+ if (pan_cb.num_conns &&
+ (local_uuid->uu.uuid16 == UUID_SERVCLASS_PANU ||
+ pan_cb.active_role == PAN_ROLE_CLIENT))
+ {
+ PAN_TRACE_ERROR0 ("PAN already have a connection and can't be user");
+ BNEP_ConnectResp (handle, BNEP_CONN_FAILED_DST_UUID);
+ return;
+ }
+ }
+
+ /* This is a new connection */
+ PAN_TRACE_DEBUG1 ("New connection indication for handle %d", handle);
+ pcb = pan_allocate_pcb (p_bda, handle);
+ if (!pcb)
+ {
+ PAN_TRACE_ERROR0 ("PAN no control block for new connection");
+ BNEP_ConnectResp (handle, BNEP_CONN_FAILED);
+ return;
+ }
+
+ PAN_TRACE_EVENT1 ("PAN connection destination UUID is 0x%x", local_uuid->uu.uuid16);
+ /* Set the latest active PAN role */
+ pan_cb.active_role = req_role;
+ pcb->src_uuid = local_uuid->uu.uuid16;
+ pcb->dst_uuid = remote_uuid->uu.uuid16;
+ pcb->con_state = PAN_STATE_CONN_START;
+ pan_cb.num_conns++;
+
+ BNEP_ConnectResp (handle, BNEP_SUCCESS);
+ return;
+}
+
+
+/*******************************************************************************
+**
+** Function pan_connect_state_cb
+**
+** Description This function is registered with BNEP as connection state
+** change callback. BNEP will call this when the connection
+** is established successfully or terminated
+**
+** Parameters: handle - handle for the connection given in the connection
+** indication callback
+** rem_bda - remote device bd addr
+** result - indicates whether the connection is up or down
+** BNEP_SUCCESS if the connection is up
+** all other values indicates appropriate errors
+** is_role_change - flag to indicate that it is a role change
+**
+** Returns none
+**
+*******************************************************************************/
+void pan_connect_state_cb (UINT16 handle, BD_ADDR rem_bda, tBNEP_RESULT result, BOOLEAN is_role_change)
+{
+ tPAN_CONN *pcb;
+ UINT8 peer_role;
+
+ PAN_TRACE_EVENT2 ("pan_connect_state_cb - for handle %d, result %d", handle, result);
+ pcb = pan_get_pcb_by_handle (handle);
+ if (!pcb)
+ {
+ PAN_TRACE_ERROR1 ("PAN State change indication for wrong handle %d", handle);
+ return;
+ }
+
+ /* If the connection is getting terminated remove bridging */
+ if (result != BNEP_SUCCESS)
+ {
+ /* Inform the application that connection is down */
+ if (pan_cb.pan_conn_state_cb)
+ (*pan_cb.pan_conn_state_cb) (pcb->handle, pcb->rem_bda, result, is_role_change, PAN_ROLE_INACTIVE, PAN_ROLE_INACTIVE);
+
+ /* Check if this failure is for role change only */
+ if (pcb->con_state != PAN_STATE_CONNECTED &&
+ (pcb->con_flags & PAN_FLAGS_CONN_COMPLETED))
+ {
+ /* restore the original values */
+ PAN_TRACE_EVENT0 ("restoring the connection state to active");
+ pcb->con_state = PAN_STATE_CONNECTED;
+ pcb->con_flags &= (~PAN_FLAGS_CONN_COMPLETED);
+
+ pcb->src_uuid = pcb->prv_src_uuid;
+ pcb->dst_uuid = pcb->prv_dst_uuid;
+ pan_cb.active_role = pan_cb.prv_active_role;
+
+ if ((pcb->src_uuid == UUID_SERVCLASS_NAP) && pan_cb.pan_bridge_req_cb)
+ (*pan_cb.pan_bridge_req_cb) (pcb->rem_bda, TRUE);
+
+ return;
+ }
+
+ if (pcb->con_state == PAN_STATE_CONNECTED)
+ {
+ /* If the connections destination role is NAP remove bridging */
+ if ((pcb->src_uuid == UUID_SERVCLASS_NAP) && pan_cb.pan_bridge_req_cb)
+ (*pan_cb.pan_bridge_req_cb) (pcb->rem_bda, FALSE);
+ }
+
+ pan_cb.num_conns--;
+ pan_release_pcb (pcb);
+ return;
+ }
+
+ /* Requested destination role is */
+ if (pcb->src_uuid == UUID_SERVCLASS_PANU)
+ pan_cb.active_role = PAN_ROLE_CLIENT;
+ else if (pcb->src_uuid == UUID_SERVCLASS_GN)
+ pan_cb.active_role = PAN_ROLE_GN_SERVER;
+ else
+ pan_cb.active_role = PAN_ROLE_NAP_SERVER;
+
+ if (pcb->dst_uuid == UUID_SERVCLASS_PANU)
+ peer_role = PAN_ROLE_CLIENT;
+ else if (pcb->dst_uuid == UUID_SERVCLASS_GN)
+ peer_role = PAN_ROLE_GN_SERVER;
+ else
+ peer_role = PAN_ROLE_NAP_SERVER;
+
+ pcb->con_state = PAN_STATE_CONNECTED;
+
+ /* Inform the application that connection is down */
+ if (pan_cb.pan_conn_state_cb)
+ (*pan_cb.pan_conn_state_cb) (pcb->handle, pcb->rem_bda, PAN_SUCCESS, is_role_change, pan_cb.active_role, peer_role);
+
+ /* Create bridge if the destination role is NAP */
+ if (pan_cb.pan_bridge_req_cb && pcb->src_uuid == UUID_SERVCLASS_NAP)
+ {
+ PAN_TRACE_EVENT0 ("PAN requesting for bridge");
+ (*pan_cb.pan_bridge_req_cb) (pcb->rem_bda, TRUE);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function pan_data_ind_cb
+**
+** Description This function is registered with BNEP as data indication
+** callback. BNEP will call this when the peer sends any data
+** on this connection
+**
+** Parameters: handle - handle for the connection
+** src - source BD Addr
+** dst - destination BD Addr
+** protocol - Network protocol of the Eth packet
+** p_data - pointer to the data
+** len - length of the data
+** fw_ext_present - to indicate whether the data contains any
+** extension headers before the payload
+**
+** Returns none
+**
+*******************************************************************************/
+void pan_data_ind_cb (UINT16 handle,
+ UINT8 *src,
+ UINT8 *dst,
+ UINT16 protocol,
+ UINT8 *p_data,
+ UINT16 len,
+ BOOLEAN ext)
+{
+ tPAN_CONN *pcb;
+ UINT16 i;
+ BOOLEAN forward;
+
+ /*
+ ** Check the connection status
+ ** If the destination address is MAC broadcast send on all links
+ ** except on the one received
+ ** If the destination uuid is for NAP send to host system also
+ ** If the destination address is one of the devices connected
+ ** send the packet to over that link
+ ** If the destination address is unknown and destination uuid is NAP
+ ** send it to the host system
+ */
+
+ PAN_TRACE_EVENT1 ("pan_data_ind_cb - for handle %d", handle);
+ pcb = pan_get_pcb_by_handle (handle);
+ if (!pcb)
+ {
+ PAN_TRACE_ERROR1 ("PAN Data indication for wrong handle %d", handle);
+ return;
+ }
+
+ if (pcb->con_state != PAN_STATE_CONNECTED)
+ {
+ PAN_TRACE_ERROR2 ("PAN Data indication in wrong state %d for handle %d",
+ pcb->con_state, handle);
+ return;
+ }
+
+ /* Check if it is broadcast packet */
+ if (dst[0] & 0x01)
+ {
+ PAN_TRACE_DEBUG2 ("PAN received broadcast packet on handle %d, src uuid 0x%x",
+ handle, pcb->src_uuid);
+ for (i=0; i<MAX_PAN_CONNS; i++)
+ {
+ if (pan_cb.pcb[i].con_state == PAN_STATE_CONNECTED &&
+ pan_cb.pcb[i].handle != handle &&
+ pcb->src_uuid == pan_cb.pcb[i].src_uuid)
+ {
+ BNEP_Write (pan_cb.pcb[i].handle, dst, p_data, len, protocol, src, ext);
+ }
+ }
+
+ if (pan_cb.pan_data_ind_cb)
+ (*pan_cb.pan_data_ind_cb) (pcb->handle, src, dst, protocol, p_data, len, ext, TRUE);
+
+ return;
+ }
+
+ /* Check if it is for any other PAN connection */
+ for (i=0; i<MAX_PAN_CONNS; i++)
+ {
+ if (pan_cb.pcb[i].con_state == PAN_STATE_CONNECTED &&
+ pcb->src_uuid == pan_cb.pcb[i].src_uuid)
+ {
+ if (memcmp (pan_cb.pcb[i].rem_bda, dst, BD_ADDR_LEN) == 0)
+ {
+ BNEP_Write (pan_cb.pcb[i].handle, dst, p_data, len, protocol, src, ext);
+ return;
+ }
+ }
+ }
+
+ if (pcb->src_uuid == UUID_SERVCLASS_NAP)
+ forward = TRUE;
+ else
+ forward = FALSE;
+
+ /* Send it over the LAN or give it to host software */
+ if (pan_cb.pan_data_ind_cb)
+ (*pan_cb.pan_data_ind_cb) (pcb->handle, src, dst, protocol, p_data, len, ext, forward);
+
+ return;
+}
+
+
+/*******************************************************************************
+**
+** Function pan_data_buf_ind_cb
+**
+** Description This function is registered with BNEP as data buffer indication
+** callback. BNEP will call this when the peer sends any data
+** on this connection. PAN is responsible to release the buffer
+**
+** Parameters: handle - handle for the connection
+** src - source BD Addr
+** dst - destination BD Addr
+** protocol - Network protocol of the Eth packet
+** p_buf - pointer to the data buffer
+** ext - to indicate whether the data contains any
+** extension headers before the payload
+**
+** Returns none
+**
+*******************************************************************************/
+void pan_data_buf_ind_cb (UINT16 handle,
+ UINT8 *src,
+ UINT8 *dst,
+ UINT16 protocol,
+ BT_HDR *p_buf,
+ BOOLEAN ext)
+{
+ tPAN_CONN *pcb, *dst_pcb;
+ tBNEP_RESULT result;
+ UINT16 i, len;
+ UINT8 *p_data;
+ BOOLEAN forward = FALSE;
+
+ /* Check if the connection is in right state */
+ pcb = pan_get_pcb_by_handle (handle);
+ if (!pcb)
+ {
+ PAN_TRACE_ERROR1 ("PAN Data buffer indication for wrong handle %d", handle);
+ GKI_freebuf (p_buf);
+ return;
+ }
+
+ if (pcb->con_state != PAN_STATE_CONNECTED)
+ {
+ PAN_TRACE_ERROR2 ("PAN Data indication in wrong state %d for handle %d",
+ pcb->con_state, handle);
+ GKI_freebuf (p_buf);
+ return;
+ }
+
+ p_data = (UINT8 *)(p_buf + 1) + p_buf->offset;
+ len = p_buf->len;
+
+ PAN_TRACE_EVENT4 ("pan_data_buf_ind_cb - for handle %d, protocol 0x%x, length %d, ext %d",
+ handle, protocol, len, ext);
+
+ if (pcb->src_uuid == UUID_SERVCLASS_NAP)
+ forward = TRUE;
+ else
+ forward = FALSE;
+
+ /* Check if it is broadcast or multicast packet */
+ if (pcb->src_uuid != UUID_SERVCLASS_PANU)
+ {
+ if (dst[0] & 0x01)
+ {
+ PAN_TRACE_DEBUG2 ("PAN received broadcast packet on handle %d, src uuid 0x%x",
+ handle, pcb->src_uuid);
+ for (i=0; i<MAX_PAN_CONNS; i++)
+ {
+ if (pan_cb.pcb[i].con_state == PAN_STATE_CONNECTED &&
+ pan_cb.pcb[i].handle != handle &&
+ pcb->src_uuid == pan_cb.pcb[i].src_uuid)
+ {
+ BNEP_Write (pan_cb.pcb[i].handle, dst, p_data, len, protocol, src, ext);
+ }
+ }
+
+ if (pan_cb.pan_data_buf_ind_cb)
+ (*pan_cb.pan_data_buf_ind_cb) (pcb->handle, src, dst, protocol, p_buf, ext, forward);
+ else if (pan_cb.pan_data_ind_cb)
+ {
+ (*pan_cb.pan_data_ind_cb) (pcb->handle, src, dst, protocol, p_data, len, ext, forward);
+ GKI_freebuf (p_buf);
+ }
+
+ return;
+ }
+
+ /* Check if it is for any other PAN connection */
+ dst_pcb = pan_get_pcb_by_addr (dst);
+ if (dst_pcb)
+ {
+ PAN_TRACE_EVENT0 ("pan_data_buf_ind_cb - destination PANU found and sending the data");
+ result = BNEP_WriteBuf (dst_pcb->handle, dst, p_buf, protocol, src, ext);
+ if (result != BNEP_SUCCESS && result != BNEP_IGNORE_CMD)
+ PAN_TRACE_ERROR1 ("Failed to write data for PAN connection handle %d", dst_pcb->handle);
+ return;
+ }
+ }
+
+ /* Send it over the LAN or give it to host software */
+ if (pan_cb.pan_data_buf_ind_cb)
+ (*pan_cb.pan_data_buf_ind_cb) (pcb->handle, src, dst, protocol, p_buf, ext, forward);
+ else if (pan_cb.pan_data_ind_cb)
+ {
+ (*pan_cb.pan_data_ind_cb) (pcb->handle, src, dst, protocol, p_data, len, ext, forward);
+ GKI_freebuf (p_buf);
+ }
+ else
+ GKI_freebuf (p_buf);
+
+ return;
+}
+
+/*******************************************************************************
+**
+** Function pan_proto_filt_ind_cb
+**
+** Description This function is registered with BNEP to receive tx data
+** flow status
+**
+** Parameters: handle - handle for the connection
+** event - flow status
+**
+** Returns none
+**
+*******************************************************************************/
+void pan_tx_data_flow_cb (UINT16 handle,
+ tBNEP_RESULT event)
+{
+
+ if (pan_cb.pan_tx_data_flow_cb)
+ (*pan_cb.pan_tx_data_flow_cb) (handle, event);
+
+ return;
+}
+
+/*******************************************************************************
+**
+** Function pan_proto_filt_ind_cb
+**
+** Description This function is registered with BNEP as proto filter indication
+** callback. BNEP will call this when the peer sends any protocol
+** filter set for the connection or to indicate the result of the
+** protocol filter set by the local device
+**
+** Parameters: handle - handle for the connection
+** indication - TRUE if this is indication
+** FALSE if it is called to give the result of local
+** device protocol filter set
+** result - This gives the result of the filter set operation
+** num_filters - number of filters set by the peer device
+** p_filters - pointer to the filters set by the peer device
+**
+** Returns none
+**
+*******************************************************************************/
+void pan_proto_filt_ind_cb (UINT16 handle,
+ BOOLEAN indication,
+ tBNEP_RESULT result,
+ UINT16 num_filters,
+ UINT8 *p_filters)
+{
+#if (defined (BNEP_SUPPORTS_PROT_FILTERS) && BNEP_SUPPORTS_PROT_FILTERS == TRUE)
+ PAN_TRACE_EVENT4 ("pan_proto_filt_ind_cb - called for handle %d with ind %d, result %d, num %d",
+ handle, indication, result, num_filters);
+
+ if (pan_cb.pan_pfilt_ind_cb)
+ (*pan_cb.pan_pfilt_ind_cb) (handle, indication, result, num_filters, p_filters);
+#endif
+
+ return;
+}
+
+
+/*******************************************************************************
+**
+** Function pan_mcast_filt_ind_cb
+**
+** Description This function is registered with BNEP as mcast filter indication
+** callback. BNEP will call this when the peer sends any multicast
+** filter set for the connection or to indicate the result of the
+** multicast filter set by the local device
+**
+** Parameters: handle - handle for the connection
+** indication - TRUE if this is indication
+** FALSE if it is called to give the result of local
+** device multicast filter set
+** result - This gives the result of the filter set operation
+** num_filters - number of filters set by the peer device
+** p_filters - pointer to the filters set by the peer device
+**
+** Returns none
+**
+*******************************************************************************/
+void pan_mcast_filt_ind_cb (UINT16 handle,
+ BOOLEAN indication,
+ tBNEP_RESULT result,
+ UINT16 num_filters,
+ UINT8 *p_filters)
+{
+#if (defined (BNEP_SUPPORTS_MULTI_FILTERS) && BNEP_SUPPORTS_MULTI_FILTERS == TRUE)
+ PAN_TRACE_EVENT4 ("pan_mcast_filt_ind_cb - called for handle %d with ind %d, result %d, num %d",
+ handle, indication, result, num_filters);
+
+ if (pan_cb.pan_mfilt_ind_cb)
+ (*pan_cb.pan_mfilt_ind_cb) (handle, indication, result, num_filters, p_filters);
+#endif
+
+ return;
+}
+
diff --git a/stack/pan/pan_utils.c b/stack/pan/pan_utils.c
new file mode 100644
index 0000000..33cd151
--- /dev/null
+++ b/stack/pan/pan_utils.c
@@ -0,0 +1,338 @@
+/****************************************************************************/
+/* */
+/* Name: pan_utils.c */
+/* */
+/* Function: this file contains main functions to support PAN profile */
+/* commands and events. */
+/* */
+/* Copyright (c) 1999-2004, WIDCOMM Inc., All Rights Reserved. */
+/* WIDCOMM Bluetooth Core. Proprietary and confidential. */
+/* */
+/****************************************************************************/
+
+#include <string.h>
+#include <stdio.h>
+#include "gki.h"
+#include "bnep_api.h"
+#include "pan_api.h"
+#include "pan_int.h"
+#include "sdp_api.h"
+#include "sdpdefs.h"
+#include "l2c_api.h"
+#include "hcidefs.h"
+#include "btm_api.h"
+
+
+static const UINT8 pan_proto_elem_data[] = {
+ 0x35, 0x18, /* data element sequence of length 0x18 bytes */
+ 0x35, 0x06, /* data element sequence for L2CAP descriptor */
+ 0x19, 0x01, 0x00, /* UUID for L2CAP - 0x0100 */
+ 0x09, 0x00, 0x0F, /* PSM for BNEP - 0x000F */
+ 0x35, 0x0E, /* data element seqence for BNEP descriptor */
+ 0x19, 0x00, 0x0F, /* UUID for BNEP - 0x000F */
+ 0x09, 0x01, 0x00, /* BNEP specific parameter 0 -- Version of BNEP = version 1 = 0x0001 */
+ 0x35, 0x06, /* BNEP specific parameter 1 -- Supported network packet type list */
+ 0x09, 0x08, 0x00, /* network packet type IPv4 = 0x0800 */
+ 0x09, 0x08, 0x06 /* network packet type ARP = 0x0806 */
+};
+
+/*******************************************************************************
+**
+** Function pan_register_with_sdp
+**
+** Description
+**
+** Returns
+**
+*******************************************************************************/
+UINT32 pan_register_with_sdp (UINT16 uuid, UINT8 sec_mask, char *p_name, char *p_desc)
+{
+ UINT32 sdp_handle;
+ UINT16 browse_list = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
+ UINT16 security = 0;
+ UINT8 availability;
+ UINT32 proto_len = (UINT32)pan_proto_elem_data[1];
+
+ /* Create a record */
+ sdp_handle = SDP_CreateRecord ();
+
+ if (sdp_handle == 0)
+ {
+ PAN_TRACE_ERROR0 ("PAN_SetRole - could not create SDP record");
+ return 0;
+ }
+
+ /* Service Class ID List */
+ SDP_AddServiceClassIdList (sdp_handle, 1, &uuid);
+
+ /* Add protocol element sequence from the constant string */
+ SDP_AddAttribute (sdp_handle, ATTR_ID_PROTOCOL_DESC_LIST, DATA_ELE_SEQ_DESC_TYPE,
+ proto_len, (UINT8 *)(pan_proto_elem_data+2));
+
+// btla-specific ++
+#if 0
+ availability = 0xFF;
+ SDP_AddAttribute (sdp_handle, ATTR_ID_SERVICE_AVAILABILITY, UINT_DESC_TYPE, 1, &availability);
+#endif
+// btla-specific --
+
+ /* Language base */
+ SDP_AddLanguageBaseAttrIDList (sdp_handle, LANG_ID_CODE_ENGLISH, LANG_ID_CHAR_ENCODE_UTF8, LANGUAGE_BASE_ID);
+
+ /* Profile descriptor list */
+ SDP_AddProfileDescriptorList (sdp_handle, uuid, PAN_PROFILE_VERSION);
+
+ /* Service Name */
+ SDP_AddAttribute (sdp_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE,
+ (UINT8) (strlen(p_name) + 1), (UINT8 *)p_name);
+
+ /* Service description */
+ SDP_AddAttribute (sdp_handle, ATTR_ID_SERVICE_DESCRIPTION, TEXT_STR_DESC_TYPE,
+ (UINT8) (strlen(p_desc) + 1), (UINT8 *)p_desc);
+
+ /* Security description */
+ if (sec_mask)
+ {
+ UINT16_TO_BE_FIELD(&security, 0x0001);
+ }
+ SDP_AddAttribute (sdp_handle, ATTR_ID_SECURITY_DESCRIPTION, UINT_DESC_TYPE, 2, (UINT8 *)&security);
+
+#if (defined (PAN_SUPPORTS_ROLE_NAP) && PAN_SUPPORTS_ROLE_NAP == TRUE)
+ if (uuid == UUID_SERVCLASS_NAP)
+ {
+ UINT16 NetAccessType = 0x0005; /* Ethernet */
+ UINT32 NetAccessRate = 0x0001312D0; /* 10Mb/sec */
+ UINT8 array[10], *p;
+
+ /* Net access type. */
+ p = array;
+ UINT16_TO_BE_STREAM (p, NetAccessType);
+ SDP_AddAttribute (sdp_handle, ATTR_ID_NET_ACCESS_TYPE, UINT_DESC_TYPE, 2, array);
+
+ /* Net access rate. */
+ p = array;
+ UINT32_TO_BE_STREAM (p, NetAccessRate);
+ SDP_AddAttribute (sdp_handle, ATTR_ID_MAX_NET_ACCESS_RATE, UINT_DESC_TYPE, 4, array);
+
+ /* Register with Security Manager for the specific security level */
+ if ((!BTM_SetSecurityLevel (TRUE, p_name, BTM_SEC_SERVICE_BNEP_NAP,
+ sec_mask, BT_PSM_BNEP, BTM_SEC_PROTO_BNEP, UUID_SERVCLASS_NAP))
+ || (!BTM_SetSecurityLevel (FALSE, p_name, BTM_SEC_SERVICE_BNEP_NAP,
+ sec_mask, BT_PSM_BNEP, BTM_SEC_PROTO_BNEP, UUID_SERVCLASS_NAP)))
+ {
+ PAN_TRACE_ERROR0 ("PAN Security Registration failed for PANU");
+ }
+ }
+#endif
+#if (defined (PAN_SUPPORTS_ROLE_GN) && PAN_SUPPORTS_ROLE_GN == TRUE)
+ if (uuid == UUID_SERVCLASS_GN)
+ {
+ if ((!BTM_SetSecurityLevel (TRUE, p_name, BTM_SEC_SERVICE_BNEP_GN,
+ sec_mask, BT_PSM_BNEP, BTM_SEC_PROTO_BNEP, UUID_SERVCLASS_GN))
+ || (!BTM_SetSecurityLevel (FALSE, p_name, BTM_SEC_SERVICE_BNEP_GN,
+ sec_mask, BT_PSM_BNEP, BTM_SEC_PROTO_BNEP, UUID_SERVCLASS_GN)))
+ {
+ PAN_TRACE_ERROR0 ("PAN Security Registration failed for GN");
+ }
+ }
+#endif
+#if (defined (PAN_SUPPORTS_ROLE_PANU) && PAN_SUPPORTS_ROLE_PANU == TRUE)
+ if (uuid == UUID_SERVCLASS_PANU)
+ {
+ if ((!BTM_SetSecurityLevel (TRUE, p_name, BTM_SEC_SERVICE_BNEP_PANU,
+ sec_mask, BT_PSM_BNEP, BTM_SEC_PROTO_BNEP, UUID_SERVCLASS_PANU))
+ || (!BTM_SetSecurityLevel (FALSE, p_name, BTM_SEC_SERVICE_BNEP_PANU,
+ sec_mask, BT_PSM_BNEP, BTM_SEC_PROTO_BNEP, UUID_SERVCLASS_PANU)))
+ {
+ PAN_TRACE_ERROR0 ("PAN Security Registration failed for PANU");
+ }
+ }
+#endif
+
+ /* Make the service browsable */
+ SDP_AddUuidSequence (sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &browse_list);
+
+
+ return sdp_handle;
+}
+
+
+
+/*******************************************************************************
+**
+** Function pan_allocate_pcb
+**
+** Description
+**
+** Returns
+**
+*******************************************************************************/
+tPAN_CONN *pan_allocate_pcb (BD_ADDR p_bda, UINT16 handle)
+{
+ UINT16 i;
+
+ for (i=0; i<MAX_PAN_CONNS; i++)
+ {
+ if (pan_cb.pcb[i].con_state != PAN_STATE_IDLE &&
+ pan_cb.pcb[i].handle == handle)
+ return NULL;
+ }
+
+ for (i=0; i<MAX_PAN_CONNS; i++)
+ {
+ if (pan_cb.pcb[i].con_state != PAN_STATE_IDLE &&
+ memcmp (pan_cb.pcb[i].rem_bda, p_bda, BD_ADDR_LEN) == 0)
+ return NULL;
+ }
+
+ for (i=0; i<MAX_PAN_CONNS; i++)
+ {
+ if (pan_cb.pcb[i].con_state == PAN_STATE_IDLE)
+ {
+ memset (&(pan_cb.pcb[i]), 0, sizeof (tPAN_CONN));
+ memcpy (pan_cb.pcb[i].rem_bda, p_bda, BD_ADDR_LEN);
+ pan_cb.pcb[i].handle = handle;
+ return &(pan_cb.pcb[i]);
+ }
+ }
+ return NULL;
+}
+
+
+/*******************************************************************************
+**
+** Function pan_get_pcb_by_handle
+**
+** Description
+**
+** Returns
+**
+*******************************************************************************/
+tPAN_CONN *pan_get_pcb_by_handle (UINT16 handle)
+{
+ UINT16 i;
+
+ for (i=0; i<MAX_PAN_CONNS; i++)
+ {
+ if (pan_cb.pcb[i].con_state != PAN_STATE_IDLE &&
+ pan_cb.pcb[i].handle == handle)
+ return &(pan_cb.pcb[i]);
+ }
+
+ return NULL;
+}
+
+
+/*******************************************************************************
+**
+** Function pan_get_pcb_by_addr
+**
+** Description
+**
+** Returns
+**
+*******************************************************************************/
+tPAN_CONN *pan_get_pcb_by_addr (BD_ADDR p_bda)
+{
+ UINT16 i;
+
+ for (i=0; i<MAX_PAN_CONNS; i++)
+ {
+ if (pan_cb.pcb[i].con_state == PAN_STATE_IDLE)
+ continue;
+
+ if (memcmp (pan_cb.pcb[i].rem_bda, p_bda, BD_ADDR_LEN) == 0)
+ return &(pan_cb.pcb[i]);
+
+ /*
+ if (pan_cb.pcb[i].mfilter_present &&
+ (memcmp (p_bda, pan_cb.pcb[i].multi_cast_bridge, BD_ADDR_LEN) == 0))
+ return &(pan_cb.pcb[i]);
+ */
+ }
+
+ return NULL;
+}
+
+
+
+
+/*******************************************************************************
+**
+** Function pan_close_all_connections
+**
+** Description
+**
+** Returns void
+**
+*******************************************************************************/
+void pan_close_all_connections (void)
+{
+ UINT16 i;
+
+ for (i=0; i<MAX_PAN_CONNS; i++)
+ {
+ if (pan_cb.pcb[i].con_state != PAN_STATE_IDLE)
+ {
+ BNEP_Disconnect (pan_cb.pcb[i].handle);
+ pan_cb.pcb[i].con_state = PAN_STATE_IDLE;
+ }
+ }
+
+ pan_cb.active_role = PAN_ROLE_INACTIVE;
+ pan_cb.num_conns = 0;
+ return;
+}
+
+
+/*******************************************************************************
+**
+** Function pan_release_pcb
+**
+** Description This function releases a PCB.
+**
+** Returns void
+**
+*******************************************************************************/
+void pan_release_pcb (tPAN_CONN *p_pcb)
+{
+ /* Drop any response pointer we may be holding */
+ memset (p_pcb, 0, sizeof (tPAN_CONN));
+ p_pcb->con_state = PAN_STATE_IDLE;
+}
+
+
+/*******************************************************************************
+**
+** Function pan_dump_status
+**
+** Description This function dumps the pan control block and connection
+** blocks information
+**
+** Returns none
+**
+*******************************************************************************/
+void pan_dump_status (void)
+{
+#if (defined (PAN_SUPPORTS_DEBUG_DUMP) && PAN_SUPPORTS_DEBUG_DUMP == TRUE)
+ UINT16 i;
+ char buff[200];
+ tPAN_CONN *p_pcb;
+
+ PAN_TRACE_DEBUG3 ("PAN role %x, active role %d, num_conns %d",
+ pan_cb.role, pan_cb.active_role, pan_cb.num_conns);
+
+ for (i = 0, p_pcb = pan_cb.pcb; i < MAX_PAN_CONNS; i++, p_pcb++)
+ {
+ sprintf (buff, "%d state %d, handle %d, src 0x%x, dst 0x%x, BD %x.%x.%x.%x.%x.%x",
+ i, p_pcb->con_state, p_pcb->handle, p_pcb->src_uuid, p_pcb->dst_uuid,
+ p_pcb->rem_bda[0], p_pcb->rem_bda[1], p_pcb->rem_bda[2],
+ p_pcb->rem_bda[3], p_pcb->rem_bda[4], p_pcb->rem_bda[5]);
+
+ PAN_TRACE_DEBUG0 (buff);
+ }
+#endif
+}
+
+
+
diff --git a/stack/rfcomm/port_api.c b/stack/rfcomm/port_api.c
new file mode 100644
index 0000000..fe023a4
--- /dev/null
+++ b/stack/rfcomm/port_api.c
@@ -0,0 +1,1525 @@
+/*****************************************************************************
+**
+** Name: port_api.c
+**
+** Description: this file contains the Serial Port API code
+**
+**
+** Copyright (c) 1999-2009, Broadcom Corp., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+
+#include <string.h>
+#include "bt_target.h"
+#include "gki.h"
+#include "rfcdefs.h"
+#include "port_api.h"
+#include "port_int.h"
+#include "btm_int.h"
+#include "btm_api.h"
+#include "rfc_int.h"
+#include "l2c_api.h"
+#include "sdp_api.h"
+
+/* duration of break in 200ms units */
+#define PORT_BREAK_DURATION 1
+
+/*******************************************************************************
+**
+** Function RFCOMM_CreateConnection
+**
+** Description RFCOMM_CreateConnection function is used from the application
+** to establish serial port connection to the peer device,
+** or allow RFCOMM to accept a connection from the peer
+** application.
+**
+** Parameters: scn - Service Channel Number as registered with
+** the SDP (server) or obtained using SDP from
+** the peer device (client).
+** is_server - TRUE if requesting application is a server
+** mtu - Maximum frame size the application can accept
+** bd_addr - BD_ADDR of the peer (client)
+** mask - specifies events to be enabled. A value
+** of zero disables all events.
+** p_handle - OUT pointer to the handle.
+** p_mgmt_cb - pointer to callback function to receive
+** connection up/down events.
+** Notes:
+**
+** Server can call this function with the same scn parameter multiple times if
+** it is ready to accept multiple simulteneous connections.
+**
+** DLCI for the connection is (scn * 2 + 1) if client originates connection on
+** existing none initiator multiplexer channel. Otherwise it is (scn * 2).
+** For the server DLCI can be changed later if client will be calling it using
+** (scn * 2 + 1) dlci.
+**
+*******************************************************************************/
+int RFCOMM_CreateConnection (UINT16 uuid, UINT8 scn, BOOLEAN is_server,
+ UINT16 mtu, BD_ADDR bd_addr, UINT16 *p_handle,
+ tPORT_CALLBACK *p_mgmt_cb)
+{
+ tPORT *p_port;
+ int i;
+ UINT8 dlci;
+ tRFC_MCB *p_mcb = port_find_mcb (bd_addr);
+ UINT16 rfcomm_mtu;
+
+ RFCOMM_TRACE_API3 ("RFCOMM_CreateConnection() called SCN: %d is_server:%d mtu:%d",
+ scn, is_server, mtu);
+ RFCOMM_TRACE_API6 ("RFCOMM_CreateConnection() BDA: %02x-%02x-%02x-%02x-%02x-%02x",
+ bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
+
+ *p_handle = 0;
+
+ if (( scn == 0 )||(scn >= PORT_MAX_RFC_PORTS ))
+ {
+ /* Server Channel Number(SCN) should be in range 1...30 */
+ RFCOMM_TRACE_ERROR0 ("RFCOMM_CreateConnection - invalid SCN");
+ return (PORT_INVALID_SCN);
+ }
+
+ /* For client that originate connection on the existing none initiator */
+ /* multiplexer channel DLCI should be odd */
+ if (p_mcb && !p_mcb->is_initiator && !is_server)
+ dlci = (scn << 1) + 1;
+ else
+ dlci = (scn << 1);
+
+ /* For the server side always allocate a new port. On the client side */
+ /* do not allow the same (dlci, bd_addr) to be opened twice by application */
+ if (!is_server && ((p_port = port_find_port (dlci, bd_addr)) != NULL))
+ {
+ /* if existing port is also a client port */
+ if (p_port->is_server == FALSE)
+ {
+ RFCOMM_TRACE_ERROR3 ("RFCOMM_CreateConnection - already opened state:%d, RFC state:%d, MCB state:%d",
+ p_port->state, p_port->rfc.state, p_port->rfc.p_mcb ? p_port->rfc.p_mcb->state : 0);
+ return (PORT_ALREADY_OPENED);
+ }
+ }
+
+ if ((p_port = port_allocate_port (dlci, bd_addr)) == NULL)
+ {
+ RFCOMM_TRACE_WARNING0 ("RFCOMM_CreateConnection - no resources");
+ return (PORT_NO_RESOURCES);
+ }
+
+ p_port->default_signal_state = (PORT_DTRDSR_ON | PORT_CTSRTS_ON | PORT_DCD_ON);
+
+ switch (uuid)
+ {
+ case UUID_PROTOCOL_OBEX:
+ p_port->default_signal_state = PORT_OBEX_DEFAULT_SIGNAL_STATE;
+ break;
+ case UUID_SERVCLASS_SERIAL_PORT:
+ p_port->default_signal_state = PORT_SPP_DEFAULT_SIGNAL_STATE;
+ break;
+ case UUID_SERVCLASS_LAN_ACCESS_USING_PPP:
+ p_port->default_signal_state = PORT_PPP_DEFAULT_SIGNAL_STATE;
+ break;
+ case UUID_SERVCLASS_DIALUP_NETWORKING:
+ case UUID_SERVCLASS_FAX:
+ p_port->default_signal_state = PORT_DUN_DEFAULT_SIGNAL_STATE;
+ break;
+ }
+
+ RFCOMM_TRACE_EVENT2 ("RFCOMM_CreateConnection dlci:%d signal state:0x%x", dlci, p_port->default_signal_state);
+
+ *p_handle = p_port->inx;
+
+ p_port->state = PORT_STATE_OPENING;
+ p_port->uuid = uuid;
+ p_port->is_server = is_server;
+ p_port->scn = scn;
+ p_port->ev_mask = 0;
+
+ /* If the MTU is not specified (0), keep MTU decision until the
+ * PN frame has to be send
+ * at that time connection should be established and we
+ * will know for sure our prefered MTU
+ */
+
+ rfcomm_mtu = L2CAP_MTU_SIZE - RFCOMM_DATA_OVERHEAD;
+
+ if (mtu)
+ p_port->mtu = (mtu < rfcomm_mtu) ? mtu : rfcomm_mtu;
+ else
+ p_port->mtu = rfcomm_mtu;
+
+ /* server doesn't need to release port when closing */
+ if( is_server )
+ {
+ p_port->keep_port_handle = TRUE;
+
+ /* keep mtu that user asked, p_port->mtu could be updated during param negotiation */
+ p_port->keep_mtu = p_port->mtu;
+ }
+
+ p_port->local_ctrl.modem_signal = p_port->default_signal_state;
+ p_port->local_ctrl.fc = FALSE;
+
+ p_port->p_mgmt_callback = p_mgmt_cb;
+
+ for (i = 0; i < BD_ADDR_LEN; i++)
+ p_port->bd_addr[i] = bd_addr[i];
+
+ /* If this is not initiator of the connection need to just wait */
+ if (p_port->is_server)
+ {
+ return (PORT_SUCCESS);
+ }
+
+ /* Open will be continued after security checks are passed */
+ return port_open_continue (p_port);
+}
+
+
+/*******************************************************************************
+**
+** Function RFCOMM_RemoveConnection
+**
+** Description This function is called to close the specified connection.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+**
+*******************************************************************************/
+int RFCOMM_RemoveConnection (UINT16 handle)
+{
+ tPORT *p_port;
+
+ RFCOMM_TRACE_API1 ("RFCOMM_RemoveConnection() handle:%d", handle);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ RFCOMM_TRACE_ERROR1 ("RFCOMM_RemoveConnection() BAD handle:%d", handle);
+ return (PORT_BAD_HANDLE);
+ }
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ RFCOMM_TRACE_EVENT1 ("RFCOMM_RemoveConnection() Not opened:%d", handle);
+ return (PORT_SUCCESS);
+ }
+
+ p_port->state = PORT_STATE_CLOSING;
+
+ port_start_close (p_port);
+
+ return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function RFCOMM_RemoveServer
+**
+** Description This function is called to close the server port.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+**
+*******************************************************************************/
+int RFCOMM_RemoveServer (UINT16 handle)
+{
+ tPORT *p_port;
+
+ RFCOMM_TRACE_API1 ("RFCOMM_RemoveServer() handle:%d", handle);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ RFCOMM_TRACE_ERROR1 ("RFCOMM_RemoveServer() BAD handle:%d", handle);
+ return (PORT_BAD_HANDLE);
+ }
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ /* Do not report any events to the client any more. */
+ p_port->p_mgmt_callback = NULL;
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ RFCOMM_TRACE_EVENT1 ("RFCOMM_RemoveServer() Not opened:%d", handle);
+ return (PORT_SUCCESS);
+ }
+
+ /* this port will be deallocated after closing */
+ p_port->keep_port_handle = FALSE;
+ p_port->state = PORT_STATE_CLOSING;
+
+ port_start_close (p_port);
+
+ return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function PORT_SetEventCallback
+**
+** Description This function is called to provide an address of the
+** function which will be called when one of the events
+** specified in the mask occures.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** p_callback - address of the callback function which should
+** be called from the RFCOMM when an event
+** specified in the mask occures.
+**
+**
+*******************************************************************************/
+int PORT_SetEventCallback (UINT16 port_handle, tPORT_CALLBACK *p_port_cb)
+{
+ tPORT *p_port;
+
+ /* Check if handle is valid to avoid crashing */
+ if ((port_handle == 0) || (port_handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[port_handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ RFCOMM_TRACE_API1 ("PORT_SetEventCallback() handle:%d", port_handle);
+
+ p_port->p_callback = p_port_cb;
+
+ return (PORT_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_SetDataCallback
+**
+** Description This function is when a data packet is received
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** p_callback - address of the callback function which should
+** be called from the RFCOMM when data packet
+** is received.
+**
+**
+*******************************************************************************/
+int PORT_SetDataCallback (UINT16 port_handle, tPORT_DATA_CALLBACK *p_port_cb)
+{
+ tPORT *p_port;
+
+ RFCOMM_TRACE_API2 ("PORT_SetDataCallback() handle:%d cb 0x%x", port_handle, p_port_cb);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((port_handle == 0) || (port_handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[port_handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ p_port->p_data_callback = p_port_cb;
+
+ return (PORT_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_SetEventMask
+**
+** Description This function is called to close the specified connection.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** mask - Bitmask of the events the host is interested in
+**
+*******************************************************************************/
+int PORT_SetEventMask (UINT16 port_handle, UINT32 mask)
+{
+ tPORT *p_port;
+
+ RFCOMM_TRACE_API2 ("PORT_SetEventMask() handle:%d mask:0x%x", port_handle, mask);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((port_handle == 0) || (port_handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[port_handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ p_port->ev_mask = mask;
+
+ return (PORT_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_CheckConnection
+**
+** Description This function returns PORT_SUCCESS if connection referenced
+** by handle is up and running
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** bd_addr - OUT bd_addr of the peer
+** p_lcid - OUT L2CAP's LCID
+**
+*******************************************************************************/
+int PORT_CheckConnection (UINT16 handle, BD_ADDR bd_addr, UINT16 *p_lcid)
+{
+ tPORT *p_port;
+
+ RFCOMM_TRACE_API1 ("PORT_CheckConnection() handle:%d", handle);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ if (!p_port->rfc.p_mcb
+ || !p_port->rfc.p_mcb->peer_ready
+ || (p_port->rfc.state != RFC_STATE_OPENED))
+ {
+ return (PORT_LINE_ERR);
+ }
+
+ memcpy (bd_addr, p_port->rfc.p_mcb->bd_addr, BD_ADDR_LEN);
+ if (p_lcid)
+ *p_lcid = p_port->rfc.p_mcb->lcid;
+
+ return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function PORT_IsOpening
+**
+** Description This function returns TRUE if there is any RFCOMM connection
+** opening in process.
+**
+** Parameters: TRUE if any connection opening is found
+** bd_addr - bd_addr of the peer
+**
+*******************************************************************************/
+BOOLEAN PORT_IsOpening (BD_ADDR bd_addr)
+{
+ UINT8 xx, yy;
+ tRFC_MCB *p_mcb = NULL;
+ tPORT *p_port;
+ BOOLEAN found_port;
+
+ /* Check for any rfc_mcb which is in the middle of opening. */
+ for (xx = 0; xx < MAX_BD_CONNECTIONS; xx++)
+ {
+ if ((rfc_cb.port.rfc_mcb[xx].state > RFC_MX_STATE_IDLE) &&
+ (rfc_cb.port.rfc_mcb[xx].state < RFC_MX_STATE_CONNECTED))
+ {
+ memcpy (bd_addr, rfc_cb.port.rfc_mcb[xx].bd_addr, BD_ADDR_LEN);
+ return TRUE;
+ }
+
+ if (rfc_cb.port.rfc_mcb[xx].state == RFC_MX_STATE_CONNECTED)
+ {
+ found_port = FALSE;
+ p_mcb = &rfc_cb.port.rfc_mcb[xx];
+ p_port = &rfc_cb.port.port[0];
+
+ for (yy = 0; yy < MAX_RFC_PORTS; yy++, p_port++)
+ {
+ if (p_port->rfc.p_mcb == p_mcb)
+ {
+ found_port = TRUE;
+ break;
+ }
+ }
+
+ if ((!found_port) ||
+ (found_port && (p_port->rfc.state < RFC_STATE_OPENED)))
+ {
+ /* Port is not established yet. */
+ memcpy (bd_addr, rfc_cb.port.rfc_mcb[xx].bd_addr, BD_ADDR_LEN);
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function PORT_SetState
+**
+** Description This function configures connection according to the
+** specifications in the tPORT_STATE structure.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** p_settings - Pointer to a tPORT_STATE structure containing
+** configuration information for the connection.
+**
+**
+*******************************************************************************/
+int PORT_SetState (UINT16 handle, tPORT_STATE *p_settings)
+{
+ tPORT *p_port;
+ UINT8 baud_rate;
+
+ RFCOMM_TRACE_API1 ("PORT_SetState() handle:%d", handle);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ if (p_port->line_status)
+ {
+ return (PORT_LINE_ERR);
+ }
+
+ RFCOMM_TRACE_API2 ("PORT_SetState() handle:%d FC_TYPE:0x%x", handle,
+ p_settings->fc_type);
+
+ baud_rate = p_port->user_port_pars.baud_rate;
+ p_port->user_port_pars = *p_settings;
+
+ /* for now we've been asked to pass only baud rate */
+ if (baud_rate != p_settings->baud_rate)
+ {
+ port_start_par_neg (p_port);
+ }
+ return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function PORT_GetRxQueueCnt
+**
+** Description This function return number of buffers on the rx queue.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** p_rx_queue_count - Pointer to return queue count in.
+**
+*******************************************************************************/
+int PORT_GetRxQueueCnt (UINT16 handle, UINT16 *p_rx_queue_count)
+{
+ tPORT *p_port;
+
+ RFCOMM_TRACE_API1 ("PORT_GetRxQueueCnt() handle:%d", handle);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ if (p_port->line_status)
+ {
+ return (PORT_LINE_ERR);
+ }
+
+ *p_rx_queue_count = p_port->rx.queue_size;
+
+ RFCOMM_TRACE_API2 ("PORT_GetRxQueueCnt() p_rx_queue_count:%d, p_port->rx.queue.count = %d",
+ *p_rx_queue_count, p_port->rx.queue_size);
+
+ return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function PORT_GetState
+**
+** Description This function is called to fill tPORT_STATE structure
+** with the curremt control settings for the port
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** p_settings - Pointer to a tPORT_STATE structure in which
+** configuration information is returned.
+**
+*******************************************************************************/
+int PORT_GetState (UINT16 handle, tPORT_STATE *p_settings)
+{
+ tPORT *p_port;
+
+ RFCOMM_TRACE_API1 ("PORT_GetState() handle:%d", handle);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ if (p_port->line_status)
+ {
+ return (PORT_LINE_ERR);
+ }
+
+ *p_settings = p_port->user_port_pars;
+ return (PORT_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_Control
+**
+** Description This function directs a specified connection to pass control
+** control information to the peer device.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** signal = specify the function to be passed
+**
+*******************************************************************************/
+int PORT_Control (UINT16 handle, UINT8 signal)
+{
+ tPORT *p_port;
+ UINT8 old_modem_signal;
+
+ RFCOMM_TRACE_API2 ("PORT_Control() handle:%d signal:0x%x", handle, signal);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ old_modem_signal = p_port->local_ctrl.modem_signal;
+ p_port->local_ctrl.break_signal = 0;
+
+ switch (signal)
+ {
+ case PORT_SET_CTSRTS:
+ p_port->local_ctrl.modem_signal |= PORT_CTSRTS_ON;
+ break;
+
+ case PORT_CLR_CTSRTS:
+ p_port->local_ctrl.modem_signal &= ~PORT_CTSRTS_ON;
+ break;
+
+ case PORT_SET_DTRDSR:
+ p_port->local_ctrl.modem_signal |= PORT_DTRDSR_ON;
+ break;
+
+ case PORT_CLR_DTRDSR:
+ p_port->local_ctrl.modem_signal &= ~PORT_DTRDSR_ON;
+ break;
+
+ case PORT_SET_RI:
+ p_port->local_ctrl.modem_signal |= PORT_RING_ON;
+ break;
+
+ case PORT_CLR_RI:
+ p_port->local_ctrl.modem_signal &= ~PORT_RING_ON;
+ break;
+
+ case PORT_SET_DCD:
+ p_port->local_ctrl.modem_signal |= PORT_DCD_ON;
+ break;
+
+ case PORT_CLR_DCD:
+ p_port->local_ctrl.modem_signal &= ~PORT_DCD_ON;
+ break;
+ }
+
+ if (signal == PORT_BREAK)
+ p_port->local_ctrl.break_signal = PORT_BREAK_DURATION;
+ else if (p_port->local_ctrl.modem_signal == old_modem_signal)
+ return (PORT_SUCCESS);
+
+ port_start_control (p_port);
+
+ RFCOMM_TRACE_EVENT4 ("PORT_Control DTR_DSR : %d, RTS_CTS : %d, RI : %d, DCD : %d",
+ ((p_port->local_ctrl.modem_signal & MODEM_SIGNAL_DTRDSR) ? 1 : 0),
+ ((p_port->local_ctrl.modem_signal & MODEM_SIGNAL_RTSCTS) ? 1 : 0),
+ ((p_port->local_ctrl.modem_signal & MODEM_SIGNAL_RI) ? 1 : 0),
+ ((p_port->local_ctrl.modem_signal & MODEM_SIGNAL_DCD) ? 1 : 0));
+
+ return (PORT_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_FlowControl
+**
+** Description This function directs a specified connection to pass
+** flow control message to the peer device. Enable flag passed
+** shows if port can accept more data.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** enable - enables data flow
+**
+*******************************************************************************/
+int PORT_FlowControl (UINT16 handle, BOOLEAN enable)
+{
+ tPORT *p_port;
+ BOOLEAN old_fc;
+ UINT32 events;
+
+ RFCOMM_TRACE_API2 ("PORT_FlowControl() handle:%d enable: %d", handle, enable);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ if (!p_port->rfc.p_mcb)
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ p_port->rx.user_fc = !enable;
+
+ if (p_port->rfc.p_mcb->flow == PORT_FC_CREDIT)
+ {
+ if (!p_port->rx.user_fc)
+ {
+ port_flow_control_peer(p_port, TRUE, 0);
+ }
+ }
+ else
+ {
+ old_fc = p_port->local_ctrl.fc;
+
+ /* FC is set if user is set or peer is set */
+ p_port->local_ctrl.fc = (p_port->rx.user_fc | p_port->rx.peer_fc);
+
+ if (p_port->local_ctrl.fc != old_fc)
+ port_start_control (p_port);
+ }
+
+ /* Need to take care of the case when we could not deliver events */
+ /* to the application because we were flow controlled */
+ if (enable && (p_port->rx.queue_size != 0))
+ {
+ events = PORT_EV_RXCHAR;
+ if (p_port->rx_flag_ev_pending)
+ {
+ p_port->rx_flag_ev_pending = FALSE;
+ events |= PORT_EV_RXFLAG;
+ }
+
+ events &= p_port->ev_mask;
+ if (p_port->p_callback && events)
+ {
+ p_port->p_callback (events, p_port->inx);
+ }
+ }
+ return (PORT_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_GetModemStatus
+**
+** Description This function retrieves modem control signals. Normally
+** application will call this function after a callback
+** function is called with notification that one of signals
+** has been changed.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** p_signal - specify the pointer to control signals info
+**
+*******************************************************************************/
+int PORT_GetModemStatus (UINT16 handle, UINT8 *p_signal)
+{
+ tPORT *p_port;
+
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ *p_signal = p_port->peer_ctrl.modem_signal;
+
+ RFCOMM_TRACE_API2 ("PORT_GetModemStatus() handle:%d signal:%x", handle, *p_signal);
+
+ return (PORT_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_ClearError
+**
+** Description This function retreives information about a communications
+** error and reports current status of a connection. The
+** function should be called when an error occures to clear
+** the connection error flag and to enable additional read
+** and write operations.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** p_errors - pointer of the variable to receive error codes
+** p_status - pointer to the tPORT_STATUS structur to receive
+** connection status
+**
+*******************************************************************************/
+int PORT_ClearError (UINT16 handle, UINT16 *p_errors, tPORT_STATUS *p_status)
+{
+ tPORT *p_port;
+
+ RFCOMM_TRACE_API1 ("PORT_ClearError() handle:%d", handle);
+
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ *p_errors = p_port->line_status;
+
+ /* This is the only call to clear error status. We can not clear */
+ /* connection failed status. To clean it port should be closed and reopened */
+ p_port->line_status = (p_port->line_status & LINE_STATUS_FAILED);
+
+ PORT_GetQueueStatus (handle, p_status);
+ return (PORT_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_SendError
+**
+** Description This function send a communications error to the peer device
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** errors - receive error codes
+**
+*******************************************************************************/
+int PORT_SendError (UINT16 handle, UINT8 errors)
+{
+ tPORT *p_port;
+
+ RFCOMM_TRACE_API2 ("PORT_SendError() handle:%d errors:0x%x", handle, errors);
+
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ if (!p_port->rfc.p_mcb)
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ RFCOMM_LineStatusReq (p_port->rfc.p_mcb, p_port->dlci, errors);
+ return (PORT_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_GetQueueStatus
+**
+** Description This function reports current status of a connection.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** p_status - pointer to the tPORT_STATUS structur to receive
+** connection status
+**
+*******************************************************************************/
+int PORT_GetQueueStatus (UINT16 handle, tPORT_STATUS *p_status)
+{
+ tPORT *p_port;
+
+ /* RFCOMM_TRACE_API1 ("PORT_GetQueueStatus() handle:%d", handle); */
+
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ p_status->in_queue_size = (UINT16) p_port->rx.queue_size;
+ p_status->out_queue_size = (UINT16) p_port->tx.queue_size;
+
+ p_status->mtu_size = (UINT16) p_port->peer_mtu;
+
+ p_status->flags = 0;
+
+ if (!(p_port->peer_ctrl.modem_signal & PORT_CTSRTS_ON))
+ p_status->flags |= PORT_FLAG_CTS_HOLD;
+
+ if (!(p_port->peer_ctrl.modem_signal & PORT_DTRDSR_ON))
+ p_status->flags |= PORT_FLAG_DSR_HOLD;
+
+ if (!(p_port->peer_ctrl.modem_signal & PORT_DCD_ON))
+ p_status->flags |= PORT_FLAG_RLSD_HOLD;
+
+ return (PORT_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_Purge
+**
+** Description This function discards all the data from the output or
+** input queues of the specified connection.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** purge_flags - specify the action to take.
+**
+*******************************************************************************/
+int PORT_Purge (UINT16 handle, UINT8 purge_flags)
+{
+ tPORT *p_port;
+ BT_HDR *p_buf;
+ UINT16 count;
+ UINT32 events;
+
+ RFCOMM_TRACE_API2 ("PORT_Purge() handle:%d flags:0x%x", handle, purge_flags);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ if (purge_flags & PORT_PURGE_RXCLEAR)
+ {
+ PORT_SCHEDULE_LOCK; /* to prevent missing credit */
+
+ count = p_port->rx.queue.count;
+
+ while ((p_buf = (BT_HDR *)GKI_dequeue (&p_port->rx.queue)) != NULL)
+ GKI_freebuf (p_buf);
+
+ p_port->rx.queue_size = 0;
+
+ PORT_SCHEDULE_UNLOCK;
+
+ /* If we flowed controlled peer based on rx_queue size enable data again */
+ if (count)
+ port_flow_control_peer (p_port, TRUE, count);
+ }
+
+ if (purge_flags & PORT_PURGE_TXCLEAR)
+ {
+ PORT_SCHEDULE_LOCK; /* to prevent tx.queue_size from being negative */
+
+ while ((p_buf = (BT_HDR *)GKI_dequeue (&p_port->tx.queue)) != NULL)
+ GKI_freebuf (p_buf);
+
+ p_port->tx.queue_size = 0;
+
+ PORT_SCHEDULE_UNLOCK;
+
+ events = PORT_EV_TXEMPTY;
+
+ events |= port_flow_control_user (p_port);
+
+ events &= p_port->ev_mask;
+
+ if ((p_port->p_callback != NULL) && events)
+ (p_port->p_callback)(events, p_port->inx);
+ }
+
+ return (PORT_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_ReadData
+**
+** Description Normally not GKI aware application will call this function
+** after receiving PORT_EV_RXCHAR event.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** p_data - Data area
+** max_len - Byte count requested
+** p_len - Byte count received
+**
+*******************************************************************************/
+int PORT_ReadData (UINT16 handle, char *p_data, UINT16 max_len, UINT16 *p_len)
+{
+ tPORT *p_port;
+ BT_HDR *p_buf;
+ UINT16 count;
+
+ RFCOMM_TRACE_API2 ("PORT_ReadData() handle:%d max_len:%d", handle, max_len);
+
+ /* Initialize this in case of an error */
+ *p_len = 0;
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ if (p_port->line_status)
+ {
+ return (PORT_LINE_ERR);
+ }
+
+ p_buf = (BT_HDR *)GKI_getfirst (&p_port->rx.queue);
+ if (!p_buf)
+ return (PORT_SUCCESS);
+
+ count = 0;
+
+ while (max_len && p_buf)
+ {
+ if (p_buf->len > max_len)
+ {
+ memcpy (p_data, (UINT8 *)(p_buf + 1) + p_buf->offset, max_len);
+ p_buf->offset += max_len;
+ p_buf->len -= max_len;
+
+ *p_len += max_len;
+
+ PORT_SCHEDULE_LOCK;
+
+ p_port->rx.queue_size -= max_len;
+
+ PORT_SCHEDULE_UNLOCK;
+
+ break;
+ }
+ else
+ {
+ memcpy (p_data, (UINT8 *)(p_buf + 1) + p_buf->offset, p_buf->len);
+
+ *p_len += p_buf->len;
+ max_len -= p_buf->len;
+
+ PORT_SCHEDULE_LOCK;
+
+ p_port->rx.queue_size -= p_buf->len;
+
+ if (max_len)
+ {
+ p_data += p_buf->len;
+ p_buf = (BT_HDR *)GKI_getnext (p_buf);
+ }
+
+ GKI_freebuf (GKI_dequeue (&p_port->rx.queue));
+
+ PORT_SCHEDULE_UNLOCK;
+
+ count++;
+ }
+ }
+
+ if (*p_len == 1)
+ {
+ RFCOMM_TRACE_EVENT3 ("PORT_ReadData queue:%d returned:%d %x", p_port->rx.queue_size, *p_len, (p_data[0]));
+ }
+ else
+ {
+ RFCOMM_TRACE_EVENT2 ("PORT_ReadData queue:%d returned:%d", p_port->rx.queue_size, *p_len);
+ }
+
+ /* If rfcomm suspended traffic from the peer based on the rx_queue_size */
+ /* check if it can be resumed now */
+ port_flow_control_peer (p_port, TRUE, count);
+
+ return (PORT_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_Read
+**
+** Description Normally application will call this function after receiving
+** PORT_EV_RXCHAR event.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** pp_buf - pointer to address of buffer with data,
+**
+*******************************************************************************/
+int PORT_Read (UINT16 handle, BT_HDR **pp_buf)
+{
+ tPORT *p_port;
+ BT_HDR *p_buf;
+
+ RFCOMM_TRACE_API1 ("PORT_Read() handle:%d", handle);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ if (p_port->line_status)
+ {
+ return (PORT_LINE_ERR);
+ }
+
+ PORT_SCHEDULE_LOCK;
+
+ p_buf = (BT_HDR *)GKI_dequeue (&p_port->rx.queue);
+ if (p_buf)
+ {
+ p_port->rx.queue_size -= p_buf->len;
+
+ PORT_SCHEDULE_UNLOCK;
+
+ /* If rfcomm suspended traffic from the peer based on the rx_queue_size */
+ /* check if it can be resumed now */
+ port_flow_control_peer (p_port, TRUE, 1);
+ }
+ else
+ {
+ PORT_SCHEDULE_UNLOCK;
+ }
+
+ *pp_buf = p_buf;
+ return (PORT_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function port_write
+**
+** Description This function when a data packet is received from the apper
+** layer task.
+**
+** Parameters: p_port - pointer to address of port control block
+** p_buf - pointer to address of buffer with data,
+**
+*******************************************************************************/
+static int port_write (tPORT *p_port, BT_HDR *p_buf)
+{
+ /* We should not allow to write data in to server port when connection is not opened */
+ if (p_port->is_server && (p_port->rfc.state != RFC_STATE_OPENED))
+ {
+ GKI_freebuf (p_buf);
+ return (PORT_CLOSED);
+ }
+
+ /* Keep the data in pending queue if peer does not allow data, or */
+ /* Peer is not ready or Port is not yet opened or initial port control */
+ /* command has not been sent */
+ if (p_port->tx.peer_fc
+ || !p_port->rfc.p_mcb
+ || !p_port->rfc.p_mcb->peer_ready
+ || (p_port->rfc.state != RFC_STATE_OPENED)
+ || ((p_port->port_ctrl & (PORT_CTRL_REQ_SENT | PORT_CTRL_IND_RECEIVED)) !=
+ (PORT_CTRL_REQ_SENT | PORT_CTRL_IND_RECEIVED)))
+ {
+ if ((p_port->tx.queue_size > PORT_TX_CRITICAL_WM)
+ || (p_port->tx.queue.count > PORT_TX_BUF_CRITICAL_WM))
+ {
+ RFCOMM_TRACE_WARNING1 ("PORT_Write: Queue size: %d",
+ p_port->tx.queue_size);
+
+ GKI_freebuf (p_buf);
+
+ if ((p_port->p_callback != NULL) && (p_port->ev_mask & PORT_EV_ERR))
+ p_port->p_callback (PORT_EV_ERR, p_port->inx);
+
+ return (PORT_TX_FULL);
+ }
+
+ RFCOMM_TRACE_EVENT4 ("PORT_Write : Data is enqued. flow disabled %d peer_ready %d state %d ctrl_state %x",
+ p_port->tx.peer_fc,
+ (p_port->rfc.p_mcb && p_port->rfc.p_mcb->peer_ready),
+ p_port->rfc.state,
+ p_port->port_ctrl);
+
+ GKI_enqueue (&p_port->tx.queue, p_buf);
+ p_port->tx.queue_size += p_buf->len;
+
+ return (PORT_CMD_PENDING);
+ }
+ else
+ {
+ RFCOMM_TRACE_EVENT0 ("PORT_Write : Data is being sent");
+
+ RFCOMM_DataReq (p_port->rfc.p_mcb, p_port->dlci, p_buf);
+ return (PORT_SUCCESS);
+ }
+}
+
+/*******************************************************************************
+**
+** Function PORT_Write
+**
+** Description This function when a data packet is received from the apper
+** layer task.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** pp_buf - pointer to address of buffer with data,
+**
+*******************************************************************************/
+int PORT_Write (UINT16 handle, BT_HDR *p_buf)
+{
+ tPORT *p_port;
+ UINT32 event = 0;
+ int rc;
+
+ RFCOMM_TRACE_API1 ("PORT_Write() handle:%d", handle);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ GKI_freebuf (p_buf);
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ GKI_freebuf (p_buf);
+ return (PORT_NOT_OPENED);
+ }
+
+ if (p_port->line_status)
+ {
+ RFCOMM_TRACE_WARNING1 ("PORT_Write: Data dropped line_status:0x%x",
+ p_port->line_status);
+ GKI_freebuf (p_buf);
+ return (PORT_LINE_ERR);
+ }
+
+ rc = port_write (p_port, p_buf);
+ event |= port_flow_control_user (p_port);
+
+ switch (rc)
+ {
+ case PORT_TX_FULL:
+ event |= PORT_EV_ERR;
+ break;
+
+ case PORT_SUCCESS:
+ event |= (PORT_EV_TXCHAR | PORT_EV_TXEMPTY);
+ break;
+ }
+ /* Mask out all events that are not of interest to user */
+ event &= p_port->ev_mask;
+
+ /* Send event to the application */
+ if (p_port->p_callback && event)
+ (p_port->p_callback)(event, p_port->inx);
+
+ return (PORT_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_WriteData
+**
+** Description Normally not GKI aware application will call this function
+** to send data to the port.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** p_data - Data area
+** max_len - Byte count requested
+** p_len - Byte count received
+**
+*******************************************************************************/
+int PORT_WriteData (UINT16 handle, char *p_data, UINT16 max_len, UINT16 *p_len)
+{
+ tPORT *p_port;
+ BT_HDR *p_buf;
+ UINT32 event = 0;
+ int rc = 0;
+ UINT16 length;
+
+ RFCOMM_TRACE_API1 ("PORT_WriteData() max_len:%d", max_len);
+
+ *p_len = 0;
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ RFCOMM_TRACE_WARNING1 ("PORT_WriteData() no port state:%d", p_port->state);
+ return (PORT_NOT_OPENED);
+ }
+
+ if (!max_len || !p_port->peer_mtu)
+ {
+ RFCOMM_TRACE_ERROR1 ("PORT_WriteData() peer_mtu:%d", p_port->peer_mtu);
+ return (PORT_UNKNOWN_ERROR);
+ }
+
+ /* Length for each buffer is the smaller of GKI buffer, peer MTU, or max_len */
+ length = RFCOMM_DATA_POOL_BUF_SIZE -
+ (UINT16)(sizeof(BT_HDR) + L2CAP_MIN_OFFSET + RFCOMM_DATA_OVERHEAD);
+
+ /* If there are buffers scheduled for transmission check if requested */
+ /* data fits into the end of the queue */
+ PORT_SCHEDULE_LOCK;
+
+ if (((p_buf = (BT_HDR *)p_port->tx.queue.p_last) != NULL)
+ && ((p_buf->len + max_len) <= p_port->peer_mtu)
+ && ((p_buf->len + max_len) <= length))
+ {
+ memcpy ((UINT8 *)(p_buf + 1) + p_buf->offset + p_buf->len, p_data, max_len);
+ p_port->tx.queue_size += max_len;
+
+ *p_len = max_len;
+ p_buf->len += max_len;
+
+ PORT_SCHEDULE_UNLOCK;
+
+ return (PORT_SUCCESS);
+ }
+
+ PORT_SCHEDULE_UNLOCK;
+
+ while (max_len)
+ {
+ /* if we're over buffer high water mark, we're done */
+ if ((p_port->tx.queue_size > PORT_TX_HIGH_WM)
+ || (p_port->tx.queue.count > PORT_TX_BUF_HIGH_WM))
+ break;
+
+ /* continue with rfcomm data write */
+ p_buf = (BT_HDR *)GKI_getpoolbuf (RFCOMM_DATA_POOL_ID);
+ if (!p_buf)
+ break;
+
+ p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_MIN_OFFSET;
+ p_buf->layer_specific = handle;
+
+ if (p_port->peer_mtu < length)
+ length = p_port->peer_mtu;
+ if (max_len < length)
+ length = max_len;
+ p_buf->len = length;
+ p_buf->event = BT_EVT_TO_BTU_SP_DATA;
+
+ memcpy ((UINT8 *)(p_buf + 1) + p_buf->offset, p_data, length);
+
+ RFCOMM_TRACE_EVENT1 ("PORT_WriteData %d bytes", length);
+
+ rc = port_write (p_port, p_buf);
+
+ /* If queue went below the threashold need to send flow control */
+ event |= port_flow_control_user (p_port);
+
+ if (rc == PORT_SUCCESS)
+ event |= PORT_EV_TXCHAR;
+
+ if ((rc != PORT_SUCCESS) && (rc != PORT_CMD_PENDING))
+ break;
+
+ *p_len += length;
+ max_len -= length;
+ p_data += length;
+
+ }
+ if (!max_len && (rc != PORT_CMD_PENDING) && (rc != PORT_TX_QUEUE_DISABLED))
+ event |= PORT_EV_TXEMPTY;
+
+ /* Mask out all events that are not of interest to user */
+ event &= p_port->ev_mask;
+
+ /* Send event to the application */
+ if (p_port->p_callback && event)
+ (p_port->p_callback)(event, p_port->inx);
+
+ return (PORT_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_Test
+**
+** Description Application can call this function to send RFCOMM Test frame
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** p_data - Data area
+** max_len - Byte count requested
+**
+*******************************************************************************/
+int PORT_Test (UINT16 handle, UINT8 *p_data, UINT16 len)
+{
+ BT_HDR *p_buf;
+ tPORT *p_port;
+
+ RFCOMM_TRACE_API1 ("PORT_Test() len:%d", len);
+
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ if (len > ((p_port->mtu == 0) ? RFCOMM_DEFAULT_MTU : p_port->mtu))
+ {
+ return (PORT_UNKNOWN_ERROR);
+ }
+
+ if ((p_buf = (BT_HDR *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) != NULL)
+ {
+
+ p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_MIN_OFFSET + 2;
+ p_buf->len = len;
+
+ memcpy ((UINT8 *)(p_buf + 1) + p_buf->offset, p_data, p_buf->len);
+
+ rfc_send_test (p_port->rfc.p_mcb, TRUE, p_buf);
+ return (PORT_SUCCESS);
+ }
+ else
+ {
+ return (PORT_NO_MEM);
+ }
+}
+
+/*******************************************************************************
+**
+** Function RFCOMM_Init
+**
+** Description This function is called to initialize RFCOMM layer
+**
+*******************************************************************************/
+void RFCOMM_Init (void)
+{
+ memset (&rfc_cb, 0, sizeof (tRFC_CB)); /* Init RFCOMM control block */
+
+ rfc_cb.rfc.last_mux = MAX_BD_CONNECTIONS;
+
+#if defined(RFCOMM_INITIAL_TRACE_LEVEL)
+ rfc_cb.trace_level = RFCOMM_INITIAL_TRACE_LEVEL;
+#else
+ rfc_cb.trace_level = BT_TRACE_LEVEL_NONE; /* No traces */
+#endif
+
+ rfcomm_l2cap_if_init ();
+}
+
+/*******************************************************************************
+**
+** Function PORT_SetTraceLevel
+**
+** Description This function sets the trace level for RFCOMM. If called with
+** a value of 0xFF, it simply reads the current trace level.
+**
+** Returns the new (current) trace level
+**
+*******************************************************************************/
+UINT8 PORT_SetTraceLevel (UINT8 new_level)
+{
+ if (new_level != 0xFF)
+ rfc_cb.trace_level = new_level;
+
+ return (rfc_cb.trace_level);
+}
+
diff --git a/stack/rfcomm/port_int.h b/stack/rfcomm/port_int.h
new file mode 100644
index 0000000..acd56b7
--- /dev/null
+++ b/stack/rfcomm/port_int.h
@@ -0,0 +1,237 @@
+/*****************************************************************************/
+/* */
+/* Name: port_int.h */
+/* */
+/* Description: This file contains definitions internal to the PORT unit */
+/* */
+/* */
+/* Copyright (c) 1999-2009, Broadcom Corp., All Rights Reserved. */
+/* Broadcom Bluetooth Core. Proprietary and confidential. */
+/*****************************************************************************/
+#ifndef PORT_INT_H
+#define PORT_INT_H
+
+#include "bt_target.h"
+#include "gki.h"
+#include "rfcdefs.h"
+#include "port_api.h"
+
+/* Local events passed when application event is sent from the api to PORT */
+/* ???*/
+#define PORT_EVENT_OPEN (1 | BT_EVT_TO_BTU_SP_EVT)
+#define PORT_EVENT_CONTROL (2 | BT_EVT_TO_BTU_SP_EVT)
+#define PORT_EVENT_SET_STATE (3 | BT_EVT_TO_BTU_SP_EVT)
+#define PORT_EVENT_SET_CALLBACK (5 | BT_EVT_TO_BTU_SP_EVT)
+#define PORT_EVENT_WRITE (6 | BT_EVT_TO_BTU_SP_EVT)
+#define PORT_EVENT_PURGE (7 | BT_EVT_TO_BTU_SP_EVT)
+#define PORT_EVENT_SEND_ERROR (8 | BT_EVT_TO_BTU_SP_EVT)
+#define PORT_EVENT_FLOW_CONTROL (9 | BT_EVT_TO_BTU_SP_EVT)
+
+/*
+** Flow control configuration values for the mux
+*/
+#define PORT_FC_UNDEFINED 0 /* mux flow control mechanism not defined yet */
+#define PORT_FC_TS710 1 /* use TS 07.10 flow control */
+#define PORT_FC_CREDIT 2 /* use RFCOMM credit based flow control */
+
+/*
+** Define Port Data Transfere control block
+*/
+typedef struct
+{
+ BUFFER_Q queue; /* Queue of buffers waiting to be sent */
+ BOOLEAN peer_fc; /* TRUE if flow control is set based on peer's request */
+ BOOLEAN user_fc; /* TRUE if flow control is set based on user's request */
+ UINT32 queue_size; /* Number of data bytes in the queue */
+ tPORT_CALLBACK *p_callback; /* Address of the callback function */
+} tPORT_DATA;
+
+/*
+** Port control structure used to pass modem info
+*/
+typedef struct
+{
+#define MODEM_SIGNAL_DTRDSR 0x01
+#define MODEM_SIGNAL_RTSCTS 0x02
+#define MODEM_SIGNAL_RI 0x04
+#define MODEM_SIGNAL_DCD 0x08
+
+ UINT8 modem_signal; /* [DTR/DSR | RTS/CTS | RI | DCD ] */
+
+ UINT8 break_signal; /* 0-3 s in steps of 200 ms */
+
+ UINT8 discard_buffers; /* 0 - do not discard, 1 - discard */
+
+#define RFCOMM_CTRL_BREAK_ASAP 0
+#define RFCOMM_CTRL_BREAK_IN_SEQ 1
+
+ UINT8 break_signal_seq; /* as soon as possible | in sequence (default) */
+
+ BOOLEAN fc; /* TRUE when the device is unable to accept frames */
+} tPORT_CTRL;
+
+
+/*
+** RFCOMM multiplexer Control Block
+*/
+typedef struct
+{
+ TIMER_LIST_ENT tle; /* Timer list entry */
+ BUFFER_Q cmd_q; /* Queue for command messages on this mux */
+ UINT8 port_inx[RFCOMM_MAX_DLCI + 1]; /* Array for quick access to */
+ /* tPORT based on dlci */
+ BD_ADDR bd_addr; /* BD ADDR of the peer if initiator */
+ UINT16 lcid; /* Local cid used for this channel */
+ UINT16 peer_l2cap_mtu; /* Max frame that can be sent to peer L2CAP */
+ UINT8 state; /* Current multiplexer channel state */
+ UINT8 is_initiator; /* TRUE if this side sends SABME (dlci=0) */
+ BOOLEAN local_cfg_sent;
+ BOOLEAN peer_cfg_rcvd;
+ BOOLEAN restart_required; /* TRUE if has to restart channel after disc */
+ BOOLEAN peer_ready; /* True if other side can accept frames */
+ UINT8 flow; /* flow control mechanism for this mux */
+ BOOLEAN l2cap_congested; /* TRUE if L2CAP is congested */
+ BOOLEAN is_disc_initiator; /* TRUE if initiated disc of port */
+ UINT16 pending_lcid; /* store LCID for incoming connection while connecting */
+ UINT8 pending_id; /* store l2cap ID for incoming connection while connecting */
+} tRFC_MCB;
+
+
+/*
+** RFCOMM Port Connection Control Block
+*/
+struct t_rfc_port
+{
+#define RFC_PORT_STATE_IDLE 0
+#define RFC_PORT_STATE_WAIT_START 1
+#define RFC_PORT_STATE_OPENING 2
+#define RFC_PORT_STATE_OPENED 3
+#define RFC_PORT_STATE_CLOSING 4
+
+ UINT8 state; /* Current state of the connection */
+
+#define RFC_RSP_PN 0x01
+#define RFC_RSP_RPN_REPLY 0x02
+#define RFC_RSP_RPN 0x04
+#define RFC_RSP_MSC 0x08
+#define RFC_RSP_RLS 0x10
+
+ UINT8 expected_rsp;
+
+ tRFC_MCB *p_mcb;
+
+ TIMER_LIST_ENT tle; /* Timer list entry */
+};
+typedef struct t_rfc_port tRFC_PORT;
+
+
+/*
+** Define control block containing information about PORT connection
+*/
+struct t_port_info
+{
+ UINT8 inx; /* Index of this control block in the port_info array */
+ BOOLEAN in_use; /* True when structure is allocated */
+
+#define PORT_STATE_CLOSED 0
+#define PORT_STATE_OPENING 1
+#define PORT_STATE_OPENED 2
+#define PORT_STATE_CLOSING 3
+
+ UINT8 state; /* State of the application */
+
+ UINT8 scn; /* Service channel number */
+ UINT16 uuid; /* Service UUID */
+
+ BD_ADDR bd_addr; /* BD ADDR of the device for the multiplexer channel */
+ BOOLEAN is_server; /* TRUE if the server application */
+ UINT8 dlci; /* DLCI of the connection */
+
+ UINT8 error; /* Last error detected */
+
+ UINT8 line_status; /* Line status as reported by peer */
+
+ UINT8 default_signal_state; /* Initial signal state depending on uuid */
+
+ UINT16 mtu; /* Max MTU that port can receive */
+ UINT16 peer_mtu; /* Max MTU that port can send */
+
+ tPORT_DATA tx; /* Control block for data from app to peer */
+ tPORT_DATA rx; /* Control block for data from peer to app */
+
+ tPORT_STATE user_port_pars; /* Port parameters for user connection */
+ tPORT_STATE peer_port_pars; /* Port parameters for user connection */
+
+ tPORT_CTRL local_ctrl;
+ tPORT_CTRL peer_ctrl;
+
+#define PORT_CTRL_REQ_SENT 0x01
+#define PORT_CTRL_REQ_CONFIRMED 0x02
+#define PORT_CTRL_IND_RECEIVED 0x04
+#define PORT_CTRL_IND_RESPONDED 0x08
+
+ UINT8 port_ctrl; /* Modem Status Command */
+
+ BOOLEAN rx_flag_ev_pending; /* RXFLAG Character is received */
+
+ tRFC_PORT rfc; /* RFCOMM port control block */
+
+ UINT32 ev_mask; /* Event mask for the callback */
+ tPORT_CALLBACK *p_callback; /* Pointer to users callback function */
+ tPORT_CALLBACK *p_mgmt_callback; /* Callback function to receive connection up/down */
+ tPORT_DATA_CALLBACK *p_data_callback; /* Callback function to receive data indications */
+ UINT16 credit_tx; /* Flow control credits for tx path */
+ UINT16 credit_rx; /* Flow control credits for rx path, this is */
+ /* number of buffers peer is allowed to sent */
+ UINT16 credit_rx_max; /* Max number of credits we will allow this guy to sent */
+ UINT16 credit_rx_low; /* Number of credits when we send credit update */
+ UINT16 rx_buf_critical; /* port receive queue critical watermark level */
+ BOOLEAN keep_port_handle; /* TRUE if port is not deallocated when closing */
+ /* it is set to TRUE for server when allocating port */
+ UINT16 keep_mtu; /* Max MTU that port can receive by server */
+};
+typedef struct t_port_info tPORT;
+
+
+/* Define the PORT/RFCOMM control structure
+*/
+typedef struct
+{
+ tPORT port[MAX_RFC_PORTS]; /* Port info pool */
+ tRFC_MCB rfc_mcb[MAX_BD_CONNECTIONS]; /* RFCOMM bd_connections pool */
+} tPORT_CB;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+** Functions provided by the port_utils.c
+*/
+extern tPORT *port_allocate_port (UINT8 dlci, BD_ADDR bd_addr);
+extern void port_set_defaults (tPORT *p_port);
+extern void port_select_mtu (tPORT *p_port);
+extern void port_release_port (tPORT *p_port);
+extern tPORT *port_find_mcb_dlci_port (tRFC_MCB *p_mcb, UINT8 dlci);
+extern tRFC_MCB *port_find_mcb (BD_ADDR bd_addr);
+extern tPORT *port_find_dlci_port (UINT8 dlci);
+extern tPORT *port_find_port (UINT8 dlci, BD_ADDR bd_addr);
+extern UINT32 port_get_signal_changes (tPORT *p_port, UINT8 old_signals, UINT8 signal);
+extern UINT32 port_flow_control_user (tPORT *p_port);
+extern void port_flow_control_peer(tPORT *p_port, BOOLEAN enable, UINT16 count);
+
+/*
+** Functions provided by the port_rfc.c
+*/
+extern int port_open_continue (tPORT *p_port);
+extern void port_start_port_open (tPORT *p_port);
+extern void port_start_par_neg (tPORT *p_port);
+extern void port_start_control (tPORT *p_port);
+extern void port_start_close (tPORT *p_port);
+extern void port_rfc_closed (tPORT *p_port, UINT8 res);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/stack/rfcomm/port_rfc.c b/stack/rfcomm/port_rfc.c
new file mode 100644
index 0000000..c4ac929
--- /dev/null
+++ b/stack/rfcomm/port_rfc.c
@@ -0,0 +1,1088 @@
+/*****************************************************************************
+**
+** Name: port_rfc.c
+**
+** Description: This module contains functions for port emulation entity
+** and RFCOMM communications
+**
+**
+** Copyright (c) 1999-2009, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+#include <string.h>
+
+#include "bt_target.h"
+#include "gki.h"
+#include "rfcdefs.h"
+#include "port_api.h"
+#include "btm_int.h"
+#include "btm_api.h"
+#include "port_int.h"
+#include "rfc_int.h"
+
+/*
+** Local function definitions
+*/
+UINT32 port_rfc_send_tx_data (tPORT *p_port);
+void port_rfc_closed (tPORT *p_port, UINT8 res);
+void port_get_credits (tPORT *p_port, UINT8 k);
+
+
+/*******************************************************************************
+**
+** Function port_open_continue
+**
+** Description This function is called after security manager completes
+** required security checks.
+**
+** Returns void
+**
+*******************************************************************************/
+int port_open_continue (tPORT *p_port)
+{
+ tRFC_MCB *p_mcb;
+
+ RFCOMM_TRACE_EVENT0 ("port_open_continue");
+
+ /* Check if multiplexer channel has already been established */
+ if ((p_mcb = rfc_alloc_multiplexer_channel (p_port->bd_addr, TRUE)) == NULL)
+ {
+ RFCOMM_TRACE_WARNING0 ("port_open_continue no mx channel");
+ port_release_port (p_port);
+ return (PORT_NO_RESOURCES);
+ }
+
+ p_port->rfc.p_mcb = p_mcb;
+
+ p_mcb->port_inx[p_port->dlci] = p_port->inx;
+
+ /* Connection is up and we know local and remote features, select MTU */
+ port_select_mtu (p_port);
+
+ if (p_mcb->state == RFC_MX_STATE_CONNECTED)
+ {
+ RFCOMM_ParNegReq (p_mcb, p_port->dlci, p_port->mtu);
+ }
+ else if ((p_mcb->state == RFC_MX_STATE_IDLE)
+ ||(p_mcb->state == RFC_MX_STATE_DISC_WAIT_UA))
+ {
+ /* In RFC_MX_STATE_IDLE state, MX state machine will create connection */
+ /* In RFC_MX_STATE_DISC_WAIT_UA state, MX state machine will recreate connection */
+ /* after disconnecting is completed */
+ RFCOMM_StartReq (p_mcb);
+ }
+ else
+ {
+ /* MX state machine ignores RFC_MX_EVENT_START_REQ in these states */
+ /* When it enters RFC_MX_STATE_CONNECTED, it will check any openning ports */
+ RFCOMM_TRACE_DEBUG1 ("port_open_continue: mx state(%d) mx channel is openning", p_mcb->state);
+ }
+ return (PORT_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function port_start_control
+**
+** Description This function is called in the BTU_TASK context to
+** send control information
+**
+** Returns void
+**
+*******************************************************************************/
+void port_start_control (tPORT *p_port)
+{
+ tRFC_MCB *p_mcb = p_port->rfc.p_mcb;
+
+ if (p_mcb == NULL)
+ return;
+
+ RFCOMM_ControlReq (p_mcb, p_port->dlci, &p_port->local_ctrl);
+}
+
+
+/*******************************************************************************
+**
+** Function port_start_par_neg
+**
+** Description This function is called in the BTU_TASK context to
+** send configuration information
+**
+** Returns void
+**
+*******************************************************************************/
+void port_start_par_neg (tPORT *p_port)
+{
+ tRFC_MCB *p_mcb = p_port->rfc.p_mcb;
+
+ if (p_mcb == NULL)
+ return;
+
+ RFCOMM_PortNegReq (p_mcb, p_port->dlci, &p_port->user_port_pars);
+}
+
+
+/*******************************************************************************
+**
+** Function port_start_close
+**
+** Description This function is called in the BTU_TASK context to
+** release DLC
+**
+** Returns void
+**
+*******************************************************************************/
+void port_start_close (tPORT *p_port)
+{
+ tRFC_MCB *p_mcb = p_port->rfc.p_mcb;
+ UINT8 old_signals;
+ UINT32 events = 0;
+
+ /* At first indicate to the user that signals on the connection were dropped */
+ p_port->line_status |= LINE_STATUS_FAILED;
+ old_signals = p_port->peer_ctrl.modem_signal;
+
+ p_port->peer_ctrl.modem_signal &= ~(PORT_DTRDSR_ON | PORT_CTSRTS_ON | PORT_DCD_ON);
+
+ events |= port_get_signal_changes (p_port, old_signals, p_port->peer_ctrl.modem_signal);
+
+ if(p_port->ev_mask & PORT_EV_CONNECT_ERR)
+ events |= PORT_EV_CONNECT_ERR;
+
+ if(p_port->ev_mask & PORT_EV_ERR)
+ events |= PORT_EV_ERR;
+
+ if ((p_port->p_callback != NULL) && events)
+ p_port->p_callback (events, p_port->inx);
+
+
+ /* Check if RFCOMM side has been closed while the message was queued */
+ if ((p_mcb == NULL) || (p_port->rfc.state == RFC_STATE_CLOSED))
+ {
+ /* Call management callback function before calling port_release_port() to clear tPort */
+ if (p_port->p_mgmt_callback)
+ p_port->p_mgmt_callback (PORT_CLOSED, p_port->inx);
+
+ port_release_port (p_port);
+ }
+ else
+ {
+ RFCOMM_DlcReleaseReq (p_mcb, p_port->dlci);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_StartCnf
+**
+** Description This function is called from the RFCOMM layer when
+** establishing of the multiplexer channel is completed.
+** Continue establishing of the connection for all ports that
+** are in the OPENING state
+**
+*******************************************************************************/
+void PORT_StartCnf (tRFC_MCB *p_mcb, UINT16 result)
+{
+ tPORT *p_port;
+ int i;
+ BOOLEAN no_ports_up = TRUE;
+
+ RFCOMM_TRACE_EVENT1 ("PORT_StartCnf result:%d", result);
+
+ p_port = &rfc_cb.port.port[0];
+ for (i = 0; i < MAX_RFC_PORTS; i++, p_port++)
+ {
+ if (p_port->rfc.p_mcb == p_mcb)
+ {
+ no_ports_up = FALSE;
+
+ if (result == RFCOMM_SUCCESS)
+ RFCOMM_ParNegReq (p_mcb, p_port->dlci, p_port->mtu);
+ else
+ {
+ RFCOMM_TRACE_WARNING1 ("PORT_StartCnf failed result:%d", result);
+
+ /* Warning: result is also set to 4 when l2cap connection
+ fails due to l2cap connect cnf (no_resources) */
+ if( result == HCI_ERR_PAGE_TIMEOUT )
+ p_port->error = PORT_PAGE_TIMEOUT;
+ else
+ p_port->error = PORT_START_FAILED;
+
+ rfc_release_multiplexer_channel (p_mcb);
+ p_port->rfc.p_mcb = NULL;
+
+ /* Send event to the application */
+ if (p_port->p_callback && (p_port->ev_mask & PORT_EV_CONNECT_ERR))
+ (p_port->p_callback)(PORT_EV_CONNECT_ERR, p_port->inx);
+
+ if (p_port->p_mgmt_callback)
+ p_port->p_mgmt_callback (PORT_START_FAILED, p_port->inx);
+
+ port_release_port (p_port);
+ }
+ }
+ }
+
+ /* There can be a situation when after starting connection, user closes the */
+ /* port, we can catch it here to close multiplexor channel */
+ if (no_ports_up)
+ {
+ rfc_check_mcb_active (p_mcb);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_StartInd
+**
+** Description This function is called from the RFCOMM layer when
+** some peer device wants to establish a multiplexer
+** connection. Check if there are any ports open with this
+** or not assigned multiplexer.
+**
+*******************************************************************************/
+void PORT_StartInd (tRFC_MCB *p_mcb)
+{
+ tPORT *p_port;
+ int i;
+
+ RFCOMM_TRACE_EVENT0 ("PORT_StartInd");
+
+ p_port = &rfc_cb.port.port[0];
+ for (i = 0; i < MAX_RFC_PORTS; i++, p_port++)
+ {
+ if ((p_port->rfc.p_mcb == NULL)
+ || (p_port->rfc.p_mcb == p_mcb))
+ {
+ RFCOMM_StartRsp (p_mcb, RFCOMM_SUCCESS);
+ return;
+ }
+ }
+ RFCOMM_StartRsp (p_mcb, RFCOMM_ERROR);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_ParNegInd
+**
+** Description This function is called from the RFCOMM layer to change
+** DLCI parameters (currently only MTU is negotiated).
+** If can not find the port do not accept the request.
+** Otherwise save the MTU size supported by the peer.
+**
+*******************************************************************************/
+void PORT_ParNegInd (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu, UINT8 cl, UINT8 k)
+{
+ tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
+ UINT8 our_cl;
+ UINT8 our_k;
+
+ RFCOMM_TRACE_EVENT2 ("PORT_ParNegInd dlci:%d mtu:%d", dlci, mtu);
+
+ if (!p_port)
+ {
+ /* This can be a first request for this port */
+ p_port = port_find_dlci_port (dlci);
+ if (!p_port)
+ {
+ /* If the port cannot be opened, send a DM. Per Errata 1205 */
+ rfc_send_dm(p_mcb, dlci, FALSE);
+ /* check if this is the last port open, some headsets have
+ problem, they don't disconnect if we send DM */
+ rfc_check_mcb_active( p_mcb );
+ RFCOMM_TRACE_EVENT0( "PORT_ParNegInd: port not found" );
+ return;
+ }
+ p_mcb->port_inx[dlci] = p_port->inx;
+ }
+
+ memcpy (p_port->bd_addr, p_mcb->bd_addr, BD_ADDR_LEN);
+
+ /* Connection is up and we know local and remote features, select MTU */
+ port_select_mtu (p_port);
+
+ p_port->rfc.p_mcb = p_mcb;
+ p_port->mtu = (p_port->mtu < mtu) ? p_port->mtu : mtu;
+ p_port->peer_mtu = p_port->mtu;
+
+ /* Negotiate the flow control mechanism. If flow control mechanism for */
+ /* mux has not been set yet, set it now. If either we or peer wants TS 07.10, */
+ /* use that. Otherwise both must want credit based, so use that. If flow is */
+ /* already defined for this mux, we respond with that value. */
+ if (p_mcb->flow == PORT_FC_UNDEFINED)
+ {
+ if ((PORT_FC_DEFAULT == PORT_FC_TS710) || (cl == RFCOMM_PN_CONV_LAYER_TYPE_1))
+ {
+ p_mcb->flow = PORT_FC_TS710;
+ }
+ else
+ {
+ p_mcb->flow = PORT_FC_CREDIT;
+ }
+ }
+
+ /* Regardless of our flow control mechanism, if the PN cl is zero, we must */
+ /* respond with zero. "A responding implementation must set this field to 14 */
+ /* if (and only if) the PN request was 15." This could happen if a PN is sent */
+ /* after the DLCI is already established-- the PN in that case must have cl = 0. */
+ /* See RFCOMM spec 5.5.3 */
+ if (cl == RFCOMM_PN_CONV_LAYER_TYPE_1)
+ {
+ our_cl = RFCOMM_PN_CONV_LAYER_TYPE_1;
+ our_k = 0;
+ }
+ else if (p_mcb->flow == PORT_FC_CREDIT)
+ {
+ /* get credits */
+ port_get_credits (p_port, k);
+
+ /* Set convergence layer and number of credits (k) */
+ our_cl = RFCOMM_PN_CONV_LAYER_CBFC_R;
+ our_k = (p_port->credit_rx_max < RFCOMM_K_MAX) ? p_port->credit_rx_max : RFCOMM_K_MAX;
+ p_port->credit_rx = our_k;
+ }
+ else
+ {
+ /* must not be using credit based flow control; use TS 7.10 */
+ our_cl = RFCOMM_PN_CONV_LAYER_TYPE_1;
+ our_k = 0;
+ }
+ RFCOMM_ParNegRsp (p_mcb, dlci, p_port->mtu, our_cl, our_k);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_ParNegCnf
+**
+** Description This function is called from the RFCOMM layer to change
+** DLCI parameters (currently only MTU is negotiated).
+** Save the MTU size supported by the peer.
+** If the confirmation is received during the port opening
+** procedure send EstablishRequest to continue.
+**
+*******************************************************************************/
+void PORT_ParNegCnf (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu, UINT8 cl, UINT8 k)
+{
+ tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
+
+ RFCOMM_TRACE_EVENT4 ("PORT_ParNegCnf dlci:%d mtu:%d cl: %d k: %d", dlci, mtu, cl, k);
+
+ if (!p_port)
+ return;
+
+ /* Flow control mechanism not set yet. Negotiate flow control mechanism. */
+ if (p_mcb->flow == PORT_FC_UNDEFINED)
+ {
+ /* Our stack is configured for TS07.10 and they responded with credit-based. */
+ /* This is illegal-- negotiation fails. */
+ if ((PORT_FC_DEFAULT == PORT_FC_TS710) && (cl == RFCOMM_PN_CONV_LAYER_CBFC_R))
+ {
+ rfc_send_disc (p_mcb, p_port->dlci);
+ rfc_port_closed (p_port);
+ return;
+ }
+ /* Our stack is configured for credit-based and they responded with credit-based. */
+ else if (cl == RFCOMM_PN_CONV_LAYER_CBFC_R)
+ {
+ p_mcb->flow = PORT_FC_CREDIT;
+ }
+ /* They responded with any other value. Treat this as negotiation to TS07.10. */
+ else
+ {
+ p_mcb->flow = PORT_FC_TS710;
+ }
+ }
+ /* If mux flow control mechanism set, we honor that setting regardless of */
+ /* the CL value in their response. This allows us to gracefully accept any */
+ /* illegal PN negotiation scenarios. */
+
+ p_port->mtu = (p_port->mtu < mtu) ? p_port->mtu : mtu;
+ p_port->peer_mtu = p_port->mtu;
+
+ if (p_mcb->flow == PORT_FC_CREDIT)
+ {
+ port_get_credits (p_port, k);
+ }
+
+ if (p_port->state == PORT_STATE_OPENING)
+ RFCOMM_DlcEstablishReq (p_mcb, p_port->dlci, p_port->mtu);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_DlcEstablishInd
+**
+** Description This function is called from the RFCOMM layer when peer
+** device wants to establish a new DLC. If this is not the
+** first message in the establishment procedure port_handle
+** has a handle to the port control block otherwise the control
+** block should be found based on the muliplexer channel and
+** dlci. The block should be allocated allocated before
+** meaning that application already made open.
+**
+*******************************************************************************/
+void PORT_DlcEstablishInd (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu)
+{
+ tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
+
+ RFCOMM_TRACE_EVENT2 ("PORT_DlcEstablishInd dlci:%d mtu:%d", dlci, mtu);
+
+ if (!p_port)
+ {
+ /* This can be a first request for this port */
+ p_port = port_find_dlci_port (dlci);
+ if (!p_port)
+ {
+ RFCOMM_DlcEstablishRsp (p_mcb, dlci, 0, RFCOMM_ERROR);
+ return;
+ }
+ p_mcb->port_inx[dlci] = p_port->inx;
+ }
+
+ /* If L2CAP's mtu less then RFCOMM's take it */
+ if (mtu && (mtu < p_port->peer_mtu))
+ p_port->peer_mtu = mtu;
+
+ /* If there was an inactivity timer running for MCB stop it */
+ rfc_timer_stop (p_mcb);
+
+ RFCOMM_DlcEstablishRsp (p_mcb, dlci, p_port->mtu, RFCOMM_SUCCESS);
+
+ /* This is the server side. If application wants to know when connection */
+ /* is established, thats the place */
+ if (p_port->p_callback && (p_port->ev_mask & PORT_EV_CONNECTED))
+ (p_port->p_callback)(PORT_EV_CONNECTED, p_port->inx);
+
+ if (p_port->p_mgmt_callback)
+ p_port->p_mgmt_callback (PORT_SUCCESS, p_port->inx);
+
+ p_port->state = PORT_STATE_OPENED;
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_DlcEstablishCnf
+**
+** Description This function is called from the RFCOMM layer when peer
+** acknowledges establish procedure (SABME/UA). Send reply
+** to the user and set state to OPENED if result was
+** successfull.
+**
+*******************************************************************************/
+void PORT_DlcEstablishCnf (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu, UINT16 result)
+{
+ tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
+
+ RFCOMM_TRACE_EVENT3 ("PORT_DlcEstablishCnf dlci:%d mtu:%d result:%d", dlci, mtu, result);
+
+ if (!p_port)
+ return;
+
+ if (result != RFCOMM_SUCCESS)
+ {
+ p_port->error = PORT_START_FAILED;
+ port_rfc_closed (p_port, PORT_START_FAILED);
+ return;
+ }
+
+ /* If L2CAP's mtu less then RFCOMM's take it */
+ if (mtu && (mtu < p_port->peer_mtu))
+ p_port->peer_mtu = mtu;
+
+ /* If there was an inactivity timer running for MCB stop it */
+ rfc_timer_stop (p_mcb);
+
+ if (p_port->p_callback && (p_port->ev_mask & PORT_EV_CONNECTED))
+ (p_port->p_callback)(PORT_EV_CONNECTED, p_port->inx);
+
+ if (p_port->p_mgmt_callback)
+ p_port->p_mgmt_callback (PORT_SUCCESS, p_port->inx);
+
+ p_port->state = PORT_STATE_OPENED;
+
+ /* RPN is required only if we want to tell DTE how the port should be opened */
+ if ((p_port->uuid == UUID_SERVCLASS_DIALUP_NETWORKING)
+ || (p_port->uuid == UUID_SERVCLASS_FAX))
+ RFCOMM_PortNegReq (p_port->rfc.p_mcb, p_port->dlci, NULL);
+ else
+ RFCOMM_ControlReq (p_port->rfc.p_mcb, p_port->dlci, &p_port->local_ctrl);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_PortNegInd
+**
+** Description This function is called from the RFCOMM layer when peer
+** device wants to set parameters of the port. As per the spec
+** this message has to be sent before the first data packet
+** and can be sent before establish. The block should be
+** allocated before meaning that application already made open.
+**
+*******************************************************************************/
+void PORT_PortNegInd (tRFC_MCB *p_mcb, UINT8 dlci, tPORT_STATE *p_pars,
+ UINT16 param_mask)
+{
+ tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
+
+ RFCOMM_TRACE_EVENT0 ("PORT_PortNegInd");
+
+ if (!p_port)
+ {
+ /* This can be a first request for this port */
+ p_port = port_find_dlci_port (dlci);
+ if (!p_port)
+ {
+ RFCOMM_PortNegRsp (p_mcb, dlci, p_pars, 0);
+ return;
+ }
+ p_mcb->port_inx[dlci] = p_port->inx;
+ }
+
+ /* Check if the flow control is acceptable on local side */
+ p_port->peer_port_pars = *p_pars;
+ RFCOMM_PortNegRsp (p_mcb, dlci, p_pars, param_mask);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_PortNegCnf
+**
+** Description This function is called from the RFCOMM layer to change
+** state for the port. Propagate change to the user.
+**
+*******************************************************************************/
+void PORT_PortNegCnf (tRFC_MCB *p_mcb, UINT8 dlci, tPORT_STATE *p_pars, UINT16 result)
+{
+ tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
+
+ RFCOMM_TRACE_EVENT0 ("PORT_PortNegCnf");
+
+ if (!p_port)
+ {
+ RFCOMM_TRACE_WARNING0 ("PORT_PortNegCnf no port");
+ return;
+ }
+ /* Port negotiation failed. Drop the connection */
+ if (result != RFCOMM_SUCCESS)
+ {
+ p_port->error = PORT_PORT_NEG_FAILED;
+
+ RFCOMM_DlcReleaseReq (p_mcb, p_port->dlci);
+
+ port_rfc_closed (p_port, PORT_PORT_NEG_FAILED);
+ return;
+ }
+
+ if (!(p_port->port_ctrl & PORT_CTRL_REQ_SENT))
+ {
+ RFCOMM_ControlReq (p_port->rfc.p_mcb, p_port->dlci, &p_port->local_ctrl);
+ }
+ else
+ {
+ RFCOMM_TRACE_WARNING0 ("PORT_PortNegCnf Control Already sent");
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_ControlInd
+**
+** Description This function is called from the RFCOMM layer on the modem
+** signal change. Propagate change to the user.
+**
+*******************************************************************************/
+void PORT_ControlInd (tRFC_MCB *p_mcb, UINT8 dlci, tPORT_CTRL *p_pars)
+{
+ tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
+ UINT32 event;
+ UINT8 old_signals;
+
+ RFCOMM_TRACE_EVENT0 ("PORT_ControlInd");
+
+ if (!p_port)
+ return;
+
+ old_signals = p_port->peer_ctrl.modem_signal;
+
+ event = port_get_signal_changes (p_port, old_signals, p_pars->modem_signal);
+
+ p_port->peer_ctrl = *p_pars;
+
+ if (!(p_port->port_ctrl & PORT_CTRL_REQ_SENT))
+ RFCOMM_ControlReq (p_port->rfc.p_mcb, p_port->dlci, &p_port->local_ctrl);
+ else
+ {
+ /* If this is the first time we received control RFCOMM is connected */
+ if (!(p_port->port_ctrl & PORT_CTRL_IND_RECEIVED))
+ {
+ event |= (PORT_EV_CONNECTED & p_port->ev_mask);
+ }
+
+ if (p_port->port_ctrl & PORT_CTRL_REQ_CONFIRMED)
+ {
+ event |= port_rfc_send_tx_data(p_port);
+ }
+ }
+
+ p_port->port_ctrl |= (PORT_CTRL_IND_RECEIVED | PORT_CTRL_IND_RESPONDED);
+
+ if (p_pars->break_signal)
+ event |= (PORT_EV_BREAK & p_port->ev_mask);
+
+ /* execute call back function only if the application is registered for events */
+ if (event && p_port->p_callback)
+ (p_port->p_callback)(event, p_port->inx);
+
+ RFCOMM_TRACE_EVENT4 ("PORT_ControlInd DTR_DSR : %d, RTS_CTS : %d, RI : %d, DCD : %d",
+ ((p_port->peer_ctrl.modem_signal & MODEM_SIGNAL_DTRDSR) ? 1 : 0),
+ ((p_port->peer_ctrl.modem_signal & MODEM_SIGNAL_RTSCTS) ? 1 : 0),
+ ((p_port->peer_ctrl.modem_signal & MODEM_SIGNAL_RI) ? 1 : 0),
+ ((p_port->peer_ctrl.modem_signal & MODEM_SIGNAL_DCD) ? 1 : 0));
+
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_ControlCnf
+**
+** Description This function is called from the RFCOMM layer when
+** peer acknowleges change of the modem signals.
+**
+*******************************************************************************/
+void PORT_ControlCnf (tRFC_MCB *p_mcb, UINT8 dlci, tPORT_CTRL *p_pars)
+{
+ tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
+ UINT32 event = 0;
+
+ RFCOMM_TRACE_EVENT0 ("PORT_ControlCnf");
+
+ if (!p_port)
+ return;
+
+ if (!(p_port->port_ctrl & PORT_CTRL_REQ_CONFIRMED))
+ {
+ p_port->port_ctrl |= PORT_CTRL_REQ_CONFIRMED;
+
+ if (p_port->port_ctrl & PORT_CTRL_IND_RECEIVED)
+ event = (p_port->ev_mask & PORT_EV_CONNECTED);
+ }
+
+ if (p_port->port_ctrl & PORT_CTRL_IND_RECEIVED)
+ {
+ event |= port_rfc_send_tx_data(p_port);
+ }
+
+ /* execute call back function only if the application is registered for events */
+ if (event && p_port->p_callback)
+ (p_port->p_callback)(event, p_port->inx);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_LineStatusInd
+**
+** Description This function is called from the RFCOMM layer when
+** peer indicates change in the line status
+**
+*******************************************************************************/
+void PORT_LineStatusInd (tRFC_MCB *p_mcb, UINT8 dlci, UINT8 line_status)
+{
+ tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
+ UINT32 event = 0;
+
+ RFCOMM_TRACE_EVENT0 ("PORT_LineStatusInd");
+
+ if (!p_port)
+ return;
+
+ p_port->line_status |= line_status;
+
+ if (line_status & PORT_ERR_OVERRUN)
+ event |= PORT_EV_OVERRUN;
+
+ if (line_status & PORT_ERR_BREAK)
+ event |= PORT_EV_BREAK;
+
+ if (line_status & ~(PORT_ERR_OVERRUN | PORT_ERR_BREAK))
+ event |= PORT_EV_ERR;
+
+ if ((p_port->p_callback != NULL) && (p_port->ev_mask & event))
+ p_port->p_callback ((p_port->ev_mask & event), p_port->inx);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_DlcReleaseInd
+**
+** Description This function is called from the RFCOMM layer when
+** DLC connection is released.
+**
+*******************************************************************************/
+void PORT_DlcReleaseInd (tRFC_MCB *p_mcb, UINT8 dlci)
+{
+ tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
+
+ RFCOMM_TRACE_EVENT0 ("PORT_DlcReleaseInd");
+
+ if (!p_port)
+ return;
+
+ port_rfc_closed (p_port, PORT_CLOSED);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_CloseInd
+**
+** Description This function is called from the RFCOMM layer when
+** multiplexer connection is released.
+**
+*******************************************************************************/
+void PORT_CloseInd (tRFC_MCB *p_mcb)
+{
+ tPORT *p_port;
+ int i;
+
+ RFCOMM_TRACE_EVENT0 ("PORT_CloseInd");
+
+ p_port = &rfc_cb.port.port[0];
+ for (i = 0; i < MAX_RFC_PORTS; i++, p_port++)
+ {
+ if (p_port->rfc.p_mcb == p_mcb)
+ {
+ port_rfc_closed (p_port, PORT_PEER_CONNECTION_FAILED);
+ }
+ }
+ rfc_release_multiplexer_channel (p_mcb);
+}
+
+/*******************************************************************************
+**
+** Function Port_TimeOutCloseMux
+**
+** Description This function is called when RFCOMM timesout on a command
+** as a result multiplexer connection is closed.
+**
+*******************************************************************************/
+void Port_TimeOutCloseMux (tRFC_MCB *p_mcb)
+{
+ tPORT *p_port;
+ int i;
+
+ RFCOMM_TRACE_EVENT0 ("Port_TimeOutCloseMux");
+
+ p_port = &rfc_cb.port.port[0];
+ for (i = 0; i < MAX_RFC_PORTS; i++, p_port++)
+ {
+ if (p_port->rfc.p_mcb == p_mcb)
+ {
+ port_rfc_closed (p_port, PORT_PEER_TIMEOUT);
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_DataInd
+**
+** Description This function is called from the RFCOMM layer when data
+** buffer is received from the peer.
+**
+*******************************************************************************/
+void PORT_DataInd (tRFC_MCB *p_mcb, UINT8 dlci, BT_HDR *p_buf)
+{
+ tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
+ UINT8 rx_char1;
+ UINT32 events = 0;
+ UINT8 *p;
+ int i;
+
+ RFCOMM_TRACE_EVENT1 ("PORT_DataInd with data length %d", p_buf->len);
+ if (!p_port)
+ {
+ GKI_freebuf (p_buf);
+ return;
+ }
+
+ /* If client registered callback we can just deliver receive data */
+ if (p_port->p_data_callback)
+ {
+ /* Another packet is delivered to user. Send credits to peer if required */
+ port_flow_control_peer(p_port, TRUE, 1);
+
+ p_port->p_data_callback (p_port->inx, (UINT8 *)(p_buf + 1) + p_buf->offset, p_buf->len);
+ GKI_freebuf (p_buf);
+ return;
+ }
+
+ /* Check if rx queue exceeds the limit */
+ if ((p_port->rx.queue_size + p_buf->len > PORT_RX_CRITICAL_WM)
+ || (p_port->rx.queue.count + 1 > p_port->rx_buf_critical))
+ {
+ RFCOMM_TRACE_EVENT0 ("PORT_DataInd. Buffer over run. Dropping the buffer");
+ GKI_freebuf (p_buf);
+
+ RFCOMM_LineStatusReq (p_mcb, dlci, LINE_STATUS_OVERRUN);
+ return;
+ }
+
+ /* If user registered to receive notification when a particular byte is */
+ /* received we mast check all received bytes */
+ if (((rx_char1 = p_port->user_port_pars.rx_char1) != 0)
+ && (p_port->ev_mask & PORT_EV_RXFLAG))
+ {
+ for (i = 0, p = (UINT8 *)(p_buf + 1) + p_buf->offset; i < p_buf->len; i++)
+ {
+ if (*p++ == rx_char1)
+ {
+ events |= PORT_EV_RXFLAG;
+ break;
+ }
+ }
+ }
+
+ PORT_SCHEDULE_LOCK;
+
+ GKI_enqueue (&p_port->rx.queue, p_buf);
+ p_port->rx.queue_size += p_buf->len;
+
+ PORT_SCHEDULE_UNLOCK;
+
+ /* perform flow control procedures if necessary */
+ port_flow_control_peer(p_port, FALSE, 0);
+
+ /* If user indicated flow control can not deliver any notifications to him */
+ if (p_port->rx.user_fc)
+ {
+ if (events & PORT_EV_RXFLAG)
+ p_port->rx_flag_ev_pending = TRUE;
+
+ return;
+ }
+
+ events |= PORT_EV_RXCHAR;
+
+ /* Mask out all events that are not of interest to user */
+ events &= p_port->ev_mask;
+
+ if (p_port->p_callback && events)
+ p_port->p_callback (events, p_port->inx);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_FlowInd
+**
+** Description This function is called from the RFCOMM layer on the flow
+** control signal change. Propagate change to the user.
+**
+*******************************************************************************/
+void PORT_FlowInd (tRFC_MCB *p_mcb, UINT8 dlci, BOOLEAN enable_data)
+{
+ tPORT *p_port = (tPORT *)NULL;
+ UINT32 events = 0;
+ int i;
+
+ RFCOMM_TRACE_EVENT1 ("PORT_FlowInd fc:%d", enable_data);
+
+ if (dlci == 0)
+ {
+ p_mcb->peer_ready = enable_data;
+ }
+ else
+ {
+ if ((p_port = port_find_mcb_dlci_port (p_mcb, dlci)) == NULL)
+ return;
+
+ p_port->tx.peer_fc = !enable_data;
+ }
+
+ for (i = 0; i < MAX_RFC_PORTS; i++)
+ {
+ /* If DLCI is 0 event applies to all ports */
+ if (dlci == 0)
+ {
+ p_port = &rfc_cb.port.port[i];
+ if (!p_port->in_use
+ || (p_port->rfc.p_mcb != p_mcb)
+ || (p_port->rfc.state != RFC_STATE_OPENED))
+ continue;
+ }
+ events = 0;
+
+ /* Check if flow of data is still enabled */
+ events |= port_flow_control_user (p_port);
+
+ /* Check if data can be sent and send it */
+ events |= port_rfc_send_tx_data (p_port);
+
+ /* Mask out all events that are not of interest to user */
+ events &= p_port->ev_mask;
+
+ /* Send event to the application */
+ if (p_port->p_callback && events)
+ (p_port->p_callback)(events, p_port->inx);
+
+ /* If DLCI is not 0 event applies to one port only */
+ if (dlci != 0)
+ break;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function port_rfc_send_tx_data
+**
+** Description This function is when forward data can be sent to the peer
+**
+*******************************************************************************/
+UINT32 port_rfc_send_tx_data (tPORT *p_port)
+{
+ UINT32 events = 0;
+ BT_HDR *p_buf;
+
+ /* if there is data to be sent */
+ if (p_port->tx.queue_size > 0)
+ {
+ /* while the rfcomm peer is not flow controlling us, and peer is ready */
+ while (!p_port->tx.peer_fc && p_port->rfc.p_mcb && p_port->rfc.p_mcb->peer_ready)
+ {
+ /* get data from tx queue and send it */
+ PORT_SCHEDULE_LOCK;
+
+ if ((p_buf = (BT_HDR *)GKI_dequeue (&p_port->tx.queue)) != NULL)
+ {
+ p_port->tx.queue_size -= p_buf->len;
+
+ PORT_SCHEDULE_UNLOCK;
+
+ RFCOMM_TRACE_DEBUG1 ("Sending RFCOMM_DataReq tx.queue_size=%d", p_port->tx.queue_size);
+
+ RFCOMM_DataReq (p_port->rfc.p_mcb, p_port->dlci, p_buf);
+
+ events |= PORT_EV_TXCHAR;
+
+ if (p_port->tx.queue_size == 0)
+ {
+ events |= PORT_EV_TXEMPTY;
+ break;
+ }
+ }
+ /* queue is empty-- all data sent */
+ else
+ {
+ PORT_SCHEDULE_UNLOCK;
+
+ events |= PORT_EV_TXEMPTY;
+ break;
+ }
+ }
+ /* If we flow controlled user based on the queue size enable data again */
+ events |= port_flow_control_user (p_port);
+ }
+ return (events & p_port->ev_mask);
+}
+
+
+/*******************************************************************************
+**
+** Function port_rfc_closed
+**
+** Description This function when RFCOMM side of port is closed
+**
+*******************************************************************************/
+void port_rfc_closed (tPORT *p_port, UINT8 res)
+{
+ UINT8 old_signals;
+ UINT32 events = 0;
+ tRFC_MCB *p_mcb = p_port->rfc.p_mcb;
+
+ if ((p_port->state == PORT_STATE_OPENING) && (p_port->is_server))
+ {
+ /* The servr side has not been informed that connection is up, ignore */
+ RFCOMM_TRACE_EVENT0 ("port_rfc_closed in OPENING state ignored");
+
+ rfc_port_timer_stop (p_port);
+ p_port->rfc.state = RFC_STATE_CLOSED;
+
+ if (p_mcb)
+ {
+ p_mcb->port_inx[p_port->dlci] = 0;
+
+ /* If there are no more ports opened on this MCB release it */
+ rfc_check_mcb_active (p_mcb);
+ p_port->rfc.p_mcb = NULL;
+ }
+
+ /* Need to restore DLCI to listening state
+ * if the server was on the initiating RFC
+ */
+ p_port->dlci &= 0xfe;
+
+ return;
+ }
+
+ if ((p_port->state != PORT_STATE_CLOSING) && (p_port->state != PORT_STATE_CLOSED))
+ {
+ p_port->line_status |= LINE_STATUS_FAILED;
+
+ old_signals = p_port->peer_ctrl.modem_signal;
+
+ p_port->peer_ctrl.modem_signal &= ~(PORT_DTRDSR_ON | PORT_CTSRTS_ON | PORT_DCD_ON);
+
+ events |= port_get_signal_changes (p_port, old_signals, p_port->peer_ctrl.modem_signal);
+
+ if(p_port->ev_mask & PORT_EV_CONNECT_ERR)
+ events |= PORT_EV_CONNECT_ERR;
+ }
+ RFCOMM_TRACE_EVENT2 ("port_rfc_closed state:%d sending events:%x", p_port->state, events);
+
+ if ((p_port->p_callback != NULL) && events)
+ p_port->p_callback (events, p_port->inx);
+
+ if (p_port->p_mgmt_callback)
+ p_port->p_mgmt_callback (res, p_port->inx);
+
+ p_port->rfc.state = RFC_STATE_CLOSED;
+
+ port_release_port (p_port);
+}
+
+
+/*******************************************************************************
+**
+** Function port_get_credits
+**
+** Description Set initial values for credits.
+** Adjust max number of rx credits based on negotiated MTU.
+** Check max allowed num of bytes, max allowed num buffers,
+** should be less then 255
+**
+*******************************************************************************/
+void port_get_credits (tPORT *p_port, UINT8 k)
+{
+ p_port->credit_tx = k;
+ if (p_port->credit_tx == 0)
+ p_port->tx.peer_fc = TRUE;
+}
+
+
+
diff --git a/stack/rfcomm/port_utils.c b/stack/rfcomm/port_utils.c
new file mode 100644
index 0000000..5a52774
--- /dev/null
+++ b/stack/rfcomm/port_utils.c
@@ -0,0 +1,562 @@
+/*****************************************************************************
+**
+** Name: port_utils.c
+**
+** Description: Port Emulation entity utilities
+**
+**
+** Copyright (c) 1999-2009, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+#include <string.h>
+
+#include "bt_target.h"
+#include "gki.h"
+#include "rfcdefs.h"
+#include "port_api.h"
+#include "port_int.h"
+#include "rfc_int.h"
+#include "l2cdefs.h"
+#include "btm_int.h"
+#include "btu.h"
+
+
+static const tPORT_STATE default_port_pars =
+{
+ PORT_BAUD_RATE_9600,
+ PORT_8_BITS,
+ PORT_ONESTOPBIT,
+ PORT_PARITY_NO,
+ PORT_ODD_PARITY,
+ PORT_FC_OFF,
+ 0, /* No rx_char */
+ PORT_XON_DC1,
+ PORT_XOFF_DC3,
+};
+
+
+
+/*******************************************************************************
+**
+** Function port_allocate_port
+**
+** Description Look through the Port Control Blocks for a free one. Note
+** that one server can open several ports with the same SCN
+** if it can support simulteneous requests from different
+** clients.
+**
+** Returns Pointer to the PORT or NULL if not found
+**
+*******************************************************************************/
+tPORT *port_allocate_port (UINT8 dlci, BD_ADDR bd_addr)
+{
+ tPORT *p_port = &rfc_cb.port.port[0];
+ UINT8 xx, yy;
+
+ for (xx = 0, yy = rfc_cb.rfc.last_port + 1; xx < MAX_RFC_PORTS; xx++, yy++)
+ {
+ if (yy >= MAX_RFC_PORTS)
+ yy = 0;
+
+ p_port = &rfc_cb.port.port[yy];
+ if (!p_port->in_use)
+ {
+ memset (p_port, 0, sizeof (tPORT));
+
+ p_port->in_use = TRUE;
+ p_port->inx = yy + 1;
+
+ p_port->dlci = dlci;
+ memcpy (p_port->bd_addr, bd_addr, BD_ADDR_LEN);
+
+ /* During the open set default state for the port connection */
+ port_set_defaults (p_port);
+
+ rfc_cb.rfc.last_port = yy;
+ return (p_port);
+ }
+ }
+
+ /* If here, no free PORT found */
+ return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function port_set_defaults
+**
+** Description Set defualt port parameters
+**
+**
+*******************************************************************************/
+void port_set_defaults (tPORT *p_port)
+{
+ p_port->ev_mask = 0;
+ p_port->p_callback = NULL;
+ p_port->port_ctrl = 0;
+ p_port->error = 0;
+ p_port->line_status = 0;
+ p_port->rx_flag_ev_pending = FALSE;
+ p_port->peer_mtu = RFCOMM_DEFAULT_MTU;
+
+ p_port->user_port_pars = default_port_pars;
+ p_port->peer_port_pars = default_port_pars;
+
+ p_port->credit_tx = 0;
+ p_port->credit_rx = 0;
+/* p_port->credit_rx_max = PORT_CREDIT_RX_MAX; Determined later */
+/* p_port->credit_rx_low = PORT_CREDIT_RX_LOW; Determined later */
+
+ memset (&p_port->local_ctrl, 0, sizeof (p_port->local_ctrl));
+ memset (&p_port->peer_ctrl, 0, sizeof (p_port->peer_ctrl));
+ memset (&p_port->rx, 0, sizeof (p_port->rx));
+ memset (&p_port->tx, 0, sizeof (p_port->tx));
+}
+
+/*******************************************************************************
+**
+** Function port_select_mtu
+**
+** Description Select MTU which will best serve connection from our
+** point of view.
+** If our device is 1.2 or lower we calculate how many DH5s
+** fit into 1 RFCOMM buffer.
+**
+**
+*******************************************************************************/
+void port_select_mtu (tPORT *p_port)
+{
+ UINT16 packet_size;
+
+ /* Will select MTU only if application did not setup something */
+ if (p_port->mtu == 0)
+ {
+ /* find packet size which connection supports */
+ packet_size = btm_get_max_packet_size (p_port->bd_addr);
+ if (packet_size == 0)
+ {
+ /* something is very wrong */
+ RFCOMM_TRACE_WARNING0 ("port_select_mtu bad packet size");
+ p_port->mtu = RFCOMM_DEFAULT_MTU;
+ }
+ else
+ {
+ /* We try to negotiate MTU that each packet can be split into whole
+ number of max packets. For example if link is 1.2 max packet size is 339 bytes.
+ At first calculate how many whole packets it is. MAX L2CAP is 1691 + 4 overhead.
+ 1695, that will be 5 Dh5 packets. Now maximum RFCOMM packet is
+ 5 * 339 = 1695. Minus 4 bytes L2CAP header 1691. Minus RFCOMM 6 bytes header overhead 1685
+
+ For EDR 2.0 packet size is 1027. So we better send RFCOMM packet as 1 3DH5 packet
+ 1 * 1027 = 1027. Minus 4 bytes L2CAP header 1023. Minus RFCOMM 6 bytes header overhead 1017 */
+ if ((L2CAP_MTU_SIZE + L2CAP_PKT_OVERHEAD) >= packet_size)
+ {
+ p_port->mtu = ((L2CAP_MTU_SIZE + L2CAP_PKT_OVERHEAD) / packet_size * packet_size) - RFCOMM_DATA_OVERHEAD - L2CAP_PKT_OVERHEAD;
+ RFCOMM_TRACE_DEBUG1 ("port_select_mtu selected %d based on connection speed", p_port->mtu);
+ }
+ else
+ {
+ p_port->mtu = L2CAP_MTU_SIZE - RFCOMM_DATA_OVERHEAD;
+ RFCOMM_TRACE_DEBUG1 ("port_select_mtu selected %d based on l2cap PDU size", p_port->mtu);
+ }
+ }
+ }
+ else
+ {
+ RFCOMM_TRACE_DEBUG1 ("port_select_mtu application selected %d", p_port->mtu);
+ }
+ p_port->credit_rx_max = (PORT_RX_HIGH_WM / p_port->mtu);
+ if( p_port->credit_rx_max > PORT_RX_BUF_HIGH_WM )
+ p_port->credit_rx_max = PORT_RX_BUF_HIGH_WM;
+ p_port->credit_rx_low = (PORT_RX_LOW_WM / p_port->mtu);
+ if( p_port->credit_rx_low > PORT_RX_BUF_LOW_WM )
+ p_port->credit_rx_low = PORT_RX_BUF_LOW_WM;
+ p_port->rx_buf_critical = (PORT_RX_CRITICAL_WM / p_port->mtu);
+ if( p_port->rx_buf_critical > PORT_RX_BUF_CRITICAL_WM )
+ p_port->rx_buf_critical = PORT_RX_BUF_CRITICAL_WM;
+ RFCOMM_TRACE_DEBUG3 ("port_select_mtu credit_rx_max %d, credit_rx_low %d, rx_buf_critical %d",
+ p_port->credit_rx_max, p_port->credit_rx_low, p_port->rx_buf_critical);
+}
+
+
+/*******************************************************************************
+**
+** Function port_release_port
+**
+** Description Release port infor control block.
+**
+** Returns Pointer to the PORT or NULL if not found
+**
+*******************************************************************************/
+void port_release_port (tPORT *p_port)
+{
+ BT_HDR *p_buf;
+ UINT32 mask;
+ tPORT_CALLBACK *p_port_cb;
+ tPORT_STATE user_port_pars;
+
+ PORT_SCHEDULE_LOCK;
+
+ while ((p_buf = (BT_HDR *)GKI_dequeue (&p_port->rx.queue)) != NULL)
+ GKI_freebuf (p_buf);
+
+ p_port->rx.queue_size = 0;
+
+ while ((p_buf = (BT_HDR *)GKI_dequeue (&p_port->tx.queue)) != NULL)
+ GKI_freebuf (p_buf);
+
+ p_port->tx.queue_size = 0;
+
+ PORT_SCHEDULE_UNLOCK;
+
+ p_port->state = PORT_STATE_CLOSED;
+
+ if (p_port->rfc.state == RFC_STATE_CLOSED)
+ {
+ RFCOMM_TRACE_DEBUG0 ("rfc_port_closed DONE");
+ if (p_port->rfc.p_mcb)
+ {
+ p_port->rfc.p_mcb->port_inx[p_port->dlci] = 0;
+
+ /* If there are no more ports opened on this MCB release it */
+ rfc_check_mcb_active (p_port->rfc.p_mcb);
+ }
+ rfc_port_timer_stop (p_port);
+
+ if( p_port->keep_port_handle )
+ {
+ RFCOMM_TRACE_DEBUG1 ("port_release_port:Initialize handle:%d", p_port->inx);
+ /* save event mask and callback */
+ mask = p_port->ev_mask;
+ p_port_cb = p_port->p_callback;
+ user_port_pars = p_port->user_port_pars;
+
+ port_set_defaults(p_port);
+ /* restore */
+ p_port->ev_mask = mask;
+ p_port->p_callback = p_port_cb;
+ p_port->user_port_pars = user_port_pars;
+ p_port->mtu = p_port->keep_mtu;
+
+ p_port->state = PORT_STATE_OPENING;
+ p_port->rfc.p_mcb = NULL;
+ if(p_port->is_server)
+ p_port->dlci &= 0xfe;
+
+ p_port->local_ctrl.modem_signal = p_port->default_signal_state;
+ memcpy (p_port->bd_addr, BT_BD_ANY, BD_ADDR_LEN);
+ }
+ else
+ {
+ RFCOMM_TRACE_DEBUG1 ("port_release_port:Clean-up handle:%d", p_port->inx);
+ memset (p_port, 0, sizeof (tPORT));
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function port_find_mcb
+**
+** Description This function checks if connection exists to device with
+** the BD_ADDR.
+**
+*******************************************************************************/
+tRFC_MCB *port_find_mcb (BD_ADDR bd_addr)
+{
+ int i;
+
+ for (i = 0; i < MAX_BD_CONNECTIONS; i++)
+ {
+ if ((rfc_cb.port.rfc_mcb[i].state != RFC_MX_STATE_IDLE)
+ && !memcmp (rfc_cb.port.rfc_mcb[i].bd_addr, bd_addr, BD_ADDR_LEN))
+ {
+ /* Multiplexer channel found do not change anything */
+ return (&rfc_cb.port.rfc_mcb[i]);
+ }
+ }
+ return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function port_find_mcb_dlci_port
+**
+** Description Find port on the multiplexer channel based on DLCI. If
+** this port with DLCI not found try to use even DLCI. This
+** is for the case when client is establishing connection on
+** none-initiator MCB.
+**
+** Returns Pointer to the PORT or NULL if not found
+**
+*******************************************************************************/
+tPORT *port_find_mcb_dlci_port (tRFC_MCB *p_mcb, UINT8 dlci)
+{
+ UINT8 inx;
+
+ if (!p_mcb)
+ return (NULL);
+
+ if (dlci > RFCOMM_MAX_DLCI)
+ return (NULL);
+
+ inx = p_mcb->port_inx[dlci];
+ if (inx == 0)
+ return (NULL);
+ else
+ return (&rfc_cb.port.port[inx - 1]);
+}
+
+
+/*******************************************************************************
+**
+** Function port_find_dlci_port
+**
+** Description Find port with DLCI not assigned to multiplexer channel
+**
+** Returns Pointer to the PORT or NULL if not found
+**
+*******************************************************************************/
+tPORT *port_find_dlci_port (UINT8 dlci)
+{
+ UINT16 i;
+ tPORT *p_port;
+
+ for (i = 0; i < MAX_RFC_PORTS; i++)
+ {
+ p_port = &rfc_cb.port.port[i];
+ if (p_port->in_use && (p_port->rfc.p_mcb == NULL))
+ {
+ if (p_port->dlci == dlci)
+ {
+ return (p_port);
+ }
+ else if ((dlci & 0x01) && (p_port->dlci == (dlci - 1)))
+ {
+ p_port->dlci++;
+ return (p_port);
+ }
+ }
+ }
+ return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function port_find_port
+**
+** Description Find port with DLCI, BD_ADDR
+**
+** Returns Pointer to the PORT or NULL if not found
+**
+*******************************************************************************/
+tPORT *port_find_port (UINT8 dlci, BD_ADDR bd_addr)
+{
+ UINT16 i;
+ tPORT *p_port;
+
+ for (i = 0; i < MAX_RFC_PORTS; i++)
+ {
+ p_port = &rfc_cb.port.port[i];
+ if (p_port->in_use
+ && (p_port->dlci == dlci)
+ && !memcmp (p_port->bd_addr, bd_addr, BD_ADDR_LEN))
+ {
+ return (p_port);
+ }
+ }
+ return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function port_flow_control_user
+**
+** Description Check the current user flow control and if necessary return
+** events to be send to the user based on the user's specified
+** flow control type.
+**
+** Returns event mask to be returned to the application
+**
+*******************************************************************************/
+UINT32 port_flow_control_user (tPORT *p_port)
+{
+ UINT32 event = 0;
+
+ /* Flow control to the user can be caused by flow controlling by the peer */
+ /* (FlowInd, or flow control by the peer RFCOMM (Fcon) or internally if */
+ /* tx_queue is full */
+ BOOLEAN fc = p_port->tx.peer_fc
+ || !p_port->rfc.p_mcb
+ || !p_port->rfc.p_mcb->peer_ready
+ || (p_port->tx.queue_size > PORT_TX_HIGH_WM)
+ || (p_port->tx.queue.count > PORT_TX_BUF_HIGH_WM);
+
+ if (p_port->tx.user_fc == fc)
+ return (0);
+
+ p_port->tx.user_fc = fc;
+
+ if (fc)
+ event = PORT_EV_FC;
+ else
+ event = PORT_EV_FC | PORT_EV_FCS;
+
+ return (event);
+}
+
+
+/*******************************************************************************
+**
+** Function port_get_signal_changes
+**
+** Description Check modem signals that has been changed
+**
+** Returns event mask to be returned to the application
+**
+*******************************************************************************/
+UINT32 port_get_signal_changes (tPORT *p_port, UINT8 old_signals, UINT8 signal)
+{
+ UINT8 changed_signals = (signal ^ old_signals);
+ UINT32 events = 0;
+
+ if (changed_signals & PORT_DTRDSR_ON)
+ {
+ events |= PORT_EV_DSR;
+
+ if (signal & PORT_DTRDSR_ON)
+ events |= PORT_EV_DSRS;
+ }
+
+ if (changed_signals & PORT_CTSRTS_ON)
+ {
+ events |= PORT_EV_CTS;
+
+ if (signal & PORT_CTSRTS_ON)
+ events |= PORT_EV_CTSS;
+ }
+
+ if (changed_signals & PORT_RING_ON)
+ events |= PORT_EV_RING;
+
+ if (changed_signals & PORT_DCD_ON)
+ {
+ events |= PORT_EV_RLSD;
+
+ if (signal & PORT_DCD_ON)
+ events |= PORT_EV_RLSDS;
+ }
+
+ return (p_port->ev_mask & events);
+}
+
+/*******************************************************************************
+**
+** Function port_flow_control_peer
+**
+** Description Send flow control messages to the peer for both enabling
+** and disabling flow control, for both credit-based and
+** TS 07.10 flow control mechanisms.
+**
+** Returns nothing
+**
+*******************************************************************************/
+void port_flow_control_peer(tPORT *p_port, BOOLEAN enable, UINT16 count)
+{
+ if (!p_port->rfc.p_mcb)
+ return;
+
+ /* If using credit based flow control */
+ if (p_port->rfc.p_mcb->flow == PORT_FC_CREDIT)
+ {
+ /* if want to enable flow from peer */
+ if (enable)
+ {
+ /* update rx credits */
+ if (count > p_port->credit_rx)
+ {
+ p_port->credit_rx = 0;
+ }
+ else
+ {
+ p_port->credit_rx -= count;
+ }
+
+ /* If credit count is less than low credit watermark, and user */
+ /* did not force flow control, send a credit update */
+ /* There might be a special case when we just adjusted rx_max */
+ if ((p_port->credit_rx <= p_port->credit_rx_low)
+ && !p_port->rx.user_fc
+ && (p_port->credit_rx_max > p_port->credit_rx))
+ {
+ rfc_send_credit(p_port->rfc.p_mcb, p_port->dlci,
+ (UINT8) (p_port->credit_rx_max - p_port->credit_rx));
+
+ p_port->credit_rx = p_port->credit_rx_max;
+
+ p_port->rx.peer_fc = FALSE;
+ }
+ }
+ /* else want to disable flow from peer */
+ else
+ {
+ /* if client registered data callback, just do what they want */
+ if (p_port->p_data_callback)
+ {
+ p_port->rx.peer_fc = TRUE;
+ }
+ /* if queue count reached credit rx max, set peer fc */
+ else if (p_port->rx.queue.count >= p_port->credit_rx_max)
+ {
+ p_port->rx.peer_fc = TRUE;
+ }
+ }
+ }
+ /* else using TS 07.10 flow control */
+ else
+ {
+ /* if want to enable flow from peer */
+ if (enable)
+ {
+ /* If rfcomm suspended traffic from the peer based on the rx_queue_size */
+ /* check if it can be resumed now */
+ if (p_port->rx.peer_fc
+ && (p_port->rx.queue_size < PORT_RX_LOW_WM)
+ && (p_port->rx.queue.count < PORT_RX_BUF_LOW_WM))
+ {
+ p_port->rx.peer_fc = FALSE;
+
+ /* If user did not force flow control allow traffic now */
+ if (!p_port->rx.user_fc)
+ RFCOMM_FlowReq (p_port->rfc.p_mcb, p_port->dlci, TRUE);
+ }
+ }
+ /* else want to disable flow from peer */
+ else
+ {
+ /* if client registered data callback, just do what they want */
+ if (p_port->p_data_callback)
+ {
+ p_port->rx.peer_fc = TRUE;
+ RFCOMM_FlowReq (p_port->rfc.p_mcb, p_port->dlci, FALSE);
+ }
+ /* Check the size of the rx queue. If it exceeds certain */
+ /* level and flow control has not been sent to the peer do it now */
+ else if ( ((p_port->rx.queue_size > PORT_RX_HIGH_WM)
+ || (p_port->rx.queue.count > PORT_RX_BUF_HIGH_WM))
+ && !p_port->rx.peer_fc)
+ {
+ RFCOMM_TRACE_EVENT0 ("PORT_DataInd Data reached HW. Sending FC set.");
+
+ p_port->rx.peer_fc = TRUE;
+ RFCOMM_FlowReq (p_port->rfc.p_mcb, p_port->dlci, FALSE);
+ }
+ }
+ }
+}
+
diff --git a/stack/rfcomm/rfc_int.h b/stack/rfcomm/rfc_int.h
new file mode 100644
index 0000000..fcafdf0
--- /dev/null
+++ b/stack/rfcomm/rfc_int.h
@@ -0,0 +1,373 @@
+/*****************************************************************************/
+/* */
+/* Name: rfc_int.h */
+/* */
+/* Description: This file contains definitions internal to the RFC unit */
+/* */
+/* */
+/* Copyright (c) 1999-2008, Broadcom Corp., All Rights Reserved. */
+/* WIDCOMM Bluetooth Core. Proprietary and confidential. */
+/*****************************************************************************/
+#ifndef RFC_INT_H
+#define RFC_INT_H
+
+#include "l2c_api.h"
+#include "port_int.h"
+
+/*
+** Define RFCOMM result codes
+*/
+#define RFCOMM_SUCCESS 0
+#define RFCOMM_ERROR 1
+#define RFCOMM_LOW_RESOURCES 2
+#define RFCOMM_TRY_LATER 3
+
+#define RFCOMM_USER_ERR 111
+#define RFCOMM_SECURITY_ERR 112
+
+/*
+** Define max and min RFCOMM MTU (N1)
+*/
+#define RFCOMM_MIN_MTU 23
+#define RFCOMM_MAX_MTU 32767
+
+extern void RFCOMM_StartReq (tRFC_MCB *p_mcb);
+extern void RFCOMM_StartRsp (tRFC_MCB *p_mcb, UINT16 result);
+
+extern void RFCOMM_DlcEstablishReq (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu);
+extern void RFCOMM_DlcEstablishRsp (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu, UINT16 result);
+
+extern void RFCOMM_DataReq (tRFC_MCB *p_mcb, UINT8 dlci, BT_HDR *p_buf);
+
+extern void RFCOMM_DlcReleaseReq (tRFC_MCB *p_mcb, UINT8 dlci);
+
+extern void RFCOMM_ParNegReq (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu);
+extern void RFCOMM_ParNegRsp (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu, UINT8 cl, UINT8 k);
+
+extern void RFCOMM_TestReq (UINT8 *p_data, UINT16 len);
+
+#define RFCOMM_FLOW_STATE_DISABLE 0
+#define RFCOMM_FLOW_STATE_ENABLE 1
+
+extern void RFCOMM_FlowReq (tRFC_MCB *p_mcb, UINT8 dlci, UINT8 state);
+
+extern void RFCOMM_PortNegReq (tRFC_MCB *p_mcb, UINT8 dlci, tPORT_STATE *p_pars);
+extern void RFCOMM_PortNegRsp (tRFC_MCB *p_mcb, UINT8 dlci, tPORT_STATE *p_pars, UINT16 param_mask);
+
+extern void RFCOMM_ControlReq (tRFC_MCB *p_mcb, UINT8 dlci, tPORT_CTRL *p_pars);
+extern void RFCOMM_ControlRsp (tRFC_MCB *p_mcb, UINT8 dlci, tPORT_CTRL *p_pars);
+
+extern void RFCOMM_LineStatusReq (tRFC_MCB *p_mcb, UINT8 dlci, UINT8 line_status);
+/*
+** Define logical struct used for sending and decoding MX frames
+*/
+typedef struct
+{
+ UINT8 dlci;
+ UINT8 type;
+ UINT8 cr;
+ UINT8 ea;
+ UINT8 pf;
+ UINT8 credit;
+
+ union
+ {
+ struct
+ {
+ UINT8 dlci;
+ UINT8 frame_type;
+ UINT8 conv_layer;
+ UINT8 priority;
+ UINT8 t1;
+ UINT16 mtu;
+ UINT8 n2;
+ UINT8 k;
+ } pn;
+ struct
+ {
+ UINT8 *p_data;
+ UINT16 data_len;
+ } test;
+ struct
+ {
+ UINT8 dlci;
+ UINT8 signals;
+ UINT8 break_present;
+ UINT8 break_duration;
+ } msc;
+ struct
+ {
+ UINT8 ea;
+ UINT8 cr;
+ UINT8 type;
+ } nsc;
+ struct
+ {
+ UINT8 dlci;
+ UINT8 is_request;
+ UINT8 baud_rate;
+ UINT8 byte_size;
+ UINT8 stop_bits;
+ UINT8 parity;
+ UINT8 parity_type;
+ UINT8 fc_type;
+ UINT8 xon_char;
+ UINT8 xoff_char;
+ UINT16 param_mask;
+ } rpn;
+ struct
+ {
+ UINT8 dlci;
+ UINT8 line_status;
+ } rls;
+ } u;
+} MX_FRAME;
+
+#define LINE_STATUS_NO_ERROR 0x00
+#define LINE_STATUS_OVERRUN 0x02 /* Receive Overrun Error */
+#define LINE_STATUS_RXPARITY 0x04 /* Receive Parity Error */
+#define LINE_STATUS_FRAME 0x08 /* Receive Framing error */
+#define LINE_STATUS_FAILED 0x10 /* Connection Failed */
+
+/*
+** Define states and events for the RFC multiplexer state machine
+*/
+#define RFC_MX_STATE_IDLE 0
+#define RFC_MX_STATE_WAIT_CONN_CNF 1
+#define RFC_MX_STATE_CONFIGURE 2
+#define RFC_MX_STATE_SABME_WAIT_UA 3
+#define RFC_MX_STATE_WAIT_SABME 4
+#define RFC_MX_STATE_CONNECTED 5
+#define RFC_MX_STATE_DISC_WAIT_UA 6
+
+/*
+** Define port states
+*/
+#define RFC_STATE_CLOSED 0
+#define RFC_STATE_SABME_WAIT_UA 1
+#define RFC_STATE_ORIG_WAIT_SEC_CHECK 2
+#define RFC_STATE_TERM_WAIT_SEC_CHECK 3
+#define RFC_STATE_OPENED 4
+#define RFC_STATE_DISC_WAIT_UA 5
+
+/*
+** Events that can be received by multiplexer as well as port state machines
+*/
+#define RFC_EVENT_SABME 0
+#define RFC_EVENT_UA 1
+#define RFC_EVENT_DM 2
+#define RFC_EVENT_DISC 3
+#define RFC_EVENT_UIH 4
+#define RFC_EVENT_TIMEOUT 5
+#define RFC_EVENT_BAD_FRAME 50
+/*
+** Multiplexer events
+*/
+#define RFC_MX_EVENT_START_REQ 6
+#define RFC_MX_EVENT_START_RSP 7
+#define RFC_MX_EVENT_CLOSE_REQ 8
+#define RFC_MX_EVENT_CONN_CNF 9
+#define RFC_MX_EVENT_CONN_IND 10
+#define RFC_MX_EVENT_CONF_CNF 11
+#define RFC_MX_EVENT_CONF_IND 12
+#define RFC_MX_EVENT_QOS_VIOLATION_IND 13
+#define RFC_MX_EVENT_DISC_IND 14
+#define RFC_MX_EVENT_TEST_CMD 15
+#define RFC_MX_EVENT_TEST_RSP 16
+#define RFC_MX_EVENT_FCON_CMD 17
+#define RFC_MX_EVENT_FCOFF_CMD 18
+#define RFC_MX_EVENT_NSC 19
+#define RFC_MX_EVENT_NSC_RSP 20
+
+/*
+** Port events
+*/
+#define RFC_EVENT_OPEN 9
+#define RFC_EVENT_ESTABLISH_RSP 11
+#define RFC_EVENT_CLOSE 12
+#define RFC_EVENT_CLEAR 13
+#define RFC_EVENT_DATA 14
+#define RFC_EVENT_SEC_COMPLETE 15
+
+// btla-specific ++
+#define RFC_T1_TIMEOUT 20 /* seconds to wait for reply with Poll bit */
+#define RFC_PORT_T1_TIMEOUT 60 /* seconds to wait for reply with Poll bit other than MX */
+#define RFC_T2_TIMEOUT 20 /* timeout to wait for Mx UIH */
+// btla-specific --
+#define RFC_DISC_TIMEOUT 3 /* If something goes wrong and we send DISC we should not wait for min */
+#define RFC_CLOSE_TIMEOUT 10
+#define RFCOMM_CONN_TIMEOUT 120 /* first connection to be established on Mx */
+
+
+/* Define RFComm control block
+*/
+typedef struct
+{
+ MX_FRAME rx_frame;
+ tL2CAP_APPL_INFO reg_info; /* L2CAP Registration info */
+ tRFC_MCB *p_rfc_lcid_mcb[MAX_L2CAP_CHANNELS]; /* MCB based on the L2CAP's lcid */
+ BOOLEAN peer_rx_disabled; /* If TRUE peer sent FCOFF */
+ UINT8 last_mux; /* Last mux allocated */
+ UINT8 last_port; /* Last port allocated */
+} tRFCOMM_CB;
+
+/* Main Control Block for the RFCOMM Layer (PORT and RFC) */
+typedef struct
+{
+ tRFCOMM_CB rfc;
+ tPORT_CB port;
+ UINT8 trace_level;
+} tRFC_CB;
+
+
+#if RFC_DYNAMIC_MEMORY == FALSE
+RFC_API extern tRFC_CB rfc_cb;
+#else
+RFC_API extern tRFC_CB *rfc_cb_ptr;
+#define rfc_cb (*rfc_cb_ptr)
+#endif
+
+/* Timer running on the multiplexor channel while no DLCI connection is opened */
+#define RFC_MCB_INIT_INACT_TIMER 60 /* in seconds */
+
+/* Timer running on the multiplexor channel after last DLCI is released */
+#define RFC_MCB_RELEASE_INACT_TIMER 2 /* in seconds */
+
+/*
+** Define RFCOMM frame processing errors
+*/
+#define RFCOMM_ERR_BAD_SABME 1
+#define RFCOMM_ERR_BAD_UA 2
+#define RFCOMM_ERR_BAD_DM 3
+#define RFCOMM_ERR_BAD_DISC 4
+#define RFCOMM_ERR_BAD_UIH 5
+
+#ifdef RFCOMM_PRECALC_FCS
+
+#define RFCOMM_SABME_FCS(p_data, cr, dlci) rfc_sabme_fcs[cr][dlci]
+#define RFCOMM_UA_FCS(p_data, cr, dlci) rfc_ua_fcs[cr][dlci]
+#define RFCOMM_DM_FCS(p_data, cr, dlci) rfc_dm_fcs[cr][dlci]
+#define RFCOMM_DISC_FCS(p_data, cr, dlci) rfc_disc_fcs[cr][dlci]
+#define RFCOMM_UIH_FCS(p_data, dlci) rfc_uih_fcs[dlci]
+
+#else
+
+extern UINT8 rfc_calc_fcs (UINT16 len, UINT8 *p);
+
+#define RFCOMM_SABME_FCS(p_data, cr, dlci) rfc_calc_fcs(3, p_data)
+#define RFCOMM_UA_FCS(p_data, cr, dlci) rfc_calc_fcs(3, p_data)
+#define RFCOMM_DM_FCS(p_data, cr, dlci) rfc_calc_fcs(3, p_data)
+#define RFCOMM_DISC_FCS(p_data, cr, dlci) rfc_calc_fcs(3, p_data)
+#define RFCOMM_UIH_FCS(p_data, dlci) rfc_calc_fcs(2, p_data)
+
+#endif
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void rfc_mx_sm_execute (tRFC_MCB *p_mcb, UINT16 event, void *p_data);
+
+/*
+** Functions provided by the rfc_port_fsm.c
+*/
+extern void rfc_port_sm_execute (tPORT *p_port, UINT16 event, void *p_data);
+
+
+extern void rfc_process_pn (tRFC_MCB *p_rfc_mcb, BOOLEAN is_command, MX_FRAME *p_frame);
+extern void rfc_process_msc (tRFC_MCB *p_rfc_mcb, BOOLEAN is_command, MX_FRAME *p_frame);
+extern void rfc_process_rpn (tRFC_MCB *p_rfc_mcb, BOOLEAN is_command, BOOLEAN is_request, MX_FRAME *p_frame);
+extern void rfc_process_rls (tRFC_MCB *p_rfc_mcb, BOOLEAN is_command, MX_FRAME *p_frame);
+extern void rfc_process_nsc (tRFC_MCB *p_rfc_mcb, MX_FRAME *p_frame);
+extern void rfc_process_test_rsp (tRFC_MCB *p_rfc_mcb, BT_HDR *p_buf);
+extern void rfc_process_fcon (tRFC_MCB *p_rfc_mcb, BOOLEAN is_command);
+extern void rfc_process_fcoff (tRFC_MCB *p_rfc_mcb, BOOLEAN is_command);
+extern void rfc_process_l2cap_congestion (tRFC_MCB *p_mcb, BOOLEAN is_congested);
+
+/*
+** Functions provided by the rfc_utils.c
+*/
+tRFC_MCB *rfc_alloc_multiplexer_channel (BD_ADDR bd_addr, BOOLEAN is_initiator);
+extern void rfc_release_multiplexer_channel (tRFC_MCB *p_rfc_mcb);
+extern void rfc_timer_start (tRFC_MCB *p_rfc_mcb, UINT16 timeout);
+extern void rfc_timer_stop (tRFC_MCB *p_rfc_mcb);
+extern void rfc_port_timer_start (tPORT *p_port, UINT16 tout);
+extern void rfc_port_timer_stop (tPORT *p_port);
+
+BOOLEAN rfc_check_uih_fcs (UINT8 dlci, UINT8 received_fcs);
+BOOLEAN rfc_check_fcs (UINT16 len, UINT8 *p, UINT8 received_fcs);
+tRFC_MCB *rfc_find_lcid_mcb (UINT16 lcid);
+extern void rfc_save_lcid_mcb (tRFC_MCB *p_rfc_mcb, UINT16 lcid);
+extern void rfc_check_mcb_active (tRFC_MCB *p_mcb);
+extern void rfc_port_closed (tPORT *p_port);
+extern void rfc_sec_check_complete (BD_ADDR bd_addr, void *p_ref_data, UINT8 res);
+extern void rfc_inc_credit (tPORT *p_port, UINT8 credit);
+extern void rfc_dec_credit (tPORT *p_port);
+extern void rfc_check_send_cmd(tRFC_MCB *p_mcb, BT_HDR *p_buf);
+
+/*
+** Functions provided by the rfc_ts_frames.c
+*/
+extern void rfc_send_sabme (tRFC_MCB *p_rfc_mcb, UINT8 dlci);
+extern void rfc_send_ua (tRFC_MCB *p_rfc_mcb, UINT8 dlci);
+extern void rfc_send_dm (tRFC_MCB *p_rfc_mcb, UINT8 dlci, BOOLEAN pf);
+extern void rfc_send_disc (tRFC_MCB *p_rfc_mcb, UINT8 dlci);
+extern void rfc_send_pn (tRFC_MCB *p_mcb, UINT8 dlci, BOOLEAN is_command, UINT16 mtu,
+ UINT8 cl, UINT8 k);
+extern void rfc_send_test (tRFC_MCB *p_rfc_mcb, BOOLEAN is_command, BT_HDR *p_buf);
+extern void rfc_send_msc (tRFC_MCB *p_mcb, UINT8 dlci, BOOLEAN is_command,
+ tPORT_CTRL *p_pars);
+extern void rfc_send_rls (tRFC_MCB *p_mcb, UINT8 dlci, BOOLEAN is_command, UINT8 status);
+extern void rfc_send_rpn (tRFC_MCB *p_mcb, UINT8 dlci, BOOLEAN is_command,
+ tPORT_STATE *p_pars, UINT16 mask);
+extern void rfc_send_fcon (tRFC_MCB *p_mcb, BOOLEAN is_command);
+extern void rfc_send_fcoff (tRFC_MCB *p_mcb, BOOLEAN is_command);
+extern void rfc_send_buf_uih (tRFC_MCB *p_rfc_mcb, UINT8 dlci, BT_HDR *p_buf);
+extern void rfc_send_credit(tRFC_MCB *p_mcb, UINT8 dlci, UINT8 credit);
+extern void rfc_process_mx_message (tRFC_MCB *p_rfc_mcb, BT_HDR *p_buf);
+extern UINT8 rfc_parse_data (tRFC_MCB *p_rfc_mcb, MX_FRAME *p_frame, BT_HDR *p_buf);
+
+/*
+** Functions provided by the rfc_disp.c
+*/
+
+
+
+/* Call back functions from RFCOMM */
+extern void rfcomm_l2cap_if_init (void);
+
+extern void PORT_StartInd (tRFC_MCB *p_mcb);
+extern void PORT_StartCnf (tRFC_MCB *p_mcb, UINT16 result);
+
+extern void PORT_CloseInd (tRFC_MCB *p_mcb);
+extern void Port_TimeOutCloseMux (tRFC_MCB *p_mcb);
+
+extern void PORT_DlcEstablishInd (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu);
+extern void PORT_DlcEstablishCnf (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu, UINT16 result);
+
+extern void PORT_DataInd (tRFC_MCB *p_mcb, UINT8 dlci, BT_HDR *p_buf);
+
+extern void PORT_DlcReleaseInd (tRFC_MCB *p_mcb, UINT8 dlci);
+
+extern void PORT_ParNegInd (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu, UINT8 cl, UINT8 k);
+extern void PORT_ParNegCnf (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu, UINT8 cl, UINT8 k);
+
+extern void PORT_TestCnf (tRFC_MCB *p_mcb, UINT8 *p_data, UINT16 len);
+
+extern void PORT_FlowInd (tRFC_MCB *p_mcb, UINT8 dlci, BOOLEAN fc);
+
+extern void PORT_PortNegInd (tRFC_MCB *p_mcb, UINT8 dlci, tPORT_STATE *p_pars, UINT16 param_mask);
+extern void PORT_PortNegCnf (tRFC_MCB *p_mcb, UINT8 dlci, tPORT_STATE *p_pars, UINT16 result);
+
+extern void PORT_ControlInd (tRFC_MCB *p_mcb, UINT8 dlci, tPORT_CTRL *p_pars);
+extern void PORT_ControlCnf (tRFC_MCB *p_mcb, UINT8 dlci, tPORT_CTRL *p_pars);
+
+extern void PORT_LineStatusInd (tRFC_MCB *p_mcb, UINT8 dlci, UINT8 line_status);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/stack/rfcomm/rfc_l2cap_if.c b/stack/rfcomm/rfc_l2cap_if.c
new file mode 100644
index 0000000..fb10d07
--- /dev/null
+++ b/stack/rfcomm/rfc_l2cap_if.c
@@ -0,0 +1,430 @@
+/*****************************************************************************
+**
+** Name: rfc_l2cap_if.c
+**
+** Description: This file contains L2CAP interface functions
+**
+**
+** Copyright (c) 1999-2009, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+
+#include "bt_target.h"
+#include "gki.h"
+
+#include "rfcdefs.h"
+#include "port_api.h"
+#include "port_int.h"
+#include "l2c_api.h"
+#include "l2cdefs.h"
+#include "rfc_int.h"
+
+
+/*
+** Define Callback functions to be called by L2CAP
+*/
+static void RFCOMM_ConnectInd (BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id);
+static void RFCOMM_ConnectCnf (UINT16 lcid, UINT16 err);
+static void RFCOMM_ConfigInd (UINT16 lcid, tL2CAP_CFG_INFO *p_cfg);
+static void RFCOMM_ConfigCnf (UINT16 lcid, tL2CAP_CFG_INFO *p_cfg);
+static void RFCOMM_DisconnectInd (UINT16 lcid, BOOLEAN is_clear);
+static void RFCOMM_QoSViolationInd (BD_ADDR bd_addr);
+static void RFCOMM_BufDataInd (UINT16 lcid, BT_HDR *p_buf);
+static void RFCOMM_CongestionStatusInd (UINT16 lcid, BOOLEAN is_congested);
+
+
+/*******************************************************************************
+**
+** Function rfcomm_l2cap_if_init
+**
+** Description This function is called during the RFCOMM task startup
+** to register interface functions with L2CAP.
+**
+*******************************************************************************/
+void rfcomm_l2cap_if_init (void)
+{
+ tL2CAP_APPL_INFO *p_l2c = &rfc_cb.rfc.reg_info;
+
+ p_l2c->pL2CA_ConnectInd_Cb = RFCOMM_ConnectInd;
+ p_l2c->pL2CA_ConnectCfm_Cb = RFCOMM_ConnectCnf;
+ p_l2c->pL2CA_ConnectPnd_Cb = NULL;
+ p_l2c->pL2CA_ConfigInd_Cb = RFCOMM_ConfigInd;
+ p_l2c->pL2CA_ConfigCfm_Cb = RFCOMM_ConfigCnf;
+ p_l2c->pL2CA_DisconnectInd_Cb = RFCOMM_DisconnectInd;
+ p_l2c->pL2CA_DisconnectCfm_Cb = NULL;
+ p_l2c->pL2CA_QoSViolationInd_Cb = RFCOMM_QoSViolationInd;
+ p_l2c->pL2CA_DataInd_Cb = RFCOMM_BufDataInd;
+ p_l2c->pL2CA_CongestionStatus_Cb = RFCOMM_CongestionStatusInd;
+ p_l2c->pL2CA_TxComplete_Cb = NULL;
+
+
+ L2CA_Register (BT_PSM_RFCOMM, p_l2c);
+}
+
+
+/*******************************************************************************
+**
+** Function RFCOMM_ConnectInd
+**
+** Description This is a callback function called by L2CAP when
+** L2CA_ConnectInd received. Allocate multiplexer control block
+** and dispatch the event to it.
+**
+*******************************************************************************/
+void RFCOMM_ConnectInd (BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id)
+{
+ tRFC_MCB *p_mcb = rfc_alloc_multiplexer_channel(bd_addr, FALSE);
+
+ if ((p_mcb)&&(p_mcb->state != RFC_MX_STATE_IDLE))
+ {
+ /* if this is collision case */
+ if ((p_mcb->is_initiator)&&(p_mcb->state == RFC_MX_STATE_WAIT_CONN_CNF))
+ {
+ p_mcb->pending_lcid = lcid;
+ p_mcb->pending_id = id;
+
+ /* wait random timeout (2 - 12) to resolve collision */
+ /* if peer gives up then local device rejects incoming connection and continues as initiator */
+ /* if timeout, local device disconnects outgoing connection and continues as acceptor */
+ RFCOMM_TRACE_DEBUG2 ("RFCOMM_ConnectInd start timer for collision, initiator's LCID(0x%x), acceptor's LCID(0x%x)",
+ p_mcb->lcid, p_mcb->pending_lcid);
+
+ rfc_timer_start(p_mcb, (UINT16)(GKI_get_tick_count()%10 + 2));
+ return;
+ }
+ else
+ {
+ /* we cannot accept connection request from peer at this state */
+ /* don't update lcid */
+ p_mcb = NULL;
+ }
+ }
+ else
+ {
+ /* store mcb even if null */
+ rfc_save_lcid_mcb (p_mcb, lcid);
+ }
+
+ if (p_mcb == NULL)
+ {
+ L2CA_ConnectRsp (bd_addr, id, lcid, L2CAP_CONN_NO_RESOURCES, 0);
+ return;
+ }
+ p_mcb->lcid = lcid;
+
+ rfc_mx_sm_execute (p_mcb, RFC_MX_EVENT_CONN_IND, &id);
+}
+
+
+/*******************************************************************************
+**
+** Function RFCOMM_ConnectCnf
+**
+** Description This is a callback function called by L2CAP when
+** L2CA_ConnectCnf received. Save L2CAP handle and dispatch
+** event to the FSM.
+**
+*******************************************************************************/
+void RFCOMM_ConnectCnf (UINT16 lcid, UINT16 result)
+{
+ tRFC_MCB *p_mcb = rfc_find_lcid_mcb (lcid);
+
+ if (!p_mcb)
+ {
+ RFCOMM_TRACE_ERROR1 ("RFCOMM_ConnectCnf LCID:0x%x", lcid);
+ return;
+ }
+
+ if (p_mcb->pending_lcid)
+ {
+ /* if peer rejects our connect request but peer's connect request is pending */
+ if (result != L2CAP_CONN_OK )
+ {
+ UINT16 i;
+ UINT8 idx;
+
+ RFCOMM_TRACE_DEBUG1 ("RFCOMM_ConnectCnf retry as acceptor on pending LCID(0x%x)", p_mcb->pending_lcid);
+
+ /* remove mcb from mapping table */
+ rfc_save_lcid_mcb (NULL, p_mcb->lcid);
+
+ p_mcb->lcid = p_mcb->pending_lcid;
+ p_mcb->is_initiator = FALSE;
+ p_mcb->state = RFC_MX_STATE_IDLE;
+
+ /* store mcb into mapping table */
+ rfc_save_lcid_mcb (p_mcb, p_mcb->lcid);
+
+ /* update direction bit */
+ for (i = 0; i < RFCOMM_MAX_DLCI; i += 2)
+ {
+ if ((idx = p_mcb->port_inx[i]) != 0)
+ {
+ p_mcb->port_inx[i] = 0;
+ p_mcb->port_inx[i+1] = idx;
+ rfc_cb.port.port[idx - 1].dlci += 1;
+ RFCOMM_TRACE_DEBUG2 ("RFCOMM MX - DLCI:%d -> %d", i, rfc_cb.port.port[idx - 1].dlci);
+ }
+ }
+
+ rfc_mx_sm_execute (p_mcb, RFC_MX_EVENT_CONN_IND, &(p_mcb->pending_id));
+ return;
+ }
+ else
+ {
+ RFCOMM_TRACE_DEBUG1 ("RFCOMM_ConnectCnf peer gave up pending LCID(0x%x)", p_mcb->pending_lcid);
+
+ /* Peer gave up his connection request, make sure cleaning up L2CAP channel */
+ L2CA_ConnectRsp (p_mcb->bd_addr, p_mcb->pending_id, p_mcb->pending_lcid, L2CAP_CONN_NO_RESOURCES, 0);
+
+ p_mcb->pending_lcid = 0;
+ }
+ }
+
+ /* Save LCID to be used in all consecutive calls to L2CAP */
+ p_mcb->lcid = lcid;
+
+ rfc_mx_sm_execute (p_mcb, RFC_MX_EVENT_CONN_CNF, &result);
+}
+
+
+/*******************************************************************************
+**
+** Function RFCOMM_ConfigInd
+**
+** Description This is a callback function called by L2CAP when
+** L2CA_ConfigInd received. Save parameters in the control
+** block and dispatch event to the FSM.
+**
+*******************************************************************************/
+void RFCOMM_ConfigInd (UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
+{
+ tRFC_MCB *p_mcb = rfc_find_lcid_mcb (lcid);
+
+ if (!p_mcb)
+ {
+ RFCOMM_TRACE_ERROR1 ("RFCOMM_ConfigInd LCID:0x%x", lcid);
+ return;
+ }
+
+ rfc_mx_sm_execute (p_mcb, RFC_MX_EVENT_CONF_IND, (void *)p_cfg);
+}
+
+
+/*******************************************************************************
+**
+** Function RFCOMM_ConfigCnf
+**
+** Description This is a callback function called by L2CAP when
+** L2CA_ConfigCnf received. Save L2CAP handle and dispatch
+** event to the FSM.
+**
+*******************************************************************************/
+void RFCOMM_ConfigCnf (UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
+{
+ tRFC_MCB *p_mcb = rfc_find_lcid_mcb (lcid);
+
+ if (!p_mcb)
+ {
+ RFCOMM_TRACE_ERROR1 ("RFCOMM_ConfigCnf no MCB LCID:0x%x", lcid);
+ return;
+ }
+
+ rfc_mx_sm_execute (p_mcb, RFC_MX_EVENT_CONF_CNF, (void *)p_cfg);
+}
+
+
+/*******************************************************************************
+**
+** Function RFCOMM_QoSViolationInd
+**
+** Description This is a callback function called by L2CAP when
+** L2CA_QoSViolationIndInd received. Dispatch event to the FSM.
+**
+*******************************************************************************/
+void RFCOMM_QoSViolationInd (BD_ADDR bd_addr)
+{
+}
+
+
+/*******************************************************************************
+**
+** Function RFCOMM_DisconnectInd
+**
+** Description This is a callback function called by L2CAP when
+** L2CA_DisconnectInd received. Dispatch event to the FSM.
+**
+*******************************************************************************/
+void RFCOMM_DisconnectInd (UINT16 lcid, BOOLEAN is_conf_needed)
+{
+ tRFC_MCB *p_mcb = rfc_find_lcid_mcb (lcid);
+
+ if (is_conf_needed)
+ {
+ L2CA_DisconnectRsp (lcid);
+ }
+
+ if (!p_mcb)
+ {
+ RFCOMM_TRACE_WARNING1 ("RFCOMM_DisconnectInd LCID:0x%x", lcid);
+ return;
+ }
+
+ rfc_mx_sm_execute (p_mcb, RFC_MX_EVENT_DISC_IND, NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function RFCOMM_BufDataInd
+**
+** Description This is a callback function called by L2CAP when
+** data RFCOMM frame is received. Parse the frames, check
+** the checksum and dispatch event to multiplexer or port
+** state machine depending on the frame destination.
+**
+*******************************************************************************/
+void RFCOMM_BufDataInd (UINT16 lcid, BT_HDR *p_buf)
+{
+ tRFC_MCB *p_mcb = rfc_find_lcid_mcb (lcid);
+ tPORT *p_port;
+ UINT8 event;
+
+
+ if (!p_mcb)
+ {
+ RFCOMM_TRACE_WARNING1 ("RFCOMM_BufDataInd LCID:0x%x", lcid);
+ GKI_freebuf (p_buf);
+ return;
+ }
+
+ event = rfc_parse_data (p_mcb, &rfc_cb.rfc.rx_frame, p_buf);
+
+ /* If the frame did not pass validation just ignore it */
+ if (event == RFC_EVENT_BAD_FRAME)
+ {
+ GKI_freebuf (p_buf);
+ return;
+ }
+
+ if (rfc_cb.rfc.rx_frame.dlci == RFCOMM_MX_DLCI)
+ {
+ /* Take special care of the Multiplexer Control Messages */
+ if (event == RFC_EVENT_UIH)
+ {
+ rfc_process_mx_message (p_mcb, p_buf);
+ return;
+ }
+
+ /* Other multiplexer events go to state machine */
+ rfc_mx_sm_execute (p_mcb, event, NULL);
+ GKI_freebuf (p_buf);
+ return;
+ }
+
+ /* The frame was received on the data channel DLCI, verify that DLC exists */
+ if (((p_port = port_find_mcb_dlci_port (p_mcb, rfc_cb.rfc.rx_frame.dlci)) == NULL)
+ || (!p_port->rfc.p_mcb))
+ {
+ /* If this is a SABME on the new port, check if any appl is waiting for it */
+ if (event != RFC_EVENT_SABME)
+ {
+ if (( p_mcb->is_initiator && !rfc_cb.rfc.rx_frame.cr)
+ || (!p_mcb->is_initiator && rfc_cb.rfc.rx_frame.cr))
+ rfc_send_dm (p_mcb, rfc_cb.rfc.rx_frame.dlci, rfc_cb.rfc.rx_frame.pf);
+ GKI_freebuf (p_buf);
+ return;
+ }
+
+ if ((p_port = port_find_dlci_port (rfc_cb.rfc.rx_frame.dlci)) == NULL)
+ {
+ rfc_send_dm (p_mcb, rfc_cb.rfc.rx_frame.dlci, TRUE);
+ GKI_freebuf (p_buf);
+ return;
+ }
+ p_mcb->port_inx[rfc_cb.rfc.rx_frame.dlci] = p_port->inx;
+ p_port->rfc.p_mcb = p_mcb;
+ }
+
+ if (event == RFC_EVENT_UIH)
+ {
+ if (p_buf->len > 0)
+ rfc_port_sm_execute (p_port, event, p_buf);
+ else
+ GKI_freebuf (p_buf);
+
+ if (rfc_cb.rfc.rx_frame.credit != 0)
+ rfc_inc_credit (p_port, rfc_cb.rfc.rx_frame.credit);
+
+ return;
+ }
+ rfc_port_sm_execute (p_port, event, NULL);
+ GKI_freebuf (p_buf);
+}
+
+/*******************************************************************************
+**
+** Function RFCOMM_CongestionStatusInd
+**
+** Description This is a callback function called by L2CAP when
+** data RFCOMM L2CAP congestion status changes
+**
+*******************************************************************************/
+void RFCOMM_CongestionStatusInd (UINT16 lcid, BOOLEAN is_congested)
+{
+ tRFC_MCB *p_mcb = rfc_find_lcid_mcb (lcid);
+
+ if (!p_mcb)
+ {
+ RFCOMM_TRACE_ERROR1 ("RFCOMM_CongestionStatusInd dropped LCID:0x%x", lcid);
+ return;
+ }
+ else
+ {
+ RFCOMM_TRACE_EVENT1 ("RFCOMM_CongestionStatusInd LCID:0x%x", lcid);
+ }
+ rfc_process_l2cap_congestion (p_mcb, is_congested);
+}
+
+/*******************************************************************************
+**
+** Function rfc_find_lcid_mcb
+**
+** Description This function returns MCB block supporting local cid
+**
+*******************************************************************************/
+tRFC_MCB *rfc_find_lcid_mcb (UINT16 lcid)
+{
+ tRFC_MCB *p_mcb;
+
+ if (lcid - L2CAP_BASE_APPL_CID >= MAX_L2CAP_CHANNELS)
+ {
+ RFCOMM_TRACE_ERROR1 ("rfc_find_lcid_mcb LCID:0x%x", lcid);
+ return (NULL);
+ }
+ else
+ {
+ if ((p_mcb = rfc_cb.rfc.p_rfc_lcid_mcb[lcid - L2CAP_BASE_APPL_CID]) != NULL)
+ {
+ if (p_mcb->lcid != lcid)
+ {
+ RFCOMM_TRACE_WARNING2 ("rfc_find_lcid_mcb LCID reused LCID:0x%x current:0x%x", lcid, p_mcb->lcid);
+ return (NULL);
+ }
+ }
+ }
+ return (p_mcb);
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_save_lcid_mcb
+**
+** Description This function returns MCB block supporting local cid
+**
+*******************************************************************************/
+void rfc_save_lcid_mcb (tRFC_MCB *p_mcb, UINT16 lcid)
+{
+ rfc_cb.rfc.p_rfc_lcid_mcb[lcid - L2CAP_BASE_APPL_CID] = p_mcb;
+}
diff --git a/stack/rfcomm/rfc_mx_fsm.c b/stack/rfcomm/rfc_mx_fsm.c
new file mode 100644
index 0000000..2f267a7
--- /dev/null
+++ b/stack/rfcomm/rfc_mx_fsm.c
@@ -0,0 +1,650 @@
+/*****************************************************************************
+**
+** Name: rfc_mx_fsm.c
+**
+** Description: This file contains state machine and action routines for
+** multiplexer channel of the RFCOMM unit
+**
+**
+** Copyright (c) 1999-2010, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+#include <string.h>
+#include "gki.h"
+#include "bt_types.h"
+#include "rfcdefs.h"
+#include "l2cdefs.h"
+#include "port_api.h"
+#include "port_int.h"
+#include "l2c_api.h"
+#include "rfc_int.h"
+
+#define L2CAP_SUCCESS 0
+#define L2CAP_ERROR 1
+
+
+/********************************************************************************/
+/* L O C A L F U N C T I O N P R O T O T Y P E S */
+/********************************************************************************/
+static void rfc_mx_sm_state_idle (tRFC_MCB *p_mcb, UINT16 event, void *p_data);
+static void rfc_mx_sm_state_wait_conn_cnf (tRFC_MCB *p_mcb, UINT16 event, void *p_data);
+static void rfc_mx_sm_state_configure (tRFC_MCB *p_mcb, UINT16 event, void *p_data);
+static void rfc_mx_sm_sabme_wait_ua (tRFC_MCB *p_mcb, UINT16 event, void *p_data);
+static void rfc_mx_sm_state_wait_sabme (tRFC_MCB *p_mcb, UINT16 event, void *p_data);
+static void rfc_mx_sm_state_connected (tRFC_MCB *p_mcb, UINT16 event, void *p_data);
+static void rfc_mx_sm_state_disc_wait_ua (tRFC_MCB *p_mcb, UINT16 event, void *p_data);
+
+static void rfc_mx_send_config_req (tRFC_MCB *p_mcb);
+static void rfc_mx_conf_ind (tRFC_MCB *p_mcb, tL2CAP_CFG_INFO *p_cfg);
+static void rfc_mx_conf_cnf (tRFC_MCB *p_mcb, tL2CAP_CFG_INFO *p_cfg);
+
+
+
+/*******************************************************************************
+**
+** Function rfc_mx_sm_execute
+**
+** Description This function sends multiplexor events through the state
+** machine.
+**
+** Returns void
+**
+*******************************************************************************/
+void rfc_mx_sm_execute (tRFC_MCB *p_mcb, UINT16 event, void *p_data)
+{
+ switch (p_mcb->state)
+ {
+ case RFC_MX_STATE_IDLE:
+ rfc_mx_sm_state_idle (p_mcb, event, p_data);
+ break;
+
+ case RFC_MX_STATE_WAIT_CONN_CNF:
+ rfc_mx_sm_state_wait_conn_cnf (p_mcb, event, p_data);
+ break;
+
+ case RFC_MX_STATE_CONFIGURE:
+ rfc_mx_sm_state_configure (p_mcb, event, p_data);
+ break;
+
+ case RFC_MX_STATE_SABME_WAIT_UA:
+ rfc_mx_sm_sabme_wait_ua (p_mcb, event, p_data);
+ break;
+
+ case RFC_MX_STATE_WAIT_SABME:
+ rfc_mx_sm_state_wait_sabme (p_mcb, event, p_data);
+ break;
+
+ case RFC_MX_STATE_CONNECTED:
+ rfc_mx_sm_state_connected (p_mcb, event, p_data);
+ break;
+
+ case RFC_MX_STATE_DISC_WAIT_UA:
+ rfc_mx_sm_state_disc_wait_ua (p_mcb, event, p_data);
+ break;
+
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_mx_sm_state_idle
+**
+** Description This function handles events when the multiplexer is in
+** IDLE state. This state exists when connection is being
+** initially established.
+**
+** Returns void
+**
+*******************************************************************************/
+void rfc_mx_sm_state_idle (tRFC_MCB *p_mcb, UINT16 event, void *p_data)
+{
+ RFCOMM_TRACE_EVENT1 ("rfc_mx_sm_state_idle - evt:%d", event);
+ switch (event)
+ {
+ case RFC_MX_EVENT_START_REQ:
+
+ /* Initialize L2CAP MTU */
+ p_mcb->peer_l2cap_mtu = L2CAP_DEFAULT_MTU - RFCOMM_MIN_OFFSET - 1;
+
+ if ((p_mcb->lcid = L2CA_ConnectReq (BT_PSM_RFCOMM, p_mcb->bd_addr)) == 0)
+ {
+ PORT_StartCnf (p_mcb, RFCOMM_ERROR);
+ return;
+ }
+ /* Save entry for quicker access to mcb based on the LCID */
+ rfc_save_lcid_mcb (p_mcb, p_mcb->lcid);
+
+ p_mcb->state = RFC_MX_STATE_WAIT_CONN_CNF;
+ return;
+
+ case RFC_MX_EVENT_START_RSP:
+ case RFC_MX_EVENT_CONN_CNF:
+ case RFC_MX_EVENT_CONF_IND:
+ case RFC_MX_EVENT_CONF_CNF:
+ RFCOMM_TRACE_ERROR2 ("Mx error state %d event %d", p_mcb->state, event);
+ return;
+
+ case RFC_MX_EVENT_CONN_IND:
+
+ rfc_timer_start (p_mcb, RFCOMM_CONN_TIMEOUT);
+ L2CA_ConnectRsp (p_mcb->bd_addr, *((UINT8 *)p_data), p_mcb->lcid, L2CAP_CONN_OK, 0);
+
+ rfc_mx_send_config_req (p_mcb);
+
+ p_mcb->state = RFC_MX_STATE_CONFIGURE;
+ return;
+
+ case RFC_EVENT_SABME:
+ break;
+
+ case RFC_EVENT_UA:
+ case RFC_EVENT_DM:
+ return;
+
+ case RFC_EVENT_DISC:
+ rfc_send_dm (p_mcb, RFCOMM_MX_DLCI, TRUE);
+ return;
+
+ case RFC_EVENT_UIH:
+ rfc_send_dm (p_mcb, RFCOMM_MX_DLCI, FALSE);
+ return;
+ }
+ RFCOMM_TRACE_EVENT2 ("RFCOMM MX ignored - evt:%d in state:%d", event, p_mcb->state);
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_mx_sm_state_wait_conn_cnf
+**
+** Description This function handles events when the multiplexer is
+** waiting for Connection Confirm from L2CAP.
+**
+** Returns void
+**
+*******************************************************************************/
+void rfc_mx_sm_state_wait_conn_cnf (tRFC_MCB *p_mcb, UINT16 event, void *p_data)
+{
+ RFCOMM_TRACE_EVENT1 ("rfc_mx_sm_state_wait_conn_cnf - evt:%d", event);
+ switch (event)
+ {
+ case RFC_MX_EVENT_START_REQ:
+ RFCOMM_TRACE_ERROR2 ("Mx error state %d event %d", p_mcb->state, event);
+ return;
+
+ /* There is some new timing so that Config Ind comes before security is completed
+ so we are still waiting fo the confirmation. */
+ case RFC_MX_EVENT_CONF_IND:
+ rfc_mx_conf_ind (p_mcb, (tL2CAP_CFG_INFO *)p_data);
+ return;
+
+ case RFC_MX_EVENT_CONN_CNF:
+ if (*((UINT16 *)p_data) != L2CAP_SUCCESS)
+ {
+ p_mcb->state = RFC_MX_STATE_IDLE;
+
+ PORT_StartCnf (p_mcb, *((UINT16 *)p_data));
+ return;
+ }
+ p_mcb->state = RFC_MX_STATE_CONFIGURE;
+ rfc_mx_send_config_req (p_mcb);
+ return;
+
+ case RFC_MX_EVENT_DISC_IND:
+ p_mcb->state = RFC_MX_STATE_IDLE;
+ PORT_CloseInd (p_mcb);
+ return;
+
+ case RFC_EVENT_TIMEOUT:
+ p_mcb->state = RFC_MX_STATE_IDLE;
+ L2CA_DisconnectReq (p_mcb->lcid);
+
+ /* we gave up outgoing connection request then try peer's request */
+ if (p_mcb->pending_lcid)
+ {
+ UINT16 i;
+ UINT8 idx;
+
+ RFCOMM_TRACE_DEBUG2 ("RFCOMM MX retry as acceptor in collision case - evt:%d in state:%d", event, p_mcb->state);
+
+ rfc_save_lcid_mcb (NULL, p_mcb->lcid);
+ p_mcb->lcid = p_mcb->pending_lcid;
+ rfc_save_lcid_mcb (p_mcb, p_mcb->lcid);
+
+ p_mcb->is_initiator = FALSE;
+
+ /* update direction bit */
+ for (i = 0; i < RFCOMM_MAX_DLCI; i += 2)
+ {
+ if ((idx = p_mcb->port_inx[i]) != 0)
+ {
+ p_mcb->port_inx[i] = 0;
+ p_mcb->port_inx[i+1] = idx;
+ rfc_cb.port.port[idx - 1].dlci += 1;
+ RFCOMM_TRACE_DEBUG2 ("RFCOMM MX - DLCI:%d -> %d", i, rfc_cb.port.port[idx - 1].dlci);
+ }
+ }
+
+ rfc_mx_sm_execute (p_mcb, RFC_MX_EVENT_CONN_IND, &(p_mcb->pending_id));
+ }
+ else
+ {
+ PORT_CloseInd (p_mcb);
+ }
+ return;
+ }
+ RFCOMM_TRACE_EVENT2 ("RFCOMM MX ignored - evt:%d in state:%d", event, p_mcb->state);
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_mx_sm_state_configure
+**
+** Description This function handles events when the multiplexer in the
+** configuration state.
+**
+** Returns void
+**
+*******************************************************************************/
+void rfc_mx_sm_state_configure (tRFC_MCB *p_mcb, UINT16 event, void *p_data)
+{
+ RFCOMM_TRACE_EVENT1 ("rfc_mx_sm_state_configure - evt:%d", event);
+ switch (event)
+ {
+ case RFC_MX_EVENT_START_REQ:
+ case RFC_MX_EVENT_CONN_CNF:
+
+ RFCOMM_TRACE_ERROR2 ("Mx error state %d event %d", p_mcb->state, event);
+ return;
+
+ case RFC_MX_EVENT_CONF_IND:
+ rfc_mx_conf_ind (p_mcb, (tL2CAP_CFG_INFO *)p_data);
+ return;
+
+ case RFC_MX_EVENT_CONF_CNF:
+ rfc_mx_conf_cnf (p_mcb, (tL2CAP_CFG_INFO *)p_data);
+ return;
+
+ case RFC_MX_EVENT_DISC_IND:
+ p_mcb->state = RFC_MX_STATE_IDLE;
+ PORT_CloseInd (p_mcb);
+ return;
+
+ case RFC_EVENT_TIMEOUT:
+ p_mcb->state = RFC_MX_STATE_IDLE;
+ L2CA_DisconnectReq (p_mcb->lcid);
+
+ PORT_StartCnf (p_mcb, RFCOMM_ERROR);
+ return;
+ }
+ RFCOMM_TRACE_EVENT2 ("RFCOMM MX ignored - evt:%d in state:%d", event, p_mcb->state);
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_mx_sm_sabme_wait_ua
+**
+** Description This function handles events when the multiplexer sent
+** SABME and is waiting for UA reply.
+**
+** Returns void
+**
+*******************************************************************************/
+void rfc_mx_sm_sabme_wait_ua (tRFC_MCB *p_mcb, UINT16 event, void *p_data)
+{
+ RFCOMM_TRACE_EVENT1 ("rfc_mx_sm_sabme_wait_ua - evt:%d", event);
+ switch (event)
+ {
+ case RFC_MX_EVENT_START_REQ:
+ case RFC_MX_EVENT_CONN_CNF:
+ RFCOMM_TRACE_ERROR2 ("Mx error state %d event %d", p_mcb->state, event);
+ return;
+
+ /* workaround: we don't support reconfig */
+ /* commented out until we support reconfig
+ case RFC_MX_EVENT_CONF_IND:
+ rfc_mx_conf_ind (p_mcb, (tL2CAP_CFG_INFO *)p_data);
+ return;
+
+ case RFC_MX_EVENT_CONF_CNF:
+ rfc_mx_conf_cnf (p_mcb, (tL2CAP_CFG_INFO *)p_data);
+ return;
+ */
+
+ case RFC_MX_EVENT_DISC_IND:
+ p_mcb->state = RFC_MX_STATE_IDLE;
+ PORT_CloseInd (p_mcb);
+ return;
+
+ case RFC_EVENT_UA:
+ rfc_timer_stop (p_mcb);
+
+ p_mcb->state = RFC_MX_STATE_CONNECTED;
+ p_mcb->peer_ready = TRUE;
+
+ PORT_StartCnf (p_mcb, RFCOMM_SUCCESS);
+ return;
+
+ case RFC_EVENT_DM:
+ rfc_timer_stop (p_mcb);
+ /* Case falls through */
+
+ case RFC_MX_EVENT_CONF_IND: /* workaround: we don't support reconfig */
+ case RFC_MX_EVENT_CONF_CNF: /* workaround: we don't support reconfig */
+ case RFC_EVENT_TIMEOUT:
+ p_mcb->state = RFC_MX_STATE_IDLE;
+ L2CA_DisconnectReq (p_mcb->lcid);
+
+ PORT_StartCnf (p_mcb, RFCOMM_ERROR);
+ return;
+ }
+ RFCOMM_TRACE_EVENT2 ("RFCOMM MX ignored - evt:%d in state:%d", event, p_mcb->state);
+}
+
+/*******************************************************************************
+**
+** Function rfc_mx_sm_state_wait_sabme
+**
+** Description This function handles events when the multiplexer is
+** waiting for SABME on the acceptor side after configuration
+**
+** Returns void
+**
+*******************************************************************************/
+void rfc_mx_sm_state_wait_sabme (tRFC_MCB *p_mcb, UINT16 event, void *p_data)
+{
+ RFCOMM_TRACE_EVENT1 ("rfc_mx_sm_state_wait_sabme - evt:%d", event);
+ switch (event)
+ {
+ case RFC_MX_EVENT_DISC_IND:
+ p_mcb->state = RFC_MX_STATE_IDLE;
+ PORT_CloseInd (p_mcb);
+ return;
+
+ case RFC_EVENT_SABME:
+ /* if we gave up outgoing connection request */
+ if (p_mcb->pending_lcid)
+ {
+ p_mcb->pending_lcid = 0;
+
+ rfc_send_ua (p_mcb, RFCOMM_MX_DLCI);
+
+ rfc_timer_stop (p_mcb);
+ p_mcb->state = RFC_MX_STATE_CONNECTED;
+ p_mcb->peer_ready = TRUE;
+
+ /* MX channel collision has been resolved, continue to open ports */
+ PORT_StartCnf (p_mcb, RFCOMM_SUCCESS);
+ }
+ else
+ {
+ rfc_timer_stop (p_mcb);
+ PORT_StartInd (p_mcb);
+ }
+ return;
+
+ case RFC_MX_EVENT_START_RSP:
+ if (*((UINT16 *)p_data) != RFCOMM_SUCCESS)
+ rfc_send_dm (p_mcb, RFCOMM_MX_DLCI, TRUE);
+ else
+ {
+ rfc_send_ua (p_mcb, RFCOMM_MX_DLCI);
+
+ p_mcb->state = RFC_MX_STATE_CONNECTED;
+ p_mcb->peer_ready = TRUE;
+ }
+ return;
+
+ case RFC_MX_EVENT_CONF_IND: /* workaround: we don't support reconfig */
+ case RFC_MX_EVENT_CONF_CNF: /* workaround: we don't support reconfig */
+ case RFC_EVENT_TIMEOUT:
+ p_mcb->state = RFC_MX_STATE_IDLE;
+ L2CA_DisconnectReq (p_mcb->lcid);
+
+ PORT_CloseInd (p_mcb);
+ return;
+ }
+ RFCOMM_TRACE_EVENT2 ("RFCOMM MX ignored - evt:%d in state:%d", event, p_mcb->state);
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_mx_sm_state_connected
+**
+** Description This function handles events when the multiplexer is
+** in the CONNECTED state
+**
+** Returns void
+**
+*******************************************************************************/
+void rfc_mx_sm_state_connected (tRFC_MCB *p_mcb, UINT16 event, void *p_data)
+{
+ RFCOMM_TRACE_EVENT1 ("rfc_mx_sm_state_connected - evt:%d", event);
+
+ switch (event)
+ {
+ case RFC_EVENT_TIMEOUT:
+ case RFC_MX_EVENT_CLOSE_REQ:
+ rfc_timer_start (p_mcb, RFC_DISC_TIMEOUT);
+ p_mcb->state = RFC_MX_STATE_DISC_WAIT_UA;
+ rfc_send_disc (p_mcb, RFCOMM_MX_DLCI);
+ return;
+
+ case RFC_MX_EVENT_DISC_IND:
+ p_mcb->state = RFC_MX_STATE_IDLE;
+ PORT_CloseInd (p_mcb);
+ return;
+
+ case RFC_EVENT_DISC:
+ /* Reply with UA. If initiator bring down L2CAP connection */
+ /* If server wait for some time if client decide to reinitiate channel */
+ rfc_send_ua (p_mcb, RFCOMM_MX_DLCI);
+ if (p_mcb->is_initiator)
+ {
+ L2CA_DisconnectReq (p_mcb->lcid);
+ }
+ /* notify all ports that connection is gone */
+ PORT_CloseInd (p_mcb);
+ return;
+ }
+ RFCOMM_TRACE_EVENT2 ("RFCOMM MX ignored - evt:%d in state:%d", event, p_mcb->state);
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_mx_sm_state_disc_wait_ua
+**
+** Description This function handles events when the multiplexer sent
+** DISC and is waiting for UA reply.
+**
+** Returns void
+**
+*******************************************************************************/
+void rfc_mx_sm_state_disc_wait_ua (tRFC_MCB *p_mcb, UINT16 event, void *p_data)
+{
+ BT_HDR *p_buf;
+
+ RFCOMM_TRACE_EVENT1 ("rfc_mx_sm_state_disc_wait_ua - evt:%d", event);
+ switch (event)
+ {
+ case RFC_EVENT_UA:
+ case RFC_EVENT_DM:
+ case RFC_EVENT_TIMEOUT:
+ L2CA_DisconnectReq (p_mcb->lcid);
+
+ if (p_mcb->restart_required)
+ {
+ /* Start Request was received while disconnecting. Execute it again */
+ if ((p_mcb->lcid = L2CA_ConnectReq (BT_PSM_RFCOMM, p_mcb->bd_addr)) == 0)
+ {
+ PORT_StartCnf (p_mcb, RFCOMM_ERROR);
+ return;
+ }
+ /* Save entry for quicker access to mcb based on the LCID */
+ rfc_save_lcid_mcb (p_mcb, p_mcb->lcid);
+
+ /* clean up before reuse it */
+ while ((p_buf = (BT_HDR *)GKI_dequeue(&p_mcb->cmd_q)) != NULL)
+ GKI_freebuf(p_buf);
+
+ rfc_timer_start (p_mcb, RFC_MCB_INIT_INACT_TIMER);
+
+ p_mcb->is_initiator = TRUE;
+ p_mcb->restart_required = FALSE;
+ p_mcb->local_cfg_sent = FALSE;
+ p_mcb->peer_cfg_rcvd = FALSE;
+
+ p_mcb->state = RFC_MX_STATE_WAIT_CONN_CNF;
+ return;
+ }
+ rfc_release_multiplexer_channel (p_mcb);
+ return;
+
+ case RFC_EVENT_DISC:
+ rfc_send_ua (p_mcb, RFCOMM_MX_DLCI);
+ return;
+
+ case RFC_EVENT_UIH:
+ GKI_freebuf (p_data);
+ rfc_send_dm (p_mcb, RFCOMM_MX_DLCI, FALSE);
+ return;
+
+ case RFC_MX_EVENT_START_REQ:
+ p_mcb->restart_required = TRUE;
+ return;
+
+ case RFC_MX_EVENT_DISC_IND:
+ p_mcb->state = RFC_MX_STATE_IDLE;
+ PORT_CloseInd (p_mcb);
+ return;
+
+ case RFC_MX_EVENT_CLOSE_REQ:
+ return;
+
+ case RFC_MX_EVENT_QOS_VIOLATION_IND:
+ break;
+ }
+ RFCOMM_TRACE_EVENT2 ("RFCOMM MX ignored - evt:%d in state:%d", event, p_mcb->state);
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_mx_send_config_req
+**
+** Description This function handles L2CA_ConnectInd message from the
+** L2CAP. Accept connection.
+**
+*******************************************************************************/
+static void rfc_mx_send_config_req (tRFC_MCB *p_mcb)
+{
+ tL2CAP_CFG_INFO cfg;
+
+ RFCOMM_TRACE_EVENT0 ("rfc_mx_send_config_req");
+
+ memset (&cfg, 0, sizeof (tL2CAP_CFG_INFO));
+
+ cfg.mtu_present = TRUE;
+ cfg.mtu = L2CAP_MTU_SIZE;
+
+/* Defaults set by memset
+ cfg.flush_to_present = FALSE;
+ cfg.qos_present = FALSE;
+ cfg.fcr_present = FALSE;
+ cfg.fcr.mode = L2CAP_FCR_BASIC_MODE;
+ cfg.fcs_present = FALSE;
+ cfg.fcs = N/A when fcs_present is FALSE;
+*/
+ L2CA_ConfigReq (p_mcb->lcid, &cfg);
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_mx_conf_cnf
+**
+** Description This function handles L2CA_ConfigCnf message from the
+** L2CAP. If result is not success tell upper layer that
+** start has not been accepted. If initiator send SABME
+** on DLCI 0. T1 is still running.
+**
+*******************************************************************************/
+static void rfc_mx_conf_cnf (tRFC_MCB *p_mcb, tL2CAP_CFG_INFO *p_cfg)
+{
+ RFCOMM_TRACE_EVENT2 ("rfc_mx_conf_cnf p_cfg:%08x res:%d ", p_cfg, (p_cfg) ? p_cfg->result : 0);
+
+ if (p_cfg->result != L2CAP_CFG_OK)
+ {
+ if (p_mcb->is_initiator)
+ {
+ PORT_StartCnf (p_mcb, p_cfg->result);
+ L2CA_DisconnectReq (p_mcb->lcid);
+ }
+ rfc_release_multiplexer_channel (p_mcb);
+ return;
+ }
+
+ p_mcb->local_cfg_sent = TRUE;
+ if ((p_mcb->state == RFC_MX_STATE_CONFIGURE) && p_mcb->peer_cfg_rcvd)
+ {
+ if (p_mcb->is_initiator)
+ {
+ p_mcb->state = RFC_MX_STATE_SABME_WAIT_UA;
+ rfc_send_sabme (p_mcb, RFCOMM_MX_DLCI);
+ rfc_timer_start (p_mcb, RFC_T1_TIMEOUT);
+ }
+ else
+ {
+ p_mcb->state = RFC_MX_STATE_WAIT_SABME;
+ rfc_timer_start (p_mcb, RFC_T2_TIMEOUT);
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_mx_conf_ind
+**
+** Description This function handles L2CA_ConfigInd message from the
+** L2CAP. Send the L2CA_ConfigRsp message.
+**
+*******************************************************************************/
+static void rfc_mx_conf_ind (tRFC_MCB *p_mcb, tL2CAP_CFG_INFO *p_cfg)
+{
+ /* Save peer L2CAP MTU if present */
+ /* RFCOMM adds 3-4 bytes in the beginning and 1 bytes FCS */
+ if (p_cfg->mtu_present)
+ p_mcb->peer_l2cap_mtu = p_cfg->mtu - RFCOMM_MIN_OFFSET - 1;
+ else
+ p_mcb->peer_l2cap_mtu = L2CAP_DEFAULT_MTU - RFCOMM_MIN_OFFSET - 1;
+
+ p_cfg->mtu_present = FALSE;
+ p_cfg->flush_to_present = FALSE;
+ p_cfg->qos_present = FALSE;
+
+ p_cfg->result = L2CAP_CFG_OK;
+
+ L2CA_ConfigRsp (p_mcb->lcid, p_cfg);
+
+ p_mcb->peer_cfg_rcvd = TRUE;
+ if ((p_mcb->state == RFC_MX_STATE_CONFIGURE) && p_mcb->local_cfg_sent)
+ {
+ if (p_mcb->is_initiator)
+ {
+ p_mcb->state = RFC_MX_STATE_SABME_WAIT_UA;
+ rfc_send_sabme (p_mcb, RFCOMM_MX_DLCI);
+ rfc_timer_start (p_mcb, RFC_T1_TIMEOUT);
+ }
+ else
+ {
+ p_mcb->state = RFC_MX_STATE_WAIT_SABME;
+ rfc_timer_start (p_mcb, RFC_T2_TIMEOUT);
+ }
+ }
+}
diff --git a/stack/rfcomm/rfc_port_fsm.c b/stack/rfcomm/rfc_port_fsm.c
new file mode 100644
index 0000000..2d34edb
--- /dev/null
+++ b/stack/rfcomm/rfc_port_fsm.c
@@ -0,0 +1,902 @@
+/*****************************************************************************
+**
+** Name: rfc_port_fsm.c
+**
+** Description: This file contains state machine and action routines for
+** a port of the RFCOMM unit
+**
+**
+** Copyright (c) 1999-2010, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+#include <string.h>
+#include "bt_target.h"
+#include "gki.h"
+#include "rfcdefs.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "port_api.h"
+#include "port_int.h"
+#include "rfc_int.h"
+
+/********************************************************************************/
+/* L O C A L F U N C T I O N P R O T O T Y P E S */
+/********************************************************************************/
+static void rfc_port_sm_state_closed (tPORT *p_port, UINT16 event, void *p_data);
+static void rfc_port_sm_sabme_wait_ua (tPORT *p_port, UINT16 event, void *p_data);
+static void rfc_port_sm_opened (tPORT *p_port, UINT16 event, void *p_data);
+static void rfc_port_sm_orig_wait_sec_check (tPORT *p_port, UINT16 event, void *p_data);
+static void rfc_port_sm_term_wait_sec_check (tPORT *p_port, UINT16 event, void *p_data);
+static void rfc_port_sm_disc_wait_ua (tPORT *p_port, UINT16 event, void *p_data);
+
+static void rfc_port_uplink_data (tPORT *p_port, BT_HDR *p_buf);
+
+static void rfc_set_port_state(tPORT_STATE *port_pars, MX_FRAME *p_frame);
+
+
+/*******************************************************************************
+**
+** Function rfc_port_sm_execute
+**
+** Description This function sends port events through the state
+** machine.
+**
+** Returns void
+**
+*******************************************************************************/
+void rfc_port_sm_execute (tPORT *p_port, UINT16 event, void *p_data)
+{
+ if (!p_port)
+ {
+ RFCOMM_TRACE_WARNING1 ("NULL port event %d", event);
+ return;
+ }
+
+ switch (p_port->rfc.state)
+ {
+ case RFC_STATE_CLOSED:
+ rfc_port_sm_state_closed (p_port, event, p_data);
+ break;
+
+ case RFC_STATE_SABME_WAIT_UA:
+ rfc_port_sm_sabme_wait_ua (p_port, event, p_data);
+ break;
+
+ case RFC_STATE_ORIG_WAIT_SEC_CHECK:
+ rfc_port_sm_orig_wait_sec_check (p_port, event, p_data);
+ break;
+
+ case RFC_STATE_TERM_WAIT_SEC_CHECK:
+ rfc_port_sm_term_wait_sec_check (p_port, event, p_data);
+ break;
+
+ case RFC_STATE_OPENED:
+ rfc_port_sm_opened (p_port, event, p_data);
+ break;
+
+ case RFC_STATE_DISC_WAIT_UA:
+ rfc_port_sm_disc_wait_ua (p_port, event, p_data);
+ break;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_port_sm_state_closed
+**
+** Description This function handles events when the port is in
+** CLOSED state. This state exists when port is
+** being initially established.
+**
+** Returns void
+**
+*******************************************************************************/
+void rfc_port_sm_state_closed (tPORT *p_port, UINT16 event, void *p_data)
+{
+ switch (event)
+ {
+ case RFC_EVENT_OPEN:
+ p_port->rfc.state = RFC_STATE_ORIG_WAIT_SEC_CHECK;
+ btm_sec_mx_access_request (p_port->rfc.p_mcb->bd_addr, BT_PSM_RFCOMM, TRUE,
+ BTM_SEC_PROTO_RFCOMM, (UINT32)(p_port->dlci / 2),
+ &rfc_sec_check_complete, p_port);
+ return;
+
+ case RFC_EVENT_CLOSE:
+ break;
+
+ case RFC_EVENT_CLEAR:
+ return;
+
+ case RFC_EVENT_DATA:
+ GKI_freebuf (p_data);
+ break;
+
+ case RFC_EVENT_SABME:
+ /* make sure the multiplexer disconnect timer is not running (reconnect case) */
+ rfc_timer_stop(p_port->rfc.p_mcb );
+
+ /* Open will be continued after security checks are passed */
+ p_port->rfc.state = RFC_STATE_TERM_WAIT_SEC_CHECK;
+ btm_sec_mx_access_request (p_port->rfc.p_mcb->bd_addr, BT_PSM_RFCOMM, FALSE,
+ BTM_SEC_PROTO_RFCOMM, (UINT32)(p_port->dlci / 2),
+ &rfc_sec_check_complete, p_port);
+ return;
+
+ case RFC_EVENT_UA:
+ return;
+
+ case RFC_EVENT_DM:
+ rfc_port_closed (p_port);
+ return;
+
+ case RFC_EVENT_UIH:
+ GKI_freebuf (p_data);
+ rfc_send_dm (p_port->rfc.p_mcb, p_port->dlci, FALSE);
+ return;
+
+ case RFC_EVENT_DISC:
+ rfc_send_dm (p_port->rfc.p_mcb, p_port->dlci, FALSE);
+ return;
+
+ case RFC_EVENT_TIMEOUT:
+ Port_TimeOutCloseMux( p_port->rfc.p_mcb ) ;
+ RFCOMM_TRACE_ERROR2 ("Port error state %d event %d", p_port->rfc.state, event);
+ return;
+ }
+
+ RFCOMM_TRACE_WARNING1 ("Port state closed Event ignored %d", event);
+ return;
+}
+
+/*******************************************************************************
+**
+** Function rfc_port_sm_sabme_wait_ua
+**
+** Description This function handles events when SABME on the DLC was
+** sent and SM is waiting for UA or DM.
+**
+** Returns void
+**
+*******************************************************************************/
+void rfc_port_sm_sabme_wait_ua (tPORT *p_port, UINT16 event, void *p_data)
+{
+ switch (event)
+ {
+ case RFC_EVENT_OPEN:
+ case RFC_EVENT_ESTABLISH_RSP:
+ RFCOMM_TRACE_ERROR2 ("Port error state %d event %d", p_port->rfc.state, event);
+ return;
+
+ case RFC_EVENT_CLOSE:
+ rfc_port_timer_start (p_port, RFC_DISC_TIMEOUT);
+ rfc_send_disc (p_port->rfc.p_mcb, p_port->dlci);
+ p_port->rfc.expected_rsp = 0;
+ p_port->rfc.state = RFC_STATE_DISC_WAIT_UA;
+ return;
+
+ case RFC_EVENT_CLEAR:
+ rfc_port_closed (p_port);
+ return;
+
+ case RFC_EVENT_DATA:
+ GKI_freebuf (p_data);
+ break;
+
+ case RFC_EVENT_UA:
+ rfc_port_timer_stop (p_port);
+ p_port->rfc.state = RFC_STATE_OPENED;
+ PORT_DlcEstablishCnf (p_port->rfc.p_mcb, p_port->dlci, p_port->rfc.p_mcb->peer_l2cap_mtu, RFCOMM_SUCCESS);
+ return;
+
+ case RFC_EVENT_DM:
+ p_port->rfc.p_mcb->is_disc_initiator = TRUE;
+ PORT_DlcEstablishCnf (p_port->rfc.p_mcb, p_port->dlci, p_port->rfc.p_mcb->peer_l2cap_mtu, RFCOMM_ERROR);
+ rfc_port_closed (p_port);
+ return;
+
+ case RFC_EVENT_DISC:
+ rfc_send_ua (p_port->rfc.p_mcb, p_port->dlci);
+ PORT_DlcEstablishCnf (p_port->rfc.p_mcb, p_port->dlci, p_port->rfc.p_mcb->peer_l2cap_mtu, RFCOMM_ERROR);
+ rfc_port_closed (p_port);
+ return;
+
+ case RFC_EVENT_SABME:
+ /* Continue to wait for the UA the SABME this side sent */
+ rfc_send_ua (p_port->rfc.p_mcb, p_port->dlci);
+ return;
+
+ case RFC_EVENT_UIH:
+ GKI_freebuf (p_data);
+ return;
+
+ case RFC_EVENT_TIMEOUT:
+ p_port->rfc.state = RFC_STATE_CLOSED;
+ PORT_DlcEstablishCnf (p_port->rfc.p_mcb, p_port->dlci, p_port->rfc.p_mcb->peer_l2cap_mtu, RFCOMM_ERROR);
+ return;
+ }
+ RFCOMM_TRACE_WARNING1 ("Port state sabme_wait_ua Event ignored %d", event);
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_port_sm_term_wait_sec_check
+**
+** Description This function handles events for the port in the
+** WAIT_SEC_CHECK state. SABME has been received from the
+** peer and Security Manager verifes BD_ADDR, before we can
+** send ESTABLISH_IND to the Port entity
+**
+** Returns void
+**
+*******************************************************************************/
+void rfc_port_sm_term_wait_sec_check (tPORT *p_port, UINT16 event, void *p_data)
+{
+ switch (event)
+ {
+ case RFC_EVENT_SEC_COMPLETE:
+ if (*((UINT8 *)p_data) != BTM_SUCCESS)
+ {
+ /* Authentication/authorization failed. If link is still */
+ /* up send DM and check if we need to start inactive timer */
+ if (p_port->rfc.p_mcb)
+ {
+ rfc_send_dm (p_port->rfc.p_mcb, p_port->dlci, TRUE);
+ p_port->rfc.p_mcb->is_disc_initiator = TRUE;
+ port_rfc_closed (p_port, PORT_SEC_FAILED);
+ }
+ }
+ else
+ {
+ PORT_DlcEstablishInd (p_port->rfc.p_mcb, p_port->dlci, p_port->rfc.p_mcb->peer_l2cap_mtu);
+ }
+ return;
+
+ case RFC_EVENT_OPEN:
+ case RFC_EVENT_CLOSE:
+ RFCOMM_TRACE_ERROR2 ("Port error state %d event %d", p_port->rfc.state, event);
+ return;
+
+ case RFC_EVENT_CLEAR:
+ btm_sec_abort_access_req (p_port->rfc.p_mcb->bd_addr);
+ rfc_port_closed (p_port);
+ return;
+
+ case RFC_EVENT_DATA:
+ RFCOMM_TRACE_ERROR0 ("Port error state Term Wait Sec event Data");
+ GKI_freebuf (p_data);
+ return;
+
+ case RFC_EVENT_SABME:
+ /* Ignore SABME retransmission if client dares to do so */
+ return;
+
+ case RFC_EVENT_DISC:
+ btm_sec_abort_access_req (p_port->rfc.p_mcb->bd_addr);
+ p_port->rfc.state = RFC_STATE_CLOSED;
+ rfc_send_ua (p_port->rfc.p_mcb, p_port->dlci);
+
+ PORT_DlcReleaseInd (p_port->rfc.p_mcb, p_port->dlci);
+ return;
+
+ case RFC_EVENT_UIH:
+ GKI_freebuf (p_data);
+ return;
+
+ case RFC_EVENT_ESTABLISH_RSP:
+ if (*((UINT8 *)p_data) != RFCOMM_SUCCESS)
+ {
+ if (p_port->rfc.p_mcb)
+ rfc_send_dm (p_port->rfc.p_mcb, p_port->dlci, TRUE);
+ }
+ else
+ {
+ rfc_send_ua (p_port->rfc.p_mcb, p_port->dlci);
+ p_port->rfc.state = RFC_STATE_OPENED;
+ }
+ return;
+ }
+ RFCOMM_TRACE_WARNING1 ("Port state term_wait_sec_check Event ignored %d", event);
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_port_sm_orig_wait_sec_check
+**
+** Description This function handles events for the port in the
+** ORIG_WAIT_SEC_CHECK state. RFCOMM is waiting for Security
+** manager to finish before sending SABME to the peer
+**
+** Returns void
+**
+*******************************************************************************/
+void rfc_port_sm_orig_wait_sec_check (tPORT *p_port, UINT16 event, void *p_data)
+{
+ switch (event)
+ {
+ case RFC_EVENT_SEC_COMPLETE:
+ if (*((UINT8 *)p_data) != BTM_SUCCESS)
+ {
+ p_port->rfc.p_mcb->is_disc_initiator = TRUE;
+ PORT_DlcEstablishCnf (p_port->rfc.p_mcb, p_port->dlci, 0, RFCOMM_SECURITY_ERR);
+ rfc_port_closed (p_port);
+ return;
+ }
+ rfc_send_sabme (p_port->rfc.p_mcb, p_port->dlci);
+ rfc_port_timer_start (p_port, RFC_PORT_T1_TIMEOUT);
+ p_port->rfc.state = RFC_STATE_SABME_WAIT_UA;
+ return;
+
+ case RFC_EVENT_OPEN:
+ case RFC_EVENT_SABME: /* Peer should not use the same dlci */
+ RFCOMM_TRACE_ERROR2 ("Port error state %d event %d", p_port->rfc.state, event);
+ return;
+
+ case RFC_EVENT_CLOSE:
+ btm_sec_abort_access_req (p_port->rfc.p_mcb->bd_addr);
+ rfc_port_closed (p_port);
+ return;
+
+ case RFC_EVENT_DATA:
+ RFCOMM_TRACE_ERROR0 ("Port error state Orig Wait Sec event Data");
+ GKI_freebuf (p_data);
+ return;
+
+ case RFC_EVENT_UIH:
+ GKI_freebuf (p_data);
+ return;
+ }
+ RFCOMM_TRACE_WARNING1 ("Port state orig_wait_sec_check Event ignored %d", event);
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_port_sm_opened
+**
+** Description This function handles events for the port in the OPENED
+** state
+**
+** Returns void
+**
+*******************************************************************************/
+void rfc_port_sm_opened (tPORT *p_port, UINT16 event, void *p_data)
+{
+ switch (event)
+ {
+ case RFC_EVENT_OPEN:
+ RFCOMM_TRACE_ERROR2 ("Port error state %d event %d", p_port->rfc.state, event);
+ return;
+
+ case RFC_EVENT_CLOSE:
+ rfc_port_timer_start (p_port, RFC_DISC_TIMEOUT);
+ rfc_send_disc (p_port->rfc.p_mcb, p_port->dlci);
+ p_port->rfc.expected_rsp = 0;
+ p_port->rfc.state = RFC_STATE_DISC_WAIT_UA;
+ return;
+
+ case RFC_EVENT_CLEAR:
+ rfc_port_closed (p_port);
+ return;
+
+ case RFC_EVENT_DATA:
+ /* Send credits in the frame. Pass them in the layer specific member of the hdr. */
+ /* There might be an initial case when we reduced rx_max and credit_rx is still */
+ /* bigger. Make sure that we do not send 255 */
+ if ((p_port->rfc.p_mcb->flow == PORT_FC_CREDIT)
+ && (((BT_HDR *)p_data)->len < p_port->peer_mtu)
+ && (!p_port->rx.user_fc)
+ && (p_port->credit_rx_max > p_port->credit_rx))
+ {
+ ((BT_HDR *)p_data)->layer_specific = (UINT8) (p_port->credit_rx_max - p_port->credit_rx);
+ p_port->credit_rx = p_port->credit_rx_max;
+ }
+ else
+ {
+ ((BT_HDR *)p_data)->layer_specific = 0;
+ }
+ rfc_send_buf_uih (p_port->rfc.p_mcb, p_port->dlci, (BT_HDR *)p_data);
+ rfc_dec_credit (p_port);
+ return;
+
+ case RFC_EVENT_UA:
+ return;
+
+ case RFC_EVENT_SABME:
+ rfc_send_ua (p_port->rfc.p_mcb, p_port->dlci);
+ return;
+
+ case RFC_EVENT_DM:
+ PORT_DlcReleaseInd (p_port->rfc.p_mcb, p_port->dlci);
+ rfc_port_closed (p_port);
+ return;
+
+ case RFC_EVENT_DISC:
+ p_port->rfc.state = RFC_STATE_CLOSED;
+ rfc_send_ua (p_port->rfc.p_mcb, p_port->dlci);
+ if(p_port->rx.queue.count)
+ {
+ /* give a chance to upper stack to close port properly */
+ RFCOMM_TRACE_DEBUG0("port queue is not empty");
+ rfc_port_timer_start (p_port, RFC_DISC_TIMEOUT);
+ }
+ else
+ PORT_DlcReleaseInd (p_port->rfc.p_mcb, p_port->dlci);
+ return;
+
+ case RFC_EVENT_UIH:
+ rfc_port_uplink_data (p_port, (BT_HDR *)p_data);
+ return;
+
+ case RFC_EVENT_TIMEOUT:
+ Port_TimeOutCloseMux( p_port->rfc.p_mcb ) ;
+ RFCOMM_TRACE_ERROR2 ("Port error state %d event %d", p_port->rfc.state, event);
+ return;
+ }
+ RFCOMM_TRACE_WARNING1 ("Port state opened Event ignored %d", event);
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_port_sm_disc_wait_ua
+**
+** Description This function handles events when DISC on the DLC was
+** sent and SM is waiting for UA or DM.
+**
+** Returns void
+**
+*******************************************************************************/
+void rfc_port_sm_disc_wait_ua (tPORT *p_port, UINT16 event, void *p_data)
+{
+ switch (event)
+ {
+ case RFC_EVENT_OPEN:
+ case RFC_EVENT_ESTABLISH_RSP:
+ RFCOMM_TRACE_ERROR2 ("Port error state %d event %d", p_port->rfc.state, event);
+ return;
+
+ case RFC_EVENT_CLEAR:
+ rfc_port_closed (p_port);
+ return;
+
+ case RFC_EVENT_DATA:
+ GKI_freebuf (p_data);
+ return;
+
+ case RFC_EVENT_UA:
+ p_port->rfc.p_mcb->is_disc_initiator = TRUE;
+ /* Case falls through */
+
+ case RFC_EVENT_DM:
+ rfc_port_closed (p_port);
+ return;
+
+ case RFC_EVENT_SABME:
+ rfc_send_dm (p_port->rfc.p_mcb, p_port->dlci, TRUE);
+ return;
+
+ case RFC_EVENT_DISC:
+ rfc_send_dm (p_port->rfc.p_mcb, p_port->dlci, TRUE);
+ return;
+
+ case RFC_EVENT_UIH:
+ GKI_freebuf (p_data);
+ rfc_send_dm (p_port->rfc.p_mcb, p_port->dlci, FALSE);
+ return;
+
+ case RFC_EVENT_TIMEOUT:
+ rfc_port_closed (p_port);
+ return;
+ }
+
+ RFCOMM_TRACE_WARNING1 ("Port state disc_wait_ua Event ignored %d", event);
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_port_uplink_data
+**
+** Description This function handles uplink information data frame.
+**
+*******************************************************************************/
+void rfc_port_uplink_data (tPORT *p_port, BT_HDR *p_buf)
+{
+ PORT_DataInd (p_port->rfc.p_mcb, p_port->dlci, p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_process_pn
+**
+** Description This function handles DLC parameter negotiation frame.
+** Record MTU and pass indication to the upper layer.
+**
+*******************************************************************************/
+void rfc_process_pn (tRFC_MCB *p_mcb, BOOLEAN is_command, MX_FRAME *p_frame)
+{
+ tPORT *p_port;
+ UINT8 dlci = p_frame->dlci;
+
+ if (is_command)
+ {
+ /* Ignore if Multiplexer is being shut down */
+ if (p_mcb->state != RFC_MX_STATE_DISC_WAIT_UA)
+ {
+ PORT_ParNegInd (p_mcb, dlci, p_frame->u.pn.mtu,
+ p_frame->u.pn.conv_layer, p_frame->u.pn.k);
+ }
+ else
+ {
+ rfc_send_dm(p_mcb, dlci, FALSE);
+ RFCOMM_TRACE_WARNING0("***** MX PN while disconnecting *****");
+ }
+
+ return;
+ }
+ /* If we are not awaiting response just ignore it */
+ p_port = port_find_mcb_dlci_port (p_mcb, dlci);
+ if ((p_port == NULL) || !(p_port->rfc.expected_rsp & RFC_RSP_PN))
+ return;
+
+ p_port->rfc.expected_rsp &= ~RFC_RSP_PN;
+
+ rfc_port_timer_stop (p_port);
+
+ PORT_ParNegCnf (p_mcb, dlci, p_frame->u.pn.mtu,
+ p_frame->u.pn.conv_layer, p_frame->u.pn.k);
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_process_rpn
+**
+** Description This function handles Remote DLC parameter negotiation
+** command/response. Pass command to the user.
+**
+*******************************************************************************/
+void rfc_process_rpn (tRFC_MCB *p_mcb, BOOLEAN is_command,
+ BOOLEAN is_request, MX_FRAME *p_frame)
+{
+ tPORT_STATE port_pars;
+ tPORT *p_port;
+
+ if ((p_port = port_find_mcb_dlci_port (p_mcb, p_frame->dlci)) == NULL)
+ {
+ /* This is the first command on the port */
+ if (is_command)
+ {
+
+ memset(&port_pars, 0, sizeof(tPORT_STATE));
+ rfc_set_port_state(&port_pars, p_frame);
+
+ PORT_PortNegInd(p_mcb, p_frame->dlci, &port_pars, p_frame->u.rpn.param_mask);
+ }
+ return;
+ }
+
+ if (is_command && is_request)
+ {
+ /* This is the special situation when peer just request local pars */
+ port_pars = p_port->peer_port_pars;
+ rfc_send_rpn (p_mcb, p_frame->dlci, FALSE, &p_port->peer_port_pars, 0);
+ return;
+ }
+
+ port_pars = p_port->peer_port_pars;
+
+ rfc_set_port_state(&port_pars, p_frame);
+
+ if (is_command)
+ {
+ PORT_PortNegInd (p_mcb, p_frame->dlci, &port_pars, p_frame->u.rpn.param_mask);
+ return;
+ }
+
+ /* If we are not awaiting response just ignore it */
+ p_port = port_find_mcb_dlci_port (p_mcb, p_frame->dlci);
+ if ((p_port == NULL) || !(p_port->rfc.expected_rsp & (RFC_RSP_RPN | RFC_RSP_RPN_REPLY)))
+ return;
+
+ /* If we sent a request for port parameters to the peer he is replying with */
+ /* mask 0. */
+ rfc_port_timer_stop (p_port);
+
+ if (p_port->rfc.expected_rsp & RFC_RSP_RPN_REPLY)
+ {
+ p_port->rfc.expected_rsp &= ~RFC_RSP_RPN_REPLY;
+
+ p_port->peer_port_pars = port_pars;
+
+ if ((port_pars.fc_type == (RFCOMM_FC_RTR_ON_INPUT | RFCOMM_FC_RTR_ON_OUTPUT))
+ || (port_pars.fc_type == (RFCOMM_FC_RTC_ON_INPUT | RFCOMM_FC_RTC_ON_OUTPUT)))
+ {
+ /* This is satisfactory port parameters. Set mask as it was Ok */
+ p_frame->u.rpn.param_mask = RFCOMM_RPN_PM_MASK;
+ }
+ else
+ {
+ /* Current peer parameters are not good, try to fix them */
+ p_port->peer_port_pars.fc_type = (RFCOMM_FC_RTR_ON_INPUT | RFCOMM_FC_RTR_ON_OUTPUT);
+
+ p_port->rfc.expected_rsp |= RFC_RSP_RPN;
+ rfc_send_rpn (p_mcb, p_frame->dlci, TRUE, &p_port->peer_port_pars,
+ RFCOMM_RPN_PM_RTR_ON_INPUT | RFCOMM_RPN_PM_RTR_ON_OUTPUT);
+ rfc_port_timer_start (p_port, RFC_T2_TIMEOUT) ;
+ return;
+ }
+ }
+ else
+ p_port->rfc.expected_rsp &= ~RFC_RSP_RPN;
+
+ /* Check if all suggested parameters were accepted */
+ if (((p_frame->u.rpn.param_mask & (RFCOMM_RPN_PM_RTR_ON_INPUT | RFCOMM_RPN_PM_RTR_ON_OUTPUT)) ==
+ (RFCOMM_RPN_PM_RTR_ON_INPUT | RFCOMM_RPN_PM_RTR_ON_OUTPUT))
+ || ((p_frame->u.rpn.param_mask & (RFCOMM_RPN_PM_RTC_ON_INPUT | RFCOMM_RPN_PM_RTC_ON_OUTPUT)) ==
+ (RFCOMM_RPN_PM_RTC_ON_INPUT | RFCOMM_RPN_PM_RTC_ON_OUTPUT)))
+ {
+ PORT_PortNegCnf (p_mcb, p_port->dlci, &port_pars, RFCOMM_SUCCESS);
+ return;
+ }
+
+ /* If we were proposing RTR flow control try RTC flow control */
+ /* If we were proposing RTC flow control try no flow control */
+ /* otherwise drop the connection */
+ if (p_port->peer_port_pars.fc_type == (RFCOMM_FC_RTR_ON_INPUT | RFCOMM_FC_RTR_ON_OUTPUT))
+ {
+ /* Current peer parameters are not good, try to fix them */
+ p_port->peer_port_pars.fc_type = (RFCOMM_FC_RTC_ON_INPUT | RFCOMM_FC_RTC_ON_OUTPUT);
+
+ p_port->rfc.expected_rsp |= RFC_RSP_RPN;
+
+ rfc_send_rpn (p_mcb, p_frame->dlci, TRUE, &p_port->peer_port_pars,
+ RFCOMM_RPN_PM_RTC_ON_INPUT | RFCOMM_RPN_PM_RTC_ON_OUTPUT);
+ rfc_port_timer_start (p_port, RFC_T2_TIMEOUT) ;
+ return;
+ }
+
+ /* Other side does not support flow control */
+ if (p_port->peer_port_pars.fc_type == (RFCOMM_FC_RTC_ON_INPUT | RFCOMM_FC_RTC_ON_OUTPUT))
+ {
+ p_port->peer_port_pars.fc_type = RFCOMM_FC_OFF;
+ PORT_PortNegCnf (p_mcb, p_port->dlci, &port_pars, RFCOMM_SUCCESS);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_process_msc
+**
+** Description This function handles Modem Status Command.
+** Pass command to the user.
+**
+*******************************************************************************/
+void rfc_process_msc (tRFC_MCB *p_mcb, BOOLEAN is_command, MX_FRAME *p_frame)
+{
+ tPORT_CTRL pars;
+ tPORT *p_port;
+ UINT8 modem_signals = p_frame->u.msc.signals;
+ BOOLEAN new_peer_fc = FALSE;
+
+ p_port = port_find_mcb_dlci_port (p_mcb, p_frame->dlci);
+ if (p_port == NULL)
+ return;
+
+ pars.modem_signal = 0;
+
+ if (modem_signals & RFCOMM_MSC_RTC)
+ pars.modem_signal |= MODEM_SIGNAL_DTRDSR;
+
+ if (modem_signals & RFCOMM_MSC_RTR)
+ pars.modem_signal |= MODEM_SIGNAL_RTSCTS;
+
+ if (modem_signals & RFCOMM_MSC_IC)
+ pars.modem_signal |= MODEM_SIGNAL_RI;
+
+ if (modem_signals & RFCOMM_MSC_DV)
+ pars.modem_signal |= MODEM_SIGNAL_DCD;
+
+ pars.fc = ((modem_signals & RFCOMM_MSC_FC) == RFCOMM_MSC_FC);
+
+ pars.break_signal = (p_frame->u.msc.break_present) ?
+ p_frame->u.msc.break_duration : 0;
+ pars.discard_buffers = 0;
+ pars.break_signal_seq = RFCOMM_CTRL_BREAK_IN_SEQ; /* this is default */
+
+ /* Check if this command is passed only to indicate flow control */
+ if (is_command)
+ {
+ rfc_send_msc (p_mcb, p_frame->dlci, FALSE, &pars);
+
+ if (p_port->rfc.p_mcb->flow != PORT_FC_CREDIT)
+ {
+ /* Spec 1.1 indicates that only FC bit is used for flow control */
+ p_port->peer_ctrl.fc = new_peer_fc = pars.fc;
+
+ if (new_peer_fc != p_port->tx.peer_fc)
+ PORT_FlowInd (p_mcb, p_frame->dlci, (BOOLEAN)!new_peer_fc);
+ }
+
+ PORT_ControlInd (p_mcb, p_frame->dlci, &pars);
+
+ return;
+ }
+
+ /* If we are not awaiting response just ignore it */
+ if (!(p_port->rfc.expected_rsp & RFC_RSP_MSC))
+ return;
+
+ p_port->rfc.expected_rsp &= ~RFC_RSP_MSC;
+
+ rfc_port_timer_stop (p_port);
+
+ PORT_ControlCnf (p_port->rfc.p_mcb, p_port->dlci, &pars);
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_process_rls
+**
+** Description This function handles Remote Line Status command.
+** Pass command to the user.
+**
+*******************************************************************************/
+void rfc_process_rls (tRFC_MCB *p_mcb, BOOLEAN is_command, MX_FRAME *p_frame)
+{
+ tPORT *p_port;
+
+ if (is_command)
+ {
+ PORT_LineStatusInd (p_mcb, p_frame->dlci, p_frame->u.rls.line_status);
+ rfc_send_rls (p_mcb, p_frame->dlci, FALSE, p_frame->u.rls.line_status);
+ }
+ else
+ {
+ p_port = port_find_mcb_dlci_port (p_mcb, p_frame->dlci);
+
+ /* If we are not awaiting response just ignore it */
+ if (!p_port || !(p_port->rfc.expected_rsp & RFC_RSP_RLS))
+ return;
+
+ p_port->rfc.expected_rsp &= ~RFC_RSP_RLS;
+
+ rfc_port_timer_stop (p_port);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_process_nsc
+**
+** Description This function handles None Supported Command frame.
+**
+*******************************************************************************/
+void rfc_process_nsc (tRFC_MCB *p_mcb, MX_FRAME *p_frame)
+{
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_process_test
+**
+** Description This function handles Test frame. If this is a command
+** reply to it. Otherwise pass response to the user.
+**
+*******************************************************************************/
+void rfc_process_test_rsp (tRFC_MCB *p_mcb, BT_HDR *p_buf)
+{
+ GKI_freebuf (p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_process_fcon
+**
+** Description This function handles FCON frame. The peer entity is able
+** to receive new information
+**
+*******************************************************************************/
+void rfc_process_fcon (tRFC_MCB *p_mcb, BOOLEAN is_command)
+{
+ if (is_command)
+ {
+ rfc_cb.rfc.peer_rx_disabled = FALSE;
+
+ rfc_send_fcon (p_mcb, FALSE);
+
+ if (!p_mcb->l2cap_congested)
+ PORT_FlowInd (p_mcb, 0, TRUE);
+ }
+}
+
+/*******************************************************************************
+**
+** Function rfc_process_fcoff
+**
+** Description This function handles FCOFF frame. The peer entity is unable
+** to receive new information
+**
+*******************************************************************************/
+void rfc_process_fcoff (tRFC_MCB *p_mcb, BOOLEAN is_command)
+{
+ if (is_command)
+ {
+ rfc_cb.rfc.peer_rx_disabled = TRUE;
+
+ if (!p_mcb->l2cap_congested)
+ PORT_FlowInd (p_mcb, 0, FALSE);
+
+ rfc_send_fcoff (p_mcb, FALSE);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_process_l2cap_congestion
+**
+** Description This function handles L2CAP congestion messages
+**
+*******************************************************************************/
+void rfc_process_l2cap_congestion (tRFC_MCB *p_mcb, BOOLEAN is_congested)
+{
+ p_mcb->l2cap_congested = is_congested;
+
+ if (!is_congested)
+ {
+ rfc_check_send_cmd(p_mcb, NULL);
+ }
+
+ if (!rfc_cb.rfc.peer_rx_disabled)
+ {
+ if (!is_congested)
+ PORT_FlowInd (p_mcb, 0, TRUE);
+ else
+ PORT_FlowInd (p_mcb, 0, FALSE);
+ }
+}
+
+/*******************************************************************************
+**
+** Function rfc_set_port_pars
+**
+** Description This function sets the tPORT_STATE structure given a p_frame.
+**
+*******************************************************************************/
+
+void rfc_set_port_state(tPORT_STATE *port_pars, MX_FRAME *p_frame)
+{
+ if (p_frame->u.rpn.param_mask & RFCOMM_RPN_PM_BIT_RATE)
+ port_pars->baud_rate = p_frame->u.rpn.baud_rate;
+ if (p_frame->u.rpn.param_mask & RFCOMM_RPN_PM_DATA_BITS)
+ port_pars->byte_size = p_frame->u.rpn.byte_size;
+ if (p_frame->u.rpn.param_mask & RFCOMM_RPN_PM_STOP_BITS)
+ port_pars->stop_bits = p_frame->u.rpn.stop_bits;
+ if (p_frame->u.rpn.param_mask & RFCOMM_RPN_PM_PARITY)
+ port_pars->parity = p_frame->u.rpn.parity;
+ if (p_frame->u.rpn.param_mask & RFCOMM_RPN_PM_PARITY_TYPE)
+ port_pars->parity_type = p_frame->u.rpn.parity_type;
+ if (p_frame->u.rpn.param_mask & (RFCOMM_RPN_PM_XONXOFF_ON_INPUT |
+ RFCOMM_RPN_PM_XONXOFF_ON_OUTPUT |
+ RFCOMM_RPN_PM_RTR_ON_INPUT |
+ RFCOMM_RPN_PM_RTR_ON_OUTPUT |
+ RFCOMM_RPN_PM_RTC_ON_INPUT |
+ RFCOMM_RPN_PM_RTC_ON_OUTPUT))
+ port_pars->fc_type = p_frame->u.rpn.fc_type;
+ if (p_frame->u.rpn.param_mask & RFCOMM_RPN_PM_XON_CHAR)
+ port_pars->xon_char = p_frame->u.rpn.xon_char;
+ if (p_frame->u.rpn.param_mask & RFCOMM_RPN_PM_XOFF_CHAR)
+ port_pars->xoff_char = p_frame->u.rpn.xoff_char;
+}
+
diff --git a/stack/rfcomm/rfc_port_if.c b/stack/rfcomm/rfc_port_if.c
new file mode 100644
index 0000000..03fb339
--- /dev/null
+++ b/stack/rfcomm/rfc_port_if.c
@@ -0,0 +1,325 @@
+/*****************************************************************************/
+/* */
+/* Name: rfc_port_if.c */
+/* */
+/* Description: This file contains functions callable by an application */
+/* running on top of RFCOMM */
+/* */
+/* */
+/* Copyright (c) 1999-2004, WIDCOMM Inc., All Rights Reserved. */
+/* WIDCOMM Bluetooth Core. Proprietary and confidential. */
+/*****************************************************************************/
+#include <string.h>
+#include "bt_target.h"
+#include "gki.h"
+#include "rfcdefs.h"
+#include "port_api.h"
+#include "l2c_api.h"
+#include "port_int.h"
+#include "rfc_int.h"
+
+
+#if RFC_DYNAMIC_MEMORY == FALSE
+tRFC_CB rfc_cb;
+#endif
+
+/*******************************************************************************
+**
+** Function RFCOMM_StartReq
+**
+** Description This function handles Start Request from the upper layer.
+** If RFCOMM multiplexer channel can not be allocated
+** send start not accepted confirmation. Otherwise dispatch
+** start event to the state machine.
+**
+*******************************************************************************/
+void RFCOMM_StartReq (tRFC_MCB *p_mcb)
+{
+ rfc_mx_sm_execute (p_mcb, RFC_MX_EVENT_START_REQ, NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function RFCOMM_StartRsp
+**
+** Description This function handles Start Response from the upper layer.
+** Save upper layer handle and result of the Start Indication
+** in the control block and dispatch event to the FSM.
+**
+*******************************************************************************/
+void RFCOMM_StartRsp (tRFC_MCB *p_mcb, UINT16 result)
+{
+ rfc_mx_sm_execute (p_mcb, RFC_MX_EVENT_START_RSP, &result);
+}
+
+
+/*******************************************************************************
+**
+** Function RFCOMM_DlcEstablishReq
+**
+** Description This function is called by the user app to establish
+** connection with the specific dlci on a specific bd device.
+** It will allocate RFCOMM connection control block if not
+** allocated before and dispatch open event to the state
+** machine.
+**
+*******************************************************************************/
+void RFCOMM_DlcEstablishReq (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu)
+{
+ tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
+
+ if (p_mcb->state != RFC_MX_STATE_CONNECTED)
+ {
+ PORT_DlcEstablishCnf (p_mcb, dlci, 0, RFCOMM_ERROR);
+ return;
+ }
+
+ rfc_port_sm_execute(p_port, RFC_EVENT_OPEN, NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function RFCOMM_DlcEstablishRsp
+**
+** Description This function is called by the port emulation entity
+** acks Establish Indication.
+**
+*******************************************************************************/
+void RFCOMM_DlcEstablishRsp (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu, UINT16 result)
+{
+ tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
+
+ if ((p_mcb->state != RFC_MX_STATE_CONNECTED) && (result == RFCOMM_SUCCESS))
+ {
+ PORT_DlcReleaseInd (p_mcb, dlci);
+ return;
+ }
+
+ rfc_port_sm_execute(p_port, RFC_EVENT_ESTABLISH_RSP, &result);
+}
+
+
+/*******************************************************************************
+**
+** Function RFCOMM_ParNegReq
+**
+** Description This function is called by the user app to start
+** DLC parameter negotiation. Port emulation can send this
+** request before actually establishing the DLC. In this
+** case the function will allocate RFCOMM connection control
+** block.
+**
+*******************************************************************************/
+void RFCOMM_ParNegReq (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu)
+{
+ tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
+ UINT8 flow;
+ UINT8 cl;
+ UINT8 k;
+
+ if (p_mcb->state != RFC_MX_STATE_CONNECTED)
+ {
+ p_port->error = PORT_PAR_NEG_FAILED;
+ return;
+ }
+
+ /* Negotiate the flow control mechanism. If flow control mechanism for */
+ /* mux has not been set yet, use our default value. If it has been set, */
+ /* use that value. */
+ flow = (p_mcb->flow == PORT_FC_UNDEFINED) ? PORT_FC_DEFAULT : p_mcb->flow;
+
+ /* Set convergence layer and number of credits (k) */
+ if (flow == PORT_FC_CREDIT)
+ {
+ cl = RFCOMM_PN_CONV_LAYER_CBFC_I;
+ k = (p_port->credit_rx_max < RFCOMM_K_MAX) ? p_port->credit_rx_max : RFCOMM_K_MAX;
+ p_port->credit_rx = k;
+ }
+ else
+ {
+ cl = RFCOMM_PN_CONV_LAYER_TYPE_1;
+ k = 0;
+ }
+
+ /* Send Parameter Negotiation Command UIH frame */
+ p_port->rfc.expected_rsp |= RFC_RSP_PN;
+
+ rfc_send_pn (p_mcb, dlci, TRUE, mtu, cl, k);
+
+ rfc_port_timer_start (p_port, RFC_T2_TIMEOUT) ;
+}
+
+
+/*******************************************************************************
+**
+** Function RFCOMM_ParNegRsp
+**
+** Description This function is called by the user app to acknowledge
+** DLC parameter negotiation.
+**
+*******************************************************************************/
+void RFCOMM_ParNegRsp (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu, UINT8 cl, UINT8 k)
+{
+ if (p_mcb->state != RFC_MX_STATE_CONNECTED)
+ return;
+
+ /* Send Parameter Negotiation Response UIH frame */
+ rfc_send_pn (p_mcb, dlci, FALSE, mtu, cl, k);
+}
+
+
+/*******************************************************************************
+**
+** Function RFCOMM_PortNegReq
+**
+** Description This function is called by the user app to start
+** Remote Port parameter negotiation. Port emulation can
+** send this request before actually establishing the DLC.
+** In this case the function will allocate RFCOMM connection
+** control block.
+**
+*******************************************************************************/
+void RFCOMM_PortNegReq (tRFC_MCB *p_mcb, UINT8 dlci, tPORT_STATE *p_pars)
+{
+ tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
+
+ if (p_mcb->state != RFC_MX_STATE_CONNECTED)
+ {
+ PORT_PortNegCnf (p_mcb, dlci, NULL, RFCOMM_ERROR);
+ return;
+ }
+
+ /* Send Parameter Negotiation Command UIH frame */
+ if (!p_pars)
+ p_port->rfc.expected_rsp |= RFC_RSP_RPN_REPLY;
+ else
+ p_port->rfc.expected_rsp |= RFC_RSP_RPN;
+
+ rfc_send_rpn (p_mcb, dlci, TRUE, p_pars, RFCOMM_RPN_PM_MASK);
+ rfc_port_timer_start (p_port, RFC_T2_TIMEOUT) ;
+
+}
+
+
+/*******************************************************************************
+**
+** Function RFCOMM_PortNegRsp
+**
+** Description This function is called by the user app to acknowledge
+** Port parameters negotiation.
+**
+*******************************************************************************/
+void RFCOMM_PortNegRsp (tRFC_MCB *p_mcb, UINT8 dlci, tPORT_STATE *p_pars,
+ UINT16 param_mask)
+{
+ if (p_mcb->state != RFC_MX_STATE_CONNECTED)
+ return;
+
+ rfc_send_rpn (p_mcb, dlci, FALSE, p_pars, param_mask);
+}
+
+
+/*******************************************************************************
+**
+** Function RFCOMM_ControlReq
+**
+** Description This function is called by the port entity to send control
+** parameters to remote port emulation entity.
+**
+*******************************************************************************/
+void RFCOMM_ControlReq (tRFC_MCB *p_mcb, UINT8 dlci, tPORT_CTRL *p_pars)
+{
+ tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
+
+ if ((p_port->state != PORT_STATE_OPENED)
+ || (p_port->rfc.state != RFC_STATE_OPENED))
+ return;
+
+ p_port->port_ctrl |= PORT_CTRL_REQ_SENT;
+
+ p_port->rfc.expected_rsp |= RFC_RSP_MSC;
+
+ rfc_send_msc (p_mcb, dlci, TRUE, p_pars);
+ rfc_port_timer_start (p_port, RFC_T2_TIMEOUT) ;
+
+}
+
+
+/*******************************************************************************
+**
+** Function RFCOMM_FlowReq
+**
+** Description This function is called by the port entity when flow
+** control state has changed. Enable flag passed shows if
+** port can accept more data.
+**
+*******************************************************************************/
+void RFCOMM_FlowReq (tRFC_MCB *p_mcb, UINT8 dlci, UINT8 enable)
+{
+ tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
+
+ if ((p_port->state != PORT_STATE_OPENED)
+ || (p_port->rfc.state != RFC_STATE_OPENED))
+ return;
+
+ p_port->local_ctrl.fc = !enable;
+
+ p_port->rfc.expected_rsp |= RFC_RSP_MSC;
+
+ rfc_send_msc (p_mcb, dlci, TRUE, &p_port->local_ctrl);
+ rfc_port_timer_start (p_port, RFC_T2_TIMEOUT) ;
+
+}
+
+
+/*******************************************************************************
+**
+** Function RFCOMM_LineStatusReq
+**
+** Description This function is called by the port entity when line
+** status should be delivered to the peer.
+**
+*******************************************************************************/
+void RFCOMM_LineStatusReq (tRFC_MCB *p_mcb, UINT8 dlci, UINT8 status)
+{
+ tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
+
+ if ((p_port->state != PORT_STATE_OPENED)
+ || (p_port->rfc.state != RFC_STATE_OPENED))
+ return;
+
+ p_port->rfc.expected_rsp |= RFC_RSP_RLS;
+
+ rfc_send_rls (p_mcb, dlci, TRUE, status);
+ rfc_port_timer_start (p_port, RFC_T2_TIMEOUT);
+}
+
+
+/*******************************************************************************
+**
+** Function RFCOMM_DlcReleaseReq
+**
+** Description This function is called by the PORT unit to close DLC
+**
+*******************************************************************************/
+void RFCOMM_DlcReleaseReq (tRFC_MCB *p_mcb, UINT8 dlci)
+{
+ rfc_port_sm_execute(port_find_mcb_dlci_port (p_mcb, dlci), RFC_EVENT_CLOSE, 0);
+}
+
+
+/*******************************************************************************
+**
+** Function RFCOMM_DataReq
+**
+** Description This function is called by the user app to send data buffer
+**
+*******************************************************************************/
+void RFCOMM_DataReq (tRFC_MCB *p_mcb, UINT8 dlci, BT_HDR *p_buf)
+{
+ rfc_port_sm_execute(port_find_mcb_dlci_port (p_mcb, dlci), RFC_EVENT_DATA, p_buf);
+}
+
+
diff --git a/stack/rfcomm/rfc_ts_frames.c b/stack/rfcomm/rfc_ts_frames.c
new file mode 100644
index 0000000..ad9aaef
--- /dev/null
+++ b/stack/rfcomm/rfc_ts_frames.c
@@ -0,0 +1,895 @@
+/*****************************************************************************
+**
+** Name: rfc_ts_frames.c
+**
+** Description: This file contains functions to send TS 07.10 frames
+**
+**
+** Copyright (c) 1999-2008, Broadcom Corp., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+#include "bt_target.h"
+#include "gki.h"
+#include "rfcdefs.h"
+#include "port_api.h"
+#include "l2c_api.h"
+#include "port_int.h"
+#include "rfc_int.h"
+
+/*******************************************************************************
+**
+** Function rfc_send_sabme
+**
+** Description This function sends SABME frame.
+**
+*******************************************************************************/
+void rfc_send_sabme (tRFC_MCB *p_mcb, UINT8 dlci)
+{
+ BT_HDR *p_buf;
+ UINT8 *p_data;
+ UINT8 cr = RFCOMM_CR(p_mcb->is_initiator, TRUE);
+
+ if ((p_buf = (BT_HDR *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) == NULL)
+ return;
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_data = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ /* SABME frame, command, PF = 1, dlci */
+ *p_data++ = RFCOMM_EA | cr | (dlci << RFCOMM_SHIFT_DLCI);
+ *p_data++ = RFCOMM_SABME | RFCOMM_PF;
+ *p_data++ = RFCOMM_EA | 0;
+
+ *p_data = RFCOMM_SABME_FCS ((UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET, cr, dlci);
+
+ p_buf->len = 4;
+
+ rfc_check_send_cmd(p_mcb, p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_send_ua
+**
+** Description This function sends UA frame.
+**
+*******************************************************************************/
+void rfc_send_ua (tRFC_MCB *p_mcb, UINT8 dlci)
+{
+ BT_HDR *p_buf;
+ UINT8 *p_data;
+ UINT8 cr = RFCOMM_CR(p_mcb->is_initiator, FALSE);
+
+ if ((p_buf = (BT_HDR *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) == NULL)
+ return;
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_data = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ /* ua frame, response, PF = 1, dlci */
+ *p_data++ = RFCOMM_EA | cr | (dlci << RFCOMM_SHIFT_DLCI);
+ *p_data++ = RFCOMM_UA | RFCOMM_PF;
+ *p_data++ = RFCOMM_EA | 0;
+
+ *p_data = RFCOMM_UA_FCS ((UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET, cr, dlci);
+
+ p_buf->len = 4;
+
+ rfc_check_send_cmd(p_mcb, p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_send_dm
+**
+** Description This function sends DM frame.
+**
+*******************************************************************************/
+void rfc_send_dm (tRFC_MCB *p_mcb, UINT8 dlci, BOOLEAN pf)
+{
+ BT_HDR *p_buf;
+ UINT8 *p_data;
+ UINT8 cr = RFCOMM_CR(p_mcb->is_initiator, FALSE);
+
+ if ((p_buf = (BT_HDR *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) == NULL)
+ return;
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_data = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ /* DM frame, response, PF = 1, dlci */
+ *p_data++ = RFCOMM_EA | cr | (dlci << RFCOMM_SHIFT_DLCI);
+ *p_data++ = RFCOMM_DM | ((pf) ? RFCOMM_PF : 0);
+ *p_data++ = RFCOMM_EA | 0;
+
+ *p_data = RFCOMM_DM_FCS ((UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET, cr, dlci);
+
+ p_buf->len = 4;
+
+ rfc_check_send_cmd(p_mcb, p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_send_disc
+**
+** Description This function sends DISC frame.
+**
+*******************************************************************************/
+void rfc_send_disc (tRFC_MCB *p_mcb, UINT8 dlci)
+{
+ BT_HDR *p_buf;
+ UINT8 *p_data;
+ UINT8 cr = RFCOMM_CR(p_mcb->is_initiator, TRUE);
+
+ if ((p_buf = (BT_HDR *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) == NULL)
+ return;
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_data = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ /* DISC frame, command, PF = 1, dlci */
+ *p_data++ = RFCOMM_EA | cr | (dlci << RFCOMM_SHIFT_DLCI);
+ *p_data++ = RFCOMM_DISC | RFCOMM_PF;
+ *p_data++ = RFCOMM_EA | 0;
+
+ *p_data = RFCOMM_DISC_FCS ((UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET, cr, dlci);
+
+ p_buf->len = 4;
+
+ rfc_check_send_cmd(p_mcb, p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_send_buf_uih
+**
+** Description This function sends UIH frame.
+**
+*******************************************************************************/
+void rfc_send_buf_uih (tRFC_MCB *p_mcb, UINT8 dlci, BT_HDR *p_buf)
+{
+ UINT8 *p_data;
+ UINT8 cr = RFCOMM_CR(p_mcb->is_initiator, TRUE);
+ UINT8 credits;
+
+ p_buf->offset -= RFCOMM_CTRL_FRAME_LEN;
+ if (p_buf->len > 127)
+ p_buf->offset--;
+
+ if (dlci)
+ credits = (UINT8)p_buf->layer_specific;
+ else
+ credits = 0;
+
+ if (credits)
+ p_buf->offset--;
+
+ p_data = (UINT8 *)(p_buf + 1) + p_buf->offset;
+
+ /* UIH frame, command, PF = 0, dlci */
+ *p_data++ = RFCOMM_EA | cr | (dlci << RFCOMM_SHIFT_DLCI);
+ *p_data++ = RFCOMM_UIH | ((credits) ? RFCOMM_PF : 0);
+ if (p_buf->len <= 127)
+ {
+ *p_data++ = RFCOMM_EA | (p_buf->len << 1);
+ p_buf->len += 3;
+ }
+ else
+ {
+ *p_data++ = (p_buf->len & 0x7f) << 1;
+ *p_data++ = p_buf->len >> RFCOMM_SHIFT_LENGTH2;
+ p_buf->len += 4;
+ }
+
+ if (credits)
+ {
+ *p_data++ = credits;
+ p_buf->len++;
+ }
+
+ p_data = (UINT8 *)(p_buf + 1) + p_buf->offset + p_buf->len++;
+
+ *p_data = RFCOMM_UIH_FCS ((UINT8 *)(p_buf + 1) + p_buf->offset, dlci);
+
+ if (dlci == RFCOMM_MX_DLCI)
+ {
+ rfc_check_send_cmd(p_mcb, p_buf);
+ }
+ else
+ {
+
+ L2CA_DataWrite (p_mcb->lcid, p_buf);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_send_pn
+**
+** Description This function sends DLC Parameters Negotiation Frame.
+**
+*******************************************************************************/
+void rfc_send_pn (tRFC_MCB *p_mcb, UINT8 dlci, BOOLEAN is_command, UINT16 mtu, UINT8 cl, UINT8 k)
+{
+ BT_HDR *p_buf;
+ UINT8 *p_data;
+
+ if ((p_buf = (BT_HDR *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) == NULL)
+ return;
+
+ p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_CTRL_FRAME_LEN;
+ p_data = (UINT8 *)(p_buf + 1) + p_buf->offset;
+
+ *p_data++ = RFCOMM_EA | RFCOMM_I_CR(is_command) | RFCOMM_MX_PN;
+ *p_data++ = RFCOMM_EA | (RFCOMM_MX_PN_LEN << 1);
+
+ *p_data++ = dlci;
+ *p_data++ = RFCOMM_PN_FRAM_TYPE_UIH | cl;
+
+ /* It appeared that we need to reply with the same priority bits as we received.
+ ** We will use the fact that we reply in the same context so rx_frame can still be used.
+ */
+ if (is_command)
+ *p_data++ = RFCOMM_PN_PRIORITY_0;
+ else
+ *p_data++ = rfc_cb.rfc.rx_frame.u.pn.priority;
+
+ *p_data++ = RFCOMM_T1_DSEC;
+ *p_data++ = mtu & 0xFF;
+ *p_data++ = mtu >> 8;
+ *p_data++ = RFCOMM_N2;
+ *p_data = k;
+
+ /* Total length is sizeof PN data + mx header 2 */
+ p_buf->len = RFCOMM_MX_PN_LEN + 2;
+
+ rfc_send_buf_uih (p_mcb, RFCOMM_MX_DLCI, p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_send_fcon
+**
+** Description This function sends Flow Control On Command.
+**
+*******************************************************************************/
+void rfc_send_fcon (tRFC_MCB *p_mcb, BOOLEAN is_command)
+{
+ BT_HDR *p_buf;
+ UINT8 *p_data;
+
+ if ((p_buf = (BT_HDR *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) == NULL)
+ return;
+
+ p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_CTRL_FRAME_LEN;
+ p_data = (UINT8 *)(p_buf + 1) + p_buf->offset;
+
+ *p_data++ = RFCOMM_EA | RFCOMM_I_CR(is_command) | RFCOMM_MX_FCON;
+ *p_data++ = RFCOMM_EA | (RFCOMM_MX_FCON_LEN << 1);
+
+ /* Total length is sizeof FCON data + mx header 2 */
+ p_buf->len = RFCOMM_MX_FCON_LEN + 2;
+
+ rfc_send_buf_uih (p_mcb, RFCOMM_MX_DLCI, p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_send_fcoff
+**
+** Description This function sends Flow Control Off Command.
+**
+*******************************************************************************/
+void rfc_send_fcoff (tRFC_MCB *p_mcb, BOOLEAN is_command)
+{
+ BT_HDR *p_buf;
+ UINT8 *p_data;
+
+ if ((p_buf = (BT_HDR *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) == NULL)
+ return;
+
+ p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_CTRL_FRAME_LEN;
+ p_data = (UINT8 *)(p_buf + 1) + p_buf->offset;
+
+ *p_data++ = RFCOMM_EA | RFCOMM_I_CR(is_command) | RFCOMM_MX_FCOFF;
+ *p_data++ = RFCOMM_EA | (RFCOMM_MX_FCOFF_LEN << 1);
+
+ /* Total length is sizeof FCOFF data + mx header 2 */
+ p_buf->len = RFCOMM_MX_FCOFF_LEN + 2;
+
+ rfc_send_buf_uih (p_mcb, RFCOMM_MX_DLCI, p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_send_msc
+**
+** Description This function sends Modem Status Command Frame.
+**
+*******************************************************************************/
+void rfc_send_msc (tRFC_MCB *p_mcb, UINT8 dlci, BOOLEAN is_command,
+ tPORT_CTRL *p_pars)
+{
+ BT_HDR *p_buf;
+ UINT8 *p_data;
+ UINT8 signals;
+ UINT8 break_duration;
+ UINT8 len;
+
+ signals = p_pars->modem_signal;
+ break_duration = p_pars->break_signal;
+
+ if ((p_buf = (BT_HDR *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) == NULL)
+ return;
+
+ p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_CTRL_FRAME_LEN;
+ p_data = (UINT8 *)(p_buf + 1) + p_buf->offset;
+
+ if (break_duration)
+ len = RFCOMM_MX_MSC_LEN_WITH_BREAK;
+ else
+ len = RFCOMM_MX_MSC_LEN_NO_BREAK;
+
+ *p_data++ = RFCOMM_EA | RFCOMM_I_CR(is_command) | RFCOMM_MX_MSC;
+ *p_data++ = RFCOMM_EA | (len << 1);
+
+ *p_data++ = RFCOMM_EA | RFCOMM_CR_MASK | (dlci << RFCOMM_SHIFT_DLCI);
+ *p_data++ = RFCOMM_EA |
+ ((p_pars->fc) ? RFCOMM_MSC_FC : 0) |
+ ((signals & MODEM_SIGNAL_DTRDSR) ? RFCOMM_MSC_RTC : 0) |
+ ((signals & MODEM_SIGNAL_RTSCTS) ? RFCOMM_MSC_RTR : 0) |
+ ((signals & MODEM_SIGNAL_RI) ? RFCOMM_MSC_IC : 0) |
+ ((signals & MODEM_SIGNAL_DCD) ? RFCOMM_MSC_DV : 0);
+
+ if (break_duration)
+ {
+ *p_data++ = RFCOMM_EA | RFCOMM_MSC_BREAK_PRESENT_MASK |
+ (break_duration << RFCOMM_MSC_SHIFT_BREAK);
+ }
+
+ /* Total length is sizeof MSC data + mx header 2 */
+ p_buf->len = len + 2;
+
+ rfc_send_buf_uih (p_mcb, RFCOMM_MX_DLCI, p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_send_rls
+**
+** Description This function sends Remote Line Status Command Frame.
+**
+*******************************************************************************/
+void rfc_send_rls (tRFC_MCB *p_mcb, UINT8 dlci, BOOLEAN is_command, UINT8 status)
+{
+ BT_HDR *p_buf;
+ UINT8 *p_data;
+
+ if ((p_buf = (BT_HDR *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) == NULL)
+ return;
+
+ p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_CTRL_FRAME_LEN;
+ p_data = (UINT8 *)(p_buf + 1) + p_buf->offset;
+
+ *p_data++ = RFCOMM_EA | RFCOMM_I_CR(is_command) | RFCOMM_MX_RLS;
+ *p_data++ = RFCOMM_EA | (RFCOMM_MX_RLS_LEN << 1);
+
+ *p_data++ = RFCOMM_EA | RFCOMM_CR_MASK | (dlci << RFCOMM_SHIFT_DLCI);
+ *p_data++ = RFCOMM_RLS_ERROR | status;
+
+ /* Total length is sizeof RLS data + mx header 2 */
+ p_buf->len = RFCOMM_MX_RLS_LEN + 2;
+
+ rfc_send_buf_uih (p_mcb, RFCOMM_MX_DLCI, p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_send_nsc
+**
+** Description This function sends Non Supported Command Response.
+**
+*******************************************************************************/
+void rfc_send_nsc (tRFC_MCB *p_mcb)
+{
+ BT_HDR *p_buf;
+ UINT8 *p_data;
+
+ if ((p_buf = (BT_HDR *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) == NULL)
+ return;
+
+ p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_CTRL_FRAME_LEN;
+ p_data = (UINT8 *)(p_buf + 1) + p_buf->offset;
+
+ *p_data++ = RFCOMM_EA | RFCOMM_I_CR(FALSE) | RFCOMM_MX_NSC;
+ *p_data++ = RFCOMM_EA | (RFCOMM_MX_NSC_LEN << 1);
+
+ *p_data++ = rfc_cb.rfc.rx_frame.ea |
+ (rfc_cb.rfc.rx_frame.cr << RFCOMM_SHIFT_CR) |
+ rfc_cb.rfc.rx_frame.type;
+
+ /* Total length is sizeof NSC data + mx header 2 */
+ p_buf->len = RFCOMM_MX_NSC_LEN + 2;
+
+ rfc_send_buf_uih (p_mcb, RFCOMM_MX_DLCI, p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_send_rpn
+**
+** Description This function sends Remote Port Negotiation Command
+**
+*******************************************************************************/
+void rfc_send_rpn (tRFC_MCB *p_mcb, UINT8 dlci, BOOLEAN is_command,
+ tPORT_STATE *p_pars, UINT16 mask)
+{
+ BT_HDR *p_buf;
+ UINT8 *p_data;
+
+ if ((p_buf = (BT_HDR *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) == NULL)
+ return;
+
+ p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_CTRL_FRAME_LEN;
+ p_data = (UINT8 *)(p_buf + 1) + p_buf->offset;
+
+ *p_data++ = RFCOMM_EA | RFCOMM_I_CR(is_command) | RFCOMM_MX_RPN;
+
+ if (!p_pars)
+ {
+ *p_data++ = RFCOMM_EA | (RFCOMM_MX_RPN_REQ_LEN << 1);
+
+ *p_data++ = RFCOMM_EA | RFCOMM_CR_MASK | (dlci << RFCOMM_SHIFT_DLCI);
+
+ p_buf->len = RFCOMM_MX_RPN_REQ_LEN + 2;
+ }
+ else
+ {
+ *p_data++ = RFCOMM_EA | (RFCOMM_MX_RPN_LEN << 1);
+
+ *p_data++ = RFCOMM_EA | RFCOMM_CR_MASK | (dlci << RFCOMM_SHIFT_DLCI);
+ *p_data++ = p_pars->baud_rate;
+ *p_data++ = (p_pars->byte_size << RFCOMM_RPN_BITS_SHIFT)
+ | (p_pars->stop_bits << RFCOMM_RPN_STOP_BITS_SHIFT)
+ | (p_pars->parity << RFCOMM_RPN_PARITY_SHIFT)
+ | (p_pars->parity_type << RFCOMM_RPN_PARITY_TYPE_SHIFT);
+ *p_data++ = p_pars->fc_type;
+ *p_data++ = p_pars->xon_char;
+ *p_data++ = p_pars->xoff_char;
+ *p_data++ = (mask & 0xFF);
+ *p_data++ = (mask >> 8);
+
+ /* Total length is sizeof RPN data + mx header 2 */
+ p_buf->len = RFCOMM_MX_RPN_LEN + 2;
+ }
+
+ rfc_send_buf_uih (p_mcb, RFCOMM_MX_DLCI, p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_send_test
+**
+** Description This function sends Test frame.
+**
+*******************************************************************************/
+void rfc_send_test (tRFC_MCB *p_mcb, BOOLEAN is_command, BT_HDR *p_buf)
+{
+ UINT8 *p_data;
+ UINT16 xx;
+ UINT8 *p_src, *p_dest;
+
+ /* Shift buffer to give space for header */
+ if (p_buf->offset < (L2CAP_MIN_OFFSET + RFCOMM_MIN_OFFSET + 2))
+ {
+ p_src = (UINT8 *) (p_buf + 1) + p_buf->offset + p_buf->len - 1;
+ p_dest = (UINT8 *) (p_buf + 1) + L2CAP_MIN_OFFSET + RFCOMM_MIN_OFFSET + 2 + p_buf->len - 1;
+
+ for (xx = 0; xx < p_buf->len; xx++)
+ *p_dest-- = *p_src--;
+
+ p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_MIN_OFFSET + 2;
+ }
+
+ /* Adjust offset by number of bytes we are going to fill */
+ p_buf->offset -= 2;
+ p_data = (UINT8 *)(p_buf + 1) + p_buf->offset;
+
+ *p_data++ = RFCOMM_EA | RFCOMM_I_CR(is_command) | RFCOMM_MX_TEST;
+ *p_data++ = RFCOMM_EA | (p_buf->len << 1);
+
+ p_buf->len += 2;
+
+ rfc_send_buf_uih (p_mcb, RFCOMM_MX_DLCI, p_buf);
+}
+
+/*******************************************************************************
+**
+** Function rfc_send_credit
+**
+** Description This function sends a flow control credit in UIH frame.
+**
+*******************************************************************************/
+void rfc_send_credit(tRFC_MCB *p_mcb, UINT8 dlci, UINT8 credit)
+{
+ BT_HDR *p_buf;
+ UINT8 *p_data;
+ UINT8 cr = RFCOMM_CR(p_mcb->is_initiator, TRUE);
+
+ if ((p_buf = (BT_HDR *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) == NULL)
+ return;
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_data = (UINT8 *)(p_buf + 1) + p_buf->offset;
+
+ *p_data++ = RFCOMM_EA | cr | (dlci << RFCOMM_SHIFT_DLCI);
+ *p_data++ = RFCOMM_UIH | RFCOMM_PF;
+ *p_data++ = RFCOMM_EA | 0;
+ *p_data++ = credit;
+ *p_data = RFCOMM_UIH_FCS ((UINT8 *)(p_buf + 1) + p_buf->offset, dlci);
+
+ p_buf->len = 5;
+
+ rfc_check_send_cmd(p_mcb, p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_parse_data
+**
+** Description This function processes data packet received from L2CAP
+**
+*******************************************************************************/
+UINT8 rfc_parse_data (tRFC_MCB *p_mcb, MX_FRAME *p_frame, BT_HDR *p_buf)
+{
+ UINT8 ead, eal, fcs;
+ UINT8 *p_data = (UINT8 *)(p_buf + 1) + p_buf->offset;
+ UINT8 *p_start = p_data;
+ UINT16 len;
+
+ if (p_buf->len < RFCOMM_CTRL_FRAME_LEN)
+ {
+ RFCOMM_TRACE_ERROR1 ("Bad Length1: %d", p_buf->len);
+ return (RFC_EVENT_BAD_FRAME);
+ }
+
+ RFCOMM_PARSE_CTRL_FIELD (ead, p_frame->cr, p_frame->dlci, p_data);
+ if( !ead )
+ {
+ RFCOMM_TRACE_ERROR0 ("Bad Address(EA must be 1)");
+ return (RFC_EVENT_BAD_FRAME);
+ }
+ RFCOMM_PARSE_TYPE_FIELD (p_frame->type, p_frame->pf, p_data);
+ RFCOMM_PARSE_LEN_FIELD (eal, len, p_data);
+
+ p_buf->len -= (3 + !ead + !eal + 1); /* Additional 1 for FCS */
+ p_buf->offset += (3 + !ead + !eal);
+
+ /* handle credit if credit based flow control */
+ if ((p_mcb->flow == PORT_FC_CREDIT) && (p_frame->type == RFCOMM_UIH) &&
+ (p_frame->dlci != RFCOMM_MX_DLCI) && (p_frame->pf == 1))
+ {
+ p_frame->credit = *p_data++;
+ p_buf->len--;
+ p_buf->offset++;
+ }
+ else
+ p_frame->credit = 0;
+
+ if (p_buf->len != len)
+ {
+ RFCOMM_TRACE_ERROR2 ("Bad Length2 %d %d", p_buf->len, len);
+ return (RFC_EVENT_BAD_FRAME);
+ }
+
+ fcs = *(p_data + len);
+
+ /* All control frames that we are sending are sent with P=1, expect */
+ /* reply with F=1 */
+ /* According to TS 07.10 spec ivalid frames are discarded without */
+ /* notification to the sender */
+ switch (p_frame->type)
+ {
+ case RFCOMM_SABME:
+ if (RFCOMM_FRAME_IS_RSP(p_mcb->is_initiator, p_frame->cr)
+ || !p_frame->pf || len || !RFCOMM_VALID_DLCI (p_frame->dlci)
+ || !rfc_check_fcs (RFCOMM_CTRL_FRAME_LEN, p_start, fcs))
+ {
+ RFCOMM_TRACE_ERROR0 ("Bad SABME");
+ return (RFC_EVENT_BAD_FRAME);
+ }
+ else
+ return (RFC_EVENT_SABME);
+
+ case RFCOMM_UA:
+ if (RFCOMM_FRAME_IS_CMD(p_mcb->is_initiator, p_frame->cr)
+ || !p_frame->pf || len || !RFCOMM_VALID_DLCI (p_frame->dlci)
+ || !rfc_check_fcs (RFCOMM_CTRL_FRAME_LEN, p_start, fcs))
+ {
+ RFCOMM_TRACE_ERROR0 ("Bad UA");
+ return (RFC_EVENT_BAD_FRAME);
+ }
+ else
+ return (RFC_EVENT_UA);
+
+ case RFCOMM_DM:
+ if (RFCOMM_FRAME_IS_CMD(p_mcb->is_initiator, p_frame->cr)
+ || len || !RFCOMM_VALID_DLCI(p_frame->dlci)
+ || !rfc_check_fcs (RFCOMM_CTRL_FRAME_LEN, p_start, fcs))
+ {
+ RFCOMM_TRACE_ERROR0 ("Bad DM");
+ return (RFC_EVENT_BAD_FRAME);
+ }
+ else
+ return (RFC_EVENT_DM);
+
+ case RFCOMM_DISC:
+ if (RFCOMM_FRAME_IS_RSP(p_mcb->is_initiator, p_frame->cr)
+ || !p_frame->pf || len || !RFCOMM_VALID_DLCI(p_frame->dlci)
+ || !rfc_check_fcs (RFCOMM_CTRL_FRAME_LEN, p_start, fcs))
+ {
+ RFCOMM_TRACE_ERROR0 ("Bad DISC");
+ return (RFC_EVENT_BAD_FRAME);
+ }
+ else
+ return (RFC_EVENT_DISC);
+
+ case RFCOMM_UIH:
+ if (!RFCOMM_VALID_DLCI(p_frame->dlci))
+ {
+ RFCOMM_TRACE_ERROR0 ("Bad UIH - invalid DLCI");
+ return (RFC_EVENT_BAD_FRAME);
+ }
+ else if (!rfc_check_fcs (2, p_start, fcs))
+ {
+ RFCOMM_TRACE_ERROR0 ("Bad UIH - FCS");
+ return (RFC_EVENT_BAD_FRAME);
+ }
+ else if (RFCOMM_FRAME_IS_RSP(p_mcb->is_initiator, p_frame->cr))
+ {
+ /* we assume that this is ok to allow bad implementations to work */
+ RFCOMM_TRACE_ERROR0 ("Bad UIH - response");
+ return (RFC_EVENT_UIH);
+ }
+ else
+ return (RFC_EVENT_UIH);
+ }
+
+ return (RFC_EVENT_BAD_FRAME);
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_process_mx_message
+**
+** Description This function processes UIH frames received on the
+** multiplexer control channel.
+**
+*******************************************************************************/
+void rfc_process_mx_message (tRFC_MCB *p_mcb, BT_HDR *p_buf)
+{
+ UINT8 *p_data = (UINT8 *)(p_buf + 1) + p_buf->offset;
+ MX_FRAME *p_rx_frame = &rfc_cb.rfc.rx_frame;
+ UINT16 length = p_buf->len;
+ UINT8 ea, cr, mx_len;
+ BOOLEAN is_command;
+
+ p_rx_frame->ea = *p_data & RFCOMM_EA;
+ p_rx_frame->cr = (*p_data & RFCOMM_CR_MASK) >> RFCOMM_SHIFT_CR;
+ p_rx_frame->type = *p_data++ & ~(RFCOMM_CR_MASK | RFCOMM_EA_MASK);
+
+ if (!p_rx_frame->ea || !length)
+ {
+ RFCOMM_TRACE_ERROR2 ("Illegal MX Frame ea:%d len:%d", p_rx_frame->ea, length);
+ GKI_freebuf (p_buf);
+ return;
+ }
+
+ length--;
+
+ is_command = p_rx_frame->cr;
+
+ ea = *p_data & RFCOMM_EA;
+
+ mx_len = *p_data++ >> RFCOMM_SHIFT_LENGTH1;
+ length--;
+
+ if (!ea)
+ {
+ mx_len += *p_data++ << RFCOMM_SHIFT_LENGTH2;
+ length --;
+ }
+
+ if (mx_len != length)
+ {
+ RFCOMM_TRACE_ERROR0 ("Bad MX frame");
+ GKI_freebuf (p_buf);
+ return;
+ }
+
+ switch (p_rx_frame->type)
+ {
+ case RFCOMM_MX_PN:
+ if (length != RFCOMM_MX_PN_LEN)
+ break;
+
+ p_rx_frame->dlci = *p_data++ & RFCOMM_PN_DLCI_MASK;
+ p_rx_frame->u.pn.frame_type = *p_data & RFCOMM_PN_FRAME_TYPE_MASK;
+ p_rx_frame->u.pn.conv_layer = *p_data++ & RFCOMM_PN_CONV_LAYER_MASK;
+ p_rx_frame->u.pn.priority = *p_data++ & RFCOMM_PN_PRIORITY_MASK;
+ p_rx_frame->u.pn.t1 = *p_data++;
+ p_rx_frame->u.pn.mtu = *p_data + (*(p_data + 1) << 8);
+ p_data += 2;
+ p_rx_frame->u.pn.n2 = *p_data++;
+ p_rx_frame->u.pn.k = *p_data++ & RFCOMM_PN_K_MASK;
+
+ if (!p_rx_frame->dlci
+ || !RFCOMM_VALID_DLCI (p_rx_frame->dlci)
+ || (p_rx_frame->u.pn.mtu < RFCOMM_MIN_MTU)
+ || (p_rx_frame->u.pn.mtu > RFCOMM_MAX_MTU))
+ {
+ RFCOMM_TRACE_ERROR0 ("Bad PN frame");
+ break;
+ }
+
+ GKI_freebuf (p_buf);
+
+ rfc_process_pn (p_mcb, is_command, p_rx_frame);
+ return;
+
+ case RFCOMM_MX_TEST:
+ if (!length)
+ break;
+
+ p_rx_frame->u.test.p_data = p_data;
+ p_rx_frame->u.test.data_len = length;
+
+ p_buf->offset += 2;
+ p_buf->len -= 2;
+
+ if (is_command)
+ rfc_send_test (p_mcb, FALSE, p_buf);
+ else
+ rfc_process_test_rsp (p_mcb, p_buf);
+ return;
+
+ case RFCOMM_MX_FCON:
+ if (length != RFCOMM_MX_FCON_LEN)
+ break;
+
+ GKI_freebuf (p_buf);
+
+ rfc_process_fcon (p_mcb, is_command);
+ return;
+
+ case RFCOMM_MX_FCOFF:
+ if (length != RFCOMM_MX_FCOFF_LEN)
+ break;
+
+ GKI_freebuf (p_buf);
+
+ rfc_process_fcoff (p_mcb, is_command);
+ return;
+
+ case RFCOMM_MX_MSC:
+
+ ea = *p_data & RFCOMM_EA;
+ cr = (*p_data & RFCOMM_CR_MASK) >> RFCOMM_SHIFT_CR;
+ p_rx_frame->dlci = *p_data++ >> RFCOMM_SHIFT_DLCI;
+
+ if (!ea || !cr || !p_rx_frame->dlci
+ || !RFCOMM_VALID_DLCI (p_rx_frame->dlci))
+ {
+ RFCOMM_TRACE_ERROR0 ("Bad MSC frame");
+ break;
+ }
+
+ p_rx_frame->u.msc.signals = *p_data++;
+
+ if (mx_len == RFCOMM_MX_MSC_LEN_WITH_BREAK)
+ {
+ p_rx_frame->u.msc.break_present = *p_data & RFCOMM_MSC_BREAK_PRESENT_MASK;
+ p_rx_frame->u.msc.break_duration = (*p_data & RFCOMM_MSC_BREAK_MASK) >> RFCOMM_MSC_SHIFT_BREAK;
+ }
+ else
+ {
+ p_rx_frame->u.msc.break_present = FALSE;
+ p_rx_frame->u.msc.break_duration = 0;
+ }
+ GKI_freebuf (p_buf);
+
+ rfc_process_msc (p_mcb, is_command, p_rx_frame);
+ return;
+
+ case RFCOMM_MX_NSC:
+ if ((length != RFCOMM_MX_NSC_LEN) || !is_command)
+ break;
+
+ p_rx_frame->u.nsc.ea = *p_data & RFCOMM_EA;
+ p_rx_frame->u.nsc.cr = (*p_data & RFCOMM_CR_MASK) >> RFCOMM_SHIFT_CR;
+ p_rx_frame->u.nsc.type = *p_data++ >> RFCOMM_SHIFT_DLCI;
+
+ GKI_freebuf (p_buf);
+
+ rfc_process_nsc (p_mcb, p_rx_frame);
+ return;
+
+ case RFCOMM_MX_RPN:
+ if ((length != RFCOMM_MX_RPN_REQ_LEN) && (length != RFCOMM_MX_RPN_LEN))
+ break;
+
+ ea = *p_data & RFCOMM_EA;
+ cr = (*p_data & RFCOMM_CR_MASK) >> RFCOMM_SHIFT_CR;
+ p_rx_frame->dlci = *p_data++ >> RFCOMM_SHIFT_DLCI;
+
+ if (!ea || !cr || !p_rx_frame->dlci
+ || !RFCOMM_VALID_DLCI (p_rx_frame->dlci))
+ {
+ RFCOMM_TRACE_ERROR0 ("Bad RPN frame");
+ break;
+ }
+
+ p_rx_frame->u.rpn.is_request = (length == RFCOMM_MX_RPN_REQ_LEN);
+
+ if (!p_rx_frame->u.rpn.is_request)
+ {
+ p_rx_frame->u.rpn.baud_rate = *p_data++;
+ p_rx_frame->u.rpn.byte_size = (*p_data >> RFCOMM_RPN_BITS_SHIFT) & RFCOMM_RPN_BITS_MASK;
+ p_rx_frame->u.rpn.stop_bits = (*p_data >> RFCOMM_RPN_STOP_BITS_SHIFT) & RFCOMM_RPN_STOP_BITS_MASK;
+ p_rx_frame->u.rpn.parity = (*p_data >> RFCOMM_RPN_PARITY_SHIFT) & RFCOMM_RPN_PARITY_MASK;
+ p_rx_frame->u.rpn.parity_type = (*p_data++ >> RFCOMM_RPN_PARITY_TYPE_SHIFT) & RFCOMM_RPN_PARITY_TYPE_MASK;
+
+ p_rx_frame->u.rpn.fc_type = *p_data++ & RFCOMM_FC_MASK;
+ p_rx_frame->u.rpn.xon_char = *p_data++;
+ p_rx_frame->u.rpn.xoff_char = *p_data++;
+ p_rx_frame->u.rpn.param_mask = (*p_data + (*(p_data + 1) << 8)) & RFCOMM_RPN_PM_MASK;
+ }
+ GKI_freebuf (p_buf);
+
+ rfc_process_rpn (p_mcb, is_command, p_rx_frame->u.rpn.is_request, p_rx_frame);
+ return;
+
+ case RFCOMM_MX_RLS:
+ if (length != RFCOMM_MX_RLS_LEN)
+ break;
+
+ ea = *p_data & RFCOMM_EA;
+ cr = (*p_data & RFCOMM_CR_MASK) >> RFCOMM_SHIFT_CR;
+
+ p_rx_frame->dlci = *p_data++ >> RFCOMM_SHIFT_DLCI;
+ p_rx_frame->u.rls.line_status = (*p_data & ~0x01);
+
+ if (!ea || !cr || !p_rx_frame->dlci
+ || !RFCOMM_VALID_DLCI (p_rx_frame->dlci))
+ {
+ RFCOMM_TRACE_ERROR0 ("Bad RPN frame");
+ break;
+ }
+
+ GKI_freebuf (p_buf);
+
+ rfc_process_rls (p_mcb, is_command, p_rx_frame);
+ return;
+ }
+
+ GKI_freebuf (p_buf);
+
+ if (is_command)
+ rfc_send_nsc (p_mcb);
+}
+
diff --git a/stack/rfcomm/rfc_utils.c b/stack/rfcomm/rfc_utils.c
new file mode 100644
index 0000000..9395891
--- /dev/null
+++ b/stack/rfcomm/rfc_utils.c
@@ -0,0 +1,453 @@
+/*****************************************************************************/
+/* */
+/* Name: rfc_utils.c */
+/* */
+/* Description: This file contains collection of utility functions used */
+/* the RFCOMM unit */
+/* */
+/* Copyright (c) 1999-2008, Broadcom Corp., All Rights Reserved. */
+/* WIDCOMM Bluetooth Core. Proprietary and confidential. */
+/*****************************************************************************/
+#include "bt_target.h"
+#include "gki.h"
+
+#include "btm_api.h"
+#include "btm_int.h"
+#include "rfcdefs.h"
+#include "port_api.h"
+#include "port_ext.h"
+#include "port_int.h"
+#include "rfc_int.h"
+#include "btu.h"
+
+#include <string.h>
+
+/*******************************************************************************
+**
+** Function rfc_calc_fcs
+**
+** Description Reversed CRC Table , 8-bit, poly=0x07
+** (GSM 07.10 TS 101 369 V6.3.0)
+*******************************************************************************/
+static const UINT8 rfc_crctable[] =
+{
+ 0x00, 0x91, 0xE3, 0x72, 0x07, 0x96, 0xE4, 0x75, 0x0E, 0x9F, 0xED, 0x7C, 0x09, 0x98, 0xEA, 0x7B,
+ 0x1C, 0x8D, 0xFF, 0x6E, 0x1B, 0x8A, 0xF8, 0x69, 0x12, 0x83, 0xF1, 0x60, 0x15, 0x84, 0xF6, 0x67,
+ 0x38, 0xA9, 0xDB, 0x4A, 0x3F, 0xAE, 0xDC, 0x4D, 0x36, 0xA7, 0xD5, 0x44, 0x31, 0xA0, 0xD2, 0x43,
+ 0x24, 0xB5, 0xC7, 0x56, 0x23, 0xB2, 0xC0, 0x51, 0x2A, 0xBB, 0xC9, 0x58, 0x2D, 0xBC, 0xCE, 0x5F,
+
+ 0x70, 0xE1, 0x93, 0x02, 0x77, 0xE6, 0x94, 0x05, 0x7E, 0xEF, 0x9D, 0x0C, 0x79, 0xE8, 0x9A, 0x0B,
+ 0x6C, 0xFD, 0x8F, 0x1E, 0x6B, 0xFA, 0x88, 0x19, 0x62, 0xF3, 0x81, 0x10, 0x65, 0xF4, 0x86, 0x17,
+ 0x48, 0xD9, 0xAB, 0x3A, 0x4F, 0xDE, 0xAC, 0x3D, 0x46, 0xD7, 0xA5, 0x34, 0x41, 0xD0, 0xA2, 0x33,
+ 0x54, 0xC5, 0xB7, 0x26, 0x53, 0xC2, 0xB0, 0x21, 0x5A, 0xCB, 0xB9, 0x28, 0x5D, 0xCC, 0xBE, 0x2F,
+
+ 0xE0, 0x71, 0x03, 0x92, 0xE7, 0x76, 0x04, 0x95, 0xEE, 0x7F, 0x0D, 0x9C, 0xE9, 0x78, 0x0A, 0x9B,
+ 0xFC, 0x6D, 0x1F, 0x8E, 0xFB, 0x6A, 0x18, 0x89, 0xF2, 0x63, 0x11, 0x80, 0xF5, 0x64, 0x16, 0x87,
+ 0xD8, 0x49, 0x3B, 0xAA, 0xDF, 0x4E, 0x3C, 0xAD, 0xD6, 0x47, 0x35, 0xA4, 0xD1, 0x40, 0x32, 0xA3,
+ 0xC4, 0x55, 0x27, 0xB6, 0xC3, 0x52, 0x20, 0xB1, 0xCA, 0x5B, 0x29, 0xB8, 0xCD, 0x5C, 0x2E, 0xBF,
+
+ 0x90, 0x01, 0x73, 0xE2, 0x97, 0x06, 0x74, 0xE5, 0x9E, 0x0F, 0x7D, 0xEC, 0x99, 0x08, 0x7A, 0xEB,
+ 0x8C, 0x1D, 0x6F, 0xFE, 0x8B, 0x1A, 0x68, 0xF9, 0x82, 0x13, 0x61, 0xF0, 0x85, 0x14, 0x66, 0xF7,
+ 0xA8, 0x39, 0x4B, 0xDA, 0xAF, 0x3E, 0x4C, 0xDD, 0xA6, 0x37, 0x45, 0xD4, 0xA1, 0x30, 0x42, 0xD3,
+ 0xB4, 0x25, 0x57, 0xC6, 0xB3, 0x22, 0x50, 0xC1, 0xBA, 0x2B, 0x59, 0xC8, 0xBD, 0x2C, 0x5E, 0xCF
+};
+
+
+/*******************************************************************************
+**
+** Function rfc_calc_fcs
+**
+** Description This function calculate FCS for the RFCOMM frame
+** (GSM 07.10 TS 101 369 V6.3.0)
+**
+** Input len - number of bytes in the message
+** p - points to message
+**
+*******************************************************************************/
+UINT8 rfc_calc_fcs (UINT16 len, UINT8 *p)
+{
+ UINT8 fcs = 0xFF;
+
+ while (len--)
+ {
+ fcs = rfc_crctable[fcs ^ *p++];
+ }
+
+ /* Ones compliment */
+ return (0xFF - fcs);
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_check_fcs
+**
+** Description This function checks FCS for the RFCOMM frame
+** (GSM 07.10 TS 101 369 V6.3.0)
+**
+** Input len - number of bytes in the message
+** p - points to message
+** received_fcs - received FCS
+**
+*******************************************************************************/
+BOOLEAN rfc_check_fcs (UINT16 len, UINT8 *p, UINT8 received_fcs)
+{
+ UINT8 fcs = 0xFF;
+
+ while (len--)
+ {
+ fcs = rfc_crctable[fcs ^ *p++];
+ }
+
+ /* Ones compliment */
+ fcs = rfc_crctable[fcs ^ received_fcs];
+
+ /*0xCF is the reversed order of 11110011.*/
+ return (fcs == 0xCF);
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_alloc_multiplexer_channel
+**
+** Description This function returns existing or new control block for
+** the BD_ADDR.
+**
+*******************************************************************************/
+tRFC_MCB *rfc_alloc_multiplexer_channel (BD_ADDR bd_addr, BOOLEAN is_initiator)
+{
+ int i, j;
+ tRFC_MCB *p_mcb = NULL;
+
+ for (i = 0; i < MAX_BD_CONNECTIONS; i++)
+ {
+ if ((rfc_cb.port.rfc_mcb[i].state != RFC_MX_STATE_IDLE)
+ && (!memcmp (rfc_cb.port.rfc_mcb[i].bd_addr, bd_addr, BD_ADDR_LEN)))
+ {
+ /* Multiplexer channel found do not change anything */
+ /* If there was an inactivity timer running stop it now */
+ if (rfc_cb.port.rfc_mcb[i].state == RFC_MX_STATE_CONNECTED)
+ rfc_timer_stop (&rfc_cb.port.rfc_mcb[i]);
+ return (&rfc_cb.port.rfc_mcb[i]);
+ }
+ }
+
+ /* connection with bd_addr does not exist */
+ for (i = 0, j = rfc_cb.rfc.last_mux + 1; i < MAX_BD_CONNECTIONS; i++, j++)
+ {
+ if (j >= MAX_BD_CONNECTIONS)
+ j = 0;
+
+ p_mcb = &rfc_cb.port.rfc_mcb[j];
+ if (rfc_cb.port.rfc_mcb[j].state == RFC_MX_STATE_IDLE)
+ {
+ /* New multiplexer control block */
+ memset (p_mcb, 0, sizeof (tRFC_MCB));
+ memcpy (p_mcb->bd_addr, bd_addr, BD_ADDR_LEN);
+
+ GKI_init_q(&p_mcb->cmd_q);
+
+ p_mcb->is_initiator = is_initiator;
+
+ rfc_timer_start (p_mcb, RFC_MCB_INIT_INACT_TIMER);
+
+ rfc_cb.rfc.last_mux = (UINT8) j;
+ return (p_mcb);
+ }
+ }
+ return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_release_multiplexer_channel
+**
+** Description This function returns existing or new control block for
+** the BD_ADDR.
+**
+*******************************************************************************/
+void rfc_release_multiplexer_channel (tRFC_MCB *p_mcb)
+{
+ void *p_buf;
+
+ rfc_timer_stop (p_mcb);
+
+ while ((p_buf = GKI_dequeue(&p_mcb->cmd_q)) != NULL)
+ GKI_freebuf(p_buf);
+
+ memset (p_mcb, 0, sizeof (tRFC_MCB));
+ p_mcb->state = RFC_MX_STATE_IDLE;
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_timer_start
+**
+** Description Start RFC Timer
+**
+*******************************************************************************/
+void rfc_timer_start (tRFC_MCB *p_mcb, UINT16 timeout)
+{
+ TIMER_LIST_ENT *p_tle = &p_mcb->tle;
+
+ RFCOMM_TRACE_EVENT1 ("rfc_timer_start - timeout:%d", timeout);
+
+ p_tle->param = (UINT32)p_mcb;
+
+ btu_start_timer (p_tle, BTU_TTYPE_RFCOMM_MFC, timeout);
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_timer_stop
+**
+** Description Stop RFC Timer
+**
+*******************************************************************************/
+void rfc_timer_stop (tRFC_MCB *p_mcb)
+{
+ RFCOMM_TRACE_EVENT0 ("rfc_timer_stop");
+
+ btu_stop_timer (&p_mcb->tle);
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_port_timer_start
+**
+** Description Start RFC Timer
+**
+*******************************************************************************/
+void rfc_port_timer_start (tPORT *p_port, UINT16 timeout)
+{
+ TIMER_LIST_ENT *p_tle = &p_port->rfc.tle;
+
+ RFCOMM_TRACE_EVENT1 ("rfc_port_timer_start - timeout:%d", timeout);
+
+ p_tle->param = (UINT32)p_port;
+
+ btu_start_timer (p_tle, BTU_TTYPE_RFCOMM_PORT, timeout);
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_port_timer_stop
+**
+** Description Stop RFC Timer
+**
+*******************************************************************************/
+void rfc_port_timer_stop (tPORT *p_port)
+{
+ RFCOMM_TRACE_EVENT0 ("rfc_port_timer_stop");
+
+ btu_stop_timer (&p_port->rfc.tle);
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_check_mcb_active
+**
+** Description Check if there are any opened ports on the MCB if not
+** start MCB Inact timer.
+**
+** Returns void
+**
+*******************************************************************************/
+void rfc_check_mcb_active (tRFC_MCB *p_mcb)
+{
+ UINT16 i;
+
+ for (i = 0; i < RFCOMM_MAX_DLCI; i++)
+ {
+ if (p_mcb->port_inx[i] != 0)
+ {
+ p_mcb->is_disc_initiator = FALSE;
+ return;
+ }
+ }
+ /* The last port was DISCed. On the client side start disconnecting Mx */
+ /* On the server side start inactivity timer */
+ if (p_mcb->is_disc_initiator)
+ {
+ p_mcb->is_disc_initiator = FALSE;
+ rfc_mx_sm_execute (p_mcb, RFC_MX_EVENT_CLOSE_REQ, NULL);
+ }
+ else
+ rfc_timer_start (p_mcb, RFC_MCB_RELEASE_INACT_TIMER);
+}
+
+
+/*******************************************************************************
+**
+** Function rfcomm_process_timeout
+**
+** Description The function called every second to check RFCOMM timers
+**
+** Returns void
+**
+*******************************************************************************/
+void rfcomm_process_timeout (TIMER_LIST_ENT *p_tle)
+{
+ switch (p_tle->event)
+ {
+ case BTU_TTYPE_RFCOMM_MFC:
+ rfc_mx_sm_execute ((tRFC_MCB *)p_tle->param, RFC_EVENT_TIMEOUT, NULL);
+ break;
+
+ case BTU_TTYPE_RFCOMM_PORT:
+ rfc_port_sm_execute ((tPORT *)p_tle->param, RFC_EVENT_TIMEOUT, NULL);
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_sec_check_complete
+**
+** Description The function called when Security Manager finishes
+** verification of the service side connection
+**
+** Returns void
+**
+*******************************************************************************/
+void rfc_sec_check_complete (BD_ADDR bd_addr, void *p_ref_data, UINT8 res)
+{
+ tPORT *p_port = (tPORT *)p_ref_data;
+
+ /* Verify that PORT is still waiting for Security to complete */
+ if (!p_port->in_use
+ || ((p_port->rfc.state != RFC_STATE_ORIG_WAIT_SEC_CHECK)
+ && (p_port->rfc.state != RFC_STATE_TERM_WAIT_SEC_CHECK)))
+ return;
+
+ rfc_port_sm_execute ((tPORT *)p_ref_data, RFC_EVENT_SEC_COMPLETE, &res);
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_port_closed
+**
+** Description The function is called when port is released based on the
+** event received from the lower layer, typically L2CAP
+** connection down, DISC, or DM frame.
+**
+** Returns void
+**
+*******************************************************************************/
+void rfc_port_closed (tPORT *p_port)
+{
+ tRFC_MCB *p_mcb = p_port->rfc.p_mcb;
+
+ RFCOMM_TRACE_DEBUG0 ("rfc_port_closed");
+
+ rfc_port_timer_stop (p_port);
+
+ p_port->rfc.state = RFC_STATE_CLOSED;
+
+ /* If multiplexer channel was up mark it as down */
+ if (p_mcb)
+ {
+ p_mcb->port_inx[p_port->dlci] = 0;
+
+ /* If there are no more ports opened on this MCB release it */
+ rfc_check_mcb_active (p_mcb);
+ }
+
+ /* Notify port that RFC connection is gone */
+ port_rfc_closed (p_port, PORT_CLOSED);
+}
+
+/*******************************************************************************
+**
+** Function rfc_inc_credit
+**
+** Description The function is called when a credit is received in a UIH
+** frame. It increments the TX credit count, and if data
+** flow had halted, it restarts it.
+**
+** Returns void
+**
+*******************************************************************************/
+void rfc_inc_credit (tPORT *p_port, UINT8 credit)
+{
+ if (p_port->rfc.p_mcb->flow == PORT_FC_CREDIT)
+ {
+ p_port->credit_tx += credit;
+
+ RFCOMM_TRACE_EVENT1 ("rfc_inc_credit:%d", p_port->credit_tx);
+
+ if (p_port->tx.peer_fc == TRUE)
+ PORT_FlowInd(p_port->rfc.p_mcb, p_port->dlci, TRUE);
+ }
+}
+
+/*******************************************************************************
+**
+** Function rfc_dec_credit
+**
+** Description The function is called when a UIH frame of user data is
+** sent. It decrements the credit count. If credit count
+** Reaches zero, peer_fc is set.
+**
+** Returns void
+**
+*******************************************************************************/
+void rfc_dec_credit (tPORT *p_port)
+{
+ if (p_port->rfc.p_mcb->flow == PORT_FC_CREDIT)
+ {
+ if (p_port->credit_tx > 0)
+ p_port->credit_tx--;
+
+ if (p_port->credit_tx == 0)
+ p_port->tx.peer_fc = TRUE;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function rfc_check_send_cmd
+**
+** Description This function is called to send an RFCOMM command message
+** or to handle the RFCOMM command message queue.
+**
+** Returns void
+**
+*******************************************************************************/
+void rfc_check_send_cmd(tRFC_MCB *p_mcb, BT_HDR *p_buf)
+{
+ BT_HDR *p;
+
+ /* if passed a buffer queue it */
+ if (p_buf != NULL)
+ {
+ GKI_enqueue(&p_mcb->cmd_q, p_buf);
+ }
+
+ /* handle queue if L2CAP not congested */
+ while (p_mcb->l2cap_congested == FALSE)
+ {
+ if ((p = (BT_HDR *) GKI_dequeue(&p_mcb->cmd_q)) == NULL)
+ {
+ break;
+ }
+
+
+ L2CA_DataWrite (p_mcb->lcid, p);
+ }
+}
+
+
diff --git a/stack/sdp/sdp_api.c b/stack/sdp/sdp_api.c
new file mode 100644
index 0000000..2545181
--- /dev/null
+++ b/stack/sdp/sdp_api.c
@@ -0,0 +1,1264 @@
+/*****************************************************************************
+**
+** Name: sdp_api.c
+**
+** Description: this file contains SDP interface functions
+**
+**
+** Copyright (c) 1999-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "bt_target.h"
+#include "gki.h"
+#include "l2cdefs.h"
+#include "hcidefs.h"
+#include "hcimsgs.h"
+
+#include "sdp_api.h"
+#include "sdpint.h"
+#include "btu.h"
+
+
+/**********************************************************************
+** C L I E N T F U N C T I O N P R O T O T Y P E S *
+***********************************************************************/
+
+/*******************************************************************************
+**
+** Function SDP_InitDiscoveryDb
+**
+** Description This function is called to initialize a discovery database.
+**
+** Parameters: p_db - (input) address of an area of memory where the
+** discovery database is managed.
+** len - (input) size (in bytes) of the memory
+** NOTE: This must be larger than sizeof(tSDP_DISCOVERY_DB)
+** num_uuid - (input) number of UUID filters applied
+** p_uuid_list - (input) list of UUID filters
+** num_attr - (input) number of attribute filters applied
+** p_attr_list - (input) list of attribute filters
+**
+**
+** Returns BOOLEAN
+** TRUE if successful
+** FALSE if one or more parameters are bad
+**
+*******************************************************************************/
+BOOLEAN SDP_InitDiscoveryDb (tSDP_DISCOVERY_DB *p_db, UINT32 len, UINT16 num_uuid,
+ tSDP_UUID *p_uuid_list, UINT16 num_attr, UINT16 *p_attr_list)
+{
+#if SDP_CLIENT_ENABLED == TRUE
+ UINT16 xx;
+
+ /* verify the parameters */
+ if (p_db == NULL || (sizeof (tSDP_DISCOVERY_DB) > len) ||
+ num_attr > SDP_MAX_ATTR_FILTERS || num_uuid > SDP_MAX_UUID_FILTERS)
+ {
+ SDP_TRACE_ERROR4("SDP_InitDiscoveryDb Illegal param: p_db 0x%x, len %d, num_uuid %d, num_attr %d",
+ (UINT32)p_db, len, num_uuid, num_attr);
+
+ return (FALSE);
+ }
+
+ memset (p_db, 0, (size_t)len);
+
+ p_db->mem_size = len - sizeof (tSDP_DISCOVERY_DB);
+ p_db->mem_free = p_db->mem_size;
+ p_db->p_first_rec = NULL;
+ p_db->p_free_mem = (UINT8 *)(p_db + 1);
+
+ for (xx = 0; xx < num_uuid; xx++)
+ p_db->uuid_filters[xx] = *p_uuid_list++;
+
+ p_db->num_uuid_filters = num_uuid;
+
+ for (xx = 0; xx < num_attr; xx++)
+ p_db->attr_filters[xx] = *p_attr_list++;
+
+ /* sort attributes */
+ sdpu_sort_attr_list( num_attr, p_db );
+
+ p_db->num_attr_filters = num_attr;
+#endif
+ return (TRUE);
+}
+
+
+
+/*******************************************************************************
+**
+** Function SDP_CancelServiceSearch
+**
+** Description This function cancels an active query to an SDP server.
+**
+** Returns TRUE if discovery cancelled, FALSE if a matching activity is not found.
+**
+*******************************************************************************/
+BOOLEAN SDP_CancelServiceSearch (tSDP_DISCOVERY_DB *p_db)
+{
+#if SDP_CLIENT_ENABLED == TRUE
+ tCONN_CB *p_ccb = sdpu_find_ccb_by_db (p_db);
+ if (!p_ccb)
+ return (FALSE);
+
+ sdp_disconnect (p_ccb, SDP_CANCEL);
+ p_ccb->disc_state = SDP_DISC_WAIT_CANCEL;
+#endif
+ return (TRUE);
+}
+
+
+
+/*******************************************************************************
+**
+** Function SDP_ServiceSearchRequest
+**
+** Description This function queries an SDP server for information.
+**
+** Returns TRUE if discovery started, FALSE if failed.
+**
+*******************************************************************************/
+BOOLEAN SDP_ServiceSearchRequest (UINT8 *p_bd_addr, tSDP_DISCOVERY_DB *p_db,
+ tSDP_DISC_CMPL_CB *p_cb)
+{
+#if SDP_CLIENT_ENABLED == TRUE
+ tCONN_CB *p_ccb;
+
+ /* Specific BD address */
+ p_ccb = sdp_conn_originate (p_bd_addr);
+
+ if (!p_ccb)
+ return (FALSE);
+
+ p_ccb->disc_state = SDP_DISC_WAIT_CONN;
+ p_ccb->p_db = p_db;
+ p_ccb->p_cb = p_cb;
+
+ return (TRUE);
+#else
+ return (FALSE);
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function SDP_ServiceSearchAttributeRequest
+**
+** Description This function queries an SDP server for information.
+**
+** The difference between this API function and the function
+** SDP_ServiceSearchRequest is that this one does a
+** combined ServiceSearchAttributeRequest SDP function.
+** (This is for Unplug Testing)
+**
+** Returns TRUE if discovery started, FALSE if failed.
+**
+*******************************************************************************/
+BOOLEAN SDP_ServiceSearchAttributeRequest (UINT8 *p_bd_addr, tSDP_DISCOVERY_DB *p_db,
+ tSDP_DISC_CMPL_CB *p_cb)
+{
+#if SDP_CLIENT_ENABLED == TRUE
+ tCONN_CB *p_ccb;
+
+ /* Specific BD address */
+ p_ccb = sdp_conn_originate (p_bd_addr);
+
+ if (!p_ccb)
+ return (FALSE);
+
+ p_ccb->disc_state = SDP_DISC_WAIT_CONN;
+ p_ccb->p_db = p_db;
+ p_ccb->p_cb = p_cb;
+
+ p_ccb->is_attr_search = TRUE;
+
+ return (TRUE);
+#else
+ return (FALSE);
+#endif
+}
+
+#if SDP_CLIENT_ENABLED == TRUE
+void SDP_SetIdleTimeout (BD_ADDR addr, UINT16 timeout)
+{
+}
+#endif
+
+/*******************************************************************************
+**
+** Function SDP_FindAttributeInDb
+**
+** Description This function queries an SDP database for a specific attribute.
+** If the p_start_rec pointer is NULL, it looks from the beginning
+** of the database, else it continues from the next record after
+** p_start_rec.
+**
+** Returns Pointer to matching record, or NULL
+**
+*******************************************************************************/
+tSDP_DISC_REC *SDP_FindAttributeInDb (tSDP_DISCOVERY_DB *p_db, UINT16 attr_id,
+ tSDP_DISC_REC *p_start_rec)
+{
+#if SDP_CLIENT_ENABLED == TRUE
+ tSDP_DISC_REC *p_rec;
+ tSDP_DISC_ATTR *p_attr;
+
+ /* Must have a valid database */
+ if (p_db == NULL)
+ return (NULL);
+
+ if (!p_start_rec)
+ p_rec = p_db->p_first_rec;
+ else
+ p_rec = p_start_rec->p_next_rec;
+
+ while (p_rec)
+ {
+ p_attr = p_rec->p_first_attr;
+ while (p_attr)
+ {
+ if (p_attr->attr_id == attr_id)
+ return (p_rec);
+
+ p_attr = p_attr->p_next_attr;
+ }
+
+ p_rec = p_rec->p_next_rec;
+ }
+#endif
+ /* If here, no matching attribute found */
+ return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function SDP_FindAttributeInRec
+**
+** Description This function searches an SDP discovery record for a specific
+** attribute.
+**
+** Returns Pointer to matching attribute entry, or NULL
+**
+*******************************************************************************/
+tSDP_DISC_ATTR *SDP_FindAttributeInRec (tSDP_DISC_REC *p_rec, UINT16 attr_id)
+{
+#if SDP_CLIENT_ENABLED == TRUE
+ tSDP_DISC_ATTR *p_attr;
+
+ p_attr = p_rec->p_first_attr;
+ while (p_attr)
+ {
+ if (p_attr->attr_id == attr_id)
+ return (p_attr);
+
+ p_attr = p_attr->p_next_attr;
+ }
+#endif
+ /* If here, no matching attribute found */
+ return (NULL);
+}
+
+/*******************************************************************************
+**
+** Function SDP_FindServiceUUIDInRec
+**
+** Description This function is called to read the service UUID within a record
+** if there is any.
+**
+** Parameters: p_rec - pointer to a SDP record.
+** p_uuid - output parameter to save the UUID found.
+**
+** Returns TRUE if found, otherwise FALSE.
+**
+*******************************************************************************/
+BOOLEAN SDP_FindServiceUUIDInRec(tSDP_DISC_REC *p_rec, tBT_UUID * p_uuid)
+{
+#if SDP_CLIENT_ENABLED == TRUE
+ tSDP_DISC_ATTR *p_attr, *p_sattr, *p_extra_sattr;
+
+ p_attr = p_rec->p_first_attr;
+
+ while (p_attr)
+ {
+ if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST)
+ && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE))
+ {
+ for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr)
+ {
+ if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE)
+ {
+ /* only support 16 bits UUID for now */
+ if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2)
+ {
+ p_uuid->len = 2;
+ p_uuid->uu.uuid16 = p_sattr->attr_value.v.u16;
+ }
+ return (TRUE);
+ }
+
+ /* Checking for Toyota G Block Car Kit:
+ ** This car kit puts an extra data element sequence
+ ** where the UUID is suppose to be!!!
+ */
+ else
+ {
+ if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)
+ {
+ /* Look through data element sequence until no more UUIDs */
+ for (p_extra_sattr = p_sattr->attr_value.v.p_sub_attr; p_extra_sattr; p_extra_sattr = p_extra_sattr->p_next_attr)
+ {
+ /* Increment past this to see if the next attribut is UUID */
+ if ((SDP_DISC_ATTR_TYPE(p_extra_sattr->attr_len_type) == UUID_DESC_TYPE)
+ /* only support 16 bits UUID for now */
+ && (SDP_DISC_ATTR_LEN(p_extra_sattr->attr_len_type) == 2))
+ {
+ p_uuid->len = 2;
+ p_uuid->uu.uuid16 = p_extra_sattr->attr_value.v.u16;
+ return (TRUE);
+ }
+ }
+ }
+ }
+ }
+ break;
+ }
+ else if (p_attr->attr_id == ATTR_ID_SERVICE_ID)
+ {
+ if ((SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE)
+ /* only support 16 bits UUID for now */
+ && (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == 2))
+ {
+ p_uuid->len = 2;
+ p_uuid->uu.uuid16 = p_attr->attr_value.v.u16;
+ return (TRUE);
+ }
+ }
+ p_attr = p_attr->p_next_attr;
+ }
+ return FALSE;
+#endif
+}
+
+/*******************************************************************************
+**
+** Function SDP_FindServiceInDb
+**
+** Description This function queries an SDP database for a specific service.
+** If the p_start_rec pointer is NULL, it looks from the beginning
+** of the database, else it continues from the next record after
+** p_start_rec.
+**
+** Returns Pointer to record containing service class, or NULL
+**
+*******************************************************************************/
+tSDP_DISC_REC *SDP_FindServiceInDb (tSDP_DISCOVERY_DB *p_db, UINT16 service_uuid, tSDP_DISC_REC *p_start_rec)
+{
+#if SDP_CLIENT_ENABLED == TRUE
+ tSDP_DISC_REC *p_rec;
+ tSDP_DISC_ATTR *p_attr, *p_sattr, *p_extra_sattr;
+
+ /* Must have a valid database */
+ if (p_db == NULL)
+ return (NULL);
+
+ if (!p_start_rec)
+ p_rec = p_db->p_first_rec;
+ else
+ p_rec = p_start_rec->p_next_rec;
+
+ while (p_rec)
+ {
+ p_attr = p_rec->p_first_attr;
+ while (p_attr)
+ {
+ if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST)
+ && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE))
+ {
+ for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr)
+ {
+ if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE)
+ && (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2)
+ /* for a specific uuid, or any one */
+ && ((p_sattr->attr_value.v.u16 == service_uuid) || service_uuid == 0))
+ {
+ return (p_rec);
+ }
+
+ /* Checking for Toyota G Block Car Kit:
+ ** This car kit puts an extra data element sequence
+ ** where the UUID is suppose to be!!!
+ */
+ else
+ {
+ if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)
+ {
+ /* Look through data element sequence until no more UUIDs */
+ for (p_extra_sattr = p_sattr->attr_value.v.p_sub_attr; p_extra_sattr; p_extra_sattr = p_extra_sattr->p_next_attr)
+ {
+ /* Increment past this to see if the next attribut is UUID */
+ if ((SDP_DISC_ATTR_TYPE(p_extra_sattr->attr_len_type) == UUID_DESC_TYPE)
+ && (SDP_DISC_ATTR_LEN(p_extra_sattr->attr_len_type) == 2)
+ /* for a specific uuid, or any one */
+ && ((p_extra_sattr->attr_value.v.u16 == service_uuid) || (service_uuid == 0)))
+ {
+ return (p_rec);
+ }
+ }
+ }
+ }
+ }
+ break;
+ }
+ else if (p_attr->attr_id == ATTR_ID_SERVICE_ID)
+ {
+ if ((SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE)
+ && (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == 2)
+ /* find a specific UUID or anyone */
+ && ((p_attr->attr_value.v.u16 == service_uuid) || service_uuid == 0))
+ return (p_rec);
+ }
+
+ p_attr = p_attr->p_next_attr;
+ }
+
+ p_rec = p_rec->p_next_rec;
+ }
+#endif
+ /* If here, no matching UUID found */
+ return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function SDP_FindServiceUUIDInDb
+**
+** Description This function queries an SDP database for a specific service.
+** If the p_start_rec pointer is NULL, it looks from the beginning
+** of the database, else it continues from the next record after
+** p_start_rec.
+**
+** NOTE the only difference between this function and the previous function
+** "SDP_FindServiceInDb()" is that this function takes a tBT_UUID input
+**
+** Returns Pointer to record containing service class, or NULL
+**
+*******************************************************************************/
+tSDP_DISC_REC *SDP_FindServiceUUIDInDb (tSDP_DISCOVERY_DB *p_db, tBT_UUID *p_uuid, tSDP_DISC_REC *p_start_rec)
+{
+#if SDP_CLIENT_ENABLED == TRUE
+ tSDP_DISC_REC *p_rec;
+ tSDP_DISC_ATTR *p_attr, *p_sattr;
+
+ /* Must have a valid database */
+ if (p_db == NULL)
+ return (NULL);
+
+ if (!p_start_rec)
+ p_rec = p_db->p_first_rec;
+ else
+ p_rec = p_start_rec->p_next_rec;
+
+ while (p_rec)
+ {
+ p_attr = p_rec->p_first_attr;
+ while (p_attr)
+ {
+ if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST)
+ && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE))
+ {
+ for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr)
+ {
+ if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE)
+ {
+ if (sdpu_compare_uuid_with_attr (p_uuid, p_sattr))
+ return (p_rec);
+ }
+ }
+ break;
+ }
+ else if (p_attr->attr_id == ATTR_ID_SERVICE_ID)
+ {
+ if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE )
+ {
+ if (sdpu_compare_uuid_with_attr (p_uuid, p_attr))
+ return (p_rec);
+ }
+ }
+
+ p_attr = p_attr->p_next_attr;
+ }
+
+ p_rec = p_rec->p_next_rec;
+ }
+#endif /* CLIENT_ENABLED == TRUE */
+ /* If here, no matching UUID found */
+ return (NULL);
+}
+
+#if SDP_CLIENT_ENABLED == TRUE
+/*******************************************************************************
+**
+** Function sdp_fill_proto_elem
+**
+** Description This function retrieves the protocol element.
+**
+** Returns TRUE if found, FALSE if not
+** If found, the passed protocol list element is filled in.
+**
+*******************************************************************************/
+static BOOLEAN sdp_fill_proto_elem( tSDP_DISC_ATTR *p_attr, UINT16 layer_uuid,
+ tSDP_PROTOCOL_ELEM *p_elem)
+{
+ tSDP_DISC_ATTR *p_sattr;
+
+ /* Walk through the protocol descriptor list */
+ for (p_attr = p_attr->attr_value.v.p_sub_attr; p_attr; p_attr = p_attr->p_next_attr)
+ {
+ /* Safety check - each entry should itself be a sequence */
+ if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) != DATA_ELE_SEQ_DESC_TYPE)
+ return (FALSE);
+
+ /* Now, see if the entry contains the layer we are interested in */
+ for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr)
+ {
+ /* SDP_TRACE_DEBUG3 ("SDP - p_sattr 0x%x, layer_uuid:0x%x, u16:0x%x####",
+ p_sattr, layer_uuid, p_sattr->attr_value.v.u16); */
+
+ if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE)
+ && (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2)
+ && (p_sattr->attr_value.v.u16 == layer_uuid))
+ {
+ /* Bingo. Now fill in the passed element */
+ p_elem->protocol_uuid = layer_uuid;
+ p_elem->num_params = 0;
+
+ /* Store the parameters, if any */
+ for (p_sattr = p_sattr->p_next_attr; p_sattr; p_sattr = p_sattr->p_next_attr)
+ {
+ if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) != UINT_DESC_TYPE)
+ break;
+
+ if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2)
+ p_elem->params[p_elem->num_params++] = p_sattr->attr_value.v.u16;
+ else
+ p_elem->params[p_elem->num_params++] = p_sattr->attr_value.v.u8;
+
+ if (p_elem->num_params >= SDP_MAX_PROTOCOL_PARAMS)
+ break;
+ }
+ return (TRUE);
+ }
+ }
+ }
+
+ return (FALSE);
+}
+#endif /* CLIENT_ENABLED == TRUE */
+
+/*******************************************************************************
+**
+** Function SDP_FindProtocolListElemInRec
+**
+** Description This function looks at a specific discovery record for a protocol
+** list element.
+**
+** Returns TRUE if found, FALSE if not
+** If found, the passed protocol list element is filled in.
+**
+*******************************************************************************/
+BOOLEAN SDP_FindProtocolListElemInRec (tSDP_DISC_REC *p_rec, UINT16 layer_uuid, tSDP_PROTOCOL_ELEM *p_elem)
+{
+#if SDP_CLIENT_ENABLED == TRUE
+ tSDP_DISC_ATTR *p_attr;
+
+ p_attr = p_rec->p_first_attr;
+ while (p_attr)
+ {
+ /* Find the protocol descriptor list */
+ if ((p_attr->attr_id == ATTR_ID_PROTOCOL_DESC_LIST)
+ && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE))
+ {
+ return sdp_fill_proto_elem(p_attr, layer_uuid, p_elem);
+ }
+ p_attr = p_attr->p_next_attr;
+ }
+#endif
+ /* If here, no match found */
+ return (FALSE);
+}
+
+
+/*******************************************************************************
+**
+** Function SDP_FindAddProtoListsElemInRec
+**
+** Description This function looks at a specific discovery record for a protocol
+** list element.
+**
+** Returns TRUE if found, FALSE if not
+** If found, the passed protocol list element is filled in.
+**
+*******************************************************************************/
+BOOLEAN SDP_FindAddProtoListsElemInRec (tSDP_DISC_REC *p_rec, UINT16 layer_uuid, tSDP_PROTOCOL_ELEM *p_elem)
+{
+#if SDP_CLIENT_ENABLED == TRUE
+ tSDP_DISC_ATTR *p_attr, *p_sattr;
+ BOOLEAN ret = FALSE;
+
+ p_attr = p_rec->p_first_attr;
+ while (p_attr)
+ {
+ /* Find the additional protocol descriptor list attribute */
+ if ((p_attr->attr_id == ATTR_ID_ADDITION_PROTO_DESC_LISTS)
+ && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE))
+ {
+ for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr)
+ {
+ /* Safety check - each entry should itself be a sequence */
+ if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)
+ {
+ if( (ret = sdp_fill_proto_elem(p_sattr, layer_uuid, p_elem)) == TRUE)
+ break;
+ }
+ }
+ return ret;
+ }
+ p_attr = p_attr->p_next_attr;
+ }
+#endif
+ /* If here, no match found */
+ return (FALSE);
+}
+
+
+/*******************************************************************************
+**
+** Function SDP_FindProfileVersionInRec
+**
+** Description This function looks at a specific discovery record for the
+** Profile list descriptor, and pulls out the version number.
+** The version number consists of an 8-bit major version and
+** an 8-bit minor version.
+**
+** Returns TRUE if found, FALSE if not
+** If found, the major and minor version numbers that were passed
+** in are filled in.
+**
+*******************************************************************************/
+BOOLEAN SDP_FindProfileVersionInRec (tSDP_DISC_REC *p_rec, UINT16 profile_uuid, UINT16 *p_version)
+{
+#if SDP_CLIENT_ENABLED == TRUE
+ tSDP_DISC_ATTR *p_attr, *p_sattr;
+
+ p_attr = p_rec->p_first_attr;
+ while (p_attr)
+ {
+ /* Find the profile descriptor list */
+ if ((p_attr->attr_id == ATTR_ID_BT_PROFILE_DESC_LIST)
+ && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE))
+ {
+ /* Walk through the protocol descriptor list */
+ for (p_attr = p_attr->attr_value.v.p_sub_attr; p_attr; p_attr = p_attr->p_next_attr)
+ {
+ /* Safety check - each entry should itself be a sequence */
+ if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) != DATA_ELE_SEQ_DESC_TYPE)
+ return (FALSE);
+
+ /* Now, see if the entry contains the profile UUID we are interested in */
+ for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr)
+ {
+ if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE)
+ && (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2) /* <- This is bytes, not size code! */
+ && (p_sattr->attr_value.v.u16 == profile_uuid))
+ {
+ /* Now fill in the major and minor numbers */
+ /* if the attribute matches the description for version (type UINT, size 2 bytes) */
+ p_sattr = p_sattr->p_next_attr;
+
+ if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UINT_DESC_TYPE) &&
+ (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2))
+ {
+ /* The high order 8 bits is the major number, low order is the minor number (big endian) */
+ *p_version = p_sattr->attr_value.v.u16;
+
+ return (TRUE);
+ }
+ else
+ return (FALSE); /* The type and/or size was not valid for the profile list version */
+ }
+ }
+ }
+
+ return (FALSE);
+ }
+ p_attr = p_attr->p_next_attr;
+ }
+#endif /* CLIENT_ENABLED == TRUE */
+
+ /* If here, no match found */
+ return (FALSE);
+}
+
+/*******************************************************************************
+** Device Identification (DI) Client Functions
+*******************************************************************************/
+
+/*******************************************************************************
+**
+** Function SDP_DiDiscover
+**
+** Description This function queries a remote device for DI information.
+**
+** Returns SDP_SUCCESS if query started successfully, else error
+**
+*******************************************************************************/
+UINT16 SDP_DiDiscover( BD_ADDR remote_device, tSDP_DISCOVERY_DB *p_db,
+ UINT32 len, tSDP_DISC_CMPL_CB *p_cb )
+{
+#if SDP_CLIENT_ENABLED == TRUE
+ UINT16 result = SDP_DI_DISC_FAILED;
+ UINT16 num_uuids = 1;
+ UINT16 di_uuid = UUID_SERVCLASS_PNP_INFORMATION;
+
+ /* build uuid for db init */
+ tSDP_UUID init_uuid;
+ init_uuid.len = 2;
+ init_uuid.uu.uuid16 = di_uuid;
+
+ if( SDP_InitDiscoveryDb(p_db, len, num_uuids, &init_uuid, 0, NULL) )
+ if( SDP_ServiceSearchRequest(remote_device, p_db, p_cb) )
+ result = SDP_SUCCESS;
+
+ return result;
+#else
+ return SDP_DI_DISC_FAILED;
+#endif
+}
+
+/*******************************************************************************
+**
+** Function SDP_GetNumDiRecords
+**
+** Description Searches specified database for DI records
+**
+** Returns number of DI records found
+**
+*******************************************************************************/
+UINT8 SDP_GetNumDiRecords( tSDP_DISCOVERY_DB *p_db )
+{
+#if SDP_CLIENT_ENABLED == TRUE
+ UINT8 num_records = 0;
+ tSDP_DISC_REC *p_curr_record = NULL;
+
+ do
+ {
+ p_curr_record = SDP_FindServiceInDb( p_db, UUID_SERVCLASS_PNP_INFORMATION,
+ p_curr_record );
+ if( p_curr_record )
+ num_records++;
+ }while( p_curr_record );
+
+ return num_records;
+#else
+ return 0;
+#endif
+}
+
+/*******************************************************************************
+**
+** Function SDP_GetDiRecord
+**
+** Description This function retrieves a remote device's DI record from
+** the specified database.
+**
+** Returns SDP_SUCCESS if record retrieved, else error
+**
+*******************************************************************************/
+UINT16 SDP_GetDiRecord( UINT8 get_record_index, tSDP_DI_GET_RECORD *p_device_info,
+ tSDP_DISCOVERY_DB *p_db )
+{
+#if SDP_CLIENT_ENABLED == TRUE
+ UINT16 result = SDP_NO_DI_RECORD_FOUND;
+ UINT8 curr_record_index = 1;
+
+ tSDP_DISC_REC *p_curr_record = NULL;
+
+ /* find the requested SDP record in the discovery database */
+ do
+ {
+ p_curr_record = SDP_FindServiceInDb( p_db, UUID_SERVCLASS_PNP_INFORMATION,
+ p_curr_record );
+ if( p_curr_record )
+ {
+ if( curr_record_index++ == get_record_index )
+ {
+ result = SDP_SUCCESS;
+ break;
+ }
+ }
+ }while( p_curr_record );
+
+ if( result == SDP_SUCCESS )
+ {
+ /* copy the information from the SDP record to the DI record */
+ tSDP_DISC_ATTR *p_curr_attr = NULL;
+
+ /* ClientExecutableURL is optional */
+ p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_CLIENT_EXE_URL );
+ if( p_curr_attr )
+ BCM_STRNCPY_S( p_device_info->rec.client_executable_url, sizeof(p_device_info->rec.client_executable_url),
+ (char *)p_curr_attr->attr_value.v.array, SDP_MAX_ATTR_LEN );
+ else
+ p_device_info->rec.client_executable_url[0] = '\0';
+
+ /* Service Description is optional */
+ p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_SERVICE_DESCRIPTION );
+ if( p_curr_attr )
+ BCM_STRNCPY_S( p_device_info->rec.service_description, sizeof(p_device_info->rec.service_description),
+ (char *)p_curr_attr->attr_value.v.array, SDP_MAX_ATTR_LEN );
+ else
+ p_device_info->rec.service_description[0] = '\0';
+
+ /* DocumentationURL is optional */
+ p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_DOCUMENTATION_URL );
+ if( p_curr_attr )
+ BCM_STRNCPY_S( p_device_info->rec.documentation_url, sizeof(p_device_info->rec.documentation_url),
+ (char *)p_curr_attr->attr_value.v.array, SDP_MAX_ATTR_LEN );
+ else
+ p_device_info->rec.documentation_url[0] = '\0';
+
+ p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_SPECIFICATION_ID );
+ if( p_curr_attr )
+ p_device_info->spec_id = p_curr_attr->attr_value.v.u16;
+ else
+ result = SDP_ERR_ATTR_NOT_PRESENT;
+
+ p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_VENDOR_ID );
+ if( p_curr_attr )
+ p_device_info->rec.vendor = p_curr_attr->attr_value.v.u16;
+ else
+ result = SDP_ERR_ATTR_NOT_PRESENT;
+
+ p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_VENDOR_ID_SOURCE );
+ if( p_curr_attr )
+ p_device_info->rec.vendor_id_source = p_curr_attr->attr_value.v.u16;
+ else
+ result = SDP_ERR_ATTR_NOT_PRESENT;
+
+ p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_PRODUCT_ID );
+ if( p_curr_attr )
+ p_device_info->rec.product = p_curr_attr->attr_value.v.u16;
+ else
+ result = SDP_ERR_ATTR_NOT_PRESENT;
+
+ p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_PRODUCT_VERSION );
+ if( p_curr_attr )
+ p_device_info->rec.version = p_curr_attr->attr_value.v.u16;
+ else
+ result = SDP_ERR_ATTR_NOT_PRESENT;
+
+ p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_PRIMARY_RECORD );
+ if( p_curr_attr )
+ p_device_info->rec.primary_record = (BOOLEAN)p_curr_attr->attr_value.v.u8;
+ else
+ result = SDP_ERR_ATTR_NOT_PRESENT;
+ }
+
+ return result;
+#else /* SDP_CLIENT_ENABLED is FALSE */
+ return SDP_NO_DI_RECORD_FOUND;
+#endif
+}
+
+/*******************************************************************************
+** Device Identification (DI) Server Functions
+*******************************************************************************/
+
+/*******************************************************************************
+**
+** Function SDP_SetLocalDiRecord
+**
+** Description This function adds a DI record to the local SDP database.
+**
+**
+**
+** Returns Returns SDP_SUCCESS if record added successfully, else error
+**
+*******************************************************************************/
+UINT16 SDP_SetLocalDiRecord( tSDP_DI_RECORD *p_device_info, UINT32 *p_handle )
+{
+#if SDP_SERVER_ENABLED == TRUE
+ UINT16 result = SDP_SUCCESS;
+ UINT32 handle;
+ UINT16 di_uuid = UUID_SERVCLASS_PNP_INFORMATION;
+ UINT16 di_specid = BLUETOOTH_DI_SPECIFICATION;
+ UINT8 temp_u16[2];
+ UINT8 *p_temp;
+ UINT8 u8;
+
+ *p_handle = 0;
+ if( p_device_info == NULL )
+ return SDP_ILLEGAL_PARAMETER;
+
+ /* if record is to be primary record, get handle to replace old primary */
+ if( p_device_info->primary_record == TRUE && sdp_cb.server_db.di_primary_handle )
+ handle = sdp_cb.server_db.di_primary_handle;
+ else
+ {
+ if( (handle = SDP_CreateRecord()) == 0 )
+ return SDP_NO_RESOURCES;
+ }
+
+ *p_handle = handle;
+
+ /* build the SDP entry */
+ /* Add the UUID to the Service Class ID List */
+ if ((SDP_AddServiceClassIdList(handle, 1, &di_uuid)) == FALSE)
+ result = SDP_DI_REG_FAILED;
+
+ /* mandatory */
+ if ( result == SDP_SUCCESS)
+ {
+ p_temp = temp_u16;
+ UINT16_TO_BE_STREAM(p_temp, di_specid);
+ if( !(SDP_AddAttribute(handle, ATTR_ID_SPECIFICATION_ID,
+ UINT_DESC_TYPE, sizeof(di_specid),
+ temp_u16)) )
+ result = SDP_DI_REG_FAILED;
+ }
+
+ /* optional - if string is null, do not add attribute */
+ if( result == SDP_SUCCESS )
+ {
+ if( p_device_info->client_executable_url[0] != '\0' )
+ {
+ if( !((strlen(p_device_info->client_executable_url)+1 <= SDP_MAX_ATTR_LEN) &&
+ SDP_AddAttribute(handle, ATTR_ID_CLIENT_EXE_URL, URL_DESC_TYPE,
+ (UINT32)(strlen(p_device_info->client_executable_url)+1),
+ (UINT8 *)p_device_info->client_executable_url)) )
+ result = SDP_DI_REG_FAILED;
+ }
+ }
+
+ /* optional - if string is null, do not add attribute */
+ if( result == SDP_SUCCESS )
+ {
+ if( p_device_info->service_description[0] != '\0' )
+ {
+ if ( !((strlen(p_device_info->service_description)+1 <= SDP_MAX_ATTR_LEN) &&
+ SDP_AddAttribute(handle, ATTR_ID_SERVICE_DESCRIPTION,
+ TEXT_STR_DESC_TYPE,
+ (UINT32)(strlen(p_device_info->service_description)+1),
+ (UINT8 *)p_device_info->service_description)) )
+ result = SDP_DI_REG_FAILED;
+ }
+ }
+
+ /* optional - if string is null, do not add attribute */
+ if( result == SDP_SUCCESS )
+ {
+ if( p_device_info->documentation_url[0] != '\0' )
+ {
+ if( !((strlen(p_device_info->documentation_url)+1 <= SDP_MAX_ATTR_LEN) &&
+ SDP_AddAttribute(handle, ATTR_ID_DOCUMENTATION_URL, URL_DESC_TYPE,
+ (UINT32)(strlen(p_device_info->documentation_url)+1),
+ (UINT8 *)p_device_info->documentation_url)) )
+ result = SDP_DI_REG_FAILED;
+ }
+ }
+
+ /* mandatory */
+ if ( result == SDP_SUCCESS)
+ {
+ p_temp = temp_u16;
+ UINT16_TO_BE_STREAM(p_temp, p_device_info->vendor);
+ if ( !(SDP_AddAttribute(handle, ATTR_ID_VENDOR_ID, UINT_DESC_TYPE,
+ sizeof(p_device_info->vendor), temp_u16)) )
+ result = SDP_DI_REG_FAILED;
+ }
+
+ /* mandatory */
+ if ( result == SDP_SUCCESS)
+ {
+ p_temp = temp_u16;
+ UINT16_TO_BE_STREAM (p_temp, p_device_info->product);
+ if( !(SDP_AddAttribute(handle, ATTR_ID_PRODUCT_ID,
+ UINT_DESC_TYPE, sizeof(p_device_info->product), temp_u16)) )
+ result = SDP_DI_REG_FAILED;
+ }
+
+ /* mandatory */
+ if ( result == SDP_SUCCESS)
+ {
+ p_temp = temp_u16;
+ UINT16_TO_BE_STREAM (p_temp, p_device_info->version);
+ if( !(SDP_AddAttribute(handle, ATTR_ID_PRODUCT_VERSION, UINT_DESC_TYPE,
+ sizeof(p_device_info->version), temp_u16)) )
+ result = SDP_DI_REG_FAILED;
+ }
+
+ /* mandatory */
+ if ( result == SDP_SUCCESS)
+ {
+ u8 = (UINT8)p_device_info->primary_record;
+ if( !(SDP_AddAttribute(handle, ATTR_ID_PRIMARY_RECORD,
+ BOOLEAN_DESC_TYPE, 1, &u8)) )
+ result = SDP_DI_REG_FAILED;
+ }
+
+ /* mandatory */
+ if ( result == SDP_SUCCESS)
+ {
+ p_temp = temp_u16;
+ UINT16_TO_BE_STREAM(p_temp, p_device_info->vendor_id_source);
+ if ( !(SDP_AddAttribute(handle, ATTR_ID_VENDOR_ID_SOURCE, UINT_DESC_TYPE,
+ sizeof(p_device_info->vendor_id_source), temp_u16)) )
+ result = SDP_DI_REG_FAILED;
+ }
+
+ if( result != SDP_SUCCESS )
+ SDP_DeleteRecord( handle );
+ else if (p_device_info->primary_record == TRUE)
+ sdp_cb.server_db.di_primary_handle = handle;
+
+ return result;
+#else /* SDP_SERVER_ENABLED is FALSE */
+ return SDP_DI_REG_FAILED;
+#endif /* if SDP_SERVER_ENABLED */
+}
+
+/*******************************************************************************
+**
+** Function SDP_GetLocalDiRecord
+**
+** Description This function adds a DI record to the local SDP database.
+**
+** Fills in the device information of the record
+** p_handle - if p_handle == 0, the primary record is returned
+**
+** Returns Returns SDP_SUCCESS if record exists, else error
+**
+*******************************************************************************/
+UINT16 SDP_GetLocalDiRecord(tSDP_DI_GET_RECORD *p_device_info, UINT32 *p_handle )
+{
+ UINT16 result = SDP_NO_DI_RECORD_FOUND;
+
+#if SDP_SERVER_ENABLED == TRUE
+ tSDP_RECORD *p_rec;
+ tSDP_ATTRIBUTE *p_attr;
+ UINT8 *p_temp;
+ INT32 templen;
+
+ if (*p_handle == 0)
+ *p_handle = sdp_cb.server_db.di_primary_handle;
+
+ if ((p_rec = sdp_db_find_record(*p_handle)) != NULL)
+ {
+ memset(p_device_info, 0, sizeof(tSDP_DI_RECORD));
+
+ result = SDP_SUCCESS;
+
+ /* Retrieve the Specification ID */
+ if ((p_attr = sdp_db_find_attr_in_rec(p_rec, ATTR_ID_SPECIFICATION_ID,
+ ATTR_ID_SPECIFICATION_ID)) != NULL)
+ {
+ p_temp = p_attr->value_ptr;
+ BE_STREAM_TO_UINT16 (p_device_info->spec_id, p_temp);
+ }
+
+ /* Retrieve the Vendor ID */
+ if ((p_attr = sdp_db_find_attr_in_rec(p_rec, ATTR_ID_VENDOR_ID,
+ ATTR_ID_VENDOR_ID)) != NULL)
+ {
+ p_temp = p_attr->value_ptr;
+ BE_STREAM_TO_UINT16 (p_device_info->rec.vendor, p_temp);
+ }
+
+ /* Retrieve the Product ID */
+ if ((p_attr = sdp_db_find_attr_in_rec(p_rec, ATTR_ID_PRODUCT_ID,
+ ATTR_ID_PRODUCT_ID)) != NULL)
+ {
+ p_temp = p_attr->value_ptr;
+ BE_STREAM_TO_UINT16 (p_device_info->rec.product, p_temp);
+ }
+
+ /* Retrieve the Version ID */
+ if ((p_attr = sdp_db_find_attr_in_rec(p_rec, ATTR_ID_PRODUCT_VERSION,
+ ATTR_ID_PRODUCT_VERSION)) != NULL)
+ {
+ p_temp = p_attr->value_ptr;
+ BE_STREAM_TO_UINT16 (p_device_info->rec.version, p_temp);
+ }
+
+ /* Retrieve the Vendor ID Source ID */
+ if ((p_attr = sdp_db_find_attr_in_rec(p_rec, ATTR_ID_VENDOR_ID_SOURCE,
+ ATTR_ID_VENDOR_ID_SOURCE)) != NULL)
+ {
+ p_temp = p_attr->value_ptr;
+ BE_STREAM_TO_UINT16 (p_device_info->rec.vendor_id_source, p_temp);
+ }
+
+ /* Retrieve the Primary Record */
+ if ((p_attr = sdp_db_find_attr_in_rec(p_rec, ATTR_ID_PRIMARY_RECORD,
+ ATTR_ID_PRIMARY_RECORD)) != NULL)
+ {
+ p_device_info->rec.primary_record = *p_attr->value_ptr;
+ }
+
+ /* Retrieve the Client Executable URL */
+ if ((p_attr = sdp_db_find_attr_in_rec(p_rec, ATTR_ID_CLIENT_EXE_URL,
+ ATTR_ID_CLIENT_EXE_URL)) != NULL)
+ {
+ templen = (INT32)((p_attr->len < SDP_MAX_ATTR_LEN) ? p_attr->len : SDP_MAX_ATTR_LEN);
+ p_temp = p_attr->value_ptr;
+ BE_STREAM_TO_ARRAY (p_temp, p_device_info->rec.client_executable_url, templen);
+ }
+
+ /* Retrieve the Service Description */
+ if ((p_attr = sdp_db_find_attr_in_rec(p_rec, ATTR_ID_SERVICE_DESCRIPTION,
+ ATTR_ID_SERVICE_DESCRIPTION)) != NULL)
+ {
+ templen = (INT32)((p_attr->len < SDP_MAX_ATTR_LEN) ? p_attr->len : SDP_MAX_ATTR_LEN);
+ p_temp = p_attr->value_ptr;
+ BE_STREAM_TO_ARRAY (p_temp, p_device_info->rec.service_description, templen);
+ }
+
+ /* Retrieve the Documentation URL */
+ if ((p_attr = sdp_db_find_attr_in_rec(p_rec, ATTR_ID_DOCUMENTATION_URL,
+ ATTR_ID_DOCUMENTATION_URL)) != NULL)
+ {
+ templen = (INT32)((p_attr->len < SDP_MAX_ATTR_LEN) ? p_attr->len : SDP_MAX_ATTR_LEN);
+ p_temp = p_attr->value_ptr;
+ BE_STREAM_TO_ARRAY (p_temp, p_device_info->rec.documentation_url, templen);
+ }
+ }
+ else
+ *p_handle = 0;
+#endif
+
+ return result;
+}
+
+
+/*******************************************************************************
+**
+** Function SDP_SetTraceLevel
+**
+** Description This function sets the trace level for SDP. If called with
+** a value of 0xFF, it simply reads the current trace level.
+**
+** Returns the new (current) trace level
+**
+*******************************************************************************/
+UINT8 SDP_SetTraceLevel (UINT8 new_level)
+{
+ if (new_level != 0xFF)
+ sdp_cb.trace_level = new_level;
+
+ return (sdp_cb.trace_level);
+}
+
+#if SDP_FOR_JV_INCLUDED == TRUE
+/*******************************************************************************
+**
+** Function SDP_ConnOpen
+**
+** Description This function creates a connection to the SDP server on the
+** given device.
+**
+** Returns 0, if failed to initiate connection. Otherwise, the handle.
+**
+*******************************************************************************/
+UINT32 SDP_ConnOpen (UINT8 *p_bd_addr, tSDP_DISC_RES_CB *p_rcb,
+ tSDP_DISC_CMPL_CB *p_cb)
+{
+#if SDP_CLIENT_ENABLED == TRUE
+ tCONN_CB *p_ccb;
+ UINT32 idx = 0;
+
+ if (!p_cb || !p_rcb)
+ return (idx);
+
+ /* Specific BD address */
+ p_ccb = sdp_conn_originate (p_bd_addr);
+
+ if (!p_ccb)
+ return (idx);
+
+ p_ccb->disc_state = SDP_DISC_WAIT_CONN;
+ p_ccb->p_db = (tSDP_DISCOVERY_DB *)p_rcb;
+ p_ccb->p_cb = p_cb;
+
+ p_ccb->is_attr_search = SDP_IS_PASS_THRU;
+
+ idx = (UINT32)(p_ccb - sdp_cb.ccb);
+ return (UINT32)(idx + 1);
+#else
+ return (0);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function SDP_WriteData
+**
+** Description This function sends data to the connected SDP server.
+**
+** Returns TRUE if data is sent, FALSE if failed.
+**
+*******************************************************************************/
+BOOLEAN SDP_WriteData (UINT32 handle, BT_HDR *p_msg)
+{
+#if SDP_CLIENT_ENABLED == TRUE
+ tCONN_CB *p_ccb = NULL;
+
+ if(p_msg && (handle > 0) && (handle <= SDP_MAX_CONNECTIONS) )
+ {
+ p_ccb = &sdp_cb.ccb[handle - 1];
+ if( (p_ccb->con_state == SDP_STATE_CONNECTED) &&
+ (p_ccb->con_flags & SDP_FLAGS_IS_ORIG) )
+ {
+ /* Start inactivity timer */
+ btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_SDP, SDP_INACT_TIMEOUT);
+ L2CA_DataWrite (p_ccb->connection_id, p_msg);
+ return TRUE;
+ }
+ }
+#endif
+ return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function SDP_ConnClose
+**
+** Description This function is called to close a SDP connection.
+**
+** Parameters: handle - Handle of the connection returned by SDP_ConnOpen
+**
+** Returns TRUE if connection is closed, FALSE if failed to find the handle.
+**
+*******************************************************************************/
+BOOLEAN SDP_ConnClose (UINT32 handle)
+{
+#if SDP_CLIENT_ENABLED == TRUE
+ tCONN_CB *p_ccb = NULL;
+
+ if(handle > 0 && handle <= SDP_MAX_CONNECTIONS)
+ {
+ p_ccb = &sdp_cb.ccb[handle - 1];
+ sdp_disconnect (p_ccb, SDP_SUCCESS);
+ return TRUE;
+ }
+#endif
+ return FALSE;
+}
+#endif
diff --git a/stack/sdp/sdp_db.c b/stack/sdp/sdp_db.c
new file mode 100644
index 0000000..e9a35fc
--- /dev/null
+++ b/stack/sdp/sdp_db.c
@@ -0,0 +1,948 @@
+/*****************************************************************************
+** *
+** Name: sdp_db.c *
+** *
+** Description: this file contains functions that handle the database *
+** *
+** Copyright (c) 1999-2009, Broadcom Corp., All Rights Reserved. *
+** WIDCOMM Bluetooth Core. Proprietary and confidential. *
+******************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "bt_target.h"
+
+#include "gki.h"
+
+#include "l2cdefs.h"
+#include "hcidefs.h"
+#include "hcimsgs.h"
+
+#include "sdp_api.h"
+#include "sdpint.h"
+#include "wbt_api.h"
+
+#if SDP_SERVER_ENABLED == TRUE
+/********************************************************************************/
+/* L O C A L F U N C T I O N P R O T O T Y P E S */
+/********************************************************************************/
+static BOOLEAN find_uuid_in_seq (UINT8 *p , UINT32 seq_len, UINT8 *p_his_uuid,
+ UINT16 his_len, int nest_level);
+
+
+/*******************************************************************************
+**
+** Function sdp_db_service_search
+**
+** Description This function searches for a record that contains the
+** specified UIDs. It is passed either NULL to start at the
+** beginning, or the previous record found.
+**
+** Returns Pointer to the record, or NULL if not found.
+**
+*******************************************************************************/
+tSDP_RECORD *sdp_db_service_search (tSDP_RECORD *p_rec, tSDP_UUID_SEQ *p_seq)
+{
+ UINT16 xx, yy;
+ tSDP_ATTRIBUTE *p_attr;
+ tSDP_RECORD *p_end = &sdp_cb.server_db.record[sdp_cb.server_db.num_records];
+
+ /* If NULL, start at the beginning, else start at the first specified record */
+ if (!p_rec)
+ p_rec = &sdp_cb.server_db.record[0];
+ else
+ p_rec++;
+
+ /* Look through the records. The spec says that a match occurs if */
+ /* the record contains all the passed UUIDs in it. */
+ for ( ; p_rec < p_end; p_rec++)
+ {
+ for (yy = 0; yy < p_seq->num_uids; yy++)
+ {
+ p_attr = &p_rec->attribute[0];
+ for (xx = 0; xx < p_rec->num_attributes; xx++, p_attr++)
+ {
+ if (p_attr->type == UUID_DESC_TYPE)
+ {
+ if (sdpu_compare_uuid_arrays (p_attr->value_ptr, p_attr->len,
+ &p_seq->uuid_entry[yy].value[0],
+ p_seq->uuid_entry[yy].len))
+ break;
+ }
+ else if (p_attr->type == DATA_ELE_SEQ_DESC_TYPE)
+ {
+ if (find_uuid_in_seq (p_attr->value_ptr, p_attr->len,
+ &p_seq->uuid_entry[yy].value[0],
+ p_seq->uuid_entry[yy].len, 0))
+ break;
+ }
+ }
+ /* If any UUID was not found, on to the next record */
+ if (xx == p_rec->num_attributes)
+ break;
+ }
+
+ /* If every UUID was found in the record, return the record */
+ if (yy == p_seq->num_uids)
+ return (p_rec);
+ }
+
+ /* If here, no more records found */
+ return (NULL);
+}
+
+/*******************************************************************************
+**
+** Function find_uuid_in_seq
+**
+** Description This function searches a data element sequenct for a UUID.
+**
+** Returns TRUE if found, else FALSE
+**
+*******************************************************************************/
+static BOOLEAN find_uuid_in_seq (UINT8 *p , UINT32 seq_len, UINT8 *p_uuid,
+ UINT16 uuid_len, int nest_level)
+{
+ UINT8 *p_end = p + seq_len;
+ UINT8 type;
+ UINT32 len;
+
+ /* A little safety check to avoid excessive recursion */
+ if (nest_level > 3)
+ return (FALSE);
+
+ while (p < p_end)
+ {
+ type = *p++;
+ p = sdpu_get_len_from_type (p, type, &len);
+ type = type >> 3;
+ if (type == UUID_DESC_TYPE)
+ {
+ if (sdpu_compare_uuid_arrays (p, len, p_uuid, uuid_len))
+ return (TRUE);
+ }
+ else if (type == DATA_ELE_SEQ_DESC_TYPE)
+ {
+ if (find_uuid_in_seq (p, len, p_uuid, uuid_len, nest_level + 1))
+ return (TRUE);
+ }
+ p = p + len;
+ }
+
+ /* If here, failed to match */
+ return (FALSE);
+}
+
+/*******************************************************************************
+**
+** Function sdp_db_find_record
+**
+** Description This function searches for a record with a specific handle
+** It is passed the handle of the record.
+**
+** Returns Pointer to the record, or NULL if not found.
+**
+*******************************************************************************/
+tSDP_RECORD *sdp_db_find_record (UINT32 handle)
+{
+ tSDP_RECORD *p_rec;
+ tSDP_RECORD *p_end = &sdp_cb.server_db.record[sdp_cb.server_db.num_records];
+
+ /* Look through the records for the caller's handle */
+ for (p_rec = &sdp_cb.server_db.record[0]; p_rec < p_end; p_rec++)
+ {
+ if (p_rec->record_handle == handle)
+ return (p_rec);
+ }
+
+ /* Record with that handle not found. */
+ return (NULL);
+}
+
+/*******************************************************************************
+**
+** Function sdp_db_find_attr_in_rec
+**
+** Description This function searches a record for specific attributes.
+** It is passed a pointer to the record. If the record contains
+** the specified attribute, (the caller may specify be a range
+** of attributes), the attribute is returned.
+**
+** Returns Pointer to the attribute, or NULL if not found.
+**
+*******************************************************************************/
+tSDP_ATTRIBUTE *sdp_db_find_attr_in_rec (tSDP_RECORD *p_rec, UINT16 start_attr,
+ UINT16 end_attr)
+{
+ tSDP_ATTRIBUTE *p_at;
+ UINT16 xx;
+
+ /* Note that the attributes in a record are assumed to be in sorted order */
+ for (xx = 0, p_at = &p_rec->attribute[0]; xx < p_rec->num_attributes;
+ xx++, p_at++)
+ {
+ if ((p_at->id >= start_attr) && (p_at->id <= end_attr))
+ return (p_at);
+ }
+
+ /* No matching attribute found */
+ return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function sdp_compose_proto_list
+**
+** Description This function is called to compose a data sequence from
+** protocol element list struct pointer
+**
+** Returns the length of the data sequence
+**
+*******************************************************************************/
+static int sdp_compose_proto_list( UINT8 *p, UINT16 num_elem,
+ tSDP_PROTOCOL_ELEM *p_elem_list)
+{
+ UINT16 xx, yy, len;
+ BOOLEAN is_rfcomm_scn;
+ UINT8 *p_head = p;
+ UINT8 *p_len;
+
+ /* First, build the protocol list. This consists of a set of data element
+ ** sequences, one for each layer. Each layer sequence consists of layer's
+ ** UUID and optional parameters
+ */
+ for (xx = 0; xx < num_elem; xx++, p_elem_list++)
+ {
+ len = 3 + (p_elem_list->num_params * 3);
+ UINT8_TO_BE_STREAM (p, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
+
+ p_len = p;
+ *p++ = (UINT8) len;
+
+ UINT8_TO_BE_STREAM (p, (UUID_DESC_TYPE << 3) | SIZE_TWO_BYTES);
+ UINT16_TO_BE_STREAM (p, p_elem_list->protocol_uuid);
+
+ if (p_elem_list->protocol_uuid == UUID_PROTOCOL_RFCOMM)
+ is_rfcomm_scn = TRUE;
+ else
+ is_rfcomm_scn = FALSE;
+
+ for (yy = 0; yy < p_elem_list->num_params; yy++)
+ {
+ if (is_rfcomm_scn)
+ {
+ UINT8_TO_BE_STREAM (p, (UINT_DESC_TYPE << 3) | SIZE_ONE_BYTE);
+ UINT8_TO_BE_STREAM (p, p_elem_list->params[yy]);
+
+ *p_len -= 1;
+ }
+ else
+ {
+ UINT8_TO_BE_STREAM (p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
+ UINT16_TO_BE_STREAM (p, p_elem_list->params[yy]);
+ }
+ }
+ }
+ return (p - p_head);
+}
+
+#endif /* SDP_SERVER_ENABLED == TRUE */
+
+/*******************************************************************************
+**
+** Function SDP_CreateRecord
+**
+** Description This function is called to create a record in the database.
+** This would be through the SDP database maintenance API. The
+** record is created empty, teh application should then call
+** "add_attribute" to add the record's attributes.
+**
+** Returns Record handle if OK, else 0.
+**
+*******************************************************************************/
+UINT32 SDP_CreateRecord (void)
+{
+#if SDP_SERVER_ENABLED == TRUE
+ UINT32 handle;
+ UINT8 buf[4];
+ tSDP_DB *p_db = &sdp_cb.server_db;
+
+ /* First, check if there is a free record */
+ if (p_db->num_records < SDP_MAX_RECORDS)
+ {
+ memset (&p_db->record[p_db->num_records], 0,
+ sizeof (tSDP_RECORD));
+
+ /* We will use a handle of the first unreserved handle plus last record
+ ** number + 1 */
+ if (p_db->num_records)
+ handle = p_db->record[p_db->num_records - 1].record_handle + 1;
+ else
+ handle = 0x10000;
+
+ p_db->record[p_db->num_records].record_handle = handle;
+
+ p_db->num_records++;
+
+ /* Add the first attribute (the handle) automatically */
+ UINT32_TO_BE_FIELD (buf, handle);
+ SDP_AddAttribute (handle, ATTR_ID_SERVICE_RECORD_HDL, UINT_DESC_TYPE,
+ 4, buf);
+
+ return (p_db->record[p_db->num_records - 1].record_handle);
+ }
+#endif
+ return (0);
+}
+
+
+/*******************************************************************************
+**
+** Function SDP_DeleteRecord
+**
+** Description This function is called to add a record (or all records)
+** from the database. This would be through the SDP database
+** maintenance API.
+**
+** If a record handle of 0 is passed, all records are deleted.
+**
+** Returns TRUE if succeeded, else FALSE
+**
+*******************************************************************************/
+BOOLEAN SDP_DeleteRecord (UINT32 handle)
+{
+#if SDP_SERVER_ENABLED == TRUE
+ UINT16 xx, yy, zz;
+ tSDP_RECORD *p_rec = &sdp_cb.server_db.record[0];
+
+ if (handle == 0 || sdp_cb.server_db.num_records == 0)
+ {
+ /* Delete all records in the database */
+ sdp_cb.server_db.num_records = 0;
+
+ /* require new DI record to be created in SDP_SetLocalDiRecord */
+ sdp_cb.server_db.di_primary_handle = 0;
+ sdp_cb.server_db.brcm_di_registered = 0;
+
+ return (TRUE);
+ }
+ else
+ {
+ /* Find the record in the database */
+ for (xx = 0; xx < sdp_cb.server_db.num_records; xx++, p_rec++)
+ {
+ if (p_rec->record_handle == handle)
+ {
+ /* Found it. Shift everything up one */
+ for (yy = xx; yy < sdp_cb.server_db.num_records; yy++, p_rec++)
+ {
+ *p_rec = *(p_rec + 1);
+
+ /* Adjust the attribute value pointer for each attribute */
+ for (zz = 0; zz < p_rec->num_attributes; zz++)
+ p_rec->attribute[zz].value_ptr -= sizeof(tSDP_RECORD);
+ }
+
+ sdp_cb.server_db.num_records--;
+
+ /* if we're deleting the primary DI record, clear the */
+ /* value in the control block */
+ if( sdp_cb.server_db.di_primary_handle == handle )
+ {
+ sdp_cb.server_db.di_primary_handle = 0;
+ sdp_cb.server_db.brcm_di_registered = 0;
+ }
+
+ return (TRUE);
+ }
+ }
+ }
+#endif
+ return (FALSE);
+}
+
+
+/*******************************************************************************
+**
+** Function SDP_AddAttribute
+**
+** Description This function is called to add an attribute to a record.
+** This would be through the SDP database maintenance API.
+** If the attribute already exists in the record, it is replaced
+** with the new value.
+**
+** NOTE Attribute values must be passed as a Big Endian stream.
+**
+** Returns TRUE if added OK, else FALSE
+**
+*******************************************************************************/
+BOOLEAN SDP_AddAttribute (UINT32 handle, UINT16 attr_id, UINT8 attr_type,
+ UINT32 attr_len, UINT8 *p_val)
+{
+#if SDP_SERVER_ENABLED == TRUE
+ UINT16 xx, yy, zz;
+ tSDP_RECORD *p_rec = &sdp_cb.server_db.record[0];
+
+#if (BT_TRACE_VERBOSE == TRUE)
+ if (sdp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG)
+ {
+ if ((attr_type == UINT_DESC_TYPE) ||
+ (attr_type == TWO_COMP_INT_DESC_TYPE) ||
+ (attr_type == UUID_DESC_TYPE) ||
+ (attr_type == DATA_ELE_SEQ_DESC_TYPE) ||
+ (attr_type == DATA_ELE_ALT_DESC_TYPE))
+ {
+ UINT8 num_array[400];
+ UINT32 i;
+ UINT32 len = (attr_len > 200) ? 200 : attr_len;
+
+ num_array[0] ='\0';
+ for (i = 0; i < len; i++)
+ {
+ sprintf((char *)&num_array[i*2],"%02X",(UINT8)(p_val[i]));
+ }
+ SDP_TRACE_DEBUG6("SDP_AddAttribute: handle:%X, id:%04X, type:%d, len:%d, p_val:%p, *p_val:%s",
+ handle,attr_id,attr_type,attr_len,p_val,num_array);
+ }
+ else if (attr_type == BOOLEAN_DESC_TYPE)
+ {
+ SDP_TRACE_DEBUG6("SDP_AddAttribute: handle:%X, id:%04X, type:%d, len:%d, p_val:%p, *p_val:%d",
+ handle,attr_id,attr_type,attr_len,p_val,*p_val);
+ }
+ else
+ {
+ SDP_TRACE_DEBUG6("SDP_AddAttribute: handle:%X, id:%04X, type:%d, len:%d, p_val:%p, *p_val:%s",
+ handle,attr_id,attr_type,attr_len,p_val,p_val);
+ }
+ }
+#endif
+
+ /* Find the record in the database */
+ for (zz = 0; zz < sdp_cb.server_db.num_records; zz++, p_rec++)
+ {
+ if (p_rec->record_handle == handle)
+ {
+ tSDP_ATTRIBUTE *p_attr = &p_rec->attribute[0];
+
+ /* Found the record. Now, see if the attribute already exists */
+ for (xx = 0; xx < p_rec->num_attributes; xx++, p_attr++)
+ {
+ /* The attribute exists. replace it */
+ if (p_attr->id == attr_id)
+ {
+ SDP_DeleteAttribute (handle, attr_id);
+ break;
+ }
+ if (p_attr->id > attr_id)
+ break;
+ }
+
+ if (p_rec->num_attributes == SDP_MAX_REC_ATTR)
+ return (FALSE);
+
+ /* If not found, see if we can allocate a new entry */
+ if (xx == p_rec->num_attributes)
+ p_attr = &p_rec->attribute[p_rec->num_attributes];
+ else
+ {
+ /* Since the attributes are kept in sorted order, insert ours here */
+ for (yy = p_rec->num_attributes; yy > xx; yy--)
+ p_rec->attribute[yy] = p_rec->attribute[yy - 1];
+ }
+
+ p_attr->id = attr_id;
+ p_attr->type = attr_type;
+ p_attr->len = attr_len;
+
+ if (p_rec->free_pad_ptr + attr_len >= SDP_MAX_PAD_LEN)
+ {
+ /* do truncate only for text string type descriptor */
+ if (attr_type == TEXT_STR_DESC_TYPE)
+ {
+ SDP_TRACE_WARNING2("SDP_AddAttribute: attr_len:%d too long. truncate to (%d)",
+ attr_len, SDP_MAX_PAD_LEN - p_rec->free_pad_ptr );
+
+ attr_len = SDP_MAX_PAD_LEN - p_rec->free_pad_ptr;
+ p_val[SDP_MAX_PAD_LEN - p_rec->free_pad_ptr] = '\0';
+ p_val[SDP_MAX_PAD_LEN - p_rec->free_pad_ptr+1] = '\0';
+ }
+ else
+ attr_len = 0;
+ }
+
+ if ((attr_len > 0) && (p_val != 0))
+ {
+ p_attr->len = attr_len;
+ memcpy (&p_rec->attr_pad[p_rec->free_pad_ptr], p_val, (size_t)attr_len);
+ p_attr->value_ptr = &p_rec->attr_pad[p_rec->free_pad_ptr];
+ p_rec->free_pad_ptr += attr_len;
+ }
+ else if ((attr_len == 0 && p_attr->len != 0) || /* if truncate to 0 length, simply don't add */
+ p_val == 0)
+ {
+ SDP_TRACE_ERROR2("SDP_AddAttribute fail, length exceed maximum: ID %d: attr_len:%d ",
+ attr_id, attr_len );
+ p_attr->id = p_attr->type = p_attr->len = 0;
+ return (FALSE);
+ }
+ p_rec->num_attributes++;
+
+ /*** Mark DI record as used by Broadcom ***/
+ if (handle == sdp_cb.server_db.di_primary_handle &&
+ attr_id == ATTR_ID_EXT_BRCM_VERSION)
+ sdp_cb.server_db.brcm_di_registered = TRUE;
+
+ return (TRUE);
+ }
+ }
+#endif
+ return (FALSE);
+}
+
+
+/*******************************************************************************
+**
+** Function SDP_AddSequence
+**
+** Description This function is called to add a sequence to a record.
+** This would be through the SDP database maintenance API.
+** If the sequence already exists in the record, it is replaced
+** with the new sequence.
+**
+** NOTE Element values must be passed as a Big Endian stream.
+**
+** Returns TRUE if added OK, else FALSE
+**
+*******************************************************************************/
+BOOLEAN SDP_AddSequence (UINT32 handle, UINT16 attr_id, UINT16 num_elem,
+ UINT8 type[], UINT8 len[], UINT8 *p_val[])
+{
+#if SDP_SERVER_ENABLED == TRUE
+ UINT16 xx;
+ UINT8 buff[SDP_MAX_ATTR_LEN * 2];
+ UINT8 *p;
+ UINT8 *p_head;
+
+ p = buff;
+ /* First, build the sequence */
+ for (xx = 0; xx < num_elem; xx++)
+ {
+ p_head = p;
+ switch (len[xx])
+ {
+ case 1:
+ UINT8_TO_BE_STREAM (p, (type[xx] << 3) | SIZE_ONE_BYTE);
+ break;
+ case 2:
+ UINT8_TO_BE_STREAM (p, (type[xx] << 3) | SIZE_TWO_BYTES);
+ break;
+ case 4:
+ UINT8_TO_BE_STREAM (p, (type[xx] << 3) | SIZE_FOUR_BYTES);
+ break;
+ case 8:
+ UINT8_TO_BE_STREAM (p, (type[xx] << 3) | SIZE_EIGHT_BYTES);
+ break;
+ case 16:
+ UINT8_TO_BE_STREAM (p, (type[xx] << 3) | SIZE_SIXTEEN_BYTES);
+ break;
+ default:
+ UINT8_TO_BE_STREAM (p, (type[xx] << 3) | SIZE_IN_NEXT_BYTE);
+ UINT8_TO_BE_STREAM (p, len[xx]);
+ break;
+ }
+
+ ARRAY_TO_BE_STREAM (p, p_val[xx], len[xx]);
+
+ if (p - buff > SDP_MAX_ATTR_LEN)
+ {
+ /* go back to before we add this element */
+ p = p_head;
+ if(p_head == buff)
+ {
+ /* the first element exceed the max length */
+ SDP_TRACE_ERROR0 ("SDP_AddSequence - too long(attribute is not added)!!");
+ return FALSE;
+ }
+ else
+ SDP_TRACE_ERROR2 ("SDP_AddSequence - too long, add %d elements of %d", xx, num_elem);
+ break;
+ }
+ }
+
+ return (SDP_AddAttribute (handle, attr_id, DATA_ELE_SEQ_DESC_TYPE,
+ (UINT32) (p - buff), buff));
+#else /* SDP_SERVER_ENABLED == FALSE */
+ return (FALSE);
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function SDP_AddUuidSequence
+**
+** Description This function is called to add a UUID sequence to a record.
+** This would be through the SDP database maintenance API.
+** If the sequence already exists in the record, it is replaced
+** with the new sequence.
+**
+** Returns TRUE if added OK, else FALSE
+**
+*******************************************************************************/
+BOOLEAN SDP_AddUuidSequence (UINT32 handle, UINT16 attr_id, UINT16 num_uuids,
+ UINT16 *p_uuids)
+{
+#if SDP_SERVER_ENABLED == TRUE
+ UINT16 xx;
+ UINT8 buff[SDP_MAX_ATTR_LEN * 2];
+ UINT8 *p = buff;
+ INT32 max_len = SDP_MAX_ATTR_LEN -3;
+
+ /* First, build the sequence */
+ for (xx = 0; xx < num_uuids ; xx++, p_uuids++)
+ {
+ UINT8_TO_BE_STREAM (p, (UUID_DESC_TYPE << 3) | SIZE_TWO_BYTES);
+ UINT16_TO_BE_STREAM (p, *p_uuids);
+
+ if((p - buff) > max_len)
+ {
+ SDP_TRACE_WARNING2 ("SDP_AddUuidSequence - too long, add %d uuids of %d", xx, num_uuids);
+ break;
+ }
+ }
+
+ return (SDP_AddAttribute (handle, attr_id, DATA_ELE_SEQ_DESC_TYPE,
+ (UINT32) (p - buff), buff));
+#else /* SDP_SERVER_ENABLED == FALSE */
+ return (FALSE);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function SDP_AddProtocolList
+**
+** Description This function is called to add a protocol descriptor list to
+** a record. This would be through the SDP database maintenance API.
+** If the protocol list already exists in the record, it is replaced
+** with the new list.
+**
+** Returns TRUE if added OK, else FALSE
+**
+*******************************************************************************/
+BOOLEAN SDP_AddProtocolList (UINT32 handle, UINT16 num_elem,
+ tSDP_PROTOCOL_ELEM *p_elem_list)
+{
+#if SDP_SERVER_ENABLED == TRUE
+ UINT8 buff[SDP_MAX_ATTR_LEN * 2];
+ int offset;
+
+ offset = sdp_compose_proto_list(buff, num_elem, p_elem_list);
+
+ return (SDP_AddAttribute (handle, ATTR_ID_PROTOCOL_DESC_LIST,
+ DATA_ELE_SEQ_DESC_TYPE, (UINT32) offset, buff));
+#else /* SDP_SERVER_ENABLED == FALSE */
+ return (FALSE);
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function SDP_AddAdditionProtoLists
+**
+** Description This function is called to add a protocol descriptor list to
+** a record. This would be through the SDP database maintenance API.
+** If the protocol list already exists in the record, it is replaced
+** with the new list.
+**
+** Returns TRUE if added OK, else FALSE
+**
+*******************************************************************************/
+BOOLEAN SDP_AddAdditionProtoLists (UINT32 handle, UINT16 num_elem,
+ tSDP_PROTO_LIST_ELEM *p_proto_list)
+{
+#if SDP_SERVER_ENABLED == TRUE
+ UINT16 xx;
+ UINT8 buff[SDP_MAX_ATTR_LEN * 2];
+ UINT8 *p = buff;
+ UINT8 *p_len;
+ int offset;
+
+ /* for each ProtocolDescriptorList */
+ for (xx = 0; xx < num_elem; xx++, p_proto_list++)
+ {
+ UINT8_TO_BE_STREAM (p, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
+ p_len = p++;
+
+ offset = sdp_compose_proto_list(p, p_proto_list->num_elems,
+ p_proto_list->list_elem);
+ p += offset;
+
+ *p_len = (UINT8)(p - p_len - 1);
+ }
+
+ return (SDP_AddAttribute (handle, ATTR_ID_ADDITION_PROTO_DESC_LISTS,
+ DATA_ELE_SEQ_DESC_TYPE, (UINT32) (p - buff), buff));
+#else /* SDP_SERVER_ENABLED == FALSE */
+ return (FALSE);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function SDP_AddProfileDescriptorList
+**
+** Description This function is called to add a profile descriptor list to
+** a record. This would be through the SDP database maintenance API.
+** If the version already exists in the record, it is replaced
+** with the new one.
+**
+** Returns TRUE if added OK, else FALSE
+**
+*******************************************************************************/
+BOOLEAN SDP_AddProfileDescriptorList (UINT32 handle, UINT16 profile_uuid,
+ UINT16 version)
+{
+#if SDP_SERVER_ENABLED == TRUE
+ UINT8 buff[SDP_MAX_ATTR_LEN];
+ UINT8 *p = &buff[2];
+
+ /* First, build the profile descriptor list. This consists of a data element sequence. */
+ /* The sequence consists of profile's UUID and version number */
+ UINT8_TO_BE_STREAM (p, (UUID_DESC_TYPE << 3) | SIZE_TWO_BYTES);
+ UINT16_TO_BE_STREAM (p, profile_uuid);
+
+ UINT8_TO_BE_STREAM (p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
+ UINT16_TO_BE_STREAM (p, version);
+
+ /* Add in type and length fields */
+ buff[0] = (UINT8) ((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
+ buff[1] = (UINT8) (p - &buff[2]);
+
+ return (SDP_AddAttribute (handle, ATTR_ID_BT_PROFILE_DESC_LIST,
+ DATA_ELE_SEQ_DESC_TYPE, (UINT32) (p - buff), buff));
+#else /* SDP_SERVER_ENABLED == FALSE */
+ return (FALSE);
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function SDP_AddLanguageBaseAttrIDList
+**
+** Description This function is called to add a language base attr list to
+** a record. This would be through the SDP database maintenance API.
+** If the version already exists in the record, it is replaced
+** with the new one.
+**
+** Returns TRUE if added OK, else FALSE
+**
+*******************************************************************************/
+BOOLEAN SDP_AddLanguageBaseAttrIDList (UINT32 handle, UINT16 lang,
+ UINT16 char_enc, UINT16 base_id)
+{
+#if SDP_SERVER_ENABLED == TRUE
+ UINT8 buff[SDP_MAX_ATTR_LEN];
+ UINT8 *p = buff;
+
+ /* First, build the language base descriptor list. This consists of a data */
+ /* element sequence. The sequence consists of 9 bytes (3 UINt16 fields) */
+ UINT8_TO_BE_STREAM (p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
+ UINT16_TO_BE_STREAM (p, lang);
+
+ UINT8_TO_BE_STREAM (p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
+ UINT16_TO_BE_STREAM (p, char_enc);
+
+ UINT8_TO_BE_STREAM (p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
+ UINT16_TO_BE_STREAM (p, base_id);
+
+ return (SDP_AddAttribute (handle, ATTR_ID_LANGUAGE_BASE_ATTR_ID_LIST,
+ DATA_ELE_SEQ_DESC_TYPE, (UINT32) (p - buff), buff));
+#else /* SDP_SERVER_ENABLED == FALSE */
+ return (FALSE);
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function SDP_AddServiceClassIdList
+**
+** Description This function is called to add a service list to a record.
+** This would be through the SDP database maintenance API.
+** If the service list already exists in the record, it is replaced
+** with the new list.
+**
+** Returns TRUE if added OK, else FALSE
+**
+*******************************************************************************/
+BOOLEAN SDP_AddServiceClassIdList (UINT32 handle, UINT16 num_services,
+ UINT16 *p_service_uuids)
+{
+#if SDP_SERVER_ENABLED == TRUE
+ UINT16 xx;
+ UINT8 buff[SDP_MAX_ATTR_LEN * 2];
+ UINT8 *p = buff;
+
+ for (xx = 0; xx < num_services; xx++, p_service_uuids++)
+ {
+ UINT8_TO_BE_STREAM (p, (UUID_DESC_TYPE << 3) | SIZE_TWO_BYTES);
+ UINT16_TO_BE_STREAM (p, *p_service_uuids);
+ }
+
+ return (SDP_AddAttribute (handle, ATTR_ID_SERVICE_CLASS_ID_LIST,
+ DATA_ELE_SEQ_DESC_TYPE, (UINT32) (p - buff), buff));
+#else /* SDP_SERVER_ENABLED == FALSE */
+ return (FALSE);
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function SDP_DeleteAttribute
+**
+** Description This function is called to delete an attribute from a record.
+** This would be through the SDP database maintenance API.
+**
+** Returns TRUE if deleted OK, else FALSE if not found
+**
+*******************************************************************************/
+BOOLEAN SDP_DeleteAttribute (UINT32 handle, UINT16 attr_id)
+{
+#if SDP_SERVER_ENABLED == TRUE
+ UINT16 xx, yy;
+ tSDP_RECORD *p_rec = &sdp_cb.server_db.record[0];
+ UINT8 *pad_ptr;
+ UINT32 len; /* Number of bytes in the entry */
+
+ /* Find the record in the database */
+ for (xx = 0; xx < sdp_cb.server_db.num_records; xx++, p_rec++)
+ {
+ if (p_rec->record_handle == handle)
+ {
+ tSDP_ATTRIBUTE *p_attr = &p_rec->attribute[0];
+
+ SDP_TRACE_API2("Deleting attr_id 0x%04x for handle 0x%x", attr_id, handle);
+ /* Found it. Now, find the attribute */
+ for (xx = 0; xx < p_rec->num_attributes; xx++, p_attr++)
+ {
+ if (p_attr->id == attr_id)
+ {
+ pad_ptr = p_attr->value_ptr;
+ len = p_attr->len;
+
+ if (len)
+ {
+ for (yy = 0; yy < p_rec->num_attributes; yy++)
+ {
+ if( p_rec->attribute[yy].value_ptr > pad_ptr )
+ p_rec->attribute[yy].value_ptr -= len;
+ }
+ }
+
+ /* Found it. Shift everything up one */
+ p_rec->num_attributes--;
+
+ for (yy = xx; yy < p_rec->num_attributes; yy++, p_attr++)
+ {
+ *p_attr = *(p_attr + 1);
+ }
+
+ /* adjust attribute values if needed */
+ if (len)
+ {
+ xx = (p_rec->free_pad_ptr - ((pad_ptr+len) -
+ &p_rec->attr_pad[0]));
+ for( yy=0; yy<xx; yy++, pad_ptr++)
+ *pad_ptr = *(pad_ptr+len);
+ p_rec->free_pad_ptr -= len;
+ }
+ return (TRUE);
+ }
+ }
+ }
+ }
+#endif
+ /* If here, not found */
+ return (FALSE);
+}
+
+/*******************************************************************************
+**
+** Function SDP_ReadRecord
+**
+** Description This function is called to get the raw data of the record
+** with the given handle from the database.
+**
+** Returns -1, if the record is not found.
+** Otherwise, the offset (0 or 1) to start of data in p_data.
+**
+** The size of data copied into p_data is in *p_data_len.
+**
+*******************************************************************************/
+#if (SDP_RAW_DATA_INCLUDED == TRUE)
+INT32 SDP_ReadRecord(UINT32 handle, UINT8 *p_data, INT32 *p_data_len)
+{
+ INT32 len = 0; /* Number of bytes in the entry */
+ INT32 offset = -1; /* default to not found */
+#if SDP_SERVER_ENABLED == TRUE
+ tSDP_RECORD *p_rec;
+ UINT16 start = 0;
+ UINT16 end = 0xffff;
+ tSDP_ATTRIBUTE *p_attr;
+ UINT16 rem_len;
+ UINT8 *p_rsp;
+
+ /* Find the record in the database */
+ p_rec = sdp_db_find_record(handle);
+ if(p_rec && p_data && p_data_len)
+ {
+ p_rsp = &p_data[3];
+ while ( (p_attr = sdp_db_find_attr_in_rec (p_rec, start, end)) != NULL)
+ {
+ /* Check if attribute fits. Assume 3-byte value type/length */
+ rem_len = *p_data_len - (UINT16) (p_rsp - p_data);
+
+ if (p_attr->len > (UINT32)(rem_len - 6))
+ break;
+
+ p_rsp = sdpu_build_attrib_entry (p_rsp, p_attr);
+
+ /* next attr id */
+ start = p_attr->id + 1;
+ }
+ len = (INT32) (p_rsp - p_data);
+
+ /* Put in the sequence header (2 or 3 bytes) */
+ if (len > 255)
+ {
+ offset = 0;
+ p_data[0] = (UINT8) ((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_WORD);
+ p_data[1] = (UINT8) ((len - 3) >> 8);
+ p_data[2] = (UINT8) (len - 3);
+ }
+ else
+ {
+ offset = 1;
+
+ p_data[1] = (UINT8) ((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
+ p_data[2] = (UINT8) (len - 3);
+
+ len--;
+ }
+ *p_data_len = len;
+ }
+#endif
+ /* If here, not found */
+ return (offset);
+}
+#endif
+
+
+
diff --git a/stack/sdp/sdp_discovery.c b/stack/sdp/sdp_discovery.c
new file mode 100644
index 0000000..1092584
--- /dev/null
+++ b/stack/sdp/sdp_discovery.c
@@ -0,0 +1,1113 @@
+/****************************************************************************
+**
+** Name: sdp_discovery.c
+**
+** Description: this file contains SDP discovery functions
+**
+** Copyright (c) 1999-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "bt_target.h"
+#include "gki.h"
+#include "l2cdefs.h"
+#include "hcidefs.h"
+#include "hcimsgs.h"
+#include "sdp_api.h"
+#include "sdpint.h"
+#include "btu.h"
+#include "btm_api.h"
+
+
+#ifndef SDP_DEBUG_RAW
+#define SDP_DEBUG_RAW FALSE
+#endif
+
+/********************************************************************************/
+/* L O C A L F U N C T I O N P R O T O T Y P E S */
+/********************************************************************************/
+#if SDP_CLIENT_ENABLED == TRUE
+static void process_service_search_rsp (tCONN_CB *p_ccb, UINT8 *p_reply, UINT16 len);
+static void process_service_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply, UINT16 len);
+static void process_service_search_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply, UINT16 len);
+static UINT8 *save_attr_seq (tCONN_CB *p_ccb, UINT8 *p, UINT8 *p_msg_end);
+static tSDP_DISC_REC *add_record (tSDP_DISCOVERY_DB *p_db, BD_ADDR p_bda);
+static UINT8 *add_attr (UINT8 *p, tSDP_DISCOVERY_DB *p_db, tSDP_DISC_REC *p_rec,
+ UINT16 attr_id, tSDP_DISC_ATTR *p_parent_attr, UINT8 nest_level);
+
+/* Safety check in case we go crazy */
+#define MAX_NEST_LEVELS 5
+
+
+/*******************************************************************************
+**
+** Function sdpu_build_uuid_seq
+**
+** Description This function builds a UUID sequence from the list of
+** passed UUIDs. It is also passed the address of the output
+** buffer.
+**
+** Returns Pointer to next byte in the output buffer.
+**
+*******************************************************************************/
+static UINT8 *sdpu_build_uuid_seq (UINT8 *p_out, UINT16 num_uuids, tSDP_UUID *p_uuid_list)
+{
+ UINT16 xx;
+ UINT8 *p_len;
+
+ /* First thing is the data element header */
+ UINT8_TO_BE_STREAM (p_out, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
+
+ /* Remember where the length goes. Leave space for it. */
+ p_len = p_out;
+ p_out += 1;
+
+ /* Now, loop through and put in all the UUID(s) */
+ for (xx = 0; xx < num_uuids; xx++, p_uuid_list++)
+ {
+ if (p_uuid_list->len == 2)
+ {
+ UINT8_TO_BE_STREAM (p_out, (UUID_DESC_TYPE << 3) | SIZE_TWO_BYTES);
+ UINT16_TO_BE_STREAM (p_out, p_uuid_list->uu.uuid16);
+ }
+ else if (p_uuid_list->len == 4)
+ {
+ UINT8_TO_BE_STREAM (p_out, (UUID_DESC_TYPE << 3) | SIZE_FOUR_BYTES);
+ UINT32_TO_BE_STREAM (p_out, p_uuid_list->uu.uuid32);
+ }
+ else
+ {
+ UINT8_TO_BE_STREAM (p_out, (UUID_DESC_TYPE << 3) | SIZE_SIXTEEN_BYTES);
+ ARRAY_TO_BE_STREAM (p_out, p_uuid_list->uu.uuid128, p_uuid_list->len);
+ }
+ }
+
+ /* Now, put in the length */
+ xx = (UINT16)(p_out - p_len - 1);
+ UINT8_TO_BE_STREAM (p_len, xx);
+
+ return (p_out);
+}
+
+/*******************************************************************************
+**
+** Function sdp_snd_service_search_req
+**
+** Description Send a service search request to the SDP server.
+**
+** Returns void
+**
+*******************************************************************************/
+static void sdp_snd_service_search_req(tCONN_CB *p_ccb, UINT8 cont_len, UINT8 * p_cont)
+{
+ UINT8 *p, *p_start, *p_param_len;
+ BT_HDR *p_cmd;
+ UINT16 param_len;
+
+ /* Get a buffer to send the packet to L2CAP */
+ if ((p_cmd = (BT_HDR *) GKI_getpoolbuf (SDP_POOL_ID)) == NULL)
+ {
+ sdp_disconnect (p_ccb, SDP_NO_RESOURCES);
+ return;
+ }
+
+ p_cmd->offset = L2CAP_MIN_OFFSET;
+ p = p_start = (UINT8 *)(p_cmd + 1) + L2CAP_MIN_OFFSET;
+
+ /* Build a service search request packet */
+ UINT8_TO_BE_STREAM (p, SDP_PDU_SERVICE_SEARCH_REQ);
+ UINT16_TO_BE_STREAM (p, p_ccb->transaction_id);
+ p_ccb->transaction_id++;
+
+ /* Skip the length, we need to add it at the end */
+ p_param_len = p;
+ p += 2;
+
+ /* Build the UID sequence. */
+#if (defined(SDP_BROWSE_PLUS) && SDP_BROWSE_PLUS == TRUE)
+ p = sdpu_build_uuid_seq (p, 1, &p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx]);
+#else
+ p = sdpu_build_uuid_seq (p, p_ccb->p_db->num_uuid_filters, p_ccb->p_db->uuid_filters);
+#endif
+
+ /* Set max service record count */
+ UINT16_TO_BE_STREAM (p, sdp_cb.max_recs_per_search);
+
+ /* Set continuation state */
+ UINT8_TO_BE_STREAM (p, cont_len);
+
+ /* if this is not the first request */
+ if(cont_len && p_cont)
+ {
+ memcpy(p, p_cont, cont_len);
+ p += cont_len;
+ }
+
+ /* Go back and put the parameter length into the buffer */
+ param_len = (UINT16)(p - p_param_len - 2);
+ UINT16_TO_BE_STREAM (p_param_len, param_len);
+
+ p_ccb->disc_state = SDP_DISC_WAIT_HANDLES;
+
+ /* Set the length of the SDP data in the buffer */
+ p_cmd->len = (UINT16)(p - p_start);
+
+#if (SDP_DEBUG_RAW == TRUE)
+ SDP_TRACE_WARNING2("sdp_snd_service_search_req cont_len :%d disc_state:%d",cont_len, p_ccb->disc_state);
+#endif
+
+
+ L2CA_DataWrite (p_ccb->connection_id, p_cmd);
+
+ /* Start inactivity timer */
+ btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_SDP, SDP_INACT_TIMEOUT);
+
+}
+
+/*******************************************************************************
+**
+** Function sdp_disc_connected
+**
+** Description This function is called when an SDP discovery attempt is
+** connected.
+**
+** Returns void
+**
+*******************************************************************************/
+void sdp_disc_connected (tCONN_CB *p_ccb)
+{
+
+#if SDP_FOR_JV_INCLUDED == TRUE
+ if (SDP_IS_PASS_THRU == p_ccb->is_attr_search)
+ {
+ tSDP_DISC_RES_CB *p_rcb = (tSDP_DISC_RES_CB *) p_ccb->p_db;
+ tSDP_DR_OPEN evt_data;
+ /* report connected */
+ p_ccb->disc_state = SDP_DISC_WAIT_PASS_THRU;
+ if (p_rcb)
+ {
+ memcpy(evt_data.peer_addr, p_ccb->device_address, BD_ADDR_LEN);
+ evt_data.peer_mtu = p_ccb->rem_mtu_size;
+ (*p_rcb)(SDP_EVT_OPEN, (void *)&evt_data);
+ }
+ }
+ else
+#endif
+ if (p_ccb->is_attr_search)
+ {
+ p_ccb->disc_state = SDP_DISC_WAIT_SEARCH_ATTR;
+
+ process_service_search_attr_rsp (p_ccb, NULL, 0);
+ }
+ else
+ {
+ /* First step is to get a list of the handles from the server. */
+ /* We are not searching for a specific attribute, so we will */
+ /* first search for the service, then get all attributes of it */
+
+ p_ccb->num_handles = 0;
+ sdp_snd_service_search_req(p_ccb, 0, NULL);
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function sdp_disc_server_rsp
+**
+** Description This function is called when there is a response from
+** the server.
+**
+** Returns void
+**
+*******************************************************************************/
+void sdp_disc_server_rsp (tCONN_CB *p_ccb, BT_HDR *p_msg)
+{
+ UINT8 *p, rsp_pdu;
+ BOOLEAN invalid_pdu = TRUE;
+
+#if (SDP_DEBUG_RAW == TRUE)
+ SDP_TRACE_WARNING1("sdp_disc_server_rsp disc_state:%d", p_ccb->disc_state);
+#endif
+
+ /* stop inactivity timer when we receive a response */
+ btu_stop_timer (&p_ccb->timer_entry);
+
+#if SDP_FOR_JV_INCLUDED == TRUE
+ if(SDP_IS_PASS_THRU == p_ccb->is_attr_search)
+ {
+ tSDP_DISC_RES_CB *p_rcb = (tSDP_DISC_RES_CB *) p_ccb->p_db;
+ tSDP_DR_DATA data;
+ if (p_rcb)
+ {
+ data.p_data = (UINT8 *)(p_msg + 1) + p_msg->offset;
+ data.data_len = p_msg->len;
+ (*p_rcb)(SDP_EVT_DATA_IND, (void *)&data);
+ }
+ return;
+ }
+#endif
+
+ /* Got a reply!! Check what we got back */
+ p = (UINT8 *)(p_msg + 1) + p_msg->offset;
+
+ BE_STREAM_TO_UINT8 (rsp_pdu, p);
+
+ p_msg->len--;
+
+ switch (rsp_pdu)
+ {
+ case SDP_PDU_SERVICE_SEARCH_RSP:
+ if (p_ccb->disc_state == SDP_DISC_WAIT_HANDLES)
+ {
+ process_service_search_rsp (p_ccb, p, p_msg->len);
+ invalid_pdu = FALSE;
+ }
+ break;
+
+ case SDP_PDU_SERVICE_ATTR_RSP:
+ if (p_ccb->disc_state == SDP_DISC_WAIT_ATTR)
+ {
+ process_service_attr_rsp (p_ccb, p, p_msg->len);
+ invalid_pdu = FALSE;
+ }
+ break;
+
+ case SDP_PDU_SERVICE_SEARCH_ATTR_RSP:
+ if (p_ccb->disc_state == SDP_DISC_WAIT_SEARCH_ATTR)
+ {
+ process_service_search_attr_rsp (p_ccb, p, p_msg->len);
+ invalid_pdu = FALSE;
+ }
+ break;
+ }
+
+ if (invalid_pdu)
+ {
+ SDP_TRACE_WARNING2 ("SDP - Unexp. PDU: %d in state: %d", rsp_pdu, p_ccb->disc_state);
+ sdp_disconnect (p_ccb, SDP_GENERIC_ERROR);
+ }
+}
+
+/******************************************************************************
+**
+** Function process_service_search_rsp
+**
+** Description This function is called when there is a search response from
+** the server.
+**
+** Returns void
+**
+*******************************************************************************/
+static void process_service_search_rsp (tCONN_CB *p_ccb, UINT8 *p_reply, UINT16 len)
+{
+ UINT16 xx;
+ UINT16 total, cur_handles, orig;
+ UINT8 cont_len;
+
+ /* Skip transaction, and param len */
+ p_reply += 4;
+ BE_STREAM_TO_UINT16 (total, p_reply);
+ BE_STREAM_TO_UINT16 (cur_handles, p_reply);
+
+ orig = p_ccb->num_handles;
+ p_ccb->num_handles += cur_handles;
+ if (p_ccb->num_handles == 0)
+ {
+ SDP_TRACE_WARNING0 ("SDP - Rcvd ServiceSearchRsp, no matches");
+ sdp_disconnect (p_ccb, SDP_NO_RECS_MATCH);
+ return;
+ }
+
+ /* Save the handles that match. We will can only process a certain number. */
+ if (total > sdp_cb.max_recs_per_search)
+ total = sdp_cb.max_recs_per_search;
+ if (p_ccb->num_handles > sdp_cb.max_recs_per_search)
+ p_ccb->num_handles = sdp_cb.max_recs_per_search;
+
+ for (xx = orig; xx < p_ccb->num_handles; xx++)
+ BE_STREAM_TO_UINT32 (p_ccb->handles[xx], p_reply);
+
+ BE_STREAM_TO_UINT8 (cont_len, p_reply);
+ if(cont_len != 0)
+ {
+ if(cont_len > SDP_MAX_CONTINUATION_LEN)
+ {
+ sdp_disconnect (p_ccb, SDP_INVALID_CONT_STATE);
+ return;
+ }
+ /* stay in the same state */
+ sdp_snd_service_search_req(p_ccb, cont_len, p_reply);
+ }
+ else
+ {
+ /* change state */
+ p_ccb->disc_state = SDP_DISC_WAIT_ATTR;
+
+ /* Kick off the first attribute request */
+ process_service_attr_rsp (p_ccb, NULL, 0);
+ }
+}
+
+/*******************************************************************************
+**
+** Function sdp_copy_raw_data
+**
+** Description copy the raw data
+**
+**
+** Returns void
+**
+*******************************************************************************/
+#if (SDP_RAW_DATA_INCLUDED == TRUE)
+static void sdp_copy_raw_data (tCONN_CB *p_ccb, UINT16 len, BOOLEAN offset)
+{
+ unsigned int cpy_len;
+ UINT32 list_len;
+ UINT8 *p;
+ UINT8 * p_temp;
+ UINT8 type;
+ UINT32 delta_len = 0;
+
+#if (SDP_DEBUG_RAW == TRUE)
+ UINT8 num_array[SDP_MAX_LIST_BYTE_COUNT];
+ UINT32 i;
+
+ for (i = 0; i < p_ccb->list_len; i++)
+ {
+ sprintf((char *)&num_array[i*2],"%02X",(UINT8)(p_ccb->rsp_list[i]));
+ }
+ SDP_TRACE_WARNING1("result :%s",num_array);
+#endif
+
+ if(p_ccb->p_db->raw_data)
+ {
+ cpy_len = p_ccb->p_db->raw_size - p_ccb->p_db->raw_used;
+ list_len = p_ccb->list_len;
+ p_temp = p = &p_ccb->rsp_list[0];
+
+ if(offset)
+ {
+ type = *p++;
+ p = sdpu_get_len_from_type (p, type, &list_len);
+ }
+ if(list_len && list_len < cpy_len )
+ {
+ cpy_len = list_len;
+ }
+#if (SDP_DEBUG_RAW == TRUE)
+ SDP_TRACE_WARNING4("list_len :%d cpy_len:%d raw_size:%d raw_used:%d",
+ list_len, cpy_len, p_ccb->p_db->raw_size, p_ccb->p_db->raw_used);
+#endif
+ memcpy (&p_ccb->p_db->raw_data[p_ccb->p_db->raw_used], p, cpy_len);
+ p_ccb->p_db->raw_used += cpy_len;
+ }
+}
+#endif
+
+/*******************************************************************************
+**
+** Function process_service_attr_rsp
+**
+** Description This function is called when there is a attribute response from
+** the server.
+**
+** Returns void
+**
+*******************************************************************************/
+static void process_service_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply, UINT16 len)
+{
+ UINT8 *p_start, *p_param_len;
+ UINT16 param_len, list_byte_count;
+ BOOLEAN cont_request_needed = FALSE;
+
+#if (SDP_DEBUG_RAW == TRUE)
+ SDP_TRACE_WARNING2("process_service_attr_rsp len:%d raw inc:%d",
+ len, SDP_RAW_DATA_INCLUDED);
+#endif
+ /* If p_reply is NULL, we were called after the records handles were read */
+ if (p_reply)
+ {
+#if (SDP_DEBUG_RAW == TRUE)
+ SDP_TRACE_WARNING4("ID & len: 0x%02x-%02x-%02x-%02x",
+ p_reply[0], p_reply[1], p_reply[2], p_reply[3]);
+#endif
+ /* Skip transaction ID and length */
+ p_reply += 4;
+
+ BE_STREAM_TO_UINT16 (list_byte_count, p_reply);
+#if (SDP_DEBUG_RAW == TRUE)
+ SDP_TRACE_WARNING1("list_byte_count:%d", list_byte_count);
+#endif
+
+ /* Copy the response to the scratchpad. First, a safety check on the length */
+ if ((p_ccb->list_len + list_byte_count) > SDP_MAX_LIST_BYTE_COUNT)
+ {
+ sdp_disconnect (p_ccb, SDP_INVALID_PDU_SIZE);
+ return;
+ }
+
+#if (SDP_DEBUG_RAW == TRUE)
+ SDP_TRACE_WARNING2("list_len: %d, list_byte_count: %d",
+ p_ccb->list_len, list_byte_count);
+#endif
+ if (p_ccb->rsp_list == NULL)
+ {
+ p_ccb->rsp_list = (UINT8 *)GKI_getbuf (SDP_MAX_LIST_BYTE_COUNT);
+ if (p_ccb->rsp_list == NULL)
+ {
+ SDP_TRACE_ERROR0 ("SDP - no gki buf to save rsp");
+ sdp_disconnect (p_ccb, SDP_NO_RESOURCES);
+ return;
+ }
+ }
+ memcpy (&p_ccb->rsp_list[p_ccb->list_len], p_reply, list_byte_count);
+ p_ccb->list_len += list_byte_count;
+ p_reply += list_byte_count;
+#if (SDP_DEBUG_RAW == TRUE)
+ SDP_TRACE_WARNING1("list_len: %d(attr_rsp)", p_ccb->list_len);
+
+ /* Check if we need to request a continuation */
+ SDP_TRACE_WARNING2("*p_reply:%d(%d)", *p_reply, SDP_MAX_CONTINUATION_LEN);
+#endif
+ if (*p_reply)
+ {
+ if (*p_reply > SDP_MAX_CONTINUATION_LEN)
+ {
+ sdp_disconnect (p_ccb, SDP_INVALID_CONT_STATE);
+ return;
+ }
+ cont_request_needed = TRUE;
+ }
+ else
+ {
+
+#if (SDP_RAW_DATA_INCLUDED == TRUE)
+ SDP_TRACE_WARNING0("process_service_attr_rsp");
+ sdp_copy_raw_data (p_ccb, len, FALSE);
+#endif
+
+ /* Save the response in the database. Stop on any error */
+ if (!save_attr_seq (p_ccb, &p_ccb->rsp_list[0], &p_ccb->rsp_list[p_ccb->list_len]))
+ {
+ sdp_disconnect (p_ccb, SDP_DB_FULL);
+ return;
+ }
+ p_ccb->list_len = 0;
+ p_ccb->cur_handle++;
+ }
+ }
+
+ /* Now, ask for the next handle. Re-use the buffer we just got. */
+ if (p_ccb->cur_handle < p_ccb->num_handles)
+ {
+ BT_HDR *p_msg = (BT_HDR *) GKI_getpoolbuf (SDP_POOL_ID);
+ UINT8 *p;
+
+ if (!p_msg)
+ {
+ sdp_disconnect (p_ccb, SDP_NO_RESOURCES);
+ return;
+ }
+
+ p_msg->offset = L2CAP_MIN_OFFSET;
+ p = p_start = (UINT8 *)(p_msg + 1) + L2CAP_MIN_OFFSET;
+
+ /* Get all the attributes from the server */
+ UINT8_TO_BE_STREAM (p, SDP_PDU_SERVICE_ATTR_REQ);
+ UINT16_TO_BE_STREAM (p, p_ccb->transaction_id);
+ p_ccb->transaction_id++;
+
+ /* Skip the length, we need to add it at the end */
+ p_param_len = p;
+ p += 2;
+
+ UINT32_TO_BE_STREAM (p, p_ccb->handles[p_ccb->cur_handle]);
+
+ /* Max attribute byte count */
+ UINT16_TO_BE_STREAM (p, sdp_cb.max_attr_list_size);
+
+ /* If no attribute filters, build a wildcard attribute sequence */
+ if (p_ccb->p_db->num_attr_filters)
+ p = sdpu_build_attrib_seq (p, p_ccb->p_db->attr_filters, p_ccb->p_db->num_attr_filters);
+ else
+ p = sdpu_build_attrib_seq (p, NULL, 0);
+
+ /* Was this a continuation request ? */
+ if (cont_request_needed)
+ {
+ memcpy (p, p_reply, *p_reply + 1);
+ p += *p_reply + 1;
+ }
+ else
+ UINT8_TO_BE_STREAM (p, 0);
+
+ /* Go back and put the parameter length into the buffer */
+ param_len = (UINT16)(p - p_param_len - 2);
+ UINT16_TO_BE_STREAM (p_param_len, param_len);
+
+ /* Set the length of the SDP data in the buffer */
+ p_msg->len = (UINT16)(p - p_start);
+
+
+ L2CA_DataWrite (p_ccb->connection_id, p_msg);
+
+ /* Start inactivity timer */
+ btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_SDP, SDP_INACT_TIMEOUT);
+ }
+ else
+ {
+ sdp_disconnect (p_ccb, SDP_SUCCESS);
+ return;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function process_service_search_attr_rsp
+**
+** Description This function is called when there is a search attribute
+** response from the server.
+**
+** Returns void
+**
+*******************************************************************************/
+static void process_service_search_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply, UINT16 len)
+{
+ UINT8 *p, *p_start, *p_end, *p_param_len;
+ UINT8 type;
+ UINT32 seq_len;
+ UINT16 param_len, lists_byte_count = 0;
+ BOOLEAN cont_request_needed = FALSE;
+
+#if (SDP_DEBUG_RAW == TRUE)
+ SDP_TRACE_WARNING1("process_service_search_attr_rsp len:%d", len);
+#endif
+ /* If p_reply is NULL, we were called for the initial read */
+ if (p_reply)
+ {
+#if (SDP_DEBUG_RAW == TRUE)
+ SDP_TRACE_WARNING4("ID & len: 0x%02x-%02x-%02x-%02x",
+ p_reply[0], p_reply[1], p_reply[2], p_reply[3]);
+#endif
+ /* Skip transaction ID and length */
+ p_reply += 4;
+
+ BE_STREAM_TO_UINT16 (lists_byte_count, p_reply);
+#if (SDP_DEBUG_RAW == TRUE)
+ SDP_TRACE_WARNING1("lists_byte_count:%d", lists_byte_count);
+#endif
+
+ /* Copy the response to the scratchpad. First, a safety check on the length */
+ if ((p_ccb->list_len + lists_byte_count) > SDP_MAX_LIST_BYTE_COUNT)
+ {
+ sdp_disconnect (p_ccb, SDP_INVALID_PDU_SIZE);
+ return;
+ }
+
+#if (SDP_DEBUG_RAW == TRUE)
+ SDP_TRACE_WARNING2("list_len: %d, list_byte_count: %d",
+ p_ccb->list_len, lists_byte_count);
+#endif
+ if (p_ccb->rsp_list == NULL)
+ {
+ p_ccb->rsp_list = (UINT8 *)GKI_getbuf (SDP_MAX_LIST_BYTE_COUNT);
+ if (p_ccb->rsp_list == NULL)
+ {
+ SDP_TRACE_ERROR0 ("SDP - no gki buf to save rsp");
+ sdp_disconnect (p_ccb, SDP_NO_RESOURCES);
+ return;
+ }
+ }
+ memcpy (&p_ccb->rsp_list[p_ccb->list_len], p_reply, lists_byte_count);
+ p_ccb->list_len += lists_byte_count;
+ p_reply += lists_byte_count;
+#if (SDP_DEBUG_RAW == TRUE)
+ SDP_TRACE_WARNING1("list_len: %d(search_attr_rsp)", p_ccb->list_len);
+
+ /* Check if we need to request a continuation */
+ SDP_TRACE_WARNING2("*p_reply:%d(%d)", *p_reply, SDP_MAX_CONTINUATION_LEN);
+#endif
+ if (*p_reply)
+ {
+ if (*p_reply > SDP_MAX_CONTINUATION_LEN)
+ {
+ sdp_disconnect (p_ccb, SDP_INVALID_CONT_STATE);
+ return;
+ }
+
+ cont_request_needed = TRUE;
+ }
+ }
+
+#if (SDP_DEBUG_RAW == TRUE)
+ SDP_TRACE_WARNING1("cont_request_needed:%d", cont_request_needed);
+#endif
+ /* If continuation request (or first time request) */
+ if ((cont_request_needed) || (!p_reply))
+ {
+ BT_HDR *p_msg = (BT_HDR *) GKI_getpoolbuf (SDP_POOL_ID);
+ UINT8 *p;
+
+ if (!p_msg)
+ {
+ sdp_disconnect (p_ccb, SDP_NO_RESOURCES);
+ return;
+ }
+
+ p_msg->offset = L2CAP_MIN_OFFSET;
+ p = p_start = (UINT8 *)(p_msg + 1) + L2CAP_MIN_OFFSET;
+
+ /* Build a service search request packet */
+ UINT8_TO_BE_STREAM (p, SDP_PDU_SERVICE_SEARCH_ATTR_REQ);
+ UINT16_TO_BE_STREAM (p, p_ccb->transaction_id);
+ p_ccb->transaction_id++;
+
+ /* Skip the length, we need to add it at the end */
+ p_param_len = p;
+ p += 2;
+
+ /* Build the UID sequence. */
+#if (defined(SDP_BROWSE_PLUS) && SDP_BROWSE_PLUS == TRUE)
+ p = sdpu_build_uuid_seq (p, 1, &p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx]);
+#else
+ p = sdpu_build_uuid_seq (p, p_ccb->p_db->num_uuid_filters, p_ccb->p_db->uuid_filters);
+#endif
+
+ /* Max attribute byte count */
+ UINT16_TO_BE_STREAM (p, sdp_cb.max_attr_list_size);
+
+ /* If no attribute filters, build a wildcard attribute sequence */
+ if (p_ccb->p_db->num_attr_filters)
+ p = sdpu_build_attrib_seq (p, p_ccb->p_db->attr_filters, p_ccb->p_db->num_attr_filters);
+ else
+ p = sdpu_build_attrib_seq (p, NULL, 0);
+
+ /* No continuation for first request */
+ if (p_reply)
+ {
+ memcpy (p, p_reply, *p_reply + 1);
+ p += *p_reply + 1;
+ }
+ else
+ UINT8_TO_BE_STREAM (p, 0);
+
+ /* Go back and put the parameter length into the buffer */
+ param_len = p - p_param_len - 2;
+ UINT16_TO_BE_STREAM (p_param_len, param_len);
+
+ /* Set the length of the SDP data in the buffer */
+ p_msg->len = p - p_start;
+
+
+ L2CA_DataWrite (p_ccb->connection_id, p_msg);
+
+ /* Start inactivity timer */
+ btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_SDP, SDP_INACT_TIMEOUT);
+
+ return;
+ }
+
+
+ /*******************************************************************/
+ /* We now have the full response, which is a sequence of sequences */
+ /*******************************************************************/
+
+#if (SDP_RAW_DATA_INCLUDED == TRUE)
+ SDP_TRACE_WARNING0("process_service_search_attr_rsp");
+ sdp_copy_raw_data (p_ccb, len, TRUE);
+#endif
+
+ p = &p_ccb->rsp_list[0];
+
+ /* The contents is a sequence of attribute sequences */
+ type = *p++;
+
+ if ((type >> 3) != DATA_ELE_SEQ_DESC_TYPE)
+ {
+ SDP_TRACE_WARNING1 ("SDP - Wrong type: 0x%02x in attr_rsp", type);
+ return;
+ }
+ p = sdpu_get_len_from_type (p, type, &seq_len);
+
+ p_end = &p_ccb->rsp_list[p_ccb->list_len];
+
+ if ((p + seq_len) != p_end)
+ {
+ sdp_disconnect (p_ccb, SDP_INVALID_CONT_STATE);
+ return;
+ }
+
+ while (p < p_end)
+ {
+ p = save_attr_seq (p_ccb, p, &p_ccb->rsp_list[p_ccb->list_len]);
+ if (!p)
+ {
+ sdp_disconnect (p_ccb, SDP_DB_FULL);
+ return;
+ }
+ }
+
+ /* Since we got everything we need, disconnect the call */
+ sdp_disconnect (p_ccb, SDP_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function save_attr_seq
+**
+** Description This function is called when there is a response from
+** the server.
+**
+** Returns pointer to next byte or NULL if error
+**
+*******************************************************************************/
+static UINT8 *save_attr_seq (tCONN_CB *p_ccb, UINT8 *p, UINT8 *p_msg_end)
+{
+ UINT32 seq_len, attr_len;
+ UINT16 attr_id;
+ UINT8 type, *p_seq_end;
+ tSDP_DISC_REC *p_rec;
+
+ type = *p++;
+
+ if ((type >> 3) != DATA_ELE_SEQ_DESC_TYPE)
+ {
+ SDP_TRACE_WARNING1 ("SDP - Wrong type: 0x%02x in attr_rsp", type);
+ return (NULL);
+ }
+
+ p = sdpu_get_len_from_type (p, type, &seq_len);
+ if ((p + seq_len) > p_msg_end)
+ {
+ SDP_TRACE_WARNING1 ("SDP - Bad len in attr_rsp %d", seq_len);
+ return (NULL);
+ }
+
+ /* Create a record */
+ p_rec = add_record (p_ccb->p_db, p_ccb->device_address);
+ if (!p_rec)
+ {
+ SDP_TRACE_WARNING0 ("SDP - DB full add_record");
+ return (NULL);
+ }
+
+ p_seq_end = p + seq_len;
+
+ while (p < p_seq_end)
+ {
+ /* First get the attribute ID */
+ type = *p++;
+ p = sdpu_get_len_from_type (p, type, &attr_len);
+ if (((type >> 3) != UINT_DESC_TYPE) || (attr_len != 2))
+ {
+ SDP_TRACE_WARNING2 ("SDP - Bad type: 0x%02x or len: %d in attr_rsp", type, attr_len);
+ return (NULL);
+ }
+ BE_STREAM_TO_UINT16 (attr_id, p);
+
+ /* Now, add the attribute value */
+ p = add_attr (p, p_ccb->p_db, p_rec, attr_id, NULL, 0);
+
+ if (!p)
+ {
+ SDP_TRACE_WARNING0 ("SDP - DB full add_attr");
+ return (NULL);
+ }
+ }
+
+ return (p);
+}
+
+
+/*******************************************************************************
+**
+** Function add_record
+**
+** Description This function allocates space for a record from the DB.
+**
+** Returns pointer to next byte in data stream
+**
+*******************************************************************************/
+tSDP_DISC_REC *add_record (tSDP_DISCOVERY_DB *p_db, BD_ADDR p_bda)
+{
+ tSDP_DISC_REC *p_rec;
+
+ /* See if there is enough space in the database */
+ if (p_db->mem_free < sizeof (tSDP_DISC_REC))
+ return (NULL);
+
+ p_rec = (tSDP_DISC_REC *) p_db->p_free_mem;
+ p_db->p_free_mem += sizeof (tSDP_DISC_REC);
+ p_db->mem_free -= sizeof (tSDP_DISC_REC);
+
+ p_rec->p_first_attr = NULL;
+ p_rec->p_next_rec = NULL;
+
+ memcpy (p_rec->remote_bd_addr, p_bda, BD_ADDR_LEN);
+
+ /* Add the record to the end of chain */
+ if (!p_db->p_first_rec)
+ p_db->p_first_rec = p_rec;
+ else
+ {
+ tSDP_DISC_REC *p_rec1 = p_db->p_first_rec;
+
+ while (p_rec1->p_next_rec)
+ p_rec1 = p_rec1->p_next_rec;
+
+ p_rec1->p_next_rec = p_rec;
+ }
+
+ return (p_rec);
+}
+
+#define SDP_ADDITIONAL_LIST_MASK 0x80
+/*******************************************************************************
+**
+** Function add_attr
+**
+** Description This function allocates space for an attribute from the DB
+** and copies the data into it.
+**
+** Returns pointer to next byte in data stream
+**
+*******************************************************************************/
+static UINT8 *add_attr (UINT8 *p, tSDP_DISCOVERY_DB *p_db, tSDP_DISC_REC *p_rec,
+ UINT16 attr_id, tSDP_DISC_ATTR *p_parent_attr, UINT8 nest_level)
+{
+ tSDP_DISC_ATTR *p_attr;
+ UINT32 attr_len;
+ UINT32 total_len;
+ UINT16 attr_type;
+ UINT16 id;
+ UINT8 type;
+ UINT8 *p_end;
+ UINT8 is_additional_list = nest_level & SDP_ADDITIONAL_LIST_MASK;
+
+ nest_level &= ~(SDP_ADDITIONAL_LIST_MASK);
+
+ type = *p++;
+ p = sdpu_get_len_from_type (p, type, &attr_len);
+
+ attr_len &= SDP_DISC_ATTR_LEN_MASK;
+ attr_type = (type >> 3) & 0x0f;
+
+ /* See if there is enough space in the database */
+ if (attr_len > 4)
+ total_len = attr_len - 4 + (UINT16)sizeof (tSDP_DISC_ATTR);
+ else
+ total_len = sizeof (tSDP_DISC_ATTR);
+
+ /* Ensure it is a multiple of 4 */
+ total_len = (total_len + 3) & ~3;
+
+ /* See if there is enough space in the database */
+ if (p_db->mem_free < total_len)
+ return (NULL);
+
+ p_attr = (tSDP_DISC_ATTR *) p_db->p_free_mem;
+ p_attr->attr_id = attr_id;
+ p_attr->attr_len_type = (UINT16)attr_len | (attr_type << 12);
+ p_attr->p_next_attr = NULL;
+
+ /* Store the attribute value */
+ switch (attr_type)
+ {
+ case UINT_DESC_TYPE:
+ if( (is_additional_list != 0) && (attr_len == 2) )
+ {
+ BE_STREAM_TO_UINT16 (id, p);
+ if(id != ATTR_ID_PROTOCOL_DESC_LIST)
+ p -= 2;
+ else
+ {
+ /* Reserve the memory for the attribute now, as we need to add sub-attributes */
+ p_db->p_free_mem += sizeof (tSDP_DISC_ATTR);
+ p_db->mem_free -= sizeof (tSDP_DISC_ATTR);
+ p_end = p + attr_len;
+ total_len = 0;
+
+ /* SDP_TRACE_DEBUG1 ("SDP - attr nest level:%d(list)", nest_level); */
+ if (nest_level >= MAX_NEST_LEVELS)
+ {
+ SDP_TRACE_ERROR0 ("SDP - attr nesting too deep");
+ return (p_end);
+ }
+
+ /* Now, add the list entry */
+ p = add_attr (p, p_db, p_rec, ATTR_ID_PROTOCOL_DESC_LIST, p_attr, (UINT8)(nest_level + 1));
+
+ break;
+ }
+ }
+ /* Case falls through */
+
+ case TWO_COMP_INT_DESC_TYPE:
+ switch (attr_len)
+ {
+ case 1:
+ p_attr->attr_value.v.u8 = *p++;
+ break;
+ case 2:
+ BE_STREAM_TO_UINT16 (p_attr->attr_value.v.u16, p);
+ break;
+ case 4:
+ BE_STREAM_TO_UINT32 (p_attr->attr_value.v.u32, p);
+ break;
+ default:
+ BE_STREAM_TO_ARRAY (p, p_attr->attr_value.v.array, (INT32)attr_len);
+ break;
+ }
+ break;
+
+ case UUID_DESC_TYPE:
+ switch (attr_len)
+ {
+ case 2:
+ BE_STREAM_TO_UINT16 (p_attr->attr_value.v.u16, p);
+ break;
+ case 4:
+ BE_STREAM_TO_UINT32 (p_attr->attr_value.v.u32, p);
+ if (p_attr->attr_value.v.u32 < 0x10000)
+ {
+ attr_len = 2;
+ p_attr->attr_len_type = (UINT16)attr_len | (attr_type << 12);
+ p_attr->attr_value.v.u16 = (UINT16) p_attr->attr_value.v.u32;
+
+ }
+ break;
+ case 16:
+ /* See if we can compress his UUID down to 16 or 32bit UUIDs */
+ if (sdpu_is_base_uuid (p))
+ {
+ if ((p[0] == 0) && (p[1] == 0))
+ {
+ p_attr->attr_len_type = (p_attr->attr_len_type & ~SDP_DISC_ATTR_LEN_MASK) | 2;
+ p += 2;
+ BE_STREAM_TO_UINT16 (p_attr->attr_value.v.u16, p);
+ p += MAX_UUID_SIZE - 4;
+ }
+ else
+ {
+ p_attr->attr_len_type = (p_attr->attr_len_type & ~SDP_DISC_ATTR_LEN_MASK) | 4;
+ BE_STREAM_TO_UINT32 (p_attr->attr_value.v.u32, p);
+ p += MAX_UUID_SIZE - 4;
+ }
+ }
+ else
+ {
+ /* coverity[overrun-local] */
+ /*
+ Event overrun-local: Overrun of static array "p_attr->attr_value.v.array" of size 4 at position 15 with index variable "ijk"
+ False-positive: SDP uses scratch buffer to hold the attribute value.
+ The actual size of tSDP_DISC_ATVAL does not matter.
+ If the array size in tSDP_DISC_ATVAL is increase, we would increase the system RAM usage unnecessarily
+ */
+ BE_STREAM_TO_ARRAY (p, p_attr->attr_value.v.array, (INT32)attr_len);
+ }
+ break;
+ default:
+ SDP_TRACE_WARNING1 ("SDP - bad len in UUID attr: %d", attr_len);
+ return (p + attr_len);
+ }
+ break;
+
+ case DATA_ELE_SEQ_DESC_TYPE:
+ case DATA_ELE_ALT_DESC_TYPE:
+ /* Reserve the memory for the attribute now, as we need to add sub-attributes */
+ p_db->p_free_mem += sizeof (tSDP_DISC_ATTR);
+ p_db->mem_free -= sizeof (tSDP_DISC_ATTR);
+ p_end = p + attr_len;
+ total_len = 0;
+
+ /* SDP_TRACE_DEBUG1 ("SDP - attr nest level:%d", nest_level); */
+ if (nest_level >= MAX_NEST_LEVELS)
+ {
+ SDP_TRACE_ERROR0 ("SDP - attr nesting too deep");
+ return (p_end);
+ }
+ if(is_additional_list != 0 || attr_id == ATTR_ID_ADDITION_PROTO_DESC_LISTS)
+ nest_level |= SDP_ADDITIONAL_LIST_MASK;
+ /* SDP_TRACE_DEBUG1 ("SDP - attr nest level:0x%x(finish)", nest_level); */
+
+ while (p < p_end)
+ {
+ /* Now, add the list entry */
+ p = add_attr (p, p_db, p_rec, 0, p_attr, (UINT8)(nest_level + 1));
+
+ if (!p)
+ return (NULL);
+ }
+ break;
+
+ case TEXT_STR_DESC_TYPE:
+ case URL_DESC_TYPE:
+ BE_STREAM_TO_ARRAY (p, p_attr->attr_value.v.array, (INT32)attr_len);
+ break;
+
+ case BOOLEAN_DESC_TYPE:
+ switch (attr_len)
+ {
+ case 1:
+ p_attr->attr_value.v.u8 = *p++;
+ break;
+ default:
+ SDP_TRACE_WARNING1 ("SDP - bad len in boolean attr: %d", attr_len);
+ return (p + attr_len);
+ }
+ break;
+
+ default: /* switch (attr_type) */
+ break;
+ }
+
+ p_db->p_free_mem += total_len;
+ p_db->mem_free -= total_len;
+
+ /* Add the attribute to the end of the chain */
+ if (!p_parent_attr)
+ {
+ if (!p_rec->p_first_attr)
+ p_rec->p_first_attr = p_attr;
+ else
+ {
+ tSDP_DISC_ATTR *p_attr1 = p_rec->p_first_attr;
+
+ while (p_attr1->p_next_attr)
+ p_attr1 = p_attr1->p_next_attr;
+
+ p_attr1->p_next_attr = p_attr;
+ }
+ }
+ else
+ {
+ if (!p_parent_attr->attr_value.v.p_sub_attr)
+ {
+ p_parent_attr->attr_value.v.p_sub_attr = p_attr;
+ /* SDP_TRACE_DEBUG4 ("parent:0x%x(id:%d), ch:0x%x(id:%d)",
+ p_parent_attr, p_parent_attr->attr_id, p_attr, p_attr->attr_id); */
+ }
+ else
+ {
+ tSDP_DISC_ATTR *p_attr1 = p_parent_attr->attr_value.v.p_sub_attr;
+ /* SDP_TRACE_DEBUG4 ("parent:0x%x(id:%d), ch1:0x%x(id:%d)",
+ p_parent_attr, p_parent_attr->attr_id, p_attr1, p_attr1->attr_id); */
+
+ while (p_attr1->p_next_attr)
+ p_attr1 = p_attr1->p_next_attr;
+
+ p_attr1->p_next_attr = p_attr;
+ /* SDP_TRACE_DEBUG2 ("new ch:0x%x(id:%d)", p_attr, p_attr->attr_id); */
+ }
+ }
+
+ return (p);
+}
+
+#endif /* CLIENT_ENABLED == TRUE */
diff --git a/stack/sdp/sdp_main.c b/stack/sdp/sdp_main.c
new file mode 100644
index 0000000..8a9f6c5
--- /dev/null
+++ b/stack/sdp/sdp_main.c
@@ -0,0 +1,694 @@
+/*****************************************************************************/
+/* */
+/* Name: sdp_main.c */
+/* */
+/* Description: this file contains the main SDP functions */
+/* */
+/* Copyright (c) 1999-2009, Broadcom Corp., All Rights Reserved. */
+/* Broadcom Bluetooth Core. Proprietary and confidential. */
+/*****************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "bt_target.h"
+#include "gki.h"
+#include "l2cdefs.h"
+#include "hcidefs.h"
+#include "hcimsgs.h"
+
+#include "l2c_api.h"
+#include "l2cdefs.h"
+
+#include "btu.h"
+#include "btm_api.h"
+
+#include "sdp_api.h"
+#include "sdpint.h"
+
+
+/********************************************************************************/
+/* G L O B A L S D P D A T A */
+/********************************************************************************/
+#if SDP_DYNAMIC_MEMORY == FALSE
+tSDP_CB sdp_cb;
+#endif
+
+/********************************************************************************/
+/* L O C A L F U N C T I O N P R O T O T Y P E S */
+/********************************************************************************/
+static void sdp_connect_ind (BD_ADDR bd_addr, UINT16 l2cap_cid, UINT16 psm,
+ UINT8 l2cap_id);
+static void sdp_config_ind (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg);
+static void sdp_config_cfm (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg);
+static void sdp_disconnect_ind (UINT16 l2cap_cid, BOOLEAN ack_needed);
+static void sdp_data_ind (UINT16 l2cap_cid, BT_HDR *p_msg);
+
+#if SDP_CLIENT_ENABLED == TRUE
+static void sdp_connect_cfm (UINT16 l2cap_cid, UINT16 result);
+static void sdp_disconnect_cfm (UINT16 l2cap_cid, UINT16 result);
+#else
+#define sdp_connect_cfm NULL
+#define sdp_disconnect_cfm NULL
+#endif
+
+
+/*******************************************************************************
+**
+** Function sdp_init
+**
+** Description This function initializes the SDP unit.
+**
+** Returns void
+**
+*******************************************************************************/
+void sdp_init (void)
+{
+ /* Clears all structures and local SDP database (if Server is enabled) */
+ memset (&sdp_cb, 0, sizeof (tSDP_CB));
+
+ /* Initialize the L2CAP configuration. We only care about MTU and flush */
+ sdp_cb.l2cap_my_cfg.mtu_present = TRUE;
+ sdp_cb.l2cap_my_cfg.mtu = SDP_MTU_SIZE;
+ sdp_cb.l2cap_my_cfg.flush_to_present = TRUE;
+ sdp_cb.l2cap_my_cfg.flush_to = SDP_FLUSH_TO;
+
+ sdp_cb.max_attr_list_size = SDP_MTU_SIZE - 16;
+ sdp_cb.max_recs_per_search = SDP_MAX_DISC_SERVER_RECS;
+
+#if SDP_SERVER_ENABLED == TRUE
+ /* Register with Security Manager for the specific security level */
+ if (!BTM_SetSecurityLevel (FALSE, SDP_SERVICE_NAME, BTM_SEC_SERVICE_SDP_SERVER,
+ SDP_SECURITY_LEVEL, SDP_PSM, 0, 0))
+ {
+ SDP_TRACE_ERROR0 ("Security Registration Server failed");
+ return;
+ }
+#endif
+
+#if SDP_CLIENT_ENABLED == TRUE
+ /* Register with Security Manager for the specific security level */
+ if (!BTM_SetSecurityLevel (TRUE, SDP_SERVICE_NAME, BTM_SEC_SERVICE_SDP_SERVER,
+ SDP_SECURITY_LEVEL, SDP_PSM, 0, 0))
+ {
+ SDP_TRACE_ERROR0 ("Security Registration for Client failed");
+ return;
+ }
+#endif
+
+#if defined(SDP_INITIAL_TRACE_LEVEL)
+ sdp_cb.trace_level = SDP_INITIAL_TRACE_LEVEL;
+#else
+ sdp_cb.trace_level = BT_TRACE_LEVEL_NONE; /* No traces */
+#endif
+
+ sdp_cb.reg_info.pL2CA_ConnectInd_Cb = sdp_connect_ind;
+ sdp_cb.reg_info.pL2CA_ConnectCfm_Cb = sdp_connect_cfm;
+ sdp_cb.reg_info.pL2CA_ConnectPnd_Cb = NULL;
+ sdp_cb.reg_info.pL2CA_ConfigInd_Cb = sdp_config_ind;
+ sdp_cb.reg_info.pL2CA_ConfigCfm_Cb = sdp_config_cfm;
+ sdp_cb.reg_info.pL2CA_DisconnectInd_Cb = sdp_disconnect_ind;
+ sdp_cb.reg_info.pL2CA_DisconnectCfm_Cb = sdp_disconnect_cfm;
+ sdp_cb.reg_info.pL2CA_QoSViolationInd_Cb = NULL;
+ sdp_cb.reg_info.pL2CA_DataInd_Cb = sdp_data_ind;
+ sdp_cb.reg_info.pL2CA_CongestionStatus_Cb = NULL;
+ sdp_cb.reg_info.pL2CA_TxComplete_Cb = NULL;
+
+ /* Now, register with L2CAP */
+ if (!L2CA_Register (SDP_PSM, &sdp_cb.reg_info))
+ {
+ SDP_TRACE_ERROR0 ("SDP Registration failed");
+ }
+}
+
+#if (defined(SDP_DEBUG) && SDP_DEBUG == TRUE)
+/*******************************************************************************
+**
+** Function sdp_set_max_attr_list_size
+**
+** Description This function sets the max attribute list size to use
+**
+** Returns void
+**
+*******************************************************************************/
+UINT16 sdp_set_max_attr_list_size (UINT16 max_size)
+{
+ if (max_size > (sdp_cb.l2cap_my_cfg.mtu - 16) )
+ max_size = sdp_cb.l2cap_my_cfg.mtu - 16;
+
+ sdp_cb.max_attr_list_size = max_size;
+
+ return sdp_cb.max_attr_list_size;
+}
+#endif
+
+/*******************************************************************************
+**
+** Function sdp_connect_ind
+**
+** Description This function handles an inbound connection indication
+** from L2CAP. This is the case where we are acting as a
+** server.
+**
+** Returns void
+**
+*******************************************************************************/
+static void sdp_connect_ind (BD_ADDR bd_addr, UINT16 l2cap_cid, UINT16 psm, UINT8 l2cap_id)
+{
+#if SDP_SERVER_ENABLED == TRUE
+ tCONN_CB *p_ccb;
+
+ /* Allocate a new CCB. Return if none available. */
+ if ((p_ccb = sdpu_allocate_ccb()) == NULL)
+ return;
+
+ /* Transition to the next appropriate state, waiting for config setup. */
+ p_ccb->con_state = SDP_STATE_CFG_SETUP;
+
+ /* Save the BD Address and Channel ID. */
+ memcpy (&p_ccb->device_address[0], bd_addr, sizeof (BD_ADDR));
+ p_ccb->connection_id = l2cap_cid;
+
+ /* Send response to the L2CAP layer. */
+ L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_OK, L2CAP_CONN_OK);
+ {
+ tL2CAP_CFG_INFO cfg = sdp_cb.l2cap_my_cfg;
+
+ if (cfg.fcr_present)
+ {
+ SDP_TRACE_DEBUG6("sdp_connect_ind: mode %u, txwinsz %u, max_trans %u, rtrans_tout %u, mon_tout %u, mps %u",
+ cfg.fcr.mode, cfg.fcr.tx_win_sz, cfg.fcr.max_transmit,
+ cfg.fcr.rtrans_tout,cfg.fcr.mon_tout, cfg.fcr.mps);
+ }
+
+ if ((!L2CA_ConfigReq (l2cap_cid, &cfg)) && cfg.fcr_present
+ && cfg.fcr.mode != L2CAP_FCR_BASIC_MODE)
+ {
+ /* FCR not desired; try again in basic mode */
+ cfg.fcr.mode = L2CAP_FCR_BASIC_MODE;
+ cfg.fcr_present = FALSE;
+ L2CA_ConfigReq (l2cap_cid, &cfg);
+ }
+ }
+
+ SDP_TRACE_EVENT1 ("SDP - Rcvd L2CAP conn ind, sent config req, CID 0x%x", p_ccb->connection_id);
+#else /* No server */
+ /* Reject the connection */
+ L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_NO_PSM, 0);
+#endif
+}
+
+#if SDP_CLIENT_ENABLED == TRUE
+/*******************************************************************************
+**
+** Function sdp_connect_cfm
+**
+** Description This function handles the connect confirm events
+** from L2CAP. This is the case when we are acting as a
+** client and have sent a connect request.
+**
+** Returns void
+**
+*******************************************************************************/
+static void sdp_connect_cfm (UINT16 l2cap_cid, UINT16 result)
+{
+ tCONN_CB *p_ccb;
+ tL2CAP_CFG_INFO cfg;
+
+ /* Find CCB based on CID */
+ if ((p_ccb = sdpu_find_ccb_by_cid (l2cap_cid)) == NULL)
+ {
+ SDP_TRACE_WARNING1 ("SDP - Rcvd conn cnf for unknown CID 0x%x", l2cap_cid);
+ return;
+ }
+
+ /* If the connection response contains success status, then */
+ /* Transition to the next state and startup the timer. */
+ if ((result == L2CAP_CONN_OK) && (p_ccb->con_state == SDP_STATE_CONN_SETUP))
+ {
+ p_ccb->con_state = SDP_STATE_CFG_SETUP;
+
+ cfg = sdp_cb.l2cap_my_cfg;
+
+ if (cfg.fcr_present)
+ {
+ SDP_TRACE_DEBUG6("sdp_connect_cfm: mode %u, txwinsz %u, max_trans %u, rtrans_tout %u, mon_tout %u, mps %u",
+ cfg.fcr.mode, cfg.fcr.tx_win_sz, cfg.fcr.max_transmit,
+ cfg.fcr.rtrans_tout,cfg.fcr.mon_tout, cfg.fcr.mps);
+ }
+
+ if ((!L2CA_ConfigReq (l2cap_cid, &cfg)) && cfg.fcr_present
+ && cfg.fcr.mode != L2CAP_FCR_BASIC_MODE)
+ {
+ /* FCR not desired; try again in basic mode */
+ cfg.fcr_present = FALSE;
+ cfg.fcr.mode = L2CAP_FCR_BASIC_MODE;
+ L2CA_ConfigReq (l2cap_cid, &cfg);
+ }
+
+ SDP_TRACE_EVENT1 ("SDP - got conn cnf, sent cfg req, CID: 0x%x", p_ccb->connection_id);
+ }
+ else
+ {
+ SDP_TRACE_WARNING2 ("SDP - Rcvd conn cnf with error: 0x%x CID 0x%x", result, p_ccb->connection_id);
+
+ /* Tell the user if he has a callback */
+ if (p_ccb->p_cb)
+ {
+ if ((result == HCI_ERR_HOST_REJECT_SECURITY)
+ || (result == HCI_ERR_AUTH_FAILURE)
+ || (result == HCI_ERR_PAIRING_NOT_ALLOWED)
+ || (result == HCI_ERR_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED)
+ || (result == HCI_ERR_KEY_MISSING))
+ (*p_ccb->p_cb) (SDP_SECURITY_ERR);
+ else if (result == HCI_ERR_HOST_REJECT_DEVICE)
+ (*p_ccb->p_cb) (SDP_CONN_REJECTED);
+ else
+ (*p_ccb->p_cb) (SDP_CONN_FAILED);
+ }
+
+ sdpu_release_ccb (p_ccb);
+ }
+}
+#endif /* SDP_CLIENT_ENABLED == TRUE */
+
+
+/*******************************************************************************
+**
+** Function sdp_config_ind
+**
+** Description This function processes the L2CAP configuration indication
+** event.
+**
+** Returns void
+**
+*******************************************************************************/
+static void sdp_config_ind (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg)
+{
+ tCONN_CB *p_ccb;
+
+ /* Find CCB based on CID */
+ if ((p_ccb = sdpu_find_ccb_by_cid (l2cap_cid)) == NULL)
+ {
+ SDP_TRACE_WARNING1 ("SDP - Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid);
+ return;
+ }
+
+ /* Remember the remote MTU size */
+ if (!p_cfg->mtu_present)
+ {
+ /* use min(L2CAP_DEFAULT_MTU,SDP_MTU_SIZE) for GKI buffer size reasons */
+ p_ccb->rem_mtu_size = (L2CAP_DEFAULT_MTU > SDP_MTU_SIZE)?SDP_MTU_SIZE:L2CAP_DEFAULT_MTU;
+ }
+ else
+ {
+ if (p_cfg->mtu > SDP_MTU_SIZE)
+ p_ccb->rem_mtu_size = SDP_MTU_SIZE;
+ else
+ p_ccb->rem_mtu_size = p_cfg->mtu;
+ }
+
+ /* For now, always accept configuration from the other side */
+ p_cfg->flush_to_present = FALSE;
+ p_cfg->mtu_present = FALSE;
+ p_cfg->result = L2CAP_CFG_OK;
+
+ /* Check peer config request against our rfcomm configuration */
+ if (p_cfg->fcr_present)
+ {
+ /* Reject the window size if it is bigger than we want it to be */
+ if (p_cfg->fcr.mode != L2CAP_FCR_BASIC_MODE)
+ {
+ if (sdp_cb.l2cap_my_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE
+ && p_cfg->fcr.tx_win_sz > sdp_cb.l2cap_my_cfg.fcr.tx_win_sz)
+ {
+ p_cfg->fcr.tx_win_sz = sdp_cb.l2cap_my_cfg.fcr.tx_win_sz;
+ p_cfg->result = L2CAP_CFG_UNACCEPTABLE_PARAMS;
+ SDP_TRACE_DEBUG0("sdp_config_ind(CONFIG) -> Please try again with SMALLER TX WINDOW");
+ }
+
+ /* Reject if locally we want basic and they don't */
+ if (sdp_cb.l2cap_my_cfg.fcr.mode == L2CAP_FCR_BASIC_MODE)
+ {
+ /* Ask for a new setup */
+ p_cfg->fcr.mode = L2CAP_FCR_BASIC_MODE;
+ p_cfg->result = L2CAP_CFG_UNACCEPTABLE_PARAMS;
+ SDP_TRACE_DEBUG0("sdp_config_ind(CONFIG) -> Please try again with BASIC mode");
+ }
+ /* Remain in configure state and give the peer our desired configuration */
+ if (p_cfg->result != L2CAP_CFG_OK)
+ {
+ SDP_TRACE_WARNING1 ("SDP - Rcvd cfg ind, Unacceptable Parameters sent cfg cfm, CID: 0x%x", l2cap_cid);
+ L2CA_ConfigRsp (l2cap_cid, p_cfg);
+ return;
+ }
+ }
+ else /* We agree with peer's request */
+ p_cfg->fcr_present = FALSE;
+ }
+
+ L2CA_ConfigRsp (l2cap_cid, p_cfg);
+
+ SDP_TRACE_EVENT1 ("SDP - Rcvd cfg ind, sent cfg cfm, CID: 0x%x", l2cap_cid);
+
+ p_ccb->con_flags |= SDP_FLAGS_HIS_CFG_DONE;
+
+ if (p_ccb->con_flags & SDP_FLAGS_MY_CFG_DONE)
+ {
+ p_ccb->con_state = SDP_STATE_CONNECTED;
+
+ if (p_ccb->con_flags & SDP_FLAGS_IS_ORIG)
+ sdp_disc_connected (p_ccb);
+ else
+ /* Start inactivity timer */
+ btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_SDP, SDP_INACT_TIMEOUT);
+ }
+
+}
+
+
+/*******************************************************************************
+**
+** Function sdp_config_cfm
+**
+** Description This function processes the L2CAP configuration confirmation
+** event.
+**
+** Returns void
+**
+*******************************************************************************/
+static void sdp_config_cfm (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg)
+{
+ tCONN_CB *p_ccb;
+
+ SDP_TRACE_EVENT2 ("SDP - Rcvd cfg cfm, CID: 0x%x Result: %d", l2cap_cid, p_cfg->result);
+
+ /* Find CCB based on CID */
+ if ((p_ccb = sdpu_find_ccb_by_cid (l2cap_cid)) == NULL)
+ {
+ SDP_TRACE_WARNING1 ("SDP - Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid);
+ return;
+ }
+
+ /* For now, always accept configuration from the other side */
+ if (p_cfg->result == L2CAP_CFG_OK)
+ {
+ p_ccb->con_flags |= SDP_FLAGS_MY_CFG_DONE;
+
+ if (p_ccb->con_flags & SDP_FLAGS_HIS_CFG_DONE)
+ {
+ p_ccb->con_state = SDP_STATE_CONNECTED;
+
+ if (p_ccb->con_flags & SDP_FLAGS_IS_ORIG)
+ sdp_disc_connected (p_ccb);
+ else
+ /* Start inactivity timer */
+ btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_SDP, SDP_INACT_TIMEOUT);
+ }
+ }
+ else
+ {
+ /* If peer has rejected FCR and suggested basic then try basic */
+ if (p_cfg->fcr_present)
+ {
+ tL2CAP_CFG_INFO cfg = sdp_cb.l2cap_my_cfg;
+ cfg.fcr_present = FALSE;
+ L2CA_ConfigReq (l2cap_cid, &cfg);
+
+ /* Remain in configure state */
+ return;
+ }
+
+#if SDP_CLIENT_ENABLED == TRUE
+ sdp_disconnect(p_ccb, SDP_CFG_FAILED);
+#endif
+ }
+}
+
+/*******************************************************************************
+**
+** Function sdp_disconnect_ind
+**
+** Description This function handles a disconnect event from L2CAP. If
+** requested to, we ack the disconnect before dropping the CCB
+**
+** Returns void
+**
+*******************************************************************************/
+static void sdp_disconnect_ind (UINT16 l2cap_cid, BOOLEAN ack_needed)
+{
+ tCONN_CB *p_ccb;
+
+ /* Find CCB based on CID */
+ if ((p_ccb = sdpu_find_ccb_by_cid (l2cap_cid)) == NULL)
+ {
+ SDP_TRACE_WARNING1 ("SDP - Rcvd L2CAP disc, unknown CID: 0x%x", l2cap_cid);
+ return;
+ }
+
+ if (ack_needed)
+ L2CA_DisconnectRsp (l2cap_cid);
+
+ SDP_TRACE_EVENT1 ("SDP - Rcvd L2CAP disc, CID: 0x%x", l2cap_cid);
+#if SDP_CLIENT_ENABLED == TRUE
+ /* Tell the user if he has a callback */
+ if (p_ccb->p_cb)
+ (*p_ccb->p_cb) ((UINT16) ((p_ccb->con_state == SDP_STATE_CONNECTED) ?
+ SDP_SUCCESS : SDP_CONN_FAILED));
+#endif
+ sdpu_release_ccb (p_ccb);
+}
+
+/*******************************************************************************
+**
+** Function sdp_data_ind
+**
+** Description This function is called when data is received from L2CAP.
+** if we are the originator of the connection, we are the SDP
+** client, and the received message is queued up for the client.
+**
+** If we are the destination of the connection, we are the SDP
+** server, so the message is passed to the server processing
+** function.
+**
+** Returns void
+**
+*******************************************************************************/
+static void sdp_data_ind (UINT16 l2cap_cid, BT_HDR *p_msg)
+{
+ tCONN_CB *p_ccb;
+
+ /* Find CCB based on CID */
+ if ((p_ccb = sdpu_find_ccb_by_cid (l2cap_cid)) != NULL)
+ {
+ if (p_ccb->con_state == SDP_STATE_CONNECTED)
+ {
+ if (p_ccb->con_flags & SDP_FLAGS_IS_ORIG)
+ sdp_disc_server_rsp (p_ccb, p_msg);
+ else
+ sdp_server_handle_client_req (p_ccb, p_msg);
+ }
+ else
+ {
+ SDP_TRACE_WARNING2 ("SDP - Ignored L2CAP data while in state: %d, CID: 0x%x",
+ p_ccb->con_state, l2cap_cid);
+ }
+ }
+ else
+ {
+ SDP_TRACE_WARNING1 ("SDP - Rcvd L2CAP data, unknown CID: 0x%x", l2cap_cid);
+ }
+
+ GKI_freebuf (p_msg);
+}
+
+
+#if SDP_CLIENT_ENABLED == TRUE
+/*******************************************************************************
+**
+** Function sdp_conn_originate
+**
+** Description This function is called from the API to originate a
+** connection.
+**
+** Returns void
+**
+*******************************************************************************/
+tCONN_CB* sdp_conn_originate (UINT8 *p_bd_addr)
+{
+ tCONN_CB *p_ccb;
+ UINT16 cid;
+
+ /* Allocate a new CCB. Return if none available. */
+ if ((p_ccb = sdpu_allocate_ccb()) == NULL)
+ {
+ SDP_TRACE_WARNING0 ("SDP - no spare CCB for orig");
+ return (NULL);
+ }
+
+ SDP_TRACE_EVENT0 ("SDP - Originate started");
+
+ /* We are the originator of this connection */
+ p_ccb->con_flags |= SDP_FLAGS_IS_ORIG;
+
+ /* Save the BD Address and Channel ID. */
+ memcpy (&p_ccb->device_address[0], p_bd_addr, sizeof (BD_ADDR));
+
+ /* Transition to the next appropriate state, waiting for connection confirm. */
+ p_ccb->con_state = SDP_STATE_CONN_SETUP;
+
+// btla-specific ++
+#ifndef ANDROID_APP_INCLUDED /* Skip for Android: Do not need to set out_service for sdp, since sdp does not use sec. Prevents over-writing service_rec of a connection already in progress */
+ BTM_SetOutService(p_bd_addr, BTM_SEC_SERVICE_SDP_SERVER, 0);
+#endif
+// btla-specific --
+
+ cid = L2CA_ConnectReq (SDP_PSM, p_bd_addr);
+
+ /* Check if L2CAP started the connection process */
+ if (cid != 0)
+ {
+ p_ccb->connection_id = cid;
+
+ return (p_ccb);
+ }
+ else
+ {
+ SDP_TRACE_WARNING0 ("SDP - Originate failed");
+ sdpu_release_ccb (p_ccb);
+ return (NULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function sdp_disconnect
+**
+** Description This function disconnects a connection.
+**
+** Returns void
+**
+*******************************************************************************/
+void sdp_disconnect (tCONN_CB*p_ccb, UINT16 reason)
+{
+#if (defined(SDP_BROWSE_PLUS) && SDP_BROWSE_PLUS == TRUE)
+
+ /* If we are browsing for multiple UUIDs ... */
+ if ((p_ccb->con_state == SDP_STATE_CONNECTED)
+ && (p_ccb->con_flags & SDP_FLAGS_IS_ORIG)
+ && ((reason == SDP_SUCCESS) || (reason == SDP_NO_RECS_MATCH)))
+ {
+ /* If the browse found something, do no more searching */
+ if ((p_ccb->cur_uuid_idx == 0) && (p_ccb->p_db->p_first_rec))
+ p_ccb->cur_uuid_idx = p_ccb->p_db->num_uuid_filters;
+
+ while (++p_ccb->cur_uuid_idx < p_ccb->p_db->num_uuid_filters)
+ {
+ /* Check we have not already found the UUID (maybe through browse) */
+ if ((p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx].len == 2)
+ && (SDP_FindServiceInDb (p_ccb->p_db,
+ p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx].uu.uuid16,
+ NULL)))
+ continue;
+
+ if ((p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx].len > 2)
+ && (SDP_FindServiceUUIDInDb (p_ccb->p_db,
+ &p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx], NULL)))
+ continue;
+
+ p_ccb->cur_handle = 0;
+
+ SDP_TRACE_EVENT1 ("SDP - looking for for more, CID: 0x%x",
+ p_ccb->connection_id);
+
+ sdp_disc_connected (p_ccb);
+ return;
+ }
+ }
+
+ if ((reason == SDP_NO_RECS_MATCH) && (p_ccb->p_db->p_first_rec))
+ reason = SDP_SUCCESS;
+
+#endif
+
+ SDP_TRACE_EVENT1 ("SDP - disconnect CID: 0x%x", p_ccb->connection_id);
+
+ /* Check if we have a connection ID */
+ if (p_ccb->connection_id != 0)
+ {
+ L2CA_DisconnectReq (p_ccb->connection_id);
+ p_ccb->disconnect_reason = reason;
+ }
+
+ /* If at setup state, we may not get callback ind from L2CAP */
+ /* Call user callback immediately */
+ if (p_ccb->con_state == SDP_STATE_CONN_SETUP)
+ {
+ /* Tell the user if he has a callback */
+ if (p_ccb->p_cb)
+ (*p_ccb->p_cb) (reason);
+
+ sdpu_release_ccb (p_ccb);
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function sdp_disconnect_cfm
+**
+** Description This function handles a disconnect confirm event from L2CAP.
+**
+** Returns void
+**
+*******************************************************************************/
+static void sdp_disconnect_cfm (UINT16 l2cap_cid, UINT16 result)
+{
+ tCONN_CB *p_ccb;
+
+ /* Find CCB based on CID */
+ if ((p_ccb = sdpu_find_ccb_by_cid (l2cap_cid)) == NULL)
+ {
+ SDP_TRACE_WARNING1 ("SDP - Rcvd L2CAP disc cfm, unknown CID: 0x%x", l2cap_cid);
+ return;
+ }
+
+ SDP_TRACE_EVENT1 ("SDP - Rcvd L2CAP disc cfm, CID: 0x%x", l2cap_cid);
+
+ /* Tell the user if he has a callback */
+ if (p_ccb->p_cb)
+ (*p_ccb->p_cb) (p_ccb->disconnect_reason);
+
+ sdpu_release_ccb (p_ccb);
+}
+
+#endif /* SDP_CLIENT_ENABLED == TRUE */
+
+/*******************************************************************************
+**
+** Function sdp_conn_timeout
+**
+** Description This function processes a timeout. Currently, we simply send
+** a disconnect request to L2CAP.
+**
+** Returns void
+**
+*******************************************************************************/
+void sdp_conn_timeout (tCONN_CB*p_ccb)
+{
+ SDP_TRACE_EVENT2 ("SDP - CCB timeout in state: %d CID: 0x%x",
+ p_ccb->con_state, p_ccb->connection_id);
+
+ L2CA_DisconnectReq (p_ccb->connection_id);
+#if SDP_CLIENT_ENABLED == TRUE
+ /* Tell the user if he has a callback */
+ if (p_ccb->p_cb)
+ (*p_ccb->p_cb) (SDP_CONN_FAILED);
+#endif
+ sdpu_release_ccb (p_ccb);
+}
+
+
+
+
diff --git a/stack/sdp/sdp_server.c b/stack/sdp/sdp_server.c
new file mode 100644
index 0000000..3640dc2
--- /dev/null
+++ b/stack/sdp/sdp_server.c
@@ -0,0 +1,821 @@
+/*****************************************************************************/
+/* */
+/* Name: sdp_server.c */
+/* */
+/* Description: this file contains functions that handle the SDP server */
+/* functions. This is mainly dealing with client requests */
+/* */
+/* Copyright (c) 1999-2004, WIDCOMM Inc., All Rights Reserved. */
+/* WIDCOMM Bluetooth Core. Proprietary and confidential. */
+/*****************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "gki.h"
+#include "bt_types.h"
+#include "btu.h"
+
+#include "l2cdefs.h"
+#include "hcidefs.h"
+#include "hcimsgs.h"
+
+#include "sdp_api.h"
+#include "sdpint.h"
+
+
+#if SDP_SERVER_ENABLED == TRUE
+
+/* Maximum number of bytes to reserve out of SDP MTU for response data */
+#define SDP_MAX_SERVICE_RSPHDR_LEN 12
+#define SDP_MAX_SERVATTR_RSPHDR_LEN 10
+#define SDP_MAX_ATTR_RSPHDR_LEN 10
+
+/********************************************************************************/
+/* L O C A L F U N C T I O N P R O T O T Y P E S */
+/********************************************************************************/
+static void process_service_search (tCONN_CB *p_ccb, UINT16 trans_num,
+ UINT16 param_len, UINT8 *p_req,
+ UINT8 *p_req_end);
+
+static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
+ UINT16 param_len, UINT8 *p_req,
+ UINT8 *p_req_end);
+
+static void process_service_search_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
+ UINT16 param_len, UINT8 *p_req,
+ UINT8 *p_req_end);
+
+
+/********************************************************************************/
+/* E R R O R T E X T S T R I N G S */
+/* */
+/* The default is to have no text string, but we allow the strings to be */
+/* configured in target.h if people want them. */
+/********************************************************************************/
+#ifndef SDP_TEXT_BAD_HEADER
+#define SDP_TEXT_BAD_HEADER NULL
+#endif
+
+#ifndef SDP_TEXT_BAD_PDU
+#define SDP_TEXT_BAD_PDU NULL
+#endif
+
+#ifndef SDP_TEXT_BAD_UUID_LIST
+#define SDP_TEXT_BAD_UUID_LIST NULL
+#endif
+
+#ifndef SDP_TEXT_BAD_HANDLE
+#define SDP_TEXT_BAD_HANDLE NULL
+#endif
+
+#ifndef SDP_TEXT_BAD_ATTR_LIST
+#define SDP_TEXT_BAD_ATTR_LIST NULL
+#endif
+
+#ifndef SDP_TEXT_BAD_CONT_LEN
+#define SDP_TEXT_BAD_CONT_LEN NULL
+#endif
+
+#ifndef SDP_TEXT_BAD_CONT_INX
+#define SDP_TEXT_BAD_CONT_INX NULL
+#endif
+
+/*******************************************************************************
+**
+** Function sdp_server_handle_client_req
+**
+** Description This is the main dispatcher of the SDP server. It is called
+** when any data is received from L2CAP, and dispatches the
+** request to the appropriate handler.
+**
+** Returns void
+**
+*******************************************************************************/
+void sdp_server_handle_client_req (tCONN_CB *p_ccb, BT_HDR *p_msg)
+{
+ UINT8 *p_req = (UINT8 *) (p_msg + 1) + p_msg->offset;
+ UINT8 *p_req_end = p_req + p_msg->len;
+ UINT8 pdu_id;
+ UINT16 trans_num, param_len;
+
+
+ /* Start inactivity timer */
+ btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_SDP, SDP_INACT_TIMEOUT);
+
+ /* The first byte in the message is the pdu type */
+ pdu_id = *p_req++;
+
+ /* Extract the transaction number and parameter length */
+ BE_STREAM_TO_UINT16 (trans_num, p_req);
+ BE_STREAM_TO_UINT16 (param_len, p_req);
+
+ if ((p_req + param_len) > p_req_end)
+ {
+ sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_PDU_SIZE, SDP_TEXT_BAD_HEADER);
+ return;
+ }
+
+ switch (pdu_id)
+ {
+ case SDP_PDU_SERVICE_SEARCH_REQ:
+ process_service_search (p_ccb, trans_num, param_len, p_req, p_req_end);
+ break;
+
+ case SDP_PDU_SERVICE_ATTR_REQ:
+ process_service_attr_req (p_ccb, trans_num, param_len, p_req, p_req_end);
+ break;
+
+ case SDP_PDU_SERVICE_SEARCH_ATTR_REQ:
+ process_service_search_attr_req (p_ccb, trans_num, param_len, p_req, p_req_end);
+ break;
+
+ default:
+ sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_PDU);
+ SDP_TRACE_WARNING1 ("SDP - server got unknown PDU: 0x%x", pdu_id);
+ break;
+ }
+}
+
+
+
+/*******************************************************************************
+**
+** Function process_service_search
+**
+** Description This function handles a service search request from the
+** client. It builds a reply message with info from the database,
+** and sends the reply back to the client.
+**
+** Returns void
+**
+*******************************************************************************/
+static void process_service_search (tCONN_CB *p_ccb, UINT16 trans_num,
+ UINT16 param_len, UINT8 *p_req,
+ UINT8 *p_req_end)
+{
+ UINT16 max_replies, cur_handles, rem_handles, cont_offset;
+ tSDP_UUID_SEQ uid_seq;
+ UINT8 *p_rsp, *p_rsp_start, *p_rsp_param_len;
+ UINT16 rsp_param_len, num_rsp_handles, xx;
+ UINT32 rsp_handles[SDP_MAX_RECORDS];
+ tSDP_RECORD *p_rec = NULL;
+ BT_HDR *p_buf;
+ BOOLEAN is_cont = FALSE;
+
+ p_req = sdpu_extract_uid_seq (p_req, param_len, &uid_seq);
+
+ if ((!p_req) || (!uid_seq.num_uids))
+ {
+ sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_UUID_LIST);
+ return;
+ }
+
+ /* Get the max replies we can send. Cap it at our max anyways. */
+ BE_STREAM_TO_UINT16 (max_replies, p_req);
+
+ if (max_replies > SDP_MAX_RECORDS)
+ max_replies = SDP_MAX_RECORDS;
+
+ /* Get a list of handles that match the UUIDs given to us */
+ for (num_rsp_handles = 0; num_rsp_handles < max_replies; )
+ {
+ p_rec = sdp_db_service_search (p_rec, &uid_seq);
+
+ if (p_rec)
+ rsp_handles[num_rsp_handles++] = p_rec->record_handle;
+ else
+ break;
+ }
+
+ /* Check if this is a continuation request */
+ if (*p_req)
+ {
+ if (*p_req++ != SDP_CONTINUATION_LEN)
+ {
+ sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE,
+ SDP_TEXT_BAD_CONT_LEN);
+ return;
+ }
+ BE_STREAM_TO_UINT16 (cont_offset, p_req);
+
+ if (cont_offset != p_ccb->cont_offset)
+ {
+ sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE,
+ SDP_TEXT_BAD_CONT_INX);
+ return;
+ }
+
+ rem_handles = num_rsp_handles - cont_offset; /* extract the remaining handles */
+ }
+ else
+ {
+ rem_handles = num_rsp_handles;
+ cont_offset = 0;
+ }
+
+ /* Calculate how many handles will fit in one PDU */
+ cur_handles = (UINT16)((p_ccb->rem_mtu_size - SDP_MAX_SERVICE_RSPHDR_LEN) / 4);
+
+ if (rem_handles <= cur_handles)
+ cur_handles = rem_handles;
+ else /* Continuation is set */
+ {
+ p_ccb->cont_offset += cur_handles;
+ is_cont = TRUE;
+ }
+
+ /* Get a buffer to use to build the response */
+ if ((p_buf = (BT_HDR *)GKI_getpoolbuf (SDP_POOL_ID)) == NULL)
+ {
+ SDP_TRACE_ERROR0 ("SDP - no buf for search rsp");
+ return;
+ }
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_rsp = p_rsp_start = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ /* Start building a rsponse */
+ UINT8_TO_BE_STREAM (p_rsp, SDP_PDU_SERVICE_SEARCH_RSP);
+ UINT16_TO_BE_STREAM (p_rsp, trans_num);
+
+ /* Skip the length, we need to add it at the end */
+ p_rsp_param_len = p_rsp;
+ p_rsp += 2;
+
+ /* Put in total and current number of handles, and handles themselves */
+ UINT16_TO_BE_STREAM (p_rsp, num_rsp_handles);
+ UINT16_TO_BE_STREAM (p_rsp, cur_handles);
+
+/* SDP_TRACE_DEBUG5("SDP Service Rsp: tothdl %d, curhdlr %d, start %d, end %d, cont %d",
+ num_rsp_handles, cur_handles, cont_offset,
+ cont_offset + cur_handles-1, is_cont); */
+ for (xx = cont_offset; xx < cont_offset + cur_handles; xx++)
+ UINT32_TO_BE_STREAM (p_rsp, rsp_handles[xx]);
+
+ if (is_cont)
+ {
+ UINT8_TO_BE_STREAM (p_rsp, SDP_CONTINUATION_LEN);
+ UINT16_TO_BE_STREAM (p_rsp, p_ccb->cont_offset);
+ }
+ else
+ UINT8_TO_BE_STREAM (p_rsp, 0);
+
+ /* Go back and put the parameter length into the buffer */
+ rsp_param_len = p_rsp - p_rsp_param_len - 2;
+ UINT16_TO_BE_STREAM (p_rsp_param_len, rsp_param_len);
+
+ /* Set the length of the SDP data in the buffer */
+ p_buf->len = p_rsp - p_rsp_start;
+
+
+ /* Send the buffer through L2CAP */
+ L2CA_DataWrite (p_ccb->connection_id, p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function process_service_attr_req
+**
+** Description This function handles an attribute request from the client.
+** It builds a reply message with info from the database,
+** and sends the reply back to the client.
+**
+** Returns void
+**
+*******************************************************************************/
+static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
+ UINT16 param_len, UINT8 *p_req,
+ UINT8 *p_req_end)
+{
+ UINT16 max_list_len, len_to_send, cont_offset;
+ INT16 rem_len;
+ tSDP_ATTR_SEQ attr_seq, attr_seq_sav;
+ UINT8 *p_rsp, *p_rsp_start, *p_rsp_param_len;
+ UINT16 rsp_param_len, xx;
+ UINT32 rec_handle;
+ tSDP_RECORD *p_rec;
+ tSDP_ATTRIBUTE *p_attr;
+ BT_HDR *p_buf;
+ BOOLEAN is_cont = FALSE;
+ UINT16 attr_len;
+
+ /* Extract the record handle */
+ BE_STREAM_TO_UINT32 (rec_handle, p_req);
+
+ if (p_req > p_req_end)
+ {
+ sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_SERV_REC_HDL, SDP_TEXT_BAD_HANDLE);
+ return;
+ }
+
+ /* Get the max list length we can send. Cap it at MTU size minus overhead */
+ BE_STREAM_TO_UINT16 (max_list_len, p_req);
+
+ if (max_list_len > (p_ccb->rem_mtu_size - SDP_MAX_ATTR_RSPHDR_LEN))
+ max_list_len = p_ccb->rem_mtu_size - SDP_MAX_ATTR_RSPHDR_LEN;
+
+ p_req = sdpu_extract_attr_seq (p_req, param_len, &attr_seq);
+
+ if ((!p_req) || (!attr_seq.num_attr) || (p_req > p_req_end))
+ {
+ sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_ATTR_LIST);
+ return;
+ }
+
+ memcpy(&attr_seq_sav, &attr_seq, sizeof(tSDP_ATTR_SEQ)) ;
+
+ /* Find a record with the record handle */
+ p_rec = sdp_db_find_record (rec_handle);
+ if (!p_rec)
+ {
+ sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_SERV_REC_HDL, SDP_TEXT_BAD_HANDLE);
+ return;
+ }
+
+ /* Check if this is a continuation request */
+ if (*p_req)
+ {
+ if (*p_req++ != SDP_CONTINUATION_LEN)
+ {
+ sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE, SDP_TEXT_BAD_CONT_LEN);
+ return;
+ }
+ BE_STREAM_TO_UINT16 (cont_offset, p_req);
+
+ if (cont_offset != p_ccb->cont_offset)
+ {
+ sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE, SDP_TEXT_BAD_CONT_INX);
+ return;
+ }
+
+ if (!p_ccb->rsp_list)
+ {
+ sdpu_build_n_send_error (p_ccb, trans_num, SDP_NO_RESOURCES, NULL);
+ return;
+ }
+ is_cont = TRUE;
+
+ /* Initialise for continuation response */
+ p_rsp = &p_ccb->rsp_list[0];
+ attr_seq.attr_entry[p_ccb->cont_info.next_attr_index].start = p_ccb->cont_info.next_attr_start_id;
+ }
+ else
+ {
+ /* Get a scratch buffer to store response */
+ if (!p_ccb->rsp_list)
+ {
+ p_ccb->rsp_list = (UINT8 *)GKI_getbuf (max_list_len);
+ if (p_ccb->rsp_list == NULL)
+ {
+ SDP_TRACE_ERROR0 ("SDP - no scratch buf for search rsp");
+ return;
+ }
+ }
+
+ p_ccb->cont_offset = 0;
+ p_rsp = &p_ccb->rsp_list[3]; /* Leave space for data elem descr */
+
+ /* Reset continuation parameters in p_ccb */
+ p_ccb->cont_info.prev_sdp_rec = NULL;
+ p_ccb->cont_info.next_attr_index = 0;
+ p_ccb->cont_info.attr_offset = 0;
+ }
+
+ /* Search for attributes that match the list given to us */
+ for (xx = p_ccb->cont_info.next_attr_index; xx < attr_seq.num_attr; xx++)
+ {
+ p_attr = sdp_db_find_attr_in_rec (p_rec, attr_seq.attr_entry[xx].start, attr_seq.attr_entry[xx].end);
+
+ if (p_attr)
+ {
+ /* Check if attribute fits. Assume 3-byte value type/length */
+ rem_len = max_list_len - (INT16) (p_rsp - &p_ccb->rsp_list[0]);
+
+ /* just in case */
+ if (rem_len <= 0)
+ {
+ p_ccb->cont_info.next_attr_index = xx;
+ p_ccb->cont_info.next_attr_start_id = p_attr->id;
+ break;
+ }
+
+ attr_len = sdpu_get_attrib_entry_len(p_attr);
+ /* if there is a partial attribute pending to be sent */
+ if (p_ccb->cont_info.attr_offset)
+ {
+ p_rsp = sdpu_build_partial_attrib_entry (p_rsp, p_attr, rem_len,
+ &p_ccb->cont_info.attr_offset);
+
+ /* If the partial attrib could not been fully added yet */
+ if (p_ccb->cont_info.attr_offset != attr_len)
+ break;
+ else /* If the partial attrib has been added in full by now */
+ p_ccb->cont_info.attr_offset = 0; /* reset attr_offset */
+ }
+ else if (rem_len < attr_len) /* Not enough space for attr... so add partially */
+ {
+ if (attr_len >= MAX_ATTR_LEN)
+ {
+ SDP_TRACE_ERROR2("SDP attr too big: max_list_len=%d,attr_len=%d", max_list_len, attr_len);
+ sdpu_build_n_send_error (p_ccb, trans_num, SDP_NO_RESOURCES, NULL);
+ return;
+ }
+
+ /* add the partial attribute if possible */
+ p_rsp = sdpu_build_partial_attrib_entry (p_rsp, p_attr, (UINT16)rem_len,
+ &p_ccb->cont_info.attr_offset);
+
+ p_ccb->cont_info.next_attr_index = xx;
+ p_ccb->cont_info.next_attr_start_id = p_attr->id;
+ break;
+ }
+ else /* build the whole attribute */
+ p_rsp = sdpu_build_attrib_entry (p_rsp, p_attr);
+
+ /* If doing a range, stick with this one till no more attributes found */
+ if (attr_seq.attr_entry[xx].start != attr_seq.attr_entry[xx].end)
+ {
+ /* Update for next time through */
+ attr_seq.attr_entry[xx].start = p_attr->id + 1;
+
+ xx--;
+ }
+ }
+ }
+ /* If all the attributes have been accomodated in p_rsp,
+ reset next_attr_index */
+ if (xx == attr_seq.num_attr)
+ p_ccb->cont_info.next_attr_index = 0;
+
+ len_to_send = (UINT16) (p_rsp - &p_ccb->rsp_list[0]);
+ cont_offset = 0;
+
+ if (!is_cont)
+ {
+ p_ccb->list_len = sdpu_get_attrib_seq_len(p_rec, &attr_seq_sav) + 3;
+ /* Put in the sequence header (2 or 3 bytes) */
+ if (p_ccb->list_len > 255)
+ {
+ p_ccb->rsp_list[0] = (UINT8) ((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_WORD);
+ p_ccb->rsp_list[1] = (UINT8) ((p_ccb->list_len - 3) >> 8);
+ p_ccb->rsp_list[2] = (UINT8) (p_ccb->list_len - 3);
+ }
+ else
+ {
+ cont_offset = 1;
+
+ p_ccb->rsp_list[1] = (UINT8) ((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
+ p_ccb->rsp_list[2] = (UINT8) (p_ccb->list_len - 3);
+
+ p_ccb->list_len--;
+ len_to_send--;
+ }
+ }
+
+ /* Get a buffer to use to build the response */
+ if ((p_buf = (BT_HDR *)GKI_getpoolbuf (SDP_POOL_ID)) == NULL)
+ {
+ SDP_TRACE_ERROR0 ("SDP - no buf for search rsp");
+ return;
+ }
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_rsp = p_rsp_start = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ /* Start building a rsponse */
+ UINT8_TO_BE_STREAM (p_rsp, SDP_PDU_SERVICE_ATTR_RSP);
+ UINT16_TO_BE_STREAM (p_rsp, trans_num);
+
+ /* Skip the parameter length, add it when we know the length */
+ p_rsp_param_len = p_rsp;
+ p_rsp += 2;
+
+ UINT16_TO_BE_STREAM (p_rsp, len_to_send);
+
+ memcpy (p_rsp, &p_ccb->rsp_list[cont_offset], len_to_send);
+ p_rsp += len_to_send;
+
+ p_ccb->cont_offset += len_to_send;
+
+ /* If anything left to send, continuation needed */
+ if (p_ccb->cont_offset < p_ccb->list_len)
+ {
+ is_cont = TRUE;
+
+ UINT8_TO_BE_STREAM (p_rsp, SDP_CONTINUATION_LEN);
+ UINT16_TO_BE_STREAM (p_rsp, p_ccb->cont_offset);
+ }
+ else
+ UINT8_TO_BE_STREAM (p_rsp, 0);
+
+ /* Go back and put the parameter length into the buffer */
+ rsp_param_len = p_rsp - p_rsp_param_len - 2;
+ UINT16_TO_BE_STREAM (p_rsp_param_len, rsp_param_len);
+
+ /* Set the length of the SDP data in the buffer */
+ p_buf->len = p_rsp - p_rsp_start;
+
+
+ /* Send the buffer through L2CAP */
+ L2CA_DataWrite (p_ccb->connection_id, p_buf);
+}
+
+
+
+/*******************************************************************************
+**
+** Function process_service_search_attr_req
+**
+** Description This function handles a combined service search and attribute
+** read request from the client. It builds a reply message with
+** info from the database, and sends the reply back to the client.
+**
+** Returns void
+**
+*******************************************************************************/
+static void process_service_search_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
+ UINT16 param_len, UINT8 *p_req,
+ UINT8 *p_req_end)
+{
+ UINT16 max_list_len;
+ INT16 rem_len;
+ UINT16 len_to_send, cont_offset;
+ tSDP_UUID_SEQ uid_seq;
+ UINT8 *p_rsp, *p_rsp_start, *p_rsp_param_len;
+ UINT16 rsp_param_len, xx;
+ tSDP_RECORD *p_rec;
+ tSDP_ATTR_SEQ attr_seq, attr_seq_sav;
+ tSDP_ATTRIBUTE *p_attr;
+ BT_HDR *p_buf;
+ BOOLEAN maxxed_out = FALSE, is_cont = FALSE;
+ UINT8 *p_seq_start;
+ UINT16 seq_len, attr_len;
+
+ /* Extract the UUID sequence to search for */
+ p_req = sdpu_extract_uid_seq (p_req, param_len, &uid_seq);
+
+ if ((!p_req) || (!uid_seq.num_uids))
+ {
+ sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_UUID_LIST);
+ return;
+ }
+
+ /* Get the max list length we can send. Cap it at our max list length. */
+ BE_STREAM_TO_UINT16 (max_list_len, p_req);
+
+ if (max_list_len > (p_ccb->rem_mtu_size - SDP_MAX_SERVATTR_RSPHDR_LEN))
+ max_list_len = p_ccb->rem_mtu_size - SDP_MAX_SERVATTR_RSPHDR_LEN;
+
+ p_req = sdpu_extract_attr_seq (p_req, param_len, &attr_seq);
+
+ if ((!p_req) || (!attr_seq.num_attr))
+ {
+ sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_ATTR_LIST);
+ return;
+ }
+
+ memcpy(&attr_seq_sav, &attr_seq, sizeof(tSDP_ATTR_SEQ)) ;
+
+ /* Check if this is a continuation request */
+ if (*p_req)
+ {
+ if (*p_req++ != SDP_CONTINUATION_LEN)
+ {
+ sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE, SDP_TEXT_BAD_CONT_LEN);
+ return;
+ }
+ BE_STREAM_TO_UINT16 (cont_offset, p_req);
+
+ if (cont_offset != p_ccb->cont_offset)
+ {
+ sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE, SDP_TEXT_BAD_CONT_INX);
+ return;
+ }
+
+ if (!p_ccb->rsp_list)
+ {
+ sdpu_build_n_send_error (p_ccb, trans_num, SDP_NO_RESOURCES, NULL);
+ return;
+ }
+ is_cont = TRUE;
+
+ /* Initialise for continuation response */
+ p_rsp = &p_ccb->rsp_list[0];
+ attr_seq.attr_entry[p_ccb->cont_info.next_attr_index].start = p_ccb->cont_info.next_attr_start_id;
+ }
+ else
+ {
+ /* Get a scratch buffer to store response */
+ if (!p_ccb->rsp_list)
+ {
+ p_ccb->rsp_list = (UINT8 *)GKI_getbuf (max_list_len);
+ if (p_ccb->rsp_list == NULL)
+ {
+ SDP_TRACE_ERROR0 ("SDP - no scratch buf for search rsp");
+ return;
+ }
+ }
+
+ p_ccb->cont_offset = 0;
+ p_rsp = &p_ccb->rsp_list[3]; /* Leave space for data elem descr */
+
+ /* Reset continuation parameters in p_ccb */
+ p_ccb->cont_info.prev_sdp_rec = NULL;
+ p_ccb->cont_info.next_attr_index = 0;
+ p_ccb->cont_info.last_attr_seq_desc_sent = FALSE;
+ p_ccb->cont_info.attr_offset = 0;
+ }
+
+ /* Get a list of handles that match the UUIDs given to us */
+ for (p_rec = sdp_db_service_search (p_ccb->cont_info.prev_sdp_rec, &uid_seq); p_rec; p_rec = sdp_db_service_search (p_rec, &uid_seq))
+ {
+ /* Allow space for attribute sequence type and length */
+ p_seq_start = p_rsp;
+ if (p_ccb->cont_info.last_attr_seq_desc_sent == FALSE)
+ {
+ /* See if there is enough room to include a new service in the current response */
+ rem_len = max_list_len - (INT16) (p_rsp - &p_ccb->rsp_list[0]);
+ if (rem_len < 3)
+ {
+ /* Not enough room. Update continuation info for next response */
+ p_ccb->cont_info.next_attr_index = 0;
+ p_ccb->cont_info.next_attr_start_id = attr_seq.attr_entry[0].start;
+ break;
+ }
+ p_rsp += 3;
+ }
+
+ /* Get a list of handles that match the UUIDs given to us */
+ for (xx = p_ccb->cont_info.next_attr_index; xx < attr_seq.num_attr; xx++)
+ {
+ p_attr = sdp_db_find_attr_in_rec (p_rec, attr_seq.attr_entry[xx].start, attr_seq.attr_entry[xx].end);
+
+ if (p_attr)
+ {
+ /* Check if attribute fits. Assume 3-byte value type/length */
+ rem_len = max_list_len - (INT16) (p_rsp - &p_ccb->rsp_list[0]);
+
+ /* just in case */
+ if (rem_len <= 0)
+ {
+ p_ccb->cont_info.next_attr_index = xx;
+ p_ccb->cont_info.next_attr_start_id = p_attr->id;
+ maxxed_out = TRUE;
+ break;
+ }
+
+ attr_len = sdpu_get_attrib_entry_len(p_attr);
+ /* if there is a partial attribute pending to be sent */
+ if (p_ccb->cont_info.attr_offset)
+ {
+ p_rsp = sdpu_build_partial_attrib_entry (p_rsp, p_attr, rem_len,
+ &p_ccb->cont_info.attr_offset);
+
+ /* If the partial attrib could not been fully added yet */
+ if (p_ccb->cont_info.attr_offset != attr_len)
+ {
+ maxxed_out = TRUE;
+ break;
+ }
+ else /* If the partial attrib has been added in full by now */
+ p_ccb->cont_info.attr_offset = 0; /* reset attr_offset */
+ }
+ else if (rem_len < attr_len) /* Not enough space for attr... so add partially */
+ {
+ if (attr_len >= MAX_ATTR_LEN)
+ {
+ SDP_TRACE_ERROR2("SDP attr too big: max_list_len=%d,attr_len=%d", max_list_len, attr_len);
+ sdpu_build_n_send_error (p_ccb, trans_num, SDP_NO_RESOURCES, NULL);
+ return;
+ }
+
+ /* add the partial attribute if possible */
+ p_rsp = sdpu_build_partial_attrib_entry (p_rsp, p_attr, (UINT16)rem_len,
+ &p_ccb->cont_info.attr_offset);
+
+ p_ccb->cont_info.next_attr_index = xx;
+ p_ccb->cont_info.next_attr_start_id = p_attr->id;
+ maxxed_out = TRUE;
+ break;
+ }
+ else /* build the whole attribute */
+ p_rsp = sdpu_build_attrib_entry (p_rsp, p_attr);
+
+ /* If doing a range, stick with this one till no more attributes found */
+ if (attr_seq.attr_entry[xx].start != attr_seq.attr_entry[xx].end)
+ {
+ /* Update for next time through */
+ attr_seq.attr_entry[xx].start = p_attr->id + 1;
+
+ xx--;
+ }
+ }
+ }
+
+ /* Go back and put the type and length into the buffer */
+ if (p_ccb->cont_info.last_attr_seq_desc_sent == FALSE)
+ {
+ seq_len = sdpu_get_attrib_seq_len(p_rec, &attr_seq_sav);
+ if (seq_len != 0)
+ {
+ UINT8_TO_BE_STREAM (p_seq_start, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_WORD);
+ UINT16_TO_BE_STREAM (p_seq_start, seq_len);
+
+ if (maxxed_out)
+ p_ccb->cont_info.last_attr_seq_desc_sent = TRUE;
+ }
+ else
+ p_rsp = p_seq_start;
+ }
+
+ if (maxxed_out)
+ break;
+
+ /* Restore the attr_seq to look for in the next sdp record */
+ memcpy(&attr_seq, &attr_seq_sav, sizeof(tSDP_ATTR_SEQ)) ;
+
+ /* Reset the next attr index */
+ p_ccb->cont_info.next_attr_index = 0;
+ p_ccb->cont_info.prev_sdp_rec = p_rec;
+ p_ccb->cont_info.last_attr_seq_desc_sent = FALSE;
+ }
+
+ /* response length */
+ len_to_send = (UINT16) (p_rsp - &p_ccb->rsp_list[0]);
+ cont_offset = 0;
+
+ /* If first response, insert sequence header */
+ if (!is_cont)
+ {
+ /* Get the total list length for requested uid and attribute sequence */
+ p_ccb->list_len = sdpu_get_list_len(&uid_seq, &attr_seq_sav) + 3;
+ /* Put in the sequence header (2 or 3 bytes) */
+ if (p_ccb->list_len > 255)
+ {
+ p_ccb->rsp_list[0] = (UINT8) ((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_WORD);
+ p_ccb->rsp_list[1] = (UINT8) ((p_ccb->list_len - 3) >> 8);
+ p_ccb->rsp_list[2] = (UINT8) (p_ccb->list_len - 3);
+ }
+ else
+ {
+ cont_offset = 1;
+
+ p_ccb->rsp_list[1] = (UINT8) ((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
+ p_ccb->rsp_list[2] = (UINT8) (p_ccb->list_len - 3);
+
+ p_ccb->list_len--;
+ len_to_send--;
+ }
+ }
+
+ /* Get a buffer to use to build the response */
+ if ((p_buf = (BT_HDR *)GKI_getpoolbuf (SDP_POOL_ID)) == NULL)
+ {
+ SDP_TRACE_ERROR0 ("SDP - no buf for search rsp");
+ return;
+ }
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_rsp = p_rsp_start = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ /* Start building a rsponse */
+ UINT8_TO_BE_STREAM (p_rsp, SDP_PDU_SERVICE_SEARCH_ATTR_RSP);
+ UINT16_TO_BE_STREAM (p_rsp, trans_num);
+
+ /* Skip the parameter length, add it when we know the length */
+ p_rsp_param_len = p_rsp;
+ p_rsp += 2;
+
+ /* Stream the list length to send */
+ UINT16_TO_BE_STREAM (p_rsp, len_to_send);
+
+ /* copy from rsp_list to the actual buffer to be sent */
+ memcpy (p_rsp, &p_ccb->rsp_list[cont_offset], len_to_send);
+ p_rsp += len_to_send;
+
+ p_ccb->cont_offset += len_to_send;
+
+ /* If anything left to send, continuation needed */
+ if (p_ccb->cont_offset < p_ccb->list_len)
+ {
+ is_cont = TRUE;
+
+ UINT8_TO_BE_STREAM (p_rsp, SDP_CONTINUATION_LEN);
+ UINT16_TO_BE_STREAM (p_rsp, p_ccb->cont_offset);
+ }
+ else
+ UINT8_TO_BE_STREAM (p_rsp, 0);
+
+ /* Go back and put the parameter length into the buffer */
+ rsp_param_len = p_rsp - p_rsp_param_len - 2;
+ UINT16_TO_BE_STREAM (p_rsp_param_len, rsp_param_len);
+
+ /* Set the length of the SDP data in the buffer */
+ p_buf->len = p_rsp - p_rsp_start;
+
+
+ /* Send the buffer through L2CAP */
+ L2CA_DataWrite (p_ccb->connection_id, p_buf);
+}
+
+#endif /* SDP_SERVER_ENABLED == TRUE */
diff --git a/stack/sdp/sdp_utils.c b/stack/sdp/sdp_utils.c
new file mode 100644
index 0000000..2e0fdd8
--- /dev/null
+++ b/stack/sdp/sdp_utils.c
@@ -0,0 +1,1004 @@
+/*****************************************************************************/
+/* */
+/* Name: sdp_utils.c */
+/* */
+/* Description: this file contains SDP utility functions */
+/* */
+/* Copyright (c) 1999-2011, Broadcom Corp., All Rights Reserved. */
+/* Broadcom Bluetooth Core. Proprietary and confidential. */
+/*****************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "gki.h"
+#include "bt_types.h"
+
+#include "l2cdefs.h"
+#include "hcidefs.h"
+#include "hcimsgs.h"
+
+#include "sdp_api.h"
+#include "sdpint.h"
+
+#include "btu.h"
+
+
+static const UINT8 sdp_base_uuid[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB};
+
+/*******************************************************************************
+**
+** Function sdpu_find_ccb_by_cid
+**
+** Description This function searches the CCB table for an entry with the
+** passed CID.
+**
+** Returns the CCB address, or NULL if not found.
+**
+*******************************************************************************/
+tCONN_CB *sdpu_find_ccb_by_cid (UINT16 cid)
+{
+ UINT16 xx;
+ tCONN_CB *p_ccb;
+
+ /* Look through each connection control block */
+ for (xx = 0, p_ccb = sdp_cb.ccb; xx < SDP_MAX_CONNECTIONS; xx++, p_ccb++)
+ {
+ if ((p_ccb->con_state != SDP_STATE_IDLE) && (p_ccb->connection_id == cid))
+ return (p_ccb);
+ }
+
+ /* If here, not found */
+ return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function sdpu_find_ccb_by_db
+**
+** Description This function searches the CCB table for an entry with the
+** passed discovery db.
+**
+** Returns the CCB address, or NULL if not found.
+**
+*******************************************************************************/
+tCONN_CB *sdpu_find_ccb_by_db (tSDP_DISCOVERY_DB *p_db)
+{
+#if SDP_CLIENT_ENABLED == TRUE
+ UINT16 xx;
+ tCONN_CB *p_ccb;
+
+ if (p_db)
+ {
+ /* Look through each connection control block */
+ for (xx = 0, p_ccb = sdp_cb.ccb; xx < SDP_MAX_CONNECTIONS; xx++, p_ccb++)
+ {
+ if ((p_ccb->con_state != SDP_STATE_IDLE) && (p_ccb->p_db == p_db))
+ return (p_ccb);
+ }
+ }
+#endif
+ /* If here, not found */
+ return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function sdpu_allocate_ccb
+**
+** Description This function allocates a new CCB.
+**
+** Returns CCB address, or NULL if none available.
+**
+*******************************************************************************/
+tCONN_CB *sdpu_allocate_ccb (void)
+{
+ UINT16 xx;
+ tCONN_CB *p_ccb;
+
+ /* Look through each connection control block for a free one */
+ for (xx = 0, p_ccb = sdp_cb.ccb; xx < SDP_MAX_CONNECTIONS; xx++, p_ccb++)
+ {
+ if (p_ccb->con_state == SDP_STATE_IDLE)
+ {
+ memset (p_ccb, 0, sizeof (tCONN_CB));
+
+ p_ccb->timer_entry.param = (UINT32) p_ccb;
+
+ return (p_ccb);
+ }
+ }
+
+ /* If here, no free CCB found */
+ return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function sdpu_release_ccb
+**
+** Description This function releases a CCB.
+**
+** Returns void
+**
+*******************************************************************************/
+void sdpu_release_ccb (tCONN_CB *p_ccb)
+{
+ /* Ensure timer is stopped */
+ btu_stop_timer (&p_ccb->timer_entry);
+
+ /* Drop any response pointer we may be holding */
+ p_ccb->con_state = SDP_STATE_IDLE;
+#if SDP_CLIENT_ENABLED == TRUE
+ p_ccb->is_attr_search = FALSE;
+#endif
+
+ /* Free the response buffer */
+ if (p_ccb->rsp_list)
+ {
+ SDP_TRACE_DEBUG0("releasing SDP rsp_list");
+
+ GKI_freebuf(p_ccb->rsp_list);
+ p_ccb->rsp_list = NULL;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function sdpu_build_attrib_seq
+**
+** Description This function builds an attribute sequence from the list of
+** passed attributes. It is also passed the address of the output
+** buffer.
+**
+** Returns Pointer to next byte in the output buffer.
+**
+*******************************************************************************/
+UINT8 *sdpu_build_attrib_seq (UINT8 *p_out, UINT16 *p_attr, UINT16 num_attrs)
+{
+ UINT16 xx;
+
+ /* First thing is the data element header. See if the length fits 1 byte */
+ /* If no attributes, assume a 4-byte wildcard */
+ if (!p_attr)
+ xx = 5;
+ else
+ xx = num_attrs * 3;
+
+ if (xx > 255)
+ {
+ UINT8_TO_BE_STREAM (p_out, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_WORD);
+ UINT16_TO_BE_STREAM (p_out, xx);
+ }
+ else
+ {
+ UINT8_TO_BE_STREAM (p_out, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
+ UINT8_TO_BE_STREAM (p_out, xx);
+ }
+
+ /* If there are no attributes specified, assume caller wants wildcard */
+ if (!p_attr)
+ {
+ UINT8_TO_BE_STREAM (p_out, (UINT_DESC_TYPE << 3) | SIZE_FOUR_BYTES);
+ UINT16_TO_BE_STREAM (p_out, 0);
+ UINT16_TO_BE_STREAM (p_out, 0xFFFF);
+ }
+ else
+ {
+ /* Loop through and put in all the attributes(s) */
+ for (xx = 0; xx < num_attrs; xx++, p_attr++)
+ {
+ UINT8_TO_BE_STREAM (p_out, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
+ UINT16_TO_BE_STREAM (p_out, *p_attr);
+ }
+ }
+
+ return (p_out);
+}
+
+
+/*******************************************************************************
+**
+** Function sdpu_build_attrib_entry
+**
+** Description This function builds an attribute entry from the passed
+** attribute record. It is also passed the address of the output
+** buffer.
+**
+** Returns Pointer to next byte in the output buffer.
+**
+*******************************************************************************/
+UINT8 *sdpu_build_attrib_entry (UINT8 *p_out, tSDP_ATTRIBUTE *p_attr)
+{
+ /* First, store the attribute ID. Goes as a UINT */
+ UINT8_TO_BE_STREAM (p_out, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
+ UINT16_TO_BE_STREAM (p_out, p_attr->id);
+
+ /* the attribute is in the db record.
+ * assuming the attribute len is less than SDP_MAX_ATTR_LEN */
+ switch(p_attr->type)
+ {
+ case TEXT_STR_DESC_TYPE: /* 4 */
+ case DATA_ELE_SEQ_DESC_TYPE:/* 6 */
+ case DATA_ELE_ALT_DESC_TYPE:/* 7 */
+ case URL_DESC_TYPE: /* 8 */
+#if (SDP_MAX_ATTR_LEN > 0xFFFF)
+ if(p_attr->len > 0xFFFF)
+ {
+ UINT8_TO_BE_STREAM (p_out, (p_attr->type << 3) | SIZE_IN_NEXT_LONG);
+ UINT32_TO_BE_STREAM (p_out, p_attr->len);
+ }
+ else
+
+#endif /* 0xFFFF - 0xFF */
+#if (SDP_MAX_ATTR_LEN > 0xFF)
+ if(p_attr->len > 0xFF)
+ {
+ UINT8_TO_BE_STREAM (p_out, (p_attr->type << 3) | SIZE_IN_NEXT_WORD);
+ UINT16_TO_BE_STREAM (p_out, p_attr->len);
+ }
+ else
+
+#endif /* 0xFF and less*/
+ {
+ UINT8_TO_BE_STREAM (p_out, (p_attr->type << 3) | SIZE_IN_NEXT_BYTE);
+ UINT8_TO_BE_STREAM (p_out, p_attr->len);
+ }
+
+ ARRAY_TO_BE_STREAM (p_out, p_attr->value_ptr, (int)p_attr->len);
+
+ return (p_out);
+ }
+
+ /* Now, store the attribute value */
+ switch (p_attr->len)
+ {
+ case 1:
+ UINT8_TO_BE_STREAM (p_out, (p_attr->type << 3) | SIZE_ONE_BYTE);
+ break;
+ case 2:
+ UINT8_TO_BE_STREAM (p_out, (p_attr->type << 3) | SIZE_TWO_BYTES);
+ break;
+ case 4:
+ UINT8_TO_BE_STREAM (p_out, (p_attr->type << 3) | SIZE_FOUR_BYTES);
+ break;
+ case 8:
+ UINT8_TO_BE_STREAM (p_out, (p_attr->type << 3) | SIZE_EIGHT_BYTES);
+ break;
+ case 16:
+ UINT8_TO_BE_STREAM (p_out, (p_attr->type << 3) | SIZE_SIXTEEN_BYTES);
+ break;
+ default:
+ UINT8_TO_BE_STREAM (p_out, (p_attr->type << 3) | SIZE_IN_NEXT_BYTE);
+ UINT8_TO_BE_STREAM (p_out, p_attr->len);
+ break;
+ }
+
+ ARRAY_TO_BE_STREAM (p_out, p_attr->value_ptr, (int)p_attr->len);
+
+ return (p_out);
+}
+
+
+/*******************************************************************************
+**
+** Function sdpu_build_n_send_error
+**
+** Description This function builds and sends an error packet.
+**
+** Returns void
+**
+*******************************************************************************/
+void sdpu_build_n_send_error (tCONN_CB *p_ccb, UINT16 trans_num, UINT16 error_code, char *p_error_text)
+{
+ UINT8 *p_rsp, *p_rsp_start, *p_rsp_param_len;
+ UINT16 rsp_param_len;
+ BT_HDR *p_buf;
+
+
+ SDP_TRACE_WARNING2 ("SDP - sdpu_build_n_send_error code: 0x%x CID: 0x%x",
+ error_code, p_ccb->connection_id);
+
+ /* Get a buffer to use to build and send the packet to L2CAP */
+ if ((p_buf = (BT_HDR *)GKI_getpoolbuf (SDP_POOL_ID)) == NULL)
+ {
+ SDP_TRACE_ERROR0 ("SDP - no buf for err msg");
+ return;
+ }
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_rsp = p_rsp_start = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ UINT8_TO_BE_STREAM (p_rsp, SDP_PDU_ERROR_RESPONSE);
+ UINT16_TO_BE_STREAM (p_rsp, trans_num);
+
+ /* Skip the parameter length, we need to add it at the end */
+ p_rsp_param_len = p_rsp;
+ p_rsp += 2;
+
+ UINT16_TO_BE_STREAM (p_rsp, error_code);
+
+ /* Unplugfest example traces do not have any error text */
+ if (p_error_text)
+ ARRAY_TO_BE_STREAM (p_rsp, p_error_text, (int) strlen (p_error_text));
+
+ /* Go back and put the parameter length into the buffer */
+ rsp_param_len = p_rsp - p_rsp_param_len - 2;
+ UINT16_TO_BE_STREAM (p_rsp_param_len, rsp_param_len);
+
+ /* Set the length of the SDP data in the buffer */
+ p_buf->len = p_rsp - p_rsp_start;
+
+
+ /* Send the buffer through L2CAP */
+ L2CA_DataWrite (p_ccb->connection_id, p_buf);
+}
+
+
+
+/*******************************************************************************
+**
+** Function sdpu_extract_uid_seq
+**
+** Description This function extracts a UUID sequence from the passed input
+** buffer, and puts it into the passed output list.
+**
+** Returns Pointer to next byte in the input buffer after the sequence.
+**
+*******************************************************************************/
+UINT8 *sdpu_extract_uid_seq (UINT8 *p, UINT16 param_len, tSDP_UUID_SEQ *p_seq)
+{
+ UINT8 *p_seq_end;
+ UINT8 descr, type, size;
+ UINT32 seq_len, uuid_len;
+
+ /* Assume none found */
+ p_seq->num_uids = 0;
+
+ /* A UID sequence is composed of a bunch of UIDs. */
+
+ BE_STREAM_TO_UINT8 (descr, p);
+ type = descr >> 3;
+ size = descr & 7;
+
+ if (type != DATA_ELE_SEQ_DESC_TYPE)
+ return (NULL);
+
+ switch (size)
+ {
+ case SIZE_TWO_BYTES:
+ seq_len = 2;
+ break;
+ case SIZE_FOUR_BYTES:
+ seq_len = 4;
+ break;
+ case SIZE_SIXTEEN_BYTES:
+ seq_len = 16;
+ break;
+ case SIZE_IN_NEXT_BYTE:
+ BE_STREAM_TO_UINT8 (seq_len, p);
+ break;
+ case SIZE_IN_NEXT_WORD:
+ BE_STREAM_TO_UINT16 (seq_len, p);
+ break;
+ case SIZE_IN_NEXT_LONG:
+ BE_STREAM_TO_UINT32 (seq_len, p);
+ break;
+ default:
+ return (NULL);
+ }
+
+ if (seq_len >= param_len)
+ return (NULL);
+
+ p_seq_end = p + seq_len;
+
+ /* Loop through, extracting the UIDs */
+ for ( ; p < p_seq_end ; )
+ {
+ BE_STREAM_TO_UINT8 (descr, p);
+ type = descr >> 3;
+ size = descr & 7;
+
+ if (type != UUID_DESC_TYPE)
+ return (NULL);
+
+ switch (size)
+ {
+ case SIZE_TWO_BYTES:
+ uuid_len = 2;
+ break;
+ case SIZE_FOUR_BYTES:
+ uuid_len = 4;
+ break;
+ case SIZE_SIXTEEN_BYTES:
+ uuid_len = 16;
+ break;
+ case SIZE_IN_NEXT_BYTE:
+ BE_STREAM_TO_UINT8 (uuid_len, p);
+ break;
+ case SIZE_IN_NEXT_WORD:
+ BE_STREAM_TO_UINT16 (uuid_len, p);
+ break;
+ case SIZE_IN_NEXT_LONG:
+ BE_STREAM_TO_UINT32 (uuid_len, p);
+ break;
+ default:
+ return (NULL);
+ }
+
+ /* If UUID length is valid, copy it across */
+ if ((uuid_len == 2) || (uuid_len == 4) || (uuid_len == 16))
+ {
+ p_seq->uuid_entry[p_seq->num_uids].len = (UINT16) uuid_len;
+ BE_STREAM_TO_ARRAY (p, p_seq->uuid_entry[p_seq->num_uids].value, (int)uuid_len);
+ p_seq->num_uids++;
+ }
+ else
+ return (NULL);
+
+ /* We can only do so many */
+ if (p_seq->num_uids >= MAX_UUIDS_PER_SEQ)
+ return (NULL);
+ }
+
+ if (p != p_seq_end)
+ return (NULL);
+
+ return (p);
+}
+
+
+
+/*******************************************************************************
+**
+** Function sdpu_extract_attr_seq
+**
+** Description This function extracts an attribute sequence from the passed
+** input buffer, and puts it into the passed output list.
+**
+** Returns Pointer to next byte in the input buffer after the sequence.
+**
+*******************************************************************************/
+UINT8 *sdpu_extract_attr_seq (UINT8 *p, UINT16 param_len, tSDP_ATTR_SEQ *p_seq)
+{
+ UINT8 *p_end_list;
+ UINT8 descr, type, size;
+ UINT32 list_len, attr_len;
+
+ /* Assume none found */
+ p_seq->num_attr = 0;
+
+ /* Get attribute sequence info */
+ BE_STREAM_TO_UINT8 (descr, p);
+ type = descr >> 3;
+ size = descr & 7;
+
+ if (type != DATA_ELE_SEQ_DESC_TYPE)
+ return (p);
+
+ switch (size)
+ {
+ case SIZE_IN_NEXT_BYTE:
+ BE_STREAM_TO_UINT8 (list_len, p);
+ break;
+
+ case SIZE_IN_NEXT_WORD:
+ BE_STREAM_TO_UINT16 (list_len, p);
+ break;
+
+ case SIZE_IN_NEXT_LONG:
+ BE_STREAM_TO_UINT32 (list_len, p);
+ break;
+
+ default:
+ return (p);
+ }
+
+ if (list_len > param_len)
+ return (p);
+
+ p_end_list = p + list_len;
+
+ /* Loop through, extracting the attribute IDs */
+ for ( ; p < p_end_list ; )
+ {
+ BE_STREAM_TO_UINT8 (descr, p);
+ type = descr >> 3;
+ size = descr & 7;
+
+ if (type != UINT_DESC_TYPE)
+ return (p);
+
+ switch (size)
+ {
+ case SIZE_TWO_BYTES:
+ attr_len = 2;
+ break;
+ case SIZE_FOUR_BYTES:
+ attr_len = 4;
+ break;
+ case SIZE_IN_NEXT_BYTE:
+ BE_STREAM_TO_UINT8 (attr_len, p);
+ break;
+ case SIZE_IN_NEXT_WORD:
+ BE_STREAM_TO_UINT16 (attr_len, p);
+ break;
+ case SIZE_IN_NEXT_LONG:
+ BE_STREAM_TO_UINT32 (attr_len, p);
+ break;
+ default:
+ return (NULL);
+ break;
+ }
+
+ /* Attribute length must be 2-bytes or 4-bytes for a paired entry. */
+ if (attr_len == 2)
+ {
+ BE_STREAM_TO_UINT16 (p_seq->attr_entry[p_seq->num_attr].start, p);
+ p_seq->attr_entry[p_seq->num_attr].end = p_seq->attr_entry[p_seq->num_attr].start;
+ }
+ else if (attr_len == 4)
+ {
+ BE_STREAM_TO_UINT16 (p_seq->attr_entry[p_seq->num_attr].start, p);
+ BE_STREAM_TO_UINT16 (p_seq->attr_entry[p_seq->num_attr].end, p);
+ }
+ else
+ return (NULL);
+
+ /* We can only do so many */
+ if (++p_seq->num_attr >= MAX_ATTR_PER_SEQ)
+ return (NULL);
+ }
+
+ return (p);
+}
+
+
+/*******************************************************************************
+**
+** Function sdpu_get_len_from_type
+**
+** Description This function gets the length
+**
+** Returns void
+**
+*******************************************************************************/
+UINT8 *sdpu_get_len_from_type (UINT8 *p, UINT8 type, UINT32 *p_len)
+{
+ UINT8 u8;
+ UINT16 u16;
+ UINT32 u32;
+
+ switch (type & 7)
+ {
+ case SIZE_ONE_BYTE:
+ *p_len = 1;
+ break;
+ case SIZE_TWO_BYTES:
+ *p_len = 2;
+ break;
+ case SIZE_FOUR_BYTES:
+ *p_len = 4;
+ break;
+ case SIZE_EIGHT_BYTES:
+ *p_len = 8;
+ break;
+ case SIZE_SIXTEEN_BYTES:
+ *p_len = 16;
+ break;
+ case SIZE_IN_NEXT_BYTE:
+ BE_STREAM_TO_UINT8 (u8, p);
+ *p_len = u8;
+ break;
+ case SIZE_IN_NEXT_WORD:
+ BE_STREAM_TO_UINT16 (u16, p);
+ *p_len = u16;
+ break;
+ case SIZE_IN_NEXT_LONG:
+ BE_STREAM_TO_UINT32 (u32, p);
+ *p_len = (UINT16) u32;
+ break;
+ }
+
+ return (p);
+}
+
+
+/*******************************************************************************
+**
+** Function sdpu_is_base_uuid
+**
+** Description This function checks a 128-bit UUID with the base to see if
+** it matches. Only the last 12 bytes are compared.
+**
+** Returns TRUE if matched, else FALSE
+**
+*******************************************************************************/
+BOOLEAN sdpu_is_base_uuid (UINT8 *p_uuid)
+{
+ UINT16 xx;
+
+ for (xx = 4; xx < MAX_UUID_SIZE; xx++)
+ if (p_uuid[xx] != sdp_base_uuid[xx])
+ return (FALSE);
+
+ /* If here, matched */
+ return (TRUE);
+}
+
+
+/*******************************************************************************
+**
+** Function sdpu_compare_uuid_arrays
+**
+** Description This function compares 2 BE UUIDs. If needed, they are expanded
+** to 128-bit UUIDs, then compared.
+**
+** NOTE it is assumed that the arrays are in Big Endian format
+**
+** Returns TRUE if matched, else FALSE
+**
+*******************************************************************************/
+BOOLEAN sdpu_compare_uuid_arrays (UINT8 *p_uuid1, UINT32 len1, UINT8 *p_uuid2, UINT16 len2)
+{
+ UINT8 nu1[MAX_UUID_SIZE];
+ UINT8 nu2[MAX_UUID_SIZE];
+
+ /* If lengths match, do a straight compare */
+ if (len1 == len2)
+ {
+ if (len1 == 2)
+ return ((p_uuid1[0] == p_uuid2[0]) && (p_uuid1[1] == p_uuid2[1]));
+ if (len1 == 4)
+ return ( (p_uuid1[0] == p_uuid2[0]) && (p_uuid1[1] == p_uuid2[1])
+ && (p_uuid1[2] == p_uuid2[2]) && (p_uuid1[3] == p_uuid2[3]) );
+ else
+ return (memcmp (p_uuid1, p_uuid2, (size_t)len1) == 0);
+ }
+ else if (len1 > len2)
+ {
+ /* If the len1 was 4-byte, (so len2 is 2-byte), compare on the fly */
+ if (len1 == 4)
+ {
+ return ( (p_uuid1[0] == 0) && (p_uuid1[1] == 0)
+ && (p_uuid1[2] == p_uuid2[0]) && (p_uuid1[3] == p_uuid2[1]) );
+ }
+ else
+ {
+ /* Normalize UUIDs to 16-byte form, then compare. Len1 must be 16 */
+ memcpy (nu1, p_uuid1, MAX_UUID_SIZE);
+ memcpy (nu2, sdp_base_uuid, MAX_UUID_SIZE);
+
+ if (len2 == 4)
+ memcpy (nu2, p_uuid2, len2);
+ else
+ memcpy (nu2 + 2, p_uuid2, len2);
+
+ return (memcmp (nu1, nu2, MAX_UUID_SIZE) == 0);
+ }
+ }
+ else
+ {
+ /* len2 is greater than len1 */
+ /* If the len2 was 4-byte, (so len1 is 2-byte), compare on the fly */
+ if (len2 == 4)
+ {
+ return ( (p_uuid2[0] == 0) && (p_uuid2[1] == 0)
+ && (p_uuid2[2] == p_uuid1[0]) && (p_uuid2[3] == p_uuid1[1]) );
+ }
+ else
+ {
+ /* Normalize UUIDs to 16-byte form, then compare. Len1 must be 16 */
+ memcpy (nu2, p_uuid2, MAX_UUID_SIZE);
+ memcpy (nu1, sdp_base_uuid, MAX_UUID_SIZE);
+
+ if (len1 == 4)
+ memcpy (nu1, p_uuid1, (size_t)len1);
+ else
+ memcpy (nu1 + 2, p_uuid1, (size_t)len1);
+
+ return (memcmp (nu1, nu2, MAX_UUID_SIZE) == 0);
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function sdpu_compare_bt_uuids
+**
+** Description This function compares 2 BT UUID structures.
+**
+** NOTE it is assumed that BT UUID structures are compressed to the
+** smallest possible UUIDs (by removing the base SDP UUID)
+**
+** Returns TRUE if matched, else FALSE
+**
+*******************************************************************************/
+BOOLEAN sdpu_compare_bt_uuids (tBT_UUID *p_uuid1, tBT_UUID *p_uuid2)
+{
+ /* Lengths must match for BT UUIDs to match */
+ if (p_uuid1->len == p_uuid2->len)
+ {
+ if (p_uuid1->len == 2)
+ return (p_uuid1->uu.uuid16 == p_uuid2->uu.uuid16);
+ else if (p_uuid1->len == 4)
+ return (p_uuid1->uu.uuid32 == p_uuid2->uu.uuid32);
+ else if (!memcmp (p_uuid1->uu.uuid128, p_uuid2->uu.uuid128, 16))
+ return (TRUE);
+ }
+
+ return (FALSE);
+}
+
+
+/*******************************************************************************
+**
+** Function sdpu_compare_uuid_with_attr
+**
+** Description This function compares a BT UUID structure with the UUID in an
+** SDP attribute record. If needed, they are expanded to 128-bit
+** UUIDs, then compared.
+**
+** NOTE - it is assumed that BT UUID structures are compressed to the
+** smallest possible UUIDs (by removing the base SDP UUID).
+** - it is also assumed that the discovery atribute is compressed
+** to the smallest possible
+**
+** Returns TRUE if matched, else FALSE
+**
+*******************************************************************************/
+BOOLEAN sdpu_compare_uuid_with_attr (tBT_UUID *p_btuuid, tSDP_DISC_ATTR *p_attr)
+{
+ UINT16 attr_len = SDP_DISC_ATTR_LEN (p_attr->attr_len_type);
+
+ /* Since both UUIDs are compressed, lengths must match */
+ if (p_btuuid->len != attr_len)
+ return (FALSE);
+
+ if (p_btuuid->len == 2)
+ return (BOOLEAN)(p_btuuid->uu.uuid16 == p_attr->attr_value.v.u16);
+ else if (p_btuuid->len == 4)
+ return (BOOLEAN)(p_btuuid->uu.uuid32 == p_attr->attr_value.v.u32);
+ /* coverity[overrun-buffer-arg] */
+ /*
+ Event overrun-buffer-arg: Overrun of static array "&p_attr->attr_value.v.array" of size 4 bytes by passing it to a function which indexes it with argument "16U" at byte position 15
+ FALSE-POSITIVE error from Coverity test tool. Please do NOT remove following comment.
+ False-positive: SDP uses scratch buffer to hold the attribute value.
+ The actual size of tSDP_DISC_ATVAL does not matter.
+ If the array size in tSDP_DISC_ATVAL is increase, we would increase the system RAM usage unnecessarily
+ */
+ else if (!memcmp (p_btuuid->uu.uuid128, p_attr->attr_value.v.array, MAX_UUID_SIZE))
+ return (TRUE);
+
+ return (FALSE);
+}
+
+/*******************************************************************************
+**
+** Function sdpu_sort_attr_list
+**
+** Description sorts a list of attributes in numeric order from lowest to
+** highest to conform to SDP specification
+**
+** Returns void
+**
+*******************************************************************************/
+void sdpu_sort_attr_list( UINT16 num_attr, tSDP_DISCOVERY_DB *p_db )
+{
+ UINT16 i;
+ UINT16 x;
+
+ /* Done if no attributes to sort */
+ if (num_attr <= 1)
+ {
+ return;
+ }
+ else if (num_attr > SDP_MAX_ATTR_FILTERS)
+ {
+ num_attr = SDP_MAX_ATTR_FILTERS;
+ }
+
+ num_attr--; /* for the for-loop */
+ for( i = 0; i < num_attr; )
+ {
+ if( p_db->attr_filters[i] > p_db->attr_filters[i+1] )
+ {
+ /* swap the attribute IDs and start from the beginning */
+ x = p_db->attr_filters[i];
+ p_db->attr_filters[i] = p_db->attr_filters[i+1];
+ p_db->attr_filters[i+1] = x;
+
+ i = 0;
+ }
+ else
+ i++;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function sdpu_get_list_len
+**
+** Description gets the total list length in the sdp database for a given
+** uid sequence and attr sequence
+**
+** Returns void
+**
+*******************************************************************************/
+UINT16 sdpu_get_list_len(tSDP_UUID_SEQ *uid_seq, tSDP_ATTR_SEQ *attr_seq)
+{
+ tSDP_RECORD *p_rec;
+ UINT16 len = 0;
+ UINT16 len1;
+
+ for (p_rec = sdp_db_service_search (NULL, uid_seq); p_rec; p_rec = sdp_db_service_search (p_rec, uid_seq))
+ {
+ len += 3;
+
+ len1 = sdpu_get_attrib_seq_len(p_rec, attr_seq );
+
+ if (len1 != 0)
+ len += len1;
+ else
+ len -= 3;
+ }
+ return len;
+}
+
+/*******************************************************************************
+**
+** Function sdpu_get_attrib_seq_len
+**
+** Description gets the length of the specific attributes in a given
+** sdp record
+**
+** Returns void
+**
+*******************************************************************************/
+UINT16 sdpu_get_attrib_seq_len(tSDP_RECORD *p_rec, tSDP_ATTR_SEQ *attr_seq)
+{
+ tSDP_ATTRIBUTE *p_attr;
+ UINT16 len1 = 0;
+ UINT16 xx;
+ BOOLEAN is_range = FALSE;
+ UINT16 start_id, end_id;
+
+ for (xx = 0; xx < attr_seq->num_attr; xx++)
+ {
+ if (is_range == FALSE)
+ {
+ start_id = attr_seq->attr_entry[xx].start;
+ end_id = attr_seq->attr_entry[xx].end;
+ }
+ p_attr = sdp_db_find_attr_in_rec (p_rec,
+ start_id,
+ end_id);
+ if (p_attr)
+ {
+ len1 += sdpu_get_attrib_entry_len (p_attr);
+
+ /* If doing a range, stick with this one till no more attributes found */
+ if (start_id != end_id)
+ {
+ /* Update for next time through */
+ start_id = p_attr->id + 1;
+ xx--;
+ is_range = TRUE;
+ }
+ else
+ is_range = FALSE;
+ }
+ else
+ is_range = FALSE;
+ }
+ return len1;
+}
+
+/*******************************************************************************
+**
+** Function sdpu_get_attrib_entry_len
+**
+** Description gets the length of a specific attribute
+**
+** Returns void
+**
+*******************************************************************************/
+UINT16 sdpu_get_attrib_entry_len(tSDP_ATTRIBUTE *p_attr)
+{
+ UINT16 len = 3;
+
+ /* the attribute is in the db record.
+ * assuming the attribute len is less than SDP_MAX_ATTR_LEN */
+ switch(p_attr->type)
+ {
+ case TEXT_STR_DESC_TYPE: /* 4 */
+ case DATA_ELE_SEQ_DESC_TYPE:/* 6 */
+ case DATA_ELE_ALT_DESC_TYPE:/* 7 */
+ case URL_DESC_TYPE: /* 8 */
+#if (SDP_MAX_ATTR_LEN > 0xFFFF)
+ if(p_attr->len > 0xFFFF)
+ {
+ len += 5;
+ }
+ else
+
+#endif/* 0xFFFF - 0xFF */
+#if (SDP_MAX_ATTR_LEN > 0xFF)
+ if(p_attr->len > 0xFF)
+ {
+ len += 3;
+ }
+ else
+
+#endif /* 0xFF and less*/
+ {
+ len += 2;
+ }
+ len += p_attr->len;
+ return len;
+ }
+
+ /* Now, the attribute value */
+ switch (p_attr->len)
+ {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ case 16:
+ len += 1;
+ break;
+ default:
+ len += 2;
+ break;
+ }
+
+ len += p_attr->len;
+ return len;
+}
+
+
+/*******************************************************************************
+**
+** Function sdpu_build_partial_attrib_entry
+**
+** Description This function fills a buffer with partial attribute. It is
+** assumed that the maximum size of any attribute is 256 bytes.
+**
+** p_out: output buffer
+** p_attr: attribute to be copied partially into p_out
+** rem_len: num bytes to copy into p_out
+** offset: current start offset within the attr that needs to be copied
+**
+** Returns Pointer to next byte in the output buffer.
+** offset is also updated
+**
+*******************************************************************************/
+UINT8 *sdpu_build_partial_attrib_entry (UINT8 *p_out, tSDP_ATTRIBUTE *p_attr, UINT16 len, UINT16 *offset)
+{
+ UINT8 tmp_attr[MAX_ATTR_LEN];
+ UINT8 *p_tmp_attr = &tmp_attr[0];
+ size_t len_to_copy;
+ UINT16 attr_len;
+
+ sdpu_build_attrib_entry(p_tmp_attr, p_attr);
+ attr_len = sdpu_get_attrib_entry_len(p_attr);
+
+ len_to_copy = ((attr_len - *offset) < len) ? (attr_len - *offset): len;
+
+ memcpy(p_out, &tmp_attr[*offset], len_to_copy);
+
+ p_out = &p_out[len_to_copy];
+ *offset += len_to_copy;
+
+ return p_out;
+}
+
diff --git a/stack/sdp/sdpint.h b/stack/sdp/sdpint.h
new file mode 100644
index 0000000..0f16b8c
--- /dev/null
+++ b/stack/sdp/sdpint.h
@@ -0,0 +1,313 @@
+/****************************************************************************/
+/* */
+/* Name: sdp_int.h */
+/* */
+/* Function this file contains internally used SDP definitions */
+/* */
+/* Copyright (c) 1999-2009, Broadcom Corp., All Rights Reserved. */
+/* WIDCOMM Bluetooth Core. Proprietary and confidential. */
+/* */
+/*****************************************************************************/
+
+#ifndef SDP_INT_H
+#define SDP_INT_H
+
+#include "bt_target.h"
+#include "sdp_api.h"
+#include "l2c_api.h"
+
+
+/* Continuation length - we use a 2-byte offset */
+#define SDP_CONTINUATION_LEN 2
+#define SDP_MAX_CONTINUATION_LEN 16 /* As per the spec */
+
+/* Timeout definitions. */
+#define SDP_INACT_TIMEOUT 30 /* Inactivity timeout */
+
+
+/* Define the Out-Flow default values. */
+#define SDP_OFLOW_QOS_FLAG 0
+#define SDP_OFLOW_SERV_TYPE 0
+#define SDP_OFLOW_TOKEN_RATE 0
+#define SDP_OFLOW_TOKEN_BUCKET_SIZE 0
+#define SDP_OFLOW_PEAK_BANDWIDTH 0
+#define SDP_OFLOW_LATENCY 0
+#define SDP_OFLOW_DELAY_VARIATION 0
+
+/* Define the In-Flow default values. */
+#define SDP_IFLOW_QOS_FLAG 0
+#define SDP_IFLOW_SERV_TYPE 0
+#define SDP_IFLOW_TOKEN_RATE 0
+#define SDP_IFLOW_TOKEN_BUCKET_SIZE 0
+#define SDP_IFLOW_PEAK_BANDWIDTH 0
+#define SDP_IFLOW_LATENCY 0
+#define SDP_IFLOW_DELAY_VARIATION 0
+
+#define SDP_LINK_TO 0
+
+/* Define the type of device notification. */
+/* (Inquiry Scan and Page Scan) */
+#define SDP_DEVICE_NOTI_LEN sizeof (BT_HDR) + \
+ HCIC_PREAMBLE_SIZE + \
+ HCIC_PARAM_SIZE_WRITE_PARAM1
+
+#define SDP_DEVICE_NOTI_FLAG 0x03
+
+/* Define the Protocol Data Unit (PDU) types.
+*/
+#define SDP_PDU_ERROR_RESPONSE 0x01
+#define SDP_PDU_SERVICE_SEARCH_REQ 0x02
+#define SDP_PDU_SERVICE_SEARCH_RSP 0x03
+#define SDP_PDU_SERVICE_ATTR_REQ 0x04
+#define SDP_PDU_SERVICE_ATTR_RSP 0x05
+#define SDP_PDU_SERVICE_SEARCH_ATTR_REQ 0x06
+#define SDP_PDU_SERVICE_SEARCH_ATTR_RSP 0x07
+
+/* Max UUIDs and attributes we support per sequence */
+#define MAX_UUIDS_PER_SEQ 16
+#define MAX_ATTR_PER_SEQ 16
+
+/* Max length we support for any attribute */
+// btla-specific ++
+#ifdef SDP_MAX_ATTR_LEN
+#define MAX_ATTR_LEN SDP_MAX_ATTR_LEN
+#else
+#define MAX_ATTR_LEN 256
+#endif
+// btla-specific --
+
+/* Internal UUID sequence representation */
+typedef struct
+{
+ UINT16 len;
+ UINT8 value[MAX_UUID_SIZE];
+} tUID_ENT;
+
+typedef struct
+{
+ UINT16 num_uids;
+ tUID_ENT uuid_entry[MAX_UUIDS_PER_SEQ];
+} tSDP_UUID_SEQ;
+
+
+/* Internal attribute sequence definitions */
+typedef struct
+{
+ UINT16 start;
+ UINT16 end;
+} tATT_ENT;
+
+typedef struct
+{
+ UINT16 num_attr;
+ tATT_ENT attr_entry[MAX_ATTR_PER_SEQ];
+} tSDP_ATTR_SEQ;
+
+
+/* Define the attribute element of the SDP database record */
+typedef struct
+{
+ UINT32 len; /* Number of bytes in the entry */
+ UINT8 *value_ptr; /* Points to attr_pad */
+ UINT16 id;
+ UINT8 type;
+} tSDP_ATTRIBUTE;
+
+/* An SDP record consists of a handle, and 1 or more attributes */
+typedef struct
+{
+ UINT32 record_handle;
+ UINT32 free_pad_ptr;
+ UINT16 num_attributes;
+ tSDP_ATTRIBUTE attribute[SDP_MAX_REC_ATTR];
+ UINT8 attr_pad[SDP_MAX_PAD_LEN];
+} tSDP_RECORD;
+
+
+/* Define the SDP database */
+typedef struct
+{
+ UINT32 di_primary_handle; /* Device ID Primary record or NULL if nonexistent */
+ BOOLEAN brcm_di_registered;
+ UINT16 num_records;
+ tSDP_RECORD record[SDP_MAX_RECORDS];
+} tSDP_DB;
+
+enum
+{
+ SDP_IS_SEARCH,
+ SDP_IS_ATTR_SEARCH,
+ SDP_IS_PASS_THRU /* only when SDP_FOR_JV_INCLUDED == TRUE */
+};
+
+#if SDP_SERVER_ENABLED == TRUE
+/* Continuation information for the SDP server response */
+typedef struct
+{
+ UINT16 next_attr_index; /* attr index for next continuation response */
+ UINT16 next_attr_start_id; /* attr id to start with for the attr index in next cont. response */
+ tSDP_RECORD *prev_sdp_rec; /* last sdp record that was completely sent in the response */
+ BOOLEAN last_attr_seq_desc_sent; /* whether attr seq length has been sent previously */
+ UINT16 attr_offset; /* offset within the attr to keep trak of partial attributes in the responses */
+} tSDP_CONT_INFO;
+#endif /* SDP_SERVER_ENABLED == TRUE */
+
+/* Define the SDP Connection Control Block */
+typedef struct
+{
+#define SDP_STATE_IDLE 0
+#define SDP_STATE_CONN_SETUP 1
+#define SDP_STATE_CFG_SETUP 2
+#define SDP_STATE_CONNECTED 3
+ UINT8 con_state;
+
+#define SDP_FLAGS_IS_ORIG 0x01
+#define SDP_FLAGS_HIS_CFG_DONE 0x02
+#define SDP_FLAGS_MY_CFG_DONE 0x04
+ UINT8 con_flags;
+
+ BD_ADDR device_address;
+ TIMER_LIST_ENT timer_entry;
+ UINT16 rem_mtu_size;
+ UINT16 connection_id;
+ UINT16 list_len; /* length of the response in the GKI buffer */
+ UINT8 *rsp_list; /* pointer to GKI buffer holding response */
+
+#if SDP_CLIENT_ENABLED == TRUE
+ tSDP_DISCOVERY_DB *p_db; /* Database to save info into */
+ tSDP_DISC_CMPL_CB *p_cb; /* Callback for discovery done */
+ UINT32 handles[SDP_MAX_DISC_SERVER_RECS]; /* Discovered server record handles */
+ UINT16 num_handles; /* Number of server handles */
+ UINT16 cur_handle; /* Current handle being processed */
+ UINT16 transaction_id;
+ UINT16 disconnect_reason; /* Disconnect reason */
+#if (defined(SDP_BROWSE_PLUS) && SDP_BROWSE_PLUS == TRUE)
+ UINT16 cur_uuid_idx;
+#endif
+
+#define SDP_DISC_WAIT_CONN 0
+#define SDP_DISC_WAIT_HANDLES 1
+#define SDP_DISC_WAIT_ATTR 2
+#define SDP_DISC_WAIT_SEARCH_ATTR 3
+#define SDP_DISC_WAIT_PASS_THRU 4 /* only when SDP_FOR_JV_INCLUDED == TRUE */
+#define SDP_DISC_WAIT_CANCEL 5
+
+ UINT8 disc_state;
+ UINT8 is_attr_search;
+#endif /* SDP_CLIENT_ENABLED == TRUE */
+
+#if SDP_SERVER_ENABLED == TRUE
+ UINT16 cont_offset; /* Continuation state data in the server response */
+ tSDP_CONT_INFO cont_info; /* structure to hold continuation information for the server response */
+#endif /* SDP_SERVER_ENABLED == TRUE */
+} tCONN_CB;
+
+
+/* The main SDP control block */
+typedef struct
+{
+ tL2CAP_CFG_INFO l2cap_my_cfg; /* My L2CAP config */
+ tCONN_CB ccb[SDP_MAX_CONNECTIONS];
+#if SDP_SERVER_ENABLED == TRUE
+ tSDP_DB server_db;
+#endif
+ tL2CAP_APPL_INFO reg_info; /* L2CAP Registration info */
+ UINT16 max_attr_list_size; /* Max attribute list size to use */
+ UINT16 max_recs_per_search; /* Max records we want per seaarch */
+ UINT8 trace_level;
+} tSDP_CB;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/* Global SDP data */
+#if SDP_DYNAMIC_MEMORY == FALSE
+SDP_API extern tSDP_CB sdp_cb;
+#else
+SDP_API extern tSDP_CB *sdp_cb_ptr;
+#define sdp_cb (*sdp_cb_ptr)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+/* Functions provided by sdp_main.c */
+SDP_API extern void sdp_init (void);
+extern void sdp_disconnect (tCONN_CB*p_ccb, UINT16 reason);
+
+#if (defined(SDP_DEBUG) && SDP_DEBUG == TRUE)
+SDP_API extern UINT16 sdp_set_max_attr_list_size (UINT16 max_size);
+#endif
+
+/* Functions provided by sdp_conn.c
+*/
+extern void sdp_conn_rcv_l2e_conn_ind (BT_HDR *p_msg);
+extern void sdp_conn_rcv_l2e_conn_cfm (BT_HDR *p_msg);
+extern void sdp_conn_rcv_l2e_disc (BT_HDR *p_msg);
+extern void sdp_conn_rcv_l2e_config_ind (BT_HDR *p_msg);
+extern void sdp_conn_rcv_l2e_config_cfm (BT_HDR *p_msg);
+extern void sdp_conn_rcv_l2e_conn_failed (BT_HDR *p_msg);
+extern void sdp_conn_rcv_l2e_connected (BT_HDR *p_msg);
+extern void sdp_conn_rcv_l2e_conn_failed (BT_HDR *p_msg);
+extern void sdp_conn_rcv_l2e_data (BT_HDR *p_msg);
+extern void sdp_conn_timeout (tCONN_CB *p_ccb);
+
+extern tCONN_CB *sdp_conn_originate (UINT8 *p_bd_addr);
+
+/* Functions provided by sdp_utils.c
+*/
+extern tCONN_CB *sdpu_find_ccb_by_cid (UINT16 cid);
+extern tCONN_CB *sdpu_find_ccb_by_db (tSDP_DISCOVERY_DB *p_db);
+extern tCONN_CB *sdpu_allocate_ccb (void);
+extern void sdpu_release_ccb (tCONN_CB *p_ccb);
+
+extern UINT8 *sdpu_build_attrib_seq (UINT8 *p_out, UINT16 *p_attr, UINT16 num_attrs);
+extern UINT8 *sdpu_build_attrib_entry (UINT8 *p_out, tSDP_ATTRIBUTE *p_attr);
+extern void sdpu_build_n_send_error (tCONN_CB *p_ccb, UINT16 trans_num, UINT16 error_code, char *p_error_text);
+
+extern UINT8 *sdpu_extract_attr_seq (UINT8 *p, UINT16 param_len, tSDP_ATTR_SEQ *p_seq);
+extern UINT8 *sdpu_extract_uid_seq (UINT8 *p, UINT16 param_len, tSDP_UUID_SEQ *p_seq);
+
+SDP_API extern UINT8 *sdpu_get_len_from_type (UINT8 *p, UINT8 type, UINT32 *p_len);
+extern BOOLEAN sdpu_is_base_uuid (UINT8 *p_uuid);
+extern BOOLEAN sdpu_compare_uuid_arrays (UINT8 *p_uuid1, UINT32 len1, UINT8 *p_uuid2, UINT16 len2);
+SDP_API extern BOOLEAN sdpu_compare_bt_uuids (tBT_UUID *p_uuid1, tBT_UUID *p_uuid2);
+extern BOOLEAN sdpu_compare_uuid_with_attr (tBT_UUID *p_btuuid, tSDP_DISC_ATTR *p_attr);
+
+extern void sdpu_sort_attr_list( UINT16 num_attr, tSDP_DISCOVERY_DB *p_db );
+extern UINT16 sdpu_get_list_len( tSDP_UUID_SEQ *uid_seq, tSDP_ATTR_SEQ *attr_seq );
+extern UINT16 sdpu_get_attrib_seq_len(tSDP_RECORD *p_rec, tSDP_ATTR_SEQ *attr_seq);
+extern UINT16 sdpu_get_attrib_entry_len(tSDP_ATTRIBUTE *p_attr);
+extern UINT8 *sdpu_build_partial_attrib_entry (UINT8 *p_out, tSDP_ATTRIBUTE *p_attr, UINT16 len, UINT16 *offset);
+
+
+/* Functions provided by sdp_db.c
+*/
+extern tSDP_RECORD *sdp_db_service_search (tSDP_RECORD *p_rec, tSDP_UUID_SEQ *p_seq);
+extern tSDP_RECORD *sdp_db_find_record (UINT32 handle);
+extern tSDP_ATTRIBUTE *sdp_db_find_attr_in_rec (tSDP_RECORD *p_rec, UINT16 start_attr, UINT16 end_attr);
+
+
+/* Functions provided by sdp_server.c
+*/
+#if SDP_SERVER_ENABLED == TRUE
+extern void sdp_server_handle_client_req (tCONN_CB *p_ccb, BT_HDR *p_msg);
+#else
+#define sdp_server_handle_client_req(p_ccb, p_msg)
+#endif
+
+/* Functions provided by sdp_discovery.c
+*/
+#if SDP_CLIENT_ENABLED == TRUE
+extern void sdp_disc_connected (tCONN_CB *p_ccb);
+extern void sdp_disc_server_rsp (tCONN_CB *p_ccb, BT_HDR *p_msg);
+#else
+#define sdp_disc_connected(p_ccb)
+#define sdp_disc_server_rsp(p_ccb, p_msg)
+#endif
+
+
+
+#endif
+
diff --git a/stack/smp/aes.c b/stack/smp/aes.c
new file mode 100644
index 0000000..5b3fefa
--- /dev/null
+++ b/stack/smp/aes.c
@@ -0,0 +1,926 @@
+/*
+ ---------------------------------------------------------------------------
+ Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved.
+
+ LICENSE TERMS
+
+ The redistribution and use of this software (with or without changes)
+ is allowed without the payment of fees or royalties provided that:
+
+ 1. source code distributions include the above copyright notice, this
+ list of conditions and the following disclaimer;
+
+ 2. binary distributions include the above copyright notice, this list
+ of conditions and the following disclaimer in their documentation;
+
+ 3. the name of the copyright holder is not used to endorse products
+ built using this software without specific written permission.
+
+ DISCLAIMER
+
+ This software is provided 'as is' with no explicit or implied warranties
+ in respect of its properties, including, but not limited to, correctness
+ and/or fitness for purpose.
+ ---------------------------------------------------------------------------
+ Issue 09/09/2006
+
+ This is an AES implementation that uses only 8-bit byte operations on the
+ cipher state (there are options to use 32-bit types if available).
+
+ The combination of mix columns and byte substitution used here is based on
+ that developed by Karl Malbrain. His contribution is acknowledged.
+ */
+
+/* define if you have a fast memcpy function on your system */
+#if 1
+# define HAVE_MEMCPY
+# include <string.h>
+#if 0
+# if defined( _MSC_VER )
+# include <intrin.h>
+# pragma intrinsic( memcpy )
+# endif
+#endif
+#endif
+
+#include <stdlib.h>
+
+/* define if you have fast 32-bit types on your system */
+#if 1
+# define HAVE_UINT_32T
+#endif
+
+/* define if you don't want any tables */
+#if 1
+# define USE_TABLES
+#endif
+
+/* On Intel Core 2 duo VERSION_1 is faster */
+
+/* alternative versions (test for performance on your system) */
+#if 1
+# define VERSION_1
+#endif
+
+#include "aes.h"
+
+#if defined( HAVE_UINT_32T )
+ typedef unsigned long uint_32t;
+#endif
+
+/* functions for finite field multiplication in the AES Galois field */
+
+#define WPOLY 0x011b
+#define BPOLY 0x1b
+#define DPOLY 0x008d
+
+#define f1(x) (x)
+#define f2(x) ((x << 1) ^ (((x >> 7) & 1) * WPOLY))
+#define f4(x) ((x << 2) ^ (((x >> 6) & 1) * WPOLY) ^ (((x >> 6) & 2) * WPOLY))
+#define f8(x) ((x << 3) ^ (((x >> 5) & 1) * WPOLY) ^ (((x >> 5) & 2) * WPOLY) \
+ ^ (((x >> 5) & 4) * WPOLY))
+#define d2(x) (((x) >> 1) ^ ((x) & 1 ? DPOLY : 0))
+
+#define f3(x) (f2(x) ^ x)
+#define f9(x) (f8(x) ^ x)
+#define fb(x) (f8(x) ^ f2(x) ^ x)
+#define fd(x) (f8(x) ^ f4(x) ^ x)
+#define fe(x) (f8(x) ^ f4(x) ^ f2(x))
+
+#if defined( USE_TABLES )
+
+#define sb_data(w) { /* S Box data values */ \
+ w(0x63), w(0x7c), w(0x77), w(0x7b), w(0xf2), w(0x6b), w(0x6f), w(0xc5),\
+ w(0x30), w(0x01), w(0x67), w(0x2b), w(0xfe), w(0xd7), w(0xab), w(0x76),\
+ w(0xca), w(0x82), w(0xc9), w(0x7d), w(0xfa), w(0x59), w(0x47), w(0xf0),\
+ w(0xad), w(0xd4), w(0xa2), w(0xaf), w(0x9c), w(0xa4), w(0x72), w(0xc0),\
+ w(0xb7), w(0xfd), w(0x93), w(0x26), w(0x36), w(0x3f), w(0xf7), w(0xcc),\
+ w(0x34), w(0xa5), w(0xe5), w(0xf1), w(0x71), w(0xd8), w(0x31), w(0x15),\
+ w(0x04), w(0xc7), w(0x23), w(0xc3), w(0x18), w(0x96), w(0x05), w(0x9a),\
+ w(0x07), w(0x12), w(0x80), w(0xe2), w(0xeb), w(0x27), w(0xb2), w(0x75),\
+ w(0x09), w(0x83), w(0x2c), w(0x1a), w(0x1b), w(0x6e), w(0x5a), w(0xa0),\
+ w(0x52), w(0x3b), w(0xd6), w(0xb3), w(0x29), w(0xe3), w(0x2f), w(0x84),\
+ w(0x53), w(0xd1), w(0x00), w(0xed), w(0x20), w(0xfc), w(0xb1), w(0x5b),\
+ w(0x6a), w(0xcb), w(0xbe), w(0x39), w(0x4a), w(0x4c), w(0x58), w(0xcf),\
+ w(0xd0), w(0xef), w(0xaa), w(0xfb), w(0x43), w(0x4d), w(0x33), w(0x85),\
+ w(0x45), w(0xf9), w(0x02), w(0x7f), w(0x50), w(0x3c), w(0x9f), w(0xa8),\
+ w(0x51), w(0xa3), w(0x40), w(0x8f), w(0x92), w(0x9d), w(0x38), w(0xf5),\
+ w(0xbc), w(0xb6), w(0xda), w(0x21), w(0x10), w(0xff), w(0xf3), w(0xd2),\
+ w(0xcd), w(0x0c), w(0x13), w(0xec), w(0x5f), w(0x97), w(0x44), w(0x17),\
+ w(0xc4), w(0xa7), w(0x7e), w(0x3d), w(0x64), w(0x5d), w(0x19), w(0x73),\
+ w(0x60), w(0x81), w(0x4f), w(0xdc), w(0x22), w(0x2a), w(0x90), w(0x88),\
+ w(0x46), w(0xee), w(0xb8), w(0x14), w(0xde), w(0x5e), w(0x0b), w(0xdb),\
+ w(0xe0), w(0x32), w(0x3a), w(0x0a), w(0x49), w(0x06), w(0x24), w(0x5c),\
+ w(0xc2), w(0xd3), w(0xac), w(0x62), w(0x91), w(0x95), w(0xe4), w(0x79),\
+ w(0xe7), w(0xc8), w(0x37), w(0x6d), w(0x8d), w(0xd5), w(0x4e), w(0xa9),\
+ w(0x6c), w(0x56), w(0xf4), w(0xea), w(0x65), w(0x7a), w(0xae), w(0x08),\
+ w(0xba), w(0x78), w(0x25), w(0x2e), w(0x1c), w(0xa6), w(0xb4), w(0xc6),\
+ w(0xe8), w(0xdd), w(0x74), w(0x1f), w(0x4b), w(0xbd), w(0x8b), w(0x8a),\
+ w(0x70), w(0x3e), w(0xb5), w(0x66), w(0x48), w(0x03), w(0xf6), w(0x0e),\
+ w(0x61), w(0x35), w(0x57), w(0xb9), w(0x86), w(0xc1), w(0x1d), w(0x9e),\
+ w(0xe1), w(0xf8), w(0x98), w(0x11), w(0x69), w(0xd9), w(0x8e), w(0x94),\
+ w(0x9b), w(0x1e), w(0x87), w(0xe9), w(0xce), w(0x55), w(0x28), w(0xdf),\
+ w(0x8c), w(0xa1), w(0x89), w(0x0d), w(0xbf), w(0xe6), w(0x42), w(0x68),\
+ w(0x41), w(0x99), w(0x2d), w(0x0f), w(0xb0), w(0x54), w(0xbb), w(0x16) }
+
+#define isb_data(w) { /* inverse S Box data values */ \
+ w(0x52), w(0x09), w(0x6a), w(0xd5), w(0x30), w(0x36), w(0xa5), w(0x38),\
+ w(0xbf), w(0x40), w(0xa3), w(0x9e), w(0x81), w(0xf3), w(0xd7), w(0xfb),\
+ w(0x7c), w(0xe3), w(0x39), w(0x82), w(0x9b), w(0x2f), w(0xff), w(0x87),\
+ w(0x34), w(0x8e), w(0x43), w(0x44), w(0xc4), w(0xde), w(0xe9), w(0xcb),\
+ w(0x54), w(0x7b), w(0x94), w(0x32), w(0xa6), w(0xc2), w(0x23), w(0x3d),\
+ w(0xee), w(0x4c), w(0x95), w(0x0b), w(0x42), w(0xfa), w(0xc3), w(0x4e),\
+ w(0x08), w(0x2e), w(0xa1), w(0x66), w(0x28), w(0xd9), w(0x24), w(0xb2),\
+ w(0x76), w(0x5b), w(0xa2), w(0x49), w(0x6d), w(0x8b), w(0xd1), w(0x25),\
+ w(0x72), w(0xf8), w(0xf6), w(0x64), w(0x86), w(0x68), w(0x98), w(0x16),\
+ w(0xd4), w(0xa4), w(0x5c), w(0xcc), w(0x5d), w(0x65), w(0xb6), w(0x92),\
+ w(0x6c), w(0x70), w(0x48), w(0x50), w(0xfd), w(0xed), w(0xb9), w(0xda),\
+ w(0x5e), w(0x15), w(0x46), w(0x57), w(0xa7), w(0x8d), w(0x9d), w(0x84),\
+ w(0x90), w(0xd8), w(0xab), w(0x00), w(0x8c), w(0xbc), w(0xd3), w(0x0a),\
+ w(0xf7), w(0xe4), w(0x58), w(0x05), w(0xb8), w(0xb3), w(0x45), w(0x06),\
+ w(0xd0), w(0x2c), w(0x1e), w(0x8f), w(0xca), w(0x3f), w(0x0f), w(0x02),\
+ w(0xc1), w(0xaf), w(0xbd), w(0x03), w(0x01), w(0x13), w(0x8a), w(0x6b),\
+ w(0x3a), w(0x91), w(0x11), w(0x41), w(0x4f), w(0x67), w(0xdc), w(0xea),\
+ w(0x97), w(0xf2), w(0xcf), w(0xce), w(0xf0), w(0xb4), w(0xe6), w(0x73),\
+ w(0x96), w(0xac), w(0x74), w(0x22), w(0xe7), w(0xad), w(0x35), w(0x85),\
+ w(0xe2), w(0xf9), w(0x37), w(0xe8), w(0x1c), w(0x75), w(0xdf), w(0x6e),\
+ w(0x47), w(0xf1), w(0x1a), w(0x71), w(0x1d), w(0x29), w(0xc5), w(0x89),\
+ w(0x6f), w(0xb7), w(0x62), w(0x0e), w(0xaa), w(0x18), w(0xbe), w(0x1b),\
+ w(0xfc), w(0x56), w(0x3e), w(0x4b), w(0xc6), w(0xd2), w(0x79), w(0x20),\
+ w(0x9a), w(0xdb), w(0xc0), w(0xfe), w(0x78), w(0xcd), w(0x5a), w(0xf4),\
+ w(0x1f), w(0xdd), w(0xa8), w(0x33), w(0x88), w(0x07), w(0xc7), w(0x31),\
+ w(0xb1), w(0x12), w(0x10), w(0x59), w(0x27), w(0x80), w(0xec), w(0x5f),\
+ w(0x60), w(0x51), w(0x7f), w(0xa9), w(0x19), w(0xb5), w(0x4a), w(0x0d),\
+ w(0x2d), w(0xe5), w(0x7a), w(0x9f), w(0x93), w(0xc9), w(0x9c), w(0xef),\
+ w(0xa0), w(0xe0), w(0x3b), w(0x4d), w(0xae), w(0x2a), w(0xf5), w(0xb0),\
+ w(0xc8), w(0xeb), w(0xbb), w(0x3c), w(0x83), w(0x53), w(0x99), w(0x61),\
+ w(0x17), w(0x2b), w(0x04), w(0x7e), w(0xba), w(0x77), w(0xd6), w(0x26),\
+ w(0xe1), w(0x69), w(0x14), w(0x63), w(0x55), w(0x21), w(0x0c), w(0x7d) }
+
+#define mm_data(w) { /* basic data for forming finite field tables */ \
+ w(0x00), w(0x01), w(0x02), w(0x03), w(0x04), w(0x05), w(0x06), w(0x07),\
+ w(0x08), w(0x09), w(0x0a), w(0x0b), w(0x0c), w(0x0d), w(0x0e), w(0x0f),\
+ w(0x10), w(0x11), w(0x12), w(0x13), w(0x14), w(0x15), w(0x16), w(0x17),\
+ w(0x18), w(0x19), w(0x1a), w(0x1b), w(0x1c), w(0x1d), w(0x1e), w(0x1f),\
+ w(0x20), w(0x21), w(0x22), w(0x23), w(0x24), w(0x25), w(0x26), w(0x27),\
+ w(0x28), w(0x29), w(0x2a), w(0x2b), w(0x2c), w(0x2d), w(0x2e), w(0x2f),\
+ w(0x30), w(0x31), w(0x32), w(0x33), w(0x34), w(0x35), w(0x36), w(0x37),\
+ w(0x38), w(0x39), w(0x3a), w(0x3b), w(0x3c), w(0x3d), w(0x3e), w(0x3f),\
+ w(0x40), w(0x41), w(0x42), w(0x43), w(0x44), w(0x45), w(0x46), w(0x47),\
+ w(0x48), w(0x49), w(0x4a), w(0x4b), w(0x4c), w(0x4d), w(0x4e), w(0x4f),\
+ w(0x50), w(0x51), w(0x52), w(0x53), w(0x54), w(0x55), w(0x56), w(0x57),\
+ w(0x58), w(0x59), w(0x5a), w(0x5b), w(0x5c), w(0x5d), w(0x5e), w(0x5f),\
+ w(0x60), w(0x61), w(0x62), w(0x63), w(0x64), w(0x65), w(0x66), w(0x67),\
+ w(0x68), w(0x69), w(0x6a), w(0x6b), w(0x6c), w(0x6d), w(0x6e), w(0x6f),\
+ w(0x70), w(0x71), w(0x72), w(0x73), w(0x74), w(0x75), w(0x76), w(0x77),\
+ w(0x78), w(0x79), w(0x7a), w(0x7b), w(0x7c), w(0x7d), w(0x7e), w(0x7f),\
+ w(0x80), w(0x81), w(0x82), w(0x83), w(0x84), w(0x85), w(0x86), w(0x87),\
+ w(0x88), w(0x89), w(0x8a), w(0x8b), w(0x8c), w(0x8d), w(0x8e), w(0x8f),\
+ w(0x90), w(0x91), w(0x92), w(0x93), w(0x94), w(0x95), w(0x96), w(0x97),\
+ w(0x98), w(0x99), w(0x9a), w(0x9b), w(0x9c), w(0x9d), w(0x9e), w(0x9f),\
+ w(0xa0), w(0xa1), w(0xa2), w(0xa3), w(0xa4), w(0xa5), w(0xa6), w(0xa7),\
+ w(0xa8), w(0xa9), w(0xaa), w(0xab), w(0xac), w(0xad), w(0xae), w(0xaf),\
+ w(0xb0), w(0xb1), w(0xb2), w(0xb3), w(0xb4), w(0xb5), w(0xb6), w(0xb7),\
+ w(0xb8), w(0xb9), w(0xba), w(0xbb), w(0xbc), w(0xbd), w(0xbe), w(0xbf),\
+ w(0xc0), w(0xc1), w(0xc2), w(0xc3), w(0xc4), w(0xc5), w(0xc6), w(0xc7),\
+ w(0xc8), w(0xc9), w(0xca), w(0xcb), w(0xcc), w(0xcd), w(0xce), w(0xcf),\
+ w(0xd0), w(0xd1), w(0xd2), w(0xd3), w(0xd4), w(0xd5), w(0xd6), w(0xd7),\
+ w(0xd8), w(0xd9), w(0xda), w(0xdb), w(0xdc), w(0xdd), w(0xde), w(0xdf),\
+ w(0xe0), w(0xe1), w(0xe2), w(0xe3), w(0xe4), w(0xe5), w(0xe6), w(0xe7),\
+ w(0xe8), w(0xe9), w(0xea), w(0xeb), w(0xec), w(0xed), w(0xee), w(0xef),\
+ w(0xf0), w(0xf1), w(0xf2), w(0xf3), w(0xf4), w(0xf5), w(0xf6), w(0xf7),\
+ w(0xf8), w(0xf9), w(0xfa), w(0xfb), w(0xfc), w(0xfd), w(0xfe), w(0xff) }
+
+static const uint_8t sbox[256] = sb_data(f1);
+static const uint_8t isbox[256] = isb_data(f1);
+
+static const uint_8t gfm2_sbox[256] = sb_data(f2);
+static const uint_8t gfm3_sbox[256] = sb_data(f3);
+
+static const uint_8t gfmul_9[256] = mm_data(f9);
+static const uint_8t gfmul_b[256] = mm_data(fb);
+static const uint_8t gfmul_d[256] = mm_data(fd);
+static const uint_8t gfmul_e[256] = mm_data(fe);
+
+#define s_box(x) sbox[(x)]
+#define is_box(x) isbox[(x)]
+#define gfm2_sb(x) gfm2_sbox[(x)]
+#define gfm3_sb(x) gfm3_sbox[(x)]
+#define gfm_9(x) gfmul_9[(x)]
+#define gfm_b(x) gfmul_b[(x)]
+#define gfm_d(x) gfmul_d[(x)]
+#define gfm_e(x) gfmul_e[(x)]
+
+#else
+
+/* this is the high bit of x right shifted by 1 */
+/* position. Since the starting polynomial has */
+/* 9 bits (0x11b), this right shift keeps the */
+/* values of all top bits within a byte */
+
+static uint_8t hibit(const uint_8t x)
+{ uint_8t r = (uint_8t)((x >> 1) | (x >> 2));
+
+ r |= (r >> 2);
+ r |= (r >> 4);
+ return (r + 1) >> 1;
+}
+
+/* return the inverse of the finite field element x */
+
+static uint_8t gf_inv(const uint_8t x)
+{ uint_8t p1 = x, p2 = BPOLY, n1 = hibit(x), n2 = 0x80, v1 = 1, v2 = 0;
+
+ if(x < 2)
+ return x;
+
+ for( ; ; )
+ {
+ if(n1)
+ while(n2 >= n1) /* divide polynomial p2 by p1 */
+ {
+ n2 /= n1; /* shift smaller polynomial left */
+ p2 ^= (p1 * n2) & 0xff; /* and remove from larger one */
+ v2 ^= (v1 * n2); /* shift accumulated value and */
+ n2 = hibit(p2); /* add into result */
+ }
+ else
+ return v1;
+
+ if(n2) /* repeat with values swapped */
+ while(n1 >= n2)
+ {
+ n1 /= n2;
+ p1 ^= p2 * n1;
+ v1 ^= v2 * n1;
+ n1 = hibit(p1);
+ }
+ else
+ return v2;
+ }
+}
+
+/* The forward and inverse affine transformations used in the S-box */
+uint_8t fwd_affine(const uint_8t x)
+{
+#if defined( HAVE_UINT_32T )
+ uint_32t w = x;
+ w ^= (w << 1) ^ (w << 2) ^ (w << 3) ^ (w << 4);
+ return 0x63 ^ ((w ^ (w >> 8)) & 0xff);
+#else
+ return 0x63 ^ x ^ (x << 1) ^ (x << 2) ^ (x << 3) ^ (x << 4)
+ ^ (x >> 7) ^ (x >> 6) ^ (x >> 5) ^ (x >> 4);
+#endif
+}
+
+uint_8t inv_affine(const uint_8t x)
+{
+#if defined( HAVE_UINT_32T )
+ uint_32t w = x;
+ w = (w << 1) ^ (w << 3) ^ (w << 6);
+ return 0x05 ^ ((w ^ (w >> 8)) & 0xff);
+#else
+ return 0x05 ^ (x << 1) ^ (x << 3) ^ (x << 6)
+ ^ (x >> 7) ^ (x >> 5) ^ (x >> 2);
+#endif
+}
+
+#define s_box(x) fwd_affine(gf_inv(x))
+#define is_box(x) gf_inv(inv_affine(x))
+#define gfm2_sb(x) f2(s_box(x))
+#define gfm3_sb(x) f3(s_box(x))
+#define gfm_9(x) f9(x)
+#define gfm_b(x) fb(x)
+#define gfm_d(x) fd(x)
+#define gfm_e(x) fe(x)
+
+#endif
+
+#if defined( HAVE_MEMCPY )
+# define block_copy_nn(d, s, l) memcpy(d, s, l)
+# define block_copy(d, s) memcpy(d, s, N_BLOCK)
+#else
+# define block_copy_nn(d, s, l) copy_block_nn(d, s, l)
+# define block_copy(d, s) copy_block(d, s)
+#endif
+
+#if !defined( HAVE_MEMCPY )
+static void copy_block( void *d, const void *s )
+{
+#if defined( HAVE_UINT_32T )
+ ((uint_32t*)d)[ 0] = ((uint_32t*)s)[ 0];
+ ((uint_32t*)d)[ 1] = ((uint_32t*)s)[ 1];
+ ((uint_32t*)d)[ 2] = ((uint_32t*)s)[ 2];
+ ((uint_32t*)d)[ 3] = ((uint_32t*)s)[ 3];
+#else
+ ((uint_8t*)d)[ 0] = ((uint_8t*)s)[ 0];
+ ((uint_8t*)d)[ 1] = ((uint_8t*)s)[ 1];
+ ((uint_8t*)d)[ 2] = ((uint_8t*)s)[ 2];
+ ((uint_8t*)d)[ 3] = ((uint_8t*)s)[ 3];
+ ((uint_8t*)d)[ 4] = ((uint_8t*)s)[ 4];
+ ((uint_8t*)d)[ 5] = ((uint_8t*)s)[ 5];
+ ((uint_8t*)d)[ 6] = ((uint_8t*)s)[ 6];
+ ((uint_8t*)d)[ 7] = ((uint_8t*)s)[ 7];
+ ((uint_8t*)d)[ 8] = ((uint_8t*)s)[ 8];
+ ((uint_8t*)d)[ 9] = ((uint_8t*)s)[ 9];
+ ((uint_8t*)d)[10] = ((uint_8t*)s)[10];
+ ((uint_8t*)d)[11] = ((uint_8t*)s)[11];
+ ((uint_8t*)d)[12] = ((uint_8t*)s)[12];
+ ((uint_8t*)d)[13] = ((uint_8t*)s)[13];
+ ((uint_8t*)d)[14] = ((uint_8t*)s)[14];
+ ((uint_8t*)d)[15] = ((uint_8t*)s)[15];
+#endif
+}
+
+static void copy_block_nn( void * d, const void *s, uint_8t nn )
+{
+ while( nn-- )
+ *((uint_8t*)d)++ = *((uint_8t*)s)++;
+}
+#endif
+
+static void xor_block( void *d, const void *s )
+{
+#if defined( HAVE_UINT_32T )
+ ((uint_32t*)d)[ 0] ^= ((uint_32t*)s)[ 0];
+ ((uint_32t*)d)[ 1] ^= ((uint_32t*)s)[ 1];
+ ((uint_32t*)d)[ 2] ^= ((uint_32t*)s)[ 2];
+ ((uint_32t*)d)[ 3] ^= ((uint_32t*)s)[ 3];
+#else
+ ((uint_8t*)d)[ 0] ^= ((uint_8t*)s)[ 0];
+ ((uint_8t*)d)[ 1] ^= ((uint_8t*)s)[ 1];
+ ((uint_8t*)d)[ 2] ^= ((uint_8t*)s)[ 2];
+ ((uint_8t*)d)[ 3] ^= ((uint_8t*)s)[ 3];
+ ((uint_8t*)d)[ 4] ^= ((uint_8t*)s)[ 4];
+ ((uint_8t*)d)[ 5] ^= ((uint_8t*)s)[ 5];
+ ((uint_8t*)d)[ 6] ^= ((uint_8t*)s)[ 6];
+ ((uint_8t*)d)[ 7] ^= ((uint_8t*)s)[ 7];
+ ((uint_8t*)d)[ 8] ^= ((uint_8t*)s)[ 8];
+ ((uint_8t*)d)[ 9] ^= ((uint_8t*)s)[ 9];
+ ((uint_8t*)d)[10] ^= ((uint_8t*)s)[10];
+ ((uint_8t*)d)[11] ^= ((uint_8t*)s)[11];
+ ((uint_8t*)d)[12] ^= ((uint_8t*)s)[12];
+ ((uint_8t*)d)[13] ^= ((uint_8t*)s)[13];
+ ((uint_8t*)d)[14] ^= ((uint_8t*)s)[14];
+ ((uint_8t*)d)[15] ^= ((uint_8t*)s)[15];
+#endif
+}
+
+static void copy_and_key( void *d, const void *s, const void *k )
+{
+#if defined( HAVE_UINT_32T )
+ ((uint_32t*)d)[ 0] = ((uint_32t*)s)[ 0] ^ ((uint_32t*)k)[ 0];
+ ((uint_32t*)d)[ 1] = ((uint_32t*)s)[ 1] ^ ((uint_32t*)k)[ 1];
+ ((uint_32t*)d)[ 2] = ((uint_32t*)s)[ 2] ^ ((uint_32t*)k)[ 2];
+ ((uint_32t*)d)[ 3] = ((uint_32t*)s)[ 3] ^ ((uint_32t*)k)[ 3];
+#elif 1
+ ((uint_8t*)d)[ 0] = ((uint_8t*)s)[ 0] ^ ((uint_8t*)k)[ 0];
+ ((uint_8t*)d)[ 1] = ((uint_8t*)s)[ 1] ^ ((uint_8t*)k)[ 1];
+ ((uint_8t*)d)[ 2] = ((uint_8t*)s)[ 2] ^ ((uint_8t*)k)[ 2];
+ ((uint_8t*)d)[ 3] = ((uint_8t*)s)[ 3] ^ ((uint_8t*)k)[ 3];
+ ((uint_8t*)d)[ 4] = ((uint_8t*)s)[ 4] ^ ((uint_8t*)k)[ 4];
+ ((uint_8t*)d)[ 5] = ((uint_8t*)s)[ 5] ^ ((uint_8t*)k)[ 5];
+ ((uint_8t*)d)[ 6] = ((uint_8t*)s)[ 6] ^ ((uint_8t*)k)[ 6];
+ ((uint_8t*)d)[ 7] = ((uint_8t*)s)[ 7] ^ ((uint_8t*)k)[ 7];
+ ((uint_8t*)d)[ 8] = ((uint_8t*)s)[ 8] ^ ((uint_8t*)k)[ 8];
+ ((uint_8t*)d)[ 9] = ((uint_8t*)s)[ 9] ^ ((uint_8t*)k)[ 9];
+ ((uint_8t*)d)[10] = ((uint_8t*)s)[10] ^ ((uint_8t*)k)[10];
+ ((uint_8t*)d)[11] = ((uint_8t*)s)[11] ^ ((uint_8t*)k)[11];
+ ((uint_8t*)d)[12] = ((uint_8t*)s)[12] ^ ((uint_8t*)k)[12];
+ ((uint_8t*)d)[13] = ((uint_8t*)s)[13] ^ ((uint_8t*)k)[13];
+ ((uint_8t*)d)[14] = ((uint_8t*)s)[14] ^ ((uint_8t*)k)[14];
+ ((uint_8t*)d)[15] = ((uint_8t*)s)[15] ^ ((uint_8t*)k)[15];
+#else
+ block_copy(d, s);
+ xor_block(d, k);
+#endif
+}
+
+static void add_round_key( uint_8t d[N_BLOCK], const uint_8t k[N_BLOCK] )
+{
+ xor_block(d, k);
+}
+
+static void shift_sub_rows( uint_8t st[N_BLOCK] )
+{ uint_8t tt;
+
+ st[ 0] = s_box(st[ 0]); st[ 4] = s_box(st[ 4]);
+ st[ 8] = s_box(st[ 8]); st[12] = s_box(st[12]);
+
+ tt = st[1]; st[ 1] = s_box(st[ 5]); st[ 5] = s_box(st[ 9]);
+ st[ 9] = s_box(st[13]); st[13] = s_box( tt );
+
+ tt = st[2]; st[ 2] = s_box(st[10]); st[10] = s_box( tt );
+ tt = st[6]; st[ 6] = s_box(st[14]); st[14] = s_box( tt );
+
+ tt = st[15]; st[15] = s_box(st[11]); st[11] = s_box(st[ 7]);
+ st[ 7] = s_box(st[ 3]); st[ 3] = s_box( tt );
+}
+
+static void inv_shift_sub_rows( uint_8t st[N_BLOCK] )
+{ uint_8t tt;
+
+ st[ 0] = is_box(st[ 0]); st[ 4] = is_box(st[ 4]);
+ st[ 8] = is_box(st[ 8]); st[12] = is_box(st[12]);
+
+ tt = st[13]; st[13] = is_box(st[9]); st[ 9] = is_box(st[5]);
+ st[ 5] = is_box(st[1]); st[ 1] = is_box( tt );
+
+ tt = st[2]; st[ 2] = is_box(st[10]); st[10] = is_box( tt );
+ tt = st[6]; st[ 6] = is_box(st[14]); st[14] = is_box( tt );
+
+ tt = st[3]; st[ 3] = is_box(st[ 7]); st[ 7] = is_box(st[11]);
+ st[11] = is_box(st[15]); st[15] = is_box( tt );
+}
+
+#if defined( VERSION_1 )
+ static void mix_sub_columns( uint_8t dt[N_BLOCK] )
+ { uint_8t st[N_BLOCK];
+ block_copy(st, dt);
+#else
+ static void mix_sub_columns( uint_8t dt[N_BLOCK], uint_8t st[N_BLOCK] )
+ {
+#endif
+ dt[ 0] = gfm2_sb(st[0]) ^ gfm3_sb(st[5]) ^ s_box(st[10]) ^ s_box(st[15]);
+ dt[ 1] = s_box(st[0]) ^ gfm2_sb(st[5]) ^ gfm3_sb(st[10]) ^ s_box(st[15]);
+ dt[ 2] = s_box(st[0]) ^ s_box(st[5]) ^ gfm2_sb(st[10]) ^ gfm3_sb(st[15]);
+ dt[ 3] = gfm3_sb(st[0]) ^ s_box(st[5]) ^ s_box(st[10]) ^ gfm2_sb(st[15]);
+
+ dt[ 4] = gfm2_sb(st[4]) ^ gfm3_sb(st[9]) ^ s_box(st[14]) ^ s_box(st[3]);
+ dt[ 5] = s_box(st[4]) ^ gfm2_sb(st[9]) ^ gfm3_sb(st[14]) ^ s_box(st[3]);
+ dt[ 6] = s_box(st[4]) ^ s_box(st[9]) ^ gfm2_sb(st[14]) ^ gfm3_sb(st[3]);
+ dt[ 7] = gfm3_sb(st[4]) ^ s_box(st[9]) ^ s_box(st[14]) ^ gfm2_sb(st[3]);
+
+ dt[ 8] = gfm2_sb(st[8]) ^ gfm3_sb(st[13]) ^ s_box(st[2]) ^ s_box(st[7]);
+ dt[ 9] = s_box(st[8]) ^ gfm2_sb(st[13]) ^ gfm3_sb(st[2]) ^ s_box(st[7]);
+ dt[10] = s_box(st[8]) ^ s_box(st[13]) ^ gfm2_sb(st[2]) ^ gfm3_sb(st[7]);
+ dt[11] = gfm3_sb(st[8]) ^ s_box(st[13]) ^ s_box(st[2]) ^ gfm2_sb(st[7]);
+
+ dt[12] = gfm2_sb(st[12]) ^ gfm3_sb(st[1]) ^ s_box(st[6]) ^ s_box(st[11]);
+ dt[13] = s_box(st[12]) ^ gfm2_sb(st[1]) ^ gfm3_sb(st[6]) ^ s_box(st[11]);
+ dt[14] = s_box(st[12]) ^ s_box(st[1]) ^ gfm2_sb(st[6]) ^ gfm3_sb(st[11]);
+ dt[15] = gfm3_sb(st[12]) ^ s_box(st[1]) ^ s_box(st[6]) ^ gfm2_sb(st[11]);
+ }
+
+#if defined( VERSION_1 )
+ static void inv_mix_sub_columns( uint_8t dt[N_BLOCK] )
+ { uint_8t st[N_BLOCK];
+ block_copy(st, dt);
+#else
+ static void inv_mix_sub_columns( uint_8t dt[N_BLOCK], uint_8t st[N_BLOCK] )
+ {
+#endif
+ dt[ 0] = is_box(gfm_e(st[ 0]) ^ gfm_b(st[ 1]) ^ gfm_d(st[ 2]) ^ gfm_9(st[ 3]));
+ dt[ 5] = is_box(gfm_9(st[ 0]) ^ gfm_e(st[ 1]) ^ gfm_b(st[ 2]) ^ gfm_d(st[ 3]));
+ dt[10] = is_box(gfm_d(st[ 0]) ^ gfm_9(st[ 1]) ^ gfm_e(st[ 2]) ^ gfm_b(st[ 3]));
+ dt[15] = is_box(gfm_b(st[ 0]) ^ gfm_d(st[ 1]) ^ gfm_9(st[ 2]) ^ gfm_e(st[ 3]));
+
+ dt[ 4] = is_box(gfm_e(st[ 4]) ^ gfm_b(st[ 5]) ^ gfm_d(st[ 6]) ^ gfm_9(st[ 7]));
+ dt[ 9] = is_box(gfm_9(st[ 4]) ^ gfm_e(st[ 5]) ^ gfm_b(st[ 6]) ^ gfm_d(st[ 7]));
+ dt[14] = is_box(gfm_d(st[ 4]) ^ gfm_9(st[ 5]) ^ gfm_e(st[ 6]) ^ gfm_b(st[ 7]));
+ dt[ 3] = is_box(gfm_b(st[ 4]) ^ gfm_d(st[ 5]) ^ gfm_9(st[ 6]) ^ gfm_e(st[ 7]));
+
+ dt[ 8] = is_box(gfm_e(st[ 8]) ^ gfm_b(st[ 9]) ^ gfm_d(st[10]) ^ gfm_9(st[11]));
+ dt[13] = is_box(gfm_9(st[ 8]) ^ gfm_e(st[ 9]) ^ gfm_b(st[10]) ^ gfm_d(st[11]));
+ dt[ 2] = is_box(gfm_d(st[ 8]) ^ gfm_9(st[ 9]) ^ gfm_e(st[10]) ^ gfm_b(st[11]));
+ dt[ 7] = is_box(gfm_b(st[ 8]) ^ gfm_d(st[ 9]) ^ gfm_9(st[10]) ^ gfm_e(st[11]));
+
+ dt[12] = is_box(gfm_e(st[12]) ^ gfm_b(st[13]) ^ gfm_d(st[14]) ^ gfm_9(st[15]));
+ dt[ 1] = is_box(gfm_9(st[12]) ^ gfm_e(st[13]) ^ gfm_b(st[14]) ^ gfm_d(st[15]));
+ dt[ 6] = is_box(gfm_d(st[12]) ^ gfm_9(st[13]) ^ gfm_e(st[14]) ^ gfm_b(st[15]));
+ dt[11] = is_box(gfm_b(st[12]) ^ gfm_d(st[13]) ^ gfm_9(st[14]) ^ gfm_e(st[15]));
+ }
+
+#if defined( AES_ENC_PREKEYED ) || defined( AES_DEC_PREKEYED )
+
+/* Set the cipher key for the pre-keyed version */
+
+return_type aes_set_key( const unsigned char key[], length_type keylen, aes_context ctx[1] )
+{
+ uint_8t cc, rc, hi;
+
+ switch( keylen )
+ {
+ case 16:
+ case 128:
+ keylen = 16;
+ break;
+ case 24:
+ case 192:
+ keylen = 24;
+ break;
+ case 32:
+ case 256:
+ keylen = 32;
+ break;
+ default:
+ ctx->rnd = 0;
+ return (return_type)-1;
+ }
+ block_copy_nn(ctx->ksch, key, keylen);
+ hi = (keylen + 28) << 2;
+ ctx->rnd = (hi >> 4) - 1;
+ for( cc = keylen, rc = 1; cc < hi; cc += 4 )
+ { uint_8t tt, t0, t1, t2, t3;
+
+ t0 = ctx->ksch[cc - 4];
+ t1 = ctx->ksch[cc - 3];
+ t2 = ctx->ksch[cc - 2];
+ t3 = ctx->ksch[cc - 1];
+ if( cc % keylen == 0 )
+ {
+ tt = t0;
+ t0 = s_box(t1) ^ rc;
+ t1 = s_box(t2);
+ t2 = s_box(t3);
+ t3 = s_box(tt);
+ rc = f2(rc);
+ }
+ else if( keylen > 24 && cc % keylen == 16 )
+ {
+ t0 = s_box(t0);
+ t1 = s_box(t1);
+ t2 = s_box(t2);
+ t3 = s_box(t3);
+ }
+ tt = cc - keylen;
+ ctx->ksch[cc + 0] = ctx->ksch[tt + 0] ^ t0;
+ ctx->ksch[cc + 1] = ctx->ksch[tt + 1] ^ t1;
+ ctx->ksch[cc + 2] = ctx->ksch[tt + 2] ^ t2;
+ ctx->ksch[cc + 3] = ctx->ksch[tt + 3] ^ t3;
+ }
+ return 0;
+}
+
+#endif
+
+#if defined( AES_ENC_PREKEYED )
+
+/* Encrypt a single block of 16 bytes */
+
+return_type aes_encrypt( const unsigned char in[N_BLOCK], unsigned char out[N_BLOCK], const aes_context ctx[1] )
+{
+ if( ctx->rnd )
+ {
+ uint_8t s1[N_BLOCK], r;
+ copy_and_key( s1, in, ctx->ksch );
+
+ for( r = 1 ; r < ctx->rnd ; ++r )
+#if defined( VERSION_1 )
+ {
+ mix_sub_columns( s1 );
+ add_round_key( s1, ctx->ksch + r * N_BLOCK);
+ }
+#else
+ { uint_8t s2[N_BLOCK];
+ mix_sub_columns( s2, s1 );
+ copy_and_key( s1, s2, ctx->ksch + r * N_BLOCK);
+ }
+#endif
+ shift_sub_rows( s1 );
+ copy_and_key( out, s1, ctx->ksch + r * N_BLOCK );
+ }
+ else
+ return (return_type)-1;
+ return 0;
+}
+
+/* CBC encrypt a number of blocks (input and return an IV) */
+
+return_type aes_cbc_encrypt( const unsigned char *in, unsigned char *out,
+ int n_block, unsigned char iv[N_BLOCK], const aes_context ctx[1] )
+{
+
+ while(n_block--)
+ {
+ xor_block(iv, in);
+ if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)
+ return EXIT_FAILURE;
+ memcpy(out, iv, N_BLOCK);
+ in += N_BLOCK;
+ out += N_BLOCK;
+ }
+ return EXIT_SUCCESS;
+}
+
+#endif
+
+#if defined( AES_DEC_PREKEYED )
+
+/* Decrypt a single block of 16 bytes */
+
+return_type aes_decrypt( const unsigned char in[N_BLOCK], unsigned char out[N_BLOCK], const aes_context ctx[1] )
+{
+ if( ctx->rnd )
+ {
+ uint_8t s1[N_BLOCK], r;
+ copy_and_key( s1, in, ctx->ksch + ctx->rnd * N_BLOCK );
+ inv_shift_sub_rows( s1 );
+
+ for( r = ctx->rnd ; --r ; )
+#if defined( VERSION_1 )
+ {
+ add_round_key( s1, ctx->ksch + r * N_BLOCK );
+ inv_mix_sub_columns( s1 );
+ }
+#else
+ { uint_8t s2[N_BLOCK];
+ copy_and_key( s2, s1, ctx->ksch + r * N_BLOCK );
+ inv_mix_sub_columns( s1, s2 );
+ }
+#endif
+ copy_and_key( out, s1, ctx->ksch );
+ }
+ else
+ return (return_type)-1;
+ return 0;
+}
+
+/* CBC decrypt a number of blocks (input and return an IV) */
+
+return_type aes_cbc_decrypt( const unsigned char *in, unsigned char *out,
+ int n_block, unsigned char iv[N_BLOCK], const aes_context ctx[1] )
+{
+ while(n_block--)
+ { uint_8t tmp[N_BLOCK];
+
+ memcpy(tmp, in, N_BLOCK);
+ if(aes_decrypt(in, out, ctx) != EXIT_SUCCESS)
+ return EXIT_FAILURE;
+ xor_block(out, iv);
+ memcpy(iv, tmp, N_BLOCK);
+ in += N_BLOCK;
+ out += N_BLOCK;
+ }
+ return EXIT_SUCCESS;
+}
+
+#endif
+
+#if defined( AES_ENC_128_OTFK )
+
+/* The 'on the fly' encryption key update for for 128 bit keys */
+
+static void update_encrypt_key_128( uint_8t k[N_BLOCK], uint_8t *rc )
+{ uint_8t cc;
+
+ k[0] ^= s_box(k[13]) ^ *rc;
+ k[1] ^= s_box(k[14]);
+ k[2] ^= s_box(k[15]);
+ k[3] ^= s_box(k[12]);
+ *rc = f2( *rc );
+
+ for(cc = 4; cc < 16; cc += 4 )
+ {
+ k[cc + 0] ^= k[cc - 4];
+ k[cc + 1] ^= k[cc - 3];
+ k[cc + 2] ^= k[cc - 2];
+ k[cc + 3] ^= k[cc - 1];
+ }
+}
+
+/* Encrypt a single block of 16 bytes with 'on the fly' 128 bit keying */
+
+void aes_encrypt_128( const unsigned char in[N_BLOCK], unsigned char out[N_BLOCK],
+ const unsigned char key[N_BLOCK], unsigned char o_key[N_BLOCK] )
+{ uint_8t s1[N_BLOCK], r, rc = 1;
+
+ if(o_key != key)
+ block_copy( o_key, key );
+ copy_and_key( s1, in, o_key );
+
+ for( r = 1 ; r < 10 ; ++r )
+#if defined( VERSION_1 )
+ {
+ mix_sub_columns( s1 );
+ update_encrypt_key_128( o_key, &rc );
+ add_round_key( s1, o_key );
+ }
+#else
+ { uint_8t s2[N_BLOCK];
+ mix_sub_columns( s2, s1 );
+ update_encrypt_key_128( o_key, &rc );
+ copy_and_key( s1, s2, o_key );
+ }
+#endif
+
+ shift_sub_rows( s1 );
+ update_encrypt_key_128( o_key, &rc );
+ copy_and_key( out, s1, o_key );
+}
+
+#endif
+
+#if defined( AES_DEC_128_OTFK )
+
+/* The 'on the fly' decryption key update for for 128 bit keys */
+
+static void update_decrypt_key_128( uint_8t k[N_BLOCK], uint_8t *rc )
+{ uint_8t cc;
+
+ for( cc = 12; cc > 0; cc -= 4 )
+ {
+ k[cc + 0] ^= k[cc - 4];
+ k[cc + 1] ^= k[cc - 3];
+ k[cc + 2] ^= k[cc - 2];
+ k[cc + 3] ^= k[cc - 1];
+ }
+ *rc = d2(*rc);
+ k[0] ^= s_box(k[13]) ^ *rc;
+ k[1] ^= s_box(k[14]);
+ k[2] ^= s_box(k[15]);
+ k[3] ^= s_box(k[12]);
+}
+
+/* Decrypt a single block of 16 bytes with 'on the fly' 128 bit keying */
+
+void aes_decrypt_128( const unsigned char in[N_BLOCK], unsigned char out[N_BLOCK],
+ const unsigned char key[N_BLOCK], unsigned char o_key[N_BLOCK] )
+{
+ uint_8t s1[N_BLOCK], r, rc = 0x6c;
+ if(o_key != key)
+ block_copy( o_key, key );
+
+ copy_and_key( s1, in, o_key );
+ inv_shift_sub_rows( s1 );
+
+ for( r = 10 ; --r ; )
+#if defined( VERSION_1 )
+ {
+ update_decrypt_key_128( o_key, &rc );
+ add_round_key( s1, o_key );
+ inv_mix_sub_columns( s1 );
+ }
+#else
+ { uint_8t s2[N_BLOCK];
+ update_decrypt_key_128( o_key, &rc );
+ copy_and_key( s2, s1, o_key );
+ inv_mix_sub_columns( s1, s2 );
+ }
+#endif
+ update_decrypt_key_128( o_key, &rc );
+ copy_and_key( out, s1, o_key );
+}
+
+#endif
+
+#if defined( AES_ENC_256_OTFK )
+
+/* The 'on the fly' encryption key update for for 256 bit keys */
+
+static void update_encrypt_key_256( uint_8t k[2 * N_BLOCK], uint_8t *rc )
+{ uint_8t cc;
+
+ k[0] ^= s_box(k[29]) ^ *rc;
+ k[1] ^= s_box(k[30]);
+ k[2] ^= s_box(k[31]);
+ k[3] ^= s_box(k[28]);
+ *rc = f2( *rc );
+
+ for(cc = 4; cc < 16; cc += 4)
+ {
+ k[cc + 0] ^= k[cc - 4];
+ k[cc + 1] ^= k[cc - 3];
+ k[cc + 2] ^= k[cc - 2];
+ k[cc + 3] ^= k[cc - 1];
+ }
+
+ k[16] ^= s_box(k[12]);
+ k[17] ^= s_box(k[13]);
+ k[18] ^= s_box(k[14]);
+ k[19] ^= s_box(k[15]);
+
+ for( cc = 20; cc < 32; cc += 4 )
+ {
+ k[cc + 0] ^= k[cc - 4];
+ k[cc + 1] ^= k[cc - 3];
+ k[cc + 2] ^= k[cc - 2];
+ k[cc + 3] ^= k[cc - 1];
+ }
+}
+
+/* Encrypt a single block of 16 bytes with 'on the fly' 256 bit keying */
+
+void aes_encrypt_256( const unsigned char in[N_BLOCK], unsigned char out[N_BLOCK],
+ const unsigned char key[2 * N_BLOCK], unsigned char o_key[2 * N_BLOCK] )
+{
+ uint_8t s1[N_BLOCK], r, rc = 1;
+ if(o_key != key)
+ {
+ block_copy( o_key, key );
+ block_copy( o_key + 16, key + 16 );
+ }
+ copy_and_key( s1, in, o_key );
+
+ for( r = 1 ; r < 14 ; ++r )
+#if defined( VERSION_1 )
+ {
+ mix_sub_columns(s1);
+ if( r & 1 )
+ add_round_key( s1, o_key + 16 );
+ else
+ {
+ update_encrypt_key_256( o_key, &rc );
+ add_round_key( s1, o_key );
+ }
+ }
+#else
+ { uint_8t s2[N_BLOCK];
+ mix_sub_columns( s2, s1 );
+ if( r & 1 )
+ copy_and_key( s1, s2, o_key + 16 );
+ else
+ {
+ update_encrypt_key_256( o_key, &rc );
+ copy_and_key( s1, s2, o_key );
+ }
+ }
+#endif
+
+ shift_sub_rows( s1 );
+ update_encrypt_key_256( o_key, &rc );
+ copy_and_key( out, s1, o_key );
+}
+
+#endif
+
+#if defined( AES_DEC_256_OTFK )
+
+/* The 'on the fly' encryption key update for for 256 bit keys */
+
+static void update_decrypt_key_256( uint_8t k[2 * N_BLOCK], uint_8t *rc )
+{ uint_8t cc;
+
+ for(cc = 28; cc > 16; cc -= 4)
+ {
+ k[cc + 0] ^= k[cc - 4];
+ k[cc + 1] ^= k[cc - 3];
+ k[cc + 2] ^= k[cc - 2];
+ k[cc + 3] ^= k[cc - 1];
+ }
+
+ k[16] ^= s_box(k[12]);
+ k[17] ^= s_box(k[13]);
+ k[18] ^= s_box(k[14]);
+ k[19] ^= s_box(k[15]);
+
+ for(cc = 12; cc > 0; cc -= 4)
+ {
+ k[cc + 0] ^= k[cc - 4];
+ k[cc + 1] ^= k[cc - 3];
+ k[cc + 2] ^= k[cc - 2];
+ k[cc + 3] ^= k[cc - 1];
+ }
+
+ *rc = d2(*rc);
+ k[0] ^= s_box(k[29]) ^ *rc;
+ k[1] ^= s_box(k[30]);
+ k[2] ^= s_box(k[31]);
+ k[3] ^= s_box(k[28]);
+}
+
+/* Decrypt a single block of 16 bytes with 'on the fly'
+ 256 bit keying
+*/
+void aes_decrypt_256( const unsigned char in[N_BLOCK], unsigned char out[N_BLOCK],
+ const unsigned char key[2 * N_BLOCK], unsigned char o_key[2 * N_BLOCK] )
+{
+ uint_8t s1[N_BLOCK], r, rc = 0x80;
+
+ if(o_key != key)
+ {
+ block_copy( o_key, key );
+ block_copy( o_key + 16, key + 16 );
+ }
+
+ copy_and_key( s1, in, o_key );
+ inv_shift_sub_rows( s1 );
+
+ for( r = 14 ; --r ; )
+#if defined( VERSION_1 )
+ {
+ if( ( r & 1 ) )
+ {
+ update_decrypt_key_256( o_key, &rc );
+ add_round_key( s1, o_key + 16 );
+ }
+ else
+ add_round_key( s1, o_key );
+ inv_mix_sub_columns( s1 );
+ }
+#else
+ { uint_8t s2[N_BLOCK];
+ if( ( r & 1 ) )
+ {
+ update_decrypt_key_256( o_key, &rc );
+ copy_and_key( s2, s1, o_key + 16 );
+ }
+ else
+ copy_and_key( s2, s1, o_key );
+ inv_mix_sub_columns( s1, s2 );
+ }
+#endif
+ copy_and_key( out, s1, o_key );
+}
+
+#endif
diff --git a/stack/smp/aes.h b/stack/smp/aes.h
new file mode 100644
index 0000000..dcfde93
--- /dev/null
+++ b/stack/smp/aes.h
@@ -0,0 +1,162 @@
+/*
+ ---------------------------------------------------------------------------
+ Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved.
+
+ LICENSE TERMS
+
+ The redistribution and use of this software (with or without changes)
+ is allowed without the payment of fees or royalties provided that:
+
+ 1. source code distributions include the above copyright notice, this
+ list of conditions and the following disclaimer;
+
+ 2. binary distributions include the above copyright notice, this list
+ of conditions and the following disclaimer in their documentation;
+
+ 3. the name of the copyright holder is not used to endorse products
+ built using this software without specific written permission.
+
+ DISCLAIMER
+
+ This software is provided 'as is' with no explicit or implied warranties
+ in respect of its properties, including, but not limited to, correctness
+ and/or fitness for purpose.
+ ---------------------------------------------------------------------------
+ Issue 09/09/2006
+
+ This is an AES implementation that uses only 8-bit byte operations on the
+ cipher state.
+ */
+
+#ifndef AES_H
+#define AES_H
+
+#if 1
+# define AES_ENC_PREKEYED /* AES encryption with a precomputed key schedule */
+#endif
+#if 1
+# define AES_DEC_PREKEYED /* AES decryption with a precomputed key schedule */
+#endif
+#if 1
+# define AES_ENC_128_OTFK /* AES encryption with 'on the fly' 128 bit keying */
+#endif
+#if 1
+# define AES_DEC_128_OTFK /* AES decryption with 'on the fly' 128 bit keying */
+#endif
+#if 1
+# define AES_ENC_256_OTFK /* AES encryption with 'on the fly' 256 bit keying */
+#endif
+#if 1
+# define AES_DEC_256_OTFK /* AES decryption with 'on the fly' 256 bit keying */
+#endif
+
+#define N_ROW 4
+#define N_COL 4
+#define N_BLOCK (N_ROW * N_COL)
+#define N_MAX_ROUNDS 14
+
+typedef unsigned char uint_8t;
+
+typedef uint_8t return_type;
+
+/* Warning: The key length for 256 bit keys overflows a byte
+ (see comment below)
+*/
+
+typedef uint_8t length_type;
+
+typedef struct
+{ uint_8t ksch[(N_MAX_ROUNDS + 1) * N_BLOCK];
+ uint_8t rnd;
+} aes_context;
+
+/* The following calls are for a precomputed key schedule
+
+ NOTE: If the length_type used for the key length is an
+ unsigned 8-bit character, a key length of 256 bits must
+ be entered as a length in bytes (valid inputs are hence
+ 128, 192, 16, 24 and 32).
+*/
+
+#if defined( AES_ENC_PREKEYED ) || defined( AES_DEC_PREKEYED )
+
+return_type aes_set_key( const unsigned char key[],
+ length_type keylen,
+ aes_context ctx[1] );
+#endif
+
+#if defined( AES_ENC_PREKEYED )
+
+return_type aes_encrypt( const unsigned char in[N_BLOCK],
+ unsigned char out[N_BLOCK],
+ const aes_context ctx[1] );
+
+return_type aes_cbc_encrypt( const unsigned char *in,
+ unsigned char *out,
+ int n_block,
+ unsigned char iv[N_BLOCK],
+ const aes_context ctx[1] );
+#endif
+
+#if defined( AES_DEC_PREKEYED )
+
+return_type aes_decrypt( const unsigned char in[N_BLOCK],
+ unsigned char out[N_BLOCK],
+ const aes_context ctx[1] );
+
+return_type aes_cbc_decrypt( const unsigned char *in,
+ unsigned char *out,
+ int n_block,
+ unsigned char iv[N_BLOCK],
+ const aes_context ctx[1] );
+#endif
+
+/* The following calls are for 'on the fly' keying. In this case the
+ encryption and decryption keys are different.
+
+ The encryption subroutines take a key in an array of bytes in
+ key[L] where L is 16, 24 or 32 bytes for key lengths of 128,
+ 192, and 256 bits respectively. They then encrypts the input
+ data, in[] with this key and put the reult in the output array
+ out[]. In addition, the second key array, o_key[L], is used
+ to output the key that is needed by the decryption subroutine
+ to reverse the encryption operation. The two key arrays can
+ be the same array but in this case the original key will be
+ overwritten.
+
+ In the same way, the decryption subroutines output keys that
+ can be used to reverse their effect when used for encryption.
+
+ Only 128 and 256 bit keys are supported in these 'on the fly'
+ modes.
+*/
+
+#if defined( AES_ENC_128_OTFK )
+void aes_encrypt_128( const unsigned char in[N_BLOCK],
+ unsigned char out[N_BLOCK],
+ const unsigned char key[N_BLOCK],
+ uint_8t o_key[N_BLOCK] );
+#endif
+
+#if defined( AES_DEC_128_OTFK )
+void aes_decrypt_128( const unsigned char in[N_BLOCK],
+ unsigned char out[N_BLOCK],
+ const unsigned char key[N_BLOCK],
+ unsigned char o_key[N_BLOCK] );
+#endif
+
+#if defined( AES_ENC_256_OTFK )
+void aes_encrypt_256( const unsigned char in[N_BLOCK],
+ unsigned char out[N_BLOCK],
+ const unsigned char key[2 * N_BLOCK],
+ unsigned char o_key[2 * N_BLOCK] );
+#endif
+
+#if defined( AES_DEC_256_OTFK )
+void aes_decrypt_256( const unsigned char in[N_BLOCK],
+ unsigned char out[N_BLOCK],
+ const unsigned char key[2 * N_BLOCK],
+ unsigned char o_key[2 * N_BLOCK] );
+#endif
+
+#endif
diff --git a/stack/smp/smp_act.c b/stack/smp/smp_act.c
new file mode 100644
index 0000000..af4bd2e
--- /dev/null
+++ b/stack/smp/smp_act.c
@@ -0,0 +1,943 @@
+/*****************************************************************************
+**
+** Name: smp_act.c
+**
+** File: SMP Action Functions
+**
+** Copyright (c) 2003-2009, Broadcom Corp., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+
+#if SMP_INCLUDED == TRUE
+
+ #include <string.h>
+ #include "btm_int.h"
+ #include "l2c_api.h"
+ #include "smp_int.h"
+
+
+const UINT8 smp_association_table[2][SMP_IO_CAP_MAX][SMP_IO_CAP_MAX] =
+{
+ /* initiator */
+ {{SMP_MODEL_ENC_ONLY, SMP_MODEL_ENC_ONLY, SMP_MODEL_PASSKEY, SMP_MODEL_ENC_ONLY, SMP_MODEL_PASSKEY}, /* Display Only */
+ {SMP_MODEL_ENC_ONLY, SMP_MODEL_ENC_ONLY, SMP_MODEL_PASSKEY, SMP_MODEL_ENC_ONLY, SMP_MODEL_PASSKEY}, /* SMP_CAP_IO = 1 */
+ {SMP_MODEL_KEY_NOTIF, SMP_MODEL_KEY_NOTIF, SMP_MODEL_PASSKEY, SMP_MODEL_ENC_ONLY, SMP_MODEL_KEY_NOTIF}, /* keyboard only */
+ {SMP_MODEL_ENC_ONLY, SMP_MODEL_ENC_ONLY, SMP_MODEL_ENC_ONLY, SMP_MODEL_ENC_ONLY, SMP_MODEL_ENC_ONLY},/* No Input No Output */
+ {SMP_MODEL_KEY_NOTIF, SMP_MODEL_KEY_NOTIF, SMP_MODEL_PASSKEY, SMP_MODEL_ENC_ONLY, SMP_MODEL_KEY_NOTIF}}, /* keyboard display */
+ /* responder */
+ {{SMP_MODEL_ENC_ONLY, SMP_MODEL_ENC_ONLY, SMP_MODEL_KEY_NOTIF, SMP_MODEL_ENC_ONLY, SMP_MODEL_KEY_NOTIF}, /* Display Only */
+ {SMP_MODEL_ENC_ONLY, SMP_MODEL_ENC_ONLY, SMP_MODEL_PASSKEY, SMP_MODEL_ENC_ONLY, SMP_MODEL_KEY_NOTIF}, /* SMP_CAP_IO = 1 */
+ {SMP_MODEL_PASSKEY, SMP_MODEL_PASSKEY, SMP_MODEL_PASSKEY, SMP_MODEL_ENC_ONLY, SMP_MODEL_PASSKEY}, /* keyboard only */
+ {SMP_MODEL_ENC_ONLY, SMP_MODEL_ENC_ONLY, SMP_MODEL_ENC_ONLY, SMP_MODEL_ENC_ONLY, SMP_MODEL_ENC_ONLY},/* No Input No Output */
+ {SMP_MODEL_PASSKEY, SMP_MODEL_PASSKEY, SMP_MODEL_KEY_NOTIF, SMP_MODEL_ENC_ONLY, SMP_MODEL_PASSKEY}} /* keyboard display */
+ /* display only */ /*SMP_CAP_IO = 1 */ /* keyboard only */ /* No InputOutput */ /* keyboard display */
+};
+
+const tSMP_ACT smp_distribute_act [] =
+{
+ smp_generate_ltk,
+ smp_send_id_info,
+ smp_generate_csrk
+};
+
+/*******************************************************************************
+** Function smp_update_key_mask
+** Description This function updates the key mask for sending or receiving.
+*******************************************************************************/
+static void smp_update_key_mask (tSMP_CB *p_cb, UINT8 key_type, BOOLEAN recv)
+{
+ SMP_TRACE_DEBUG0 ("smp_update_key_mask ");
+ SMP_TRACE_DEBUG4("before update role=%d recv=%d loc_i_key = %02x, loc_r_key = %02x", p_cb->role, recv, p_cb->loc_i_key, p_cb->loc_r_key);
+ if (p_cb->role == HCI_ROLE_SLAVE)
+ {
+ if (recv)
+ p_cb->loc_i_key &= ~key_type;
+ else
+ p_cb->loc_r_key &= ~key_type;
+ }
+ else
+ {
+ if (recv)
+ p_cb->loc_r_key &= ~key_type;
+ else
+ p_cb->loc_i_key &= ~key_type;
+ }
+
+ SMP_TRACE_DEBUG2("updated loc_i_key = %02x, loc_r_key = %02x", p_cb->loc_i_key, p_cb->loc_r_key);
+}
+/*******************************************************************************
+** Function smp_io_cap_req
+** Description send SMP IO request
+*******************************************************************************/
+void smp_send_app_cback(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ tSMP_EVT_DATA cb_data;
+ tSMP_STATUS callback_rc;
+ SMP_TRACE_DEBUG1 ("smp_send_app_cback p_cb->cb_evt=%d", p_cb->cb_evt );
+ if (p_cb->p_callback && p_cb->cb_evt != 0)
+ {
+ if (p_cb->cb_evt == SMP_IO_CAP_REQ_EVT)
+ {
+ cb_data.io_req.auth_req = p_cb->peer_auth_req;
+ cb_data.io_req.oob_data = SMP_OOB_NONE;
+ cb_data.io_req.io_cap = SMP_DEFAULT_IO_CAPS;
+ cb_data.io_req.max_key_size = SMP_MAX_ENC_KEY_SIZE;
+ cb_data.io_req.init_keys = p_cb->loc_i_key ;
+ cb_data.io_req.resp_keys = p_cb->loc_r_key ;
+
+ SMP_TRACE_WARNING1( "io_cap = %d",cb_data.io_req.io_cap);
+ }
+ callback_rc = (*p_cb->p_callback)(p_cb->cb_evt, p_cb->pairing_bda, &cb_data);
+
+ SMP_TRACE_DEBUG2 ("callback_rc=%d p_cb->cb_evt=%d",callback_rc, p_cb->cb_evt );
+
+ if (callback_rc == SMP_SUCCESS && p_cb->cb_evt == SMP_IO_CAP_REQ_EVT)
+ {
+ p_cb->loc_auth_req = cb_data.io_req.auth_req;
+ p_cb->loc_io_caps = cb_data.io_req.io_cap;
+ p_cb->loc_oob_flag = cb_data.io_req.oob_data;
+ p_cb->loc_enc_size = cb_data.io_req.max_key_size;
+ p_cb->loc_i_key = cb_data.io_req.init_keys;
+ p_cb->loc_r_key = cb_data.io_req.resp_keys;
+
+ SMP_TRACE_WARNING2( "new io_cap = %d p_cb->loc_enc_size = %d",p_cb->loc_io_caps, p_cb->loc_enc_size);
+
+ smp_sm_event(p_cb, SMP_IO_RSP_EVT, NULL);
+ }
+ }
+
+ if (!p_cb->cb_evt && p_cb->discard_sec_req)
+ {
+ p_cb->discard_sec_req = FALSE;
+ smp_sm_event(p_cb, SMP_DISCARD_SEC_REQ_EVT, NULL);
+ }
+ SMP_TRACE_DEBUG0 ("smp_send_app_cback return");
+}
+/*******************************************************************************
+** Function smp_send_pair_fail
+** Description pairing failure to peer device if needed.
+*******************************************************************************/
+void smp_send_pair_fail(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ p_cb->status = *(UINT8 *)p_data;
+ p_cb->failure = *(UINT8 *)p_data;
+
+ SMP_TRACE_DEBUG2 ("smp_send_pair_fail status=%d failure=%d ",p_cb->status, p_cb->failure);
+
+ if (p_cb->status <= SMP_REPEATED_ATTEMPTS && p_cb->status != SMP_SUCCESS)
+ {
+ smp_send_cmd(SMP_OPCODE_PAIRING_FAILED, p_cb);
+ }
+}
+
+/*******************************************************************************
+** Function smp_send_pair_req
+** Description process pairing request to slave device
+*******************************************************************************/
+void smp_send_pair_req(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (p_cb->pairing_bda);
+ SMP_TRACE_DEBUG0 ("smp_send_pair_req ");
+
+ /* erase all keys when master sends pairing req*/
+ if (p_dev_rec)
+ btm_sec_clear_ble_keys(p_dev_rec);
+ /* do not manipulate the key, let app decide,
+ leave out to BTM to mandate key distribution for bonding case */
+ smp_send_cmd(SMP_OPCODE_PAIRING_REQ, p_cb);
+}
+/*******************************************************************************
+** Function smp_send_pair_rsp
+** Description process pairing response to slave device
+*******************************************************************************/
+void smp_send_pair_rsp(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG0 ("smp_send_pair_rsp ");
+
+ p_cb->loc_i_key &= p_cb->peer_i_key;
+ p_cb->loc_r_key &= p_cb->peer_r_key;
+
+ if (smp_send_cmd (SMP_OPCODE_PAIRING_RSP, p_cb))
+ {
+ smp_decide_asso_model(p_cb, NULL);
+ }
+}
+
+/*******************************************************************************
+** Function smp_send_pair_request
+** Description process pairing request to slave device
+*******************************************************************************/
+void smp_send_confirm(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG0 ("smp_send_confirm ");
+ smp_send_cmd(SMP_OPCODE_CONFIRM, p_cb);
+}
+/*******************************************************************************
+** Function smp_send_init
+** Description process pairing initializer to slave device
+*******************************************************************************/
+void smp_send_init(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG0 ("smp_send_init ");
+
+#if SMP_CONFORMANCE_TESTING == TRUE
+ if (p_cb->enable_test_rand_val)
+ {
+ SMP_TRACE_DEBUG0 ("Use rand value from script");
+ memcpy(p_cb->rand, p_cb->test_rand, BT_OCTET16_LEN);
+ }
+#endif
+
+ smp_send_cmd(SMP_OPCODE_INIT, p_cb);
+}
+/*******************************************************************************
+** Function smp_send_enc_info
+** Description send security information command.
+*******************************************************************************/
+void smp_send_enc_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ tBTM_LE_LENC_KEYS le_key;
+
+ SMP_TRACE_DEBUG1 ("smp_send_enc_info p_cb->loc_enc_size = %d", p_cb->loc_enc_size);
+ smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_ENC, FALSE);
+
+ smp_send_cmd(SMP_OPCODE_ENCRYPT_INFO, p_cb);
+ smp_send_cmd(SMP_OPCODE_MASTER_ID, p_cb);
+
+ /* save the DIV and key size information when acting as slave device */
+ le_key.div = p_cb->div;
+ le_key.key_size = p_cb->loc_enc_size;
+ le_key.sec_level = p_cb->sec_level;
+ btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_LENC, (tBTM_LE_KEY_VALUE *)&le_key, TRUE);
+
+ SMP_TRACE_WARNING0( "smp_send_enc_info");
+
+ smp_key_distribution(p_cb, NULL);
+}
+/*******************************************************************************
+** Function smp_send_id_info
+** Description send ID information command.
+*******************************************************************************/
+void smp_send_id_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG0 ("smp_send_id_info ");
+ smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_ID, FALSE);
+
+ smp_send_cmd(SMP_OPCODE_IDENTITY_INFO, p_cb);
+ smp_send_cmd(SMP_OPCODE_ID_ADDR, p_cb);
+
+ SMP_TRACE_WARNING0( "smp_send_id_info");
+
+ smp_key_distribution(p_cb, NULL);
+}
+/*******************************************************************************
+** Function smp_send_csrk_info
+** Description send CSRK command.
+*******************************************************************************/
+void smp_send_csrk_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ tBTM_LE_KEY_VALUE key;
+ SMP_TRACE_DEBUG0 ("smp_send_csrk_info ");
+ smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_CSRK, FALSE);
+
+ if (smp_send_cmd(SMP_OPCODE_SIGN_INFO, p_cb))
+ {
+ key.lcsrk_key.div = p_cb->div;
+ key.lcsrk_key.sec_level = p_cb->sec_level;
+ key.lcsrk_key.counter = 0; /* initialize the local counter */
+ btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_LCSRK, &key, TRUE);
+ }
+
+ smp_key_distribution(p_cb, NULL);
+}
+
+/*******************************************************************************
+** Function smp_send_ltk_reply
+** Description send LTK reply
+*******************************************************************************/
+void smp_send_ltk_reply(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG0 ("smp_send_ltk_reply ");
+ /* send stk as LTK response */
+ btm_ble_ltk_request_reply(p_cb->pairing_bda, TRUE, p_data->key.p_data);
+}
+/*******************************************************************************
+** Function smp_proc_sec_req
+** Description process security request.
+*******************************************************************************/
+void smp_proc_sec_req(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ tBTM_LE_AUTH_REQ auth_req = *(tBTM_LE_AUTH_REQ *)p_data;
+ tBTM_BLE_SEC_REQ_ACT sec_req_act;
+
+
+ SMP_TRACE_DEBUG1 ("smp_proc_sec_req auth_req=0x%x",auth_req);
+
+ p_cb->cb_evt = 0;
+
+ btm_ble_link_sec_check(p_cb->pairing_bda, auth_req, &sec_req_act);
+
+ SMP_TRACE_DEBUG1 ("smp_proc_sec_req sec_req_act=0x%x",sec_req_act);
+
+ switch (sec_req_act)
+ {
+ case BTM_BLE_SEC_REQ_ACT_ENCRYPT:
+ SMP_TRACE_DEBUG0 ("smp_proc_sec_req BTM_BLE_SEC_REQ_ACT_ENCRYPT");
+ smp_sm_event(p_cb, SMP_ENC_REQ_EVT, NULL);
+ break;
+
+ case BTM_BLE_SEC_REQ_ACT_PAIR:
+ /* initialize local i/r key to be default keys */
+ SMP_TRACE_DEBUG0 ("smp_proc_sec_req BTM_BLE_SEC_REQ_ACT_PAIR");
+ p_cb->peer_auth_req = auth_req;
+ p_cb->loc_r_key = p_cb->loc_i_key = SMP_SEC_DEFAULT_KEY ;
+ p_cb->cb_evt = SMP_SEC_REQUEST_EVT;
+ break;
+
+ case BTM_BLE_SEC_REQ_ACT_DISCARD:
+ p_cb->discard_sec_req = TRUE;
+ break;
+
+ default:
+ /* do nothing */
+ break;
+ }
+}
+/*******************************************************************************
+** Function smp_proc_sec_grant
+** Description process security grant.
+*******************************************************************************/
+void smp_proc_sec_grant(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UINT8 res= *(UINT8 *)p_data;
+ SMP_TRACE_DEBUG0 ("smp_proc_sec_grant ");
+ if (res != SMP_SUCCESS)
+ {
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, p_data);
+ }
+ else /*otherwise, start pairing */
+ {
+ /* send IO request callback */
+ p_cb->cb_evt = SMP_IO_CAP_REQ_EVT;
+ }
+}
+/*******************************************************************************
+** Function smp_proc_pair_fail
+** Description process pairing failure from peer device
+*******************************************************************************/
+void smp_proc_pair_fail(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG0 ("smp_proc_pair_fail ");
+ p_cb->status = *(UINT8 *)p_data;
+}
+/*******************************************************************************
+** Function smp_proc_pair_cmd
+** Description Process the SMP pairing request/response from peer device
+*******************************************************************************/
+void smp_proc_pair_cmd(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UINT8 *p = (UINT8 *)p_data;
+ UINT8 reason = SMP_ENC_KEY_SIZE;
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (p_cb->pairing_bda);
+
+ SMP_TRACE_DEBUG0 ("smp_proc_pair_cmd ");
+ /* erase all keys if it is slave proc pairing req*/
+ if (p_dev_rec && (p_cb->role == HCI_ROLE_SLAVE))
+ btm_sec_clear_ble_keys(p_dev_rec);
+
+ p_cb->flags |= SMP_PAIR_FLAG_ENC_AFTER_PAIR;
+
+ STREAM_TO_UINT8(p_cb->peer_io_caps, p);
+ STREAM_TO_UINT8(p_cb->peer_oob_flag, p);
+ STREAM_TO_UINT8(p_cb->peer_auth_req, p);
+ STREAM_TO_UINT8(p_cb->peer_enc_size, p);
+ STREAM_TO_UINT8(p_cb->peer_i_key, p);
+ STREAM_TO_UINT8(p_cb->peer_r_key, p);
+
+#if SMP_CONFORMANCE_TESTING == TRUE
+ if (p_cb->enable_test_pair_fail)
+ {
+ SMP_TRACE_DEBUG0 ("Forced pair fair");
+ if (p_cb->peer_enc_size < SMP_MIN_ENC_KEY_SIZE)
+ {
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ }
+ else
+ {
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &(p_cb->pair_fail_status));
+ }
+ return;
+ }
+#endif
+
+
+ if (p_cb->peer_enc_size < SMP_MIN_ENC_KEY_SIZE)
+ {
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ }
+ else if (p_cb->role == HCI_ROLE_SLAVE)
+ {
+ if (!(p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD))
+ {
+ p_cb->loc_i_key = p_cb->peer_i_key;
+ p_cb->loc_r_key = p_cb->peer_r_key;
+ }
+ else /* update local i/r key according to pairing request */
+ {
+ p_cb->loc_i_key &= p_cb->peer_i_key;
+ p_cb->loc_r_key &= p_cb->peer_r_key;
+ }
+
+ p_cb->cb_evt = SMP_SEC_REQUEST_EVT;
+ }
+}
+/*******************************************************************************
+** Function smp_proc_confirm
+** Description process pairing confirm from peer device
+*******************************************************************************/
+void smp_proc_confirm(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UINT8 *p = (UINT8 *)p_data;
+
+ SMP_TRACE_DEBUG0 ("smp_proc_confirm ");
+ if (p != NULL)
+ {
+ /* save the SConfirm for comparison later */
+ STREAM_TO_ARRAY(p_cb->rconfirm, p, BT_OCTET16_LEN);
+ }
+
+ p_cb->flags |= SMP_PAIR_FLAGS_CMD_CONFIRM;
+}
+
+/*******************************************************************************
+** Function smp_proc_init
+** Description process pairing initializer from peer device
+*******************************************************************************/
+void smp_proc_init(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UINT8 *p = (UINT8 *)p_data;
+ SMP_TRACE_DEBUG0 ("smp_proc_init ");
+ /* save the SRand for comparison */
+ STREAM_TO_ARRAY(p_cb->rrand, p, BT_OCTET16_LEN);
+
+}
+/*******************************************************************************
+** Function smp_proc_enc_info
+** Description process encryption information from peer device
+*******************************************************************************/
+void smp_proc_enc_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UINT8 *p = (UINT8 *)p_data;
+
+ SMP_TRACE_DEBUG0 ("smp_proc_enc_info ");
+ STREAM_TO_ARRAY(p_cb->ltk, p, BT_OCTET16_LEN);
+
+ smp_key_distribution(p_cb, NULL);
+}
+/*******************************************************************************
+** Function smp_proc_master_id
+** Description process master ID from slave device
+*******************************************************************************/
+void smp_proc_master_id(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UINT8 *p = (UINT8 *)p_data;
+ tBTM_LE_PENC_KEYS le_key;
+
+ SMP_TRACE_DEBUG0 (" smp_proc_master_id");
+ smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_ENC, TRUE);
+
+ STREAM_TO_UINT16(le_key.ediv, p);
+ STREAM_TO_ARRAY(le_key.rand, p, BT_OCTET8_LEN );
+
+ /* store the encryption keys from peer device */
+ memcpy(le_key.ltk, p_cb->ltk, BT_OCTET16_LEN);
+ le_key.sec_level = p_cb->sec_level;
+ le_key.key_size = p_cb->loc_enc_size;
+ btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_PENC, (tBTM_LE_KEY_VALUE *)&le_key, TRUE);
+
+ smp_key_distribution(p_cb, NULL);
+}
+/*******************************************************************************
+** Function smp_proc_enc_info
+** Description process identity information from peer device
+*******************************************************************************/
+void smp_proc_id_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UINT8 *p = (UINT8 *)p_data;
+
+ SMP_TRACE_DEBUG0 ("smp_proc_id_info ");
+ STREAM_TO_ARRAY (p_cb->tk, p, BT_OCTET16_LEN); /* reuse TK for IRK */
+ /* store the ID key from peer device */
+ btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_PID, (tBTM_LE_KEY_VALUE *)&p_cb->tk, TRUE);
+
+ smp_key_distribution(p_cb, NULL);
+}
+/*******************************************************************************
+** Function smp_proc_id_addr
+** Description process identity address from peer device
+*******************************************************************************/
+void smp_proc_id_addr(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UINT8 *p = (UINT8 *)p_data;
+ BD_ADDR mac_bda;
+
+ SMP_TRACE_DEBUG0 ("smp_proc_id_addr ");
+ smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_ID, TRUE);
+
+ STREAM_TO_BDADDR(mac_bda, p);
+
+ /* TODO, update MAC address */
+
+ smp_key_distribution(p_cb, NULL);
+}
+/*******************************************************************************
+** Function smp_proc_srk_info
+** Description process security information from peer device
+*******************************************************************************/
+void smp_proc_srk_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ tBTM_LE_PCSRK_KEYS le_key;
+
+ SMP_TRACE_DEBUG0 ("smp_proc_srk_info ");
+ smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_CSRK, TRUE);
+
+ /* save CSRK to security record */
+ le_key.sec_level = p_cb->sec_level;
+ memcpy (le_key.csrk, p_data, BT_OCTET16_LEN); /* get peer CSRK */
+ le_key.counter = 0; /* initialize the peer counter */
+ btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_PCSRK, (tBTM_LE_KEY_VALUE *)&le_key, TRUE);
+
+ smp_key_distribution(p_cb, NULL);
+}
+
+/*******************************************************************************
+** Function smp_proc_compare
+** Description process compare value
+*******************************************************************************/
+void smp_proc_compare(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UINT8 reason;
+
+ SMP_TRACE_DEBUG0 ("smp_proc_compare ");
+ if (!memcmp(p_cb->rconfirm, p_data->key.p_data, BT_OCTET16_LEN))
+ {
+ /* compare the max encryption key size, and save the smaller one for the link */
+ if ( p_cb->peer_enc_size < p_cb->loc_enc_size)
+ p_cb->loc_enc_size = p_cb->peer_enc_size;
+
+ if (p_cb->role == HCI_ROLE_SLAVE)
+ smp_sm_event(p_cb, SMP_RAND_EVT, NULL);
+ else
+ {
+ /* master device always use received i/r key as keys to distribute */
+ p_cb->loc_i_key = p_cb->peer_i_key;
+ p_cb->loc_r_key = p_cb->peer_r_key;
+
+ smp_sm_event(p_cb, SMP_ENC_REQ_EVT, NULL);
+ }
+
+ }
+ else
+ {
+ reason = p_cb->failure = SMP_CONFIRM_VALUE_ERR;
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ }
+}
+/*******************************************************************************
+** Function smp_proc_sl_key
+** Description process key ready events.
+*******************************************************************************/
+void smp_proc_sl_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UINT8 key_type = p_data->key.key_type;
+
+ SMP_TRACE_DEBUG0 ("smp_proc_sl_keysmp_proc_sl_key ");
+ if (key_type == SMP_KEY_TYPE_TK)
+ {
+ smp_generate_confirm(p_cb, NULL);
+ }
+ else if (key_type == SMP_KEY_TYPE_CFM)
+ {
+ smp_set_state(SMP_ST_WAIT_CONFIRM);
+
+ if (p_cb->flags & SMP_PAIR_FLAGS_CMD_CONFIRM)
+ smp_sm_event(p_cb, SMP_CONFIRM_EVT, NULL);
+
+ }
+}
+/*******************************************************************************
+** Function smp_start_enc
+** Description start encryption
+*******************************************************************************/
+void smp_start_enc(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ BOOLEAN cmd;
+ UINT8 reason = SMP_ENC_FAIL;
+
+ SMP_TRACE_DEBUG0 ("smp_start_enc ");
+ if (p_data != NULL)
+ cmd = btm_ble_start_encrypt(p_cb->pairing_bda, TRUE, p_data->key.p_data);
+ else
+ cmd = btm_ble_start_encrypt(p_cb->pairing_bda, FALSE, NULL);
+
+ if (!cmd)
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+
+}
+
+/*******************************************************************************
+** Function smp_proc_discard
+** Description processing for discard security request
+*******************************************************************************/
+void smp_proc_discard(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG0 ("smp_proc_discard ");
+ smp_cb_cleanup(p_cb);
+}
+/*******************************************************************************
+** Function smp_proc_release_delay
+** Description process the release delay request
+*******************************************************************************/
+void smp_proc_release_delay(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG0 ("smp_proc_release_delay ");
+ btu_stop_timer (&p_cb->rsp_timer_ent);
+ btu_start_timer (&p_cb->rsp_timer_ent, BTU_TTYPE_SMP_PAIRING_CMD,
+ SMP_WAIT_FOR_REL_DELAY_TOUT);
+}
+
+/*******************************************************************************
+** Function smp_proc_release_delay_tout
+** Description processing the release delay timeout
+*******************************************************************************/
+void smp_proc_release_delay_tout(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG0 ("smp_proc_release_delay_tout ");
+ btu_stop_timer (&p_cb->rsp_timer_ent);
+ smp_proc_pairing_cmpl(p_cb);
+}
+
+
+/*******************************************************************************
+** Function smp_enc_cmpl
+** Description encryption success
+*******************************************************************************/
+void smp_enc_cmpl(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UINT8 enc_enable = *(UINT8 *)p_data;
+ UINT8 reason = enc_enable ? SMP_SUCCESS : SMP_ENC_FAIL;
+
+ SMP_TRACE_DEBUG0 ("smp_enc_cmpl ");
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+}
+
+
+/*******************************************************************************
+** Function smp_check_auth_req
+** Description check authentication request
+*******************************************************************************/
+void smp_check_auth_req(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UINT8 enc_enable = *(UINT8 *)p_data;
+ UINT8 reason = enc_enable ? SMP_SUCCESS : SMP_ENC_FAIL;
+
+ SMP_TRACE_DEBUG3 ("smp_check_auth_req enc_enable=%d i_keys=0x%x r_keys=0x%x (i-initiator r-responder)",
+ enc_enable, p_cb->loc_i_key, p_cb->loc_r_key);
+ if (enc_enable == 1)
+ {
+ if (/*((p_cb->peer_auth_req & SMP_AUTH_BOND) ||
+ (p_cb->loc_auth_req & SMP_AUTH_BOND)) &&*/
+ (p_cb->loc_i_key || p_cb->loc_r_key))
+ {
+ smp_sm_event(p_cb, SMP_BOND_REQ_EVT, NULL);
+ }
+ else
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ }
+ else if (enc_enable == 0)
+ {
+ /* if failed for encryption after pairing, send callback */
+ if (p_cb->flags & SMP_PAIR_FLAG_ENC_AFTER_PAIR)
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ /* if enc failed for old security information */
+ /* if master device, clean up and abck to idle; slave device do nothing */
+ else if (p_cb->role == HCI_ROLE_MASTER)
+ {
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ }
+ }
+}
+
+/*******************************************************************************
+** Function smp_key_pick_key
+** Description Pick a key distribution function based on the key mask.
+*******************************************************************************/
+void smp_key_pick_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UINT8 key_to_dist = (p_cb->role == HCI_ROLE_SLAVE) ? p_cb->loc_r_key : p_cb->loc_i_key;
+ UINT8 i = 0;
+
+ SMP_TRACE_DEBUG1 ("smp_key_pick_key key_to_dist=0x%x", key_to_dist);
+ while (i < 3)
+ {
+ SMP_TRACE_DEBUG2("key to send = %02x, i = %d", key_to_dist, i);
+
+ if (key_to_dist & (1 << i))
+ {
+ SMP_TRACE_DEBUG1 ("smp_distribute_act[%d]", i);
+ (* smp_distribute_act[i])(p_cb, p_data);
+ break;
+ }
+ i ++;
+ }
+}
+/*******************************************************************************
+** Function smp_key_distribution
+** Description start key distribution if required.
+*******************************************************************************/
+void smp_key_distribution(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UINT8 reason = SMP_SUCCESS;
+ SMP_TRACE_DEBUG3 ("smp_key_distribution role=%d (0-master) r_keys=0x%x i_keys=0x%x",
+ p_cb->role, p_cb->loc_r_key, p_cb->loc_i_key);
+
+ if (p_cb->role == HCI_ROLE_SLAVE||
+ (!p_cb->loc_r_key && p_cb->role == HCI_ROLE_MASTER))
+ {
+ smp_key_pick_key(p_cb, p_data);
+ }
+
+ if (!p_cb->loc_i_key && !p_cb->loc_r_key)
+ {
+ /* state check to prevent re-entrant */
+ if (smp_get_state() == SMP_ST_BOND_PENDING)
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ }
+}
+/*******************************************************************************
+** Function smp_decide_asso_model
+** Description This function is called to compare both sides' io capability
+** oob data flag and authentication request, and decide the
+** association model to use for the authentication.
+*******************************************************************************/
+void smp_decide_asso_model(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UINT8 failure = SMP_UNKNOWN_IO_CAP;
+ tSMP_ASSO_MODEL model = SMP_MODEL_MAX;
+ UINT8 int_evt = 0;
+ tSMP_KEY key;
+ tSMP_INT_DATA *p;
+
+ SMP_TRACE_DEBUG3 ("smp_decide_asso_model p_cb->peer_io_caps = %d p_cb->loc_io_caps = %d \
+ p_cb->peer_auth_req = %02x",
+ p_cb->peer_io_caps, p_cb->loc_io_caps, p_cb->peer_auth_req);
+
+ /* OOB data present on both devices, use OOB association model */
+ if (p_cb->peer_oob_flag == SMP_OOB_PRESENT && p_cb->loc_oob_flag == SMP_OOB_PRESENT)
+ {
+ model = SMP_MODEL_OOB;
+ }
+ /* no MITM required, ignore IO cap, use encryption only */
+ else if (SMP_NO_MITM_REQUIRED (p_cb->peer_auth_req) &&
+ SMP_NO_MITM_REQUIRED(p_cb->loc_auth_req))
+ {
+ model = SMP_MODEL_ENC_ONLY;
+ }
+ else/* use IO capability to decide assiciation model */
+ {
+ if (p_cb->peer_io_caps < SMP_IO_CAP_MAX && p_cb->loc_io_caps < SMP_IO_CAP_MAX)
+ {
+ if (p_cb->role == HCI_ROLE_MASTER)
+ model = smp_association_table[p_cb->role][p_cb->peer_io_caps][p_cb->loc_io_caps];
+ else
+ model = smp_association_table[p_cb->role][p_cb->loc_io_caps][p_cb->peer_io_caps];
+ }
+ }
+
+ SMP_TRACE_DEBUG1("Association Model = %d", model);
+
+ if (model == SMP_MODEL_OOB)
+ {
+ SMP_TRACE_ERROR0("Association Model = SMP_MODEL_OOB");
+ p_cb->sec_level = SMP_SEC_AUTHENTICATED;
+ SMP_TRACE_EVENT1 ("p_cb->sec_level =%d (SMP_SEC_AUTHENTICATED) ", p_cb->sec_level );
+ p_cb->cb_evt = SMP_OOB_REQ_EVT;
+
+ int_evt = SMP_TK_REQ_EVT;
+ }
+ else if (model == SMP_MODEL_PASSKEY)
+ {
+ p_cb->sec_level = SMP_SEC_AUTHENTICATED;
+ SMP_TRACE_EVENT1 ("p_cb->sec_level =%d (SMP_SEC_AUTHENTICATED) ", p_cb->sec_level );
+
+ p_cb->cb_evt = SMP_PASSKEY_REQ_EVT;
+ int_evt = SMP_TK_REQ_EVT;
+ }
+ else if (model == SMP_MODEL_KEY_NOTIF)
+ {
+ p_cb->sec_level = SMP_SEC_AUTHENTICATED;
+
+ SMP_TRACE_DEBUG0("Need to generate Passkey");
+ /* generate passkey and notify application */
+ smp_generate_passkey(p_cb, NULL);
+ }
+ else if (model == SMP_MODEL_ENC_ONLY) /* TK = 0, go calculate Confirm */
+ {
+ if (p_cb->role == HCI_ROLE_MASTER &&
+ ((p_cb->peer_auth_req & SMP_AUTH_YN_BIT) != 0) &&
+ ((p_cb->loc_auth_req & SMP_AUTH_YN_BIT) == 0))
+ {
+ SMP_TRACE_ERROR0("IO capability does not meet authentication requirement");
+ failure = SMP_PAIR_AUTH_FAIL;
+ p = (tSMP_INT_DATA *)&failure;
+ int_evt = SMP_AUTH_CMPL_EVT;
+ }
+ else
+ {
+ p_cb->sec_level = SMP_SEC_UNAUTHENTICATE;
+ SMP_TRACE_EVENT1 ("p_cb->sec_level =%d (SMP_SEC_UNAUTHENTICATE) ", p_cb->sec_level );
+
+ key.key_type = SMP_KEY_TYPE_TK;
+ key.p_data = p_cb->tk;
+ p = (tSMP_INT_DATA *)&key;
+
+ memset(p_cb->tk, 0, BT_OCTET16_LEN);
+ /* TK, ready */
+ int_evt = SMP_KEY_READY_EVT;
+ }
+ }
+ else if (model == SMP_MODEL_MAX)
+ {
+ SMP_TRACE_ERROR0("Association Model = SMP_MODEL_MAX (failed)");
+ p = (tSMP_INT_DATA *)&failure;
+ int_evt = SMP_AUTH_CMPL_EVT;
+ }
+
+ SMP_TRACE_EVENT1 ("sec_level=%d ", p_cb->sec_level );
+ if (int_evt)
+ smp_sm_event(p_cb, int_evt, p);
+}
+
+/*******************************************************************************
+** Function smp_proc_io_rsp
+** Description process IO response for a slave device.
+*******************************************************************************/
+void smp_proc_io_rsp(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG0 ("smp_proc_io_rsp ");
+ if (p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD)
+ {
+ smp_set_state(SMP_ST_SEC_REQ_PENDING);
+ smp_send_cmd(SMP_OPCODE_SEC_REQ, p_cb);
+ }
+ else /* respond to pairing request */
+ {
+ smp_send_pair_rsp(p_cb, NULL);
+ }
+}
+/*******************************************************************************
+** Function smp_pairing_cmpl
+** Description This function is called to send the pairing complete callback
+** and remove the connection if needed.
+*******************************************************************************/
+void smp_pairing_cmpl(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+
+ SMP_TRACE_DEBUG0 ("smp_pairing_cmpl ");
+
+ if ((p_cb->status == SMP_SUCCESS) ||
+ (p_cb->status <= SMP_REPEATED_ATTEMPTS && p_cb->status != SMP_SUCCESS))
+ {
+ smp_sm_event(p_cb, SMP_RELEASE_DELAY_EVT, p_data);
+ }
+ else
+ {
+ /* this will transition to idle state right away */
+ smp_sm_event(p_cb, SMP_RELEASE_DELAY_TOUT_EVT, p_data);
+ }
+
+}
+/*******************************************************************************
+** Function smp_pair_terminate
+** Description This function is called to send the pairing complete callback
+** and remove the connection if needed.
+*******************************************************************************/
+void smp_pair_terminate(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG0 ("smp_pair_terminate ");
+ p_cb->status = SMP_PAIR_FAIL_UNKNOWN;
+ smp_proc_pairing_cmpl(p_cb);
+}
+/*******************************************************************************
+** Function smp_idle_terminate
+** Description This function calledin idle state to determine to send authentication
+** complete or not.
+*******************************************************************************/
+void smp_idle_terminate(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ if (p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD)
+ {
+ SMP_TRACE_DEBUG0("Pairing terminated at IDLE state.");
+ p_cb->status = SMP_FAIL;
+ smp_proc_pairing_cmpl(p_cb);
+ }
+}
+/*******************************************************************************
+**
+** Function smp_link_encrypted
+**
+** Description This function is called when link is encrypted and notified to
+** slave device. Proceed to to send LTK, DIV and ER to master if
+** bonding the devices.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_link_encrypted(BD_ADDR bda, UINT8 encr_enable)
+{
+ tSMP_CB *p_cb = &smp_cb;
+
+ SMP_TRACE_DEBUG1 ("smp_link_encrypted encr_enable=%d",encr_enable);
+
+ if (memcmp(&smp_cb.pairing_bda[0], bda, BD_ADDR_LEN) == 0)
+ {
+ /* encryption completed with STK, remmeber the key size now, could be overwite
+ * when key exchange happens */
+ if (p_cb->loc_enc_size != 0 && encr_enable)
+ {
+ /* update the link encryption key size if a SMP pairing just performed */
+ btm_ble_update_sec_key_size(bda, p_cb->loc_enc_size);
+ }
+
+ smp_sm_event(&smp_cb, SMP_ENCRYPTED_EVT, &encr_enable);
+ }
+}
+/*******************************************************************************
+**
+** Function smp_proc_ltk_request
+**
+** Description This function is called when LTK request is received from
+** controller.
+**
+** Returns void
+**
+*******************************************************************************/
+BOOLEAN smp_proc_ltk_request(BD_ADDR bda)
+{
+ SMP_TRACE_DEBUG1 ("smp_proc_ltk_request state = %d", smp_cb.state);
+ if ( smp_cb.state == SMP_ST_ENC_PENDING &&
+ !memcmp(bda, smp_cb.pairing_bda, BD_ADDR_LEN))
+ {
+ smp_sm_event(&smp_cb, SMP_ENC_REQ_EVT, NULL);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+#endif
+
diff --git a/stack/smp/smp_api.c b/stack/smp/smp_api.c
new file mode 100644
index 0000000..e0c37e0
--- /dev/null
+++ b/stack/smp/smp_api.c
@@ -0,0 +1,324 @@
+/*****************************************************************************
+**
+** Name: smp_api.c
+**
+** Description: This file contains the implementation of the SMP
+** interface used by applications that can run over an SMP.
+**
+**
+** Copyright (c) 2008-2009, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+#include <string.h>
+
+#include "bt_target.h"
+#if SMP_INCLUDED == TRUE
+ #include "smp_int.h"
+ #include "smp_api.h"
+ #include "l2cdefs.h"
+ #include "l2c_int.h"
+ #include "btm_int.h"
+ #include "hcimsgs.h"
+
+ #include "btu.h"
+
+
+/*******************************************************************************
+**
+** Function SMP_Init
+**
+** Description This function initializes the SMP unit.
+**
+** Returns void
+**
+*******************************************************************************/
+void SMP_Init(void)
+{
+
+ SMP_TRACE_EVENT0 ("SMP_Init");
+ memset(&smp_cb, 0, sizeof(tSMP_CB));
+
+#if defined(SMP_INITIAL_TRACE_LEVEL)
+ smp_cb.trace_level = SMP_INITIAL_TRACE_LEVEL;
+#else
+ smp_cb.trace_level = BT_TRACE_LEVEL_NONE; /* No traces */
+#endif
+
+ smp_l2cap_if_init();
+}
+
+
+/*******************************************************************************
+**
+** Function SMP_SetTraceLevel
+**
+** Description This function sets the trace level for SMP. If called with
+** a value of 0xFF, it simply returns the current trace level.
+**
+** Input Parameters:
+** level: The level to set the GATT tracing to:
+** 0xff-returns the current setting.
+** 0-turns off tracing.
+** >= 1-Errors.
+** >= 2-Warnings.
+** >= 3-APIs.
+** >= 4-Events.
+** >= 5-Debug.
+**
+** Returns The new or current trace level
+**
+*******************************************************************************/
+SMP_API extern UINT8 SMP_SetTraceLevel (UINT8 new_level)
+{
+ if (new_level != 0xFF)
+ smp_cb.trace_level = new_level;
+
+ return(smp_cb.trace_level);
+}
+
+
+/*******************************************************************************
+**
+** Function SMP_Register
+**
+** Description This function register for the SMP services callback.
+**
+** Returns void
+**
+*******************************************************************************/
+BOOLEAN SMP_Register (tSMP_CALLBACK *p_cback)
+{
+ SMP_TRACE_EVENT1 ("SMP_Register state=%d", smp_cb.state);
+
+ if (smp_cb.p_callback != NULL)
+ {
+ SMP_TRACE_ERROR0 ("SMP_Register: duplicate registration, overwrite it");
+ }
+ smp_cb.p_callback = p_cback;
+
+ return(TRUE);
+
+}
+
+/*******************************************************************************
+**
+** Function SMP_Pair
+**
+** Description This function call to perform a SMP pairing with peer device.
+** Device support one SMP pairing at one time.
+**
+** Parameters bd_addr - peer device bd address.
+**
+** Returns None
+**
+*******************************************************************************/
+tSMP_STATUS SMP_Pair (BD_ADDR bd_addr)
+{
+ tSMP_CB *p_cb = &smp_cb;
+ UINT8 status = SMP_PAIR_INTERNAL_ERR;
+
+ BTM_TRACE_EVENT2 ("SMP_Pair state=%d flag=0x%x ", p_cb->state, p_cb->flags);
+ if (p_cb->state != SMP_ST_IDLE || p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD)
+ {
+ /* pending security on going, reject this one */
+ return SMP_BUSY;
+ }
+ else
+ {
+ p_cb->flags = SMP_PAIR_FLAGS_WE_STARTED_DD;
+
+ memcpy (p_cb->pairing_bda, bd_addr, BD_ADDR_LEN);
+
+ if (!L2CA_ConnectFixedChnl (L2CAP_SMP_CID, bd_addr))
+ {
+ SMP_TRACE_ERROR0("SMP_Pair: L2C connect fixed channel failed.");
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status);
+ return status;
+ }
+
+ return SMP_STARTED;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function SMP_PairCancel
+**
+** Description This function call to cancel a SMP pairing with peer device.
+**
+** Parameters bd_addr - peer device bd address.
+**
+** Returns TRUE - Pairining is cancelled
+**
+*******************************************************************************/
+BOOLEAN SMP_PairCancel (BD_ADDR bd_addr)
+{
+ tSMP_CB *p_cb = &smp_cb;
+ UINT8 err_code = SMP_PAIR_FAIL_UNKNOWN;
+ BOOLEAN status = FALSE;
+
+ BTM_TRACE_EVENT2 ("SMP_CancelPair state=%d flag=0x%x ", p_cb->state, p_cb->flags);
+ if ( (p_cb->state != SMP_ST_IDLE) &&
+ (!memcmp (p_cb->pairing_bda, bd_addr, BD_ADDR_LEN)) )
+ {
+ p_cb->is_pair_cancel = TRUE;
+ SMP_TRACE_DEBUG0("Cancel Pairing: set fail reason Unknown");
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &err_code);
+ status = TRUE;
+ }
+
+ return status;
+}
+/*******************************************************************************
+**
+** Function SMP_SecurityGrant
+**
+** Description This function is called to grant security process.
+**
+** Parameters bd_addr - peer device bd address.
+** res - result of the operation SMP_SUCCESS if success.
+** Otherwise, SMP_REPEATED_ATTEMPTS is too many attempts.
+**
+** Returns None
+**
+*******************************************************************************/
+void SMP_SecurityGrant(BD_ADDR bd_addr, UINT8 res)
+{
+ SMP_TRACE_EVENT0 ("SMP_SecurityGrant ");
+ if (smp_cb.state != SMP_ST_WAIT_APP_RSP ||
+ smp_cb.cb_evt != SMP_SEC_REQUEST_EVT ||
+ memcmp (smp_cb.pairing_bda, bd_addr, BD_ADDR_LEN))
+ return;
+
+ smp_sm_event(&smp_cb, SMP_API_SEC_GRANT_EVT, &res);
+}
+
+/*******************************************************************************
+**
+** Function SMP_PasskeyReply
+**
+** Description This function is called after Security Manager submitted
+** passkey request to the application.
+**
+** Parameters: bd_addr - Address of the device for which passkey was requested
+** res - result of the operation SMP_SUCCESS if success
+** passkey - numeric value in the range of
+** BTM_MIN_PASSKEY_VAL(0) - BTM_MAX_PASSKEY_VAL(999999(0xF423F)).
+**
+*******************************************************************************/
+void SMP_PasskeyReply (BD_ADDR bd_addr, UINT8 res, UINT32 passkey)
+{
+ tSMP_CB *p_cb = & smp_cb;
+ UINT8 failure = SMP_PASSKEY_ENTRY_FAIL;
+ tBTM_SEC_DEV_REC *p_dev_rec;
+
+ SMP_TRACE_EVENT2 ("SMP_PasskeyReply: Key: %d Result:%d",
+ passkey, res);
+
+ /* If timeout already expired or has been canceled, ignore the reply */
+ if (p_cb->cb_evt != SMP_PASSKEY_REQ_EVT)
+ {
+ SMP_TRACE_WARNING1 ("SMP_PasskeyReply() - Wrong State: %d", p_cb->state);
+ return;
+ }
+
+ if (memcmp (bd_addr, p_cb->pairing_bda, BD_ADDR_LEN) != 0)
+ {
+ SMP_TRACE_ERROR0 ("SMP_PasskeyReply() - Wrong BD Addr");
+ return;
+ }
+
+ if ((p_dev_rec = btm_find_dev (bd_addr)) == NULL)
+ {
+ SMP_TRACE_ERROR0 ("SMP_PasskeyReply() - no dev CB");
+ return;
+ }
+
+
+ if (passkey > BTM_MAX_PASSKEY_VAL || res != SMP_SUCCESS)
+ {
+ SMP_TRACE_WARNING1 ("SMP_PasskeyReply() - Wrong key len: %d or passkey entry fail", passkey);
+ /* send pairing failure */
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure);
+
+ }
+ else
+ {
+ smp_convert_string_to_tk(p_cb->tk, passkey);
+ }
+
+ return;
+}
+
+/*******************************************************************************
+**
+** Function SMP_OobDataReply
+**
+** Description This function is called to provide the OOB data for
+** SMP in response to SMP_OOB_REQ_EVT
+**
+** Parameters: bd_addr - Address of the peer device
+** res - result of the operation SMP_SUCCESS if success
+** p_data - simple pairing Randomizer C.
+**
+*******************************************************************************/
+void SMP_OobDataReply(BD_ADDR bd_addr, tSMP_STATUS res, UINT8 len, UINT8 *p_data)
+{
+ tSMP_CB *p_cb = & smp_cb;
+ UINT8 failure = SMP_OOB_FAIL;
+ tSMP_KEY key;
+
+ SMP_TRACE_EVENT2 ("SMP_OobDataReply State: %d res:%d",
+ smp_cb.state, res);
+
+ /* If timeout already expired or has been canceled, ignore the reply */
+ if (p_cb->state != SMP_ST_WAIT_APP_RSP || p_cb->cb_evt != SMP_OOB_REQ_EVT)
+ return;
+
+ if (res != SMP_SUCCESS || len == 0 || !p_data)
+ {
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure);
+ }
+ else
+ {
+ if (len > BT_OCTET16_LEN)
+ len = BT_OCTET16_LEN;
+
+ memcpy(p_cb->tk, p_data, len);
+
+ key.key_type = SMP_KEY_TYPE_TK;
+ key.p_data = p_cb->tk;
+
+ smp_sm_event(&smp_cb, SMP_KEY_READY_EVT, &key);
+ }
+}
+
+/*******************************************************************************
+**
+** Function SMP_Encrypt
+**
+** Description This function is called to encrypt the data with the specified
+** key
+**
+** Parameters: key - Pointer to key key[0] conatins the MSB
+** key_len - key length
+** plain_text - Pointer to data to be encrypted
+** plain_text[0] conatins the MSB
+** pt_len - plain text length
+** p_out - output of the encrypted texts
+**
+** Returns Boolean - request is successful
+*******************************************************************************/
+BOOLEAN SMP_Encrypt (UINT8 *key, UINT8 key_len,
+ UINT8 *plain_text, UINT8 pt_len,
+ tSMP_ENC *p_out)
+
+{
+ BOOLEAN status=FALSE;
+ status = smp_encrypt_data(key, key_len, plain_text, pt_len, p_out);
+ return status;
+}
+#endif /* SMP_INCLUDED */
+
+
diff --git a/stack/smp/smp_cmac.c b/stack/smp/smp_cmac.c
new file mode 100644
index 0000000..d72c3b5
--- /dev/null
+++ b/stack/smp/smp_cmac.c
@@ -0,0 +1,376 @@
+/*****************************************************************************
+**
+** Name: smp_cmac.c
+**
+** Description: This file contains the implementation of the AES128 CMAC
+** algorithm.
+**
+**
+** Copyright (c) 2008-2009, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+
+#include "bt_target.h"
+
+#if SMP_INCLUDED == TRUE
+ #include <stdio.h>
+ #include <string.h>
+
+ #include "btm_ble_api.h"
+ #include "smp_int.h"
+ #include "hcimsgs.h"
+
+typedef struct
+{
+ UINT8 *text;
+ UINT16 len;
+ UINT16 round;
+}tCMAC_CB;
+
+tCMAC_CB cmac_cb;
+
+/* Rb for AES-128 as block cipher, LSB as [0] */
+BT_OCTET16 const_Rb = {
+ 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+void print128(BT_OCTET16 x, const UINT8 *key_name)
+{
+#if SMP_DEBUG == TRUE
+ UINT8 *p = (UINT8 *)x;
+ UINT8 i;
+
+ SMP_TRACE_WARNING1("%s(MSB ~ LSB) = ", key_name);
+
+ for (i = 0; i < 4; i ++)
+ {
+ SMP_TRACE_WARNING4("%02x %02x %02x %02x",
+ p[BT_OCTET16_LEN - i*4 -1], p[BT_OCTET16_LEN - i*4 -2],
+ p[BT_OCTET16_LEN - i*4 -3], p[BT_OCTET16_LEN - i*4 -4]);
+ }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function padding
+**
+** Description utility function to padding the given text to be a 128 bits
+** data. The parameter dest is input and output parameter, it
+** must point to a BT_OCTET16_LEN memory space; where include
+** length bytes valid data.
+**
+** Returns void
+**
+*******************************************************************************/
+static void padding ( BT_OCTET16 dest, UINT8 length )
+{
+ UINT8 i, *p = dest;
+ /* original last block */
+ for ( i = length ; i < BT_OCTET16_LEN; i++ )
+ p[BT_OCTET16_LEN - i - 1] = ( i == length ) ? 0x80 : 0;
+}
+/*******************************************************************************
+**
+** Function leftshift_onebit
+**
+** Description utility function to left shift one bit for a 128 bits value.
+**
+** Returns void
+**
+*******************************************************************************/
+static void leftshift_onebit(UINT8 *input, UINT8 *output)
+{
+ UINT8 i, overflow = 0 , next_overflow = 0;
+ SMP_TRACE_EVENT0 ("leftshift_onebit ");
+ /* input[0] is LSB */
+ for ( i = 0; i < BT_OCTET16_LEN ; i ++ )
+ {
+ next_overflow = (input[i] & 0x80) ? 1:0;
+ output[i] = (input[i] << 1) | overflow;
+ overflow = next_overflow;
+ }
+ return;
+}
+/*******************************************************************************
+**
+** Function cmac_aes_cleanup
+**
+** Description clean up function for AES_CMAC algorithm.
+**
+** Returns void
+**
+*******************************************************************************/
+static void cmac_aes_cleanup(void)
+{
+ if (cmac_cb.text != NULL)
+ {
+ GKI_freebuf(cmac_cb.text);
+ }
+ memset(&cmac_cb, 0, sizeof(tCMAC_CB));
+}
+
+/*******************************************************************************
+**
+** Function cmac_aes_k_calculate
+**
+** Description This function is the calculation of block cipher using AES-128.
+**
+** Returns void
+**
+*******************************************************************************/
+static BOOLEAN cmac_aes_k_calculate(BT_OCTET16 key, UINT8 *p_signature, UINT16 tlen)
+{
+ tSMP_ENC output;
+ UINT8 i = 1, err = 0;
+ UINT8 x[16] = {0};
+ UINT8 *p_mac;
+
+ SMP_TRACE_EVENT0 ("cmac_aes_k_calculate ");
+
+ while (i <= cmac_cb.round)
+ {
+ smp_xor_128(&cmac_cb.text[(cmac_cb.round - i)*BT_OCTET16_LEN], x); /* Mi' := Mi (+) X */
+
+ if (!SMP_Encrypt(key, BT_OCTET16_LEN, &cmac_cb.text[(cmac_cb.round - i)*BT_OCTET16_LEN], BT_OCTET16_LEN, &output))
+ {
+ err = 1;
+ break;
+ }
+
+ memcpy(x, output.param_buf, BT_OCTET16_LEN);
+ i ++;
+ }
+
+ if (!err)
+ {
+ p_mac = output.param_buf + (BT_OCTET16_LEN - tlen);
+ memcpy(p_signature, p_mac, tlen);
+
+ SMP_TRACE_DEBUG2("tlen = %d p_mac = %d", tlen, p_mac);
+ SMP_TRACE_DEBUG4("p_mac[0] = 0x%02x p_mac[1] = 0x%02x p_mac[2] = 0x%02x p_mac[3] = 0x%02x",
+ *p_mac, *(p_mac + 1), *(p_mac + 2), *(p_mac + 3));
+ SMP_TRACE_DEBUG4("p_mac[4] = 0x%02x p_mac[5] = 0x%02x p_mac[6] = 0x%02x p_mac[7] = 0x%02x",
+ *(p_mac + 4), *(p_mac + 5), *(p_mac + 6), *(p_mac + 7));
+
+ return TRUE;
+
+ }
+ else
+ return FALSE;
+}
+/*******************************************************************************
+**
+** Function cmac_prepare_last_block
+**
+** Description This function proceeed to prepare the last block of message
+** Mn depending on the size of the message.
+**
+** Returns void
+**
+*******************************************************************************/
+static void cmac_prepare_last_block (BT_OCTET16 k1, BT_OCTET16 k2)
+{
+// UINT8 x[16] = {0};
+ BOOLEAN flag;
+
+ SMP_TRACE_EVENT0 ("cmac_prepare_last_block ");
+ /* last block is a complete block set flag to 1 */
+ flag = ((cmac_cb.len % BT_OCTET16_LEN) == 0 && cmac_cb.len != 0) ? TRUE : FALSE;
+
+ SMP_TRACE_WARNING2("flag = %d round = %d", flag, cmac_cb.round);
+
+ if ( flag )
+ { /* last block is complete block */
+ smp_xor_128(&cmac_cb.text[0], k1);
+ }
+ else /* padding then xor with k2 */
+ {
+ padding(&cmac_cb.text[0], (UINT8)(cmac_cb.len % 16));
+
+ smp_xor_128(&cmac_cb.text[0], k2);
+ }
+}
+/*******************************************************************************
+**
+** Function cmac_subkey_cont
+**
+** Description This is the callback function when CIPHk(0[128]) is completed.
+**
+** Returns void
+**
+*******************************************************************************/
+static void cmac_subkey_cont(tSMP_ENC *p)
+{
+ UINT8 k1[BT_OCTET16_LEN], k2[BT_OCTET16_LEN];
+ UINT8 *pp = p->param_buf;
+ SMP_TRACE_EVENT0 ("cmac_subkey_cont ");
+ print128(pp, (const UINT8 *)"K1 before shift");
+
+ /* If MSB(L) = 0, then K1 = L << 1 */
+ if ( (pp[BT_OCTET16_LEN - 1] & 0x80) != 0 )
+ {
+ /* Else K1 = ( L << 1 ) (+) Rb */
+ leftshift_onebit(pp, k1);
+ smp_xor_128(k1, const_Rb);
+ }
+ else
+ {
+ leftshift_onebit(pp, k1);
+ }
+
+ if ( (k1[BT_OCTET16_LEN - 1] & 0x80) != 0 )
+ {
+ /* K2 = (K1 << 1) (+) Rb */
+ leftshift_onebit(k1, k2);
+ smp_xor_128(k2, const_Rb);
+ }
+ else
+ {
+ /* If MSB(K1) = 0, then K2 = K1 << 1 */
+ leftshift_onebit(k1, k2);
+ }
+
+ print128(k1, (const UINT8 *)"K1");
+ print128(k2, (const UINT8 *)"K2");
+
+ cmac_prepare_last_block (k1, k2);
+}
+/*******************************************************************************
+**
+** Function cmac_generate_subkey
+**
+** Description This is the function to generate the two subkeys.
+**
+** Parameters key - CMAC key, expect SRK when used by SMP.
+**
+** Returns void
+**
+*******************************************************************************/
+static BOOLEAN cmac_generate_subkey(BT_OCTET16 key)
+{
+ BT_OCTET16 z = {0};
+ BOOLEAN ret = TRUE;
+ tSMP_ENC output;
+ SMP_TRACE_EVENT0 (" cmac_generate_subkey");
+
+ if (SMP_Encrypt(key, BT_OCTET16_LEN, z, BT_OCTET16_LEN, &output))
+ {
+ cmac_subkey_cont(&output);;
+ }
+ else
+ ret = FALSE;
+
+ return ret;
+}
+/*******************************************************************************
+**
+** Function AES_CMAC
+**
+** Description This is the AES-CMAC Generation Function with tlen implemented.
+**
+** Parameters key - CMAC key in little endian order, expect SRK when used by SMP.
+** input - text to be signed in little endian byte order.
+** length - length of the input in byte.
+** tlen - lenth of mac desired
+** p_signature - data pointer to where signed data to be stored, tlen long.
+**
+** Returns void
+**
+*******************************************************************************/
+BOOLEAN AES_CMAC ( BT_OCTET16 key, UINT8 *input, UINT16 length,
+ UINT16 tlen, UINT8 *p_signature)
+{
+ UINT16 len, diff;
+ UINT16 n = (length + BT_OCTET16_LEN - 1) / BT_OCTET16_LEN; /* n is number of rounds */
+ BOOLEAN ret = FALSE;
+
+ SMP_TRACE_EVENT0 ("AES_CMAC ");
+
+ if (n == 0) n = 1;
+ len = n * BT_OCTET16_LEN;
+
+ SMP_TRACE_WARNING1("AES128_CMAC started, allocate buffer size = %d", len);
+ /* allocate a memory space of multiple of 16 bytes to hold text */
+ if ((cmac_cb.text = (UINT8 *)GKI_getbuf(len)) != NULL)
+ {
+ cmac_cb.round = n;
+
+ memset(cmac_cb.text, 0, len);
+ diff = len - length;
+
+ if (input != NULL && length > 0)
+ {
+ memcpy(&cmac_cb.text[diff] , input, (int)length);
+ cmac_cb.len = length;
+ }
+ else
+ cmac_cb.len = 0;
+
+ /* prepare calculation for subkey s and last block of data */
+ if (cmac_generate_subkey(key))
+ {
+ /* start calculation */
+ ret = cmac_aes_k_calculate(key, p_signature, tlen);
+ }
+ /* clean up */
+ cmac_aes_cleanup();
+ }
+ else
+ {
+ ret = FALSE;
+ SMP_TRACE_ERROR0("No resources");
+ }
+
+ return ret;
+}
+
+ #if 0 /* testing code, sample data from spec */
+void test_cmac_cback(UINT8 *p_mac, UINT16 tlen)
+{
+ SMP_TRACE_EVENT0 ("test_cmac_cback ");
+ SMP_TRACE_ERROR0("test_cmac_cback");
+}
+
+void test_cmac(void)
+{
+ SMP_TRACE_EVENT0 ("test_cmac ");
+ UINT8 M[64] = {
+ 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+ 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+ 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+ 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+ 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+ 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+ 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
+ 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10
+ };
+
+ UINT8 key[16] = {
+ 0x3c, 0x4f, 0xcf, 0x09, 0x88, 0x15, 0xf7, 0xab,
+ 0xa6, 0xd2, 0xae, 0x28, 0x16, 0x15, 0x7e, 0x2b
+ };
+ UINT8 i =0, tmp;
+ UINT16 len;
+
+ len = 64;
+
+ for (i = 0; i < len/2; i ++)
+ {
+ tmp = M[i];
+ M[i] = M[len -1 - i];
+ M[len -1 - i] = tmp;
+ }
+
+
+ memset(&cmac_cb, 0, sizeof(tCMAC_CB));
+
+ SMP_TRACE_WARNING1("\n Example 1: len = %d\n", len);
+
+ AES_CMAC(key, M, len, 128, test_cmac_cback, 0);
+
+}
+ #endif
+#endif
+
diff --git a/stack/smp/smp_int.h b/stack/smp/smp_int.h
new file mode 100644
index 0000000..4ca9563
--- /dev/null
+++ b/stack/smp/smp_int.h
@@ -0,0 +1,301 @@
+/****************************************************************************/
+/* */
+/* Name: smp_int.h */
+/* */
+/* Function this file contains internally used SMP definitions */
+/* */
+/* Copyright (c) 1999-2008, Broadcom Corp., All Rights Reserved. */
+/* WIDCOMM Bluetooth Core. Proprietary and confidential. */
+/* */
+/*****************************************************************************/
+#ifndef SMP_INT_H
+#define SMP_INT_H
+
+#include "btu.h"
+#include "smp_api.h"
+
+#define SMP_MODEL_ENC_ONLY 0
+#define SMP_MODEL_PASSKEY 1
+#define SMP_MODEL_OOB 2
+#define SMP_MODEL_KEY_NOTIF 3
+#define SMP_MODEL_MAX 4
+typedef UINT8 tSMP_ASSO_MODEL;
+
+
+#ifndef SMP_MAX_CONN
+ #define SMP_MAX_CONN 2
+#endif
+
+#define SMP_WAIT_FOR_RSP_TOUT 30
+#define SMP_WAIT_FOR_REL_DELAY_TOUT 5
+/* SMP L2CAP command code */
+#define SMP_OPCODE_PAIRING_REQ 0x01
+#define SMP_OPCODE_PAIRING_RSP 0x02
+#define SMP_OPCODE_CONFIRM 0x03
+#define SMP_OPCODE_INIT 0x04
+#define SMP_OPCODE_PAIRING_FAILED 0x05
+#define SMP_OPCODE_ENCRYPT_INFO 0x06
+#define SMP_OPCODE_MASTER_ID 0x07
+#define SMP_OPCODE_IDENTITY_INFO 0x08
+#define SMP_OPCODE_ID_ADDR 0x09
+#define SMP_OPCODE_SIGN_INFO 0x0A
+#define SMP_OPCODE_SEC_REQ 0x0B
+#define SMP_OPCODE_MAX (SMP_OPCODE_SEC_REQ + 1)
+
+/* SMP events */
+#define SMP_PAIRING_REQ_EVT SMP_OPCODE_PAIRING_REQ
+#define SMP_PAIRING_RSP_EVT SMP_OPCODE_PAIRING_RSP
+#define SMP_CONFIRM_EVT SMP_OPCODE_CONFIRM
+#define SMP_RAND_EVT SMP_OPCODE_INIT
+#define SMP_PAIRING_FAILED_EVT SMP_OPCODE_PAIRING_FAILED
+#define SMP_ENCRPTION_INFO_EVT SMP_OPCODE_ENCRYPT_INFO
+#define SMP_MASTER_ID_EVT SMP_OPCODE_MASTER_ID
+#define SMP_ID_INFO_EVT SMP_OPCODE_IDENTITY_INFO
+#define SMP_ID_ADDR_EVT SMP_OPCODE_ID_ADDR
+#define SMP_SIGN_INFO_EVT SMP_OPCODE_SIGN_INFO
+#define SMP_SECURITY_REQ_EVT SMP_OPCODE_SEC_REQ
+
+#define SMP_SELF_DEF_EVT SMP_SECURITY_REQ_EVT
+#define SMP_KEY_READY_EVT (SMP_SELF_DEF_EVT + 1)
+#define SMP_ENCRYPTED_EVT (SMP_SELF_DEF_EVT + 2)
+#define SMP_L2CAP_CONN_EVT (SMP_SELF_DEF_EVT + 3)
+#define SMP_L2CAP_DISCONN_EVT (SMP_SELF_DEF_EVT + 4)
+#define SMP_IO_RSP_EVT (SMP_SELF_DEF_EVT + 5)
+#define SMP_API_SEC_GRANT_EVT (SMP_SELF_DEF_EVT + 6)
+#define SMP_TK_REQ_EVT (SMP_SELF_DEF_EVT + 7)
+#define SMP_AUTH_CMPL_EVT (SMP_SELF_DEF_EVT + 8)
+#define SMP_ENC_REQ_EVT (SMP_SELF_DEF_EVT + 9)
+#define SMP_BOND_REQ_EVT (SMP_SELF_DEF_EVT + 10)
+#define SMP_DISCARD_SEC_REQ_EVT (SMP_SELF_DEF_EVT + 11)
+#define SMP_RELEASE_DELAY_EVT (SMP_SELF_DEF_EVT + 12)
+#define SMP_RELEASE_DELAY_TOUT_EVT (SMP_SELF_DEF_EVT + 13)
+typedef UINT8 tSMP_EVENT;
+#define SMP_MAX_EVT SMP_RELEASE_DELAY_TOUT_EVT + 1
+
+/* auumption it's only using the low 8 bits, if bigger than that, need to expand it to be 16 bits */
+#define SMP_SEC_KEY_MASK 0x00ff
+
+/* SMP pairing state */
+enum
+{
+ SMP_ST_IDLE,
+ SMP_ST_WAIT_APP_RSP,
+ SMP_ST_SEC_REQ_PENDING,
+ SMP_ST_PAIR_REQ_RSP,
+ SMP_ST_WAIT_CONFIRM,
+ SMP_ST_CONFIRM,
+ SMP_ST_RAND,
+ SMP_ST_ENC_PENDING,
+ SMP_ST_BOND_PENDING,
+ SMP_ST_RELEASE_DELAY,
+ SMP_ST_MAX
+};
+typedef UINT8 tSMP_STATE;
+
+/* random and encrption activity state */
+enum
+{
+ SMP_GEN_COMPARE = 1,
+ SMP_GEN_CONFIRM,
+
+ SMP_GEN_DIV_LTK,
+ SMP_GEN_DIV_CSRK,
+ SMP_GEN_RAND_V,
+ SMP_GEN_TK,
+ SMP_GEN_SRAND_MRAND,
+ SMP_GEN_SRAND_MRAND_CONT
+};
+
+enum
+{
+ SMP_KEY_TYPE_TK,
+ SMP_KEY_TYPE_CFM,
+ SMP_KEY_TYPE_CMP,
+ SMP_KEY_TYPE_STK,
+ SMP_KEY_TYPE_LTK
+};
+typedef struct
+{
+ UINT8 key_type;
+ UINT8* p_data;
+}tSMP_KEY;
+
+typedef union
+{
+ UINT8 *p_data; /* UINT8 type data pointer */
+ tSMP_KEY key;
+ UINT16 reason;
+}tSMP_INT_DATA;
+
+/* internal status mask */
+#define SMP_PAIR_FLAGS_WE_STARTED_DD (1)
+#define SMP_PAIR_FLAGS_PEER_STARTED_DD (1 << 1)
+#define SMP_PAIR_FLAGS_CMD_CONFIRM (1 << SMP_OPCODE_CONFIRM) /* 1 << 3 */
+#define SMP_PAIR_FLAG_ENC_AFTER_PAIR (1 << 4)
+
+/* check if authentication requirement need MITM protection */
+#define SMP_NO_MITM_REQUIRED(x) (((x) & SMP_AUTH_YN_BIT) == 0)
+
+#define SMP_ENCRYT_KEY_SIZE 16
+#define SMP_ENCRYT_DATA_SIZE 16
+#define SMP_ECNCRPYT_STATUS HCI_SUCCESS
+
+/* SMP control block */
+typedef struct
+{
+ tSMP_CALLBACK *p_callback;
+ TIMER_LIST_ENT rsp_timer_ent;
+ UINT8 trace_level;
+
+ BD_ADDR pairing_bda;
+
+ tSMP_STATE state;
+ UINT8 failure;
+ UINT8 status;
+ UINT8 role;
+ UINT8 flags;
+ UINT8 cb_evt;
+
+ tSMP_SEC_LEVEL sec_level;
+ BOOLEAN connect_initialized;
+ BT_OCTET16 confirm;
+ BT_OCTET16 rconfirm;
+ BT_OCTET16 rrand;
+ BT_OCTET16 rand;
+ tSMP_IO_CAP peer_io_caps;
+ tSMP_IO_CAP loc_io_caps;
+ tSMP_OOB_FLAG peer_oob_flag;
+ tSMP_OOB_FLAG loc_oob_flag;
+ tSMP_AUTH_REQ peer_auth_req;
+ tSMP_AUTH_REQ loc_auth_req;
+ UINT8 peer_enc_size;
+ UINT8 loc_enc_size;
+ UINT8 peer_i_key;
+ UINT8 peer_r_key;
+ UINT8 loc_i_key;
+ UINT8 loc_r_key;
+
+ BT_OCTET16 tk;
+ BT_OCTET16 ltk;
+ UINT16 div;
+ BT_OCTET16 csrk; /* storage for local CSRK */
+ UINT16 ediv;
+ BT_OCTET8 enc_rand;
+
+ UINT8 rand_enc_proc;
+ BOOLEAN last_cmd;
+ BD_ADDR local_bda;
+ BOOLEAN is_pair_cancel;
+ BOOLEAN discard_sec_req;
+#if SMP_CONFORMANCE_TESTING == TRUE
+ BOOLEAN enable_test_confirm_val;
+ BT_OCTET16 test_confirm;
+ BOOLEAN enable_test_rand_val;
+ BT_OCTET16 test_rand;
+ BOOLEAN enable_test_pair_fail;
+ UINT8 pair_fail_status;
+ BOOLEAN remove_fixed_channel_disable;
+#endif
+
+}tSMP_CB;
+
+/* Server Action functions are of this type */
+typedef void (*tSMP_ACT)(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#if SMP_DYNAMIC_MEMORY == FALSE
+ SMP_API extern tSMP_CB smp_cb;
+#else
+ SMP_API extern tSMP_CB *smp_cb_ptr;
+#define smp_cb (*smp_cb_ptr)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+/* Functions provided by att_main.c */
+SMP_API extern void smp_init (void);
+
+#if SMP_CONFORMANCE_TESTING == TRUE
+/* Used only for conformance testing */
+SMP_API extern void smp_set_test_confirm_value (BOOLEAN enable, UINT8 *p_c_value);
+SMP_API extern void smp_set_test_rand_value (BOOLEAN enable, UINT8 *p_c_value);
+SMP_API extern void smp_set_test_pair_fail_status (BOOLEAN enable, UINT8 status);
+SMP_API extern void smp_remove_fixed_channel_disable (BOOLEAN disable);
+#endif
+/* smp main */
+extern void smp_sm_event(tSMP_CB *p_cb, tSMP_EVENT event, void *p_data);
+
+extern void smp_proc_sec_request(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_send_pair_req(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_send_confirm(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_send_pair_fail(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_send_init(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_proc_sec_request(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_proc_pair_fail(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_proc_confirm(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_proc_init(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_proc_enc_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_proc_master_id(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_proc_id_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_proc_id_addr(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_proc_sec_grant(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_proc_sec_req(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_proc_sl_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_start_enc(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_enc_cmpl(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_proc_discard(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_proc_release_delay(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_proc_release_delay_tout(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_pairing_cmpl(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_decide_asso_model(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_send_app_cback(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_proc_compare(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_check_auth_req(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_proc_io_rsp(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_send_id_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_send_enc_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_send_csrk_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_send_ltk_reply(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_proc_pair_cmd(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_pair_terminate(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_idle_terminate(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_send_pair_rsp(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_key_distribution(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_proc_srk_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_generate_csrk(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+/* smp_l2c */
+extern void smp_l2cap_if_init (void);
+
+/* smp utility */
+extern BOOLEAN smp_send_cmd(UINT8 cmd_code, tSMP_CB *p_cb);
+extern void smp_cb_cleanup(tSMP_CB *p_cb);
+extern void smp_reset_control_value(tSMP_CB *p_cb);
+extern void smp_proc_pairing_cmpl(tSMP_CB *p_cb);
+extern void smp_convert_string_to_tk(BT_OCTET16 tk, UINT32 passkey);
+extern void smp_mask_enc_key(UINT8 loc_enc_size, UINT8 * p_data);
+extern void smp_rsp_timeout(TIMER_LIST_ENT *p_tle);
+extern void smp_xor_128(BT_OCTET16 a, BT_OCTET16 b);
+extern BOOLEAN smp_encrypt_data (UINT8 *key, UINT8 key_len,
+ UINT8 *plain_text, UINT8 pt_len,
+ tSMP_ENC *p_out);
+/* smp key */
+extern void smp_generate_confirm (tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_generate_compare (tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_generate_stk (tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_generate_ltk(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_generate_passkey (tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_genenrate_rand_cont(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+
+/* smp main util */
+extern void smp_set_state(tSMP_STATE state);
+extern tSMP_STATE smp_get_state(void);
+
+#endif /* SMP_INT_H */
+
diff --git a/stack/smp/smp_keys.c b/stack/smp/smp_keys.c
new file mode 100644
index 0000000..a7c8496
--- /dev/null
+++ b/stack/smp/smp_keys.c
@@ -0,0 +1,896 @@
+/*****************************************************************************
+**
+** Name: smp_keys.c
+**
+** Description: This file contains the implementation of the SMP
+** utility functions used by SMP.
+**
+**
+** Copyright (c) 2008-2010, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+
+#include "bt_target.h"
+
+#if SMP_INCLUDED == TRUE
+ #if SMP_DEBUG == TRUE
+ #include <stdio.h>
+ #endif
+ #include <string.h>
+
+ #include "btm_ble_api.h"
+ #include "smp_int.h"
+ #include "btm_int.h"
+ #include "btm_ble_int.h"
+ #include "hcimsgs.h"
+ #include "aes.h"
+ #ifndef SMP_MAX_ENC_REPEAT
+ #define SMP_MAX_ENC_REPEAT 3
+ #endif
+
+static void smp_rand_back(tBTM_RAND_ENC *p);
+static void smp_genenrate_confirm(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+static void smp_genenrate_ltk_cont(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+static void smp_generate_y(tSMP_CB *p_cb, tSMP_INT_DATA *p);
+static void smp_generate_rand_vector (tSMP_CB *p_cb, tSMP_INT_DATA *p);
+static void smp_process_stk(tSMP_CB *p_cb, tSMP_ENC *p);
+static void smp_calculate_comfirm_cont(tSMP_CB *p_cb, tSMP_ENC *p);
+static void smp_process_confirm(tSMP_CB *p_cb, tSMP_ENC *p);
+static void smp_process_compare(tSMP_CB *p_cb, tSMP_ENC *p);
+static void smp_process_ediv(tSMP_CB *p_cb, tSMP_ENC *p);
+
+static const tSMP_ACT smp_encrypt_action[] =
+{
+ smp_generate_compare, /* SMP_GEN_COMPARE */
+ smp_genenrate_confirm, /* SMP_GEN_CONFIRM*/
+ smp_generate_stk, /* SMP_GEN_STK*/
+ smp_genenrate_ltk_cont, /* SMP_GEN_LTK */
+ smp_generate_ltk, /* SMP_GEN_DIV_LTK */
+ smp_generate_rand_vector, /* SMP_GEN_RAND_V */
+ smp_generate_y, /* SMP_GEN_EDIV */
+ smp_generate_passkey, /* SMP_GEN_TK */
+ smp_generate_confirm, /* SMP_GEN_SRAND_MRAND */
+ smp_genenrate_rand_cont /* SMP_GEN_SRAND_MRAND_CONT */
+};
+
+
+ #define SMP_PASSKEY_MASK 0xfff00000
+
+ #if SMP_DEBUG == TRUE
+static void smp_debug_print_nbyte_little_endian (UINT8 *p, const UINT8 *key_name, UINT8 len)
+{
+ int i, x = 0;
+ UINT8 p_buf[100];
+ memset(p_buf, 0, 100);
+
+ for (i = 0; i < len; i ++)
+ {
+ x += sprintf ((char *)&p_buf[x], "%02x ", p[i]);
+ }
+ SMP_TRACE_WARNING2("%s(LSB ~ MSB) = %s", key_name, p_buf);
+}
+ #else
+ #define smp_debug_print_nbyte_little_endian(p, key_name, len)
+ #endif
+
+/*******************************************************************************
+**
+** Function smp_encrypt_data
+**
+** Description This function is called to generate passkey.
+**
+** Returns void
+**
+*******************************************************************************/
+BOOLEAN smp_encrypt_data (UINT8 *key, UINT8 key_len,
+ UINT8 *plain_text, UINT8 pt_len,
+ tSMP_ENC *p_out)
+{
+ aes_context ctx;
+ UINT8 *p_start = NULL;
+ UINT8 *p = NULL;
+ UINT8 *p_rev_data = NULL; /* input data in big endilan format */
+ UINT8 *p_rev_key = NULL; /* input key in big endilan format */
+ UINT8 *p_rev_output = NULL; /* encrypted output in big endilan format */
+
+ SMP_TRACE_DEBUG0 ("smp_encrypt_data");
+ if ( (p_out == NULL ) || (key_len != SMP_ENCRYT_KEY_SIZE) )
+ {
+ BTM_TRACE_ERROR0 ("smp_encrypt_data Failed");
+ return(FALSE);
+ }
+
+ if ((p_start = (UINT8 *)GKI_getbuf((SMP_ENCRYT_DATA_SIZE*4))) == NULL)
+ {
+ BTM_TRACE_ERROR0 ("smp_encrypt_data Failed unable to allocate buffer");
+ return(FALSE);
+ }
+
+ if (pt_len > SMP_ENCRYT_DATA_SIZE)
+ pt_len = SMP_ENCRYT_DATA_SIZE;
+
+ memset(p_start, 0, SMP_ENCRYT_DATA_SIZE * 4);
+ p = p_start;
+ ARRAY_TO_STREAM (p, plain_text, pt_len); /* byte 0 to byte 15 */
+ p_rev_data = p = p_start + SMP_ENCRYT_DATA_SIZE; /* start at byte 16 */
+ REVERSE_ARRAY_TO_STREAM (p, p_start, SMP_ENCRYT_DATA_SIZE); /* byte 16 to byte 31 */
+ p_rev_key = p; /* start at byte 32 */
+ REVERSE_ARRAY_TO_STREAM (p, key, SMP_ENCRYT_KEY_SIZE); /* byte 32 to byte 47 */
+
+ smp_debug_print_nbyte_little_endian(key, (const UINT8 *)"Key", SMP_ENCRYT_KEY_SIZE);
+ smp_debug_print_nbyte_little_endian(p_start, (const UINT8 *)"Plain text", SMP_ENCRYT_DATA_SIZE);
+ p_rev_output = p;
+ aes_set_key(p_rev_key, SMP_ENCRYT_KEY_SIZE, &ctx);
+ aes_encrypt(p_rev_data, p, &ctx); /* outputs in byte 48 to byte 63 */
+
+ p = p_out->param_buf;
+ REVERSE_ARRAY_TO_STREAM (p, p_rev_output, SMP_ENCRYT_DATA_SIZE);
+ smp_debug_print_nbyte_little_endian(p_out->param_buf, (const UINT8 *)"Encrypted text", SMP_ENCRYT_KEY_SIZE);
+
+ p_out->param_len = SMP_ENCRYT_KEY_SIZE;
+ p_out->status = HCI_SUCCESS;
+ p_out->opcode = HCI_BLE_ENCRYPT;
+
+ GKI_freebuf(p_start);
+
+ return(TRUE);
+}
+
+
+/*******************************************************************************
+**
+** Function smp_generate_passkey
+**
+** Description This function is called to generate passkey.
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_generate_passkey(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG0 ("smp_generate_passkey");
+ p_cb->rand_enc_proc = SMP_GEN_TK;
+
+ /* generate MRand or SRand */
+ if (!btsnd_hcic_ble_rand((void *)smp_rand_back))
+ smp_rand_back(NULL);
+}
+/*******************************************************************************
+**
+** Function smp_proc_passkey
+**
+** Description This function is called to process a passkey.
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_proc_passkey(tSMP_CB *p_cb , tBTM_RAND_ENC *p)
+{
+ UINT8 *tt = p_cb->tk;
+ tSMP_KEY key;
+ UINT32 passkey; //= 19655 test number; */
+ UINT8 *pp = p->param_buf;
+
+ SMP_TRACE_DEBUG0 ("smp_proc_passkey ");
+ STREAM_TO_UINT32(passkey, pp);
+ passkey &= ~SMP_PASSKEY_MASK;
+
+ /* truncate by maximum value */
+ while (passkey > BTM_MAX_PASSKEY_VAL)
+ passkey >>= 1;
+ SMP_TRACE_ERROR1("Passkey generated = %d", passkey);
+
+ /* save the TK */
+ memset(p_cb->tk, 0, BT_OCTET16_LEN);
+ UINT32_TO_STREAM(tt, passkey);
+
+ key.key_type = SMP_KEY_TYPE_TK;
+ key.p_data = p_cb->tk;
+
+ if (p_cb->p_callback)
+ {
+ (*p_cb->p_callback)(SMP_PASSKEY_NOTIF_EVT, p_cb->pairing_bda, (tSMP_EVT_DATA *)&passkey);
+ }
+
+ smp_sm_event(p_cb, SMP_KEY_READY_EVT, (tSMP_INT_DATA *)&key);
+}
+
+
+/*******************************************************************************
+**
+** Function smp_generate_stk
+**
+** Description This function is called to generate STK calculated by running
+** AES with the TK value as key and a concatenation of the random
+** values.
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_generate_stk (tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ BT_OCTET16 ptext;
+ UINT8 *p = ptext;
+ tSMP_ENC output;
+ tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN;
+
+ SMP_TRACE_DEBUG0 ("smp_generate_stk ");
+
+ memset(p, 0, BT_OCTET16_LEN);
+ if (p_cb->role == HCI_ROLE_MASTER)
+ {
+ memcpy(p, p_cb->rand, BT_OCTET8_LEN);
+ memcpy(&p[BT_OCTET8_LEN], p_cb->rrand, BT_OCTET8_LEN);
+ }
+ else
+ {
+ memcpy(p, p_cb->rrand, BT_OCTET8_LEN);
+ memcpy(&p[BT_OCTET8_LEN], p_cb->rand, BT_OCTET8_LEN);
+ }
+
+ /* generate STK = Etk(rand|rrand)*/
+ if (!SMP_Encrypt( p_cb->tk, BT_OCTET16_LEN, ptext, BT_OCTET16_LEN, &output))
+ {
+ SMP_TRACE_ERROR0("smp_generate_stk failed");
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status);
+ }
+ else
+ {
+ smp_process_stk(p_cb, &output);
+ }
+
+}
+/*******************************************************************************
+**
+** Function smp_generate_confirm
+**
+** Description This function is called to start the second pairing phase by
+** start generating initializer random number.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_generate_confirm (tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG0 ("smp_generate_confirm");
+ p_cb->rand_enc_proc = SMP_GEN_SRAND_MRAND;
+ /* generate MRand or SRand */
+ if (!btsnd_hcic_ble_rand((void *)smp_rand_back))
+ smp_rand_back(NULL);
+}
+/*******************************************************************************
+**
+** Function smp_genenrate_rand_cont
+**
+** Description This function is called to generate another 64 bits random for
+** MRand or Srand.
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_genenrate_rand_cont(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG0 ("smp_genenrate_rand_cont ");
+ p_cb->rand_enc_proc = SMP_GEN_SRAND_MRAND_CONT;
+ /* generate 64 MSB of MRand or SRand */
+
+ if (!btsnd_hcic_ble_rand((void *)smp_rand_back))
+ smp_rand_back(NULL);
+}
+/*******************************************************************************
+**
+** Function smp_generate_ltk
+**
+** Description This function is called to calculate LTK, starting with DIV
+** generation.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_generate_ltk(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ BOOLEAN div_status;
+
+ SMP_TRACE_DEBUG0 ("smp_generate_ltk ");
+
+ div_status = btm_get_local_div(p_cb->pairing_bda, &p_cb->div);
+
+ if (div_status)
+ {
+ smp_genenrate_ltk_cont(p_cb, NULL);
+ }
+ else
+ {
+ SMP_TRACE_DEBUG0 ("Generate DIV for LTK");
+ p_cb->rand_enc_proc = SMP_GEN_DIV_LTK;
+ /* generate MRand or SRand */
+ if (!btsnd_hcic_ble_rand((void *)smp_rand_back))
+ smp_rand_back(NULL);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function smp_compute_csrk
+**
+** Description This function is called to calculate CSRK
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_compute_csrk(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ BT_OCTET16 er;
+ UINT8 buffer[4]; /* for (r || DIV) r=1*/
+ UINT16 r=1;
+ UINT8 *p=buffer;
+ tSMP_ENC output;
+ tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN;
+
+ SMP_TRACE_DEBUG1 ("smp_compute_csrk div=%x", p_cb->div);
+ BTM_GetDeviceEncRoot(er);
+ /* CSRK = d1(ER, DIV, 1) */
+ UINT16_TO_STREAM(p, p_cb->div);
+ UINT16_TO_STREAM(p, r);
+
+ if (!SMP_Encrypt(er, BT_OCTET16_LEN, buffer, 4, &output))
+ {
+ SMP_TRACE_ERROR0("smp_generate_csrk failed");
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status);
+ }
+ else
+ {
+ memcpy((void *)p_cb->csrk, output.param_buf, BT_OCTET16_LEN);
+ smp_send_csrk_info(p_cb, NULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function smp_generate_csrk
+**
+** Description This function is called to calculate LTK, starting with DIV
+** generation.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_generate_csrk(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ BOOLEAN div_status;
+
+ SMP_TRACE_DEBUG0 ("smp_generate_csrk");
+
+ div_status = btm_get_local_div(p_cb->pairing_bda, &p_cb->div);
+ if (div_status)
+ {
+ smp_compute_csrk(p_cb, NULL);
+ }
+ else
+ {
+ SMP_TRACE_DEBUG0 ("Generate DIV for CSRK");
+ p_cb->rand_enc_proc = SMP_GEN_DIV_CSRK;
+ if (!btsnd_hcic_ble_rand((void *)smp_rand_back))
+ smp_rand_back(NULL);
+ }
+}
+
+
+/*******************************************************************************
+** Function smp_concatenate_peer
+** add pairing command sent from local device into p1.
+*******************************************************************************/
+void smp_concatenate_local( tSMP_CB *p_cb, UINT8 **p_data, UINT8 op_code)
+{
+ UINT8 *p = *p_data;
+
+ SMP_TRACE_DEBUG0 ("smp_concatenate_local ");
+ UINT8_TO_STREAM(p, op_code);
+ UINT8_TO_STREAM(p, p_cb->loc_io_caps);
+ UINT8_TO_STREAM(p, p_cb->loc_oob_flag);
+ UINT8_TO_STREAM(p, p_cb->loc_auth_req);
+ UINT8_TO_STREAM(p, p_cb->loc_enc_size);
+ UINT8_TO_STREAM(p, p_cb->loc_i_key);
+ UINT8_TO_STREAM(p, p_cb->loc_r_key);
+
+ *p_data = p;
+}
+/*******************************************************************************
+** Function smp_concatenate_peer
+** add pairing command received from peer device into p1.
+*******************************************************************************/
+void smp_concatenate_peer( tSMP_CB *p_cb, UINT8 **p_data, UINT8 op_code)
+{
+ UINT8 *p = *p_data;
+
+ SMP_TRACE_DEBUG0 ("smp_concatenate_peer ");
+ UINT8_TO_STREAM(p, op_code);
+ UINT8_TO_STREAM(p, p_cb->peer_io_caps);
+ UINT8_TO_STREAM(p, p_cb->peer_oob_flag);
+ UINT8_TO_STREAM(p, p_cb->peer_auth_req);
+ UINT8_TO_STREAM(p, p_cb->peer_enc_size);
+ UINT8_TO_STREAM(p, p_cb->peer_i_key);
+ UINT8_TO_STREAM(p, p_cb->peer_r_key);
+
+ *p_data = p;
+}
+/*******************************************************************************
+**
+** Function smp_gen_p1_4_confirm
+**
+** Description Generate Confirm/Compare Step1:
+** p1 = pres || preq || rat' || iat'
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_gen_p1_4_confirm( tSMP_CB *p_cb, BT_OCTET16 p1)
+{
+ UINT8 *p = (UINT8 *)p1;
+ tBTM_SEC_DEV_REC *p_dev_rec;
+
+ SMP_TRACE_DEBUG0 ("smp_gen_p1_4_confirm");
+ if ((p_dev_rec = btm_find_dev (p_cb->pairing_bda)) == NULL)
+ {
+ SMP_TRACE_ERROR0("can not generate confirm for unknown device");
+ return;
+ }
+
+ BTM_ReadConnectionAddr(p_cb->local_bda);
+
+ if (p_cb->role == HCI_ROLE_MASTER)
+ {
+ /* LSB : rat': initiator's(local) address type */
+ UINT8_TO_STREAM(p, 0);
+ /* LSB : iat': responder's address type */
+ UINT8_TO_STREAM(p, p_dev_rec->ble.ble_addr_type);
+ /* concatinate preq */
+ smp_concatenate_local(p_cb, &p, SMP_OPCODE_PAIRING_REQ);
+ /* concatinate pres */
+ smp_concatenate_peer(p_cb, &p, SMP_OPCODE_PAIRING_RSP);
+ }
+ else
+ {
+ /* LSB : iat': initiator's address type */
+ UINT8_TO_STREAM(p, p_dev_rec->ble.ble_addr_type);
+ /* LSB : rat': responder's(local) address type */
+ UINT8_TO_STREAM(p, 0);
+ /* concatinate preq */
+ smp_concatenate_peer(p_cb, &p, SMP_OPCODE_PAIRING_REQ);
+ /* concatinate pres */
+ smp_concatenate_local(p_cb, &p, SMP_OPCODE_PAIRING_RSP);
+ }
+#if SMP_DEBUG == TRUE
+ SMP_TRACE_DEBUG0("p1 = pres || preq || rat' || iat'");
+ smp_debug_print_nbyte_little_endian ((UINT8 *)p1, (const UINT8 *)"P1", 16);
+#endif
+}
+/*******************************************************************************
+**
+** Function smp_gen_p2_4_confirm
+**
+** Description Generate Confirm/Compare Step2:
+** p2 = padding || ia || ra
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_gen_p2_4_confirm( tSMP_CB *p_cb, BT_OCTET16 p2)
+{
+ UINT8 *p = (UINT8 *)p2;
+
+ SMP_TRACE_DEBUG0 ("smp_gen_p2_4_confirm");
+ memset(p, 0, sizeof(BT_OCTET16));
+
+ if (p_cb->role == HCI_ROLE_MASTER)
+ {
+ /* LSB ra */
+ BDADDR_TO_STREAM(p, p_cb->pairing_bda);
+ /* ia */
+ BDADDR_TO_STREAM(p, p_cb->local_bda);
+ }
+ else
+ {
+ /* LSB ra */
+ BDADDR_TO_STREAM(p, p_cb->local_bda);
+ /* ia */
+ BDADDR_TO_STREAM(p, p_cb->pairing_bda);
+ }
+#if SMP_DEBUG == TRUE
+ SMP_TRACE_DEBUG0("p2 = padding || ia || ra");
+ smp_debug_print_nbyte_little_endian(p2, (const UINT8 *)"p2", 16);
+#endif
+}
+/*******************************************************************************
+**
+** Function smp_calculate_comfirm
+**
+** Description This function is called to calculate Confirm value.
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_calculate_comfirm (tSMP_CB *p_cb, BT_OCTET16 rand, BD_ADDR bda)
+{
+ BT_OCTET16 p1;
+ tSMP_ENC output;
+ tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN;
+
+ SMP_TRACE_DEBUG0 ("smp_calculate_comfirm ");
+ /* generate p1 = pres || preq || rat' || iat' */
+ smp_gen_p1_4_confirm(p_cb, p1);
+
+ /* p1 = rand XOR p1 */
+ smp_xor_128(p1, rand);
+
+ smp_debug_print_nbyte_little_endian ((UINT8 *)p1, (const UINT8 *)"P1' = r XOR p1", 16);
+
+ /* calculate e(k, r XOR p1), where k = TK */
+ if (!SMP_Encrypt(p_cb->tk, BT_OCTET16_LEN, p1, BT_OCTET16_LEN, &output))
+ {
+ SMP_TRACE_ERROR0("smp_generate_csrk failed");
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status);
+ }
+ else
+ {
+ smp_calculate_comfirm_cont(p_cb, &output);
+ }
+}
+/*******************************************************************************
+**
+** Function smp_calculate_comfirm_cont
+**
+** Description This function is called when SConfirm/MConfirm is generated
+** proceed to send the Confirm request/response to peer device.
+**
+** Returns void
+**
+*******************************************************************************/
+static void smp_calculate_comfirm_cont(tSMP_CB *p_cb, tSMP_ENC *p)
+{
+ BT_OCTET16 p2;
+ tSMP_ENC output;
+ tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN;
+
+ SMP_TRACE_DEBUG0 ("smp_calculate_comfirm_cont ");
+#if SMP_DEBUG == TRUE
+ SMP_TRACE_DEBUG0("Confirm step 1 p1' = e(k, r XOR p1) Generated");
+ smp_debug_print_nbyte_little_endian (p->param_buf, (const UINT8 *)"C1", 16);
+#endif
+
+ smp_gen_p2_4_confirm(p_cb, p2);
+
+ /* calculate p2 = (p1' XOR p2) */
+ smp_xor_128(p2, p->param_buf);
+ smp_debug_print_nbyte_little_endian ((UINT8 *)p2, (const UINT8 *)"p2' = C1 xor p2", 16);
+
+ /* calculate: Confirm = E(k, p1' XOR p2) */
+ if (!SMP_Encrypt(p_cb->tk, BT_OCTET16_LEN, p2, BT_OCTET16_LEN, &output))
+ {
+ SMP_TRACE_ERROR0("smp_calculate_comfirm_cont failed");
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status);
+ }
+ else
+ {
+ switch (p_cb->rand_enc_proc)
+ {
+ case SMP_GEN_CONFIRM:
+ smp_process_confirm(p_cb, &output);
+ break;
+
+ case SMP_GEN_COMPARE:
+ smp_process_compare(p_cb, &output);
+ break;
+ }
+ }
+}
+/*******************************************************************************
+**
+** Function smp_genenrate_confirm
+**
+** Description This function is called when a 48 bits random number is generated
+** as SRand or MRand, continue to calculate Sconfirm or MConfirm.
+**
+** Returns void
+**
+*******************************************************************************/
+static void smp_genenrate_confirm(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG0 ("smp_genenrate_confirm ");
+ p_cb->rand_enc_proc = SMP_GEN_CONFIRM;
+
+ smp_debug_print_nbyte_little_endian ((UINT8 *)p_cb->rand, (const UINT8 *)"local rand", 16);
+
+ smp_calculate_comfirm(p_cb, p_cb->rand, p_cb->pairing_bda);
+}
+/*******************************************************************************
+**
+** Function smp_generate_compare
+**
+** Description This function is called to generate SConfirm for Slave device,
+** or MSlave for Master device. This function can be also used for
+** generating Compare number for confirm value check.
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_generate_compare (tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG0 ("smp_generate_compare ");
+ p_cb->rand_enc_proc = SMP_GEN_COMPARE;
+
+ smp_debug_print_nbyte_little_endian ((UINT8 *)p_cb->rrand, (const UINT8 *)"peer rand", 16);
+
+ smp_calculate_comfirm(p_cb, p_cb->rrand, p_cb->local_bda);
+}
+/*******************************************************************************
+**
+** Function smp_process_confirm
+**
+** Description This function is called when SConfirm/MConfirm is generated
+** proceed to send the Confirm request/response to peer device.
+**
+** Returns void
+**
+*******************************************************************************/
+static void smp_process_confirm(tSMP_CB *p_cb, tSMP_ENC *p)
+{
+ tSMP_KEY key;
+
+ SMP_TRACE_DEBUG0 ("smp_process_confirm ");
+#if SMP_CONFORMANCE_TESTING == TRUE
+ if (p_cb->enable_test_confirm_val)
+ {
+ BTM_TRACE_DEBUG0 ("Use confirm value from script");
+ memcpy(p_cb->confirm, p_cb->test_confirm, BT_OCTET16_LEN);
+ }
+ else
+ memcpy(p_cb->confirm, p->param_buf, BT_OCTET16_LEN);
+#else
+ memcpy(p_cb->confirm, p->param_buf, BT_OCTET16_LEN);
+#endif
+
+
+#if (SMP_DEBUG == TRUE)
+ SMP_TRACE_DEBUG0("Confirm Generated");
+ smp_debug_print_nbyte_little_endian ((UINT8 *)p_cb->confirm, (const UINT8 *)"Confirm", 16);
+#endif
+
+ key.key_type = SMP_KEY_TYPE_CFM;
+ key.p_data = p->param_buf;
+
+ smp_sm_event(p_cb, SMP_KEY_READY_EVT, &key);
+}
+/*******************************************************************************
+**
+** Function smp_process_compare
+**
+** Description This function is called when Compare is generated using the
+** RRand and local BDA, TK information.
+**
+** Returns void
+**
+*******************************************************************************/
+static void smp_process_compare(tSMP_CB *p_cb, tSMP_ENC *p)
+{
+ tSMP_KEY key;
+
+ SMP_TRACE_DEBUG0 ("smp_process_compare ");
+#if (SMP_DEBUG == TRUE)
+ SMP_TRACE_DEBUG0("Compare Generated");
+ smp_debug_print_nbyte_little_endian (p->param_buf, (const UINT8 *)"Compare", 16);
+#endif
+ key.key_type = SMP_KEY_TYPE_CMP;
+ key.p_data = p->param_buf;
+
+ smp_sm_event(p_cb, SMP_KEY_READY_EVT, &key);
+}
+
+/*******************************************************************************
+**
+** Function smp_process_stk
+**
+** Description This function is called when STK is generated
+** proceed to send the encrypt the link using STK.
+**
+** Returns void
+**
+*******************************************************************************/
+static void smp_process_stk(tSMP_CB *p_cb, tSMP_ENC *p)
+{
+ tSMP_KEY key;
+
+ SMP_TRACE_DEBUG0 ("smp_process_stk ");
+#if (SMP_DEBUG == TRUE)
+ SMP_TRACE_ERROR0("STK Generated");
+#endif
+ smp_mask_enc_key(p_cb->loc_enc_size, p->param_buf);
+
+ key.key_type = SMP_KEY_TYPE_STK;
+ key.p_data = p->param_buf;
+
+ smp_sm_event(p_cb, SMP_KEY_READY_EVT, &key);
+}
+
+/*******************************************************************************
+**
+** Function smp_genenrate_ltk_cont
+**
+** Description This function is to calculate LTK = d1(ER, DIV, 0)= e(ER, DIV)
+**
+** Returns void
+**
+*******************************************************************************/
+static void smp_genenrate_ltk_cont(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ BT_OCTET16 er;
+ tSMP_ENC output;
+ tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN;
+
+ SMP_TRACE_DEBUG0 ("smp_genenrate_ltk_cont ");
+ BTM_GetDeviceEncRoot(er);
+
+ /* LTK = d1(ER, DIV, 0)= e(ER, DIV)*/
+ if (!SMP_Encrypt(er, BT_OCTET16_LEN, (UINT8 *)&p_cb->div,
+ sizeof(UINT16), &output))
+ {
+ SMP_TRACE_ERROR0("smp_genenrate_ltk_cont failed");
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status);
+ }
+ else
+ {
+ /* mask the LTK */
+ smp_mask_enc_key(p_cb->loc_enc_size, output.param_buf);
+ memcpy((void *)p_cb->ltk, output.param_buf, BT_OCTET16_LEN);
+ smp_generate_rand_vector(p_cb, NULL);
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function smp_generate_y
+**
+** Description This function is to proceed generate Y = E(DHK, Rand)
+**
+** Returns void
+**
+*******************************************************************************/
+static void smp_generate_y(tSMP_CB *p_cb, tSMP_INT_DATA *p)
+{
+ BT_OCTET16 dhk;
+ tSMP_ENC output;
+ tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN;
+
+
+ SMP_TRACE_DEBUG0 ("smp_generate_y ");
+ BTM_GetDeviceDHK(dhk);
+
+ if (!SMP_Encrypt(dhk, BT_OCTET16_LEN, p_cb->enc_rand,
+ BT_OCTET8_LEN, &output))
+ {
+ SMP_TRACE_ERROR0("smp_generate_y failed");
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status);
+ }
+ else
+ {
+ smp_process_ediv(p_cb, &output);
+ }
+}
+/*******************************************************************************
+**
+** Function smp_generate_rand_vector
+**
+** Description This function is called when LTK is generated, send state machine
+** event to SMP.
+**
+** Returns void
+**
+*******************************************************************************/
+static void smp_generate_rand_vector (tSMP_CB *p_cb, tSMP_INT_DATA *p)
+{
+ /* generate EDIV and rand now */
+ /* generate random vector */
+ SMP_TRACE_DEBUG0 ("smp_generate_rand_vector ");
+ p_cb->rand_enc_proc = SMP_GEN_RAND_V;
+ if (!btsnd_hcic_ble_rand((void *)smp_rand_back))
+ smp_rand_back(NULL);
+
+}
+/*******************************************************************************
+**
+** Function smp_genenrate_smp_process_edivltk_cont
+**
+** Description This function is to calculate EDIV = Y xor DIV
+**
+** Returns void
+**
+*******************************************************************************/
+static void smp_process_ediv(tSMP_CB *p_cb, tSMP_ENC *p)
+{
+ tSMP_KEY key;
+ UINT8 *pp= p->param_buf;
+ UINT16 y;
+
+ SMP_TRACE_DEBUG0 ("smp_process_ediv ");
+ STREAM_TO_UINT16(y, pp);
+
+ /* EDIV = Y xor DIV */
+ p_cb->ediv = p_cb->div ^ y;
+ /* send LTK ready */
+ SMP_TRACE_ERROR0("LTK ready");
+ key.key_type = SMP_KEY_TYPE_LTK;
+ key.p_data = p->param_buf;
+
+ smp_sm_event(p_cb, SMP_KEY_READY_EVT, &key);
+}
+
+/*******************************************************************************
+**
+** Function smp_rand_back
+**
+** Description This function is to process the rand command finished,
+** process the random/encrypted number for further action.
+**
+** Returns void
+**
+*******************************************************************************/
+static void smp_rand_back(tBTM_RAND_ENC *p)
+{
+ tSMP_CB *p_cb = &smp_cb;
+ UINT8 *pp = p->param_buf;
+ UINT8 failure = SMP_PAIR_FAIL_UNKNOWN;
+ UINT8 state = p_cb->rand_enc_proc & ~0x80;
+
+ SMP_TRACE_DEBUG1 ("smp_rand_back state=0x%x", state);
+ if (p && p->status == HCI_SUCCESS)
+ {
+ switch (state)
+ {
+
+ case SMP_GEN_SRAND_MRAND:
+ memcpy((void *)p_cb->rand, p->param_buf, p->param_len);
+ smp_genenrate_rand_cont(p_cb, NULL);
+ break;
+
+ case SMP_GEN_SRAND_MRAND_CONT:
+ memcpy((void *)&p_cb->rand[8], p->param_buf, p->param_len);
+ smp_genenrate_confirm(p_cb, NULL);
+ break;
+
+ case SMP_GEN_DIV_LTK:
+ STREAM_TO_UINT16(p_cb->div, pp);
+ smp_genenrate_ltk_cont(p_cb, NULL);
+ break;
+
+ case SMP_GEN_DIV_CSRK:
+ STREAM_TO_UINT16(p_cb->div, pp);
+ smp_compute_csrk(p_cb, NULL);
+ break;
+
+ case SMP_GEN_TK:
+ smp_proc_passkey(p_cb, p);
+ break;
+
+ case SMP_GEN_RAND_V:
+ memcpy(p_cb->enc_rand, p->param_buf, BT_OCTET8_LEN);
+ smp_generate_y(p_cb, NULL);
+ break;
+
+ }
+
+ return;
+ }
+
+ SMP_TRACE_ERROR1("smp_rand_back Key generation failed: (%d)", p_cb->rand_enc_proc);
+
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure);
+
+}
+#endif
+
diff --git a/stack/smp/smp_l2c.c b/stack/smp/smp_l2c.c
new file mode 100644
index 0000000..0356612
--- /dev/null
+++ b/stack/smp/smp_l2c.c
@@ -0,0 +1,148 @@
+/*****************************************************************************
+** *
+** Name: smp_l2c.c *
+** *
+** Description: This file contains functions for the SMP L2Cap interface *
+** *
+** *
+** Copyright (c) 1999-2009, Broadcom Corp., All Rights Reserved. *
+** Broadcom Bluetooth Core. Proprietary and confidential. *
+******************************************************************************/
+
+#include "bt_target.h"
+
+#if SMP_INCLUDED == TRUE
+
+#include <string.h>
+#include "btm_ble_api.h"
+#include "l2c_api.h"
+
+#include "smp_int.h"
+
+
+
+static void smp_connect_cback (BD_ADDR bd_addr, BOOLEAN connected, UINT16 reason);
+static void smp_data_ind (BD_ADDR bd_addr, BT_HDR *p_buf);
+
+/*******************************************************************************
+**
+** Function smp_l2cap_if_init
+**
+** Description This function is called during the SMP task startup
+** to register interface functions with L2CAP.
+**
+*******************************************************************************/
+void smp_l2cap_if_init (void)
+{
+ tL2CAP_FIXED_CHNL_REG fixed_reg;
+ SMP_TRACE_EVENT0 ("SMDBG l2c smp_l2cap_if_init");
+ fixed_reg.fixed_chnl_opts.mode = L2CAP_FCR_BASIC_MODE;
+ fixed_reg.fixed_chnl_opts.max_transmit = 0;
+ fixed_reg.fixed_chnl_opts.rtrans_tout = 0;
+ fixed_reg.fixed_chnl_opts.mon_tout = 0;
+ fixed_reg.fixed_chnl_opts.mps = 0;
+ fixed_reg.fixed_chnl_opts.tx_win_sz = 0;
+
+ fixed_reg.pL2CA_FixedConn_Cb = smp_connect_cback;
+ fixed_reg.pL2CA_FixedData_Cb = smp_data_ind;
+ fixed_reg.default_idle_tout = 60; /* set 60 seconds timeout, 0xffff default idle timeout */
+
+ /* Now, register with L2CAP */
+ L2CA_RegisterFixedChannel (L2CAP_SMP_CID, &fixed_reg);
+}
+
+/*******************************************************************************
+**
+** Function smp_connect_cback
+**
+** Description This callback function is called by L2CAP to indicate that
+** SMP channel is
+** connected (conn = TRUE)/disconnected (conn = FALSE).
+**
+*******************************************************************************/
+static void smp_connect_cback (BD_ADDR bd_addr, BOOLEAN connected, UINT16 reason)
+{
+ tSMP_CB *p_cb = &smp_cb;
+ tSMP_INT_DATA int_data;
+
+ SMP_TRACE_EVENT0 ("SMDBG l2c smp_connect_cback ");
+
+ if (memcmp(bd_addr, p_cb->pairing_bda, BD_ADDR_LEN) == 0)
+ {
+ SMP_TRACE_EVENT3 ("smp_connect_cback() for pairing BDA: %08x%04x Event: %s",
+ (bd_addr[0]<<24)+(bd_addr[1]<<16)+(bd_addr[2]<<8) + bd_addr[3],
+ (bd_addr[4]<<8)+bd_addr[5], (connected) ? "connected" : "disconnected");
+
+ if (connected)
+ {
+ if(!p_cb->connect_initialized)
+ {
+ p_cb->connect_initialized = TRUE;
+ /* initiating connection established */
+ p_cb->role = L2CA_GetBleConnRole(bd_addr);
+
+ /* initialize local i/r key to be default keys */
+ p_cb->loc_r_key = p_cb->loc_i_key = SMP_SEC_DEFAULT_KEY;
+ p_cb->loc_auth_req = p_cb->peer_auth_req = SMP_DEFAULT_AUTH_REQ;
+ p_cb->cb_evt = SMP_IO_CAP_REQ_EVT;
+ smp_sm_event(p_cb, SMP_L2CAP_CONN_EVT, NULL);
+
+ BTM_ReadConnectionAddr(p_cb->local_bda);
+ }
+ }
+ else
+ {
+ int_data.reason = reason;
+ /* Disconnected while doing security */
+ smp_sm_event(p_cb, SMP_L2CAP_DISCONN_EVT, &int_data);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function smp_data_ind
+**
+** Description This function is called when data is received from L2CAP on
+** SMP channel.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void smp_data_ind (BD_ADDR bd_addr, BT_HDR *p_buf)
+{
+ tSMP_CB *p_cb = &smp_cb;
+ UINT8 *p = (UINT8 *)(p_buf + 1) + p_buf->offset;
+ UINT8 cmd ;
+ SMP_TRACE_EVENT0 ("SMDBG l2c smp_data_ind");
+
+ SMP_TRACE_EVENT0 ("Got smp_data_ind");
+
+ STREAM_TO_UINT8(cmd, p);
+
+
+ /* reject the pairing request if there is an on-going SMP pairing */
+ if (SMP_OPCODE_PAIRING_REQ == cmd || SMP_OPCODE_SEC_REQ == cmd)
+ {
+ if (p_cb->state == SMP_ST_IDLE)
+ {
+ p_cb->role = L2CA_GetBleConnRole(bd_addr);
+ memcpy(&p_cb->pairing_bda[0], bd_addr, BD_ADDR_LEN);
+ }
+ else if (memcmp(&bd_addr[0], p_cb->pairing_bda, BD_ADDR_LEN))
+ {
+ p_cb->failure = SMP_PAIR_NOT_SUPPORT;
+ smp_send_cmd(SMP_OPCODE_PAIRING_FAILED, p_cb);
+ }
+ }
+
+ if (memcmp(&bd_addr[0], p_cb->pairing_bda, BD_ADDR_LEN) == 0)
+ {
+ btu_stop_timer (&p_cb->rsp_timer_ent);
+ smp_sm_event(p_cb, cmd, p);
+ }
+
+ GKI_freebuf (p_buf);
+}
+#endif
diff --git a/stack/smp/smp_main.c b/stack/smp/smp_main.c
new file mode 100644
index 0000000..1b67011
--- /dev/null
+++ b/stack/smp/smp_main.c
@@ -0,0 +1,511 @@
+/*****************************************************************************
+**
+** Name: smp_main.c
+**
+** File: SMP State Machine and Control Block Access Functions
+**
+** Copyright (c) 2003-2009, Broadcom Corp., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bt_target.h"
+
+#if SMP_INCLUDED == TRUE
+
+ #include <string.h>
+ #include "smp_int.h"
+
+
+const char * const smp_state_name [] =
+{
+ "SMP_ST_IDLE",
+ "SMP_ST_WAIT_APP_RSP",
+ "SMP_ST_SEC_REQ_PENDING",
+ "SMP_ST_PAIR_REQ_RSP",
+ "SMP_ST_WAIT_CONFIRM",
+ "SMP_ST_CONFIRM",
+ "SMP_ST_RAND",
+ "SMP_ST_ENC_PENDING",
+ "SMP_ST_BOND_PENDING",
+ "SMP_ST_RELEASE_DELAY",
+ "SMP_ST_MAX"
+};
+const char * const smp_event_name [] =
+{
+ "PAIRING_REQ_EVT",
+ "PAIRING_RSP_EVT",
+ "CONFIRM_EVT",
+ "RAND_EVT",
+ "PAIRING_FAILED_EVT",
+ "ENC_INFO_EVT",
+ "MASTER_ID_EVT",
+ "ID_INFO_EVT",
+ "ID_ADDR_EVT",
+ "SIGN_INFO_EVT",
+ "SECURITY_REQ_EVT",
+ "KEY_READY_EVT",
+ "ENCRYPTED_EVT",
+ "L2CAP_CONN_EVT",
+ "L2CAP_DISCONN_EVT",
+ "API_IO_RSP_EVT",
+ "API_SEC_GRANT_EVT",
+ "TK_REQ_EVT",
+ "AUTH_CMPL_EVT",
+ "ENC_REQ_EVT",
+ "BOND_REQ_EVT",
+ "DISCARD_SEC_REQ_EVT",
+ "RELEASE_DELAY_EVT",
+ "RELEASE_DELAY_TOUT_EVT",
+ "MAX_EVT"
+};
+const char * smp_get_event_name(tSMP_EVENT event);
+const char * smp_get_state_name(tSMP_STATE state);
+
+ #define SMP_SM_IGNORE 0
+ #define SMP_NUM_ACTIONS 2
+ #define SMP_SME_NEXT_STATE 2
+ #define SMP_SM_NUM_COLS 3
+typedef const UINT8 (*tSMP_SM_TBL)[SMP_SM_NUM_COLS];
+
+enum
+{
+ SMP_PROC_SEC_REQ,
+ SMP_SEND_PAIR_REQ,
+ SMP_SEND_PAIR_RSP,
+ SMP_SEND_CONFIRM,
+ SMP_SEND_PAIR_FAIL,
+ SMP_SEND_INIT,
+ SMP_SEND_SECU_INFO,
+ SMP_SEND_ID_INFO,
+ SMP_SEND_LTK_REPLY,
+ SMP_PROC_PAIR_CMD,
+ SMP_PROC_PAIR_FAIL,
+ SMP_PROC_CONFIRM,
+ SMP_PROC_INIT,
+ SMP_PROC_ENC_INFO,
+ SMP_PROC_MASTER_ID,
+ SMP_PROC_ID_INFO,
+ SMP_PROC_ID_ADDR,
+ SMP_PROC_SRK_INFO,
+ SMP_PROC_SEC_GRANT,
+ SMP_PROC_SL_KEY,
+ SMP_PROC_COMPARE,
+ SMP_PROC_IO_RSP,
+ SMP_GENERATE_COMPARE,
+ SMP_GENERATE_CONFIRM,
+ SMP_GENERATE_STK,
+ SMP_KEY_DISTRIBUTE,
+ SMP_START_ENC,
+ SMP_PAIRING_CMPL,
+ SMP_DECIDE_ASSO_MODEL,
+ SMP_SEND_APP_CBACK,
+ SMP_CHECK_AUTH_REQ,
+ SMP_PAIR_TERMINATE,
+ SMP_ENC_CMPL,
+ SMP_PROC_DISCARD,
+ SMP_PROC_REL_DELAY,
+ SMP_PROC_REL_DELAY_TOUT,
+ SMP_SM_NO_ACTION
+};
+
+static const tSMP_ACT smp_sm_action[] =
+{
+ smp_proc_sec_req,
+ smp_send_pair_req,
+ smp_send_pair_rsp,
+ smp_send_confirm,
+ smp_send_pair_fail,
+ smp_send_init,
+ smp_send_enc_info,
+ smp_send_id_info,
+ smp_send_ltk_reply,
+ smp_proc_pair_cmd,
+ smp_proc_pair_fail,
+ smp_proc_confirm,
+ smp_proc_init,
+ smp_proc_enc_info,
+ smp_proc_master_id,
+ smp_proc_id_info,
+ smp_proc_id_addr,
+ smp_proc_srk_info,
+ smp_proc_sec_grant,
+ smp_proc_sl_key,
+ smp_proc_compare,
+ smp_proc_io_rsp,
+ smp_generate_compare,
+ smp_generate_confirm,
+ smp_generate_stk,
+ smp_key_distribution,
+ smp_start_enc,
+ smp_pairing_cmpl,
+ smp_decide_asso_model,
+ smp_send_app_cback,
+ smp_check_auth_req,
+ smp_pair_terminate,
+ smp_enc_cmpl,
+ smp_proc_discard,
+ smp_proc_release_delay,
+ smp_proc_release_delay_tout,
+};
+/************ SMP Master FSM State/Event Indirection Table **************/
+static const UINT8 smp_ma_entry_map[][SMP_ST_MAX] =
+{
+/* state name: Idle WaitApp SecReq Pair Wait Confirm Init Enc Bond Rel
+ Rsp Pend ReqRsp Cfm Pend Pend Delay */
+/* PAIR_REQ */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+/* PAIR_RSP */{ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 },
+/* CONFIRM */{ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 },
+/* INIT */{ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 },
+/* PAIR_FAIL */{ 0, 0x81, 0, 0x81, 0x81,0x81, 0x81,0, 0, 0 },
+/* ENC_INFO */{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 },
+/* MASTER_ID */{ 0, 0, 0, 0, 0, 0, 0, 0, 4, 0 },
+/* ID_INFO */{ 0, 0, 0, 0, 0, 0, 0, 0, 2, 0 },
+/* ID_ADDR */{ 0, 0, 0, 0, 0, 0, 0, 0, 5, 0 },
+/* SIGN_INFO */{ 0, 0, 0, 0, 0, 0, 0, 0, 3, 0 },
+/* SEC_REQ */{ 2, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+/* KEY_READY */{ 0, 3, 0, 3, 1, 0, 2, 1, 6, 0 },
+/* ENC_CMPL */{ 0, 0, 0, 0, 0, 0, 0, 2, 0, 0 },
+/* L2C_CONN */{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+/* L2C_DISC */{ 0, 0x83, 0, 0x83, 0x83,0x83, 0x83,0x83, 0x83, 2 },
+/* IO_RSP */{ 0, 2, 0, 0, 0, 0, 0, 0, 0, 0 },
+/* SEC_GRANT */{ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
+/* TK_REQ */{ 0, 0, 0, 2, 0, 0, 0, 0, 0, 0 },
+/* AUTH_CMPL */{ 0, 0x82, 0, 0x82, 0x82,0x82, 0x82,0x82, 0x82, 0 },
+/* ENC_REQ */{ 0, 4, 0, 0, 0, 0, 3, 0, 0, 0 },
+/* BOND_REQ */{ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0 },
+/* DISCARD_SEC_REQ */{ 0, 5, 0, 0, 0, 0, 0, 3, 0, 0 },
+/* RELEASE_DELAY */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
+/* RELEASE_DELAY_TOUT */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 },
+};
+
+static const UINT8 smp_all_table[][SMP_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* PAIR_FAIL */ {SMP_PROC_PAIR_FAIL, SMP_PROC_REL_DELAY_TOUT, SMP_ST_IDLE},
+/* AUTH_CMPL */ {SMP_SEND_PAIR_FAIL, SMP_PAIRING_CMPL, SMP_ST_RELEASE_DELAY},
+/* L2C_DISC */ {SMP_PAIR_TERMINATE, SMP_SM_NO_ACTION, SMP_ST_IDLE}
+};
+
+static const UINT8 smp_ma_idle_table[][SMP_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* L2C_CONN */ {SMP_SEND_APP_CBACK, SMP_SM_NO_ACTION, SMP_ST_WAIT_APP_RSP},
+/* SEC_REQ */ {SMP_PROC_SEC_REQ, SMP_SEND_APP_CBACK, SMP_ST_WAIT_APP_RSP}
+};
+
+static const UINT8 smp_ma_wait_app_rsp_table[][SMP_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* SEC_GRANT */ { SMP_PROC_SEC_GRANT, SMP_SEND_APP_CBACK, SMP_ST_WAIT_APP_RSP},
+/* IO_RSP */ { SMP_SEND_PAIR_REQ, SMP_SM_NO_ACTION, SMP_ST_PAIR_REQ_RSP},
+/* KEY_READY */ { SMP_GENERATE_CONFIRM, SMP_SM_NO_ACTION, SMP_ST_WAIT_CONFIRM},/* TK ready */
+/* ENC_REQ */ { SMP_START_ENC, SMP_SM_NO_ACTION, SMP_ST_ENC_PENDING},/* start enc mode setup */
+/* DISCARD_SEC_REQ */ { SMP_PROC_DISCARD, SMP_SM_NO_ACTION, SMP_ST_IDLE}
+};
+
+static const UINT8 smp_ma_pair_req_rsp_table [][SMP_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* PAIR_RSP */ { SMP_PROC_PAIR_CMD, SMP_DECIDE_ASSO_MODEL, SMP_ST_PAIR_REQ_RSP},
+/* TK_REQ */ { SMP_SEND_APP_CBACK, SMP_SM_NO_ACTION, SMP_ST_WAIT_APP_RSP},
+/* KEY_READY */{ SMP_GENERATE_CONFIRM, SMP_SM_NO_ACTION, SMP_ST_WAIT_CONFIRM} /* TK ready */
+};
+
+static const UINT8 smp_ma_wait_confirm_table[][SMP_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* KEY_READY*/ {SMP_SEND_CONFIRM, SMP_SM_NO_ACTION, SMP_ST_CONFIRM}/* CONFIRM ready */
+};
+
+static const UINT8 smp_ma_confirm_table [][SMP_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* CONFIRM */ { SMP_PROC_CONFIRM, SMP_SEND_INIT, SMP_ST_RAND}
+};
+
+static const UINT8 smp_ma_init_table [][SMP_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* INIT */ { SMP_PROC_INIT, SMP_GENERATE_COMPARE, SMP_ST_RAND},
+/* KEY_READY*/ { SMP_PROC_COMPARE, SMP_SM_NO_ACTION, SMP_ST_RAND}, /* Compare ready */
+/* ENC_REQ */ { SMP_GENERATE_STK, SMP_SM_NO_ACTION, SMP_ST_ENC_PENDING}
+};
+static const UINT8 smp_ma_enc_pending_table[][SMP_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* KEY_READY */ { SMP_START_ENC, SMP_SM_NO_ACTION, SMP_ST_ENC_PENDING}, /* STK ready */
+/* ENCRYPTED */ { SMP_CHECK_AUTH_REQ, SMP_SM_NO_ACTION, SMP_ST_ENC_PENDING},
+/* BOND_REQ */ { SMP_KEY_DISTRIBUTE, SMP_SM_NO_ACTION, SMP_ST_BOND_PENDING}
+};
+static const UINT8 smp_ma_bond_pending_table[][SMP_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* ENC_INFO */ { SMP_PROC_ENC_INFO, SMP_SM_NO_ACTION, SMP_ST_BOND_PENDING},
+/* ID_INFO */ { SMP_PROC_ID_INFO, SMP_SM_NO_ACTION, SMP_ST_BOND_PENDING},
+/* SIGN_INFO*/ { SMP_PROC_SRK_INFO, SMP_SM_NO_ACTION, SMP_ST_BOND_PENDING},
+/* MASTER_ID*/ { SMP_PROC_MASTER_ID, SMP_SM_NO_ACTION, SMP_ST_BOND_PENDING},
+/* ID_ADDR */ { SMP_PROC_ID_ADDR, SMP_SM_NO_ACTION, SMP_ST_BOND_PENDING},
+/* KEY_READY */ {SMP_SEND_SECU_INFO, SMP_SM_NO_ACTION, SMP_ST_BOND_PENDING} /* LTK ready */
+};
+
+static const UINT8 smp_ma_rel_delay_table[][SMP_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* RELEASE_DELAY*/ {SMP_PROC_REL_DELAY, SMP_SM_NO_ACTION, SMP_ST_RELEASE_DELAY},
+/* RELEASE_DELAY_TOUT*/ {SMP_PROC_REL_DELAY_TOUT, SMP_SM_NO_ACTION, SMP_ST_IDLE}
+};
+
+
+/************ SMP Slave FSM State/Event Indirection Table **************/
+static const UINT8 smp_sl_entry_map[][SMP_ST_MAX] =
+{
+/* state name: Idle Wait SecReq Pair Wait Confirm Init Enc Bond Rel
+ AppRsp Pend ReqRsp Cfm Pend Pend Delay */
+/* PAIR_REQ */ { 2, 0, 1, 0, 0, 0, 0, 0, 0, 0 },
+/* PAIR_RSP */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+/* CONFIRM */ { 0, 4, 0, 1, 1, 0, 0, 0, 0, 0 },
+/* INIT */ { 0, 0, 0, 0, 0, 1, 2, 0, 0, 0 },
+/* PAIR_FAIL*/ { 0, 0x81, 0x81, 0x81, 0x81,0x81, 0x81,0x81, 0, 0 },
+/* ENC_INFO */ { 0, 0, 0, 0, 0, 0, 0, 0, 3, 0 },
+/* MASTER_ID*/ { 0, 0, 0, 0, 0, 0, 0, 0, 5, 0 },
+/* ID_INFO */ { 0, 0, 0, 0, 0, 0, 0, 0, 4, 0 },
+/* ID_ADDR */ { 0, 0, 0, 0, 0, 0, 0, 0, 6, 0 },
+/* SIGN_INFO*/ { 0, 0, 0, 0, 0, 0, 0, 0, 2, 0 },
+/* SEC_REQ */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+
+/* KEY_READY*/ { 0, 3, 0, 3, 2, 2, 1, 2, 1, 0 },
+/* ENC_CMPL */ { 0, 0, 2, 0, 0, 0, 0, 3, 0, 0 },
+/* L2C_CONN */ { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+/* L2C_DISC */ { 0, 0x83, 0x83, 0x83, 0x83,0x83, 0x83,0x83, 0x83, 2 },
+/* IO_RSP */ { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
+/* SEC_GRANT*/ { 0, 2, 0, 0, 0, 0, 0, 0, 0, 0 },
+
+/* TK_REQ */ { 0, 0, 0, 2, 0, 0, 0, 0, 0, 0 },
+/* AUTH_CMPL*/ { 0, 0x82, 0x82, 0x82, 0x82,0x82, 0x82,0x82, 0x82, 0 },
+/* ENC_REQ */ { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 },
+/* BOND_REQ */ { 0, 0, 0, 0, 0, 0, 0, 4, 0, 0 },
+/* DISCARD_SEC_REQ */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+/* RELEASE_DELAY */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
+/* RELEASE_DELAY_TOUT */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 },
+};
+
+static const UINT8 smp_sl_idle_table[][SMP_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* L2C_CONN */ {SMP_SEND_APP_CBACK, SMP_SM_NO_ACTION, SMP_ST_WAIT_APP_RSP},
+/* PAIR_REQ */ {SMP_PROC_PAIR_CMD, SMP_SEND_APP_CBACK, SMP_ST_WAIT_APP_RSP}
+};
+
+static const UINT8 smp_sl_wait_app_rsp_table [][SMP_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* IO_RSP */ {SMP_PROC_IO_RSP, SMP_SM_NO_ACTION, SMP_ST_PAIR_REQ_RSP},
+/* SEC_GRANT */ {SMP_PROC_SEC_GRANT, SMP_SEND_APP_CBACK, SMP_ST_WAIT_APP_RSP},
+/* KEY_READY */ {SMP_PROC_SL_KEY, SMP_SM_NO_ACTION, SMP_ST_WAIT_APP_RSP},/* TK ready */
+/* CONFIRM */ {SMP_PROC_CONFIRM, SMP_SM_NO_ACTION, SMP_ST_CONFIRM}
+};
+
+static const UINT8 smp_sl_sec_request_table[][SMP_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* PAIR_REQ */{SMP_PROC_PAIR_CMD, SMP_SEND_PAIR_RSP, SMP_ST_PAIR_REQ_RSP},
+/* ENCRYPTED*/{SMP_ENC_CMPL, SMP_SM_NO_ACTION, SMP_ST_PAIR_REQ_RSP},
+};
+
+static const UINT8 smp_sl_pair_req_rsp_table[][SMP_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* CONFIRM */ {SMP_PROC_CONFIRM, SMP_SM_NO_ACTION, SMP_ST_CONFIRM},
+/* TK_REQ */ {SMP_SEND_APP_CBACK, SMP_SM_NO_ACTION, SMP_ST_WAIT_APP_RSP},
+/* KEY_READY */{SMP_PROC_SL_KEY, SMP_SM_NO_ACTION, SMP_ST_PAIR_REQ_RSP} /* TK/Confirm ready */
+
+};
+
+static const UINT8 smp_sl_wait_confirm_table[][SMP_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* CONFIRM */ {SMP_PROC_CONFIRM, SMP_SEND_CONFIRM, SMP_ST_CONFIRM},
+/* KEY_READY*/ {SMP_PROC_SL_KEY, SMP_SM_NO_ACTION, SMP_ST_WAIT_CONFIRM}
+};
+static const UINT8 smp_sl_confirm_table [][SMP_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* INIT_EVT */{ SMP_PROC_INIT, SMP_GENERATE_COMPARE, SMP_ST_RAND},
+/* KEY_READY*/ {SMP_PROC_SL_KEY, SMP_SM_NO_ACTION, SMP_ST_CONFIRM} /* TK/Confirm ready */
+};
+static const UINT8 smp_sl_init_table [][SMP_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* KEY_READY */ {SMP_PROC_COMPARE, SMP_SM_NO_ACTION, SMP_ST_RAND}, /* compare match */
+/* INIT_EVT */ {SMP_SEND_INIT, SMP_SM_NO_ACTION, SMP_ST_ENC_PENDING}
+};
+static const UINT8 smp_sl_enc_pending_table[][SMP_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* ENC_REQ */ {SMP_GENERATE_STK, SMP_SM_NO_ACTION, SMP_ST_ENC_PENDING},
+/* KEY_READY */ {SMP_SEND_LTK_REPLY, SMP_SM_NO_ACTION, SMP_ST_ENC_PENDING},/* STK ready */
+/* ENCRYPTED */ {SMP_CHECK_AUTH_REQ, SMP_SM_NO_ACTION, SMP_ST_ENC_PENDING},
+/* BOND_REQ */ {SMP_KEY_DISTRIBUTE, SMP_SM_NO_ACTION, SMP_ST_BOND_PENDING}
+};
+static const UINT8 smp_sl_bond_pending_table[][SMP_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* KEY_READY */ {SMP_SEND_SECU_INFO, SMP_SM_NO_ACTION, SMP_ST_BOND_PENDING}, /* LTK ready */
+/* SIGN_INFO */ {SMP_PROC_SRK_INFO, SMP_SM_NO_ACTION, SMP_ST_BOND_PENDING}, /* rev SRK */
+/* ENC_INFO */ { SMP_PROC_ENC_INFO, SMP_SM_NO_ACTION, SMP_ST_BOND_PENDING},
+/* ID_INFO */ { SMP_PROC_ID_INFO, SMP_SM_NO_ACTION, SMP_ST_BOND_PENDING},
+/* MASTER_ID*/ { SMP_PROC_MASTER_ID, SMP_SM_NO_ACTION, SMP_ST_BOND_PENDING},
+/* ID_ADDR */ { SMP_PROC_ID_ADDR, SMP_SM_NO_ACTION, SMP_ST_BOND_PENDING}
+
+};
+
+static const UINT8 smp_sl_rel_delay_table[][SMP_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* RELEASE_DELAY*/ {SMP_PROC_REL_DELAY, SMP_SM_NO_ACTION, SMP_ST_RELEASE_DELAY},
+/* RELEASE_DELAY_TOUT*/ {SMP_PROC_REL_DELAY_TOUT, SMP_SM_NO_ACTION, SMP_ST_IDLE}
+};
+
+static const tSMP_SM_TBL smp_state_table[][2] = {
+ {smp_ma_idle_table, smp_sl_idle_table}, /* SMP_ST_IDLE*/
+ {smp_ma_wait_app_rsp_table, smp_sl_wait_app_rsp_table}, /* SMP_ST_WAIT_APP_RSP */
+ {NULL, smp_sl_sec_request_table}, /* SMP_ST_SEC_REQ_PENDING */
+ {smp_ma_pair_req_rsp_table, smp_sl_pair_req_rsp_table}, /* SMP_ST_PAIR_REQ_RSP */
+ {smp_ma_wait_confirm_table, smp_sl_wait_confirm_table}, /* SMP_ST_WAIT_CONFIRM */
+ {smp_ma_confirm_table, smp_sl_confirm_table}, /* SMP_ST_CONFIRM */
+ {smp_ma_init_table, smp_sl_init_table}, /* SMP_ST_RAND */
+ {smp_ma_enc_pending_table, smp_sl_enc_pending_table}, /* SMP_ST_ENC_PENDING */
+ {smp_ma_bond_pending_table, smp_sl_bond_pending_table}, /* SMP_ST_BOND_PENDING */
+ {smp_ma_rel_delay_table, smp_sl_rel_delay_table} /* SMP_ST_RELEASE_DELAY */
+};
+
+typedef const UINT8 (*tSMP_ENTRY_TBL)[SMP_ST_MAX];
+static const tSMP_ENTRY_TBL smp_entry_table[] ={
+ smp_ma_entry_map,
+ smp_sl_entry_map
+};
+
+#if SMP_DYNAMIC_MEMORY == FALSE
+tSMP_CB smp_cb;
+#endif
+#define SMP_ALL_TBL_MASK 0x80
+
+
+/*******************************************************************************
+** Function smp_set_state
+** Returns None
+*******************************************************************************/
+void smp_set_state(tSMP_STATE state)
+{
+ if (state < SMP_ST_MAX)
+ {
+ SMP_TRACE_DEBUG4( "State change: %s(%d) ==> %s(%d)",
+ smp_get_state_name(smp_cb.state), smp_cb.state,
+ smp_get_state_name(state), state );
+ smp_cb.state = state;
+ }
+ else
+ {
+ SMP_TRACE_DEBUG1("smp_set_state invalid state =%d", state );
+ }
+}
+
+/*******************************************************************************
+** Function smp_get_state
+** Returns The smp state
+*******************************************************************************/
+tSMP_STATE smp_get_state(void)
+{
+ return smp_cb.state;
+}
+
+
+/*******************************************************************************
+**
+** Function smp_sm_event
+**
+** Description Handle events to the state machine. It looks up the entry
+** in the smp_entry_table array.
+** If it is a valid entry, it gets the state table.Set the next state,
+** if not NULL state.Execute the action function according to the
+** state table. If the state returned by action function is not NULL
+** state, adjust the new state to the returned state.If (api_evt != MAX),
+** call callback function.
+**
+** Returns void.
+**
+*******************************************************************************/
+void smp_sm_event(tSMP_CB *p_cb, tSMP_EVENT event, void *p_data)
+{
+ UINT8 curr_state = p_cb->state;
+ tSMP_SM_TBL state_table;
+ UINT8 action, entry, i;
+ tSMP_ENTRY_TBL entry_table = smp_entry_table[p_cb->role];
+
+ SMP_TRACE_EVENT0("main smp_sm_event");
+ if (curr_state >= SMP_ST_MAX)
+ {
+ SMP_TRACE_DEBUG1( "Invalid state: %d", curr_state) ;
+ return;
+ }
+
+ SMP_TRACE_DEBUG5( "SMP Role: %s State: [%s (%d)], Event: [%s (%d)]",\
+ (p_cb->role == 0x01) ?"Slave" : "Master", smp_get_state_name( p_cb->state),
+ p_cb->state, smp_get_event_name(event), event) ;
+
+ /* look up the state table for the current state */
+ /* lookup entry /w event & curr_state */
+ /* If entry is ignore, return.
+ * Otherwise, get state table (according to curr_state or all_state) */
+ if ( (entry = entry_table[event - 1][curr_state]) != SMP_SM_IGNORE )
+ {
+ if (entry & SMP_ALL_TBL_MASK)
+ {
+ entry &= ~SMP_ALL_TBL_MASK;
+ state_table = smp_all_table;
+ }
+ else
+ state_table = smp_state_table[curr_state][p_cb->role];
+ }
+ else
+ {
+ SMP_TRACE_DEBUG4( "Ignore event [%s (%d)] in state [%s (%d)]",
+ smp_get_event_name(event), event, smp_get_state_name(curr_state), curr_state);
+ return;
+ }
+
+ /* Get possible next state from state table. */
+
+ smp_set_state(state_table[entry-1][SMP_SME_NEXT_STATE]);
+
+ /* If action is not ignore, clear param, exec action and get next state.
+ * The action function may set the Param for cback.
+ * Depending on param, call cback or free buffer. */
+ /* execute action */
+ /* execute action functions */
+ for (i = 0; i < SMP_NUM_ACTIONS; i++)
+ {
+ if ((action = state_table[entry-1][i]) != SMP_SM_NO_ACTION)
+ {
+ (*smp_sm_action[action])(p_cb, (tSMP_INT_DATA *)p_data);
+ }
+ else
+ {
+ break;
+ }
+ }
+ SMP_TRACE_DEBUG1( "result state = %s", smp_get_state_name( p_cb->state ) ) ;
+}
+
+
+/*******************************************************************************
+** Function smp_get_state_name
+** Returns The smp state name.
+*******************************************************************************/
+const char * smp_get_state_name(tSMP_STATE state)
+{
+ const char * p_str = smp_state_name[SMP_ST_MAX];
+
+ if (state < SMP_ST_MAX)
+ {
+ p_str = smp_state_name[state];
+ }
+ return p_str;
+}
+/*******************************************************************************
+** Function smp_get_event_name
+** Returns The smp event name.
+*******************************************************************************/
+const char * smp_get_event_name(tSMP_EVENT event)
+{
+ const char * p_str = smp_event_name[SMP_MAX_EVT - 1];
+
+ if (event < SMP_MAX_EVT)
+ {
+ p_str = smp_event_name[event- 1];
+ }
+ return p_str;
+}
+#endif
+
diff --git a/stack/smp/smp_utils.c b/stack/smp/smp_utils.c
new file mode 100644
index 0000000..7e4700f
--- /dev/null
+++ b/stack/smp/smp_utils.c
@@ -0,0 +1,665 @@
+/*****************************************************************************
+** *
+** Name: smp_utils.c *
+** *
+** Description: This file contains functions for the SMP L2Cap utility *
+** functions *
+** *
+** Copyright (c) 1999-2009, Broadcom Corp., All Rights Reserved. *
+** Broadcom Bluetooth Core. Proprietary and confidential. *
+******************************************************************************/
+#include "bt_target.h"
+
+#if SMP_INCLUDED == TRUE
+
+ #include "bt_types.h"
+ #include <string.h>
+ #include <ctype.h>
+ #include "hcidefs.h"
+ #include "btm_ble_api.h"
+ #include "l2c_api.h"
+ #include "l2c_int.h"
+ #include "smp_int.h"
+
+ #if (BT_TRACE_PROTOCOL == TRUE)
+ #include "trace_api.h"
+ #endif
+
+ #define SMP_PAIRING_REQ_SIZE 7
+ #define SMP_CONFIRM_CMD_SIZE (BT_OCTET16_LEN + 1)
+ #define SMP_INIT_CMD_SIZE (BT_OCTET16_LEN + 1)
+ #define SMP_ENC_INFO_SIZE (BT_OCTET16_LEN + 1)
+ #define SMP_MASTER_ID_SIZE (BT_OCTET8_LEN + 2 + 1)
+ #define SMP_ID_INFO_SIZE (BT_OCTET16_LEN + 1)
+ #define SMP_ID_ADDR_SIZE (BD_ADDR_LEN + 1 + 1)
+ #define SMP_SIGN_INFO_SIZE (BT_OCTET16_LEN + 1)
+ #define SMP_PAIR_FAIL_SIZE 2
+
+
+/* type for action functions */
+typedef BT_HDR * (*tSMP_CMD_ACT)(UINT8 cmd_code, tSMP_CB *p_cb);
+
+static BT_HDR * smp_build_pairing_cmd(UINT8 cmd_code, tSMP_CB *p_cb);
+static BT_HDR * smp_build_confirm_cmd(UINT8 cmd_code, tSMP_CB *p_cb);
+static BT_HDR * smp_build_rand_cmd(UINT8 cmd_code, tSMP_CB *p_cb);
+static BT_HDR * smp_build_pairing_fail(UINT8 cmd_code, tSMP_CB *p_cb);
+static BT_HDR * smp_build_identity_info_cmd(UINT8 cmd_code, tSMP_CB *p_cb);
+static BT_HDR * smp_build_encrypt_info_cmd(UINT8 cmd_code, tSMP_CB *p_cb);
+static BT_HDR * smp_build_security_request(UINT8 cmd_code, tSMP_CB *p_cb);
+static BT_HDR * smp_build_signing_info_cmd(UINT8 cmd_code, tSMP_CB *p_cb);
+static BT_HDR * smp_build_master_id_cmd(UINT8 cmd_code, tSMP_CB *p_cb);
+static BT_HDR * smp_build_id_addr_cmd(UINT8 cmd_code, tSMP_CB *p_cb);
+
+const tSMP_CMD_ACT smp_cmd_build_act[] =
+{
+ NULL,
+ smp_build_pairing_cmd, /* 0x01: pairing request */
+ smp_build_pairing_cmd, /* 0x02: pairing response */
+ smp_build_confirm_cmd, /* 0x03: pairing confirm */
+ smp_build_rand_cmd, /* 0x04: pairing initializer request */
+ smp_build_pairing_fail, /* 0x05: pairing failure */
+ smp_build_encrypt_info_cmd, /* 0x06: security information command */
+ smp_build_master_id_cmd, /* 0x07: master identity command */
+ smp_build_identity_info_cmd, /* 0x08: identity information command */
+ smp_build_id_addr_cmd, /* 0x09: signing information */
+ smp_build_signing_info_cmd, /* 0x0A: signing information */
+ smp_build_security_request /* 0x0B: security request */
+};
+/*******************************************************************************
+**
+** Function smp_send_msg_to_L2CAP
+**
+** Description Send message to L2CAP.
+**
+*******************************************************************************/
+BOOLEAN smp_send_msg_to_L2CAP(BD_ADDR rem_bda, BT_HDR *p_toL2CAP)
+{
+ UINT16 l2cap_ret;
+
+ SMP_TRACE_EVENT0("smp_send_msg_to_L2CAP");
+
+ if ((l2cap_ret = L2CA_SendFixedChnlData (L2CAP_SMP_CID, rem_bda, p_toL2CAP)) == L2CAP_DW_FAILED)
+ {
+ SMP_TRACE_ERROR1("SMP failed to pass msg:0x%0x to L2CAP",
+ *((UINT8 *)(p_toL2CAP + 1) + p_toL2CAP->offset));
+ GKI_freebuf(p_toL2CAP);
+ return FALSE;
+ }
+ else
+ {
+ return TRUE;
+ }
+}
+/*******************************************************************************
+**
+** Function smp_send_cmd
+**
+** Description send a SMP command on L2CAP channel.
+**
+*******************************************************************************/
+BOOLEAN smp_send_cmd(UINT8 cmd_code, tSMP_CB *p_cb)
+{
+ BT_HDR *p_buf;
+ BOOLEAN sent = FALSE;
+ UINT8 failure = SMP_PAIR_INTERNAL_ERR;
+ SMP_TRACE_EVENT1("smp_send_cmd on l2cap cmd_code=0x%x", cmd_code);
+ if ( cmd_code < SMP_OPCODE_MAX &&
+ smp_cmd_build_act[cmd_code] != NULL)
+ {
+ p_buf = (*smp_cmd_build_act[cmd_code])(cmd_code, p_cb);
+
+ if (p_buf != NULL &&
+ smp_send_msg_to_L2CAP(p_cb->pairing_bda, p_buf))
+ {
+ sent = TRUE;
+
+ btu_stop_timer (&p_cb->rsp_timer_ent);
+ btu_start_timer (&p_cb->rsp_timer_ent, BTU_TTYPE_SMP_PAIRING_CMD,
+ SMP_WAIT_FOR_RSP_TOUT);
+ }
+ }
+
+ if (!sent)
+ {
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure);
+ }
+ return sent;
+}
+
+
+
+/*******************************************************************************
+**
+** Function smp_rsp_timeout
+**
+** Description Called when SMP wait for SMP command response timer expires
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_rsp_timeout(TIMER_LIST_ENT *p_tle)
+{
+ tSMP_CB *p_cb = &smp_cb;
+ UINT8 failure = SMP_RSP_TIMEOUT;
+
+ SMP_TRACE_EVENT1("smp_rsp_timeout state:%d", p_cb->state);
+
+ if (smp_get_state() == SMP_ST_RELEASE_DELAY)
+ {
+ smp_sm_event(p_cb, SMP_RELEASE_DELAY_TOUT_EVT, NULL);
+ }
+ else
+ {
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure);
+ }
+}
+
+/*******************************************************************************
+**
+** Function smp_build_pairing_req_cmd
+**
+** Description Build pairing request command.
+**
+*******************************************************************************/
+BT_HDR * smp_build_pairing_cmd(UINT8 cmd_code, tSMP_CB *p_cb)
+{
+ BT_HDR *p_buf = NULL ;
+ UINT8 *p;
+ SMP_TRACE_EVENT0("smp_build_pairing_cmd");
+ if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + SMP_PAIRING_REQ_SIZE + L2CAP_MIN_OFFSET)) != NULL)
+ {
+ p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ UINT8_TO_STREAM (p, cmd_code);
+ UINT8_TO_STREAM (p, p_cb->loc_io_caps);
+ UINT8_TO_STREAM (p, p_cb->loc_oob_flag);
+ UINT8_TO_STREAM (p, p_cb->loc_auth_req);
+ UINT8_TO_STREAM (p, p_cb->loc_enc_size);
+ UINT8_TO_STREAM (p, p_cb->loc_i_key);
+ UINT8_TO_STREAM (p, p_cb->loc_r_key);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ /* 1B ERR_RSP op code + 1B cmd_op_code + 2B handle + 1B status */
+ p_buf->len = SMP_PAIRING_REQ_SIZE;
+ }
+
+ return p_buf;
+}
+
+/*******************************************************************************
+**
+** Function smp_build_confirm_cmd
+**
+** Description Build confirm request command.
+**
+*******************************************************************************/
+static BT_HDR * smp_build_confirm_cmd(UINT8 cmd_code, tSMP_CB *p_cb)
+{
+ BT_HDR *p_buf = NULL ;
+ UINT8 *p;
+ SMP_TRACE_EVENT0("smp_build_confirm_cmd");
+ if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + SMP_CONFIRM_CMD_SIZE + L2CAP_MIN_OFFSET)) != NULL)
+ {
+ p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ UINT8_TO_STREAM (p, SMP_OPCODE_CONFIRM);
+ ARRAY_TO_STREAM (p, p_cb->confirm, BT_OCTET16_LEN);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = SMP_CONFIRM_CMD_SIZE;
+ }
+
+ return p_buf;
+}
+/*******************************************************************************
+**
+** Function smp_build_rand_cmd
+**
+** Description Build Initializer command.
+**
+*******************************************************************************/
+static BT_HDR * smp_build_rand_cmd(UINT8 cmd_code, tSMP_CB *p_cb)
+{
+ BT_HDR *p_buf = NULL ;
+ UINT8 *p;
+ SMP_TRACE_EVENT0("smp_build_rand_cmd");
+ if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + SMP_INIT_CMD_SIZE + L2CAP_MIN_OFFSET)) != NULL)
+ {
+ p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ UINT8_TO_STREAM (p, SMP_OPCODE_INIT);
+ ARRAY_TO_STREAM (p, p_cb->rand, BT_OCTET16_LEN);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = SMP_INIT_CMD_SIZE;
+ }
+
+ return p_buf;
+}
+/*******************************************************************************
+**
+** Function smp_build_encrypt_info_cmd
+**
+** Description Build security information command.
+**
+*******************************************************************************/
+static BT_HDR * smp_build_encrypt_info_cmd(UINT8 cmd_code, tSMP_CB *p_cb)
+{
+ BT_HDR *p_buf = NULL ;
+ UINT8 *p;
+ SMP_TRACE_EVENT0("smp_build_encrypt_info_cmd");
+ if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + SMP_ENC_INFO_SIZE + L2CAP_MIN_OFFSET)) != NULL)
+ {
+ p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ UINT8_TO_STREAM (p, SMP_OPCODE_ENCRYPT_INFO);
+ ARRAY_TO_STREAM (p, p_cb->ltk, BT_OCTET16_LEN);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = SMP_ENC_INFO_SIZE;
+ }
+
+ return p_buf;
+}
+/*******************************************************************************
+**
+** Function smp_build_master_id_cmd
+**
+** Description Build security information command.
+**
+*******************************************************************************/
+static BT_HDR * smp_build_master_id_cmd(UINT8 cmd_code, tSMP_CB *p_cb)
+{
+ BT_HDR *p_buf = NULL ;
+ UINT8 *p;
+ SMP_TRACE_EVENT0("smp_build_master_id_cmd ");
+ if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + SMP_MASTER_ID_SIZE + L2CAP_MIN_OFFSET)) != NULL)
+ {
+ p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ UINT8_TO_STREAM (p, SMP_OPCODE_MASTER_ID);
+ UINT16_TO_STREAM (p, p_cb->ediv);
+ ARRAY_TO_STREAM (p, p_cb->enc_rand, BT_OCTET8_LEN);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = SMP_MASTER_ID_SIZE;
+ }
+
+ return p_buf;
+}
+/*******************************************************************************
+**
+** Function smp_build_identity_info_cmd
+**
+** Description Build identity information command.
+**
+*******************************************************************************/
+static BT_HDR * smp_build_identity_info_cmd(UINT8 cmd_code, tSMP_CB *p_cb)
+{
+ BT_HDR *p_buf = NULL ;
+ UINT8 *p;
+ BT_OCTET16 irk;
+ SMP_TRACE_EVENT0("smp_build_identity_info_cmd");
+ if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + SMP_ID_INFO_SIZE + L2CAP_MIN_OFFSET)) != NULL)
+ {
+ p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ BTM_GetDeviceIDRoot(irk);
+
+ UINT8_TO_STREAM (p, SMP_OPCODE_IDENTITY_INFO);
+ ARRAY_TO_STREAM (p, irk, BT_OCTET16_LEN);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = SMP_ID_INFO_SIZE;
+ }
+
+ return p_buf;
+}
+/*******************************************************************************
+**
+** Function smp_build_id_addr_cmd
+**
+** Description Build identity address information command.
+**
+*******************************************************************************/
+static BT_HDR * smp_build_id_addr_cmd(UINT8 cmd_code, tSMP_CB *p_cb)
+{
+ BT_HDR *p_buf = NULL ;
+ UINT8 *p;
+ BT_OCTET16 irk;
+ SMP_TRACE_EVENT0("smp_build_id_addr_cmd");
+ if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + SMP_ID_ADDR_SIZE + L2CAP_MIN_OFFSET)) != NULL)
+ {
+ p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ BTM_GetDeviceIDRoot(irk);
+
+ UINT8_TO_STREAM (p, SMP_OPCODE_ID_ADDR);
+ UINT8_TO_STREAM (p, 0); /* TODO: update with local address type */
+ BTM_ReadConnectionAddr(p_cb->local_bda);
+ BDADDR_TO_STREAM (p, p_cb->local_bda);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = SMP_ID_ADDR_SIZE;
+ }
+
+ return p_buf;
+}
+
+/*******************************************************************************
+**
+** Function smp_build_signing_info_cmd
+**
+** Description Build signing information command.
+**
+*******************************************************************************/
+static BT_HDR * smp_build_signing_info_cmd(UINT8 cmd_code, tSMP_CB *p_cb)
+{
+ BT_HDR *p_buf = NULL ;
+ UINT8 *p;
+ //BT_OCTET16 srk; remove
+ SMP_TRACE_EVENT0("smp_build_signing_info_cmd");
+ if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + SMP_SIGN_INFO_SIZE + L2CAP_MIN_OFFSET)) != NULL)
+ {
+ p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ UINT8_TO_STREAM (p, SMP_OPCODE_SIGN_INFO);
+ ARRAY_TO_STREAM (p, p_cb->csrk, BT_OCTET16_LEN);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = SMP_SIGN_INFO_SIZE;
+ }
+
+ return p_buf;
+}
+/*******************************************************************************
+**
+** Function smp_build_pairing_fail
+**
+** Description Build Pairing Fail command.
+**
+*******************************************************************************/
+static BT_HDR * smp_build_pairing_fail(UINT8 cmd_code, tSMP_CB *p_cb)
+{
+ BT_HDR *p_buf = NULL ;
+ UINT8 *p;
+ SMP_TRACE_EVENT0("smp_build_pairing_fail");
+ if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + SMP_PAIR_FAIL_SIZE + L2CAP_MIN_OFFSET)) != NULL)
+ {
+ p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ UINT8_TO_STREAM (p, SMP_OPCODE_PAIRING_FAILED);
+ UINT8_TO_STREAM (p, p_cb->failure);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = SMP_PAIR_FAIL_SIZE;
+ }
+
+ return p_buf;
+}
+/*******************************************************************************
+**
+** Function smp_build_security_request
+**
+** Description Build security request command.
+**
+*******************************************************************************/
+static BT_HDR * smp_build_security_request(UINT8 cmd_code, tSMP_CB *p_cb)
+{
+ BT_HDR *p_buf = NULL ;
+ UINT8 *p;
+ SMP_TRACE_EVENT0("smp_build_security_request");
+
+ if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + 2 + L2CAP_MIN_OFFSET)) != NULL)
+ {
+ p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ UINT8_TO_STREAM (p, SMP_OPCODE_SEC_REQ);
+ UINT8_TO_STREAM (p, p_cb->loc_auth_req);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = 2;
+
+ SMP_TRACE_EVENT2("opcode=%d auth_req=0x%x",SMP_OPCODE_SEC_REQ, p_cb->loc_auth_req );
+ }
+
+ return p_buf;
+
+}
+
+/*******************************************************************************
+**
+** Function smp_convert_string_to_tk
+**
+** Description This function is called to convert a 6 to 16 digits numeric
+** character string into SMP TK.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_convert_string_to_tk(BT_OCTET16 tk, UINT32 passkey)
+{
+ UINT8 *p = tk;
+ tSMP_KEY key;
+ SMP_TRACE_EVENT0("smp_convert_string_to_tk");
+ UINT32_TO_STREAM(p, passkey);
+
+ key.key_type = SMP_KEY_TYPE_TK;
+ key.p_data = tk;
+
+ smp_sm_event(&smp_cb, SMP_KEY_READY_EVT, &key);
+}
+
+/*******************************************************************************
+**
+** Function smp_mask_enc_key
+**
+** Description This function is called to mask off the encryption key based
+** on the maximum encryption key size.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_mask_enc_key(UINT8 loc_enc_size, UINT8 * p_data)
+{
+ SMP_TRACE_EVENT0("smp_mask_enc_key");
+ if (loc_enc_size < BT_OCTET16_LEN)
+ {
+ for (; loc_enc_size < BT_OCTET16_LEN; loc_enc_size ++)
+ * (p_data + loc_enc_size) = 0;
+ }
+ return;
+}
+/*******************************************************************************
+**
+** Function smp_xor_128
+**
+** Description utility function to do an biteise exclusive-OR of two bit
+** strings of the length of BT_OCTET16_LEN.
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_xor_128(BT_OCTET16 a, BT_OCTET16 b)
+{
+ UINT8 i, *aa = a, *bb = b;
+
+ SMP_TRACE_EVENT0("smp_xor_128");
+ for (i = 0; i < BT_OCTET16_LEN; i++)
+ {
+ aa[i] = aa[i] ^ bb[i];
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function smp_cb_cleanup
+**
+** Description Clean up SMP control block
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_cb_cleanup(tSMP_CB *p_cb)
+{
+ tSMP_CALLBACK *p_callback = p_cb->p_callback;
+ UINT8 trace_level = p_cb->trace_level;
+
+ SMP_TRACE_EVENT0("smp_cb_cleanup");
+ memset(p_cb, 0, sizeof(tSMP_CB));
+ p_cb->p_callback = p_callback;
+ p_cb->trace_level = trace_level;
+}
+/*******************************************************************************
+**
+** Function smp_reset_control_value
+**
+** Description This function is called to reset the control block value when
+** pairing procedure finished.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_reset_control_value(tSMP_CB *p_cb)
+{
+ SMP_TRACE_EVENT0("smp_reset_control_value");
+ btu_stop_timer (&p_cb->rsp_timer_ent);
+#if SMP_CONFORMANCE_TESTING == TRUE
+
+ SMP_TRACE_EVENT1("smp_cb.remove_fixed_channel_disable=%d", smp_cb.remove_fixed_channel_disable);
+ if (!smp_cb.remove_fixed_channel_disable)
+ {
+ L2CA_RemoveFixedChnl (L2CAP_SMP_CID, p_cb->pairing_bda);
+ }
+ else
+ {
+ SMP_TRACE_EVENT0("disable the removal of the fixed channel");
+ }
+
+
+#else
+ /* We can tell L2CAP to remove the fixed channel (if it has one) */
+ L2CA_RemoveFixedChnl (L2CAP_SMP_CID, p_cb->pairing_bda);
+
+#endif
+ smp_cb_cleanup(p_cb);
+
+}
+/*******************************************************************************
+**
+** Function smp_proc_pairing_cmpl
+**
+** Description This function is called to process pairing complete
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_proc_pairing_cmpl(tSMP_CB *p_cb)
+{
+ tSMP_EVT_DATA evt_data = {0};
+
+ SMP_TRACE_DEBUG0 ("smp_proc_pairing_cmpl ");
+
+ evt_data.cmplt.reason = p_cb->status;
+
+ if (p_cb->status == SMP_SUCCESS)
+ evt_data.cmplt.sec_level = p_cb->sec_level;
+
+ evt_data.cmplt.is_pair_cancel = FALSE;
+
+ if (p_cb->is_pair_cancel)
+ evt_data.cmplt.is_pair_cancel = TRUE;
+
+
+ SMP_TRACE_DEBUG2 ("send SMP_COMPLT_EVT reason=0x%0x sec_level=0x%0x",
+ evt_data.cmplt.reason,
+ evt_data.cmplt.sec_level );
+ if (p_cb->p_callback)
+ (*p_cb->p_callback) (SMP_COMPLT_EVT, p_cb->pairing_bda, &evt_data);
+
+#if 0 /* TESTING CODE : as a master, reencrypt using LTK */
+ if (evt_data.cmplt.reason == 0 && p_cb->role == HCI_ROLE_MASTER)
+ {
+ btm_ble_start_encrypt(p_cb->pairing_bda, FALSE, NULL);
+ }
+#endif
+
+ smp_reset_control_value(p_cb);
+}
+
+#if SMP_CONFORMANCE_TESTING == TRUE
+/*******************************************************************************
+**
+** Function smp_set_test_confirm_value
+**
+** Description This function is called to set the test confirm value
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_set_test_confirm_value(BOOLEAN enable, UINT8 *p_c_val)
+{
+ SMP_TRACE_DEBUG1("smp_set_test_confirm_value enable=%d", enable);
+ smp_cb.enable_test_confirm_val = enable;
+ memcpy(smp_cb.test_confirm, p_c_val, BT_OCTET16_LEN);
+}
+
+
+/*******************************************************************************
+**
+** Function smp_set_test_confirm_value
+**
+** Description This function is called to set the test rand value
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_set_test_rand_value(BOOLEAN enable, UINT8 *p_c_val)
+{
+ SMP_TRACE_DEBUG1("smp_set_test_rand_value enable=%d", enable);
+ smp_cb.enable_test_rand_val = enable;
+ memcpy(smp_cb.test_rand, p_c_val, BT_OCTET16_LEN);
+}
+
+
+/*******************************************************************************
+**
+** Function smp_set_test_pair_fail_status
+**
+** Description This function is called to set the test fairing fair status
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_set_test_pair_fail_status (BOOLEAN enable, UINT8 status)
+{
+ SMP_TRACE_DEBUG1("smp_set_test_confirm_value enable=%d", enable);
+ smp_cb.enable_test_pair_fail = enable;
+ smp_cb.pair_fail_status = status;
+}
+
+/*******************************************************************************
+**
+** Function smp_set_test_pair_fail_status
+**
+** Description This function is called to disable the removal of fixed channel
+** in smp_reset_control_value
+** Returns void
+**
+*******************************************************************************/
+void smp_remove_fixed_channel_disable (BOOLEAN disable)
+{
+ SMP_TRACE_DEBUG1("smp_remove_fixed_channel_disable disable =%d", disable);
+ smp_cb.remove_fixed_channel_disable = disable;
+}
+
+#endif
+
+
+#endif
+
diff --git a/stack/xml/xml_bld.c b/stack/xml/xml_bld.c
new file mode 100644
index 0000000..57a7347
--- /dev/null
+++ b/stack/xml/xml_bld.c
@@ -0,0 +1,192 @@
+/*****************************************************************************
+**
+** Name: xml_bld_api.c
+**
+** File: Implements the XML Builder
+**
+**
+** Copyright (c) 2000-2004, WIDCOMM Inc., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include <string.h>
+#include <stdio.h>
+
+#include "bt_target.h"
+#include "xml_bld_api.h"
+
+/* The XML Builder is dependent on the Object Store. At present
+** the object store resides in GOEP and hence the builder is
+** dependent on GOEP. The builder only uses the Object Store
+** in GOEP, so if the Object Store is separated from GOEP in the
+** future, the builder will not be dependent on GOEP.
+*/
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+#define XML_ST "<"
+#define XML_EM "/"
+#define XML_SP " "
+#define XML_CO ":"
+#define XML_EQ "="
+#define XML_GT ">"
+#define XML_QT "\""
+
+#define XML_LF "\n" /* Line feed */
+
+/*****************************************************************************
+** Interface functions
+*****************************************************************************/
+
+
+/*****************************************************************************
+**
+** Function: XML_BufAddTag
+**
+** Purpose: Write a start or end tag and optional prefix.
+**
+** Parameters:
+** UINT8 **pp_buf reference to the storage to hold the XML object
+** GOEP_WriteStore.
+** const UINT8* prefix tag prefix (namespace)
+** const UINT8* tag tag name
+** BOOLEAN start_tag TRUE = start tag, FALSE = end tag
+** BOOLEAN has_attr TRUE if the tag contains attributes
+**
+** Returns: XML_BLD_SUCCESS if success
+**
+*****************************************************************************/
+tXML_BLD_RESULT XML_BufAddTag (UINT8 **pp_buf,
+ const UINT8 *prefix,
+ const UINT8 *tag,
+ BOOLEAN start_tag,
+ BOOLEAN has_attr)
+{
+ UINT16 status = XML_BLD_ERROR;
+ int n;
+
+ if (tag != NULL)
+ {
+ if(start_tag)
+ n = sprintf((char *)*pp_buf, XML_ST);
+ else
+ n = sprintf((char *)*pp_buf, XML_ST XML_EM);
+ *pp_buf += n;
+
+ if (prefix != NULL)
+ {
+ n = sprintf((char *)*pp_buf, "%s" XML_CO, prefix );
+ *pp_buf += n;
+ }
+ n = sprintf((char *)*pp_buf, "%s" , tag );
+ *pp_buf += n;
+ if(!has_attr)
+ {
+ n = sprintf((char *)*pp_buf, XML_GT);
+ *pp_buf += n;
+ if (!start_tag)
+ {
+ n = sprintf((char *)*pp_buf, XML_LF);
+ *pp_buf += n;
+ }
+ }
+
+ status = XML_BLD_SUCCESS;
+ }
+ return status;
+}
+
+
+
+/*****************************************************************************
+**
+** Function: XML_BufAddAttribute
+**
+** Purpose: Write an attribute and optional prefix.
+**
+** Parameters:
+** UINT8 **pp_buf reference to the storage to hold the XML object
+** const UINT8* prefix attribute prefix (namespace)
+** const UINT8* attr_name attribute name
+** const UINT8* attr_value attribute value
+**
+** Returns: XML_BLD_SUCCESS if success
+**
+*****************************************************************************/
+tXML_BLD_RESULT XML_BufAddAttribute (UINT8 **pp_buf,
+ const UINT8 *prefix,
+ const UINT8 *attr_name,
+ const UINT8 *attr_value,
+ tXML_ATTR_END last_attr)
+{
+ UINT16 status = XML_BLD_ERROR;
+ int n;
+
+ if (attr_name != NULL && attr_value != NULL)
+ {
+ n = sprintf((char *)*pp_buf, XML_SP);
+ *pp_buf += n;
+ if (prefix != NULL)
+ {
+ n = sprintf((char *)*pp_buf, "%s" XML_CO, prefix );
+ *pp_buf += n;
+ }
+ n = sprintf((char *)*pp_buf, "%s" XML_EQ XML_QT "%s", attr_name, attr_value );
+ *pp_buf += n;
+ switch(last_attr)
+ {
+ case XML_ATTR_CONT:
+ n = sprintf((char *)*pp_buf, XML_QT );
+ break;
+ case XML_ATTR_LAST:
+ n = sprintf((char *)*pp_buf, XML_QT XML_GT XML_LF );
+ break;
+ case XML_ATTR_ETAG:
+ n = sprintf((char *)*pp_buf, XML_QT XML_EM XML_GT XML_LF );
+ break;
+ default:
+ n = 0;
+ break;
+ }
+ *pp_buf += n;
+ status = XML_BLD_SUCCESS;
+ }
+ else if(last_attr == XML_ATTR_ETAG)
+ {
+ /* allow the call to only add the closing attribute */
+ n = sprintf((char *)*pp_buf, XML_EM XML_GT XML_LF );
+ *pp_buf += n ;
+ status = XML_BLD_SUCCESS;
+ }
+ return status;
+}
+
+/*****************************************************************************
+**
+** Function: XML_BufAddCharData
+**
+** Purpose: Write the element content.
+**
+** Parameters:
+** UINT8 **pp_buf reference to the storage to hold the XML object
+** const UINT8* content element content
+**
+** Returns: XML_BLD_SUCCESS if success
+**
+*****************************************************************************/
+tXML_BLD_RESULT XML_BufAddCharData (UINT8 **pp_buf, const UINT8 *charData)
+{
+ UINT16 status = XML_BLD_ERROR;
+ int n;
+
+ if (charData != NULL)
+ {
+ n = sprintf((char *)*pp_buf, "%s", charData);
+ *pp_buf += n;
+ status = XML_BLD_SUCCESS;
+ }
+ return status;
+}
+
diff --git a/stack/xml/xml_erp.c b/stack/xml/xml_erp.c
new file mode 100644
index 0000000..90711e2
--- /dev/null
+++ b/stack/xml/xml_erp.c
@@ -0,0 +1,907 @@
+/******************************************************************************
+ **
+ ** Name: xml_erp.c
+ **
+ ** Description: This module contains xml parser of MAP event report object
+ **
+ ** Copyright (c) 2004-2011, Broadcom Corporation, All Rights Reserved.
+ ** Broadcom Bluetooth Core. Proprietary and confidential.
+ ******************************************************************************/
+
+#include "bt_target.h"
+#include "gki.h"
+#include "xml_erp_api.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+#ifndef EVT_RPT_DEBUG_XML
+#define EVT_RPT_DEBUG_XML TRUE
+#endif
+#define EVT_RPT_DEBUG_LEN 50
+#if (defined(EVT_RPT_DEBUG_XML) && EVT_RPT_DEBUG_XML == TRUE)
+#define XML_TRACE_DEBUG0(m) {BT_TRACE_0(TRACE_LAYER_GOEP, TRACE_TYPE_DEBUG, m);}
+#define XML_TRACE_DEBUG1(m,p1) {BT_TRACE_1(TRACE_LAYER_GOEP, TRACE_TYPE_DEBUG, m,p1);}
+#define XML_TRACE_DEBUG2(m,p1,p2) {BT_TRACE_2(TRACE_LAYER_GOEP, TRACE_TYPE_DEBUG, m,p1,p2);}
+#define XML_TRACE_DEBUG3(m,p1,p2,p3) {BT_TRACE_3(TRACE_LAYER_GOEP, TRACE_TYPE_DEBUG, m,p1,p2,p3);}
+#define XML_TRACE_DEBUG4(m,p1,p2,p3,p4) {BT_TRACE_4(TRACE_LAYER_GOEP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4);}
+#define XML_TRACE_DEBUG5(m,p1,p2,p3,p4,p5) {BT_TRACE_5(TRACE_LAYER_GOEP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5);}
+#define XML_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) {BT_TRACE_6(TRACE_LAYER_GOEP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5,p6);}
+#else
+#define XML_TRACE_DEBUG0(m)
+#define XML_TRACE_DEBUG1(m,p1)
+#define XML_TRACE_DEBUG2(m,p1,p2)
+#define XML_TRACE_DEBUG3(m,p1,p2,p3)
+#define XML_TRACE_DEBUG4(m,p1,p2,p3,p4)
+#define XML_TRACE_DEBUG5(m,p1,p2,p3,p4,p5)
+#define XML_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6)
+#endif
+
+#define XML_PERM_LEN_MAX 4
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+const UINT8 xml_evt_rpt_elem[] = "MAP-event-report";
+const UINT8 xml_evt_rpt_event_elem[] = "event";
+const UINT8 xml_evt_rpt_type_attr[] = "type";
+const UINT8 xml_evt_rpt_handle_attr[] = "handle";
+const UINT8 xml_evt_rpt_folder_attr[] = "folder";
+const UINT8 xml_evt_rpt_old_folder_attr[] = "old_folder";
+const UINT8 xml_evt_rpt_msg_type_attr[] = "msg_type";
+const UINT8 xml_evt_rpt_version_attr[] = "version";
+const UINT8 xml_evt_rpt_unknown[] = "unknown";
+
+#define XML_EVT_RPT_ELEM_ID 0x01
+#define XML_EVT_RPT_EVT_ELEM_ID 0x02
+#define XML_EVT_RPT_MAX_OBJ_TAG_ID XML_EVT_RPT_ELEM_ID
+#define XML_EVT_RPT_TYPE_ATTR_ID 0x03
+#define XML_EVT_RPT_HANDLE_ATTR_ID 0x04
+#define XML_EVT_RPT_FOLDER_ATTR_ID 0x05
+#define XML_EVT_RPT_OLD_FOLDER_ATTR_ID 0x06
+#define XML_EVT_RPT_MSG_TYPE_ATTR_ID 0x07
+#define XML_EVT_RPT_VERSION_ATTR_ID 0x08
+#define XML_EVT_RPT_UNKNOWN_ID 0x09
+#define XML_EVT_RPT_MAX_ID 0x0a /* keep in sync with above */
+#define XML_EVT_RPT_TAG_END_ID 0x0b /* closing tag found end=true */
+#define XML_EVT_RPT_PAUSE_ID 0x0c /* closing tag found end=false */
+
+
+#define XML_EVT_RPT_TTBL_SIZE (XML_EVT_RPT_MAX_ID+1)
+
+/*****************************************************************************
+** Type Definitions
+*****************************************************************************/
+
+typedef struct
+{
+ const UINT8 *p_name;
+ UINT8 len;
+} tXML_EVT_RPT_TTBL_ELEM;
+
+typedef tXML_EVT_RPT_TTBL_ELEM tXML_EVT_RPT_TTBL[]; /* Tag Table */
+
+
+static const tXML_EVT_RPT_TTBL_ELEM xml_erp_ttbl[XML_EVT_RPT_TTBL_SIZE] =
+{ /* index (EVT_RPT_XP_*_ID) & name */
+ {(UINT8*) "", XML_EVT_RPT_MAX_ID-1}, /* \x00 Number of elements in array */
+ /* XML EVT_RPT element (TAG) name */
+ {xml_evt_rpt_elem, 16}, /* x01 MAP-event-report */
+ {xml_evt_rpt_event_elem, 5}, /* 0x02 event */
+ {xml_evt_rpt_type_attr, 4}, /* x03 type */
+ {xml_evt_rpt_handle_attr, 6}, /* x04 handle */
+ {xml_evt_rpt_folder_attr, 6}, /* x05 folder */
+ {xml_evt_rpt_old_folder_attr, 10}, /* x06 old_folder */
+ {xml_evt_rpt_msg_type_attr, 8}, /* x07 msg_type */
+ {xml_evt_rpt_version_attr, 7}, /* x08 version */
+ {xml_evt_rpt_unknown, 7} /* x09 unknown */
+};
+
+#define XML_MAP_EVT_RPT_PTBL_SIZE 0x03
+typedef UINT8 * tXML_MAP_EVT_RPT_PTBL_ELEM;
+
+static const tXML_MAP_EVT_RPT_PTBL_ELEM xml_erp_ptbl[XML_MAP_EVT_RPT_PTBL_SIZE] =
+{
+ (UINT8 *) "\x01", /* index x00, all valide attributes in above list */
+ (UINT8 *) "\x08\x02", /* x01 attributes and sub-tags supported */
+ (UINT8 *) "\x03\x04\x05\x06\x07" /* x02: event report attributes */
+};
+
+
+#if (EVT_RPT_DEBUG_XML == TRUE)
+void xml_erp_debug_str(tXML_STR *p_str, UINT8 *p_buf)
+{
+ int dbg_len;
+ if ( (p_str == NULL) || (NULL==p_str->p))
+ BCM_STRNCPY_S( (char *)p_buf, EVT_RPT_DEBUG_LEN, "(NULL)", EVT_RPT_DEBUG_LEN-1 );
+ else
+ {
+ dbg_len = p_str->len;
+ if ( dbg_len >= EVT_RPT_DEBUG_LEN)
+ dbg_len = EVT_RPT_DEBUG_LEN - 1;
+ BCM_STRNCPY_S( (char *)p_buf, EVT_RPT_DEBUG_LEN, (char *)p_str->p, dbg_len);
+ p_buf[dbg_len] = 0;
+ }
+}
+
+#else
+#define xml_erp_debug_str(p_str, p_buf)
+#endif
+
+/*****************************************************************************
+ ** Function xml_erp_proc_tag
+ ** Description
+ ** Parameters -
+ ** Returns
+ *****************************************************************************/
+static UINT8 xml_erp_proc_tag( tXML_EVT_RPT_STATE *p_st, tXML_STR *p_name, tXML_STACK *p_stk)
+{
+ const UINT8 *p_stag; /* sub tag pointer */
+ UINT8 curr = p_stk->stack[p_stk->top];
+#if (defined(EVT_RPT_DEBUG_XML) && EVT_RPT_DEBUG_XML == TRUE)
+ UINT8 dbg_name[EVT_RPT_DEBUG_LEN];
+#endif
+
+
+ if (curr < XML_MAP_EVT_RPT_PTBL_SIZE)
+ {
+ /* Iterate over allowed sub-tags for the current tag. */
+ for (p_stag = xml_erp_ptbl[curr]; p_stag && *p_stag ; p_stag++)
+ {
+ if (*p_stag >= XML_EVT_RPT_TTBL_SIZE)
+ continue;
+ if (p_name->len == xml_erp_ttbl[*p_stag].len &&
+ strncmp((char *)p_name->p, (char *)xml_erp_ttbl[*p_stag].p_name, p_name->len) == 0)
+ {
+ p_stk->top++;
+ p_stk->stack[p_stk->top] = *p_stag;
+
+ return *p_stag;
+ }
+ }
+ }
+
+#if (defined(EVT_RPT_DEBUG_XML) && EVT_RPT_DEBUG_XML == TRUE)
+ xml_erp_debug_str(p_name, dbg_name);
+ XML_TRACE_DEBUG1("xml_erp_proc_tag: bad name:%s", dbg_name );
+#endif
+
+ return XML_EVT_RPT_UNKNOWN_ID;
+}
+
+
+/*****************************************************************************
+ ** Function xml_erp_proc_attr
+ ** Description
+ ** Parameters -
+ ** Returns
+ *****************************************************************************/
+static UINT8 xml_erp_proc_attr(tXML_EVT_RPT_STATE *p_st, tXML_STR *p_name, tXML_STACK *p_stk)
+{
+ const UINT8 *p_stag; /* sub tag pointer */
+ UINT8 curr = p_stk->stack[p_stk->top];
+#if (EVT_RPT_DEBUG_XML == TRUE)
+ UINT8 dbg_name[EVT_RPT_DEBUG_LEN];
+#endif
+ if (curr < XML_MAP_EVT_RPT_PTBL_SIZE)
+ {
+ /* Iterate over allowed sub-tags for the current tag. */
+ for (p_stag = xml_erp_ptbl[curr]; p_stag && *p_stag; p_stag++)
+ {
+ if (*p_stag >= XML_EVT_RPT_TTBL_SIZE)
+ continue;
+ if (p_name->len == xml_erp_ttbl[*p_stag].len &&
+ strncmp((char *)p_name->p, (char *)xml_erp_ttbl[*p_stag].p_name, p_name->len) == 0)
+ {
+ p_stk->top++;
+ p_stk->stack[p_stk->top] = *p_stag;
+
+ return *p_stag;
+ }
+ }
+ }
+
+#if (defined(EVT_RPT_DEBUG_XML) && EVT_RPT_DEBUG_XML == TRUE)
+ xml_erp_debug_str(p_name, dbg_name);
+ XML_TRACE_DEBUG1("xml_erp_proc_attr: bad name:%s", dbg_name);
+#endif
+ return XML_EVT_RPT_UNKNOWN_ID;
+}
+
+/*****************************************************************************
+ ** Function xml_erp_find_ch_n_copy
+ ** Description copy any chacter till one char in p_str. Any char in p_str
+ ** will stop copy pointed by p_begin
+ ** Parameters
+ ** Returns
+ *****************************************************************************/
+static void xml_erp_find_ch_n_copy( tXML_MCOPY *p_copy )
+{
+ const UINT8 *p_tmp;
+ const UINT8 *p_str = (UINT8 *)">"; /* was: ":=/> \t\n\r". i think we should copy till
+ closing flag */
+ unsigned int last = XML_EVT_RPT_CARRY_OVER_LEN; /* maximum carry over len we can support */
+ UINT8 *p_last = p_copy->last.p + p_copy->last.len - 1; /* point to the last char of carry
+ over buffer */
+ BOOLEAN found = FALSE;
+ /* check if the last char in p_last is in p_str */
+ for (p_tmp = p_str; *p_tmp; p_tmp++)
+ {
+ if (*p_last == *p_tmp)
+ {
+ found = TRUE;
+ break;
+ }
+ } /* for */
+
+ if (found == FALSE)
+ {
+ /* if not in p_str, move chars from p_begin to p_last
+ * until reached last_len or any char in p_str */
+ p_last++;
+ last -= p_copy->last.len; /* calculate the maximum number of chars we can copy */
+ while (*(p_copy->p_begin) && last) /* rl: not sure that this buffer is termninated by a 0 */
+ {
+ /* copy from source (new buffer) to carry over. adjust only carry over ptr. */
+ *p_last++ = *p_copy->p_begin;
+ last--;
+ for (p_tmp = p_str; *p_tmp; p_tmp++)
+ {
+ if (*p_copy->p_begin == *p_tmp)
+ {
+ p_copy->p_begin++; /* adjust pointer to point to next char to read */
+ /* calculate new length of carry over buffer contents */
+ p_copy->last.len = XML_EVT_RPT_CARRY_OVER_LEN-last;
+ *p_last = 0; /* NULL terminate p_last. rl: not really neccessary. */
+ return;
+ }
+ } /* for */
+ p_copy->p_begin++; /* update now to next char. this way abort char is also copied */
+ } /* while */
+ } /* !found */
+}
+
+/*****************************************************************************
+** Function xml_evt_rpt_cback
+** Description
+**
+** Parameters
+** Returns
+*****************************************************************************/
+static BOOLEAN xml_evt_rpt_cback( tXML_EVENT event, void *p_event_data, void *p_usr_data)
+{
+ tXML_MEVT_DATA *p_ed = (tXML_MEVT_DATA*) p_event_data;
+ tXML_EVT_RPT_STATE *p_st = (tXML_EVT_RPT_STATE *) p_usr_data;
+ tXML_PROP *p_cp = &p_st->p_prop[p_st->prop_index];
+ BOOLEAN ret = TRUE;
+ UINT8 next; /* next element */
+ UINT8 curr = p_ed->stack.stack[p_ed->stack.top]; /* current element */
+#if (EVT_RPT_DEBUG_XML == TRUE)
+ UINT8 dbg_name[EVT_RPT_DEBUG_LEN];
+ UINT8 dbg_prefix[EVT_RPT_DEBUG_LEN];
+ UINT8 dbg_value[EVT_RPT_DEBUG_LEN];
+#endif
+
+#if (EVT_RPT_DEBUG_XML == TRUE)
+ XML_TRACE_DEBUG1("xml_evt_rpt_cback:%d", event);
+#endif
+
+ switch (event)
+ {
+ case XML_TAG : /* <tag-name */
+ next = xml_erp_proc_tag(p_st, &p_ed->tag.name, &p_ed->stack);
+#if (EVT_RPT_DEBUG_XML == TRUE)
+ xml_erp_debug_str(&p_ed->tag.name, dbg_name);
+ xml_erp_debug_str(&p_ed->tag.prefix, dbg_prefix);
+ XML_TRACE_DEBUG2("XML_TAG: p:%s, name:%s", dbg_prefix, dbg_name);
+ XML_TRACE_DEBUG2("top:x%x, stk:x%x", p_ed->stack.top, p_ed->stack.stack[p_ed->stack.top]);
+
+#endif
+ if (next != 0)
+ {
+ if (next <= XML_EVT_RPT_MAX_OBJ_TAG_ID)
+ p_st->obj = next;
+
+ if (p_st->prop_index <p_st->max_num_prop)
+ {
+ /* we do not use prefix in FTC */
+ p_cp->name = next;
+ p_cp->p_data = NULL;
+ p_cp->len = 0;
+ p_cp->level = p_ed->stack.top;
+ p_st->prop_index++;
+ }
+ else
+ ret = FALSE;
+ }
+ break;
+
+ case XML_ATTRIBUTE : /* attr-name="attr-value" */
+ curr = xml_erp_proc_attr(p_st, &p_ed->attr.name, &p_ed->stack);
+#if (defined(EVT_RPT_DEBUG_XML) && EVT_RPT_DEBUG_XML == TRUE)
+ xml_erp_debug_str(&p_ed->attr.name, dbg_name);
+ xml_erp_debug_str(&p_ed->attr.prefix, dbg_prefix);
+ xml_erp_debug_str(&p_ed->attr.value, dbg_value);
+ XML_TRACE_DEBUG4("[xml evt_rpt] XML_ATTRIBUTE: p:%s, name:%s, v:%s, curr:%x",
+ dbg_prefix, dbg_name, dbg_value, curr );
+ XML_TRACE_DEBUG2("top 1:x%x, stk:x%x", p_ed->stack.top, p_ed->stack.stack[p_ed->stack.top]);
+#endif
+ if ((curr != 0) && (curr != XML_EVT_RPT_UNKNOWN_ID))
+ {
+ if (p_st->prop_index <p_st->max_num_prop)
+ {
+ p_cp->name = curr;
+ p_cp->p_data = p_ed->attr.value.p;
+ p_cp->len = p_ed->attr.value.len;
+ p_cp->level = p_ed->stack.top;
+ p_st->prop_index++;
+ }
+ else
+ ret = FALSE;
+ p_ed->stack.top--;
+ XML_TRACE_DEBUG2("top 2:x%x, stk:x%x", p_ed->stack.top, p_ed->stack.stack[p_ed->stack.top]);
+ }
+ break;
+
+ case XML_CHARDATA :
+#if (defined(EVT_RPT_DEBUG_XML) && EVT_RPT_DEBUG_XML == TRUE)
+ xml_erp_debug_str(&p_ed->ch_data.value, dbg_value);
+ XML_TRACE_DEBUG2("XML_CHARDATA: v:%s, last:%d", dbg_value, p_ed->ch_data.last);
+#endif
+ break;
+
+ case XML_ETAG : /* </tag-name> */
+ if (p_ed->stack.top > 0)
+ {
+ p_ed->stack.stack[p_ed->stack.top] = 0;
+ p_ed->stack.top--;
+ p_st->ended = (BOOLEAN) (p_ed->stack.top == 0);
+ }
+#if (defined(EVT_RPT_DEBUG_XML) && EVT_RPT_DEBUG_XML == TRUE)
+ xml_erp_debug_str(&p_ed->etag.name, dbg_name);
+ xml_erp_debug_str(&p_ed->etag.prefix, dbg_prefix);
+ XML_TRACE_DEBUG2("[xml evt_rpt] XML_ETAG: p:%s, name:%s", dbg_prefix, dbg_name);
+ XML_TRACE_DEBUG2("[xml evt_rpt] top:x%x, stk:x%x", p_ed->stack.top, p_ed->stack.stack[p_ed->stack.top]);
+#endif
+ break;
+
+ case XML_TAG_END: /* /> */
+ curr = p_ed->stack.stack[p_ed->stack.top];
+
+ if (p_st->prop_index <p_st->max_num_prop)
+ {
+ if (p_ed->empty_elem.end)
+ p_cp->name = XML_EVT_RPT_TAG_END_ID;
+ else
+ p_cp->name = XML_EVT_RPT_PAUSE_ID;
+ p_cp->p_data = NULL;
+ p_cp->len = 0;
+ p_cp->level = p_ed->stack.top;
+ p_st->prop_index++;
+ if (p_ed->empty_elem.end && p_ed->stack.top > 0)
+ {
+ p_ed->stack.top--;
+ }
+ }
+ else
+ ret = FALSE;
+
+#if (defined(EVT_RPT_DEBUG_XML) && EVT_RPT_DEBUG_XML == TRUE)
+ XML_TRACE_DEBUG4("[xml evt_rpt] XML_TAG_END: %d, top:x%x, stk:x%x, curr:x%x",
+ p_ed->empty_elem.end, p_ed->stack.top, p_ed->stack.stack[p_ed->stack.top], curr);
+#endif
+ break;
+
+ case XML_PARTIAL:
+ if (p_st->p_prop[p_st->prop_index-1].name != XML_EVT_RPT_TAG_END_ID)
+ {
+ p_ed->stack.top--;
+#if (defined(EVT_RPT_DEBUG_XML) && EVT_RPT_DEBUG_XML == TRUE)
+ XML_TRACE_DEBUG0("[xml evt_rpt] adjust due to XML_PARTIAL");
+#endif
+ }
+ break;
+
+ case XML_COPY:
+ xml_erp_find_ch_n_copy( &p_ed->copy );
+ XML_TRACE_DEBUG1("[xml evt_rpt] XML_COPY: %s", p_ed->copy.last.p);
+ break;
+
+ default :
+#if (defined(EVT_RPT_DEBUG_XML) && EVT_RPT_DEBUG_XML == TRUE)
+ XML_TRACE_DEBUG1("[xml evt_rpt] default: XML event: %d", event);
+#endif
+ break;
+ }
+
+ return ret;
+}
+
+
+
+
+/**********************************************************************************
+** Function xml_erp_int_fill_file_folder
+** Description fill in file/folder structure.
+**
+** Parameters
+** Returns xx: > 0 : number of properties scanned, folder entry is added
+** = 0 : no end tag found, carry over to next parse
+** = -1: no dst_resource avaibale, all prop left to next parse
+** = -2: exceed max entry, no folder entry added
+**********************************************************************************/
+static INT16 xml_erp_int_fill_evt_rpt( tXML_EVT_RPT_STATE * p_xud,
+ tXML_PROP *p_prop,
+ UINT16 *num_prop,
+ UINT8 **p_dst_data,
+ UINT16 *dst_len)
+{
+ INT16 xx;
+ UINT16 len;
+ BOOLEAN end = FALSE;
+ tXML_PROP *cur_prop = p_prop;
+ UINT8 *p_cur_offset = *p_dst_data;
+ BOOLEAN copy_attr_info;
+ BOOLEAN no_buf_left;
+ UINT8 **p_attr_data = NULL;
+ UINT16 *p_attr_len = NULL;
+
+ if ( p_xud->current_entry >= p_xud->max_entry )
+ return -2;
+
+ for (xx=0; (xx < *num_prop) && !end; xx++, cur_prop++)
+ {
+#if (defined(EVT_RPT_DEBUG_XML) && EVT_RPT_DEBUG_XML == TRUE)
+ /* XML_TRACE_DEBUG5( "[xml evt_rpt] fill: num_prop:%d, name id: x%x, p_prop: x%x, len: %d p_data:%s",
+ (*num_prop-xx) , cur_prop->name, cur_prop, cur_prop->len, cur_prop->p_data, ); */
+#endif
+ copy_attr_info = TRUE;
+ no_buf_left = FALSE;
+ len = cur_prop->len;
+
+ switch (cur_prop->name)
+ {
+ case XML_EVT_RPT_TYPE_ATTR_ID:
+ if ((*dst_len - len) > 0) /* enough data buffer available? */
+ {
+ p_attr_data = &(p_xud->p_entry[p_xud->current_entry].type) ;
+ p_attr_len = &(p_xud->p_entry[p_xud->current_entry].type_len);
+ }
+ else /* run out of dst buffer resource */
+ no_buf_left = TRUE;
+ break;
+
+ case XML_EVT_RPT_HANDLE_ATTR_ID:
+ if ((*dst_len - len) > 0) /* enough data buffer available? */
+ {
+ p_attr_data = &(p_xud->p_entry[p_xud->current_entry].handle) ;
+ p_attr_len = &(p_xud->p_entry[p_xud->current_entry].handle_len);
+ }
+ else /* run out of dst buffer resource */
+ no_buf_left = TRUE;
+ break;
+ case XML_EVT_RPT_FOLDER_ATTR_ID:
+ if ((*dst_len - len) > 0) /* enough data buffer available? */
+ {
+ p_attr_data = &(p_xud->p_entry[p_xud->current_entry].folder) ;
+ p_attr_len = &(p_xud->p_entry[p_xud->current_entry].folder_len);
+ }
+ else /* run out of dst buffer resource */
+ no_buf_left = TRUE;
+ break;
+ case XML_EVT_RPT_OLD_FOLDER_ATTR_ID:
+ if ((*dst_len - len) > 0) /* enough data buffer available? */
+ {
+ p_attr_data = &(p_xud->p_entry[p_xud->current_entry].old_folder) ;
+ p_attr_len = &(p_xud->p_entry[p_xud->current_entry].old_folder_len);
+ }
+ else /* run out of dst buffer resource */
+ no_buf_left = TRUE;
+ break;
+ case XML_EVT_RPT_MSG_TYPE_ATTR_ID:
+ if ((*dst_len - len) > 0) /* enough data buffer available? */
+ {
+
+ p_attr_data = &(p_xud->p_entry[p_xud->current_entry].msg_type) ;
+ p_attr_len = &(p_xud->p_entry[p_xud->current_entry].msg_type_len);
+ }
+ else /* run out of dst buffer resource */
+ no_buf_left = TRUE;
+ break;
+ case XML_EVT_RPT_TAG_END_ID:
+ /* -------------------- CUSTOMER SPECIFIC ---------------------- */
+ p_xud->current_entry++; /* increment only when end tag (/>) found */
+ copy_attr_info = FALSE;
+ XML_TRACE_DEBUG1("[xml ml]: current_entry=%d",p_xud->current_entry);
+ break;
+ /* case XML_VERSION_ATTR_ID: */
+ default:
+ copy_attr_info = FALSE;
+ XML_TRACE_DEBUG1("[xml evt_rpt] unknown attrib: %d", cur_prop->name );
+ break;
+ }
+
+ if (copy_attr_info && p_attr_data && p_attr_len)
+ {
+ *p_attr_data = p_cur_offset;
+ *p_attr_len = len;
+
+ memcpy( (void *)*p_attr_data,
+ (const void *)cur_prop->p_data,
+ len );
+ (*p_attr_data)[len] = 0; /* null terminate string */
+ p_cur_offset += (len + 1);
+ *dst_len = *dst_len - (len + 1) ;
+
+ #if (defined(EVT_RPT_DEBUG_XML) && EVT_RPT_DEBUG_XML == TRUE)
+
+ XML_TRACE_DEBUG5("[xml evt_rpt]: Attr ID=%d val=[%s] len=%d level=%d dst_len lef=%d",
+ cur_prop->name,
+ *p_attr_data,
+ *p_attr_len,
+ cur_prop->level,
+ *dst_len);
+ #endif
+ }
+
+ if (no_buf_left)
+ {
+ return -1;
+ }
+
+ }
+#if (EVT_RPT_DEBUG_XML == TRUE)
+ XML_TRACE_DEBUG2("[xml evt_rpt] fill_evt_rpt: end:%d, xx:%d", end, xx);
+#endif
+#if 0
+ /* if end tag not found -> split over two buffers. but parser will still show rest of
+ found properties. so return still found properties. */
+ if (end == FALSE)
+ xx = 0;
+#endif
+
+ /* keep track of current data buffer offset */
+ *p_dst_data = p_cur_offset;
+ return xx;
+} /* xml_erp_int_fill_file_evt_rpt() */
+
+
+/**********************************************************************************
+** Function xml_erp_int_fill_evt_data
+**
+** Description fill in MAP event report structure.
+**
+** Parameters
+** Returns
+**********************************************************************************/
+static tXML_EVT_RPT_RES xml_erp_int_fill_evt_data( UINT8 op,
+ void *p_evt_data,
+ tXML_PROP **p_prop,
+ UINT16 *num_prop,
+ UINT8 **p_dst_data,
+ UINT16 *dst_len)
+{
+ tXML_EVT_RPT_STATE *p_xud = (tXML_EVT_RPT_STATE *)p_evt_data;
+ INT16 inc_prop;
+ UINT8 prop_name; /* Property name. */
+ tXML_PROP *cur_prop = *p_prop;
+ UINT8 *p_cur_offset = *p_dst_data;
+
+ tXML_EVT_RPT_RES x_res = XML_EVT_RPT_OK;
+ BOOLEAN x_no_res = FALSE; /* guard dest buffer resource */
+
+ if ( op == 0 || op > XML_EVT_RPT_MAX_OBJ_TAG_ID || *num_prop == 0)
+ return XML_EVT_RPT_ERROR;
+
+#if EVT_RPT_DEBUG_XML
+ XML_TRACE_DEBUG2( "[xml evt_rpt] xml_erp_int_fill_evt_data op:%d, num_prop:%d",
+ op, *num_prop);
+#endif
+
+
+
+ while ( *num_prop > 0 && !x_no_res )
+ {
+#if (defined(EVT_RPT_DEBUG_XML) && EVT_RPT_DEBUG_XML == TRUE)
+ XML_TRACE_DEBUG2("end_prop:%d, name id: x%x", *num_prop, cur_prop->name);
+#endif
+ prop_name = cur_prop->name;
+ cur_prop++;
+ *num_prop -= 1;
+
+
+ switch ( prop_name )
+ {
+ case XML_EVT_RPT_ELEM_ID:
+ XML_TRACE_DEBUG0("[xml evt_rpt] xml_etag_elem");
+ /* skip over version attribute which should always be 1.0. this is the top level */
+ break;
+
+ case XML_EVT_RPT_EVT_ELEM_ID:
+ XML_TRACE_DEBUG0("[xml evt_rpt] xml_etag_elem");
+ inc_prop = xml_erp_int_fill_evt_rpt( p_xud,
+ cur_prop,
+ num_prop,
+ &p_cur_offset,
+ dst_len);
+ if (inc_prop == -1) /* no dst_buf available */
+ {
+ /* backup one more prop to obtain the skipped evt_rpt/file entry header */
+ cur_prop --;
+ *num_prop += 1;
+
+ x_res = XML_EVT_RPT_DST_NO_RES;
+ x_no_res = TRUE;
+ }
+ else if (inc_prop == -2) /* exceed max entry */
+ {
+ x_no_res = TRUE;
+ x_res = XML_EVT_RPT_OUT_FULL;
+ }
+ else /* found evt_rpt entry */
+ {
+ cur_prop += inc_prop;
+ *num_prop -= inc_prop;
+ }
+ break;
+
+ case XML_EVT_RPT_PAUSE_ID:
+ XML_TRACE_DEBUG0("[xml evt_rpt] xml_etag_elem");
+
+#if (EVT_RPT_DEBUG_XML==TRUE)
+ XML_TRACE_DEBUG0( "[xml evt_rpt] xml_erp_int_fill_evt_data(): XML_EVT_RPT_PAUSE_ID" );
+#endif
+ break;
+
+ case XML_EVT_RPT_TAG_END_ID:
+ XML_TRACE_DEBUG0("[xml evt_rpt] xml_etag_elem");
+#if (EVT_RPT_DEBUG_XML==TRUE)
+ XML_TRACE_DEBUG0( "[xml evt_rpt] xml_erp_int_fill_evt_data(): XML_EVT_RPT_TAG_END_ID" );
+#endif
+ break;
+
+ default:
+ XML_TRACE_DEBUG1( "[xml evt_rpt] xml_erp_int_fill_evt_data():unknown element: %d", prop_name );
+ break;
+ }
+ }
+
+ /* keep track of current filling position, and current available dst buffer */
+ *p_prop = cur_prop;
+ *p_dst_data = p_cur_offset;
+
+ return x_res;
+} /* xml_erp_int_fill_evt_data() */
+
+
+/**************************************************************************************
+** Function XML_EvtRptInit
+**
+** Description Initialize xml parser state machine.
+**
+** Parameters p_xml_state: address of an xml parser state machine to be initialized,
+** allocate an additional space of size XML_EVT_RPT_CARRY_OVER_LEN
+** right after *p_xml_state to hold carry over data.
+** p_entry : points start of output directory entry. caller needs do
+** free this memory
+** max_entry : max is 16 bit integer value which is the maximum number
+** of evt_rpt entries.
+
+**
+** Returns void
+**************************************************************************************/
+
+void XML_EvtRptInit( tXML_EVT_RPT_PARSER *p_xml_state,
+ tXML_EVT_RPT_ENTRY *p_entry,
+ const UINT16 max_entry )
+{
+ XML_TRACE_DEBUG0("[xml evt_rpt] XML_EvtRptInit");
+ /* Initialize the generic xml parser state machine.*/
+ XML_InitPars( &p_xml_state->xml, xml_evt_rpt_cback, &p_xml_state->xml_user_data );
+
+ /* User need to allocate an additional space of size XML_EVT_RPT_CARRY_OVER_LEN */
+ /* right after *p_xml_state to hold carry over data. */
+ /* point to the end of the allocated buffer for p_xml_state, which is the */
+ /* beginning of buffer(XML_EVT_RPT_CARRY_OVER_LEN) */
+ p_xml_state->xml.last_bfr.p = (UINT8 *)(p_xml_state + 1);
+ p_xml_state->xml.last_bfr.len = XML_EVT_RPT_CARRY_OVER_LEN;
+
+ /* Initialize user data */
+ p_xml_state->xml_user_data.p_entry = p_entry;
+ p_xml_state->xml_user_data.current_entry = 0;
+ p_xml_state->xml_user_data.max_name_len = XML_UI_ENTRY_MAX_NAME_LEN + 1;
+ p_xml_state->xml_user_data.max_entry = (UINT16)max_entry;
+ p_xml_state->xml_user_data.prop_num = 0;
+}
+
+
+/**************************************************************************************
+** Function XML_EvtRptParse
+**
+** Description This function is called to parse the xml data received from OBEX
+** into folder entries associated with properties value. It can also be
+** used as clean up function to delete left over data from previous parse.
+** This clean up function is typically used when application runs out of
+** resource and decides to discard extra xml data received.
+**
+** Parameters p_xml_state: pointer to a xml parser initialized by XML_EvtRptInit().
+** xml_data: valid pointer to OBEX list data in xml format.
+** xml_len: length of the package, must be non-zero value.
+** dst_data: valid pointer to the buffer for holding converted folder entry name.
+ When dst_data is NULL, clean up all remaining data in the parser.
+** dst_len: pointer to the length of dst_data buffer, its carry out value
+** is the number of bytes remaining buffer.When dst_len is NULL,
+** it will cause to flush the internal data in the parser.
+** num_entries: current number of entries, in the end it is the total number of entries
+**
+** Returns tXML_EVT_RPT_RES (see xml_erp.h)
+** XML_PENDING: parsing not completed
+** XML_END_LIST: found /folder-listing but no final flag detected
+** XML_EVT_RPT_OUT_FULL: reached max_entry -> do not call parser anymore!!! dump data
+** XML_EVT_RPT_DST_NO_RES : run out of dst buffer resource while
+** some xml data still remains.
+
+**************************************************************************************/
+tXML_EVT_RPT_RES XML_EvtRptParse( tXML_EVT_RPT_PARSER *p_xml_state,
+ UINT8 *xml_data, UINT16 xml_len,
+ UINT8 *dst_data, UINT16 *dst_len,
+ UINT16 *num_entries )
+{
+ tXML_OS xos;
+ BOOLEAN is_remain = TRUE;
+ tXML_MUL_STATE *p_xml = &p_xml_state->xml;
+ tXML_EVT_RPT_STATE *p_st = &p_xml_state->xml_user_data;
+ tXML_EVT_RPT_RES x_res = XML_EVT_RPT_OK;
+ tXML_RESULT res = XML_NO_PROP;
+ UINT16 max_num_prop = GKI_BUF3_SIZE/sizeof(tXML_PROP); /* i hope this is sufficient for 1 */
+
+
+#if (defined(EVT_RPT_DEBUG_XML) && EVT_RPT_DEBUG_XML == TRUE)
+ int xx;
+ UINT8 dbg_buf[EVT_RPT_DEBUG_LEN];
+ tXML_STR str;
+#endif
+
+ XML_TRACE_DEBUG0("[xml evt_rpt] XML_EvtRptParse");
+ /* if dst_data is NULL, clean up remaining data */
+ if (!dst_data || !dst_len)
+ {
+ /* clean out remained xml data left over from last parse */
+ if (p_xml_state->xml_user_data.p_prop )
+ {
+ GKI_freebuf( p_st->p_prop );
+ p_st->p_prop = p_st->offset_prop = NULL;
+ p_st->prop_num = 0;
+ }
+#if (EVT_RPT_DEBUG_XML == TRUE)
+ XML_TRACE_DEBUG0( "[xml evt_rpt] XML_EvtRptParse() Clean up left over!");
+#endif
+ return x_res;
+ }
+
+ /* if illegal OBEX data or dst buffer pointer received, return ERROR */
+ if (xml_len == 0 || !xml_data)
+ {
+ return XML_EVT_RPT_ERROR;
+ }
+
+ /* XML_EvtRptParse receive new xml data, allocate buffer to hold parsed prop */
+ if (p_st->offset_prop == NULL)
+ {
+
+#if (EVT_RPT_DEBUG_XML == TRUE)
+ XML_TRACE_DEBUG0( "[xml evt_rpt] XML_EvtRptParse() Receive New Data!");
+ XML_TRACE_DEBUG2( "[xml evt_rpt] XML_data start[%x] end [%x]",xml_data, xml_data+xml_len);
+#endif
+ is_remain = FALSE;
+ if ( NULL!= (p_st->p_prop = (tXML_PROP *)GKI_getbuf( GKI_BUF3_SIZE ) ) )
+ {
+ /* pointing next prop to be converted into file entry */
+ p_st->prop_num = 0;
+ }
+ else
+ {
+ GKI_freebuf( p_xml_state );
+ x_res = XML_EVT_RPT_NO_RES;
+ return x_res;
+ }
+ }
+#if (EVT_RPT_DEBUG_XML == TRUE)
+ else
+ {
+ XML_TRACE_DEBUG0( "[xml evt_rpt] XML_EvtRptParse(): Keep cleaning up old xml data !");
+ }
+#endif
+ /* update the data address */
+ xos.p_begin = xml_data;
+ xos.p_end = xml_data + xml_len;
+
+ while ( res == XML_NO_PROP )
+ {
+ /* if no remaining data in p_st->p_prop, parse new xml data */
+ if (!is_remain)
+ {
+ p_st->max_num_prop = max_num_prop;
+ p_st->prop_index = 0;
+ res = XML_MulParse( p_xml, &xos );
+
+
+#if (EVT_RPT_DEBUG_XML == TRUE)
+ XML_TRACE_DEBUG4( "xml_evt_rpt_parse obj: %x, max: %d, num: %d, res: %d",
+ p_st->obj, max_num_prop, p_st->prop_index, res);
+
+ if (res != 0)
+ {
+ XML_TRACE_DEBUG1( "XML_MulParse Parsing: %d !!!", res);
+ }
+
+ for (xx=0; xx<p_st->prop_index; xx++)
+ {
+ if ( p_st->p_prop[xx].name < XML_EVT_RPT_MAX_ID )
+ {
+ str.p = p_st->p_prop[xx].p_data;
+ str.len = p_st->p_prop[xx].len;
+ xml_erp_debug_str(&str, dbg_buf);
+ XML_TRACE_DEBUG5( "[xml evt_rpt] parsed: index[%d]:%d:%s: %s(%d)", p_st->prop_index-xx, p_st->p_prop[xx].level,
+ xml_erp_ttbl[p_st->p_prop[xx].name].p_name, dbg_buf, p_st->p_prop[xx].len);
+ }
+ else
+ {
+ XML_TRACE_DEBUG3( "[xml evt_rpt] internal prop: %d:%d:%d", xx, p_st->p_prop[xx].level,
+ p_st->p_prop[xx].name );
+ }
+ }
+#endif
+ p_st->prop_num = p_st->prop_index ;
+ p_st->offset_prop = p_st->p_prop;
+ }
+ else
+ {
+ /* This is left over data, pick up the result from the previous parse */
+ res = p_xml->pars_res;
+ }
+
+ if ( res != XML_OBJ_ST_EMPTY )
+ {
+ x_res = xml_erp_int_fill_evt_data( p_st->obj, p_st, &p_st->offset_prop, &p_st->prop_num, &dst_data, dst_len );
+
+ if ( (XML_EVT_RPT_OK == x_res) && (XML_NO_END == res) )
+ {
+ /* XML_NO_END means that the xml is not completly finished and fill returns
+ ok when when partial filling has been ok */
+ x_res = XML_EVT_RPT_PENDING;
+ }
+
+ /* all parsed xml data has been converted into file entry */
+ /* or exceed max entry number , break the parsing loop */
+ if (XML_EVT_RPT_OUT_FULL != x_res && XML_EVT_RPT_DST_NO_RES != x_res)
+ {
+ is_remain = FALSE;
+ }
+ else
+ break;
+ }
+ } /* while */
+
+ /* free property table. at next call a new one is allocated */
+ if ((x_res != XML_EVT_RPT_DST_NO_RES && p_st->p_prop) ||
+ XML_EVT_RPT_OUT_FULL == x_res)
+ {
+ GKI_freebuf( p_st->p_prop );
+ p_st->p_prop = NULL;
+ p_st->offset_prop = NULL;
+ }
+
+ if ( x_res != XML_EVT_RPT_DST_NO_RES && p_st->ended)
+ {
+ /* this should happen on the same time as final flag in fact */
+ x_res = XML_EVT_RPT_END_LIST; /* found closing /evt_rpt-listing */
+ }
+
+
+ *num_entries = p_st->current_entry; /* report number of entries found. only when ended is true
+ application really should be interested! */
+ return x_res;
+}
+
diff --git a/stack/xml/xml_flp.c b/stack/xml/xml_flp.c
new file mode 100644
index 0000000..688f1b5
--- /dev/null
+++ b/stack/xml/xml_flp.c
@@ -0,0 +1,971 @@
+/******************************************************************************
+ **
+ ** Name: xml_flp.c
+ **
+ ** Description: This module contains xml parser of obex folder listing
+ **
+ ** Copyright (c) 2004-2011, Broadcom Corporation, All Rights Reserved.
+ ** Broadcom Bluetooth Core. Proprietary and confidential.
+ ******************************************************************************/
+
+#include "bt_target.h"
+#include "gki.h"
+#include "xml_flp_api.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+#ifndef FOLDER_DEBUG_XML
+#define FOLDER_DEBUG_XML FALSE
+#endif
+#define FOLDER_DEBUG_LEN 50
+#if (defined(FOLDER_DEBUG_XML) && FOLDER_DEBUG_XML == TRUE)
+#define XML_TRACE_DEBUG0(m) {BT_TRACE_0(TRACE_LAYER_FTP, TRACE_TYPE_DEBUG, m);}
+#define XML_TRACE_DEBUG1(m,p1) {BT_TRACE_1(TRACE_LAYER_FTP, TRACE_TYPE_DEBUG, m,p1);}
+#define XML_TRACE_DEBUG2(m,p1,p2) {BT_TRACE_2(TRACE_LAYER_FTP, TRACE_TYPE_DEBUG, m,p1,p2);}
+#define XML_TRACE_DEBUG3(m,p1,p2,p3) {BT_TRACE_3(TRACE_LAYER_FTP, TRACE_TYPE_DEBUG, m,p1,p2,p3);}
+#define XML_TRACE_DEBUG4(m,p1,p2,p3,p4) {BT_TRACE_4(TRACE_LAYER_FTP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4);}
+#define XML_TRACE_DEBUG5(m,p1,p2,p3,p4,p5) {BT_TRACE_5(TRACE_LAYER_FTP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5);}
+#define XML_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) {BT_TRACE_6(TRACE_LAYER_FTP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5,p6);}
+#else
+#define XML_TRACE_DEBUG0(m)
+#define XML_TRACE_DEBUG1(m,p1)
+#define XML_TRACE_DEBUG2(m,p1,p2)
+#define XML_TRACE_DEBUG3(m,p1,p2,p3)
+#define XML_TRACE_DEBUG4(m,p1,p2,p3,p4)
+#define XML_TRACE_DEBUG5(m,p1,p2,p3,p4,p5)
+#define XML_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6)
+#endif
+
+#define XML_PERM_LEN_MAX 4
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+const UINT8 xml_folder_listing_elem[] = "folder-listing";
+const UINT8 xml_file_elem[] = "file";
+const UINT8 xml_folder_elem[] = "folder";
+const UINT8 xml_parent_folder_elem[] = "parent-folder";
+const UINT8 xml_name_attr[] = "name";
+const UINT8 xml_size_attr[] = "size";
+const UINT8 xml_type_attr[] = "type";
+const UINT8 xml_modified_attr[] = "modified";
+const UINT8 xml_created_attr[] = "created";
+const UINT8 xml_accessed_attr[] = "accessed";
+const UINT8 xml_user_perm_attr[] = "user-perm";
+const UINT8 xml_group_perm_attr[] = "group-perm";
+const UINT8 xml_other_perm_attr[] = "other-perm";
+const UINT8 xml_group_attr[] = "group";
+const UINT8 xml_owner_attr[] = "owner";
+const UINT8 xml_version_attr[] = "version";
+const UINT8 xml_lang_attr[] = "xml:lang";
+const UINT8 xml_unknown[] = "unknown";
+
+#define XML_FOLDER_LISTING_ELEM_ID 0x01
+#define XML_FILE_ELEM_ID 0x02
+#define XML_FOLDER_ELEM_ID 0x03
+#define XML_PARENT_FOLDER_ELEM_ID 0x04
+#define XML_MAX_OBJ_TAG_ID XML_FOLDER_LISTING_ELEM_ID
+#define XML_NAME_ATTR_ID 0x05
+#define XML_SIZE_ATTR_ID 0x06
+#define XML_TYPE_ATTR_ID 0x07
+#define XML_MODIFIED_ATTR_ID 0x08
+#define XML_CREATED_ATTR_ID 0x09
+#define XML_ACCESSED_ATTR_ID 0x0a
+#define XML_USER_PERM_ATTR_ID 0x0b
+#define XML_GROUP_PERM_ATTR_ID 0x0c
+#define XML_OTHER_PERM_ATTR_ID 0x0d
+#define XML_GROUP_ATTR_ID 0x0e
+#define XML_OWNER_ATTR_ID 0x0f
+#define XML_VERSION_ATTR_ID 0x10
+#define XML_LANG_ATTR_ID 0x11
+#define XML_XP_UNKNOWN_ID 0x12
+#define XML_FOLDER_MAX_ID 0x13 /* keep in sync with above */
+#define XML_FOLDER_TAG_END_ID 0x13 /* closing tag found end=true */
+#define XML_FOLDER_PAUSE_ID 0x14 /* closing tag found end=false */
+
+
+#define XML_FOLDER_TTBL_SIZE (XML_FOLDER_MAX_ID+1)
+
+/*****************************************************************************
+** Type Definitions
+*****************************************************************************/
+
+typedef struct
+{
+ const UINT8 *p_name;
+ UINT8 len;
+} tXML_FOLDER_TTBL_ELEM;
+
+typedef tXML_FOLDER_TTBL_ELEM tXML_FOLDER_TTBL[]; /* Tag Table */
+
+
+static const tXML_FOLDER_TTBL_ELEM xml_flp_ttbl[XML_FOLDER_TTBL_SIZE] =
+{ /* index (FOLDER_XP_*_ID) & name */
+ {(UINT8*) "", XML_FOLDER_MAX_ID-1}, /* \x00 Number of elements in array */
+ /* XML FOLDER element (TAG) name */
+ {xml_folder_listing_elem, 14}, /* x01 folder-listing */
+ {xml_file_elem, 4}, /* 0x02 file */
+ {xml_folder_elem, 6}, /* x03 folder */
+ {xml_parent_folder_elem, 13}, /* x04 parent-folder */
+ {xml_name_attr, 4}, /* x05 name */
+ {xml_size_attr, 4}, /* x06 size */
+ {xml_type_attr, 4}, /* x07 type */
+ {xml_modified_attr, 8}, /* x08 modified */
+ {xml_created_attr, 7}, /* x09 created */
+ {xml_accessed_attr, 8}, /* x0a accessed */
+ {xml_user_perm_attr, 9}, /* x0b user-perm */
+ {xml_group_perm_attr, 10}, /* x0c group-perm */
+ {xml_other_perm_attr, 10}, /* x0d other-perm */
+ {xml_group_attr, 5}, /* x0e group */
+ {xml_owner_attr, 5}, /* x0f owner */
+ {xml_version_attr, 7}, /* x10 version */
+ {xml_lang_attr, 8}, /* x11 xml:lang */
+ {xml_unknown, 7 } /* x12 unknown */
+};
+
+#define XML_FOLDER_PTBL_SIZE 0x10
+typedef UINT8 * tXML_FOLDER_PTBL_ELEM;
+
+static const tXML_FOLDER_PTBL_ELEM xml_flp_ptbl[XML_FOLDER_PTBL_SIZE] =
+{
+ (UINT8 *) "\x01\x02\x03\x04", /* index x00, all valide attributes in above list */
+ (UINT8 *) "\x10\x02\x03\x04", /* x01 attributes and sub-tags supported */
+ (UINT8 *) "\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x11", /* x02: file attributes */
+ (UINT8 *) "\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x11", /* x03: folder attributes */
+ (UINT8 *) "" /* x04 parent folder has no attributes */
+};
+
+
+#if (FOLDER_DEBUG_XML == TRUE)
+void xml_flp_debug_str(tXML_STR *p_str, UINT8 *p_buf)
+{
+ int dbg_len;
+ if ( (p_str == NULL) || (NULL==p_str->p))
+ BCM_STRCPY_S( (char *)p_buf, FOLDER_DEBUG_LEN, "(NULL)" );
+ else
+ {
+ dbg_len = p_str->len;
+ if ( dbg_len >= FOLDER_DEBUG_LEN)
+ dbg_len = FOLDER_DEBUG_LEN - 1;
+ BCM_STRNCPY_S( (char *)p_buf, FOLDER_DEBUG_LEN, (char *)p_str->p, dbg_len);
+ p_buf[dbg_len] = 0;
+ }
+}
+
+#else
+#define xml_flp_debug_str(p_str, p_buf)
+#endif
+
+/*****************************************************************************
+ ** Function xml_flp_proc_tag
+ ** Description
+ ** Parameters -
+ ** Returns
+ *****************************************************************************/
+static UINT8 xml_flp_proc_tag( tXML_FOLDER_STATE *p_st, tXML_STR *p_name, tXML_STACK *p_stk)
+{
+ const UINT8 *p_stag; /* sub tag pointer */
+ UINT8 curr = p_stk->stack[p_stk->top];
+#if (defined(FOLDER_DEBUG_XML) && FOLDER_DEBUG_XML == TRUE)
+ UINT8 dbg_name[FOLDER_DEBUG_LEN];
+#endif
+
+ if (curr < XML_FOLDER_PTBL_SIZE)
+ {
+ /* Iterate over allowed sub-tags for the current tag. */
+ for (p_stag = xml_flp_ptbl[curr]; p_stag && *p_stag ; p_stag++)
+ {
+ if (*p_stag >= XML_FOLDER_TTBL_SIZE)
+ continue;
+ if(p_name->len == xml_flp_ttbl[*p_stag].len &&
+ strncmp((char *)p_name->p, (char *)xml_flp_ttbl[*p_stag].p_name, p_name->len) == 0)
+ {
+ p_stk->top++;
+ p_stk->stack[p_stk->top] = *p_stag;
+
+ return *p_stag;
+ }
+ }
+ }
+
+#if (defined(FOLDER_DEBUG_XML) && FOLDER_DEBUG_XML == TRUE)
+ xml_flp_debug_str(p_name, dbg_name);
+ XML_TRACE_DEBUG1("xml_flp_proc_tag: bad name:%s", dbg_name );
+#endif
+
+ p_stk->top++;
+ p_stk->stack[p_stk->top] = XML_XP_UNKNOWN_ID;
+ return XML_XP_UNKNOWN_ID;
+}
+
+
+/*****************************************************************************
+ ** Function xml_flp_proc_attr
+ ** Description
+ ** Parameters -
+ ** Returns
+ *****************************************************************************/
+static UINT8 xml_flp_proc_attr(tXML_FOLDER_STATE *p_st, tXML_STR *p_name, tXML_STACK *p_stk)
+{
+ const UINT8 *p_stag; /* sub tag pointer */
+ UINT8 curr = p_stk->stack[p_stk->top];
+#if (FOLDER_DEBUG_XML == TRUE)
+ UINT8 dbg_name[FOLDER_DEBUG_LEN];
+#endif
+
+ if (curr < XML_FOLDER_PTBL_SIZE)
+ {
+ /* Iterate over allowed sub-tags for the current tag. */
+ for (p_stag = xml_flp_ptbl[curr]; p_stag && *p_stag; p_stag++)
+ {
+ if (*p_stag >= XML_FOLDER_TTBL_SIZE)
+ continue;
+ if(p_name->len == xml_flp_ttbl[*p_stag].len &&
+ strncmp((char *)p_name->p, (char *)xml_flp_ttbl[*p_stag].p_name, p_name->len) == 0)
+ {
+ p_stk->top++;
+ p_stk->stack[p_stk->top] = *p_stag;
+
+ return *p_stag;
+ }
+ }
+ }
+
+#if (defined(FOLDER_DEBUG_XML) && FOLDER_DEBUG_XML == TRUE)
+ xml_flp_debug_str(p_name, dbg_name);
+ XML_TRACE_DEBUG1("xml_flp_proc_attr: bad name:%s", dbg_name);
+#endif
+ return XML_XP_UNKNOWN_ID;
+}
+/*****************************************************************************
+ ** Function xml_flp_get_perm
+ ** Description Translate permission character into XML_PERM_MASK
+ ** Returns XML_PERM_MASK: permission mask
+ *****************************************************************************/
+static XML_PERM_MASK xml_flp_get_perm(char *right, UINT16 len )
+{
+ XML_PERM_MASK mask = 0;
+ UINT8 perm_str[XML_PERM_LEN_MAX] = {0};
+
+ memcpy(perm_str, right, XML_PERM_LEN_MAX);
+ perm_str[len] = '\0';
+
+ if (strchr((char *)perm_str, 'R'))
+ mask |= XML_PERM_READ_B;
+ if (strchr((char *)perm_str, 'W'))
+ mask |= XML_PERM_WRITE_B;
+ if (strchr((char *)perm_str, 'D'))
+ mask |= XML_PERM_DELETE_B;
+
+#if (FOLDER_DEBUG_XML == TRUE)
+ XML_TRACE_DEBUG2("xml_flp_get_perm [%s] -> %d",perm_str, mask);
+#endif
+ return mask;
+}
+
+/*****************************************************************************
+ ** Function xml_flp_find_ch_n_copy
+ ** Description copy any chacter till one char in p_str. Any char in p_str
+ ** will stop copy pointed by p_begin
+ ** Parameters
+ ** Returns
+ *****************************************************************************/
+static void xml_flp_find_ch_n_copy( tXML_MCOPY *p_copy )
+{
+ const UINT8 *p_tmp;
+ const UINT8 *p_str = (UINT8 *)">"; /* was: ":=/> \t\n\r". i think we should copy till
+ closing flag */
+ unsigned int last = XML_FOLDER_CARRY_OVER_LEN; /* maximum carry over len we can support */
+ UINT8 *p_last = p_copy->last.p + p_copy->last.len - 1; /* point to the last char of carry
+ over buffer */
+ BOOLEAN found = FALSE;
+
+ /* check if the last char in p_last is in p_str */
+ for (p_tmp = p_str; *p_tmp; p_tmp++)
+ {
+ if (*p_last == *p_tmp)
+ {
+ found = TRUE;
+ break;
+ }
+ } /* for */
+
+ if (found == FALSE)
+ {
+ /* if not in p_str, move chars from p_begin to p_last
+ * until reached last_len or any char in p_str */
+ p_last++;
+ last -= p_copy->last.len; /* calculate the maximum number of chars we can copy */
+ while (*(p_copy->p_begin) && last) /* rl: not sure that this buffer is termninated by a 0 */
+ {
+ /* copy from source (new buffer) to carry over. adjust only carry over ptr. */
+ *p_last++ = *p_copy->p_begin;
+ last--;
+ for (p_tmp = p_str; *p_tmp; p_tmp++)
+ {
+ if (*p_copy->p_begin == *p_tmp)
+ {
+ p_copy->p_begin++; /* adjust pointer to point to next char to read */
+ /* calculate new length of carry over buffer contents */
+ p_copy->last.len = XML_FOLDER_CARRY_OVER_LEN-last;
+ *p_last = 0; /* NULL terminate p_last. rl: not really neccessary. */
+ return;
+ }
+ } /* for */
+ p_copy->p_begin++; /* update now to next char. this way abort char is also copied */
+ } /* while */
+ } /* !found */
+}
+
+/*****************************************************************************
+** Function xml_folder_cback
+** Description
+**
+** Parameters
+** Returns
+*****************************************************************************/
+static BOOLEAN xml_folder_cback( tXML_EVENT event, void *p_event_data, void *p_usr_data)
+{
+ tXML_MEVT_DATA *p_ed = (tXML_MEVT_DATA*) p_event_data;
+ tXML_FOLDER_STATE *p_st = (tXML_FOLDER_STATE *) p_usr_data;
+ tXML_PROP *p_cp = &p_st->p_prop[p_st->prop_index];
+ BOOLEAN ret = TRUE;
+ UINT8 next; /* next element */
+ UINT8 curr = p_ed->stack.stack[p_ed->stack.top]; /* current element */
+#if (FOLDER_DEBUG_XML == TRUE)
+ UINT8 dbg_name[FOLDER_DEBUG_LEN];
+ UINT8 dbg_prefix[FOLDER_DEBUG_LEN];
+ UINT8 dbg_value[FOLDER_DEBUG_LEN];
+#endif
+
+#if (FOLDER_DEBUG_XML == TRUE)
+ XML_TRACE_DEBUG1("xml_folder_cback:%d", event);
+#endif
+
+ switch (event)
+ {
+ case XML_TAG : /* <tag-name */
+ next = xml_flp_proc_tag(p_st, &p_ed->tag.name, &p_ed->stack);
+#if (FOLDER_DEBUG_XML == TRUE)
+ xml_flp_debug_str(&p_ed->tag.name, dbg_name);
+ xml_flp_debug_str(&p_ed->tag.prefix, dbg_prefix);
+ XML_TRACE_DEBUG2("XML_TAG: p:%s, name:%s", dbg_prefix, dbg_name);
+ XML_TRACE_DEBUG2("top:x%x, stk:x%x", p_ed->stack.top, p_ed->stack.stack[p_ed->stack.top]);
+
+#endif
+ if (next != 0)
+ {
+ if (next <= XML_MAX_OBJ_TAG_ID)
+ p_st->obj = next;
+
+ if(p_st->prop_index <p_st->max_num_prop)
+ {
+ /* we do not use prefix in FTC */
+ p_cp->name = next;
+ p_cp->p_data = NULL;
+ p_cp->len = 0;
+ p_cp->level = p_ed->stack.top;
+ p_st->prop_index++;
+ }
+ else
+ ret = FALSE;
+ }
+ break;
+
+ case XML_ATTRIBUTE : /* attr-name="attr-value" */
+ curr = xml_flp_proc_attr(p_st, &p_ed->attr.name, &p_ed->stack);
+#if (defined(FOLDER_DEBUG_XML) && FOLDER_DEBUG_XML == TRUE)
+ xml_flp_debug_str(&p_ed->attr.name, dbg_name);
+ xml_flp_debug_str(&p_ed->attr.prefix, dbg_prefix);
+ xml_flp_debug_str(&p_ed->attr.value, dbg_value);
+ XML_TRACE_DEBUG4("[xml folder] XML_ATTRIBUTE: p:%s, name:%s, v:%s, curr:%x",
+ dbg_prefix, dbg_name, dbg_value, curr);
+#endif
+ if ((curr != 0) && (curr != XML_XP_UNKNOWN_ID))
+ {
+ if(p_st->prop_index <p_st->max_num_prop)
+ {
+ p_cp->name = curr;
+ p_cp->p_data = p_ed->attr.value.p;
+ p_cp->len = p_ed->attr.value.len;
+ p_cp->level = p_ed->stack.top;
+ p_st->prop_index++;
+ }
+ else
+ ret = FALSE;
+ p_ed->stack.top--;
+ }
+ break;
+
+ case XML_CHARDATA :
+#if (defined(FOLDER_DEBUG_XML) && FOLDER_DEBUG_XML == TRUE)
+ xml_flp_debug_str(&p_ed->ch_data.value, dbg_value);
+ XML_TRACE_DEBUG2("XML_CHARDATA: v:%s, last:%d", dbg_value, p_ed->ch_data.last);
+#endif
+ break;
+
+ case XML_ETAG : /* </tag-name> */
+ if(p_ed->stack.top > 0)
+ {
+ p_ed->stack.stack[p_ed->stack.top] = 0;
+ p_ed->stack.top--;
+ p_st->ended = (BOOLEAN) (p_ed->stack.top == 0);
+ }
+#if (defined(FOLDER_DEBUG_XML) && FOLDER_DEBUG_XML == TRUE)
+ xml_flp_debug_str(&p_ed->etag.name, dbg_name);
+ xml_flp_debug_str(&p_ed->etag.prefix, dbg_prefix);
+ XML_TRACE_DEBUG2("[xml folder] XML_ETAG: p:%s, name:%s", dbg_prefix, dbg_name);
+ XML_TRACE_DEBUG2("[xml folder] top:x%x, stk:x%x", p_ed->stack.top, p_ed->stack.stack[p_ed->stack.top]);
+#endif
+ break;
+
+ case XML_TAG_END: /* /> */
+ curr = p_ed->stack.stack[p_ed->stack.top];
+
+ if(p_st->prop_index <p_st->max_num_prop)
+ {
+ if(p_ed->empty_elem.end)
+ p_cp->name = XML_FOLDER_TAG_END_ID;
+ else
+ p_cp->name = XML_FOLDER_PAUSE_ID;
+ p_cp->p_data = NULL;
+ p_cp->len = 0;
+ p_cp->level = p_ed->stack.top;
+ p_st->prop_index++;
+ if(p_ed->empty_elem.end && p_ed->stack.top > 0)
+ {
+ p_ed->stack.top--;
+ }
+ }
+ else
+ ret = FALSE;
+
+#if (defined(FOLDER_DEBUG_XML) && FOLDER_DEBUG_XML == TRUE)
+ XML_TRACE_DEBUG4("[xml folder] XML_TAG_END: %d, top:x%x, stk:x%x, curr:x%x",
+ p_ed->empty_elem.end, p_ed->stack.top, p_ed->stack.stack[p_ed->stack.top], curr);
+#endif
+ break;
+
+ case XML_PARTIAL:
+ if(p_st->p_prop[p_st->prop_index-1].name != XML_FOLDER_TAG_END_ID)
+ {
+ p_ed->stack.top--;
+#if (defined(FOLDER_DEBUG_XML) && FOLDER_DEBUG_XML == TRUE)
+ XML_TRACE_DEBUG0("[xml folder] adjust due to XML_PARTIAL");
+#endif
+ }
+ break;
+
+ case XML_COPY:
+ xml_flp_find_ch_n_copy( &p_ed->copy );
+ XML_TRACE_DEBUG1("[xml folder] XML_COPY: %s", p_ed->copy.last.p);
+ break;
+
+ default :
+#if (defined(FOLDER_DEBUG_XML) && FOLDER_DEBUG_XML == TRUE)
+ XML_TRACE_DEBUG1("[xml folder] XML event: %d", event);
+#endif
+ break;
+ }
+
+ return ret;
+}
+
+/**********************************************************************************
+** Function xml_flp_int_fill_file_folder
+** Description fill in file/folder structure.
+**
+** Parameters
+** Returns xx: > 0 : number of properties scanned, folder entry is added
+** = 0 : no end tag found, carry over to next parse
+** = -1: no dst_resource avaibale, all prop left to next parse
+** = -2: exceed max entry, no folder entry added
+**********************************************************************************/
+static INT16 xml_flp_int_fill_file_folder( const UINT8 type,
+ tXML_FOLDER_STATE * p_xud,
+ tXML_PROP *p_prop,
+ UINT16 *num_prop,
+ UINT8 **p_dst_data,
+ UINT16 *dst_len)
+{
+ INT16 xx;
+ UINT16 len;
+ BOOLEAN end = FALSE;
+ tXML_PROP *cur_prop = p_prop;
+ UINT8 *p_cur_offset = *p_dst_data;
+
+ for(xx=0; (xx < *num_prop) && !end; xx++, cur_prop++)
+ {
+#if (defined(FOLDER_DEBUG_XML) && FOLDER_DEBUG_XML == TRUE)
+ XML_TRACE_DEBUG5( "[xml folder] fill: num_prop:%d, name id: x%x, p_prop: x%x, p_data:%s, len: %d",
+ (*num_prop-xx) , cur_prop->name, cur_prop, cur_prop->p_data, cur_prop->len);
+#endif
+ switch (cur_prop->name)
+ {
+ case XML_NAME_ATTR_ID:
+ if ( p_xud->current_entry < p_xud->max_entry )
+ {
+ /* as long as we do not exceed the number of entries in the ouput array copy name */
+ p_xud->p_entry[p_xud->current_entry].type = type;
+ /* calculate the max length to copy */
+ len = (cur_prop->len<=p_xud->max_name_len) ? cur_prop->len:p_xud->max_name_len;
+ if ((*dst_len - len) > 0) /* enough data buffer available? */
+ {
+ p_xud->p_entry[p_xud->current_entry].data = p_cur_offset;
+ p_xud->p_entry[p_xud->current_entry].len = len;
+
+ memcpy( (void *)p_xud->p_entry[p_xud->current_entry].data,
+ (const void *)cur_prop->p_data,
+ len );
+ p_xud->p_entry[p_xud->current_entry].data[len] = 0; /* null terminate string */
+ p_cur_offset += (len + 1);
+ *dst_len = *dst_len - (len + 1) ;
+
+#if (defined(FOLDER_DEBUG_XML) && FOLDER_DEBUG_XML == TRUE)
+ XML_TRACE_DEBUG3("[xml folder]: catch filename [%s] len [%d] dst_len left:[%d]",
+ p_xud->p_entry[p_xud->current_entry].data,
+ len,
+ *dst_len);
+#endif
+ }
+ else /* run out of dst buffer resource */
+ {
+ xx = -1;
+ return xx;
+ }
+ }
+ else /* exceed max entry */
+ return -2;
+
+ break;
+
+ case XML_SIZE_ATTR_ID:
+ if ( p_xud->current_entry < p_xud->max_entry )
+ {
+ p_xud->p_entry[p_xud->current_entry].size = atol( (const char *)cur_prop->p_data );
+ }
+ break;
+
+ case XML_USER_PERM_ATTR_ID:
+ if ( p_xud->current_entry < p_xud->max_entry )
+ {
+ p_xud->p_entry[p_xud->current_entry].user_perm = xml_flp_get_perm( (char *)cur_prop->p_data, cur_prop->len);
+ }
+ break;
+ case XML_TYPE_ATTR_ID:
+ case XML_MODIFIED_ATTR_ID:
+ case XML_CREATED_ATTR_ID:
+ case XML_ACCESSED_ATTR_ID:
+ case XML_GROUP_PERM_ATTR_ID:
+ case XML_OTHER_PERM_ATTR_ID:
+ case XML_GROUP_ATTR_ID:
+ case XML_OWNER_ATTR_ID:
+ case XML_LANG_ATTR_ID:
+
+#if (defined(FOLDER_DEBUG_XML) && FOLDER_DEBUG_XML == TRUE)
+ XML_TRACE_DEBUG1( "[xml folder] ignored attr: 0x%x", cur_prop->name );
+#endif
+ break;
+
+ case XML_FOLDER_TAG_END_ID:
+ /* -------------------- CUSTOMER SPECIFIC ---------------------- */
+ p_xud->current_entry++; /* increment only when end tag (/>) found */
+
+#if (defined(FOLDER_DEBUG_XML) && FOLDER_DEBUG_XML == TRUE)
+ XML_TRACE_DEBUG1( "[xml folder] FOUND END TAG: 0x%x", cur_prop->name );
+#endif
+
+ end = TRUE;
+ break;
+
+ default:
+ XML_TRACE_DEBUG1("[xml folder] unknown attrib: %d", cur_prop->name );
+ break;
+ }
+ }
+#if (FOLDER_DEBUG_XML == TRUE)
+ XML_TRACE_DEBUG2("[xml folder] fill_file_folder: end:%d, xx:%d", end, xx);
+#endif
+#if 0
+ /* if end tag not found -> split over two buffers. but parser will still show rest of
+ found properties. so return still found properties. */
+ if(end == FALSE)
+ xx = 0;
+#endif
+
+ /* keep track of current data buffer offset */
+ *p_dst_data = p_cur_offset;
+ return xx;
+} /* xml_flp_int_fill_file_folder() */
+
+
+/**********************************************************************************
+** Function xml_flp_int_fill_evt_data
+**
+** Description fill in file/folder structure.
+**
+** Parameters
+** Returns
+**********************************************************************************/
+static tXML_FOLDER_RES xml_flp_int_fill_evt_data( UINT8 op,
+ void *p_evt_data,
+ tXML_PROP **p_prop,
+ UINT16 *num_prop,
+ UINT8 **p_dst_data,
+ UINT16 *dst_len)
+{
+ tXML_FOLDER_STATE *p_xud = (tXML_FOLDER_STATE *)p_evt_data;
+ INT16 inc_prop;
+ UINT8 prop_name; /* Property name. */
+ UINT8 entry_type;
+ tXML_PROP *cur_prop = *p_prop;
+ UINT8 *p_cur_offset = *p_dst_data;
+
+ tXML_FOLDER_RES x_res = XML_FOLDER_OK;
+ BOOLEAN x_no_res = FALSE; /* guard dest buffer resource */
+
+
+ if ( op == 0 || op > XML_MAX_OBJ_TAG_ID || *num_prop == 0)
+ return XML_FOLDER_ERROR;
+
+#if FOLDER_DEBUG_XML
+ XML_TRACE_DEBUG2( "[xml folder] xml_flp_int_fill_evt_data op:%d, num_prop:%d",
+ op, *num_prop);
+#endif
+
+
+
+ while ( *num_prop > 0 && !x_no_res )
+ {
+#if (defined(FOLDER_DEBUG_XML) && FOLDER_DEBUG_XML == TRUE)
+ XML_TRACE_DEBUG2("end_prop:%d, name id: x%x", *num_prop, cur_prop->name);
+#endif
+ prop_name = cur_prop->name;
+ cur_prop++;
+ *num_prop -= 1;
+
+
+ switch( prop_name )
+ {
+ case XML_FOLDER_LISTING_ELEM_ID:
+ /* skip over version attribute which should always be 1.0. this is the top level */
+ break;
+
+ case XML_FILE_ELEM_ID:
+ case XML_FOLDER_ELEM_ID:
+ /* folder or file: only type is the difference */
+ entry_type = (XML_FILE_ELEM_ID==prop_name)?XML_OBX_FILE:XML_OBX_FOLDER;
+ inc_prop = xml_flp_int_fill_file_folder( entry_type,
+ p_xud,
+ cur_prop,
+ num_prop,
+ &p_cur_offset,
+ dst_len);
+ if (inc_prop == -1) /* no dst_buf available */
+ {
+ /* backup one more prop to obtain the skipped folder/file entry header */
+ cur_prop --;
+ *num_prop += 1;
+
+ x_res = XML_FOLDER_DST_NO_RES;
+ x_no_res = TRUE;
+ }
+ else if (inc_prop == -2) /* exceed max entry */
+ {
+ x_no_res = TRUE;
+ x_res = XML_FOLDER_OUT_FULL;
+ }
+ else /* found folder entry */
+ {
+ cur_prop += inc_prop;
+ *num_prop -= inc_prop;
+ }
+ break;
+
+ case XML_PARENT_FOLDER_ELEM_ID:
+ if ( p_xud->current_entry < p_xud->max_entry )
+ {
+ /* set type of entry (file, folder) */
+ p_xud->p_entry[p_xud->current_entry].type = XML_OBX_FOLDER;
+ /* copy folder name if dst buffer is big enough, parent folder as ".." */
+ if ((*dst_len - strlen(XML_PARENT_FOLDER)) > 0)
+ {
+ p_xud->p_entry[p_xud->current_entry].data = p_cur_offset;
+ p_xud->p_entry[p_xud->current_entry].len = 2;
+ memcpy( (void *)p_xud->p_entry[p_xud->current_entry].data,
+ (const void *)XML_PARENT_FOLDER, 2);
+ p_xud->p_entry[p_xud->current_entry].data[2] = '\0'; /* null terminate */
+ p_xud->current_entry ++;
+ p_cur_offset += 3 ;
+ *dst_len -= 3;
+ }
+ else
+ {
+ x_no_res = TRUE;
+ x_res = XML_FOLDER_DST_NO_RES;
+ }
+ }
+ else
+ {
+ x_no_res = TRUE;
+ x_res = XML_FOLDER_OUT_FULL;
+ }
+ break;
+
+ case XML_FOLDER_PAUSE_ID:
+
+#if (FOLDER_DEBUG_XML==TRUE)
+ XML_TRACE_DEBUG0( "[xml folder] xml_flp_int_fill_evt_data(): XML_FOLDER_PAUSE_ID" );
+#endif
+ break;
+
+ case XML_FOLDER_TAG_END_ID:
+#if (FOLDER_DEBUG_XML==TRUE)
+ XML_TRACE_DEBUG0( "[xml folder] xml_flp_int_fill_evt_data(): XML_FOLDER_TAG_END_ID" );
+#endif
+ break;
+
+ default:
+ XML_TRACE_DEBUG1( "[xml folder] xml_flp_int_fill_evt_data():unknown element: %d", prop_name );
+ break;
+ }
+ }
+
+ /* keep track of current filling position, and current available dst buffer */
+ *p_prop = cur_prop;
+ *p_dst_data = p_cur_offset;
+
+ return x_res;
+} /* xml_flp_int_fill_evt_data() */
+
+
+/**************************************************************************************
+** Function XML_FolderInit
+**
+** Description Initialize xml parser state machine.
+**
+** Parameters p_xml_state: address of an xml parser state machine to be initialized,
+** allocate an additional space of size XML_FOLDER_CARRY_OVER_LEN
+** right after *p_xml_state to hold carry over data.
+** p_entry : points start of output directory entry. caller needs do
+** free this memory
+** max_entry : max is 16 bit integer value which is the maximum number
+** of folder entries.
+
+**
+** Returns void
+**************************************************************************************/
+
+void XML_FolderInit( tXML_FOLDER_PARSER *p_xml_state,
+ tXML_FOLDER_ENTRY *p_entry,
+ const UINT16 max_entry )
+{
+ /* Initialize the generic xml parser state machine.*/
+ XML_InitPars( &p_xml_state->xml, xml_folder_cback, &p_xml_state->xml_user_data );
+
+ /* User need to allocate an additional space of size XML_FOLDER_CARRY_OVER_LEN */
+ /* right after *p_xml_state to hold carry over data. */
+ /* point to the end of the allocated buffer for p_xml_state, which is the */
+ /* beginning of buffer(XML_FOLDER_CARRY_OVER_LEN) */
+ p_xml_state->xml.last_bfr.p = (UINT8 *)(p_xml_state + 1);
+ p_xml_state->xml.last_bfr.len = XML_FOLDER_CARRY_OVER_LEN;
+
+ /* Initialize user data */
+ p_xml_state->xml_user_data.p_entry = p_entry;
+ p_xml_state->xml_user_data.current_entry = 0;
+ p_xml_state->xml_user_data.max_name_len = XML_UI_ENTRY_MAX_NAME_LEN + 1;
+ p_xml_state->xml_user_data.max_entry = (UINT16)max_entry;
+ p_xml_state->xml_user_data.prop_num = 0;
+}
+
+
+/**************************************************************************************
+** Function XML_FolderParse
+**
+** Description This function is called to parse the xml data received from OBEX
+** into folder entries associated with properties value. It can also be
+** used as clean up function to delete left over data from previous parse.
+** This clean up function is typically used when application runs out of
+** resource and decides to discard extra xml data received.
+**
+** Parameters p_xml_state: pointer to a xml parser initialized by XML_FolderInit().
+** xml_data: valid pointer to OBEX list data in xml format.
+** xml_len: length of the package, must be non-zero value.
+** dst_data: valid pointer to the buffer for holding converted folder entry name.
+ When dst_data is NULL, clean up all remaining data in the parser.
+** dst_len: pointer to the length of dst_data buffer, its carry out value
+** is the number of bytes remaining buffer.When dst_len is NULL,
+** it will cause to flush the internal data in the parser.
+** num_entries: current number of entries, in the end it is the total number of entries
+**
+** Returns tXML_FOLDER_RES (see xml_flp.h)
+** XML_PENDING: parsing not completed
+** XML_END_LIST: found /folder-listing but no final flag detected
+** XML_FOLDER_OUT_FULL: reached max_entry -> do not call parser anymore!!! dump data
+** XML_FOLDER_DST_NO_RES : run out of dst buffer resource while
+** some xml data still remains.
+
+**************************************************************************************/
+tXML_FOLDER_RES XML_FolderParse( tXML_FOLDER_PARSER *p_xml_state,
+ UINT8 *xml_data, UINT16 xml_len,
+ UINT8 *dst_data, UINT16 *dst_len,
+ UINT16 *num_entries )
+{
+ tXML_OS xos;
+ BOOLEAN is_remain = TRUE;
+ tXML_MUL_STATE *p_xml = &p_xml_state->xml;
+ tXML_FOLDER_STATE *p_st = &p_xml_state->xml_user_data;
+ tXML_FOLDER_RES x_res = XML_FOLDER_OK;
+ tXML_RESULT res = XML_NO_PROP;
+ UINT16 max_num_prop = OBX_LRG_DATA_POOL_SIZE/sizeof(tXML_PROP); /* Changed to use the reserved buffer pool */
+
+
+#if (defined(FOLDER_DEBUG_XML) && FOLDER_DEBUG_XML == TRUE)
+ int xx;
+ UINT8 dbg_buf[FOLDER_DEBUG_LEN];
+ tXML_STR str;
+#endif
+
+ /* if dst_data is NULL, clean up remaining data */
+ if (!dst_data || !dst_len)
+ {
+ /* clean out remained xml data left over from last parse */
+ if (p_xml_state->xml_user_data.p_prop )
+ {
+ GKI_freebuf( p_st->p_prop );
+ p_st->p_prop = p_st->offset_prop = NULL;
+ p_st->prop_num = 0;
+ }
+#if (FOLDER_DEBUG_XML == TRUE)
+ XML_TRACE_DEBUG0( "[xml folder] XML_FolderParse() Clean up left over!");
+#endif
+ return x_res;
+ }
+
+ /* if illegal OBEX data or dst buffer pointer received, return ERROR */
+ if (xml_len == 0 || !xml_data)
+ {
+ return XML_FOLDER_ERROR;
+ }
+
+ /* XML_FolderParse receive new xml data, allocate buffer to hold parsed prop */
+ if (p_st->offset_prop == NULL)
+ {
+
+#if (FOLDER_DEBUG_XML == TRUE)
+ XML_TRACE_DEBUG0( "[xml folder] XML_FolderParse() Receive New Data!");
+ XML_TRACE_DEBUG2( "[xml folder] XML_data start[%x] end [%x]",xml_data, xml_data+xml_len);
+#endif
+ is_remain = FALSE;
+ if ( NULL!= (p_st->p_prop = (tXML_PROP *)GKI_getpoolbuf( OBX_LRG_DATA_POOL_ID ) ) )
+ {
+ /* pointing next prop to be converted into file entry */
+ p_st->prop_num = 0;
+ }
+ else
+ {
+ GKI_freebuf( p_xml_state );
+ x_res = XML_FOLDER_NO_RES;
+ return x_res;
+ }
+ }
+#if (FOLDER_DEBUG_XML == TRUE)
+ else
+ {
+ XML_TRACE_DEBUG0( "[xml folder] XML_FolderParse(): Keep cleaning up old xml data !");
+ }
+#endif
+ /* update the data address */
+ xos.p_begin = xml_data;
+ xos.p_end = xml_data + xml_len;
+
+ while( res == XML_NO_PROP )
+ {
+ /* if no remaining data in p_st->p_prop, parse new xml data */
+ if (!is_remain)
+ {
+ p_st->max_num_prop = max_num_prop;
+ p_st->prop_index = 0;
+ res = XML_MulParse( p_xml, &xos );
+
+
+#if (FOLDER_DEBUG_XML == TRUE)
+ XML_TRACE_DEBUG4( "xml_folder_parse obj: %x, max: %d, num: %d, res: %d",
+ p_st->obj, max_num_prop, p_st->prop_index, res);
+
+ if (res != 0)
+ {
+ XML_TRACE_DEBUG1( "XML_MulParse Parsing: %d !!!", res);
+ }
+
+ for(xx=0; xx<p_st->prop_index; xx++)
+ {
+ if ( p_st->p_prop[xx].name < XML_FOLDER_MAX_ID )
+ {
+ str.p = p_st->p_prop[xx].p_data;
+ str.len = p_st->p_prop[xx].len;
+ xml_flp_debug_str(&str, dbg_buf);
+ XML_TRACE_DEBUG5( "[xml folder] parsed: index[%d]:%d:%s: %s(%d)", p_st->prop_index-xx, p_st->p_prop[xx].level,
+ xml_flp_ttbl[p_st->p_prop[xx].name].p_name, dbg_buf, p_st->p_prop[xx].len);
+ }
+ else
+ {
+ XML_TRACE_DEBUG3( "[xml folder] internal prop: %d:%d:%d", xx, p_st->p_prop[xx].level,
+ p_st->p_prop[xx].name );
+ }
+ }
+#endif
+ p_st->prop_num = p_st->prop_index ;
+ p_st->offset_prop = p_st->p_prop;
+ }
+ else
+ {
+ /* This is left over data, pick up the result from the previous parse */
+ res = p_xml->pars_res;
+ }
+
+ if ( res != XML_OBJ_ST_EMPTY )
+ {
+ x_res = xml_flp_int_fill_evt_data( p_st->obj, p_st, &p_st->offset_prop, &p_st->prop_num, &dst_data, dst_len );
+
+ if ( (XML_FOLDER_OK == x_res) && (XML_NO_END == res) )
+ {
+ /* XML_NO_END means that the xml is not completly finished and fill returns
+ ok when when partial filling has been ok */
+ x_res = XML_FOLDER_PENDING;
+ }
+
+ /* all parsed xml data has been converted into file entry */
+ /* or exceed max entry number , break the parsing loop */
+ if (XML_FOLDER_OUT_FULL != x_res && XML_FOLDER_DST_NO_RES != x_res)
+ {
+ is_remain = FALSE;
+ }
+ else
+ break;
+ }
+ } /* while */
+
+ /* free property table. at next call a new one is allocated */
+ if ((x_res != XML_FOLDER_DST_NO_RES && p_st->p_prop) ||
+ XML_FOLDER_OUT_FULL == x_res)
+ {
+ GKI_freebuf( p_st->p_prop );
+ p_st->p_prop = NULL;
+ p_st->offset_prop = NULL;
+ }
+
+ if ( x_res != XML_FOLDER_DST_NO_RES && p_st->ended)
+ {
+ /* this should happen on the same time as final flag in fact */
+ x_res = XML_FOLDER_END_LIST; /* found closing /folder-listing */
+ }
+
+
+ *num_entries = p_st->current_entry; /* report number of entries found. only when ended is true
+ application really should be interested! */
+ return x_res;
+}
+
diff --git a/stack/xml/xml_mlp.c b/stack/xml/xml_mlp.c
new file mode 100644
index 0000000..aca0cb5
--- /dev/null
+++ b/stack/xml/xml_mlp.c
@@ -0,0 +1,1060 @@
+/******************************************************************************
+ **
+ ** Name: xml_mlp.c
+ **
+ ** Description: This module contains xml parser of MAP message list object
+ **
+ ** Copyright (c) 2004-2011, Broadcom Corporation, All Rights Reserved.
+ ** Broadcom Bluetooth Core. Proprietary and confidential.
+ ******************************************************************************/
+
+#include "bt_target.h"
+#include "gki.h"
+#include "xml_mlp_api.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+#ifndef ML_DEBUG_XML
+#define ML_DEBUG_XML TRUE
+#endif
+#define ML_DEBUG_LEN 50
+#if (defined(ML_DEBUG_XML) && ML_DEBUG_XML == TRUE)
+#define XML_TRACE_DEBUG0(m) {BT_TRACE_0(TRACE_LAYER_GOEP, TRACE_TYPE_DEBUG, m);}
+#define XML_TRACE_DEBUG1(m,p1) {BT_TRACE_1(TRACE_LAYER_GOEP, TRACE_TYPE_DEBUG, m,p1);}
+#define XML_TRACE_DEBUG2(m,p1,p2) {BT_TRACE_2(TRACE_LAYER_GOEP, TRACE_TYPE_DEBUG, m,p1,p2);}
+#define XML_TRACE_DEBUG3(m,p1,p2,p3) {BT_TRACE_3(TRACE_LAYER_GOEP, TRACE_TYPE_DEBUG, m,p1,p2,p3);}
+#define XML_TRACE_DEBUG4(m,p1,p2,p3,p4) {BT_TRACE_4(TRACE_LAYER_GOEP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4);}
+#define XML_TRACE_DEBUG5(m,p1,p2,p3,p4,p5) {BT_TRACE_5(TRACE_LAYER_GOEP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5);}
+#define XML_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) {BT_TRACE_6(TRACE_LAYER_GOEP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5,p6);}
+#else
+#define XML_TRACE_DEBUG0(m)
+#define XML_TRACE_DEBUG1(m,p1)
+#define XML_TRACE_DEBUG2(m,p1,p2)
+#define XML_TRACE_DEBUG3(m,p1,p2,p3)
+#define XML_TRACE_DEBUG4(m,p1,p2,p3,p4)
+#define XML_TRACE_DEBUG5(m,p1,p2,p3,p4,p5)
+#define XML_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6)
+#endif
+
+#define XML_PERM_LEN_MAX 4
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+const UINT8 xml_ml_elem[] = "MAP-msg-listing";
+const UINT8 xml_ml_msg_elem[] = "msg";
+const UINT8 xml_ml_handle_attr[] = "handle";
+const UINT8 xml_ml_subject_attr[] = "subject";
+const UINT8 xml_ml_datetime_attr[] = "datetime";
+const UINT8 xml_ml_sender_name_attr[] = "sender_name";
+const UINT8 xml_ml_sender_addressing_attr[] = "sender_addressing";
+const UINT8 xml_ml_replyto_addressing_attr[] = "replyto_addressing";
+const UINT8 xml_ml_recipient_name_attr[] = "recipient_name";
+const UINT8 xml_ml_recipient_addressing_attr[] = "recipient_addressing";
+const UINT8 xml_ml_type_attr[] = "type";
+const UINT8 xml_ml_size_attr[] = "size";
+const UINT8 xml_ml_text_attr[] = "text";
+const UINT8 xml_ml_reception_status_attr[] = "reception_status";
+const UINT8 xml_ml_attachment_size_attr[] = "attachment_size";
+const UINT8 xml_ml_priority_attr[] = "priority";
+const UINT8 xml_ml_read_attr[] = "read";
+const UINT8 xml_ml_sent_attr[] = "sent";
+const UINT8 xml_ml_protected_attr[] = "protected";
+const UINT8 xml_ml_version_attr[] = "version";
+const UINT8 xml_ml_unknown[] = "unknown";
+
+#define XML_ML_ELEM_ID 0x01
+#define XML_ML_MSG_ELEM_ID 0x02
+#define XML_ML_MAX_OBJ_TAG_ID XML_ML_ELEM_ID
+#define XML_ML_HANDLE_ATTR_ID 0x03
+#define XML_ML_SUBJECT_ATTR_ID 0x04
+#define XML_ML_DATETIME_ATTR_ID 0x05
+#define XML_ML_SENDER_NAME_ATTR_ID 0x06
+#define XML_ML_SENDER_ADDRESSING_ATTR_ID 0x07
+#define XML_ML_REPLYTO_ADDRESSING_ATTR_ID 0x08
+#define XML_ML_RECIPIENT_NAME_ATTR_ID 0x09
+#define XML_ML_RECIPIENT_ADDRESSING_ATTR_ID 0x0a
+#define XML_ML_TYPE_ATTR_ID 0x0b
+#define XML_ML_SIZE_ATTR_ID 0x0c
+#define XML_ML_TEXT_ATTR_ID 0x0d
+#define XML_ML_RECEPTION_STATUS_ATTR_ID 0x0e
+#define XML_ML_ATTACHMENT_SIZE_ATTR_ID 0x0f
+#define XML_ML_PRIORITY_ATTR_ID 0x10
+#define XML_ML_READ_ATTR_ID 0x11
+#define XML_ML_SENT_ATTR_ID 0x12
+#define XML_ML_PROTECTED_ATTR_ID 0x13
+#define XML_ML_VERSION_ATTR_ID 0x14
+#define XML_ML_UNKNOWN_ID 0x15
+#define XML_ML_MAX_ID 0x16 /* keep in sync with above */
+#define XML_ML_TAG_END_ID 0x17 /* closing tag found end=true */
+#define XML_ML_PAUSE_ID 0x18 /* closing tag found end=false */
+
+#define XML_ML_TTBL_SIZE (XML_ML_MAX_ID+1)
+
+/*****************************************************************************
+** Type Definitions
+*****************************************************************************/
+
+typedef struct
+{
+ const UINT8 *p_name;
+ UINT8 len;
+} tXML_ML_TTBL_ELEM;
+
+typedef tXML_ML_TTBL_ELEM tXML_ML_TTBL[]; /* Tag Table */
+
+
+static const tXML_ML_TTBL_ELEM xml_ml_ttbl[XML_ML_TTBL_SIZE] =
+{ /* index (ML_XP_*_ID) & name */
+ {(UINT8*) "", XML_ML_MAX_ID-1}, /* \x00 Number of elements in array */
+ /* XML EVT_RPT element (TAG) name */
+ {xml_ml_elem, 15}, /* x01 MAP-msg-listing */
+ {xml_ml_msg_elem, 3}, /* x02 msg */
+ {xml_ml_handle_attr, 6}, /* x03 handle */
+ {xml_ml_subject_attr, 7}, /* x04 subject */
+ {xml_ml_datetime_attr, 8}, /* x05 datetime */
+ {xml_ml_sender_name_attr, 11}, /* x06 sender_name */
+ {xml_ml_sender_addressing_attr, 17}, /* x07 sender_addressing */
+ {xml_ml_replyto_addressing_attr, 18}, /* x08 replyto_addressing */
+ {xml_ml_recipient_name_attr, 14}, /* x09 recipient_name */
+ {xml_ml_recipient_addressing_attr, 20}, /* x0a recipient_addressing */
+ {xml_ml_type_attr, 4}, /* x0b type */
+ {xml_ml_size_attr, 4}, /* x0c size */
+ {xml_ml_text_attr, 4}, /* x0d text */
+ {xml_ml_reception_status_attr, 16}, /* x0e reception_status */
+ {xml_ml_attachment_size_attr, 15}, /* x0f attachment_size */
+ {xml_ml_priority_attr, 8}, /* x10 priority */
+ {xml_ml_read_attr, 4}, /* x11 read */
+ {xml_ml_sent_attr, 4}, /* x12 sent */
+ {xml_ml_protected_attr, 9}, /* x13 protected */
+ {xml_ml_version_attr, 7}, /* x14 version */
+ {xml_ml_unknown, 7} /* x15 unknown */
+};
+
+#define XML_MAP_ML_PTBL_SIZE 0x03
+typedef UINT8 * tXML_MAP_ML_PTBL_ELEM;
+
+static const tXML_MAP_ML_PTBL_ELEM xml_ml_ptbl[XML_MAP_ML_PTBL_SIZE] =
+{
+ (UINT8 *) "\x01", /* index x00, all valide attributes in above list */
+ (UINT8 *) "\x14\x02", /* x01 attributes and sub-tags supported */
+ (UINT8 *) "\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13"
+};
+
+
+#if (ML_DEBUG_XML == TRUE)
+void xml_ml_debug_str(tXML_STR *p_str, UINT8 *p_buf)
+{
+ int dbg_len;
+ if ( (p_str == NULL) || (NULL==p_str->p))
+ BCM_STRNCPY_S( (char *)p_buf, ML_DEBUG_LEN, "(NULL)", ML_DEBUG_LEN-1);
+ else
+ {
+ dbg_len = p_str->len;
+ if ( dbg_len >= ML_DEBUG_LEN)
+ dbg_len = ML_DEBUG_LEN - 1;
+ BCM_STRNCPY_S( (char *)p_buf, ML_DEBUG_LEN, (char *)p_str->p, dbg_len);
+ p_buf[dbg_len] = 0;
+ }
+}
+
+#else
+#define xml_ml_debug_str(p_str, p_buf)
+#endif
+
+/*****************************************************************************
+ ** Function xml_ml_proc_tag
+ ** Description
+ ** Parameters -
+ ** Returns
+ *****************************************************************************/
+static UINT8 xml_ml_proc_tag( tXML_ML_STATE *p_st, tXML_STR *p_name, tXML_STACK *p_stk)
+{
+ const UINT8 *p_stag; /* sub tag pointer */
+ UINT8 curr = p_stk->stack[p_stk->top];
+#if (defined(ML_DEBUG_XML) && ML_DEBUG_XML == TRUE)
+ UINT8 dbg_name[ML_DEBUG_LEN];
+#endif
+
+
+ if (curr < XML_MAP_ML_PTBL_SIZE)
+ {
+ /* Iterate over allowed sub-tags for the current tag. */
+ for (p_stag = xml_ml_ptbl[curr]; p_stag && *p_stag ; p_stag++)
+ {
+ if (*p_stag >= XML_ML_TTBL_SIZE)
+ continue;
+ if (p_name->len == xml_ml_ttbl[*p_stag].len &&
+ strncmp((char *)p_name->p, (char *)xml_ml_ttbl[*p_stag].p_name, p_name->len) == 0)
+ {
+ p_stk->top++;
+ p_stk->stack[p_stk->top] = *p_stag;
+
+ return *p_stag;
+ }
+ }
+ }
+
+#if (defined(ML_DEBUG_XML) && ML_DEBUG_XML == TRUE)
+ xml_ml_debug_str(p_name, dbg_name);
+ XML_TRACE_DEBUG1("xml_ml_proc_tag: bad name:%s", dbg_name );
+#endif
+
+ return XML_ML_UNKNOWN_ID;
+}
+
+
+/*****************************************************************************
+ ** Function xml_ml_proc_attr
+ ** Description
+ ** Parameters -
+ ** Returns
+ *****************************************************************************/
+static UINT8 xml_ml_proc_attr(tXML_ML_STATE *p_st, tXML_STR *p_name, tXML_STACK *p_stk)
+{
+ const UINT8 *p_stag; /* sub tag pointer */
+ UINT8 curr = p_stk->stack[p_stk->top];
+#if (ML_DEBUG_XML == TRUE)
+ UINT8 dbg_name[ML_DEBUG_LEN];
+#endif
+ if (curr < XML_MAP_ML_PTBL_SIZE)
+ {
+ /* Iterate over allowed sub-tags for the current tag. */
+ for (p_stag = xml_ml_ptbl[curr]; p_stag && *p_stag; p_stag++)
+ {
+ if (*p_stag >= XML_ML_TTBL_SIZE)
+ continue;
+ if (p_name->len == xml_ml_ttbl[*p_stag].len &&
+ strncmp((char *)p_name->p, (char *)xml_ml_ttbl[*p_stag].p_name, p_name->len) == 0)
+ {
+ p_stk->top++;
+ p_stk->stack[p_stk->top] = *p_stag;
+
+ return *p_stag;
+ }
+ }
+ }
+
+#if (defined(ML_DEBUG_XML) && ML_DEBUG_XML == TRUE)
+ xml_ml_debug_str(p_name, dbg_name);
+ XML_TRACE_DEBUG1("xml_ml_proc_attr: bad name:%s", dbg_name);
+#endif
+ return XML_ML_UNKNOWN_ID;
+}
+
+/*****************************************************************************
+ ** Function xml_ml_find_ch_n_copy
+ ** Description copy any chacter till one char in p_str. Any char in p_str
+ ** will stop copy pointed by p_begin
+ ** Parameters
+ ** Returns
+ *****************************************************************************/
+static void xml_ml_find_ch_n_copy( tXML_MCOPY *p_copy )
+{
+ const UINT8 *p_tmp;
+ const UINT8 *p_str = (UINT8 *)">"; /* was: ":=/> \t\n\r". i think we should copy till
+ closing flag */
+ unsigned int last = XML_ML_CARRY_OVER_LEN; /* maximum carry over len we can support */
+ UINT8 *p_last = p_copy->last.p + p_copy->last.len - 1; /* point to the last char of carry
+ over buffer */
+ BOOLEAN found = FALSE;
+ /* check if the last char in p_last is in p_str */
+ for (p_tmp = p_str; *p_tmp; p_tmp++)
+ {
+ if (*p_last == *p_tmp)
+ {
+ found = TRUE;
+ break;
+ }
+ } /* for */
+
+ if (found == FALSE)
+ {
+ /* if not in p_str, move chars from p_begin to p_last
+ * until reached last_len or any char in p_str */
+ p_last++;
+ last -= p_copy->last.len; /* calculate the maximum number of chars we can copy */
+ while (*(p_copy->p_begin) && last) /* rl: not sure that this buffer is termninated by a 0 */
+ {
+ /* copy from source (new buffer) to carry over. adjust only carry over ptr. */
+ *p_last++ = *p_copy->p_begin;
+ last--;
+ for (p_tmp = p_str; *p_tmp; p_tmp++)
+ {
+ if (*p_copy->p_begin == *p_tmp)
+ {
+ p_copy->p_begin++; /* adjust pointer to point to next char to read */
+ /* calculate new length of carry over buffer contents */
+ p_copy->last.len = XML_ML_CARRY_OVER_LEN-last;
+ *p_last = 0; /* NULL terminate p_last. rl: not really neccessary. */
+ return;
+ }
+ } /* for */
+ p_copy->p_begin++; /* update now to next char. this way abort char is also copied */
+ } /* while */
+ } /* !found */
+}
+
+/*****************************************************************************
+** Function xml_ml_cback
+** Description
+**
+** Parameters
+** Returns
+*****************************************************************************/
+static BOOLEAN xml_ml_cback( tXML_EVENT event, void *p_event_data, void *p_usr_data)
+{
+ tXML_MEVT_DATA *p_ed = (tXML_MEVT_DATA*) p_event_data;
+ tXML_ML_STATE *p_st = (tXML_ML_STATE *) p_usr_data;
+ tXML_PROP *p_cp = &p_st->p_prop[p_st->prop_index];
+ BOOLEAN ret = TRUE;
+ UINT8 next; /* next element */
+ UINT8 curr = p_ed->stack.stack[p_ed->stack.top]; /* current element */
+#if (ML_DEBUG_XML == TRUE)
+ UINT8 dbg_name[ML_DEBUG_LEN];
+ UINT8 dbg_prefix[ML_DEBUG_LEN];
+ UINT8 dbg_value[ML_DEBUG_LEN];
+#endif
+
+#if (ML_DEBUG_XML == TRUE)
+ XML_TRACE_DEBUG1("xml_ml_cback:%d", event);
+#endif
+
+ switch (event)
+ {
+ case XML_TAG : /* <tag-name */
+ next = xml_ml_proc_tag(p_st, &p_ed->tag.name, &p_ed->stack);
+#if (ML_DEBUG_XML == TRUE)
+ xml_ml_debug_str(&p_ed->tag.name, dbg_name);
+ xml_ml_debug_str(&p_ed->tag.prefix, dbg_prefix);
+ XML_TRACE_DEBUG2("XML_TAG: p:%s, name:%s", dbg_prefix, dbg_name);
+ XML_TRACE_DEBUG2("top:x%x, stk:x%x", p_ed->stack.top, p_ed->stack.stack[p_ed->stack.top]);
+
+#endif
+ if (next != 0)
+ {
+ if (next <= XML_ML_MAX_OBJ_TAG_ID)
+ p_st->obj = next;
+
+ if (p_st->prop_index <p_st->max_num_prop)
+ {
+ /* we do not use prefix in FTC */
+ p_cp->name = next;
+ p_cp->p_data = NULL;
+ p_cp->len = 0;
+ p_cp->level = p_ed->stack.top;
+ p_st->prop_index++;
+ }
+ else
+ ret = FALSE;
+ }
+ break;
+
+ case XML_ATTRIBUTE : /* attr-name="attr-value" */
+ curr = xml_ml_proc_attr(p_st, &p_ed->attr.name, &p_ed->stack);
+#if (defined(ML_DEBUG_XML) && ML_DEBUG_XML == TRUE)
+ xml_ml_debug_str(&p_ed->attr.name, dbg_name);
+ xml_ml_debug_str(&p_ed->attr.prefix, dbg_prefix);
+ xml_ml_debug_str(&p_ed->attr.value, dbg_value);
+ XML_TRACE_DEBUG4("[xml ml] XML_ATTRIBUTE: p:%s, name:%s, v:%s, curr:%x",
+ dbg_prefix, dbg_name, dbg_value, curr );
+ XML_TRACE_DEBUG2("top 1:x%x, stk:x%x", p_ed->stack.top, p_ed->stack.stack[p_ed->stack.top]);
+#endif
+ if ((curr != 0) && (curr != XML_ML_UNKNOWN_ID))
+ {
+ if (p_st->prop_index <p_st->max_num_prop)
+ {
+ p_cp->name = curr;
+ p_cp->p_data = p_ed->attr.value.p;
+ p_cp->len = p_ed->attr.value.len;
+ p_cp->level = p_ed->stack.top;
+ p_st->prop_index++;
+ }
+ else
+ ret = FALSE;
+ p_ed->stack.top--;
+ XML_TRACE_DEBUG2("top 2:x%x, stk:x%x", p_ed->stack.top, p_ed->stack.stack[p_ed->stack.top]);
+ }
+ break;
+
+ case XML_CHARDATA :
+#if (defined(ML_DEBUG_XML) && ML_DEBUG_XML == TRUE)
+ xml_ml_debug_str(&p_ed->ch_data.value, dbg_value);
+ XML_TRACE_DEBUG2("XML_CHARDATA: v:%s, last:%d", dbg_value, p_ed->ch_data.last);
+#endif
+ break;
+
+ case XML_ETAG : /* </tag-name> */
+ if (p_ed->stack.top > 0)
+ {
+ p_ed->stack.stack[p_ed->stack.top] = 0;
+ p_ed->stack.top--;
+ p_st->ended = (BOOLEAN) (p_ed->stack.top == 0);
+ }
+#if (defined(ML_DEBUG_XML) && ML_DEBUG_XML == TRUE)
+ xml_ml_debug_str(&p_ed->etag.name, dbg_name);
+ xml_ml_debug_str(&p_ed->etag.prefix, dbg_prefix);
+ XML_TRACE_DEBUG2("[xml ml] XML_ETAG: p:%s, name:%s", dbg_prefix, dbg_name);
+ XML_TRACE_DEBUG2("[xml ml] top:x%x, stk:x%x", p_ed->stack.top, p_ed->stack.stack[p_ed->stack.top]);
+#endif
+ break;
+
+ case XML_TAG_END: /* /> */
+ curr = p_ed->stack.stack[p_ed->stack.top];
+
+ if (p_st->prop_index <p_st->max_num_prop)
+ {
+ if (p_ed->empty_elem.end)
+ p_cp->name = XML_ML_TAG_END_ID;
+ else
+ p_cp->name = XML_ML_PAUSE_ID;
+ p_cp->p_data = NULL;
+ p_cp->len = 0;
+ p_cp->level = p_ed->stack.top;
+ p_st->prop_index++;
+ if (p_ed->empty_elem.end && p_ed->stack.top > 0)
+ {
+ p_ed->stack.top--;
+ }
+ }
+ else
+ ret = FALSE;
+
+#if (defined(ML_DEBUG_XML) && ML_DEBUG_XML == TRUE)
+ XML_TRACE_DEBUG4("[xml ml] XML_TAG_END: %d, top:x%x, stk:x%x, curr:x%x",
+ p_ed->empty_elem.end, p_ed->stack.top, p_ed->stack.stack[p_ed->stack.top], curr);
+#endif
+ break;
+
+ case XML_PARTIAL:
+ if (p_st->p_prop[p_st->prop_index-1].name != XML_ML_TAG_END_ID)
+ {
+ p_ed->stack.top--;
+#if (defined(ML_DEBUG_XML) && ML_DEBUG_XML == TRUE)
+ XML_TRACE_DEBUG0("[xml ml] adjust due to XML_PARTIAL");
+#endif
+ }
+ break;
+
+ case XML_COPY:
+ xml_ml_find_ch_n_copy( &p_ed->copy );
+ XML_TRACE_DEBUG1("[xml ml] XML_COPY: %s", p_ed->copy.last.p);
+ break;
+
+ default :
+#if (defined(ML_DEBUG_XML) && ML_DEBUG_XML == TRUE)
+ XML_TRACE_DEBUG1("[xml ml] default: XML event: %d", event);
+#endif
+ break;
+ }
+
+ return ret;
+}
+
+
+
+
+/**********************************************************************************
+** Function xml_ml_int_fill_msg_list
+** Description fill in file/folder structure.
+**
+** Parameters
+** Returns xx: > 0 : number of properties scanned, folder entry is added
+** = 0 : no end tag found, carry over to next parse
+** = -1: no dst_resource avaibale, all prop left to next parse
+** = -2: exceed max entry, no folder entry added
+**********************************************************************************/
+static INT16 xml_ml_int_fill_msg_list( tXML_ML_STATE * p_xud,
+ tXML_PROP *p_prop,
+ UINT16 *num_prop,
+ UINT8 **p_dst_data,
+ UINT16 *dst_len)
+{
+ INT16 xx;
+ UINT16 len;
+ BOOLEAN end = FALSE;
+ tXML_PROP *cur_prop = p_prop;
+ UINT8 *p_cur_offset = *p_dst_data;
+ BOOLEAN copy_attr_info;
+ BOOLEAN no_buf_left;
+ UINT8 **p_attr_data = NULL;
+ UINT16 *p_attr_len = NULL;
+
+ if ( p_xud->current_entry >= p_xud->max_entry )
+ return -2;
+
+ for (xx=0; (xx < *num_prop) && !end; xx++, cur_prop++)
+ {
+#if (defined(ML_DEBUG_XML) && ML_DEBUG_XML == TRUE)
+ /* XML_TRACE_DEBUG5( "[xml ml] fill: num_prop:%d, name id: x%x, p_prop: x%x, len: %d p_data:%s",
+ (*num_prop-xx) , cur_prop->name, cur_prop, cur_prop->len, cur_prop->p_data, ); */
+#endif
+ copy_attr_info = TRUE;
+ no_buf_left = FALSE;
+ len = cur_prop->len;
+
+ switch (cur_prop->name)
+ {
+ case XML_ML_HANDLE_ATTR_ID:
+ if ((*dst_len - len) > 0) /* enough data buffer available? */
+ {
+ p_attr_data = &(p_xud->p_entry[p_xud->current_entry].msg_handle) ;
+ p_attr_len = &(p_xud->p_entry[p_xud->current_entry].msg_handle_len);
+ }
+ else /* run out of dst buffer resource */
+ no_buf_left = TRUE;
+ break;
+
+ case XML_ML_SUBJECT_ATTR_ID:
+ if ((*dst_len - len) > 0) /* enough data buffer available? */
+ {
+ p_attr_data = &(p_xud->p_entry[p_xud->current_entry].subject) ;
+ p_attr_len = &(p_xud->p_entry[p_xud->current_entry].subject_len);
+ }
+ else /* run out of dst buffer resource */
+ no_buf_left = TRUE;
+ break;
+ case XML_ML_DATETIME_ATTR_ID:
+ if ((*dst_len - len) > 0) /* enough data buffer available? */
+ {
+ p_attr_data = &(p_xud->p_entry[p_xud->current_entry].datetime) ;
+ p_attr_len = &(p_xud->p_entry[p_xud->current_entry].datetime_len);
+ }
+ else /* run out of dst buffer resource */
+ no_buf_left = TRUE;
+ break;
+ case XML_ML_SENDER_NAME_ATTR_ID:
+ if ((*dst_len - len) > 0) /* enough data buffer available? */
+ {
+ p_attr_data = &(p_xud->p_entry[p_xud->current_entry].sender_name) ;
+ p_attr_len = &(p_xud->p_entry[p_xud->current_entry].sender_name_len);
+ }
+ else /* run out of dst buffer resource */
+ no_buf_left = TRUE;
+ break;
+ case XML_ML_SENDER_ADDRESSING_ATTR_ID :
+ if ((*dst_len - len) > 0) /* enough data buffer available? */
+ {
+
+ p_attr_data = &(p_xud->p_entry[p_xud->current_entry].sender_addressing) ;
+ p_attr_len = &(p_xud->p_entry[p_xud->current_entry].sender_addressing_len);
+ }
+ else /* run out of dst buffer resource */
+ no_buf_left = TRUE;
+ break;
+ case XML_ML_REPLYTO_ADDRESSING_ATTR_ID :
+ if ((*dst_len - len) > 0) /* enough data buffer available? */
+ {
+
+ p_attr_data = &(p_xud->p_entry[p_xud->current_entry].replyto_addressing) ;
+ p_attr_len = &(p_xud->p_entry[p_xud->current_entry].replyto_addressing_len);
+ }
+ else /* run out of dst buffer resource */
+ no_buf_left = TRUE;
+ break;
+ case XML_ML_RECIPIENT_NAME_ATTR_ID :
+ if ((*dst_len - len) > 0) /* enough data buffer available? */
+ {
+
+ p_attr_data = &(p_xud->p_entry[p_xud->current_entry].recipient_name) ;
+ p_attr_len = &(p_xud->p_entry[p_xud->current_entry].recipient_name_len);
+ }
+ else /* run out of dst buffer resource */
+ no_buf_left = TRUE;
+ break;
+ case XML_ML_RECIPIENT_ADDRESSING_ATTR_ID:
+ if ((*dst_len - len) > 0) /* enough data buffer available? */
+ {
+
+ p_attr_data = &(p_xud->p_entry[p_xud->current_entry].recipient_addressing) ;
+ p_attr_len = &(p_xud->p_entry[p_xud->current_entry].recipient_addressing_len);
+ }
+ else /* run out of dst buffer resource */
+ no_buf_left = TRUE;
+ break;
+ case XML_ML_TYPE_ATTR_ID :
+ if ((*dst_len - len) > 0) /* enough data buffer available? */
+ {
+
+ p_attr_data = &(p_xud->p_entry[p_xud->current_entry].type) ;
+ p_attr_len = &(p_xud->p_entry[p_xud->current_entry].type_len);
+ }
+ else /* run out of dst buffer resource */
+ no_buf_left = TRUE;
+ break;
+
+ case XML_ML_SIZE_ATTR_ID :
+ if ((*dst_len - len) > 0) /* enough data buffer available? */
+ {
+
+ p_attr_data = &(p_xud->p_entry[p_xud->current_entry].org_msg_size) ;
+ p_attr_len = &(p_xud->p_entry[p_xud->current_entry].org_msg_size_len);
+ }
+ else /* run out of dst buffer resource */
+ no_buf_left = TRUE;
+ break;
+ case XML_ML_TEXT_ATTR_ID:
+ if ((*dst_len - len) > 0) /* enough data buffer available? */
+ {
+
+ p_attr_data = &(p_xud->p_entry[p_xud->current_entry].text) ;
+ p_attr_len = &(p_xud->p_entry[p_xud->current_entry].text_len);
+ }
+ else /* run out of dst buffer resource */
+ no_buf_left = TRUE;
+ break;
+ case XML_ML_RECEPTION_STATUS_ATTR_ID:
+ if ((*dst_len - len) > 0) /* enough data buffer available? */
+ {
+
+ p_attr_data = &(p_xud->p_entry[p_xud->current_entry].reception_status) ;
+ p_attr_len = &(p_xud->p_entry[p_xud->current_entry].reception_status_len);
+ }
+ else /* run out of dst buffer resource */
+ no_buf_left = TRUE;
+ break;
+ case XML_ML_ATTACHMENT_SIZE_ATTR_ID :
+ if ((*dst_len - len) > 0) /* enough data buffer available? */
+ {
+
+ p_attr_data = &(p_xud->p_entry[p_xud->current_entry].attachment_size) ;
+ p_attr_len = &(p_xud->p_entry[p_xud->current_entry].attachment_size_len);
+ }
+ else /* run out of dst buffer resource */
+ no_buf_left = TRUE;
+ break;
+ case XML_ML_PRIORITY_ATTR_ID :
+ if ((*dst_len - len) > 0) /* enough data buffer available? */
+ {
+
+ p_attr_data = &(p_xud->p_entry[p_xud->current_entry].priority_status) ;
+ p_attr_len = &(p_xud->p_entry[p_xud->current_entry].priority_status_len);
+ }
+ else /* run out of dst buffer resource */
+ no_buf_left = TRUE;
+ break;
+ case XML_ML_READ_ATTR_ID :
+ if ((*dst_len - len) > 0) /* enough data buffer available? */
+ {
+
+ p_attr_data = &(p_xud->p_entry[p_xud->current_entry].read) ;
+ p_attr_len = &(p_xud->p_entry[p_xud->current_entry].read_len);
+ }
+ else /* run out of dst buffer resource */
+ no_buf_left = TRUE;
+ break;
+ case XML_ML_SENT_ATTR_ID :
+ if ((*dst_len - len) > 0) /* enough data buffer available? */
+ {
+
+ p_attr_data = &(p_xud->p_entry[p_xud->current_entry].sent) ;
+ p_attr_len = &(p_xud->p_entry[p_xud->current_entry].sent_len);
+ }
+ else /* run out of dst buffer resource */
+ no_buf_left = TRUE;
+ break;
+ case XML_ML_PROTECTED_ATTR_ID :
+ if ((*dst_len - len) > 0) /* enough data buffer available? */
+ {
+ p_attr_data = &(p_xud->p_entry[p_xud->current_entry].is_protected) ;
+ p_attr_len = &(p_xud->p_entry[p_xud->current_entry].is_protected_len);
+ }
+ else /* run out of dst buffer resource */
+ no_buf_left = TRUE;
+ break;
+
+ case XML_ML_TAG_END_ID:
+ /* -------------------- CUSTOMER SPECIFIC ---------------------- */
+ p_xud->current_entry++; /* increment only when end tag (/>) found */
+ copy_attr_info = FALSE;
+ XML_TRACE_DEBUG1("[xml ml]: current_entry cnt=%d",p_xud->current_entry);
+ break;
+ /* case XML_VERSION_ATTR_ID: */
+ default:
+ copy_attr_info = FALSE;
+ XML_TRACE_DEBUG1("[xml ml] unknown attrib: %d", cur_prop->name );
+ break;
+ }
+
+ if (copy_attr_info && p_attr_data && p_attr_len)
+ {
+ *p_attr_data = p_cur_offset;
+ *p_attr_len = len;
+
+ memcpy( (void *)*p_attr_data,
+ (const void *)cur_prop->p_data,
+ len );
+ (*p_attr_data)[len] = 0; /* null terminate string */
+ p_cur_offset += (len + 1);
+ *dst_len = *dst_len - (len + 1) ;
+
+ #if (defined(ML_DEBUG_XML) && ML_DEBUG_XML == TRUE)
+
+ XML_TRACE_DEBUG5("[xml ml]: Attr ID=%d val=[%s] len=%d level=%d dst_len_left=%d",
+ cur_prop->name,
+ *p_attr_data,
+ *p_attr_len,
+ cur_prop->level,
+ *dst_len);
+ #endif
+ }
+
+ if (no_buf_left)
+ {
+ #if (defined(ML_DEBUG_XML) && ML_DEBUG_XML == TRUE)
+ XML_TRACE_DEBUG0("Error!! No more buffer left to store the parser outputs");
+ #endif
+ return -1;
+ }
+
+ }
+#if (ML_DEBUG_XML == TRUE)
+ XML_TRACE_DEBUG2("[xml ml] fill_ml: end:%d, xx:%d", end, xx);
+#endif
+#if 0
+ /* if end tag not found -> split over two buffers. but parser will still show rest of
+ found properties. so return still found properties. */
+ if (end == FALSE)
+ xx = 0;
+#endif
+
+ /* keep track of current data buffer offset */
+ *p_dst_data = p_cur_offset;
+ return xx;
+} /* xml_ml_int_fill_msg_list() */
+
+
+/**********************************************************************************
+** Function xml_ml_int_fill_evt_data
+**
+** Description fill in MAP event report structure.
+**
+** Parameters
+** Returns
+**********************************************************************************/
+static tXML_ML_RES xml_ml_int_fill_evt_data( UINT8 op,
+ void *p_evt_data,
+ tXML_PROP **p_prop,
+ UINT16 *num_prop,
+ UINT8 **p_dst_data,
+ UINT16 *dst_len)
+{
+ tXML_ML_STATE *p_xud = (tXML_ML_STATE *)p_evt_data;
+ INT16 inc_prop;
+ UINT8 prop_name; /* Property name. */
+ tXML_PROP *cur_prop = *p_prop;
+ UINT8 *p_cur_offset = *p_dst_data;
+
+ tXML_ML_RES x_res = XML_ML_OK;
+ BOOLEAN x_no_res = FALSE; /* guard dest buffer resource */
+
+ if ( op == 0 || op > XML_ML_MAX_OBJ_TAG_ID || *num_prop == 0)
+ return XML_ML_ERROR;
+
+#if ML_DEBUG_XML
+ XML_TRACE_DEBUG2( "[xml ml] xml_ml_int_fill_evt_data op:%d, num_prop:%d",
+ op, *num_prop);
+#endif
+
+
+
+ while ( *num_prop > 0 && !x_no_res )
+ {
+#if (defined(ML_DEBUG_XML) && ML_DEBUG_XML == TRUE)
+ XML_TRACE_DEBUG2("end_prop:%d, name id: x%x", *num_prop, cur_prop->name);
+#endif
+ prop_name = cur_prop->name;
+ cur_prop++;
+ *num_prop -= 1;
+
+
+ switch ( prop_name )
+ {
+ case XML_ML_ELEM_ID:
+ XML_TRACE_DEBUG0("[xml ml] xml_etag_elem");
+ /* skip over version attribute which should always be 1.0. this is the top level */
+ break;
+
+ case XML_ML_MSG_ELEM_ID:
+ XML_TRACE_DEBUG0("[xml ml] xml_etag_elem");
+ inc_prop = xml_ml_int_fill_msg_list( p_xud,
+ cur_prop,
+ num_prop,
+ &p_cur_offset,
+ dst_len);
+ if (inc_prop == -1) /* no dst_buf available */
+ {
+ /* backup one more prop to obtain the skipped ml/file entry header */
+ cur_prop --;
+ *num_prop += 1;
+
+ x_res = XML_ML_DST_NO_RES;
+ x_no_res = TRUE;
+ }
+ else if (inc_prop == -2) /* exceed max entry */
+ {
+ x_no_res = TRUE;
+ x_res = XML_ML_OUT_FULL;
+ }
+ else /* found ml entry */
+ {
+ cur_prop += inc_prop;
+ *num_prop -= inc_prop;
+ }
+ break;
+
+ case XML_ML_PAUSE_ID:
+#if (ML_DEBUG_XML==TRUE)
+ XML_TRACE_DEBUG0( "[xml ml] xml_ml_int_fill_evt_data(): XML_ML_PAUSE_ID" );
+#endif
+ break;
+
+ case XML_ML_TAG_END_ID:
+#if (ML_DEBUG_XML==TRUE)
+ XML_TRACE_DEBUG0( "[xml ml] xml_ml_int_fill_evt_data(): XML_ML_TAG_END_ID" );
+#endif
+ break;
+
+ default:
+ XML_TRACE_DEBUG1( "[xml ml] xml_ml_int_fill_evt_data():unknown element: %d", prop_name );
+ break;
+ }
+ }
+
+ /* keep track of current filling position, and current available dst buffer */
+ *p_prop = cur_prop;
+ *p_dst_data = p_cur_offset;
+
+ return x_res;
+} /* xml_ml_int_fill_evt_data() */
+
+
+/**************************************************************************************
+** Function XML_MlInit
+**
+** Description Initialize xml parser state machine.
+**
+** Parameters p_xml_state: address of an xml parser state machine to be initialized,
+** allocate an additional space of size XML_ML_CARRY_OVER_LEN
+** right after *p_xml_state to hold carry over data.
+** p_entry : points start of output directory entry. caller needs do
+** free this memory
+** max_entry : max is 16 bit integer value which is the maximum number
+** of ml entries.
+
+**
+** Returns void
+**************************************************************************************/
+
+void XML_MlInit( tXML_ML_PARSER *p_xml_state,
+ tXML_ML_ENTRY *p_entry,
+ const UINT16 max_entry )
+{
+ XML_TRACE_DEBUG0("[xml ml] XML_MlInit");
+ /* Initialize the generic xml parser state machine.*/
+ XML_InitPars( &p_xml_state->xml, xml_ml_cback, &p_xml_state->xml_user_data );
+
+ /* User need to allocate an additional space of size XML_ML_CARRY_OVER_LEN */
+ /* right after *p_xml_state to hold carry over data. */
+ /* point to the end of the allocated buffer for p_xml_state, which is the */
+ /* beginning of buffer(XML_ML_CARRY_OVER_LEN) */
+ p_xml_state->xml.last_bfr.p = (UINT8 *)(p_xml_state + 1);
+ p_xml_state->xml.last_bfr.len = XML_ML_CARRY_OVER_LEN;
+
+ /* Initialize user data */
+ p_xml_state->xml_user_data.p_entry = p_entry;
+ p_xml_state->xml_user_data.current_entry = 0;
+ p_xml_state->xml_user_data.max_name_len = XML_UI_ENTRY_MAX_NAME_LEN + 1;
+ p_xml_state->xml_user_data.max_entry = (UINT16)max_entry;
+ p_xml_state->xml_user_data.prop_num = 0;
+}
+
+
+/**************************************************************************************
+** Function XML_MlParse
+**
+** Description This function is called to parse the xml data received from OBEX
+** into folder entries associated with properties value. It can also be
+** used as clean up function to delete left over data from previous parse.
+** This clean up function is typically used when application runs out of
+** resource and decides to discard extra xml data received.
+**
+** Parameters p_xml_state: pointer to a xml parser initialized by XML_MlInit().
+** xml_data: valid pointer to OBEX list data in xml format.
+** xml_len: length of the package, must be non-zero value.
+** dst_data: valid pointer to the buffer for holding converted folder entry name.
+ When dst_data is NULL, clean up all remaining data in the parser.
+** dst_len: pointer to the length of dst_data buffer, its carry out value
+** is the number of bytes remaining buffer.When dst_len is NULL,
+** it will cause to flush the internal data in the parser.
+** num_entries: current number of entries, in the end it is the total number of entries
+**
+** Returns tXML_ML_RES (see xml_erp.h)
+** XML_PENDING: parsing not completed
+** XML_END_LIST: found /folder-listing but no final flag detected
+** XML_ML_OUT_FULL: reached max_entry -> do not call parser anymore!!! dump data
+** XML_ML_DST_NO_RES : run out of dst buffer resource while
+** some xml data still remains.
+
+**************************************************************************************/
+tXML_ML_RES XML_MlParse( tXML_ML_PARSER *p_xml_state,
+ UINT8 *xml_data, UINT16 xml_len,
+ UINT8 *dst_data, UINT16 *dst_len,
+ UINT16 *num_entries )
+{
+ tXML_OS xos;
+ BOOLEAN is_remain = TRUE;
+ tXML_MUL_STATE *p_xml = &p_xml_state->xml;
+ tXML_ML_STATE *p_st = &p_xml_state->xml_user_data;
+ tXML_ML_RES x_res = XML_ML_OK;
+ tXML_RESULT res = XML_NO_PROP;
+ UINT16 max_num_prop = GKI_BUF3_SIZE/sizeof(tXML_PROP); /* i hope this is sufficient for 1 */
+
+
+#if (defined(ML_DEBUG_XML) && ML_DEBUG_XML == TRUE)
+ int xx;
+ UINT8 dbg_buf[ML_DEBUG_LEN];
+ tXML_STR str;
+#endif
+
+ XML_TRACE_DEBUG0("[xml ml] XML_MlParse");
+ /* if dst_data is NULL, clean up remaining data */
+ if (!dst_data || !dst_len)
+ {
+ /* clean out remained xml data left over from last parse */
+ if (p_xml_state->xml_user_data.p_prop )
+ {
+ GKI_freebuf( p_st->p_prop );
+ p_st->p_prop = p_st->offset_prop = NULL;
+ p_st->prop_num = 0;
+ }
+#if (ML_DEBUG_XML == TRUE)
+ XML_TRACE_DEBUG0( "[xml ml] XML_MlParse() Clean up left over!");
+#endif
+ return x_res;
+ }
+
+ /* if illegal OBEX data or dst buffer pointer received, return ERROR */
+ if (xml_len == 0 || !xml_data)
+ {
+ return XML_ML_ERROR;
+ }
+
+ /* XML_MlParse receive new xml data, allocate buffer to hold parsed prop */
+ if (p_st->offset_prop == NULL)
+ {
+
+#if (ML_DEBUG_XML == TRUE)
+ XML_TRACE_DEBUG0( "[xml ml] XML_MlParse() Receive New Data!");
+ XML_TRACE_DEBUG2( "[xml ml] XML_data start[%x] end [%x]",xml_data, xml_data+xml_len);
+#endif
+ is_remain = FALSE;
+ if ( NULL!= (p_st->p_prop = (tXML_PROP *)GKI_getbuf( GKI_BUF3_SIZE ) ) )
+ {
+ /* pointing next prop to be converted into file entry */
+ p_st->prop_num = 0;
+ }
+ else
+ {
+ GKI_freebuf( p_xml_state );
+ x_res = XML_ML_NO_RES;
+ return x_res;
+ }
+ }
+#if (ML_DEBUG_XML == TRUE)
+ else
+ {
+ XML_TRACE_DEBUG0( "[xml ml] XML_MlParse(): Keep cleaning up old xml data !");
+ }
+#endif
+ /* update the data address */
+ xos.p_begin = xml_data;
+ xos.p_end = xml_data + xml_len;
+
+ while ( res == XML_NO_PROP )
+ {
+ /* if no remaining data in p_st->p_prop, parse new xml data */
+ if (!is_remain)
+ {
+ p_st->max_num_prop = max_num_prop;
+ p_st->prop_index = 0;
+ res = XML_MulParse( p_xml, &xos );
+
+
+#if (ML_DEBUG_XML == TRUE)
+ XML_TRACE_DEBUG4( "xml_ml_parse obj: %x, max: %d, num: %d, res: %d",
+ p_st->obj, max_num_prop, p_st->prop_index, res);
+ if (res != 0)
+ {
+ XML_TRACE_DEBUG1( "XML_MulParse Parsing: %d !!!", res);
+ }
+
+ for (xx=0; xx<p_st->prop_index; xx++)
+ {
+ if ( p_st->p_prop[xx].name < XML_ML_MAX_ID )
+ {
+ str.p = p_st->p_prop[xx].p_data;
+ str.len = p_st->p_prop[xx].len;
+ xml_ml_debug_str(&str, dbg_buf);
+ XML_TRACE_DEBUG5( "[xml ml] parsed: index[%d]:%d:%s: %s(%d)", p_st->prop_index-xx, p_st->p_prop[xx].level,
+ xml_ml_ttbl[p_st->p_prop[xx].name].p_name, dbg_buf, p_st->p_prop[xx].len);
+ }
+ else
+ {
+ XML_TRACE_DEBUG3( "[xml ml] internal prop: %d:%d:%d", xx, p_st->p_prop[xx].level,
+ p_st->p_prop[xx].name );
+ }
+ }
+#endif
+ p_st->prop_num = p_st->prop_index ;
+ p_st->offset_prop = p_st->p_prop;
+ }
+ else
+ {
+ /* This is left over data, pick up the result from the previous parse */
+ res = p_xml->pars_res;
+ }
+
+ if ( res != XML_OBJ_ST_EMPTY )
+ {
+ x_res = xml_ml_int_fill_evt_data( p_st->obj, p_st, &p_st->offset_prop, &p_st->prop_num, &dst_data, dst_len );
+
+ if ( (XML_ML_OK == x_res) && (XML_NO_END == res) )
+ {
+ /* XML_NO_END means that the xml is not completly finished and fill returns
+ ok when when partial filling has been ok */
+ x_res = XML_ML_PENDING;
+ }
+
+ /* all parsed xml data has been converted into file entry */
+ /* or exceed max entry number , break the parsing loop */
+ if (XML_ML_OUT_FULL != x_res && XML_ML_DST_NO_RES != x_res)
+ {
+ is_remain = FALSE;
+ }
+ else
+ break;
+ }
+ } /* while */
+
+ /* free property table. at next call a new one is allocated */
+ if ((x_res != XML_ML_DST_NO_RES && p_st->p_prop) ||
+ XML_ML_OUT_FULL == x_res)
+ {
+ GKI_freebuf( p_st->p_prop );
+ p_st->p_prop = NULL;
+ p_st->offset_prop = NULL;
+ }
+
+ if ( x_res != XML_ML_DST_NO_RES && p_st->ended)
+ {
+ /* this should happen on the same time as final flag in fact */
+ x_res = XML_ML_END_LIST; /* found closing /ml-listing */
+ }
+
+ *num_entries = p_st->current_entry; /* report number of entries found. only when ended is true
+ application really should be interested! */
+ return x_res;
+}
+
diff --git a/stack/xml/xml_parse.c b/stack/xml/xml_parse.c
new file mode 100644
index 0000000..3f9e2e1
--- /dev/null
+++ b/stack/xml/xml_parse.c
@@ -0,0 +1,1502 @@
+/*****************************************************************************
+**
+** Name: xml_parse.c
+**
+** File: XML Parser
+**
+** Copyright (c) 2000-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include "bt_target.h"
+#include "xml_pars_api.h"
+#include "data_types.h"
+#include "bt_types.h"
+/* The XML Parser is dependent on the Object Store. At present
+** the object store resides in GOEP and hence the parser is
+** dependent on GOEP. The parser only uses the Object Store
+** in GOEP, so if the Object Store is separated from GOEP in the
+** future, the parser will not be dependent on GOEP.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef BIP_TRACE_XML
+#define BIP_TRACE_XML FALSE
+#endif
+
+#if (defined(BIP_TRACE_XML) && BIP_TRACE_XML == TRUE)
+#define XML_TRACE_DEBUG0(m) {BT_TRACE_0(TRACE_LAYER_GOEP, TRACE_TYPE_DEBUG, m);}
+#define XML_TRACE_DEBUG1(m,p1) {BT_TRACE_1(TRACE_LAYER_GOEP, TRACE_TYPE_DEBUG, m,p1);}
+#define XML_TRACE_DEBUG2(m,p1,p2) {BT_TRACE_2(TRACE_LAYER_GOEP, TRACE_TYPE_DEBUG, m,p1,p2);}
+#define XML_TRACE_DEBUG3(m,p1,p2,p3) {BT_TRACE_3(TRACE_LAYER_GOEP, TRACE_TYPE_DEBUG, m,p1,p2,p3);}
+#define XML_TRACE_DEBUG4(m,p1,p2,p3,p4) {BT_TRACE_4(TRACE_LAYER_GOEP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4);}
+#define XML_TRACE_DEBUG5(m,p1,p2,p3,p4,p5) {BT_TRACE_5(TRACE_LAYER_GOEP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5);}
+#define XML_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) {BT_TRACE_6(TRACE_LAYER_GOEP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5,p6);}
+#else
+#define XML_TRACE_DEBUG0(m)
+#define XML_TRACE_DEBUG1(m,p1)
+#define XML_TRACE_DEBUG2(m,p1,p2)
+#define XML_TRACE_DEBUG3(m,p1,p2,p3)
+#define XML_TRACE_DEBUG4(m,p1,p2,p3,p4)
+#define XML_TRACE_DEBUG5(m,p1,p2,p3,p4,p5)
+#define XML_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6)
+#endif
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+#define XML_ST '<'
+#define XML_GT '>'
+#define XML_QM '?'
+#define XML_EX '!'
+#define XML_EM '/' /* End Mark */
+#define XML_CO ':'
+#define XML_EQ '='
+#define XML_SQ '\''
+#define XML_DQ '"'
+#define XML_AM '&'
+#define XML_SC ';'
+#define XML_PD '#'
+#define XML_HX 'x'
+#define XML_HY '-'
+#define XML_LB '['
+
+#define XML_LT_STR "lt"
+#define XML_GT_STR "gt"
+#define XML_AMP_STR "amp"
+#define XML_APOS_STR "apos"
+#define XML_QUOT_STR "quot"
+
+#define XML_QTAG_END_STR "?>"
+#define XML_COMM_STR "--"
+#define XML_COMM_END_STR "-->"
+#define XML_CDS_STR "[CDATA["
+#define XML_CDS_END_STR "]]>"
+#define XML_DOCT_STR "<'\""
+
+static const UINT8 xml_name_srch[] = ":=/> \t\n\r";
+
+
+/*****************************************************************************
+** Type Definitions
+*****************************************************************************/
+
+enum
+{
+ XML_PASS_WS,
+ XML_SKIP_WS,
+ XML_NORM_WS
+};
+typedef UINT16 tXML_WS_OP;
+
+
+
+/*****************************************************************************
+** Globals
+**
+** The global below is used as the buffer set (tXML_BFR_SET) in a local
+** variable (of type tXML_MUL_STATE) in XML_Parse. The buffer set memory, is
+** separated from the rest of tXML_MUL_STATE to make it easy to change the
+** allocation of its memory if found necessary. See xml_alloc_bfr_set.
+*****************************************************************************/
+
+/*****************************************************************************
+** Macro Functions
+*****************************************************************************/
+
+#define XML_EOS(p_st) ((p_st)->curr_res <= 0) /* End Of Store */
+/* white space: " ", \t, \r, \n */
+#define XML_IS_WS(c) (((c) == 0x20) || ((c) == 0x9) || \
+ ((c) == 0xD) || ((c) == 0xA) || \
+ ((c) == 0x00) )
+
+
+/*****************************************************************************
+** Function Prototypes
+*****************************************************************************/
+
+static BOOLEAN xml_get_next(tXML_MUL_STATE *, tXML_WS_OP);
+
+static BOOLEAN xml_find_ch(tXML_MUL_STATE *, UINT8, tXML_WS_OP);
+
+static void xml_incr_pars_res(tXML_MUL_STATE *, tXML_RESULT);
+
+static void xml_set_bfr(tXML_MUL_STATE *, UINT8);
+
+/* parsing static functions */
+
+static BOOLEAN xml_elems(tXML_MUL_STATE *, BOOLEAN);
+
+static BOOLEAN xml_qm_elem(tXML_MUL_STATE *);
+
+static BOOLEAN xml_ex_elem(tXML_MUL_STATE *, BOOLEAN);
+
+static BOOLEAN xml_tag_elem(tXML_MUL_STATE *);
+
+static BOOLEAN xml_etag_elem(tXML_MUL_STATE *);
+
+#define XML_SET_CLEAR 0
+#define XML_SET_NAME 1
+#define XML_SET_VALUE 2
+
+
+
+
+/*****************************************************************************
+** API Functions
+*****************************************************************************/
+
+void XML_InitPars(tXML_MUL_STATE *p_st, tXML_CBACK xml_cback, void *p_usr_data)
+{
+ memset(p_st, 0, sizeof(tXML_MUL_STATE));
+ p_st->cback = xml_cback;
+ p_st->p_usr_data = p_usr_data;
+
+ /* by memset()
+ p_st->p_data_bfr = NULL;
+ p_st->next_token = 0;
+ p_st->curr_res = 0;
+ p_st->pars_res = XML_SUCCESS;
+ p_st->skip_next_nl = FALSE;
+
+ p_st->prefix.p = NULL;
+ p_st->name.p = NULL;
+ p_st->value.p = NULL;
+ p_st->prefix.len= 0;
+ p_st->name.len = 0;
+ p_st->value.len = 0;
+
+ p_st->status = XML_STS_INIT;
+ */
+}
+
+
+
+/*****************************************************************************
+**
+** Function XML_MulParse
+**
+** Description
+** The current implementation of the xml_pars_api supports only those
+** XML-contructs needed in BPP SOAP-messages. The parser must have a
+** small footprint and is therefore small and simple.
+**
+** According to SOAP a message must not contain the doctypedecl construct
+** (production) and it must not contain Processing Instructions (PI
+** production), i.e. these constructs are not supported. In addition,
+** CDATA sections, any external or internal entities and the XML
+** Declaration are not supported (not used in BPP). Should any of these
+** be included in a message being parsed, they will be reported returning
+** a warning code. The parser will then try to find the next tag.
+** When the parser reports an XML-event using the callback it will always
+** continue, even if the callback returns false. All strings in event
+** data passed with the callback are limited to 64 bytes in size, except
+** the prefix string which has 32 as max size. Consequtive XML_CHARDATA
+** events are not supported. Leading and trailing white space is removed
+** from the value string before sending the XML_CHARDATA event.
+**
+** This function and also all other helping static parsing functions use
+** more than one return statement in a function. The reason is that
+** a parse error has been found and to exit as soon as possible.
+** If one had used only one return in each function, the path
+** representing a correct xml syntax had been expressed with very deeply
+** nested if-statements.
+**
+** Parameters
+** see h-file
+** Returns
+** see h-file
+*****************************************************************************/
+
+tXML_RESULT XML_MulParse(tXML_MUL_STATE *p_st, tXML_OS *p_os)
+{
+ BOOLEAN found;
+ BOOLEAN query, partial = FALSE;
+ BOOLEAN parse_ok = TRUE;
+ int keep_size;
+ tXML_RESULT res = XML_SUCCESS;
+ tXML_RESULT old_pars_res;
+
+ p_st->curr_res = 1; /* not EOS */
+ memcpy(&p_st->xml_os, p_os, sizeof(tXML_OS));
+ old_pars_res = p_st->pars_res;
+ p_st->pars_res = XML_SUCCESS;
+ p_st->prefix.len = 0;
+ p_st->name.len = 0;
+ p_st->value.len = 0;
+ p_st->p_last_stm = 0;
+ p_st->p_copy = 0;
+
+#if ((defined (BIP_TRACE_XML) && BIP_TRACE_XML == TRUE) || (defined FOLDER_DEBUG_XML && FOLDER_DEBUG_XML== TRUE))
+ XML_TRACE_DEBUG4("XML_MulParse status:%d, pars_res: %d, begin:%x, end:x%x",
+ p_st->status, old_pars_res, p_os->p_begin, p_os->p_end);
+#endif
+
+ /* this do-while(0) loop is to avoid too many return statements in this routine.
+ * it's easier to "cleanup" with only one return statement */
+ if(p_st->status == XML_STS_INIT)
+ {
+
+ p_st->p_cur = p_os->p_begin;
+#if ((defined (BIP_TRACE_XML) && BIP_TRACE_XML == TRUE) || (defined FOLDER_DEBUG_XML && FOLDER_DEBUG_XML== TRUE))
+ XML_TRACE_DEBUG1("p_cur:x%x", p_st->p_cur);
+#endif
+ do
+ {
+ if (!xml_get_next(p_st, XML_PASS_WS)) /* obj store empty or err */
+ {
+ res = XML_OBJ_ST_EMPTY;
+ break;
+ }
+
+ found = FALSE;
+ while (!XML_EOS(p_st) && !found)
+ { /* skip all but top element */
+ if (!xml_find_ch(p_st, XML_ST, XML_PASS_WS) ||
+ !xml_get_next(p_st, XML_PASS_WS))
+ {
+ res = XML_ERR;
+ break;
+ }
+
+ if (p_st->next_token == XML_QM)
+ {
+ parse_ok = xml_qm_elem(p_st);
+ }
+ else if (p_st->next_token == XML_EX)
+ {
+ parse_ok = xml_ex_elem(p_st, TRUE);
+ }
+ else if (p_st->next_token == XML_EM)
+ {
+ parse_ok = FALSE;
+ if (!xml_get_next(p_st, XML_PASS_WS))
+ {
+ res = XML_ERR;
+ break;
+ }
+ }
+ else
+ {
+ found = TRUE;
+ parse_ok = TRUE;
+ }
+
+ if (!parse_ok)
+ xml_incr_pars_res(p_st, XML_ERR);
+ }
+ } while (0);
+ p_st->status = XML_STS_1STM;
+ }
+ else if(old_pars_res == XML_NO_PROP)
+ {
+ }
+ else
+ {
+#if ((defined (BIP_TRACE_XML) && BIP_TRACE_XML == TRUE) || (defined FOLDER_DEBUG_XML && FOLDER_DEBUG_XML== TRUE))
+ XML_TRACE_DEBUG2("p_st->last_bfr.p:x%x, p_st->used_last_bfr:%d",
+ p_st->last_bfr.p, p_st->used_last_bfr);
+#endif
+
+/* if there was some data left, read it here. */
+ if(p_st->partial_st.last_bfr.p && p_st->partial_st.used_last_bfr )
+ {
+ memcpy(p_st->last_bfr.p, p_st->partial_st.last_bfr.p, p_st->partial_st.used_last_bfr);
+ p_st->used_last_bfr = p_st->partial_st.used_last_bfr;
+ p_st->last_bfr.p[p_st->partial_st.used_last_bfr] = 0;
+ p_st->event_data.part.parse = p_st->partial_st.event_data.part.parse;
+
+ /* set length to 0 */
+ p_st->partial_st.used_last_bfr = 0;
+ XML_TRACE_DEBUG1("retrieved PARTIAL data = [%s]\n", p_st->last_bfr.p);
+
+ p_st->p_cur = p_st->last_bfr.p;
+ /* continuation packet */
+ /* read a ch, setup xml_set_bfr */
+ xml_get_next(p_st, XML_PASS_WS);
+ p_st->event_data.copy.p_begin = p_st->xml_os.p_begin;
+ p_st->event_data.copy.last.p = p_st->last_bfr.p;
+ p_st->event_data.copy.last.len = p_st->used_last_bfr;
+ p_st->cback(XML_COPY, &(p_st->event_data), p_st->p_usr_data);
+ }
+ else
+ {
+ if(p_st->used_last_bfr == 0)
+ {
+ p_st->p_cur = p_os->p_begin;
+ xml_get_next(p_st, XML_PASS_WS);
+ }
+ else
+ return XML_NO_MEM;
+ }
+#if ((defined (BIP_TRACE_XML) && BIP_TRACE_XML == TRUE) || (defined FOLDER_DEBUG_XML && FOLDER_DEBUG_XML== TRUE))
+ XML_TRACE_DEBUG1("p_st->p_cur:x%x", p_st->p_cur);
+#endif
+ }
+
+ XML_TRACE_DEBUG0("XML_MulParse end while");
+
+ if(res == XML_SUCCESS)
+ {
+ /* here we found "<(a-z)" */
+ if (!XML_EOS(p_st))
+ {
+ if(p_st->status == XML_STS_1STM)
+ {
+ /* remeber the beginning position right after '<' in the first line */
+ /* if the first line can't be parsed at first round, save it to the second parse */
+ p_st->p_copy = p_st->p_cur - 1;
+ parse_ok = xml_tag_elem(p_st);
+ }
+
+ /* parsed the first line */
+ XML_TRACE_DEBUG0("XML_MulParse exit xml_tag_elem");
+
+ if (!parse_ok)
+ {
+ query = p_st->cback(XML_QUERY, &(p_st->event_data), p_st->p_usr_data);
+
+ /* if first line parsing is not completed while reach the end of stack, ERROR occurs */
+ if (query == TRUE)
+ xml_incr_pars_res(p_st, XML_ERR);
+ else /* first line parsing to be continued, copy partial data at later point*/
+ partial = TRUE;
+ }
+ else /* first line is parsed ok, change parsing status */
+ p_st->status = XML_STS_1TAG;
+
+
+
+ if (!XML_EOS(p_st) && parse_ok)
+ {
+ parse_ok = xml_elems(p_st, parse_ok);
+ query = p_st->cback(XML_QUERY, &(p_st->event_data), p_st->p_usr_data);
+ if (parse_ok == FALSE || query == FALSE)
+ {
+ partial = TRUE;
+
+ }
+ else
+ p_st->status = XML_STS_DONE;
+ }
+
+ /* copy partial data if any */
+ if (partial)
+ {
+ if(p_st->pars_res == XML_NO_PROP)
+ {
+ p_st->p_cur = p_st->p_copy;
+ p_st->event_data.part.parse = p_st->pars_res;
+ p_st->event_data.part.p_keep = p_st->p_cur;
+ XML_TRACE_DEBUG1("p_st->p_cur:x%x (last_stm)", p_st->p_cur);
+ p_st->cback(XML_PARTIAL, &(p_st->event_data), p_st->p_usr_data);
+ xml_incr_pars_res(p_st, XML_NO_END);
+ }
+ else
+ {
+ if( p_st->last_bfr.p &&
+ (p_st->p_copy > p_st->xml_os.p_begin) &&
+ (p_st->p_copy < p_st->xml_os.p_end) )
+ {
+ keep_size = p_st->xml_os.p_end - p_st->p_copy;
+ if(keep_size < p_st->last_bfr.len)
+ {
+ /* store the partial data to a temporary buffer,
+ NOT to the queue of buffers as it would overwrite current ones! */
+ if(p_st->partial_st.last_bfr.p )
+ {
+ XML_TRACE_DEBUG0("Store partial data\n");
+ BCM_STRNCPY_S((char *)p_st->partial_st.last_bfr.p, 512, (char *)p_st->p_copy, keep_size);
+ p_st->partial_st.used_last_bfr= keep_size;
+ p_st->partial_st.last_bfr.p[keep_size] = 0;
+ p_st->partial_st.event_data.part.parse = p_st->pars_res;
+ p_st->partial_st.event_data.part.p_keep= p_st->last_bfr.p;
+ }
+ else
+ XML_TRACE_DEBUG0("ERROR to store partial data");
+
+ p_st->cback(XML_PARTIAL, &(p_st->event_data), p_st->p_usr_data);
+ xml_incr_pars_res(p_st, XML_NO_END);
+ }
+ }
+ }/* else NO_PROP */
+ } /* end of partial */
+ } /* end of !XML_EOS(p_st) */
+ } /* end of res == XML_SUCCESS */
+
+
+ return p_st->pars_res;
+}
+
+
+/*****************************************************************************
+** Static Functions
+*****************************************************************************/
+
+
+
+/*****************************************************************************
+**
+** Function xml_set_bfr
+**
+** Description
+** Sets the buffer that is going to be used when tokens are pushed from
+** p_st->next_token into some buffer in the buffer set.
+**
+** Parameters
+** p_st (in/out) : the parser state
+** p_bfr (in) : the buffer that will get all tokens (characters)
+** NULL is allowed in which case no buffer is used.
+** bfr_max_ind (in) : the max index into the buffer in which a non-null
+** char may be stored
+**
+** Returns
+** -
+*****************************************************************************/
+static void xml_set_bfr(tXML_MUL_STATE *p_st, UINT8 set)
+{
+ switch(set)
+ {
+ case XML_SET_NAME:
+ p_st->name.p = p_st->p_cur - 1;
+ p_st->p_data_bfr = p_st->name.p;
+ p_st->name.len = 0;
+ break;
+ case XML_SET_VALUE:
+ p_st->value.p = p_st->p_cur - 1;
+ p_st->p_data_bfr = p_st->value.p;
+ p_st->value.len = 0;
+ break;
+ default:
+ p_st->p_data_bfr = NULL;
+ }
+}
+
+
+/*****************************************************************************
+**
+** Function xml_write_bfr
+**
+** Description
+** Pushes (copies) the character from p_st->next_token to the buffer, if
+** any, that has been set calling xml_set_bfr.
+**
+** Parameters
+** p_st (in/out) : the parser state
+**
+** Returns
+** -
+*****************************************************************************/
+
+static void xml_write_bfr(tXML_MUL_STATE *p_st)
+{
+ if (p_st->p_data_bfr)
+ {
+ if(p_st->p_data_bfr == p_st->name.p)
+ p_st->name.len++;
+ else
+ p_st->value.len++;
+ }
+}
+
+
+/*****************************************************************************
+**
+** Function xml_incr_pars_res
+**
+** Description
+** Sets the final parsing result if the new_res provided has
+** higher rank than the current parsing result.
+**
+** Parameters
+** p_st (in/out) : the parser state
+** new_res (in) : the new parsing result
+**
+** Returns
+** -
+*****************************************************************************/
+
+static void xml_incr_pars_res(tXML_MUL_STATE *p_st, tXML_RESULT new_res)
+{
+ if (new_res > p_st->pars_res)
+ {
+ switch(p_st->pars_res)
+ {
+ /* preserve these error messages */
+ case XML_OBJ_ST_EMPTY:
+ case XML_NO_MEM: /* no last_bfr.p, and the tXML_MUL_STATE is not in init */
+ case XML_NO_PROP: /* run out of tXML_PROP */
+ break;
+
+ default:
+ /*
+ case XML_SUCCESS:
+ case XML_WARNING:
+ case XML_ERR:
+ */
+ p_st->pars_res = new_res;
+ break;
+ }
+ }
+}
+
+
+/*****************************************************************************
+**
+** Function xml_read_char
+**
+** Description
+*****************************************************************************/
+static void xml_read_char(tXML_MUL_STATE *p_st)
+{
+ BOOLEAN get_new = FALSE;
+
+ if (p_st->p_cur && p_st->p_cur >= p_st->last_bfr.p && p_st->p_cur < (p_st->last_bfr.p + p_st->used_last_bfr))
+ {
+ /* left over from previous parse */
+ p_st->next_token = *p_st->p_cur;
+ if(p_st->next_token == 0)
+ {
+ /* leftover is done, use the new one */
+ p_st->p_cur = p_st->xml_os.p_begin;
+ p_st->last_bfr.p[0] = 0;
+ p_st->used_last_bfr = 0;
+ get_new = TRUE;
+ }
+ else
+ {
+ p_st->p_cur++;
+ p_st->curr_res = 1;
+ }
+ }
+ else
+ {
+ if(p_st->p_cur == (p_st->last_bfr.p + p_st->used_last_bfr))
+ {
+ p_st->used_last_bfr = 0;
+ p_st->p_cur = p_st->xml_os.p_begin;
+ }
+ get_new = TRUE;
+ }
+
+ if(get_new)
+ {
+ if(p_st->p_cur && p_st->p_cur < p_st->xml_os.p_end)
+ {
+ /* use buffer given to XML_Parse */
+ p_st->next_token = *p_st->p_cur;
+ p_st->p_cur++;
+ p_st->curr_res = 1;
+ }
+ else
+ p_st->curr_res = 0;
+ }
+
+
+/*
+ XML_TRACE_DEBUG4("xml_read_char p_cur: x%x, curr_res:%d, get_new:%d, token:%c",
+ p_st->p_cur, p_st->curr_res, get_new, p_st->next_token);
+*/
+}
+
+/*****************************************************************************
+**
+** Function xml_get_next
+**
+** Description
+** Writes the character in p_st->next_token to the current buffer if set.
+** Then the next character is read from the Object Store into
+** p_st->next_token. The first time get_next is called, the current
+** buffer must be NULL, i.e p_st->data_bfr must be NULL.
+**
+** xml_get_next handles end-of-line as specified in the xml spec. It
+** passes, skips or normalises (p.29 in XML spec) white spaces (ws)
+** as specified in the ws_op param. Note, the ws_op applies when
+** getting one (or many characters) from Object Store into the
+** p_st->next_token. It does not apply when pushing the (initial)
+** p_st->next_token to the current buffer.
+**
+** The characters are read one by one from the Object Store.
+** Presently this is not anticipated to cause any problems
+** regarding reading speed. Should it become a problem in the
+** future, a new buffer could be introduced into which a chunk
+** of characters could be put, using one Object Store read call.
+** The get_next function would then get the next character from
+** the new buffer.
+**
+** Parameters
+** p_st (in/out) : the parser state
+** ws_op (in) : the requested white space handling.
+**
+** Returns
+** True if a character was successfully read into p_st->next_token.
+** False otherwise.
+*****************************************************************************/
+
+static BOOLEAN xml_get_next(tXML_MUL_STATE *p_st, tXML_WS_OP ws_op)
+{
+ xml_write_bfr(p_st);
+ do
+ {
+ xml_read_char(p_st);
+ } while ((ws_op == XML_SKIP_WS) && XML_IS_WS(p_st->next_token) &&
+ !XML_EOS(p_st));
+
+
+ /* handle end-of-line if any after the do-while above */
+
+ if (!XML_EOS(p_st) && (p_st->next_token == 0xA) && p_st->skip_next_nl)
+ { /* we have previously found 0xD (cr) and have set the state var
+ ** p_st->skip_next_nl,see below
+ */
+ xml_read_char(p_st);
+ }
+ p_st->skip_next_nl = FALSE;
+
+ if (XML_EOS(p_st))
+ {
+ p_st->next_token = 0;
+ return FALSE;
+ }
+
+ if (p_st->next_token == 0xD)
+ {
+ p_st->next_token = 0xA;
+ p_st->skip_next_nl = TRUE;
+ }
+
+ if ((ws_op == XML_NORM_WS) &&
+ ((p_st->next_token == 0xA) || (p_st->next_token == 0x9)))
+ {
+ p_st->next_token = 0x20;
+ }
+
+ return TRUE;
+}
+
+
+/*****************************************************************************
+**
+** Function xml_find_ch
+**
+** Description
+** Searches for the character given in ch. It starts searching in
+** p_st->next_token and if not found it gets characters from the Object
+** Store until ch is in p_st->next_token.
+**
+** Parameters
+** p_st (in/out) : the parser state
+** ch (in) : the character to search for
+** ws_op (in) : the requested white space handling when getting chars
+**
+** Returns
+** True if the character was found.
+** False otherwise.
+*****************************************************************************/
+
+static BOOLEAN xml_find_ch(tXML_MUL_STATE *p_st, UINT8 ch, tXML_WS_OP ws_op)
+{
+ while (!XML_EOS(p_st) && (p_st->next_token != ch))
+ xml_get_next(p_st, ws_op);
+ return (BOOLEAN) !XML_EOS(p_st);
+}
+
+
+/*****************************************************************************
+**
+** Function xml_find_ch_n
+**
+** Description
+** Same function as xml_find_ch, except that any character in p_str
+** that is found will stop the search.
+**
+** Parameters
+** p_st (in/out) : the parser state
+** p_str (in) : the string containing the characters searched for.
+** Must not be NULL or an empty string.
+**
+** Returns
+** True if any of the characters in p_str was found.
+** Fase otherwise.
+*****************************************************************************/
+
+static BOOLEAN xml_find_ch_n(tXML_MUL_STATE *p_st, const UINT8 *p_str)
+{
+ const UINT8 *p_tmp;
+
+ while (!XML_EOS(p_st))
+ {
+ for (p_tmp = p_str; *p_tmp; p_tmp++)
+ {
+ if (p_st->next_token == *p_tmp)
+ return TRUE;
+ }
+ xml_get_next(p_st, XML_PASS_WS);
+ }
+ return FALSE;
+}
+
+
+/*****************************************************************************
+**
+** Function xml_find_str
+**
+** Description
+** Searches for p_str (i.e the exact sequence of characters in p_str) in
+** the input from Object Store. The function ends with the character
+** succeeding p_str in the input, (i.e that char is in p_st->next_token
+** upon return) or with XML_EOS.
+**
+** Parameters
+** p_st (in/out) : the parser state
+** p_str (in) : the string to search for and pass by.
+** Must not be NULL or an empty string.
+**
+** Returns
+** True if the string was found.
+** False otherwise.
+*****************************************************************************/
+
+static BOOLEAN xml_find_str(tXML_MUL_STATE *p_st, const UINT8 *p_str)
+{
+ const UINT8 *p_tmp;
+
+ p_tmp = p_str;
+ while (*p_tmp && !XML_EOS(p_st))
+ {
+ for (p_tmp = p_str; *p_tmp && !XML_EOS(p_st); p_tmp++)
+ {
+ if (p_st->next_token != *p_tmp)
+ break;
+ xml_get_next(p_st, XML_PASS_WS);
+ }
+
+ if ((p_tmp == p_str) && !XML_EOS(p_st))
+ {
+ xml_get_next(p_st, XML_PASS_WS);
+ }
+ }
+
+ return (BOOLEAN) (*p_tmp == 0);
+}
+
+
+/*****************************************************************************
+**
+** Function xml_consume_str
+**
+** Description
+** Checks for p_str i.e that the first character from p_str is in
+** p_st->next_token and that the successors immediately follows in the
+** Object Store. The p_str must not be last in the Object Store.
+**
+** Parameters
+** p_st (in/out) : the parser state
+** p_str (in) : the string to check if present next and to pass by
+** Must not be NULL.
+**
+** Returns
+** True if the string was found and was not last in the Object Store.
+** False otherwise.
+*****************************************************************************/
+
+static BOOLEAN xml_consume_str(tXML_MUL_STATE *p_st, const UINT8 *p_str)
+{
+ do
+ {
+ if (p_st->next_token != *p_str)
+ return FALSE;
+ p_str++;
+ if (!xml_get_next(p_st, XML_PASS_WS))
+ return FALSE;
+ } while (*p_str);
+ return TRUE;
+}
+
+
+/*****************************************************************************
+**
+** Function xml_resolve_refs
+**
+** Description
+** Resolves predefined entity references (sect. 4.6 in the XML spec)
+** and character references (sect 4.1) that may be found in
+** AttValue and content. (According to the XML spec it may also
+** be in an EntityValue. However EntityValues are in the
+** doctypedecl part which is not supported).
+**
+** The AttValue and content not beginning with a tag, must be
+** stored in the p_st->p_bfr_set->value buffer.
+**
+** Parameters
+** p_st (in/out) : the parser state
+**
+** Returns
+** -
+*****************************************************************************/
+
+static void xml_resolve_refs(tXML_MUL_STATE *p_st)
+{
+ UINT8 *p_srch; /* where next search for & starts */
+ UINT8 *p_am; /* points to found & */
+ UINT8 *p_sc; /* points to found ; and succeeding chars */
+ UINT8 *p_start;
+ UINT8 *p_tmp;
+ UINT32 ch_code;
+ UINT32 tmp_code;
+ INT8 i;
+ BOOLEAN resolved;
+ UINT16 len_left;
+
+ p_srch = p_st->value.p;
+ len_left = p_st->value.len;
+ do
+ {
+ p_start = p_srch;
+ p_am = (UINT8*) strchr((char*) p_srch, XML_AM);
+ p_sc = p_am ? (UINT8*) strchr((char*) p_am, XML_SC) : NULL;
+ /* make sure the ptr does not exceed the end of the value str */
+ if(p_sc > (len_left + p_start))
+ p_sc = NULL;
+
+ if (p_am && p_sc)
+ {
+ resolved = FALSE;
+ p_tmp = p_am + 1;
+ *p_sc = 0; /* terminate the ref by replacing ; with 0 */
+ if (*p_tmp == XML_PD) /* character ref */
+ {
+ if (p_tmp[1] == XML_HX)
+ *p_tmp = '0';
+ else
+ {
+ for(p_tmp++; *p_tmp == '0'; p_tmp++)
+ {
+ ;
+ }
+ }
+
+ ch_code = strtoul((char*) p_tmp, NULL, 0);
+ /* skip leading zero bytes */
+ for (i = 3; (i >= 0) && !(ch_code >> i * 8); i--)
+ {
+ ;
+ }
+ p_tmp = p_am;
+ while (i >= 0)
+ {
+ /* mask out one byte and shift it rightmost */
+ /* preceding bytes must be zero so shift left first */
+ tmp_code = ch_code << ((3-i) * 8);
+ *p_tmp = (UINT8) (tmp_code >> 24);
+ p_tmp++;
+ i--;
+ }
+ resolved = TRUE;
+ }
+ else if (p_tmp < p_sc) /* check if predefined ref */
+ {
+ resolved = TRUE;
+ if (strcmp((char*) p_tmp, XML_LT_STR) == 0)
+ {
+ *p_am = XML_ST;
+ p_st->value.len = p_st->value.len - 3; /* remove the length for lt; */
+ p_st->p_cur = p_st->p_cur - 3;
+ }
+ else if (strcmp((char*) p_tmp, XML_GT_STR) == 0)
+ {
+ *p_am = XML_GT;
+ p_st->value.len = p_st->value.len - 3; /* remove the length for gt; */
+ p_st->p_cur = p_st->p_cur - 3;
+ }
+ else if (strcmp((char*) p_tmp, XML_AMP_STR) == 0)
+ {
+ *p_am = XML_AM;
+ p_st->value.len = p_st->value.len - 4; /* remove the length for amp; */
+ p_st->p_cur = p_st->p_cur - 4;
+ }
+ else if (strcmp((char*) p_tmp, XML_APOS_STR) == 0)
+ {
+ *p_am = XML_SQ;
+ p_st->value.len = p_st->value.len - 5; /* remove the length for apos; */
+ p_st->p_cur = p_st->p_cur - 5;
+ }
+ else if (strcmp((char*) p_tmp, XML_QUOT_STR) == 0)
+ {
+ *p_am = XML_DQ;
+ p_st->value.len = p_st->value.len - 5; /* remove the length for quot; */
+ p_st->p_cur = p_st->p_cur - 5;
+ }
+ else
+ resolved = FALSE;
+ }
+
+ if (resolved)
+ {
+ p_srch = p_tmp; /* will contain char after ; */
+ p_sc++;
+ while(*p_sc)
+ {
+ *p_tmp++ = *p_sc++;
+ }
+ }
+ else
+ {
+ *p_sc = XML_SC; /* restore the ref end */
+ p_srch = p_sc + 1;
+ }
+
+ } /* end if */
+ } while (*p_srch && p_am && p_sc);
+}
+
+
+/*****************************************************************************
+**
+** Function xml_remove_trail_ws
+**
+** Description
+** Removes trailing white space from the p_st->p_data_bfr buffer.
+**
+** Parameters
+** p_st (in/out) : the parser state
+**
+** Returns
+** -
+*****************************************************************************/
+
+static void xml_remove_trail_ws(tXML_MUL_STATE *p_st)
+{
+ UINT16 xx;
+
+ if(p_st->value.p)
+ {
+ xx = p_st->value.len;
+ while(xx && XML_IS_WS(p_st->value.p[xx-1]))
+ xx--;
+ p_st->value.len = xx;
+ }
+
+}
+
+
+/*****************************************************************************
+** Parsing Static Functions
+*****************************************************************************/
+
+
+/*****************************************************************************
+**
+** Function xml_name
+**
+** Description
+** Parses a name and its prefix if any. The prefix and name buffers
+** are set.
+** The functions ends with either white space,
+** XML_EQ, XML_EM or XML_GT in p_st->next_token or with XML_EOS.
+**
+** Parameters
+** p_st (in/out) : the parser state
+**
+** Returns
+** True if no error was found.
+** False otherwise.
+*****************************************************************************/
+
+static BOOLEAN xml_name(tXML_MUL_STATE *p_st)
+{
+ BOOLEAN found = FALSE;
+
+ p_st->prefix.p = NULL;
+ p_st->prefix.len = 0;
+ xml_set_bfr(p_st, XML_SET_NAME);
+ xml_find_ch_n(p_st, xml_name_srch);
+ if (!XML_EOS(p_st) && (p_st->next_token == XML_CO))
+ {
+ if (p_st->name.len)
+ {
+ found = TRUE;
+ /* p_st->name.len is string size in name buffer, \0 excl.
+ */
+ p_st->prefix.p = p_st->name.p;
+ p_st->prefix.len = p_st->name.len;
+ }
+ xml_get_next(p_st, XML_PASS_WS);
+ xml_set_bfr(p_st, XML_SET_NAME);
+ if (!XML_EOS(p_st))
+ {
+ xml_find_ch_n(p_st, xml_name_srch + 1);
+ }
+ }
+
+ found = (BOOLEAN) (found || p_st->name.len);
+ if(found)
+ xml_set_bfr(p_st, XML_SET_CLEAR);
+ return found;
+}
+
+
+/*****************************************************************************
+**
+** Function xml_attributes
+**
+** Description
+** Parses an attribute list.
+** The functions ends with the XML_GT or XML_EM char or XML_EOS.
+** Error is reported if the attribute list is last in the Object
+** Store.
+** Sends a XML_ATTRIBUTE event in the user callback for each
+** attribute found.
+**
+** Parameters
+** p_st (in/out) : the parser state
+**
+** Returns
+** True if no error was found.
+** False otherwise.
+*****************************************************************************/
+
+static BOOLEAN xml_attributes(tXML_MUL_STATE *p_st)
+{
+ BOOLEAN cb_ret = TRUE;
+ UINT8 q_ch;
+
+ XML_TRACE_DEBUG1("[xml_parse] xml_attributes: res= %d", p_st->pars_res);
+
+ while ( cb_ret)
+ {
+ /* if this is a white space, then the next character is read from the
+ Object Store into p_st->next_token */
+ if( XML_IS_WS(p_st->next_token) )
+ {
+ if (!xml_get_next(p_st, XML_SKIP_WS))
+ return FALSE;
+ }
+
+ if (p_st->next_token == XML_EQ)
+ return FALSE;
+
+ if ((p_st->next_token == XML_GT) || (p_st->next_token == XML_EM))
+ return TRUE;
+ if (!xml_name(p_st) || XML_EOS(p_st))
+ {
+ return FALSE;
+ }
+ if(XML_IS_WS(p_st->next_token))
+ {
+ if (!xml_get_next(p_st, XML_SKIP_WS))
+ return FALSE;
+ }
+
+ if (p_st->next_token != XML_EQ)
+ return FALSE;
+
+ if (!xml_get_next(p_st, XML_SKIP_WS))
+ return FALSE;
+
+ if ((p_st->next_token != XML_SQ) && (p_st->next_token != XML_DQ))
+ return FALSE;
+
+ q_ch = p_st->next_token;
+ if (!xml_get_next(p_st, XML_PASS_WS))
+ return FALSE;
+
+
+ xml_set_bfr(p_st, XML_SET_VALUE);
+ if (!xml_find_ch(p_st, q_ch, XML_NORM_WS))
+ {
+ return FALSE;
+ }
+
+ xml_set_bfr(p_st, XML_SET_CLEAR);
+ xml_resolve_refs(p_st);
+
+ p_st->event_data.attr.prefix.p = p_st->prefix.p;
+ p_st->event_data.attr.prefix.len = p_st->prefix.len;
+ p_st->event_data.attr.name.p = p_st->name.p;
+ p_st->event_data.attr.name.len = p_st->name.len;
+ p_st->event_data.attr.value.p = p_st->value.p;
+ p_st->event_data.attr.value.len = p_st->value.len;
+ p_st->value.len = 0;
+ cb_ret = p_st->cback(XML_ATTRIBUTE, &(p_st->event_data), p_st->p_usr_data);
+ /* chk cback return */
+ if(cb_ret == FALSE)
+ {
+ xml_incr_pars_res(p_st, XML_NO_PROP);
+ return FALSE;
+ }
+
+ if (!xml_get_next(p_st, XML_PASS_WS))
+ return FALSE;
+ }
+
+ return (BOOLEAN)
+ ((p_st->next_token == XML_GT) || (p_st->next_token == XML_EM));
+}
+
+
+/*****************************************************************************
+**
+** Function xml_elems
+**
+** Description
+** Parses all elements with all their content.This function is not a
+** one-to-one mapped implementation of one production from the XML spec.
+** Instead it uses a simplified iterative (as opposed to recursive)
+** approach when parsing both the element and content productions.
+**
+** When a parsing error is found, this function tries to recover by
+** searching for the next element (tag).
+**
+** When char data is found, the function sends the XML_CHARDATA event in
+** the user callback.
+**
+** Other static functions with production names, start their parsing
+** from the first character in their production. They might check
+** that the first character (token) in the production matches
+** p_st->next_token, alternatively they can just get rid of the first
+** char in the production by calling get_next_ch. The exceptions to this
+** are the xml_qm_elem, xml_ex_elem, xml_etag_elem and the xml_tag_elem
+** functions which starts with the XML_QM, XML_EX, XML_EM and the first
+** char in the tag name, respectively.
+**
+** Parameters
+** p_st (in/out) : the parser state
+** prev_ok (in) : if parsing done before calling this function was
+** ok. If not, the functions starts with recovering.
+**
+** Returns
+** True if parsing was successful possibly with successful recoveries.
+** False if an error was found from which recovery failed (XML_EOS).
+*****************************************************************************/
+
+static BOOLEAN xml_elems(tXML_MUL_STATE *p_st, BOOLEAN prev_ok)
+{
+ BOOLEAN tag_found;
+ BOOLEAN cb_ret = TRUE;
+
+ while (!XML_EOS(p_st) && prev_ok)
+ {
+ /* remove leading ws even if char data */
+ if (XML_IS_WS(p_st->next_token))
+ {
+ if (!xml_get_next(p_st, XML_SKIP_WS))
+ return TRUE;
+ }
+
+ tag_found = (BOOLEAN) (p_st->next_token == XML_ST);
+ if (!tag_found)
+ {
+ xml_set_bfr(p_st, XML_SET_VALUE);
+ tag_found = xml_find_ch(p_st, XML_ST, XML_PASS_WS);
+
+ xml_remove_trail_ws(p_st);
+ if (p_st->value.len > 0)
+ {
+ xml_resolve_refs(p_st);
+ p_st->event_data.ch_data.value.p = p_st->value.p;
+ p_st->event_data.ch_data.value.len = p_st->value.len;
+ p_st->event_data.ch_data.last = TRUE;
+ p_st->value.len = 0;
+ cb_ret = p_st->cback(XML_CHARDATA, &(p_st->event_data), p_st->p_usr_data);
+ /* chk cback return */
+ if(cb_ret == FALSE)
+ {
+ xml_incr_pars_res(p_st, XML_NO_PROP);
+ return FALSE;
+ }
+
+ }
+ xml_set_bfr(p_st, XML_SET_CLEAR);
+
+ if (!tag_found)
+ return prev_ok;
+ }
+ else
+ {
+ p_st->p_last_stm = p_st->p_cur - 1;
+
+ if (p_st->p_cur)
+ p_st->p_copy = p_st->p_last_stm;
+
+ p_st->cback(XML_TOP, &(p_st->event_data), p_st->p_usr_data);
+ }
+
+ /* tag was found */
+ if (!xml_get_next(p_st, XML_PASS_WS))
+ return FALSE;
+
+
+ if (p_st->next_token == XML_QM)
+ prev_ok = xml_qm_elem(p_st);
+ else if (p_st->next_token == XML_EX)
+ {
+ prev_ok = xml_ex_elem(p_st, FALSE);
+ }
+ else if (p_st->next_token == XML_EM)
+ {
+ prev_ok = xml_etag_elem(p_st);
+ }
+ else
+ prev_ok = xml_tag_elem(p_st);
+
+
+
+ if (!prev_ok)
+ xml_incr_pars_res(p_st, XML_ERR);
+ }
+
+ XML_TRACE_DEBUG1("xml_elems prev_ok:%d", prev_ok);
+ return prev_ok;
+}
+
+
+/*****************************************************************************
+**
+** Function xml_qm_elem
+**
+** Description
+** Recognises all productions starting with "<?". That is PI and XML decl.
+** These productions are skipped and XML_WARNING is set.
+** The function starts with the XML_QM as the first char (is in
+** p_st->next_token).It ends with the XML_GT successor (is in
+** p_st->next_token) or XML_EOS.
+**
+** Parameters
+** p_st (in/out) : the parser state
+**
+** Returns
+** True if no error was found trying to recognise the start and end of
+** the productions. False otherwise.
+*****************************************************************************/
+
+static BOOLEAN xml_qm_elem(tXML_MUL_STATE *p_st)
+{
+ if (!xml_get_next(p_st, XML_PASS_WS))
+ return FALSE;
+ if (!xml_find_str(p_st, (UINT8*) XML_QTAG_END_STR))
+ return FALSE;
+ xml_incr_pars_res(p_st, XML_WARNING);
+ return TRUE;
+}
+
+
+/*****************************************************************************
+**
+** Function xml_ex_elem
+**
+** Description
+** Handles all productions starting with "<!". They are Comments, CDSect
+** doctypedecl and markupdecl. All are skipped. However, the inpar
+** prolog must be set for the function to try to detect the doctypedecl
+** and markupdecl beginning.
+**
+** The function starts with the XML_EX as the first char.
+** The function ends with XML_EOS or the char succeeding XML_GT,
+** except for doctypedecl and marcupdecl which ends with the next XM_TAG.
+**
+** Parameters
+** p_st (in/out) : the parser state
+** prolog (in) : should be set if in prolog in which case the function
+** tries to detect (allows) the beginning of doctypedecl
+** and markupdecl.
+** Returns
+** True if no error was found trying to recognise the start and end of
+** the productions. False otherwise.
+*****************************************************************************/
+
+static BOOLEAN xml_ex_elem(tXML_MUL_STATE *p_st, BOOLEAN prolog)
+{
+ UINT8 q_ch;
+
+ if (!xml_get_next(p_st, XML_PASS_WS))
+ return FALSE;
+
+ if (p_st->next_token == XML_HY) /* comment */
+ {
+ if (!xml_consume_str(p_st, (UINT8*) XML_COMM_STR))
+ return FALSE;
+
+ if (!xml_find_str(p_st, (UINT8*) XML_COMM_END_STR))
+ return FALSE;
+ }
+ else if (p_st->next_token == XML_LB) /* CDSect */
+ {
+ if (!xml_consume_str(p_st, (UINT8*) XML_CDS_STR))
+ return FALSE;
+
+ if (!xml_find_str(p_st, (UINT8*) XML_CDS_END_STR))
+ return FALSE;
+
+ xml_incr_pars_res(p_st, XML_WARNING);
+ }
+ else if (prolog) /* doctypedecl or markupdecl */
+ {
+ do
+ {
+ if (!xml_find_ch_n(p_st, (UINT8*) XML_DOCT_STR))
+ return FALSE;
+
+ if ((p_st->next_token == XML_SQ) || (p_st->next_token == XML_DQ))
+ {
+ q_ch = p_st->next_token;
+ if (!xml_get_next(p_st, XML_PASS_WS))
+ return FALSE;
+
+ if (!xml_find_ch(p_st, q_ch, XML_PASS_WS))
+ return FALSE;
+
+ xml_get_next(p_st, XML_PASS_WS);
+ }
+ } while (!XML_EOS(p_st) && (p_st->next_token != XML_ST));
+
+ xml_incr_pars_res(p_st, XML_WARNING);
+ }
+ else /* error */
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/*****************************************************************************
+**
+** Function xml_tag_elem
+**
+** Description
+** Parses a tag element. The function starts with the char succeeding the
+** XML_ST char.
+** The functions ends with the char succeeding the XML_GT char or
+** with XML_EOS.
+** Sends the XML_TAG and the XML_TAG_END events in a callback each.
+**
+** Parameters
+** p_st (in/out) : the parser state
+**
+** Returns
+** True if no error was found.
+** False otherwise.
+*****************************************************************************/
+
+static BOOLEAN xml_tag_elem(tXML_MUL_STATE *p_st)
+{
+ BOOLEAN cb_ret = TRUE;
+
+ if (!xml_name(p_st))
+ return FALSE;
+
+ p_st->event_data.tag.prefix.p = p_st->prefix.p;
+ p_st->event_data.tag.name.p = p_st->name.p;
+ p_st->event_data.tag.prefix.len = p_st->prefix.len;
+ p_st->event_data.tag.name.len = p_st->name.len;
+ p_st->event_data.tag.p_last_stm = p_st->p_last_stm;
+ cb_ret = p_st->cback(XML_TAG, &(p_st->event_data), p_st->p_usr_data);
+ if(cb_ret == FALSE)
+ {
+ xml_incr_pars_res(p_st, XML_NO_PROP);
+ return FALSE;
+ }
+
+ /* chk cback return */
+
+ if (XML_EOS(p_st))
+ return FALSE;
+
+ if (XML_IS_WS(p_st->next_token))
+ {
+ if (!xml_attributes(p_st))
+ return FALSE;
+ }
+
+ p_st->event_data.empty_elem.end = (BOOLEAN) (p_st->next_token == XML_EM);
+ if (p_st->event_data.empty_elem.end)
+ {
+ if (!xml_get_next(p_st, XML_PASS_WS))
+ return FALSE;
+ }
+
+ if (p_st->next_token != XML_GT)
+ return FALSE;
+
+ xml_get_next(p_st, XML_PASS_WS);
+
+ cb_ret = p_st->cback(XML_TAG_END, &(p_st->event_data), p_st->p_usr_data);
+
+
+ if(cb_ret == FALSE)
+ {
+ xml_incr_pars_res(p_st, XML_NO_PROP);
+ return FALSE;
+ }
+
+ p_st->p_copy = p_st->p_cur - 1;
+ p_st->cback(XML_TOP, &(p_st->event_data), p_st->p_usr_data);
+ /* chk cback return */
+
+ return TRUE;
+}
+
+
+/*****************************************************************************
+**
+** Function xml_etag_elem
+**
+** Description
+** Parses an end tag element. The function starts with the XML_EM char.
+** The functions ends with the char succeeding the XML_GT char or
+** with XML_EOS. Sends the XML_ETAG event in the user callback.
+**
+** Parameters
+** p_st (in/out) : the parser state
+**
+** Returns
+** True if no error was found.
+** False otherwise.
+*****************************************************************************/
+
+static BOOLEAN xml_etag_elem(tXML_MUL_STATE *p_st)
+{
+ BOOLEAN cb_ret = TRUE;
+
+ if (!xml_get_next(p_st, XML_PASS_WS))
+ return FALSE;
+
+ if (!xml_name(p_st))
+ return FALSE;
+
+ p_st->event_data.etag.prefix.p = p_st->prefix.p;
+ p_st->event_data.etag.name.p = p_st->name.p;
+ p_st->event_data.etag.name.len = p_st->name.len;
+ p_st->event_data.etag.prefix.len = p_st->prefix.len;
+ cb_ret = p_st->cback(XML_ETAG, &(p_st->event_data), p_st->p_usr_data);
+ if(cb_ret == FALSE)
+ {
+ xml_incr_pars_res(p_st, XML_NO_PROP);
+ return FALSE;
+ }
+
+ p_st->p_copy = (p_st->prefix.p) ? p_st->prefix.p - 2: p_st->name.p - 2;
+ p_st->cback(XML_TOP, &(p_st->event_data), p_st->p_usr_data);
+
+ /* chk cback return */
+
+ if (XML_EOS(p_st))
+ return FALSE;
+
+ if (XML_IS_WS(p_st->next_token))
+ if (!xml_get_next(p_st, XML_SKIP_WS))
+ return FALSE;
+
+ if (p_st->next_token != XML_GT)
+ return FALSE;
+
+ xml_get_next(p_st, XML_PASS_WS);
+
+ return TRUE;
+}
+
diff --git a/stack/xml/xml_vlist.c b/stack/xml/xml_vlist.c
new file mode 100644
index 0000000..2800c12
--- /dev/null
+++ b/stack/xml/xml_vlist.c
@@ -0,0 +1,873 @@
+/******************************************************************************
+ **
+ ** Name: xml_vlist.c
+ **
+ ** Description: This module contains xml parser of VCard listing
+ **
+ ** Copyright (c) 2004-2011, Broadcom Corporation, All Rights Reserved.
+ ** Broadcom Bluetooth Core. Proprietary and confidential.
+ ******************************************************************************/
+
+#include "bt_target.h"
+#include "gki.h"
+#include "xml_vlist_api.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+#ifndef VLIST_DEBUG_XML
+#define VLIST_DEBUG_XML FALSE
+#endif
+#define VLIST_DEBUG_LEN 50
+#if (defined(VLIST_DEBUG_XML) && VLIST_DEBUG_XML == TRUE)
+#define XML_TRACE_DEBUG0(m) {BT_TRACE_0(TRACE_LAYER_FTP, TRACE_TYPE_DEBUG, m);}
+#define XML_TRACE_DEBUG1(m,p1) {BT_TRACE_1(TRACE_LAYER_FTP, TRACE_TYPE_DEBUG, m,p1);}
+#define XML_TRACE_DEBUG2(m,p1,p2) {BT_TRACE_2(TRACE_LAYER_FTP, TRACE_TYPE_DEBUG, m,p1,p2);}
+#define XML_TRACE_DEBUG3(m,p1,p2,p3) {BT_TRACE_3(TRACE_LAYER_FTP, TRACE_TYPE_DEBUG, m,p1,p2,p3);}
+#define XML_TRACE_DEBUG4(m,p1,p2,p3,p4) {BT_TRACE_4(TRACE_LAYER_FTP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4);}
+#define XML_TRACE_DEBUG5(m,p1,p2,p3,p4,p5) {BT_TRACE_5(TRACE_LAYER_FTP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5);}
+#define XML_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) {BT_TRACE_6(TRACE_LAYER_FTP, TRACE_TYPE_DEBUG, m,p1,p2,p3,p4,p5,p6);}
+#else
+#define XML_TRACE_DEBUG0(m)
+#define XML_TRACE_DEBUG1(m,p1)
+#define XML_TRACE_DEBUG2(m,p1,p2)
+#define XML_TRACE_DEBUG3(m,p1,p2,p3)
+#define XML_TRACE_DEBUG4(m,p1,p2,p3,p4)
+#define XML_TRACE_DEBUG5(m,p1,p2,p3,p4,p5)
+#define XML_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6)
+#endif
+
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+const UINT8 xml_vlist_elem[] = "vCard-listing";/* "vCard-listing" */
+const UINT8 xml_card_elem[] = "card"; /* "card" */
+const UINT8 xml_handle_attr[] = "handle"; /* "handle" */
+const UINT8 xml_vlist_name_attr[] = "name"; /* "name" */
+const UINT8 xml_vlist_version_attr[] = "version"; /* "version" */
+const UINT8 xml_vlist_unknown[] = "unknown"; /* "unknown" */
+
+
+#define XML_VLIST_ELEM_ID 0x01
+#define XML_CARD_ELEM_ID 0x02
+#define XML_MAX_OBJ_TAG_ID XML_VLIST_ELEM_ID
+#define XML_HANDLE_ATTR_ID 0x03
+#define XML_NAME_ATTR_ID 0x04
+#define XML_VERSION_ATTR_ID 0x05
+#define XML_XP_UNKNOWN_ID 0x06
+#define XML_VLIST_MAX_ID 0x07 /* keep in sync with above */
+#define XML_VLIST_TAG_END_ID 0x07 /* closing tag found end=true */
+#define XML_VLIST_PAUSE_ID 0x08 /* closing tag found end=false */
+
+
+#define XML_VLIST_TTBL_SIZE (XML_VLIST_MAX_ID+1)
+
+/*****************************************************************************
+** Type Definitions
+*****************************************************************************/
+
+typedef struct
+{
+ const UINT8 *p_name;
+ UINT8 len;
+} tXML_VLIST_TTBL_ELEM;
+
+typedef tXML_VLIST_TTBL_ELEM tXML_VLIST_TTBL[]; /* Tag Table */
+
+
+static const tXML_VLIST_TTBL_ELEM xml_vlist_ttbl[XML_VLIST_TTBL_SIZE] =
+{ /* index (VLIST_XP_*_ID) & name */
+ {(UINT8*) "", XML_VLIST_MAX_ID-1}, /* \x00 Number of elements in array */
+ {xml_vlist_elem, 13}, /* \x01 vcard listing */
+ {xml_card_elem, 4}, /* \x02 card */
+ {xml_handle_attr, 6}, /* \x03 handle */
+ {xml_vlist_name_attr, 4}, /* \x04 name */
+ {xml_vlist_version_attr, 7}, /* \x05 version */
+ {xml_vlist_unknown, 7}, /* \x06 unknown */
+};
+
+#define XML_VLIST_PTBL_SIZE 0x03
+typedef UINT8 * tXML_VLIST_PTBL_ELEM;
+
+static const tXML_VLIST_PTBL_ELEM xml_vlist_ptbl[XML_VLIST_PTBL_SIZE] =
+{
+ (UINT8*) "\x01", /* \x00 */
+ (UINT8*) "\x05\x02", /* \x01 Vcard Listing */
+ (UINT8*) "\x03\x04" /* \x02 Card */
+};
+
+
+#if (VLIST_DEBUG_XML == TRUE)
+void xml_vlist_debug_str(tXML_STR *p_str, UINT8 *p_buf)
+{
+ int dbg_len;
+ if ( (p_str == NULL) || (NULL==p_str->p))
+ BCM_STRCPY_S( (char *)p_buf, VLIST_DEBUG_LEN, "(NULL)" );
+ else
+ {
+ dbg_len = p_str->len;
+ if ( dbg_len >= VLIST_DEBUG_LEN)
+ dbg_len = VLIST_DEBUG_LEN - 1;
+ BCM_STRNCPY_S( (char *)p_buf, VLIST_DEBUG_LEN, (char *)p_str->p, dbg_len);
+ p_buf[dbg_len] = 0;
+ }
+}
+
+#else
+#define xml_vlist_debug_str(p_str, p_buf)
+#endif
+
+/*****************************************************************************
+ ** Function xml_vlist_proc_tag
+ ** Description
+ ** Parameters -
+ ** Returns
+ *****************************************************************************/
+static UINT8 xml_vlist_proc_tag( tXML_VLIST_STATE *p_st, tXML_STR *p_name, tXML_STACK *p_stk)
+{
+ const UINT8 *p_stag; /* sub tag pointer */
+ UINT8 curr = p_stk->stack[p_stk->top];
+#if (defined(VLIST_DEBUG_XML) && VLIST_DEBUG_XML == TRUE)
+ UINT8 dbg_name[VLIST_DEBUG_LEN];
+#endif
+
+ if (curr < XML_VLIST_PTBL_SIZE)
+ {
+ /* Iterate over allowed sub-tags for the current tag. */
+ for (p_stag = xml_vlist_ptbl[curr]; p_stag && *p_stag ; p_stag++)
+ {
+ if (*p_stag >= XML_VLIST_TTBL_SIZE)
+ continue;
+ if(p_name->len == xml_vlist_ttbl[*p_stag].len &&
+ strncmp((char *)p_name->p, (char *)xml_vlist_ttbl[*p_stag].p_name, p_name->len) == 0)
+ {
+ p_stk->top++;
+ p_stk->stack[p_stk->top] = *p_stag;
+
+ return *p_stag;
+ }
+ }
+ }
+
+#if (defined(VLIST_DEBUG_XML) && VLIST_DEBUG_XML == TRUE)
+ xml_vlist_debug_str(p_name, dbg_name);
+ XML_TRACE_DEBUG1("xml_vlist_proc_tag: bad name:%s", dbg_name );
+#endif
+
+ return XML_XP_UNKNOWN_ID;
+}
+
+
+/*****************************************************************************
+ ** Function xml_vlist_proc_attr
+ ** Description
+ ** Parameters -
+ ** Returns
+ *****************************************************************************/
+static UINT8 xml_vlist_proc_attr(tXML_VLIST_STATE *p_st, tXML_STR *p_name, tXML_STACK *p_stk)
+{
+ const UINT8 *p_stag; /* sub tag pointer */
+ UINT8 curr = p_stk->stack[p_stk->top];
+#if (VLIST_DEBUG_XML == TRUE)
+ UINT8 dbg_name[VLIST_DEBUG_LEN];
+#endif
+
+ if (curr < XML_VLIST_PTBL_SIZE)
+ {
+ /* Iterate over allowed sub-tags for the current tag. */
+ for (p_stag = xml_vlist_ptbl[curr]; p_stag && *p_stag; p_stag++)
+ {
+ if (*p_stag >= XML_VLIST_TTBL_SIZE)
+ continue;
+ if(p_name->len == xml_vlist_ttbl[*p_stag].len &&
+ strncmp((char *)p_name->p, (char *)xml_vlist_ttbl[*p_stag].p_name, p_name->len) == 0)
+ {
+ p_stk->top++;
+ p_stk->stack[p_stk->top] = *p_stag;
+
+ return *p_stag;
+ }
+ }
+ }
+
+#if (defined(VLIST_DEBUG_XML) && VLIST_DEBUG_XML == TRUE)
+ xml_vlist_debug_str(p_name, dbg_name);
+ XML_TRACE_DEBUG1("xml_vlist_proc_attr: bad name:%s", dbg_name);
+#endif
+ return XML_XP_UNKNOWN_ID;
+}
+
+
+/*****************************************************************************
+ ** Function xml_vlist_find_ch_n_copy
+ ** Description copy any chacter till one char in p_str. Any char in p_str
+ ** will stop copy pointed by p_begin
+ ** Parameters
+ ** Returns
+ *****************************************************************************/
+static void xml_vlist_find_ch_n_copy( tXML_MCOPY *p_copy )
+{
+ const UINT8 *p_tmp;
+ const UINT8 *p_str = (UINT8 *)">"; /* was: ":=/> \t\n\r". i think we should copy till
+ closing flag */
+ unsigned int last = XML_VLIST_CARRY_OVER_LEN; /* maximum carry over len we can support */
+ UINT8 *p_last = p_copy->last.p + p_copy->last.len - 1; /* point to the last char of carry
+ over buffer */
+ BOOLEAN found = FALSE;
+
+ /* check if the last char in p_last is in p_str */
+ for (p_tmp = p_str; *p_tmp; p_tmp++)
+ {
+ if (*p_last == *p_tmp)
+ {
+ found = TRUE;
+ break;
+ }
+ } /* for */
+
+ if (found == FALSE)
+ {
+ /* if not in p_str, move chars from p_begin to p_last
+ * until reached last_len or any char in p_str */
+ p_last++;
+ last -= p_copy->last.len; /* calculate the maximum number of chars we can copy */
+ while (*(p_copy->p_begin) && last) /* rl: not sure that this buffer is termninated by a 0 */
+ {
+ /* copy from source (new buffer) to carry over. adjust only carry over ptr. */
+ *p_last++ = *p_copy->p_begin;
+ last--;
+ for (p_tmp = p_str; *p_tmp; p_tmp++)
+ {
+ if (*p_copy->p_begin == *p_tmp)
+ {
+ p_copy->p_begin++; /* adjust pointer to point to next char to read */
+ /* calculate new length of carry over buffer contents */
+ p_copy->last.len = XML_VLIST_CARRY_OVER_LEN-last;
+ *p_last = 0; /* NULL terminate p_last. rl: not really neccessary. */
+ return;
+ }
+ } /* for */
+ p_copy->p_begin++; /* update now to next char. this way abort char is also copied */
+ } /* while */
+ } /* !found */
+}
+
+/*****************************************************************************
+** Function xml_vlist_cback
+** Description
+**
+** Parameters
+** Returns
+*****************************************************************************/
+static BOOLEAN xml_vlist_cback( tXML_EVENT event, void *p_event_data, void *p_usr_data)
+{
+ tXML_MEVT_DATA *p_ed = (tXML_MEVT_DATA*) p_event_data;
+ tXML_VLIST_STATE *p_st = (tXML_VLIST_STATE *) p_usr_data;
+ tXML_PROP *p_cp = &p_st->p_prop[p_st->prop_index];
+ BOOLEAN ret = TRUE;
+ UINT8 next; /* next element */
+ UINT8 curr = p_ed->stack.stack[p_ed->stack.top]; /* current element */
+#if (VLIST_DEBUG_XML == TRUE)
+ UINT8 dbg_name[VLIST_DEBUG_LEN];
+ UINT8 dbg_prefix[VLIST_DEBUG_LEN];
+ UINT8 dbg_value[VLIST_DEBUG_LEN];
+#endif
+
+#if (VLIST_DEBUG_XML == TRUE)
+ XML_TRACE_DEBUG1("xml_vlist_cback:%d", event);
+#endif
+
+ switch (event)
+ {
+ case XML_TAG : /* <tag-name */
+ next = xml_vlist_proc_tag(p_st, &p_ed->tag.name, &p_ed->stack);
+#if (VLIST_DEBUG_XML == TRUE)
+ xml_vlist_debug_str(&p_ed->tag.name, dbg_name);
+ xml_vlist_debug_str(&p_ed->tag.prefix, dbg_prefix);
+ XML_TRACE_DEBUG2("XML_TAG: p:%s, name:%s", dbg_prefix, dbg_name);
+ XML_TRACE_DEBUG2("top:x%x, stk:x%x", p_ed->stack.top, p_ed->stack.stack[p_ed->stack.top]);
+
+#endif
+ if (next != 0)
+ {
+ if (next <= XML_MAX_OBJ_TAG_ID)
+ p_st->obj = next;
+
+ if(p_st->prop_index <p_st->max_num_prop)
+ {
+ p_cp->name = next;
+ p_cp->p_data = NULL;
+ p_cp->len = 0;
+ p_cp->level = p_ed->stack.top;
+ p_st->prop_index++;
+ }
+ else
+ ret = FALSE;
+ }
+ break;
+
+ case XML_ATTRIBUTE : /* attr-name="attr-value" */
+ curr = xml_vlist_proc_attr(p_st, &p_ed->attr.name, &p_ed->stack);
+#if (defined(VLIST_DEBUG_XML) && VLIST_DEBUG_XML == TRUE)
+ xml_vlist_debug_str(&p_ed->attr.name, dbg_name);
+ xml_vlist_debug_str(&p_ed->attr.prefix, dbg_prefix);
+ xml_vlist_debug_str(&p_ed->attr.value, dbg_value);
+ XML_TRACE_DEBUG4("[xml vlist] XML_ATTRIBUTE: p:%s, name:%s, v:%s, curr:%x",
+ dbg_prefix, dbg_name, dbg_value, curr);
+#endif
+ if (curr != 0)
+ {
+ if(p_st->prop_index <p_st->max_num_prop)
+ {
+ p_cp->name = curr;
+ p_cp->p_data = p_ed->attr.value.p;
+ p_cp->len = p_ed->attr.value.len;
+ p_cp->level = p_ed->stack.top;
+ p_st->prop_index++;
+ }
+ else
+ ret = FALSE;
+ p_ed->stack.top--;
+ }
+ break;
+
+ case XML_CHARDATA :
+#if (defined(VLIST_DEBUG_XML) && VLIST_DEBUG_XML == TRUE)
+ xml_vlist_debug_str(&p_ed->ch_data.value, dbg_value);
+ XML_TRACE_DEBUG2("XML_CHARDATA: v:%s, last:%d", dbg_value, p_ed->ch_data.last);
+#endif
+ break;
+
+ case XML_ETAG : /* </tag-name> */
+ if(p_ed->stack.top > 0)
+ {
+ p_ed->stack.stack[p_ed->stack.top] = 0;
+ p_ed->stack.top--;
+ p_st->ended = (BOOLEAN) (p_ed->stack.top == 0);
+ }
+#if (defined(VLIST_DEBUG_XML) && VLIST_DEBUG_XML == TRUE)
+ xml_vlist_debug_str(&p_ed->etag.name, dbg_name);
+ xml_vlist_debug_str(&p_ed->etag.prefix, dbg_prefix);
+ XML_TRACE_DEBUG2("[xml vlist] XML_ETAG: p:%s, name:%s", dbg_prefix, dbg_name);
+ XML_TRACE_DEBUG2("[xml vlist] top:x%x, stk:x%x", p_ed->stack.top, p_ed->stack.stack[p_ed->stack.top]);
+#endif
+ break;
+
+ case XML_TAG_END: /* /> */
+ curr = p_ed->stack.stack[p_ed->stack.top];
+
+ if(p_st->prop_index <p_st->max_num_prop)
+ {
+ if(p_ed->empty_elem.end)
+ p_cp->name = XML_VLIST_TAG_END_ID;
+ else
+ p_cp->name = XML_VLIST_PAUSE_ID;
+ p_cp->p_data = NULL;
+ p_cp->len = 0;
+ p_cp->level = p_ed->stack.top;
+ p_st->prop_index++;
+ if(p_ed->empty_elem.end && p_ed->stack.top > 0)
+ {
+ p_ed->stack.top--;
+ }
+ }
+ else
+ ret = FALSE;
+
+#if (defined(VLIST_DEBUG_XML) && VLIST_DEBUG_XML == TRUE)
+ XML_TRACE_DEBUG4("[xml vlist] XML_TAG_END: %d, top:x%x, stk:x%x, curr:x%x",
+ p_ed->empty_elem.end, p_ed->stack.top, p_ed->stack.stack[p_ed->stack.top], curr);
+#endif
+ break;
+
+ case XML_PARTIAL:
+ if(p_st->p_prop[p_st->prop_index-1].name != XML_VLIST_TAG_END_ID)
+ {
+ p_ed->stack.top--;
+#if (defined(VLIST_DEBUG_XML) && VLIST_DEBUG_XML == TRUE)
+ XML_TRACE_DEBUG0("[xml vlist] adjust due to XML_PARTIAL");
+#endif
+ }
+ break;
+
+ case XML_COPY:
+ xml_vlist_find_ch_n_copy( &p_ed->copy );
+ XML_TRACE_DEBUG1("[xml vlist] XML_COPY: %s", p_ed->copy.last.p);
+ break;
+
+ default :
+#if (defined(VLIST_DEBUG_XML) && VLIST_DEBUG_XML == TRUE)
+ XML_TRACE_DEBUG1("[xml vlist] XML event: %d", event);
+#endif
+ break;
+ }
+
+ return ret;
+}
+
+/**********************************************************************************
+** Function xml_vlist_int_fill_attribute
+** Description fill in file/folder structure.
+**
+** Parameters
+** Returns xx: > 0 : number of properties scanned, folder entry is added
+** = 0 : no end tag found, carry over to next parse
+** = -1: no dst_resource avaibale, all prop left to next parse
+** = -2: exceed max entry, no folder entry added
+**********************************************************************************/
+static INT16 xml_vlist_int_fill_attribute(tXML_VLIST_STATE * p_xud,
+ tXML_PROP *p_prop,
+ UINT16 *num_prop,
+ UINT8 **p_dst_data,
+ UINT16 *dst_len)
+{
+ INT16 xx;
+ UINT16 len;
+ BOOLEAN end = FALSE;
+ tXML_PROP *cur_prop = p_prop;
+ UINT8 *p_cur_offset = *p_dst_data;
+
+ for(xx=0; (xx < *num_prop) && !end; xx++, cur_prop++)
+ {
+#if (defined(VLIST_DEBUG_XML) && VLIST_DEBUG_XML == TRUE)
+ XML_TRACE_DEBUG5( "[xml vlist] fill: num_prop:%d, name id: x%x, p_prop: x%x, p_data:%s, len: %d",
+ (*num_prop-xx) , cur_prop->name, cur_prop, cur_prop->p_data, cur_prop->len);
+#endif
+ switch (cur_prop->name)
+ {
+ case XML_NAME_ATTR_ID:
+ if ( p_xud->current_entry < p_xud->max_entry )
+ {
+ /* calculate the max length to copy */
+ len = (cur_prop->len<=p_xud->max_name_len) ? cur_prop->len:p_xud->max_name_len;
+ if ((*dst_len - len) > 0) /* enough data buffer available? */
+ {
+ p_xud->p_entry[p_xud->current_entry].name = p_cur_offset;
+ p_xud->p_entry[p_xud->current_entry].name_len = len;
+
+ memcpy( (void *)p_xud->p_entry[p_xud->current_entry].name,
+ (const void *)cur_prop->p_data,
+ len );
+ p_xud->p_entry[p_xud->current_entry].name[len] = 0; /* null terminate string */
+ p_cur_offset += (len + 1);
+ *dst_len = *dst_len - (len + 1) ;
+
+#if (defined(VLIST_DEBUG_XML) && VLIST_DEBUG_XML == TRUE)
+ XML_TRACE_DEBUG3("[xml vlist]: catch filename [%s] len [%d] dst_len left:[%d]",
+ p_xud->p_entry[p_xud->current_entry].name,
+ len,
+ *dst_len);
+#endif
+ }
+ else /* run out of dst buffer resource */
+ {
+ xx = -1;
+ return xx;
+ }
+ }
+ else /* exceed max entry */
+ return -2;
+
+ break;
+
+ case XML_HANDLE_ATTR_ID:
+ if ( p_xud->current_entry < p_xud->max_entry )
+ {
+ /* as long as we do not exceed the number of entries in the ouput array copy name */
+ /* calculate the max length to copy */
+ len = (cur_prop->len<=p_xud->max_name_len) ? cur_prop->len:p_xud->max_name_len;
+ if ((*dst_len - len) > 0) /* enough data buffer available? */
+ {
+ p_xud->p_entry[p_xud->current_entry].handle = p_cur_offset;
+ p_xud->p_entry[p_xud->current_entry].handle_len = len;
+
+ memcpy( (void *)p_xud->p_entry[p_xud->current_entry].handle,
+ (const void *)cur_prop->p_data,
+ len );
+ p_xud->p_entry[p_xud->current_entry].handle[len] = 0; /* null terminate string */
+ p_cur_offset += (len + 1);
+ *dst_len = *dst_len - (len + 1) ;
+
+#if (defined(VLIST_DEBUG_XML) && VLIST_DEBUG_XML == TRUE)
+ XML_TRACE_DEBUG3("[xml vlist]: catch filename [%s] len [%d] dst_len left:[%d]",
+ p_xud->p_entry[p_xud->current_entry].handle,
+ len,
+ *dst_len);
+#endif
+ }
+ else /* run out of dst buffer resource */
+ {
+ xx = -1;
+ return xx;
+ }
+ }
+ else /* exceed max entry */
+ return -2;
+
+ break;
+
+ case XML_VLIST_TAG_END_ID:
+ /* -------------------- CUSTOMER SPECIFIC ---------------------- */
+ p_xud->current_entry++; /* increment only when end tag (/>) found */
+
+#if (defined(VLIST_DEBUG_XML) && VLIST_DEBUG_XML == TRUE)
+ XML_TRACE_DEBUG1( "[xml vlist] FOUND END TAG: 0x%x", cur_prop->name );
+#endif
+
+ end = TRUE;
+ break;
+
+ default:
+ XML_TRACE_DEBUG1("[xml vlist] unknown attrib: %d", cur_prop->name );
+ break;
+ }
+ }
+#if (VLIST_DEBUG_XML == TRUE)
+ XML_TRACE_DEBUG2("[xml vlist] fill_attribute: end:%d, xx:%d", end, xx);
+#endif
+#if 0
+ /* if end tag not found -> split over two buffers. but parser will still show rest of
+ found properties. so return still found properties. */
+ if(end == FALSE)
+ xx = 0;
+#endif
+
+ /* keep track of current data buffer offset */
+ *p_dst_data = p_cur_offset;
+ return xx;
+}
+
+
+/**********************************************************************************
+** Function xml_vlist_int_fill_evt_data
+**
+** Description fill in file/folder structure.
+**
+** Parameters
+** Returns
+**********************************************************************************/
+static tXML_VLIST_RES xml_vlist_int_fill_evt_data( UINT8 op,
+ void *p_evt_data,
+ tXML_PROP **p_prop,
+ UINT16 *num_prop,
+ UINT8 **p_dst_data,
+ UINT16 *dst_len)
+{
+ tXML_VLIST_STATE *p_xud = (tXML_VLIST_STATE *)p_evt_data;
+ INT16 inc_prop;
+ UINT8 prop_name; /* Property name. */
+ tXML_PROP *cur_prop = *p_prop;
+ UINT8 *p_cur_offset = *p_dst_data;
+
+ tXML_VLIST_RES x_res = XML_VLIST_OK;
+ BOOLEAN x_no_res = FALSE; /* guard dest buffer resource */
+
+
+ if ( op == 0 || op > XML_MAX_OBJ_TAG_ID || *num_prop == 0)
+ return XML_VLIST_ERROR;
+
+#if VLIST_DEBUG_XML
+ XML_TRACE_DEBUG2( "[xml vlist] xml_vlist_int_fill_evt_data op:%d, num_prop:%d",
+ op, *num_prop);
+#endif
+
+
+
+ while ( *num_prop > 0 && !x_no_res )
+ {
+#if (defined(VLIST_DEBUG_XML) && VLIST_DEBUG_XML == TRUE)
+ XML_TRACE_DEBUG2("end_prop:%d, name id: x%x", *num_prop, cur_prop->name);
+#endif
+ prop_name = cur_prop->name;
+ cur_prop++;
+ *num_prop -= 1;
+
+
+ switch( prop_name )
+ {
+ case XML_VLIST_ELEM_ID:
+ /* skip over version attribute which should always be 1.0. this is the top level */
+ break;
+
+ case XML_CARD_ELEM_ID:
+ inc_prop = xml_vlist_int_fill_attribute(p_xud,
+ cur_prop,
+ num_prop,
+ &p_cur_offset,
+ dst_len);
+ if (inc_prop == -1) /* no dst_buf available */
+ {
+ /* backup one more prop to obtain the skipped folder/file entry header */
+ cur_prop --;
+ *num_prop += 1;
+
+ x_res = XML_VLIST_DST_NO_RES;
+ x_no_res = TRUE;
+ }
+ else if (inc_prop == -2) /* exceed max entry */
+ {
+ x_no_res = TRUE;
+ x_res = XML_VLIST_OUT_FULL;
+ }
+ else /* found folder entry */
+ {
+ cur_prop += inc_prop;
+ *num_prop -= inc_prop;
+ }
+ break;
+
+
+ case XML_VLIST_PAUSE_ID:
+
+#if (VLIST_DEBUG_XML==TRUE)
+ XML_TRACE_DEBUG0( "[xml vlist] xml_vlist_int_fill_evt_data(): XML_VLIST_PAUSE_ID" );
+#endif
+ break;
+
+ case XML_VLIST_TAG_END_ID:
+#if (VLIST_DEBUG_XML==TRUE)
+ XML_TRACE_DEBUG0( "[xml vlist] xml_vlist_int_fill_evt_data(): XML_VLIST_TAG_END_ID" );
+#endif
+ break;
+
+ default:
+ XML_TRACE_DEBUG1( "[xml vlist] xml_vlist_int_fill_evt_data():unknown element: %d", prop_name );
+ break;
+ }
+ }
+
+ /* keep track of current filling position, and current available dst buffer */
+ *p_prop = cur_prop;
+ *p_dst_data = p_cur_offset;
+
+ return x_res;
+}
+
+
+/**************************************************************************************
+** Function XML_VlistInit
+**
+** Description Initialize xml parser state machine.
+**
+** Parameters p_xml_state: address of an xml parser state machine to be initialized,
+** allocate an additional space of size XML_VLIST_CARRY_OVER_LEN
+** right after *p_xml_state to hold carry over data.
+** p_entry : points start of output vlist entry. caller needs do
+** free this memory
+** max_entry : max is 16 bit integer value which is the maximum number
+** of folder entries.
+
+**
+** Returns void
+**************************************************************************************/
+
+void XML_VlistInit( tXML_VLIST_PARSER *p_xml_state,
+ tXML_VLIST_ENTRY *p_entry,
+ const UINT16 max_entry )
+{
+ /* Initialize the generic xml parser state machine.*/
+ XML_InitPars( &p_xml_state->xml, xml_vlist_cback, &p_xml_state->xml_user_data );
+
+ /* User need to allocate an additional space of size XML_VLIST_CARRY_OVER_LEN */
+ /* right after *p_xml_state to hold carry over data. */
+ /* point to the end of the allocated buffer for p_xml_state, which is the */
+ /* beginning of buffer(XML_VLIST_CARRY_OVER_LEN) */
+ p_xml_state->xml.last_bfr.p = (UINT8 *)(p_xml_state + 1);
+ p_xml_state->xml.last_bfr.len = XML_VLIST_CARRY_OVER_LEN;
+
+ /* Initialize user data */
+ p_xml_state->xml_user_data.p_entry = p_entry;
+ p_xml_state->xml_user_data.current_entry = 0;
+ p_xml_state->xml_user_data.max_name_len = XML_UI_ENTRY_MAX_NAME_LEN + 1;
+ p_xml_state->xml_user_data.max_entry = (UINT16)max_entry;
+ p_xml_state->xml_user_data.prop_num = 0;
+}
+
+
+/**************************************************************************************
+** Function XML_VlistParse
+**
+** Description This function is called to parse the xml data received from OBEX
+** into folder entries associated with properties value. It can also be
+** used as clean up function to delete left over data from previous parse.
+** This clean up function is typically used when application runs out of
+** resource and decides to discard extra xml data received.
+**
+** Parameters p_xml_state: pointer to a xml parser initialized by XML_VlistInit().
+** xml_data: valid pointer to OBEX list data in xml format.
+** xml_len: length of the package, must be non-zero value.
+** dst_data: valid pointer to the buffer for holding converted folder entry name.
+ When dst_data is NULL, clean up all remaining data in the parser.
+** dst_len: pointer to the length of dst_data buffer, its carry out value
+** is the number of bytes remaining buffer.When dst_len is NULL,
+** it will cause to flush the internal data in the parser.
+** num_entries: current number of entries, in the end it is the total number of entries
+**
+** Returns tXML_VLIST_RES (see xml_vlist_api.h)
+** XML_PENDING: parsing not completed
+** XML_END_LIST: found /VCard-listing but no final flag detected
+** XML_VLIST_OUT_FULL: reached max_entry -> do not call parser anymore!!! dump data
+** XML_VLIST_DST_NO_RES : run out of dst buffer resource while
+** some xml data still remains.
+
+**************************************************************************************/
+tXML_VLIST_RES XML_VlistParse( tXML_VLIST_PARSER *p_xml_state,
+ UINT8 *xml_data, UINT16 xml_len,
+ UINT8 *dst_data, UINT16 *dst_len,
+ UINT16 *num_entries )
+{
+ tXML_OS xos;
+ BOOLEAN is_remain = TRUE;
+ tXML_MUL_STATE *p_xml = &p_xml_state->xml;
+ tXML_VLIST_STATE *p_st = &p_xml_state->xml_user_data;
+ tXML_VLIST_RES x_res = XML_VLIST_OK;
+ tXML_RESULT res = XML_NO_PROP;
+ UINT16 max_num_prop = GKI_BUF3_SIZE/sizeof(tXML_PROP); /* i hope this is sufficient for 1 */
+
+#if (defined(VLIST_DEBUG_XML) && VLIST_DEBUG_XML == TRUE)
+ int xx;
+ UINT8 dbg_buf[VLIST_DEBUG_LEN];
+ tXML_STR str;
+#endif
+
+ /* if dst_data is NULL, clean up remaining data */
+ if (!dst_data || !dst_len)
+ {
+ /* clean out remained xml data left over from last parse */
+ if (p_xml_state->xml_user_data.p_prop )
+ {
+ GKI_freebuf( p_st->p_prop );
+ p_st->p_prop = p_st->offset_prop = NULL;
+ p_st->prop_num = 0;
+ }
+#if (VLIST_DEBUG_XML == TRUE)
+ XML_TRACE_DEBUG0( "[xml vlist] XML_VlistParse() Clean up left over!");
+#endif
+ return x_res;
+ }
+
+ /* if illegal OBEX data or dst buffer pointer received, return ERROR */
+ if (xml_len == 0 || !xml_data)
+ {
+ return XML_VLIST_ERROR;
+ }
+
+ /* XML_VlistParse receive new xml data, allocate buffer to hold parsed prop */
+ if (p_st->offset_prop == NULL)
+ {
+
+#if (VLIST_DEBUG_XML == TRUE)
+ XML_TRACE_DEBUG0( "[xml vlist] XML_VlistParse() Receive New Data!");
+ XML_TRACE_DEBUG2( "[xml vlist] XML_data start[%x] end [%x]",xml_data, xml_data+xml_len);
+#endif
+ is_remain = FALSE;
+ if ( NULL!= (p_st->p_prop = (tXML_PROP *)GKI_getbuf( GKI_BUF3_SIZE ) ) )
+ {
+ xos.p_begin = xml_data;
+ xos.p_end = xml_data + xml_len;
+ /* pointing next prop to be converted into file entry */
+ p_st->prop_num = 0;
+ }
+ else
+ {
+ GKI_freebuf( p_xml_state );
+ x_res = XML_VLIST_NO_RES;
+ return x_res;
+ }
+ }
+#if (VLIST_DEBUG_XML == TRUE)
+ else
+ {
+ XML_TRACE_DEBUG0( "[xml vlist] XML_VlistParse(): Keep cleaning up old xml data !");
+ }
+#endif
+
+ while( res == XML_NO_PROP )
+ {
+ /* if no remaining data in p_st->p_prop, parse new xml data */
+ if (!is_remain)
+ {
+ p_st->max_num_prop = max_num_prop;
+ p_st->prop_index = 0;
+ res = XML_MulParse( p_xml, &xos );
+
+
+#if (VLIST_DEBUG_XML == TRUE)
+ XML_TRACE_DEBUG4( "xml_vlist_parse obj: %x, max: %d, num: %d, res: %d",
+ p_st->obj, max_num_prop, p_st->prop_index, res);
+
+ if (res != 0)
+ {
+ XML_TRACE_DEBUG1( "XML_MulParse Parsing: %d !!!", res);
+ }
+
+ for(xx=0; xx<p_st->prop_index; xx++)
+ {
+ if ( p_st->p_prop[xx].name < XML_VLIST_MAX_ID )
+ {
+ str.p = p_st->p_prop[xx].p_data;
+ str.len = p_st->p_prop[xx].len;
+ xml_vlist_debug_str(&str, dbg_buf);
+ XML_TRACE_DEBUG5( "[xml vlist] parsed: index[%d]:%d:%s: %s(%d)", p_st->prop_index-xx, p_st->p_prop[xx].level,
+ xml_vlist_ttbl[p_st->p_prop[xx].name].p_name, dbg_buf, p_st->p_prop[xx].len);
+ }
+ else
+ {
+ XML_TRACE_DEBUG3( "[xml vlist] internal prop: %d:%d:%d", xx, p_st->p_prop[xx].level,
+ p_st->p_prop[xx].name );
+ }
+ }
+#endif
+ p_st->prop_num = p_st->prop_index ;
+ p_st->offset_prop = p_st->p_prop;
+ }
+ else
+ {
+ /* This is left over data, pick up the result from the previous parse */
+ res = p_xml->pars_res;
+ }
+
+ if ( res != XML_OBJ_ST_EMPTY )
+ {
+ x_res = xml_vlist_int_fill_evt_data( p_st->obj, p_st, &p_st->offset_prop, &p_st->prop_num, &dst_data, dst_len );
+
+ if ( (XML_VLIST_OK == x_res) && (XML_NO_END == res) )
+ {
+ /* XML_NO_END means that the xml is not completly finished and fill returns
+ ok when when partial filling has been ok */
+ x_res = XML_VLIST_PENDING;
+ }
+
+ /* all parsed xml data has been converted into file entry */
+ /* or exceed max entry number , break the parsing loop */
+ if (XML_VLIST_OUT_FULL != x_res && XML_VLIST_DST_NO_RES != x_res)
+ {
+ is_remain = FALSE;
+ }
+ else
+ break;
+ }
+ } /* while */
+
+ /* free property table. at next call a new one is allocated */
+ if ((x_res != XML_VLIST_DST_NO_RES && p_st->p_prop) ||
+ XML_VLIST_OUT_FULL == x_res)
+ {
+ GKI_freebuf( p_st->p_prop );
+ p_st->p_prop = NULL;
+ p_st->offset_prop = NULL;
+ }
+
+ if ( x_res != XML_VLIST_DST_NO_RES && p_st->ended)
+ {
+ /* this should happen on the same time as final flag in fact */
+ x_res = XML_VLIST_END_LIST; /* found closing /folder-listing */
+ }
+
+
+ *num_entries = p_st->current_entry; /* report number of entries found. only when ended is true
+ application really should be interested! */
+ return x_res;
+}
+
diff --git a/udrv/include/unv.h b/udrv/include/unv.h
new file mode 100644
index 0000000..9e85bc8
--- /dev/null
+++ b/udrv/include/unv.h
@@ -0,0 +1,205 @@
+/************************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * This program is the proprietary software of Broadcom Corporation and/or its
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
+ *
+ * Except as expressly set forth in the Authorized License,
+ *
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
+ * Broadcom integrated circuit products.
+ *
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT
+ * OF USE OR PERFORMANCE OF THE SOFTWARE.
+ *
+ * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR
+ * ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+ *
+ ************************************************************************************/
+
+/************************************************************************************
+ *
+ * Filename: unv.h
+ *
+ * Description: Universal NV Ram API
+ *
+ ***********************************************************************************/
+
+#ifndef UNV_H
+#define UNV_H
+
+/************************************************************************************
+** Constants & Macros
+************************************************************************************/
+
+/* any keyfile line cannot exceed this length */
+#define UNV_MAXLINE_LENGTH (2048)
+
+/************************************************************************************
+** Type definitions for callback functions
+************************************************************************************/
+typedef int (*unv_iter_cb)(char *key, char *val, void *userdata);
+
+/************************************************************************************
+** Type definitions and return values
+************************************************************************************/
+
+/************************************************************************************
+** Extern variables and functions
+************************************************************************************/
+
+/************************************************************************************
+** Functions
+************************************************************************************/
+
+/******************************************************************************
+**
+** Function unv_create_directory
+**
+** Description Creates directory, if full path is not available it
+** will construct it. Must be called from BTIF task context.
+**
+** Parameters
+** path : directory path to be created
+**
+** Returns 0 if successful, -1 if failure
+**
+*******************************************************************************/
+
+int unv_create_directory(const char *path);
+
+
+/*******************************************************************************
+**
+** Function unv_create_file
+**
+** Description Creates file
+** Must be called from BTIF task context
+**
+** Parameters
+** filename : file path to be created
+**
+** Returns 0 if successful, -1 if failure
+**
+*******************************************************************************/
+
+int unv_create_file(const char *filename);
+
+/*******************************************************************************
+**
+** Function unv_read_key
+**
+** Description Reads keyvalue from file
+** Path must be an existing absolute path
+** Must be called from BTIF task context
+**
+** Parameters
+** path : path of keyfile
+** key : key string to query for
+** p_out : output line buffer supplied by caller
+** out_len : max length of output buffer
+**
+** Returns Returns buffer of key value.
+**
+*******************************************************************************/
+
+char* unv_read_key( const char *path,
+ const char *key,
+ char *p_out,
+ int out_len);
+
+/*******************************************************************************
+**
+** Function unv_read_key_iter
+**
+** Description Reads keyvalue from file iteratively
+** Path must be an existing absolute path
+** cb is the callback that is invoked for each entry read
+** Must be called from BTIF task context
+**
+** Parameters
+** path : path of keyfile
+** cb : iteration callback
+** userdata : context specific userdata passed onto callback
+**
+** Returns 0 if successful, -1 if failure
+**
+*******************************************************************************/
+
+int unv_read_key_iter( const char *path,
+ unv_iter_cb cb,
+ void *userdata );
+
+
+/*******************************************************************************
+**
+** Function unv_write_key
+**
+** Description Writes key to file. If key value exists it will be updated
+** Path must be an existing absolute path
+** Must be called from BTIF task context
+**
+** Parameters
+** path : path of keyfile
+** key : key string to write
+** value : value string to set for this key
+**
+** Returns 0 if successful, -1 if failure
+**
+*******************************************************************************/
+
+int unv_write_key( const char *path,
+ const char *key,
+ const char *value );
+
+
+/*******************************************************************************
+**
+** Function unv_remove_key
+**
+** Description Removes keyvalue from file
+** Path must be an existing absolute path
+** Must be called from BTIF task context
+**
+** Parameters
+** path : path of keyfile
+** key : key string to delete
+**
+** Returns 0 if successful, -1 if failure
+**
+*******************************************************************************/
+
+int unv_remove_key( const char *path,
+ const char *key );
+
+#endif /* UNV_H */
+
+
diff --git a/udrv/ulinux/uipc_linux.h b/udrv/ulinux/uipc_linux.h
new file mode 100644
index 0000000..5365806
--- /dev/null
+++ b/udrv/ulinux/uipc_linux.h
@@ -0,0 +1,36 @@
+/********************************************************************************
+** *
+** Name uipc_linux.h *
+** *
+** Function Linux specific UIPC definitions *
+** *
+** *
+** Copyright (c) 2007-2010, Broadcom Corp., All Rights Reserved. *
+** Proprietary and confidential. *
+** *
+*********************************************************************************/
+#ifndef _UIPC_LINUX_H_
+#define _UIPC_LINUX_H_
+
+typedef int SOCKET;
+#define INVALID_SOCKET (SOCKET)(-1)
+#define SOCKET_ERROR (-1)
+
+/* tcp/ip socket configuration */
+typedef struct {
+ char *p_address;
+ unsigned int port;
+} tUIPC_LINUX_CFG_TCP ;
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Socket configuration for GLGPS interface */
+extern tUIPC_LINUX_CFG_TCP uipc_linux_cfg_glgps;
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _UIPC_LINUX_H_ */
diff --git a/udrv/ulinux/unv_linux.c b/udrv/ulinux/unv_linux.c
new file mode 100644
index 0000000..6737ca0
--- /dev/null
+++ b/udrv/ulinux/unv_linux.c
@@ -0,0 +1,818 @@
+/************************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * This program is the proprietary software of Broadcom Corporation and/or its
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
+ *
+ * Except as expressly set forth in the Authorized License,
+ *
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
+ * Broadcom integrated circuit products.
+ *
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT
+ * OF USE OR PERFORMANCE OF THE SOFTWARE.
+ *
+ * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR
+ * ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+ *
+ ************************************************************************************/
+
+/************************************************************************************
+ *
+ * Filename: unv_linux.c
+ *
+ * Description: Universal NV Ram API.
+ * Manages all non volatile (file) database entries used by
+ * bluetooth upper layer stack.
+ *
+ ***********************************************************************************/
+
+#include "unv.h"
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <stdlib.h>
+#include <sys/prctl.h>
+#include <pthread.h>
+
+#define LOG_TAG "UNV_LINUX"
+#include <utils/Log.h>
+
+/************************************************************************************
+** Constants & Macros
+************************************************************************************/
+
+#define info(fmt, ...) LOGI ("%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
+#define debug(fmt, ...) LOGD ("%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
+#define verbose(fmt, ...) //LOGD ("%s: " fmt, __FUNCTION__, ## __VA_ARGS__)
+#define error(fmt, ...) LOGE ("##### ERROR : %s: " fmt "#####", __FUNCTION__, ## __VA_ARGS__)
+
+#define UNV_DELIM "\r\n"
+
+/* fixme -- incorporate field delim definition */
+#define UNV_FIELD_DELIM " "
+
+/* keystring + space + valuestring + null terminate */
+#define KEYVAL_SZ(key, val) (strlen(key) + 1 + strlen(val) + strlen(UNV_DELIM) + 1)
+
+#define DIR_MODE 0740
+#define FILE_MODE 0644
+
+#define BTIF_TASK_STR "BTIF"
+
+/************************************************************************************
+** Local type definitions
+************************************************************************************/
+
+
+/************************************************************************************
+** Static variables
+************************************************************************************/
+
+/************************************************************************************
+** Static functions
+************************************************************************************/
+
+/************************************************************************************
+** Externs
+************************************************************************************/
+
+/************************************************************************************
+** Functions
+************************************************************************************/
+
+/*******************************************************************************
+**
+** Function check_caller_context
+**
+** Description Checks pthread name of caller. Currently only BTIF thread
+** is allowed to call in here to avoid multithreading issues
+**
+** Returns 1 if correct context, 0 otherwise
+**
+*******************************************************************************/
+
+static int check_caller_context(void)
+{
+ char name[16];
+
+ prctl(PR_GET_NAME, name, 0, 0, 0);
+
+ if (strncmp(name, BTIF_TASK_STR, strlen(BTIF_TASK_STR)) != 0)
+ {
+ error("only btif context allowed (%s)", name);
+ return 0;
+ }
+ return 1;
+}
+
+/*******************************************************************************
+**
+** Function mk_dir
+**
+** Description Create directory
+**
+** Returns 0 if successful, -1 if failure
+**
+*******************************************************************************/
+
+static int mk_dir(const char *path)
+{
+ struct stat st;
+
+ if (stat(path, &st) == 0)
+ {
+ if (!S_ISDIR(st.st_mode))
+ {
+ /* path is not a directory */
+ error("directory path %s is not a directory (%s)", path, strerror(errno));
+ return -1;
+ }
+
+ /* already exist */
+ return 0;
+ }
+
+ /* no existing dir path, try creating it */
+ if (mkdir(path, DIR_MODE) != 0)
+ {
+ error("failed to create dir [%s] (%s)", path, strerror(errno));
+ return -1;
+ }
+ return 0;
+}
+
+/*******************************************************************************
+**
+** Function rm_dir
+**
+** Description Removes directory. Assumes empty directory
+**
+** Returns 0 if successful, -1 if failure
+**
+*******************************************************************************/
+
+static int rm_dir(const char *path)
+{
+ int status;
+
+ status = rmdir(path);
+
+ if (status < 0) {
+ error("rmdir %s failed (%s)", path, strerror(errno));
+ return -1;
+ }
+ return 0;
+}
+
+/*******************************************************************************
+**
+** Function write_keyval
+**
+** Description Writes a key and value string to file descriptor
+**
+** Returns Nbr bytes written, -1 if failure
+**
+*******************************************************************************/
+
+static int write_keyval( int fd,
+ const char *key,
+ const char *val )
+{
+ int len = 0;
+ int written = 0;
+ int linesz = KEYVAL_SZ(key, val);
+ char *line;
+
+ /* check if written line would exceed the max read size of a line */
+ if (linesz > UNV_MAXLINE_LENGTH)
+ return -1;
+
+ line = malloc(linesz);
+
+ if (!line)
+ {
+ error("alloc failed (%s)", strerror(errno));
+ return -1;
+ }
+
+ len = sprintf(line, "%s %s%s", key, val, UNV_DELIM);
+
+ //info("write_keyval %s %s (%d bytes)", key, val, len);
+
+ /* update line */
+ written = write(fd, line, len);
+
+ free(line);
+
+ return written;
+}
+
+/*******************************************************************************
+**
+** Function update_key
+**
+** Description Updates existing keyvalue in file
+**
+** key : key string to be updated
+** value : updated value string, NULL removes line
+** pos_start : start offset of string to be updated
+** pos_stop : end offset of string to be updated
+**
+** Returns returns bytes written, -1 if failure
+**
+*******************************************************************************/
+
+static int update_key( int fd,
+ const char *key,
+ const char *value,
+ int pos_start,
+ int pos_stop )
+{
+ char *line;
+ char *p_tail = NULL;
+ int tail_sz;
+ struct stat st;
+ int len = 0;
+
+ if (value)
+ {
+ verbose("update key [%s %s]", key, value);
+ }
+ else
+ {
+ verbose("remove key [%s]", key);
+ }
+
+ /* update file with new value for this key */
+
+ if (fstat(fd, &st) != 0)
+ {
+ error("stat failed (%s)", strerror(errno));
+ return -1;
+ }
+
+ tail_sz = st.st_size-pos_stop;
+
+ if (tail_sz > 0)
+ {
+ /* allocate working area */
+ p_tail = malloc(tail_sz);
+
+ if (!p_tail)
+ {
+ error("malloc failed (%s)", strerror(errno));
+ return -1;
+ }
+
+ /* copy anything after updated line */
+ lseek(fd, pos_stop, SEEK_SET);
+
+ /* read reamining portion into cache */
+ if (read(fd, p_tail, tail_sz) < 0)
+ {
+ error("read failed %s", strerror(errno));
+ return -1;
+ }
+ }
+
+ /* rewind and update new line */
+ lseek(fd, pos_start, SEEK_SET);
+ len = pos_start;
+
+ /* a null key means remove entry */
+ if (value)
+ {
+ len += write_keyval(fd, key, value);
+ }
+
+ /* write tail content */
+ if (p_tail)
+ {
+ len += write(fd, p_tail, tail_sz);
+ free(p_tail);
+ }
+
+ /* finally truncate file to new length */
+ ftruncate(fd, len);
+
+ return len;
+}
+
+/******************************************************************************
+**
+** Function get_keyval
+**
+** Description Reads keyvalue from filedescriptor
+**
+** Parameters
+** fd : file descriptor of file to search
+** key : string to search for in keyfile
+** p_out : output buffer supplied by caller
+** out_len : max length of output line buffer
+** pos_begin : returns keyvalue start offset in file
+** pos_end : returns keyvalue end offset in file
+**
+** Returns String of key value, NULL if not found
+**
+******************************************************************************/
+
+static char *get_keyval( int fd,
+ const char *key,
+ char *p_out,
+ int out_len,
+ int *pos_begin,
+ int *pos_end)
+{
+ char *p_value = NULL;
+ struct stat st;
+ char *p_buf;
+ char *line;
+ char *p;
+
+ if (fstat(fd, &st) != 0)
+ {
+ error("stat failed (%s)", strerror(errno));
+ return NULL;
+ }
+
+ p_buf = malloc(st.st_size + 1);
+
+ if (!p_buf)
+ return NULL;
+
+ p = p_buf;
+
+ if (read(fd, p, st.st_size) < 0)
+ {
+ error("read failed %s", strerror(errno));
+ return NULL;
+ }
+ *(p_buf + st.st_size) = 0;
+
+ /* tokenize first line */
+ line = strtok(p, UNV_DELIM);
+
+ while (line && (p_value == NULL))
+ {
+ /* check for match */
+ if (strncmp(line, key, strlen(key)) == 0)
+ {
+ if (pos_begin)
+ *pos_begin = (line-p_buf);
+
+ /* point line to key value */
+ line += strlen(key) + 1;
+
+ /* make sure supplied buffer isn't overflowed */
+ if (out_len < (int)strlen(line))
+ {
+ error("output buffer too small (%d %d)", out_len, (int)strlen(line));
+ info("line %s\n", line);
+ return NULL;
+ }
+
+ p_value = p_out;
+ /* should be ok to just strcpy from 'line' as
+ * strrok shall null-terminate the token
+ * in the above call */
+ strcpy(p_value, line);
+
+ verbose("found [%s=%s]", key, p_value);
+
+ if (pos_end)
+ *pos_end = (line-p_buf) + strlen(line) + strlen(UNV_DELIM);
+ }
+
+ /* check next line */
+ line = strtok(NULL, UNV_DELIM);
+ }
+
+ free(p_buf);
+
+ /* rewind */
+ lseek(fd, 0, SEEK_SET);
+
+ return p_value;
+}
+
+
+/*****************************************************************************
+**
+** MAIN API
+**
+******************************************************************************/
+
+
+
+
+
+/******************************************************************************
+**
+** Function unv_create_directory
+**
+** Description Creates directory, if full path is not available it
+** will construct it. Must be called from BTIF task context.
+**
+** Parameters
+** path : directory path to be created
+**
+** Returns 0 if successful, -1 if failure
+**
+*******************************************************************************/
+
+int unv_create_directory(const char *path)
+{
+ int status = 0;
+ char tmpbuf[128];
+ char *p_copy;
+ char *p;
+
+ verbose("CREATE DIR %s", path);
+
+ if (check_caller_context() == 0)
+ return -1;
+
+ /* assumes absolute paths */
+ if (strncmp(path, "./", 2) == 0)
+ {
+ error("%s not an absolute path", path);
+ return -1;
+ }
+
+ /* try creating dir directly */
+ if (mk_dir(path) == 0)
+ return 0;
+
+ /* directory does not exit, create it */
+
+ /* first make sure we won't overflow the path buffer */
+ if ((strlen(path)+1) > sizeof(tmpbuf))
+ return -1;
+
+ /* setup scratch buffer, make sure path is ended with / */
+ sprintf(tmpbuf, "%s/", path);
+
+ p_copy = tmpbuf;
+
+ p = strchr(p_copy+1, '/'); /* skip root */
+
+ while ((status == 0) && p)
+ {
+ /*
+ * temporarily null terminate to allow creating
+ * directories up to this point
+ */
+ *p= '\0';
+ status = mk_dir(p_copy);
+ *p= '/';
+
+ /* find next */
+ p = strchr(++p, '/');
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function unv_create_file
+**
+** Description Creates file
+** Must be called from BTIF task context
+**
+** Parameters
+** filename : file path to be created
+**
+** Returns 0 if successful, -1 if failure
+**
+*******************************************************************************/
+
+int unv_create_file(const char *filename)
+{
+ int fd;
+ char *p;
+ char *path = strdup(filename); /* rw copy */
+
+ if (check_caller_context() == 0)
+ return -1;
+
+ /* separate path from filename */
+ p = strrchr(path, '/');
+
+ if (p)
+ {
+ *p = '\0';
+ if (unv_create_directory(path) < 0)
+ {
+ free(path);
+ return -1;
+ }
+ }
+
+ free(path);
+
+ verbose("CREATE FILE %s", filename);
+
+ fd = open(filename, O_RDWR|O_CREAT, FILE_MODE);
+
+ if (fd < 0)
+ {
+ error("file failed to create %s errno: (%s)", filename, strerror(errno));
+ return -1;
+ }
+
+ close(fd);
+
+ return 0;
+}
+
+
+/*******************************************************************************
+**
+** Function unv_read_key
+**
+** Description Reads keyvalue from file
+** Path must be an existing absolute path
+** Must be called from BTIF task context
+**
+** Parameters
+** path : path of keyfile
+** key : key string to query for
+** p_out : output line buffer supplied by caller
+** out_len : max length of output buffer
+**
+** Returns Returns buffer of key value.
+**
+******************************************************************************/
+
+char* unv_read_key( const char *path,
+ const char *key,
+ char *p_out,
+ int out_len)
+{
+ int fd;
+ char *p_search;
+
+ verbose("READ KEY [%s]", key);
+
+ /* sanity check */
+ if (key == NULL)
+ return NULL;
+
+ if (check_caller_context() == 0)
+ return NULL;
+
+ fd = open(path, O_RDONLY, FILE_MODE);
+
+ if (fd < 0) {
+ error("file failed to open %s (%s)", path, strerror(errno));
+ return NULL;
+ }
+
+ p_search = get_keyval(fd, key, p_out, out_len, NULL, NULL);
+
+ close(fd);
+
+ return p_search;
+}
+
+/*******************************************************************************
+**
+** Function unv_read_key_iter
+**
+** Description Reads keyvalue from file iteratively
+** Path must be an existing absolute path
+** Must be called from BTIF task context
+**
+** Parameters
+** path : path of keyfile
+** cb : iteration callback invoked for each entry read
+** userdata : context specific userdata passed onto callback
+**
+** Returns 0 if successful, -1 if failure
+**
+*******************************************************************************/
+
+int unv_read_key_iter( const char *path,
+ unv_iter_cb cb,
+ void *userdata )
+{
+ int fd;
+ char *p, *p_buf;
+ struct stat st;
+ char *line;
+ int cnt = 0;
+
+ verbose("READ KEY ITER");
+
+ if (check_caller_context() == 0)
+ return -1;
+
+ fd = open(path, O_RDONLY, FILE_MODE);
+
+ if (fd < 0) {
+ error("file failed to open %s (%s)", path, strerror(errno));
+ return -1;
+ }
+
+ if (fstat(fd, &st) != 0)
+ {
+ error("stat failed (%s)", strerror(errno));
+ return -1;
+ }
+
+ p_buf = malloc(st.st_size + 1);
+
+ if (!p_buf)
+ return -1;
+
+ p = p_buf;
+
+ if (read(fd, p, st.st_size) < 0)
+ {
+ error("read failed %s", strerror(errno));
+ free(p_buf);
+ return -1;
+ }
+
+ *(p + st.st_size) = 0;
+
+ /* tokenize first line */
+ line = strtok(p, UNV_DELIM);
+ while (line)
+ {
+ char key[128], value[128];
+ char *needle;
+
+ needle = strchr(line, ' ');
+ memset(key, 0, sizeof(key));
+ memcpy(key, line, (needle-line));
+ needle++;
+ strcpy(value, needle);
+
+ cb(key, value, userdata);
+ cnt++;
+
+ line = strtok(NULL, UNV_DELIM);
+ }
+
+ free(p_buf);
+
+ close(fd);
+
+ return cnt;
+}
+
+/*******************************************************************************
+**
+** Function unv_write_key
+**
+** Description Writes key to file. If key value exists it will be updated
+** Path must be an existing absolute path
+** Must be called from BTIF task context
+**
+** Parameters
+** path : path of keyfile
+** key : key string to write
+** value : value string to set for this key
+**
+** Returns 0 if successful, -1 if failure
+**
+*******************************************************************************/
+
+int unv_write_key( const char *path,
+ const char *key,
+ const char *value )
+{
+ int fd;
+ int pos_start = 0;
+ int pos_stop = 0;
+ char *keyval = NULL;
+ char *p_line = malloc(UNV_MAXLINE_LENGTH);
+
+ verbose("WRITE KEY [%s %s]", key, value);
+
+ /* sanity check */
+ if (key == NULL)
+ return -1;
+
+ if (check_caller_context() == 0)
+ return -1;
+
+ fd = open(path, O_RDWR, FILE_MODE);
+
+ if (fd < 0)
+ {
+ error("file failed to create %s (%s)", path, strerror(errno));
+ return -1;
+ }
+
+ /* check if key already present */
+ keyval = get_keyval(fd, key, p_line, UNV_MAXLINE_LENGTH, &pos_start, &pos_stop);
+
+ if (keyval)
+ {
+ update_key(fd, key, value, pos_start, pos_stop);
+ }
+ else
+ {
+ /* append at end of file */
+ lseek(fd, 0, SEEK_END);
+ write_keyval(fd, key, value);
+ }
+
+ free(p_line);
+ close(fd);
+
+ return 0;
+}
+
+/*******************************************************************************
+**
+** Function unv_remove_key
+**
+** Description Removes keyvalue from file
+** Path must be an existing absolute path
+** Must be called from BTIF task context
+**
+** Parameters
+** path : path of keyfile
+** key : key string to delete
+**
+** Returns 0 if successful, -1 if failure
+**
+*******************************************************************************/
+
+int unv_remove_key( const char *path,
+ const char *key )
+{
+ int fd;
+ char *p_search;
+ int pos_begin = 0;
+ int pos_stop = 0;
+ char *p_line = malloc(UNV_MAXLINE_LENGTH);
+
+ verbose("READ KEY [%s]", key);
+
+ /* sanity check */
+ if (key == NULL)
+ return -1;
+
+ if (check_caller_context() == 0)
+ return -1;
+
+ fd = open(path, O_RDWR, FILE_MODE);
+
+ if (fd < 0) {
+ error("file failed to open %s (%s)", path, strerror(errno));
+ return -1;
+ }
+
+ p_search = get_keyval(fd, key, p_line, UNV_MAXLINE_LENGTH, &pos_begin, &pos_stop);
+
+ if (p_search)
+ {
+ /* NULL value entry means remove key/val line in file */
+ update_key(fd, key, NULL, pos_begin, pos_stop);
+ }
+
+ return (p_search ? 0 : -1);
+}
+
+
diff --git a/vendor/Android.mk b/vendor/Android.mk
new file mode 100644
index 0000000..d940fa5
--- /dev/null
+++ b/vendor/Android.mk
@@ -0,0 +1,3 @@
+ifneq ($(TARGET_SIMULATOR),true)
+ include $(call all-subdir-makefiles)
+endif
diff --git a/vendor/firmware/Android.mk b/vendor/firmware/Android.mk
new file mode 100644
index 0000000..8338432
--- /dev/null
+++ b/vendor/firmware/Android.mk
@@ -0,0 +1,2 @@
+include $(call all-subdir-makefiles)
+
diff --git a/vendor/firmware/LICENSE.TXT b/vendor/firmware/LICENSE.TXT
new file mode 100644
index 0000000..a418468
--- /dev/null
+++ b/vendor/firmware/LICENSE.TXT
@@ -0,0 +1,216 @@
+SOFTWARE LICENSE AGREEMENT
+
+Unless you and Broadcom Corporation ("Broadcom") execute a separate written
+software license agreement governing use of the accompanying software, this
+software is licensed to you under the terms of this Software License
+Agreement ("Agreement").
+
+ANY USE, REPRODUCTION OR DISTRIBUTION OF THE SOFTWARE CONSTITUTES YOUR
+ACCEPTANCE OF THIS AGREEMENT.
+
+1. DEFINITIONS.
+
+1.1. "Broadcom Product" means any of the proprietary integrated circuit
+product(s) sold by Broadcom with which the Software was designed to be used,
+or their successors.
+
+1.2. "Licensee" means you or if you are accepting on behalf of an entity
+then the entity and its affiliates exercising rights under, and complying
+with all of the terms of this Agreement.
+
+1.3. "Software" shall mean that software made available by Broadcom to
+Licensee in binary code form with this Agreement.
+
+2. LICENSE GRANT; OWNERSHIP
+
+2.1. License Grants. Subject to the terms and conditions of this Agreement,
+Broadcom hereby grants to Licensee a non-exclusive, non-transferable,
+royalty-free license (i) to use and integrate the Software in conjunction
+with any other software; and (ii) to reproduce and distribute the Software
+complete, unmodified and only for use with a Broadcom Product.
+
+2.2. Restriction on Modification. If and to the extent that the Software is
+designed to be compliant with any published communications standard
+(including, without limitation, DOCSIS, HomePNA, IEEE, and ITU standards),
+Licensee may not make any modifications to the Software that would cause the
+Software or the accompanying Broadcom Products to be incompatible with such
+standard.
+
+2.3. Restriction on Distribution. Licensee shall only distribute the
+Software (a) under the terms of this Agreement and a copy of this Agreement
+accompanies such distribution, and (b) agrees to defend and indemnify
+Broadcom and its licensors from and against any damages, costs, liabilities,
+settlement amounts and/or expenses (including attorneys' fees) incurred in
+connection with any claim, lawsuit or action by any third party that arises
+or results from the use or distribution of any and all Software by the
+Licensee except as contemplated herein.
+
+2.4. Proprietary Notices. Licensee shall not remove, efface or obscure any
+copyright or trademark notices from the Software. Licensee shall include
+reproductions of the Broadcom copyright notice with each copy of the
+Software, except where such Software is embedded in a manner not readily
+accessible to the end user. Licensee acknowledges that any symbols,
+trademarks, tradenames, and service marks adopted by Broadcom to identify the
+Software belong to Broadcom and that Licensee shall have no rights therein.
+
+2.5. Ownership. Broadcom shall retain all right, title and interest,
+including all intellectual property rights, in and to the Software. Licensee
+hereby covenants that it will not assert any claim that the Software created
+by or for Broadcom infringe any intellectual property right owned or
+controlled by Licensee.
+
+2.6. No Other Rights Granted; Restrictions. Apart from the license rights
+expressly set forth in this Agreement, Broadcom does not grant and Licensee
+does not receive any ownership right, title or interest nor any security
+interest or other interest in any intellectual property rights relating to
+the Software, nor in any copy of any part of the foregoing. No license is
+granted to Licensee in any human readable code of the Software (source code).
+Licensee shall not (i) use, license, sell or otherwise distribute the
+Software except as provided in this Agreement, (ii) attempt to reverse
+engineer, decompile or disassemble any portion of the Software; or (iii) use
+the Software or other material in violation of any applicable law or
+regulation, including but not limited to any regulatory agency, such as FCC,
+rules.
+
+3. NO WARRANTY OR SUPPORT
+
+3.1. No Warranty. THE SOFTWARE IS OFFERED "AS IS," AND BROADCOM GRANTS AND
+LICENSEE RECEIVES NO WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, BY STATUTE,
+COMMUNICATION OR CONDUCT WITH LICENSEE, OR OTHERWISE. BROADCOM SPECIFICALLY
+DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A SPECIFIC
+PURPOSE OR NONINFRINGEMENT CONCERNING THE SOFTWARE OR ANY UPGRADES TO OR
+DOCUMENTATION FOR THE SOFTWARE. WITHOUT LIMITATION OF THE ABOVE, BROADCOM
+GRANTS NO WARRANTY THAT THE SOFTWARE IS ERROR-FREE OR WILL OPERATE WITHOUT
+INTERRUPTION, AND GRANTS NO WARRANTY REGARDING ITS USE OR THE RESULTS
+THEREFROM INCLUDING, WITHOUT LIMITATION, ITS CORRECTNESS, ACCURACY OR
+RELIABILITY.
+
+3.2. No Support. Nothing in this agreement shall obligate Broadcom to
+provide any support for the Software. Broadcom may, but shall be under no
+obligation to, correct any defects in the Software and/or provide updates to
+licensees of the Software. Licensee shall make reasonable efforts to
+promptly report to Broadcom any defects it finds in the Software, as an aid
+to creating improved revisions of the Software.
+
+3.3. Dangerous Applications. The Software is not designed, intended, or
+certified for use in components of systems intended for the operation of
+weapons, weapons systems, nuclear installations, means of mass
+transportation, aviation, life-support computers or equipment (including
+resuscitation equipment and surgical implants), pollution control, hazardous
+substances management, or for any other dangerous application in which the
+failure of the Software could create a situation where personal injury or
+death may occur. Licensee understands that use of the Software in such
+applications is fully at the risk of Licensee.
+
+4. TERM AND TERMINATION
+
+4.1. Termination. This Agreement will automatically terminate if Licensee
+fails to comply with any of the terms and conditions hereof. In such event,
+Licensee must destroy all copies of the Software and all of its component
+parts.
+
+4.2. Effect Of Termination. Upon any termination of this Agreement, the
+rights and licenses granted to Licensee under this Agreement shall
+immediately terminate.
+
+4.3. Survival. The rights and obligations under this Agreement which by
+their nature should survive termination will remain in effect after
+expiration or termination of this Agreement.
+
+5. CONFIDENTIALITY
+
+5.1. Obligations. Licensee acknowledges and agrees that any documentation
+relating to the Software, and any other information (if such other
+information is identified as confidential or should be recognized as
+confidential under the circumstances) provided to Licensee by Broadcom
+hereunder (collectively, "Confidential Information") constitute the
+confidential and proprietary information of Broadcom, and that Licensee's
+protection thereof is an essential condition to Licensee's use and possession
+of the Software. Licensee shall retain all Confidential Information in
+strict confidence and not disclose it to any third party or use it in any way
+except under a written agreement with terms and conditions at least as
+protective as the terms of this Section. Licensee will exercise at least the
+same amount of diligence in preserving the secrecy of the Confidential
+Information as it uses in preserving the secrecy of its own most valuable
+confidential information, but in no event less than reasonable diligence.
+Information shall not be considered Confidential Information if and to the
+extent that it: (i) was in the public domain at the time it was disclosed or
+has entered the public domain through no fault of Licensee; (ii) was known to
+Licensee, without restriction, at the time of disclosure as proven by the
+files of Licensee in existence at the time of disclosure; or (iii) becomes
+known to Licensee, without restriction, from a source other than Broadcom
+without breach of this Agreement by Licensee and otherwise not in violation
+of Broadcom's rights.
+
+5.2. Return of Confidential Information. Notwithstanding the foregoing, all
+documents and other tangible objects containing or representing Broadcom
+Confidential Information and all copies thereof which are in the possession
+of Licensee shall be and remain the property of Broadcom, and shall be
+promptly returned to Broadcom upon written request by Broadcom or upon
+termination of this Agreement.
+
+6. LIMITATION OF LIABILITY
+TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR ANY OF
+BROADCOM'S LICENSORS HAVE ANY LIABILITY FOR ANY INDIRECT, INCIDENTAL,
+SPECIAL, OR CONSEQUENTIAL DAMAGES, HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER FOR BREACH OF CONTRACT, TORT (INCLUDING NEGLIGENCE) OR
+OTHERWISE, ARISING OUT OF THIS AGREEMENT, INCLUDING BUT NOT LIMITED TO LOSS
+OF PROFITS, EVEN IF SUCH PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES. IN NO EVENT WILL BROADCOM'S LIABILITY WHETHER IN CONTRACT, TORT
+(INCLUDING NEGLIGENCE), OR OTHERWISE, EXCEED THE AMOUNT PAID BY LICENSEE FOR
+SOFTWARE UNDER THIS AGREEMENT. THESE LIMITATIONS SHALL APPLY NOTWITHSTANDING
+ANY FAILURE OF ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+
+7. MISCELLANEOUS
+
+7.1. Export Regulations. YOU UNDERSTAND AND AGREE THAT THE SOFTWARE IS
+SUBJECT TO UNITED STATES AND OTHER APPLICABLE EXPORT-RELATED LAWS AND
+REGULATIONS AND THAT YOU MAY NOT EXPORT, RE-EXPORT OR TRANSFER THE SOFTWARE
+OR ANY DIRECT PRODUCT OF THE SOFTWARE EXCEPT AS PERMITTED UNDER THOSE LAWS.
+WITHOUT LIMITING THE FOREGOING, EXPORT, RE-EXPORT OR TRANSFER OF THE SOFTWARE
+TO CUBA, IRAN, NORTH KOREA, SUDAN AND SYRIA IS PROHIBITED.
+
+7.2 Assignment. This Agreement shall be binding upon and inure to the
+benefit of the parties and their respective successors and assigns, provided,
+however that Licensee may not assign this Agreement or any rights or
+obligation hereunder, directly or indirectly, by operation of law or
+otherwise, without the prior written consent of Broadcom, and any such
+attempted assignment shall be void. Notwithstanding the foregoing, Licensee
+may assign this Agreement to a successor to all or substantially all of its
+business or assets to which this Agreement relates that is not a competitor
+of Broadcom.
+
+7.3. Governing Law; Venue. This Agreement shall be governed by the laws of
+California without regard to any conflict-of-laws rules, and the United
+Nations Convention on Contracts for the International Sale of Goods is hereby
+excluded. The sole jurisdiction and venue for actions related to the subject
+matter hereof shall be the state and federal courts located in the County of
+Orange, California, and both parties hereby consent to such jurisdiction and
+venue.
+
+7.4. Severability. All terms and provisions of this Agreement shall, if
+possible, be construed in a manner which makes them valid, but in the event
+any term or provision of this Agreement is found by a court of competent
+jurisdiction to be illegal or unenforceable, the validity or enforceability
+of the remainder of this Agreement shall not be affected if the illegal or
+unenforceable provision does not materially affect the intent of this
+Agreement. If the illegal or unenforceable provision materially affects the
+intent of the parties to this Agreement, this Agreement shall become
+terminated.
+
+7.5. Equitable Relief. Licensee hereby acknowledges that its breach of this
+Agreement would cause irreparable harm and significant injury to Broadcom
+that may be difficult to ascertain and that a remedy at law would be
+inadequate. Accordingly, Licensee agrees that Broadcom shall have the right
+to seek and obtain immediate injunctive relief to enforce obligations under
+the Agreement in addition to any other rights and remedies it may have.
+
+7.6. Waiver. The waiver of, or failure to enforce, any breach or default
+hereunder shall not constitute the waiver of any other or subsequent breach
+or default.
+
+7.7. Entire Agreement. This Agreement sets forth the entire Agreement
+between the parties and supersedes any and all prior proposals, agreements
+and representations between them, whether written or oral concerning the
+Software. This Agreement may be changed only by mutual agreement of the
+parties in writing.
diff --git a/vendor/firmware/bcm4329/Android.mk b/vendor/firmware/bcm4329/Android.mk
new file mode 100644
index 0000000..e8e3449
--- /dev/null
+++ b/vendor/firmware/bcm4329/Android.mk
@@ -0,0 +1,19 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := bcm4329.hcd
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT)/vendor/firmware
+
+#LOCAL_SRC_FILES := $(LOCAL_MODULE)
+LOCAL_SRC_FILES := BCM4329B1_002.002.023.0944.0956.hcd
+
+#PRODUCT_COPY_FILES += \
+# hardware/broadcom/bt/firmware/bcm4330/BCM4329B1_002.002.023.0944.0956.hcd:system/vendor/firmware/BCM4329B1_002.002.023.0944.0956.hcd \
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_PREBUILT)
+
+
diff --git a/vendor/firmware/bcm4329/BCM4329B1_002.002.023.0944.0956.hcd b/vendor/firmware/bcm4329/BCM4329B1_002.002.023.0944.0956.hcd
new file mode 100644
index 0000000..581125a
--- /dev/null
+++ b/vendor/firmware/bcm4329/BCM4329B1_002.002.023.0944.0956.hcd
Binary files differ
diff --git a/vendor/firmware/bcm4330/Android.mk b/vendor/firmware/bcm4330/Android.mk
new file mode 100644
index 0000000..3742d98
--- /dev/null
+++ b/vendor/firmware/bcm4330/Android.mk
@@ -0,0 +1,19 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := bcm4330.hcd
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT)/vendor/firmware
+
+#LOCAL_SRC_FILES := $(LOCAL_MODULE)
+LOCAL_SRC_FILES := BCM4330B1.hcd
+
+#PRODUCT_COPY_FILES += \
+# hardware/broadcom/bt/firmware/bcm4330/BCM4330B1.hcd:system/vendor/firmware/BCM4330B1.hcd
+
+LOCAL_MODULE_TAGS := eng
+
+include $(BUILD_PREBUILT)
+
+
diff --git a/vendor/firmware/bcm4330/BCM4330B1.hcd b/vendor/firmware/bcm4330/BCM4330B1.hcd
new file mode 100644
index 0000000..983d40e
--- /dev/null
+++ b/vendor/firmware/bcm4330/BCM4330B1.hcd
Binary files differ
diff --git a/vendor/libvendor/Android.mk b/vendor/libvendor/Android.mk
new file mode 100644
index 0000000..8ea5e90
--- /dev/null
+++ b/vendor/libvendor/Android.mk
@@ -0,0 +1,23 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ src/bt_vendor_brcm.c \
+ src/hci_h4.c \
+ src/userial.c \
+ src/hardware.c \
+ src/upio.c \
+ src/utils.c \
+ src/btsnoop.c
+
+LOCAL_C_INCLUDES += \
+ $(LOCAL_PATH)/include
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils
+
+LOCAL_MODULE := libbt-vendor
+LOCAL_MODULE_TAGS := eng
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/vendor/libvendor/include/bt_vendor_brcm.h b/vendor/libvendor/include/bt_vendor_brcm.h
new file mode 100644
index 0000000..e89fa9e
--- /dev/null
+++ b/vendor/libvendor/include/bt_vendor_brcm.h
@@ -0,0 +1,414 @@
+/************************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * This program is the proprietary software of Broadcom Corporation and/or its
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
+ *
+ * Except as expressly set forth in the Authorized License,
+ *
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
+ * Broadcom integrated circuit products.
+ *
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT
+ * OF USE OR PERFORMANCE OF THE SOFTWARE.
+ *
+ * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR
+ * ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+ *
+ ************************************************************************************/
+
+/************************************************************************************
+ *
+ * Filename: bt_vendor_brcm.h
+ *
+ * Description:
+ *
+ ***********************************************************************************/
+
+#ifndef BT_VENDOR_BRCM_H
+#define BT_VENDOR_BRCM_H
+
+#include "bt_vendor_lib.h"
+#include "vnd_buildcfg.h"
+
+/************************************************************************************
+** Constants & Macros
+************************************************************************************/
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef TRUE
+#define TRUE (!FALSE)
+#endif
+
+#ifndef BTVND_LINUX_BASE_PRIORITY
+#define BTVND_LINUX_BASE_PRIORITY 30
+#endif
+
+#ifndef BTVND_USERIAL_READ_THREAD_PRIORITY
+#define BTVND_USERIAL_READ_THREAD_PRIORITY (BTVND_LINUX_BASE_PRIORITY)
+#endif
+
+#ifndef BTVND_MAIN_THREAD_PRIORITY
+#define BTVND_MAIN_THREAD_PRIORITY (BTVND_LINUX_BASE_PRIORITY-1)
+#endif
+
+#ifndef BTVND_USERIAL_READ_MEM_SIZE
+#define BTVND_USERIAL_READ_MEM_SIZE (1024)
+#endif
+
+/* Vendor lib internal event ID */
+#define VND_EVENT_PRELOAD 0x0001
+#define VND_EVENT_POSTLOAD 0x0002
+#define VND_EVENT_RX 0x0004
+#define VND_EVENT_TX 0x0008
+#define VND_EVENT_LPM_ENABLE 0x0010
+#define VND_EVENT_LPM_DISABLE 0x0020
+#define VND_EVENT_LPM_WAKE_DEVICE 0x0040
+#define VND_EVENT_LPM_ALLOW_SLEEP 0x0080
+#define VND_EVENT_LPM_IDLE_TIMEOUT 0x0100
+#define VND_EVENT_EXIT 0x0200
+
+/* Message event mask across vendor lib and stack */
+#define MSG_EVT_MASK 0xFF00 /* eq. BT_EVT_MASK */
+#define MSG_SUB_EVT_MASK 0x00FF /* eq. BT_SUB_EVT_MASK */
+
+/* Message event ID passed from vendor lib to stack */
+#define MSG_VND_TO_STACK_HCI_ERR 0x1300 /* HCIT_TYPE_COMMAND = BT_EVT_TO_BTU_HCIT_ERR */
+#define MSG_VND_TO_STACK_HCI_ACL 0x1100 /* HCIT_TYPE_ACL_DATA = BT_EVT_TO_BTU_HCI_ACL */
+#define MSG_VND_TO_STACK_HCI_SCO 0x1200 /* HCIT_TYPE_SCO_DATA = BT_EVT_TO_BTU_HCI_SCO */
+#define MSG_VND_TO_STACK_HCI_EVT 0x1000 /* HCIT_TYPE_EVENT = BT_EVT_TO_BTU_HCI_EVT */
+#define MSG_VND_TO_STACK_L2C_SEG_XMIT 0x1900 /* L2CAP segment(s) transmitted = BT_EVT_TO_BTU_L2C_SEG_XMIT */
+
+/* Message event ID passed from stack to vendor lib */
+#define MSG_STACK_TO_VND_HCI_ACL 0x2100 /* HCI ACL Data = BT_EVT_TO_LM_HCI_ACL */
+#define MSG_STACK_TO_VND_HCI_SCO 0x2200 /* HCI SCO Data = BT_EVT_TO_LM_HCI_SCO */
+#define MSG_STACK_TO_VND_HCI_CMD 0x2000 /* HCI Command = BT_EVT_TO_LM_HCI_CMD */
+
+/* Local Bluetooth Controller ID for BR/EDR */
+#define LOCAL_BR_EDR_CONTROLLER_ID 0
+
+/* Device port name where Bluetooth controller attached */
+#ifndef BLUETOOTH_UART_DEVICE_PORT
+#define BLUETOOTH_UART_DEVICE_PORT "/dev/ttyO1" /* maguro */
+#endif
+
+/* Location of firmware patch files */
+#ifndef FW_PATCHFILE_LOCATION
+#define FW_PATCHFILE_LOCATION ("/vendor/firmware/") /* maguro */
+#endif
+
+#ifndef UART_TARGET_BAUD_RATE
+#define UART_TARGET_BAUD_RATE 3000000
+#endif
+
+/* sleep mode
+
+ 0: disable
+ 1: UART with Host wake/BT wake out of band signals
+*/
+#ifndef LPM_SLEEP_MODE
+#define LPM_SLEEP_MODE 1
+#endif
+
+/* Host Stack Idle Threshold in 300ms or 25ms
+
+ In sleep mode 1, this is the number of firmware loops executed with no activity
+ before the Host wake line is deasserted. Activity includes HCI traffic excluding
+ certain sleep mode commands and the presence of SCO connections if the
+ "Allow Host Sleep During SCO" flag is not set to 1. Each count of this
+ parameter is roughly equivalent to 300ms or 25ms.
+*/
+#ifndef LPM_IDLE_THRESHOLD
+#define LPM_IDLE_THRESHOLD 1
+#endif
+
+/* Host Controller Idle Threshold in 300ms or 25ms
+
+ This is the number of firmware loops executed with no activity before the HC is
+ considered idle. Depending on the mode, HC may then attempt to sleep.
+ Activity includes HCI traffic excluding certain sleep mode commands and
+ the presence of ACL/SCO connections.
+
+*/
+#ifndef LPM_HC_IDLE_THRESHOLD
+#define LPM_HC_IDLE_THRESHOLD 1
+#endif
+
+/* BT_WAKE Polarity - 0=Active Low, 1= Active High */
+#ifndef LPM_BT_WAKE_POLARITY
+#define LPM_BT_WAKE_POLARITY 1 /* maguro */
+#endif
+
+/* HOST_WAKE Polarity - 0=Active Low, 1= Active High */
+#ifndef LPM_HOST_WAKE_POLARITY
+#define LPM_HOST_WAKE_POLARITY 1 /* maguro */
+#endif
+
+/* LPM_ALLOW_HOST_SLEEP_DURING_SCO
+
+ When this flag is set to 0, the host is not allowed to sleep while
+ an SCO is active. In sleep mode 1, the device will keep the host
+ wake line asserted while an SCO is active.
+ When this flag is set to 1, the host can sleep while an SCO is active.
+ This flag should only be set to 1 if SCO traffic is directed to the PCM interface.
+*/
+#ifndef LPM_ALLOW_HOST_SLEEP_DURING_SCO
+#define LPM_ALLOW_HOST_SLEEP_DURING_SCO 1
+#endif
+
+/* LPM_COMBINE_SLEEP_MODE_AND_LPM
+
+ In Mode 0, always set byte 7 to 0. In sleep mode 1, device always
+ requires permission to sleep between scans / periodic inquiries regardless
+ of the setting of this byte. In sleep mode 1, if byte is set, device must
+ have "permission" to sleep during the low power modes of sniff, hold, and park.
+ If byte is not set, device can sleep without permission during these modes.
+ Permission to sleep in Mode 1 is obtained if the BT_WAKE signal is not asserted.
+*/
+#ifndef LPM_COMBINE_SLEEP_MODE_AND_LPM
+#define LPM_COMBINE_SLEEP_MODE_AND_LPM 1
+#endif
+
+/* LPM_ENABLE_UART_TXD_TRI_STATE
+
+ When set to 0, the device will not tristate its UART TX line before going to sleep.
+ When set to 1, the device will tristate its UART TX line before going to sleep.
+*/
+#ifndef LPM_ENABLE_UART_TXD_TRI_STATE
+#define LPM_ENABLE_UART_TXD_TRI_STATE 0
+#endif
+
+/* LPM_PULSED_HOST_WAKE
+*/
+#ifndef LPM_PULSED_HOST_WAKE
+#define LPM_PULSED_HOST_WAKE 0
+#endif
+
+/* LPM_IDLE_TIMEOUT_MULTIPLE
+
+ The multiple factor of host stack idle threshold in 300ms/25ms
+*/
+#ifndef LPM_IDLE_TIMEOUT_MULTIPLE
+#define LPM_IDLE_TIMEOUT_MULTIPLE 10
+#endif
+
+/* SCO_CFG_INCLUDED
+
+ Do SCO configuration by default. If the firmware patch had been embedded
+ with desired SCO configuration, set this FALSE to bypass configuration
+ from host software.
+*/
+#ifndef SCO_CFG_INCLUDED
+#define SCO_CFG_INCLUDED TRUE
+#endif
+
+#ifndef SCO_USE_I2S_INTERFACE
+#define SCO_USE_I2S_INTERFACE FALSE
+#endif
+
+#if (SCO_USE_I2S_INTERFACE == TRUE)
+#define SCO_I2SPCM_PARAM_SIZE 4
+
+/* SCO_I2SPCM_IF_MODE - 0=Disable, 1=Enable */
+#ifndef SCO_I2SPCM_IF_MODE
+#define SCO_I2SPCM_IF_MODE 1
+#endif
+
+/* SCO_I2SPCM_IF_ROLE - 0=Slave, 1=Master */
+#ifndef SCO_I2SPCM_IF_ROLE
+#define SCO_I2SPCM_IF_ROLE 1
+#endif
+
+/* SCO_I2SPCM_IF_SAMPLE_RATE
+
+ 0 : 8K
+ 1 : 16K
+ 2 : 4K
+*/
+#ifndef SCO_I2SPCM_IF_SAMPLE_RATE
+#define SCO_I2SPCM_IF_SAMPLE_RATE 0
+#endif
+
+/* SCO_I2SPCM_IF_CLOCK_RATE
+
+ 0 : 128K
+ 1 : 256K
+ 2 : 512K
+ 3 : 1024K
+ 4 : 2048K
+*/
+#ifndef SCO_I2SPCM_IF_CLOCK_RATE
+#define SCO_I2SPCM_IF_CLOCK_RATE 1
+#endif
+#endif // SCO_USE_I2S_INTERFACE
+
+
+#define SCO_PCM_PARAM_SIZE 5
+
+/* SCO_PCM_ROUTING
+
+ 0 : PCM
+ 1 : Transport
+ 2 : Codec
+ 3 : I2S
+*/
+#ifndef SCO_PCM_ROUTING
+#define SCO_PCM_ROUTING 0
+#endif
+
+/* SCO_PCM_IF_CLOCK_RATE
+
+ 0 : 128K
+ 1 : 256K
+ 2 : 512K
+ 3 : 1024K
+ 4 : 2048K
+*/
+#ifndef SCO_PCM_IF_CLOCK_RATE
+#define SCO_PCM_IF_CLOCK_RATE 4
+#endif
+
+/* SCO_PCM_IF_FRAME_TYPE - 0=Short, 1=Long */
+#ifndef SCO_PCM_IF_FRAME_TYPE
+#define SCO_PCM_IF_FRAME_TYPE 0
+#endif
+
+/* SCO_PCM_IF_SYNC_MODE - 0=Slave, 1=Master */
+#ifndef SCO_PCM_IF_SYNC_MODE
+#define SCO_PCM_IF_SYNC_MODE 0
+#endif
+
+/* SCO_PCM_IF_CLOCK_MODE - 0=Slave, 1=Master */
+#ifndef SCO_PCM_IF_CLOCK_MODE
+#define SCO_PCM_IF_CLOCK_MODE 0
+#endif
+
+#define PCM_DATA_FORMAT_PARAM_SIZE 5
+
+/* PCM_DATA_FMT_SHIFT_MODE
+
+ 0 : MSB first
+ 1 : LSB first
+*/
+#ifndef PCM_DATA_FMT_SHIFT_MODE
+#define PCM_DATA_FMT_SHIFT_MODE 0
+#endif
+
+/* PCM_DATA_FMT_FILL_BITS
+
+ Specifies the value with which to fill unused bits
+ if Fill_Method is set to programmable
+*/
+#ifndef PCM_DATA_FMT_FILL_BITS
+#define PCM_DATA_FMT_FILL_BITS 0
+#endif
+
+/* PCM_DATA_FMT_FILL_METHOD
+
+ 0 : 0's
+ 1 : 1's
+ 2 : Signed
+ 3 : Programmable
+*/
+#ifndef PCM_DATA_FMT_FILL_METHOD
+#define PCM_DATA_FMT_FILL_METHOD 3
+#endif
+
+/* PCM_DATA_FMT_FILL_NUM
+
+ Specifies the number of bits to be filled
+*/
+#ifndef PCM_DATA_FMT_FILL_NUM
+#define PCM_DATA_FMT_FILL_NUM 3
+#endif
+
+/* PCM_DATA_FMT_JUSTIFY_MODE
+
+ 0 : Left justify (fill data shifted out last)
+ 1 : Right justify (fill data shifted out first)
+*/
+#ifndef PCM_DATA_FMT_JUSTIFY_MODE
+#define PCM_DATA_FMT_JUSTIFY_MODE 0
+#endif
+
+/************************************************************************************
+** Type definitions and return values
+************************************************************************************/
+
+typedef struct
+{
+ uint16_t event;
+ uint16_t len;
+ uint16_t offset;
+ uint16_t layer_specific;
+} VND_BT_HDR;
+
+#define BT_VND_HDR_SIZE (sizeof(VND_BT_HDR))
+
+
+typedef struct _vnd_buffer_hdr
+{
+ struct _vnd_buffer_hdr *p_next; /* next buffer in the queue */
+ uint8_t reserved1;
+ uint8_t reserved2;
+ uint8_t reserved3;
+ uint8_t reserved4;
+} VND_BUFFER_HDR_T;
+
+#define BT_VND_BUFFER_HDR_SIZE (sizeof(VND_BUFFER_HDR_T))
+
+/************************************************************************************
+** Extern variables and functions
+************************************************************************************/
+
+extern bt_vendor_callbacks_t *bt_vendor_cbacks;
+
+/************************************************************************************
+** Functions
+************************************************************************************/
+
+/*******************************************************************************
+**
+** Function btvnd_signal_event
+**
+** Description Perform context switch to bt_vendor main thread
+**
+** Returns None
+**
+*******************************************************************************/
+extern void btvnd_signal_event(uint16_t event);
+
+
+#endif /* BT_VENDOR_BRCM_H */
+
diff --git a/vendor/libvendor/include/bt_vendor_lib.h b/vendor/libvendor/include/bt_vendor_lib.h
new file mode 100644
index 0000000..226d4f4
--- /dev/null
+++ b/vendor/libvendor/include/bt_vendor_lib.h
@@ -0,0 +1,222 @@
+/************************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * This program is the proprietary software of Broadcom Corporation and/or its
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
+ *
+ * Except as expressly set forth in the Authorized License,
+ *
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
+ * Broadcom integrated circuit products.
+ *
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT
+ * OF USE OR PERFORMANCE OF THE SOFTWARE.
+ *
+ * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR
+ * ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+ *
+ ************************************************************************************/
+
+#ifndef BT_VENDOR_LIB_H
+#define BT_VENDOR_LIB_H
+
+#include <stdint.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+/** Struct types */
+
+
+/** Typedefs and defines */
+
+/* Generic purpose transac returned upon request complete */
+typedef void* TRANSAC;
+
+/** Bluetooth Power Control States */
+typedef enum {
+ BT_VENDOR_CHIP_PWR_OFF,
+ BT_VENDOR_CHIP_PWR_ON,
+} bt_vendor_chip_power_state_t;
+
+/** Bluetooth Low Power Mode */
+typedef enum {
+ BT_VENDOR_LPM_DISABLE,
+ BT_VENDOR_LPM_ENABLE,
+ BT_VENDOR_LPM_WAKE_ASSERT,
+ BT_VENDOR_LPM_WAKE_DEASSERT,
+} bt_vendor_low_power_event_t;
+
+/** Receive flow control */
+typedef enum {
+ BT_RXFLOW_OFF, /* add transport device fd to select set */
+ BT_RXFLOW_ON, /* remove transport device to from select set */
+} bt_rx_flow_state_t;
+
+/** Result of write request */
+typedef enum {
+ BT_VENDOR_TX_SUCCESS, /* a buffer is fully processed and can be released */
+ BT_VENDOR_TX_FAIL, /* transmit fail */
+ BT_VENDOR_TX_FRAGMENT, /* send back split ACL packet for core stack to reprocess */
+} bt_vendor_transmit_result_t;
+
+/** Result of preload initialization */
+typedef enum {
+ BT_VENDOR_PRELOAD_SUCCESS,
+ BT_VENDOR_PRELOAD_FAIL,
+} bt_vendor_preload_result_t;
+
+/** Result of postload initialization */
+typedef enum {
+ BT_VENDOR_POSTLOAD_SUCCESS,
+ BT_VENDOR_POSTLOAD_FAIL,
+} bt_vendor_postload_result_t;
+
+/** Result of low power enable/disable request */
+typedef enum {
+ BT_VENDOR_LPM_DISABLED,
+ BT_VENDOR_LPM_ENABLED,
+} bt_vendor_lpm_request_result_t;
+
+/** Vendor Library Return Status */
+typedef enum {
+ BT_VENDOR_STATUS_SUCCESS,
+ BT_VENDOR_STATUS_FAIL,
+ BT_VENDOR_STATUS_NOT_READY,
+ BT_VENDOR_STATUS_NOMEM,
+ BT_VENDOR_STATUS_BUSY,
+ BT_VENDOR_STATUS_CORRUPTED_BUFFER
+} bt_vnd_status_t;
+
+
+/* Section comment */
+
+/*
+ * Bluetooth Vendor callback structure.
+ */
+
+/* called upon bt host wake signal */
+typedef void (*hostwake_ind_cb)(bt_vendor_low_power_event_t event);
+
+/* preload initialization callback */
+typedef void (*preload_result_cb)(TRANSAC transac, bt_vendor_preload_result_t result);
+
+/* postload initialization callback */
+typedef void (*postload_result_cb)(TRANSAC transac, bt_vendor_postload_result_t result);
+
+/* lpm enable/disable callback */
+typedef void (*lpm_result_cb)(bt_vendor_lpm_request_result_t result);
+
+/* datapath buffer allocation callback (callout) */
+typedef char* (*alloc_mem_cb)(int size);
+
+/* datapath buffer deallocation callback (callout) */
+typedef int (*dealloc_mem_cb)(TRANSAC transac, char *p_buf);
+
+/* transmit result callback */
+typedef int (*tx_result_cb)(TRANSAC transac, char *p_buf, bt_vendor_transmit_result_t result);
+
+/* a previously setup buffer is read and available for processing
+ buffer is deallocated in stack when processed */
+typedef int (*data_ind_cb)(TRANSAC transac, char *p_buf, int len);
+
+typedef struct {
+ /** set to sizeof(bt_vendor_callbacks_t) */
+ size_t size;
+
+ /* notifies caller result of preload request */
+ preload_result_cb preload_cb;
+
+ /* notifies caller result of postload request */
+ postload_result_cb postload_cb;
+
+ /* notifies caller result of lpm enable/disable */
+ lpm_result_cb lpm_cb;
+
+ /* notifies hardware on host wake state */
+ hostwake_ind_cb hostwake_ind;
+
+ /* buffer allocation request */
+ alloc_mem_cb alloc;
+
+ /* buffer deallocation request */
+ dealloc_mem_cb dealloc;
+
+ /* notifies stack data is available */
+ data_ind_cb data_ind;
+
+ /* notifies caller when a buffer is transmitted (or failed) */
+ tx_result_cb tx_result;
+} bt_vendor_callbacks_t;
+
+/*
+ * Bluetooth Vendor Interface
+ */
+typedef struct {
+ /** Set to sizeof(bt_vendor_interface_t) */
+ size_t size;
+
+ /**
+ * Opens the interface and provides the callback routines
+ * to the implemenation of this interface.
+ */
+ int (*init)(const bt_vendor_callbacks_t* p_cb);
+
+ /** Chip power control */
+ void (*set_power)(bt_vendor_chip_power_state_t state);
+
+ /** Set low power mode wake */
+ int (*lpm)(bt_vendor_low_power_event_t event);
+
+ /** Called prior to stack initialization */
+ void (*preload)(TRANSAC transac);
+
+ /** Called post stack initialization */
+ void (*postload)(TRANSAC transac);
+
+ /** Transmit buffer */
+ int (*transmit_buf)(TRANSAC transac, char *p_buf, int len);
+
+ /** Controls receive flow */
+ int (*set_rxflow)(bt_rx_flow_state_t state);
+
+ /** Closes the interface */
+ void (*cleanup)( void );
+} bt_vendor_interface_t;
+
+
+/*
+ * External shared lib functions
+ */
+
+extern const bt_vendor_interface_t* bt_vendor_get_interface(void);
+
+#endif /* BT_VENDOR_LIB_H */
+
diff --git a/vendor/libvendor/include/upio.h b/vendor/libvendor/include/upio.h
new file mode 100644
index 0000000..9135da5
--- /dev/null
+++ b/vendor/libvendor/include/upio.h
@@ -0,0 +1,136 @@
+/************************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * This program is the proprietary software of Broadcom Corporation and/or its
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
+ *
+ * Except as expressly set forth in the Authorized License,
+ *
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
+ * Broadcom integrated circuit products.
+ *
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT
+ * OF USE OR PERFORMANCE OF THE SOFTWARE.
+ *
+ * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR
+ * ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+ *
+ ************************************************************************************/
+
+/************************************************************************************
+ *
+ * Filename: upio.h
+ *
+ * Description:
+ *
+ ***********************************************************************************/
+
+#ifndef UPIO_H
+#define UPIO_H
+
+/************************************************************************************
+** Constants & Macros
+************************************************************************************/
+
+#define UPIO_BT_POWER_OFF 0
+#define UPIO_BT_POWER_ON 1
+
+/* UPIO signals */
+enum {
+ UPIO_BT_WAKE = 0,
+ UPIO_HOST_WAKE,
+ UPIO_MAX_COUNT
+};
+
+/* UPIO assertion/deassertion */
+enum {
+ UPIO_UNKNOWN = 0,
+ UPIO_DEASSERT,
+ UPIO_ASSERT
+};
+
+
+/************************************************************************************
+** Extern variables and functions
+************************************************************************************/
+
+/************************************************************************************
+** Functions
+************************************************************************************/
+
+/*******************************************************************************
+**
+** Function upio_init
+**
+** Description Initialization
+**
+** Returns None
+**
+*******************************************************************************/
+void upio_init(void);
+
+/*******************************************************************************
+**
+** Function upio_cleanup
+**
+** Description Clean up
+**
+** Returns None
+**
+*******************************************************************************/
+void upio_cleanup(void);
+
+/*******************************************************************************
+**
+** Function upio_set_bluetooth_power
+**
+** Description Interact with low layer driver to set Bluetooth power
+** on/off.
+**
+** Returns 0 : SUCCESS or Not-Applicable
+** <0 : ERROR
+**
+*******************************************************************************/
+int upio_set_bluetooth_power(int on);
+
+/*******************************************************************************
+**
+** Function upio_set
+**
+** Description Set i/o based on polarity
+**
+** Returns None
+**
+*******************************************************************************/
+void upio_set(uint8_t pio, uint8_t action, uint8_t polarity);
+
+#endif /* UPIO_H */
+
diff --git a/vendor/libvendor/include/userial.h b/vendor/libvendor/include/userial.h
new file mode 100644
index 0000000..c7a97b9
--- /dev/null
+++ b/vendor/libvendor/include/userial.h
@@ -0,0 +1,245 @@
+/************************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * This program is the proprietary software of Broadcom Corporation and/or its
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
+ *
+ * Except as expressly set forth in the Authorized License,
+ *
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
+ * Broadcom integrated circuit products.
+ *
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT
+ * OF USE OR PERFORMANCE OF THE SOFTWARE.
+ *
+ * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR
+ * ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+ *
+ ************************************************************************************/
+
+/************************************************************************************
+ *
+ * Filename: userial.h
+ *
+ * Description:
+ *
+ ***********************************************************************************/
+
+#ifndef USERIAL_H
+#define USERIAL_H
+
+/************************************************************************************
+** Constants & Macros
+************************************************************************************/
+
+/**** port IDs ****/
+#define USERIAL_PORT_1 0
+#define USERIAL_PORT_2 1
+#define USERIAL_PORT_3 2
+#define USERIAL_PORT_4 3
+#define USERIAL_PORT_5 4
+#define USERIAL_PORT_6 5
+#define USERIAL_PORT_7 6
+#define USERIAL_PORT_8 7
+#define USERIAL_PORT_9 8
+#define USERIAL_PORT_10 9
+#define USERIAL_PORT_11 10
+#define USERIAL_PORT_12 11
+#define USERIAL_PORT_13 12
+#define USERIAL_PORT_14 13
+#define USERIAL_PORT_15 14
+#define USERIAL_PORT_16 15
+#define USERIAL_PORT_17 16
+#define USERIAL_PORT_18 17
+
+/**** baud rates ****/
+#define USERIAL_BAUD_300 0
+#define USERIAL_BAUD_600 1
+#define USERIAL_BAUD_1200 2
+#define USERIAL_BAUD_2400 3
+#define USERIAL_BAUD_9600 4
+#define USERIAL_BAUD_19200 5
+#define USERIAL_BAUD_57600 6
+#define USERIAL_BAUD_115200 7
+#define USERIAL_BAUD_230400 8
+#define USERIAL_BAUD_460800 9
+#define USERIAL_BAUD_921600 10
+#define USERIAL_BAUD_1M 11
+#define USERIAL_BAUD_1_5M 12
+#define USERIAL_BAUD_2M 13
+#define USERIAL_BAUD_3M 14
+#define USERIAL_BAUD_4M 15
+#define USERIAL_BAUD_AUTO 16
+
+/**** Data Format ****/
+/* Stop Bits */
+#define USERIAL_STOPBITS_1 1
+#define USERIAL_STOPBITS_1_5 (1<<1)
+#define USERIAL_STOPBITS_2 (1<<2)
+
+/* Parity Bits */
+#define USERIAL_PARITY_NONE (1<<3)
+#define USERIAL_PARITY_EVEN (1<<4)
+#define USERIAL_PARITY_ODD (1<<5)
+
+/* Data Bits */
+#define USERIAL_DATABITS_5 (1<<6)
+#define USERIAL_DATABITS_6 (1<<7)
+#define USERIAL_DATABITS_7 (1<<8)
+#define USERIAL_DATABITS_8 (1<<9)
+
+typedef enum {
+ USERIAL_OP_INIT,
+ USERIAL_OP_RXFLOW_ON,
+ USERIAL_OP_RXFLOW_OFF,
+#if (BT_WAKE_VIA_USERIAL_IOCTL==TRUE)
+ USERIAL_OP_ASSERT_BT_WAKE,
+ USERIAL_OP_DEASSERT_BT_WAKE,
+ USERIAL_OP_GET_BT_WAKE_STATE
+#endif
+} userial_ioctl_op_t;
+
+#if (BT_WAKE_VIA_USERIAL_IOCTL==TRUE)
+/* These are the ioctl values used for bt_wake ioctl via UART driver. you may need to
+ * redefine them on you platform!
+ * Logically they need to be unique and not colide with existing uart ioctl's.
+ */
+#ifndef USERIAL_IOCTL_BT_WAKE_ASSERT
+#define USERIAL_IOCTL_BT_WAKE_ASSERT 0x8003
+#endif
+#ifndef USERIAL_IOCTL_BT_WAKE_DEASSERT
+#define USERIAL_IOCTL_BT_WAKE_DEASSERT 0x8004
+#endif
+#ifndef USERIAL_IOCTL_BT_WAKE_GET_ST
+#define USERIAL_IOCTL_BT_WAKE_GET_ST 0x8005
+#endif
+#endif // (BT_WAKE_VIA_USERIAL_IOCTL==TRUE)
+
+/************************************************************************************
+** Type definitions
+************************************************************************************/
+
+/* Structure used to configure serial port during open */
+typedef struct
+{
+ uint16_t fmt; /* Data format */
+ uint8_t baud; /* Baud rate */
+} tUSERIAL_CFG;
+
+/************************************************************************************
+** Extern variables and functions
+************************************************************************************/
+
+/************************************************************************************
+** Functions
+************************************************************************************/
+
+/*******************************************************************************
+**
+** Function userial_init
+**
+** Description Initializes the userial driver
+**
+** Returns TRUE/FALSE
+**
+*******************************************************************************/
+uint8_t userial_init(void);
+
+/*******************************************************************************
+**
+** Function userial_open
+**
+** Description Open the indicated serial port with the given configuration
+**
+** Returns TRUE/FALSE
+**
+*******************************************************************************/
+uint8_t userial_open(uint8_t port, tUSERIAL_CFG *p_cfg);
+
+/*******************************************************************************
+**
+** Function userial_read
+**
+** Description Read data from the userial port
+**
+** Returns Number of bytes actually read from the userial port and
+** copied into p_data. This may be less than len.
+**
+*******************************************************************************/
+uint16_t userial_read(uint8_t *p_buffer, uint16_t len);
+
+/*******************************************************************************
+**
+** Function userial_write
+**
+** Description Write data to the userial port
+**
+** Returns Number of bytes actually written to the userial port. This
+** may be less than len.
+**
+*******************************************************************************/
+uint16_t userial_write(uint8_t *p_data, uint16_t len);
+
+/*******************************************************************************
+**
+** Function userial_close
+**
+** Description Close the userial port
+**
+** Returns None
+**
+*******************************************************************************/
+void userial_close(void);
+
+/*******************************************************************************
+**
+** Function userial_change_baud
+**
+** Description Change baud rate of userial port
+**
+** Returns None
+**
+*******************************************************************************/
+void userial_change_baud(uint8_t baud);
+
+/*******************************************************************************
+**
+** Function userial_ioctl
+**
+** Description ioctl inteface
+**
+** Returns None
+**
+*******************************************************************************/
+void userial_ioctl(userial_ioctl_op_t op, void *p_data);
+
+#endif /* USERIAL_H */
+
diff --git a/vendor/libvendor/include/utils.h b/vendor/libvendor/include/utils.h
new file mode 100644
index 0000000..c1a5f35
--- /dev/null
+++ b/vendor/libvendor/include/utils.h
@@ -0,0 +1,200 @@
+/************************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * This program is the proprietary software of Broadcom Corporation and/or its
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
+ *
+ * Except as expressly set forth in the Authorized License,
+ *
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
+ * Broadcom integrated circuit products.
+ *
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT
+ * OF USE OR PERFORMANCE OF THE SOFTWARE.
+ *
+ * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR
+ * ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+ *
+ ************************************************************************************/
+
+/************************************************************************************
+ *
+ * Filename: utils.h
+ *
+ * Description: Utility functions declaration
+ *
+ ***********************************************************************************/
+
+#ifndef UTILS_H
+#define UTILS_H
+
+/************************************************************************************
+** Constants & Macros
+************************************************************************************/
+
+#define STREAM_TO_UINT16(u16, p) {u16 = ((uint16_t)(*(p)) + (((uint16_t)(*((p) + 1))) << 8)); (p) += 2;}
+#define UINT16_TO_STREAM(p, u16) {*(p)++ = (uint8_t)(u16); *(p)++ = (uint8_t)((u16) >> 8);}
+#define UINT32_TO_STREAM(p, u32) {*(p)++ = (uint8_t)(u32); *(p)++ = (uint8_t)((u32) >> 8); *(p)++ = (uint8_t)((u32) >> 16); *(p)++ = (uint8_t)((u32) >> 24);}
+
+/************************************************************************************
+** Type definitions
+************************************************************************************/
+
+typedef struct
+{
+ void *p_first;
+ void *p_last;
+ uint16_t count;
+} BUFFER_Q;
+
+/************************************************************************************
+** Extern variables and functions
+************************************************************************************/
+
+/************************************************************************************
+** Functions
+************************************************************************************/
+
+/*******************************************************************************
+**
+** Function utils_init
+**
+** Description Utils initialization
+**
+** Returns None
+**
+*******************************************************************************/
+void utils_init ();
+
+/*******************************************************************************
+**
+** Function utils_cleanup
+**
+** Description Utils cleanup
+**
+** Returns None
+**
+*******************************************************************************/
+void utils_cleanup ();
+
+/*******************************************************************************
+**
+** Function utils_queue_init
+**
+** Description Initialize the given buffer queue
+**
+** Returns None
+**
+*******************************************************************************/
+void utils_queue_init (BUFFER_Q *p_q);
+
+/*******************************************************************************
+**
+** Function utils_enqueue
+**
+** Description Enqueue a buffer at the tail of the given queue
+**
+** Returns None
+**
+*******************************************************************************/
+void utils_enqueue (BUFFER_Q *p_q, void *p_buf);
+
+/*******************************************************************************
+**
+** Function utils_dequeue
+**
+** Description Dequeues a buffer from the head of the given queue
+**
+** Returns NULL if queue is empty, else buffer
+**
+*******************************************************************************/
+void *utils_dequeue (BUFFER_Q *p_q);
+
+/*******************************************************************************
+**
+** Function utils_getnext
+**
+** Description Return a pointer to the next buffer linked to the given buffer
+**
+** Returns NULL if the given buffer does not point to any next buffer,
+** else next buffer address
+**
+*******************************************************************************/
+void *utils_getnext (void *p_buf);
+
+/*******************************************************************************
+**
+** Function utils_remove_from_queue
+**
+** Description Dequeue the given buffer from the middle of the given queue
+**
+** Returns NULL if the given queue is empty, else the given buffer
+**
+*******************************************************************************/
+void *utils_remove_from_queue (BUFFER_Q *p_q, void *p_buf);
+
+/*******************************************************************************
+**
+** Function utils_delay
+**
+** Description sleep unconditionally for timeout milliseconds
+**
+** Returns None
+**
+*******************************************************************************/
+void utils_delay (uint32_t timeout);
+
+/*******************************************************************************
+**
+** Function utils_lock
+**
+** Description application calls this function before entering critical
+** section
+**
+** Returns None
+**
+*******************************************************************************/
+void utils_lock (void);
+
+/*******************************************************************************
+**
+** Function utils_unlock
+**
+** Description application calls this function when leaving critical
+** section
+**
+** Returns None
+**
+*******************************************************************************/
+void utils_unlock (void);
+
+#endif /* UTILS_H */
+
diff --git a/vendor/libvendor/include/vnd_buildcfg.h b/vendor/libvendor/include/vnd_buildcfg.h
new file mode 100644
index 0000000..a6fbb23
--- /dev/null
+++ b/vendor/libvendor/include/vnd_buildcfg.h
@@ -0,0 +1,14 @@
+#ifndef VND_BUILDCFG_H
+#define VND_BUILDCFG_H
+//#define BLUETOOTH_UART_DEVICE_PORT "/dev/ttyHS0" /* pyramid */
+//#define FW_PATCHFILE_LOCATION ("/etc/firmware/") /* pyramid */
+//#define LPM_BT_WAKE_POLARITY 0 /* pyramid */
+//#define LPM_HOST_WAKE_POLARITY 0 /* pyramid */
+#define BT_WAKE_VIA_USERIAL_IOCTL TRUE
+#define LPM_IDLE_TIMEOUT_MULTIPLE 5
+#define BTSNOOPDISP_INCLUDED TRUE
+#define BTSNOOP_FILENAME "/data/misc/bluedroid/btsnoop_hci.cfa"
+#define SNOOP_CONFIG_PATH "/data/misc/bluedroid/btsnoop_enabled"
+#define BTSNOOP_DBG FALSE
+#define SCO_USE_I2S_INTERFACE TRUE
+#endif // VND_BUILDCFG_H
diff --git a/vendor/libvendor/src/bt_vendor_brcm.c b/vendor/libvendor/src/bt_vendor_brcm.c
new file mode 100644
index 0000000..20cd7a3
--- /dev/null
+++ b/vendor/libvendor/src/bt_vendor_brcm.c
@@ -0,0 +1,455 @@
+/************************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * This program is the proprietary software of Broadcom Corporation and/or its
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
+ *
+ * Except as expressly set forth in the Authorized License,
+ *
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
+ * Broadcom integrated circuit products.
+ *
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT
+ * OF USE OR PERFORMANCE OF THE SOFTWARE.
+ *
+ * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR
+ * ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+ *
+ ************************************************************************************/
+
+/************************************************************************************
+ *
+ * Filename: bt_vendor_brcm.c
+ *
+ * Description: Bluetooth vendor library implementation
+ *
+ ***********************************************************************************/
+
+#define LOG_TAG "bt_vendor_brcm"
+
+#include <utils/Log.h>
+#include <pthread.h>
+#include "bt_vendor_brcm.h"
+#include "upio.h"
+#include "utils.h"
+#include "userial.h"
+
+#ifndef BTVND_DBG
+#define BTVND_DBG FALSE
+#endif
+
+#if (BTVND_DBG == TRUE)
+#define BTVNDDBG LOGD
+#else
+#define BTVNDDBG
+#endif
+
+/************************************************************************************
+** Externs
+************************************************************************************/
+
+extern int num_hci_cmd_pkts;
+void hci_h4_init(void);
+void hci_h4_cleanup(void);
+void hci_h4_send_msg(VND_BT_HDR *p_msg);
+uint16_t hci_h4_receive_msg(void);
+void hci_h4_get_acl_data_length(void);
+void hw_config_start(void);
+uint8_t hw_lpm_enable(uint8_t turn_on);
+void hw_lpm_deassert_bt_wake(void);
+void hw_lpm_allow_bt_device_sleep(void);
+void hw_lpm_assert_bt_wake(void);
+#if (SCO_CFG_INCLUDED == TRUE)
+void hw_sco_config(void);
+#endif
+
+/************************************************************************************
+** Variables
+************************************************************************************/
+
+bt_vendor_callbacks_t *bt_vendor_cbacks = NULL;
+
+/************************************************************************************
+** Static Variables
+************************************************************************************/
+
+static pthread_t worker_thread;
+static volatile uint8_t lib_running = 0;
+static pthread_mutex_t vnd_mutex;
+static pthread_cond_t vnd_cond;
+static volatile uint16_t ready_events = 0;
+static volatile uint8_t tx_cmd_pkts_pending = FALSE;
+
+static const tUSERIAL_CFG userial_init_cfg =
+{
+ (USERIAL_DATABITS_8 | USERIAL_PARITY_NONE | USERIAL_STOPBITS_1),
+ USERIAL_BAUD_115200
+};
+
+BUFFER_Q tx_q;
+
+/************************************************************************************
+** Functions
+************************************************************************************/
+
+static void *bt_vndor_worker_thread(void *arg);
+
+void btvnd_signal_event(uint16_t event)
+{
+ pthread_mutex_lock(&vnd_mutex);
+ ready_events |= event;
+ pthread_cond_signal(&vnd_cond);
+ pthread_mutex_unlock(&vnd_mutex);
+}
+
+/*****************************************************************************
+**
+** BLUETOOTH VENDOR LIBRARY INTERFACE FUNCTIONS
+**
+*****************************************************************************/
+
+static int init(const bt_vendor_callbacks_t* p_cb)
+{
+ pthread_attr_t thread_attr;
+ struct sched_param param;
+ int policy;
+
+ BTVNDDBG("init");
+
+ if (p_cb == NULL)
+ {
+ LOGE("init failed with no user callbacks!");
+ return BT_VENDOR_STATUS_FAIL;
+ }
+
+ /* store reference to user callbacks */
+ bt_vendor_cbacks = (bt_vendor_callbacks_t *) p_cb;
+
+ utils_init();
+ upio_init();
+ hci_h4_init();
+ userial_init();
+
+ utils_queue_init(&tx_q);
+
+ if (lib_running)
+ {
+ LOGW("init has been called repeatedly without calling cleanup ?");
+ }
+
+ lib_running = 1;
+ ready_events = 0;
+ pthread_mutex_init(&vnd_mutex, NULL);
+ pthread_cond_init(&vnd_cond, NULL);
+ pthread_attr_init(&thread_attr);
+
+ if (pthread_create(&worker_thread, &thread_attr, bt_vndor_worker_thread, NULL) != 0)
+ {
+ LOGE("pthread_create failed!");
+ lib_running = 0;
+ return BT_VENDOR_STATUS_FAIL;
+ }
+
+ if(pthread_getschedparam(worker_thread, &policy, &param)==0)
+ {
+ policy = SCHED_FIFO;
+ param.sched_priority = BTVND_MAIN_THREAD_PRIORITY;
+ pthread_setschedparam(worker_thread, policy, &param);
+ }
+
+ return BT_VENDOR_STATUS_SUCCESS;
+}
+
+
+/** Chip power control */
+static void set_power(bt_vendor_chip_power_state_t state)
+{
+ BTVNDDBG("set_power %d", state);
+
+ if (state == BT_VENDOR_CHIP_PWR_OFF)
+ upio_set_bluetooth_power(UPIO_BT_POWER_OFF);
+ else if (state == BT_VENDOR_CHIP_PWR_ON)
+ upio_set_bluetooth_power(UPIO_BT_POWER_ON);
+}
+
+
+/** Configure low power mode wake state */
+static int lpm(bt_vendor_low_power_event_t event)
+{
+ uint8_t status = TRUE;
+
+ switch (event)
+ {
+ case BT_VENDOR_LPM_DISABLE:
+ btvnd_signal_event(VND_EVENT_LPM_DISABLE);
+ break;
+
+ case BT_VENDOR_LPM_ENABLE:
+ btvnd_signal_event(VND_EVENT_LPM_ENABLE);
+ break;
+
+ case BT_VENDOR_LPM_WAKE_ASSERT:
+ btvnd_signal_event(VND_EVENT_LPM_WAKE_DEVICE);
+ break;
+
+ case BT_VENDOR_LPM_WAKE_DEASSERT:
+ btvnd_signal_event(VND_EVENT_LPM_ALLOW_SLEEP);
+ break;
+ }
+
+ return(status == TRUE) ? BT_VENDOR_STATUS_SUCCESS : BT_VENDOR_STATUS_FAIL;
+}
+
+
+/** Called prio to stack initialization */
+static void preload(TRANSAC transac)
+{
+ BTVNDDBG("preload");
+ btvnd_signal_event(VND_EVENT_PRELOAD);
+}
+
+
+/** Called post stack initialization */
+static void postload(TRANSAC transac)
+{
+ BTVNDDBG("postload");
+ btvnd_signal_event(VND_EVENT_POSTLOAD);
+}
+
+
+/** Transmit frame */
+static int transmit_buf(TRANSAC transac, char *p_buf, int len)
+{
+ utils_enqueue(&tx_q, (void *) transac);
+
+ btvnd_signal_event(VND_EVENT_TX);
+
+ return BT_VENDOR_STATUS_SUCCESS;
+}
+
+
+/** Controls receive flow */
+static int set_rxflow(bt_rx_flow_state_t state)
+{
+ BTVNDDBG("set_rxflow %d", state);
+
+ userial_ioctl(((state == BT_RXFLOW_ON) ? USERIAL_OP_RXFLOW_ON : USERIAL_OP_RXFLOW_OFF), NULL);
+
+ return BT_VENDOR_STATUS_SUCCESS;
+}
+
+
+/** Closes the interface */
+static void cleanup( void )
+{
+ BTVNDDBG("cleanup");
+
+ if (lib_running)
+ {
+ lib_running = 0;
+ btvnd_signal_event(VND_EVENT_EXIT);
+ pthread_join(worker_thread, NULL);
+ }
+
+ userial_close();
+ hci_h4_cleanup();
+ upio_cleanup();
+ utils_cleanup();
+
+ bt_vendor_cbacks = NULL;
+}
+
+
+static const bt_vendor_interface_t bluetoothVendorLibInterface = {
+ sizeof(bt_vendor_interface_t),
+ init,
+ set_power,
+ lpm,
+ preload,
+ postload,
+ transmit_buf,
+ set_rxflow,
+ cleanup
+};
+
+
+/*******************************************************************************
+**
+** Function bt_vndor_worker_thread
+**
+** Description Mian worker thread
+**
+** Returns void *
+**
+*******************************************************************************/
+static void *bt_vndor_worker_thread(void *arg)
+{
+ uint16_t events;
+ VND_BT_HDR *p_msg, *p_next_msg;
+
+ BTVNDDBG("bt_vndor_worker_thread started");
+ tx_cmd_pkts_pending = FALSE;
+
+ while (lib_running)
+ {
+ pthread_mutex_lock(&vnd_mutex);
+ while (ready_events == 0)
+ {
+ pthread_cond_wait(&vnd_cond, &vnd_mutex);
+ }
+ events = ready_events;
+ ready_events = 0;
+ pthread_mutex_unlock(&vnd_mutex);
+
+ if (events & VND_EVENT_RX)
+ {
+ hci_h4_receive_msg();
+
+ if ((tx_cmd_pkts_pending == TRUE) && (num_hci_cmd_pkts > 0))
+ {
+ /* Got HCI Cmd Credits from Controller.
+ * Prepare to send prior pending Cmd packets in the
+ * following VND_EVENT_TX session.
+ */
+ events |= VND_EVENT_TX;
+ }
+ }
+
+ if (events & VND_EVENT_PRELOAD)
+ {
+ userial_open(USERIAL_PORT_1, (tUSERIAL_CFG *) &userial_init_cfg);
+ hw_config_start();
+ }
+
+ if (events & VND_EVENT_POSTLOAD)
+ {
+ /* Start from SCO related H/W configuration, if SCO configuration
+ * is required. Then, follow with reading requests of getting
+ * ACL data length for both BR/EDR and LE.
+ */
+#if (SCO_CFG_INCLUDED == TRUE)
+ hw_sco_config();
+#else
+ hci_h4_get_acl_data_length();
+#endif
+ }
+
+ if (events & VND_EVENT_TX)
+ {
+ /*
+ * We will go through every packets in the tx queue.
+ * Fine to clear tx_cmd_pkts_pending.
+ */
+ tx_cmd_pkts_pending = FALSE;
+
+ p_next_msg = tx_q.p_first;
+ while (p_next_msg)
+ {
+ if ((p_next_msg->event & MSG_EVT_MASK) == MSG_STACK_TO_VND_HCI_CMD)
+ {
+ /*
+ * if we have used up controller's outstanding HCI command credits
+ * (normally is 1), skip all HCI command packets in the queue.
+ * The pending command packets will be sent once controller gives
+ * back us credits through CommandCompleteEvent or CommandStatusEvent.
+ */
+ if ((tx_cmd_pkts_pending == TRUE) || (num_hci_cmd_pkts <= 0))
+ {
+ tx_cmd_pkts_pending = TRUE;
+ p_next_msg = utils_getnext(p_next_msg);
+ continue;
+ }
+ }
+
+ p_msg = p_next_msg;
+ p_next_msg = utils_getnext(p_msg);
+ utils_remove_from_queue(&tx_q, p_msg);
+ hci_h4_send_msg(p_msg);
+ }
+
+ if (tx_cmd_pkts_pending == TRUE)
+ BTVNDDBG("Used up Tx Cmd credits");
+
+ }
+
+ if (events & VND_EVENT_LPM_ENABLE)
+ {
+ hw_lpm_enable(TRUE);
+ }
+
+ if (events & VND_EVENT_LPM_DISABLE)
+ {
+ hw_lpm_enable(FALSE);
+ }
+
+ if (events & VND_EVENT_LPM_IDLE_TIMEOUT)
+ {
+ hw_lpm_deassert_bt_wake();
+ }
+
+ if (events & VND_EVENT_LPM_ALLOW_SLEEP)
+ {
+ hw_lpm_allow_bt_device_sleep();
+ }
+
+ if (events & VND_EVENT_LPM_WAKE_DEVICE)
+ {
+ hw_lpm_assert_bt_wake();
+ }
+
+ if (events & VND_EVENT_EXIT)
+ break;
+ }
+
+ BTVNDDBG("bt_vndor_worker_thread exiting");
+
+ pthread_exit(NULL);
+
+ return NULL; // compiler friendly
+}
+
+
+/*******************************************************************************
+**
+** Function bt_vendor_get_interface
+**
+** Description Caller calls this function to get API instance
+**
+** Returns API table
+**
+*******************************************************************************/
+const bt_vendor_interface_t *bt_vendor_get_interface(void)
+{
+ return &bluetoothVendorLibInterface;
+}
+
+
+
diff --git a/vendor/libvendor/src/btsnoop.c b/vendor/libvendor/src/btsnoop.c
new file mode 100644
index 0000000..a0476b4
--- /dev/null
+++ b/vendor/libvendor/src/btsnoop.c
@@ -0,0 +1,721 @@
+/************************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * This program is the proprietary software of Broadcom Corporation and/or its
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
+ *
+ * Except as expressly set forth in the Authorized License,
+ *
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
+ * Broadcom integrated circuit products.
+ *
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT
+ * OF USE OR PERFORMANCE OF THE SOFTWARE.
+ *
+ * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR
+ * ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+ *
+ ************************************************************************************/
+
+/****************************************************************************
+ *
+ * Name: btsnoopdisp.c
+ *
+ * Function: this file contains functions to generate a BTSNOOP file
+ *
+ *
+ ****************************************************************************/
+#include <stdio.h>
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <pthread.h>
+#include <sys/prctl.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <fcntl.h>
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+/* for gettimeofday */
+#include <sys/time.h>
+/* for the S_* open parameters */
+#include <sys/stat.h>
+/* for write */
+#include <unistd.h>
+/* for O_* open parameters */
+#include <fcntl.h>
+/* defines the O_* open parameters */
+#include <fcntl.h>
+
+#define LOG_TAG "BTSNOOP-DISP"
+#include <cutils/log.h>
+
+#include "bt_vendor_brcm.h"
+#include "utils.h"
+
+#ifndef BTSNOOP_DBG
+#define BTSNOOP_DBG FALSE
+#endif
+
+#if (BTSNOOP_DBG == TRUE)
+#define SNOOPDBG LOGD
+#else
+#define SNOOPDBG
+#endif
+
+/* file descriptor of the BT snoop file (by default, -1 means disabled) */
+int hci_btsnoop_fd = -1;
+
+#if defined(BTSNOOPDISP_INCLUDED) && (BTSNOOPDISP_INCLUDED == TRUE)
+
+/* if not specified in .txt file then use this as default */
+#ifndef BTSNOOP_FILENAME
+
+//#define BTSNOOP_FILENAME "/sdcard/snoop_log.cfa"
+#error "BTSNOOP_FILENAME needs to be defined in vnd_buildcfg.h"
+
+#endif /* BTSNOOP_FILENAME */
+
+#endif /* BTSNOOPDISP_INCLUDED */
+
+/* Macro to perform a multiplication of 2 unsigned 32bit values and store the result
+ * in an unsigned 64 bit value (as two 32 bit variables):
+ * u64 = u32In1 * u32In2
+ * u32OutLow = u64[31:0]
+ * u32OutHi = u64[63:32]
+ * basically the algorithm:
+ * (hi1*2^16 + lo1)*(hi2*2^16 + lo2) = lo1*lo2 + (hi1*hi2)*2^32 + (hi1*lo2 + hi2*lo1)*2^16
+ * and the carry is propagated 16 bit by 16 bit:
+ * result[15:0] = lo1*lo2 & 0xFFFF
+ * result[31:16] = ((lo1*lo2) >> 16) + (hi1*lo2 + hi2*lo1)
+ * and so on
+ */
+#define HCIDISP_MULT_64(u32In1, u32In2, u32OutLo, u32OutHi) \
+do { \
+ uint32_t u32In1Tmp = u32In1; \
+ uint32_t u32In2Tmp = u32In2; \
+ uint32_t u32Tmp, u32Carry; \
+ u32OutLo = (u32In1Tmp & 0xFFFF) * (u32In2Tmp & 0xFFFF); /*lo1*lo2*/ \
+ u32OutHi = ((u32In1Tmp >> 16) & 0xFFFF) * ((u32In2Tmp >> 16) & 0xFFFF); /*hi1*hi2*/ \
+ u32Tmp = (u32In1Tmp & 0xFFFF) * ((u32In2Tmp >> 16) & 0xFFFF); /*lo1*hi2*/ \
+ u32Carry = (uint32_t)((u32OutLo>>16)&0xFFFF); \
+ u32Carry += (u32Tmp&0xFFFF); \
+ u32OutLo += (u32Tmp << 16) ; \
+ u32OutHi += (u32Tmp >> 16); \
+ u32Tmp = ((u32In1Tmp >> 16) & 0xFFFF) * (u32In2Tmp & 0xFFFF); \
+ u32Carry += (u32Tmp)&0xFFFF; \
+ u32Carry>>=16; \
+ u32OutLo += (u32Tmp << 16); \
+ u32OutHi += (u32Tmp >> 16); \
+ u32OutHi += u32Carry; \
+} while (0)
+
+/* Macro to make an addition of 2 64 bit values:
+ * result = (u32OutHi & u32OutLo) + (u32InHi & u32InLo)
+ * u32OutHi = result[63:32]
+ * u32OutLo = result[31:0]
+ */
+#define HCIDISP_ADD_64(u32InLo, u32InHi, u32OutLo, u32OutHi) \
+do { \
+ (u32OutLo) += (u32InLo); \
+ if ((u32OutLo) < (u32InLo)) (u32OutHi)++; \
+ (u32OutHi) += (u32InHi); \
+} while (0)
+
+/* EPOCH in microseconds since 01/01/0000 : 0x00dcddb3.0f2f8000 */
+#define BTSNOOP_EPOCH_HI 0x00dcddb3U
+#define BTSNOOP_EPOCH_LO 0x0f2f8000U
+
+/*******************************************************************************
+ **
+ ** Function tv_to_btsnoop_ts
+ **
+ ** Description This function generate a BT Snoop timestamp.
+ **
+ ** Returns void
+ **
+ ** NOTE
+ ** The return value is 64 bit as 2 32 bit variables out_lo and * out_hi.
+ ** A BT Snoop timestamp is the number of microseconds since 01/01/0000.
+ ** The timeval structure contains the number of microseconds since EPOCH
+ ** (01/01/1970) encoded as: tv.tv_sec, number of seconds since EPOCH and
+ ** tv_usec, number of microseconds in current second
+ **
+ ** Therefore the algorithm is:
+ ** result = tv.tv_sec * 1000000
+ ** result += tv.tv_usec
+ ** result += EPOCH_OFFSET
+ *******************************************************************************/
+static void tv_to_btsnoop_ts(uint32_t *out_lo, uint32_t *out_hi, struct timeval *tv)
+{
+ /* multiply the seconds by 1000000 */
+ HCIDISP_MULT_64(tv->tv_sec, 0xf4240, *out_lo, *out_hi);
+
+ /* add the microseconds */
+ HCIDISP_ADD_64((uint32_t)tv->tv_usec, 0, *out_lo, *out_hi);
+
+ /* add the epoch */
+ HCIDISP_ADD_64(BTSNOOP_EPOCH_LO, BTSNOOP_EPOCH_HI, *out_lo, *out_hi);
+}
+
+/*******************************************************************************
+ **
+ ** Function l_to_be
+ **
+ ** Description Function to convert a 32 bit value into big endian format
+ **
+ ** Returns 32 bit value in big endian format
+*******************************************************************************/
+static uint32_t l_to_be(uint32_t x)
+{
+ #if __BIG_ENDIAN != TRUE
+ x = (x >> 24) |
+ ((x >> 8) & 0xFF00) |
+ ((x << 8) & 0xFF0000) |
+ (x << 24);
+ #endif
+ return x;
+}
+
+/*******************************************************************************
+ **
+ ** Function btsnoop_is_open
+ **
+ ** Description Function to check if BTSNOOP is open
+ **
+ ** Returns 1 if open otherwise 0
+*******************************************************************************/
+int btsnoop_is_open(void)
+{
+#if defined(BTSNOOPDISP_INCLUDED) && (BTSNOOPDISP_INCLUDED == TRUE)
+ SNOOPDBG("btsnoop_is_open: snoop fd = %d\n", hci_btsnoop_fd);
+
+ if (hci_btsnoop_fd != -1)
+ {
+ return 1;
+ }
+ return 0;
+#else
+ return 2; /* Snoop not available */
+#endif
+}
+
+/*******************************************************************************
+ **
+ ** Function btsnoop_log_open
+ **
+ ** Description Function to open the BTSNOOP file
+ **
+ ** Returns None
+*******************************************************************************/
+static int btsnoop_log_open(void)
+{
+#if defined(BTSNOOPDISP_INCLUDED) && (BTSNOOPDISP_INCLUDED == TRUE)
+ hci_btsnoop_fd = -1;
+
+ SNOOPDBG("btsnoop_log_open: snoop log file = %s\n", BTSNOOP_FILENAME);
+
+ /* write the BT snoop header */
+ if (BTSNOOP_FILENAME != NULL)
+ {
+ hci_btsnoop_fd = open((char*)BTSNOOP_FILENAME, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
+ if (hci_btsnoop_fd == -1)
+ {
+ perror("open");
+ SNOOPDBG("btsnoop_log_open: Unable to open snoop log file\n");
+ hci_btsnoop_fd = -1;
+ return 0;
+ }
+ write(hci_btsnoop_fd, "btsnoop\0\0\0\0\1\0\0\x3\xea", 16);
+ return 1;
+ }
+#else
+ return 2; /* Snoop not available */
+#endif
+}
+
+/*******************************************************************************
+ **
+ ** Function btsnoop_log_close
+ **
+ ** Description Function to close the BTSNOOP file
+ **
+ ** Returns None
+*******************************************************************************/
+static int btsnoop_log_close(void)
+{
+#if defined(BTSNOOPDISP_INCLUDED) && (BTSNOOPDISP_INCLUDED == TRUE)
+ /* write the BT snoop header */
+ if (hci_btsnoop_fd != -1)
+ {
+ SNOOPDBG("btsnoop_log_close: Closing snoop log file\n");
+ close(hci_btsnoop_fd);
+ hci_btsnoop_fd = -1;
+ return 1;
+ }
+ return 0;
+#else
+ return 2; /* Snoop not available */
+#endif
+}
+
+/*******************************************************************************
+ **
+ ** Function btsnoop_hci_cmd
+ **
+ ** Description Function to add a command in the BTSNOOP file
+ **
+ ** Returns None
+*******************************************************************************/
+void btsnoop_hci_cmd(uint8_t *p)
+{
+ SNOOPDBG("btsnoop_hci_cmd: fd = %d", hci_btsnoop_fd);
+
+ if (hci_btsnoop_fd != -1)
+ {
+ uint32_t value, value_hi;
+ struct timeval tv;
+
+ /* since these display functions are called from different contexts */
+ utils_lock();
+
+ /* store the length in both original and included fields */
+ value = l_to_be(p[2] + 4);
+ write(hci_btsnoop_fd, &value, 4);
+ write(hci_btsnoop_fd, &value, 4);
+ /* flags: command sent from the host */
+ value = l_to_be(2);
+ write(hci_btsnoop_fd, &value, 4);
+ /* drops: none */
+ value = 0;
+ write(hci_btsnoop_fd, &value, 4);
+ /* time */
+ gettimeofday(&tv, NULL);
+ tv_to_btsnoop_ts(&value, &value_hi, &tv);
+ value_hi = l_to_be(value_hi);
+ value = l_to_be(value);
+ write(hci_btsnoop_fd, &value_hi, 4);
+ write(hci_btsnoop_fd, &value, 4);
+ /* data */
+ write(hci_btsnoop_fd, "\x1", 1);
+ write(hci_btsnoop_fd, p, p[2] + 3);
+
+ /* since these display functions are called from different contexts */
+ utils_unlock();
+ }
+}
+
+/*******************************************************************************
+ **
+ ** Function btsnoop_hci_evt
+ **
+ ** Description Function to add a event in the BTSNOOP file
+ **
+ ** Returns None
+*******************************************************************************/
+void btsnoop_hci_evt(uint8_t *p)
+{
+ SNOOPDBG("btsnoop_hci_evt: fd = %d", hci_btsnoop_fd);
+
+ if (hci_btsnoop_fd != -1)
+ {
+ uint32_t value, value_hi;
+ struct timeval tv;
+
+ /* since these display functions are called from different contexts */
+ utils_lock();
+
+ /* store the length in both original and included fields */
+ value = l_to_be(p[1] + 3);
+ write(hci_btsnoop_fd, &value, 4);
+ write(hci_btsnoop_fd, &value, 4);
+ /* flags: event received in the host */
+ value = l_to_be(3);
+ write(hci_btsnoop_fd, &value, 4);
+ /* drops: none */
+ value = 0;
+ write(hci_btsnoop_fd, &value, 4);
+ /* time */
+ gettimeofday(&tv, NULL);
+ tv_to_btsnoop_ts(&value, &value_hi, &tv);
+ value_hi = l_to_be(value_hi);
+ value = l_to_be(value);
+ write(hci_btsnoop_fd, &value_hi, 4);
+ write(hci_btsnoop_fd, &value, 4);
+ /* data */
+ write(hci_btsnoop_fd, "\x4", 1);
+ write(hci_btsnoop_fd, p, p[1] + 2);
+
+ /* since these display functions are called from different contexts */
+ utils_unlock();
+ }
+}
+
+/*******************************************************************************
+ **
+ ** Function btsnoop_sco_data
+ **
+ ** Description Function to add a SCO data packet in the BTSNOOP file
+ **
+ ** Returns None
+*******************************************************************************/
+void btsnoop_sco_data(uint8_t *p, uint8_t is_rcvd)
+{
+ SNOOPDBG("btsnoop_sco_data: fd = %d", hci_btsnoop_fd);
+
+ if (hci_btsnoop_fd != -1)
+ {
+ uint32_t value, value_hi;
+ struct timeval tv;
+
+ /* since these display functions are called from different contexts */
+ utils_lock();
+
+ /* store the length in both original and included fields */
+ value = l_to_be(p[2] + 4);
+ write(hci_btsnoop_fd, &value, 4);
+ write(hci_btsnoop_fd, &value, 4);
+ /* flags: data can be sent or received */
+ value = l_to_be(is_rcvd?1:0);
+ write(hci_btsnoop_fd, &value, 4);
+ /* drops: none */
+ value = 0;
+ write(hci_btsnoop_fd, &value, 4);
+ /* time */
+ gettimeofday(&tv, NULL);
+ tv_to_btsnoop_ts(&value, &value_hi, &tv);
+ value_hi = l_to_be(value_hi);
+ value = l_to_be(value);
+ write(hci_btsnoop_fd, &value_hi, 4);
+ write(hci_btsnoop_fd, &value, 4);
+ /* data */
+ write(hci_btsnoop_fd, "\x3", 1);
+ write(hci_btsnoop_fd, p, p[2] + 3);
+
+ /* since these display functions are called from different contexts */
+ utils_unlock();
+ }
+}
+
+/*******************************************************************************
+ **
+ ** Function btsnoop_acl_data
+ **
+ ** Description Function to add an ACL data packet in the BTSNOOP file
+ **
+ ** Returns None
+*******************************************************************************/
+void btsnoop_acl_data(uint8_t *p, uint8_t is_rcvd)
+{
+ SNOOPDBG("btsnoop_acl_data: fd = %d", hci_btsnoop_fd);
+ if (hci_btsnoop_fd != -1)
+ {
+ uint32_t value, value_hi;
+ struct timeval tv;
+
+ /* since these display functions are called from different contexts */
+ utils_lock();
+
+ /* store the length in both original and included fields */
+ value = l_to_be((p[3]<<8) + p[2] + 5);
+ write(hci_btsnoop_fd, &value, 4);
+ write(hci_btsnoop_fd, &value, 4);
+ /* flags: data can be sent or received */
+ value = l_to_be(is_rcvd?1:0);
+ write(hci_btsnoop_fd, &value, 4);
+ /* drops: none */
+ value = 0;
+ write(hci_btsnoop_fd, &value, 4);
+ /* time */
+ gettimeofday(&tv, NULL);
+ tv_to_btsnoop_ts(&value, &value_hi, &tv);
+ value_hi = l_to_be(value_hi);
+ value = l_to_be(value);
+ write(hci_btsnoop_fd, &value_hi, 4);
+ write(hci_btsnoop_fd, &value, 4);
+ /* data */
+ write(hci_btsnoop_fd, "\x2", 1);
+ write(hci_btsnoop_fd, p, (p[3]<<8) + p[2] + 4);
+
+ /* since these display functions are called from different contexts */
+ utils_unlock();
+ }
+}
+
+
+/********************************************************************************
+ ** API allow external realtime parsing of output using e.g hcidump
+ *********************************************************************************/
+
+#define EXT_PARSER_PORT 4330
+
+static pthread_t thread_id;
+static int s_listen = -1;
+static int ext_parser_fd = -1;
+
+static void ext_parser_detached(void);
+
+int ext_parser_accept(int port)
+{
+ socklen_t clilen;
+ struct sockaddr_in cliaddr, servaddr;
+ int s, srvlen;
+ int n = 1;
+ int size_n;
+ int result = 0;
+
+ LOGD("waiting for connection on port %d", port);
+
+ s_listen = socket(AF_INET, SOCK_STREAM, 0);
+
+ if (s_listen < 0)
+ {
+ LOGE("listener not created: listen fd %d", s_listen);
+ return -1;
+ }
+
+ bzero(&servaddr, sizeof(servaddr));
+ servaddr.sin_family = AF_INET;
+ servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
+ servaddr.sin_port = htons(port);
+
+ srvlen = sizeof(servaddr);
+
+ /* allow reuse of sock addr upon bind */
+ result = setsockopt(s_listen, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n));
+
+ if (result<0)
+ {
+ perror("setsockopt");
+ }
+
+ result = bind(s_listen, (struct sockaddr *) &servaddr, srvlen);
+
+ if (result < 0)
+ perror("bind");
+
+ result = listen(s_listen, 1);
+
+ if (result < 0)
+ perror("listen");
+
+ clilen = sizeof(struct sockaddr_in);
+
+ s = accept(s_listen, (struct sockaddr *) &cliaddr, &clilen);
+
+ if (s < 0)
+{
+ perror("accept");
+ return -1;
+ }
+
+ LOGD("connected (%d)", s);
+
+ return s;
+}
+
+static int send_ext_parser(char *p, int len)
+{
+ int n;
+
+ /* check if io socket is connected */
+ if (ext_parser_fd == -1)
+ return 0;
+
+ SNOOPDBG("write %d to snoop socket\n", len);
+
+ n = write(ext_parser_fd, p, len);
+
+ if (n<=0)
+ {
+ ext_parser_detached();
+ }
+
+ return n;
+}
+
+static void ext_parser_detached(void)
+{
+ LOGD("ext parser detached");
+
+ if (ext_parser_fd>0)
+ close(ext_parser_fd);
+
+ if (s_listen > 0)
+ close(s_listen);
+
+ ext_parser_fd = -1;
+ s_listen = -1;
+}
+
+static void interruptFn (int sig)
+{
+ LOGD("interruptFn");
+ pthread_exit(0);
+}
+
+static void ext_parser_thread(void* param)
+{
+ int fd;
+ int sig = SIGUSR2;
+ sigset_t sigSet;
+ sigemptyset (&sigSet);
+ sigaddset (&sigSet, sig);
+
+ LOGD("ext_parser_thread");
+
+ prctl(PR_SET_NAME, (unsigned long)"BtsnoopExtParser", 0, 0, 0);
+
+ pthread_sigmask (SIG_UNBLOCK, &sigSet, NULL);
+
+ struct sigaction act;
+ act.sa_handler = interruptFn;
+ sigaction (sig, &act, NULL );
+
+ do
+ {
+ fd = ext_parser_accept(EXT_PARSER_PORT);
+
+ ext_parser_fd = fd;
+
+ LOGD("ext parser attached on fd %d\n", ext_parser_fd);
+ } while (1);
+}
+
+void btsnoop_stop_listener(void)
+{
+ LOGD("btsnoop_init");
+ ext_parser_detached();
+}
+
+void btsnoop_init(void)
+{
+ LOGD("btsnoop_init");
+
+ /* always setup ext listener port */
+ if (pthread_create(&thread_id, NULL,
+ (void*)ext_parser_thread,NULL)!=0)
+ perror("pthread_create");
+}
+
+void btsnoop_open(void)
+{
+ LOGD("btsnoop_open");
+ btsnoop_log_open();
+}
+
+void btsnoop_close(void)
+{
+ LOGD("btsnoop_close");
+ btsnoop_log_close();
+}
+
+void btsnoop_cleanup (void)
+{
+ LOGD("btsnoop_cleanup");
+ pthread_kill(thread_id, SIGUSR2);
+ pthread_join(thread_id, NULL);
+ ext_parser_detached();
+}
+
+
+#define HCIT_TYPE_COMMAND 1
+#define HCIT_TYPE_ACL_DATA 2
+#define HCIT_TYPE_SCO_DATA 3
+#define HCIT_TYPE_EVENT 4
+
+void btsnoop_capture(VND_BT_HDR *p_buf, uint8_t is_rcvd)
+{
+ uint8_t *p = (uint8_t *)(p_buf + 1) + p_buf->offset;
+
+ SNOOPDBG("btsnoop_capture: fd = %d, type %x, rcvd %d, ext %d", hci_btsnoop_fd, p_buf->event, is_rcvd, ext_parser_fd);
+
+ if (ext_parser_fd > 0)
+ {
+ uint8_t tmp = *p;
+
+ /* borrow one byte for H4 packet type indicator */
+ p--;
+
+ switch (p_buf->event & MSG_EVT_MASK)
+ {
+ case MSG_VND_TO_STACK_HCI_EVT:
+ *p = HCIT_TYPE_EVENT;
+ break;
+ case MSG_VND_TO_STACK_HCI_ACL:
+ case MSG_STACK_TO_VND_HCI_ACL:
+ *p = HCIT_TYPE_ACL_DATA;
+ break;
+ case MSG_VND_TO_STACK_HCI_SCO:
+ case MSG_STACK_TO_VND_HCI_SCO:
+ *p = HCIT_TYPE_SCO_DATA;
+ break;
+ case MSG_STACK_TO_VND_HCI_CMD:
+ *p = HCIT_TYPE_COMMAND;
+ break;
+ }
+
+ send_ext_parser((char*)p, p_buf->len+1);
+ *(++p) = tmp;
+ return;
+ }
+
+ if (hci_btsnoop_fd == -1)
+ return;
+
+ switch (p_buf->event & MSG_EVT_MASK)
+ {
+ case MSG_VND_TO_STACK_HCI_EVT:
+ SNOOPDBG("TYPE : EVT");
+ btsnoop_hci_evt(p);
+ break;
+ case MSG_VND_TO_STACK_HCI_ACL:
+ case MSG_STACK_TO_VND_HCI_ACL:
+ SNOOPDBG("TYPE : ACL");
+ btsnoop_acl_data(p, is_rcvd);
+ break;
+ case MSG_VND_TO_STACK_HCI_SCO:
+ case MSG_STACK_TO_VND_HCI_SCO:
+ SNOOPDBG("TYPE : SCO");
+ btsnoop_sco_data(p, is_rcvd);
+ break;
+ case MSG_STACK_TO_VND_HCI_CMD:
+ SNOOPDBG("TYPE : CMD");
+ btsnoop_hci_cmd(p);
+ break;
+ }
+}
+
+
diff --git a/vendor/libvendor/src/hardware.c b/vendor/libvendor/src/hardware.c
new file mode 100644
index 0000000..de2bc1e
--- /dev/null
+++ b/vendor/libvendor/src/hardware.c
@@ -0,0 +1,1012 @@
+/************************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * This program is the proprietary software of Broadcom Corporation and/or its
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
+ *
+ * Except as expressly set forth in the Authorized License,
+ *
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
+ * Broadcom integrated circuit products.
+ *
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT
+ * OF USE OR PERFORMANCE OF THE SOFTWARE.
+ *
+ * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR
+ * ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+ *
+ ************************************************************************************/
+
+/************************************************************************************
+ *
+ * Filename: hardware.c
+ *
+ * Description:
+ *
+ ***********************************************************************************/
+
+#define LOG_TAG "bt_hw"
+
+#include <utils/Log.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <time.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include "bt_vendor_brcm.h"
+#include "userial.h"
+#include "utils.h"
+#include "upio.h"
+
+/************************************************************************************
+** Constants & Macros
+************************************************************************************/
+
+#ifndef BTHW_DBG
+#define BTHW_DBG FALSE
+#endif
+
+#if (BTHW_DBG == TRUE)
+#define BTHWDBG LOGD
+#else
+#define BTHWDBG
+#endif
+
+#define FW_PATCHFILE_EXTENSION ".hcd"
+#define FW_PATCHFILE_EXTENSION_LEN 4
+#define FW_PATCHFILE_PATH_MAXLEN 248 /* Local_Name length of return of HCI_Read_Local_Name */
+
+#define HCI_CMD_MAX_LEN 258
+
+#define HCI_RESET 0x0C03
+#define HCI_VSC_WRITE_UART_CLOCK_SETTING 0xFC45
+#define HCI_VSC_UPDATE_BAUDRATE 0xFC18
+#define HCI_READ_LOCAL_NAME 0x0C14
+#define HCI_VSC_DOWNLOAD_MINIDRV 0xFC2E
+#define HCI_VSC_WRITE_BD_ADDR 0xFC01
+#define HCI_VSC_WRITE_SLEEP_MODE 0xFC27
+#define HCI_VSC_WRITE_SCO_PCM_INT_PARAM 0xFC1C
+#define HCI_VSC_WRITE_PCM_DATA_FORMAT_PARAM 0xFC1E
+#define HCI_VSC_WRITE_I2SPCM_INTERFACE_PARAM 0xFC6D
+
+#define LPM_CMD_PARAMETER_LEN 12
+
+
+/************************************************************************************
+** Local type definitions
+************************************************************************************/
+
+/* Hardware Configuration State */
+enum {
+ HW_CFG_START = 1,
+ HW_CFG_SET_UART_CLOCK,
+ HW_CFG_SET_UART_BAUD_1,
+ HW_CFG_READ_LOCAL_NAME,
+ HW_CFG_DL_MINIDRIVER,
+ HW_CFG_DL_FW_PATCH,
+ HW_CFG_SET_UART_BAUD_2,
+ HW_CFG_SET_BD_ADDR
+};
+
+/* low power mode parameters */
+typedef struct
+{
+ uint8_t sleep_mode; /* Sleep Mode 0(disable),1(UART),9(H5) */
+ uint8_t host_stack_idle_threshold; /* Host Idle Treshold in 300ms/25ms if mode = 1 */
+ uint8_t host_controller_idle_threshold; /* Host Controller Idle Treshold in 300ms/25ms if mode = 1,9 */
+ uint8_t bt_wake_polarity; /* BT_WAKE Polarity - 0=Active Low, 1= Active High if mode = 1 */
+ uint8_t host_wake_polarity; /* HOST_WAKE Polarity - 0=Active Low, 1= Active High if mode = 1 */
+ uint8_t allow_host_sleep_during_sco; /* Allow host Sleep during SCO if mode = 1 */
+ uint8_t combine_sleep_mode_and_lpm; /* Combine Sleep Mode and LPM if mode = 1 */
+ uint8_t enable_uart_txd_tri_state; /* UART_TXD Tri-State if mode = 1 */
+ uint8_t sleep_guard_time; /* sleep guard time in 12.5ms */
+ uint8_t wakeup_guard_time; /* wakeup guard time in 12.5ms */
+ uint8_t txd_config; /* TXD is high in sleep state */
+ uint8_t pulsed_host_wake; /* pulsed host wake if mode = 1 */
+} bt_lpm_param_t;
+
+enum {
+ HW_LPM_DISABLED = 0, /* initial state */
+ HW_LPM_ENABLED,
+ HW_LPM_ENABLING,
+ HW_LPM_DISABLING
+};
+
+enum {
+ LPM_BTWAKE_DEASSERTED = 0, /* initial state */
+ LPM_BTWAKE_W4_TX_DONE,
+ LPM_BTWAKE_W4_TIMEOUT,
+ LPM_BTWAKE_ASSERTED
+};
+
+/* low power mode control block */
+typedef struct
+{
+ uint8_t state; /* DISABLED, ENABLED, ENABLING, DISABLING */
+ uint8_t btwake_state; /* ASSERTED, W4_TX_DONE, W4_TIMEOUT, DEASSERTED */
+ uint8_t no_tx_data;
+ uint8_t timer_created;
+ timer_t timer_id;
+ uint32_t timeout_ms; /* 10 times of the chip unit */
+} bt_lpm_cb_t;
+
+/************************************************************************************
+** Externs
+************************************************************************************/
+
+/* Callback function for the returned event of internal issued command */
+typedef void (*tINT_CMD_CBACK)(VND_BT_HDR *p_buf);
+uint8_t hci_h4_send_int_cmd(uint16_t opcode, VND_BT_HDR *p_buf, tINT_CMD_CBACK p_cback);
+void hci_h4_get_acl_data_length(void);
+
+
+/************************************************************************************
+** Static variables
+************************************************************************************/
+
+static uint8_t hw_cfg_state = 0;
+static int fw_fd = -1;
+static uint8_t f_set_baud_2 = FALSE;
+static uint8_t local_bd_addr[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+static const uint8_t null_bdaddr[6] = {0,0,0,0,0,0};
+static char local_chip_name[32];
+static bt_lpm_cb_t hw_lpm_cb;
+
+static bt_lpm_param_t lpm_param =
+{
+ LPM_SLEEP_MODE,
+ LPM_IDLE_THRESHOLD,
+ LPM_HC_IDLE_THRESHOLD,
+ LPM_BT_WAKE_POLARITY,
+ LPM_HOST_WAKE_POLARITY,
+ LPM_ALLOW_HOST_SLEEP_DURING_SCO,
+ LPM_COMBINE_SLEEP_MODE_AND_LPM,
+ LPM_ENABLE_UART_TXD_TRI_STATE,
+ 0, /* not applicable */
+ 0, /* not applicable */
+ 0, /* not applicable */
+ LPM_PULSED_HOST_WAKE
+};
+
+#if (SCO_USE_I2S_INTERFACE == FALSE)
+static uint8_t bt_sco_param[SCO_PCM_PARAM_SIZE] =
+{
+ SCO_PCM_ROUTING,
+ SCO_PCM_IF_CLOCK_RATE,
+ SCO_PCM_IF_FRAME_TYPE,
+ SCO_PCM_IF_SYNC_MODE,
+ SCO_PCM_IF_CLOCK_MODE
+};
+
+static uint8_t bt_pcm_data_fmt_param[PCM_DATA_FORMAT_PARAM_SIZE] =
+{
+ PCM_DATA_FMT_SHIFT_MODE,
+ PCM_DATA_FMT_FILL_BITS,
+ PCM_DATA_FMT_FILL_METHOD,
+ PCM_DATA_FMT_FILL_NUM,
+ PCM_DATA_FMT_JUSTIFY_MODE
+};
+#else
+static uint8_t bt_sco_param[SCO_I2SPCM_PARAM_SIZE] =
+{
+ SCO_I2SPCM_IF_MODE,
+ SCO_I2SPCM_IF_ROLE,
+ SCO_I2SPCM_IF_SAMPLE_RATE,
+ SCO_I2SPCM_IF_CLOCK_RATE
+};
+#endif
+
+/************************************************************************************
+** Static functions
+************************************************************************************/
+
+/*****************************************************************************
+** Controller Initialization Static Functions
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function hw_config_findpatch
+**
+** Description Search for a proper firmware patch file
+** The selected firmware patch file name with full path
+** will be stored in the input string parameter, i.e.
+** p_chip_id_str, when returns.
+**
+** Returns TRUE when found the target patch file, otherwise FALSE
+**
+*******************************************************************************/
+uint8_t hw_config_findpatch(char *p_chip_id_str)
+{
+ DIR *dirp;
+ struct dirent *dp;
+ int filenamelen;
+ uint8_t retval = FALSE;
+
+ BTHWDBG("Chip-name = [%s]", p_chip_id_str);
+
+ if ((dirp = opendir(FW_PATCHFILE_LOCATION)) != NULL)
+ {
+ /* Fetch next filename in patchfile directory */
+ while ((dp = readdir(dirp)) != NULL)
+ {
+ /* Check if filename starts with chip-id name */
+ if ((strncmp(dp->d_name, p_chip_id_str, strlen(p_chip_id_str))) == 0)
+ {
+ /* Check if it has .hcd extenstion */
+ filenamelen = strlen(dp->d_name);
+ if ((filenamelen >= FW_PATCHFILE_EXTENSION_LEN) &&
+ ((strncmp(&dp->d_name[filenamelen-FW_PATCHFILE_EXTENSION_LEN], FW_PATCHFILE_EXTENSION, FW_PATCHFILE_EXTENSION_LEN)) == 0))
+ {
+ LOGI("Found patchfile: %s/%s", FW_PATCHFILE_LOCATION, dp->d_name);
+
+ /* Make sure length does not exceed maximum */
+ if ((filenamelen + strlen(FW_PATCHFILE_LOCATION)) > FW_PATCHFILE_PATH_MAXLEN)
+ {
+ LOGE("Invalid patchfile name (too long)");
+ }
+ else
+ {
+ memset(p_chip_id_str, 0, FW_PATCHFILE_PATH_MAXLEN);
+ /* Found patchfile. Store location and name */
+ strcpy(p_chip_id_str, FW_PATCHFILE_LOCATION);
+ if (FW_PATCHFILE_LOCATION[strlen(FW_PATCHFILE_LOCATION) - 1] != '/')
+ strcat(p_chip_id_str, "/");
+ strcat(p_chip_id_str, dp->d_name);
+ retval = TRUE;
+ }
+ break;
+ }
+ }
+ }
+ closedir(dirp);
+ }
+ else
+ {
+ LOGE("Could not open %s", FW_PATCHFILE_LOCATION);
+ }
+
+ return (retval);
+}
+
+/*******************************************************************************
+**
+** Function hw_config_cback
+**
+** Description Callback function for controller configuration
+**
+** Returns None
+**
+*******************************************************************************/
+void hw_config_cback(VND_BT_HDR *p_evt_buf)
+{
+ char *p_name;
+ uint8_t *p, status;
+ uint16_t opcode;
+ VND_BT_HDR *p_buf=NULL;
+
+ status = *((uint8_t *)(p_evt_buf + 1) + 5);
+
+ /* Ask a new buffer big enough to hold any HCI commands sent in here */
+ if ((status == 0) && bt_vendor_cbacks)
+ p_buf = (VND_BT_HDR *) bt_vendor_cbacks->alloc(BT_VND_HDR_SIZE+HCI_CMD_MAX_LEN);
+
+ if ((status != 0) || (p_buf == NULL))
+ {
+ if (bt_vendor_cbacks)
+ {
+ bt_vendor_cbacks->dealloc((TRANSAC) p_evt_buf, (char *) (p_evt_buf + 1));
+ LOGE("vendor lib preload aborted [no buffer]");
+ bt_vendor_cbacks->preload_cb(NULL, BT_VENDOR_PRELOAD_FAIL);
+ }
+
+ hw_cfg_state = 0;
+ return;
+ }
+
+ p_buf->event = MSG_STACK_TO_VND_HCI_CMD;
+ p_buf->offset = 0;
+ p_buf->len = 0;
+ p_buf->layer_specific = 0;
+
+ p = (uint8_t *) (p_buf + 1);
+
+ switch (hw_cfg_state)
+ {
+ case HW_CFG_SET_UART_BAUD_1:
+ /* update baud rate of host's UART port */
+ userial_change_baud(USERIAL_BAUD_3M);
+
+ /* read local name */
+ UINT16_TO_STREAM(p, HCI_READ_LOCAL_NAME);
+ *p = 0; /* parameter length */
+
+ p_buf->len = 3;
+ hw_cfg_state = HW_CFG_READ_LOCAL_NAME;
+
+ hci_h4_send_int_cmd(HCI_READ_LOCAL_NAME, p_buf, hw_config_cback);
+ break;
+
+ case HW_CFG_READ_LOCAL_NAME:
+ p_name = (char *) (p_evt_buf + 1) + 6;
+ strncpy(local_chip_name, p_name, 15);
+ local_chip_name[15] = 0;
+ if ((status = hw_config_findpatch(p_name)) == TRUE)
+ {
+ if ((fw_fd = open(p_name, O_RDONLY)) == -1)
+ {
+ LOGE("vendor lib preload aborted [Failed to open %s]", p_name);
+ bt_vendor_cbacks->preload_cb(NULL, BT_VENDOR_PRELOAD_FAIL);
+ hw_cfg_state = 0;
+ }
+ else
+ {
+ /* vsc_download_minidriver */
+ UINT16_TO_STREAM(p, HCI_VSC_DOWNLOAD_MINIDRV);
+ *p = 0; /* parameter length */
+
+ p_buf->len = 3;
+ hw_cfg_state = HW_CFG_DL_MINIDRIVER;
+
+ hci_h4_send_int_cmd(HCI_VSC_DOWNLOAD_MINIDRV, p_buf, hw_config_cback);
+ }
+ }
+ else
+ {
+ LOGE("vendor lib preload aborted [Failed to locate firmware patch file]");
+ bt_vendor_cbacks->preload_cb(NULL, BT_VENDOR_PRELOAD_FAIL);
+ hw_cfg_state = 0;
+ }
+ break;
+
+ case HW_CFG_DL_MINIDRIVER:
+ /* give time for placing firmware in download mode */
+ utils_delay(50);
+ hw_cfg_state = HW_CFG_DL_FW_PATCH;
+ /* fall through intentionally */
+ case HW_CFG_DL_FW_PATCH:
+ p_buf->len = read(fw_fd, p, 3);
+ if (p_buf->len > 0)
+ {
+ p_buf->len += read(fw_fd, p+3, *(p+2));
+ STREAM_TO_UINT16(opcode,p);
+ hci_h4_send_int_cmd(opcode, p_buf, hw_config_cback);
+ break;
+ }
+
+ close(fw_fd);
+ fw_fd = -1;
+
+ /* Normally the firmware patch configuration file
+ * sets the new starting baud rate at 115200.
+ * So, we need update host's baud rate accordingly.
+ */
+ userial_change_baud(USERIAL_BAUD_115200);
+
+ /* Next, we would like to boost baud rate up again
+ * to desired working speed.
+ */
+ f_set_baud_2 = TRUE;
+
+ /* fall through intentionally */
+ case HW_CFG_START:
+ if (UART_TARGET_BAUD_RATE > 3000000)
+ {
+ /* set UART clock to 48MHz */
+ UINT16_TO_STREAM(p, HCI_VSC_WRITE_UART_CLOCK_SETTING);
+ *p++ = 1; /* parameter length */
+ *p = 1; /* (1, "UART CLOCK 48 MHz")(2, "UART CLOCK 24 MHz") */
+
+ p_buf->len = 4;
+ hw_cfg_state = HW_CFG_SET_UART_CLOCK;
+
+ hci_h4_send_int_cmd(HCI_VSC_WRITE_UART_CLOCK_SETTING, p_buf, hw_config_cback);
+ break;
+ }
+ /* fall through intentionally */
+ case HW_CFG_SET_UART_CLOCK:
+ /* set controller's UART baud rate to 3M */
+ UINT16_TO_STREAM(p, HCI_VSC_UPDATE_BAUDRATE);
+ *p++ = 6; /* parameter length */
+ *p++ = 0; /* encoded baud rate */
+ *p++ = 0; /* use encoded form */
+ UINT32_TO_STREAM(p, UART_TARGET_BAUD_RATE);
+
+ p_buf->len = 9;
+ hw_cfg_state = (f_set_baud_2) ? HW_CFG_SET_UART_BAUD_2 : HW_CFG_SET_UART_BAUD_1;
+
+ hci_h4_send_int_cmd(HCI_VSC_UPDATE_BAUDRATE, p_buf, hw_config_cback);
+ break;
+
+ case HW_CFG_SET_UART_BAUD_2:
+ /* update baud rate of host's UART port */
+ userial_change_baud(USERIAL_BAUD_3M);
+
+ /* See if bda addr needs to be programmed */
+ if (memcmp(local_bd_addr, null_bdaddr, 6) != 0)
+ {
+ LOGI("Setting local bd addr to %02X:%02X:%02X:%02X:%02X:%02X",
+ local_bd_addr[0], local_bd_addr[1], local_bd_addr[2],
+ local_bd_addr[3], local_bd_addr[4], local_bd_addr[5]);
+
+ UINT16_TO_STREAM(p, HCI_VSC_WRITE_BD_ADDR);
+ *p++ = 6; /* parameter length */
+ *p++ = local_bd_addr[5];
+ *p++ = local_bd_addr[4];
+ *p++ = local_bd_addr[3];
+ *p++ = local_bd_addr[2];
+ *p++ = local_bd_addr[1];
+ *p = local_bd_addr[0];
+
+ p_buf->len = 9;
+ hw_cfg_state = HW_CFG_SET_BD_ADDR;
+
+ hci_h4_send_int_cmd(HCI_VSC_WRITE_BD_ADDR, p_buf, hw_config_cback);
+ break;
+ }
+ /* fall through intentionally */
+ case HW_CFG_SET_BD_ADDR:
+ if (bt_vendor_cbacks)
+ {
+ bt_vendor_cbacks->dealloc((TRANSAC) p_buf, (char *) (p_buf + 1));
+ LOGI("vendor lib preload completed");
+ bt_vendor_cbacks->preload_cb(NULL, BT_VENDOR_PRELOAD_SUCCESS);
+ }
+
+ hw_cfg_state = 0;
+ break;
+
+ }
+
+ /* Free the RX event buffer */
+ if (bt_vendor_cbacks)
+ bt_vendor_cbacks->dealloc((TRANSAC) p_evt_buf, (char *) (p_evt_buf + 1));
+}
+
+
+/*****************************************************************************
+** LPM Static Functions
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function hw_lpm_idle_timeout
+**
+** Description Timeout thread of transport idle timer
+**
+** Returns None
+**
+*******************************************************************************/
+static void hw_lpm_idle_timeout(union sigval arg)
+{
+ BTHWDBG("..hw_lpm_idle_timeout..");
+
+ if ((hw_lpm_cb.state == HW_LPM_ENABLED) && (hw_lpm_cb.btwake_state == LPM_BTWAKE_W4_TIMEOUT))
+ btvnd_signal_event(VND_EVENT_LPM_IDLE_TIMEOUT);
+}
+
+/*******************************************************************************
+**
+** Function hw_lpm_start_transport_idle_timer
+**
+** Description Launch transport idle timer
+**
+** Returns None
+**
+*******************************************************************************/
+static void hw_lpm_start_transport_idle_timer(void)
+{
+ int status;
+ struct itimerspec ts;
+ struct sigevent se;
+
+ if (hw_lpm_cb.state != HW_LPM_ENABLED)
+ return;
+
+ if (hw_lpm_cb.timer_created == FALSE)
+ {
+ se.sigev_notify = SIGEV_THREAD;
+ se.sigev_value.sival_ptr = &hw_lpm_cb.timer_id;
+ se.sigev_notify_function = hw_lpm_idle_timeout;
+ se.sigev_notify_attributes = NULL;
+
+ /* set idle time to be LPM_IDLE_TIMEOUT_MULTIPLE times of host stack idle threshold (in 300ms/25ms) */
+ hw_lpm_cb.timeout_ms = (uint32_t)lpm_param.host_stack_idle_threshold * LPM_IDLE_TIMEOUT_MULTIPLE;
+
+ if (strstr(local_chip_name, "BCM4325") != NULL)
+ hw_lpm_cb.timeout_ms *= 25; // 12.5 or 25 ?
+ else
+ hw_lpm_cb.timeout_ms *= 300;
+
+ status = timer_create(CLOCK_MONOTONIC, &se, &hw_lpm_cb.timer_id);
+
+ if (status == 0)
+ hw_lpm_cb.timer_created = TRUE;
+ }
+
+ if (hw_lpm_cb.timer_created == TRUE)
+ {
+ ts.it_value.tv_sec = hw_lpm_cb.timeout_ms/1000;
+ ts.it_value.tv_nsec = 1000*(hw_lpm_cb.timeout_ms%1000);
+ ts.it_interval.tv_sec = 0;
+ ts.it_interval.tv_nsec = 0;
+
+ status = timer_settime(hw_lpm_cb.timer_id, 0, &ts, 0);
+ if (status == -1)
+ LOGE("[START] Failed to set LPM idle timeout");
+ }
+}
+
+/*******************************************************************************
+**
+** Function hw_lpm_stop_transport_idle_timer
+**
+** Description Launch transport idle timer
+**
+** Returns None
+**
+*******************************************************************************/
+static void hw_lpm_stop_transport_idle_timer(void)
+{
+ int status;
+ struct itimerspec ts;
+
+ if (hw_lpm_cb.timer_created == TRUE)
+ {
+ ts.it_value.tv_sec = 0;
+ ts.it_value.tv_nsec = 0;
+ ts.it_interval.tv_sec = 0;
+ ts.it_interval.tv_nsec = 0;
+
+ status = timer_settime(hw_lpm_cb.timer_id, 0, &ts, 0);
+ if (status == -1)
+ LOGE("[STOP] Failed to set LPM idle timeout");
+ }
+}
+
+/*******************************************************************************
+**
+** Function hw_lpm_ctrl_cback
+**
+** Description Callback function for lpm enable/disable rquest
+**
+** Returns None
+**
+*******************************************************************************/
+void hw_lpm_ctrl_cback(VND_BT_HDR *p_evt_buf)
+{
+ uint8_t next_state;
+
+ if (*((uint8_t *)(p_evt_buf + 1) + 5) == 0)
+ {
+ /* Status == Success */
+ hw_lpm_cb.state = (hw_lpm_cb.state == HW_LPM_ENABLING) ? HW_LPM_ENABLED : HW_LPM_DISABLED;
+ }
+ else
+ {
+ hw_lpm_cb.state = (hw_lpm_cb.state == HW_LPM_ENABLING) ? HW_LPM_DISABLED : HW_LPM_ENABLED;
+ }
+
+ if (bt_vendor_cbacks)
+ {
+ if (hw_lpm_cb.state == HW_LPM_ENABLED)
+ bt_vendor_cbacks->lpm_cb(BT_VENDOR_LPM_ENABLED);
+ else
+ bt_vendor_cbacks->lpm_cb(BT_VENDOR_LPM_DISABLED);
+ }
+
+ if (hw_lpm_cb.state == HW_LPM_DISABLED)
+ {
+ if (hw_lpm_cb.timer_created == TRUE)
+ {
+ timer_delete(hw_lpm_cb.timer_id);
+ }
+
+ memset(&hw_lpm_cb, 0, sizeof(bt_lpm_cb_t));
+ }
+
+ if (bt_vendor_cbacks)
+ {
+ bt_vendor_cbacks->dealloc((TRANSAC) p_evt_buf, (char *) (p_evt_buf + 1));
+ }
+}
+
+
+#if (SCO_CFG_INCLUDED == TRUE)
+/*****************************************************************************
+** SCO Configuration Static Functions
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function hw_sco_cfg_cback
+**
+** Description Callback function for SCO configuration rquest
+**
+** Returns None
+**
+*******************************************************************************/
+void hw_sco_cfg_cback(VND_BT_HDR *p_evt_buf)
+{
+ uint8_t *p;
+ uint16_t opcode;
+ VND_BT_HDR *p_buf=NULL;
+
+ p = (uint8_t *)(p_evt_buf + 1) + 3;
+ STREAM_TO_UINT16(opcode,p);
+
+ /* Free the RX event buffer */
+ if (bt_vendor_cbacks)
+ bt_vendor_cbacks->dealloc((TRANSAC) p_evt_buf, (char *) (p_evt_buf+1));
+
+#if (SCO_USE_I2S_INTERFACE == FALSE)
+ if (opcode == HCI_VSC_WRITE_SCO_PCM_INT_PARAM)
+ {
+ uint8_t ret = FALSE;
+
+ /* Ask a new buffer to hold WRITE_PCM_DATA_FORMAT_PARAM command */
+ if (bt_vendor_cbacks)
+ p_buf = (VND_BT_HDR *) bt_vendor_cbacks->alloc(BT_VND_HDR_SIZE + \
+ 3 + PCM_DATA_FORMAT_PARAM_SIZE);
+ if (p_buf)
+ {
+ p_buf->event = MSG_STACK_TO_VND_HCI_CMD;
+ p_buf->offset = 0;
+ p_buf->layer_specific = 0;
+ p_buf->len = 3 + PCM_DATA_FORMAT_PARAM_SIZE;
+
+ p = (uint8_t *) (p_buf + 1);
+ UINT16_TO_STREAM(p, HCI_VSC_WRITE_PCM_DATA_FORMAT_PARAM);
+ *p++ = PCM_DATA_FORMAT_PARAM_SIZE;
+ memcpy(p, &bt_pcm_data_fmt_param, PCM_DATA_FORMAT_PARAM_SIZE);
+
+ if ((ret = hci_h4_send_int_cmd(HCI_VSC_WRITE_PCM_DATA_FORMAT_PARAM,\
+ p_buf, hw_sco_cfg_cback)) == FALSE)
+ {
+ bt_vendor_cbacks->dealloc((TRANSAC) p_buf, (char *) (p_buf + 1));
+ }
+ else
+ return;
+ }
+ }
+#endif // !SCO_USE_I2S_INTERFACE
+
+ hci_h4_get_acl_data_length();
+}
+#endif // SCO_CFG_INCLUDED
+
+/*****************************************************************************
+** Hardware Configuration Interface Functions
+*****************************************************************************/
+
+
+/*******************************************************************************
+**
+** Function hw_config_start
+**
+** Description Kick off controller initialization process
+**
+** Returns None
+**
+*******************************************************************************/
+void hw_config_start(void)
+{
+ VND_BT_HDR *p_buf = NULL;
+ uint8_t *p;
+
+ hw_cfg_state = 0;
+ f_set_baud_2 = FALSE;
+ hw_lpm_cb.state = HW_LPM_DISABLED;
+
+ /****************************************
+ * !!! TODO !!!
+ *
+ * === Custom Porting Required ===
+ *
+ * Unique Bluetooth address should be
+ * assigned to local_bd_addr[6] in
+ * production line for each device.
+ ****************************************/
+#if 0
+ local_bd_addr[5] = 0x12;
+ local_bd_addr[4] = 0x20;
+ local_bd_addr[3] = 0x5C;
+ local_bd_addr[2] = 0x0A;
+ local_bd_addr[1] = 0x30;
+ local_bd_addr[0] = 0x43;
+#endif
+
+ /* Start from sending HCI_RESET */
+
+ if (bt_vendor_cbacks)
+ p_buf = (VND_BT_HDR *) bt_vendor_cbacks->alloc(BT_VND_HDR_SIZE+3);
+
+ if (p_buf)
+ {
+ p_buf->event = MSG_STACK_TO_VND_HCI_CMD;
+ p_buf->offset = 0;
+ p_buf->layer_specific = 0;
+ p_buf->len = 3;
+
+ p = (uint8_t *) (p_buf + 1);
+ UINT16_TO_STREAM(p, HCI_RESET);
+ *p = 0; /* parameter length */
+
+ hw_cfg_state = HW_CFG_START;
+
+ hci_h4_send_int_cmd(HCI_RESET, p_buf, hw_config_cback);
+ }
+ else
+ {
+ if (bt_vendor_cbacks)
+ {
+ LOGE("vendor lib preload aborted [no buffer]");
+ bt_vendor_cbacks->preload_cb(NULL, BT_VENDOR_PRELOAD_FAIL);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function hw_lpm_enable
+**
+** Description Enalbe/Disable LPM
+**
+** Returns TRUE/FALSE
+**
+*******************************************************************************/
+uint8_t hw_lpm_enable(uint8_t turn_on)
+{
+ VND_BT_HDR *p_buf = NULL;
+ uint8_t *p;
+ uint8_t ret = FALSE;
+
+ if ((hw_lpm_cb.state != HW_LPM_DISABLED) && (hw_lpm_cb.state != HW_LPM_ENABLED))
+ {
+ LOGW("Still busy on processing prior LPM enable/disable request...");
+ return FALSE;
+ }
+
+ if ((turn_on == TRUE) && (hw_lpm_cb.state == HW_LPM_ENABLED))
+ {
+ LOGI("LPM is already on!!!");
+ if (bt_vendor_cbacks)
+ bt_vendor_cbacks->lpm_cb(BT_VENDOR_LPM_ENABLED);
+ return TRUE;
+ }
+ else if ((turn_on == FALSE) && (hw_lpm_cb.state == HW_LPM_DISABLED))
+ {
+ LOGI("LPM is already off!!!");
+ if (bt_vendor_cbacks)
+ bt_vendor_cbacks->lpm_cb(BT_VENDOR_LPM_DISABLED);
+ return TRUE;
+ }
+
+ if (bt_vendor_cbacks)
+ p_buf = (VND_BT_HDR *) bt_vendor_cbacks->alloc(BT_VND_HDR_SIZE+3+LPM_CMD_PARAMETER_LEN);
+
+ if (p_buf)
+ {
+ p_buf->event = MSG_STACK_TO_VND_HCI_CMD;
+ p_buf->offset = 0;
+ p_buf->layer_specific = 0;
+ p_buf->len = 3+LPM_CMD_PARAMETER_LEN;
+
+ p = (uint8_t *) (p_buf + 1);
+ UINT16_TO_STREAM(p, HCI_VSC_WRITE_SLEEP_MODE);
+ *p++ = LPM_CMD_PARAMETER_LEN; /* parameter length */
+
+ if (turn_on)
+ {
+ memcpy(p, &lpm_param, LPM_CMD_PARAMETER_LEN);
+ hw_lpm_cb.state = HW_LPM_ENABLING;
+ }
+ else
+ {
+ memset(p, 0, LPM_CMD_PARAMETER_LEN);
+ hw_lpm_cb.state = HW_LPM_DISABLING;
+ }
+
+ if ((ret = hci_h4_send_int_cmd(HCI_VSC_WRITE_SLEEP_MODE, p_buf, hw_lpm_ctrl_cback)) == FALSE)
+ {
+ hw_lpm_cb.state = (hw_lpm_cb.state == HW_LPM_ENABLING) ? HW_LPM_DISABLED : HW_LPM_ENABLED;
+
+ if (bt_vendor_cbacks)
+ bt_vendor_cbacks->dealloc((TRANSAC) p_buf, (char *) (p_buf + 1));
+ }
+ }
+
+ return ret;
+}
+
+/*******************************************************************************
+**
+** Function hw_lpm_tx_done
+**
+** Description This function is to inform the lpm module
+** if data is waiting in the Tx Q or not.
+**
+** IsTxDone: TRUE if All data in the Tx Q are gone
+** FALSE if any data is still in the Tx Q.
+** Typicaly this function must be called
+** before USERIAL Write and in the Tx Done routine
+**
+** Returns None
+**
+*******************************************************************************/
+void hw_lpm_tx_done(uint8_t is_tx_done)
+{
+ hw_lpm_cb.no_tx_data = is_tx_done;
+
+ if ((hw_lpm_cb.btwake_state == LPM_BTWAKE_W4_TX_DONE) && (is_tx_done == TRUE))
+ {
+ hw_lpm_cb.btwake_state = LPM_BTWAKE_W4_TIMEOUT;
+ hw_lpm_start_transport_idle_timer();
+ }
+}
+
+/*******************************************************************************
+**
+** Function hw_lpm_assert_bt_wake
+**
+** Description Called to wake up Bluetooth chip.
+** Normally this is called when there is data to be sent
+** over UART.
+**
+** Returns TRUE/FALSE
+**
+*******************************************************************************/
+void hw_lpm_assert_bt_wake(void)
+{
+ if (hw_lpm_cb.state != HW_LPM_DISABLED)
+ {
+ BTHWDBG("LPM assert BT_WAKE");
+ upio_set(UPIO_BT_WAKE, UPIO_ASSERT, lpm_param.bt_wake_polarity);
+
+ hw_lpm_stop_transport_idle_timer();
+
+ hw_lpm_cb.btwake_state = LPM_BTWAKE_ASSERTED;
+ }
+
+ hw_lpm_tx_done(FALSE);
+}
+
+/*******************************************************************************
+**
+** Function hw_lpm_allow_bt_device_sleep
+**
+** Description Start LPM idle timer if allowed
+**
+** Returns None
+**
+*******************************************************************************/
+void hw_lpm_allow_bt_device_sleep(void)
+{
+ if ((hw_lpm_cb.state == HW_LPM_ENABLED) && (hw_lpm_cb.btwake_state == LPM_BTWAKE_ASSERTED))
+ {
+ if(hw_lpm_cb.no_tx_data == TRUE)
+ {
+ hw_lpm_cb.btwake_state = LPM_BTWAKE_W4_TIMEOUT;
+ hw_lpm_start_transport_idle_timer();
+ }
+ else
+ {
+ hw_lpm_cb.btwake_state = LPM_BTWAKE_W4_TX_DONE;
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function hw_lpm_deassert_bt_wake
+**
+** Description Deassert bt_wake if allowed
+**
+** Returns None
+**
+*******************************************************************************/
+void hw_lpm_deassert_bt_wake(void)
+{
+ if ((hw_lpm_cb.state == HW_LPM_ENABLED) && (hw_lpm_cb.no_tx_data == TRUE))
+ {
+ BTHWDBG("LPM deassert BT_WAKE");
+ upio_set(UPIO_BT_WAKE, UPIO_DEASSERT, lpm_param.bt_wake_polarity);
+ hw_lpm_cb.btwake_state = LPM_BTWAKE_DEASSERTED;
+ }
+}
+
+#if (SCO_CFG_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function hw_sco_config
+**
+** Description Configure SCO related hardware settings
+**
+** Returns None
+**
+*******************************************************************************/
+void hw_sco_config(void)
+{
+ VND_BT_HDR *p_buf = NULL;
+ uint8_t *p, ret;
+
+#if (SCO_USE_I2S_INTERFACE == FALSE)
+ uint16_t cmd_u16 = 3 + SCO_PCM_PARAM_SIZE;
+#else
+ uint16_t cmd_u16 = 3 + SCO_I2SPCM_PARAM_SIZE;
+#endif
+
+ if (bt_vendor_cbacks)
+ p_buf = (VND_BT_HDR *) bt_vendor_cbacks->alloc(BT_VND_HDR_SIZE+cmd_u16);
+
+ if (p_buf)
+ {
+ p_buf->event = MSG_STACK_TO_VND_HCI_CMD;
+ p_buf->offset = 0;
+ p_buf->layer_specific = 0;
+ p_buf->len = cmd_u16;
+
+ p = (uint8_t *) (p_buf + 1);
+#if (SCO_USE_I2S_INTERFACE == FALSE)
+ UINT16_TO_STREAM(p, HCI_VSC_WRITE_SCO_PCM_INT_PARAM);
+ *p++ = SCO_PCM_PARAM_SIZE;
+ memcpy(p, &bt_sco_param, SCO_PCM_PARAM_SIZE);
+ cmd_u16 = HCI_VSC_WRITE_SCO_PCM_INT_PARAM;
+ LOGI("SCO PCM configure {%d, %d, %d, %d, %d}",
+ bt_sco_param[0], bt_sco_param[1], bt_sco_param[2], bt_sco_param[3], \
+ bt_sco_param[4]);
+
+#else
+ UINT16_TO_STREAM(p, HCI_VSC_WRITE_I2SPCM_INTERFACE_PARAM);
+ *p++ = SCO_I2SPCM_PARAM_SIZE;
+ memcpy(p, &bt_sco_param, SCO_I2SPCM_PARAM_SIZE);
+ cmd_u16 = HCI_VSC_WRITE_I2SPCM_INTERFACE_PARAM;
+ LOGI("SCO over I2SPCM interface {%d, %d, %d, %d}",
+ bt_sco_param[0], bt_sco_param[1], bt_sco_param[2], bt_sco_param[3]);
+#endif
+
+ if ((ret = hci_h4_send_int_cmd(cmd_u16, p_buf, hw_sco_cfg_cback)) == FALSE)
+ {
+ bt_vendor_cbacks->dealloc((TRANSAC) p_buf, (char *) (p_buf + 1));
+ }
+ else
+ return;
+ }
+
+ if (bt_vendor_cbacks)
+ {
+ LOGE("vendor lib postload aborted");
+ bt_vendor_cbacks->postload_cb(NULL, BT_VENDOR_POSTLOAD_FAIL);
+ }
+}
+#endif // SCO_CFG_INCLUDED
+
diff --git a/vendor/libvendor/src/hci_h4.c b/vendor/libvendor/src/hci_h4.c
new file mode 100644
index 0000000..5436d14
--- /dev/null
+++ b/vendor/libvendor/src/hci_h4.c
@@ -0,0 +1,1047 @@
+/************************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * This program is the proprietary software of Broadcom Corporation and/or its
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
+ *
+ * Except as expressly set forth in the Authorized License,
+ *
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
+ * Broadcom integrated circuit products.
+ *
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT
+ * OF USE OR PERFORMANCE OF THE SOFTWARE.
+ *
+ * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR
+ * ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+ *
+ ************************************************************************************/
+
+/************************************************************************************
+ *
+ * Filename: hci_h4.c
+ *
+ * Description:
+ *
+ ***********************************************************************************/
+
+#define LOG_TAG "bt_h4"
+
+#include <utils/Log.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include "bt_vendor_brcm.h"
+#include "userial.h"
+#include "utils.h"
+
+/************************************************************************************
+** Constants & Macros
+************************************************************************************/
+
+#ifndef HCIH4_DBG
+#define HCIH4_DBG FALSE
+#endif
+
+#if (HCIH4_DBG == TRUE)
+#define HCIH4DBG LOGD
+#else
+#define HCIH4DBG
+#endif
+
+/* Preamble length for HCI Commands:
+** 2-bytes for opcode and 1 byte for length
+*/
+#define HCI_CMD_PREAMBLE_SIZE 3
+
+/* Preamble length for HCI Events:
+** 1-byte for opcode and 1 byte for length
+*/
+#define HCI_EVT_PREAMBLE_SIZE 2
+
+/* Preamble length for SCO Data:
+** 2-byte for Handle and 1 byte for length
+*/
+#define HCI_SCO_PREAMBLE_SIZE 3
+
+/* Preamble length for ACL Data:
+** 2-byte for Handle and 2 byte for length
+*/
+#define HCI_ACL_PREAMBLE_SIZE 4
+
+/* Table of HCI preamble sizes for the different HCI message types */
+static const uint8_t hci_preamble_table[] =
+{
+ HCI_CMD_PREAMBLE_SIZE,
+ HCI_ACL_PREAMBLE_SIZE,
+ HCI_SCO_PREAMBLE_SIZE,
+ HCI_EVT_PREAMBLE_SIZE
+};
+
+/* HCI H4 message type definitions */
+#define H4_TYPE_COMMAND 1
+#define H4_TYPE_ACL_DATA 2
+#define H4_TYPE_SCO_DATA 3
+#define H4_TYPE_EVENT 4
+
+static const uint16_t msg_evt_table[] =
+{
+ MSG_VND_TO_STACK_HCI_ERR, /* H4_TYPE_COMMAND */
+ MSG_VND_TO_STACK_HCI_ACL, /* H4_TYPE_ACL_DATA */
+ MSG_VND_TO_STACK_HCI_SCO, /* H4_TYPE_SCO_DATA */
+ MSG_VND_TO_STACK_HCI_EVT /* H4_TYPE_EVENT */
+};
+
+#define ACL_RX_PKT_START 2
+#define ACL_RX_PKT_CONTINUE 1
+#define L2CAP_HEADER_SIZE 4
+
+/* Maximum numbers of allowed internal
+** outstanding command packets at any time
+*/
+#define INT_CMD_PKT_MAX_COUNT 8
+#define INT_CMD_PKT_IDX_MASK 0x07
+
+#define HCI_COMMAND_COMPLETE_EVT 0x0E
+#define HCI_COMMAND_STATUS_EVT 0x0F
+#define HCI_READ_BUFFER_SIZE 0x1005
+#define HCI_LE_READ_BUFFER_SIZE 0x2002
+
+/************************************************************************************
+** Local type definitions
+************************************************************************************/
+
+/* H4 Rx States */
+typedef enum {
+ H4_RX_MSGTYPE_ST,
+ H4_RX_LEN_ST,
+ H4_RX_DATA_ST,
+ H4_RX_IGNORE_ST
+} tHCI_H4_RCV_STATE;
+
+/* Callback function for the returned event of internal issued command */
+typedef void (*tINT_CMD_CBACK)(VND_BT_HDR *p_buf);
+
+typedef struct
+{
+ uint16_t opcode; /* OPCODE of outstanding internal commands */
+ tINT_CMD_CBACK cback; /* Callback function if return of internal command is received */
+} tINT_CMD_Q;
+
+/* Control block for HCISU_H4 */
+typedef struct
+{
+ VND_BT_HDR *p_rcv_msg; /* Buffer for holding current incoming HCI message */
+ uint16_t rcv_len; /* Size of current incoming message */
+ uint8_t rcv_msg_type; /* Current incoming message type */
+ tHCI_H4_RCV_STATE rcv_state; /* Receive state of current incoming message */
+ uint16_t hc_acl_data_size; /* Host Controller's maximum ACL data length */
+ uint16_t hc_ble_acl_data_size; /* Host Controller's maximum BLE ACL data length */
+ BUFFER_Q acl_rx_q; /* Queue to hold base buffer for fragmented ACL pkts */
+ uint8_t preload_count; /* Count numbers of preload bytes */
+ uint8_t preload_buffer[6]; /* HCI_ACL_PREAMBLE_SIZE + 2 */
+ int int_cmd_rsp_pending; /* Numbers of internal commands pending for response */
+ uint8_t int_cmd_rd_idx; /* Read index of int_cmd_opcode queue */
+ uint8_t int_cmd_wrt_idx; /* Write index of int_cmd_opcode queue */
+ tINT_CMD_Q int_cmd[INT_CMD_PKT_MAX_COUNT]; /* FIFO queue */
+} tHCI_H4_CB;
+
+/************************************************************************************
+** Externs
+************************************************************************************/
+
+extern BUFFER_Q tx_q;
+
+void btsnoop_init(void);
+void btsnoop_open(void);
+void btsnoop_close(void);
+void btsnoop_cleanup (void);
+void btsnoop_capture(VND_BT_HDR *p_buf, uint8_t is_rcvd);
+uint8_t hci_h4_send_int_cmd(uint16_t opcode, VND_BT_HDR *p_buf, tINT_CMD_CBACK p_cback);
+void hw_lpm_assert_bt_wake(void);
+void hw_lpm_tx_done(uint8_t is_tx_done);
+
+/************************************************************************************
+** Variables
+************************************************************************************/
+
+volatile int num_hci_cmd_pkts = 1; /* Num of allowed outstanding HCI CMD packets */
+
+/************************************************************************************
+** Static variables
+************************************************************************************/
+
+static tHCI_H4_CB h4_cb;
+
+/************************************************************************************
+** Static functions
+************************************************************************************/
+
+/*******************************************************************************
+**
+** Function is_snoop_enabled
+**
+** Description Enable bt snoop
+**
+** Returns TRUE(enabled)/FALSE
+**
+*******************************************************************************/
+static uint8_t is_snoop_enabled()
+{
+ char buf[8];
+ int flag = 0;
+ int fd = open(SNOOP_CONFIG_PATH, O_RDONLY, 0644);
+
+ if (fd < 0) {
+ LOGE("file failed to open %s ", SNOOP_CONFIG_PATH);
+ return FALSE;
+ }
+ read(fd, buf, sizeof(buf));
+ flag = atoi(buf);
+ return (flag == 1) ? TRUE : FALSE;
+}
+
+/*******************************************************************************
+**
+** Function get_acl_data_length_cback
+**
+** Description Callback function for HCI_READ_BUFFER_SIZE and
+** HCI_LE_READ_BUFFER_SIZE commands if they were sent because
+** of internal request.
+**
+** Returns None
+**
+*******************************************************************************/
+void get_acl_data_length_cback(VND_BT_HDR *p_buf)
+{
+ uint8_t *p, status;
+ uint16_t opcode, len=0;
+
+ p = (uint8_t *)(p_buf + 1) + 3;
+ STREAM_TO_UINT16(opcode, p)
+ status = *p++;
+ if (status == 0) /* Success */
+ STREAM_TO_UINT16(len, p)
+
+ if (opcode == HCI_READ_BUFFER_SIZE)
+ {
+ if (status == 0)
+ h4_cb.hc_acl_data_size = len;
+
+ /* reuse the rx buffer for sending HCI_LE_READ_BUFFER_SIZE command */
+ p_buf->event = MSG_STACK_TO_VND_HCI_CMD;
+ p_buf->offset = 0;
+ p_buf->layer_specific = 0;
+ p_buf->len = 3;
+
+ p = (uint8_t *) (p_buf + 1);
+ UINT16_TO_STREAM(p, HCI_LE_READ_BUFFER_SIZE);
+ *p = 0;
+
+ if ((status = hci_h4_send_int_cmd(HCI_LE_READ_BUFFER_SIZE, p_buf, get_acl_data_length_cback)) == FALSE)
+ {
+ bt_vendor_cbacks->dealloc((TRANSAC) p_buf, (char *) (p_buf + 1));
+ bt_vendor_cbacks->postload_cb(NULL, BT_VENDOR_POSTLOAD_SUCCESS);
+ }
+ }
+ else if (opcode == HCI_LE_READ_BUFFER_SIZE)
+ {
+ if (status == 0)
+ h4_cb.hc_ble_acl_data_size = (len) ? len : h4_cb.hc_acl_data_size;
+
+ if (bt_vendor_cbacks)
+ {
+ bt_vendor_cbacks->dealloc((TRANSAC) p_buf, (char *) (p_buf + 1));
+ LOGE("vendor lib postload completed");
+ bt_vendor_cbacks->postload_cb(NULL, BT_VENDOR_POSTLOAD_SUCCESS);
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function internal_event_intercept
+**
+** Description This function is called to parse received HCI event and
+** - update the Num_HCI_Command_Packets
+** - intercept the event if it is the result of an early
+** issued internal command.
+**
+** Returns TRUE : if the event had been intercepted for internal process
+** FALSE : send this event to core stack
+**
+*******************************************************************************/
+uint8_t internal_event_intercept(void)
+{
+ uint8_t *p;
+ uint8_t event_code;
+ uint16_t opcode, len;
+ tHCI_H4_CB *p_cb = &h4_cb;
+
+ p = (uint8_t *)(p_cb->p_rcv_msg + 1);
+
+ event_code = *p++;
+ len = *p++;
+
+ if (event_code == HCI_COMMAND_COMPLETE_EVT)
+ {
+ num_hci_cmd_pkts = *p++;
+
+ if (p_cb->int_cmd_rsp_pending > 0)
+ {
+ STREAM_TO_UINT16(opcode, p)
+
+ if (opcode == p_cb->int_cmd[p_cb->int_cmd_rd_idx].opcode)
+ {
+ HCIH4DBG("Intercept CommandCompleteEvent for internal command (0x%04X)", opcode);
+ p_cb->int_cmd[p_cb->int_cmd_rd_idx].cback(p_cb->p_rcv_msg);
+ p_cb->int_cmd_rd_idx = ((p_cb->int_cmd_rd_idx+1) & INT_CMD_PKT_IDX_MASK);
+ p_cb->int_cmd_rsp_pending--;
+ return TRUE;
+ }
+ }
+ }
+ else if (event_code == HCI_COMMAND_STATUS_EVT)
+ {
+ num_hci_cmd_pkts = *(++p);
+ }
+
+ return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function acl_rx_frame_buffer_alloc
+**
+** Description This function is called from the HCI transport when the
+** first 4 or 6 bytes of an HCI ACL packet have been received:
+** - Allocate a new buffer if it is a start pakcet of L2CAP
+** message.
+** - Return the buffer address of the starting L2CAP message
+** frame if the packet is the next segment of a fragmented
+** L2CAP message.
+**
+** Returns the address of the receive buffer H4 RX should use
+** (CR419: Modified to return NULL in case of error.)
+**
+** NOTE This assumes that the L2CAP MTU size is less than the size
+** of an HCI ACL buffer, so the maximum L2CAP message will fit
+** into one buffer.
+**
+*******************************************************************************/
+static VND_BT_HDR *acl_rx_frame_buffer_alloc (void)
+{
+ uint8_t *p;
+ uint16_t handle;
+ uint16_t hci_len;
+ uint16_t total_len;
+ uint8_t pkt_type;
+ VND_BT_HDR *p_return_buf = NULL;
+ tHCI_H4_CB *p_cb = &h4_cb;
+
+
+ p = p_cb->preload_buffer;
+
+ STREAM_TO_UINT16 (handle, p);
+ STREAM_TO_UINT16 (hci_len, p);
+ STREAM_TO_UINT16 (total_len, p);
+
+ pkt_type = (uint8_t)(((handle) >> 12) & 0x0003);
+ handle = (uint16_t)((handle) & 0x0FFF);
+
+ if (p_cb->acl_rx_q.count)
+ {
+ uint16_t save_handle;
+ VND_BT_HDR *p_hdr = p_cb->acl_rx_q.p_first;
+
+ while (p_hdr != NULL)
+ {
+ p = (uint8_t *)(p_hdr + 1);
+ STREAM_TO_UINT16 (save_handle, p);
+ save_handle = (uint16_t)((save_handle) & 0x0FFF);
+ if (save_handle == handle)
+ {
+ p_return_buf = p_hdr;
+ break;
+ }
+ p_hdr = utils_getnext(p_hdr);
+ }
+ }
+
+ if (pkt_type == ACL_RX_PKT_START) /*** START PACKET ***/
+ {
+ /* Might have read 2 bytes for the L2CAP payload length */
+ p_cb->rcv_len = (hci_len) ? (hci_len - 2) : 0;
+
+ /* Start of packet. If we were in the middle of receiving */
+ /* a packet on the same ACL handle, the original packet is incomplete. Drop it. */
+ if (p_return_buf)
+ {
+ LOGW("H4 - dropping incomplete ACL frame");
+
+ utils_remove_from_queue(&(p_cb->acl_rx_q), p_return_buf);
+
+ if (bt_vendor_cbacks)
+ bt_vendor_cbacks->dealloc((TRANSAC) p_return_buf, (char *) (p_return_buf + 1));
+
+ p_return_buf = NULL;
+ }
+
+ /* Allocate a buffer for message */
+ if (bt_vendor_cbacks)
+ {
+ int len = total_len + HCI_ACL_PREAMBLE_SIZE + L2CAP_HEADER_SIZE + BT_VND_HDR_SIZE;
+ p_return_buf = (VND_BT_HDR *) bt_vendor_cbacks->alloc(len);
+ }
+
+ if (p_return_buf)
+ {
+ /* Initialize buffer with preloaded data */
+ p_return_buf->offset = 0;
+ p_return_buf->layer_specific = 0;
+ p_return_buf->event = MSG_VND_TO_STACK_HCI_ACL;
+ p_return_buf->len = p_cb->preload_count;
+ memcpy((uint8_t *)(p_return_buf + 1), p_cb->preload_buffer, p_cb->preload_count);
+
+ if (hci_len && ((total_len + L2CAP_HEADER_SIZE) > hci_len))
+ {
+ /* Will expect to see fragmented ACL packets */
+ /* Keep the base buffer address in the watching queue */
+ utils_enqueue(&(p_cb->acl_rx_q), p_return_buf);
+ }
+ }
+ }
+ else /*** CONTINUATION PACKET ***/
+ {
+ p_cb->rcv_len = hci_len;
+
+ if (p_return_buf)
+ {
+ /* Packet continuation and found the original rx buffer */
+ uint8_t *p_f = p = (uint8_t *)(p_return_buf + 1) + 2;
+
+ STREAM_TO_UINT16 (total_len, p);
+
+ /* Update HCI header of first segment (base buffer) with new length */
+ total_len += hci_len;
+ UINT16_TO_STREAM (p_f, total_len);
+ }
+ }
+
+ return (p_return_buf);
+}
+
+/*******************************************************************************
+**
+** Function acl_rx_frame_end_chk
+**
+** Description This function is called from the HCI transport when the last
+** byte of an HCI ACL packet has been received. It checks if the
+** L2CAP message is complete, i.e. no more continuation packets
+** are expected.
+**
+** Returns TRUE if message complete, FALSE if continuation expected
+**
+*******************************************************************************/
+static uint8_t acl_rx_frame_end_chk (void)
+{
+ uint8_t *p;
+ uint16_t handle, hci_len, l2cap_len;
+ VND_BT_HDR *p_buf;
+ tHCI_H4_CB *p_cb = &h4_cb;
+ uint8_t frame_end=TRUE;
+
+ p_buf = p_cb->p_rcv_msg;
+ p = (uint8_t *)(p_buf + 1);
+
+ STREAM_TO_UINT16 (handle, p);
+ STREAM_TO_UINT16 (hci_len, p);
+ STREAM_TO_UINT16 (l2cap_len, p);
+
+ if (hci_len > 0)
+ {
+ if (l2cap_len > (p_buf->len - (HCI_ACL_PREAMBLE_SIZE + L2CAP_HEADER_SIZE)))
+ {
+ /* If the L2CAP length has not been reached, tell H4 not to send this buffer to stack */
+ frame_end = FALSE;
+ }
+ else
+ {
+ /*
+ * The current buffer coulb be in the watching list.
+ * Remove it from the list if it is in.
+ */
+ if (p_cb->acl_rx_q.count)
+ utils_remove_from_queue(&(p_cb->acl_rx_q), p_buf);
+ }
+ }
+
+ /****
+ ** Print snoop trace
+ ****/
+ if (p_buf->offset)
+ {
+ /* CONTINUATION PACKET */
+
+ /* save original p_buf->len content */
+ uint16_t tmp_u16 = p_buf->len;
+
+ /* borrow HCI_ACL_PREAMBLE_SIZE bytes from the payload section */
+ p = (uint8_t *)(p_buf + 1) + p_buf->offset - HCI_ACL_PREAMBLE_SIZE;
+
+ /* save contents */
+ memcpy(p_cb->preload_buffer, p, HCI_ACL_PREAMBLE_SIZE);
+
+ /* Set packet boundary flags to "continuation packet" */
+ handle = (handle & 0xCFFF) | 0x1000;
+
+ /* write handl & length info */
+ UINT16_TO_STREAM (p, handle);
+ UINT16_TO_STREAM (p, (p_buf->len - p_buf->offset));
+
+ /* roll pointer back */
+ p = p - HCI_ACL_PREAMBLE_SIZE;
+
+ /* adjust `p_buf->offset` & `p_buf->len` before calling btsnoop_capture() */
+ p_buf->offset = p_buf->offset - HCI_ACL_PREAMBLE_SIZE;
+ p_buf->len = p_buf->len - p_buf->offset;
+
+ btsnoop_capture(p_buf, TRUE);
+
+ /* restore contents */
+ memcpy(p, p_cb->preload_buffer, HCI_ACL_PREAMBLE_SIZE);
+
+ /* restore p_buf->len */
+ p_buf->len = tmp_u16;
+ }
+ else
+ {
+ /* START PACKET */
+ btsnoop_capture(p_buf, TRUE);
+ }
+
+ if (frame_end == TRUE)
+ p_buf->offset = 0;
+ else
+ p_buf->offset = p_buf->len; /* save current buffer-end position */
+
+ return frame_end;
+}
+
+/*****************************************************************************
+** HCI H4 INTERFACE FUNCTIONS
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function hci_h4_init
+**
+** Description Initialize H4 module
+**
+** Returns None
+**
+*******************************************************************************/
+void hci_h4_init(void)
+{
+ HCIH4DBG("hci_h4_init");
+
+ memset(&h4_cb, 0, sizeof(tHCI_H4_CB));
+ utils_queue_init(&(h4_cb.acl_rx_q));
+
+ /* Per HCI spec., always starts with 1 */
+ num_hci_cmd_pkts = 1;
+
+ /* Give an initial values of Host Controller's ACL data packet length
+ * Will update with an internal HCI(_LE)_Read_Buffer_Size request
+ */
+ h4_cb.hc_acl_data_size = 1021;
+ h4_cb.hc_ble_acl_data_size = 27;
+
+ btsnoop_init();
+ if (is_snoop_enabled() == TRUE)
+ {
+ btsnoop_open();
+ }
+}
+
+/*******************************************************************************
+**
+** Function hci_h4_cleanup
+**
+** Description Clean H4 module
+**
+** Returns None
+**
+*******************************************************************************/
+void hci_h4_cleanup(void)
+{
+ HCIH4DBG("hci_h4_cleanup");
+
+ btsnoop_close();
+ btsnoop_cleanup();
+}
+
+/*******************************************************************************
+**
+** Function hci_h4_send_msg
+**
+** Description Determine message type, set HCI H4 packet indicator, and
+** send message through USERIAL driver
+**
+** Returns None
+**
+*******************************************************************************/
+void hci_h4_send_msg(VND_BT_HDR *p_msg)
+{
+ uint8_t type = 0;
+ uint16_t handle;
+ uint16_t bytes_to_send, lay_spec;
+ uint8_t *p = ((uint8_t *)(p_msg + 1)) + p_msg->offset;
+ uint16_t event = p_msg->event & MSG_EVT_MASK;
+ uint16_t sub_event = p_msg->event & MSG_SUB_EVT_MASK;
+ uint16_t acl_pkt_size = 0, acl_data_size = 0;
+ uint16_t bytes_sent;
+
+ /* wake up BT device if its in sleep mode */
+ hw_lpm_assert_bt_wake();
+
+ if (event == MSG_STACK_TO_VND_HCI_ACL)
+ type = H4_TYPE_ACL_DATA;
+ else if (event == MSG_STACK_TO_VND_HCI_SCO)
+ type = H4_TYPE_SCO_DATA;
+ else if (event == MSG_STACK_TO_VND_HCI_CMD)
+ type = H4_TYPE_COMMAND;
+
+ if (sub_event == LOCAL_BR_EDR_CONTROLLER_ID)
+ {
+ acl_data_size = h4_cb.hc_acl_data_size;
+ acl_pkt_size = h4_cb.hc_acl_data_size + HCI_ACL_PREAMBLE_SIZE;
+ }
+ else
+ {
+ acl_data_size = h4_cb.hc_ble_acl_data_size;
+ acl_pkt_size = h4_cb.hc_ble_acl_data_size + HCI_ACL_PREAMBLE_SIZE;
+ }
+
+ /* Check if sending ACL data that needs fragmenting */
+ if ((event == MSG_STACK_TO_VND_HCI_ACL) && (p_msg->len > acl_pkt_size))
+ {
+ /* Get the handle from the packet */
+ STREAM_TO_UINT16 (handle, p);
+
+ /* Set packet boundary flags to "continuation packet" */
+ handle = (handle & 0xCFFF) | 0x1000;
+
+ /* Do all the first chunks */
+ while (p_msg->len > acl_pkt_size)
+ {
+ /* remember layer_specific because uart borrow
+ one byte from layer_specific for packet type */
+ lay_spec = p_msg->layer_specific;
+
+ p = ((uint8_t *)(p_msg + 1)) + p_msg->offset - 1;
+ *p = type;
+ bytes_to_send = acl_pkt_size + 1; /* packet_size + message type */
+
+ bytes_sent = userial_write((uint8_t *) p, bytes_to_send);
+
+ /* generate snoop trace message */
+ btsnoop_capture(p_msg, FALSE);
+
+ p_msg->layer_specific = lay_spec;
+ /* Adjust offset and length for what we just sent */
+ p_msg->offset += acl_data_size;
+ p_msg->len -= acl_data_size;
+
+ p = ((uint8_t *)(p_msg + 1)) + p_msg->offset;
+
+ UINT16_TO_STREAM (p, handle);
+
+ if (p_msg->len > acl_pkt_size)
+ {
+ UINT16_TO_STREAM (p, acl_data_size);
+ }
+ else
+ {
+ UINT16_TO_STREAM (p, p_msg->len - HCI_ACL_PREAMBLE_SIZE);
+ }
+
+ /* If we were only to send partial buffer, stop when done. */
+ /* Send the buffer back to L2CAP to send the rest of it later */
+ if (p_msg->layer_specific)
+ {
+ if (--p_msg->layer_specific == 0)
+ {
+ p_msg->event = MSG_VND_TO_STACK_L2C_SEG_XMIT;
+
+ if (bt_vendor_cbacks)
+ bt_vendor_cbacks->tx_result((TRANSAC) p_msg, (char *) (p_msg + 1), BT_VENDOR_TX_FRAGMENT);
+
+ return;
+ }
+ }
+ }
+ }
+
+
+ /* remember layer_specific because uart borrow
+ one byte from layer_specific for packet type */
+ lay_spec = p_msg->layer_specific;
+
+ /* Put the HCI Transport packet type 1 byte before the message */
+ p = ((uint8_t *)(p_msg + 1)) + p_msg->offset - 1;
+ *p = type;
+ bytes_to_send = p_msg->len + 1; /* message_size + message type */
+
+ bytes_sent = userial_write((uint8_t *) p, bytes_to_send);
+
+ p_msg->layer_specific = lay_spec;
+
+ if (event == MSG_STACK_TO_VND_HCI_CMD)
+ {
+ num_hci_cmd_pkts--;
+
+ /* If this is an internal Cmd packet, the layer_specific field would
+ * have stored with the opcode of HCI command.
+ * Retrieve the opcode from the Cmd packet.
+ */
+ p++;
+ STREAM_TO_UINT16(lay_spec, p);
+ }
+
+ /* generate snoop trace message */
+ btsnoop_capture(p_msg, FALSE);
+
+ if (bt_vendor_cbacks)
+ {
+ if ((event == MSG_STACK_TO_VND_HCI_CMD) && (h4_cb.int_cmd_rsp_pending > 0) && (p_msg->layer_specific == lay_spec))
+ {
+ bt_vendor_cbacks->dealloc((TRANSAC) p_msg, (char *) (p_msg + 1)); /* dealloc buffer of internal command */
+ }
+ else
+ {
+ bt_vendor_cbacks->tx_result((TRANSAC) p_msg, (char *) (p_msg + 1), BT_VENDOR_TX_SUCCESS);
+ }
+ }
+
+ hw_lpm_tx_done(TRUE);
+
+ return;
+}
+
+
+/*******************************************************************************
+**
+** Function hci_h4_receive_msg
+**
+** Description
+**
+** Returns
+**
+*******************************************************************************/
+uint16_t hci_h4_receive_msg(void)
+{
+ uint16_t bytes_read = 0;
+ uint8_t byte;
+ uint16_t msg_len, len;
+ uint8_t msg_received;
+ tHCI_H4_CB *p_cb=&h4_cb;
+
+ while (TRUE)
+ {
+ /* Read one byte to see if there is anything waiting to be read */
+ if (userial_read(&byte, 1) == 0)
+ {
+ break;
+ }
+
+ bytes_read++;
+ msg_received = FALSE;
+
+ switch (p_cb->rcv_state)
+ {
+ case H4_RX_MSGTYPE_ST:
+ /* Start of new message */
+ if ((byte < H4_TYPE_ACL_DATA) || (byte > H4_TYPE_EVENT))
+ {
+ /* Unknown HCI message type */
+ /* Drop this byte */
+ LOGE( "[h4] Unknown HCI message type drop this byte 0x%x", byte);
+ break;
+ }
+
+ /* Initialize rx parameters */
+ p_cb->rcv_msg_type = byte;
+ p_cb->rcv_len = hci_preamble_table[byte-1];
+ memset(p_cb->preload_buffer, 0 , 6);
+ p_cb->preload_count = 0;
+ // p_cb->p_rcv_msg = NULL;
+ p_cb->rcv_state = H4_RX_LEN_ST; /* Next, wait for length to come in */
+ break;
+
+ case H4_RX_LEN_ST:
+ /* Receiving preamble */
+ p_cb->preload_buffer[p_cb->preload_count++] = byte;
+ p_cb->rcv_len--;
+
+ /* Check if we received entire preamble yet */
+ if (p_cb->rcv_len == 0)
+ {
+ if (p_cb->rcv_msg_type == H4_TYPE_ACL_DATA)
+ {
+ /* ACL data lengths are 16-bits */
+ msg_len = p_cb->preload_buffer[3];
+ msg_len = (msg_len << 8) + p_cb->preload_buffer[2];
+
+ if (msg_len && (p_cb->preload_count == 4))
+ {
+ /* Check if this is a start packet */
+ byte = ((p_cb->preload_buffer[1] >> 4) & 0x03);
+
+ if (byte == ACL_RX_PKT_START)
+ {
+ /*
+ * A start packet & with non-zero data payload length.
+ * We want to read 2 more bytes to get L2CAP payload length
+ */
+ p_cb->rcv_len = 2;
+
+ break;
+ }
+ }
+
+ /* Check for segmented packets. If this is a continuation packet, then */
+ /* we will continue appending data to the original rcv buffer. */
+ p_cb->p_rcv_msg = acl_rx_frame_buffer_alloc();
+ }
+ else
+ {
+ /* Received entire preamble. Length is in the last received byte */
+ msg_len = byte;
+ p_cb->rcv_len = msg_len;
+
+ /* Allocate a buffer for message */
+ if (bt_vendor_cbacks)
+ {
+ len = msg_len + p_cb->preload_count + BT_VND_HDR_SIZE;
+ p_cb->p_rcv_msg = (VND_BT_HDR *) bt_vendor_cbacks->alloc(len);
+ }
+
+ if (p_cb->p_rcv_msg)
+ {
+ /* Initialize buffer with preloaded data */
+ p_cb->p_rcv_msg->offset = 0;
+ p_cb->p_rcv_msg->layer_specific = 0;
+ p_cb->p_rcv_msg->event = msg_evt_table[p_cb->rcv_msg_type-1];
+ p_cb->p_rcv_msg->len = p_cb->preload_count;
+ memcpy((uint8_t *)(p_cb->p_rcv_msg + 1), p_cb->preload_buffer, p_cb->preload_count);
+ }
+ }
+
+ if (p_cb->p_rcv_msg == NULL)
+ {
+ /* Unable to acquire message buffer. */
+ LOGE("H4: Unable to acquire buffer for incoming HCI message.");
+
+ if (msg_len == 0)
+ {
+ p_cb->rcv_state = H4_RX_MSGTYPE_ST; /* Wait for next message */
+ }
+ else
+ {
+ p_cb->rcv_state = H4_RX_IGNORE_ST; /* Ignore rest of the packet */
+ }
+
+ break;
+ }
+
+ /* Message length is valid */
+ if (msg_len)
+ {
+ /* Read rest of message */
+ p_cb->rcv_state = H4_RX_DATA_ST;
+ }
+ else
+ {
+ /* Message has no additional parameters. (Entire message has been received) */
+ if (p_cb->rcv_msg_type == H4_TYPE_ACL_DATA)
+ acl_rx_frame_end_chk(); /* to print snoop trace */
+
+ msg_received = TRUE;
+ p_cb->rcv_state = H4_RX_MSGTYPE_ST; /* Next, wait for next message */
+ }
+ }
+ break;
+
+ case H4_RX_DATA_ST:
+ *((uint8_t *)(p_cb->p_rcv_msg + 1) + p_cb->p_rcv_msg->len++) = byte;
+ p_cb->rcv_len--;
+
+ if (p_cb->rcv_len > 0)
+ {
+ /* Read in the rest of the message */
+ len = userial_read(((uint8_t *)(p_cb->p_rcv_msg + 1) + p_cb->p_rcv_msg->len), p_cb->rcv_len);
+ p_cb->p_rcv_msg->len += len;
+ p_cb->rcv_len -= len;
+ bytes_read += len;
+ }
+
+ /* Check if we read in entire message yet */
+ if (p_cb->rcv_len == 0)
+ {
+ /* Received entire packet. */
+ /* Check for segmented l2cap packets */
+ if ((p_cb->rcv_msg_type == H4_TYPE_ACL_DATA) &&
+ !acl_rx_frame_end_chk())
+ {
+ /* Not the end of packet yet. */
+ p_cb->rcv_state = H4_RX_MSGTYPE_ST; /* Next, wait for next message */
+ }
+ else
+ {
+ msg_received = TRUE;
+ p_cb->rcv_state = H4_RX_MSGTYPE_ST; /* Next, wait for next message */
+ }
+ }
+ break;
+
+
+ case H4_RX_IGNORE_ST:
+ /* Ignore reset of packet */
+ p_cb->rcv_len--;
+
+ /* Check if we read in entire message yet */
+ if (p_cb->rcv_len == 0)
+ {
+ p_cb->rcv_state = H4_RX_MSGTYPE_ST; /* Next, wait for next message */
+ }
+ break;
+ }
+
+
+ /* If we received entire message, then send it to the task */
+ if (msg_received)
+ {
+ uint8_t intercepted = FALSE;
+
+ /* generate snoop trace message */
+ if (p_cb->p_rcv_msg->event != MSG_VND_TO_STACK_HCI_ACL) /* had done in acl_rx_frame_end_chk() */
+ btsnoop_capture(p_cb->p_rcv_msg, TRUE);
+
+ if (p_cb->p_rcv_msg->event == MSG_VND_TO_STACK_HCI_EVT)
+ intercepted = internal_event_intercept();
+
+ if ((bt_vendor_cbacks) && (intercepted == FALSE))
+ {
+ bt_vendor_cbacks->data_ind((TRANSAC) p_cb->p_rcv_msg, (char *) (p_cb->p_rcv_msg + 1), p_cb->p_rcv_msg->len + BT_VND_HDR_SIZE);
+ }
+ p_cb->p_rcv_msg = NULL;
+ }
+ }
+
+ return (bytes_read);
+}
+
+
+/*******************************************************************************
+**
+** Function hci_h4_send_int_cmd
+**
+** Description
+**
+** Returns TRUE/FALSE
+**
+*******************************************************************************/
+uint8_t hci_h4_send_int_cmd(uint16_t opcode, VND_BT_HDR *p_buf, tINT_CMD_CBACK p_cback)
+{
+ if (h4_cb.int_cmd_rsp_pending > INT_CMD_PKT_MAX_COUNT)
+ {
+ LOGE("Currently we only allow %d outstanding internal command at a time [Reject 0x%04X]", INT_CMD_PKT_MAX_COUNT, opcode);
+ return FALSE;
+ }
+
+ h4_cb.int_cmd_rsp_pending++;
+ h4_cb.int_cmd[h4_cb.int_cmd_wrt_idx].opcode = opcode;
+ h4_cb.int_cmd[h4_cb.int_cmd_wrt_idx].cback = p_cback;
+ h4_cb.int_cmd_wrt_idx = ((h4_cb.int_cmd_wrt_idx + 1) & INT_CMD_PKT_IDX_MASK);
+
+ p_buf->layer_specific = opcode; /* signature to indicate an internal command */
+
+ utils_enqueue(&tx_q, (void *) p_buf);
+ btvnd_signal_event(VND_EVENT_TX);
+
+ return TRUE;
+}
+
+
+/*******************************************************************************
+**
+** Function hci_h4_get_acl_data_length
+**
+** Description
+**
+** Returns None
+**
+*******************************************************************************/
+void hci_h4_get_acl_data_length(void)
+{
+ VND_BT_HDR *p_buf = NULL;
+ uint8_t *p, ret;
+
+ if (bt_vendor_cbacks)
+ p_buf = (VND_BT_HDR *) bt_vendor_cbacks->alloc(BT_VND_HDR_SIZE+3);
+
+ if (p_buf)
+ {
+ p_buf->event = MSG_STACK_TO_VND_HCI_CMD;
+ p_buf->offset = 0;
+ p_buf->layer_specific = 0;
+ p_buf->len = 3;
+
+ p = (uint8_t *) (p_buf + 1);
+ UINT16_TO_STREAM(p, HCI_READ_BUFFER_SIZE);
+ *p = 0;
+
+ if ((ret = hci_h4_send_int_cmd(HCI_READ_BUFFER_SIZE, p_buf, get_acl_data_length_cback)) == FALSE)
+ {
+ bt_vendor_cbacks->dealloc((TRANSAC) p_buf, (char *) (p_buf + 1));
+ }
+ else
+ return;
+ }
+
+ if (bt_vendor_cbacks)
+ {
+ LOGE("vendor lib postload aborted");
+ bt_vendor_cbacks->postload_cb(NULL, BT_VENDOR_POSTLOAD_FAIL);
+ }
+}
+
diff --git a/vendor/libvendor/src/upio.c b/vendor/libvendor/src/upio.c
new file mode 100644
index 0000000..c8c51dc
--- /dev/null
+++ b/vendor/libvendor/src/upio.c
@@ -0,0 +1,322 @@
+/************************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * This program is the proprietary software of Broadcom Corporation and/or its
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
+ *
+ * Except as expressly set forth in the Authorized License,
+ *
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
+ * Broadcom integrated circuit products.
+ *
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT
+ * OF USE OR PERFORMANCE OF THE SOFTWARE.
+ *
+ * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR
+ * ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+ *
+ ************************************************************************************/
+
+/************************************************************************************
+ *
+ * Filename: upio.c
+ *
+ * Description:
+ *
+ ***********************************************************************************/
+
+#define LOG_TAG "bt_upio"
+
+#include <utils/Log.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <cutils/properties.h>
+#include "bt_vendor_brcm.h"
+#include "upio.h"
+#include "userial.h"
+
+/************************************************************************************
+** Constants & Macros
+************************************************************************************/
+
+#ifndef UPIO_DBG
+#define UPIO_DBG FALSE
+#endif
+
+#if (UPIO_DBG == TRUE)
+#define UPIODBG LOGD
+#else
+#define UPIODBG LOGV
+#endif
+
+/************************************************************************************
+** Local type definitions
+************************************************************************************/
+
+/************************************************************************************
+** Static variables
+************************************************************************************/
+
+static uint8_t upio_state[UPIO_MAX_COUNT];
+static int rfkill_id = -1;
+static int bt_emul_enable = 0;
+static char *rfkill_state_path = NULL;
+
+/************************************************************************************
+** Static functions
+************************************************************************************/
+
+/* for friendly debugging outpout string */
+static char *lpm_state[] = {
+ "UNKNOWN",
+ "de-asserted",
+ "asserted"
+};
+
+/*****************************************************************************
+** Bluetooth On/Off Static Functions
+*****************************************************************************/
+static int is_emulator_context(void)
+{
+ char value[PROPERTY_VALUE_MAX];
+
+ property_get("ro.kernel.qemu", value, "0");
+ UPIODBG("is_emulator_context : %s", value);
+ if (strcmp(value, "1") == 0) {
+ return 1;
+ }
+ return 0;
+}
+
+static int is_rfkill_disabled(void)
+{
+ char value[PROPERTY_VALUE_MAX];
+
+ property_get("ro.rfkilldisabled", value, "0");
+ UPIODBG("is_rfkill_disabled ? [%s]", value);
+
+ if (strcmp(value, "1") == 0) {
+ return UPIO_BT_POWER_ON;
+ }
+
+ return UPIO_BT_POWER_OFF;
+}
+
+static int init_rfkill()
+{
+ char path[64];
+ char buf[16];
+ int fd, sz, id;
+
+ if (is_rfkill_disabled())
+ return -1;
+
+ for (id = 0; ; id++)
+ {
+ snprintf(path, sizeof(path), "/sys/class/rfkill/rfkill%d/type", id);
+ fd = open(path, O_RDONLY);
+ if (fd < 0)
+ {
+ LOGE("init_rfkill : open(%s) failed: %s (%d)\n", path, strerror(errno), errno);
+ return -1;
+ }
+
+ sz = read(fd, &buf, sizeof(buf));
+ close(fd);
+
+ if (sz >= 9 && memcmp(buf, "bluetooth", 9) == 0)
+ {
+ rfkill_id = id;
+ break;
+ }
+ }
+
+ asprintf(&rfkill_state_path, "/sys/class/rfkill/rfkill%d/state", rfkill_id);
+ return 0;
+}
+
+/*****************************************************************************
+** LPM Static Functions
+*****************************************************************************/
+
+/*****************************************************************************
+** UPIO Interface Functions
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function upio_init
+**
+** Description Initialization
+**
+** Returns None
+**
+*******************************************************************************/
+void upio_init(void)
+{
+ memset(upio_state, UPIO_UNKNOWN, UPIO_MAX_COUNT);
+}
+
+/*******************************************************************************
+**
+** Function upio_cleanup
+**
+** Description Clean up
+**
+** Returns None
+**
+*******************************************************************************/
+void upio_cleanup(void)
+{
+}
+
+/*******************************************************************************
+**
+** Function upio_set_bluetooth_power
+**
+** Description Interact with low layer driver to set Bluetooth power
+** on/off.
+**
+** Returns 0 : SUCCESS or Not-Applicable
+** <0 : ERROR
+**
+*******************************************************************************/
+int upio_set_bluetooth_power(int on)
+{
+ int sz;
+ int fd = -1;
+ int ret = -1;
+ char buffer = '0';
+
+ switch(on)
+ {
+ case UPIO_BT_POWER_OFF:
+ buffer = '0';
+ break;
+
+ case UPIO_BT_POWER_ON:
+ buffer = '1';
+ break;
+ }
+
+ if (is_emulator_context())
+ {
+ /* if new value is same as current, return -1 */
+ if (bt_emul_enable == on)
+ return ret;
+
+ UPIODBG("set_bluetooth_power [emul] %d", on);
+
+ bt_emul_enable = on;
+ return 0;
+ }
+
+ /* check if we have rfkill interface */
+ if (is_rfkill_disabled())
+ return 0;
+
+ if (rfkill_id == -1)
+ {
+ if (init_rfkill())
+ return ret;
+ }
+
+ fd = open(rfkill_state_path, O_WRONLY);
+
+ if (fd < 0)
+ {
+ LOGE("set_bluetooth_power : open(%s) for write failed: %s (%d)",
+ rfkill_state_path, strerror(errno), errno);
+ return ret;
+ }
+
+ sz = write(fd, &buffer, 1);
+
+ if (sz < 0) {
+ LOGE("set_bluetooth_power : write(%s) failed: %s (%d)",
+ rfkill_state_path, strerror(errno),errno);
+ }
+ else
+ ret = 0;
+
+ if (fd >= 0)
+ close(fd);
+
+ return ret;
+}
+
+
+/*******************************************************************************
+**
+** Function upio_set
+**
+** Description Set i/o based on polarity
+**
+** Returns None
+**
+*******************************************************************************/
+void upio_set(uint8_t pio, uint8_t action, uint8_t polarity)
+{
+ int rc;
+
+ switch (pio)
+ {
+ case UPIO_BT_WAKE:
+
+ if (upio_state[UPIO_BT_WAKE] == action)
+ {
+ UPIODBG("BT_WAKE is %s already", lpm_state[action]);
+ return;
+ }
+
+ upio_state[UPIO_BT_WAKE] = action;
+
+ /****************************************
+ * !!! TODO !!!
+ *
+ * === Custom Porting Required ===
+ *
+ * Platform dependent user-to-kernel
+ * interface is required to set output
+ * state of physical BT_WAKE pin.
+ ****************************************/
+#if (BT_WAKE_VIA_USERIAL_IOCTL == TRUE)
+ userial_ioctl(((action==UPIO_ASSERT) ? USERIAL_OP_ASSERT_BT_WAKE : USERIAL_OP_DEASSERT_BT_WAKE), NULL);
+#endif
+ break;
+
+ case UPIO_HOST_WAKE:
+ UPIODBG("upio_set: UPIO_HOST_WAKE");
+ break;
+ }
+}
+
+
diff --git a/vendor/libvendor/src/userial.c b/vendor/libvendor/src/userial.c
new file mode 100644
index 0000000..c1742ca
--- /dev/null
+++ b/vendor/libvendor/src/userial.c
@@ -0,0 +1,745 @@
+/************************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * This program is the proprietary software of Broadcom Corporation and/or its
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
+ *
+ * Except as expressly set forth in the Authorized License,
+ *
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
+ * Broadcom integrated circuit products.
+ *
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT
+ * OF USE OR PERFORMANCE OF THE SOFTWARE.
+ *
+ * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR
+ * ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+ *
+ ************************************************************************************/
+
+/************************************************************************************
+ *
+ * Filename: userial.c
+ *
+ * Description:
+ *
+ ***********************************************************************************/
+
+#define LOG_TAG "bt_userial"
+
+#include <utils/Log.h>
+#include <pthread.h>
+#include <termios.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <sys/socket.h>
+#include "bt_vendor_brcm.h"
+#include "userial.h"
+#include "utils.h"
+
+/************************************************************************************
+** Constants & Macros
+************************************************************************************/
+
+#ifndef USERIAL_DBG
+#define USERIAL_DBG FALSE
+#endif
+
+#if (USERIAL_DBG == TRUE)
+#define USERIALDBG LOGD
+#else
+#define USERIALDBG
+#endif
+
+#define MAX_SERIAL_PORT (USERIAL_PORT_3 + 1)
+#define READ_LIMIT (BTVND_USERIAL_READ_MEM_SIZE - BT_VND_HDR_SIZE)
+
+enum {
+ USERIAL_RX_EXIT,
+ USERIAL_RX_FLOW_OFF,
+ USERIAL_RX_FLOW_ON
+};
+
+/************************************************************************************
+** Local type definitions
+************************************************************************************/
+
+typedef struct
+{
+ int sock;
+ uint8_t port;
+ pthread_t read_thread;
+ tUSERIAL_CFG cfg;
+ BUFFER_Q rx_q;
+ VND_BT_HDR *p_rx_hdr;
+} tUSERIAL_CB;
+
+/************************************************************************************
+** Static variables
+************************************************************************************/
+
+static tUSERIAL_CB userial_cb;
+static volatile uint8_t userial_running = 0;
+
+/* Mapping of USERIAL_PORT_x to device ports */
+char userial_dev[][256] =
+{
+ BLUETOOTH_UART_DEVICE_PORT /* USERIAL_PORT_1 (HCI)*/
+};
+
+/* for friendly debugging outpout string */
+static uint32_t userial_baud_tbl[] =
+{
+ 300, /* USERIAL_BAUD_300 0 */
+ 600, /* USERIAL_BAUD_600 1 */
+ 1200, /* USERIAL_BAUD_1200 2 */
+ 2400, /* USERIAL_BAUD_2400 3 */
+ 9600, /* USERIAL_BAUD_9600 4 */
+ 19200, /* USERIAL_BAUD_19200 5 */
+ 57600, /* USERIAL_BAUD_57600 6 */
+ 115200, /* USERIAL_BAUD_115200 7 */
+ 230400, /* USERIAL_BAUD_230400 8 */
+ 460800, /* USERIAL_BAUD_460800 9 */
+ 921600, /* USERIAL_BAUD_921600 10 */
+ 1000000, /* USERIAL_BAUD_1M 11 */
+ 1500000, /* USERIAL_BAUD_1_5M 12 */
+ 2000000, /* USERIAL_BAUD_2M 13 */
+ 3000000, /* USERIAL_BAUD_3M 14 */
+ 4000000 /* USERIAL_BAUD_4M 15 */
+};
+
+/************************************************************************************
+** Static functions
+************************************************************************************/
+
+/*****************************************************************************
+** Socket signal functions to wake up userial_read_thread for termination
+**
+** creating an unnamed pair of connected sockets
+** - signal_fds[0]: join fd_set in select call of userial_read_thread
+** - signal_fds[1]: trigger from userial_close
+*****************************************************************************/
+static int signal_fds[2]={0,1};
+static uint8_t rx_flow_on = TRUE;
+static inline int create_signal_fds(fd_set* set)
+{
+ if(signal_fds[0] == 0 && socketpair(AF_UNIX, SOCK_STREAM, 0, signal_fds) < 0)
+ {
+ LOGE("create_signal_sockets:socketpair failed, errno: %d", errno);
+ return -1;
+ }
+ FD_SET(signal_fds[0], set);
+ return signal_fds[0];
+}
+static inline int send_wakeup_signal(char sig_cmd)
+{
+ return send(signal_fds[1], &sig_cmd, sizeof(sig_cmd), 0);
+}
+static inline char reset_signal()
+{
+ char sig_recv = -1;
+ recv(signal_fds[0], &sig_recv, sizeof(sig_recv), MSG_WAITALL);
+ return sig_recv;
+}
+static inline int is_signaled(fd_set* set)
+{
+ return FD_ISSET(signal_fds[0], set);
+}
+
+/*******************************************************************************
+**
+** Function select_read
+**
+** Description check if fd is ready for reading and listen for termination
+** signal. need to use select in order to avoid collision
+** between read and close on the same fd
+**
+** Returns -1: termination
+** >=0: numbers of bytes read back from fd
+**
+*******************************************************************************/
+static int select_read(int fd, uint8_t *pbuf, int len)
+{
+ fd_set input;
+ int n = 0, ret = -1;
+ char reason = 0;
+
+ while (userial_running)
+ {
+ /* Initialize the input fd set */
+ FD_ZERO(&input);
+ if (rx_flow_on == TRUE)
+ {
+ FD_SET(fd, &input);
+ }
+ int fd_max = create_signal_fds(&input);
+ fd_max = fd_max > fd ? fd_max : fd;
+
+ /* Do the select */
+ n = select(fd_max+1, &input, NULL, NULL, NULL);
+ if(is_signaled(&input))
+ {
+ reason = reset_signal();
+ if (reason == USERIAL_RX_EXIT)
+ {
+ USERIALDBG("RX termination");
+ return -1;
+ }
+ else if (reason == USERIAL_RX_FLOW_OFF)
+ {
+ USERIALDBG("RX flow OFF");
+ rx_flow_on = FALSE;
+ }
+ else if (reason == USERIAL_RX_FLOW_ON)
+ {
+ USERIALDBG("RX flow ON");
+ rx_flow_on = TRUE;
+ }
+ }
+
+ if (n > 0)
+ {
+ /* We might have input */
+ if (FD_ISSET(fd, &input))
+ {
+ ret = read(fd, pbuf, (size_t)len);
+ if (0 == ret)
+ LOGW( "read() returned 0!" );
+
+ return ret;
+ }
+ }
+ else if (n < 0)
+ LOGW( "select() Failed");
+ else if (n == 0)
+ LOGW( "Got a select() TIMEOUT");
+
+ }
+
+ return ret;
+}
+
+/*******************************************************************************
+**
+** Function userial_read_thread
+**
+** Description
+**
+** Returns void *
+**
+*******************************************************************************/
+static void *userial_read_thread(void *arg)
+{
+ int rx_length = 0;
+ VND_BT_HDR *p_buf = NULL;
+ uint8_t *p;
+
+ USERIALDBG("Entering userial_read_thread()");
+
+ rx_flow_on = TRUE;
+ userial_running = 1;
+
+ while (userial_running)
+ {
+ if (bt_vendor_cbacks)
+ {
+ p_buf = (VND_BT_HDR *) bt_vendor_cbacks->alloc(BTVND_USERIAL_READ_MEM_SIZE);
+ }
+ else
+ p_buf = NULL;
+
+ if (p_buf != NULL)
+ {
+ p_buf->offset = 0;
+ p_buf->layer_specific = 0;
+
+ p = (uint8_t *) (p_buf + 1);
+ rx_length = select_read(userial_cb.sock, p, READ_LIMIT);
+ }
+ else
+ {
+ rx_length = 0;
+ utils_delay(100);
+ LOGW("userial_read_thread() failed to gain buffers");
+ continue;
+ }
+
+
+ if (rx_length > 0)
+ {
+ p_buf->len = (uint16_t)rx_length;
+ utils_enqueue(&(userial_cb.rx_q), p_buf);
+ btvnd_signal_event(VND_EVENT_RX);
+ }
+ else /* either 0 or < 0 */
+ {
+ LOGW("select_read return size <=0:%d, exiting userial_read_thread", rx_length);
+ /* if we get here, we should have a buffer */
+ bt_vendor_cbacks->dealloc((TRANSAC) p_buf, (char *) (p_buf + 1));
+ /* negative value means exit thread */
+ break;
+ }
+ } /* for */
+
+ userial_running = 0;
+ USERIALDBG("Leaving userial_read_thread()");
+ pthread_exit(NULL);
+
+ return NULL; // Compiler friendly
+}
+
+
+/*****************************************************************************
+** Helper Functions
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function baud_userial_to_tcio
+**
+** Description helper function converts USERIAL baud rates into TCIO
+** conforming baud rates
+**
+** Returns TRUE/FALSE
+**
+*******************************************************************************/
+uint8_t userial_to_tcio_baud(uint8_t cfg_baud, uint32_t *baud)
+{
+ if (cfg_baud == USERIAL_BAUD_600)
+ *baud = B600;
+ else if (cfg_baud == USERIAL_BAUD_1200)
+ *baud = B1200;
+ else if (cfg_baud == USERIAL_BAUD_9600)
+ *baud = B9600;
+ else if (cfg_baud == USERIAL_BAUD_19200)
+ *baud = B19200;
+ else if (cfg_baud == USERIAL_BAUD_57600)
+ *baud = B57600;
+ else if (cfg_baud == USERIAL_BAUD_115200)
+ *baud = B115200;
+ else if (cfg_baud == USERIAL_BAUD_230400)
+ *baud = B230400;
+ else if (cfg_baud == USERIAL_BAUD_460800)
+ *baud = B460800;
+ else if (cfg_baud == USERIAL_BAUD_921600)
+ *baud = B921600;
+ else if (cfg_baud == USERIAL_BAUD_1M)
+ *baud = B1000000;
+ else if (cfg_baud == USERIAL_BAUD_2M)
+ *baud = B2000000;
+ else if (cfg_baud == USERIAL_BAUD_3M)
+ *baud = B3000000;
+ else if (cfg_baud == USERIAL_BAUD_4M)
+ *baud = B4000000;
+ else
+ {
+ LOGE( "userial_open: unsupported baud idx %i", cfg_baud);
+ *baud = B115200;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+#if (BT_WAKE_VIA_USERIAL_IOCTL==TRUE)
+/*******************************************************************************
+**
+** Function userial_ioctl_init_bt_wake
+**
+** Description helper function to set the open state of the bt_wake if ioctl
+** is used. it should not hurt in the rfkill case but it might
+** be better to compile it out.
+**
+** Returns none
+**
+*******************************************************************************/
+void userial_ioctl_init_bt_wake(int fd)
+{
+ uint32_t bt_wake_state;
+
+ /* assert BT_WAKE through ioctl */
+ ioctl( fd, USERIAL_IOCTL_BT_WAKE_ASSERT, NULL);
+ ioctl( fd, USERIAL_IOCTL_BT_WAKE_GET_ST, &bt_wake_state);
+ USERIALDBG("userial_ioctl_init_bt_wake read back BT_WAKE state=%i", bt_wake_state);
+}
+#endif // (BT_WAKE_VIA_USERIAL_IOCTL==TRUE)
+
+
+/*****************************************************************************
+** Userial API Functions
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function userial_init
+**
+** Description Initializes the userial driver
+**
+** Returns TRUE/FALSE
+**
+*******************************************************************************/
+uint8_t userial_init(void)
+{
+ USERIALDBG("userial_init");
+ memset(&userial_cb, 0, sizeof(tUSERIAL_CB));
+ userial_cb.sock = -1;
+ utils_queue_init(&(userial_cb.rx_q));
+ return TRUE;
+}
+
+
+/*******************************************************************************
+**
+** Function userial_open
+**
+** Description Open the indicated serial port with the given configuration
+**
+** Returns TRUE/FALSE
+**
+*******************************************************************************/
+uint8_t userial_open(uint8_t port, tUSERIAL_CFG *p_cfg)
+{
+ uint32_t baud;
+ uint8_t data_bits;
+ uint16_t parity;
+ uint8_t stop_bits;
+ struct termios termios;
+ struct sched_param param;
+ int policy;
+ pthread_attr_t thread_attr;
+ char device_name[20];
+
+ USERIALDBG("userial_open(port:%d, baud:%d)", port, p_cfg->baud);
+
+ if (userial_running)
+ {
+ /* Userial is open; close it first */
+ userial_close();
+ utils_delay(50);
+ }
+
+ if (port >= MAX_SERIAL_PORT)
+ {
+ LOGE("Port > MAX_SERIAL_PORT");
+ return FALSE;
+ }
+
+ if (!userial_to_tcio_baud(p_cfg->baud, &baud))
+ {
+ return FALSE;
+ }
+
+ if(p_cfg->fmt & USERIAL_DATABITS_8)
+ data_bits = CS8;
+ else if(p_cfg->fmt & USERIAL_DATABITS_7)
+ data_bits = CS7;
+ else if(p_cfg->fmt & USERIAL_DATABITS_6)
+ data_bits = CS6;
+ else if(p_cfg->fmt & USERIAL_DATABITS_5)
+ data_bits = CS5;
+ else
+ {
+ LOGE("userial_open: unsupported data bits");
+ return FALSE;
+ }
+
+ if(p_cfg->fmt & USERIAL_PARITY_NONE)
+ parity = 0;
+ else if(p_cfg->fmt & USERIAL_PARITY_EVEN)
+ parity = PARENB;
+ else if(p_cfg->fmt & USERIAL_PARITY_ODD)
+ parity = (PARENB | PARODD);
+ else
+ {
+ LOGE("userial_open: unsupported parity bit mode");
+ return FALSE;
+ }
+
+ if(p_cfg->fmt & USERIAL_STOPBITS_1)
+ stop_bits = 0;
+ else if(p_cfg->fmt & USERIAL_STOPBITS_2)
+ stop_bits = CSTOPB;
+ else
+ {
+ LOGE("userial_open: unsupported stop bits");
+ return FALSE;
+ }
+
+ sprintf(device_name, "%s", userial_dev[port]);
+ LOGI("userial_open: opening %s", device_name);
+
+ if ((userial_cb.sock = open(device_name, O_RDWR)) == -1)
+ {
+ LOGE("userial_open: unable to open %s", device_name);
+ return FALSE;
+ }
+
+ tcflush(userial_cb.sock, TCIOFLUSH);
+
+ tcgetattr(userial_cb.sock, &termios);
+ cfmakeraw(&termios);
+ termios.c_cflag |= (CRTSCTS | stop_bits);
+ tcsetattr(userial_cb.sock, TCSANOW, &termios);
+
+ tcflush(userial_cb.sock, TCIOFLUSH);
+
+ /* set input/output baudrate */
+ cfsetospeed(&termios, baud);
+ cfsetispeed(&termios, baud);
+ tcsetattr(userial_cb.sock, TCSANOW, &termios);
+
+#if (BT_WAKE_VIA_USERIAL_IOCTL==TRUE)
+ userial_ioctl_init_bt_wake(userial_cb.sock);
+#endif
+
+ USERIALDBG( "sock = %d", userial_cb.sock);
+
+ userial_cb.port = port;
+ memcpy(&userial_cb.cfg, p_cfg, sizeof(tUSERIAL_CFG));
+
+
+ pthread_attr_init(&thread_attr);
+
+ if (pthread_create(&(userial_cb.read_thread), &thread_attr, userial_read_thread, NULL) != 0 )
+ {
+ LOGE("pthread_create failed!\n\r");
+ return FALSE;
+ }
+
+ if(pthread_getschedparam(userial_cb.read_thread, &policy, &param)==0)
+ {
+ policy = SCHED_FIFO;
+ param.sched_priority = BTVND_USERIAL_READ_THREAD_PRIORITY;
+ pthread_setschedparam(userial_cb.read_thread, policy, &param);
+ }
+
+ return TRUE;
+}
+
+/*******************************************************************************
+**
+** Function userial_read
+**
+** Description Read data from the userial port
+**
+** Returns Number of bytes actually read from the userial port and
+** copied into p_data. This may be less than len.
+**
+*******************************************************************************/
+uint16_t userial_read(uint8_t *p_buffer, uint16_t len)
+{
+ uint16_t total_len = 0;
+ uint16_t copy_len = 0;
+ uint8_t *p_data = NULL;
+
+ do
+ {
+ if(userial_cb.p_rx_hdr != NULL)
+ {
+ p_data = ((uint8_t *)(userial_cb.p_rx_hdr + 1)) + (userial_cb.p_rx_hdr->offset);
+
+ if((userial_cb.p_rx_hdr->len) <= (len - total_len))
+ copy_len = userial_cb.p_rx_hdr->len;
+ else
+ copy_len = (len - total_len);
+
+ memcpy((p_buffer + total_len), p_data, copy_len);
+
+ total_len += copy_len;
+
+ userial_cb.p_rx_hdr->offset += copy_len;
+ userial_cb.p_rx_hdr->len -= copy_len;
+
+ if(userial_cb.p_rx_hdr->len == 0)
+ {
+ if (bt_vendor_cbacks)
+ bt_vendor_cbacks->dealloc((TRANSAC) userial_cb.p_rx_hdr, (char *) (userial_cb.p_rx_hdr + 1));
+
+ userial_cb.p_rx_hdr = NULL;
+ }
+ }
+
+ if(userial_cb.p_rx_hdr == NULL)
+ {
+ userial_cb.p_rx_hdr = (VND_BT_HDR *)utils_dequeue(&(userial_cb.rx_q));
+ }
+ } while ((userial_cb.p_rx_hdr != NULL) && (total_len < len));
+
+#if 0
+ if (total_len < len)
+ USERIALDBG("userial_read() gives %d when asks %d", total_len, len);
+#endif
+
+ return total_len;
+}
+
+/*******************************************************************************
+**
+** Function userial_write
+**
+** Description Write data to the userial port
+**
+** Returns Number of bytes actually written to the userial port. This
+** may be less than len.
+**
+*******************************************************************************/
+uint16_t userial_write(uint8_t *p_data, uint16_t len)
+{
+ int ret, total = 0;
+
+ while(len != 0)
+ {
+ ret = write(userial_cb.sock, p_data+total, len);
+ total += ret;
+ len -= ret;
+ }
+
+#if 0
+ if (total < len)
+ USERIALDBG("userial_write() does %d when asks %d", total, len);
+#endif
+
+ return ((uint16_t)total);
+}
+
+/*******************************************************************************
+**
+** Function userial_close
+**
+** Description Close the userial port
+**
+** Returns None
+**
+*******************************************************************************/
+void userial_close(void)
+{
+ int result;
+ TRANSAC p_buf;
+
+ USERIALDBG("userial_close(sock:%d)", userial_cb.sock);
+
+ if (userial_running)
+ send_wakeup_signal(USERIAL_RX_EXIT);
+
+ if ((result=pthread_join(userial_cb.read_thread, NULL)) < 0)
+ LOGE( "pthread_join() FAILED result:%d", result);
+
+#if (BT_WAKE_VIA_USERIAL_IOCTL==TRUE)
+ /* de-assert bt_wake BEFORE closing port */
+ ioctl(userial_cb.sock, USERIAL_IOCTL_BT_WAKE_DEASSERT, NULL);
+#endif
+
+ if ((result=close(userial_cb.sock)) < 0)
+ LOGE( "close(sock:%d) FAILED result:%d", userial_cb.sock, result);
+
+ userial_cb.sock = -1;
+
+ if (bt_vendor_cbacks)
+ {
+ while ((p_buf = utils_dequeue (&(userial_cb.rx_q))) != NULL)
+ {
+ bt_vendor_cbacks->dealloc(p_buf, (char *) ((VND_BT_HDR *)p_buf + 1));
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function userial_change_baud
+**
+** Description Change baud rate of userial port
+**
+** Returns None
+**
+*******************************************************************************/
+void userial_change_baud(uint8_t baud)
+{
+ struct termios termios;
+
+ USERIALDBG("userial_change_baud: Closing UART Port");
+ userial_close();
+
+ utils_delay(50);
+
+ /* change baud rate in settings - leave everything else the same */
+ userial_cb.cfg.baud = baud;
+
+ LOGI("userial_change_rate: Attempting to reopen the UART Port at %i", (unsigned int)userial_baud_tbl[baud]);
+
+ userial_open(userial_cb.port, &userial_cb.cfg);
+}
+
+/*******************************************************************************
+**
+** Function userial_ioctl
+**
+** Description ioctl inteface
+**
+** Returns None
+**
+*******************************************************************************/
+void userial_ioctl(userial_ioctl_op_t op, void *p_data)
+{
+ switch(op)
+ {
+ case USERIAL_OP_RXFLOW_ON:
+ if (userial_running)
+ send_wakeup_signal(USERIAL_RX_FLOW_ON);
+ break;
+
+ case USERIAL_OP_RXFLOW_OFF:
+ if (userial_running)
+ send_wakeup_signal(USERIAL_RX_FLOW_OFF);
+ break;
+
+#if (BT_WAKE_VIA_USERIAL_IOCTL==TRUE)
+ case USERIAL_OP_ASSERT_BT_WAKE:
+ USERIALDBG("##### userial_ioctl: Asserting BT_Wake ####");
+ ioctl(userial_cb.sock, USERIAL_IOCTL_BT_WAKE_ASSERT, NULL);
+ break;
+
+ case USERIAL_OP_DEASSERT_BT_WAKE:
+ USERIALDBG("##### userial_ioctl: De-asserting BT_Wake ####");
+ ioctl(userial_cb.sock, USERIAL_IOCTL_BT_WAKE_DEASSERT, NULL);
+ break;
+
+ case USERIAL_OP_GET_BT_WAKE_STATE:
+ ioctl(userial_cb.sock, USERIAL_IOCTL_BT_WAKE_GET_ST, p_data);
+ break;
+#endif // (BT_WAKE_VIA_USERIAL_IOCTL==TRUE)
+
+ case USERIAL_OP_INIT:
+ default:
+ break;
+ }
+}
+
diff --git a/vendor/libvendor/src/utils.c b/vendor/libvendor/src/utils.c
new file mode 100644
index 0000000..85336b5
--- /dev/null
+++ b/vendor/libvendor/src/utils.c
@@ -0,0 +1,312 @@
+/************************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * This program is the proprietary software of Broadcom Corporation and/or its
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
+ *
+ * Except as expressly set forth in the Authorized License,
+ *
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
+ * Broadcom integrated circuit products.
+ *
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT
+ * OF USE OR PERFORMANCE OF THE SOFTWARE.
+ *
+ * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR
+ * ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+ *
+ ************************************************************************************/
+
+/************************************************************************************
+ *
+ * Filename: utils.c
+ *
+ * Description:
+ *
+ ***********************************************************************************/
+
+#include <errno.h>
+#include <pthread.h>
+#include <time.h>
+#include "bt_vendor_brcm.h"
+#include "utils.h"
+
+/************************************************************************************
+** Static variables
+************************************************************************************/
+
+static pthread_mutex_t utils_mutex;
+
+/*****************************************************************************
+** UTILS INTERFACE FUNCTIONS
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function utils_init
+**
+** Description Utils initialization
+**
+** Returns None
+**
+*******************************************************************************/
+void utils_init (void)
+{
+ pthread_mutex_init(&utils_mutex, NULL);
+}
+
+/*******************************************************************************
+**
+** Function utils_cleanup
+**
+** Description Utils cleanup
+**
+** Returns None
+**
+*******************************************************************************/
+void utils_cleanup (void)
+{
+}
+
+/*******************************************************************************
+**
+** Function utils_queue_init
+**
+** Description Initialize the given buffer queue
+**
+** Returns None
+**
+*******************************************************************************/
+void utils_queue_init (BUFFER_Q *p_q)
+{
+ p_q->p_first = p_q->p_last = NULL;
+ p_q->count = 0;
+}
+
+/*******************************************************************************
+**
+** Function utils_enqueue
+**
+** Description Enqueue a buffer at the tail of the given queue
+**
+** Returns None
+**
+*******************************************************************************/
+void utils_enqueue (BUFFER_Q *p_q, void *p_buf)
+{
+ VND_BUFFER_HDR_T *p_hdr;
+
+ p_hdr = (VND_BUFFER_HDR_T *) ((uint8_t *) p_buf - BT_VND_BUFFER_HDR_SIZE);
+
+ pthread_mutex_lock(&utils_mutex);
+
+ if (p_q->p_last)
+ {
+ VND_BUFFER_HDR_T *p_last_hdr = (VND_BUFFER_HDR_T *)((uint8_t *)p_q->p_last - BT_VND_BUFFER_HDR_SIZE);
+ p_last_hdr->p_next = p_hdr;
+ }
+ else
+ p_q->p_first = p_buf;
+
+ p_q->p_last = p_buf;
+ p_q->count++;
+
+ p_hdr->p_next = NULL;
+
+ pthread_mutex_unlock(&utils_mutex);
+}
+
+/*******************************************************************************
+**
+** Function utils_dequeue
+**
+** Description Dequeues a buffer from the head of the given queue
+**
+** Returns NULL if queue is empty, else buffer
+**
+*******************************************************************************/
+void *utils_dequeue (BUFFER_Q *p_q)
+{
+ VND_BUFFER_HDR_T *p_hdr;
+
+ pthread_mutex_lock(&utils_mutex);
+
+ if (!p_q || !p_q->count)
+ {
+ pthread_mutex_unlock(&utils_mutex);
+ return (NULL);
+ }
+
+ p_hdr = (VND_BUFFER_HDR_T *)((uint8_t *)p_q->p_first - BT_VND_BUFFER_HDR_SIZE);
+
+ if (p_hdr->p_next)
+ p_q->p_first = ((uint8_t *)p_hdr->p_next + BT_VND_BUFFER_HDR_SIZE);
+ else
+ {
+ p_q->p_first = NULL;
+ p_q->p_last = NULL;
+ }
+
+ p_q->count--;
+
+ p_hdr->p_next = NULL;
+
+ pthread_mutex_unlock(&utils_mutex);
+
+ return ((uint8_t *)p_hdr + BT_VND_BUFFER_HDR_SIZE);
+}
+
+/*******************************************************************************
+**
+** Function utils_getnext
+**
+** Description Return a pointer to the next buffer linked to the given buffer
+**
+** Returns NULL if the given buffer does not point to any next buffer,
+** else next buffer address
+**
+*******************************************************************************/
+void *utils_getnext (void *p_buf)
+{
+ VND_BUFFER_HDR_T *p_hdr;
+
+ p_hdr = (VND_BUFFER_HDR_T *) ((uint8_t *) p_buf - BT_VND_BUFFER_HDR_SIZE);
+
+ if (p_hdr->p_next)
+ return ((uint8_t *)p_hdr->p_next + BT_VND_BUFFER_HDR_SIZE);
+ else
+ return (NULL);
+}
+
+/*******************************************************************************
+**
+** Function utils_remove_from_queue
+**
+** Description Dequeue the given buffer from the middle of the given queue
+**
+** Returns NULL if the given queue is empty, else the given buffer
+**
+*******************************************************************************/
+void *utils_remove_from_queue (BUFFER_Q *p_q, void *p_buf)
+{
+ VND_BUFFER_HDR_T *p_prev;
+ VND_BUFFER_HDR_T *p_buf_hdr;
+
+ pthread_mutex_lock(&utils_mutex);
+
+ if (p_buf == p_q->p_first)
+ {
+ pthread_mutex_unlock(&utils_mutex);
+ return (utils_dequeue (p_q));
+ }
+
+ p_buf_hdr = (VND_BUFFER_HDR_T *)((uint8_t *)p_buf - BT_VND_BUFFER_HDR_SIZE);
+ p_prev = (VND_BUFFER_HDR_T *)((uint8_t *)p_q->p_first - BT_VND_BUFFER_HDR_SIZE);
+
+ for ( ; p_prev; p_prev = p_prev->p_next)
+ {
+ /* If the previous points to this one, move the pointers around */
+ if (p_prev->p_next == p_buf_hdr)
+ {
+ p_prev->p_next = p_buf_hdr->p_next;
+
+ /* If we are removing the last guy in the queue, update p_last */
+ if (p_buf == p_q->p_last)
+ p_q->p_last = p_prev + 1;
+
+ /* One less in the queue */
+ p_q->count--;
+
+ /* The buffer is now unlinked */
+ p_buf_hdr->p_next = NULL;
+
+ pthread_mutex_unlock(&utils_mutex);
+ return (p_buf);
+ }
+ }
+
+ pthread_mutex_unlock(&utils_mutex);
+ return (NULL);
+}
+
+/*******************************************************************************
+**
+** Function utils_delay
+**
+** Description sleep unconditionally for timeout milliseconds
+**
+** Returns None
+**
+*******************************************************************************/
+void utils_delay (uint32_t timeout)
+{
+ struct timespec delay;
+ int err;
+
+ delay.tv_sec = timeout / 1000;
+ delay.tv_nsec = 1000 * 1000 * (timeout%1000);
+
+ /* [u]sleep can't be used because it uses SIGALRM */
+ do {
+ err = nanosleep(&delay, &delay);
+ } while (err < 0 && errno ==EINTR);
+}
+
+/*******************************************************************************
+**
+** Function utils_lock
+**
+** Description application calls this function before entering critical
+** section
+**
+** Returns None
+**
+*******************************************************************************/
+void utils_lock (void)
+{
+ pthread_mutex_lock(&utils_mutex);
+}
+
+/*******************************************************************************
+**
+** Function utils_unlock
+**
+** Description application calls this function when leaving critical
+** section
+**
+** Returns None
+**
+*******************************************************************************/
+void utils_unlock (void)
+{
+ pthread_mutex_unlock(&utils_mutex);
+}
+